Don't sort opcodes; move all pseudo-ops to the beginning

We don't need to sort opcodes anymore, since we are using an O(1) hash
and not binary search.  Instead, sort them in the order they first
appear in insns.dat; this lets us move all the pseudo-ops to a
contiguous range at the start of the file, for more efficient
handling.

Change the functions that process pseudo-ops accordingly.

Signed-off-by: H. Peter Anvin <hpa@zytor.com>
This commit is contained in:
H. Peter Anvin 2017-05-01 21:44:24 -07:00
parent d23066906c
commit af9fe8f597
6 changed files with 81 additions and 76 deletions

View file

@ -555,7 +555,7 @@ int64_t assemble(int32_t segment, int64_t start, int bits, insn *instruction)
data.sign = OUT_WRAP;
data.bits = bits;
wsize = idata_bytes(instruction->opcode);
wsize = db_bytes(instruction->opcode);
if (wsize == -1)
return 0;
@ -790,7 +790,7 @@ int64_t insn_size(int32_t segment, int64_t offset, int bits, insn *instruction)
int32_t isize, osize, wsize;
isize = 0;
wsize = idata_bytes(instruction->opcode);
wsize = db_bytes(instruction->opcode);
nasm_assert(wsize > 0);
list_for_each(e, instruction->eops) {

View file

@ -666,7 +666,7 @@ is_float:
eop->type = EOT_DB_STRING;
result->eops_float = true;
eop->stringlen = idata_bytes(result->opcode);
eop->stringlen = db_bytes(result->opcode);
if (eop->stringlen > 16) {
nasm_error(ERR_NONFATAL, "floating-point constant"
" encountered in DY or DZ instruction");
@ -1129,7 +1129,7 @@ is_expression:
* Transform RESW, RESD, RESQ, REST, RESO, RESY, RESZ into RESB.
*/
if (opcode_is_resb(result->opcode)) {
result->oprs[0].offset *= resv_bytes(result->opcode);
result->oprs[0].offset *= resb_bytes(result->opcode);
result->oprs[0].offset *= result->times;
result->times = 1;
result->opcode = I_RESB;

View file

@ -62,61 +62,3 @@ const char *prefix_name(int token)
return prefix_names[prefix];
}
/*
* initialized data bytes length from opcode
*/
int idata_bytes(int opcode)
{
switch (opcode) {
case I_DB:
return 1;
case I_DW:
return 2;
case I_DD:
return 4;
case I_DQ:
return 8;
case I_DT:
return 10;
case I_DO:
return 16;
case I_DY:
return 32;
case I_DZ:
return 64;
case I_none:
return -1;
default:
return 0;
}
}
/*
* Uninitialized data bytes length from opcode
*/
int resv_bytes(int opcode)
{
switch (opcode) {
case I_RESB:
return 1;
case I_RESW:
return 2;
case I_RESD:
return 4;
case I_RESQ:
return 8;
case I_REST:
return 10;
case I_RESO:
return 16;
case I_RESY:
return 32;
case I_RESZ:
return 64;
case I_none:
return -1;
default:
return 0;
}
}

View file

@ -48,23 +48,79 @@ extern const uint8_t nasm_bytecodes[];
*/
#define ITEMPLATE_END {-1,-1,{-1,-1,-1,-1,-1},{-1,-1,-1,-1,-1},NULL,0}
/* Width of Dx and RESx instructions */
int const_func idata_bytes(enum opcode opcode);
int const_func resv_bytes(enum opcode opcode);
/*
* Pseudo-op tests
*/
/* DB-type instruction (DB, DW, ...) */
static inline bool opcode_is_db(enum opcode opcode)
static inline bool const_func opcode_is_db(enum opcode opcode)
{
return idata_bytes(opcode) > 0;
return opcode >= I_DB && opcode < I_RESB;
}
/* RESB-type instruction (RESB, RESW, ...) */
static inline bool opcode_is_resb(enum opcode opcode)
static inline bool const_func opcode_is_resb(enum opcode opcode)
{
return resv_bytes(opcode) > 0;
return opcode >= I_RESB && opcode < I_INCBIN;
}
/* Width of Dx and RESx instructions */
/*
* initialized data bytes length from opcode
*/
static inline int const_func db_bytes(int opcode)
{
switch (opcode) {
case I_DB:
return 1;
case I_DW:
return 2;
case I_DD:
return 4;
case I_DQ:
return 8;
case I_DT:
return 10;
case I_DO:
return 16;
case I_DY:
return 32;
case I_DZ:
return 64;
case I_none:
return -1;
default:
return 0;
}
}
/*
* Uninitialized data bytes length from opcode
*/
static inline int resb_bytes(enum opcode opcode)
{
switch (opcode) {
case I_RESB:
return 1;
case I_RESW:
return 2;
case I_RESD:
return 4;
case I_RESQ:
return 8;
case I_REST:
return 10;
case I_RESO:
return 16;
case I_RESY:
return 32;
case I_RESZ:
return 64;
case I_none:
return -1;
default:
return 0;
}
}
#endif /* NASM_INSNS_H */

View file

@ -48,6 +48,8 @@
;
;# Special instructions...
; These MUST be first in this file and must maintain the pattern of
; Dx by size, RESx by size, and INCBIN in that order.
DB ignore ignore ignore
DW ignore ignore ignore
DD ignore ignore ignore
@ -64,6 +66,7 @@ REST ignore ignore ignore
RESO ignore ignore ignore
RESY ignore ignore ignore
RESZ ignore ignore ignore
INCBIN ignore ignore ignore
;# Conventional instructions
AAA void [ 37] 8086,NOLONG
@ -652,7 +655,6 @@ INC rm8 [m: hle fe /0] 8086,LOCK
INC rm16 [m: hle o16 ff /0] 8086,LOCK
INC rm32 [m: hle o32 ff /0] 386,LOCK
INC rm64 [m: hle o64 ff /0] X64,LOCK
INCBIN ignore ignore ignore
INSB void [ 6c] 186
INSD void [ o32 6d] 386
INSW void [ o16 6d] 186

View file

@ -1,7 +1,7 @@
#!/usr/bin/perl
## --------------------------------------------------------------------------
##
## Copyright 1996-2016 The NASM Authors - All Rights Reserved
## Copyright 1996-2017 The NASM Authors - All Rights Reserved
## See the file AUTHORS included with the NASM distribution for
## the specific copyright holders.
##
@ -89,6 +89,7 @@ open(F, '<', $fname) || die "unable to open $fname";
$line = 0;
$insns = 0;
$n_opcodes = $n_opcodes_cc = 0;
while (<F>) {
$line++;
chomp;
@ -146,10 +147,14 @@ while (<F>) {
}
if ( $fields[0] =~ /cc$/ ) {
# Conditional instruction
$k_opcodes_cc{$fields[0]}++;
if (!defined($k_opcodes_cc{$fields[0]})) {
$k_opcodes_cc{$fields[0]} = $n_opcodes_cc++;
}
} else {
# Unconditional instruction
$k_opcodes{$fields[0]}++;
if (!defined($k_opcodes{$fields[0]})) {
$k_opcodes{$fields[0]} = $n_opcodes++;
}
}
if ($formatted && !$nd) {
push @big, $formatted;
@ -189,8 +194,8 @@ foreach $bl (@bytecode_list) {
}
undef @bytecode_list;
@opcodes = sort keys(%k_opcodes);
@opcodes_cc = sort keys(%k_opcodes_cc);
@opcodes = sort { $k_opcodes{$a} <=> $k_opcodes{$b} } keys(%k_opcodes);
@opcodes_cc = sort { $k_opcodes_cc{$a} <=> $k_opcodes_cc{$b} } keys(%k_opcodes_cc);
if ( $output eq 'b') {
print STDERR "Writing $oname...\n";