4 * (c)Copyright 2016, Matthew Dillon, All Rights Reserved. See the COPYRIGHT
5 * file at the base of the distribution.
10 typedef struct GlobalImmediate {
11 struct GlobalImmediate *next;
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);
29 srunesize_t ProcStackSize;
30 srunesize_t ProcStackPad;
31 void (*RegAllocator) (RASParser *p, rblock_t *rblock, urunesize_t bytes);
33 void (*ProbeFunc) (RASParser *p, rinsn_t *rin);
36 * .proc symbol, stacksz, stackalgn
39 PsopPROC(RASParser *p, rinsn_t *dummy __unused)
45 rastoken_t t = p->tok;
50 RasResetRegNumbering();
52 t = RasToken(p); /* skip .proc */
53 dummy_rin.loc_file = 0;
54 dummy_rin.loc_line = 0;
59 RUNE_INIT(&p->rblock_list);
60 RUNE_INIT(&p->blockdef_list);
61 rblock = RasBlockAlloc(&p->rblock_list);
63 t = RasParseSymbol(p, t, &psym);
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);
73 RasError(p, "Extranious junk on line");
82 InsnProcedureBasicBlock(p, rblock, bytes, align);
85 * Collect the instructions for the procedure into basic blocks. Add any
86 * missing fall-through linkages (allows us to rearrange any block except
89 while (RasLine(p, &lab)) {
91 * Check for symbol, allow processing
99 if (t == RAS_TOK_COLON) {
102 rin = zalloc(sizeof(*rin));
103 rin->op = INSN_LABEL;
104 rin->func = InsnLABEL;
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);
111 RasError(p, "label: must be on a line "
116 rin = zalloc(sizeof(*rin));
117 rin->op = INSN_LABEL;
118 rin->func = InsnLABEL;
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);
135 if (t == RAS_TOK_DOT) {
137 RasError(p, "labeled pseudoop is not legal");
139 if (t != RAS_TOK_ID && t != RAS_TOK_SYMBOL) {
140 RasError(p, "Unknown pseudoop");
144 if (isym->tok == RAS_TOK_ENDPROC)
146 if (isym->tok == RAS_TOK_FILE) {
148 } else if (isym->tok == RAS_TOK_LOC) {
149 isym->func(p, &dummy_rin);
151 RasError(p, "this pseudoop is illegal "
156 if (t != RAS_TOK_ID && t != RAS_TOK_SYMBOL) {
157 RasError(p, "Expected instruction");
161 if ((isym->tok & INSNF_INSN) == 0) {
162 RasError(p, "Expected instruction");
167 * Ok, parse-out the instruction
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;
177 t = RasParseInsnEXT(p, RasToken(p), rin);
179 if (rin->flags & RINSF_BRANCH) {
180 dassert(rin->op & INSNF_COND);
200 if (t && maxea > 0) {
201 t = RasParseEA(p, t, rin, &rin->arg1, &rin->arg1d);
204 if (t == RAS_TOK_COMMA && maxea > 1) {
206 t = RasParseEA(p, t, rin, &rin->arg2, &rin->arg2d);
209 if (t == RAS_TOK_COMMA && maxea > 2) {
211 t = RasParseEA(p, t, rin, &rin->arg3, &rin->arg3d);
214 if (t == RAS_TOK_COMMA && maxea > 3) {
216 t = RasParseEA(p, t, rin, &rin->arg4, &rin->arg4d);
221 * Handle characterization of the EAs to the instruction.
223 chize = isym->characterize;
224 if (chize & CHF_READLST) {
225 switch (rin->operands) {
242 if (chize & CHF_WRITELST) {
243 switch (rin->operands) {
260 if (chize & CHF_FLOATLST) {
261 switch (rin->operands) {
279 if (rin->operands >= 1) {
280 rin->arg1.flags |= (chize >> CHF_ARG1SHIFT) &
282 if (rin->arg1.flags & RAF_LEA) {
283 rin->arg1.rea->flags |= REAF_ADDRUSED;
284 rin->arg1.rea->flags &= ~REAF_CACHEABLE;
287 if (rin->operands >= 2) {
288 rin->arg2.flags |= (chize >> CHF_ARG2SHIFT) &
290 if (rin->arg2.flags & RAF_LEA) {
291 rin->arg2.rea->flags |= REAF_ADDRUSED;
292 rin->arg2.rea->flags &= ~REAF_CACHEABLE;
295 if (rin->operands >= 3) {
296 rin->arg3.flags |= (chize >> CHF_ARG3SHIFT) &
298 if (rin->arg3.flags & RAF_LEA) {
299 rin->arg3.rea->flags |= REAF_ADDRUSED;
300 rin->arg3.rea->flags &= ~REAF_CACHEABLE;
303 if (rin->operands >= 4) {
304 rin->arg4.flags |= (chize >> CHF_ARG4SHIFT) &
306 if (rin->arg4.flags & RAF_LEA) {
307 rin->arg4.rea->flags |= REAF_ADDRUSED;
308 rin->arg4.rea->flags &= ~REAF_CACHEABLE;
313 * Branches always have two branch targets, one for true and one for
314 * false, except for JMP which only has one.
316 if (rin->flags & RINSF_BRANCH) {
318 if (t == RAS_TOK_COMMA)
321 RasError(p, "Condition branch missing");
323 t = RasParseLabel(p, t, &rin->brtrue);
324 if (t == RAS_TOK_COMMA) {
326 t = RasParseLabel(p, t, &rin->brfalse);
327 } else if (rin->op != INSN_JMP) {
328 RasError(p, "Conditional needs "
329 "two branch labels");
333 RasError(p, "Extranious junk after instruction");
337 * The RET instruction is effectively a branch for the purposes of
338 * block characterization.
340 if (rin->op == INSN_RET)
341 rin->flags |= RINSF_BRANCH;
344 * Add the instruction to the current basic block, possibly creating
347 InsnTargetAdjust(p, rin);
348 RasBlockAdd(rblock, rin);
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
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
363 BlockCharacterize(p, rblock);
364 BlockCollapse(p, rblock);
367 * Optimize, potentially reordering basic blocks. Note that conditionals
368 * always automatically self-optimize through reversal or inversion.
370 RegAllocator(p, RUNE_FIRST(&p->rblock_list), bytes);
375 dummy_rin.loc_file = 0;
376 dummy_rin.loc_line = 0;
379 * Spit-out the results
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);
387 printf("# RBlock %p START count=%d\n",
388 rblock, rblock->count);
390 if (rblock->reachcount) {
393 RUNE_FOREACH(rin, &rblock->rinsn_list, node) {
394 rasDebugInsn(rin, DOTRACE);
395 if (rin->flags & RINSF_DROPME) {
396 printf("\t# (dropped)\n");
398 if (dummy_rin.loc_file !=
400 dummy_rin.loc_line !=
407 printf("\t.loc\t%ju %jd 0\n",
408 (intmax_t)rin->loc_file,
409 (intmax_t)rin->loc_line);
411 dassert(rin->func != NULL);
412 p->opt_last = p->opt_flags;
422 printf("# RBlock %p END\n", rblock);
424 printf(".LRET%d:\n", ProcNo);
425 InsnProcedureEnd(p, bytes, align);
430 printf("\t.size\t%s, . - %s\n", psym->id + 1, psym->id + 1);
432 DumpGlobalImmediates();
433 RasInvalidateRegNumbering();
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);
445 droprea(&rin->arg1d);
446 droprea(&rin->arg2d);
447 droprea(&rin->arg3d);
448 droprea(&rin->arg4d);
449 zfree(rin, sizeof(*rin));
451 RUNE_REMOVE(&p->rblock_list, rblock, node);
452 zfree(rblock, sizeof(*rblock));
457 CreateGlobalImmediate(rea_t *sea, rea_t *dea, uint8_t ext)
466 snprintf(buf, sizeof(buf), "@rune_imm_%02x",
467 (uint8_t) sea->immlo);
471 snprintf(buf, sizeof(buf), "@rune_imm_%04x",
472 (uint16_t) sea->immlo);
476 snprintf(buf, sizeof(buf), "@rune_imm_%08x",
477 (uint32_t) sea->immlo);
481 snprintf(buf, sizeof(buf), "@rune_imm_%016jx",
482 (intmax_t) (uint64_t) sea->immlo);
486 snprintf(buf, sizeof(buf), "@rune_imm_%016jx%016jx",
487 (intmax_t) (uint64_t) sea->immhi,
488 (intmax_t) (uint64_t) sea->immlo);
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;
508 bzero(dea, sizeof(*dea));
509 dea->eamode = EA_MEMORY;
514 DumpGlobalImmediates(void)
517 uint8_t last_bytes = 0;
519 printf("\t.section\t.rodata\n");
520 while ((gimm = GIMMBase) != NULL) {
521 GIMMBase = gimm->next;
523 if (last_bytes != gimm->bytes) {
524 printf("\t.align\t%d\n", gimm->bytes);
525 last_bytes = gimm->bytes;
527 printf("%s:\n", gimm->sym->id + 1);
529 switch (gimm->bytes) {
531 printf("\t.byte\t%jd\n", (intmax_t) gimm->immlo);
534 printf("\t.value\t%jd\n", (intmax_t) gimm->immlo);
537 printf("\t.long\t%jd\n", (intmax_t) gimm->immlo);
540 printf("\t.quad\t%jd\n", (intmax_t) gimm->immlo);
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);
547 printf("\t.quad\t%jd\n", (intmax_t) gimm->immhi);
548 printf("\t.quad\t%jd\n", (intmax_t) gimm->immlo);
555 zfree(gimm, sizeof(*gimm));
560 static void rasDebugDumpSPAN(rspan_t *skel, int action);
564 rasDebugSPAN(rspan_t *span, const char *nom)
569 rasDebugDumpSPAN(span->root, 1);
570 rasDebugDumpSPAN(span->root, -1);
575 rasDebugDumpSPAN(rspan_t *skel, int action)
585 if (skel->flags & RAF_SPAN) {
586 skel->flags &= ~RAF_SPAN;
587 rasDebugDumpSPAN(skel->strue, action);
588 rasDebugDumpSPAN(skel->sfalse, action);
592 if (skel->flags & RAF_SPAN) /* already scanned */
594 skel->flags |= RAF_SPAN;
597 printf("\t#BLOCK %p RAF_SKELETON %d(%016jx:%d,%016jx:%d)\t",
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) {
615 rin = RUNE_FIRST(&skel->block->rinsn_list);
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");
630 rasDebugInsn(rin, 0);
633 * Check span for rin iteration. Several EAs may be associated with
636 while (span->rin == rin) {
643 * If that was the last variable use-case and all branches are to
644 * skeleton elements, we can stop.
647 if ((skel->strue == NULL ||
648 (skel->strue->flags & RAF_SKELETON)) &&
649 (skel->sfalse == NULL ||
650 (skel->sfalse->flags & RAF_SKELETON))) {
654 rin = RUNE_NEXT(rin, node);
661 rasDebugDumpSPAN(skel->strue, 0);
662 rasDebugDumpSPAN(skel->sfalse, 0);
667 checkDiscard(rspan_t *span)
669 rea_t *rea = span->rea;
673 if ((rea->flags & (REAF_CACHEABLE | REAF_DROPOK)) == 0)
675 if ((span->flags & RAF_WRITE) == 0)
677 if (span->flags & RAF_LIFE_END)
684 rasDebugInsn(rinsn_t *rin, int dotrace)
690 * Label instructions are trivially output, generating a comment only
693 if (rin->op == INSN_LABEL) {
697 oplen = strlen(rin->opname) + 2; /* semicolon + space */
699 oplen += 2; /* .EXT */
701 oplen += 2; /* .EXT */
703 printf("\t# %s", rin->opname);
705 rasDebugREXT(rin->ext1);
707 rasDebugREXT(rin->ext2);
708 if (rin->flags & RINSF_BRANCH)
710 if (rin->special_save)
711 printf("[special-%04jx]", (intmax_t) rin->special_save);
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)) {
723 printf("[nodrop %d,%d,%d,%d]",
724 checkDiscard(&rin->arg1),
725 checkDiscard(&rin->arg2),
726 checkDiscard(&rin->arg3),
727 checkDiscard(&rin->arg4));
732 dassert(rin->arg1.rea->orig_eamode);
735 printf("\t[%04jx] ", (intmax_t) rin->regused_agg);
736 rasDebugEA(rin, &rin->arg1, &rin->arg1d);
738 printf("\t[%04jx]", (intmax_t) rin->regused_agg);
741 dassert(rin->arg2.rea->orig_eamode);
743 rasDebugEA(rin, &rin->arg2, &rin->arg2d);
746 dassert(rin->arg3.rea->orig_eamode);
748 rasDebugEA(rin, &rin->arg3, &rin->arg3d);
751 dassert(rin->arg4.rea->orig_eamode);
753 rasDebugEA(rin, &rin->arg4, &rin->arg4d);
760 printf("%s[%p]", rin->brtrue->id, rin->brtrue->label_block);
763 printf(", %s[%p]", rin->brfalse->id, rin->brfalse->label_block);
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");
781 rasDebugEA(rinsn_t *rin, rspan_t *span, rspan_t *spand)
783 rea_t *rea = span->rea;
786 switch (rea->orig_eamode) {
788 rasDebugREG(rin->ext1, rea);
795 printf("%s", rea->sym->id);
796 if (rea->orig_offset > 0)
799 if (rea->orig_offset ||
800 (rea->sym == NULL && (regea->regno & ~REGF_PTR) == 0)) {
801 printf("%jd", (intmax_t) rea->orig_offset);
803 if (regea->target_reg || (regea->regno & ~REGF_PTR)) {
806 rasDebugREG(rin->ext1, regea);
808 rasDebugEA(rin, spand, NULL);
814 printf("%s", rea->sym->id);
818 if (rea->immlo || rea->sym == NULL)
819 printf("$%jd", (intmax_t) rea->immlo);
822 printf("$0x%016jx%016jx",
823 (intmax_t) rea->immhi, (intmax_t) rea->immlo);
826 printf("?ea=%d", rea->orig_eamode);
829 if (rea->flags & REAF_BOOLD)
831 if ((rea->flags & REAF_CACHEABLE)) {
832 printf(".CACHE[%p:%d:", rea, rea->regweight);
833 if (rea->flags & REAF_ADDRUSED)
835 if (span->flags & RAF_READ)
837 if (span->flags & RAF_WRITE)
839 if (span->flags & RAF_LEA)
841 if (span->flags & RAF_LIFE_BEG)
843 if (span->flags & RAF_LIFE_END)
845 if (rea->flags & REAF_DROPOK)
847 printf("%d", rea->refs);
849 } else if (rea->flags & REAF_DROPOK) {
856 rasDebugREXT(uint8_t ext)
891 rasDebugREG(uint8_t ext, rea_t *rea)
893 uint32_t regno = rea->orig_regno;
894 uint16_t target_reg = rea->target_reg;
897 * Instruction might have a machine register instead of a pseudo-reg.
899 if (target_reg && (regno == 0 || (rea->flags & REAF_REGALLOCD) == 0)) {
900 InsnDebugREG(target_reg, ext);
904 if (regno & REGF_ADHOC) {
905 if (regno & REGF_PTR)
906 printf("%%q%d", regno & REGF_MASK);
908 printf("%%v%d", regno & REGF_MASK);
909 } else if (regno & REGF_PTR) {
933 printf("%%p%d", regno & REGF_MASK);
937 printf("%%r%d", regno & REGF_MASK);