// Copyright 2010 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Software IEEE754 64-bit floating point.
// Only referred to (and thus linked in) by softfloat targets
// and by tests in this directory.

package runtime

const (
	mantbits64 uint = 52
	expbits64  uint = 11
	bias64          = -1<<(expbits64-1) + 1

	nan64 uint64 = (1<<expbits64-1)<<mantbits64 + 1<<(mantbits64-1) // quiet NaN, 0 payload
	inf64 uint64 = (1<<expbits64 - 1) << mantbits64
	neg64 uint64 = 1 << (expbits64 + mantbits64)

	mantbits32 uint = 23
	expbits32  uint = 8
	bias32          = -1<<(expbits32-1) + 1

	nan32 uint32 = (1<<expbits32-1)<<mantbits32 + 1<<(mantbits32-1) // quiet NaN, 0 payload
	inf32 uint32 = (1<<expbits32 - 1) << mantbits32
	neg32 uint32 = 1 << (expbits32 + mantbits32)
)

func funpack64( uint64) (,  uint64,  int, ,  bool) {
	 =  & (1 << (mantbits64 + expbits64))
	 =  & (1<<mantbits64 - 1)
	 = int(>>mantbits64) & (1<<expbits64 - 1)

	switch  {
	case 1<<expbits64 - 1:
		if  != 0 {
			 = true
			return
		}
		 = true
		return

	case 0:
		// denormalized
		if  != 0 {
			 += bias64 + 1
			for  < 1<<mantbits64 {
				 <<= 1
				--
			}
		}

	default:
		// add implicit top bit
		 |= 1 << mantbits64
		 += bias64
	}
	return
}

func funpack32( uint32) (,  uint32,  int, ,  bool) {
	 =  & (1 << (mantbits32 + expbits32))
	 =  & (1<<mantbits32 - 1)
	 = int(>>mantbits32) & (1<<expbits32 - 1)

	switch  {
	case 1<<expbits32 - 1:
		if  != 0 {
			 = true
			return
		}
		 = true
		return

	case 0:
		// denormalized
		if  != 0 {
			 += bias32 + 1
			for  < 1<<mantbits32 {
				 <<= 1
				--
			}
		}

	default:
		// add implicit top bit
		 |= 1 << mantbits32
		 += bias32
	}
	return
}

func fpack64(,  uint64,  int,  uint64) uint64 {
	, ,  := , , 
	if  == 0 {
		return 
	}
	for  < 1<<mantbits64 {
		 <<= 1
		--
	}
	for  >= 4<<mantbits64 {
		 |=  & 1
		 >>= 1
		++
	}
	if  >= 2<<mantbits64 {
		if &1 != 0 && ( != 0 || &2 != 0) {
			++
			if  >= 4<<mantbits64 {
				 >>= 1
				++
			}
		}
		 >>= 1
		++
	}
	if  >= 1<<expbits64-1+bias64 {
		return  ^ inf64
	}
	if  < bias64+1 {
		if  < bias64-int(mantbits64) {
			return  | 0
		}
		// repeat expecting denormal
		, ,  = , , 
		for  < bias64 {
			 |=  & 1
			 >>= 1
			++
		}
		if &1 != 0 && ( != 0 || &2 != 0) {
			++
		}
		 >>= 1
		++
		if  < 1<<mantbits64 {
			return  | 
		}
	}
	return  | uint64(-bias64)<<mantbits64 | &(1<<mantbits64-1)
}

func fpack32(,  uint32,  int,  uint32) uint32 {
	, ,  := , , 
	if  == 0 {
		return 
	}
	for  < 1<<mantbits32 {
		 <<= 1
		--
	}
	for  >= 4<<mantbits32 {
		 |=  & 1
		 >>= 1
		++
	}
	if  >= 2<<mantbits32 {
		if &1 != 0 && ( != 0 || &2 != 0) {
			++
			if  >= 4<<mantbits32 {
				 >>= 1
				++
			}
		}
		 >>= 1
		++
	}
	if  >= 1<<expbits32-1+bias32 {
		return  ^ inf32
	}
	if  < bias32+1 {
		if  < bias32-int(mantbits32) {
			return  | 0
		}
		// repeat expecting denormal
		, ,  = , , 
		for  < bias32 {
			 |=  & 1
			 >>= 1
			++
		}
		if &1 != 0 && ( != 0 || &2 != 0) {
			++
		}
		 >>= 1
		++
		if  < 1<<mantbits32 {
			return  | 
		}
	}
	return  | uint32(-bias32)<<mantbits32 | &(1<<mantbits32-1)
}

