/*	$Id: table.c,v 1.13 2007/11/24 14:03:31 stefan Exp $	*/
/*-
 * Copyright (c) 2007 Gregory McGarry <g.mcgarry@ieee.org>
 *
 * Permission to use, copy, modify, and distribute this software for any
 * purpose with or without fee is hereby granted, provided that the above
 * copyright notice and this permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

/*
 * A template has five logical sections:
 *
 *	1) subtree (operator); goal to achieve (cookie)
 *	2) left node descendent of operator (node class; type)
 *	3) right node descendent of operator (node class; type)
 *	4) resource requirements (number of scratch registers);
 *	   subtree rewriting rule
 *	5) emitted instructions
 */

#include "pass2.h"

#define TUWORD	TUNSIGNED|TULONG
#define TSWORD	TINT|TLONG
#define TWORD	TUWORD|TSWORD

#ifdef ELFABI
#define HA16(x)	# x "@ha"
#define LO16(x)	# x "@l"
#define COM	"	# "
#else
#define HA16(x)	"ha16(" # x ")"
#define LO16(x)	"lo16(" # x ")"
#define COM	"	; "
#endif

struct optab table[] = {
/* First entry must be an empty entry */
{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },

/* PCONVs are not necessary */
{ PCONV,	INAREG,
	SAREG,	TWORD|TPOINT,
	SAREG,	TWORD|TPOINT,
		0,	RLEFT,
		COM "pointer conversion\n", },

/*
 * Conversions of integral types
 */

/* convert (u)char to (u)char */
{ SCONV,	INAREG,
	SAREG,	TCHAR|TUCHAR,
	SAREG,	TCHAR|TUCHAR,
		0,	RLEFT,
		COM "convert between (u)char and (u)char\n", },

/* convert (u)short to (u)short */
{ SCONV,	INAREG,
	SAREG,	TSHORT|TUSHORT,
	SAREG,	TSHORT|TUSHORT,
		0,	RLEFT,
		COM "convert between (u)short and (u)short\n", },

/* convert pointers to (u)int/(u)long */
{ SCONV,	INAREG,
	SAREG,	TPOINT|TWORD,
	SAREG,	TWORD,
		0,	RLEFT,
		COM "convert a pointer/word to an int\n", },

/* convert pointers to pointers */
{ SCONV,	INAREG,
	SAREG,	TPOINT,
	SAREG,	TPOINT,
		0,	RLEFT,
		COM "convert pointers\n", },

/* convert (u)longlong to (u)longlong */
{ SCONV,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SBREG,	TLONGLONG|TULONGLONG,
		0,	RLEFT,
		COM "convert (u)longlong to (u)longlong\n", },

/* convert char to short */
{ SCONV,	INAREG,
	SAREG,	TCHAR,
	SAREG,	TSHORT|TSWORD,
		NASL|NAREG,	RESC1,
		"	extsb A1,AL" COM "convert char to short/int\n", },

/* convert uchar to short */
{ SCONV,	INAREG,
	SAREG,	TUCHAR,
	SAREG,	TSHORT|TSWORD,
		NASL|NAREG,	RESC1,
		COM "convert uchar to short/int\n", },

/* convert uchar to ushort/uint/ulong */
{ SCONV,	INAREG,
	SAREG,	TUCHAR,
	SAREG,	TUSHORT|TUWORD,
		0,		RLEFT,
		COM "convert uchar (AL) to ushort/unsigned (A1)\n", },

/* XXX is this necessary? */
/* convert char to ushort/uint/ulong */
{ SCONV,	INAREG,
	SAREG,	TCHAR,
	SAREG,	TUSHORT|TUWORD,
		NASL|NAREG|NSPECIAL,	RESC1,
		"	extsb A1,AL" COM "convert char (AL) to ushort/unsigned (A1)\n", },

/* convert uchar/ushort/uint to (u)longlong */
{ SCONV,	INBREG,
	SAREG,	TUCHAR|TUSHORT|TUNSIGNED,
	SBREG,	TLONGLONG|TULONGLONG,
		NBREG,		RESC1,
		"	mr A1,AL" COM "convert uchar/ushort/uint to (u)longlong\n"
		"	li U1,0\n", },

/* convert char/short/int to (u)longlong */
{ SCONV,	INBREG,
	SAREG,	TCHAR|TSHORT|TSWORD,
	SBREG,	TULONGLONG|TLONGLONG,
		NBREG,		RESC1,
		"	mr A1,AL" COM "convert char/short/int to ulonglong\n"
		"	srawi U1,AL,31\n", },

/* convert (u)short to (u)char  */
{ SCONV,	INAREG,
	SAREG,	TSHORT|TUSHORT,
	SAREG,	TCHAR|TUCHAR,
		NSPECIAL|NAREG|NASL,	RESC1,
		"	andi. A1,AL,255" COM "convert (u)short to (u)char\n", },

/* XXX is this really necessary? */
/* convert short to (u)int */
{ SCONV,	INAREG,
	SAREG,	TSHORT,
	SAREG,	TWORD,
		NAREG|NASL,	RESC1,
		"	extsh A1,AL" COM "convert short to int\n", },

/* convert ushort to (u)int. */
{ SCONV,	INAREG,
	SAREG,	TUSHORT,
	SAREG,	TWORD,
		NASL|NAREG|NSPECIAL,	RESC1,
		COM "convert ushort to word\n", },

/* convert (u)int to (u)char */
{ SCONV,	INAREG,
	SAREG,	TWORD,
	SAREG,	TCHAR|TUCHAR,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	andi. A1,AL,255" COM "convert (u)int to (u)char\n", },

/* convert (u)int to (u)short */
{ SCONV,	INAREG,
	SAREG,	TWORD,
	SAREG,	TSHORT|TUSHORT,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	andi. A1,AL,65535" COM "convert (u)int to (u)short\n", },

/* convert (u)longlong to (u)char */
{ SCONV,	INAREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SAREG,	TCHAR|TUCHAR,
		NAREG|NSPECIAL,	RESC1,
		"	andi. A1,AL,255" COM "(u)longlong to (u)char\n", },

/* convert (u)longlong to (u)short*/
{ SCONV,	INAREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SAREG,	TSHORT|TUSHORT,
		NAREG|NSPECIAL,	RESC1,
		"	andi. A1,AL,65535" COM "(u)longlong to (u)short\n", },

/* convert (u)longlong to (u)int */
{ SCONV,	INAREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SAREG,	TWORD,
		NAREG,		RESC1,
		"	mr A1,AL" COM "convert (u)longlong to (u)int/long\n", },

/* conversions on load from memory */

/* char */
{ SCONV,	INAREG,
	SOREG,	TCHAR,
	SAREG,	TWORD,
		NASL|NAREG|NSPECIAL,	RESC1,
		"	lbz A1,AL" COM "convert char to int/long\n"
		"	extsb A1,A1\n", },

/* uchar */
{ SCONV,	INAREG,
	SOREG,	TUCHAR,
	SAREG,	TWORD,
		NASL|NAREG|NSPECIAL,	RESC1,
		"	lbz A1,AL" COM "convert uchar to int/long\n", },

/* short */
{ SCONV,	INAREG,
	SOREG,	TSHORT,
	SAREG,	TWORD,
		NASL|NAREG|NSPECIAL,	RESC1,
		"	lha A1,AL" COM "convert short to int/long\n", },

/* ushort */
{ SCONV,	INAREG,
	SOREG,	TUSHORT,
	SAREG,	TWORD,
		NASL|NAREG|NSPECIAL,	RESC1,
		"	lhz A1,AL" COM "convert ushort to int/long\n", },

/* (u)longlong to (u)char */
{ SCONV,	INAREG,
	SOREG,	TLONGLONG|TULONGLONG,
	SAREG,	TCHAR|TUCHAR,
		NAREG|NSPECIAL,	RESC1,
		"	lwz A1,AL" COM "(u)longlong to (u)char\n"
		"	andi. A1,A1,255\n", },

/* (u)longlong to (u)short */
{ SCONV,	INAREG,
	SOREG,	TLONGLONG|TULONGLONG,
	SAREG,	TSHORT|TUSHORT,
		NAREG|NSPECIAL,	RESC1,
		"	lwz A1,AL" COM "(u)longlong to (u)short\n"
		"	andi. A1,A1,65535\n", },

/* (u)longlong to (u)int */
{ SCONV,	INAREG,
	SOREG,	TLONGLONG|TULONGLONG,
	SAREG,	TWORD,
		NAREG|NSPECIAL,	RESC1,
		"	lwz A1,AL" COM "(u)longlong to (u)int\n", },

/* XXX where are the other OREG conversions? endianness problems? */

/*
 * Subroutine calls.
 */

{ CALL,		FOREFF,
	SCON|SNAME,	TANY,
	SANY,		TANY,
		0,	0,
		"	bl CL" COM "call (args, no result) to scon/sname (CL)\n", },

{ UCALL,	FOREFF,
	SCON|SNAME,	TANY,
	SANY,		TANY,
		0,	0,
		"	bl CL" COM "call (no args, no result) to scon/sname (CL)\n", },

{ CALL,		INAREG,
	SCON|SNAME,	TANY,
	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT,
		NAREG|NASL,	RESC1,	/* should be 0 */
		"	bl CL" COM "call (args, result in r3) to scon/sname (CL)\n", },

{ CALL,		INBREG,
	SCON|SNAME,	TANY,
	SBREG,		TLONGLONG|TULONGLONG,
		NBREG|NBSL,	RESC1,	/* should be 0 */
		"	bl CL" COM "call (args, result in r3:r4) to scon/sname (CL)\n", },

{ UCALL,	INAREG,
	SCON|SNAME,	TANY,
	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT,
		NAREG|NASL,	RESC1,	/* should be 0 */
		"	bl CL" COM "call (no args, result in r3) to scon/sname (CL)\n", },

{ UCALL,	INBREG,
	SCON|SNAME,	TANY,
	SBREG,		TLONGLONG|TULONGLONG,
		NBREG|NBSL,	RESC1,	/* should be 0 */
		"	bl CL" COM "call (no args, result in r3:r4) to scon/sname (CL)\n", },

/* struct return */
{ USTCALL,	FOREFF,
	SCON,	TANY,
	SANY,	TANY,
		NAREG|NASL,	0,
		"ZP	call CL\n", },

{ USTCALL,	INAREG,
	SCON,	TANY,
	SANY,	TANY,
		NAREG|NASL,	RESC1,	/* should be 0 */
		"ZP	call CL\n", },

{ USTCALL,	INAREG,
	SNAME|SAREG,	TANY,
	SANY,	TANY,
		NAREG|NASL,	RESC1,	/* should be 0 */
		"ZP	call *AL\n", },

{ STCALL,	FOREFF,
	SCON,	TANY,
	SANY,	TANY,
		NAREG|NASL,	0,
		"ZP	call CL\n", },

{ STCALL,	INAREG,
	SCON,	TANY,
	SANY,	TANY,
		NAREG|NASL,	RESC1,	/* should be 0 */
		"ZP	call CL\n", },

{ STCALL,	INAREG,
	SNAME|SAREG,	TANY,
	SANY,	TANY,
		NAREG|NASL,	RESC1,	/* should be 0 */
		"ZP	call *AL\n", },

/*
 * The next rules handle all binop-style operators.
 */

/* XXX AL cannot be R0 */
{ PLUS,		INAREG,
	SAREG,	TWORD|TPOINT,
	SSCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	addi A1,AL,AR" COM "addition of constant\n", },

/* XXX AL cannot be R0 */
{ PLUS,		INAREG|FORCC,
	SAREG,	TWORD|TPOINT,
	SSCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	addic. A1,AL,AR" COM "addition of constant\n", },

{ PLUS,		INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SSCON,	TANY,
		NBREG|NBSL,	RESC1,
		"	addic A1,AL,AR" COM "64-bit addition of constant\n"
		"	addze U1,UL\n", },

{ PLUS,		INAREG,
	SAREG,	TWORD|TPOINT,
	SAREG,	TWORD|TPOINT,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	add A1,AL,AR\n", },

{ PLUS,		INAREG|FORCC,
	SAREG,	TWORD|TPOINT,
	SAREG,	TWORD|TPOINT,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	add. A1,AL,AR\n", },

{ PLUS,		INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SBREG,	TLONGLONG|TULONGLONG,
		NBREG|NBSL,	RESC1,
		"	addc A1,AL,AR" COM "64-bit add\n"
		"	adde U1,UL,UR\n", },

{ MINUS,	INAREG,
	SAREG,	TWORD|TPOINT,
	SSCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	addi A1,AL,-AR\n", },

{ MINUS,	INAREG|FORCC,
	SAREG,	TWORD|TPOINT,
	SSCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	addic. A1,AL,-AR\n", },

{ MINUS,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SSCON,	TANY,
		NBREG|NBSL,	RESC1,
		"	addic A1,AL,-AR\n"
		"	addme U1,UL\n", },

{ MINUS,	INAREG,
	SAREG,	TWORD|TPOINT,
	SAREG,	TWORD|TPOINT,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	subf A1,AR,AL\n", },

{ MINUS,	INAREG|FORCC,
	SAREG,	TWORD|TPOINT,
	SAREG,	TWORD|TPOINT,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	subf. A1,AR,AL\n", },

{ MINUS,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SBREG,	TLONGLONG|TULONGLONG,
		NBREG|NBSL,	RESC1,
		"	subfc A1,AR,AL" COM "64-bit subtraction\n"
		"	subfe U1,UR,UL\n", },

/*
 * The next rules handle all shift operators.
 */

{ LS,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL,	RESC1,
		"	slw A1,AL,AR" COM "left shift\n", },

{ LS,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL,	RESC1,
		"	slw. A1,AL,AR" COM "left shift\n", },

{ LS,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SCON,	TANY,
		NAREG|NASL,	RESC1,
		"	slwi A1,AL,AR" COM "left shift by constant\n", },

{ LS,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SCON,	TANY,
		NAREG|NASL,	RESC1,
		"	slwi. A1,AL,AR" COM "left shift by constant\n", },

{ LS,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SCON,	TANY,
		NBREG,	RESC1,
		"ZO" },

{ RS,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL,	RESC1,
		"	srw A1,AL,AR" COM "right shift\n", },

{ RS,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL,	RESC1,
		"	srw. A1,AL,AR" COM "right shift\n", },

{ RS,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SCON,	TANY,
		NAREG|NASL,	RESC1,
		"	srwi A1,AL,AR" COM "right shift by constant\n", },

{ RS,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SCON,	TANY,
		NAREG|NASL,	RESC1,
		"	srwi. A1,AL,AR" COM "right shift by constant\n", },

{ RS,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SCON,	TANY,
		NBREG,	RESC1,
		"ZO" },

/*
 * The next rules takes care of assignments. "=".
 */

/* assign 16-bit constant to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TANY,
	SSCON,		TANY,
		0,	RDEST,
		"	li AL,AR\n", },

/* assign 16-bit constant to register */
{ ASSIGN,	FOREFF|INBREG,
	SBREG,		TANY,
	SSCON,		TANY,
		0,	RDEST,
		"	li AL,AR\n"
		"	li UL,UR\n", },

/* assign constant to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TANY,
	SCON,		TANY,
		0,	RDEST,
		"	lis AL," HA16(AR) "\n"
		"	addi AL,AL," LO16(AR) "\n", },

/* assign constant to register */
{ ASSIGN,	FOREFF|INBREG,
	SBREG,		TANY,
	SCON,		TANY,
		0,	RDEST,
		"	lis AL," HA16(AR) "\n"
		"	addi AL,AL," LO16(AR) "\n"
		"	lis UL," HA16(UR) "\n"\
		"	addi UL,UL," LO16(UR) "\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TWORD|TPOINT,
	SOREG,		TWORD|TPOINT,
		NSPECIAL,	RDEST,
		"	lwz AL,AR\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TWORD|TPOINT,
	SNAME,		TWORD|TPOINT,
		NSPECIAL,	RDEST,
		"	lis AL," HA16(AR) COM "assign sname to reg\n"
		"	lwz AL," LO16(AR) "(AL)\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INBREG,
	SBREG,		TLONGLONG|TULONGLONG,
	SOREG,		TLONGLONG|TULONGLONG,
		NSPECIAL,	RDEST,
		"	lwz AL,AR" COM "assign llong to reg\n"
		"	lwz UL,UR\n" },

{ ASSIGN,	FOREFF|INAREG,
	SBREG,		TLONGLONG|TULONGLONG,
	SNAME,		TLONGLONG|TULONGLONG,
		NSPECIAL,	RDEST,
		"	lis AL," HA16(AR) COM "assign 64-bit sname to reg\n"
		"	lwz AL," LO16(AR) "(AL)\n"
		"	lis UL," HA16(UR) "\n"
		"	lwz UL," LO16(UR) "(UL)\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INBREG,
	SBREG,		TLONGLONG|TULONGLONG,
	SOREG,		TSWORD,
		NSPECIAL,	RDEST,
		"	lwz AL,AR" COM "load int/pointer into llong\n"
		"	srawi UL,AR,31\n" },

/* assign memory to register */
{ ASSIGN,	FOREFF|INBREG,
	SBREG,		TLONGLONG|TULONGLONG,
	SOREG,		TUNSIGNED|TPOINT,
		NSPECIAL,	RDEST,
		"	lwz AL,AR" COM "load uint/pointer into (u)llong\n"
		"	li UL, 0\n" },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TUCHAR,
	SOREG,		TUCHAR,
		NSPECIAL,	RDEST,
		"	lbz AL,AR\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TUCHAR,
	SNAME,		TUCHAR,
		NSPECIAL,	RDEST,
		"	lis AL," HA16(AR) COM "assign uchar sname to reg\n"
		"	lbz AL," LO16(AR) "(AL)\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TCHAR,
	SOREG,		TCHAR,
		NSPECIAL,	RDEST,
		"	lbz AL,AR\n"
		"	extsb AL,AL\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TCHAR,
	SNAME,		TCHAR,
		NSPECIAL,	RDEST,
		"	lis AL," HA16(AR) COM "assign char sname to reg\n"
		"	lbz AL," LO16(AR) "(AL)\n"
		"	extsb AL,AL\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TWORD|TPOINT,
	SOREG,		TSHORT,
		NSPECIAL,	RDEST,
		"	lha AL,AR\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TWORD|TPOINT,
	SOREG,		TUSHORT,
		NSPECIAL,	RDEST,
		"	lhz AL,AR\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TWORD,
	SNAME,		TSHORT,
		NSPECIAL,	RDEST,
		"	lis AL," HA16(AR) "\n"
		"	lha AL," LO16(AR) "(AL)\n", },

/* assign memory to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TWORD,
	SNAME,		TUSHORT,
		NSPECIAL,	RDEST,
		"	lis AL," HA16(AR) "\n"
		"	lhz AL," LO16(AR) "(AL)\n", },

/* assign register to memory */
{ ASSIGN,	FOREFF|INAREG,
	SOREG,		TWORD|TPOINT,
	SAREG,		TWORD|TPOINT,
		NSPECIAL,	RDEST,
		"	stw AR,AL\n", },

/* assign register to memory */
{ ASSIGN,	FOREFF|INAREG,
	SNAME,		TWORD|TPOINT,
	SAREG,		TWORD|TPOINT,
		NAREG|NSPECIAL,	RDEST,
		"	lis A1," HA16(AL) COM "assign reg to sname\n"
		"	stw AR," LO16(AL) "(A1)\n", },

/* assign register to memory */
{ ASSIGN,	FOREFF|INBREG,
	SOREG,		TLONGLONG|TULONGLONG,
	SBREG,		TLONGLONG|TULONGLONG,
		NSPECIAL,	RDEST,
		"	stw AR,AL" COM "store 64-bit value\n"
		"	stw UR,UL\n", },

/* assign register to memory */
{ ASSIGN,	FOREFF|INBREG,
	SNAME,		TLONGLONG|TULONGLONG,
	SBREG,		TLONGLONG|TULONGLONG,
		NBREG|NSPECIAL,	RDEST,
		"	lis A1," HA16(AL) COM "assign reg to 64-bit sname\n"
		"	stw AR," LO16(AL) "(A1)\n"
		"	lis U1," HA16(UL) "\n"
		"	stw UR," LO16(UL) "(U1)\n", },

/* assign register to memory */
{ ASSIGN,	FOREFF|INAREG,
	SOREG,		TCHAR|TUCHAR,
	SAREG,		TCHAR|TUCHAR,
		NSPECIAL,	RDEST,
		"	stb AR,AL\n", },

/* assign register to memory */
{ ASSIGN,	FOREFF|INAREG,
	SNAME,		TCHAR|TUCHAR,
	SAREG,		TCHAR|TUCHAR,
		NAREG|NSPECIAL,	RDEST,
		"	lis A1," HA16(AL) "\n"
		"	stb AR," LO16(AL) "(A1)\n", },

/* assign register to memory */
{ ASSIGN,	FOREFF|INAREG,
	SOREG,		TSHORT|TUSHORT,
	SAREG,		TSHORT|TUSHORT,
		NSPECIAL,	RDEST,
		"	sth AR,AL\n", },

/* assign register to memory */
{ ASSIGN,	FOREFF|INAREG,
	SNAME,		TSHORT|TUSHORT,
	SAREG,		TSHORT|TUSHORT,
		NAREG|NSPECIAL,	RDEST,
		"	lis A1," HA16(AL) "\n"
		"	sth AR," LO16(AL) "(A1)\n", },

/* assign register to register */
{ ASSIGN,	FOREFF|INAREG,
	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
		0,	RDEST,
		"	mr AL,AR" COM "assign AR to AL\n", },

{ ASSIGN,      FOREFF|INBREG,
        SBREG,	TLONGLONG|TULONGLONG,
        SBREG,	TLONGLONG|TULONGLONG,
                0,  RDEST,
		"	mr AL,AR" COM "assign UR:AR to UL:AL\n"
                "	mr UL,UR\n", },

#if 0
/* assign register to memory */
{ ASSIGN,	FOREFF,
	SAREG,		TPOINT,
	SAREG,		TWORD,
		0,	RDEST,
		"	stw AR,0(AL)" COM "indirect assign\n", },
#endif

#if 0
{ ASSIGN,	FOREFF|INAREG,
	SFLD,	TANY,
	SAREG,	TANY,
		NAREG,	RDEST,
		"ZE", },

{ ASSIGN,	FOREFF,
	SFLD,	TANY,
	SAREG,	TANY,
		NAREG,	0,
		"ZE", },
#endif

/* Do not generate memcpy if return from funcall */
#if 0
{ STASG,	INAREG|FOREFF,
	SOREG|SNAME|SAREG,	TPTRTO|TSTRUCT,
	SFUNCALL,	TPTRTO|TSTRUCT,
		0,	RRIGHT,
		"", },
#endif

{ STASG,	INAREG|FOREFF,
	SOREG,	TANY,
	SAREG,	TPTRTO|TANY,
		NSPECIAL,	RRIGHT,
		"ZQ", },

/*
 * DIV/MOD/MUL 
 */

{ DIV,	INAREG,
	SAREG,	TSWORD,
	SAREG,	TWORD,
		NAREG|NASL,	RESC1,
		"	divw A1,AL,AR\n", },

{ DIV,	INAREG,
	SAREG,	TUWORD|TPOINT,
	SAREG,	TUWORD|TPOINT,
		NAREG|NASL,	RESC1,
		"	divwu A1,AL,AR\n", },

{ MOD,	INAREG,
	SAREG,	TSWORD,
	SAREG,	TSWORD,
		NAREG,	RESC1,
		"	divw A1,AL,AR" COM "signed modulo\n"
		"	mullw A1,A1,AR\n"
		"	subf A1,A1,AL\n", },

{ MOD,	INAREG,
	SAREG,	TWORD|TPOINT,
	SAREG,	TUWORD|TPOINT,
		NAREG,	RESC1,
		"	divwu A1,AL,AR" COM "unsigned modulo\n"
		"	mullw A1,A1,AR\n"
		"	subf A1,A1,AL\n", },

{ MUL,	INAREG,
	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SSCON,		TANY,
		NAREG|NASL,	RESC1,
		"	mulli A1,AL,AR\n", },

{ MUL,	INAREG,
	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL,	RESC1,
		"	mullw A1,AL,AR\n", },

{ MUL,	INBREG,
	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,		TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NBREG,	RESC1,
		"	mullw A1,AL,AR\n"
		"	mulhw U1,AL,AR\n", },

{ MUL,	INBREG,
	SBREG,		TLONGLONG|TULONGLONG,
	SBREG,		TLONGLONG|TULONGLONG,
		NBREG,	RESC1,
		"	mullw A1,AL,AR\n"
		"	mulhw U1,AL,AR\n", },

/*
 * Indirection operators.
 */

{ UMUL,	INAREG,
	SANY,		TANY,
	SOREG,		TWORD|TPOINT,
		NAREG|NSPECIAL,	RESC1,
		"	lwz A1,AL" COM "word load\n", },

{ UMUL,	INAREG,
	SANY,		TANY,
	SOREG,		TCHAR,
		NAREG|NSPECIAL,	RESC1,
		"	lbz A1,AL" COM "char load\n"
		"	extsb A1,A1\n", },

{ UMUL,	INAREG,
	SANY,		TANY,
	SOREG,		TUCHAR,
		NAREG|NSPECIAL,	RESC1,
		"	lbz A1,AL" COM "uchar load\n", },

{ UMUL,	INAREG,
	SANY,		TANY,
	SOREG,		TSHORT,
		NAREG|NSPECIAL,	RESC1,
		"	lha A1,AL" COM "short load\n", },

{ UMUL,	INAREG,
	SANY,		TANY,
	SOREG,		TUSHORT,
		NAREG|NSPECIAL,	RESC1,
		"	lhz A1,AL" COM "ushort load\n", },

{ UMUL, INBREG,
	SANY,		TANY,
	SOREG,		TLONGLONG|TULONGLONG,
		NBREG, RESC1,
		"	lwz A1,AL" COM "64-bit load\n"
		"	lwz U1,UL\n", },

/* XXX UMUL of SNAME and AREG !!! */

/*
 * Logical/branching operators
 */

/* compare with constant */
{ OPLOG,	FORCC,
	SAREG,	TSWORD|TSHORT|TCHAR,
	SSCON,	TANY,
		0, 	RESCC,
		"	cmpwi AL,AR\n", },

/* compare with constant */
{ OPLOG,	FORCC,
	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
	SSCON,	TANY,
		0, 	RESCC,
		"	cmplwi AL,AR\n", },

/* compare with register */
{ OPLOG,	FORCC,
	SAREG,	TSWORD|TSHORT|TCHAR,
	SAREG,	TSWORD|TSHORT|TCHAR,
		0, 	RESCC,
		"	cmpw AL,AR\n", },

/* compare with register */
{ OPLOG,	FORCC,
	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
	SAREG,	TUWORD|TPOINT|TUSHORT|TUCHAR,
		0, 	RESCC,
		"	cmplw AL,AR\n", },

/* compare with register */
{ OPLOG,	FORCC,
	SBREG,	TLONGLONG|TULONGLONG,
	SBREG,	TLONGLONG|TULONGLONG,
		0, 	0,
		"ZD", },

{ OPLOG,	FORCC,
	SANY,	TANY,
	SANY,	TANY,
		REWRITE,	0,
		"diediedie!", },

/* AND/OR/ER */
{ AND,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	and A1,AL,AR\n", },

{ AND,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	and. A1,AL,AR\n", },

/* AR must be positive */
{ AND,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TCHAR,
	SPCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	andi. A1,AL,AR\n", },

{ AND,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SBREG,	TLONGLONG|TULONGLONG,
		NBREG|NBSL,	RESC1,
		"	and A1,AL,AR" COM "64-bit and\n"
		"	and U1,UL,UR\n" },

{ AND,	INBREG|FORCC,
	SBREG,	TLONGLONG|TULONGLONG,
	SPCON,	TANY,
		NBREG|NBSL,	RESC1|RESCC,
		"	andi. A1,AL,AR" COM "64-bit and with constant\n"
		"	li U1,0\n" },

{ OR,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	or A1,AL,AR\n", },

{ OR,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	or. A1,AL,AR\n", },

{ OR,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TCHAR,
	SSCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	ori A1,AL,AR\n", },

{ OR,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TCHAR,
	SSCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	ori. A1,AL,AR\n", },

{ OR,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SBREG,	TLONGLONG|TULONGLONG,
		NBREG|NBSL,	RESC1,
		"	or A1,AL,AR" COM "64-bit or\n"
		"	or U1,UL,UR\n" },

{ OR,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SSCON,	TANY,
		NBREG|NBSL,	RESC1,
		"	ori A1,AL,AR" COM "64-bit or with constant\n" },

{ OR,	INBREG|FORCC,
	SBREG,	TLONGLONG|TULONGLONG,
	SSCON,	TANY,
		NBREG|NBSL,	RESC1|RESCC,
		"	ori. A1,AL,AR" COM "64-bit or with constant\n" },

{ ER,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	xor A1,AL,AR\n", },

{ ER,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	xor. A1,AL,AR\n", },

{ ER,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TCHAR,
	SSCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	xori A1,AL,AR\n", },

{ ER,	INAREG|FORCC,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TCHAR,
	SSCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1|RESCC,
		"	xori. A1,AL,AR\n", },

{ ER,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SBREG,	TLONGLONG|TULONGLONG,
		NBREG|NBSL,	RESC1,
		"	xor A1,AL,AR" COM "64-bit xor\n"
		"	xor U1,UL,UR\n" },

{ ER,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SSCON,	TANY,
		NBREG|NBSL,	RESC1,
		"	xori A1,AL,AR" COM "64-bit xor with constant\n" },

{ ER,	INBREG|FORCC,
	SBREG,	TLONGLONG|TULONGLONG,
	SSCON,	TANY,
		NBREG|NBSL,	RESC1|RESCC,
		"	xori. A1,AL,AR" COM "64-bit xor with constant\n" },

/*
 * Jumps.
 */
{ GOTO, 	FOREFF,
	SCON,	TANY,
	SANY,	TANY,
		0,	RNOP,
		"	ba LL\n", },

{ GOTO, 	FOREFF,
	SAREG,	TANY,
	SANY,	TANY,
		0,	RNOP,
		"	mtctr AL\n"
		"	bctr\n", },

/*
 * Convert LTYPE to reg.
 */

{ OPLTYPE,      INBREG,
        SANY,   	TANY,
        SOREG,		TLONGLONG|TULONGLONG,
                NBREG,  RESC1,
                "	lwz A1,AL" COM "load llong from memory\n"
		"	lwz U1,UL\n", },

{ OPLTYPE,      INBREG,
        SANY,   	TANY,
        SNAME,		TLONGLONG|TULONGLONG,
                NBREG,  RESC1,
		"	lis A1," HA16(AL) COM "load llong from sname\n"
		"	lwz A1," LO16(AL) "(A1)\n"
		"	lis U1," HA16(UL) "\n"
		"	lwz U1," LO16(UL) "(U1)\n", },

/* load word from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SOREG,	TWORD|TPOINT,
		NAREG,	RESC1,
		"	lwz A1,AL" COM "load word from memory\n", },

/* load word from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SNAME,		TWORD|TPOINT,
		NAREG|NSPECIAL,	RESC1,
		"	lis A1," HA16(AL) COM "load word from sname\n"
		"	lwz A1," LO16(AL) "(A1)\n", },

/* load char from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SOREG,		TCHAR,
		NAREG,	RESC1,
		"	lbz A1,AL" COM "load char from memory\n"
		"	extsb A1,A1\n", },

/* load char from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SNAME,		TCHAR,
		NAREG|NSPECIAL,	RESC1,
		"	lis A1," HA16(AL) COM "load char from sname\n"
		"	lbz A1," LO16(AL) "(A1)\n"
		"	extsb A1,A1\n", },

/* load uchar from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SOREG,		TUCHAR,
		NAREG,	RESC1,
		"	lbz A1,AL" COM "load uchar from memory\n", },

/* load uchar from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SNAME,		TUCHAR,
		NAREG|NSPECIAL,	RESC1,
		"	lis A1," HA16(AL) COM "load uchar from sname\n"
		"	lbz A1," LO16(AL) "(A1)\n", },

/* load short from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SOREG,		TSHORT,
		NAREG,	RESC1,
		"	lha A1,AL" COM "load short from memory\n", },

/* load ushort from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SOREG,		TUSHORT,
		NAREG,	RESC1,
		"	lhz A1,AL" COM "load ushort from memory\n", },

/* load short from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SNAME,		TSHORT,
		NAREG|NSPECIAL,	RESC1,
		"	lis A1," HA16(AL) COM "load short from sname\n"
		"	lha A1," LO16(AL) "(A1)\n", },

/* load ushort from memory */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SNAME,		TUSHORT,
		NAREG|NSPECIAL,	RESC1,
		"	lis A1," HA16(AL) COM "load ushort from sname\n"
		"	lhz A1," LO16(AL) "(A1)\n", },

/* load from 16-bit constant */
{ OPLTYPE,	INAREG,
	SANY,		TANY,
	SSCON,		TANY,
		NAREG,	RESC1,
		"	li A1,AL" COM "load 16-bit constant\n", },

/* load from 16-bit constant */
{ OPLTYPE,	INBREG,
	SANY,	TANY,
	SSCON,	TANY,
		NBREG,	RESC1,
		"	li A1,AL" COM "load 16-bit constant\n"
		"	li U1,UL\n", },

/* load from constant */
{ OPLTYPE,	INAREG,
	SANY,	TANY,
	SCON,	TANY,
		NAREG|NASL|NSPECIAL,	RESC1,
		"	lis A1," HA16(AL) COM "load constant into register\n"
		"	addi A1,A1," LO16(AL) "\n", },

/* load from constant */
{ OPLTYPE,	INBREG,
	SANY,	TANY,
	SCON,	TANY,
		NBREG,	RESC1,
		"	lis A1," HA16(AL) COM "load constant into register\n"
		"	addi A1,A1," LO16(AL) "\n"
		"	lis U1," HA16(UL) "\n"
		"	addi U1,U1," LO16(UL) "\n", },

/* load from register */
{ OPLTYPE,	INAREG,
	SANY,	TANY,
	SAREG,	TANY,
		NAREG,	RESC1,
		"	mr A1,AL" COM "load AL into A1\n" },

/* load from register */
{ OPLTYPE,      INBREG,
        SANY,   TANY,
        SBREG,	TLONGLONG|TULONGLONG,
                NBREG,  RESC1,
		"	mr A1,AL" COM "load UL:AL into U1:A1\n"
                "       mr U1,UL\n", },

/*
 * Negate a word.
 */

{ UMINUS,	INAREG,
	SAREG,	TWORD|TPOINT|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SANY,	TANY,
		NAREG|NASL,	RESC1,
		"	neg A1,AL\n", },

{ UMINUS,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SANY,	TANY,
		NBREG|NBSL,	RESC1,
		"	subfic A1,AL,0\n"
		"	subfze U1,UL\n", },

{ COMPL,	INAREG,
	SAREG,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SANY,	TANY,
		NAREG|NASL,	RESC1,
		"	not A1,AL\n", },

{ COMPL,	INBREG,
	SBREG,	TLONGLONG|TULONGLONG,
	SANY,	TANY,
		NBREG|NBSL,	RESC1,
		"	not A1,AL\n"
		"	not U1,UL\n", },

/*
 * Arguments to functions.
 */

#if 0
{ FUNARG,	FOREFF,
	SCON|SAREG|SNAME|SOREG,	TWORD|TPOINT,
	SANY,	TWORD|TPOINT,
		0,	RNULL,
		"	pushl AL\n", },

{ FUNARG,	FOREFF,
	SCON,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SANY,	TWORD|TSHORT|TUSHORT|TCHAR|TUCHAR,
		0,	RNULL,
		"	pushl AL\n", },

{ FUNARG,	FOREFF,
	SAREG|SNAME|SOREG,	TSHORT,
	SANY,	TSHORT,
		NAREG,	0,
		"	movswl AL,ZN\n	pushl ZN\n", },
#endif

{ FUNARG,	FOREFF,
	SAREG|SNAME|SOREG,	TUSHORT,
	SANY,	TUSHORT,
		NAREG,	0,
		"	movzwl AL,ZN\n	pushl ZN\n", },

#if 0
{ FUNARG,	FOREFF,
	SHCH|SNAME|SOREG,	TCHAR,
	SANY,			TCHAR,
		NAREG,	0,
		"	movsbl AL,A1\n	pushl A1\n", },
#endif

#if 0
{ FUNARG,	FOREFF,
	SHCH|SNAME|SOREG,	TUCHAR,
	SANY,	TUCHAR,
		NAREG,	0,
		"	movzbl AL,A1\n	pushl A1\n", },
#endif

#if 0
{ STARG,	FOREFF,
	SAREG|SOREG|SNAME|SCON,	TANY,
	SANY,	TSTRUCT,
		NSPECIAL|NAREG,	0,
		"ZF", },
#endif

# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""

{ UMUL, DF( UMUL ), },

{ ASSIGN, DF(ASSIGN), },

{ STASG, DF(STASG), },

{ FLD, DF(FLD), },

{ OPLEAF, DF(NAME), },

/* { INIT, DF(INIT), }, */

{ OPUNARY, DF(UMINUS), },

{ OPANY, DF(BITYPE), },

{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
};

int tablesize = sizeof(table)/sizeof(table[0]);


syntax highlighted by Code2HTML, v. 0.9.1