📄 ia64-gen.c
字号:
totbits += 16; } /* Now allocate the space. */ needed_bytes = (totbits + 7) / 8; if ((needed_bytes + insn_list_len) > tot_insn_list_len) { tot_insn_list_len += 256; insn_list = (unsigned char *) xrealloc (insn_list, tot_insn_list_len); } our_offset = insn_list_len; insn_list_len += needed_bytes; memset (insn_list + our_offset, 0, needed_bytes); /* Encode the skip entry by setting bit 6 set in the state op field, and store the # of bits to skip immediately after. */ if (ent->skip_flag) { bitsused += 5; insn_list[our_offset + 0] |= 0x40 | ((ent->bits_to_skip >> 2) & 0xf); insn_list[our_offset + 1] |= ((ent->bits_to_skip & 3) << 6); }#define IS_ONLY_IFZERO(ENT) \ ((ENT)->bits[0] != NULL && (ENT)->bits[1] == NULL && (ENT)->bits[2] == NULL \ && (ENT)->disent == NULL && (ENT)->skip_flag == 0) /* Store an "if (bit is zero)" instruction by setting bit 7 in the state op field. */ if (ent->bits[0] != NULL) { struct bittree *nent = ent->bits[0]; zero_count = 0; insn_list[our_offset] |= 0x80; /* We can encode sequences of multiple "if (bit is zero)" tests by storing the # of zero bits to check in the lower 3 bits of the instruction. However, this only applies if the state solely tests for a zero bit. */ if (IS_ONLY_IFZERO (ent)) { while (IS_ONLY_IFZERO (nent) && zero_count < 7) { nent = nent->bits[0]; zero_count++; } insn_list[our_offset + 0] |= zero_count; } zero_dest = insn_list_len; gen_dis_table (nent); } /* Now store the remaining tests. We also handle a sole "termination entry" by storing it as an "any bit" test. */ for (x = 1; x < 3; x++) { if (ent->bits[x] != NULL || (x == 2 && ent->disent != NULL)) { struct bittree *i = ent->bits[x]; int idest; int currbits = 15; if (i != NULL) { /* If the instruction being branched to only consists of a termination entry, use the termination entry as the place to branch to instead. */ if (i->bits[0] == NULL && i->bits[1] == NULL && i->bits[2] == NULL && i->disent != NULL) { idest = i->disent->ournum; i = NULL; } else idest = insn_list_len - our_offset; } else idest = ent->disent->ournum; /* If the destination offset for the if (bit is 1) test is less than 256 bytes away, we can store it as 8-bits instead of 16; the instruction has bit 5 set for the 16-bit address, and bit 4 for the 8-bit address. Since we've already allocated 16 bits for the address we need to deallocate the space. Note that branchings within the table are relative, and there are no branches that branch past our instruction yet so we do not need to adjust any other offsets. */ if (x == 1) { if (idest <= 256) { int start = our_offset + bitsused / 8 + 1; memmove (insn_list + start, insn_list + start + 1, insn_list_len - (start + 1)); currbits = 7; totbits -= 8; needed_bytes--; insn_list_len--; insn_list[our_offset] |= 0x10; idest--; } else insn_list[our_offset] |= 0x20; } else { /* An instruction which solely consists of a termination marker and whose disassembly name index is < 4096 can be stored in 16 bits. The encoding is slightly odd; the upper 4 bits of the instruction are 0x3, and bit 3 loses its normal meaning. */ if (ent->bits[0] == NULL && ent->bits[1] == NULL && ent->bits[2] == NULL && ent->skip_flag == 0 && ent->disent != NULL && ent->disent->ournum < (32768 + 4096)) { int start = our_offset + bitsused / 8 + 1; memmove (insn_list + start, insn_list + start + 1, insn_list_len - (start + 1)); currbits = 11; totbits -= 5; bitsused--; needed_bytes--; insn_list_len--; insn_list[our_offset] |= 0x30; idest &= ~32768; } else insn_list[our_offset] |= 0x08; } if (debug) { int id = idest; if (i == NULL) id |= 32768; else if (! (id & 32768)) id += our_offset; if (x == 1) printf ("%d: if (1) goto %d\n", our_offset, id); else printf ("%d: try %d\n", our_offset, id); } /* Store the address of the entry being branched to. */ while (currbits >= 0) { unsigned char *byte = insn_list + our_offset + bitsused / 8; if (idest & (1 << currbits)) *byte |= (1 << (7 - (bitsused % 8))); bitsused++; currbits--; } /* Now generate the states for the entry being branched to. */ if (i != NULL) gen_dis_table (i); } } if (debug) { if (ent->skip_flag) printf ("%d: skipping %d\n", our_offset, ent->bits_to_skip); if (ent->bits[0] != NULL) printf ("%d: if (0:%d) goto %d\n", our_offset, zero_count + 1, zero_dest); } if (bitsused != totbits) abort ();}static voidprint_dis_table (void){ int x; struct disent *cent = disinsntable; printf ("static const char dis_table[] = {\n"); for (x = 0; x < insn_list_len; x++) { if ((x > 0) && ((x % 12) == 0)) printf ("\n"); printf ("0x%02x, ", insn_list[x]); } printf ("\n};\n\n"); printf ("static const struct ia64_dis_names ia64_dis_names[] = {\n"); while (cent != NULL) { struct disent *ent = cent; while (ent != NULL) { printf ("{ 0x%x, %d, %d, %d },\n", ent->completer_index, ent->insn, (ent->nexte != NULL ? 1 : 0), ent->priority); ent = ent->nexte; } cent = cent->next_ent; } printf ("};\n\n");}static voidgenerate_disassembler (void){ int i; bittree = make_bittree_entry (); for (i = 0; i < otlen; i++) { struct main_entry *ptr = ordered_table[i]; if (ptr->opcode->type != IA64_TYPE_DYN) add_dis_entry (bittree, ptr->opcode->opcode, ptr->opcode->mask, ptr->main_index, ptr->completers, 1); } compact_distree (bittree); finish_distable (); gen_dis_table (bittree); print_dis_table ();}static voidprint_string_table (void){ int x; char lbuf[80], buf[80]; int blen = 0; printf ("static const char * const ia64_strings[] = {\n"); lbuf[0] = '\0'; for (x = 0; x < strtablen; x++) { int len; if (strlen (string_table[x]->s) > 75) abort (); sprintf (buf, " \"%s\",", string_table[x]->s); len = strlen (buf); if ((blen + len) > 75) { printf (" %s\n", lbuf); lbuf[0] = '\0'; blen = 0; } strcat (lbuf, buf); blen += len; } if (blen > 0) printf (" %s\n", lbuf); printf ("};\n\n");}static struct completer_entry **glist;static int glistlen = 0;static int glisttotlen = 0;/* If the completer trees ENT1 and ENT2 are equal, return 1. */static intcompleter_entries_eq (ent1, ent2) struct completer_entry *ent1, *ent2;{ while (ent1 != NULL && ent2 != NULL) { if (ent1->name->num != ent2->name->num || ent1->bits != ent2->bits || ent1->mask != ent2->mask || ent1->is_terminal != ent2->is_terminal || ent1->dependencies != ent2->dependencies || ent1->order != ent2->order) return 0; if (! completer_entries_eq (ent1->addl_entries, ent2->addl_entries)) return 0; ent1 = ent1->alternative; ent2 = ent2->alternative; } return ent1 == ent2;}/* Insert ENT into the global list of completers and return it. If an equivalent entry (according to completer_entries_eq) already exists, it is returned instead. */static struct completer_entry *insert_gclist (struct completer_entry *ent){ if (ent != NULL) { int i; int x; int start = 0, end; ent->addl_entries = insert_gclist (ent->addl_entries); ent->alternative = insert_gclist (ent->alternative); i = glistlen / 2; end = glistlen; if (glisttotlen == glistlen) { glisttotlen += 20; glist = (struct completer_entry **) xrealloc (glist, sizeof (struct completer_entry *) * glisttotlen); } if (glistlen == 0) { glist[0] = ent; glistlen = 1; return ent; } if (ent->name->num < glist[0]->name->num) i = 0; else if (ent->name->num > glist[end - 1]->name->num) i = end; else { int c; while (1) { i = (start + end) / 2; c = ent->name->num - glist[i]->name->num; if (c < 0) end = i - 1; else if (c == 0) { while (i > 0 && ent->name->num == glist[i - 1]->name->num) i--; break; } else start = i + 1; if (start > end) break; } if (c == 0) { while (i < glistlen) { if (ent->name->num != glist[i]->name->num) break; if (completer_entries_eq (ent, glist[i])) return glist[i]; i++; } } } for (; i > 0 && i < glistlen; i--) if (ent->name->num >= glist[i - 1]->name->num) break; for (; i < glistlen; i++) if (ent->name->num < glist[i]->name->num) break; for (x = glistlen - 1; x >= i; x--) glist[x + 1] = glist[x]; glist[i] = ent; glistlen++; } return ent;}static intget_prefix_len (name) const char *name;{ char *c; if (name[0] == '\0') return 0; c = strchr (name, '.'); if (c != NULL) return c - name; else return strlen (name);}static voidcompute_completer_bits (ment, ent) struct main_entry *ment; struct completer_entry *ent;{ while (ent != NULL) { compute_completer_bits (ment, ent->addl_entries); if (ent->is_terminal) { ia64_insn mask = 0; ia64_insn our_bits = ent->bits; struct completer_entry *p = ent->parent; ia64_insn p_bits; int x; while (p != NULL && ! p->is_terminal) p = p->parent; if (p != NULL) p_bits = p->bits; else p_bits = ment->opcode->opcode; for (x = 0; x < 64; x++) { ia64_insn m = ((ia64_insn) 1) << x; if ((p_bits & m) != (our_bits & m)) mask |= m; else our_bits &= ~m; } ent->bits = our_bits; ent->mask = mask; } else { ent->bits = 0; ent->mask = 0; } ent = ent->alternative; }}/* Find identical completer trees that are used in different instructions and collapse their entries. */static voidcollapse_redundant_completers (void){ struct main_entry *ptr; int x; for (ptr = maintable; ptr != NULL; ptr = ptr->next) { if (ptr->completers == NULL) abort ()
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -