2 * code.c - Code generator for ktap
4 * This file is part of ktap by Jovi Zhangwei.
6 * Copyright (C) 2012-2013 Jovi Zhangwei <jovi.zhangwei@gmail.com>.
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.
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.
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
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.
30 #include "../include/ktap_types.h"
31 #include "../include/ktap_opcodes.h"
33 #include "../runtime/kp_obj.h"
36 #define hasjumps(e) ((e)->t != (e)->f)
38 void codegen_patchtohere (ktap_funcstate *fs, int list);
40 static int isnumeral(ktap_expdesc *e)
42 return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
45 void codegen_nil(ktap_funcstate *fs, int from, int n)
47 ktap_instruction *previous;
48 int l = from + n - 1; /* last register to set nil */
50 if (fs->pc > fs->lasttarget) { /* no jumps to current position? */
51 previous = &fs->f->code[fs->pc-1];
52 if (GET_OPCODE(*previous) == OP_LOADNIL) {
53 int pfrom = GETARG_A(*previous);
54 int pl = pfrom + GETARG_B(*previous);
56 if ((pfrom <= from && from <= pl + 1) ||
57 (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
59 from = pfrom; /* from = min(from, pfrom) */
61 l = pl; /* l = max(l, pl) */
62 SETARG_A(*previous, from);
63 SETARG_B(*previous, l - from);
66 } /* else go through */
68 codegen_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
71 int codegen_jump(ktap_funcstate *fs)
73 int jpc = fs->jpc; /* save list of jumps to here */
77 j = codegen_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
78 codegen_concat(fs, &j, jpc); /* keep them on hold */
82 void codegen_ret(ktap_funcstate *fs, int first, int nret)
84 codegen_codeABC(fs, OP_RETURN, first, nret+1, 0);
87 static int condjump(ktap_funcstate *fs, OpCode op, int A, int B, int C)
89 codegen_codeABC(fs, op, A, B, C);
90 return codegen_jump(fs);
93 static void fixjump(ktap_funcstate *fs, int pc, int dest)
95 ktap_instruction *jmp = &fs->f->code[pc];
96 int offset = dest-(pc+1);
98 ktap_assert(dest != NO_JUMP);
99 if (abs(offset) > MAXARG_sBx)
100 lex_syntaxerror(fs->ls, "control structure too long");
101 SETARG_sBx(*jmp, offset);
105 * returns current `pc' and marks it as a jump target (to avoid wrong
106 * optimizations with consecutive instructions not in the same basic block).
108 int codegen_getlabel(ktap_funcstate *fs)
110 fs->lasttarget = fs->pc;
114 static int getjump(ktap_funcstate *fs, int pc)
116 int offset = GETARG_sBx(fs->f->code[pc]);
118 if (offset == NO_JUMP) /* point to itself represents end of list */
119 return NO_JUMP; /* end of list */
121 return (pc+1)+offset; /* turn offset into absolute position */
124 static ktap_instruction *getjumpcontrol(ktap_funcstate *fs, int pc)
126 ktap_instruction *pi = &fs->f->code[pc];
127 if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
134 * check whether list has any jump that do not produce a value
135 * (or produce an inverted value)
137 static int need_value(ktap_funcstate *fs, int list)
139 for (; list != NO_JUMP; list = getjump(fs, list)) {
140 ktap_instruction i = *getjumpcontrol(fs, list);
141 if (GET_OPCODE(i) != OP_TESTSET)
144 return 0; /* not found */
147 static int patchtestreg(ktap_funcstate *fs, int node, int reg)
149 ktap_instruction *i = getjumpcontrol(fs, node);
150 if (GET_OPCODE(*i) != OP_TESTSET)
151 return 0; /* cannot patch other instructions */
152 if (reg != NO_REG && reg != GETARG_B(*i))
154 else /* no register to put value or register already has the value */
155 *i = CREATE_ABC(OP_TEST, GETARG_B(*i), 0, GETARG_C(*i));
160 static void removevalues(ktap_funcstate *fs, int list)
162 for (; list != NO_JUMP; list = getjump(fs, list))
163 patchtestreg(fs, list, NO_REG);
166 static void patchlistaux(ktap_funcstate *fs, int list, int vtarget, int reg,
169 while (list != NO_JUMP) {
170 int next = getjump(fs, list);
171 if (patchtestreg(fs, list, reg))
172 fixjump(fs, list, vtarget);
174 fixjump(fs, list, dtarget); /* jump to default target */
179 static void dischargejpc(ktap_funcstate *fs)
181 patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
185 void codegen_patchlist(ktap_funcstate *fs, int list, int target)
187 if (target == fs->pc)
188 codegen_patchtohere(fs, list);
190 ktap_assert(target < fs->pc);
191 patchlistaux(fs, list, target, NO_REG, target);
195 void codegen_patchclose(ktap_funcstate *fs, int list, int level)
197 level++; /* argument is +1 to reserve 0 as non-op */
198 while (list != NO_JUMP) {
199 int next = getjump(fs, list);
200 ktap_assert(GET_OPCODE(fs->f->code[list]) == OP_JMP &&
201 (GETARG_A(fs->f->code[list]) == 0 ||
202 GETARG_A(fs->f->code[list]) >= level));
203 SETARG_A(fs->f->code[list], level);
208 void codegen_patchtohere(ktap_funcstate *fs, int list)
210 codegen_getlabel(fs);
211 codegen_concat(fs, &fs->jpc, list);
214 void codegen_concat(ktap_funcstate *fs, int *l1, int l2)
218 else if (*l1 == NO_JUMP)
223 while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
225 fixjump(fs, list, l2);
229 static int codegen_code(ktap_funcstate *fs, ktap_instruction i)
231 ktap_proto *f = fs->f;
233 dischargejpc(fs); /* `pc' will change */
235 /* put new instruction in code array */
236 ktapc_growvector(f->code, fs->pc, f->sizecode, ktap_instruction,
240 /* save corresponding line information */
241 ktapc_growvector(f->lineinfo, fs->pc, f->sizelineinfo, int,
243 f->lineinfo[fs->pc] = fs->ls->lastline;
247 int codegen_codeABC(ktap_funcstate *fs, OpCode o, int a, int b, int c)
249 ktap_assert(getOpMode(o) == iABC);
250 //ktap_assert(getBMode(o) != OpArgN || b == 0);
251 //ktap_assert(getCMode(o) != OpArgN || c == 0);
252 //ktap_assert(a <= MAXARG_A && b <= MAXARG_B && c <= MAXARG_C);
253 return codegen_code(fs, CREATE_ABC(o, a, b, c));
256 int codegen_codeABx(ktap_funcstate *fs, OpCode o, int a, unsigned int bc)
258 ktap_assert(getOpMode(o) == iABx || getOpMode(o) == iAsBx);
259 ktap_assert(getCMode(o) == OpArgN);
260 ktap_assert(a <= MAXARG_A && bc <= MAXARG_Bx);
261 return codegen_code(fs, CREATE_ABx(o, a, bc));
264 static int codeextraarg(ktap_funcstate *fs, int a)
266 ktap_assert(a <= MAXARG_Ax);
267 return codegen_code(fs, CREATE_Ax(OP_EXTRAARG, a));
270 int codegen_codek(ktap_funcstate *fs, int reg, int k)
273 return codegen_codeABx(fs, OP_LOADK, reg, k);
275 int p = codegen_codeABx(fs, OP_LOADKX, reg, 0);
281 void codegen_checkstack(ktap_funcstate *fs, int n)
283 int newstack = fs->freereg + n;
285 if (newstack > fs->f->maxstacksize) {
286 if (newstack >= MAXSTACK)
287 lex_syntaxerror(fs->ls, "function or expression too complex");
288 fs->f->maxstacksize = (u8)(newstack);
292 void codegen_reserveregs(ktap_funcstate *fs, int n)
294 codegen_checkstack(fs, n);
298 static void freereg(ktap_funcstate *fs, int reg)
300 if (!ISK(reg) && reg >= fs->nactvar) {
302 ktap_assert(reg == fs->freereg);
306 static void freeexp(ktap_funcstate *fs, ktap_expdesc *e)
308 if (e->k == VNONRELOC)
309 freereg(fs, e->u.info);
312 static int addk(ktap_funcstate *fs, ktap_value *key, ktap_value *v)
314 const ktap_value *idx = ktapc_table_get(fs->h, key);
315 ktap_proto *f = fs->f;
319 if (is_number(idx)) {
320 ktap_number n = nvalue(idx);
322 if (ktapc_equalobj(&f->k[k], v))
324 /* else may be a collision (e.g., between 0.0 and "\0\0\0\0\0\0\0\0");
325 go through and create a new entry for this value */
327 /* constant not found; create a new entry */
331 /* numerical value does not need GC barrier;
332 table has no metatable, so it does not need to invalidate cache */
333 set_number(&kn, (ktap_number)k);
334 ktapc_table_setvalue(fs->h, key, &kn);
335 ktapc_growvector(f->k, k, f->sizek, ktap_value, MAXARG_Ax, "constants");
336 while (oldsize < f->sizek)
337 set_nil(&f->k[oldsize++]);
338 set_obj(&f->k[k], v);
343 int codegen_stringK(ktap_funcstate *fs, ktap_string *s)
348 return addk(fs, &o, &o);
351 int codegen_numberK(ktap_funcstate *fs, ktap_number r)
357 if (r == 0 || ktap_numisnan(NULL, r)) { /* handle -0 and NaN */
358 /* use raw representation as key to avoid numeric problems */
359 set_string(&s, ktapc_ts_newlstr((char *)&r, sizeof(r)));
361 n = addk(fs, &s, &o);
364 n = addk(fs, &o, &o); /* regular case */
368 static int boolK(ktap_funcstate *fs, int b)
372 return addk(fs, &o, &o);
375 static int nilK(ktap_funcstate *fs)
379 /* cannot use nil as key; instead use table itself to represent nil */
380 set_table(&k, fs->h);
381 return addk(fs, &k, &v);
384 void codegen_setreturns(ktap_funcstate *fs, ktap_expdesc *e, int nresults)
386 if (e->k == VCALL) { /* expression is an open function call? */
387 SETARG_C(getcode(fs, e), nresults+1);
389 else if (e->k == VVARARG) {
390 SETARG_B(getcode(fs, e), nresults+1);
391 SETARG_A(getcode(fs, e), fs->freereg);
392 codegen_reserveregs(fs, 1);
396 void codegen_setoneret(ktap_funcstate *fs, ktap_expdesc *e)
398 if (e->k == VCALL) { /* expression is an open function call? */
400 e->u.info = GETARG_A(getcode(fs, e));
401 } else if (e->k == VVARARG) {
402 SETARG_B(getcode(fs, e), 2);
403 e->k = VRELOCABLE; /* can relocate its simple result */
407 void codegen_dischargevars(ktap_funcstate *fs, ktap_expdesc *e)
415 e->u.info = codegen_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
420 OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */
421 freereg(fs, e->u.ind.idx);
422 if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */
423 freereg(fs, e->u.ind.t);
426 e->u.info = codegen_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
432 codegen_setoneret(fs, e);
436 break; /* there is one value available (somewhere) */
440 static int code_label(ktap_funcstate *fs, int A, int b, int jump)
442 codegen_getlabel(fs); /* those instructions may be jump targets */
443 return codegen_codeABC(fs, OP_LOADBOOL, A, b, jump);
446 static void discharge2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg)
448 codegen_dischargevars(fs, e);
451 codegen_nil(fs, reg, 1);
454 case VFALSE: case VTRUE: {
455 codegen_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
459 codegen_codeABC(fs, OP_EVENT, reg, 0, 0);
462 codegen_codeABC(fs, OP_EVENTNAME, reg, 0, 0);
465 codegen_codeABC(fs, OP_EVENTARG, reg, e->u.info, 0);
468 codegen_codek(fs, reg, e->u.info);
472 codegen_codek(fs, reg, codegen_numberK(fs, e->u.nval));
476 ktap_instruction *pc = &getcode(fs, e);
481 if (reg != e->u.info)
482 codegen_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
486 ktap_assert(e->k == VVOID || e->k == VJMP);
487 return; /* nothing to do... */
494 static void discharge2anyreg(ktap_funcstate *fs, ktap_expdesc *e)
496 if (e->k != VNONRELOC) {
497 codegen_reserveregs(fs, 1);
498 discharge2reg(fs, e, fs->freereg-1);
502 static void exp2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg)
504 discharge2reg(fs, e, reg);
506 codegen_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */
508 int final; /* position after whole expression */
509 int p_f = NO_JUMP; /* position of an eventual LOAD false */
510 int p_t = NO_JUMP; /* position of an eventual LOAD true */
512 if (need_value(fs, e->t) || need_value(fs, e->f)) {
513 int fj = (e->k == VJMP) ? NO_JUMP : codegen_jump(fs);
515 p_f = code_label(fs, reg, 0, 1);
516 p_t = code_label(fs, reg, 1, 0);
517 codegen_patchtohere(fs, fj);
519 final = codegen_getlabel(fs);
520 patchlistaux(fs, e->f, final, reg, p_f);
521 patchlistaux(fs, e->t, final, reg, p_t);
523 e->f = e->t = NO_JUMP;
528 void codegen_exp2nextreg(ktap_funcstate *fs, ktap_expdesc *e)
530 codegen_dischargevars(fs, e);
532 codegen_reserveregs(fs, 1);
533 exp2reg(fs, e, fs->freereg - 1);
536 int codegen_exp2anyreg(ktap_funcstate *fs, ktap_expdesc *e)
538 codegen_dischargevars(fs, e);
539 if (e->k == VNONRELOC) {
541 return e->u.info; /* exp is already in a register */
542 if (e->u.info >= fs->nactvar) { /* reg. is not a local? */
543 exp2reg(fs, e, e->u.info); /* put value on it */
547 codegen_exp2nextreg(fs, e); /* default */
551 void codegen_exp2anyregup(ktap_funcstate *fs, ktap_expdesc *e)
553 if (e->k != VUPVAL || hasjumps(e))
554 codegen_exp2anyreg(fs, e);
557 void codegen_exp2val(ktap_funcstate *fs, ktap_expdesc *e)
560 codegen_exp2anyreg(fs, e);
562 codegen_dischargevars(fs, e);
565 int codegen_exp2RK(ktap_funcstate *fs, ktap_expdesc *e)
567 codegen_exp2val(fs, e);
572 if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */
573 e->u.info = (e->k == VNIL) ? nilK(fs) :
574 boolK(fs, (e->k == VTRUE));
576 return RKASK(e->u.info);
582 e->u.info = codegen_numberK(fs, e->u.nval);
587 if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */
588 return RKASK(e->u.info);
595 /* not a constant in the right range: put it in a register */
596 return codegen_exp2anyreg(fs, e);
599 void codegen_storevar(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex)
604 exp2reg(fs, ex, var->u.info);
608 int e = codegen_exp2anyreg(fs, ex);
609 codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
613 OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE : OP_SETTABUP;
614 int e = codegen_exp2RK(fs, ex);
615 codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
619 ktap_assert(0); /* invalid var kind to store */
626 void codegen_storeincr(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex)
629 #if 0 /*current not supported */
632 exp2reg(fs, ex, var->u.info);
636 int e = codegen_exp2anyreg(fs, ex);
637 codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
642 OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE_INCR :
644 int e = codegen_exp2RK(fs, ex);
645 codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
649 ktap_assert(0); /* invalid var kind to store */
656 void codegen_store_aggr(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex)
659 #if 0 /*current not supported */
662 exp2reg(fs, ex, var->u.info);
666 int e = codegen_exp2anyreg(fs, ex);
667 codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
672 OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE_AGGR :
674 int e = codegen_exp2RK(fs, ex);
675 codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
679 ktap_assert(0); /* invalid var kind to store */
686 void codegen_self(ktap_funcstate *fs, ktap_expdesc *e, ktap_expdesc *key)
690 codegen_exp2anyreg(fs, e);
691 ereg = e->u.info; /* register where 'e' was placed */
693 e->u.info = fs->freereg; /* base register for op_self */
695 codegen_reserveregs(fs, 2); /* function and 'self' produced by op_self */
696 codegen_codeABC(fs, OP_SELF, e->u.info, ereg, codegen_exp2RK(fs, key));
700 static void invertjump(ktap_funcstate *fs, ktap_expdesc *e)
702 ktap_instruction *pc = getjumpcontrol(fs, e->u.info);
703 ktap_assert(testTMode(GET_OPCODE(*pc)) && GET_OPCODE(*pc) != OP_TESTSET &&
704 GET_OPCODE(*pc) != OP_TEST);
705 SETARG_A(*pc, !(GETARG_A(*pc)));
708 static int jumponcond(ktap_funcstate *fs, ktap_expdesc *e, int cond)
710 if (e->k == VRELOCABLE) {
711 ktap_instruction ie = getcode(fs, e);
712 if (GET_OPCODE(ie) == OP_NOT) {
713 fs->pc--; /* remove previous OP_NOT */
714 return condjump(fs, OP_TEST, GETARG_B(ie), 0, !cond);
716 /* else go through */
718 discharge2anyreg(fs, e);
720 return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
723 void codegen_goiftrue(ktap_funcstate *fs, ktap_expdesc *e)
725 int pc; /* pc of last jump */
727 codegen_dischargevars(fs, e);
734 case VK: case VKNUM: case VTRUE: {
735 pc = NO_JUMP; /* always true; do nothing */
739 pc = jumponcond(fs, e, 0);
743 codegen_concat(fs, &e->f, pc); /* insert last jump in `f' list */
744 codegen_patchtohere(fs, e->t);
748 void codegen_goiffalse(ktap_funcstate *fs, ktap_expdesc *e)
750 int pc; /* pc of last jump */
751 codegen_dischargevars(fs, e);
758 case VNIL: case VFALSE: {
759 pc = NO_JUMP; /* always false; do nothing */
763 pc = jumponcond(fs, e, 1);
766 codegen_concat(fs, &e->t, pc); /* insert last jump in `t' list */
767 codegen_patchtohere(fs, e->f);
771 static void codenot(ktap_funcstate *fs, ktap_expdesc *e)
773 codegen_dischargevars(fs, e);
775 case VNIL: case VFALSE: {
779 case VK: case VKNUM: case VTRUE: {
789 discharge2anyreg(fs, e);
791 e->u.info = codegen_codeABC(fs, OP_NOT, 0, e->u.info, 0);
796 ktap_assert(0); /* cannot happen */
800 /* interchange true and false lists */
801 { int temp = e->f; e->f = e->t; e->t = temp; }
802 removevalues(fs, e->f);
803 removevalues(fs, e->t);
806 void codegen_indexed(ktap_funcstate *fs, ktap_expdesc *t, ktap_expdesc *k)
808 ktap_assert(!hasjumps(t));
809 t->u.ind.t = t->u.info;
810 t->u.ind.idx = codegen_exp2RK(fs, k);
811 t->u.ind.vt = (t->k == VUPVAL) ? VUPVAL
812 : check_exp(vkisinreg(t->k), VLOCAL);
816 static int constfolding(OpCode op, ktap_expdesc *e1, ktap_expdesc *e2)
820 if (!isnumeral(e1) || !isnumeral(e2))
823 if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0)
824 return 0; /* do not attempt to divide by 0 */
827 return 0; /* ktap current do not suppor pow arith */
829 r = ktapc_arith(op - OP_ADD + KTAP_OPADD, e1->u.nval, e2->u.nval);
834 static void codearith(ktap_funcstate *fs, OpCode op,
835 ktap_expdesc *e1, ktap_expdesc *e2, int line)
837 if (constfolding(op, e1, e2))
840 int o2 = (op != OP_UNM && op != OP_LEN) ? codegen_exp2RK(fs, e2) : 0;
841 int o1 = codegen_exp2RK(fs, e1);
850 e1->u.info = codegen_codeABC(fs, op, 0, o1, o2);
852 codegen_fixline(fs, line);
856 static void codecomp(ktap_funcstate *fs, OpCode op, int cond, ktap_expdesc *e1,
859 int o1 = codegen_exp2RK(fs, e1);
860 int o2 = codegen_exp2RK(fs, e2);
864 if (cond == 0 && op != OP_EQ) {
865 int temp; /* exchange args to replace by `<' or `<=' */
866 temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */
869 e1->u.info = condjump(fs, op, cond, o1, o2);
873 void codegen_prefix(ktap_funcstate *fs, UnOpr op, ktap_expdesc *e, int line)
877 e2.t = e2.f = NO_JUMP;
883 if (isnumeral(e)) /* minus constant? */
884 e->u.nval = ktap_numunm(e->u.nval); /* fold it */
886 codegen_exp2anyreg(fs, e);
887 codearith(fs, OP_UNM, e, &e2, line);
895 codegen_exp2anyreg(fs, e); /* cannot operate on constants */
896 codearith(fs, OP_LEN, e, &e2, line);
904 void codegen_infix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *v)
908 codegen_goiftrue(fs, v);
912 codegen_goiffalse(fs, v);
916 codegen_exp2nextreg(fs, v); /* operand must be on the `stack' */
919 case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
920 case OPR_MOD: case OPR_POW: {
921 if (!isnumeral(v)) codegen_exp2RK(fs, v);
925 codegen_exp2RK(fs, v);
930 void codegen_posfix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *e1, ktap_expdesc *e2, int line)
934 ktap_assert(e1->t == NO_JUMP); /* list must be closed */
935 codegen_dischargevars(fs, e2);
936 codegen_concat(fs, &e2->f, e1->f);
941 ktap_assert(e1->f == NO_JUMP); /* list must be closed */
942 codegen_dischargevars(fs, e2);
943 codegen_concat(fs, &e2->t, e1->t);
948 codegen_exp2val(fs, e2);
949 if (e2->k == VRELOCABLE && GET_OPCODE(getcode(fs, e2)) == OP_CONCAT) {
950 ktap_assert(e1->u.info == GETARG_B(getcode(fs, e2))-1);
952 SETARG_B(getcode(fs, e2), e1->u.info);
953 e1->k = VRELOCABLE; e1->u.info = e2->u.info;
955 codegen_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
956 codearith(fs, OP_CONCAT, e1, e2, line);
960 case OPR_ADD: case OPR_SUB: case OPR_MUL: case OPR_DIV:
961 case OPR_MOD: case OPR_POW: {
962 codearith(fs, (OpCode)(op - OPR_ADD + OP_ADD), e1, e2, line);
965 case OPR_EQ: case OPR_LT: case OPR_LE: {
966 codecomp(fs, (OpCode)(op - OPR_EQ + OP_EQ), 1, e1, e2);
969 case OPR_NE: case OPR_GT: case OPR_GE: {
970 codecomp(fs, (OpCode)(op - OPR_NE + OP_EQ), 0, e1, e2);
978 void codegen_fixline(ktap_funcstate *fs, int line)
980 fs->f->lineinfo[fs->pc - 1] = line;
983 void codegen_setlist(ktap_funcstate *fs, int base, int nelems, int tostore)
985 int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
986 int b = (tostore == KTAP_MULTRET) ? 0 : tostore;
988 ktap_assert(tostore != 0);
990 codegen_codeABC(fs, OP_SETLIST, base, b, c);
991 else if (c <= MAXARG_Ax) {
992 codegen_codeABC(fs, OP_SETLIST, base, b, 0);
995 lex_syntaxerror(fs->ls, "constructor too long");
996 fs->freereg = base + 1; /* free registers with list values */