Skip to content

Commit 5422294

Browse files
H. Peter Anvin (Intel)Copilot
andcommitted
testgen: add implicitly-sized memory operand coverage
For instruction operand tokens that carry an explicit size in their own name (mem8/16/32/64/..., rm8/16/32/64, xmmrm.../ymmrm256/zmmrm512, mmxrm/mmxrm64), the generator previously always emitted an explicit size keyword (e.g. "dword", "oword") for the memory operand. This never exercised NASM's SM-flag-driven implicit-size-inference path, where the size of an ambiguous memory operand is inferred from a paired already-sized operand (typically a same-width register) in the same instruction template (e.g. ADD reg32,rm32 or MOVBE reg32,mem32 don't need an explicit size keyword). Add build_implicitsize_line(), which replaces the first memory-capable operand whose base token has a nonzero %mem_sizebits entry with a bare (size-keyword-free) memory operand, leaving all other operands as normally generated. As with the other coverage buckets (hireg, apxreg, mask/maskz/broadcast/saeer, disp8/32 boundary), the candidate line is routed through the shared cumulative staged probe and only kept if it actually assembles for that instruction -- this avoids needing to parse and replicate NASM's own SM/AR flag-driven operand-size-disambiguation logic. Note: for tokens with no size in their own name (plain "mem"), the existing mem_operand($rng, 0) generator path already omits the size keyword unconditionally, so that half of implicit-size coverage was already exercised prior to this change; only explicitly-sized tokens needed the new candidate. Verified via full scratch regeneration (2606 mnemonics / 16 dropped, unchanged) + nasm-t.py run (6955/6955 PASS, 0 FAIL) + per-mnemonic .json entry-count diff against the prior committed tree (zero differences, confirming no bit-width regressions). 1922/2606 mnemonics gained new implicit-size coverage lines. Regenerated travis/insns/ and validated via 'make -j32 travis' (all PASS, ~26s). Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
1 parent 5d8ec17 commit 5422294

3,993 files changed

Lines changed: 6736 additions & 69 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

tools/testgen/gen-insn-tests.pl

Lines changed: 57 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -651,6 +651,48 @@ sub build_dispboundary_line {
651651
return { text => lc($mnem) . ' ' . join(', ', @operands), needs64 => $needs64 };
652652
}
653653

