1; RUN: opt -S -codegenprepare %s -o - | FileCheck %s
2; This file tests the different cases what are involved when codegen prepare
3; tries to get sign extension out of the way of addressing mode.
4; This tests require an actual target as addressing mode decisions depends
5; on the target.
6
7target datalayout = "e-i64:64-f80:128-s:64-n8:16:32:64-S128"
8target triple = "x86_64-apple-macosx"
9
10
11; Check that we correctly promote both operands of the promotable add.
12; CHECK-LABEL: @twoArgsPromotion
13; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i32 %arg1 to i64
14; CHECK: [[ARG2SEXT:%[a-zA-Z_0-9-]+]] = sext i32 %arg2 to i64
15; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], [[ARG2SEXT]]
16; CHECK: inttoptr i64 [[PROMOTED]] to i8*
17; CHECK: ret
18define i8 @twoArgsPromotion(i32 %arg1, i32 %arg2) {
19  %add = add nsw i32 %arg1, %arg2
20  %sextadd = sext i32 %add to i64
21  %base = inttoptr i64 %sextadd to i8*
22  %res = load i8* %base
23  ret i8 %res
24}
25
26; Check that we do not promote both operands of the promotable add when
27; the instruction will not be folded into the addressing mode.
28; Otherwise, we will increase the number of instruction executed.
29; (This is a heuristic of course, because the new sext could have been
30; merged with something else.)
31; CHECK-LABEL: @twoArgsNoPromotion
32; CHECK: add nsw i32 %arg1, %arg2
33; CHECK: ret
34define i8 @twoArgsNoPromotion(i32 %arg1, i32 %arg2, i8* %base) {
35  %add = add nsw i32 %arg1, %arg2
36  %sextadd = sext i32 %add to i64
37  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
38  %res = load i8* %arrayidx
39  ret i8 %res
40}
41
42; Check that we do not promote when the related instruction does not have
43; the nsw flag.
44; CHECK-LABEL: @noPromotion
45; CHECK-NOT: add i64
46; CHECK: ret
47define i8 @noPromotion(i32 %arg1, i32 %arg2, i8* %base) {
48  %add = add i32 %arg1, %arg2
49  %sextadd = sext i32 %add to i64
50  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
51  %res = load i8* %arrayidx
52  ret i8 %res
53}
54
55; Check that we correctly promote constant arguments.
56; CHECK-LABEL: @oneArgPromotion
57; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i32 %arg1 to i64
58; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
59; CHECK: getelementptr inbounds i8* %base, i64 [[PROMOTED]]
60; CHECK: ret
61define i8 @oneArgPromotion(i32 %arg1, i8* %base) {
62  %add = add nsw i32 %arg1, 1
63  %sextadd = sext i32 %add to i64
64  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
65  %res = load i8* %arrayidx
66  ret i8 %res
67}
68
69; Check that we do not promote truncate when we cannot determine the
70; bits that are dropped.
71; CHECK-LABEL: @oneArgPromotionBlockTrunc1
72; CHECK: [[ARG1TRUNC:%[a-zA-Z_0-9-]+]] = trunc i32 %arg1 to i8
73; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i8 [[ARG1TRUNC]] to i64
74; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
75; CHECK: getelementptr inbounds i8* %base, i64 [[PROMOTED]]
76; CHECK: ret
77define i8 @oneArgPromotionBlockTrunc1(i32 %arg1, i8* %base) {
78  %trunc = trunc i32 %arg1 to i8
79  %add = add nsw i8 %trunc, 1
80  %sextadd = sext i8 %add to i64
81  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
82  %res = load i8* %arrayidx
83  ret i8 %res
84}
85
86; Check that we do not promote truncate when we cannot determine all the
87; bits that are dropped.
88; CHECK-LABEL: @oneArgPromotionBlockTrunc2
89; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i16 %arg1 to i32
90; CHECK: [[ARG1TRUNC:%[a-zA-Z_0-9-]+]] = trunc i32 [[ARG1SEXT]] to i8
91; CHECK: [[ARG1SEXT64:%[a-zA-Z_0-9-]+]] = sext i8 [[ARG1TRUNC]] to i64
92; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT64]], 1
93; CHECK: getelementptr inbounds i8* %base, i64 [[PROMOTED]]
94; CHECK: ret
95define i8 @oneArgPromotionBlockTrunc2(i16 %arg1, i8* %base) {
96  %sextarg1 = sext i16 %arg1 to i32
97  %trunc = trunc i32 %sextarg1 to i8
98  %add = add nsw i8 %trunc, 1
99  %sextadd = sext i8 %add to i64
100  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
101  %res = load i8* %arrayidx
102  ret i8 %res
103}
104
105; Check that we are able to promote truncate when we know all the bits
106; that are dropped.
107; CHECK-LABEL: @oneArgPromotionPassTruncKeepSExt
108; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i1 %arg1 to i64
109; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
110; CHECK: getelementptr inbounds i8* %base, i64 [[PROMOTED]]
111; CHECK: ret
112define i8 @oneArgPromotionPassTruncKeepSExt(i1 %arg1, i8* %base) {
113  %sextarg1 = sext i1 %arg1 to i32
114  %trunc = trunc i32 %sextarg1 to i8
115  %add = add nsw i8 %trunc, 1
116  %sextadd = sext i8 %add to i64
117  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
118  %res = load i8* %arrayidx
119  ret i8 %res
120}
121
122; On X86 truncate are free. Check that we are able to promote the add
123; to be used as addressing mode and that we insert a truncate for the other
124; use.
125; CHECK-LABEL: @oneArgPromotionTruncInsert
126; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i8 %arg1 to i64
127; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
128; CHECK: [[TRUNC:%[a-zA-Z_0-9-]+]] = trunc i64 [[PROMOTED]] to i8
129; CHECK: [[GEP:%[a-zA-Z_0-9-]+]] = getelementptr inbounds i8* %base, i64 [[PROMOTED]]
130; CHECK: [[LOAD:%[a-zA-Z_0-9-]+]] = load i8* [[GEP]]
131; CHECK: add i8 [[LOAD]], [[TRUNC]]
132; CHECK: ret
133define i8 @oneArgPromotionTruncInsert(i8 %arg1, i8* %base) {
134  %add = add nsw i8 %arg1, 1
135  %sextadd = sext i8 %add to i64
136  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
137  %res = load i8* %arrayidx
138  %finalres = add i8 %res, %add
139  ret i8 %finalres
140}
141
142; Cannot sext from a larger type than the promoted type.
143; CHECK-LABEL: @oneArgPromotionLargerType
144; CHECK: [[ARG1TRUNC:%[a-zA-Z_0-9-]+]] = trunc i128 %arg1 to i8
145; CHECK: [[ARG1SEXT64:%[a-zA-Z_0-9-]+]] = sext i8 [[ARG1TRUNC]] to i64
146; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT64]], 1
147; CHECK: getelementptr inbounds i8* %base, i64 [[PROMOTED]]
148; CHECK: ret
149define i8 @oneArgPromotionLargerType(i128 %arg1, i8* %base) {
150  %trunc = trunc i128 %arg1 to i8
151  %add = add nsw i8 %trunc, 1
152  %sextadd = sext i8 %add to i64
153  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
154  %res = load i8* %arrayidx
155  %finalres = add i8 %res, %add
156  ret i8 %finalres
157}
158
159; Use same inserted trunc
160; On X86 truncate are free. Check that we are able to promote the add
161; to be used as addressing mode and that we insert a truncate for
162; *all* the other uses.
163; CHECK-LABEL: @oneArgPromotionTruncInsertSeveralUse
164; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i8 %arg1 to i64
165; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
166; CHECK: [[TRUNC:%[a-zA-Z_0-9-]+]] = trunc i64 [[PROMOTED]] to i8
167; CHECK: [[GEP:%[a-zA-Z_0-9-]+]] = getelementptr inbounds i8* %base, i64 [[PROMOTED]]
168; CHECK: [[LOAD:%[a-zA-Z_0-9-]+]] = load i8* [[GEP]]
169; CHECK: [[ADDRES:%[a-zA-Z_0-9-]+]] = add i8 [[LOAD]], [[TRUNC]]
170; CHECK: add i8 [[ADDRES]], [[TRUNC]]
171; CHECK: ret
172define i8 @oneArgPromotionTruncInsertSeveralUse(i8 %arg1, i8* %base) {
173  %add = add nsw i8 %arg1, 1
174  %sextadd = sext i8 %add to i64
175  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
176  %res = load i8* %arrayidx
177  %almostfinalres = add i8 %res, %add
178  %finalres = add i8 %almostfinalres, %add
179  ret i8 %finalres
180}
181
182; Check that the promoted instruction is used for all uses of the original
183; sign extension.
184; CHECK-LABEL: @oneArgPromotionSExtSeveralUse
185; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i8 %arg1 to i64
186; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
187; CHECK: [[GEP:%[a-zA-Z_0-9-]+]] = getelementptr inbounds i8* %base, i64 [[PROMOTED]]
188; CHECK: [[LOAD:%[a-zA-Z_0-9-]+]] = load i8* [[GEP]]
189; CHECK: [[ADDRES:%[a-zA-Z_0-9-]+]] = zext i8 [[LOAD]] to i64
190; CHECK: add i64 [[ADDRES]], [[PROMOTED]]
191; CHECK: ret
192define i64 @oneArgPromotionSExtSeveralUse(i8 %arg1, i8* %base) {
193  %add = add nsw i8 %arg1, 1
194  %sextadd = sext i8 %add to i64
195  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
196  %res = load i8* %arrayidx
197  %almostfinalres = zext i8 %res to i64
198  %finalres = add i64 %almostfinalres, %sextadd
199  ret i64 %finalres
200}
201
202; Check all types of rollback mechanism.
203; For this test, the sign extension stays in place.
204; However, the matching process goes until promoting both the operands
205; of the first promotable add implies.
206; At this point the rollback mechanism kicks in and restores the states
207; until the addressing mode matcher is able to match something: in that
208; case promote nothing.
209; Along the way, the promotion mechanism involves:
210; - Mutating the type of %promotableadd1 and %promotableadd2.
211; - Creating a sext for %arg1 and %arg2.
212; - Creating a trunc for a use of %promotableadd1.
213; - Replacing a bunch of uses.
214; - Setting the operands of the promoted instruction with the promoted values.
215; - Moving instruction around (mainly sext when promoting instruction).
216; Each type of those promotions has to be undo at least once during this
217; specific test.
218; CHECK-LABEL: @twoArgsPromotionNest
219; CHECK: [[ORIG:%[a-zA-Z_0-9-]+]] = add nsw i32 %arg1, %arg2
220; CHECK: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i32 [[ORIG]], [[ORIG]]
221; CHECK: [[SEXT:%[a-zA-Z_0-9-]+]] = sext i32 [[ADD]] to i64
222; CHECK: getelementptr inbounds i8* %base, i64 [[SEXT]]
223; CHECK: ret
224define i8 @twoArgsPromotionNest(i32 %arg1, i32 %arg2, i8* %base) {
225  %promotableadd1 = add nsw i32 %arg1, %arg2
226  %promotableadd2 = add nsw i32 %promotableadd1, %promotableadd1
227  %sextadd = sext i32 %promotableadd2 to i64
228  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
229  %res = load i8* %arrayidx
230  ret i8 %res
231}
232
233; Test the InstructionRemover undo, which was the only one not
234; kicked in the previous test.
235; The matcher first promotes the add, removes the trunc and promotes
236; the sext of arg1.
237; Then, the matcher cannot use an addressing mode r + r + r, thus it
238; rolls back.
239; CHECK-LABEL: @twoArgsNoPromotionRemove
240; CHECK: [[SEXTARG1:%[a-zA-Z_0-9-]+]] = sext i1 %arg1 to i32
241; CHECK: [[TRUNC:%[a-zA-Z_0-9-]+]] = trunc i32 [[SEXTARG1]] to i8
242; CHECK: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i8 [[TRUNC]], %arg2
243; CHECK: [[SEXT:%[a-zA-Z_0-9-]+]] = sext i8 [[ADD]] to i64
244; CHECK: getelementptr inbounds i8* %base, i64 [[SEXT]]
245; CHECK: ret
246define i8 @twoArgsNoPromotionRemove(i1 %arg1, i8 %arg2, i8* %base) {
247  %sextarg1 = sext i1 %arg1 to i32
248  %trunc = trunc i32 %sextarg1 to i8
249  %add = add nsw i8 %trunc, %arg2
250  %sextadd = sext i8 %add to i64
251  %arrayidx = getelementptr inbounds i8* %base, i64 %sextadd
252  %res = load i8* %arrayidx
253  ret i8 %res
254}
255
256; Ensure that when the profitability checks kicks in, the IR is not modified
257; will IgnoreProfitability is on.
258; The profitabily check happens when a candidate instruction has several uses.
259; The matcher will create a new matcher for each use and check if the
260; instruction is in the list of the matched instructions of this new matcher.
261; All changes made by the new matchers must be dropped before pursuing
262; otherwise the state of the original matcher will be wrong.
263;
264; Without the profitability check, when checking for the second use of
265; arrayidx, the matcher promotes everything all the way to %arg1, %arg2.
266; Check that we did not promote anything in the final matching.
267;
268; <rdar://problem/16020230>
269; CHECK-LABEL: @checkProfitability
270; CHECK-NOT: {{%[a-zA-Z_0-9-]+}} = sext i32 %arg1 to i64
271; CHECK-NOT: {{%[a-zA-Z_0-9-]+}} = sext i32 %arg2 to i64
272; CHECK: [[SHL:%[a-zA-Z_0-9-]+]] = shl nsw i32 %arg1, 1
273; CHECK: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i32 [[SHL]], %arg2
274; CHECK: [[SEXTADD:%[a-zA-Z_0-9-]+]] = sext i32 [[ADD]] to i64
275; BB then
276; CHECK: [[BASE1:%[a-zA-Z_0-9-]+]] = add i64 [[SEXTADD]], 48
277; CHECK: [[ADDR1:%[a-zA-Z_0-9-]+]] = inttoptr i64 [[BASE1]] to i32*
278; CHECK: load i32* [[ADDR1]]
279; BB else
280; CHECK: [[BASE2:%[a-zA-Z_0-9-]+]] = add i64 [[SEXTADD]], 48
281; CHECK: [[ADDR2:%[a-zA-Z_0-9-]+]] = inttoptr i64 [[BASE2]] to i32*
282; CHECK: load i32* [[ADDR2]]
283; CHECK: ret
284define i32 @checkProfitability(i32 %arg1, i32 %arg2, i1 %test) {
285  %shl = shl nsw i32 %arg1, 1
286  %add1 = add nsw i32 %shl, %arg2
287  %sextidx1 = sext i32 %add1 to i64
288  %tmpptr = inttoptr i64 %sextidx1 to i32*
289  %arrayidx1 = getelementptr i32* %tmpptr, i64 12
290  br i1 %test, label %then, label %else
291then:
292  %res1 = load i32* %arrayidx1
293  br label %end
294else:
295  %res2 = load i32* %arrayidx1
296  br label %end
297end:
298  %tmp = phi i32 [%res1, %then], [%res2, %else]
299  %res = add i32 %tmp, %add1
300  %addr = inttoptr i32 %res to i32*
301  %final = load i32* %addr
302  ret i32 %final
303}
304