xref: /llvm-project/llvm/test/Transforms/InstCombine/usubo.ll (revision e5748c6e73e7a3173046002b1f9a556965552c37)
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
2; RUN: opt < %s -passes=instcombine -S | FileCheck %s
3
4declare { i64, i1 } @llvm.usub.with.overflow.i64(i64, i64)
5declare { i8, i1 } @llvm.usub.with.overflow.i8(i8, i8)
6
7declare void @use(i1)
8
9define i1 @test_generic(i64 %a, i64 %b) {
10; CHECK-LABEL: @test_generic(
11; CHECK-NEXT:    [[OVERFLOW:%.*]] = icmp ult i64 [[A:%.*]], [[B:%.*]]
12; CHECK-NEXT:    ret i1 [[OVERFLOW]]
13;
14  %res = tail call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
15  %overflow = extractvalue { i64, i1 } %res, 1
16  ret i1 %overflow
17}
18
19define i1 @test_constant0(i8 %a) {
20; CHECK-LABEL: @test_constant0(
21; CHECK-NEXT:    ret i1 false
22;
23  %res = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %a, i8 0)
24  %overflow = extractvalue { i8, i1 } %res, 1
25  ret i1 %overflow
26}
27
28define i1 @test_constant1(i8 %a) {
29; CHECK-LABEL: @test_constant1(
30; CHECK-NEXT:    [[OVERFLOW:%.*]] = icmp eq i8 [[A:%.*]], 0
31; CHECK-NEXT:    ret i1 [[OVERFLOW]]
32;
33  %res = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %a, i8 1)
34  %overflow = extractvalue { i8, i1 } %res, 1
35  ret i1 %overflow
36}
37
38define i1 @test_constant2(i8 %a) {
39; CHECK-LABEL: @test_constant2(
40; CHECK-NEXT:    [[OVERFLOW:%.*]] = icmp ult i8 [[A:%.*]], 2
41; CHECK-NEXT:    ret i1 [[OVERFLOW]]
42;
43  %res = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %a, i8 2)
44  %overflow = extractvalue { i8, i1 } %res, 1
45  ret i1 %overflow
46}
47
48define i1 @test_constant3(i8 %a) {
49; CHECK-LABEL: @test_constant3(
50; CHECK-NEXT:    [[OVERFLOW:%.*]] = icmp ult i8 [[A:%.*]], 3
51; CHECK-NEXT:    ret i1 [[OVERFLOW]]
52;
53  %res = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %a, i8 3)
54  %overflow = extractvalue { i8, i1 } %res, 1
55  ret i1 %overflow
56}
57
58define i1 @test_constant4(i8 %a) {
59; CHECK-LABEL: @test_constant4(
60; CHECK-NEXT:    [[OVERFLOW:%.*]] = icmp ult i8 [[A:%.*]], 4
61; CHECK-NEXT:    ret i1 [[OVERFLOW]]
62;
63  %res = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %a, i8 4)
64  %overflow = extractvalue { i8, i1 } %res, 1
65  ret i1 %overflow
66}
67
68
69define i1 @test_constant127(i8 %a) {
70; CHECK-LABEL: @test_constant127(
71; CHECK-NEXT:    [[OVERFLOW:%.*]] = icmp ult i8 [[A:%.*]], 127
72; CHECK-NEXT:    ret i1 [[OVERFLOW]]
73;
74  %res = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %a, i8 127)
75  %overflow = extractvalue { i8, i1 } %res, 1
76  ret i1 %overflow
77}
78
79define i1 @test_constant128(i8 %a) {
80; CHECK-LABEL: @test_constant128(
81; CHECK-NEXT:    [[OVERFLOW:%.*]] = icmp sgt i8 [[A:%.*]], -1
82; CHECK-NEXT:    ret i1 [[OVERFLOW]]
83;
84  %res = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %a, i8 128)
85  %overflow = extractvalue { i8, i1 } %res, 1
86  ret i1 %overflow
87}
88
89define i1 @test_constant255(i8 %a) {
90; CHECK-LABEL: @test_constant255(
91; CHECK-NEXT:    [[OVERFLOW:%.*]] = icmp ne i8 [[A:%.*]], -1
92; CHECK-NEXT:    ret i1 [[OVERFLOW]]
93;
94  %res = tail call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %a, i8 255)
95  %overflow = extractvalue { i8, i1 } %res, 1
96  ret i1 %overflow
97}
98
99define i1 @sub_eq0(i8 %x, i8 %y, i1 %b) {
100; CHECK-LABEL: @sub_eq0(
101; CHECK-NEXT:    [[OV:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]]
102; CHECK-NEXT:    call void @use(i1 [[OV]])
103; CHECK-NEXT:    [[EQ0:%.*]] = icmp eq i8 [[X]], [[Y]]
104; CHECK-NEXT:    ret i1 [[EQ0]]
105;
106  %us = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
107  %ov = extractvalue { i8, i1 } %us, 1
108  call void @use(i1 %ov)
109  %sub = extractvalue { i8, i1 } %us, 0
110  %eq0 = icmp eq i8 %sub, 0
111  ret i1 %eq0
112}
113
114define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) {
115; CHECK-LABEL: @sub_ne0(
116; CHECK-NEXT:    [[OV:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]]
117; CHECK-NEXT:    call void @use(i1 [[OV]])
118; CHECK-NEXT:    [[NE0:%.*]] = icmp ne i8 [[X]], [[Y]]
119; CHECK-NEXT:    ret i1 [[NE0]]
120;
121  %us = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
122  %ov = extractvalue { i8, i1 } %us, 1
123  call void @use(i1 %ov)
124  %sub = extractvalue { i8, i1 } %us, 0
125  %ne0 = icmp ne i8 %sub, 0
126  ret i1 %ne0
127}
128
129; negative test - need zero
130
131define i1 @sub_eq1(i8 %x, i8 %y, i1 %b) {
132; CHECK-LABEL: @sub_eq1(
133; CHECK-NEXT:    [[SS:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
134; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1
135; CHECK-NEXT:    call void @use(i1 [[OV]])
136; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0
137; CHECK-NEXT:    [[EQ1:%.*]] = icmp eq i8 [[SUB]], 1
138; CHECK-NEXT:    ret i1 [[EQ1]]
139;
140  %ss = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
141  %ov = extractvalue { i8, i1 } %ss, 1
142  call void @use(i1 %ov)
143  %sub = extractvalue { i8, i1 } %ss, 0
144  %eq1 = icmp eq i8 %sub, 1
145  ret i1 %eq1
146}
147
148; negative test - need equality pred
149
150define i1 @sub_sgt0(i8 %x, i8 %y, i1 %b) {
151; CHECK-LABEL: @sub_sgt0(
152; CHECK-NEXT:    [[SS:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]])
153; CHECK-NEXT:    [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1
154; CHECK-NEXT:    call void @use(i1 [[OV]])
155; CHECK-NEXT:    [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0
156; CHECK-NEXT:    [[SGT0:%.*]] = icmp sgt i8 [[SUB]], 0
157; CHECK-NEXT:    ret i1 [[SGT0]]
158;
159  %ss = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y)
160  %ov = extractvalue { i8, i1 } %ss, 1
161  call void @use(i1 %ov)
162  %sub = extractvalue { i8, i1 } %ss, 0
163  %sgt0 = icmp sgt i8 %sub, 0
164  ret i1 %sgt0
165}
166