func fadd64(,  uint64) uint64 {
	, , , ,  := funpack64()
	, , , ,  := funpack64()

	// Special cases.
	switch {
	case  || : // NaN + x or x + NaN = NaN
		return nan64

	case  &&  &&  != : // +Inf + -Inf or -Inf + +Inf = NaN
		return nan64

	case : // ±Inf + g = ±Inf
		return 

	case : // f + ±Inf = ±Inf
		return 

	case  == 0 &&  == 0 &&  != 0 &&  != 0: // -0 + -0 = -0
		return 

	case  == 0: // 0 + g = g but 0 + -0 = +0
		if  == 0 {
			 ^= 
		}
		return 

	case  == 0: // f + 0 = f
		return 

	}

	if  <  ||  ==  &&  <  {
		, , , , , , ,  = , , , , , , , 
	}

	 := uint( - )
	 <<= 2
	 <<= 2
	 :=  & (1<< - 1)
	 >>= 
	if  ==  {
		 += 
	} else {
		 -= 
		if  != 0 {
			--
		}
	}
	if  == 0 {
		 = 0
	}
	return fpack64(, , -2, )
}

func fsub64(,  uint64) uint64 {
	return fadd64(, fneg64())
}

func fneg64( uint64) uint64 {
	return  ^ (1 << (mantbits64 + expbits64))
}

func fmul64(,  uint64) uint64 {
	, , , ,  := funpack64()
	, , , ,  := funpack64()

	// Special cases.
	switch {
	case  || : // NaN * g or f * NaN = NaN
		return nan64

	case  && : // Inf * Inf = Inf (with sign adjusted)
		return  ^ 

	case  &&  == 0,  == 0 && : // 0 * Inf = Inf * 0 = NaN
		return nan64

	case  == 0: // 0 * x = 0 (with sign adjusted)
		return  ^ 

	case  == 0: // x * 0 = 0 (with sign adjusted)
		return  ^ 
	}

	// 53-bit * 53-bit = 107- or 108-bit
	,  := mullu(, )
	 := mantbits64 - 1
	 :=  & (1<< - 1)
	 := <<(64-) | >>
	return fpack64(^, , +-1, )
}

func fdiv64(,  uint64) uint64 {
	, , , ,  := funpack64()
	, , , ,  := funpack64()

	// Special cases.
	switch {
	case  || : // NaN / g = f / NaN = NaN
		return nan64

	case  && : // ±Inf / ±Inf = NaN
		return nan64

	case ! && ! &&  == 0 &&  == 0: // 0 / 0 = NaN
		return nan64

	case , ! &&  == 0: // Inf / g = f / 0 = Inf
		return  ^  ^ inf64

	case ,  == 0: // f / Inf = 0 / g = Inf
		return  ^  ^ 0
	}
	_, _, _, _ = , , , 

	// 53-bit<<54 / 53-bit = 53- or 54-bit.
	 := mantbits64 + 2
	,  := divlu(>>(64-), <<, )
	return fpack64(^, , --2, )
}

func f64to32( uint64) uint32 {
	, , , ,  := funpack64()
	if  {
		return nan32
	}
	 := uint32( >> 32)
	if  {
		return  ^ inf32
	}
	const  = mantbits64 - mantbits32 - 1
	return fpack32(, uint32(>>), -1, uint32(&(1<<-1)))
}

func f32to64( uint32) uint64 {
	const  = mantbits64 - mantbits32
	, , , ,  := funpack32()
	if  {
		return nan64
	}
	 := uint64() << 32
	if  {
		return  ^ inf64
	}
	return fpack64(, uint64()<<, , 0)
}

func fcmp64(,  uint64) ( int32,  bool) {
	, , , ,  := funpack64()
	, , , ,  := funpack64()

	switch {
	case , : // flag NaN
		return 0, true

	case ! && ! &&  == 0 &&  == 0: // ±0 == ±0
		return 0, false

	case  > : // f < 0, g > 0
		return -1, false

	case  < : // f > 0, g < 0
		return +1, false

	// Same sign, not NaN.
	// Can compare encodings directly now.
	// Reverse for sign.
	case  == 0 &&  < ,  != 0 &&  > :
		return -1, false

	case  == 0 &&  > ,  != 0 &&  < :
		return +1, false
	}

	// f == g
	return 0, false
}

func f64toint( uint64) ( int64,  bool) {
	, , , ,  := funpack64()

	switch {
	case , : // NaN
		return 0, false

	case  < -1: // f < 0.5
		return 0, false

	case  > 63: // f >= 2^63
		if  != 0 &&  == 0 { // f == -2^63
			return -1 << 63, true
		}
		if  != 0 {
			return 0, false
		}
		return 0, false
	}

	for  > int(mantbits64) {
		--
		 <<= 1
	}
	for  < int(mantbits64) {
		++
		 >>= 1
	}
	 = int64()
	if  != 0 {
		 = -
	}
	return , true
}

