about summary refs log tree commit diff
path: root/amd64.e
diff options
context:
space:
mode:
authorIrene Knapp <ireneista@irenes.space>2026-09-08 03:51:54 -0700
committerIrene Knapp <ireneista@irenes.space>2026-09-08 03:53:47 -0700
commitc02add3a9568f731d0ab420ce58499b74ce686bf (patch)
treebb4a4c84c38340da00cd0f391f35819c8eb010d1 /amd64.e
parent2b91b63149a88c4ecab606129fcc9fa28232e88d (diff)
add magic comment length tracking to all the amd64 instructions
yay!

Force-Push: yes
Change-Id: Ib54458c2466362391cc8724ad8af32f03a869e03
Diffstat (limited to 'amd64.e')
-rw-r--r--amd64.e429
1 files changed, 288 insertions, 141 deletions
diff --git a/amd64.e b/amd64.e
index 04c4aa7..d2fa2cd 100644
--- a/amd64.e
+++ b/amd64.e
@@ -23,6 +23,53 @@
 ~   TODO define instructions, assembly code, machine code, opcodes. if we ever
 ~ also want to recommend a childrens' introduction to binary, this might be
 ~ the place to do it.
+~
+~
+~ Hex-transformed output
+~ ~~~~~~~~~~~~~~~~~~~~~~
+~
+~   In addition to the actual semantics of the assembly words, there's an
+~ important layer of meaning atop them. The hex transform, described in detail
+~ in transform.e, modifies a compilation process to produce a commented hex
+~ dump instead of a binary. It includes a magic-comment feature which allows
+~ words that have opinions on what their output's hex dump should look like to
+~ express them.
+~
+~   The code in this file makes extensive use of the magic-comment feature.
+~ Any comment which starts with : as its first word is a magic comment meant
+~ for the hex transform. When the hex transform is not in use, these are
+~ ordinary comments and are ignored. When it is in use, they create and modify
+~ metadata annotations in a complex way.
+~
+~   The magic comments in this file follows two important conventions: First,
+~ entries are created by whichever word directly corresponds to a top-level
+~ assembly instruction from the perspective of someone programming with it,
+~ at some point prior to calling any word which might pack output. Second,
+~ output bytes are accounted for by whichever word directly calls a pack* word
+~ for them.
+~
+~   Thus, for example, the word "syscall" has a comment which creates an entry
+~ describing its length as 2 bytes, which never varies.
+~
+~   The word "mov-reg64-imm32", on the other hand, has a comment which
+~ creates an entry describing is length as 5 bytes - the opcode and the
+~ immediate value, which are output with calls to pack8 and pack32 in that
+~ word. However, the actual length of the instruction is 5 bytes. When
+~ mov-reg64-imm32 calls rex-w, a magic comment there modifies the most recent
+~ entry in-place, marking it as being one byte longer. Subsequently,
+~ mov-reg64-imm32 calls addressing-reg64, which calls modrm, which again
+~ modifies the same entry. Notice that addressing-reg64 didn't need to do
+~ anything, because it isn't directly responsible for any packing.
+~
+~   Notice that when an entry is modified in place, it needs to have been
+~ created first. Attempting to do it in the wrong order will have an
+~ undesired effect, most likely editing the entry of an unrelated instruction.
+~ The hex transform doesn't have detailed knowledge of assembly, and isn't in
+~ a position to know that the edits that are happening are sensible.
+~
+~   Hopefully these examples show why an accounting convention is needed. The
+~ good news is that the convention is quite robust and needs essentially no
+~ play-by-play commentary, just this explainer at the top.
 
 
 ~ Keywords
@@ -263,22 +310,54 @@ s" :cc-greater" keyword
 ~ don't have to revisit this topic.
 ~
 ~ (output point -- output point)
