News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

Mov sizes

Started by jj2007, July 28, 2009, 10:18:03 PM

Previous topic - Next topic

jj2007

Here is a little macro showing the sizes of mov dest, src:

mov dest, src   m2m     mrm     mov     desc            choice
gdw1, eax:      7       7       5+      global, eax     mov
gdw1, ebx:      7       7       6+      global, reg     mov
eax, gdw1:      7       7       5+      eax, global     mov
ebx, gdw1:      7       7       6+      reg, global     mov
gdw1, 127:      8+      10      10      global, imm8    m2m
gdw1, 999:      11      10      10+     global, imm32   mov
gdw1, hwnd:     9       8+      -       global, arg     mrm
hwnd, gdw1:     9       8+      -       arg, global     mrm
gdw1, gdw2:     12      10+     -       global, global  mrm
eax, LocDw:     4       5       3+      eax, local      mov
ebx, LocDw:     4       5       3+      reg, local      mov
LocDw, eax:     4       5       3+      local, reg      mov
LocDw, 127:     5+      8       7       local, imm8     m2m
LocDw, 999:     8       8       7+      local, imm32    mov
LocDw, hwnd:    6+      6       -       local, arg      mrm
hwnd, LocDw:    6+      6       -       arg, local      mrm
LocDw, gdw1:    9       8+      -       local, global   mrm
gdw1, LocDw:    9       8+      -       global, local   mrm
eax, 127:       3+      7       5       eax, imm8       m2m
ebx, 127:       3+      7       5       ebx, imm8       m2m
eax, 999:       6       7       5+      eax, imm32      mov
ebx, 999:       6       7       5+      ebx, imm32      mov

+ = shortest option


Source:
include \masm32\include\masm32rt.inc

MyTest PROTO:DWORD,:DWORD,:DWORD,:DWORD

detail = 0
atImmediate = 36 ; 00100100
atGlobal = 42 ; 00101010
atRegister = 48 ; 00110000
atLocal = 98 ; 01100010

; if reg supplied, mrm is forced
; otherwise m2m if shorter of mov not possible

movo MACRO dest, src, reg ;; reg is optional, forces mrm instead of m2m
LOCAL od, os, immX, regX
  od = (opattr(dest)) AND 127
  os = (opattr(src)) AND 127
  regX = (os eq 48) + (od eq 48) ;; 48 = Register
  immX = 2*(os eq 36) ;; 36 = Immediate
  if immX
if (src gt 127) or (src lt -128)
immX = 1
endif
  endif
  if immX-regX gt 0
  mov dest, src
  elseifnb <reg>
mov reg, src
mov dest, reg
  else
  push src
  pop dest
  endif
ENDM

movsize MACRO dest, src, desc
LOCAL L1, L2, L3, L4, mvr$, flag, opt, imm32, immX, regX
  imm32 = 0
  regX = 0
  flag = 0
  opt = 0
  od = (opattr(dest)) AND 127
  os = (opattr(src)) AND 127
  regX = (os eq atRegister) + (od eq atRegister)
  immX = 2*(os eq atImmediate)
  if immX
if (src gt 127) or (src lt -128)
imm32 = 1
immX = 1
endif
  endif
  if (od eq atRegister) and (os eq atImmediate) and (imm32 eq 0)
  opt=0
  elseif (os eq atRegister) or (od eq atRegister) or ((od eq atGlobal) and imm32)
opt = 2
  elseif (os eq atGlobal) or (od eq atGlobal)
  opt =1
  if (os eq atImmediate) and (imm32 eq 0)
opt = 0
  endif
  elseif (os eq atImmediate) and imm32
opt = 2
  endif
  echo desc
L1:
  push src ;; m2m
  pop dest
L2:
  mov eax, src ; mrm
  mov dest, eax
L3:
  if (os eq atImmediate) or (os eq atRegister) or (od eq atRegister)
mvr$ CATSTR <mov >, <dest>, <, >, <src>
mvr$
flag = 1
  endif