func fintto64( int64) ( uint64) {
	 := uint64() & (1 << 63)
	 := uint64()
	if  != 0 {
		 = -
	}
	return fpack64(, , int(mantbits64), 0)
}
func fintto32( int64) ( uint32) {
	 := uint64() & (1 << 63)
	 := uint64()
	if  != 0 {
		 = -
	}
	// Reduce mantissa size until it fits into a uint32.
	// Keep track of the bits we throw away, and if any are
	// nonzero or them into the lowest bit.
	 := int(mantbits32)
	var  uint32
	for  >= 1<<32 {
		 |= uint32() & 1
		 >>= 1
		++
	}

	return fpack32(uint32(>>32), uint32(), , )
}

// 64x64 -> 128 multiply.
// adapted from hacker's delight.
func mullu(,  uint64) (,  uint64) {
	const (
		    = 32
		 = 1<< - 1
	)
	 :=  & 
	 :=  >> 
	 :=  & 
	 :=  >> 
	 :=  * 
	 := * + >>
	 :=  & 
	 :=  >> 
	 +=  * 
	return  * , * +  + >>
}

// 128/64 -> 64 quotient, 64 remainder.
// adapted from hacker's delight
func divlu(, ,  uint64) (,  uint64) {
	const  = 1 << 32

	if  >=  {
		return 1<<64 - 1, 1<<64 - 1
	}

	// s = nlz(v); v <<= s
	 := uint(0)
	for &(1<<63) == 0 {
		++
		 <<= 1
	}

	 :=  >> 32
	 :=  & (1<<32 - 1)
	 := << | >>(64-)
	 :=  << 
	 :=  >> 32
	 :=  & (1<<32 - 1)
	 :=  / 
	 :=  - *

:
	if  >=  || * > *+ {
		--
		 += 
		if  <  {
			goto 
		}
	}

	 := * +  - *
	 :=  / 
	 =  - *

:
	if  >=  || * > *+ {
		--
		 += 
		if  <  {
			goto 
		}
	}

	return * + , (* +  - *) >> 
}

func fadd32(,  uint32) uint32 {
	return f64to32(fadd64(f32to64(), f32to64()))
}

func fmul32(,  uint32) uint32 {
	return f64to32(fmul64(f32to64(), f32to64()))
}

func fdiv32(,  uint32) uint32 {
	// TODO: are there double-rounding problems here? See issue 48807.
	return f64to32(fdiv64(f32to64(), f32to64()))
}

func feq32(,  uint32) bool {
	,  := fcmp64(f32to64(), f32to64())
	return  == 0 && !
}

func fgt32(,  uint32) bool {
	,  := fcmp64(f32to64(), f32to64())
	return  >= 1 && !
}

func fge32(,  uint32) bool {
	,  := fcmp64(f32to64(), f32to64())
	return  >= 0 && !
}

func feq64(,  uint64) bool {
	,  := fcmp64(, )
	return  == 0 && !
}

func fgt64(,  uint64) bool {
	,  := fcmp64(, )
	return  >= 1 && !
}

func fge64(,  uint64) bool {
	,  := fcmp64(, )
	return  >= 0 && !
}

func fint32to32( int32) uint32 {
	return fintto32(int64())
}

func fint32to64( int32) uint64 {
	return fintto64(int64())
}

func fint64to32( int64) uint32 {
	return fintto32()
}

func fint64to64( int64) uint64 {
	return fintto64()
}

func f32toint32( uint32) int32 {
	,  := f64toint(f32to64())
	return int32()
}

func f32toint64( uint32) int64 {
	,  := f64toint(f32to64())
	return 
}

func f64toint32( uint64) int32 {
	,  := f64toint()
	return int32()
}

func f64toint64( uint64) int64 {
	,  := f64toint()
	return 
}

func f64touint64( uint64) uint64 {
	var  uint64 = 0x43e0000000000000 // float64 1<<63
	if fgt64(, ) {
		return uint64(f64toint64())
	}
	 := fadd64(, -)
	 := uint64(f64toint64())
	return  | (1 << 63)
}

func f32touint64( uint32) uint64 {
	var  uint32 = 0x5f000000 // float32 1<<63
	if fgt32(, ) {
		return uint64(f32toint64())
	}
	 := fadd32(, -)
	 := uint64(f32toint64())
	return  | (1 << 63)
}

func fuint64to64( uint64) uint64 {
	if int64() >= 0 {
		return fint64to64(int64())
	}
	// See ../cmd/compile/internal/ssagen/ssa.go:uint64Tofloat
	 :=  & 1
	 :=  >> 1
	 =  | 
	 := fint64to64(int64())
	return fadd64(, )
}

func fuint64to32( uint64) uint32 {
	if int64() >= 0 {
		return fint64to32(int64())
	}
	// See ../cmd/compile/internal/ssagen/ssa.go:uint64Tofloat
	 :=  & 1
	 :=  >> 1
	 =  | 
	 := fint64to32(int64())
	return fadd32(, )
}