Skip to content

[x86] OptPass1LEA improvements

Summary

This merge request streamlines and improves the LEA/LEA optimisations under OptPass1LEA to better reduce instruction counts and break dependency chains.

System

  • Processor architecture: i386, x86_64

What is the current bug behavior?

N/A

What is the behavior after applying this patch?

Optimisations involving lea instructions are slightly improved.

Relevant logs and/or screenshots

(All comparisons done under -O4, x86_64-win64)

A large number of units receive improvements.

A couple of simple ones in the graph unit (the shll and addl instructions are converted from lea instructions in Pass 2):

.section .text.n_graph_$$_floodfill$smallint$smallint$word,"ax"
	...
	leaq	1(%rdx),%rax
	leaq	(,%rax,8),%rsi
	...
.section .text.n_graph_$$_wincreate$$qword,"ax"
	...
	shll	$1,%eax
	addl	%esi,%eax
	...

After:

.section .text.n_graph_$$_floodfill$smallint$smallint$word,"ax"
	...
	leaq	8(,%rdx,8),%rsi
	...
.section .text.n_graph_$$_wincreate$$qword,"ax"
	...
	leal	(%esi,%eax,2),%eax
	...

in the blowfish unit, an optimisation is performed where the instructions aren't adjacent - before:

.section .text.n_blowfish$_$tblowfishencryptstream_$__$$_flush,"ax"
	...
	movq	%rcx,%rbx
	cmpb	$0,48(%rcx)
	jna	.Lj117
	leaq	40(%rcx),%rdx
	movzbl	48(%rcx),%eax
	leaq	(%rdx,%rax,1),%rcx
	movzbl	48(%rbx),%eax
	movl	$8,%edx
	...

After:

.section .text.n_blowfish$_$tblowfishencryptstream_$__$$_flush,"ax"
	...
	movq	%rcx,%rbx
	cmpb	$0,48(%rcx)
	jna	.Lj117
	movzbl	48(%rcx),%eax
	leaq	40(%rcx,%rax,1),%rcx
	movzbl	48(%rbx),%eax
	movl	$8,%edx
	...

This is an interesting block because movzbl 48(%rbx),%eax is logically redundant, since %eax contains the value of movzbl 48(%rcx),%eax at that point, where %rbx = %rcx. The feature in !191 can possibly the redundant instruction with some tuning.

In the chmreader unit, the improved optimisations causes a better cascade that reduces the instructions in a block from 4 to 2 - before:

.section .text.n_chmreader$_$tarrayhelper$1$crc8d68c026_crc1ceae787_$__$$_median$hhkolmv67x4h,"ax"
	...
	movq	%r8,%rsi
	movq	%rcx,%rbx
	movq	%rdx,%rax
	shrq	$1,%rax
	shlq	$3,%rax
	leaq	(%rax,%rcx),%rdi
	leaq	-8(,%rdx,8),%rax
	leaq	(%rax,%rcx),%r12	...

After:

.section .text.n_chmreader$_$tarrayhelper$1$crc8d68c026_crc1ceae787_$__$$_median$hhkolmv67x4h,"ax"
	...
	movq	%r8,%rsi
	movq	%rcx,%rbx
	movq	%rdx,%rax
	shrq	$1,%rax
	leaq	(%rcx,%rax,8),%rdi
	leaq	-8(%rcx,%rdx,8),%r12
	...

In the system unit, the optimisation is performed even though the intermediate register is still in use afterwards, meaning the original instruction isn't removed (this optimisation isn't performed under -Os), however it breaks the dependency chain - before:

.section .text.n_system_$$_align$qword$qword$$qword,"ax"
	...
	movq	%rdx,%r8
	leaq	-1(%rdx),%rax
	leaq	(%rcx,%rax),%r9
	andq	%rax,%rdx

After:

.section .text.n_system_$$_align$qword$qword$$qword,"ax"
	...
	movq	%rdx,%r8
	leaq	-1(%rdx),%rax
	leaq	-1(%rcx,%rdx),%r9
	andq	%rax,%rdx

This one is also interesting from an optimisation standpoint because %r8 doesn't actually get used in the procedure and so movq %rdx,%r8 can be removed.

Merge request reports