Alan Donovan | 713699d | 2013-08-27 18:49:13 -0400 | [diff] [blame] | 1 | // 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 Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 5 | package ssa |
| 6 | |
| 7 | // lvalues are the union of addressable expressions and map-index |
| 8 | // expressions. |
| 9 | |
| 10 | import ( |
Alan Donovan | 55d678e | 2013-07-15 13:56:46 -0400 | [diff] [blame] | 11 | "go/ast" |
Alan Donovan | 6c7ce1c | 2013-05-30 09:59:17 -0400 | [diff] [blame] | 12 | "go/token" |
Alan Donovan | 542ffc7 | 2015-12-29 13:06:30 -0500 | [diff] [blame] | 13 | "go/types" |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 14 | ) |
| 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 Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 19 | type 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 Donovan | 55d678e | 2013-07-15 13:56:46 -0400 | [diff] [blame] | 22 | address(fn *Function) Value // address of the location |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 23 | typ() types.Type // returns the type of the location |
| 24 | } |
| 25 | |
| 26 | // An address is an lvalue represented by a true pointer. |
| 27 | type address struct { |
Anton Telyshev | 0500fd4 | 2023-03-20 11:14:02 +0200 | [diff] [blame] | 28 | addr Value // must have a pointer core type. |
Alan Donovan | 538acf1 | 2014-12-29 16:49:20 -0500 | [diff] [blame] | 29 | pos token.Pos // source position |
Alan Donovan | 33fcc81 | 2015-03-13 14:29:51 -0400 | [diff] [blame] | 30 | expr ast.Expr // source syntax of the value (not address) [debug mode] |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 31 | } |
| 32 | |
Alan Donovan | 69ce87a | 2013-07-18 16:59:06 -0400 | [diff] [blame] | 33 | func (a *address) load(fn *Function) Value { |
Alan Donovan | 6c7ce1c | 2013-05-30 09:59:17 -0400 | [diff] [blame] | 34 | load := emitLoad(fn, a.addr) |
Alan Donovan | 538acf1 | 2014-12-29 16:49:20 -0500 | [diff] [blame] | 35 | load.pos = a.pos |
Alan Donovan | 6c7ce1c | 2013-05-30 09:59:17 -0400 | [diff] [blame] | 36 | return load |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 37 | } |
| 38 | |
Alan Donovan | 69ce87a | 2013-07-18 16:59:06 -0400 | [diff] [blame] | 39 | func (a *address) store(fn *Function, v Value) { |
Alan Donovan | 538acf1 | 2014-12-29 16:49:20 -0500 | [diff] [blame] | 40 | store := emitStore(fn, a.addr, v, a.pos) |
Alan Donovan | c28bf6e | 2013-07-31 13:13:05 -0400 | [diff] [blame] | 41 | if a.expr != nil { |
Alan Donovan | 9f640c2 | 2013-10-24 18:31:50 -0400 | [diff] [blame] | 42 | // store.Val is v, converted for assignability. |
| 43 | emitDebugRef(fn, a.expr, store.Val, false) |
Alan Donovan | 55d678e | 2013-07-15 13:56:46 -0400 | [diff] [blame] | 44 | } |
| 45 | } |
| 46 | |
Alan Donovan | 69ce87a | 2013-07-18 16:59:06 -0400 | [diff] [blame] | 47 | func (a *address) address(fn *Function) Value { |
Alan Donovan | c28bf6e | 2013-07-31 13:13:05 -0400 | [diff] [blame] | 48 | if a.expr != nil { |
Alan Donovan | 9f640c2 | 2013-10-24 18:31:50 -0400 | [diff] [blame] | 49 | emitDebugRef(fn, a.expr, a.addr, true) |
Alan Donovan | 55d678e | 2013-07-15 13:56:46 -0400 | [diff] [blame] | 50 | } |
| 51 | return a.addr |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 52 | } |
| 53 | |
Alan Donovan | 69ce87a | 2013-07-18 16:59:06 -0400 | [diff] [blame] | 54 | func (a *address) typ() types.Type { |
Anton Telyshev | 0500fd4 | 2023-03-20 11:14:02 +0200 | [diff] [blame] | 55 | return mustDeref(a.addr.Type()) |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 56 | } |
| 57 | |
| 58 | // An element is an lvalue represented by m[k], the location of an |
Tim King | 36a5c6a | 2022-08-25 11:09:24 -0400 | [diff] [blame] | 59 | // element of a map. These locations are not addressable |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 60 | // since pointers cannot be formed from them, but they do support |
Tim King | 36a5c6a | 2022-08-25 11:09:24 -0400 | [diff] [blame] | 61 | // load() and store(). |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 62 | type element struct { |
Tim King | 36a5c6a | 2022-08-25 11:09:24 -0400 | [diff] [blame] | 63 | m, k Value // map |
| 64 | t types.Type // map element type |
Alan Donovan | c8a6890 | 2013-08-22 10:13:51 -0400 | [diff] [blame] | 65 | pos token.Pos // source position of colon ({k:v}) or lbrack (m[k]=v) |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 66 | } |
| 67 | |
| 68 | func (e *element) load(fn *Function) Value { |
| 69 | l := &Lookup{ |
| 70 | X: e.m, |
| 71 | Index: e.k, |
| 72 | } |
Alan Donovan | c8a6890 | 2013-08-22 10:13:51 -0400 | [diff] [blame] | 73 | l.setPos(e.pos) |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 74 | l.setType(e.t) |
| 75 | return fn.emit(l) |
| 76 | } |
| 77 | |
| 78 | func (e *element) store(fn *Function, v Value) { |
Alan Donovan | c8a6890 | 2013-08-22 10:13:51 -0400 | [diff] [blame] | 79 | up := &MapUpdate{ |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 80 | Map: e.m, |
| 81 | Key: e.k, |
| 82 | Value: emitConv(fn, v, e.t), |
Alan Donovan | c8a6890 | 2013-08-22 10:13:51 -0400 | [diff] [blame] | 83 | } |
| 84 | up.pos = e.pos |
| 85 | fn.emit(up) |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 86 | } |
| 87 | |
Alan Donovan | 55d678e | 2013-07-15 13:56:46 -0400 | [diff] [blame] | 88 | func (e *element) address(fn *Function) Value { |
Tim King | 36a5c6a | 2022-08-25 11:09:24 -0400 | [diff] [blame] | 89 | panic("map elements are not addressable") |
Alan Donovan | 55d678e | 2013-07-15 13:56:46 -0400 | [diff] [blame] | 90 | } |
| 91 | |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 92 | func (e *element) typ() types.Type { |
| 93 | return e.t |
| 94 | } |
| 95 | |
Tim King | 1928cea | 2022-10-12 14:24:32 -0700 | [diff] [blame] | 96 | // 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. |
| 101 | type 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 | |
| 108 | func (l *lazyAddress) load(fn *Function) Value { |
| 109 | load := emitLoad(fn, l.addr(fn)) |
| 110 | load.pos = l.pos |
| 111 | return load |
| 112 | } |
| 113 | |
| 114 | func (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 | |
| 122 | func (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 | |
| 130 | func (l *lazyAddress) typ() types.Type { return l.t } |
| 131 | |
Alan Donovan | 7072253 | 2013-08-19 15:38:30 -0400 | [diff] [blame] | 132 | // A blank is a dummy variable whose name is "_". |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 133 | // It is not reified: loads are illegal and stores are ignored. |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 134 | type blank struct{} |
| 135 | |
| 136 | func (bl blank) load(fn *Function) Value { |
| 137 | panic("blank.load is illegal") |
| 138 | } |
| 139 | |
| 140 | func (bl blank) store(fn *Function, v Value) { |
| 141 | // no-op |
| 142 | } |
| 143 | |
Alan Donovan | 55d678e | 2013-07-15 13:56:46 -0400 | [diff] [blame] | 144 | func (bl blank) address(fn *Function) Value { |
| 145 | panic("blank var is not addressable") |
| 146 | } |
| 147 | |
Rob Pike | 83f21b9 | 2013-05-17 13:25:48 -0700 | [diff] [blame] | 148 | func (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 | } |