#!/bin/sh
#
# mklabel.sh - Make label tables for computed goto's.
#
# Copyright (C) 2002, 2004  Southern Storm Software, Pty Ltd.
#
# This file is part of the libjit library.
#
# The libjit library is free software: you can redistribute it and/or
# modify it under the terms of the GNU Lesser General Public License
# as published by the Free Software Foundation, either version 2.1 of
# the License, or (at your option) any later version.
#
# The libjit library is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
# Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public
# License along with the libjit library.  If not, see
# <http://www.gnu.org/licenses/>.
#
# Usage: mklabel.sh awk jit-opcode.h jit-interp.h >jit-interp-labels.h

# Validate the parameters.
if test "x$1" = "x" ; then
	echo "Usage: $0 awk jit-opcode.h jit-interp.h >jit-interp-labels.h" 1>&2
	exit 1
fi
if test "x$2" = "x" ; then
	echo "Usage: $0 awk jit-opcode.h jit-interp.h >jit-interp-labels.h" 1>&2
	exit 1
fi
if test "x$3" = "x" ; then
	echo "Usage: $0 awk jit-opcode.h jit-interp.h >jit-interp-labels.h" 1>&2
	exit 1
fi

# Output the "do not edit" header.
echo '/* This file is automatically generated - do not edit */'
echo ''

# Define a null assembly statement.  This is a trick to stop gcc doing
# tail-end combination on the cases within the switch statements.
echo '#if defined(__GNUC__)'
echo '#define VMNULLASM()         __asm__("")'
echo '#else'
echo '#define VMNULLASM()'
echo '#endif'
echo '#define VMFETCH(pc)         ((int)*((jit_nint *)(pc)))'
echo ''

# Are we compiling an interpreter that uses PIC computed goto's?
echo '#if defined(JIT_INTERP_TOKEN_PIC)'
echo ''

# Output a table of PIC labels, based on an incoming stream
# of #define's for opcodes.  Some awks don't support hex
# string to number conversion, which is why we have to convert
# the opcode value the hard way.
pic_table()
{
	"$1" 'BEGIN{
		      nextval=0
		  }
		  {
		      currval=0;
			  hexval=$3
			  ch=substr(hexval,1,1);
			  if(ch == "(")
			    hexval=$5
			  ch=substr(hexval,3,1);
		  	  if(ch == "0") currval=currval+0; else
		  	  if(ch == "1") currval=currval+1; else
		  	  if(ch == "2") currval=currval+2; else
		  	  if(ch == "3") currval=currval+3; else
		  	  if(ch == "4") currval=currval+4; else
		  	  if(ch == "5") currval=currval+5; else
		  	  if(ch == "6") currval=currval+6; else
		  	  if(ch == "7") currval=currval+7; else
		  	  if(ch == "8") currval=currval+8; else
		  	  if(ch == "9") currval=currval+9; else
		  	  if(ch == "A") currval=currval+10; else
		  	  if(ch == "B") currval=currval+11; else
		  	  if(ch == "C") currval=currval+12; else
		  	  if(ch == "D") currval=currval+13; else
		  	  if(ch == "E") currval=currval+14; else
		  	  if(ch == "F") currval=currval+15;
			  currval=currval*16;
			  ch=substr(hexval,4,1);
		  	  if(ch == "0") currval=currval+0; else
		  	  if(ch == "1") currval=currval+1; else
		  	  if(ch == "2") currval=currval+2; else
		  	  if(ch == "3") currval=currval+3; else
		  	  if(ch == "4") currval=currval+4; else
		  	  if(ch == "5") currval=currval+5; else
		  	  if(ch == "6") currval=currval+6; else
		  	  if(ch == "7") currval=currval+7; else
		  	  if(ch == "8") currval=currval+8; else
		  	  if(ch == "9") currval=currval+9; else
		  	  if(ch == "A") currval=currval+10; else
		  	  if(ch == "B") currval=currval+11; else
		  	  if(ch == "C") currval=currval+12; else
		  	  if(ch == "D") currval=currval+13; else
		  	  if(ch == "E") currval=currval+14; else
		  	  if(ch == "F") currval=currval+15;
			  currval=currval*16;
			  ch=substr(hexval,5,1);
		  	  if(ch == "0") currval=currval+0; else
		  	  if(ch == "1") currval=currval+1; else
		  	  if(ch == "2") currval=currval+2; else
		  	  if(ch == "3") currval=currval+3; else
		  	  if(ch == "4") currval=currval+4; else
		  	  if(ch == "5") currval=currval+5; else
		  	  if(ch == "6") currval=currval+6; else
		  	  if(ch == "7") currval=currval+7; else
		  	  if(ch == "8") currval=currval+8; else
		  	  if(ch == "9") currval=currval+9; else
		  	  if(ch == "A") currval=currval+10; else
		  	  if(ch == "B") currval=currval+11; else
		  	  if(ch == "C") currval=currval+12; else
		  	  if(ch == "D") currval=currval+13; else
		  	  if(ch == "E") currval=currval+14; else
		  	  if(ch == "F") currval=currval+15;
			  currval=currval*16;
			  ch=substr(hexval,6,1);
		  	  if(ch == "0") currval=currval+0; else
		  	  if(ch == "1") currval=currval+1; else
		  	  if(ch == "2") currval=currval+2; else
		  	  if(ch == "3") currval=currval+3; else
		  	  if(ch == "4") currval=currval+4; else
		  	  if(ch == "5") currval=currval+5; else
		  	  if(ch == "6") currval=currval+6; else
		  	  if(ch == "7") currval=currval+7; else
		  	  if(ch == "8") currval=currval+8; else
		  	  if(ch == "9") currval=currval+9; else
		  	  if(ch == "A") currval=currval+10; else
		  	  if(ch == "B") currval=currval+11; else
		  	  if(ch == "C") currval=currval+12; else
		  	  if(ch == "D") currval=currval+13; else
		  	  if(ch == "E") currval=currval+14; else
		  	  if(ch == "F") currval=currval+15;
		      while(nextval < currval)
			  {
			      print "	&&'"$2"' - &&JIT_OP_NOP_label,"
			      ++nextval
			  }
		      print "	&&" $2 "_label - &&JIT_OP_NOP_label,"
		      ++nextval
		  }' -
	return 0
}

