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