]> git.karo-electronics.de Git - karo-tx-linux.git/blob - drivers/staging/ktap/userspace/code.c
Merge 3.12-rc6 into staging-next.
[karo-tx-linux.git] / drivers / staging / ktap / userspace / code.c
1 /*
2  * code.c - Code generator for ktap
3  *
4  * This file is part of ktap by Jovi Zhangwei.
5  *
6  * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
7  *
8  * Copyright (C) 1994-2013 Lua.org, PUC-Rio.
9  *  - The part of code in this file is copied from lua initially.
10  *  - lua's MIT license is compatible with GPL.
11  *
12  * ktap is free software; you can redistribute it and/or modify it
13  * under the terms and conditions of the GNU General Public License,
14  * version 2, as published by the Free Software Foundation.
15  *
16  * ktap is distributed in the hope it will be useful, but WITHOUT
17  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
19  * more details.
20  *
21  * You should have received a copy of the GNU General Public License along with
22  * this program; if not, write to the Free Software Foundation, Inc.,
23  * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
24  */
25
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "../include/ktap_types.h"
31 #include "../include/ktap_opcodes.h"
32 #include "ktapc.h"
33
34
35 #define hasjumps(e)     ((e)->t != (e)->f)
36
37 void codegen_patchtohere (ktap_funcstate *fs, int list);
38
39 static int isnumeral(ktap_expdesc *e)
40 {
41         return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
42 }
43
44 void codegen_nil(ktap_funcstate *fs, int from, int n)
45 {
46         ktap_instruction *previous;
47         int l = from + n - 1;  /* last register to set nil */
48
49         if (fs->pc > fs->lasttarget) {  /* no jumps to current position? */
50                 previous = &fs->f->code[fs->pc-1];
51                 if (GET_OPCODE(*previous) == OP_LOADNIL) {
52                         int pfrom = GETARG_A(*previous);
53                         int pl = pfrom + GETARG_B(*previous);
54
55                         if ((pfrom <= from && from <= pl + 1) ||
56                                 (from <= pfrom && pfrom <= l + 1)) {  /* can connect both? */
57                                 if (pfrom < from)
58                                         from = pfrom;  /* from = min(from, pfrom) */
59                                 if (pl > l)
60                                         l = pl;  /* l = max(l, pl) */
61                                 SETARG_A(*previous, from);
62                                 SETARG_B(*previous, l - from);
63                                 return;
64                         }
65                 }  /* else go through */
66         }
67         codegen_codeABC(fs, OP_LOADNIL, from, n - 1, 0);  /* else no optimization */
68 }
69
70 int codegen_jump(ktap_funcstate *fs)
71 {
72         int jpc = fs->jpc;  /* save list of jumps to here */
73         int j;
74
75         fs->jpc = NO_JUMP;
76         j = codegen_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
77         codegen_concat(fs, &j, jpc);  /* keep them on hold */
78         return j;
79 }
80
81 void codegen_ret(ktap_funcstate *fs, int first, int nret)
82 {
83         codegen_codeABC(fs, OP_RETURN, first, nret+1, 0);
84 }
85
86 static int condjump(ktap_funcstate *fs, OpCode op, int A, int B, int C)
87 {
88         codegen_codeABC(fs, op, A, B, C);
89         return codegen_jump(fs);
90 }
91
92 static void fixjump(ktap_funcstate *fs, int pc, int dest)
93 {
94         ktap_instruction *jmp = &fs->f->code[pc];
95         int offset = dest-(pc+1);
96
97         ktap_assert(dest != NO_JUMP);
98         if (abs(offset) > MAXARG_sBx)
99                 lex_syntaxerror(fs->ls, "control structure too long");
100         SETARG_sBx(*jmp, offset);
101 }
102
103 /*
104  * returns current `pc' and marks it as a jump target (to avoid wrong
105  * optimizations with consecutive instructions not in the same basic block).
106  */
107 int codegen_getlabel(ktap_funcstate *fs)
108 {
109         fs->lasttarget = fs->pc;
110         return fs->pc;
111 }
112
113 static int getjump(ktap_funcstate *fs, int pc)
114 {
115         int offset = GETARG_sBx(fs->f->code[pc]);
116
117         if (offset == NO_JUMP)  /* point to itself represents end of list */
118                 return NO_JUMP;  /* end of list */
119         else
120                 return (pc+1)+offset;  /* turn offset into absolute position */
121 }
122
123 static ktap_instruction *getjumpcontrol(ktap_funcstate *fs, int pc)
124 {
125         ktap_instruction *pi = &fs->f->code[pc];
126         if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
127                 return pi-1;
128         else
129                 return pi;
130 }
131
132 /*
133  * check whether list has any jump that do not produce a value
134  * (or produce an inverted value)
135  */
136 static int need_value(ktap_funcstate *fs, int list)
137 {
138         for (; list != NO_JUMP; list = getjump(fs, list)) {
139                 ktap_instruction i = *getjumpcontrol(fs, list);
140                 if (GET_OPCODE(i) != OP_TESTSET)
141                         return 1;
142         }
143         return 0;  /* not found */
144 }
145
146 static int patchtestreg(ktap_funcstate *fs, int node, int reg)
147 {
148         ktap_instruction *i = getjumpcontrol(fs, node);
149         if (GET_OPCODE(*i) != OP_TESTSET)
150                 return 0;  /* cannot patch other instructions */
151         if (reg != NO_REG && reg != GETARG_B(*i))
152                 SETARG_A(*i, reg);
153         else  /* no register to put value or register already has the value */
154                 *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
155
156         return 1;
157 }
158
159 static void removevalues(ktap_funcstate *fs, int list)
160 {
161         for (; list != NO_JUMP; list = getjump(fs, list))
162                 patchtestreg(fs, list, NO_REG);
163 }
164
165 static void patchlistaux(ktap_funcstate *fs, int list, int vtarget, int reg,
166                          int dtarget)
167 {
168         while (list != NO_JUMP) {
169                 int next = getjump(fs, list);
170                 if (patchtestreg(fs, list, reg))
171                         fixjump(fs, list, vtarget);
172                 else
173                         fixjump(fs, list, dtarget);  /* jump to default target */
174                 list = next;
175         }
176 }
177
178 static void dischargejpc(ktap_funcstate *fs)
179 {
180         patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
181         fs->jpc = NO_JUMP;
182 }
183
184 void codegen_patchlist(ktap_funcstate *fs, int list, int target)
185 {
186         if (target == fs->pc)
187                 codegen_patchtohere(fs, list);
188         else {
189                 ktap_assert(target < fs->pc);
190                 patchlistaux(fs, list, target, NO_REG, target);
191         }
192 }
193
194 void codegen_patchclose(ktap_funcstate *fs, int list, int level)
195 {
196         level++;  /* argument is +1 to reserve 0 as non-op */
197         while (list != NO_JUMP) {
198                 int next = getjump(fs, list);
199                 ktap_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
200                            (GETARG_A(fs->f->code[list]) == 0 ||
201                             GETARG_A(fs->f->code[list]) >= level));
202                 SETARG_A(fs->f->code[list], level);
203                 list = next;
204         }
205 }
206
207 void codegen_patchtohere(ktap_funcstate *fs, int list)
208 {
209         codegen_getlabel(fs);
210         codegen_concat(fs, &fs->jpc, list);
211 }
212
213 void codegen_concat(ktap_funcstate *fs, int *l1, int l2)
214 {
215         if (l2 == NO_JUMP)
216                 return;
217         else if (*l1 == NO_JUMP)
218                 *l1 = l2;
219         else {
220                 int list = *l1;
221                 int next;
222                 while ((next = getjump(fs, list)) != NO_JUMP)  /* find last element */
223                         list = next;
224                 fixjump(fs, list, l2);
225         }
226 }
227
228 static int codegen_code(ktap_funcstate *fs, ktap_instruction i)
229 {
230         ktap_proto *f = fs->f;
231
232         dischargejpc(fs);  /* `pc' will change */
233
234         /* put new instruction in code array */
235         ktapc_growvector(f->code, fs->pc, f->sizecode, ktap_instruction,
236                          MAX_INT, "opcodes");
237         f->code[fs->pc] = i;
238
239         /* save corresponding line information */
240         ktapc_growvector(f->lineinfo, fs->pc, f->sizelineinfo, int,
241                          MAX_INT, "opcodes");
242         f->lineinfo[fs->pc] = fs->ls->lastline;
243         return fs->pc++;
244 }
245
246 int codegen_codeABC(ktap_funcstate *fs, OpCode o, int a, int b, int c)
247 {
248         ktap_assert(getOpMode(o) == iABC);
249         //ktap_assert(getBMode(o) != OpArgN || b == 0);
250         //ktap_assert(getCMode(o) != OpArgN || c == 0);
251         //ktap_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
252         return codegen_code(fs, CREATE_ABC(o, a, b, c));
253 }
254
255 int codegen_codeABx(ktap_funcstate *fs, OpCode o, int a, unsigned int bc)
256 {
257         ktap_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
258         ktap_assert(getCMode(o) == OpArgN);
259         ktap_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
260         return codegen_code(fs, CREATE_ABx(o, a, bc));
261 }
262
263 static int codeextraarg(ktap_funcstate *fs, int a)
264 {
265         ktap_assert(a <= MAXARG_Ax);
266         return codegen_code(fs, CREATE_Ax(OP_EXTRAARG, a));
267 }
268
269 int codegen_codek(ktap_funcstate *fs, int reg, int k)
270 {
271         if (k <= MAXARG_Bx)
272                 return codegen_codeABx(fs, OP_LOADK, reg, k);
273         else {
274                 int p = codegen_codeABx(fs, OP_LOADKX, reg, 0);
275                 codeextraarg(fs, k);
276                 return p;
277         }
278 }
279
280 void codegen_checkstack(ktap_funcstate *fs, int n)
281 {
282         int newstack = fs->freereg + n;
283
284         if (newstack > fs->f->maxstacksize) {
285                 if (newstack >= MAXSTACK)
286                         lex_syntaxerror(fs->ls, "function or expression too complex");
287                 fs->f->maxstacksize = (u8)(newstack);
288         }
289 }
290
291 void codegen_reserveregs(ktap_funcstate *fs, int n)
292 {
293         codegen_checkstack(fs, n);
294         fs->freereg += n;
295 }
296
297 static void freereg(ktap_funcstate *fs, int reg)
298 {
299         if (!ISK(reg) && reg >= fs->nactvar) {
300                 fs->freereg--;
301                 ktap_assert(reg == fs->freereg);
302         }
303 }
304
305 static void freeexp(ktap_funcstate *fs, ktap_expdesc *e)
306 {
307         if (e->k == VNONRELOC)
308                 freereg(fs, e->u.info);
309 }
310
311 static int addk(ktap_funcstate *fs, ktap_value *key, ktap_value *v)
312 {
313         const ktap_value *idx = ktapc_table_get(fs->h, key);
314         ktap_proto *f = fs->f;
315         ktap_value kn;
316         int k, oldsize;
317
318         if (ttisnumber(idx)) {
319                 ktap_number n = nvalue(idx);
320                 ktap_number2int(k, n);
321                 if (ktapc_equalobj(&f->k[k], v))
322                         return k;
323                 /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0");
324                         go through and create a new entry for this value */
325         }
326         /* constant not found; create a new entry */
327         oldsize = f->sizek;
328         k = fs->nk;
329
330         /* numerical value does not need GC barrier;
331            table has no metatable, so it does not need to invalidate cache */
332         setnvalue(&kn, (ktap_number)k);
333         ktapc_table_setvalue(fs->h, key, &kn);
334         ktapc_growvector(f->k, k, f->sizek, ktap_value, MAXARG_Ax, "constants");
335         while (oldsize < f->sizek)
336                 setnilvalue(&f->k[oldsize++]);
337         setobj(&f->k[k], v);
338         fs->nk++;
339         return k;
340 }
341
342 int codegen_stringK(ktap_funcstate *fs, ktap_string *s)
343 {
344         ktap_value o;
345
346         setsvalue(&o, s);
347         return addk(fs, &o, &o);
348 }
349
350 int codegen_numberK(ktap_funcstate *fs, ktap_number r)
351 {
352         int n;
353         ktap_value o, s;
354
355         setnvalue(&o, r);
356         if (r == 0 || ktap_numisnan(NULL, r)) {  /* handle -0 and NaN */
357                 /* use raw representation as key to avoid numeric problems */
358                 setsvalue(&s, ktapc_ts_newlstr((char *)&r, sizeof(r)));
359                 //   incr_top(L);
360                 n = addk(fs, &s, &o);
361                 //   L->top--;
362         } else
363                 n = addk(fs, &o, &o);  /* regular case */
364         return n;
365 }
366
367 static int boolK(ktap_funcstate *fs, int b)
368 {
369         ktap_value o;
370         setbvalue(&o, b);
371         return addk(fs, &o, &o);
372 }
373
374 static int nilK(ktap_funcstate *fs)
375 {
376         ktap_value k, v;
377         setnilvalue(&v);
378         /* cannot use nil as key; instead use table itself to represent nil */
379         sethvalue(&k, fs->h);
380         return addk(fs, &k, &v);
381 }
382
383 void codegen_setreturns(ktap_funcstate *fs, ktap_expdesc *e, int nresults)
384 {
385         if (e->k == VCALL) {  /* expression is an open function call? */
386                 SETARG_C(getcode(fs, e), nresults+1);
387         }
388         else if (e->k == VVARARG) {
389                 SETARG_B(getcode(fs, e), nresults+1);
390                 SETARG_A(getcode(fs, e), fs->freereg);
391                 codegen_reserveregs(fs, 1);
392         }
393 }
394
395 void codegen_setoneret(ktap_funcstate *fs, ktap_expdesc *e)
396 {
397         if (e->k == VCALL) {  /* expression is an open function call? */
398                 e->k = VNONRELOC;
399                 e->u.info = GETARG_A(getcode(fs, e));
400         } else if (e->k == VVARARG) {
401                 SETARG_B(getcode(fs, e), 2);
402                 e->k = VRELOCABLE;  /* can relocate its simple result */
403         }
404 }
405
406 void codegen_dischargevars(ktap_funcstate *fs, ktap_expdesc *e)
407 {
408         switch (e->k) {
409         case VLOCAL: {
410                 e->k = VNONRELOC;
411                 break;
412         }
413         case VUPVAL: {
414                 e->u.info = codegen_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
415                 e->k = VRELOCABLE;
416                 break;
417         }
418         case VINDEXED: {
419                 OpCode op = OP_GETTABUP;  /* assume 't' is in an upvalue */
420                 freereg(fs, e->u.ind.idx);
421                 if (e->u.ind.vt == VLOCAL) {  /* 't' is in a register? */
422                         freereg(fs, e->u.ind.t);
423                         op = OP_GETTABLE;
424                 }
425                 e->u.info = codegen_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
426                 e->k = VRELOCABLE;
427                 break;
428         }
429         case VVARARG:
430         case VCALL: {
431                 codegen_setoneret(fs, e);
432                 break;
433         }
434         default:
435                 break;  /* there is one value available (somewhere) */
436         }
437 }
438
439 static int code_label(ktap_funcstate *fs, int A, int b, int jump)
440 {
441         codegen_getlabel(fs);  /* those instructions may be jump targets */
442         return codegen_codeABC(fs, OP_LOADBOOL, A, b, jump);
443 }
444
445 static void discharge2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg)
446 {
447         codegen_dischargevars(fs, e);
448         switch (e->k) {
449         case VNIL: {
450                 codegen_nil(fs, reg, 1);
451                 break;
452         }
453         case VFALSE:  case VTRUE: {
454                 codegen_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
455                 break;
456         }
457         case VEVENT:
458                 codegen_codeABC(fs, OP_EVENT, reg, 0, 0);
459                 break;
460         case VEVENTNAME:
461                 codegen_codeABC(fs, OP_EVENTNAME, reg, 0, 0);
462                 break;
463         case VEVENTARG:
464                 codegen_codeABC(fs, OP_EVENTARG, reg, e->u.info, 0);
465                 break;
466         case VK: {
467                 codegen_codek(fs, reg, e->u.info);
468                 break;
469         }
470         case VKNUM: {
471                 codegen_codek(fs, reg, codegen_numberK(fs, e->u.nval));
472                 break;
473         }
474         case VRELOCABLE: {
475                 ktap_instruction *pc = &getcode(fs, e);
476                 SETARG_A(*pc, reg);
477                 break;
478         }
479         case VNONRELOC: {
480                 if (reg != e->u.info)
481                         codegen_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
482                 break;
483         }
484         default:
485                 ktap_assert(e->k == VVOID || e->k == VJMP);
486                 return;  /* nothing to do... */
487         }
488
489         e->u.info = reg;
490         e->k = VNONRELOC;
491 }
492
493 static void discharge2anyreg(ktap_funcstate *fs, ktap_expdesc *e)
494 {
495         if (e->k != VNONRELOC) {
496                 codegen_reserveregs(fs, 1);
497                 discharge2reg(fs, e, fs->freereg-1);
498         }
499 }
500
501 static void exp2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg)
502 {
503         discharge2reg(fs, e, reg);
504         if (e->k == VJMP)
505                 codegen_concat(fs, &e->t, e->u.info);  /* put this jump in `t' list */
506         if (hasjumps(e)) {
507                 int final;  /* position after whole expression */
508                 int p_f = NO_JUMP;  /* position of an eventual LOAD false */
509                 int p_t = NO_JUMP;  /* position of an eventual LOAD true */
510
511                 if (need_value(fs, e->t) || need_value(fs, e->f)) {
512                         int fj = (e->k == VJMP) ? NO_JUMP : codegen_jump(fs);
513
514                         p_f = code_label(fs, reg, 0, 1);
515                         p_t = code_label(fs, reg, 1, 0);
516                         codegen_patchtohere(fs, fj);
517                 }
518                 final = codegen_getlabel(fs);
519                 patchlistaux(fs, e->f, final, reg, p_f);
520                 patchlistaux(fs, e->t, final, reg, p_t);
521         }
522         e->f = e->t = NO_JUMP;
523         e->u.info = reg;
524         e->k = VNONRELOC;
525 }
526
527 void codegen_exp2nextreg(ktap_funcstate *fs, ktap_expdesc *e)
528 {
529         codegen_dischargevars(fs, e);
530         freeexp(fs, e);
531         codegen_reserveregs(fs, 1);
532         exp2reg(fs, e, fs->freereg - 1);
533 }
534
535 int codegen_exp2anyreg(ktap_funcstate *fs, ktap_expdesc *e)
536 {
537         codegen_dischargevars(fs, e);
538         if (e->k == VNONRELOC) {
539                 if (!hasjumps(e))
540                         return e->u.info;  /* exp is already in a register */
541                 if (e->u.info >= fs->nactvar) {  /* reg. is not a local? */
542                         exp2reg(fs, e, e->u.info);  /* put value on it */
543                         return e->u.info;
544                 }
545         }
546         codegen_exp2nextreg(fs, e);  /* default */
547         return e->u.info;
548 }
549
550 void codegen_exp2anyregup(ktap_funcstate *fs, ktap_expdesc *e)
551 {
552         if (e->k != VUPVAL || hasjumps(e))
553                 codegen_exp2anyreg(fs, e);
554 }
555
556 void codegen_exp2val(ktap_funcstate *fs, ktap_expdesc *e)
557 {
558         if (hasjumps(e))
559                 codegen_exp2anyreg(fs, e);
560         else
561                 codegen_dischargevars(fs, e);
562 }
563
564 int codegen_exp2RK(ktap_funcstate *fs, ktap_expdesc *e)
565 {
566         codegen_exp2val(fs, e);
567         switch (e->k) {
568         case VTRUE:
569         case VFALSE:
570         case VNIL: {
571                 if (fs->nk <= MAXINDEXRK) {  /* constant fits in RK operand? */
572                         e->u.info = (e->k == VNIL) ? nilK(fs) :
573                                                      boolK(fs, (e->k == VTRUE));
574                         e->k = VK;
575                         return RKASK(e->u.info);
576                 }
577                 else
578                         break;
579         }
580         case VKNUM: {
581                 e->u.info = codegen_numberK(fs, e->u.nval);
582                 e->k = VK;
583                 /* go through */
584         }
585         case VK: {
586                 if (e->u.info <= MAXINDEXRK)  /* constant fits in argC? */
587                         return RKASK(e->u.info);
588                 else
589                         break;
590         }
591         default:
592                 break;
593         }
594         /* not a constant in the right range: put it in a register */
595         return codegen_exp2anyreg(fs, e);
596 }
597
598 void codegen_storevar(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex)
599 {
600         switch (var->k) {
601         case VLOCAL: {
602                 freeexp(fs, ex);
603                 exp2reg(fs, ex, var->u.info);
604                 return;
605         }
606         case VUPVAL: {
607                 int e = codegen_exp2anyreg(fs, ex);
608                 codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
609                 break;
610         }
611         case VINDEXED: {
612                 OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
613                 int e = codegen_exp2RK(fs, ex);
614                 codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
615                 break;
616         }
617         default:
618                 ktap_assert(0);  /* invalid var kind to store */
619                 break;
620         }
621
622         freeexp(fs, ex);
623 }
624
625 void codegen_storeincr(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex)
626 {
627         switch (var->k) {
628 #if 0 /*current not supported */
629         case VLOCAL: {
630                 freeexp(fs, ex);
631                 exp2reg(fs, ex, var->u.info);
632                 return;
633         }
634         case VUPVAL: {
635                 int e = codegen_exp2anyreg(fs, ex);
636                 codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
637                 break;
638         }
639 #endif
640         case VINDEXED: {
641                 OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE_INCR :
642                                 OP_SETTABUP_INCR;
643                 int e = codegen_exp2RK(fs, ex);
644                 codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
645                 break;
646         }
647         default:
648                 ktap_assert(0);  /* invalid var kind to store */
649                 break;
650         }
651
652         freeexp(fs, ex);
653 }
654
655
656 void codegen_self(ktap_funcstate *fs, ktap_expdesc *e, ktap_expdesc *key)
657 {
658         int ereg;
659
660         codegen_exp2anyreg(fs, e);
661         ereg = e->u.info;  /* register where 'e' was placed */
662         freeexp(fs, e);
663         e->u.info = fs->freereg;  /* base register for op_self */
664         e->k = VNONRELOC;
665         codegen_reserveregs(fs, 2);  /* function and 'self' produced by op_self */
666         codegen_codeABC(fs, OP_SELF, e->u.info, ereg, codegen_exp2RK(fs, key));
667         freeexp(fs, key);
668 }
669
670 static void invertjump(ktap_funcstate *fs, ktap_expdesc *e)
671 {
672         ktap_instruction *pc = getjumpcontrol(fs, e->u.info);
673         ktap_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
674                         GET_OPCODE(*pc) != OP_TEST);
675         SETARG_A(*pc, !(GETARG_A(*pc)));
676 }
677
678 static int jumponcond(ktap_funcstate *fs, ktap_expdesc *e, int cond)
679 {
680         if (e->k == VRELOCABLE) {
681                 ktap_instruction ie = getcode(fs, e);
682                 if (GET_OPCODE(ie) == OP_NOT) {
683                         fs->pc--;  /* remove previous OP_NOT */
684                         return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
685                 }
686                 /* else go through */
687         }
688         discharge2anyreg(fs, e);
689         freeexp(fs, e);
690         return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
691 }
692
693 void codegen_goiftrue(ktap_funcstate *fs, ktap_expdesc *e)
694 {
695         int pc;  /* pc of last jump */
696
697         codegen_dischargevars(fs, e);
698         switch (e->k) {
699         case VJMP: {
700                 invertjump(fs, e);
701                 pc = e->u.info;
702                 break;
703         }
704         case VK: case VKNUM: case VTRUE: {
705                 pc = NO_JUMP;  /* always true; do nothing */
706                 break;
707         }
708         default:
709                 pc = jumponcond(fs, e, 0);
710                 break;
711         }
712
713         codegen_concat(fs, &e->f, pc);  /* insert last jump in `f' list */
714         codegen_patchtohere(fs, e->t);
715         e->t = NO_JUMP;
716 }
717
718 void codegen_goiffalse(ktap_funcstate *fs, ktap_expdesc *e)
719 {
720         int pc;  /* pc of last jump */
721         codegen_dischargevars(fs, e);
722
723         switch (e->k) {
724         case VJMP: {
725                 pc = e->u.info;
726                 break;
727         }
728         case VNIL: case VFALSE: {
729                 pc = NO_JUMP;  /* always false; do nothing */
730                 break;
731         }
732         default:
733                 pc = jumponcond(fs, e, 1);
734                 break;
735         }
736         codegen_concat(fs, &e->t, pc);  /* insert last jump in `t' list */
737         codegen_patchtohere(fs, e->f);
738         e->f = NO_JUMP;
739 }
740
741 static void codenot(ktap_funcstate *fs, ktap_expdesc *e)
742 {
743         codegen_dischargevars(fs, e);
744         switch (e->k) {
745         case VNIL: case VFALSE: {
746                 e->k = VTRUE;
747                 break;
748         }
749         case VK: case VKNUM: case VTRUE: {
750                 e->k = VFALSE;
751                 break;
752         }
753         case VJMP: {
754                 invertjump(fs, e);
755                 break;
756         }
757         case VRELOCABLE:
758         case VNONRELOC: {
759                 discharge2anyreg(fs, e);
760                 freeexp(fs, e);
761                 e->u.info = codegen_codeABC(fs, OP_NOT, 0, e->u.info, 0);
762                 e->k = VRELOCABLE;
763                 break;
764         }
765         default:
766                 ktap_assert(0);  /* cannot happen */
767                 break;
768         }
769
770         /* interchange true and false lists */
771         { int temp = e->f; e->f = e->t; e->t = temp; }
772         removevalues(fs, e->f);
773         removevalues(fs, e->t);
774 }
775
776 void codegen_indexed(ktap_funcstate *fs, ktap_expdesc *t, ktap_expdesc *k)
777 {
778         ktap_assert(!hasjumps(t));
779         t->u.ind.t = t->u.info;
780         t->u.ind.idx = codegen_exp2RK(fs, k);
781         t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
782                         : check_exp(vkisinreg(t->k), VLOCAL);
783         t->k = VINDEXED;
784 }
785
786 static int constfolding(OpCode op, ktap_expdesc *e1, ktap_expdesc *e2)
787 {
788         ktap_number r;
789
790         if (!isnumeral(e1) || !isnumeral(e2))
791                 return 0;
792
793         if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0)
794                 return 0;  /* do not attempt to divide by 0 */
795
796         if (op == OP_POW)
797                 return 0; /* ktap current do not suppor pow arith */
798
799         r = ktapc_arith(op - OP_ADD + KTAP_OPADD, e1->u.nval, e2->u.nval);
800         e1->u.nval = r;
801         return 1;
802 }
803
804 static void codearith(ktap_funcstate *fs, OpCode op,
805                       ktap_expdesc *e1, ktap_expdesc *e2, int line)
806 {
807         if (constfolding(op, e1, e2))
808                 return;
809         else {
810                 int o2 = (op != OP_UNM && op != OP_LEN) ? codegen_exp2RK(fs, e2) : 0;
811                 int o1 = codegen_exp2RK(fs, e1);
812
813                 if (o1 > o2) {
814                         freeexp(fs, e1);
815                         freeexp(fs, e2);
816                 } else {
817                         freeexp(fs, e2);
818                         freeexp(fs, e1);
819                 }
820                 e1->u.info = codegen_codeABC(fs, op, 0, o1, o2);
821                 e1->k = VRELOCABLE;
822                 codegen_fixline(fs, line);
823         }
824 }
825
826 static void codecomp(ktap_funcstate *fs, OpCode op, int cond, ktap_expdesc *e1,
827                      ktap_expdesc *e2)
828 {
829         int o1 = codegen_exp2RK(fs, e1);
830         int o2 = codegen_exp2RK(fs, e2);
831
832         freeexp(fs, e2);
833         freeexp(fs, e1);
834         if (cond == 0 && op != OP_EQ) {
835                 int temp;  /* exchange args to replace by `<' or `<=' */
836                 temp = o1; o1 = o2; o2 = temp;  /* o1 <==> o2 */
837                 cond = 1;
838         }
839         e1->u.info = condjump(fs, op, cond, o1, o2);
840         e1->k = VJMP;
841 }
842
843 void codegen_prefix(ktap_funcstate *fs, UnOpr op, ktap_expdesc *e, int line)
844 {
845         ktap_expdesc e2;
846
847         e2.t = e2.f = NO_JUMP;
848         e2.k = VKNUM;
849         e2.u.nval = 0;
850
851         switch (op) {
852         case OPR_MINUS: {
853                 if (isnumeral(e))  /* minus constant? */
854                         e->u.nval = ktap_numunm(e->u.nval);  /* fold it */
855                 else {
856                         codegen_exp2anyreg(fs, e);
857                         codearith(fs, OP_UNM, e, &e2, line);
858                 }
859                 break;
860         }
861         case OPR_NOT:
862                 codenot(fs, e);
863                 break;
864         case OPR_LEN: {
865                 codegen_exp2anyreg(fs, e);  /* cannot operate on constants */
866                 codearith(fs, OP_LEN, e, &e2, line);
867                 break;
868         }
869         default:
870                 ktap_assert(0);
871         }
872 }
873
874 void codegen_infix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *v)
875 {
876         switch (op) {
877         case OPR_AND: {
878                 codegen_goiftrue(fs, v);
879                 break;
880         }
881         case OPR_OR: {
882                 codegen_goiffalse(fs, v);
883                 break;
884         }
885         case OPR_CONCAT: {
886                 codegen_exp2nextreg(fs, v);  /* operand must be on the `stack' */
887                 break;
888         }
889         case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
890         case OPR_MOD: case OPR_POW: {
891                 if (!isnumeral(v)) codegen_exp2RK(fs, v);
892                         break;
893         }
894         default:
895                 codegen_exp2RK(fs, v);
896                 break;
897         }
898 }
899
900 void codegen_posfix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *e1, ktap_expdesc *e2, int line)
901 {
902         switch (op) {
903         case OPR_AND: {
904                 ktap_assert(e1->t == NO_JUMP);  /* list must be closed */
905                 codegen_dischargevars(fs, e2);
906                 codegen_concat(fs, &e2->f, e1->f);
907                 *e1 = *e2;
908                 break;
909         }
910         case OPR_OR: {
911                 ktap_assert(e1->f == NO_JUMP);  /* list must be closed */
912                 codegen_dischargevars(fs, e2);
913                 codegen_concat(fs, &e2->t, e1->t);
914                 *e1 = *e2;
915                 break;
916         }
917         case OPR_CONCAT: {
918                 codegen_exp2val(fs, e2);
919                 if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
920                         ktap_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
921                         freeexp(fs, e1);
922                         SETARG_B(getcode(fs, e2), e1->u.info);
923                         e1->k = VRELOCABLE; e1->u.info = e2->u.info;
924                 } else {
925                         codegen_exp2nextreg(fs, e2);  /* operand must be on the 'stack' */
926                         codearith(fs, OP_CONCAT, e1, e2, line);
927                 }
928                 break;
929         }
930         case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
931         case OPR_MOD: case OPR_POW: {
932                 codearith(fs, (OpCode)(op - OPR_ADD + OP_ADD), e1, e2, line);
933                 break;
934         }
935         case OPR_EQ: case OPR_LT: case OPR_LE: {
936                 codecomp(fs, (OpCode)(op - OPR_EQ + OP_EQ), 1, e1, e2);
937                 break;
938         }
939         case OPR_NE: case OPR_GT: case OPR_GE: {
940                 codecomp(fs, (OpCode)(op - OPR_NE + OP_EQ), 0, e1, e2);
941                 break;
942         }
943         default:
944                 ktap_assert(0);
945         }
946 }
947
948 void codegen_fixline(ktap_funcstate *fs, int line)
949 {
950         fs->f->lineinfo[fs->pc - 1] = line;
951 }
952
953 void codegen_setlist(ktap_funcstate *fs, int base, int nelems, int tostore)
954 {
955         int c =  (nelems - 1)/LFIELDS_PER_FLUSH + 1;
956         int b = (tostore == KTAP_MULTRET) ? 0 : tostore;
957
958         ktap_assert(tostore != 0);
959         if (c <= MAXARG_C)
960                 codegen_codeABC(fs, OP_SETLIST, base, b, c);
961         else if (c <= MAXARG_Ax) {
962                 codegen_codeABC(fs, OP_SETLIST, base, b, 0);
963                 codeextraarg(fs, c);
964         } else
965                 lex_syntaxerror(fs->ls, "constructor too long");
966         fs->freereg = base + 1;  /* free registers with list values */
967 }
968