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) 8 9; The basic assumption of all following tests is that on z13, we never 10; want to see two square root instructions directly in a row, so the 11; post-RA scheduler will always schedule something else in between 12; whenever possible. 13 14; We can move any FP operation across a (normal) store. 15 16define void @f1(float %f1, float %f2, float *%ptr1, float *%ptr2) { 17; CHECK-LABEL: f1: 18; CHECK: sqebr 19; CHECK: ste 20; CHECK: sqebr 21; CHECK: ste 22; CHECK: br %r14 23 24 %sqrt1 = call float @llvm.sqrt.f32(float %f1) 25 %sqrt2 = call float @llvm.sqrt.f32(float %f2) 26 27 store float %sqrt1, float *%ptr1 28 store float %sqrt2, float *%ptr2 29 30 ret void 31} 32 33define void @f2(float %f1, float %f2, float *%ptr1, float *%ptr2) { 34; CHECK-LABEL: f2: 35; CHECK: sqebr 36; CHECK: ste 37; CHECK: sqebr 38; CHECK: ste 39; CHECK: br %r14 40 41 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 42 float %f1, 43 metadata !"round.dynamic", 44 metadata !"fpexcept.ignore") 45 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 46 float %f2, 47 metadata !"round.dynamic", 48 metadata !"fpexcept.ignore") 49 50 store float %sqrt1, float *%ptr1 51 store float %sqrt2, float *%ptr2 52 53 ret void 54} 55 56define void @f3(float %f1, float %f2, float *%ptr1, float *%ptr2) { 57; CHECK-LABEL: f3: 58; CHECK: sqebr 59; CHECK: ste 60; CHECK: sqebr 61; CHECK: ste 62; CHECK: br %r14 63 64 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 65 float %f1, 66 metadata !"round.dynamic", 67 metadata !"fpexcept.strict") 68 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 69 float %f2, 70 metadata !"round.dynamic", 71 metadata !"fpexcept.strict") 72 73 store float %sqrt1, float *%ptr1 74 store float %sqrt2, float *%ptr2 75 76 ret void 77} 78 79 80; We can move a non-strict FP operation or a fpexcept.ignore 81; operation even across a volatile store, but not a fpexcept.strict 82; operation. 83 84define void @f4(float %f1, float %f2, float *%ptr1, float *%ptr2) { 85; CHECK-LABEL: f4: 86; CHECK: sqebr 87; CHECK: ste 88; CHECK: sqebr 89; CHECK: ste 90; CHECK: br %r14 91 92 %sqrt1 = call float @llvm.sqrt.f32(float %f1) 93 %sqrt2 = call float @llvm.sqrt.f32(float %f2) 94 95 store volatile float %sqrt1, float *%ptr1 96 store volatile float %sqrt2, float *%ptr2 97 98 ret void 99} 100 101define void @f5(float %f1, float %f2, float *%ptr1, float *%ptr2) { 102; CHECK-LABEL: f5: 103; CHECK: sqebr 104; CHECK: ste 105; CHECK: sqebr 106; CHECK: ste 107; CHECK: br %r14 108 109 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 110 float %f1, 111 metadata !"round.dynamic", 112 metadata !"fpexcept.ignore") 113 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 114 float %f2, 115 metadata !"round.dynamic", 116 metadata !"fpexcept.ignore") 117 118 store volatile float %sqrt1, float *%ptr1 119 store volatile float %sqrt2, float *%ptr2 120 121 ret void 122} 123 124define void @f6(float %f1, float %f2, float *%ptr1, float *%ptr2) { 125; CHECK-LABEL: f6: 126; CHECK: sqebr 127; CHECK: sqebr 128; CHECK: ste 129; CHECK: ste 130; CHECK: br %r14 131 132 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 133 float %f1, 134 metadata !"round.dynamic", 135 metadata !"fpexcept.strict") 136 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 137 float %f2, 138 metadata !"round.dynamic", 139 metadata !"fpexcept.strict") 140 141 store volatile float %sqrt1, float *%ptr1 142 store volatile float %sqrt2, float *%ptr2 143 144 ret void 145} 146 147 148; No variant of FP operations can be scheduled across a SPFC. 149 150define void @f7(float %f1, float %f2, float *%ptr1, float *%ptr2) { 151; CHECK-LABEL: f7: 152; CHECK: sqebr 153; CHECK: sqebr 154; CHECK: ste 155; CHECK: ste 156; CHECK: br %r14 157 158 %sqrt1 = call float @llvm.sqrt.f32(float %f1) 159 %sqrt2 = call float @llvm.sqrt.f32(float %f2) 160 161 call void @llvm.s390.sfpc(i32 0) 162 163 store float %sqrt1, float *%ptr1 164 store float %sqrt2, float *%ptr2 165 166 ret void 167} 168 169define void @f8(float %f1, float %f2, float *%ptr1, float *%ptr2) { 170; CHECK-LABEL: f8: 171; CHECK: sqebr 172; CHECK: sqebr 173; CHECK: ste 174; CHECK: ste 175; CHECK: br %r14 176 177 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 178 float %f1, 179 metadata !"round.dynamic", 180 metadata !"fpexcept.ignore") 181 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 182 float %f2, 183 metadata !"round.dynamic", 184 metadata !"fpexcept.ignore") 185 186 call void @llvm.s390.sfpc(i32 0) 187 188 store float %sqrt1, float *%ptr1 189 store float %sqrt2, float *%ptr2 190 191 ret void 192} 193 194define void @f9(float %f1, float %f2, float *%ptr1, float *%ptr2) { 195; CHECK-LABEL: f9: 196; CHECK: sqebr 197; CHECK: sqebr 198; CHECK: ste 199; CHECK: ste 200; CHECK: br %r14 201 202 %sqrt1 = call float @llvm.experimental.constrained.sqrt.f32( 203 float %f1, 204 metadata !"round.dynamic", 205 metadata !"fpexcept.strict") 206 %sqrt2 = call float @llvm.experimental.constrained.sqrt.f32( 207 float %f2, 208 metadata !"round.dynamic", 209 metadata !"fpexcept.strict") 210 211 call void @llvm.s390.sfpc(i32 0) 212 213 store float %sqrt1, float *%ptr1 214 store float %sqrt2, float *%ptr2 215 216 ret void 217} 218 219