• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2; RUN: llc < %s -mtriple=x86_64-unknown-unknown -global-isel | FileCheck %s
3
4; The fundamental problem: an add separated from other arithmetic by a sign or
5; zero extension can't be combined with the later instructions. However, if the
6; first add is 'nsw' or 'nuw' respectively, then we can promote the extension
7; 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, %edi
13; CHECK-NEXT:    movslq %edi, %rax
14; CHECK-NEXT:    addq $7, %rax
15; CHECK-NEXT:    retq
16
17  %add = add nsw i32 %i, 5
18  %ext = sext i32 %add to i64
19  %idx = add i64 %ext, 7
20  ret i64 %idx
21}
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, %edi
30; CHECK-NEXT:    movslq %edi, %rax
31; CHECK-NEXT:    addq %rsi, %rax
32; CHECK-NEXT:    retq
33
34  %add = add nsw i32 %i, 5
35  %ext = sext i32 %add to i64
36  %idx = add i64 %x, %ext
37  ret i64 %idx
38}
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, %edi
47; CHECK-NEXT:    movslq %edi, %rax
48; CHECK-NEXT:    shlq $3, %rax
49; CHECK-NEXT:    addq %rsi, %rax
50; CHECK-NEXT:    retq
51
52  %add = add nsw i32 %i, -5
53  %ext = sext i32 %add to i64
54  %shl = shl i64 %ext, 3
55  %idx = add i64 %x, %shl
56  ret i64 %idx
57}
58
59; Don't promote the sext if it has no users. The wider add instruction needs an
60; 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, %edi
66; CHECK-NEXT:    movslq %edi, %rax
67; CHECK-NEXT:    retq
68
69  %add = add nsw i32 %i, 5
70  %ext = sext i32 %add to i64
71  ret i64 %ext
72}
73
74; The typical use case: a 64-bit system where an 'int' is used as an index into an array.
75
76define i8* @gep8(i32 %i, i8* %x) {
77; CHECK-LABEL: gep8:
78; CHECK:       # %bb.0:
79; CHECK-NEXT:    addl $5, %edi
80; CHECK-NEXT:    movslq %edi, %rax
81; CHECK-NEXT:    addq %rsi, %rax
82; CHECK-NEXT:    retq
83
84  %add = add nsw i32 %i, 5
85  %ext = sext i32 %add to i64
86  %idx = getelementptr i8, i8* %x, i64 %ext
87  ret i8* %idx
88}
89
90define i16* @gep16(i32 %i, i16* %x) {
91; CHECK-LABEL: gep16:
92; CHECK:       # %bb.0:
93; CHECK-NEXT:    addl $-5, %edi
94; CHECK-NEXT:    movslq %edi, %rax
95; CHECK-NEXT:    imulq $2, %rax, %rax
96; CHECK-NEXT:    addq %rsi, %rax
97; CHECK-NEXT:    retq
98
99  %add = add nsw i32 %i, -5
100  %ext = sext i32 %add to i64
101  %idx = getelementptr i16, i16* %x, i64 %ext
102  ret i16* %idx
103}
104
105define i32* @gep32(i32 %i, i32* %x) {
106; CHECK-LABEL: gep32:
107; CHECK:       # %bb.0:
108; CHECK-NEXT:    addl $5, %edi
109; CHECK-NEXT:    movslq %edi, %rax
110; CHECK-NEXT:    imulq $4, %rax, %rax
111; CHECK-NEXT:    addq %rsi, %rax
112; CHECK-NEXT:    retq
113
114  %add = add nsw i32 %i, 5
115  %ext = sext i32 %add to i64
116  %idx = getelementptr i32, i32* %x, i64 %ext
117  ret i32* %idx
118}
119
120define i64* @gep64(i32 %i, i64* %x) {
121; CHECK-LABEL: gep64:
122; CHECK:       # %bb.0:
123; CHECK-NEXT:    addl $-5, %edi
124; CHECK-NEXT:    movslq %edi, %rax
125; CHECK-NEXT:    imulq $8, %rax, %rax
126; CHECK-NEXT:    addq %rsi, %rax
127; CHECK-NEXT:    retq
128
129  %add = add nsw i32 %i, -5
130  %ext = sext i32 %add to i64
131  %idx = getelementptr i64, i64* %x, i64 %ext
132  ret i64* %idx
133}
134
135; LEA can't scale by 16, but the adds can still be combined into an LEA.
136
137define i128* @gep128(i32 %i, i128* %x) {
138; CHECK-LABEL: gep128:
139; CHECK:       # %bb.0:
140; CHECK-NEXT:    addl $5, %edi
141; CHECK-NEXT:    movslq %edi, %rax
142; CHECK-NEXT:    imulq $16, %rax, %rax
143; CHECK-NEXT:    addq %rsi, %rax
144; CHECK-NEXT:    retq
145
146  %add = add nsw i32 %i, 5
147  %ext = sext i32 %add to i64
148  %idx = getelementptr i128, i128* %x, i64 %ext
149  ret i128* %idx
150}
151
152; A bigger win can be achieved when there is more than one use of the
153; sign extended value. In this case, we can eliminate sign extension
154; instructions plus use more efficient addressing modes for memory ops.
155
156define void @PR20134(i32* %a, i32 %i) {
157; CHECK-LABEL: PR20134:
158; CHECK:       # %bb.0:
159; CHECK-NEXT:    # kill: def $esi killed $esi def $rsi
160; CHECK-NEXT:    leal 1(%rsi), %eax
161; CHECK-NEXT:    cltq
162; CHECK-NEXT:    imulq $4, %rax, %rax
163; CHECK-NEXT:    addq %rdi, %rax
164; CHECK-NEXT:    leal 2(%rsi), %ecx
165; CHECK-NEXT:    movslq %ecx, %rcx
166; CHECK-NEXT:    imulq $4, %rcx, %rcx
167; CHECK-NEXT:    addq %rdi, %rcx
168; CHECK-NEXT:    movl (%rcx), %ecx
169; CHECK-NEXT:    addl (%rax), %ecx
170; CHECK-NEXT:    movslq %esi, %rax
171; CHECK-NEXT:    imulq $4, %rax, %rax
172; CHECK-NEXT:    addq %rdi, %rax
173; CHECK-NEXT:    movl %ecx, (%rax)
174; CHECK-NEXT:    retq
175
176  %add1 = add nsw i32 %i, 1
177  %idx1 = sext i32 %add1 to i64
178  %gep1 = getelementptr i32, i32* %a, i64 %idx1
179  %load1 = load i32, i32* %gep1, align 4
180
181  %add2 = add nsw i32 %i, 2
182  %idx2 = sext i32 %add2 to i64
183  %gep2 = getelementptr i32, i32* %a, i64 %idx2
184  %load2 = load i32, i32* %gep2, align 4
185
186  %add3 = add i32 %load1, %load2
187  %idx3 = sext i32 %i to i64
188  %gep3 = getelementptr i32, i32* %a, i64 %idx3
189  store i32 %add3, i32* %gep3, align 4
190  ret void
191}
192
193; The same as @PR20134 but sign extension is replaced with zero extension
194define void @PR20134_zext(i32* %a, i32 %i) {
195; CHECK-LABEL: PR20134_zext:
196; CHECK:       # %bb.0:
197; CHECK-NEXT:    # kill: def $esi killed $esi def $rsi
198; CHECK-NEXT:    leal 1(%rsi), %eax
199; CHECK-NEXT:    movl %eax, %eax
200; CHECK-NEXT:    imulq $4, %rax, %rax
201; CHECK-NEXT:    addq %rdi, %rax
202; CHECK-NEXT:    leal 2(%rsi), %ecx
203; CHECK-NEXT:    movl %ecx, %ecx
204; CHECK-NEXT:    imulq $4, %rcx, %rcx
205; CHECK-NEXT:    addq %rdi, %rcx
206; CHECK-NEXT:    movl (%rcx), %ecx
207; CHECK-NEXT:    addl (%rax), %ecx
208; CHECK-NEXT:    movl %esi, %eax
209; CHECK-NEXT:    imulq $4, %rax, %rax
210; CHECK-NEXT:    addq %rdi, %rax
211; CHECK-NEXT:    movl %ecx, (%rax)
212; CHECK-NEXT:    retq
213
214  %add1 = add nuw i32 %i, 1
215  %idx1 = zext i32 %add1 to i64
216  %gep1 = getelementptr i32, i32* %a, i64 %idx1
217  %load1 = load i32, i32* %gep1, align 4
218
219  %add2 = add nuw i32 %i, 2
220  %idx2 = zext i32 %add2 to i64
221  %gep2 = getelementptr i32, i32* %a, i64 %idx2
222  %load2 = load i32, i32* %gep2, align 4
223
224  %add3 = add i32 %load1, %load2
225  %idx3 = zext i32 %i to i64
226  %gep3 = getelementptr i32, i32* %a, i64 %idx3
227  store i32 %add3, i32* %gep3, align 4
228  ret void
229}
230