blob: 6bf5899ba0bfc691ea242bc199d2d82b34cfa68a [file] [log] [blame]
Keith Randalld2fd43a2015-04-15 15:51:25 -07001// Copyright 2015 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
5package gc
6
7import (
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07008 "bytes"
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07009 "fmt"
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -070010 "html"
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -070011 "os"
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -060012 "strings"
Keith Randalld2fd43a2015-04-15 15:51:25 -070013
Keith Randall067e8df2015-05-28 13:49:20 -070014 "cmd/compile/internal/ssa"
Keith Randall083a6462015-05-12 11:06:44 -070015 "cmd/internal/obj"
Keith Randalld2fd43a2015-04-15 15:51:25 -070016)
17
Keith Randallc0740fe2016-03-03 22:06:57 -080018var ssaEnabled = true
19
Keith Randall2f57d0f2016-01-28 13:46:30 -080020var ssaConfig *ssa.Config
21var ssaExp ssaExport
22
David Chase378a8632016-02-25 13:10:51 -050023func initssa() *ssa.Config {
24 ssaExp.unimplemented = false
25 ssaExp.mustImplement = true
26 if ssaConfig == nil {
27 ssaConfig = ssa.NewConfig(Thearch.Thestring, &ssaExp, Ctxt, Debug['N'] == 0)
28 }
29 return ssaConfig
30}
31
Keith Randall5b355a72015-12-11 20:41:52 -080032func shouldssa(fn *Node) bool {
33 if Thearch.Thestring != "amd64" {
34 return false
35 }
Keith Randallc0740fe2016-03-03 22:06:57 -080036 if !ssaEnabled {
37 return false
38 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070039
David Chasee99dd522015-10-19 11:36:07 -040040 // Environment variable control of SSA CG
41 // 1. IF GOSSAFUNC == current function name THEN
42 // compile this function with SSA and log output to ssa.html
43
David Chase729abfa2015-10-26 17:34:06 -040044 // 2. IF GOSSAHASH == "" THEN
David Chasee99dd522015-10-19 11:36:07 -040045 // compile this function (and everything else) with SSA
46
David Chase729abfa2015-10-26 17:34:06 -040047 // 3. IF GOSSAHASH == "n" or "N"
David Chasee99dd522015-10-19 11:36:07 -040048 // IF GOSSAPKG == current package name THEN
49 // compile this function (and everything in this package) with SSA
50 // ELSE
51 // use the old back end for this function.
52 // This is for compatibility with existing test harness and should go away.
53
54 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
55 // compile this function with SSA
56 // ELSE
57 // compile this function with the old back end.
58
David Chase729abfa2015-10-26 17:34:06 -040059 // Plan is for 3 to be removed when the tests are revised.
60 // SSA is now default, and is disabled by setting
61 // GOSSAHASH to n or N, or selectively with strings of
62 // 0 and 1.
David Chasee99dd522015-10-19 11:36:07 -040063
Keith Randall5b355a72015-12-11 20:41:52 -080064 name := fn.Func.Nname.Sym.Name
65
66 funcname := os.Getenv("GOSSAFUNC")
67 if funcname != "" {
68 // If GOSSAFUNC is set, compile only that function.
69 return name == funcname
70 }
71
72 pkg := os.Getenv("GOSSAPKG")
73 if pkg != "" {
74 // If GOSSAPKG is set, compile only that package.
75 return localpkg.Name == pkg
76 }
77
David Chase378a8632016-02-25 13:10:51 -050078 return initssa().DebugHashMatch("GOSSAHASH", name)
Keith Randall5b355a72015-12-11 20:41:52 -080079}
80
81// buildssa builds an SSA function.
82func buildssa(fn *Node) *ssa.Func {
83 name := fn.Func.Nname.Sym.Name
Keith Randall59681802016-03-01 13:47:48 -080084 printssa := name == os.Getenv("GOSSAFUNC")
Keith Randall5b355a72015-12-11 20:41:52 -080085 if printssa {
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -070086 fmt.Println("generating SSA for", name)
Ian Lance Taylor55c65d42016-03-04 13:16:48 -080087 dumplist("buildssa-enter", fn.Func.Enter)
88 dumplist("buildssa-body", fn.Nbody)
89 dumplist("buildssa-exit", fn.Func.Exit)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070090 }
Keith Randalld2fd43a2015-04-15 15:51:25 -070091
Keith Randallcfc2aa52015-05-18 16:44:20 -070092 var s state
Michael Matloob81ccf502015-05-30 01:03:06 -040093 s.pushLine(fn.Lineno)
94 defer s.popLine()
95
Keith Randall6a8a9da2016-02-27 17:49:31 -080096 if fn.Func.Pragma&CgoUnsafeArgs != 0 {
97 s.cgoUnsafeArgs = true
98 }
Keith Randalld2fd43a2015-04-15 15:51:25 -070099 // TODO(khr): build config just once at the start of the compiler binary
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700100
Keith Randall2f57d0f2016-01-28 13:46:30 -0800101 ssaExp.log = printssa
David Chase378a8632016-02-25 13:10:51 -0500102
103 s.config = initssa()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700104 s.f = s.config.NewFunc()
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700105 s.f.Name = name
David Chase8824dcc2015-10-08 12:39:56 -0400106 s.exitCode = fn.Func.Exit
Keith Randall74e568f2015-11-09 21:35:40 -0800107 s.panics = map[funcLine]*ssa.Block{}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700108
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700109 if name == os.Getenv("GOSSAFUNC") {
110 // TODO: tempfile? it is handy to have the location
111 // of this file be stable, so you can just reload in the browser.
Keith Randallda8af472016-01-13 11:14:57 -0800112 s.config.HTML = ssa.NewHTMLWriter("ssa.html", s.config, name)
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700113 // TODO: generate and print a mapping from nodes to values and blocks
114 }
115 defer func() {
Keith Randall5b355a72015-12-11 20:41:52 -0800116 if !printssa {
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700117 s.config.HTML.Close()
118 }
119 }()
120
Keith Randalld2fd43a2015-04-15 15:51:25 -0700121 // Allocate starting block
122 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
123
Keith Randallcfc2aa52015-05-18 16:44:20 -0700124 // Allocate starting values
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700125 s.labels = map[string]*ssaLabel{}
126 s.labeledNodes = map[*Node]*ssaLabel{}
Keith Randall02f4d0a2015-11-02 08:10:26 -0800127 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -0700128 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
129 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
Keith Randall8c46aa52015-06-19 21:02:28 -0700130
David Chase956f3192015-09-11 16:40:05 -0400131 s.startBlock(s.f.Entry)
132 s.vars[&memVar] = s.startmem
133
Todd Neald076ef72015-10-15 20:25:32 -0500134 s.varsyms = map[*Node]interface{}{}
135
Keith Randall8c46aa52015-06-19 21:02:28 -0700136 // Generate addresses of local declarations
137 s.decladdrs = map[*Node]*ssa.Value{}
Keith Randall4fffd4562016-02-29 13:31:48 -0800138 for _, n := range fn.Func.Dcl {
Keith Randall8c46aa52015-06-19 21:02:28 -0700139 switch n.Class {
Keith Randall6a8a9da2016-02-27 17:49:31 -0800140 case PPARAM, PPARAMOUT:
Todd Neald076ef72015-10-15 20:25:32 -0500141 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randall8c46aa52015-06-19 21:02:28 -0700142 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800143 if n.Class == PPARAMOUT && s.canSSA(n) {
144 // Save ssa-able PPARAMOUT variables so we can
145 // store them back to the stack at the end of
146 // the function.
147 s.returns = append(s.returns, n)
148 }
David Chase956f3192015-09-11 16:40:05 -0400149 case PAUTO | PHEAP:
150 // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
Todd Neald076ef72015-10-15 20:25:32 -0500151 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
David Chase956f3192015-09-11 16:40:05 -0400152 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
David Chase8824dcc2015-10-08 12:39:56 -0400153 case PPARAM | PHEAP, PPARAMOUT | PHEAP:
154 // This ends up wrong, have to do it at the PARAM node instead.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800155 case PAUTO:
Keith Randalld2107fc2015-08-24 02:16:19 -0700156 // processed at each use, to prevent Addr coming
157 // before the decl.
Keith Randallc3eb1a72015-09-06 13:42:26 -0700158 case PFUNC:
159 // local function - already handled by frontend
Daniel Morsingbe2a3e22015-07-01 20:37:25 +0100160 default:
161 str := ""
162 if n.Class&PHEAP != 0 {
163 str = ",heap"
164 }
Josh Bleecher Snyder58446032015-08-23 20:29:43 -0700165 s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
Keith Randall8c46aa52015-06-19 21:02:28 -0700166 }
167 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700168
169 // Convert the AST-based IR to the SSA-based IR
Keith Randall4fffd4562016-02-29 13:31:48 -0800170 s.stmts(fn.Func.Enter)
Keith Randall9d854fd2016-03-01 12:50:17 -0800171 s.stmts(fn.Nbody)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700172
Keith Randallcfc2aa52015-05-18 16:44:20 -0700173 // fallthrough to exit
Keith Randalla7cfc7592015-09-08 16:04:37 -0700174 if s.curBlock != nil {
Keith Randallddc6b642016-03-09 19:27:57 -0800175 s.pushLine(fn.Func.Endlineno)
176 s.exit()
177 s.popLine()
Keith Randallcfc2aa52015-05-18 16:44:20 -0700178 }
179
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700180 // Check that we used all labels
181 for name, lab := range s.labels {
182 if !lab.used() && !lab.reported {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800183 yyerrorl(lab.defNode.Lineno, "label %v defined and not used", name)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700184 lab.reported = true
185 }
186 if lab.used() && !lab.defined() && !lab.reported {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800187 yyerrorl(lab.useNode.Lineno, "label %v not defined", name)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700188 lab.reported = true
189 }
190 }
191
192 // Check any forward gotos. Non-forward gotos have already been checked.
193 for _, n := range s.fwdGotos {
194 lab := s.labels[n.Left.Sym.Name]
195 // If the label is undefined, we have already have printed an error.
196 if lab.defined() {
197 s.checkgoto(n, lab.defNode)
198 }
199 }
200
201 if nerrors > 0 {
Keith Randall4c5459d2016-01-28 16:11:56 -0800202 s.f.Free()
Keith Randall5b355a72015-12-11 20:41:52 -0800203 return nil
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700204 }
205
Keith Randalld2fd43a2015-04-15 15:51:25 -0700206 // Link up variable uses to variable definitions
207 s.linkForwardReferences()
208
David Chase8824dcc2015-10-08 12:39:56 -0400209 // Don't carry reference this around longer than necessary
Keith Randall4fffd4562016-02-29 13:31:48 -0800210 s.exitCode = Nodes{}
David Chase8824dcc2015-10-08 12:39:56 -0400211
Josh Bleecher Snyder983bc8d2015-07-17 16:47:43 +0000212 // Main call to ssa package to compile function
213 ssa.Compile(s.f)
214
Keith Randall5b355a72015-12-11 20:41:52 -0800215 return s.f
Keith Randalld2fd43a2015-04-15 15:51:25 -0700216}
217
Keith Randallcfc2aa52015-05-18 16:44:20 -0700218type state struct {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700219 // configuration (arch) information
220 config *ssa.Config
221
222 // function we're building
223 f *ssa.Func
224
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700225 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
226 labels map[string]*ssaLabel
227 labeledNodes map[*Node]*ssaLabel
228
229 // gotos that jump forward; required for deferred checkgoto calls
230 fwdGotos []*Node
David Chase8824dcc2015-10-08 12:39:56 -0400231 // Code that must precede any return
232 // (e.g., copying value of heap-escaped paramout back to true paramout)
Keith Randall4fffd4562016-02-29 13:31:48 -0800233 exitCode Nodes
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700234
235 // unlabeled break and continue statement tracking
236 breakTo *ssa.Block // current target for plain break statement
237 continueTo *ssa.Block // current target for plain continue statement
Keith Randalld2fd43a2015-04-15 15:51:25 -0700238
239 // current location where we're interpreting the AST
240 curBlock *ssa.Block
241
Keith Randall8c46aa52015-06-19 21:02:28 -0700242 // variable assignments in the current block (map from variable symbol to ssa value)
243 // *Node is the unique identifier (an ONAME Node) for the variable.
244 vars map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700245
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000246 // all defined variables at the end of each block. Indexed by block ID.
Keith Randall8c46aa52015-06-19 21:02:28 -0700247 defvars []map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700248
Keith Randalld2107fc2015-08-24 02:16:19 -0700249 // addresses of PPARAM and PPARAMOUT variables.
Keith Randall8c46aa52015-06-19 21:02:28 -0700250 decladdrs map[*Node]*ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700251
Todd Neald076ef72015-10-15 20:25:32 -0500252 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
253 varsyms map[*Node]interface{}
254
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000255 // starting values. Memory, stack pointer, and globals pointer
Keith Randallcfc2aa52015-05-18 16:44:20 -0700256 startmem *ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700257 sp *ssa.Value
Keith Randall8c46aa52015-06-19 21:02:28 -0700258 sb *ssa.Value
Michael Matloob81ccf502015-05-30 01:03:06 -0400259
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000260 // line number stack. The current line number is top of stack
Michael Matloob81ccf502015-05-30 01:03:06 -0400261 line []int32
Keith Randall74e568f2015-11-09 21:35:40 -0800262
263 // list of panic calls by function name and line number.
264 // Used to deduplicate panic calls.
265 panics map[funcLine]*ssa.Block
Keith Randallb5c5efd2016-01-14 16:02:23 -0800266
267 // list of FwdRef values.
268 fwdRefs []*ssa.Value
Keith Randall6a8a9da2016-02-27 17:49:31 -0800269
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000270 // list of PPARAMOUT (return) variables. Does not include PPARAM|PHEAP vars.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800271 returns []*Node
272
273 cgoUnsafeArgs bool
Keith Randall74e568f2015-11-09 21:35:40 -0800274}
275
276type funcLine struct {
277 f *Node
278 line int32
Keith Randalld2fd43a2015-04-15 15:51:25 -0700279}
280
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700281type ssaLabel struct {
282 target *ssa.Block // block identified by this label
283 breakTarget *ssa.Block // block to break to in control flow node identified by this label
284 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
285 defNode *Node // label definition Node (OLABEL)
286 // Label use Node (OGOTO, OBREAK, OCONTINUE).
287 // Used only for error detection and reporting.
288 // There might be multiple uses, but we only need to track one.
289 useNode *Node
290 reported bool // reported indicates whether an error has already been reported for this label
291}
292
293// defined reports whether the label has a definition (OLABEL node).
294func (l *ssaLabel) defined() bool { return l.defNode != nil }
295
296// used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
297func (l *ssaLabel) used() bool { return l.useNode != nil }
298
299// label returns the label associated with sym, creating it if necessary.
300func (s *state) label(sym *Sym) *ssaLabel {
301 lab := s.labels[sym.Name]
302 if lab == nil {
303 lab = new(ssaLabel)
304 s.labels[sym.Name] = lab
305 }
306 return lab
307}
308
Keith Randallda8af472016-01-13 11:14:57 -0800309func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
David Chase88b230e2016-01-29 14:44:15 -0500310func (s *state) Log() bool { return s.config.Log() }
Keith Randallda8af472016-01-13 11:14:57 -0800311func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(s.peekLine(), msg, args...) }
312func (s *state) Unimplementedf(msg string, args ...interface{}) {
313 s.config.Unimplementedf(s.peekLine(), msg, args...)
314}
Todd Neal98b88de2016-03-13 23:04:31 -0500315func (s *state) Warnl(line int32, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
316func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700317
Keith Randall269baa92015-09-17 10:31:16 -0700318var (
319 // dummy node for the memory variable
Keith Randallc24681a2015-10-22 14:22:38 -0700320 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
Keith Randall8c46aa52015-06-19 21:02:28 -0700321
Keith Randall269baa92015-09-17 10:31:16 -0700322 // dummy nodes for temporary variables
Keith Randallc24681a2015-10-22 14:22:38 -0700323 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
324 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
325 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
326 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
327 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
Keith Randall269baa92015-09-17 10:31:16 -0700328)
Keith Randall5505e8c2015-09-12 23:27:26 -0700329
Keith Randalld2fd43a2015-04-15 15:51:25 -0700330// startBlock sets the current block we're generating code in to b.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700331func (s *state) startBlock(b *ssa.Block) {
332 if s.curBlock != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700333 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700334 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700335 s.curBlock = b
Keith Randall8c46aa52015-06-19 21:02:28 -0700336 s.vars = map[*Node]*ssa.Value{}
Keith Randalld2fd43a2015-04-15 15:51:25 -0700337}
338
339// endBlock marks the end of generating code for the current block.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000340// Returns the (former) current block. Returns nil if there is no current
Keith Randalld2fd43a2015-04-15 15:51:25 -0700341// block, i.e. if no code flows to the current execution point.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700342func (s *state) endBlock() *ssa.Block {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700343 b := s.curBlock
344 if b == nil {
345 return nil
346 }
347 for len(s.defvars) <= int(b.ID) {
348 s.defvars = append(s.defvars, nil)
349 }
350 s.defvars[b.ID] = s.vars
351 s.curBlock = nil
352 s.vars = nil
Michael Matloob81ccf502015-05-30 01:03:06 -0400353 b.Line = s.peekLine()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700354 return b
355}
356
Michael Matloob81ccf502015-05-30 01:03:06 -0400357// pushLine pushes a line number on the line number stack.
358func (s *state) pushLine(line int32) {
359 s.line = append(s.line, line)
360}
361
362// popLine pops the top of the line number stack.
363func (s *state) popLine() {
364 s.line = s.line[:len(s.line)-1]
365}
366
367// peekLine peek the top of the line number stack.
368func (s *state) peekLine() int32 {
369 return s.line[len(s.line)-1]
370}
371
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700372func (s *state) Error(msg string, args ...interface{}) {
Robert Griesemerb83f3972016-03-02 11:01:25 -0800373 yyerrorl(s.peekLine(), msg, args...)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700374}
375
Keith Randall8f22b522015-06-11 21:29:25 -0700376// newValue0 adds a new value with no arguments to the current block.
377func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
378 return s.curBlock.NewValue0(s.peekLine(), op, t)
379}
380
381// newValue0A adds a new value with no arguments and an aux value to the current block.
382func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
383 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400384}
385
Todd Neal991036a2015-09-03 18:24:22 -0500386// newValue0I adds a new value with no arguments and an auxint value to the current block.
387func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
388 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
389}
390
Michael Matloob81ccf502015-05-30 01:03:06 -0400391// newValue1 adds a new value with one argument to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700392func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
393 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
394}
395
396// newValue1A adds a new value with one argument and an aux value to the current block.
397func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
398 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400399}
400
Keith Randallcd7e0592015-07-15 21:33:49 -0700401// newValue1I adds a new value with one argument and an auxint value to the current block.
402func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
403 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
404}
405
Michael Matloob81ccf502015-05-30 01:03:06 -0400406// newValue2 adds a new value with two arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700407func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
408 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400409}
410
Daniel Morsing66b47812015-06-27 15:45:20 +0100411// newValue2I adds a new value with two arguments and an auxint value to the current block.
412func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
413 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
414}
415
Michael Matloob81ccf502015-05-30 01:03:06 -0400416// newValue3 adds a new value with three arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700417func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
418 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
Michael Matloob81ccf502015-05-30 01:03:06 -0400419}
420
Keith Randalld4cc51d2015-08-14 21:47:20 -0700421// newValue3I adds a new value with three arguments and an auxint value to the current block.
422func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
423 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
424}
425
Todd Neal991036a2015-09-03 18:24:22 -0500426// entryNewValue0 adds a new value with no arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700427func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
428 return s.f.Entry.NewValue0(s.peekLine(), op, t)
429}
430
Todd Neal991036a2015-09-03 18:24:22 -0500431// entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700432func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
433 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400434}
435
Todd Neal991036a2015-09-03 18:24:22 -0500436// entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
437func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
438 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
439}
440
Michael Matloob81ccf502015-05-30 01:03:06 -0400441// entryNewValue1 adds a new value with one argument to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700442func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
443 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
444}
445
446// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
447func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
448 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400449}
450
Keith Randall8c46aa52015-06-19 21:02:28 -0700451// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
452func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
453 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
454}
455
Michael Matloob81ccf502015-05-30 01:03:06 -0400456// entryNewValue2 adds a new value with two arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700457func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
458 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400459}
460
Josh Bleecher Snydercea44142015-09-08 16:52:25 -0700461// const* routines add a new const value to the entry block.
Josh Bleecher Snyder39214272016-03-06 18:06:09 -0800462func (s *state) constSlice(t ssa.Type) *ssa.Value { return s.f.ConstSlice(s.peekLine(), t) }
463func (s *state) constInterface(t ssa.Type) *ssa.Value { return s.f.ConstInterface(s.peekLine(), t) }
464func (s *state) constNil(t ssa.Type) *ssa.Value { return s.f.ConstNil(s.peekLine(), t) }
465func (s *state) constEmptyString(t ssa.Type) *ssa.Value { return s.f.ConstEmptyString(s.peekLine(), t) }
Josh Bleecher Snydercea44142015-09-08 16:52:25 -0700466func (s *state) constBool(c bool) *ssa.Value {
467 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
468}
Keith Randall9cb332e2015-07-28 14:19:20 -0700469func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
470 return s.f.ConstInt8(s.peekLine(), t, c)
471}
472func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
473 return s.f.ConstInt16(s.peekLine(), t, c)
474}
475func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
476 return s.f.ConstInt32(s.peekLine(), t, c)
477}
478func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
479 return s.f.ConstInt64(s.peekLine(), t, c)
480}
David Chase997a9f32015-08-12 16:38:11 -0400481func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
482 return s.f.ConstFloat32(s.peekLine(), t, c)
483}
484func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
485 return s.f.ConstFloat64(s.peekLine(), t, c)
486}
Michael Matloob81ccf502015-05-30 01:03:06 -0400487func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
Keith Randall9cb332e2015-07-28 14:19:20 -0700488 if s.config.IntSize == 8 {
489 return s.constInt64(t, c)
490 }
491 if int64(int32(c)) != c {
492 s.Fatalf("integer constant too big %d", c)
493 }
494 return s.constInt32(t, int32(c))
Michael Matloob81ccf502015-05-30 01:03:06 -0400495}
496
Keith Randall4fffd4562016-02-29 13:31:48 -0800497func (s *state) stmts(a Nodes) {
498 for _, x := range a.Slice() {
499 s.stmt(x)
500 }
501}
502
Keith Randalld2fd43a2015-04-15 15:51:25 -0700503// ssaStmtList converts the statement n to SSA and adds it to s.
Ian Lance Taylorc4012b62016-03-08 10:26:20 -0800504func (s *state) stmtList(l Nodes) {
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800505 for _, n := range l.Slice() {
506 s.stmt(n)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700507 }
508}
509
510// ssaStmt converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700511func (s *state) stmt(n *Node) {
Michael Matloob81ccf502015-05-30 01:03:06 -0400512 s.pushLine(n.Lineno)
513 defer s.popLine()
514
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700515 // If s.curBlock is nil, then we're about to generate dead code.
516 // We can't just short-circuit here, though,
517 // because we check labels and gotos as part of SSA generation.
518 // Provide a block for the dead code so that we don't have
519 // to add special cases everywhere else.
520 if s.curBlock == nil {
521 dead := s.f.NewBlock(ssa.BlockPlain)
522 s.startBlock(dead)
523 }
524
Keith Randalld2fd43a2015-04-15 15:51:25 -0700525 s.stmtList(n.Ninit)
526 switch n.Op {
527
528 case OBLOCK:
529 s.stmtList(n.List)
530
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600531 // No-ops
Todd Neal67e43c12015-08-28 21:19:40 -0500532 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600533
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600534 // Expression statements
535 case OCALLFUNC, OCALLMETH, OCALLINTER:
Keith Randalld24768e2015-09-09 23:56:59 -0700536 s.call(n, callNormal)
Keith Randallfb54e032016-02-24 16:19:20 -0800537 if n.Op == OCALLFUNC && n.Left.Op == ONAME && n.Left.Class == PFUNC &&
538 (compiling_runtime != 0 && n.Left.Sym.Name == "throw" ||
Keith Randall6a8a9da2016-02-27 17:49:31 -0800539 n.Left.Sym.Pkg == Runtimepkg && (n.Left.Sym.Name == "gopanic" || n.Left.Sym.Name == "selectgo" || n.Left.Sym.Name == "block")) {
Keith Randallfaf1bdb2016-02-06 22:35:34 -0800540 m := s.mem()
541 b := s.endBlock()
542 b.Kind = ssa.BlockExit
543 b.Control = m
544 // TODO: never rewrite OPANIC to OCALLFUNC in the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000545 // first place. Need to wait until all backends
Keith Randallfaf1bdb2016-02-06 22:35:34 -0800546 // go through SSA.
547 }
Keith Randalld24768e2015-09-09 23:56:59 -0700548 case ODEFER:
549 s.call(n.Left, callDefer)
550 case OPROC:
551 s.call(n.Left, callGo)
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600552
Keith Randall269baa92015-09-17 10:31:16 -0700553 case OAS2DOTTYPE:
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800554 res, resok := s.dottype(n.Rlist.First(), true)
555 s.assign(n.List.First(), res, needwritebarrier(n.List.First(), n.Rlist.First()), false, n.Lineno)
556 s.assign(n.List.Second(), resok, false, false, n.Lineno)
Keith Randall269baa92015-09-17 10:31:16 -0700557 return
558
Keith Randalld2fd43a2015-04-15 15:51:25 -0700559 case ODCL:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100560 if n.Left.Class&PHEAP == 0 {
561 return
562 }
563 if compiling_runtime != 0 {
Keith Randall0ec72b62015-09-08 15:42:53 -0700564 Fatalf("%v escapes to heap, not allowed in runtime.", n)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100565 }
566
567 // TODO: the old pass hides the details of PHEAP
568 // variables behind ONAME nodes. Figure out if it's better
569 // to rewrite the tree and make the heapaddr construct explicit
570 // or to keep this detail hidden behind the scenes.
571 palloc := prealloc[n.Left]
572 if palloc == nil {
573 palloc = callnew(n.Left.Type)
574 prealloc[n.Left] = palloc
575 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700576 r := s.expr(palloc)
Keith Randall5ba31942016-01-25 17:06:54 -0800577 s.assign(n.Left.Name.Heapaddr, r, false, false, n.Lineno)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700578
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700579 case OLABEL:
580 sym := n.Left.Sym
581
582 if isblanksym(sym) {
Keith Randall7e4c06d2015-07-12 11:52:09 -0700583 // Empty identifier is valid but useless.
584 // See issues 11589, 11593.
585 return
586 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700587
588 lab := s.label(sym)
589
590 // Associate label with its control flow node, if any
591 if ctl := n.Name.Defn; ctl != nil {
592 switch ctl.Op {
593 case OFOR, OSWITCH, OSELECT:
594 s.labeledNodes[ctl] = lab
595 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -0700596 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700597
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700598 if !lab.defined() {
599 lab.defNode = n
600 } else {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -0800601 s.Error("label %v already defined at %v", sym, linestr(lab.defNode.Lineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700602 lab.reported = true
Keith Randalld2fd43a2015-04-15 15:51:25 -0700603 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700604 // The label might already have a target block via a goto.
605 if lab.target == nil {
606 lab.target = s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700607 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700608
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700609 // go to that label (we pretend "label:" is preceded by "goto label")
610 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500611 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700612 s.startBlock(lab.target)
613
614 case OGOTO:
615 sym := n.Left.Sym
616
617 lab := s.label(sym)
618 if lab.target == nil {
619 lab.target = s.f.NewBlock(ssa.BlockPlain)
620 }
621 if !lab.used() {
622 lab.useNode = n
623 }
624
625 if lab.defined() {
626 s.checkgoto(n, lab.defNode)
627 } else {
628 s.fwdGotos = append(s.fwdGotos, n)
629 }
630
631 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500632 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700633
Keith Randall290d8fc2015-06-10 15:03:06 -0700634 case OAS, OASWB:
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -0700635 // Check whether we can generate static data rather than code.
636 // If so, ignore n and defer data generation until codegen.
637 // Failure to do this causes writes to readonly symbols.
638 if gen_as_init(n, true) {
639 var data []*Node
640 if s.f.StaticData != nil {
641 data = s.f.StaticData.([]*Node)
642 }
643 s.f.StaticData = append(data, n)
644 return
645 }
Keith Randall5ba31942016-01-25 17:06:54 -0800646
647 var t *Type
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700648 if n.Right != nil {
Keith Randall5ba31942016-01-25 17:06:54 -0800649 t = n.Right.Type
650 } else {
651 t = n.Left.Type
652 }
653
654 // Evaluate RHS.
655 rhs := n.Right
656 if rhs != nil && (rhs.Op == OSTRUCTLIT || rhs.Op == OARRAYLIT) {
657 // All literals with nonzero fields have already been
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000658 // rewritten during walk. Any that remain are just T{}
659 // or equivalents. Use the zero value.
Keith Randall5ba31942016-01-25 17:06:54 -0800660 if !iszero(rhs) {
661 Fatalf("literal with nonzero value in SSA: %v", rhs)
662 }
663 rhs = nil
664 }
665 var r *ssa.Value
666 needwb := n.Op == OASWB && rhs != nil
667 deref := !canSSAType(t)
668 if deref {
669 if rhs == nil {
670 r = nil // Signal assign to use OpZero.
Keith Randalld3886902015-09-18 22:12:38 -0700671 } else {
Keith Randall5ba31942016-01-25 17:06:54 -0800672 r = s.addr(rhs, false)
673 }
674 } else {
675 if rhs == nil {
676 r = s.zeroVal(t)
677 } else {
678 r = s.expr(rhs)
Keith Randalld3886902015-09-18 22:12:38 -0700679 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700680 }
Keith Randall5ba31942016-01-25 17:06:54 -0800681 if rhs != nil && rhs.Op == OAPPEND {
Keith Randall9d22c102015-09-11 11:02:57 -0700682 // Yuck! The frontend gets rid of the write barrier, but we need it!
683 // At least, we need it in the case where growslice is called.
684 // TODO: Do the write barrier on just the growslice branch.
685 // TODO: just add a ptr graying to the end of growslice?
686 // TODO: check whether we need to do this for ODOTTYPE and ORECV also.
687 // They get similar wb-removal treatment in walk.go:OAS.
Keith Randall5ba31942016-01-25 17:06:54 -0800688 needwb = true
Keith Randall9d22c102015-09-11 11:02:57 -0700689 }
Keith Randall5ba31942016-01-25 17:06:54 -0800690
691 s.assign(n.Left, r, needwb, deref, n.Lineno)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100692
Keith Randalld2fd43a2015-04-15 15:51:25 -0700693 case OIF:
Keith Randalld2fd43a2015-04-15 15:51:25 -0700694 bThen := s.f.NewBlock(ssa.BlockPlain)
695 bEnd := s.f.NewBlock(ssa.BlockPlain)
696 var bElse *ssa.Block
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800697 if n.Rlist.Len() != 0 {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700698 bElse = s.f.NewBlock(ssa.BlockPlain)
Keith Randall99187312015-11-02 16:56:53 -0800699 s.condBranch(n.Left, bThen, bElse, n.Likely)
700 } else {
701 s.condBranch(n.Left, bThen, bEnd, n.Likely)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700702 }
703
704 s.startBlock(bThen)
Keith Randall9d854fd2016-03-01 12:50:17 -0800705 s.stmts(n.Nbody)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700706 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500707 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700708 }
709
Ian Lance Taylor38921b32016-03-08 15:10:26 -0800710 if n.Rlist.Len() != 0 {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700711 s.startBlock(bElse)
Keith Randalle707fbe2015-06-11 10:20:39 -0700712 s.stmtList(n.Rlist)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700713 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500714 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700715 }
716 }
717 s.startBlock(bEnd)
718
719 case ORETURN:
720 s.stmtList(n.List)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800721 s.exit()
Keith Randall8a1f6212015-09-08 21:28:44 -0700722 case ORETJMP:
723 s.stmtList(n.List)
Keith Randall6a8a9da2016-02-27 17:49:31 -0800724 b := s.exit()
725 b.Kind = ssa.BlockRetJmp // override BlockRet
Keith Randall8a1f6212015-09-08 21:28:44 -0700726 b.Aux = n.Left.Sym
Keith Randalld2fd43a2015-04-15 15:51:25 -0700727
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700728 case OCONTINUE, OBREAK:
729 var op string
730 var to *ssa.Block
731 switch n.Op {
732 case OCONTINUE:
733 op = "continue"
734 to = s.continueTo
735 case OBREAK:
736 op = "break"
737 to = s.breakTo
738 }
739 if n.Left == nil {
740 // plain break/continue
741 if to == nil {
742 s.Error("%s is not in a loop", op)
743 return
744 }
745 // nothing to do; "to" is already the correct target
746 } else {
747 // labeled break/continue; look up the target
748 sym := n.Left.Sym
749 lab := s.label(sym)
750 if !lab.used() {
751 lab.useNode = n.Left
752 }
753 if !lab.defined() {
754 s.Error("%s label not defined: %v", op, sym)
755 lab.reported = true
756 return
757 }
758 switch n.Op {
759 case OCONTINUE:
760 to = lab.continueTarget
761 case OBREAK:
762 to = lab.breakTarget
763 }
764 if to == nil {
765 // Valid label but not usable with a break/continue here, e.g.:
766 // for {
767 // continue abc
768 // }
769 // abc:
770 // for {}
771 s.Error("invalid %s label %v", op, sym)
772 lab.reported = true
773 return
774 }
775 }
776
777 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500778 b.AddEdgeTo(to)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700779
Keith Randalld2fd43a2015-04-15 15:51:25 -0700780 case OFOR:
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700781 // OFOR: for Ninit; Left; Right { Nbody }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700782 bCond := s.f.NewBlock(ssa.BlockPlain)
783 bBody := s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700784 bIncr := s.f.NewBlock(ssa.BlockPlain)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700785 bEnd := s.f.NewBlock(ssa.BlockPlain)
786
787 // first, jump to condition test
788 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500789 b.AddEdgeTo(bCond)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700790
791 // generate code to test condition
Keith Randalld2fd43a2015-04-15 15:51:25 -0700792 s.startBlock(bCond)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700793 if n.Left != nil {
Keith Randall99187312015-11-02 16:56:53 -0800794 s.condBranch(n.Left, bBody, bEnd, 1)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700795 } else {
Keith Randall99187312015-11-02 16:56:53 -0800796 b := s.endBlock()
797 b.Kind = ssa.BlockPlain
798 b.AddEdgeTo(bBody)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700799 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700800
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700801 // set up for continue/break in body
802 prevContinue := s.continueTo
803 prevBreak := s.breakTo
804 s.continueTo = bIncr
805 s.breakTo = bEnd
806 lab := s.labeledNodes[n]
807 if lab != nil {
808 // labeled for loop
809 lab.continueTarget = bIncr
810 lab.breakTarget = bEnd
811 }
812
Keith Randalld2fd43a2015-04-15 15:51:25 -0700813 // generate body
814 s.startBlock(bBody)
Keith Randall9d854fd2016-03-01 12:50:17 -0800815 s.stmts(n.Nbody)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700816
817 // tear down continue/break
818 s.continueTo = prevContinue
819 s.breakTo = prevBreak
820 if lab != nil {
821 lab.continueTarget = nil
822 lab.breakTarget = nil
823 }
824
825 // done with body, goto incr
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700826 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500827 b.AddEdgeTo(bIncr)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700828 }
829
830 // generate incr
831 s.startBlock(bIncr)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700832 if n.Right != nil {
833 s.stmt(n.Right)
834 }
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700835 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500836 b.AddEdgeTo(bCond)
Josh Bleecher Snyder6c140592015-07-04 09:07:54 -0700837 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700838 s.startBlock(bEnd)
839
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700840 case OSWITCH, OSELECT:
841 // These have been mostly rewritten by the front end into their Nbody fields.
842 // Our main task is to correctly hook up any break statements.
843 bEnd := s.f.NewBlock(ssa.BlockPlain)
844
845 prevBreak := s.breakTo
846 s.breakTo = bEnd
847 lab := s.labeledNodes[n]
848 if lab != nil {
849 // labeled
850 lab.breakTarget = bEnd
851 }
852
853 // generate body code
Keith Randall9d854fd2016-03-01 12:50:17 -0800854 s.stmts(n.Nbody)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700855
856 s.breakTo = prevBreak
857 if lab != nil {
858 lab.breakTarget = nil
859 }
860
Keith Randalleb0cff92016-02-09 12:28:02 -0800861 // OSWITCH never falls through (s.curBlock == nil here).
862 // OSELECT does not fall through if we're calling selectgo.
863 // OSELECT does fall through if we're calling selectnb{send,recv}[2].
864 // In those latter cases, go to the code after the select.
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700865 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500866 b.AddEdgeTo(bEnd)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700867 }
868 s.startBlock(bEnd)
869
Keith Randalld2fd43a2015-04-15 15:51:25 -0700870 case OVARKILL:
Keith Randalld2107fc2015-08-24 02:16:19 -0700871 // Insert a varkill op to record that a variable is no longer live.
872 // We only care about liveness info at call sites, so putting the
873 // varkill in the store chain is enough to keep it correctly ordered
874 // with respect to call ops.
Keith Randall6a8a9da2016-02-27 17:49:31 -0800875 if !s.canSSA(n.Left) {
Keith Randalld29e92b2015-09-19 12:01:39 -0700876 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
877 }
Keith Randall9569b952015-08-28 22:51:01 -0700878
Keith Randall23d58102016-01-19 09:59:21 -0800879 case OVARLIVE:
880 // Insert a varlive op to record that a variable is still live.
881 if !n.Left.Addrtaken {
882 s.Fatalf("VARLIVE variable %s must have Addrtaken set", n.Left)
883 }
884 s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, ssa.TypeMem, n.Left, s.mem())
885
Keith Randall46ffb022015-09-12 14:06:44 -0700886 case OCHECKNIL:
887 p := s.expr(n.Left)
888 s.nilCheck(p)
889
Keith Randalld2fd43a2015-04-15 15:51:25 -0700890 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700891 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -0700892 }
893}
894
Keith Randall6a8a9da2016-02-27 17:49:31 -0800895// exit processes any code that needs to be generated just before returning.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000896// It returns a BlockRet block that ends the control flow. Its control value
Keith Randall6a8a9da2016-02-27 17:49:31 -0800897// will be set to the final memory state.
898func (s *state) exit() *ssa.Block {
Keith Randallddc6b642016-03-09 19:27:57 -0800899 if hasdefer {
900 s.rtcall(Deferreturn, true, nil)
901 }
902
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000903 // Run exit code. Typically, this code copies heap-allocated PPARAMOUT
Keith Randall6a8a9da2016-02-27 17:49:31 -0800904 // variables back to the stack.
905 s.stmts(s.exitCode)
906
907 // Store SSAable PPARAMOUT variables back to stack locations.
908 for _, n := range s.returns {
909 aux := &ssa.ArgSymbol{Typ: n.Type, Node: n}
910 addr := s.newValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
911 val := s.variable(n, n.Type)
912 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, n, s.mem())
913 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, n.Type.Size(), addr, val, s.mem())
914 // TODO: if val is ever spilled, we'd like to use the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +0000915 // PPARAMOUT slot for spilling it. That won't happen
Keith Randall6a8a9da2016-02-27 17:49:31 -0800916 // currently.
917 }
918
919 // Do actual return.
920 m := s.mem()
921 b := s.endBlock()
922 b.Kind = ssa.BlockRet
923 b.Control = m
924 return b
925}
926
Keith Randall67fdb0d2015-07-19 15:48:20 -0700927type opAndType struct {
Keith Randall4304fbc2015-11-16 13:20:16 -0800928 op Op
929 etype EType
Keith Randall67fdb0d2015-07-19 15:48:20 -0700930}
931
932var opToSSA = map[opAndType]ssa.Op{
David Chase997a9f32015-08-12 16:38:11 -0400933 opAndType{OADD, TINT8}: ssa.OpAdd8,
934 opAndType{OADD, TUINT8}: ssa.OpAdd8,
935 opAndType{OADD, TINT16}: ssa.OpAdd16,
936 opAndType{OADD, TUINT16}: ssa.OpAdd16,
937 opAndType{OADD, TINT32}: ssa.OpAdd32,
938 opAndType{OADD, TUINT32}: ssa.OpAdd32,
939 opAndType{OADD, TPTR32}: ssa.OpAdd32,
940 opAndType{OADD, TINT64}: ssa.OpAdd64,
941 opAndType{OADD, TUINT64}: ssa.OpAdd64,
942 opAndType{OADD, TPTR64}: ssa.OpAdd64,
943 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
944 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -0700945
David Chase997a9f32015-08-12 16:38:11 -0400946 opAndType{OSUB, TINT8}: ssa.OpSub8,
947 opAndType{OSUB, TUINT8}: ssa.OpSub8,
948 opAndType{OSUB, TINT16}: ssa.OpSub16,
949 opAndType{OSUB, TUINT16}: ssa.OpSub16,
950 opAndType{OSUB, TINT32}: ssa.OpSub32,
951 opAndType{OSUB, TUINT32}: ssa.OpSub32,
952 opAndType{OSUB, TINT64}: ssa.OpSub64,
953 opAndType{OSUB, TUINT64}: ssa.OpSub64,
954 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
955 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -0700956
Josh Bleecher Snydere61e7c92015-07-22 19:19:40 -0700957 opAndType{ONOT, TBOOL}: ssa.OpNot,
958
David Chase3a9d0ac2015-08-28 14:24:10 -0400959 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
960 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
961 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
962 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
963 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
964 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
965 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
966 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
967 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
968 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +0200969
Keith Randall4b803152015-07-29 17:07:09 -0700970 opAndType{OCOM, TINT8}: ssa.OpCom8,
971 opAndType{OCOM, TUINT8}: ssa.OpCom8,
972 opAndType{OCOM, TINT16}: ssa.OpCom16,
973 opAndType{OCOM, TUINT16}: ssa.OpCom16,
974 opAndType{OCOM, TINT32}: ssa.OpCom32,
975 opAndType{OCOM, TUINT32}: ssa.OpCom32,
976 opAndType{OCOM, TINT64}: ssa.OpCom64,
977 opAndType{OCOM, TUINT64}: ssa.OpCom64,
978
Josh Bleecher Snyderfa5fe192015-09-06 19:24:59 -0700979 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
980 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
981 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
982 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
983
David Chase997a9f32015-08-12 16:38:11 -0400984 opAndType{OMUL, TINT8}: ssa.OpMul8,
985 opAndType{OMUL, TUINT8}: ssa.OpMul8,
986 opAndType{OMUL, TINT16}: ssa.OpMul16,
987 opAndType{OMUL, TUINT16}: ssa.OpMul16,
988 opAndType{OMUL, TINT32}: ssa.OpMul32,
989 opAndType{OMUL, TUINT32}: ssa.OpMul32,
990 opAndType{OMUL, TINT64}: ssa.OpMul64,
991 opAndType{OMUL, TUINT64}: ssa.OpMul64,
992 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
993 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
994
995 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
996 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
Keith Randallbe1eb572015-07-22 13:46:15 -0700997
Todd Neal67cbd5b2015-08-18 19:14:47 -0500998 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
999 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
1000 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
1001 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
1002 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
1003 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
1004
Todd Neala45f2d82015-08-17 17:46:06 -05001005 opAndType{ODIV, TINT8}: ssa.OpDiv8,
1006 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
1007 opAndType{ODIV, TINT16}: ssa.OpDiv16,
1008 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
1009 opAndType{ODIV, TINT32}: ssa.OpDiv32,
1010 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
1011 opAndType{ODIV, TINT64}: ssa.OpDiv64,
1012 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
1013
Todd Neal57d9e7e2015-08-18 19:51:44 -05001014 opAndType{OMOD, TINT8}: ssa.OpMod8,
1015 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
1016 opAndType{OMOD, TINT16}: ssa.OpMod16,
1017 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
1018 opAndType{OMOD, TINT32}: ssa.OpMod32,
1019 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
1020 opAndType{OMOD, TINT64}: ssa.OpMod64,
1021 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
1022
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001023 opAndType{OAND, TINT8}: ssa.OpAnd8,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001024 opAndType{OAND, TUINT8}: ssa.OpAnd8,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001025 opAndType{OAND, TINT16}: ssa.OpAnd16,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001026 opAndType{OAND, TUINT16}: ssa.OpAnd16,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001027 opAndType{OAND, TINT32}: ssa.OpAnd32,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001028 opAndType{OAND, TUINT32}: ssa.OpAnd32,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001029 opAndType{OAND, TINT64}: ssa.OpAnd64,
Keith Randall2a5e6c42015-07-23 14:35:02 -07001030 opAndType{OAND, TUINT64}: ssa.OpAnd64,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02001031
Alexandru Moșoi74024162015-07-29 17:52:25 +02001032 opAndType{OOR, TINT8}: ssa.OpOr8,
1033 opAndType{OOR, TUINT8}: ssa.OpOr8,
1034 opAndType{OOR, TINT16}: ssa.OpOr16,
1035 opAndType{OOR, TUINT16}: ssa.OpOr16,
1036 opAndType{OOR, TINT32}: ssa.OpOr32,
1037 opAndType{OOR, TUINT32}: ssa.OpOr32,
1038 opAndType{OOR, TINT64}: ssa.OpOr64,
1039 opAndType{OOR, TUINT64}: ssa.OpOr64,
1040
Alexandru Moșoi6d9362a12015-07-30 12:33:36 +02001041 opAndType{OXOR, TINT8}: ssa.OpXor8,
1042 opAndType{OXOR, TUINT8}: ssa.OpXor8,
1043 opAndType{OXOR, TINT16}: ssa.OpXor16,
1044 opAndType{OXOR, TUINT16}: ssa.OpXor16,
1045 opAndType{OXOR, TINT32}: ssa.OpXor32,
1046 opAndType{OXOR, TUINT32}: ssa.OpXor32,
1047 opAndType{OXOR, TINT64}: ssa.OpXor64,
1048 opAndType{OXOR, TUINT64}: ssa.OpXor64,
1049
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001050 opAndType{OEQ, TBOOL}: ssa.OpEq8,
1051 opAndType{OEQ, TINT8}: ssa.OpEq8,
1052 opAndType{OEQ, TUINT8}: ssa.OpEq8,
1053 opAndType{OEQ, TINT16}: ssa.OpEq16,
1054 opAndType{OEQ, TUINT16}: ssa.OpEq16,
1055 opAndType{OEQ, TINT32}: ssa.OpEq32,
1056 opAndType{OEQ, TUINT32}: ssa.OpEq32,
1057 opAndType{OEQ, TINT64}: ssa.OpEq64,
1058 opAndType{OEQ, TUINT64}: ssa.OpEq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -07001059 opAndType{OEQ, TINTER}: ssa.OpEqInter,
1060 opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001061 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
1062 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
1063 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -05001064 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001065 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
1066 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
David Chase8e601b22015-08-18 14:39:26 -04001067 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
1068 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001069
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001070 opAndType{ONE, TBOOL}: ssa.OpNeq8,
1071 opAndType{ONE, TINT8}: ssa.OpNeq8,
1072 opAndType{ONE, TUINT8}: ssa.OpNeq8,
1073 opAndType{ONE, TINT16}: ssa.OpNeq16,
1074 opAndType{ONE, TUINT16}: ssa.OpNeq16,
1075 opAndType{ONE, TINT32}: ssa.OpNeq32,
1076 opAndType{ONE, TUINT32}: ssa.OpNeq32,
1077 opAndType{ONE, TINT64}: ssa.OpNeq64,
1078 opAndType{ONE, TUINT64}: ssa.OpNeq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -07001079 opAndType{ONE, TINTER}: ssa.OpNeqInter,
1080 opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001081 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1082 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1083 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -05001084 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001085 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1086 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
David Chase8e601b22015-08-18 14:39:26 -04001087 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1088 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001089
David Chase8e601b22015-08-18 14:39:26 -04001090 opAndType{OLT, TINT8}: ssa.OpLess8,
1091 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1092 opAndType{OLT, TINT16}: ssa.OpLess16,
1093 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1094 opAndType{OLT, TINT32}: ssa.OpLess32,
1095 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1096 opAndType{OLT, TINT64}: ssa.OpLess64,
1097 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1098 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1099 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001100
David Chase8e601b22015-08-18 14:39:26 -04001101 opAndType{OGT, TINT8}: ssa.OpGreater8,
1102 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1103 opAndType{OGT, TINT16}: ssa.OpGreater16,
1104 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1105 opAndType{OGT, TINT32}: ssa.OpGreater32,
1106 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1107 opAndType{OGT, TINT64}: ssa.OpGreater64,
1108 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1109 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1110 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001111
David Chase8e601b22015-08-18 14:39:26 -04001112 opAndType{OLE, TINT8}: ssa.OpLeq8,
1113 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1114 opAndType{OLE, TINT16}: ssa.OpLeq16,
1115 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1116 opAndType{OLE, TINT32}: ssa.OpLeq32,
1117 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1118 opAndType{OLE, TINT64}: ssa.OpLeq64,
1119 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1120 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1121 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001122
David Chase8e601b22015-08-18 14:39:26 -04001123 opAndType{OGE, TINT8}: ssa.OpGeq8,
1124 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1125 opAndType{OGE, TINT16}: ssa.OpGeq16,
1126 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1127 opAndType{OGE, TINT32}: ssa.OpGeq32,
1128 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1129 opAndType{OGE, TINT64}: ssa.OpGeq64,
1130 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1131 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1132 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
David Chase40aba8c2015-08-05 22:11:14 -04001133
1134 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1135 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1136 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1137 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
Keith Randalla329e212015-09-12 13:26:57 -07001138
1139 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001140}
1141
Keith Randall4304fbc2015-11-16 13:20:16 -08001142func (s *state) concreteEtype(t *Type) EType {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001143 e := t.Etype
1144 switch e {
1145 default:
1146 return e
Keith Randall67fdb0d2015-07-19 15:48:20 -07001147 case TINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001148 if s.config.IntSize == 8 {
1149 return TINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001150 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001151 return TINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001152 case TUINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001153 if s.config.IntSize == 8 {
1154 return TUINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001155 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001156 return TUINT32
1157 case TUINTPTR:
1158 if s.config.PtrSize == 8 {
1159 return TUINT64
1160 }
1161 return TUINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001162 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001163}
1164
Keith Randall4304fbc2015-11-16 13:20:16 -08001165func (s *state) ssaOp(op Op, t *Type) ssa.Op {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001166 etype := s.concreteEtype(t)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001167 x, ok := opToSSA[opAndType{op, etype}]
1168 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001169 s.Unimplementedf("unhandled binary op %s %s", opnames[op], Econv(etype))
Keith Randall67fdb0d2015-07-19 15:48:20 -07001170 }
1171 return x
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001172}
1173
David Chase3a9d0ac2015-08-28 14:24:10 -04001174func floatForComplex(t *Type) *Type {
1175 if t.Size() == 8 {
1176 return Types[TFLOAT32]
1177 } else {
1178 return Types[TFLOAT64]
1179 }
1180}
1181
Keith Randall4b803152015-07-29 17:07:09 -07001182type opAndTwoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001183 op Op
1184 etype1 EType
1185 etype2 EType
Keith Randall4b803152015-07-29 17:07:09 -07001186}
1187
David Chased052bbd2015-09-01 17:09:00 -04001188type twoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001189 etype1 EType
1190 etype2 EType
David Chased052bbd2015-09-01 17:09:00 -04001191}
1192
1193type twoOpsAndType struct {
1194 op1 ssa.Op
1195 op2 ssa.Op
Keith Randall4304fbc2015-11-16 13:20:16 -08001196 intermediateType EType
David Chased052bbd2015-09-01 17:09:00 -04001197}
1198
1199var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1200
1201 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1202 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1203 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1204 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1205
1206 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1207 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1208 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1209 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1210
1211 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1212 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1213 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1214 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1215
1216 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1217 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1218 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1219 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1220 // unsigned
1221 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1222 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1223 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1224 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1225
1226 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1227 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1228 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1229 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1230
1231 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1232 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1233 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1234 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1235
1236 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1237 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1238 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1239 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1240
1241 // float
1242 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1243 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1244 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1245 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1246}
1247
Keith Randall4b803152015-07-29 17:07:09 -07001248var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1249 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1250 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1251 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1252 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1253 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1254 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1255 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1256 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1257
1258 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1259 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1260 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1261 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1262 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1263 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1264 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1265 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1266
1267 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1268 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1269 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1270 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1271 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1272 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1273 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1274 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1275
1276 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1277 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1278 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1279 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1280 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1281 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1282 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1283 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1284
1285 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1286 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1287 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1288 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1289 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1290 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1291 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1292 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1293
1294 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1295 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1296 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1297 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1298 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1299 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1300 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1301 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1302
1303 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1304 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1305 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1306 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1307 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1308 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1309 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1310 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1311
1312 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1313 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1314 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1315 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1316 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1317 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1318 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1319 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1320}
1321
Keith Randall4304fbc2015-11-16 13:20:16 -08001322func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
Keith Randall4b803152015-07-29 17:07:09 -07001323 etype1 := s.concreteEtype(t)
1324 etype2 := s.concreteEtype(u)
1325 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1326 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001327 s.Unimplementedf("unhandled shift op %s etype=%s/%s", opnames[op], Econv(etype1), Econv(etype2))
Keith Randall4b803152015-07-29 17:07:09 -07001328 }
1329 return x
1330}
1331
Keith Randall4304fbc2015-11-16 13:20:16 -08001332func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
David Chase40aba8c2015-08-05 22:11:14 -04001333 etype1 := s.concreteEtype(t)
1334 x, ok := opToSSA[opAndType{op, etype1}]
1335 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001336 s.Unimplementedf("unhandled rotate op %s etype=%s", opnames[op], Econv(etype1))
David Chase40aba8c2015-08-05 22:11:14 -04001337 }
1338 return x
1339}
1340
Keith Randalld2fd43a2015-04-15 15:51:25 -07001341// expr converts the expression n to ssa, adds it to s and returns the ssa result.
Keith Randallcfc2aa52015-05-18 16:44:20 -07001342func (s *state) expr(n *Node) *ssa.Value {
Michael Matloob81ccf502015-05-30 01:03:06 -04001343 s.pushLine(n.Lineno)
1344 defer s.popLine()
1345
Keith Randall06f32922015-07-11 11:39:12 -07001346 s.stmtList(n.Ninit)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001347 switch n.Op {
Todd Nealdef7c652015-09-07 19:07:02 -05001348 case OCFUNC:
Todd Neald076ef72015-10-15 20:25:32 -05001349 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Left.Sym})
Todd Nealdef7c652015-09-07 19:07:02 -05001350 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
David Chase956f3192015-09-11 16:40:05 -04001351 case OPARAM:
David Chase57670ad2015-10-09 16:48:30 -04001352 addr := s.addr(n, false)
David Chase32ffbf72015-10-08 17:14:12 -04001353 return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001354 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07001355 if n.Class == PFUNC {
1356 // "value" of a function is the address of the function's closure
Keith Randall8c46aa52015-06-19 21:02:28 -07001357 sym := funcsym(n.Sym)
1358 aux := &ssa.ExternSymbol{n.Type, sym}
1359 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
Keith Randall23df95b2015-05-12 15:16:52 -07001360 }
Keith Randall6a8a9da2016-02-27 17:49:31 -08001361 if s.canSSA(n) {
Keith Randall8c46aa52015-06-19 21:02:28 -07001362 return s.variable(n, n.Type)
Keith Randall290d8fc2015-06-10 15:03:06 -07001363 }
David Chase57670ad2015-10-09 16:48:30 -04001364 addr := s.addr(n, false)
Keith Randall8f22b522015-06-11 21:29:25 -07001365 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
David Chase956f3192015-09-11 16:40:05 -04001366 case OCLOSUREVAR:
David Chase57670ad2015-10-09 16:48:30 -04001367 addr := s.addr(n, false)
David Chase956f3192015-09-11 16:40:05 -04001368 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001369 case OLITERAL:
Keith Randalle707fbe2015-06-11 10:20:39 -07001370 switch n.Val().Ctype() {
Keith Randalld2fd43a2015-04-15 15:51:25 -07001371 case CTINT:
Keith Randall9cb332e2015-07-28 14:19:20 -07001372 i := Mpgetfix(n.Val().U.(*Mpint))
1373 switch n.Type.Size() {
1374 case 1:
1375 return s.constInt8(n.Type, int8(i))
1376 case 2:
1377 return s.constInt16(n.Type, int16(i))
1378 case 4:
1379 return s.constInt32(n.Type, int32(i))
1380 case 8:
1381 return s.constInt64(n.Type, i)
1382 default:
1383 s.Fatalf("bad integer size %d", n.Type.Size())
1384 return nil
1385 }
1386 case CTSTR:
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001387 if n.Val().U == "" {
1388 return s.constEmptyString(n.Type)
1389 }
Keith Randall9cb332e2015-07-28 14:19:20 -07001390 return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
1391 case CTBOOL:
Keith Randallb5c5efd2016-01-14 16:02:23 -08001392 v := s.constBool(n.Val().U.(bool))
1393 // For some reason the frontend gets the line numbers of
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00001394 // CTBOOL literals totally wrong. Fix it here by grabbing
Keith Randallb5c5efd2016-01-14 16:02:23 -08001395 // the line number of the enclosing AST node.
1396 if len(s.line) >= 2 {
1397 v.Line = s.line[len(s.line)-2]
1398 }
1399 return v
Brad Fitzpatrick337b7e72015-07-13 17:30:42 -06001400 case CTNIL:
Keith Randall9f954db2015-08-18 10:26:28 -07001401 t := n.Type
1402 switch {
1403 case t.IsSlice():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001404 return s.constSlice(t)
Keith Randall9f954db2015-08-18 10:26:28 -07001405 case t.IsInterface():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001406 return s.constInterface(t)
Keith Randall9f954db2015-08-18 10:26:28 -07001407 default:
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08001408 return s.constNil(t)
Keith Randall9f954db2015-08-18 10:26:28 -07001409 }
David Chase997a9f32015-08-12 16:38:11 -04001410 case CTFLT:
1411 f := n.Val().U.(*Mpflt)
1412 switch n.Type.Size() {
1413 case 4:
Keith Randall733bf6e2016-01-25 20:26:06 -08001414 return s.constFloat32(n.Type, mpgetflt32(f))
David Chase997a9f32015-08-12 16:38:11 -04001415 case 8:
Keith Randall733bf6e2016-01-25 20:26:06 -08001416 return s.constFloat64(n.Type, mpgetflt(f))
David Chase997a9f32015-08-12 16:38:11 -04001417 default:
1418 s.Fatalf("bad float size %d", n.Type.Size())
1419 return nil
1420 }
David Chase52578582015-08-28 14:24:10 -04001421 case CTCPLX:
1422 c := n.Val().U.(*Mpcplx)
1423 r := &c.Real
1424 i := &c.Imag
1425 switch n.Type.Size() {
1426 case 8:
1427 {
1428 pt := Types[TFLOAT32]
1429 return s.newValue2(ssa.OpComplexMake, n.Type,
Keith Randall733bf6e2016-01-25 20:26:06 -08001430 s.constFloat32(pt, mpgetflt32(r)),
1431 s.constFloat32(pt, mpgetflt32(i)))
David Chase52578582015-08-28 14:24:10 -04001432 }
1433 case 16:
1434 {
1435 pt := Types[TFLOAT64]
1436 return s.newValue2(ssa.OpComplexMake, n.Type,
Keith Randall733bf6e2016-01-25 20:26:06 -08001437 s.constFloat64(pt, mpgetflt(r)),
1438 s.constFloat64(pt, mpgetflt(i)))
David Chase52578582015-08-28 14:24:10 -04001439 }
1440 default:
1441 s.Fatalf("bad float size %d", n.Type.Size())
1442 return nil
1443 }
David Chase997a9f32015-08-12 16:38:11 -04001444
Keith Randalld2fd43a2015-04-15 15:51:25 -07001445 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001446 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001447 return nil
1448 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001449 case OCONVNOP:
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001450 to := n.Type
1451 from := n.Left.Type
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001452
1453 // Assume everything will work out, so set up our return value.
1454 // Anything interesting that happens from here is a fatal.
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001455 x := s.expr(n.Left)
David Chasee99dd522015-10-19 11:36:07 -04001456
1457 // Special case for not confusing GC and liveness.
1458 // We don't want pointers accidentally classified
1459 // as not-pointers or vice-versa because of copy
1460 // elision.
1461 if to.IsPtr() != from.IsPtr() {
Keith Randall7807bda2015-11-10 15:35:36 -08001462 return s.newValue2(ssa.OpConvert, to, x, s.mem())
David Chasee99dd522015-10-19 11:36:07 -04001463 }
1464
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001465 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1466
Todd Nealdef7c652015-09-07 19:07:02 -05001467 // CONVNOP closure
1468 if to.Etype == TFUNC && from.IsPtr() {
1469 return v
1470 }
1471
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001472 // named <--> unnamed type or typed <--> untyped const
1473 if from.Etype == to.Etype {
1474 return v
1475 }
David Chasee99dd522015-10-19 11:36:07 -04001476
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001477 // unsafe.Pointer <--> *T
1478 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1479 return v
1480 }
1481
1482 dowidth(from)
1483 dowidth(to)
1484 if from.Width != to.Width {
1485 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1486 return nil
1487 }
1488 if etypesign(from.Etype) != etypesign(to.Etype) {
Keith Randall4304fbc2015-11-16 13:20:16 -08001489 s.Fatalf("CONVNOP sign mismatch %v (%s) -> %v (%s)\n", from, Econv(from.Etype), to, Econv(to.Etype))
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001490 return nil
1491 }
1492
Ian Lance Taylor88e18032016-03-01 15:17:34 -08001493 if instrumenting {
David Chase57670ad2015-10-09 16:48:30 -04001494 // These appear to be fine, but they fail the
1495 // integer constraint below, so okay them here.
1496 // Sample non-integer conversion: map[string]string -> *uint8
1497 return v
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001498 }
1499
1500 if etypesign(from.Etype) == 0 {
1501 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1502 return nil
1503 }
1504
1505 // integer, same width, same sign
1506 return v
1507
Michael Matloob73054f52015-06-14 11:38:46 -07001508 case OCONV:
1509 x := s.expr(n.Left)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001510 ft := n.Left.Type // from type
1511 tt := n.Type // to type
1512 if ft.IsInteger() && tt.IsInteger() {
1513 var op ssa.Op
1514 if tt.Size() == ft.Size() {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001515 op = ssa.OpCopy
Keith Randall2a5e6c42015-07-23 14:35:02 -07001516 } else if tt.Size() < ft.Size() {
1517 // truncation
1518 switch 10*ft.Size() + tt.Size() {
1519 case 21:
1520 op = ssa.OpTrunc16to8
1521 case 41:
1522 op = ssa.OpTrunc32to8
1523 case 42:
1524 op = ssa.OpTrunc32to16
1525 case 81:
1526 op = ssa.OpTrunc64to8
1527 case 82:
1528 op = ssa.OpTrunc64to16
1529 case 84:
1530 op = ssa.OpTrunc64to32
1531 default:
1532 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1533 }
1534 } else if ft.IsSigned() {
1535 // sign extension
1536 switch 10*ft.Size() + tt.Size() {
1537 case 12:
1538 op = ssa.OpSignExt8to16
1539 case 14:
1540 op = ssa.OpSignExt8to32
1541 case 18:
1542 op = ssa.OpSignExt8to64
1543 case 24:
1544 op = ssa.OpSignExt16to32
1545 case 28:
1546 op = ssa.OpSignExt16to64
1547 case 48:
1548 op = ssa.OpSignExt32to64
1549 default:
1550 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1551 }
1552 } else {
1553 // zero extension
1554 switch 10*ft.Size() + tt.Size() {
1555 case 12:
1556 op = ssa.OpZeroExt8to16
1557 case 14:
1558 op = ssa.OpZeroExt8to32
1559 case 18:
1560 op = ssa.OpZeroExt8to64
1561 case 24:
1562 op = ssa.OpZeroExt16to32
1563 case 28:
1564 op = ssa.OpZeroExt16to64
1565 case 48:
1566 op = ssa.OpZeroExt32to64
1567 default:
1568 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1569 }
1570 }
1571 return s.newValue1(op, n.Type, x)
1572 }
David Chase42825882015-08-20 15:14:20 -04001573
David Chased052bbd2015-09-01 17:09:00 -04001574 if ft.IsFloat() || tt.IsFloat() {
1575 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1576 if !ok {
1577 s.Fatalf("weird float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001578 }
David Chased052bbd2015-09-01 17:09:00 -04001579 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1580
1581 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1582 // normal case, not tripping over unsigned 64
1583 if op1 == ssa.OpCopy {
1584 if op2 == ssa.OpCopy {
1585 return x
1586 }
1587 return s.newValue1(op2, n.Type, x)
1588 }
1589 if op2 == ssa.OpCopy {
1590 return s.newValue1(op1, n.Type, x)
1591 }
1592 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1593 }
1594 // Tricky 64-bit unsigned cases.
1595 if ft.IsInteger() {
1596 // therefore tt is float32 or float64, and ft is also unsigned
David Chase42825882015-08-20 15:14:20 -04001597 if tt.Size() == 4 {
1598 return s.uint64Tofloat32(n, x, ft, tt)
1599 }
1600 if tt.Size() == 8 {
1601 return s.uint64Tofloat64(n, x, ft, tt)
1602 }
David Chased052bbd2015-09-01 17:09:00 -04001603 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001604 }
David Chased052bbd2015-09-01 17:09:00 -04001605 // therefore ft is float32 or float64, and tt is unsigned integer
David Chase73151062015-08-26 14:25:40 -04001606 if ft.Size() == 4 {
David Chased052bbd2015-09-01 17:09:00 -04001607 return s.float32ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001608 }
David Chased052bbd2015-09-01 17:09:00 -04001609 if ft.Size() == 8 {
1610 return s.float64ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001611 }
David Chased052bbd2015-09-01 17:09:00 -04001612 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1613 return nil
David Chase42825882015-08-20 15:14:20 -04001614 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001615
1616 if ft.IsComplex() && tt.IsComplex() {
1617 var op ssa.Op
1618 if ft.Size() == tt.Size() {
1619 op = ssa.OpCopy
1620 } else if ft.Size() == 8 && tt.Size() == 16 {
1621 op = ssa.OpCvt32Fto64F
1622 } else if ft.Size() == 16 && tt.Size() == 8 {
1623 op = ssa.OpCvt64Fto32F
1624 } else {
1625 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1626 }
1627 ftp := floatForComplex(ft)
1628 ttp := floatForComplex(tt)
1629 return s.newValue2(ssa.OpComplexMake, tt,
1630 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1631 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1632 }
David Chase42825882015-08-20 15:14:20 -04001633
Keith Randall4304fbc2015-11-16 13:20:16 -08001634 s.Unimplementedf("unhandled OCONV %s -> %s", Econv(n.Left.Type.Etype), Econv(n.Type.Etype))
Keith Randall2a5e6c42015-07-23 14:35:02 -07001635 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001636
Keith Randall269baa92015-09-17 10:31:16 -07001637 case ODOTTYPE:
1638 res, _ := s.dottype(n, false)
1639 return res
1640
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001641 // binary ops
1642 case OLT, OEQ, ONE, OLE, OGE, OGT:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001643 a := s.expr(n.Left)
1644 b := s.expr(n.Right)
Keith Randalldb380bf2015-09-10 11:05:42 -07001645 if n.Left.Type.IsComplex() {
Keith Randallc244ce02015-09-10 14:59:00 -07001646 pt := floatForComplex(n.Left.Type)
Keith Randalldb380bf2015-09-10 11:05:42 -07001647 op := s.ssaOp(OEQ, pt)
1648 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1649 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1650 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1651 switch n.Op {
1652 case OEQ:
1653 return c
1654 case ONE:
1655 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1656 default:
1657 s.Fatalf("ordered complex compare %s", opnames[n.Op])
1658 }
Keith Randalldb380bf2015-09-10 11:05:42 -07001659 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001660 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
David Chase3a9d0ac2015-08-28 14:24:10 -04001661 case OMUL:
1662 a := s.expr(n.Left)
1663 b := s.expr(n.Right)
1664 if n.Type.IsComplex() {
1665 mulop := ssa.OpMul64F
1666 addop := ssa.OpAdd64F
1667 subop := ssa.OpSub64F
1668 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1669 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1670
1671 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1672 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1673 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1674 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1675
1676 if pt != wt { // Widen for calculation
1677 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1678 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1679 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1680 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1681 }
1682
1683 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1684 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1685
1686 if pt != wt { // Narrow to store back
1687 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1688 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1689 }
1690
1691 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1692 }
1693 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1694
1695 case ODIV:
1696 a := s.expr(n.Left)
1697 b := s.expr(n.Right)
1698 if n.Type.IsComplex() {
1699 // TODO this is not executed because the front-end substitutes a runtime call.
1700 // That probably ought to change; with modest optimization the widen/narrow
1701 // conversions could all be elided in larger expression trees.
1702 mulop := ssa.OpMul64F
1703 addop := ssa.OpAdd64F
1704 subop := ssa.OpSub64F
1705 divop := ssa.OpDiv64F
1706 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1707 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1708
1709 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1710 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1711 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1712 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1713
1714 if pt != wt { // Widen for calculation
1715 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1716 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1717 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1718 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1719 }
1720
1721 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1722 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1723 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1724
1725 // TODO not sure if this is best done in wide precision or narrow
1726 // Double-rounding might be an issue.
1727 // Note that the pre-SSA implementation does the entire calculation
1728 // in wide format, so wide is compatible.
1729 xreal = s.newValue2(divop, wt, xreal, denom)
1730 ximag = s.newValue2(divop, wt, ximag, denom)
1731
1732 if pt != wt { // Narrow to store back
1733 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1734 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1735 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001736 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1737 }
David Chase18559e22015-10-28 13:55:46 -04001738 if n.Type.IsFloat() {
1739 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1740 } else {
1741 // do a size-appropriate check for zero
1742 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1743 s.check(cmp, panicdivide)
1744 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1745 }
1746 case OMOD:
1747 a := s.expr(n.Left)
1748 b := s.expr(n.Right)
1749 // do a size-appropriate check for zero
1750 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1751 s.check(cmp, panicdivide)
David Chase3a9d0ac2015-08-28 14:24:10 -04001752 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1753 case OADD, OSUB:
1754 a := s.expr(n.Left)
1755 b := s.expr(n.Right)
1756 if n.Type.IsComplex() {
1757 pt := floatForComplex(n.Type)
1758 op := s.ssaOp(n.Op, pt)
1759 return s.newValue2(ssa.OpComplexMake, n.Type,
1760 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1761 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1762 }
1763 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
David Chase18559e22015-10-28 13:55:46 -04001764 case OAND, OOR, OHMUL, OXOR:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001765 a := s.expr(n.Left)
1766 b := s.expr(n.Right)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001767 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
Keith Randall4b803152015-07-29 17:07:09 -07001768 case OLSH, ORSH:
1769 a := s.expr(n.Left)
1770 b := s.expr(n.Right)
1771 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
David Chase40aba8c2015-08-05 22:11:14 -04001772 case OLROT:
1773 a := s.expr(n.Left)
1774 i := n.Right.Int()
1775 if i <= 0 || i >= n.Type.Size()*8 {
1776 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1777 }
1778 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001779 case OANDAND, OOROR:
1780 // To implement OANDAND (and OOROR), we introduce a
1781 // new temporary variable to hold the result. The
1782 // variable is associated with the OANDAND node in the
1783 // s.vars table (normally variables are only
1784 // associated with ONAME nodes). We convert
1785 // A && B
1786 // to
1787 // var = A
1788 // if var {
1789 // var = B
1790 // }
1791 // Using var in the subsequent block introduces the
1792 // necessary phi variable.
1793 el := s.expr(n.Left)
1794 s.vars[n] = el
1795
1796 b := s.endBlock()
1797 b.Kind = ssa.BlockIf
1798 b.Control = el
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07001799 // In theory, we should set b.Likely here based on context.
1800 // However, gc only gives us likeliness hints
1801 // in a single place, for plain OIF statements,
1802 // and passing around context is finnicky, so don't bother for now.
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001803
1804 bRight := s.f.NewBlock(ssa.BlockPlain)
1805 bResult := s.f.NewBlock(ssa.BlockPlain)
1806 if n.Op == OANDAND {
Todd Neal47d67992015-08-28 21:36:29 -05001807 b.AddEdgeTo(bRight)
1808 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001809 } else if n.Op == OOROR {
Todd Neal47d67992015-08-28 21:36:29 -05001810 b.AddEdgeTo(bResult)
1811 b.AddEdgeTo(bRight)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001812 }
1813
1814 s.startBlock(bRight)
1815 er := s.expr(n.Right)
1816 s.vars[n] = er
1817
1818 b = s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05001819 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001820
1821 s.startBlock(bResult)
Josh Bleecher Snyder35ad1fc2015-08-27 10:11:08 -07001822 return s.variable(n, Types[TBOOL])
Keith Randall7e390722015-09-12 14:14:02 -07001823 case OCOMPLEX:
1824 r := s.expr(n.Left)
1825 i := s.expr(n.Right)
1826 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001827
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001828 // unary ops
David Chase3a9d0ac2015-08-28 14:24:10 -04001829 case OMINUS:
1830 a := s.expr(n.Left)
1831 if n.Type.IsComplex() {
1832 tp := floatForComplex(n.Type)
1833 negop := s.ssaOp(n.Op, tp)
1834 return s.newValue2(ssa.OpComplexMake, n.Type,
1835 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1836 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1837 }
1838 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randalla329e212015-09-12 13:26:57 -07001839 case ONOT, OCOM, OSQRT:
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001840 a := s.expr(n.Left)
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +02001841 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randall2f518072015-09-10 11:37:09 -07001842 case OIMAG, OREAL:
1843 a := s.expr(n.Left)
1844 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001845 case OPLUS:
1846 return s.expr(n.Left)
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001847
Keith Randallcfc2aa52015-05-18 16:44:20 -07001848 case OADDR:
David Chase57670ad2015-10-09 16:48:30 -04001849 return s.addr(n.Left, n.Bounded)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001850
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07001851 case OINDREG:
1852 if int(n.Reg) != Thearch.REGSP {
1853 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1854 return nil
1855 }
1856 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1857 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1858
Keith Randalld2fd43a2015-04-15 15:51:25 -07001859 case OIND:
1860 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001861 s.nilCheck(p)
Keith Randall8f22b522015-06-11 21:29:25 -07001862 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07001863
Keith Randallcd7e0592015-07-15 21:33:49 -07001864 case ODOT:
Keith Randalla734bbc2016-01-11 21:05:33 -08001865 t := n.Left.Type
1866 if canSSAType(t) {
1867 v := s.expr(n.Left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07001868 return s.newValue1I(ssa.OpStructSelect, n.Type, int64(fieldIdx(n)), v)
Keith Randalla734bbc2016-01-11 21:05:33 -08001869 }
David Chase57670ad2015-10-09 16:48:30 -04001870 p := s.addr(n, false)
Keith Randall97035642015-10-09 09:33:29 -07001871 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcd7e0592015-07-15 21:33:49 -07001872
Keith Randalld2fd43a2015-04-15 15:51:25 -07001873 case ODOTPTR:
1874 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001875 s.nilCheck(p)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08001876 p = s.newValue1I(ssa.OpOffPtr, p.Type, n.Xoffset, p)
Keith Randall8f22b522015-06-11 21:29:25 -07001877 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001878
1879 case OINDEX:
Keith Randall97035642015-10-09 09:33:29 -07001880 switch {
1881 case n.Left.Type.IsString():
Keith Randallcfc2aa52015-05-18 16:44:20 -07001882 a := s.expr(n.Left)
1883 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001884 i = s.extendIndex(i)
Keith Randall97035642015-10-09 09:33:29 -07001885 if !n.Bounded {
1886 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1887 s.boundsCheck(i, len)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07001888 }
Keith Randall97035642015-10-09 09:33:29 -07001889 ptrtyp := Ptrto(Types[TUINT8])
1890 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08001891 if Isconst(n.Right, CTINT) {
1892 ptr = s.newValue1I(ssa.OpOffPtr, ptrtyp, n.Right.Int(), ptr)
1893 } else {
1894 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1895 }
Keith Randall97035642015-10-09 09:33:29 -07001896 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1897 case n.Left.Type.IsSlice():
David Chase57670ad2015-10-09 16:48:30 -04001898 p := s.addr(n, false)
Keith Randall8f22b522015-06-11 21:29:25 -07001899 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
Keith Randall97035642015-10-09 09:33:29 -07001900 case n.Left.Type.IsArray():
1901 // TODO: fix when we can SSA arrays of length 1.
David Chase57670ad2015-10-09 16:48:30 -04001902 p := s.addr(n, false)
Keith Randall97035642015-10-09 09:33:29 -07001903 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1904 default:
1905 s.Fatalf("bad type for index %v", n.Left.Type)
1906 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001907 }
Keith Randalld2fd43a2015-04-15 15:51:25 -07001908
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001909 case OLEN, OCAP:
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001910 switch {
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001911 case n.Left.Type.IsSlice():
1912 op := ssa.OpSliceLen
1913 if n.Op == OCAP {
1914 op = ssa.OpSliceCap
1915 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001916 return s.newValue1(op, Types[TINT], s.expr(n.Left))
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001917 case n.Left.Type.IsString(): // string; not reachable for OCAP
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001918 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
Todd Neal707af252015-08-28 15:56:43 -05001919 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1920 return s.referenceTypeBuiltin(n, s.expr(n.Left))
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001921 default: // array
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001922 return s.constInt(Types[TINT], n.Left.Type.Bound)
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001923 }
1924
Josh Bleecher Snydera2d15802015-08-12 10:12:14 -07001925 case OSPTR:
1926 a := s.expr(n.Left)
1927 if n.Left.Type.IsSlice() {
1928 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
1929 } else {
1930 return s.newValue1(ssa.OpStringPtr, n.Type, a)
1931 }
1932
Keith Randalld1c15a02015-08-04 15:47:22 -07001933 case OITAB:
1934 a := s.expr(n.Left)
1935 return s.newValue1(ssa.OpITab, n.Type, a)
1936
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07001937 case OEFACE:
1938 tab := s.expr(n.Left)
1939 data := s.expr(n.Right)
Keith Randall808d7c72015-10-07 14:35:25 -07001940 // The frontend allows putting things like struct{*byte} in
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00001941 // the data portion of an eface. But we don't want struct{*byte}
Keith Randall808d7c72015-10-07 14:35:25 -07001942 // as a register type because (among other reasons) the liveness
1943 // analysis is confused by the "fat" variables that result from
1944 // such types being spilled.
1945 // So here we ensure that we are selecting the underlying pointer
1946 // when we build an eface.
Keith Randalla734bbc2016-01-11 21:05:33 -08001947 // TODO: get rid of this now that structs can be SSA'd?
Keith Randall808d7c72015-10-07 14:35:25 -07001948 for !data.Type.IsPtr() {
1949 switch {
1950 case data.Type.IsArray():
Matthew Dempsky0b281872016-03-10 14:35:39 -08001951 data = s.newValue1I(ssa.OpArrayIndex, data.Type.ElemType(), 0, data)
Keith Randall808d7c72015-10-07 14:35:25 -07001952 case data.Type.IsStruct():
1953 for i := data.Type.NumFields() - 1; i >= 0; i-- {
1954 f := data.Type.FieldType(i)
1955 if f.Size() == 0 {
1956 // eface type could also be struct{p *byte; q [0]int}
1957 continue
1958 }
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07001959 data = s.newValue1I(ssa.OpStructSelect, f, int64(i), data)
Keith Randall808d7c72015-10-07 14:35:25 -07001960 break
1961 }
1962 default:
1963 s.Fatalf("type being put into an eface isn't a pointer")
1964 }
1965 }
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07001966 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
1967
Keith Randall5505e8c2015-09-12 23:27:26 -07001968 case OSLICE, OSLICEARR:
1969 v := s.expr(n.Left)
1970 var i, j *ssa.Value
1971 if n.Right.Left != nil {
1972 i = s.extendIndex(s.expr(n.Right.Left))
1973 }
1974 if n.Right.Right != nil {
1975 j = s.extendIndex(s.expr(n.Right.Right))
1976 }
1977 p, l, c := s.slice(n.Left.Type, v, i, j, nil)
1978 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07001979 case OSLICESTR:
Keith Randall5505e8c2015-09-12 23:27:26 -07001980 v := s.expr(n.Left)
1981 var i, j *ssa.Value
1982 if n.Right.Left != nil {
1983 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07001984 }
Keith Randall5505e8c2015-09-12 23:27:26 -07001985 if n.Right.Right != nil {
1986 j = s.extendIndex(s.expr(n.Right.Right))
Keith Randall3526cf52015-08-24 23:52:03 -07001987 }
Keith Randall5505e8c2015-09-12 23:27:26 -07001988 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
1989 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
1990 case OSLICE3, OSLICE3ARR:
1991 v := s.expr(n.Left)
1992 var i *ssa.Value
1993 if n.Right.Left != nil {
1994 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07001995 }
Keith Randall5505e8c2015-09-12 23:27:26 -07001996 j := s.extendIndex(s.expr(n.Right.Right.Left))
1997 k := s.extendIndex(s.expr(n.Right.Right.Right))
1998 p, l, c := s.slice(n.Left.Type, v, i, j, k)
1999 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07002000
Keith Randalld24768e2015-09-09 23:56:59 -07002001 case OCALLFUNC, OCALLINTER, OCALLMETH:
Keith Randall5ba31942016-01-25 17:06:54 -08002002 a := s.call(n, callNormal)
2003 return s.newValue2(ssa.OpLoad, n.Type, a, s.mem())
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07002004
2005 case OGETG:
Keith Randalld694f832015-10-19 18:54:40 -07002006 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07002007
Keith Randall9d22c102015-09-11 11:02:57 -07002008 case OAPPEND:
2009 // append(s, e1, e2, e3). Compile like:
2010 // ptr,len,cap := s
2011 // newlen := len + 3
2012 // if newlen > s.cap {
2013 // ptr,_,cap = growslice(s, newlen)
2014 // }
2015 // *(ptr+len) = e1
2016 // *(ptr+len+1) = e2
2017 // *(ptr+len+2) = e3
2018 // makeslice(ptr,newlen,cap)
2019
2020 et := n.Type.Type
2021 pt := Ptrto(et)
2022
2023 // Evaluate slice
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002024 slice := s.expr(n.List.First())
Keith Randall9d22c102015-09-11 11:02:57 -07002025
Keith Randall9d22c102015-09-11 11:02:57 -07002026 // Allocate new blocks
2027 grow := s.f.NewBlock(ssa.BlockPlain)
Keith Randall9d22c102015-09-11 11:02:57 -07002028 assign := s.f.NewBlock(ssa.BlockPlain)
2029
2030 // Decide if we need to grow
Ian Lance Taylor38921b32016-03-08 15:10:26 -08002031 nargs := int64(n.List.Len() - 1)
Keith Randall9d22c102015-09-11 11:02:57 -07002032 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
2033 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
2034 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
2035 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
2036 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
Keith Randallb32217a2015-09-17 16:45:10 -07002037 s.vars[&ptrVar] = p
2038 s.vars[&capVar] = c
Keith Randall9d22c102015-09-11 11:02:57 -07002039 b := s.endBlock()
2040 b.Kind = ssa.BlockIf
2041 b.Likely = ssa.BranchUnlikely
2042 b.Control = cmp
2043 b.AddEdgeTo(grow)
2044 b.AddEdgeTo(assign)
2045
2046 // Call growslice
2047 s.startBlock(grow)
2048 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type)}, s.sb)
2049
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002050 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
Keith Randall9d22c102015-09-11 11:02:57 -07002051
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002052 s.vars[&ptrVar] = r[0]
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002053 // Note: we don't need to read r[1], the result's length. It will be nl.
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002054 // (or maybe we should, we just have to spill/restore nl otherwise?)
2055 s.vars[&capVar] = r[2]
Keith Randall9d22c102015-09-11 11:02:57 -07002056 b = s.endBlock()
2057 b.AddEdgeTo(assign)
2058
2059 // assign new elements to slots
2060 s.startBlock(assign)
Keith Randall9aba7e72015-10-05 13:48:40 -07002061
2062 // Evaluate args
2063 args := make([]*ssa.Value, 0, nargs)
Keith Randall808d7c72015-10-07 14:35:25 -07002064 store := make([]bool, 0, nargs)
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002065 for _, n := range n.List.Slice()[1:] {
2066 if canSSAType(n.Type) {
2067 args = append(args, s.expr(n))
Keith Randall808d7c72015-10-07 14:35:25 -07002068 store = append(store, true)
2069 } else {
Ian Lance Taylorcd6619d2016-03-09 12:39:36 -08002070 args = append(args, s.addr(n, false))
Keith Randall808d7c72015-10-07 14:35:25 -07002071 store = append(store, false)
2072 }
Keith Randall9aba7e72015-10-05 13:48:40 -07002073 }
2074
Keith Randallb32217a2015-09-17 16:45:10 -07002075 p = s.variable(&ptrVar, pt) // generates phi for ptr
2076 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
Keith Randall9d22c102015-09-11 11:02:57 -07002077 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
Keith Randall5ba31942016-01-25 17:06:54 -08002078 // TODO: just one write barrier call for all of these writes?
2079 // TODO: maybe just one writeBarrier.enabled check?
Keith Randall9d22c102015-09-11 11:02:57 -07002080 for i, arg := range args {
Keith Randall582baae2015-11-02 21:28:13 -08002081 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
Keith Randall808d7c72015-10-07 14:35:25 -07002082 if store[i] {
Keith Randall5ba31942016-01-25 17:06:54 -08002083 if haspointers(et) {
2084 s.insertWBstore(et, addr, arg, n.Lineno)
2085 } else {
2086 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2087 }
Keith Randall808d7c72015-10-07 14:35:25 -07002088 } else {
Keith Randall5ba31942016-01-25 17:06:54 -08002089 if haspointers(et) {
2090 s.insertWBmove(et, addr, arg, n.Lineno)
2091 } else {
2092 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2093 }
Keith Randall9d22c102015-09-11 11:02:57 -07002094 }
2095 }
2096
2097 // make result
Keith Randallb32217a2015-09-17 16:45:10 -07002098 delete(s.vars, &ptrVar)
2099 delete(s.vars, &capVar)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002100 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
Keith Randall9d22c102015-09-11 11:02:57 -07002101
Keith Randalld2fd43a2015-04-15 15:51:25 -07002102 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07002103 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -07002104 return nil
2105 }
2106}
2107
Keith Randall99187312015-11-02 16:56:53 -08002108// condBranch evaluates the boolean expression cond and branches to yes
2109// if cond is true and no if cond is false.
2110// This function is intended to handle && and || better than just calling
2111// s.expr(cond) and branching on the result.
2112func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2113 if cond.Op == OANDAND {
2114 mid := s.f.NewBlock(ssa.BlockPlain)
2115 s.stmtList(cond.Ninit)
2116 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2117 s.startBlock(mid)
2118 s.condBranch(cond.Right, yes, no, likely)
2119 return
2120 // Note: if likely==1, then both recursive calls pass 1.
2121 // If likely==-1, then we don't have enough information to decide
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002122 // whether the first branch is likely or not. So we pass 0 for
Keith Randall99187312015-11-02 16:56:53 -08002123 // the likeliness of the first branch.
2124 // TODO: have the frontend give us branch prediction hints for
2125 // OANDAND and OOROR nodes (if it ever has such info).
2126 }
2127 if cond.Op == OOROR {
2128 mid := s.f.NewBlock(ssa.BlockPlain)
2129 s.stmtList(cond.Ninit)
2130 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2131 s.startBlock(mid)
2132 s.condBranch(cond.Right, yes, no, likely)
2133 return
2134 // Note: if likely==-1, then both recursive calls pass -1.
2135 // If likely==1, then we don't have enough info to decide
2136 // the likelihood of the first branch.
2137 }
Keith Randalld19bfc32015-11-03 09:30:17 -08002138 if cond.Op == ONOT {
2139 s.stmtList(cond.Ninit)
2140 s.condBranch(cond.Left, no, yes, -likely)
2141 return
2142 }
Keith Randall99187312015-11-02 16:56:53 -08002143 c := s.expr(cond)
2144 b := s.endBlock()
2145 b.Kind = ssa.BlockIf
2146 b.Control = c
2147 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2148 b.AddEdgeTo(yes)
2149 b.AddEdgeTo(no)
2150}
2151
Keith Randall5ba31942016-01-25 17:06:54 -08002152// assign does left = right.
2153// Right has already been evaluated to ssa, left has not.
2154// If deref is true, then we do left = *right instead (and right has already been nil-checked).
2155// If deref is true and right == nil, just do left = 0.
2156// Include a write barrier if wb is true.
2157func (s *state) assign(left *Node, right *ssa.Value, wb, deref bool, line int32) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002158 if left.Op == ONAME && isblank(left) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002159 return
2160 }
Keith Randalld4cc51d2015-08-14 21:47:20 -07002161 t := left.Type
2162 dowidth(t)
Keith Randall6a8a9da2016-02-27 17:49:31 -08002163 if s.canSSA(left) {
Keith Randall5ba31942016-01-25 17:06:54 -08002164 if deref {
2165 s.Fatalf("can SSA LHS %s but not RHS %s", left, right)
2166 }
Keith Randalla734bbc2016-01-11 21:05:33 -08002167 if left.Op == ODOT {
2168 // We're assigning to a field of an ssa-able value.
2169 // We need to build a new structure with the new value for the
2170 // field we're assigning and the old values for the other fields.
2171 // For instance:
2172 // type T struct {a, b, c int}
2173 // var T x
2174 // x.b = 5
2175 // For the x.b = 5 assignment we want to generate x = T{x.a, 5, x.c}
2176
2177 // Grab information about the structure type.
2178 t := left.Left.Type
2179 nf := t.NumFields()
2180 idx := fieldIdx(left)
2181
2182 // Grab old value of structure.
2183 old := s.expr(left.Left)
2184
2185 // Make new structure.
2186 new := s.newValue0(ssa.StructMakeOp(t.NumFields()), t)
2187
2188 // Add fields as args.
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002189 for i := 0; i < nf; i++ {
Keith Randalla734bbc2016-01-11 21:05:33 -08002190 if i == idx {
2191 new.AddArg(right)
2192 } else {
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002193 new.AddArg(s.newValue1I(ssa.OpStructSelect, t.FieldType(i), int64(i), old))
Keith Randalla734bbc2016-01-11 21:05:33 -08002194 }
2195 }
2196
2197 // Recursively assign the new value we've made to the base of the dot op.
Keith Randall5ba31942016-01-25 17:06:54 -08002198 s.assign(left.Left, new, false, false, line)
Keith Randalla734bbc2016-01-11 21:05:33 -08002199 // TODO: do we need to update named values here?
2200 return
2201 }
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002202 // Update variable assignment.
Josh Bleecher Snyder07269312015-08-29 14:54:45 -07002203 s.vars[left] = right
Keith Randallc24681a2015-10-22 14:22:38 -07002204 s.addNamedValue(left, right)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002205 return
2206 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002207 // Left is not ssa-able. Compute its address.
David Chase57670ad2015-10-09 16:48:30 -04002208 addr := s.addr(left, false)
Keith Randalld2107fc2015-08-24 02:16:19 -07002209 if left.Op == ONAME {
Keith Randallb32217a2015-09-17 16:45:10 -07002210 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
Keith Randalld2107fc2015-08-24 02:16:19 -07002211 }
Keith Randall5ba31942016-01-25 17:06:54 -08002212 if deref {
2213 // Treat as a mem->mem move.
2214 if right == nil {
2215 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
2216 return
2217 }
2218 if wb {
2219 s.insertWBmove(t, addr, right, line)
2220 return
2221 }
2222 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), addr, right, s.mem())
2223 return
Keith Randalle3869a62015-09-07 23:18:02 -07002224 }
Keith Randall5ba31942016-01-25 17:06:54 -08002225 // Treat as a store.
2226 if wb {
2227 s.insertWBstore(t, addr, right, line)
2228 return
2229 }
2230 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002231}
2232
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002233// zeroVal returns the zero value for type t.
2234func (s *state) zeroVal(t *Type) *ssa.Value {
2235 switch {
Keith Randall9cb332e2015-07-28 14:19:20 -07002236 case t.IsInteger():
2237 switch t.Size() {
2238 case 1:
2239 return s.constInt8(t, 0)
2240 case 2:
2241 return s.constInt16(t, 0)
2242 case 4:
2243 return s.constInt32(t, 0)
2244 case 8:
2245 return s.constInt64(t, 0)
2246 default:
2247 s.Fatalf("bad sized integer type %s", t)
2248 }
Todd Neal752fe4d2015-08-25 19:21:45 -05002249 case t.IsFloat():
2250 switch t.Size() {
2251 case 4:
2252 return s.constFloat32(t, 0)
2253 case 8:
2254 return s.constFloat64(t, 0)
2255 default:
2256 s.Fatalf("bad sized float type %s", t)
2257 }
David Chase52578582015-08-28 14:24:10 -04002258 case t.IsComplex():
2259 switch t.Size() {
2260 case 8:
2261 z := s.constFloat32(Types[TFLOAT32], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002262 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002263 case 16:
2264 z := s.constFloat64(Types[TFLOAT64], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002265 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002266 default:
2267 s.Fatalf("bad sized complex type %s", t)
2268 }
2269
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002270 case t.IsString():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002271 return s.constEmptyString(t)
Keith Randall9cb332e2015-07-28 14:19:20 -07002272 case t.IsPtr():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002273 return s.constNil(t)
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002274 case t.IsBoolean():
Josh Bleecher Snydercea44142015-09-08 16:52:25 -07002275 return s.constBool(false)
Keith Randall9f954db2015-08-18 10:26:28 -07002276 case t.IsInterface():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002277 return s.constInterface(t)
Keith Randall9f954db2015-08-18 10:26:28 -07002278 case t.IsSlice():
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08002279 return s.constSlice(t)
Keith Randalla734bbc2016-01-11 21:05:33 -08002280 case t.IsStruct():
2281 n := t.NumFields()
2282 v := s.entryNewValue0(ssa.StructMakeOp(t.NumFields()), t)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002283 for i := 0; i < n; i++ {
Keith Randalla734bbc2016-01-11 21:05:33 -08002284 v.AddArg(s.zeroVal(t.FieldType(i).(*Type)))
2285 }
2286 return v
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002287 }
2288 s.Unimplementedf("zero for type %v not implemented", t)
2289 return nil
2290}
2291
Keith Randalld24768e2015-09-09 23:56:59 -07002292type callKind int8
2293
2294const (
2295 callNormal callKind = iota
2296 callDefer
2297 callGo
2298)
2299
Keith Randall5ba31942016-01-25 17:06:54 -08002300// Calls the function n using the specified call type.
2301// Returns the address of the return value (or nil if none).
Keith Randalld24768e2015-09-09 23:56:59 -07002302func (s *state) call(n *Node, k callKind) *ssa.Value {
2303 var sym *Sym // target symbol (if static)
2304 var closure *ssa.Value // ptr to closure to run (if dynamic)
2305 var codeptr *ssa.Value // ptr to target code (if dynamic)
2306 var rcvr *ssa.Value // receiver to set
2307 fn := n.Left
2308 switch n.Op {
2309 case OCALLFUNC:
2310 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2311 sym = fn.Sym
2312 break
2313 }
2314 closure = s.expr(fn)
Keith Randalld24768e2015-09-09 23:56:59 -07002315 case OCALLMETH:
2316 if fn.Op != ODOTMETH {
2317 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2318 }
2319 if fn.Right.Op != ONAME {
2320 Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
2321 }
2322 if k == callNormal {
2323 sym = fn.Right.Sym
2324 break
2325 }
2326 n2 := *fn.Right
2327 n2.Class = PFUNC
2328 closure = s.expr(&n2)
2329 // Note: receiver is already assigned in n.List, so we don't
2330 // want to set it here.
2331 case OCALLINTER:
2332 if fn.Op != ODOTINTER {
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002333 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(fn.Op, 0))
Keith Randalld24768e2015-09-09 23:56:59 -07002334 }
2335 i := s.expr(fn.Left)
2336 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2337 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2338 itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
2339 if k == callNormal {
2340 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2341 } else {
2342 closure = itab
2343 }
2344 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2345 }
2346 dowidth(fn.Type)
2347 stksize := fn.Type.Argwid // includes receiver
2348
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002349 // Run all argument assignments. The arg slots have already
Keith Randalld24768e2015-09-09 23:56:59 -07002350 // been offset by the appropriate amount (+2*widthptr for go/defer,
2351 // +widthptr for interface calls).
2352 // For OCALLMETH, the receiver is set in these statements.
2353 s.stmtList(n.List)
2354
2355 // Set receiver (for interface calls)
2356 if rcvr != nil {
Keith Randall7c4fbb62015-10-19 13:56:55 -07002357 argStart := Ctxt.FixedFrameSize()
Keith Randalld24768e2015-09-09 23:56:59 -07002358 if k != callNormal {
2359 argStart += int64(2 * Widthptr)
2360 }
2361 addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002362 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002363 }
2364
2365 // Defer/go args
2366 if k != callNormal {
2367 // Write argsize and closure (args to Newproc/Deferproc).
2368 argsize := s.constInt32(Types[TUINT32], int32(stksize))
Keith Randallb32217a2015-09-17 16:45:10 -07002369 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002370 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002371 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002372 stksize += 2 * int64(Widthptr)
2373 }
2374
2375 // call target
2376 bNext := s.f.NewBlock(ssa.BlockPlain)
2377 var call *ssa.Value
2378 switch {
2379 case k == callDefer:
2380 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2381 case k == callGo:
2382 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2383 case closure != nil:
2384 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2385 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2386 case codeptr != nil:
2387 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2388 case sym != nil:
2389 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2390 default:
2391 Fatalf("bad call type %s %v", opnames[n.Op], n)
2392 }
2393 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2394
2395 // Finish call block
Keith Randallb32217a2015-09-17 16:45:10 -07002396 s.vars[&memVar] = call
Keith Randalld24768e2015-09-09 23:56:59 -07002397 b := s.endBlock()
2398 b.Kind = ssa.BlockCall
2399 b.Control = call
2400 b.AddEdgeTo(bNext)
Keith Randallddc6b642016-03-09 19:27:57 -08002401 if k == callDefer {
2402 // Add recover edge to exit code.
2403 b.Kind = ssa.BlockDefer
2404 r := s.f.NewBlock(ssa.BlockPlain)
2405 s.startBlock(r)
2406 s.exit()
2407 b.AddEdgeTo(r)
2408 b.Likely = ssa.BranchLikely
2409 }
Keith Randalld24768e2015-09-09 23:56:59 -07002410
Keith Randall5ba31942016-01-25 17:06:54 -08002411 // Start exit block, find address of result.
Keith Randalld24768e2015-09-09 23:56:59 -07002412 s.startBlock(bNext)
Matthew Dempskyf6fab932016-03-15 11:06:03 -07002413 res := n.Left.Type.Results()
2414 if res.NumFields() == 0 || k != callNormal {
Keith Randalld24768e2015-09-09 23:56:59 -07002415 // call has no return value. Continue with the next statement.
2416 return nil
2417 }
Matthew Dempskyf6fab932016-03-15 11:06:03 -07002418 fp := res.Field(0)
Keith Randall5ba31942016-01-25 17:06:54 -08002419 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
Keith Randalld24768e2015-09-09 23:56:59 -07002420}
2421
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002422// etypesign returns the signed-ness of e, for integer/pointer etypes.
2423// -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
Keith Randall4304fbc2015-11-16 13:20:16 -08002424func etypesign(e EType) int8 {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002425 switch e {
2426 case TINT8, TINT16, TINT32, TINT64, TINT:
2427 return -1
2428 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2429 return +1
2430 }
2431 return 0
2432}
2433
Todd Neald076ef72015-10-15 20:25:32 -05002434// lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2435// This improves the effectiveness of cse by using the same Aux values for the
2436// same symbols.
2437func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2438 switch sym.(type) {
2439 default:
2440 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2441 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2442 // these are the only valid types
2443 }
2444
2445 if lsym, ok := s.varsyms[n]; ok {
2446 return lsym
2447 } else {
2448 s.varsyms[n] = sym
2449 return sym
2450 }
2451}
2452
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07002453// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
Keith Randallc3c84a22015-07-13 15:55:37 -07002454// The value that the returned Value represents is guaranteed to be non-nil.
David Chase57670ad2015-10-09 16:48:30 -04002455// If bounded is true then this address does not require a nil check for its operand
2456// even if that would otherwise be implied.
2457func (s *state) addr(n *Node, bounded bool) *ssa.Value {
Keith Randallc24681a2015-10-22 14:22:38 -07002458 t := Ptrto(n.Type)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002459 switch n.Op {
2460 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07002461 switch n.Class {
2462 case PEXTERN:
Keith Randallcfc2aa52015-05-18 16:44:20 -07002463 // global variable
Todd Neal74180dd2015-10-27 21:35:48 -05002464 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Sym})
Keith Randallc24681a2015-10-22 14:22:38 -07002465 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
Josh Bleecher Snyder67df7932015-07-28 11:08:44 -07002466 // TODO: Make OpAddr use AuxInt as well as Aux.
2467 if n.Xoffset != 0 {
2468 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2469 }
2470 return v
David Chase956f3192015-09-11 16:40:05 -04002471 case PPARAM:
2472 // parameter slot
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002473 v := s.decladdrs[n]
Keith Randall4304fbc2015-11-16 13:20:16 -08002474 if v != nil {
2475 return v
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002476 }
Keith Randall4304fbc2015-11-16 13:20:16 -08002477 if n.String() == ".fp" {
2478 // Special arg that points to the frame pointer.
2479 // (Used by the race detector, others?)
2480 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2481 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2482 }
2483 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2484 return nil
Keith Randalld2107fc2015-08-24 02:16:19 -07002485 case PAUTO:
Todd Neal40bfec02016-03-11 20:03:17 -06002486 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
Keith Randallc24681a2015-10-22 14:22:38 -07002487 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002488 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
Todd Neald076ef72015-10-15 20:25:32 -05002489 // ensure that we reuse symbols for out parameters so
2490 // that cse works on their addresses
2491 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randallc24681a2015-10-22 14:22:38 -07002492 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002493 case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002494 return s.expr(n.Name.Heapaddr)
Keith Randall290d8fc2015-06-10 15:03:06 -07002495 default:
Josh Bleecher Snyder58446032015-08-23 20:29:43 -07002496 s.Unimplementedf("variable address class %v not implemented", n.Class)
Keith Randall290d8fc2015-06-10 15:03:06 -07002497 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07002498 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002499 case OINDREG:
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002500 // indirect off a register
Keith Randallcfc2aa52015-05-18 16:44:20 -07002501 // used for storing/loading arguments/returns to/from callees
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002502 if int(n.Reg) != Thearch.REGSP {
2503 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2504 return nil
2505 }
Keith Randallc24681a2015-10-22 14:22:38 -07002506 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002507 case OINDEX:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002508 if n.Left.Type.IsSlice() {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002509 a := s.expr(n.Left)
2510 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002511 i = s.extendIndex(i)
Keith Randallc24681a2015-10-22 14:22:38 -07002512 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
Keith Randall46e62f82015-08-18 14:17:30 -07002513 if !n.Bounded {
2514 s.boundsCheck(i, len)
2515 }
Keith Randallc24681a2015-10-22 14:22:38 -07002516 p := s.newValue1(ssa.OpSlicePtr, t, a)
2517 return s.newValue2(ssa.OpPtrIndex, t, p, i)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002518 } else { // array
David Chase57670ad2015-10-09 16:48:30 -04002519 a := s.addr(n.Left, bounded)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002520 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002521 i = s.extendIndex(i)
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07002522 len := s.constInt(Types[TINT], n.Left.Type.Bound)
Keith Randall46e62f82015-08-18 14:17:30 -07002523 if !n.Bounded {
2524 s.boundsCheck(i, len)
2525 }
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002526 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002527 }
Todd Nealb383de22015-07-13 21:22:16 -05002528 case OIND:
2529 p := s.expr(n.Left)
David Chase57670ad2015-10-09 16:48:30 -04002530 if !bounded {
2531 s.nilCheck(p)
2532 }
Todd Nealb383de22015-07-13 21:22:16 -05002533 return p
Keith Randallc3c84a22015-07-13 15:55:37 -07002534 case ODOT:
David Chase57670ad2015-10-09 16:48:30 -04002535 p := s.addr(n.Left, bounded)
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08002536 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
Keith Randallc3c84a22015-07-13 15:55:37 -07002537 case ODOTPTR:
2538 p := s.expr(n.Left)
David Chase57670ad2015-10-09 16:48:30 -04002539 if !bounded {
2540 s.nilCheck(p)
2541 }
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08002542 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset, p)
David Chase956f3192015-09-11 16:40:05 -04002543 case OCLOSUREVAR:
Josh Bleecher Snyderda1802f2016-03-04 12:34:43 -08002544 return s.newValue1I(ssa.OpOffPtr, t, n.Xoffset,
2545 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])))
David Chase32ffbf72015-10-08 17:14:12 -04002546 case OPARAM:
2547 p := n.Left
2548 if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
2549 s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
2550 }
2551
2552 // Recover original offset to address passed-in param value.
2553 original_p := *p
2554 original_p.Xoffset = n.Xoffset
2555 aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
Keith Randallc24681a2015-10-22 14:22:38 -07002556 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase57670ad2015-10-09 16:48:30 -04002557 case OCONVNOP:
2558 addr := s.addr(n.Left, bounded)
Keith Randallc24681a2015-10-22 14:22:38 -07002559 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
Keith Randall5ba31942016-01-25 17:06:54 -08002560 case OCALLFUNC, OCALLINTER, OCALLMETH:
2561 return s.call(n, callNormal)
David Chase57670ad2015-10-09 16:48:30 -04002562
Keith Randallcfc2aa52015-05-18 16:44:20 -07002563 default:
Matthew Dempskyc3dfad52016-03-07 08:23:55 -08002564 s.Unimplementedf("unhandled addr %v", Oconv(n.Op, 0))
Keith Randallcfc2aa52015-05-18 16:44:20 -07002565 return nil
2566 }
2567}
2568
Keith Randall290d8fc2015-06-10 15:03:06 -07002569// canSSA reports whether n is SSA-able.
Keith Randalla734bbc2016-01-11 21:05:33 -08002570// n must be an ONAME (or an ODOT sequence with an ONAME base).
Keith Randall6a8a9da2016-02-27 17:49:31 -08002571func (s *state) canSSA(n *Node) bool {
Keith Randalla734bbc2016-01-11 21:05:33 -08002572 for n.Op == ODOT {
2573 n = n.Left
2574 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002575 if n.Op != ONAME {
Daniel Morsing66b47812015-06-27 15:45:20 +01002576 return false
Keith Randall290d8fc2015-06-10 15:03:06 -07002577 }
2578 if n.Addrtaken {
2579 return false
2580 }
2581 if n.Class&PHEAP != 0 {
2582 return false
2583 }
Josh Bleecher Snyder96548732015-08-28 13:35:32 -07002584 switch n.Class {
Keith Randall6a8a9da2016-02-27 17:49:31 -08002585 case PEXTERN, PPARAMREF:
2586 // TODO: maybe treat PPARAMREF with an Arg-like op to read from closure?
Keith Randall290d8fc2015-06-10 15:03:06 -07002587 return false
Keith Randall6a8a9da2016-02-27 17:49:31 -08002588 case PPARAMOUT:
2589 if hasdefer {
2590 // TODO: handle this case? Named return values must be
2591 // in memory so that the deferred function can see them.
2592 // Maybe do: if !strings.HasPrefix(n.String(), "~") { return false }
2593 return false
2594 }
2595 if s.cgoUnsafeArgs {
2596 // Cgo effectively takes the address of all result args,
2597 // but the compiler can't see that.
2598 return false
2599 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002600 }
Keith Randall8a1f6212015-09-08 21:28:44 -07002601 if n.Class == PPARAM && n.String() == ".this" {
2602 // wrappers generated by genwrapper need to update
2603 // the .this pointer in place.
Keith Randall6a8a9da2016-02-27 17:49:31 -08002604 // TODO: treat as a PPARMOUT?
Keith Randall8a1f6212015-09-08 21:28:44 -07002605 return false
2606 }
Keith Randall9f954db2015-08-18 10:26:28 -07002607 return canSSAType(n.Type)
2608 // TODO: try to make more variables SSAable?
2609}
2610
2611// canSSA reports whether variables of type t are SSA-able.
2612func canSSAType(t *Type) bool {
2613 dowidth(t)
2614 if t.Width > int64(4*Widthptr) {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002615 // 4*Widthptr is an arbitrary constant. We want it
Keith Randall9f954db2015-08-18 10:26:28 -07002616 // to be at least 3*Widthptr so slices can be registerized.
2617 // Too big and we'll introduce too much register pressure.
Daniel Morsing66b47812015-06-27 15:45:20 +01002618 return false
2619 }
Keith Randall9f954db2015-08-18 10:26:28 -07002620 switch t.Etype {
2621 case TARRAY:
2622 if Isslice(t) {
2623 return true
2624 }
2625 // We can't do arrays because dynamic indexing is
2626 // not supported on SSA variables.
2627 // TODO: maybe allow if length is <=1? All indexes
2628 // are constant? Might be good for the arrays
2629 // introduced by the compiler for variadic functions.
2630 return false
2631 case TSTRUCT:
Keith Randalla734bbc2016-01-11 21:05:33 -08002632 if countfield(t) > ssa.MaxStruct {
Keith Randall9f954db2015-08-18 10:26:28 -07002633 return false
2634 }
Matthew Dempskyfe5b4a62016-03-10 01:50:58 -08002635 for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
Keith Randall9f954db2015-08-18 10:26:28 -07002636 if !canSSAType(t1.Type) {
2637 return false
2638 }
2639 }
Keith Randalla734bbc2016-01-11 21:05:33 -08002640 return true
Keith Randall9f954db2015-08-18 10:26:28 -07002641 default:
2642 return true
2643 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002644}
2645
Keith Randallcfc2aa52015-05-18 16:44:20 -07002646// nilCheck generates nil pointer checking code.
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002647// Starts a new block on return, unless nil checks are disabled.
Josh Bleecher Snyder7e74e432015-07-24 11:55:52 -07002648// Used only for automatically inserted nil checks,
2649// not for user code like 'x != nil'.
Keith Randallcfc2aa52015-05-18 16:44:20 -07002650func (s *state) nilCheck(ptr *ssa.Value) {
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002651 if Disable_checknil != 0 {
2652 return
2653 }
Keith Randall31115a52015-10-23 19:12:49 -07002654 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07002655 b := s.endBlock()
Keith Randall31115a52015-10-23 19:12:49 -07002656 b.Kind = ssa.BlockCheck
2657 b.Control = chk
Keith Randallcfc2aa52015-05-18 16:44:20 -07002658 bNext := s.f.NewBlock(ssa.BlockPlain)
Todd Neal47d67992015-08-28 21:36:29 -05002659 b.AddEdgeTo(bNext)
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002660 s.startBlock(bNext)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002661}
2662
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002663// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
Keith Randallcfc2aa52015-05-18 16:44:20 -07002664// Starts a new block on return.
2665func (s *state) boundsCheck(idx, len *ssa.Value) {
Keith Randall8d236812015-08-18 15:25:40 -07002666 if Debug['B'] != 0 {
2667 return
2668 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002669 // TODO: convert index to full width?
2670 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2671
2672 // bounds check
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07002673 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002674 s.check(cmp, Panicindex)
Keith Randall3526cf52015-08-24 23:52:03 -07002675}
2676
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002677// sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
Keith Randall3526cf52015-08-24 23:52:03 -07002678// Starts a new block on return.
2679func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2680 if Debug['B'] != 0 {
2681 return
2682 }
2683 // TODO: convert index to full width?
2684 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2685
2686 // bounds check
2687 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002688 s.check(cmp, panicslice)
Keith Randall3526cf52015-08-24 23:52:03 -07002689}
2690
Keith Randall3a70bf92015-09-17 16:54:15 -07002691// If cmp (a bool) is true, panic using the given function.
2692func (s *state) check(cmp *ssa.Value, fn *Node) {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002693 b := s.endBlock()
2694 b.Kind = ssa.BlockIf
2695 b.Control = cmp
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07002696 b.Likely = ssa.BranchLikely
Keith Randallcfc2aa52015-05-18 16:44:20 -07002697 bNext := s.f.NewBlock(ssa.BlockPlain)
Keith Randall74e568f2015-11-09 21:35:40 -08002698 line := s.peekLine()
2699 bPanic := s.panics[funcLine{fn, line}]
2700 if bPanic == nil {
2701 bPanic = s.f.NewBlock(ssa.BlockPlain)
2702 s.panics[funcLine{fn, line}] = bPanic
2703 s.startBlock(bPanic)
2704 // The panic call takes/returns memory to ensure that the right
2705 // memory state is observed if the panic happens.
2706 s.rtcall(fn, false, nil)
2707 }
Todd Neal47d67992015-08-28 21:36:29 -05002708 b.AddEdgeTo(bNext)
2709 b.AddEdgeTo(bPanic)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002710 s.startBlock(bNext)
2711}
2712
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002713// rtcall issues a call to the given runtime function fn with the listed args.
2714// Returns a slice of results of the given result types.
2715// The call is added to the end of the current block.
2716// If returns is false, the block is marked as an exit block.
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002717// If returns is true, the block is marked as a call block. A new block
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002718// is started to load the return values.
2719func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2720 // Write args to the stack
2721 var off int64 // TODO: arch-dependent starting offset?
2722 for _, arg := range args {
2723 t := arg.Type
2724 off = Rnd(off, t.Alignment())
2725 ptr := s.sp
2726 if off != 0 {
2727 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2728 }
2729 size := t.Size()
2730 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2731 off += size
2732 }
2733 off = Rnd(off, int64(Widthptr))
2734
2735 // Issue call
2736 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2737 s.vars[&memVar] = call
2738
2739 // Finish block
2740 b := s.endBlock()
2741 if !returns {
2742 b.Kind = ssa.BlockExit
2743 b.Control = call
2744 call.AuxInt = off
2745 if len(results) > 0 {
2746 Fatalf("panic call can't have results")
2747 }
2748 return nil
2749 }
2750 b.Kind = ssa.BlockCall
2751 b.Control = call
2752 bNext := s.f.NewBlock(ssa.BlockPlain)
2753 b.AddEdgeTo(bNext)
2754 s.startBlock(bNext)
2755
2756 // Load results
2757 res := make([]*ssa.Value, len(results))
2758 for i, t := range results {
2759 off = Rnd(off, t.Alignment())
2760 ptr := s.sp
2761 if off != 0 {
2762 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2763 }
2764 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
2765 off += t.Size()
2766 }
2767 off = Rnd(off, int64(Widthptr))
2768
2769 // Remember how much callee stack space we needed.
2770 call.AuxInt = off
2771
2772 return res
2773}
2774
Keith Randall5ba31942016-01-25 17:06:54 -08002775// insertWBmove inserts the assignment *left = *right including a write barrier.
2776// t is the type being assigned.
2777func (s *state) insertWBmove(t *Type, left, right *ssa.Value, line int32) {
Keith Randall4304fbc2015-11-16 13:20:16 -08002778 // if writeBarrier.enabled {
Keith Randall5ba31942016-01-25 17:06:54 -08002779 // typedmemmove(&t, left, right)
2780 // } else {
2781 // *left = *right
Keith Randall9d22c102015-09-11 11:02:57 -07002782 // }
2783 bThen := s.f.NewBlock(ssa.BlockPlain)
Keith Randall5ba31942016-01-25 17:06:54 -08002784 bElse := s.f.NewBlock(ssa.BlockPlain)
2785 bEnd := s.f.NewBlock(ssa.BlockPlain)
Keith Randall9d22c102015-09-11 11:02:57 -07002786
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002787 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier").Sym}
David Chase8107b002016-02-28 11:15:22 -05002788 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002789 // TODO: select the .enabled field. It is currently first, so not needed for now.
David Chase8107b002016-02-28 11:15:22 -05002790 // Load word, test byte, avoiding partial register write from load byte.
2791 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
2792 flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
Keith Randall9d22c102015-09-11 11:02:57 -07002793 b := s.endBlock()
2794 b.Kind = ssa.BlockIf
2795 b.Likely = ssa.BranchUnlikely
2796 b.Control = flag
2797 b.AddEdgeTo(bThen)
Keith Randall5ba31942016-01-25 17:06:54 -08002798 b.AddEdgeTo(bElse)
Keith Randall9d22c102015-09-11 11:02:57 -07002799
2800 s.startBlock(bThen)
Keith Randall9d22c102015-09-11 11:02:57 -07002801 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
Keith Randall5ba31942016-01-25 17:06:54 -08002802 s.rtcall(typedmemmove, true, nil, taddr, left, right)
2803 s.endBlock().AddEdgeTo(bEnd)
2804
2805 s.startBlock(bElse)
2806 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, t.Size(), left, right, s.mem())
2807 s.endBlock().AddEdgeTo(bEnd)
2808
2809 s.startBlock(bEnd)
Keith Randall9d22c102015-09-11 11:02:57 -07002810
David Chase729abfa2015-10-26 17:34:06 -04002811 if Debug_wb > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002812 Warnl(line, "write barrier")
David Chase729abfa2015-10-26 17:34:06 -04002813 }
Keith Randall5ba31942016-01-25 17:06:54 -08002814}
David Chase729abfa2015-10-26 17:34:06 -04002815
Keith Randall5ba31942016-01-25 17:06:54 -08002816// insertWBstore inserts the assignment *left = right including a write barrier.
2817// t is the type being assigned.
2818func (s *state) insertWBstore(t *Type, left, right *ssa.Value, line int32) {
2819 // store scalar fields
2820 // if writeBarrier.enabled {
2821 // writebarrierptr for pointer fields
2822 // } else {
2823 // store pointer fields
2824 // }
2825
Keith Randallaebf6612016-01-29 21:57:57 -08002826 s.storeTypeScalars(t, left, right)
Keith Randall5ba31942016-01-25 17:06:54 -08002827
2828 bThen := s.f.NewBlock(ssa.BlockPlain)
2829 bElse := s.f.NewBlock(ssa.BlockPlain)
2830 bEnd := s.f.NewBlock(ssa.BlockPlain)
2831
Matthew Dempskydafbcf62016-03-04 15:19:06 -08002832 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier").Sym}
David Chase8107b002016-02-28 11:15:22 -05002833 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TUINT32]), aux, s.sb)
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00002834 // TODO: select the .enabled field. It is currently first, so not needed for now.
David Chase8107b002016-02-28 11:15:22 -05002835 // Load word, test byte, avoiding partial register write from load byte.
2836 flag := s.newValue2(ssa.OpLoad, Types[TUINT32], flagaddr, s.mem())
2837 flag = s.newValue1(ssa.OpTrunc64to8, Types[TBOOL], flag)
Keith Randall5ba31942016-01-25 17:06:54 -08002838 b := s.endBlock()
2839 b.Kind = ssa.BlockIf
2840 b.Likely = ssa.BranchUnlikely
2841 b.Control = flag
2842 b.AddEdgeTo(bThen)
2843 b.AddEdgeTo(bElse)
2844
2845 // Issue write barriers for pointer writes.
2846 s.startBlock(bThen)
Keith Randallaebf6612016-01-29 21:57:57 -08002847 s.storeTypePtrsWB(t, left, right)
2848 s.endBlock().AddEdgeTo(bEnd)
2849
2850 // Issue regular stores for pointer writes.
2851 s.startBlock(bElse)
2852 s.storeTypePtrs(t, left, right)
2853 s.endBlock().AddEdgeTo(bEnd)
2854
2855 s.startBlock(bEnd)
2856
2857 if Debug_wb > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08002858 Warnl(line, "write barrier")
Keith Randallaebf6612016-01-29 21:57:57 -08002859 }
2860}
2861
2862// do *left = right for all scalar (non-pointer) parts of t.
2863func (s *state) storeTypeScalars(t *Type, left, right *ssa.Value) {
2864 switch {
2865 case t.IsBoolean() || t.IsInteger() || t.IsFloat() || t.IsComplex():
2866 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), left, right, s.mem())
2867 case t.IsPtr() || t.IsMap() || t.IsChan():
2868 // no scalar fields.
2869 case t.IsString():
2870 len := s.newValue1(ssa.OpStringLen, Types[TINT], right)
2871 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2872 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2873 case t.IsSlice():
2874 len := s.newValue1(ssa.OpSliceLen, Types[TINT], right)
2875 cap := s.newValue1(ssa.OpSliceCap, Types[TINT], right)
2876 lenAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), s.config.IntSize, left)
2877 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, lenAddr, len, s.mem())
2878 capAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TINT]), 2*s.config.IntSize, left)
2879 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, capAddr, cap, s.mem())
2880 case t.IsInterface():
2881 // itab field doesn't need a write barrier (even though it is a pointer).
2882 itab := s.newValue1(ssa.OpITab, Ptrto(Types[TUINT8]), right)
2883 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.IntSize, left, itab, s.mem())
2884 case t.IsStruct():
2885 n := t.NumFields()
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002886 for i := 0; i < n; i++ {
Keith Randallaebf6612016-01-29 21:57:57 -08002887 ft := t.FieldType(i)
2888 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002889 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
Keith Randallaebf6612016-01-29 21:57:57 -08002890 s.storeTypeScalars(ft.(*Type), addr, val)
2891 }
2892 default:
2893 s.Fatalf("bad write barrier type %s", t)
2894 }
2895}
2896
2897// do *left = right for all pointer parts of t.
2898func (s *state) storeTypePtrs(t *Type, left, right *ssa.Value) {
2899 switch {
2900 case t.IsPtr() || t.IsMap() || t.IsChan():
2901 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, right, s.mem())
2902 case t.IsString():
2903 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2904 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2905 case t.IsSlice():
2906 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2907 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, left, ptr, s.mem())
2908 case t.IsInterface():
2909 // itab field is treated as a scalar.
2910 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2911 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2912 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, s.config.PtrSize, idataAddr, idata, s.mem())
2913 case t.IsStruct():
2914 n := t.NumFields()
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002915 for i := 0; i < n; i++ {
Keith Randallaebf6612016-01-29 21:57:57 -08002916 ft := t.FieldType(i)
2917 if !haspointers(ft.(*Type)) {
2918 continue
2919 }
2920 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002921 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
Keith Randallaebf6612016-01-29 21:57:57 -08002922 s.storeTypePtrs(ft.(*Type), addr, val)
2923 }
2924 default:
2925 s.Fatalf("bad write barrier type %s", t)
2926 }
2927}
2928
2929// do *left = right with a write barrier for all pointer parts of t.
2930func (s *state) storeTypePtrsWB(t *Type, left, right *ssa.Value) {
Keith Randall5ba31942016-01-25 17:06:54 -08002931 switch {
2932 case t.IsPtr() || t.IsMap() || t.IsChan():
2933 s.rtcall(writebarrierptr, true, nil, left, right)
2934 case t.IsString():
2935 ptr := s.newValue1(ssa.OpStringPtr, Ptrto(Types[TUINT8]), right)
2936 s.rtcall(writebarrierptr, true, nil, left, ptr)
2937 case t.IsSlice():
2938 ptr := s.newValue1(ssa.OpSlicePtr, Ptrto(Types[TUINT8]), right)
2939 s.rtcall(writebarrierptr, true, nil, left, ptr)
2940 case t.IsInterface():
2941 idata := s.newValue1(ssa.OpIData, Ptrto(Types[TUINT8]), right)
2942 idataAddr := s.newValue1I(ssa.OpOffPtr, Ptrto(Types[TUINT8]), s.config.PtrSize, left)
2943 s.rtcall(writebarrierptr, true, nil, idataAddr, idata)
Keith Randallaebf6612016-01-29 21:57:57 -08002944 case t.IsStruct():
2945 n := t.NumFields()
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002946 for i := 0; i < n; i++ {
Keith Randallaebf6612016-01-29 21:57:57 -08002947 ft := t.FieldType(i)
2948 if !haspointers(ft.(*Type)) {
2949 continue
2950 }
2951 addr := s.newValue1I(ssa.OpOffPtr, ft.PtrTo(), t.FieldOff(i), left)
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07002952 val := s.newValue1I(ssa.OpStructSelect, ft, int64(i), right)
Keith Randallaebf6612016-01-29 21:57:57 -08002953 s.storeTypePtrsWB(ft.(*Type), addr, val)
2954 }
Keith Randall5ba31942016-01-25 17:06:54 -08002955 default:
2956 s.Fatalf("bad write barrier type %s", t)
2957 }
Keith Randall9d22c102015-09-11 11:02:57 -07002958}
2959
Keith Randall5505e8c2015-09-12 23:27:26 -07002960// slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
2961// i,j,k may be nil, in which case they are set to their default value.
2962// t is a slice, ptr to array, or string type.
2963func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
2964 var elemtype *Type
2965 var ptrtype *Type
2966 var ptr *ssa.Value
2967 var len *ssa.Value
2968 var cap *ssa.Value
2969 zero := s.constInt(Types[TINT], 0)
2970 switch {
2971 case t.IsSlice():
2972 elemtype = t.Type
2973 ptrtype = Ptrto(elemtype)
2974 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
2975 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
2976 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
2977 case t.IsString():
2978 elemtype = Types[TUINT8]
2979 ptrtype = Ptrto(elemtype)
2980 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
2981 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
2982 cap = len
2983 case t.IsPtr():
2984 if !t.Type.IsArray() {
2985 s.Fatalf("bad ptr to array in slice %v\n", t)
2986 }
2987 elemtype = t.Type.Type
2988 ptrtype = Ptrto(elemtype)
2989 s.nilCheck(v)
2990 ptr = v
2991 len = s.constInt(Types[TINT], t.Type.Bound)
2992 cap = len
2993 default:
2994 s.Fatalf("bad type in slice %v\n", t)
2995 }
2996
2997 // Set default values
2998 if i == nil {
2999 i = zero
3000 }
3001 if j == nil {
3002 j = len
3003 }
3004 if k == nil {
3005 k = cap
3006 }
3007
3008 // Panic if slice indices are not in bounds.
3009 s.sliceBoundsCheck(i, j)
3010 if j != k {
3011 s.sliceBoundsCheck(j, k)
3012 }
3013 if k != cap {
3014 s.sliceBoundsCheck(k, cap)
3015 }
3016
3017 // Generate the following code assuming that indexes are in bounds.
3018 // The conditional is to make sure that we don't generate a slice
3019 // that points to the next object in memory.
Keith Randall582baae2015-11-02 21:28:13 -08003020 // rlen = (Sub64 j i)
3021 // rcap = (Sub64 k i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003022 // p = ptr
3023 // if rcap != 0 {
Keith Randall582baae2015-11-02 21:28:13 -08003024 // p = (AddPtr ptr (Mul64 low (Const64 size)))
Keith Randall5505e8c2015-09-12 23:27:26 -07003025 // }
3026 // result = (SliceMake p size)
Keith Randall582baae2015-11-02 21:28:13 -08003027 subOp := s.ssaOp(OSUB, Types[TINT])
3028 neqOp := s.ssaOp(ONE, Types[TINT])
3029 mulOp := s.ssaOp(OMUL, Types[TINT])
3030 rlen := s.newValue2(subOp, Types[TINT], j, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003031 var rcap *ssa.Value
3032 switch {
3033 case t.IsString():
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003034 // Capacity of the result is unimportant. However, we use
Keith Randall5505e8c2015-09-12 23:27:26 -07003035 // rcap to test if we've generated a zero-length slice.
3036 // Use length of strings for that.
3037 rcap = rlen
3038 case j == k:
3039 rcap = rlen
3040 default:
Keith Randall582baae2015-11-02 21:28:13 -08003041 rcap = s.newValue2(subOp, Types[TINT], k, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07003042 }
3043
Keith Randallb32217a2015-09-17 16:45:10 -07003044 s.vars[&ptrVar] = ptr
Keith Randall5505e8c2015-09-12 23:27:26 -07003045
3046 // Generate code to test the resulting slice length.
Keith Randall582baae2015-11-02 21:28:13 -08003047 cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0))
Keith Randall5505e8c2015-09-12 23:27:26 -07003048
3049 b := s.endBlock()
3050 b.Kind = ssa.BlockIf
3051 b.Likely = ssa.BranchLikely
3052 b.Control = cmp
3053
3054 // Generate code for non-zero length slice case.
3055 nz := s.f.NewBlock(ssa.BlockPlain)
3056 b.AddEdgeTo(nz)
3057 s.startBlock(nz)
3058 var inc *ssa.Value
3059 if elemtype.Width == 1 {
3060 inc = i
3061 } else {
Keith Randall582baae2015-11-02 21:28:13 -08003062 inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
Keith Randall5505e8c2015-09-12 23:27:26 -07003063 }
Keith Randallb32217a2015-09-17 16:45:10 -07003064 s.vars[&ptrVar] = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, inc)
Keith Randall5505e8c2015-09-12 23:27:26 -07003065 s.endBlock()
3066
3067 // All done.
3068 merge := s.f.NewBlock(ssa.BlockPlain)
3069 b.AddEdgeTo(merge)
3070 nz.AddEdgeTo(merge)
3071 s.startBlock(merge)
Keith Randallb32217a2015-09-17 16:45:10 -07003072 rptr := s.variable(&ptrVar, ptrtype)
3073 delete(s.vars, &ptrVar)
Keith Randall5505e8c2015-09-12 23:27:26 -07003074 return rptr, rlen, rcap
3075}
3076
David Chase42825882015-08-20 15:14:20 -04003077type u2fcvtTab struct {
3078 geq, cvt2F, and, rsh, or, add ssa.Op
3079 one func(*state, ssa.Type, int64) *ssa.Value
3080}
3081
3082var u64_f64 u2fcvtTab = u2fcvtTab{
3083 geq: ssa.OpGeq64,
3084 cvt2F: ssa.OpCvt64to64F,
3085 and: ssa.OpAnd64,
3086 rsh: ssa.OpRsh64Ux64,
3087 or: ssa.OpOr64,
3088 add: ssa.OpAdd64F,
3089 one: (*state).constInt64,
3090}
3091
3092var u64_f32 u2fcvtTab = u2fcvtTab{
3093 geq: ssa.OpGeq64,
3094 cvt2F: ssa.OpCvt64to32F,
3095 and: ssa.OpAnd64,
3096 rsh: ssa.OpRsh64Ux64,
3097 or: ssa.OpOr64,
3098 add: ssa.OpAdd32F,
3099 one: (*state).constInt64,
3100}
3101
3102// Excess generality on a machine with 64-bit integer registers.
3103// Not used on AMD64.
3104var u32_f32 u2fcvtTab = u2fcvtTab{
3105 geq: ssa.OpGeq32,
3106 cvt2F: ssa.OpCvt32to32F,
3107 and: ssa.OpAnd32,
3108 rsh: ssa.OpRsh32Ux32,
3109 or: ssa.OpOr32,
3110 add: ssa.OpAdd32F,
3111 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
3112 return s.constInt32(t, int32(x))
3113 },
3114}
3115
3116func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3117 return s.uintTofloat(&u64_f64, n, x, ft, tt)
3118}
3119
3120func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3121 return s.uintTofloat(&u64_f32, n, x, ft, tt)
3122}
3123
3124func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3125 // if x >= 0 {
3126 // result = (floatY) x
3127 // } else {
3128 // y = uintX(x) ; y = x & 1
3129 // z = uintX(x) ; z = z >> 1
3130 // z = z >> 1
3131 // z = z | y
David Chase73151062015-08-26 14:25:40 -04003132 // result = floatY(z)
3133 // result = result + result
David Chase42825882015-08-20 15:14:20 -04003134 // }
3135 //
3136 // Code borrowed from old code generator.
3137 // What's going on: large 64-bit "unsigned" looks like
3138 // negative number to hardware's integer-to-float
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003139 // conversion. However, because the mantissa is only
David Chase42825882015-08-20 15:14:20 -04003140 // 63 bits, we don't need the LSB, so instead we do an
3141 // unsigned right shift (divide by two), convert, and
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003142 // double. However, before we do that, we need to be
David Chase42825882015-08-20 15:14:20 -04003143 // sure that we do not lose a "1" if that made the
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003144 // difference in the resulting rounding. Therefore, we
3145 // preserve it, and OR (not ADD) it back in. The case
David Chase42825882015-08-20 15:14:20 -04003146 // that matters is when the eleven discarded bits are
3147 // equal to 10000000001; that rounds up, and the 1 cannot
3148 // be lost else it would round down if the LSB of the
3149 // candidate mantissa is 0.
3150 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
3151 b := s.endBlock()
3152 b.Kind = ssa.BlockIf
3153 b.Control = cmp
3154 b.Likely = ssa.BranchLikely
3155
3156 bThen := s.f.NewBlock(ssa.BlockPlain)
3157 bElse := s.f.NewBlock(ssa.BlockPlain)
3158 bAfter := s.f.NewBlock(ssa.BlockPlain)
3159
Todd Neal47d67992015-08-28 21:36:29 -05003160 b.AddEdgeTo(bThen)
David Chase42825882015-08-20 15:14:20 -04003161 s.startBlock(bThen)
3162 a0 := s.newValue1(cvttab.cvt2F, tt, x)
3163 s.vars[n] = a0
3164 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003165 bThen.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04003166
Todd Neal47d67992015-08-28 21:36:29 -05003167 b.AddEdgeTo(bElse)
David Chase42825882015-08-20 15:14:20 -04003168 s.startBlock(bElse)
3169 one := cvttab.one(s, ft, 1)
3170 y := s.newValue2(cvttab.and, ft, x, one)
3171 z := s.newValue2(cvttab.rsh, ft, x, one)
3172 z = s.newValue2(cvttab.or, ft, z, y)
3173 a := s.newValue1(cvttab.cvt2F, tt, z)
3174 a1 := s.newValue2(cvttab.add, tt, a, a)
3175 s.vars[n] = a1
3176 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003177 bElse.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04003178
3179 s.startBlock(bAfter)
3180 return s.variable(n, n.Type)
3181}
3182
Todd Neal707af252015-08-28 15:56:43 -05003183// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
3184func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
3185 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
3186 s.Fatalf("node must be a map or a channel")
3187 }
Todd Neale0e40682015-08-26 18:40:52 -05003188 // if n == nil {
3189 // return 0
3190 // } else {
Todd Neal707af252015-08-28 15:56:43 -05003191 // // len
Todd Neale0e40682015-08-26 18:40:52 -05003192 // return *((*int)n)
Todd Neal707af252015-08-28 15:56:43 -05003193 // // cap
3194 // return *(((*int)n)+1)
Todd Neale0e40682015-08-26 18:40:52 -05003195 // }
3196 lenType := n.Type
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08003197 nilValue := s.constNil(Types[TUINTPTR])
Todd Neal67ac8a32015-08-28 15:20:54 -05003198 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
Todd Neale0e40682015-08-26 18:40:52 -05003199 b := s.endBlock()
3200 b.Kind = ssa.BlockIf
3201 b.Control = cmp
3202 b.Likely = ssa.BranchUnlikely
3203
3204 bThen := s.f.NewBlock(ssa.BlockPlain)
3205 bElse := s.f.NewBlock(ssa.BlockPlain)
3206 bAfter := s.f.NewBlock(ssa.BlockPlain)
3207
Todd Neal707af252015-08-28 15:56:43 -05003208 // length/capacity of a nil map/chan is zero
Todd Neal47d67992015-08-28 21:36:29 -05003209 b.AddEdgeTo(bThen)
Todd Neale0e40682015-08-26 18:40:52 -05003210 s.startBlock(bThen)
3211 s.vars[n] = s.zeroVal(lenType)
3212 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003213 bThen.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05003214
Todd Neal47d67992015-08-28 21:36:29 -05003215 b.AddEdgeTo(bElse)
Todd Neale0e40682015-08-26 18:40:52 -05003216 s.startBlock(bElse)
Todd Neal707af252015-08-28 15:56:43 -05003217 if n.Op == OLEN {
3218 // length is stored in the first word for map/chan
3219 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
3220 } else if n.Op == OCAP {
3221 // capacity is stored in the second word for chan
3222 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
3223 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
3224 } else {
3225 s.Fatalf("op must be OLEN or OCAP")
3226 }
Todd Neale0e40682015-08-26 18:40:52 -05003227 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003228 bElse.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05003229
3230 s.startBlock(bAfter)
3231 return s.variable(n, lenType)
3232}
3233
David Chase73151062015-08-26 14:25:40 -04003234type f2uCvtTab struct {
3235 ltf, cvt2U, subf ssa.Op
3236 value func(*state, ssa.Type, float64) *ssa.Value
3237}
3238
3239var f32_u64 f2uCvtTab = f2uCvtTab{
3240 ltf: ssa.OpLess32F,
3241 cvt2U: ssa.OpCvt32Fto64,
3242 subf: ssa.OpSub32F,
3243 value: (*state).constFloat32,
3244}
3245
3246var f64_u64 f2uCvtTab = f2uCvtTab{
3247 ltf: ssa.OpLess64F,
3248 cvt2U: ssa.OpCvt64Fto64,
3249 subf: ssa.OpSub64F,
3250 value: (*state).constFloat64,
3251}
3252
3253func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3254 return s.floatToUint(&f32_u64, n, x, ft, tt)
3255}
3256func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3257 return s.floatToUint(&f64_u64, n, x, ft, tt)
3258}
3259
3260func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
3261 // if x < 9223372036854775808.0 {
3262 // result = uintY(x)
3263 // } else {
3264 // y = x - 9223372036854775808.0
3265 // z = uintY(y)
3266 // result = z | -9223372036854775808
3267 // }
3268 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
3269 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
3270 b := s.endBlock()
3271 b.Kind = ssa.BlockIf
3272 b.Control = cmp
3273 b.Likely = ssa.BranchLikely
3274
3275 bThen := s.f.NewBlock(ssa.BlockPlain)
3276 bElse := s.f.NewBlock(ssa.BlockPlain)
3277 bAfter := s.f.NewBlock(ssa.BlockPlain)
3278
Todd Neal47d67992015-08-28 21:36:29 -05003279 b.AddEdgeTo(bThen)
David Chase73151062015-08-26 14:25:40 -04003280 s.startBlock(bThen)
3281 a0 := s.newValue1(cvttab.cvt2U, tt, x)
3282 s.vars[n] = a0
3283 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003284 bThen.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04003285
Todd Neal47d67992015-08-28 21:36:29 -05003286 b.AddEdgeTo(bElse)
David Chase73151062015-08-26 14:25:40 -04003287 s.startBlock(bElse)
3288 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
3289 y = s.newValue1(cvttab.cvt2U, tt, y)
3290 z := s.constInt64(tt, -9223372036854775808)
3291 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
3292 s.vars[n] = a1
3293 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05003294 bElse.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04003295
3296 s.startBlock(bAfter)
3297 return s.variable(n, n.Type)
3298}
3299
Keith Randall269baa92015-09-17 10:31:16 -07003300// ifaceType returns the value for the word containing the type.
3301// n is the node for the interface expression.
3302// v is the corresponding value.
3303func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
3304 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
3305
3306 if isnilinter(n.Type) {
3307 // Have *eface. The type is the first word in the struct.
3308 return s.newValue1(ssa.OpITab, byteptr, v)
3309 }
3310
3311 // Have *iface.
3312 // The first word in the struct is the *itab.
3313 // If the *itab is nil, return 0.
3314 // Otherwise, the second word in the *itab is the type.
3315
3316 tab := s.newValue1(ssa.OpITab, byteptr, v)
3317 s.vars[&typVar] = tab
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08003318 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.constNil(byteptr))
Keith Randall269baa92015-09-17 10:31:16 -07003319 b := s.endBlock()
3320 b.Kind = ssa.BlockIf
3321 b.Control = isnonnil
3322 b.Likely = ssa.BranchLikely
3323
3324 bLoad := s.f.NewBlock(ssa.BlockPlain)
3325 bEnd := s.f.NewBlock(ssa.BlockPlain)
3326
3327 b.AddEdgeTo(bLoad)
3328 b.AddEdgeTo(bEnd)
3329 bLoad.AddEdgeTo(bEnd)
3330
3331 s.startBlock(bLoad)
3332 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3333 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3334 s.endBlock()
3335
3336 s.startBlock(bEnd)
3337 typ := s.variable(&typVar, byteptr)
3338 delete(s.vars, &typVar)
3339 return typ
3340}
3341
3342// dottype generates SSA for a type assertion node.
3343// commaok indicates whether to panic or return a bool.
3344// If commaok is false, resok will be nil.
3345func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3346 iface := s.expr(n.Left)
3347 typ := s.ifaceType(n.Left, iface) // actual concrete type
3348 target := s.expr(typename(n.Type)) // target type
3349 if !isdirectiface(n.Type) {
3350 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3351 Fatalf("dottype needs a direct iface type %s", n.Type)
3352 }
3353
David Chase729abfa2015-10-26 17:34:06 -04003354 if Debug_typeassert > 0 {
Robert Griesemerb83f3972016-03-02 11:01:25 -08003355 Warnl(n.Lineno, "type assertion inlined")
David Chase729abfa2015-10-26 17:34:06 -04003356 }
3357
Keith Randall269baa92015-09-17 10:31:16 -07003358 // TODO: If we have a nonempty interface and its itab field is nil,
3359 // then this test is redundant and ifaceType should just branch directly to bFail.
3360 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3361 b := s.endBlock()
3362 b.Kind = ssa.BlockIf
3363 b.Control = cond
3364 b.Likely = ssa.BranchLikely
3365
3366 byteptr := Ptrto(Types[TUINT8])
3367
3368 bOk := s.f.NewBlock(ssa.BlockPlain)
3369 bFail := s.f.NewBlock(ssa.BlockPlain)
3370 b.AddEdgeTo(bOk)
3371 b.AddEdgeTo(bFail)
3372
3373 if !commaok {
3374 // on failure, panic by calling panicdottype
3375 s.startBlock(bFail)
Keith Randall269baa92015-09-17 10:31:16 -07003376 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{byteptr, typenamesym(n.Left.Type)}, s.sb)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07003377 s.rtcall(panicdottype, false, nil, typ, target, taddr)
Keith Randall269baa92015-09-17 10:31:16 -07003378
3379 // on success, return idata field
3380 s.startBlock(bOk)
3381 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3382 }
3383
3384 // commaok is the more complicated case because we have
3385 // a control flow merge point.
3386 bEnd := s.f.NewBlock(ssa.BlockPlain)
3387
3388 // type assertion succeeded
3389 s.startBlock(bOk)
3390 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3391 s.vars[&okVar] = s.constBool(true)
3392 s.endBlock()
3393 bOk.AddEdgeTo(bEnd)
3394
3395 // type assertion failed
3396 s.startBlock(bFail)
Josh Bleecher Snyder39214272016-03-06 18:06:09 -08003397 s.vars[&idataVar] = s.constNil(byteptr)
Keith Randall269baa92015-09-17 10:31:16 -07003398 s.vars[&okVar] = s.constBool(false)
3399 s.endBlock()
3400 bFail.AddEdgeTo(bEnd)
3401
3402 // merge point
3403 s.startBlock(bEnd)
3404 res = s.variable(&idataVar, byteptr)
3405 resok = s.variable(&okVar, Types[TBOOL])
3406 delete(s.vars, &idataVar)
3407 delete(s.vars, &okVar)
3408 return res, resok
3409}
3410
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003411// checkgoto checks that a goto from from to to does not
3412// jump into a block or jump over variable declarations.
3413// It is a copy of checkgoto in the pre-SSA backend,
3414// modified only for line number handling.
3415// TODO: document how this works and why it is designed the way it is.
3416func (s *state) checkgoto(from *Node, to *Node) {
3417 if from.Sym == to.Sym {
3418 return
3419 }
3420
3421 nf := 0
3422 for fs := from.Sym; fs != nil; fs = fs.Link {
3423 nf++
3424 }
3425 nt := 0
3426 for fs := to.Sym; fs != nil; fs = fs.Link {
3427 nt++
3428 }
3429 fs := from.Sym
3430 for ; nf > nt; nf-- {
3431 fs = fs.Link
3432 }
3433 if fs != to.Sym {
3434 // decide what to complain about.
3435 // prefer to complain about 'into block' over declarations,
3436 // so scan backward to find most recent block or else dcl.
3437 var block *Sym
3438
3439 var dcl *Sym
3440 ts := to.Sym
3441 for ; nt > nf; nt-- {
3442 if ts.Pkg == nil {
3443 block = ts
3444 } else {
3445 dcl = ts
3446 }
3447 ts = ts.Link
3448 }
3449
3450 for ts != fs {
3451 if ts.Pkg == nil {
3452 block = ts
3453 } else {
3454 dcl = ts
3455 }
3456 ts = ts.Link
3457 fs = fs.Link
3458 }
3459
Robert Griesemerb83f3972016-03-02 11:01:25 -08003460 lno := from.Left.Lineno
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003461 if block != nil {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08003462 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, linestr(block.Lastlineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003463 } else {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08003464 yyerrorl(lno, "goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, linestr(dcl.Lastlineno))
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003465 }
3466 }
3467}
3468
Keith Randalld2fd43a2015-04-15 15:51:25 -07003469// variable returns the value of a variable at the current location.
Keith Randall8c46aa52015-06-19 21:02:28 -07003470func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003471 v := s.vars[name]
3472 if v == nil {
Keith Randall8f22b522015-06-11 21:29:25 -07003473 v = s.newValue0A(ssa.OpFwdRef, t, name)
Keith Randallb5c5efd2016-01-14 16:02:23 -08003474 s.fwdRefs = append(s.fwdRefs, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003475 s.vars[name] = v
Keith Randallb5c5efd2016-01-14 16:02:23 -08003476 s.addNamedValue(name, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003477 }
3478 return v
3479}
3480
Keith Randallcfc2aa52015-05-18 16:44:20 -07003481func (s *state) mem() *ssa.Value {
Keith Randallb32217a2015-09-17 16:45:10 -07003482 return s.variable(&memVar, ssa.TypeMem)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003483}
3484
Keith Randallcfc2aa52015-05-18 16:44:20 -07003485func (s *state) linkForwardReferences() {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003486 // Build SSA graph. Each variable on its first use in a basic block
Keith Randalld2fd43a2015-04-15 15:51:25 -07003487 // leaves a FwdRef in that block representing the incoming value
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003488 // of that variable. This function links that ref up with possible definitions,
3489 // inserting Phi values as needed. This is essentially the algorithm
Keith Randallb5c5efd2016-01-14 16:02:23 -08003490 // described by Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
Keith Randalld2fd43a2015-04-15 15:51:25 -07003491 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
Keith Randallb5c5efd2016-01-14 16:02:23 -08003492 // Differences:
3493 // - We use FwdRef nodes to postpone phi building until the CFG is
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003494 // completely built. That way we can avoid the notion of "sealed"
Keith Randallb5c5efd2016-01-14 16:02:23 -08003495 // blocks.
3496 // - Phi optimization is a separate pass (in ../ssa/phielim.go).
3497 for len(s.fwdRefs) > 0 {
3498 v := s.fwdRefs[len(s.fwdRefs)-1]
3499 s.fwdRefs = s.fwdRefs[:len(s.fwdRefs)-1]
3500 s.resolveFwdRef(v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003501 }
3502}
3503
Keith Randallb5c5efd2016-01-14 16:02:23 -08003504// resolveFwdRef modifies v to be the variable's value at the start of its block.
3505// v must be a FwdRef op.
3506func (s *state) resolveFwdRef(v *ssa.Value) {
3507 b := v.Block
3508 name := v.Aux.(*Node)
3509 v.Aux = nil
Keith Randalld2fd43a2015-04-15 15:51:25 -07003510 if b == s.f.Entry {
Keith Randallb5c5efd2016-01-14 16:02:23 -08003511 // Live variable at start of function.
Keith Randall6a8a9da2016-02-27 17:49:31 -08003512 if s.canSSA(name) {
Keith Randallb5c5efd2016-01-14 16:02:23 -08003513 v.Op = ssa.OpArg
3514 v.Aux = name
3515 return
Keith Randall02f4d0a2015-11-02 08:10:26 -08003516 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003517 // Not SSAable. Load it.
Keith Randall8c46aa52015-06-19 21:02:28 -07003518 addr := s.decladdrs[name]
3519 if addr == nil {
3520 // TODO: closure args reach here.
David Chase32ffbf72015-10-08 17:14:12 -04003521 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
Keith Randall8c46aa52015-06-19 21:02:28 -07003522 }
3523 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3524 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3525 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003526 v.Op = ssa.OpLoad
3527 v.AddArgs(addr, s.startmem)
3528 return
Keith Randalld2fd43a2015-04-15 15:51:25 -07003529 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003530 if len(b.Preds) == 0 {
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003531 // This block is dead; we have no predecessors and we're not the entry block.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003532 // It doesn't matter what we use here as long as it is well-formed.
3533 v.Op = ssa.OpUnknown
3534 return
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07003535 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003536 // Find variable value on each predecessor.
3537 var argstore [4]*ssa.Value
3538 args := argstore[:0]
3539 for _, p := range b.Preds {
3540 args = append(args, s.lookupVarOutgoing(p, v.Type, name, v.Line))
Keith Randalld2fd43a2015-04-15 15:51:25 -07003541 }
Keith Randallb5c5efd2016-01-14 16:02:23 -08003542
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003543 // Decide if we need a phi or not. We need a phi if there
Keith Randallb5c5efd2016-01-14 16:02:23 -08003544 // are two different args (which are both not v).
3545 var w *ssa.Value
3546 for _, a := range args {
3547 if a == v {
3548 continue // self-reference
3549 }
3550 if a == w {
3551 continue // already have this witness
3552 }
3553 if w != nil {
3554 // two witnesses, need a phi value
3555 v.Op = ssa.OpPhi
3556 v.AddArgs(args...)
3557 return
3558 }
3559 w = a // save witness
3560 }
3561 if w == nil {
3562 s.Fatalf("no witness for reachable phi %s", v)
3563 }
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003564 // One witness. Make v a copy of w.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003565 v.Op = ssa.OpCopy
3566 v.AddArg(w)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003567}
3568
3569// lookupVarOutgoing finds the variable's value at the end of block b.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003570func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node, line int32) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003571 m := s.defvars[b.ID]
3572 if v, ok := m[name]; ok {
3573 return v
3574 }
3575 // The variable is not defined by b and we haven't
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003576 // looked it up yet. Generate a FwdRef for the variable and return that.
Keith Randallb5c5efd2016-01-14 16:02:23 -08003577 v := b.NewValue0A(line, ssa.OpFwdRef, t, name)
3578 s.fwdRefs = append(s.fwdRefs, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003579 m[name] = v
Keith Randallb5c5efd2016-01-14 16:02:23 -08003580 s.addNamedValue(name, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003581 return v
3582}
3583
Keith Randallc24681a2015-10-22 14:22:38 -07003584func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3585 if n.Class == Pxxx {
3586 // Don't track our dummy nodes (&memVar etc.).
3587 return
3588 }
Keith Randallc24681a2015-10-22 14:22:38 -07003589 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3590 // Don't track autotmp_ variables.
3591 return
3592 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003593 if n.Class == PAUTO && (v.Type.IsString() || v.Type.IsSlice() || v.Type.IsInterface()) {
3594 // TODO: can't handle auto compound objects with pointers yet.
3595 // The live variable analysis barfs because we don't put VARDEF
3596 // pseudos in the right place when we spill to these nodes.
Keith Randallc24681a2015-10-22 14:22:38 -07003597 return
3598 }
Keith Randall31d13f42016-03-08 20:09:48 -08003599 if n.Class == PPARAMOUT {
3600 // Don't track named output values. This prevents return values
3601 // from being assigned too early. See #14591 and #14762. TODO: allow this.
3602 return
3603 }
Keith Randallc24681a2015-10-22 14:22:38 -07003604 if n.Class == PAUTO && n.Xoffset != 0 {
3605 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3606 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003607 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3608 values, ok := s.f.NamedValues[loc]
Keith Randallc24681a2015-10-22 14:22:38 -07003609 if !ok {
Keith Randall02f4d0a2015-11-02 08:10:26 -08003610 s.f.Names = append(s.f.Names, loc)
Keith Randallc24681a2015-10-22 14:22:38 -07003611 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003612 s.f.NamedValues[loc] = append(values, v)
Keith Randallc24681a2015-10-22 14:22:38 -07003613}
3614
Michael Pratta4e31d42016-03-12 14:07:40 -08003615// Branch is an unresolved branch.
3616type Branch struct {
3617 P *obj.Prog // branch instruction
3618 B *ssa.Block // target
Keith Randall083a6462015-05-12 11:06:44 -07003619}
3620
Michael Pratta4e31d42016-03-12 14:07:40 -08003621// SSAGenState contains state needed during Prog generation.
3622type SSAGenState struct {
3623 // Branches remembers all the branch instructions we've seen
Keith Randall9569b952015-08-28 22:51:01 -07003624 // and where they would like to go.
Michael Pratta4e31d42016-03-12 14:07:40 -08003625 Branches []Branch
Keith Randall9569b952015-08-28 22:51:01 -07003626
3627 // bstart remembers where each block starts (indexed by block ID)
3628 bstart []*obj.Prog
Keith Randall9569b952015-08-28 22:51:01 -07003629}
3630
Michael Pratta4e31d42016-03-12 14:07:40 -08003631// Pc returns the current Prog.
3632func (s *SSAGenState) Pc() *obj.Prog {
3633 return Pc
3634}
3635
3636// SetLineno sets the current source line number.
3637func (s *SSAGenState) SetLineno(l int32) {
3638 lineno = l
3639}
3640
Keith Randall083a6462015-05-12 11:06:44 -07003641// genssa appends entries to ptxt for each instruction in f.
3642// gcargs and gclocals are filled in with pointer maps for the frame.
3643func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
Michael Pratta4e31d42016-03-12 14:07:40 -08003644 var s SSAGenState
Keith Randall9569b952015-08-28 22:51:01 -07003645
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07003646 e := f.Config.Frontend().(*ssaExport)
3647 // We're about to emit a bunch of Progs.
3648 // Since the only way to get here is to explicitly request it,
3649 // just fail on unimplemented instead of trying to unwind our mess.
3650 e.mustImplement = true
3651
Keith Randall083a6462015-05-12 11:06:44 -07003652 // Remember where each block starts.
Keith Randall9569b952015-08-28 22:51:01 -07003653 s.bstart = make([]*obj.Prog, f.NumBlocks())
Keith Randall083a6462015-05-12 11:06:44 -07003654
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003655 var valueProgs map[*obj.Prog]*ssa.Value
3656 var blockProgs map[*obj.Prog]*ssa.Block
Dave Cheneycb1f2af2016-03-17 13:46:43 +11003657 var logProgs = e.log
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003658 if logProgs {
3659 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3660 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3661 f.Logf("genssa %s\n", f.Name)
3662 blockProgs[Pc] = f.Blocks[0]
3663 }
3664
Keith Randall083a6462015-05-12 11:06:44 -07003665 // Emit basic blocks
3666 for i, b := range f.Blocks {
Keith Randall9569b952015-08-28 22:51:01 -07003667 s.bstart[b.ID] = Pc
Keith Randall083a6462015-05-12 11:06:44 -07003668 // Emit values in block
Michael Pratta4e31d42016-03-12 14:07:40 -08003669 Thearch.SSAMarkMoves(&s, b)
Keith Randall083a6462015-05-12 11:06:44 -07003670 for _, v := range b.Values {
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003671 x := Pc
Michael Pratta4e31d42016-03-12 14:07:40 -08003672 Thearch.SSAGenValue(&s, v)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003673 if logProgs {
3674 for ; x != Pc; x = x.Link {
3675 valueProgs[x] = v
3676 }
3677 }
Keith Randall083a6462015-05-12 11:06:44 -07003678 }
3679 // Emit control flow instructions for block
3680 var next *ssa.Block
Keith Randall91f69c62016-02-26 16:32:01 -08003681 if i < len(f.Blocks)-1 && (Debug['N'] == 0 || b.Kind == ssa.BlockCall) {
Keith Randall8906d2a2016-02-22 23:19:00 -08003682 // If -N, leave next==nil so every block with successors
Keith Randall91f69c62016-02-26 16:32:01 -08003683 // ends in a JMP (except call blocks - plive doesn't like
3684 // select{send,recv} followed by a JMP call). Helps keep
3685 // line numbers for otherwise empty blocks.
Keith Randall083a6462015-05-12 11:06:44 -07003686 next = f.Blocks[i+1]
3687 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003688 x := Pc
Michael Pratta4e31d42016-03-12 14:07:40 -08003689 Thearch.SSAGenBlock(&s, b, next)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003690 if logProgs {
3691 for ; x != Pc; x = x.Link {
3692 blockProgs[x] = b
3693 }
3694 }
Keith Randall083a6462015-05-12 11:06:44 -07003695 }
3696
3697 // Resolve branches
Michael Pratta4e31d42016-03-12 14:07:40 -08003698 for _, br := range s.Branches {
3699 br.P.To.Val = s.bstart[br.B.ID]
Keith Randall9569b952015-08-28 22:51:01 -07003700 }
Keith Randall083a6462015-05-12 11:06:44 -07003701
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003702 if logProgs {
3703 for p := ptxt; p != nil; p = p.Link {
3704 var s string
3705 if v, ok := valueProgs[p]; ok {
3706 s = v.String()
3707 } else if b, ok := blockProgs[p]; ok {
3708 s = b.String()
3709 } else {
3710 s = " " // most value and branch strings are 2-3 characters long
3711 }
3712 f.Logf("%s\t%s\n", s, p)
3713 }
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07003714 if f.Config.HTML != nil {
3715 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3716 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3717 var buf bytes.Buffer
3718 buf.WriteString("<code>")
3719 buf.WriteString("<dl class=\"ssa-gen\">")
3720 for p := ptxt; p != nil; p = p.Link {
3721 buf.WriteString("<dt class=\"ssa-prog-src\">")
3722 if v, ok := valueProgs[p]; ok {
3723 buf.WriteString(v.HTML())
3724 } else if b, ok := blockProgs[p]; ok {
3725 buf.WriteString(b.HTML())
3726 }
3727 buf.WriteString("</dt>")
3728 buf.WriteString("<dd class=\"ssa-prog\">")
3729 buf.WriteString(html.EscapeString(p.String()))
3730 buf.WriteString("</dd>")
3731 buf.WriteString("</li>")
3732 }
3733 buf.WriteString("</dl>")
3734 buf.WriteString("</code>")
3735 f.Config.HTML.WriteColumn("genssa", buf.String())
3736 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
3737 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003738 }
3739
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07003740 // Emit static data
3741 if f.StaticData != nil {
3742 for _, n := range f.StaticData.([]*Node) {
3743 if !gen_as_init(n, false) {
Keith Randall0ec72b62015-09-08 15:42:53 -07003744 Fatalf("non-static data marked as static: %v\n\n", n, f)
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07003745 }
3746 }
3747 }
3748
Keith Randalld2107fc2015-08-24 02:16:19 -07003749 // Allocate stack frame
3750 allocauto(ptxt)
Keith Randall083a6462015-05-12 11:06:44 -07003751
Keith Randalld2107fc2015-08-24 02:16:19 -07003752 // Generate gc bitmaps.
3753 liveness(Curfn, ptxt, gcargs, gclocals)
3754 gcsymdup(gcargs)
3755 gcsymdup(gclocals)
Keith Randall083a6462015-05-12 11:06:44 -07003756
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003757 // Add frame prologue. Zero ambiguously live variables.
Keith Randalld2107fc2015-08-24 02:16:19 -07003758 Thearch.Defframe(ptxt)
3759 if Debug['f'] != 0 {
3760 frame(0)
3761 }
3762
3763 // Remove leftover instrumentation from the instruction stream.
3764 removevardef(ptxt)
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07003765
3766 f.Config.HTML.Close()
Keith Randall083a6462015-05-12 11:06:44 -07003767}
3768
Daniel Morsing66b47812015-06-27 15:45:20 +01003769// movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
Matthew Dempsky0d9258a2016-03-07 18:00:08 -08003770func movZero(as obj.As, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
Daniel Morsing66b47812015-06-27 15:45:20 +01003771 p := Prog(as)
3772 // TODO: use zero register on archs that support it.
3773 p.From.Type = obj.TYPE_CONST
3774 p.From.Offset = 0
3775 p.To.Type = obj.TYPE_MEM
3776 p.To.Reg = regnum
3777 p.To.Offset = offset
3778 offset += width
3779 nleft = nbytes - width
3780 return nleft, offset
3781}
3782
Michael Pratta4e31d42016-03-12 14:07:40 -08003783type FloatingEQNEJump struct {
3784 Jump obj.As
3785 Index int
David Chase8e601b22015-08-18 14:39:26 -04003786}
3787
Michael Pratta4e31d42016-03-12 14:07:40 -08003788func oneFPJump(b *ssa.Block, jumps *FloatingEQNEJump, likely ssa.BranchPrediction, branches []Branch) []Branch {
3789 p := Prog(jumps.Jump)
David Chase8e601b22015-08-18 14:39:26 -04003790 p.To.Type = obj.TYPE_BRANCH
Michael Pratta4e31d42016-03-12 14:07:40 -08003791 to := jumps.Index
3792 branches = append(branches, Branch{p, b.Succs[to]})
David Chase8e601b22015-08-18 14:39:26 -04003793 if to == 1 {
3794 likely = -likely
3795 }
3796 // liblink reorders the instruction stream as it sees fit.
3797 // Pass along what we know so liblink can make use of it.
3798 // TODO: Once we've fully switched to SSA,
3799 // make liblink leave our output alone.
3800 switch likely {
3801 case ssa.BranchUnlikely:
3802 p.From.Type = obj.TYPE_CONST
3803 p.From.Offset = 0
3804 case ssa.BranchLikely:
3805 p.From.Type = obj.TYPE_CONST
3806 p.From.Offset = 1
3807 }
3808 return branches
3809}
3810
Michael Pratta4e31d42016-03-12 14:07:40 -08003811func SSAGenFPJump(s *SSAGenState, b, next *ssa.Block, jumps *[2][2]FloatingEQNEJump) {
David Chase8e601b22015-08-18 14:39:26 -04003812 likely := b.Likely
3813 switch next {
3814 case b.Succs[0]:
Michael Pratta4e31d42016-03-12 14:07:40 -08003815 s.Branches = oneFPJump(b, &jumps[0][0], likely, s.Branches)
3816 s.Branches = oneFPJump(b, &jumps[0][1], likely, s.Branches)
David Chase8e601b22015-08-18 14:39:26 -04003817 case b.Succs[1]:
Michael Pratta4e31d42016-03-12 14:07:40 -08003818 s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
3819 s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
David Chase8e601b22015-08-18 14:39:26 -04003820 default:
Michael Pratta4e31d42016-03-12 14:07:40 -08003821 s.Branches = oneFPJump(b, &jumps[1][0], likely, s.Branches)
3822 s.Branches = oneFPJump(b, &jumps[1][1], likely, s.Branches)
David Chase8e601b22015-08-18 14:39:26 -04003823 q := Prog(obj.AJMP)
3824 q.To.Type = obj.TYPE_BRANCH
Michael Pratta4e31d42016-03-12 14:07:40 -08003825 s.Branches = append(s.Branches, Branch{q, b.Succs[1]})
David Chase8e601b22015-08-18 14:39:26 -04003826 }
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07003827}
3828
Michael Pratta4e31d42016-03-12 14:07:40 -08003829// AddAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
3830func AddAux(a *obj.Addr, v *ssa.Value) {
3831 AddAux2(a, v, v.AuxInt)
Keith Randall083a6462015-05-12 11:06:44 -07003832}
Michael Pratta4e31d42016-03-12 14:07:40 -08003833func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
Keith Randall8c46aa52015-06-19 21:02:28 -07003834 if a.Type != obj.TYPE_MEM {
Michael Pratta4e31d42016-03-12 14:07:40 -08003835 v.Fatalf("bad AddAux addr %s", a)
Keith Randall8c46aa52015-06-19 21:02:28 -07003836 }
3837 // add integer offset
Keith Randalld43f2e32015-10-21 13:13:56 -07003838 a.Offset += offset
Keith Randall8c46aa52015-06-19 21:02:28 -07003839
3840 // If no additional symbol offset, we're done.
3841 if v.Aux == nil {
3842 return
3843 }
3844 // Add symbol's offset from its base register.
3845 switch sym := v.Aux.(type) {
3846 case *ssa.ExternSymbol:
3847 a.Name = obj.NAME_EXTERN
3848 a.Sym = Linksym(sym.Sym.(*Sym))
3849 case *ssa.ArgSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07003850 n := sym.Node.(*Node)
3851 a.Name = obj.NAME_PARAM
3852 a.Node = n
3853 a.Sym = Linksym(n.Orig.Sym)
3854 a.Offset += n.Xoffset // TODO: why do I have to add this here? I don't for auto variables.
Keith Randall8c46aa52015-06-19 21:02:28 -07003855 case *ssa.AutoSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07003856 n := sym.Node.(*Node)
3857 a.Name = obj.NAME_AUTO
3858 a.Node = n
3859 a.Sym = Linksym(n.Sym)
Keith Randall8c46aa52015-06-19 21:02:28 -07003860 default:
3861 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
3862 }
3863}
3864
Keith Randall582baae2015-11-02 21:28:13 -08003865// extendIndex extends v to a full int width.
Keith Randall2a5e6c42015-07-23 14:35:02 -07003866func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
3867 size := v.Type.Size()
Keith Randall582baae2015-11-02 21:28:13 -08003868 if size == s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07003869 return v
3870 }
Keith Randall582baae2015-11-02 21:28:13 -08003871 if size > s.config.IntSize {
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003872 // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
Keith Randall2a5e6c42015-07-23 14:35:02 -07003873 // the high word and branch to out-of-bounds failure if it is not 0.
3874 s.Unimplementedf("64->32 index truncation not implemented")
3875 return v
3876 }
3877
3878 // Extend value to the required size
3879 var op ssa.Op
3880 if v.Type.IsSigned() {
Keith Randall582baae2015-11-02 21:28:13 -08003881 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07003882 case 14:
3883 op = ssa.OpSignExt8to32
3884 case 18:
3885 op = ssa.OpSignExt8to64
3886 case 24:
3887 op = ssa.OpSignExt16to32
3888 case 28:
3889 op = ssa.OpSignExt16to64
3890 case 48:
3891 op = ssa.OpSignExt32to64
3892 default:
3893 s.Fatalf("bad signed index extension %s", v.Type)
3894 }
3895 } else {
Keith Randall582baae2015-11-02 21:28:13 -08003896 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07003897 case 14:
3898 op = ssa.OpZeroExt8to32
3899 case 18:
3900 op = ssa.OpZeroExt8to64
3901 case 24:
3902 op = ssa.OpZeroExt16to32
3903 case 28:
3904 op = ssa.OpZeroExt16to64
3905 case 48:
3906 op = ssa.OpZeroExt32to64
3907 default:
3908 s.Fatalf("bad unsigned index extension %s", v.Type)
3909 }
3910 }
Keith Randall582baae2015-11-02 21:28:13 -08003911 return s.newValue1(op, Types[TINT], v)
Keith Randall2a5e6c42015-07-23 14:35:02 -07003912}
3913
Michael Pratta4e31d42016-03-12 14:07:40 -08003914// SSARegNum returns the register (in cmd/internal/obj numbering) to
Brad Fitzpatrick5fea2cc2016-03-01 23:21:55 +00003915// which v has been allocated. Panics if v is not assigned to a
Keith Randall083a6462015-05-12 11:06:44 -07003916// register.
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07003917// TODO: Make this panic again once it stops happening routinely.
Michael Pratta4e31d42016-03-12 14:07:40 -08003918func SSARegNum(v *ssa.Value) int16 {
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07003919 reg := v.Block.Func.RegAlloc[v.ID]
3920 if reg == nil {
3921 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
3922 return 0
3923 }
Michael Pratta4e31d42016-03-12 14:07:40 -08003924 return Thearch.SSARegToReg[reg.(*ssa.Register).Num]
Keith Randall083a6462015-05-12 11:06:44 -07003925}
3926
Michael Pratta4e31d42016-03-12 14:07:40 -08003927// AutoVar returns a *Node and int64 representing the auto variable and offset within it
Keith Randall02f4d0a2015-11-02 08:10:26 -08003928// where v should be spilled.
Michael Pratta4e31d42016-03-12 14:07:40 -08003929func AutoVar(v *ssa.Value) (*Node, int64) {
Keith Randall02f4d0a2015-11-02 08:10:26 -08003930 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
Keith Randall9094e3a2016-01-04 13:34:54 -08003931 if v.Type.Size() > loc.Type.Size() {
3932 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
3933 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003934 return loc.N.(*Node), loc.Off
Keith Randall083a6462015-05-12 11:06:44 -07003935}
Keith Randallf7f604e2015-05-27 14:52:22 -07003936
Keith Randalla734bbc2016-01-11 21:05:33 -08003937// fieldIdx finds the index of the field referred to by the ODOT node n.
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003938func fieldIdx(n *Node) int {
Keith Randalla734bbc2016-01-11 21:05:33 -08003939 t := n.Left.Type
3940 f := n.Right
3941 if t.Etype != TSTRUCT {
3942 panic("ODOT's LHS is not a struct")
3943 }
3944
Matthew Dempsky1b9f1682016-03-14 12:45:18 -07003945 var i int
Matthew Dempskyfe5b4a62016-03-10 01:50:58 -08003946 for t1, it := IterFields(t); t1 != nil; t1 = it.Next() {
Keith Randalla734bbc2016-01-11 21:05:33 -08003947 if t1.Sym != f.Sym {
3948 i++
3949 continue
3950 }
3951 if t1.Width != n.Xoffset {
3952 panic("field offset doesn't match")
3953 }
3954 return i
3955 }
3956 panic(fmt.Sprintf("can't find field in expr %s\n", n))
3957
3958 // TODO: keep the result of this fucntion somewhere in the ODOT Node
3959 // so we don't have to recompute it each time we need it.
3960}
3961
Keith Randallf7f604e2015-05-27 14:52:22 -07003962// ssaExport exports a bunch of compiler services for the ssa backend.
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07003963type ssaExport struct {
3964 log bool
3965 unimplemented bool
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07003966 mustImplement bool
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07003967}
Keith Randallf7f604e2015-05-27 14:52:22 -07003968
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07003969func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
3970func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
3971func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
3972func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
3973func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
3974func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
3975func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
3976func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
3977func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
David Chase52578582015-08-28 14:24:10 -04003978func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
3979func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07003980func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
3981func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
3982func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
3983func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
3984
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07003985// StringData returns a symbol (a *Sym wrapped in an interface) which
3986// is the data component of a global string constant containing s.
3987func (*ssaExport) StringData(s string) interface{} {
Keith Randall8c46aa52015-06-19 21:02:28 -07003988 // TODO: is idealstring correct? It might not matter...
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07003989 _, data := stringsym(s)
3990 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
Keith Randallf7f604e2015-05-27 14:52:22 -07003991}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07003992
Keith Randallc24681a2015-10-22 14:22:38 -07003993func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
Keith Randalld2107fc2015-08-24 02:16:19 -07003994 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
3995 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
3996 return n
3997}
3998
Keith Randall7d612462015-10-22 13:07:38 -07003999func (e *ssaExport) CanSSA(t ssa.Type) bool {
Keith Randall37590bd2015-09-18 22:58:10 -07004000 return canSSAType(t.(*Type))
4001}
4002
Keith Randallb5c5efd2016-01-14 16:02:23 -08004003func (e *ssaExport) Line(line int32) string {
Robert Griesemer2faf5bc2016-03-02 11:30:29 -08004004 return linestr(line)
Keith Randallb5c5efd2016-01-14 16:02:23 -08004005}
4006
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004007// Log logs a message from the compiler.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07004008func (e *ssaExport) Logf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004009 // If e was marked as unimplemented, anything could happen. Ignore.
4010 if e.log && !e.unimplemented {
4011 fmt.Printf(msg, args...)
4012 }
4013}
4014
David Chase88b230e2016-01-29 14:44:15 -05004015func (e *ssaExport) Log() bool {
4016 return e.log
4017}
4018
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004019// Fatal reports a compiler error and exits.
Keith Randallda8af472016-01-13 11:14:57 -08004020func (e *ssaExport) Fatalf(line int32, msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004021 // If e was marked as unimplemented, anything could happen. Ignore.
4022 if !e.unimplemented {
Keith Randallda8af472016-01-13 11:14:57 -08004023 lineno = line
Keith Randall0ec72b62015-09-08 15:42:53 -07004024 Fatalf(msg, args...)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004025 }
4026}
4027
4028// Unimplemented reports that the function cannot be compiled.
4029// It will be removed once SSA work is complete.
Keith Randallda8af472016-01-13 11:14:57 -08004030func (e *ssaExport) Unimplementedf(line int32, msg string, args ...interface{}) {
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004031 if e.mustImplement {
Keith Randallda8af472016-01-13 11:14:57 -08004032 lineno = line
Keith Randall0ec72b62015-09-08 15:42:53 -07004033 Fatalf(msg, args...)
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004034 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004035 const alwaysLog = false // enable to calculate top unimplemented features
4036 if !e.unimplemented && (e.log || alwaysLog) {
4037 // first implementation failure, print explanation
4038 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
4039 }
4040 e.unimplemented = true
4041}
Keith Randallc24681a2015-10-22 14:22:38 -07004042
David Chase729abfa2015-10-26 17:34:06 -04004043// Warnl reports a "warning", which is usually flag-triggered
4044// logging output for the benefit of tests.
Todd Neal98b88de2016-03-13 23:04:31 -05004045func (e *ssaExport) Warnl(line int32, fmt_ string, args ...interface{}) {
4046 Warnl(line, fmt_, args...)
David Chase729abfa2015-10-26 17:34:06 -04004047}
4048
4049func (e *ssaExport) Debug_checknil() bool {
4050 return Debug_checknil != 0
4051}
4052
Keith Randallc24681a2015-10-22 14:22:38 -07004053func (n *Node) Typ() ssa.Type {
4054 return n.Type
4055}