Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 1 | ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py |
| 2 | ; RUN: opt < %s -instcombine -S | FileCheck %s |
| 3 | |
| 4 | ; If we have a masked merge, in the form of: (M is constant) |
| 5 | ; ((x ^ y) & M) ^ y |
| 6 | ; Unfold it to |
| 7 | ; (x & M) | (y & ~M) |
| 8 | |
| 9 | define i4 @scalar0 (i4 %x, i4 %y) { |
| 10 | ; CHECK-LABEL: @scalar0( |
Roman Lebedev | aa4faec | 2018-04-30 17:59:33 +0000 | [diff] [blame] | 11 | ; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X:%.*]], 1 |
| 12 | ; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y:%.*]], -2 |
| 13 | ; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]] |
Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 14 | ; CHECK-NEXT: ret i4 [[R]] |
| 15 | ; |
| 16 | %n0 = xor i4 %x, %y |
| 17 | %n1 = and i4 %n0, 1 |
| 18 | %r = xor i4 %n1, %y |
| 19 | ret i4 %r |
| 20 | } |
| 21 | |
| 22 | define i4 @scalar1 (i4 %x, i4 %y) { |
| 23 | ; CHECK-LABEL: @scalar1( |
Roman Lebedev | aa4faec | 2018-04-30 17:59:33 +0000 | [diff] [blame] | 24 | ; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X:%.*]], -2 |
| 25 | ; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y:%.*]], 1 |
| 26 | ; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]] |
Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 27 | ; CHECK-NEXT: ret i4 [[R]] |
| 28 | ; |
| 29 | %n0 = xor i4 %x, %y |
| 30 | %n1 = and i4 %n0, -2 |
| 31 | %r = xor i4 %n1, %y |
| 32 | ret i4 %r |
| 33 | } |
| 34 | |
| 35 | ; ============================================================================ ; |
| 36 | ; Various cases with %x and/or %y being a constant |
| 37 | ; ============================================================================ ; |
| 38 | |
| 39 | define i4 @in_constant_varx_mone(i4 %x, i4 %mask) { |
| 40 | ; CHECK-LABEL: @in_constant_varx_mone( |
| 41 | ; CHECK-NEXT: [[R1:%.*]] = or i4 [[X:%.*]], -2 |
| 42 | ; CHECK-NEXT: ret i4 [[R1]] |
| 43 | ; |
| 44 | %n0 = xor i4 %x, -1 ; %x |
| 45 | %n1 = and i4 %n0, 1 |
| 46 | %r = xor i4 %n1, -1 |
| 47 | ret i4 %r |
| 48 | } |
| 49 | |
| 50 | define i4 @in_constant_varx_14(i4 %x, i4 %mask) { |
| 51 | ; CHECK-LABEL: @in_constant_varx_14( |
| 52 | ; CHECK-NEXT: [[R1:%.*]] = or i4 [[X:%.*]], -2 |
| 53 | ; CHECK-NEXT: ret i4 [[R1]] |
| 54 | ; |
| 55 | %n0 = xor i4 %x, 14 ; %x |
| 56 | %n1 = and i4 %n0, 1 |
| 57 | %r = xor i4 %n1, 14 |
| 58 | ret i4 %r |
| 59 | } |
| 60 | |
| 61 | define i4 @in_constant_mone_vary(i4 %y, i4 %mask) { |
| 62 | ; CHECK-LABEL: @in_constant_mone_vary( |
| 63 | ; CHECK-NEXT: [[N0:%.*]] = and i4 [[Y:%.*]], 1 |
| 64 | ; CHECK-NEXT: [[N1:%.*]] = xor i4 [[N0]], 1 |
| 65 | ; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]] |
| 66 | ; CHECK-NEXT: ret i4 [[R]] |
| 67 | ; |
| 68 | %n0 = xor i4 %y, -1 ; %x |
| 69 | %n1 = and i4 %n0, 1 |
| 70 | %r = xor i4 %n1, %y |
| 71 | ret i4 %r |
| 72 | } |
| 73 | |
| 74 | define i4 @in_constant_14_vary(i4 %y, i4 %mask) { |
| 75 | ; CHECK-LABEL: @in_constant_14_vary( |
| 76 | ; CHECK-NEXT: [[R:%.*]] = and i4 [[Y:%.*]], -2 |
| 77 | ; CHECK-NEXT: ret i4 [[R]] |
| 78 | ; |
| 79 | %n0 = xor i4 %y, 14 ; %x |
| 80 | %n1 = and i4 %n0, 1 |
| 81 | %r = xor i4 %n1, %y |
| 82 | ret i4 %r |
| 83 | } |
| 84 | |
| 85 | ; ============================================================================ ; |
| 86 | ; Commutativity |
| 87 | ; ============================================================================ ; |
| 88 | |
| 89 | ; Used to make sure that the IR complexity sorting does not interfere. |
| 90 | declare i4 @gen4() |
| 91 | |
| 92 | define i4 @c_1_0_0 (i4 %x, i4 %y) { |
| 93 | ; CHECK-LABEL: @c_1_0_0( |
Roman Lebedev | aa4faec | 2018-04-30 17:59:33 +0000 | [diff] [blame] | 94 | ; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X:%.*]], -2 |
| 95 | ; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y:%.*]], 1 |
| 96 | ; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]] |
Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 97 | ; CHECK-NEXT: ret i4 [[R]] |
| 98 | ; |
| 99 | %n0 = xor i4 %y, %x ; swapped order |
| 100 | %n1 = and i4 %n0, -2 |
| 101 | %r = xor i4 %n1, %y |
| 102 | ret i4 %r |
| 103 | } |
| 104 | |
| 105 | define i4 @c_0_1_0 (i4 %x, i4 %y) { |
| 106 | ; CHECK-LABEL: @c_0_1_0( |
Roman Lebedev | aa4faec | 2018-04-30 17:59:33 +0000 | [diff] [blame] | 107 | ; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[Y:%.*]], -2 |
| 108 | ; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[X:%.*]], 1 |
| 109 | ; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]] |
Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 110 | ; CHECK-NEXT: ret i4 [[R]] |
| 111 | ; |
| 112 | %n0 = xor i4 %x, %y |
| 113 | %n1 = and i4 %n0, -2 |
| 114 | %r = xor i4 %n1, %x ; %x instead of %y |
| 115 | ret i4 %r |
| 116 | } |
| 117 | |
| 118 | define i4 @c_0_0_1 () { |
| 119 | ; CHECK-LABEL: @c_0_0_1( |
| 120 | ; CHECK-NEXT: [[X:%.*]] = call i4 @gen4() |
| 121 | ; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4() |
Roman Lebedev | aa4faec | 2018-04-30 17:59:33 +0000 | [diff] [blame] | 122 | ; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X]], -2 |
| 123 | ; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y]], 1 |
| 124 | ; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]] |
Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 125 | ; CHECK-NEXT: ret i4 [[R]] |
| 126 | ; |
| 127 | %x = call i4 @gen4() |
| 128 | %y = call i4 @gen4() |
| 129 | %n0 = xor i4 %x, %y |
| 130 | %n1 = and i4 %n0, -2 |
| 131 | %r = xor i4 %y, %n1 ; swapped order |
| 132 | ret i4 %r |
| 133 | } |
| 134 | |
| 135 | define i4 @c_1_1_0 (i4 %x, i4 %y) { |
| 136 | ; CHECK-LABEL: @c_1_1_0( |
Roman Lebedev | aa4faec | 2018-04-30 17:59:33 +0000 | [diff] [blame] | 137 | ; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[Y:%.*]], -2 |
| 138 | ; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[X:%.*]], 1 |
| 139 | ; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]] |
Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 140 | ; CHECK-NEXT: ret i4 [[R]] |
| 141 | ; |
| 142 | %n0 = xor i4 %y, %x ; swapped order |
| 143 | %n1 = and i4 %n0, -2 |
| 144 | %r = xor i4 %n1, %x ; %x instead of %y |
| 145 | ret i4 %r |
| 146 | } |
| 147 | |
| 148 | define i4 @c_1_0_1 (i4 %x) { |
| 149 | ; CHECK-LABEL: @c_1_0_1( |
| 150 | ; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4() |
Roman Lebedev | aa4faec | 2018-04-30 17:59:33 +0000 | [diff] [blame] | 151 | ; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[X:%.*]], -2 |
| 152 | ; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[Y]], 1 |
| 153 | ; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]] |
Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 154 | ; CHECK-NEXT: ret i4 [[R]] |
| 155 | ; |
| 156 | %y = call i4 @gen4() |
| 157 | %n0 = xor i4 %y, %x ; swapped order |
| 158 | %n1 = and i4 %n0, -2 |
| 159 | %r = xor i4 %y, %n1 ; swapped order |
| 160 | ret i4 %r |
| 161 | } |
| 162 | |
| 163 | define i4 @c_0_1_1 (i4 %y) { |
| 164 | ; CHECK-LABEL: @c_0_1_1( |
| 165 | ; CHECK-NEXT: [[X:%.*]] = call i4 @gen4() |
Roman Lebedev | aa4faec | 2018-04-30 17:59:33 +0000 | [diff] [blame] | 166 | ; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[Y:%.*]], -2 |
| 167 | ; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[X]], 1 |
| 168 | ; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]] |
Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 169 | ; CHECK-NEXT: ret i4 [[R]] |
| 170 | ; |
| 171 | %x = call i4 @gen4() |
| 172 | %n0 = xor i4 %x, %y |
| 173 | %n1 = and i4 %n0, -2 |
| 174 | %r = xor i4 %x, %n1 ; swapped order, %x instead of %y |
| 175 | ret i4 %r |
| 176 | } |
| 177 | |
| 178 | define i4 @c_1_1_1 () { |
| 179 | ; CHECK-LABEL: @c_1_1_1( |
| 180 | ; CHECK-NEXT: [[X:%.*]] = call i4 @gen4() |
| 181 | ; CHECK-NEXT: [[Y:%.*]] = call i4 @gen4() |
Roman Lebedev | aa4faec | 2018-04-30 17:59:33 +0000 | [diff] [blame] | 182 | ; CHECK-NEXT: [[TMP1:%.*]] = and i4 [[Y]], -2 |
| 183 | ; CHECK-NEXT: [[TMP2:%.*]] = and i4 [[X]], 1 |
| 184 | ; CHECK-NEXT: [[R:%.*]] = or i4 [[TMP1]], [[TMP2]] |
Roman Lebedev | b7ae4ef | 2018-04-30 17:59:26 +0000 | [diff] [blame] | 185 | ; CHECK-NEXT: ret i4 [[R]] |
| 186 | ; |
| 187 | %x = call i4 @gen4() |
| 188 | %y = call i4 @gen4() |
| 189 | %n0 = xor i4 %y, %x ; swapped order |
| 190 | %n1 = and i4 %n0, -2 |
| 191 | %r = xor i4 %x, %n1 ; swapped order, %x instead of %y |
| 192 | ret i4 %r |
| 193 | } |
| 194 | |
| 195 | define i4 @commutativity_constant_14_vary(i4 %y, i4 %mask) { |
| 196 | ; CHECK-LABEL: @commutativity_constant_14_vary( |
| 197 | ; CHECK-NEXT: [[R:%.*]] = and i4 [[Y:%.*]], -2 |
| 198 | ; CHECK-NEXT: ret i4 [[R]] |
| 199 | ; |
| 200 | %n0 = xor i4 %y, 14 ; %x |
| 201 | %n1 = and i4 %n0, 1 |
| 202 | %r = xor i4 %y, %n1 ; swapped |
| 203 | ret i4 %r |
| 204 | } |
| 205 | |
| 206 | ; ============================================================================ ; |
| 207 | ; Negative tests. Should not be folded. |
| 208 | ; ============================================================================ ; |
| 209 | |
| 210 | ; One use only. |
| 211 | |
| 212 | declare void @use4(i4) |
| 213 | |
| 214 | define i4 @n_oneuse_D (i4 %x, i4 %y) { |
| 215 | ; CHECK-LABEL: @n_oneuse_D( |
| 216 | ; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] |
| 217 | ; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], -2 |
| 218 | ; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]] |
| 219 | ; CHECK-NEXT: call void @use4(i4 [[N0]]) |
| 220 | ; CHECK-NEXT: ret i4 [[R]] |
| 221 | ; |
| 222 | %n0 = xor i4 %x, %y ; two uses of %n0, which is going to be replaced |
| 223 | %n1 = and i4 %n0, -2 |
| 224 | %r = xor i4 %n1, %y |
| 225 | call void @use4(i4 %n0) |
| 226 | ret i4 %r |
| 227 | } |
| 228 | |
| 229 | define i4 @n_oneuse_A (i4 %x, i4 %y) { |
| 230 | ; CHECK-LABEL: @n_oneuse_A( |
| 231 | ; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] |
| 232 | ; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], -2 |
| 233 | ; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]] |
| 234 | ; CHECK-NEXT: call void @use4(i4 [[N1]]) |
| 235 | ; CHECK-NEXT: ret i4 [[R]] |
| 236 | ; |
| 237 | %n0 = xor i4 %x, %y |
| 238 | %n1 = and i4 %n0, -2 ; two uses of %n1, which is going to be replaced |
| 239 | %r = xor i4 %n1, %y |
| 240 | call void @use4(i4 %n1) |
| 241 | ret i4 %r |
| 242 | } |
| 243 | |
| 244 | define i4 @n_oneuse_AD (i4 %x, i4 %y) { |
| 245 | ; CHECK-LABEL: @n_oneuse_AD( |
| 246 | ; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] |
| 247 | ; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], -2 |
| 248 | ; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]] |
| 249 | ; CHECK-NEXT: call void @use4(i4 [[N0]]) |
| 250 | ; CHECK-NEXT: call void @use4(i4 [[N1]]) |
| 251 | ; CHECK-NEXT: ret i4 [[R]] |
| 252 | ; |
| 253 | %n0 = xor i4 %x, %y |
| 254 | %n1 = and i4 %n0, -2 ; two uses of %n1, which is going to be replaced |
| 255 | %r = xor i4 %n1, %y |
| 256 | call void @use4(i4 %n0) |
| 257 | call void @use4(i4 %n1) |
| 258 | ret i4 %r |
| 259 | } |
| 260 | |
| 261 | ; Mask is not constant |
| 262 | |
| 263 | define i4 @n_var_mask (i4 %x, i4 %y, i4 %m) { |
| 264 | ; CHECK-LABEL: @n_var_mask( |
| 265 | ; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] |
| 266 | ; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], [[M:%.*]] |
| 267 | ; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Y]] |
| 268 | ; CHECK-NEXT: ret i4 [[R]] |
| 269 | ; |
| 270 | %n0 = xor i4 %x, %y |
| 271 | %n1 = and i4 %n0, %m |
| 272 | %r = xor i4 %n1, %y |
| 273 | ret i4 %r |
| 274 | } |
| 275 | |
| 276 | ; Some third variable is used |
| 277 | |
| 278 | define i4 @n_third_var (i4 %x, i4 %y, i4 %z) { |
| 279 | ; CHECK-LABEL: @n_third_var( |
| 280 | ; CHECK-NEXT: [[N0:%.*]] = xor i4 [[X:%.*]], [[Y:%.*]] |
| 281 | ; CHECK-NEXT: [[N1:%.*]] = and i4 [[N0]], -2 |
| 282 | ; CHECK-NEXT: [[R:%.*]] = xor i4 [[N1]], [[Z:%.*]] |
| 283 | ; CHECK-NEXT: ret i4 [[R]] |
| 284 | ; |
| 285 | %n0 = xor i4 %x, %y |
| 286 | %n1 = and i4 %n0, -2 |
| 287 | %r = xor i4 %n1, %z ; not %x or %y |
| 288 | ret i4 %r |
| 289 | } |