Mercurial > hg > CbC > old > device
comparison mc-code-spu.c @ 661:f566ac85f2e0
*** empty log message ***
author | kono |
---|---|
date | Wed, 21 Feb 2007 20:11:23 +0900 |
parents | |
children | c9df4e08da9b |
comparison
equal
deleted
inserted
replaced
660:3e1dba5758d8 | 661:f566ac85f2e0 |
---|---|
1 /* Micro-C Code Generation Part for Cell SPU */ | |
2 /* ************************************************************************ | |
3 ** Copyright (C) 2007 Shinji Kono | |
4 ** 連絡先: 琉球大学情報工学科 河野 真治 | |
5 ** (E-Mail Address: kono@ie.u-ryukyu.ac.jp) | |
6 ** | |
7 ** このソースのいかなる複写,改変,修正も許諾します。ただし、 | |
8 ** その際には、誰が貢献したを示すこの部分を残すこと。 | |
9 ** 再配布や雑誌の付録などの問い合わせも必要ありません。 | |
10 ** 営利利用も上記に反しない範囲で許可します。 | |
11 ** バイナリの配布の際にはversion messageを保存することを条件とします。 | |
12 ** このプログラムについては特に何の保証もしない、悪しからず。 | |
13 ** | |
14 ** Everyone is permitted to do anything on this program | |
15 ** including copying, modifying, improving, | |
16 ** as long as you don't try to pretend that you wrote it. | |
17 ** i.e., the above copyright notice has to appear in all copies. | |
18 ** Binary distribution requires original version messages. | |
19 ** You don't have to ask before copying, redistribution or publishing. | |
20 ** THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE. | |
21 ***********************************************************************/ | |
22 | |
23 #include <stdio.h> | |
24 #include "mc.h" | |
25 #include "mc-parse.h" | |
26 #include "mc-code.h" | |
27 #include "mc-codegen.h" | |
28 | |
29 char *l_include_path[]={ | |
30 "/usr/lib/gcc/spu/4.0.2/include", | |
31 "/usr/spu/include", | |
32 0}; | |
33 | |
34 // va_start, va_arg is wrong, use va_arm.h | |
35 | |
36 static char *init_src0 = "\ | |
37 #define __SPU__ 1\n\ | |
38 #define __STDC_HOSTED__ 1\n\ | |
39 #define __GNUC__ 4\n\ | |
40 #define __FLT_MIN_EXP__ (-125)\n\ | |
41 #define __DBL_MIN__ 2.2250738585072014e-308\n\ | |
42 #define __NO_INLINE__ 1\n\ | |
43 #define __ELF__ 1\n\ | |
44 #define __FLT_RADIX__ 2\n\ | |
45 #define __LDBL_EPSILON__ 2.2204460492503131e-16L\n\ | |
46 #define __vector __attribute__((spu_vector))\n\ | |
47 #define __WCHAR_TYPE__ int\n\ | |
48 #define __DBL_EPSILON__ 2.2204460492503131e-16\n\ | |
49 #define __INTMAX_MAX__ 9223372036854775807LL\n\ | |
50 #define __FLT_DENORM_MIN__ 1.40129846e-45F\n\ | |
51 #define __FLT_MAX__ 6.80564693e+38F\n\ | |
52 #define __FLT_MIN_10_EXP__ (-37)\n\ | |
53 #define __INTMAX_TYPE__ long long int\n\ | |
54 #define __GNUC_MINOR__ 0\n\ | |
55 #define __DBL_MAX_10_EXP__ 308\n\ | |
56 #define __LDBL_DENORM_MIN__ 4.9406564584124654e-324L\n\ | |
57 #define __PTRDIFF_TYPE__ long int\n\ | |
58 #define __LDBL_MIN_10_EXP__ (-307)\n\ | |
59 #define __LDBL_DIG__ 15\n\ | |
60 #define __WINT_TYPE__ unsigned int\n\ | |
61 "; | |
62 | |
63 int data_alignment = 0; | |
64 | |
65 #define TEXT_EMIT_MODE 0 | |
66 #define DATA_EMIT_MODE 1 | |
67 #define RODATA_EMIT_MODE 2 | |
68 | |
69 #define DOT_SIZE 1 | |
70 | |
71 // static void data_mode(char *name); | |
72 // static void text_mode(int alignment); | |
73 static void ld_indexx(int byte, int n, int xreg,int reg,int sign); | |
74 static void local_table(void); | |
75 static void shift(char *op, int creg,int reg); | |
76 static int push_struct(int e4,int t,int arg); | |
77 static void register_usage(char *s); | |
78 static void code_add(int reg,int offset,int r); | |
79 static void const_list_table(); | |
80 //static int search_const(int tag,int value,int *label); | |
81 static char * cstore(int sz); | |
82 static void code_int_lib(char *lib,int reg,int oreg); | |
83 static int caller_arg_offset_v(int arg); | |
84 static void pcond(int op, int r2,int r1,int r0,int cond,int l1,int mode); | |
85 #if FLOAT_CODE | |
86 static int code_d1(double d); | |
87 static int code_d2(double d); | |
88 static void code_float_lib(char *opc,int oreg,int in_reg,int e1); | |
89 static void code_float_lib_c(char *lib,int from,int to,double value); | |
90 static void code_double_lib(char *lib,int to,int reg,int oreg); | |
91 static void code_double_lib_c(char *lib,int from,int to,double value); | |
92 static void dconst(int l,int h,double value); | |
93 static void code_assign_input_double_long(int e1,int e2) ; | |
94 static void code_assign_input_float_int(int e1,int e2) ; | |
95 #endif | |
96 static void use_input_reg(int reg,int mode); | |
97 static void ascii(char *s); | |
98 | |
99 static int creg; | |
100 static int output_mode = TEXT_EMIT_MODE; | |
101 static int register_save_return_label; | |
102 | |
103 static int r1_offset_label; | |
104 static int lvar_offset_label; | |
105 static int max_func_args = 0; | |
106 static int arg_on_register = 0; | |
107 static int max_func_arg_label = 0; | |
108 | |
109 | |
110 static int freg,ireg,lreg; | |
111 | |
112 int code_lassop_p = 4; | |
113 | |
114 #define SIZE_OF_INT 4 | |
115 #define SIZE_OF_SHORT 2 | |
116 #define SIZE_OF_FLOAT 4 | |
117 #define SIZE_OF_DOUBLE 8 | |
118 #define SIZE_OF_LONGLONG 8 | |
119 #define ENDIAN 0 | |
120 #define ENDIAN_L 0 | |
121 #define ENDIAN_D 1 | |
122 | |
123 int eval_order = NORMAL; | |
124 | |
125 static int reg_sp; /* REGister Stack-Pointer */ | |
126 static int reg_stack[MAX_MAX]; /* 実際のレジスタの領域 */ | |
127 | |
128 | |
129 #define REG_ip 13 | |
130 #define REG_fp 0 | |
131 #define REG_sp 1 | |
132 #define REG_VAR_BASE 3 | |
133 #define REG_VAR_MIN 3 | |
134 #define REG_VAR_USER_MAX 127 /* at leat 6 tmp var */ | |
135 #define REG_VAR_MAX 127 | |
136 #define MIN_TMP_REG 4 | |
137 #define MAX_TMP_REG 127 | |
138 | |
139 #define FREG_VAR_BASE 3 | |
140 #define FREG_VAR_MIN 3 | |
141 #define FREG_VAR_MAX 127 | |
142 #define MIN_TMP_FREG 3 | |
143 #define MAX_TMP_FREG 127 | |
144 | |
145 int MAX_REGISTER=127; /* ARMのレジスタを10個まで使う*/ | |
146 #define REAL_MAX_REGISTER 127 /* ARMのレジスタが32ということ*/ | |
147 | |
148 #define FREG_OFFSET 3 | |
149 #define LREG_OFFSET 3 | |
150 | |
151 int MAX_INPUT_REGISTER_VAR = 80; | |
152 int MAX_INPUT_DREGISTER_VAR = 80; | |
153 int MAX_INPUT_FREGISTER_VAR = 80; | |
154 int MAX_CODE_INPUT_REGISTER_VAR = 80; | |
155 int MAX_CODE_INPUT_DREGISTER_VAR = 80; | |
156 int MAX_CODE_INPUT_FREGISTER_VAR = 80; | |
157 | |
158 #define LREG_V 3 /* mark for virtual long long/double register */ | |
159 #define REGS_MAX (REAL_MAX_REGISTER) | |
160 static int spu_regs[REGS_MAX]; | |
161 /// #define (i) (i) | |
162 // #define (i) (i) | |
163 | |
164 #define RET_REGISTER 3 | |
165 #define REGISTER_OPERAND 3 //this is first register for input | |
166 #define REGISTER_OPERAND_1 4 | |
167 #define RET_FREGISTER FREG_OFFSET | |
168 #define FREGISTER_OPERAND (FREG_OFFSET) | |
169 #define FREGISTER_OPERAND_1 (FREG_OFFSET+1) | |
170 | |
171 #define RET_LREGISTER 3 | |
172 #define LREGISTER_OPERAND 3 | |
173 #define LREGISTER_OPERAND_1 4 | |
174 #define RET_LREGISTER_L 1 /* low word */ | |
175 #define RET_LREGISTER_H 2 /* high word */ | |
176 #define LREGISTER_OPERAND_L 1 /* low word */ | |
177 #define LREGISTER_OPERAND_H 2 /* high word */ | |
178 #define LREGISTER_OPERAND_1_L 3 /* low word */ | |
179 #define LREGISTER_OPERAND_1_H 4 /* high word */ | |
180 | |
181 #define RET_DREGISTER RET_LREGISTER | |
182 #define DREGISTER_OPERAND LREGISTER_OPERAND | |
183 #define DREGISTER_OPERAND_1 LREGISTER_OPERAND_1 | |
184 #define RET_DREGISTER_L RET_LREGISTER_L | |
185 #define RET_DREGISTER_H RET_LREGISTER_H | |
186 #define DREGISTER_OPERAND_H LREGISTER_OPERAND_H | |
187 #define DREGISTER_OPERAND_L LREGISTER_OPERAND_L | |
188 #define DREGISTER_OPERAND_1_L LREGISTER_OPERAND_1_L | |
189 #define DREGISTER_OPERAND_1_H LREGISTER_OPERAND_1_H | |
190 | |
191 static int *regs = spu_regs; | |
192 | |
193 // #define CREG_REGISTER (MAX_TMP_REG) | |
194 #define CREG_REGISTER REGISTER_OPERAND | |
195 // #define FREG_FREGISTER (MAX_TMP_FREG+FREG_OFFSET) | |
196 #define FREG_FREGISTER FREGISTER_OPERAND | |
197 // #define LREG_LREGISTER (MAX_TMP_REG+LREG_OFFSET) | |
198 #define LREG_LREGISTER LREGISTER_OPERAND | |
199 #define DREG_DREGISTER LREG_LREGISTER | |
200 #define CMP_C1T (-1) | |
201 | |
202 | |
203 static int max_reg_var; | |
204 | |
205 | |
206 static char *reg_name[] = { | |
207 "$0", "$1", "$2", "$3", "$4", "$5", "$6", "$7", | |
208 "$8", "$9", "$10", "$11", "$12", "$13", "$14", "$15", | |
209 "$16", "$17", "$18", "$19", "$20", "$21", "$22", "$23", | |
210 "$24", "$25", "$26", "$27", "$28", "$29", "$30", "$31", | |
211 "$32", "$33", "$34", "$35", "$36", "$37", "$38", "$39", | |
212 "$40", "$41", "$42", "$43", "$44", "$45", "$46", "$47", | |
213 "$48", "$49", "$50", "$51", "$52", "$53", "$54", "$55", | |
214 "$56", "$57", "$58", "$59", "$60", "$61", "$62", "$63", | |
215 "$64", "$65", "$66", "$67", "$68", "$69", "$70", "$71", | |
216 "$72", "$73", "$74", "$75", "$76", "$77", "$78", "$79", | |
217 "$80", "$81", "$82", "$83", "$84", "$85", "$86", "$87", | |
218 "$88", "$89", "$90", "$91", "$92", "$93", "$94", "$95", | |
219 "$96", "$97", "$98", "$99", "$100", "$101", "$102", "$103", | |
220 "$104", "$105", "$106", "$107", "$108", "$109", "$110", "$111", | |
221 "$112", "$113", "$114", "$115", "$116", "$117", "$118", "$119", | |
222 "$120", "$121", "$122", "$123", "$124", "$125", "$126", "$127" | |
223 }; | |
224 | |
225 #define register_name(i) reg_name[i] | |
226 #define lregister_name_low(i) reg_name[i] | |
227 #define lregister_name_high(i) reg_name[i] | |
228 | |
229 char *rn(int i) { return register_name(i); } | |
230 char *lln(int i) { return lregister_name_low(i); } | |
231 char *lhn(int i) { return lregister_name_high(i); } | |
232 int ll(int i) { return i; } | |
233 int lh(int i) { return i; } | |
234 | |
235 #define is_int_reg(i) (0<=i&&i<REAL_MAX_REGISTER) | |
236 #define is_float_reg(i) (is_int_reg(i)) | |
237 #define is_longlong_reg(i) (is_int_reg(i)) | |
238 #define is_double_reg(i) (is_int_reg(i)) | |
239 | |
240 #define use_int(reg) if (reg==USE_CREG) reg=use_int0() | |
241 static | |
242 int use_int0() { | |
243 int i = creg; | |
244 if (!i||!ireg||!is_int_reg(i)) { | |
245 if (lreg) { if (regs[lreg]) free_register(lreg); lreg = 0; } | |
246 if (!ireg) ireg = get_register(); | |
247 // else if (ireg!=i) free_register(i); | |
248 i = ireg; | |
249 } | |
250 if (!regs[i]) regs[i]=USING_REG; | |
251 creg = i; | |
252 return i; | |
253 } | |
254 | |
255 #if LONGLONG_CODE||FLOAT_CODE | |
256 #define use_longlong(reg) if (reg==USE_CREG) reg=use_int0() | |
257 /* | |
258 static | |
259 int use_longlong0() { | |
260 int i = creg; | |
261 if (!is_longlong_reg(i)) { | |
262 if (ireg) { free_register(ireg); ireg=0; } | |
263 if (!lreg||!regs[lreg]) lreg = get_lregister(); | |
264 else if (lreg!=i) free_register(i); | |
265 i = lreg; | |
266 } | |
267 if (!(i)) (i) = get_register(); | |
268 if (!(i)) (i) = get_register(); | |
269 if (!regs[i]) regs[i]=USING_REG; | |
270 if (!regs[(i)]) regs[(i)]=USING_REG; | |
271 if (!regs[(i)]) regs[(i)]=USING_REG; | |
272 creg = i; | |
273 return i; | |
274 } | |
275 */ | |
276 static void lmove(int to,int from); | |
277 #endif | |
278 | |
279 #define USING_DREG 5 | |
280 #define INPUT_DREG 6 | |
281 | |
282 | |
283 #if FLOAT_CODE | |
284 | |
285 #define dsuffix(d) (d?'d':'s') | |
286 | |
287 #define use_float(d,reg) if (reg==USE_CREG) { reg=use_int0();} | |
288 | |
289 /* | |
290 static | |
291 int use_double0() { | |
292 int i; | |
293 use_longlong0(); | |
294 use_int0(); | |
295 i = lreg; | |
296 if (!regs[i]) regs[i]=USING_DREG; | |
297 if (!regs[(i)]) regs[(i)]=USING_REG; | |
298 if (!regs[(i)]) regs[(i)]=USING_REG; | |
299 creg = i; | |
300 return i; | |
301 } | |
302 */ | |
303 void code_lassign_lvar(int e2,int creg); | |
304 int code_lrindirect(int e1, int reg, int offset, int us); | |
305 void code_lregister(int e2,int reg); | |
306 void code_lassign_gvar(int e2,int creg); | |
307 void code_lassign(int e2,int creg); | |
308 void code_lassign_lregister(int e2,int reg); | |
309 void code_lrgvar(int e1,int creg); | |
310 void code_lrlvar(int e1,int creg); | |
311 void emit_lpop_free(int xreg); | |
312 void emit_lpush(); | |
313 int emit_lpop(); | |
314 | |
315 #endif | |
316 | |
317 | |
318 | |
319 #if LONGLONG_CODE | |
320 static int code_l1(long long ll); | |
321 static int code_l2(long long ll); | |
322 #endif | |
323 | |
324 static void code_save_input_registers(int dots); | |
325 static void set_ireg(int,int); | |
326 #if FLOAT_CODE | |
327 static void set_dreg(int,int); | |
328 static void set_freg(int,int); | |
329 #endif | |
330 #if LONGLONG_CODE | |
331 static void set_lreg(int,int); | |
332 #endif | |
333 | |
334 static int max_func_args; | |
335 static int my_func_args; | |
336 | |
337 | |
338 | |
339 | |
340 | |
341 static void jcond(int l, int cond); | |
342 | |
343 #define ARG_LVAR_OFFSET 0x10000000 | |
344 | |
345 #define round16(i) ((i+0xf)&~0xf) | |
346 #define round4(i) ((i+3)&~3) | |
347 | |
348 /* | |
349 | |
350 r0 return value etc. | |
351 r0,r1 return value. (dpcmp return value on $2) | |
352 00 special register | |
353 r0-r3 input register | |
354 r7-r9 saved register variable (input register for code segment) | |
355 jump register | |
356 sp stack pointer | |
357 fp frame pointer | |
358 | |
359 f0 return value etc. | |
360 r0-r3 input register | |
361 f20-f31 saved register variable | |
362 | |
363 code segment stack frame | |
364 | |
365 register_save is done by callee | |
366 | |
367 (prev $sp) | |
368 <---lvar_offset--> | |
369 # $fp <--------------------r1_offset---------> $sp | |
370 r+ +----------+-------------+--------+-------+-----------+---------------+ | |
371 cousin arg! callee arg !reg_save!reg_arg!local caller arg | |
372 (arg4..)lvar>0 (arg0.3) lvar<0 lvar>0x1000 000 | |
373 <--------------my_func_args--><--disp-----><-max_func_arg-> | |
374 *SIZE_OF_INT *SIZE_OF_INT | |
375 prev $sp=$fp $fp $sp | |
376 | |
377 (prev $sp) | |
378 <------r1_offset----------------> $sp | |
379 (prev $fp) $fp | |
380 r+ +-----------+--------------------+----------+-----------------------+ | |
381 callee arg register save local caller arg | |
382 disp max_func_args*SIZE_OF_INT | |
383 lvar<0 lvar>0x1000 0000 | |
384 prev $sp=$fp $sp=$fp | |
385 */ | |
386 | |
387 #define arg_offset (16) | |
388 #define arg_offset1 (-64) | |
389 int disp_offset=0; // fore mc-codegen.c | |
390 #define disp_offset 0 | |
391 | |
392 #define code_disp_offset 0 | |
393 | |
394 #define CODE_LVAR(l) ((l)+code_disp_offset) | |
395 #define CODE_CALLER_ARG(l) ((l)+arg_offset1) | |
396 #define FUNC_LVAR(l) (l+disp_offset) | |
397 #define CALLER_ARG(l) ((l)+arg_offset1) | |
398 #define CALLEE_ARG(l) ((l)+arg_offset) | |
399 | |
400 static int | |
401 code_offset_set(NMTBL *fnptr) | |
402 { | |
403 int lvar_offsetv; | |
404 int r1_offsetv; | |
405 int code_f = is_code(fnptr); | |
406 | |
407 disp &= -SIZE_OF_INT; | |
408 | |
409 if (code_f) { | |
410 r1_offsetv = disp-max_func_args*SIZE_OF_INT+code_disp_offset; | |
411 printf("\t.set .LC%d, %d\n",r1_offset_label,r1_offsetv); | |
412 } else { | |
413 lvar_offsetv = | |
414 -12 - max_reg_var*SIZE_OF_INT-max_reg_var*SIZE_OF_DOUBLE; | |
415 printf("\t.set .LC%d, %d\n",lvar_offset_label,lvar_offsetv); | |
416 } | |
417 if (max_func_arg_label) { | |
418 printf("\t.set .LC%d, %d\n",max_func_arg_label,max_func_args*SIZE_OF_INT); | |
419 max_func_arg_label = 0; | |
420 } | |
421 | |
422 | |
423 // printf(" @ args = %d, pretend = %d, frame = %d\n", | |
424 // max_func_args,0,round16(-disp)); | |
425 // printf(" @ frame_needed = 1, current_function_anonymous_args = 0\n"); | |
426 | |
427 | |
428 #if 0 | |
429 printf("## vars= %d, regs= %d/%d, args= %d, extra= %d\n", | |
430 round16(-disp), | |
431 max_reg_var+2, | |
432 max_reg_var, | |
433 round16(max_func_args*SIZE_OF_INT), | |
434 0 | |
435 ); | |
436 printf("## callee arg top=\t%d\n",CALLEE_ARG(0)); | |
437 printf("## reg_save_top=\t\t%d\n",r1_offsetv); | |
438 printf("## reg_save_end=\t\t%d\n", | |
439 -max_reg_var*SIZE_OF_INT-max_reg_var*SIZE_OF_FLOAT-2*SIZE_OF_INT+ | |
440 r1_offsetv); | |
441 printf("## lvar_offset=\t\t%d %d\n",lvar_offsetv,lvar_offsetv%16); | |
442 printf("## min local var=\t%d\n",FUNC_LVAR(0)+lvar_offsetv); | |
443 printf("## max local var=\t%d\n",FUNC_LVAR(disp)+lvar_offsetv); | |
444 printf("## min caller arg var=\t%d\n", | |
445 CALLER_ARG(round16(max_func_args*SIZE_OF_INT))); | |
446 printf("## max caller arg var=\t%d\n",CALLER_ARG(0)); | |
447 printf("##\n"); | |
448 #endif | |
449 | |
450 return 0; | |
451 } | |
452 | |
453 #define LARGE_OFFSET(l) (l<-511||l>511) | |
454 | |
455 static void lvar_address(int l,int creg); | |
456 | |
457 static int large_lvar; | |
458 static void | |
459 lvar_intro(int l) | |
460 { | |
461 int large; | |
462 if (is_code(fnptr)) { | |
463 if (l>=ARG_LVAR_OFFSET) { | |
464 large = LARGE_OFFSET(CODE_CALLER_ARG(l-ARG_LVAR_OFFSET)); | |
465 } else | |
466 large = LARGE_OFFSET(CODE_LVAR(l)); | |
467 } else if (l<0) { /* local variable */ | |
468 large = LARGE_OFFSET(FUNC_LVAR(l)); | |
469 } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ | |
470 large = LARGE_OFFSET(CALLER_ARG(l-ARG_LVAR_OFFSET)); | |
471 } else { /* callee's arguments */ | |
472 large = LARGE_OFFSET(CALLEE_ARG(l)); | |
473 } | |
474 if (large) { | |
475 large_lvar = get_register(); | |
476 lvar_address(l,large_lvar); | |
477 } else { | |
478 large_lvar = 0; | |
479 } | |
480 } | |
481 | |
482 static void | |
483 lvar(int l,char *cext) | |
484 { | |
485 if (large_lvar) { | |
486 printf("[%s, 0]%s\n",register_name(large_lvar),cext); | |
487 free_register(large_lvar); | |
488 return; | |
489 } | |
490 if (is_code(fnptr)) { | |
491 if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ | |
492 printf("[sp, %d]%s\n",CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),cext); | |
493 } else | |
494 printf("[fp, %d]%s\n",CODE_LVAR(l),cext); | |
495 } else if (l<0) { /* local variable */ | |
496 //printf("[fp, #%d+.L%d]%s\n",FUNC_LVAR(l),lvar_offset_label,cext); | |
497 printf("%d($sp)\n",FUNC_LVAR(l)); | |
498 } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ | |
499 printf("[sp, %d]%s\n",CALLER_ARG(l-ARG_LVAR_OFFSET),cext); | |
500 } else { /* callee's arguments */ | |
501 printf("[fp, %d]%s\n",CALLEE_ARG(l),cext); | |
502 } | |
503 } | |
504 | |
505 static void | |
506 lvar_address(int l,int creg) | |
507 { | |
508 //int label,disp; | |
509 int disp; | |
510 int tmp = -1; | |
511 char *trn; | |
512 if (is_code(fnptr)) { | |
513 if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ | |
514 code_add(creg,CODE_CALLER_ARG(l-ARG_LVAR_OFFSET),REG_sp); | |
515 } else | |
516 code_add(creg,CODE_LVAR(l),REG_fp); | |
517 } else if (l<0) { /* local variable */ | |
518 // printf("\tsf\t%s, fp, %d\n",register_name(creg), FUNC_LVAR(l)); | |
519 trn = register_name(tmp = get_register()); | |
520 //disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(l)),&label); | |
521 printf("\tlqd\t%s, %d($sp)\n",trn,(disp*4)); | |
522 printf("\tadd\t%s, fp, %s\n",register_name(creg),trn); | |
523 } else if (l>=ARG_LVAR_OFFSET) { /* caller's arguments */ | |
524 code_add(creg,CALLER_ARG(l-ARG_LVAR_OFFSET),REG_sp); | |
525 } else { /* callee's arguments */ | |
526 code_add(creg,CALLEE_ARG(l),REG_fp); | |
527 } | |
528 if (tmp!=-1) free_register(tmp); | |
529 } | |
530 | |
531 | |
532 void | |
533 code_lvar(int e2,int reg) { | |
534 use_int(reg); | |
535 lvar_address(e2,reg); | |
536 } | |
537 | |
538 | |
539 void | |
540 code_init(void) | |
541 { | |
542 /* called only once */ | |
543 | |
544 size_of_int = SIZE_OF_INT; | |
545 size_of_short = SIZE_OF_SHORT; | |
546 size_of_float = SIZE_OF_FLOAT; | |
547 size_of_double = SIZE_OF_DOUBLE; | |
548 size_of_longlong = SIZE_OF_LONGLONG; | |
549 endian = ENDIAN; | |
550 init_src = init_src0; | |
551 | |
552 } | |
553 | |
554 extern void | |
555 emit_reinit() | |
556 { | |
557 /* called for each file */ | |
558 init_ptr_cache(); | |
559 output_mode = -1; | |
560 } | |
561 | |
562 | |
563 | |
564 void | |
565 gexpr_code_init(void){ | |
566 } | |
567 | |
568 void | |
569 code_gexpr(int e){ | |
570 if (is_int_reg(creg) && creg!=ireg) error(-1); | |
571 // register_usage("code_gexpr"); | |
572 } | |
573 | |
574 | |
575 void | |
576 code_arg_register(NMTBL *fnptr) | |
577 { | |
578 int args = fnptr->dsp; | |
579 NMTBL *n; | |
580 int reg_var = 0; | |
581 int freg_var = 0; | |
582 int type; | |
583 int reg; | |
584 int i; | |
585 int is_code0 = is_code(fnptr); | |
586 int dots; | |
587 | |
588 function_type(fnptr->ty,&dots); | |
589 while (args) { | |
590 /* process in reverse order */ | |
591 n = (NMTBL*)caddr(args); | |
592 type = n->ty; | |
593 if (scalar(type)) { | |
594 if ((reg = get_input_register_var(reg_var,n,is_code0))) { | |
595 n->sc = REGISTER; | |
596 n->dsp = cadr(reg); | |
597 regs[n->dsp]= INPUT_REG; | |
598 reg_var++; | |
599 cadddr(args)=SIZE_OF_INT; | |
600 } | |
601 } else if (type==FLOAT) { | |
602 if (is_function(fnptr)) { | |
603 if ((reg = get_input_dregister_var(reg_var,n,is_code0,0))) { | |
604 n->sc = REGISTER; | |
605 n->dsp = cadr(reg); | |
606 regs[n->dsp]= INPUT_REG; | |
607 reg_var++; | |
608 cadddr(args)=size(type); | |
609 } | |
610 } else { | |
611 if ((reg = get_input_dregister_var(freg_var,n,is_code0,0))) { | |
612 n->sc = FREGISTER; | |
613 n->dsp = cadr(reg); | |
614 regs[n->dsp]= INPUT_REG; | |
615 freg_var++; | |
616 cadddr(args)=size(type); | |
617 } | |
618 } | |
619 } else if (type==DOUBLE) { | |
620 if ((reg = get_input_dregister_var(reg_var,n,is_code0,1))) { | |
621 n->sc = LREGISTER; | |
622 n->dsp = cadr(reg); | |
623 regs[i=n->dsp]= INPUT_DREG; | |
624 regs[i]= INPUT_REG; | |
625 //regs[i]= INPUT_REG; | |
626 reg_var+=2; | |
627 cadddr(args)=size(type); | |
628 } | |
629 } else if (type==LONGLONG||type==ULONGLONG) { | |
630 if ((reg = get_input_lregister_var(reg_var,n,is_code0))) { | |
631 n->sc = LREGISTER; | |
632 n->dsp = cadr(reg); | |
633 regs[i=n->dsp]= INPUT_REG; | |
634 regs[i]= INPUT_REG; | |
635 //regs[(i)]= INPUT_REG; | |
636 reg_var+=2; | |
637 cadddr(args)=size(type); | |
638 } | |
639 } | |
640 args = cadr(args); | |
641 } | |
642 if (is_function(fnptr)) | |
643 code_save_input_registers(dots); | |
644 } | |
645 | |
646 | |
647 int | |
648 get_register(void) | |
649 { /* 使われていないレジスタを調べる */ | |
650 int i,j,reg; | |
651 for(i=MAX_TMP_REG;i>=MIN_TMP_REG;i--) { | |
652 if (regs[i]) continue; /* 使われている */ | |
653 regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ | |
654 return i; /* その場所を表す番号を返す */ | |
655 } | |
656 for(i=0;i<REG_VAR_MAX-REG_VAR_MIN;i++) { | |
657 reg =REG_VAR_BASE+i; | |
658 if (! regs[reg]) { /* 使われていないなら */ | |
659 regs[reg]=USING_REG; /* そのレジスタを使うことを宣言し */ | |
660 if (i+1>max_reg_var) max_reg_var=i+1; | |
661 return reg; /* その場所を表す番号を返す */ | |
662 } | |
663 } | |
664 /* search register stack */ | |
665 for(i=0;i<reg_sp;i++) { | |
666 if ((reg=reg_stack[i])>0) { | |
667 code_assign_lvar( | |
668 (j=new_lvar(SIZE_OF_INT)*4),reg,0); | |
669 reg_stack[i]= j-REG_LVAR_OFFSET; | |
670 return reg; | |
671 } | |
672 } | |
673 #if LONGLONG_CODE||FLOAT_CODE | |
674 /* search register stack */ | |
675 for(i=0;i<reg_sp;i++) { | |
676 if ((reg=reg_stack[i])>0) { | |
677 code_lassign_lvar( | |
678 (j=new_lvar(SIZE_OF_LONGLONG)),reg); | |
679 reg_stack[i]= j-REG_LVAR_OFFSET; | |
680 free_register(reg); | |
681 return get_register(); | |
682 } | |
683 } | |
684 #endif | |
685 /* PTR_CACHE をつぶす */ | |
686 for(i=MAX_TMP_REG;i>=MIN_TMP_REG;i--) { | |
687 if (regs[i]==PTRC_REG) { | |
688 clear_ptr_cache_reg(i); | |
689 } else | |
690 continue; | |
691 regs[i]=USING_REG; /* そのレジスタを使うことを宣言し */ | |
692 return i; /* その場所を表す番号を返す */ | |
693 } | |
694 for(i=0;i<REG_VAR_MAX-REG_VAR_MIN;i++) { | |
695 reg =REG_VAR_BASE+i; | |
696 /* PTR_CACHE をつぶす */ | |
697 if (regs[reg]==PTRC_REG) { | |
698 clear_ptr_cache_reg(reg); | |
699 regs[reg]=0; | |
700 return reg; /* その場所を表す番号を返す */ | |
701 } | |
702 } | |
703 /* あいている場所がないなら、エラー(いったい誰が使ってるの?) */ | |
704 error(RGERR); return creg; | |
705 } | |
706 | |
707 #if 0 | |
708 int | |
709 get_register(void) | |
710 { | |
711 int i = get_register0(); | |
712 printf("## get_register %d\n",i); | |
713 //printf("hoge:%d\n",i); | |
714 return i; | |
715 } | |
716 #endif | |
717 | |
718 int | |
719 pop_register(void) | |
720 { /* レジスタから値を取り出す */ | |
721 return reg_stack[--reg_sp]; | |
722 } | |
723 | |
724 #if FLOAT_CODE | |
725 int | |
726 get_dregister(int d) | |
727 { /* 使われていないレジスタを調べる */ | |
728 return get_register(); | |
729 } | |
730 | |
731 #if 0 | |
732 int | |
733 get_dregister(int d) | |
734 { | |
735 int i = get_dregister0(d); | |
736 printf("## get_dregister %d\n",i); | |
737 return i; | |
738 } | |
739 #endif | |
740 | |
741 int | |
742 pop_fregister(void) | |
743 { /* レジスタから値を取り出す */ | |
744 return reg_stack[--reg_sp]; | |
745 } | |
746 #endif | |
747 | |
748 // static int lreg_count; | |
749 int | |
750 get_lregister0() | |
751 { | |
752 return get_register(); | |
753 } | |
754 | |
755 int | |
756 get_lregister() | |
757 { | |
758 return get_register(); | |
759 } | |
760 | |
761 int | |
762 get_lregister_var(NMTBL *n) | |
763 { | |
764 return get_register_var(n); | |
765 } | |
766 | |
767 void | |
768 emit_pop_free(int xreg) | |
769 { | |
770 if (xreg>=0 && xreg!=creg) | |
771 free_register(xreg); | |
772 } | |
773 | |
774 void | |
775 | |
776 free_register(int i) { /* いらなくなったレジスタを解放 */ | |
777 // printf("## free_register %d\n",i); | |
778 regs[i]=0; | |
779 // if (is_longlong_reg(i)) { | |
780 // printf("## free lregister %d (%d)\n",i,lreg_count++); | |
781 // regs[(i)]=0; | |
782 // regs[(i)]=0; | |
783 //(i)=0; | |
784 //(i)=0; | |
785 // } | |
786 } | |
787 | |
788 extern void | |
789 use_ptr_cache(int r) | |
790 { | |
791 regs[r]=PTRC_REG; | |
792 } | |
793 | |
794 int | |
795 get_input_dregister_var(int i,NMTBL *n,int is_code,int d) | |
796 { | |
797 int j; | |
798 if (is_code) { | |
799 if(i>MAX_CODE_INPUT_DREGISTER_VAR) return 0; | |
800 i = FREG_VAR_BASE+i+FREG_OFFSET; | |
801 use_input_reg(i,1); | |
802 return list3(FREGISTER,i,(int)n); | |
803 } | |
804 if (d) { | |
805 j = get_input_lregister_var(i,n,is_code); | |
806 return j; | |
807 } else { | |
808 if (i==0) return list3(REGISTER,1,(int)n); | |
809 else if (i==1) return list3(REGISTER,2,(int)n); | |
810 else if (i==2) return list3(REGISTER,3,(int)n); | |
811 else if (i==3) return list3(REGISTER,4,(int)n); | |
812 else return 0; | |
813 } | |
814 } | |
815 | |
816 int | |
817 get_input_lregister_var(int i,NMTBL *n,int is_code) | |
818 { | |
819 return get_input_register_var(i,n,is_code); | |
820 } | |
821 | |
822 int | |
823 get_input_register_var(int i,NMTBL *n,int is_code) | |
824 { | |
825 if (is_code) { | |
826 if(!(i<REG_VAR_MAX-REG_VAR_MIN)) return 0; | |
827 i = REG_VAR_BASE+i; | |
828 use_input_reg(i,1); | |
829 } else { | |
830 if (i<0||i>=MAX_INPUT_REGISTER_VAR) return 0; | |
831 i = i+1; | |
832 } | |
833 return list3(REGISTER,i,(int)n); | |
834 } | |
835 | |
836 | |
837 int | |
838 free_register_count(int d) | |
839 { | |
840 int i,count,fcount; | |
841 fcount = count = 0; | |
842 for(i=0;i<MAX_REGISTER;i++) { | |
843 if (! regs[i]) count++; | |
844 } | |
845 for(i=0;i<MAX_REGISTER;i++) { | |
846 if (! regs[i+FREG_OFFSET]) fcount++; | |
847 } | |
848 printf("## free reg %d freg %d\n",count,fcount); | |
849 return d?fcount:count; | |
850 } | |
851 | |
852 #if 0 | |
853 static int | |
854 register_full(void) | |
855 { | |
856 int i; | |
857 for(i=0;i<MAX_REGISTER;i++) { | |
858 if (! regs[i]) { | |
859 return 0; | |
860 } | |
861 } | |
862 return 1; | |
863 } | |
864 #endif | |
865 | |
866 void | |
867 free_all_register(void) | |
868 { | |
869 int i; | |
870 // printf("## free_all register\n"); | |
871 #if LONGLONG_CODE||FLOAT_CODE | |
872 for(i=0;i<REAL_MAX_REGISTER;i++) { | |
873 regs[i+LREG_OFFSET]=0; | |
874 } | |
875 lreg = 0; | |
876 // set_lreg(LREG_LREGISTER,0); | |
877 #endif | |
878 for(i=0;i<MAX_REGISTER;i++) { regs[i]=0; } | |
879 #if FLOAT_CODE | |
880 for(i=0;i<MAX_REGISTER;i++) { regs[i+FREG_OFFSET]=0; } | |
881 freg = get_dregister(1); | |
882 set_freg(FREG_FREGISTER,0); | |
883 #endif | |
884 ireg = creg = get_register(); | |
885 set_ireg(CREG_REGISTER,0); | |
886 return; | |
887 } | |
888 | |
889 | |
890 extern int | |
891 code_register_overlap(int s,int t) | |
892 { | |
893 switch(car(s)) { | |
894 case REGISTER: | |
895 switch(car(t)) { | |
896 case FREGISTER: break; | |
897 case REGISTER: | |
898 return cadr(s)==cadr(t); | |
899 break; | |
900 case LREGISTER: case DREGISTER: | |
901 if(cadr(s)==(cadr(t))) return 1; | |
902 if(cadr(s)==(cadr(t))) return 1; | |
903 break; | |
904 } | |
905 break; | |
906 case FREGISTER: | |
907 switch(car(t)) { | |
908 case REGISTER: case LREGISTER: case DREGISTER: break; | |
909 case FREGISTER: | |
910 return cadr(s)==cadr(t); | |
911 break; | |
912 } | |
913 break; | |
914 case DREGISTER: | |
915 case LREGISTER: | |
916 switch(car(t)) { | |
917 case FREGISTER: break; | |
918 case REGISTER: | |
919 if(cadr(t)==(cadr(s))) return 1; | |
920 if(cadr(t)==(cadr(s))) return 1; | |
921 break; | |
922 case LREGISTER: case DREGISTER: | |
923 if((cadr(t))==(cadr(s))) return 1; | |
924 if((cadr(t))==(cadr(s))) return 1; | |
925 if((cadr(t))==(cadr(s))) return 1; | |
926 if((cadr(t))==(cadr(s))) return 1; | |
927 break; | |
928 } | |
929 break; | |
930 } | |
931 return 0; | |
932 } | |
933 | |
934 | |
935 void | |
936 register_usage(char *s) | |
937 { | |
938 #if 1 | |
939 int i,j; | |
940 #endif | |
941 #define USAGE_MAX 4 | |
942 if (!lsrc) return; | |
943 printf("## %d: %s:",lineno,s); | |
944 if (ireg) printf(" creg=%s",register_name(ireg)); | |
945 if (freg) printf(" freg=%s",register_name(freg)); | |
946 if (lreg) printf(" lreg=%s,%s",lregister_name_high(lreg), | |
947 lregister_name_low(lreg)); | |
948 #if 1 | |
949 for(j=0,i=1;i<MAX_REGISTER;i++) if (regs[i]) j++; | |
950 if (j>USAGE_MAX) { | |
951 // printf("\n# regs:01234567890123456789012"); | |
952 printf("\n# regs:"); | |
953 for(i=1;i<MAX_REGISTER;i++) { printf("%d",regs[i]); } | |
954 } | |
955 if (reg_sp>0) { | |
956 printf(" stack "); | |
957 for(i=reg_sp;i>0;i--) { | |
958 if(reg_stack[i-1]>=0) { | |
959 printf(" %s",register_name(reg_stack[i-1])); | |
960 } else | |
961 printf(",%d",reg_stack[i-1]); | |
962 } | |
963 } | |
964 for(j=0,i=0;i<MAX_REGISTER;i++) if (regs[i+FREG_OFFSET]) j++; | |
965 if (j>USAGE_MAX) { | |
966 printf("\n# freg:"); | |
967 for(i=0;i<MAX_REGISTER;i++) { printf("%d",regs[i+FREG_OFFSET]); } | |
968 } | |
969 if (reg_sp>0) { | |
970 printf(" fstack "); | |
971 for(i=reg_sp;i>0;i--) { | |
972 if(reg_stack[i-1]>=0) { | |
973 printf(" %s",register_name(reg_stack[i-1])); | |
974 } else | |
975 printf(",%d",reg_stack[i-1]); | |
976 } | |
977 } | |
978 | |
979 for(j=0,i=0;i<REAL_MAX_REGISTER;i++) if (regs[i+LREG_OFFSET]) j++; | |
980 if (j>USAGE_MAX) { | |
981 printf("\n# lreg:"); | |
982 for(i=0;i<REAL_MAX_REGISTER;i++) { printf("%d",regs[i+LREG_OFFSET]); } | |
983 } | |
984 if (reg_sp>0) { | |
985 printf(" lstack "); | |
986 for(i=reg_sp;i>0;i--) { | |
987 if(reg_stack[i-1]>=0) { | |
988 printf(" %s",lregister_name_high(reg_stack[i-1])); | |
989 printf(",%s",lregister_name_low(reg_stack[i-1])); | |
990 } else | |
991 printf(",%d",reg_stack[i-1]); | |
992 } | |
993 } | |
994 #endif | |
995 printf("\n"); | |
996 } | |
997 | |
998 | |
999 void | |
1000 gexpr_init(void) | |
1001 { | |
1002 while(reg_sp > 0) { | |
1003 error(-1); | |
1004 free_register(reg_stack[--reg_sp]); | |
1005 } | |
1006 while(reg_sp > 0) { | |
1007 error(-1); | |
1008 free_register(reg_stack[--reg_sp]); | |
1009 } | |
1010 while(reg_sp > 0) { | |
1011 error(-1); | |
1012 free_register(reg_stack[--reg_sp]); | |
1013 } | |
1014 use_int0(); | |
1015 text_mode(2); | |
1016 gexpr_code_init(); | |
1017 register_usage(""); | |
1018 } | |
1019 | |
1020 | |
1021 void | |
1022 | |
1023 emit_init(void) | |
1024 { | |
1025 /* called before each declaration */ | |
1026 | |
1027 free_all_register(); | |
1028 max_reg_var=0; max_reg_var=0; | |
1029 reg_sp = 0; | |
1030 reg_sp = 0; | |
1031 } | |
1032 | |
1033 #define reg_var_num(i) (REG_VAR_BASE+i) | |
1034 | |
1035 int | |
1036 get_register_var(NMTBL *n) | |
1037 { | |
1038 int i,j; | |
1039 int max = n?REG_VAR_USER_MAX-REG_VAR_BASE:REG_VAR_MAX-REG_VAR_BASE; | |
1040 for(i=0;i<max;i++) { | |
1041 j = reg_var_num(i); | |
1042 if (! regs[j]) { /* ??͡??????ˡ????ϡ????ϡ?? */ | |
1043 /* ????ۡ???????????͡??????͡?????????? */ | |
1044 regs[j]=USING_REG; | |
1045 if (i+1>=max_reg_var) max_reg_var=i+1; | |
1046 /* ????ۥ???????Υ?????襱?????衢? */ | |
1047 return list3(REGISTER,j,(int)n); | |
1048 } | |
1049 } | |
1050 return list3(LVAR,new_lvar(SIZE_OF_INT),0); | |
1051 } | |
1052 | |
1053 #define freg_var_num(i) (FREG_VAR_BASE+i+FREG_OFFSET) | |
1054 | |
1055 int | |
1056 get_dregister_var(NMTBL *n,int d) | |
1057 { | |
1058 int i,j; | |
1059 for(i=0;i<FREG_VAR_MAX-FREG_VAR_BASE;i++) { | |
1060 j = freg_var_num(i); | |
1061 if (! regs[j]) { /* 使われていないなら */ | |
1062 regs[j]=USING_REG; /* そのレジスタを使うことを宣言し */ | |
1063 if (i+1>max_reg_var) max_reg_var=i+1; | |
1064 /* その場所を表す番号を返す */ | |
1065 return list3(FREGISTER,j,(int)n); | |
1066 } | |
1067 } | |
1068 } | |
1069 | |
1070 int | |
1071 emit_push() | |
1072 { | |
1073 int new_reg,old=creg; | |
1074 if (!is_int_reg(creg)) error(-1); | |
1075 if (reg_sp>MAX_MAX) error(-1); | |
1076 new_reg = get_register(); /* 絶対にとれる */ | |
1077 if (new_reg==creg) error(-1); /* who freed creg? */ | |
1078 reg_stack[reg_sp++] = creg; /* push するかわりにレジスタを使う */ | |
1079 ireg = creg = new_reg; | |
1080 if (!regs[creg]) regs[creg]=USING_REG; | |
1081 return old; | |
1082 } | |
1083 | |
1084 int | |
1085 emit_pop(int type) | |
1086 { | |
1087 int xreg,reg; | |
1088 xreg=pop_register(); | |
1089 if (xreg<= -REG_LVAR_OFFSET) { | |
1090 reg = get_register(); | |
1091 code_rlvar(REG_LVAR_OFFSET+xreg,reg); | |
1092 free_lvar(REG_LVAR_OFFSET+xreg); | |
1093 xreg = reg; | |
1094 } | |
1095 return xreg; | |
1096 } | |
1097 | |
1098 static int const_list; | |
1099 static int const_list_label; | |
1100 static int prev_const_list; | |
1101 static int prev_const_list_label; | |
1102 | |
1103 /* | |
1104 constant table | |
1105 glist3( tag, next, value ) | |
1106 LVAR glist2(label,offset) | |
1107 GVAR nptr | |
1108 CONST value | |
1109 LABEL value | |
1110 nth element has offset n * SIZE_OF_INT | |
1111 */ | |
1112 | |
1113 #define CONST_TBL_COUNT 100 | |
1114 /* | |
1115 static int | |
1116 search_const(int tag,int value,int *label) | |
1117 { | |
1118 int p,i,j,list,prev; | |
1119 | |
1120 for(j=0;j<2;j++) { | |
1121 i = 0; | |
1122 if(j==1) { | |
1123 if (!const_list_label) const_list_label = fwdlabel(); | |
1124 *label = const_list_label; | |
1125 if (const_list==0) { | |
1126 const_list = glist3(tag,0,value); | |
1127 return 0; | |
1128 } else { | |
1129 prev = list = const_list; | |
1130 } | |
1131 } else { | |
1132 prev = list = prev_const_list; *label = prev_const_list_label; | |
1133 } | |
1134 for(p = list; p ;prev=p,p=cadr(p),i+=SIZE_OF_INT) { | |
1135 if (car(p)!=tag) continue; | |
1136 switch(tag) { | |
1137 case GVAR: case CONST: case LABEL: | |
1138 if (caddr(p)!=value) continue; | |
1139 return i; | |
1140 case LVAR: | |
1141 if (car(caddr(p))!=car(value)) continue; | |
1142 if (cadr(caddr(p))!=cadr(value)) continue; | |
1143 return i; | |
1144 } | |
1145 } | |
1146 } | |
1147 cadr(prev) = glist3(tag,0,value); | |
1148 if (i>CONST_TBL_COUNT) { | |
1149 const_list_table(); | |
1150 } | |
1151 return i; | |
1152 } | |
1153 */ | |
1154 #if FLOAT_CODE | |
1155 static int | |
1156 search_double_const(int tag,int value1,int value2,int *label) | |
1157 { | |
1158 int p,i,j,list,prev; | |
1159 | |
1160 for(j=0;j<2;j++) { | |
1161 i = 0; | |
1162 if(j==1) { | |
1163 if (!const_list_label) const_list_label = fwdlabel(); | |
1164 *label = const_list_label; | |
1165 if (const_list==0) { | |
1166 const_list = glist3(tag,glist3(tag,0,value2),value1); | |
1167 return 0; | |
1168 } else { | |
1169 prev = list = const_list; | |
1170 } | |
1171 } else { | |
1172 prev =list = prev_const_list; *label = prev_const_list_label; | |
1173 } | |
1174 for(p = list; p ;prev=p,p=cadr(p),i+=SIZE_OF_INT) { | |
1175 if (car(p)!=tag) continue; | |
1176 switch(tag) { | |
1177 case DCONST: case LCONST: | |
1178 if (caddr(p)!=value1) continue; | |
1179 p = cadr(p); | |
1180 if (!p||car(p)!=tag) error(-1); | |
1181 if (caddr(p)!=value2) continue; | |
1182 return i; | |
1183 } | |
1184 prev = p; | |
1185 } | |
1186 } | |
1187 cadr(prev) = glist3(tag,glist3(tag,0,value2),value1); | |
1188 if (i>CONST_TBL_COUNT) { | |
1189 const_list_table(); | |
1190 } | |
1191 return i; | |
1192 } | |
1193 #endif | |
1194 | |
1195 static int inst_count; | |
1196 | |
1197 static void | |
1198 const_list_table() | |
1199 { | |
1200 int p,lb=0; | |
1201 inst_count = 0; | |
1202 | |
1203 if (const_list) { | |
1204 if (control) { | |
1205 lb = fwdlabel(); | |
1206 gen_jmp(lb); | |
1207 // printf("\t.align\t2\n"); | |
1208 } | |
1209 fwddef(const_list_label); | |
1210 control=0; | |
1211 for(p = const_list; p ; p = cadr(p)) { | |
1212 switch(car(p)) { | |
1213 case GVAR: printf("\t.word\t%s\n",((NMTBL *)caddr(p))->nm); break; | |
1214 case DCONST: case LCONST: | |
1215 case CONST: printf("\t.word\t%d\n",caddr(p)); break; | |
1216 case LABEL: printf("\t.word\t.LC%d\n",caddr(p)); break; | |
1217 case LVAR: printf("\t.word\t.LC%d+%d\n", | |
1218 car(caddr(p)),cadr(caddr(p))); break; | |
1219 default: error(-1); | |
1220 } | |
1221 } | |
1222 if (lb) { | |
1223 fwddef(lb); // control==1 now | |
1224 } | |
1225 prev_const_list_label=const_list_label; | |
1226 const_list_label = 0; | |
1227 } | |
1228 for(p = prev_const_list; p ; p = cadr(p)) { | |
1229 if (car(p)==LVAR) { | |
1230 free_glist2(caddr(p)); | |
1231 } | |
1232 } | |
1233 free_glist3_a(prev_const_list); | |
1234 prev_const_list=const_list; | |
1235 const_list = 0; | |
1236 } | |
1237 | |
1238 | |
1239 extern void | |
1240 code_ptr_cache_def(int r, NMTBL *nptr) | |
1241 { | |
1242 //int label,disp; | |
1243 int disp; | |
1244 char *rrn = register_name(r); | |
1245 //disp = search_const(GVAR,(int)nptr,&label); | |
1246 printf("\tlqd\t%s, %d($sp)\n",rrn,(disp*4)); | |
1247 } | |
1248 | |
1249 #define mask8(d,bit) (d & (255 << bit)) | |
1250 | |
1251 /* | |
1252 mode CONST or other (CMP is Ok only in stage 1 result) | |
1253 *p1 stage 1 const | |
1254 *p2 stage 2 const | |
1255 *p3 stage 3 const | |
1256 return 0 ... require 4 stage | |
1257 1 ... positive result | |
1258 -1 ... negative result | |
1259 | |
1260 */ | |
1261 static int | |
1262 make_const(int c,int *p1,int *p2,int *p3,int mode) | |
1263 { | |
1264 int sign,im,jm,km; | |
1265 int min_stage = 4; | |
1266 int msign=0,mim=0,mjm,mkm; | |
1267 int id,jd,kd; | |
1268 int i,j,k; | |
1269 int d; | |
1270 if (c == (d = mask8(c,0))) { | |
1271 min_stage=1; min_stage=1; msign = 1; | |
1272 mim = d;mjm = 0;mkm = 0; | |
1273 } else if (mode!=CONST) { | |
1274 if (-c == (d = mask8(-c,0))) { | |
1275 min_stage=1; min_stage=1; msign = -1; | |
1276 mim = d;mjm = 0;mkm = 0; | |
1277 } | |
1278 } else { | |
1279 if (~c== (d = mask8(~c,0))) { | |
1280 min_stage=1; min_stage=1; msign = -1; | |
1281 mim = d;mjm = 0;mkm = 0; | |
1282 } | |
1283 } | |
1284 for(sign=1;sign>=-1;sign-=2) { | |
1285 if (min_stage==1) break; | |
1286 for(i=24;i>=0;i-=2) { | |
1287 jm = km = 0; | |
1288 if (sign>0) { | |
1289 if (c == (d = mask8(c,i))) { | |
1290 min_stage=1; min_stage=1; msign = 1; | |
1291 mim = d;mjm = 0;mkm = 0; | |
1292 break; | |
1293 } | |
1294 id = c - d; | |
1295 } else if (mode!=CONST) { | |
1296 if (-c == (d = mask8(-c,i))) { | |
1297 min_stage=1; min_stage=1; msign = -1; | |
1298 mim = d;mjm = 0;mkm = 0; | |
1299 break; | |
1300 } | |
1301 id = -c - d; | |
1302 } else { | |
1303 if (~c== (d = mask8(~c,i))) { | |
1304 min_stage=1; min_stage=1; msign = -1; | |
1305 mim = d;mjm = 0;mkm = 0; | |
1306 break; | |
1307 } | |
1308 id = ~c - d; | |
1309 } | |
1310 if (d==0) continue; | |
1311 im = d; | |
1312 if (min_stage<=2) continue; | |
1313 for(j=i-8;j>=0;j-=2) { | |
1314 km = 0; | |
1315 if (!(jm=mask8(id,j))) continue; | |
1316 jd = id - jm; | |
1317 if (jd==0) { | |
1318 min_stage=2; msign = sign; | |
1319 mim = im;mjm = jm;mkm = km; | |
1320 break; | |
1321 } | |
1322 if (min_stage<=3) continue; | |
1323 for(k=j-8;k>=0;k-=2) { | |
1324 if (!(km=mask8(jd,k))) continue; | |
1325 kd = jd - km; | |
1326 if (kd==0) { | |
1327 min_stage=3; msign = sign; | |
1328 mim = im;mjm = jm;mkm = km; | |
1329 break; | |
1330 } | |
1331 } | |
1332 } | |
1333 } | |
1334 } | |
1335 if (min_stage<=3) { | |
1336 *p1 = mim; *p2= mjm; *p3 = mkm; | |
1337 return msign; | |
1338 } else return 0; | |
1339 } | |
1340 | |
1341 static int | |
1342 is_stage1_const(int c,int mode) | |
1343 { | |
1344 int sign,p1=0,p2=0,p3=0; | |
1345 sign = make_const(c,&p1,&p2,&p3,mode); | |
1346 return (c==0||(p1&&!p2&&!p3))?sign:0; | |
1347 } | |
1348 | |
1349 | |
1350 static void | |
1351 code_const0(int e2,int reg,char *opt) | |
1352 { | |
1353 char *crn,*add,*mov; | |
1354 int s,p1,p2,p3; | |
1355 //int label,disp; | |
1356 int disp; | |
1357 | |
1358 use_int(reg); | |
1359 crn = register_name(reg); | |
1360 if ((s=make_const(e2,&p1,&p2,&p3,CONST))) { | |
1361 add = s>0?"a":"sfi"; | |
1362 /************************************************************ | |
1363 * ここでp1の値によって、命令が異なる...... * | |
1364 * il命令は-32768~32767 * | |
1365 * ila命令は262143まで * | |
1366 * それ以上はilhuとiohlを混合して使う。 * | |
1367 * example:15728639 * | |
1368 * 15728639/16^4 = 239 ilhu $4,239 * | |
1369 * 15728639%16^4 = 65535 iohl $4,65535 * | |
1370 ***********************************************************/ | |
1371 mov = s>0?"il":"mvn"; | |
1372 printf("\t%s\t%s, %d\n",mov,crn,p1); | |
1373 if (p2) printf("\t%s\t%s, %s, %d\n",add,crn,crn,p2); | |
1374 if (p3) printf("\t%s\t%s, %s, %d\n",add,crn,crn,p3); | |
1375 } else { | |
1376 //disp = search_const(CONST,e2,&label); | |
1377 printf("\tlqd\t%s, %d($sp)\n",crn,(disp*4)); | |
1378 } | |
1379 } | |
1380 | |
1381 extern void | |
1382 code_const(int e2,int reg) { | |
1383 code_const0(e2,reg,""); | |
1384 } | |
1385 | |
1386 static void | |
1387 code_add(int reg,int offset,int r) | |
1388 { | |
1389 char *crn = register_name(reg); | |
1390 char *rrn = register_name(r); | |
1391 char *drn; | |
1392 int dreg; | |
1393 int s,p1,p2,p3; | |
1394 char *add; | |
1395 //int label,disp; | |
1396 int disp; | |
1397 if (offset==0) { | |
1398 if(r!=reg) | |
1399 printf("\tori\t%s, %s, 0\n",crn,rrn); | |
1400 } else if ((s=make_const(offset,&p1,&p2,&p3,0))) { | |
1401 add = s>0?"a":"sfi"; | |
1402 printf("\t%s\t%s, %s, %d\n",add,crn,rrn,p1); | |
1403 if (p2) printf("\t%s\t%s, %s, %d\n",add,crn,crn,p2); | |
1404 if (p3) printf("\t%s\t%s, %s, %d\n",add,crn,crn,p3); | |
1405 } else { | |
1406 //disp = search_const(CONST,offset,&label); | |
1407 drn = register_name(dreg = get_register()); | |
1408 printf("\tlqd\t%s, %d($sp)\n",drn,(disp*4)); | |
1409 printf("\ta\t%s, %s, %s\n",crn,drn,rrn); | |
1410 free_register(dreg); | |
1411 } | |
1412 } | |
1413 | |
1414 | |
1415 static void | |
1416 code_ld(char *ld,int reg,int offset,int r,char *cext) | |
1417 { | |
1418 char *crn = register_name(reg); | |
1419 char *rrn = register_name(r); | |
1420 if (-1024<offset&&offset<1024) { | |
1421 printf("\t%s\t%s, [%s, %d]%s\n",ld,crn,rrn,offset,cext); | |
1422 } else { | |
1423 code_add(reg,offset,r); | |
1424 printf("\t%s\t%s, [%s, 0]%s\n",ld,crn,crn,cext); | |
1425 } | |
1426 } | |
1427 | |
1428 static void | |
1429 code_ldf(char *ld,char *crn,int offset,int r,char *cext) | |
1430 { | |
1431 //char *rrn = register_name(r); | |
1432 char *orn; | |
1433 int reg; | |
1434 if (-1024<offset&&offset<1024) { | |
1435 printf("\t%s\t%s, %d(%s)\n",ld,crn,(offset*4),cext); | |
1436 } else { | |
1437 orn = register_name(reg=get_register()); | |
1438 code_add(reg,offset,r); | |
1439 //printf("\t%s\t%s, [%s, 0]%s\n",ld,crn,orn,cext); | |
1440 printf("hoge\n"); | |
1441 free_register(reg); | |
1442 } | |
1443 } | |
1444 | |
1445 | |
1446 #define cload(sz,sign) \ | |
1447 (sz==1?(sign?"lqx":"lqa"):sz==SIZE_OF_SHORT?(sign?"lqx":"lqa"):"lqd") | |
1448 | |
1449 | |
1450 #define cext(sign,sz,reg) | |
1451 | |
1452 static char * | |
1453 cext_at(int sz,int sign) | |
1454 { | |
1455 return ((sz==1&&!sign)?" @ zero_extendqisi2":""); | |
1456 } | |
1457 | |
1458 void | |
1459 code_label(int labelno) | |
1460 { | |
1461 clear_ptr_cache(); | |
1462 printf(".LC%d:\n",labelno); | |
1463 } | |
1464 | |
1465 void | |
1466 code_gvar(int e1,int reg) { | |
1467 use_int(reg); | |
1468 code_add(reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1))); | |
1469 return; | |
1470 } | |
1471 | |
1472 void | |
1473 code_rgvar(int e1,int reg) { | |
1474 use_int(reg); | |
1475 code_ld("lqd",reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1)),""); | |
1476 } | |
1477 | |
1478 void | |
1479 code_crgvar(int e1,int reg,int sign,int sz){ | |
1480 use_int(reg); | |
1481 code_ld(cload(sz,sign),reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1)), | |
1482 cext_at(sz,sign)); | |
1483 cext(sign,sz,reg); | |
1484 } | |
1485 | |
1486 | |
1487 void | |
1488 code_register(int e2,int reg) { | |
1489 use_int(reg); | |
1490 // reg = e2 | |
1491 if (reg!=e2) { | |
1492 printf("\tori\t%s, %s, 0\n",register_name(reg),register_name(e2)); | |
1493 } | |
1494 } | |
1495 | |
1496 | |
1497 void | |
1498 code_rlvar(int e2,int reg) { | |
1499 use_int(reg); | |
1500 lvar_intro(e2); | |
1501 printf("\tlqd\t%s, ",register_name(reg)); | |
1502 e2 *= 4; | |
1503 lvar(e2,""); | |
1504 } | |
1505 | |
1506 extern void | |
1507 code_i2c(int reg) | |
1508 { | |
1509 } | |
1510 | |
1511 extern void | |
1512 code_i2s(int reg) | |
1513 { | |
1514 } | |
1515 | |
1516 extern void | |
1517 code_u2uc(int reg) | |
1518 { | |
1519 use_int(reg); | |
1520 printf("and\t%s, %s, #255\n",register_name(reg),register_name(reg)); | |
1521 } | |
1522 | |
1523 extern void | |
1524 code_u2us(int reg) | |
1525 { | |
1526 use_int(reg); | |
1527 printf("bic\t%s, %s, #16711680\n",register_name(reg),register_name(reg)); | |
1528 printf("bic\t%s, %s, #-16777216\n",register_name(reg),register_name(reg)); | |
1529 } | |
1530 | |
1531 void | |
1532 code_crlvar(int e2,int reg,int sign,int sz) { | |
1533 use_int(reg); | |
1534 lvar_intro(e2); | |
1535 printf("\t%s\t%s, ",cload(sz,sign),register_name(reg)); | |
1536 lvar(e2,cext_at(sz,sign)); | |
1537 cext(sign,sz,reg); | |
1538 } | |
1539 | |
1540 void | |
1541 code_fname(NMTBL *n,int reg) { | |
1542 int r; | |
1543 use_int(reg); | |
1544 r = get_ptr_cache(n); | |
1545 if(r!=reg) { | |
1546 printf("\tori\t%s, %s, 0\n",register_name(reg),register_name(r)); | |
1547 } | |
1548 return; | |
1549 } | |
1550 | |
1551 void | |
1552 code_label_value(int label,int reg) { | |
1553 //int lb,disp; | |
1554 use_int(reg); | |
1555 //disp = search_const(LABEL,label,&lb); | |
1556 printf("\tila\t%s,.LC%d\n",register_name(reg),label); | |
1557 return; | |
1558 } | |
1559 | |
1560 void | |
1561 code_neg(int creg) { | |
1562 use_int(creg); | |
1563 printf("\trsb\t%s, %s, #0\n", register_name(creg), register_name(creg)); | |
1564 } | |
1565 | |
1566 | |
1567 void | |
1568 code_not(int creg) { | |
1569 use_int(creg); | |
1570 printf("\tmvn\t%s, %s\n", | |
1571 register_name(creg), register_name(creg)); | |
1572 } | |
1573 | |
1574 | |
1575 void | |
1576 code_lnot(int creg) { | |
1577 use_int(creg); | |
1578 | |
1579 printf("\tcmp\t%s, #0\n", register_name(creg)); | |
1580 printf("\tmovne\t%s, #0\n", register_name(creg)); | |
1581 printf("\tmoveq\t%s, #1\n", register_name(creg)); | |
1582 } | |
1583 | |
1584 void | |
1585 code_preinc(int e1,int e2,int dir,int sign,int sz,int reg) { | |
1586 char *xrn,*drn; | |
1587 int xreg; | |
1588 if (car(e2)==REGISTER) { | |
1589 use_int(reg); | |
1590 code_add(cadr(e2),dir,cadr(e2)); | |
1591 if (reg!=cadr(e2)) | |
1592 code_register(cadr(e2),reg); | |
1593 return; | |
1594 } | |
1595 g_expr(e2); | |
1596 if (!is_int_reg(creg)) error(-1); | |
1597 xrn = register_name(xreg = creg); | |
1598 if (reg==USE_CREG) { | |
1599 reg=get_register(); if (!reg) error(-1); | |
1600 drn = register_name(reg); | |
1601 set_ireg(reg,0); | |
1602 } else { | |
1603 drn = register_name(reg); | |
1604 } | |
1605 // ldrb r2, [ip, #-1]! @ zero_extendqisi2 | |
1606 // ??????offset???????????12bit! | |
1607 code_ld(cload(sz,sign),reg,0,xreg,cext_at(sz,sign)); | |
1608 code_add(reg,dir,reg); | |
1609 code_ldf(cstore(sz),drn,0,xreg,sz==SIZE_OF_SHORT?" @ movhi":""); | |
1610 } | |
1611 | |
1612 | |
1613 void | |
1614 code_postinc(int e1,int e2,int dir,int sign,int sz,int reg) { | |
1615 char *xrn,*crn,*nrn; | |
1616 int nreg,xreg; | |
1617 if (car(e2)==REGISTER) { | |
1618 use_int(reg); | |
1619 code_register(cadr(e2),reg); | |
1620 code_add(cadr(e2),dir,cadr(e2)); | |
1621 return; | |
1622 } | |
1623 g_expr(e2); | |
1624 if (!is_int_reg(creg)) error(-1); | |
1625 crn = register_name(xreg=creg); | |
1626 nreg=get_register(); if (!nreg) error(-1); | |
1627 nrn = register_name(nreg); | |
1628 if (reg==USE_CREG) { | |
1629 reg=get_register(); if (!reg) error(-1); | |
1630 xrn = register_name(reg); | |
1631 set_ireg(reg,0); | |
1632 } else { | |
1633 xrn = register_name(reg); | |
1634 } | |
1635 //_1: ldrb r4, [r0], #1 @ zero_extendqisi2 *buffer++ | |
1636 code_ld(cload(sz,sign),reg,0,xreg,cext_at(sz,sign)); | |
1637 code_add(nreg,dir,reg); | |
1638 code_ldf(cstore(sz),nrn,0,xreg,sz==SIZE_OF_SHORT?" @ movhi":""); | |
1639 | |
1640 free_register(nreg); | |
1641 } | |
1642 | |
1643 | |
1644 void | |
1645 code_return(int creg) { | |
1646 //int label,disp; | |
1647 int disp; | |
1648 char *crn; | |
1649 use_int(creg); | |
1650 crn = register_name(creg); | |
1651 | |
1652 //disp = search_const(LABEL,retcont,&label); | |
1653 printf("\tlqd\t%s, %d($sp)\n",crn,(disp*4)); | |
1654 } | |
1655 | |
1656 void | |
1657 code_environment(int creg) { | |
1658 /* save frame pointer */ | |
1659 if (is_code(fnptr)) { | |
1660 use_int(creg); | |
1661 printf("\tmov\t%s, fp\n",register_name(creg)); | |
1662 } else { | |
1663 //int disp,label; | |
1664 int disp; | |
1665 char *trn = register_name(REG_ip); | |
1666 use_int(creg); | |
1667 //disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(0)),&label); | |
1668 printf("\tlqa\t%s, %d\n",trn,disp); | |
1669 printf("\ta\t%s, fp, %s\n",register_name(creg),trn); | |
1670 } | |
1671 } | |
1672 | |
1673 static int rexpr_bool(int e1, int reg); | |
1674 #if LONGLONG_CODE | |
1675 static int lrexpr_bool(int e1, int reg); | |
1676 #endif | |
1677 | |
1678 void | |
1679 code_bool(int e1,int reg) { | |
1680 int e2,e3; | |
1681 char *xrn; | |
1682 if (rexpr_bool(e1, reg)) return; | |
1683 #if LONGLONG_CODE | |
1684 if (lrexpr_bool(e1, reg)) return; | |
1685 #endif | |
1686 b_expr(e1,1,e2=fwdlabel(),1); /* including > < ... */ | |
1687 if (use) { | |
1688 use_int(reg); | |
1689 xrn = register_name(reg); | |
1690 printf("\tmov\t%s, #0\n",xrn); | |
1691 gen_jmp(e3=fwdlabel()); | |
1692 fwddef(e2); | |
1693 printf("\tmov\t%s, #1\n",xrn); | |
1694 fwddef(e3); | |
1695 } else { | |
1696 fwddef(e2); | |
1697 } | |
1698 } | |
1699 | |
1700 | |
1701 void | |
1702 code_cmp_crgvar(int e1,int reg,int sz,int label,int cond) { | |
1703 use_int(reg); | |
1704 code_ld(cload(sz,0),reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1)), | |
1705 cext_at(sz,0)); | |
1706 cext(0,sz,r); | |
1707 printf("\tcmp\t%s, #0\n",register_name(reg)); | |
1708 jcond(label,cond); | |
1709 } | |
1710 | |
1711 | |
1712 void | |
1713 code_cmp_crlvar(int e2,int reg, int sz,int label,int cond) { | |
1714 char *crn; | |
1715 use_int(reg); | |
1716 crn = register_name(reg); | |
1717 lvar_intro(e2); | |
1718 printf("\t%s\t%s, ",cload(sz,0),crn); | |
1719 lvar(e2,cext_at(sz,0)); | |
1720 cext(0,sz,reg); | |
1721 code_cmp_register(reg,label,cond); | |
1722 } | |
1723 | |
1724 | |
1725 void | |
1726 code_cmp_rgvar(int e1,int reg,int label,int cond) { | |
1727 use_int(reg); | |
1728 code_ld("lqd",reg,cadr(e1),get_ptr_cache((NMTBL*)caddr(e1)),""); | |
1729 code_cmp_register(reg,label,cond); | |
1730 } | |
1731 | |
1732 | |
1733 void | |
1734 code_cmp_rlvar(int e2,int reg,int label,int cond) { | |
1735 char *crn; | |
1736 use_int(reg); | |
1737 crn = register_name(reg); | |
1738 lvar_intro(e2); | |
1739 printf("\tlqd\t%s, ",crn); | |
1740 e2 *= 4; | |
1741 lvar(e2,""); | |
1742 code_cmp_register(reg,label,cond); | |
1743 } | |
1744 | |
1745 | |
1746 void | |
1747 code_cmp_register(int e2,int label,int cond) { | |
1748 use_int(e2); | |
1749 printf("\tcmp\t%s, #0\n",register_name(e2)); | |
1750 jcond(label,cond); | |
1751 } | |
1752 | |
1753 | |
1754 void | |
1755 code_string(int e1,int creg) | |
1756 { | |
1757 char *s,*crn; | |
1758 //int lb,label; | |
1759 int lb; | |
1760 printf("creg:%d\n",creg); | |
1761 NMTBL *n = (NMTBL *)cadr(e1); | |
1762 if ((lb=attr_value(n,LABEL))) { | |
1763 // already defined | |
1764 return code_label_value(lb,creg) ; | |
1765 //return code_label_value(lb,35) ; | |
1766 } | |
1767 | |
1768 use_int(creg); | |
1769 crn = register_name(creg); | |
1770 | |
1771 s=n->nm; | |
1772 lb = emit_string_label(); | |
1773 ascii(s); | |
1774 text_mode(2); | |
1775 | |
1776 //disp = search_const(LABEL,lb,&label); | |
1777 printf("\tila\t%s, .LC%d\n",crn,lb); | |
1778 set_attr(n,LABEL,lb); | |
1779 } | |
1780 | |
1781 #define MAX_COPY_LEN 20 | |
1782 | |
1783 void | |
1784 emit_copy(int from,int to,int length,int offset,int value,int det) | |
1785 { | |
1786 char *frn; | |
1787 char *trn; | |
1788 char *drn; | |
1789 char *memmove = "memmove"; | |
1790 int dreg = REG_ip; | |
1791 | |
1792 drn = register_name(dreg); | |
1793 use_int(from); | |
1794 use_int(to); | |
1795 frn = register_name(from); | |
1796 trn = register_name(to); | |
1797 | |
1798 /* length <0 means upward direction copy */ | |
1799 switch (length) { | |
1800 case 0: break; | |
1801 case 1: case -1: | |
1802 printf("\tlqd\t%s, %d(%s)\n",drn,(offset*4),trn); | |
1803 printf("\tstqd\t%s,%d(%s)\n",drn,(offset*4),trn); | |
1804 break; | |
1805 case 2: case -2: | |
1806 printf("\tlqx\t%s, [%s,#%d]\n",drn,frn,offset); | |
1807 printf("\tstqx\t%s, [%s,#%d]\n",drn,trn,offset); | |
1808 break; | |
1809 case 4: case -4: | |
1810 printf("\tlqa\t%s, [%s,#%d]\n",drn,frn,offset); | |
1811 printf("\tstqa\t%s, [%s,#%d]\n",drn,trn,offset); | |
1812 break; | |
1813 default: | |
1814 if (length <0) { | |
1815 if (length > -MAX_COPY_LEN) { | |
1816 for(;length<=-4;length+=4,offset-=4) | |
1817 emit_copy(from,to,-4,offset-4,0,det); | |
1818 for(;length<=-2;length+=2,offset-=2) | |
1819 emit_copy(from,to,-2,offset-2,0,det); | |
1820 if(length<0) | |
1821 emit_copy(from,to,length,offset-1,0,det); | |
1822 break; | |
1823 } | |
1824 } else if (length <=MAX_COPY_LEN) { | |
1825 for(;length>=4;length-=4,offset+=4) | |
1826 emit_copy(from,to,4,offset,0,det); | |
1827 for(;length>=2;length-=2,offset+=2) | |
1828 emit_copy(from,to,2,offset,0,det); | |
1829 if(length>0) | |
1830 emit_copy(from,to,length,offset,0,det); | |
1831 break; | |
1832 } | |
1833 clear_ptr_cache(); | |
1834 code_save_stacks(); | |
1835 parallel_rassign(list3(1,list3(2,0,from),to)); | |
1836 code_const(length>0?length:-length,3); | |
1837 /* overlap must be allowed */ | |
1838 // offset have to be ignored */ | |
1839 printf("\thbra\t%s\n",memmove); | |
1840 extern_define(memmove,0,FUNCTION,1); | |
1841 set_ireg(RET_REGISTER,0); | |
1842 if (creg!=to) { | |
1843 free_register(to); to = creg; | |
1844 } | |
1845 break; | |
1846 } | |
1847 if (value) { | |
1848 /* creg must point top of the destination data */ | |
1849 /* this code is necessary for the value of assignment or function call */ | |
1850 /* otherwise we don't need this */ | |
1851 if(creg!=to) { | |
1852 free_register(creg); creg=to; ireg=to; | |
1853 } | |
1854 } | |
1855 // free_register(dreg); | |
1856 } | |
1857 | |
1858 int | |
1859 push_struct(int e4,int t,int arg) | |
1860 { | |
1861 int length,len0,count; | |
1862 int dreg = -1,sreg; char *drn,*crn,*srn; | |
1863 int arg_disp = cadr(arg); | |
1864 int on_register,arg_reg; | |
1865 g_expr(e4); | |
1866 if (!is_int_reg(creg)) error(-1); | |
1867 len0=length=size(t); | |
1868 if(length%SIZE_OF_INT) { | |
1869 length += SIZE_OF_INT - (length%SIZE_OF_INT); | |
1870 } | |
1871 crn = register_name(creg); | |
1872 on_register = 0; | |
1873 // arg_reg = 1-CALLER_ARG(arg_disp-ARG_LVAR_OFFSET)/SIZE_OF_INT; | |
1874 arg_reg = (arg_disp-ARG_LVAR_OFFSET)/SIZE_OF_INT + 1; | |
1875 while (length>0 && | |
1876 arg_disp>=ARG_LVAR_OFFSET && | |
1877 CALLER_ARG(arg_disp-ARG_LVAR_OFFSET)<0) { | |
1878 /* some part will be on registers */ | |
1879 on_register ++; | |
1880 length-=SIZE_OF_INT; arg_disp+= SIZE_OF_INT; | |
1881 } | |
1882 if (length>0) { | |
1883 dreg = get_register(); if (!dreg) error(-1); | |
1884 drn = register_name(dreg); | |
1885 if (length<MAX_COPY_LEN) { | |
1886 sreg = get_register(); if (!sreg) error(-1); | |
1887 srn = register_name(sreg); | |
1888 code_lvar(arg_disp,dreg); | |
1889 for(count=0;count<length;count+=SIZE_OF_INT) { | |
1890 printf("\tlqd\t%s, [%s, #%d]\n",srn,crn,count+on_register*SIZE_OF_INT); | |
1891 printf("\tstr\t%s, [%s, #%d]\n",srn,drn,count); | |
1892 } | |
1893 free_register(sreg); | |
1894 if (on_register) { | |
1895 if (creg<=MAX_INPUT_REGISTER_VAR) { | |
1896 code_register(creg,REG_ip); | |
1897 crn = register_name(REG_ip); | |
1898 } | |
1899 } | |
1900 } else { | |
1901 code_lvar(arg_disp,dreg); | |
1902 /* downward direction copy */ | |
1903 if (on_register) { | |
1904 sreg = new_lvar(SIZE_OF_INT); | |
1905 code_assign_lvar(sreg*4,creg,0); | |
1906 code_add(creg,on_register*SIZE_OF_INT,creg); | |
1907 emit_copy(creg,dreg,length,0,0,1); | |
1908 code_rlvar(sreg,REG_ip); | |
1909 crn = register_name(REG_ip); | |
1910 free_lvar(sreg); | |
1911 } else { | |
1912 emit_copy(creg,dreg,length,0,0,1); | |
1913 } | |
1914 } | |
1915 if (dreg!=-1) free_register(dreg); | |
1916 } | |
1917 for (count=0,arg_reg; on_register-->0; arg_reg++,count+=SIZE_OF_INT) { | |
1918 // len0 = (len0>2)?0:len0; | |
1919 printf("\t%s\t%s, [%s, #%d]\n", cload(0,0), | |
1920 register_name(arg_reg), crn,count); | |
1921 use_input_reg(arg_reg,1); | |
1922 } | |
1923 return length/SIZE_OF_INT; | |
1924 } | |
1925 | |
1926 static void | |
1927 set_ireg(int reg,int mode) | |
1928 { | |
1929 if (!is_int_reg(reg)) error(-1); | |
1930 if (reg!=creg) { | |
1931 clear_ptr_cache_reg(reg); | |
1932 if (ireg && reg!=ireg ) { | |
1933 free_register(ireg); | |
1934 if (mode) { | |
1935 printf("\tori\t%s, %s, 0\n",register_name(reg),register_name(ireg)); | |
1936 } | |
1937 } | |
1938 free_register(creg); | |
1939 if (creg==lreg) lreg=0; | |
1940 regs[reg]=USING_REG; | |
1941 } | |
1942 creg = ireg = reg; | |
1943 } | |
1944 | |
1945 static void | |
1946 set_freg(int reg,int mode) | |
1947 { | |
1948 if (!is_float_reg(reg)) error(-1); | |
1949 if (reg!=creg) { | |
1950 if (freg && reg!=freg) { | |
1951 free_register(freg); | |
1952 if (mode) { | |
1953 printf("\t%s\t%s, %s\n", | |
1954 "mvfs" | |
1955 register_name(reg),register_name(freg)); | |
1956 } | |
1957 } | |
1958 // if (creg!=ireg) free_register(creg); | |
1959 regs[reg]=USING_REG; | |
1960 } | |
1961 creg = freg = reg; | |
1962 } | |
1963 | |
1964 #if LONGLONG_CODE||FLOAT_CODE | |
1965 static void | |
1966 set_lreg0(int reg,int mode) | |
1967 { | |
1968 if (reg!=creg) { | |
1969 if (lreg && reg!=lreg) { | |
1970 if (mode) { | |
1971 lmove(reg,lreg); | |
1972 } | |
1973 free_register(lreg); | |
1974 } | |
1975 if (creg!=lreg) { | |
1976 free_register(creg); | |
1977 if (creg==ireg) ireg = 0; | |
1978 } | |
1979 regs[reg]=USING_REG; | |
1980 clear_ptr_cache_reg(reg); | |
1981 regs[reg]=USING_REG; | |
1982 clear_ptr_cache_reg(reg); | |
1983 regs[reg]=USING_REG; | |
1984 } | |
1985 creg = lreg = reg; | |
1986 } | |
1987 #endif | |
1988 | |
1989 #if LONGLONG_CODE | |
1990 static void | |
1991 set_lreg(int reg,int mode) | |
1992 { | |
1993 if (!is_longlong_reg(reg)) error(-1); | |
1994 set_lreg0(reg,mode); | |
1995 } | |
1996 #endif | |
1997 | |
1998 #if FLOAT_CODE | |
1999 static void | |
2000 set_dreg(int reg,int mode) | |
2001 { | |
2002 return set_ireg(reg,mode); | |
2003 } | |
2004 | |
2005 static void | |
2006 set_lreg_operand(int reg,int mode) | |
2007 { | |
2008 // save_stack,clear_ptr_cache is assumed | |
2009 if (!is_longlong_reg(reg)) { error(-1); return; } | |
2010 if (mode) { | |
2011 lmove(LREGISTER_OPERAND,reg); | |
2012 } | |
2013 } | |
2014 | |
2015 static void | |
2016 set_dreg_operand(int reg,int mode) | |
2017 { | |
2018 set_lreg_operand(reg,mode); | |
2019 } | |
2020 | |
2021 | |
2022 #endif | |
2023 | |
2024 void | |
2025 use_reg(int arg) | |
2026 { | |
2027 // printf("## use reg %d\n",arg); | |
2028 if (arg<0||arg> REGS_MAX) | |
2029 error(-1); | |
2030 clear_ptr_cache_reg(arg); | |
2031 regs[arg]=USING_REG; | |
2032 if (is_longlong_reg(arg)) { | |
2033 clear_ptr_cache_reg(arg); | |
2034 regs[arg]=USING_REG; | |
2035 clear_ptr_cache_reg(arg); | |
2036 regs[arg]=USING_REG; | |
2037 } else if (is_double_reg(arg)) { | |
2038 clear_ptr_cache_reg(arg); | |
2039 regs[arg]=USING_REG; | |
2040 clear_ptr_cache_reg(arg); | |
2041 regs[arg]=USING_REG; | |
2042 } | |
2043 } | |
2044 | |
2045 void | |
2046 code_save_input_registers(int dots) | |
2047 { | |
2048 int args; | |
2049 NMTBL *n; | |
2050 int reg; | |
2051 int tag; | |
2052 /* fnptr->dsp=list4(type,fnptr->dsp,(int)n,0); */ | |
2053 int offset = 0; | |
2054 int reg_var = 0; | |
2055 int len; | |
2056 arg_on_register = 0; | |
2057 | |
2058 for(args = fnptr->dsp;args;args = cadr(args)) { | |
2059 n = (NMTBL *)caddr(args); | |
2060 tag = n->sc; | |
2061 reg = n->dsp; | |
2062 if (!n||n==&null_nptr) error(REG_ERR); | |
2063 if (reg_var<MAX_INPUT_REGISTER_VAR) { | |
2064 n->dsp = offset; | |
2065 n->sc = LVAR; | |
2066 len = size(n->ty); len = round4(len); | |
2067 for(;len>0 && reg_var<MAX_INPUT_REGISTER_VAR;len-=SIZE_OF_INT) { | |
2068 reg_var++; | |
2069 g_expr_u(assign_expr0(list3(LVAR,offset,0), | |
2070 list3(REGISTER,reg_var,0),INT,INT)); | |
2071 arg_on_register += SIZE_OF_INT; | |
2072 free_register(reg); | |
2073 offset += SIZE_OF_INT; | |
2074 } | |
2075 } | |
2076 } | |
2077 if (dots) { | |
2078 while ((reg = get_input_register_var(reg_var,0,0))) { | |
2079 g_expr_u(assign_expr0( | |
2080 list3(LVAR,offset,0),reg,INT,INT)); | |
2081 offset+=SIZE_OF_INT; | |
2082 reg_var++; | |
2083 arg_on_register += SIZE_OF_INT; | |
2084 } | |
2085 } | |
2086 my_func_args = offset; | |
2087 } | |
2088 | |
2089 int | |
2090 not_simple_p(int e3) | |
2091 { | |
2092 switch(e3) { | |
2093 case FUNCTION: case CONV: case STASS: case ALLOCA: | |
2094 case DIV : case UDIV : case MOD : case UMOD : | |
2095 case LDIV: case LUDIV: case LMOD: case LUMOD: | |
2096 case LMUL: case LUMUL: | |
2097 case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: | |
2098 case DDIV: case DADD: case DSUB: case DMUL: case DMINUS: | |
2099 case DPOSTINC : case DPREINC : case DASSOP : | |
2100 case DOP+LT : case DOP+LE : case DOP+GT : case DOP+GE : | |
2101 case DOP+EQ : case DOP+NEQ: | |
2102 case RBIT_FIELD: case BASS: case BASSOP: case LCALL: | |
2103 case INLINE: | |
2104 return 1; | |
2105 } | |
2106 return 0; | |
2107 } | |
2108 | |
2109 int | |
2110 simple_arg(int e3) | |
2111 { | |
2112 return !contains_p(e3,not_simple_p); | |
2113 } | |
2114 | |
2115 static int | |
2116 caller_arg_offset_v(int arg) | |
2117 { | |
2118 return ARG_LVAR_OFFSET+arg*SIZE_OF_INT; | |
2119 } | |
2120 | |
2121 /* | |
2122 Mark argument register is used. This is too complex. | |
2123 There must be an easy way. | |
2124 */ | |
2125 | |
2126 static void | |
2127 use_input_reg(int reg,int mode) | |
2128 { | |
2129 if (is_int_reg(reg)) { | |
2130 if (ireg&® == ireg) { | |
2131 if (creg==ireg) creg = 0; | |
2132 ireg = 0; | |
2133 } | |
2134 if (lreg) { | |
2135 if (lreg==reg) { | |
2136 regs[lreg]=0; | |
2137 if (lreg>reg&& | |
2138 (regs[lreg]==USING_REG|| | |
2139 regs[lreg]==USING_DREG)) | |
2140 { | |
2141 free_register(lreg); | |
2142 } | |
2143 if (creg==lreg) creg = ireg; | |
2144 free_register(lreg); | |
2145 lreg = 0; | |
2146 } else if (lreg==reg) { | |
2147 regs[lreg]=0; | |
2148 if (lreg>reg && ( | |
2149 (regs[lreg]==USING_REG) || | |
2150 (regs[lreg]==USING_DREG) )) | |
2151 { | |
2152 free_register(lreg); | |
2153 } | |
2154 if (creg==lreg) creg = ireg; | |
2155 free_register(lreg); | |
2156 lreg = 0; | |
2157 } | |
2158 } | |
2159 } else if (is_longlong_reg(reg)) { | |
2160 use_input_reg(reg,0); | |
2161 use_input_reg(reg,0); | |
2162 } else if (is_double_reg(reg)) { | |
2163 use_input_reg(reg,0); | |
2164 use_input_reg(reg,0); | |
2165 } else if (is_float_reg(reg)) { | |
2166 if (freg&® == freg) { | |
2167 if (creg==freg) creg = ireg; | |
2168 freg = 0; | |
2169 } | |
2170 } | |
2171 if (mode) use_reg(reg); | |
2172 } | |
2173 | |
2174 static void | |
2175 code_assign_input_float_int(int e1,int e2) { | |
2176 #if FLOAT_CODE | |
2177 int r,tmp=-1; | |
2178 float f; | |
2179 char *frn; | |
2180 // e1 = e2; | |
2181 if (car(e1)!=REGISTER) { error(-1); return; } | |
2182 frn = register_name(r=cadr(e1)); | |
2183 switch(car(e2)) { | |
2184 case FCONST: | |
2185 f = dcadr(e2); | |
2186 code_const(*((int*)&f),r); | |
2187 break; | |
2188 case FRGVAR: | |
2189 code_rgvar(e2,r); | |
2190 break; | |
2191 case FRLVAR: | |
2192 code_rlvar(cadr(e2),r); | |
2193 break; | |
2194 default: | |
2195 g_expr(rvalue_t(e2,FLOAT)); | |
2196 case FREGISTER: | |
2197 tmp = new_lvar(SIZE_OF_INT); | |
2198 code_dassign_lvar(tmp, (car(e2)==FREGISTER)?cadr(e2):freg,0); | |
2199 code_rlvar(tmp,r); | |
2200 if (tmp!=-1) free_lvar(tmp); | |
2201 } | |
2202 #endif | |
2203 } | |
2204 | |
2205 static void | |
2206 code_assign_input_double_long(int e1,int e2) { | |
2207 #if FLOAT_CODE | |
2208 int r,tmp=-1,reg=0; | |
2209 double value; | |
2210 // e1 = e2; | |
2211 if (car(e1)!=LREGISTER) { error(-1); return; } | |
2212 r=cadr(e1); | |
2213 switch(car(e2)) { | |
2214 case DCONST: | |
2215 value = dcadr(e2); | |
2216 dconst(r,r,value); | |
2217 break; | |
2218 case DRGVAR: | |
2219 code_lrgvar(e2,r); | |
2220 break; | |
2221 case DRLVAR: | |
2222 code_lrlvar(cadr(e2),r); | |
2223 break; | |
2224 default: | |
2225 g_expr(rvalue_t(e2,DOUBLE)); | |
2226 reg = freg; | |
2227 case DREGISTER: | |
2228 if (car(e2)==DREGISTER) reg = cadr(e2); | |
2229 printf("\tstfd\t%s, [sp, #-8]!\n",register_name(reg)); | |
2230 printf("\tldmfd\tsp!, {%s, %s}\n",lregister_name_low(r),lregister_name_high(r)); | |
2231 } | |
2232 if (tmp!=-1) free_lvar(tmp); | |
2233 #endif | |
2234 } | |
2235 | |
2236 static int | |
2237 compute_complex_arg(int e3,int reg_arg_list,int arg) { | |
2238 int t=caddr(e3); | |
2239 int e4 = car(e3); | |
2240 reg_arg_list = list2(arg,reg_arg_list); | |
2241 if (car(arg)==REGISTER||car(arg)==DREGISTER|| | |
2242 car(arg)==FREGISTER||car(arg)==LREGISTER) | |
2243 use_input_reg(cadr(arg),1); | |
2244 if (t==FLOAT&&car(arg)==REGISTER) | |
2245 code_assign_input_float_int(arg, e4); | |
2246 else if (t==DOUBLE&&car(arg)==LREGISTER) | |
2247 code_assign_input_double_long(arg, e4); | |
2248 else | |
2249 g_expr_u(assign_expr0(arg,e4,t,t)); | |
2250 car(e3) = arg; | |
2251 return reg_arg_list; | |
2252 } | |
2253 | |
2254 static void | |
2255 increment_function_arg(int e3,int *pnargs,int *preg_arg,int *pfreg_arg) { | |
2256 int nargs=0,reg_arg=0,freg_arg=0; | |
2257 int t=caddr(e3); | |
2258 if(scalar(t)) { | |
2259 nargs ++ ; reg_arg++; freg_arg++; | |
2260 } else if (t==LONGLONG||t==ULONGLONG||t==DOUBLE) { | |
2261 nargs ++ ; reg_arg++; | |
2262 nargs ++ ; reg_arg++; | |
2263 } else if (t==FLOAT) { | |
2264 reg_arg ++ ; freg_arg++; | |
2265 nargs += size(t)/SIZE_OF_INT; | |
2266 } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { | |
2267 nargs += round4(size(t))/SIZE_OF_INT; | |
2268 } else { | |
2269 error(TYERR); | |
2270 nargs ++ ; | |
2271 } | |
2272 *pnargs += nargs; | |
2273 *preg_arg += reg_arg; | |
2274 *pfreg_arg += freg_arg; | |
2275 } | |
2276 | |
2277 #define AS_SAVE 1 | |
2278 #define AS_ARG 0 | |
2279 | |
2280 static int | |
2281 get_input_arg(int t,int mode,int nargs,int reg_arg,int freg_arg) | |
2282 { | |
2283 if(scalar(t)) { | |
2284 if (mode==AS_SAVE) { | |
2285 return get_register_var(0); | |
2286 } else if (reg_arg+1>MAX_INPUT_REGISTER_VAR) { | |
2287 return list3(LVAR,caller_arg_offset_v(nargs),0); | |
2288 } else | |
2289 return get_input_register_var(reg_arg,0,0); | |
2290 } else if (t==LONGLONG||t==ULONGLONG) { | |
2291 if (mode==AS_SAVE) { | |
2292 return get_lregister_var(0); | |
2293 } else if (reg_arg+1>=MAX_INPUT_REGISTER_VAR) { | |
2294 return list3(LVAR,caller_arg_offset_v(nargs),0); | |
2295 } else | |
2296 return get_input_lregister_var(reg_arg,0,0); | |
2297 } else if (t==FLOAT) { | |
2298 if (mode==AS_SAVE) { | |
2299 return get_dregister_var(0,0); | |
2300 } else if (freg_arg>=MAX_INPUT_DREGISTER_VAR) { | |
2301 return list3(LVAR,caller_arg_offset_v(nargs),0); | |
2302 } else | |
2303 return get_input_dregister_var(freg_arg,0,0,0); | |
2304 } else if (t==DOUBLE) { | |
2305 if (mode==AS_SAVE) { | |
2306 return get_dregister_var(0,1); | |
2307 } else if (reg_arg+1>=MAX_INPUT_DREGISTER_VAR) { | |
2308 return list3(LVAR,caller_arg_offset_v(nargs),0); | |
2309 } else | |
2310 return get_input_dregister_var(reg_arg,0,0,1); | |
2311 } else if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { | |
2312 if (mode==AS_SAVE) { | |
2313 return get_register_var(0); | |
2314 } else | |
2315 return list3(LVAR,caller_arg_offset_v(nargs),0); | |
2316 } else { | |
2317 error(-1); | |
2318 return get_register_var(0); | |
2319 } | |
2320 } | |
2321 | |
2322 static void | |
2323 code_call(int e2,NMTBL *fn,int jmp) | |
2324 { | |
2325 if (car(e2) == FNAME) { | |
2326 printf("\tbrsl\t$lr,%s\n",fn->nm); | |
2327 } else { | |
2328 printf("\tmov\tlr, pc\n"); | |
2329 printf("\tmov\tpc, %s\n",register_name(cadr(jmp))); | |
2330 } | |
2331 } | |
2332 | |
2333 int | |
2334 function(int e1) | |
2335 { | |
2336 int e2,e3,e4,e5,nargs,t; | |
2337 int arg,reg_arg,freg_arg,arg_assign; | |
2338 int dots; | |
2339 int reg_arg_list=0,ret_type,special_lvar; | |
2340 NMTBL *fn = 0; | |
2341 int jmp = 0; | |
2342 int complex_; | |
2343 int pnargs,preg_arg,pfreg_arg; | |
2344 int stargs,i; | |
2345 int half_register = 0; | |
2346 | |
2347 special_lvar = -1; | |
2348 ret_type = function_type(cadddr(e1),&dots); | |
2349 if (caddr(cadddr(e1))==0) dots=1; | |
2350 | |
2351 arg_assign = 0; | |
2352 e2 = cadr(e1); | |
2353 if (car(e2) == FNAME) { | |
2354 fn=(NMTBL *)cadr(e2); | |
2355 } else { | |
2356 if (car(e2)==INDIRECT) e2=cadr(e2); // (*func)(i) case | |
2357 // jmp = get_register_var(0); | |
2358 jmp = list2(REGISTER,REG_ip); | |
2359 if (!simple_arg(e2)) { | |
2360 e3=get_register_var(0); | |
2361 reg_arg_list = list2(e3,reg_arg_list); | |
2362 g_expr_u(assign_expr0(e3,e2,INT,INT)); | |
2363 e2=e3; | |
2364 } | |
2365 reg_arg_list = list2(jmp,reg_arg_list); | |
2366 arg_assign = list2(assign_expr0(jmp,e2,INT,INT),arg_assign); | |
2367 } | |
2368 /* First we execute complex argument to avoid interaction with | |
2369 input variables. Remain the last complex argument in complex_. */ | |
2370 stargs = 0; | |
2371 complex_ = 0; | |
2372 nargs = reg_arg = freg_arg = 0; | |
2373 pnargs = preg_arg = pfreg_arg = 0; | |
2374 for (e3 = e1 = reverse0(caddr(e1)); e3; e3 = cadr(e3)) { | |
2375 t=caddr(e3); | |
2376 if (reg_arg==3 && (t==DOUBLE||t==LONGLONG||t==ULONGLONG)) { | |
2377 half_register=1; | |
2378 } | |
2379 if ((e5= !simple_arg(car(e3)))) { | |
2380 if (complex_) { | |
2381 arg = get_input_arg(caddr(complex_),AS_SAVE, | |
2382 pnargs,preg_arg,pfreg_arg); | |
2383 reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); | |
2384 } | |
2385 // memorise last complex arg parameter | |
2386 pnargs=nargs;preg_arg=reg_arg;pfreg_arg=freg_arg; | |
2387 complex_ = e3; | |
2388 } | |
2389 if (t>=0&&(car(t)==STRUCT||car(t)==UNION)) { | |
2390 // The struct should be pushed after complex arguments. | |
2391 if (e5) { // compute address only, complex_ is me now. Clear it. | |
2392 complex_ = 0; | |
2393 e4 = car(e3); | |
2394 if (car(e4)!=RSTRUCT) error(-1); | |
2395 if (!simple_arg(cadr(e4))) { | |
2396 // Calculate complex struct address here. | |
2397 // If simple, leave it. | |
2398 arg = get_register_var(0); | |
2399 g_expr_u(assign_expr0(arg,list2(ADDRESS,car(e3)),INT,INT)); | |
2400 car(e3)=arg; | |
2401 reg_arg_list = list2(arg,reg_arg_list); | |
2402 if (car(arg)==REGISTER) use_input_reg(cadr(arg),1); | |
2403 else car(e3) = rvalue_t(arg,INT); | |
2404 } | |
2405 } | |
2406 stargs = list4(e3,stargs,nargs,reg_arg); | |
2407 } | |
2408 increment_function_arg(e3,&nargs,®_arg,&freg_arg); | |
2409 } | |
2410 | |
2411 /* now all input register vars are free */ | |
2412 code_save_stacks(); | |
2413 // set_lreg(LREG_LREGISTER,0); | |
2414 set_freg(FREG_FREGISTER,0); | |
2415 set_ireg(CREG_REGISTER,0); | |
2416 | |
2417 // Struct arguments need emit_copy. it destructs 3 input registers. | |
2418 // But it returns no value on a register. So calculate it here. | |
2419 // We cannot do this in the previous loop, because the copied struct may be | |
2420 // override by other complex arguments. But before this we have to check | |
2421 // complex_. | |
2422 | |
2423 if (stargs) { | |
2424 if (complex_) { | |
2425 arg = get_input_arg(caddr(complex_),AS_SAVE, | |
2426 pnargs,preg_arg,pfreg_arg); | |
2427 reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); | |
2428 } | |
2429 for(stargs=reverse0(stargs);stargs;stargs = cadr(stargs)) { | |
2430 e3 = car(stargs); | |
2431 e4 = car(e3); | |
2432 t = caddr(e3); | |
2433 arg = get_input_arg(t,AS_ARG,caddr(stargs),cadddr(stargs),0); | |
2434 push_struct(e4,t,arg); | |
2435 car(e3)=0; // done | |
2436 if (car(arg)==REGISTER) // wrong? | |
2437 use_input_reg(cadr(arg),1); | |
2438 } | |
2439 } else { | |
2440 // last complex argument can use input register | |
2441 if (complex_) { | |
2442 arg = get_input_arg(caddr(complex_),AS_ARG,pnargs,preg_arg,pfreg_arg); | |
2443 reg_arg_list = compute_complex_arg(complex_,reg_arg_list,arg); | |
2444 if (car(arg)!=LVAR) use_input_reg(cadr(arg),1); | |
2445 car(complex_) = 0; // done. | |
2446 if (car(arg)==REGISTER) | |
2447 use_input_reg(cadr(arg),1); | |
2448 } | |
2449 } | |
2450 | |
2451 nargs = reg_arg = freg_arg = 0; | |
2452 // calc stack arguments first, it may requires extra registers, | |
2453 // and we can still use input registers now. | |
2454 for (e3 = e1; e3; | |
2455 increment_function_arg(e3,&nargs,®_arg,&freg_arg), | |
2456 e3 = cadr(e3)) { | |
2457 if (!(e4=car(e3))) continue; | |
2458 t=caddr(e3); | |
2459 arg = get_input_arg(t,AS_ARG,nargs,reg_arg,freg_arg); | |
2460 if (car(arg)!=LVAR) continue; | |
2461 g_expr_u(assign_expr0(arg,e4,t,t)); | |
2462 car(e3)=0; // done | |
2463 } | |
2464 if (half_register) { | |
2465 // half register case writes *(sp-1) but it will be Ok. | |
2466 if (max_func_args<4) max_func_args=4; | |
2467 g_expr_u(assign_expr0(list3(REGISTER,4,0), | |
2468 list3(LVAR,caller_arg_offset_v(3),0),INT,INT)); | |
2469 use_input_reg(4,1); | |
2470 } | |
2471 nargs = reg_arg = freg_arg = 0; | |
2472 for (e3 = e1; e3; | |
2473 increment_function_arg(e3,&nargs,®_arg,&freg_arg), | |
2474 e3 = cadr(e3)) { | |
2475 if (!(e4=car(e3))) continue; | |
2476 t=caddr(e3); | |
2477 arg = get_input_arg(t,AS_ARG,nargs,reg_arg,freg_arg); | |
2478 if(scalar(t)) { | |
2479 reg_arg_list = list2(arg,reg_arg_list); | |
2480 /* protect from input register free */ | |
2481 if (car(arg)==REGISTER) | |
2482 use_input_reg(cadr(arg),1); | |
2483 g_expr_u(assign_expr0(arg,e4,t,t)); | |
2484 } else if (t==LONGLONG||t==ULONGLONG) { | |
2485 if (car(arg)==LREGISTER) { | |
2486 use_input_reg(cadr(arg),1); | |
2487 } | |
2488 reg_arg_list = list2(arg,reg_arg_list); | |
2489 g_expr_u(assign_expr0(arg,e4,t,t)); | |
2490 } else if (t==DOUBLE) { | |
2491 reg_arg_list = list2(arg,reg_arg_list); | |
2492 if (car(arg)==LREGISTER) { | |
2493 use_input_reg(cadr(arg),1); | |
2494 code_assign_input_double_long(arg, e4); | |
2495 } else { | |
2496 g_expr_u(assign_expr0(arg,e4,t,t)); | |
2497 } | |
2498 } else if (t==FLOAT) { | |
2499 reg_arg_list = list2(arg,reg_arg_list); | |
2500 if (car(arg)==REGISTER) { | |
2501 use_input_reg(cadr(arg),1);/* protect from input register free */ | |
2502 code_assign_input_float_int(arg, e4); | |
2503 } else { | |
2504 g_expr_u(assign_expr0(arg,e4,t,t)); /* XXX */ | |
2505 } | |
2506 } | |
2507 // structs are finished | |
2508 } | |
2509 if (max_func_args<nargs) max_func_args=nargs; | |
2510 for(;arg_assign;arg_assign=cadr(arg_assign)) { | |
2511 g_expr_u(car(arg_assign)); | |
2512 } | |
2513 clear_ptr_cache(); | |
2514 code_call(e2,fn,jmp); | |
2515 for(;reg_arg_list;reg_arg_list=cadr(reg_arg_list)) { | |
2516 arg = car(reg_arg_list); | |
2517 if (car(arg)==REGISTER||car(arg)==DREGISTER||car(arg)==FREGISTER | |
2518 ||car(arg)==LREGISTER) | |
2519 free_register(cadr(arg)); | |
2520 else if (car(arg)==LVAR&&cadr(arg)<0) free_lvar(cadr(arg)); | |
2521 } | |
2522 for(i=1;i<MAX_INPUT_REGISTER_VAR;i++) { | |
2523 free_register(i); | |
2524 } | |
2525 if (ret_type==DOUBLE) { | |
2526 #if FLOAT_CODE | |
2527 set_dreg(RET_DREGISTER,0); | |
2528 use_reg(RET_DREGISTER); | |
2529 #endif | |
2530 } else if (ret_type==FLOAT) { | |
2531 #if FLOAT_CODE | |
2532 set_freg(RET_FREGISTER,0); | |
2533 #endif | |
2534 } else if (ret_type==ULONGLONG||ret_type==LONGLONG) { | |
2535 #if LONGLONG_CODE | |
2536 set_lreg(RET_LREGISTER,0); | |
2537 use_reg(RET_LREGISTER); | |
2538 #endif | |
2539 } else if (ret_type==VOID) { | |
2540 } else { | |
2541 set_ireg(RET_REGISTER,0); | |
2542 } | |
2543 return ret_type; | |
2544 } | |
2545 | |
2546 void | |
2547 code_alloca(int e1,int reg) | |
2548 { | |
2549 char *crn; | |
2550 | |
2551 g_expr(list3(BAND,list3(ADD,e1,list2(CONST,15)),list2(CONST,~15))); | |
2552 use_int(reg); | |
2553 crn = register_name(reg); | |
2554 printf("\trsb\tsp, %s, sp\n",crn); | |
2555 if (!max_func_arg_label) max_func_arg_label = fwdlabel(); | |
2556 code_label_value(max_func_arg_label ,REG_ip); | |
2557 printf("\ta\t%s, sp, ip\n",crn); | |
2558 } | |
2559 | |
2560 void | |
2561 code_frame_pointer(int e3) { | |
2562 use_int(e3); | |
2563 printf("\tmov\tfp, %s\n",register_name(e3)); | |
2564 } | |
2565 | |
2566 int | |
2567 code_frame_pointer_register() | |
2568 { | |
2569 return list2(REGISTER,REG_fp); | |
2570 } | |
2571 | |
2572 void | |
2573 code_fix_frame_pointer(int env) { | |
2574 char *trn; | |
2575 //int disp,label; | |
2576 //int label; | |
2577 int disp; | |
2578 if (is_function(fnptr) && ! env) { | |
2579 trn = register_name(REG_ip); | |
2580 //disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(0)),&label); | |
2581 printf("\tlqd\t%s, %d($sp)\n",trn,disp); | |
2582 printf("\ta\tfp, fp, %s\n",trn); | |
2583 } | |
2584 } | |
2585 | |
2586 static void | |
2587 code_unfix_frame_pointer() | |
2588 { | |
2589 char *trn; | |
2590 //int disp,label; | |
2591 int disp; | |
2592 | |
2593 trn = register_name(REG_ip); | |
2594 //disp = search_const(LVAR,glist2(lvar_offset_label,FUNC_LVAR(0)),&label); | |
2595 printf("\tlqd\t%s, %d($sp)\n",trn,disp); | |
2596 printf("\tsf\tfp, fp, %s\n",trn); | |
2597 } | |
2598 | |
2599 | |
2600 void | |
2601 code_jmp(char *s) { | |
2602 // jump to continuation means use all register variable | |
2603 max_reg_var = REG_VAR_MAX-REG_VAR_MIN; | |
2604 max_reg_var = FREG_VAR_MAX-FREG_VAR_MIN; | |
2605 printf("\tbr\t%s\n",s); | |
2606 control=0; | |
2607 } | |
2608 | |
2609 void | |
2610 code_indirect_jmp(int e2) { | |
2611 // jump to continuation means use all register variable | |
2612 max_reg_var = REG_VAR_MAX-REG_VAR_MIN; | |
2613 max_reg_var = FREG_VAR_MAX-FREG_VAR_MIN; | |
2614 use_int(e2); | |
2615 printf("\tmov\tpc, %s @ indirect jump\n",register_name(e2)); // ?! | |
2616 control=0; | |
2617 } | |
2618 | |
2619 void | |
2620 code_rindirect(int e1, int reg,int offset, int sign,int sz) | |
2621 { | |
2622 int lreg; | |
2623 g_expr(e1); | |
2624 if (!is_int_reg(creg)) error(-1); | |
2625 lreg = creg; | |
2626 use_int(reg); | |
2627 code_ld(cload(sz,sign),reg,offset,lreg,cext_at(sz,sign)); | |
2628 cext(sign,sz,reg); | |
2629 } | |
2630 | |
2631 #if FLOAT_CODE | |
2632 int | |
2633 code_drindirect(int e1, int reg,int offset, int d) | |
2634 { | |
2635 int xreg; | |
2636 g_expr(e1); | |
2637 if (!is_int_reg(creg)) error(-1); | |
2638 xreg = creg; | |
2639 use_float(d,reg); | |
2640 code_ldf(d?"ldfd":"ldfs",register_name(reg),offset,xreg,""); | |
2641 return d?DOUBLE:FLOAT; | |
2642 } | |
2643 #endif | |
2644 | |
2645 #if LONGLONG_CODE||FLOAT_CODE | |
2646 | |
2647 static void | |
2648 lload(int creg,int reg,int offset) | |
2649 { | |
2650 char *crn=register_name(creg); | |
2651 #if ENDIAN_L==0 | |
2652 if (creg!=reg) { | |
2653 printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset); | |
2654 printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset+SIZE_OF_INT); | |
2655 } else { | |
2656 printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset+SIZE_OF_INT); | |
2657 printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset); | |
2658 } | |
2659 #else | |
2660 if (creg!=reg) { | |
2661 printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset+SIZE_OF_INT); | |
2662 printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset); | |
2663 } else { | |
2664 printf("\tldr\t%s, [%s, #%d]\n",lregister_name_high(reg),crn,offset); | |
2665 printf("\tldr\t%s, [%s, #%d]\n",lregister_name_low(reg),crn,offset+SIZE_OF_INT); | |
2666 } | |
2667 #endif | |
2668 } | |
2669 | |
2670 | |
2671 static void | |
2672 lmove(int to,int from) | |
2673 { | |
2674 int l; | |
2675 l = list3(to,0,from); | |
2676 l = list3(to,l,from); | |
2677 parallel_rassign(l); | |
2678 } | |
2679 | |
2680 static void | |
2681 set_operands(int r0,int r1,int r2,int r3) | |
2682 { | |
2683 int l; | |
2684 l = list3(DREGISTER_OPERAND_L,0,r0); | |
2685 l = list3(DREGISTER_OPERAND_H,l,r1); | |
2686 l = list3(DREGISTER_OPERAND_1_L,l,r2); | |
2687 l = list3(DREGISTER_OPERAND_1_H,l,r3); | |
2688 parallel_rassign(l); | |
2689 } | |
2690 | |
2691 | |
2692 static void | |
2693 lstore(int e2,int creg) | |
2694 { | |
2695 char *drn = register_name(e2); | |
2696 char *crn_h; | |
2697 char *crn_l; | |
2698 crn_h = lregister_name_high(creg); | |
2699 crn_l = lregister_name_low(creg); | |
2700 #if ENDIAN_L==0 | |
2701 printf("\tstr\t%s, [%s, #0]\n",crn_l,drn); | |
2702 printf("\tstr\t%s, [%s, #%d]\n",crn_h,drn,SIZE_OF_INT); | |
2703 #else | |
2704 printf("\tstr\t%s, [%s, #0]\n",crn_h,drn); | |
2705 printf("\tstr\t%s, [%s, #%d]\n",crn_l,drn,SIZE_OF_INT); | |
2706 #endif | |
2707 } | |
2708 | |
2709 int | |
2710 code_lrindirect(int e1, int reg, int offset, int us) | |
2711 { | |
2712 int creg0; | |
2713 | |
2714 g_expr(e1); | |
2715 if (!is_int_reg(creg)) error(-1); | |
2716 creg0=creg; | |
2717 use_longlong(reg); | |
2718 lload(creg0,reg,offset); | |
2719 return us?ULONGLONG:LONGLONG; | |
2720 } | |
2721 #endif | |
2722 | |
2723 static char * | |
2724 cstore(int sz) | |
2725 { | |
2726 switch(sz) { | |
2727 case 1: return "stqx"; | |
2728 case SIZE_OF_SHORT: return "stqa"; | |
2729 default: return "stqd"; | |
2730 } | |
2731 } | |
2732 | |
2733 void | |
2734 code_assign_gvar(int e2,int creg,int byte) { | |
2735 use_int(creg); | |
2736 code_ldf(cstore(byte),register_name(creg),cadr(e2), | |
2737 get_ptr_cache((NMTBL*)caddr(e2)),byte==SIZE_OF_SHORT?" @ movhi":""); | |
2738 } | |
2739 | |
2740 void | |
2741 code_assign_lvar(int e2,int creg,int byte) { | |
2742 char *crn; | |
2743 use_int(creg); | |
2744 crn=register_name(creg); | |
2745 lvar_intro(e2); | |
2746 printf("\t%s\t%s,",cstore(byte),crn); | |
2747 e2 *= 4; | |
2748 lvar(e2,""); | |
2749 } | |
2750 | |
2751 void | |
2752 code_assign_register(int e2,int byte,int creg) { | |
2753 use_int(creg); | |
2754 if (e2!=creg) { | |
2755 printf("\tori\t%s, %s, 0\n",register_name(e2),register_name(creg)); | |
2756 } | |
2757 } | |
2758 | |
2759 void | |
2760 code_assign(int e2,int byte,int creg) { | |
2761 char *drn; | |
2762 char *crn; | |
2763 use_int(e2); | |
2764 drn=register_name(e2); | |
2765 use_int(creg); | |
2766 crn=register_name(creg); | |
2767 | |
2768 printf("\t%s\t%s, 0(%s)\n",cstore(byte),crn,drn); | |
2769 } | |
2770 | |
2771 | |
2772 void | |
2773 code_register_assop(int e2,int reg, int op,int byte) { | |
2774 // reg <= reg(e2) op=reg | |
2775 use_int(reg); | |
2776 tosop(op,e2,reg); | |
2777 } | |
2778 | |
2779 void | |
2780 code_assop(int op,int creg, int byte,int sign) { | |
2781 char *xrn,*crn,*drn; | |
2782 int xreg; | |
2783 int edx = get_register_var(0); | |
2784 if (car(edx)!=REGISTER) error(-1); | |
2785 // (*creg) op = pop() | |
2786 | |
2787 drn = register_name(edx=cadr(edx)); | |
2788 use_int(creg); | |
2789 xrn = register_name(xreg = emit_pop(0)); /* pop e3 value */ | |
2790 code_register(creg,edx); | |
2791 ld_indexx(byte,0,edx,creg,sign); | |
2792 tosop(op,creg,xreg); | |
2793 crn = register_name(creg); | |
2794 printf("\t%s\t%s, 0(%s)\n",cstore(byte),crn,drn); | |
2795 free_register(edx); | |
2796 free_register(creg); | |
2797 emit_pop_free(xreg); | |
2798 } | |
2799 | |
2800 int | |
2801 tosop_operand_safe_p(int op) | |
2802 { | |
2803 return 1; | |
2804 } | |
2805 | |
2806 void | |
2807 tosop(int op,int creg,int oreg) | |
2808 { | |
2809 int ox = -1; | |
2810 char *orn,*crn; | |
2811 // creg = creg op oreg | |
2812 | |
2813 use_int(creg); | |
2814 if(oreg==-1) { | |
2815 error(-1); | |
2816 } else if (oreg<= -REG_LVAR_OFFSET) { | |
2817 ox = get_register(); if (ox<0) error(-1); | |
2818 code_rlvar(oreg+REG_LVAR_OFFSET,ox); | |
2819 free_lvar(oreg+REG_LVAR_OFFSET); | |
2820 oreg = ox; | |
2821 } | |
2822 | |
2823 switch(op) { | |
2824 case LSHIFT: | |
2825 case ULSHIFT: | |
2826 shift("asl",creg,oreg); | |
2827 if(ox!=-1) free_register(ox); | |
2828 return; | |
2829 case RSHIFT: | |
2830 shift("asr",creg,oreg); | |
2831 if(ox!=-1) free_register(ox); | |
2832 return; | |
2833 case URSHIFT: | |
2834 shift("lsr",creg,oreg); | |
2835 if(ox!=-1) free_register(ox); | |
2836 return; | |
2837 } | |
2838 orn = register_name(oreg); | |
2839 crn = register_name(creg); | |
2840 switch(op) { | |
2841 case ADD: | |
2842 printf("\ta\t%s, %s, %s\n",crn,crn,orn); | |
2843 break; | |
2844 case SUB: | |
2845 printf("\tsf\t%s, %s, %s\n",crn,crn,orn); | |
2846 break; | |
2847 case CMP: | |
2848 printf("\tcmp\t%s, %s\n",crn,orn); | |
2849 break; | |
2850 case BAND: | |
2851 printf("\tand\t%s, %s, %s\n",crn,crn,orn); | |
2852 break; | |
2853 case EOR: | |
2854 printf("\teor\t%s, %s, %s\n",crn,crn,orn); | |
2855 break; | |
2856 case BOR: | |
2857 printf("\torr\t%s, %s, %s\n",crn,crn,orn); | |
2858 break; | |
2859 case MUL: | |
2860 case UMUL: | |
2861 /* target!=source */ | |
2862 printf("\tmul\t%s, %s, %s\n",crn,orn,crn); | |
2863 break; | |
2864 case DIV: | |
2865 code_int_lib("__divsi3",creg,oreg); break; | |
2866 case UDIV: | |
2867 code_int_lib("__udivsi3",creg,oreg); break; | |
2868 case MOD: | |
2869 code_int_lib("__modsi3",creg,oreg); break; | |
2870 case UMOD: | |
2871 code_int_lib("__umodsi3",creg,oreg); break; | |
2872 default: | |
2873 error(-1); | |
2874 } | |
2875 if(ox!=-1) free_register(ox); | |
2876 } | |
2877 | |
2878 int | |
2879 code_const_op_p(int op,int v) | |
2880 { | |
2881 if (car(v)!=CONST) return 0; | |
2882 v = cadr(v); | |
2883 switch(op) { | |
2884 case MUL: case UMUL: case DIV: case UDIV: | |
2885 return ilog(v); | |
2886 case ADD: case SUB: | |
2887 return 1; | |
2888 case LSHIFT: case ULSHIFT: case RSHIFT: case URSHIFT: | |
2889 return 0<v&&v<=32; | |
2890 case CMP: | |
2891 return is_stage1_const(v,CMP); | |
2892 case EOR: case BOR: case BAND: | |
2893 return (is_stage1_const(v,0)>0); | |
2894 default: | |
2895 return 0; | |
2896 } | |
2897 } | |
2898 | |
2899 void | |
2900 oprtc(int op,int creg, int v) | |
2901 { | |
2902 char *crn; | |
2903 use_int(creg); | |
2904 crn = register_name(creg); | |
2905 v = cadr(v); | |
2906 | |
2907 switch(op) { | |
2908 case MUL: case UMUL: | |
2909 v=ilog(v); | |
2910 case LSHIFT: | |
2911 case ULSHIFT: | |
2912 printf("\tmov\t%s, %s, asl #%d\n",crn,crn,v); | |
2913 break; | |
2914 case DIV: | |
2915 v=ilog(v); | |
2916 case RSHIFT: | |
2917 printf("\tmov\t%s, %s, asr #%d\n",crn,crn,v); | |
2918 break; | |
2919 case UDIV: | |
2920 v=ilog(v); | |
2921 case URSHIFT: | |
2922 printf("\tmov\t%s, %s, lsr #%d\n",crn,crn,v); | |
2923 break; | |
2924 case ADD: | |
2925 code_add(creg,v,creg); | |
2926 break; | |
2927 case SUB: | |
2928 code_add(creg,-v,creg); | |
2929 break; | |
2930 case CMP: printf("\tcmp\t%s,%d\n",crn,v); break; | |
2931 case BOR: printf("\torr\t%s, %s, #%d\n",crn,crn,v); break; | |
2932 case EOR: printf("\teor\t%s, %s, #%d\n",crn,crn,v); break; | |
2933 case BAND: printf("\tand\t%s, %s, #%d\n",crn,crn,v); break; | |
2934 default: | |
2935 error(-1); | |
2936 } | |
2937 } | |
2938 | |
2939 void | |
2940 shift(char *op, int creg, int reg) | |
2941 { | |
2942 char *crn; | |
2943 char *rrn = register_name(reg); | |
2944 use_int(creg); | |
2945 crn = register_name(creg); | |
2946 printf("\tmov\t%s, %s, %s %s\n",crn,crn,op,rrn); | |
2947 } | |
2948 | |
2949 void | |
2950 ld_indexx(int byte, int n, int xreg,int creg, int sign) | |
2951 { | |
2952 use_int(creg); | |
2953 code_ld(cload(byte,sign),creg,n,xreg,cext_at(byte,sign)); | |
2954 } | |
2955 | |
2956 int | |
2957 code_csvalue() | |
2958 { | |
2959 return glist2(REGISTER,creg); | |
2960 } | |
2961 | |
2962 void | |
2963 code_cmpdimm(int e, int csreg,int label,int cond) | |
2964 { | |
2965 /* used in dosiwtch() */ | |
2966 int sign,reg=-1; | |
2967 int regsv; | |
2968 char *rn,*crn; | |
2969 crn = register_name(csreg); | |
2970 | |
2971 if (!(sign=is_stage1_const(e,CMP))) { | |
2972 regsv = regs[csreg]; regs[csreg]=1; | |
2973 rn = register_name(reg= get_register()); | |
2974 regs[csreg] = regsv; | |
2975 code_const(e,reg); | |
2976 printf("\tcmp\t%s, %s\n",crn,rn); | |
2977 } else { | |
2978 if (sign>0) | |
2979 printf("\tcmp\t%s, #%d\n",crn,e); | |
2980 else | |
2981 printf("\tcmn\t%s, #%d\n",crn,-e); | |
2982 } | |
2983 switch(cond) { | |
2984 case -1: break; | |
2985 case 1: | |
2986 printf("\tbne\t.LC%d\n",label); break; | |
2987 case 0: | |
2988 printf("\tbeq\t.LC%d\n",label); break; | |
2989 case LT: | |
2990 printf("\tblt\t.LC%d\n",label); break; | |
2991 case GT: | |
2992 printf("\tbgt\t.LC%d\n",label); break; | |
2993 default: error(-1); | |
2994 } | |
2995 if (reg!=-1) free_register(reg); | |
2996 } | |
2997 | |
2998 void | |
2999 code_opening(char *filename) | |
3000 { | |
3001 /* this is called once per file */ | |
3002 //printf("@ Generated by mc for ARM/elf\n"); | |
3003 printf("\t.file \"%s\"\n",filename); | |
3004 // printf(".text\n"); | |
3005 } | |
3006 | |
3007 // should have pcond_const | |
3008 | |
3009 #define COND_BRANCH 1 | |
3010 #define COND_VALUE 2 | |
3011 #define COND_BRANCH_CONST 3 | |
3012 #define COND_VALUE_CONST 4 | |
3013 | |
3014 /* | |
3015 if (r1 cmp r2) goto l1 COND_BRANCH | |
3016 r0 = (r1 cmp r2) COND_VALUE | |
3017 */ | |
3018 static void | |
3019 pcond(int op, int r2,int r1,int r0,int cond,int l1,int mode) | |
3020 { | |
3021 char *rn2; | |
3022 char *rn1; | |
3023 char *rn0; | |
3024 char *cc=0,*ncc=0; | |
3025 | |
3026 if (mode==COND_BRANCH_CONST||mode==COND_VALUE_CONST) { | |
3027 rn1 = register_name(r1); | |
3028 if (r2>=0) | |
3029 printf("\tcmp\t%s, #%d\n",rn1,r2); | |
3030 else | |
3031 printf("\tcmn\t%s, #%d\n",rn1,-r2); | |
3032 } else { | |
3033 rn1 = register_name(r1); | |
3034 rn2 = register_name(r2); | |
3035 printf("\tcmp\t%s, %s\n",rn1,rn2); | |
3036 } | |
3037 | |
3038 switch(op+(!cond)*BNOT) { | |
3039 case GT: case LE+BNOT: cc="gt"; ncc="le"; break; | |
3040 case LE: case GT+BNOT: cc="le"; ncc="gt"; break; | |
3041 case GE: case LT+BNOT: cc="ge"; ncc="lt"; break; | |
3042 case LT: case GE+BNOT: cc="lt"; ncc="ge"; break; | |
3043 case UGT: case ULE+BNOT: cc="hi"; ncc="ls"; break; | |
3044 case ULE: case UGT+BNOT: cc="ls"; ncc="hi"; break; | |
3045 case UGE: case ULT+BNOT: cc="hs"; ncc="lo"; break; | |
3046 case ULT: case UGE+BNOT: cc="lo"; ncc="hs"; break; | |
3047 case EQ: case NEQ+BNOT: cc="eq"; ncc="ne"; break; | |
3048 case NEQ: case EQ+BNOT: cc="ne"; ncc="eq"; break; | |
3049 default: error(-1); | |
3050 } | |
3051 | |
3052 if (mode==COND_BRANCH||mode==COND_BRANCH_CONST) { | |
3053 printf("\tb%s\t.LC%d\n",cc,l1); | |
3054 } else if (mode==COND_VALUE||mode==COND_VALUE_CONST) { | |
3055 rn0 = register_name(r0); | |
3056 printf("\tmov%s\t%s, #0\n",ncc,rn0); | |
3057 printf("\tmov%s\t%s, #1\n",cc,rn0); | |
3058 } else error(-1); | |
3059 } | |
3060 | |
3061 int | |
3062 rexpr_bool(int e1, int reg) | |
3063 { | |
3064 int e2,reg0; | |
3065 int op = car(e1); | |
3066 if (!( | |
3067 op== GT || op== LT || op== UGT || op== ULT || | |
3068 op== ULE || op== UGE || op== LE || op== GE || | |
3069 op== EQ || op== NEQ | |
3070 )) return 0; | |
3071 if (car(caddr(e1))==CONST && is_stage1_const(cadr(caddr(e1)),CMP)) { | |
3072 g_expr(cadr(e1)); | |
3073 reg0 = ireg; | |
3074 use_int(reg); | |
3075 pcond(op, cadr(caddr(e1)),reg0,reg,1,0,COND_VALUE_CONST); | |
3076 } else { | |
3077 g_expr(cadr(e1)); | |
3078 emit_push(); | |
3079 g_expr(caddr(e1)); | |
3080 e2 = emit_pop(1); | |
3081 reg0 = ireg; | |
3082 use_int(reg); | |
3083 pcond(op, reg0,e2,reg,1,0,COND_VALUE); | |
3084 emit_pop_free(e2); | |
3085 } | |
3086 return 1; | |
3087 } | |
3088 | |
3089 int | |
3090 rexpr(int e1, int l1, int cond,int t) | |
3091 { | |
3092 int e2; | |
3093 int op = car(e1); | |
3094 | |
3095 if (car(caddr(e1))==CONST && is_stage1_const(cadr(caddr(e1)),CMP)) { | |
3096 g_expr(cadr(e1)); | |
3097 pcond(op, cadr(caddr(e1)),ireg,0,cond,l1,COND_BRANCH_CONST); | |
3098 } else { | |
3099 g_expr(cadr(e1)); | |
3100 emit_push(); | |
3101 g_expr(caddr(e1)); | |
3102 e2 = emit_pop(1); | |
3103 pcond(op, ireg,e2,0,cond,l1,COND_BRANCH); | |
3104 emit_pop_free(e2); | |
3105 } | |
3106 return l1; | |
3107 } | |
3108 | |
3109 #define CMP_C1T (-1) | |
3110 | |
3111 static void | |
3112 jcond(int l, int cond) | |
3113 { | |
3114 printf("\tb%s\t.LC%d\n",cond?"ne":"eq",l); | |
3115 } | |
3116 | |
3117 void | |
3118 jmp(int l) | |
3119 { | |
3120 printf("\tbr\t.LC%d\n",l); | |
3121 if (inst_count>CONST_TBL_COUNT/2) { | |
3122 const_list_table(); | |
3123 } | |
3124 } | |
3125 | |
3126 void | |
3127 code_comment(char *s) | |
3128 { | |
3129 printf("## %s",s); | |
3130 } | |
3131 /* | |
3132 static int | |
3133 code_register_save(int reg_save,int freg_save,int disp) | |
3134 { | |
3135 int i; | |
3136 printf("\tstmfd\tsp!, {"); | |
3137 for (i=reg_var_num(0);i<reg_var_num(reg_save);i++) { | |
3138 printf("%s, ",register_name(i)); | |
3139 } | |
3140 printf("fp, ip, lr, pc}\n"); | |
3141 if (freg_save>0) { | |
3142 printf("\tsfmfd\tf4, %d, [sp]!\n",freg_save); | |
3143 } | |
3144 return disp; | |
3145 } | |
3146 */ | |
3147 | |
3148 static int | |
3149 code_register_restore(int reg_save,int freg_save,int disp) | |
3150 { | |
3151 int i; | |
3152 if (freg_save>0) { | |
3153 i=reg_save*SIZE_OF_INT+ | |
3154 freg_save*SIZE_OF_DOUBLE + 20; | |
3155 printf("\tlfm\tf4, %d, [fp, #%d]\n",freg_save,-i); | |
3156 } | |
3157 //printf("\tldmea\tfp, {"); | |
3158 for (i=reg_var_num(0);i<reg_var_num(reg_save);i++) { | |
3159 printf("%s, ",register_name(i)); | |
3160 } | |
3161 //printf("fp, sp, pc}\n"); | |
3162 return disp; | |
3163 } | |
3164 | |
3165 static int entry_label; | |
3166 | |
3167 void | |
3168 code_enter(char *name) | |
3169 { | |
3170 if (output_mode!=TEXT_EMIT_MODE) | |
3171 text_mode(3); | |
3172 else | |
3173 printf("\t.align 3\n"); | |
3174 if (stmode!=STATIC) | |
3175 printf("\t.globl\t%s\n",name); | |
3176 printf("\t.type\t%s,function\n",name); | |
3177 r1_offset_label = fwdlabel(); | |
3178 max_func_args = 0; | |
3179 printf("%s:\n",name); | |
3180 code_label_value(r1_offset_label,REG_ip); | |
3181 printf("\ta\tsp, ip, fp\n"); | |
3182 clear_ptr_cache(); | |
3183 } | |
3184 | |
3185 | |
3186 void | |
3187 code_enter1(int args) | |
3188 { | |
3189 // set_lreg(LREG_LREGISTER,0); | |
3190 set_ireg(CREG_REGISTER,0); | |
3191 set_freg(FREG_FREGISTER,0); | |
3192 } | |
3193 | |
3194 void | |
3195 code_leave(char *name) | |
3196 { | |
3197 code_offset_set(fnptr); | |
3198 local_table(); | |
3199 printf("\t.size\t%s,.LC%d-%s\n",name, backdef(),name); | |
3200 } | |
3201 | |
3202 void | |
3203 enter(char *name) | |
3204 { | |
3205 if (output_mode!=TEXT_EMIT_MODE) | |
3206 text_mode(2); | |
3207 else | |
3208 printf("\t.align 2\n"); | |
3209 | |
3210 max_func_args = 0; | |
3211 | |
3212 lvar_offset_label = fwdlabel(); | |
3213 // r1_offset_label = fwdlabel(); | |
3214 printf("\t.type\t%s,function\n",name); | |
3215 if (stmode!=STATIC) | |
3216 printf("\t.globl\t%s\n",name); | |
3217 printf("%s:\n",name); | |
3218 //printf("\tmov\tip, sp\n"); | |
3219 printf("\tstqd\t$lr,16($sp)\n"); | |
3220 printf("\tstqd\t$sp,-32($sp)\n"); | |
3221 printf("\tai\t$sp,$sp,-32\n"); | |
3222 gen_jmp(entry_label = fwdlabel()); | |
3223 register_save_return_label = backdef(); | |
3224 clear_ptr_cache(); | |
3225 } | |
3226 | |
3227 void | |
3228 enter1() | |
3229 { | |
3230 text_mode(0); | |
3231 // set_lreg(LREG_LREGISTER,0); | |
3232 set_ireg(CREG_REGISTER,0); | |
3233 set_freg(FREG_FREGISTER,0); | |
3234 } | |
3235 | |
3236 void | |
3237 code_label_call(int l) | |
3238 { | |
3239 printf("\tbl\tL_%d\n",l); | |
3240 } | |
3241 | |
3242 void | |
3243 code_ret() | |
3244 { | |
3245 printf("\tmov\tpc, lr\n"); | |
3246 control=0; | |
3247 } | |
3248 | |
3249 void | |
3250 leave(int control0, char *name) | |
3251 { | |
3252 int retcont1=0,sz; | |
3253 | |
3254 if (control0) { | |
3255 code_set_return_register(1); | |
3256 } else | |
3257 text_mode(2); | |
3258 if (retcont) { | |
3259 /* return from CbC segement */ | |
3260 if (control0) gen_jmp(retlabel); | |
3261 retcont1 = fwdlabel(); | |
3262 fwddef(retcont); | |
3263 if (cadr(fnptr->ty)==FLOAT) { | |
3264 #if FLOAT_CODE | |
3265 creg = freg = cadr(get_input_dregister_var(0,0,1,0)); | |
3266 set_freg(RET_FREGISTER,1); | |
3267 #endif | |
3268 } else if (cadr(fnptr->ty)==DOUBLE) { | |
3269 #if FLOAT_CODE | |
3270 creg = lreg = cadr(get_input_dregister_var(0,0,1,1)); | |
3271 set_dreg(RET_DREGISTER,1); | |
3272 #endif | |
3273 } else if (cadr(fnptr->ty)>0&&( | |
3274 car(cadr(fnptr->ty))==STRUCT || | |
3275 car(cadr(fnptr->ty))==UNION)) { | |
3276 sz = size(cadr(fnptr->ty)); | |
3277 code_const(sz,REGISTER_OPERAND); | |
3278 printf("\tsf\tr1, r2, fp\n"); | |
3279 printf("\tlqd\tr0, [fp, #%d]\n",(my_func_args-1)*SIZE_OF_INT); | |
3280 emit_copy(6,3,sz,0,1,1); | |
3281 } else if (cadr(fnptr->ty)!=VOID) { | |
3282 creg = ireg = cadr(get_input_register_var(0,0,1)); | |
3283 if (creg!=RET_REGISTER) | |
3284 set_ireg(RET_REGISTER,1); | |
3285 } | |
3286 code_unfix_frame_pointer(); | |
3287 } | |
3288 fwddef(retlabel); | |
3289 | |
3290 code_offset_set(fnptr); | |
3291 code_register_restore(max_reg_var,max_reg_var,0); | |
3292 | |
3293 // leave part end | |
3294 | |
3295 // entry part (save register) | |
3296 | |
3297 fwddef(entry_label); | |
3298 if (arg_on_register>0) | |
3299 printf("\tsfi\tsp, sp, %d\n",arg_on_register); | |
3300 //code_register_save(max_reg_var,max_reg_var,0); | |
3301 | |
3302 //printf("\tsf\tfp, ip, #%d\n",4+arg_on_register); | |
3303 code_add(REG_sp,disp-max_func_args*SIZE_OF_INT,REG_sp); | |
3304 gen_jmp(register_save_return_label); | |
3305 local_table(); | |
3306 | |
3307 printf("\t.size\t%s,.LC%d-%s\n",name, backdef(),name); | |
3308 | |
3309 free_all_register(); | |
3310 } | |
3311 | |
3312 | |
3313 void | |
3314 code_set_return_register(int mode) { | |
3315 if (cadr(fnptr->ty)==FLOAT) { | |
3316 set_freg(RET_FREGISTER,mode); | |
3317 } else if (cadr(fnptr->ty)==DOUBLE) { | |
3318 #if FLOAT_CODE | |
3319 set_dreg(RET_DREGISTER,mode); | |
3320 #endif | |
3321 } else if (cadr(fnptr->ty)==LONGLONG||cadr(fnptr->ty)==ULONGLONG) { | |
3322 #if LONGLONG_CODE | |
3323 set_lreg(RET_LREGISTER,mode); | |
3324 #endif | |
3325 } else if (cadr(fnptr->ty)==VOID) { | |
3326 } else { | |
3327 set_ireg(RET_REGISTER,mode); | |
3328 } | |
3329 } | |
3330 | |
3331 int | |
3332 code_get_fixed_creg(int reg,int type) { | |
3333 switch(type) { | |
3334 #if FLOAT_CODE | |
3335 case DOUBLE: use_float(1,reg); break; | |
3336 case FLOAT: use_float(0,reg); break; | |
3337 #endif | |
3338 #if LONGLONG_CODE | |
3339 case LONGLONG: case ULONGLONG: use_longlong(reg); break; | |
3340 #endif | |
3341 default: | |
3342 if (reg==USE_CREG) { | |
3343 if (regs[CREG_REGISTER]==0||regs[CREG_REGISTER]==PTRC_REG) { | |
3344 set_ireg(CREG_REGISTER,is_int_reg(creg)&®s[creg]==USING_REG); | |
3345 return CREG_REGISTER; | |
3346 } | |
3347 } | |
3348 use_int(reg); | |
3349 break; | |
3350 } | |
3351 return reg; | |
3352 } | |
3353 | |
3354 void | |
3355 code_set_fixed_creg(int reg,int mode,int type) { | |
3356 if (type==FLOAT) { | |
3357 #if FLOAT_CODE | |
3358 set_freg(reg,mode); | |
3359 #endif | |
3360 } else if (type==DOUBLE) { | |
3361 #if FLOAT_CODE | |
3362 set_dreg(reg,mode); | |
3363 #endif | |
3364 } else if (type==LONGLONG||type==ULONGLONG) { | |
3365 #if LONGLONG_CODE | |
3366 set_lreg(reg,mode); | |
3367 // use_reg(reg); | |
3368 #endif | |
3369 } else { | |
3370 set_ireg(reg,mode); | |
3371 } | |
3372 } | |
3373 | |
3374 void | |
3375 gen_gdecl(char *n, int gpc) | |
3376 { | |
3377 /* | |
3378 if (stmode!=STATIC) | |
3379 printf(".globl %s\n",n); | |
3380 */ | |
3381 } | |
3382 | |
3383 void | |
3384 align(int t) | |
3385 { | |
3386 int d; | |
3387 switch(t) { | |
3388 case CHAR: case UCHAR: return; | |
3389 case SHORT: case USHORT: d = data_alignment & 1; break; | |
3390 default: d = data_alignment & 3; | |
3391 } | |
3392 if (d) { | |
3393 printf("\t.align 2\n"); | |
3394 data_alignment = 0; | |
3395 } | |
3396 } | |
3397 | |
3398 static void | |
3399 ascii(char *s) | |
3400 { | |
3401 printf("\t.string \""); | |
3402 while(*s) { | |
3403 if (*s=='\n') | |
3404 printf("%cn",92); | |
3405 else if (*s<' ') | |
3406 printf("%c%03o",92,*s); | |
3407 else if (*s=='\\') | |
3408 printf("\\\\"); | |
3409 else if (*s==34) | |
3410 printf("%c%c",92,34); | |
3411 else | |
3412 printf("%c",*s); | |
3413 s++; | |
3414 } | |
3415 printf("\\0%c\n",34); | |
3416 } | |
3417 | |
3418 int | |
3419 emit_string_label() { | |
3420 int lb; | |
3421 | |
3422 lb=fwdlabel(); | |
3423 // should put on different segement | |
3424 cstring_mode(); | |
3425 printf(".LC%d:\n",lb); | |
3426 return lb; | |
3427 } | |
3428 | |
3429 extern void | |
3430 emit_string(char *s,int t) | |
3431 { | |
3432 t = type_value(t); | |
3433 if (car(t)==ARRAY && | |
3434 (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) { | |
3435 ascii(s); | |
3436 } else { | |
3437 int l = emit_string_label(); | |
3438 ascii(s); | |
3439 emit_label(l); | |
3440 } | |
3441 return; | |
3442 } | |
3443 | |
3444 void | |
3445 emit_global(NMTBL *n,int a,int e) | |
3446 { | |
3447 int t = type_value(n->ty); | |
3448 if (e>0 && car(e)==STRING && t>0 && car(t)==ARRAY && | |
3449 (type_value(cadr(t))==CHAR||type_value(cadr(t))==UCHAR)) { | |
3450 cstring_mode(); | |
3451 } else | |
3452 data_mode(n->nm); | |
3453 align(a); | |
3454 if (n && n->sc!=STATIC) | |
3455 printf("\t.globl\t%s\n",n->nm); | |
3456 printf("%s:\n",n->nm); | |
3457 } | |
3458 | |
3459 void | |
3460 emit_space(int sp) | |
3461 { | |
3462 data_mode(0); | |
3463 printf("\t.space\t%d\n",sp); | |
3464 } | |
3465 | |
3466 void | |
3467 emit_char(int d) | |
3468 { | |
3469 data_mode(0); | |
3470 printf("\t.byte %d\n",d); | |
3471 } | |
3472 | |
3473 void | |
3474 emit_short(int d) | |
3475 { | |
3476 data_mode(0); | |
3477 printf("\t.short %d\n",d); | |
3478 } | |
3479 | |
3480 void | |
3481 emit_int(int d) | |
3482 { | |
3483 data_mode(0); | |
3484 align(0); | |
3485 printf("\t.word %d\n",d); | |
3486 } | |
3487 | |
3488 void | |
3489 emit_longlong(int e) | |
3490 { | |
3491 #if LONGLONG_CODE | |
3492 long long ll = lcadr(e); | |
3493 data_mode(0); | |
3494 #if (ENDIAN_L==0) | |
3495 printf("\t.long\t0x%x,0x%x\n",code_l1(ll),code_l2(ll)); | |
3496 #else | |
3497 printf("\t.long\t0x%x,0x%x\n",code_l2(ll),code_l1(ll)); | |
3498 #endif | |
3499 #endif | |
3500 } | |
3501 | |
3502 void | |
3503 emit_double(int e) | |
3504 { | |
3505 #if FLOAT_CODE | |
3506 double d = dcadr(e); | |
3507 data_mode(0); | |
3508 #if (ENDIAN_D==0) | |
3509 printf("\t.long\t0x%x,0x%x\n",code_d1(d),code_d2(d)); | |
3510 #else | |
3511 printf("\t.long\t0x%x,0x%x\n",code_d2(d),code_d1(d)); | |
3512 #endif | |
3513 #endif | |
3514 } | |
3515 | |
3516 void | |
3517 emit_float(int e) | |
3518 { | |
3519 #if FLOAT_CODE | |
3520 float f = dcadr(e); | |
3521 data_mode(0); | |
3522 printf("\t.long\t0x%x\n",*(int *)&f); | |
3523 #endif | |
3524 } | |
3525 | |
3526 void | |
3527 emit_address(char *s,int offset) | |
3528 { | |
3529 data_mode(0); | |
3530 if (offset) | |
3531 printf("\t.word %s+%d\n",s,offset); | |
3532 else | |
3533 printf("\t.word %s\n",s); | |
3534 } | |
3535 | |
3536 void | |
3537 emit_label(int labelno) | |
3538 { | |
3539 data_mode(0); | |
3540 printf("\t.word .L%d\n",labelno); | |
3541 } | |
3542 | |
3543 void | |
3544 emit_data_closing(NMTBL *n) | |
3545 { | |
3546 #ifdef DOT_SIZE | |
3547 int lb; | |
3548 #endif | |
3549 if (mode==GDECL) { | |
3550 data_mode(0); | |
3551 #ifdef DOT_SIZE | |
3552 lb=fwdlabel(); | |
3553 printf(".LC%d:\n",lb); | |
3554 printf("\t.size\t%s,.L%d-%s\n",n->nm,lb,n->nm); | |
3555 #endif | |
3556 } | |
3557 } | |
3558 | |
3559 | |
3560 static void | |
3561 comm(NMTBL *n) | |
3562 { | |
3563 printf(".comm %s,%d @ %d\n",n->nm,size(n->ty), | |
3564 (n->ty==DOUBLE||n->ty==LONGLONG||n->ty==ULONGLONG)?8:4 | |
3565 ); | |
3566 } | |
3567 | |
3568 void | |
3569 global_table(void) | |
3570 { | |
3571 NMTBL *n; | |
3572 int init; | |
3573 init=0; | |
3574 for(n=global_list;n;n=n->next) { | |
3575 if ((n->sc == GVAR) && n->dsp != -1) { | |
3576 /* n->dsp = -1 means initialized global */ | |
3577 if (init==0) { | |
3578 data_mode(0); | |
3579 init=1; | |
3580 } | |
3581 comm(n); | |
3582 } else if ((n->sc==STATIC) && n->dsp != -1) { | |
3583 /* n->dsp = -1 means initialized global */ | |
3584 if (is_code(n)||is_function(n)) continue; | |
3585 if (init==0) { | |
3586 data_mode(0); | |
3587 init=1; | |
3588 } | |
3589 // printf(".local %s\n",n->nm); | |
3590 comm(n); | |
3591 } | |
3592 } | |
3593 } | |
3594 | |
3595 void | |
3596 local_table(void) | |
3597 { | |
3598 NMTBL *n; | |
3599 int init; | |
3600 free_glist3_a(prev_const_list); prev_const_list = 0; | |
3601 const_list_table(); | |
3602 | |
3603 init=0; | |
3604 /* static local variables */ | |
3605 for(n=local_static_list;n;n=n->next) { | |
3606 if (n->sc == STATIC) { | |
3607 if (n->dsp != -1) { /* initialized static */ | |
3608 if (init==0) { | |
3609 data_mode(0); | |
3610 init=1; | |
3611 } | |
3612 comm(n); | |
3613 } | |
3614 } | |
3615 } | |
3616 text_mode(2); | |
3617 } | |
3618 | |
3619 void | |
3620 cstring_mode(int align) | |
3621 { | |
3622 if (output_mode!=RODATA_EMIT_MODE) { | |
3623 printf(".section\t.rodata\n\t.align 2\n"); | |
3624 output_mode = RODATA_EMIT_MODE; | |
3625 } | |
3626 } | |
3627 | |
3628 void | |
3629 text_mode(int align) | |
3630 { | |
3631 if (output_mode!=TEXT_EMIT_MODE) { | |
3632 printf(".text\n"); | |
3633 if (align) printf("\t.align %d\n",align); | |
3634 output_mode = TEXT_EMIT_MODE; | |
3635 } | |
3636 } | |
3637 | |
3638 void | |
3639 data_mode(char *name) | |
3640 { | |
3641 if (output_mode!=DATA_EMIT_MODE) { | |
3642 printf(".data\n"); | |
3643 output_mode = DATA_EMIT_MODE; | |
3644 } | |
3645 if (name) | |
3646 printf("\t.type\t%s,object\n",name); | |
3647 } | |
3648 | |
3649 #define lib_args(max) if (max_func_args<max) max_func_args=max | |
3650 | |
3651 #if LONGLONG_CODE||FLOAT_CODE | |
3652 static void | |
3653 extern_conv(char *conv) | |
3654 { | |
3655 code_save_stacks(); | |
3656 clear_ptr_cache(); | |
3657 extern_define(conv,0,FUNCTION,1); | |
3658 printf("\tbl\t%s\n",conv); | |
3659 lib_args(16); | |
3660 } | |
3661 #endif | |
3662 | |
3663 static void | |
3664 code_int_lib(char *lib,int reg,int oreg) | |
3665 { | |
3666 int g; | |
3667 code_save_stacks(); | |
3668 clear_ptr_cache(); | |
3669 g = list3(REGISTER_OPERAND,0,reg); | |
3670 g = list3(REGISTER_OPERAND_1,g,oreg); | |
3671 parallel_rassign(g); | |
3672 extern_define(lib,0,FUNCTION,1); | |
3673 printf("\tbl\t%s\n",lib); | |
3674 lib_args(16); | |
3675 set_ireg(RET_REGISTER,0); | |
3676 if (reg!=RET_REGISTER) { | |
3677 code_register(RET_REGISTER,reg); | |
3678 } | |
3679 } | |
3680 | |
3681 #if FLOAT_CODE | |
3682 | |
3683 /* floating point */ | |
3684 | |
3685 #define set_double(freg) if (regs[freg]) {regs[freg]=USING_DREG;} | |
3686 #define set_float(freg) if (regs[freg]) {regs[freg]=USING_DREG;} | |
3687 | |
3688 void | |
3689 code_cmp_dregister(int e2,int d,int label,int cond) | |
3690 { | |
3691 char *frn; | |
3692 use_float(d,e2); | |
3693 | |
3694 frn = register_name(e2); | |
3695 printf("\tcmf\t%s, #0\n",frn); | |
3696 jcond(label,cond); | |
3697 return; | |
3698 } | |
3699 | |
3700 static char * | |
3701 movef(int d) | |
3702 { | |
3703 return d?"mvfd":"mvfs"; | |
3704 } | |
3705 | |
3706 static char * | |
3707 fload(int d) { return d?"ldfd":"ldfs"; } | |
3708 | |
3709 static char * | |
3710 fstore(int d) { return d?"stfd":"stfs"; } | |
3711 | |
3712 | |
3713 void | |
3714 code_dregister(int e2,int freg,int d) | |
3715 { | |
3716 use_float(d,freg); | |
3717 if (freg!=e2) { | |
3718 if (is_int_reg(e2)) error(-1); | |
3719 printf("\t%s\t%s, %s\n",movef(d), | |
3720 register_name(freg),register_name(e2)); | |
3721 } | |
3722 } | |
3723 | |
3724 void | |
3725 code_dassign_gvar(int e2,int freg,int d) | |
3726 { | |
3727 use_float(d,freg); | |
3728 code_ldf(fstore(d),register_name(freg),cadr(e2), | |
3729 get_ptr_cache((NMTBL*)caddr(e2))," @ float"); | |
3730 } | |
3731 | |
3732 void | |
3733 code_dassign_lvar(int e2,int freg,int d) | |
3734 { | |
3735 use_float(d,freg); | |
3736 lvar_intro(e2); | |
3737 printf("\t%s\t%s, ",fstore(d),register_name(freg)); | |
3738 lvar(e2,"@ float"); | |
3739 } | |
3740 | |
3741 void | |
3742 code_dassign(int e2,int freg,int d) | |
3743 { | |
3744 use_float(d,freg); | |
3745 printf("\t%s\t%s, [%s, #0] @ float\n",fstore(d), | |
3746 register_name(freg),register_name(e2)); | |
3747 } | |
3748 | |
3749 void | |
3750 code_dassign_dregister(int e2,int d,int freg) { | |
3751 use_float(d,freg); | |
3752 if (e2!=freg) { | |
3753 printf("\t%s\t%s, %s\n",movef(d), | |
3754 register_name(e2),register_name(freg)); | |
3755 } | |
3756 } | |
3757 | |
3758 static double d0 = 1.0; | |
3759 | |
3760 int | |
3761 code_d1(double d) | |
3762 { | |
3763 int *i = (int *)&d0; int *j = (int *)&d; | |
3764 return (i[1] == 0x3ff00000)?j[0]:j[1]; | |
3765 } | |
3766 | |
3767 int | |
3768 code_d2(double d) | |
3769 { | |
3770 int *i = (int *)&d0; int *j = (int *)&d; | |
3771 return (i[1] == 0x3ff00000)?j[1]:j[0]; | |
3772 } | |
3773 | |
3774 int | |
3775 code_f(double d) | |
3776 { | |
3777 float f = d; | |
3778 int *j = (int *)&f; | |
3779 return *j; | |
3780 } | |
3781 | |
3782 static void | |
3783 dconst(int l,int h,double value) | |
3784 { | |
3785 #if ENDIAN_D==0 | |
3786 code_const(code_d1(value),l); | |
3787 code_const(code_d2(value),h); | |
3788 #else | |
3789 code_const(code_d1(value),h); | |
3790 code_const(code_d2(value),l); | |
3791 #endif | |
3792 } | |
3793 | |
3794 static void | |
3795 fconst(int reg,double value) | |
3796 { | |
3797 float f = value; | |
3798 code_const(*((int*)&f),reg); | |
3799 } | |
3800 | |
3801 void | |
3802 code_dconst(int e2,int freg,int d) | |
3803 { | |
3804 double value = dcadr(e2); | |
3805 float f = value; | |
3806 char *frn; | |
3807 int label,disp; | |
3808 | |
3809 use_float(d,freg); | |
3810 frn = register_name(freg); | |
3811 if (value==0 || value==1 || value==10) { | |
3812 printf("\t%s\t%s, #%d\n",movef(d),frn,(int)value); | |
3813 } else if (value==-1 || value==-10) { | |
3814 printf("\t%s\t%s, #%d\n",d?"mnfd":"mnfs",frn,(int)-value); | |
3815 } else if (d) { | |
3816 #if ENDIAN_D==0 | |
3817 disp = search_double_const(DCONST, | |
3818 code_d1(value),code_d2(value),&label); | |
3819 #else | |
3820 disp = search_double_const(DCONST, | |
3821 code_d2(value),code_d1(value),&label); | |
3822 #endif | |
3823 printf("\tldfd\t%s, .LC%d+%d\n",frn,label,disp); | |
3824 } else { | |
3825 //disp = search_const(CONST,*((int*)&f),&label); | |
3826 printf("\tldfs\t%s, .LC%d+%d\n",frn,label,disp); | |
3827 } | |
3828 } | |
3829 | |
3830 | |
3831 void | |
3832 code_builtin_fabsf(int e) | |
3833 { | |
3834 } | |
3835 void | |
3836 code_builtin_fabs(int e) | |
3837 { | |
3838 } | |
3839 void | |
3840 code_builtin_inff() | |
3841 { | |
3842 } | |
3843 void | |
3844 code_builtin_inf(int op) | |
3845 { | |
3846 } | |
3847 | |
3848 void | |
3849 code_dneg(int freg,int d) | |
3850 { | |
3851 char *frn; | |
3852 use_float(d,freg); | |
3853 frn = register_name(freg); | |
3854 printf("\t%s\t%s, %s\n",d?"mnfd":"mnfs",frn,frn); | |
3855 } | |
3856 | |
3857 void | |
3858 code_d2i0(int reg,int d) | |
3859 { | |
3860 int lreg; | |
3861 use_float(d,reg); | |
3862 lreg = get_register(); | |
3863 printf("\tfixz\t%s, %s\n",register_name(lreg),register_name(reg)); | |
3864 set_ireg(lreg,0); | |
3865 return; | |
3866 } | |
3867 | |
3868 void | |
3869 code_i2d0(int reg,int d) | |
3870 { | |
3871 int lreg; | |
3872 use_int(reg); | |
3873 lreg = get_dregister(1); | |
3874 printf("\tflt%c\t%s, %s\n",dsuffix(d), | |
3875 register_name(lreg),register_name(reg)); | |
3876 set_dreg(lreg,0); | |
3877 return; | |
3878 } | |
3879 | |
3880 void | |
3881 code_d2u0(int reg,int d) | |
3882 { | |
3883 int lreg,reg0; | |
3884 char *lrn,*frn,*crn; | |
3885 // u = (d>2.1e9)?((int)(d-2.1e9)^2147483648):(int)d | |
3886 use_float(1,reg); | |
3887 frn = register_name(reg); | |
3888 if (!d) printf("\tmvfd\t%s, %s\n",frn,frn); | |
3889 emit_dpush(1); | |
3890 code_dconst(dlist2(DCONST,2.147483648e9),USE_CREG,1); | |
3891 lrn = register_name(lreg = emit_dpop(d)); | |
3892 frn = register_name(freg); | |
3893 set_ireg(reg0=get_register(),0); | |
3894 crn = register_name(reg0); | |
3895 printf("\tcmfe\t%s, %s\n",lrn,frn); | |
3896 printf("\tbge\t1f\n"); | |
3897 printf("\tfixz\t%s, %s\n",crn,lrn); | |
3898 printf("\tb\t2f\n"); | |
3899 printf("1:\n"); | |
3900 printf("\tsufd\t%s, %s, %s\n",lrn,lrn,frn); | |
3901 printf("\tfixz\t%s, %s\n",crn,lrn); | |
3902 printf("\teor\t%s, %s, #-2147483648\n",crn,crn); | |
3903 printf("2:\n"); | |
3904 emit_dpop_free(lreg,d); | |
3905 return; | |
3906 } | |
3907 | |
3908 void | |
3909 code_u2d0(int reg,int d) | |
3910 { | |
3911 int tmp,freg1; | |
3912 char *crn,*frn,*lrn; | |
3913 use_int(reg); | |
3914 crn = register_name(reg); | |
3915 set_dreg(reg=get_dregister(1),0); | |
3916 frn = register_name(reg); | |
3917 printf("\tfltd\t%s, %s\n",frn,crn); | |
3918 printf("\tcmp\t%s, #0\n",crn); | |
3919 printf("\tbge\t1f\n"); | |
3920 freg1 = get_dregister(1); | |
3921 code_dconst(dlist2(DCONST,4.29496729600000000000e9),freg1,1); | |
3922 frn = register_name(creg); | |
3923 lrn = register_name(freg1); | |
3924 printf("\tadfd\t%s, %s, %s\n",frn,frn,lrn); | |
3925 printf("1:\n"); | |
3926 if (!d) | |
3927 printf("\tmvfs\t%s, %s\n",frn,frn); | |
3928 free_register(freg1); | |
3929 return; | |
3930 } | |
3931 | |
3932 void | |
3933 code_d2f(int reg) { | |
3934 char *frn; | |
3935 frn = register_name(freg); | |
3936 printf("\tmvfs\t%s,%s\n",frn,frn); | |
3937 return; | |
3938 } | |
3939 | |
3940 void | |
3941 code_f2d(int reg) { | |
3942 char *frn; | |
3943 frn = register_name(freg); | |
3944 printf("\tmvfd\t%s, %s\n",frn,frn); | |
3945 return; | |
3946 } | |
3947 | |
3948 void | |
3949 code_d2i(int reg) { | |
3950 code_d2i0(reg,1); | |
3951 } | |
3952 | |
3953 void | |
3954 code_d2u(int reg) { | |
3955 code_d2u0(reg,1); | |
3956 } | |
3957 | |
3958 void | |
3959 code_f2i(int reg) { | |
3960 code_d2i0(reg,0); | |
3961 } | |
3962 | |
3963 void | |
3964 code_f2u(int reg) { | |
3965 code_d2u0(reg,0); | |
3966 } | |
3967 | |
3968 void | |
3969 code_i2d(int reg) { | |
3970 code_i2d0(reg,1); | |
3971 } | |
3972 | |
3973 void | |
3974 code_i2f(int reg) { | |
3975 code_i2d0(reg,0); | |
3976 } | |
3977 | |
3978 void | |
3979 code_u2d(int reg) { | |
3980 code_u2d0(reg,1); | |
3981 } | |
3982 | |
3983 void | |
3984 code_u2f(int reg) { | |
3985 code_u2d0(reg,0); | |
3986 } | |
3987 | |
3988 void | |
3989 code_drgvar(int e2,int d,int freg) | |
3990 { | |
3991 use_float(d,freg); | |
3992 code_ldf(fload(d),register_name(freg),cadr(e2), | |
3993 get_ptr_cache((NMTBL*)caddr(e2)),""); | |
3994 } | |
3995 | |
3996 | |
3997 void | |
3998 code_drlvar(int e2,int d,int freg) | |
3999 { | |
4000 use_float(d,freg); | |
4001 lvar_intro(e2); | |
4002 printf("\t%s\t%s, ",fload(d),register_name(freg)); | |
4003 lvar(e2,d?"@ double":"@ float"); | |
4004 } | |
4005 | |
4006 void | |
4007 code_cmp_drgvar(int e2,int reg,int d,int label,int cond) | |
4008 { | |
4009 use_float(d,reg); | |
4010 code_drgvar(e2,d,reg); | |
4011 code_cmp_dregister(reg,d,label,cond); | |
4012 } | |
4013 | |
4014 void | |
4015 code_cmp_drlvar(int e2,int reg,int d,int label,int cond) | |
4016 { | |
4017 use_float(d,reg); | |
4018 code_drlvar(e2,d,reg); | |
4019 code_cmp_dregister(reg,d,label,cond); | |
4020 } | |
4021 | |
4022 static void | |
4023 code_double_lib(char *lib,int to,int reg,int oreg) | |
4024 { | |
4025 code_save_stacks(); | |
4026 clear_ptr_cache(); | |
4027 set_operands(reg,reg,oreg,oreg); | |
4028 extern_conv(lib); | |
4029 set_dreg(RET_DREGISTER,0); | |
4030 if (to!=RET_DREGISTER) { | |
4031 lmove(to,RET_DREGISTER); | |
4032 } | |
4033 } | |
4034 | |
4035 static void | |
4036 code_double_lib_c(char *lib,int from,int to,double value) | |
4037 { | |
4038 code_save_stacks(); | |
4039 clear_ptr_cache(); | |
4040 set_dreg_operand(from,1); | |
4041 dconst(DREGISTER_OPERAND_1_L,DREGISTER_OPERAND_1_H,value); | |
4042 extern_conv(lib); | |
4043 set_dreg(RET_DREGISTER,0); | |
4044 if (to!=RET_DREGISTER) { | |
4045 lmove(to,RET_DREGISTER); | |
4046 } | |
4047 } | |
4048 | |
4049 static void | |
4050 code_float_lib(char *lib,int to,int reg,int oreg) | |
4051 { | |
4052 code_save_stacks(); | |
4053 clear_ptr_cache(); | |
4054 if (reg!=FREGISTER_OPERAND) code_dregister(FREGISTER_OPERAND,reg,0); | |
4055 if (to!=FREGISTER_OPERAND_1) code_dregister(FREGISTER_OPERAND_1,to,0); | |
4056 extern_conv(lib); | |
4057 set_freg(RET_FREGISTER,0); | |
4058 if (to!=RET_FREGISTER) { | |
4059 code_dregister(to,RET_FREGISTER,0); | |
4060 } | |
4061 } | |
4062 | |
4063 static void | |
4064 code_float_lib_c(char *lib,int from,int to,double value) | |
4065 { | |
4066 code_save_stacks(); | |
4067 clear_ptr_cache(); | |
4068 set_dreg_operand(from,1); | |
4069 fconst(FREGISTER_OPERAND_1,value); | |
4070 extern_conv(lib); | |
4071 set_freg(RET_FREGISTER,0); | |
4072 if (to!=RET_FREGISTER) { | |
4073 code_dregister(to,RET_FREGISTER,0); | |
4074 } | |
4075 } | |
4076 | |
4077 | |
4078 void | |
4079 dtosop(int op,int reg,int e1) | |
4080 { | |
4081 char *opn=""; | |
4082 | |
4083 char *grn,*frn; | |
4084 int d; | |
4085 int cmp=0; | |
4086 | |
4087 | |
4088 d=(op<FOP); | |
4089 use_float(d,reg); | |
4090 switch(op) { | |
4091 case DADD: opn="adfd"; break; | |
4092 case DSUB: opn="sufd"; break; | |
4093 case DDIV: opn="fdvd"; break; | |
4094 case DMUL: opn="fmld"; break; | |
4095 case DCMPGE: | |
4096 case DCMP: opn="cmfe"; cmp=1; break; | |
4097 case FADD: opn="adfs"; break; | |
4098 case FSUB: opn="sufs"; break; | |
4099 case FDIV: opn="fdvs"; break; | |
4100 case FMUL: opn="fmls"; break; | |
4101 case FCMPGE: | |
4102 case FCMP: opn="cmfe"; cmp=1; break; | |
4103 default: | |
4104 error(-1); return; | |
4105 } | |
4106 grn = register_name(e1); | |
4107 frn = register_name(reg); | |
4108 if (cmp) { | |
4109 printf("\t%s\t%s, %s\n",opn,grn,frn); | |
4110 } else { | |
4111 printf("\t%s\t%s, %s, %s\n",opn,frn,frn,grn); | |
4112 } | |
4113 } | |
4114 | |
4115 | |
4116 void | |
4117 code_dassop(int op,int reg,int d) { | |
4118 /* we have lvalue in creg, applied floating value is in freg */ | |
4119 // (*creg) op = pop() | |
4120 int xreg; | |
4121 char *crn; | |
4122 char *frn; | |
4123 | |
4124 | |
4125 | |
4126 xreg=emit_dpop(d); | |
4127 crn=register_name(ireg); | |
4128 use_float(d,reg); | |
4129 frn =register_name(reg); | |
4130 | |
4131 code_ldf(fload(d),register_name(freg),0,ireg,""); | |
4132 dtosop(op,reg,xreg); | |
4133 code_ldf(fstore(d),register_name(freg),0,ireg,""); | |
4134 emit_dpop_free(xreg,d); | |
4135 } | |
4136 | |
4137 void | |
4138 code_register_dassop(int reg,int op,int d) { | |
4139 // reg op= dpop() | |
4140 int xreg; | |
4141 xreg=emit_dpop(d); | |
4142 dtosop(op,reg,xreg); | |
4143 emit_dpop_free(xreg,d); | |
4144 } | |
4145 | |
4146 static int | |
4147 code_dload_1(int d) | |
4148 { | |
4149 int g = get_dregister(d); | |
4150 printf("\tmvf%c\t%s,#1\n",dsuffix(d),register_name(g)); | |
4151 return g; | |
4152 } | |
4153 | |
4154 | |
4155 void | |
4156 code_dpreinc(int e1,int e2,int d,int reg) { | |
4157 char *frn; | |
4158 char *crn; | |
4159 int g,reg0; | |
4160 char *grn; | |
4161 int dir=caddr(e1); | |
4162 | |
4163 if (car(e2)==DREGISTER||car(e2)==FREGISTER) { | |
4164 crn=register_name(cadr(e2)); | |
4165 grn=register_name(g=code_dload_1(d)); | |
4166 if (reg==USE_CREG) { | |
4167 reg=get_dregister(d); if (!reg) error(-1); | |
4168 if (d) set_dreg(reg,0); else set_freg(reg,0); | |
4169 } | |
4170 frn=register_name(reg); | |
4171 printf("\t%s%c\t%s, %s, %s\n", | |
4172 dir>0?"adf":"suf",dsuffix(d), | |
4173 crn,crn,grn); | |
4174 if (use && reg!=cadr(e2)) { | |
4175 printf("\tmvf%c\t%s, %s\n",dsuffix(d),frn,crn); | |
4176 } | |
4177 } else { | |
4178 g_expr(e2); | |
4179 if (!is_int_reg(creg)) error(-1); | |
4180 reg0 = ireg; | |
4181 if (reg==USE_CREG) { | |
4182 reg=get_dregister(d); if (!reg) error(-1); | |
4183 if (d) set_dreg(reg,0); else set_freg(reg,0); | |
4184 } | |
4185 grn = register_name(g = code_dload_1(d)); | |
4186 frn=register_name(reg); | |
4187 code_ldf(fload(d),frn,0,reg0,""); | |
4188 printf("\t%s%c\t%s, %s, %s\n", | |
4189 dir>0?"adf":"suf",dsuffix(d), | |
4190 frn,frn,grn); | |
4191 code_ldf(fstore(d),frn,0,reg0,""); | |
4192 } | |
4193 free_register(g); | |
4194 } | |
4195 | |
4196 void | |
4197 code_dpostinc(int e1,int e2,int d,int reg) { | |
4198 char *frn; | |
4199 char *crn; | |
4200 int g,reg0; | |
4201 char *grn; | |
4202 int dir=caddr(e1); | |
4203 | |
4204 if (car(e2)==DREGISTER||car(e2)==FREGISTER) { | |
4205 crn=register_name(cadr(e2)); | |
4206 grn=register_name(g=code_dload_1(d)); | |
4207 if (reg==USE_CREG) { | |
4208 reg=get_dregister(d); if (!reg) error(-1); | |
4209 set_freg(reg,0); | |
4210 } | |
4211 frn=register_name(reg); | |
4212 if (use && reg!=cadr(e2)) { | |
4213 printf("\tmvf%c\t%s, %s\n",dsuffix(d),frn,crn); | |
4214 } | |
4215 printf("\t%s%c\t%s,%s,%s\n",dir>0?"adf":"suf", | |
4216 dsuffix(d),crn,crn,grn); | |
4217 } else { | |
4218 g_expr(e2); | |
4219 if (!is_int_reg(creg)) error(-1); | |
4220 crn=register_name(reg0=ireg); | |
4221 if (reg==USE_CREG) { | |
4222 reg=get_dregister(d); if (!reg) error(-1); | |
4223 set_freg(reg,0); | |
4224 } | |
4225 frn=register_name(reg); | |
4226 grn = register_name(g = code_dload_1(d)); | |
4227 code_ldf(fload(d),frn,0,reg0,""); | |
4228 printf("\t%s%c\t%s, %s, %s\n", | |
4229 dir>0?"adf":"suf",dsuffix(d), | |
4230 grn,frn,grn); | |
4231 code_ldf(fstore(d),grn,0,reg0,""); | |
4232 } | |
4233 free_register(g); | |
4234 } | |
4235 | |
4236 | |
4237 int | |
4238 drexpr(int e1, int e2,int l1, int op,int cond) | |
4239 { | |
4240 int op1=0; | |
4241 char *opn=0; | |
4242 if (!cond) { | |
4243 switch(op) { | |
4244 case FOP+GT: | |
4245 return drexpr(e2,e1,l1,FOP+GE,1); | |
4246 case FOP+GE: | |
4247 return drexpr(e2,e1,l1,FOP+GT,1); | |
4248 case FOP+EQ: | |
4249 op=FOP+NEQ; break; | |
4250 case FOP+NEQ: | |
4251 op=FOP+EQ; break; | |
4252 case DOP+GT: | |
4253 return drexpr(e2,e1,l1,DOP+GE,1); | |
4254 case DOP+GE: | |
4255 return drexpr(e2,e1,l1,DOP+GT,1); | |
4256 case DOP+EQ: | |
4257 op=DOP+NEQ; break; | |
4258 case DOP+NEQ: | |
4259 op=DOP+EQ; break; | |
4260 } | |
4261 } | |
4262 switch(op) { | |
4263 case FOP+GT: op1=FOP+CMP; opn = "bgt"; break; | |
4264 case FOP+GE: op1=FOP+CMPGE; opn = "bge"; break; | |
4265 case FOP+EQ: op1=FOP+CMP; opn = "beq"; break; | |
4266 case FOP+NEQ: op1=FOP+CMP; opn = "bne"; break; | |
4267 case DOP+GT: op1=DOP+CMP; opn = "bgt"; break; | |
4268 case DOP+GE: op1=DOP+CMPGE; opn = "bge"; break; | |
4269 case DOP+EQ: op1=DOP+CMP; opn = "beq"; break; | |
4270 case DOP+NEQ: op1=DOP+CMP; opn = "bne"; break; | |
4271 default: error(-1); | |
4272 } | |
4273 g_expr(list3(op1,e2,e1)); | |
4274 printf("\t%s\t.L%d\n",opn,l1); | |
4275 return l1; | |
4276 } | |
4277 | |
4278 int emit_dpop(int d) | |
4279 { | |
4280 int xreg,reg; | |
4281 xreg=pop_fregister(); | |
4282 if (xreg<= -REG_LVAR_OFFSET) { | |
4283 reg = get_dregister(d); | |
4284 code_drlvar(REG_LVAR_OFFSET+xreg,1,reg); | |
4285 free_lvar(REG_LVAR_OFFSET+xreg); | |
4286 xreg=reg; | |
4287 } | |
4288 return xreg; | |
4289 } | |
4290 | |
4291 | |
4292 void | |
4293 emit_dpop_free(int e1,int d) | |
4294 { | |
4295 free_register(e1); | |
4296 } | |
4297 | |
4298 void | |
4299 emit_dpush(int d) | |
4300 { | |
4301 int new_reg; | |
4302 if (!is_float_reg(creg)) error(-1); | |
4303 if (reg_sp>MAX_MAX) error(-1); | |
4304 new_reg = get_dregister(d); /* ?????????? */ | |
4305 reg_stack[reg_sp++] = freg; /* push ???????????????? */ | |
4306 creg = freg = new_reg; | |
4307 } | |
4308 | |
4309 #endif | |
4310 | |
4311 #if LONGLONG_CODE | |
4312 | |
4313 | |
4314 /* 64bit int part */ | |
4315 | |
4316 int | |
4317 lrexpr_bool(int e1, int reg) | |
4318 { | |
4319 return 0; | |
4320 } | |
4321 | |
4322 int | |
4323 lrexpr(int e1, int e2,int l1, int op,int cond) | |
4324 { | |
4325 int reg,regh,regl,e3h,e3l; | |
4326 int e3,l2; | |
4327 g_expr(e1); | |
4328 emit_lpush(); | |
4329 g_expr(e2); | |
4330 e3 = emit_lpop(); | |
4331 if (!is_longlong_reg(creg)) error(-1); | |
4332 reg = lreg; | |
4333 l2 = fwdlabel(); | |
4334 regh = reg; regl = reg; | |
4335 e3h = e3; e3l = e3; | |
4336 switch(op) { | |
4337 case LOP+GT: case LOP+GE: | |
4338 pcond(GT, regh,e3h,0,1,cond?l1:l2,COND_BRANCH); | |
4339 pcond(NEQ, regh,e3h,0,1,cond?l2:l1,COND_BRANCH); | |
4340 break; | |
4341 case LOP+UGT: case LOP+UGE: | |
4342 pcond(UGT, regh,e3h,0,1,cond?l1:l2,COND_BRANCH); | |
4343 pcond(NEQ, regh,e3h,0,1,cond?l2:l1,COND_BRANCH); | |
4344 break; | |
4345 case LOP+EQ: | |
4346 pcond(EQ, regh,e3h,0,0,cond?l2:l1,COND_BRANCH); | |
4347 break; | |
4348 case LOP+NEQ: | |
4349 pcond(EQ, regh,e3h,0,0,cond?l1:l2,COND_BRANCH); | |
4350 break; | |
4351 default: | |
4352 error(-1); | |
4353 } | |
4354 pcond(op%LOP,regl,e3l,0,cond,l1,COND_BRANCH); | |
4355 fwddef(l2); | |
4356 emit_lpop_free(e3); | |
4357 return l1; | |
4358 } | |
4359 | |
4360 void | |
4361 code_cmp_lregister(int reg,int label,int cond) | |
4362 { | |
4363 use_longlong(reg); | |
4364 printf("\torr\t%s, %s, %s\n", | |
4365 lregister_name_low(reg), | |
4366 lregister_name_low(reg), | |
4367 lregister_name_high(reg)); | |
4368 code_cmp_register((reg),label,cond); | |
4369 } | |
4370 | |
4371 void | |
4372 code_cmp_lrgvar(int e1,int creg,int label,int cond) | |
4373 { | |
4374 use_longlong(creg); | |
4375 code_lrgvar(e1,creg); | |
4376 code_cmp_lregister(creg,label,cond); | |
4377 } | |
4378 | |
4379 void | |
4380 code_cmp_lrlvar(int e1,int creg,int label,int cond) | |
4381 { | |
4382 use_longlong(creg); | |
4383 code_lrlvar(e1,creg); | |
4384 code_cmp_lregister(creg,label,cond); | |
4385 } | |
4386 | |
4387 #endif | |
4388 #if LONGLONG_CODE||FLOAT_CODE | |
4389 | |
4390 int | |
4391 emit_lpop() | |
4392 { | |
4393 int xreg,reg; | |
4394 xreg=reg_stack[--reg_sp]; | |
4395 if (xreg<= -REG_LVAR_OFFSET) { | |
4396 reg = get_lregister(); | |
4397 code_lrlvar(REG_LVAR_OFFSET+xreg,reg); | |
4398 free_lvar(REG_LVAR_OFFSET+xreg); | |
4399 xreg = reg; | |
4400 } | |
4401 return xreg; | |
4402 } | |
4403 | |
4404 void | |
4405 code_lregister(int e2,int reg) | |
4406 { | |
4407 use_longlong(reg); | |
4408 if (reg!=e2) { | |
4409 lmove(reg,e2); | |
4410 } | |
4411 } | |
4412 | |
4413 | |
4414 void | |
4415 code_lassign(int e2,int creg) | |
4416 { | |
4417 use_longlong(creg); | |
4418 lstore(e2,creg); | |
4419 } | |
4420 | |
4421 void | |
4422 code_lassign_gvar(int e2,int creg) | |
4423 { | |
4424 int r; | |
4425 use_longlong(creg); | |
4426 r = get_ptr_cache((NMTBL*)caddr(e2)); | |
4427 #if ENDIAN_L==0 | |
4428 code_ldf(cstore(0),lregister_name_low(creg),cadr(e2),r,""); | |
4429 code_ldf(cstore(0),lregister_name_high(creg),cadr(e2)+SIZE_OF_INT,r,""); | |
4430 #else | |
4431 code_ldf(cstore(0),lregister_name_high(creg),cadr(e2),r,""); | |
4432 code_ldf(cstore(0),lregister_name_low(creg),cadr(e2)+SIZE_OF_INT,r,""); | |
4433 #endif | |
4434 } | |
4435 | |
4436 void | |
4437 code_lassign_lvar(int e2,int creg) | |
4438 { | |
4439 char *crn_h; | |
4440 char *crn_l; | |
4441 | |
4442 use_longlong(creg); | |
4443 crn_h = lregister_name_high(creg); | |
4444 crn_l = lregister_name_low(creg); | |
4445 lvar_intro(e2); | |
4446 #if ENDIAN_L==0 | |
4447 printf("\tstr\t%s, ",crn_l);lvar(e2,""); | |
4448 printf("\tstr\t%s, ",crn_h);lvar(e2+SIZE_OF_INT,""); | |
4449 #else | |
4450 printf("\tstr\t%s, ",crn_h);lvar(e2,""); | |
4451 printf("\tstr\t%s, ",crn_l);lvar(e2+SIZE_OF_INT,""); | |
4452 #endif | |
4453 } | |
4454 | |
4455 void | |
4456 code_lassign_lregister(int e2,int reg) | |
4457 { | |
4458 use_longlong(reg); | |
4459 if (e2!=reg) { | |
4460 lmove(e2,reg); | |
4461 } | |
4462 } | |
4463 | |
4464 void | |
4465 emit_lpop_free(int xreg) | |
4466 { | |
4467 if (xreg>=0) | |
4468 free_register(xreg); | |
4469 } | |
4470 | |
4471 void | |
4472 emit_lpush() | |
4473 { | |
4474 int new_reg; | |
4475 if (!is_longlong_reg(creg)) error(-1); | |
4476 if (reg_sp>MAX_MAX) error(-1); | |
4477 new_reg = get_lregister(); /* ??????????(?) */ | |
4478 reg_stack[reg_sp++] = creg; /* push ???????????????? */ | |
4479 lreg = creg = new_reg; | |
4480 } | |
4481 | |
4482 void | |
4483 code_lrgvar(int e1,int creg) | |
4484 { | |
4485 int r; | |
4486 char *crn_h; | |
4487 char *crn_l; | |
4488 use_longlong(creg); | |
4489 crn_h = lregister_name_high(creg); | |
4490 crn_l = lregister_name_low(creg); | |
4491 r = get_ptr_cache((NMTBL*)caddr(e1)); | |
4492 #if ENDIAN_L==0 | |
4493 code_ldf("ldr",crn_l,cadr(e1),r,""); | |
4494 code_ldf("ldr",crn_h,cadr(e1)+SIZE_OF_INT,r,""); | |
4495 #else | |
4496 code_ldf("ldr",crn_h,cadr(e1),r,""); | |
4497 code_ldf("ldr",crn_l,cadr(e1)+SIZE_OF_INT,r,""); | |
4498 #endif | |
4499 } | |
4500 | |
4501 void | |
4502 code_lrlvar(int e1,int creg) | |
4503 { | |
4504 char *crn_h; | |
4505 char *crn_l; | |
4506 use_longlong(creg); | |
4507 crn_h = lregister_name_high(creg); | |
4508 crn_l = lregister_name_low(creg); | |
4509 lvar_intro(e1); | |
4510 printf("\tlqd\t%s, ",crn_l); lvar(e1,""); | |
4511 printf("\tlqd\t%s, ",crn_h); lvar(e1+SIZE_OF_INT,""); | |
4512 } | |
4513 | |
4514 #endif | |
4515 #if LONGLONG_CODE | |
4516 | |
4517 static long long ll0 = 1LL; | |
4518 | |
4519 static int | |
4520 code_l1(long long d) | |
4521 { | |
4522 int *i = (int *)&ll0; int *j = (int *)&d; | |
4523 return (i[1] == 1)?j[1]:j[0]; | |
4524 } | |
4525 | |
4526 static int | |
4527 code_l2(long long d) | |
4528 { | |
4529 int *i = (int *)&ll0; int *j = (int *)&d; | |
4530 return (i[1] == 1)?j[0]:j[1]; | |
4531 } | |
4532 | |
4533 void | |
4534 code_lconst(int e1,int creg) | |
4535 { | |
4536 use_longlong(creg); | |
4537 #if ENDIAN_L==0 | |
4538 code_const(code_l1(lcadr(e1)),(creg)); | |
4539 code_const(code_l2(lcadr(e1)),(creg)); | |
4540 #else | |
4541 code_const(code_l1(lcadr(e1)),(creg)); | |
4542 code_const(code_l2(lcadr(e1)),(creg)); | |
4543 #endif | |
4544 } | |
4545 | |
4546 void | |
4547 code_lneg(int creg) | |
4548 { | |
4549 | |
4550 char *rh,*rl; | |
4551 use_longlong(creg); | |
4552 rl=lregister_name_low(creg); | |
4553 rh=lregister_name_high(creg); | |
4554 printf("\trsbs\t%s, %s, #0\n",rl,rl); | |
4555 printf("\trsc\t%s, %s, #0\n",rh,rh); | |
4556 } | |
4557 | |
4558 static void | |
4559 code_longlong_lib(char *lib,int reg,int oreg) | |
4560 { | |
4561 code_save_stacks(); | |
4562 clear_ptr_cache(); | |
4563 set_operands((reg),(reg),(oreg),(oreg)); | |
4564 extern_conv(lib); | |
4565 // set_lreg(RET_LREGISTER,0); | |
4566 } | |
4567 | |
4568 #define check_lreg(reg) lmove(reg,RET_LREGISTER) | |
4569 | |
4570 void | |
4571 ltosop(int op,int reg,int oreg) | |
4572 { | |
4573 int dx = -1; | |
4574 int ox = -1; | |
4575 char *orn_h,*crn_h; | |
4576 char *orn_l,*crn_l; | |
4577 | |
4578 // reg = reg op oreg | |
4579 | |
4580 use_longlong(reg); | |
4581 if(oreg==-1) { | |
4582 error(-1); | |
4583 } else if (oreg<= -REG_LVAR_OFFSET) { | |
4584 ox = get_lregister(); if (ox<0) error(-1); | |
4585 use_reg(ox); | |
4586 code_rlvar(oreg+REG_LVAR_OFFSET,ox); | |
4587 oreg = ox; | |
4588 } | |
4589 | |
4590 switch(op) { | |
4591 case LLSHIFT: | |
4592 case LULSHIFT: | |
4593 code_longlong_lib("__ashldi3",reg,oreg); | |
4594 check_lreg(reg); | |
4595 if(ox!=-1) free_register(ox); | |
4596 return; | |
4597 case LRSHIFT: | |
4598 code_longlong_lib("__ashrdi3",reg,oreg); | |
4599 check_lreg(reg); | |
4600 if(ox!=-1) free_register(ox); | |
4601 return; | |
4602 case LURSHIFT: | |
4603 code_longlong_lib("__lshrdi3",reg,oreg); | |
4604 check_lreg(reg); | |
4605 if(ox!=-1) free_register(ox); | |
4606 return; | |
4607 } | |
4608 orn_h = lregister_name_high(oreg); | |
4609 orn_l = lregister_name_low(oreg); | |
4610 crn_h = lregister_name_high(reg); | |
4611 crn_l = lregister_name_low(reg); | |
4612 switch(op) { | |
4613 case LADD: | |
4614 printf("\tadds\t%s, %s, %s\n",crn_l,crn_l,orn_l); | |
4615 printf("\tadc\t%s, %s, %s\n",crn_h,crn_h,orn_h); | |
4616 break; | |
4617 case LSUB: | |
4618 printf("\tsubs\t%s, %s, %s\n",crn_l,crn_l,orn_l); | |
4619 printf("\tsbc\t%s, %s, %s\n",crn_h,crn_h,orn_h); | |
4620 break; | |
4621 case LCMP: | |
4622 error(-1); | |
4623 break; | |
4624 case LBAND: | |
4625 printf("\tand\t%s, %s, %s\n",crn_l,crn_l,orn_l); | |
4626 printf("\tand\t%s, %s, %s\n",crn_h,crn_h,orn_h); | |
4627 break; | |
4628 case LEOR: | |
4629 printf("\teor\t%s, %s, %s\n",crn_l,crn_l,orn_l); | |
4630 printf("\teor\t%s, %s, %s\n",crn_h,crn_h,orn_h); | |
4631 break; | |
4632 case LBOR: | |
4633 printf("\torr\t%s, %s, %s\n",crn_l,crn_l,orn_l); | |
4634 printf("\torr\t%s, %s, %s\n",crn_h,crn_h,orn_h); | |
4635 break; | |
4636 case LMUL: | |
4637 case LUMUL: | |
4638 code_longlong_lib("__muldi3",reg,oreg); | |
4639 check_lreg(reg); | |
4640 break; | |
4641 case LDIV: | |
4642 code_longlong_lib("__divdi3",reg,oreg); | |
4643 check_lreg(reg); | |
4644 break; | |
4645 case LUDIV: | |
4646 code_longlong_lib("__udivdi3",reg,oreg); | |
4647 check_lreg(reg); | |
4648 break; | |
4649 case LMOD: | |
4650 code_longlong_lib("__moddi3",reg,oreg); | |
4651 check_lreg(reg); | |
4652 break; | |
4653 case LUMOD: | |
4654 code_longlong_lib("__umoddi3",reg,oreg); | |
4655 check_lreg(reg); | |
4656 break; | |
4657 default: | |
4658 error(-1); | |
4659 } | |
4660 if(ox!=-1) free_register(ox); | |
4661 if(dx!=-1) free_register(dx); | |
4662 } | |
4663 | |
4664 int | |
4665 code_lconst_op_p(int op,int e) | |
4666 { | |
4667 long long v; | |
4668 if (car(e)==LCONST) { | |
4669 v = lcadr(e); | |
4670 } else if (car(e)==CONST) { | |
4671 v = cadr(e); | |
4672 } else return 0; | |
4673 | |
4674 switch(op) { | |
4675 case LMUL: case LUMUL: /* case LDIV: */ case LUDIV: | |
4676 return ilog(v); | |
4677 case LLSHIFT: case LULSHIFT: case LRSHIFT: case LURSHIFT: | |
4678 return 0<v&&v<=64; | |
4679 case LADD: | |
4680 case LSUB: | |
4681 case LBOR: | |
4682 case LEOR: case LBAND: | |
4683 return (is_stage1_const(v,0)>0) | |
4684 && (is_stage1_const(v>>32,0)>0); | |
4685 default: | |
4686 return 0; | |
4687 } | |
4688 } | |
4689 | |
4690 void | |
4691 loprtc(int op,int creg,int e) | |
4692 { | |
4693 char *crn_h; | |
4694 char *crn_l; | |
4695 char *grn; | |
4696 int v=0; | |
4697 int vh=0; | |
4698 int greg,dx=-1; | |
4699 | |
4700 use_longlong(creg); | |
4701 crn_h = lregister_name_high(creg); | |
4702 crn_l = lregister_name_low(creg); | |
4703 | |
4704 if (car(e)==LCONST) { v = lcadr(e); vh = lcadr(e)>>32; } | |
4705 else if (car(e)==CONST) { | |
4706 v = cadr(e); | |
4707 vh = (v<0)?-1:0; | |
4708 } | |
4709 | |
4710 switch(op) { | |
4711 case LMUL: case LUMUL: | |
4712 v=ilog(v); | |
4713 case LLSHIFT: | |
4714 case LULSHIFT: | |
4715 if (v==0) return; | |
4716 if (v==32) { | |
4717 code_register((creg),(creg)); | |
4718 code_const(0,(creg)); | |
4719 return; | |
4720 } else if (v>31) { | |
4721 printf("\tmov\t%s, %s, lsl #%d\n",crn_h,crn_l,v-32); | |
4722 code_const(0,(creg)); | |
4723 return; | |
4724 } | |
4725 greg = get_register(); | |
4726 grn = register_name(greg); | |
4727 printf("\tmov\t%s, %s, lsl #%d\n",crn_h,crn_h,v); | |
4728 printf("\tmov\t%s, %s, lsr #%d\n",grn,crn_l,32-v); | |
4729 printf("\torr\t%s, %s,%s\n",crn_h,crn_h,grn); | |
4730 printf("\tmov\t%s, %s, lsl #%d\n",crn_l,crn_l,v); | |
4731 free_register(greg); | |
4732 return; | |
4733 case LDIV: | |
4734 v=ilog(v); | |
4735 case LRSHIFT: | |
4736 if (v==0) return; | |
4737 if (v==32) { | |
4738 code_register((creg),(creg)); | |
4739 printf("\tmov\t%s, %s, asr #31\n",crn_h,crn_l); | |
4740 return; | |
4741 } else if (v>31) { | |
4742 printf("\tmov\t%s, %s, asr #%d\n",crn_l,crn_h,v-32); | |
4743 printf("\tmov\t%s, %s, asr #31\n",crn_h,crn_l); | |
4744 return; | |
4745 } | |
4746 greg = get_register(); | |
4747 grn = register_name(greg); | |
4748 printf("\tmov\t%s, %s, lsr #%d\n",crn_l,crn_l,v); | |
4749 printf("\tmov\t%s, %s, lsl #%d\n",grn,crn_h,32-v); | |
4750 printf("\torr\t%s, %s,%s\n",crn_l,crn_l,grn); | |
4751 printf("\tmov\t%s, %s, asr #%d\n",crn_h,crn_h,v); | |
4752 free_register(greg); | |
4753 return; | |
4754 case LUDIV: | |
4755 v=ilog(v); | |
4756 case LURSHIFT: | |
4757 if (v==0) return; | |
4758 if (v==32) { | |
4759 code_register((creg),(creg)); | |
4760 code_const(0,(creg)); | |
4761 return; | |
4762 } else if (v>31) { | |
4763 printf("\tmov\t%s, %s, lsr #%d\n",crn_l,crn_h,v-32); | |
4764 code_const(0,(creg)); | |
4765 return; | |
4766 } | |
4767 greg = get_register(); | |
4768 grn = register_name(greg); | |
4769 printf("\tmov\t%s, %s, lsl #%d\n",grn,crn_h,32-v); | |
4770 printf("\tmov\t%s, %s, lsr #%d\n",crn_l,crn_l,v); | |
4771 printf("\torr\t%s, %s,%s\n",crn_l,grn,crn_l); | |
4772 printf("\tmov\t%s, %s, lsr #%d\n",crn_h,crn_h,v); | |
4773 free_register(greg); | |
4774 return; | |
4775 case LADD: | |
4776 printf("\tadds\t%s, %s, #%d\n",crn_l,crn_l,v); | |
4777 printf("\tadc\t%s, %s, #%d\n",crn_h,crn_h,vh); | |
4778 break; | |
4779 case LSUB: | |
4780 printf("\tsubs\t%s, %s, #%d\n",crn_l,crn_l,v); | |
4781 printf("\tsbc\t%s, %s, #%d\n",crn_h,crn_h,vh); | |
4782 break; | |
4783 case LBAND: | |
4784 printf("\tand\t%s, %s, #%d\n",crn_l,crn_l,v); | |
4785 printf("\tand\t%s, %s, #%d\n",crn_h,crn_h,vh); | |
4786 break; | |
4787 case LEOR: | |
4788 printf("\teor\t%s, %s, #%d\n",crn_l,crn_l,v); | |
4789 printf("\teor\t%s, %s, #%d\n",crn_h,crn_h,vh); | |
4790 break; | |
4791 case LBOR: | |
4792 printf("\torr\t%s, %s, #%d\n",crn_l,crn_l,v); | |
4793 printf("\torr\t%s, %s, #%d\n",crn_h,crn_h,vh); | |
4794 break; | |
4795 default: | |
4796 error(-1); | |
4797 } | |
4798 if (dx!=-1) free_register(dx); | |
4799 } | |
4800 | |
4801 | |
4802 void | |
4803 code_i2ll(int reg) | |
4804 { | |
4805 char *crn,*crn_h,*crn_l; | |
4806 int reg0; | |
4807 crn = register_name(reg0 = ireg); | |
4808 use_longlong(reg); | |
4809 crn_h = lregister_name_high(lreg); | |
4810 crn_l = lregister_name_low(lreg); | |
4811 if (reg0!=(lreg)) | |
4812 printf("\tori\t%s, %s, 0\n",crn_l,crn); | |
4813 printf("\tmov\t%s, %s, asr #31\n",crn_h,crn_l); | |
4814 } | |
4815 | |
4816 void | |
4817 code_i2ull(int reg) | |
4818 { | |
4819 code_i2ll(reg); | |
4820 } | |
4821 | |
4822 void | |
4823 code_u2ll(int reg) | |
4824 { | |
4825 char *crn,*crn_h,*crn_l; | |
4826 int reg0; | |
4827 crn = register_name(reg0 = ireg); | |
4828 use_longlong(reg); | |
4829 crn_h = lregister_name_high(lreg); | |
4830 crn_l = lregister_name_low(lreg); | |
4831 if (reg0!=(lreg)) | |
4832 printf("\tori\t%s, %s, 0\n",crn_l,crn); | |
4833 printf("\tmov\t%s, #0\n",crn_h); | |
4834 } | |
4835 | |
4836 void | |
4837 code_u2ull(int creg) | |
4838 { | |
4839 code_u2ll(creg); | |
4840 } | |
4841 | |
4842 void | |
4843 code_ll2i(int reg) | |
4844 { | |
4845 char *crn_l; | |
4846 int reg0; | |
4847 crn_l = lregister_name_low(reg0=lreg); | |
4848 use_int(reg); | |
4849 if (ireg!=(reg0)) { | |
4850 printf("\tori\t%s, %s, 0\n",register_name(ireg),crn_l); | |
4851 } | |
4852 } | |
4853 | |
4854 void | |
4855 code_ll2u(int creg) | |
4856 { | |
4857 code_ll2i(creg); | |
4858 } | |
4859 | |
4860 void | |
4861 code_ull2i(int creg) | |
4862 { | |
4863 code_ll2i(creg); | |
4864 } | |
4865 | |
4866 void | |
4867 code_ull2u(int creg) | |
4868 { | |
4869 code_ll2i(creg); | |
4870 } | |
4871 | |
4872 #if FLOAT_CODE | |
4873 | |
4874 void | |
4875 code_d2ll(int reg) | |
4876 { | |
4877 // fixdfdi$stub | |
4878 code_assign_input_double_long( | |
4879 list2(LREGISTER,LREGISTER_OPERAND),list2(FREGISTER,freg)) ; | |
4880 extern_conv("__fixdfdi"); | |
4881 set_lreg(RET_LREGISTER,0); | |
4882 if (reg!=USE_CREG&®!=RET_LREGISTER) { | |
4883 use_longlong(reg); | |
4884 } | |
4885 } | |
4886 | |
4887 void | |
4888 code_d2ull(int reg) | |
4889 { | |
4890 code_assign_input_double_long( | |
4891 list2(LREGISTER,LREGISTER_OPERAND),list2(FREGISTER,freg)) ; | |
4892 extern_conv("__fixunsdfdi"); | |
4893 set_lreg(RET_LREGISTER,0); | |
4894 if (reg!=USE_CREG&®!=RET_LREGISTER) { | |
4895 use_longlong(reg); | |
4896 } | |
4897 } | |
4898 | |
4899 void | |
4900 code_f2ll(int reg) | |
4901 { | |
4902 code_assign_input_float_int(list2(REGISTER,REGISTER_OPERAND),list2(FREGISTER,freg)); | |
4903 extern_conv("__fixsfdi"); | |
4904 set_lreg(RET_LREGISTER,0); | |
4905 if (reg!=USE_CREG&®!=RET_LREGISTER) { | |
4906 use_longlong(reg); | |
4907 } | |
4908 } | |
4909 | |
4910 void | |
4911 code_f2ull(int reg) | |
4912 { | |
4913 code_assign_input_float_int(list2(REGISTER,REGISTER_OPERAND),list2(FREGISTER,freg)); | |
4914 extern_conv("__fixunssfdi"); | |
4915 set_lreg(RET_LREGISTER,0); | |
4916 if (reg!=USE_CREG&®!=RET_LREGISTER) { | |
4917 use_longlong(reg); | |
4918 } | |
4919 } | |
4920 | |
4921 void | |
4922 code_ll2d(int reg) | |
4923 { | |
4924 set_lreg(LREGISTER_OPERAND,1); | |
4925 extern_conv("__floatdidf"); | |
4926 set_dreg(RET_DREGISTER,0); | |
4927 if (reg!=USE_CREG&®!=RET_FREGISTER) | |
4928 use_float(1,reg); | |
4929 } | |
4930 | |
4931 | |
4932 void | |
4933 code_ll2f(int reg) | |
4934 { | |
4935 set_lreg(LREGISTER_OPERAND,1); | |
4936 extern_conv("__floatdisf"); | |
4937 set_freg(RET_FREGISTER,0); | |
4938 if (reg!=USE_CREG&®!=RET_FREGISTER) | |
4939 use_float(0,reg); | |
4940 } | |
4941 | |
4942 void | |
4943 code_ull2d(int creg) | |
4944 { | |
4945 code_ll2d(creg); | |
4946 } | |
4947 | |
4948 void | |
4949 code_ull2f(int creg) | |
4950 { | |
4951 code_ll2f(creg); | |
4952 } | |
4953 | |
4954 #endif | |
4955 | |
4956 static void | |
4957 ladd(int dreg,int rreg,int v) // rreg = dreg + v | |
4958 { | |
4959 // v should be 8bit const with 2's shift | |
4960 if (v>0) { | |
4961 printf("\tadds\t%s, %s, #%d\n", | |
4962 lregister_name_low(rreg),lregister_name_low(dreg), v); | |
4963 printf("\tadc\t%s, %s, #0\n", | |
4964 lregister_name_high(rreg),lregister_name_high(dreg)); | |
4965 } else { | |
4966 printf("\tsubs\t%s, %s, #%d\n", | |
4967 lregister_name_low(rreg),lregister_name_low(dreg), -v); | |
4968 printf("\tsbc\t%s, %s, #0\n", | |
4969 lregister_name_high(rreg),lregister_name_high(dreg)); | |
4970 } | |
4971 } | |
4972 | |
4973 void | |
4974 code_lpreinc(int e1,int e2,int reg) | |
4975 { | |
4976 int dreg=-1,xreg=-1; | |
4977 int dir=caddr(e1); | |
4978 if (car(e2)==LREGISTER) { | |
4979 use_longlong(reg); | |
4980 ladd(cadr(e2),cadr(e2),dir); | |
4981 if (reg!=cadr(e2)) { | |
4982 lmove(reg,cadr(e2)); | |
4983 } | |
4984 return; | |
4985 } | |
4986 g_expr(e2); | |
4987 if(!is_int_reg(creg)) error(-1); | |
4988 emit_push(); | |
4989 if (reg==USE_CREG) { | |
4990 dreg=get_lregister(); if (!dreg) error(-1); | |
4991 set_lreg(dreg,0); // free old lreg==creg | |
4992 } else { | |
4993 dreg = reg; | |
4994 } | |
4995 xreg = emit_pop(0); | |
4996 lload(xreg,dreg,0); | |
4997 ladd(dreg,dreg,dir); | |
4998 code_lassign(xreg,dreg); | |
4999 emit_pop_free(xreg); | |
5000 if (dreg!=-1) free_register(dreg); | |
5001 } | |
5002 | |
5003 void | |
5004 code_lpostinc(int e1,int e2,int reg) | |
5005 { | |
5006 int dreg,nreg,xreg; | |
5007 int dir=caddr(e1); | |
5008 if (car(e2)==LREGISTER) { | |
5009 use_longlong(reg); | |
5010 lmove(reg,cadr(e2)); | |
5011 ladd(cadr(e2),cadr(e2),dir); | |
5012 return; | |
5013 } | |
5014 g_expr(e2); | |
5015 if(!is_int_reg(creg)) error(-1); | |
5016 emit_push(); | |
5017 nreg=get_lregister(); if (!nreg) error(-1); | |
5018 if (reg==USE_CREG) { | |
5019 dreg=get_lregister(); if (!dreg) error(-1); | |
5020 set_lreg(dreg,0); // free old lreg==creg | |
5021 } else { | |
5022 dreg = reg; | |
5023 } | |
5024 xreg = emit_pop(0); | |
5025 lload(xreg,dreg,0); | |
5026 ladd(dreg,nreg,dir); | |
5027 lstore(xreg,nreg); | |
5028 emit_pop_free(xreg); | |
5029 free_register(nreg); | |
5030 } | |
5031 | |
5032 void | |
5033 code_lassop(int op,int reg) | |
5034 { | |
5035 int xreg; | |
5036 int edx,edx0=-1; | |
5037 | |
5038 // (*creg) op = pop() | |
5039 xreg = emit_lpop(0); /* pop e3 value */ | |
5040 if (!is_int_reg(creg)) error(-1); | |
5041 edx = ireg; | |
5042 emit_push(); | |
5043 use_longlong(reg); | |
5044 if ((lreg)==edx || (lreg)==edx) { | |
5045 edx0 = get_register(); if(!edx0) error(-1); | |
5046 printf("## lassop\n\tori\t%s, %s, 0\n",register_name(edx0), | |
5047 register_name(edx)); | |
5048 edx = edx0; | |
5049 } | |
5050 lload(edx,reg,0); | |
5051 // free_register(edx); don't do this, it will free pushed register | |
5052 ltosop(op,reg,xreg); // loprtc? | |
5053 emit_lpop_free(xreg); | |
5054 use_reg(reg); | |
5055 edx = emit_pop(0); | |
5056 code_lassign(edx,reg); | |
5057 emit_pop_free(edx); | |
5058 if (edx0!=-1) | |
5059 free_register(edx0); | |
5060 if (reg!=lreg) | |
5061 free_register(reg); | |
5062 } | |
5063 | |
5064 void | |
5065 code_register_lassop(int reg,int op) { | |
5066 // reg op = pop() | |
5067 int xreg=emit_lpop(); | |
5068 ltosop(op,reg,xreg); | |
5069 emit_lpop_free(xreg); | |
5070 } | |
5071 | |
5072 | |
5073 #endif | |
5074 | |
5075 void | |
5076 code_save_stacks() | |
5077 { | |
5078 int i,reg; | |
5079 for(i=0;i<reg_sp;i++) { | |
5080 if ((reg=reg_stack[i])>=0) { | |
5081 code_assign_lvar( | |
5082 (reg_stack[i]=new_lvar(SIZE_OF_INT)*4),reg,0); | |
5083 reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET; | |
5084 free_register(reg); | |
5085 } | |
5086 } | |
5087 #if FLOAT_CODE | |
5088 for(i=0;i<reg_sp;i++) { | |
5089 if ((reg=reg_stack[i])>=0) { | |
5090 code_dassign_lvar( | |
5091 (reg_stack[i]=new_lvar(SIZE_OF_DOUBLE)),reg,1); | |
5092 reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET; | |
5093 free_register(reg); | |
5094 } | |
5095 } | |
5096 #endif | |
5097 #if LONGLONG_CODE | |
5098 for(i=0;i<reg_sp;i++) { | |
5099 if ((reg=reg_stack[i])>=0) { | |
5100 code_lassign_lvar( | |
5101 (reg_stack[i]=new_lvar(SIZE_OF_LONGLONG)),reg); | |
5102 reg_stack[i]= reg_stack[i]-REG_LVAR_OFFSET; | |
5103 free_register(reg); | |
5104 } | |
5105 } | |
5106 #endif | |
5107 } | |
5108 | |
5109 void | |
5110 emit_lib(char *p[]) | |
5111 { | |
5112 while(*p) { | |
5113 printf("%s\n",*p++); | |
5114 } | |
5115 } | |
5116 | |
5117 void | |
5118 code_closing() | |
5119 { | |
5120 global_table(); | |
5121 /* printf("\t.ident \"Micro-C compiled\"\n"); */ | |
5122 } | |
5123 | |
5124 #if CASE_CODE | |
5125 | |
5126 int | |
5127 code_table_jump_p(int delta) { return delta==1||delta==2||delta==4; } | |
5128 | |
5129 void | |
5130 code_table_jump(int l,int csvalue,int delta,int max,int min,int dlabel) | |
5131 { | |
5132 int t,regsv; | |
5133 char *trn; | |
5134 | |
5135 regsv = regs[csvalue]; regs[csvalue] = 1; | |
5136 trn = register_name(t=get_register()); | |
5137 regs[csvalue] = regsv; | |
5138 | |
5139 code_add(t,-min,csvalue); | |
5140 switch(delta) { | |
5141 case 1: | |
5142 code_cmpdimm(max-min,t,dlabel,-1); | |
5143 printf("\tldrls\tpc, [pc, %s, asl #2]\n",trn); | |
5144 break; | |
5145 case 2: | |
5146 printf("\ttst\t%s, #1\n",trn); | |
5147 printf("\tbne\t.L%d\n",dlabel); | |
5148 code_cmpdimm(max-min,t,dlabel,-1); | |
5149 printf("\tldrls\tpc, [pc, %s, asl #1]\n",trn); break; | |
5150 break; | |
5151 case 4: | |
5152 printf("\ttst\t%s, #3\n",trn); | |
5153 printf("\tbne\t.L%d\n",dlabel); | |
5154 code_cmpdimm(max-min,t,dlabel,-1); | |
5155 printf("\tldrls\tpc, [pc, %s]\n",trn); break; | |
5156 break; | |
5157 default: | |
5158 error(-1); | |
5159 } | |
5160 printf("\tbr\t.L%d\n",dlabel); | |
5161 | |
5162 free_register(t); | |
5163 } | |
5164 | |
5165 void | |
5166 code_table_open(int l) | |
5167 { | |
5168 output_mode = DATA_EMIT_MODE; | |
5169 printf("\t.align 2\n"); | |
5170 fwddef(l); | |
5171 } | |
5172 | |
5173 void | |
5174 code_table_value(int label,int table_top) | |
5175 { | |
5176 printf("\t.word .L%d\n",label); | |
5177 } | |
5178 | |
5179 void | |
5180 code_table_close() | |
5181 { | |
5182 } | |
5183 | |
5184 #endif | |
5185 | |
5186 | |
5187 #if ASM_CODE | |
5188 | |
5189 /* | |
5190 print an operand | |
5191 */ | |
5192 | |
5193 static void | |
5194 emit_asm_operand(int rstr) | |
5195 { | |
5196 if (car(rstr)==REGISTER) { | |
5197 printf("%s",register_name(cadr(rstr))); | |
5198 } else if (car(rstr)==CONST) { | |
5199 printf("%d",cadr(rstr)); | |
5200 } else if (car(rstr)==FNAME) { | |
5201 printf("%s",(char*)cadr(rstr)); | |
5202 } else if (car(rstr)==STRING) { | |
5203 printf(".L%d",cadr(rstr)); | |
5204 } else { | |
5205 error(-1); | |
5206 } | |
5207 } | |
5208 | |
5209 /* | |
5210 prepare asm operands | |
5211 | |
5212 char *constraints string | |
5213 int operand expr | |
5214 int mode (ASM_INPUT,ASM_OUTPUT) | |
5215 int replacement list | |
5216 int output operands count | |
5217 int output operands replacement list | |
5218 | |
5219 retrun replacement list | |
5220 list3( operands, next, clobber ) | |
5221 0 can be shared in input/output | |
5222 1 can't be used in input | |
5223 */ | |
5224 | |
5225 int | |
5226 code_asm_operand(char *p,int e1,int mode,int repl,int n,int repl0) | |
5227 { | |
5228 int r; | |
5229 int c; | |
5230 int val; | |
5231 int clobber = 0; | |
5232 | |
5233 printf("## constraint %s\n",p); | |
5234 if (*p=='=') { | |
5235 // output register | |
5236 p++; | |
5237 } | |
5238 if (*p=='&') { | |
5239 // earlyclobber | |
5240 p++; | |
5241 clobber = 1; | |
5242 } | |
5243 c = *p; | |
5244 if (c=='r') { | |
5245 if (mode==ASM_INPUT) { | |
5246 for(;repl0;repl0 = cadr(repl0)) { | |
5247 if (car(car(repl0))==REGISTER && caddr(repl0)==0) { | |
5248 r = cadr(car(repl0)); | |
5249 caddr(repl0) = ASM_USED; | |
5250 break; | |
5251 } | |
5252 } | |
5253 r = get_register(); | |
5254 } else { | |
5255 r = get_register(); | |
5256 } | |
5257 repl = list3(list2(REGISTER,r),repl,clobber); | |
5258 } else if (c=='m') { | |
5259 repl = list3(list2(0,0),repl,clobber); | |
5260 } else if (c=='i') { | |
5261 if (car(e1)==GVAR) { | |
5262 e1=list3(FNAME,(int)(((NMTBL *)caddr(e1))->nm),0); | |
5263 } else if (car(e1)==FNAME) { | |
5264 e1=list3(FNAME,(int)(((NMTBL *)cadr(e1))->nm),0); | |
5265 } else if (car(e1)==STRING) { | |
5266 val = emit_string_label(); | |
5267 ascii((char*)cadr(e1)); | |
5268 e1=list3(STRING,val,0); | |
5269 } else if (car(e1)==CONST) { | |
5270 } else error(-1); | |
5271 repl = list3(e1,repl,clobber); | |
5272 } else if (digit(c)) { | |
5273 val = 0; | |
5274 do { val = val*10 + c-'0'; } while (digit(c=*p++)); | |
5275 if (val>MAX_ASM_REG) error(-1); // too large register | |
5276 if (n-val<0) error(-1); | |
5277 repl = list3(car(nth(n-val-1,repl0)),repl,clobber); | |
5278 } else error(-1); | |
5279 return repl; | |
5280 } | |
5281 | |
5282 void | |
5283 code_free_asm_operand(int repl) | |
5284 { | |
5285 for(;repl;repl=cadr(repl)) { | |
5286 if (car(car(repl))==REGISTER) | |
5287 free_register(cadr(car(repl))); | |
5288 } | |
5289 } | |
5290 | |
5291 | |
5292 extern void | |
5293 code_asm(char *asm_str,int repl) | |
5294 { | |
5295 int c,i,rstr,val; | |
5296 char *p; | |
5297 int reg[MAX_ASM_REG]; | |
5298 | |
5299 text_mode(2); | |
5300 c = *asm_str; | |
5301 if (c!='\t'&&c!=' ') printf("\t"); | |
5302 for(i=0;repl && i<MAX_ASM_REG;i++) { | |
5303 reg[i] = car(repl); | |
5304 repl = cadr(repl); | |
5305 } | |
5306 p = asm_str; | |
5307 while((c = *p++)) { | |
5308 if (c=='%') { | |
5309 c = *p++; | |
5310 if (!c) { break; | |
5311 } else if (c=='%') { | |
5312 printf("%%"); continue; | |
5313 } else if (!digit(c)) { | |
5314 printf("%%%c",c); continue; | |
5315 } | |
5316 val = 0; | |
5317 do { val = val*10 + c-'0'; } while (digit(c=*p++)) ; | |
5318 p--; | |
5319 if (val>MAX_ASM_REG) error(-1); // too large register | |
5320 rstr = reg[val]; | |
5321 emit_asm_operand(rstr); | |
5322 } else { | |
5323 printf("%c",c); | |
5324 } | |
5325 } | |
5326 printf("\n"); | |
5327 } | |
5328 | |
5329 #endif | |
5330 | |
5331 | |
5332 #if BIT_FIELD_CODE | |
5333 | |
5334 /* bit field alignment calcuration */ | |
5335 | |
5336 static void | |
5337 set_bitsz(int type,int *pbitpos, int *pbitsize, | |
5338 int *psign,int *pbitsz,int *palign,int *pl) | |
5339 { | |
5340 int sign=0,bitsz=0; | |
5341 int align=0,l=0; | |
5342 switch(cadr(type)) { /* value type */ | |
5343 case INT: sign=1; break; | |
5344 case UNSIGNED: break; | |
5345 case CHAR: sign=1; break; | |
5346 case UCHAR: break; | |
5347 case SHORT: sign=1; break; | |
5348 case USHORT: sign=1; break; | |
5349 case LONGLONG: sign=1; l=1; break; | |
5350 case ULONGLONG: l=1; break; | |
5351 default: error(-1); | |
5352 } | |
5353 if (car(caddr(type))>0) { /* store type */ | |
5354 if (car(car(caddr(type)))==STRUCT) { | |
5355 bitsz=64+32; align=4; l=2; | |
5356 } else error(-1); | |
5357 } else { | |
5358 switch(car(caddr(type))) { | |
5359 case INT: bitsz=32; align=4; break; | |
5360 case UNSIGNED: bitsz=32; align=4; break; | |
5361 case CHAR: bitsz= 8; align=1; break; | |
5362 case UCHAR: bitsz= 8; align=1; break; | |
5363 case SHORT: bitsz=16; align=2; break; | |
5364 case USHORT: bitsz=16; align=2; break; | |
5365 case LONGLONG: bitsz=64; align=4; l=1; break; | |
5366 case ULONGLONG: bitsz=64; align=4; l=1; break; | |
5367 default: error(-1); | |
5368 } | |
5369 } | |
5370 *pbitpos = cadr(caddr(type)); | |
5371 *pbitsize = caddr(caddr(type)); | |
5372 *psign = sign; | |
5373 *pbitsz = bitsz; | |
5374 *palign = align; | |
5375 *pl = l; | |
5376 } | |
5377 | |
5378 /* | |
5379 bit field alignment calcuration | |
5380 this is architecture depenedent | |
5381 */ | |
5382 | |
5383 #define NON_ALIGNED_BFD 1 | |
5384 | |
5385 extern int | |
5386 code_bit_field_disp(int type,int *poffset,int *bfd,int *sz) | |
5387 { | |
5388 int sign,bitsz,align; | |
5389 int i; | |
5390 int bitpos = *bfd; | |
5391 int offset = *poffset; | |
5392 int l; | |
5393 int bitsize,bitpos0; | |
5394 set_bitsz(type,&bitpos0,&bitsize,&sign,&bitsz,&align,&l); | |
5395 | |
5396 if (bitsize>bitsz) { error(BTERR); bitsize = bitsz; } | |
5397 | |
5398 /* bfd means previous bit field bit offset */ | |
5399 if (bitpos) { | |
5400 /* previous field is bit field and spaces may remain */ | |
5401 /* calc previsous offset */ | |
5402 offset-=(bitpos+7)/8; | |
5403 | |
5404 #ifdef NON_ALIGNED_BFD | |
5405 /* code for non-aligned non-hole bit-field */ | |
5406 | |
5407 /* remove extra previous offset from bitpos */ | |
5408 while(bitpos>align*8) { | |
5409 i = ((offset+(align))&~(align-1))-offset; | |
5410 offset+=i; bitpos-=i*8; | |
5411 } | |
5412 if (bitpos+bitsize > bitsz) { | |
5413 int stype=UNSIGNED; | |
5414 | |
5415 /* rewind extra previous offset */ | |
5416 bitpos = *bfd; offset=*poffset; | |
5417 offset-=(bitpos+7)/8; | |
5418 | |
5419 /* extend store type to allow |---===|===---| */ | |
5420 switch(car(caddr(type))) { | |
5421 case INT: case UNSIGNED: | |
5422 stype=ULONGLONG; align=4; break; | |
5423 case CHAR: case UCHAR: | |
5424 stype=USHORT; align=2; break; | |
5425 case SHORT: case USHORT: | |
5426 stype=UNSIGNED; align=4; break; | |
5427 case ULONGLONG: case LONGLONG: | |
5428 /* dummy struct type. fields are never used */ | |
5429 stype=list4(STRUCT,12,0,0);align=4;break; | |
5430 default: error(-1); | |
5431 } | |
5432 /* remove extra previous offset from bitpos again */ | |
5433 while(bitpos>align*8) { | |
5434 i = ((offset+(align))&~(align-1))-offset; | |
5435 offset+=i; bitpos-=i*8; | |
5436 } | |
5437 bitsz = size(stype)*8; | |
5438 /* fix store type */ | |
5439 car(caddr(type)) = stype; | |
5440 } | |
5441 #endif | |
5442 | |
5443 /* previous remaining bit space can contain this type? */ | |
5444 i= offset; | |
5445 for(l = bitpos;l>0;l -= 8,i++) { | |
5446 if ((i & (align-1))==0 && l+bitsize <= bitsz) { | |
5447 /* alignment is correct and space remains */ | |
5448 *poffset=offset=i; | |
5449 i = l+bitsize; | |
5450 *bfd = (i==bitsz)?0:i; | |
5451 *sz = (i+7)/8; | |
5452 #ifdef BITPOS_DEBUG | |
5453 printf("## %d: bitpos=%d bitsize=%d bitsz=%d offset=%d\n",lineno,bitpos,bitsize,bitsz,*poffset); | |
5454 #endif | |
5455 return l; | |
5456 } | |
5457 } | |
5458 } | |
5459 | |
5460 /* first bit-field or no remaining bits */ | |
5461 | |
5462 if ((i=(offset & (align-1)))) { | |
5463 *poffset = (offset += (align-i)); | |
5464 } | |
5465 bitpos = 0; | |
5466 *bfd = (bitsize==bitsz)?0:bitsize; | |
5467 *sz = (bitsize+7)/8; | |
5468 #ifdef BITPOS_DEBUG | |
5469 printf("## %d: bitpos=%d bitsize=%d bitsz=%d offset=%d\n",lineno,bitpos,bitsize,bitsz,*poffset); | |
5470 #endif | |
5471 return bitpos; | |
5472 } | |
5473 | |
5474 /* bit field value */ | |
5475 | |
5476 /* reg contains container value, result should be in reg */ | |
5477 extern void | |
5478 code_bit_field(int type,int adr,int reg) | |
5479 { | |
5480 int sign,bitsz,l,align; | |
5481 int bitsize,bitpos; | |
5482 int i,size; | |
5483 set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); | |
5484 size = bitsz/8; | |
5485 // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); | |
5486 /* this implementation returns -1 for int i:1; */ | |
5487 if (l==1) { | |
5488 #if LONGLONG_CODE | |
5489 // use_int(adr); | |
5490 use_longlong(reg); | |
5491 lload(adr,reg,0); | |
5492 /* shift left */ | |
5493 if ((i=bitsz-bitsize-bitpos)) | |
5494 loprtc(LLSHIFT,reg,list2(CONST,i)); | |
5495 /* shift right */ | |
5496 if ((i=bitsz-bitsize)) | |
5497 loprtc(sign?LRSHIFT:LURSHIFT,reg,list2(CONST,i)); | |
5498 } else if (l==2) { /* three int container */ | |
5499 int lvalue; | |
5500 // use_int(adr); | |
5501 use_longlong(reg); | |
5502 lvalue = get_register(); | |
5503 code_register(adr,lvalue); adr = lvalue; | |
5504 /* | |
5505 | |
5506 <-----bitsize---------------> | |
5507 hhhhhh mmmmmmmmmmmm lllllll | |
5508 lllll 00000000000 mmmmmmmmmmmm 0000000 hhhhhhh | |
5509 |-----||-----------||------------||-------||-------| | |
5510 <-bitpos---> | |
5511 <----------------bitsz-----------------------------> | |
5512 <-----32----------> <---32------> <----32----------> | |
5513 (r0:r1) <<= bitsz-bitsize-bitbos | |
5514 rest >> = b; | |
5515 rest << = a; (b>a) ==> rest >> (b-a) | |
5516 (64+32-bitsize -bitpos - (bitsz-bitsize)) | |
5517 = 64+32 -bitsz -bitbpos | |
5518 */ | |
5519 /* load hhhhh */ | |
5520 code_ld(cload(0,0),(reg),SIZE_OF_INT*2,adr,cext_at(0,0)); | |
5521 /* load mmmmmm */ | |
5522 code_ld(cload(0,0),(reg),SIZE_OF_INT,adr,cext_at(0,0)); | |
5523 i = 64-(bitsize-(32-bitpos)); | |
5524 loprtc(LLSHIFT,reg,list2(CONST,i)); | |
5525 if (i<0||64<=i) error(-1); | |
5526 /* load lllll */ | |
5527 code_ld(cload(0,0),adr,0,adr,cext_at(0,0)); | |
5528 i = (bitsize-(32-bitpos))-32; | |
5529 oprtc(URSHIFT,adr,list2(CONST,i)); | |
5530 if (i<0||32<=i) error(-1); | |
5531 printf("\tadd\t%s,%s,%s\n", | |
5532 register_name((reg)), | |
5533 register_name((reg)), | |
5534 register_name(adr)); | |
5535 i = 64-bitsize; | |
5536 loprtc(sign?LRSHIFT:LURSHIFT,reg,list2(CONST,i)); | |
5537 if (i<0||64<=i) error(-1); | |
5538 free_register(adr); | |
5539 #endif | |
5540 } else { | |
5541 // use_int(adr); | |
5542 use_int(reg); | |
5543 code_ld(cload(size,sign),reg,0,adr,cext_at(0,0)); | |
5544 /* shift left */ | |
5545 if ((i=32-bitsize-bitpos)) | |
5546 oprtc(LSHIFT,reg,list2(CONST,i)); | |
5547 /* shift right */ | |
5548 if ((i=32-bitsize)) | |
5549 oprtc(sign?RSHIFT:URSHIFT,reg,list2(CONST,i)); | |
5550 } | |
5551 } | |
5552 | |
5553 /* bit field replacement */ | |
5554 | |
5555 static void | |
5556 make_mask_and_or(int mask,int tmp,char *trn,char *crn,char *lrn) | |
5557 { | |
5558 // printf("## mask 0x%08x ~0x%08x\n",mask,~mask); | |
5559 code_const(~mask,tmp); | |
5560 printf("\torr\t%s, %s, %s\n",trn,crn,trn); | |
5561 /* do conjunction */ | |
5562 printf("\tand\t%s, %s, %s\n",lrn,trn,lrn); | |
5563 /* make or-mask */ | |
5564 code_const(mask,tmp); | |
5565 printf("\tand\t%s, %s, %s\n",trn,crn,trn); | |
5566 /* do disjunction */ | |
5567 printf("\torr\t%s, %s, %s\n",crn,trn,lrn); | |
5568 } | |
5569 | |
5570 extern void | |
5571 code_bit_replace(int adr,int value,int type) | |
5572 { | |
5573 int sign,bitsz,l,align; | |
5574 int bitsize,bitpos; | |
5575 int mask = 0; | |
5576 int tmp = -1,lvalue,size; | |
5577 char *crn,*lrn,*trn; | |
5578 set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); | |
5579 size = bitsz/8; | |
5580 // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); | |
5581 if (l==1) { | |
5582 #if LONGLONG_CODE | |
5583 int tmp2; | |
5584 // use_int(adr); | |
5585 lvalue = get_lregister(); | |
5586 tmp2 = get_register(); | |
5587 code_register(adr,tmp2); adr = tmp2; | |
5588 lload(adr,lvalue,0); | |
5589 use_longlong(value); | |
5590 crn = lregister_name_high(value); | |
5591 lrn = lregister_name_high(lvalue); | |
5592 /* shift left */ | |
5593 if (bitpos) | |
5594 loprtc(LLSHIFT,value,list2(CONST,bitpos)); | |
5595 trn = register_name(tmp = get_register()); | |
5596 if (bitpos+bitsize>=32) { | |
5597 /* make and-mask upper */ | |
5598 mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); | |
5599 make_mask_and_or(mask,tmp,trn,crn,lrn); | |
5600 } | |
5601 crn = lregister_name_low(value); | |
5602 lrn = lregister_name_low(lvalue); | |
5603 if (bitpos<32) { | |
5604 /* make and-mask lower */ | |
5605 mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); | |
5606 make_mask_and_or(mask,tmp,trn,crn,lrn); | |
5607 } | |
5608 code_lassign(adr,value); | |
5609 free_register(lvalue); | |
5610 free_register(adr); | |
5611 } else if (l==2) { | |
5612 int i; | |
5613 int tmpvar; | |
5614 // use_int(adr); | |
5615 use_longlong(value); | |
5616 lvalue = get_register(); | |
5617 code_register(adr,lvalue); adr = lvalue; | |
5618 tmpvar=new_lvar(SIZE_OF_LONGLONG); | |
5619 code_lassign_lvar(tmpvar,value); | |
5620 trn = register_name(tmp = get_register()); | |
5621 | |
5622 /* make and-mask upper */ | |
5623 i=bitpos; | |
5624 if (i) | |
5625 oprtc(LSHIFT,(value),list2(CONST,i)); | |
5626 if (i<0||32<=i) error(-1); | |
5627 crn = lregister_name_low(value); | |
5628 code_ld(cload(0,0),(value),0,adr,cext_at(0,0)); | |
5629 lrn = lregister_name_high(value); | |
5630 mask = make_mask(0,31-bitpos); | |
5631 make_mask_and_or(mask,tmp,trn,crn,lrn); | |
5632 printf("\t%s\t%s, 0(%s)\n",cstore(0),crn,register_name(adr)); | |
5633 /* | |
5634 <-----bitsize---------------> | |
5635 hhhhhh mmmmmmmmmmmm lllllll | |
5636 lllll 00000000000 mmmmmmmmmmmm 0000000 hhhhhhh | |
5637 |-----||-----------||------------||-------||-------| | |
5638 <-bitpos---> | |
5639 <----------------bitsz-----------------------------> | |
5640 <-----32----------> <---32------> <----32----------> | |
5641 */ | |
5642 /* store middle */ | |
5643 code_lrlvar(tmpvar,value); | |
5644 i=32-bitpos; | |
5645 if (i) | |
5646 loprtc(LRSHIFT,value,list2(CONST,i)); | |
5647 if (i<0||64<=i) error(-1); | |
5648 printf("\t%s\t%s, 16(%s)\n",cstore(0),crn,register_name(adr)); | |
5649 | |
5650 /* make and-mask lower */ | |
5651 code_ld(cload(0,0),(value),8,adr,cext_at(0,0)); | |
5652 if (i<0||64<=i) error(-1); | |
5653 mask = make_mask(bitsz-bitpos-bitsize,31); | |
5654 make_mask_and_or(mask,tmp,trn,lrn,crn); | |
5655 printf("\t%s\t%s, 32(%s)\n",cstore(0),lrn,register_name(adr)); | |
5656 free_lvar(tmpvar); | |
5657 free_register(adr); | |
5658 #endif | |
5659 } else { | |
5660 // use_int(adr); | |
5661 use_int(value); | |
5662 lvalue = get_register(); | |
5663 code_ld(cload(size,sign),lvalue,0,adr,cext_at(0,0)); | |
5664 crn = register_name(value); | |
5665 lrn = register_name(lvalue); | |
5666 /* shift left */ | |
5667 if (bitpos) | |
5668 oprtc(LSHIFT,value,list2(CONST,bitpos)); | |
5669 trn = register_name(tmp = get_register()); | |
5670 /* make and-mask */ | |
5671 mask = make_mask(32-bitpos-bitsize,31-bitpos); | |
5672 make_mask_and_or(mask,tmp,trn,crn,lrn); | |
5673 code_assign(adr,size,value); | |
5674 free_register(lvalue); | |
5675 } | |
5676 if (tmp!=-1) free_register(tmp); | |
5677 if (use) { | |
5678 code_bit_field(type,adr,USE_CREG); | |
5679 } | |
5680 } | |
5681 | |
5682 | |
5683 static void | |
5684 make_mask_and_or_const(int mask,char *crn,int c) | |
5685 { | |
5686 char *trn; | |
5687 int tmp = -1; | |
5688 int m; | |
5689 // printf("## mask 0x%08x ~0x%08x\n",mask,~mask); | |
5690 if ((m=(~mask|c))!=-1) { | |
5691 if (is_stage1_const(m,0)>0) { | |
5692 printf("\tand\t%s, %s, #%d\n",crn,crn,m); | |
5693 } else { | |
5694 trn = register_name(tmp=get_register()); | |
5695 code_const((~mask|c),tmp); | |
5696 /* do conjunction */ | |
5697 printf("\tand\t%s, %s, %s\n",crn,trn,crn); | |
5698 } | |
5699 } | |
5700 if (tmp!=-1) { free_register(tmp); tmp=-1; } | |
5701 /* make or-mask */ | |
5702 c = mask&c; | |
5703 if (c!=0) { | |
5704 /* do disjunction */ | |
5705 if (is_stage1_const(c,0)>0) { | |
5706 printf("\torr\t%s, %s, #%d\n",crn,crn,c); | |
5707 } else { | |
5708 trn = register_name(tmp=get_register()); | |
5709 code_const(c,tmp); | |
5710 printf("\torr\t%s, %s, %s\n",crn,trn,crn); | |
5711 } | |
5712 } | |
5713 if (tmp!=-1) free_register(tmp); | |
5714 } | |
5715 | |
5716 extern void | |
5717 code_bit_replace_const(int value,int adr,int type) | |
5718 { | |
5719 int sign,bitsz,l,align; | |
5720 int bitsize,bitpos,size; | |
5721 int mask = 0; | |
5722 int c; | |
5723 int lvalue; | |
5724 #if LONGLONG_CODE | |
5725 long long lc; | |
5726 int tmp; | |
5727 #endif | |
5728 char *crn; | |
5729 set_bitsz(type,&bitpos,&bitsize,&sign,&bitsz,&align,&l); | |
5730 size = bitsz/8; | |
5731 // printf("## %d: bitpos=%d bitsize=%d bitsz=%d\n",lineno,bitpos,bitsize,bitsz); | |
5732 if (l==1) { | |
5733 #if LONGLONG_CODE | |
5734 use_int(adr); | |
5735 lvalue = get_lregister(); | |
5736 lload(adr,lvalue,0); | |
5737 crn = lregister_name_high(lvalue); | |
5738 /* shift left */ | |
5739 lc = lcadr(value); | |
5740 lc <<= bitpos; | |
5741 if (bitpos+bitsize>=32) { | |
5742 /* make and-mask upper */ | |
5743 mask = make_mask(64-bitpos-bitsize,bitpos>=32?63-bitpos:31); | |
5744 make_mask_and_or_const(mask,crn,(int)(lc>>32)); | |
5745 } | |
5746 crn = lregister_name_low(lvalue); | |
5747 if (bitpos<32) { | |
5748 /* make and-mask lower */ | |
5749 mask = make_mask(bitpos+bitsize>=32?0:32-bitpos-bitsize,31-bitpos); | |
5750 make_mask_and_or_const(mask,crn,(int)lc); | |
5751 } | |
5752 code_lassign(adr,lvalue); | |
5753 free_register(adr); | |
5754 free_register(lvalue); | |
5755 } else if (l==2) { // three int container | |
5756 char *trn; | |
5757 /* | |
5758 hhhhhh mmmmmmmmmmmm lllllll | |
5759 lllll 00000000000 mmmmmmmmmmmm 0000000 hhhhhhh | |
5760 |-----||-----------||------------||-------||-------| | |
5761 */ | |
5762 use_int(adr); | |
5763 crn = register_name(adr); | |
5764 trn = register_name(tmp = get_register()); | |
5765 /* shift right */ | |
5766 lc = lcadr(value); | |
5767 /* make and-mask upper */ | |
5768 code_ld(cload(0,0),tmp,0,adr,cext_at(0,0)); | |
5769 mask = make_mask(0,31-bitpos); | |
5770 make_mask_and_or_const(mask,trn,(int)(lc<<bitpos)); | |
5771 printf("\t%s\t%s, 0(%s)\n",cstore(0),trn,crn); | |
5772 /* store middle */ | |
5773 code_const((int)(lc>>(32-bitpos)),tmp); | |
5774 printf("\t%s\t%s, 16(%s)\n",cstore(0),trn,crn); | |
5775 /* make and-mask lower */ | |
5776 code_ld(cload(0,0),tmp,8,adr,cext_at(0,0)); | |
5777 mask = make_mask(bitsz-bitpos-bitsize,31); | |
5778 make_mask_and_or_const(mask,trn,(int)(lc>>(64-bitpos))); | |
5779 printf("\t%s\t%s, 32(%s)\n",cstore(0),trn,crn); | |
5780 free_register(tmp); | |
5781 #endif | |
5782 } else { | |
5783 use_int(adr); | |
5784 lvalue = get_register(); | |
5785 code_ld(cload(size,sign),lvalue,0,adr,cext_at(0,0)); | |
5786 crn = register_name(lvalue); | |
5787 /* shift left */ | |
5788 c = cadr(value); | |
5789 c <<= bitpos; | |
5790 /* make and-mask */ | |
5791 mask = make_mask(32-bitpos-bitsize,31-bitpos); | |
5792 make_mask_and_or_const(mask,crn,c); | |
5793 code_assign(adr,size,lvalue); | |
5794 free_register(lvalue); | |
5795 } | |
5796 if (use) { | |
5797 code_bit_field(type,adr,USE_CREG); | |
5798 } | |
5799 } | |
5800 | |
5801 | |
5802 #endif | |
5803 | |
5804 /* end */ |