Mercurial > hg > CbC > old > device
comparison mc-code-i64.c @ 731:1f6e34c4dbbf
INTEL64 (start)
author | Shinji KONO <kono@ie.u-ryukyu.ac.jp> |
---|---|
date | Fri, 29 Oct 2010 16:14:00 +0900 (2010-10-29) |
parents | |
children | 7a4f389b5bc0 |
comparison
equal
deleted
inserted
replaced
730:9bad72e27174 | 731:1f6e34c4dbbf |
---|---|
1 /* Micro-C Code Generation Part for intel386 */ | |
2 | |
3 /************************************************************************ | |
4 ** Copyright (C) 2006 Shinji Kono | |
5 ** 連絡先: 琉球大学情報工学科 河野 真治 | |
6 ** (E-Mail Address: kono@ie.u-ryukyu.ac.jp) | |
7 ** | |
8 ** このソースのいかなる複写,改変,修正も許諾します。ただし、 | |
9 ** その際には、誰が貢献したを示すこの部分を残すこと。 | |
10 ** 再配布や雑誌の付録などの問い合わせも必要ありません。 | |
11 ** 営利利用も上記に反しない範囲で許可します。 | |
12 ** バイナリの配布の際にはversion messageを保存することを条件とします。 | |
13 ** このプログラムについては特に何の保証もしない、悪しからず。 | |
14 ** | |
15 ** Everyone is permitted to do anything on this program | |
16 ** including copying, modifying, improving, | |
17 ** as long as you don't try to pretend that you wrote it. | |
18 ** i.e., the above copyright notice has to appear in all copies. | |
19 ** Binary distribution requires original version messages. | |
20 ** You don't have to ask before copying, redistribution or publishing. | |
21 ** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. | |
22 ***********************************************************************/ | |
23 | |
24 | |
25 | |
26 #include <stdio.h> | |
27 #include "mc.h" | |
28 #include "mc-parse.h" | |
29 #include "mc-codegen.h" | |
30 #include "mc-code.h" | |
31 | |
32 #ifdef __APPLE__ | |
33 #define USE_SSE2 | |
34 #define USE_PIC | |
35 #endif | |
36 | |
37 #if defined(__GNUC__) && __GNUC__ >= 4 | |
38 | |
39 #include "mc-include.c" | |
40 | |
41 static | |
42 char *init_src0 = "\ | |
43 #define __DBL_MIN_EXP__ (-1021) | |
44 #define __FLT_MIN__ 1.17549435e-38F | |
45 #define __DEC64_DEN__ 0.000000000000001E-383DD | |
46 #define __CHAR_BIT__ 8 | |
47 #define __WCHAR_MAX__ 2147483647 | |
48 #define __DBL_DENORM_MIN__ 4.9406564584124654e-324 | |
49 #define __FLT_EVAL_METHOD__ 0 | |
50 #define __DBL_MIN_10_EXP__ (-307) | |
51 #define __FINITE_MATH_ONLY__ 0 | |
52 #define __DEC64_MAX_EXP__ 384 | |
53 #define __SHRT_MAX__ 32767 | |
54 #define __LDBL_MAX__ 1.18973149535723176502e+4932L | |
55 #define __APPLE_CC__ 5664 | |
56 #define __UINTMAX_TYPE__ long unsigned int | |
57 #define __DEC32_EPSILON__ 1E-6DF | |
58 #define __SCHAR_MAX__ 127 | |
59 #define __USER_LABEL_PREFIX__ _ | |
60 #define __STDC_HOSTED__ 1 | |
61 #define __DEC64_MIN_EXP__ (-383) | |
62 #define __DBL_DIG__ 15 | |
63 #define __FLT_EPSILON__ 1.19209290e-7F | |
64 #define __LDBL_MIN__ 3.36210314311209350626e-4932L | |
65 #define __DEC32_MAX__ 9.999999E96DF | |
66 #define __strong | |
67 #define __APPLE__ 1 | |
68 #define __DECIMAL_DIG__ 21 | |
69 #define __LDBL_HAS_QUIET_NAN__ 1 | |
70 #define __DYNAMIC__ 1 | |
71 #define __GNUC__ 4 | |
72 #define __MMX__ 1 | |
73 #define __FLT_HAS_DENORM__ 1 | |
74 #define __DBL_MAX__ 1.7976931348623157e+308 | |
75 #define __DBL_HAS_INFINITY__ 1 | |
76 #define __DEC32_MIN_EXP__ (-95) | |
77 #define OBJC_NEW_PROPERTIES 1 | |
78 #define __STRICT_ANSI__ 1 | |
79 #define __LDBL_HAS_DENORM__ 1 | |
80 #define __DEC32_MIN__ 1E-95DF | |
81 #define __weak __attribute__((objc_gc(weak))) | |
82 #define __DBL_MAX_EXP__ 1024 | |
83 #define __DEC128_EPSILON__ 1E-33DL | |
84 #define __SSE2_MATH__ 1 | |
85 #define __amd64 1 | |
86 #define __tune_core2__ 1 | |
87 #define __LONG_LONG_MAX__ 9223372036854775807LL | |
88 #define __GXX_ABI_VERSION 1002 | |
89 #define __FLT_MIN_EXP__ (-125) | |
90 #define __x86_64 1 | |
91 #define __DBL_MIN__ 2.2250738585072014e-308 | |
92 #define __LP64__ 1 | |
93 #define __DBL_HAS_QUIET_NAN__ 1 | |
94 #define __DEC128_MIN__ 1E-6143DL | |
95 #define __REGISTER_PREFIX__ | |
96 #define __DBL_HAS_DENORM__ 1 | |
97 #define __NO_INLINE__ 1 | |
98 #define __DEC_EVAL_METHOD__ 2 | |
99 #define __DEC128_MAX__ 9.999999999999999999999999999999999E6144DL | |
100 #define __FLT_MANT_DIG__ 24 | |
101 #define __VERSION__ "4.2.1 (Apple Inc. build 5664)" | |
102 #define __DEC64_EPSILON__ 1E-15DD | |
103 #define __DEC128_MIN_EXP__ (-6143) | |
104 #define __ENVIRONMENT_MAC_OS_X_VERSION_MIN_REQUIRED__ 1064 | |
105 #define __SIZE_TYPE__ long unsigned int | |
106 #define __DEC32_DEN__ 0.000001E-95DF | |
107 #define __FLT_RADIX__ 2 | |
108 #define __LDBL_EPSILON__ 1.08420217248550443401e-19L | |
109 #define __SSE_MATH__ 1 | |
110 #define __k8 1 | |
111 #define __LDBL_DIG__ 18 | |
112 #define __x86_64__ 1 | |
113 #define __FLT_HAS_QUIET_NAN__ 1 | |
114 #define __FLT_MAX_10_EXP__ 38 | |
115 #define __LONG_MAX__ 9223372036854775807L | |
116 #define __FLT_HAS_INFINITY__ 1 | |
117 #define __DEC64_MAX__ 9.999999999999999E384DD | |
118 #define __DEC64_MANT_DIG__ 16 | |
119 #define __STDC_VERSION__ 199901L | |
120 #define __DEC32_MAX_EXP__ 96 | |
121 #define __DEC128_DEN__ 0.000000000000000000000000000000001E-6143DL | |
122 #define __LITTLE_ENDIAN__ 1 | |
123 #define __LDBL_MANT_DIG__ 64 | |
124 #define __CONSTANT_CFSTRINGS__ 1 | |
125 #define __DEC32_MANT_DIG__ 7 | |
126 #define __k8__ 1 | |
127 #define __WCHAR_TYPE__ int | |
128 #define __pic__ 2 | |
129 #define __FLT_DIG__ 6 | |
130 #define __INT_MAX__ 2147483647 | |
131 #define __FLT_MAX_EXP__ 128 | |
132 #define __DBL_MANT_DIG__ 53 | |
133 #define __DEC64_MIN__ 1E-383DD | |
134 #define __WINT_TYPE__ int | |
135 #define __SSE__ 1 | |
136 #define __LDBL_MIN_EXP__ (-16381) | |
137 #define __MACH__ 1 | |
138 #define __amd64__ 1 | |
139 #define __LDBL_MAX_EXP__ 16384 | |
140 #define __SSP__ 1 | |
141 #define __LDBL_MAX_10_EXP__ 4932 | |
142 #define __DBL_EPSILON__ 2.2204460492503131e-16 | |
143 #define _LP64 1 | |
144 #define __GNUC_PATCHLEVEL__ 1 | |
145 #define __LDBL_HAS_INFINITY__ 1 | |
146 #define __GNUC_STDC_INLINE__ 1 | |
147 #define __INTMAX_MAX__ 9223372036854775807L | |
148 #define __FLT_DENORM_MIN__ 1.40129846e-45F | |
149 #define __PIC__ 2 | |
150 #define __FLT_MAX__ 3.40282347e+38F | |
151 #define __SSE2__ 1 | |
152 #define __FLT_MIN_10_EXP__ (-37) | |
153 #define __INTMAX_TYPE__ long int | |
154 #define __DEC128_MAX_EXP__ 6144 | |
155 #define __GNUC_MINOR__ 2 | |
156 #define __DBL_MAX_10_EXP__ 308 | |
157 #define __LDBL_DENORM_MIN__ 3.64519953188247460253e-4951L | |
158 #define __STDC__ 1 | |
159 #define __PTRDIFF_TYPE__ long int | |
160 #define __DEC128_MANT_DIG__ 34 | |
161 #define __LDBL_MIN_10_EXP__ (-4931) | |
162 #define __SSE3__ 1 | |
163 " | |
164 #ifdef __APPLE__ | |
165 "#define __APPLE__ 1\n" | |
166 "#define __GNUC__ 4\n" | |
167 "#define __BIG_ENDIAN__ 1\n" | |
168 #endif | |
169 ; | |
170 | |
171 /* | |
172 | |
173 #define size_t int\n\ | |
174 | |
175 */ | |
176 | |
177 #else | |
178 | |
179 #include "mc-include.c" | |
180 | |
181 #if defined(__GNUC__) && __GNUC__ >= 3 | |
182 static | |
183 char *init_src0 = "\ | |
184 #define __builtin_va_start(ap,arg) ap=(((int)(&arg))+sizeof(arg))\n\ | |
185 #define __builtin_va_arg(ap,type) (*((type *)ap)++)\n\ | |
186 #define __builtin_va_end\n\ | |
187 #define __i386__ 1\n\ | |
188 #define __LITTLE_ENDIAN__ 1\n\ | |
189 #define __STDC__ 1\n\ | |
190 #define __extension__\n\ | |
191 // #define __restrict\n\ | |
192 #define __flexarr\n\ | |
193 #define __const const\n\ | |
194 #define __THORW\n\ | |
195 // #define __attribute__(a)\n\ | |
196 #define __inline__ inline\n\ | |
197 #define __inline inline\n\ | |
198 #define __GNUC__ 3\n\ | |
199 #define __builtin_va_list int\n\ | |
200 typedef long unsigned int __SIZE_TYPE__ ;\n\ | |
201 " | |
202 | |
203 #else | |
204 static | |
205 char *init_src0 = "\ | |
206 #define va_list int\n\ | |
207 #define va_start(ap,arg) ap=(((int)(&arg))+sizeof(arg))\n\ | |
208 #define va_arg(ap,type) (*((type *)ap)++)\n\ | |
209 #define va_end\n\ | |
210 #define __i386__ 1\n\ | |
211 #define __LITTLE_ENDIAN__ 1\n\ | |
212 #define __STDC__ 1\n\ | |
213 #define __extension__\n\ | |
214 // #define __restrict\n\ | |
215 #define __flexarr\n\ | |
216 #define __const const\n\ | |
217 #define __THORW\n\ | |
218 // #define __attribute__(a)\n\ | |
219 #define __inline__ inline\n\ | |
220 #define __SIZE_TYPE__ long unsigned int\n\ | |
221 #define __GNUC__ 3\n\ | |
222 " | |
223 | |
224 #endif | |
225 | |
226 | |
227 ; | |
228 | |
229 #endif | |
230 | |
231 int data_alignment = 0; | |
232 | |
233 #define SIZE_OF_INT 4 | |
234 #define SIZE_OF_SHORT 2 | |
235 #define SIZE_OF_FLOAT 4 | |
236 #define SIZE_OF_DOUBLE 8 | |
237 #define SIZE_OF_LONGLONG 8 | |
238 #define ENDIAN 0 | |
239 #define ENDIAN_L 0 | |
240 #define ENDIAN_D 0 | |
241 | |
242 int eval_order = REVERSE; | |
243 | |
244 #define TEXT_EMIT_MODE 0 | |
245 #define DATA_EMIT_MODE 1 | |
246 #define RODATA_EMIT_MODE 2 | |
247 | |
248 #ifdef __APPLE__ | |
249 #else | |
250 #define DOT_SIZE 1 | |
251 #endif | |
252 | |
253 static int output_mode = TEXT_EMIT_MODE; | |
254 | |
255 static int creg; | |
256 static int ireg; | |
257 static int lreg; | |
258 | |
259 extern int lp64; | |
260 | |
261 #define regv_l(r) (r==REG_L?REG_ESI:REG_EAX) | |
262 #define regv_h(r) (r==REG_L?REG_EDI:REG_EDX) | |
263 | |
264 int code_lassop_p = 0; | |
265 | |
266 #define MAX_REGISTER 14 /* intel386のレジスタを6つまで使う*/ | |
267 #define REAL_MAX_REGISTER 16 /* intel386のレジスタが8つということ*/ | |
268 static int MAX_DATA_REG=8; | |
269 static int MAX_POINTER=8; | |
270 int MAX_REGISTER_VAR=8; | |
271 // static int MAX_FREGISTER=1; | |
272 | |
273 #define MAX_FPU_STACK 7 | |
274 | |
275 // static int MAX_INPUT_REGISTER_VAR = 0; | |
276 int MAX_CODE_INPUT_REGISTER_VAR = 6; | |
277 static int MAX_INPUT_DREGISTER_VAR = 6; | |
278 // static int MAX_INPUT_FREGISTER_VAR = 0; | |
279 static int MAX_CODE_INPUT_DREGISTER_VAR = 6; | |
280 | |
281 static int reg_sp; /* REGister Stack-Pointer */ | |
282 static int reg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ | |
283 static int stack_depth = 0; | |
284 | |
285 /* floating point registers */ | |
286 | |
287 static int freg_sp; /* floating point REGister Stack-Pointer */ | |
288 static int freg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ | |
289 | |
290 static int reg_var; | |
291 | |
292 | |
293 /* | |
294 local2 -8 | |
295 local1 <-- -6 0 local variable | |
296 %edi -12 <- disp_offset %ebp | |
297 %esi -8 | |
298 %ebx -4 | |
299 %ebp = %esp 0 | |
300 %eip 4 <- arg_offset | |
301 arg7 8 | |
302 %r9d arg6 | |
303 %r8d arg5 | |
304 %ecx arg4 | |
305 %edx arg3 | |
306 %esi arg2 | |
307 %rdi arg1 | |
308 see enter/enter1/leave see code_enter | |
309 */ | |
310 // static int arg_offset; | |
311 | |
312 static int code_disp_label; | |
313 | |
314 #ifdef __APPLE__ | |
315 static int goffset_label; | |
316 #endif | |
317 | |
318 | |
319 /* | |
320 creg current register | |
321 ireg current register for integer (int mode) | |
322 lreg current register for long long (long long mode) | |
323 | |
324 regs[] register usage | |
325 | |
326 freg current floating point register | |
327 kept in FPU stack (no register) | |
328 */ | |
329 | |
330 #define REAL_MAX_LREGISTER 2 | |
331 static int ia32regs[1+REAL_MAX_REGISTER+REAL_MAX_LREGISTER]; | |
332 | |
333 | |
334 static int *regs = ia32regs; | |
335 | |
336 static int ia32fregs[1]; | |
337 static int *fregs = ia32fregs; | |
338 static int freg; | |
339 | |
340 // register number should start 1 | |
341 // regs[] value | |
342 // 0 for not ready | |
343 // -1 use currrent register | |
344 // 1 used | |
345 // 2 (REG_VAR) register variable | |
346 // 3 pointer cache (not used in ia32) | |
347 | |
348 #define REG_EBP 1 | |
349 #define REG_ESP 2 | |
350 #define REG_EDI 3 // first argument register | |
351 #define REG_ESI 4 | |
352 #define REG_EDX 5 | |
353 #define REG_ECX 6 // for strange reason (code_assop) | |
354 #define REG_EAX 7 | |
355 #define REG_EBX 8 | |
356 #define is_int_reg(reg) 1 // (1<=reg&®<REG_EBP) | |
357 | |
358 // return value register | |
359 #define RET_FREGISTER | |
360 #define RET_DREGISTER | |
361 #define RET_LREGISTER REG_LCREG | |
362 #define RET_REGISTER REG_EAX | |
363 | |
364 // defalut current register | |
365 #define CREG_REGISTER REG_ECX | |
366 #define FREG_FREGISTER 0 | |
367 | |
368 static char *reg_name[8+1]; | |
369 static char *reg_name_l[4+1]; | |
370 static char *reg_name_w[4+1]; | |
371 | |
372 static void ascii(char *s); | |
373 | |
374 static int use_register(int virt, int real, int move); | |
375 static void shift(char *op, int reg,int creg); | |
376 static void ld_indexx(int byte, int n, int xreg,int reg,int sign); | |
377 //static void data_mode(char *name); | |
378 // static void text_mode(int align); | |
379 static int get_data_register(void); | |
380 | |
381 static void local_table(void); | |
382 static int push_struct(int e4,int t, int arg) ; | |
383 static void code_clear_stack_reg(int reg1); | |
384 #if FLOAT_CODE | |
385 static char * fload(int d); | |
386 static int code_d1(double d); | |
387 static int code_d2(double d); | |
388 static void code_save_fstacks(); | |
389 #endif | |
390 static void jcond(int l, char cond); | |
391 #if LONGLONG_CODE | |
392 static int code_l1(long long d); | |
393 static int code_l2(long long d); | |
394 #endif | |
395 | |
396 #define round16(i) align(i,16) | |
397 #define round4(i) align(i,4) | |
398 | |
399 | |
400 #define func_disp_offset (16) | |
401 #define code_disp_offset (16) | |
402 | |
403 #define arg_offset 8 | |
404 #define arg_offset1 0 | |
405 #define ARG_LVAR_OFFSET 0x10000000 | |
406 | |
407 #define code_disp_offset0 (-16) | |
408 // disp_offset | |
409 int disp_offset = code_disp_offset0; | |
410 | |
411 #define CODE_LVAR(l) ((l)+code_disp_offset0) | |
412 #define CODE_CALLER_ARG(l) ((l)+arg_offset1) | |
413 #define FUNC_LVAR(l) ((l)-func_disp_offset) | |
414 #define CALLER_ARG(l) ((l)+arg_offset1) | |
415 #define CALLEE_ARG(l) ((l)+arg_offset) | |
416 static int r1_offset_label; | |
417 static const char lpfx[] = "_"; | |
418 // static int lvar_offset_label; | |
419 static int max_func_args,max_func_arg_label; | |
420 | |
421 /* | |
422 function call stack frame | |
423 prev esp | |
424 <-------r1_offset------------------------------> | |
425 <----- ebp--> <----- esp | |
426 r+ +------------+---+---------------+----------+-------------------+ - | |
427 callee arg xx register save local caller arg | |
428 reg_save disp max_func_args*SIZE_OF_INT | |
429 lvar>0 lvar<0 lvar>0x1000 0000 | |
430 | |
431 code segment stack frame | |
432 | |
433 * gotoを呼び出した関数のr1 ! r1(goto前のr1) | |
434 disp_offset | |
435 # * ebp <---r1_offset---------> esp | |
436 r+ +----------+--+----------+----------------+-----------+----------+----+ | |
437 cousin arg xx reg save !callee arg !code local caller arg xx | |
438 r20-r29 lvar>0 lvar<0 lvar>0x1000 000 | |
439 f20-f31 <-my_func_args--><--disp-----><-max_func_arg-> | |
440 *SIZE_OF_INT *SIZE_OF_INT | |
441 | |
442 %esp should be alignment 16 | |
443 | |
444 */ | |
445 | |
446 void | |
447 code_offset_set(NMTBL *fnptr) | |
448 { | |
449 #if 0 | |
450 int l; | |
451 #endif | |
452 int code_f = is_code(fnptr); | |
453 int lvar_offsetv = round16(-disp); | |
454 int r1_offsetv = round16(lvar_offsetv+max_func_args*SIZE_OF_INT+func_disp_offset)+8; | |
455 | |
456 if (code_f) { | |
457 printf("\t.set _%d,%d\n",code_disp_label,r1_offsetv); | |
458 } else { | |
459 // +8 makes esp alignment 16 | |
460 // printf(".set %s%d,%d\n",lpfx,lvar_offset_label,lvar_offsetv); | |
461 if (r1_offsetv-lvar_offsetv > 65000) error(-1); | |
462 // too large function arguments? | |
463 printf(".set %s%d,%d\n",lpfx,r1_offset_label,r1_offsetv); | |
464 } | |
465 if (max_func_arg_label) { | |
466 printf(".set %s%d,%d\n",lpfx,max_func_arg_label, | |
467 round16(max_func_args*SIZE_OF_INT)); | |
468 max_func_arg_label = 0; | |
469 } | |
470 | |
471 #if 0 | |
472 printf("## reg_save %d\n",reg_save); | |
473 printf("## function %s\n",fnptr->nm); | |
474 l = ARG_LVAR_OFFSET; | |
475 printf("## offset call0\t%d\n",CALLER_ARG); | |
476 l = ARG_LVAR_OFFSET+max_func_args*SIZE_OF_INT; | |
477 printf("## offset calln\t%d %d\n",CALLER_ARG,max_func_args*SIZE_OF_INT); | |
478 l = disp; | |
479 printf("## offset lvarn\t%d %d\n",FUNC_LVAR+lvar_offsetv,disp); | |
480 l = 0; | |
481 printf("## offset lvar0\t%d\n",FUNC_LVAR+lvar_offsetv); | |
482 l = -reg_save; | |
483 printf("## offset regs\t%d\n",FUNC_LVAR+lvar_offsetv); | |
484 printf("## offset r1off\t%d\n",r1_offsetv); | |
485 l = 0; | |
486 printf("## offset carg0\t%d\n",CALLEE_ARG+r1_offsetv); | |
487 l = my_func_args; | |
488 printf("## offset cargn\t%d %d\n",CALLEE_ARG+r1_offsetv,my_func_args); | |
489 #endif | |
490 } | |
491 | |
492 | |
493 static void | |
494 lvar(int l) | |
495 { | |
496 if (is_code(fnptr)) { | |
497 if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ | |
498 printf("%d(%%esp)",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET)); | |
499 } else | |
500 printf("%d(%%ebp)",CODE_LVAR(l)); | |
501 } else if (l<0) { /* local variable */ | |
502 printf("%d(%%ebp)",FUNC_LVAR(l)); | |
503 } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ | |
504 printf("%d(%%esp)",CALLER_ARG(l-ARG_LVAR_OFFSET)); | |
505 } else { /* callee's arguments */ | |
506 printf("%d(%%ebp)",CALLEE_ARG(l)); | |
507 } | |
508 } | |
509 | |
510 | |
511 #define use_int(reg) if (reg==-1) reg=use_int0() | |
512 | |
513 static int | |
514 use_int0() { | |
515 int i = creg; | |
516 if (!i||!ireg||!is_int_reg(i)) { | |
517 if (lreg) { if (regs[lreg]) free_register(lreg); lreg = 0; } | |
518 if (!ireg) { | |
519 ireg = get_register(); | |
520 } | |
521 i = ireg; | |
522 } | |
523 if (!regs[i]) regs[i]=USING_REG; | |
524 creg = ireg = i; | |
525 return i; | |
526 } | |
527 | |
528 #define is_data_reg(reg) (REG_EAX<=reg&®<=REG_EDX) | |
529 #define is_pointer_reg(reg) (REG_ESI<=reg&®<=REG_EBP) | |
530 | |
531 static int | |
532 use_register(int reg0, int reg1, int move) | |
533 { | |
534 /* | |
535 reg0 becomes reg1, if (move) copy the content. | |
536 if reg1 is used, reg0 contains old value. | |
537 */ | |
538 | |
539 char *move_op; | |
540 code_clear_stack_reg(reg1); | |
541 move_op = (regs[reg1]||regs[reg1])?"\txchg %s,%s\n":"\tmovl %s,%s\n"; | |
542 if (move && reg0!=reg1) { | |
543 printf(move_op,reg_name[reg0],reg_name[reg1]); | |
544 if (!regs[reg1]) regs[reg1]=USING_REG; | |
545 } | |
546 return reg0; | |
547 } | |
548 | |
549 #define use_data_reg(reg,keep) \ | |
550 if (reg==-1||!is_data_reg(reg)) reg=use_data_reg0(keep,reg) | |
551 | |
552 int | |
553 use_data_reg0(int keep,int reg) | |
554 { | |
555 int ptreg =0; | |
556 int i; | |
557 if (is_pointer_reg(creg)) { | |
558 free_register(ptreg=creg); | |
559 ireg = creg = 0; | |
560 } | |
561 if (is_pointer_reg(ireg)) { | |
562 free_register(ireg); | |
563 ireg = 0; | |
564 } | |
565 i = reg==USING_REG?creg:reg; | |
566 #ifdef __APPLE__ | |
567 if (regs[i]==PTRC_REG) clear_ptr_cache_reg(i); | |
568 #endif | |
569 if (!i||!ireg||!is_data_reg(i)) { | |
570 if (lreg) { if (regs[lreg]) free_register(lreg); lreg = 0; } | |
571 if (!ireg) { | |
572 ireg = get_data_register(); | |
573 } | |
574 i = ireg; | |
575 } | |
576 if (!regs[i]) regs[i]=USING_REG; | |
577 creg = ireg = i; | |
578 if (ptreg && keep) { | |
579 printf("\tmovl %s,%s\n",reg_name[ptreg],reg_name[creg]); | |
580 } | |
581 return i; | |
582 } | |
583 | |
584 static void | |
585 set_freg(int reg,int mode) | |
586 { | |
587 } | |
588 | |
589 static void | |
590 set_ireg(int reg,int mode) | |
591 { | |
592 if (!is_int_reg(reg)) error(-1); | |
593 if (reg!=creg) { | |
594 #ifdef __APPLE__ | |
595 if (regs[reg]==PTRC_REG) | |
596 clear_ptr_cache_reg(reg); | |
597 #endif | |
598 if (ireg && reg!=ireg ) { | |
599 if (regs[ireg]!=REG_VAR) free_register(ireg); | |
600 if (mode) { | |
601 printf("\tmovl %s,%s\n",reg_name[ireg],reg_name[reg]); | |
602 } | |
603 } | |
604 if (creg>0 && regs[creg]!=REG_VAR) free_register(creg); | |
605 if (creg==lreg) lreg = 0; | |
606 } | |
607 creg = ireg = reg; | |
608 if (!regs[reg]) regs[reg]=USING_REG; | |
609 } | |
610 | |
611 #define is_long_reg(reg) (reg==REG_LCREG||reg==REG_L) | |
612 #define use_longlong(reg) \ | |
613 if (reg==-1||is_long_reg(reg)) reg=use_longlong0(reg) | |
614 | |
615 static int | |
616 use_longlong0(int reg) | |
617 { | |
618 int i = reg==USING_REG?creg:reg; | |
619 if (ireg) { if (regs[ireg]!=REG_VAR) free_register(ireg); ireg=0; } | |
620 if (!lreg||!regs[lreg]) { | |
621 // long long mode use all registers | |
622 code_save_stacks(); | |
623 #ifdef __APPLE__ | |
624 clear_ptr_cache(); | |
625 #endif | |
626 } | |
627 i = lreg = (reg==USE_CREG)?REG_LCREG:reg; | |
628 if (!regs[i]) regs[i]=USING_REG; | |
629 if (!regs[regv_l(i)]) regs[regv_l(i)]=USING_REG; | |
630 if (!regs[regv_h(i)]) regs[regv_h(i)]=USING_REG; | |
631 creg = lreg = i; | |
632 return i; | |
633 } | |
634 | |
635 static void | |
636 set_lreg(int reg,int mode) | |
637 { | |
638 use_longlong(reg); | |
639 } | |
640 | |
641 char * | |
642 l_edx(int i) { | |
643 return i==REG_L?"%edi":"%edx"; | |
644 } | |
645 char * | |
646 l_eax(int i) { | |
647 return i==REG_L?"%esi":"%eax"; | |
648 } | |
649 | |
650 extern void | |
651 code_init(void) | |
652 { | |
653 | |
654 /* called only once */ | |
655 | |
656 init_src = init_src0; | |
657 size_of_int = SIZE_OF_INT; | |
658 size_of_pointer = SIZE_OF_INT; | |
659 size_of_short = SIZE_OF_SHORT; | |
660 size_of_float = SIZE_OF_FLOAT; | |
661 size_of_double = SIZE_OF_DOUBLE; | |
662 size_of_longlong = SIZE_OF_LONGLONG; | |
663 endian = ENDIAN; | |
664 lp64 = 1; | |
665 struct_align = size_of_int; | |
666 | |
667 | |
668 // MAX_REGISTER=6; | |
669 MAX_DATA_REG=4; | |
670 MAX_POINTER=3; | |
671 MAX_REGISTER_VAR=2; | |
672 | |
673 reg_name[REG_EAX] = "%eax"; | |
674 reg_name[REG_EBX] = "%ebx"; | |
675 reg_name[REG_ECX] = "%ecx"; | |
676 reg_name[REG_EDX] = "%edx"; | |
677 reg_name[REG_ESI] = "%esi"; | |
678 reg_name[REG_EDI] = "%edi"; | |
679 reg_name[REG_EBP] = "%ebp"; | |
680 reg_name[REG_ESP] = "%esp"; | |
681 reg_name_l[REG_EAX] = "%al"; | |
682 reg_name_l[REG_EBX] = "%bl"; | |
683 reg_name_l[REG_ECX] = "%cl"; | |
684 reg_name_l[REG_EDX] = "%dl"; | |
685 reg_name_w[REG_EAX] = "%ax"; | |
686 reg_name_w[REG_EBX] = "%bx"; | |
687 reg_name_w[REG_ECX] = "%cx"; | |
688 reg_name_w[REG_EDX] = "%dx"; | |
689 | |
690 } | |
691 | |
692 extern void | |
693 emit_reinit() | |
694 { | |
695 /* called for each file */ | |
696 output_mode = -1; | |
697 #ifdef __APPLE__ | |
698 init_ptr_cache(); | |
699 #endif | |
700 } | |
701 | |
702 | |
703 char * | |
704 register_name(int i,int byte) | |
705 { | |
706 if (i<=0) { | |
707 error(REG_ERR); | |
708 return "%eax"; | |
709 } | |
710 if (byte==1 && i <= REG_EDX) { | |
711 return reg_name_l[i]; | |
712 } else if (byte==SIZE_OF_SHORT && i <= REG_EDX) { | |
713 return reg_name_w[i]; | |
714 } else { | |
715 return reg_name[i]; /* 0 or 4 means int */ | |
716 } | |
717 } | |
718 | |
719 void | |
720 gexpr_code_init(void){ | |
721 // use_register(creg,REG_EAX,0); | |
722 set_ireg(CREG_REGISTER,0); | |
723 } | |
724 | |
725 void | |
726 code_gexpr(int e){ | |
727 if ((is_int_reg(creg))&®s[creg]==REG_VAR) | |
728 creg = ireg = 0; | |
729 else if ((creg==REG_L)&®s[creg]==REG_VAR) | |
730 creg = lreg = 0; | |
731 } | |
732 | |
733 int | |
734 get_register(void) | |
735 { /* 使われていないレジスタを調べる */ | |
736 int i,reg,j; | |
737 for(i=1;i<MAX_REGISTER+1;i++) { | |
738 if (! regs[i]) { /* 使われていないなら */ | |
739 regs[i]=1; /* そのレジスタを使うことを宣言し */ | |
740 return i; /* その場所を表す番号を返す */ | |
741 } | |
742 } | |
743 #ifdef __APPLE__ | |
744 /* PTR_CACHE をつぶす */ | |
745 if ((i=last_ptr_cache())) { | |
746 clear_ptr_cache_reg(i); | |
747 regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ | |
748 return i; /* その場所を表す番号を返す */ | |
749 } | |
750 #endif | |
751 /* search register stack */ | |
752 for(i=0;i<reg_sp;i++) { | |
753 if ((reg=reg_stack[i])>=0) { | |
754 code_assign_lvar( | |
755 (j=new_lvar(SIZE_OF_INT)),reg,0); | |
756 reg_stack[i]= j-REG_LVAR_OFFSET; | |
757 return reg; | |
758 } | |
759 } | |
760 error(RGERR); | |
761 return -1; /* 空いている場所がないなら、それを表す -1 を返す */ | |
762 } | |
763 | |
764 static int | |
765 get_data_register(void) | |
766 { /* 使われていないレジスタを調べる */ | |
767 int i,reg,j; | |
768 for(i=REG_EAX;i<=REG_EDX;i++) { | |
769 if (! regs[i]) { /* 使われていないなら */ | |
770 regs[i]=1; /* そのレジスタを使うことを宣言し */ | |
771 return i; /* その場所を表す番号を返す */ | |
772 } | |
773 } | |
774 #ifdef __APPLE__ | |
775 /* PTR_CACHE をつぶす */ | |
776 while ((i=last_ptr_cache())) { | |
777 clear_ptr_cache_reg(i); | |
778 if (is_data_reg(i)) { | |
779 regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ | |
780 return i; /* その場所を表す番号を返す */ | |
781 } | |
782 } | |
783 #endif | |
784 /* search register stack */ | |
785 for(i=0;i<reg_sp;i++) { | |
786 if (is_data_reg(i) && (reg=reg_stack[i])>=0) { | |
787 code_assign_lvar( | |
788 (j=new_lvar(SIZE_OF_INT)),reg,0); | |
789 reg_stack[i]= j-REG_LVAR_OFFSET; | |
790 return reg; | |
791 } | |
792 } | |
793 error(-1); | |
794 return -1; /* 空いている場所がないなら、それを表す -1 を返す */ | |
795 } | |
796 | |
797 void | |
798 free_register(int i) { /* いらなくなったレジスタを開放 */ | |
799 if (i==REG_L) { | |
800 reg_var=0; | |
801 regs[REG_ESI]=regs[REG_EDI]=0; | |
802 } else if (regs[i]==REG_VAR) { reg_var--; | |
803 } else if(i==REG_LCREG) { //? REG_L? | |
804 regs[REG_EAX]=regs[REG_EDX]=0; | |
805 } | |
806 regs[i]=0; | |
807 } | |
808 | |
809 extern void | |
810 use_ptr_cache(int r) | |
811 { | |
812 #ifdef __APPLE__ | |
813 regs[r]=PTRC_REG; | |
814 #else | |
815 error(-1); | |
816 #endif | |
817 } | |
818 | |
819 extern void | |
820 code_ptr_cache_def(int r,NMTBL *nptr) | |
821 { | |
822 #ifdef __APPLE__ | |
823 char *rrn = register_name(r,0); | |
824 if (nptr->sc==STATIC && !(is_code(nptr)||is_function(nptr))) { | |
825 printf("\tleal _%s-_%d(%%ebx),%s\n",nptr->nm, | |
826 goffset_label,rrn); | |
827 } else { | |
828 printf("\tmovl L_%s$non_lazy_ptr-_%d(%%ebx),%s\n", | |
829 nptr->nm, | |
830 goffset_label,rrn); | |
831 } | |
832 #else | |
833 error(-1); | |
834 #endif | |
835 } | |
836 | |
837 /* | |
838 ESI,EDI are used as register variable | |
839 (both in integer and long long mode) | |
840 */ | |
841 | |
842 int | |
843 get_input_register_var(int i,NMTBL *nptr,int is_code) | |
844 { | |
845 if (is_code) { | |
846 if (i>=MAX_CODE_INPUT_REGISTER_VAR) return 0; | |
847 i += REG_EDI; | |
848 regs[i]=INPUT_REG; | |
849 return list3n(REGISTER,i,nptr); | |
850 } else { | |
851 if (i>=MAX_INPUT_REGISTER_VAR) return 0; | |
852 i += REG_EDI; | |
853 regs[i]=INPUT_REG; | |
854 return list3n(REGISTER,i,nptr); | |
855 } | |
856 } | |
857 | |
858 int | |
859 get_input_dregister_var(int i,NMTBL *nptr,int is_code,int d) | |
860 { | |
861 return 0; | |
862 } | |
863 | |
864 int | |
865 get_input_lregister_var(int i,NMTBL *nptr,int is_code) | |
866 { | |
867 int h,l; | |
868 if (is_code) { | |
869 if (i+1>=MAX_CODE_INPUT_REGISTER_VAR) return 0; | |
870 h = REG_ESI; | |
871 l = REG_EDI; | |
872 regs[h]=regs[l]=INPUT_REG; | |
873 return list2(LREGISTER,REG_L); | |
874 } | |
875 return 0; | |
876 } | |
877 | |
878 int | |
879 get_dregister(int d) | |
880 { | |
881 return -1; | |
882 } | |
883 | |
884 int | |
885 get_lregister_var(NMTBL *n) | |
886 { | |
887 int h,l; | |
888 h = REG_ESI; | |
889 l = REG_EDI; | |
890 if (regs[h]==0&®s[l]==0) { | |
891 regs[h]=regs[l]=REG_VAR; regs[REG_L]=REG_VAR; | |
892 reg_var=2; | |
893 return list2(LREGISTER,REG_L); | |
894 } | |
895 return list3n(LVAR,new_lvar(SIZE_OF_LONGLONG),0); | |
896 } | |
897 | |
898 int | |
899 get_lregister() | |
900 { | |
901 return -1; | |
902 } | |
903 | |
904 | |
905 int | |
906 register_full(void) | |
907 { | |
908 int i; | |
909 for(i=1;i<MAX_REGISTER+1;i++) { | |
910 if (! regs[i]) { | |
911 return 0; | |
912 } | |
913 } | |
914 return 1; | |
915 } | |
916 | |
917 int | |
918 free_register_count(int d) | |
919 { | |
920 int i,count; | |
921 count = 0; | |
922 for(i=1;i<MAX_REGISTER+1;i++) { | |
923 if (! regs[i]) count++; | |
924 } | |
925 return d?0:count; | |
926 } | |
927 | |
928 void | |
929 free_all_register(void) | |
930 { | |
931 int i; | |
932 for(i=1;i<MAX_REGISTER+REAL_MAX_LREGISTER+1;i++) { | |
933 regs[i]=0; | |
934 } | |
935 lreg = creg = ireg = 0; | |
936 reg_var = 0; | |
937 return; | |
938 } | |
939 | |
940 extern int | |
941 code_register_overlap(int s,int t) | |
942 { | |
943 if (car(s)==REGISTER) { | |
944 if (car(t)==REGISTER) return cadr(s)==cadr(t); | |
945 if (car(t)==LREGISTER) | |
946 return cadr(s)==REG_ESI|| cadr(s)==REG_EDI; | |
947 } else if (car(s)==LREGISTER) { | |
948 if (car(t)==LREGISTER) return 1; | |
949 if (car(t)==REGISTER) | |
950 return cadr(t)==REG_ESI|| cadr(t)==REG_EDI; | |
951 } | |
952 return 0; | |
953 } | |
954 | |
955 void | |
956 register_usage(char *s) | |
957 { | |
958 int i; | |
959 printf("## %d: %s:",lineno,s); | |
960 if (creg) printf(" creg=%s ",register_name(creg,0)); | |
961 for(i=1;i<MAX_REGISTER+1;i++) { | |
962 printf("%d",regs[i]); | |
963 } | |
964 #if 0 | |
965 printf(" regs_stack",register_name(creg,0); | |
966 for(i=reg_sp;i>=0;i--) { | |
967 if(reg_stack[i]>=0) | |
968 printf(" %s",register_name(reg_stack[i],0)); | |
969 } | |
970 #endif | |
971 printf("## f:%d",freg_sp); | |
972 printf("\n"); | |
973 } | |
974 | |
975 void | |
976 code_arg_register(NMTBL *fnptr) | |
977 { | |
978 int args = fnptr->dsp; | |
979 NMTBL *n; | |
980 int reg_var = 0; | |
981 int freg_var = 0; | |
982 int type; | |
983 int reg; | |
984 int offset = 0; | |
985 int is_code0 = is_code(fnptr); | |
986 | |
987 while (args) { | |
988 /* process in reverse order */ | |
989 n = ncadddr(args); | |
990 type = n->ty; | |
991 // n->dsp = offset; | |
992 // printf("### %s %d %d\n",n->nm,n->dsp,n->ty); | |
993 if (scalar(type)) { | |
994 if ((reg = get_input_register_var(reg_var,n,is_code0))) { | |
995 n->sc = REGISTER; | |
996 n->dsp = cadr(reg); | |
997 regs[n->dsp]= INPUT_REG; | |
998 reg_var++; | |
999 caddr(args)=SIZE_OF_INT; /* why we need this? */ | |
1000 } | |
1001 offset+=SIZE_OF_INT; | |
1002 } else if (type==FLOAT||type==DOUBLE) { | |
1003 if ((reg = get_input_dregister_var(freg_var,n,is_code0,1))) { | |
1004 n->sc = DREGISTER; | |
1005 n->dsp = cadr(reg); | |
1006 fregs[n->dsp]= INPUT_REG; | |
1007 freg_var++; | |
1008 caddr(args)=size(type); /* why we need this? */ | |
1009 } | |
1010 offset+=size(type); | |
1011 } else | |
1012 offset+=size(type); | |
1013 args = cadr(args); | |
1014 } | |
1015 } | |
1016 | |
1017 void | |
1018 gexpr_init(void) | |
1019 { | |
1020 text_mode(0); | |
1021 if (reg_sp>0) error(-1); | |
1022 if (freg_sp>0) error(-1); | |
1023 reg_sp = 0; | |
1024 freg_sp = 0; | |
1025 stack_depth = 0; | |
1026 gexpr_code_init(); | |
1027 regs[creg]=1; | |
1028 register_usage("gexpr_init"); | |
1029 } | |
1030 | |
1031 | |
1032 void | |
1033 emit_init(void) | |
1034 { | |
1035 int i; | |
1036 for(i=1;i<REAL_MAX_REGISTER+1;i++) regs[i]=0; | |
1037 free_all_register(); | |
1038 reg_sp = 0; | |
1039 freg_sp = 0; | |
1040 } | |
1041 | |
1042 int | |
1043 pop_register(void) | |
1044 { /* レジスタから値を取り出す */ | |
1045 return reg_stack[--reg_sp]; | |
1046 } | |
1047 | |
1048 void | |
1049 emit_pop_free(int xreg) | |
1050 { | |
1051 if (xreg>=0 && xreg!=creg && regs[xreg]!=REG_VAR) { | |
1052 free_register(xreg); | |
1053 } | |
1054 } | |
1055 | |
1056 | |
1057 int | |
1058 get_register_var(NMTBL *nptr) | |
1059 { | |
1060 int i; | |
1061 for(i=REG_ESI;i<REG_EBP;i++) { | |
1062 if (! regs[i]) { /* 使われていないなら */ | |
1063 regs[i]=REG_VAR; /* そのレジスタを使うことを宣言し */ | |
1064 return list3n(REGISTER,i,nptr); /* その場所を表す番号を返す */ | |
1065 } | |
1066 } | |
1067 return list3n(LVAR,new_lvar(SIZE_OF_INT),0); | |
1068 } | |
1069 | |
1070 int | |
1071 get_dregister_var(NMTBL *nptr,int d) | |
1072 { | |
1073 return list3n(LVAR,new_lvar(d?SIZE_OF_DOUBLE:SIZE_OF_FLOAT),0); | |
1074 } | |
1075 | |
1076 | |
1077 int | |
1078 emit_push() | |
1079 { | |
1080 int new_reg,old; | |
1081 new_reg = get_register(); /* 絶対に取れる */ | |
1082 // who free new_reg? | |
1083 if (new_reg==creg) error(-1); | |
1084 old = creg; | |
1085 reg_stack[reg_sp++] = creg; /* push するかわりにレジスタを使う */ | |
1086 ireg = creg = new_reg; | |
1087 if (!regs[creg]) regs[creg]=USING_REG; | |
1088 return old; | |
1089 } | |
1090 | |
1091 int | |
1092 emit_pop(int type) | |
1093 { | |
1094 int xreg,reg; | |
1095 xreg=pop_register(); | |
1096 if (xreg<= -REG_LVAR_OFFSET) { | |
1097 reg = get_register(); | |
1098 code_rlvar(REG_LVAR_OFFSET+xreg,reg); | |
1099 free_lvar(REG_LVAR_OFFSET+xreg); | |
1100 xreg = reg; | |
1101 } | |
1102 return xreg; | |
1103 } | |
1104 | |
1105 void | |
1106 code_label(int labelno) | |
1107 { | |
1108 #ifdef __APPLE__ | |
1109 clear_ptr_cache(); | |
1110 #endif | |
1111 printf("_%d:\n",labelno); | |
1112 } | |
1113 | |
1114 void | |
1115 code_gvar(int e1,int creg) { | |
1116 use_int(creg); | |
1117 #ifdef __APPLE__ | |
1118 int r = get_ptr_cache(ncaddr(e1)); | |
1119 if (cadr(e1)) { | |
1120 printf("\tleal %d(%s),%s\n", cadr(e1),register_name(r,0), | |
1121 register_name(creg,0)); | |
1122 } else { | |
1123 printf("\tmovl %s,%s\n", register_name(r,0), register_name(creg,0)); | |
1124 } | |
1125 #else | |
1126 if (cadr(e1)) { | |
1127 printf("\tmovl $%s+%d,%s\n",(ncaddr(e1))->nm,cadr(e1), | |
1128 register_name(creg,0)); | |
1129 } else { | |
1130 printf("\tmovl $%s,%s\n",(ncaddr(e1))->nm,register_name(creg,0)); | |
1131 } | |
1132 #endif | |
1133 | |
1134 } | |
1135 | |
1136 void | |
1137 code_rgvar(int e1,int creg) { | |
1138 use_int(creg); | |
1139 #ifdef __APPLE__ | |
1140 int r = get_ptr_cache(ncaddr(e1)); | |
1141 if (cadr(e1)) { | |
1142 printf("\tmovl %d(%s),%s\n", cadr(e1),register_name(r,0), | |
1143 register_name(creg,0)); | |
1144 } else { | |
1145 printf("\tmovl (%s),%s\n", register_name(r,0), register_name(creg,0)); | |
1146 } | |
1147 #else | |
1148 if (cadr(e1)) { | |
1149 printf("\tmovl %s+%d,%s\n",(ncaddr(e1))->nm,cadr(e1), | |
1150 register_name(creg,0)); | |
1151 } else | |
1152 printf("\tmovl %s,%s\n",(ncaddr(e1))->nm,register_name(creg,0)); | |
1153 #endif | |
1154 | |
1155 } | |
1156 | |
1157 static char * | |
1158 cload(int sign,int sz) { | |
1159 return sz==1?(sign?"movsbl":"movzbl"): | |
1160 sz==SIZE_OF_SHORT?(sign?"movswl":"movzwl"):"movl"; | |
1161 } | |
1162 | |
1163 void | |
1164 code_crgvar(int e1,int creg,int sign,int sz){ | |
1165 use_int(creg); | |
1166 #ifdef __APPLE__ | |
1167 int r = get_ptr_cache(ncaddr(e1)); | |
1168 if (cadr(e1)) { | |
1169 printf("\t%s %d(%s),%s\n", cload(sign,sz),cadr(e1),register_name(r,0), | |
1170 register_name(creg,0)); | |
1171 } else { | |
1172 printf("\t%s (%s),%s\n", cload(sign,sz), | |
1173 register_name(r,0), register_name(creg,0)); | |
1174 } | |
1175 #else | |
1176 if (cadr(e1)) { | |
1177 printf("\t%s %s+%d,%s\n",cload(sign,sz), | |
1178 (ncaddr(e1))->nm,cadr(e1),register_name(creg,0)); | |
1179 } else | |
1180 printf("\t%s %s,%s\n",cload(sign,sz), | |
1181 (ncaddr(e1))->nm,register_name(creg,0)); | |
1182 #endif | |
1183 | |
1184 } | |
1185 | |
1186 | |
1187 void | |
1188 code_lvar(int e2,int creg) { | |
1189 use_int(creg); | |
1190 printf("\tlea "); lvar(e2); | |
1191 printf(",%s\n",register_name(creg,0)); | |
1192 } | |
1193 | |
1194 | |
1195 void | |
1196 code_register(int e2,int creg) { | |
1197 use_int(creg); | |
1198 if (e2!=creg) | |
1199 printf("\tmovl %s,%s\n",register_name(e2,0),register_name(creg,0)); | |
1200 } | |
1201 | |
1202 | |
1203 void | |
1204 code_rlvar(int e2,int reg) { | |
1205 use_int(reg); | |
1206 printf("\tmovl "); lvar(e2); | |
1207 printf(",%s\n",register_name(reg,0)); | |
1208 } | |
1209 | |
1210 extern void | |
1211 code_i2c(int reg) | |
1212 { | |
1213 use_data_reg(reg,1); | |
1214 printf("\t%s %s,%s\n",cload(1,1), | |
1215 register_name(reg,1),register_name(reg,0)); | |
1216 } | |
1217 | |
1218 extern void | |
1219 code_i2s(int reg) | |
1220 { | |
1221 use_data_reg(reg,1); | |
1222 printf("\t%s %s,%s\n",cload(1,SIZE_OF_SHORT), | |
1223 register_name(reg,2),register_name(reg,0)); | |
1224 } | |
1225 | |
1226 extern void | |
1227 code_u2uc(int reg) | |
1228 { | |
1229 use_data_reg(reg,1); | |
1230 printf("\t%s %s,%s\n",cload(0,1), | |
1231 register_name(reg,1),register_name(reg,0)); | |
1232 } | |
1233 | |
1234 extern void | |
1235 code_u2us(int reg) | |
1236 { | |
1237 use_data_reg(reg,1); | |
1238 printf("\t%s %s,%s\n",cload(0,SIZE_OF_SHORT), | |
1239 register_name(reg,2),register_name(reg,0)); | |
1240 } | |
1241 | |
1242 void | |
1243 code_crlvar(int e2,int reg,int sign,int sz) { | |
1244 use_int(reg); | |
1245 printf("\t%s ",cload(sign,sz)); lvar(e2); | |
1246 printf(",%s\n",register_name(reg,0)); | |
1247 | |
1248 } | |
1249 | |
1250 | |
1251 void | |
1252 code_fname(NMTBL *n,int creg) { | |
1253 use_int(creg); | |
1254 #ifdef __APPLE__ | |
1255 if (n->sc==STATIC) { | |
1256 printf("\tleal _%s-_%d(%%ebx),%s\n", n->nm, goffset_label, | |
1257 register_name(creg,0)); | |
1258 return; | |
1259 } | |
1260 int r = get_ptr_cache(n); | |
1261 printf("\tmovl %s,%s\n", register_name(r,0), register_name(creg,0)); | |
1262 #else | |
1263 printf("\tmovl $%s,%s\n",n->nm,register_name(creg,0)); | |
1264 #endif | |
1265 } | |
1266 | |
1267 void | |
1268 code_label_value(int label,int reg) { | |
1269 use_int(reg); | |
1270 #ifdef __APPLE__ | |
1271 printf("\tleal _%d-_%d(%%ebx),%s\n", | |
1272 label,goffset_label,register_name(reg,0)); | |
1273 #else | |
1274 printf("\tleal _%d,%s\n",label,register_name(reg,0)); | |
1275 #endif | |
1276 } | |
1277 | |
1278 void | |
1279 code_const(int e2,int creg) { | |
1280 use_int(creg); | |
1281 printf("\tmovl $%d,%s\n",e2,register_name(creg,0)); | |
1282 } | |
1283 | |
1284 void | |
1285 code_neg(int creg) { | |
1286 use_int(creg); | |
1287 printf("\tnegl %s\n", register_name(creg,0)); | |
1288 } | |
1289 | |
1290 | |
1291 void | |
1292 code_not(int creg) { | |
1293 use_int(creg); | |
1294 printf("\tnotl %s\n", register_name(creg,0)); | |
1295 } | |
1296 | |
1297 | |
1298 void | |
1299 code_lnot(int creg) { | |
1300 char *xrn; | |
1301 | |
1302 use_data_reg(creg,1); | |
1303 xrn = register_name(creg,1); | |
1304 printf("\tcmpl $0,%s\n", register_name(creg,0)); | |
1305 printf("\tsete %s\n", xrn); | |
1306 printf("\tmovzbl %s,%s\n", xrn,register_name(creg,0)); | |
1307 } | |
1308 | |
1309 void | |
1310 code_preinc(int e1,int e2,int dir,int sign,int sz,int reg) { | |
1311 char *xrn; | |
1312 if (car(e2)==REGISTER) { | |
1313 use_int(reg); | |
1314 printf("\taddl $%d,%s\n",dir,register_name(cadr(e2),0)); | |
1315 if (use) | |
1316 printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(reg,0)); | |
1317 return; | |
1318 } | |
1319 g_expr(e2); | |
1320 xrn = register_name(creg,0); | |
1321 use_int(reg); | |
1322 printf("\t%s $%d,(%s)\n",(sz==1)?"addb":(sz==SIZE_OF_SHORT)?"addw":"addl",dir,xrn); | |
1323 if (use) | |
1324 printf("\t%s (%s),%s\n",cload(sign,sz),xrn,register_name(reg,0)); | |
1325 } | |
1326 | |
1327 | |
1328 void | |
1329 code_postinc(int e1,int e2,int dir,int sign,int sz,int reg) { | |
1330 char *xrn; | |
1331 if (car(e2)==REGISTER) { | |
1332 use_int(reg); | |
1333 if (use) | |
1334 printf("\tmovl %s,%s\n",register_name(cadr(e2),0),register_name(reg,0)); | |
1335 printf("\taddl $%d,%s\n",dir,register_name(cadr(e2),0)); | |
1336 | |
1337 return; | |
1338 } | |
1339 g_expr(e2); | |
1340 emit_push(); | |
1341 xrn = register_name((e2=emit_pop(0)),0); | |
1342 use_int(reg); | |
1343 if (use) | |
1344 printf("\t%s (%s),%s\n",cload(sign,sz),xrn,register_name(reg,0)); | |
1345 printf("\t%s $%d,(%s)\n",(sz==1)?"addb":(sz==SIZE_OF_SHORT)?"addw":"addl",dir,xrn); | |
1346 emit_pop_free(e2); | |
1347 } | |
1348 | |
1349 | |
1350 | |
1351 void | |
1352 code_return(int creg) { | |
1353 use_int(creg); | |
1354 printf("\tleal _%d,%s\n",retcont,register_name(creg,0)); | |
1355 } | |
1356 | |
1357 | |
1358 void | |
1359 code_environment(int creg) { | |
1360 use_int(creg); | |
1361 printf("\tmovl %%ebp,%s\n",register_name(creg,0)); | |
1362 } | |
1363 | |
1364 static int rexpr_bool(int e1,int reg); | |
1365 #if FLOAT_CODE | |
1366 static int drexpr_bool(int e1,int reg); | |
1367 #endif | |
1368 | |
1369 void | |
1370 code_bool(int e1,int reg) { | |
1371 char *xrn; | |
1372 int e2,e3; | |
1373 if (rexpr_bool(e1,reg)) return; | |
1374 #if FLOAT_CODE | |
1375 if (drexpr_bool(e1,reg)) return; | |
1376 #endif | |
1377 b_expr(e1,1,e2=fwdlabel(),1); /* including > < ... */ | |
1378 if (use) { | |
1379 use_int(reg); | |
1380 xrn = register_name(reg,0); | |
1381 printf("\txorl %s,%s\n",xrn,xrn); | |
1382 jmp(e3=fwdlabel()); | |
1383 fwddef(e2); | |
1384 printf("\tmovl $1,%s\n",xrn); | |
1385 fwddef(e3); | |
1386 } else { | |
1387 fwddef(e2); | |
1388 } | |
1389 } | |
1390 | |
1391 static char * | |
1392 code_gt(int cond) { | |
1393 return (cond?"g":"le"); | |
1394 } | |
1395 | |
1396 static char * | |
1397 code_ugt(int cond) { | |
1398 return (cond?"a":"be"); | |
1399 } | |
1400 | |
1401 static char * | |
1402 code_ge(int cond) { | |
1403 return (cond?"ge":"l"); | |
1404 } | |
1405 | |
1406 static char * | |
1407 code_uge(int cond) { | |
1408 return (cond?"ae":"b"); | |
1409 } | |
1410 | |
1411 static char * | |
1412 code_eq(int cond) { | |
1413 return (cond?"e":"ne"); | |
1414 } | |
1415 | |
1416 void | |
1417 code_cmp_crgvar(int e1,int reg,int sz,int label,int cond) { | |
1418 use_int(reg); | |
1419 #ifdef __APPLE__ | |
1420 int r = get_ptr_cache(ncaddr(e1)); | |
1421 if (cadr(e1)) { | |
1422 if (sz==1) | |
1423 printf("\tcmpb $0,%d(%s)\n",cadr(e1),register_name(r,0)); | |
1424 else if (sz==SIZE_OF_SHORT) | |
1425 printf("\tcmpw $0,%d(%s)\n",cadr(e1),register_name(r,0)); | |
1426 } else { | |
1427 if (sz==1) | |
1428 printf("\tcmpb $0,(%s)\n",register_name(r,0)); | |
1429 else if (sz==SIZE_OF_SHORT) | |
1430 printf("\tcmpw $0,(%s)\n",register_name(r,0)); | |
1431 } | |
1432 #else | |
1433 if (cadr(e1)) { | |
1434 if (sz==1) | |
1435 printf("\tcmpb $0,%s+%d\n",(ncaddr(e1))->nm,cadr(e1)); | |
1436 else if (sz==SIZE_OF_SHORT) | |
1437 printf("\tcmpw $0,%s+%d\n",(ncaddr(e1))->nm,cadr(e1)); | |
1438 } else { | |
1439 if (sz==1) | |
1440 printf("\tcmpb $0,%s\n",(ncaddr(e1))->nm); | |
1441 else if (sz==SIZE_OF_SHORT) | |
1442 printf("\tcmpw $0,%s\n",(ncaddr(e1))->nm); | |
1443 } | |
1444 #endif | |
1445 jcond(label,cond); | |
1446 } | |
1447 | |
1448 | |
1449 void | |
1450 code_cmp_crlvar(int e1,int reg,int sz,int label,int cond) { | |
1451 use_int(reg); | |
1452 if (sz==1) { | |
1453 printf("\tcmpb $0,"); lvar(e1); printf("\n"); | |
1454 } else if (sz==SIZE_OF_SHORT) { | |
1455 printf("\tcmpw $0,"); lvar(e1); printf("\n"); | |
1456 } | |
1457 jcond(label,cond); | |
1458 } | |
1459 | |
1460 | |
1461 void | |
1462 code_cmp_rgvar(int e1,int reg,int label,int cond) { | |
1463 use_int(reg); | |
1464 #ifdef __APPLE__ | |
1465 int r = get_ptr_cache(ncaddr(e1)); | |
1466 if (cadr(e1)) | |
1467 printf("\tcmpl $0,%d(%s)\n",cadr(e1),register_name(r,0)); | |
1468 else | |
1469 printf("\tcmpl $0,(%s)\n",register_name(r,0)); | |
1470 #else | |
1471 if (cadr(e1)) | |
1472 printf("\tcmpl $0,%s+%d\n",(ncaddr(e1))->nm,cadr(e1)); | |
1473 else | |
1474 printf("\tcmpl $0,%s\n",(ncaddr(e1))->nm); | |
1475 #endif | |
1476 jcond(label,cond); | |
1477 } | |
1478 | |
1479 | |
1480 void | |
1481 code_cmp_rlvar(int e1,int reg,int label,int cond) { | |
1482 use_int(reg); | |
1483 printf("\tcmpl $0,"); lvar(e1); printf("\n"); | |
1484 jcond(label,cond); | |
1485 } | |
1486 | |
1487 | |
1488 void | |
1489 code_cmp_register(int e2,int label,int cond) { | |
1490 use_int(e2); | |
1491 printf("\tcmpl $0,%s\n",register_name(e2,0)); | |
1492 jcond(label,cond); | |
1493 } | |
1494 | |
1495 | |
1496 void | |
1497 code_string(int e1,int creg) | |
1498 { | |
1499 char *s; | |
1500 int lb; | |
1501 NMTBL *n = ncaddr(e1); | |
1502 if ((lb=attr_value(n,LABEL))) { | |
1503 // already defined | |
1504 return code_label_value(lb,creg) ; | |
1505 } | |
1506 | |
1507 use_int(creg); | |
1508 s=n->nm; | |
1509 lb = emit_string_label(); | |
1510 ascii(s); | |
1511 if (output_mode==TEXT_EMIT_MODE) { | |
1512 printf(".text\n"); | |
1513 } else { | |
1514 text_mode(0); | |
1515 } | |
1516 #ifdef __APPLE__ | |
1517 printf("\tleal _%d-_%d(%%ebx),%s\n",lb, | |
1518 goffset_label, | |
1519 register_name(creg,0)); | |
1520 #else | |
1521 printf("\tlea _%d,%s\n",lb,register_name(creg,0)); | |
1522 #endif | |
1523 set_attr(n,LABEL,lb); | |
1524 } | |
1525 | |
1526 #define MAX_COPY_LEN 20 | |
1527 | |
1528 /* ARG_ORDER==1 case do not allow library call in emit_copy | |
1529 */ | |
1530 | |
1531 void | |
1532 emit_copy(int from,int to,int length,int offset,int value,int det) | |
1533 { | |
1534 int dreg; | |
1535 char *drn,*frn; | |
1536 char *trn; | |
1537 use_int(from); | |
1538 use_int(to); | |
1539 frn = register_name(from,0); | |
1540 trn = register_name(to,0); | |
1541 | |
1542 /* length <0 means upward direction copy */ | |
1543 switch (length) { | |
1544 case 0: break; | |
1545 case 1: case -1: | |
1546 drn = register_name(dreg = get_data_register(),1); | |
1547 printf("\tmovb %d(%s),%s\n",offset,frn,drn); | |
1548 printf("\tmovb %s,%d(%s)\n",drn,offset,trn); | |
1549 free_register(dreg); | |
1550 break; | |
1551 case 2: case -2: | |
1552 drn = register_name(dreg = get_data_register(),2); | |
1553 printf("\tmovw %d(%s),%s\n",offset,frn,drn); | |
1554 printf("\tmovw %s,%d(%s)\n",drn,offset,trn); | |
1555 free_register(dreg); | |
1556 break; | |
1557 case 4: case -4: | |
1558 drn = register_name(dreg = get_register(),0); | |
1559 printf("\tmovl %d(%s),%s\n",offset,frn,drn); | |
1560 printf("\tmovl %s,%d(%s)\n",drn,offset,trn); | |
1561 free_register(dreg); | |
1562 break; | |
1563 default: | |
1564 if (length <0) { | |
1565 if (length > -MAX_COPY_LEN) { | |
1566 for(;length<=-4;length+=4,offset-=4) | |
1567 emit_copy(from,to,-4,offset-4,0,det); | |
1568 for(;length<=-2;length+=2,offset-=2) | |
1569 emit_copy(from,to,-2,offset-2,0,det); | |
1570 if(length<0) | |
1571 emit_copy(from,to,length,offset-1,0,det); | |
1572 break; | |
1573 } | |
1574 } else if (length <=MAX_COPY_LEN) { | |
1575 for(;length>=4;length-=4,offset+=4) | |
1576 emit_copy(from,to,4,offset,0,det); | |
1577 for(;length>=2;length-=2,offset+=2) | |
1578 emit_copy(from,to,2,offset,0,det); | |
1579 if(length>0) | |
1580 emit_copy(from,to,length,offset,0,det); | |
1581 break; | |
1582 } | |
1583 // should be parallel_rassign.... | |
1584 // clear_ptr_cache(); | |
1585 // code_save_stacks(); | |
1586 | |
1587 printf("\tpushl %%esi\n"); | |
1588 printf("\tpushl %%edi\n"); | |
1589 printf("\tpushl %%ecx\n"); | |
1590 printf("\tpushl %s\n",register_name(from,0)); | |
1591 printf("\tpushl %s\n",register_name(to,0)); | |
1592 printf("\tpopl %%edi\n"); | |
1593 printf("\tpopl %%esi\n"); | |
1594 if (length<0) { | |
1595 printf("\tmovl $%d,%%ecx\n",-length/4); | |
1596 printf("\taddl $%d,%%esi\n",-length-4); | |
1597 printf("\taddl $%d,%%edi\n",-length-4 | |
1598 +(to==REG_ESP?4*4:0) | |
1599 ); | |
1600 printf("\tstd\n\trep\n\tmovsl\n"); | |
1601 printf("\tpopl %%ecx\n"); | |
1602 printf("\tpopl %%edi\n"); | |
1603 printf("\tpopl %%esi\n"); | |
1604 if(length%4) { | |
1605 offset = offset+length/SIZE_OF_INT; | |
1606 length=length%4; | |
1607 emit_copy(from,to,length,offset,0,det); | |
1608 } | |
1609 } else { | |
1610 printf("\tmovl $%d,%%ecx\n",length/4); | |
1611 if (to==REG_ESP) | |
1612 printf("\taddl $%d,%%edi\n",4*4); | |
1613 printf("\tcld\n\trep\n\tmovsl\n"); | |
1614 printf("\tpopl %%ecx\n"); | |
1615 printf("\tpopl %%edi\n"); | |
1616 printf("\tpopl %%esi\n"); | |
1617 if(length%4) { | |
1618 offset = offset+length/SIZE_OF_INT; | |
1619 length=length%4; | |
1620 emit_copy(from,to,length,offset,0,det); | |
1621 } | |
1622 } | |
1623 } | |
1624 if (value) { | |
1625 /* creg must point top of the destination data */ | |
1626 /* this code is necessary for the value of assignment or function call */ | |
1627 /* otherwise we don't need this */ | |
1628 if(creg!=to) { | |
1629 if (regs[creg]!=REG_VAR) free_register(creg); creg=to; | |
1630 } | |
1631 } | |
1632 } | |
1633 | |
1634 static int | |
1635 push_struct(int e4,int t, int arg) | |
1636 { | |
1637 int length,dreg; | |
1638 g_expr(e4); | |
1639 length=size(t); | |
1640 if(length%SIZE_OF_INT) { | |
1641 length += SIZE_OF_INT - (length%SIZE_OF_INT); | |
1642 } | |
1643 emit_push(); | |
1644 code_lvar(cadr(arg),USE_CREG); | |
1645 dreg = emit_pop(0); | |
1646 | |
1647 // copy dreg to creg with length | |
1648 // try small amount copy | |
1649 /* downward direction copy */ | |
1650 emit_copy(dreg,creg,length,0,0,1); | |
1651 emit_pop_free(dreg); | |
1652 /* we have value in creg, it may be changed */ | |
1653 return length/SIZE_OF_INT; | |
1654 } | |
1655 | |
1656 static int | |
1657 simple_arg(int e3) | |
1658 { | |
1659 return !contains_p(e3,not_simple_p); | |
1660 } | |
1661 | |
1662 #define caller_arg_offset_v(arg) (ARG_LVAR_OFFSET+(arg)*SIZE_OF_INT) | |
1663 | |
1664 /* | |
1665 Eary implementation uses pushl arg for function call. gcc | |
1666 use the same arguement evaluation order. Of course, the | |
1667 order is unspecified in C language, but it is better to | |
1668 use same argument evaluation order. Especially for test | |
1669 program. | |
1670 */ | |
1671 #define ARG_ORDER 1 | |
1672 #if (ARG_ORDER==1) | |
1673 | |
1674 static int delayed_arg; | |
1675 | |
1676 #endif | |
1677 | |
1678 static int | |
1679 compute_complex_arg(int e3,int reg_arg_list,int arg) { | |
1680 int t=caddr(e3); | |
1681 int e4 = car(e3); | |
1682 reg_arg_list = list2(arg,reg_arg_list); | |
1683 #if ARG_ORDER==1 | |
1684 delayed_arg = list2(assign_expr0(arg,e4,t,t),delayed_arg); | |
1685 #else | |
1686 g_expr_u(assign_expr0(arg,e4,t,t)); | |
1687 #endif | |
1688 | |
1689 | |
1690 | |
1691 car(e3) = arg; | |
1692 return reg_arg_list; | |
1693 } | |
1694 | |
1695 | |
1696 static void | |
1697 increment_function_arg(int e3,int *pnargs,int *preg_arg,int *pfreg_arg) { | |
1698 int nargs=0,reg_arg=0,freg_arg=0; | |
1699 int t=caddr(e3); | |
1700 if(scalar(t)) { | |
1701 nargs ++ ; reg_arg++; freg_arg++; | |
1702 } else if (t==LONGLONG||t==ULONGLONG||t==DOUBLE) { | |
1703 nargs ++ ; reg_arg++; | |
1704 nargs ++ ; reg_arg++; | |
1705 } else if (t==FLOAT) { | |
1706 reg_arg ++ ; freg_arg++; | |
1707 nargs += size(t)/SIZE_OF_INT; | |
1708 } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { | |
1709 nargs += round4(size(t))/SIZE_OF_INT; | |
1710 } else { | |
1711 error(TYERR); | |
1712 nargs ++ ; | |
1713 } | |
1714 *pnargs += nargs; | |
1715 *preg_arg += reg_arg; | |
1716 *pfreg_arg += freg_arg; | |
1717 } | |
1718 | |
1719 #define AS_SAVE 1 | |
1720 #define AS_ARG 0 | |
1721 | |
1722 static int | |
1723 get_input_arg(int t,int mode,int nargs,int reg_arg,int freg_arg) | |
1724 { | |
1725 if(scalar(t)) { | |
1726 if (mode==AS_SAVE) { | |
1727 if (parse_mode) | |
1728 return get_register_var(0); | |
1729 return list3n(LVAR,new_lvar(size(t)),0); | |
1730 } else | |
1731 return list3n(LVAR,caller_arg_offset_v(nargs),0); | |
1732 } else if (t==LONGLONG||t==ULONGLONG) { | |
1733 if (mode==AS_SAVE) { | |
1734 if (parse_mode) | |
1735 return get_lregister_var(0); | |
1736 return list3n(LVAR,new_lvar(size(t)),0); | |
1737 } else | |
1738 return list3n(LVAR,caller_arg_offset_v(nargs),0); | |
1739 } else if (t==FLOAT) { | |
1740 if (mode==AS_SAVE) { | |
1741 if (parse_mode) | |
1742 return get_dregister_var(0,0); | |
1743 return list3n(LVAR,new_lvar(size(t)),0); | |
1744 } else | |
1745 return list3n(LVAR,caller_arg_offset_v(nargs),0); | |
1746 } else if (t==DOUBLE) { | |
1747 if (mode==AS_SAVE) { | |
1748 if (parse_mode) | |
1749 return get_dregister_var(0,1); | |
1750 return list3n(LVAR,new_lvar(size(t)),0); | |
1751 } else | |
1752 return list3n(LVAR,caller_arg_offset_v(nargs),0); | |
1753 } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { | |
1754 if (mode==AS_SAVE) { | |
1755 if (parse_mode) | |
1756 return get_register_var(0); | |
1757 return list3n(LVAR,new_lvar(size(t)),0); | |
1758 } else | |
1759 return list3n(LVAR,caller_arg_offset_v(nargs),0); | |
1760 } else { | |
1761 error(-1); | |
1762 if (parse_mode) | |
1763 return get_register_var(0); | |
1764 return list3n(LVAR,new_lvar(size(t)),0); | |
1765 } | |
1766 } | |
1767 | |
1768 static void | |
1769 code_call(int e2,NMTBL *fn,int jmp) | |
1770 { | |
1771 if (car(e2) == FNAME) { | |
1772 #ifdef __APPLE__ | |
1773 printf("\tcall\tL_%s$stub\n",fn->nm); | |
1774 #else | |
1775 printf("\tcall\t%s\n",fn->nm); | |
1776 #endif | |
1777 } else { | |
1778 printf("\tcall\t*%s\n",register_name(REG_EAX,0)); | |
1779 } | |
1780 } | |
1781 | |
1782 int | |
1783 function(int e1) | |
1784 { | |
1785 | |
1786 int e2,e3,e4,e5,nargs,t; | |
1787 int arg,reg_arg,freg_arg,arg_assign; | |
1788 int dots; | |
1789 int reg_arg_list=0,ret_type,special_lvar; | |
1790 NMTBL *fn = 0; | |
1791 int jmp = 0; | |
1792 int complex_; | |
1793 int pnargs,preg_arg,pfreg_arg; | |
1794 int stargs; | |
1795 int half_register = 0; | |
1796 #if (ARG_ORDER==1) | |
1797 int save_delayed_arg = delayed_arg; | |
1798 int as_save = AS_ARG; // 1st pushed argment will evaluate at the last | |
1799 delayed_arg = 0; | |
1800 #else | |
1801 const int as_save = AS_SAVE; | |
1802 #endif | |
1803 | |
1804 special_lvar = -1; | |
1805 ret_type = function_type(cadddr(e1),&dots); | |
1806 if (caddr(cadddr(e1))==0) dots=1; | |
1807 | |
1808 arg_assign = 0; | |
1809 e2 = cadr(e1); | |
1810 if (car(e2) == FNAME) { | |
1811 fn=ncaddr(e2); | |
1812 } else { | |
1813 if (car(e2)==INDIRECT) e2=cadr(e2); // (*func)(i) case | |
1814 jmp = list3(REGISTER,REG_EAX,0); | |
1815 | |
1816 if (!simple_arg(e2)) { | |
1817 e3=get_register_var(0); | |
1818 reg_arg_list = list2(e3,reg_arg_list); | |
1819 g_expr_u(assign_expr0(e3,e2,INT,INT)); | |
1820 e2=e3; | |
1821 } | |
1822 arg_assign = list2(assign_expr0(jmp,e2,INT,INT),arg_assign); | |
1823 } | |
1824 /* First we execute complex argument to avoid interaction with | |
1825 input variables. Remain the last complex argument in complex_. */ | |
1826 stargs = 0; | |
1827 complex_ = 0; | |
1828 nargs = reg_arg = freg_arg = 0; | |
1829 pnargs = preg_arg = pfreg_arg = 0; | |
1830 for (e3 = e1 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) { | |
1831 t=caddr(e3); | |
1832 if (reg_arg==3 && (t==DOUBLE||t==LONGLONG||t==ULONGLONG)) { | |
1833 half_register=1; | |
1834 } | |
1835 if ((e5= !simple_arg(car(e3)))) { | |
1836 if (complex_) { | |
1837 arg = get_input_arg(caddr(complex_),as_save, | |
1838 pnargs,preg_arg,pfreg_arg); | |
1839 #if ARG_ORDER==1 | |
1840 as_save = AS_SAVE; | |
1841 #endif | |
1842 reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); | |
1843 } | |
1844 // memorise last complex arg parameter | |
1845 pnargs=nargs;preg_arg=reg_arg;pfreg_arg=freg_arg; | |
1846 complex_ = e3; | |
1847 } | |
1848 if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { | |
1849 // The struct should be pushed after complex arguments. | |
1850 if (e5) { // compute address only, complex_ is me now. Clear it. | |
1851 complex_ = 0; | |
1852 e4 = car(e3); | |
1853 if (car(e4)==RSTRUCT) e4 = cadr(e4); | |
1854 if (!simple_arg(e4)) { | |
1855 // Calculate complex struct address here. | |
1856 // If simple, leave it. | |
1857 arg = get_register_var(0); | |
1858 #if ARG_ORDER==1 | |
1859 delayed_arg = list2( | |
1860 assign_expr0(arg,e4,INT,INT), | |
1861 delayed_arg); | |
1862 #else | |
1863 g_expr_u(assign_expr0(arg,e4,INT,INT)); | |
1864 #endif | |
1865 car(e3)=arg; | |
1866 reg_arg_list = list2(arg,reg_arg_list); | |
1867 | |
1868 car(e3) = rvalue_t(arg,INT); | |
1869 } | |
1870 } | |
1871 stargs = list4(e3,stargs,nargs,reg_arg); | |
1872 } | |
1873 increment_function_arg(e3,&nargs,®_arg,&freg_arg); | |
1874 } | |
1875 #if (ARG_ORDER==1) | |
1876 if (complex_) { | |
1877 arg = get_input_arg(caddr(complex_),as_save, | |
1878 pnargs,preg_arg,pfreg_arg); | |
1879 reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); | |
1880 } | |
1881 for(;delayed_arg;delayed_arg = cadr(delayed_arg)) { | |
1882 g_expr_u(car(delayed_arg)); | |
1883 } | |
1884 #endif | |
1885 | |
1886 /* now all input register vars are free */ | |
1887 code_save_stacks(); | |
1888 | |
1889 // set_lreg(LREG_LREGISTER,0); | |
1890 set_freg(FREG_FREGISTER,0); | |
1891 set_ireg(CREG_REGISTER,0); | |
1892 | |
1893 // Struct arguments need emit_copy. it destructs 3 input registers. | |
1894 // But it returns no value on a register. So calculate it here. | |
1895 // We cannot do this in the previous loop, because the copied struct may be | |
1896 // override by other complex arguments. But before this we have to check | |
1897 // complex_. | |
1898 | |
1899 // ARG_ORDER==1 case put the last value on the top of stack. | |
1900 // emit_copy/push_struct must preserve argument stack, i.e. | |
1901 // no library call is allowed. | |
1902 | |
1903 if (stargs) { | |
1904 #if (ARG_ORDER!=1) | |
1905 if (complex_) { | |
1906 arg = get_input_arg(caddr(complex_),AS_SAVE, | |
1907 pnargs,preg_arg,pfreg_arg); | |
1908 reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); | |
1909 } | |
1910 #endif | |
1911 for(stargs=reverse0(stargs);stargs;stargs = cadr(stargs)) { | |
1912 e3 = car(stargs); | |
1913 e4 = car(e3); | |
1914 t = caddr(e3); | |
1915 arg = get_input_arg(t,AS_ARG,caddr(stargs),cadddr(stargs),0); | |
1916 push_struct(e4,t,arg); | |
1917 car(e3)=0; // done | |
1918 | |
1919 | |
1920 } | |
1921 #if (ARG_ORDER!=1) | |
1922 } else { | |
1923 // last complex argument can use input register | |
1924 if (complex_) { | |
1925 arg = get_input_arg(caddr(complex_),AS_ARG,pnargs,preg_arg,pfreg_arg) | |
1926 ; | |
1927 reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); | |
1928 | |
1929 car(complex_) = 0; // done. | |
1930 | |
1931 | |
1932 } | |
1933 #endif | |
1934 } | |
1935 | |
1936 nargs = reg_arg = freg_arg = 0; | |
1937 // calc stack arguments first, it may requires extra registers, | |
1938 // and we can still use input registers now. | |
1939 for (e3 = e1; e3; | |
1940 increment_function_arg(e3,&nargs,®_arg,&freg_arg), | |
1941 e3 = cadr(e3)) { | |
1942 if (!(e4=car(e3))) continue; | |
1943 t=caddr(e3); | |
1944 arg = get_input_arg(t,AS_ARG,nargs,reg_arg,freg_arg); | |
1945 if (car(arg)!=LVAR) continue; | |
1946 g_expr_u(assign_expr0(arg,e4,t,t)); | |
1947 car(e3)=0; // done | |
1948 } | |
1949 if (max_func_args<nargs) max_func_args=nargs; | |
1950 for(;arg_assign;arg_assign=cadr(arg_assign)) { | |
1951 g_expr_u(car(arg_assign)); | |
1952 } | |
1953 clear_ptr_cache(); | |
1954 code_call(e2,fn,jmp); | |
1955 free_register_var(reg_arg_list); | |
1956 if (ret_type==DOUBLE||ret_type==FLOAT) { | |
1957 } else if (ret_type==LONGLONG||ret_type==ULONGLONG) { | |
1958 use_longlong0(USE_CREG); | |
1959 } else if (ret_type==VOID) { | |
1960 } else { | |
1961 if (use) | |
1962 set_ireg(RET_REGISTER,0); | |
1963 else | |
1964 set_ireg(CREG_REGISTER,0); | |
1965 } | |
1966 #if (ARG_ORDER==1) | |
1967 delayed_arg = save_delayed_arg; | |
1968 #endif | |
1969 return ret_type; | |
1970 } | |
1971 | |
1972 void | |
1973 code_alloca(int e1,int reg) | |
1974 { | |
1975 char *crn; | |
1976 | |
1977 if (!is_const(e1)) { | |
1978 g_expr(list3(BAND,list3(ADD,e1,list2(CONST,15)),list2(CONST,~15))); | |
1979 use_int(reg); | |
1980 } else { | |
1981 use_int(reg); | |
1982 code_const(round16(cadr(e1)),reg); | |
1983 } | |
1984 crn = register_name(reg,0); | |
1985 printf("\tsubl\t%s, %%esp\n",crn); | |
1986 if (!max_func_arg_label) max_func_arg_label = fwdlabel(); | |
1987 printf("\tmovl $%s%d,%s\n",lpfx,max_func_arg_label ,crn); | |
1988 printf("\tadd\t%%esp, %s\n",crn); | |
1989 } | |
1990 | |
1991 void | |
1992 code_frame_pointer(int e3) { | |
1993 use_int(e3); | |
1994 printf("\tmovl %s,%%ebp\n",register_name(e3,0)); | |
1995 } | |
1996 | |
1997 int | |
1998 code_frame_pointer_register() | |
1999 { | |
2000 return list2(REGISTER,REG_fp); | |
2001 } | |
2002 | |
2003 void | |
2004 code_fix_frame_pointer(int disp_offset) { | |
2005 // must be empty | |
2006 } | |
2007 | |
2008 void | |
2009 code_jmp(char *s) { | |
2010 #ifdef __APPLE__ | |
2011 printf("\tjmp\tL_%s$stub\n",s); | |
2012 #else | |
2013 printf("\tjmp %s\n",s); | |
2014 #endif | |
2015 } | |
2016 | |
2017 | |
2018 void | |
2019 code_indirect_jmp(int e2) { | |
2020 use_int(e2); | |
2021 printf("\tjmp *%s\n",register_name(e2,0)); | |
2022 } | |
2023 | |
2024 void | |
2025 code_rindirect(int e1, int reg,int offset, int sign,int byte) | |
2026 { | |
2027 char *crn,*op; | |
2028 g_expr(e1); | |
2029 op=cload(sign,byte); | |
2030 crn = register_name(creg,0); | |
2031 use_int(reg); | |
2032 printf("\t%s %d(%s),%s\n",op,offset,crn,register_name(reg,0)); | |
2033 } | |
2034 | |
2035 #if FLOAT_CODE | |
2036 int | |
2037 code_drindirect(int e1, int reg,int offset, int d) | |
2038 { | |
2039 g_expr(e1); | |
2040 printf("\t%s %d(%s)\n",fload(d),offset,register_name(creg,0)); | |
2041 return DOUBLE; | |
2042 } | |
2043 #endif | |
2044 | |
2045 #if LONGLONG_CODE | |
2046 | |
2047 static void | |
2048 lload(int creg,int offset,int reg) | |
2049 { | |
2050 char *crn = register_name(creg,0); | |
2051 use_longlong(reg); | |
2052 if((reg==REG_L&&creg==REG_ESI)||(creg==REG_EAX)) { | |
2053 printf("\tmovl %d(%s),%s\n",offset+SIZE_OF_INT,crn,l_edx(reg)); | |
2054 printf("\tmovl %d(%s),%s\n",offset,crn,l_eax(reg)); | |
2055 } else { | |
2056 printf("\tmovl %d(%s),%s\n",offset,crn,l_eax(reg)); | |
2057 printf("\tmovl %d(%s),%s\n",offset+SIZE_OF_INT,crn,l_edx(reg)); | |
2058 } | |
2059 } | |
2060 | |
2061 int | |
2062 code_lrindirect(int e1, int reg, int offset, int us) | |
2063 { | |
2064 int reg0; | |
2065 g_expr(e1); | |
2066 reg0=creg; | |
2067 use_longlong(reg); | |
2068 lload(reg0,offset,reg); | |
2069 return LONGLONG; | |
2070 } | |
2071 #endif | |
2072 | |
2073 char * | |
2074 move(int byte) | |
2075 { | |
2076 return byte==1?"movb":byte==SIZE_OF_SHORT?"movw":"movl"; | |
2077 } | |
2078 | |
2079 void | |
2080 code_assign_gvar(int e2,int creg,int byte) { | |
2081 if (byte) { use_data_reg(creg,1); | |
2082 } else { use_int(creg); } | |
2083 #ifdef __APPLE__ | |
2084 int r = get_ptr_cache(ncaddr(e2)); | |
2085 if (cadr(e2)) | |
2086 printf("\t%s %s,%d(%s)\n",move(byte),register_name(creg,byte), | |
2087 cadr(e2),register_name(r,0)); | |
2088 else | |
2089 printf("\t%s %s,(%s)\n",move(byte),register_name(creg,byte), | |
2090 register_name(r,0)); | |
2091 #else | |
2092 if (cadr(e2)) | |
2093 printf("\t%s %s,%s+%d\n",move(byte),register_name(creg,byte),(ncaddr(e2))->nm,cadr(e2)); | |
2094 else | |
2095 printf("\t%s %s,%s\n",move(byte),register_name(creg,byte),(ncaddr(e2))->nm); | |
2096 #endif | |
2097 } | |
2098 | |
2099 void | |
2100 code_assign_lvar(int e2,int creg,int byte) { | |
2101 if (byte) { use_data_reg(creg,1); | |
2102 } else { use_int(creg); } | |
2103 printf("\t%s %s,",move(byte),register_name(creg,byte)); | |
2104 lvar(e2); printf("\n"); | |
2105 } | |
2106 | |
2107 void | |
2108 code_assign_register(int e2,int byte,int creg) { | |
2109 use_int(creg); | |
2110 if (creg!=e2) | |
2111 printf("\tmovl %s,%s\n",register_name(creg,0),register_name(e2,0)); | |
2112 } | |
2113 | |
2114 void | |
2115 code_assign(int e2,int byte,int creg) { | |
2116 use_int(e2); | |
2117 if (byte) { use_data_reg(creg,1); | |
2118 } else { use_int(creg); } | |
2119 printf("\t%s %s,(%s)\n",move(byte),register_name(creg,byte),register_name(e2,0)); | |
2120 } | |
2121 | |
2122 void | |
2123 code_register_assop(int e2,int reg, int op,int byte) { | |
2124 // reg <= reg(e2) op=reg | |
2125 use_int(reg); | |
2126 tosop(op,e2,reg); | |
2127 } | |
2128 | |
2129 void | |
2130 code_assop(int op,int creg,int byte,int sign) { | |
2131 int xreg; | |
2132 // (*pop()) op = creg | |
2133 // creg should be ecx | |
2134 | |
2135 use_int(creg); | |
2136 xreg = emit_pop(0); /* pop e3 value */ | |
2137 emit_push(); | |
2138 ld_indexx(byte,0,creg,ireg,sign); | |
2139 tosop(op,ireg,xreg); | |
2140 emit_pop_free(xreg); | |
2141 if (byte) { | |
2142 use_data_reg(ireg,1); | |
2143 } | |
2144 xreg = emit_pop(0); /* pop e3 value */ | |
2145 printf("\t%s %s,(%s)\n",move(byte),register_name(ireg,byte),register_name(xreg,0)); | |
2146 emit_pop_free(xreg); | |
2147 } | |
2148 | |
2149 int | |
2150 tosop_operand_safe_p(int op) | |
2151 { | |
2152 switch(op) { | |
2153 case ADD: case SUB: case CMP: | |
2154 case BAND: case EOR: case BOR: | |
2155 case MUL: case UMUL: | |
2156 return 1; | |
2157 default: return 0; | |
2158 } | |
2159 } | |
2160 | |
2161 void | |
2162 tosop(int op,int reg,int oreg) | |
2163 { | |
2164 int ox=0; | |
2165 char *orn,*crn; | |
2166 // creg = creg op oreg | |
2167 | |
2168 use_int(reg); | |
2169 | |
2170 if(oreg==-1) { | |
2171 error(-1); | |
2172 } else if (oreg<= -REG_LVAR_OFFSET) { | |
2173 ox = get_register(); if (ox<0) error(-1); | |
2174 code_rlvar(oreg+REG_LVAR_OFFSET,ox); | |
2175 free_lvar(oreg+REG_LVAR_OFFSET); | |
2176 oreg = ox; | |
2177 } | |
2178 | |
2179 switch(op) { | |
2180 case LSHIFT: | |
2181 case ULSHIFT: | |
2182 shift("sall",oreg,reg); | |
2183 if(ox) free_register(ox); | |
2184 return; | |
2185 case RSHIFT: | |
2186 shift("sarl",oreg,reg); | |
2187 if(ox) free_register(ox); | |
2188 return; | |
2189 case URSHIFT: | |
2190 shift("shrl",oreg,reg); | |
2191 if(ox) free_register(ox); | |
2192 return; | |
2193 } | |
2194 // regs[oreg]=1; | |
2195 orn = register_name(oreg,0); | |
2196 crn = register_name(reg,0); | |
2197 switch(op) { | |
2198 case ADD: | |
2199 printf("\taddl %s,%s\n",orn,crn); | |
2200 break; | |
2201 case SUB: | |
2202 printf("\tsubl %s,%s\n",orn,crn); | |
2203 break; | |
2204 case CMP: | |
2205 printf("\tcmpl %s,%s\n",orn,crn); | |
2206 break; | |
2207 case BAND: | |
2208 printf("\tandl %s,%s\n",orn,crn); | |
2209 break; | |
2210 case EOR: | |
2211 printf("\txorl %s,%s\n",orn,crn); | |
2212 break; | |
2213 case BOR: | |
2214 printf("\torl %s,%s\n",orn,crn); | |
2215 break; | |
2216 case MUL: | |
2217 case UMUL: | |
2218 printf("\t%s %s,%s\n","imull",orn,crn); | |
2219 break; | |
2220 case DIV: | |
2221 case UDIV: | |
2222 case MOD: | |
2223 case UMOD: | |
2224 #ifdef __APPLE__ | |
2225 if (regs[REG_EDX]==PTRC_REG) | |
2226 clear_ptr_cache_reg(REG_EDX); | |
2227 #endif | |
2228 use_register(reg,REG_EAX,1); | |
2229 if (oreg==REG_EAX) oreg=reg; | |
2230 if (oreg==REG_EDX) { | |
2231 use_register(oreg,REG_ECX,1); | |
2232 oreg = REG_ECX; | |
2233 } | |
2234 orn = register_name(oreg,0); | |
2235 printf((op==DIV||op==MOD)? | |
2236 "\tcltd\n\tidivl %s\n": | |
2237 "\txor %%edx,%%edx\n\tdivl %s\n",orn); | |
2238 set_ireg((op==MOD||op==UMOD)?REG_EDX:REG_EAX,0); | |
2239 set_ireg(reg,1); | |
2240 break; | |
2241 } | |
2242 if(ox && ox!=ireg) free_register(ox); | |
2243 } | |
2244 | |
2245 int | |
2246 code_const_op_p(int op,int e) | |
2247 { | |
2248 if (car(e)!=CONST) return 0; | |
2249 if (op==DIV||op==UDIV) return ilog(cadr(e)); | |
2250 if (op==MOD||op==UMOD) return 0; | |
2251 else return 1; | |
2252 } | |
2253 | |
2254 void | |
2255 oprtc(int op,int reg,int orn) | |
2256 { | |
2257 char *crn; | |
2258 int datareg; | |
2259 use_int(reg); | |
2260 crn = register_name(reg,0); | |
2261 orn = cadr(orn); | |
2262 datareg=is_data_reg(reg); | |
2263 | |
2264 switch(op) { | |
2265 case LSHIFT: | |
2266 case ULSHIFT: | |
2267 printf("\tsall $%d,%s\n",orn,crn); | |
2268 return; | |
2269 case DIV: | |
2270 orn = ilog(orn); | |
2271 case RSHIFT: | |
2272 printf("\tsarl $%d,%s\n",orn,crn); | |
2273 return; | |
2274 case UDIV: | |
2275 orn = ilog(orn); | |
2276 case URSHIFT: | |
2277 printf("\tshrl $%d,%s\n",orn,crn); | |
2278 return; | |
2279 case ADD: | |
2280 printf("\taddl $%d,%s\n",orn,crn); | |
2281 break; | |
2282 case SUB: case CMP: | |
2283 printf("\tsubl $%d,%s\n",orn,crn); | |
2284 break; | |
2285 case BAND: | |
2286 if (datareg&&(orn & ~255)==~255) | |
2287 printf("\tandb $%d,%s\n",orn,register_name(reg,1)); | |
2288 else if (datareg&&(orn & ~65535)==~65535) | |
2289 printf("\tandw $%d,%s\n",orn,register_name(reg,2)); | |
2290 else | |
2291 printf("\tandl $%d,%s\n",orn,crn); | |
2292 break; | |
2293 case EOR: | |
2294 printf("\txorl $%d,%s\n",orn,crn); | |
2295 break; | |
2296 case BOR: | |
2297 if (datareg&&(orn & ~255)==0) | |
2298 printf("\tor $%d,%s\n",orn,register_name(reg,1)); | |
2299 else if (datareg&&(orn & ~65535)==0) | |
2300 printf("\tor $%d,%s\n",orn,register_name(reg,2)); | |
2301 else | |
2302 printf("\torl $%d,%s\n",orn,crn); | |
2303 break; | |
2304 case MUL: | |
2305 case UMUL: | |
2306 if (ilog(orn)) { | |
2307 printf("\tsall $%d,%s\n",ilog(orn),crn); | |
2308 } else | |
2309 printf("\t%s $%d,%s\n","imull",orn,crn); | |
2310 break; | |
2311 default: | |
2312 error(-1); | |
2313 } | |
2314 } | |
2315 | |
2316 | |
2317 void | |
2318 shift(char *op, int oreg,int reg) | |
2319 { | |
2320 int dreg; | |
2321 use_register(oreg,REG_ECX,1); | |
2322 dreg = (reg==REG_ECX)?oreg:reg; | |
2323 printf("\t%s %%cl,%s\n",op,register_name(dreg,0)); | |
2324 set_ireg(dreg,0); | |
2325 set_ireg(reg,1); | |
2326 } | |
2327 | |
2328 void | |
2329 ld_indexx(int byte, int n, int xreg,int reg,int sign) | |
2330 { | |
2331 if (byte) { | |
2332 use_data_reg(reg,1); | |
2333 } else { | |
2334 use_int(reg); | |
2335 } | |
2336 if (n) | |
2337 printf("\t%s %d(%s),%s\n",cload(sign,byte),n, | |
2338 register_name(xreg,0),register_name(reg,0)); | |
2339 else | |
2340 printf("\t%s (%s),%s\n",cload(sign,byte), | |
2341 register_name(xreg,0),register_name(reg,0)); | |
2342 } | |
2343 | |
2344 int | |
2345 code_csvalue() | |
2346 { | |
2347 return glist2(REGISTER,creg); /* for switch value */ | |
2348 } | |
2349 | |
2350 void | |
2351 code_cmpdimm(int e, int csreg,int label,int cond) | |
2352 { | |
2353 /* used in dosiwtch() */ | |
2354 set_ireg(csreg,0); | |
2355 printf("\tcmpl $%d,%s\n",e,register_name(creg,0)); | |
2356 jcond(label,cond); | |
2357 } | |
2358 | |
2359 void | |
2360 code_opening(char *filename) | |
2361 { | |
2362 printf("\t.file \"%s\"\n",filename); | |
2363 printf("\t.version\t\"01.01\"\n"); | |
2364 /* printf("gcc2_compiled.:\n"); */ | |
2365 // printf(".text\n"); | |
2366 } | |
2367 | |
2368 void | |
2369 code_closing() | |
2370 { | |
2371 global_table(); | |
2372 printf("\t.ident \"Micro-C compiled\"\n"); | |
2373 } | |
2374 | |
2375 static char * | |
2376 code_cond(int op,int cond) | |
2377 { | |
2378 switch(op) { | |
2379 case GT: return code_gt(cond); | |
2380 case UGT: return code_ugt(cond); | |
2381 case GE: return code_ge(cond); | |
2382 case UGE: return code_uge(cond); | |
2383 case LT: return code_ge(!cond); | |
2384 case ULT: return code_uge(!cond); | |
2385 case LE: return code_gt(!cond); | |
2386 case ULE: return code_ugt(!cond); | |
2387 case EQ: return code_eq(cond); | |
2388 case NEQ: return code_eq(!cond); | |
2389 default: return 0; | |
2390 } | |
2391 } | |
2392 | |
2393 static int | |
2394 rexpr_bool(int e1,int reg) | |
2395 { | |
2396 char *s; | |
2397 if (!(s=code_cond(car(e1),1))) return 0; | |
2398 g_expr(list3(CMP,cadr(e1),caddr(e1))); | |
2399 use_data_reg(reg,1); | |
2400 printf("\tset%s\t%s\n",s,register_name(reg,1)); | |
2401 printf("\tmovzbl %s,%s\n",register_name(reg,1),register_name(reg,0)); | |
2402 return 1; | |
2403 } | |
2404 | |
2405 int | |
2406 rexpr(int e1, int l1, int cond,int t) | |
2407 { | |
2408 g_expr(list3(CMP,cadr(e1),caddr(e1))); | |
2409 printf("\tj%s\t_%d\n",code_cond(car(e1),cond),l1); | |
2410 return l1; | |
2411 } | |
2412 | |
2413 | |
2414 static void | |
2415 jcond(int l, char cond) | |
2416 { | |
2417 printf("\tj%s\t_%d\n",cond==LT?code_ge(0):cond?"ne":"e",l); | |
2418 } | |
2419 | |
2420 void | |
2421 jmp(int l) | |
2422 { | |
2423 printf("\tjmp\t_%d\n",l); | |
2424 control = 0; | |
2425 /* align? */ | |
2426 /* | |
2427 this is not allowed because of ? operator | |
2428 use_register(creg,REG_EAX,0); | |
2429 */ | |
2430 } | |
2431 | |
2432 void | |
2433 code_comment(char *s) | |
2434 { | |
2435 printf("## %s",s); | |
2436 } | |
2437 | |
2438 | |
2439 void | |
2440 code_enter(char *name) | |
2441 { | |
2442 text_mode(0); | |
2443 printf("\t.align 4\n"); | |
2444 #ifndef __APPLE__ | |
2445 if (stmode!=STATIC) | |
2446 printf(".globl %s\n",name); | |
2447 printf("\t.type\t%s,@function\n",name); | |
2448 printf("%s:\n",name); | |
2449 #else | |
2450 if (stmode!=STATIC) | |
2451 printf(".globl _%s\n",name); | |
2452 printf("_%s:\n",name); | |
2453 clear_ptr_cache(); | |
2454 #endif | |
2455 } | |
2456 | |
2457 | |
2458 void | |
2459 code_enter1(int args) | |
2460 { | |
2461 code_disp_label=fwdlabel(); | |
2462 printf("\tlea -_%d(%%ebp),%%esp\n",code_disp_label); | |
2463 | |
2464 // printf("## args %d disp %d code_disp_offset=%d\n",args,disp,code_disp_offset); | |
2465 #ifdef __APPLE__ | |
2466 printf("\tcall\t___i686.get_pc_thunk.bx\n"); | |
2467 printf("_%d:\n",labelno); | |
2468 goffset_label = labelno; | |
2469 labelno++; | |
2470 regs[REG_EBX] = 1; | |
2471 #endif | |
2472 } | |
2473 | |
2474 void | |
2475 code_leave(char *name) | |
2476 { | |
2477 code_offset_set(fnptr); | |
2478 #ifndef __APPLE__ | |
2479 printf("_%d:\n",labelno); | |
2480 printf("\t.size\t%s,_%d-%s\n",name,labelno,name); | |
2481 local_table(); | |
2482 labelno++; | |
2483 #else | |
2484 local_table(); | |
2485 #endif | |
2486 free_all_register(); | |
2487 } | |
2488 | |
2489 void | |
2490 enter(char *name) | |
2491 { | |
2492 text_mode(0); | |
2493 printf("\t.align 2\n"); | |
2494 #ifndef __APPLE__ | |
2495 if (stmode!=STATIC) | |
2496 printf(".globl %s\n",name); | |
2497 printf("%s:\n",name); | |
2498 printf("\t.type\t%s,@function\n",name); | |
2499 #else | |
2500 if (stmode!=STATIC) | |
2501 printf(".globl _%s\n",name); | |
2502 printf("_%s:\n",name); | |
2503 #endif | |
2504 | |
2505 // lvar_offset_label = fwdlabel(); | |
2506 r1_offset_label = fwdlabel(); | |
2507 max_func_args = 0; | |
2508 | |
2509 printf("\tpushl %%ebp\n"); | |
2510 printf("\tmovl %%esp,%%ebp\n"); | |
2511 printf("\tpushl %%ebx\n"); | |
2512 printf("\tpushl %%esi\n"); | |
2513 printf("\tpushl %%edi\n"); | |
2514 printf("\tlea -%s%d(%%ebp),%%esp\n",lpfx,r1_offset_label); | |
2515 #ifdef __APPLE__ | |
2516 printf("\tcall\t___i686.get_pc_thunk.bx\n"); | |
2517 printf("_%d:\n",labelno); | |
2518 goffset_label = labelno; | |
2519 labelno++; | |
2520 regs[REG_EBX] = 1; | |
2521 clear_ptr_cache(); | |
2522 #endif | |
2523 | |
2524 control=1; | |
2525 } | |
2526 | |
2527 void | |
2528 enter1() | |
2529 { | |
2530 text_mode(0); | |
2531 } | |
2532 | |
2533 void | |
2534 code_label_call(int l) | |
2535 { | |
2536 printf("\tcall\tL_%d\n",l); | |
2537 } | |
2538 | |
2539 void | |
2540 code_ret() | |
2541 { | |
2542 printf("\tret\n"); | |
2543 control=0; | |
2544 } | |
2545 | |
2546 static void | |
2547 make_return_continuation() | |
2548 { | |
2549 int ty = cadr(fnptr->ty); | |
2550 fwddef(retcont); | |
2551 if (ty==FLOAT||ty==DOUBLE) { | |
2552 printf("\tfldl %d(%%ebp)\n",-SIZE_OF_DOUBLE); | |
2553 printf("\tmovl %s,%%ebp\n",reg_name[REG_ESI]); | |
2554 } else if (ty==LONGLONG||ty==ULONGLONG) { | |
2555 set_lreg(RET_LREGISTER,0); | |
2556 printf("\tmovl %d(%%ebp),%%ebp\n",disp-SIZE_OF_INT); | |
2557 } else if (ty>0&&( car(ty)==STRUCT || car(ty)==UNION)) { | |
2558 set_ireg(RET_REGISTER,0); | |
2559 printf("\tmovl %d(%%ebp),%s\n",disp-SIZE_OF_INT, | |
2560 register_name(creg,0)); | |
2561 printf("\tmovl %s,%%ebp\n",reg_name[REG_EDI]); | |
2562 } else if (ty!=VOID) { | |
2563 set_ireg(RET_REGISTER,0); | |
2564 printf("\tmovl %s,%s\n",reg_name[REG_ESI],register_name(creg,0)); | |
2565 printf("\tmovl %s,%%ebp\n",reg_name[REG_EDI]); | |
2566 } | |
2567 } | |
2568 | |
2569 void | |
2570 leave(int control, char *name) | |
2571 { | |
2572 | |
2573 #ifdef __APPLE__ | |
2574 disp &= -(SIZE_OF_INT*4); // 16byte alignment | |
2575 disp -= 12; | |
2576 #else | |
2577 disp &= -SIZE_OF_INT; | |
2578 #endif | |
2579 if (control) | |
2580 code_set_return_register(1); | |
2581 if (retcont) { | |
2582 if (control) | |
2583 jmp(retlabel); | |
2584 make_return_continuation(); | |
2585 } | |
2586 fwddef(retlabel); | |
2587 code_offset_set(fnptr); | |
2588 | |
2589 printf("\tlea %d(%%ebp),%%esp\n",-12); | |
2590 printf("\tpopl %%edi\n"); | |
2591 printf("\tpopl %%esi\n"); | |
2592 printf("\tpopl %%ebx\n"); | |
2593 printf("\tleave\n"); | |
2594 printf("\tret\n"); | |
2595 #ifndef __APPLE__ | |
2596 printf("_%d:\n",labelno); | |
2597 printf("\t.size\t%s,_%d-%s\n",name,labelno,name); | |
2598 #endif | |
2599 local_table(); | |
2600 labelno++; | |
2601 free_all_register(); | |
2602 } | |
2603 | |
2604 int | |
2605 code_get_fixed_creg(int reg,int type) { | |
2606 if (type==FLOAT||type==DOUBLE) { | |
2607 return 0; | |
2608 } else if (type==LONGLONG||type==ULONGLONG) { | |
2609 use_longlong(reg); | |
2610 return reg; | |
2611 } else { | |
2612 if (reg==USE_CREG) { | |
2613 if (regs[CREG_REGISTER]==0) { | |
2614 set_ireg(CREG_REGISTER,is_int_reg(creg)&®s[creg]==USING_REG); | |
2615 return CREG_REGISTER; | |
2616 } | |
2617 } | |
2618 use_int(reg); | |
2619 return reg; | |
2620 } | |
2621 } | |
2622 | |
2623 void | |
2624 code_set_fixed_creg(int reg,int mode,int type) { | |
2625 if (type==FLOAT||type==DOUBLE) { | |
2626 } else if (type==LONGLONG||type==ULONGLONG) { | |
2627 } else { | |
2628 set_ireg(reg,mode); | |
2629 } | |
2630 } | |
2631 | |
2632 int | |
2633 code_set_return_register(int mode) { | |
2634 // before goto leave code, set return register | |
2635 if (cadr(fnptr->ty)==FLOAT) { | |
2636 // set_freg(RET_FREGISTER,mode); | |
2637 return 0; | |
2638 } else if (cadr(fnptr->ty)==DOUBLE) { | |
2639 // set_dreg(RET_DREGISTER,mode); | |
2640 return 0; | |
2641 } else if (cadr(fnptr->ty)==LONGLONG||cadr(fnptr->ty)==ULONGLONG) { | |
2642 set_lreg(RET_LREGISTER,mode); | |
2643 return ireg; | |
2644 } else if (cadr(fnptr->ty)==VOID) { | |
2645 return 0; | |
2646 } else { | |
2647 set_ireg(RET_REGISTER,mode); | |
2648 return ireg; | |
2649 } | |
2650 } | |
2651 | |
2652 void | |
2653 gen_gdecl(char *n, int gpc) | |
2654 { | |
2655 // must be empty | |
2656 } | |
2657 | |
2658 extern void | |
2659 ascii(char *s) | |
2660 { | |
2661 #ifdef __APPLE__ | |
2662 printf("\t.ascii \""); | |
2663 #else | |
2664 printf("\t.string \""); | |
2665 #endif | |
2666 while(*s) { | |
2667 if (*s=='\n') | |
2668 printf("%cn",92); | |
2669 else if (*s<' ') | |
2670 printf("%c%03o",92,*s); | |
2671 else if (*s=='\\') | |
2672 printf("\\\\"); | |
2673 else if (*s==34) | |
2674 printf("%c%c",92,34); | |
2675 else | |
2676 printf("%c",*s); | |
2677 s++; | |
2678 } | |
2679 #ifdef __APPLE__ | |
2680 printf("\\0%c\n",34); | |
2681 #else | |
2682 printf("%c\n",34); | |
2683 #endif | |
2684 } | |
2685 | |
2686 extern int | |
2687 emit_string_label() | |
2688 { | |
2689 int lb; | |
2690 cstring_mode(); | |
2691 lb=fwdlabel(); | |
2692 printf("_%d:\n",lb); | |
2693 return lb; | |
2694 } | |
2695 | |
2696 extern void | |
2697 emit_string(char *s,int t) | |
2698 { | |
2699 t = type_value(t); | |
2700 if (car(t)==ARRAY && | |
2701 (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) { | |
2702 ascii(s); | |
2703 } else { | |
2704 int l = emit_string_label(); | |
2705 ascii(s); | |
2706 emit_label(l); | |
2707 } | |
2708 return; | |
2709 } | |
2710 | |
2711 void | |
2712 code_align(int t) | |
2713 { | |
2714 int d; | |
2715 switch(t) { | |
2716 case CHAR: case UCHAR: return; | |
2717 case SHORT: case USHORT: d = data_alignment & 1; break; | |
2718 default: d = data_alignment & 3; | |
2719 } | |
2720 if (d) { | |
2721 printf("\t.align 2\n"); | |
2722 data_alignment = 0; | |
2723 } | |
2724 } | |
2725 | |
2726 extern void | |
2727 emit_global(NMTBL *n,int a,int e) | |
2728 { | |
2729 int t = type_value(n->ty); | |
2730 if (e>0 && car(e)==STRING && t>0 && car(t)==ARRAY && | |
2731 (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) { | |
2732 cstring_mode(); | |
2733 } else | |
2734 data_mode(n->nm); | |
2735 code_align(a); | |
2736 #ifdef __APPLE__ | |
2737 if (n && n->sc!=STATIC) | |
2738 printf(".globl\t_%s\n",n->nm); | |
2739 printf("_%s:\n",n->nm); | |
2740 #else | |
2741 if (n && n->sc!=STATIC) | |
2742 printf(".globl\t%s\n",n->nm); | |
2743 printf("%s:\n",n->nm); | |
2744 #endif | |
2745 } | |
2746 | |
2747 extern void | |
2748 emit_space(int sp) | |
2749 { | |
2750 data_mode(0); | |
2751 printf("\t.space\t%d\n",sp); | |
2752 } | |
2753 | |
2754 extern void | |
2755 emit_char(int d) | |
2756 { | |
2757 data_mode(0); | |
2758 printf("\t.byte %d\n",d); | |
2759 } | |
2760 | |
2761 extern void | |
2762 emit_short(int d) | |
2763 { | |
2764 data_mode(0); | |
2765 printf("\t.short %d\n",d); | |
2766 } | |
2767 | |
2768 extern void | |
2769 emit_int(int d) | |
2770 { | |
2771 data_mode(0); | |
2772 printf("\t.long %d\n",d); | |
2773 } | |
2774 | |
2775 extern void | |
2776 emit_longlong(int e) | |
2777 { | |
2778 #if LONGLONG_CODE | |
2779 long long ll = lcadr(e); | |
2780 data_mode(0); | |
2781 #if (ENDIAN_L==0) | |
2782 printf("\t.long\t0x%x,0x%x\n",code_l1(ll),code_l2(ll)); | |
2783 #else | |
2784 printf("\t.long\t0x%x,0x%x\n",code_l2(ll),code_l1(ll)); | |
2785 #endif | |
2786 #endif | |
2787 } | |
2788 | |
2789 extern void | |
2790 emit_double(int e) | |
2791 { | |
2792 #if FLOAT_CODE | |
2793 double d = dcadr(e); | |
2794 data_mode(0); | |
2795 #if (ENDIAN_D==0) | |
2796 printf("\t.long\t0x%x,0x%x\n",code_d1(d),code_d2(d)); | |
2797 #else | |
2798 printf("\t.long\t0x%x,0x%x\n",code_d2(d),code_d1(d)); | |
2799 #endif | |
2800 #endif | |
2801 } | |
2802 | |
2803 extern void | |
2804 emit_float(int e) | |
2805 { | |
2806 #if FLOAT_CODE | |
2807 float f = dcadr(e); | |
2808 data_mode(0); | |
2809 printf("\t.long\t0x%x\n",*(int *)&f); | |
2810 #endif | |
2811 } | |
2812 | |
2813 extern void | |
2814 emit_address(char *s,int offset) | |
2815 { | |
2816 data_mode(0); | |
2817 #ifdef __APPLE__ | |
2818 if (offset) | |
2819 printf("\t.long _%s+%d\n",s,offset); | |
2820 else | |
2821 printf("\t.long _%s\n",s); | |
2822 #else | |
2823 if (offset) | |
2824 printf("\t.long %s+%d\n",s,offset); | |
2825 else | |
2826 printf("\t.long %s\n",s); | |
2827 #endif | |
2828 } | |
2829 | |
2830 extern void | |
2831 emit_label(int labelno) | |
2832 { | |
2833 data_mode(0); | |
2834 printf("\t.long _%d\n",labelno); | |
2835 } | |
2836 | |
2837 extern void | |
2838 emit_data_closing(NMTBL *n) | |
2839 { | |
2840 #ifdef DOT_SIZE | |
2841 int lb; | |
2842 #endif | |
2843 if (mode==GDECL) { | |
2844 data_mode(0); | |
2845 #ifdef DOT_SIZE | |
2846 lb=fwdlabel(); | |
2847 printf("_%d:\n",lb); | |
2848 printf("\t.size\t%s,_%d-%s\n",n->nm,lb,n->nm); | |
2849 #endif | |
2850 } | |
2851 } | |
2852 | |
2853 #if LONGLONG_CODE | |
2854 static long long ll0 = 1LL; | |
2855 | |
2856 static int | |
2857 code_l1(long long d) | |
2858 { | |
2859 int *i = (int *)&ll0; int *j = (int *)&d; | |
2860 return (i[1] == 1)?j[1]:j[0]; | |
2861 } | |
2862 | |
2863 static int | |
2864 code_l2(long long d) | |
2865 { | |
2866 int *i = (int *)&ll0; int *j = (int *)&d; | |
2867 return (i[1] == 1)?j[0]:j[1]; | |
2868 } | |
2869 #endif | |
2870 | |
2871 void | |
2872 global_table(void) | |
2873 { | |
2874 #ifndef __APPLE__ | |
2875 NMTBL *n; | |
2876 int init; | |
2877 init=0; | |
2878 for(n=global_list;n;n = n->next) { | |
2879 if (is_code(n) || is_function(n)) { | |
2880 } | |
2881 if ((n->sc == GVAR||n->sc == STATIC) && n->dsp != -1) { | |
2882 if (is_code(n)||is_function(n)) continue; | |
2883 /* n->dsp = -1 means initialized global */ | |
2884 if (init==0) { | |
2885 data_mode(0); | |
2886 init=1; | |
2887 } | |
2888 printf(".comm %s,%d\n",n->nm,size(n->ty)); | |
2889 // .lcomm? | |
2890 } | |
2891 } | |
2892 | |
2893 #else | |
2894 | |
2895 NMTBL *n; | |
2896 int init; | |
2897 init=0; | |
2898 for(n=global_list;n;n = n->next) { | |
2899 if ((n->sc == GVAR) && n->dsp != -1) { | |
2900 if (is_code(n)||is_function(n)) continue; | |
2901 /* n->dsp = -1 means initialized global */ | |
2902 if (init==0) { | |
2903 data_mode(0); | |
2904 init=1; | |
2905 } | |
2906 printf(".comm _%s,%d\n",n->nm,size(n->ty)); | |
2907 } else if ((n->sc==STATIC) && n->dsp != -1) { | |
2908 /* n->dsp = -1 means initialized global */ | |
2909 if (is_code(n)||is_function(n)) { | |
2910 printf("\t.set L_%s$stub,_%s\n",n->nm,n->nm); | |
2911 continue; | |
2912 } | |
2913 if (init==0) { | |
2914 data_mode(0); | |
2915 init=1; | |
2916 } | |
2917 printf(".lcomm _%s,%d\n",n->nm,size(n->ty)); | |
2918 } | |
2919 } | |
2920 init=0; | |
2921 for(n = global_list;n!=&null_nptr;n = n->next) { | |
2922 if (n->sc == GVAR || | |
2923 ((is_code(n) || is_function(n)) &&has_attr(n,FNAME)) ) { | |
2924 if (init==0) { | |
2925 printf("\t.section __IMPORT,__pointers,non_lazy_symbol_pointers\n"); | |
2926 init=1; | |
2927 } | |
2928 printf("L_%s$non_lazy_ptr:\n\t.indirect_symbol _%s\n\t.long\t0\n", | |
2929 n->nm,n->nm); | |
2930 } | |
2931 } | |
2932 for(n = global_list;n!=&null_nptr;n = n->next) { | |
2933 if (n->sc==EXTRN1) { | |
2934 if (!(is_code(n) || is_function(n))) { | |
2935 printf("\t.section __IMPORT,__pointers,non_lazy_symbol_pointers\n"); | |
2936 printf("L_%s$non_lazy_ptr:\n\t.indirect_symbol _%s\n\t.long\t0\n", | |
2937 n->nm,n->nm); | |
2938 } | |
2939 printf("\t.section __IMPORT,__jump_table,symbol_stubs,self_modifying_code+pure_instructions,5\n"); | |
2940 printf("L_%s$stub:\n",n->nm); | |
2941 printf("\t.indirect_symbol _%s\n",n->nm); | |
2942 printf("\thlt ; hlt ; hlt ; hlt ; hlt\n"); | |
2943 } | |
2944 } | |
2945 printf(" .subsections_via_symbols\n"); | |
2946 printf(" .section __TEXT,__textcoal_nt,coalesced,pure_instructions\n"); | |
2947 printf(".weak_definition ___i686.get_pc_thunk.bx\n"); | |
2948 printf(".private_extern ___i686.get_pc_thunk.bx\n"); | |
2949 printf("___i686.get_pc_thunk.bx:\n"); | |
2950 printf(" movl (%%esp), %%ebx\n"); | |
2951 printf(" ret\n"); | |
2952 #endif | |
2953 } | |
2954 | |
2955 | |
2956 void | |
2957 local_table(void) | |
2958 { | |
2959 NMTBL *n; | |
2960 int init; | |
2961 init=0; | |
2962 /* static local variables */ | |
2963 for(n=local_static_list;n;n = n->next) { | |
2964 if (n->sc == STATIC) { | |
2965 if (init==0) { | |
2966 data_mode(0); | |
2967 init=1; | |
2968 } | |
2969 #ifdef __APPLE__ | |
2970 if (n->dsp!= -1) /* -1 means initialized global */ | |
2971 printf(".lcomm _%s,%d\n",n->nm,size(n->ty)); | |
2972 #else | |
2973 if (n->dsp!= -1) /* -1 means initialized global */ | |
2974 printf(".lcomm %s,%d\n",n->nm,size(n->ty)); | |
2975 #endif | |
2976 } | |
2977 } | |
2978 } | |
2979 | |
2980 void | |
2981 cstring_mode(int align) | |
2982 { | |
2983 if (output_mode!=RODATA_EMIT_MODE) { | |
2984 #ifndef __APPLE__ | |
2985 printf(".section\t.rodata\n\t.align 2\n"); | |
2986 #else | |
2987 printf("\t.cstring\n"); | |
2988 #endif | |
2989 output_mode = RODATA_EMIT_MODE; | |
2990 } | |
2991 } | |
2992 | |
2993 void | |
2994 text_mode(int align) | |
2995 { | |
2996 if (output_mode!=TEXT_EMIT_MODE) { | |
2997 printf(".text\n"); | |
2998 // printf("\t.align 2\n"); | |
2999 output_mode = TEXT_EMIT_MODE; | |
3000 } | |
3001 } | |
3002 | |
3003 void | |
3004 data_mode(char *name) | |
3005 { | |
3006 if (output_mode!=DATA_EMIT_MODE) { | |
3007 printf(".data\n"); | |
3008 output_mode = DATA_EMIT_MODE; | |
3009 } | |
3010 #ifndef __APPLE__ | |
3011 if (name) | |
3012 printf("\t.type\t%s,@object\n",name); | |
3013 #endif | |
3014 } | |
3015 | |
3016 #if FLOAT_CODE | |
3017 | |
3018 /* floating point */ | |
3019 | |
3020 | |
3021 char * | |
3022 fstore(int d) | |
3023 { | |
3024 return use? | |
3025 (d?"fstl":"fsts"): | |
3026 (d?"fstpl":"fstps") | |
3027 ; | |
3028 } | |
3029 | |
3030 char * | |
3031 fstore_u(int d) | |
3032 { | |
3033 return d?"fstpl":"fstps"; | |
3034 } | |
3035 | |
3036 char * | |
3037 fload(int d) | |
3038 { | |
3039 return d?"fldl":"flds"; | |
3040 } | |
3041 | |
3042 | |
3043 void code_dassign_gvar(int e2,int freg,int d) | |
3044 { | |
3045 #ifdef __APPLE__ | |
3046 int r = get_ptr_cache(ncaddr(e2)); | |
3047 if (cadr(e2)) | |
3048 printf("\t%s %d(%s)\n",fstore(d),cadr(e2),register_name(r,0)); | |
3049 else | |
3050 printf("\t%s (%s)\n",fstore(d),register_name(r,0)); | |
3051 #else | |
3052 if (cadr(e2)) | |
3053 printf("\t%s %s+%d\n",fstore(d),(ncaddr(e2))->nm,cadr(e2)); | |
3054 else | |
3055 printf("\t%s %s\n",fstore(d),(ncaddr(e2))->nm); | |
3056 #endif | |
3057 } | |
3058 | |
3059 void code_dassign_lvar(int e2,int freg,int d) | |
3060 { | |
3061 printf("\t%s ",fstore(d)); lvar(e2); printf("\n"); | |
3062 } | |
3063 | |
3064 void code_dassign_dregister(int e,int d,int freg) | |
3065 { | |
3066 error(-1); | |
3067 } | |
3068 | |
3069 void code_dassign(int e2,int freg,int d) | |
3070 { | |
3071 printf("\t%s (%s)\n",fstore(d),register_name(e2,0)); | |
3072 } | |
3073 | |
3074 static double d0 = 1.0; | |
3075 | |
3076 static int | |
3077 code_d1(double d) | |
3078 { | |
3079 int *i = (int *)&d0; int *j = (int *)&d; | |
3080 return (i[1] == 0x3ff00000)?j[0]:j[1]; | |
3081 } | |
3082 | |
3083 static int | |
3084 code_d2(double d) | |
3085 { | |
3086 int *i = (int *)&d0; int *j = (int *)&d; | |
3087 return (i[1] == 0x3ff00000)?j[1]:j[0]; | |
3088 } | |
3089 | |
3090 void code_dconst(int e2,int freg,int d) | |
3091 { | |
3092 int lb; | |
3093 double value = dcadr(e2); | |
3094 | |
3095 if (value==0.0) { | |
3096 printf("\tfldz\n"); return; | |
3097 } | |
3098 if (value==1.0) { | |
3099 printf("\tfld1\n"); return; | |
3100 } | |
3101 #ifdef __APPLE__ | |
3102 printf(" \t.literal8\n\t.align 3\n"); | |
3103 #else | |
3104 printf(" \t.section\t.rodata\n\t.align 8\n"); | |
3105 #endif | |
3106 lb=fwdlabel(); | |
3107 printf("_%d:\n",lb); | |
3108 #if ENDIAN_D==0 | |
3109 printf("\t.long\t0x%x,0x%x\n",code_d1(value),code_d2(value)); | |
3110 #endif | |
3111 if (output_mode==TEXT_EMIT_MODE) { | |
3112 printf(".text\n"); | |
3113 } else { | |
3114 text_mode(0); | |
3115 } | |
3116 #ifdef __APPLE__ | |
3117 printf("\tfldl _%d-_%d(%%ebx)\n",lb,goffset_label); | |
3118 #else | |
3119 printf("\tfldl _%d\n",lb); | |
3120 #endif | |
3121 } | |
3122 | |
3123 void | |
3124 code_builtin_fabsf(int e) | |
3125 { | |
3126 } | |
3127 void | |
3128 code_builtin_fabs(int e) | |
3129 { | |
3130 } | |
3131 void | |
3132 code_builtin_inff() | |
3133 { | |
3134 } | |
3135 void | |
3136 code_builtin_inf() | |
3137 { | |
3138 } | |
3139 | |
3140 void code_dneg(int freg,int d) | |
3141 { | |
3142 printf("\tfchs\n"); | |
3143 } | |
3144 | |
3145 void code_d2i(int reg) | |
3146 { | |
3147 use_int(reg); | |
3148 printf("\tlea -%d(%%esp),%%esp\n",SIZE_OF_INT*2); | |
3149 printf("\tfnstcw (%%esp)\n"); | |
3150 printf("\tmovl (%%esp), %s\n",register_name(creg,0)); | |
3151 printf("\tmovb $12, 1(%%esp)\n"); | |
3152 printf("\tfldcw (%%esp)\n"); | |
3153 printf("\tfistpl %d(%%esp)\n",SIZE_OF_INT); | |
3154 printf("\tmovl %s, (%%esp)\n",register_name(creg,0)); | |
3155 printf("\tfldcw (%%esp)\n"); | |
3156 printf("\tpopl %s\n",register_name(creg,0)); | |
3157 printf("\tpopl %s\n",register_name(creg,0)); | |
3158 } | |
3159 | |
3160 void code_i2d(int reg) | |
3161 { | |
3162 printf("\tpushl %s\n",register_name(creg,0)); | |
3163 printf("\tfildl (%%esp)\n"); | |
3164 printf("\tlea %d(%%esp),%%esp\n",SIZE_OF_INT); | |
3165 } | |
3166 | |
3167 void code_d2u(int reg) | |
3168 { | |
3169 use_int(reg); | |
3170 printf("\tlea -%d(%%esp),%%esp\n",SIZE_OF_INT*3); | |
3171 printf("\tfnstcw (%%esp)\n"); | |
3172 printf("\tmovl (%%esp), %s\n",register_name(reg,0)); | |
3173 printf("\tmovb $12, 1(%%esp)\n"); | |
3174 printf("\tfldcw (%%esp)\n"); | |
3175 printf("\tmovl %s, (%%esp)\n",register_name(reg,0)); | |
3176 printf("\tfistpll %d(%%esp)\n",SIZE_OF_INT); | |
3177 printf("\tfldcw (%%esp)\n"); | |
3178 printf("\tmovl %d(%%esp),%s\n",SIZE_OF_INT,register_name(reg,0)); | |
3179 printf("\tlea %d(%%esp),%%esp\n",SIZE_OF_INT*3); | |
3180 } | |
3181 | |
3182 void code_u2d(int reg) | |
3183 { | |
3184 printf("\tpushl %s\n",register_name(creg,0)); | |
3185 printf("\tpushl %s\n",register_name(creg,0)); | |
3186 printf("\tmovl $0, %d(%%esp)\n",SIZE_OF_INT); | |
3187 printf("\tfildll (%%esp)\n"); | |
3188 printf("\tlea %d(%%esp),%%esp\n",SIZE_OF_INT*2); | |
3189 } | |
3190 | |
3191 void code_d2f(int reg) { } | |
3192 void code_f2d(int reg) { } | |
3193 void code_f2i(int reg) { code_d2i(reg); } | |
3194 void code_f2u(int reg) { code_d2u(reg); } | |
3195 void code_i2f(int reg) { code_i2d(reg); } | |
3196 void code_u2f(int reg) { code_u2d(reg); } | |
3197 | |
3198 void code_drgvar(int e2,int d,int freg) | |
3199 { | |
3200 #ifdef __APPLE__ | |
3201 int r = get_ptr_cache(ncaddr(e2)); | |
3202 if (cadr(e2)) | |
3203 printf("\t%s %d(%s)\n",fload(d),cadr(e2),register_name(r,0)); | |
3204 else | |
3205 printf("\t%s (%s)\n",fload(d),register_name(r,0)); | |
3206 #else | |
3207 if (cadr(e2)) | |
3208 printf("\t%s %s+%d\n",fload(d),(ncaddr(e2))->nm,cadr(e2)); | |
3209 else | |
3210 printf("\t%s %s\n",fload(d),(ncaddr(e2))->nm); | |
3211 #endif | |
3212 } | |
3213 | |
3214 | |
3215 void code_drlvar(int e2,int d,int freg) | |
3216 { | |
3217 printf("\t%s ",fload(d)); lvar(e2); printf("\n"); | |
3218 } | |
3219 | |
3220 void code_cmp_drgvar(int e2,int reg,int d,int label,int cond) | |
3221 { | |
3222 #ifdef __APPLE__ | |
3223 int r = get_ptr_cache(ncaddr(e2)); | |
3224 if (cadr(e2)) | |
3225 printf("\tfcomp %d(%s)\n",cadr(e2),register_name(r,0)); | |
3226 else | |
3227 printf("\tfcomp (%s)\n",register_name(r,0)); | |
3228 #else | |
3229 if (cadr(e2)) | |
3230 printf("\tfcomp %s+%d\n",(ncaddr(e2))->nm,cadr(e2)); | |
3231 else | |
3232 printf("\tfcomp %s\n",(ncaddr(e2))->nm); | |
3233 #endif | |
3234 jcond(label,cond); | |
3235 } | |
3236 | |
3237 void code_cmp_drlvar(int e2,int reg,int d,int label,int cond) | |
3238 { | |
3239 printf("\tfcomp "); lvar(e2); printf("\n"); | |
3240 jcond(label,cond); | |
3241 } | |
3242 | |
3243 void dtosop(int op,int reg,int e1) | |
3244 { | |
3245 switch(op) { | |
3246 case FADD: | |
3247 case DADD: printf("\tfaddp %%st,%%st(1)\n"); break; | |
3248 case FSUB: | |
3249 case DSUB: printf("\tfsubp %%st,%%st(1)\n"); break; | |
3250 case FDIV: | |
3251 case DDIV: printf("\tfdivp %%st,%%st(1)\n"); break; | |
3252 case FMUL: | |
3253 case DMUL: printf("\tfmulp %%st,%%st(1)\n"); break; | |
3254 case FCMP: | |
3255 case DCMP: | |
3256 printf("\tfucompp\n"); | |
3257 printf("\tfnstsw\t%%ax\n"); | |
3258 #ifdef __APPLE__ | |
3259 if (regs[REG_EAX]==PTRC_REG) | |
3260 clear_ptr_cache_reg(REG_EAX); | |
3261 #endif | |
3262 break; | |
3263 } | |
3264 } | |
3265 | |
3266 void | |
3267 code_dassop(int op,int reg,int d) { | |
3268 /* we have lvalue in creg, applied floating value is in %st(0) */ | |
3269 emit_dpop(d); /* do nothing for 387 */ | |
3270 printf("\t%s (%s)\n",fload(d),register_name(creg,0)); | |
3271 dtosop(op,reg,0); | |
3272 printf("\t%s (%s)\n",fstore(d),register_name(creg,0)); | |
3273 } | |
3274 | |
3275 void | |
3276 code_register_dassop(int reg,int op,int d) { | |
3277 error(-1); | |
3278 } | |
3279 | |
3280 void | |
3281 code_dpreinc(int e1,int e2,int d,int freg) { | |
3282 g_expr(e2); | |
3283 printf("\t%s (%s)\n",fload(d),register_name(creg,0)); | |
3284 printf("\tfld1\n"); | |
3285 if (caddr(e1)>0) | |
3286 printf("\tfaddp %%st,%%st(1)\n"); | |
3287 else | |
3288 printf("\tfsubrp %%st,%%st(1)\n"); | |
3289 printf("\t%s (%s)\n",fstore(d),register_name(creg,0)); | |
3290 } | |
3291 | |
3292 void | |
3293 code_dpostinc(int e1,int e2,int d,int freg) { | |
3294 g_expr(e2); | |
3295 printf("\t%s (%s)\n",fload(d),register_name(creg,0)); | |
3296 if (use) | |
3297 printf("\t%s (%s)\n",fload(d),register_name(creg,0)); | |
3298 printf("\tfld1\n"); | |
3299 if (caddr(e1)>0) | |
3300 printf("\tfaddp %%st,%%st(1)\n"); | |
3301 else | |
3302 printf("\tfsubrp %%st,%%st(1)\n"); | |
3303 printf("\t%s (%s)\n",(use?fstore_u(d):fstore(d)),register_name(creg,0)); | |
3304 } | |
3305 | |
3306 #define COND_BRANCH 1 | |
3307 #define COND_VALUE 2 | |
3308 | |
3309 /* return 1 if boolean expression */ | |
3310 | |
3311 int | |
3312 drexpr0(int e1, int e2,int l1, int op,int cond,int reg,int mode) | |
3313 { | |
3314 char *s; | |
3315 if (!cond) { | |
3316 switch(op) { | |
3317 case FOP+GT: | |
3318 return drexpr0(e2,e1,l1,FOP+GE,1,reg,mode); | |
3319 case FOP+GE: | |
3320 return drexpr0(e2,e1,l1,FOP+GT,1,reg,mode); | |
3321 case FOP+EQ: | |
3322 op=FOP+NEQ; break; | |
3323 case FOP+NEQ: | |
3324 op=FOP+EQ; break; | |
3325 case DOP+GT: | |
3326 return drexpr0(e2,e1,l1,DOP+GE,1,reg,mode); | |
3327 case DOP+GE: | |
3328 return drexpr0(e2,e1,l1,DOP+GT,1,reg,mode); | |
3329 case DOP+EQ: | |
3330 op=DOP+NEQ; break; | |
3331 case DOP+NEQ: | |
3332 op=DOP+EQ; break; | |
3333 default: return 0; | |
3334 } | |
3335 } | |
3336 s = "e"; | |
3337 switch(op) { | |
3338 case DOP+GE: | |
3339 case FOP+GE: | |
3340 g_expr(list3(DCMP,e1,e2)); | |
3341 printf("\ttestb\t$5,%%ah\n"); | |
3342 break; | |
3343 case DOP+GT: | |
3344 case FOP+GT: | |
3345 g_expr(list3(DCMP,e1,e2)); | |
3346 printf("\ttestb\t$69,%%ah\n"); | |
3347 break; | |
3348 case DOP+EQ: | |
3349 case FOP+EQ: | |
3350 g_expr(list3(DCMP,e1,e2)); | |
3351 printf("\tandb\t$69,%%ah\n"); | |
3352 printf("\txorb\t$64,%%ah\n"); | |
3353 break; | |
3354 case DOP+NEQ: | |
3355 case FOP+NEQ: | |
3356 g_expr(list3(DCMP,e1,e2)); | |
3357 printf("\tandb\t$69,%%ah\n"); | |
3358 printf("\txorb\t$64,%%ah\n"); | |
3359 s = "ne"; | |
3360 break; | |
3361 default: | |
3362 return 0; | |
3363 } | |
3364 if (mode==COND_BRANCH) { | |
3365 printf("\tj%s\t_%d\n",s,l1); | |
3366 } else { | |
3367 use_data_reg(reg,0); | |
3368 printf("\tset%s\t%s\n",s,register_name(reg,1)); | |
3369 printf("\tmovzbl\t%s,%s\n", | |
3370 register_name(reg,1),register_name(reg,0)); | |
3371 } | |
3372 return 1; | |
3373 } | |
3374 | |
3375 int | |
3376 drexpr(int e1, int e2,int l1, int op,int cond) | |
3377 { | |
3378 drexpr0(e1, e2,l1, op,cond,USE_CREG,COND_BRANCH); | |
3379 return l1; | |
3380 } | |
3381 | |
3382 static int | |
3383 drexpr_bool(int e1, int reg) | |
3384 { | |
3385 return drexpr0(cadr(e1), caddr(e1),0, car(e1),1,reg,COND_VALUE); | |
3386 } | |
3387 | |
3388 | |
3389 void | |
3390 code_dregister(int e2,int freg,int d) | |
3391 { | |
3392 error(-1); | |
3393 } | |
3394 | |
3395 void | |
3396 code_cmp_dregister(int e2,int d,int label,int cond) | |
3397 { | |
3398 if (e2!=USE_CREG) | |
3399 error(-1); | |
3400 #ifdef __APPLE__ | |
3401 if (regs[REG_EAX]==PTRC_REG) | |
3402 clear_ptr_cache_reg(REG_EAX); | |
3403 #endif | |
3404 printf("\tfldz\n"); | |
3405 printf("\tfucompp\n"); | |
3406 printf("\tfnstsw\t%%ax\n"); | |
3407 printf("\tandb\t$69,%%ah\n"); | |
3408 printf("\txorb\t$64,%%ah\n"); | |
3409 jcond(label,cond); | |
3410 } | |
3411 | |
3412 int pop_fregister() | |
3413 { | |
3414 if (freg_sp<0) { error(-1); return -1;} | |
3415 // printf("## fpop: %d\n",freg_sp-1); | |
3416 return freg_stack[--freg_sp]; | |
3417 } | |
3418 | |
3419 int | |
3420 emit_dpop(int d) | |
3421 { | |
3422 int xreg; | |
3423 if ((xreg=pop_fregister())==-1) { | |
3424 } else if (xreg<= -REG_LVAR_OFFSET) { | |
3425 code_drlvar(REG_LVAR_OFFSET+xreg,1,freg); | |
3426 free_lvar(xreg+REG_LVAR_OFFSET); | |
3427 /* pushed order is reversed. We don't need this for commutable | |
3428 operator, but it is ok to do this. */ | |
3429 printf("\tfxch\t%%st(1)\n"); | |
3430 } | |
3431 return xreg; | |
3432 } | |
3433 | |
3434 | |
3435 void emit_dpop_free(int e1,int d) | |
3436 { | |
3437 } | |
3438 | |
3439 void emit_dpush(int type) | |
3440 { | |
3441 if (freg_sp>=MAX_FPU_STACK) code_save_fstacks(); | |
3442 if (freg_sp>MAX_MAX) error(-1); | |
3443 freg_stack[freg_sp++]=-1; | |
3444 // printf("## fpush:%d\n",freg_sp); | |
3445 } | |
3446 | |
3447 #endif | |
3448 | |
3449 void | |
3450 code_save_stacks() | |
3451 { | |
3452 /* registers stacks are saved in local variable */ | |
3453 int i,reg; | |
3454 for(i=0;i<reg_sp;i++) { | |
3455 if ((reg=reg_stack[i])>=0) { | |
3456 code_assign_lvar( | |
3457 (reg_stack[i]=new_lvar(SIZE_OF_INT)),reg,0); | |
3458 reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET; | |
3459 if (regs[reg]!=REG_VAR) free_register(reg); | |
3460 } | |
3461 } | |
3462 #if FLOAT_CODE | |
3463 code_save_fstacks(); | |
3464 #endif | |
3465 } | |
3466 | |
3467 static void | |
3468 code_clear_stack_reg(int reg1) | |
3469 { | |
3470 /* specified registers stacks are saved in local variable */ | |
3471 /* temporal registers are saved in local variable */ | |
3472 int i,reg; | |
3473 if (regs[reg1]==PTRC_REG) | |
3474 clear_ptr_cache_reg(reg1); | |
3475 | |
3476 for(i=0;i<reg_sp;i++) { | |
3477 if ((reg=reg_stack[i])>=0 && reg==reg1) { | |
3478 code_assign_lvar( | |
3479 (reg_stack[i]=new_lvar(SIZE_OF_INT)),reg,0); | |
3480 reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET; | |
3481 if (regs[reg]!=REG_VAR) free_register(reg); | |
3482 } | |
3483 } | |
3484 } | |
3485 | |
3486 #if FLOAT_CODE | |
3487 void | |
3488 code_save_fstacks() | |
3489 { | |
3490 /* stacks in fpu are saved in local variable */ | |
3491 int xreg,sp,uses; | |
3492 uses = use; use = 0; | |
3493 sp=freg_sp; | |
3494 while(sp-->0) { | |
3495 if ((xreg=freg_stack[sp])==-1) { | |
3496 code_dassign_lvar( | |
3497 (freg_stack[sp]=new_lvar(SIZE_OF_DOUBLE)),freg,1); | |
3498 freg_stack[sp]= freg_stack[sp]-REG_LVAR_OFFSET; | |
3499 } | |
3500 } | |
3501 use = uses; | |
3502 } | |
3503 #endif | |
3504 | |
3505 | |
3506 | |
3507 #if LONGLONG_CODE | |
3508 | |
3509 | |
3510 /* 64bit int part */ | |
3511 | |
3512 static void | |
3513 pcond(char *s,int l1) | |
3514 { | |
3515 printf("\tj%s\t_%d\n",s,l1); | |
3516 } | |
3517 | |
3518 int | |
3519 lrexpr(int e1, int e2,int l1, int op,int cond) | |
3520 { | |
3521 int l2; | |
3522 code_save_stacks(); | |
3523 g_expr(e1); | |
3524 emit_lpush(); | |
3525 g_expr(e2); | |
3526 // we are sure %ecx is free | |
3527 // %ebx is used in Intel Mac | |
3528 stack_depth -= SIZE_OF_INT * 2; | |
3529 printf("\tpopl %%ecx\n"); // LSW | |
3530 printf("\tcmpl %%edx,(%%esp)\n"); // MSW | |
3531 printf("\tpopl %%edx\n"); | |
3532 l2 = fwdlabel(); | |
3533 // cond==0 jump on false condtion ( if(x) => rexpr(.. cond=0 ...) ) | |
3534 switch(op) { | |
3535 case LOP+GT: | |
3536 case LOP+GE: | |
3537 pcond(code_gt(1),cond?l1:l2); | |
3538 pcond(code_eq(0),cond?l2:l1); | |
3539 break; | |
3540 case LOP+UGT: | |
3541 case LOP+UGE: | |
3542 pcond(code_ugt(1),cond?l1:l2); | |
3543 pcond(code_eq(0), cond?l2:l1); | |
3544 break; | |
3545 case LOP+EQ: | |
3546 pcond(code_eq(0),(cond?l2:l1)); | |
3547 break; | |
3548 case LOP+NEQ: | |
3549 pcond(code_eq(0),(cond?l1:l2)); | |
3550 break; | |
3551 default: | |
3552 error(-1); | |
3553 } | |
3554 printf("\tsubl %%eax,%%ecx\n"); | |
3555 switch(op) { | |
3556 case LOP+GT: pcond(code_gt(cond), l1); break; | |
3557 case LOP+GE: pcond(code_ge(cond), l1); break; | |
3558 case LOP+UGT: pcond(code_ugt(cond), l1); break; | |
3559 case LOP+UGE: pcond(code_uge(cond), l1); break; | |
3560 case LOP+EQ: pcond(code_eq(cond),l1); break; | |
3561 case LOP+NEQ: pcond(code_eq(!cond),l1); break; | |
3562 } | |
3563 fwddef(l2); | |
3564 return l1; | |
3565 } | |
3566 | |
3567 int emit_lpop() | |
3568 { | |
3569 return 0; | |
3570 } | |
3571 | |
3572 void code_lregister(int e2,int reg) | |
3573 { | |
3574 use_longlong(reg); | |
3575 if (reg!=REG_L) { | |
3576 printf("\tmovl %%esi,%s\n",l_eax(reg)); | |
3577 printf("\tmovl %%edi,%s\n",l_edx(reg)); | |
3578 } | |
3579 } | |
3580 | |
3581 void code_cmp_lregister(int reg,int label,int cond) | |
3582 { | |
3583 char *crn; | |
3584 use_int(reg); | |
3585 crn = register_name(reg,0); | |
3586 printf("\tmovl %%esi,%s\n",crn); | |
3587 printf("\torl %%edi,%s\n",crn); | |
3588 printf("\ttestl %s,%s\n",crn,crn); | |
3589 jcond(label,cond); | |
3590 } | |
3591 | |
3592 void code_cmp_lrgvar(int e1,int e2,int label,int cond) | |
3593 { | |
3594 char *n,*crn; | |
3595 use_int(e2); | |
3596 crn = register_name(e2,0); | |
3597 #ifdef __APPLE__ | |
3598 int r = get_ptr_cache(ncaddr(e1)); | |
3599 n = register_name(r,0); | |
3600 if (cadr(e1)) { | |
3601 printf("\tmovl %d(%s),%s\n",cadr(e1),n,crn); | |
3602 printf("\torl %d(%s),%s\n",cadr(e1)+4,n,crn); | |
3603 } else { | |
3604 printf("\tmovl (%s),%s\n",n,crn); | |
3605 printf("\torl 4(%s),%s\n",n,crn); | |
3606 } | |
3607 #else | |
3608 n = (ncaddr(e1))->nm; | |
3609 if (cadr(e1)) { | |
3610 printf("\tmovl %s+%d,%s\n",n,cadr(e1),crn); | |
3611 printf("\torl %s+%d,%s\n",n,cadr(e1)+4,crn); | |
3612 } else { | |
3613 printf("\tmovl %s,%s\n",n,crn); | |
3614 printf("\torl %s+4,%s\n",n,crn); | |
3615 } | |
3616 #endif | |
3617 printf("\ttestl %s,%s\n",crn,crn); | |
3618 jcond(label,cond); | |
3619 } | |
3620 | |
3621 void code_cmp_lrlvar(int e1,int e2,int label,int cond) | |
3622 { | |
3623 char *crn; | |
3624 use_int(e2); | |
3625 crn = register_name(e2,0); | |
3626 printf("\tmovl "); lvar(e1); printf(",%s\n",crn); | |
3627 printf("\torl "); lvar(e1+4); printf(",%s\n",crn); | |
3628 printf("\ttestl %s,%s\n",crn,crn); | |
3629 jcond(label,cond); | |
3630 } | |
3631 | |
3632 void code_lassign(int e1,int e2) | |
3633 { | |
3634 char *rn; | |
3635 // e1 = e2 | |
3636 use_longlong(e2); | |
3637 rn = register_name(e1,0); | |
3638 #if ENDIAN_L==0 | |
3639 printf("\tmovl %s,(%s)\n",l_eax(e2),rn); | |
3640 printf("\tmovl %s,4(%s)\n",l_edx(e2),rn); | |
3641 #endif | |
3642 } | |
3643 | |
3644 void code_lassign_gvar(int e1,int e2) | |
3645 { | |
3646 char *n; | |
3647 use_longlong(e2); | |
3648 #if ENDIAN_L==0 | |
3649 #ifdef __APPLE__ | |
3650 int r = get_ptr_cache(ncaddr(e1)); | |
3651 n = register_name(r,0); | |
3652 if (cadr(e1)) { | |
3653 printf("\tmovl %s,%d(%s)\n",l_eax(e2),cadr(e1),n); | |
3654 printf("\tmovl %s,%d(%s)\n",l_edx(e2),cadr(e1)+4,n); | |
3655 } else { | |
3656 printf("\tmovl %s,(%s)\n",l_eax(e2),n); | |
3657 printf("\tmovl %s,4(%s)\n",l_edx(e2),n); | |
3658 } | |
3659 #else | |
3660 n = (ncaddr(e1))->nm; | |
3661 if (cadr(e1)) { | |
3662 printf("\tmovl %s,%s+%d\n",l_eax(e2),n,cadr(e1)); | |
3663 printf("\tmovl %s,%s+%d\n",l_edx(e2),n,cadr(e1)+4); | |
3664 } else { | |
3665 printf("\tmovl %s,%s\n",l_eax(e2),n); | |
3666 printf("\tmovl %s,%s+4\n",l_edx(e2),n); | |
3667 } | |
3668 #endif | |
3669 #endif | |
3670 } | |
3671 | |
3672 void code_lassign_lvar(int e1,int e2) | |
3673 { | |
3674 use_longlong(e2); | |
3675 #if ENDIAN_L==0 | |
3676 printf("\tmovl %s,",l_eax(e2)); lvar(e1); printf("\n"); | |
3677 printf("\tmovl %s,",l_edx(e2)); lvar(e1+4); printf("\n"); | |
3678 #endif | |
3679 } | |
3680 | |
3681 void code_lassign_lregister(int e2,int reg) | |
3682 { | |
3683 // e2 = reg | |
3684 use_longlong(reg); | |
3685 if (e2!=reg) { | |
3686 printf("\tmovl %s,%s\n",l_eax(reg),l_eax(e2)); | |
3687 printf("\tmovl %s,%s\n",l_edx(reg),l_edx(e2)); | |
3688 } | |
3689 } | |
3690 | |
3691 void | |
3692 code_lconst(int e1,int creg) | |
3693 { | |
3694 use_longlong(creg); | |
3695 #if ENDIAN_L==0 | |
3696 printf("\tmovl $%d,%s\n",code_l1(lcadr(e1)),l_eax(creg)); | |
3697 printf("\tmovl $%d,%s\n",code_l2(lcadr(e1)),l_edx(creg)); | |
3698 #endif | |
3699 } | |
3700 | |
3701 void code_lneg(int e1) | |
3702 { | |
3703 use_longlong(e1); | |
3704 printf("\tnegl %s\n",l_eax(e1)); | |
3705 printf("\tadcl $0,%s\n",l_edx(e1)); | |
3706 printf("\tnegl %s\n",l_edx(e1)); | |
3707 } | |
3708 | |
3709 void code_lrgvar(int e1,int e2) | |
3710 { | |
3711 char *n; | |
3712 use_longlong(e2); | |
3713 #if ENDIAN_L==0 | |
3714 #ifdef __APPLE__ | |
3715 int r = get_ptr_cache(ncaddr(e1)); | |
3716 n = register_name(r,0); | |
3717 if (cadr(e1)) { | |
3718 printf("\tmovl %d(%s),%s\n",cadr(e1),n,l_eax(e2)); | |
3719 printf("\tmovl %d(%s),%s\n",cadr(e1)+4,n,l_edx(e2)); | |
3720 } else { | |
3721 printf("\tmovl (%s),%s\n",n,l_eax(e2)); | |
3722 printf("\tmovl 4(%s),%s\n",n,l_edx(e2)); | |
3723 } | |
3724 #else | |
3725 n = (ncaddr(e1))->nm; | |
3726 if (cadr(e1)) { | |
3727 printf("\tmovl %s+%d,%s\n",n,cadr(e1),l_eax(e2)); | |
3728 printf("\tmovl %s+%d,%s\n",n,cadr(e1)+4,l_edx(e2)); | |
3729 } else { | |
3730 printf("\tmovl %s,%s\n",n,l_eax(e2)); | |
3731 printf("\tmovl %s+4,%s\n",n,l_edx(e2)); | |
3732 } | |
3733 #endif | |
3734 #endif | |
3735 } | |
3736 | |
3737 void code_lrlvar(int e1,int e2) | |
3738 { | |
3739 use_longlong(e2); | |
3740 #if ENDIAN_L==0 | |
3741 printf("\tmovl "); lvar(e1); printf(",%s\n",l_eax(e2)); | |
3742 printf("\tmovl "); lvar(e1+4); printf(",%s\n",l_edx(e2)); | |
3743 #endif | |
3744 } | |
3745 | |
3746 #define check_lreg(reg) if (reg==REG_L) code_lassign_lregister(reg,REG_LCREG) | |
3747 | |
3748 void | |
3749 ltosop(int op,int reg,int e2) | |
3750 { | |
3751 char *opl,*oph,*call; | |
3752 int lb; | |
3753 | |
3754 // e2 (operand) is on the top of the stack | |
3755 use_longlong(reg); | |
3756 opl = 0; call=0; | |
3757 stack_depth -= SIZE_OF_INT * 2; | |
3758 | |
3759 switch(op) { | |
3760 case LLSHIFT: | |
3761 case LULSHIFT: | |
3762 printf("\tmovl %%ecx,4(%%esp)\n"); | |
3763 printf("\tpopl %%ecx\n"); | |
3764 printf("\tshldl %%eax,%%edx\n"); | |
3765 printf("\tsall %%cl,%%eax\n"); | |
3766 printf("\ttestb $32,%%cl\n"); | |
3767 printf("\tje\t_%d\n",(lb=fwdlabel())); | |
3768 printf("\tmovl %%eax,%%edx\n"); | |
3769 printf("\txorl %%eax,%%eax\n"); | |
3770 fwddef(lb); | |
3771 printf("\tpopl %%ecx\n"); | |
3772 check_lreg(reg); | |
3773 return; | |
3774 case LRSHIFT: | |
3775 printf("\tmovl %%ecx,4(%%esp)\n"); | |
3776 printf("\tpopl %%ecx\n"); | |
3777 printf("\tshrdl %%edx,%%eax\n"); | |
3778 printf("\tsarl %%cl,%%edx\n"); | |
3779 printf("\ttestb $32,%%cl\n"); | |
3780 printf("\tje\t_%d\n",(lb=fwdlabel())); | |
3781 printf("\tmovl %%edx,%%eax\n"); | |
3782 printf("\tsarl $31,%%edx\n"); | |
3783 fwddef(lb); | |
3784 printf("\tpopl %%ecx\n"); | |
3785 check_lreg(reg); | |
3786 return; | |
3787 case LURSHIFT: | |
3788 printf("\tmovl %%ecx,4(%%esp)\n"); | |
3789 printf("\tpopl %%ecx\n"); | |
3790 printf("\tshrdl %%edx,%%eax\n"); | |
3791 printf("\tshrl %%cl,%%edx\n"); | |
3792 printf("\ttestb $32,%%cl\n"); | |
3793 printf("\tje\t_%d\n",(lb=fwdlabel())); | |
3794 printf("\tmovl %%edx,%%eax\n"); | |
3795 printf("\txorl %%edx,%%edx\n"); | |
3796 fwddef(lb); | |
3797 printf("\tpopl %%ecx\n"); | |
3798 check_lreg(reg); | |
3799 return; | |
3800 } | |
3801 switch(op) { | |
3802 case LADD: opl="addl";oph="adcl"; break; | |
3803 case LSUB: opl="subl";oph="sbbl"; break; | |
3804 case LBAND: opl=oph="andl"; break; | |
3805 case LEOR: opl=oph="xorl"; break; | |
3806 case LBOR: opl=oph="orl"; break; | |
3807 case LMUL: | |
3808 case LUMUL: | |
3809 printf("\tpushl %%edx\n"); | |
3810 printf("\tpushl %%eax\n"); | |
3811 printf("\tpushl %%ecx\n"); | |
3812 // 0 saved ecx | |
3813 // 4 c_l | |
3814 // 8 c_h | |
3815 // 12 o_l | |
3816 // 16 o_h | |
3817 printf("\tmull 12(%%esp)\n"); // c_l*o_l -> %edx,%eax | |
3818 printf("\tmovl 4(%%esp),%%ecx\n"); // c_l->%ecx | |
3819 printf("\timull 16(%%esp),%%ecx\n"); // c_l*o_h->%ecx | |
3820 printf("\taddl %%ecx,%%edx\n"); // %edx+%ecx->%edx | |
3821 printf("\tmovl 8(%%esp),%%ecx\n"); // c_h->%ecx | |
3822 printf("\timull 12(%%esp),%%ecx\n"); // c_h*o_l->%ecx | |
3823 printf("\taddl %%ecx,%%edx\n"); // %edx+%ecx->%edx | |
3824 printf("\tpopl %%ecx\n"); | |
3825 // printf("\taddl $8,%%esp\n"); | |
3826 printf("\tlea 16(%%esp),%%esp\n"); | |
3827 return; | |
3828 #ifdef __APPLE__ | |
3829 case LDIV: call="L___divdi3$stub"; | |
3830 extern_define("__divdi3",0,FUNCTION,1); break; | |
3831 case LUDIV: call="L___udivdi3$stub"; | |
3832 extern_define("__udivdi3",0,FUNCTION,1); break; | |
3833 case LMOD: call="L___moddi3$stub"; | |
3834 extern_define("__moddi3",0,FUNCTION,1); break; | |
3835 case LUMOD: call="L___umoddi3$stub"; | |
3836 extern_define("__umoddi3",0,FUNCTION,1); break; | |
3837 #else | |
3838 case LDIV: call="__divdi3"; break; | |
3839 case LUDIV: call="__udivdi3"; break; | |
3840 case LMOD: call="__moddi3"; break; | |
3841 case LUMOD: call="__umoddi3"; break; | |
3842 #endif | |
3843 default: error(-1); | |
3844 } | |
3845 if (opl) { | |
3846 printf("\t%s (%%esp),%%eax\n\t%s 4(%%esp),%%edx\n",opl,oph); | |
3847 printf("\tlea 8(%%esp),%%esp\n"); | |
3848 check_lreg(reg); | |
3849 } else if (call) { | |
3850 #ifdef __APPLE__ | |
3851 clear_ptr_cache(); | |
3852 printf("\tpushl %%edx\n"); | |
3853 printf("\tpushl %%eax\n"); | |
3854 printf("\tcall %s\n",call); | |
3855 printf("\tlea 16(%%esp),%%esp\n"); | |
3856 #else | |
3857 printf("\tpushl %%edx\n"); | |
3858 printf("\tpushl %%eax\n"); | |
3859 printf("\tcall %s\n",call); | |
3860 printf("\tlea 16(%%esp),%%esp\n"); | |
3861 #endif | |
3862 check_lreg(reg); | |
3863 } else { | |
3864 error(-1); | |
3865 } | |
3866 } | |
3867 | |
3868 int code_lconst_op_p(int op,int e) { | |
3869 long long l; | |
3870 if (car(e)==CONST) l = cadr(e); | |
3871 else if (car(e)==LCONST) l = lcadr(e); | |
3872 else return 0; | |
3873 | |
3874 switch(op) { | |
3875 case LLSHIFT: | |
3876 case LULSHIFT: | |
3877 case LRSHIFT: | |
3878 case LURSHIFT: | |
3879 return (0<=l&&l<=63); | |
3880 case LMUL: | |
3881 case LUMUL: | |
3882 case LUDIV: | |
3883 /* case LDIV: */ | |
3884 return -0x10000000LL<l&&l<0x10000000LL && ilog(l); | |
3885 case LADD: | |
3886 case LSUB: | |
3887 case LBAND: | |
3888 case LEOR: | |
3889 case LBOR: | |
3890 return 1; | |
3891 default: | |
3892 return 0; | |
3893 } | |
3894 } | |
3895 | |
3896 void loprtc(int op,int reg,int e) { | |
3897 char *opl,*oph=0; | |
3898 int vl,il; | |
3899 int vh; | |
3900 long long l=0; | |
3901 | |
3902 if (car(e)==CONST) l = cadr(e); | |
3903 else if (car(e)==LCONST) l = lcadr(e); | |
3904 else error(-1); | |
3905 | |
3906 vl = code_l1(l); | |
3907 vh = code_l2(l); | |
3908 il = l; | |
3909 | |
3910 use_longlong(reg); | |
3911 opl = 0; | |
3912 | |
3913 switch(op) { | |
3914 case LMUL: case LUMUL: | |
3915 vl=il=ilog(il); | |
3916 case LLSHIFT: | |
3917 case LULSHIFT: | |
3918 if (il==0) return; | |
3919 else if (il==32) { | |
3920 code_register(regv_l(reg),regv_h(reg)); | |
3921 code_const(0,regv_l(reg)); | |
3922 return; | |
3923 } else if (il>32) { | |
3924 code_register(regv_l(reg),regv_h(reg)); | |
3925 printf("\tsall $%d,%s\n",(int)il-32,l_edx(reg)); | |
3926 code_const(0,regv_l(reg)); | |
3927 return; | |
3928 } | |
3929 printf("\tshldl $%d,%s,%s\n",vl,l_eax(reg),l_edx(reg)); | |
3930 printf("\tsall $%d,%s\n",(int)il,l_eax(reg)); return; | |
3931 case LRSHIFT: | |
3932 if (il==0) return; | |
3933 else if (il==32) { | |
3934 code_register(regv_h(reg),regv_l(reg)); | |
3935 creg = ireg = REG_EAX; | |
3936 code_i2ll(reg); | |
3937 return; | |
3938 } else if (il>32) { | |
3939 code_register(regv_h(reg),regv_l(reg)); | |
3940 printf("\tsarl $%d,%s\n",(int)il-32,l_eax(reg)); | |
3941 creg = ireg = REG_EAX; | |
3942 code_i2ll(reg); | |
3943 return; | |
3944 } | |
3945 printf("\tshrdl $%d,%s,%s\n",(int)il,l_edx(reg),l_eax(reg)); | |
3946 printf("\tsarl $%d,%s\n",(int)il,l_edx(reg)); | |
3947 return; | |
3948 case LUDIV: | |
3949 il=ilog(il); | |
3950 case LURSHIFT: | |
3951 if (il==0) return; | |
3952 else if (il==32) { | |
3953 code_register(regv_h(reg),regv_l(reg)); | |
3954 code_const(0,regv_h(reg)); | |
3955 return; | |
3956 } else if (il>32) { | |
3957 if (il>64) error(-1); | |
3958 code_register(regv_h(reg),regv_l(reg)); | |
3959 printf("\tsarl $%d,%s\n",(int)il-32,l_eax(reg)); | |
3960 code_const(0,regv_h(reg)); | |
3961 return; | |
3962 } | |
3963 printf("\tshrdl $%d,%s,%s\n",(int)il,l_edx(reg),l_eax(reg)); | |
3964 printf("\tshrl $%d,%s\n",(int)il,l_edx(reg)); | |
3965 return; | |
3966 } | |
3967 switch(op) { | |
3968 case LADD: opl="addl";oph="adcl"; break; | |
3969 case LSUB: opl="subl";oph="sbbl"; break; | |
3970 case LEOR: opl=oph="xorl"; break; | |
3971 case LBOR: opl=oph="orl"; break; | |
3972 case LBAND: opl=oph="andl"; break; | |
3973 default: error(-1); | |
3974 } | |
3975 printf("\t%s $%d,%s\n\t%s $%d,%s\n",opl,vl,l_eax(reg),oph,vh,l_edx(reg)); | |
3976 } | |
3977 | |
3978 void emit_lpop_free(int e1) | |
3979 { | |
3980 // printf("\taddl $8,%%esp\n"); | |
3981 } | |
3982 | |
3983 void emit_lpush() | |
3984 { | |
3985 stack_depth += SIZE_OF_INT * 2; | |
3986 printf("\tpushl %%edx\n\tpushl %%eax\n"); | |
3987 } | |
3988 | |
3989 void code_i2ll(int reg) | |
3990 { | |
3991 int reg0 = USE_CREG; | |
3992 int creg0 = creg; | |
3993 | |
3994 use_longlong(reg0); | |
3995 use_register(creg0,REG_EAX,1); | |
3996 | |
3997 printf("\tcltd\n"); | |
3998 check_lreg(reg); | |
3999 lreg = creg = reg0; | |
4000 } | |
4001 | |
4002 void code_i2ull(int reg) | |
4003 { | |
4004 code_i2ll(reg); | |
4005 } | |
4006 | |
4007 void code_u2ll(int reg) | |
4008 { | |
4009 int reg0 = USE_CREG; | |
4010 int creg0 = creg; | |
4011 | |
4012 use_longlong(reg0); | |
4013 use_register(creg0,REG_EAX,1); | |
4014 | |
4015 use_longlong(reg0); | |
4016 printf("\txorl %%edx,%%edx\n"); | |
4017 check_lreg(reg); | |
4018 lreg = creg = reg0; | |
4019 } | |
4020 | |
4021 void code_u2ull(int reg) | |
4022 { | |
4023 code_u2ll(reg); | |
4024 } | |
4025 | |
4026 void code_ll2i(int reg) | |
4027 { | |
4028 use_int(reg); | |
4029 if (REG_EAX!=reg) | |
4030 printf("\tmovl %%eax,%s\n",register_name(creg,0)); | |
4031 } | |
4032 | |
4033 void code_ll2u(int reg) | |
4034 { | |
4035 code_ll2i(reg); | |
4036 } | |
4037 | |
4038 void code_ull2i(int reg) | |
4039 { | |
4040 code_ll2i(reg); | |
4041 } | |
4042 | |
4043 void code_ull2u(int reg) | |
4044 { | |
4045 code_ll2i(reg); | |
4046 } | |
4047 | |
4048 #if FLOAT_CODE | |
4049 void code_d2ll(int reg) | |
4050 { | |
4051 use_longlong(reg); | |
4052 #if 1 | |
4053 printf("\tsubl $64, %%esp\n"); | |
4054 printf("\tfnstcw 34(%%esp)\n"); | |
4055 printf("\tmovzwl 34(%%esp), %%eax\n"); | |
4056 printf("\tmovb $12, %%ah\n"); | |
4057 printf("\tmovw %%ax, 32(%%esp)\n"); | |
4058 printf("\tfldcw 32(%%esp)\n"); | |
4059 printf("\tfistpll 52(%%esp)\n"); | |
4060 printf("\tfldcw 34(%%esp)\n"); | |
4061 printf("\tmovl 52(%%esp), %%eax\n"); | |
4062 printf("\tmovl 56(%%esp), %%edx\n"); | |
4063 printf("\taddl $64, %%esp\n"); | |
4064 #else | |
4065 printf("\tsubl $40,%%esp\n"); | |
4066 printf("\tfnstcw 2(%%esp)\n"); | |
4067 printf("\tmovw 2(%%esp),%%ax\n"); | |
4068 printf("\torw $3072,%%ax\n"); | |
4069 printf("\tmovw %%ax,0(%%esp)\n"); | |
4070 printf("\tfldcw 0(%%esp)\n"); | |
4071 printf("\tfistpll 12(%%esp)\n"); | |
4072 printf("\tfldcw 2(%%esp)\n"); | |
4073 printf("\tmovl 12(%%esp),%%eax\n"); | |
4074 printf("\tmovl 16(%%esp),%%edx\n"); | |
4075 printf("\taddl $40,%%esp\n"); | |
4076 #endif | |
4077 check_lreg(reg); | |
4078 } | |
4079 | |
4080 void code_d2ull(int reg) | |
4081 { | |
4082 use_longlong(reg); | |
4083 #ifdef __APPLE__ | |
4084 clear_ptr_cache(); | |
4085 #endif | |
4086 printf("\tsubl $16,%%esp\n"); | |
4087 printf("\tfstpl (%%esp)\n"); | |
4088 #ifdef __APPLE__ | |
4089 printf("\tcall L___fixunsdfdi$stub\n"); | |
4090 extern_define("__fixunsdfdi",0,FUNCTION,1); | |
4091 #else | |
4092 printf("\tcall __fixunsdfdi\n"); | |
4093 #endif | |
4094 printf("\taddl $16,%%esp\n"); | |
4095 } | |
4096 | |
4097 void code_f2ll(int reg) | |
4098 { | |
4099 code_d2ll(reg); | |
4100 } | |
4101 | |
4102 void code_f2ull(int reg) | |
4103 { | |
4104 use_longlong(reg); | |
4105 #ifdef __APPLE__ | |
4106 clear_ptr_cache(); | |
4107 #endif | |
4108 printf("\tsubl $16,%%esp\n"); | |
4109 printf("\tfstps (%%esp)\n"); | |
4110 #ifdef __APPLE__ | |
4111 printf("\tcall L___fixunssfdi$stub\n"); | |
4112 extern_define("__fixunssfdi",0,FUNCTION,1); | |
4113 #else | |
4114 printf("\tcall __fixunssfdi\n"); | |
4115 #endif | |
4116 printf("\taddl $16,%%esp\n"); | |
4117 } | |
4118 | |
4119 void code_ll2d(int reg) | |
4120 { | |
4121 printf("\tsubl $8,%%esp\n"); | |
4122 printf("\tmovl %%eax,(%%esp)\n"); | |
4123 printf("\tmovl %%edx,4(%%esp)\n"); | |
4124 printf("\tfildll (%%esp)\n"); | |
4125 printf("\taddl $8,%%esp\n"); | |
4126 } | |
4127 | |
4128 void code_ll2f(int reg) | |
4129 { | |
4130 code_ll2d(reg); | |
4131 } | |
4132 | |
4133 void code_ull2d(int reg) | |
4134 { | |
4135 code_ll2d(reg); | |
4136 } | |
4137 | |
4138 void code_ull2f(int reg) | |
4139 { | |
4140 code_ll2d(reg); | |
4141 } | |
4142 | |
4143 #endif | |
4144 | |
4145 | |
4146 void code_lpreinc(int e1,int e2,int reg) | |
4147 { | |
4148 int dir = caddr(e1); | |
4149 int creg0; | |
4150 char *crn; | |
4151 if (car(e2)==LREGISTER) { | |
4152 use_longlong(reg); | |
4153 printf("\taddl $%d,%%esi\n",dir); | |
4154 printf("\tadcl $%d,%%edi\n",dir>0?0:-1); | |
4155 if (use && reg!=REG_L) { | |
4156 code_lregister(REG_L,reg); | |
4157 } | |
4158 return; | |
4159 } | |
4160 g_expr(e2); | |
4161 crn = register_name(creg0=creg,0); | |
4162 printf("\taddl $%d,(%s)\n",dir,crn); | |
4163 printf("\tadcl $%d,4(%s)\n",dir>0?0:-1,crn); | |
4164 use_longlong(reg); | |
4165 lload(creg0,0,reg); | |
4166 } | |
4167 | |
4168 void code_lpostinc(int e1,int e2,int reg) | |
4169 { | |
4170 int dir = caddr(e1); | |
4171 int creg0; | |
4172 char *crn; | |
4173 if (car(e2)==LREGISTER) { | |
4174 use_longlong(reg); | |
4175 if (use && reg!=REG_L) { | |
4176 code_lregister(REG_L,reg); | |
4177 } | |
4178 printf("\taddl $%d,%%esi\n",dir); | |
4179 printf("\tadcl $%d,%%edi\n",dir>0?0:-1); | |
4180 return; | |
4181 } | |
4182 g_expr(e2); | |
4183 crn = register_name(creg0=creg,0); | |
4184 printf("\taddl $%d,(%s)\n",dir,crn); | |
4185 printf("\tadcl $%d,4(%s)\n",dir>0?0:-1,crn); | |
4186 if (use) { | |
4187 use_longlong(reg); | |
4188 lload(creg0,0,reg); | |
4189 printf("\taddl $%d,%s\n",-dir,l_eax(reg)); | |
4190 printf("\tadcl $%d,%s\n",-dir>0?0:-1,l_edx(reg)); | |
4191 } | |
4192 } | |
4193 | |
4194 void code_lassop(int op,int reg) | |
4195 { | |
4196 error(-1); | |
4197 } | |
4198 | |
4199 void | |
4200 code_register_lassop(int reg,int op) { | |
4201 error(-1); | |
4202 } | |
4203 | |
4204 | |
4205 #endif | |
4206 | |
4207 | |
4208 | |
4209 | |
4210 | |
4211 #if CASE_CODE | |
4212 | |
4213 int | |
4214 code_table_jump_p(int delta) { return 1; } | |
4215 | |
4216 void | |
4217 code_table_jump(int l,int csvalue,int delta,int max,int min,int dlabel) | |
4218 { | |
4219 char *crn; | |
4220 // use_register(creg,csvalue,0); | |
4221 set_ireg(csvalue,0); | |
4222 crn = register_name(creg,0); | |
4223 printf("\tsubl\t$%d,%s\n",min,crn); | |
4224 printf("\tcmpl\t$%d,%s\n",max-min,crn); | |
4225 printf("\tja\t_%d\n",dlabel); | |
4226 if (delta==1) { | |
4227 #ifdef __APPLE__ | |
4228 printf("\tmovl\t_%d-_%d(%%ebx,%s,4),%s\n",l,goffset_label,crn,crn); | |
4229 printf("\taddl\t%%ebx,%s\n",crn); | |
4230 printf("\tjmp\t*%s\n",crn); | |
4231 #else | |
4232 printf("\tjmp\t*_%d(,%s,4)\n",l,crn); | |
4233 #endif | |
4234 return; | |
4235 } | |
4236 #ifdef __APPLE__ | |
4237 if (regs[REG_EAX]==PTRC_REG) | |
4238 clear_ptr_cache_reg(REG_EAX); | |
4239 #endif | |
4240 use_register(creg,REG_EAX,1); | |
4241 crn = "%eax"; | |
4242 | |
4243 switch(delta) { | |
4244 case 2: | |
4245 printf("\tmovl\t$1,%%edx\n"); | |
4246 printf("\tandl\t%%eax,%%edx\n"); | |
4247 printf("\tjne\t_%d\n",dlabel); | |
4248 #ifdef __APPLE__ | |
4249 printf("\tmovl\t_%d-_%d(%%ebx,%s,2),%s\n",l,goffset_label,crn,crn); | |
4250 printf("\taddl\t%%ebx,%s\n",crn); | |
4251 printf("\tjmp\t*%s\n",crn); | |
4252 #else | |
4253 printf("\tjmp\t*_%d(,%%eax,2)\n",l); | |
4254 #endif | |
4255 break; | |
4256 case 4: | |
4257 printf("\tmovl\t$3,%%edx\n"); | |
4258 printf("\tandl\t%%eax,%%edx\n"); | |
4259 printf("\tjne\t_%d\n",dlabel); | |
4260 #ifdef __APPLE__ | |
4261 printf("\tmovl\t_%d-_%d(%%ebx,%s),%s\n",l,goffset_label,crn,crn); | |
4262 printf("\taddl\t%%ebx,%s\n",crn); | |
4263 printf("\tjmp\t*%s\n",crn); | |
4264 #else | |
4265 printf("\tjmp\t*_%d(%%eax)\n",l); | |
4266 #endif | |
4267 break; | |
4268 default: | |
4269 printf("\tmovl $%d,%%ecx\n",delta); | |
4270 printf("\txor %%edx,%%edx\n\tdivl %%ecx\n"); | |
4271 printf("\tandl\t%%edx,%%edx\n"); | |
4272 printf("\tjne\t_%d\n",dlabel); | |
4273 #ifdef __APPLE__ | |
4274 printf("\tmovl\t_%d-_%d(%%ebx,%s,4),%s\n",l,goffset_label,crn,crn); | |
4275 printf("\taddl\t%%ebx,%s\n",crn); | |
4276 printf("\tjmp\t*%s\n",crn); | |
4277 #else | |
4278 printf("\tjmp\t*_%d(,%%eax,4)\n",l); | |
4279 #endif | |
4280 break; | |
4281 } | |
4282 | |
4283 } | |
4284 | |
4285 void | |
4286 code_table_open(int l) | |
4287 { | |
4288 output_mode=DATA_EMIT_MODE; | |
4289 #ifdef __APPLE__ | |
4290 printf(" \t.align 2\n"); | |
4291 #else | |
4292 printf(" \t.section\t.rodata\n\t.align 4\n"); | |
4293 #endif | |
4294 fwddef(l); | |
4295 } | |
4296 | |
4297 void | |
4298 code_table_value(int label,int table_top) | |
4299 { | |
4300 #ifdef __APPLE__ | |
4301 printf("\t.long _%d-_%d\n",label,goffset_label); | |
4302 #else | |
4303 printf("\t.long _%d\n",label); | |
4304 #endif | |
4305 } | |
4306 | |
4307 void | |
4308 code_table_close() | |
4309 { | |
4310 text_mode(0); | |
4311 } | |
4312 | |
4313 #endif | |
4314 | |
4315 | |
4316 #if ASM_CODE | |
4317 | |
4318 /* | |
4319 print an operand | |
4320 */ | |
4321 | |
4322 static void | |
4323 emit_asm_operand(int rstr) | |
4324 { | |
4325 if (car(rstr)==REGISTER) { | |
4326 printf("%s",register_name(cadr(rstr),0)); | |
4327 } else if (car(rstr)==CONST) { | |
4328 printf("%d",cadr(rstr)); | |
4329 } else if (car(rstr)==FNAME) { | |
4330 #ifdef __APPLE__ | |
4331 printf("_%s-_%d",ncaddr(rstr)->nm,goffset_label); | |
4332 #else | |
4333 printf("%s",ncaddr(rstr)->nm); | |
4334 #endif | |
4335 } else if (car(rstr)==LABEL) { | |
4336 #ifdef __APPLE__ | |
4337 printf("_%d-_%d",cadr(rstr),goffset_label); | |
4338 #else | |
4339 printf("_%d",cadr(rstr)); | |
4340 #endif | |
4341 } else { | |
4342 error(-1); | |
4343 } | |
4344 } | |
4345 | |
4346 /* | |
4347 prepare asm operands | |
4348 | |
4349 char *constraints string | |
4350 int operand expr | |
4351 int mode (ASM_INPUT,ASM_OUTPUT) | |
4352 int replacement list | |
4353 int output operands count | |
4354 int output operands replacement list | |
4355 | |
4356 retrun replacement list | |
4357 list3( operands, next, clobber ) | |
4358 0 can be shared in input/output | |
4359 1 can't be used in input | |
4360 */ | |
4361 | |
4362 int | |
4363 code_asm_operand(char *p,int e1,int mode,int repl,int n,int repl0) | |
4364 { | |
4365 int r; | |
4366 int c; | |
4367 int val; | |
4368 int clobber = 0; | |
4369 | |
4370 printf("## constraint %s\n",p); | |
4371 if (*p=='=') { | |
4372 // output register | |
4373 p++; | |
4374 } | |
4375 if (*p=='&') { | |
4376 // earlyclobber | |
4377 p++; | |
4378 clobber = 1; | |
4379 } | |
4380 c = *p; | |
4381 if (c=='r') { | |
4382 if (mode==ASM_INPUT) { | |
4383 for(;repl0;repl0 = cadr(repl0)) { | |
4384 if (car(car(repl0))==REGISTER && caddr(repl0)==0) { | |
4385 r = cadr(car(repl0)); | |
4386 caddr(repl0) = ASM_USED; | |
4387 break; | |
4388 } | |
4389 } | |
4390 r = get_register(); | |
4391 } else { | |
4392 r = get_register(); | |
4393 } | |
4394 repl = list3(list2(REGISTER,r),repl,clobber); | |
4395 } else if (c=='m') { | |
4396 repl = list3(list2(0,0),repl,clobber); | |
4397 } else if (c=='i') { | |
4398 if (car(e1)==GVAR) { | |
4399 e1=list3n(FNAME,0,ncaddr(e1)); | |
4400 } else if (car(e1)==FNAME) { | |
4401 e1=list3n(FNAME,0,ncaddr(e1)); | |
4402 } else if (car(e1)==STRING) { | |
4403 val = emit_string_label(); | |
4404 ascii(ncaddr(e1)->nm); | |
4405 e1=list2(LABEL,val); | |
4406 } else if (car(e1)==CONST) { | |
4407 } else error(-1); | |
4408 repl = list3(e1,repl,clobber); | |
4409 } else if (digit(c)) { | |
4410 val = 0; | |
4411 do { val = val*10 + c-'0'; } while (digit(c=*p++)); | |
4412 if (val>MAX_ASM_REG) error(-1); // too large register | |
4413 if (n-val<0) error(-1); | |
4414 repl = list3(car(nth(n-val-1,repl0)),repl,clobber); | |
4415 } else error(-1); | |
4416 return repl; | |
4417 } | |
4418 | |
4419 void | |
4420 code_free_asm_operand(int repl) | |
4421 { | |
4422 int reg; | |
4423 for(;repl;repl=cadr(repl)) { | |
4424 if (car(car(repl))==REGISTER) { | |
4425 reg = cadr(car(repl)); | |
4426 if (regs[reg]!=REG_VAR) free_register(reg); | |
4427 } | |
4428 } | |
4429 } | |
4430 | |
4431 | |
4432 extern void | |
4433 code_asm(char *asm_str,int repl) | |
4434 { | |
4435 int c,i,rstr,val; | |
4436 char *p; | |
4437 int reg[MAX_ASM_REG]; | |
4438 | |
4439 text_mode(0); | |
4440 c = *asm_str; | |
4441 if (c!='\t'&&c!=' ') printf("\t"); | |
4442 for(i=0;repl && i<MAX_ASM_REG;i++) { | |
4443 reg[i] = car(repl); | |
4444 repl = cadr(repl); | |
4445 } | |
4446 p = asm_str; | |
4447 while((c = *p++)) { | |
4448 if (c=='%') { | |
4449 c = *p++; | |
4450 if (!c) { break; | |
4451 } else if (c=='%') { | |
4452 printf("%%"); continue; | |
4453 } else if (!digit(c)) { | |
4454 printf("%%%c",c); continue; | |
4455 } | |
4456 val = 0; | |
4457 do { val = val*10 + c-'0'; } while (digit(c=*p++)) ; | |
4458 p--; | |
4459 if (val>MAX_ASM_REG) error(-1); // too large register | |
4460 rstr = reg[val]; | |
4461 emit_asm_operand(rstr); | |
4462 } else { | |
4463 printf("%c",c); | |
4464 } | |
4465 } | |
4466 printf("\n"); | |
4467 } | |
4468 | |
4469 #endif | |
4470 | |
4471 | |
4472 #if BIT_FIELD_CODE | |
4473 | |
4474 /* bit field alignment calcuration */ | |
4475 | |
4476 static void | |
4477 set_bitsz(int type,int *pbitpos, int *pbitsize, | |
4478 int *psign,int *pbitsz,int *palign,int *pl) | |
4479 { | |
4480 int sign=0,bitsz=1; | |
4481 int align=4,l=0; | |
4482 *pbitpos = cadr(caddr(type)); | |
4483 *pbitsize = caddr(caddr(type)); | |
4484 | |
4485 switch(cadr(type)) { | |
4486 case INT: sign=1; bitsz=32; align=4;break; | |
4487 case UNSIGNED: bitsz=32; align=4;break; | |
4488 case CHAR: sign=1; bitsz= 8; align=1;break; | |
4489 case UCHAR: bitsz= 8; align=1;break; | |
4490 case SHORT: sign=1; bitsz=16; align=2;break; | |
4491 case USHORT: sign=1; bitsz=16; align=2;break; | |
4492 case LONGLONG: sign=1; bitsz=64; align=4;l=1; break; | |
4493 case ULONGLONG: bitsz=64; align=4;l=1; break; | |
4494 default: error(-1); | |
4495 } | |
4496 *psign = sign; | |
4497 *pbitsz = bitsz; | |
4498 *palign = align; | |
4499 *pl = l; | |
4500 } | |
4501 | |
4502 /* | |
4503 bit field alignment calcuration | |
4504 this is architecture depenedent | |
4505 */ | |
4506 | |
4507 extern int | |
4508 code_bit_field_disp(int type,int *poffset,int *bfd,int *sz) | |
4509 { | |
4510 int sign,bitsz,align; | |
4511 int i; | |
4512 int bitpos = *bfd; | |
4513 int bitpos0; | |
4514 int bitsize; | |
4515 int offset = *poffset; | |
4516 int l; | |
4517 set_bitsz(type,&bitpos0,&bitsize,&sign,&bitsz,&align,&l); | |
4518 | |
4519 if (bitsize>bitsz) { error(BTERR); bitsize = bitsz; } | |
4520 | |
4521 /* bfd means previous bit field bit offset */ | |
4522 if (bitpos) { | |
4523 /* previous field is bit field and spaces may remain */ | |
4524 /* calc previsous offset */ | |
4525 | |
4526 i= offset-(bitpos+7)/8; | |
4527 | |
4528 for(l = bitpos;l>0;l -= 8,i++) { | |
4529 if ((i & (align-1))==0 && l+bitsize <= bitsz) { | |
4530 /* alignment is correct and space remains */ | |
4531 *poffset=offset=i; | |
4532 i = l+bitsize; | |
4533 *bfd = (i==bitsz)?0:i; | |
4534 *sz = (i+7)/8; | |
4535 // printf("## bitpos=%d bitsize=%d bitsz=%d offset=%d\n",l,bitsize,bitsz,*poffset); | |
4536 return l; | |
4537 } | |
4538 } | |
4539 } | |
4540 | |
4541 /* first bit-field */ | |
4542 | |
4543 if ((i=(offset & (align-1)))) { | |
4544 *poffset = (offset += (align-i)); | |
4545 } | |
4546 bitpos = 0; | |
4547 *bfd = (bitsize==bitsz)?0:bitsize; | |
4548 *sz = (bitsize+7)/8; | |
4549 | |
4550 // printf("## bitpos=%d bitsize=%d bitsz=%d offset=%d\n",bitpos,bitsize,bitsz,*poffset); | |
4551 return bitpos; | |
4552 } | |
4553 | |
4554 /* bit field value */ | |
4555 | |
4556 extern void | |
4557 code_bit_field(int type,int adr,int reg) | |
4558 { | |
4559 int sign,bitsz,l,align; | |
4560 int bitsize,bitpos; | |
4561 int i,size; | |
4562 set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); | |
4563 size=bitsz/8; | |
4564 // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); | |
4565 /* this implementation returns -1 for int i:1; */ | |
4566 if (l==1) { | |
4567 #if LONGLONG_CODE | |
4568 use_int(adr); | |
4569 use_longlong(reg); | |
4570 lload(adr,0,reg); | |
4571 /* shift left */ | |
4572 if ((i=bitsz-bitsize-bitpos)) | |
4573 loprtc(LLSHIFT,reg,list2(CONST,i)); | |
4574 /* shift right */ | |
4575 if ((i=bitsz-bitsize)) | |
4576 loprtc(sign?LRSHIFT:LURSHIFT,reg,list2(CONST,i)); | |
4577 #endif | |
4578 } else { | |
4579 use_int(adr); | |
4580 use_int(reg); | |
4581 printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), | |
4582 register_name(reg,0)); | |
4583 /* shift left */ | |
4584 if ((i=32-bitsize-bitpos)) | |
4585 oprtc(LSHIFT,reg,list2(CONST,i)); | |
4586 /* shift right */ | |
4587 if ((i=32-bitsize)) | |
4588 oprtc(sign?RSHIFT:URSHIFT,reg,list2(CONST,i)); | |
4589 } | |
4590 } | |
4591 | |
4592 /* bit field replacement */ | |
4593 | |
4594 static void | |
4595 make_mask_and_or(int mask,int reg,int lreg) | |
4596 { | |
4597 printf("## mask 0x%08x ~0x%08x\n",mask,~mask); | |
4598 printf("\tpushl %s\n",register_name(reg,0)); | |
4599 /* make and-mask */ | |
4600 oprtc(BOR,reg,list2(CONST,~mask)); | |
4601 /* do conjunction */ | |
4602 if (lreg==-1) { | |
4603 printf("\tandl %s,4(%%esp)\n",register_name(reg,0)); | |
4604 } else if (lreg==-2) { | |
4605 printf("\tandl %s,8(%%esp)\n",register_name(reg,0)); | |
4606 } else { | |
4607 printf("\tandl %s,%s\n",register_name(reg,0),register_name(lreg,0)); | |
4608 } | |
4609 /* make or-mask */ | |
4610 printf("\tpopl %s\n",register_name(reg,0)); | |
4611 oprtc(BAND,reg,list2(CONST,mask)); | |
4612 /* do disjunction */ | |
4613 if (lreg==-1) { | |
4614 printf("\torl %s,0(%%esp)\n",register_name(reg,0)); | |
4615 } else if (lreg==-2) { | |
4616 printf("\torl %s,4(%%esp)\n",register_name(reg,0)); | |
4617 } else { | |
4618 printf("\torl %s,%s\n",register_name(reg,0),register_name(lreg,0)); | |
4619 printf("\txchg %s,%s\n",register_name(reg,0),register_name(lreg,0)); | |
4620 } | |
4621 } | |
4622 | |
4623 extern void | |
4624 code_bit_replace(int adr,int value,int type) | |
4625 { | |
4626 int sign,bitsz,l,align; | |
4627 int bitsize,bitpos; | |
4628 int mask = 0; | |
4629 int size; | |
4630 set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); | |
4631 size = bitsz/8; | |
4632 // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); | |
4633 if (l) { | |
4634 #if LONGLONG_CODE | |
4635 int push=0; | |
4636 use_int(adr); | |
4637 use_longlong(value); | |
4638 /* shift left */ | |
4639 if (bitpos) | |
4640 loprtc(LLSHIFT,value,list2(CONST,bitpos)); | |
4641 if (bitpos+bitsize>=32) { | |
4642 /* make and-mask upper */ | |
4643 printf("\tpushl %s\n",register_name(adr,0)); push=1; | |
4644 printf("\t%s %d(%s),%s\n",cload(sign,size),4,register_name(adr,0), | |
4645 register_name(adr,0)); | |
4646 mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); | |
4647 make_mask_and_or(mask,regv_h(value),adr); | |
4648 printf("\tmovl 0(%%esp),%s\n",register_name(adr,0)); | |
4649 printf("\t%s %s,4(%s)\n",move(0), | |
4650 l_edx(value), register_name(adr,0)); | |
4651 } | |
4652 if (bitpos<32) { | |
4653 if (!push) { printf("\tpushl %s\n",register_name(adr,0)); push=1;} | |
4654 /* make and-mask lower */ | |
4655 printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), | |
4656 register_name(adr,0)); | |
4657 mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); | |
4658 make_mask_and_or(mask,regv_l(value),adr); | |
4659 printf("\tpopl %s\n",register_name(adr,0)); push=0; | |
4660 printf("\t%s %s,(%s)\n",move(0), | |
4661 l_eax(value), register_name(adr,0)); | |
4662 } | |
4663 if (push) printf("\taddl %%sp,$4\n"); | |
4664 #endif | |
4665 } else { | |
4666 use_int(adr); | |
4667 use_int(value); | |
4668 printf("\tpushl %s\n",register_name(adr,0)); | |
4669 printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), | |
4670 register_name(adr,0)); | |
4671 /* shift left */ | |
4672 if (bitpos) | |
4673 oprtc(LSHIFT,value,list2(CONST,bitpos)); | |
4674 /* make and-mask */ | |
4675 mask = make_mask(32-bitpos-bitsize,31-bitpos); | |
4676 make_mask_and_or(mask,value,adr); | |
4677 printf("\tpopl %s\n",register_name(adr,0)); | |
4678 code_assign(adr,size==4?0:size,value); | |
4679 } | |
4680 if (use) { | |
4681 code_bit_field(type,adr,USE_CREG); | |
4682 } | |
4683 } | |
4684 | |
4685 | |
4686 static void | |
4687 make_mask_and_or_const(int mask,int reg,int c) | |
4688 { | |
4689 int a; | |
4690 // printf("## mask 0x%08x ~0x%08x\n",mask,~mask); | |
4691 a = ~mask|c; | |
4692 if (a!=-1) { | |
4693 /* do conjunction */ | |
4694 if (reg<MAX_DATA_REG && ((a& ~0xffff)==~0xffff)) { | |
4695 if ((a& ~0xff)==~0xff) | |
4696 printf("\tandb $%d,%s\n",a&0xff,register_name(reg,1)); | |
4697 else | |
4698 printf("\tandw $%d,%s\n",a&0xffff,register_name(reg,2)); | |
4699 } else | |
4700 printf("\tandl $%d,%s\n",a,register_name(reg,0)); | |
4701 } | |
4702 /* make or-mask */ | |
4703 c = mask&c; | |
4704 if (c!=0) { | |
4705 /* do disjunction */ | |
4706 if (reg<MAX_DATA_REG && (!(c& ~0xffff))) { | |
4707 if (!(c& ~0xff)) | |
4708 printf("\torb $%d,%s\n",c&0xff,register_name(reg,1)); | |
4709 else | |
4710 printf("\torw $%d,%s\n",c&0xffff,register_name(reg,2)); | |
4711 } else | |
4712 printf("\torl $%d,%s\n",c,register_name(reg,0)); | |
4713 } | |
4714 } | |
4715 | |
4716 extern void | |
4717 code_bit_replace_const(int value,int adr,int type) | |
4718 { | |
4719 int sign,bitsz,l,align; | |
4720 int bitpos,bitsize,size; | |
4721 int mask = 0; | |
4722 int c,lvalue; | |
4723 #if LONGLONG_CODE | |
4724 long long lc; | |
4725 #endif | |
4726 set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); | |
4727 size = bitsz/8; | |
4728 // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); | |
4729 use_int(adr); | |
4730 if (l) { | |
4731 #if LONGLONG_CODE | |
4732 lvalue = get_register(); | |
4733 /* shift left */ | |
4734 lc = lcadr(value); | |
4735 lc <<= bitpos; | |
4736 | |
4737 if (bitpos+bitsize>=32) { | |
4738 printf("\t%s %d(%s),%s\n",cload(sign,size),4,register_name(adr,0), | |
4739 register_name(lvalue,0)); | |
4740 /* make and-mask upper */ | |
4741 mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); | |
4742 make_mask_and_or_const(mask,lvalue,(int)(lc>>32)); | |
4743 printf("\t%s %s,4(%s)\n",move(0),register_name(lvalue,0), | |
4744 register_name(adr,0)); | |
4745 } | |
4746 if (bitpos<32) { | |
4747 printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), | |
4748 register_name(lvalue,0)); | |
4749 /* make and-mask lower */ | |
4750 mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); | |
4751 make_mask_and_or_const(mask,lvalue,(int)(lc)); | |
4752 printf("\t%s %s,(%s)\n",move(0), | |
4753 register_name(lvalue,0),register_name(adr,0)); | |
4754 } | |
4755 free_register(lvalue); | |
4756 #endif | |
4757 } else { | |
4758 lvalue = get_register(); | |
4759 printf("\t%s %d(%s),%s\n",cload(sign,size),0,register_name(adr,0), | |
4760 register_name(lvalue,0)); | |
4761 /* shift left */ | |
4762 c = cadr(value); | |
4763 c <<= bitpos; | |
4764 /* make and-mask */ | |
4765 mask = make_mask(32-bitpos-bitsize,31-bitpos); | |
4766 make_mask_and_or_const(mask,lvalue,c); | |
4767 code_assign(adr,size==4?0:size,lvalue); | |
4768 free_register(lvalue); | |
4769 } | |
4770 if (use) | |
4771 code_bit_field(type,adr,USE_CREG); | |
4772 } | |
4773 | |
4774 #endif | |
4775 | |
4776 int | |
4777 not_simple_p(int e3) | |
4778 { | |
4779 switch(e3) { | |
4780 case FUNCTION: case CONV: case STASS: case ALLOCA: | |
4781 case LDIV: case LUDIV: case LMOD: case LUMOD: | |
4782 case LMUL: case LUMUL: | |
4783 case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: | |
4784 case DDIV: case DADD: case DSUB: case DMUL: case DMINUS: | |
4785 case DPOSTINC : case DPREINC : case DASSOP : | |
4786 case DOP+LT : case DOP+LE : case DOP+GT : case DOP+GE : | |
4787 case DOP+EQ : case DOP+NEQ: | |
4788 case RBIT_FIELD: case BASS: case BASSOP: case LCALL: | |
4789 case INLINE: | |
4790 return 1; | |
4791 } | |
4792 return 0; | |
4793 } | |
4794 | |
4795 extern int | |
4796 code_arg_alignment(int args,NMTBL *n, int type0,int sz) | |
4797 { | |
4798 return code_arg_alignment0(args,n, type0,sz); | |
4799 } | |
4800 | |
4801 | |
4802 extern int | |
4803 code_lvar_alignment(int args,NMTBL *n, int type0,int sz) | |
4804 { | |
4805 return code_lvar_alignment0(args,n, type0,sz); | |
4806 } | |
4807 | |
4808 | |
4809 /* end */ |