aboutsummaryrefslogtreecommitdiff
path: root/lcode.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-05-06 12:51:41 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2002-05-06 12:51:41 -0300
commit0dbf0c5953a3d72deebc7e41840a0e73b46de8bc (patch)
treeb4a525660cba017d7985c37393f50d6b8bee9e4b /lcode.c
parent85dcb411a8454de0bc1c2c60a24af1588e436c23 (diff)
downloadlua-0dbf0c5953a3d72deebc7e41840a0e73b46de8bc.tar.gz
lua-0dbf0c5953a3d72deebc7e41840a0e73b46de8bc.tar.bz2
lua-0dbf0c5953a3d72deebc7e41840a0e73b46de8bc.zip
new format for test intructions (handle NaN correctly)
Diffstat (limited to 'lcode.c')
-rw-r--r--lcode.c148
1 files changed, 82 insertions, 66 deletions
diff --git a/lcode.c b/lcode.c
index cdac7554..a11ca0e4 100644
--- a/lcode.c
+++ b/lcode.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lcode.c,v 1.96 2002/04/22 14:37:09 roberto Exp roberto $ 2** $Id: lcode.c,v 1.97 2002/04/24 20:07:46 roberto Exp roberto $
3** Code generator for Lua 3** Code generator for Lua
4** See Copyright Notice in lua.h 4** See Copyright Notice in lua.h
5*/ 5*/
@@ -107,16 +107,21 @@ static Instruction *getjumpcontrol (FuncState *fs, int pc) {
107} 107}
108 108
109 109
110static int need_value (FuncState *fs, int list, OpCode op) { 110/*
111 /* check whether list has any jump different from `op' */ 111** check whether list has any jump that do not produce a value
112 for (; list != NO_JUMP; list = luaK_getjump(fs, list)) 112** (or produce an inverted value)
113 if (GET_OPCODE(*getjumpcontrol(fs, list)) != op) return 1; 113*/
114static int need_value (FuncState *fs, int list, int cond) {
115 for (; list != NO_JUMP; list = luaK_getjump(fs, list)) {
116 Instruction i = *getjumpcontrol(fs, list);
117 if (GET_OPCODE(i) != OP_TEST || GETARG_B(i) != cond) return 1;
118 }
114 return 0; /* not found */ 119 return 0; /* not found */
115} 120}
116 121
117 122
118static void patchtestreg (Instruction *i, int reg) { 123static void patchtestreg (Instruction *i, int reg) {
119 if (reg == NO_REG) reg = GETARG_B(*i); 124 if (reg == NO_REG) reg = GETARG_C(*i);
120 SETARG_A(*i, reg); 125 SETARG_A(*i, reg);
121} 126}
122 127
@@ -126,20 +131,20 @@ static void luaK_patchlistaux (FuncState *fs, int list,
126 while (list != NO_JUMP) { 131 while (list != NO_JUMP) {
127 int next = luaK_getjump(fs, list); 132 int next = luaK_getjump(fs, list);
128 Instruction *i = getjumpcontrol(fs, list); 133 Instruction *i = getjumpcontrol(fs, list);
129 switch (GET_OPCODE(*i)) { 134 if (GET_OPCODE(*i) != OP_TEST) {
130 case OP_TESTT: { 135 lua_assert(dtarget != NO_JUMP);
136 luaK_fixjump(fs, list, dtarget); /* jump to default target */
137 }
138 else {
139 if (GETARG_B(*i)) {
140 lua_assert(ttarget != NO_JUMP);
131 patchtestreg(i, treg); 141 patchtestreg(i, treg);
132 luaK_fixjump(fs, list, ttarget); 142 luaK_fixjump(fs, list, ttarget);
133 break;
134 } 143 }
135 case OP_TESTF: { 144 else {
145 lua_assert(ftarget != NO_JUMP);
136 patchtestreg(i, freg); 146 patchtestreg(i, freg);
137 luaK_fixjump(fs, list, ftarget); 147 luaK_fixjump(fs, list, ftarget);
138 break;
139 }
140 default: {
141 luaK_fixjump(fs, list, dtarget); /* jump to default target */
142 break;
143 } 148 }
144 } 149 }
145 list = next; 150 list = next;
@@ -342,9 +347,8 @@ static void luaK_exp2reg (FuncState *fs, expdesc *e, int reg) {
342 int final; /* position after whole expression */ 347 int final; /* position after whole expression */
343 int p_f = NO_JUMP; /* position of an eventual PUSH false */ 348 int p_f = NO_JUMP; /* position of an eventual PUSH false */
344 int p_t = NO_JUMP; /* position of an eventual PUSH true */ 349 int p_t = NO_JUMP; /* position of an eventual PUSH true */
345 if (e->k == VJMP || need_value(fs, e->f, OP_TESTF) || 350 if (e->k == VJMP || need_value(fs, e->t, 1)
346 need_value(fs, e->t, OP_TESTT)) { 351 || need_value(fs, e->f, 0)) {
347 /* expression needs values */
348 if (e->k != VJMP) { 352 if (e->k != VJMP) {
349 luaK_getlabel(fs); /* these instruction may be jump target */ 353 luaK_getlabel(fs); /* these instruction may be jump target */
350 luaK_codeAsBx(fs, OP_JMP, 0, 2); /* to jump over both pushes */ 354 luaK_codeAsBx(fs, OP_JMP, 0, 2); /* to jump over both pushes */
@@ -463,40 +467,36 @@ void luaK_self (FuncState *fs, expdesc *e, expdesc *key) {
463} 467}
464 468
465 469
466static OpCode invertoperator (OpCode op) {
467 switch (op) {
468 case OP_TESTNE: return OP_TESTEQ;
469 case OP_TESTEQ: return OP_TESTNE;
470 case OP_TESTLT: return OP_TESTGE;
471 case OP_TESTLE: return OP_TESTGT;
472 case OP_TESTGT: return OP_TESTLE;
473 case OP_TESTGE: return OP_TESTLT;
474 case OP_TESTT: return OP_TESTF;
475 case OP_TESTF: return OP_TESTT;
476 default: lua_assert(0); return op; /* invalid jump instruction */
477 }
478}
479
480
481static void invertjump (FuncState *fs, expdesc *e) { 470static void invertjump (FuncState *fs, expdesc *e) {
482 Instruction *pc = getjumpcontrol(fs, e->info); 471 Instruction *pc = getjumpcontrol(fs, e->info);
483 SET_OPCODE(*pc, invertoperator(GET_OPCODE(*pc))); 472 OpCode op = GET_OPCODE(*pc);
473 switch (op) {
474 case OP_EQ: {
475 SETARG_B(*pc, !(GETARG_B(*pc)));
476 return;
477 }
478 case OP_CMP: {
479 SETARG_B(*pc, ~(GETARG_B(*pc)));
480 return;
481 }
482 default: lua_assert(0); /* invalid jump instruction */
483 }
484 SET_OPCODE(*pc, op);
484} 485}
485 486
486 487
487static int jumponcond (FuncState *fs, expdesc *e, OpCode op) { 488static int jumponcond (FuncState *fs, expdesc *e, int cond) {
488 if (e->k == VRELOCABLE) { 489 if (e->k == VRELOCABLE) {
489 Instruction ie = getcode(fs, e); 490 Instruction ie = getcode(fs, e);
490 if (GET_OPCODE(ie) == OP_NOT) { 491 if (GET_OPCODE(ie) == OP_NOT) {
491 op = invertoperator(op);
492 fs->pc--; /* remove previous OP_NOT */ 492 fs->pc--; /* remove previous OP_NOT */
493 return luaK_condjump(fs, op, NO_REG, GETARG_B(ie), 0); 493 return luaK_condjump(fs, OP_TEST, NO_REG, !cond ,GETARG_B(ie));
494 } 494 }
495 /* else go through */ 495 /* else go through */
496 } 496 }
497 discharge2anyreg(fs, e); 497 discharge2anyreg(fs, e);
498 freeexp(fs, e); 498 freeexp(fs, e);
499 return luaK_condjump(fs, op, NO_REG, e->info, 0); 499 return luaK_condjump(fs, OP_TEST, NO_REG, cond, e->info);
500} 500}
501 501
502 502
@@ -518,7 +518,7 @@ void luaK_goiftrue (FuncState *fs, expdesc *e) {
518 break; 518 break;
519 } 519 }
520 default: { 520 default: {
521 pc = jumponcond(fs, e, OP_TESTF); 521 pc = jumponcond(fs, e, 0);
522 break; 522 break;
523 } 523 }
524 } 524 }
@@ -545,7 +545,7 @@ static void luaK_goiffalse (FuncState *fs, expdesc *e) {
545 break; 545 break;
546 } 546 }
547 default: { 547 default: {
548 pc = jumponcond(fs, e, OP_TESTT); 548 pc = jumponcond(fs, e, 1);
549 break; 549 break;
550 } 550 }
551 } 551 }
@@ -639,23 +639,46 @@ void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
639 639
640 640
641 641
642/* opcode for each binary operator */ 642static const OpCode cmp_masks[] = { /* ORDER OPR */
643static const OpCode codes[] = { /* ORDER OPR */ 643 CMP_LT, (CMP_LT | CMP_EQ), CMP_GT, (CMP_GT | CMP_EQ)
644 OP_ADD, OP_SUB, OP_MUL, OP_DIV,
645 OP_POW, OP_CONCAT,
646 OP_TESTNE, OP_TESTEQ,
647 OP_TESTLT, OP_TESTLE, OP_TESTGT, OP_TESTGE
648}; 644};
649 645
650 646
651/* `inverted' opcode for each binary operator */ 647static void codebinop (FuncState *fs, expdesc *res, BinOpr op,
652/* ( -1 means operator has no inverse) */ 648 int o1, int o2, int ic) {
653static const OpCode invcodes[] = { /* ORDER OPR */ 649 switch (op) {
654 OP_ADD, (OpCode)-1, OP_MUL, (OpCode)-1, 650 case OPR_SUB:
655 (OpCode)-1, (OpCode)-1, 651 case OPR_DIV:
656 OP_TESTNE, OP_TESTEQ, 652 case OPR_POW:
657 OP_TESTGT, OP_TESTGE, OP_TESTLT, OP_TESTLE 653 lua_assert(!ic);
658}; 654 /* go through */
655 case OPR_ADD:
656 case OPR_MULT: {
657 OpCode opc = cast(OpCode, (op - OPR_ADD) + OP_ADD);
658 res->info = luaK_codeABC(fs, opc, 0, o1, o2);
659 res->k = VRELOCABLE;
660 break;
661 }
662 case OPR_NE:
663 case OPR_EQ: {
664 res->info = luaK_condjump(fs, OP_EQ, o1, (op == OPR_EQ), o2);
665 res->k = VJMP;
666 break;
667 }
668 case OPR_LT:
669 case OPR_LE:
670 case OPR_GT:
671 case OPR_GE: {
672 int mask = cmp_masks[op - OPR_LT];
673 if (ic) /* operands were interchanged? */
674 mask ^= (CMP_LT | CMP_GT); /* correct condition */
675 res->info = luaK_condjump(fs, OP_CMP, o1, mask, o2);
676 res->k = VJMP;
677 break;
678 }
679 default: lua_assert(0);
680 }
681}
659 682
660 683
661void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) { 684void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
@@ -693,27 +716,20 @@ void luaK_posfix (FuncState *fs, BinOpr op, expdesc *e1, expdesc *e2) {
693 } 716 }
694 default: { 717 default: {
695 int o1, o2; 718 int o1, o2;
696 OpCode opc; 719 int ic; /* interchange flag */
697 if (e1->k != VK) { /* not a constant operator? */ 720 if (e1->k != VK) { /* not a constant operator? */
698 o1 = e1->info; 721 o1 = e1->info;
699 o2 = luaK_exp2RK(fs, e2); /* maybe other operator is constant... */ 722 o2 = luaK_exp2RK(fs, e2); /* maybe other operator is constant... */
700 opc = codes[op]; 723 ic = 0;
701 } 724 }
702 else { /* invert operands */ 725 else { /* interchange operands */
703 o2 = luaK_exp2RK(fs, e1); /* constant must be 2nd operand */ 726 o2 = luaK_exp2RK(fs, e1); /* constant must be 2nd operand */
704 o1 = luaK_exp2anyreg(fs, e2); /* other operator must be in register */ 727 o1 = luaK_exp2anyreg(fs, e2); /* other operator must be in register */
705 opc = invcodes[op]; /* use inverted operator */ 728 ic = 1;
706 } 729 }
707 freeexp(fs, e2); 730 freeexp(fs, e2);
708 freeexp(fs, e1); 731 freeexp(fs, e1);
709 if (op < OPR_NE) { /* ORDER OPR */ 732 codebinop(fs, e1, op, o1, o2, ic);
710 e1->info = luaK_codeABC(fs, opc, 0, o1, o2);
711 e1->k = VRELOCABLE;
712 }
713 else { /* jump */
714 e1->info = luaK_condjump(fs, opc, o1, 0, o2);
715 e1->k = VJMP;
716 }
717 } 733 }
718 } 734 }
719} 735}