Kannel: Open Source WAP and SMS gateway  $Revision: 5037 $
wsopt.c File Reference
#include "wsint.h"
#include "wsasm.h"

Go to the source code of this file.

Functions

static WsBool opt_jumps_to_jumps (WsCompilerPtr compiler)
 
static WsBool opt_jumps_to_next_instruction (WsCompilerPtr compiler)
 
static WsBool opt_dead_code (WsCompilerPtr compiler)
 
static WsBool opt_peephole (WsCompilerPtr compiler)
 
static WsBool opt_conv (WsCompilerPtr compiler)
 
void ws_asm_optimize (WsCompilerPtr compiler)
 

Function Documentation

static WsBool opt_conv ( WsCompilerPtr  compiler)
static

Definition at line 308 of file wsopt.c.

References WsCompilerRec::asm_head, WsCompilerRec::asm_tail, WsAsmInsRec::next, WsAsmInsRec::prev, WsAsmInsRec::type, WS_ASM_NOT, WS_ASM_P_LABEL, WS_ASM_P_TJUMP, WS_ASM_POP, WS_ASM_SCAND, WS_ASM_SCOR, WS_ASM_TOBOOL, WS_FALSE, ws_info(), and WS_TRUE.

Referenced by ws_asm_optimize().

309 {
310  WsBool change = WS_FALSE;
311  WsAsmIns *i, *next, *prev;
312 
313  ws_info(compiler, "optimize: peephole");
314 
315  prev = NULL;
316  i = compiler->asm_head;
317  while (i) {
318  if (i->type == WS_ASM_TOBOOL) {
319  next = i->next;
320 
321  /* Skip labels. They're not going to affect which instruction
322  * gets executed after this TOBOOL. */
323  while (next != NULL && next->type == WS_ASM_P_LABEL)
324  next = next->next;
325 
326  if (next != NULL &&
327  (next->type == WS_ASM_P_TJUMP ||
328  next->type == WS_ASM_NOT ||
329  next->type == WS_ASM_SCAND ||
330  next->type == WS_ASM_SCOR ||
331  next->type == WS_ASM_TOBOOL ||
332  next->type == WS_ASM_POP)) {
333  /* The next instruction will automatically convert its
334  * operand to boolean, or does not care about its operand
335  * (POP), so the TOBOOL is not necessary. Delete it. */
336  change = WS_TRUE;
337 
338  /* Use i->next here because next might have been incremented
339  * past a label, which we do not want to delete. */
340  if (prev)
341  prev->next = i->next;
342  else
343  compiler->asm_head = i->next;
344 
345  if (i->next)
346  i->next->prev = prev;
347  else
348  compiler->asm_tail = prev;
349  }
350  }
351 
352  prev = i;
353  i = i->next;
354  }
355 
356  return change;
357 }
#define WS_ASM_SCOR
Definition: wsasm.h:207
Definition: wsint.h:131
#define WS_ASM_P_LABEL
Definition: wsasm.h:225
#define WS_ASM_NOT
Definition: wsasm.h:205
WsAsmIns * asm_head
Definition: wsint.h:224
WsAsmIns * asm_tail
Definition: wsint.h:225
#define WS_ASM_P_TJUMP
Definition: wsasm.h:227
WsUInt16 type
Definition: wsasm.h:257
struct WsAsmInsRec * next
Definition: wsasm.h:255
#define WS_ASM_TOBOOL
Definition: wsasm.h:208
#define WS_ASM_POP
Definition: wsasm.h:210
struct WsAsmInsRec * prev
Definition: wsasm.h:256
WsBool
Definition: wsint.h:128
void ws_info(WsCompilerPtr compiler, char *message,...)
Definition: wserror.c:74
#define WS_ASM_SCAND
Definition: wsasm.h:206
static WsBool opt_dead_code ( WsCompilerPtr  compiler)
static

Definition at line 168 of file wsopt.c.

References WsCompilerRec::asm_head, WsCompilerRec::asm_tail, WsAsmInsRec::next, WsAsmInsRec::prev, WsAsmInsRec::type, WS_ASM_P_BRANCH, WS_ASM_P_JUMP, WS_ASM_P_LABEL, WS_ASM_RETURN, WS_ASM_RETURN_ES, WS_FALSE, ws_info(), and WS_TRUE.

Referenced by ws_asm_optimize().

