diff options
author | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2000-03-04 17:18:15 -0300 |
---|---|---|
committer | Roberto Ierusalimschy <roberto@inf.puc-rio.br> | 2000-03-04 17:18:15 -0300 |
commit | 563de491be90601f23a735aede89ea9a3ef86ee9 (patch) | |
tree | c92677f388289ead55c8a8778493b0af7e41f159 /lcode.c | |
parent | 29e01934253adf5fbf43faff81d87d7470cef8ce (diff) | |
download | lua-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.c | 160 |
1 files changed, 98 insertions, 62 deletions
@@ -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 | ||
23 | static 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 | */ | ||
28 | static 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 | ||
38 | static void luaK_minus (LexState *ls, expdesc *v) { | 47 | static 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 | ||
49 | static void luaK_gettable (LexState *ls, expdesc *v) { | 58 | static 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 | ||
59 | static void luaK_add (LexState *ls, expdesc *v) { | 68 | static 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 | ||
69 | static void luaK_sub (LexState *ls, expdesc *v) { | 78 | static 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 | ||
82 | void luaK_retcode (LexState *ls, int nlocals, listdesc *e) { | 91 | void 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 | ||
103 | static 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 | |||
93 | int luaK_code (LexState *ls, Instruction i, int delta) { | 115 | int 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 | */ | ||
133 | int luaK_getlabel (LexState *ls) { | ||
134 | FuncState *fs = ls->fs; | ||
135 | fs->lasttarget = fs->pc; | ||
136 | return fs->pc; | ||
137 | } | ||
138 | |||
139 | |||
107 | void luaK_deltastack (LexState *ls, int delta) { | 140 | void 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 | ||
158 | int luaK_iscall (LexState *ls, int hasjumps) { | 191 | int 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 | ||
165 | void luaK_setcallreturns (LexState *ls, int hasjumps, int nresults) { | 202 | void 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 | ||
185 | void luaK_2stack (LexState *ls, expdesc *var) { | 217 | void 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 | |||
236 | void 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 | ||
224 | void luaK_prefix (LexState *ls, int op, expdesc *v) { | 262 | void 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 | ||
232 | void luaK_infix (LexState *ls, expdesc *v) { | 269 | void 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 | ||
241 | void luaK_posfix (LexState *ls, int op, expdesc *v1, expdesc *v2) { | 278 | void 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 | ||