# Output the label table (PIC version).
echo 'static int const main_label_table[JIT_INTERP_OP_END_MARKER] = {'
grep '^#define[ 	]*JIT_OP_' "$2" | grep -v 'JIT_OP_NUM_OPCODES' | \
	pic_table "$1" JIT_OP_NOP_label
grep '^#define[ 	]*JIT_INTERP_OP_' "$3" | grep -v 'JIT_INTERP_OP_NUM_OPCODES' | \
	grep -v 'JIT_INTERP_OP_END_MARKER' | pic_table "$1" JIT_OP_NOP_label
echo '};'
echo ''

# Output the helper macros (PIC).
echo '#define VMSWITCH(pc)        { goto *(&&JIT_OP_NOP_label + main_label_table[VMFETCH((pc))]);'
echo '#define VMSWITCHEND         }'
echo '#define VMCASE(val)         val##_label'
echo '#define VMBREAK             \
            goto *(&&JIT_OP_NOP_label + main_label_table[VMFETCH((pc))])'
echo ''

# Now to handle the non-PIC case of using computed goto's.
echo '#elif defined(JIT_INTERP_TOKEN)'
echo ''

# Output a table of non-PIC labels, based on an incoming stream
# of #define's for opcodes.  Some awks don't support hex
# string to number conversion, which is why we have to convert
# the opcode value the hard way.
non_pic_table()
{
	"$1" 'BEGIN{
		      nextval=0
		  }
		  {
		      currval=0;
			  hexval=$3
			  ch=substr(hexval,1,1);
			  if(ch == "(")
			    hexval=$5
			  ch=substr(hexval,3,1);
		  	  if(ch == "0") currval=currval+0; else
		  	  if(ch == "1") currval=currval+1; else
		  	  if(ch == "2") currval=currval+2; else
		  	  if(ch == "3") currval=currval+3; else
		  	  if(ch == "4") currval=currval+4; else
		  	  if(ch == "5") currval=currval+5; else
		  	  if(ch == "6") currval=currval+6; else
		  	  if(ch == "7") currval=currval+7; else
		  	  if(ch == "8") currval=currval+8; else
		  	  if(ch == "9") currval=currval+9; else
		  	  if(ch == "A") currval=currval+10; else
		  	  if(ch == "B") currval=currval+11; else
		  	  if(ch == "C") currval=currval+12; else
		  	  if(ch == "D") currval=currval+13; else
		  	  if(ch == "E") currval=currval+14; else
		  	  if(ch == "F") currval=currval+15;
			  currval=currval*16;
			  ch=substr(hexval,4,1);
		  	  if(ch == "0") currval=currval+0; else
		  	  if(ch == "1") currval=currval+1; else
		  	  if(ch == "2") currval=currval+2; else
		  	  if(ch == "3") currval=currval+3; else
		  	  if(ch == "4") currval=currval+4; else
		  	  if(ch == "5") currval=currval+5; else
		  	  if(ch == "6") currval=currval+6; else
		  	  if(ch == "7") currval=currval+7; else
		  	  if(ch == "8") currval=currval+8; else
		  	  if(ch == "9") currval=currval+9; else
		  	  if(ch == "A") currval=currval+10; else
		  	  if(ch == "B") currval=currval+11; else
		  	  if(ch == "C") currval=currval+12; else
		  	  if(ch == "D") currval=currval+13; else
		  	  if(ch == "E") currval=currval+14; else
		  	  if(ch == "F") currval=currval+15;
			  currval=currval*16;
			  ch=substr(hexval,5,1);
		  	  if(ch == "0") currval=currval+0; else
		  	  if(ch == "1") currval=currval+1; else
		  	  if(ch == "2") currval=currval+2; else
		  	  if(ch == "3") currval=currval+3; else
		  	  if(ch == "4") currval=currval+4; else
		  	  if(ch == "5") currval=currval+5; else
		  	  if(ch == "6") currval=currval+6; else
		  	  if(ch == "7") currval=currval+7; else
		  	  if(ch == "8") currval=currval+8; else
		  	  if(ch == "9") currval=currval+9; else
		  	  if(ch == "A") currval=currval+10; else
		  	  if(ch == "B") currval=currval+11; else
		  	  if(ch == "C") currval=currval+12; else
		  	  if(ch == "D") currval=currval+13; else
		  	  if(ch == "E") currval=currval+14; else
		  	  if(ch == "F") currval=currval+15;
			  currval=currval*16;
			  ch=substr(hexval,6,1);
		  	  if(ch == "0") currval=currval+0; else
		  	  if(ch == "1") currval=currval+1; else
		  	  if(ch == "2") currval=currval+2; else
		  	  if(ch == "3") currval=currval+3; else
		  	  if(ch == "4") currval=currval+4; else
		  	  if(ch == "5") currval=currval+5; else
		  	  if(ch == "6") currval=currval+6; else
		  	  if(ch == "7") currval=currval+7; else
		  	  if(ch == "8") currval=currval+8; else
		  	  if(ch == "9") currval=currval+9; else
		  	  if(ch == "A") currval=currval+10; else
		  	  if(ch == "B") currval=currval+11; else
		  	  if(ch == "C") currval=currval+12; else
		  	  if(ch == "D") currval=currval+13; else
		  	  if(ch == "E") currval=currval+14; else
		  	  if(ch == "F") currval=currval+15;
		      while(nextval < currval)
			  {
			      print "	&&'"$2"',"
			      ++nextval
			  }
		      print "	&&" $2 "_label,"
		      ++nextval
		  }' -
	return 0
}

