github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/ir/const.go (about)

     1  // Copyright 2009 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package ir
     6  
     7  import (
     8  	"go/constant"
     9  	"math"
    10  	"math/big"
    11  
    12  	"github.com/go-asm/go/cmd/compile/base"
    13  	"github.com/go-asm/go/cmd/compile/types"
    14  	"github.com/go-asm/go/cmd/src"
    15  )
    16  
    17  // NewBool returns an OLITERAL representing b as an untyped boolean.
    18  func NewBool(pos src.XPos, b bool) Node {
    19  	return NewBasicLit(pos, types.UntypedBool, constant.MakeBool(b))
    20  }
    21  
    22  // NewInt returns an OLITERAL representing v as an untyped integer.
    23  func NewInt(pos src.XPos, v int64) Node {
    24  	return NewBasicLit(pos, types.UntypedInt, constant.MakeInt64(v))
    25  }
    26  
    27  // NewString returns an OLITERAL representing s as an untyped string.
    28  func NewString(pos src.XPos, s string) Node {
    29  	return NewBasicLit(pos, types.UntypedString, constant.MakeString(s))
    30  }
    31  
    32  // NewUintptr returns an OLITERAL representing v as a uintptr.
    33  func NewUintptr(pos src.XPos, v int64) Node {
    34  	return NewBasicLit(pos, types.Types[types.TUINTPTR], constant.MakeInt64(v))
    35  }
    36  
    37  // NewZero returns a zero value of the given type.
    38  func NewZero(pos src.XPos, typ *types.Type) Node {
    39  	switch {
    40  	case typ.HasNil():
    41  		return NewNilExpr(pos, typ)
    42  	case typ.IsInteger():
    43  		return NewBasicLit(pos, typ, intZero)
    44  	case typ.IsFloat():
    45  		return NewBasicLit(pos, typ, floatZero)
    46  	case typ.IsComplex():
    47  		return NewBasicLit(pos, typ, complexZero)
    48  	case typ.IsBoolean():
    49  		return NewBasicLit(pos, typ, constant.MakeBool(false))
    50  	case typ.IsString():
    51  		return NewBasicLit(pos, typ, constant.MakeString(""))
    52  	case typ.IsArray() || typ.IsStruct():
    53  		// TODO(mdempsky): Return a typechecked expression instead.
    54  		return NewCompLitExpr(pos, OCOMPLIT, typ, nil)
    55  	}
    56  
    57  	base.FatalfAt(pos, "unexpected type: %v", typ)
    58  	panic("unreachable")
    59  }
    60  
    61  var (
    62  	intZero     = constant.MakeInt64(0)
    63  	floatZero   = constant.ToFloat(intZero)
    64  	complexZero = constant.ToComplex(intZero)
    65  )
    66  
    67  // NewOne returns an OLITERAL representing 1 with the given type.
    68  func NewOne(pos src.XPos, typ *types.Type) Node {
    69  	var val constant.Value
    70  	switch {
    71  	case typ.IsInteger():
    72  		val = intOne
    73  	case typ.IsFloat():
    74  		val = floatOne
    75  	case typ.IsComplex():
    76  		val = complexOne
    77  	default:
    78  		base.FatalfAt(pos, "%v cannot represent 1", typ)
    79  	}
    80  
    81  	return NewBasicLit(pos, typ, val)
    82  }
    83  
    84  var (
    85  	intOne     = constant.MakeInt64(1)
    86  	floatOne   = constant.ToFloat(intOne)
    87  	complexOne = constant.ToComplex(intOne)
    88  )
    89  
    90  const (
    91  	// Maximum size in bits for big.Ints before signaling
    92  	// overflow and also mantissa precision for big.Floats.
    93  	ConstPrec = 512
    94  )
    95  
    96  func BigFloat(v constant.Value) *big.Float {
    97  	f := new(big.Float)
    98  	f.SetPrec(ConstPrec)
    99  	switch u := constant.Val(v).(type) {
   100  	case int64:
   101  		f.SetInt64(u)
   102  	case *big.Int:
   103  		f.SetInt(u)
   104  	case *big.Float:
   105  		f.Set(u)
   106  	case *big.Rat:
   107  		f.SetRat(u)
   108  	default:
   109  		base.Fatalf("unexpected: %v", u)
   110  	}
   111  	return f
   112  }
   113  
   114  // ConstOverflow reports whether constant value v is too large
   115  // to represent with type t.
   116  func ConstOverflow(v constant.Value, t *types.Type) bool {
   117  	switch {
   118  	case t.IsInteger():
   119  		bits := uint(8 * t.Size())
   120  		if t.IsUnsigned() {
   121  			x, ok := constant.Uint64Val(v)
   122  			return !ok || x>>bits != 0
   123  		}
   124  		x, ok := constant.Int64Val(v)
   125  		if x < 0 {
   126  			x = ^x
   127  		}
   128  		return !ok || x>>(bits-1) != 0
   129  	case t.IsFloat():
   130  		switch t.Size() {
   131  		case 4:
   132  			f, _ := constant.Float32Val(v)
   133  			return math.IsInf(float64(f), 0)
   134  		case 8:
   135  			f, _ := constant.Float64Val(v)
   136  			return math.IsInf(f, 0)
   137  		}
   138  	case t.IsComplex():
   139  		ft := types.FloatForComplex(t)
   140  		return ConstOverflow(constant.Real(v), ft) || ConstOverflow(constant.Imag(v), ft)
   141  	}
   142  	base.Fatalf("ConstOverflow: %v, %v", v, t)
   143  	panic("unreachable")
   144  }
   145  
   146  // IsConstNode reports whether n is a Go language constant (as opposed to a
   147  // compile-time constant).
   148  //
   149  // Expressions derived from nil, like string([]byte(nil)), while they
   150  // may be known at compile time, are not Go language constants.
   151  func IsConstNode(n Node) bool {
   152  	return n.Op() == OLITERAL
   153  }
   154  
   155  func IsSmallIntConst(n Node) bool {
   156  	if n.Op() == OLITERAL {
   157  		v, ok := constant.Int64Val(n.Val())
   158  		return ok && int64(int32(v)) == v
   159  	}
   160  	return false
   161  }