-: rex-0 0x40 pack8 ;
-: rex-w 0x48 pack8 ;
-: rex-r 0x44 pack8 ;
-: rex-x 0x42 pack8 ;
-: rex-b 0x41 pack8 ;
-: rex-wr 0x4C pack8 ;
-: rex-wx 0x4A pack8 ;
-: rex-wb 0x49 pack8 ;
-: rex-rx 0x46 pack8 ;
-: rex-rb 0x45 pack8 ;
-: rex-xb 0x43 pack8 ;
-: rex-wrx 0x4E pack8 ;
-: rex-wrb 0x4D pack8 ;
-: rex-wxb 0x4B pack8 ;
-: rex-rxb 0x47 pack8 ;
-: rex-wrxb 0x4F pack8 ;
+: rex-0
+  ~ : 1 adjust-length
+  0x40 pack8 ;
+: rex-w
+  ~ : 1 adjust-length
+  0x48 pack8 ;
+: rex-r
+  ~ : 1 adjust-length
+  0x44 pack8 ;
+: rex-x
+  ~ : 1 adjust-length
+  0x42 pack8 ;
+: rex-b
+  ~ : 1 adjust-length
+  0x41 pack8 ;
+: rex-wr
+  ~ : 1 adjust-length
+  0x4C pack8 ;
+: rex-wx
+  ~ : 1 adjust-length
+  0x4A pack8 ;
+: rex-wb
+  ~ : 1 adjust-length
+  0x49 pack8 ;
+: rex-rx
+  ~ : 1 adjust-length
+  0x46 pack8 ;
+: rex-rb
+  ~ : 1 adjust-length
+  0x45 pack8 ;
+: rex-xb
+  ~ : 1 adjust-length
+  0x43 pack8 ;
+: rex-wrx
+  ~ : 1 adjust-length
+  0x4E pack8 ;
+: rex-wrb
+  ~ : 1 adjust-length
+  0x4D pack8 ;
+: rex-wxb
+  ~ : 1 adjust-length
+  0x4B pack8 ;
+: rex-rxb
+  ~ : 1 adjust-length
+  0x47 pack8 ;
+: rex-wrxb
+  ~ : 1 adjust-length
+  0x4F pack8 ;
 
 
 ~   Some opcodes use their low three bits as a field to give a register name.
@@ -293,7 +372,9 @@ s" :cc-greater" keyword
 ~
 ~ (output point, 3-bit encoded value for register, opcode byte
 ~  -- output point)
-: opcodereg | pack8 ;
+: opcodereg
+  ~ : 1 adjust-length
+  | pack8 ;
 
 
 ~   Some opcodes use their low four bits as a field to give a condition code.
@@ -304,7 +385,9 @@ s" :cc-greater" keyword
 ~
 ~ (output point, 4-bit encoded value for condition code, opcode byte
 ~  -- output point)
-: opcodecc | pack8 ;
+: opcodecc
+  ~ : 1 adjust-length
+  | pack8 ;
 
 
 ~   A Mod/RM byte ("mode / register-or-memory") is part of the encoding of
@@ -317,7 +400,9 @@ s" :cc-greater" keyword
 ~
 ~ (output point, mod field, register/opcode field, register/memory field
 ~  -- output point)
-: modrm swap 8 * | swap 64 * | pack8 ;
+: modrm
+  ~ : 1 adjust-length
+  swap 8 * | swap 64 * | pack8 ;
 
 ~   An SIB byte ("scale, index, base") is part of the encoding of many
 ~ instructions. It's divided into three fields, with the names you've already
@@ -327,7 +412,9 @@ s" :cc-greater" keyword
 ~ its fields.
 ~
 ~ (output point, scale field, index field, base field -- output point)
-: sib swap 8 * | swap 64 * | pack8 ;
+: sib
+  ~ : 1 adjust-length
+  swap 8 * | swap 64 * | pack8 ;
 
 
 ~ Addressing modes
@@ -419,6 +506,7 @@ s" :cc-greater" keyword
   ~ If the R/M register was rsp, we need an SIB byte; otherwise, skip it.
   3roll { 0 4 :rsp reg64 sib } if
   ~ The displacement byte.