169 {
170  WsBool change = WS_FALSE;
171  WsAsmIns *i;
172 
173  ws_info(compiler, "optimize: dead code");
174 
175  for (i = compiler->asm_head; i; i = i->next) {
176  WsAsmIns * j;
177 
178  if (!(i->type == WS_ASM_P_JUMP ||
179  i->type == WS_ASM_RETURN ||
180  i->type == WS_ASM_RETURN_ES))
181  continue;
182 
183  /* Skip until the next referenced label is found. */
184  for (j = i->next;
185  j && (j->type != WS_ASM_P_LABEL || j->ws_label_refcount == 0);
186  j = j->next) {
187  /* Update label reference counts in the deleted block. */
188  if (WS_ASM_P_BRANCH(j))
189  j->ws_label->ws_label_refcount--;
190  }
191 
192  if (j == i->next)
193  /* Nothing to delete. */
194  continue;
195 
196  /* Delete everything between `i' and `j'. */
197  i->next = j;
198  if (j)
199  j->prev = i;
200  else
201  compiler->asm_tail = i;
202 
203  change = WS_TRUE;
204  }
205 
206  return change;
207 }
Definition: wsint.h:131
#define WS_ASM_P_LABEL
Definition: wsasm.h:225
#define WS_ASM_RETURN
Definition: wsasm.h:215
WsAsmIns * asm_head
Definition: wsint.h:224
WsAsmIns * asm_tail
Definition: wsint.h:225
#define WS_ASM_P_JUMP
Definition: wsasm.h:226
WsUInt16 type
Definition: wsasm.h:257
struct WsAsmInsRec * next
Definition: wsasm.h:255
struct WsAsmInsRec * prev
Definition: wsasm.h:256
WsBool
Definition: wsint.h:128
#define WS_ASM_P_BRANCH(ins)
Definition: wsasm.h:238
void ws_info(WsCompilerPtr compiler, char *message,...)
Definition: wserror.c:74
#define WS_ASM_RETURN_ES
Definition: wsasm.h:216
static WsBool opt_jumps_to_jumps ( WsCompilerPtr  compiler)
static

Definition at line 81 of file wsopt.c.

References WsCompilerRec::asm_head, WsAsmInsRec::next, WsAsmInsRec::type, WS_ASM_P_BRANCH, WS_ASM_P_JUMP, WS_ASM_P_LABEL, WS_FALSE, ws_info(), and WS_TRUE.

Referenced by ws_asm_optimize().

82 {
83  WsAsmIns *i;
84  WsBool change = WS_TRUE;
85  unsigned int count = 0;
86 
87  ws_info(compiler, "optimize: jumps to jumps");
88 
89  while (change) {
90  count++;
91  change = WS_FALSE;
92 
93  for (i = compiler->asm_head; i; i = i->next) {
94  WsAsmIns * j;
95 
96  if (!WS_ASM_P_BRANCH(i))
97  continue;
98 
99  /* Find the next instruction following the label. */
100  for (j = i->ws_label; j && j->type == WS_ASM_P_LABEL; j = j->next)
101  ;
102 
103  if (j == NULL || j->type != WS_ASM_P_JUMP)
104  /* Can't optimize this case. */
105  continue;
106 
107  /* We can optimize the jump `i' directly to the label of
108  `j'. We must remember to update the reference counts
109  too. */
110 
111  i->ws_label->ws_label_refcount--;
112  j->ws_label->ws_label_refcount++;
113 
114  i->ws_label = j->ws_label;
115  change = WS_TRUE;
116  }
117  }
118 
119  return count > 1;
120 }
Definition: wsint.h:131
#define WS_ASM_P_LABEL
Definition: wsasm.h:225
WsAsmIns * asm_head
Definition: wsint.h:224
#define WS_ASM_P_JUMP
Definition: wsasm.h:226
WsUInt16 type
Definition: wsasm.h:257
struct WsAsmInsRec * next
Definition: wsasm.h:255
WsBool
Definition: wsint.h:128
#define WS_ASM_P_BRANCH(ins)
Definition: wsasm.h:238
void ws_info(WsCompilerPtr compiler, char *message,...)
Definition: wserror.c:74
static WsBool opt_jumps_to_next_instruction ( WsCompilerPtr  compiler)
static

Definition at line 123 of file wsopt.c.

References WsCompilerRec::asm_head, WsCompilerRec::asm_tail, WsAsmInsRec::next, WsAsmInsRec::prev, WsAsmInsRec::type, WS_ASM_P_JUMP, WS_ASM_P_LABEL, WS_FALSE, ws_info(), and WS_TRUE.

Referenced by ws_asm_optimize().

