1 ; Test multiplication of two f64s, producing an f128 result. 2 ; 3 ; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s 4 5 declare double @foo() 6 7 ; Check register multiplication. "mxdbr %f0, %f2" is not valid from LLVM's 8 ; point of view, because %f2 is the low register of the FP128 %f0. Pass the 9 ; multiplier in %f4 instead. 10 define void @f1(double %f1, double %dummy, double %f2, fp128 *%dst) { 11 ; CHECK-LABEL: f1: 12 ; CHECK: mxdbr %f0, %f4 13 ; CHECK: std %f0, 0(%r2) 14 ; CHECK: std %f2, 8(%r2) 15 ; CHECK: br %r14 16 %f1x = fpext double %f1 to fp128 17 %f2x = fpext double %f2 to fp128 18 %res = fmul fp128 %f1x, %f2x 19 store fp128 %res, fp128 *%dst 20 ret void 21 } 22 23 ; Check the low end of the MXDB range. 24 define void @f2(double %f1, double *%ptr, fp128 *%dst) { 25 ; CHECK-LABEL: f2: 26 ; CHECK: mxdb %f0, 0(%r2) 27 ; CHECK: std %f0, 0(%r3) 28 ; CHECK: std %f2, 8(%r3) 29 ; CHECK: br %r14 30 %f2 = load double *%ptr 31 %f1x = fpext double %f1 to fp128 32 %f2x = fpext double %f2 to fp128 33 %res = fmul fp128 %f1x, %f2x 34 store fp128 %res, fp128 *%dst 35 ret void 36 } 37 38 ; Check the high end of the aligned MXDB range. 39 define void @f3(double %f1, double *%base, fp128 *%dst) { 40 ; CHECK-LABEL: f3: 41 ; CHECK: mxdb %f0, 4088(%r2) 42 ; CHECK: std %f0, 0(%r3) 43 ; CHECK: std %f2, 8(%r3) 44 ; CHECK: br %r14 45 %ptr = getelementptr double *%base, i64 511 46 %f2 = load double *%ptr 47 %f1x = fpext double %f1 to fp128 48 %f2x = fpext double %f2 to fp128 49 %res = fmul fp128 %f1x, %f2x 50 store fp128 %res, fp128 *%dst 51 ret void 52 } 53 54 ; Check the next doubleword up, which needs separate address logic. 55 ; Other sequences besides this one would be OK. 56 define void @f4(double %f1, double *%base, fp128 *%dst) { 57 ; CHECK-LABEL: f4: 58 ; CHECK: aghi %r2, 4096 59 ; CHECK: mxdb %f0, 0(%r2) 60 ; CHECK: std %f0, 0(%r3) 61 ; CHECK: std %f2, 8(%r3) 62 ; CHECK: br %r14 63 %ptr = getelementptr double *%base, i64 512 64 %f2 = load double *%ptr 65 %f1x = fpext double %f1 to fp128 66 %f2x = fpext double %f2 to fp128 67 %res = fmul fp128 %f1x, %f2x 68 store fp128 %res, fp128 *%dst 69 ret void 70 } 71 72 ; Check negative displacements, which also need separate address logic. 73 define void @f5(double %f1, double *%base, fp128 *%dst) { 74 ; CHECK-LABEL: f5: 75 ; CHECK: aghi %r2, -8 76 ; CHECK: mxdb %f0, 0(%r2) 77 ; CHECK: std %f0, 0(%r3) 78 ; CHECK: std %f2, 8(%r3) 79 ; CHECK: br %r14 80 %ptr = getelementptr double *%base, i64 -1 81 %f2 = load double *%ptr 82 %f1x = fpext double %f1 to fp128 83 %f2x = fpext double %f2 to fp128 84 %res = fmul fp128 %f1x, %f2x 85 store fp128 %res, fp128 *%dst 86 ret void 87 } 88 89 ; Check that MXDB allows indices. 90 define void @f6(double %f1, double *%base, i64 %index, fp128 *%dst) { 91 ; CHECK-LABEL: f6: 92 ; CHECK: sllg %r1, %r3, 3 93 ; CHECK: mxdb %f0, 800(%r1,%r2) 94 ; CHECK: std %f0, 0(%r4) 95 ; CHECK: std %f2, 8(%r4) 96 ; CHECK: br %r14 97 %ptr1 = getelementptr double *%base, i64 %index 98 %ptr2 = getelementptr double *%ptr1, i64 100 99 %f2 = load double *%ptr2 100 %f1x = fpext double %f1 to fp128 101 %f2x = fpext double %f2 to fp128 102 %res = fmul fp128 %f1x, %f2x 103 store fp128 %res, fp128 *%dst 104 ret void 105 } 106 107 ; Check that multiplications of spilled values can use MXDB rather than MXDBR. 108 define double @f7(double *%ptr0) { 109 ; CHECK-LABEL: f7: 110 ; CHECK: brasl %r14, foo@PLT 111 ; CHECK: mxdb %f0, 160(%r15) 112 ; CHECK: br %r14 113 %ptr1 = getelementptr double *%ptr0, i64 2 114 %ptr2 = getelementptr double *%ptr0, i64 4 115 %ptr3 = getelementptr double *%ptr0, i64 6 116 %ptr4 = getelementptr double *%ptr0, i64 8 117 %ptr5 = getelementptr double *%ptr0, i64 10 118 %ptr6 = getelementptr double *%ptr0, i64 12 119 %ptr7 = getelementptr double *%ptr0, i64 14 120 %ptr8 = getelementptr double *%ptr0, i64 16 121 %ptr9 = getelementptr double *%ptr0, i64 18 122 %ptr10 = getelementptr double *%ptr0, i64 20 123 124 %val0 = load double *%ptr0 125 %val1 = load double *%ptr1 126 %val2 = load double *%ptr2 127 %val3 = load double *%ptr3 128 %val4 = load double *%ptr4 129 %val5 = load double *%ptr5 130 %val6 = load double *%ptr6 131 %val7 = load double *%ptr7 132 %val8 = load double *%ptr8 133 %val9 = load double *%ptr9 134 %val10 = load double *%ptr10 135 136 %frob0 = fadd double %val0, %val0 137 %frob1 = fadd double %val1, %val1 138 %frob2 = fadd double %val2, %val2 139 %frob3 = fadd double %val3, %val3 140 %frob4 = fadd double %val4, %val4 141 %frob5 = fadd double %val5, %val5 142 %frob6 = fadd double %val6, %val6 143 %frob7 = fadd double %val7, %val7 144 %frob8 = fadd double %val8, %val8 145 %frob9 = fadd double %val9, %val9 146 %frob10 = fadd double %val9, %val10 147 148 store double %frob0, double *%ptr0 149 store double %frob1, double *%ptr1 150 store double %frob2, double *%ptr2 151 store double %frob3, double *%ptr3 152 store double %frob4, double *%ptr4 153 store double %frob5, double *%ptr5 154 store double %frob6, double *%ptr6 155 store double %frob7, double *%ptr7 156 store double %frob8, double *%ptr8 157 store double %frob9, double *%ptr9 158 store double %frob10, double *%ptr10 159 160 %ret = call double @foo() 161 162 %accext0 = fpext double %ret to fp128 163 %ext0 = fpext double %frob0 to fp128 164 %mul0 = fmul fp128 %accext0, %ext0 165 %const0 = fpext double 1.01 to fp128 166 %extra0 = fmul fp128 %mul0, %const0 167 %trunc0 = fptrunc fp128 %extra0 to double 168 169 %accext1 = fpext double %trunc0 to fp128 170 %ext1 = fpext double %frob1 to fp128 171 %mul1 = fmul fp128 %accext1, %ext1 172 %const1 = fpext double 1.11 to fp128 173 %extra1 = fmul fp128 %mul1, %const1 174 %trunc1 = fptrunc fp128 %extra1 to double 175 176 %accext2 = fpext double %trunc1 to fp128 177 %ext2 = fpext double %frob2 to fp128 178 %mul2 = fmul fp128 %accext2, %ext2 179 %const2 = fpext double 1.21 to fp128 180 %extra2 = fmul fp128 %mul2, %const2 181 %trunc2 = fptrunc fp128 %extra2 to double 182 183 %accext3 = fpext double %trunc2 to fp128 184 %ext3 = fpext double %frob3 to fp128 185 %mul3 = fmul fp128 %accext3, %ext3 186 %const3 = fpext double 1.31 to fp128 187 %extra3 = fmul fp128 %mul3, %const3 188 %trunc3 = fptrunc fp128 %extra3 to double 189 190 %accext4 = fpext double %trunc3 to fp128 191 %ext4 = fpext double %frob4 to fp128 192 %mul4 = fmul fp128 %accext4, %ext4 193 %const4 = fpext double 1.41 to fp128 194 %extra4 = fmul fp128 %mul4, %const4 195 %trunc4 = fptrunc fp128 %extra4 to double 196 197 %accext5 = fpext double %trunc4 to fp128 198 %ext5 = fpext double %frob5 to fp128 199 %mul5 = fmul fp128 %accext5, %ext5 200 %const5 = fpext double 1.51 to fp128 201 %extra5 = fmul fp128 %mul5, %const5 202 %trunc5 = fptrunc fp128 %extra5 to double 203 204 %accext6 = fpext double %trunc5 to fp128 205 %ext6 = fpext double %frob6 to fp128 206 %mul6 = fmul fp128 %accext6, %ext6 207 %const6 = fpext double 1.61 to fp128 208 %extra6 = fmul fp128 %mul6, %const6 209 %trunc6 = fptrunc fp128 %extra6 to double 210 211 %accext7 = fpext double %trunc6 to fp128 212 %ext7 = fpext double %frob7 to fp128 213 %mul7 = fmul fp128 %accext7, %ext7 214 %const7 = fpext double 1.71 to fp128 215 %extra7 = fmul fp128 %mul7, %const7 216 %trunc7 = fptrunc fp128 %extra7 to double 217 218 %accext8 = fpext double %trunc7 to fp128 219 %ext8 = fpext double %frob8 to fp128 220 %mul8 = fmul fp128 %accext8, %ext8 221 %const8 = fpext double 1.81 to fp128 222 %extra8 = fmul fp128 %mul8, %const8 223 %trunc8 = fptrunc fp128 %extra8 to double 224 225 %accext9 = fpext double %trunc8 to fp128 226 %ext9 = fpext double %frob9 to fp128 227 %mul9 = fmul fp128 %accext9, %ext9 228 %const9 = fpext double 1.91 to fp128 229 %extra9 = fmul fp128 %mul9, %const9 230 %trunc9 = fptrunc fp128 %extra9 to double 231 232 ret double %trunc9 233 } 234