L4:
  mov edx, offset L2-L1
  tmp$ CATSTR <print chr$(">, <dest>, <, >, <src>, <: ", 9)>
  tmp$
  mov edx, offset L2-L1
  if opt eq 0
print str$(edx), "+", 9
  else
print str$(edx), 9
  endif
  mov edx, offset L3-L2
  if opt eq 1
print str$(edx), "+", 9
  else
print str$(edx), 9
  endif
  if flag
mov edx, offset L4-L3
print str$(edx)
if opt eq 2
print "+"
endif
  else
print "-"
  endif
  tmp$ CATSTR <print chr$(9, ">, <desc>, <", 9)>
  tmp$
  if detail
print str$(od), "-"
print str$(os), 9
  endif
  if immX-regX gt 0
  print "mov "
  elseif immX-regX lt 0
  print "m2m "
  else
    print "mrm "
  endif
  if detail
print str$(-regX+immX), 13, 10
  else
print chr$(13, 10)
  endif
ENDM

.data? ; non-initialised variables
gdw1 dd ?
gdw2 dd ?

.code
start:
  if detail
print chr$("mov dest, src", 9, "m2m", 9, "mrm", 9, "mov", 9, "desc", 9, 9, "opattr", 9, "choice", 13, 10)
  else
print chr$("mov dest, src", 9, "m2m", 9, "mrm", 9, "mov", 9, "desc", 9, 9, "choice", 13, 10)
  endif
invoke MyTest, 12, 34, 56, 78
print chr$(13, 10, "+ = shortest option", 13, 10)
getkey
exit

MyTest proc hwnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL LocDw:DWORD
LOCAL LocDw1[400]:DWORD
movsize gdw1, eax, <global, eax>
movsize gdw1, ebx, <global, reg>
movsize eax, gdw1, <eax, global>
movsize ebx, gdw1, <reg, global>
movsize gdw1, 127, <global, imm8>
movsize gdw1, 999, <global, imm32>
movsize gdw1, hwnd, <global, arg>
movsize hwnd, gdw1, <arg, global>
movsize gdw1, gdw2, <global, global>
movsize eax, LocDw, <eax, local>
movsize ebx, LocDw, <reg, local>
movsize LocDw, eax, <local, reg>
movsize LocDw, 127, <local, imm8>
movsize LocDw, 999, <local, imm32>
movsize LocDw, hwnd, <local, arg>
movsize hwnd, LocDw, <arg, local>
movsize LocDw, gdw1, <local, global>
movsize gdw1, LocDw, <global, local>
movsize eax, 127, <eax, imm8>
movsize ebx, 127, <ebx, imm8>
movsize eax, 999, <eax, imm32>
movsize ebx, 999, <ebx, imm32>
  ret
MyTest endp
end start



Caution: mrm trashes eax

jj2007

movo aka Move Optimised decides for you which is the shortest mov option... a jewel for the macro haters :green

Usage: movo dest, src [, reg32]

; if reg supplied, mrm is forced
; otherwise m2m if shorter or mov not possible

movo MACRO dest, src, reg ;; reg is optional, forces mrm instead of m2m
LOCAL od, os, immX, regX
  od = (opattr(dest)) AND 127
  os = (opattr(src)) AND 127
  regX = (os eq 48) + (od eq 48) ;; 48 = Register
  immX = 2*(os eq 36) ;; 36 = Immediate
  if immX
if (src gt 127) or (src lt -128)
immX = 1
endif
  endif
  if immX-regX gt 0
  mov dest, src
  elseifnb <reg>
mov reg, src
mov dest, reg
  else
  push src
  pop dest
  endif
ENDM


A Replace all mov->movo is not recommended, since it doesn't work for non-dword sizes. Otherwise it seems to work fine, I tested it on a 10,000 lines source and got over 300 bytes less in the exe...

dedndave

wow - that is quite an improvement
was that the editor program ?

hutch--

 :bg

> Caution: mrm trashes eax

