Rune - Further Object abstraction work
[rune.git] / ras / insnx86.c
1 /*
2  * INSN.C
3  *
4  * (c)Copyright 2016, Matthew Dillon, All Rights Reserved.  See the COPYRIGHT
5  * file at the base of the distribution.
6  *
7  * Emit the instruction as x86 assembly.  If the EA/argument form is not
8  * compatible we make it compatible.
9  */
10
11 #include "defs.h"
12 #include "insnx86.h"
13
14 static int doHandleImmediate(rea_t *srea, rea_t *drea, uint8_t extov);
15 static void doInsnRM2NoReadDst(RASParser *p, rinsn_t *rin, const char *x86op,
16                         uint8_t extov);
17 static void doInsnMR2NoReadDst(RASParser *p, rinsn_t *rin, const char *x86op,
18                         uint8_t extov);
19 static void doInsnRMMR3(RASParser *p, rinsn_t *rin, const char *x86op);
20 static void doInsnMR3(RASParser *p, rinsn_t *rin, const char *x86op, int nodrd);
21 static void doInsn1R(RASParser *p, rinsn_t *rin, const char *x86op1,
22                         const char *x86op2, const char *x86opt2arg);
23 static void doInsnSHIFT3(RASParser *p, rinsn_t *rin, const char *x86op);
24 static void doInsnDXAX3(RASParser *p, rinsn_t *rin, const char *x86op,
25                         int issigned, int dxresult);
26 static int doInsnFloating3(RASParser *p, rinsn_t *rin, const char *x86op,
27                         int isfcmp);
28 static void doMOVE(RASParser *p, rinsn_t *rin, rea_t *sea, rea_t *dea);
29 static void doMOVEExt(RASParser *p, rinsn_t *rin, rea_t *sea, rea_t *dea,
30                         uint8_t extov);
31 static void doLEA(RASParser *p, rea_t *sea, rea_t *dea);
32 static void doSpecialSave(rinsn_t *rin);
33 static void doSpecialRestore(rinsn_t *rin);
34 static int InsnSimplifyRMMRCMP(RASParser *p, rinsn_t *rin,
35                         rea_t **sea1p, rea_t **sea2p);
36 static int InsnSimplifyMRFCMP(RASParser *p, rinsn_t *rin,
37                         rea_t **sea1p, rea_t **sea2p);
38 static rea_t *InsnSimplifyFP128(RASParser *p, rinsn_t *rin,
39                         rea_t *sea, rea_t *tea, uint8_t ext,
40                         int rspoff, int loadme);
41
42 static void printINSN(rinsn_t *rin, const char *x86op, rea_t *sea,
43                         rea_t *dea, uint8_t extov);
44 static void printEA(rea_t *rea, uint8_t extov);
45 static void printREGTGT(uint16_t target_reg, uint32_t regno, uint8_t ext);
46 static void printREG(rea_t *rea, uint8_t ext);
47 static void printBRLabel(rsym_t *label);
48 static const char *x86ext(char c, uint8_t argflags);
49 static int findfreebit(uint32_t regno, uint64_t mask);
50 #if 0
51 static void clearregbit(uint64_t *mask, rea_t *rea);
52 #endif
53 static const char *x86branch(uint32_t op, int invert, int reverse);
54 static int sameEA(rea_t *rea1, rea_t *rea2);
55 static int adjacentLabel(rinsn_t *rin, rsym_t *sym);
56 static rinsn_t *allocInsnBlock(RASParser *p, rblock_t *rblock,
57                         uint32_t op, uint8_t ext, int args);
58 static void initEA(rea_t *rea, uint8_t eamode,
59                         uint32_t regno, uint16_t target_reg);
60 static void RegAllocatorX86(RASParser *p, rblock_t *rblock,
61                         urunesize_t stacksize);
62 static void RegAllocatorScan(RASParser *p, rblock_t *rblock);
63 static void RegAllocatorClear(RASParser *p, rblock_t *rblock);
64
65 static uint8_t ExtSize;
66 static char X86Size;
67 static uint64_t SaveMask;
68 static int RegAllocWeight;
69 static urunesize_t ExtraStackBase;
70 static urunesize_t ExtraStackSpace;
71
72 static __inline
73 int
74 ISIMM64(rea_t *sea)
75 {
76     if (sea->eamode == EA_IMMEDIATE &&
77         (sea->immlo < (int)0x80000000 ||
78          sea->immlo > (int)0x7FFFFFFF)) {
79         return 1;
80     } else {
81         return 0;
82     }
83 }
84
85 /*
86  * Global initialization (occurs after initial symbol load)
87  */
88 void
89 InsnTargetInit(void)
90 {
91     ExtSize = (sizeof(urunesize_t) == 4) ? REXT_I32 : REXT_I64;
92     X86Size = x86ext(ExtSize, 0)[0];
93     RegAllocator = RegAllocatorX86;
94 }
95
96 /*
97  * Target-specific adjustments for this assembly emitter.  Called during
98  * initial parsing, prior to any characterization or optimization.
99  *
100  * Specify registers which get clobbered by certain instructions.  Note that
101  * most procedure calls will clobber a *lot* of registers, including all the
102  * %xmm* registers (if we want to be compatible with C anyhow).
103  *
104  * Our register optimizer is capable of saving/restoring some scratch
105  * registers around procedure calls, see X86_REGF_SPECIAL_SAVE.
106  */
107 void
108 InsnTargetAdjust(RASParser *p __unused, rinsn_t *rin)
109 {
110     uint64_t raf;
111     rea_t  *rea1;
112     rea_t  *rea2;
113     rea_t  *rea3;
114     rea_t  *rea4;
115
116     /*
117      * This is a bit of a brute-force approach, but the registerizer has to
118      * know before we actually start emitting instructions.
119      */
120     if (rin->op & INSNF_FLOAT) {
121         /*
122          * FP instructions may need to use XMM0 and/or XMM1 as temporaries to
123          * fix incompatible EAs.  Generally speaking all operands for 128-bit
124          * FP instructions set ADDRUSED to try to prevent caching in %xmm
125          * registers because we have to use memory ops for 80/128-bit FP
126          * operations.
127          *
128          * We have a bit of sophistication here to allow conditionals with
129          * boolean results to cache the boolean result.
130          */
131         raf = X86_REGF_XMM0 | X86_REGF_XMM1;
132         if (rin->ext1 == REXT_I128) {
133             rea1 = rin->arg1.rea;
134             rea2 = rin->arg2.rea;
135             rea3 = rin->arg3.rea;
136             if (rea1) {
137                 rea1->flags |= REAF_ADDRUSED;
138                 /* this messes up matching */
139                 /* rea1->flags &= ~REAF_CACHEABLE; */
140             }
141             if (rin->op & INSNF_COND) {
142                 if (rin->operands > 2 ||
143                     (rin->operands == 2 &&
144                      (rin->flags & RINSF_BRANCH))) {
145                     rea2->flags |= REAF_ADDRUSED;
146                     /* this messes up matching */
147                     /* rea2->flags &= ~REAF_CACHEABLE; */
148                 }
149                 if (rin->operands > 3 ||
150                     (rin->operands == 3 &&
151                      (rin->flags & RINSF_BRANCH))) {
152                     rea3->flags |= REAF_ADDRUSED;
153                     /* this messes up matching */
154                     /* rea3->flags &= ~REAF_CACHEABLE; */
155                 }
156             } else {
157                 if (rea2) {
158                     rea2->flags |= REAF_ADDRUSED;
159                     /* this messes up matching */
160                     /* rea2->flags &= ~REAF_CACHEABLE; */
161                 }
162                 if (rea3) {
163                     rea3->flags |= REAF_ADDRUSED;
164                     /* this messes up matching */
165                     /* rea3->flags &= ~REAF_CACHEABLE; */
166                 }
167             }
168             rea4 = rin->arg4.rea;
169             if (rea4) {
170                 rea4->flags |= REAF_ADDRUSED;
171                 /* rea4->flags &= ~REAF_CACHEABLE; */
172             }
173         }
174     } else {
175         /*
176          * Integer instructions might need to use RCX as a temporary to fix
177          * incompatible EAs.  Other requirements are switched on below.
178          */
179         raf = X86_REGF_RCX;
180     }
181
182     switch (rin->op) {
183     case INSN_BZERO:
184         /*
185          * For stosb
186          */
187         raf |= X86_REGF_RAX;
188         raf |= X86_REGF_RCX | X86_REGF_RDI;
189         break;
190     case INSN_BCOPY:
191         /*
192          * For movsb
193          */
194         raf |= X86_REGF_RCX | X86_REGF_RSI | X86_REGF_RDI;
195         break;
196     case INSN_MULU:
197     case INSN_MULS:
198     case INSN_DIVU:
199     case INSN_DIVS:
200     case INSN_MODU:
201     case INSN_MODS:
202         /*
203          * We may need/clobber these regs, depending.
204          */
205         raf |= X86_REGF_RAX | X86_REGF_RDX;
206         break;
207     case INSN_QCALL:
208         /*
209          * System interface call
210          */
211         raf |= X86_REGF_RAX;
212         raf |= X86_SYSF_ARG1 | X86_SYSF_ARG2 | X86_SYSF_ARG3;
213         raf |= X86_REGF_CALLSCR_SYS;
214         break;
215     case INSN_RCALL:
216         raf |= X86_REGF_RAX;
217         raf |= X86_RUNTIMEF_ARG1 | X86_RUNTIMEF_ARG2 |
218             X86_RUNTIMEF_ARG3;
219         raf |= X86_REGF_CALLSCR_RUNTIME;
220         break;
221     case INSN_CALL:
222     case INSN_TCALL:
223         /*
224          * Call arguments %ap:RSI %rp:RDI [%sg:RDX]     (linux/bsd) Call
225          * arguments %ap:RCX %rp:RDX [%sg:R8]   (ms)
226          */
227         raf |= X86_REGF_RAX;
228         raf |= X86_RUNEF_ARG1 | X86_RUNEF_ARG2 | X86_RUNEF_ARG3;
229         raf |= X86_REGF_CALLSCR_RUNE;
230         break;
231     case INSN_ASL:
232     case INSN_ASR:
233     case INSN_LSR:
234         raf |= X86_REGF_RAX | X86_REGF_RCX;
235         break;
236     case INSN_BCHECK:
237         /*
238          * BCHECK only calls the BoundsTrap on compare failure, which does
239          * not return.  Do not save/restore registers.
240          */
241         break;
242     case INSN_DET:
243         raf |= X86_REGF_CALLSCR_RUNTIME;
244         break;
245
246     case INSN_LVALLOC:
247         /* fall through */
248     case INSN_PGET:
249     case INSN_PGETH:
250     case INSN_PPUT:
251     case INSN_PPUTH:
252     case INSN_PREF:
253     case INSN_PREL:
254     case INSN_PLOCK:
255     case INSN_PUNLOCK:
256         /* fall through */
257     case INSN_IGET:
258     case INSN_IGETH:
259     case INSN_IPUT:
260     case INSN_IPUTH:
261     case INSN_IREF:
262     case INSN_IREL:
263     case INSN_ILOCK:
264     case INSN_IUNLOCK:
265         raf |= X86_REGF_RAX;
266         raf |= X86_REGF_CALLSCR_RUNTIME;
267         break;
268     case INSN_CMPTYPE:
269     case INSN_BND_TRAP:
270     case INSN_TSCHED:
271         raf |= X86_REGF_CALLSCR_RUNTIME;
272         break;
273     case INSN_UITOF:
274     case INSN_SITOF:
275     case INSN_FTOUI:
276     case INSN_FTOSI:
277     case INSN_CASTF:
278         /*
279          * Misc FP conversions might use these three registers.
280          */
281         raf = X86_REGF_XMM0 | X86_REGF_XMM1 | X86_REGF_RCX;
282         break;
283     default:
284         break;
285     }
286     rin->regused_init |= raf;
287 }
288
289 /*
290  * We need to formally add some instructions to the basic block to access the
291  * procedure arguments (%ap, %rp, and potentially %sg).  This allows us to
292  * use the register allocator to optimize which regs they go into.
293  *
294  * These instructions are set up to make sure that the register allocator
295  * does not blow away the arguments before we've had a chance to load them
296  * into the proper registers.  We must also ensure that the source and
297  * destination EAs never match which we do by setting cache_id.
298  */
299 void
300 InsnProcedureBasicBlock(RASParser * p, rblock_t * rblock,
301                         urunesize_t bytes __unused, urunesize_t align __unused)
302 {
303     rinsn_t *rin;
304
305     rin = allocInsnBlock(p, rblock, INSN_MOVE, ExtSize, 2);
306     initEA(rin->arg1.rea, EA_DIRECT, REG_AP, X86_RUNE_ARG1);
307     initEA(rin->arg2.rea, EA_DIRECT, REG_AP, 0);
308     rin->arg2.flags |= RAF_WRITE;
309     rin->arg1.rea->cache_id = 1;
310     rin->regused_init |= X86_RUNEF_ARG2;
311     rin->regused_init |= X86_RUNEF_ARG3;
312
313     rin = allocInsnBlock(p, rblock, INSN_MOVE, ExtSize, 2);
314     initEA(rin->arg1.rea, EA_DIRECT, REG_RP, X86_RUNE_ARG2);
315     initEA(rin->arg2.rea, EA_DIRECT, REG_RP, 0);
316     rin->arg2.flags |= RAF_WRITE;
317     rin->arg1.rea->cache_id = 1;
318     rin->regused_init |= X86_RUNEF_ARG3;
319
320     rin = allocInsnBlock(p, rblock, INSN_MOVE, ExtSize, 2);
321     initEA(rin->arg1.rea, EA_DIRECT, REG_SG, X86_RUNE_ARG3);
322     initEA(rin->arg2.rea, EA_DIRECT, REG_SG, 0);
323     rin->arg2.flags |= RAF_WRITE;
324     rin->arg1.rea->cache_id = 1;
325 }
326
327 /*
328  * Output prologue
329  */
330 void
331 InsnProcedureStart(RASParser *p, urunesize_t bytes, urunesize_t align)
332 {
333     static rea_t xrsp;
334     rsym_t *psym = p->psym;
335     int     count;              /* total bytes pushed on stack */
336     int     fcount;             /* floating point subsection */
337     int     i;
338
339     printf("\n");
340     printf("\t# PROC %s, %jd, %jd\n",
341            psym->id,
342            (intmax_t) bytes,
343            (intmax_t) align);
344
345     printf("\t.text\n");
346     printf("\t.globl\t%s\n", psym->id + 1);     /* skip the '@' */
347     printf("\t.type\t%s, @function\n", psym->id + 1);
348     printf("%s:\n", psym->id + 1);
349     printf("\t.cfi_startproc\n");
350
351     count = 0;
352     for (i = 0; i < (X86_REG_XMM0 & ~X86_SIZE_UNSPEC); ++i) {
353         if ((SaveMask & (1LLU << i)) == 0)
354             continue;
355         if (X86_REGF_CALLSAVE_RUNE & (1LLU << i)) {
356             printf("\tpush%c\t", X86Size);
357             printREGTGT(i | X86_SIZE_UNSPEC, 0, ExtSize);
358             printf("\n");
359             count += sizeof(void *);
360             /* do not bump bytes, not included */
361         }
362     }
363
364     fcount = 0;
365     for (i = (X86_REG_XMM0 & ~X86_SIZE_UNSPEC); i < 64; ++i) {
366         if ((SaveMask & (1LLU << i)) == 0)
367             continue;
368         if (X86_REGF_CALLSAVE_RUNE & (1LLU << i))
369             ++fcount;
370     }
371     bytes += fcount * 16;       /* (temporary) */
372     if (fcount && align < 16)
373         align = 16;
374
375     /*
376      * We may need extra stack space for ABI calls
377      */
378     if (ExtraStackSpace) {
379         if (align < 16)
380             align = 16;
381         bytes = (bytes + 15) & ~15;
382         bytes += ExtraStackSpace;
383     }
384
385     if (bytes) {
386         size_t  pad;
387
388         if (align < 16)
389             align = 16;
390         if (bytes < align)
391             bytes = align;
392         bytes = (bytes + align - 1) & ~(align - 1);
393
394         /*
395          * 16-byte align our pushes + %rip to ensure that the resulting stack
396          * pointer is fully aligned.
397          */
398         count += sizeof(void *);        /* include %rip */
399         pad = ((count + 15) & ~15) - count;     /* 16-byte align */
400         bytes += pad;
401
402         xrsp.target_reg = X86_REG_RSP;
403         xrsp.eamode = EA_DIRECT;
404         printf("\tsub%c\t$%jd, ", X86Size, (intmax_t) bytes);
405         printEA(&xrsp, ExtSize);
406         printf("\n");
407         count += bytes;
408         bytes -= pad;           /* undo */
409         ProcStackPad = pad;
410     } else {
411         ProcStackPad = 0;
412     }
413
414     /*
415      * Save FP registers past the nominal stack and extra space.
416      */
417     bytes -= fcount * 16;       /* undo */
418     fcount = 0;
419     for (i = (X86_REG_XMM0 & ~X86_SIZE_UNSPEC); i < 64; ++i) {
420         if ((SaveMask & (1LLU << i)) == 0)
421             continue;
422         if (X86_REGF_CALLSAVE_RUNE & (1LLU << i)) {
423             printf("\tmovaps\t");
424             printREGTGT(i | X86_SIZE_UNSPEC, 0, ExtSize);
425             printf(", %zd(%%rsp)\n", bytes + fcount *16);
426             ++fcount;
427         }
428     }
429
430     /*
431      * count is the whole frame
432      *
433      * ProcStackSize is just the base variable and extra space, and does not
434      * count the register save area, pad, or %rip.
435      */
436     printf("\t.cfi_def_cfa_offset\t%jd\n", (intmax_t) (count));
437     ProcStackSize = (ssize_t)bytes;
438 }
439
440 void
441 InsnProcedureEnd(RASParser *p __unused,
442                  urunesize_t bytes, urunesize_t align __unused)
443 {
444     static rea_t xrsp;
445     int     fcount;
446     int     i;
447
448     /*
449      * Restore FP regs after the variable space
450      */
451     fcount = 0;
452     for (i = 32; i < 64; ++i) {
453         if ((SaveMask & (1LLU << i)) == 0)
454             continue;
455         if (X86_REGF_CALLSAVE_RUNE & (1LLU << i)) {
456             printf("\tmovaps\t");
457             printf("%zd(%%rsp), ", ProcStackSize + fcount *16);
458             printREGTGT(i | X86_SIZE_UNSPEC, 0, ExtSize);
459             printf("\n");
460             ++fcount;
461         }
462     }
463
464     /*
465      * Include the FP and %rip save space in the %rsp restore
466      */
467     bytes = ProcStackSize + fcount * 16 + ProcStackPad;
468     if (bytes) {
469         xrsp.target_reg = X86_REG_RSP;
470         xrsp.eamode = EA_DIRECT;
471         printf("\tadd%c\t$%zd, ", X86Size, bytes);
472         printEA(&xrsp, ExtSize);
473         printf("\n");
474     }
475
476     /*
477      * Use pop for normal registers
478      */
479     for (i = 31; i >= 0; --i) {
480         if ((SaveMask & (1LLU << i)) == 0)
481             continue;
482         if (X86_REGF_CALLSAVE_RUNE & (1LLU << i)) {
483             printf("\tpop%c\t", X86Size);
484             printREGTGT(i | X86_SIZE_UNSPEC, 0, ExtSize);
485             printf("\n");
486         }
487     }
488
489     printf("\tret%c\n", X86Size);
490     printf("\t.cfi_endproc\n");
491 }
492
493 void
494 InsnLABEL(RASParser *p __unused, rinsn_t *rin)
495 {
496     printf(".L%d%s:\n", ProcNo, rin->label->id);
497 }
498
499 void
500 InsnMOVE(RASParser *p, rinsn_t *rin)
501 {
502     if (rin->arg1.rea->eamode == EA_MEMORY &&
503         rin->arg2.rea->eamode == EA_MEMORY &&
504         rin->ext1 == REXT_I128) {
505         rin->arg1.flags |= RAF_FLOAT;
506         rin->arg2.flags |= RAF_FLOAT;
507     }
508     if (rin->arg1.rea->eamode == EA_MEMORY)
509         doInsnMR2NoReadDst(p, rin, "mov", 0);
510     else
511         doInsnRM2NoReadDst(p, rin, "mov", 0);
512 }
513
514 void
515 InsnADD(RASParser *p, rinsn_t *rin)
516 {
517     doInsnRMMR3(p, rin, "add");
518 }
519
520 void
521 InsnSUB(RASParser *p, rinsn_t *rin)
522 {
523     doInsnRMMR3(p, rin, "sub");
524 }
525
526 void
527 InsnAND(RASParser *p, rinsn_t *rin)
528 {
529     doInsnRMMR3(p, rin, "and");
530 }
531
532 void
533 InsnOR(RASParser *p, rinsn_t *rin)
534 {
535     doInsnRMMR3(p, rin, "or");
536 }
537
538 void
539 InsnXOR(RASParser *p, rinsn_t *rin)
540 {
541     doInsnRMMR3(p, rin, "xor");
542 }
543
544 void
545 InsnNOT(RASParser *p, rinsn_t *rin)
546 {
547     static rea_t xrcx;
548
549     if (rin->operands == 1 || rin->ext1 == rin->ext2) {
550         if (rin->ext1 == REXT_I8) {
551             printf("\tcmp%s\t$0, ", x86ext(rin->ext1, 0));
552             printEA(rin->arg1.rea, rin->ext1);
553             printf("\n");
554             printf("\tsete\t");
555             if (rin->operands == 1)
556                 printEA(rin->arg1.rea, rin->ext1);
557             else
558                 printEA(rin->arg2.rea, rin->ext1);
559         } else {
560             xrcx.target_reg = X86_REG_RCX;
561             xrcx.eamode = EA_DIRECT;
562             printf("\txorl\t%%ecx, %%ecx\n");
563             printf("\tcmp%s\t$0, ", x86ext(rin->ext1, 0));
564             printEA(rin->arg1.rea, rin->ext1);
565             printf("\n");
566             printf("\tsete\t%%cl\n");
567             if (rin->operands == 1)
568                 doMOVE(p, rin, &xrcx, rin->arg1.rea);
569             else
570                 doMOVE(p, rin, &xrcx, rin->arg2.rea);
571         }
572         printf("\n");
573     } else {
574         dassert(rin->operands == 2);
575         printf("\tcmp%s\t$0, ", x86ext(rin->ext1, 0));
576         printEA(rin->arg1.rea, rin->ext1);
577         printf("\n");
578         printf("\tsete\t");
579         printEA(rin->arg2.rea, rin->ext2);
580         printf("\n");
581     }
582 }
583
584 void
585 InsnCOM(RASParser *p, rinsn_t *rin)
586 {
587     doInsn1R(p, rin, "not", "xor", "$-1");
588 }
589
590 void
591 InsnNEG(RASParser *p, rinsn_t *rin)
592 {
593     doInsn1R(p, rin, "neg", NULL, NULL);
594 }
595
596 void
597 InsnPOS(RASParser *p, rinsn_t *rin)
598 {
599     InsnMOVE(p, rin);
600 }
601
602 void
603 InsnASL(RASParser *p, rinsn_t *rin)
604 {
605     doInsnSHIFT3(p, rin, "sal");
606 }
607
608 void
609 InsnASR(RASParser *p, rinsn_t *rin)
610 {
611     doInsnSHIFT3(p, rin, "sar");
612 }
613
614 void
615 InsnLSR(RASParser *p, rinsn_t *rin)
616 {
617     doInsnSHIFT3(p, rin, "shr");
618 }
619
620 void
621 InsnADDC(RASParser *p __unused, rinsn_t *rin __unused)
622 {
623     dpanic("ADDC not supported");
624 }
625
626 void
627 InsnSUBC(RASParser *p __unused, rinsn_t *rin __unused)
628 {
629     dpanic("SUBC not supported");
630 }
631
632
633 void
634 InsnMULU(RASParser *p, rinsn_t *rin)
635 {
636     doInsnDXAX3(p, rin, "mul", 0, 0);
637     /* doInsnMR3(p, rin, "imul"); *//* imul work for signed? */
638 }
639
640 void
641 InsnMULS(RASParser *p, rinsn_t *rin)
642 {
643     doInsnMR3(p, rin, "imul", 0);
644 }
645
646 /*
647  * WARNING: Intermediate value in %rdx:%rax
648  */
649 void
650 InsnDIVU(RASParser *p, rinsn_t *rin)
651 {
652     doInsnDXAX3(p, rin, "div", 0, 0);
653 }
654
655 /*
656  * WARNING: Intermediate value in %rdx:%rax
657  */
658 void
659 InsnDIVS(RASParser *p, rinsn_t *rin)
660 {
661     doInsnDXAX3(p, rin, "idiv", 1, 0);
662 }
663
664 void
665 InsnMODU(RASParser *p, rinsn_t *rin)
666 {
667     doInsnDXAX3(p, rin, "div", 0, 1);   /* result in %*dx */
668 }
669
670 void
671 InsnMODS(RASParser *p, rinsn_t *rin)
672 {
673     doInsnDXAX3(p, rin, "idiv", 1, 1);  /* result in %*dx */
674 }
675
676
677 void
678 InsnINC(RASParser *p, rinsn_t *rin)
679 {
680     doInsn1R(p, rin, "inc", "add", "$1");
681 }
682
683 void
684 InsnDEC(RASParser *p, rinsn_t *rin)
685 {
686     doInsn1R(p, rin, "dec", "sub", "$1");
687 }
688
689
690 void
691 InsnCMP(RASParser *p, rinsn_t *rin)
692 {
693     rea_t  *sea1;
694     rea_t  *sea2;
695     int     rev;
696
697     /*
698      * Issue comparison
699      */
700     rev = InsnSimplifyRMMRCMP(p, rin, &sea1, &sea2);
701     printf("\tcmp%s\t", x86ext(rin->ext1, 0));
702     printEA(sea1, rin->ext1);
703     printf(", ");
704     printEA(sea2, rin->ext1);
705     printf("\n");
706
707
708     if (rin->flags & RINSF_BRANCH) {
709         /*
710          * Compare and branch.  Invert sense if we can optimize the jmp.
711          */
712         if (adjacentLabel(rin, rin->brtrue)) {
713             /*
714              * next insn matches true path, invert and branch on-false.
715              */
716             printf("\tj%s\t", x86branch(rin->op, 1, rev));
717             printBRLabel(rin->brfalse);
718             printf("\n");
719         } else if (adjacentLabel(rin, rin->brfalse)) {
720             /*
721              * next insn matches false path, do not invert and branch
722              * on-true.
723              */
724             printf("\tj%s\t", x86branch(rin->op, 0, rev));
725             printBRLabel(rin->brtrue);
726             printf("\n");
727         } else {
728             /*
729              * next insn does not match either path.
730              */
731             printf("\tj%s\t", x86branch(rin->op, 0, rev));
732             printBRLabel(rin->brtrue);
733             printf("\n");
734             printf("\tjmp\t");
735             printBRLabel(rin->brfalse);
736             printf("\n");
737         }
738     } else {
739         /*
740          * Compare and set result
741          */
742         printf("\tset%s\t", x86branch(rin->op, 0, rev));
743         printEA(rin->arg3.rea, REXT_I8);
744         printf("\n");
745     }
746 }
747
748
749 void
750 InsnMOVEA(RASParser *p, rinsn_t *rin)
751 {
752     InsnMOVE(p, rin);
753 }
754
755 void
756 InsnADDA(RASParser *p, rinsn_t *rin)
757 {
758     InsnADD(p, rin);
759 }
760
761 void
762 InsnSUBA(RASParser *p, rinsn_t *rin)
763 {
764     InsnSUB(p, rin);
765 }
766
767 void
768 InsnADDAU(RASParser *p, rinsn_t *rin)
769 {
770     InsnADD(p, rin);
771 }
772
773 void
774 InsnSUBAU(RASParser *p, rinsn_t *rin)
775 {
776     InsnSUB(p, rin);
777 }
778
779 void
780 InsnSUBAA(RASParser *p, rinsn_t *rin)
781 {
782     InsnSUB(p, rin);
783 }
784
785 void
786 InsnLEA(RASParser *p, rinsn_t *rin)
787 {
788     rea_t  *rea1 = rin->arg1.rea;
789     rea_t  *rea2 = rin->arg2.rea;
790
791     if (rea1->eamode != EA_MEMORY) {
792         doInsnRM2NoReadDst(p, rin, "mov", 0);
793     } else if (rea1->eamode == EA_MEMORY && rea1->sym == NULL &&
794                rea1->direct->target_reg && rea1->offset == 0) {
795         doMOVE(p, rin, rea1->direct, rea2);
796     } else {
797         doInsnMR2NoReadDst(p, rin, "lea", ExtSize);
798     }
799 }
800
801
802 /*
803  * BCOPY.align bytes,sea,dea    (non-overlapping guaranteed)
804  */
805 void
806 InsnBCOPY(RASParser *p, rinsn_t *rin)
807 {
808     static rea_t xrdi;
809     static rea_t xrsi;
810     static rea_t xrcx;
811
812     xrdi.target_reg = X86_REG_RDI;
813     xrdi.eamode = EA_DIRECT;
814     xrsi.target_reg = X86_REG_RSI;
815     xrsi.eamode = EA_DIRECT;
816     xrcx.target_reg = X86_REG_RCX;
817     xrcx.eamode = EA_DIRECT;
818
819     printf("\tcld\n");
820     doMOVEExt(p, rin, rin->arg1.rea, &xrcx, ExtSize);
821     doLEA(p, rin->arg2.rea, &xrsi);
822     doLEA(p, rin->arg3.rea, &xrdi);
823     printf("\trep\n");
824     printf("\tmovsb\n");
825 }
826
827 /*
828  * BZERO.align bytes,dea
829  */
830 void
831 InsnBZERO(RASParser *p, rinsn_t *rin)
832 {
833     static rea_t xrax __unused;
834     static rea_t xrdi;
835     static rea_t xrcx;
836     static rea_t xmm0 __unused;
837     rea_t   rea2;
838     urunesize_t value __unused;
839
840     xrax.target_reg = X86_REG_RAX;
841     xrax.eamode = EA_DIRECT;
842     xrdi.target_reg = X86_REG_RDI;
843     xrdi.eamode = EA_DIRECT;
844     xrcx.target_reg = X86_REG_RCX;
845     xrcx.eamode = EA_DIRECT;
846     xmm0.target_reg = X86_REG_XMM0;
847     xmm0.eamode = EA_DIRECT;
848
849     if (rin->arg1.rea->eamode == EA_IMMEDIATE)
850         value = rin->arg1.rea->immlo;
851     else
852         value = 0;
853
854     /* retain zerod register optimizations for mixed BZEROs */
855     p->opt_flags |= p->opt_last & (RASOPT_RAX_ZERO | RASOPT_XMM0_ZERO);
856
857     rea2 = *rin->arg2.rea;
858     if (rin->ext2 == REXT_I8 && value <= 4) {
859         dassert(value == 1 || rea2.eamode == EA_MEMORY);
860         if (p->opt_last & RASOPT_RAX_ZERO)
861             printf("\t# xorl\t%%eax, %%eax\n");
862         else
863             printf("\txorl\t%%eax, %%eax\n");
864         p->opt_flags |= RASOPT_RAX_ZERO;
865         while (value > 0) {
866             doMOVEExt(p, rin, &xrax, &rea2, rin->ext2);
867             rea2.offset += 2;
868             value -= 2;
869         }
870     } else if (rin->ext2 == REXT_I16 && (value & 1) == 0 && value <= 8) {
871         dassert(value == 2 || rea2.eamode == EA_MEMORY);
872         if (p->opt_last & RASOPT_RAX_ZERO)
873             printf("\t# xorl\t%%eax, %%eax\n");
874         else
875             printf("\txorl\t%%eax, %%eax\n");
876         p->opt_flags |= RASOPT_RAX_ZERO;
877         while (value > 0) {
878             doMOVEExt(p, rin, &xrax, &rea2, rin->ext2);
879             rea2.offset += 2;
880             value -= 2;
881         }
882     } else if (rin->ext2 == REXT_I32 && (value & 3) == 0 && value <= 16) {
883         dassert(value == 4 || rea2.eamode == EA_MEMORY);
884         if (p->opt_last & RASOPT_RAX_ZERO)
885             printf("\t# xorl\t%%eax, %%eax\n");
886         else
887             printf("\txorl\t%%eax, %%eax\n");
888         p->opt_flags |= RASOPT_RAX_ZERO;
889         while (value > 0) {
890             doMOVEExt(p, rin, &xrax, &rea2, rin->ext2);
891             rea2.offset += 4;
892             value -= 4;
893         }
894     } else if (rin->ext2 == REXT_I64 && (value & 7) == 0 && value <= 40 &&
895                ExtSize == REXT_I64) {
896         dassert(value == 8 || rea2.eamode == EA_MEMORY);
897         if (p->opt_last & RASOPT_RAX_ZERO)
898             printf("\t# xorl\t%%eax, %%eax\n");
899         else
900             printf("\txorl\t%%eax, %%eax\n");
901         p->opt_flags |= RASOPT_RAX_ZERO;
902         while (value > 0) {
903             doMOVEExt(p, rin, &xrax, &rea2, rin->ext2);
904             rea2.offset += 8;
905             value -= 8;
906         }
907     } else if (rin->ext2 == REXT_I128 && (value & 15) == 0 && value <= 80) {
908         dassert(value == 16 || rea2.eamode == EA_MEMORY);
909         if (p->opt_last & RASOPT_XMM0_ZERO)
910             printf("\t# pxor\t%%xmm0, %%xmm0\n");
911         else
912             printf("\tpxor\t%%xmm0, %%xmm0\n");
913         p->opt_flags |= RASOPT_XMM0_ZERO;
914         while (value > 0) {
915             doMOVEExt(p, rin, &xmm0, &rea2,
916                       rin->ext2 | REXTF_FLOAT);
917             rea2.offset += 16;
918             value -= 16;
919         }
920     } else {
921         printf("\tcld\n");
922         printf("\txorl\t%%eax, %%eax\n");
923         doMOVEExt(p, rin, rin->arg1.rea, &xrcx, ExtSize);
924         doLEA(p, &rea2, &xrdi);
925         printf("\trep\n");
926         printf("\tstosb\n");
927     }
928 }
929
930
931 void
932 InsnCMPTYPE(RASParser *p, rinsn_t *rin)
933 {
934     static rea_t xarg1;
935     static rea_t xarg2;
936     static rea_t xrax;
937
938     xarg1.target_reg = X86_RUNTIME_ARG1;
939     xarg1.eamode = EA_DIRECT;
940     xarg2.target_reg = X86_RUNTIME_ARG2;
941     xarg2.eamode = EA_DIRECT;
942
943     doLEA(p, rin->arg1.rea, &xarg1);
944     doLEA(p, rin->arg2.rea, &xarg2);
945     doSpecialSave(rin);
946     printf("\tcall\tRuneRunTime_SWCmpType\n");
947     doSpecialRestore(rin);
948     if (rin->flags & RINSF_BRANCH) {
949         xrax.target_reg = X86_REG_RAX;
950         xrax.eamode = EA_DIRECT;
951         printf("\tcmp%c\t$0, ", X86Size);
952         printEA(&xrax, ExtSize);
953         printf("\n");
954         if (adjacentLabel(rin, rin->brtrue)) {
955             /*
956              * next insn matches true path, invert and branch on-false.
957              */
958             printf("\tje\t");
959             printBRLabel(rin->brfalse);
960         } else if (adjacentLabel(rin, rin->brfalse)) {
961             /*
962              * next insn matches false path, do not invert and branch
963              * on-true.
964              */
965             printf("\tjne\t");
966             printBRLabel(rin->brtrue);
967         } else {
968             /*
969              * next insn does not match either path.
970              */
971             printf("\tjne\t");
972             printBRLabel(rin->brtrue);
973             printf("\n");
974             printf("\tjmp\t");
975             printBRLabel(rin->brfalse);
976         }
977         printf("\n");
978     } else {
979         xrax.target_reg = X86_REG_RAX;
980         xrax.eamode = EA_DIRECT;
981         doMOVEExt(p, rin, &xrax, rin->arg3.rea, REXT_I8);
982     }
983 }
984
985
986 /*
987  * Cast unsigned integer to size
988  */
989 void
990 InsnCASTU(RASParser *p, rinsn_t *rin)
991 {
992     static rea_t xrea;
993
994     if (rin->ext1 == rin->ext2) {
995         /* doMOVE(p, rin, rin->arg1.rea, rin->arg2.rea); */
996         InsnMOVE(p, rin);
997     } else if (rin->arg1.rea->eamode == EA_IMMEDIATE ||
998                rin->arg1.rea->eamode == EA_IMMEDIATE16) {
999         doMOVEExt(p, rin, rin->arg1.rea, rin->arg2.rea, REXTF_EA2);
1000     } else if (rin->ext1 < rin->ext2) {
1001         switch (rin->ext1) {
1002         case REXT_I8:
1003             doInsnMR2NoReadDst(p, rin, "movzb",
1004                                REXTF_SEA1 | REXTF_EA2);
1005             break;
1006         case REXT_I16:
1007             doInsnMR2NoReadDst(p, rin, "movzw",
1008                                REXTF_SEA1 | REXTF_EA2);
1009             break;
1010         case REXT_I32:
1011             if (rin->arg1.rea->eamode == EA_MEMORY) {
1012                 xrea.target_reg = X86_REG_RCX;
1013                 xrea.eamode = EA_DIRECT;
1014                 doMOVEExt(p, rin, rin->arg1.rea, &xrea,
1015                           REXT_I32);
1016                 printINSN(rin, "mov", &xrea, rin->arg2.rea,
1017                           REXTF_EA2);
1018             } else {
1019                 doMOVEExt(p, rin, rin->arg1.rea, rin->arg1.rea,
1020                           REXT_I32);
1021                 printINSN(rin, "mov",
1022                           rin->arg1.rea, rin->arg2.rea,
1023                           REXTF_EA2);
1024             }
1025             break;
1026         default:
1027             dpanic("Unknown/unsupported REXT %d", rin->ext1);
1028             break;
1029         }
1030     } else {
1031         if (rin->arg1.rea->eamode == EA_MEMORY) {
1032             xrea.target_reg = X86_REG_RCX;
1033             xrea.eamode = EA_DIRECT;
1034             doMOVE(p, rin, rin->arg1.rea, &xrea);
1035             printINSN(rin, "mov", &xrea, rin->arg2.rea, REXTF_EA2);
1036         } else {
1037             printINSN(rin, "mov", rin->arg1.rea, rin->arg2.rea,
1038                       REXTF_EA2);
1039         }
1040     }
1041 }
1042
1043 /*
1044  * Cast signed integer to size
1045  */
1046 void
1047 InsnCASTS(RASParser *p, rinsn_t *rin)
1048 {
1049     static rea_t xrea;
1050
1051     if (rin->ext1 == rin->ext2) {
1052         /* doMOVE(p, rin, rin->arg1.rea, rin->arg2.rea); */
1053         InsnMOVE(p, rin);
1054     } else if (rin->arg1.rea->eamode == EA_IMMEDIATE ||
1055                rin->arg1.rea->eamode == EA_IMMEDIATE16) {
1056         doMOVEExt(p, rin, rin->arg1.rea, rin->arg2.rea, REXTF_EA2);
1057     } else if (rin->ext1 < rin->ext2) {
1058         switch (rin->ext1) {
1059         case REXT_I8:
1060             doInsnMR2NoReadDst(p, rin, "movsb",
1061                                REXTF_SEA1 | REXTF_EA2);
1062             break;
1063         case REXT_I16:
1064             doInsnMR2NoReadDst(p, rin, "movsw",
1065                                REXTF_SEA1 | REXTF_EA2);
1066             break;
1067         case REXT_I32:
1068             doInsnMR2NoReadDst(p, rin, "movsl",
1069                                REXTF_SEA1 | REXTF_EA2);
1070             break;
1071         default:
1072             dpanic("Unknown/unsupported REXT %d", rin->ext1);
1073             break;
1074         }
1075     } else {
1076         if (rin->arg1.rea->eamode == EA_MEMORY) {
1077             xrea.target_reg = X86_REG_RCX;
1078             xrea.eamode = EA_DIRECT;
1079             doMOVE(p, rin, rin->arg1.rea, &xrea);
1080             printINSN(rin, "mov", &xrea, rin->arg2.rea, REXTF_EA2);
1081         } else {
1082             printINSN(rin, "mov", rin->arg1.rea, rin->arg2.rea,
1083                       REXTF_EA2);
1084         }
1085     }
1086 }
1087
1088 /*
1089  * CASTP - Cast a pointer to an integer.
1090  */
1091 void
1092 InsnCASTP(RASParser *p, rinsn_t *rin)
1093 {
1094     InsnCASTS(p, rin);
1095 }
1096
1097 static
1098 void
1099 insnZeroArgNoReturn(RASParser *p __unused, rinsn_t *rin, const char *fname)
1100 {
1101     doSpecialSave(rin);
1102     printf("\tcall\tRuneRunTime_%s\n", fname);
1103     doSpecialRestore(rin);
1104 }
1105
1106 #if 0
1107 /*
1108  * Used to be used to obtain implicit context, e.g. STKIGET.  We may have
1109  * a use for this later so keep it around.
1110  */
1111 static
1112 void
1113 insnZeroArgRet(RASParser *p, rinsn_t *rin, const char *fname)
1114 {
1115     static rea_t xrax;
1116
1117     xrax.target_reg = X86_REG_RAX;
1118     xrax.eamode = EA_DIRECT;
1119
1120     doSpecialSave(rin);
1121     printf("\tcall\tRuneRunTime_%s\n", fname);
1122     doSpecialRestore(rin);
1123     if ((rin->arg2.flags & RAF_LIFE_END) == 0) {
1124         xrax.target_reg = X86_REG_RAX;
1125         xrax.eamode = EA_DIRECT;
1126         doMOVEExt(p, rin, &xrax, rin->arg1.rea, ExtSize);
1127     }
1128 }
1129 #endif
1130
1131 static
1132 void
1133 insnOneArgNoReturn(RASParser *p, rinsn_t *rin, const char *fname)
1134 {
1135     static rea_t xarg1;
1136
1137     xarg1.target_reg = X86_RUNTIME_ARG1;
1138     xarg1.eamode = EA_DIRECT;
1139
1140     doLEA(p, rin->arg1.rea, &xarg1);
1141     doSpecialSave(rin);
1142     printf("\tcall\tRuneRunTime_%s\n", fname);
1143     doSpecialRestore(rin);
1144 }
1145
1146 static
1147 void
1148 insnOneArg32NoReturn(RASParser *p, rinsn_t *rin, const char *fname)
1149 {
1150     static rea_t xarg1;
1151
1152     xarg1.target_reg = X86_RUNTIME_ARG1;
1153     xarg1.eamode = EA_DIRECT;
1154
1155     doMOVE(p, rin, rin->arg1.rea, &xarg1);
1156     doSpecialSave(rin);
1157     printf("\tcall\tRuneRunTime_%s\n", fname);
1158     doSpecialRestore(rin);
1159 }
1160
1161 #if 0
1162 /*
1163  * Used to be used for e.g. PIGET but we may have a use for it again later,
1164  * so keep it around.
1165  */
1166 static
1167 void
1168 insnOneArgRet(RASParser *p, rinsn_t *rin, const char *fname)
1169 {
1170     static rea_t xarg1;
1171     static rea_t xrax;
1172
1173     xarg1.target_reg = X86_RUNTIME_ARG1;
1174     xarg1.eamode = EA_DIRECT;
1175     doLEA(p, rin->arg1.rea, &xarg1);
1176
1177     doSpecialSave(rin);
1178     printf("\tcall\tRuneRunTime_%s\n", fname);
1179     doSpecialRestore(rin);
1180
1181     if ((rin->arg2.flags & RAF_LIFE_END) == 0) {
1182         xrax.target_reg = X86_REG_RAX;
1183         xrax.eamode = EA_DIRECT;
1184         doMOVEExt(p, rin, &xrax, rin->arg2.rea, ExtSize);
1185     }
1186 }
1187 #endif
1188
1189 #if 0
1190 /*
1191  * Used to be used for PCOPY but we may have a use for it again later,
1192  * so keep it around.
1193  */
1194 static
1195 void
1196 insnTwoArgNoReturn(RASParser *p, rinsn_t *rin, const char *fname)
1197 {
1198     static rea_t xarg1;
1199     static rea_t xarg2;
1200
1201     xarg1.target_reg = X86_RUNTIME_ARG1;
1202     xarg1.eamode = EA_DIRECT;
1203     xarg2.target_reg = X86_RUNTIME_ARG2;
1204     xarg2.eamode = EA_DIRECT;
1205
1206     doLEA(p, rin->arg1.rea, &xarg1);
1207     doLEA(p, rin->arg2.rea, &xarg2);
1208     doSpecialSave(rin);
1209     printf("\tcall\tRuneRunTime_%s\n", fname);
1210     doSpecialRestore(rin);
1211 }
1212 #endif
1213
1214 #if 0
1215 static
1216 void
1217 insnTwoArgRet(RASParser *p, rinsn_t *rin, const char *fname)
1218 {
1219     static rea_t xarg1;
1220     static rea_t xarg2;
1221     static rea_t xrax;
1222
1223     xarg1.target_reg = X86_RUNTIME_ARG1;
1224     xarg1.eamode = EA_DIRECT;
1225     doLEA(p, rin->arg1.rea, &xarg1);
1226
1227     xarg2.target_reg = X86_RUNTIME_ARG2;
1228     xarg2.eamode = EA_DIRECT;
1229     doLEA(p, rin->arg2.rea, &xarg2);
1230
1231     doSpecialSave(rin);
1232     printf("\tcall\tRuneRunTime_%s\n", fname);
1233     doSpecialRestore(rin);
1234
1235     xrax.target_reg = X86_REG_RAX;
1236     xrax.eamode = EA_DIRECT;
1237     doMOVEExt(p, rin, &xrax, rin->arg3.rea, ExtSize);
1238 }
1239 #endif
1240
1241 #if 0
1242 void
1243 InsnPCOPY(RASParser *p, rinsn_t *rin)
1244 {
1245     insnTwoArgNoReturn(p, rin, "PCopy");
1246 }
1247 #endif
1248
1249 /*
1250  * Reference context routines
1251  */
1252 void
1253 InsnPGET(RASParser *p, rinsn_t *rin)
1254 {
1255     insnOneArgNoReturn(p, rin, "PGet");
1256 }
1257
1258 void
1259 InsnPGETH(RASParser *p, rinsn_t *rin)
1260 {
1261     insnOneArgNoReturn(p, rin, "PGetH");
1262 }
1263
1264 void
1265 InsnPPUT(RASParser *p, rinsn_t *rin)
1266 {
1267     insnOneArgNoReturn(p, rin, "PPut");
1268 }
1269
1270 void
1271 InsnPPUTH(RASParser *p, rinsn_t *rin)
1272 {
1273     insnOneArgNoReturn(p, rin, "PPutH");
1274 }
1275
1276 void
1277 InsnPREF(RASParser *p, rinsn_t *rin)
1278 {
1279     insnOneArgNoReturn(p, rin, "PRef");
1280 }
1281
1282 void
1283 InsnPREL(RASParser *p, rinsn_t *rin)
1284 {
1285     insnOneArgNoReturn(p, rin, "PRel");
1286 }
1287
1288 void
1289 InsnPLOCK(RASParser *p, rinsn_t *rin)
1290 {
1291     insnOneArgNoReturn(p, rin, "PLock");
1292 }
1293
1294 void
1295 InsnPLOCKH(RASParser *p, rinsn_t *rin)
1296 {
1297     insnOneArgNoReturn(p, rin, "PLockH");
1298 }
1299
1300 void
1301 InsnPUNLOCK(RASParser *p, rinsn_t *rin)
1302 {
1303     insnOneArgNoReturn(p, rin, "PUnlock");
1304 }
1305
1306 void
1307 InsnPUNLOCKH(RASParser *p, rinsn_t *rin)
1308 {
1309     insnOneArgNoReturn(p, rin, "PUnlockH");
1310 }
1311
1312 /*
1313  * Object context routines
1314  */
1315 void
1316 InsnIGET(RASParser *p, rinsn_t *rin)
1317 {
1318     insnOneArgNoReturn(p, rin, "IGet");
1319 }
1320
1321 void
1322 InsnIGETH(RASParser *p, rinsn_t *rin)
1323 {
1324     insnOneArgNoReturn(p, rin, "IGetH");
1325 }
1326
1327 void
1328 InsnIPUT(RASParser *p, rinsn_t *rin)
1329 {
1330     insnOneArgNoReturn(p, rin, "IPut");
1331 }
1332
1333 void
1334 InsnIPUTH(RASParser *p, rinsn_t *rin)
1335 {
1336     insnOneArgNoReturn(p, rin, "IPutH");
1337 }
1338
1339 void
1340 InsnIREF(RASParser *p, rinsn_t *rin)
1341 {
1342     insnOneArgNoReturn(p, rin, "IRef");
1343 }
1344
1345 void
1346 InsnIREL(RASParser *p, rinsn_t *rin)
1347 {
1348     insnOneArgNoReturn(p, rin, "IRel");
1349 }
1350
1351 void
1352 InsnILOCK(RASParser *p, rinsn_t *rin)
1353 {
1354     insnOneArgNoReturn(p, rin, "ILock");
1355 }
1356
1357 void
1358 InsnILOCKH(RASParser *p, rinsn_t *rin)
1359 {
1360     insnOneArgNoReturn(p, rin, "ILockH");
1361 }
1362
1363 void
1364 InsnIUNLOCK(RASParser *p, rinsn_t *rin)
1365 {
1366     insnOneArgNoReturn(p, rin, "IUnlock");
1367 }
1368
1369 void
1370 InsnIUNLOCKH(RASParser *p, rinsn_t *rin)
1371 {
1372     insnOneArgNoReturn(p, rin, "IUnlockH");
1373 }
1374
1375 void
1376 InsnLVALLOC(RASParser *p, rinsn_t *rin)
1377 {
1378     static rea_t xarg1;
1379     static rea_t xarg2;
1380     static rea_t xrax;
1381
1382     xarg1.target_reg = X86_RUNTIME_ARG1;
1383     xarg1.eamode = EA_DIRECT;
1384     doLEA(p, rin->arg1.rea, &xarg1);
1385
1386     xarg2.target_reg = X86_RUNTIME_ARG2;
1387     xarg2.eamode = EA_DIRECT;
1388     doLEA(p, rin->arg2.rea, &xarg2);
1389
1390     doSpecialSave(rin);
1391     printf("\tcall\tRuneRunTime_LVAlloc\n");
1392     doSpecialRestore(rin);
1393
1394     if ((rin->arg3.flags & RAF_LIFE_END) == 0) {
1395         xrax.target_reg = X86_REG_RAX;
1396         xrax.eamode = EA_DIRECT;
1397         doMOVEExt(p, rin, &xrax, rin->arg3.rea, REXT_I8);
1398     }
1399 }
1400
1401 void
1402 InsnBCHECK(RASParser *p, rinsn_t *rin)
1403 {
1404     rea_t  *sea1;
1405     rea_t  *sea2;
1406     int     rev;
1407
1408     /*
1409      * Issue comparison, branch past bounds trap if valid.
1410      *
1411      * WARNING!  BCHECK instruction regs assume that BoundsTrap never
1412      * returns, does not save/restore registers.
1413      */
1414     rev = InsnSimplifyRMMRCMP(p, rin, &sea1, &sea2);
1415     printf("\tcmp%s\t", x86ext(rin->ext1, 0));
1416     printEA(sea1, rin->ext1);
1417     printf(", ");
1418     printEA(sea2, rin->ext1);
1419     printf("\n");
1420     if (rev)
1421         printf("\tjb\t1f\n");
1422     else
1423         printf("\tjae\t1f\n");
1424     printf("\tcall\tRuneRunTime_BoundsTrap\n");
1425     printf("1:\n");
1426 }
1427
1428 void
1429 InsnBNDTRAP(RASParser *p __unused, rinsn_t *rin __unused)
1430 {
1431     printf("\tcall\tRuneRunTime_BoundsTrap\n");
1432 }
1433
1434 void
1435 InsnCMPA(RASParser *p, rinsn_t *rin)
1436 {
1437     InsnCMP(p, rin);
1438 }
1439
1440 /*
1441  * Rune-Rune call
1442  */
1443 void
1444 InsnCALL(RASParser *p, rinsn_t *rin)
1445 {
1446     static rea_t xrax;
1447     static rea_t xarg1;
1448     static rea_t xarg2;
1449     static rea_t xarg3;
1450     int     doind = 0;
1451
1452     /* XXX eamode not really deterministic */
1453     if (rin->arg1.rea->eamode == EA_DIRECT || rin->arg1.rea->regno) {
1454         xrax.target_reg = X86_REG_RAX;
1455         xrax.eamode = EA_DIRECT;
1456         doMOVEExt(p, rin, rin->arg1.rea, &xrax, ExtSize);
1457         doind = 1;
1458     } else if (rin->op == INSN_TCALL) {
1459         xarg3.target_reg = X86_RUNE_ARG3;
1460         xarg3.eamode = EA_DIRECT;
1461         doLEA(p, rin->arg1.rea, &xarg3);
1462     }
1463
1464     xarg1.target_reg = X86_RUNE_ARG1;
1465     xarg1.eamode = EA_DIRECT;
1466     xarg2.target_reg = X86_RUNE_ARG2;
1467     xarg2.eamode = EA_DIRECT;
1468     if (rin->arg4.rea) {
1469         dassert(rin->op != INSN_TCALL); /* XXX fixme */
1470         xarg3.target_reg = X86_RUNE_ARG3;
1471         xarg3.eamode = EA_DIRECT;
1472         if (rin->arg4.rea->eamode == EA_DIRECT ||
1473             rin->arg4.rea->regno) {
1474             doMOVEExt(p, rin, rin->arg4.rea, &xarg3, ExtSize);
1475         } else {
1476             doLEA(p, rin->arg4.rea, &xarg3);
1477         }
1478     }
1479     if (rin->arg2.rea)
1480         doLEA(p, rin->arg2.rea, &xarg1);
1481     if (rin->arg3.rea)
1482         doLEA(p, rin->arg3.rea, &xarg2);
1483     doSpecialSave(rin);
1484     if (rin->op == INSN_TCALL) {
1485         printf("\tcall\tRuneRunTime_ThreadedCall\n");
1486     } else if (doind) {
1487         if (ExtSize == REXT_I32)
1488             printf("\tcall\t*%%eax\n");
1489         else
1490             printf("\tcall\t*%%rax\n");
1491     } else {
1492         printf("\tcall\t");
1493         printEA(rin->arg1.rea, ExtSize);
1494         printf("\n");
1495     }
1496     doSpecialRestore(rin);
1497 }
1498
1499 /*
1500  * Rune-Rune threaded call
1501  */
1502 void
1503 InsnTCALL(RASParser *p, rinsn_t *rin)
1504 {
1505     InsnCALL(p, rin);
1506 }
1507
1508 void
1509 InsnLCALL(RASParser *p __unused, rinsn_t *rin __unused)
1510 {
1511     printf("\t#XXX\n");
1512 }
1513
1514 /*
1515  * System interfacing call (e.g. native libc, system call, etc)
1516  */
1517 void
1518 InsnQCALL(RASParser *p, rinsn_t *rin)
1519 {
1520     static rea_t xrax;
1521     static rea_t xarg1;
1522     static rea_t xarg2;
1523     int     doind = 0;
1524
1525     /* XXX eamode not really deterministic */
1526     if (rin->arg1.rea->eamode == EA_DIRECT || rin->arg1.rea->regno) {
1527         xrax.target_reg = X86_REG_RAX;
1528         xrax.eamode = EA_DIRECT;
1529         doMOVEExt(p, rin, rin->arg1.rea, &xrax, ExtSize);
1530         doind = 1;
1531     }
1532
1533     xarg1.target_reg = X86_SYS_ARG1;
1534     xarg1.eamode = EA_DIRECT;
1535     xarg2.target_reg = X86_SYS_ARG2;
1536     xarg2.eamode = EA_DIRECT;
1537     dassert(rin->arg4.rea == NULL);
1538     if (rin->arg2.rea)
1539         doLEA(p, rin->arg2.rea, &xarg1);
1540     if (rin->arg3.rea)
1541         doLEA(p, rin->arg3.rea, &xarg2);
1542     doSpecialSave(rin);
1543     if (doind) {
1544         if (ExtSize == REXT_I32)
1545             printf("\tcall\t*%%eax\n");
1546         else
1547             printf("\tcall\t*%%rax\n");
1548     } else {
1549         printf("\tcall\t");
1550         printEA(rin->arg1.rea, ExtSize);
1551         printf("\n");
1552     }
1553     doSpecialRestore(rin);
1554 }
1555
1556 /*
1557  * RuneRunTime_*() call ABI
1558  */
1559 void
1560 InsnRCALL(RASParser *p, rinsn_t *rin)
1561 {
1562     static rea_t xrax;
1563     static rea_t xarg1;
1564     static rea_t xarg2;
1565     int     doind = 0;
1566
1567     /* XXX eamode not really deterministic */
1568     if (rin->arg1.rea->eamode == EA_DIRECT || rin->arg1.rea->regno) {
1569         xrax.target_reg = X86_REG_RAX;
1570         xrax.eamode = EA_DIRECT;
1571         doMOVEExt(p, rin, rin->arg1.rea, &xrax, ExtSize);
1572         doind = 1;
1573     }
1574
1575     xarg1.target_reg = X86_RUNTIME_ARG1;
1576     xarg1.eamode = EA_DIRECT;
1577     xarg2.target_reg = X86_RUNTIME_ARG2;
1578     xarg2.eamode = EA_DIRECT;
1579     dassert(rin->arg4.rea == NULL);
1580     if (rin->arg2.rea)
1581         doLEA(p, rin->arg2.rea, &xarg1);
1582     if (rin->arg3.rea)
1583         doLEA(p, rin->arg3.rea, &xarg2);
1584     doSpecialSave(rin);
1585     if (doind) {
1586         if (ExtSize == REXT_I32)
1587             printf("\tcall\t*%%eax\n");
1588         else
1589             printf("\tcall\t*%%rax\n");
1590     } else {
1591         printf("\tcall\t");
1592         printEA(rin->arg1.rea, ExtSize);
1593         printf("\n");
1594     }
1595     doSpecialRestore(rin);
1596 }
1597
1598 void
1599 InsnRET(RASParser *p __unused, rinsn_t *rin)
1600 {
1601     rinsn_t *scan;
1602
1603     /*
1604      * If we are at the end of the procedure we can just fall through,
1605      * otherwise jump to the return label.
1606      */
1607     scan = RUNE_NEXT(rin, node);
1608     while (scan && scan->op == INSN_LABEL)
1609         scan = RUNE_NEXT(scan, node);
1610     if (scan)
1611         printf("\tjmp\t.LRET%d\n", ProcNo);
1612 }
1613
1614 void
1615 InsnDET(RASParser *p, rinsn_t *rin)
1616 {
1617     insnZeroArgNoReturn(p, rin, "ThreadedDetach");
1618 }
1619
1620 void
1621 InsnLINK(RASParser *p __unused, rinsn_t *rin __unused)
1622 {
1623     printf("\t#XXX\n");
1624 }
1625
1626 void
1627 InsnTSCHED(RASParser *p, rinsn_t *rin)
1628 {
1629     insnOneArg32NoReturn(p, rin, "TSched");
1630 }
1631
1632 void
1633 InsnJMP(RASParser *p __unused, rinsn_t *rin)
1634 {
1635     if (!adjacentLabel(rin, rin->brtrue)) {
1636         printf("\tjmp\t");
1637         printBRLabel(rin->brtrue);
1638         printf("\n");
1639     }
1640 }
1641
1642 void
1643 InsnTEST(RASParser *p __unused, rinsn_t *rin)
1644 {
1645     const char *brtrue;
1646     const char *brfalse;
1647
1648     /*
1649      * For TEST_EQ      this is 'e' For TEST_NE this is 'ne'
1650      */
1651     brtrue = x86branch(rin->op, 0, 0);
1652     brfalse = x86branch(rin->op, 1, 0);
1653
1654     printf("\tcmp%s\t$0, ", x86ext(rin->ext1, 0));
1655     printEA(rin->arg1.rea, rin->ext1);
1656     printf("\n");
1657     if (rin->flags & RINSF_BRANCH) {
1658         if (adjacentLabel(rin, rin->brtrue)) {
1659             /*
1660              * next insn matches true path, invert and branch on-false.
1661              */
1662             printf("\tj%s\t", brfalse);
1663             printBRLabel(rin->brfalse);
1664         } else if (adjacentLabel(rin, rin->brfalse)) {
1665             /*
1666              * next insn matches false path, do not invert and branch
1667              * on-true.
1668              */
1669             printf("\tj%s\t", brtrue);
1670             printBRLabel(rin->brtrue);
1671         } else {
1672             /*
1673              * next insn does not match either path.
1674              */
1675             printf("\tj%s\t", brtrue);
1676             printBRLabel(rin->brtrue);
1677             printf("\n");
1678             printf("\tjmp\t");
1679             printBRLabel(rin->brfalse);
1680         }
1681     } else {
1682         printf("\tset%s\t", brtrue);
1683         printEA(rin->arg2.rea, REXT_I8);
1684     }
1685     printf("\n");
1686 }
1687
1688
1689 void
1690 InsnFMOVE(RASParser *p, rinsn_t *rin)
1691 {
1692     doInsnRMMR3(p, rin, "mov");
1693 }
1694
1695 void
1696 InsnFADD(RASParser *p, rinsn_t *rin)
1697 {
1698     doInsnFloating3(p, rin, "add", 0);
1699 }
1700
1701 void
1702 InsnFSUB(RASParser *p, rinsn_t *rin)
1703 {
1704     doInsnFloating3(p, rin, "sub", 0);
1705 }
1706
1707 void
1708 InsnFMUL(RASParser *p, rinsn_t *rin)
1709 {
1710     doInsnFloating3(p, rin, "mul", 0);
1711 }
1712
1713 void
1714 InsnFDIV(RASParser *p, rinsn_t *rin)
1715 {
1716     doInsnFloating3(p, rin, "div", 0);
1717 }
1718
1719 static
1720 rea_t *
1721 getFPImm(RASParser *p __unused, rinsn_t *rin, int v)
1722 {
1723     static rea_t imm;
1724     union {
1725         float   f;
1726         const   int32_t v;
1727     } uu;
1728     union {
1729         double  d;
1730         const   int64_t v;
1731     } vv;
1732     union {
1733         long double x;
1734         const   int64_t v[2];
1735     } ww;
1736
1737     switch (rin->ext1) {
1738     case REXT_I32:
1739         uu.f = (float)v;
1740         imm.eamode = EA_IMMEDIATE;
1741         imm.immlo = uu.v;
1742         imm.immhi = 0;
1743         break;
1744     case REXT_I64:
1745         vv.d = (double)v;
1746         imm.eamode = EA_IMMEDIATE;
1747         imm.immlo = vv.v;
1748         imm.immhi = 0;
1749         break;
1750     case REXT_I128:
1751         imm.eamode = EA_IMMEDIATE16;
1752         ww.x = (long double)v;
1753 #if _BYTE_ORDER == _LITTLE_ENDIAN
1754         imm.immlo = ww.v[0];
1755         imm.immhi = ww.v[1];
1756 #else
1757         imm.immlo = ww.v[1];
1758         imm.immhi = ww.v[0];
1759 #endif
1760         break;
1761     default:
1762         dpanic("Unknown/unsupported REXT %d", rin->ext1);
1763         break;
1764     }
1765     return &imm;
1766 }
1767
1768 void
1769 InsnFINC(RASParser *p, rinsn_t *rin)
1770 {
1771     static rinsn_t srin;
1772
1773     srin.operands = rin->operands + 1;
1774     srin.arg1.flags = srin.arg2.flags = srin.arg3.flags = RAF_FLOAT;
1775     srin.arg1.rea = getFPImm(p, rin, 1);
1776     srin.arg2.rea = rin->arg1.rea;
1777     srin.arg3.rea = rin->arg2.rea;
1778     srin.ext1 = rin->ext1;
1779
1780     doInsnFloating3(p, &srin, "add", 0);
1781 }
1782
1783 void
1784 InsnFDEC(RASParser *p, rinsn_t *rin)
1785 {
1786     static rinsn_t srin;
1787
1788     srin.operands = rin->operands + 1;
1789     srin.arg1.flags = srin.arg2.flags = srin.arg3.flags = RAF_FLOAT;
1790     srin.arg1.rea = getFPImm(p, rin, 1);
1791     srin.arg2.rea = rin->arg1.rea;
1792     srin.arg3.rea = rin->arg2.rea;
1793     srin.ext1 = rin->ext1;
1794
1795     doInsnFloating3(p, &srin, "sub", 0);
1796 }
1797
1798 void
1799 InsnFNEG(RASParser *p, rinsn_t *rin)
1800 {
1801     static rinsn_t srin;
1802
1803     srin.operands = 3;
1804     srin.arg1.flags = srin.arg2.flags = srin.arg3.flags = RAF_FLOAT;
1805     if (rin->operands == 1) {
1806         srin.arg1.rea = rin->arg1.rea;
1807         srin.arg2.rea = getFPImm(p, rin, 0);
1808         srin.arg3.rea = rin->arg1.rea;
1809     } else {
1810         srin.arg1.rea = rin->arg1.rea;
1811         srin.arg2.rea = getFPImm(p, rin, 0);
1812         srin.arg3.rea = rin->arg2.rea;
1813     }
1814     srin.ext1 = rin->ext1;
1815
1816     doInsnFloating3(p, &srin, "sub", 0);
1817 }
1818
1819 void
1820 InsnFPOS(RASParser *p, rinsn_t *rin)
1821 {
1822     InsnPOS(p, rin);
1823 }
1824
1825 void
1826 InsnFNOT(RASParser *p, rinsn_t *rin)
1827 {
1828
1829     dassert(rin->operands == 2);
1830     dassert(rin->ext2 == REXT_I8);
1831
1832     if (rin->ext1 != REXT_I128) {
1833         printf("\tpxor\t%%xmm0, %%xmm0\n");
1834         printf("\tucomis%c\t",
1835                ((rin->ext1 == REXT_I32) ? 's' : 'd'));
1836         printEA(rin->arg1.rea, rin->ext1);
1837         printf(", %%xmm0\n");
1838
1839         printf("\tsete\t");
1840         printEA(rin->arg2.rea, rin->ext2);
1841         printf("\n");
1842     } else {
1843         static rea_t xrea;
1844         rea_t  *sea;
1845
1846         sea = InsnSimplifyFP128(p, rin, rin->arg1.rea, &xrea,
1847                                 rin->ext1, -16, 1);
1848         printf("\tfldt\t");
1849         printEA(sea, REXT_I128);
1850         printf("\n");
1851
1852         printf("\tfldz\n");
1853         printf("\tfucomip\t%%st(1), %%st\n");
1854         printf("\tfstp\t%%st(0)\n");
1855
1856         printf("\tsete\t");
1857         printEA(rin->arg2.rea, rin->ext2);
1858         printf("\n");
1859     }
1860 }
1861
1862
1863 void
1864 InsnUITOF(RASParser *p, rinsn_t *rin)
1865 {
1866     printf("\t#XXX\n");
1867     InsnSITOF(p, rin);
1868 }
1869
1870 void
1871 InsnSITOF(RASParser *p, rinsn_t *rin)
1872 {
1873     static rea_t xsea;
1874     static rea_t xdea;
1875     static rea_t xrcx;
1876     int     isunsigned = (rin->op == INSN_UITOF);
1877
1878     if (rin->ext2 != REXT_I128) {
1879         /*
1880          * f32 and f64
1881          */
1882         xsea.target_reg = X86_REG_RCX;
1883         xsea.eamode = EA_DIRECT;
1884         xsea.offset = 0;
1885         xdea.target_reg = X86_REG_XMM0;
1886         xdea.eamode = EA_DIRECT;
1887
1888         doMOVE(p, rin, rin->arg1.rea, &xsea);
1889         if (rin->ext1 == REXT_I8) {
1890             if (isunsigned)
1891                 printf("\tmovzbl\t%%cl, %%ecx\n");
1892             else
1893                 printf("\tmovsbl\t%%cl, %%ecx\n");
1894         }
1895         if (rin->ext1 == REXT_I16) {
1896             if (isunsigned)
1897                 printf("\tmovzwl\t%%cx, %%ecx\n");
1898             else
1899                 printf("\tmovswl\t%%cx, %%ecx\n");
1900         }
1901
1902         if (rin->ext1 == REXT_I64) {
1903             printf("\tcvtsi2%sq\t%%rcx, %%xmm0\n",
1904                    x86ext(rin->ext2, RAF_FLOAT));
1905             doMOVEExt(p, rin, &xdea, rin->arg2.rea, REXTF_EA2);
1906         } else {
1907             printf("\tcvtsi2%s\t%%ecx, %%xmm0\n",
1908                    x86ext(rin->ext2, RAF_FLOAT));
1909             doMOVEExt(p, rin, &xdea, rin->arg2.rea, REXTF_EA2);
1910         }
1911     } else {
1912         rea_t  *sea;
1913         rea_t  *dea;
1914         uint8_t sext;
1915
1916         /*
1917          * SimplifyFP128 ensures that the requested argument is in memory and
1918          * not a register or immediate.  We have to do more work for signed
1919          * 8-bit quantities.
1920          */
1921         if (rin->ext1 == REXT_I8 ||
1922             (isunsigned && rin->ext1 != REXT_I64)) {
1923             xsea.target_reg = X86_REG_RSP;
1924             xsea.eamode = EA_MEMORY;
1925             xsea.offset = -16;
1926             sea = &xsea;
1927         } else {
1928             sea = InsnSimplifyFP128(p, rin, rin->arg1.rea, &xsea,
1929                                     rin->ext1, -16, 1);
1930         }
1931
1932         dea = InsnSimplifyFP128(p, rin, rin->arg2.rea, &xdea,
1933                                 rin->ext2, -32, 0);
1934
1935         switch (rin->ext1) {
1936         case REXT_I8:
1937             xrcx.target_reg = X86_REG_RCX;
1938             xrcx.eamode = EA_DIRECT;
1939             xrcx.offset = 0;
1940             doMOVEExt(p, rin, rin->arg1.rea, &xrcx,
1941                       rin->ext1 | REXTF_SEA1);
1942             if (isunsigned)
1943                 printf("\tmovzbw\t%%cl, %%cx\n");
1944             else
1945                 printf("\tmovsbw\t%%cl, %%cx\n");
1946             doMOVEExt(p, rin, &xrcx, sea, REXT_I16);
1947             sext = REXT_I16;
1948             printf("\tfilds\t");
1949             break;
1950         case REXT_I16:
1951             if (isunsigned) {
1952                 xrcx.target_reg = X86_REG_RCX;
1953                 xrcx.eamode = EA_DIRECT;
1954                 xrcx.offset = 0;
1955                 doMOVEExt(p, rin, rin->arg1.rea, &xrcx,
1956                           rin->ext1 | REXTF_SEA1);
1957                 printf("\tmovzwl\t%%cx, %%ecx\n");
1958                 doMOVEExt(p, rin, &xrcx, sea, REXT_I32);
1959                 sext = REXT_I32;
1960                 printf("\tfildl\t");
1961             } else {
1962                 sext = REXT_I16;
1963                 printf("\tfilds\t");
1964             }
1965             break;
1966         case REXT_I32:
1967             if (isunsigned) {
1968                 xrcx.target_reg = X86_REG_RCX;
1969                 xrcx.eamode = EA_DIRECT;
1970                 xrcx.offset = 0;
1971                 /* moves to %e* zero-ext to %r* */
1972                 doMOVEExt(p, rin, rin->arg1.rea, &xrcx,
1973                           rin->ext1 | REXTF_SEA1);
1974                 doMOVEExt(p, rin, &xrcx, sea, REXT_I64);
1975                 sext = REXT_I64;
1976                 printf("\tfildq\t");
1977             } else {
1978                 sext = REXT_I32;
1979                 printf("\tfildl\t");
1980             }
1981             break;
1982         case REXT_I64:
1983             sext = REXT_I64;
1984             printf("\tfildq\t");
1985             break;
1986         default:
1987             sext = 0;
1988             dpanic("Unknown/unsupported REXT %d", rin->ext1);
1989             break;
1990         }
1991         printEA(sea, sext);
1992         printf("\n");
1993
1994         /*
1995          * A bit of magic for unsigned 64-bits.
1996          */
1997         if (rin->ext1 == REXT_I64 && isunsigned) {
1998             static rea_t gimmin;
1999             static rea_t gimmout;
2000             static int ulabel = 100;
2001
2002             gimmin.eamode = EA_IMMEDIATE;
2003             gimmin.immlo = 1602224128;
2004
2005             CreateGlobalImmediate(&gimmin, &gimmout, rin->ext1);
2006             printf("\ttestq\t%%rcx, %%rcx\n");
2007             printf("\tjns\t.LITOF%d\n", ulabel);
2008
2009             printf("\tfadds\t");
2010             printEA(&gimmout, REXT_I64);
2011             printf("\n");
2012
2013             printf(".LITOF%d:\n", ulabel);
2014             ++ulabel;
2015         }
2016
2017         printf("\tfstpt\t");
2018         printEA(dea, REXT_I128);
2019         printf("\n");
2020
2021         if (dea != rin->arg2.rea)
2022             doMOVEExt(p, rin, dea, rin->arg2.rea,
2023                       rin->ext2 | REXTF_FLOAT | REXTF_EA2);
2024     }
2025 }
2026
2027 void
2028 InsnFTOUI(RASParser *p, rinsn_t *rin)
2029 {
2030     printf("\t#XXX supposed to be unsigned\n");
2031     InsnFTOSI(p, rin);
2032 }
2033
2034
2035 static int LastWasFTOI;
2036
2037 static void
2038 InsnFTOIProbe(RASParser *p __unused, rinsn_t *rin)
2039 {
2040     static rea_t x2ea;
2041
2042     if (rin == NULL ||
2043         (rin->op != INSN_FTOSI && rin->op != INSN_FTOUI)) {
2044         if (LastWasFTOI) {
2045             x2ea.target_reg = X86_REG_RSP;
2046             x2ea.offset = -18;
2047             x2ea.eamode = EA_MEMORY;
2048             printf("\tfldcw\t");
2049             printEA(&x2ea, rin->ext2);
2050             printf("\n");
2051         }
2052         LastWasFTOI = 0;
2053         ProbeFunc = NULL;
2054     }
2055 }
2056
2057 void
2058 InsnFTOSI(RASParser *p, rinsn_t *rin)
2059 {
2060     static rea_t xrea;
2061     static rea_t x2ea;
2062
2063     if (rin->ext1 != REXT_I128) {
2064         /*
2065          * f32 and f64
2066          */
2067         xrea.target_reg = X86_REG_XMM0;
2068         xrea.eamode = EA_DIRECT;
2069         x2ea.target_reg = X86_REG_RCX;
2070         x2ea.eamode = EA_DIRECT;
2071         x2ea.offset = 0;
2072         doMOVE(p, rin, rin->arg1.rea, &xrea);
2073
2074         if (rin->ext2 == REXT_I64) {
2075             printf("\tcvt%s2siq\t%%xmm0, %%rcx\n",
2076                    x86ext(rin->ext1, RAF_FLOAT));
2077             doMOVEExt(p, rin, &x2ea, rin->arg2.rea, REXTF_EA2);
2078         } else {
2079             printf("\tcvt%s2si\t%%xmm0, %%ecx\n",
2080                    x86ext(rin->ext1, RAF_FLOAT));
2081             doMOVEExt(p, rin, &x2ea, rin->arg2.rea, REXTF_EA2);
2082         }
2083     } else {
2084         /*
2085          * f128 (i.e. FP80)
2086          */
2087         rea_t  *sea;
2088
2089         sea = InsnSimplifyFP128(p, rin, rin->arg1.rea, &xrea,
2090                                 rin->ext1, -16, 1);
2091         printf("\tfldt\t");
2092         printEA(sea, REXT_I128);
2093         printf("\n");
2094
2095         xrea.target_reg = X86_REG_RCX;
2096         xrea.eamode = EA_DIRECT;
2097
2098         if (LastWasFTOI == 0) {
2099             ProbeFunc = InsnFTOIProbe;
2100
2101             x2ea.target_reg = X86_REG_RSP;
2102             x2ea.offset = -18;
2103             x2ea.eamode = EA_MEMORY;
2104             printf("\tfnstcw\t");
2105             printEA(&x2ea, rin->ext2);
2106             printf("\n");
2107
2108             printf("\tmovzwl\t");
2109             printEA(&x2ea, rin->ext2);
2110             printf(",%%ecx\n");
2111
2112             x2ea.target_reg = X86_REG_RSP;
2113             x2ea.offset = -20;
2114             x2ea.eamode = EA_MEMORY;
2115             printf("\torb\t$12, %%ch\n");
2116             printf("\tmovw\t%%cx, ");
2117             printEA(&x2ea, rin->ext2);
2118             printf("\n");
2119
2120             printf("\tfldcw\t");
2121             printEA(&x2ea, rin->ext2);
2122             printf("\n");
2123             LastWasFTOI = 1;
2124         }
2125
2126         printf("\tfistp%c\t",
2127                ((rin->ext2 == REXT_I8) ? 's' :
2128                 ((rin->ext2 == REXT_I16) ? 's' :
2129                  ((rin->ext2 == REXT_I32) ? 'l' :
2130                   ((rin->ext2 == REXT_I64) ? 'q' : '?')))));
2131
2132         if (rin->arg2.rea->eamode != EA_MEMORY || rin->ext2 == REXT_I8) {
2133             x2ea.target_reg = X86_REG_RSP;
2134             x2ea.offset = -32;
2135             x2ea.eamode = EA_MEMORY;
2136             printEA(&x2ea, rin->ext2);
2137             printf("\n");
2138             if (rin->arg2.rea->eamode == EA_MEMORY) {
2139                 doMOVEExt(p, rin, &x2ea, &xrea, REXTF_EA2);
2140                 doMOVEExt(p, rin, &xrea, rin->arg2.rea,
2141                           REXTF_EA2);
2142             } else {
2143                 doMOVEExt(p, rin, &x2ea, rin->arg2.rea,
2144                           REXTF_EA2);
2145             }
2146         } else {
2147             printEA(rin->arg2.rea, rin->ext2);
2148             printf("\n");
2149         }
2150
2151     }
2152 }
2153
2154 void
2155 InsnCASTF(RASParser *p, rinsn_t *rin)
2156 {
2157     static rea_t xrea;
2158     static rea_t x2ea;
2159
2160     if (rin->ext1 != REXT_I128 && rin->ext2 != REXT_I128) {
2161         /*
2162          * f32/f64 <-> f32/f64 (SSE2)
2163          */
2164         xrea.target_reg = X86_REG_XMM0;
2165         xrea.eamode = EA_DIRECT;
2166         doMOVE(p, rin, rin->arg1.rea, &xrea);
2167         printf("\tcvt%s2%s\t%%xmm0, %%xmm0\n",
2168                x86ext(rin->ext1, RAF_FLOAT),
2169                x86ext(rin->ext2, RAF_FLOAT));
2170         doMOVEExt(p, rin, &xrea, rin->arg2.rea, REXTF_EA2);
2171     } else if (rin->ext1 == REXT_I128) {
2172         /*
2173          * f128 -> f32/f64
2174          */
2175         rea_t  *sea;
2176
2177         sea = InsnSimplifyFP128(p, rin, rin->arg1.rea, &xrea,
2178                                 rin->ext1, -16, 1);
2179         printf("\tfldt\t");
2180         printEA(sea, REXT_I128);
2181         printf("\n");
2182
2183         printf("\tfstp%c\t",
2184                (rin->ext2 == REXT_I32) ? 's' : 'l');
2185         if (rin->arg2.rea->eamode != EA_MEMORY) {
2186             x2ea.target_reg = X86_REG_RSP;
2187             x2ea.offset = -32;
2188             x2ea.eamode = EA_MEMORY;
2189             printEA(&x2ea, rin->ext2);
2190             printf("\n");
2191             doMOVEExt(p, rin, &x2ea, rin->arg2.rea, REXTF_EA2);
2192         } else {
2193             printEA(rin->arg2.rea, rin->ext2);
2194             printf("\n");
2195         }
2196     } else {
2197         /*
2198          * f32/f64 -> f128
2199          */
2200         rea_t  *sea;
2201
2202         sea = InsnSimplifyFP128(p, rin, rin->arg1.rea, &xrea,
2203                                 rin->ext1, -16, 1);
2204         printf("\tfld%c\t",
2205                (rin->ext1 == REXT_I32) ? 's' : 'l');
2206         printEA(sea, REXT_I128);
2207         printf("\n");
2208
2209         printf("\tfstpt\t");
2210         if (rin->arg2.rea->eamode != EA_MEMORY) {
2211             x2ea.target_reg = X86_REG_RSP;
2212             x2ea.offset = -32;
2213             x2ea.eamode = EA_MEMORY;
2214             printEA(&x2ea, rin->ext2);
2215             printf("\n");
2216             doMOVEExt(p, rin, &x2ea, rin->arg2.rea, REXTF_EA2);
2217         } else {
2218             printEA(rin->arg2.rea, rin->ext2);
2219             printf("\n");
2220         }
2221     }
2222 }
2223
2224
2225 void
2226 InsnFCMP(RASParser *p, rinsn_t *rin)
2227 {
2228     rea_t  *sea1;
2229     rea_t  *sea2;
2230     int     rev;
2231
2232     /*
2233      * Bleh, have to use FP stack, and 128-bit immediate values don't work.
2234      */
2235     if (rin->ext1 == REXT_I128) {
2236         rev = doInsnFloating3(p, rin, "fucomip", 1);
2237     } else {
2238         rev = InsnSimplifyMRFCMP(p, rin, &sea1, &sea2);
2239
2240         /*
2241          * 128-bit is unfortunately different from 32-bit and 64-bit.
2242          */
2243         printf("\tucomi%s\t", x86ext(rin->ext1, RAF_FLOAT));
2244         printEA(sea1, rin->ext1);
2245         printf(", ");
2246         printEA(sea2, rin->ext1);
2247         printf("\n");
2248     }
2249
2250     if (rin->flags & RINSF_BRANCH) {
2251         /*
2252          * Compare and branch.  Invert sense if we can optimize the jmp.
2253          */
2254         if (adjacentLabel(rin, rin->brtrue)) {
2255             /*
2256              * next insn matches true path, invert and branch on-false.
2257              */
2258             printf("\tj%s\t", x86branch(rin->op, 1, rev));
2259             printBRLabel(rin->brfalse);
2260             printf("\n");
2261         } else if (adjacentLabel(rin, rin->brfalse)) {
2262             /*
2263              * next insn matches false path, do not invert and branch
2264              * on-true.
2265              */
2266             printf("\tj%s\t", x86branch(rin->op, 0, rev));
2267             printBRLabel(rin->brtrue);
2268             printf("\n");
2269         } else {
2270             /*
2271              * next insn does not match either path.
2272              */
2273             printf("\tj%s\t", x86branch(rin->op, 0, rev));
2274             printBRLabel(rin->brtrue);
2275             printf("\n");
2276             printf("\tjmp\t");
2277             printBRLabel(rin->brfalse);
2278             printf("\n");
2279         }
2280     } else {
2281         /*
2282          * Compare and set result
2283          */
2284         printf("\tset%s\t", x86branch(rin->op, 0, rev));
2285         printEA(rin->arg3.rea, REXT_I8);
2286         printf("\n");
2287     }
2288 }
2289
2290 /*
2291  * Complex helper functions
2292  */
2293
2294 /*
2295  * srea is an immediate value, determine if it can be directly specified in
2296  * assembly or if it must be loaded into a register first.
2297  */
2298 static
2299 int
2300 doHandleImmediate(rea_t *srea, rea_t *drea, uint8_t extov)
2301 {
2302     if ((extov & REXTF_MASK) == REXT_I64 &&
2303         (srea->immlo < (int64_t) (int)0x80000000U ||
2304          srea->immlo > (int64_t) 0x7FFFFFFFU)) {
2305         drea->target_reg = X86_REG_RCX;
2306         drea->eamode = EA_DIRECT;
2307
2308         printf("\tmovabsq\t");
2309         printEA(srea, extov);
2310         printf(", ");
2311         printEA(drea, extov);
2312         printf("\n");
2313         return 1;
2314     }
2315     return 0;
2316 }
2317
2318 /*
2319  * Binary (1-arg or 2-arg) (i.e. FMOVE, MOVE, LEA)
2320  *
2321  * RM2 - reg,mem MR2 - mem,reg
2322  *
2323  * NOTE: For CAST* insns which pass SEA1|EA2, we need to use only EA2 for the
2324  * second instruction when we have to break the operation up into two since
2325  * the first instructions handles converting ext1 into ext2 for the
2326  * intermediate result.
2327  */
2328 static
2329 void
2330 doInsnRM2NoReadDst(RASParser *p, rinsn_t *rin, const char *x86op, uint8_t extov)
2331 {
2332     static rea_t xrea;
2333
2334     if (rin->operands == 2) {
2335         if (sameEA(rin->arg1.rea, rin->arg2.rea)) {
2336             ;
2337         } else if (rin->arg1.rea->eamode == EA_MEMORY ||
2338                    ISIMM64(rin->arg1.rea)) {
2339             if (rin->arg1.flags & RAF_FLOAT) {
2340                 xrea.target_reg = X86_REG_XMM0;
2341                 xrea.eamode = EA_DIRECT;
2342             } else {
2343                 xrea.target_reg = X86_REG_RCX;
2344                 xrea.eamode = EA_DIRECT;
2345             }
2346             doMOVE(p, rin, rin->arg1.rea, &xrea);
2347             printINSN(rin, x86op, &xrea, rin->arg2.rea,
2348                       extov & ~REXTF_SEA1);
2349         } else {
2350             printINSN(rin, x86op, rin->arg1.rea, rin->arg2.rea, extov);
2351         }
2352     } else {
2353         RasError(p, "Instruction must be 2-op only");
2354     }
2355 }
2356
2357 static
2358 void
2359 doInsnMR2NoReadDst(RASParser *p, rinsn_t *rin, const char *x86op, uint8_t extov)
2360 {
2361     static rea_t xrea;
2362
2363     if (rin->operands == 2) {
2364         if (sameEA(rin->arg1.rea, rin->arg2.rea)) {
2365             ;
2366         } else if (rin->arg2.rea->eamode == EA_MEMORY) {
2367             if (rin->arg2.flags & RAF_FLOAT) {
2368                 xrea.target_reg = X86_REG_XMM0;
2369                 xrea.eamode = EA_DIRECT;
2370             } else {
2371                 xrea.target_reg = X86_REG_RCX;
2372                 xrea.eamode = EA_DIRECT;
2373             }
2374             printINSN(rin, x86op, rin->arg1.rea, &xrea, extov);
2375             doMOVEExt(p, rin, &xrea, rin->arg2.rea,
2376                       extov & ~REXTF_SEA1);
2377         } else {
2378             printINSN(rin, x86op, rin->arg1.rea, rin->arg2.rea, extov);
2379         }
2380     } else {
2381         RasError(p, "Instruction must be 2-op only");
2382     }
2383 }
2384
2385 /*
2386  * Binary (2-arg or 3-arg)
2387  *
2388  * RM3  - imm/reg,*,mem MR3     - mem,*,reg             (so far not needed)
2389  * RMMR3- can be either
2390  *
2391  * If x86op is "mov" then we can optimize the 2-op instruction which is
2392  * particularly useful when moving zero into a FP register.
2393  */
2394 static
2395 void
2396 doInsnRMMR3(RASParser *p, rinsn_t *rin, const char *x86op)
2397 {
2398     static rea_t xrea;
2399     static rea_t x2ea;
2400     int     noimm;
2401
2402     if (rin->op & INSNF_FLOAT)
2403         noimm = 1;
2404     else
2405         noimm = 0;
2406
2407     if (rin->operands == 2 || sameEA(rin->arg2.rea, rin->arg3.rea)) {
2408         if (rin->arg1.rea->eamode == EA_MEMORY ||
2409             (noimm && (rin->arg1.rea->eamode == EA_IMMEDIATE ||
2410                        rin->arg1.rea->eamode == EA_IMMEDIATE16))) {
2411             if (rin->arg1.flags & RAF_FLOAT) {
2412                 xrea.target_reg = X86_REG_XMM0;
2413                 xrea.eamode = EA_DIRECT;
2414             } else {
2415                 xrea.target_reg = X86_REG_RCX;
2416                 xrea.eamode = EA_DIRECT;
2417             }
2418             if (rin->arg1.rea->eamode != EA_MEMORY &&
2419                 strcmp(x86op, "mov") == 0) {
2420                 doMOVE(p, rin, rin->arg1.rea, rin->arg2.rea);
2421             } else {
2422                 doMOVE(p, rin, rin->arg1.rea, &xrea);
2423                 printINSN(rin, x86op, &xrea, rin->arg2.rea, 0);
2424             }
2425         } else {
2426             printINSN(rin, x86op, rin->arg1.rea, rin->arg2.rea, 0);
2427         }
2428     } else if (rin->operands == 3) {
2429         rea_t  *dea;
2430
2431         if (rin->arg3.rea->eamode == EA_DIRECT &&
2432             !sameEA(rin->arg1.rea, rin->arg3.rea)) {
2433             /*
2434              * Optimize if target is a register.
2435              */
2436             dea = rin->arg3.rea;
2437         } else if (rin->arg2.flags & RAF_FLOAT) {
2438             xrea.target_reg = X86_REG_XMM1;
2439             xrea.eamode = EA_DIRECT;
2440             dea = &xrea;
2441         } else {
2442             xrea.target_reg = X86_REG_RCX;
2443             xrea.eamode = EA_DIRECT;
2444             dea = &xrea;
2445         }
2446         if (noimm && (rin->arg1.rea->eamode == EA_IMMEDIATE ||
2447                       rin->arg1.rea->eamode == EA_IMMEDIATE16)) {
2448             dassert(rin->arg1.flags & RAF_FLOAT);
2449             x2ea.target_reg = X86_REG_XMM0;
2450             x2ea.eamode = EA_DIRECT;
2451             doMOVE(p, rin, rin->arg1.rea, &x2ea);
2452             doMOVE(p, rin, rin->arg2.rea, dea);
2453             printINSN(rin, x86op, &x2ea, dea, 0);
2454             if (dea != rin->arg3.rea)
2455                 doMOVE(p, rin, dea, rin->arg3.rea);
2456         } else {
2457             doMOVE(p, rin, rin->arg2.rea, dea);
2458             printINSN(rin, x86op, rin->arg1.rea, dea, 0);
2459             if (dea != rin->arg3.rea)
2460                 doMOVE(p, rin, dea, rin->arg3.rea);
2461         }
2462     } else {
2463         RasError(p, "Instruction must be 2-op or 3-op only");
2464     }
2465 }
2466
2467 /*
2468  * Instruction requires mem,reg or reg,reg.  If this is a floating point
2469  * instruction an immediate source must be placed in a register or be
2470  * accessed from memory.
2471  *
2472  * If nodrd is non-zero it means the destination in a 2-op instruction is NOT
2473  * read, so we don't have to copy arg2.rea into the destination before
2474  * issuing the instruction.
2475  */
2476 static
2477 void
2478 doInsnMR3(RASParser *p, rinsn_t *rin, const char *x86op, int nodrd)
2479 {
2480     static rea_t xrea;
2481     static rea_t x2ea;
2482     rea_t  *sea;
2483
2484     /*
2485      * Floating point instructions can't have an immediate source. doMOVE()
2486      * will handle optimizing the immediate value for us.
2487      */
2488     if ((rin->op & INSNF_FLOAT) &&
2489         (rin->arg1.rea->eamode == EA_IMMEDIATE ||
2490          rin->arg1.rea->eamode == EA_IMMEDIATE16)) {
2491         CreateGlobalImmediate(rin->arg1.rea, &x2ea, rin->ext1);
2492         sea = &x2ea;
2493     } else {
2494         sea = rin->arg1.rea;
2495     }
2496
2497     /*
2498      * Handle 2-arg and 3-arg mechanics.  A memory destination is not
2499      * allowed.
2500      */
2501     if (rin->operands == 2 || sameEA(rin->arg2.rea, rin->arg3.rea)) {
2502         if (rin->arg2.rea->eamode == EA_MEMORY) {
2503             if (rin->arg2.flags & RAF_FLOAT) {
2504                 xrea.target_reg = X86_REG_XMM0;
2505                 xrea.eamode = EA_DIRECT;
2506             } else {
2507                 xrea.target_reg = X86_REG_RCX;
2508                 xrea.eamode = EA_DIRECT;
2509             }
2510             if (nodrd == 0)
2511                 doMOVE(p, rin, rin->arg2.rea, &xrea);
2512             printINSN(rin, x86op, sea, &xrea, 0);
2513             doMOVE(p, rin, &xrea, rin->arg2.rea);
2514         } else {
2515             printINSN(rin, x86op, sea, rin->arg2.rea, 0);
2516         }
2517     } else if (rin->operands == 3) {
2518         rea_t  *dea;
2519
2520         if (rin->arg3.rea->eamode == EA_DIRECT &&
2521             !sameEA(rin->arg1.rea, rin->arg3.rea)) {
2522             /*
2523              * Optimize if target is a register.
2524              */
2525             dea = rin->arg3.rea;
2526         } else if (rin->arg2.flags & RAF_FLOAT) {
2527             xrea.target_reg = X86_REG_XMM0;
2528             xrea.eamode = EA_DIRECT;
2529             dea = &xrea;
2530         } else {
2531             xrea.target_reg = X86_REG_RCX;
2532             xrea.eamode = EA_DIRECT;
2533             dea = &xrea;
2534         }
2535         doMOVE(p, rin, rin->arg2.rea, dea);
2536         printINSN(rin, x86op, sea, dea, 0);
2537         if (dea != rin->arg3.rea)
2538             doMOVE(p, rin, dea, rin->arg3.rea);
2539     } else {
2540         RasError(p, "Instruction must be 2-op or 3-op only");
2541     }
2542 }
2543
2544 /*
2545  * Unary (1-arg) with possible 2-arg optimization
2546  *
2547  * R    - single argument to register, else 2-arg optimization to either
2548  * register or memory.
2549  */
2550 static
2551 void
2552 doInsn1R(RASParser * p, rinsn_t * rin, const char *x86op1,
2553          const char *x86op2, const char *x86opt2arg)
2554 {
2555     static rea_t xrea;
2556
2557     if (rin->operands == 1 || sameEA(rin->arg1.rea, rin->arg2.rea)) {
2558         if (rin->arg1.rea->eamode == EA_DIRECT) {
2559             /*
2560              * 1-operand unary insn with register target
2561              */
2562             printINSN(rin, x86op1, rin->arg1.rea, NULL, 0);
2563         } else if (x86op2) {
2564             /*
2565              * Alternative for 1-operand unary insn with memory argument
2566              */
2567             printf("\t%s%s\t%s, ",
2568                    x86op2, x86ext(rin->ext1, rin->arg1.flags),
2569                    x86opt2arg);
2570             printEA(rin->arg1.rea, rin->ext1);
2571             printf("\n");
2572         } else {
2573             /*
2574              * No alternative
2575              */
2576             if (rin->arg1.flags & RAF_FLOAT) {
2577                 xrea.target_reg = X86_REG_XMM0;
2578                 xrea.eamode = EA_DIRECT;
2579             } else {
2580                 xrea.target_reg = X86_REG_RCX;
2581                 xrea.eamode = EA_DIRECT;
2582             }
2583             doMOVE(p, rin, rin->arg1.rea, &xrea);
2584             printINSN(rin, x86op1, &xrea, NULL, 0);
2585             doMOVE(p, rin, &xrea, rin->arg1.rea);
2586         }
2587     } else if (rin->operands == 2) {
2588         if (x86op2 && rin->arg2.rea->eamode == EA_DIRECT) {
2589             /*
2590              * Alternative for 2-operand unary insn
2591              */
2592             doMOVE(p, rin, rin->arg1.rea, rin->arg2.rea);
2593             printf("\t%s%s\t%s, ",
2594                    x86op2, x86ext(rin->ext1, rin->arg1.flags),
2595                    x86opt2arg);
2596             printEA(rin->arg2.rea, rin->ext1);
2597             printf("\n");
2598         } else {
2599             /*
2600              * No alternative
2601              */
2602             if (rin->arg1.flags & RAF_FLOAT) {
2603                 xrea.target_reg = X86_REG_XMM0;
2604                 xrea.eamode = EA_DIRECT;
2605             } else {
2606                 xrea.target_reg = X86_REG_RCX;
2607                 xrea.eamode = EA_DIRECT;
2608             }
2609             doMOVE(p, rin, rin->arg1.rea, &xrea);
2610             printINSN(rin, x86op1, &xrea, NULL, 0);
2611             doMOVE(p, rin, &xrea, rin->arg2.rea);
2612         }
2613     } else {
2614         RasError(p, "Instruction must be 1-op or 2-op only");
2615     }
2616 }
2617
2618 /*
2619  * The shift instruction has two size extensions.  ext1 applies to the shift
2620  * count, ext2 to the target.  The shift count must be either an immediate
2621  * value or loaded into %cl (%ecx or %rcx ok).
2622  *
2623  * NOTE: We may have to adjust ext1/ext2 if we call other helper functions to
2624  * present the correct operand size.
2625  *
2626  * NOTE: Cannot shift floating point values (for now)
2627  */
2628 static
2629 void
2630 doInsnSHIFT3(RASParser *p, rinsn_t *rin, const char *x86op)
2631 {
2632     static rea_t xrea;
2633     rea_t  *sea;
2634     uint8_t tmpext;
2635
2636     printf("\t# SHIFT3\n");
2637     if (rin->arg1.rea->eamode == EA_IMMEDIATE) {
2638         /*
2639          * Immediate shift count
2640          */
2641         sea = rin->arg1.rea;
2642     } else if (rin->arg1.rea->eamode != EA_DIRECT ||
2643                rin->arg1.rea->target_reg != X86_REG_RCX) {
2644         /*
2645          * Else shift counter must be %cl/%cx/%ecx/%rcx
2646          */
2647         xrea.target_reg = X86_REG_RCX;
2648         xrea.eamode = EA_DIRECT;
2649         doMOVE(p, rin, rin->arg1.rea, &xrea);
2650         sea = &xrea;
2651     } else {
2652         sea = rin->arg1.rea;
2653     }
2654     tmpext = rin->ext1;
2655     rin->ext1 = rin->ext2;
2656
2657     if (rin->operands == 2 || sameEA(rin->arg2.rea, rin->arg3.rea)) {
2658         printINSN(rin, x86op, sea, rin->arg2.rea,
2659                   REXTF_SEA1 | REXTF_EA2);
2660     } else if (rin->operands == 3) {
2661         static rea_t x2ea;
2662         rea_t  *dea;
2663
2664         if (rin->arg3.rea->eamode == EA_DIRECT) {
2665             /*
2666              * Optimize if target is a register.  can't match sea by
2667              * definition.
2668              */
2669             dea = rin->arg3.rea;
2670         } else if (rin->arg2.flags & RAF_FLOAT) {
2671             x2ea.target_reg = X86_REG_XMM0;
2672             x2ea.eamode = EA_DIRECT;
2673             dea = &x2ea;
2674         } else {
2675             x2ea.target_reg = X86_REG_RAX;
2676             x2ea.eamode = EA_DIRECT;
2677             dea = &x2ea;
2678         }
2679         doMOVEExt(p, rin, rin->arg2.rea, dea, REXTF_EA2);
2680         printINSN(rin, x86op, sea, dea, REXTF_SEA1 | REXTF_EA2);
2681         if (dea != rin->arg3.rea)
2682             doMOVEExt(p, rin, dea, rin->arg3.rea, REXTF_EA2);
2683     } else {
2684         RasError(p, "Instruction must be 2-op or 3-op only");
2685     }
2686     rin->ext1 = tmpext;
2687 }
2688
2689 /*
2690  * Binary (2-arg or 3-arg), destination is in %*DX:%*AX and result is in
2691  * either %*DX or %*AX.  Requires spewing a multitude of adjustment
2692  * instructions.
2693  */
2694 static
2695 void
2696 doInsnDXAX3(RASParser * p, rinsn_t * rin, const char *x86op,
2697             int issigned, int dxresult)
2698 {
2699     static rea_t xrea;
2700     static rea_t x2ea;
2701     rea_t  *dea;
2702
2703     printf("\t# DXAX3 for %s\n", x86op);
2704     if (rin->operands == 2 || sameEA(rin->arg2.rea, rin->arg3.rea)) {
2705         dea = rin->arg2.rea;
2706     } else if (rin->operands == 3) {
2707         dea = rin->arg3.rea;
2708     } else {
2709         RasError(p, "Instruction must be 2-op or 3-op only");
2710         return;
2711     }
2712     x2ea.target_reg = X86_REG_RCX;
2713     x2ea.eamode = EA_DIRECT;
2714     doMOVE(p, rin, rin->arg1.rea, &x2ea);
2715
2716     xrea.target_reg = X86_REG_RAX;
2717     xrea.eamode = EA_DIRECT;
2718     doMOVE(p, rin, rin->arg2.rea, &xrea);
2719     if (issigned) {
2720         switch (rin->ext1) {
2721         case REXT_I8:
2722             printf("\tcbtw\n");
2723             break;
2724         case REXT_I16:
2725             printf("\tcwtd\n");
2726             break;
2727         case REXT_I32:
2728             printf("\tcltd\n");
2729             break;
2730         case REXT_I64:
2731             printf("\tcqto\n");
2732             break;
2733         default:
2734             dpanic("Unknown/unsupported REXT %d", rin->ext1);
2735             break;
2736         }
2737     } else {
2738         switch (rin->ext1) {
2739         case REXT_I8:
2740             printf("\txorl\t%%edx, %%edx\n");
2741             break;
2742         case REXT_I16:
2743             printf("\txorl\t%%edx, %%edx\n");
2744             break;
2745         case REXT_I32:
2746             printf("\txorl\t%%edx, %%edx\n");
2747             break;
2748         case REXT_I64:
2749             printf("\txorl\t%%edx, %%edx\n");
2750             break;
2751         default:
2752             dpanic("Unknown/unsupported REXT %d", rin->ext1);
2753             break;
2754         }
2755     }
2756     printf("\t%s%s\t", x86op, x86ext(rin->ext1, rin->arg1.flags));
2757     printEA(&x2ea, rin->ext1);
2758     printf("\n");
2759     if (dxresult)
2760         xrea.target_reg = X86_REG_RDX;
2761     doMOVE(p, rin, &xrea, dea);
2762 }
2763
2764 /*
2765  * 80-bit is messy to say the least
2766  */
2767 static
2768 int
2769 doInsnFloating3(RASParser *p, rinsn_t *rin, const char *x86op, int isfcmp)
2770 {
2771     int     rev = 0;
2772
2773     if (rin->ext1 != REXT_I128) {
2774         /*
2775          * NOTE: InsnFCMP path never hits this (it wouldn't work anyway)
2776          */
2777         doInsnMR3(p, rin, x86op, 0);
2778     } else {
2779         rea_t   xsea;
2780         rea_t   xmea;
2781         rea_t   xdea;
2782         rea_t  *sea;
2783         rea_t  *mea;
2784         rea_t  *dea;
2785         int     sea_sp;
2786         int     mea_sp;
2787 #if 0
2788         int     dea_sp;
2789         int     ttl_sp;
2790 #endif
2791
2792         sea_sp = (rin->arg1.rea->eamode == EA_DIRECT);
2793         mea_sp = (rin->arg2.rea->eamode == EA_DIRECT);
2794 #if 0
2795         dea_sp = (isfcmp == 0 && rin->operands != 2 &&
2796                   !sameEA(rin->arg2.rea, rin->arg3.rea));
2797         ttl_sp = (sea_sp + mea_sp + dea_sp) *16;
2798 #endif
2799
2800 #if 0
2801         /* XXX removed, using red zone instead */
2802         if (ttl_sp) {
2803             printf("\tsub%c\t$%d, ", X86Size, ttl_sp);
2804             printREGTGT(X86_REG_RSP, 0, ExtSize);
2805             printf("\n");
2806         }
2807 #endif
2808
2809         sea = InsnSimplifyFP128(p, rin, rin->arg1.rea, &xsea,
2810                                 rin->ext1, -16, 1);
2811 #if 0
2812         sea = rin->arg1.rea;
2813         if (sea->eamode == EA_IMMEDIATE16) {
2814             CreateGlobalImmediate(sea, &xsea, rin->ext1);
2815             sea = &xsea;
2816         } else if (sea->eamode != EA_MEMORY) {
2817             bzero(&xsea, sizeof(xsea));
2818             xsea.target_reg = X86_REG_RSP;
2819             xsea.eamode = EA_MEMORY;
2820             xsea.offset = -16;
2821             doMOVE(p, rin, sea, &xsea);
2822             sea = &xsea;
2823         }
2824 #endif
2825         mea = InsnSimplifyFP128(p, rin, rin->arg2.rea, &xmea,
2826                                 rin->ext1, -32, 1);
2827
2828 #if 0
2829         mea = rin->arg2.rea;
2830         if (mea->eamode == EA_IMMEDIATE16) {
2831             CreateGlobalImmediate(mea, &xmea, rin->ext1);
2832             mea = &xmea;
2833         } else if (mea->eamode != EA_MEMORY) {
2834             bzero(&xmea, sizeof(xmea));
2835             xmea.target_reg = X86_REG_RSP;
2836             xmea.eamode = EA_MEMORY;
2837             xmea.offset = -16 - sea_sp * 16;
2838             doMOVE(p, rin, mea, &xmea);
2839             mea = &xmea;
2840         }
2841 #endif
2842
2843         /*
2844          * FCMP doesn't store a floating point result
2845          */
2846         if (isfcmp == 0) {
2847             if (rin->operands == 2 ||
2848                 sameEA(rin->arg2.rea, rin->arg3.rea)) {
2849                 dea = mea;
2850             } else {
2851                 dea = rin->arg3.rea;
2852                 if (dea->eamode != EA_MEMORY) {
2853                     bzero(&xdea, sizeof(xdea));
2854                     xdea.target_reg = X86_REG_RSP;
2855                     xdea.eamode = EA_MEMORY;
2856                     xdea.offset = -16 -
2857                         (sea_sp + mea_sp) *16;
2858                     dea = &xdea;
2859                 }
2860             }
2861         } else {
2862             dea = NULL;
2863         }
2864         printf("\tfldt\t");
2865         printEA(sea, REXT_I128);
2866         printf("\n");
2867
2868         printf("\tfldt\t");
2869         printEA(mea, REXT_I128);
2870         printf("\n");
2871
2872         if (isfcmp) {
2873 #if 0
2874             if (ttl_sp) {
2875                 printf("\tadd%c\t$%d, ", X86Size, ttl_sp);
2876                 printREGTGT(X86_REG_RSP, 0, ExtSize);
2877                 printf("\n");
2878             }
2879 #endif
2880             printf("\t%s\t%%st(1), %%st\n", x86op);
2881             printf("\tfstp\t%%st(0)\n");
2882             /* looks like we should leave rev 0 here */
2883         } else {
2884             printf("\tf%sp\t%%st, %%st(1)\n", x86op);
2885             printf("\tfstpt\t");
2886             printEA(dea, REXT_I128);
2887             printf("\n");
2888         }
2889
2890         if (isfcmp == 0) {
2891             if (rin->operands == 2 ||
2892                 sameEA(rin->arg2.rea, rin->arg3.rea)) {
2893                 if (rin->arg2.rea->eamode != EA_MEMORY)
2894                     doMOVE(p, rin, dea, rin->arg2.rea);
2895             } else {
2896                 if (rin->arg3.rea->eamode != EA_MEMORY)
2897                     doMOVE(p, rin, dea, rin->arg3.rea);
2898             }
2899 #if 0
2900             if (ttl_sp) {
2901                 printf("\tadd%c\t$%d, ", X86Size, ttl_sp);
2902                 printREGTGT(X86_REG_RSP, 0, ExtSize);
2903                 printf("\n");
2904             }
2905 #endif
2906         }
2907     }
2908     return rev;
2909 }
2910
2911 /*
2912  * This helper can handle the following MOVEs for integer and floating point:
2913  *
2914  * imm/reg imm/mem reg/reg reg/mem mem/reg
2915  *
2916  * This function does not handle mem/mem.
2917  *
2918  * This function may eat XMM0 or RCX, but is guaranteed not to eat any
2919  * registers if either the source or target is a register (an immediate
2920  * source does not count so imm,reg CAN eat another register).
2921  */
2922 static
2923 void
2924 doMOVE(RASParser *p, rinsn_t *rin, rea_t *sea, rea_t *dea)
2925 {
2926     static rea_t xrea;
2927
2928     if ((rin->arg1.flags & RAF_FLOAT) &&
2929         ((sea->eamode == EA_IMMEDIATE && sea->immlo == 0) ||
2930          (sea->eamode == EA_IMMEDIATE16 && sea->immlo == 0 &&
2931           sea->immhi == 0))) {
2932         /*
2933          * MOVE $0,dea
2934          */
2935         if (dea->eamode == EA_DIRECT) {
2936             printf("\tpxor\t");
2937             printEA(dea, rin->ext1);
2938             printf(", ");
2939             printEA(dea, rin->ext1);
2940             printf("\n");
2941         } else {
2942             if (p->opt_last & RASOPT_XMM0_ZERO) {
2943                 printf("\t# pxor %%xmm0, %%xmm0\n");
2944             } else {
2945                 xrea.target_reg = X86_REG_XMM0;
2946                 xrea.eamode = EA_DIRECT;
2947                 printf("\tpxor\t");
2948                 printEA(&xrea, rin->ext1);
2949                 printf(", ");
2950                 printEA(&xrea, rin->ext1);
2951                 printf("\n");
2952             }
2953             p->opt_flags |= RASOPT_XMM0_ZERO;
2954             doMOVE(p, rin, &xrea, dea);
2955         }
2956     } else if ((rin->arg1.flags & RAF_FLOAT) &&
2957                (sea->eamode == EA_IMMEDIATE ||
2958                 sea->eamode == EA_IMMEDIATE16)) {
2959         rea_t   irea;
2960
2961         CreateGlobalImmediate(sea, &irea, rin->ext1);
2962         printf("\tmov%s\t", x86ext(rin->ext1, rin->arg1.flags));
2963         printEA(&irea, rin->ext1);
2964         printf(", ");
2965         if (dea->eamode == EA_DIRECT) {
2966             printEA(dea, rin->ext1);
2967             printf("\n");
2968         } else {
2969             xrea.target_reg = X86_REG_XMM0;
2970             xrea.eamode = EA_DIRECT;
2971             printEA(&xrea, rin->ext1);
2972             printf("\n");
2973             doMOVE(p, rin, &xrea, dea);
2974         }
2975     } else if (sea->eamode == EA_IMMEDIATE && sea->immlo == 0 &&
2976                dea->eamode == EA_DIRECT) {
2977         /*
2978          * MOVE $0,IREG
2979          */
2980         printf("\txorl\t");     /* avoid REX */
2981         printEA(dea, REXT_I32);
2982         printf(", ");
2983         printEA(dea, REXT_I32);
2984         printf("\n");
2985     } else if (ISIMM64(sea)) {
2986         /*
2987          * MOVE 64-bit immediate to target
2988          */
2989         if (dea->eamode == EA_DIRECT) {
2990             printf("\tmovabsq\t");
2991             printEA(sea, rin->ext1);
2992             printf(", ");
2993             printEA(dea, rin->ext1);
2994             printf("\n");
2995         } else {
2996             xrea.target_reg = X86_REG_RCX;
2997             xrea.eamode = EA_DIRECT;
2998             printf("\tmovabsq\t");
2999             printEA(sea, rin->ext1);
3000             printf(", ");
3001             printEA(&xrea, rin->ext1);
3002             printf("\n");
3003
3004             printf("\tmov%s\t", x86ext(rin->ext1, rin->arg1.flags));
3005             printEA(&xrea, rin->ext1);
3006             printf(", ");
3007             printEA(dea, rin->ext1);
3008             printf("\n");
3009         }
3010     } else {
3011         /*
3012          * MOVE generic (to/from register)
3013          */
3014         printf("\tmov%s\t", x86ext(rin->ext1, rin->arg1.flags));
3015         printEA(sea, rin->ext1);
3016         printf(", ");
3017         printEA(dea, rin->ext1);
3018         printf("\n");
3019     }
3020 }
3021
3022 static
3023 void
3024 doMOVEExt(RASParser *p __unused, rinsn_t *rin, rea_t *sea, rea_t *dea,
3025           uint8_t extov)
3026 {
3027     uint8_t sext = rin->ext1;
3028     uint8_t dext = rin->ext1;
3029     uint8_t sflags = rin->arg1.flags;
3030     uint8_t dflags = rin->arg1.flags;
3031
3032     if (extov & REXTF_MASK) {
3033         sext = extov & REXTF_MASK;
3034         dext = sext;
3035     }
3036     if (extov & REXTF_EA2) {
3037         sext = rin->ext2;
3038         dext = rin->ext2;
3039         sflags = rin->arg2.flags;
3040         dflags = rin->arg2.flags;
3041     }
3042     if (extov & REXTF_SEA1) {
3043         sext = rin->ext1;
3044         sflags = rin->arg1.flags;
3045     }
3046     if (sflags & RAF_FLOAT)
3047         sext |= REXTF_FLOAT;
3048     if (dflags & RAF_FLOAT)
3049         dext |= REXTF_FLOAT;
3050
3051     if (sea->eamode == EA_IMMEDIATE && sea->immlo == 0 &&
3052         dea->eamode == EA_DIRECT) {
3053         printf("\txorl\t");     /* avoid REX */
3054         printEA(dea, REXT_I32);
3055         printf(", ");
3056         printEA(dea, REXT_I32);
3057     } else {
3058         printf("\tmov%s\t", x86ext(dext, dflags));
3059         printEA(sea, sext);
3060         printf(", ");
3061         printEA(dea, dext);
3062     }
3063     printf("\n");
3064 }
3065
3066 /*
3067  * Load effective-address instead of contents.  Note that some originally
3068  * EA_DIRECT EAs may have been converted to stack-temporary storage.  In this
3069  * situation the effective-address is, in fact, the contents of the storage.
3070  */
3071 static
3072 void
3073 doLEA(RASParser *p __unused, rea_t *sea, rea_t *dea)
3074 {
3075     if (sea->orig_eamode == EA_DIRECT) {
3076         printf("\tmov%c\t", X86Size);
3077         printEA(sea, ExtSize);
3078         printf(", ");
3079         printEA(dea, ExtSize);
3080     } else if (sea->eamode == EA_MEMORY &&
3081                sea->sym == NULL &&
3082                sea->regno == 0) {
3083         if (sea->offset == 0 && dea->eamode == EA_DIRECT) {
3084             printf("\txorl\t"); /* avoid REX */
3085             printEA(dea, REXT_I32);
3086             printf(", ");
3087             printEA(dea, REXT_I32);
3088         } else {
3089             printf("\tmov%c\t$%jd, ", X86Size, sea->offset);
3090             printEA(dea, ExtSize);
3091         }
3092     } else {
3093         printf("\tlea%c\t", X86Size);
3094         printEA(sea, ExtSize);
3095         printf(", ");
3096         printEA(dea, ExtSize);
3097     }
3098     printf("\n");
3099 }
3100
3101 static
3102 void
3103 doSpecialSave(rinsn_t *rin)
3104 {
3105     uint64_t mask;
3106     size_t  fpcount;
3107     size_t  count;
3108     int     i;
3109
3110     mask = rin->special_save;
3111     if (mask == 0)
3112         return;
3113     printf("\t# SPECIAL SAVE\n");
3114     fpcount = 0;
3115     count = 0;
3116     for (i = 0; mask; ++i) {
3117         if ((mask & (1LLU << i)) == 0)
3118             continue;
3119         if (i < X86_REG_FBASE) {
3120             mask &= ~(1LLU << i);
3121             printf("\tpush%c\t", X86Size);
3122             printREGTGT(i | X86_SIZE_UNSPEC, 0, ExtSize);
3123             printf("\n");
3124             count += sizeof(void *);
3125         } else {
3126             fpcount += 16;
3127         }
3128     }
3129     count = ((count + 15) & ~(size_t) 15) - count;      /* 16-byte align */
3130     if (fpcount + count) {
3131         printf("\tsub%c\t$%zd, ", X86Size, (fpcount + count));
3132         printREGTGT(X86_REG_RSP, 0, ExtSize);
3133         printf("\n");
3134     }
3135     if (fpcount == 0)
3136         return;
3137
3138     for (i = X86_REG_FBASE; mask; ++i) {
3139         if ((mask & (1LLU << i)) == 0)
3140             continue;
3141         mask &= ~(1LLU << i);
3142         printf("\tmovaps\t%%xmm%d, %zd(", i - X86_REG_FBASE, fpcount);
3143         printREGTGT(X86_REG_RSP, 0, ExtSize);
3144         printf(")\n");
3145         fpcount += 16;
3146     }
3147 }
3148
3149 static
3150 void
3151 doSpecialRestore(rinsn_t *rin)
3152 {
3153     uint64_t mask;
3154     size_t  fpcount;
3155     size_t  count;
3156     int     i;
3157
3158     mask = rin->special_save;
3159     if (mask == 0)
3160         return;
3161     printf("\t# SPECIAL RESTORE\n");
3162
3163     fpcount = 0;
3164     for (i = X86_REG_FBASE; mask & 0xFFFFFFFF00000000LLU; ++i) {
3165         if ((mask & (1LLU << i)) == 0)
3166             continue;
3167         mask &= ~(1LLU << i);
3168         printf("\tmovaps\t%zd(", fpcount);
3169         printREGTGT(X86_REG_RSP, 0, ExtSize);
3170         printf("), %%xmm%d\n", i - X86_REG_FBASE);
3171         fpcount += 16;
3172     }
3173
3174     count = 0;
3175     for (i = 31; i >= 0; --i) {
3176         if ((mask & (1LLU << i)) == 0)
3177             continue;
3178         count += sizeof(void *);
3179     }
3180     count = ((count + 15) & ~(size_t) 15) - count;      /* 16-byte align */
3181
3182     if (fpcount + count) {
3183         printf("\tadd%c\t$%jd, ", X86Size, (intmax_t) (fpcount + count));
3184         printREGTGT(X86_REG_RSP, 0, ExtSize);
3185         printf("\n");
3186     }
3187     for (i = 31; mask; --i) {
3188         if ((mask & (1LLU << i)) == 0)
3189             continue;
3190         mask &= ~(1LLU << i);
3191         printf("\tpop%c\t", X86Size);
3192         printREGTGT(i | X86_SIZE_UNSPEC, 0, ExtSize);
3193         printf("\n");
3194     }
3195 }
3196
3197
3198 /*
3199  * Used for CMP instructions where arg1 and arg2.rea are both source
3200  * arguments. Allow either reg,mem or $imm,mem or mem,reg.
3201  *
3202  * We have an optimization to reverse the comparison and return the reverse
3203  * status to the caller (allows immediate arg2.rea to be optimized).
3204  */
3205 static
3206 int
3207 InsnSimplifyRMMRCMP(RASParser *p, rinsn_t *rin, rea_t **sea1p, rea_t **sea2p)
3208 {
3209     static rea_t xrea;
3210     int     rev;
3211
3212     if (rin->arg2.rea->eamode == EA_IMMEDIATE ||
3213         rin->arg2.rea->eamode == EA_IMMEDIATE16) {
3214         if (rin->arg1.rea->eamode == EA_IMMEDIATE ||
3215             rin->arg1.rea->eamode == EA_IMMEDIATE16) {
3216             /*
3217              * Bleh, a constant expression didn't get collapsed. Make it
3218              * work.  We don't interpret here (yet).
3219              */
3220             if (rin->arg2.flags & RAF_FLOAT) {
3221                 xrea.target_reg = X86_REG_XMM0;
3222                 xrea.eamode = EA_DIRECT;
3223             } else {
3224                 xrea.target_reg = X86_REG_RCX;
3225                 xrea.eamode = EA_DIRECT;
3226             }
3227             *sea1p = rin->arg1.rea;
3228             *sea2p = &xrea;
3229             doMOVE(p, rin, rin->arg2.rea, &xrea);
3230             rev = 0;
3231         } else {
3232             /*
3233              * $imm,reg/mem - We are good.
3234              */
3235             if (doHandleImmediate(rin->arg2.rea, &xrea, rin->ext1))
3236                 *sea1p = &xrea;
3237             else
3238                 *sea1p = rin->arg2.rea;
3239             *sea2p = rin->arg1.rea;
3240             rev = 1;
3241         }
3242     } else if (rin->arg1.rea->eamode == EA_IMMEDIATE ||
3243                rin->arg1.rea->eamode == EA_IMMEDIATE16) {
3244         /*
3245          * $imm,reg/mem - We are good.
3246          */
3247         if (doHandleImmediate(rin->arg1.rea, &xrea, rin->ext1))
3248             *sea1p = &xrea;
3249         else
3250             *sea1p = rin->arg1.rea;
3251         *sea2p = rin->arg2.rea;
3252         rev = 0;
3253     } else if (rin->arg1.rea->eamode != EA_DIRECT &&
3254                rin->arg2.rea->eamode != EA_DIRECT) {
3255         /*
3256          * Usually better to put arg1 in register (but we could put arg2.rea
3257          * in the register).
3258          */
3259         if (rin->arg1.flags & RAF_FLOAT) {
3260             xrea.target_reg = X86_REG_XMM0;
3261             xrea.eamode = EA_DIRECT;
3262         } else {
3263             xrea.target_reg = X86_REG_RCX;
3264             xrea.eamode = EA_DIRECT;
3265         }
3266         *sea1p = &xrea;
3267         *sea2p = rin->arg2.rea;
3268         doMOVE(p, rin, rin->arg1.rea, &xrea);
3269         rev = 0;
3270     } else {
3271         /*
3272          * Otherwise we are good
3273          */
3274         *sea1p = rin->arg1.rea;
3275         *sea2p = rin->arg2.rea;
3276         rev = 0;
3277     }
3278     return rev;
3279 }
3280
3281 /*
3282  * Floating point version allows a memory or register source and register
3283  * destination.  Unlike normal instructions, an immediate source is not
3284  * allowed.
3285  *
3286  * If possible, reverse the sense of the comparison if it will generate more
3287  * optimal code.
3288  */
3289 static
3290 int
3291 InsnSimplifyMRFCMP(RASParser *p, rinsn_t *rin, rea_t **sea1p, rea_t **sea2p)
3292 {
3293     static rea_t xrea;
3294     static rea_t x2ea;
3295     int     rev;
3296
3297     if (rin->arg2.rea->eamode == EA_DIRECT) {
3298         /*
3299          * ARG2 is direct, which is optimal.  ARG1 can be direct or memory,
3300          * but cannot be immediate.  Don't reverse.
3301          */
3302         rev = 0;
3303         if (rin->arg1.rea->eamode == EA_DIRECT ||
3304             rin->arg1.rea->eamode == EA_MEMORY) {
3305             *sea1p = rin->arg1.rea;
3306             *sea2p = rin->arg2.rea;
3307         } else {
3308             xrea.target_reg = X86_REG_XMM0;
3309             xrea.eamode = EA_DIRECT;
3310             doMOVE(p, rin, rin->arg1.rea, &xrea);
3311             *sea1p = &xrea;
3312             *sea2p = rin->arg2.rea;
3313         }
3314     } else if (rin->arg1.rea->eamode == EA_DIRECT &&
3315                (rin->arg2.rea->eamode == EA_IMMEDIATE ||
3316                 rin->arg2.rea->eamode == EA_IMMEDIATE16)) {
3317         /*
3318          * ARG1 is direct and ARG2 is immediate.  Since we need a
3319          * memory-immediate, reverse it and optimize the immediate.
3320          */
3321         rev = 1;
3322         CreateGlobalImmediate(rin->arg2.rea, &xrea, rin->ext1);
3323         *sea1p = &xrea;
3324         *sea2p = rin->arg1.rea;
3325     } else if (rin->arg1.rea->eamode == EA_DIRECT) {
3326         /*
3327          * ARG1 is direct so lets reverse it in case ARG2 is memory. Plus
3328          * this is optimal if ARG2 happens to be immediate.
3329          */
3330         rev = 1;
3331         xrea.target_reg = X86_REG_XMM0;
3332         xrea.eamode = EA_DIRECT;
3333         doMOVE(p, rin, rin->arg2.rea, &xrea);
3334         *sea1p = &xrea;
3335         *sea2p = rin->arg1.rea;
3336     } else if ((rin->arg1.rea->eamode == EA_IMMEDIATE ||
3337                 rin->arg1.rea->eamode == EA_IMMEDIATE16) &&
3338                (rin->arg2.rea->eamode == EA_IMMEDIATE ||
3339                 rin->arg2.rea->eamode == EA_IMMEDIATE16)) {
3340         /*
3341          * Sigh, both ARG1 and ARG2 are immediate.  We can use
3342          * CreateGlobalImmediate() to get a memory-immediate for arg1.rea.
3343          */
3344         rev = 0;
3345         CreateGlobalImmediate(rin->arg1.rea, &xrea, rin->ext1);
3346         x2ea.target_reg = X86_REG_XMM1;
3347         x2ea.eamode = EA_DIRECT;
3348         doMOVE(p, rin, rin->arg2.rea, &x2ea);
3349         *sea1p = &xrea;
3350         *sea2p = &x2ea;
3351     } else if (rin->arg2.rea->eamode == EA_IMMEDIATE ||
3352                rin->arg2.rea->eamode == EA_IMMEDIATE16) {
3353         /*
3354          * ARG1 is memory and arg2.rea is immediate.  We have to throw
3355          * arg2.rea into a register so don't reverse.
3356          */
3357         rev = 0;
3358         x2ea.target_reg = X86_REG_XMM1;
3359         x2ea.eamode = EA_DIRECT;
3360         doMOVE(p, rin, rin->arg2.rea, &x2ea);
3361         *sea1p = rin->arg1.rea;
3362         *sea2p = &x2ea;
3363     } else {
3364         /*
3365          * arg1 is immediate or memory, arg2 is memory.  Since immediate
3366          * values aren't allowed both sides are effectively memory.  Reverse
3367          * it (no reason, just feel like it).
3368          */
3369         rev = 1;
3370         x2ea.target_reg = X86_REG_XMM0;
3371         x2ea.eamode = EA_DIRECT;
3372         doMOVE(p, rin, rin->arg1.rea, &x2ea);
3373         *sea1p = rin->arg2.rea;
3374         *sea2p = &x2ea;
3375     }
3376     return rev;
3377 }
3378
3379 /*
3380  * Simplify an EA into a memory operand for float128's (FP80)
3381  */
3382 static
3383 rea_t *
3384 InsnSimplifyFP128(RASParser * p, rinsn_t * rin, rea_t * sea, rea_t * tea,
3385                   uint8_t ext, int rspoff, int loadme)
3386 {
3387     if (sea->eamode == EA_IMMEDIATE16) {
3388         CreateGlobalImmediate(sea, tea, ext);
3389         sea = tea;
3390     } else if (sea->eamode != EA_MEMORY) {
3391         bzero(tea, sizeof(*tea));
3392         tea->target_reg = X86_REG_RSP;
3393         tea->eamode = EA_MEMORY;
3394         tea->offset = rspoff;
3395         if (loadme)
3396             doMOVE(p, rin, sea, tea);
3397         sea = tea;
3398     }
3399     return sea;
3400 }
3401
3402 /*
3403  * Low level helper functions
3404  */
3405 static
3406 void
3407 printREGTGT(uint16_t target_reg, uint32_t regno, uint8_t ext)
3408 {
3409     dassert(ext);
3410     if (target_reg) {
3411         const char *rid;
3412         char    buf[16];
3413         int     mr;
3414
3415         mr = target_reg;
3416
3417         switch (mr) {
3418         case X86_REG_RAX:
3419             rid = "ax";
3420             break;
3421         case X86_REG_RCX:
3422             rid = "cx";
3423             break;
3424         case X86_REG_RDX:
3425             rid = "dx";
3426             break;
3427         case X86_REG_RBX:
3428             rid = "bx";
3429             break;
3430         case X86_REG_RSP:
3431             rid = "sp";
3432             break;
3433         case X86_REG_RBP:
3434             rid = "bp";
3435             break;
3436         case X86_REG_RSI:
3437             rid = "si";
3438             break;
3439         case X86_REG_RDI:
3440             rid = "di";
3441             break;
3442         case X86_REG_R8:
3443             rid = "r8";
3444             break;
3445         case X86_REG_R9:
3446             rid = "r9";
3447             break;
3448         case X86_REG_R10:
3449             rid = "r10";
3450             break;
3451         case X86_REG_R11:
3452             rid = "r11";
3453             break;
3454         case X86_REG_R12:
3455             rid = "r12";
3456             break;
3457         case X86_REG_R13:
3458             rid = "r13";
3459             break;
3460         case X86_REG_R14:
3461             rid = "r14";
3462             break;
3463         case X86_REG_R15:
3464             rid = "r15";
3465             break;
3466         case X86_REG_RIP:
3467             rid = "ip";
3468             break;
3469         case X86_REG_XMM0:
3470             rid = "xmm0";
3471             break;
3472         case X86_REG_XMM1:
3473             rid = "xmm1";
3474             break;
3475         case X86_REG_XMM2:
3476             rid = "xmm2";
3477             break;
3478         case X86_REG_XMM3:
3479             rid = "xmm3";
3480             break;
3481         case X86_REG_XMM4:
3482             rid = "xmm4";
3483             break;
3484         case X86_REG_XMM5:
3485             rid = "xmm5";
3486             break;
3487         case X86_REG_XMM6:
3488             rid = "xmm6";
3489             break;
3490         case X86_REG_XMM7:
3491             rid = "xmm7";
3492             break;
3493         case X86_REG_XMM8:
3494             rid = "xmm8";
3495             break;
3496         case X86_REG_XMM9:
3497             rid = "xmm9";
3498             break;
3499         case X86_REG_XMM10:
3500             rid = "xmm10";
3501             break;
3502         case X86_REG_XMM11:
3503             rid = "xmm11";
3504             break;
3505         case X86_REG_XMM12:
3506             rid = "xmm12";
3507             break;
3508         case X86_REG_XMM13:
3509             rid = "xmm13";
3510             break;
3511         case X86_REG_XMM14:
3512             rid = "xmm14";
3513             break;
3514         case X86_REG_XMM15:
3515             rid = "xmm15";
3516             break;
3517         default:
3518             if ((mr & X86_REG_MASK) < 32)
3519                 snprintf(buf, sizeof(buf), "rats%d",
3520                          mr & 255);
3521             else
3522                 snprintf(buf, sizeof(buf), "ratsF%d",
3523                          (mr - 32) & 255);
3524             rid = buf;
3525             break;
3526         }
3527         mr &= X86_REG_MASK;
3528
3529         switch (ext & REXTF_MASK) {
3530         case REXT_I8:
3531             dassert(mr < 32);
3532             if (mr < 4) {
3533                 printf("%%%cl", rid[0]);
3534             } else if (mr < 8) {
3535                 printf("%%%sl", rid);
3536             } else {
3537                 printf("%%%sb", rid);
3538             }
3539             break;
3540 #if 0
3541         case X86_SIZE_HIBYTE:
3542             dassert(mr < 4);
3543             printf("%%%ch", rid[0]);
3544             break;
3545 #endif
3546         case REXT_I16:
3547             dassert(mr < 32);
3548             if (mr < 8)
3549                 printf("%%%s", rid);
3550             else
3551                 printf("%%%sw", rid);
3552             break;
3553         case REXT_I32:
3554             if (mr < 8)
3555                 printf("%%e%s", rid);
3556             else if (mr < 32)
3557                 printf("%%%sd", rid);
3558             else
3559                 printf("%%%s", rid);
3560             break;
3561         case REXT_I64:
3562             if (mr < 8)
3563                 printf("%%r%s", rid);
3564             else if (mr < 32)
3565                 printf("%%%s", rid);
3566             else
3567                 printf("%%%s", rid);
3568             break;
3569         case REXT_I128:
3570             dassert(mr >= 32);
3571             printf("%%%s", rid);
3572             break;
3573         case REXT_F32:
3574             dassert(mr >= 32);
3575             printf("%%%s", rid);
3576             break;
3577         case REXT_F64:
3578             dassert(mr >= 32);
3579             printf("%%%s", rid);
3580             break;
3581         case REXT_F128:
3582             /*
3583              * Suitable for e.g. FMOVE, not suitable for fp stack ops.  FP
3584              * insns will do those manually.
3585              */
3586             dassert(mr >= 32);
3587             printf("%%%s", rid);
3588             break;
3589         default:
3590             printf("[REXT%d]", ext);
3591             break;
3592         }
3593     } else {
3594         if (regno & REGF_ADHOC) {
3595             if (regno & REGF_PTR)
3596                 printf("%%q%d", regno & REGF_MASK);
3597             else
3598                 printf("%%v%d", regno & REGF_MASK);
3599         } else if (regno & REGF_PTR) {
3600             switch (regno) {
3601             case REG_SG:
3602                 printf("%%sg");
3603                 break;
3604             case REG_RP:
3605                 printf("%%rp");
3606                 break;
3607             case REG_DB:
3608                 printf("%%db");
3609                 break;
3610             case REG_TP:
3611                 printf("%%tp");
3612                 break;
3613             case REG_AP:
3614                 printf("%%ap");
3615                 break;
3616             case REG_FP:
3617                 printf("%%fp");
3618                 break;
3619             case REG_PC:
3620                 printf("%%pc");
3621                 break;
3622             default:
3623                 printf("%%p%d", regno & REGF_MASK);
3624                 break;
3625             }
3626         } else {
3627             printf("%%r%d", regno & REGF_MASK);
3628         }
3629     }
3630 }
3631
3632 static
3633 void
3634 printREG(rea_t *rea, uint8_t ext)
3635 {
3636     printREGTGT(rea->target_reg, rea->regno, ext);
3637 }
3638
3639 void
3640 InsnDebugREG(uint16_t target_reg, uint8_t ext)
3641 {
3642     rea_t   rea;
3643
3644     rea.target_reg = target_reg;
3645     rea.regno = 0;
3646     printREG(&rea, ext);
3647 }
3648
3649 static
3650 void
3651 printINSN(rinsn_t * rin, const char *x86op, rea_t * sea, rea_t * dea,
3652           uint8_t extov)
3653 {
3654     int     sext;
3655     int     dext;
3656
3657     if (extov & REXTF_EA2) {
3658         printf("\t%s%s", x86op, x86ext(rin->ext2, rin->arg2.flags));
3659         sext = rin->ext2;
3660         dext = rin->ext2;
3661     } else {
3662         printf("\t%s%s", x86op, x86ext(rin->ext1, rin->arg1.flags));
3663         sext = rin->ext1;
3664         dext = rin->ext1;
3665     }
3666     if (extov & REXTF_SEA1)
3667         sext = rin->ext1;
3668     if (extov & REXTF_MASK) {
3669         sext = extov & REXTF_MASK;
3670         dext = extov & REXTF_MASK;
3671     }
3672
3673     if (sea && dea) {
3674         printf("\t");
3675         printEA(sea, sext);
3676         printf(", ");
3677         printEA(dea, dext);
3678     } else if (sea) {
3679         printf("\t");
3680         printEA(sea, sext);
3681     } else if (dea) {
3682         printf("\t");
3683         printEA(dea, dext);
3684     }
3685     printf("\n");
3686 }
3687
3688 static
3689 void
3690 printEA(rea_t *rea, uint8_t ext)
3691 {
3692     rea_t  *regea;
3693
3694     /*
3695      * Print the EA
3696      */
3697     switch (rea->eamode) {
3698     case EA_DIRECT:
3699         printREG(rea, ext);
3700         break;
3701     case EA_MEMORY:
3702         regea = rea;
3703         if (rea->direct) {
3704             regea = rea->direct;
3705
3706             /*
3707              * This can occur if the register allocator is unable to allocate
3708              * a mandatory register.
3709              */
3710             dassert(regea->eamode == EA_DIRECT);
3711         }
3712         if (rea->sym) {
3713             if (rea->sym->id[0] == '@')
3714                 printf("%s", rea->sym->id + 1);
3715             else
3716                 printf(".L%d%s", ProcNo, rea->sym->id);
3717             if (rea->offset > 0)
3718                 printf("+");
3719         }
3720         if (rea->offset ||
3721             (rea->sym == NULL && (regea->regno & ~REGF_PTR) == 0)) {
3722             printf("%jd", (intmax_t) rea->offset);
3723         }
3724         if (regea->target_reg || (regea->regno & ~REGF_PTR)) {
3725             printf("(");
3726             printREG(regea, ExtSize);
3727             printf(")");
3728         }
3729
3730         /*
3731          * Catch broken stack-relative accesses.
3732          */
3733         if (regea->target_reg == X86_REG_RSP && rea->offset >= ProcStackSize) {
3734             printf(" [OUT OF BOUNDS] ");
3735 #if 1
3736             dwarn("RAS Assembly used an out-of-bounds frame "
3737                    "offset (%zd/%zd)",
3738                    rea->offset, ProcStackSize);
3739 #endif
3740         }
3741         break;
3742     case EA_IMMEDIATE:
3743         if (rea->sym) {
3744             printf("%s", rea->sym->id);
3745             if (rea->immlo > 0)
3746                 printf("+");
3747         }
3748         if (rea->immlo || rea->sym == NULL)
3749             printf("$%jd", (intmax_t) rea->immlo);
3750         break;
3751     case EA_IMMEDIATE16:
3752         printf("$0x%016jx%016jx",
3753                (intmax_t) rea->immhi, (intmax_t) rea->immlo);
3754         break;
3755     default:
3756         printf("?ea=%d", rea->eamode);
3757         break;
3758     }
3759 }
3760
3761 static
3762 void
3763 printBRLabel(rsym_t *label)
3764 {
3765     printf(".L%d%s", ProcNo, label->id);
3766 }
3767
3768 /************************************************************************
3769  *                        REGISTGER ALLOCATOR                           *
3770  ************************************************************************
3771  *
3772  */
3773 static void
3774 regAllocEA(RASParser * p, rinsn_t * rin,
3775            rspan_t * arg, rspan_t * argd, int pass);
3776 static uint64_t regAllocSpan(rinsn_t * rin, rspan_t * span,
3777                              uint16_t target_reg, int special_case);
3778 static void regClearEA(RASParser *p, rspan_t *span, rspan_t *spand);
3779
3780 static
3781 void
3782 RegAllocatorX86(RASParser *p, rblock_t *rblock, urunesize_t bytes)
3783 {
3784     int     wlow = 0;
3785     int     whigh = 65536;
3786     int     wmid;
3787
3788     /*
3789      * Try maximum registerization first.
3790      */
3791     RegAllocWeight = 0;
3792     ExtraStackSpace = 0;
3793     ExtraStackBase = (bytes + RAWPTR_ALIGN) & ~RAWPTR_ALIGN;
3794     SaveMask = 0;
3795     RegAllocatorScan(p, rblock);
3796     if ((SaveMask & ~X86_REGF_GOOD) == 0)
3797         return;
3798
3799     /*
3800      * Didn't work, search the weighting.
3801      */
3802     while (wlow < whigh - 1) {
3803         RegAllocatorClear(p, rblock);
3804         wmid = wlow + (whigh - wlow) / 2;
3805         RegAllocWeight = wmid;
3806         SaveMask = 0;
3807         ExtraStackSpace = 0;
3808         ExtraStackBase = (bytes + RAWPTR_ALIGN) & ~RAWPTR_ALIGN;
3809         RegAllocatorScan(p, rblock);
3810         if (SaveMask & ~X86_REGF_GOOD) {
3811             /*
3812              * Too many registers were allocated, increase weight
3813              * requirement.
3814              */
3815             wlow = wmid;
3816         } else {
3817             /*
3818              * Not enough registers were allocated, increase weight
3819              * requirement.
3820              */
3821             whigh = wmid;
3822         }
3823     }
3824     if (SaveMask & ~X86_REGF_GOOD) {
3825         RegAllocatorClear(p, rblock);
3826         ++RegAllocWeight;
3827         SaveMask = 0;
3828         ExtraStackSpace = 0;
3829         ExtraStackBase = (bytes + RAWPTR_ALIGN) & ~RAWPTR_ALIGN;
3830         RegAllocatorScan(p, rblock);
3831     }
3832     if (SaveMask & ~X86_REGF_GOOD)
3833         fprintf(stderr, "UseWeight %d - FAILED (complexity %d)\n",
3834                 RegAllocWeight, p->pcomplexity);
3835     else
3836         fprintf(stderr, "UseWeight %d - Success\n", RegAllocWeight);
3837     fflush(stderr);
3838 }
3839
3840 static
3841 void
3842 RegAllocatorScan(RASParser *p, rblock_t *rblock)
3843 {
3844     rinsn_t *rin;
3845     uint64_t incmask = 0;
3846     int     pass;
3847
3848     if (rblock->flags & RBLKF_REGALLOCATOR)
3849         return;
3850     rblock->flags |= RBLKF_REGALLOCATOR;
3851
3852     for (pass = 1; pass < 2; ++pass) {
3853         RUNE_FOREACH(rin, &rblock->rinsn_list, node) {
3854             if (rin->op == INSN_LABEL)
3855                 continue;
3856
3857             /*
3858              * Note that as we are post-merge, some of these EAs may be the
3859              * same.
3860              */
3861             incmask |= rin->regused_init;
3862             regAllocEA(p, rin, &rin->arg1, &rin->arg1d, pass);
3863             regAllocEA(p, rin, &rin->arg2, &rin->arg2d, pass);
3864             regAllocEA(p, rin, &rin->arg3, &rin->arg3d, pass);
3865             regAllocEA(p, rin, &rin->arg4, &rin->arg4d, pass);
3866         }
3867         if (rblock->btrue) {
3868             RegAllocatorScan(p, rblock->btrue);
3869             if (rblock->bfalse)
3870                 RegAllocatorScan(p, rblock->bfalse);
3871         }
3872     }
3873     SaveMask |= incmask;
3874 }
3875
3876 /*
3877  * Allocate a register for an rea, adjust the rea's span to account for the
3878  * register.
3879  *
3880  * Generally speaking we have a 64-bit mask of which, really, only 16 general
3881  * registers are mapped.  Remaining bits are used to help calculate overflow.
3882  * If we fill up all 64-bits we will start allocating register %rats64.
3883  */
3884 static
3885 void
3886 regAllocEA(RASParser *p, rinsn_t *rin, rspan_t *arg, rspan_t *argd, int pass)
3887 {
3888     int     special_case;
3889     uint64_t agg;
3890     rea_t  *rea;
3891
3892     rea = arg->rea;
3893     if (rea == NULL)
3894         return;
3895     if (rea->direct)
3896         regAllocEA(p, rin, argd, NULL, pass);
3897     dassert(rin == arg->rin);
3898     if ((rea->flags & REAF_CACHEABLE) == 0)
3899         return;
3900     dassert(rea->refs == 1 || arg->root);
3901
3902     /*
3903      * Already allocated (SaveMask also already set).  Happens for many
3904      * reasons including rea's representing the same object being shared.
3905      */
3906     if (rea->flags & REAF_REGALLOCD)
3907         return;
3908
3909     /*
3910      * If the instruction is being dropped adjust the masks just so the
3911      * deallocator is happy (the bit is most likely just going to get cleared
3912      * again), but do NOT set the register in SaveMask yet as we are not
3913      * actually going to use it in this insn.
3914      *
3915      * This allows someone else to use this register and still span this
3916      * instruction.
3917      *
3918      * XXX It would be even better if the BlockReach*() code could chain the
3919      * drops upward and potentially drop even more instructions, but DROPME
3920      * is set later in the BlockCollapse() so at the moment this is the best
3921      * we can do.  Regardless, this is still 100% efficient IF this was the
3922      * only instruction using this cacheable EA.
3923      */
3924     if (rin->flags & RINSF_DROPME)
3925         return;
3926
3927     /*
3928      * We don't need to reallocate if we already allocated it or if the
3929      * register was statically assigned.
3930      */
3931     if (rea->target_reg)        /* statically allocated */
3932         return;
3933
3934     /*
3935      * Check EA weight, do not allocate register if too low.
3936      *
3937      * Distinguish between direct and indirect registers.  This is a bit
3938      * confusing.  For EA_DIRECT, if REAF_DIRECT is set we are pushed into a
3939      * rea->direct rea and working on an indirect register.  If not set, then
3940      * we are working on a direct register.
3941      *
3942      * Generally speaking, we must allocate a real register for indirect
3943      * registers.
3944      */
3945     special_case = 0;
3946     if (rea->regweight < RegAllocWeight || (rea->flags & REAF_ADDRUSED)) {
3947         if (rea->orig_eamode == EA_MEMORY)
3948             return;
3949         if (rea->orig_eamode == EA_DIRECT &&
3950             (rea->flags & REAF_DIRECT) == 0) {
3951             urunesize_t bytes;
3952
3953             if (rea->regno & REGF_PTR) {
3954                 bytes = RAWPTR_SIZE;
3955             } else {
3956                 switch (rin->ext1) {
3957                 case REXT_I8:
3958                     bytes = 1;
3959                     break;
3960                 case REXT_I16:
3961                     bytes = 2;
3962                     break;
3963                 case REXT_I32:
3964                     bytes = 4;
3965                     break;
3966                 case REXT_I64:
3967                     bytes = 8;
3968                     break;
3969                 case REXT_I128:
3970                     bytes = 16;
3971                     break;
3972                 case REXT_F32:
3973                     bytes = 4;
3974                     break;
3975                 case REXT_F64:
3976                     bytes = 8;
3977                     break;
3978                 case REXT_F128:
3979                     bytes = 16;
3980                     break;
3981                 default:
3982                     dpanic("Unknown REXT %d", rin->ext1);
3983                     bytes = 1;
3984                     break;
3985                 }
3986             }
3987             ExtraStackSpace = (ExtraStackSpace + bytes - 1) &
3988                 ~(bytes - 1);
3989             rea->eamode = EA_MEMORY;
3990             rea->offset = ExtraStackBase + ExtraStackSpace;
3991             rea->orig_offset = rea->offset;
3992             rea->target_reg = X86_REG_RSP;
3993             ExtraStackSpace += bytes;
3994             rea->flags |= REAF_REGALLOCD;
3995             return;
3996         }
3997         special_case = 1;
3998     }
3999
4000     /*
4001      * If allocating.  Once allocated the target_reg remains intact through
4002      * potentially many shared references and passes.  Keep in mind that many
4003      * instructions may share this rea.
4004      */
4005     switch (rea->eamode) {
4006     case EA_IMMEDIATE:
4007         break;
4008     case EA_MEMORY:
4009         if (rea->regno == 0)
4010             break;
4011         agg = regAllocSpan(rin, arg, 0, special_case);
4012         agg |= X86_REGF_RSP | X86_REGF_RIP;
4013         if (arg->flags & RAF_FLOAT)
4014             agg |= X86_REGF_IMASK;
4015         else
4016             agg |= X86_REGF_FMASK;
4017         rea->target_reg = findfreebit(0, agg);
4018 #if 0
4019         if ((1LLU << rea->target_reg) & ~X86_REGF_GOOD)
4020             printf("MEMALLOCFAIL-%d %016jx [%016jx] @%s[%p]\n",
4021                    special_case,
4022                    agg,
4023                    regAllocSpan(rin, arg, 0, special_case),
4024                    rin->opname, rea);
4025 #endif
4026         dassert(rea->regno == REG_FP ||
4027                 rea->target_reg != (X86_REG_RSP & X86_REG_MASK));
4028         SaveMask |= 1LLU << rea->target_reg;
4029         rea->target_reg |= X86_SIZE_UNSPEC;
4030         regAllocSpan(rin, arg, rea->target_reg, special_case);
4031         rea->eamode = EA_DIRECT;
4032         rea->flags |= REAF_REGALLOCD;
4033         break;
4034     case EA_DIRECT:
4035         dassert(rea->regno);
4036         agg = regAllocSpan(rin, arg, 0, special_case);
4037         agg |= X86_REGF_RSP | X86_REGF_RIP;
4038         if (arg->flags & RAF_FLOAT)
4039             agg |= X86_REGF_IMASK;
4040         else
4041             agg |= X86_REGF_FMASK;
4042         rea->target_reg = findfreebit(rea->regno, agg);
4043 #if 0
4044         if ((1LLU << rea->target_reg) & ~X86_REGF_GOOD)
4045             printf("DIRALLOCFAIL-%d %016jx [%016jx] @%s[%p]\n",
4046                    special_case,
4047                    agg,
4048                    regAllocSpan(rin, arg, 0, special_case),
4049                    rin->opname, rea);
4050 #endif
4051         dassert(rea->regno == REG_FP ||
4052                 rea->target_reg != (X86_REG_RSP & X86_REG_MASK));
4053         SaveMask |= 1LLU << rea->target_reg;
4054         rea->target_reg |= X86_SIZE_UNSPEC;
4055         regAllocSpan(rin, arg, rea->target_reg, special_case);
4056         rea->eamode = EA_DIRECT;
4057         rea->flags |= REAF_REGALLOCD;
4058         break;
4059     }
4060 }
4061
4062 static uint64_t regAllocSpanRecurse(rspan_t * skel, uint64_t mask, uint64_t bit,
4063                                     uint16_t target_reg, int special_case);
4064
4065 static
4066 uint64_t
4067 regAllocSpan(rinsn_t *rin, rspan_t *span, uint16_t target_reg, int special_case)
4068 {
4069     uint64_t mask;
4070     uint64_t bit;
4071
4072     bit = 1LLU << (target_reg & X86_REG_MASK);
4073
4074     if (special_case)
4075         mask = rin->regused_init & ~X86_REGF_SPECIAL_SAVE;
4076     else
4077         mask = rin->regused_init;
4078
4079     mask |= rin->regused_agg;
4080     if (target_reg) {
4081         rin->regused_agg |= bit;
4082         if (special_case &&
4083             (bit & rin->regused_init & X86_REGF_SPECIAL_SAVE)) {
4084             rin->special_save |= bit;
4085         }
4086     }
4087     if (span->root) {
4088         mask = regAllocSpanRecurse(span->root, mask, bit,
4089                                    target_reg, special_case);
4090         SpanClear(span->root);
4091     }
4092
4093     return mask;
4094 }
4095
4096 static
4097 uint64_t
4098 regAllocSpanRecurse(rspan_t * skel, uint64_t mask, uint64_t bit,
4099                     uint16_t target_reg, int special_case)
4100 {
4101     rinsn_t *rin;
4102     rspan_t *span;
4103
4104     if (skel->flags & RAF_SPAN) /* already scanned */
4105         return (mask);
4106     skel->flags |= RAF_SPAN;
4107
4108     span = skel->link;
4109     if (skel->flags & RAF_SKELETON) {
4110         if (span)
4111             rin = span->rin;
4112         else
4113             rin = NULL;
4114     } else {
4115         rin = RUNE_FIRST(&skel->block->rinsn_list);
4116     }
4117     while (rin) {
4118         /*
4119          * Incorporate bit
4120          */
4121         if (special_case)
4122             mask |= rin->regused_init & ~X86_REGF_SPECIAL_SAVE;
4123         else
4124             mask |= rin->regused_init;
4125         mask |= rin->regused_agg;
4126         if (target_reg) {
4127             rin->regused_agg |= bit;
4128             if (special_case && (bit & rin->regused_init &
4129                                  X86_REGF_SPECIAL_SAVE)) {
4130                 rin->special_save |= bit;
4131             }
4132         }
4133
4134         /*
4135          * Check span for rin iteration.
4136          *
4137          * If there are no more instructions in this block using our
4138          * variable, check our block linkages.  If all block linkages set
4139          * RAF_SKELETON then the variable is not used any more and we can
4140          * stop.
4141          */
4142         while (span && span->rin == rin)
4143             span = span->link;
4144         if (span == NULL) {
4145             if ((skel->strue == NULL ||
4146                  (skel->strue->flags & RAF_SKELETON)) &&
4147                 (skel->sfalse == NULL ||
4148                  (skel->sfalse->flags & RAF_SKELETON))) {
4149                 break;
4150             }
4151         }
4152         rin = RUNE_NEXT(rin, node);
4153     }
4154
4155     /*
4156      * Recurse skeleton
4157      */
4158     if (skel->strue)
4159         mask = regAllocSpanRecurse(skel->strue, mask, bit,
4160                                    target_reg, special_case);
4161     if (skel->sfalse)
4162         mask = regAllocSpanRecurse(skel->sfalse, mask, bit,
4163                                    target_reg, special_case);
4164     return mask;
4165 }
4166
4167 static
4168 void
4169 RegAllocatorClear(RASParser *p, rblock_t *rblock)
4170 {
4171     rinsn_t *rin;
4172
4173     if ((rblock->flags & RBLKF_REGALLOCATOR) == 0)
4174         return;
4175     rblock->flags &= ~RBLKF_REGALLOCATOR;
4176     RUNE_FOREACH(rin, &rblock->rinsn_list, node) {
4177         rin->regused_agg = 0;
4178         if (rin->op == INSN_LABEL)
4179             continue;
4180         rin->special_save = 0;
4181         if (rin->arg1.rea)
4182             regClearEA(p, &rin->arg1, &rin->arg1d);
4183         if (rin->arg2.rea)
4184             regClearEA(p, &rin->arg2, &rin->arg2d);
4185         if (rin->arg3.rea)
4186             regClearEA(p, &rin->arg3, &rin->arg3d);
4187         if (rin->arg4.rea)
4188             regClearEA(p, &rin->arg4, &rin->arg4d);
4189
4190         if (rin->brtrue) {
4191             dassert(RUNE_NEXT(rin, node) == NULL);
4192             RegAllocatorClear(p, rin->brtrue->label_block);
4193             if (rin->brfalse)
4194                 RegAllocatorClear(p, rin->brfalse->label_block);
4195         }
4196     }
4197 }
4198
4199 static
4200 void
4201 regClearEA(RASParser *p, rspan_t *span, rspan_t *spand)
4202 {
4203     rea_t  *rea = span->rea;
4204
4205     if (rea->direct) {
4206         dassert(rea->direct == spand->rea);
4207         regClearEA(p, spand, NULL);
4208     }
4209     if (rea->flags & REAF_REGALLOCD) {
4210         rea->target_reg = 0;
4211         rea->eamode = rea->orig_eamode;
4212         rea->regno = rea->orig_regno;
4213         rea->offset = rea->orig_offset;
4214         rea->flags &= ~REAF_REGALLOCD;
4215     }
4216 }
4217
4218 /************************************************************************
4219  *                          HELPER FUNCTIONS                            *
4220  ************************************************************************
4221  *
4222  */
4223 static
4224 int
4225 findfreebit(uint32_t regno, uint64_t mask)
4226 {
4227     static int lookup[16] = {
4228          /* 0 */ 0,
4229          /* 1 */ 1,
4230          /* 2 */ 0,
4231          /* 3 */ 2,
4232          /* 4 */ 0,
4233          /* 5 */ 1,
4234          /* 6 */ 0,
4235          /* 7 */ 3,
4236          /* 8 */ 0,
4237          /* 9 */ 1,
4238          /* A */ 0,
4239          /* B */ 2,
4240          /* C */ 0,
4241          /* D */ 1,
4242          /* E */ 0,
4243          /* F */ 4
4244     };
4245
4246     /*
4247      * Prefer certain registers, disallow others.
4248      */
4249     if (regno) {
4250         switch (regno) {
4251         case REG_PC:
4252             return (X86_REG_RIP & X86_REG_MASK);
4253         case REG_FP:
4254             return (X86_REG_RSP & X86_REG_MASK);
4255         case REG_AP:
4256             if (mask & (1LLU << (X86_REG_RSI & X86_REG_MASK)))
4257                 break;
4258             return (X86_REG_RSI & X86_REG_MASK);
4259             break;
4260         case REG_RP:
4261             if (mask & (1LLU << (X86_REG_RDI & X86_REG_MASK)))
4262                 break;
4263             return (X86_REG_RDI & X86_REG_MASK);
4264             break;
4265         case REG_SG:
4266             if (mask & (1LLU << (X86_REG_RDX & X86_REG_MASK)))
4267                 break;
4268             return (X86_REG_RDX & X86_REG_MASK);
4269             break;
4270         }
4271     }
4272
4273     /*
4274      * General bit find
4275      */
4276     if ((mask & 0x00000000FFFFFFFFLLU) == 0x00000000FFFFFFFFLLU)
4277         return (findfreebit(0, mask >> 32) + 32);
4278     if ((mask & 0x000000000000FFFFLLU) == 0x000000000000FFFFLLU)
4279         return (findfreebit(0, mask >> 16) + 16);
4280     if ((mask & 0x00000000000000FFLLU) == 0x00000000000000FFLLU)
4281         return (findfreebit(0, mask >> 8) + 8);
4282     if ((mask & 0x000000000000000FLLU) == 0x000000000000000FLLU)
4283         return (findfreebit(0, mask >> 4) + 4);
4284     return (lookup[(int)mask & 15]);
4285 }
4286
4287 #if 0
4288 static
4289 void
4290 clearregbit(uint64_t *mask, rea_t *rea)
4291 {
4292     if (rea->target_reg)
4293         *mask &= ~(1LLU << (rea->target_reg & X86_REG_MASK));
4294 }
4295 #endif
4296
4297 static
4298 const char *
4299 x86ext(char c, uint8_t argflags)
4300 {
4301     if (argflags & RAF_FLOAT)
4302         c |= REXTF_FLOAT;
4303
4304     switch (c) {
4305     case REXT_I8:
4306         return ("b");
4307     case REXT_I16:
4308         return ("w");
4309     case REXT_I32:
4310         return ("l");
4311     case REXT_I64:
4312         return ("q");
4313     case REXT_F32:
4314         return ("ss");
4315     case REXT_F64:
4316         return ("sd");
4317     case REXT_F128:
4318         return ("aps");
4319     default:
4320         return ("?");
4321     }
4322 }
4323
4324 static
4325 const
4326 char   *
4327 x86branch(uint32_t op, int invert, int reverse)
4328 {
4329     if (invert == 0) {
4330         if (reverse) {
4331             switch (op & 0x0F00) {
4332             case 0x0000:        /* EQ */
4333                 return ("e");
4334             case 0x0100:        /* NE */
4335                 return ("ne");
4336             case 0x0200:        /* UGT */
4337                 return ("a");
4338             case 0x0300:        /* UGE */
4339                 return ("nb");
4340             case 0x0400:        /* ULT */
4341                 return ("b");
4342             case 0x0500:        /* ULE */
4343                 return ("be");
4344             case 0x0600:        /* SGT */
4345                 return ("g");
4346             case 0x0700:        /* SGE */
4347                 return ("ge");
4348             case 0x0800:        /* SLT */
4349                 return ("l");
4350             case 0x0900:        /* SLE */
4351                 return ("le");
4352             default:
4353                 return ("??");
4354             }
4355         } else {
4356             switch (op & 0x0F00) {
4357             case 0x0000:        /* EQ */
4358                 return ("e");
4359             case 0x0100:        /* NE */
4360                 return ("ne");
4361             case 0x0200:        /* UGT */
4362                 return ("b");
4363             case 0x0300:        /* UGE */
4364                 return ("be");
4365             case 0x0400:        /* ULT */
4366                 return ("a");
4367             case 0x0500:        /* ULE */
4368                 return ("nb");
4369             case 0x0600:        /* SGT */
4370                 return ("l");
4371             case 0x0700:        /* SGE */
4372                 return ("le");
4373             case 0x0800:        /* SLT */
4374                 return ("g");
4375             case 0x0900:        /* SLE */
4376                 return ("ge");
4377             default:
4378                 return ("??");
4379             }
4380         }
4381     } else {
4382         if (reverse) {
4383             switch (op & 0x0F00) {
4384             case 0x0000:        /* EQ */
4385                 return ("ne");
4386             case 0x0100:        /* NE */
4387                 return ("e");
4388             case 0x0200:        /* UGT */
4389                 return ("be");
4390             case 0x0300:        /* UGE */
4391                 return ("b");
4392             case 0x0400:        /* ULT */
4393                 return ("nb");
4394             case 0x0500:        /* ULE */
4395                 return ("a");
4396             case 0x0600:        /* SGT */
4397                 return ("le");
4398             case 0x0700:        /* SGE */
4399                 return ("l");
4400             case 0x0800:        /* SLT */
4401                 return ("ge");
4402             case 0x0900:        /* SLE */
4403                 return ("g");
4404             default:
4405                 return ("??");
4406             }
4407         } else {
4408             switch (op & 0x0F00) {
4409             case 0x0000:        /* EQ */
4410                 return ("ne");
4411             case 0x0100:        /* NE */
4412                 return ("e");
4413             case 0x0200:        /* UGT */
4414                 return ("nb");
4415             case 0x0300:        /* UGE */
4416                 return ("a");
4417             case 0x0400:        /* ULT */
4418                 return ("be");
4419             case 0x0500:        /* ULE */
4420                 return ("b");
4421             case 0x0600:        /* SGT */
4422                 return ("ge");
4423             case 0x0700:        /* SGE */
4424                 return ("g");
4425             case 0x0800:        /* SLT */
4426                 return ("le");
4427             case 0x0900:        /* SLE */
4428                 return ("l");
4429             default:
4430                 return ("??");
4431             }
4432         }
4433     }
4434 }
4435
4436 static
4437 int
4438 sameEA(rea_t *rea1, rea_t *rea2)
4439 {
4440     if (rea1->eamode == EA_DIRECT && rea2->eamode == EA_DIRECT) {
4441         dassert(rea1->target_reg);
4442         dassert(rea2->target_reg);
4443     }
4444
4445     /*
4446      * NOTE: No need to test cache_id at this point.
4447      */
4448     if (rea1->regno == rea2->regno &&
4449         rea1->target_reg == rea2->target_reg &&
4450         rea1->offset == rea2->offset &&
4451         rea1->sym == rea2->sym &&
4452         rea1->immlo == rea2->immlo &&
4453         rea1->immhi == rea2->immhi)
4454         return 1;
4455     else
4456         return 0;
4457 }
4458
4459 static
4460 int
4461 adjacentLabel(rinsn_t *rin, rsym_t *sym)
4462 {
4463     rinsn_t *scan;
4464     rblock_t *block;
4465
4466     scan = RUNE_NEXT(rin, node);
4467     for (;;) {
4468         while (scan) {
4469             if (scan->op != INSN_LABEL)
4470                 return 0;
4471             if (sym == scan->label)
4472                 return 1;
4473             scan = RUNE_NEXT(scan, node);
4474         }
4475         block = RUNE_NEXT(rin->block, node);
4476         if (block == NULL)
4477             break;
4478         rin = scan = RUNE_FIRST(&block->rinsn_list);
4479     }
4480     return 0;
4481 }
4482
4483 static
4484 rinsn_t *
4485 allocInsnBlock(RASParser * p, rblock_t * rblock, uint32_t op,
4486                uint8_t ext, int args)
4487 {
4488     rinsn_t *rin;
4489     rea_t  *rea;
4490     int     i;
4491
4492     rin = zalloc(sizeof(*rin));
4493     rin->op = op;
4494     rin->operands = args;
4495     rin->ext1 = ext;
4496
4497     for (i = 0; i < args; ++i) {
4498         rea = zalloc(sizeof(*rea));
4499         rea->refs = 1;
4500
4501         switch (i) {
4502         case 0:
4503             rin->arg1.rea = rea;
4504             break;
4505         case 1:
4506             rin->arg2.rea = rea;
4507             break;
4508         case 2:
4509             rin->arg3.rea = rea;
4510             break;
4511         case 3:
4512             rin->arg4.rea = rea;
4513             break;
4514         default:
4515             dpanic("Too many EAs for allocInsnBlock()");
4516             break;
4517         }
4518     }
4519     switch (op) {
4520     case INSN_MOVE:
4521         rin->opname = "MOVE";
4522         rin->func = InsnMOVE;
4523         break;
4524     default:
4525         dpanic("Unsupported insn for allocInsnBlock()");
4526         break;
4527     }
4528
4529     /* rin->block = rblock; handled by block scan */
4530     InsnTargetAdjust(p, rin);
4531     RasBlockAdd(rblock, rin);
4532
4533     return rin;
4534 }
4535
4536 /*
4537  * Initialize an rea, make it cacheable if EA_DIRECT+reg or EA_IMMEDIATE*
4538  */
4539 static
4540 void
4541 initEA(rea_t *rea, uint8_t eamode, uint32_t regno, uint16_t target_reg)
4542 {
4543     rea->eamode = eamode;
4544     rea->regno = regno;
4545     rea->target_reg = target_reg;
4546     rea->orig_eamode = eamode;
4547     rea->orig_regno = regno;
4548     if (target_reg == 0 && regno && eamode == EA_DIRECT)
4549         rea->flags |= REAF_CACHEABLE;
4550     if (eamode == EA_IMMEDIATE || eamode == EA_IMMEDIATE16)
4551         rea->flags |= REAF_CACHEABLE;
4552 }