# Output the label table (non-PIC).
echo 'static void * main_label_table[JIT_INTERP_OP_END_MARKER] = {'
grep '^#define[ 	]*JIT_OP_' "$2" | grep -v 'JIT_OP_NUM_OPCODES' | \
	non_pic_table "$1" JIT_OP_NOP_label
grep '^#define[ 	]*JIT_INTERP_OP_' "$3" | grep -v 'JIT_INTERP_OP_NUM_OPCODES' | \
	grep -v 'JIT_INTERP_OP_END_MARKER' | non_pic_table "$1" JIT_OP_NOP_label
echo '};'
echo ''

# Output the helper macros (non-PIC).
echo '#define VMSWITCH(pc)        { goto *main_label_table[VMFETCH((pc))];'
echo '#define VMSWITCHEND         }'
echo '#define VMCASE(val)         val##_label'
echo '#define VMBREAK             \
            goto *main_label_table[VMFETCH((pc))]'
echo ''

# Output the non-goto case of the helper macros.
echo '#else /* JIT_INTERP_SWITCH */'
echo ''
echo '#define VMSWITCH(pc)        for(;;) { switch(VMFETCH((pc)))'
echo '#define VMSWITCHEND         }'
echo '#define VMCASE(val)         case (val)'
echo '#define VMBREAK             VMNULLASM(); break'
echo ''
echo '#endif /* JIT_INTERP_SWITCH */'

# Done.
exit 0
