1/*	Id: table.c,v 1.5 2014/12/27 21:18:19 ragge Exp 	*/
2/*	$NetBSD: table.c,v 1.1.1.1 2016/02/09 20:28:39 plunky Exp $	*/
3/*
4 * Copyright (c) 2003 Anders Magnusson (ragge@ludd.luth.se).
5 * Copyright (c) 2014 Alan Cox (alan@lxorguk.ukuu.org.uk).
6 * All rights reserved.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 *    derived from this software without specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31
32# include "pass2.h"
33
34/*
35 * TODO
36 *  -	clean up TLL usage so we are ready for 64bit longlong (T32 and T64?)
37 *  -	Clean up all the SHINT SHCH etc oddities for clarity
38 *  -	Better optimisation of constant multiply/divide etc on 8086
39 *  -	some how lose the final bogus sp adjust we generate
40 *  -	write helper lib for long and longlong ops
41 *  -	add an E class and virtual 4 register longlong model
42 *  -   bcc fastcall format
43 *
44 *  -	How to do configurable code-gen
45 *	For 80186 we want to use the better shifts, push constant, mul/div
46 *	features and enter/leave
47 *	For 80286 it's not clear we need to do anything for real mode. However
48 *	for large data/huge models protected mode means minimising ds/es
49 *	reloads with the same data
50 *	With 80386 there is lots more - but who wants 80386/16bit optimised
51 *	code !
52 *
53 *  -	FPU has not been tackled. FPU/FPU should be fine (barring the odd
54 *	gnu style instruction forms), but FPU/other is quite different
55 *	because the 4 byte conversions are now long not int and two register
56 *	while 8 byte longlong ones are going to need some gymnastics once
57 *	we support the virtual 64bit registers
58 *
59 *  -	FPU/noFPU option. Assuming FPU present on 8086 is a bit obnoxious
60 *	as a default. Need to be able to generate entirely soft-float calls.
61 *
62 *  -   We can't currently do various conversions we'd like to have, notably
63 *	things like  "and ax, $ff"  to convert AL into AX from uchar to uint
64 *	(that needs core changes and also allocator changes to try and avoid
65 *	high bits being occupied by other users)
66 *
67 *  -	Shifts should be optimised for 8/16/24/32 cases
68 *
69 *  -	No attempt is made to deal with larger models than tiny
70 *
71 *	small mode should work (just keep constant data in data segments)
72 *
73 *	large code/small data should be fine-ish. Really that implies 32bit
74 *	void * but for most uses you want 32bit only to be function pointers
75 *	even if its not to spec. Function entry/exit needs to allow for the
76 *	extra 2 bytes, call becomes call far, call ptr becomes a bit trickier
77 *	but not a lot. Not that ld86 can link large model yet!
78 *
79 *	large data is much harder because an address is 32bit, half of which
80 *	needs to keep getting stuck into a segment register. However we often
81 *	(usually) work with multiple pointers to the same object. Any given
82 *	object has a single segment so we will badly need optimisations to
83 *	"share" segment data and avoid lots of duplicate register uses and
84 *	mov es, foo statements.
85 *
86 *	huge model makes all pointers 32bit and all objects 32bit sized. That
87 *	probably makes the sharing es issue go away somewhat, but raises the
88 *	ugly problems of pointer normalisation (00:10 is the same as 01:00
89 *	which b*ggers up comparisons royally) and also protected mode where
90 *	your segment jump as you go over 64K boundaries is different. On the
91 *	bright side huge model performance will suck whatever the compiler
92 *	does.
93 *
94 */
95
96/* 64bit values */
97# define T64 TLONGLONG|TULONGLONG
98/* 32bit values */
99# define T32 TLONG|TULONG
100/* 16bit values */
101# define T16 TINT|TUNSIGNED
102/* 16bit values including pointers */
103# define TP16 TINT|TUNSIGNED|TPOINT
104/* 8bit values */
105# define T8  TCHAR|TUCHAR
106
107#define	 SHINT	SAREG	/* short and int */
108#define	 ININT	INAREG
109#define	 SHCH	SBREG	/* shape for char */
110#define	 INCH	INBREG
111#define	 SHLL	SCREG	/* shape for long long FIXME */
112#define	 INLL	INCREG
113#define	 SHL	SCREG	/* shape for long*/
114#define	 INL	INCREG
115#define	 SHFL	SDREG	/* shape for float/double */
116#define	 INFL	INDREG	/* shape for float/double */
117
118struct optab table[] = {
119/* First entry must be an empty entry */
120{ -1, FOREFF, SANY, TANY, SANY, TANY, 0, 0, "", },
121
122/* PCONVs are usually not necessary */
123{ PCONV,	INAREG,
124	SAREG,	T16|TPOINT,
125	SAREG,	T16|TPOINT,
126		0,	RLEFT,
127		"", },
128
129/*
130 * A bunch conversions of integral<->integral types
131 * There are lots of them, first in table conversions to itself
132 * and then conversions from each type to the others.
133 */
134
135/* itself to itself, including pointers */
136
137/* convert (u)char to (u)char. */
138{ SCONV,	INCH,
139		SHCH,			T8,
140		SHCH,			T8,
141		0,			RLEFT,
142		"", },
143
144/* convert pointers to int. */
145{ SCONV,	ININT,
146		SHINT,			TPOINT|T16,
147		SANY,			T16,
148		0,			RLEFT,
149		"", },
150
151/* convert (u)long to (u)long. */
152{ SCONV,	INL,
153		SHL,			T32,
154		SHL,			T32,
155		0,			RLEFT,
156		"", },
157
158/* convert (u)long and (u)longlong to (u)longlong. */
159{ SCONV,	INLL,
160		SHLL,			T64,
161		SHLL,			T64,
162		0,			RLEFT,
163		"", },
164
165/* convert between float/double/long double. */
166{ SCONV,	INFL,
167	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
168	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
169		0,			RLEFT,
170		"ZI", },
171
172/* convert pointers to pointers. */
173{ SCONV,	ININT,
174		SHINT,			TPOINT,
175		SANY,			TPOINT,
176		0,			RLEFT,
177		"", },
178
179/* char to something */
180
181/* convert char to 16bit types. */
182
183/* 8086: Only as op on AL,AX */
184{ SCONV,	ININT,
185		SBREG,			TCHAR,
186		SAREG,			T16,
187		NSPECIAL|NAREG|NASL,	RESC1,
188		"	cbw\n", },
189
190/* convert unsigned char to 16bit types.
191   We can do this one with any register */
192{ SCONV,	ININT,
193		SHCH|SOREG|SNAME,	TUCHAR,
194		SAREG,			T16,
195		NSPECIAL|NAREG,		RESC1,
196		"ZT", },
197
198/* convert char to (u)long
199   8086 can only do cbw/cwd on AX and AX:DX pair */
200{ SCONV,	INL,
201		SHCH,			TCHAR,
202		SCREG,			T32,
203		NSPECIAL|NCREG|NCSL,	RESC1,
204		"; using AL\n	cbw\n	cwd\n", },
205
206/* convert unsigned char to (u)long
207   we can do this with any register */
208{ SCONV,	INL,
209		SHCH|SOREG|SNAME,	TUCHAR,
210		SANY,			T32,
211		NCREG|NCSL,		RESC1,
212		"ZT	xor U1,U1\n", },
213
214/* convert char (in register) to double XXX - use NTEMP */
215/* FIXME : need NSPECIAL to force into AL
216	check AX:DX right way around ! */
217{ SCONV,	INFL,
218		SHCH|SOREG|SNAME,	TCHAR,
219		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
220		NAREG|NASL|NDREG,	RESC2,
221		"	cbw\n	cwd\n	push ax\n	push dx\n"
222		"	fildl [sp]\n	add sp, #4\n", },
223
224/* convert (u)char (in register) to double XXX - use NTEMP */
225/* FIXME : needs to use ZT to get sizes right, need a register
226   from somewhere to put 0 on the stack for the high bits */
227{ SCONV,	INFL,
228		SHCH|SOREG|SNAME,	TUCHAR,
229		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
230		NAREG|NASL|NDREG,	RESC2,
231		"	mov A1 AL\n	and A1, #0xff\n	push A1\npush #0\n"
232		"	fildl [sp]\n	add sp,#4\n", },
233
234/* 16bit to something */
235
236/* convert 16bit to 16bit. */
237{ SCONV,	INAREG,
238		SAREG,			T16,
239		SAREG,			T16,
240		0,			RLEFT,
241		"", },
242
243/* convert 16bit (in memory) to char */
244/* NOTE: uses new 'ZP' type for 'untyped right' */
245{ SCONV,	INCH,
246		SNAME|SOREG,		TP16,
247		SHCH,			T8,
248		NBREG|NBSL,		RESC1,
249		"	mov A1,ZP AL\n", },
250
251/* convert 16bit (in reg) to char. Done as a special but basically a mov */
252{ SCONV,	INCH,
253		SAREG|SNAME|SOREG,	TP16,
254		SHCH,			T8,
255		NSPECIAL|NBREG|NBSL,	RESC1,
256		"ZM", },
257
258/* convert short/int to (u)long
259   This must go via AX so we can use cwd */
260{ SCONV,	INL,
261		SAREG,			TINT,
262		SHL,			T32,
263		NSPECIAL|NCREG|NCSL,	RESC1,
264		"	mov A1, AL\n	cwd\n", },
265
266/* convert unsigned short/int to (u)long
267   Any pair will do. Note currently the compiler can't optimise
268   out the reg->reg move involved */
269{ SCONV,	INLL,
270		SAREG|SOREG|SNAME,	TUNSIGNED|TPOINT,
271		SHL,			T32,
272		NCREG|NCSL,		RESC1,
273		"	mov A1,AL\n	xor U1,U1\n", },
274
275/* convert short/int (in memory) to float/double */
276{ SCONV,	INFL,
277		SOREG|SNAME,		TINT,
278		SDREG,			TLDOUBLE|TDOUBLE|TFLOAT,
279		NDREG,			RESC1,
280		"	fild AL\n", },
281
282/* convert short/int (in register) to float/double */
283{ SCONV,	INFL,
284		SAREG,			TINT,
285		SDREG,			TLDOUBLE|TDOUBLE|TFLOAT,
286		NTEMP|NDREG,		RESC1,
287		"	push AL\n	fild [sp]\n"
288		"	inc sp\n	inc sp\n", },
289
290/* convert unsigned short/int/ptr to double XXX - use NTEMP */
291/* FIXME: need to force this via AX so we can cwd, fix stack setup to
292   push both ax.dx*/
293{ SCONV,	INFL,
294		SAREG|SOREG|SNAME,	TUNSIGNED|TPOINT,
295		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
296		NAREG|NASL|NDREG|NTEMP,	RESC2,
297		"	cwd\n		push ax\n"
298		"	fild [sp]\n	inc sp\n"
299		"	inc sp\n", },
300
301/* long to something */
302
303/* convert (u)long to (u)char (mem->reg) */
304{ SCONV,	INCH,
305		SOREG|SNAME,		T32,
306		SANY,			T8,
307		NBREG|NBSL,		RESC1,
308		"	mov A1, AL\n", },
309
310/* convert (u)long to (u)char (reg->reg, hopefully nothing) */
311{ SCONV,	INCH,
312		SHL,			T32,
313		SANY,			T8,
314		NBREG|NBSL|NTEMP,	RESC1,
315		"ZS", },
316
317/* convert (u)long to (u)short (mem->reg) */
318{ SCONV,	INAREG,
319		SOREG|SNAME,		T32,
320		SAREG,			TP16,
321		NAREG|NASL,		RESC1,
322		"	mov A1,AL\n", },
323
324/* convert (u)long to 16bit (reg->reg, hopefully nothing) */
325{ SCONV,	INAREG,
326		SHL|SOREG|SNAME,	T32,
327		SAREG,			T16,
328		NAREG|NASL|NTEMP,	RESC1,
329		"ZS", },
330
331/* FIXME: float stuff is all TODO */
332
333/* convert long long (in memory) to floating */
334{ SCONV,	INFL,
335		SOREG|SNAME,		TLONGLONG,
336		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
337		NDREG,			RESC1,
338		"	fild AL\n", },
339
340/* convert long (in register) to floating */
341{ SCONV,	INFL,
342		SHL,			TLONGLONG,
343		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
344		NTEMP|NDREG,		RESC1,
345		"	push UL\n	push AL\n"
346		"	fild [sp]\n	add sp, #8\n", },
347
348/* convert unsigned long to floating */
349{ SCONV,	INFL,
350		SCREG,			TULONGLONG,
351		SDREG,			TLDOUBLE|TDOUBLE|TFLOAT,
352		NDREG,			RESC1,
353		"ZJ", },
354
355/* float to something */
356
357#if 0 /* go via int by adding an extra sconv in clocal() */
358/* convert float/double to (u) char. XXX should use NTEMP here */
359{ SCONV,	INCH,
360		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
361		SHCH,			T16|T8,
362		NBREG,			RESC1,
363		"	sub sp,#4\n	fistpl [sp]\n	pop	A1\n	pop U1\n", },
364
365/* convert float/double to (u) int/short/char. XXX should use NTEMP here */
366{ SCONV,	INCH,
367		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
368		SHCH,			T16|T8,
369		NCREG,			RESC1,
370		"	sub sp,#4\n	fistpl (%sp)\n	pop A1\n	inc sp\n	inc sp\n", },
371#endif
372
373/* convert float/double to long XXX should use NTEMP here */
374{ SCONV,	INAREG,
375	SHFL,	TLDOUBLE|TDOUBLE|TFLOAT,
376	SAREG,	TLONG,
377		NAREG,	RESC1,
378		"	sub sp, #12\n"
379		"	fstcw sp\n"
380		"	fstcw 4[sp]\n"
381		"	mov byte ptr 1[sp], #12\n"
382		"	fldcw sp\n"
383		"	fistp 8[sp]\n"
384		"	movl A1, 8(p)\n"
385		"	fldcw 4[sp]\n"
386		"	add sp, #4\n", },
387
388/* convert float/double to unsigned long. XXX should use NTEMP here */
389{ SCONV,       INAREG,
390		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
391		SAREG,			TULONG,
392		NAREG,			RESC1,
393		"	sub sp, #16\n"
394		"	fnstcw [sp]\n"
395		"	fnstcw 4[sp]\n"
396		"	mov byte ptr 1[sp], #12\n"
397		"	fldcw [sp[\n"
398		"	fistpq 8[sp]\n"
399		"	mov word ptr 8[sp],A1\n"
400		"	mov word ptr 10[sp],U1\n"
401		"	fldcw 4[sp]\n"
402		"	add sp, #16\n", },
403
404/* convert float/double (in register) to long long */
405{ SCONV,	INLL,
406		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
407		SHLL,			TLONGLONG,
408		NCREG,			RESC1,
409		"	sub sp, #16\n"
410		"	fnstcw [sp]\n"
411		"	fnstcw [sp]\n"
412		"	mov byte ptr 1[sp], #12\n"
413		"	fldcw [sp]\n"
414		"	fistpq 8[sp]\n"
415		"	movl 8[sp],A1\n"
416		"	movl 10[sp],U1\n"
417		/* need to put 12/14 somewhere FIXME */
418		"	fldcw 4[sp]\n"
419		"	add sp, #16\n", },
420
421/* convert float/double (in register) to unsigned long long */
422{ SCONV,	INLL,
423		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
424		SHLL,			TULONGLONG,
425		NCREG,			RESC1,
426		"	sub sp, #16\n"
427		"	fnstcw [sp]\n"
428		"	fnstcw 4[sp]\n"
429		"	mov byte ptr 1[sp], #15\n"	/* 64-bit prec */
430		"	fldcw [sp]\n"
431		"	movl $0x5f000000, 8(%sp)\n"	/* (float)(1<<63) */
432		"	fsubs 8[sp]\n"	/* keep in range of fistpq */
433		"	fistpq 8[sp]\n"
434		"	xor byte ptr 15[sp], #0x80\n"	/* addq $1>>63 to 8(%sp) */
435		"	movl A1, 8[sp]\n"
436		"	movl U1, 10[sp]\n"
437		"	fldcw 4[sp]\n"
438		"	add sp, #16\n", },
439
440
441
442/* slut sconv */
443
444/*
445 * Subroutine calls.
446 */
447
448{ UCALL,	FOREFF,
449		SCON,			TANY,
450		SANY,			TANY,
451		0,	0,
452		"	call CL\nZC", },
453
454{ CALL,		FOREFF,
455		SCON,			TANY,
456		SANY,			TANY,
457		0,	0,
458		"	call CL\nZC", },
459
460//{ UCALL,	FOREFF,
461//	SCON,	TANY,
462//	SAREG,	TP16,
463//		0,	0,
464//		"	call CL\nZC", },
465
466{ CALL,	INAREG,
467		SCON,			TANY,
468		SAREG,			TP16,
469		NAREG|NASL,		RESC1,	/* should be 0 */
470		"	call CL\nZC", },
471
472{ UCALL,	INAREG,
473		SCON,			TANY,
474		SAREG,			TP16,
475		NAREG|NASL,		RESC1,	/* should be 0 */
476		"	call CL\nZC", },
477
478{ CALL,	INBREG,
479		SCON,			TANY,
480		SBREG,			T8,
481		NBREG,			RESC1,	/* should be 0 */
482		"	call CL\nZC", },
483
484{ UCALL,	INBREG,
485		SCON,			TANY,
486		SBREG,			T8,
487		NBREG,			RESC1,	/* should be 0 */
488		"	call CL\nZC", },
489
490{ CALL,		INCREG,
491		SCON,			TANY,
492		SCREG,			TANY,
493		NCREG|NCSL,		RESC1,	/* should be 0 */
494		"	call CL\nZC", },
495
496{ UCALL,	INCREG,
497		SCON,			TANY,
498		SCREG,			TANY,
499		NCREG|NCSL,		RESC1,	/* should be 0 */
500		"	call CL\nZC", },
501
502{ CALL,	INDREG,
503		SCON,			TANY,
504		SDREG,			TANY,
505		NDREG|NDSL,		RESC1,	/* should be 0 */
506		"	call CL\nZC", },
507
508{ UCALL,	INDREG,
509		SCON,			TANY,
510		SDREG,			TANY,
511		NDREG|NDSL,		RESC1,	/* should be 0 */
512		"	call CL\nZC", },
513
514{ CALL,		FOREFF,
515		SAREG,			TANY,
516		SANY,			TANY,
517		0,	0,
518		"	call *AL\nZC", },
519
520{ UCALL,	FOREFF,
521		SAREG,			TANY,
522		SANY,			TANY,
523		0,	0,
524		"	call *AL\nZC", },
525
526{ CALL,		INAREG,
527		SAREG,			TANY,
528		SANY,			TANY,
529		NAREG|NASL,		RESC1,	/* should be 0 */
530		"	call *AL\nZC", },
531
532{ UCALL,	INAREG,
533		SAREG,			TANY,
534		SANY,			TANY,
535		NAREG|NASL,		RESC1,	/* should be 0 */
536		"	call *AL\nZC", },
537
538{ CALL,		INBREG,
539		SAREG,			TANY,
540		SANY,			TANY,
541		NBREG|NBSL,		RESC1,	/* should be 0 */
542		"	call *AL\nZC", },
543
544{ UCALL,	INBREG,
545		SAREG,			TANY,
546		SANY,			TANY,
547		NBREG|NBSL,		RESC1,	/* should be 0 */
548		"	call *AL\nZC", },
549
550{ CALL,		INCREG,
551		SAREG,			TANY,
552		SANY,			TANY,
553		NCREG|NCSL,		RESC1,	/* should be 0 */
554		"	call *AL\nZC", },
555
556{ UCALL,	INCREG,
557		SAREG,			TANY,
558		SANY,			TANY,
559		NCREG|NCSL,		RESC1,	/* should be 0 */
560		"	call *AL\nZC", },
561
562{ CALL,		INDREG,
563		SAREG,			TANY,
564		SANY,			TANY,
565		NDREG|NDSL,		RESC1,	/* should be 0 */
566		"	call *AL\nZC", },
567
568{ UCALL,	INDREG,
569		SAREG,			TANY,
570		SANY,			TANY,
571		NDREG|NDSL,		RESC1,	/* should be 0 */
572		"	call *AL\nZC", },
573
574{ STCALL,	FOREFF,
575		SCON,			TANY,
576		SANY,			TANY,
577		NAREG|NASL,	0,
578		"	call CL\nZC", },
579
580{ STCALL,	INAREG,
581		SCON,			TANY,
582		SANY,			TANY,
583		NAREG|NASL,		RESC1,	/* should be 0 */
584		"	call CL\nZC", },
585
586{ STCALL,	INAREG,
587		SNAME|SAREG,		TANY,
588		SANY,			TANY,
589		NAREG|NASL,		RESC1,	/* should be 0 */
590		"	call *AL\nZC", },
591
592/*
593 * The next rules handle all binop-style operators.
594 *
595 * 8 and 16bit we do directly, 32bit is a mix of helpers and
596 * direct operations. 64bit TODO, FPU lives in it's own little
597 * world.
598 */
599{ PLUS,		INL|FOREFF,
600		SHL,			T32,
601		SHL|SNAME|SOREG,	T32,
602		0,			RLEFT,
603		"	add AL,AR\n	adc UL,UR\n", },
604
605{ PLUS,		INL|FOREFF,
606		SHL|SNAME|SOREG,	T32,
607		SHL|SCON,		T32,
608		0,			RLEFT,
609		"	add AL,AR\n	adc UL,UR\n", },
610
611/* Special treatment for long  XXX - fix commutative check */
612{ PLUS,		INL|FOREFF,
613		SHL|SNAME|SOREG,	T32,
614		SHL,			T32,
615		0,			RRIGHT,
616		"	add AL,AR\n	adc UL,UR\n", },
617
618{ PLUS,		INFL,
619		SHFL,			TDOUBLE,
620		SNAME|SOREG,		TDOUBLE,
621		0,			RLEFT,
622		"	faddl AR\n", },
623
624{ PLUS,		INFL|FOREFF,
625		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
626		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
627		0,			RLEFT,
628		"	faddp\n", },
629
630{ PLUS,		INAREG|FOREFF,
631		SAREG|SNAME|SOREG,	TP16,
632		SONE,			TANY,
633		0,			RLEFT,
634		"	inc AL\n", },
635
636{ PLUS,		INAREG|FOREFF,
637		SAREG|SNAME|SOREG,	TP16,
638		STWO,			TANY,
639		0,			RLEFT,
640		"	inc AL\n	inc AL\n", },
641
642{ PLUS,		INCH|FOREFF,
643		SHCH|SNAME|SOREG,	T8,
644		SONE,			TANY,
645		0,			RLEFT,
646		"	inc AL\n", },
647
648{ PLUS,		INCH|FOREFF,
649		SHCH|SNAME|SOREG,	T8,
650		STWO,			TANY,
651		0,			RLEFT,
652		"	inc AL\n	inc AL\n", },
653
654{ PLUS,		INAREG,
655		SAREG,			T16,
656		SAREG,			T16,
657		NAREG|NASL|NASR,	RESC1,
658		"	lea A1, [AL+AR]\n", },
659
660{ MINUS,	INAREG|FOREFF,
661		SAREG|SNAME|SOREG,	TP16,
662		SONE,			TANY,
663		0,			RLEFT,
664		"	dec AL\n", },
665
666{ MINUS,	INAREG|FOREFF,
667		SAREG|SNAME|SOREG,	TP16,
668		STWO,			TANY,
669		0,			RLEFT,
670		"	dec AL\n	dec AL\n", },
671
672{ MINUS,	INCH|FOREFF,
673		SHCH|SNAME|SOREG,	T8,
674		SONE,			TANY,
675		0,			RLEFT,
676		"	dec AL\n", },
677
678{ MINUS,	INCH|FOREFF,
679		SHCH|SNAME|SOREG,	T8,
680		STWO,			TANY,
681		0,			RLEFT,
682		"	dec AL\n	decl AL\n", },
683
684/* address as register offset, negative */
685{ MINUS,	INLL|FOREFF,
686		SHL,			T32,
687		SHL|SNAME|SOREG,	T32,
688		0,			RLEFT,
689		"	sub AL,AR\n	sbb UL,UR\n", },
690
691{ MINUS,	INL|FOREFF,
692		SHL|SNAME|SOREG,	T32,
693		SHL|SCON,		T32,
694		0,			RLEFT,
695		"	sub AL,AR\n	sbb UL,UR\n", },
696
697{ MINUS,	INFL,
698		SHFL,			TDOUBLE,
699		SNAME|SOREG,		TDOUBLE,
700		0,			RLEFT,
701		"	fsubl AR\n", },
702
703{ MINUS,	INFL|FOREFF,
704		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
705		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
706		0,			RLEFT,
707		"	fsubZAp\n", },
708
709/* Simple r/m->reg ops */
710/* m/r |= r */
711
712{ OPSIMP,	INAREG|FOREFF|FORCC,
713		SHINT|SNAME|SOREG,	TP16,
714		SHINT,			TP16,
715		0,			RLEFT|RESCC,
716		"	Ow AL,AR\n", },
717
718/* r |= r/m */
719{ OPSIMP,	INAREG|FOREFF|FORCC,
720		SHINT,			T16,
721		SHINT|SNAME|SOREG,	T16,
722		0,			RLEFT|RESCC,
723		"	Ow AL,AR\n", },
724
725/* m/r |= r */
726{ OPSIMP,	INCH|FOREFF|FORCC,
727		SHCH,			T8,
728		SHCH|SNAME|SOREG,	T8,
729		0,			RLEFT|RESCC,
730		"	Ob AL,AR\n", },
731
732/* r |= r/m */
733{ OPSIMP,	INCH|FOREFF|FORCC,
734		SHCH,			T8,
735		SHCH|SNAME|SOREG,	T8,
736		0,			RLEFT|RESCC,
737		"	Ob AL,AR\n", },
738
739/* m/r |= const */
740{ OPSIMP,	INAREG|FOREFF|FORCC,
741		SHINT|SNAME|SOREG,	TP16,
742		SCON,			TANY,
743		0,			RLEFT|RESCC,
744		"	Ow AL,AR\n", },
745
746{ OPSIMP,	INCH|FOREFF|FORCC,
747		SHCH|SNAME|SOREG,	T8,
748		SCON,			TANY,
749		0,			RLEFT|RESCC,
750		"	Ob AL,AR\n", },
751
752/* r |= r/m */
753{ OPSIMP,	INL|FOREFF,
754		SHL,			T32,
755		SHL|SNAME|SOREG,	T32,
756		0,			RLEFT,
757		"	Ow AL,AR\n	Ow UL,UR\n", },
758
759/* m/r |= r/const */
760{ OPSIMP,	INL|FOREFF,
761		SHL|SNAME|SOREG,	T32,
762		SHL|SCON,		T32,
763		0,			RLEFT,
764		"	Ow AL,AR\n	Ow UL,UR\n", },
765
766/* Try use-reg instructions first */
767{ PLUS,		INAREG,
768		SAREG,			TP16,
769		SCON,			TANY,
770		NAREG|NASL,		RESC1,
771		"	lea A1, CR[AL]\n", },
772
773{ MINUS,	INAREG,
774		SAREG,			TP16,
775		SPCON,			TANY,
776		NAREG|NASL,		RESC1,
777		"	lea A1, -CR[AL]\n", },
778
779
780/*
781 * The next rules handle all shift operators.
782 */
783/* (u)long left shift is emulated, longlong to do */
784
785/* For 8086 we only have shift by 1 or shift by CL
786
787   We need a way to optimise shifts by 8/16/24/32/etc
788   shifts by 8 16 24 and 32 as moves between registers for
789   the bigger types. (eg >> 16 on a long might be mov dx, ax,
790   xor ax, ax) */
791
792{ LS,		INCREG,
793		SCREG,			T32,
794		SHCH,			T8,
795		0,			RLEFT,
796		"ZO", },
797
798/* Register 8086 timing is 2 for #1 versus 8 + 4/bin for multiple
799   so a lot of shifts would in fact best be done without using the cl
800   variant, especially including the cost of a) loading cl b) probably
801   having to boot something out of cx in the first place. For memory
802   its 15+EA v 20 + EA + 4/bit, so the other way.
803
804   8,16,24 should of course be done by loads.. FIXME
805
806   Also the compiler keeps generating mov dh, #8, mov cl, dh.. FIXME
807
808   For 80186 onwards we have shl reg, immediate (other than 1), 186 shift
809   is also much faster */
810
811
812/* r/m <<= const 1*/
813{ LS,		INAREG|FOREFF,
814		SAREG|SNAME|SOREG,	T16,
815		SONE,			TANY,
816		0,			RLEFT,
817		"	shl AL,#1\n", },
818
819/* r <<= const 2 */
820{ LS,		INAREG|FOREFF,
821		SAREG,			T16,
822		STWO,			TANY,
823		0,			RLEFT,
824		"	shl AL,#1\n	shl AL,#1\n", },
825
826/* r/m <<= r */
827{ LS,		INAREG|FOREFF,
828		SAREG|SNAME|SOREG,	T16,
829		SHCH,			T8,
830		NSPECIAL,		RLEFT,
831		"	shl AL,AR\n", },
832
833{ LS,		INCH|FOREFF,
834		SHCH|SNAME|SOREG,	T8,
835		SONE,			TANY,
836		NSPECIAL,		RLEFT,
837		"	sal AL,#1\n", },
838
839{ LS,		INCH|FOREFF,
840		SHCH,			T8,
841		STWO,			TANY,
842		NSPECIAL,		RLEFT,
843		"	sal AL,#1\n	sal AL,#1", },
844
845{ LS,		INCH|FOREFF,
846		SHCH|SNAME|SOREG,	T8,
847		SHCH,			T8,
848		NSPECIAL,		RLEFT,
849		"	sal AL,AR\n", },
850
851/* (u)long right shift is emulated. Use a 16bit register so the push
852   comes out sanely */
853{ RS,		INCREG,
854		SCREG,			T32,
855		SHCH,			T8,
856		0,			RLEFT,
857		"ZO", },
858
859{ RS,		INAREG|FOREFF,
860		SAREG|SNAME|SOREG,	TINT,
861		SHCH,			T8,
862		NSPECIAL,		RLEFT,
863		"	sar AL,AR\n", },
864
865{ RS,		INAREG|FOREFF,
866		SAREG|SNAME|SOREG,	TINT,
867		SONE,			TANY,
868		NSPECIAL,		RLEFT,
869		"	sar AL,#1\n", },
870
871{ RS,		INAREG|FOREFF,
872		SAREG,			TINT,
873		STWO,			TANY,
874		NSPECIAL,		RLEFT,
875		"	sar AL,#1\n	sar AL,#1", },
876
877{ RS,		INAREG|FOREFF,
878		SAREG|SNAME|SOREG,	TUNSIGNED|TPOINT,
879		SHCH,			T8,
880		NSPECIAL,		RLEFT,
881		"	shr AL,AR\n", },
882
883{ RS,		INAREG|FOREFF,
884		SAREG|SNAME|SOREG,	TUNSIGNED,
885		SONE,			TANY,
886		0,			RLEFT,
887		"	shr AL,#1\n", },
888
889{ RS,		INAREG|FOREFF,
890		SAREG,			TUNSIGNED,
891		STWO,			TANY,
892		0,			RLEFT,
893		"	shr AL,#1	shr AL,#1\n", },
894
895{ RS,	INCH|FOREFF,
896		SHCH|SNAME|SOREG,	TCHAR,
897		SHCH,			T8,
898		NSPECIAL,		RLEFT,
899		"	sar AL,AR\n", },
900
901{ RS,	INCH|FOREFF,
902		SHCH|SNAME|SOREG,	TCHAR,
903		SONE,			TANY,
904		NSPECIAL,		RLEFT,
905		"	sar AL,#1\n", },
906
907{ RS,	INCH|FOREFF,
908		SHCH|SNAME|SOREG,	TCHAR,
909		STWO,			TANY,
910		NSPECIAL,		RLEFT,
911		"	sar AL,#1\n	sar AL,#1\n", },
912
913{ RS,	INCH|FOREFF,
914		SHCH|SNAME|SOREG,	TUCHAR,
915		SHCH,			T8,
916		NSPECIAL,		RLEFT,
917		"	shr AL,AR\n", },
918
919{ RS,		INCH|FOREFF,
920		SHCH|SNAME|SOREG,	TUCHAR,
921		SONE,			TANY,
922		NSPECIAL,		RLEFT,
923		"	shr AL,#1\n", },
924
925{ RS,		INCH|FOREFF,
926		SHCH|SNAME|SOREG,	TUCHAR,
927		STWO,			TANY,
928		NSPECIAL,		RLEFT,
929		"	shr AL,#1\n	shr AL,#1\n", },
930
931/*
932 * The next rules takes care of assignments. "=".
933 */
934
935{ ASSIGN,	FORCC|FOREFF|INL,
936		SHL,			T32,
937		SMIXOR,			TANY,
938		0,			RDEST,
939		"	xor AL,AL\n	xor UL,UL\n", },
940
941{ ASSIGN,	FORCC|FOREFF|INL,
942		SHL,			T32,
943		SMILWXOR,		TANY,
944		0,			RDEST,
945		"	xor AL,AL\n	mov UR,UL\n", },
946
947{ ASSIGN,	FORCC|FOREFF|INL,
948		SHL,			T32,
949		SMIHWXOR,		TANY,
950		0,			RDEST,
951		"	mov AL,AR\n	xor UL,UL\n", },
952
953{ ASSIGN,	FOREFF|INL,
954		SHL,			T32,
955		SCON,			TANY,
956		0,			RDEST,
957		"	mov AL,AR\n	mov UL,UR\n", },
958
959{ ASSIGN,	FOREFF,
960		SHL|SNAME|SOREG,	T32,
961		SCON,			TANY,
962		0,			0,
963		"	mov AL,AR\n	mov UL,UR\n", },
964
965{ ASSIGN,	FOREFF,
966		SAREG|SNAME|SOREG,	TP16,
967		SCON,			TANY,
968		0,			0,
969		"	mov AL, AR\n", },
970
971{ ASSIGN,	FOREFF|INAREG,
972		SAREG,			TP16,
973		SCON,			TANY,
974		0,			RDEST,
975		"	mov AL, AR\n", },
976
977{ ASSIGN,	FOREFF,
978		SHCH|SNAME|SOREG,	T8,
979		SCON,			TANY,
980		0,	0,
981		"	mov AL, AR\n", },
982
983{ ASSIGN,	FOREFF|INCH,
984		SHCH,			T8,
985		SCON,			TANY,
986		0,			RDEST,
987		"	mov AL, AR\n", },
988
989{ ASSIGN,	FOREFF|INL,
990		SNAME|SOREG,		T32,
991		SHL,			T32,
992		0,			RDEST,
993		"	mov AL,AR\n	mov UL,UR\n", },
994
995{ ASSIGN,	FOREFF|INL,
996		SHL,			T32,
997		SHL,			T32,
998		0,			RDEST,
999		"ZH", },
1000
1001{ ASSIGN,	FOREFF|INAREG,
1002		SAREG|SNAME|SOREG,	TP16,
1003		SAREG,			TP16,
1004		0,			RDEST,
1005		"	mov AL,AR\n", },
1006
1007{ ASSIGN,	FOREFF|INAREG,
1008		SAREG,			TP16,
1009		SAREG|SNAME|SOREG,	TP16,
1010		0,			RDEST,
1011		"	mov AL,AR\n", },
1012
1013{ ASSIGN,	FOREFF|INCH,
1014		SHCH|SNAME|SOREG,	T8,
1015		SHCH,			T8|T16,
1016		0,			RDEST,
1017		"	mov AL,AR\n", },
1018
1019{ ASSIGN,	INDREG|FOREFF,
1020		SHFL,			TFLOAT|TDOUBLE|TLDOUBLE,
1021		SHFL,			TFLOAT|TDOUBLE|TLDOUBLE,
1022		0,			RDEST,
1023		"", }, /* This will always be in the correct register */
1024
1025/* order of table entries is very important here! */
1026{ ASSIGN,	INFL,
1027		SNAME|SOREG,		TLDOUBLE,
1028		SHFL,			TFLOAT|TDOUBLE|TLDOUBLE,
1029		0,			RDEST,
1030		"	fstpt AL\n	fldt AL\n", }, /* XXX */
1031
1032{ ASSIGN,	FOREFF,
1033		SNAME|SOREG,		TLDOUBLE,
1034		SHFL,			TFLOAT|TDOUBLE|TLDOUBLE,
1035		0,			0,
1036		"	fstpt AL\n", },
1037
1038{ ASSIGN,	INFL,
1039		SNAME|SOREG,		TDOUBLE,
1040		SHFL,			TFLOAT|TDOUBLE|TLDOUBLE,
1041		0,			RDEST,
1042		"	fstl AL\n", },
1043
1044{ ASSIGN,	FOREFF,
1045		SNAME|SOREG,		TDOUBLE,
1046		SHFL,			TFLOAT|TDOUBLE|TLDOUBLE,
1047		0,			0,
1048		"	fstpl AL\n", },
1049
1050{ ASSIGN,	INFL,
1051		SNAME|SOREG,		TFLOAT,
1052		SHFL,			TFLOAT|TDOUBLE|TLDOUBLE,
1053		0,			RDEST,
1054		"	fsts AL\n", },
1055
1056{ ASSIGN,	FOREFF,
1057		SNAME|SOREG,		TFLOAT,
1058		SHFL,			TFLOAT|TDOUBLE|TLDOUBLE,
1059		0,			0,
1060		"	fstps AL\n", },
1061/* end very important order */
1062
1063{ ASSIGN,	INFL|FOREFF,
1064		SHFL,			TLDOUBLE,
1065		SHFL|SOREG|SNAME,	TLDOUBLE,
1066		0,			RDEST,
1067		"	fldt AR\n", },
1068
1069{ ASSIGN,	INFL|FOREFF,
1070		SHFL,			TDOUBLE,
1071		SHFL|SOREG|SNAME,	TDOUBLE,
1072		0,			RDEST,
1073		"	fldl AR\n", },
1074
1075{ ASSIGN,	INFL|FOREFF,
1076		SHFL,			TFLOAT,
1077		SHFL|SOREG|SNAME,	TFLOAT,
1078		0,			RDEST,
1079		"	flds AR\n", },
1080
1081/* Do not generate memcpy if return from funcall */
1082#if 0
1083{ STASG,	INAREG|FOREFF,
1084		SOREG|SNAME|SAREG,	TPTRTO|TSTRUCT,
1085		SFUNCALL,		TPTRTO|TSTRUCT,
1086		0,			RRIGHT,
1087		"", },
1088#endif
1089
1090{ STASG,	INAREG|FOREFF,
1091		SOREG|SNAME,		TANY,
1092		SAREG,			TPTRTO|TANY,
1093		NSPECIAL|NAREG,		RDEST,
1094		"F	mov A1,si\nZQF	mov si,A1\n", },
1095
1096/*
1097 * DIV/MOD/MUL
1098 */
1099/* long div is emulated */
1100{ DIV,	INCREG,
1101		SCREG|SNAME|SOREG|SCON, T32,
1102		SCREG|SNAME|SOREG|SCON, T32,
1103		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
1104		"ZO", },
1105
1106/* REVIEW We can only do (i)divb ax/byte  and (i)divw (dx:ax)/word
1107   and the results are always in ah/al (remainer/mod)
1108   or dx:ax (dx = remainer, ax = mod)
1109
1110   Power of two needs to be done by shifts. For other cases of constants
1111   we need to implement two things
1112   1. Spotting add sequences for constants with few 1 bits on one side
1113   2. Spotting cases we can compute the magic constant to multiply with for
1114      the same result */
1115
1116
1117{ DIV,	INAREG,
1118		SAREG,			TUNSIGNED|TPOINT,
1119		SAREG|SNAME|SOREG,	TUNSIGNED|TPOINT,
1120		NSPECIAL,		RDEST,
1121		"	xor dx,dx\n	divw AR\n", },
1122
1123{ DIV,	INCH,
1124		SHCH,			TUCHAR,
1125		SHCH|SNAME|SOREG,	TUCHAR,
1126		NSPECIAL,		RDEST,
1127		"	xor ah,ah\n	divb AR\n", },
1128
1129{ DIV,	INFL,
1130		SHFL,			TDOUBLE,
1131		SNAME|SOREG,		TDOUBLE,
1132		0,			RLEFT,
1133		"	fdivl AR\n", },
1134
1135{ DIV,	INFL,
1136		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
1137		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
1138		0,			RLEFT,
1139		"	fdivZAp\n", },
1140
1141/* (u)long mod is emulated */
1142{ MOD,		INCREG,
1143		SCREG|SNAME|SOREG|SCON,	T32,
1144		SCREG|SNAME|SOREG|SCON,	T32,
1145		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
1146		"ZO", },
1147
1148{ MOD,		INAREG,
1149		SAREG,			TP16,
1150		SAREG|SNAME|SOREG,	TP16,
1151		NAREG|NSPECIAL,		RESC1,
1152		"	xor dx,dx\n	divw AR\n", },
1153
1154{ MOD,	INCH,
1155		SHCH,			TUCHAR,
1156		SHCH|SNAME|SOREG,	TUCHAR,
1157		NBREG|NSPECIAL,		RESC1,
1158		"	xor ah,ah\n	divb AR\n", },
1159
1160/* (u)long mul is emulated */
1161/* On 8086 we can only do multiplies of al * value into ax (for 8bit)
1162   or ax * value into dx:ax for 16bit
1163
1164   80186 allows us to do a signed multiply of a register with a constant
1165   into a second register
1166
1167   Same about shifts, and add optimisations applies here too */
1168
1169/* 32bit mul is emulated (for now) */
1170{ MUL,		INCREG,
1171		SCREG|SNAME|SOREG|SCON,		T32,
1172		SCREG|SNAME|SOREG|SCON,		T32,
1173		NSPECIAL|NCREG|NCSL|NCSR,	RESC1,
1174		"ZO", },
1175
1176/* FIMXE: need special rules */
1177{ MUL,	INAREG,
1178		SAREG,			T16|TPOINT,
1179		SAREG|SNAME|SOREG,	T16|TPOINT,
1180		NSPECIAL,		RDEST,
1181		"	mul AR\n", },
1182
1183{ MUL,	INCH,
1184		SHCH,			T8,
1185		SHCH|SNAME|SOREG,	T8,
1186		NSPECIAL,		RDEST,
1187		"	mulb AR\n", },
1188
1189{ MUL,	INFL,
1190		SHFL,			TDOUBLE,
1191		SNAME|SOREG,		TDOUBLE,
1192		0,			RLEFT,
1193		"	fmull AR\n", },
1194
1195{ MUL,	INFL,
1196		SHFL	,		TLDOUBLE|TDOUBLE|TFLOAT,
1197		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
1198		0,			RLEFT,
1199		"	fmulp\n", },
1200
1201/*
1202 * Indirection operators.
1203 */
1204{ UMUL,	INLL,
1205		SANY,			TANY,
1206		SOREG,			T32,
1207		NCREG,			RESC1,
1208		"	mov UL,U1\n	mov AL,A1\n", },
1209
1210{ UMUL,	INAREG,
1211		SANY,			TP16,
1212		SOREG,			TP16,
1213		NAREG|NASL,		RESC1,
1214		"	mov AL,A1\n", },
1215
1216{ UMUL,	INCH,
1217		SANY,			TANY,
1218		SOREG,			T8,
1219		NBREG|NBSL,		RESC1,
1220		"	mov AL,A1\n", },
1221
1222{ UMUL,	INAREG,
1223		SANY,			TANY,
1224		SOREG,			T16,
1225		NAREG|NASL,		RESC1,
1226		"	mov AL,A1\n", },
1227
1228{ UMUL,	INFL,
1229		SANY,			TANY,
1230		SOREG,			TLDOUBLE,
1231		NDREG|NDSL,		RESC1,
1232		"	fldt AL\n", },
1233
1234{ UMUL,	INFL,
1235		SANY,			TANY,
1236		SOREG,			TDOUBLE,
1237		NDREG|NDSL,		RESC1,
1238		"	fldl AL\n", },
1239
1240{ UMUL,	INFL,
1241		SANY,			TANY,
1242		SOREG,			TFLOAT,
1243		NDREG|NDSL,		RESC1,
1244		"	flds AL\n", },
1245
1246/*
1247 * Logical/branching operators
1248 */
1249
1250/* Comparisions, take care of everything */
1251{ OPLOG,	FORCC,
1252		SHL|SOREG|SNAME,	T32,
1253		SHL,			T32,
1254		0,	0,
1255		"ZD", },
1256
1257{ OPLOG,	FORCC,
1258		SAREG|SOREG|SNAME,	TP16,
1259		SCON|SAREG,		TP16,
1260		0, 			RESCC,
1261		"	cmp AL,AR\n", },
1262
1263
1264{ OPLOG,	FORCC,
1265		SCON|SAREG,		TP16,
1266		SAREG|SOREG|SNAME,	TP16,
1267		0, 			RESCC,
1268		"	cmp AL,AR\n", },
1269
1270{ OPLOG,	FORCC,
1271		SBREG|SOREG|SNAME,	T8,
1272		SCON|SBREG,		TANY,
1273		0, 			RESCC,
1274		"	cmpb AL,AR\n", },
1275
1276{ OPLOG,	FORCC,
1277		SCON|SBREG,		T8,
1278		SBREG|SOREG|SNAME,	TANY,
1279		0, 			RESCC,
1280		"	cmpb AL,AR\n", },
1281
1282{ OPLOG,	FORCC,
1283		SDREG,			TLDOUBLE|TDOUBLE|TFLOAT,
1284		SDREG,			TLDOUBLE|TDOUBLE|TFLOAT,
1285		0, 			RNOP,
1286		"ZG", },
1287
1288{ OPLOG,	FORCC,
1289		SANY,			TANY,
1290		SANY,			TANY,
1291		REWRITE,	0,
1292		"diediedie!", },
1293
1294/* AND/OR/ER/NOT */
1295
1296/* FIXME: pcc generates nonsense ands, but they should be fixed somewhere
1297   if possible. In particular it will do the classic 32bit and with a 16bit
1298   0xFFFF by generating and ax,#ffff and bx,#0
1299   	eg compiling
1300   		sum1 = (sum1 & 0xFFFF) + (sum1 >> 16);
1301	writes a pile of crap code.
1302*/
1303
1304
1305{ AND,	INCREG|FOREFF,
1306		SCREG,			T32,
1307		SCREG|SOREG|SNAME,	T32,
1308		0,			RLEFT,
1309		"	and AR,AL\n	and UR,UL\n", },
1310
1311{ AND,	INAREG|FOREFF,
1312		SAREG,			T16,
1313		SAREG|SOREG|SNAME,	T16,
1314		0,			RLEFT,
1315		"	and AR,AL\n", },
1316
1317{ AND,	INAREG|FOREFF,
1318		SAREG|SOREG|SNAME,	T16,
1319		SCON|SAREG,		T16,
1320		0,			RLEFT,
1321		"	and AR,AL\n", },
1322
1323{ AND,	INBREG|FOREFF,
1324		SBREG|SOREG|SNAME,	T8,
1325		SCON|SBREG,		T8,
1326		0,			RLEFT,
1327		"	and AR,AL\n", },
1328
1329{ AND,	INBREG|FOREFF,
1330		SBREG,			T8,
1331		SBREG|SOREG|SNAME,	T8,
1332		0,			RLEFT,
1333		"	and AR,AL\n", },
1334/* AND/OR/ER/NOT */
1335
1336/*
1337 * Jumps.
1338 */
1339{ GOTO, 	FOREFF,
1340		SCON,			TANY,
1341		SANY,			TANY,
1342		0,			RNOP,
1343		"	jmp LL\n", },
1344
1345#if defined(GCC_COMPAT) || defined(LANG_F77)
1346{ GOTO, 	FOREFF,
1347		SAREG,			TANY,
1348		SANY,			TANY,
1349		0,			RNOP,
1350		"	jmp *AL\n", },
1351#endif
1352
1353/*
1354 * Convert LTYPE to reg.
1355 */
1356{ OPLTYPE,	FORCC|INL,
1357		SCREG,			T32,
1358		SMIXOR,			TANY,
1359		NCREG,			RESC1,
1360		"	xor U1,U1\n	xor A1,A1\n", },
1361
1362{ OPLTYPE,	FORCC|INL,
1363		SCREG,			T32,
1364		SMILWXOR,		TANY,
1365		NCREG,			RESC1,
1366		"	mov U1,UL\n	xor A1,A1\n", },
1367
1368{ OPLTYPE,	FORCC|INL,
1369		SCREG,			T32,
1370		SMIHWXOR,		TANY,
1371		NCREG,			RESC1,
1372		"	xor U1,U1\n	mov A1,AL\n", },
1373
1374{ OPLTYPE,	INL,
1375		SANY,			TANY,
1376		SCREG,			T32,
1377		NCREG,			RESC1,
1378		"ZK", },
1379
1380{ OPLTYPE,	INL,
1381		SANY,			TANY,
1382		SCON|SOREG|SNAME,	T32,
1383		NCREG,			RESC1,
1384		"	mov U1,UL\n	mov A1,AL\n", },
1385
1386{ OPLTYPE,	FORCC|INAREG,
1387		SAREG,			TP16,
1388		SMIXOR,			TANY,
1389		NAREG|NASL,		RESC1,
1390		"	xor A1,A1\n", },
1391
1392{ OPLTYPE,	INAREG,
1393		SANY,			TANY,
1394		SAREG|SCON|SOREG|SNAME,	TP16,
1395		NAREG|NASL,		RESC1,
1396		"	mov A1,AL\n", },
1397
1398{ OPLTYPE,	INBREG,
1399		SANY,			TANY,
1400		SBREG|SOREG|SNAME|SCON,	T8,
1401		NBREG,			RESC1,
1402		"	mov A1,AL\n", },
1403
1404{ OPLTYPE,	FORCC|INAREG,
1405		SAREG,			T16,
1406		SMIXOR,			TANY,
1407		NAREG,			RESC1,
1408		"	xor A1,A1\n", },
1409
1410{ OPLTYPE,	INAREG,
1411		SANY,			TANY,
1412		SAREG|SOREG|SNAME|SCON,	T16,
1413		NAREG,			RESC1,
1414		"	mov A1,AL\n", },
1415
1416{ OPLTYPE,	INDREG,
1417		SANY,			TLDOUBLE,
1418		SOREG|SNAME,		TLDOUBLE,
1419		NDREG,			RESC1,
1420		"	fldt AL\n", },
1421
1422{ OPLTYPE,	INDREG,
1423		SANY,			TDOUBLE,
1424		SOREG|SNAME,		TDOUBLE,
1425		NDREG,			RESC1,
1426		"	fldl AL\n", },
1427
1428{ OPLTYPE,	INDREG,
1429		SANY,			TFLOAT,
1430		SOREG|SNAME,		TFLOAT,
1431		NDREG,			RESC1,
1432		"	flds AL\n", },
1433
1434/* Only used in ?: constructs. The stack already contains correct value */
1435{ OPLTYPE,	INDREG,
1436		SANY,			TFLOAT|TDOUBLE|TLDOUBLE,
1437		SDREG,			TFLOAT|TDOUBLE|TLDOUBLE,
1438		NDREG,			RESC1,
1439		"", },
1440
1441/*
1442 * Negate a word.
1443 */
1444
1445{ UMINUS,	INCREG|FOREFF,
1446		SCREG,			T32,
1447		SCREG,			T32,
1448		0,			RLEFT,
1449		"	neg AL\n	adc UL,#0\n	neg UL\n", },
1450
1451{ UMINUS,	INAREG|FOREFF,
1452		SAREG,			TP16,
1453		SAREG,			TP16,
1454		0,			RLEFT,
1455		"	neg AL\n", },
1456
1457{ UMINUS,	INBREG|FOREFF,
1458		SBREG,			T8,
1459		SBREG,			T8,
1460		0,			RLEFT,
1461		"	neg AL\n", },
1462
1463{ UMINUS,	INFL|FOREFF,
1464		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
1465		SHFL,			TLDOUBLE|TDOUBLE|TFLOAT,
1466		0,			RLEFT,
1467		"	fchs\n", },
1468
1469{ COMPL,	INCREG,
1470		SCREG,			T32,
1471		SANY,			TANY,
1472		0,			RLEFT,
1473		"	not AL\n	not UL\n", },
1474
1475{ COMPL,	INAREG,
1476		SAREG,			T16,
1477		SANY,			TANY,
1478		0,			RLEFT,
1479		"	not AL\n", },
1480
1481{ COMPL,	INBREG,
1482		SBREG,			T8,
1483		SANY,			TANY,
1484		0,			RLEFT,
1485		"	not AL\n", },
1486
1487/*
1488 * Arguments to functions.
1489 *
1490 * char has already been promoted to integer types
1491 */
1492
1493/* Push immediate not 8086... Loading a register and pushing costs us
1494   4 + 11 clocks, loading memory would cost us 16 + EA */
1495{ FUNARG,	FOREFF,
1496		/*SCON|*/SCREG|SNAME|SOREG,	T32,
1497		SANY,			T32,
1498		0,			RNULL,
1499		"	push UL\n	push AL\n", },
1500
1501{ FUNARG,	FOREFF,
1502		/*SCON|*/SAREG|SNAME|SOREG,	T16|TPOINT,
1503		SANY,			TP16,
1504		0,			RNULL,
1505		"	push AL\n", },
1506
1507/* FIXME: FPU needs reworking into 4 regs or a memcpy */
1508{ FUNARG,	FOREFF,
1509		SNAME|SOREG,		TDOUBLE,
1510		SANY,			TDOUBLE,
1511		0,			0,
1512		"	pushl UL\n	pushl AL\n", },
1513
1514{ FUNARG,	FOREFF,
1515		SDREG,			TDOUBLE,
1516		SANY,			TDOUBLE,
1517		0,			0,
1518		"	sub sp,#8\n	fstpl [sp]\n", },
1519
1520{ FUNARG,	FOREFF,
1521		SNAME|SOREG,		TFLOAT,
1522		SANY,			TFLOAT,
1523		0,	0,
1524		"	push UL\n	push AL\n", },
1525
1526{ FUNARG,	FOREFF,
1527		SDREG,			TFLOAT,
1528		SANY,			TFLOAT,
1529		0,			0,
1530		"	sub sp,#4\n	fstps [sp]\n", },
1531
1532{ FUNARG,	FOREFF,
1533		SDREG,			TLDOUBLE,
1534		SANY,			TLDOUBLE,
1535		0,			0,
1536		"	sub sp,#12\n	fstpt [sp]\n", },
1537
1538{ STARG,	FOREFF,
1539		SAREG,			TPTRTO|TSTRUCT,
1540		SANY,			TSTRUCT,
1541		NSPECIAL,		0,
1542		"ZF", },
1543
1544# define DF(x) FORREW,SANY,TANY,SANY,TANY,REWRITE,x,""
1545
1546{ UMUL, DF( UMUL ), },
1547
1548{ ASSIGN, DF(ASSIGN), },
1549
1550{ STASG, DF(STASG), },
1551
1552{ FLD, DF(FLD), },
1553
1554{ OPLEAF, DF(NAME), },
1555
1556/* { INIT, DF(INIT), }, */
1557
1558{ OPUNARY, DF(UMINUS), },
1559
1560{ OPANY, DF(BITYPE), },
1561
1562{ FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	FREE,	"help; I'm in trouble\n" },
1563};
1564
1565int tablesize = sizeof(table)/sizeof(table[0]);
1566