Source file test/codegen/math.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  var sink64 [8]float64
    12  
    13  func approx(x float64) {
    14  	// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
    15  	// amd64:"ROUNDSD\t[$]2"
    16  	// s390x:"FIDBR\t[$]6"
    17  	// arm64:"FRINTPD"
    18  	// ppc64:"FRIP"
    19  	// ppc64le:"FRIP"
    20  	// wasm:"F64Ceil"
    21  	sink64[0] = math.Ceil(x)
    22  
    23  	// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
    24  	// amd64:"ROUNDSD\t[$]1"
    25  	// s390x:"FIDBR\t[$]7"
    26  	// arm64:"FRINTMD"
    27  	// ppc64:"FRIM"
    28  	// ppc64le:"FRIM"
    29  	// wasm:"F64Floor"
    30  	sink64[1] = math.Floor(x)
    31  
    32  	// s390x:"FIDBR\t[$]1"
    33  	// arm64:"FRINTAD"
    34  	// ppc64:"FRIN"
    35  	// ppc64le:"FRIN"
    36  	sink64[2] = math.Round(x)
    37  
    38  	// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
    39  	// amd64:"ROUNDSD\t[$]3"
    40  	// s390x:"FIDBR\t[$]5"
    41  	// arm64:"FRINTZD"
    42  	// ppc64:"FRIZ"
    43  	// ppc64le:"FRIZ"
    44  	// wasm:"F64Trunc"
    45  	sink64[3] = math.Trunc(x)
    46  
    47  	// amd64/v2:-".*x86HasSSE41" amd64/v3:-".*x86HasSSE41"
    48  	// amd64:"ROUNDSD\t[$]0"
    49  	// s390x:"FIDBR\t[$]4"
    50  	// arm64:"FRINTND"
    51  	// wasm:"F64Nearest"
    52  	sink64[4] = math.RoundToEven(x)
    53  }
    54  
    55  func sqrt(x float64) float64 {
    56  	// amd64:"SQRTSD"
    57  	// 386/sse2:"SQRTSD" 386/softfloat:-"SQRTD"
    58  	// arm64:"FSQRTD"
    59  	// arm/7:"SQRTD"
    60  	// mips/hardfloat:"SQRTD" mips/softfloat:-"SQRTD"
    61  	// mips64/hardfloat:"SQRTD" mips64/softfloat:-"SQRTD"
    62  	// wasm:"F64Sqrt"
    63  	// ppc64le:"FSQRT"
    64  	// ppc64:"FSQRT"
    65  	return math.Sqrt(x)
    66  }
    67  
    68  func sqrt32(x float32) float32 {
    69  	// amd64:"SQRTSS"
    70  	// 386/sse2:"SQRTSS" 386/softfloat:-"SQRTS"
    71  	// arm64:"FSQRTS"
    72  	// arm/7:"SQRTF"
    73  	// mips/hardfloat:"SQRTF" mips/softfloat:-"SQRTF"
    74  	// mips64/hardfloat:"SQRTF" mips64/softfloat:-"SQRTF"
    75  	// wasm:"F32Sqrt"
    76  	// ppc64le:"FSQRTS"
    77  	// ppc64:"FSQRTS"
    78  	return float32(math.Sqrt(float64(x)))
    79  }
    80  
    81  // Check that it's using integer registers
    82  func abs(x, y float64) {
    83  	// amd64:"BTRQ\t[$]63"
    84  	// arm64:"FABSD\t"
    85  	// s390x:"LPDFR\t",-"MOVD\t"     (no integer load/store)
    86  	// ppc64:"FABS\t"
    87  	// ppc64le:"FABS\t"
    88  	// riscv64:"FABSD\t"
    89  	// wasm:"F64Abs"
    90  	// arm/6:"ABSD\t"
    91  	sink64[0] = math.Abs(x)
    92  
    93  	// amd64:"BTRQ\t[$]63","PXOR"    (TODO: this should be BTSQ)
    94  	// s390x:"LNDFR\t",-"MOVD\t"     (no integer load/store)
    95  	// ppc64:"FNABS\t"
    96  	// ppc64le:"FNABS\t"
    97  	sink64[1] = -math.Abs(y)
    98  }
    99  
   100  // Check that it's using integer registers
   101  func abs32(x float32) float32 {
   102  	// s390x:"LPDFR",-"LDEBR",-"LEDBR"     (no float64 conversion)
   103  	return float32(math.Abs(float64(x)))
   104  }
   105  
   106  // Check that it's using integer registers
   107  func copysign(a, b, c float64) {
   108  	// amd64:"BTRQ\t[$]63","ANDQ","ORQ"
   109  	// s390x:"CPSDR",-"MOVD"         (no integer load/store)
   110  	// ppc64:"FCPSGN"
   111  	// ppc64le:"FCPSGN"
   112  	// riscv64:"FSGNJD"
   113  	// wasm:"F64Copysign"
   114  	sink64[0] = math.Copysign(a, b)
   115  
   116  	// amd64:"BTSQ\t[$]63"
   117  	// s390x:"LNDFR\t",-"MOVD\t"     (no integer load/store)
   118  	// ppc64:"FCPSGN"
   119  	// ppc64le:"FCPSGN"
   120  	// riscv64:"FSGNJD"
   121  	// arm64:"ORR", -"AND"
   122  	sink64[1] = math.Copysign(c, -1)
   123  
   124  	// Like math.Copysign(c, -1), but with integer operations. Useful
   125  	// for platforms that have a copysign opcode to see if it's detected.
   126  	// s390x:"LNDFR\t",-"MOVD\t"     (no integer load/store)
   127  	sink64[2] = math.Float64frombits(math.Float64bits(a) | 1<<63)
   128  
   129  	// amd64:"ANDQ","ORQ"
   130  	// s390x:"CPSDR\t",-"MOVD\t"     (no integer load/store)
   131  	// ppc64:"FCPSGN"
   132  	// ppc64le:"FCPSGN"
   133  	// riscv64:"FSGNJD"
   134  	sink64[3] = math.Copysign(-1, c)
   135  }
   136  
   137  func fma(x, y, z float64) float64 {
   138  	// amd64/v3:-".*x86HasFMA"
   139  	// amd64:"VFMADD231SD"
   140  	// arm/6:"FMULAD"
   141  	// arm64:"FMADDD"
   142  	// s390x:"FMADD"
   143  	// ppc64:"FMADD"
   144  	// ppc64le:"FMADD"
   145  	// riscv64:"FMADDD"
   146  	return math.FMA(x, y, z)
   147  }
   148  
   149  func fms(x, y, z float64) float64 {
   150  	// riscv64:"FMSUBD"
   151  	return math.FMA(x, y, -z)
   152  }
   153  
   154  func fnma(x, y, z float64) float64 {
   155  	// riscv64:"FNMADDD"
   156  	return math.FMA(-x, y, z)
   157  }
   158  
   159  func fnms(x, y, z float64) float64 {
   160  	// riscv64:"FNMSUBD"
   161  	return math.FMA(x, -y, -z)
   162  }
   163  
   164  func fromFloat64(f64 float64) uint64 {
   165  	// amd64:"MOVQ\tX.*, [^X].*"
   166  	// arm64:"FMOVD\tF.*, R.*"
   167  	// ppc64:"MFVSRD"
   168  	// ppc64le:"MFVSRD"
   169  	return math.Float64bits(f64+1) + 1
   170  }
   171  
   172  func fromFloat32(f32 float32) uint32 {
   173  	// amd64:"MOVL\tX.*, [^X].*"
   174  	// arm64:"FMOVS\tF.*, R.*"
   175  	return math.Float32bits(f32+1) + 1
   176  }
   177  
   178  func toFloat64(u64 uint64) float64 {
   179  	// amd64:"MOVQ\t[^X].*, X.*"
   180  	// arm64:"FMOVD\tR.*, F.*"
   181  	// ppc64:"MTVSRD"
   182  	// ppc64le:"MTVSRD"
   183  	return math.Float64frombits(u64+1) + 1
   184  }
   185  
   186  func toFloat32(u32 uint32) float32 {
   187  	// amd64:"MOVL\t[^X].*, X.*"
   188  	// arm64:"FMOVS\tR.*, F.*"
   189  	return math.Float32frombits(u32+1) + 1
   190  }
   191  
   192  // Test that comparisons with constants converted to float
   193  // are evaluated at compile-time
   194  
   195  func constantCheck64() bool {
   196  	// amd64:"(MOVB\t[$]0)|(XORL\t[A-Z][A-Z0-9]+, [A-Z][A-Z0-9]+)",-"FCMP",-"MOVB\t[$]1"
   197  	// s390x:"MOV(B|BZ|D)\t[$]0,",-"FCMPU",-"MOV(B|BZ|D)\t[$]1,"
   198  	return 0.5 == float64(uint32(1)) || 1.5 > float64(uint64(1<<63))
   199  }
   200  
   201  func constantCheck32() bool {
   202  	// amd64:"MOV(B|L)\t[$]1",-"FCMP",-"MOV(B|L)\t[$]0"
   203  	// s390x:"MOV(B|BZ|D)\t[$]1,",-"FCMPU",-"MOV(B|BZ|D)\t[$]0,"
   204  	return float32(0.5) <= float32(int64(1)) && float32(1.5) >= float32(int32(-1<<31))
   205  }
   206  
   207  // Test that integer constants are converted to floating point constants
   208  // at compile-time
   209  
   210  func constantConvert32(x float32) float32 {
   211  	// amd64:"MOVSS\t[$]f32.3f800000\\(SB\\)"
   212  	// s390x:"FMOVS\t[$]f32.3f800000\\(SB\\)"
   213  	// ppc64:"FMOVS\t[$]f32.3f800000\\(SB\\)"
   214  	// ppc64le:"FMOVS\t[$]f32.3f800000\\(SB\\)"
   215  	// arm64:"FMOVS\t[$]\\(1.0\\)"
   216  	if x > math.Float32frombits(0x3f800000) {
   217  		return -x
   218  	}
   219  	return x
   220  }
   221  
   222  func constantConvertInt32(x uint32) uint32 {
   223  	// amd64:-"MOVSS"
   224  	// s390x:-"FMOVS"
   225  	// ppc64:-"FMOVS"
   226  	// ppc64le:-"FMOVS"
   227  	// arm64:-"FMOVS"
   228  	if x > math.Float32bits(1) {
   229  		return -x
   230  	}
   231  	return x
   232  }
   233  
   234  func nanGenerate64() float64 {
   235  	// Test to make sure we don't generate a NaN while constant propagating.
   236  	// See issue 36400.
   237  	zero := 0.0
   238  	// amd64:-"DIVSD"
   239  	inf := 1 / zero // +inf. We can constant propagate this one.
   240  	negone := -1.0
   241  
   242  	// amd64:"DIVSD"
   243  	z0 := zero / zero
   244  	// amd64:"MULSD"
   245  	z1 := zero * inf
   246  	// amd64:"SQRTSD"
   247  	z2 := math.Sqrt(negone)
   248  	return z0 + z1 + z2
   249  }
   250  
   251  func nanGenerate32() float32 {
   252  	zero := float32(0.0)
   253  	// amd64:-"DIVSS"
   254  	inf := 1 / zero // +inf. We can constant propagate this one.
   255  
   256  	// amd64:"DIVSS"
   257  	z0 := zero / zero
   258  	// amd64:"MULSS"
   259  	z1 := zero * inf
   260  	return z0 + z1
   261  }
   262  

View as plain text