source: EcnlProtoTool/trunk/tcc-0.9.26/il-gen.c@ 279

Last change on this file since 279 was 279, checked in by coas-nagasima, 7 years ago

ファイルを追加、更新。

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
  • Property svn:mime-type set to text/x-csrc
File size: 17.9 KB
Line 
1/*
2 * CIL code generator for TCC
3 *
4 * Copyright (c) 2002 Fabrice Bellard
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 */
20#ifdef TARGET_DEFS_ONLY
21
22/* number of available registers */
23#define NB_REGS 3
24#define NB_ASM_REGS 8 // TODO:
25#define ELF_PAGE_SIZE 0x1000 // TODO:
26#define MAX_ALIGN 8 // TODO:
27#define R_DATA_32 R_386_32 // TODO:
28#define R_DATA_PTR R_386_32 // TODO:
29#define R_JMP_SLOT R_386_JMP_SLOT // TODO:
30#define R_COPY R_386_COPY // TODO:
31#define ELF_START_ADDR 0x08048000 // TODO:
32#define EM_TCC_TARGET 0xFF // TODO:
33
34/* a register can belong to several classes. The classes must be
35 sorted from more general to more precise (see gv2() code which does
36 assumptions on it). */
37#define RC_ST 0x0001 /* any stack entry */
38#define RC_ST0 0x0002 /* top of stack */
39#define RC_ST1 0x0004 /* top - 1 */
40
41#define RC_INT RC_ST
42#define RC_FLOAT RC_ST
43#define RC_IRET RC_ST0 /* function return: integer register */
44#define RC_LRET RC_ST0 /* function return: second integer register */
45#define RC_FRET RC_ST0 /* function return: float register */
46
47/* pretty names for the registers */
48enum {
49 REG_ST0 = 0,
50 REG_ST1,
51 REG_ST2,
52};
53
54/* return registers for function */
55#define REG_IRET REG_ST0 /* single word int return register */
56#define REG_LRET REG_ST0 /* second word return register (for long long) */
57#define REG_FRET REG_ST0 /* float return register */
58
59/* defined if function parameters must be evaluated in reverse order */
60//#define INVERT_FUNC_PARAMS
61
62/* defined if structures are passed as pointers. Otherwise structures
63 are directly pushed on stack. */
64//#define FUNC_STRUCT_PARAM_AS_PTR
65
66/* pointer size, in bytes */
67#define PTR_SIZE 4
68
69/* long double size and alignment, in bytes */
70#define LDOUBLE_SIZE 8
71#define LDOUBLE_ALIGN 8
72
73/* function call context */
74typedef struct GFuncContext {
75 int func_call; /* func call type (FUNC_STDCALL or FUNC_CDECL) */
76} GFuncContext;
77
78/******************************************************/
79/* opcode definitions */
80
81#define IL_OP_PREFIX 0xFE
82
83enum ILOPCodes {
84#define ENUM_ILOPCODES_DEF
85#define OP(name, str, n) IL_OP_ ## name = n,
86#include "il-opcodes.h"
87#undef OP
88#undef ENUM_ILOPCODES_DEF
89};
90
91/******************************************************/
92#else /* ! TARGET_DEFS_ONLY */
93 /******************************************************/
94#include "tcc.h"
95
96const int reg_classes[NB_REGS] = {
97 /* ST0 */ RC_ST | RC_ST0,
98 /* ST1 */ RC_ST | RC_ST1,
99 /* ST2 */ RC_ST,
100};
101
102char *il_opcodes_str[] = {
103#define OP(name, str, n) /*[n] = */str,
104#include "il-opcodes.h"
105#undef OP
106};
107
108/******************************************************/
109
110/* arguments variable numbers start from there */
111#define ARG_BASE 0x70000000
112
113static FILE *il_outfile;
114
115static void out_byte(int c)
116{
117 int ind1 = ind + 1;
118 if (ind1 > cur_text_section->data_allocated)
119 section_realloc(cur_text_section, ind1);
120 *(char *)(cur_text_section->data + ind) = c;
121 ind++;
122}
123
124static void out_le32(int c)
125{
126 out_byte(c);
127 out_byte(c >> 8);
128 out_byte(c >> 16);
129 out_byte(c >> 24);
130}
131
132static void init_outfile(void)
133{
134 if (!il_outfile) {
135 il_outfile = stdout;
136 fprintf(il_outfile,
137 ".assembly extern mscorlib\n"
138 "{\n"
139 ".ver 1:0:2411:0\n"
140 "}\n\n");
141 }
142}
143
144static void out_op1(int op)
145{
146 if (op & 0x100)
147 out_byte(IL_OP_PREFIX);
148 out_byte(op & 0xff);
149}
150
151/* output an opcode with prefix */
152static void out_op(int op)
153{
154 out_op1(op);
155 fprintf(il_outfile, " %s\n", il_opcodes_str[op]);
156}
157
158static void out_opb(int op, int c)
159{
160 out_op1(op);
161 out_byte(c);
162 fprintf(il_outfile, " %s %d\n", il_opcodes_str[op], c);
163}
164
165static void out_opi(int op, int c)
166{
167 out_op1(op);
168 out_le32(c);
169 fprintf(il_outfile, " %s 0x%x\n", il_opcodes_str[op], c);
170}
171
172/* XXX: not complete */
173static void il_type_to_str(char *buf, int buf_size,
174 int t, const char *varstr)
175{
176 int bt;
177 Sym *s, *sa;
178 char buf1[256];
179 const char *tstr;
180
181 t = t & VT_TYPE;
182 bt = t & VT_BTYPE;
183 buf[0] = '\0';
184 if (t & VT_UNSIGNED)
185 pstrcat(buf, buf_size, "unsigned ");
186 switch(bt) {
187 case VT_VOID:
188 tstr = "void";
189 goto add_tstr;
190 case VT_BOOL:
191 tstr = "bool";
192 goto add_tstr;
193 case VT_BYTE:
194 tstr = "int8";
195 goto add_tstr;
196 case VT_SHORT:
197 tstr = "int16";
198 goto add_tstr;
199 case VT_ENUM:
200 case VT_INT:
201 case VT_LONG:
202 tstr = "int32";
203 goto add_tstr;
204 case VT_LLONG:
205 tstr = "int64";
206 goto add_tstr;
207 case VT_FLOAT:
208 tstr = "float32";
209 goto add_tstr;
210 case VT_DOUBLE:
211 case VT_LDOUBLE:
212 tstr = "float64";
213 add_tstr:
214 pstrcat(buf, buf_size, tstr);
215 break;
216 case VT_STRUCT:
217 tcc_error("structures not handled yet");
218 break;
219 case VT_FUNC:
220 s = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
221 if (s == NULL)
222 break;
223 il_type_to_str(buf, buf_size, s->type.t, varstr);
224 pstrcat(buf, buf_size, "(");
225 sa = s->next;
226 while (sa != NULL) {
227 il_type_to_str(buf1, sizeof(buf1), sa->type.t, NULL);
228 pstrcat(buf, buf_size, buf1);
229 sa = sa->next;
230 if (sa)
231 pstrcat(buf, buf_size, ", ");
232 }
233 pstrcat(buf, buf_size, ")");
234 goto no_var;
235 case VT_PTR:
236 s = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
237 if (s == NULL)
238 break;
239 pstrcpy(buf1, sizeof(buf1), "*");
240 if (varstr)
241 pstrcat(buf1, sizeof(buf1), varstr);
242 il_type_to_str(buf, buf_size, s->type.t, buf1);
243 goto no_var;
244 }
245 if (varstr) {
246 pstrcat(buf, buf_size, " ");
247 pstrcat(buf, buf_size, varstr);
248 }
249 no_var: ;
250}
251
252#define Reloc void
253/* patch relocation entry with value 'val' */
254void greloc_patch1(Reloc *p, int val)
255{
256}
257
258/* output a symbol and patch all calls to it */
259void gsym_addr(t, a)
260{
261}
262
263/* output jump and return symbol */
264static int out_opj(int op, int c)
265{
266 out_op1(op);
267 out_le32(0);
268 if (c == 0) {
269 c = ind - (int)cur_text_section->data;
270 }
271 fprintf(il_outfile, " %s L%d\n", il_opcodes_str[op], c);
272 return c;
273}
274
275void gsym(int t)
276{
277 fprintf(il_outfile, "L%d:\n", t);
278}
279
280/* load 'r' from value 'sv' */
281void load(int r, SValue *sv)
282{
283 int v, fc, ft;
284
285 v = sv->r & VT_VALMASK;
286 fc = sv->c.i;
287 ft = sv->type.t;
288
289 if (sv->r & VT_LVAL) {
290 if (v == VT_LOCAL) {
291 if (fc >= ARG_BASE) {
292 fc -= ARG_BASE;
293 if (fc >= 0 && fc <= 4) {
294 out_op(IL_OP_LDARG_0 + fc);
295 } else if (fc <= 0xff) {
296 out_opb(IL_OP_LDARG_S, fc);
297 } else {
298 out_opi(IL_OP_LDARG, fc);
299 }
300 } else {
301 if (fc >= 0 && fc <= 4) {
302 out_op(IL_OP_LDLOC_0 + fc);
303 } else if (fc <= 0xff) {
304 out_opb(IL_OP_LDLOC_S, fc);
305 } else {
306 out_opi(IL_OP_LDLOC, fc);
307 }
308 }
309 } else if (v == VT_CONST) {
310 /* XXX: handle globals */
311 out_opi(IL_OP_LDSFLD, 0);
312 } else {
313 if ((ft & VT_BTYPE) == VT_FLOAT) {
314 out_op(IL_OP_LDIND_R4);
315 } else if ((ft & VT_BTYPE) == VT_DOUBLE) {
316 out_op(IL_OP_LDIND_R8);
317 } else if ((ft & VT_BTYPE) == VT_LDOUBLE) {
318 out_op(IL_OP_LDIND_R8);
319 } else if ((ft & VT_TYPE) == VT_BYTE)
320 out_op(IL_OP_LDIND_I1);
321 else if ((ft & VT_TYPE) == (VT_BYTE | VT_UNSIGNED))
322 out_op(IL_OP_LDIND_U1);
323 else if ((ft & VT_TYPE) == VT_SHORT)
324 out_op(IL_OP_LDIND_I2);
325 else if ((ft & VT_TYPE) == (VT_SHORT | VT_UNSIGNED))
326 out_op(IL_OP_LDIND_U2);
327 else
328 out_op(IL_OP_LDIND_I4);
329 }
330 } else {
331 if (v == VT_CONST) {
332 /* XXX: handle globals */
333 if (fc >= -1 && fc <= 8) {
334 out_op(IL_OP_LDC_I4_M1 + fc + 1);
335 } else {
336 out_opi(IL_OP_LDC_I4, fc);
337 }
338 } else if (v == VT_LOCAL) {
339 if (fc >= ARG_BASE) {
340 fc -= ARG_BASE;
341 if (fc <= 0xff) {
342 out_opb(IL_OP_LDARGA_S, fc);
343 } else {
344 out_opi(IL_OP_LDARGA, fc);
345 }
346 } else {
347 if (fc <= 0xff) {
348 out_opb(IL_OP_LDLOCA_S, fc);
349 } else {
350 out_opi(IL_OP_LDLOCA, fc);
351 }
352 }
353 } else {
354 /* XXX: do it */
355 }
356 }
357}
358
359/* store register 'r' in lvalue 'v' */
360void store(int r, SValue *sv)
361{
362 int v, fc, ft;
363
364 v = sv->r & VT_VALMASK;
365 fc = sv->c.i;
366 ft = sv->type.t;
367 if (v == VT_LOCAL) {
368 if (fc >= ARG_BASE) {
369 fc -= ARG_BASE;
370 /* XXX: check IL arg store semantics */
371 if (fc <= 0xff) {
372 out_opb(IL_OP_STARG_S, fc);
373 } else {
374 out_opi(IL_OP_STARG, fc);
375 }
376 } else {
377 if (fc >= 0 && fc <= 4) {
378 out_op(IL_OP_STLOC_0 + fc);
379 } else if (fc <= 0xff) {
380 out_opb(IL_OP_STLOC_S, fc);
381 } else {
382 out_opi(IL_OP_STLOC, fc);
383 }
384 }
385 } else if (v == VT_CONST) {
386 /* XXX: handle globals */
387 out_opi(IL_OP_STSFLD, 0);
388 } else {
389 if ((ft & VT_BTYPE) == VT_FLOAT)
390 out_op(IL_OP_STIND_R4);
391 else if ((ft & VT_BTYPE) == VT_DOUBLE)
392 out_op(IL_OP_STIND_R8);
393 else if ((ft & VT_BTYPE) == VT_LDOUBLE)
394 out_op(IL_OP_STIND_R8);
395 else if ((ft & VT_BTYPE) == VT_BYTE)
396 out_op(IL_OP_STIND_I1);
397 else if ((ft & VT_BTYPE) == VT_SHORT)
398 out_op(IL_OP_STIND_I2);
399 else
400 out_op(IL_OP_STIND_I4);
401 }
402}
403
404/* start function call and return function call context */
405void gfunc_start(GFuncContext *c, int func_call)
406{
407 c->func_call = func_call;
408}
409
410/* push function parameter which is in (vtop->t, vtop->c). Stack entry
411 is then popped. */
412void gfunc_param(GFuncContext *c)
413{
414 if ((vtop->type.t & VT_BTYPE) == VT_STRUCT) {
415 tcc_error("structures passed as value not handled yet");
416 } else {
417 /* simply push on stack */
418 gv(RC_ST0);
419 }
420 vtop--;
421}
422
423/* generate function call with address in (vtop->t, vtop->c) and free function
424 context. Stack entry is popped */
425void gfunc_call(GFuncContext *c)
426{
427 char buf[1024];
428
429 if ((vtop->r & (VT_VALMASK | VT_LVAL)) == VT_CONST) {
430 /* XXX: more info needed from tcc */
431 il_type_to_str(buf, sizeof(buf), vtop->type.t, "xxx");
432 fprintf(il_outfile, " call %s\n", buf);
433 } else {
434 /* indirect call */
435 gv(RC_INT);
436 il_type_to_str(buf, sizeof(buf), vtop->type.t, NULL);
437 fprintf(il_outfile, " calli %s\n", buf);
438 }
439 vtop--;
440}
441
442/* generate function prolog of type 't' */
443void gfunc_prolog(int t)
444{
445 int addr, u, func_call;
446 Sym *sym;
447 char buf[1024];
448
449 init_outfile();
450
451 /* XXX: pass function name to gfunc_prolog */
452 il_type_to_str(buf, sizeof(buf), t, funcname);
453 fprintf(il_outfile, ".method static %s il managed\n", buf);
454 fprintf(il_outfile, "{\n");
455 /* XXX: cannot do better now */
456 fprintf(il_outfile, " .maxstack %d\n", NB_REGS);
457 fprintf(il_outfile, " .locals (int32, int32, int32, int32, int32, int32, int32, int32)\n");
458
459 if (!strcmp(funcname, "main"))
460 fprintf(il_outfile, " .entrypoint\n");
461
462 sym = sym_find((unsigned)t >> VT_STRUCT_SHIFT);
463 if (sym == NULL)
464 return;
465
466 addr = ARG_BASE;
467 /* if the function returns a structure, then add an
468 implicit pointer parameter */
469 func_vt = sym->type;
470 if ((func_vt.t & VT_BTYPE) == VT_STRUCT) {
471 func_vc = addr;
472 addr++;
473 }
474 /* define parameters */
475 while ((sym = sym->next) != NULL) {
476 u = sym->type.t;
477 sym_push(sym->v & ~SYM_FIELD, u,
478 VT_LOCAL | lvalue_type(sym->type.t), addr);
479 addr++;
480 }
481}
482
483/* generate function epilog */
484void gfunc_epilog(void)
485{
486 out_op(IL_OP_RET);
487 fprintf(il_outfile, "}\n\n");
488}
489
490/* generate a jump to a label */
491int gjmp(int t)
492{
493 return out_opj(IL_OP_BR, t);
494}
495
496/* generate a jump to a fixed address */
497void gjmp_addr(int a)
498{
499 /* XXX: handle syms */
500 out_opi(IL_OP_BR, a);
501}
502
503/* generate a test. set 'inv' to invert test. Stack entry is popped */
504int gtst(int inv, int t)
505{
506 int v, *p, c;
507
508 v = vtop->r & VT_VALMASK;
509 if (v == VT_CMP) {
510 c = vtop->c.i ^ inv;
511 switch(c) {
512 case TOK_EQ:
513 c = IL_OP_BEQ;
514 break;
515 case TOK_NE:
516 c = IL_OP_BNE_UN;
517 break;
518 case TOK_LT:
519 c = IL_OP_BLT;
520 break;
521 case TOK_LE:
522 c = IL_OP_BLE;
523 break;
524 case TOK_GT:
525 c = IL_OP_BGT;
526 break;
527 case TOK_GE:
528 c = IL_OP_BGE;
529 break;
530 case TOK_ULT:
531 c = IL_OP_BLT_UN;
532 break;
533 case TOK_ULE:
534 c = IL_OP_BLE_UN;
535 break;
536 case TOK_UGT:
537 c = IL_OP_BGT_UN;
538 break;
539 case TOK_UGE:
540 c = IL_OP_BGE_UN;
541 break;
542 }
543 t = out_opj(c, t);
544 } else if (v == VT_JMP || v == VT_JMPI) {
545 /* && or || optimization */
546 if ((v & 1) == inv) {
547 /* insert vtop->c jump list in t */
548 p = &vtop->c.i;
549 while (*p != 0)
550 p = (int *)*p;
551 *p = t;
552 t = vtop->c.i;
553 } else {
554 t = gjmp(t);
555 gsym(vtop->c.i);
556 }
557 } else {
558 if (is_float(vtop->type.t)) {
559 vpushi(0);
560 gen_op(TOK_NE);
561 }
562#define VT_FORWARD 0
563 if ((vtop->r & (VT_VALMASK | VT_LVAL | VT_FORWARD)) == VT_CONST) {
564 /* constant jmp optimization */
565 if ((vtop->c.i != 0) != inv)
566 t = gjmp(t);
567 } else {
568 v = gv(RC_INT);
569 t = out_opj(IL_OP_BRTRUE - inv, t);
570 }
571 }
572 vtop--;
573 return t;
574}
575
576/* generate an integer binary operation */
577void gen_opi(int op)
578{
579 gv2(RC_ST1, RC_ST0);
580 switch(op) {
581 case '+':
582 out_op(IL_OP_ADD);
583 goto std_op;
584 case '-':
585 out_op(IL_OP_SUB);
586 goto std_op;
587 case '&':
588 out_op(IL_OP_AND);
589 goto std_op;
590 case '^':
591 out_op(IL_OP_XOR);
592 goto std_op;
593 case '|':
594 out_op(IL_OP_OR);
595 goto std_op;
596 case '*':
597 out_op(IL_OP_MUL);
598 goto std_op;
599 case TOK_SHL:
600 out_op(IL_OP_SHL);
601 goto std_op;
602 case TOK_SHR:
603 out_op(IL_OP_SHR_UN);
604 goto std_op;
605 case TOK_SAR:
606 out_op(IL_OP_SHR);
607 goto std_op;
608 case '/':
609 case TOK_PDIV:
610 out_op(IL_OP_DIV);
611 goto std_op;
612 case TOK_UDIV:
613 out_op(IL_OP_DIV_UN);
614 goto std_op;
615 case '%':
616 out_op(IL_OP_REM);
617 goto std_op;
618 case TOK_UMOD:
619 out_op(IL_OP_REM_UN);
620 std_op:
621 vtop--;
622 vtop[0].r = REG_ST0;
623 break;
624 case TOK_EQ:
625 case TOK_NE:
626 case TOK_LT:
627 case TOK_LE:
628 case TOK_GT:
629 case TOK_GE:
630 case TOK_ULT:
631 case TOK_ULE:
632 case TOK_UGT:
633 case TOK_UGE:
634 vtop--;
635 vtop[0].r = VT_CMP;
636 vtop[0].c.i = op;
637 break;
638 }
639}
640
641/* generate a floating point operation 'v = t1 op t2' instruction. The
642 two operands are guaranted to have the same floating point type */
643void gen_opf(int op)
644{
645 /* same as integer */
646 gen_opi(op);
647}
648
649/* convert integers to fp 't' type. Must handle 'int', 'unsigned int'
650 and 'long long' cases. */
651void gen_cvt_itof(int t)
652{
653 gv(RC_ST0);
654 if (t == VT_FLOAT)
655 out_op(IL_OP_CONV_R4);
656 else
657 out_op(IL_OP_CONV_R8);
658}
659
660/* convert fp to int 't' type */
661/* XXX: handle long long case */
662void gen_cvt_ftoi(int t)
663{
664 gv(RC_ST0);
665 switch(t) {
666 case VT_INT | VT_UNSIGNED:
667 out_op(IL_OP_CONV_U4);
668 break;
669 case VT_LLONG:
670 out_op(IL_OP_CONV_I8);
671 break;
672 case VT_LLONG | VT_UNSIGNED:
673 out_op(IL_OP_CONV_U8);
674 break;
675 default:
676 out_op(IL_OP_CONV_I4);
677 break;
678 }
679}
680
681/* convert from one floating point type to another */
682void gen_cvt_ftof(int t)
683{
684 gv(RC_ST0);
685 if (t == VT_FLOAT) {
686 out_op(IL_OP_CONV_R4);
687 } else {
688 out_op(IL_OP_CONV_R8);
689 }
690}
691
692void ggoto(void) { }
693void gen_bounded_ptr_add(void) {}
694void gen_bounded_ptr_deref(int t) {}
695void gen_expr32(void) {}
696void asm_opcode(TCCState *s1, int opcode) {}
697void asm_compute_constraints(ASMOperand *operands,
698 int nb_operands, int nb_outputs,
699 const uint8_t *clobber_regs,
700 int *pout_reg) {}
701void subst_asm_operand(CString *add_str,
702 SValue *sv, int modifier) {}
703void asm_gen_code(ASMOperand *operands, int nb_operands,
704 int nb_outputs, int is_output,
705 uint8_t *clobber_regs,
706 int out_reg) {}
707void asm_clobber(uint8_t *clobber_regs, const char *str) {}
708void gen_le32(int c) {}
709void g(int c) {}
710void gen_le16(int v) {}
711
712/* end of CIL code generator */
713/*************************************************************/
714#endif
715/*************************************************************/
Note: See TracBrowser for help on using the repository browser.