124 {
125  WsAsmIns *i;
126  WsBool change = WS_FALSE;
127 
128  ws_info(compiler, "optimize: jumps to next instruction");
129 
130  for (i = compiler->asm_head; i; i = i->next) {
131  WsAsmIns * j;
132 
133  if (i->type != WS_ASM_P_JUMP)
134  continue;
135 
136  for (j = i->next;
137  j && j->type == WS_ASM_P_LABEL && i->ws_label != j;
138  j = j->next)
139  ;
140 
141  if (i->ws_label != j)
142  /* Nop. */
143  continue;
144 
145  /* Remove the jump instruction `i'. */
146 
147  change = WS_TRUE;
148  i->ws_label->ws_label_refcount--;
149 
150  if (i->next)
151  i->next->prev = i->prev;
152  else
153  compiler->asm_tail = i->prev;
154 
155  if (i->prev)
156  i->prev->next = i->next;
157  else
158  compiler->asm_head = i->next;
159 
160  /* Continue from the label `j'. */
161  i = j;
162  }
163 
164  return change;
165 }
Definition: wsint.h:131
#define WS_ASM_P_LABEL
Definition: wsasm.h:225
WsAsmIns * asm_head
Definition: wsint.h:224
WsAsmIns * asm_tail
Definition: wsint.h:225
#define WS_ASM_P_JUMP
Definition: wsasm.h:226
WsUInt16 type
Definition: wsasm.h:257
struct WsAsmInsRec * next
Definition: wsasm.h:255
struct WsAsmInsRec * prev
Definition: wsasm.h:256
WsBool
Definition: wsint.h:128
void ws_info(WsCompilerPtr compiler, char *message,...)
Definition: wserror.c:74
static WsBool opt_peephole ( WsCompilerPtr  compiler)
static

Definition at line 210 of file wsopt.c.

References WsCompilerRec::asm_head, WsCompilerRec::asm_tail, WsAsmInsRec::line, WsAsmInsRec::next, WsAsmInsRec::prev, WsAsmInsRec::type, WS_ASM_CONST_0, WS_ASM_CONST_1, WS_ASM_CONST_ES, WS_ASM_CONST_FALSE, WS_ASM_CONST_INVALID, WS_ASM_CONST_M1, WS_ASM_CONST_TRUE, ws_asm_ins(), WS_ASM_P_LOAD_CONST, WS_ASM_P_LOAD_VAR, WS_ASM_POP, WS_ASM_RETURN, WS_ASM_RETURN_ES, WS_FALSE, ws_info(), and WS_TRUE.

Referenced by ws_asm_optimize().

211 {
212  WsBool change = WS_FALSE;
213  WsAsmIns *i, *i2, *prev;
214  WsAsmIns *new;
215 
216  ws_info(compiler, "optimize: peephole");
217 
218  prev = NULL;
219  i = compiler->asm_head;
220  while (i) {
221  /* Two instructions wide peephole. */
222  if (i->next) {
223  i2 = i->next;
224 
225  /*
226  * {load*,const*} => -
227  * pop
228  */
229  if (i2->type == WS_ASM_POP
230  && (i->type == WS_ASM_P_LOAD_VAR
231  || i->type == WS_ASM_P_LOAD_CONST
232  || i->type == WS_ASM_CONST_0
233  || i->type == WS_ASM_CONST_1
234  || i->type == WS_ASM_CONST_M1
235  || i->type == WS_ASM_CONST_ES
236  || i->type == WS_ASM_CONST_INVALID
237  || i->type == WS_ASM_CONST_TRUE
238  || i->type == WS_ASM_CONST_FALSE)) {
239  /* Remove both instructions. */
240  change = WS_TRUE;
241 
242  if (prev)
243  prev->next = i2->next;
244  else
245  compiler->asm_head = i2->next;
246 
247  if (i2->next)
248  i2->next->prev = prev;
249  else
250  compiler->asm_tail = prev;
251 
252  i = i2->next;
253  continue;
254  }
255 
256  /*
257  * const_es => return_es
258  * return
259  */
260  if (i2->type == WS_ASM_RETURN && i->type == WS_ASM_CONST_ES) {
261  /* Replace with WS_ASM_RETURN_ES */
262  new = ws_asm_ins(compiler, i->line, WS_ASM_RETURN_ES);
263  if (new) {
264  change = WS_TRUE;
265 
266  if (prev)
267  prev->next = new;
268  else
269  compiler->asm_head = new;
270 
271  new->prev = prev;
272  new->next = i2->next;
273 
274  if (new->next)
275  new->next->prev = new;
276  else
277  compiler->asm_tail = new;
278 
279  i = new;
280  continue;
281  }
282  }
283  }
284 
285  /* Move forward. */
286  prev = i;
287  i = i->next;
288  }
289 
290  /* The interpreter will by default return the empty string if a
291  * function ends without a return statement, so returning the
292  * empty string at the end of a function is never useful. */
293  if (compiler->asm_tail && compiler->asm_tail->type == WS_ASM_RETURN_ES) {
294  compiler->asm_tail = compiler->asm_tail->prev;
295  if (compiler->asm_tail == NULL)
296  compiler->asm_head = NULL;
297  else
298  compiler->asm_tail->next = NULL;
299  }
300 
301  return change;
302 }
#define WS_ASM_CONST_TRUE
Definition: wsasm.h:175
Definition: wsint.h:131
#define WS_ASM_RETURN
Definition: wsasm.h:215
WsAsmIns * asm_head
Definition: wsint.h:224
WsAsmIns * asm_tail
Definition: wsint.h:225
#define WS_ASM_CONST_INVALID
Definition: wsasm.h:174
#define WS_ASM_CONST_M1
Definition: wsasm.h:172
#define WS_ASM_CONST_FALSE
Definition: wsasm.h:176
WsUInt16 type
Definition: wsasm.h:257
struct WsAsmInsRec * next
Definition: wsasm.h:255
#define WS_ASM_P_LOAD_VAR
Definition: wsasm.h:231
WsAsmIns * ws_asm_ins(WsCompiler *compiler, WsUInt32 line, WsUInt8 opcode)
Definition: wsasm.c:920
#define WS_ASM_POP
Definition: wsasm.h:210
struct WsAsmInsRec * prev
Definition: wsasm.h:256
WsUInt32 line
Definition: wsasm.h:260
WsBool
Definition: wsint.h:128
#define WS_ASM_CONST_1
Definition: wsasm.h:171
#define WS_ASM_P_LOAD_CONST
Definition: wsasm.h:234
#define WS_ASM_CONST_0
Definition: wsasm.h:170
void ws_info(WsCompilerPtr compiler, char *message,...)
Definition: wserror.c:74
#define WS_ASM_CONST_ES
Definition: wsasm.h:173
#define WS_ASM_RETURN_ES
Definition: wsasm.h:216
void ws_asm_optimize ( WsCompilerPtr  compiler)

