aboutsummaryrefslogtreecommitdiff
path: root/lcode.c
diff options
context:
space:
mode:
authorRoberto Ierusalimschy <roberto@inf.puc-rio.br>2000-03-04 17:18:15 -0300
committerRoberto Ierusalimschy <roberto@inf.puc-rio.br>2000-03-04 17:18:15 -0300
commit563de491be90601f23a735aede89ea9a3ef86ee9 (patch)
treec92677f388289ead55c8a8778493b0af7e41f159 /lcode.c
parent29e01934253adf5fbf43faff81d87d7470cef8ce (diff)
downloadlua-563de491be90601f23a735aede89ea9a3ef86ee9.tar.gz
lua-563de491be90601f23a735aede89ea9a3ef86ee9.tar.bz2
lua-563de491be90601f23a735aede89ea9a3ef86ee9.zip
a better way to control optimizations.
Diffstat (limited to 'lcode.c')
-rw-r--r--lcode.c160
1 files changed, 98 insertions, 62 deletions
diff --git a/lcode.c b/lcode.c
index be97e2bb..d43103fd 100644
--- a/lcode.c
+++ b/lcode.c
@@ -1,5 +1,5 @@
1/* 1/*
2** $Id: lcode.c,v 1.4 2000/03/03 18:53:17 roberto Exp roberto $ 2** $Id: lcode.c,v 1.5 2000/03/03 20:30:47 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*/
@@ -20,10 +20,19 @@ void luaK_error (LexState *ls, const char *msg) {
20} 20}
21 21
22 22
23static Instruction *last_i (LexState *ls, expdesc *v) { 23/*
24** Returns the address of the previous instruction, for optimizations.
25** If there is a jump target between this and the current instruction,
26** returns the address of a dummy instruction to avoid wrong optimizations.
27*/
28static Instruction *previous_instruction (LexState *ls) {
24 FuncState *fs = ls->fs; 29 FuncState *fs = ls->fs;
25 int last_pc = (v->info != NOJUMPS) ? v->info : fs->pc-1; 30 if (fs->pc > fs->lasttarget) /* no jumps to current position? */
26 return &fs->f->code[last_pc]; 31 return &fs->f->code[fs->pc-1]; /* returns previous instruction */
32 else {
33 static Instruction dummy = CREATE_0(ENDCODE);
34 return &dummy; /* no optimizations after an `ENDCODE' */
35 }
27} 36}
28 37
29 38
@@ -35,61 +44,74 @@ int luaK_primitivecode (LexState *ls, Instruction i) {
35} 44}
36 45
37 46
38static void luaK_minus (LexState *ls, expdesc *v) { 47static void luaK_minus (LexState *ls) {
39 Instruction *last = last_i(ls, v); 48 Instruction *previous = previous_instruction(ls);
40 switch(GET_OPCODE(*last)) { 49 switch(GET_OPCODE(*previous)) {
41 case PUSHINT: *last = SETARG_S(*last, -GETARG_S(*last)); return; 50 case PUSHINT: *previous = SETARG_S(*previous, -GETARG_S(*previous)); return;
42 case PUSHNUM: *last = SET_OPCODE(*last, PUSHNEGNUM); return; 51 case PUSHNUM: *previous = SET_OPCODE(*previous, PUSHNEGNUM); return;
43 case PUSHNEGNUM: *last = SET_OPCODE(*last, PUSHNUM); return; 52 case PUSHNEGNUM: *previous = SET_OPCODE(*previous, PUSHNUM); return;
44 default: luaK_primitivecode(ls, CREATE_0(MINUSOP)); 53 default: luaK_primitivecode(ls, CREATE_0(MINUSOP));
45 } 54 }
46} 55}
47 56
48 57
49static void luaK_gettable (LexState *ls, expdesc *v) { 58static void luaK_gettable (LexState *ls) {
50 Instruction *last = last_i(ls, v); 59 Instruction *previous = previous_instruction(ls);
51 luaK_deltastack(ls, -1); 60 luaK_deltastack(ls, -1);
52 switch(GET_OPCODE(*last)) { 61 switch(GET_OPCODE(*previous)) {
53 case PUSHSTRING: *last = SET_OPCODE(*last, GETDOTTED); break; 62 case PUSHSTRING: *previous = SET_OPCODE(*previous, GETDOTTED); break;
54 default: luaK_primitivecode(ls, CREATE_0(GETTABLE)); 63 default: luaK_primitivecode(ls, CREATE_0(GETTABLE));
55 } 64 }
56} 65}
57 66
58 67
59static void luaK_add (LexState *ls, expdesc *v) { 68static void luaK_add (LexState *ls) {
60 Instruction *last = last_i(ls, v); 69 Instruction *previous = previous_instruction(ls);
61 luaK_deltastack(ls, -1); 70 luaK_deltastack(ls, -1);
62 switch(GET_OPCODE(*last)) { 71 switch(GET_OPCODE(*previous)) {
63 case PUSHINT: *last = SET_OPCODE(*last, ADDI); break; 72 case PUSHINT: *previous = SET_OPCODE(*previous, ADDI); break;
64 default: luaK_primitivecode(ls, CREATE_0(ADDOP)); 73 default: luaK_primitivecode(ls, CREATE_0(ADDOP));
65 } 74 }
66} 75}
67 76
68 77
69static void luaK_sub (LexState *ls, expdesc *v) { 78static void luaK_sub (LexState *ls) {
70 Instruction *last = last_i(ls, v); 79 Instruction *previous = previous_instruction(ls);
71 luaK_deltastack(ls, -1); 80 luaK_deltastack(ls, -1);
72 switch(GET_OPCODE(*last)) { 81 switch(GET_OPCODE(*previous)) {
73 case PUSHINT: 82 case PUSHINT:
74 *last = SET_OPCODE(*last, ADDI); 83 *previous = SET_OPCODE(*previous, ADDI);
75 *last = SETARG_S(*last, -GETARG_S(*last)); 84 *previous = SETARG_S(*previous, -GETARG_S(*previous));
76 break; 85 break;
77 default: luaK_primitivecode(ls, CREATE_0(SUBOP)); 86 default: luaK_primitivecode(ls, CREATE_0(SUBOP));
78 } 87 }
79} 88}
80 89
81 90
82void luaK_retcode (LexState *ls, int nlocals, listdesc *e) { 91void luaK_retcode (LexState *ls, int nlocals, int nexps) {
83 if (e->n > 0 && luaK_iscall(ls, e->info)) { 92 Instruction *previous = previous_instruction(ls);
84 Instruction *last = &ls->fs->f->code[ls->fs->pc-1]; 93 if (nexps > 0 && GET_OPCODE(*previous) == CALL) {
85 *last = SET_OPCODE(*last, TAILCALL); 94 LUA_ASSERT(ls->L, GETARG_B(*previous) == MULT_RET, "call should be open");
86 *last = SETARG_B(*last, nlocals); 95 *previous = SET_OPCODE(*previous, TAILCALL);
96 *previous = SETARG_B(*previous, nlocals);
87 } 97 }
88 else 98 else
89 luaK_primitivecode(ls, CREATE_U(RETCODE, nlocals)); 99 luaK_primitivecode(ls, CREATE_U(RETCODE, nlocals));
90} 100}
91 101
92 102
103static void luaK_pushnil (LexState *ls, int n) {
104 Instruction *previous = previous_instruction(ls);
105 luaK_deltastack(ls, n);
106 switch(GET_OPCODE(*previous)) {
107 case PUSHNIL:
108 *previous = SETARG_U(*previous, GETARG_U(*previous)+n);
109 break;
110 default: luaK_primitivecode(ls, CREATE_U(PUSHNIL, n));
111 }
112}
113
114
93int luaK_code (LexState *ls, Instruction i, int delta) { 115int luaK_code (LexState *ls, Instruction i, int delta) {
94 luaK_deltastack(ls, delta); 116 luaK_deltastack(ls, delta);
95 return luaK_primitivecode(ls, i); 117 return luaK_primitivecode(ls, i);
@@ -104,6 +126,17 @@ void luaK_fixjump (LexState *ls, int pc, int dest) {
104} 126}
105 127
106 128
129/*
130** returns current `pc' and marks it as a jump target (to avoid wrong
131** optimizations with consecutive instructions not in the same basic block).
132*/
133int luaK_getlabel (LexState *ls) {
134 FuncState *fs = ls->fs;
135 fs->lasttarget = fs->pc;
136 return fs->pc;
137}
138
139
107void luaK_deltastack (LexState *ls, int delta) { 140void luaK_deltastack (LexState *ls, int delta) {
108 FuncState *fs = ls->fs; 141 FuncState *fs = ls->fs;
109 fs->stacksize += delta; 142 fs->stacksize += delta;
@@ -151,28 +184,27 @@ void luaK_adjuststack (LexState *ls, int n) {
151 if (n > 0) 184 if (n > 0)
152 luaK_U(ls, POP, n, -n); 185 luaK_U(ls, POP, n, -n);
153 else if (n < 0) 186 else if (n < 0)
154 luaK_U(ls, PUSHNIL, (-n)-1, -n); 187 luaK_pushnil(ls, -n);
155} 188}
156 189
157 190
158int luaK_iscall (LexState *ls, int hasjumps) { 191int luaK_lastisopen (LexState *ls) {
159 if (hasjumps) return 0; /* a call cannot have internal jumps */ 192 /* check whether last instruction is an (open) function call */
160 else /* check whether last instruction is a function call */ 193 Instruction *i = previous_instruction(ls);
161 return (GET_OPCODE(ls->fs->f->code[ls->fs->pc-1]) == CALL); 194 if (GET_OPCODE(*i) == CALL) {
195 LUA_ASSERT(ls->L, GETARG_B(*i) == MULT_RET, "call should be open");
196 return 1;
197 }
198 else return 0;
162} 199}
163 200
164 201
165void luaK_setcallreturns (LexState *ls, int hasjumps, int nresults) { 202void luaK_setcallreturns (LexState *ls, int nresults) {
166 if (!hasjumps) { /* if `hasjumps' cannot be a function call */ 203 Instruction *i = previous_instruction(ls);
167 Instruction *i = &ls->fs->f->code[ls->fs->pc-1]; 204 if (GET_OPCODE(*i) == CALL) { /* expression is a function call? */
168 if (GET_OPCODE(*i) == CALL) { /* expression is a function call? */ 205 LUA_ASSERT(ls->L, GETARG_B(*i) == MULT_RET, "call should be open");
169 int old_nresults = GETARG_B(*i); 206 *i = SETARG_B(*i, nresults); /* set nresults */
170 if (old_nresults != MULT_RET) 207 luaK_deltastack(ls, nresults); /* push results */
171 luaK_deltastack(ls, -old_nresults); /* pop old nresults */
172 *i = SETARG_B(*i, nresults); /* set nresults */
173 if (nresults != MULT_RET)
174 luaK_deltastack(ls, nresults); /* push results */
175 }
176 } 208 }
177} 209}
178 210
@@ -182,7 +214,7 @@ static void assertglobal (LexState *ls, int index) {
182} 214}
183 215
184 216
185void luaK_2stack (LexState *ls, expdesc *var) { 217void luaK_tostack (LexState *ls, expdesc *var) {
186 switch (var->k) { 218 switch (var->k) {
187 case VLOCAL: 219 case VLOCAL:
188 luaK_U(ls, PUSHLOCAL, var->info, 1); 220 luaK_U(ls, PUSHLOCAL, var->info, 1);
@@ -192,14 +224,20 @@ void luaK_2stack (LexState *ls, expdesc *var) {
192 assertglobal(ls, var->info); /* make sure that there is a global */ 224 assertglobal(ls, var->info); /* make sure that there is a global */
193 break; 225 break;
194 case VINDEXED: 226 case VINDEXED:
195 luaK_gettable(ls, var); 227 luaK_gettable(ls);
196 break; 228 break;
197 case VEXP: 229 case VEXP:
198 luaK_setcallreturns(ls, var->info, 1); /* call must return 1 value */ 230 return; /* exp result is already on stack */
199 return; /* does not change var->info */
200 } 231 }
201 var->k = VEXP; 232 var->k = VEXP;
202 var->info = NOJUMPS; 233}
234
235
236void luaK_1tostack (LexState *ls, expdesc *var) {
237 if (var->k == VEXP)
238 luaK_setcallreturns(ls, 1); /* call must return 1 value */
239 else
240 luaK_tostack(ls, var);
203} 241}
204 242
205 243
@@ -222,30 +260,29 @@ void luaK_storevar (LexState *ls, const expdesc *var) {
222 260
223 261
224void luaK_prefix (LexState *ls, int op, expdesc *v) { 262void luaK_prefix (LexState *ls, int op, expdesc *v) {
225 luaK_2stack(ls, v); 263 luaK_1tostack(ls, v);
226 if (op == '-') luaK_minus(ls, v); 264 if (op == '-') luaK_minus(ls);
227 else luaK_0(ls, NOTOP, 0); 265 else luaK_0(ls, NOTOP, 0);
228 v->info = NOJUMPS;
229} 266}
230 267
231 268
232void luaK_infix (LexState *ls, expdesc *v) { 269void luaK_infix (LexState *ls, int op, expdesc *v) {
233 luaK_2stack(ls, v); 270 luaK_1tostack(ls, v);
234 if (ls->token == AND) 271 if (op == AND)
235 v->info = luaK_0(ls, ONFJMP, -1); 272 v->info = luaK_0(ls, ONFJMP, -1);
236 else if (ls->token == OR) 273 else if (op == OR)
237 v->info = luaK_0(ls, ONTJMP, -1); 274 v->info = luaK_0(ls, ONTJMP, -1);
238} 275}
239 276
240 277
241void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) { 278void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) {
242 luaK_2stack(ls, v2); 279 luaK_1tostack(ls, v2);
243 switch (op) { 280 switch (op) {
244 case AND: case OR: 281 case AND: case OR:
245 luaK_fixjump(ls, v1->info, ls->fs->pc); 282 luaK_fixjump(ls, v1->info, luaK_getlabel(ls));
246 return; /* keep v1->info != NOJUMPS */ 283 break;
247 case '+': luaK_add(ls, v2); break; 284 case '+': luaK_add(ls); break;
248 case '-': luaK_sub(ls, v2); break; 285 case '-': luaK_sub(ls); break;
249 case '*': luaK_0(ls, MULTOP, -1); break; 286 case '*': luaK_0(ls, MULTOP, -1); break;
250 case '/': luaK_0(ls, DIVOP, -1); break; 287 case '/': luaK_0(ls, DIVOP, -1); break;
251 case '^': luaK_0(ls, POWOP, -1); break; 288 case '^': luaK_0(ls, POWOP, -1); break;
@@ -257,6 +294,5 @@ void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) {
257 case GE: luaK_0(ls, GEOP, -1); break; 294 case GE: luaK_0(ls, GEOP, -1); break;
258 case LE: luaK_0(ls, LEOP, -1); break; 295 case LE: luaK_0(ls, LEOP, -1); break;
259 } 296 }
260 v1->info = NOJUMPS;
261} 297}
262 298