blob: 186cfcae70427bee3a11e3edd8656548cb8b5e7b [file] [log] [blame]
Alan Donovan713699d2013-08-27 18:49:13 -04001// Copyright 2013 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
Rob Pike83f21b92013-05-17 13:25:48 -07005package ssa
6
7// lvalues are the union of addressable expressions and map-index
8// expressions.
9
10import (
Alan Donovan55d678e2013-07-15 13:56:46 -040011 "go/ast"
Alan Donovan6c7ce1c2013-05-30 09:59:17 -040012 "go/token"
Alan Donovan542ffc72015-12-29 13:06:30 -050013 "go/types"
Rob Pike83f21b92013-05-17 13:25:48 -070014)
15
16// An lvalue represents an assignable location that may appear on the
17// left-hand side of an assignment. This is a generalization of a
18// pointer to permit updates to elements of maps.
Rob Pike83f21b92013-05-17 13:25:48 -070019type lvalue interface {
20 store(fn *Function, v Value) // stores v into the location
21 load(fn *Function) Value // loads the contents of the location
Alan Donovan55d678e2013-07-15 13:56:46 -040022 address(fn *Function) Value // address of the location
Rob Pike83f21b92013-05-17 13:25:48 -070023 typ() types.Type // returns the type of the location
24}
25
26// An address is an lvalue represented by a true pointer.
27type address struct {
Anton Telyshev0500fd42023-03-20 11:14:02 +020028 addr Value // must have a pointer core type.
Alan Donovan538acf12014-12-29 16:49:20 -050029 pos token.Pos // source position
Alan Donovan33fcc812015-03-13 14:29:51 -040030 expr ast.Expr // source syntax of the value (not address) [debug mode]
Rob Pike83f21b92013-05-17 13:25:48 -070031}
32
Alan Donovan69ce87a2013-07-18 16:59:06 -040033func (a *address) load(fn *Function) Value {
Alan Donovan6c7ce1c2013-05-30 09:59:17 -040034 load := emitLoad(fn, a.addr)
Alan Donovan538acf12014-12-29 16:49:20 -050035 load.pos = a.pos
Alan Donovan6c7ce1c2013-05-30 09:59:17 -040036 return load
Rob Pike83f21b92013-05-17 13:25:48 -070037}
38
Alan Donovan69ce87a2013-07-18 16:59:06 -040039func (a *address) store(fn *Function, v Value) {
Alan Donovan538acf12014-12-29 16:49:20 -050040 store := emitStore(fn, a.addr, v, a.pos)
Alan Donovanc28bf6e2013-07-31 13:13:05 -040041 if a.expr != nil {
Alan Donovan9f640c22013-10-24 18:31:50 -040042 // store.Val is v, converted for assignability.
43 emitDebugRef(fn, a.expr, store.Val, false)
Alan Donovan55d678e2013-07-15 13:56:46 -040044 }
45}
46
Alan Donovan69ce87a2013-07-18 16:59:06 -040047func (a *address) address(fn *Function) Value {
Alan Donovanc28bf6e2013-07-31 13:13:05 -040048 if a.expr != nil {
Alan Donovan9f640c22013-10-24 18:31:50 -040049 emitDebugRef(fn, a.expr, a.addr, true)
Alan Donovan55d678e2013-07-15 13:56:46 -040050 }
51 return a.addr
Rob Pike83f21b92013-05-17 13:25:48 -070052}
53
Alan Donovan69ce87a2013-07-18 16:59:06 -040054func (a *address) typ() types.Type {
Anton Telyshev0500fd42023-03-20 11:14:02 +020055 return mustDeref(a.addr.Type())
Rob Pike83f21b92013-05-17 13:25:48 -070056}
57
58// An element is an lvalue represented by m[k], the location of an
Tim King36a5c6a2022-08-25 11:09:24 -040059// element of a map. These locations are not addressable
Rob Pike83f21b92013-05-17 13:25:48 -070060// since pointers cannot be formed from them, but they do support
Tim King36a5c6a2022-08-25 11:09:24 -040061// load() and store().
Rob Pike83f21b92013-05-17 13:25:48 -070062type element struct {
Tim King36a5c6a2022-08-25 11:09:24 -040063 m, k Value // map
64 t types.Type // map element type
Alan Donovanc8a68902013-08-22 10:13:51 -040065 pos token.Pos // source position of colon ({k:v}) or lbrack (m[k]=v)
Rob Pike83f21b92013-05-17 13:25:48 -070066}
67
68func (e *element) load(fn *Function) Value {
69 l := &Lookup{
70 X: e.m,
71 Index: e.k,
72 }
Alan Donovanc8a68902013-08-22 10:13:51 -040073 l.setPos(e.pos)
Rob Pike83f21b92013-05-17 13:25:48 -070074 l.setType(e.t)
75 return fn.emit(l)
76}
77
78func (e *element) store(fn *Function, v Value) {
Alan Donovanc8a68902013-08-22 10:13:51 -040079 up := &MapUpdate{
Rob Pike83f21b92013-05-17 13:25:48 -070080 Map: e.m,
81 Key: e.k,
82 Value: emitConv(fn, v, e.t),
Alan Donovanc8a68902013-08-22 10:13:51 -040083 }
84 up.pos = e.pos
85 fn.emit(up)
Rob Pike83f21b92013-05-17 13:25:48 -070086}
87
Alan Donovan55d678e2013-07-15 13:56:46 -040088func (e *element) address(fn *Function) Value {
Tim King36a5c6a2022-08-25 11:09:24 -040089 panic("map elements are not addressable")
Alan Donovan55d678e2013-07-15 13:56:46 -040090}
91
Rob Pike83f21b92013-05-17 13:25:48 -070092func (e *element) typ() types.Type {
93 return e.t
94}
95
Tim King1928cea2022-10-12 14:24:32 -070096// A lazyAddress is an lvalue whose address is the result of an instruction.
97// These work like an *address except a new address.address() Value
98// is created on each load, store and address call.
99// A lazyAddress can be used to control when a side effect (nil pointer
100// dereference, index out of bounds) of using a location happens.
101type lazyAddress struct {
102 addr func(fn *Function) Value // emit to fn the computation of the address
103 t types.Type // type of the location
104 pos token.Pos // source position
105 expr ast.Expr // source syntax of the value (not address) [debug mode]
106}
107
108func (l *lazyAddress) load(fn *Function) Value {
109 load := emitLoad(fn, l.addr(fn))
110 load.pos = l.pos
111 return load
112}
113
114func (l *lazyAddress) store(fn *Function, v Value) {
115 store := emitStore(fn, l.addr(fn), v, l.pos)
116 if l.expr != nil {
117 // store.Val is v, converted for assignability.
118 emitDebugRef(fn, l.expr, store.Val, false)
119 }
120}
121
122func (l *lazyAddress) address(fn *Function) Value {
123 addr := l.addr(fn)
124 if l.expr != nil {
125 emitDebugRef(fn, l.expr, addr, true)
126 }
127 return addr
128}
129
130func (l *lazyAddress) typ() types.Type { return l.t }
131
Alan Donovan70722532013-08-19 15:38:30 -0400132// A blank is a dummy variable whose name is "_".
Rob Pike83f21b92013-05-17 13:25:48 -0700133// It is not reified: loads are illegal and stores are ignored.
Rob Pike83f21b92013-05-17 13:25:48 -0700134type blank struct{}
135
136func (bl blank) load(fn *Function) Value {
137 panic("blank.load is illegal")
138}
139
140func (bl blank) store(fn *Function, v Value) {
141 // no-op
142}
143
Alan Donovan55d678e2013-07-15 13:56:46 -0400144func (bl blank) address(fn *Function) Value {
145 panic("blank var is not addressable")
146}
147
Rob Pike83f21b92013-05-17 13:25:48 -0700148func (bl blank) typ() types.Type {
149 // This should be the type of the blank Ident; the typechecker
150 // doesn't provide this yet, but fortunately, we don't need it
151 // yet either.
152 panic("blank.typ is unimplemented")
153}