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/zero 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 ptr
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 ptr
22  %res = load i8, ptr %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, ptr %base) {
35  %add = add nsw i32 %arg1, %arg2
36  %sextadd = sext i32 %add to i64
37  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
38  %res = load i8, ptr %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, ptr %base) {
48  %add = add i32 %arg1, %arg2
49  %sextadd = sext i32 %add to i64
50  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
51  %res = load i8, ptr %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, ptr %base, i64 [[PROMOTED]]
60; CHECK: ret
61define i8 @oneArgPromotion(i32 %arg1, ptr %base) {
62  %add = add nsw i32 %arg1, 1
63  %sextadd = sext i32 %add to i64
64  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
65  %res = load i8, ptr %arrayidx
66  ret i8 %res
67}
68
69; Check that we are able to merge a sign extension with a zero extension.
70; CHECK-LABEL: @oneArgPromotionZExt
71; CHECK: [[ARG1ZEXT:%[a-zA-Z_0-9-]+]] = zext i8 %arg1 to i64
72; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1ZEXT]], 1
73; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
74; CHECK: ret
75define i8 @oneArgPromotionZExt(i8 %arg1, ptr %base) {
76  %zext = zext i8 %arg1 to i32
77  %add = add nsw i32 %zext, 1
78  %sextadd = sext i32 %add to i64
79  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
80  %res = load i8, ptr %arrayidx
81  ret i8 %res
82}
83
84; When promoting a constant zext, the IR builder returns a constant,
85; not an instruction. Make sure this is properly handled. This used
86; to crash.
87; Note: The constant zext is promoted, but does not help matching
88; more thing in the addressing mode. Therefore the modification is
89; rolled back.
90; Still, this test case exercises the desired code path.
91; CHECK-LABEL: @oneArgPromotionCstZExt
92; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 0, 1
93; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
94; CHECK: ret
95define i8 @oneArgPromotionCstZExt(ptr %base) {
96  %cst = zext i16 undef to i32
97  %add = add nsw i32 %cst, 1
98  %sextadd = sext i32 %add to i64
99  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
100  %res = load i8, ptr %arrayidx
101  ret i8 %res
102}
103
104; Check that we do not promote truncate when we cannot determine the
105; bits that are dropped.
106; CHECK-LABEL: @oneArgPromotionBlockTrunc1
107; CHECK: [[ARG1TRUNC:%[a-zA-Z_0-9-]+]] = trunc i32 %arg1 to i8
108; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i8 [[ARG1TRUNC]] to i64
109; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
110; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
111; CHECK: ret
112define i8 @oneArgPromotionBlockTrunc1(i32 %arg1, ptr %base) {
113  %trunc = trunc i32 %arg1 to i8
114  %add = add nsw i8 %trunc, 1
115  %sextadd = sext i8 %add to i64
116  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
117  %res = load i8, ptr %arrayidx
118  ret i8 %res
119}
120
121; Check that we do not promote truncate when we cannot determine all the
122; bits that are dropped.
123; CHECK-LABEL: @oneArgPromotionBlockTrunc2
124; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i16 %arg1 to i32
125; CHECK: [[ARG1TRUNC:%[a-zA-Z_0-9-]+]] = trunc i32 [[ARG1SEXT]] to i8
126; CHECK: [[ARG1SEXT64:%[a-zA-Z_0-9-]+]] = sext i8 [[ARG1TRUNC]] to i64
127; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT64]], 1
128; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
129; CHECK: ret
130define i8 @oneArgPromotionBlockTrunc2(i16 %arg1, ptr %base) {
131  %sextarg1 = sext i16 %arg1 to i32
132  %trunc = trunc i32 %sextarg1 to i8
133  %add = add nsw i8 %trunc, 1
134  %sextadd = sext i8 %add to i64
135  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
136  %res = load i8, ptr %arrayidx
137  ret i8 %res
138}
139
140; Check that we are able to promote truncate when we know all the bits
141; that are dropped.
142; CHECK-LABEL: @oneArgPromotionPassTruncKeepSExt
143; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i1 %arg1 to i64
144; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
145; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
146; CHECK: ret
147define i8 @oneArgPromotionPassTruncKeepSExt(i1 %arg1, ptr %base) {
148  %sextarg1 = sext i1 %arg1 to i32
149  %trunc = trunc i32 %sextarg1 to i8
150  %add = add nsw i8 %trunc, 1
151  %sextadd = sext i8 %add to i64
152  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
153  %res = load i8, ptr %arrayidx
154  ret i8 %res
155}
156
157; On X86 truncate are free. Check that we are able to promote the add
158; to be used as addressing mode and that we insert a truncate for the other
159; use.
160; CHECK-LABEL: @oneArgPromotionTruncInsert
161; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i8 %arg1 to i64
162; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
163; CHECK: [[TRUNC:%[a-zA-Z_0-9-]+]] = trunc i64 [[PROMOTED]] to i8
164; CHECK: [[GEP:%[a-zA-Z_0-9-]+]] = getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
165; CHECK: [[LOAD:%[a-zA-Z_0-9-]+]] = load i8, ptr [[GEP]]
166; CHECK: add i8 [[LOAD]], [[TRUNC]]
167; CHECK: ret
168define i8 @oneArgPromotionTruncInsert(i8 %arg1, ptr %base) {
169  %add = add nsw i8 %arg1, 1
170  %sextadd = sext i8 %add to i64
171  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
172  %res = load i8, ptr %arrayidx
173  %finalres = add i8 %res, %add
174  ret i8 %finalres
175}
176
177; Cannot sext from a larger type than the promoted type.
178; CHECK-LABEL: @oneArgPromotionLargerType
179; CHECK: [[ARG1TRUNC:%[a-zA-Z_0-9-]+]] = trunc i128 %arg1 to i8
180; CHECK: [[ARG1SEXT64:%[a-zA-Z_0-9-]+]] = sext i8 [[ARG1TRUNC]] to i64
181; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT64]], 1
182; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
183; CHECK: ret
184define i8 @oneArgPromotionLargerType(i128 %arg1, ptr %base) {
185  %trunc = trunc i128 %arg1 to i8
186  %add = add nsw i8 %trunc, 1
187  %sextadd = sext i8 %add to i64
188  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
189  %res = load i8, ptr %arrayidx
190  %finalres = add i8 %res, %add
191  ret i8 %finalres
192}
193
194; Use same inserted trunc
195; On X86 truncate are free. Check that we are able to promote the add
196; to be used as addressing mode and that we insert a truncate for
197; *all* the other uses.
198; CHECK-LABEL: @oneArgPromotionTruncInsertSeveralUse
199; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i8 %arg1 to i64
200; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
201; CHECK: [[TRUNC:%[a-zA-Z_0-9-]+]] = trunc i64 [[PROMOTED]] to i8
202; CHECK: [[GEP:%[a-zA-Z_0-9-]+]] = getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
203; CHECK: [[LOAD:%[a-zA-Z_0-9-]+]] = load i8, ptr [[GEP]]
204; CHECK: [[ADDRES:%[a-zA-Z_0-9-]+]] = add i8 [[LOAD]], [[TRUNC]]
205; CHECK: add i8 [[ADDRES]], [[TRUNC]]
206; CHECK: ret
207define i8 @oneArgPromotionTruncInsertSeveralUse(i8 %arg1, ptr %base) {
208  %add = add nsw i8 %arg1, 1
209  %sextadd = sext i8 %add to i64
210  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
211  %res = load i8, ptr %arrayidx
212  %almostfinalres = add i8 %res, %add
213  %finalres = add i8 %almostfinalres, %add
214  ret i8 %finalres
215}
216
217; Check that the promoted instruction is used for all uses of the original
218; sign extension.
219; CHECK-LABEL: @oneArgPromotionSExtSeveralUse
220; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i8 %arg1 to i64
221; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nsw i64 [[ARG1SEXT]], 1
222; CHECK: [[GEP:%[a-zA-Z_0-9-]+]] = getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
223; CHECK: [[LOAD:%[a-zA-Z_0-9-]+]] = load i8, ptr [[GEP]]
224; CHECK: [[ADDRES:%[a-zA-Z_0-9-]+]] = zext i8 [[LOAD]] to i64
225; CHECK: add i64 [[ADDRES]], [[PROMOTED]]
226; CHECK: ret
227define i64 @oneArgPromotionSExtSeveralUse(i8 %arg1, ptr %base) {
228  %add = add nsw i8 %arg1, 1
229  %sextadd = sext i8 %add to i64
230  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
231  %res = load i8, ptr %arrayidx
232  %almostfinalres = zext i8 %res to i64
233  %finalres = add i64 %almostfinalres, %sextadd
234  ret i64 %finalres
235}
236
237; Check all types of rollback mechanism.
238; For this test, the sign extension stays in place.
239; However, the matching process goes until promoting both the operands
240; of the first promotable add implies.
241; At this point the rollback mechanism kicks in and restores the states
242; until the addressing mode matcher is able to match something: in that
243; case promote nothing.
244; Along the way, the promotion mechanism involves:
245; - Mutating the type of %promotableadd1 and %promotableadd2.
246; - Creating a sext for %arg1 and %arg2.
247; - Creating a trunc for a use of %promotableadd1.
248; - Replacing a bunch of uses.
249; - Setting the operands of the promoted instruction with the promoted values.
250; - Moving instruction around (mainly sext when promoting instruction).
251; Each type of those promotions has to be undo at least once during this
252; specific test.
253; CHECK-LABEL: @twoArgsPromotionNest
254; CHECK: [[ORIG:%[a-zA-Z_0-9-]+]] = add nsw i32 %arg1, %arg2
255; CHECK: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i32 [[ORIG]], [[ORIG]]
256; CHECK: [[SEXT:%[a-zA-Z_0-9-]+]] = sext i32 [[ADD]] to i64
257; CHECK: getelementptr inbounds i8, ptr %base, i64 [[SEXT]]
258; CHECK: ret
259define i8 @twoArgsPromotionNest(i32 %arg1, i32 %arg2, ptr %base) {
260  %promotableadd1 = add nsw i32 %arg1, %arg2
261  %promotableadd2 = add nsw i32 %promotableadd1, %promotableadd1
262  %sextadd = sext i32 %promotableadd2 to i64
263  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
264  %res = load i8, ptr %arrayidx
265  ret i8 %res
266}
267
268; Test the InstructionRemover undo, which was the only one not
269; kicked in the previous test.
270; The matcher first promotes the add, removes the trunc and promotes
271; the sext of arg1.
272; Then, the matcher cannot use an addressing mode r + r + r, thus it
273; rolls back.
274; CHECK-LABEL: @twoArgsNoPromotionRemove
275; CHECK: [[SEXTARG1:%[a-zA-Z_0-9-]+]] = sext i1 %arg1 to i32
276; CHECK: [[TRUNC:%[a-zA-Z_0-9-]+]] = trunc i32 [[SEXTARG1]] to i8
277; CHECK: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i8 [[TRUNC]], %arg2
278; CHECK: [[SEXT:%[a-zA-Z_0-9-]+]] = sext i8 [[ADD]] to i64
279; CHECK: getelementptr inbounds i8, ptr %base, i64 [[SEXT]]
280; CHECK: ret
281define i8 @twoArgsNoPromotionRemove(i1 %arg1, i8 %arg2, ptr %base) {
282  %sextarg1 = sext i1 %arg1 to i32
283  %trunc = trunc i32 %sextarg1 to i8
284  %add = add nsw i8 %trunc, %arg2
285  %sextadd = sext i8 %add to i64
286  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %sextadd
287  %res = load i8, ptr %arrayidx
288  ret i8 %res
289}
290
291; Ensure that when the profitability checks kicks in, the IR is not modified
292; will IgnoreProfitability is on.
293; The profitabily check happens when a candidate instruction has several uses.
294; The matcher will create a new matcher for each use and check if the
295; instruction is in the list of the matched instructions of this new matcher.
296; All changes made by the new matchers must be dropped before pursuing
297; otherwise the state of the original matcher will be wrong.
298;
299; Without the profitability check, when checking for the second use of
300; arrayidx, the matcher promotes everything all the way to %arg1, %arg2.
301; Check that we did not promote anything in the final matching.
302;
303; <rdar://problem/16020230>
304; CHECK-LABEL: @checkProfitability
305; CHECK-NOT: {{%[a-zA-Z_0-9-]+}} = sext i32 %arg1 to i64
306; CHECK-NOT: {{%[a-zA-Z_0-9-]+}} = sext i32 %arg2 to i64
307; CHECK: [[SHL:%[a-zA-Z_0-9-]+]] = shl nsw i32 %arg1, 1
308; CHECK: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i32 [[SHL]], %arg2
309; CHECK: [[SEXTADD:%[a-zA-Z_0-9-]+]] = sext i32 [[ADD]] to i64
310; BB then
311; CHECK: [[BASE1:%[a-zA-Z_0-9-]+]] = inttoptr i64 [[SEXTADD]] to ptr
312; CHECK: [[FULL1:%[a-zA-Z_0-9-]+]] = getelementptr i8, ptr [[BASE1]], i64 48
313; CHECK: load i32, ptr [[FULL1]]
314; BB else
315; CHECK: [[BASE2:%[a-zA-Z_0-9-]+]] = inttoptr i64 [[SEXTADD]] to ptr
316; CHECK: [[FULL2:%[a-zA-Z_0-9-]+]] = getelementptr i8, ptr [[BASE2]], i64 48
317; CHECK: load i32, ptr [[FULL2]]
318; CHECK: ret
319define i32 @checkProfitability(i32 %arg1, i32 %arg2, i1 %test) {
320  %shl = shl nsw i32 %arg1, 1
321  %add1 = add nsw i32 %shl, %arg2
322  %sextidx1 = sext i32 %add1 to i64
323  %tmpptr = inttoptr i64 %sextidx1 to ptr
324  %arrayidx1 = getelementptr i32, ptr %tmpptr, i64 12
325  br i1 %test, label %then, label %else
326then:
327  %res1 = load i32, ptr %arrayidx1
328  br label %end
329else:
330  %res2 = load i32, ptr %arrayidx1
331  br label %end
332end:
333  %tmp = phi i32 [%res1, %then], [%res2, %else]
334  %res = add i32 %tmp, %add1
335  %addr = inttoptr i32 %res to ptr
336  %final = load i32, ptr %addr
337  ret i32 %final
338}
339
340%struct.dns_packet = type { i32, i32, %union.anon }
341%union.anon = type { i32 }
342
343@a = common global i32 0, align 4
344@b = common global i16 0, align 2
345
346; We used to crash on this function because we did not return the right
347; promoted instruction for %conv.i.
348; Make sure we generate the right code now.
349; CHECK-LABEL: @fn3
350; %conv.i is used twice and only one of its use is being promoted.
351; Use it at the starting point for the matching.
352; CHECK: %conv.i = zext i16 [[PLAIN_OPND:%[.a-zA-Z_0-9-]+]] to i32
353; CHECK-NEXT: [[PROMOTED_CONV:%[.a-zA-Z_0-9-]+]] = zext i16 [[PLAIN_OPND]] to i64
354; CHECK-NEXT: [[ADD:%[a-zA-Z_0-9-]+]] = getelementptr i8, ptr %P, i64 [[PROMOTED_CONV]]
355; CHECK-NEXT: [[ADDR:%[a-zA-Z_0-9-]+]] = getelementptr i8, ptr [[ADD]], i64 7
356; CHECK-NEXT: load i8, ptr [[ADDR]], align 1
357define signext i16 @fn3(ptr nocapture readonly %P) {
358entry:
359  %tmp = getelementptr inbounds %struct.dns_packet, ptr %P, i64 0, i32 2
360  br label %while.body.i.i
361
362while.body.i.i:                                   ; preds = %while.body.i.i, %entry
363  %src.addr.0.i.i = phi i16 [ 0, %entry ], [ %inc.i.i, %while.body.i.i ]
364  %inc.i.i = add i16 %src.addr.0.i.i, 1
365  %idxprom.i.i = sext i16 %src.addr.0.i.i to i64
366  %arrayidx.i.i = getelementptr inbounds [0 x i8], ptr %tmp, i64 0, i64 %idxprom.i.i
367  %tmp1 = load i8, ptr %arrayidx.i.i, align 1
368  %conv2.i.i = zext i8 %tmp1 to i32
369  %and.i.i = and i32 %conv2.i.i, 15
370  store i32 %and.i.i, ptr @a, align 4
371  %tobool.i.i = icmp eq i32 %and.i.i, 0
372  br i1 %tobool.i.i, label %while.body.i.i, label %fn1.exit.i
373
374fn1.exit.i:                                       ; preds = %while.body.i.i
375  %inc.i.i.lcssa = phi i16 [ %inc.i.i, %while.body.i.i ]
376  %conv.i = zext i16 %inc.i.i.lcssa to i32
377  %sub.i = add nsw i32 %conv.i, -1
378  %idxprom.i = sext i32 %sub.i to i64
379  %arrayidx.i = getelementptr inbounds [0 x i8], ptr %tmp, i64 0, i64 %idxprom.i
380  %tmp2 = load i8, ptr %arrayidx.i, align 1
381  %conv2.i = sext i8 %tmp2 to i16
382  store i16 %conv2.i, ptr @b, align 2
383  %sub4.i = sub nsw i32 0, %conv.i
384  %conv5.i = zext i16 %conv2.i to i32
385  %cmp.i = icmp sgt i32 %conv5.i, %sub4.i
386  br i1 %cmp.i, label %if.then.i, label %fn2.exit
387
388if.then.i:                                        ; preds = %fn1.exit.i
389  %end.i = getelementptr inbounds %struct.dns_packet, ptr %P, i64 0, i32 1
390  %tmp3 = load i32, ptr %end.i, align 4
391  %sub7.i = add i32 %tmp3, 65535
392  %conv8.i = trunc i32 %sub7.i to i16
393  br label %fn2.exit
394
395fn2.exit:                                         ; preds = %if.then.i, %fn1.exit.i
396  %retval.0.i = phi i16 [ %conv8.i, %if.then.i ], [ undef, %fn1.exit.i ]
397  ret i16 %retval.0.i
398}
399
400; Check that we do not promote an extension if the non-wrapping flag does not
401; match the kind of the extension.
402; CHECK-LABEL: @noPromotionFlag
403; CHECK: [[ADD:%[a-zA-Z_0-9-]+]] = add nsw i32 %arg1, %arg2
404; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = zext i32 [[ADD]] to i64
405; CHECK: inttoptr i64 [[PROMOTED]] to ptr
406; CHECK: ret
407define i8 @noPromotionFlag(i32 %arg1, i32 %arg2) {
408  %add = add nsw i32 %arg1, %arg2
409  %zextadd = zext i32 %add to i64
410  %base = inttoptr i64 %zextadd to ptr
411  %res = load i8, ptr %base
412  ret i8 %res
413}
414
415; Check that we correctly promote both operands of the promotable add with zext.
416; CHECK-LABEL: @twoArgsPromotionZExt
417; CHECK: [[ARG1ZEXT:%[a-zA-Z_0-9-]+]] = zext i32 %arg1 to i64
418; CHECK: [[ARG2ZEXT:%[a-zA-Z_0-9-]+]] = zext i32 %arg2 to i64
419; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nuw i64 [[ARG1ZEXT]], [[ARG2ZEXT]]
420; CHECK: inttoptr i64 [[PROMOTED]] to ptr
421; CHECK: ret
422define i8 @twoArgsPromotionZExt(i32 %arg1, i32 %arg2) {
423  %add = add nuw i32 %arg1, %arg2
424  %zextadd = zext i32 %add to i64
425  %base = inttoptr i64 %zextadd to ptr
426  %res = load i8, ptr %base
427  ret i8 %res
428}
429
430; Check that we correctly promote constant arguments.
431; CHECK-LABEL: @oneArgPromotionNegativeCstZExt
432; CHECK: [[ARG1ZEXT:%[a-zA-Z_0-9-]+]] = zext i8 %arg1 to i64
433; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nuw i64 [[ARG1ZEXT]], 255
434; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
435; CHECK: ret
436define i8 @oneArgPromotionNegativeCstZExt(i8 %arg1, ptr %base) {
437  %add = add nuw i8 %arg1, -1
438  %zextadd = zext i8 %add to i64
439  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %zextadd
440  %res = load i8, ptr %arrayidx
441  ret i8 %res
442}
443
444; Check that we are able to merge two zero extensions.
445; CHECK-LABEL: @oneArgPromotionZExtZExt
446; CHECK: [[ARG1ZEXT:%[a-zA-Z_0-9-]+]] = zext i8 %arg1 to i64
447; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nuw i64 [[ARG1ZEXT]], 1
448; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
449; CHECK: ret
450define i8 @oneArgPromotionZExtZExt(i8 %arg1, ptr %base) {
451  %zext = zext i8 %arg1 to i32
452  %add = add nuw i32 %zext, 1
453  %zextadd = zext i32 %add to i64
454  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %zextadd
455  %res = load i8, ptr %arrayidx
456  ret i8 %res
457}
458
459; Check that we do not promote truncate when the dropped bits
460; are of a different kind.
461; CHECK-LABEL: @oneArgPromotionBlockTruncZExt
462; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i1 %arg1 to i32
463; CHECK: [[ARG1TRUNC:%[a-zA-Z_0-9-]+]] = trunc i32 [[ARG1SEXT]] to i8
464; CHECK: [[ARG1ZEXT:%[a-zA-Z_0-9-]+]] = zext i8 [[ARG1TRUNC]] to i64
465; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nuw i64 [[ARG1ZEXT]], 1
466; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
467; CHECK: ret
468define i8 @oneArgPromotionBlockTruncZExt(i1 %arg1, ptr %base) {
469  %sextarg1 = sext i1 %arg1 to i32
470  %trunc = trunc i32 %sextarg1 to i8
471  %add = add nuw i8 %trunc, 1
472  %zextadd = zext i8 %add to i64
473  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %zextadd
474  %res = load i8, ptr %arrayidx
475  ret i8 %res
476}
477
478; Check that we are able to promote truncate when we know all the bits
479; that are dropped.
480; CHECK-LABEL: @oneArgPromotionPassTruncZExt
481; CHECK: [[ARG1ZEXT:%[a-zA-Z_0-9-]+]] = zext i1 %arg1 to i64
482; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nuw i64 [[ARG1ZEXT]], 1
483; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
484; CHECK: ret
485define i8 @oneArgPromotionPassTruncZExt(i1 %arg1, ptr %base) {
486  %sextarg1 = zext i1 %arg1 to i32
487  %trunc = trunc i32 %sextarg1 to i8
488  %add = add nuw i8 %trunc, 1
489  %zextadd = zext i8 %add to i64
490  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %zextadd
491  %res = load i8, ptr %arrayidx
492  ret i8 %res
493}
494
495; Check that we do not promote sext with zext.
496; CHECK-LABEL: @oneArgPromotionBlockSExtZExt
497; CHECK: [[ARG1SEXT:%[a-zA-Z_0-9-]+]] = sext i1 %arg1 to i8
498; CHECK: [[ARG1ZEXT:%[a-zA-Z_0-9-]+]] = zext i8 [[ARG1SEXT]] to i64
499; CHECK: [[PROMOTED:%[a-zA-Z_0-9-]+]] = add nuw i64 [[ARG1ZEXT]], 1
500; CHECK: getelementptr inbounds i8, ptr %base, i64 [[PROMOTED]]
501; CHECK: ret
502define i8 @oneArgPromotionBlockSExtZExt(i1 %arg1, ptr %base) {
503  %sextarg1 = sext i1 %arg1 to i8
504  %add = add nuw i8 %sextarg1, 1
505  %zextadd = zext i8 %add to i64
506  %arrayidx = getelementptr inbounds i8, ptr %base, i64 %zextadd
507  %res = load i8, ptr %arrayidx
508  ret i8 %res
509}
510