Rune - Further Object abstraction work
[rune.git] / ras / proc.c
1 /*
2  * PROC.C
3  *
4  * (c)Copyright 2016, Matthew Dillon, All Rights Reserved.  See the COPYRIGHT
5  * file at the base of the distribution.
6  */
7
8 #include "defs.h"
9
10 typedef struct GlobalImmediate {
11     struct GlobalImmediate *next;
12     uint64_t immlo;
13     uint64_t immhi;
14     uint8_t ext;
15     uint8_t bytes;
16     uint8_t unused02;
17     uint8_t unused03;
18     rsym_t *sym;
19 } gimm_t;
20
21 #define DOTRACE 0
22
23 static void rasDebugInsn(rinsn_t *rin, int dotrace);
24 static void rasDebugEA(rinsn_t *rin, rspan_t *span, rspan_t *spand);
25 static void rasDebugREXT(uint8_t ext);
26 static void rasDebugREG(uint8_t ext, rea_t *rea);
27
28 int     ProcNo;
29 srunesize_t ProcStackSize;
30 srunesize_t ProcStackPad;
31 void    (*RegAllocator) (RASParser *p, rblock_t *rblock, urunesize_t bytes);
32 gimm_t *GIMMBase;
33 void    (*ProbeFunc) (RASParser *p, rinsn_t *rin);
34
35 /*
36  * .proc symbol, stacksz, stackalgn
37  */
38 void
39 PsopPROC(RASParser *p, rinsn_t *dummy __unused)
40 {
41     rsym_t *psym;
42     rsym_t *lab;
43     rblock_t *rblock;
44     rinsn_t *rin;
45     rastoken_t t = p->tok;
46     urunesize_t bytes;
47     urunesize_t align;
48     rinsn_t dummy_rin;
49
50     RasResetRegNumbering();
51     RasSymReinit();
52     t = RasToken(p);            /* skip .proc */
53     dummy_rin.loc_file = 0;
54     dummy_rin.loc_line = 0;
55
56     /*
57      * Entry block
58      */
59     RUNE_INIT(&p->rblock_list);
60     RUNE_INIT(&p->blockdef_list);
61     rblock = RasBlockAlloc(&p->rblock_list);
62
63     t = RasParseSymbol(p, t, &psym);
64     bytes = 0;
65     align = 0;
66     if (t == RAS_TOK_COMMA) {
67         t = RasParseSizeValue(p, RasToken(p), &bytes);
68         if (t == RAS_TOK_COMMA) {
69             t = RasParseSizeValue(p, RasToken(p), &align);
70         }
71     }
72     if (t) {
73         RasError(p, "Extranious junk on line");
74         return;
75     }
76     if (p->error)
77         return;
78     p->psym = psym;
79
80     ++ProcNo;
81
82     InsnProcedureBasicBlock(p, rblock, bytes, align);
83
84     /*
85      * Collect the instructions for the procedure into basic blocks. Add any
86      * missing fall-through linkages (allows us to rearrange any block except
87      * the entry block).
88      */
89     while (RasLine(p, &lab)) {
90         /*
91          * Check for symbol, allow processing
92          */
93         rsym_t *isym;
94         int     maxea;
95         uint32_t chize;
96
97         t = RasToken(p);
98         if (lab) {
99             if (t == RAS_TOK_COLON) {
100                 t = RasToken(p);
101                 if (t == 0) {
102                     rin = zalloc(sizeof(*rin));
103                     rin->op = INSN_LABEL;
104                     rin->func = InsnLABEL;
105                     rin->label = lab;
106                     rin->loc_file = dummy_rin.loc_file;
107                     rin->loc_line = dummy_rin.loc_line;
108                     rin->ras_line = p->lineno;
109                     RasBlockAdd(rblock, rin);
110                 } else {
111                     RasError(p, "label: must be on a line "
112                              "by itself");
113                 }
114                 continue;
115             }
116             rin = zalloc(sizeof(*rin));
117             rin->op = INSN_LABEL;
118             rin->func = InsnLABEL;
119             rin->label = lab;
120             rin->loc_file = dummy_rin.loc_file;
121             rin->loc_line = dummy_rin.loc_line;
122             rin->ras_line = p->lineno;
123             RasBlockAdd(rblock, rin);
124         }
125
126         /*
127          * Empty remainder.
128          */
129         if (t == 0)
130             continue;
131
132         /*
133          * Pseudoop
134          */
135         if (t == RAS_TOK_DOT) {
136             if (lab)
137                 RasError(p, "labeled pseudoop is not legal");
138             t = RasToken(p);
139             if (t != RAS_TOK_ID && t != RAS_TOK_SYMBOL) {
140                 RasError(p, "Unknown pseudoop");
141                 continue;
142             }
143             isym = p->sym;
144             if (isym->tok == RAS_TOK_ENDPROC)
145                 break;
146             if (isym->tok == RAS_TOK_FILE) {
147                 isym->func(p, NULL);
148             } else if (isym->tok == RAS_TOK_LOC) {
149                 isym->func(p, &dummy_rin);
150             } else {
151                 RasError(p, "this pseudoop is illegal "
152                          "inside .proc");
153             }
154             continue;
155         }
156         if (t != RAS_TOK_ID && t != RAS_TOK_SYMBOL) {
157             RasError(p, "Expected instruction");
158             continue;
159         }
160         isym = p->sym;
161         if ((isym->tok & INSNF_INSN) == 0) {
162             RasError(p, "Expected instruction");
163             continue;
164         }
165
166         /*
167          * Ok, parse-out the instruction
168          */
169         rin = zalloc(sizeof(*rin));
170         rin->op = isym->tok & ~RAS_TOKF_INSN;
171         rin->opname = isym->id;
172         rin->func = isym->func;
173         rin->loc_file = dummy_rin.loc_file;
174         rin->loc_line = dummy_rin.loc_line;
175         rin->ras_line = p->lineno;
176
177         t = RasParseInsnEXT(p, RasToken(p), rin);
178
179         if (rin->flags & RINSF_BRANCH) {
180             dassert(rin->op & INSNF_COND);
181
182             switch (rin->op) {
183             case INSN_JMP:
184                 maxea = 0;
185                 break;
186             case INSN_TEST_EQ:
187                 maxea = 1;
188                 break;
189             case INSN_TEST_NE:
190                 maxea = 1;
191                 break;
192             default:
193                 maxea = 2;
194                 break;
195             }
196         } else {
197             maxea = 4;
198         }
199
200         if (t && maxea > 0) {
201             t = RasParseEA(p, t, rin, &rin->arg1, &rin->arg1d);
202             rin->operands = 1;
203         }
204         if (t == RAS_TOK_COMMA && maxea > 1) {
205             t = RasToken(p);
206             t = RasParseEA(p, t, rin, &rin->arg2, &rin->arg2d);
207             rin->operands = 2;
208         }
209         if (t == RAS_TOK_COMMA && maxea > 2) {
210             t = RasToken(p);
211             t = RasParseEA(p, t, rin, &rin->arg3, &rin->arg3d);
212             rin->operands = 3;
213         }
214         if (t == RAS_TOK_COMMA && maxea > 3) {
215             t = RasToken(p);
216             t = RasParseEA(p, t, rin, &rin->arg4, &rin->arg4d);
217             rin->operands = 4;
218         }
219
220         /*
221          * Handle characterization of the EAs to the instruction.
222          */
223         chize = isym->characterize;
224         if (chize & CHF_READLST) {
225             switch (rin->operands) {
226             case 0:
227                 break;
228             case 1:
229                 chize |= CHF_READ1;
230                 break;
231             case 2:
232                 chize |= CHF_READ2;
233                 break;
234             case 3:
235                 chize |= CHF_READ3;
236                 break;
237             case 4:
238                 chize |= CHF_READ4;
239                 break;
240             }
241         }
242         if (chize & CHF_WRITELST) {
243             switch (rin->operands) {
244             case 0:
245                 break;
246             case 1:
247                 chize |= CHF_WRITE1;
248                 break;
249             case 2:
250                 chize |= CHF_WRITE2;
251                 break;
252             case 3:
253                 chize |= CHF_WRITE3;
254                 break;
255             case 4:
256                 chize |= CHF_WRITE4;
257                 break;
258             }
259         }
260         if (chize & CHF_FLOATLST) {
261             switch (rin->operands) {
262             case 0:
263                 break;
264             case 1:
265                 chize |= CHF_FLOAT1;
266                 break;
267             case 2:
268                 chize |= CHF_FLOAT2;
269                 break;
270             case 3:
271                 chize |= CHF_FLOAT3;
272                 break;
273             case 4:
274                 chize |= CHF_FLOAT4;
275                 break;
276             }
277         }
278
279         if (rin->operands >= 1) {
280             rin->arg1.flags |= (chize >> CHF_ARG1SHIFT) &
281                 CHF_ARG1MASK;
282             if (rin->arg1.flags & RAF_LEA) {
283                 rin->arg1.rea->flags |= REAF_ADDRUSED;
284                 rin->arg1.rea->flags &= ~REAF_CACHEABLE;
285             }
286         }
287         if (rin->operands >= 2) {
288             rin->arg2.flags |= (chize >> CHF_ARG2SHIFT) &
289                 CHF_ARG1MASK;
290             if (rin->arg2.flags & RAF_LEA) {
291                 rin->arg2.rea->flags |= REAF_ADDRUSED;
292                 rin->arg2.rea->flags &= ~REAF_CACHEABLE;
293             }
294         }
295         if (rin->operands >= 3) {
296             rin->arg3.flags |= (chize >> CHF_ARG3SHIFT) &
297                 CHF_ARG1MASK;
298             if (rin->arg3.flags & RAF_LEA) {
299                 rin->arg3.rea->flags |= REAF_ADDRUSED;
300                 rin->arg3.rea->flags &= ~REAF_CACHEABLE;
301             }
302         }
303         if (rin->operands >= 4) {
304             rin->arg4.flags |= (chize >> CHF_ARG4SHIFT) &
305                 CHF_ARG1MASK;
306             if (rin->arg4.flags & RAF_LEA) {
307                 rin->arg4.rea->flags |= REAF_ADDRUSED;
308                 rin->arg4.rea->flags &= ~REAF_CACHEABLE;
309             }
310         }
311
312         /*
313          * Branches always have two branch targets, one for true and one for
314          * false, except for JMP which only has one.
315          */
316         if (rin->flags & RINSF_BRANCH) {
317             if (maxea != 0) {
318                 if (t == RAS_TOK_COMMA)
319                     t = RasToken(p);
320                 else
321                     RasError(p, "Condition branch missing");
322             }
323             t = RasParseLabel(p, t, &rin->brtrue);
324             if (t == RAS_TOK_COMMA) {
325                 t = RasToken(p);
326                 t = RasParseLabel(p, t, &rin->brfalse);
327             } else if (rin->op != INSN_JMP) {
328                 RasError(p, "Conditional needs "
329                          "two branch labels");
330             }
331         }
332         if (t) {
333             RasError(p, "Extranious junk after instruction");
334         }
335
336         /*
337          * The RET instruction is effectively a branch for the purposes of
338          * block characterization.
339          */
340         if (rin->op == INSN_RET)
341             rin->flags |= RINSF_BRANCH;
342
343         /*
344          * Add the instruction to the current basic block, possibly creating
345          * a new basic block.
346          */
347         InsnTargetAdjust(p, rin);
348         RasBlockAdd(rblock, rin);
349     }
350
351     /*
352      * Basic characterization.  This separates the instructions out into
353      * multiple basic blocks, calculates the life times for cacheable
354      * elements and shares the related EAs.  Set appropriate insn->argflags.
355      * Note that non-overlapping independent use cases for the same cacheable
356      * element are considered to be different, allowing better
357      * registerization.
358      *
359      * The original basic block (rblock here, first item in the list and only
360      * item to start) stays intact, but hopefully with most instructions
361      * moved out of it.
362      */
363     BlockCharacterize(p, rblock);
364     BlockCollapse(p, rblock);
365
366     /*
367      * Optimize, potentially reordering basic blocks.  Note that conditionals
368      * always automatically self-optimize through reversal or inversion.
369      */
370     RegAllocator(p, RUNE_FIRST(&p->rblock_list), bytes);
371
372     /*
373      * Track .loc output
374      */
375     dummy_rin.loc_file = 0;
376     dummy_rin.loc_line = 0;
377
378     /*
379      * Spit-out the results
380      */
381     InsnProcedureStart(p, bytes, align);
382     RUNE_FOREACH(rblock, &p->rblock_list, node) {
383         if (rblock->reachcount == 0) {
384             printf("# RBlock %p START count=%d not reachable XXX\n",
385                    rblock, rblock->count);
386         } else {
387             printf("# RBlock %p START count=%d\n",
388                    rblock, rblock->count);
389         }
390         if (rblock->reachcount) {
391             p->opt_last = 0;
392             p->opt_flags = 0;
393             RUNE_FOREACH(rin, &rblock->rinsn_list, node) {
394                 rasDebugInsn(rin, DOTRACE);
395                 if (rin->flags & RINSF_DROPME) {
396                     printf("\t# (dropped)\n");
397                 } else {
398                     if (dummy_rin.loc_file !=
399                         rin->loc_file ||
400                         dummy_rin.loc_line !=
401                         rin->loc_line) {
402                         dummy_rin.loc_file =
403                             rin->loc_file;
404                         dummy_rin.loc_line =
405                             rin->loc_line;
406                         if (rin->loc_file)
407                             printf("\t.loc\t%ju %jd 0\n",
408                                    (intmax_t)rin->loc_file,
409                                    (intmax_t)rin->loc_line);
410                     }
411                     dassert(rin->func != NULL);
412                     p->opt_last = p->opt_flags;
413                     p->opt_flags = 0;
414                     if (ProbeFunc)
415                         ProbeFunc(p, rin);
416                     rin->func(p, rin);
417                 }
418             }
419         }
420         if (ProbeFunc)
421             ProbeFunc(p, NULL);
422         printf("# RBlock %p END\n", rblock);
423     }
424     printf(".LRET%d:\n", ProcNo);
425     InsnProcedureEnd(p, bytes, align);
426
427     /*
428      * Post cleanup
429      */
430     printf("\t.size\t%s, . - %s\n", psym->id + 1, psym->id + 1);
431     printf("\n");
432     DumpGlobalImmediates();
433     RasInvalidateRegNumbering();
434
435     /*
436      * Cleanup
437      */
438     while ((rblock = RUNE_FIRST(&p->rblock_list)) != NULL) {
439         while ((rin = RUNE_FIRST(&rblock->rinsn_list)) != NULL) {
440             RUNE_REMOVE(&rblock->rinsn_list, rin, node);
441             droprea(&rin->arg1);
442             droprea(&rin->arg2);
443             droprea(&rin->arg3);
444             droprea(&rin->arg4);
445             droprea(&rin->arg1d);
446             droprea(&rin->arg2d);
447             droprea(&rin->arg3d);
448             droprea(&rin->arg4d);
449             zfree(rin, sizeof(*rin));
450         }
451         RUNE_REMOVE(&p->rblock_list, rblock, node);
452         zfree(rblock, sizeof(*rblock));
453     }
454 }
455
456 void
457 CreateGlobalImmediate(rea_t *sea, rea_t *dea, uint8_t ext)
458 {
459     gimm_t *gimm;
460     rsym_t *sym;
461     char    buf[64];
462     int     bytes;
463
464     switch (ext) {
465     case REXT_I8:
466         snprintf(buf, sizeof(buf), "@rune_imm_%02x",
467                  (uint8_t) sea->immlo);
468         bytes = 1;
469         break;
470     case REXT_I16:
471         snprintf(buf, sizeof(buf), "@rune_imm_%04x",
472                  (uint16_t) sea->immlo);
473         bytes = 2;
474         break;
475     case REXT_I32:
476         snprintf(buf, sizeof(buf), "@rune_imm_%08x",
477                  (uint32_t) sea->immlo);
478         bytes = 4;
479         break;
480     case REXT_I64:
481         snprintf(buf, sizeof(buf), "@rune_imm_%016jx",
482                  (intmax_t) (uint64_t) sea->immlo);
483         bytes = 8;
484         break;
485     case REXT_I128:
486         snprintf(buf, sizeof(buf), "@rune_imm_%016jx%016jx",
487                  (intmax_t) (uint64_t) sea->immhi,
488                  (intmax_t) (uint64_t) sea->immlo);
489         bytes = 16;
490         break;
491     default:
492         dassert(0);
493         bytes = 0;
494     }
495
496     sym = RasGetSymbol((const uint8_t *)buf, strlen(buf));
497     if (sym->characterize == 0) {
498         sym->characterize = 1;
499         gimm = zalloc(sizeof(*gimm));
500         gimm->next = GIMMBase;
501         gimm->immlo = sea->immlo;
502         gimm->immhi = sea->immhi;
503         gimm->bytes = bytes;
504         gimm->ext = ext;
505         gimm->sym = sym;
506         GIMMBase = gimm;
507     }
508     bzero(dea, sizeof(*dea));
509     dea->eamode = EA_MEMORY;
510     dea->sym = sym;
511 }
512
513 void
514 DumpGlobalImmediates(void)
515 {
516     gimm_t *gimm;
517     uint8_t last_bytes = 0;
518
519     printf("\t.section\t.rodata\n");
520     while ((gimm = GIMMBase) != NULL) {
521         GIMMBase = gimm->next;
522
523         if (last_bytes != gimm->bytes) {
524             printf("\t.align\t%d\n", gimm->bytes);
525             last_bytes = gimm->bytes;
526         }
527         printf("%s:\n", gimm->sym->id + 1);
528
529         switch (gimm->bytes) {
530         case 1:
531             printf("\t.byte\t%jd\n", (intmax_t) gimm->immlo);
532             break;
533         case 2:
534             printf("\t.value\t%jd\n", (intmax_t) gimm->immlo);
535             break;
536         case 4:
537             printf("\t.long\t%jd\n", (intmax_t) gimm->immlo);
538             break;
539         case 8:
540             printf("\t.quad\t%jd\n", (intmax_t) gimm->immlo);
541             break;
542         case 16:
543 #if _BYTE_ORDER == _LITTLE_ENDIAN
544             printf("\t.quad\t%jd\n", (intmax_t) gimm->immlo);
545             printf("\t.quad\t%jd\n", (intmax_t) gimm->immhi);
546 #else
547             printf("\t.quad\t%jd\n", (intmax_t) gimm->immhi);
548             printf("\t.quad\t%jd\n", (intmax_t) gimm->immlo);
549 #endif
550             break;
551         default:
552             dassert(0);
553             break;
554         }
555         zfree(gimm, sizeof(*gimm));
556     }
557     printf("\n");
558 }
559
560 static void rasDebugDumpSPAN(rspan_t *skel, int action);
561
562 static
563 void
564 rasDebugSPAN(rspan_t *span, const char *nom)
565 {
566     if (span == NULL)
567         return;
568     printf("%s\n", nom);
569     rasDebugDumpSPAN(span->root, 1);
570     rasDebugDumpSPAN(span->root, -1);
571 }
572
573 static
574 void
575 rasDebugDumpSPAN(rspan_t *skel, int action)
576 {
577     rspan_t *span;
578 #if 0
579     rinsn_t *rin;
580 #endif
581
582     if (skel == NULL)
583         return;
584     if (action < 0) {
585         if (skel->flags & RAF_SPAN) {
586             skel->flags &= ~RAF_SPAN;
587             rasDebugDumpSPAN(skel->strue, action);
588             rasDebugDumpSPAN(skel->sfalse, action);
589         }
590         return;
591     }
592     if (skel->flags & RAF_SPAN) /* already scanned */
593         return;
594     skel->flags |= RAF_SPAN;
595
596     span = skel->link;
597     printf("\t#BLOCK %p RAF_SKELETON %d(%016jx:%d,%016jx:%d)\t",
598            skel->block,
599            ((skel->flags & RAF_SKELETON) != 0),
600            (skel->strue ? (intmax_t) (uintptr_t) skel->strue->block : 0),
601            (skel->strue ? ((skel->strue->flags & RAF_SKELETON) != 0) : 1),
602            (skel->sfalse ? (intmax_t) (uintptr_t) skel->sfalse->block : 0),
603            (skel->sfalse ? ((skel->sfalse->flags & RAF_SKELETON) != 0) : 1));
604     if (skel->flags & RAF_SKELETON) {
605         if (span) {
606             printf("ATIN");
607         } else {
608             printf("SKIP");
609 #if 0
610             rin = NULL;
611 #endif
612         }
613     } else {
614 #if 0
615         rin = RUNE_FIRST(&skel->block->rinsn_list);
616 #endif
617         printf("ABEG");
618     }
619     if ((skel->strue == NULL ||
620          (skel->strue->flags & RAF_SKELETON)) &&
621         (skel->sfalse == NULL ||
622          (skel->sfalse->flags & RAF_SKELETON))) {
623         printf(" LIMITED\n");
624     } else {
625         printf(" TOEND\n");
626     }
627 #if 0
628     while (rin) {
629         printf("\t");
630         rasDebugInsn(rin, 0);
631
632         /*
633          * Check span for rin iteration.  Several EAs may be associated with
634          * the same rin.
635          */
636         while (span->rin == rin) {
637             span = span->link;
638             if (span == NULL)
639                 break;
640         }
641
642         /*
643          * If that was the last variable use-case and all branches are to
644          * skeleton elements, we can stop.
645          */
646         if (span == NULL) {
647             if ((skel->strue == NULL ||
648                  (skel->strue->flags & RAF_SKELETON)) &&
649                 (skel->sfalse == NULL ||
650                  (skel->sfalse->flags & RAF_SKELETON))) {
651                 break;
652             }
653         }
654         rin = RUNE_NEXT(rin, node);
655     }
656 #endif
657
658     /*
659      * Recurse skeleton
660      */
661     rasDebugDumpSPAN(skel->strue, 0);
662     rasDebugDumpSPAN(skel->sfalse, 0);
663 }
664
665 static
666 int
667 checkDiscard(rspan_t *span)
668 {
669     rea_t  *rea = span->rea;
670
671     if (rea == NULL)
672         return 1;
673     if ((rea->flags & (REAF_CACHEABLE | REAF_DROPOK)) == 0)
674         return 0;
675     if ((span->flags & RAF_WRITE) == 0)
676         return 1;
677     if (span->flags & RAF_LIFE_END)
678         return 1;
679     return 0;
680 }
681
682 static
683 void
684 rasDebugInsn(rinsn_t *rin, int dotrace)
685 {
686     size_t  oplen;
687     uint32_t raf;
688
689     /*
690      * Label instructions are trivially output, generating a comment only
691      * causes confusion.
692      */
693     if (rin->op == INSN_LABEL) {
694         return;
695     }
696
697     oplen = strlen(rin->opname) + 2;    /* semicolon + space */
698     if (rin->ext1)
699         oplen += 2;             /* .EXT */
700     if (rin->ext2)
701         oplen += 2;             /* .EXT */
702
703     printf("\t# %s", rin->opname);
704     if (rin->ext1)
705         rasDebugREXT(rin->ext1);
706     if (rin->ext2)
707         rasDebugREXT(rin->ext2);
708     if (rin->flags & RINSF_BRANCH)
709         printf(".BR");
710     if (rin->special_save)
711         printf("[special-%04jx]", (intmax_t) rin->special_save);
712
713     raf = rin->arg1.flags | rin->arg2.flags |
714         rin->arg3.flags | rin->arg3.flags;
715     if ((raf & (RAF_WRITE | RAF_NODROP | RAF_LIFE_END)) ==
716         (RAF_WRITE | RAF_LIFE_END)) {
717         if (checkDiscard(&rin->arg1) &&
718             checkDiscard(&rin->arg2) &&
719             checkDiscard(&rin->arg3) &&
720             checkDiscard(&rin->arg4)) {
721             printf("[drop]");
722         } else {
723             printf("[nodrop %d,%d,%d,%d]",
724                    checkDiscard(&rin->arg1),
725                    checkDiscard(&rin->arg2),
726                    checkDiscard(&rin->arg3),
727                    checkDiscard(&rin->arg4));
728         }
729     }
730
731     if (rin->arg1.rea) {
732         dassert(rin->arg1.rea->orig_eamode);
733         if (oplen < 8)
734             printf("\t");
735         printf("\t[%04jx] ", (intmax_t) rin->regused_agg);
736         rasDebugEA(rin, &rin->arg1, &rin->arg1d);
737     } else {
738         printf("\t[%04jx]", (intmax_t) rin->regused_agg);
739     }
740     if (rin->arg2.rea) {
741         dassert(rin->arg2.rea->orig_eamode);
742         printf(", ");
743         rasDebugEA(rin, &rin->arg2, &rin->arg2d);
744     }
745     if (rin->arg3.rea) {
746         dassert(rin->arg3.rea->orig_eamode);
747         printf(", ");
748         rasDebugEA(rin, &rin->arg3, &rin->arg3d);
749     }
750     if (rin->arg4.rea) {
751         dassert(rin->arg4.rea->orig_eamode);
752         printf(", ");
753         rasDebugEA(rin, &rin->arg4, &rin->arg4d);
754     }
755     if (rin->brtrue) {
756         if (rin->arg1.rea)
757             printf(", ");
758         else
759             printf("\t");
760         printf("%s[%p]", rin->brtrue->id, rin->brtrue->label_block);
761     }
762     if (rin->brfalse) {
763         printf(", %s[%p]", rin->brfalse->id, rin->brfalse->label_block);
764     }
765     printf("\n");
766
767     if (dotrace) {
768         rasDebugSPAN(&rin->arg1, "#ARG1");
769         rasDebugSPAN(&rin->arg1d, "#ARG1D");
770         rasDebugSPAN(&rin->arg2, "#ARG2");
771         rasDebugSPAN(&rin->arg2d, "#ARG2D");
772         rasDebugSPAN(&rin->arg3, "#ARG3");
773         rasDebugSPAN(&rin->arg3d, "#ARG3D");
774         rasDebugSPAN(&rin->arg4, "#ARG4");
775         rasDebugSPAN(&rin->arg4d, "#ARG4D");
776     }
777 }
778
779 static
780 void
781 rasDebugEA(rinsn_t *rin, rspan_t *span, rspan_t *spand)
782 {
783     rea_t  *rea = span->rea;
784     rea_t  *regea;
785
786     switch (rea->orig_eamode) {
787     case EA_DIRECT:
788         rasDebugREG(rin->ext1, rea);
789         break;
790     case EA_MEMORY:
791         regea = rea;
792         if (rea->direct)
793             regea = rea->direct;
794         if (rea->sym) {
795             printf("%s", rea->sym->id);
796             if (rea->orig_offset > 0)
797                 printf("+");
798         }
799         if (rea->orig_offset ||
800             (rea->sym == NULL && (regea->regno & ~REGF_PTR) == 0)) {
801             printf("%jd", (intmax_t) rea->orig_offset);
802         }
803         if (regea->target_reg || (regea->regno & ~REGF_PTR)) {
804             printf("(");
805             if (rea == regea)
806                 rasDebugREG(rin->ext1, regea);
807             else
808                 rasDebugEA(rin, spand, NULL);
809             printf(")");
810         }
811         break;
812     case EA_IMMEDIATE:
813         if (rea->sym) {
814             printf("%s", rea->sym->id);
815             if (rea->immlo > 0)
816                 printf("+");
817         }
818         if (rea->immlo || rea->sym == NULL)
819             printf("$%jd", (intmax_t) rea->immlo);
820         break;
821     case EA_IMMEDIATE16:
822         printf("$0x%016jx%016jx",
823                (intmax_t) rea->immhi, (intmax_t) rea->immlo);
824         break;
825     default:
826         printf("?ea=%d", rea->orig_eamode);
827         break;
828     }
829     if (rea->flags & REAF_BOOLD)
830         printf(".B");
831     if ((rea->flags & REAF_CACHEABLE)) {
832         printf(".CACHE[%p:%d:", rea, rea->regweight);
833         if (rea->flags & REAF_ADDRUSED)
834             printf("A");
835         if (span->flags & RAF_READ)
836             printf("R");
837         if (span->flags & RAF_WRITE)
838             printf("W");
839         if (span->flags & RAF_LEA)
840             printf("L");
841         if (span->flags & RAF_LIFE_BEG)
842             printf("B");
843         if (span->flags & RAF_LIFE_END)
844             printf("X");
845         if (rea->flags & REAF_DROPOK)
846             printf("K");
847         printf("%d", rea->refs);
848         printf("]");
849     } else if (rea->flags & REAF_DROPOK) {
850         printf(".DROPOK");
851     }
852 }
853
854 static
855 void
856 rasDebugREXT(uint8_t ext)
857 {
858     switch (ext) {
859     case REXT_I8:
860         printf(".B");
861         break;
862     case REXT_I16:
863         printf(".W");
864         break;
865     case REXT_I32:
866         printf(".L");
867         break;
868     case REXT_I64:
869         printf(".Q");
870         break;
871     case REXT_I128:
872         printf(".X");
873         break;
874     case REXT_F32:
875         printf(".L");
876         break;
877     case REXT_F64:
878         printf(".Q");
879         break;
880     case REXT_F128:
881         printf(".X");
882         break;
883     default:
884         printf(".?");
885         break;
886     }
887 }
888
889 static
890 void
891 rasDebugREG(uint8_t ext, rea_t *rea)
892 {
893     uint32_t regno = rea->orig_regno;
894     uint16_t target_reg = rea->target_reg;
895
896     /*
897      * Instruction might have a machine register instead of a pseudo-reg.
898      */
899     if (target_reg && (regno == 0 || (rea->flags & REAF_REGALLOCD) == 0)) {
900         InsnDebugREG(target_reg, ext);
901         return;
902     }
903
904     if (regno & REGF_ADHOC) {
905         if (regno & REGF_PTR)
906             printf("%%q%d", regno & REGF_MASK);
907         else
908             printf("%%v%d", regno & REGF_MASK);
909     } else if (regno & REGF_PTR) {
910         switch (regno) {
911         case REG_SG:
912             printf("%%sg");
913             break;
914         case REG_RP:
915             printf("%%rp");
916             break;
917         case REG_DB:
918             printf("%%db");
919             break;
920         case REG_TP:
921             printf("%%tp");
922             break;
923         case REG_AP:
924             printf("%%ap");
925             break;
926         case REG_FP:
927             printf("%%fp");
928             break;
929         case REG_PC:
930             printf("%%pc");
931             break;
932         default:
933             printf("%%p%d", regno & REGF_MASK);
934             break;
935         }
936     } else {
937         printf("%%r%d", regno & REGF_MASK);
938     }
939 }