1 ; Test memory-to-memory ANDs. 2 ; 3 ; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s 4 5 @g1src = global i8 1 6 @g1dst = global i8 1 7 @g2src = global i16 2 8 @g2dst = global i16 2 9 10 ; Test the simple i8 case. 11 define void @f1(i8 *%ptr1) { 12 ; CHECK-LABEL: f1: 13 ; CHECK: nc 1(1,%r2), 0(%r2) 14 ; CHECK: br %r14 15 %ptr2 = getelementptr i8 *%ptr1, i64 1 16 %val = load i8 *%ptr1 17 %old = load i8 *%ptr2 18 %and = and i8 %val, %old 19 store i8 %and, i8 *%ptr2 20 ret void 21 } 22 23 ; ...and again in reverse. 24 define void @f2(i8 *%ptr1) { 25 ; CHECK-LABEL: f2: 26 ; CHECK: nc 1(1,%r2), 0(%r2) 27 ; CHECK: br %r14 28 %ptr2 = getelementptr i8 *%ptr1, i64 1 29 %val = load i8 *%ptr1 30 %old = load i8 *%ptr2 31 %and = and i8 %old, %val 32 store i8 %and, i8 *%ptr2 33 ret void 34 } 35 36 ; Test i8 cases where one value is zero-extended to 32 bits and the other 37 ; sign-extended. 38 define void @f3(i8 *%ptr1) { 39 ; CHECK-LABEL: f3: 40 ; CHECK: nc 1(1,%r2), 0(%r2) 41 ; CHECK: br %r14 42 %ptr2 = getelementptr i8 *%ptr1, i64 1 43 %val = load i8 *%ptr1 44 %extval = zext i8 %val to i32 45 %old = load i8 *%ptr2 46 %extold = sext i8 %old to i32 47 %and = and i32 %extval, %extold 48 %trunc = trunc i32 %and to i8 49 store i8 %trunc, i8 *%ptr2 50 ret void 51 } 52 53 ; ...and again with the extension types reversed. 54 define void @f4(i8 *%ptr1) { 55 ; CHECK-LABEL: f4: 56 ; CHECK: nc 1(1,%r2), 0(%r2) 57 ; CHECK: br %r14 58 %ptr2 = getelementptr i8 *%ptr1, i64 1 59 %val = load i8 *%ptr1 60 %extval = sext i8 %val to i32 61 %old = load i8 *%ptr2 62 %extold = zext i8 %old to i32 63 %and = and i32 %extval, %extold 64 %trunc = trunc i32 %and to i8 65 store i8 %trunc, i8 *%ptr2 66 ret void 67 } 68 69 ; ...and again with two sign extensions. 70 define void @f5(i8 *%ptr1) { 71 ; CHECK-LABEL: f5: 72 ; CHECK: nc 1(1,%r2), 0(%r2) 73 ; CHECK: br %r14 74 %ptr2 = getelementptr i8 *%ptr1, i64 1 75 %val = load i8 *%ptr1 76 %extval = sext i8 %val to i32 77 %old = load i8 *%ptr2 78 %extold = sext i8 %old to i32 79 %and = and i32 %extval, %extold 80 %trunc = trunc i32 %and to i8 81 store i8 %trunc, i8 *%ptr2 82 ret void 83 } 84 85 ; ...and again with two zero extensions. 86 define void @f6(i8 *%ptr1) { 87 ; CHECK-LABEL: f6: 88 ; CHECK: nc 1(1,%r2), 0(%r2) 89 ; CHECK: br %r14 90 %ptr2 = getelementptr i8 *%ptr1, i64 1 91 %val = load i8 *%ptr1 92 %extval = zext i8 %val to i32 93 %old = load i8 *%ptr2 94 %extold = zext i8 %old to i32 95 %and = and i32 %extval, %extold 96 %trunc = trunc i32 %and to i8 97 store i8 %trunc, i8 *%ptr2 98 ret void 99 } 100 101 ; Test i8 cases where the value is extended to 64 bits (just one case 102 ; this time). 103 define void @f7(i8 *%ptr1) { 104 ; CHECK-LABEL: f7: 105 ; CHECK: nc 1(1,%r2), 0(%r2) 106 ; CHECK: br %r14 107 %ptr2 = getelementptr i8 *%ptr1, i64 1 108 %val = load i8 *%ptr1 109 %extval = sext i8 %val to i64 110 %old = load i8 *%ptr2 111 %extold = zext i8 %old to i64 112 %and = and i64 %extval, %extold 113 %trunc = trunc i64 %and to i8 114 store i8 %trunc, i8 *%ptr2 115 ret void 116 } 117 118 ; Test the simple i16 case. 119 define void @f8(i16 *%ptr1) { 120 ; CHECK-LABEL: f8: 121 ; CHECK: nc 2(2,%r2), 0(%r2) 122 ; CHECK: br %r14 123 %ptr2 = getelementptr i16 *%ptr1, i64 1 124 %val = load i16 *%ptr1 125 %old = load i16 *%ptr2 126 %and = and i16 %val, %old 127 store i16 %and, i16 *%ptr2 128 ret void 129 } 130 131 ; Test i16 cases where the value is extended to 32 bits. 132 define void @f9(i16 *%ptr1) { 133 ; CHECK-LABEL: f9: 134 ; CHECK: nc 2(2,%r2), 0(%r2) 135 ; CHECK: br %r14 136 %ptr2 = getelementptr i16 *%ptr1, i64 1 137 %val = load i16 *%ptr1 138 %extval = zext i16 %val to i32 139 %old = load i16 *%ptr2 140 %extold = sext i16 %old to i32 141 %and = and i32 %extval, %extold 142 %trunc = trunc i32 %and to i16 143 store i16 %trunc, i16 *%ptr2 144 ret void 145 } 146 147 ; Test i16 cases where the value is extended to 64 bits. 148 define void @f10(i16 *%ptr1) { 149 ; CHECK-LABEL: f10: 150 ; CHECK: nc 2(2,%r2), 0(%r2) 151 ; CHECK: br %r14 152 %ptr2 = getelementptr i16 *%ptr1, i64 1 153 %val = load i16 *%ptr1 154 %extval = sext i16 %val to i64 155 %old = load i16 *%ptr2 156 %extold = zext i16 %old to i64 157 %and = and i64 %extval, %extold 158 %trunc = trunc i64 %and to i16 159 store i16 %trunc, i16 *%ptr2 160 ret void 161 } 162 163 ; Test the simple i32 case. 164 define void @f11(i32 *%ptr1) { 165 ; CHECK-LABEL: f11: 166 ; CHECK: nc 4(4,%r2), 0(%r2) 167 ; CHECK: br %r14 168 %ptr2 = getelementptr i32 *%ptr1, i64 1 169 %val = load i32 *%ptr1 170 %old = load i32 *%ptr2 171 %and = and i32 %old, %val 172 store i32 %and, i32 *%ptr2 173 ret void 174 } 175 176 ; Test i32 cases where the value is extended to 64 bits. 177 define void @f12(i32 *%ptr1) { 178 ; CHECK-LABEL: f12: 179 ; CHECK: nc 4(4,%r2), 0(%r2) 180 ; CHECK: br %r14 181 %ptr2 = getelementptr i32 *%ptr1, i64 1 182 %val = load i32 *%ptr1 183 %extval = sext i32 %val to i64 184 %old = load i32 *%ptr2 185 %extold = zext i32 %old to i64 186 %and = and i64 %extval, %extold 187 %trunc = trunc i64 %and to i32 188 store i32 %trunc, i32 *%ptr2 189 ret void 190 } 191 192 ; Test the i64 case. 193 define void @f13(i64 *%ptr1) { 194 ; CHECK-LABEL: f13: 195 ; CHECK: nc 8(8,%r2), 0(%r2) 196 ; CHECK: br %r14 197 %ptr2 = getelementptr i64 *%ptr1, i64 1 198 %val = load i64 *%ptr1 199 %old = load i64 *%ptr2 200 %and = and i64 %old, %val 201 store i64 %and, i64 *%ptr2 202 ret void 203 } 204 205 ; Make sure that we don't use NC if the first load is volatile. 206 define void @f14(i64 *%ptr1) { 207 ; CHECK-LABEL: f14: 208 ; CHECK-NOT: nc 209 ; CHECK: br %r14 210 %ptr2 = getelementptr i64 *%ptr1, i64 1 211 %val = load volatile i64 *%ptr1 212 %old = load i64 *%ptr2 213 %and = and i64 %old, %val 214 store i64 %and, i64 *%ptr2 215 ret void 216 } 217 218 ; ...likewise the second. 219 define void @f15(i64 *%ptr1) { 220 ; CHECK-LABEL: f15: 221 ; CHECK-NOT: nc 222 ; CHECK: br %r14 223 %ptr2 = getelementptr i64 *%ptr1, i64 1 224 %val = load i64 *%ptr1 225 %old = load volatile i64 *%ptr2 226 %and = and i64 %old, %val 227 store i64 %and, i64 *%ptr2 228 ret void 229 } 230 231 ; ...likewise the store. 232 define void @f16(i64 *%ptr1) { 233 ; CHECK-LABEL: f16: 234 ; CHECK-NOT: nc 235 ; CHECK: br %r14 236 %ptr2 = getelementptr i64 *%ptr1, i64 1 237 %val = load i64 *%ptr1 238 %old = load i64 *%ptr2 239 %and = and i64 %old, %val 240 store volatile i64 %and, i64 *%ptr2 241 ret void 242 } 243 244 ; Test that NC is not used for aligned loads and stores if there is 245 ; no way of telling whether they alias. We don't want to use NC in 246 ; cases where the addresses could be equal. 247 define void @f17(i64 *%ptr1, i64 *%ptr2) { 248 ; CHECK-LABEL: f17: 249 ; CHECK-NOT: nc 250 ; CHECK: br %r14 251 %val = load i64 *%ptr1 252 %old = load i64 *%ptr2 253 %and = and i64 %old, %val 254 store i64 %and, i64 *%ptr2 255 ret void 256 } 257 258 ; ...but if one of the loads isn't aligned, we can't be sure. 259 define void @f18(i64 *%ptr1, i64 *%ptr2) { 260 ; CHECK-LABEL: f18: 261 ; CHECK-NOT: nc 262 ; CHECK: br %r14 263 %val = load i64 *%ptr1, align 2 264 %old = load i64 *%ptr2 265 %and = and i64 %old, %val 266 store i64 %and, i64 *%ptr2 267 ret void 268 } 269 270 ; Repeat the previous test with the operands in the opposite order. 271 define void @f19(i64 *%ptr1, i64 *%ptr2) { 272 ; CHECK-LABEL: f19: 273 ; CHECK-NOT: nc 274 ; CHECK: br %r14 275 %val = load i64 *%ptr1, align 2 276 %old = load i64 *%ptr2 277 %and = and i64 %val, %old 278 store i64 %and, i64 *%ptr2 279 ret void 280 } 281 282 ; ...and again with the other operand being unaligned. 283 define void @f20(i64 *%ptr1, i64 *%ptr2) { 284 ; CHECK-LABEL: f20: 285 ; CHECK-NOT: nc 286 ; CHECK: br %r14 287 %val = load i64 *%ptr1 288 %old = load i64 *%ptr2, align 2 289 %and = and i64 %val, %old 290 store i64 %and, i64 *%ptr2, align 2 291 ret void 292 } 293 294 ; Test a case where there is definite overlap. 295 define void @f21(i64 %base) { 296 ; CHECK-LABEL: f21: 297 ; CHECK-NOT: nc 298 ; CHECK: br %r14 299 %add = add i64 %base, 1 300 %ptr1 = inttoptr i64 %base to i64 * 301 %ptr2 = inttoptr i64 %add to i64 * 302 %val = load i64 *%ptr1 303 %old = load i64 *%ptr2, align 1 304 %and = and i64 %old, %val 305 store i64 %and, i64 *%ptr2, align 1 306 ret void 307 } 308 309 ; Test that we can use NC for global addresses for i8. 310 define void @f22(i8 *%ptr) { 311 ; CHECK-LABEL: f22: 312 ; CHECK-DAG: larl [[SRC:%r[0-5]]], g1src 313 ; CHECK-DAG: larl [[DST:%r[0-5]]], g1dst 314 ; CHECK: nc 0(1,[[DST]]), 0([[SRC]]) 315 ; CHECK: br %r14 316 %val = load i8 *@g1src 317 %old = load i8 *@g1dst 318 %and = and i8 %val, %old 319 store i8 %and, i8 *@g1dst 320 ret void 321 } 322 323 ; Test that we use NC even where LHRL and STHRL are available. 324 define void @f23(i16 *%ptr) { 325 ; CHECK-LABEL: f23: 326 ; CHECK-DAG: larl [[SRC:%r[0-5]]], g2src 327 ; CHECK-DAG: larl [[DST:%r[0-5]]], g2dst 328 ; CHECK: nc 0(2,[[DST]]), 0([[SRC]]) 329 ; CHECK: br %r14 330 %val = load i16 *@g2src 331 %old = load i16 *@g2dst 332 %and = and i16 %val, %old 333 store i16 %and, i16 *@g2dst 334 ret void 335 } 336 337 ; Test a case where offset disambiguation is enough. 338 define void @f24(i64 *%ptr1) { 339 ; CHECK-LABEL: f24: 340 ; CHECK: nc 8(8,%r2), 0(%r2) 341 ; CHECK: br %r14 342 %ptr2 = getelementptr i64 *%ptr1, i64 1 343 %val = load i64 *%ptr1, align 1 344 %old = load i64 *%ptr2, align 1 345 %and = and i64 %old, %val 346 store i64 %and, i64 *%ptr2, align 1 347 ret void 348 } 349 350 ; Test a case where TBAA tells us there is no alias. 351 define void @f25(i64 *%ptr1, i64 *%ptr2) { 352 ; CHECK-LABEL: f25: 353 ; CHECK: nc 0(8,%r3), 0(%r2) 354 ; CHECK: br %r14 355 %val = load i64 *%ptr1, align 2, !tbaa !3 356 %old = load i64 *%ptr2, align 2, !tbaa !4 357 %and = and i64 %old, %val 358 store i64 %and, i64 *%ptr2, align 2, !tbaa !4 359 ret void 360 } 361 362 ; Test a case where TBAA information is present but doesn't help. 363 define void @f26(i64 *%ptr1, i64 *%ptr2) { 364 ; CHECK-LABEL: f26: 365 ; CHECK-NOT: nc 366 ; CHECK: br %r14 367 %val = load i64 *%ptr1, align 2, !tbaa !3 368 %old = load i64 *%ptr2, align 2, !tbaa !3 369 %and = and i64 %old, %val 370 store i64 %and, i64 *%ptr2, align 2, !tbaa !3 371 ret void 372 } 373 374 !0 = metadata !{ metadata !"root" } 375 !1 = metadata !{ metadata !"set1", metadata !0 } 376 !2 = metadata !{ metadata !"set2", metadata !0 } 377 !3 = metadata !{ metadata !1, metadata !1, i64 0} 378 !4 = metadata !{ metadata !2, metadata !2, i64 0} 379