654+
# Implicitly-sized memory operand coverage.
655+
#
656+
# For memory-capable operand tokens that carry an explicit size in
657+
# their own name (mem8/16/32/.../xmmrm128/ymmrm256/zmmrm512/mmxrm...,
658+
# i.e. every key in %mem_sizebits with a nonzero size), the generator
659+
# always renders a size keyword ("byte"/"dword"/"oword"/...) on the
660+
# memory form. But NASM permits omitting the keyword entirely whenever
661+
# the instruction template declares the operand's size is implied --
662+
# either a fixed size (x86/iflags.ph's SB/SW/SD/SQ/ST/SO/SY/SZ flags,
663+
# e.g. plain "mem" tokens like CLFLUSH/MOVNTI, already unsized by
664+
# %mem_sizebits and so not touched here) or a size *match* to another,
665+
# already-sized operand in the same template (SM0-4 flags, e.g.
666+
# "ADD reg32,rm32" / "MOVBE reg32,mem32" -- extremely common for
667+
# ALU/data-movement instructions pairing a register with a same-width
668+
# memory operand). Rather than parsing/expanding the SM/AR flag ranges
669+
# from insns.xda to decide exactly when this is legal, this candidate
670+
# simply tries the unsized form and lets the existing staged probe
671+
# below keep it only if it actually assembles -- consistent with the
672+
# rest of this tool's "regression test, not correctness oracle"
673+
# philosophy, and far simpler than re-deriving NASM's own operand-size
674+
# disambiguation logic.
675+
sub build_implicitsize_line {
676+
my ($rng, $mnem, $ops, $is_branch) = @_;
677+
my @operands;
678+
my $used_mem = 0;
679+
my $needs64 = 0;
680+
for my $tok (@$ops) {
681+
my $base = base_token($tok);
682+
if (!$used_mem && ($mem_sizebits{$base} // 0)) {
683+
push @operands, mem_operand($rng, 0);
684+
$used_mem = 1;
685+
next;
686+
}
687+
my $val = gen_operand($rng, $tok, $mnem, $is_branch);
688+
return undef unless defined $val;
689+
$needs64 = 1 if $needs64_token{$base};
690+
push @operands, $val;
691+
}
692+
return undef unless $used_mem;
693+
return { text => lc($mnem) . ' ' . join(', ', @operands), needs64 => $needs64 };
694+
}
695+
654696
sub make_rng {
655697
my ($seedval) = @_;
656698
# Small deterministic xorshift-ish PRNG so runs are reproducible
@@ -718,6 +760,7 @@ sub render_body {
718760
my @extra_broadcast; # candidate {1toN}-broadcast lines
719761
my @extra_saeer; # candidate {sae}/{rn-sae}-decorated lines
720762
my @extra_dispboundary; # candidate [eax+1]/[eax+64] boundary lines
763+
my @extra_implicitsize; # candidate unsized-memory-operand lines
721764
for my $t (@sample) {
722765
my $opt_idx = optional_operand_index($t->{ops});
723766
my $extendable = has_extendable_token($t->{ops});
@@ -809,6 +852,18 @@ sub render_body {
809852
}
810853
}
811854

855+
# Implicitly-sized memory operand coverage (see
856+
# build_implicitsize_line() above): once per *distinct* template
857+
# across the mnemonic's entire template set, same reasoning as the
858+
# two loops above. Candidates only, routed through the same staged
859+
# probe -- omitting the size keyword is only legal when the
860+
# instruction's flags declare a fixed or size-matched operand size,
861+
# which this generator doesn't parse directly (see comment above).
862+
for my $t (@dedup_all) {
863+
my $dl = build_implicitsize_line($rng, $mnem, $t->{ops}, $is_branch);
864+
push @extra_implicitsize, $dl if defined $dl;
865+
}
866+
812867
next unless @lines; # nothing we knew how to generate
813868

814869
my @narrow_lines = grep { !$_->{needs64} } @lines;
@@ -870,7 +925,8 @@ sub render_body {
870925

871926
my @full_lines = @lines;
872927
for my $cat (\@extra_hireg, \@extra_apxreg, \@extra_mask, \@extra_maskz,
873-
\@extra_broadcast, \@extra_saeer, \@extra_dispboundary) {
928+
\@extra_broadcast, \@extra_saeer, \@extra_dispboundary,
929+
\@extra_implicitsize) {
874930
next unless @$cat;
875931
my $candidate = [@full_lines, @$cat];
876932
@full_lines = @$candidate if $probe_ok->($candidate);

travis/insns/aadd/aadd.asm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ default rel
1111
aadd dword [eax+64], eax
1212
aadd qword [eax+1], rbx
1313
aadd qword [eax+64], rcx
14+
aadd [0xd52], edi
15+
aadd [0x5d8], rdi

travis/insns/aadd/aadd.bin64.t

19 Bytes
Binary file not shown.

travis/insns/aand/aand.asm

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,5 @@ default rel
1111
aand dword [eax+64], edi
1212
aand qword [eax+1], rdx
1313
aand qword [eax+64], rsi
14+
aand [0x436], edi
15+
aand [0x77b], rdx

travis/insns/aand/aand.bin64.t

21 Bytes
Binary file not shown.

travis/insns/adc/adc.asm

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,33 @@ default rel
7575
adc edi, dword [eax+64], 0x1c9b9a8
7676
adc rsi, qword [eax+1], -428886289
7777
adc rsi, qword [eax+64], 6139295
78+
adc [0xa68], bl
79+
adc [0xe3d], bp
80+
adc [0xb68], ecx
81+
adc [0x31c], rdx
82+
adc al, [0x685]
83+
adc dx, [0xe6d]
84+
adc esi, [0x8d9]
85+
adc rdx, [0x342]
86+
adc [0x1ad], 0x1e
87+
adc [0x398], -56
88+
adc [0x6be], 0x5482
89+
adc [0xa03], 122
90+
adc [0xe68], 0xf951f04
91+
adc [0x92a], -90
92+
adc [0x7a2], 41191012
93+
adc cl, bl, [0xb7a]
94+
adc si, di, [0x8d4]
95+
adc esi, esi, [0x3a2]
96+
adc rbp, rbp, [0x4f1]
97+
adc dl, [0x228], cl
98+
adc cx, [0xa58], bx
99+
adc esi, [0xd3a], eax
100+
adc rbp, [0x906], rbp
101+
adc di, [0xa86], 27
102+
adc edx, [0xf56], -13
103+
adc rdx, [0x7d0], 59
104+
adc dl, [0x397], 0x64
105+
adc si, [0x1be], 0x6934
106+
adc ebp, [0xc5c], 0x3a6c5247
107+
adc rdi, [0x7e4], 220977984

travis/insns/adc/adc.bin64.t

295 Bytes
Binary file not shown.

travis/insns/adc/adc.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,8 @@
2828
"source": "adc.asm",
2929
"option": "--bits 64 -w-ea-absolute -w-implicit-abs-deprecated -I./travis/insns/adc/",
3030
"target": [
31-
{ "output": "adc.bin64", "match": "adc.bin64.t" }
31+
{ "output": "adc.bin64", "match": "adc.bin64.t" },
32+
{ "stderr": "adc.stderr64" }
3233
]
3334
}
3435
]

travis/insns/adc/adc.stderr64

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
./travis/insns/adc/adc.asm:88: warning: byte exceeds bounds [-w+number-overflow]
2+
./travis/insns/adc/adc.asm:90: warning: byte exceeds bounds [-w+number-overflow]
3+
./travis/insns/adc/adc.asm:92: warning: byte exceeds bounds [-w+number-overflow]

travis/insns/adcx/adcx.asm

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,7 @@ default rel
2525
adcx ebx, ecx, dword [eax+64]
2626
adcx rdi, rax, qword [eax+1]
2727
adcx rax, rbx, qword [eax+64]
28+
adcx ebp, [0x4e0]
29+
adcx rbx, [0x3eb]
30+
adcx edx, edx, [0x280]
31+
adcx rdx, rdx, [0xffe]

0 commit comments

Comments
 (0)