1; Verify that strict FP operations are not rescheduled 2; 3; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 | FileCheck %s 4 5declare float @llvm.experimental.constrained.sqrt.f32(float, metadata, metadata) 6declare float @llvm.sqrt.f32(float) 7declare void @llvm.s390.sfpc(i32) 8declare void @bar() 9 10; The basic assumption of all following tests is that on z13, we never 11; want to see two square root instructions directly in a row, so the 12; post-RA scheduler will always schedule something else in between 13; whenever possible. 14 15; We can move any FP operation across a (normal) store. 16 17define void @f1(float %f1, float %f2, ptr %ptr1, ptr %ptr2) { 18; CHECK-LABEL: f1: 19; CHECK: sqebr 20; CHECK: ste 21; CHECK: sqebr 22; CHECK: ste 23; CHECK: br %r14 24 25 %sqrt1 = call float @llvm.sqrt.f32(float %f1) 26 %sqrt2 = call float @llvm.sqrt.f32(float %f2) 27 28 store float %sqrt1, ptr %ptr1 29 store float %sqrt2, ptr %ptr2 30 31 ret void 32} 33 34define void @f2(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 { 35; CHECK-LABEL: f2: 36; CHECK: sqebr 37; CHECK: ste 38; CHECK: sqebr 39; CHECK: ste 40; CHECK: br %r14 41 42 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 43 float %f1, 44 metadata !"round.dynamic", 45 metadata !"fpexcept.ignore") #0 46 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 47 float %f2, 48 metadata !"round.dynamic", 49 metadata !"fpexcept.ignore") #0 50 51 store float %sqrt1, ptr %ptr1 52 store float %sqrt2, ptr %ptr2 53 54 ret void 55} 56 57define void @f3(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 { 58; CHECK-LABEL: f3: 59; CHECK: sqebr 60; CHECK: ste 61; CHECK: sqebr 62; CHECK: ste 63; CHECK: br %r14 64 65 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 66 float %f1, 67 metadata !"round.dynamic", 68 metadata !"fpexcept.maytrap") #0 69 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 70 float %f2, 71 metadata !"round.dynamic", 72 metadata !"fpexcept.maytrap") #0 73 74 store float %sqrt1, ptr %ptr1 75 store float %sqrt2, ptr %ptr2 76 77 ret void 78} 79 80define void @f4(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 { 81; CHECK-LABEL: f4: 82; CHECK: sqebr 83; CHECK: ste 84; CHECK: sqebr 85; CHECK: ste 86; CHECK: br %r14 87 88 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 89 float %f1, 90 metadata !"round.dynamic", 91 metadata !"fpexcept.strict") #0 92 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 93 float %f2, 94 metadata !"round.dynamic", 95 metadata !"fpexcept.strict") #0 96 97 store float %sqrt1, ptr %ptr1 98 store float %sqrt2, ptr %ptr2 99 100 ret void 101} 102 103 104; We can move a non-strict FP operation or a fpexcept.ignore 105; operation even across a volatile store, but not a fpexcept.maytrap 106; or fpexcept.strict operation. 107 108define void @f5(float %f1, float %f2, ptr %ptr1, ptr %ptr2) { 109; CHECK-LABEL: f5: 110; CHECK: sqebr 111; CHECK: ste 112; CHECK: sqebr 113; CHECK: ste 114; CHECK: br %r14 115 116 %sqrt1 = call float @llvm.sqrt.f32(float %f1) 117 %sqrt2 = call float @llvm.sqrt.f32(float %f2) 118 119 store volatile float %sqrt1, ptr %ptr1 120 store volatile float %sqrt2, ptr %ptr2 121 122 ret void 123} 124 125define void @f6(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 { 126; CHECK-LABEL: f6: 127; CHECK: sqebr 128; CHECK: ste 129; CHECK: sqebr 130; CHECK: ste 131; CHECK: br %r14 132 133 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 134 float %f1, 135 metadata !"round.dynamic", 136 metadata !"fpexcept.ignore") #0 137 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 138 float %f2, 139 metadata !"round.dynamic", 140 metadata !"fpexcept.ignore") #0 141 142 store volatile float %sqrt1, ptr %ptr1 143 store volatile float %sqrt2, ptr %ptr2 144 145 ret void 146} 147 148define void @f7(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 { 149; CHECK-LABEL: f7: 150; CHECK: sqebr 151; CHECK: sqebr 152; CHECK: ste 153; CHECK: ste 154; CHECK: br %r14 155 156 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 157 float %f1, 158 metadata !"round.dynamic", 159 metadata !"fpexcept.maytrap") #0 160 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 161 float %f2, 162 metadata !"round.dynamic", 163 metadata !"fpexcept.maytrap") #0 164 165 store volatile float %sqrt1, ptr %ptr1 166 store volatile float %sqrt2, ptr %ptr2 167 168 ret void 169} 170 171define void @f8(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 { 172; CHECK-LABEL: f8: 173; CHECK: sqebr 174; CHECK: sqebr 175; CHECK: ste 176; CHECK: ste 177; CHECK: br %r14 178 179 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 180 float %f1, 181 metadata !"round.dynamic", 182 metadata !"fpexcept.strict") #0 183 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 184 float %f2, 185 metadata !"round.dynamic", 186 metadata !"fpexcept.strict") #0 187 188 store volatile float %sqrt1, ptr %ptr1 189 store volatile float %sqrt2, ptr %ptr2 190 191 ret void 192} 193 194 195; No variant of FP operations can be scheduled across a SPFC. 196 197define void @f9(float %f1, float %f2, ptr %ptr1, ptr %ptr2) { 198; CHECK-LABEL: f9: 199; CHECK: sqebr 200; CHECK: sqebr 201; CHECK: ste 202; CHECK: ste 203; CHECK: br %r14 204 205 %sqrt1 = call float @llvm.sqrt.f32(float %f1) 206 %sqrt2 = call float @llvm.sqrt.f32(float %f2) 207 208 call void @llvm.s390.sfpc(i32 0) 209 210 store float %sqrt1, ptr %ptr1 211 store float %sqrt2, ptr %ptr2 212 213 ret void 214} 215 216define void @f10(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 { 217; CHECK-LABEL: f10: 218; CHECK: sqebr 219; CHECK: sqebr 220; CHECK: ste 221; CHECK: ste 222; CHECK: br %r14 223 224 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 225 float %f1, 226 metadata !"round.dynamic", 227 metadata !"fpexcept.ignore") #0 228 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 229 float %f2, 230 metadata !"round.dynamic", 231 metadata !"fpexcept.ignore") #0 232 233 call void @llvm.s390.sfpc(i32 0) #0 234 235 store float %sqrt1, ptr %ptr1 236 store float %sqrt2, ptr %ptr2 237 238 ret void 239} 240 241define void @f11(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 { 242; CHECK-LABEL: f11: 243; CHECK: sqebr 244; CHECK: sqebr 245; CHECK: ste 246; CHECK: ste 247; CHECK: br %r14 248 249 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 250 float %f1, 251 metadata !"round.dynamic", 252 metadata !"fpexcept.maytrap") #0 253 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 254 float %f2, 255 metadata !"round.dynamic", 256 metadata !"fpexcept.maytrap") #0 257 258 call void @llvm.s390.sfpc(i32 0) #0 259 260 store float %sqrt1, ptr %ptr1 261 store float %sqrt2, ptr %ptr2 262 263 ret void 264} 265 266define void @f12(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 { 267; CHECK-LABEL: f12: 268; CHECK: sqebr 269; CHECK: sqebr 270; CHECK: ste 271; CHECK: ste 272; CHECK: br %r14 273 274 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 275 float %f1, 276 metadata !"round.dynamic", 277 metadata !"fpexcept.strict") #0 278 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 279 float %f2, 280 metadata !"round.dynamic", 281 metadata !"fpexcept.strict") #0 282 283 call void @llvm.s390.sfpc(i32 0) #0 284 285 store float %sqrt1, ptr %ptr1 286 store float %sqrt2, ptr %ptr2 287 288 ret void 289} 290 291; If the result of any FP operation is unused, it can be removed 292; -- except for fpexcept.strict operations. 293 294define void @f13(float %f1) { 295; CHECK-LABEL: f13: 296; CHECK-NOT: sqeb 297; CHECK: br %r14 298 299 %sqrt = call float @llvm.sqrt.f32(float %f1) 300 301 ret void 302} 303 304define void @f14(float %f1) #0 { 305; CHECK-LABEL: f14: 306; CHECK-NOT: sqeb 307; CHECK: br %r14 308 309 %sqrt = call float @llvm.experimental.constrained.sqrt.f32( 310 float %f1, 311 metadata !"round.dynamic", 312 metadata !"fpexcept.ignore") #0 313 314 ret void 315} 316 317define void @f15(float %f1) #0 { 318; CHECK-LABEL: f15: 319; CHECK-NOT: sqeb 320; CHECK: br %r14 321 322 %sqrt = call float @llvm.experimental.constrained.sqrt.f32( 323 float %f1, 324 metadata !"round.dynamic", 325 metadata !"fpexcept.maytrap") #0 326 327 ret void 328} 329 330define void @f16(float %f1) #0 { 331; CHECK-LABEL: f16: 332; CHECK: sqebr 333; CHECK: br %r14 334 335 %sqrt = call float @llvm.experimental.constrained.sqrt.f32( 336 float %f1, 337 metadata !"round.dynamic", 338 metadata !"fpexcept.strict") #0 339 340 ret void 341} 342 343 344; Verify that constrained intrinsics and memory operations get their 345; chains linked up properly. 346 347define void @f17(float %in, ptr %out) #0 { 348; CHECK-LABEL: f17: 349; CHECK: sqebr 350; CHECK: ste 351; CHECK: jg bar 352 %sqrt = call float @llvm.experimental.constrained.sqrt.f32( 353 float %in, 354 metadata !"round.dynamic", 355 metadata !"fpexcept.ignore") #0 356 store float %sqrt, ptr %out, align 4 357 tail call void @bar() #0 358 ret void 359} 360 361define void @f18(float %in, ptr %out) #0 { 362; CHECK-LABEL: f18: 363; CHECK: sqebr 364; CHECK: ste 365; CHECK: jg bar 366 %sqrt = call float @llvm.experimental.constrained.sqrt.f32( 367 float %in, 368 metadata !"round.dynamic", 369 metadata !"fpexcept.ignore") #0 370 store float %sqrt, ptr %out, align 4 371 tail call void @bar() #0 372 ret void 373} 374 375define void @f19(float %in, ptr %out) #0 { 376; CHECK-LABEL: f19: 377; CHECK: sqebr 378; CHECK: ste 379; CHECK: jg bar 380 %sqrt = call float @llvm.experimental.constrained.sqrt.f32( 381 float %in, 382 metadata !"round.dynamic", 383 metadata !"fpexcept.maytrap") #0 384 store float %sqrt, ptr %out, align 4 385 tail call void @bar() #0 386 ret void 387} 388 389define void @f20(float %in, ptr %out) #0 { 390; CHECK-LABEL: f20: 391; CHECK: sqebr 392; CHECK: ste 393; CHECK: jg bar 394 %sqrt = call float @llvm.experimental.constrained.sqrt.f32( 395 float %in, 396 metadata !"round.dynamic", 397 metadata !"fpexcept.strict") #0 398 store float %sqrt, ptr %out, align 4 399 tail call void @bar() #0 400 ret void 401} 402 403attributes #0 = { strictfp } 404