Definition at line 362 of file wsopt.c.

References WsCompilerParamsRec::no_opt_conv, WsCompilerParamsRec::no_opt_dead_code, WsCompilerParamsRec::no_opt_jumps_to_jumps, WsCompilerParamsRec::no_opt_jumps_to_next_instruction, WsCompilerParamsRec::no_opt_peephole, opt_conv(), opt_dead_code(), opt_jumps_to_jumps(), opt_jumps_to_next_instruction(), opt_peephole(), WsCompilerRec::params, WS_FALSE, and WS_TRUE.

Referenced by compile_stream().

363 {
364  WsBool change = WS_TRUE;
365 
366  /* While we manage to change the assembler, perform the requested
367  optimizations. */
368  while (change) {
369  change = WS_FALSE;
370 
371  /* Useless conversions */
372  if (!compiler->params.no_opt_conv && opt_conv(compiler))
373  change = WS_TRUE;
374 
375  /* Peephole. */
376  if (!compiler->params.no_opt_peephole && opt_peephole(compiler))
377  change = WS_TRUE;
378 
379  /* Jumps to jump instructions. */
380  if (!compiler->params.no_opt_jumps_to_jumps
381  && opt_jumps_to_jumps(compiler))
382  change = WS_TRUE;
383 
384  /* Jumps to the next instruction. */
386  && opt_jumps_to_next_instruction(compiler))
387  change = WS_TRUE;
388 
389  /* Unreachable code. */
390  if (!compiler->params.no_opt_dead_code && opt_dead_code(compiler))
391  change = WS_TRUE;
392  }
393 }
unsigned int no_opt_dead_code
Definition: ws.h:138
Definition: wsint.h:131
unsigned int no_opt_conv
Definition: ws.h:141
static WsBool opt_jumps_to_jumps(WsCompilerPtr compiler)
Definition: wsopt.c:81
unsigned int no_opt_jumps_to_next_instruction
Definition: ws.h:135
static WsBool opt_dead_code(WsCompilerPtr compiler)
Definition: wsopt.c:168
static WsBool opt_peephole(WsCompilerPtr compiler)
Definition: wsopt.c:210
static WsBool opt_jumps_to_next_instruction(WsCompilerPtr compiler)
Definition: wsopt.c:123
unsigned int no_opt_peephole
Definition: ws.h:128
WsBool
Definition: wsint.h:128
static WsBool opt_conv(WsCompilerPtr compiler)
Definition: wsopt.c:308
WsCompilerParams params
Definition: wsint.h:193
unsigned int no_opt_jumps_to_jumps
Definition: ws.h:132
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.