x86lint examines x86-64 machine code to find suboptimal encodings and sequences.
For example, add eax, 1 can encode with either an 8- or 32-bit immediate:
83C0 01
81C0 01000000
Using the former can result in smaller and faster code. x86lint can help compiler writers generate better code and documents the complexity of x86.
- missing LOCK prefix on CMPXCHG and XADD
- oversized ADD 128
05 80000000instead of83E8 80(ADD EAX, 128 -> SUB EAX, -128)
- oversized branch displacement
E9 00000000instead ofEB 03(JMP rel32 that fits in rel8)
- oversized immediates
81C0 01000000instead of83C0 01(ADD EAX, 1)
- oversized MOV encoding
C7C0 01000000instead ofB8 01000000(MOV EAX, 1)
- redundant ADD/SUB zero
83C0 00(ADD EAX, 0) -- use TEST or remove
- redundant MOV reg, reg
4889C0(MOV RAX, RAX)
- suboptimal AND immediate
83E0 FF(AND EAX, 0xFF) -- use MOVZBL
- suboptimal CMP zero
83F8 00instead of85C0(CMP EAX, 0 -> TEST EAX, EAX)
- suboptimal IMUL constant
6BC0 03(IMUL EAX, EAX, 3) -- use LEA or SHL
suboptimal NOP sequence, see #9- multiple
90instead of a single66 90, etc.
- multiple
- suboptimal SUB reg, reg
29C0(SUB EAX, EAX) -- use XOR for dependency-breaking
suboptimal zero register, see #7- MOV EAX, 0 instead of XOR EAX, EAX
- unneeded explicit immediate
C1D0 01instead ofD1D0(RCL EAX, 1)
- unneeded explicit register
81C0 00010000instead of05 00010000(ADD EAX, 0x100)
- unneeded LOCK prefix on XCHG
- unneeded MOVSXD
48 63 C0instead of48 98(MOVSXD RAX, EAX -> CDQE)
- unneeded REX prefix
- XOR RAX, RAX
4831C0instead of XOR EAX, EAX31C0 40C9instead ofC9(LEAVE)
- XOR RAX, RAX
- unneeded SIB byte
C64465 04 05instead ofC645 04 05(MOV byte [RBP+4], 5)
- unneeded zero displacement
017E 00instead of013E(ADD [RSI], EDI)
First install the Intel x86 encoder decoder:
git clone https://github.com/intelxed/xed.git xed
git clone https://github.com/intelxed/mbuild.git mbuild
cd xed
./mfile.py install --install-dir=kits/xed-install
Next build x86lint:
git clone https://github.com/gaul/x86lint.git x86lint
cd x86lint
XED_PATH=/path/to/xed make all
x86lint is intended to be part of compiler test suites which should #include "x86lint.h" and link libx86lint.a. It can also read arbitrary ELF executables via:
./x86lint /bin/ls
- Agner Fog optimization guide
- Intel instruction set reference
- Intel optimization manual
- Intel x86 encoder decoder - library to parse instructions
Copyright (C) 2018 Andrew Gaul
Licensed under the Apache License, Version 2.0