Source file test/codegen/math.go

     1  // asmcheck -gcflags=-d=converthash=qy
     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  var sink64 [8]float64
    12  
    13  func approx(x float64) {
    14  	// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
    15  	// amd64:"ROUNDSD [$]2"
    16  	// s390x:"FIDBR [$]6"
    17  	// arm64:"FRINTPD"
    18  	// ppc64x:"FRIP"
    19  	// wasm:"F64Ceil"
    20  	sink64[0] = math.Ceil(x)
    21  
    22  	// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
    23  	// amd64:"ROUNDSD [$]1"
    24  	// s390x:"FIDBR [$]7"
    25  	// arm64:"FRINTMD"
    26  	// ppc64x:"FRIM"
    27  	// wasm:"F64Floor"
    28  	sink64[1] = math.Floor(x)
    29  
    30  	// s390x:"FIDBR [$]1"
    31  	// arm64:"FRINTAD"
    32  	// ppc64x:"FRIN"
    33  	sink64[2] = math.Round(x)
    34  
    35  	// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
    36  	// amd64:"ROUNDSD [$]3"
    37  	// s390x:"FIDBR [$]5"
    38  	// arm64:"FRINTZD"
    39  	// ppc64x:"FRIZ"
    40  	// wasm:"F64Trunc"
    41  	sink64[3] = math.Trunc(x)
    42  
    43  	// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
    44  	// amd64:"ROUNDSD [$]0"
    45  	// s390x:"FIDBR [$]4"
    46  	// arm64:"FRINTND"
    47  	// wasm:"F64Nearest"
    48  	sink64[4] = math.RoundToEven(x)
    49  }
    50  
    51  func sqrt(x float64) float64 {
    52  	// amd64:"SQRTSD"
    53  	// 386/sse2:"SQRTSD" 386/softfloat:-"SQRTD"
    54  	// arm64:"FSQRTD"
    55  	// arm/7:"SQRTD"
    56  	// loong64:"SQRTD"
    57  	// mips/hardfloat:"SQRTD" mips/softfloat:-"SQRTD"
    58  	// mips64/hardfloat:"SQRTD" mips64/softfloat:-"SQRTD"
    59  	// wasm:"F64Sqrt"
    60  	// ppc64x:"FSQRT"
    61  	// riscv64: "FSQRTD"
    62  	return math.Sqrt(x)
    63  }
    64  
    65  func sqrt32(x float32) float32 {
    66  	// amd64:"SQRTSS"
    67  	// 386/sse2:"SQRTSS" 386/softfloat:-"SQRTS"
    68  	// arm64:"FSQRTS"
    69  	// arm/7:"SQRTF"
    70  	// loong64:"SQRTF"
    71  	// mips/hardfloat:"SQRTF" mips/softfloat:-"SQRTF"
    72  	// mips64/hardfloat:"SQRTF" mips64/softfloat:-"SQRTF"
    73  	// wasm:"F32Sqrt"
    74  	// ppc64x:"FSQRTS"
    75  	// riscv64: "FSQRTS"
    76  	return float32(math.Sqrt(float64(x)))
    77  }
    78  
    79  // Check that it's using integer registers
    80  func abs(x, y float64) {
    81  	// amd64:"BTRQ [$]63"
    82  	// arm64:"FABSD "
    83  	// loong64:"ABSD "
    84  	// s390x:"LPDFR " -"MOVD "     (no integer load/store)
    85  	// ppc64x:"FABS "
    86  	// riscv64:"FABSD "
    87  	// wasm:"F64Abs"
    88  	// arm/6:"ABSD "
    89  	// mips64/hardfloat:"ABSD "
    90  	// mips/hardfloat:"ABSD "
    91  	sink64[0] = math.Abs(x)
    92  
    93  	// amd64:"BTRQ [$]63" "PXOR"    (TODO: this should be BTSQ)
    94  	// s390x:"LNDFR " -"MOVD "     (no integer load/store)
    95  	// ppc64x:"FNABS "
    96  	sink64[1] = -math.Abs(y)
    97  }
    98  
    99  // Check that it's using integer registers
   100  func abs32(x float32) float32 {
   101  	// s390x:"LPDFR" -"LDEBR" -"LEDBR"     (no float64 conversion)
   102  	return float32(math.Abs(float64(x)))
   103  }
   104  
   105  // Check that it's using integer registers
   106  func copysign(a, b, c float64) {
   107  	// amd64:"BTRQ [$]63" "ANDQ" "ORQ"
   108  	// loong64:"FCOPYSGD"
   109  	// s390x:"CPSDR" -"MOVD"         (no integer load/store)
   110  	// ppc64x:"FCPSGN"
   111  	// riscv64:"FSGNJD"
   112  	// wasm:"F64Copysign"
   113  	sink64[0] = math.Copysign(a, b)
   114  
   115  	// amd64:"BTSQ [$]63"
   116  	// loong64:"FCOPYSGD"
   117  	// s390x:"LNDFR " -"MOVD "     (no integer load/store)
   118  	// ppc64x:"FCPSGN"
   119  	// riscv64:"FSGNJD"
   120  	// arm64:"ORR", -"AND"
   121  	sink64[1] = math.Copysign(c, -1)
   122  
   123  	// Like math.Copysign(c, -1), but with integer operations. Useful
   124  	// for platforms that have a copysign opcode to see if it's detected.
   125  	// s390x:"LNDFR " -"MOVD "     (no integer load/store)
   126  	sink64[2] = math.Float64frombits(math.Float64bits(a) | 1<<63)
   127  
   128  	// amd64:"ANDQ" "ORQ"
   129  	// loong64:"FCOPYSGD"
   130  	// s390x:"CPSDR " -"MOVD "     (no integer load/store)
   131  	// ppc64x:"FCPSGN"
   132  	// riscv64:"FSGNJD"
   133  	sink64[3] = math.Copysign(-1, c)
   134  }
   135  
   136  func fma(x, y, z float64) float64 {
   137  	// amd64/v3:-".*x86HasFMA"
   138  	// amd64:"VFMADD231SD"
   139  	// arm/6:"FMULAD"
   140  	// arm64:"FMADDD"
   141  	// loong64:"FMADDD"
   142  	// s390x:"FMADD"
   143  	// ppc64x:"FMADD"
   144  	// riscv64:"FMADDD"
   145  	return math.FMA(x, y, z)
   146  }
   147  
   148  func fms(x, y, z float64) float64 {
   149  	// riscv64:"FMSUBD"
   150  	return math.FMA(x, y, -z)
   151  }
   152  
   153  func fnms(x, y, z float64) float64 {
   154  	// riscv64:"FNMSUBD" -"FNMADDD"
   155  	return math.FMA(-x, y, z)
   156  }
   157  
   158  func fnma(x, y, z float64) float64 {
   159  	// riscv64:"FNMADDD" -"FNMSUBD"
   160  	return math.FMA(x, -y, -z)
   161  }
   162  
   163  func isPosInf(x float64) bool {
   164  	// riscv64:"FCLASSD"
   165  	return math.IsInf(x, 1)
   166  }
   167  
   168  func isPosInfEq(x float64) bool {
   169  	// riscv64:"FCLASSD"
   170  	return x == math.Inf(1)
   171  }
   172  
   173  func isPosInfCmp(x float64) bool {
   174  	// riscv64:"FCLASSD"
   175  	return x > math.MaxFloat64
   176  }
   177  
   178  func isNotPosInf(x float64) bool {
   179  	// riscv64:"FCLASSD"
   180  	return !math.IsInf(x, 1)
   181  }
   182  
   183  func isNotPosInfEq(x float64) bool {
   184  	// riscv64:"FCLASSD"
   185  	return x != math.Inf(1)
   186  }
   187  
   188  func isNotPosInfCmp(x float64) bool {
   189  	// riscv64:"FCLASSD"
   190  	return x <= math.MaxFloat64
   191  }
   192  
   193  func isNegInf(x float64) bool {
   194  	// riscv64:"FCLASSD"
   195  	return math.IsInf(x, -1)
   196  }
   197  
   198  func isNegInfEq(x float64) bool {
   199  	// riscv64:"FCLASSD"
   200  	return x == math.Inf(-1)
   201  }
   202  
   203  func isNegInfCmp(x float64) bool {
   204  	// riscv64:"FCLASSD"
   205  	return x < -math.MaxFloat64
   206  }
   207  
   208  func isNotNegInf(x float64) bool {
   209  	// riscv64:"FCLASSD"
   210  	return !math.IsInf(x, -1)
   211  }
   212  
   213  func isNotNegInfEq(x float64) bool {
   214  	// riscv64:"FCLASSD"
   215  	return x != math.Inf(-1)
   216  }
   217  
   218  func isNotNegInfCmp(x float64) bool {
   219  	// riscv64:"FCLASSD"
   220  	return x >= -math.MaxFloat64
   221  }
   222  
   223  func fromFloat64(f64 float64) uint64 {
   224  	// amd64:"MOVQ X.*, [^X].*"
   225  	// arm64:"FMOVD F.*, R.*"
   226  	// loong64:"MOVV F.*, R.*"
   227  	// ppc64x:"MFVSRD"
   228  	// mips64/hardfloat:"MOVV F.*, R.*"
   229  	// riscv64:"FMVXD"
   230  	return math.Float64bits(f64+1) + 1
   231  }
   232  
   233  func fromFloat32(f32 float32) uint32 {
   234  	// amd64:"MOVL X.*, [^X].*"
   235  	// arm64:"FMOVS F.*, R.*"
   236  	// loong64:"MOVW F.*, R.*"
   237  	// mips64/hardfloat:"MOVW F.*, R.*"
   238  	// riscv64:"FMVXW"
   239  	return math.Float32bits(f32+1) + 1
   240  }
   241  
   242  func toFloat64(u64 uint64) float64 {
   243  	// amd64:"MOVQ [^X].*, X.*"
   244  	// arm64:"FMOVD R.*, F.*"
   245  	// loong64:"MOVV R.*, F.*"
   246  	// ppc64x:"MTVSRD"
   247  	// mips64/hardfloat:"MOVV R.*, F.*"
   248  	// riscv64:"FMVDX"
   249  	return math.Float64frombits(u64+1) + 1
   250  }
   251  
   252  func toFloat32(u32 uint32) float32 {
   253  	// amd64:"MOVL [^X].*, X.*"
   254  	// arm64:"FMOVS R.*, F.*"
   255  	// loong64:"MOVW R.*, F.*"
   256  	// mips64/hardfloat:"MOVW R.*, F.*"
   257  	// riscv64:"FMVWX"
   258  	return math.Float32frombits(u32+1) + 1
   259  }
   260  
   261  // Test that comparisons with constants converted to float
   262  // are evaluated at compile-time
   263  
   264  func constantCheck64() bool {
   265  	// amd64:"(MOVB [$]0)|(XORL [A-Z][A-Z0-9]+, [A-Z][A-Z0-9]+)" -"FCMP" -"MOVB [$]1"
   266  	// s390x:"MOV(B|BZ|D) [$]0," -"FCMPU" -"MOV(B|BZ|D) [$]1,"
   267  	return 0.5 == float64(uint32(1)) || 1.5 > float64(uint64(1<<63))
   268  }
   269  
   270  func constantCheck32() bool {
   271  	// amd64:"MOV(B|L) [$]1" -"FCMP" -"MOV(B|L) [$]0"
   272  	// s390x:"MOV(B|BZ|D) [$]1," -"FCMPU" -"MOV(B|BZ|D) [$]0,"
   273  	return float32(0.5) <= float32(int64(1)) && float32(1.5) >= float32(int32(-1<<31))
   274  }
   275  
   276  // Test that integer constants are converted to floating point constants
   277  // at compile-time
   278  
   279  func constantConvert32(x float32) float32 {
   280  	// amd64:"MOVSS [$]f32.3f800000\\(SB\\)"
   281  	// s390x:"FMOVS [$]f32.3f800000\\(SB\\)"
   282  	// ppc64x/power8:"FMOVS [$]f32.3f800000\\(SB\\)"
   283  	// ppc64x/power9:"FMOVS [$]f32.3f800000\\(SB\\)"
   284  	// ppc64x/power10:"XXSPLTIDP [$]1065353216, VS0"
   285  	// arm64:"FMOVS [$]\\(1.0\\)"
   286  	if x > math.Float32frombits(0x3f800000) {
   287  		return -x
   288  	}
   289  	return x
   290  }
   291  
   292  func constantConvertInt32(x uint32) uint32 {
   293  	// amd64:-"MOVSS"
   294  	// s390x:-"FMOVS"
   295  	// ppc64x:-"FMOVS"
   296  	// arm64:-"FMOVS"
   297  	if x > math.Float32bits(1) {
   298  		return -x
   299  	}
   300  	return x
   301  }
   302  
   303  func nanGenerate64() float64 {
   304  	// Test to make sure we don't generate a NaN while constant propagating.
   305  	// See issue 36400.
   306  	zero := 0.0
   307  	// amd64:-"DIVSD"
   308  	inf := 1 / zero // +inf. We can constant propagate this one.
   309  	negone := -1.0
   310  
   311  	// amd64:"DIVSD"
   312  	z0 := zero / zero
   313  	// amd64/v1,amd64/v2:"MULSD"
   314  	z1 := zero * inf
   315  	// amd64:"SQRTSD"
   316  	z2 := math.Sqrt(negone)
   317  	// amd64/v3:"VFMADD231SD"
   318  	return z0 + z1 + z2
   319  }
   320  
   321  func nanGenerate32() float32 {
   322  	zero := float32(0.0)
   323  	// amd64:-"DIVSS"
   324  	inf := 1 / zero // +inf. We can constant propagate this one.
   325  
   326  	// amd64:"DIVSS"
   327  	z0 := zero / zero
   328  	// amd64/v1,amd64/v2:"MULSS"
   329  	z1 := zero * inf
   330  	// amd64/v3:"VFMADD231SS"
   331  	return z0 + z1
   332  }
   333  
   334  func outOfBoundsConv(i32 *[2]int32, u32 *[2]uint32, i64 *[2]int64, u64 *[2]uint64) {
   335  	// arm64: "FCVTZSDW"
   336  	// amd64: "CVTTSD2SL", "CVTSD2SS"
   337  	i32[0] = int32(two40())
   338  	// arm64: "FCVTZSDW"
   339  	// amd64: "CVTTSD2SL", "CVTSD2SS"
   340  	i32[1] = int32(-two40())
   341  	// arm64: "FCVTZSDW"
   342  	// amd64: "CVTTSD2SL", "CVTSD2SS"
   343  	u32[0] = uint32(two41())
   344  	// on arm64, this uses an explicit <0 comparison, so it constant folds.
   345  	// on amd64, this uses an explicit <0 comparison, so it constant folds.
   346  	// amd64: "MOVL [$]0,"
   347  	u32[1] = uint32(minus1())
   348  	// arm64: "FCVTZSD"
   349  	// amd64: "CVTTSD2SQ"
   350  	i64[0] = int64(two80())
   351  	// arm64: "FCVTZSD"
   352  	// amd64: "CVTTSD2SQ"
   353  	i64[1] = int64(-two80())
   354  	// arm64: "FCVTZUD"
   355  	// amd64: "CVTTSD2SQ"
   356  	u64[0] = uint64(two81())
   357  	// arm64: "FCVTZUD"
   358  	// on amd64, this uses an explicit <0 comparison, so it constant folds.
   359  	// amd64: "MOVQ [$]0,"
   360  	u64[1] = uint64(minus1())
   361  }
   362  
   363  func two40() float64 {
   364  	return 1 << 40
   365  }
   366  func two41() float64 {
   367  	return 1 << 41
   368  }
   369  func two80() float64 {
   370  	return 1 << 80
   371  }
   372  func two81() float64 {
   373  	return 1 << 81
   374  }
   375  func minus1() float64 {
   376  	return -1
   377  }
   378  

View as plain text