1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5
; RUN: opt < %s -passes=instcombine -S | FileCheck %s
declare void @use(i8 %value);
; Since we know that any comparison of ucmp/scmp with a constant will result in
; a comparison of ucmp/scmp's operands, we can propagate such a comparison
; through the phi node and let the next iteration of instcombine simplify it.
define i1 @icmp_of_phi_of_scmp_with_constant(i1 %c, i16 %x, i16 %y)
; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_constant(
; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]]
; CHECK: [[TRUE]]:
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i16 [[X]], [[Y]]
; CHECK-NEXT: br label %[[EXIT:.*]]
; CHECK: [[FALSE]]:
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i16 [[Y]], [[X]]
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[R:%.*]] = phi i1 [ [[TMP0]], %[[TRUE]] ], [ [[TMP1]], %[[FALSE]] ]
; CHECK-NEXT: ret i1 [[R]]
;
{
entry:
br i1 %c, label %true, label %false
true:
%cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y)
br label %exit
false:
%cmp2 = call i8 @llvm.scmp(i16 %y, i16 %x)
br label %exit
exit:
%phi = phi i8 [%cmp1, %true], [%cmp2, %false]
%r = icmp slt i8 %phi, 0
ret i1 %r
}
; When one of the incoming values is ucmp/scmp and the other is not we can still perform the transformation
define i1 @icmp_of_phi_of_one_scmp_with_constant(i1 %c, i16 %x, i16 %y, i8 %false_val)
; CHECK-LABEL: define i1 @icmp_of_phi_of_one_scmp_with_constant(
; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]], i8 [[FALSE_VAL:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]]
; CHECK: [[TRUE]]:
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i16 [[X]], [[Y]]
; CHECK-NEXT: br label %[[EXIT:.*]]
; CHECK: [[FALSE]]:
; CHECK-NEXT: [[TMP1:%.*]] = icmp slt i8 [[FALSE_VAL]], 0
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[PHI:%.*]] = phi i1 [ [[TMP0]], %[[TRUE]] ], [ [[TMP1]], %[[FALSE]] ]
; CHECK-NEXT: ret i1 [[PHI]]
;
{
entry:
br i1 %c, label %true, label %false
true:
%cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y)
br label %exit
false:
br label %exit
exit:
%phi = phi i8 [%cmp1, %true], [%false_val, %false]
%r = icmp slt i8 %phi, 0
ret i1 %r
}
; Negative test: the RHS of comparison that uses the phi node is not constant
define i1 @icmp_of_phi_of_scmp_with_non_constant(i1 %c, i16 %x, i16 %y, i8 %cmp)
; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_non_constant(
; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]], i8 [[CMP:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]]
; CHECK: [[TRUE]]:
; CHECK-NEXT: [[CMP1:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[X]], i16 [[Y]])
; CHECK-NEXT: br label %[[EXIT:.*]]
; CHECK: [[FALSE]]:
; CHECK-NEXT: [[CMP2:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[Y]], i16 [[X]])
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[PHI:%.*]] = phi i8 [ [[CMP1]], %[[TRUE]] ], [ [[CMP2]], %[[FALSE]] ]
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[PHI]], [[CMP]]
; CHECK-NEXT: ret i1 [[R]]
;
{
entry:
br i1 %c, label %true, label %false
true:
%cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y)
br label %exit
false:
%cmp2 = call i8 @llvm.scmp(i16 %y, i16 %x)
br label %exit
exit:
%phi = phi i8 [%cmp1, %true], [%cmp2, %false]
%r = icmp slt i8 %phi, %cmp
ret i1 %r
}
; Negative test: more than one incoming value of the phi node is not one-use
define i1 @icmp_of_phi_of_scmp_with_constant_not_one_use(i1 %c, i16 %x, i16 %y)
; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_constant_not_one_use(
; CHECK-SAME: i1 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*:]]
; CHECK-NEXT: br i1 [[C]], label %[[TRUE:.*]], label %[[FALSE:.*]]
; CHECK: [[TRUE]]:
; CHECK-NEXT: [[CMP1:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[X]], i16 [[Y]])
; CHECK-NEXT: call void @use(i8 [[CMP1]])
; CHECK-NEXT: br label %[[EXIT:.*]]
; CHECK: [[FALSE]]:
; CHECK-NEXT: [[CMP2:%.*]] = call i8 @llvm.scmp.i8.i16(i16 [[Y]], i16 [[X]])
; CHECK-NEXT: call void @use(i8 [[CMP2]])
; CHECK-NEXT: br label %[[EXIT]]
; CHECK: [[EXIT]]:
; CHECK-NEXT: [[PHI:%.*]] = phi i8 [ [[CMP1]], %[[TRUE]] ], [ [[CMP2]], %[[FALSE]] ]
; CHECK-NEXT: [[R:%.*]] = icmp slt i8 [[PHI]], 0
; CHECK-NEXT: ret i1 [[R]]
;
{
entry:
br i1 %c, label %true, label %false
true:
%cmp1 = call i8 @llvm.scmp(i16 %x, i16 %y)
call void @use(i8 %cmp1)
br label %exit
false:
%cmp2 = call i8 @llvm.scmp(i16 %y, i16 %x)
call void @use(i8 %cmp2)
br label %exit
exit:
%phi = phi i8 [%cmp1, %true], [%cmp2, %false]
%r = icmp slt i8 %phi, 0
ret i1 %r
}
; Same as the first transformation, but the phi node uses the result of scmp twice. This verifies that we don't clone values more than once per block
define i1 @icmp_of_phi_of_scmp_with_constant_one_user_two_uses(i8 %c, i16 %x, i16 %y, i8 %false_val) {
; CHECK-LABEL: define i1 @icmp_of_phi_of_scmp_with_constant_one_user_two_uses(
; CHECK-SAME: i8 [[C:%.*]], i16 [[X:%.*]], i16 [[Y:%.*]], i8 [[FALSE_VAL:%.*]]) {
; CHECK-NEXT: [[ENTRY:.*]]:
; CHECK-NEXT: [[TMP0:%.*]] = icmp slt i16 [[X]], [[Y]]
; CHECK-NEXT: switch i8 [[C]], label %[[BB_2:.*]] [
; CHECK-NEXT: i8 0, label %[[BB:.*]]
; CHECK-NEXT: i8 1, label %[[BB]]
; CHECK-NEXT: ]
; CHECK: [[BB_2]]:
; CHECK-NEXT: br label %[[BB]]
; CHECK: [[BB]]:
; CHECK-NEXT: [[R:%.*]] = phi i1 [ [[TMP0]], %[[ENTRY]] ], [ [[TMP0]], %[[ENTRY]] ], [ false, %[[BB_2]] ]
; CHECK-NEXT: ret i1 [[R]]
;
entry:
%cmp = call i8 @llvm.scmp(i16 %x, i16 %y)
switch i8 %c, label %bb_2 [
i8 0, label %bb
i8 1, label %bb
]
bb_2:
br label %bb
bb:
%phi = phi i8 [ %cmp, %entry ], [ %cmp, %entry ], [ 0, %bb_2 ]
%r = icmp slt i8 %phi, 0
ret i1 %r
}
|