# Rules for optimizing BCC assembler output

# Rules for loading short variables

mov	%2,%[ax|bx|cx|dx]1
mov	%[ax|bx|cx|dx]1,%2
=
mov	%2,%1

# Assign a constant
mov	%[ax|bx|cx|dx]3,%[#|*]0%1
mov	%2[%4],%[ax|bx|cx|dx]3
!BCC_EOS
=
mov	word ptr %2[%4],%0%1
!BCC_EOS

# Assign a constant char
mov	al,%[#|*]0%1
mov	%2,al
!BCC_EOS
=
mov	byte ptr %2,%0%1
!BCC_EOS

# Assign a constant long from a small int
xor	ax,ax
mov	bx,%[#|*]0%1
mov	[%2],ax
mov	[%2+2],bx
!BCC_EOS
=
mov	word ptr [%2],#0
mov	word ptr [%2+2],%0%1
!BCC_EOS

# Assign a constant long from a 2^16 mod int.
mov	ax,%[#|*]0%1
xor	bx,bx
mov	[%2],ax
mov	[%2+2],bx
!BCC_EOS
=
mov	word ptr [%2],%0%1
mov	word ptr [%2+2],#0
!BCC_EOS

# Assign a constant long from a big int
mov	ax,%[#|*]4%1
mov	bx,%[#|*]5%3
mov	[%2],ax
mov	[%2+2],bx
!BCC_EOS
=
mov	word ptr [%2],%4%1
mov	word ptr [%2+2],%5%3
!BCC_EOS

# rule for (char*)  *x++
mov	bx,%1
%[inc|dec]2	bx
mov	%1,bx
mov	al,-1[bx]
xor	ah,ah
=
mov	bx,%1
%2	word ptr %1
mov	al,[bx]
xor	ah,ah

# Rules for incrementing short variables
mov	%[ax|bx|si|di]2,%1
%[inc|dec]3	%[ax|bx|si|di]2
mov	%1,%[ax|bx|si|di]2
!BCC_EOS
=
%3	word ptr %1
!BCC_EOS

mov	%[ax|bx|si|di]2,%1
%[inc|dec]3	%[ax|bx|si|di]2
mov	%1,%[ax|bx|si|di]2
=
%3	word ptr %1
mov	%2,%1


# Rules for manipulating characters with register char*s

inc	%[si|di]*
inc	%[si|di]*
mov	al,-1[si]
mov	-1[di],al
!BCC_EOS
=
lodsb
stosb
!BCC_EOS

inc	%[si|di]*
inc	%[si|di]*
mov	al,-1[di]
mov	-1[si],al
!BCC_EOS
=
xchg	si,di
lodsb
stosb
xchg	si,di
!BCC_EOS

inc	si
mov	al,-1[si]
=
lodsb

inc	di
mov	-1[di],al
=
stosb

dec	%[si|di]*
dec	%[si|di]*
mov	al,1[si]
mov	1[di],al
=
std
lodsb
stosb
cld

dec	%[si|di]*
dec	%[si|di]*
mov	al,1[di]
mov	1[si],al
=
std
xchg	si,di
lodsb
stosb
xchg	si,di
cld

dec	si
mov	al,1[si]
=
std
lodsb
cld

dec	di
mov	1[di],al
=
std
stosb
cld


# Rules for manipulating short values

# These rules only apply at end of statment.
mov	%[ax|bx]2,%1
%[add|and|xor|sub|or]4	%[ax|bx]2,%3
mov	%1,%[ax|bx]2
!BCC_EOS
=
mov	%2,%3
%4	%1,%2
!BCC_EOS

mov	%[ax|bx]2,%1
%[add|and|xor|or]4	%[ax|bx]2,%3
mov	%3,%[ax|bx]2
!BCC_EOS
=
mov	%2,%1
%4	%3,%2
!BCC_EOS

mov	al,%1
xor	ah,ah
%[add|and|xor|sub|or]2	ax,%[#|*]0%3
mov	%1,al
!BCC_EOS
=
%2	byte ptr %1,%0%3
!BCC_EOS

# This is safe with an embedded assign.
mov	%[ax|bx]4,%1
%[add|and|xor|sub|or]2	%[si|di]3,%[ax|bx]4
=
%2	%3,%1

# Rules for comparing short values

# Compare doesn't need to leave any register in a specific state.

mov	%[ax|bx]3,%1[%4]
cmp	%[ax|bx]3,%[#|*]0%2
=
cmp	word ptr %1[%4],%0%2

mov	al,%1[%4]
cmp	al,%[#|*]0%2
=
cmp	byte ptr %1[%4],%0%2

mov	%[ax|bx]3,%[ax|bx|cx|dx|si|di]2
cmp	%[ax|bx]3,%1
=
cmp	%2,%1


# General comparison rules

xor	%1,%1
mov	%2,%3
cmp	%2,%1
=
mov	%2,%3
cmp	%2,#0

mov	%1,%[#|*]0%2
mov	%3,%4
cmp	%3,%1
=
mov	%3,%4
cmp	%3,%0%2

mov	%1,%2
cmp	%1,%[#|*]00
%[jne |je  ]4	%3
=
mov	%1,%2
test	%1,%1
%4	%3

%[and|xor|or]1	%2,%3
test	%2,%2
=
%1	%2,%3


# General incrementation and decrementation rules

inc	%3 ptr %1
mov	%2,%1
dec	%2
=
mov	%2,%1
inc	%3 ptr %1

dec	%3 ptr %1
mov	%2,%1
inc	%2
=
mov	%2,%1
dec	%3 ptr %1

mov	%1,%2
inc	%3 ptr %2
push	%1
=
push	%3 ptr %2
inc	%3 ptr %2

mov	%1,%2
dec	%3 ptr %2
push	%1
=
push	%3 ptr %2
dec	%3 ptr %2


# Misc. rules

push	word %[#|*]0%1
inc	%[si|di]2
inc	%[si|di]2
mov	%[ax|bx|cx|dx]3,%*[bp]
mov	%4[%[si|di]2],%[ax|bx|cx|dx]3
inc	sp
inc	sp
=
mov	word ptr %(%4+2)[%2],%0%1
inc	%2
inc	%2

push	%1
mov	%[ax|bx|cx|dx]3,%2
%[add|and|xor|or]4	%[ax|bx|cx|dx]3,%*[bp]
inc	sp
inc	sp
=
mov	%3,%1
%4	%3,%2

# If %1 is ax this fails badly.
# push	%1
# mov	%[ax|bx|cx|dx]3,%2
# %[add|sub|and|xor|or]5	%[ax|bx|cx|dx]3,%6
# %[add|sub|and|xor|or]4	%[ax|dx|cx|dx]3,%*[bp]
# inc	sp
# inc	sp
# =
# mov	%3,%2
# %5	%3,%6
# %4	%3,%1

push	%1
mov	%[ax|bx|cx|dx]3,%*[bp]
%[add|sub|and|xor|or]4	%2,%[ax|bx|cx|dx]3
inc	sp
inc	sp
=
mov	%3,%1
%4	%2,%3

mov	%1,%[ax|bx|cx|dx]2
push	%1
=
mov	%1,%2
push	%2

# Rules to remove superflous mov instructions

mov	%1,%2
mov	%1,%2
=
mov	%1,%2

mov	%1,%2
.%3:
mov	%1,%2
=
.%3:
mov	%1,%2

mov	%1,%2
mov	%2,%1
=
mov	%1,%2

mov	%1,%[ax|bx|cx|dx|eax|ebx|ecx|edx]2
mov	%[ax|bx|cx|dx|eax|ebx|ecx|edx]3,%1
=
mov	%1,%2
mov	%3,%2

mov	%1,%1
=
!mov	%1,%1

# Sometimes the compiler puts a jump right after a ret or another jump
# (in if-else-if constructions). Eliminate the second unnecessary jump.
# Also it puts a jump to the next instruction in extensive if-else
# constructions. That jump can also be removed.

jmp	.%1
jmp	.%2
=
jmp	%1

ret
jmp	%2
=
ret

jmp .%1
.%1:
=
.%1:

jmp .%1
.%2:
!BCC_EOS
.%1:
=
.%2:
!BCC_EOS
.%1:

jmp .%1
.%3:
.%2:
.%1:
=
.%3:
.%2:
.%1:


# When using register variables the compiler initializes them when
# they are found in the source code, and sets up the stack frame for
# other local variables lateron. Move initialization of register variables
# behind the add-sp instruction to make further optimization easier.

proc_start
mov	%[si|di]3,%1
add	sp,*%2
=
proc_start
add	sp,*%2
mov	%3,%1

proc_start
mov	%[si|di]3,%1
dec	sp
dec	sp
=
proc_start
dec	sp
dec	sp
mov	%3,%1

add	sp,*%1
add	sp,*%2
=
add	sp,*%1+%2

dec	sp
dec	sp
add	sp,*%1
=
add	sp,*%1-2

add	sp,*%1
dec	sp
dec	sp
=
add	sp,*%1-2

inc	sp
inc	sp
%1	%2
inc	sp
inc	sp
=
%1	%2
add	sp,*4

inc	sp
inc	sp
%1	%2
add	sp,*%3
=
%1	%2
add	sp,*%3+2

add	sp,*%3
%1	%2
inc	sp
inc	sp
=
%1	%2
add	sp,*%3+2

add	sp,*%3
%1	%2
add	sp,*%4
=
%1	%2
add	sp,*%3+%4

# And a great bug floating push/pop
push	dx
push	cx
push	bx
push	ax
pop	ax
pop	bx
pop	cx
pop	dx
=
! push/pop float

# Long right shift by 16 unsigned
mov	ax,%1
mov	bx,%2
xchg	bx,ax
xor	bx,bx
=
mov	ax,%2
xor	bx,bx

# Long right shift by 16 signed
mov	ax,%1
mov	bx,%2
xchg	bx,ax
cwd
=
mov	ax,%2
cwd

# Load long and exchange
mov	ax,%1
mov	bx,%2
xchg	bx,ax
=
mov	bx,%1
mov	ax,%2

# Repeated clear.
xor	bx,bx
xchg	bx,ax
xor	ax,ax
=
xchg	bx,ax
xor	ax,ax

# Long expression assigned to an int
cwd
mov	bx,dx
mov	%1,ax
!BCC_EOS
=
mov	%1,ax
!BCC_EOS

# Load unsigned into high word of long
mov	ax,%1
xchg	bx,ax
xor	ax,ax
=
mov	bx,%1
xor	ax,ax

# Souped up strcpy;  "while(*d++ = *s++);" in a function with no reg vars.
.%3:
!BCC_EOS
.%4:
mov	bx,%1
inc	bx
mov	%1,bx
mov	si,%2
inc	si
mov	%2,si
mov	al,-1[bx]
mov	-1[si],al
test	al,al
jne	.%3
=
.%4:
mov	si,%1
mov	di,%2
.%3:
lodsb
stosb
test	al,al
jne	.%3
mov	%1,si
mov	%2,di
!BCC_EOS

###
mov	ax,%1
mov	%[ax|bx|cx|dx]2,ax
mov	ax,%3
=
mov	%2,%1
mov	ax,%3
