"Fossies" - the Fresh Open Source Software Archive  

Source code changes of the file "src/cmd/compile/internal/ssagen/ssa.go" between
go1.19.src.tar.gz and go1.19.1.src.tar.gz

About: Google’s Go is a compiled, garbage-collected, concurrent programming language.
Latest stable release (1.19).

ssa.go  (go1.19.src):ssa.go  (go1.19.1.src)
skipping to change at line 108 skipping to change at line 108
ir.Syms.AssertI2I2 = typecheck.LookupRuntimeFunc("assertI2I2") ir.Syms.AssertI2I2 = typecheck.LookupRuntimeFunc("assertI2I2")
ir.Syms.CheckPtrAlignment = typecheck.LookupRuntimeFunc("checkptrAlignmen t") ir.Syms.CheckPtrAlignment = typecheck.LookupRuntimeFunc("checkptrAlignmen t")
ir.Syms.Deferproc = typecheck.LookupRuntimeFunc("deferproc") ir.Syms.Deferproc = typecheck.LookupRuntimeFunc("deferproc")
ir.Syms.DeferprocStack = typecheck.LookupRuntimeFunc("deferprocStack") ir.Syms.DeferprocStack = typecheck.LookupRuntimeFunc("deferprocStack")
ir.Syms.Deferreturn = typecheck.LookupRuntimeFunc("deferreturn") ir.Syms.Deferreturn = typecheck.LookupRuntimeFunc("deferreturn")
ir.Syms.Duffcopy = typecheck.LookupRuntimeFunc("duffcopy") ir.Syms.Duffcopy = typecheck.LookupRuntimeFunc("duffcopy")
ir.Syms.Duffzero = typecheck.LookupRuntimeFunc("duffzero") ir.Syms.Duffzero = typecheck.LookupRuntimeFunc("duffzero")
ir.Syms.GCWriteBarrier = typecheck.LookupRuntimeFunc("gcWriteBarrier") ir.Syms.GCWriteBarrier = typecheck.LookupRuntimeFunc("gcWriteBarrier")
ir.Syms.Goschedguarded = typecheck.LookupRuntimeFunc("goschedguarded") ir.Syms.Goschedguarded = typecheck.LookupRuntimeFunc("goschedguarded")
ir.Syms.Growslice = typecheck.LookupRuntimeFunc("growslice") ir.Syms.Growslice = typecheck.LookupRuntimeFunc("growslice")
ir.Syms.Memmove = typecheck.LookupRuntimeFunc("memmove")
ir.Syms.Msanread = typecheck.LookupRuntimeFunc("msanread") ir.Syms.Msanread = typecheck.LookupRuntimeFunc("msanread")
ir.Syms.Msanwrite = typecheck.LookupRuntimeFunc("msanwrite") ir.Syms.Msanwrite = typecheck.LookupRuntimeFunc("msanwrite")
ir.Syms.Msanmove = typecheck.LookupRuntimeFunc("msanmove") ir.Syms.Msanmove = typecheck.LookupRuntimeFunc("msanmove")
ir.Syms.Asanread = typecheck.LookupRuntimeFunc("asanread") ir.Syms.Asanread = typecheck.LookupRuntimeFunc("asanread")
ir.Syms.Asanwrite = typecheck.LookupRuntimeFunc("asanwrite") ir.Syms.Asanwrite = typecheck.LookupRuntimeFunc("asanwrite")
ir.Syms.Newobject = typecheck.LookupRuntimeFunc("newobject") ir.Syms.Newobject = typecheck.LookupRuntimeFunc("newobject")
ir.Syms.Newproc = typecheck.LookupRuntimeFunc("newproc") ir.Syms.Newproc = typecheck.LookupRuntimeFunc("newproc")
ir.Syms.Panicdivide = typecheck.LookupRuntimeFunc("panicdivide") ir.Syms.Panicdivide = typecheck.LookupRuntimeFunc("panicdivide")
ir.Syms.PanicdottypeE = typecheck.LookupRuntimeFunc("panicdottypeE") ir.Syms.PanicdottypeE = typecheck.LookupRuntimeFunc("panicdottypeE")
ir.Syms.PanicdottypeI = typecheck.LookupRuntimeFunc("panicdottypeI") ir.Syms.PanicdottypeI = typecheck.LookupRuntimeFunc("panicdottypeI")
skipping to change at line 1362 skipping to change at line 1363
} }
func (s *state) zero(t *types.Type, dst *ssa.Value) { func (s *state) zero(t *types.Type, dst *ssa.Value) {
s.instrument(t, dst, instrumentWrite) s.instrument(t, dst, instrumentWrite)
store := s.newValue2I(ssa.OpZero, types.TypeMem, t.Size(), dst, s.mem()) store := s.newValue2I(ssa.OpZero, types.TypeMem, t.Size(), dst, s.mem())
store.Aux = t store.Aux = t
s.vars[memVar] = store s.vars[memVar] = store
} }
func (s *state) move(t *types.Type, dst, src *ssa.Value) { func (s *state) move(t *types.Type, dst, src *ssa.Value) {
s.moveWhichMayOverlap(t, dst, src, false)
}
func (s *state) moveWhichMayOverlap(t *types.Type, dst, src *ssa.Value, mayOverl
ap bool) {
s.instrumentMove(t, dst, src) s.instrumentMove(t, dst, src)
if mayOverlap && t.IsArray() && t.NumElem() > 1 && !ssa.IsInlinableMemmov
e(dst, src, t.Size(), s.f.Config) {
// Normally, when moving Go values of type T from one location to
another,
// we don't need to worry about partial overlaps. The two Ts must
either be
// in disjoint (nonoverlapping) memory or in exactly the same loc
ation.
// There are 2 cases where this isn't true:
// 1) Using unsafe you can arrange partial overlaps.
// 2) Since Go 1.17, you can use a cast from a slice to a ptr-to
-array.
// https://go.dev/ref/spec#Conversions_from_slice_to_array_po
inter
// This feature can be used to construct partial overlaps of
array types.
// var a [3]int
// p := (*[2]int)(a[:])
// q := (*[2]int)(a[1:])
// *p = *q
// We don't care about solving 1. Or at least, we haven't histori
cally
// and no one has complained.
// For 2, we need to ensure that if there might be partial overla
p,
// then we can't use OpMove; we must use memmove instead.
// (memmove handles partial overlap by copying in the correct
// direction. OpMove does not.)
//
// Note that we have to be careful here not to introduce a call w
hen
// we're marshaling arguments to a call or unmarshaling results f
rom a call.
// Cases where this is happening must pass mayOverlap to false.
// (Currently this only happens when unmarshaling results of a ca
ll.)
if t.HasPointers() {
s.rtcall(ir.Syms.Typedmemmove, true, nil, s.reflectType(t
), dst, src)
// We would have otherwise implemented this move with str
aightline code,
// including a write barrier. Pretend we issue a write ba
rrier here,
// so that the write barrier tests work. (Otherwise they'
d need to know
// the details of IsInlineableMemmove.)
s.curfn.SetWBPos(s.peekPos())
} else {
s.rtcall(ir.Syms.Memmove, true, nil, dst, src, s.constInt
(types.Types[types.TUINTPTR], t.Size()))
}
ssa.LogLargeCopy(s.f.Name, s.peekPos(), t.Size())
return
}
store := s.newValue3I(ssa.OpMove, types.TypeMem, t.Size(), dst, src, s.me m()) store := s.newValue3I(ssa.OpMove, types.TypeMem, t.Size(), dst, src, s.me m())
store.Aux = t store.Aux = t
s.vars[memVar] = store s.vars[memVar] = store
} }
// stmtList converts the statement list n to SSA and adds it to s. // stmtList converts the statement list n to SSA and adds it to s.
func (s *state) stmtList(l ir.Nodes) { func (s *state) stmtList(l ir.Nodes) {
for _, n := range l { for _, n := range l {
s.stmt(n) s.stmt(n)
} }
skipping to change at line 1544 skipping to change at line 1585
// An x=x assignment. No point in doing anything // An x=x assignment. No point in doing anything
// here. In addition, skipping this assignment // here. In addition, skipping this assignment
// prevents generating: // prevents generating:
// VARDEF x // VARDEF x
// COPY x -> x // COPY x -> x
// which is bad because x is incorrectly considered // which is bad because x is incorrectly considered
// dead before the vardef. See issue #14904. // dead before the vardef. See issue #14904.
return return
} }
// mayOverlap keeps track of whether the LHS and RHS might
// refer to overlapping memory.
mayOverlap := true
if n.Y == nil {
// Not a move at all, mayOverlap is not relevant.
} else if n.Def {
// A variable being defined cannot overlap anything else.
mayOverlap = false
} else if n.X.Op() == ir.ONAME && n.Y.Op() == ir.ONAME {
// Two named things never overlap.
// (Or they are identical, which we treat as nonoverlappi
ng.)
mayOverlap = false
} else if n.Y.Op() == ir.ODEREF {
p := n.Y.(*ir.StarExpr).X
for p.Op() == ir.OCONVNOP {
p = p.(*ir.ConvExpr).X
}
if p.Op() == ir.OSPTR && p.(*ir.UnaryExpr).X.Type().IsStr
ing() {
// Pointer fields of strings point to unmodifiabl
e memory.
// That memory can't overlap with the memory bein
g written.
mayOverlap = false
}
} else if n.Y.Op() == ir.ORESULT || n.Y.Op() == ir.OCALLFUNC || n
.Y.Op() == ir.OCALLINTER {
// When copying values out of the return area of a call,
we know
// the source and destination don't overlap. Importantly,
we must
// set mayOverlap so we don't introduce a call to memmove
while
// we still have live data in the argument area.
mayOverlap = false
}
// Evaluate RHS. // Evaluate RHS.
rhs := n.Y rhs := n.Y
if rhs != nil { if rhs != nil {
switch rhs.Op() { switch rhs.Op() {
case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT: case ir.OSTRUCTLIT, ir.OARRAYLIT, ir.OSLICELIT:
// All literals with nonzero fields have already been // All literals with nonzero fields have already been
// rewritten during walk. Any that remain are jus t T{} // rewritten during walk. Any that remain are jus t T{}
// or equivalents. Use the zero value. // or equivalents. Use the zero value.
if !ir.IsZero(rhs) { if !ir.IsZero(rhs) {
s.Fatalf("literal with nonzero value in S SA: %v", rhs) s.Fatalf("literal with nonzero value in S SA: %v", rhs)
skipping to change at line 1644 skipping to change at line 1715
skip |= skipPtr skip |= skipPtr
if j == nil { if j == nil {
skip |= skipLen skip |= skipLen
} }
if k == nil { if k == nil {
skip |= skipCap skip |= skipCap
} }
} }
} }
s.assign(n.X, r, deref, skip) s.assignWhichMayOverlap(n.X, r, deref, skip, mayOverlap)
case ir.OIF: case ir.OIF:
n := n.(*ir.IfStmt) n := n.(*ir.IfStmt)
if ir.IsConst(n.Cond, constant.Bool) { if ir.IsConst(n.Cond, constant.Bool) {
s.stmtList(n.Cond.Init()) s.stmtList(n.Cond.Init())
if ir.BoolVal(n.Cond) { if ir.BoolVal(n.Cond) {
s.stmtList(n.Body) s.stmtList(n.Body)
} else { } else {
s.stmtList(n.Else) s.stmtList(n.Else)
} }
skipping to change at line 3567 skipping to change at line 3638
skipPtr skipMask = 1 << iota skipPtr skipMask = 1 << iota
skipLen skipLen
skipCap skipCap
) )
// assign does left = right. // assign does left = right.
// Right has already been evaluated to ssa, left has not. // Right has already been evaluated to ssa, left has not.
// If deref is true, then we do left = *right instead (and right has already bee n nil-checked). // If deref is true, then we do left = *right instead (and right has already bee n nil-checked).
// If deref is true and right == nil, just do left = 0. // If deref is true and right == nil, just do left = 0.
// skip indicates assignments (at the top level) that can be avoided. // skip indicates assignments (at the top level) that can be avoided.
// mayOverlap indicates whether left&right might partially overlap in memory. De fault is false.
func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask ) { func (s *state) assign(left ir.Node, right *ssa.Value, deref bool, skip skipMask ) {
s.assignWhichMayOverlap(left, right, deref, skip, false)
}
func (s *state) assignWhichMayOverlap(left ir.Node, right *ssa.Value, deref bool
, skip skipMask, mayOverlap bool) {
if left.Op() == ir.ONAME && ir.IsBlank(left) { if left.Op() == ir.ONAME && ir.IsBlank(left) {
return return
} }
t := left.Type() t := left.Type()
types.CalcSize(t) types.CalcSize(t)
if s.canSSA(left) { if s.canSSA(left) {
if deref { if deref {
s.Fatalf("can SSA LHS %v but not RHS %s", left, right) s.Fatalf("can SSA LHS %v but not RHS %s", left, right)
} }
if left.Op() == ir.ODOT { if left.Op() == ir.ODOT {
skipping to change at line 3668 skipping to change at line 3743
// is valid, even though they have type uintptr (#19168). // is valid, even though they have type uintptr (#19168).
// Mark it pointer type to signal the writebarrier pass to // Mark it pointer type to signal the writebarrier pass to
// insert a write barrier. // insert a write barrier.
t = types.Types[types.TUNSAFEPTR] t = types.Types[types.TUNSAFEPTR]
} }
if deref { if deref {
// Treat as a mem->mem move. // Treat as a mem->mem move.
if right == nil { if right == nil {
s.zero(t, addr) s.zero(t, addr)
} else { } else {
s.move(t, addr, right) s.moveWhichMayOverlap(t, addr, right, mayOverlap)
} }
return return
} }
// Treat as a store. // Treat as a store.
s.storeType(t, addr, right, skip, !ir.IsAutoTmp(left)) s.storeType(t, addr, right, skip, !ir.IsAutoTmp(left))
} }
// zeroVal returns the zero value for type t. // zeroVal returns the zero value for type t.
func (s *state) zeroVal(t *types.Type) *ssa.Value { func (s *state) zeroVal(t *types.Type) *ssa.Value {
switch { switch {
skipping to change at line 7265 skipping to change at line 7340
defframe(&s, e, f) defframe(&s, e, f)
f.HTMLWriter.Close() f.HTMLWriter.Close()
f.HTMLWriter = nil f.HTMLWriter = nil
} }
func defframe(s *State, e *ssafn, f *ssa.Func) { func defframe(s *State, e *ssafn, f *ssa.Func) {
pp := s.pp pp := s.pp
frame := types.Rnd(s.maxarg+e.stksize, int64(types.RegSize)) s.maxarg = types.Rnd(s.maxarg, e.stkalign)
frame := s.maxarg + e.stksize
if Arch.PadFrame != nil { if Arch.PadFrame != nil {
frame = Arch.PadFrame(frame) frame = Arch.PadFrame(frame)
} }
// Fill in argument and frame size. // Fill in argument and frame size.
pp.Text.To.Type = obj.TYPE_TEXTSIZE pp.Text.To.Type = obj.TYPE_TEXTSIZE
pp.Text.To.Val = int32(types.Rnd(f.OwnAux.ArgWidth(), int64(types.RegSize ))) pp.Text.To.Val = int32(types.Rnd(f.OwnAux.ArgWidth(), int64(types.RegSize )))
pp.Text.To.Offset = frame pp.Text.To.Offset = frame
p := pp.Text p := pp.Text
skipping to change at line 7703 skipping to change at line 7779
// so we don't have to recompute it each time we need it. // so we don't have to recompute it each time we need it.
} }
// ssafn holds frontend information about a function that the backend is process ing. // ssafn holds frontend information about a function that the backend is process ing.
// It also exports a bunch of compiler services for the ssa backend. // It also exports a bunch of compiler services for the ssa backend.
type ssafn struct { type ssafn struct {
curfn *ir.Func curfn *ir.Func
strings map[string]*obj.LSym // map from constant string to data symbo ls strings map[string]*obj.LSym // map from constant string to data symbo ls
stksize int64 // stack size for current frame stksize int64 // stack size for current frame
stkptrsize int64 // prefix of stack containing pointers stkptrsize int64 // prefix of stack containing pointers
log bool // print ssa debug to the stdout
// alignment for current frame.
// NOTE: when stkalign > PtrSize, currently this only ensures the offsets
of
// objects in the stack frame are aligned. The stack pointer is still ali
gned
// only PtrSize.
stkalign int64
log bool // print ssa debug to the stdout
} }
// StringData returns a symbol which // StringData returns a symbol which
// is the data component of a global string constant containing s. // is the data component of a global string constant containing s.
func (e *ssafn) StringData(s string) *obj.LSym { func (e *ssafn) StringData(s string) *obj.LSym {
if aux, ok := e.strings[s]; ok { if aux, ok := e.strings[s]; ok {
return aux return aux
} }
if e.strings == nil { if e.strings == nil {
e.strings = make(map[string]*obj.LSym) e.strings = make(map[string]*obj.LSym)
 End of changes. 10 change blocks. 
4 lines changed or deleted 116 lines changed or added

Home  |  About  |  Features  |  All  |  Newest  |  Dox  |  Diffs  |  RSS Feeds  |  Screenshots  |  Comments  |  Imprint  |  Privacy  |  HTTP(S)