mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
Previously the compiler rewrote constant division into OHMUL operations, but that rewriting was moved to SSA in CL 37015. Now OHMUL is unused, so we can get rid of it. Change-Id: Ib6fc7c2b6435510bafb5735b3b4f42cfd8ed8cdb Reviewed-on: https://go-review.googlesource.com/37750 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com> Reviewed-by: Keith Randall <khr@golang.org>
472 lines
11 KiB
Go
472 lines
11 KiB
Go
// Copyright 2009 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.
|
|
|
|
package gc
|
|
|
|
// builtinpkg is a fake package that declares the universe block.
|
|
var builtinpkg *Pkg
|
|
|
|
var itable *Type // distinguished *byte
|
|
|
|
var basicTypes = [...]struct {
|
|
name string
|
|
etype EType
|
|
}{
|
|
{"int8", TINT8},
|
|
{"int16", TINT16},
|
|
{"int32", TINT32},
|
|
{"int64", TINT64},
|
|
{"uint8", TUINT8},
|
|
{"uint16", TUINT16},
|
|
{"uint32", TUINT32},
|
|
{"uint64", TUINT64},
|
|
{"float32", TFLOAT32},
|
|
{"float64", TFLOAT64},
|
|
{"complex64", TCOMPLEX64},
|
|
{"complex128", TCOMPLEX128},
|
|
{"bool", TBOOL},
|
|
{"string", TSTRING},
|
|
}
|
|
|
|
var typedefs = [...]struct {
|
|
name string
|
|
etype EType
|
|
width *int
|
|
sameas32 EType
|
|
sameas64 EType
|
|
}{
|
|
{"int", TINT, &Widthint, TINT32, TINT64},
|
|
{"uint", TUINT, &Widthint, TUINT32, TUINT64},
|
|
{"uintptr", TUINTPTR, &Widthptr, TUINT32, TUINT64},
|
|
}
|
|
|
|
var builtinFuncs = [...]struct {
|
|
name string
|
|
op Op
|
|
}{
|
|
{"append", OAPPEND},
|
|
{"cap", OCAP},
|
|
{"close", OCLOSE},
|
|
{"complex", OCOMPLEX},
|
|
{"copy", OCOPY},
|
|
{"delete", ODELETE},
|
|
{"imag", OIMAG},
|
|
{"len", OLEN},
|
|
{"make", OMAKE},
|
|
{"new", ONEW},
|
|
{"panic", OPANIC},
|
|
{"print", OPRINT},
|
|
{"println", OPRINTN},
|
|
{"real", OREAL},
|
|
{"recover", ORECOVER},
|
|
}
|
|
|
|
var unsafeFuncs = [...]struct {
|
|
name string
|
|
op Op
|
|
}{
|
|
{"Alignof", OALIGNOF},
|
|
{"Offsetof", OOFFSETOF},
|
|
{"Sizeof", OSIZEOF},
|
|
}
|
|
|
|
// initUniverse initializes the universe block.
|
|
func initUniverse() {
|
|
lexinit()
|
|
typeinit()
|
|
lexinit1()
|
|
}
|
|
|
|
// lexinit initializes known symbols and the basic types.
|
|
func lexinit() {
|
|
for _, s := range basicTypes {
|
|
etype := s.etype
|
|
if int(etype) >= len(Types) {
|
|
Fatalf("lexinit: %s bad etype", s.name)
|
|
}
|
|
s2 := Pkglookup(s.name, builtinpkg)
|
|
t := Types[etype]
|
|
if t == nil {
|
|
t = typ(etype)
|
|
t.Sym = s2
|
|
if etype != TANY && etype != TSTRING {
|
|
dowidth(t)
|
|
}
|
|
Types[etype] = t
|
|
}
|
|
s2.Def = typenod(t)
|
|
s2.Def.Name = new(Name)
|
|
}
|
|
|
|
for _, s := range builtinFuncs {
|
|
// TODO(marvin): Fix Node.EType type union.
|
|
s2 := Pkglookup(s.name, builtinpkg)
|
|
s2.Def = nod(ONAME, nil, nil)
|
|
s2.Def.Sym = s2
|
|
s2.Def.Etype = EType(s.op)
|
|
}
|
|
|
|
for _, s := range unsafeFuncs {
|
|
s2 := Pkglookup(s.name, unsafepkg)
|
|
s2.Def = nod(ONAME, nil, nil)
|
|
s2.Def.Sym = s2
|
|
s2.Def.Etype = EType(s.op)
|
|
}
|
|
|
|
idealstring = typ(TSTRING)
|
|
idealbool = typ(TBOOL)
|
|
Types[TANY] = typ(TANY)
|
|
|
|
s := Pkglookup("true", builtinpkg)
|
|
s.Def = nodbool(true)
|
|
s.Def.Sym = lookup("true")
|
|
s.Def.Name = new(Name)
|
|
s.Def.Type = idealbool
|
|
|
|
s = Pkglookup("false", builtinpkg)
|
|
s.Def = nodbool(false)
|
|
s.Def.Sym = lookup("false")
|
|
s.Def.Name = new(Name)
|
|
s.Def.Type = idealbool
|
|
|
|
s = lookup("_")
|
|
s.Block = -100
|
|
s.Def = nod(ONAME, nil, nil)
|
|
s.Def.Sym = s
|
|
Types[TBLANK] = typ(TBLANK)
|
|
s.Def.Type = Types[TBLANK]
|
|
nblank = s.Def
|
|
|
|
s = Pkglookup("_", builtinpkg)
|
|
s.Block = -100
|
|
s.Def = nod(ONAME, nil, nil)
|
|
s.Def.Sym = s
|
|
Types[TBLANK] = typ(TBLANK)
|
|
s.Def.Type = Types[TBLANK]
|
|
|
|
Types[TNIL] = typ(TNIL)
|
|
s = Pkglookup("nil", builtinpkg)
|
|
var v Val
|
|
v.U = new(NilVal)
|
|
s.Def = nodlit(v)
|
|
s.Def.Sym = s
|
|
s.Def.Name = new(Name)
|
|
|
|
s = Pkglookup("iota", builtinpkg)
|
|
s.Def = nod(OIOTA, nil, nil)
|
|
s.Def.Sym = s
|
|
s.Def.Name = new(Name)
|
|
}
|
|
|
|
func typeinit() {
|
|
if Widthptr == 0 {
|
|
Fatalf("typeinit before betypeinit")
|
|
}
|
|
|
|
for et := EType(0); et < NTYPE; et++ {
|
|
simtype[et] = et
|
|
}
|
|
|
|
Types[TPTR32] = typ(TPTR32)
|
|
dowidth(Types[TPTR32])
|
|
|
|
Types[TPTR64] = typ(TPTR64)
|
|
dowidth(Types[TPTR64])
|
|
|
|
t := typ(TUNSAFEPTR)
|
|
Types[TUNSAFEPTR] = t
|
|
t.Sym = Pkglookup("Pointer", unsafepkg)
|
|
t.Sym.Def = typenod(t)
|
|
t.Sym.Def.Name = new(Name)
|
|
dowidth(Types[TUNSAFEPTR])
|
|
|
|
Tptr = TPTR32
|
|
if Widthptr == 8 {
|
|
Tptr = TPTR64
|
|
}
|
|
|
|
for et := TINT8; et <= TUINT64; et++ {
|
|
isInt[et] = true
|
|
}
|
|
isInt[TINT] = true
|
|
isInt[TUINT] = true
|
|
isInt[TUINTPTR] = true
|
|
|
|
isFloat[TFLOAT32] = true
|
|
isFloat[TFLOAT64] = true
|
|
|
|
isComplex[TCOMPLEX64] = true
|
|
isComplex[TCOMPLEX128] = true
|
|
|
|
isforw[TFORW] = true
|
|
|
|
// initialize okfor
|
|
for et := EType(0); et < NTYPE; et++ {
|
|
if isInt[et] || et == TIDEAL {
|
|
okforeq[et] = true
|
|
okforcmp[et] = true
|
|
okforarith[et] = true
|
|
okforadd[et] = true
|
|
okforand[et] = true
|
|
okforconst[et] = true
|
|
issimple[et] = true
|
|
minintval[et] = new(Mpint)
|
|
maxintval[et] = new(Mpint)
|
|
}
|
|
|
|
if isFloat[et] {
|
|
okforeq[et] = true
|
|
okforcmp[et] = true
|
|
okforadd[et] = true
|
|
okforarith[et] = true
|
|
okforconst[et] = true
|
|
issimple[et] = true
|
|
minfltval[et] = newMpflt()
|
|
maxfltval[et] = newMpflt()
|
|
}
|
|
|
|
if isComplex[et] {
|
|
okforeq[et] = true
|
|
okforadd[et] = true
|
|
okforarith[et] = true
|
|
okforconst[et] = true
|
|
issimple[et] = true
|
|
}
|
|
}
|
|
|
|
issimple[TBOOL] = true
|
|
|
|
okforadd[TSTRING] = true
|
|
|
|
okforbool[TBOOL] = true
|
|
|
|
okforcap[TARRAY] = true
|
|
okforcap[TCHAN] = true
|
|
okforcap[TSLICE] = true
|
|
|
|
okforconst[TBOOL] = true
|
|
okforconst[TSTRING] = true
|
|
|
|
okforlen[TARRAY] = true
|
|
okforlen[TCHAN] = true
|
|
okforlen[TMAP] = true
|
|
okforlen[TSLICE] = true
|
|
okforlen[TSTRING] = true
|
|
|
|
okforeq[TPTR32] = true
|
|
okforeq[TPTR64] = true
|
|
okforeq[TUNSAFEPTR] = true
|
|
okforeq[TINTER] = true
|
|
okforeq[TCHAN] = true
|
|
okforeq[TSTRING] = true
|
|
okforeq[TBOOL] = true
|
|
okforeq[TMAP] = true // nil only; refined in typecheck
|
|
okforeq[TFUNC] = true // nil only; refined in typecheck
|
|
okforeq[TSLICE] = true // nil only; refined in typecheck
|
|
okforeq[TARRAY] = true // only if element type is comparable; refined in typecheck
|
|
okforeq[TSTRUCT] = true // only if all struct fields are comparable; refined in typecheck
|
|
|
|
okforcmp[TSTRING] = true
|
|
|
|
var i int
|
|
for i = 0; i < len(okfor); i++ {
|
|
okfor[i] = okfornone[:]
|
|
}
|
|
|
|
// binary
|
|
okfor[OADD] = okforadd[:]
|
|
|
|
okfor[OAND] = okforand[:]
|
|
okfor[OANDAND] = okforbool[:]
|
|
okfor[OANDNOT] = okforand[:]
|
|
okfor[ODIV] = okforarith[:]
|
|
okfor[OEQ] = okforeq[:]
|
|
okfor[OGE] = okforcmp[:]
|
|
okfor[OGT] = okforcmp[:]
|
|
okfor[OLE] = okforcmp[:]
|
|
okfor[OLT] = okforcmp[:]
|
|
okfor[OMOD] = okforand[:]
|
|
okfor[OMUL] = okforarith[:]
|
|
okfor[ONE] = okforeq[:]
|
|
okfor[OOR] = okforand[:]
|
|
okfor[OOROR] = okforbool[:]
|
|
okfor[OSUB] = okforarith[:]
|
|
okfor[OXOR] = okforand[:]
|
|
okfor[OLSH] = okforand[:]
|
|
okfor[ORSH] = okforand[:]
|
|
|
|
// unary
|
|
okfor[OCOM] = okforand[:]
|
|
|
|
okfor[OMINUS] = okforarith[:]
|
|
okfor[ONOT] = okforbool[:]
|
|
okfor[OPLUS] = okforarith[:]
|
|
|
|
// special
|
|
okfor[OCAP] = okforcap[:]
|
|
|
|
okfor[OLEN] = okforlen[:]
|
|
|
|
// comparison
|
|
iscmp[OLT] = true
|
|
|
|
iscmp[OGT] = true
|
|
iscmp[OGE] = true
|
|
iscmp[OLE] = true
|
|
iscmp[OEQ] = true
|
|
iscmp[ONE] = true
|
|
|
|
maxintval[TINT8].SetString("0x7f")
|
|
minintval[TINT8].SetString("-0x80")
|
|
maxintval[TINT16].SetString("0x7fff")
|
|
minintval[TINT16].SetString("-0x8000")
|
|
maxintval[TINT32].SetString("0x7fffffff")
|
|
minintval[TINT32].SetString("-0x80000000")
|
|
maxintval[TINT64].SetString("0x7fffffffffffffff")
|
|
minintval[TINT64].SetString("-0x8000000000000000")
|
|
|
|
maxintval[TUINT8].SetString("0xff")
|
|
maxintval[TUINT16].SetString("0xffff")
|
|
maxintval[TUINT32].SetString("0xffffffff")
|
|
maxintval[TUINT64].SetString("0xffffffffffffffff")
|
|
|
|
// f is valid float if min < f < max. (min and max are not themselves valid.)
|
|
maxfltval[TFLOAT32].SetString("33554431p103") // 2^24-1 p (127-23) + 1/2 ulp
|
|
minfltval[TFLOAT32].SetString("-33554431p103")
|
|
maxfltval[TFLOAT64].SetString("18014398509481983p970") // 2^53-1 p (1023-52) + 1/2 ulp
|
|
minfltval[TFLOAT64].SetString("-18014398509481983p970")
|
|
|
|
maxfltval[TCOMPLEX64] = maxfltval[TFLOAT32]
|
|
minfltval[TCOMPLEX64] = minfltval[TFLOAT32]
|
|
maxfltval[TCOMPLEX128] = maxfltval[TFLOAT64]
|
|
minfltval[TCOMPLEX128] = minfltval[TFLOAT64]
|
|
|
|
// for walk to use in error messages
|
|
Types[TFUNC] = functype(nil, nil, nil)
|
|
|
|
// types used in front end
|
|
// types[TNIL] got set early in lexinit
|
|
Types[TIDEAL] = typ(TIDEAL)
|
|
|
|
Types[TINTER] = typ(TINTER)
|
|
|
|
// simple aliases
|
|
simtype[TMAP] = Tptr
|
|
|
|
simtype[TCHAN] = Tptr
|
|
simtype[TFUNC] = Tptr
|
|
simtype[TUNSAFEPTR] = Tptr
|
|
|
|
array_array = int(Rnd(0, int64(Widthptr)))
|
|
array_nel = int(Rnd(int64(array_array)+int64(Widthptr), int64(Widthint)))
|
|
array_cap = int(Rnd(int64(array_nel)+int64(Widthint), int64(Widthint)))
|
|
sizeof_Array = int(Rnd(int64(array_cap)+int64(Widthint), int64(Widthptr)))
|
|
|
|
// string is same as slice wo the cap
|
|
sizeof_String = int(Rnd(int64(array_nel)+int64(Widthint), int64(Widthptr)))
|
|
|
|
dowidth(Types[TSTRING])
|
|
dowidth(idealstring)
|
|
|
|
itable = typPtr(Types[TUINT8])
|
|
}
|
|
|
|
func makeErrorInterface() *Type {
|
|
field := newField()
|
|
field.Type = Types[TSTRING]
|
|
f := functypefield(fakethisfield(), nil, []*Field{field})
|
|
|
|
field = newField()
|
|
field.Sym = lookup("Error")
|
|
field.Type = f
|
|
|
|
t := typ(TINTER)
|
|
t.SetFields([]*Field{field})
|
|
return t
|
|
}
|
|
|
|
func lexinit1() {
|
|
// error type
|
|
s := Pkglookup("error", builtinpkg)
|
|
errortype = makeErrorInterface()
|
|
errortype.Sym = s
|
|
// TODO: If we can prove that it's safe to set errortype.Orig here
|
|
// than we don't need the special errortype/errorInterface case in
|
|
// bexport.go. See also issue #15920.
|
|
// errortype.Orig = makeErrorInterface()
|
|
s.Def = typenod(errortype)
|
|
|
|
// We create separate byte and rune types for better error messages
|
|
// rather than just creating type alias *Sym's for the uint8 and
|
|
// int32 types. Hence, (bytetype|runtype).Sym.isAlias() is false.
|
|
// TODO(gri) Should we get rid of this special case (at the cost
|
|
// of less informative error messages involving bytes and runes)?
|
|
// (Alternatively, we could introduce an OTALIAS node representing
|
|
// type aliases, albeit at the cost of having to deal with it everywhere).
|
|
|
|
// byte alias
|
|
s = Pkglookup("byte", builtinpkg)
|
|
bytetype = typ(TUINT8)
|
|
bytetype.Sym = s
|
|
s.Def = typenod(bytetype)
|
|
s.Def.Name = new(Name)
|
|
|
|
// rune alias
|
|
s = Pkglookup("rune", builtinpkg)
|
|
runetype = typ(TINT32)
|
|
runetype.Sym = s
|
|
s.Def = typenod(runetype)
|
|
s.Def.Name = new(Name)
|
|
|
|
// backend-dependent builtin types (e.g. int).
|
|
for _, s := range typedefs {
|
|
s1 := Pkglookup(s.name, builtinpkg)
|
|
|
|
sameas := s.sameas32
|
|
if *s.width == 8 {
|
|
sameas = s.sameas64
|
|
}
|
|
|
|
simtype[s.etype] = sameas
|
|
minfltval[s.etype] = minfltval[sameas]
|
|
maxfltval[s.etype] = maxfltval[sameas]
|
|
minintval[s.etype] = minintval[sameas]
|
|
maxintval[s.etype] = maxintval[sameas]
|
|
|
|
t := typ(s.etype)
|
|
t.Sym = s1
|
|
Types[s.etype] = t
|
|
s1.Def = typenod(t)
|
|
s1.Def.Name = new(Name)
|
|
s1.Origpkg = builtinpkg
|
|
|
|
dowidth(t)
|
|
}
|
|
}
|
|
|
|
// finishUniverse makes the universe block visible within the current package.
|
|
func finishUniverse() {
|
|
// Operationally, this is similar to a dot import of builtinpkg, except
|
|
// that we silently skip symbols that are already declared in the
|
|
// package block rather than emitting a redeclared symbol error.
|
|
|
|
for _, s := range builtinpkg.Syms {
|
|
if s.Def == nil {
|
|
continue
|
|
}
|
|
s1 := lookup(s.Name)
|
|
if s1.Def != nil {
|
|
continue
|
|
}
|
|
|
|
s1.Def = s.Def
|
|
s1.Block = s.Block
|
|
}
|
|
|
|
nodfp = nod(ONAME, nil, nil)
|
|
nodfp.Type = Types[TINT32]
|
|
nodfp.Xoffset = 0
|
|
nodfp.Class = PPARAM
|
|
nodfp.Sym = lookup(".fp")
|
|
}
|