lvalue.go
2.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
// Copyright 2013 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 ssa
// lvalues are the union of addressable expressions and map-index
// expressions.
import (
"go/ast"
"go/token"
"llvm.org/llgo/third_party/gotools/go/types"
)
// An lvalue represents an assignable location that may appear on the
// left-hand side of an assignment. This is a generalization of a
// pointer to permit updates to elements of maps.
//
type lvalue interface {
store(fn *Function, v Value) // stores v into the location
load(fn *Function) Value // loads the contents of the location
address(fn *Function) Value // address of the location
typ() types.Type // returns the type of the location
}
// An address is an lvalue represented by a true pointer.
type address struct {
addr Value
pos token.Pos // source position
expr ast.Expr // source syntax of the value (not address) [debug mode]
}
func (a *address) load(fn *Function) Value {
load := emitLoad(fn, a.addr)
load.pos = a.pos
return load
}
func (a *address) store(fn *Function, v Value) {
store := emitStore(fn, a.addr, v, a.pos)
if a.expr != nil {
// store.Val is v, converted for assignability.
emitDebugRef(fn, a.expr, store.Val, false)
}
}
func (a *address) address(fn *Function) Value {
if a.expr != nil {
emitDebugRef(fn, a.expr, a.addr, true)
}
return a.addr
}
func (a *address) typ() types.Type {
return deref(a.addr.Type())
}
// An element is an lvalue represented by m[k], the location of an
// element of a map or string. These locations are not addressable
// since pointers cannot be formed from them, but they do support
// load(), and in the case of maps, store().
//
type element struct {
m, k Value // map or string
t types.Type // map element type or string byte type
pos token.Pos // source position of colon ({k:v}) or lbrack (m[k]=v)
}
func (e *element) load(fn *Function) Value {
l := &Lookup{
X: e.m,
Index: e.k,
}
l.setPos(e.pos)
l.setType(e.t)
return fn.emit(l)
}
func (e *element) store(fn *Function, v Value) {
up := &MapUpdate{
Map: e.m,
Key: e.k,
Value: emitConv(fn, v, e.t),
}
up.pos = e.pos
fn.emit(up)
}
func (e *element) address(fn *Function) Value {
panic("map/string elements are not addressable")
}
func (e *element) typ() types.Type {
return e.t
}
// A blank is a dummy variable whose name is "_".
// It is not reified: loads are illegal and stores are ignored.
//
type blank struct{}
func (bl blank) load(fn *Function) Value {
panic("blank.load is illegal")
}
func (bl blank) store(fn *Function, v Value) {
// no-op
}
func (bl blank) address(fn *Function) Value {
panic("blank var is not addressable")
}
func (bl blank) typ() types.Type {
// This should be the type of the blank Ident; the typechecker
// doesn't provide this yet, but fortunately, we don't need it
// yet either.
panic("blank.typ is unimplemented")
}