Craig Topper 46e5052b8e [X86FixupLEAs] Turn optIncDec into a generic two address LEA optimizer. Support LEA64_32r properly.
INC/DEC is really a special case of a more generic issue. We should also turn leas into add reg/reg or add reg/imm regardless of the slow lea flags.

This also supports LEA64_32 which has 64 bit input registers and 32 bit output registers. So we need to convert the 64 bit inputs to their 32 bit equivalents to check if they are equal to base reg.

One thing to note, the original code preserved the kill flags by adding operands to the new instruction instead of using addReg. But I think tied operands aren't supposed to have the kill flag set. I dropped the kill flags, but I could probably try to preserve it in the add reg/reg case if we think its important. Not sure which operand its supposed to go on for the LEA64_32r instruction due to the super reg implicit uses. Though I'm also not sure those are needed since they were probably just created by an INSERT_SUBREG from a 32-bit input.

Differential Revision: https://reviews.llvm.org/D61472

llvm-svn: 361691
2019-05-25 06:17:47 +00:00

438 lines
13 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -enable-cse-in-irtranslator=0 -enable-cse-in-legalizer=0 -mtriple=i386-linux-gnu -mattr=+sse2 -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X32
; RUN: llc -enable-cse-in-irtranslator=0 -enable-cse-in-legalizer=0 -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=ALL --check-prefix=X64
define i32 @test_ret_i32() {
; X32-LABEL: test_ret_i32:
; X32: # %bb.0:
; X32-NEXT: movl $20, %eax
; X32-NEXT: retl
;
; X64-LABEL: test_ret_i32:
; X64: # %bb.0:
; X64-NEXT: movl $20, %eax
; X64-NEXT: retq
ret i32 20
}
define i64 @test_ret_i64() {
; X32-LABEL: test_ret_i64:
; X32: # %bb.0:
; X32-NEXT: movl $4294967295, %eax # imm = 0xFFFFFFFF
; X32-NEXT: movl $15, %edx
; X32-NEXT: retl
;
; X64-LABEL: test_ret_i64:
; X64: # %bb.0:
; X64-NEXT: movabsq $68719476735, %rax # imm = 0xFFFFFFFFF
; X64-NEXT: retq
ret i64 68719476735
}
define i8 @test_arg_i8(i8 %a) {
; X32-LABEL: test_arg_i8:
; X32: # %bb.0:
; X32-NEXT: movb {{[0-9]+}}(%esp), %al
; X32-NEXT: retl
;
; X64-LABEL: test_arg_i8:
; X64: # %bb.0:
; X64-NEXT: movl %edi, %eax
; X64-NEXT: # kill: def $al killed $al killed $eax
; X64-NEXT: retq
ret i8 %a
}
define i16 @test_arg_i16(i16 %a) {
; X32-LABEL: test_arg_i16:
; X32: # %bb.0:
; X32-NEXT: movzwl {{[0-9]+}}(%esp), %eax
; X32-NEXT: retl
;
; X64-LABEL: test_arg_i16:
; X64: # %bb.0:
; X64-NEXT: movl %edi, %eax
; X64-NEXT: # kill: def $ax killed $ax killed $eax
; X64-NEXT: retq
ret i16 %a
}
define i32 @test_arg_i32(i32 %a) {
; X32-LABEL: test_arg_i32:
; X32: # %bb.0:
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: retl
;
; X64-LABEL: test_arg_i32:
; X64: # %bb.0:
; X64-NEXT: movl %edi, %eax
; X64-NEXT: retq
ret i32 %a
}
define i64 @test_arg_i64(i64 %a) {
; X32-LABEL: test_arg_i64:
; X32: # %bb.0:
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %edx
; X32-NEXT: retl
;
; X64-LABEL: test_arg_i64:
; X64: # %bb.0:
; X64-NEXT: movq %rdi, %rax
; X64-NEXT: retq
ret i64 %a
}
define i64 @test_i64_args_8(i64 %arg1, i64 %arg2, i64 %arg3, i64 %arg4, i64 %arg5, i64 %arg6, i64 %arg7, i64 %arg8) {
; X32-LABEL: test_i64_args_8:
; X32: # %bb.0:
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %edx
; X32-NEXT: retl
;
; X64-LABEL: test_i64_args_8:
; X64: # %bb.0:
; X64-NEXT: movq {{[0-9]+}}(%rsp), %rax
; X64-NEXT: retq
ret i64 %arg8
}
define <4 x i32> @test_v4i32_args(<4 x i32> %arg1, <4 x i32> %arg2) {
; X32-LABEL: test_v4i32_args:
; X32: # %bb.0:
; X32-NEXT: movaps %xmm1, %xmm0
; X32-NEXT: retl
;
; X64-LABEL: test_v4i32_args:
; X64: # %bb.0:
; X64-NEXT: movaps %xmm1, %xmm0
; X64-NEXT: retq
ret <4 x i32> %arg2
}
define <8 x i32> @test_v8i32_args(<8 x i32> %arg1, <8 x i32> %arg2) {
; X32-LABEL: test_v8i32_args:
; X32: # %bb.0:
; X32-NEXT: subl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 16
; X32-NEXT: movaps %xmm2, %xmm0
; X32-NEXT: movups {{[0-9]+}}(%esp), %xmm1
; X32-NEXT: addl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_v8i32_args:
; X64: # %bb.0:
; X64-NEXT: movaps %xmm2, %xmm0
; X64-NEXT: movaps %xmm3, %xmm1
; X64-NEXT: retq
ret <8 x i32> %arg2
}
declare void @trivial_callee()
define void @test_trivial_call() {
; X32-LABEL: test_trivial_call:
; X32: # %bb.0:
; X32-NEXT: subl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 16
; X32-NEXT: calll trivial_callee
; X32-NEXT: addl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_trivial_call:
; X64: # %bb.0:
; X64-NEXT: pushq %rax
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: callq trivial_callee
; X64-NEXT: popq %rax
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
call void @trivial_callee()
ret void
}
declare void @simple_arg_callee(i32 %in0, i32 %in1)
define void @test_simple_arg_call(i32 %in0, i32 %in1) {
; X32-LABEL: test_simple_arg_call:
; X32: # %bb.0:
; X32-NEXT: subl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 16
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X32-NEXT: movl %ecx, (%esp)
; X32-NEXT: movl %eax, {{[0-9]+}}(%esp)
; X32-NEXT: calll simple_arg_callee
; X32-NEXT: addl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_simple_arg_call:
; X64: # %bb.0:
; X64-NEXT: pushq %rax
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: movl %edi, %eax
; X64-NEXT: movl %esi, %edi
; X64-NEXT: movl %eax, %esi
; X64-NEXT: callq simple_arg_callee
; X64-NEXT: popq %rax
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
call void @simple_arg_callee(i32 %in1, i32 %in0)
ret void
}
declare void @simple_arg8_callee(i32 %arg1, i32 %arg2, i32 %arg3, i32 %arg4, i32 %arg5, i32 %arg6, i32 %arg7, i32 %arg8)
define void @test_simple_arg8_call(i32 %in0) {
; X32-LABEL: test_simple_arg8_call:
; X32: # %bb.0:
; X32-NEXT: subl $44, %esp
; X32-NEXT: .cfi_def_cfa_offset 48
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: movl %eax, {{[0-9]+}}(%esp)
; X32-NEXT: movl %eax, {{[0-9]+}}(%esp)
; X32-NEXT: movl %eax, {{[0-9]+}}(%esp)
; X32-NEXT: movl %eax, {{[0-9]+}}(%esp)
; X32-NEXT: movl %eax, {{[0-9]+}}(%esp)
; X32-NEXT: movl %eax, {{[0-9]+}}(%esp)
; X32-NEXT: movl %eax, {{[0-9]+}}(%esp)
; X32-NEXT: calll simple_arg8_callee
; X32-NEXT: addl $44, %esp
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_simple_arg8_call:
; X64: # %bb.0:
; X64-NEXT: subq $24, %rsp
; X64-NEXT: .cfi_def_cfa_offset 32
; X64-NEXT: movl %edi, (%rsp)
; X64-NEXT: movl %edi, {{[0-9]+}}(%rsp)
; X64-NEXT: movl %edi, %esi
; X64-NEXT: movl %edi, %edx
; X64-NEXT: movl %edi, %ecx
; X64-NEXT: movl %edi, %r8d
; X64-NEXT: movl %edi, %r9d
; X64-NEXT: callq simple_arg8_callee
; X64-NEXT: addq $24, %rsp
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
call void @simple_arg8_callee(i32 %in0, i32 %in0, i32 %in0, i32 %in0,i32 %in0, i32 %in0, i32 %in0, i32 %in0)
ret void
}
declare i32 @simple_return_callee(i32 %in0)
define i32 @test_simple_return_callee() {
; X32-LABEL: test_simple_return_callee:
; X32: # %bb.0:
; X32-NEXT: subl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 16
; X32-NEXT: movl $5, %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll simple_return_callee
; X32-NEXT: addl %eax, %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_simple_return_callee:
; X64: # %bb.0:
; X64-NEXT: pushq %rax
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: movl $5, %edi
; X64-NEXT: callq simple_return_callee
; X64-NEXT: addl %eax, %eax
; X64-NEXT: popq %rcx
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
%call = call i32 @simple_return_callee(i32 5)
%r = add i32 %call, %call
ret i32 %r
}
declare <8 x i32> @split_return_callee(<8 x i32> %in0)
define <8 x i32> @test_split_return_callee(<8 x i32> %arg1, <8 x i32> %arg2) {
; X32-LABEL: test_split_return_callee:
; X32: # %bb.0:
; X32-NEXT: subl $44, %esp
; X32-NEXT: .cfi_def_cfa_offset 48
; X32-NEXT: movaps %xmm0, (%esp) # 16-byte Spill
; X32-NEXT: movaps %xmm1, {{[0-9]+}}(%esp) # 16-byte Spill
; X32-NEXT: movdqa %xmm2, %xmm0
; X32-NEXT: movdqu {{[0-9]+}}(%esp), %xmm1
; X32-NEXT: calll split_return_callee
; X32-NEXT: paddd (%esp), %xmm0 # 16-byte Folded Reload
; X32-NEXT: paddd {{[0-9]+}}(%esp), %xmm1 # 16-byte Folded Reload
; X32-NEXT: addl $44, %esp
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_split_return_callee:
; X64: # %bb.0:
; X64-NEXT: subq $40, %rsp
; X64-NEXT: .cfi_def_cfa_offset 48
; X64-NEXT: movaps %xmm0, (%rsp) # 16-byte Spill
; X64-NEXT: movaps %xmm1, {{[0-9]+}}(%rsp) # 16-byte Spill
; X64-NEXT: movdqa %xmm2, %xmm0
; X64-NEXT: movdqa %xmm3, %xmm1
; X64-NEXT: callq split_return_callee
; X64-NEXT: paddd (%rsp), %xmm0 # 16-byte Folded Reload
; X64-NEXT: paddd {{[0-9]+}}(%rsp), %xmm1 # 16-byte Folded Reload
; X64-NEXT: addq $40, %rsp
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
%call = call <8 x i32> @split_return_callee(<8 x i32> %arg2)
%r = add <8 x i32> %arg1, %call
ret <8 x i32> %r
}
define void @test_indirect_call(void()* %func) {
; X32-LABEL: test_indirect_call:
; X32: # %bb.0:
; X32-NEXT: subl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 16
; X32-NEXT: calll *{{[0-9]+}}(%esp)
; X32-NEXT: addl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_indirect_call:
; X64: # %bb.0:
; X64-NEXT: pushq %rax
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: callq *%rdi
; X64-NEXT: popq %rax
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
call void %func()
ret void
}
declare void @take_char(i8)
define void @test_abi_exts_call(i8* %addr) {
; X32-LABEL: test_abi_exts_call:
; X32: # %bb.0:
; X32-NEXT: pushl %ebx
; X32-NEXT: .cfi_def_cfa_offset 8
; X32-NEXT: pushl %esi
; X32-NEXT: .cfi_def_cfa_offset 12
; X32-NEXT: pushl %eax
; X32-NEXT: .cfi_def_cfa_offset 16
; X32-NEXT: .cfi_offset %esi, -12
; X32-NEXT: .cfi_offset %ebx, -8
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movb (%eax), %bl
; X32-NEXT: movzbl %bl, %esi
; X32-NEXT: movl %esi, (%esp)
; X32-NEXT: calll take_char
; X32-NEXT: movsbl %bl, %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll take_char
; X32-NEXT: movl %esi, (%esp)
; X32-NEXT: calll take_char
; X32-NEXT: addl $4, %esp
; X32-NEXT: .cfi_def_cfa_offset 12
; X32-NEXT: popl %esi
; X32-NEXT: .cfi_def_cfa_offset 8
; X32-NEXT: popl %ebx
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_abi_exts_call:
; X64: # %bb.0:
; X64-NEXT: pushq %rbx
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: .cfi_offset %rbx, -16
; X64-NEXT: movb (%rdi), %al
; X64-NEXT: movzbl %al, %ebx
; X64-NEXT: movl %ebx, %edi
; X64-NEXT: callq take_char
; X64-NEXT: movsbl %bl, %edi
; X64-NEXT: callq take_char
; X64-NEXT: movl %ebx, %edi
; X64-NEXT: callq take_char
; X64-NEXT: popq %rbx
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
%val = load i8, i8* %addr
call void @take_char(i8 %val)
call void @take_char(i8 signext %val)
call void @take_char(i8 zeroext %val)
ret void
}
declare void @variadic_callee(i8*, ...)
define void @test_variadic_call_1(i8** %addr_ptr, i32* %val_ptr) {
; X32-LABEL: test_variadic_call_1:
; X32: # %bb.0:
; X32-NEXT: subl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 16
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: movl (%ecx), %ecx
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: movl %ecx, {{[0-9]+}}(%esp)
; X32-NEXT: calll variadic_callee
; X32-NEXT: addl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_variadic_call_1:
; X64: # %bb.0:
; X64-NEXT: pushq %rax
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: movq (%rdi), %rdi
; X64-NEXT: movl (%rsi), %esi
; X64-NEXT: movb $0, %al
; X64-NEXT: callq variadic_callee
; X64-NEXT: popq %rax
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
%addr = load i8*, i8** %addr_ptr
%val = load i32, i32* %val_ptr
call void (i8*, ...) @variadic_callee(i8* %addr, i32 %val)
ret void
}
define void @test_variadic_call_2(i8** %addr_ptr, double* %val_ptr) {
; X32-LABEL: test_variadic_call_2:
; X32: # %bb.0:
; X32-NEXT: subl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 16
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movl {{[0-9]+}}(%esp), %ecx
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: movl (%ecx), %edx
; X32-NEXT: movl 4(%ecx), %ecx
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: movl $4, %eax
; X32-NEXT: addl %esp, %eax
; X32-NEXT: movl %edx, {{[0-9]+}}(%esp)
; X32-NEXT: movl %ecx, 4(%eax)
; X32-NEXT: calll variadic_callee
; X32-NEXT: addl $12, %esp
; X32-NEXT: .cfi_def_cfa_offset 4
; X32-NEXT: retl
;
; X64-LABEL: test_variadic_call_2:
; X64: # %bb.0:
; X64-NEXT: pushq %rax
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: movq (%rdi), %rdi
; X64-NEXT: movq (%rsi), %rax
; X64-NEXT: movq %rax, %xmm0
; X64-NEXT: movb $1, %al
; X64-NEXT: callq variadic_callee
; X64-NEXT: popq %rax
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
%addr = load i8*, i8** %addr_ptr
%val = load double, double* %val_ptr
call void (i8*, ...) @variadic_callee(i8* %addr, double %val)
ret void
}