196 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py2; RUN: llc < %s -mtriple=x86_64-unknown-unknown | 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: movslq %edi, %rax13; CHECK-NEXT: addq $12, %rax14; CHECK-NEXT: retq15 16 %add = add nsw i32 %i, 517 %ext = sext i32 %add to i6418 %idx = add i64 %ext, 719 ret i64 %idx20}21 22; An x86 bonus: If we promote the sext ahead of the 'add nsw',23; we allow LEA formation and eliminate an add instruction.24 25define i64 @add_nsw_sext_add(i32 %i, i64 %x) {26; CHECK-LABEL: add_nsw_sext_add:27; CHECK: # %bb.0:28; CHECK-NEXT: movslq %edi, %rax29; CHECK-NEXT: leaq 5(%rax,%rsi), %rax30; CHECK-NEXT: retq31 32 %add = add nsw i32 %i, 533 %ext = sext i32 %add to i6434 %idx = add i64 %x, %ext35 ret i64 %idx36}37 38; Throw in a scale (left shift) because an LEA can do that too.39; Use a negative constant (LEA displacement) to verify that's handled correctly.40 41define i64 @add_nsw_sext_lsh_add(i32 %i, i64 %x) {42; CHECK-LABEL: add_nsw_sext_lsh_add:43; CHECK: # %bb.0:44; CHECK-NEXT: movslq %edi, %rax45; CHECK-NEXT: leaq -40(%rsi,%rax,8), %rax46; CHECK-NEXT: retq47 48 %add = add nsw i32 %i, -549 %ext = sext i32 %add to i6450 %shl = shl i64 %ext, 351 %idx = add i64 %x, %shl52 ret i64 %idx53}54 55; Don't promote the sext if it has no users. The wider add instruction needs an56; extra byte to encode.57 58define i64 @add_nsw_sext(i32 %i, i64 %x) {59; CHECK-LABEL: add_nsw_sext:60; CHECK: # %bb.0:61; CHECK-NEXT: addl $5, %edi62; CHECK-NEXT: movslq %edi, %rax63; CHECK-NEXT: retq64 65 %add = add nsw i32 %i, 566 %ext = sext i32 %add to i6467 ret i64 %ext68}69 70; The typical use case: a 64-bit system where an 'int' is used as an index into an array.71 72define ptr @gep8(i32 %i, ptr %x) {73; CHECK-LABEL: gep8:74; CHECK: # %bb.0:75; CHECK-NEXT: movslq %edi, %rax76; CHECK-NEXT: leaq 5(%rax,%rsi), %rax77; CHECK-NEXT: retq78 79 %add = add nsw i32 %i, 580 %ext = sext i32 %add to i6481 %idx = getelementptr i8, ptr %x, i64 %ext82 ret ptr %idx83}84 85define ptr @gep16(i32 %i, ptr %x) {86; CHECK-LABEL: gep16:87; CHECK: # %bb.0:88; CHECK-NEXT: movslq %edi, %rax89; CHECK-NEXT: leaq -10(%rsi,%rax,2), %rax90; CHECK-NEXT: retq91 92 %add = add nsw i32 %i, -593 %ext = sext i32 %add to i6494 %idx = getelementptr i16, ptr %x, i64 %ext95 ret ptr %idx96}97 98define ptr @gep32(i32 %i, ptr %x) {99; CHECK-LABEL: gep32:100; CHECK: # %bb.0:101; CHECK-NEXT: movslq %edi, %rax102; CHECK-NEXT: leaq 20(%rsi,%rax,4), %rax103; CHECK-NEXT: retq104 105 %add = add nsw i32 %i, 5106 %ext = sext i32 %add to i64107 %idx = getelementptr i32, ptr %x, i64 %ext108 ret ptr %idx109}110 111define ptr @gep64(i32 %i, ptr %x) {112; CHECK-LABEL: gep64:113; CHECK: # %bb.0:114; CHECK-NEXT: movslq %edi, %rax115; CHECK-NEXT: leaq -40(%rsi,%rax,8), %rax116; CHECK-NEXT: retq117 118 %add = add nsw i32 %i, -5119 %ext = sext i32 %add to i64120 %idx = getelementptr i64, ptr %x, i64 %ext121 ret ptr %idx122}123 124; LEA can't scale by 16, but the adds can still be combined into an LEA.125 126define ptr @gep128(i32 %i, ptr %x) {127; CHECK-LABEL: gep128:128; CHECK: # %bb.0:129; CHECK-NEXT: movslq %edi, %rax130; CHECK-NEXT: shlq $4, %rax131; CHECK-NEXT: leaq 80(%rax,%rsi), %rax132; CHECK-NEXT: retq133 134 %add = add nsw i32 %i, 5135 %ext = sext i32 %add to i64136 %idx = getelementptr i128, ptr %x, i64 %ext137 ret ptr %idx138}139 140; A bigger win can be achieved when there is more than one use of the141; sign extended value. In this case, we can eliminate sign extension142; instructions plus use more efficient addressing modes for memory ops.143 144define void @PR20134(ptr %a, i32 %i) {145; CHECK-LABEL: PR20134:146; CHECK: # %bb.0:147; CHECK-NEXT: movslq %esi, %rax148; CHECK-NEXT: movl 4(%rdi,%rax,4), %ecx149; CHECK-NEXT: addl 8(%rdi,%rax,4), %ecx150; CHECK-NEXT: movl %ecx, (%rdi,%rax,4)151; CHECK-NEXT: retq152 153 %add1 = add nsw i32 %i, 1154 %idx1 = sext i32 %add1 to i64155 %gep1 = getelementptr i32, ptr %a, i64 %idx1156 %load1 = load i32, ptr %gep1, align 4157 158 %add2 = add nsw i32 %i, 2159 %idx2 = sext i32 %add2 to i64160 %gep2 = getelementptr i32, ptr %a, i64 %idx2161 %load2 = load i32, ptr %gep2, align 4162 163 %add3 = add i32 %load1, %load2164 %idx3 = sext i32 %i to i64165 %gep3 = getelementptr i32, ptr %a, i64 %idx3166 store i32 %add3, ptr %gep3, align 4167 ret void168}169 170; The same as @PR20134 but sign extension is replaced with zero extension171define void @PR20134_zext(ptr %a, i32 %i) {172; CHECK-LABEL: PR20134_zext:173; CHECK: # %bb.0:174; CHECK-NEXT: movl %esi, %eax175; CHECK-NEXT: movl 4(%rdi,%rax,4), %ecx176; CHECK-NEXT: addl 8(%rdi,%rax,4), %ecx177; CHECK-NEXT: movl %ecx, (%rdi,%rax,4)178; CHECK-NEXT: retq179 180 %add1 = add nuw i32 %i, 1181 %idx1 = zext i32 %add1 to i64182 %gep1 = getelementptr i32, ptr %a, i64 %idx1183 %load1 = load i32, ptr %gep1, align 4184 185 %add2 = add nuw i32 %i, 2186 %idx2 = zext i32 %add2 to i64187 %gep2 = getelementptr i32, ptr %a, i64 %idx2188 %load2 = load i32, ptr %gep2, align 4189 190 %add3 = add i32 %load1, %load2191 %idx3 = zext i32 %i to i64192 %gep3 = getelementptr i32, ptr %a, i64 %idx3193 store i32 %add3, ptr %gep3, align 4194 ret void195}196