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"
35 #define hasjumps(e) ((e)->t != (e)->f)
37 void codegen_patchtohere (ktap_funcstate *fs, int list);
39 static int isnumeral(ktap_expdesc *e)
41 return (e->k == VKNUM && e->t == NO_JUMP && e->f == NO_JUMP);
44 void codegen_nil(ktap_funcstate *fs, int from, int n)
46 ktap_instruction *previous;
47 int l = from + n - 1; /* last register to set nil */
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);
55 if ((pfrom <= from && from <= pl + 1) ||
56 (from <= pfrom && pfrom <= l + 1)) { /* can connect both? */
58 from = pfrom; /* from = min(from, pfrom) */
60 l = pl; /* l = max(l, pl) */
61 SETARG_A(*previous, from);
62 SETARG_B(*previous, l - from);
65 } /* else go through */
67 codegen_codeABC(fs, OP_LOADNIL, from, n - 1, 0); /* else no optimization */
70 int codegen_jump(ktap_funcstate *fs)
72 int jpc = fs->jpc; /* save list of jumps to here */
76 j = codegen_codeAsBx(fs, OP_JMP, 0, NO_JUMP);
77 codegen_concat(fs, &j, jpc); /* keep them on hold */
81 void codegen_ret(ktap_funcstate *fs, int first, int nret)
83 codegen_codeABC(fs, OP_RETURN, first, nret+1, 0);
86 static int condjump(ktap_funcstate *fs, OpCode op, int A, int B, int C)
88 codegen_codeABC(fs, op, A, B, C);
89 return codegen_jump(fs);
92 static void fixjump(ktap_funcstate *fs, int pc, int dest)
94 ktap_instruction *jmp = &fs->f->code[pc];
95 int offset = dest-(pc+1);
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);
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).
107 int codegen_getlabel(ktap_funcstate *fs)
109 fs->lasttarget = fs->pc;
113 static int getjump(ktap_funcstate *fs, int pc)
115 int offset = GETARG_sBx(fs->f->code[pc]);
117 if (offset == NO_JUMP) /* point to itself represents end of list */
118 return NO_JUMP; /* end of list */
120 return (pc+1)+offset; /* turn offset into absolute position */
123 static ktap_instruction *getjumpcontrol(ktap_funcstate *fs, int pc)
125 ktap_instruction *pi = &fs->f->code[pc];
126 if (pc >= 1 && testTMode(GET_OPCODE(*(pi-1))))
133 * check whether list has any jump that do not produce a value
134 * (or produce an inverted value)
136 static int need_value(ktap_funcstate *fs, int list)
138 for (; list != NO_JUMP; list = getjump(fs, list)) {
139 ktap_instruction i = *getjumpcontrol(fs, list);
140 if (GET_OPCODE(i) != OP_TESTSET)
143 return 0; /* not found */
146 static int patchtestreg(ktap_funcstate *fs, int node, int reg)
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))
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));
159 static void removevalues(ktap_funcstate *fs, int list)
161 for (; list != NO_JUMP; list = getjump(fs, list))
162 patchtestreg(fs, list, NO_REG);
165 static void patchlistaux(ktap_funcstate *fs, int list, int vtarget, int reg,
168 while (list != NO_JUMP) {
169 int next = getjump(fs, list);
170 if (patchtestreg(fs, list, reg))
171 fixjump(fs, list, vtarget);
173 fixjump(fs, list, dtarget); /* jump to default target */
178 static void dischargejpc(ktap_funcstate *fs)
180 patchlistaux(fs, fs->jpc, fs->pc, NO_REG, fs->pc);
184 void codegen_patchlist(ktap_funcstate *fs, int list, int target)
186 if (target == fs->pc)
187 codegen_patchtohere(fs, list);
189 ktap_assert(target < fs->pc);
190 patchlistaux(fs, list, target, NO_REG, target);
194 void codegen_patchclose(ktap_funcstate *fs, int list, int level)
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);
207 void codegen_patchtohere(ktap_funcstate *fs, int list)
209 codegen_getlabel(fs);
210 codegen_concat(fs, &fs->jpc, list);
213 void codegen_concat(ktap_funcstate *fs, int *l1, int l2)
217 else if (*l1 == NO_JUMP)
222 while ((next = getjump(fs, list)) != NO_JUMP) /* find last element */
224 fixjump(fs, list, l2);
228 static int codegen_code(ktap_funcstate *fs, ktap_instruction i)
230 ktap_proto *f = fs->f;
232 dischargejpc(fs); /* `pc' will change */
234 /* put new instruction in code array */
235 ktapc_growvector(f->code, fs->pc, f->sizecode, ktap_instruction,
239 /* save corresponding line information */
240 ktapc_growvector(f->lineinfo, fs->pc, f->sizelineinfo, int,
242 f->lineinfo[fs->pc] = fs->ls->lastline;
246 int codegen_codeABC(ktap_funcstate *fs, OpCode o, int a, int b, int c)
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));
255 int codegen_codeABx(ktap_funcstate *fs, OpCode o, int a, unsigned int bc)
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));
263 static int codeextraarg(ktap_funcstate *fs, int a)
265 ktap_assert(a <= MAXARG_Ax);
266 return codegen_code(fs, CREATE_Ax(OP_EXTRAARG, a));
269 int codegen_codek(ktap_funcstate *fs, int reg, int k)
272 return codegen_codeABx(fs, OP_LOADK, reg, k);
274 int p = codegen_codeABx(fs, OP_LOADKX, reg, 0);
280 void codegen_checkstack(ktap_funcstate *fs, int n)
282 int newstack = fs->freereg + n;
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);
291 void codegen_reserveregs(ktap_funcstate *fs, int n)
293 codegen_checkstack(fs, n);
297 static void freereg(ktap_funcstate *fs, int reg)
299 if (!ISK(reg) && reg >= fs->nactvar) {
301 ktap_assert(reg == fs->freereg);
305 static void freeexp(ktap_funcstate *fs, ktap_expdesc *e)
307 if (e->k == VNONRELOC)
308 freereg(fs, e->u.info);
311 static int addk(ktap_funcstate *fs, ktap_value *key, ktap_value *v)
313 const ktap_value *idx = ktapc_table_get(fs->h, key);
314 ktap_proto *f = fs->f;
318 if (ttisnumber(idx)) {
319 ktap_number n = nvalue(idx);
320 ktap_number2int(k, n);
321 if (ktapc_equalobj(&f->k[k], v))
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 */
326 /* constant not found; create a new entry */
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++]);
342 int codegen_stringK(ktap_funcstate *fs, ktap_string *s)
347 return addk(fs, &o, &o);
350 int codegen_numberK(ktap_funcstate *fs, ktap_number 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)));
360 n = addk(fs, &s, &o);
363 n = addk(fs, &o, &o); /* regular case */
367 static int boolK(ktap_funcstate *fs, int b)
371 return addk(fs, &o, &o);
374 static int nilK(ktap_funcstate *fs)
378 /* cannot use nil as key; instead use table itself to represent nil */
379 sethvalue(&k, fs->h);
380 return addk(fs, &k, &v);
383 void codegen_setreturns(ktap_funcstate *fs, ktap_expdesc *e, int nresults)
385 if (e->k == VCALL) { /* expression is an open function call? */
386 SETARG_C(getcode(fs, e), nresults+1);
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);
395 void codegen_setoneret(ktap_funcstate *fs, ktap_expdesc *e)
397 if (e->k == VCALL) { /* expression is an open function call? */
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 */
406 void codegen_dischargevars(ktap_funcstate *fs, ktap_expdesc *e)
414 e->u.info = codegen_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0);
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);
425 e->u.info = codegen_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx);
431 codegen_setoneret(fs, e);
435 break; /* there is one value available (somewhere) */
439 static int code_label(ktap_funcstate *fs, int A, int b, int jump)
441 codegen_getlabel(fs); /* those instructions may be jump targets */
442 return codegen_codeABC(fs, OP_LOADBOOL, A, b, jump);
445 static void discharge2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg)
447 codegen_dischargevars(fs, e);
450 codegen_nil(fs, reg, 1);
453 case VFALSE: case VTRUE: {
454 codegen_codeABC(fs, OP_LOADBOOL, reg, e->k == VTRUE, 0);
458 codegen_codeABC(fs, OP_EVENT, reg, 0, 0);
461 codegen_codeABC(fs, OP_EVENTNAME, reg, 0, 0);
464 codegen_codeABC(fs, OP_EVENTARG, reg, e->u.info, 0);
467 codegen_codek(fs, reg, e->u.info);
471 codegen_codek(fs, reg, codegen_numberK(fs, e->u.nval));
475 ktap_instruction *pc = &getcode(fs, e);
480 if (reg != e->u.info)
481 codegen_codeABC(fs, OP_MOVE, reg, e->u.info, 0);
485 ktap_assert(e->k == VVOID || e->k == VJMP);
486 return; /* nothing to do... */
493 static void discharge2anyreg(ktap_funcstate *fs, ktap_expdesc *e)
495 if (e->k != VNONRELOC) {
496 codegen_reserveregs(fs, 1);
497 discharge2reg(fs, e, fs->freereg-1);
501 static void exp2reg(ktap_funcstate *fs, ktap_expdesc *e, int reg)
503 discharge2reg(fs, e, reg);
505 codegen_concat(fs, &e->t, e->u.info); /* put this jump in `t' list */
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 */
511 if (need_value(fs, e->t) || need_value(fs, e->f)) {
512 int fj = (e->k == VJMP) ? NO_JUMP : codegen_jump(fs);
514 p_f = code_label(fs, reg, 0, 1);
515 p_t = code_label(fs, reg, 1, 0);
516 codegen_patchtohere(fs, fj);
518 final = codegen_getlabel(fs);
519 patchlistaux(fs, e->f, final, reg, p_f);
520 patchlistaux(fs, e->t, final, reg, p_t);
522 e->f = e->t = NO_JUMP;
527 void codegen_exp2nextreg(ktap_funcstate *fs, ktap_expdesc *e)
529 codegen_dischargevars(fs, e);
531 codegen_reserveregs(fs, 1);
532 exp2reg(fs, e, fs->freereg - 1);
535 int codegen_exp2anyreg(ktap_funcstate *fs, ktap_expdesc *e)
537 codegen_dischargevars(fs, e);
538 if (e->k == VNONRELOC) {
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 */
546 codegen_exp2nextreg(fs, e); /* default */
550 void codegen_exp2anyregup(ktap_funcstate *fs, ktap_expdesc *e)
552 if (e->k != VUPVAL || hasjumps(e))
553 codegen_exp2anyreg(fs, e);
556 void codegen_exp2val(ktap_funcstate *fs, ktap_expdesc *e)
559 codegen_exp2anyreg(fs, e);
561 codegen_dischargevars(fs, e);
564 int codegen_exp2RK(ktap_funcstate *fs, ktap_expdesc *e)
566 codegen_exp2val(fs, e);
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));
575 return RKASK(e->u.info);
581 e->u.info = codegen_numberK(fs, e->u.nval);
586 if (e->u.info <= MAXINDEXRK) /* constant fits in argC? */
587 return RKASK(e->u.info);
594 /* not a constant in the right range: put it in a register */
595 return codegen_exp2anyreg(fs, e);
598 void codegen_storevar(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex)
603 exp2reg(fs, ex, var->u.info);
607 int e = codegen_exp2anyreg(fs, ex);
608 codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
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);
618 ktap_assert(0); /* invalid var kind to store */
625 void codegen_storeincr(ktap_funcstate *fs, ktap_expdesc *var, ktap_expdesc *ex)
628 #if 0 /*current not supported */
631 exp2reg(fs, ex, var->u.info);
635 int e = codegen_exp2anyreg(fs, ex);
636 codegen_codeABC(fs, OP_SETUPVAL, e, var->u.info, 0);
641 OpCode op = (var->u.ind.vt == VLOCAL) ? OP_SETTABLE_INCR :
643 int e = codegen_exp2RK(fs, ex);
644 codegen_codeABC(fs, op, var->u.ind.t, var->u.ind.idx, e);
648 ktap_assert(0); /* invalid var kind to store */
656 void codegen_self(ktap_funcstate *fs, ktap_expdesc *e, ktap_expdesc *key)
660 codegen_exp2anyreg(fs, e);
661 ereg = e->u.info; /* register where 'e' was placed */
663 e->u.info = fs->freereg; /* base register for op_self */
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));
670 static void invertjump(ktap_funcstate *fs, ktap_expdesc *e)
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)));
678 static int jumponcond(ktap_funcstate *fs, ktap_expdesc *e, int cond)
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);
686 /* else go through */
688 discharge2anyreg(fs, e);
690 return condjump(fs, OP_TESTSET, NO_REG, e->u.info, cond);
693 void codegen_goiftrue(ktap_funcstate *fs, ktap_expdesc *e)
695 int pc; /* pc of last jump */
697 codegen_dischargevars(fs, e);
704 case VK: case VKNUM: case VTRUE: {
705 pc = NO_JUMP; /* always true; do nothing */
709 pc = jumponcond(fs, e, 0);
713 codegen_concat(fs, &e->f, pc); /* insert last jump in `f' list */
714 codegen_patchtohere(fs, e->t);
718 void codegen_goiffalse(ktap_funcstate *fs, ktap_expdesc *e)
720 int pc; /* pc of last jump */
721 codegen_dischargevars(fs, e);
728 case VNIL: case VFALSE: {
729 pc = NO_JUMP; /* always false; do nothing */
733 pc = jumponcond(fs, e, 1);
736 codegen_concat(fs, &e->t, pc); /* insert last jump in `t' list */
737 codegen_patchtohere(fs, e->f);
741 static void codenot(ktap_funcstate *fs, ktap_expdesc *e)
743 codegen_dischargevars(fs, e);
745 case VNIL: case VFALSE: {
749 case VK: case VKNUM: case VTRUE: {
759 discharge2anyreg(fs, e);
761 e->u.info = codegen_codeABC(fs, OP_NOT, 0, e->u.info, 0);
766 ktap_assert(0); /* cannot happen */
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);
776 void codegen_indexed(ktap_funcstate *fs, ktap_expdesc *t, ktap_expdesc *k)
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);
786 static int constfolding(OpCode op, ktap_expdesc *e1, ktap_expdesc *e2)
790 if (!isnumeral(e1) || !isnumeral(e2))
793 if ((op == OP_DIV || op == OP_MOD) && e2->u.nval == 0)
794 return 0; /* do not attempt to divide by 0 */
797 return 0; /* ktap current do not suppor pow arith */
799 r = ktapc_arith(op - OP_ADD + KTAP_OPADD, e1->u.nval, e2->u.nval);
804 static void codearith(ktap_funcstate *fs, OpCode op,
805 ktap_expdesc *e1, ktap_expdesc *e2, int line)
807 if (constfolding(op, e1, e2))
810 int o2 = (op != OP_UNM && op != OP_LEN) ? codegen_exp2RK(fs, e2) : 0;
811 int o1 = codegen_exp2RK(fs, e1);
820 e1->u.info = codegen_codeABC(fs, op, 0, o1, o2);
822 codegen_fixline(fs, line);
826 static void codecomp(ktap_funcstate *fs, OpCode op, int cond, ktap_expdesc *e1,
829 int o1 = codegen_exp2RK(fs, e1);
830 int o2 = codegen_exp2RK(fs, e2);
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 */
839 e1->u.info = condjump(fs, op, cond, o1, o2);
843 void codegen_prefix(ktap_funcstate *fs, UnOpr op, ktap_expdesc *e, int line)
847 e2.t = e2.f = NO_JUMP;
853 if (isnumeral(e)) /* minus constant? */
854 e->u.nval = ktap_numunm(e->u.nval); /* fold it */
856 codegen_exp2anyreg(fs, e);
857 codearith(fs, OP_UNM, e, &e2, line);
865 codegen_exp2anyreg(fs, e); /* cannot operate on constants */
866 codearith(fs, OP_LEN, e, &e2, line);
874 void codegen_infix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *v)
878 codegen_goiftrue(fs, v);
882 codegen_goiffalse(fs, v);
886 codegen_exp2nextreg(fs, v); /* operand must be on the `stack' */
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);
895 codegen_exp2RK(fs, v);
900 void codegen_posfix(ktap_funcstate *fs, BinOpr op, ktap_expdesc *e1, ktap_expdesc *e2, int line)
904 ktap_assert(e1->t == NO_JUMP); /* list must be closed */
905 codegen_dischargevars(fs, e2);
906 codegen_concat(fs, &e2->f, e1->f);
911 ktap_assert(e1->f == NO_JUMP); /* list must be closed */
912 codegen_dischargevars(fs, e2);
913 codegen_concat(fs, &e2->t, e1->t);
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);
922 SETARG_B(getcode(fs, e2), e1->u.info);
923 e1->k = VRELOCABLE; e1->u.info = e2->u.info;
925 codegen_exp2nextreg(fs, e2); /* operand must be on the 'stack' */
926 codearith(fs, OP_CONCAT, e1, e2, line);
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);
935 case OPR_EQ: case OPR_LT: case OPR_LE: {
936 codecomp(fs, (OpCode)(op - OPR_EQ + OP_EQ), 1, e1, e2);
939 case OPR_NE: case OPR_GT: case OPR_GE: {
940 codecomp(fs, (OpCode)(op - OPR_NE + OP_EQ), 0, e1, e2);
948 void codegen_fixline(ktap_funcstate *fs, int line)
950 fs->f->lineinfo[fs->pc - 1] = line;
953 void codegen_setlist(ktap_funcstate *fs, int base, int nelems, int tostore)
955 int c = (nelems - 1)/LFIELDS_PER_FLUSH + 1;
956 int b = (tostore == KTAP_MULTRET) ? 0 : tostore;
958 ktap_assert(tostore != 0);
960 codegen_codeABC(fs, OP_SETLIST, base, b, c);
961 else if (c <= MAXARG_Ax) {
962 codegen_codeABC(fs, OP_SETLIST, base, b, 0);
965 lex_syntaxerror(fs->ls, "constructor too long");
966 fs->freereg = base + 1; /* free registers with list values */