1 /****************************************************************************
2 * Copyright (C) 2009 by Matteo Franchin *
3 * *
4 * This file is part of Box. *
5 * *
6 * Box is free software: you can redistribute it and/or modify it *
7 * under the terms of the GNU Lesser General Public License as published *
8 * by the Free Software Foundation, either version 3 of the License, or *
9 * (at your option) any later version. *
10 * *
11 * Box 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 *
14 * GNU 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 Box. If not, see <http://www.gnu.org/licenses/>. *
18 ****************************************************************************/
19
20 #include <stdarg.h>
21 #include <assert.h>
22
23 #include "types.h"
24 #include "mem.h"
25 #include "messages.h"
26 #include "vm_priv.h"
27 #include "vmsym.h"
28 #include "vmproc.h"
29 #include "vmsymstuff.h"
30 #include "container.h"
31 #include "registers.h"
32
33 #include "vmcode.h"
34 #include "compiler_priv.h"
35
36 /* Function called to begin for BOXVMCODETYPE_MAIN or BOXVMCODETYPE_SUB */
My_Proc_Begin(BoxVMCode * p)37 static void My_Proc_Begin(BoxVMCode *p) {
38 BoxVMProcID proc_id, previous_target;
39 BoxVMSymID sym_id;
40
41 /* Assemble the newc, newi, ... instructions */
42 proc_id = BoxVMCode_Get_ProcID(p);
43 previous_target = BoxVM_Proc_Target_Set(p->cmp->vm, proc_id);
44 ASSERT_TASK(BoxVMSym_Assemble_Proc_Head(p->cmp->vm, & sym_id));
45
46 if (p->style == BOXVMCODESTYLE_SUB) {
47 /* If this is a subprocedure then we need to get parent and child
48 * from global registers and put them into local registers, so they can
49 * be utilised later.
50 */
51 if (p->have.parent) {
52 p->reg_parent = Reg_Occupy(& p->reg_alloc, BOXTYPEID_PTR);
53 BoxVM_Assemble(p->cmp->vm, BOXOP_SHIFT_OO,
54 BOXOPARGFORM_LREG, p->reg_parent,
55 BOXOPARGFORM_GREG, (BoxInt) 1);
56 }
57
58 if (p->have.child) {
59 p->reg_child = Reg_Occupy(& p->reg_alloc, BOXTYPEID_PTR);
60 BoxVM_Assemble(p->cmp->vm, BOXOP_SHIFT_OO,
61 BOXOPARGFORM_LREG, p->reg_child,
62 BOXOPARGFORM_GREG, (BoxInt) 2);
63 }
64 }
65
66 (void) BoxVM_Proc_Target_Set(p->cmp->vm, previous_target);
67
68 p->have.head = 1;
69 p->head_sym_id = sym_id;
70 }
71
72 /* Function called to end for BOXVMCODETYPE_MAIN or BOXVMCODETYPE_SUB */
My_Proc_End(BoxVMCode * p)73 static void My_Proc_End(BoxVMCode *p) {
74 BoxVMProcID proc_id, previous_target;
75
76 if (p->have.head) {
77 RegAlloc *ra = BoxVMCode_Get_RegAlloc(p);
78 BoxInt num_reg[NUM_TYPES], num_var[NUM_TYPES];
79
80 /* Global registers are allocated only for main */
81 if (p->style == BOXVMCODESTYLE_MAIN) {
82 Reg_Get_Global_Nums(ra, num_reg, num_var);
83 ASSERT_TASK( BoxVM_Alloc_Global_Regs(p->cmp->vm, num_var, num_reg) );
84 }
85
86 /* Local register should be allocated anyway */
87 Reg_Get_Local_Nums(ra, num_reg, num_var);
88 ASSERT_TASK(BoxVMSym_Def_Proc_Head(p->cmp->vm, p->head_sym_id,
89 num_var, num_reg));
90
91 }
92
93 proc_id = BoxVMCode_Get_ProcID(p);
94 previous_target = BoxVM_Proc_Target_Set(p->cmp->vm, proc_id);
95 BoxVM_Assemble(p->cmp->vm, BOXOP_RET);
96 (void) BoxVM_Proc_Target_Set(p->cmp->vm, previous_target);
97 }
98
BoxVMCode_Init(BoxVMCode * p,BoxCmp * c,BoxVMCodeStyle style)99 void BoxVMCode_Init(BoxVMCode *p, BoxCmp *c, BoxVMCodeStyle style) {
100 p->style = style;
101 p->cmp = c;
102 p->have.parent = 0;
103 p->have.child = 0;
104 p->have.reg_alloc = 0;
105 p->have.proc_id = 0;
106 p->have.proc_name = 0;
107 p->have.alter_name = 0;
108 p->have.call_num = 0;
109 p->have.wrote_beg = 0;
110 p->have.wrote_end = 0;
111 p->have.installed = 0;
112 p->have.head = 0;
113 p->perm.proc_id = 1;
114 p->beginning = NULL;
115 p->ending = NULL;
116
117 switch(style) {
118 case BOXVMCODESTYLE_PLAIN:
119 break;
120 case BOXVMCODESTYLE_SUB:
121 case BOXVMCODESTYLE_MAIN:
122 p->beginning = My_Proc_Begin;
123 p->ending = My_Proc_End;
124 (void) BoxVMCode_Get_RegAlloc(p); /* Force initialisation
125 of register allocator */
126 break;
127 case BOXVMCODESTYLE_EXTERN:
128 p->perm.proc_id = 0; /* Deny permission to create proc_id */
129 break;
130 default:
131 MSG_FATAL("BoxVMCode_Init: Invalid value for style (BoxVMCodeStyle).");
132 assert(0);
133 }
134
135 p->have.callable = 0;
136 p->callable = NULL;
137 }
138
BoxVMCode_Finish(BoxVMCode * p)139 void BoxVMCode_Finish(BoxVMCode *p) {
140 if (p->have.callable)
141 (void) BoxCallable_Unlink(p->callable);
142 if (p->have.proc_name)
143 Box_Mem_Free(p->proc_name);
144 if (p->have.alter_name)
145 Box_Mem_Free(p->alter_name);
146 if (p->have.reg_alloc)
147 Reg_Finish(& p->reg_alloc);
148 }
149
BoxVMCode_Set_Callable(BoxVMCode * p,BoxCallable * cb)150 void BoxVMCode_Set_Callable(BoxVMCode *p, BoxCallable *cb) {
151 if (p->have.callable)
152 (void) BoxCallable_Unlink(cb);
153
154 p->callable = BoxCallable_Link(cb);
155 p->have.callable = 1;
156 }
157
BoxVMCode_Create(BoxCmp * c,BoxVMCodeStyle style)158 BoxVMCode *BoxVMCode_Create(BoxCmp *c, BoxVMCodeStyle style) {
159 BoxVMCode *p = Box_Mem_Alloc(sizeof(BoxVMCode));
160 if (p == NULL) return NULL;
161 BoxVMCode_Init(p, c, style);
162 return p;
163 }
164
BoxVMCode_Destroy(BoxVMCode * p)165 void BoxVMCode_Destroy(BoxVMCode *p) {
166 BoxVMCode_Finish(p);
167 Box_Mem_Free(p);
168 }
169
BoxVMCode_Begin(BoxVMCode * p)170 void BoxVMCode_Begin(BoxVMCode *p) {
171 if (p->beginning != NULL && p->have.wrote_beg == 0) {
172 p->beginning(p);
173 p->have.wrote_beg = 1;
174 }
175 }
176
BoxVMCode_End(BoxVMCode * p)177 void BoxVMCode_End(BoxVMCode *p) {
178 if (p->ending != NULL && p->have.wrote_end == 0) {
179 p->ending(p);
180 p->have.wrote_end = 1;
181 }
182 }
183
BoxVMCode_Set_Prototype(BoxVMCode * p,int have_child,int have_parent)184 void BoxVMCode_Set_Prototype(BoxVMCode *p, int have_child, int have_parent) {
185 if (p->have.wrote_beg) {
186 MSG_WARNING("BoxVMCode_Set_Prototype: cannot change the prototype for "
187 "the procedure: the procedure has been already generated!");
188
189 } else if (p->style != BOXVMCODESTYLE_SUB) {
190 MSG_WARNING("BoxVMCode_Set_Prototype: the prototype can be set only for "
191 "BOXVMCODESTYLE_SUB.");
192 }
193
194 p->have.parent = have_parent;
195 p->have.child = have_child;
196 }
197
BoxVMCode_Get_Parent_Reg(BoxVMCode * p)198 BoxVMRegNum BoxVMCode_Get_Parent_Reg(BoxVMCode *p) {
199 if (!p->have.wrote_beg)
200 BoxVMCode_Begin(p);
201
202 if (p->have.parent)
203 return p->reg_parent;
204
205 MSG_FATAL("BoxVMCode_Get_Parent_Reg: procedure does not have the parent.");
206 assert(0);
207 return 0;
208 }
209
BoxVMCode_Get_Child_Reg(BoxVMCode * p)210 BoxVMRegNum BoxVMCode_Get_Child_Reg(BoxVMCode *p) {
211 if (!p->have.wrote_beg)
212 BoxVMCode_Begin(p);
213
214 if (p->have.child)
215 return p->reg_child;
216
217 MSG_FATAL("BoxVMCode_Get_Child_Reg: procedure does not have the child.");
218 assert(0);
219 return 0;
220 }
221
BoxVMCode_Get_Style(BoxVMCode * p)222 BoxVMCodeStyle BoxVMCode_Get_Style(BoxVMCode *p) {
223 return p->style;
224 }
225
BoxVMCode_Get_RegAlloc(BoxVMCode * p)226 RegAlloc *BoxVMCode_Get_RegAlloc(BoxVMCode *p) {
227 if (p->have.reg_alloc)
228 return & p->reg_alloc;
229
230 else {
231 Reg_Init(& p->reg_alloc);
232 p->have.reg_alloc = 1;
233 return & p->reg_alloc;
234 }
235 }
236
BoxVMCode_Get_ProcID(BoxVMCode * p)237 BoxVMProcID BoxVMCode_Get_ProcID(BoxVMCode *p) {
238 if (!p->perm.proc_id) {
239 MSG_FATAL("BoxVMCode_Get_ProcID: operation not permitted.");
240 assert(0);
241 }
242
243 if (p->have.proc_id)
244 return p->proc_id;
245
246 else {
247 p->have.proc_id = 1;
248 p->proc_id = BoxVM_Proc_Code_New(p->cmp->vm);
249 return p->proc_id;
250 }
251 }
252
BoxVMCode_Set_Alter_Name(BoxVMCode * p,const char * alter_name)253 void BoxVMCode_Set_Alter_Name(BoxVMCode *p, const char *alter_name) {
254 if (p->have.installed) {
255 MSG_FATAL("Too late to set the alternative name \"%s\"! "
256 "The procedure has already been installed using \"%s\".",
257 alter_name, p->alter_name);
258 assert(0);
259 }
260
261 if (p->have.alter_name)
262 Box_Mem_Free(p->alter_name);
263
264 p->alter_name = Box_Mem_Strdup(alter_name);
265 p->have.alter_name = 1;
266 }
267
BoxVMCode_Get_Alter_Name(BoxVMCode * p)268 char *BoxVMCode_Get_Alter_Name(BoxVMCode *p) {
269 /* The description is just a help string to make the ASM more readable
270 * (may disappear in the future). For now it is:
271 * - the type of the procedure, if this is known;
272 * - the name of the procedure, if this is known;
273 * - "|unknown|"
274 */
275 if (p->have.alter_name)
276 return Box_Mem_Strdup(p->alter_name);
277
278 else
279 return Box_Mem_Strdup((p->have.proc_name) ? p->proc_name : "|unknown|");
280 }
281
BoxVMCode_Get_Code_Size(BoxVMCode * p)282 size_t BoxVMCode_Get_Code_Size(BoxVMCode *p) {
283 return (p->have.proc_id) ? BoxVM_Proc_Get_Size(p->cmp->vm, p->proc_id) : 0;
284 }
285
BoxVMCode_Get_Call_Num(BoxVMCode * p)286 BoxVMCallNum BoxVMCode_Get_Call_Num(BoxVMCode *p) {
287 if (p->have.call_num)
288 return p->call_num;
289
290 else {
291 p->call_num = BoxVM_Allocate_Call_Num(p->cmp->vm);
292 p->have.call_num = 1;
293 return p->call_num;
294 }
295 }
296
BoxVMCode_Install(BoxVMCode * p)297 BoxVMCallNum BoxVMCode_Install(BoxVMCode *p) {
298 if (p->style == BOXVMCODESTYLE_EXTERN) {
299 MSG_FATAL("BoxVMCode_Install: Case BOXVMCODESTYLE_EXTERN "
300 "not implemented!");
301 return BOXVMCALLNUM_NONE;
302
303 } else if (!p->have.installed) {
304 BoxVMProcID pn = BoxVMCode_Get_ProcID(p);
305 char *alter_name,
306 *proc_name = (p->have.proc_name) ? p->proc_name : NULL;
307 BoxVMCode_End(p); /* End the procedure, if not done explicitly */
308
309 if (!p->have.call_num) {
310 p->call_num = BoxVM_Allocate_Call_Num(p->cmp->vm);
311 p->have.call_num = 1;
312 }
313
314 if (p->call_num == BOXVMCALLNUM_NONE)
315 return BOXVMCALLNUM_NONE;
316
317 if (!BoxVM_Install_Proc_Code(p->cmp->vm, p->call_num, pn)) {
318 (void) BoxVM_Deallocate_Call_Num(p->cmp->vm, p->call_num);
319 return BOXVMCALLNUM_NONE;
320 }
321
322 alter_name = BoxVMCode_Get_Alter_Name(p);
323 (void) BoxVM_Set_Proc_Names(p->cmp->vm, p->call_num,
324 proc_name, alter_name);
325 Box_Mem_Free(alter_name);
326
327 p->have.installed = 1;
328 return p->call_num;
329
330 } else {
331 assert(p->have.call_num);
332 return p->call_num;
333 }
334 }
335
BoxVMCode_Raw_VA_Assemble(BoxVMCode * p,BoxOpId op,va_list ap)336 void BoxVMCode_Raw_VA_Assemble(BoxVMCode *p, BoxOpId op, va_list ap) {
337 BoxVMProcID proc_id, previous_target;
338 BoxVMCode_Begin(p); /* Begin the procedure, if not done explicitly */
339 proc_id = BoxVMCode_Get_ProcID(p);
340 previous_target = BoxVM_Proc_Target_Set(p->cmp->vm, proc_id);
341 BoxVM_VA_Assemble(p->cmp->vm, op, ap);
342 (void) BoxVM_Proc_Target_Set(p->cmp->vm, previous_target);
343 }
344
BoxVMCode_Raw_Assemble(BoxVMCode * p,BoxOpId op,...)345 void BoxVMCode_Raw_Assemble(BoxVMCode *p, BoxOpId op, ...) {
346 va_list ap;
347 va_start(ap, op);
348 BoxVMCode_Raw_VA_Assemble(p, op, ap);
349 va_end(ap);
350 }
351
BoxVMCode_Assemble_Call(BoxVMCode * code,BoxVMCallNum call_num)352 void BoxVMCode_Assemble_Call(BoxVMCode *code, BoxVMCallNum call_num) {
353 BoxVMProcID proc_id, previous_target;
354 BoxVMCode_Begin(code); /* Begin the procedure, if not done explicitly */
355 proc_id = BoxVMCode_Get_ProcID(code);
356 previous_target = BoxVM_Proc_Target_Set(code->cmp->vm, proc_id);
357 BoxVM_Assemble(code->cmp->vm, BOXOP_CALL_I, BOXCONTCATEG_IMM, call_num);
358 (void) BoxVM_Proc_Target_Set(code->cmp->vm, previous_target);
359 }
360
361 /** Internal function used by My_Unsafe_Assemble to assemble operation
362 * involving pointer access (i.e. involving args like i[ro5+16]).
363 * This function is used when assembling things like:
364 *
365 * mov ro0, ro3 <-- this line is what we want to emit
366 * mov i[ro0+8], 45
367 */
My_Prepare_Ptr_Access(BoxVMCode * p,const BoxCont * c)368 static void My_Prepare_Ptr_Access(BoxVMCode *p, const BoxCont *c) {
369 BoxInt ptr_reg = c->value.ptr.reg;
370 if (c->categ == BOXCONTCATEG_PTR && (c->value.ptr.is_greg || ptr_reg != 0)) {
371 BoxInt categ = c->value.ptr.is_greg ? BOXCONTCATEG_GREG : BOXCONTCATEG_LREG;
372 BoxVMCode_Raw_Assemble(p, BOXOP_MOV_OO, BOXOPARGFORM_LREG, (BoxInt) 0,
373 categ, ptr_reg);
374 }
375 }
376
377 /** Internal function used by My_Unsafe_Assemble.
378 * Used to get the integer value of a container whose value is an integer.
379 * Containers having this property are: registers (both local and global)
380 * pointers and immediate integers/chars.
381 */
My_Int_Val_From_Cont(const BoxCont * c)382 static BoxInt My_Int_Val_From_Cont(const BoxCont *c) {
383 if (c->categ == BOXCONTCATEG_LREG || c->categ == BOXCONTCATEG_GREG)
384 return c->value.reg;
385
386 else if (c->categ == BOXCONTCATEG_PTR)
387 return c->value.ptr.offset;
388
389 else {
390 if (c->type == BOXCONTTYPE_CHAR)
391 return (BoxInt) c->value.imm.box_char;
392 else if (c->type == BOXCONTTYPE_INT)
393 return c->value.imm.box_int;
394 assert(0);
395 }
396 }
397
398 /** Internal function used by BoxVMCode_Assemble and co.
399 * Similar to BoxVMCode_Assemble, but works only in certain particular cases
400 * and does not check these are actually satisfied. In particular this
401 * function assumes that:
402 * - the operands pointed by cs[0] (and cs[1], if num_args == 2)
403 * are not both pointers, such as:
404 *
405 * cs[0] -> i[ro5+8] cs[1] -> i[ro6+16]
406 *
407 * - there are no immediates in the operands (such as cs[1] -> 1.2345).
408 * Moreover this function does not deal with implicit input/output registers.
409 */
My_Unsafe_Assemble(BoxVMCode * p,BoxOpId op,int num_args,const BoxCont ** cs)410 static void My_Unsafe_Assemble(BoxVMCode *p, BoxOpId op,
411 int num_args, const BoxCont **cs) {
412 assert(num_args >= 0 && num_args <= 2);
413 if (num_args == 0) {
414 BoxVMCode_Raw_Assemble(p, op);
415 return;
416
417 } else if (num_args == 1) {
418 const BoxCont *c1 = cs[0];
419 My_Prepare_Ptr_Access(p, c1);
420 if (c1->categ != BOXCONTCATEG_IMM) {
421 BoxInt c1_int_val = My_Int_Val_From_Cont(c1);
422 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1_int_val);
423 return;
424
425 } else {
426 switch(c1->type) {
427 case BOXCONTTYPE_CHAR:
428 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1->value.imm.box_char);
429 return;
430 case BOXCONTTYPE_INT:
431 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1->value.imm.box_int);
432 return;
433 case BOXCONTTYPE_REAL:
434 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1->value.imm.box_real);
435 return;
436 case BOXCONTTYPE_POINT:
437 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1->value.imm.box_point);
438 return;
439 default:
440 MSG_FATAL("My_Unsafe_Assemble: invalid type for immediate.");
441 assert(0);
442 }
443 }
444
445 } else {
446 const BoxCont *c1 = cs[0], *c2 = cs[1];
447
448 My_Prepare_Ptr_Access(p, c1);
449 My_Prepare_Ptr_Access(p, c2);
450
451 if (c2->categ != BOXCONTCATEG_IMM) {
452 BoxInt c1_int_val = My_Int_Val_From_Cont(c1),
453 c2_int_val = My_Int_Val_From_Cont(c2);
454
455 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1_int_val,
456 c2->categ, c2_int_val);
457 return;
458
459 } else {
460 BoxInt c1_int_val = (c1->categ == BOXCONTCATEG_PTR) ?
461 c1->value.ptr.offset : c1->value.reg;
462 switch(c1->type) {
463 case BOXCONTTYPE_CHAR:
464 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1_int_val,
465 c2->categ, c2->value.imm.box_char);
466 return;
467 case BOXCONTTYPE_INT:
468 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1_int_val,
469 c2->categ, c2->value.imm.box_int);
470 return;
471 case BOXCONTTYPE_REAL:
472 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1_int_val,
473 c2->categ, c2->value.imm.box_real);
474 return;
475 case BOXCONTTYPE_POINT:
476 BoxVMCode_Raw_Assemble(p, op, c1->categ, c1_int_val,
477 c2->categ, c2->value.imm.box_point);
478 return;
479 default:
480 MSG_FATAL("My_Unsafe_Assemble: invalid type for immediate.");
481 assert(0);
482 }
483 }
484
485 }
486 }
487
My_Gather_Implicit_Input_Regs(BoxVMCode * p,int num_regs,BoxOpReg * regs,const BoxCont ** args)488 static void My_Gather_Implicit_Input_Regs(BoxVMCode *p,
489 int num_regs, BoxOpReg *regs,
490 const BoxCont **args) {
491 int i;
492 for(i = 0; i < num_regs; i++) {
493 BoxOpReg *reg = & regs[i];
494 if (reg->kind == 'r') {
495 if (reg->io == 'i' || reg->io == 'b') {
496 const BoxCont *src = args[i];
497 BoxCont dst;
498
499 dst.type = BoxContType_From_Char(reg->type);
500 dst.categ = BOXCONTCATEG_LREG;
501 dst.value.reg = reg->num;
502
503 if (!(dst.categ == src->categ && dst.value.reg == src->value.reg))
504 BoxVMCode_Assemble(p, BOXGOP_MOV, 2, & dst, src);
505 }
506 }
507 }
508 }
509
My_Scatter_Implicit_Input_Regs(BoxVMCode * p,int num_regs,BoxOpReg * regs,const BoxCont ** args)510 static void My_Scatter_Implicit_Input_Regs(BoxVMCode *p,
511 int num_regs, BoxOpReg *regs,
512 const BoxCont **args) {
513 int i;
514 for(i = 0; i < num_regs; i++) {
515 BoxOpReg *reg = & regs[i];
516 if (reg->kind == 'r') {
517 if (reg->io == 'o' || reg->io == 'b') {
518 BoxTypeId t = BoxContType_From_Char(reg->type);
519 BoxGOp gop = (t == BOXTYPEID_PTR) ? BOXGOP_SHIFT : BOXGOP_MOV;
520 const BoxCont *dst = args[i];
521 BoxCont src;
522
523 src.type = t;
524 src.categ = BOXCONTCATEG_LREG;
525 src.value.reg = reg->num;
526
527 if (!(dst->categ == src.categ && dst->value.reg == src.value.reg))
528 BoxVMCode_Assemble(p, gop, 2, dst, & src);
529 }
530 }
531 }
532 }
533
534 typedef struct {
535 BoxOpInfo *oi;
536 int num_exp_args,
537 ro0_arg_conflict,
538 ro0_input_conflict;
539 const BoxCont *exp_args[2];
540 BoxCont aux_arg;
541 } MyFoundOp;
542
My_ContTypes_Match(BoxContType t1,BoxContType t2)543 int My_ContTypes_Match(BoxContType t1, BoxContType t2) {
544 return ((t1 == BOXCONTTYPE_OBJ) ? BOXCONTTYPE_PTR : t1)
545 == ((t2 == BOXCONTTYPE_OBJ) ? BOXCONTTYPE_PTR : t2);
546 }
547
My_Find_Op(BoxVMCode * p,MyFoundOp * info,BoxGOp g_op,int num_args,const BoxCont ** args,int ignore_signature)548 static BoxOpInfo *My_Find_Op(BoxVMCode *p, MyFoundOp *info, BoxGOp g_op,
549 int num_args, const BoxCont **args,
550 int ignore_signature) {
551 BoxOpInfo *oi;
552 int num_exp_args, ro0_arg_conflict, ro0_input_conflict;
553
554 /* Search for operations whose argument number and type match */
555 for(oi = BoxVM_Get_Op_Info(p->cmp->vm, g_op); oi; oi = oi->next) {
556 if (oi->num_regs == num_args) {
557 /* Consider only operations with matching arg number */
558 BoxOpSignature signature;
559 int i;
560
561 /* Now let's check for matching arg type and signature */
562 num_exp_args = 0;
563 ro0_arg_conflict = 0;
564 ro0_input_conflict = 0;
565 signature = BOXOPSIGNATURE_NONE;
566 for(i = 0; i < num_args; i++) {
567 BoxOpReg *reg = & oi->regs[i];
568 BoxContType t = BoxContType_From_Char(reg->type);
569 if (!My_ContTypes_Match(t, args[i]->type))
570 break; /* Exit if type for this arg does not match */
571
572 /* In the meanwhile we compute the signature: if types of args match
573 * then we'll have to check also for matching signature!
574 */
575 if (reg->kind == 'a') {
576 /* Explicit register */
577 int is_immediate;
578
579 assert(num_exp_args < 2);
580
581 info->exp_args[num_exp_args] = args[i];
582
583 /* We also start to take note about possible register conflicts */
584 ro0_arg_conflict += (args[i]->categ == BOXCONTCATEG_PTR);
585
586 is_immediate = (args[i]->categ == BOXCONTCATEG_IMM &&
587 args[i]->type != BOXCONTTYPE_INT &&
588 args[i]->type != BOXCONTTYPE_CHAR);
589 if (num_exp_args == 0)
590 signature = (is_immediate) ?
591 BOXOPSIGNATURE_IMM : BOXOPSIGNATURE_ANY;
592 else
593 signature = (is_immediate) ?
594 BOXOPSIGNATURE_ANY_IMM : BOXOPSIGNATURE_ANY_ANY;
595 ++num_exp_args;
596
597 } else {
598 /* Implicit register */
599 assert(reg->kind == 'r');
600 if (reg->type == 'o' && reg->num == 0)
601 ro0_input_conflict |= (reg->io == 'i' || reg->io == 'b');
602 }
603 }
604
605 if (i >= num_args && (signature == oi->signature || ignore_signature)) {
606 info->oi = oi;
607 info->num_exp_args = num_exp_args;
608 info->ro0_arg_conflict = ro0_arg_conflict;
609 info->ro0_input_conflict = ro0_input_conflict;
610 return oi;
611 }
612 }
613 }
614
615 info->oi = NULL;
616 return NULL;
617 }
618
619 static void
My_Load_Immediates(BoxVMCode * p,int num_regs,BoxOpReg * regs,const BoxCont ** args,MyFoundOp * op)620 My_Load_Immediates(BoxVMCode *p, int num_regs, BoxOpReg *regs,
621 const BoxCont **args, MyFoundOp *op) {
622 int i, j;
623 for(i = 0; i < num_regs; i++) {
624 const BoxCont *src = args[i];
625 BoxOpReg *reg = & regs[i];
626 if (src->categ == BOXCONTCATEG_IMM && (reg->io == 'i' || reg->io == 'b')) {
627 if (src->type == BOXCONTTYPE_INT && sizeof(BoxInt) > sizeof(int32_t)) {
628 BoxInt value = src->value.imm.box_int;
629 if (value != (BoxInt) ((int32_t) value)) {
630 BoxCont *ri0 = & op->aux_arg;
631
632 ri0->categ = BOXCONTCATEG_LREG;
633 ri0->type = BOXCONTTYPE_INT;
634 ri0->value.reg = 0;
635 BoxVMCode_Raw_Assemble(p, BOXOP_MOV_Iimm,
636 ri0->categ, ri0->value.reg,
637 BOXCONTCATEG_IMM, value);
638
639 /* Update references to the container. */
640 args[i] = ri0;
641 for (j = 0; j < op->num_exp_args; j++)
642 if (op->exp_args[j] == src)
643 op->exp_args[j] = ri0;
644 }
645 }
646 }
647 }
648 }
649
BoxVMCode_VA_Assemble(BoxVMCode * p,BoxGOp g_op,int num_args,va_list ap)650 void BoxVMCode_VA_Assemble(BoxVMCode *p, BoxGOp g_op, int num_args, va_list ap) {
651 const BoxCont *args[BOXOP_MAX_NUM_ARGS];
652 BoxOpInfo *oi;
653 MyFoundOp op;
654 int i;
655
656 if (num_args > BOXOP_MAX_NUM_ARGS) {
657 MSG_FATAL("BoxVMCode_Assemble: the given number of arguments is too high.");
658 assert(0);
659 }
660
661 for(i = 0; i < num_args; i++)
662 args[i] = va_arg(ap, BoxCont *);
663
664 /* Search for operations whose argument number and type match */
665 oi = My_Find_Op(p, & op, g_op, num_args, args, /*ignore_signature*/ 0);
666
667 if (oi == NULL) {
668 /* Try to search again ignoring the signature: it may be that an immediate
669 * value is being passed and that the operation doesn't allow immediate
670 * values. If this is the case we should move the immediate to a temporary
671 * register and retry
672 */
673 oi = My_Find_Op(p, & op, g_op, num_args, args, /*ignore_signature*/ 1);
674 if (oi == NULL) {
675 int i;
676 char *sep = "";
677 fprintf(stderr, "BoxVMCode_Assemble: cannot find a matching operation.\n");
678 fprintf(stderr, "Possible signatures are:\n");
679 BoxOpInfo_Print(stderr, BoxVM_Get_Op_Info(p->cmp->vm, g_op));
680 fprintf(stderr, "Got the following %d arguments: ", num_args);
681 for(i = 0; i < num_args; i++) {
682 fprintf(stderr, "%s%s", sep, BoxCont_To_String(args[i]));
683 sep = ", ";
684 }
685 fprintf(stderr, "\n");
686 MSG_FATAL("BoxVMCode_Assemble: aborting!");
687 assert(0);
688
689 } else {
690 /* This means that the first operation search failed because the last
691 * argument is an immediate
692 */
693 BoxCont r0;
694 r0.type = BoxContType_From_Char(oi->arg_type);
695 r0.categ = BOXCONTCATEG_LREG;
696 r0.value.reg = 0;
697 if (op.num_exp_args == 2) {
698 BoxVMCode_Assemble(p, BOXGOP_MOV, 2, & r0, op.exp_args[1]);
699 BoxVMCode_Assemble(p, g_op, 2, op.exp_args[0], & r0);
700
701 } else {
702 assert(op.num_exp_args == 1);
703 BoxVMCode_Assemble(p, BOXGOP_MOV, 2, & r0, op.exp_args[1]);
704 BoxVMCode_Assemble(p, g_op, 1, & r0);
705 }
706 return;
707 }
708 }
709
710 /* Make sure there are no conflicts between implicit and explicit
711 * registers. A conflict happens when an implicit input register appears
712 * also as explicit register or when an implicit output register appears
713 * also as explicit register (this case is practically excluded for now,
714 * as it happens to be there is no operation which has more than one
715 * output register).
716 * Example: jc ri0 (which doesn't make sense anyway)
717 * araddr 0, ri0
718 * These seem to be the only operations presenting such conflicts.
719 * It may then make sense not to check for it.
720 * NOTE: we assume the user does not fiddle with 0 registers: we do not
721 * catch things like "mov o[ro0+8], ro0"
722 * NOT DOING THIS FOR NOW!
723 */
724
725 /* Use separate load for immediates, if they are out of the admissible
726 * range.
727 */
728 My_Load_Immediates(p, num_args, oi->regs, args, & op);
729
730 /* Setting all the implicit input registers from the given arguments */
731 My_Gather_Implicit_Input_Regs(p, num_args, oi->regs, args);
732
733 if (!op.ro0_input_conflict) {
734 /* ro0 is not an implicit input register */
735 if (op.ro0_arg_conflict < 2) {
736 /* The arguments of the operation are not both pointers.
737 * A direct assembly is then possible:
738 *
739 * add ri5, ri6
740 *
741 * or:
742 *
743 * mov ro0, ro5
744 * add ri5, i[ro0+32]
745 */
746 My_Unsafe_Assemble(p, oi->opcode, op.num_exp_args, op.exp_args);
747
748 } else {
749 /* The argument of the operation are both pointers: we then have to
750 * be careful on how the ro0 register is used!
751 */
752 assert(op.num_exp_args == 2);
753 if (oi->arg_type != 'o') {
754 /* we can do something like:
755 *
756 * mov ro0, ro5
757 * mov ri0, i[ro0+8]
758 * mov ro0, ro6
759 * add i[ro0+16], ri0
760 */
761 BoxCont r0;
762 r0.type = BoxContType_From_Char(oi->arg_type);
763 r0.categ = BOXCONTCATEG_LREG;
764 r0.value.reg = 0;
765 /* Note exp_arg[1] is never an output register, so we can put it
766 * into a temporary register (the Box VM operations never have more
767 * than one output argument and when they have just one, then it is
768 * always exp_arg[0] and not exp_arg[1]).
769 */
770 BoxVMCode_Assemble(p, BOXGOP_MOV, 2, & r0, op.exp_args[1]);
771 op.exp_args[1] = & r0;
772 My_Unsafe_Assemble(p, oi->opcode, 2, op.exp_args);
773
774 } else {
775 /* we can do something like:
776 *
777 * push ro1
778 * mov ro0, ro5
779 * mov ro1, o[ro0+8]
780 * mov ro0, ro6
781 * pop ro1
782 */
783 BoxCont ro1;
784 const BoxCont *cs[1];
785 ro1.type = BOXCONTTYPE_PTR;
786 ro1.categ = BOXCONTCATEG_LREG;
787 ro1.value.reg = 1;
788 cs[0] = & ro1;
789 My_Unsafe_Assemble(p, BOXOP_PUSH_O, 1, cs);
790 BoxVMCode_Assemble(p, BOXGOP_MOV, 2, & ro1, op.exp_args[1]);
791 op.exp_args[1] = & ro1;
792 My_Unsafe_Assemble(p, oi->opcode, 2, op.exp_args);
793 My_Unsafe_Assemble(p, BOXOP_POP_O, 1, cs);
794 }
795 }
796
797 } else {
798 if (op.ro0_arg_conflict == 0)
799 My_Unsafe_Assemble(p, oi->opcode, op.num_exp_args, op.exp_args);
800
801 else if (op.ro0_arg_conflict == 1) {
802 /* ro0 is an implicit input register */
803 MSG_FATAL("ro0 is an implicit input register: not implemented yet!");
804 assert(0);
805
806 } else {
807 MSG_FATAL("too many register conflicts: not implemented yet!");
808 assert(0);
809 }
810 }
811
812 /* Distributing all the implicit output registers to the corresponding
813 * arguments
814 */
815 My_Scatter_Implicit_Input_Regs(p, num_args, oi->regs, args);
816 }
817
BoxVMCode_Assemble(BoxVMCode * p,BoxGOp g_op,int num_args,...)818 void BoxVMCode_Assemble(BoxVMCode *p, BoxGOp g_op, int num_args, ...) {
819 va_list ap;
820 va_start(ap, num_args);
821 BoxVMCode_VA_Assemble(p, g_op, num_args, ap);
822 va_end(ap);
823 }
824
BoxVMCode_Jump_Label_New(BoxVMCode * p)825 BoxVMSymID BoxVMCode_Jump_Label_New(BoxVMCode *p) {
826 return BoxVMSym_New_Label(p->cmp->vm);
827 }
828
BoxVMCode_Jump_Label_Here(BoxVMCode * p)829 BoxVMSymID BoxVMCode_Jump_Label_Here(BoxVMCode *p) {
830 BoxVMSymID jl = BoxVMCode_Jump_Label_New(p);
831 BoxVMCode_Jump_Label_Define(p, jl);
832 return jl;
833 }
834
835 /* Abbreviations for a few procedures sharing the same structure */
836 #define MY_ASSEMBLE_BEGIN() \
837 BoxVMProcID proc_id, previous_target; \
838 BoxVMCode_Begin(p); \
839 proc_id = BoxVMCode_Get_ProcID(p); \
840 previous_target = BoxVM_Proc_Target_Set(p->cmp->vm, proc_id)
841
842 #define MY_ASSEMBLE_END() \
843 (void) BoxVM_Proc_Target_Set(p->cmp->vm, previous_target)
844
BoxVMCode_Jump_Label_Define(BoxVMCode * p,BoxVMSymID jl)845 void BoxVMCode_Jump_Label_Define(BoxVMCode *p, BoxVMSymID jl) {
846 MY_ASSEMBLE_BEGIN();
847 ASSERT_TASK( BoxVMSym_Def_Label_Here(p->cmp->vm, jl) );
848 MY_ASSEMBLE_END();
849 }
850
BoxVMCode_Jump_Label_Release(BoxVMCode * p,BoxVMSymID jl)851 void BoxVMCode_Jump_Label_Release(BoxVMCode *p, BoxVMSymID jl) {
852 ASSERT_TASK( BoxVMSym_Release_Label(p->cmp->vm, jl) );
853 }
854
BoxVMCode_Assemble_Jump(BoxVMCode * p,BoxVMSymID jl)855 void BoxVMCode_Assemble_Jump(BoxVMCode *p, BoxVMSymID jl) {
856 MY_ASSEMBLE_BEGIN();
857 ASSERT_TASK( BoxVMSym_Jmp(p->cmp->vm, jl) );
858 MY_ASSEMBLE_END();
859 }
860
BoxVMCode_Assemble_CJump(BoxVMCode * p,BoxVMSymID jl,BoxCont * cont)861 void BoxVMCode_Assemble_CJump(BoxVMCode *p, BoxVMSymID jl, BoxCont *cont) {
862 BoxCont ri0_cont;
863 MY_ASSEMBLE_BEGIN();
864 BoxCont_Set(& ri0_cont, "ri", 0);
865 BoxVMCode_Assemble(p, BOXGOP_MOV, 2, & ri0_cont, cont);
866 ASSERT_TASK( BoxVMSym_Jc(p->cmp->vm, jl) );
867 MY_ASSEMBLE_END();
868 }
869
BoxVMCode_Associate_Source(BoxVMCode * p,BoxSrcPos * src_pos)870 void BoxVMCode_Associate_Source(BoxVMCode *p, BoxSrcPos *src_pos) {
871 BoxVM_Proc_Associate_Source(p->cmp->vm, BoxVMCode_Get_ProcID(p), src_pos);
872 }
873