+  ~ : 1 adjust-length
   swap pack8 ;
 
 ~ (output point, reg/op field value, reg/mem field register,
@@ -433,6 +521,7 @@ s" :cc-greater" keyword
   ~ If the R/M register was rsp, we need an SIB byte; otherwise, skip it.
   3roll { 0 4 :rsp reg64 sib } if
   ~ The displacement value.
+  ~ : 4 adjust-length
   swap pack32 ;
 
 ~ (output point, reg/op field value,
@@ -456,6 +545,7 @@ s" :cc-greater" keyword
   ~ Reg/mem value 4 means to use an SIB byte (at least, with this mode).
   6 roll 1 7 roll 4 modrm 5 unroll
   5 unroll reg64 3unroll reg64 3unroll scalefield 3unroll sib
+  ~ : 1 adjust-length
   swap pack8 ;
 
 
@@ -466,47 +556,55 @@ s" :cc-greater" keyword
 ~ grouping. These are the ones that were easy to deal with.
 
 ~ (output point -- output point)
-: cld ~ : cld
+: cld
+  ~ : 1 cld
   0xFC pack8 ;
-: std ~ : std
+: std
+  ~ : 1 std
   0xFD pack8 ;
-: syscall ~ : syscall
+: syscall
+  ~ : 2 syscall
   0x0F pack8 0x05 pack8 ;
-: hlt ~ : hlt
+: hlt
+  ~ : 1 hlt
   0xF4 pack8 ;
 
 ~ (output point, source register -- output point)
-: push-reg64 ~ : push-reg64
+: push-reg64
+  ~ : 0 push-reg64
   reg64 0x50 opcodereg ;
-: push-extrareg64 ~ : push-extrareg64
+: push-extrareg64
+  ~ : 0 push-extrareg64
   swap rex-b swap extrareg64 0x50 opcodereg ;
   ~   Note the use of the B rex bit here; this instruction puts the register
   ~ number in the opcode field, so it uses Table 3-1.
 
 ~ (output point, target register -- output point)
-: pop-reg64 ~ : pop-reg64
+: pop-reg64
+  ~ : 1 pop-reg64
   reg64 0x58 opcodereg ;
-: pop-extrareg64 ~ : pop-extrareg64
+: pop-extrareg64
+  ~ : 2 pop-extrareg64
   swap rex-b swap extrareg64 0x58 opcodereg ;
   ~   Note the use of the B rex bit here; this instruction puts the register
   ~ number in the opcode field, so it uses Table 3-1.
 
 ~ (output point, immediate value -- output point)
 : push-imm32-extended64
-  ~ : push-imm32-extended64
+  ~ : 5 push-imm32-extended64
   swap 0x68 pack8 swap pack32 ;
 
 ~ (output point, source register, source displacement value, target register
 ~  -- output point)
 : lea-reg64-disp8-reg64
-  ~ : lea-reg64-disp8-reg64
+  ~ : 1 lea-reg64-disp8-reg64
   4 roll rex-w 0x8D pack8 4 unroll
   reg64 3unroll addressing-disp8-reg64 ;
 
 ~ (output point, source register, source displacement value, target register
 ~  -- output point)
 : lea-reg64-disp32-reg64
-  ~ : lea-reg64-disp32-reg64
+  ~ : 1 lea-reg64-disp32-reg64
   4 roll rex-w 0x8D pack8 4 unroll
   reg64 3unroll addressing-disp32-reg64 ;
 
@@ -514,7 +612,7 @@ s" :cc-greater" keyword
 ~  source base register, source index register, source index scale factor,
 ~  target register -- output point)
 : lea-reg64-indexed-reg64
-  ~ : lea-reg64-indexed-reg64
+  ~ : 1 lea-reg64-indexed-reg64
   5 roll rex-w 0x8D pack8 5 unroll
   reg64 4 unroll 3unroll swap addressing-indexed-reg64 ;
 
@@ -523,7 +621,7 @@ s" :cc-greater" keyword
 ~  source displacement value,
 ~  target register -- output point)
 : lea-reg64-disp8-indexed-reg64
-  ~ : lea-reg64-disp8-indexed-reg64
+  ~ : 1 lea-reg64-disp8-indexed-reg64
   6 roll rex-w 0x8D pack8 6 unroll
   reg64 5 unroll 3 roll 4 roll 3 roll addressing-disp8-indexed-reg64 ;
 
@@ -543,50 +641,51 @@ s" :cc-greater" keyword
 
 ~ (output point, immediate value, register -- output point)
 : mov-reg64-imm32
-  ~ : mov-reg64-imm32
-  3roll rex-w 0xC7 pack8 swap
+  ~ : 5 mov-reg64-imm32
+  3roll
+  rex-w 0xC7 pack8 swap
   0 swap addressing-reg64
   swap pack32 ;
 : mov-reg64-imm64
-  ~ : mov-reg64-imm64
+  ~ : 8 mov-reg64-imm64
   3roll rex-w swap reg64 0xB8 opcodereg swap pack64 ;
 : mov-extrareg64-imm64
-  ~ : mov-extrareg64-imm64
+  ~ : 8 mov-extrareg64-imm64
   ~   Note the use of the B rex bit here; this instruction puts the register
   ~ number in the opcode field, so it uses Table 3-1.
   3roll rex-wb swap extrareg64 0xB8 opcodereg swap pack64 ;
 
 ~ (output point, source register, target register -- output point)
 : mov-reg64-reg64
-  ~ : mov-reg64-reg64
+  ~ : 1 mov-reg64-reg64
   3roll rex-w 0x89 pack8 3unroll
   swap reg64 swap addressing-reg64 ;
 : mov-indirect-reg64-reg64
-  ~ : mov-indirect-reg64-reg64
+  ~ : 1 mov-indirect-reg64-reg64
   3roll rex-w 0x89 pack8 3unroll
   swap reg64 swap addressing-indirect-reg64 ;
 
 ~ (output point, source register, target register, target displacement value
 ~  -- output point)
 : mov-disp8-reg64-reg64
-  ~ : mov-disp8-reg64-reg64
+  ~ : 1 mov-disp8-reg64-reg64
   4 roll rex-w 0x89 pack8 4 unroll
   3roll reg64 3unroll addressing-disp8-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : mov-reg64-indirect-reg64
