[DAGCombiner] Add target hook function to decide folding (mul (add x, c1), c2)
[llvm-project.git] / llvm / test / Transforms / Reassociate / matching-binops.ll
blob4771e3c8e1cd963b9b127808e9dd12073a26cf80
1 ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2 ; RUN: opt < %s -reassociate -S | FileCheck %s
4 ; PR37098 - https://bugs.llvm.org/show_bug.cgi?id=37098
5 ; In all positive tests, we should reassociate binops
6 ; to allow more factoring folds.
8 ; There are 5 associative integer binops *
9 ;           13 integer binops *
10 ;           4 operand commutes =
11 ;           260 potential variations of this fold
12 ; for integer binops. There are another 40 for FP.
13 ; Mix the commutation options to provide coverage using less tests.
15 define i8 @and_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
16 ; CHECK-LABEL: @and_shl(
17 ; CHECK-NEXT:    [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
18 ; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
19 ; CHECK-NEXT:    [[A:%.*]] = and i8 [[SX]], [[Z:%.*]]
20 ; CHECK-NEXT:    [[R:%.*]] = and i8 [[A]], [[SY]]
21 ; CHECK-NEXT:    ret i8 [[R]]
23   %sx = shl i8 %x, %shamt
24   %sy = shl i8 %y, %shamt
25   %a = and i8 %sx, %z
26   %r = and i8 %sy, %a
27   ret i8 %r
30 define i8 @or_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
31 ; CHECK-LABEL: @or_shl(
32 ; CHECK-NEXT:    [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
33 ; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
34 ; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
35 ; CHECK-NEXT:    [[R:%.*]] = or i8 [[A]], [[SY]]
36 ; CHECK-NEXT:    ret i8 [[R]]
38   %sx = shl i8 %x, %shamt
39   %sy = shl i8 %y, %shamt
40   %a = or i8 %sx, %z
41   %r = or i8 %a, %sy
42   ret i8 %r
45 define i8 @xor_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
46 ; CHECK-LABEL: @xor_shl(
47 ; CHECK-NEXT:    [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
48 ; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
49 ; CHECK-NEXT:    [[A:%.*]] = xor i8 [[SX]], [[Z:%.*]]
50 ; CHECK-NEXT:    [[R:%.*]] = xor i8 [[A]], [[SY]]
51 ; CHECK-NEXT:    ret i8 [[R]]
53   %sx = shl i8 %x, %shamt
54   %sy = shl i8 %y, %shamt
55   %a = xor i8 %z, %sx
56   %r = xor i8 %a, %sy
57   ret i8 %r
60 define i8 @and_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
61 ; CHECK-LABEL: @and_lshr(
62 ; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
63 ; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
64 ; CHECK-NEXT:    [[A:%.*]] = and i8 [[SX]], [[Z:%.*]]
65 ; CHECK-NEXT:    [[R:%.*]] = and i8 [[A]], [[SY]]
66 ; CHECK-NEXT:    ret i8 [[R]]
68   %sx = lshr i8 %x, %shamt
69   %sy = lshr i8 %y, %shamt
70   %a = and i8 %z, %sx
71   %r = and i8 %sy, %a
72   ret i8 %r
75 define i8 @or_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
76 ; CHECK-LABEL: @or_lshr(
77 ; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
78 ; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
79 ; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
80 ; CHECK-NEXT:    [[R:%.*]] = or i8 [[A]], [[SY]]
81 ; CHECK-NEXT:    ret i8 [[R]]
83   %sx = lshr i8 %x, %shamt
84   %sy = lshr i8 %y, %shamt
85   %a = or i8 %sx, %z
86   %r = or i8 %sy, %a
87   ret i8 %r
90 define i8 @xor_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
91 ; CHECK-LABEL: @xor_lshr(
92 ; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
93 ; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
94 ; CHECK-NEXT:    [[A:%.*]] = xor i8 [[SX]], [[Z:%.*]]
95 ; CHECK-NEXT:    [[R:%.*]] = xor i8 [[A]], [[SY]]
96 ; CHECK-NEXT:    ret i8 [[R]]
98   %sx = lshr i8 %x, %shamt
99   %sy = lshr i8 %y, %shamt
100   %a = xor i8 %sx, %z
101   %r = xor i8 %a, %sy
102   ret i8 %r
105 define i8 @and_ashr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
106 ; CHECK-LABEL: @and_ashr(
107 ; CHECK-NEXT:    [[SX:%.*]] = ashr i8 [[X:%.*]], [[SHAMT:%.*]]
108 ; CHECK-NEXT:    [[SY:%.*]] = ashr i8 [[Y:%.*]], [[SHAMT]]
109 ; CHECK-NEXT:    [[A:%.*]] = and i8 [[SX]], [[Z:%.*]]
110 ; CHECK-NEXT:    [[R:%.*]] = and i8 [[A]], [[SY]]
111 ; CHECK-NEXT:    ret i8 [[R]]
113   %sx = ashr i8 %x, %shamt
114   %sy = ashr i8 %y, %shamt
115   %a = and i8 %z, %sx
116   %r = and i8 %a, %sy
117   ret i8 %r
120 define i8 @or_ashr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
121 ; CHECK-LABEL: @or_ashr(
122 ; CHECK-NEXT:    [[SX:%.*]] = ashr i8 [[X:%.*]], [[SHAMT:%.*]]
123 ; CHECK-NEXT:    [[SY:%.*]] = ashr i8 [[Y:%.*]], [[SHAMT]]
124 ; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
125 ; CHECK-NEXT:    [[R:%.*]] = or i8 [[A]], [[SY]]
126 ; CHECK-NEXT:    ret i8 [[R]]
128   %sx = ashr i8 %x, %shamt
129   %sy = ashr i8 %y, %shamt
130   %a = or i8 %z, %sx
131   %r = or i8 %sy, %a
132   ret i8 %r
135 ; Vectors work too.
137 define <2 x i8> @xor_ashr(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z, <2 x i8> %shamt) {
138 ; CHECK-LABEL: @xor_ashr(
139 ; CHECK-NEXT:    [[SX:%.*]] = ashr <2 x i8> [[X:%.*]], [[SHAMT:%.*]]
140 ; CHECK-NEXT:    [[SY:%.*]] = ashr <2 x i8> [[Y:%.*]], [[SHAMT]]
141 ; CHECK-NEXT:    [[A:%.*]] = xor <2 x i8> [[SX]], [[Z:%.*]]
142 ; CHECK-NEXT:    [[R:%.*]] = xor <2 x i8> [[A]], [[SY]]
143 ; CHECK-NEXT:    ret <2 x i8> [[R]]
145   %sx = ashr <2 x i8> %x, %shamt
146   %sy = ashr <2 x i8> %y, %shamt
147   %a = xor <2 x i8> %sx, %z
148   %r = xor <2 x i8> %a, %sy
149   ret <2 x i8> %r
152 ; Negative test - different logic ops
154 define i8 @or_and_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
155 ; CHECK-LABEL: @or_and_shl(
156 ; CHECK-NEXT:    [[SX:%.*]] = shl i8 [[X:%.*]], [[SHAMT:%.*]]
157 ; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
158 ; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
159 ; CHECK-NEXT:    [[R:%.*]] = and i8 [[A]], [[SY]]
160 ; CHECK-NEXT:    ret i8 [[R]]
162   %sx = shl i8 %x, %shamt
163   %sy = shl i8 %y, %shamt
164   %a = or i8 %sx, %z
165   %r = and i8 %sy, %a
166   ret i8 %r
169 ; Negative test - different shift ops
171 define i8 @or_lshr_shl(i8 %x, i8 %y, i8 %z, i8 %shamt) {
172 ; CHECK-LABEL: @or_lshr_shl(
173 ; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
174 ; CHECK-NEXT:    [[SY:%.*]] = shl i8 [[Y:%.*]], [[SHAMT]]
175 ; CHECK-NEXT:    [[A:%.*]] = or i8 [[SX]], [[Z:%.*]]
176 ; CHECK-NEXT:    [[R:%.*]] = or i8 [[A]], [[SY]]
177 ; CHECK-NEXT:    ret i8 [[R]]
179   %sx = lshr i8 %x, %shamt
180   %sy = shl i8 %y, %shamt
181   %a = or i8 %sx, %z
182   %r = or i8 %a, %sy
183   ret i8 %r
186 ; Negative test - multi-use
188 define i8 @xor_lshr_multiuse(i8 %x, i8 %y, i8 %z, i8 %shamt) {
189 ; CHECK-LABEL: @xor_lshr_multiuse(
190 ; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
191 ; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
192 ; CHECK-NEXT:    [[A:%.*]] = xor i8 [[SX]], [[Z:%.*]]
193 ; CHECK-NEXT:    [[R:%.*]] = xor i8 [[A]], [[SY]]
194 ; CHECK-NEXT:    [[R2:%.*]] = sdiv i8 [[A]], [[R]]
195 ; CHECK-NEXT:    ret i8 [[R2]]
197   %sx = lshr i8 %x, %shamt
198   %sy = lshr i8 %y, %shamt
199   %a = xor i8 %sx, %z
200   %r = xor i8 %a, %sy
201   %r2 = sdiv i8 %a, %r
202   ret i8 %r2
205 ; Math ops work too. Change instruction positions too to verify placement.
207 define i8 @add_lshr(i8 %x, i8 %y, i8 %z, i8 %shamt) {
208 ; CHECK-LABEL: @add_lshr(
209 ; CHECK-NEXT:    [[SX:%.*]] = lshr i8 [[X:%.*]], [[SHAMT:%.*]]
210 ; CHECK-NEXT:    [[A:%.*]] = add i8 [[SX]], [[Z:%.*]]
211 ; CHECK-NEXT:    [[SY:%.*]] = lshr i8 [[Y:%.*]], [[SHAMT]]
212 ; CHECK-NEXT:    [[R:%.*]] = add i8 [[A]], [[SY]]
213 ; CHECK-NEXT:    ret i8 [[R]]
215   %sx = lshr i8 %x, %shamt
216   %a = add i8 %sx, %z
217   %sy = lshr i8 %y, %shamt
218   %r = add i8 %a, %sy
219   ret i8 %r
222 ; Make sure wrapping flags are cleared.
224 define i8 @mul_sub(i8 %x, i8 %y, i8 %z, i8 %m) {
225 ; CHECK-LABEL: @mul_sub(
226 ; CHECK-NEXT:    [[SX:%.*]] = sub i8 [[X:%.*]], [[M:%.*]]
227 ; CHECK-NEXT:    [[SY:%.*]] = sub i8 [[Y:%.*]], [[M]]
228 ; CHECK-NEXT:    [[A:%.*]] = mul nsw i8 [[SX]], [[Z:%.*]]
229 ; CHECK-NEXT:    [[R:%.*]] = mul nuw i8 [[A]], [[SY]]
230 ; CHECK-NEXT:    ret i8 [[R]]
232   %sx = sub i8 %x, %m
233   %sy = sub i8 %y, %m
234   %a = mul nsw i8 %sx, %z
235   %r = mul nuw i8 %a, %sy
236   ret i8 %r
239 define i8 @add_mul(i8 %x, i8 %y, i8 %z, i8 %m) {
240 ; CHECK-LABEL: @add_mul(
241 ; CHECK-NEXT:    [[SX:%.*]] = mul nuw i8 [[X:%.*]], 42
242 ; CHECK-NEXT:    [[A:%.*]] = add nuw i8 [[Z:%.*]], [[SX]]
243 ; CHECK-NEXT:    [[SY:%.*]] = mul nsw i8 [[M:%.*]], [[Y:%.*]]
244 ; CHECK-NEXT:    [[R:%.*]] = add nsw i8 [[A]], [[SY]]
245 ; CHECK-NEXT:    ret i8 [[R]]
247   %sx = mul nuw i8 %x, 42
248   %a = add nuw i8 %sx, %z
249   %sy = mul nsw i8 %y, %m
250   %r = add nsw i8 %sy, %a
251   ret i8 %r
254 ; Floating-point works too if it's not strict.
255 ; TODO: These should not require the full 'fast' FMF.
257 define float @fadd_fmul(float %x, float %y, float %z, float %m) {
258 ; CHECK-LABEL: @fadd_fmul(
259 ; CHECK-NEXT:    [[SX:%.*]] = fmul float [[X:%.*]], [[M:%.*]]
260 ; CHECK-NEXT:    [[A:%.*]] = fadd fast float [[SX]], [[Z:%.*]]
261 ; CHECK-NEXT:    [[SY:%.*]] = fmul float [[Y:%.*]], [[M]]
262 ; CHECK-NEXT:    [[R:%.*]] = fadd fast float [[A]], [[SY]]
263 ; CHECK-NEXT:    ret float [[R]]
265   %sx = fmul float %x, %m
266   %a = fadd fast float %sx, %z
267   %sy = fmul float %y, %m
268   %r = fadd fast float %sy, %a
269   ret float %r
272 define float @fmul_fdiv(float %x, float %y, float %z, float %m) {
273 ; CHECK-LABEL: @fmul_fdiv(
274 ; CHECK-NEXT:    [[SX:%.*]] = fdiv float [[X:%.*]], [[M:%.*]]
275 ; CHECK-NEXT:    [[SY:%.*]] = fdiv float [[Y:%.*]], 4.200000e+01
276 ; CHECK-NEXT:    [[A:%.*]] = fmul fast float [[SY]], [[Z:%.*]]
277 ; CHECK-NEXT:    [[R:%.*]] = fmul fast float [[A]], [[SX]]
278 ; CHECK-NEXT:    ret float [[R]]
280   %sx = fdiv float %x, %m
281   %sy = fdiv float %y, 42.0
282   %a = fmul fast float %z, %sx
283   %r = fmul fast float %sy, %a
284   ret float %r
287 ; Verify that debug info for modified instructions gets discarded (references become undef).
289 define i32 @and_shl_dbg(i32 %x, i32 %y, i32 %z, i32 %shamt) {
290 ; CHECK-LABEL: @and_shl_dbg(
291 ; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 [[X:%.*]], metadata !7, metadata !DIExpression()), !dbg !20
292 ; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 [[Y:%.*]], metadata !13, metadata !DIExpression()), !dbg !21
293 ; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 [[Z:%.*]], metadata !14, metadata !DIExpression()), !dbg !22
294 ; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 [[SHAMT:%.*]], metadata !15, metadata !DIExpression()), !dbg !23
295 ; CHECK-NEXT:    [[SHL:%.*]] = shl i32 [[X]], [[SHAMT]], !dbg !24
296 ; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 [[SHL]], metadata !16, metadata !DIExpression()), !dbg !25
297 ; CHECK-NEXT:    [[SHL1:%.*]] = shl i32 [[Y]], [[SHAMT]], !dbg !26
298 ; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 [[SHL1]], metadata !17, metadata !DIExpression()), !dbg !27
299 ; CHECK-NEXT:    [[AND:%.*]] = and i32 [[SHL]], [[Z]], !dbg !28
300 ; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 [[AND]], metadata !18, metadata !DIExpression()), !dbg !29
301 ; CHECK-NEXT:    [[AND2:%.*]] = and i32 [[AND]], [[SHL1]], !dbg !30
302 ; CHECK-NEXT:    call void @llvm.dbg.value(metadata i32 [[AND2]], metadata !19, metadata !DIExpression()), !dbg !31
303 ; CHECK-NEXT:    ret i32 [[AND2]], !dbg !32
305   call void @llvm.dbg.value(metadata i32 %x, metadata !13, metadata !DIExpression()), !dbg !21
306   call void @llvm.dbg.value(metadata i32 %y, metadata !14, metadata !DIExpression()), !dbg !22
307   call void @llvm.dbg.value(metadata i32 %z, metadata !15, metadata !DIExpression()), !dbg !23
308   call void @llvm.dbg.value(metadata i32 %shamt, metadata !16, metadata !DIExpression()), !dbg !24
309   %shl = shl i32 %x, %shamt, !dbg !25
310   call void @llvm.dbg.value(metadata i32 %shl, metadata !17, metadata !DIExpression()), !dbg !26
311   %shl1 = shl i32 %y, %shamt, !dbg !27
312   call void @llvm.dbg.value(metadata i32 %shl1, metadata !18, metadata !DIExpression()), !dbg !28
313   %and = and i32 %shl, %z, !dbg !29
314   call void @llvm.dbg.value(metadata i32 %and, metadata !19, metadata !DIExpression()), !dbg !30
315   %and2 = and i32 %and, %shl1, !dbg !31
316   call void @llvm.dbg.value(metadata i32 %and2, metadata !20, metadata !DIExpression()), !dbg !32
317   ret i32 %and2, !dbg !33
320 declare void @llvm.dbg.value(metadata, metadata, metadata)
322 !llvm.dbg.cu = !{!0}
323 !llvm.module.flags = !{!3, !4, !5, !6}
325 !0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 7.0.0 (trunk 331069)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2)
326 !1 = !DIFile(filename: "ass.c", directory: "/Users/spatel/myllvm/release/bin")
327 !2 = !{}
328 !3 = !{i32 2, !"Dwarf Version", i32 4}
329 !4 = !{i32 2, !"Debug Info Version", i32 3}
330 !5 = !{i32 1, !"wchar_size", i32 4}
331 !6 = !{i32 7, !"PIC Level", i32 2}
332 !7 = !{!"clang version 7.0.0 (trunk 331069)"}
333 !8 = distinct !DISubprogram(name: "and_shl_dbg", scope: !1, file: !1, line: 1, type: !9, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: true, unit: !0, retainedNodes: !12)
334 !9 = !DISubroutineType(types: !10)
335 !10 = !{!11, !11, !11, !11, !11}
336 !11 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
337 !12 = !{!13, !14, !15, !16, !17, !18, !19, !20}
338 !13 = !DILocalVariable(name: "x", arg: 1, scope: !8, file: !1, line: 1, type: !11)
339 !14 = !DILocalVariable(name: "y", arg: 2, scope: !8, file: !1, line: 1, type: !11)
340 !15 = !DILocalVariable(name: "z", arg: 3, scope: !8, file: !1, line: 1, type: !11)
341 !16 = !DILocalVariable(name: "shamt", arg: 4, scope: !8, file: !1, line: 1, type: !11)
342 !17 = !DILocalVariable(name: "sx", scope: !8, file: !1, line: 2, type: !11)
343 !18 = !DILocalVariable(name: "sy", scope: !8, file: !1, line: 3, type: !11)
344 !19 = !DILocalVariable(name: "a", scope: !8, file: !1, line: 4, type: !11)
345 !20 = !DILocalVariable(name: "r", scope: !8, file: !1, line: 5, type: !11)
346 !21 = !DILocation(line: 1, column: 21, scope: !8)
347 !22 = !DILocation(line: 1, column: 28, scope: !8)
348 !23 = !DILocation(line: 1, column: 35, scope: !8)
349 !24 = !DILocation(line: 1, column: 42, scope: !8)
350 !25 = !DILocation(line: 2, column: 14, scope: !8)
351 !26 = !DILocation(line: 2, column: 7, scope: !8)
352 !27 = !DILocation(line: 3, column: 14, scope: !8)
353 !28 = !DILocation(line: 3, column: 7, scope: !8)
354 !29 = !DILocation(line: 4, column: 14, scope: !8)
355 !30 = !DILocation(line: 4, column: 7, scope: !8)
356 !31 = !DILocation(line: 5, column: 14, scope: !8)
357 !32 = !DILocation(line: 5, column: 7, scope: !8)
358 !33 = !DILocation(line: 6, column: 3, scope: !8)