xref: /netbsd-src/external/bsd/pcc/dist/pcc/arch/i86/table.c (revision 411dcbec990c8aa9c57d3bd2f4bcacadec0b1ab5)
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 
118 struct 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 
1565 int tablesize = sizeof(table)/sizeof(table[0]);
1566