diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2016-01-04 11:40:57 -0200 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2016-01-04 11:40:57 -0200 |
commit | b12b635a9052240538daf0d049834b60aa64b435 (patch) | |
tree | db7df4a80a7180044dd8ab407b5ac4b64e172308 | |
parent | 7cd7c2e0a1e947bbcb03da123b31f4f74b366020 (diff) | |
download | lua-b12b635a9052240538daf0d049834b60aa64b435.tar.gz lua-b12b635a9052240538daf0d049834b60aa64b435.tar.bz2 lua-b12b635a9052240538daf0d049834b60aa64b435.zip |
more refactoring
-rw-r--r-- | lcode.c | 191 |
1 files changed, 97 insertions, 94 deletions
@@ -1,5 +1,5 @@ | |||
1 | /* | 1 | /* |
2 | ** $Id: lcode.c,v 2.103 2015/11/19 19:16:22 roberto Exp roberto $ | 2 | ** $Id: lcode.c,v 2.106 2015/12/18 13:53:36 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 | */ |
@@ -401,6 +401,24 @@ static void freeexp (FuncState *fs, expdesc *e) { | |||
401 | 401 | ||
402 | 402 | ||
403 | /* | 403 | /* |
404 | ** Free registers used by expressions 'e1' and 'e2' (if any) in proper | ||
405 | ** order. | ||
406 | */ | ||
407 | static void freeexps (FuncState *fs, expdesc *e1, expdesc *e2) { | ||
408 | int r1 = (e1->k == VNONRELOC) ? e1->u.info : -1; | ||
409 | int r2 = (e2->k == VNONRELOC) ? e2->u.info : -1; | ||
410 | if (r1 > r2) { | ||
411 | freereg(fs, r1); | ||
412 | freereg(fs, r2); | ||
413 | } | ||
414 | else { | ||
415 | freereg(fs, r2); | ||
416 | freereg(fs, r1); | ||
417 | } | ||
418 | } | ||
419 | |||
420 | |||
421 | /* | ||
404 | ** Add constant 'v' to prototype's list of constants (field 'k'). | 422 | ** Add constant 'v' to prototype's list of constants (field 'k'). |
405 | ** Use scanner's table to cache position of constants in constant list | 423 | ** Use scanner's table to cache position of constants in constant list |
406 | ** and try to reuse constants. Because some values should not be used | 424 | ** and try to reuse constants. Because some values should not be used |
@@ -531,33 +549,35 @@ void luaK_setoneret (FuncState *fs, expdesc *e) { | |||
531 | 549 | ||
532 | 550 | ||
533 | /* | 551 | /* |
534 | ** Ensure that expression 'e' has a value somewhere (either it | 552 | ** Ensure that expression 'e' is not a variable. |
535 | ** is a constant or result is in a register). | ||
536 | */ | 553 | */ |
537 | void luaK_dischargevars (FuncState *fs, expdesc *e) { | 554 | void luaK_dischargevars (FuncState *fs, expdesc *e) { |
538 | switch (e->k) { | 555 | switch (e->k) { |
539 | case VLOCAL: { | 556 | case VLOCAL: { /* already in a register */ |
540 | e->k = VNONRELOC; /* becomes a non-relocatable value */ | 557 | e->k = VNONRELOC; /* becomes a non-relocatable value */ |
541 | break; | 558 | break; |
542 | } | 559 | } |
543 | case VUPVAL: { | 560 | case VUPVAL: { /* move value to some (pending) register */ |
544 | e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); | 561 | e->u.info = luaK_codeABC(fs, OP_GETUPVAL, 0, e->u.info, 0); |
545 | e->k = VRELOCABLE; | 562 | e->k = VRELOCABLE; |
546 | break; | 563 | break; |
547 | } | 564 | } |
548 | case VINDEXED: { | 565 | case VINDEXED: { |
549 | OpCode op = OP_GETTABUP; /* assume 't' is in an upvalue */ | 566 | OpCode op; |
550 | freereg(fs, e->u.ind.idx); | 567 | freereg(fs, e->u.ind.idx); |
551 | if (e->u.ind.vt == VLOCAL) { /* 't' is in a register? */ | 568 | if (e->u.ind.vt == VLOCAL) { /* is 't' in a register? */ |
552 | freereg(fs, e->u.ind.t); | 569 | freereg(fs, e->u.ind.t); |
553 | op = OP_GETTABLE; | 570 | op = OP_GETTABLE; |
554 | } | 571 | } |
572 | else { | ||
573 | lua_assert(e->u.ind.vt == VUPVAL); | ||
574 | op = OP_GETTABUP; /* 't' is in an upvalue */ | ||
575 | } | ||
555 | e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); | 576 | e->u.info = luaK_codeABC(fs, op, 0, e->u.ind.t, e->u.ind.idx); |
556 | e->k = VRELOCABLE; | 577 | e->k = VRELOCABLE; |
557 | break; | 578 | break; |
558 | } | 579 | } |
559 | case VVARARG: | 580 | case VVARARG: case VCALL: { |
560 | case VCALL: { | ||
561 | luaK_setoneret(fs, e); | 581 | luaK_setoneret(fs, e); |
562 | break; | 582 | break; |
563 | } | 583 | } |
@@ -731,36 +751,22 @@ void luaK_exp2val (FuncState *fs, expdesc *e) { | |||
731 | ** Ensures final expression result is in a valid R/K index | 751 | ** Ensures final expression result is in a valid R/K index |
732 | ** (that is, it is either in a register or in 'k' with an index | 752 | ** (that is, it is either in a register or in 'k' with an index |
733 | ** in the range of R/K indices). | 753 | ** in the range of R/K indices). |
754 | ** Returns R/K index. | ||
734 | */ | 755 | */ |
735 | int luaK_exp2RK (FuncState *fs, expdesc *e) { | 756 | int luaK_exp2RK (FuncState *fs, expdesc *e) { |
736 | luaK_exp2val(fs, e); | 757 | luaK_exp2val(fs, e); |
737 | switch (e->k) { /* handle constants */ | 758 | switch (e->k) { /* move constants to 'k' */ |
738 | case VTRUE: | 759 | case VTRUE: e->u.info = boolK(fs, 1); goto vk; |
739 | case VFALSE: | 760 | case VFALSE: e->u.info = boolK(fs, 0); goto vk; |
740 | case VNIL: { | 761 | case VNIL: e->u.info = nilK(fs); goto vk; |
741 | if (fs->nk <= MAXINDEXRK) { /* constant fits in RK operand? */ | 762 | case VKINT: e->u.info = luaK_intK(fs, e->u.ival); goto vk; |
742 | e->u.info = (e->k == VNIL) ? nilK(fs) : boolK(fs, (e->k == VTRUE)); | 763 | case VKFLT: e->u.info = luaK_numberK(fs, e->u.nval); goto vk; |
743 | e->k = VK; | 764 | case VK: |
744 | return RKASK(e->u.info); | ||
745 | } | ||
746 | else break; | ||
747 | } | ||
748 | case VKINT: { | ||
749 | e->u.info = luaK_intK(fs, e->u.ival); | ||
750 | e->k = VK; | ||
751 | goto vk; | ||
752 | } | ||
753 | case VKFLT: { | ||
754 | e->u.info = luaK_numberK(fs, e->u.nval); | ||
755 | e->k = VK; | ||
756 | } | ||
757 | /* FALLTHROUGH */ | ||
758 | case VK: { | ||
759 | vk: | 765 | vk: |
766 | e->k = VK; | ||
760 | if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ | 767 | if (e->u.info <= MAXINDEXRK) /* constant fits in 'argC'? */ |
761 | return RKASK(e->u.info); | 768 | return RKASK(e->u.info); |
762 | else break; | 769 | else break; |
763 | } | ||
764 | default: break; | 770 | default: break; |
765 | } | 771 | } |
766 | /* not a constant in the right range: put it in a register */ | 772 | /* not a constant in the right range: put it in a register */ |
@@ -988,65 +994,62 @@ static int constfolding (FuncState *fs, int op, expdesc *e1, expdesc *e2) { | |||
988 | 994 | ||
989 | 995 | ||
990 | /* | 996 | /* |
991 | ** Emit code for binary and unary expressions that "produce values" | 997 | ** Emit code for unary expressions that "produce values" |
992 | ** (everything but logical operators 'and', 'or' and comparison | 998 | ** (everything but 'not'). |
999 | ** Expression to produce final result will be encoded in 'e'. | ||
1000 | */ | ||
1001 | static void codeunexpval (FuncState *fs, OpCode op, expdesc *e, int line) { | ||
1002 | int r = luaK_exp2anyreg(fs, e); /* opcodes operate only on registers */ | ||
1003 | freeexp(fs, e); | ||
1004 | e->u.info = luaK_codeABC(fs, op, 0, r, 0); /* generate opcode */ | ||
1005 | e->k = VRELOCABLE; /* all those operations are relocatable */ | ||
1006 | luaK_fixline(fs, line); | ||
1007 | } | ||
1008 | |||
1009 | |||
1010 | /* | ||
1011 | ** Emit code for binary expressions that "produce values" | ||
1012 | ** (everything but logical operators 'and'/'or' and comparison | ||
993 | ** operators). | 1013 | ** operators). |
994 | ** First try to do constant folding (only for numeric [arithmetic and | 1014 | ** Expression to produce final result will be encoded in 'e1'. |
995 | ** bitwise] operations, which is what 'lua_arith' accepts). Expression | ||
996 | ** to produce final result will be encoded in 'e1'. | ||
997 | ** (The "free registers in proper order" reason is tricky: because | ||
998 | ** expression evaluation can be delayed, the final numbering for | ||
999 | ** registers in 'e1' and 'e2' depends on how each one was delayed.) | ||
1000 | */ | 1015 | */ |
1001 | static void codeexpval (FuncState *fs, OpCode op, | 1016 | static void codebinexpval (FuncState *fs, OpCode op, |
1002 | expdesc *e1, expdesc *e2, int line) { | 1017 | expdesc *e1, expdesc *e2, int line) { |
1003 | lua_assert(OP_ADD <= op && op <= OP_CONCAT); | 1018 | int rk1 = luaK_exp2RK(fs, e1); /* both operands are "RK" */ |
1004 | if (op <= OP_BNOT && constfolding(fs, (op - OP_ADD) + LUA_OPADD, e1, e2)) | 1019 | int rk2 = luaK_exp2RK(fs, e2); |
1005 | return; /* result has been folded */ | 1020 | freeexps(fs, e1, e2); |
1006 | else { | 1021 | e1->u.info = luaK_codeABC(fs, op, 0, rk1, rk2); /* generate opcode */ |
1007 | int o1, o2; | 1022 | e1->k = VRELOCABLE; /* all those operations are relocatable */ |
1008 | /* move operands to registers (if needed) */ | 1023 | luaK_fixline(fs, line); |
1009 | if (op == OP_UNM || op == OP_BNOT || op == OP_LEN) { /* unary op? */ | ||
1010 | o2 = 0; /* no second expression */ | ||
1011 | o1 = luaK_exp2anyreg(fs, e1); /* cannot operate on constants */ | ||
1012 | } | ||
1013 | else { /* regular case (binary operators) */ | ||
1014 | o2 = luaK_exp2RK(fs, e2); /* both operands are "RK" */ | ||
1015 | o1 = luaK_exp2RK(fs, e1); | ||
1016 | } | ||
1017 | if (o1 > o2) { /* free registers in proper order */ | ||
1018 | freeexp(fs, e1); | ||
1019 | freeexp(fs, e2); | ||
1020 | } | ||
1021 | else { | ||
1022 | freeexp(fs, e2); | ||
1023 | freeexp(fs, e1); | ||
1024 | } | ||
1025 | e1->u.info = luaK_codeABC(fs, op, 0, o1, o2); /* generate opcode */ | ||
1026 | e1->k = VRELOCABLE; /* all those operations are relocatable */ | ||
1027 | luaK_fixline(fs, line); | ||
1028 | } | ||
1029 | } | 1024 | } |
1030 | 1025 | ||
1031 | 1026 | ||
1032 | /* | 1027 | /* |
1033 | ** Emit code for comparisons. | 1028 | ** Emit code for comparisons. |
1034 | ** Code will jump if result equals 'cond' ('cond' true <=> code will | 1029 | ** 'e1' was already put in R/K form by 'luaK_infix'. |
1035 | ** jump if result is true). | ||
1036 | */ | 1030 | */ |
1037 | static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, | 1031 | static void codecomp (FuncState *fs, BinOpr opr, expdesc *e1, expdesc *e2) { |
1038 | expdesc *e2) { | 1032 | int rk1 = (e1->k == VK) ? RKASK(e1->u.info) |
1039 | int o1 = luaK_exp2RK(fs, e1); | 1033 | : check_exp(e1->k == VNONRELOC, e1->u.info); |
1040 | int o2 = luaK_exp2RK(fs, e2); | 1034 | int rk2 = luaK_exp2RK(fs, e2); |
1041 | lua_assert(OP_EQ <= op && op <= OP_LE); /* comparison operation */ | 1035 | freeexps(fs, e1, e2); |
1042 | freeexp(fs, e2); | 1036 | switch (opr) { |
1043 | freeexp(fs, e1); | 1037 | case OPR_NE: { /* '(a ~= b)' ==> 'not (a == b)' */ |
1044 | if (cond == 0 && op != OP_EQ) { | 1038 | e1->u.info = condjump(fs, OP_EQ, 0, rk1, rk2); |
1045 | int temp; /* exchange args to replace by '<' or '<=' */ | 1039 | break; |
1046 | temp = o1; o1 = o2; o2 = temp; /* o1 <==> o2 */ | 1040 | } |
1047 | cond = 1; | 1041 | case OPR_GT: case OPR_GE: { |
1042 | /* '(a > b)' ==> '(b < a)'; '(a >= b)' ==> '(b <= a)' */ | ||
1043 | OpCode op = cast(OpCode, (opr - OPR_NE) + OP_EQ); | ||
1044 | e1->u.info = condjump(fs, op, 1, rk2, rk1); /* invert operands */ | ||
1045 | break; | ||
1046 | } | ||
1047 | default: { /* '==', '<', '<=' use their own opcodes */ | ||
1048 | OpCode op = cast(OpCode, (opr - OPR_EQ) + OP_EQ); | ||
1049 | e1->u.info = condjump(fs, op, 1, rk1, rk2); | ||
1050 | break; | ||
1051 | } | ||
1048 | } | 1052 | } |
1049 | e1->u.info = condjump(fs, op, cond, o1, o2); | ||
1050 | e1->k = VJMP; | 1053 | e1->k = VJMP; |
1051 | } | 1054 | } |
1052 | 1055 | ||
@@ -1055,13 +1058,15 @@ static void codecomp (FuncState *fs, OpCode op, int cond, expdesc *e1, | |||
1055 | ** Aplly prefix operation 'op' to expression 'e'. | 1058 | ** Aplly prefix operation 'op' to expression 'e'. |
1056 | */ | 1059 | */ |
1057 | void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { | 1060 | void luaK_prefix (FuncState *fs, UnOpr op, expdesc *e, int line) { |
1058 | expdesc e2; /* fake 2nd operand */ | 1061 | static expdesc ef = {VKINT, {0}, NO_JUMP, NO_JUMP}; /* fake 2nd operand */ |
1059 | e2.t = e2.f = NO_JUMP; e2.k = VKINT; e2.u.ival = 0; | ||
1060 | switch (op) { | 1062 | switch (op) { |
1061 | case OPR_MINUS: case OPR_BNOT: case OPR_LEN: { | 1063 | case OPR_MINUS: case OPR_BNOT: |
1062 | codeexpval(fs, cast(OpCode, (op - OPR_MINUS) + OP_UNM), e, &e2, line); | 1064 | if (constfolding(fs, op + LUA_OPUNM, e, &ef)) |
1065 | break; | ||
1066 | /* else go through */ | ||
1067 | case OPR_LEN: | ||
1068 | codeunexpval(fs, cast(OpCode, op + OP_UNM), e, line); | ||
1063 | break; | 1069 | break; |
1064 | } | ||
1065 | case OPR_NOT: codenot(fs, e); break; | 1070 | case OPR_NOT: codenot(fs, e); break; |
1066 | default: lua_assert(0); | 1071 | default: lua_assert(0); |
1067 | } | 1072 | } |
@@ -1137,7 +1142,7 @@ void luaK_posfix (FuncState *fs, BinOpr op, | |||
1137 | } | 1142 | } |
1138 | else { | 1143 | else { |
1139 | luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ | 1144 | luaK_exp2nextreg(fs, e2); /* operand must be on the 'stack' */ |
1140 | codeexpval(fs, OP_CONCAT, e1, e2, line); | 1145 | codebinexpval(fs, OP_CONCAT, e1, e2, line); |
1141 | } | 1146 | } |
1142 | break; | 1147 | break; |
1143 | } | 1148 | } |
@@ -1145,15 +1150,13 @@ void luaK_posfix (FuncState *fs, BinOpr op, | |||
1145 | case OPR_IDIV: case OPR_MOD: case OPR_POW: | 1150 | case OPR_IDIV: case OPR_MOD: case OPR_POW: |
1146 | case OPR_BAND: case OPR_BOR: case OPR_BXOR: | 1151 | case OPR_BAND: case OPR_BOR: case OPR_BXOR: |
1147 | case OPR_SHL: case OPR_SHR: { | 1152 | case OPR_SHL: case OPR_SHR: { |
1148 | codeexpval(fs, cast(OpCode, (op - OPR_ADD) + OP_ADD), e1, e2, line); | 1153 | if (!constfolding(fs, op + LUA_OPADD, e1, e2)) |
1149 | break; | 1154 | codebinexpval(fs, cast(OpCode, op + OP_ADD), e1, e2, line); |
1150 | } | ||
1151 | case OPR_EQ: case OPR_LT: case OPR_LE: { | ||
1152 | codecomp(fs, cast(OpCode, (op - OPR_EQ) + OP_EQ), 1, e1, e2); | ||
1153 | break; | 1155 | break; |
1154 | } | 1156 | } |
1157 | case OPR_EQ: case OPR_LT: case OPR_LE: | ||
1155 | case OPR_NE: case OPR_GT: case OPR_GE: { | 1158 | case OPR_NE: case OPR_GT: case OPR_GE: { |
1156 | codecomp(fs, cast(OpCode, (op - OPR_NE) + OP_EQ), 0, e1, e2); | 1159 | codecomp(fs, op, e1, e2); |
1157 | break; | 1160 | break; |
1158 | } | 1161 | } |
1159 | default: lua_assert(0); | 1162 | default: lua_assert(0); |