230 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc < %s -mtriple=x86_64-unknown-unknown -global-isel | FileCheck %s3 4; The fundamental problem: an add separated from other arithmetic by a sign or5; zero extension can't be combined with the later instructions. However, if the6; first add is 'nsw' or 'nuw' respectively, then we can promote the extension7; ahead of that add to allow optimizations.8 9define i64 @add_nsw_consts(i32 %i) {10; CHECK-LABEL: add_nsw_consts:11; CHECK: # %bb.0:12; CHECK-NEXT: addl $5, %edi13; CHECK-NEXT: movslq %edi, %rax14; CHECK-NEXT: addq $7, %rax15; CHECK-NEXT: retq16 17 %add = add nsw i32 %i, 518 %ext = sext i32 %add to i6419 %idx = add i64 %ext, 720 ret i64 %idx21}22 23; An x86 bonus: If we promote the sext ahead of the 'add nsw',24; we allow LEA formation and eliminate an add instruction.25 26define i64 @add_nsw_sext_add(i32 %i, i64 %x) {27; CHECK-LABEL: add_nsw_sext_add:28; CHECK: # %bb.0:29; CHECK-NEXT: addl $5, %edi30; CHECK-NEXT: movslq %edi, %rax31; CHECK-NEXT: addq %rsi, %rax32; CHECK-NEXT: retq33 34 %add = add nsw i32 %i, 535 %ext = sext i32 %add to i6436 %idx = add i64 %x, %ext37 ret i64 %idx38}39 40; Throw in a scale (left shift) because an LEA can do that too.41; Use a negative constant (LEA displacement) to verify that's handled correctly.42 43define i64 @add_nsw_sext_lsh_add(i32 %i, i64 %x) {44; CHECK-LABEL: add_nsw_sext_lsh_add:45; CHECK: # %bb.0:46; CHECK-NEXT: addl $-5, %edi47; CHECK-NEXT: movslq %edi, %rax48; CHECK-NEXT: shlq $3, %rax49; CHECK-NEXT: addq %rsi, %rax50; CHECK-NEXT: retq51 52 %add = add nsw i32 %i, -553 %ext = sext i32 %add to i6454 %shl = shl i64 %ext, 355 %idx = add i64 %x, %shl56 ret i64 %idx57}58 59; Don't promote the sext if it has no users. The wider add instruction needs an60; extra byte to encode.61 62define i64 @add_nsw_sext(i32 %i, i64 %x) {63; CHECK-LABEL: add_nsw_sext:64; CHECK: # %bb.0:65; CHECK-NEXT: addl $5, %edi66; CHECK-NEXT: movslq %edi, %rax67; CHECK-NEXT: retq68 69 %add = add nsw i32 %i, 570 %ext = sext i32 %add to i6471 ret i64 %ext72}73 74; The typical use case: a 64-bit system where an 'int' is used as an index into an array.75 76define ptr @gep8(i32 %i, ptr %x) {77; CHECK-LABEL: gep8:78; CHECK: # %bb.0:79; CHECK-NEXT: addl $5, %edi80; CHECK-NEXT: movslq %edi, %rax81; CHECK-NEXT: addq %rsi, %rax82; CHECK-NEXT: retq83 84 %add = add nsw i32 %i, 585 %ext = sext i32 %add to i6486 %idx = getelementptr i8, ptr %x, i64 %ext87 ret ptr %idx88}89 90define ptr @gep16(i32 %i, ptr %x) {91; CHECK-LABEL: gep16:92; CHECK: # %bb.0:93; CHECK-NEXT: addl $-5, %edi94; CHECK-NEXT: movslq %edi, %rax95; CHECK-NEXT: imulq $2, %rax, %rax96; CHECK-NEXT: addq %rsi, %rax97; CHECK-NEXT: retq98 99 %add = add nsw i32 %i, -5100 %ext = sext i32 %add to i64101 %idx = getelementptr i16, ptr %x, i64 %ext102 ret ptr %idx103}104 105define ptr @gep32(i32 %i, ptr %x) {106; CHECK-LABEL: gep32:107; CHECK: # %bb.0:108; CHECK-NEXT: addl $5, %edi109; CHECK-NEXT: movslq %edi, %rax110; CHECK-NEXT: imulq $4, %rax, %rax111; CHECK-NEXT: addq %rsi, %rax112; CHECK-NEXT: retq113 114 %add = add nsw i32 %i, 5115 %ext = sext i32 %add to i64116 %idx = getelementptr i32, ptr %x, i64 %ext117 ret ptr %idx118}119 120define ptr @gep64(i32 %i, ptr %x) {121; CHECK-LABEL: gep64:122; CHECK: # %bb.0:123; CHECK-NEXT: addl $-5, %edi124; CHECK-NEXT: movslq %edi, %rax125; CHECK-NEXT: imulq $8, %rax, %rax126; CHECK-NEXT: addq %rsi, %rax127; CHECK-NEXT: retq128 129 %add = add nsw i32 %i, -5130 %ext = sext i32 %add to i64131 %idx = getelementptr i64, ptr %x, i64 %ext132 ret ptr %idx133}134 135; LEA can't scale by 16, but the adds can still be combined into an LEA.136 137define ptr @gep128(i32 %i, ptr %x) {138; CHECK-LABEL: gep128:139; CHECK: # %bb.0:140; CHECK-NEXT: addl $5, %edi141; CHECK-NEXT: movslq %edi, %rax142; CHECK-NEXT: imulq $16, %rax, %rax143; CHECK-NEXT: addq %rsi, %rax144; CHECK-NEXT: retq145 146 %add = add nsw i32 %i, 5147 %ext = sext i32 %add to i64148 %idx = getelementptr i128, ptr %x, i64 %ext149 ret ptr %idx150}151 152; A bigger win can be achieved when there is more than one use of the153; sign extended value. In this case, we can eliminate sign extension154; instructions plus use more efficient addressing modes for memory ops.155 156define void @PR20134(ptr %a, i32 %i) {157; CHECK-LABEL: PR20134:158; CHECK: # %bb.0:159; CHECK-NEXT: # kill: def $esi killed $esi def $rsi160; CHECK-NEXT: leal 1(%rsi), %eax161; CHECK-NEXT: cltq162; CHECK-NEXT: imulq $4, %rax, %rax163; CHECK-NEXT: addq %rdi, %rax164; CHECK-NEXT: leal 2(%rsi), %ecx165; CHECK-NEXT: movslq %ecx, %rcx166; CHECK-NEXT: imulq $4, %rcx, %rcx167; CHECK-NEXT: addq %rdi, %rcx168; CHECK-NEXT: movl (%rcx), %ecx169; CHECK-NEXT: addl (%rax), %ecx170; CHECK-NEXT: movslq %esi, %rax171; CHECK-NEXT: imulq $4, %rax, %rax172; CHECK-NEXT: addq %rdi, %rax173; CHECK-NEXT: movl %ecx, (%rax)174; CHECK-NEXT: retq175 176 %add1 = add nsw i32 %i, 1177 %idx1 = sext i32 %add1 to i64178 %gep1 = getelementptr i32, ptr %a, i64 %idx1179 %load1 = load i32, ptr %gep1, align 4180 181 %add2 = add nsw i32 %i, 2182 %idx2 = sext i32 %add2 to i64183 %gep2 = getelementptr i32, ptr %a, i64 %idx2184 %load2 = load i32, ptr %gep2, align 4185 186 %add3 = add i32 %load1, %load2187 %idx3 = sext i32 %i to i64188 %gep3 = getelementptr i32, ptr %a, i64 %idx3189 store i32 %add3, ptr %gep3, align 4190 ret void191}192 193; The same as @PR20134 but sign extension is replaced with zero extension194define void @PR20134_zext(ptr %a, i32 %i) {195; CHECK-LABEL: PR20134_zext:196; CHECK: # %bb.0:197; CHECK-NEXT: # kill: def $esi killed $esi def $rsi198; CHECK-NEXT: leal 1(%rsi), %eax199; CHECK-NEXT: movl %eax, %eax200; CHECK-NEXT: imulq $4, %rax, %rax201; CHECK-NEXT: addq %rdi, %rax202; CHECK-NEXT: leal 2(%rsi), %ecx203; CHECK-NEXT: movl %ecx, %ecx204; CHECK-NEXT: imulq $4, %rcx, %rcx205; CHECK-NEXT: addq %rdi, %rcx206; CHECK-NEXT: movl (%rcx), %ecx207; CHECK-NEXT: addl (%rax), %ecx208; CHECK-NEXT: movl %esi, %eax209; CHECK-NEXT: imulq $4, %rax, %rax210; CHECK-NEXT: addq %rdi, %rax211; CHECK-NEXT: movl %ecx, (%rax)212; CHECK-NEXT: retq213 214 %add1 = add nuw i32 %i, 1215 %idx1 = zext i32 %add1 to i64216 %gep1 = getelementptr i32, ptr %a, i64 %idx1217 %load1 = load i32, ptr %gep1, align 4218 219 %add2 = add nuw i32 %i, 2220 %idx2 = zext i32 %add2 to i64221 %gep2 = getelementptr i32, ptr %a, i64 %idx2222 %load2 = load i32, ptr %gep2, align 4223 224 %add3 = add i32 %load1, %load2225 %idx3 = zext i32 %i to i64226 %gep3 = getelementptr i32, ptr %a, i64 %idx3227 store i32 %add3, ptr %gep3, align 4228 ret void229}230