404 lines · plain
1; Verify that strict FP operations are not rescheduled2;3; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z13 | FileCheck %s4 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 never11; want to see two square root instructions directly in a row, so the12; post-RA scheduler will always schedule something else in between13; 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: sqebr20; CHECK: ste21; CHECK: sqebr22; CHECK: ste23; CHECK: br %r1424 25 %sqrt1 = call float @llvm.sqrt.f32(float %f1)26 %sqrt2 = call float @llvm.sqrt.f32(float %f2)27 28 store float %sqrt1, ptr %ptr129 store float %sqrt2, ptr %ptr230 31 ret void32}33 34define void @f2(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {35; CHECK-LABEL: f2:36; CHECK: sqebr37; CHECK: ste38; CHECK: sqebr39; CHECK: ste40; CHECK: br %r1441 42 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(43 float %f1,44 metadata !"round.dynamic",45 metadata !"fpexcept.ignore") #046 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(47 float %f2,48 metadata !"round.dynamic",49 metadata !"fpexcept.ignore") #050 51 store float %sqrt1, ptr %ptr152 store float %sqrt2, ptr %ptr253 54 ret void55}56 57define void @f3(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {58; CHECK-LABEL: f3:59; CHECK: sqebr60; CHECK: ste61; CHECK: sqebr62; CHECK: ste63; CHECK: br %r1464 65 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(66 float %f1,67 metadata !"round.dynamic",68 metadata !"fpexcept.maytrap") #069 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(70 float %f2,71 metadata !"round.dynamic",72 metadata !"fpexcept.maytrap") #073 74 store float %sqrt1, ptr %ptr175 store float %sqrt2, ptr %ptr276 77 ret void78}79 80define void @f4(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {81; CHECK-LABEL: f4:82; CHECK: sqebr83; CHECK: ste84; CHECK: sqebr85; CHECK: ste86; CHECK: br %r1487 88 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(89 float %f1,90 metadata !"round.dynamic",91 metadata !"fpexcept.strict") #092 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(93 float %f2,94 metadata !"round.dynamic",95 metadata !"fpexcept.strict") #096 97 store float %sqrt1, ptr %ptr198 store float %sqrt2, ptr %ptr299 100 ret void101}102 103 104; We can move a non-strict FP operation or a fpexcept.ignore105; operation even across a volatile store, but not a fpexcept.maytrap106; or fpexcept.strict operation.107 108define void @f5(float %f1, float %f2, ptr %ptr1, ptr %ptr2) {109; CHECK-LABEL: f5:110; CHECK: sqebr111; CHECK: ste112; CHECK: sqebr113; CHECK: ste114; CHECK: br %r14115 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 %ptr1120 store volatile float %sqrt2, ptr %ptr2121 122 ret void123}124 125define void @f6(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {126; CHECK-LABEL: f6:127; CHECK: sqebr128; CHECK: ste129; CHECK: sqebr130; CHECK: ste131; CHECK: br %r14132 133 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(134 float %f1,135 metadata !"round.dynamic",136 metadata !"fpexcept.ignore") #0137 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(138 float %f2,139 metadata !"round.dynamic",140 metadata !"fpexcept.ignore") #0141 142 store volatile float %sqrt1, ptr %ptr1143 store volatile float %sqrt2, ptr %ptr2144 145 ret void146}147 148define void @f7(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {149; CHECK-LABEL: f7:150; CHECK: sqebr151; CHECK: sqebr152; CHECK: ste153; CHECK: ste154; CHECK: br %r14155 156 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(157 float %f1,158 metadata !"round.dynamic",159 metadata !"fpexcept.maytrap") #0160 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(161 float %f2,162 metadata !"round.dynamic",163 metadata !"fpexcept.maytrap") #0164 165 store volatile float %sqrt1, ptr %ptr1166 store volatile float %sqrt2, ptr %ptr2167 168 ret void169}170 171define void @f8(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {172; CHECK-LABEL: f8:173; CHECK: sqebr174; CHECK: sqebr175; CHECK: ste176; CHECK: ste177; CHECK: br %r14178 179 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(180 float %f1,181 metadata !"round.dynamic",182 metadata !"fpexcept.strict") #0183 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(184 float %f2,185 metadata !"round.dynamic",186 metadata !"fpexcept.strict") #0187 188 store volatile float %sqrt1, ptr %ptr1189 store volatile float %sqrt2, ptr %ptr2190 191 ret void192}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: sqebr200; CHECK: sqebr201; CHECK: ste202; CHECK: ste203; CHECK: br %r14204 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 %ptr1211 store float %sqrt2, ptr %ptr2212 213 ret void214}215 216define void @f10(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {217; CHECK-LABEL: f10:218; CHECK: sqebr219; CHECK: sqebr220; CHECK: ste221; CHECK: ste222; CHECK: br %r14223 224 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(225 float %f1,226 metadata !"round.dynamic",227 metadata !"fpexcept.ignore") #0228 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(229 float %f2,230 metadata !"round.dynamic",231 metadata !"fpexcept.ignore") #0232 233 call void @llvm.s390.sfpc(i32 0) #0234 235 store float %sqrt1, ptr %ptr1236 store float %sqrt2, ptr %ptr2237 238 ret void239}240 241define void @f11(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {242; CHECK-LABEL: f11:243; CHECK: sqebr244; CHECK: sqebr245; CHECK: ste246; CHECK: ste247; CHECK: br %r14248 249 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(250 float %f1,251 metadata !"round.dynamic",252 metadata !"fpexcept.maytrap") #0253 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(254 float %f2,255 metadata !"round.dynamic",256 metadata !"fpexcept.maytrap") #0257 258 call void @llvm.s390.sfpc(i32 0) #0259 260 store float %sqrt1, ptr %ptr1261 store float %sqrt2, ptr %ptr2262 263 ret void264}265 266define void @f12(float %f1, float %f2, ptr %ptr1, ptr %ptr2) #0 {267; CHECK-LABEL: f12:268; CHECK: sqebr269; CHECK: sqebr270; CHECK: ste271; CHECK: ste272; CHECK: br %r14273 274 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32(275 float %f1,276 metadata !"round.dynamic",277 metadata !"fpexcept.strict") #0278 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32(279 float %f2,280 metadata !"round.dynamic",281 metadata !"fpexcept.strict") #0282 283 call void @llvm.s390.sfpc(i32 0) #0284 285 store float %sqrt1, ptr %ptr1286 store float %sqrt2, ptr %ptr2287 288 ret void289}290 291; If the result of any FP operation is unused, it can be removed292; -- except for fpexcept.strict operations.293 294define void @f13(float %f1) {295; CHECK-LABEL: f13:296; CHECK-NOT: sqeb297; CHECK: br %r14298 299 %sqrt = call float @llvm.sqrt.f32(float %f1)300 301 ret void302}303 304define void @f14(float %f1) #0 {305; CHECK-LABEL: f14:306; CHECK-NOT: sqeb307; CHECK: br %r14308 309 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(310 float %f1,311 metadata !"round.dynamic",312 metadata !"fpexcept.ignore") #0313 314 ret void315}316 317define void @f15(float %f1) #0 {318; CHECK-LABEL: f15:319; CHECK-NOT: sqeb320; CHECK: br %r14321 322 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(323 float %f1,324 metadata !"round.dynamic",325 metadata !"fpexcept.maytrap") #0326 327 ret void328}329 330define void @f16(float %f1) #0 {331; CHECK-LABEL: f16:332; CHECK: sqebr333; CHECK: br %r14334 335 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(336 float %f1,337 metadata !"round.dynamic",338 metadata !"fpexcept.strict") #0339 340 ret void341}342 343 344; Verify that constrained intrinsics and memory operations get their345; chains linked up properly.346 347define void @f17(float %in, ptr %out) #0 {348; CHECK-LABEL: f17:349; CHECK: sqebr350; CHECK: ste351; CHECK: jg bar352 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(353 float %in,354 metadata !"round.dynamic",355 metadata !"fpexcept.ignore") #0356 store float %sqrt, ptr %out, align 4357 tail call void @bar() #0358 ret void359}360 361define void @f18(float %in, ptr %out) #0 {362; CHECK-LABEL: f18:363; CHECK: sqebr364; CHECK: ste365; CHECK: jg bar366 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(367 float %in,368 metadata !"round.dynamic",369 metadata !"fpexcept.ignore") #0370 store float %sqrt, ptr %out, align 4371 tail call void @bar() #0372 ret void373}374 375define void @f19(float %in, ptr %out) #0 {376; CHECK-LABEL: f19:377; CHECK: sqebr378; CHECK: ste379; CHECK: jg bar380 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(381 float %in,382 metadata !"round.dynamic",383 metadata !"fpexcept.maytrap") #0384 store float %sqrt, ptr %out, align 4385 tail call void @bar() #0386 ret void387}388 389define void @f20(float %in, ptr %out) #0 {390; CHECK-LABEL: f20:391; CHECK: sqebr392; CHECK: ste393; CHECK: jg bar394 %sqrt = call float @llvm.experimental.constrained.sqrt.f32(395 float %in,396 metadata !"round.dynamic",397 metadata !"fpexcept.strict") #0398 store float %sqrt, ptr %out, align 4399 tail call void @bar() #0400 ret void401}402 403attributes #0 = { strictfp }404