Main Page | Alphabetical List | Data Structures | Directories | File List | Data Fields | Globals

wsopt.c

Go to the documentation of this file.
00001 /* ==================================================================== 
00002  * The Kannel Software License, Version 1.0 
00003  * 
00004  * Copyright (c) 2001-2008 Kannel Group  
00005  * Copyright (c) 1998-2001 WapIT Ltd.   
00006  * All rights reserved. 
00007  * 
00008  * Redistribution and use in source and binary forms, with or without 
00009  * modification, are permitted provided that the following conditions 
00010  * are met: 
00011  * 
00012  * 1. Redistributions of source code must retain the above copyright 
00013  *    notice, this list of conditions and the following disclaimer. 
00014  * 
00015  * 2. Redistributions in binary form must reproduce the above copyright 
00016  *    notice, this list of conditions and the following disclaimer in 
00017  *    the documentation and/or other materials provided with the 
00018  *    distribution. 
00019  * 
00020  * 3. The end-user documentation included with the redistribution, 
00021  *    if any, must include the following acknowledgment: 
00022  *       "This product includes software developed by the 
00023  *        Kannel Group (http://www.kannel.org/)." 
00024  *    Alternately, this acknowledgment may appear in the software itself, 
00025  *    if and wherever such third-party acknowledgments normally appear. 
00026  * 
00027  * 4. The names "Kannel" and "Kannel Group" must not be used to 
00028  *    endorse or promote products derived from this software without 
00029  *    prior written permission. For written permission, please  
00030  *    contact org@kannel.org. 
00031  * 
00032  * 5. Products derived from this software may not be called "Kannel", 
00033  *    nor may "Kannel" appear in their name, without prior written 
00034  *    permission of the Kannel Group. 
00035  * 
00036  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED 
00037  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 
00038  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
00039  * DISCLAIMED.  IN NO EVENT SHALL THE KANNEL GROUP OR ITS CONTRIBUTORS 
00040  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,  
00041  * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT  
00042  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR  
00043  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,  
00044  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE  
00045  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,  
00046  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 
00047  * ==================================================================== 
00048  * 
00049  * This software consists of voluntary contributions made by many 
00050  * individuals on behalf of the Kannel Group.  For more information on  
00051  * the Kannel Group, please see <http://www.kannel.org/>. 
00052  * 
00053  * Portions of this software are based upon software originally written at  
00054  * WapIT Ltd., Helsinki, Finland for the Kannel project.  
00055  */ 
00056 
00057 /*
00058  *
00059  * wsopt.c
00060  *
00061  * Author: Markku Rossi <mtr@iki.fi>
00062  *
00063  * Copyright (c) 1999-2000 WAPIT OY LTD.
00064  *       All rights reserved.
00065  *
00066  * Optimizations for the WMLScript symbolic assembler.
00067  *
00068  */
00069 
00070 #include "wsint.h"
00071 #include "wsasm.h"
00072 
00073 /* TODO: liveness analyzation */
00074 /* TODO: jumps to return or return_es */
00075 /* TODO: remove empty labels (helps peephole opt) */
00076 /* TODO: i++; becomes "load, incr, pop", optimize to just incr. */
00077 /* TODO: { const; tjump } -> { jump or nothing } */
00078 
00079 /********************* Optimization functions ***************************/
00080 
00081 static WsBool opt_jumps_to_jumps(WsCompilerPtr compiler)
00082 {
00083     WsAsmIns *i;
00084     WsBool change = WS_TRUE;
00085     unsigned int count = 0;
00086 
00087     ws_info(compiler, "optimize: jumps to jumps");
00088 
00089     while (change) {
00090         count++;
00091         change = WS_FALSE;
00092 
00093         for (i = compiler->asm_head; i; i = i->next) {
00094             WsAsmIns * j;
00095 
00096             if (!WS_ASM_P_BRANCH(i))
00097                 continue;
00098 
00099             /* Find the next instruction following the label. */
00100             for (j = i->ws_label; j && j->type == WS_ASM_P_LABEL; j = j->next)
00101                 ;
00102 
00103             if (j == NULL || j->type != WS_ASM_P_JUMP)
00104                 /* Can't optimize this case. */
00105                 continue;
00106 
00107             /* We can optimize the jump `i' directly to the label of
00108                       `j'.  We must remember to update the reference counts
00109                       too. */
00110 
00111             i->ws_label->ws_label_refcount--;
00112             j->ws_label->ws_label_refcount++;
00113 
00114             i->ws_label = j->ws_label;
00115             change = WS_TRUE;
00116         }
00117     }
00118 
00119     return count > 1;
00120 }
00121 
00122 
00123 static WsBool opt_jumps_to_next_instruction(WsCompilerPtr compiler)
00124 {
00125     WsAsmIns *i;
00126     WsBool change = WS_FALSE;
00127 
00128     ws_info(compiler, "optimize: jumps to next instruction");
00129 
00130     for (i = compiler->asm_head; i; i = i->next) {
00131         WsAsmIns * j;
00132 
00133         if (i->type != WS_ASM_P_JUMP)
00134             continue;
00135 
00136         for (j = i->next;
00137              j && j->type == WS_ASM_P_LABEL && i->ws_label != j;
00138              j = j->next)
00139             ;
00140 
00141         if (i->ws_label != j)
00142             /* Nop. */
00143             continue;
00144 
00145         /* Remove the jump instruction `i'. */
00146 
00147         change = WS_TRUE;
00148         i->ws_label->ws_label_refcount--;
00149 
00150         if (i->next)
00151             i->next->prev = i->prev;
00152         else
00153             compiler->asm_tail = i->prev;
00154 
00155         if (i->prev)
00156             i->prev->next = i->next;
00157         else
00158             compiler->asm_head = i->next;
00159 
00160         /* Continue from the label `j'. */
00161         i = j;
00162     }
00163 
00164     return change;
00165 }
00166 
00167 
00168 static WsBool opt_dead_code(WsCompilerPtr compiler)
00169 {
00170     WsBool change = WS_FALSE;
00171     WsAsmIns *i;
00172 
00173     ws_info(compiler, "optimize: dead code");
00174 
00175     for (i = compiler->asm_head; i; i = i->next) {
00176         WsAsmIns * j;
00177 
00178         if (!(i->type == WS_ASM_P_JUMP ||
00179               i->type == WS_ASM_RETURN ||
00180               i->type == WS_ASM_RETURN_ES))
00181             continue;
00182 
00183         /* Skip until the next referenced label is found. */
00184         for (j = i->next;
00185              j && (j->type != WS_ASM_P_LABEL || j->ws_label_refcount == 0);
00186              j = j->next) {
00187             /* Update label reference counts in the deleted block. */
00188             if (WS_ASM_P_BRANCH(j))
00189                 j->ws_label->ws_label_refcount--;
00190         }
00191 
00192         if (j == i->next)
00193             /* Nothing to delete. */
00194             continue;
00195 
00196         /* Delete everything between `i' and `j'. */
00197         i->next = j;
00198         if (j)
00199             j->prev = i;
00200         else
00201             compiler->asm_tail = i;
00202 
00203         change = WS_TRUE;
00204     }
00205 
00206     return change;
00207 }
00208 
00209 
00210 static WsBool opt_peephole(WsCompilerPtr compiler)
00211 {
00212     WsBool change = WS_FALSE;
00213     WsAsmIns *i, *i2, *prev;
00214     WsAsmIns *new;
00215 
00216     ws_info(compiler, "optimize: peephole");
00217 
00218     prev = NULL;
00219     i = compiler->asm_head;
00220     while (i) {
00221         /* Two instructions wide peephole. */
00222         if (i->next) {
00223             i2 = i->next;
00224 
00225             /*
00226              * {load*,const*}   =>  -
00227              * pop
00228              */
00229             if (i2->type == WS_ASM_POP
00230                 && (i->type == WS_ASM_P_LOAD_VAR
00231                     || i->type == WS_ASM_P_LOAD_CONST
00232                     || i->type == WS_ASM_CONST_0
00233                     || i->type == WS_ASM_CONST_1
00234                     || i->type == WS_ASM_CONST_M1
00235                     || i->type == WS_ASM_CONST_ES
00236                     || i->type == WS_ASM_CONST_INVALID
00237                     || i->type == WS_ASM_CONST_TRUE
00238                     || i->type == WS_ASM_CONST_FALSE)) {
00239                 /* Remove both instructions. */
00240                 change = WS_TRUE;
00241 
00242                 if (prev)
00243                     prev->next = i2->next;
00244                 else
00245                     compiler->asm_head = i2->next;
00246 
00247                 if (i2->next)
00248                     i2->next->prev = prev;
00249                 else
00250                     compiler->asm_tail = prev;
00251 
00252                 i = i2->next;
00253                 continue;
00254             }
00255 
00256             /*
00257              * const_es           =>      return_es
00258              * return
00259              */
00260             if (i2->type == WS_ASM_RETURN && i->type == WS_ASM_CONST_ES) {
00261                 /* Replace with WS_ASM_RETURN_ES */
00262                 new = ws_asm_ins(compiler, i->line, WS_ASM_RETURN_ES);
00263                 if (new) {
00264                     change = WS_TRUE;
00265 
00266                     if (prev)
00267                         prev->next = new;
00268                     else
00269                         compiler->asm_head = new;
00270 
00271                     new->prev = prev;
00272                     new->next = i2->next;
00273 
00274                     if (new->next)
00275                         new->next->prev = new;
00276                     else
00277                         compiler->asm_tail = new;
00278 
00279                     i = new;
00280                     continue;
00281                 }
00282             }
00283         }
00284 
00285         /* Move forward. */
00286         prev = i;
00287         i = i->next;
00288     }
00289 
00290     /* The interpreter will by default return the empty string if a
00291      * function ends without a return statement, so returning the
00292      * empty string at the end of a function is never useful. */
00293     if (compiler->asm_tail && compiler->asm_tail->type == WS_ASM_RETURN_ES) {
00294         compiler->asm_tail = compiler->asm_tail->prev;
00295         if (compiler->asm_tail == NULL)
00296             compiler->asm_head = NULL;
00297         else
00298             compiler->asm_tail->next = NULL;
00299     }
00300 
00301     return change;
00302 }
00303 
00304 /*
00305  * Remove conversions that are followed by an opcode that does
00306  * that conversion automatically anyway.
00307  */
00308 static WsBool opt_conv(WsCompilerPtr compiler)
00309 {
00310     WsBool change = WS_FALSE;
00311     WsAsmIns *i, *next, *prev;
00312 
00313     ws_info(compiler, "optimize: peephole");
00314 
00315     prev = NULL;
00316     i = compiler->asm_head;
00317     while (i) {
00318         if (i->type == WS_ASM_TOBOOL) {
00319         next = i->next;
00320 
00321             /* Skip labels.  They're not going to affect which instruction
00322              * gets executed after this TOBOOL. */
00323         while (next != NULL && next->type == WS_ASM_P_LABEL)
00324             next = next->next;
00325 
00326         if (next != NULL &&
00327                 (next->type == WS_ASM_P_TJUMP ||
00328                  next->type == WS_ASM_NOT ||
00329              next->type == WS_ASM_SCAND ||
00330              next->type == WS_ASM_SCOR ||
00331              next->type == WS_ASM_TOBOOL ||
00332              next->type == WS_ASM_POP)) {
00333             /* The next instruction will automatically convert its
00334              * operand to boolean, or does not care about its operand
00335              * (POP), so the TOBOOL is not necessary.  Delete it.  */
00336             change = WS_TRUE;
00337 
00338             /* Use i->next here because next might have been incremented
00339              * past a label, which we do not want to delete. */
00340             if (prev)
00341                 prev->next = i->next;
00342             else
00343                 compiler->asm_head = i->next;
00344 
00345             if (i->next)
00346                     i->next->prev = prev;
00347                 else
00348                     compiler->asm_tail = prev;
00349         }
00350         }
00351 
00352     prev = i;
00353     i = i->next;
00354     }
00355 
00356     return change;
00357 }
00358 
00359 
00360 /********************* Global entry point *******************************/
00361 
00362 void ws_asm_optimize(WsCompilerPtr compiler)
00363 {
00364     WsBool change = WS_TRUE;
00365 
00366     /* While we manage to change the assembler, perform the requested
00367        optimizations. */
00368     while (change) {
00369         change = WS_FALSE;
00370 
00371     /* Useless conversions */
00372     if (!compiler->params.no_opt_conv && opt_conv(compiler))
00373         change = WS_TRUE;
00374 
00375         /* Peephole. */
00376         if (!compiler->params.no_opt_peephole && opt_peephole(compiler))
00377             change = WS_TRUE;
00378 
00379         /* Jumps to jump instructions. */
00380         if (!compiler->params.no_opt_jumps_to_jumps
00381             && opt_jumps_to_jumps(compiler))
00382             change = WS_TRUE;
00383 
00384         /* Jumps to the next instruction. */
00385         if (!compiler->params.no_opt_jumps_to_next_instruction
00386             && opt_jumps_to_next_instruction(compiler))
00387             change = WS_TRUE;
00388 
00389         /* Unreachable code. */
00390         if (!compiler->params.no_opt_dead_code && opt_dead_code(compiler))
00391             change = WS_TRUE;
00392     }
00393 }
See file LICENSE for details about the license agreement for using, modifying, copying or deriving work from this software.