Source file test/codegen/floats.go
1 // asmcheck 2 3 // Copyright 2018 The Go Authors. All rights reserved. 4 // Use of this source code is governed by a BSD-style 5 // license that can be found in the LICENSE file. 6 7 package codegen 8 9 import "math" 10 11 // This file contains codegen tests related to arithmetic 12 // simplifications and optimizations on float types. 13 // For codegen tests on integer types, see arithmetic.go. 14 15 // --------------------- // 16 // Strength-reduce // 17 // --------------------- // 18 19 func Mul2(f float64) float64 { 20 // 386/sse2:"ADDSD" -"MULSD" 21 // amd64:"ADDSD" -"MULSD" 22 // arm/7:"ADDD" -"MULD" 23 // arm64:"FADDD" -"FMULD" 24 // loong64:"ADDD" -"MULD" 25 // ppc64x:"FADD" -"FMUL" 26 // riscv64:"FADDD" -"FMULD" 27 return f * 2.0 28 } 29 30 func DivPow2(f1, f2, f3 float64) (float64, float64, float64) { 31 // 386/sse2:"MULSD" -"DIVSD" 32 // amd64:"MULSD" -"DIVSD" 33 // arm/7:"MULD" -"DIVD" 34 // arm64:"FMULD" -"FDIVD" 35 // loong64:"MULD" -"DIVD" 36 // ppc64x:"FMUL" -"FDIV" 37 // riscv64:"FMULD" -"FDIVD" 38 x := f1 / 16.0 39 40 // 386/sse2:"MULSD" -"DIVSD" 41 // amd64:"MULSD" -"DIVSD" 42 // arm/7:"MULD" -"DIVD" 43 // arm64:"FMULD" -"FDIVD" 44 // loong64:"MULD" -"DIVD" 45 // ppc64x:"FMUL" -"FDIVD" 46 // riscv64:"FMULD" -"FDIVD" 47 y := f2 / 0.125 48 49 // 386/sse2:"ADDSD" -"DIVSD" -"MULSD" 50 // amd64:"ADDSD" -"DIVSD" -"MULSD" 51 // arm/7:"ADDD" -"MULD" -"DIVD" 52 // arm64:"FADDD" -"FMULD" -"FDIVD" 53 // loong64:"ADDD" -"MULD" -"DIVD" 54 // ppc64x:"FADD" -"FMUL" -"FDIV" 55 // riscv64:"FADDD" -"FMULD" -"FDIVD" 56 z := f3 / 0.5 57 58 return x, y, z 59 } 60 61 func indexLoad(b0 []float32, b1 float32, idx int) float32 { 62 // arm64:`FMOVS \(R[0-9]+\)\(R[0-9]+<<2\), F[0-9]+` 63 // loong64:`MOVF \(R[0-9]+\)\(R[0-9]+\), F[0-9]+` 64 return b0[idx] * b1 65 } 66 67 func indexStore(b0 []float64, b1 float64, idx int) { 68 // arm64:`FMOVD F[0-9]+, \(R[0-9]+\)\(R[0-9]+<<3\)` 69 // loong64:`MOVD F[0-9]+, \(R[0-9]+\)\(R[0-9]+\)` 70 b0[idx] = b1 71 } 72 73 // ----------- // 74 // Fused // 75 // ----------- // 76 77 func FusedAdd32(x, y, z float32) float32 { 78 // s390x:"FMADDS " 79 // ppc64x:"FMADDS " 80 // arm64:"FMADDS" 81 // loong64:"FMADDF " 82 // riscv64:"FMADDS " 83 // amd64/v3:"VFMADD231SS " 84 return x*y + z 85 } 86 87 func FusedSub32_a(x, y, z float32) float32 { 88 // s390x:"FMSUBS " 89 // ppc64x:"FMSUBS " 90 // riscv64:"FMSUBS " 91 // loong64:"FMSUBF " 92 return x*y - z 93 } 94 95 func FusedSub32_b(x, y, z float32) float32 { 96 // arm64:"FMSUBS" 97 // loong64:"FNMSUBF " 98 // riscv64:"FNMSUBS " 99 return z - x*y 100 } 101 102 func FusedAdd64(x, y, z float64) float64 { 103 // s390x:"FMADD " 104 // ppc64x:"FMADD " 105 // arm64:"FMADDD" 106 // loong64:"FMADDD " 107 // riscv64:"FMADDD " 108 // amd64/v3:"VFMADD231SD " 109 return x*y + z 110 } 111 112 func FusedSub64_a(x, y, z float64) float64 { 113 // s390x:"FMSUB " 114 // ppc64x:"FMSUB " 115 // riscv64:"FMSUBD " 116 // loong64:"FMSUBD " 117 return x*y - z 118 } 119 120 func FusedSub64_b(x, y, z float64) float64 { 121 // arm64:"FMSUBD" 122 // loong64:"FNMSUBD " 123 // riscv64:"FNMSUBD " 124 return z - x*y 125 } 126 127 func Cmp(f float64) bool { 128 // arm64:"FCMPD" "(BGT|BLE|BMI|BPL)" -"CSET GT" -"CBZ" 129 return f > 4 || f < -4 130 } 131 132 func CmpZero64(f float64) bool { 133 // s390x:"LTDBR" -"FCMPU" 134 return f <= 0 135 } 136 137 func CmpZero32(f float32) bool { 138 // s390x:"LTEBR" -"CEBR" 139 return f <= 0 140 } 141 142 func CmpWithSub(a float64, b float64) bool { 143 f := a - b 144 // s390x:-"LTDBR" 145 return f <= 0 146 } 147 148 func CmpWithAdd(a float64, b float64) bool { 149 f := a + b 150 // s390x:-"LTDBR" 151 return f <= 0 152 } 153 154 // ---------------- // 155 // Non-floats // 156 // ---------------- // 157 158 func ArrayZero() [16]byte { 159 // amd64:"MOVUPS" 160 var a [16]byte 161 return a 162 } 163 164 func ArrayCopy(a [16]byte) (b [16]byte) { 165 // amd64:"MOVUPS" 166 b = a 167 return 168 } 169 170 // ---------------- // 171 // Float Min/Max // 172 // ---------------- // 173 174 func Float64Min(a, b float64) float64 { 175 // FIXME: add WFMINDB on s390x/z14 when GOS390X is added. 176 177 // amd64:"MINSD" 178 // arm64:"FMIND" 179 // loong64:"FMIND" 180 // riscv64:"FMIN" 181 // ppc64/power9:"XSMINJDP" 182 // ppc64/power10:"XSMINJDP" 183 return min(a, b) 184 } 185 186 func Float64Max(a, b float64) float64 { 187 // FIXME: add WFMAXDB on s390x/z14 when GOS390X is added. 188 189 // amd64:"MINSD" 190 // arm64:"FMAXD" 191 // loong64:"FMAXD" 192 // riscv64:"FMAX" 193 // ppc64/power9:"XSMAXJDP" 194 // ppc64/power10:"XSMAXJDP" 195 return max(a, b) 196 } 197 198 func Float32Min(a, b float32) float32 { 199 // FIXME: add WFMINSB on s390x/z14 when GOS390X is added. 200 201 // amd64:"MINSS" 202 // arm64:"FMINS" 203 // loong64:"FMINF" 204 // riscv64:"FMINS" 205 // ppc64/power9:"XSMINJDP" 206 // ppc64/power10:"XSMINJDP" 207 return min(a, b) 208 } 209 210 func Float32Max(a, b float32) float32 { 211 // FIXME: add WFMAXSB on s390x/z14 when GOS390X is added. 212 213 // amd64:"MINSS" 214 // arm64:"FMAXS" 215 // loong64:"FMAXF" 216 // riscv64:"FMAXS" 217 // ppc64/power9:"XSMAXJDP" 218 // ppc64/power10:"XSMAXJDP" 219 return max(a, b) 220 } 221 222 // ------------------------ // 223 // Constant Optimizations // 224 // ------------------------ // 225 226 func Float32ConstantZero() float32 { 227 // arm64:"FMOVS ZR," 228 // riscv64:"MOVF X0," 229 return 0.0 230 } 231 232 func Float32ConstantChipFloat() float32 { 233 // arm64:"FMOVS [$]\\(2\\.25\\)," 234 return 2.25 235 } 236 237 func Float32Constant() float32 { 238 // arm64:"FMOVS [$]f32\\.42440000\\(SB\\)" 239 // ppc64x/power8:"FMOVS [$]f32\\.42440000\\(SB\\)" 240 // ppc64x/power9:"FMOVS [$]f32\\.42440000\\(SB\\)" 241 // ppc64x/power10:"XXSPLTIDP [$]1111752704," 242 // riscv64:"MOVF [$]f32\\.42440000\\(SB\\)" 243 return 49.0 244 } 245 246 func Float64ConstantZero() float64 { 247 // arm64:"FMOVD ZR," 248 // riscv64:"MOVD X0," 249 return 0.0 250 } 251 252 func Float64ConstantChipFloat() float64 { 253 // arm64:"FMOVD [$]\\(2\\.25\\)," 254 return 2.25 255 } 256 257 func Float64Constant() float64 { 258 // arm64:"FMOVD [$]f64\\.4048800000000000\\(SB\\)" 259 // ppc64x/power8:"FMOVD [$]f64\\.4048800000000000\\(SB\\)" 260 // ppc64x/power9:"FMOVD [$]f64\\.4048800000000000\\(SB\\)" 261 // ppc64x/power10:"XXSPLTIDP [$]1111752704," 262 // riscv64:"MOVD [$]f64\\.4048800000000000\\(SB\\)" 263 return 49.0 264 } 265 266 func Float32DenormalConstant() float32 { 267 // ppc64x:"FMOVS [$]f32\\.00400000\\(SB\\)" 268 return 0x1p-127 269 } 270 271 // A float64 constant which can be exactly represented as a 272 // denormal float32 value. On ppc64x, denormal values cannot 273 // be used with XXSPLTIDP. 274 func Float64DenormalFloat32Constant() float64 { 275 // ppc64x:"FMOVD [$]f64\\.3800000000000000\\(SB\\)" 276 return 0x1p-127 277 } 278 279 func Float32ConstantStore(p *float32) { 280 // amd64:"MOVL [$]1085133554" 281 // riscv64: "MOVF [$]f32.40add2f2" 282 *p = 5.432 283 } 284 285 func Float64ConstantStore(p *float64) { 286 // amd64: "MOVQ [$]4617801906721357038" 287 // riscv64: "MOVD [$]f64.4015ba5e353f7cee" 288 *p = 5.432 289 } 290 291 func WideCeilNarrow(x float32) float32 { 292 // amd64/v3:"ROUNDSS" -"CVTSS2SD" -"CVTSD2SS" 293 // arm64:"FRINTPS" -"FCVTSD" -"FCVTDS" 294 // wasm:"F32Ceil" -"F64PromoteF32" -"F32DemoteF64" 295 return float32(math.Ceil(float64(x))) 296 } 297 298 func WideTruncNarrow(x float32) float32 { 299 // amd64/v3:"ROUNDSS" -"CVTSS2SD" -"CVTSD2SS" 300 // arm64:"FRINTZS" -"FCVTSD" -"FCVTDS" 301 // wasm:"F32Trunc" -"F64PromoteF32" -"F32DemoteF64" 302 return float32(math.Trunc(float64(x))) 303 } 304 305 func WideFloorNarrow(x float32) float32 { 306 // amd64/v3:"ROUNDSS" -"CVTSS2SD" -"CVTSD2SS" 307 // arm64:"FRINTMS" -"FCVTSD" -"FCVTDS" 308 // wasm:"F32Floor" -"F64PromoteF32" -"F32DemoteF64" 309 return float32(math.Floor(float64(x))) 310 } 311 312 func WideRoundNarrow(x float32) float32 { 313 // arm64:"FRINTAS" -"FCVTSD" -"FCVTDS" 314 return float32(math.Round(float64(x))) 315 } 316 317 func WideRoundToEvenNarrow(x float32) float32 { 318 // amd64/v3:"ROUNDSS" -"CVTSS2SD" -"CVTSD2SS" 319 // arm64:"FRINTNS" -"FCVTSD" -"FCVTDS" 320 // wasm:"F32Nearest" -"F64PromoteF32" -"F32DemoteF64" 321 return float32(math.RoundToEven(float64(x))) 322 } 323 324 func WideSqrtNarrow(x float32) float32 { 325 // arm64:"FSQRTS" -"FCVTSD" -"FCVTDS" 326 // loong64:"SQRTF" -"MOVFD" -"MOVDF" 327 // mips64/hardfloat:"SQRTF" -"MOVFD" -"MOVDF" 328 // riscv64:"FSQRTS" -"FCVTDS" -"FCVTSD" 329 // wasm:"F32Sqrt" -"F64PromoteF32" -"F32DemoteF64" 330 return float32(math.Sqrt(float64(x))) 331 } 332 333 func WideAbsNarrow(x float32) float32 { 334 // arm64:"FABSS" -"FCVTSD" -"FCVTDS" 335 // loong64:"ABSF" -"MOVFD" -"MOVDF" 336 // mips64/hardfloat:"ABSF" -"MOVFD" -"MOVDF" 337 // riscv64:"FABSS" -"FCVTDS" -"FCVTSD" 338 // wasm:"F32Abs" -"F64PromoteF32" -"F32DemoteF64" 339 return float32(math.Abs(float64(x))) 340 } 341 342 func WideCopysignNarrow(x, y float32) float32 { 343 // wasm:"F32Copysign" 344 return float32(math.Copysign(float64(x), float64(y))) 345 } 346 347 // ------------------------ // 348 // Subnormal tests // 349 // ------------------------ // 350 351 func isSubnormal(x float64) bool { 352 // riscv64:"FCLASSD" -"FABSD" 353 return math.Abs(x) < 2.2250738585072014e-308 354 } 355 356 func isNormal(x float64) bool { 357 // riscv64:"FCLASSD" -"FABSD" 358 return math.Abs(x) >= 0x1p-1022 359 } 360 361 func isPosSubnormal(x float64) bool { 362 // riscv64:"FCLASSD" 363 return x > 0 && x < 2.2250738585072014e-308 364 } 365 366 func isNegSubnormal(x float64) bool { 367 // riscv64:"FCLASSD" 368 return x < 0 && x > -0x1p-1022 369 } 370 371 func isPosNormal(x float64) bool { 372 // riscv64:"FCLASSD" 373 return x >= 2.2250738585072014e-308 374 } 375 376 func isNegNormal(x float64) bool { 377 // riscv64:"FCLASSD" 378 return x <= -2.2250738585072014e-308 379 } 380