EAX is expendable.  :P
Download site for MASM32      New MASM Forum
https://masm32.com          https://masm32.com/board/index.php

cmpxchg

first of all imm8 equals to 0-255

at least in some places you should change imm8 to imm4 for size info to be valid. And imm4 will be equal to 0-127

Quote
eax, 127:       3+      7       5       eax, imm8       m2m
ebx, 127:       3+      7       5       ebx, imm8       m2m
eax, 999:       6       7       5+      eax, imm32      mov
ebx, 999:       6       7       5+      ebx, imm32      mov

I don't know how you managed more than 5bytes for "mov reg32,imm32" in protected mode

3 bytes EXACTLY

push $ffffffff
pop reg32


4 bytes, works only with eax

xor eax, eax
add/mov/or  al, imm8 (0-255)



if in you code you need to load 2(or more!!) constants less than 128 then

xor  ecx, ecx
lea  edx, [ecx+127]
lea  ebx, [ecx+127] 

will give you 2(or more) byte size advantage over this (which reminds me  - stop using macro)

mov  edx, 127
mov  ebx, 127

"lea" most likely faster than using memory(stack)

stay away from esp & ebp in addressing: mov(or any insrtuction) reg, [eBP+something]. They will add additional byte

Rockoon

Quote from: cmpxchg on August 02, 2009, 02:38:18 AM
first of all imm8 equals to 0-255

at least in some places you should change imm8 to imm4 for size info to be valid. And imm4 will be equal to 0-127


0..15 for 4-bit immediates

0..127 would be for 7-bit immediates

immediates are treated as signed in most cases where it might matter, so something like 'add reg, 128' should encode as a 32-bit immediate, whereas 'sub reg, -128' would use an 8-bit immediate (the two instructions perform equivilent work)

When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

MichaelW

Quote from: Rockoon on August 02, 2009, 12:28:15 PM
immediates are treated as signed in most cases where it might matter, so something like 'add reg, 128' should encode as a 32-bit immediate, whereas 'sub reg, -128' would use an 8-bit immediate (the two instructions perform equivilent work)

A good point, but I think you have the size of the immediate operands reversed.
eschew obfuscation

Rockoon

Quote from: MichaelW on August 02, 2009, 01:14:31 PM
Quote from: Rockoon on August 02, 2009, 12:28:15 PM
immediates are treated as signed in most cases where it might matter, so something like 'add reg, 128' should encode as a 32-bit immediate, whereas 'sub reg, -128' would use an 8-bit immediate (the two instructions perform equivilent work)

A good point, but I think you have the size of the immediate operands reversed.


I do not.

128 cannot be stored in a signed 8-bit value, but -128 can.

The valid range is

-128..+127 for 8-bit signed
-32768..+32767 for 16-bit signed
-2147483648..+2147483647 for 32-bit signed

In all cases, there is 1 more negative number than positive numbers (when treating 0 as neither)


http://en.wikipedia.org/wiki/Two's_complement
When C++ compilers can be coerced to emit rcl and rcr, I *might* consider using one.

MichaelW

Yes, you're right, my mistake.
eschew obfuscation

jj2007

Quote from: cmpxchg on August 02, 2009, 02:38:18 AM
> first of all imm8 equals to 0-255
Yes.

> at least in some places you should change imm8 to imm4 for size info to be valid. And imm4 will be equal to 0-127
No. As MichaelW and Rockoon rightly explained, the range for the short versions of the opcodes is -128 to +127, imm8

> I don't know how you managed more than 5bytes for "mov reg32,imm32" in protected mode
Read posts properly before answering: "+ = shortest option", not "more than"

> 3 bytes EXACTLY
> push $ffffffff
> pop reg32
Indeed, but it's not imm32 - it's imm8. $ffffffff is -1 and therefore part of the -128 ... +128 range

> stay away from esp & ebp in addressing: mov(or any insrtuction) reg, [eBP+something]. They will add additional byte
True for esp but not for ebp. You should RTFM