-  ~ : mov-reg64-indirect-reg64
+  ~ : 1 mov-reg64-indirect-reg64
   3roll rex-w 0x8B pack8 3unroll
   reg64 swap addressing-indirect-reg64 ;
 
 ~ (output point, source register, source displacement value, target register
 ~  -- output point)
 : mov-reg64-disp8-reg64
-  ~ : mov-reg64-disp8-reg64
+  ~ : 1 mov-reg64-disp8-reg64
   4 roll rex-w 0x8B pack8 4 unroll
   reg64 3unroll addressing-disp8-reg64 ;
 : mov-reg64-disp32-reg64
-  ~ : mov-reg64-disp32-reg64
+  ~ : 1 mov-reg64-disp32-reg64
   4 roll rex-w 0x89 pack8 4 unroll
   3roll reg64 swap 3roll addressing-disp32-reg64 ;
 
@@ -594,7 +693,7 @@ s" :cc-greater" keyword
 ~  source base register, source index register, source index scale factor,
 ~  target register -- output point)
 : mov-reg64-indexed-reg64
-  ~ : mov-reg64-indexed-reg64
+  ~ : 1 mov-reg64-indexed-reg64
   5 roll rex-w 0x8B pack8 5 unroll
   reg64 4 unroll 3unroll swap addressing-indexed-reg64 ;
 
@@ -602,92 +701,92 @@ s" :cc-greater" keyword
 ~  target base register, target index register, target index scale factor
 ~  -- output point)
 : mov-indexed-reg64-reg64
-  ~ : mov-indexed-reg64-reg64
+  ~ : 1 mov-indexed-reg64-reg64
   5 roll rex-w 0x89 pack8 5 unroll
   4 roll reg64 4 unroll
   3unroll swap addressing-indexed-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : mov-indirect-reg64-reg32
-  ~ : mov-indirect-reg64-reg32
+  ~ : 1 mov-indirect-reg64-reg32
   3roll 0x89 pack8 3unroll
   swap reg32 swap addressing-indirect-reg64 ;
 
