You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
386 lines
11 KiB
386 lines
11 KiB
13 years ago
|
/**********************************************************************
|
||
|
* psopt.c
|
||
|
* String Stack Optimizaitons
|
||
|
*
|
||
|
* Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
|
||
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
||
|
*
|
||
|
* Redistribution and use in source and binary forms, with or without
|
||
|
* modification, are permitted provided that the following conditions
|
||
|
* are met:
|
||
|
*
|
||
|
* 1. Redistributions of source code must retain the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer.
|
||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||
|
* notice, this list of conditions and the following disclaimer in
|
||
|
* the documentation and/or other materials provided with the
|
||
|
* distribution.
|
||
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
||
|
* used to endorse or promote products derived from this software
|
||
|
* without specific prior written permission.
|
||
|
*
|
||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
||
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||
|
*
|
||
|
**********************************************************************/
|
||
|
|
||
|
/* The statement generation logic generates a PUSHS and POPS around
|
||
|
* every statement. These instructions save and restore the string
|
||
|
* stack pointer registers. However, only some statements actually
|
||
|
* modify the string stack. So the first major step in the optimatization
|
||
|
* process is to retain only PUSHS and POPS statements that are
|
||
|
* actually required.
|
||
|
*/
|
||
|
|
||
|
/**********************************************************************
|
||
|
* Included Files
|
||
|
**********************************************************************/
|
||
|
|
||
|
#include <stdint.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "keywords.h"
|
||
|
#include "pdefs.h"
|
||
|
#include "pedefs.h"
|
||
|
#include "pinsn32.h"
|
||
|
#include "pxdefs.h"
|
||
|
|
||
|
#include "popt.h"
|
||
|
#include "psopt.h"
|
||
|
|
||
|
/**********************************************************************
|
||
|
* Definitions
|
||
|
**********************************************************************/
|
||
|
|
||
|
#define PBUFFER_SIZE 1024
|
||
|
#define NPBUFFERS 8
|
||
|
|
||
|
/**********************************************************************
|
||
|
* Private Data
|
||
|
**********************************************************************/
|
||
|
|
||
|
static uint8_t *pbuffer[NPBUFFERS];
|
||
|
static int nbytes_in_pbuffer[NPBUFFERS];
|
||
|
static int current_level = -1;
|
||
|
static int inch;
|
||
|
|
||
|
/**********************************************************************
|
||
|
* Private Function Prototypes
|
||
|
**********************************************************************/
|
||
|
|
||
|
static inline void putbuf(int c, poffProgHandle_t poffProgHandle);
|
||
|
static inline void flushc(int c, poffProgHandle_t poffProgHandle);
|
||
|
static inline void flushbuf(poffProgHandle_t poffProgHandle);
|
||
|
static void dopush(poffHandle_t poffHandle, poffProgHandle_t poffProgHandle);
|
||
|
static void dopop(poffHandle_t poffHandle, poffProgHandle_t poffProgHandle);
|
||
|
|
||
|
/**********************************************************************
|
||
|
* Private Inline Functions
|
||
|
**********************************************************************/
|
||
|
|
||
|
static inline void putbuf(int c, poffProgHandle_t poffProgHandle)
|
||
|
{
|
||
|
int dlvl = current_level;
|
||
|
|
||
|
if (dlvl < 0)
|
||
|
{
|
||
|
/* No PUSHS encountered. Write byte directly to output */
|
||
|
|
||
|
poffAddTmpProgByte(poffProgHandle, (uint8_t)c);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* PUSHS encountered. Write byte into buffer associated with
|
||
|
* nesting level.
|
||
|
*/
|
||
|
|
||
|
int idx = nbytes_in_pbuffer[dlvl];
|
||
|
uint8_t *dest = pbuffer[dlvl] + idx;
|
||
|
*dest = c;
|
||
|
nbytes_in_pbuffer[dlvl] = idx + 1;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void flushc(int c, poffProgHandle_t poffProgHandle)
|
||
|
{
|
||
|
if (current_level > 0)
|
||
|
{
|
||
|
/* Nested PUSHS encountered. Write byte into buffer associated
|
||
|
* with the previous nesting level.
|
||
|
*/
|
||
|
|
||
|
int dlvl = current_level - 1;
|
||
|
int idx = nbytes_in_pbuffer[dlvl];
|
||
|
uint8_t *dest = pbuffer[dlvl] + idx;
|
||
|
*dest = c;
|
||
|
nbytes_in_pbuffer[dlvl] = idx + 1;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Only one PUSHS encountered. Write directly to the output
|
||
|
* buffer
|
||
|
*/
|
||
|
|
||
|
poffAddTmpProgByte(poffProgHandle, (uint8_t)c);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static inline void flushbuf(poffProgHandle_t poffProgHandle)
|
||
|
{
|
||
|
int errCode;
|
||
|
int slvl = current_level;
|
||
|
|
||
|
if (nbytes_in_pbuffer[slvl] > 0)
|
||
|
{
|
||
|
if (current_level > 0)
|
||
|
{
|
||
|
/* Nested PUSHS encountered. Flush buffer into buffer associated
|
||
|
* with the previous nesting level.
|
||
|
*/
|
||
|
|
||
|
int dlvl = slvl - 1;
|
||
|
uint8_t *src = pbuffer[slvl];
|
||
|
uint8_t *dest = pbuffer[dlvl] + nbytes_in_pbuffer[dlvl];
|
||
|
|
||
|
memcpy(dest, src, nbytes_in_pbuffer[slvl]);
|
||
|
nbytes_in_pbuffer[dlvl] += nbytes_in_pbuffer[slvl];
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* Only one PUSHS encountered. Flush directly to the output
|
||
|
* buffer
|
||
|
*/
|
||
|
|
||
|
errCode = poffWriteTmpProgBytes(pbuffer[0], nbytes_in_pbuffer[0],
|
||
|
poffProgHandle);
|
||
|
|
||
|
if (errCode != eNOERROR)
|
||
|
{
|
||
|
printf("Error writing to file: %d\n", errCode);
|
||
|
exit(1);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
nbytes_in_pbuffer[slvl] = 0;
|
||
|
}
|
||
|
|
||
|
/**********************************************************************
|
||
|
* Private Functions
|
||
|
**********************************************************************/
|
||
|
|
||
|
static void dopush(poffHandle_t poffHandle, poffProgHandle_t poffProgHandle)
|
||
|
{
|
||
|
int opcode;
|
||
|
|
||
|
while (inch != EOF)
|
||
|
{
|
||
|
/* Search for a PUSHS opcode */
|
||
|
|
||
|
if (inch != oPUSHS)
|
||
|
{
|
||
|
/* Its not PUSHS, just echo to the output file/buffer */
|
||
|
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
|
||
|
/* Get the next byte from the input stream */
|
||
|
|
||
|
opcode = inch;
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
|
||
|
/* Check for a 32-bit argument */
|
||
|
|
||
|
if ((opcode & o32) != 0)
|
||
|
{
|
||
|
/* Echo the 32-bits of the argument */
|
||
|
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
/* We have found PUSHS. No search for the next occurrence
|
||
|
* of either and instruction that increments the string
|
||
|
* stack or for the matching POPS
|
||
|
*/
|
||
|
|
||
|
current_level++;
|
||
|
dopop(poffHandle, poffProgHandle);
|
||
|
current_level--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void dopop(poffHandle_t poffHandle, poffProgHandle_t poffProgHandle)
|
||
|
{
|
||
|
/* We have found PUSHS. No search for the next occurrence
|
||
|
* of either and instruction that increments the string
|
||
|
* stack or for the matching POPS
|
||
|
*/
|
||
|
|
||
|
/* Skip over the PUSHS for now */
|
||
|
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
|
||
|
while (inch != EOF)
|
||
|
{
|
||
|
/* Did we encounter another PUSHS? */
|
||
|
|
||
|
if (inch == oPUSHS)
|
||
|
{
|
||
|
/* Yes... recurse to handle it */
|
||
|
|
||
|
current_level++;
|
||
|
dopop(poffHandle, poffProgHandle);
|
||
|
current_level--;
|
||
|
}
|
||
|
|
||
|
else if (inch == oPOPS)
|
||
|
{
|
||
|
/* Flush the buffered data without the PUSHS */
|
||
|
|
||
|
flushbuf(poffProgHandle);
|
||
|
|
||
|
/* And discard the matching POPS */
|
||
|
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
break;
|
||
|
}
|
||
|
else if (inch == oLIB)
|
||
|
{
|
||
|
uint32_t arg32;
|
||
|
unsigned int tmp;
|
||
|
|
||
|
/* Get the 32-bit argument from the big endian data stream */
|
||
|
|
||
|
tmp = poffGetProgByte(poffHandle);
|
||
|
arg32 = tmp << 24;
|
||
|
putbuf(tmp, poffProgHandle);
|
||
|
|
||
|
tmp = poffGetProgByte(poffHandle);
|
||
|
arg32 |= tmp << 16;
|
||
|
putbuf(tmp, poffProgHandle);
|
||
|
|
||
|
tmp = poffGetProgByte(poffHandle);
|
||
|
arg32 |= tmp << 8;
|
||
|
putbuf(tmp, poffProgHandle);
|
||
|
|
||
|
tmp = poffGetProgByte(poffHandle);
|
||
|
arg32 |= tmp;
|
||
|
putbuf(tmp, poffProgHandle);
|
||
|
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
|
||
|
/* Is it LIB MKSTK? MKSTKSTR? or MKSTKC? */
|
||
|
|
||
|
if ((arg32 == lbMKSTK) ||
|
||
|
(arg32 == lbMKSTKSTR) ||
|
||
|
(arg32 == lbMKSTKC))
|
||
|
{
|
||
|
/* Flush the buffered data with the PUSHS */
|
||
|
|
||
|
flushc(oPUSHS, poffProgHandle);
|
||
|
flushbuf(poffProgHandle);
|
||
|
|
||
|
/* And break out of the loop to search for
|
||
|
* the next PUSHS
|
||
|
*/
|
||
|
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
int opcode;
|
||
|
|
||
|
/* Something else. Put it in the buffer */
|
||
|
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
|
||
|
/* Get the next byte from the input stream */
|
||
|
|
||
|
opcode = inch;
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
|
||
|
/* Check for a 32-bit argument */
|
||
|
|
||
|
if (opcode & o32 != 0)
|
||
|
{
|
||
|
/* Buffer the remaining 24-bits of the argument */
|
||
|
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
putbuf(inch, poffProgHandle);
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**********************************************************************
|
||
|
* Global Functions
|
||
|
**********************************************************************/
|
||
|
|
||
|
void stringStackOptimize(poffHandle_t poffHandle,
|
||
|
poffProgHandle_t poffProgHandle)
|
||
|
{
|
||
|
int i;
|
||
|
|
||
|
/* Allocate an array of buffers to hold pcode data */
|
||
|
|
||
|
for (i = 0; i < NPBUFFERS; i++)
|
||
|
{
|
||
|
pbuffer[i] = (uint8_t*)malloc(PBUFFER_SIZE);
|
||
|
if (pbuffer[i] == NULL)
|
||
|
{
|
||
|
printf("Failed to allocate pcode buffer\n");
|
||
|
exit(1);
|
||
|
}
|
||
|
nbytes_in_pbuffer[i] = 0;
|
||
|
}
|
||
|
|
||
|
/* Prime the search logic */
|
||
|
|
||
|
inch = poffGetProgByte(poffHandle);
|
||
|
current_level = -1;
|
||
|
|
||
|
/* And parse the input file to the output file, removing unnecessary string
|
||
|
* stack operations.
|
||
|
*/
|
||
|
|
||
|
dopush(poffHandle, poffProgHandle);
|
||
|
|
||
|
/* Release the buffers */
|
||
|
|
||
|
for (i = 0; i < NPBUFFERS; i++)
|
||
|
{
|
||
|
free(pbuffer[i]);
|
||
|
pbuffer[i] = NULL;
|
||
|
nbytes_in_pbuffer[i] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**********************************************************************/
|