/*
 * Copyright (c) 2008 David Crawshaw <david@zentus.com>
 * 
 * Permission to use, copy, modify, and/or 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.
 */

#include "pass2.h"

#define TS64   TLONG|TLONGLONG
#define TU64   TULONG|TULONGLONG|TPOINT
#define T64    TS64|TU64

struct optab table[] = {

{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },      /* empty */

{ PCONV,	INAREG,
	SAREG,	T64|TINT,
	SAREG,	T64,
		0,	RLEFT,
		"	! convert between word and pointer\n", },

/* Conversions. */

{ SCONV,	INAREG,
	SAREG,	T64|TUNSIGNED,
	SAREG,	TINT,
		NAREG|NASL,	RESC1,
		"	sra AL,0,A1	\t\t! (u)int64/32 -> (u)int32\n", },

{ SCONV,	INAREG,
	SAREG,	T64|TINT|TUNSIGNED,
	SAREG,	TSHORT,
		NAREG|NASL,	RESC1,
		"	sll AL,16,A1	\t\t! (u)int64/32 -> int16\n"
		"	sra AL,16,A1\n"
		"	sra AL, 0,A1\n", },

{ SCONV,	INAREG,
	SAREG,	T64|TINT|TUNSIGNED,
	SAREG,	TUSHORT,
		NAREG|NASL,	RESC1,
		"	sll AL,16,A1	\t\t! (u)int64/32 -> uint16\n"
		"	srl AL,16,A1\n", },

{ SCONV,	INAREG,
	SAREG,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT,
	SAREG,	TCHAR,
		NAREG|NASL,	RESC1,
		"	sll AL,24,A1	\t\t! (u)int64/32/16 -> int8\n"
		"	sra AL,24,A1\n"
		"	sra AL, 0,A1\n", },

{ SCONV,	INAREG,
	SAREG,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT,
	SAREG,	TUCHAR,
		NAREG|NASL,	RESC1,
		"	and AL,0xff,A1	\t\t! (u)int64/32/16 -> uint8\n", },

{ SCONV,	INAREG,
	SAREG,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR, /* TCHAR|TUCHAR added to handle char -> long (among others) */
	SAREG,	T64,
		0,	RLEFT,
		"	              	\t\t! (u)int64...8 -> (u)int64\n", },

{ SCONV,	INAREG,
	SAREG,	TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG,	TINT,
		0,	RLEFT,
		"	              	\t\t! (u)int16/8 -> int32\n", },

{ SCONV,	INAREG,
	SAREG,	T64|TINT|TSHORT|TCHAR,
	SAREG,	TUNSIGNED,
		0,	RLEFT,
		"	srl AL, 0,A1	\t\t! int32/16/8 -> uint32\n", },

{ SCONV,	INAREG,
	SAREG,	TUSHORT|TUCHAR,
	SAREG,	TUNSIGNED,
		0,	RLEFT,
		"	              	\t\t! uint16/8 -> uint32\n", },

{ SCONV,	INBREG,
	SBREG,	TINT|TUNSIGNED,
	SBREG,	TFLOAT,
		NBREG|NASL,	RESC1,
		"	fitos AL,A1         \t\t! (u)int32 -> float\n", },

{ SCONV,	INBREG,
	SBREG,	T64,
	SBREG,	TFLOAT,
		NBREG|NASL,	RESC1,
		"	fxtos AL,A1         \t\t! (u)int64 -> float\n", },

{ SCONV,	INCREG,
	SCREG,	TINT|TUNSIGNED,
	SCREG,	TDOUBLE,
		NCREG|NASL,	RESC1,
		"	fitod AL,A1         \t\t! (u)int32 -> double\n", },

{ SCONV,	INCREG,
	SCREG,	T64,
	SCREG,	TDOUBLE,
		NCREG|NASL,	RESC1,
		"	fxtod AL,A1         \t\t! (u)int64 -> double\n", },


/* Floating-point conversions must be stored and loaded. */

{ SCONV, 	INAREG,
	SOREG, 	TFLOAT,
	SAREG,	TINT,
		NAREG|(2*NBREG),	RESC1,
		" 	ld [AL],A2    \t\t! float -> int32\n"
		"	nop\n"
		"	fmovs A2,A3\n"
		"	fstoi A2,A2\n"
		"	st A2,[AL]\n"
		"	nop\n"
		"	ld [AL],A1\n"
		"	nop\n"
		"	st A3,[AL]\n"
		"	nop\n", },

{ SCONV, 	INAREG,
	SOREG, 	TDOUBLE,
	SAREG,	TINT,
		NAREG|(2*NCREG),	RESC1,
		" 	ld [AL],A2    \t\t! double -> int32\n"
		"	nop\n"
		"	fmovd A2,A3\n"
		"	fdtoi A2,A2\n"
		"	std A2,[AL]\n"
		"	nop\n"
		"	ldd [AL],A1\n"
		"	nop\n"
		"	std A3,[AL]\n"
		"	nop\n", },

{ SCONV,	INBREG,
	SOREG,	T64|TUNSIGNED,
	SBREG,	TFLOAT,
		NBREG,	RESC1,
		"	ld [AL],A1	\t\t! int64 -> float\n"
		"	fxtos A1,A1\n", },

{ SCONV,	INBREG,
	SOREG,	TINT|TSHORT|TCHAR,
	SBREG,	TFLOAT,
		NBREG,	RESC1,
		"	ld [AL],A1	\t\t! int32/16/8 -> float\n"
		"	fitos A1,A1\n", }, // XXX need 'lds', 'ldh', etc

{ SCONV,	INCREG,
	SOREG,	T64|TUNSIGNED,
	SCREG,	TDOUBLE,
		NCREG,	RESC1,
		"	ldd [AL],A1	\t\t! (u)int64 -> double\n"
		"	fxtod A1,A1\n", },

{ SCONV,	INCREG,
	SOREG,	TINT|TSHORT|TCHAR,
	SCREG,	TDOUBLE,
		NCREG,	RESC1,
		"	ld [AL],A1	\t\t! int32/16/8 -> double\n"
		"	fitod A1,A1\n", }, // XXX need 'lds' 'ldh' 'ld', etc.

{ SCONV,	INBREG,
	SCREG,	TDOUBLE,
	SBREG,	TFLOAT,
		NBREG,	RESC1,
		"	fdtos AL,A1 	\t\t! double -> float\n",},

{ SCONV,	INCREG,
	SBREG,	TFLOAT,
	SCREG,	TDOUBLE,
		NCREG,	RESC1,
		"	fstod AL,A1 	\t\t! float -> double\n",},

{ SCONV,    INAREG,
	SBREG,  TFLOAT,
	SAREG,  TINT,
		NAREG|NBREG,    RESC1,
		"	fstoi AL,A2     \t\t! float -> int\n"
		"	st A2,[%fp+2047]\n"
		"	nop\n"
		"	ld [%fp+2047],A1\n"
		"	nop\n",},

{ SCONV,    INAREG,
	SCREG,  TDOUBLE,
	SAREG,  TINT,
		NAREG|NCREG,    RESC1,
		"	fdtoi AL,A2     \t\t! double -> int\n"
		"	st A2,[%fp+2047]\n"
		"	nop\n"
		"	ld [%fp+2047],A1\n"
        "	nop\n",},


/* Multiplication and division */

{ MUL,	INAREG,
	SAREG,	TANY,
	SAREG,	TANY,
		NAREG|NASR|NASL,	RESC1,
		"	mulx AL,AR,A1		! multiply\n", },

{ MUL,	INBREG,
	SBREG,	TFLOAT,
	SBREG,	TFLOAT,
		NBREG|NBSR|NBSL,	RESC1,
		"	fmuls AL,AR,A1		! multiply float\n", },

{ MUL,	INCREG,
	SCREG,	TDOUBLE,
	SCREG,	TDOUBLE,
		NCREG|NCSR|NCSL,	RESC1,
		"	fmuld AL,AR,A1		! multiply double\n", },

{ DIV,	INAREG,
	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
		NAREG|NASR|NASL,	RESC1,
		"	udivx AL,AR,A1		! unsigned division\n", },

{ DIV,	INAREG,
	SAREG,	TINT|TSHORT|TCHAR|TS64,
	SAREG,	TINT|TSHORT|TCHAR|TS64,
		NAREG|NASR|NASL,	RESC1,
		"	sdivx AL,AR,A1		! signed division\n", },

{ DIV,	INBREG,
	SBREG,	TFLOAT,
	SBREG,	TFLOAT,
		NBREG|NBSR|NBSL,	RESC1,
		"	fdivs AL,AR,A1		! divide float\n", },

{ DIV,	INCREG,
	SCREG,	TDOUBLE,
	SCREG,	TDOUBLE,
		NCREG|NCSR|NCSL,	RESC1,
		"	fdivd AL,AR,A1		! divide double\n", },

{ MOD,	INAREG,
	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
	SAREG,	TUNSIGNED|TUSHORT|TUCHAR|TU64,
		NAREG, RESC1,
		"	udivx AL,AR,A1		! unsigned modulo\n"
		"	mulx A1,AR,A1\n"
		"	sub AL,A1,A1\n", },

{ MOD,	INAREG,
	SAREG,	TINT|TSHORT|TCHAR|TS64,
	SAREG,	TINT|TSHORT|TCHAR|TS64,
		NAREG, RESC1,
		"	sdivx AL,AR,A1		! signed modulo\n"
		"	mulx A1,AR,A1\n"
		"	sub AL,A1,A1\n", },

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

{ PLUS,	INBREG,
	SBREG,	TFLOAT,
	SBREG,	TFLOAT,
		NBREG|NBSL,	RESC1,
      		"	fadds AL,AR,A1\n", },

{ PLUS,	INCREG,
	SCREG,	TDOUBLE,
	SCREG,	TDOUBLE,
		NCREG|NCSL,	RESC1,
      		"	faddd AL,AR,A1\n", },

{ PLUS,	INAREG,
	SAREG,	TANY,
	SCON,	TANY,
		(3*NAREG),	RESC1,
		"ZA", },

{ MINUS,	INAREG,
	SAREG,	TANY,
	SAREG,	TANY,
		NAREG|NASL,	RESC1,
		"	sub AL,AR,A1\n", },

{ MINUS,	INBREG,
	SBREG,	TANY,
	SBREG,	TANY,
		NBREG|NBSL|NBSR,	RESC1,
      		"	fsubs AL,AR,A1\n", },

{ MINUS,	INCREG,
	SCREG,	TANY,
	SCREG,	TANY,
		NCREG|NCSL|NBSR,	RESC1,
      		"	fsubd AL,AR,A1\n", },

{ MINUS,	INAREG,
	SAREG,	TANY,
	SCON,	TANY,
		(3*NAREG),	RESC1,
		"ZB", },

{ UMINUS,	INAREG,
	SAREG,	TANY,
	SANY,	TANY,
		NAREG|NASL,	RESC1,
		"	sub %g0,AL,A1\n", },

{ UMINUS,	INBREG,
	SBREG,	TANY,
	SANY,	TANY,
		NBREG|NBSL,	RESC1,
		"	fsubs %g0,AL,A1\n", },

{ UMINUS,	INCREG,
	SCREG,	TANY,
	SANY,	TANY,
		NCREG|NCSL,	RESC1,
		"	fsubd %g0,AL,A1\n", },

/* Shifts */

{ RS,	INAREG,
	SAREG,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG|SCON,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL,	RESC1,
		"	srl AL,AR,A1			! shift right\n", },

{ RS,	INAREG,
	SAREG,	T64,
	SAREG|SCON,	T64|TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL,	RESC1,
		"	srlx AL,AR,A1			! shift right\n", },

{ LS,	INAREG,
	SAREG,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
	SAREG|SCON,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL,	RESC1,
		"	sll AL,AR,A1			! shift left\n", },

{ LS,	INAREG,
	SAREG,	T64,
	SAREG|SCON,	TINT|TUNSIGNED|TSHORT|TUSHORT|TCHAR|TUCHAR,
		NAREG|NASL,	RESC1,
		"	sllx AL,AR,A1			! shift left\n", },

{ COMPL,	INAREG,
	SAREG,	TANY,
	SANY,	TANY,
		NAREG|NASL,	RESC1,
		"	not AL,A1			! complement\n", },

/* Assignments */

{ ASSIGN,	FOREFF|INAREG,			/* FIXME: Remove [,] here and add them in adrput instead. */
	SAREG|SOREG,	TINT|TUNSIGNED,
	SAREG,	TINT|TUNSIGNED,
		0,	RDEST,
		"	stw AR,[AL]		! store (u)int32\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INAREG,
	SOREG,	TSHORT|TUSHORT,
	SAREG,	TSHORT|TUSHORT,
		0,	RDEST,
        	"	sth AR,[AL]		! store (u)int16\n"
		"	nop\n", },	

{ ASSIGN,	FOREFF|INAREG,
	SOREG,	TCHAR|TUCHAR,
	SAREG,	TCHAR|TUCHAR,
		0,	RDEST,
        	"	stb AR,[AL]		! store (u)int8\n"
		"	nop\n", },	

{ ASSIGN,	FOREFF|INAREG,
	SOREG,	T64,
	SAREG,	T64,
		0,	RDEST,
		"	stx AR,[AL] 		! store (u)int64\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INBREG,
	SOREG,	TFLOAT,
	SBREG,	TFLOAT,
		0,	RDEST,
		"	st AR,[AL] 		! store float\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INBREG,
	SOREG,	TINT,
	SBREG,	TINT,
		0,	RDEST,
		"	st AR,[AL] 		! store int from fp address\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INCREG,
	SOREG,	TDOUBLE,
	SCREG,	TDOUBLE,
		0,	RDEST,
		"	std AR,[AL] 		! store double\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INCREG,
	SOREG,	TINT,
	SCREG,	TINT,
		0,	RDEST,
		"	st AR,[AL] 		! store int from fp address\n"
		"	nop\n", },


{ ASSIGN,	FOREFF|INAREG,
	SNAME,	TINT|TUNSIGNED,
	SAREG,	TINT|TUNSIGNED,
		NAREG,	RDEST,
		"	sethi %h44(AL),A1	\t! store (u)int32 into sname\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	stw AR,[A1+%l44(AL)]\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INAREG,
	SNAME,	TSHORT|TUSHORT,
	SAREG,	TSHORT|TUSHORT,
		NAREG,	RDEST,
		"	sethi %h44(AL),A1	\t! store (u)int16 into sname\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	sth AR,[A1+%l44(AL)]\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INAREG,
	SNAME,	TCHAR|TUCHAR,
	SAREG,	TCHAR|TUCHAR,
		NAREG,	RDEST,
		"	sethi %h44(AL),A1	\t! store (u)int8 into sname\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	stb AR,[A1+%l44(AL)]\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INAREG,
	SNAME,	T64,
	SAREG,	T64,
		NAREG,	RDEST,
		"	sethi %h44(AL),A1	\t! store (u)int64 into sname\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	stx AR,[A1+%l44(AL)]\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INBREG,
	SNAME,	TFLOAT|TINT,
	SBREG,	TFLOAT|TINT,
		NAREG,	RDEST,
		"	sethi %h44(AL),A1	\t! store float into sname\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	st AR,[A1+%l44(AL)]\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INCREG,
	SNAME,	TDOUBLE,
	SCREG,	TDOUBLE,
		NAREG,	RDEST,
		"	sethi %h44(AL),A1	\t! store double into sname\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	std AR,[A1+%l44(AL)]\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INCREG,
	SNAME,	TINT,
	SCREG,	TINT,
		NAREG,	RDEST,
		"	sethi %h44(AL),A1	\t! store int into sname\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	st AR,[A1+%l44(AL)]\n"
		"	nop\n", },

{ ASSIGN,	FOREFF|INAREG,
	SAREG,	TANY,
	SAREG,	TANY,
		0,	RDEST,
		"	mov AR,AL			! register move\n", },

{ ASSIGN,	FOREFF|INBREG,
	SBREG,	TANY,
	SBREG,	TANY,
		0,	RDEST,
		"	fmovs AR,AL			! move float\n", },

{ ASSIGN,	FOREFF|INCREG,
	SCREG,	TANY,
	SCREG,	TANY,
		0,	RDEST,
		"	fmovd AR,AL			! move double\n", },

/* Structure assignment. */

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

/* Comparisons. */

{ EQ,	FORCC,
        SAREG,	TANY,
        SAREG,	TANY,
                0,      RESCC,
		"	cmp AL,AR			! eq\n"
		"	be LC\n"
		"	nop\n", },

{ NE,	FORCC,
        SAREG,	TANY,
        SAREG,	TANY,
                0,      RESCC,
		"	cmp AL,AR			! ne\n"
                "	bne LC\n"
		"	nop\n", },

{ OPLOG,	FORCC,
	SAREG,	TANY,
	SZERO,	TANY,
		0,	RESCC,
		"	O AL,LC\n"
		"	nop\n", },

{ OPLOG,	FORCC,
	SAREG,	TANY,
	SAREG,	TANY,
		NAREG|NASL,	RESCC,
		"	sub AL,AR,A1			! oplog\n"
		"	O A1,LC\n"
		"	nop\n", },

{ OPLOG,	FORCC,
	SAREG,	TANY,
	SCCON,	TANY,
		NAREG|NASL,	RESCC,
		"	sub AL,AR,A1			! oplog sccon\n"
		"	O A1,LC\n"
		"	nop\n", },

{ OPLOG,	FORCC,
	SBREG,	TFLOAT,
	SBREG,	TFLOAT,
		NBREG, RESCC,
		"	fcmps AL,AR			! oplog float\n"
		"	ZF LC\n", },

{ OPLOG,	FORCC,
	SOREG,	TFLOAT,
	SBREG,	TFLOAT,
		NBREG, RESCC,
		"	ld [AL], A1    			! oplog float oreg\n"
		"	nop\n"
		"	fcmps A1,AR\n"
		"	ZF LC\n", },

{ OPLOG,	FORCC,
	SCREG,	TDOUBLE,
	SCREG,	TDOUBLE,
		NCREG, RESCC,
		"	fcmpd AL,AR			! oplog double\n"
		"	ZF LC\n", },

{ OPLOG,	FORCC,
	SOREG,	TDOUBLE,
	SCREG,	TDOUBLE,
		NCREG, RESCC,
		"	ldd [AL], A1   			! oplog double oreg\n"
		"	nop\n"
		"	fcmpd A1,AR\n"
		"	ZF LC\n", },


/* Load constants to register. */

{ OPLTYPE,	INAREG,
	SCON,		TANY,
	SNAME,		T64,
		NAREG,	RESC1,
		"	sethi %h44(AL),A1\t	! load const (u)int64 to reg\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	ldx [A1+%l44(AL)],A1\n"
		"	nop\n", },
{ OPLTYPE,	INAREG,
	SCON,		TANY,
	SNAME,		TINT,
		NAREG,	RESC1,
		"	sethi %h44(AL),A1\t	! load const int32 to reg\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	ldsw [A1+%l44(AL)],A1\n"
		"	nop\n", },

{ OPLTYPE,	INAREG,
	SCON,		TANY,
	SNAME,		TUNSIGNED,
		NAREG,	RESC1,
		"	sethi %h44(AL),A1\t! load const uint32 to reg\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	lduw [A1+%l44(AL)],A1\n"
		"	nop\n", },
{ OPLTYPE,	INAREG,
	SCON,		TANY,
	SNAME,		TSHORT,
		NAREG,	RESC1,
		"	sethi %h44(AL),A1\t! load const int16 to reg\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	ldsh [A1+%l44(AL)],A1\n"
		"	nop\n", },
{ OPLTYPE,	INAREG,
	SCON,		TANY,
	SNAME,		TUSHORT,
		NAREG,	RESC1,
		"	sethi %h44(AL),A1\t	! load const uint16 to reg\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	lduh [A1+%l44(AL)],A1\n"
		"	nop\n", },
{ OPLTYPE,	INAREG,
	SCON,		TANY,
	SNAME,		TCHAR,
		NAREG,	RESC1,
		"	sethi %h44(AL),A1\t\t! load const int8 to reg\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	ldsb [A1+%l44(AL)],A1\n"
		"	nop\n", },
{ OPLTYPE,	INAREG,
	SCON,		TANY,
	SNAME,		TUCHAR,
		NAREG,	RESC1,
		"	sethi %h44(AL),A1\t! load const uint8 to reg\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	ldub [A1+%l44(AL)],A1\n"
		"	nop\n", },

{ OPLTYPE,	INBREG,
	SBREG,	TANY,
	SNAME,	TANY,
		NAREG|NBREG,	RESC2,
		"	sethi %h44(AL),A1\t\t! load const to fp reg\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	ld [A1+%l44(AL)],A2\n"
		"	nop\n", },

{ OPLTYPE,	INCREG,
	SCREG,	TANY,
	SNAME,	TANY,
		NAREG|NCREG,	RESC2,
		"	sethi %h44(AL),A1\t\t! load const to fp reg\n"
		"	or A1,%m44(AL),A1\n"
		"	sllx A1,12,A1\n"
		"	ldd [A1+%l44(AL)],A2\n"
		"	nop\n", },

{ OPLTYPE,	INAREG,
	SANY,	TANY,
	SCON,	TANY,
		(2*NAREG),	RESC1,
		"ZC" },

/* Convert LTYPE to reg. */

{ OPLTYPE,	INAREG,
	SAREG,	TANY,
	SOREG,	TCHAR,
		NAREG,	RESC1,
		"	ldsb [AL],A1		! load int8 to reg\n"
		"	nop\n", },

{ OPLTYPE,	INAREG,
	SAREG,	TANY,
	SOREG,	TUCHAR,
		NAREG,	RESC1,
		"	ldub [AL],A1		! load uint8 to reg\n"
		"	nop\n", },

{ OPLTYPE,	INAREG,
	SAREG,	TANY,
	SOREG,	TSHORT,
		NAREG,	RESC1,
		"	ldsh [AL],A1		! load int16 to reg\n"
		"	nop\n", },

{ OPLTYPE,	INAREG,
	SAREG,	TANY,
	SOREG,	TUSHORT,
		NAREG,	RESC1,
		"	lduh [AL],A1		! load uint16 to reg\n"
		"	nop\n", },

{ OPLTYPE,	INAREG,
	SAREG,	TANY,
	SOREG,	TINT,
		NAREG,	RESC1,
		"	ldsw [AL],A1		! load int32 to reg\n"
		"	nop\n", },

{ OPLTYPE,	INAREG,
	SAREG,	TANY,
	SOREG,	TUNSIGNED,
		NAREG,	RESC1,
		"	lduw [AL],A1		! load uint32 to reg\n"
		"	nop\n", },

{ OPLTYPE,	INAREG,
	SAREG,	TANY,
	SOREG,	T64,
		NAREG,	RESC1,
		"	ldx [AL],A1		! load (u)int64 to reg\n"
		"	nop\n", },

{ OPLTYPE,	INAREG,
	SANY,	TANY,
	SZERO,	TANY,
		NAREG,	RESC1,
		"	mov \%g0,A1\t		! load 0 to reg\n", },

{ OPLTYPE,	INBREG,
	SBREG,	TFLOAT,
	SOREG,	TFLOAT,
		NBREG,	RESC1,
		"	ld [AL],A1  		! load float to reg\n"
		"	nop\n", },

{ OPLTYPE,	INCREG,
	SCREG,	TDOUBLE,
	SOREG,	TDOUBLE,
		NCREG,	RESC1,
		"	ldd [AL],A1  		! load double to reg\n"
		"	nop\n", },

/* Jumps. */

{ GOTO, 	FOREFF,
	SCON,	TANY,
	SANY,	TANY,
		0,	RNOP,
		"	call LL		 	! goto LL\n"
		"	nop\n", },

{ UCALL,	FOREFF,
	SCON,		TANY,
	SANY,		TANY,
		0,	0,
		"	call CL			! void CL()\n"
		"	nop\n", },

{ UCALL,         INAREG,
        SCON,		TANY,
        SAREG,          TANY,
                NAREG,     RESC1,
		"	call CL			! = CL()\n"
		" 	nop\n", },

{ CALL,		FOREFF,
	SCON,		TANY,
	SANY,		TANY,
		0,	0,
		"	call CL			! void CL(constant)\n"
		"	nop\n", },

{ CALL,		INAREG,
	SCON,		TANY,
	SAREG,		TANY,
		NAREG,		RESC1,
		"	call CL			! = CL(constant)\n"
		"	nop\n", },

{ CALL,		INBREG,
	SCON,		TANY,
	SBREG,		TFLOAT,
		NBREG,		RESC1,
		"	call CL			! = CL(constant)\n"
		"	nop\n", },

{ CALL,		INCREG,
	SCON,		TANY,
	SCREG,		TDOUBLE,
		NCREG,		RESC1,
		"	call CL			! = CL(constant)\n"
		"	nop\n", },

{ CALL,         INAREG,
        SAREG,		TANY,
        SAREG,		TANY,
                NAREG,     RESC1,
		"	call AL			! = AL(args)\n"
		"	nop\n", },

{ CALL,		FOREFF,
	SAREG,		TANY,
	SANY,		TANY,
		0,		0,
		"	call AL			! void AL(args)\n"
		"	nop\n", },

{ UCALL,	FOREFF,
	SAREG,		TANY,
	SANY,		TANY,
		0,	0,
		"	call AL			! (*AL)()\n"
		"	nop\n", },

{ UCALL,	INAREG,
	SAREG,		TANY,
	SAREG,		TANY,
		NAREG,		RESC1,
		"	call AL			! = (*AL)()\n"
		"	nop\n", },

{ CALL,		INAREG,
	SAREG,		TANY,
	SAREG,		TANY,
		NAREG,		RESC1,
		"	call AL			! = (*AL)(args)\n"
		"	nop\n", },

/* Function arguments. */

{ FUNARG,       FOREFF,
        SAREG,  T64,
        SANY,   TANY,
                0,      0,
                "	stx AL,[%sp+AR]   	\t! save func arg to stack\n"
		"	nop\n", },

{ FUNARG,       FOREFF,
        SAREG,  TINT|TUNSIGNED,
        SANY,   TANY,
                0,      0,
                "	stw AL,[%sp+AR]   	\t! save func arg to stack\n"
		"	nop\n", },

{ FUNARG,       FOREFF,
        SAREG,  TSHORT|TUSHORT,
        SANY,   TANY,
                0,      0,
                "	sth AL,[%sp+AR]   	\t! save func arg to stack\n"
		"	nop\n", },

{ FUNARG,       FOREFF,
        SAREG,  TCHAR|TUCHAR,
        SANY,   TANY,
                0,      0,
                "	stb AL,[%sp+AR]  	\t! save func arg to stack\n"
		"	nop\n", },

{ FUNARG,       FOREFF,
        SBREG,  TFLOAT,
        SANY,   TANY,
                0,      0,
                "	st AL,[%sp+AR]  	\t! save func arg to stack\n"
		"	nop\n", },

{ FUNARG,       FOREFF,
        SCREG,  TDOUBLE,
        SANY,   TANY,
                0,      0,
                "	std AL,[%sp+AR]  	\t! save func arg to stack\n"
		"	nop\n", },


/* Indirection. */

{ OPSIMP,	INAREG,
	SAREG,	TANY,
	SAREG,	TANY,
		NAREG|NASR|NASL,	RESC1,
		"	O AL,AR,A1\n", },

{ UMUL, INAREG,
	SAREG,	T64,
	SOREG,	T64,
		NAREG,		RESC1,
		"	ldx [AL],A1		! (u)int64 load\n"
		"	nop\n", },
{ UMUL, INAREG,
	SAREG,	TINT,
	SOREG,	TINT,
		NAREG,		RESC1,
		"	ldsw [AL],A1		! int32 load\n"
		"	nop\n", },
{ UMUL, INAREG,
	SAREG,	TUNSIGNED,
	SOREG,	TUNSIGNED,
		NAREG,		RESC1,
		"	lduw [AL],A1		! uint32 load\n"
		"	nop\n", },
{ UMUL, INAREG,
	SAREG,	TCHAR,
	SOREG,	TCHAR,
		NAREG,		RESC1,
		"	ldsb [AL],A1		! int8 load\n"
		"	nop\n", },
{ UMUL, INAREG,
	SAREG,	TUCHAR,
	SOREG,	TUCHAR,
		NAREG,		RESC1,
		"	ldub [AL],A1		! uint8 load\n"
		"	nop\n", },
{ UMUL, INAREG,
	SAREG,	TSHORT,
	SOREG,	TSHORT,
		NAREG,		RESC1,
		"	ldsh [AL],A1		! int16 load\n"
		"	nop\n", },
{ UMUL, INAREG,
	SAREG,	TUSHORT,
	SOREG,	TUSHORT,
		NAREG,		RESC1,
		"	lduh [AL],A1		! uint16 load\n"
		"	nop\n", },

{ UMUL, INBREG,
	SAREG,	TFLOAT,
	SOREG,	TFLOAT,
		NBREG,		RESC1,
		"	ld [AL],A1		! load float\n"
		"	nop\n", },

{ UMUL, INCREG,
	SAREG,	TDOUBLE,
	SOREG,	TDOUBLE,
		NCREG,		RESC1,
		"	ldd [AL],A1		! load double\n"
		"	nop\n", },

{ FREE,FREE,FREE,FREE,FREE,FREE,FREE,FREE, "ERR: printing free op\n" },

};

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