-~ (output point, source regisgter, target register, target displacement value
+~ (output point, source register, target register, target displacement value
 ~  -- output point)
 : mov-disp8-reg64-reg32
-  ~ : mov-disp8-reg64-reg32
+  ~ : 1 mov-disp8-reg64-reg32
   4 roll 0x89 pack8 4 unroll
   3roll reg32 3unroll addressing-disp8-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : mov-reg32-indirect-reg64
-  ~ : mov-reg32-indirect-reg64
+  ~ : 1 mov-reg32-indirect-reg64
   3roll 0x8B pack8 3unroll
   reg32 swap addressing-indirect-reg64 ;
 
 ~ (output point, source register, source displacement value, target register
 ~ -- output point)
 : mov-reg32-disp8-reg64
-  ~ : mov-reg32-disp8-reg64
+  ~ : 1 mov-reg32-disp8-reg64
   4 roll 0x8B pack8 4 unroll
   reg32 3unroll addressing-disp8-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : mov-indirect-reg64-reg16
-  ~ : mov-indirect-reg64-reg16
+  ~ : 2 mov-indirect-reg64-reg16
   3roll 0x66 pack8 0x89 pack8 3unroll
   swap reg16 swap addressing-indirect-reg64 ;
 
 ~ (output point, source register, target register, target displacement value
 ~  -- output point)
 : mov-disp8-reg64-reg16
-  ~ : mov-disp8-reg64-reg16
+  ~ : 2 mov-disp8-reg64-reg16
   4 roll 0x66 pack8 0x89 pack8 4 unroll
   3roll reg16 3unroll addressing-disp8-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : mov-reg16-indirect-reg64
-  ~ : mov-reg16-indirect-reg64
+  ~ : 2 mov-reg16-indirect-reg64
   3roll 0x66 pack8 0x8B pack8 3unroll
   reg16 swap addressing-indirect-reg64 ;
 
 ~ (output point, source register, target displacement value, target register
 ~  -- output point)
 : mov-reg16-disp8-reg64
-  ~ : mov-reg16-disp8-reg64
+  ~ : 2 mov-reg16-disp8-reg64
   4 roll 0x66 pack8 0x8B pack8 4 unroll
   reg16 3unroll addressing-disp8-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : mov-indirect-reg64-reg8
-  ~ : mov-indirect-reg64-reg8
+  ~ : 1 mov-indirect-reg64-reg8
   3roll 0x88 pack8 3unroll
   swap reg8 swap addressing-indirect-reg64 ;
 
 ~ (output point, source register, target register, target displacement value
 ~  -- output point)
 : mov-disp8-reg64-reg8
-  ~ : mov-disp8-reg64-reg8
+  ~ : 1 mov-disp8-reg64-reg8
   4 roll 0x88 pack8 4 unroll
   3roll reg8 3unroll addressing-disp8-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : mov-reg8-indirect-reg64
-  ~ : mov-reg8-indirect-reg64
+  ~ : 1 mov-reg8-indirect-reg64
   3roll 0x8A pack8 3unroll
   reg8 swap addressing-indirect-reg64 ;
 
 ~ (output point, source register, source displacement value, target register
 ~  -- output point)
 : mov-reg8-disp8-reg64
-  ~ : mov-reg8-disp8-reg64
+  ~ : 2 mov-reg8-disp8-reg64
   4 roll pack8 0x8A pack8 4 unroll
   reg8 3unroll addressing-disp8-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : mov-reg8-reg8
-  ~ : mov-reg8-reg8
+  ~ : 1 mov-reg8-reg8
   3roll 0x88 pack8 3unroll
   swap reg8 swap addressing-reg8 ;
 
@@ -722,109 +821,157 @@ s" :cc-greater" keyword
 ~ here...
 
 ~ (output point -- output point)
-: movs8 ~ : movs8
+: movs8
+  ~ : 1 movs8
   0xA4 pack8 ;
-: movs16 ~ : movs16
+: movs16
+  ~ : 2 movs16
   0x66 pack8 0xA5 pack8 ;
-: movs32 ~ : movs32
+: movs32
+  ~ : 1 movs32
   0xA5 pack8 ;
-: movs64 ~ : movs64
+: movs64
+  ~ : 1 movs64
   rex-w 0xA5 pack8 ;
-: rep-movs8 ~ : rep-movs8
+: rep-movs8
+  ~ : 2 rep-movs8
   0xF3 pack8 0xA4 pack8 ;
-: rep-movs16 ~ : rep-movs16
+: rep-movs16
+  ~ : 3 rep-movs16
   0xF3 pack8 0x66 pack8 0xA5 pack8 ;
-: rep-movs32 ~ : rep-movs32
+: rep-movs32
+  ~ : 2 rep-movs32
   0xF3 pack8 0xA5 pack8 ;
-: rep-movs64 ~ : rep-movs64
+: rep-movs64
+  ~ : 2 rep-movs64
   0xF3 pack8 rex-w 0xA5 pack8 ;
 
 ~ (output point -- output point)
-: lods8 ~ : lods8
+: lods8
+  ~ : 1 lods8
   0xAC pack8 ;
-: lods16 ~ : lods16
+: lods16
+  ~ : 2 lods16
   0x66 pack8 0xAd pack8 ;
-: lods32 ~ : lods32
+: lods32
+  ~ : 1 lods32
   0xAD pack8 ;
-: lods64 ~ : lods64
+: lods64
+  ~ : 1 lods64
   rex-w 0xAD pack8 ;
-: rep-lods8 ~ : rep-lods8
+: rep-lods8
+  ~ : 2 rep-lods8
   0xF3 pack8 0xAC pack8 ;
-: rep-lods16 ~ : rep-lods16
+: rep-lods16
+  ~ : 3 rep-lods16
   0xF3 pack8 0x66 pack8 0xAD pack8 ;
-: rep-lods32 ~ : rep-lods32
+: rep-lods32
+  ~ : 2 rep-lods32
   0xF3 pack8 0xAD pack8 ;
-: rep-lods64 ~ : rep-lods64
+: rep-lods64
+  ~ : 2 rep-lods64
   0xF3 pack8 rex-w 0xAD pack8 ;
 
 ~ (output point -- output point)
-: stos8 ~ : stos8
+: stos8
+  ~ : 1 stos8
   0xAA pack8 ;
-: stos16 ~ : stos16
+: stos16
+  ~ : 2 stos16
   0x66 pack8 0xAB pack8 ;
-: stos32 ~ : stos32
+: stos32
+  ~ : 1 stos32
   0xAB pack8 ;
-: stos64 ~ : stos64
+: stos64
+  ~ : 1 stos64
   rex-w 0xAB pack8 ;
-: rep-stos8 ~ : rep-stos8
+: rep-stos8
+  ~ : 2 rep-stos8
   0xF3 pack8 0xAA pack8 ;
-: rep-stos16 ~ : rep-stos16
+: rep-stos16
+  ~ : 3 rep-stos16
   0xF3 pack8 0x66 pack8 0xAB pack8 ;
-: rep-stos32 ~ : rep-stos32
+: rep-stos32
+  ~ : 2 rep-stos32
   0xF3 pack8 0xAB pack8 ;
-: rep-stos64 ~ : rep-stos64
+: rep-stos64
+  ~ : 2 rep-stos64
   0xF3 pack8 rex-w 0xAB pack8 ;
 
 ~ (output point -- output point)
-: cmps8 ~ : cmps8
+: cmps8
+  ~ : 1 cmps8
   0xA6 pack8 ;
-: cmps16 ~ : cmps16
+: cmps16
+  ~ : 2 cmps16
   0x66 pack8 0xA7 pack8 ;
-: cmps32 ~ : cmps32
+: cmps32
+  ~ : 1 cmps32
   0xA7 pack8 ;
-: cmps64 ~ : cmps64
+: cmps64
+  ~ : 1 cmps64
   rex-w 0xA7 pack8 ;
-: repz-cmps8 ~ : repz-cmps8
+: repz-cmps8
+  ~ : 2 repz-cmps8
   0xF3 pack8 0xA6 pack8 ;
-: repz-cmps16 ~ : repz-cmps16
+: repz-cmps16
+  ~ : 3 repz-cmps16
   0xF3 pack8 0x66 pack8 0xA7 pack8 ;
-: repz-cmps32 ~ : repz-cmps32
+: repz-cmps32
+  ~ : 2 repz-cmps32
   0xF3 pack8 0xA7 pack8 ;
-: repz-cmps64 ~ : repz-cmps64
+: repz-cmps64
+  ~ : 2 repz-cmps64
   0xF3 pack8 rex-w 0xA7 pack8 ;
-: repnz-cmps8 ~ : repnz-cmps8
+: repnz-cmps8
+  ~ : 2 repnz-cmps8
   0xF2 pack8 0xA6 pack8 ;
-: repnz-cmps16 ~ : repnz-cmps16
+: repnz-cmps16
+  ~ : 3 repnz-cmps16
   0xF2 pack8 0x66 pack8 0xA7 pack8 ;
-: repnz-cmps32 ~ : repnz-cmps32
+: repnz-cmps32
+  ~ : 2 repnz-cmps32
   0xF2 pack8 0xA7 pack8 ;
-: repnz-cmps64 ~ : repnz-cmps64
+: repnz-cmps64
+  ~ : 2 repnz-cmps64
   0xF2 pack8 rex-w 0xA7 pack8 ;
 
 ~ (output point -- output point)
-: scas8 ~ : scas8
+: scas8
+  ~ : 1 scas8
   0xA8 pack8 ;
-: scas16 ~ : scas16
+: scas16
+  ~ : 2 scas16
   0x66 pack8 0xAF pack8 ;
-: scas32 ~ : scas32
+: scas32
+  ~ : 1 scas32
   0xAF pack8 ;
-: scas64 ~ : scas64
+: scas64
+  ~ : 1 scas64
   rex-w 0xAF pack8 ;
-: repz-scas8 ~ : repz-scas8
+: repz-scas8
+  ~ : 2 repz-scas8
   0xF3 pack8 0xAE pack8 ;
-: repz-scas16 ~ : repz-scas16
+: repz-scas16
+  ~ : 3 repz-scas16
   0xF3 pack8 0x66 pack8 0xAF pack8 ;
-: repz-scas32 ~ : repz-scas32
+: repz-scas32
+  ~ : 2 repz-scas32
   0xF3 pack8 0xAF pack8 ;
-: repz-scas64 ~ : repz-scas64
+: repz-scas64
+  ~ : 2 repz-scas64
   0xF3 pack8 rex-w 0xAF pack8 ;
-: repnz-scas8 ~ : repnz-scas8
+: repnz-scas8
+  ~ : 2 repnz-scas8
   0xF2 pack8 0xAE pack8 ;
-: repnz-scas16 ~ : repnz-scas16
+: repnz-scas16
+  ~ : 3 repnz-scas16
   0xF2 pack8 0x66 pack8 0xAF pack8 ;
-: repnz-scas32 ~ : repnz-scas32
+: repnz-scas32
+  ~ : 2 repnz-scas32
   0xF2 pack8 0xAF pack8 ;
-: repnz-scas64 ~ : repnz-scas64
+: repnz-scas64
+  ~ : 2 repnz-scas64
   0xF2 pack8 rex-w 0xAF pack8 ;
 
 
@@ -843,25 +990,25 @@ s" :cc-greater" keyword
 
 ~ (output point, source register, target register -- output point)
 : add-reg64-reg64
-  ~ : add-reg64-reg64
+  ~ : 1 add-reg64-reg64
   3roll rex-w 0x01 pack8 3unroll
   swap reg64 swap addressing-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : add-indirect-reg64-reg64
-  ~ : add-indirect-reg64-reg64
+  ~ : 1 add-indirect-reg64-reg64
   3roll rex-w 0x01 pack8 3unroll
   swap reg64 swap addressing-indirect-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : add-reg64-indirect-reg64
-  ~ : add-reg64-indirect-reg64
+  ~ : 1 add-reg64-indirect-reg64
   3roll rex-w 0x03 pack8 3unroll
   reg64 swap addressing-indirect-reg64 ;
 
 ~ (output point, immediate value, target register -- output point)
 : add-reg64-imm8
-  ~ : add-reg64-imm8
+  ~ : 2 add-reg64-imm8
   3roll rex-w 0x83 pack8 swap 0 swap addressing-reg64
   swap pack8 ;
 
@@ -869,13 +1016,13 @@ s" :cc-greater" keyword
 ~
 ~ (output point, source register, target register -- output point)
 : sub-reg64-reg64
-  ~ : sub-reg64-reg64
+  ~ : 1 sub-reg64-reg64
   3roll rex-w 0x2B pack8 3unroll
   reg64 swap addressing-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : sub-indirect-reg64-reg64
-  ~ : sub-indirect-reg64-reg64
+  ~ : 1 sub-indirect-reg64-reg64
   3roll rex-w 0x2B pack8 3unroll
   swap reg64 swap addressing-indirect-reg64 ;
 
@@ -883,7 +1030,7 @@ s" :cc-greater" keyword
 ~
 ~ (output point, immediate value, target register -- output point)
 : sub-reg64-imm8
-  ~ : sub-reg64-imm8
+  ~ : 2 sub-reg64-imm8
   3roll rex-w 0x83 pack8 swap 5 swap addressing-reg64
   swap pack8 ;
 
@@ -891,7 +1038,7 @@ s" :cc-greater" keyword
 ~
 ~ (output point, source register, target register -- output point)
 : sbb-reg64-imm8
-  ~ : sbb-reg64-imm8
+  ~ : 2 sbb-reg64-imm8
   3roll rex-w 0x83 pack8 swap 3 swap addressing-reg64
   swap pack8 ;
 
@@ -899,7 +1046,7 @@ s" :cc-greater" keyword
 ~
 ~ (output point, source register -- output point)
 : mul-reg64
-  ~ : mul-reg64
+  ~ : 1 mul-reg64
   swap rex-w 0xF7 pack8 swap
   4 swap addressing-reg64 ;
 
@@ -912,7 +1059,7 @@ s" :cc-greater" keyword
 ~
 ~ (output point, divisor register -- output point)
 : divmod-reg64
-  ~ : divmod-reg64
+  ~ : 1 divmod-reg64
   swap rex-w 0xF7 pack8 swap
   6 swap addressing-reg64 ;
 
@@ -920,82 +1067,82 @@ s" :cc-greater" keyword
 ~
 ~ (output point, divisor register -- output point)
 : idivmod-reg64
-  ~ : idivmod-reg64
+  ~ : 1 idivmod-reg64
   swap rex-w 0xF7 pack8 swap
   7 swap addressing-reg64 ;
 
 ~ (output point, target register -- output point)
 : inc-reg64
-  ~ : inc-reg64
+  ~ : 1 inc-reg64
   swap rex-w 0xFF pack8 swap 0 swap addressing-reg64 ;
 
 ~ (output point, target register -- output point)
 : dec-reg64
-  ~ : dec-reg64
+  ~ : 1 dec-reg64
   swap rex-w 0xFF pack8 swap 1 swap addressing-reg64 ;
 
 ~ (output point, source register, target register -- output point)
 : and-reg64-reg64
-  ~ : and-reg64-reg64
+  ~ : 1 and-reg64-reg64
   3roll rex-w 0x23 pack8 3unroll
   reg64 swap addressing-reg64 ;
 
 ~ (output point, source value, target register -- output point)
 : and-reg64-imm8
-  ~ : and-reg64-imm8
+  ~ : 2 and-reg64-imm8
   3roll rex-w 0x83 pack8 swap
   4 swap addressing-reg64
   swap pack8 ;
 
 ~ (output point, source register, target register -- output point)
 : or-reg64-reg64
-  ~ : or-reg64-reg64
+  ~ : 1 or-reg64-reg64
   3roll rex-w 0x0B pack8 3unroll
   reg64 swap addressing-reg64 ;
 
 ~ (output point, source value, target register -- output point)
 : or-reg64-imm8
-  ~ : or-reg64-imm8
+  ~ : 2 or-reg64-imm8
   3roll rex-w 0x83 pack8 swap
   1 swap addressing-reg64
   swap pack8 ;
 
 ~ (output point, source register, target register -- output point)
 : xor-reg64-reg64
-  ~ : xor-reg64-reg64
+  ~ : 1 xor-reg64-reg64
   3roll rex-w 0x33 pack8 3unroll
   reg64 swap addressing-reg64 ;
 
 ~ (output point, target register -- output point)
 : not-reg64
-  ~ : not-reg64
+  ~ : 1 not-reg64
   swap rex-w 0xF7 pack8
   swap 2 swap addressing-reg64 ;
 
 ~ (output point, bit count, target register -- output point)
 : rol-reg64-imm8
-  ~ : rol-reg64-imm8
+  ~ : 2 rol-reg64-imm8
   3roll rex-w 0xC1 pack8 swap
   0 swap addressing-reg64
   swap pack8 ;
 
 ~ (output point, bit count, target register -- output point)
 : rol-reg8-imm8
-  ~ : rol-reg8-imm8
+  ~ : 2 rol-reg8-imm8
   3roll 0xC0 pack8 swap
   0 swap addressing-reg8
   swap pack8 ;
 
 ~ (output point, bit count, target register -- output point)
 : ror-reg64-imm8
-  ~ : ror-reg64-imm8
+  ~ : 1 ror-reg64-imm8
   3roll rex-w 0xC1 swap
   1 swap addressing-reg64
   swap pack8 ;
 
 ~ (output point, bit count, target register -- output point)
 : ror-reg8-imm8
-  ~ : ror-reg8-imm8
+  ~ : 2 ror-reg8-imm8
   3roll 0xC0 pack8 swap
   1 swap addressing-reg64
   swap pack8 ;
@@ -1013,7 +1160,7 @@ s" :cc-greater" keyword
 ~
 ~ (output point, left register, right register -- output point)
 : cmp-reg64-reg64
-  ~ : cmp-reg64-reg64
+  ~ : 1 cmp-reg64-reg64
   3roll rex-w 0x3B pack8 3unroll
   reg64 swap addressing-reg64 ;
 
@@ -1021,7 +1168,7 @@ s" :cc-greater" keyword
 ~
 ~ (output point, immediate value, target register -- output point)
 : cmp-reg64-imm8
-  ~ : cmp-reg64-imm8
+  ~ : 2 cmp-reg64-imm8
   3roll rex-w 0x83 pack8
   ~ (immediate value, register, output point)
   swap 7 swap addressing-reg64
@@ -1037,45 +1184,45 @@ s" :cc-greater" keyword
 ~
 ~ (output point, left register, right register -- output point)
 : test-reg64-reg64
-  ~ : test-reg64-reg64
+  ~ : 1 test-reg64-reg64
   3roll rex-w 0x85 pack8 3unroll
   swap reg64 swap addressing-reg64 ;
 
 ~ (output point, condition code, target register -- output point)
 : set-reg8-cc
-  ~ : set-reg8-cc
+  ~ : 1 set-reg8-cc
   3roll 0x0F pack8
   3roll condition-code 0x90 opcodecc
   swap reg8 3 0 3roll modrm ;
 
 ~ (output point, address offset value, condition code -- output point)
 : jmp-cc-rel-imm8
-  ~ : jmp-cc-rel-imm8
+  ~ : 1 jmp-cc-rel-imm8
   3roll swap condition-code 0x70 opcodecc
   swap pack8 ;
 
 ~ (output point, address offset value, condition code -- output point)
 : jmp-cc-rel-imm32
-  ~ : jmp-cc-rel-imm32
+  ~ : 5 jmp-cc-rel-imm32
   3unroll 0x0F pack8
   swap condition-code 0x70 opcodecc
   swap pack32 ;
 
 ~ (output point, register -- output point)
 : jmp-abs-indirect-reg64
-  ~ : jmp-abs-indirect-reg64
+  ~ : 1 jmp-abs-indirect-reg64
   swap 0xFF pack8 swap
   4 swap addressing-indirect-reg64 ;
 
 ~ (output point, address offset value -- output point)
 : jmp-rel-imm8
-  ~ : jmp-rel-imm8
+  ~ : 2 jmp-rel-imm8
   swap 0xEB pack8
   swap pack8 ;
 
 ~ (output point, address offset value -- output point)
 : jmp-rel-imm32
-  ~ : jmp-rel-imm32
+  ~ : 5 jmp-rel-imm32
   swap 0xE9 pack8
   swap pack32 ;
 
@@ -1083,7 +1230,7 @@ s" :cc-greater" keyword
 ~
 ~ (output point, address offset value -- output point)
 : call-rel-imm32
-  ~ : call-rel-imm32
+  ~ : 5 call-rel-imm32
   swap 0xE8 pack8
   swap pack32 ;
 
@@ -1091,6 +1238,6 @@ s" :cc-greater" keyword
 ~
 ~ (output point)
 : ret
-  ~ : ret
+  ~ : 1 ret
   0xC3 pack8 ;