Merge empty reservations from TIMES; add counts in listings

For constructs like TIMES xx RESB yy merge the TIMES and RESB and feed
a single reservation to the backend; this can (obviously) be
dramatically faster.

Add byte count in listings for <incbin> and repeat count to <rept>; to
make them more reasonable in length shorten to <bin ...> and <rep ...>
respectively, and don't require leading zeroes in bin/rep/res count.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2019-08-07 00:46:27 -07:00
parent 77a9b7d689
commit 0d4d431a01
5 changed files with 92 additions and 48 deletions

View file

@ -583,6 +583,22 @@ static bool jmp_match(int32_t segment, int64_t offset, int bits,
return is_byte;
}
static inline int64_t merge_resb(insn *ins, int64_t isize)
{
int nbytes = resb_bytes(ins->opcode);
if (likely(!nbytes))
return isize;
if (isize != nbytes * ins->oprs[0].offset)
return isize; /* Has prefixes of some sort */
ins->oprs[0].offset *= ins->times;
isize *= ins->times;
ins->times = 1;
return isize;
}
/* This is totally just a wild guess what is reasonable... */
#define INCBIN_MAX_BUF (ZERO_BUF_SIZE * 16)
@ -682,7 +698,7 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
}
lfmt->set_offset(data.offset);
lfmt->uplevel(LIST_INCBIN);
lfmt->uplevel(LIST_INCBIN, len);
if (!len)
goto end_incbin;
@ -738,7 +754,7 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
end_incbin:
lfmt->downlevel(LIST_INCBIN);
if (instruction->times > 1) {
lfmt->uplevel(LIST_TIMES);
lfmt->uplevel(LIST_TIMES, instruction->times);
lfmt->downlevel(LIST_TIMES);
}
if (ferror(fp)) {
@ -764,8 +780,6 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
if (m == MOK_GOOD) {
/* Matches! */
int64_t insn_size;
if (unlikely(itemp_has(temp, IF_OBSOLETE))) {
/*
* If IF_OBSOLETE is set, warn unless we have *exactly*
@ -793,6 +807,7 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
data.inslen = calcsize(data.segment, data.offset,
bits, instruction, temp);
nasm_assert(data.inslen >= 0);
data.inslen = merge_resb(instruction, data.inslen);
gencode(&data, instruction);
nasm_assert(data.insoffs == data.inslen);
@ -963,6 +978,7 @@ static void define_equ(insn * instruction)
}
}
int64_t insn_size(int32_t segment, int64_t offset, int bits, insn *instruction)
{
const struct itemplate *temp;
@ -1039,6 +1055,7 @@ int64_t insn_size(int32_t segment, int64_t offset, int bits, insn *instruction)
isize = calcsize(segment, offset, bits, instruction, temp);
debug_set_type(instruction);
isize = merge_resb(instruction, isize);
return isize;
}

View file

@ -45,7 +45,7 @@
#include "strlist.h"
#include "listing.h"
#define LIST_MAX_LEN 256 /* something sensible */
#define LIST_MAX_LEN 1024 /* something sensible */
#define LIST_INDENT 40
#define LIST_HEXBIT 18
@ -57,7 +57,7 @@ static struct MacroInhibit {
int inhibiting;
} *mistack;
static char xdigit[] = "0123456789ABCDEF";
static const char xdigit[] = "0123456789ABCDEF";
#define HEX(a,b) (*(a)=xdigit[((b)>>4)&15],(a)[1]=xdigit[(b)&15]);
@ -245,7 +245,7 @@ static void list_output(const struct out_data *data)
break;
case OUT_RESERVE:
{
snprintf(q, sizeof(q), "<res %08"PRIX64">", size);
snprintf(q, sizeof(q), "<res %"PRIX64">", size);
list_out(offset, q);
break;
}
@ -274,35 +274,54 @@ static void list_line(int type, char *line)
list_emit();
listlineno = src_get_linnum();
listlinep = true;
strncpy(listline, line, LIST_MAX_LEN - 1);
listline[LIST_MAX_LEN - 1] = '\0';
strlcpy(listline, line, LIST_MAX_LEN-3);
memcpy(listline + LIST_MAX_LEN-4, "...", 4);
listlevel_e = listlevel;
}
static void list_uplevel(int type)
static void mistack_push(bool inhibiting)
{
MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
temp->next = mistack;
temp->level = listlevel;
temp->inhibiting = inhibiting;
mistack = temp;
}
static void list_uplevel(int type, int64_t size)
{
char str[64];
if (!listp)
return;
if (type == LIST_INCBIN || type == LIST_TIMES) {
suppress |= (type == LIST_INCBIN ? 1 : 2);
list_out(listoffset, type == LIST_INCBIN ? "<incbin>" : "<rept>");
return;
}
listlevel++;
switch (type) {
case LIST_INCBIN:
suppress |= 1;
snprintf(str, sizeof str, "<bin %"PRIX64">", size);
list_out(listoffset, str);
break;
if (mistack && mistack->inhibiting && type == LIST_INCLUDE) {
MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
temp->next = mistack;
temp->level = listlevel;
temp->inhibiting = false;
mistack = temp;
} else if (type == LIST_MACRO_NOLIST) {
MacroInhibit *temp = nasm_malloc(sizeof(MacroInhibit));
temp->next = mistack;
temp->level = listlevel;
temp->inhibiting = true;
mistack = temp;
case LIST_TIMES:
suppress |= 2;
snprintf(str, sizeof str, "<rep %"PRIX64">", size);
list_out(listoffset, str);
break;
case LIST_INCLUDE:
listlevel++;
if (mistack && mistack->inhibiting)
mistack_push(false);
break;
case LIST_MACRO_NOLIST:
listlevel++;
mistack_push(true);
break;
default:
listlevel++;
break;
}
}
@ -311,16 +330,23 @@ static void list_downlevel(int type)
if (!listp)
return;
if (type == LIST_INCBIN || type == LIST_TIMES) {
suppress &= ~(type == LIST_INCBIN ? 1 : 2);
return;
}
switch (type) {
case LIST_INCBIN:
suppress &= ~1;
break;
listlevel--;
while (mistack && mistack->level > listlevel) {
MacroInhibit *temp = mistack;
mistack = temp->next;
nasm_free(temp);
case LIST_TIMES:
suppress &= ~2;
break;
default:
listlevel--;
while (mistack && mistack->level > listlevel) {
MacroInhibit *temp = mistack;
mistack = temp->next;
nasm_free(temp);
}
break;
}
}

View file

@ -74,19 +74,20 @@ struct lfmt {
void (*line)(int type, char *line);
/*
* Called to change one of the various levelled mechanisms in
* the listing generator. LIST_INCLUDE and LIST_MACRO can be
* used to increase the nesting level of include files and
* macro expansions; LIST_TIMES and LIST_INCBIN switch on the
* two binary-output-suppression mechanisms for large-scale
* pseudo-instructions.
* Called to change one of the various levelled mechanisms in the
* listing generator. LIST_INCLUDE and LIST_MACRO can be used to
* increase the nesting level of include files and macro
* expansions; LIST_TIMES and LIST_INCBIN switch on the two
* binary-output-suppression mechanisms for large-scale
* pseudo-instructions; the size argument prints the size or
* repetiiton count.
*
* LIST_MACRO_NOLIST is synonymous with LIST_MACRO except that
* it indicates the beginning of the expansion of a `nolist'
* macro, so anything under that level won't be expanded unless
* it includes another file.
*/
void (*uplevel)(int type);
void (*uplevel)(int type, int64_t size);
/*
* Reverse the effects of uplevel.

View file

@ -1465,7 +1465,7 @@ static void process_insn(insn *instruction)
increment_offset(l);
if (instruction->times > 1) {
lfmt->uplevel(LIST_TIMES);
lfmt->uplevel(LIST_TIMES, instruction->times);
for (n = 2; n <= instruction->times; n++) {
l = assemble(location.segment, location.offset,
globalbits, instruction);

View file

@ -2598,7 +2598,7 @@ static int do_directive(Token *tline, Token **output)
inc->expansion = NULL;
inc->mstk = NULL;
istk = inc;
lfmt->uplevel(LIST_INCLUDE);
lfmt->uplevel(LIST_INCLUDE, 0);
}
free_tlist(origline);
return DIRECTIVE_FOUND;
@ -3066,7 +3066,7 @@ issue_error:
istk->mstk = defining;
lfmt->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
lfmt->uplevel(defining->nolist ? LIST_MACRO_NOLIST : LIST_MACRO, 0);
tmp_defining = defining;
defining = defining->rep_nest;
free_tlist(origline);
@ -4921,7 +4921,7 @@ static int expand_mmacro(Token * tline)
}
}
lfmt->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO);
lfmt->uplevel(m->nolist ? LIST_MACRO_NOLIST : LIST_MACRO, 0);
return 1;
}