; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-linux | FileCheck %s -check-prefix=CHECK -check-prefix=ENABLED ; RUN: llc --disable-x86-lea-opt < %s -mtriple=x86_64-linux | FileCheck %s -check-prefix=CHECK -check-prefix=DISABLED %struct.anon1 = type { i32, i32, i32 } %struct.anon2 = type { i32, [32 x i32], i32 } @arr1 = external dso_local global [65 x %struct.anon1], align 16 @arr2 = external dso_local global [65 x %struct.anon2], align 16 define void @test1(i64 %x) nounwind { ; ENABLED-LABEL: test1: ; ENABLED: # %bb.0: # %entry ; ENABLED-NEXT: shlq $2, %rdi ; ENABLED-NEXT: movl arr1(%rdi,%rdi,2), %ecx ; ENABLED-NEXT: leaq arr1+4(%rdi,%rdi,2), %rax ; ENABLED-NEXT: subl arr1+4(%rdi,%rdi,2), %ecx ; ENABLED-NEXT: addl arr1+8(%rdi,%rdi,2), %ecx ; ENABLED-NEXT: cmpl $2, %ecx ; ENABLED-NEXT: je .LBB0_3 ; ENABLED-NEXT: # %bb.1: # %entry ; ENABLED-NEXT: cmpl $1, %ecx ; ENABLED-NEXT: jne .LBB0_4 ; ENABLED-NEXT: # %bb.2: # %sw.bb.1 ; ENABLED-NEXT: movl $111, (%rax) ; ENABLED-NEXT: movl $222, 4(%rax) ; ENABLED-NEXT: retq ; ENABLED-NEXT: .LBB0_3: # %sw.bb.2 ; ENABLED-NEXT: movl $333, (%rax) # imm = 0x14D ; ENABLED-NEXT: movl $444, 4(%rax) # imm = 0x1BC ; ENABLED-NEXT: .LBB0_4: # %sw.epilog ; ENABLED-NEXT: retq ; ; DISABLED-LABEL: test1: ; DISABLED: # %bb.0: # %entry ; DISABLED-NEXT: shlq $2, %rdi ; DISABLED-NEXT: movl arr1(%rdi,%rdi,2), %edx ; DISABLED-NEXT: leaq arr1+4(%rdi,%rdi,2), %rax ; DISABLED-NEXT: subl arr1+4(%rdi,%rdi,2), %edx ; DISABLED-NEXT: leaq arr1+8(%rdi,%rdi,2), %rcx ; DISABLED-NEXT: addl arr1+8(%rdi,%rdi,2), %edx ; DISABLED-NEXT: cmpl $2, %edx ; DISABLED-NEXT: je .LBB0_3 ; DISABLED-NEXT: # %bb.1: # %entry ; DISABLED-NEXT: cmpl $1, %edx ; DISABLED-NEXT: jne .LBB0_4 ; DISABLED-NEXT: # %bb.2: # %sw.bb.1 ; DISABLED-NEXT: movl $111, (%rax) ; DISABLED-NEXT: movl $222, (%rcx) ; DISABLED-NEXT: retq ; DISABLED-NEXT: .LBB0_3: # %sw.bb.2 ; DISABLED-NEXT: movl $333, (%rax) # imm = 0x14D ; DISABLED-NEXT: movl $444, (%rcx) # imm = 0x1BC ; DISABLED-NEXT: .LBB0_4: # %sw.epilog ; DISABLED-NEXT: retq entry: %a = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 0 %tmp = load i32, i32* %a, align 4 %b = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 1 %tmp1 = load i32, i32* %b, align 4 %sub = sub i32 %tmp, %tmp1 %c = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 2 %tmp2 = load i32, i32* %c, align 4 %add = add nsw i32 %sub, %tmp2 switch i32 %add, label %sw.epilog [ i32 1, label %sw.bb.1 i32 2, label %sw.bb.2 ] sw.bb.1: ; preds = %entry store i32 111, i32* %b, align 4 store i32 222, i32* %c, align 4 br label %sw.epilog sw.bb.2: ; preds = %entry store i32 333, i32* %b, align 4 store i32 444, i32* %c, align 4 br label %sw.epilog sw.epilog: ; preds = %sw.bb.2, %sw.bb.1, %entry ret void } define void @test2(i64 %x) nounwind optsize { ; ENABLED-LABEL: test2: ; ENABLED: # %bb.0: # %entry ; ENABLED-NEXT: shlq $2, %rdi ; ENABLED-NEXT: leaq arr1+4(%rdi,%rdi,2), %rax ; ENABLED-NEXT: movl -4(%rax), %ecx ; ENABLED-NEXT: subl (%rax), %ecx ; ENABLED-NEXT: addl 4(%rax), %ecx ; ENABLED-NEXT: cmpl $2, %ecx ; ENABLED-NEXT: je .LBB1_3 ; ENABLED-NEXT: # %bb.1: # %entry ; ENABLED-NEXT: cmpl $1, %ecx ; ENABLED-NEXT: jne .LBB1_4 ; ENABLED-NEXT: # %bb.2: # %sw.bb.1 ; ENABLED-NEXT: movl $111, (%rax) ; ENABLED-NEXT: movl $222, 4(%rax) ; ENABLED-NEXT: retq ; ENABLED-NEXT: .LBB1_3: # %sw.bb.2 ; ENABLED-NEXT: movl $333, (%rax) # imm = 0x14D ; ENABLED-NEXT: movl $444, 4(%rax) # imm = 0x1BC ; ENABLED-NEXT: .LBB1_4: # %sw.epilog ; ENABLED-NEXT: retq ; ; DISABLED-LABEL: test2: ; DISABLED: # %bb.0: # %entry ; DISABLED-NEXT: shlq $2, %rdi ; DISABLED-NEXT: movl arr1(%rdi,%rdi,2), %edx ; DISABLED-NEXT: leaq arr1+4(%rdi,%rdi,2), %rax ; DISABLED-NEXT: subl arr1+4(%rdi,%rdi,2), %edx ; DISABLED-NEXT: leaq arr1+8(%rdi,%rdi,2), %rcx ; DISABLED-NEXT: addl arr1+8(%rdi,%rdi,2), %edx ; DISABLED-NEXT: cmpl $2, %edx ; DISABLED-NEXT: je .LBB1_3 ; DISABLED-NEXT: # %bb.1: # %entry ; DISABLED-NEXT: cmpl $1, %edx ; DISABLED-NEXT: jne .LBB1_4 ; DISABLED-NEXT: # %bb.2: # %sw.bb.1 ; DISABLED-NEXT: movl $111, (%rax) ; DISABLED-NEXT: movl $222, (%rcx) ; DISABLED-NEXT: retq ; DISABLED-NEXT: .LBB1_3: # %sw.bb.2 ; DISABLED-NEXT: movl $333, (%rax) # imm = 0x14D ; DISABLED-NEXT: movl $444, (%rcx) # imm = 0x1BC ; DISABLED-NEXT: .LBB1_4: # %sw.epilog ; DISABLED-NEXT: retq entry: %a = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 0 %tmp = load i32, i32* %a, align 4 %b = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 1 %tmp1 = load i32, i32* %b, align 4 %sub = sub i32 %tmp, %tmp1 %c = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 2 %tmp2 = load i32, i32* %c, align 4 %add = add nsw i32 %sub, %tmp2 switch i32 %add, label %sw.epilog [ i32 1, label %sw.bb.1 i32 2, label %sw.bb.2 ] sw.bb.1: ; preds = %entry store i32 111, i32* %b, align 4 store i32 222, i32* %c, align 4 br label %sw.epilog sw.bb.2: ; preds = %entry store i32 333, i32* %b, align 4 store i32 444, i32* %c, align 4 br label %sw.epilog sw.epilog: ; preds = %sw.bb.2, %sw.bb.1, %entry ret void } ; Check that LEA optimization pass takes into account a resultant address ; displacement when choosing a LEA instruction for replacing a redundant ; address recalculation. define void @test3(i64 %x) nounwind optsize { ; ENABLED-LABEL: test3: ; ENABLED: # %bb.0: # %entry ; ENABLED-NEXT: movq %rdi, %rax ; ENABLED-NEXT: shlq $7, %rax ; ENABLED-NEXT: leaq arr2+132(%rax,%rdi,8), %rcx ; ENABLED-NEXT: leaq arr2(%rax,%rdi,8), %rax ; ENABLED-NEXT: movl (%rcx), %edx ; ENABLED-NEXT: addl (%rax), %edx ; ENABLED-NEXT: cmpl $2, %edx ; ENABLED-NEXT: je .LBB2_3 ; ENABLED-NEXT: # %bb.1: # %entry ; ENABLED-NEXT: cmpl $1, %edx ; ENABLED-NEXT: jne .LBB2_4 ; ENABLED-NEXT: # %bb.2: # %sw.bb.1 ; ENABLED-NEXT: movl $111, (%rcx) ; ENABLED-NEXT: movl $222, (%rax) ; ENABLED-NEXT: retq ; ENABLED-NEXT: .LBB2_3: # %sw.bb.2 ; ENABLED-NEXT: movl $333, (%rcx) # imm = 0x14D ; ENABLED-NEXT: movl %eax, (%rax) ; ENABLED-NEXT: .LBB2_4: # %sw.epilog ; ENABLED-NEXT: retq ; ; DISABLED-LABEL: test3: ; DISABLED: # %bb.0: # %entry ; DISABLED-NEXT: movq %rdi, %rsi ; DISABLED-NEXT: shlq $7, %rsi ; DISABLED-NEXT: leaq arr2+132(%rsi,%rdi,8), %rcx ; DISABLED-NEXT: leaq arr2(%rsi,%rdi,8), %rax ; DISABLED-NEXT: movl arr2+132(%rsi,%rdi,8), %edx ; DISABLED-NEXT: addl arr2(%rsi,%rdi,8), %edx ; DISABLED-NEXT: cmpl $2, %edx ; DISABLED-NEXT: je .LBB2_3 ; DISABLED-NEXT: # %bb.1: # %entry ; DISABLED-NEXT: cmpl $1, %edx ; DISABLED-NEXT: jne .LBB2_4 ; DISABLED-NEXT: # %bb.2: # %sw.bb.1 ; DISABLED-NEXT: movl $111, (%rcx) ; DISABLED-NEXT: movl $222, (%rax) ; DISABLED-NEXT: retq ; DISABLED-NEXT: .LBB2_3: # %sw.bb.2 ; DISABLED-NEXT: movl $333, (%rcx) # imm = 0x14D ; DISABLED-NEXT: movl %eax, (%rax) ; DISABLED-NEXT: .LBB2_4: # %sw.epilog ; DISABLED-NEXT: retq entry: %a = getelementptr inbounds [65 x %struct.anon2], [65 x %struct.anon2]* @arr2, i64 0, i64 %x, i32 2 %tmp = load i32, i32* %a, align 4 %b = getelementptr inbounds [65 x %struct.anon2], [65 x %struct.anon2]* @arr2, i64 0, i64 %x, i32 0 %tmp1 = load i32, i32* %b, align 4 %add = add nsw i32 %tmp, %tmp1 switch i32 %add, label %sw.epilog [ i32 1, label %sw.bb.1 i32 2, label %sw.bb.2 ] sw.bb.1: ; preds = %entry store i32 111, i32* %a, align 4 store i32 222, i32* %b, align 4 br label %sw.epilog sw.bb.2: ; preds = %entry store i32 333, i32* %a, align 4 ; Make sure the REG3's definition LEA won't be removed as redundant. %cvt = ptrtoint i32* %b to i32 store i32 %cvt, i32* %b, align 4 br label %sw.epilog sw.epilog: ; preds = %sw.bb.2, %sw.bb.1, %entry ret void ; REG3's definition is closer to movl than REG2's, but the pass still chooses ; REG2 because it provides the resultant address displacement fitting 1 byte. } define void @test4(i64 %x) nounwind minsize { ; ENABLED-LABEL: test4: ; ENABLED: # %bb.0: # %entry ; ENABLED-NEXT: imulq $12, %rdi, %rax ; ENABLED-NEXT: leaq arr1+4(%rax), %rax ; ENABLED-NEXT: movl -4(%rax), %ecx ; ENABLED-NEXT: subl (%rax), %ecx ; ENABLED-NEXT: addl 4(%rax), %ecx ; ENABLED-NEXT: cmpl $2, %ecx ; ENABLED-NEXT: je .LBB3_3 ; ENABLED-NEXT: # %bb.1: # %entry ; ENABLED-NEXT: cmpl $1, %ecx ; ENABLED-NEXT: jne .LBB3_4 ; ENABLED-NEXT: # %bb.2: # %sw.bb.1 ; ENABLED-NEXT: movl $111, (%rax) ; ENABLED-NEXT: movl $222, 4(%rax) ; ENABLED-NEXT: retq ; ENABLED-NEXT: .LBB3_3: # %sw.bb.2 ; ENABLED-NEXT: movl $333, (%rax) # imm = 0x14D ; ENABLED-NEXT: movl $444, 4(%rax) # imm = 0x1BC ; ENABLED-NEXT: .LBB3_4: # %sw.epilog ; ENABLED-NEXT: retq ; ; DISABLED-LABEL: test4: ; DISABLED: # %bb.0: # %entry ; DISABLED-NEXT: imulq $12, %rdi, %rsi ; DISABLED-NEXT: movl arr1(%rsi), %edx ; DISABLED-NEXT: leaq arr1+4(%rsi), %rax ; DISABLED-NEXT: subl arr1+4(%rsi), %edx ; DISABLED-NEXT: leaq arr1+8(%rsi), %rcx ; DISABLED-NEXT: addl arr1+8(%rsi), %edx ; DISABLED-NEXT: cmpl $2, %edx ; DISABLED-NEXT: je .LBB3_3 ; DISABLED-NEXT: # %bb.1: # %entry ; DISABLED-NEXT: cmpl $1, %edx ; DISABLED-NEXT: jne .LBB3_4 ; DISABLED-NEXT: # %bb.2: # %sw.bb.1 ; DISABLED-NEXT: movl $111, (%rax) ; DISABLED-NEXT: movl $222, (%rcx) ; DISABLED-NEXT: retq ; DISABLED-NEXT: .LBB3_3: # %sw.bb.2 ; DISABLED-NEXT: movl $333, (%rax) # imm = 0x14D ; DISABLED-NEXT: movl $444, (%rcx) # imm = 0x1BC ; DISABLED-NEXT: .LBB3_4: # %sw.epilog ; DISABLED-NEXT: retq entry: %a = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 0 %tmp = load i32, i32* %a, align 4 %b = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 1 %tmp1 = load i32, i32* %b, align 4 %sub = sub i32 %tmp, %tmp1 %c = getelementptr inbounds [65 x %struct.anon1], [65 x %struct.anon1]* @arr1, i64 0, i64 %x, i32 2 %tmp2 = load i32, i32* %c, align 4 %add = add nsw i32 %sub, %tmp2 switch i32 %add, label %sw.epilog [ i32 1, label %sw.bb.1 i32 2, label %sw.bb.2 ] sw.bb.1: ; preds = %entry store i32 111, i32* %b, align 4 store i32 222, i32* %c, align 4 br label %sw.epilog sw.bb.2: ; preds = %entry store i32 333, i32* %b, align 4 store i32 444, i32* %c, align 4 br label %sw.epilog sw.epilog: ; preds = %sw.bb.2, %sw.bb.1, %entry ret void } define i32 @test5(i32 %x, i32 %y) #0 { ; CHECK-LABEL: test5: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: addl %esi, %esi ; CHECK-NEXT: subl %esi, %eax ; CHECK-NEXT: retq entry: %mul = mul nsw i32 %y, -2 %add = add nsw i32 %mul, %x ret i32 %add } define i32 @test6(i32 %x, i32 %y) #0 { ; CHECK-LABEL: test6: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: # kill: def $esi killed $esi def $rsi ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: leal (%rsi,%rsi,2), %ecx ; CHECK-NEXT: subl %ecx, %eax ; CHECK-NEXT: retq entry: %mul = mul nsw i32 %y, -3 %add = add nsw i32 %mul, %x ret i32 %add } define i32 @test7(i32 %x, i32 %y) #0 { ; CHECK-LABEL: test7: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: shll $2, %esi ; CHECK-NEXT: subl %esi, %eax ; CHECK-NEXT: retq entry: %mul = mul nsw i32 %y, -4 %add = add nsw i32 %mul, %x ret i32 %add } define i32 @test8(i32 %x, i32 %y) #0 { ; CHECK-LABEL: test8: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: # kill: def $esi killed $esi def $rsi ; CHECK-NEXT: leal (,%rsi,4), %eax ; CHECK-NEXT: subl %edi, %eax ; CHECK-NEXT: retq entry: %mul = shl nsw i32 %y, 2 %sub = sub nsw i32 %mul, %x ret i32 %sub } define i32 @test9(i32 %x, i32 %y) #0 { ; CHECK-LABEL: test9: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: addl %esi, %esi ; CHECK-NEXT: subl %esi, %eax ; CHECK-NEXT: retq entry: %mul = mul nsw i32 -2, %y %add = add nsw i32 %x, %mul ret i32 %add } define i32 @test10(i32 %x, i32 %y) #0 { ; CHECK-LABEL: test10: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: # kill: def $esi killed $esi def $rsi ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: leal (%rsi,%rsi,2), %ecx ; CHECK-NEXT: subl %ecx, %eax ; CHECK-NEXT: retq entry: %mul = mul nsw i32 -3, %y %add = add nsw i32 %x, %mul ret i32 %add } define i32 @test11(i32 %x, i32 %y) #0 { ; CHECK-LABEL: test11: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: shll $2, %esi ; CHECK-NEXT: subl %esi, %eax ; CHECK-NEXT: retq entry: %mul = mul nsw i32 -4, %y %add = add nsw i32 %x, %mul ret i32 %add } define i32 @test12(i32 %x, i32 %y) #0 { ; CHECK-LABEL: test12: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: # kill: def $esi killed $esi def $rsi ; CHECK-NEXT: leal (,%rsi,4), %eax ; CHECK-NEXT: subl %edi, %eax ; CHECK-NEXT: retq entry: %mul = mul nsw i32 4, %y %sub = sub nsw i32 %mul, %x ret i32 %sub } define i64 @test13(i64 %x, i64 %y) #0 { ; CHECK-LABEL: test13: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: movq %rdi, %rax ; CHECK-NEXT: shlq $2, %rsi ; CHECK-NEXT: subq %rsi, %rax ; CHECK-NEXT: retq entry: %mul = mul nsw i64 -4, %y %add = add nsw i64 %x, %mul ret i64 %add } define i32 @test14(i32 %x, i32 %y) #0 { ; CHECK-LABEL: test14: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: # kill: def $esi killed $esi def $rsi ; CHECK-NEXT: leal (,%rsi,4), %eax ; CHECK-NEXT: subl %edi, %eax ; CHECK-NEXT: retq entry: %mul = mul nsw i32 4, %y %sub = sub nsw i32 %mul, %x ret i32 %sub } define zeroext i16 @test15(i16 zeroext %x, i16 zeroext %y) #0 { ; CHECK-LABEL: test15: ; CHECK: # %bb.0: # %entry ; CHECK-NEXT: movl %edi, %eax ; CHECK-NEXT: shll $3, %esi ; CHECK-NEXT: subl %esi, %eax ; CHECK-NEXT: # kill: def $ax killed $ax killed $eax ; CHECK-NEXT: retq entry: %conv = zext i16 %x to i32 %conv1 = zext i16 %y to i32 %mul = mul nsw i32 -8, %conv1 %add = add nsw i32 %conv, %mul %conv2 = trunc i32 %add to i16 ret i16 %conv2 } attributes #0 = { norecurse nounwind optsize readnone uwtable}