blob: eee3051c396fa92bd32f1ee04b1e1c9145401678 [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"
Keith Randalle3869a62015-09-07 23:18:02 -07009 "crypto/sha1"
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070010 "fmt"
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -070011 "html"
Todd Neal19447a62015-09-04 06:33:56 -050012 "math"
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -070013 "os"
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -060014 "strings"
Keith Randalld2fd43a2015-04-15 15:51:25 -070015
Keith Randall067e8df2015-05-28 13:49:20 -070016 "cmd/compile/internal/ssa"
Keith Randall083a6462015-05-12 11:06:44 -070017 "cmd/internal/obj"
Keith Randall8c46aa52015-06-19 21:02:28 -070018 "cmd/internal/obj/x86"
Keith Randalld2fd43a2015-04-15 15:51:25 -070019)
20
Keith Randall31115a52015-10-23 19:12:49 -070021// Smallest possible faulting page at address zero.
22const minZeroPage = 4096
23
Keith Randall5b355a72015-12-11 20:41:52 -080024func shouldssa(fn *Node) bool {
25 if Thearch.Thestring != "amd64" {
26 return false
27 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070028
David Chasee99dd522015-10-19 11:36:07 -040029 // Environment variable control of SSA CG
30 // 1. IF GOSSAFUNC == current function name THEN
31 // compile this function with SSA and log output to ssa.html
32
David Chase729abfa2015-10-26 17:34:06 -040033 // 2. IF GOSSAHASH == "" THEN
David Chasee99dd522015-10-19 11:36:07 -040034 // compile this function (and everything else) with SSA
35
David Chase729abfa2015-10-26 17:34:06 -040036 // 3. IF GOSSAHASH == "n" or "N"
David Chasee99dd522015-10-19 11:36:07 -040037 // IF GOSSAPKG == current package name THEN
38 // compile this function (and everything in this package) with SSA
39 // ELSE
40 // use the old back end for this function.
41 // This is for compatibility with existing test harness and should go away.
42
43 // 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
44 // compile this function with SSA
45 // ELSE
46 // compile this function with the old back end.
47
David Chase729abfa2015-10-26 17:34:06 -040048 // Plan is for 3 to be removed when the tests are revised.
49 // SSA is now default, and is disabled by setting
50 // GOSSAHASH to n or N, or selectively with strings of
51 // 0 and 1.
David Chasee99dd522015-10-19 11:36:07 -040052
Keith Randall5b355a72015-12-11 20:41:52 -080053 name := fn.Func.Nname.Sym.Name
54
55 funcname := os.Getenv("GOSSAFUNC")
56 if funcname != "" {
57 // If GOSSAFUNC is set, compile only that function.
58 return name == funcname
59 }
60
61 pkg := os.Getenv("GOSSAPKG")
62 if pkg != "" {
63 // If GOSSAPKG is set, compile only that package.
64 return localpkg.Name == pkg
65 }
66
67 gossahash := os.Getenv("GOSSAHASH")
68 if gossahash == "" || gossahash == "y" || gossahash == "Y" {
69 return true
70 }
71 if gossahash == "n" || gossahash == "N" {
72 return false
73 }
74
75 // Check the hash of the name against a partial input hash.
76 // We use this feature to do a binary search within a package to
77 // find a function that is incorrectly compiled.
78 hstr := ""
79 for _, b := range sha1.Sum([]byte(name)) {
80 hstr += fmt.Sprintf("%08b", b)
81 }
82
83 if strings.HasSuffix(hstr, gossahash) {
84 fmt.Printf("GOSSAHASH triggered %s\n", name)
85 return true
86 }
87
88 // Iteratively try additional hashes to allow tests for multi-point
89 // failure.
90 for i := 0; true; i++ {
91 ev := fmt.Sprintf("GOSSAHASH%d", i)
92 evv := os.Getenv(ev)
93 if evv == "" {
94 break
95 }
96 if strings.HasSuffix(hstr, evv) {
97 fmt.Printf("%s triggered %s\n", ev, name)
98 return true
99 }
100 }
101
102 return false
103}
104
105// buildssa builds an SSA function.
106func buildssa(fn *Node) *ssa.Func {
107 name := fn.Func.Nname.Sym.Name
108 printssa := strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
109 if printssa {
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700110 fmt.Println("generating SSA for", name)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700111 dumplist("buildssa-enter", fn.Func.Enter)
112 dumplist("buildssa-body", fn.Nbody)
David Chase8824dcc2015-10-08 12:39:56 -0400113 dumplist("buildssa-exit", fn.Func.Exit)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700114 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700115
Keith Randallcfc2aa52015-05-18 16:44:20 -0700116 var s state
Michael Matloob81ccf502015-05-30 01:03:06 -0400117 s.pushLine(fn.Lineno)
118 defer s.popLine()
119
Keith Randalld2fd43a2015-04-15 15:51:25 -0700120 // TODO(khr): build config just once at the start of the compiler binary
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700121
122 var e ssaExport
Keith Randall5b355a72015-12-11 20:41:52 -0800123 e.log = printssa
Keith Randall7d612462015-10-22 13:07:38 -0700124 s.config = ssa.NewConfig(Thearch.Thestring, &e, Ctxt)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700125 s.f = s.config.NewFunc()
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700126 s.f.Name = name
David Chase8824dcc2015-10-08 12:39:56 -0400127 s.exitCode = fn.Func.Exit
Keith Randall74e568f2015-11-09 21:35:40 -0800128 s.panics = map[funcLine]*ssa.Block{}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700129
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700130 if name == os.Getenv("GOSSAFUNC") {
131 // TODO: tempfile? it is handy to have the location
132 // of this file be stable, so you can just reload in the browser.
133 s.config.HTML = ssa.NewHTMLWriter("ssa.html", &s, name)
134 // TODO: generate and print a mapping from nodes to values and blocks
135 }
136 defer func() {
Keith Randall5b355a72015-12-11 20:41:52 -0800137 if !printssa {
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -0700138 s.config.HTML.Close()
139 }
140 }()
141
Keith Randalld2fd43a2015-04-15 15:51:25 -0700142 // We construct SSA using an algorithm similar to
143 // Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau
144 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
145 // TODO: check this comment
146
147 // Allocate starting block
148 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
149
Keith Randallcfc2aa52015-05-18 16:44:20 -0700150 // Allocate starting values
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700151 s.labels = map[string]*ssaLabel{}
152 s.labeledNodes = map[*Node]*ssaLabel{}
Keith Randall02f4d0a2015-11-02 08:10:26 -0800153 s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem)
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -0700154 s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead
155 s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR])
Keith Randall8c46aa52015-06-19 21:02:28 -0700156
David Chase956f3192015-09-11 16:40:05 -0400157 s.startBlock(s.f.Entry)
158 s.vars[&memVar] = s.startmem
159
Todd Neald076ef72015-10-15 20:25:32 -0500160 s.varsyms = map[*Node]interface{}{}
161
Keith Randall8c46aa52015-06-19 21:02:28 -0700162 // Generate addresses of local declarations
163 s.decladdrs = map[*Node]*ssa.Value{}
164 for d := fn.Func.Dcl; d != nil; d = d.Next {
165 n := d.N
166 switch n.Class {
David Chase956f3192015-09-11 16:40:05 -0400167 case PPARAM:
Todd Neald076ef72015-10-15 20:25:32 -0500168 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randall8c46aa52015-06-19 21:02:28 -0700169 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -0400170 case PAUTO | PHEAP:
171 // TODO this looks wrong for PAUTO|PHEAP, no vardef, but also no definition
Todd Neald076ef72015-10-15 20:25:32 -0500172 aux := s.lookupSymbol(n, &ssa.AutoSymbol{Typ: n.Type, Node: n})
David Chase956f3192015-09-11 16:40:05 -0400173 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
David Chase8824dcc2015-10-08 12:39:56 -0400174 case PPARAM | PHEAP, PPARAMOUT | PHEAP:
175 // This ends up wrong, have to do it at the PARAM node instead.
David Chase956f3192015-09-11 16:40:05 -0400176 case PAUTO, PPARAMOUT:
Keith Randalld2107fc2015-08-24 02:16:19 -0700177 // processed at each use, to prevent Addr coming
178 // before the decl.
Keith Randallc3eb1a72015-09-06 13:42:26 -0700179 case PFUNC:
180 // local function - already handled by frontend
Daniel Morsingbe2a3e22015-07-01 20:37:25 +0100181 default:
182 str := ""
183 if n.Class&PHEAP != 0 {
184 str = ",heap"
185 }
Josh Bleecher Snyder58446032015-08-23 20:29:43 -0700186 s.Unimplementedf("local variable with class %s%s unimplemented", classnames[n.Class&^PHEAP], str)
Keith Randall8c46aa52015-06-19 21:02:28 -0700187 }
188 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700189
190 // Convert the AST-based IR to the SSA-based IR
Keith Randallf7f604e2015-05-27 14:52:22 -0700191 s.stmtList(fn.Func.Enter)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700192 s.stmtList(fn.Nbody)
193
Keith Randallcfc2aa52015-05-18 16:44:20 -0700194 // fallthrough to exit
Keith Randalla7cfc7592015-09-08 16:04:37 -0700195 if s.curBlock != nil {
David Chase8824dcc2015-10-08 12:39:56 -0400196 s.stmtList(s.exitCode)
Keith Randalla7cfc7592015-09-08 16:04:37 -0700197 m := s.mem()
198 b := s.endBlock()
Keith Randalld9f2caf2015-09-03 14:28:52 -0700199 b.Kind = ssa.BlockRet
Keith Randalla7cfc7592015-09-08 16:04:37 -0700200 b.Control = m
Keith Randallcfc2aa52015-05-18 16:44:20 -0700201 }
202
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700203 // Check that we used all labels
204 for name, lab := range s.labels {
205 if !lab.used() && !lab.reported {
206 yyerrorl(int(lab.defNode.Lineno), "label %v defined and not used", name)
207 lab.reported = true
208 }
209 if lab.used() && !lab.defined() && !lab.reported {
210 yyerrorl(int(lab.useNode.Lineno), "label %v not defined", name)
211 lab.reported = true
212 }
213 }
214
215 // Check any forward gotos. Non-forward gotos have already been checked.
216 for _, n := range s.fwdGotos {
217 lab := s.labels[n.Left.Sym.Name]
218 // If the label is undefined, we have already have printed an error.
219 if lab.defined() {
220 s.checkgoto(n, lab.defNode)
221 }
222 }
223
224 if nerrors > 0 {
Keith Randall5b355a72015-12-11 20:41:52 -0800225 return nil
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700226 }
227
Keith Randalld2fd43a2015-04-15 15:51:25 -0700228 // Link up variable uses to variable definitions
229 s.linkForwardReferences()
230
David Chase8824dcc2015-10-08 12:39:56 -0400231 // Don't carry reference this around longer than necessary
232 s.exitCode = nil
233
Josh Bleecher Snyder983bc8d2015-07-17 16:47:43 +0000234 // Main call to ssa package to compile function
235 ssa.Compile(s.f)
236
Keith Randall5b355a72015-12-11 20:41:52 -0800237 return s.f
Keith Randalld2fd43a2015-04-15 15:51:25 -0700238}
239
Keith Randallcfc2aa52015-05-18 16:44:20 -0700240type state struct {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700241 // configuration (arch) information
242 config *ssa.Config
243
244 // function we're building
245 f *ssa.Func
246
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700247 // labels and labeled control flow nodes (OFOR, OSWITCH, OSELECT) in f
248 labels map[string]*ssaLabel
249 labeledNodes map[*Node]*ssaLabel
250
251 // gotos that jump forward; required for deferred checkgoto calls
252 fwdGotos []*Node
David Chase8824dcc2015-10-08 12:39:56 -0400253 // Code that must precede any return
254 // (e.g., copying value of heap-escaped paramout back to true paramout)
255 exitCode *NodeList
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700256
257 // unlabeled break and continue statement tracking
258 breakTo *ssa.Block // current target for plain break statement
259 continueTo *ssa.Block // current target for plain continue statement
Keith Randalld2fd43a2015-04-15 15:51:25 -0700260
261 // current location where we're interpreting the AST
262 curBlock *ssa.Block
263
Keith Randall8c46aa52015-06-19 21:02:28 -0700264 // variable assignments in the current block (map from variable symbol to ssa value)
265 // *Node is the unique identifier (an ONAME Node) for the variable.
266 vars map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700267
268 // all defined variables at the end of each block. Indexed by block ID.
Keith Randall8c46aa52015-06-19 21:02:28 -0700269 defvars []map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700270
Keith Randalld2107fc2015-08-24 02:16:19 -0700271 // addresses of PPARAM and PPARAMOUT variables.
Keith Randall8c46aa52015-06-19 21:02:28 -0700272 decladdrs map[*Node]*ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700273
Todd Neald076ef72015-10-15 20:25:32 -0500274 // symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
275 varsyms map[*Node]interface{}
276
Keith Randall7d612462015-10-22 13:07:38 -0700277 // starting values. Memory, stack pointer, and globals pointer
Keith Randallcfc2aa52015-05-18 16:44:20 -0700278 startmem *ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700279 sp *ssa.Value
Keith Randall8c46aa52015-06-19 21:02:28 -0700280 sb *ssa.Value
Michael Matloob81ccf502015-05-30 01:03:06 -0400281
282 // line number stack. The current line number is top of stack
283 line []int32
Keith Randall74e568f2015-11-09 21:35:40 -0800284
285 // list of panic calls by function name and line number.
286 // Used to deduplicate panic calls.
287 panics map[funcLine]*ssa.Block
288}
289
290type funcLine struct {
291 f *Node
292 line int32
Keith Randalld2fd43a2015-04-15 15:51:25 -0700293}
294
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700295type ssaLabel struct {
296 target *ssa.Block // block identified by this label
297 breakTarget *ssa.Block // block to break to in control flow node identified by this label
298 continueTarget *ssa.Block // block to continue to in control flow node identified by this label
299 defNode *Node // label definition Node (OLABEL)
300 // Label use Node (OGOTO, OBREAK, OCONTINUE).
301 // Used only for error detection and reporting.
302 // There might be multiple uses, but we only need to track one.
303 useNode *Node
304 reported bool // reported indicates whether an error has already been reported for this label
305}
306
307// defined reports whether the label has a definition (OLABEL node).
308func (l *ssaLabel) defined() bool { return l.defNode != nil }
309
310// used reports whether the label has a use (OGOTO, OBREAK, or OCONTINUE node).
311func (l *ssaLabel) used() bool { return l.useNode != nil }
312
313// label returns the label associated with sym, creating it if necessary.
314func (s *state) label(sym *Sym) *ssaLabel {
315 lab := s.labels[sym.Name]
316 if lab == nil {
317 lab = new(ssaLabel)
318 s.labels[sym.Name] = lab
319 }
320 return lab
321}
322
David Chase729abfa2015-10-26 17:34:06 -0400323func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
324func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(msg, args...) }
325func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimplementedf(msg, args...) }
326func (s *state) Warnl(line int, msg string, args ...interface{}) { s.config.Warnl(line, msg, args...) }
327func (s *state) Debug_checknil() bool { return s.config.Debug_checknil() }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700328
Keith Randall269baa92015-09-17 10:31:16 -0700329var (
330 // dummy node for the memory variable
Keith Randallc24681a2015-10-22 14:22:38 -0700331 memVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "mem"}}
Keith Randall8c46aa52015-06-19 21:02:28 -0700332
Keith Randall269baa92015-09-17 10:31:16 -0700333 // dummy nodes for temporary variables
Keith Randallc24681a2015-10-22 14:22:38 -0700334 ptrVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ptr"}}
335 capVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "cap"}}
336 typVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "typ"}}
337 idataVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "idata"}}
338 okVar = Node{Op: ONAME, Class: Pxxx, Sym: &Sym{Name: "ok"}}
Keith Randall269baa92015-09-17 10:31:16 -0700339)
Keith Randall5505e8c2015-09-12 23:27:26 -0700340
Keith Randalld2fd43a2015-04-15 15:51:25 -0700341// startBlock sets the current block we're generating code in to b.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700342func (s *state) startBlock(b *ssa.Block) {
343 if s.curBlock != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700344 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700345 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700346 s.curBlock = b
Keith Randall8c46aa52015-06-19 21:02:28 -0700347 s.vars = map[*Node]*ssa.Value{}
Keith Randalld2fd43a2015-04-15 15:51:25 -0700348}
349
350// endBlock marks the end of generating code for the current block.
351// Returns the (former) current block. Returns nil if there is no current
352// block, i.e. if no code flows to the current execution point.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700353func (s *state) endBlock() *ssa.Block {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700354 b := s.curBlock
355 if b == nil {
356 return nil
357 }
358 for len(s.defvars) <= int(b.ID) {
359 s.defvars = append(s.defvars, nil)
360 }
361 s.defvars[b.ID] = s.vars
362 s.curBlock = nil
363 s.vars = nil
Michael Matloob81ccf502015-05-30 01:03:06 -0400364 b.Line = s.peekLine()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700365 return b
366}
367
Michael Matloob81ccf502015-05-30 01:03:06 -0400368// pushLine pushes a line number on the line number stack.
369func (s *state) pushLine(line int32) {
370 s.line = append(s.line, line)
371}
372
373// popLine pops the top of the line number stack.
374func (s *state) popLine() {
375 s.line = s.line[:len(s.line)-1]
376}
377
378// peekLine peek the top of the line number stack.
379func (s *state) peekLine() int32 {
380 return s.line[len(s.line)-1]
381}
382
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700383func (s *state) Error(msg string, args ...interface{}) {
384 yyerrorl(int(s.peekLine()), msg, args...)
385}
386
Keith Randall8f22b522015-06-11 21:29:25 -0700387// newValue0 adds a new value with no arguments to the current block.
388func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
389 return s.curBlock.NewValue0(s.peekLine(), op, t)
390}
391
392// newValue0A adds a new value with no arguments and an aux value to the current block.
393func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
394 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400395}
396
Todd Neal991036a2015-09-03 18:24:22 -0500397// newValue0I adds a new value with no arguments and an auxint value to the current block.
398func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
399 return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint)
400}
401
Michael Matloob81ccf502015-05-30 01:03:06 -0400402// newValue1 adds a new value with one argument to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700403func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
404 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
405}
406
407// newValue1A adds a new value with one argument and an aux value to the current block.
408func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
409 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400410}
411
Keith Randallcd7e0592015-07-15 21:33:49 -0700412// newValue1I adds a new value with one argument and an auxint value to the current block.
413func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
414 return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
415}
416
Michael Matloob81ccf502015-05-30 01:03:06 -0400417// newValue2 adds a new value with two arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700418func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
419 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400420}
421
Daniel Morsing66b47812015-06-27 15:45:20 +0100422// newValue2I adds a new value with two arguments and an auxint value to the current block.
423func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
424 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
425}
426
Michael Matloob81ccf502015-05-30 01:03:06 -0400427// newValue3 adds a new value with three arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700428func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
429 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
Michael Matloob81ccf502015-05-30 01:03:06 -0400430}
431
Keith Randalld4cc51d2015-08-14 21:47:20 -0700432// newValue3I adds a new value with three arguments and an auxint value to the current block.
433func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
434 return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2)
435}
436
Todd Neal991036a2015-09-03 18:24:22 -0500437// entryNewValue0 adds a new value with no arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700438func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
439 return s.f.Entry.NewValue0(s.peekLine(), op, t)
440}
441
Todd Neal991036a2015-09-03 18:24:22 -0500442// entryNewValue0A adds a new value with no arguments and an aux value to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700443func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
444 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400445}
446
Todd Neal991036a2015-09-03 18:24:22 -0500447// entryNewValue0I adds a new value with no arguments and an auxint value to the entry block.
448func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value {
449 return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint)
450}
451
Michael Matloob81ccf502015-05-30 01:03:06 -0400452// entryNewValue1 adds a new value with one argument to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700453func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
454 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
455}
456
457// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
458func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
459 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400460}
461
Keith Randall8c46aa52015-06-19 21:02:28 -0700462// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
463func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
464 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
465}
466
Michael Matloob81ccf502015-05-30 01:03:06 -0400467// entryNewValue2 adds a new value with two arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700468func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
469 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400470}
471
Josh Bleecher Snydercea44142015-09-08 16:52:25 -0700472// const* routines add a new const value to the entry block.
473func (s *state) constBool(c bool) *ssa.Value {
474 return s.f.ConstBool(s.peekLine(), Types[TBOOL], c)
475}
Keith Randall9cb332e2015-07-28 14:19:20 -0700476func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
477 return s.f.ConstInt8(s.peekLine(), t, c)
478}
479func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
480 return s.f.ConstInt16(s.peekLine(), t, c)
481}
482func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
483 return s.f.ConstInt32(s.peekLine(), t, c)
484}
485func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
486 return s.f.ConstInt64(s.peekLine(), t, c)
487}
David Chase997a9f32015-08-12 16:38:11 -0400488func (s *state) constFloat32(t ssa.Type, c float64) *ssa.Value {
489 return s.f.ConstFloat32(s.peekLine(), t, c)
490}
491func (s *state) constFloat64(t ssa.Type, c float64) *ssa.Value {
492 return s.f.ConstFloat64(s.peekLine(), t, c)
493}
Michael Matloob81ccf502015-05-30 01:03:06 -0400494func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
Keith Randall9cb332e2015-07-28 14:19:20 -0700495 if s.config.IntSize == 8 {
496 return s.constInt64(t, c)
497 }
498 if int64(int32(c)) != c {
499 s.Fatalf("integer constant too big %d", c)
500 }
501 return s.constInt32(t, int32(c))
Michael Matloob81ccf502015-05-30 01:03:06 -0400502}
503
Keith Randalld2fd43a2015-04-15 15:51:25 -0700504// ssaStmtList converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700505func (s *state) stmtList(l *NodeList) {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700506 for ; l != nil; l = l.Next {
507 s.stmt(l.N)
508 }
509}
510
511// ssaStmt converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700512func (s *state) stmt(n *Node) {
Michael Matloob81ccf502015-05-30 01:03:06 -0400513 s.pushLine(n.Lineno)
514 defer s.popLine()
515
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700516 // If s.curBlock is nil, then we're about to generate dead code.
517 // We can't just short-circuit here, though,
518 // because we check labels and gotos as part of SSA generation.
519 // Provide a block for the dead code so that we don't have
520 // to add special cases everywhere else.
521 if s.curBlock == nil {
522 dead := s.f.NewBlock(ssa.BlockPlain)
523 s.startBlock(dead)
524 }
525
Keith Randalld2fd43a2015-04-15 15:51:25 -0700526 s.stmtList(n.Ninit)
527 switch n.Op {
528
529 case OBLOCK:
530 s.stmtList(n.List)
531
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600532 // No-ops
Todd Neal67e43c12015-08-28 21:19:40 -0500533 case OEMPTY, ODCLCONST, ODCLTYPE, OFALL:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600534
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600535 // Expression statements
536 case OCALLFUNC, OCALLMETH, OCALLINTER:
Keith Randalld24768e2015-09-09 23:56:59 -0700537 s.call(n, callNormal)
538 case ODEFER:
539 s.call(n.Left, callDefer)
540 case OPROC:
541 s.call(n.Left, callGo)
Josh Bleecher Snyder2574e4a2015-07-16 13:25:36 -0600542
Keith Randall269baa92015-09-17 10:31:16 -0700543 case OAS2DOTTYPE:
544 res, resok := s.dottype(n.Rlist.N, true)
Keith Randallb386c342016-01-07 10:00:16 -0800545 s.assign(n.List.N, res, false, n.Lineno)
546 s.assign(n.List.Next.N, resok, false, n.Lineno)
Keith Randall269baa92015-09-17 10:31:16 -0700547 return
548
Keith Randalld2fd43a2015-04-15 15:51:25 -0700549 case ODCL:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100550 if n.Left.Class&PHEAP == 0 {
551 return
552 }
553 if compiling_runtime != 0 {
Keith Randall0ec72b62015-09-08 15:42:53 -0700554 Fatalf("%v escapes to heap, not allowed in runtime.", n)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100555 }
556
557 // TODO: the old pass hides the details of PHEAP
558 // variables behind ONAME nodes. Figure out if it's better
559 // to rewrite the tree and make the heapaddr construct explicit
560 // or to keep this detail hidden behind the scenes.
561 palloc := prealloc[n.Left]
562 if palloc == nil {
563 palloc = callnew(n.Left.Type)
564 prealloc[n.Left] = palloc
565 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700566 r := s.expr(palloc)
Keith Randallb386c342016-01-07 10:00:16 -0800567 s.assign(n.Left.Name.Heapaddr, r, false, n.Lineno)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700568
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700569 case OLABEL:
570 sym := n.Left.Sym
571
572 if isblanksym(sym) {
Keith Randall7e4c06d2015-07-12 11:52:09 -0700573 // Empty identifier is valid but useless.
574 // See issues 11589, 11593.
575 return
576 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700577
578 lab := s.label(sym)
579
580 // Associate label with its control flow node, if any
581 if ctl := n.Name.Defn; ctl != nil {
582 switch ctl.Op {
583 case OFOR, OSWITCH, OSELECT:
584 s.labeledNodes[ctl] = lab
585 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -0700586 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700587
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700588 if !lab.defined() {
589 lab.defNode = n
590 } else {
591 s.Error("label %v already defined at %v", sym, Ctxt.Line(int(lab.defNode.Lineno)))
592 lab.reported = true
Keith Randalld2fd43a2015-04-15 15:51:25 -0700593 }
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700594 // The label might already have a target block via a goto.
595 if lab.target == nil {
596 lab.target = s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700597 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700598
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700599 // go to that label (we pretend "label:" is preceded by "goto label")
600 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500601 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700602 s.startBlock(lab.target)
603
604 case OGOTO:
605 sym := n.Left.Sym
606
607 lab := s.label(sym)
608 if lab.target == nil {
609 lab.target = s.f.NewBlock(ssa.BlockPlain)
610 }
611 if !lab.used() {
612 lab.useNode = n
613 }
614
615 if lab.defined() {
616 s.checkgoto(n, lab.defNode)
617 } else {
618 s.fwdGotos = append(s.fwdGotos, n)
619 }
620
621 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500622 b.AddEdgeTo(lab.target)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700623
Keith Randall290d8fc2015-06-10 15:03:06 -0700624 case OAS, OASWB:
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -0700625 // Check whether we can generate static data rather than code.
626 // If so, ignore n and defer data generation until codegen.
627 // Failure to do this causes writes to readonly symbols.
628 if gen_as_init(n, true) {
629 var data []*Node
630 if s.f.StaticData != nil {
631 data = s.f.StaticData.([]*Node)
632 }
633 s.f.StaticData = append(data, n)
634 return
635 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700636 var r *ssa.Value
637 if n.Right != nil {
Keith Randalld3886902015-09-18 22:12:38 -0700638 if n.Right.Op == OSTRUCTLIT || n.Right.Op == OARRAYLIT {
639 // All literals with nonzero fields have already been
640 // rewritten during walk. Any that remain are just T{}
641 // or equivalents. Leave r = nil to get zeroing behavior.
642 if !iszero(n.Right) {
643 Fatalf("literal with nonzero value in SSA: %v", n.Right)
644 }
645 } else {
646 r = s.expr(n.Right)
647 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -0700648 }
Keith Randall9d22c102015-09-11 11:02:57 -0700649 if n.Right != nil && n.Right.Op == OAPPEND {
650 // Yuck! The frontend gets rid of the write barrier, but we need it!
651 // At least, we need it in the case where growslice is called.
652 // TODO: Do the write barrier on just the growslice branch.
653 // TODO: just add a ptr graying to the end of growslice?
654 // TODO: check whether we need to do this for ODOTTYPE and ORECV also.
655 // They get similar wb-removal treatment in walk.go:OAS.
Keith Randallb386c342016-01-07 10:00:16 -0800656 s.assign(n.Left, r, true, n.Lineno)
Keith Randall9d22c102015-09-11 11:02:57 -0700657 return
658 }
Keith Randallb386c342016-01-07 10:00:16 -0800659 s.assign(n.Left, r, n.Op == OASWB, n.Lineno)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100660
Keith Randalld2fd43a2015-04-15 15:51:25 -0700661 case OIF:
Keith Randalld2fd43a2015-04-15 15:51:25 -0700662 bThen := s.f.NewBlock(ssa.BlockPlain)
663 bEnd := s.f.NewBlock(ssa.BlockPlain)
664 var bElse *ssa.Block
Keith Randall99187312015-11-02 16:56:53 -0800665 if n.Rlist != nil {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700666 bElse = s.f.NewBlock(ssa.BlockPlain)
Keith Randall99187312015-11-02 16:56:53 -0800667 s.condBranch(n.Left, bThen, bElse, n.Likely)
668 } else {
669 s.condBranch(n.Left, bThen, bEnd, n.Likely)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700670 }
671
672 s.startBlock(bThen)
673 s.stmtList(n.Nbody)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700674 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500675 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700676 }
677
Keith Randalle707fbe2015-06-11 10:20:39 -0700678 if n.Rlist != nil {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700679 s.startBlock(bElse)
Keith Randalle707fbe2015-06-11 10:20:39 -0700680 s.stmtList(n.Rlist)
Josh Bleecher Snydere0ac5c52015-07-20 18:42:45 -0700681 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500682 b.AddEdgeTo(bEnd)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700683 }
684 }
685 s.startBlock(bEnd)
686
687 case ORETURN:
688 s.stmtList(n.List)
David Chase8824dcc2015-10-08 12:39:56 -0400689 s.stmtList(s.exitCode)
Keith Randalla7cfc7592015-09-08 16:04:37 -0700690 m := s.mem()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700691 b := s.endBlock()
Keith Randall10f38f52015-09-03 09:09:59 -0700692 b.Kind = ssa.BlockRet
Keith Randalla7cfc7592015-09-08 16:04:37 -0700693 b.Control = m
Keith Randall8a1f6212015-09-08 21:28:44 -0700694 case ORETJMP:
695 s.stmtList(n.List)
David Chase8824dcc2015-10-08 12:39:56 -0400696 s.stmtList(s.exitCode)
Keith Randall8a1f6212015-09-08 21:28:44 -0700697 m := s.mem()
698 b := s.endBlock()
699 b.Kind = ssa.BlockRetJmp
700 b.Aux = n.Left.Sym
701 b.Control = m
Keith Randalld2fd43a2015-04-15 15:51:25 -0700702
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700703 case OCONTINUE, OBREAK:
704 var op string
705 var to *ssa.Block
706 switch n.Op {
707 case OCONTINUE:
708 op = "continue"
709 to = s.continueTo
710 case OBREAK:
711 op = "break"
712 to = s.breakTo
713 }
714 if n.Left == nil {
715 // plain break/continue
716 if to == nil {
717 s.Error("%s is not in a loop", op)
718 return
719 }
720 // nothing to do; "to" is already the correct target
721 } else {
722 // labeled break/continue; look up the target
723 sym := n.Left.Sym
724 lab := s.label(sym)
725 if !lab.used() {
726 lab.useNode = n.Left
727 }
728 if !lab.defined() {
729 s.Error("%s label not defined: %v", op, sym)
730 lab.reported = true
731 return
732 }
733 switch n.Op {
734 case OCONTINUE:
735 to = lab.continueTarget
736 case OBREAK:
737 to = lab.breakTarget
738 }
739 if to == nil {
740 // Valid label but not usable with a break/continue here, e.g.:
741 // for {
742 // continue abc
743 // }
744 // abc:
745 // for {}
746 s.Error("invalid %s label %v", op, sym)
747 lab.reported = true
748 return
749 }
750 }
751
752 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500753 b.AddEdgeTo(to)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700754
Keith Randalld2fd43a2015-04-15 15:51:25 -0700755 case OFOR:
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700756 // OFOR: for Ninit; Left; Right { Nbody }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700757 bCond := s.f.NewBlock(ssa.BlockPlain)
758 bBody := s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700759 bIncr := s.f.NewBlock(ssa.BlockPlain)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700760 bEnd := s.f.NewBlock(ssa.BlockPlain)
761
762 // first, jump to condition test
763 b := s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -0500764 b.AddEdgeTo(bCond)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700765
766 // generate code to test condition
Keith Randalld2fd43a2015-04-15 15:51:25 -0700767 s.startBlock(bCond)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700768 if n.Left != nil {
Keith Randall99187312015-11-02 16:56:53 -0800769 s.condBranch(n.Left, bBody, bEnd, 1)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700770 } else {
Keith Randall99187312015-11-02 16:56:53 -0800771 b := s.endBlock()
772 b.Kind = ssa.BlockPlain
773 b.AddEdgeTo(bBody)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700774 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700775
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700776 // set up for continue/break in body
777 prevContinue := s.continueTo
778 prevBreak := s.breakTo
779 s.continueTo = bIncr
780 s.breakTo = bEnd
781 lab := s.labeledNodes[n]
782 if lab != nil {
783 // labeled for loop
784 lab.continueTarget = bIncr
785 lab.breakTarget = bEnd
786 }
787
Keith Randalld2fd43a2015-04-15 15:51:25 -0700788 // generate body
789 s.startBlock(bBody)
790 s.stmtList(n.Nbody)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700791
792 // tear down continue/break
793 s.continueTo = prevContinue
794 s.breakTo = prevBreak
795 if lab != nil {
796 lab.continueTarget = nil
797 lab.breakTarget = nil
798 }
799
800 // done with body, goto incr
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700801 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500802 b.AddEdgeTo(bIncr)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700803 }
804
805 // generate incr
806 s.startBlock(bIncr)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700807 if n.Right != nil {
808 s.stmt(n.Right)
809 }
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700810 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500811 b.AddEdgeTo(bCond)
Josh Bleecher Snyder6c140592015-07-04 09:07:54 -0700812 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700813 s.startBlock(bEnd)
814
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700815 case OSWITCH, OSELECT:
816 // These have been mostly rewritten by the front end into their Nbody fields.
817 // Our main task is to correctly hook up any break statements.
818 bEnd := s.f.NewBlock(ssa.BlockPlain)
819
820 prevBreak := s.breakTo
821 s.breakTo = bEnd
822 lab := s.labeledNodes[n]
823 if lab != nil {
824 // labeled
825 lab.breakTarget = bEnd
826 }
827
828 // generate body code
829 s.stmtList(n.Nbody)
830
831 s.breakTo = prevBreak
832 if lab != nil {
833 lab.breakTarget = nil
834 }
835
836 if b := s.endBlock(); b != nil {
Todd Neal47d67992015-08-28 21:36:29 -0500837 b.AddEdgeTo(bEnd)
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -0700838 }
839 s.startBlock(bEnd)
840
Keith Randalld2fd43a2015-04-15 15:51:25 -0700841 case OVARKILL:
Keith Randalld2107fc2015-08-24 02:16:19 -0700842 // Insert a varkill op to record that a variable is no longer live.
843 // We only care about liveness info at call sites, so putting the
844 // varkill in the store chain is enough to keep it correctly ordered
845 // with respect to call ops.
Keith Randalld29e92b2015-09-19 12:01:39 -0700846 if !canSSA(n.Left) {
847 s.vars[&memVar] = s.newValue1A(ssa.OpVarKill, ssa.TypeMem, n.Left, s.mem())
848 }
Keith Randall9569b952015-08-28 22:51:01 -0700849
Keith Randall46ffb022015-09-12 14:06:44 -0700850 case OCHECKNIL:
851 p := s.expr(n.Left)
852 s.nilCheck(p)
853
Keith Randalld2fd43a2015-04-15 15:51:25 -0700854 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700855 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -0700856 }
857}
858
Keith Randall67fdb0d2015-07-19 15:48:20 -0700859type opAndType struct {
Keith Randall4304fbc2015-11-16 13:20:16 -0800860 op Op
861 etype EType
Keith Randall67fdb0d2015-07-19 15:48:20 -0700862}
863
864var opToSSA = map[opAndType]ssa.Op{
David Chase997a9f32015-08-12 16:38:11 -0400865 opAndType{OADD, TINT8}: ssa.OpAdd8,
866 opAndType{OADD, TUINT8}: ssa.OpAdd8,
867 opAndType{OADD, TINT16}: ssa.OpAdd16,
868 opAndType{OADD, TUINT16}: ssa.OpAdd16,
869 opAndType{OADD, TINT32}: ssa.OpAdd32,
870 opAndType{OADD, TUINT32}: ssa.OpAdd32,
871 opAndType{OADD, TPTR32}: ssa.OpAdd32,
872 opAndType{OADD, TINT64}: ssa.OpAdd64,
873 opAndType{OADD, TUINT64}: ssa.OpAdd64,
874 opAndType{OADD, TPTR64}: ssa.OpAdd64,
875 opAndType{OADD, TFLOAT32}: ssa.OpAdd32F,
876 opAndType{OADD, TFLOAT64}: ssa.OpAdd64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -0700877
David Chase997a9f32015-08-12 16:38:11 -0400878 opAndType{OSUB, TINT8}: ssa.OpSub8,
879 opAndType{OSUB, TUINT8}: ssa.OpSub8,
880 opAndType{OSUB, TINT16}: ssa.OpSub16,
881 opAndType{OSUB, TUINT16}: ssa.OpSub16,
882 opAndType{OSUB, TINT32}: ssa.OpSub32,
883 opAndType{OSUB, TUINT32}: ssa.OpSub32,
884 opAndType{OSUB, TINT64}: ssa.OpSub64,
885 opAndType{OSUB, TUINT64}: ssa.OpSub64,
886 opAndType{OSUB, TFLOAT32}: ssa.OpSub32F,
887 opAndType{OSUB, TFLOAT64}: ssa.OpSub64F,
Keith Randall67fdb0d2015-07-19 15:48:20 -0700888
Josh Bleecher Snydere61e7c92015-07-22 19:19:40 -0700889 opAndType{ONOT, TBOOL}: ssa.OpNot,
890
David Chase3a9d0ac2015-08-28 14:24:10 -0400891 opAndType{OMINUS, TINT8}: ssa.OpNeg8,
892 opAndType{OMINUS, TUINT8}: ssa.OpNeg8,
893 opAndType{OMINUS, TINT16}: ssa.OpNeg16,
894 opAndType{OMINUS, TUINT16}: ssa.OpNeg16,
895 opAndType{OMINUS, TINT32}: ssa.OpNeg32,
896 opAndType{OMINUS, TUINT32}: ssa.OpNeg32,
897 opAndType{OMINUS, TINT64}: ssa.OpNeg64,
898 opAndType{OMINUS, TUINT64}: ssa.OpNeg64,
899 opAndType{OMINUS, TFLOAT32}: ssa.OpNeg32F,
900 opAndType{OMINUS, TFLOAT64}: ssa.OpNeg64F,
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +0200901
Keith Randall4b803152015-07-29 17:07:09 -0700902 opAndType{OCOM, TINT8}: ssa.OpCom8,
903 opAndType{OCOM, TUINT8}: ssa.OpCom8,
904 opAndType{OCOM, TINT16}: ssa.OpCom16,
905 opAndType{OCOM, TUINT16}: ssa.OpCom16,
906 opAndType{OCOM, TINT32}: ssa.OpCom32,
907 opAndType{OCOM, TUINT32}: ssa.OpCom32,
908 opAndType{OCOM, TINT64}: ssa.OpCom64,
909 opAndType{OCOM, TUINT64}: ssa.OpCom64,
910
Josh Bleecher Snyderfa5fe192015-09-06 19:24:59 -0700911 opAndType{OIMAG, TCOMPLEX64}: ssa.OpComplexImag,
912 opAndType{OIMAG, TCOMPLEX128}: ssa.OpComplexImag,
913 opAndType{OREAL, TCOMPLEX64}: ssa.OpComplexReal,
914 opAndType{OREAL, TCOMPLEX128}: ssa.OpComplexReal,
915
David Chase997a9f32015-08-12 16:38:11 -0400916 opAndType{OMUL, TINT8}: ssa.OpMul8,
917 opAndType{OMUL, TUINT8}: ssa.OpMul8,
918 opAndType{OMUL, TINT16}: ssa.OpMul16,
919 opAndType{OMUL, TUINT16}: ssa.OpMul16,
920 opAndType{OMUL, TINT32}: ssa.OpMul32,
921 opAndType{OMUL, TUINT32}: ssa.OpMul32,
922 opAndType{OMUL, TINT64}: ssa.OpMul64,
923 opAndType{OMUL, TUINT64}: ssa.OpMul64,
924 opAndType{OMUL, TFLOAT32}: ssa.OpMul32F,
925 opAndType{OMUL, TFLOAT64}: ssa.OpMul64F,
926
927 opAndType{ODIV, TFLOAT32}: ssa.OpDiv32F,
928 opAndType{ODIV, TFLOAT64}: ssa.OpDiv64F,
Keith Randallbe1eb572015-07-22 13:46:15 -0700929
Todd Neal67cbd5b2015-08-18 19:14:47 -0500930 opAndType{OHMUL, TINT8}: ssa.OpHmul8,
931 opAndType{OHMUL, TUINT8}: ssa.OpHmul8u,
932 opAndType{OHMUL, TINT16}: ssa.OpHmul16,
933 opAndType{OHMUL, TUINT16}: ssa.OpHmul16u,
934 opAndType{OHMUL, TINT32}: ssa.OpHmul32,
935 opAndType{OHMUL, TUINT32}: ssa.OpHmul32u,
936
Todd Neala45f2d82015-08-17 17:46:06 -0500937 opAndType{ODIV, TINT8}: ssa.OpDiv8,
938 opAndType{ODIV, TUINT8}: ssa.OpDiv8u,
939 opAndType{ODIV, TINT16}: ssa.OpDiv16,
940 opAndType{ODIV, TUINT16}: ssa.OpDiv16u,
941 opAndType{ODIV, TINT32}: ssa.OpDiv32,
942 opAndType{ODIV, TUINT32}: ssa.OpDiv32u,
943 opAndType{ODIV, TINT64}: ssa.OpDiv64,
944 opAndType{ODIV, TUINT64}: ssa.OpDiv64u,
945
Todd Neal57d9e7e2015-08-18 19:51:44 -0500946 opAndType{OMOD, TINT8}: ssa.OpMod8,
947 opAndType{OMOD, TUINT8}: ssa.OpMod8u,
948 opAndType{OMOD, TINT16}: ssa.OpMod16,
949 opAndType{OMOD, TUINT16}: ssa.OpMod16u,
950 opAndType{OMOD, TINT32}: ssa.OpMod32,
951 opAndType{OMOD, TUINT32}: ssa.OpMod32u,
952 opAndType{OMOD, TINT64}: ssa.OpMod64,
953 opAndType{OMOD, TUINT64}: ssa.OpMod64u,
954
Alexandru Moșoiedff8812015-07-28 14:58:49 +0200955 opAndType{OAND, TINT8}: ssa.OpAnd8,
Keith Randall2a5e6c42015-07-23 14:35:02 -0700956 opAndType{OAND, TUINT8}: ssa.OpAnd8,
Alexandru Moșoiedff8812015-07-28 14:58:49 +0200957 opAndType{OAND, TINT16}: ssa.OpAnd16,
Keith Randall2a5e6c42015-07-23 14:35:02 -0700958 opAndType{OAND, TUINT16}: ssa.OpAnd16,
Alexandru Moșoiedff8812015-07-28 14:58:49 +0200959 opAndType{OAND, TINT32}: ssa.OpAnd32,
Keith Randall2a5e6c42015-07-23 14:35:02 -0700960 opAndType{OAND, TUINT32}: ssa.OpAnd32,
Alexandru Moșoiedff8812015-07-28 14:58:49 +0200961 opAndType{OAND, TINT64}: ssa.OpAnd64,
Keith Randall2a5e6c42015-07-23 14:35:02 -0700962 opAndType{OAND, TUINT64}: ssa.OpAnd64,
Alexandru Moșoiedff8812015-07-28 14:58:49 +0200963
Alexandru Moșoi74024162015-07-29 17:52:25 +0200964 opAndType{OOR, TINT8}: ssa.OpOr8,
965 opAndType{OOR, TUINT8}: ssa.OpOr8,
966 opAndType{OOR, TINT16}: ssa.OpOr16,
967 opAndType{OOR, TUINT16}: ssa.OpOr16,
968 opAndType{OOR, TINT32}: ssa.OpOr32,
969 opAndType{OOR, TUINT32}: ssa.OpOr32,
970 opAndType{OOR, TINT64}: ssa.OpOr64,
971 opAndType{OOR, TUINT64}: ssa.OpOr64,
972
Alexandru Moșoi6d9362a12015-07-30 12:33:36 +0200973 opAndType{OXOR, TINT8}: ssa.OpXor8,
974 opAndType{OXOR, TUINT8}: ssa.OpXor8,
975 opAndType{OXOR, TINT16}: ssa.OpXor16,
976 opAndType{OXOR, TUINT16}: ssa.OpXor16,
977 opAndType{OXOR, TINT32}: ssa.OpXor32,
978 opAndType{OXOR, TUINT32}: ssa.OpXor32,
979 opAndType{OXOR, TINT64}: ssa.OpXor64,
980 opAndType{OXOR, TUINT64}: ssa.OpXor64,
981
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -0700982 opAndType{OEQ, TBOOL}: ssa.OpEq8,
983 opAndType{OEQ, TINT8}: ssa.OpEq8,
984 opAndType{OEQ, TUINT8}: ssa.OpEq8,
985 opAndType{OEQ, TINT16}: ssa.OpEq16,
986 opAndType{OEQ, TUINT16}: ssa.OpEq16,
987 opAndType{OEQ, TINT32}: ssa.OpEq32,
988 opAndType{OEQ, TUINT32}: ssa.OpEq32,
989 opAndType{OEQ, TINT64}: ssa.OpEq64,
990 opAndType{OEQ, TUINT64}: ssa.OpEq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -0700991 opAndType{OEQ, TINTER}: ssa.OpEqInter,
992 opAndType{OEQ, TARRAY}: ssa.OpEqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -0700993 opAndType{OEQ, TFUNC}: ssa.OpEqPtr,
994 opAndType{OEQ, TMAP}: ssa.OpEqPtr,
995 opAndType{OEQ, TCHAN}: ssa.OpEqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -0500996 opAndType{OEQ, TPTR64}: ssa.OpEqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -0700997 opAndType{OEQ, TUINTPTR}: ssa.OpEqPtr,
998 opAndType{OEQ, TUNSAFEPTR}: ssa.OpEqPtr,
David Chase8e601b22015-08-18 14:39:26 -0400999 opAndType{OEQ, TFLOAT64}: ssa.OpEq64F,
1000 opAndType{OEQ, TFLOAT32}: ssa.OpEq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001001
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001002 opAndType{ONE, TBOOL}: ssa.OpNeq8,
1003 opAndType{ONE, TINT8}: ssa.OpNeq8,
1004 opAndType{ONE, TUINT8}: ssa.OpNeq8,
1005 opAndType{ONE, TINT16}: ssa.OpNeq16,
1006 opAndType{ONE, TUINT16}: ssa.OpNeq16,
1007 opAndType{ONE, TINT32}: ssa.OpNeq32,
1008 opAndType{ONE, TUINT32}: ssa.OpNeq32,
1009 opAndType{ONE, TINT64}: ssa.OpNeq64,
1010 opAndType{ONE, TUINT64}: ssa.OpNeq64,
Keith Randall1e4ebfd2015-09-10 13:53:27 -07001011 opAndType{ONE, TINTER}: ssa.OpNeqInter,
1012 opAndType{ONE, TARRAY}: ssa.OpNeqSlice,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001013 opAndType{ONE, TFUNC}: ssa.OpNeqPtr,
1014 opAndType{ONE, TMAP}: ssa.OpNeqPtr,
1015 opAndType{ONE, TCHAN}: ssa.OpNeqPtr,
Todd Neal5fdd4fe2015-08-30 20:47:26 -05001016 opAndType{ONE, TPTR64}: ssa.OpNeqPtr,
Josh Bleecher Snyder1bab5b92015-07-28 14:14:25 -07001017 opAndType{ONE, TUINTPTR}: ssa.OpNeqPtr,
1018 opAndType{ONE, TUNSAFEPTR}: ssa.OpNeqPtr,
David Chase8e601b22015-08-18 14:39:26 -04001019 opAndType{ONE, TFLOAT64}: ssa.OpNeq64F,
1020 opAndType{ONE, TFLOAT32}: ssa.OpNeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001021
David Chase8e601b22015-08-18 14:39:26 -04001022 opAndType{OLT, TINT8}: ssa.OpLess8,
1023 opAndType{OLT, TUINT8}: ssa.OpLess8U,
1024 opAndType{OLT, TINT16}: ssa.OpLess16,
1025 opAndType{OLT, TUINT16}: ssa.OpLess16U,
1026 opAndType{OLT, TINT32}: ssa.OpLess32,
1027 opAndType{OLT, TUINT32}: ssa.OpLess32U,
1028 opAndType{OLT, TINT64}: ssa.OpLess64,
1029 opAndType{OLT, TUINT64}: ssa.OpLess64U,
1030 opAndType{OLT, TFLOAT64}: ssa.OpLess64F,
1031 opAndType{OLT, TFLOAT32}: ssa.OpLess32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001032
David Chase8e601b22015-08-18 14:39:26 -04001033 opAndType{OGT, TINT8}: ssa.OpGreater8,
1034 opAndType{OGT, TUINT8}: ssa.OpGreater8U,
1035 opAndType{OGT, TINT16}: ssa.OpGreater16,
1036 opAndType{OGT, TUINT16}: ssa.OpGreater16U,
1037 opAndType{OGT, TINT32}: ssa.OpGreater32,
1038 opAndType{OGT, TUINT32}: ssa.OpGreater32U,
1039 opAndType{OGT, TINT64}: ssa.OpGreater64,
1040 opAndType{OGT, TUINT64}: ssa.OpGreater64U,
1041 opAndType{OGT, TFLOAT64}: ssa.OpGreater64F,
1042 opAndType{OGT, TFLOAT32}: ssa.OpGreater32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001043
David Chase8e601b22015-08-18 14:39:26 -04001044 opAndType{OLE, TINT8}: ssa.OpLeq8,
1045 opAndType{OLE, TUINT8}: ssa.OpLeq8U,
1046 opAndType{OLE, TINT16}: ssa.OpLeq16,
1047 opAndType{OLE, TUINT16}: ssa.OpLeq16U,
1048 opAndType{OLE, TINT32}: ssa.OpLeq32,
1049 opAndType{OLE, TUINT32}: ssa.OpLeq32U,
1050 opAndType{OLE, TINT64}: ssa.OpLeq64,
1051 opAndType{OLE, TUINT64}: ssa.OpLeq64U,
1052 opAndType{OLE, TFLOAT64}: ssa.OpLeq64F,
1053 opAndType{OLE, TFLOAT32}: ssa.OpLeq32F,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001054
David Chase8e601b22015-08-18 14:39:26 -04001055 opAndType{OGE, TINT8}: ssa.OpGeq8,
1056 opAndType{OGE, TUINT8}: ssa.OpGeq8U,
1057 opAndType{OGE, TINT16}: ssa.OpGeq16,
1058 opAndType{OGE, TUINT16}: ssa.OpGeq16U,
1059 opAndType{OGE, TINT32}: ssa.OpGeq32,
1060 opAndType{OGE, TUINT32}: ssa.OpGeq32U,
1061 opAndType{OGE, TINT64}: ssa.OpGeq64,
1062 opAndType{OGE, TUINT64}: ssa.OpGeq64U,
1063 opAndType{OGE, TFLOAT64}: ssa.OpGeq64F,
1064 opAndType{OGE, TFLOAT32}: ssa.OpGeq32F,
David Chase40aba8c2015-08-05 22:11:14 -04001065
1066 opAndType{OLROT, TUINT8}: ssa.OpLrot8,
1067 opAndType{OLROT, TUINT16}: ssa.OpLrot16,
1068 opAndType{OLROT, TUINT32}: ssa.OpLrot32,
1069 opAndType{OLROT, TUINT64}: ssa.OpLrot64,
Keith Randalla329e212015-09-12 13:26:57 -07001070
1071 opAndType{OSQRT, TFLOAT64}: ssa.OpSqrt,
Keith Randall67fdb0d2015-07-19 15:48:20 -07001072}
1073
Keith Randall4304fbc2015-11-16 13:20:16 -08001074func (s *state) concreteEtype(t *Type) EType {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001075 e := t.Etype
1076 switch e {
1077 default:
1078 return e
Keith Randall67fdb0d2015-07-19 15:48:20 -07001079 case TINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001080 if s.config.IntSize == 8 {
1081 return TINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001082 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001083 return TINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001084 case TUINT:
Keith Randall2a5e6c42015-07-23 14:35:02 -07001085 if s.config.IntSize == 8 {
1086 return TUINT64
Keith Randall67fdb0d2015-07-19 15:48:20 -07001087 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001088 return TUINT32
1089 case TUINTPTR:
1090 if s.config.PtrSize == 8 {
1091 return TUINT64
1092 }
1093 return TUINT32
Keith Randall67fdb0d2015-07-19 15:48:20 -07001094 }
Keith Randall2a5e6c42015-07-23 14:35:02 -07001095}
1096
Keith Randall4304fbc2015-11-16 13:20:16 -08001097func (s *state) ssaOp(op Op, t *Type) ssa.Op {
Keith Randall2a5e6c42015-07-23 14:35:02 -07001098 etype := s.concreteEtype(t)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001099 x, ok := opToSSA[opAndType{op, etype}]
1100 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001101 s.Unimplementedf("unhandled binary op %s %s", opnames[op], Econv(etype))
Keith Randall67fdb0d2015-07-19 15:48:20 -07001102 }
1103 return x
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001104}
1105
David Chase3a9d0ac2015-08-28 14:24:10 -04001106func floatForComplex(t *Type) *Type {
1107 if t.Size() == 8 {
1108 return Types[TFLOAT32]
1109 } else {
1110 return Types[TFLOAT64]
1111 }
1112}
1113
Keith Randall4b803152015-07-29 17:07:09 -07001114type opAndTwoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001115 op Op
1116 etype1 EType
1117 etype2 EType
Keith Randall4b803152015-07-29 17:07:09 -07001118}
1119
David Chased052bbd2015-09-01 17:09:00 -04001120type twoTypes struct {
Keith Randall4304fbc2015-11-16 13:20:16 -08001121 etype1 EType
1122 etype2 EType
David Chased052bbd2015-09-01 17:09:00 -04001123}
1124
1125type twoOpsAndType struct {
1126 op1 ssa.Op
1127 op2 ssa.Op
Keith Randall4304fbc2015-11-16 13:20:16 -08001128 intermediateType EType
David Chased052bbd2015-09-01 17:09:00 -04001129}
1130
1131var fpConvOpToSSA = map[twoTypes]twoOpsAndType{
1132
1133 twoTypes{TINT8, TFLOAT32}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to32F, TINT32},
1134 twoTypes{TINT16, TFLOAT32}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to32F, TINT32},
1135 twoTypes{TINT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to32F, TINT32},
1136 twoTypes{TINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to32F, TINT64},
1137
1138 twoTypes{TINT8, TFLOAT64}: twoOpsAndType{ssa.OpSignExt8to32, ssa.OpCvt32to64F, TINT32},
1139 twoTypes{TINT16, TFLOAT64}: twoOpsAndType{ssa.OpSignExt16to32, ssa.OpCvt32to64F, TINT32},
1140 twoTypes{TINT32, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt32to64F, TINT32},
1141 twoTypes{TINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCvt64to64F, TINT64},
1142
1143 twoTypes{TFLOAT32, TINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1144 twoTypes{TFLOAT32, TINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1145 twoTypes{TFLOAT32, TINT32}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpCopy, TINT32},
1146 twoTypes{TFLOAT32, TINT64}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpCopy, TINT64},
1147
1148 twoTypes{TFLOAT64, TINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1149 twoTypes{TFLOAT64, TINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1150 twoTypes{TFLOAT64, TINT32}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpCopy, TINT32},
1151 twoTypes{TFLOAT64, TINT64}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpCopy, TINT64},
1152 // unsigned
1153 twoTypes{TUINT8, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to32F, TINT32},
1154 twoTypes{TUINT16, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to32F, TINT32},
1155 twoTypes{TUINT32, TFLOAT32}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to32F, TINT64}, // go wide to dodge unsigned
1156 twoTypes{TUINT64, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto32F, branchy code expansion instead
1157
1158 twoTypes{TUINT8, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt8to32, ssa.OpCvt32to64F, TINT32},
1159 twoTypes{TUINT16, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt16to32, ssa.OpCvt32to64F, TINT32},
1160 twoTypes{TUINT32, TFLOAT64}: twoOpsAndType{ssa.OpZeroExt32to64, ssa.OpCvt64to64F, TINT64}, // go wide to dodge unsigned
1161 twoTypes{TUINT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpInvalid, TUINT64}, // Cvt64Uto64F, branchy code expansion instead
1162
1163 twoTypes{TFLOAT32, TUINT8}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to8, TINT32},
1164 twoTypes{TFLOAT32, TUINT16}: twoOpsAndType{ssa.OpCvt32Fto32, ssa.OpTrunc32to16, TINT32},
1165 twoTypes{TFLOAT32, TUINT32}: twoOpsAndType{ssa.OpCvt32Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1166 twoTypes{TFLOAT32, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt32Fto64U, branchy code expansion instead
1167
1168 twoTypes{TFLOAT64, TUINT8}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to8, TINT32},
1169 twoTypes{TFLOAT64, TUINT16}: twoOpsAndType{ssa.OpCvt64Fto32, ssa.OpTrunc32to16, TINT32},
1170 twoTypes{TFLOAT64, TUINT32}: twoOpsAndType{ssa.OpCvt64Fto64, ssa.OpTrunc64to32, TINT64}, // go wide to dodge unsigned
1171 twoTypes{TFLOAT64, TUINT64}: twoOpsAndType{ssa.OpInvalid, ssa.OpCopy, TUINT64}, // Cvt64Fto64U, branchy code expansion instead
1172
1173 // float
1174 twoTypes{TFLOAT64, TFLOAT32}: twoOpsAndType{ssa.OpCvt64Fto32F, ssa.OpCopy, TFLOAT32},
1175 twoTypes{TFLOAT64, TFLOAT64}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT64},
1176 twoTypes{TFLOAT32, TFLOAT32}: twoOpsAndType{ssa.OpCopy, ssa.OpCopy, TFLOAT32},
1177 twoTypes{TFLOAT32, TFLOAT64}: twoOpsAndType{ssa.OpCvt32Fto64F, ssa.OpCopy, TFLOAT64},
1178}
1179
Keith Randall4b803152015-07-29 17:07:09 -07001180var shiftOpToSSA = map[opAndTwoTypes]ssa.Op{
1181 opAndTwoTypes{OLSH, TINT8, TUINT8}: ssa.OpLsh8x8,
1182 opAndTwoTypes{OLSH, TUINT8, TUINT8}: ssa.OpLsh8x8,
1183 opAndTwoTypes{OLSH, TINT8, TUINT16}: ssa.OpLsh8x16,
1184 opAndTwoTypes{OLSH, TUINT8, TUINT16}: ssa.OpLsh8x16,
1185 opAndTwoTypes{OLSH, TINT8, TUINT32}: ssa.OpLsh8x32,
1186 opAndTwoTypes{OLSH, TUINT8, TUINT32}: ssa.OpLsh8x32,
1187 opAndTwoTypes{OLSH, TINT8, TUINT64}: ssa.OpLsh8x64,
1188 opAndTwoTypes{OLSH, TUINT8, TUINT64}: ssa.OpLsh8x64,
1189
1190 opAndTwoTypes{OLSH, TINT16, TUINT8}: ssa.OpLsh16x8,
1191 opAndTwoTypes{OLSH, TUINT16, TUINT8}: ssa.OpLsh16x8,
1192 opAndTwoTypes{OLSH, TINT16, TUINT16}: ssa.OpLsh16x16,
1193 opAndTwoTypes{OLSH, TUINT16, TUINT16}: ssa.OpLsh16x16,
1194 opAndTwoTypes{OLSH, TINT16, TUINT32}: ssa.OpLsh16x32,
1195 opAndTwoTypes{OLSH, TUINT16, TUINT32}: ssa.OpLsh16x32,
1196 opAndTwoTypes{OLSH, TINT16, TUINT64}: ssa.OpLsh16x64,
1197 opAndTwoTypes{OLSH, TUINT16, TUINT64}: ssa.OpLsh16x64,
1198
1199 opAndTwoTypes{OLSH, TINT32, TUINT8}: ssa.OpLsh32x8,
1200 opAndTwoTypes{OLSH, TUINT32, TUINT8}: ssa.OpLsh32x8,
1201 opAndTwoTypes{OLSH, TINT32, TUINT16}: ssa.OpLsh32x16,
1202 opAndTwoTypes{OLSH, TUINT32, TUINT16}: ssa.OpLsh32x16,
1203 opAndTwoTypes{OLSH, TINT32, TUINT32}: ssa.OpLsh32x32,
1204 opAndTwoTypes{OLSH, TUINT32, TUINT32}: ssa.OpLsh32x32,
1205 opAndTwoTypes{OLSH, TINT32, TUINT64}: ssa.OpLsh32x64,
1206 opAndTwoTypes{OLSH, TUINT32, TUINT64}: ssa.OpLsh32x64,
1207
1208 opAndTwoTypes{OLSH, TINT64, TUINT8}: ssa.OpLsh64x8,
1209 opAndTwoTypes{OLSH, TUINT64, TUINT8}: ssa.OpLsh64x8,
1210 opAndTwoTypes{OLSH, TINT64, TUINT16}: ssa.OpLsh64x16,
1211 opAndTwoTypes{OLSH, TUINT64, TUINT16}: ssa.OpLsh64x16,
1212 opAndTwoTypes{OLSH, TINT64, TUINT32}: ssa.OpLsh64x32,
1213 opAndTwoTypes{OLSH, TUINT64, TUINT32}: ssa.OpLsh64x32,
1214 opAndTwoTypes{OLSH, TINT64, TUINT64}: ssa.OpLsh64x64,
1215 opAndTwoTypes{OLSH, TUINT64, TUINT64}: ssa.OpLsh64x64,
1216
1217 opAndTwoTypes{ORSH, TINT8, TUINT8}: ssa.OpRsh8x8,
1218 opAndTwoTypes{ORSH, TUINT8, TUINT8}: ssa.OpRsh8Ux8,
1219 opAndTwoTypes{ORSH, TINT8, TUINT16}: ssa.OpRsh8x16,
1220 opAndTwoTypes{ORSH, TUINT8, TUINT16}: ssa.OpRsh8Ux16,
1221 opAndTwoTypes{ORSH, TINT8, TUINT32}: ssa.OpRsh8x32,
1222 opAndTwoTypes{ORSH, TUINT8, TUINT32}: ssa.OpRsh8Ux32,
1223 opAndTwoTypes{ORSH, TINT8, TUINT64}: ssa.OpRsh8x64,
1224 opAndTwoTypes{ORSH, TUINT8, TUINT64}: ssa.OpRsh8Ux64,
1225
1226 opAndTwoTypes{ORSH, TINT16, TUINT8}: ssa.OpRsh16x8,
1227 opAndTwoTypes{ORSH, TUINT16, TUINT8}: ssa.OpRsh16Ux8,
1228 opAndTwoTypes{ORSH, TINT16, TUINT16}: ssa.OpRsh16x16,
1229 opAndTwoTypes{ORSH, TUINT16, TUINT16}: ssa.OpRsh16Ux16,
1230 opAndTwoTypes{ORSH, TINT16, TUINT32}: ssa.OpRsh16x32,
1231 opAndTwoTypes{ORSH, TUINT16, TUINT32}: ssa.OpRsh16Ux32,
1232 opAndTwoTypes{ORSH, TINT16, TUINT64}: ssa.OpRsh16x64,
1233 opAndTwoTypes{ORSH, TUINT16, TUINT64}: ssa.OpRsh16Ux64,
1234
1235 opAndTwoTypes{ORSH, TINT32, TUINT8}: ssa.OpRsh32x8,
1236 opAndTwoTypes{ORSH, TUINT32, TUINT8}: ssa.OpRsh32Ux8,
1237 opAndTwoTypes{ORSH, TINT32, TUINT16}: ssa.OpRsh32x16,
1238 opAndTwoTypes{ORSH, TUINT32, TUINT16}: ssa.OpRsh32Ux16,
1239 opAndTwoTypes{ORSH, TINT32, TUINT32}: ssa.OpRsh32x32,
1240 opAndTwoTypes{ORSH, TUINT32, TUINT32}: ssa.OpRsh32Ux32,
1241 opAndTwoTypes{ORSH, TINT32, TUINT64}: ssa.OpRsh32x64,
1242 opAndTwoTypes{ORSH, TUINT32, TUINT64}: ssa.OpRsh32Ux64,
1243
1244 opAndTwoTypes{ORSH, TINT64, TUINT8}: ssa.OpRsh64x8,
1245 opAndTwoTypes{ORSH, TUINT64, TUINT8}: ssa.OpRsh64Ux8,
1246 opAndTwoTypes{ORSH, TINT64, TUINT16}: ssa.OpRsh64x16,
1247 opAndTwoTypes{ORSH, TUINT64, TUINT16}: ssa.OpRsh64Ux16,
1248 opAndTwoTypes{ORSH, TINT64, TUINT32}: ssa.OpRsh64x32,
1249 opAndTwoTypes{ORSH, TUINT64, TUINT32}: ssa.OpRsh64Ux32,
1250 opAndTwoTypes{ORSH, TINT64, TUINT64}: ssa.OpRsh64x64,
1251 opAndTwoTypes{ORSH, TUINT64, TUINT64}: ssa.OpRsh64Ux64,
1252}
1253
Keith Randall4304fbc2015-11-16 13:20:16 -08001254func (s *state) ssaShiftOp(op Op, t *Type, u *Type) ssa.Op {
Keith Randall4b803152015-07-29 17:07:09 -07001255 etype1 := s.concreteEtype(t)
1256 etype2 := s.concreteEtype(u)
1257 x, ok := shiftOpToSSA[opAndTwoTypes{op, etype1, etype2}]
1258 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001259 s.Unimplementedf("unhandled shift op %s etype=%s/%s", opnames[op], Econv(etype1), Econv(etype2))
Keith Randall4b803152015-07-29 17:07:09 -07001260 }
1261 return x
1262}
1263
Keith Randall4304fbc2015-11-16 13:20:16 -08001264func (s *state) ssaRotateOp(op Op, t *Type) ssa.Op {
David Chase40aba8c2015-08-05 22:11:14 -04001265 etype1 := s.concreteEtype(t)
1266 x, ok := opToSSA[opAndType{op, etype1}]
1267 if !ok {
Keith Randall4304fbc2015-11-16 13:20:16 -08001268 s.Unimplementedf("unhandled rotate op %s etype=%s", opnames[op], Econv(etype1))
David Chase40aba8c2015-08-05 22:11:14 -04001269 }
1270 return x
1271}
1272
Keith Randalld2fd43a2015-04-15 15:51:25 -07001273// expr converts the expression n to ssa, adds it to s and returns the ssa result.
Keith Randallcfc2aa52015-05-18 16:44:20 -07001274func (s *state) expr(n *Node) *ssa.Value {
Michael Matloob81ccf502015-05-30 01:03:06 -04001275 s.pushLine(n.Lineno)
1276 defer s.popLine()
1277
Keith Randall06f32922015-07-11 11:39:12 -07001278 s.stmtList(n.Ninit)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001279 switch n.Op {
Todd Nealdef7c652015-09-07 19:07:02 -05001280 case OCFUNC:
Todd Neald076ef72015-10-15 20:25:32 -05001281 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Left.Sym})
Todd Nealdef7c652015-09-07 19:07:02 -05001282 return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
David Chase956f3192015-09-11 16:40:05 -04001283 case OPARAM:
David Chase57670ad2015-10-09 16:48:30 -04001284 addr := s.addr(n, false)
David Chase32ffbf72015-10-08 17:14:12 -04001285 return s.newValue2(ssa.OpLoad, n.Left.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001286 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07001287 if n.Class == PFUNC {
1288 // "value" of a function is the address of the function's closure
Keith Randall8c46aa52015-06-19 21:02:28 -07001289 sym := funcsym(n.Sym)
1290 aux := &ssa.ExternSymbol{n.Type, sym}
1291 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
Keith Randall23df95b2015-05-12 15:16:52 -07001292 }
Keith Randall290d8fc2015-06-10 15:03:06 -07001293 if canSSA(n) {
Keith Randall8c46aa52015-06-19 21:02:28 -07001294 return s.variable(n, n.Type)
Keith Randall290d8fc2015-06-10 15:03:06 -07001295 }
David Chase57670ad2015-10-09 16:48:30 -04001296 addr := s.addr(n, false)
Keith Randall8f22b522015-06-11 21:29:25 -07001297 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
David Chase956f3192015-09-11 16:40:05 -04001298 case OCLOSUREVAR:
David Chase57670ad2015-10-09 16:48:30 -04001299 addr := s.addr(n, false)
David Chase956f3192015-09-11 16:40:05 -04001300 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001301 case OLITERAL:
Keith Randalle707fbe2015-06-11 10:20:39 -07001302 switch n.Val().Ctype() {
Keith Randalld2fd43a2015-04-15 15:51:25 -07001303 case CTINT:
Keith Randall9cb332e2015-07-28 14:19:20 -07001304 i := Mpgetfix(n.Val().U.(*Mpint))
1305 switch n.Type.Size() {
1306 case 1:
1307 return s.constInt8(n.Type, int8(i))
1308 case 2:
1309 return s.constInt16(n.Type, int16(i))
1310 case 4:
1311 return s.constInt32(n.Type, int32(i))
1312 case 8:
1313 return s.constInt64(n.Type, i)
1314 default:
1315 s.Fatalf("bad integer size %d", n.Type.Size())
1316 return nil
1317 }
1318 case CTSTR:
1319 return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
1320 case CTBOOL:
Josh Bleecher Snydercea44142015-09-08 16:52:25 -07001321 return s.constBool(n.Val().U.(bool))
Brad Fitzpatrick337b7e72015-07-13 17:30:42 -06001322 case CTNIL:
Keith Randall9f954db2015-08-18 10:26:28 -07001323 t := n.Type
1324 switch {
1325 case t.IsSlice():
1326 return s.entryNewValue0(ssa.OpConstSlice, t)
1327 case t.IsInterface():
1328 return s.entryNewValue0(ssa.OpConstInterface, t)
1329 default:
1330 return s.entryNewValue0(ssa.OpConstNil, t)
1331 }
David Chase997a9f32015-08-12 16:38:11 -04001332 case CTFLT:
1333 f := n.Val().U.(*Mpflt)
1334 switch n.Type.Size() {
1335 case 4:
Todd Nealadba6c42015-09-08 07:50:25 -04001336 // -0.0 literals need to be treated as if they were 0.0, adding 0.0 here
1337 // accomplishes this while not affecting other values.
1338 return s.constFloat32(n.Type, mpgetflt32(f)+0.0)
David Chase997a9f32015-08-12 16:38:11 -04001339 case 8:
Todd Nealadba6c42015-09-08 07:50:25 -04001340 return s.constFloat64(n.Type, mpgetflt(f)+0.0)
David Chase997a9f32015-08-12 16:38:11 -04001341 default:
1342 s.Fatalf("bad float size %d", n.Type.Size())
1343 return nil
1344 }
David Chase52578582015-08-28 14:24:10 -04001345 case CTCPLX:
1346 c := n.Val().U.(*Mpcplx)
1347 r := &c.Real
1348 i := &c.Imag
1349 switch n.Type.Size() {
1350 case 8:
1351 {
1352 pt := Types[TFLOAT32]
Todd Nealadba6c42015-09-08 07:50:25 -04001353 // -0.0 literals need to be treated as if they were 0.0, adding 0.0 here
1354 // accomplishes this while not affecting other values.
David Chase52578582015-08-28 14:24:10 -04001355 return s.newValue2(ssa.OpComplexMake, n.Type,
Todd Nealadba6c42015-09-08 07:50:25 -04001356 s.constFloat32(pt, mpgetflt32(r)+0.0),
1357 s.constFloat32(pt, mpgetflt32(i)+0.0))
David Chase52578582015-08-28 14:24:10 -04001358 }
1359 case 16:
1360 {
1361 pt := Types[TFLOAT64]
1362 return s.newValue2(ssa.OpComplexMake, n.Type,
Todd Nealadba6c42015-09-08 07:50:25 -04001363 s.constFloat64(pt, mpgetflt(r)+0.0),
1364 s.constFloat64(pt, mpgetflt(i)+0.0))
David Chase52578582015-08-28 14:24:10 -04001365 }
1366 default:
1367 s.Fatalf("bad float size %d", n.Type.Size())
1368 return nil
1369 }
David Chase997a9f32015-08-12 16:38:11 -04001370
Keith Randalld2fd43a2015-04-15 15:51:25 -07001371 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001372 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001373 return nil
1374 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001375 case OCONVNOP:
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001376 to := n.Type
1377 from := n.Left.Type
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001378
1379 // Assume everything will work out, so set up our return value.
1380 // Anything interesting that happens from here is a fatal.
Keith Randall0ad9c8c2015-06-12 16:24:33 -07001381 x := s.expr(n.Left)
David Chasee99dd522015-10-19 11:36:07 -04001382
1383 // Special case for not confusing GC and liveness.
1384 // We don't want pointers accidentally classified
1385 // as not-pointers or vice-versa because of copy
1386 // elision.
1387 if to.IsPtr() != from.IsPtr() {
Keith Randall7807bda2015-11-10 15:35:36 -08001388 return s.newValue2(ssa.OpConvert, to, x, s.mem())
David Chasee99dd522015-10-19 11:36:07 -04001389 }
1390
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001391 v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
1392
Todd Nealdef7c652015-09-07 19:07:02 -05001393 // CONVNOP closure
1394 if to.Etype == TFUNC && from.IsPtr() {
1395 return v
1396 }
1397
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001398 // named <--> unnamed type or typed <--> untyped const
1399 if from.Etype == to.Etype {
1400 return v
1401 }
David Chasee99dd522015-10-19 11:36:07 -04001402
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001403 // unsafe.Pointer <--> *T
1404 if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
1405 return v
1406 }
1407
1408 dowidth(from)
1409 dowidth(to)
1410 if from.Width != to.Width {
1411 s.Fatalf("CONVNOP width mismatch %v (%d) -> %v (%d)\n", from, from.Width, to, to.Width)
1412 return nil
1413 }
1414 if etypesign(from.Etype) != etypesign(to.Etype) {
Keith Randall4304fbc2015-11-16 13:20:16 -08001415 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 -07001416 return nil
1417 }
1418
1419 if flag_race != 0 {
David Chase57670ad2015-10-09 16:48:30 -04001420 // These appear to be fine, but they fail the
1421 // integer constraint below, so okay them here.
1422 // Sample non-integer conversion: map[string]string -> *uint8
1423 return v
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001424 }
1425
1426 if etypesign(from.Etype) == 0 {
1427 s.Fatalf("CONVNOP unrecognized non-integer %v -> %v\n", from, to)
1428 return nil
1429 }
1430
1431 // integer, same width, same sign
1432 return v
1433
Michael Matloob73054f52015-06-14 11:38:46 -07001434 case OCONV:
1435 x := s.expr(n.Left)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001436 ft := n.Left.Type // from type
1437 tt := n.Type // to type
1438 if ft.IsInteger() && tt.IsInteger() {
1439 var op ssa.Op
1440 if tt.Size() == ft.Size() {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07001441 op = ssa.OpCopy
Keith Randall2a5e6c42015-07-23 14:35:02 -07001442 } else if tt.Size() < ft.Size() {
1443 // truncation
1444 switch 10*ft.Size() + tt.Size() {
1445 case 21:
1446 op = ssa.OpTrunc16to8
1447 case 41:
1448 op = ssa.OpTrunc32to8
1449 case 42:
1450 op = ssa.OpTrunc32to16
1451 case 81:
1452 op = ssa.OpTrunc64to8
1453 case 82:
1454 op = ssa.OpTrunc64to16
1455 case 84:
1456 op = ssa.OpTrunc64to32
1457 default:
1458 s.Fatalf("weird integer truncation %s -> %s", ft, tt)
1459 }
1460 } else if ft.IsSigned() {
1461 // sign extension
1462 switch 10*ft.Size() + tt.Size() {
1463 case 12:
1464 op = ssa.OpSignExt8to16
1465 case 14:
1466 op = ssa.OpSignExt8to32
1467 case 18:
1468 op = ssa.OpSignExt8to64
1469 case 24:
1470 op = ssa.OpSignExt16to32
1471 case 28:
1472 op = ssa.OpSignExt16to64
1473 case 48:
1474 op = ssa.OpSignExt32to64
1475 default:
1476 s.Fatalf("bad integer sign extension %s -> %s", ft, tt)
1477 }
1478 } else {
1479 // zero extension
1480 switch 10*ft.Size() + tt.Size() {
1481 case 12:
1482 op = ssa.OpZeroExt8to16
1483 case 14:
1484 op = ssa.OpZeroExt8to32
1485 case 18:
1486 op = ssa.OpZeroExt8to64
1487 case 24:
1488 op = ssa.OpZeroExt16to32
1489 case 28:
1490 op = ssa.OpZeroExt16to64
1491 case 48:
1492 op = ssa.OpZeroExt32to64
1493 default:
1494 s.Fatalf("weird integer sign extension %s -> %s", ft, tt)
1495 }
1496 }
1497 return s.newValue1(op, n.Type, x)
1498 }
David Chase42825882015-08-20 15:14:20 -04001499
David Chased052bbd2015-09-01 17:09:00 -04001500 if ft.IsFloat() || tt.IsFloat() {
1501 conv, ok := fpConvOpToSSA[twoTypes{s.concreteEtype(ft), s.concreteEtype(tt)}]
1502 if !ok {
1503 s.Fatalf("weird float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001504 }
David Chased052bbd2015-09-01 17:09:00 -04001505 op1, op2, it := conv.op1, conv.op2, conv.intermediateType
1506
1507 if op1 != ssa.OpInvalid && op2 != ssa.OpInvalid {
1508 // normal case, not tripping over unsigned 64
1509 if op1 == ssa.OpCopy {
1510 if op2 == ssa.OpCopy {
1511 return x
1512 }
1513 return s.newValue1(op2, n.Type, x)
1514 }
1515 if op2 == ssa.OpCopy {
1516 return s.newValue1(op1, n.Type, x)
1517 }
1518 return s.newValue1(op2, n.Type, s.newValue1(op1, Types[it], x))
1519 }
1520 // Tricky 64-bit unsigned cases.
1521 if ft.IsInteger() {
1522 // therefore tt is float32 or float64, and ft is also unsigned
David Chase42825882015-08-20 15:14:20 -04001523 if tt.Size() == 4 {
1524 return s.uint64Tofloat32(n, x, ft, tt)
1525 }
1526 if tt.Size() == 8 {
1527 return s.uint64Tofloat64(n, x, ft, tt)
1528 }
David Chased052bbd2015-09-01 17:09:00 -04001529 s.Fatalf("weird unsigned integer to float conversion %s -> %s", ft, tt)
David Chase42825882015-08-20 15:14:20 -04001530 }
David Chased052bbd2015-09-01 17:09:00 -04001531 // therefore ft is float32 or float64, and tt is unsigned integer
David Chase73151062015-08-26 14:25:40 -04001532 if ft.Size() == 4 {
David Chased052bbd2015-09-01 17:09:00 -04001533 return s.float32ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001534 }
David Chased052bbd2015-09-01 17:09:00 -04001535 if ft.Size() == 8 {
1536 return s.float64ToUint64(n, x, ft, tt)
David Chase73151062015-08-26 14:25:40 -04001537 }
David Chased052bbd2015-09-01 17:09:00 -04001538 s.Fatalf("weird float to unsigned integer conversion %s -> %s", ft, tt)
1539 return nil
David Chase42825882015-08-20 15:14:20 -04001540 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001541
1542 if ft.IsComplex() && tt.IsComplex() {
1543 var op ssa.Op
1544 if ft.Size() == tt.Size() {
1545 op = ssa.OpCopy
1546 } else if ft.Size() == 8 && tt.Size() == 16 {
1547 op = ssa.OpCvt32Fto64F
1548 } else if ft.Size() == 16 && tt.Size() == 8 {
1549 op = ssa.OpCvt64Fto32F
1550 } else {
1551 s.Fatalf("weird complex conversion %s -> %s", ft, tt)
1552 }
1553 ftp := floatForComplex(ft)
1554 ttp := floatForComplex(tt)
1555 return s.newValue2(ssa.OpComplexMake, tt,
1556 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexReal, ftp, x)),
1557 s.newValue1(op, ttp, s.newValue1(ssa.OpComplexImag, ftp, x)))
1558 }
David Chase42825882015-08-20 15:14:20 -04001559
Keith Randall4304fbc2015-11-16 13:20:16 -08001560 s.Unimplementedf("unhandled OCONV %s -> %s", Econv(n.Left.Type.Etype), Econv(n.Type.Etype))
Keith Randall2a5e6c42015-07-23 14:35:02 -07001561 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001562
Keith Randall269baa92015-09-17 10:31:16 -07001563 case ODOTTYPE:
1564 res, _ := s.dottype(n, false)
1565 return res
1566
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -07001567 // binary ops
1568 case OLT, OEQ, ONE, OLE, OGE, OGT:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001569 a := s.expr(n.Left)
1570 b := s.expr(n.Right)
Keith Randalldb380bf2015-09-10 11:05:42 -07001571 if n.Left.Type.IsComplex() {
Keith Randallc244ce02015-09-10 14:59:00 -07001572 pt := floatForComplex(n.Left.Type)
Keith Randalldb380bf2015-09-10 11:05:42 -07001573 op := s.ssaOp(OEQ, pt)
1574 r := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b))
1575 i := s.newValue2(op, Types[TBOOL], s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b))
1576 c := s.newValue2(ssa.OpAnd8, Types[TBOOL], r, i)
1577 switch n.Op {
1578 case OEQ:
1579 return c
1580 case ONE:
1581 return s.newValue1(ssa.OpNot, Types[TBOOL], c)
1582 default:
1583 s.Fatalf("ordered complex compare %s", opnames[n.Op])
1584 }
Keith Randalldb380bf2015-09-10 11:05:42 -07001585 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001586 return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b)
David Chase3a9d0ac2015-08-28 14:24:10 -04001587 case OMUL:
1588 a := s.expr(n.Left)
1589 b := s.expr(n.Right)
1590 if n.Type.IsComplex() {
1591 mulop := ssa.OpMul64F
1592 addop := ssa.OpAdd64F
1593 subop := ssa.OpSub64F
1594 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1595 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1596
1597 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1598 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1599 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1600 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1601
1602 if pt != wt { // Widen for calculation
1603 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1604 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1605 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1606 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1607 }
1608
1609 xreal := s.newValue2(subop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1610 ximag := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, bimag), s.newValue2(mulop, wt, aimag, breal))
1611
1612 if pt != wt { // Narrow to store back
1613 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1614 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1615 }
1616
1617 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1618 }
1619 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1620
1621 case ODIV:
1622 a := s.expr(n.Left)
1623 b := s.expr(n.Right)
1624 if n.Type.IsComplex() {
1625 // TODO this is not executed because the front-end substitutes a runtime call.
1626 // That probably ought to change; with modest optimization the widen/narrow
1627 // conversions could all be elided in larger expression trees.
1628 mulop := ssa.OpMul64F
1629 addop := ssa.OpAdd64F
1630 subop := ssa.OpSub64F
1631 divop := ssa.OpDiv64F
1632 pt := floatForComplex(n.Type) // Could be Float32 or Float64
1633 wt := Types[TFLOAT64] // Compute in Float64 to minimize cancellation error
1634
1635 areal := s.newValue1(ssa.OpComplexReal, pt, a)
1636 breal := s.newValue1(ssa.OpComplexReal, pt, b)
1637 aimag := s.newValue1(ssa.OpComplexImag, pt, a)
1638 bimag := s.newValue1(ssa.OpComplexImag, pt, b)
1639
1640 if pt != wt { // Widen for calculation
1641 areal = s.newValue1(ssa.OpCvt32Fto64F, wt, areal)
1642 breal = s.newValue1(ssa.OpCvt32Fto64F, wt, breal)
1643 aimag = s.newValue1(ssa.OpCvt32Fto64F, wt, aimag)
1644 bimag = s.newValue1(ssa.OpCvt32Fto64F, wt, bimag)
1645 }
1646
1647 denom := s.newValue2(addop, wt, s.newValue2(mulop, wt, breal, breal), s.newValue2(mulop, wt, bimag, bimag))
1648 xreal := s.newValue2(addop, wt, s.newValue2(mulop, wt, areal, breal), s.newValue2(mulop, wt, aimag, bimag))
1649 ximag := s.newValue2(subop, wt, s.newValue2(mulop, wt, aimag, breal), s.newValue2(mulop, wt, areal, bimag))
1650
1651 // TODO not sure if this is best done in wide precision or narrow
1652 // Double-rounding might be an issue.
1653 // Note that the pre-SSA implementation does the entire calculation
1654 // in wide format, so wide is compatible.
1655 xreal = s.newValue2(divop, wt, xreal, denom)
1656 ximag = s.newValue2(divop, wt, ximag, denom)
1657
1658 if pt != wt { // Narrow to store back
1659 xreal = s.newValue1(ssa.OpCvt64Fto32F, pt, xreal)
1660 ximag = s.newValue1(ssa.OpCvt64Fto32F, pt, ximag)
1661 }
David Chase3a9d0ac2015-08-28 14:24:10 -04001662 return s.newValue2(ssa.OpComplexMake, n.Type, xreal, ximag)
1663 }
David Chase18559e22015-10-28 13:55:46 -04001664 if n.Type.IsFloat() {
1665 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1666 } else {
1667 // do a size-appropriate check for zero
1668 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1669 s.check(cmp, panicdivide)
1670 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1671 }
1672 case OMOD:
1673 a := s.expr(n.Left)
1674 b := s.expr(n.Right)
1675 // do a size-appropriate check for zero
1676 cmp := s.newValue2(s.ssaOp(ONE, n.Type), Types[TBOOL], b, s.zeroVal(n.Type))
1677 s.check(cmp, panicdivide)
David Chase3a9d0ac2015-08-28 14:24:10 -04001678 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
1679 case OADD, OSUB:
1680 a := s.expr(n.Left)
1681 b := s.expr(n.Right)
1682 if n.Type.IsComplex() {
1683 pt := floatForComplex(n.Type)
1684 op := s.ssaOp(n.Op, pt)
1685 return s.newValue2(ssa.OpComplexMake, n.Type,
1686 s.newValue2(op, pt, s.newValue1(ssa.OpComplexReal, pt, a), s.newValue1(ssa.OpComplexReal, pt, b)),
1687 s.newValue2(op, pt, s.newValue1(ssa.OpComplexImag, pt, a), s.newValue1(ssa.OpComplexImag, pt, b)))
1688 }
1689 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
David Chase18559e22015-10-28 13:55:46 -04001690 case OAND, OOR, OHMUL, OXOR:
Keith Randalld2fd43a2015-04-15 15:51:25 -07001691 a := s.expr(n.Left)
1692 b := s.expr(n.Right)
Keith Randall67fdb0d2015-07-19 15:48:20 -07001693 return s.newValue2(s.ssaOp(n.Op, n.Type), a.Type, a, b)
Keith Randall4b803152015-07-29 17:07:09 -07001694 case OLSH, ORSH:
1695 a := s.expr(n.Left)
1696 b := s.expr(n.Right)
1697 return s.newValue2(s.ssaShiftOp(n.Op, n.Type, n.Right.Type), a.Type, a, b)
David Chase40aba8c2015-08-05 22:11:14 -04001698 case OLROT:
1699 a := s.expr(n.Left)
1700 i := n.Right.Int()
1701 if i <= 0 || i >= n.Type.Size()*8 {
1702 s.Fatalf("Wrong rotate distance for LROT, expected 1 through %d, saw %d", n.Type.Size()*8-1, i)
1703 }
1704 return s.newValue1I(s.ssaRotateOp(n.Op, n.Type), a.Type, i, a)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001705 case OANDAND, OOROR:
1706 // To implement OANDAND (and OOROR), we introduce a
1707 // new temporary variable to hold the result. The
1708 // variable is associated with the OANDAND node in the
1709 // s.vars table (normally variables are only
1710 // associated with ONAME nodes). We convert
1711 // A && B
1712 // to
1713 // var = A
1714 // if var {
1715 // var = B
1716 // }
1717 // Using var in the subsequent block introduces the
1718 // necessary phi variable.
1719 el := s.expr(n.Left)
1720 s.vars[n] = el
1721
1722 b := s.endBlock()
1723 b.Kind = ssa.BlockIf
1724 b.Control = el
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07001725 // In theory, we should set b.Likely here based on context.
1726 // However, gc only gives us likeliness hints
1727 // in a single place, for plain OIF statements,
1728 // and passing around context is finnicky, so don't bother for now.
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001729
1730 bRight := s.f.NewBlock(ssa.BlockPlain)
1731 bResult := s.f.NewBlock(ssa.BlockPlain)
1732 if n.Op == OANDAND {
Todd Neal47d67992015-08-28 21:36:29 -05001733 b.AddEdgeTo(bRight)
1734 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001735 } else if n.Op == OOROR {
Todd Neal47d67992015-08-28 21:36:29 -05001736 b.AddEdgeTo(bResult)
1737 b.AddEdgeTo(bRight)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001738 }
1739
1740 s.startBlock(bRight)
1741 er := s.expr(n.Right)
1742 s.vars[n] = er
1743
1744 b = s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05001745 b.AddEdgeTo(bResult)
Brad Fitzpatricke8167112015-07-10 12:58:53 -06001746
1747 s.startBlock(bResult)
Josh Bleecher Snyder35ad1fc2015-08-27 10:11:08 -07001748 return s.variable(n, Types[TBOOL])
Keith Randall7e390722015-09-12 14:14:02 -07001749 case OCOMPLEX:
1750 r := s.expr(n.Left)
1751 i := s.expr(n.Right)
1752 return s.newValue2(ssa.OpComplexMake, n.Type, r, i)
Keith Randalld2fd43a2015-04-15 15:51:25 -07001753
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001754 // unary ops
David Chase3a9d0ac2015-08-28 14:24:10 -04001755 case OMINUS:
1756 a := s.expr(n.Left)
1757 if n.Type.IsComplex() {
1758 tp := floatForComplex(n.Type)
1759 negop := s.ssaOp(n.Op, tp)
1760 return s.newValue2(ssa.OpComplexMake, n.Type,
1761 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexReal, tp, a)),
1762 s.newValue1(negop, tp, s.newValue1(ssa.OpComplexImag, tp, a)))
1763 }
1764 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randalla329e212015-09-12 13:26:57 -07001765 case ONOT, OCOM, OSQRT:
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001766 a := s.expr(n.Left)
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +02001767 return s.newValue1(s.ssaOp(n.Op, n.Type), a.Type, a)
Keith Randall2f518072015-09-10 11:37:09 -07001768 case OIMAG, OREAL:
1769 a := s.expr(n.Left)
1770 return s.newValue1(s.ssaOp(n.Op, n.Left.Type), n.Type, a)
Josh Bleecher Snyder4178f202015-09-05 19:28:00 -07001771 case OPLUS:
1772 return s.expr(n.Left)
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001773
Keith Randallcfc2aa52015-05-18 16:44:20 -07001774 case OADDR:
David Chase57670ad2015-10-09 16:48:30 -04001775 return s.addr(n.Left, n.Bounded)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001776
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07001777 case OINDREG:
1778 if int(n.Reg) != Thearch.REGSP {
1779 s.Unimplementedf("OINDREG of non-SP register %s in expr: %v", obj.Rconv(int(n.Reg)), n)
1780 return nil
1781 }
1782 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
1783 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
1784
Keith Randalld2fd43a2015-04-15 15:51:25 -07001785 case OIND:
1786 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001787 s.nilCheck(p)
Keith Randall8f22b522015-06-11 21:29:25 -07001788 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07001789
Keith Randallcd7e0592015-07-15 21:33:49 -07001790 case ODOT:
Keith Randall97035642015-10-09 09:33:29 -07001791 // TODO: fix when we can SSA struct types.
David Chase57670ad2015-10-09 16:48:30 -04001792 p := s.addr(n, false)
Keith Randall97035642015-10-09 09:33:29 -07001793 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcd7e0592015-07-15 21:33:49 -07001794
Keith Randalld2fd43a2015-04-15 15:51:25 -07001795 case ODOTPTR:
1796 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001797 s.nilCheck(p)
Keith Randall582baae2015-11-02 21:28:13 -08001798 p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(Types[TINT], n.Xoffset))
Keith Randall8f22b522015-06-11 21:29:25 -07001799 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -07001800
1801 case OINDEX:
Keith Randall97035642015-10-09 09:33:29 -07001802 switch {
1803 case n.Left.Type.IsString():
Keith Randallcfc2aa52015-05-18 16:44:20 -07001804 a := s.expr(n.Left)
1805 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07001806 i = s.extendIndex(i)
Keith Randall97035642015-10-09 09:33:29 -07001807 if !n.Bounded {
1808 len := s.newValue1(ssa.OpStringLen, Types[TINT], a)
1809 s.boundsCheck(i, len)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07001810 }
Keith Randall97035642015-10-09 09:33:29 -07001811 ptrtyp := Ptrto(Types[TUINT8])
1812 ptr := s.newValue1(ssa.OpStringPtr, ptrtyp, a)
1813 ptr = s.newValue2(ssa.OpAddPtr, ptrtyp, ptr, i)
1814 return s.newValue2(ssa.OpLoad, Types[TUINT8], ptr, s.mem())
1815 case n.Left.Type.IsSlice():
David Chase57670ad2015-10-09 16:48:30 -04001816 p := s.addr(n, false)
Keith Randall8f22b522015-06-11 21:29:25 -07001817 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
Keith Randall97035642015-10-09 09:33:29 -07001818 case n.Left.Type.IsArray():
1819 // TODO: fix when we can SSA arrays of length 1.
David Chase57670ad2015-10-09 16:48:30 -04001820 p := s.addr(n, false)
Keith Randall97035642015-10-09 09:33:29 -07001821 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
1822 default:
1823 s.Fatalf("bad type for index %v", n.Left.Type)
1824 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07001825 }
Keith Randalld2fd43a2015-04-15 15:51:25 -07001826
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001827 case OLEN, OCAP:
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001828 switch {
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001829 case n.Left.Type.IsSlice():
1830 op := ssa.OpSliceLen
1831 if n.Op == OCAP {
1832 op = ssa.OpSliceCap
1833 }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001834 return s.newValue1(op, Types[TINT], s.expr(n.Left))
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06001835 case n.Left.Type.IsString(): // string; not reachable for OCAP
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001836 return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left))
Todd Neal707af252015-08-28 15:56:43 -05001837 case n.Left.Type.IsMap(), n.Left.Type.IsChan():
1838 return s.referenceTypeBuiltin(n, s.expr(n.Left))
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001839 default: // array
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07001840 return s.constInt(Types[TINT], n.Left.Type.Bound)
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -07001841 }
1842
Josh Bleecher Snydera2d15802015-08-12 10:12:14 -07001843 case OSPTR:
1844 a := s.expr(n.Left)
1845 if n.Left.Type.IsSlice() {
1846 return s.newValue1(ssa.OpSlicePtr, n.Type, a)
1847 } else {
1848 return s.newValue1(ssa.OpStringPtr, n.Type, a)
1849 }
1850
Keith Randalld1c15a02015-08-04 15:47:22 -07001851 case OITAB:
1852 a := s.expr(n.Left)
1853 return s.newValue1(ssa.OpITab, n.Type, a)
1854
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07001855 case OEFACE:
1856 tab := s.expr(n.Left)
1857 data := s.expr(n.Right)
Keith Randall808d7c72015-10-07 14:35:25 -07001858 // The frontend allows putting things like struct{*byte} in
1859 // the data portion of an eface. But we don't want struct{*byte}
1860 // as a register type because (among other reasons) the liveness
1861 // analysis is confused by the "fat" variables that result from
1862 // such types being spilled.
1863 // So here we ensure that we are selecting the underlying pointer
1864 // when we build an eface.
1865 for !data.Type.IsPtr() {
1866 switch {
1867 case data.Type.IsArray():
1868 data = s.newValue2(ssa.OpArrayIndex, data.Type.Elem(), data, s.constInt(Types[TINT], 0))
1869 case data.Type.IsStruct():
1870 for i := data.Type.NumFields() - 1; i >= 0; i-- {
1871 f := data.Type.FieldType(i)
1872 if f.Size() == 0 {
1873 // eface type could also be struct{p *byte; q [0]int}
1874 continue
1875 }
1876 data = s.newValue1I(ssa.OpStructSelect, f, data.Type.FieldOff(i), data)
1877 break
1878 }
1879 default:
1880 s.Fatalf("type being put into an eface isn't a pointer")
1881 }
1882 }
Josh Bleecher Snyder1792b362015-09-05 19:28:27 -07001883 return s.newValue2(ssa.OpIMake, n.Type, tab, data)
1884
Keith Randall5505e8c2015-09-12 23:27:26 -07001885 case OSLICE, OSLICEARR:
1886 v := s.expr(n.Left)
1887 var i, j *ssa.Value
1888 if n.Right.Left != nil {
1889 i = s.extendIndex(s.expr(n.Right.Left))
1890 }
1891 if n.Right.Right != nil {
1892 j = s.extendIndex(s.expr(n.Right.Right))
1893 }
1894 p, l, c := s.slice(n.Left.Type, v, i, j, nil)
1895 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07001896 case OSLICESTR:
Keith Randall5505e8c2015-09-12 23:27:26 -07001897 v := s.expr(n.Left)
1898 var i, j *ssa.Value
1899 if n.Right.Left != nil {
1900 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07001901 }
Keith Randall5505e8c2015-09-12 23:27:26 -07001902 if n.Right.Right != nil {
1903 j = s.extendIndex(s.expr(n.Right.Right))
Keith Randall3526cf52015-08-24 23:52:03 -07001904 }
Keith Randall5505e8c2015-09-12 23:27:26 -07001905 p, l, _ := s.slice(n.Left.Type, v, i, j, nil)
1906 return s.newValue2(ssa.OpStringMake, n.Type, p, l)
1907 case OSLICE3, OSLICE3ARR:
1908 v := s.expr(n.Left)
1909 var i *ssa.Value
1910 if n.Right.Left != nil {
1911 i = s.extendIndex(s.expr(n.Right.Left))
Keith Randall3526cf52015-08-24 23:52:03 -07001912 }
Keith Randall5505e8c2015-09-12 23:27:26 -07001913 j := s.extendIndex(s.expr(n.Right.Right.Left))
1914 k := s.extendIndex(s.expr(n.Right.Right.Right))
1915 p, l, c := s.slice(n.Left.Type, v, i, j, k)
1916 return s.newValue3(ssa.OpSliceMake, n.Type, p, l, c)
Keith Randall3526cf52015-08-24 23:52:03 -07001917
Keith Randalld24768e2015-09-09 23:56:59 -07001918 case OCALLFUNC, OCALLINTER, OCALLMETH:
1919 return s.call(n, callNormal)
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07001920
1921 case OGETG:
Keith Randalld694f832015-10-19 18:54:40 -07001922 return s.newValue1(ssa.OpGetG, n.Type, s.mem())
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07001923
Keith Randall9d22c102015-09-11 11:02:57 -07001924 case OAPPEND:
1925 // append(s, e1, e2, e3). Compile like:
1926 // ptr,len,cap := s
1927 // newlen := len + 3
1928 // if newlen > s.cap {
1929 // ptr,_,cap = growslice(s, newlen)
1930 // }
1931 // *(ptr+len) = e1
1932 // *(ptr+len+1) = e2
1933 // *(ptr+len+2) = e3
1934 // makeslice(ptr,newlen,cap)
1935
1936 et := n.Type.Type
1937 pt := Ptrto(et)
1938
1939 // Evaluate slice
1940 slice := s.expr(n.List.N)
1941
Keith Randall9d22c102015-09-11 11:02:57 -07001942 // Allocate new blocks
1943 grow := s.f.NewBlock(ssa.BlockPlain)
Keith Randall9d22c102015-09-11 11:02:57 -07001944 assign := s.f.NewBlock(ssa.BlockPlain)
1945
1946 // Decide if we need to grow
Keith Randall9aba7e72015-10-05 13:48:40 -07001947 nargs := int64(count(n.List) - 1)
Keith Randall9d22c102015-09-11 11:02:57 -07001948 p := s.newValue1(ssa.OpSlicePtr, pt, slice)
1949 l := s.newValue1(ssa.OpSliceLen, Types[TINT], slice)
1950 c := s.newValue1(ssa.OpSliceCap, Types[TINT], slice)
1951 nl := s.newValue2(s.ssaOp(OADD, Types[TINT]), Types[TINT], l, s.constInt(Types[TINT], nargs))
1952 cmp := s.newValue2(s.ssaOp(OGT, Types[TINT]), Types[TBOOL], nl, c)
Keith Randallb32217a2015-09-17 16:45:10 -07001953 s.vars[&ptrVar] = p
1954 s.vars[&capVar] = c
Keith Randall9d22c102015-09-11 11:02:57 -07001955 b := s.endBlock()
1956 b.Kind = ssa.BlockIf
1957 b.Likely = ssa.BranchUnlikely
1958 b.Control = cmp
1959 b.AddEdgeTo(grow)
1960 b.AddEdgeTo(assign)
1961
1962 // Call growslice
1963 s.startBlock(grow)
1964 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(n.Type)}, s.sb)
1965
Keith Randall8c5bfcc2015-09-18 15:11:30 -07001966 r := s.rtcall(growslice, true, []*Type{pt, Types[TINT], Types[TINT]}, taddr, p, l, c, nl)
Keith Randall9d22c102015-09-11 11:02:57 -07001967
Keith Randall8c5bfcc2015-09-18 15:11:30 -07001968 s.vars[&ptrVar] = r[0]
1969 // Note: we don't need to read r[1], the result's length. It will be nl.
1970 // (or maybe we should, we just have to spill/restore nl otherwise?)
1971 s.vars[&capVar] = r[2]
Keith Randall9d22c102015-09-11 11:02:57 -07001972 b = s.endBlock()
1973 b.AddEdgeTo(assign)
1974
1975 // assign new elements to slots
1976 s.startBlock(assign)
Keith Randall9aba7e72015-10-05 13:48:40 -07001977
1978 // Evaluate args
1979 args := make([]*ssa.Value, 0, nargs)
Keith Randall808d7c72015-10-07 14:35:25 -07001980 store := make([]bool, 0, nargs)
Keith Randall9aba7e72015-10-05 13:48:40 -07001981 for l := n.List.Next; l != nil; l = l.Next {
Keith Randall808d7c72015-10-07 14:35:25 -07001982 if canSSAType(l.N.Type) {
1983 args = append(args, s.expr(l.N))
1984 store = append(store, true)
1985 } else {
David Chase57670ad2015-10-09 16:48:30 -04001986 args = append(args, s.addr(l.N, false))
Keith Randall808d7c72015-10-07 14:35:25 -07001987 store = append(store, false)
1988 }
Keith Randall9aba7e72015-10-05 13:48:40 -07001989 }
1990
Keith Randallb32217a2015-09-17 16:45:10 -07001991 p = s.variable(&ptrVar, pt) // generates phi for ptr
1992 c = s.variable(&capVar, Types[TINT]) // generates phi for cap
Keith Randall9d22c102015-09-11 11:02:57 -07001993 p2 := s.newValue2(ssa.OpPtrIndex, pt, p, l)
1994 for i, arg := range args {
Keith Randall582baae2015-11-02 21:28:13 -08001995 addr := s.newValue2(ssa.OpPtrIndex, pt, p2, s.constInt(Types[TINT], int64(i)))
Keith Randall808d7c72015-10-07 14:35:25 -07001996 if store[i] {
1997 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, et.Size(), addr, arg, s.mem())
1998 } else {
1999 s.vars[&memVar] = s.newValue3I(ssa.OpMove, ssa.TypeMem, et.Size(), addr, arg, s.mem())
2000 }
Keith Randall9d22c102015-09-11 11:02:57 -07002001 if haspointers(et) {
2002 // TODO: just one write barrier call for all of these writes?
Keith Randall4304fbc2015-11-16 13:20:16 -08002003 // TODO: maybe just one writeBarrier.enabled check?
David Chase729abfa2015-10-26 17:34:06 -04002004 s.insertWB(et, addr, n.Lineno)
Keith Randall9d22c102015-09-11 11:02:57 -07002005 }
2006 }
2007
2008 // make result
Keith Randallb32217a2015-09-17 16:45:10 -07002009 delete(s.vars, &ptrVar)
2010 delete(s.vars, &capVar)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002011 return s.newValue3(ssa.OpSliceMake, n.Type, p, nl, c)
Keith Randall9d22c102015-09-11 11:02:57 -07002012
Keith Randalld2fd43a2015-04-15 15:51:25 -07002013 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07002014 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -07002015 return nil
2016 }
2017}
2018
Keith Randall99187312015-11-02 16:56:53 -08002019// condBranch evaluates the boolean expression cond and branches to yes
2020// if cond is true and no if cond is false.
2021// This function is intended to handle && and || better than just calling
2022// s.expr(cond) and branching on the result.
2023func (s *state) condBranch(cond *Node, yes, no *ssa.Block, likely int8) {
2024 if cond.Op == OANDAND {
2025 mid := s.f.NewBlock(ssa.BlockPlain)
2026 s.stmtList(cond.Ninit)
2027 s.condBranch(cond.Left, mid, no, max8(likely, 0))
2028 s.startBlock(mid)
2029 s.condBranch(cond.Right, yes, no, likely)
2030 return
2031 // Note: if likely==1, then both recursive calls pass 1.
2032 // If likely==-1, then we don't have enough information to decide
2033 // whether the first branch is likely or not. So we pass 0 for
2034 // the likeliness of the first branch.
2035 // TODO: have the frontend give us branch prediction hints for
2036 // OANDAND and OOROR nodes (if it ever has such info).
2037 }
2038 if cond.Op == OOROR {
2039 mid := s.f.NewBlock(ssa.BlockPlain)
2040 s.stmtList(cond.Ninit)
2041 s.condBranch(cond.Left, yes, mid, min8(likely, 0))
2042 s.startBlock(mid)
2043 s.condBranch(cond.Right, yes, no, likely)
2044 return
2045 // Note: if likely==-1, then both recursive calls pass -1.
2046 // If likely==1, then we don't have enough info to decide
2047 // the likelihood of the first branch.
2048 }
Keith Randalld19bfc32015-11-03 09:30:17 -08002049 if cond.Op == ONOT {
2050 s.stmtList(cond.Ninit)
2051 s.condBranch(cond.Left, no, yes, -likely)
2052 return
2053 }
Keith Randall99187312015-11-02 16:56:53 -08002054 c := s.expr(cond)
2055 b := s.endBlock()
2056 b.Kind = ssa.BlockIf
2057 b.Control = c
2058 b.Likely = ssa.BranchPrediction(likely) // gc and ssa both use -1/0/+1 for likeliness
2059 b.AddEdgeTo(yes)
2060 b.AddEdgeTo(no)
2061}
2062
Keith Randallb386c342016-01-07 10:00:16 -08002063func (s *state) assign(left *Node, right *ssa.Value, wb bool, line int32) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002064 if left.Op == ONAME && isblank(left) {
Keith Randalld4cc51d2015-08-14 21:47:20 -07002065 return
2066 }
Keith Randalld4cc51d2015-08-14 21:47:20 -07002067 t := left.Type
2068 dowidth(t)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002069 if right == nil {
2070 // right == nil means use the zero value of the assigned type.
Daniel Morsing66b47812015-06-27 15:45:20 +01002071 if !canSSA(left) {
2072 // if we can't ssa this memory, treat it as just zeroing out the backing memory
David Chase57670ad2015-10-09 16:48:30 -04002073 addr := s.addr(left, false)
Keith Randalld2107fc2015-08-24 02:16:19 -07002074 if left.Op == ONAME {
Keith Randallb32217a2015-09-17 16:45:10 -07002075 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
Keith Randalld2107fc2015-08-24 02:16:19 -07002076 }
Keith Randallb32217a2015-09-17 16:45:10 -07002077 s.vars[&memVar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
Daniel Morsing66b47812015-06-27 15:45:20 +01002078 return
2079 }
Josh Bleecher Snyder07269312015-08-29 14:54:45 -07002080 right = s.zeroVal(t)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002081 }
2082 if left.Op == ONAME && canSSA(left) {
2083 // Update variable assignment.
Josh Bleecher Snyder07269312015-08-29 14:54:45 -07002084 s.vars[left] = right
Keith Randallc24681a2015-10-22 14:22:38 -07002085 s.addNamedValue(left, right)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002086 return
2087 }
2088 // not ssa-able. Treat as a store.
David Chase57670ad2015-10-09 16:48:30 -04002089 addr := s.addr(left, false)
Keith Randalld2107fc2015-08-24 02:16:19 -07002090 if left.Op == ONAME {
Keith Randallb32217a2015-09-17 16:45:10 -07002091 s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, ssa.TypeMem, left, s.mem())
Keith Randalld2107fc2015-08-24 02:16:19 -07002092 }
Keith Randallb32217a2015-09-17 16:45:10 -07002093 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, t.Size(), addr, right, s.mem())
Keith Randalle3869a62015-09-07 23:18:02 -07002094 if wb {
Keith Randallb386c342016-01-07 10:00:16 -08002095 s.insertWB(left.Type, addr, line)
Keith Randalle3869a62015-09-07 23:18:02 -07002096 }
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002097}
2098
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002099// zeroVal returns the zero value for type t.
2100func (s *state) zeroVal(t *Type) *ssa.Value {
2101 switch {
Keith Randall9cb332e2015-07-28 14:19:20 -07002102 case t.IsInteger():
2103 switch t.Size() {
2104 case 1:
2105 return s.constInt8(t, 0)
2106 case 2:
2107 return s.constInt16(t, 0)
2108 case 4:
2109 return s.constInt32(t, 0)
2110 case 8:
2111 return s.constInt64(t, 0)
2112 default:
2113 s.Fatalf("bad sized integer type %s", t)
2114 }
Todd Neal752fe4d2015-08-25 19:21:45 -05002115 case t.IsFloat():
2116 switch t.Size() {
2117 case 4:
2118 return s.constFloat32(t, 0)
2119 case 8:
2120 return s.constFloat64(t, 0)
2121 default:
2122 s.Fatalf("bad sized float type %s", t)
2123 }
David Chase52578582015-08-28 14:24:10 -04002124 case t.IsComplex():
2125 switch t.Size() {
2126 case 8:
2127 z := s.constFloat32(Types[TFLOAT32], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002128 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002129 case 16:
2130 z := s.constFloat64(Types[TFLOAT64], 0)
Keith Randalla5cffb62015-08-28 13:52:26 -07002131 return s.entryNewValue2(ssa.OpComplexMake, t, z, z)
David Chase52578582015-08-28 14:24:10 -04002132 default:
2133 s.Fatalf("bad sized complex type %s", t)
2134 }
2135
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002136 case t.IsString():
Keith Randall9cb332e2015-07-28 14:19:20 -07002137 return s.entryNewValue0A(ssa.OpConstString, t, "")
2138 case t.IsPtr():
2139 return s.entryNewValue0(ssa.OpConstNil, t)
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002140 case t.IsBoolean():
Josh Bleecher Snydercea44142015-09-08 16:52:25 -07002141 return s.constBool(false)
Keith Randall9f954db2015-08-18 10:26:28 -07002142 case t.IsInterface():
2143 return s.entryNewValue0(ssa.OpConstInterface, t)
2144 case t.IsSlice():
2145 return s.entryNewValue0(ssa.OpConstSlice, t)
Josh Bleecher Snyder21bd4832015-07-20 15:30:52 -07002146 }
2147 s.Unimplementedf("zero for type %v not implemented", t)
2148 return nil
2149}
2150
Keith Randalld24768e2015-09-09 23:56:59 -07002151type callKind int8
2152
2153const (
2154 callNormal callKind = iota
2155 callDefer
2156 callGo
2157)
2158
2159func (s *state) call(n *Node, k callKind) *ssa.Value {
2160 var sym *Sym // target symbol (if static)
2161 var closure *ssa.Value // ptr to closure to run (if dynamic)
2162 var codeptr *ssa.Value // ptr to target code (if dynamic)
2163 var rcvr *ssa.Value // receiver to set
2164 fn := n.Left
2165 switch n.Op {
2166 case OCALLFUNC:
2167 if k == callNormal && fn.Op == ONAME && fn.Class == PFUNC {
2168 sym = fn.Sym
2169 break
2170 }
2171 closure = s.expr(fn)
2172 if closure == nil {
2173 return nil // TODO: remove when expr always returns non-nil
2174 }
2175 case OCALLMETH:
2176 if fn.Op != ODOTMETH {
2177 Fatalf("OCALLMETH: n.Left not an ODOTMETH: %v", fn)
2178 }
2179 if fn.Right.Op != ONAME {
2180 Fatalf("OCALLMETH: n.Left.Right not a ONAME: %v", fn.Right)
2181 }
2182 if k == callNormal {
2183 sym = fn.Right.Sym
2184 break
2185 }
2186 n2 := *fn.Right
2187 n2.Class = PFUNC
2188 closure = s.expr(&n2)
2189 // Note: receiver is already assigned in n.List, so we don't
2190 // want to set it here.
2191 case OCALLINTER:
2192 if fn.Op != ODOTINTER {
2193 Fatalf("OCALLINTER: n.Left not an ODOTINTER: %v", Oconv(int(fn.Op), 0))
2194 }
2195 i := s.expr(fn.Left)
2196 itab := s.newValue1(ssa.OpITab, Types[TUINTPTR], i)
2197 itabidx := fn.Xoffset + 3*int64(Widthptr) + 8 // offset of fun field in runtime.itab
2198 itab = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], itabidx, itab)
2199 if k == callNormal {
2200 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], itab, s.mem())
2201 } else {
2202 closure = itab
2203 }
2204 rcvr = s.newValue1(ssa.OpIData, Types[TUINTPTR], i)
2205 }
2206 dowidth(fn.Type)
2207 stksize := fn.Type.Argwid // includes receiver
2208
2209 // Run all argument assignments. The arg slots have already
2210 // been offset by the appropriate amount (+2*widthptr for go/defer,
2211 // +widthptr for interface calls).
2212 // For OCALLMETH, the receiver is set in these statements.
2213 s.stmtList(n.List)
2214
2215 // Set receiver (for interface calls)
2216 if rcvr != nil {
Keith Randall7c4fbb62015-10-19 13:56:55 -07002217 argStart := Ctxt.FixedFrameSize()
Keith Randalld24768e2015-09-09 23:56:59 -07002218 if k != callNormal {
2219 argStart += int64(2 * Widthptr)
2220 }
2221 addr := s.entryNewValue1I(ssa.OpOffPtr, Types[TUINTPTR], argStart, s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002222 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, rcvr, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002223 }
2224
2225 // Defer/go args
2226 if k != callNormal {
2227 // Write argsize and closure (args to Newproc/Deferproc).
2228 argsize := s.constInt32(Types[TUINT32], int32(stksize))
Keith Randallb32217a2015-09-17 16:45:10 -07002229 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, 4, s.sp, argsize, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002230 addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(Types[TUINTPTR]), int64(Widthptr), s.sp)
Keith Randallb32217a2015-09-17 16:45:10 -07002231 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, int64(Widthptr), addr, closure, s.mem())
Keith Randalld24768e2015-09-09 23:56:59 -07002232 stksize += 2 * int64(Widthptr)
2233 }
2234
2235 // call target
2236 bNext := s.f.NewBlock(ssa.BlockPlain)
2237 var call *ssa.Value
2238 switch {
2239 case k == callDefer:
2240 call = s.newValue1(ssa.OpDeferCall, ssa.TypeMem, s.mem())
2241 case k == callGo:
2242 call = s.newValue1(ssa.OpGoCall, ssa.TypeMem, s.mem())
2243 case closure != nil:
2244 codeptr = s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem())
2245 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, codeptr, closure, s.mem())
2246 case codeptr != nil:
2247 call = s.newValue2(ssa.OpInterCall, ssa.TypeMem, codeptr, s.mem())
2248 case sym != nil:
2249 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, sym, s.mem())
2250 default:
2251 Fatalf("bad call type %s %v", opnames[n.Op], n)
2252 }
2253 call.AuxInt = stksize // Call operations carry the argsize of the callee along with them
2254
2255 // Finish call block
Keith Randallb32217a2015-09-17 16:45:10 -07002256 s.vars[&memVar] = call
Keith Randalld24768e2015-09-09 23:56:59 -07002257 b := s.endBlock()
2258 b.Kind = ssa.BlockCall
2259 b.Control = call
2260 b.AddEdgeTo(bNext)
2261
2262 // Read result from stack at the start of the fallthrough block
2263 s.startBlock(bNext)
2264 var titer Iter
2265 fp := Structfirst(&titer, Getoutarg(n.Left.Type))
2266 if fp == nil || k != callNormal {
2267 // call has no return value. Continue with the next statement.
2268 return nil
2269 }
2270 a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
2271 return s.newValue2(ssa.OpLoad, fp.Type, a, call)
2272}
2273
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002274// etypesign returns the signed-ness of e, for integer/pointer etypes.
2275// -1 means signed, +1 means unsigned, 0 means non-integer/non-pointer.
Keith Randall4304fbc2015-11-16 13:20:16 -08002276func etypesign(e EType) int8 {
Josh Bleecher Snyder95aff4d2015-07-28 14:31:25 -07002277 switch e {
2278 case TINT8, TINT16, TINT32, TINT64, TINT:
2279 return -1
2280 case TUINT8, TUINT16, TUINT32, TUINT64, TUINT, TUINTPTR, TUNSAFEPTR:
2281 return +1
2282 }
2283 return 0
2284}
2285
Todd Neald076ef72015-10-15 20:25:32 -05002286// lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
2287// This improves the effectiveness of cse by using the same Aux values for the
2288// same symbols.
2289func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
2290 switch sym.(type) {
2291 default:
2292 s.Fatalf("sym %v is of uknown type %T", sym, sym)
2293 case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
2294 // these are the only valid types
2295 }
2296
2297 if lsym, ok := s.varsyms[n]; ok {
2298 return lsym
2299 } else {
2300 s.varsyms[n] = sym
2301 return sym
2302 }
2303}
2304
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -07002305// 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 -07002306// The value that the returned Value represents is guaranteed to be non-nil.
David Chase57670ad2015-10-09 16:48:30 -04002307// If bounded is true then this address does not require a nil check for its operand
2308// even if that would otherwise be implied.
2309func (s *state) addr(n *Node, bounded bool) *ssa.Value {
Keith Randallc24681a2015-10-22 14:22:38 -07002310 t := Ptrto(n.Type)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002311 switch n.Op {
2312 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -07002313 switch n.Class {
2314 case PEXTERN:
Keith Randallcfc2aa52015-05-18 16:44:20 -07002315 // global variable
Todd Neal74180dd2015-10-27 21:35:48 -05002316 aux := s.lookupSymbol(n, &ssa.ExternSymbol{n.Type, n.Sym})
Keith Randallc24681a2015-10-22 14:22:38 -07002317 v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
Josh Bleecher Snyder67df7932015-07-28 11:08:44 -07002318 // TODO: Make OpAddr use AuxInt as well as Aux.
2319 if n.Xoffset != 0 {
2320 v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
2321 }
2322 return v
David Chase956f3192015-09-11 16:40:05 -04002323 case PPARAM:
2324 // parameter slot
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002325 v := s.decladdrs[n]
Keith Randall4304fbc2015-11-16 13:20:16 -08002326 if v != nil {
2327 return v
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -07002328 }
Keith Randall4304fbc2015-11-16 13:20:16 -08002329 if n.String() == ".fp" {
2330 // Special arg that points to the frame pointer.
2331 // (Used by the race detector, others?)
2332 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
2333 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
2334 }
2335 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
2336 return nil
Keith Randalld2107fc2015-08-24 02:16:19 -07002337 case PAUTO:
2338 // We need to regenerate the address of autos
2339 // at every use. This prevents LEA instructions
2340 // from occurring before the corresponding VarDef
2341 // op and confusing the liveness analysis into thinking
2342 // the variable is live at function entry.
2343 // TODO: I'm not sure if this really works or we're just
2344 // getting lucky. We might need a real dependency edge
2345 // between vardef and addr ops.
2346 aux := &ssa.AutoSymbol{Typ: n.Type, Node: n}
Keith Randallc24681a2015-10-22 14:22:38 -07002347 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002348 case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
Todd Neald076ef72015-10-15 20:25:32 -05002349 // ensure that we reuse symbols for out parameters so
2350 // that cse works on their addresses
2351 aux := s.lookupSymbol(n, &ssa.ArgSymbol{Typ: n.Type, Node: n})
Keith Randallc24681a2015-10-22 14:22:38 -07002352 return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase956f3192015-09-11 16:40:05 -04002353 case PAUTO | PHEAP, PPARAM | PHEAP, PPARAMOUT | PHEAP, PPARAMREF:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +01002354 return s.expr(n.Name.Heapaddr)
Keith Randall290d8fc2015-06-10 15:03:06 -07002355 default:
Josh Bleecher Snyder58446032015-08-23 20:29:43 -07002356 s.Unimplementedf("variable address class %v not implemented", n.Class)
Keith Randall290d8fc2015-06-10 15:03:06 -07002357 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -07002358 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002359 case OINDREG:
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002360 // indirect off a register
Keith Randallcfc2aa52015-05-18 16:44:20 -07002361 // used for storing/loading arguments/returns to/from callees
Josh Bleecher Snyder25d19162015-07-28 12:37:46 -07002362 if int(n.Reg) != Thearch.REGSP {
2363 s.Unimplementedf("OINDREG of non-SP register %s in addr: %v", obj.Rconv(int(n.Reg)), n)
2364 return nil
2365 }
Keith Randallc24681a2015-10-22 14:22:38 -07002366 return s.entryNewValue1I(ssa.OpOffPtr, t, n.Xoffset, s.sp)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002367 case OINDEX:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002368 if n.Left.Type.IsSlice() {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002369 a := s.expr(n.Left)
2370 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002371 i = s.extendIndex(i)
Keith Randallc24681a2015-10-22 14:22:38 -07002372 len := s.newValue1(ssa.OpSliceLen, Types[TINT], a)
Keith Randall46e62f82015-08-18 14:17:30 -07002373 if !n.Bounded {
2374 s.boundsCheck(i, len)
2375 }
Keith Randallc24681a2015-10-22 14:22:38 -07002376 p := s.newValue1(ssa.OpSlicePtr, t, a)
2377 return s.newValue2(ssa.OpPtrIndex, t, p, i)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002378 } else { // array
David Chase57670ad2015-10-09 16:48:30 -04002379 a := s.addr(n.Left, bounded)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002380 i := s.expr(n.Right)
Keith Randall2a5e6c42015-07-23 14:35:02 -07002381 i = s.extendIndex(i)
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07002382 len := s.constInt(Types[TINT], n.Left.Type.Bound)
Keith Randall46e62f82015-08-18 14:17:30 -07002383 if !n.Bounded {
2384 s.boundsCheck(i, len)
2385 }
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06002386 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002387 }
Todd Nealb383de22015-07-13 21:22:16 -05002388 case OIND:
2389 p := s.expr(n.Left)
David Chase57670ad2015-10-09 16:48:30 -04002390 if !bounded {
2391 s.nilCheck(p)
2392 }
Todd Nealb383de22015-07-13 21:22:16 -05002393 return p
Keith Randallc3c84a22015-07-13 15:55:37 -07002394 case ODOT:
David Chase57670ad2015-10-09 16:48:30 -04002395 p := s.addr(n.Left, bounded)
Keith Randall582baae2015-11-02 21:28:13 -08002396 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
Keith Randallc3c84a22015-07-13 15:55:37 -07002397 case ODOTPTR:
2398 p := s.expr(n.Left)
David Chase57670ad2015-10-09 16:48:30 -04002399 if !bounded {
2400 s.nilCheck(p)
2401 }
Keith Randall582baae2015-11-02 21:28:13 -08002402 return s.newValue2(ssa.OpAddPtr, t, p, s.constInt(Types[TINT], n.Xoffset))
David Chase956f3192015-09-11 16:40:05 -04002403 case OCLOSUREVAR:
Keith Randallc24681a2015-10-22 14:22:38 -07002404 return s.newValue2(ssa.OpAddPtr, t,
Keith Randall129261a2015-10-27 10:15:02 -07002405 s.entryNewValue0(ssa.OpGetClosurePtr, Ptrto(Types[TUINT8])),
Keith Randall582baae2015-11-02 21:28:13 -08002406 s.constInt(Types[TINT], n.Xoffset))
David Chase32ffbf72015-10-08 17:14:12 -04002407 case OPARAM:
2408 p := n.Left
2409 if p.Op != ONAME || !(p.Class == PPARAM|PHEAP || p.Class == PPARAMOUT|PHEAP) {
2410 s.Fatalf("OPARAM not of ONAME,{PPARAM,PPARAMOUT}|PHEAP, instead %s", nodedump(p, 0))
2411 }
2412
2413 // Recover original offset to address passed-in param value.
2414 original_p := *p
2415 original_p.Xoffset = n.Xoffset
2416 aux := &ssa.ArgSymbol{Typ: n.Type, Node: &original_p}
Keith Randallc24681a2015-10-22 14:22:38 -07002417 return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
David Chase57670ad2015-10-09 16:48:30 -04002418 case OCONVNOP:
2419 addr := s.addr(n.Left, bounded)
Keith Randallc24681a2015-10-22 14:22:38 -07002420 return s.newValue1(ssa.OpCopy, t, addr) // ensure that addr has the right type
David Chase57670ad2015-10-09 16:48:30 -04002421
Keith Randallcfc2aa52015-05-18 16:44:20 -07002422 default:
Josh Bleecher Snyder58446032015-08-23 20:29:43 -07002423 s.Unimplementedf("unhandled addr %v", Oconv(int(n.Op), 0))
Keith Randallcfc2aa52015-05-18 16:44:20 -07002424 return nil
2425 }
2426}
2427
Keith Randall290d8fc2015-06-10 15:03:06 -07002428// canSSA reports whether n is SSA-able.
2429// n must be an ONAME.
2430func canSSA(n *Node) bool {
2431 if n.Op != ONAME {
Daniel Morsing66b47812015-06-27 15:45:20 +01002432 return false
Keith Randall290d8fc2015-06-10 15:03:06 -07002433 }
2434 if n.Addrtaken {
2435 return false
2436 }
2437 if n.Class&PHEAP != 0 {
2438 return false
2439 }
Josh Bleecher Snyder96548732015-08-28 13:35:32 -07002440 switch n.Class {
2441 case PEXTERN, PPARAMOUT, PPARAMREF:
Keith Randall290d8fc2015-06-10 15:03:06 -07002442 return false
2443 }
Keith Randall8a1f6212015-09-08 21:28:44 -07002444 if n.Class == PPARAM && n.String() == ".this" {
2445 // wrappers generated by genwrapper need to update
2446 // the .this pointer in place.
2447 return false
2448 }
Keith Randall9f954db2015-08-18 10:26:28 -07002449 return canSSAType(n.Type)
2450 // TODO: try to make more variables SSAable?
2451}
2452
2453// canSSA reports whether variables of type t are SSA-able.
2454func canSSAType(t *Type) bool {
2455 dowidth(t)
2456 if t.Width > int64(4*Widthptr) {
2457 // 4*Widthptr is an arbitrary constant. We want it
2458 // to be at least 3*Widthptr so slices can be registerized.
2459 // Too big and we'll introduce too much register pressure.
Daniel Morsing66b47812015-06-27 15:45:20 +01002460 return false
2461 }
Keith Randall9f954db2015-08-18 10:26:28 -07002462 switch t.Etype {
2463 case TARRAY:
2464 if Isslice(t) {
2465 return true
2466 }
2467 // We can't do arrays because dynamic indexing is
2468 // not supported on SSA variables.
2469 // TODO: maybe allow if length is <=1? All indexes
2470 // are constant? Might be good for the arrays
2471 // introduced by the compiler for variadic functions.
2472 return false
2473 case TSTRUCT:
2474 if countfield(t) > 4 {
2475 // 4 is an arbitrary constant. Same reasoning
2476 // as above, lots of small fields would waste
2477 // register space needed by other values.
2478 return false
2479 }
2480 for t1 := t.Type; t1 != nil; t1 = t1.Down {
2481 if !canSSAType(t1.Type) {
2482 return false
2483 }
2484 }
2485 return false // until it is implemented
2486 //return true
2487 default:
2488 return true
2489 }
Keith Randall290d8fc2015-06-10 15:03:06 -07002490}
2491
Keith Randallcfc2aa52015-05-18 16:44:20 -07002492// nilCheck generates nil pointer checking code.
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002493// Starts a new block on return, unless nil checks are disabled.
Josh Bleecher Snyder7e74e432015-07-24 11:55:52 -07002494// Used only for automatically inserted nil checks,
2495// not for user code like 'x != nil'.
Keith Randallcfc2aa52015-05-18 16:44:20 -07002496func (s *state) nilCheck(ptr *ssa.Value) {
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002497 if Disable_checknil != 0 {
2498 return
2499 }
Keith Randall31115a52015-10-23 19:12:49 -07002500 chk := s.newValue2(ssa.OpNilCheck, ssa.TypeVoid, ptr, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -07002501 b := s.endBlock()
Keith Randall31115a52015-10-23 19:12:49 -07002502 b.Kind = ssa.BlockCheck
2503 b.Control = chk
Keith Randallcfc2aa52015-05-18 16:44:20 -07002504 bNext := s.f.NewBlock(ssa.BlockPlain)
Todd Neal47d67992015-08-28 21:36:29 -05002505 b.AddEdgeTo(bNext)
Josh Bleecher Snyder463858e2015-08-11 09:47:45 -07002506 s.startBlock(bNext)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002507}
2508
2509// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
2510// Starts a new block on return.
2511func (s *state) boundsCheck(idx, len *ssa.Value) {
Keith Randall8d236812015-08-18 15:25:40 -07002512 if Debug['B'] != 0 {
2513 return
2514 }
Keith Randallcfc2aa52015-05-18 16:44:20 -07002515 // TODO: convert index to full width?
2516 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2517
2518 // bounds check
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07002519 cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002520 s.check(cmp, Panicindex)
Keith Randall3526cf52015-08-24 23:52:03 -07002521}
2522
2523// sliceBoundsCheck generates slice bounds checking code. Checks if 0 <= idx <= len, branches to exit if not.
2524// Starts a new block on return.
2525func (s *state) sliceBoundsCheck(idx, len *ssa.Value) {
2526 if Debug['B'] != 0 {
2527 return
2528 }
2529 // TODO: convert index to full width?
2530 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
2531
2532 // bounds check
2533 cmp := s.newValue2(ssa.OpIsSliceInBounds, Types[TBOOL], idx, len)
Keith Randall3a70bf92015-09-17 16:54:15 -07002534 s.check(cmp, panicslice)
Keith Randall3526cf52015-08-24 23:52:03 -07002535}
2536
Keith Randall3a70bf92015-09-17 16:54:15 -07002537// If cmp (a bool) is true, panic using the given function.
2538func (s *state) check(cmp *ssa.Value, fn *Node) {
Keith Randallcfc2aa52015-05-18 16:44:20 -07002539 b := s.endBlock()
2540 b.Kind = ssa.BlockIf
2541 b.Control = cmp
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07002542 b.Likely = ssa.BranchLikely
Keith Randallcfc2aa52015-05-18 16:44:20 -07002543 bNext := s.f.NewBlock(ssa.BlockPlain)
Keith Randall74e568f2015-11-09 21:35:40 -08002544 line := s.peekLine()
2545 bPanic := s.panics[funcLine{fn, line}]
2546 if bPanic == nil {
2547 bPanic = s.f.NewBlock(ssa.BlockPlain)
2548 s.panics[funcLine{fn, line}] = bPanic
2549 s.startBlock(bPanic)
2550 // The panic call takes/returns memory to ensure that the right
2551 // memory state is observed if the panic happens.
2552 s.rtcall(fn, false, nil)
2553 }
Todd Neal47d67992015-08-28 21:36:29 -05002554 b.AddEdgeTo(bNext)
2555 b.AddEdgeTo(bPanic)
Keith Randallcfc2aa52015-05-18 16:44:20 -07002556 s.startBlock(bNext)
2557}
2558
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002559// rtcall issues a call to the given runtime function fn with the listed args.
2560// Returns a slice of results of the given result types.
2561// The call is added to the end of the current block.
2562// If returns is false, the block is marked as an exit block.
2563// If returns is true, the block is marked as a call block. A new block
2564// is started to load the return values.
2565func (s *state) rtcall(fn *Node, returns bool, results []*Type, args ...*ssa.Value) []*ssa.Value {
2566 // Write args to the stack
2567 var off int64 // TODO: arch-dependent starting offset?
2568 for _, arg := range args {
2569 t := arg.Type
2570 off = Rnd(off, t.Alignment())
2571 ptr := s.sp
2572 if off != 0 {
2573 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2574 }
2575 size := t.Size()
2576 s.vars[&memVar] = s.newValue3I(ssa.OpStore, ssa.TypeMem, size, ptr, arg, s.mem())
2577 off += size
2578 }
2579 off = Rnd(off, int64(Widthptr))
2580
2581 // Issue call
2582 call := s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, fn.Sym, s.mem())
2583 s.vars[&memVar] = call
2584
2585 // Finish block
2586 b := s.endBlock()
2587 if !returns {
2588 b.Kind = ssa.BlockExit
2589 b.Control = call
2590 call.AuxInt = off
2591 if len(results) > 0 {
2592 Fatalf("panic call can't have results")
2593 }
2594 return nil
2595 }
2596 b.Kind = ssa.BlockCall
2597 b.Control = call
2598 bNext := s.f.NewBlock(ssa.BlockPlain)
2599 b.AddEdgeTo(bNext)
2600 s.startBlock(bNext)
2601
2602 // Load results
2603 res := make([]*ssa.Value, len(results))
2604 for i, t := range results {
2605 off = Rnd(off, t.Alignment())
2606 ptr := s.sp
2607 if off != 0 {
2608 ptr = s.newValue1I(ssa.OpOffPtr, Types[TUINTPTR], off, s.sp)
2609 }
2610 res[i] = s.newValue2(ssa.OpLoad, t, ptr, s.mem())
2611 off += t.Size()
2612 }
2613 off = Rnd(off, int64(Widthptr))
2614
2615 // Remember how much callee stack space we needed.
2616 call.AuxInt = off
2617
2618 return res
2619}
2620
Keith Randall9d22c102015-09-11 11:02:57 -07002621// insertWB inserts a write barrier. A value of type t has already
2622// been stored at location p. Tell the runtime about this write.
2623// Note: there must be no GC suspension points between the write and
2624// the call that this function inserts.
David Chase729abfa2015-10-26 17:34:06 -04002625func (s *state) insertWB(t *Type, p *ssa.Value, line int32) {
Keith Randall4304fbc2015-11-16 13:20:16 -08002626 // if writeBarrier.enabled {
Keith Randall9d22c102015-09-11 11:02:57 -07002627 // typedmemmove_nostore(&t, p)
2628 // }
2629 bThen := s.f.NewBlock(ssa.BlockPlain)
Keith Randall9d22c102015-09-11 11:02:57 -07002630
Keith Randall4304fbc2015-11-16 13:20:16 -08002631 aux := &ssa.ExternSymbol{Types[TBOOL], syslook("writeBarrier", 0).Sym}
Keith Randall9d22c102015-09-11 11:02:57 -07002632 flagaddr := s.newValue1A(ssa.OpAddr, Ptrto(Types[TBOOL]), aux, s.sb)
Keith Randall4304fbc2015-11-16 13:20:16 -08002633 // TODO: select the .enabled field. It is currently first, so not needed for now.
Keith Randall9d22c102015-09-11 11:02:57 -07002634 flag := s.newValue2(ssa.OpLoad, Types[TBOOL], flagaddr, s.mem())
2635 b := s.endBlock()
2636 b.Kind = ssa.BlockIf
2637 b.Likely = ssa.BranchUnlikely
2638 b.Control = flag
2639 b.AddEdgeTo(bThen)
Keith Randall9d22c102015-09-11 11:02:57 -07002640
2641 s.startBlock(bThen)
2642 // TODO: writebarrierptr_nostore if just one pointer word (or a few?)
2643 taddr := s.newValue1A(ssa.OpAddr, Types[TUINTPTR], &ssa.ExternSymbol{Types[TUINTPTR], typenamesym(t)}, s.sb)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002644 s.rtcall(typedmemmove_nostore, true, nil, taddr, p)
Keith Randall9d22c102015-09-11 11:02:57 -07002645
David Chase729abfa2015-10-26 17:34:06 -04002646 if Debug_wb > 0 {
2647 Warnl(int(line), "write barrier")
2648 }
2649
Keith Randall8c5bfcc2015-09-18 15:11:30 -07002650 b.AddEdgeTo(s.curBlock)
Keith Randall9d22c102015-09-11 11:02:57 -07002651}
2652
Keith Randall5505e8c2015-09-12 23:27:26 -07002653// slice computes the slice v[i:j:k] and returns ptr, len, and cap of result.
2654// i,j,k may be nil, in which case they are set to their default value.
2655// t is a slice, ptr to array, or string type.
2656func (s *state) slice(t *Type, v, i, j, k *ssa.Value) (p, l, c *ssa.Value) {
2657 var elemtype *Type
2658 var ptrtype *Type
2659 var ptr *ssa.Value
2660 var len *ssa.Value
2661 var cap *ssa.Value
2662 zero := s.constInt(Types[TINT], 0)
2663 switch {
2664 case t.IsSlice():
2665 elemtype = t.Type
2666 ptrtype = Ptrto(elemtype)
2667 ptr = s.newValue1(ssa.OpSlicePtr, ptrtype, v)
2668 len = s.newValue1(ssa.OpSliceLen, Types[TINT], v)
2669 cap = s.newValue1(ssa.OpSliceCap, Types[TINT], v)
2670 case t.IsString():
2671 elemtype = Types[TUINT8]
2672 ptrtype = Ptrto(elemtype)
2673 ptr = s.newValue1(ssa.OpStringPtr, ptrtype, v)
2674 len = s.newValue1(ssa.OpStringLen, Types[TINT], v)
2675 cap = len
2676 case t.IsPtr():
2677 if !t.Type.IsArray() {
2678 s.Fatalf("bad ptr to array in slice %v\n", t)
2679 }
2680 elemtype = t.Type.Type
2681 ptrtype = Ptrto(elemtype)
2682 s.nilCheck(v)
2683 ptr = v
2684 len = s.constInt(Types[TINT], t.Type.Bound)
2685 cap = len
2686 default:
2687 s.Fatalf("bad type in slice %v\n", t)
2688 }
2689
2690 // Set default values
2691 if i == nil {
2692 i = zero
2693 }
2694 if j == nil {
2695 j = len
2696 }
2697 if k == nil {
2698 k = cap
2699 }
2700
2701 // Panic if slice indices are not in bounds.
2702 s.sliceBoundsCheck(i, j)
2703 if j != k {
2704 s.sliceBoundsCheck(j, k)
2705 }
2706 if k != cap {
2707 s.sliceBoundsCheck(k, cap)
2708 }
2709
2710 // Generate the following code assuming that indexes are in bounds.
2711 // The conditional is to make sure that we don't generate a slice
2712 // that points to the next object in memory.
Keith Randall582baae2015-11-02 21:28:13 -08002713 // rlen = (Sub64 j i)
2714 // rcap = (Sub64 k i)
Keith Randall5505e8c2015-09-12 23:27:26 -07002715 // p = ptr
2716 // if rcap != 0 {
Keith Randall582baae2015-11-02 21:28:13 -08002717 // p = (AddPtr ptr (Mul64 low (Const64 size)))
Keith Randall5505e8c2015-09-12 23:27:26 -07002718 // }
2719 // result = (SliceMake p size)
Keith Randall582baae2015-11-02 21:28:13 -08002720 subOp := s.ssaOp(OSUB, Types[TINT])
2721 neqOp := s.ssaOp(ONE, Types[TINT])
2722 mulOp := s.ssaOp(OMUL, Types[TINT])
2723 rlen := s.newValue2(subOp, Types[TINT], j, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07002724 var rcap *ssa.Value
2725 switch {
2726 case t.IsString():
2727 // Capacity of the result is unimportant. However, we use
2728 // rcap to test if we've generated a zero-length slice.
2729 // Use length of strings for that.
2730 rcap = rlen
2731 case j == k:
2732 rcap = rlen
2733 default:
Keith Randall582baae2015-11-02 21:28:13 -08002734 rcap = s.newValue2(subOp, Types[TINT], k, i)
Keith Randall5505e8c2015-09-12 23:27:26 -07002735 }
2736
Keith Randallb32217a2015-09-17 16:45:10 -07002737 s.vars[&ptrVar] = ptr
Keith Randall5505e8c2015-09-12 23:27:26 -07002738
2739 // Generate code to test the resulting slice length.
Keith Randall582baae2015-11-02 21:28:13 -08002740 cmp := s.newValue2(neqOp, Types[TBOOL], rcap, s.constInt(Types[TINT], 0))
Keith Randall5505e8c2015-09-12 23:27:26 -07002741
2742 b := s.endBlock()
2743 b.Kind = ssa.BlockIf
2744 b.Likely = ssa.BranchLikely
2745 b.Control = cmp
2746
2747 // Generate code for non-zero length slice case.
2748 nz := s.f.NewBlock(ssa.BlockPlain)
2749 b.AddEdgeTo(nz)
2750 s.startBlock(nz)
2751 var inc *ssa.Value
2752 if elemtype.Width == 1 {
2753 inc = i
2754 } else {
Keith Randall582baae2015-11-02 21:28:13 -08002755 inc = s.newValue2(mulOp, Types[TINT], i, s.constInt(Types[TINT], elemtype.Width))
Keith Randall5505e8c2015-09-12 23:27:26 -07002756 }
Keith Randallb32217a2015-09-17 16:45:10 -07002757 s.vars[&ptrVar] = s.newValue2(ssa.OpAddPtr, ptrtype, ptr, inc)
Keith Randall5505e8c2015-09-12 23:27:26 -07002758 s.endBlock()
2759
2760 // All done.
2761 merge := s.f.NewBlock(ssa.BlockPlain)
2762 b.AddEdgeTo(merge)
2763 nz.AddEdgeTo(merge)
2764 s.startBlock(merge)
Keith Randallb32217a2015-09-17 16:45:10 -07002765 rptr := s.variable(&ptrVar, ptrtype)
2766 delete(s.vars, &ptrVar)
Keith Randall5505e8c2015-09-12 23:27:26 -07002767 return rptr, rlen, rcap
2768}
2769
David Chase42825882015-08-20 15:14:20 -04002770type u2fcvtTab struct {
2771 geq, cvt2F, and, rsh, or, add ssa.Op
2772 one func(*state, ssa.Type, int64) *ssa.Value
2773}
2774
2775var u64_f64 u2fcvtTab = u2fcvtTab{
2776 geq: ssa.OpGeq64,
2777 cvt2F: ssa.OpCvt64to64F,
2778 and: ssa.OpAnd64,
2779 rsh: ssa.OpRsh64Ux64,
2780 or: ssa.OpOr64,
2781 add: ssa.OpAdd64F,
2782 one: (*state).constInt64,
2783}
2784
2785var u64_f32 u2fcvtTab = u2fcvtTab{
2786 geq: ssa.OpGeq64,
2787 cvt2F: ssa.OpCvt64to32F,
2788 and: ssa.OpAnd64,
2789 rsh: ssa.OpRsh64Ux64,
2790 or: ssa.OpOr64,
2791 add: ssa.OpAdd32F,
2792 one: (*state).constInt64,
2793}
2794
2795// Excess generality on a machine with 64-bit integer registers.
2796// Not used on AMD64.
2797var u32_f32 u2fcvtTab = u2fcvtTab{
2798 geq: ssa.OpGeq32,
2799 cvt2F: ssa.OpCvt32to32F,
2800 and: ssa.OpAnd32,
2801 rsh: ssa.OpRsh32Ux32,
2802 or: ssa.OpOr32,
2803 add: ssa.OpAdd32F,
2804 one: func(s *state, t ssa.Type, x int64) *ssa.Value {
2805 return s.constInt32(t, int32(x))
2806 },
2807}
2808
2809func (s *state) uint64Tofloat64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2810 return s.uintTofloat(&u64_f64, n, x, ft, tt)
2811}
2812
2813func (s *state) uint64Tofloat32(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2814 return s.uintTofloat(&u64_f32, n, x, ft, tt)
2815}
2816
2817func (s *state) uintTofloat(cvttab *u2fcvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2818 // if x >= 0 {
2819 // result = (floatY) x
2820 // } else {
2821 // y = uintX(x) ; y = x & 1
2822 // z = uintX(x) ; z = z >> 1
2823 // z = z >> 1
2824 // z = z | y
David Chase73151062015-08-26 14:25:40 -04002825 // result = floatY(z)
2826 // result = result + result
David Chase42825882015-08-20 15:14:20 -04002827 // }
2828 //
2829 // Code borrowed from old code generator.
2830 // What's going on: large 64-bit "unsigned" looks like
2831 // negative number to hardware's integer-to-float
2832 // conversion. However, because the mantissa is only
2833 // 63 bits, we don't need the LSB, so instead we do an
2834 // unsigned right shift (divide by two), convert, and
2835 // double. However, before we do that, we need to be
2836 // sure that we do not lose a "1" if that made the
2837 // difference in the resulting rounding. Therefore, we
2838 // preserve it, and OR (not ADD) it back in. The case
2839 // that matters is when the eleven discarded bits are
2840 // equal to 10000000001; that rounds up, and the 1 cannot
2841 // be lost else it would round down if the LSB of the
2842 // candidate mantissa is 0.
2843 cmp := s.newValue2(cvttab.geq, Types[TBOOL], x, s.zeroVal(ft))
2844 b := s.endBlock()
2845 b.Kind = ssa.BlockIf
2846 b.Control = cmp
2847 b.Likely = ssa.BranchLikely
2848
2849 bThen := s.f.NewBlock(ssa.BlockPlain)
2850 bElse := s.f.NewBlock(ssa.BlockPlain)
2851 bAfter := s.f.NewBlock(ssa.BlockPlain)
2852
Todd Neal47d67992015-08-28 21:36:29 -05002853 b.AddEdgeTo(bThen)
David Chase42825882015-08-20 15:14:20 -04002854 s.startBlock(bThen)
2855 a0 := s.newValue1(cvttab.cvt2F, tt, x)
2856 s.vars[n] = a0
2857 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05002858 bThen.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04002859
Todd Neal47d67992015-08-28 21:36:29 -05002860 b.AddEdgeTo(bElse)
David Chase42825882015-08-20 15:14:20 -04002861 s.startBlock(bElse)
2862 one := cvttab.one(s, ft, 1)
2863 y := s.newValue2(cvttab.and, ft, x, one)
2864 z := s.newValue2(cvttab.rsh, ft, x, one)
2865 z = s.newValue2(cvttab.or, ft, z, y)
2866 a := s.newValue1(cvttab.cvt2F, tt, z)
2867 a1 := s.newValue2(cvttab.add, tt, a, a)
2868 s.vars[n] = a1
2869 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05002870 bElse.AddEdgeTo(bAfter)
David Chase42825882015-08-20 15:14:20 -04002871
2872 s.startBlock(bAfter)
2873 return s.variable(n, n.Type)
2874}
2875
Todd Neal707af252015-08-28 15:56:43 -05002876// referenceTypeBuiltin generates code for the len/cap builtins for maps and channels.
2877func (s *state) referenceTypeBuiltin(n *Node, x *ssa.Value) *ssa.Value {
2878 if !n.Left.Type.IsMap() && !n.Left.Type.IsChan() {
2879 s.Fatalf("node must be a map or a channel")
2880 }
Todd Neale0e40682015-08-26 18:40:52 -05002881 // if n == nil {
2882 // return 0
2883 // } else {
Todd Neal707af252015-08-28 15:56:43 -05002884 // // len
Todd Neale0e40682015-08-26 18:40:52 -05002885 // return *((*int)n)
Todd Neal707af252015-08-28 15:56:43 -05002886 // // cap
2887 // return *(((*int)n)+1)
Todd Neale0e40682015-08-26 18:40:52 -05002888 // }
2889 lenType := n.Type
Todd Neal67ac8a32015-08-28 15:20:54 -05002890 nilValue := s.newValue0(ssa.OpConstNil, Types[TUINTPTR])
2891 cmp := s.newValue2(ssa.OpEqPtr, Types[TBOOL], x, nilValue)
Todd Neale0e40682015-08-26 18:40:52 -05002892 b := s.endBlock()
2893 b.Kind = ssa.BlockIf
2894 b.Control = cmp
2895 b.Likely = ssa.BranchUnlikely
2896
2897 bThen := s.f.NewBlock(ssa.BlockPlain)
2898 bElse := s.f.NewBlock(ssa.BlockPlain)
2899 bAfter := s.f.NewBlock(ssa.BlockPlain)
2900
Todd Neal707af252015-08-28 15:56:43 -05002901 // length/capacity of a nil map/chan is zero
Todd Neal47d67992015-08-28 21:36:29 -05002902 b.AddEdgeTo(bThen)
Todd Neale0e40682015-08-26 18:40:52 -05002903 s.startBlock(bThen)
2904 s.vars[n] = s.zeroVal(lenType)
2905 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05002906 bThen.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05002907
Todd Neal47d67992015-08-28 21:36:29 -05002908 b.AddEdgeTo(bElse)
Todd Neale0e40682015-08-26 18:40:52 -05002909 s.startBlock(bElse)
Todd Neal707af252015-08-28 15:56:43 -05002910 if n.Op == OLEN {
2911 // length is stored in the first word for map/chan
2912 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, x, s.mem())
2913 } else if n.Op == OCAP {
2914 // capacity is stored in the second word for chan
2915 sw := s.newValue1I(ssa.OpOffPtr, lenType.PtrTo(), lenType.Width, x)
2916 s.vars[n] = s.newValue2(ssa.OpLoad, lenType, sw, s.mem())
2917 } else {
2918 s.Fatalf("op must be OLEN or OCAP")
2919 }
Todd Neale0e40682015-08-26 18:40:52 -05002920 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05002921 bElse.AddEdgeTo(bAfter)
Todd Neale0e40682015-08-26 18:40:52 -05002922
2923 s.startBlock(bAfter)
2924 return s.variable(n, lenType)
2925}
2926
David Chase73151062015-08-26 14:25:40 -04002927type f2uCvtTab struct {
2928 ltf, cvt2U, subf ssa.Op
2929 value func(*state, ssa.Type, float64) *ssa.Value
2930}
2931
2932var f32_u64 f2uCvtTab = f2uCvtTab{
2933 ltf: ssa.OpLess32F,
2934 cvt2U: ssa.OpCvt32Fto64,
2935 subf: ssa.OpSub32F,
2936 value: (*state).constFloat32,
2937}
2938
2939var f64_u64 f2uCvtTab = f2uCvtTab{
2940 ltf: ssa.OpLess64F,
2941 cvt2U: ssa.OpCvt64Fto64,
2942 subf: ssa.OpSub64F,
2943 value: (*state).constFloat64,
2944}
2945
2946func (s *state) float32ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2947 return s.floatToUint(&f32_u64, n, x, ft, tt)
2948}
2949func (s *state) float64ToUint64(n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2950 return s.floatToUint(&f64_u64, n, x, ft, tt)
2951}
2952
2953func (s *state) floatToUint(cvttab *f2uCvtTab, n *Node, x *ssa.Value, ft, tt *Type) *ssa.Value {
2954 // if x < 9223372036854775808.0 {
2955 // result = uintY(x)
2956 // } else {
2957 // y = x - 9223372036854775808.0
2958 // z = uintY(y)
2959 // result = z | -9223372036854775808
2960 // }
2961 twoToThe63 := cvttab.value(s, ft, 9223372036854775808.0)
2962 cmp := s.newValue2(cvttab.ltf, Types[TBOOL], x, twoToThe63)
2963 b := s.endBlock()
2964 b.Kind = ssa.BlockIf
2965 b.Control = cmp
2966 b.Likely = ssa.BranchLikely
2967
2968 bThen := s.f.NewBlock(ssa.BlockPlain)
2969 bElse := s.f.NewBlock(ssa.BlockPlain)
2970 bAfter := s.f.NewBlock(ssa.BlockPlain)
2971
Todd Neal47d67992015-08-28 21:36:29 -05002972 b.AddEdgeTo(bThen)
David Chase73151062015-08-26 14:25:40 -04002973 s.startBlock(bThen)
2974 a0 := s.newValue1(cvttab.cvt2U, tt, x)
2975 s.vars[n] = a0
2976 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05002977 bThen.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04002978
Todd Neal47d67992015-08-28 21:36:29 -05002979 b.AddEdgeTo(bElse)
David Chase73151062015-08-26 14:25:40 -04002980 s.startBlock(bElse)
2981 y := s.newValue2(cvttab.subf, ft, x, twoToThe63)
2982 y = s.newValue1(cvttab.cvt2U, tt, y)
2983 z := s.constInt64(tt, -9223372036854775808)
2984 a1 := s.newValue2(ssa.OpOr64, tt, y, z)
2985 s.vars[n] = a1
2986 s.endBlock()
Todd Neal47d67992015-08-28 21:36:29 -05002987 bElse.AddEdgeTo(bAfter)
David Chase73151062015-08-26 14:25:40 -04002988
2989 s.startBlock(bAfter)
2990 return s.variable(n, n.Type)
2991}
2992
Keith Randall269baa92015-09-17 10:31:16 -07002993// ifaceType returns the value for the word containing the type.
2994// n is the node for the interface expression.
2995// v is the corresponding value.
2996func (s *state) ifaceType(n *Node, v *ssa.Value) *ssa.Value {
2997 byteptr := Ptrto(Types[TUINT8]) // type used in runtime prototypes for runtime type (*byte)
2998
2999 if isnilinter(n.Type) {
3000 // Have *eface. The type is the first word in the struct.
3001 return s.newValue1(ssa.OpITab, byteptr, v)
3002 }
3003
3004 // Have *iface.
3005 // The first word in the struct is the *itab.
3006 // If the *itab is nil, return 0.
3007 // Otherwise, the second word in the *itab is the type.
3008
3009 tab := s.newValue1(ssa.OpITab, byteptr, v)
3010 s.vars[&typVar] = tab
3011 isnonnil := s.newValue2(ssa.OpNeqPtr, Types[TBOOL], tab, s.entryNewValue0(ssa.OpConstNil, byteptr))
3012 b := s.endBlock()
3013 b.Kind = ssa.BlockIf
3014 b.Control = isnonnil
3015 b.Likely = ssa.BranchLikely
3016
3017 bLoad := s.f.NewBlock(ssa.BlockPlain)
3018 bEnd := s.f.NewBlock(ssa.BlockPlain)
3019
3020 b.AddEdgeTo(bLoad)
3021 b.AddEdgeTo(bEnd)
3022 bLoad.AddEdgeTo(bEnd)
3023
3024 s.startBlock(bLoad)
3025 off := s.newValue1I(ssa.OpOffPtr, byteptr, int64(Widthptr), tab)
3026 s.vars[&typVar] = s.newValue2(ssa.OpLoad, byteptr, off, s.mem())
3027 s.endBlock()
3028
3029 s.startBlock(bEnd)
3030 typ := s.variable(&typVar, byteptr)
3031 delete(s.vars, &typVar)
3032 return typ
3033}
3034
3035// dottype generates SSA for a type assertion node.
3036// commaok indicates whether to panic or return a bool.
3037// If commaok is false, resok will be nil.
3038func (s *state) dottype(n *Node, commaok bool) (res, resok *ssa.Value) {
3039 iface := s.expr(n.Left)
3040 typ := s.ifaceType(n.Left, iface) // actual concrete type
3041 target := s.expr(typename(n.Type)) // target type
3042 if !isdirectiface(n.Type) {
3043 // walk rewrites ODOTTYPE/OAS2DOTTYPE into runtime calls except for this case.
3044 Fatalf("dottype needs a direct iface type %s", n.Type)
3045 }
3046
David Chase729abfa2015-10-26 17:34:06 -04003047 if Debug_typeassert > 0 {
3048 Warnl(int(n.Lineno), "type assertion inlined")
3049 }
3050
Keith Randall269baa92015-09-17 10:31:16 -07003051 // TODO: If we have a nonempty interface and its itab field is nil,
3052 // then this test is redundant and ifaceType should just branch directly to bFail.
3053 cond := s.newValue2(ssa.OpEqPtr, Types[TBOOL], typ, target)
3054 b := s.endBlock()
3055 b.Kind = ssa.BlockIf
3056 b.Control = cond
3057 b.Likely = ssa.BranchLikely
3058
3059 byteptr := Ptrto(Types[TUINT8])
3060
3061 bOk := s.f.NewBlock(ssa.BlockPlain)
3062 bFail := s.f.NewBlock(ssa.BlockPlain)
3063 b.AddEdgeTo(bOk)
3064 b.AddEdgeTo(bFail)
3065
3066 if !commaok {
3067 // on failure, panic by calling panicdottype
3068 s.startBlock(bFail)
Keith Randall269baa92015-09-17 10:31:16 -07003069 taddr := s.newValue1A(ssa.OpAddr, byteptr, &ssa.ExternSymbol{byteptr, typenamesym(n.Left.Type)}, s.sb)
Keith Randall8c5bfcc2015-09-18 15:11:30 -07003070 s.rtcall(panicdottype, false, nil, typ, target, taddr)
Keith Randall269baa92015-09-17 10:31:16 -07003071
3072 // on success, return idata field
3073 s.startBlock(bOk)
3074 return s.newValue1(ssa.OpIData, n.Type, iface), nil
3075 }
3076
3077 // commaok is the more complicated case because we have
3078 // a control flow merge point.
3079 bEnd := s.f.NewBlock(ssa.BlockPlain)
3080
3081 // type assertion succeeded
3082 s.startBlock(bOk)
3083 s.vars[&idataVar] = s.newValue1(ssa.OpIData, n.Type, iface)
3084 s.vars[&okVar] = s.constBool(true)
3085 s.endBlock()
3086 bOk.AddEdgeTo(bEnd)
3087
3088 // type assertion failed
3089 s.startBlock(bFail)
3090 s.vars[&idataVar] = s.entryNewValue0(ssa.OpConstNil, byteptr)
3091 s.vars[&okVar] = s.constBool(false)
3092 s.endBlock()
3093 bFail.AddEdgeTo(bEnd)
3094
3095 // merge point
3096 s.startBlock(bEnd)
3097 res = s.variable(&idataVar, byteptr)
3098 resok = s.variable(&okVar, Types[TBOOL])
3099 delete(s.vars, &idataVar)
3100 delete(s.vars, &okVar)
3101 return res, resok
3102}
3103
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003104// checkgoto checks that a goto from from to to does not
3105// jump into a block or jump over variable declarations.
3106// It is a copy of checkgoto in the pre-SSA backend,
3107// modified only for line number handling.
3108// TODO: document how this works and why it is designed the way it is.
3109func (s *state) checkgoto(from *Node, to *Node) {
3110 if from.Sym == to.Sym {
3111 return
3112 }
3113
3114 nf := 0
3115 for fs := from.Sym; fs != nil; fs = fs.Link {
3116 nf++
3117 }
3118 nt := 0
3119 for fs := to.Sym; fs != nil; fs = fs.Link {
3120 nt++
3121 }
3122 fs := from.Sym
3123 for ; nf > nt; nf-- {
3124 fs = fs.Link
3125 }
3126 if fs != to.Sym {
3127 // decide what to complain about.
3128 // prefer to complain about 'into block' over declarations,
3129 // so scan backward to find most recent block or else dcl.
3130 var block *Sym
3131
3132 var dcl *Sym
3133 ts := to.Sym
3134 for ; nt > nf; nt-- {
3135 if ts.Pkg == nil {
3136 block = ts
3137 } else {
3138 dcl = ts
3139 }
3140 ts = ts.Link
3141 }
3142
3143 for ts != fs {
3144 if ts.Pkg == nil {
3145 block = ts
3146 } else {
3147 dcl = ts
3148 }
3149 ts = ts.Link
3150 fs = fs.Link
3151 }
3152
3153 lno := int(from.Left.Lineno)
3154 if block != nil {
3155 yyerrorl(lno, "goto %v jumps into block starting at %v", from.Left.Sym, Ctxt.Line(int(block.Lastlineno)))
3156 } else {
3157 yyerrorl(lno, "goto %v jumps over declaration of %v at %v", from.Left.Sym, dcl, Ctxt.Line(int(dcl.Lastlineno)))
3158 }
3159 }
3160}
3161
Keith Randalld2fd43a2015-04-15 15:51:25 -07003162// variable returns the value of a variable at the current location.
Keith Randall8c46aa52015-06-19 21:02:28 -07003163func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003164 v := s.vars[name]
3165 if v == nil {
3166 // TODO: get type? Take Sym as arg?
Keith Randall8f22b522015-06-11 21:29:25 -07003167 v = s.newValue0A(ssa.OpFwdRef, t, name)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003168 s.vars[name] = v
3169 }
3170 return v
3171}
3172
Keith Randallcfc2aa52015-05-18 16:44:20 -07003173func (s *state) mem() *ssa.Value {
Keith Randallb32217a2015-09-17 16:45:10 -07003174 return s.variable(&memVar, ssa.TypeMem)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003175}
3176
Keith Randallcfc2aa52015-05-18 16:44:20 -07003177func (s *state) linkForwardReferences() {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003178 // Build ssa graph. Each variable on its first use in a basic block
3179 // leaves a FwdRef in that block representing the incoming value
3180 // of that variable. This function links that ref up with possible definitions,
3181 // inserting Phi values as needed. This is essentially the algorithm
3182 // described by Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
3183 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
3184 for _, b := range s.f.Blocks {
3185 for _, v := range b.Values {
3186 if v.Op != ssa.OpFwdRef {
3187 continue
3188 }
Keith Randall8c46aa52015-06-19 21:02:28 -07003189 name := v.Aux.(*Node)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003190 v.Op = ssa.OpCopy
3191 v.Aux = nil
3192 v.SetArgs1(s.lookupVarIncoming(b, v.Type, name))
3193 }
3194 }
3195}
3196
3197// lookupVarIncoming finds the variable's value at the start of block b.
Keith Randall8c46aa52015-06-19 21:02:28 -07003198func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003199 // TODO(khr): have lookupVarIncoming overwrite the fwdRef or copy it
3200 // will be used in, instead of having the result used in a copy value.
3201 if b == s.f.Entry {
Keith Randallb32217a2015-09-17 16:45:10 -07003202 if name == &memVar {
Keith Randallcfc2aa52015-05-18 16:44:20 -07003203 return s.startmem
Keith Randalld2fd43a2015-04-15 15:51:25 -07003204 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003205 if canSSA(name) {
3206 v := s.entryNewValue0A(ssa.OpArg, t, name)
3207 // v starts with AuxInt == 0.
3208 s.addNamedValue(name, v)
3209 return v
3210 }
Keith Randalld2fd43a2015-04-15 15:51:25 -07003211 // variable is live at the entry block. Load it.
Keith Randall8c46aa52015-06-19 21:02:28 -07003212 addr := s.decladdrs[name]
3213 if addr == nil {
3214 // TODO: closure args reach here.
David Chase32ffbf72015-10-08 17:14:12 -04003215 s.Unimplementedf("unhandled closure arg %s at entry to function %s", name, b.Func.Name)
Keith Randall8c46aa52015-06-19 21:02:28 -07003216 }
3217 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
3218 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
3219 }
Keith Randall8f22b522015-06-11 21:29:25 -07003220 return s.entryNewValue2(ssa.OpLoad, t, addr, s.startmem)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003221 }
3222 var vals []*ssa.Value
3223 for _, p := range b.Preds {
3224 vals = append(vals, s.lookupVarOutgoing(p, t, name))
3225 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07003226 if len(vals) == 0 {
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003227 // This block is dead; we have no predecessors and we're not the entry block.
3228 // It doesn't matter what we use here as long as it is well-formed,
3229 // so use the default/zero value.
Keith Randallb32217a2015-09-17 16:45:10 -07003230 if name == &memVar {
Josh Bleecher Snyder61aa0952015-07-20 15:39:14 -07003231 return s.startmem
3232 }
3233 return s.zeroVal(name.Type)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07003234 }
Keith Randalld2fd43a2015-04-15 15:51:25 -07003235 v0 := vals[0]
3236 for i := 1; i < len(vals); i++ {
3237 if vals[i] != v0 {
3238 // need a phi value
Keith Randall8f22b522015-06-11 21:29:25 -07003239 v := b.NewValue0(s.peekLine(), ssa.OpPhi, t)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003240 v.AddArgs(vals...)
Keith Randallc24681a2015-10-22 14:22:38 -07003241 s.addNamedValue(name, v)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003242 return v
3243 }
3244 }
3245 return v0
3246}
3247
3248// lookupVarOutgoing finds the variable's value at the end of block b.
Keith Randall8c46aa52015-06-19 21:02:28 -07003249func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -07003250 m := s.defvars[b.ID]
3251 if v, ok := m[name]; ok {
3252 return v
3253 }
3254 // The variable is not defined by b and we haven't
3255 // looked it up yet. Generate v, a copy value which
3256 // will be the outgoing value of the variable. Then
3257 // look up w, the incoming value of the variable.
3258 // Make v = copy(w). We need the extra copy to
3259 // prevent infinite recursion when looking up the
3260 // incoming value of the variable.
Keith Randall8f22b522015-06-11 21:29:25 -07003261 v := b.NewValue0(s.peekLine(), ssa.OpCopy, t)
Keith Randalld2fd43a2015-04-15 15:51:25 -07003262 m[name] = v
3263 v.AddArg(s.lookupVarIncoming(b, t, name))
3264 return v
3265}
3266
3267// TODO: the above mutually recursive functions can lead to very deep stacks. Fix that.
3268
Keith Randallc24681a2015-10-22 14:22:38 -07003269func (s *state) addNamedValue(n *Node, v *ssa.Value) {
3270 if n.Class == Pxxx {
3271 // Don't track our dummy nodes (&memVar etc.).
3272 return
3273 }
3274 if n.Sym == nil {
3275 // TODO: What the heck is this?
3276 return
3277 }
3278 if strings.HasPrefix(n.Sym.Name, "autotmp_") {
3279 // Don't track autotmp_ variables.
3280 return
3281 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003282 if n.Class == PAUTO && (v.Type.IsString() || v.Type.IsSlice() || v.Type.IsInterface()) {
3283 // TODO: can't handle auto compound objects with pointers yet.
3284 // The live variable analysis barfs because we don't put VARDEF
3285 // pseudos in the right place when we spill to these nodes.
Keith Randallc24681a2015-10-22 14:22:38 -07003286 return
3287 }
3288 if n.Class == PAUTO && n.Xoffset != 0 {
3289 s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset)
3290 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003291 loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0}
3292 values, ok := s.f.NamedValues[loc]
Keith Randallc24681a2015-10-22 14:22:38 -07003293 if !ok {
Keith Randall02f4d0a2015-11-02 08:10:26 -08003294 s.f.Names = append(s.f.Names, loc)
Keith Randallc24681a2015-10-22 14:22:38 -07003295 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08003296 s.f.NamedValues[loc] = append(values, v)
Keith Randallc24681a2015-10-22 14:22:38 -07003297}
3298
Keith Randall083a6462015-05-12 11:06:44 -07003299// an unresolved branch
3300type branch struct {
3301 p *obj.Prog // branch instruction
3302 b *ssa.Block // target
3303}
3304
Keith Randall9569b952015-08-28 22:51:01 -07003305type genState struct {
3306 // branches remembers all the branch instructions we've seen
3307 // and where they would like to go.
3308 branches []branch
3309
3310 // bstart remembers where each block starts (indexed by block ID)
3311 bstart []*obj.Prog
3312
3313 // deferBranches remembers all the defer branches we've seen.
3314 deferBranches []*obj.Prog
3315
3316 // deferTarget remembers the (last) deferreturn call site.
3317 deferTarget *obj.Prog
3318}
3319
Keith Randall083a6462015-05-12 11:06:44 -07003320// genssa appends entries to ptxt for each instruction in f.
3321// gcargs and gclocals are filled in with pointer maps for the frame.
3322func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
Keith Randall9569b952015-08-28 22:51:01 -07003323 var s genState
3324
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07003325 e := f.Config.Frontend().(*ssaExport)
3326 // We're about to emit a bunch of Progs.
3327 // Since the only way to get here is to explicitly request it,
3328 // just fail on unimplemented instead of trying to unwind our mess.
3329 e.mustImplement = true
3330
Keith Randall083a6462015-05-12 11:06:44 -07003331 // Remember where each block starts.
Keith Randall9569b952015-08-28 22:51:01 -07003332 s.bstart = make([]*obj.Prog, f.NumBlocks())
Keith Randall083a6462015-05-12 11:06:44 -07003333
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003334 var valueProgs map[*obj.Prog]*ssa.Value
3335 var blockProgs map[*obj.Prog]*ssa.Block
3336 const logProgs = true
3337 if logProgs {
3338 valueProgs = make(map[*obj.Prog]*ssa.Value, f.NumValues())
3339 blockProgs = make(map[*obj.Prog]*ssa.Block, f.NumBlocks())
3340 f.Logf("genssa %s\n", f.Name)
3341 blockProgs[Pc] = f.Blocks[0]
3342 }
3343
Keith Randall083a6462015-05-12 11:06:44 -07003344 // Emit basic blocks
3345 for i, b := range f.Blocks {
Keith Randall9569b952015-08-28 22:51:01 -07003346 s.bstart[b.ID] = Pc
Keith Randall083a6462015-05-12 11:06:44 -07003347 // Emit values in block
3348 for _, v := range b.Values {
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003349 x := Pc
Keith Randall9569b952015-08-28 22:51:01 -07003350 s.genValue(v)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003351 if logProgs {
3352 for ; x != Pc; x = x.Link {
3353 valueProgs[x] = v
3354 }
3355 }
Keith Randall083a6462015-05-12 11:06:44 -07003356 }
3357 // Emit control flow instructions for block
3358 var next *ssa.Block
3359 if i < len(f.Blocks)-1 {
3360 next = f.Blocks[i+1]
3361 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003362 x := Pc
Keith Randall9569b952015-08-28 22:51:01 -07003363 s.genBlock(b, next)
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003364 if logProgs {
3365 for ; x != Pc; x = x.Link {
3366 blockProgs[x] = b
3367 }
3368 }
Keith Randall083a6462015-05-12 11:06:44 -07003369 }
3370
3371 // Resolve branches
Keith Randall9569b952015-08-28 22:51:01 -07003372 for _, br := range s.branches {
3373 br.p.To.Val = s.bstart[br.b.ID]
3374 }
Keith Randallca9e4502015-09-08 08:59:57 -07003375 if s.deferBranches != nil && s.deferTarget == nil {
3376 // This can happen when the function has a defer but
3377 // no return (because it has an infinite loop).
3378 s.deferReturn()
3379 Prog(obj.ARET)
3380 }
Keith Randall9569b952015-08-28 22:51:01 -07003381 for _, p := range s.deferBranches {
3382 p.To.Val = s.deferTarget
Keith Randall083a6462015-05-12 11:06:44 -07003383 }
3384
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003385 if logProgs {
3386 for p := ptxt; p != nil; p = p.Link {
3387 var s string
3388 if v, ok := valueProgs[p]; ok {
3389 s = v.String()
3390 } else if b, ok := blockProgs[p]; ok {
3391 s = b.String()
3392 } else {
3393 s = " " // most value and branch strings are 2-3 characters long
3394 }
3395 f.Logf("%s\t%s\n", s, p)
3396 }
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07003397 if f.Config.HTML != nil {
3398 saved := ptxt.Ctxt.LineHist.PrintFilenameOnly
3399 ptxt.Ctxt.LineHist.PrintFilenameOnly = true
3400 var buf bytes.Buffer
3401 buf.WriteString("<code>")
3402 buf.WriteString("<dl class=\"ssa-gen\">")
3403 for p := ptxt; p != nil; p = p.Link {
3404 buf.WriteString("<dt class=\"ssa-prog-src\">")
3405 if v, ok := valueProgs[p]; ok {
3406 buf.WriteString(v.HTML())
3407 } else if b, ok := blockProgs[p]; ok {
3408 buf.WriteString(b.HTML())
3409 }
3410 buf.WriteString("</dt>")
3411 buf.WriteString("<dd class=\"ssa-prog\">")
3412 buf.WriteString(html.EscapeString(p.String()))
3413 buf.WriteString("</dd>")
3414 buf.WriteString("</li>")
3415 }
3416 buf.WriteString("</dl>")
3417 buf.WriteString("</code>")
3418 f.Config.HTML.WriteColumn("genssa", buf.String())
3419 ptxt.Ctxt.LineHist.PrintFilenameOnly = saved
3420 }
Josh Bleecher Snyderb8efee02015-07-31 14:37:15 -07003421 }
3422
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07003423 // Emit static data
3424 if f.StaticData != nil {
3425 for _, n := range f.StaticData.([]*Node) {
3426 if !gen_as_init(n, false) {
Keith Randall0ec72b62015-09-08 15:42:53 -07003427 Fatalf("non-static data marked as static: %v\n\n", n, f)
Josh Bleecher Snyder6b416652015-07-28 10:56:39 -07003428 }
3429 }
3430 }
3431
Keith Randalld2107fc2015-08-24 02:16:19 -07003432 // Allocate stack frame
3433 allocauto(ptxt)
Keith Randall083a6462015-05-12 11:06:44 -07003434
Keith Randalld2107fc2015-08-24 02:16:19 -07003435 // Generate gc bitmaps.
3436 liveness(Curfn, ptxt, gcargs, gclocals)
3437 gcsymdup(gcargs)
3438 gcsymdup(gclocals)
Keith Randall083a6462015-05-12 11:06:44 -07003439
Keith Randalld2107fc2015-08-24 02:16:19 -07003440 // Add frame prologue. Zero ambiguously live variables.
3441 Thearch.Defframe(ptxt)
3442 if Debug['f'] != 0 {
3443 frame(0)
3444 }
3445
3446 // Remove leftover instrumentation from the instruction stream.
3447 removevardef(ptxt)
Josh Bleecher Snyder35fb5142015-08-10 12:15:52 -07003448
3449 f.Config.HTML.Close()
Keith Randall083a6462015-05-12 11:06:44 -07003450}
3451
David Chase997a9f32015-08-12 16:38:11 -04003452// opregreg emits instructions for
David Chase8e601b22015-08-18 14:39:26 -04003453// dest := dest(To) op src(From)
David Chase997a9f32015-08-12 16:38:11 -04003454// and also returns the created obj.Prog so it
3455// may be further adjusted (offset, scale, etc).
3456func opregreg(op int, dest, src int16) *obj.Prog {
3457 p := Prog(op)
3458 p.From.Type = obj.TYPE_REG
3459 p.To.Type = obj.TYPE_REG
3460 p.To.Reg = dest
3461 p.From.Reg = src
3462 return p
3463}
3464
Keith Randall9569b952015-08-28 22:51:01 -07003465func (s *genState) genValue(v *ssa.Value) {
Michael Matloob81ccf502015-05-30 01:03:06 -04003466 lineno = v.Line
Keith Randall083a6462015-05-12 11:06:44 -07003467 switch v.Op {
Keith Randall0dca7352015-06-06 16:03:33 -07003468 case ssa.OpAMD64ADDQ:
Keith Randall083a6462015-05-12 11:06:44 -07003469 // TODO: use addq instead of leaq if target is in the right register.
3470 p := Prog(x86.ALEAQ)
3471 p.From.Type = obj.TYPE_MEM
3472 p.From.Reg = regnum(v.Args[0])
3473 p.From.Scale = 1
3474 p.From.Index = regnum(v.Args[1])
3475 p.To.Type = obj.TYPE_REG
3476 p.To.Reg = regnum(v)
Michael Matloob73054f52015-06-14 11:38:46 -07003477 case ssa.OpAMD64ADDL:
3478 p := Prog(x86.ALEAL)
3479 p.From.Type = obj.TYPE_MEM
3480 p.From.Reg = regnum(v.Args[0])
3481 p.From.Scale = 1
3482 p.From.Index = regnum(v.Args[1])
3483 p.To.Type = obj.TYPE_REG
3484 p.To.Reg = regnum(v)
3485 case ssa.OpAMD64ADDW:
3486 p := Prog(x86.ALEAW)
3487 p.From.Type = obj.TYPE_MEM
3488 p.From.Reg = regnum(v.Args[0])
3489 p.From.Scale = 1
3490 p.From.Index = regnum(v.Args[1])
3491 p.To.Type = obj.TYPE_REG
3492 p.To.Reg = regnum(v)
Keith Randall20550cb2015-07-28 16:04:50 -07003493 // 2-address opcode arithmetic, symmetric
David Chase997a9f32015-08-12 16:38:11 -04003494 case ssa.OpAMD64ADDB, ssa.OpAMD64ADDSS, ssa.OpAMD64ADDSD,
Alexandru Moșoiedff8812015-07-28 14:58:49 +02003495 ssa.OpAMD64ANDQ, ssa.OpAMD64ANDL, ssa.OpAMD64ANDW, ssa.OpAMD64ANDB,
Keith Randall20550cb2015-07-28 16:04:50 -07003496 ssa.OpAMD64ORQ, ssa.OpAMD64ORL, ssa.OpAMD64ORW, ssa.OpAMD64ORB,
3497 ssa.OpAMD64XORQ, ssa.OpAMD64XORL, ssa.OpAMD64XORW, ssa.OpAMD64XORB,
David Chase997a9f32015-08-12 16:38:11 -04003498 ssa.OpAMD64MULQ, ssa.OpAMD64MULL, ssa.OpAMD64MULW, ssa.OpAMD64MULB,
David Chase3a9d0ac2015-08-28 14:24:10 -04003499 ssa.OpAMD64MULSS, ssa.OpAMD64MULSD, ssa.OpAMD64PXOR:
Michael Matloob73054f52015-06-14 11:38:46 -07003500 r := regnum(v)
3501 x := regnum(v.Args[0])
3502 y := regnum(v.Args[1])
3503 if x != r && y != r {
David Chase997a9f32015-08-12 16:38:11 -04003504 opregreg(regMoveByTypeAMD64(v.Type), r, x)
Michael Matloob73054f52015-06-14 11:38:46 -07003505 x = r
3506 }
3507 p := Prog(v.Op.Asm())
3508 p.From.Type = obj.TYPE_REG
3509 p.To.Type = obj.TYPE_REG
3510 p.To.Reg = r
3511 if x == r {
3512 p.From.Reg = y
3513 } else {
3514 p.From.Reg = x
3515 }
Keith Randall20550cb2015-07-28 16:04:50 -07003516 // 2-address opcode arithmetic, not symmetric
3517 case ssa.OpAMD64SUBQ, ssa.OpAMD64SUBL, ssa.OpAMD64SUBW, ssa.OpAMD64SUBB:
Keith Randallbe1eb572015-07-22 13:46:15 -07003518 r := regnum(v)
3519 x := regnum(v.Args[0])
Keith Randall20550cb2015-07-28 16:04:50 -07003520 y := regnum(v.Args[1])
3521 var neg bool
3522 if y == r {
3523 // compute -(y-x) instead
3524 x, y = y, x
3525 neg = true
Keith Randallbe1eb572015-07-22 13:46:15 -07003526 }
Keith Randall083a6462015-05-12 11:06:44 -07003527 if x != r {
David Chase997a9f32015-08-12 16:38:11 -04003528 opregreg(regMoveByTypeAMD64(v.Type), r, x)
Keith Randall083a6462015-05-12 11:06:44 -07003529 }
David Chase997a9f32015-08-12 16:38:11 -04003530 opregreg(v.Op.Asm(), r, y)
Keith Randall20550cb2015-07-28 16:04:50 -07003531
Keith Randall20550cb2015-07-28 16:04:50 -07003532 if neg {
3533 p := Prog(x86.ANEGQ) // TODO: use correct size? This is mostly a hack until regalloc does 2-address correctly
Keith Randall20550cb2015-07-28 16:04:50 -07003534 p.To.Type = obj.TYPE_REG
3535 p.To.Reg = r
3536 }
David Chase997a9f32015-08-12 16:38:11 -04003537 case ssa.OpAMD64SUBSS, ssa.OpAMD64SUBSD, ssa.OpAMD64DIVSS, ssa.OpAMD64DIVSD:
3538 r := regnum(v)
3539 x := regnum(v.Args[0])
3540 y := regnum(v.Args[1])
3541 if y == r && x != r {
3542 // r/y := x op r/y, need to preserve x and rewrite to
3543 // r/y := r/y op x15
3544 x15 := int16(x86.REG_X15)
3545 // register move y to x15
3546 // register move x to y
3547 // rename y with x15
3548 opregreg(regMoveByTypeAMD64(v.Type), x15, y)
3549 opregreg(regMoveByTypeAMD64(v.Type), r, x)
3550 y = x15
3551 } else if x != r {
3552 opregreg(regMoveByTypeAMD64(v.Type), r, x)
3553 }
3554 opregreg(v.Op.Asm(), r, y)
3555
Todd Neala45f2d82015-08-17 17:46:06 -05003556 case ssa.OpAMD64DIVQ, ssa.OpAMD64DIVL, ssa.OpAMD64DIVW,
Todd Neal57d9e7e2015-08-18 19:51:44 -05003557 ssa.OpAMD64DIVQU, ssa.OpAMD64DIVLU, ssa.OpAMD64DIVWU,
3558 ssa.OpAMD64MODQ, ssa.OpAMD64MODL, ssa.OpAMD64MODW,
3559 ssa.OpAMD64MODQU, ssa.OpAMD64MODLU, ssa.OpAMD64MODWU:
Todd Neala45f2d82015-08-17 17:46:06 -05003560
3561 // Arg[0] is already in AX as it's the only register we allow
3562 // and AX is the only output
3563 x := regnum(v.Args[1])
3564
3565 // CPU faults upon signed overflow, which occurs when most
Todd Neal57d9e7e2015-08-18 19:51:44 -05003566 // negative int is divided by -1.
Todd Neala45f2d82015-08-17 17:46:06 -05003567 var j *obj.Prog
3568 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
Todd Neal57d9e7e2015-08-18 19:51:44 -05003569 v.Op == ssa.OpAMD64DIVW || v.Op == ssa.OpAMD64MODQ ||
3570 v.Op == ssa.OpAMD64MODL || v.Op == ssa.OpAMD64MODW {
Todd Neala45f2d82015-08-17 17:46:06 -05003571
3572 var c *obj.Prog
3573 switch v.Op {
Todd Neal57d9e7e2015-08-18 19:51:44 -05003574 case ssa.OpAMD64DIVQ, ssa.OpAMD64MODQ:
Todd Neala45f2d82015-08-17 17:46:06 -05003575 c = Prog(x86.ACMPQ)
Todd Neal57d9e7e2015-08-18 19:51:44 -05003576 j = Prog(x86.AJEQ)
3577 // go ahead and sign extend to save doing it later
3578 Prog(x86.ACQO)
3579
3580 case ssa.OpAMD64DIVL, ssa.OpAMD64MODL:
Todd Neala45f2d82015-08-17 17:46:06 -05003581 c = Prog(x86.ACMPL)
Todd Neal57d9e7e2015-08-18 19:51:44 -05003582 j = Prog(x86.AJEQ)
3583 Prog(x86.ACDQ)
3584
3585 case ssa.OpAMD64DIVW, ssa.OpAMD64MODW:
Todd Neala45f2d82015-08-17 17:46:06 -05003586 c = Prog(x86.ACMPW)
Todd Neal57d9e7e2015-08-18 19:51:44 -05003587 j = Prog(x86.AJEQ)
3588 Prog(x86.ACWD)
Todd Neala45f2d82015-08-17 17:46:06 -05003589 }
3590 c.From.Type = obj.TYPE_REG
3591 c.From.Reg = x
3592 c.To.Type = obj.TYPE_CONST
3593 c.To.Offset = -1
3594
Todd Neala45f2d82015-08-17 17:46:06 -05003595 j.To.Type = obj.TYPE_BRANCH
3596
3597 }
3598
Todd Neal57d9e7e2015-08-18 19:51:44 -05003599 // for unsigned ints, we sign extend by setting DX = 0
3600 // signed ints were sign extended above
3601 if v.Op == ssa.OpAMD64DIVQU || v.Op == ssa.OpAMD64MODQU ||
3602 v.Op == ssa.OpAMD64DIVLU || v.Op == ssa.OpAMD64MODLU ||
3603 v.Op == ssa.OpAMD64DIVWU || v.Op == ssa.OpAMD64MODWU {
Todd Neala45f2d82015-08-17 17:46:06 -05003604 c := Prog(x86.AXORQ)
3605 c.From.Type = obj.TYPE_REG
3606 c.From.Reg = x86.REG_DX
3607 c.To.Type = obj.TYPE_REG
3608 c.To.Reg = x86.REG_DX
Todd Neala45f2d82015-08-17 17:46:06 -05003609 }
3610
3611 p := Prog(v.Op.Asm())
3612 p.From.Type = obj.TYPE_REG
3613 p.From.Reg = x
3614
3615 // signed division, rest of the check for -1 case
3616 if j != nil {
3617 j2 := Prog(obj.AJMP)
3618 j2.To.Type = obj.TYPE_BRANCH
3619
Todd Neal57d9e7e2015-08-18 19:51:44 -05003620 var n *obj.Prog
3621 if v.Op == ssa.OpAMD64DIVQ || v.Op == ssa.OpAMD64DIVL ||
3622 v.Op == ssa.OpAMD64DIVW {
3623 // n * -1 = -n
3624 n = Prog(x86.ANEGQ)
3625 n.To.Type = obj.TYPE_REG
3626 n.To.Reg = x86.REG_AX
3627 } else {
3628 // n % -1 == 0
3629 n = Prog(x86.AXORQ)
3630 n.From.Type = obj.TYPE_REG
3631 n.From.Reg = x86.REG_DX
3632 n.To.Type = obj.TYPE_REG
3633 n.To.Reg = x86.REG_DX
3634 }
Todd Neala45f2d82015-08-17 17:46:06 -05003635
3636 j.To.Val = n
3637 j2.To.Val = Pc
3638 }
3639
Todd Neal67cbd5b2015-08-18 19:14:47 -05003640 case ssa.OpAMD64HMULL, ssa.OpAMD64HMULW, ssa.OpAMD64HMULB,
3641 ssa.OpAMD64HMULLU, ssa.OpAMD64HMULWU, ssa.OpAMD64HMULBU:
3642 // the frontend rewrites constant division by 8/16/32 bit integers into
3643 // HMUL by a constant
3644
3645 // Arg[0] is already in AX as it's the only register we allow
3646 // and DX is the only output we care about (the high bits)
3647 p := Prog(v.Op.Asm())
3648 p.From.Type = obj.TYPE_REG
3649 p.From.Reg = regnum(v.Args[1])
3650
3651 // IMULB puts the high portion in AH instead of DL,
3652 // so move it to DL for consistency
3653 if v.Type.Size() == 1 {
3654 m := Prog(x86.AMOVB)
3655 m.From.Type = obj.TYPE_REG
3656 m.From.Reg = x86.REG_AH
3657 m.To.Type = obj.TYPE_REG
3658 m.To.Reg = x86.REG_DX
3659 }
3660
Keith Randall20550cb2015-07-28 16:04:50 -07003661 case ssa.OpAMD64SHLQ, ssa.OpAMD64SHLL, ssa.OpAMD64SHLW, ssa.OpAMD64SHLB,
3662 ssa.OpAMD64SHRQ, ssa.OpAMD64SHRL, ssa.OpAMD64SHRW, ssa.OpAMD64SHRB,
3663 ssa.OpAMD64SARQ, ssa.OpAMD64SARL, ssa.OpAMD64SARW, ssa.OpAMD64SARB:
Keith Randall6f188472015-06-10 10:39:57 -07003664 x := regnum(v.Args[0])
3665 r := regnum(v)
3666 if x != r {
3667 if r == x86.REG_CX {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07003668 v.Fatalf("can't implement %s, target and shift both in CX", v.LongString())
Keith Randall6f188472015-06-10 10:39:57 -07003669 }
Keith Randall20550cb2015-07-28 16:04:50 -07003670 p := Prog(regMoveAMD64(v.Type.Size()))
Keith Randall6f188472015-06-10 10:39:57 -07003671 p.From.Type = obj.TYPE_REG
3672 p.From.Reg = x
3673 p.To.Type = obj.TYPE_REG
3674 p.To.Reg = r
Keith Randall6f188472015-06-10 10:39:57 -07003675 }
Michael Matloob703ef062015-06-16 11:11:16 -07003676 p := Prog(v.Op.Asm())
Keith Randall6f188472015-06-10 10:39:57 -07003677 p.From.Type = obj.TYPE_REG
3678 p.From.Reg = regnum(v.Args[1]) // should be CX
3679 p.To.Type = obj.TYPE_REG
3680 p.To.Reg = r
Keith Randall20550cb2015-07-28 16:04:50 -07003681 case ssa.OpAMD64ADDQconst, ssa.OpAMD64ADDLconst, ssa.OpAMD64ADDWconst:
3682 // TODO: use addq instead of leaq if target is in the right register.
3683 var asm int
3684 switch v.Op {
3685 case ssa.OpAMD64ADDQconst:
3686 asm = x86.ALEAQ
3687 case ssa.OpAMD64ADDLconst:
3688 asm = x86.ALEAL
3689 case ssa.OpAMD64ADDWconst:
3690 asm = x86.ALEAW
3691 }
3692 p := Prog(asm)
3693 p.From.Type = obj.TYPE_MEM
3694 p.From.Reg = regnum(v.Args[0])
3695 p.From.Offset = v.AuxInt
3696 p.To.Type = obj.TYPE_REG
3697 p.To.Reg = regnum(v)
Alexandru Moșoi7a6de6d2015-08-14 13:23:11 +02003698 case ssa.OpAMD64MULQconst, ssa.OpAMD64MULLconst, ssa.OpAMD64MULWconst, ssa.OpAMD64MULBconst:
Keith Randall20550cb2015-07-28 16:04:50 -07003699 r := regnum(v)
3700 x := regnum(v.Args[0])
3701 if r != x {
3702 p := Prog(regMoveAMD64(v.Type.Size()))
3703 p.From.Type = obj.TYPE_REG
3704 p.From.Reg = x
3705 p.To.Type = obj.TYPE_REG
3706 p.To.Reg = r
3707 }
3708 p := Prog(v.Op.Asm())
3709 p.From.Type = obj.TYPE_CONST
3710 p.From.Offset = v.AuxInt
3711 p.To.Type = obj.TYPE_REG
3712 p.To.Reg = r
3713 // TODO: Teach doasm to compile the three-address multiply imul $c, r1, r2
3714 // instead of using the MOVQ above.
3715 //p.From3 = new(obj.Addr)
3716 //p.From3.Type = obj.TYPE_REG
3717 //p.From3.Reg = regnum(v.Args[0])
3718 case ssa.OpAMD64ADDBconst,
3719 ssa.OpAMD64ANDQconst, ssa.OpAMD64ANDLconst, ssa.OpAMD64ANDWconst, ssa.OpAMD64ANDBconst,
3720 ssa.OpAMD64ORQconst, ssa.OpAMD64ORLconst, ssa.OpAMD64ORWconst, ssa.OpAMD64ORBconst,
3721 ssa.OpAMD64XORQconst, ssa.OpAMD64XORLconst, ssa.OpAMD64XORWconst, ssa.OpAMD64XORBconst,
3722 ssa.OpAMD64SUBQconst, ssa.OpAMD64SUBLconst, ssa.OpAMD64SUBWconst, ssa.OpAMD64SUBBconst,
3723 ssa.OpAMD64SHLQconst, ssa.OpAMD64SHLLconst, ssa.OpAMD64SHLWconst, ssa.OpAMD64SHLBconst,
3724 ssa.OpAMD64SHRQconst, ssa.OpAMD64SHRLconst, ssa.OpAMD64SHRWconst, ssa.OpAMD64SHRBconst,
David Chase40aba8c2015-08-05 22:11:14 -04003725 ssa.OpAMD64SARQconst, ssa.OpAMD64SARLconst, ssa.OpAMD64SARWconst, ssa.OpAMD64SARBconst,
3726 ssa.OpAMD64ROLQconst, ssa.OpAMD64ROLLconst, ssa.OpAMD64ROLWconst, ssa.OpAMD64ROLBconst:
Keith Randall20550cb2015-07-28 16:04:50 -07003727 // This code compensates for the fact that the register allocator
3728 // doesn't understand 2-address instructions yet. TODO: fix that.
Keith Randall247786c2015-05-28 10:47:24 -07003729 x := regnum(v.Args[0])
3730 r := regnum(v)
3731 if x != r {
Keith Randall20550cb2015-07-28 16:04:50 -07003732 p := Prog(regMoveAMD64(v.Type.Size()))
Keith Randall247786c2015-05-28 10:47:24 -07003733 p.From.Type = obj.TYPE_REG
3734 p.From.Reg = x
3735 p.To.Type = obj.TYPE_REG
3736 p.To.Reg = r
Keith Randall247786c2015-05-28 10:47:24 -07003737 }
Michael Matloob703ef062015-06-16 11:11:16 -07003738 p := Prog(v.Op.Asm())
Keith Randall247786c2015-05-28 10:47:24 -07003739 p.From.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -07003740 p.From.Offset = v.AuxInt
Keith Randall247786c2015-05-28 10:47:24 -07003741 p.To.Type = obj.TYPE_REG
Keith Randalldbd83c42015-06-28 06:08:50 -07003742 p.To.Reg = r
Keith Randall4b803152015-07-29 17:07:09 -07003743 case ssa.OpAMD64SBBQcarrymask, ssa.OpAMD64SBBLcarrymask:
Keith Randall6f188472015-06-10 10:39:57 -07003744 r := regnum(v)
Keith Randall20550cb2015-07-28 16:04:50 -07003745 p := Prog(v.Op.Asm())
Keith Randall6f188472015-06-10 10:39:57 -07003746 p.From.Type = obj.TYPE_REG
3747 p.From.Reg = r
3748 p.To.Type = obj.TYPE_REG
3749 p.To.Reg = r
Todd Neald90e0482015-07-23 20:01:40 -05003750 case ssa.OpAMD64LEAQ1, ssa.OpAMD64LEAQ2, ssa.OpAMD64LEAQ4, ssa.OpAMD64LEAQ8:
Keith Randall247786c2015-05-28 10:47:24 -07003751 p := Prog(x86.ALEAQ)
3752 p.From.Type = obj.TYPE_MEM
3753 p.From.Reg = regnum(v.Args[0])
Todd Neald90e0482015-07-23 20:01:40 -05003754 switch v.Op {
3755 case ssa.OpAMD64LEAQ1:
3756 p.From.Scale = 1
3757 case ssa.OpAMD64LEAQ2:
3758 p.From.Scale = 2
3759 case ssa.OpAMD64LEAQ4:
3760 p.From.Scale = 4
3761 case ssa.OpAMD64LEAQ8:
3762 p.From.Scale = 8
3763 }
Keith Randall247786c2015-05-28 10:47:24 -07003764 p.From.Index = regnum(v.Args[1])
Keith Randall8c46aa52015-06-19 21:02:28 -07003765 addAux(&p.From, v)
3766 p.To.Type = obj.TYPE_REG
3767 p.To.Reg = regnum(v)
3768 case ssa.OpAMD64LEAQ:
3769 p := Prog(x86.ALEAQ)
3770 p.From.Type = obj.TYPE_MEM
3771 p.From.Reg = regnum(v.Args[0])
3772 addAux(&p.From, v)
Keith Randall247786c2015-05-28 10:47:24 -07003773 p.To.Type = obj.TYPE_REG
3774 p.To.Reg = regnum(v)
Keith Randall20550cb2015-07-28 16:04:50 -07003775 case ssa.OpAMD64CMPQ, ssa.OpAMD64CMPL, ssa.OpAMD64CMPW, ssa.OpAMD64CMPB,
3776 ssa.OpAMD64TESTQ, ssa.OpAMD64TESTL, ssa.OpAMD64TESTW, ssa.OpAMD64TESTB:
David Chase8e601b22015-08-18 14:39:26 -04003777 opregreg(v.Op.Asm(), regnum(v.Args[1]), regnum(v.Args[0]))
3778 case ssa.OpAMD64UCOMISS, ssa.OpAMD64UCOMISD:
3779 // Go assembler has swapped operands for UCOMISx relative to CMP,
3780 // must account for that right here.
3781 opregreg(v.Op.Asm(), regnum(v.Args[0]), regnum(v.Args[1]))
Keith Randall20550cb2015-07-28 16:04:50 -07003782 case ssa.OpAMD64CMPQconst, ssa.OpAMD64CMPLconst, ssa.OpAMD64CMPWconst, ssa.OpAMD64CMPBconst,
3783 ssa.OpAMD64TESTQconst, ssa.OpAMD64TESTLconst, ssa.OpAMD64TESTWconst, ssa.OpAMD64TESTBconst:
3784 p := Prog(v.Op.Asm())
Keith Randallcfc2aa52015-05-18 16:44:20 -07003785 p.From.Type = obj.TYPE_REG
3786 p.From.Reg = regnum(v.Args[0])
3787 p.To.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -07003788 p.To.Offset = v.AuxInt
Keith Randall9cb332e2015-07-28 14:19:20 -07003789 case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
Keith Randall083a6462015-05-12 11:06:44 -07003790 x := regnum(v)
Keith Randall9cb332e2015-07-28 14:19:20 -07003791 p := Prog(v.Op.Asm())
Keith Randall083a6462015-05-12 11:06:44 -07003792 p.From.Type = obj.TYPE_CONST
Keith Randall9cb332e2015-07-28 14:19:20 -07003793 var i int64
3794 switch v.Op {
3795 case ssa.OpAMD64MOVBconst:
3796 i = int64(int8(v.AuxInt))
3797 case ssa.OpAMD64MOVWconst:
3798 i = int64(int16(v.AuxInt))
3799 case ssa.OpAMD64MOVLconst:
3800 i = int64(int32(v.AuxInt))
3801 case ssa.OpAMD64MOVQconst:
3802 i = v.AuxInt
3803 }
3804 p.From.Offset = i
Keith Randall083a6462015-05-12 11:06:44 -07003805 p.To.Type = obj.TYPE_REG
3806 p.To.Reg = x
David Chase997a9f32015-08-12 16:38:11 -04003807 case ssa.OpAMD64MOVSSconst, ssa.OpAMD64MOVSDconst:
3808 x := regnum(v)
3809 p := Prog(v.Op.Asm())
3810 p.From.Type = obj.TYPE_FCONST
Todd Neal19447a62015-09-04 06:33:56 -05003811 p.From.Val = math.Float64frombits(uint64(v.AuxInt))
David Chase997a9f32015-08-12 16:38:11 -04003812 p.To.Type = obj.TYPE_REG
3813 p.To.Reg = x
Keith Randall10462eb2015-10-21 17:18:07 -07003814 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVSSload, ssa.OpAMD64MOVSDload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload, ssa.OpAMD64MOVOload:
Michael Matloob703ef062015-06-16 11:11:16 -07003815 p := Prog(v.Op.Asm())
Keith Randallcfc2aa52015-05-18 16:44:20 -07003816 p.From.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07003817 p.From.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07003818 addAux(&p.From, v)
Keith Randallcfc2aa52015-05-18 16:44:20 -07003819 p.To.Type = obj.TYPE_REG
3820 p.To.Reg = regnum(v)
David Chase997a9f32015-08-12 16:38:11 -04003821 case ssa.OpAMD64MOVQloadidx8, ssa.OpAMD64MOVSDloadidx8:
3822 p := Prog(v.Op.Asm())
Keith Randallcfc2aa52015-05-18 16:44:20 -07003823 p.From.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07003824 p.From.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07003825 addAux(&p.From, v)
Keith Randallcfc2aa52015-05-18 16:44:20 -07003826 p.From.Scale = 8
3827 p.From.Index = regnum(v.Args[1])
3828 p.To.Type = obj.TYPE_REG
3829 p.To.Reg = regnum(v)
David Chase997a9f32015-08-12 16:38:11 -04003830 case ssa.OpAMD64MOVSSloadidx4:
3831 p := Prog(v.Op.Asm())
3832 p.From.Type = obj.TYPE_MEM
3833 p.From.Reg = regnum(v.Args[0])
3834 addAux(&p.From, v)
3835 p.From.Scale = 4
3836 p.From.Index = regnum(v.Args[1])
3837 p.To.Type = obj.TYPE_REG
3838 p.To.Reg = regnum(v)
Keith Randall10462eb2015-10-21 17:18:07 -07003839 case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVSSstore, ssa.OpAMD64MOVSDstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore, ssa.OpAMD64MOVOstore:
Michael Matloob73054f52015-06-14 11:38:46 -07003840 p := Prog(v.Op.Asm())
Keith Randall083a6462015-05-12 11:06:44 -07003841 p.From.Type = obj.TYPE_REG
Keith Randallcfc2aa52015-05-18 16:44:20 -07003842 p.From.Reg = regnum(v.Args[1])
Keith Randall083a6462015-05-12 11:06:44 -07003843 p.To.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07003844 p.To.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07003845 addAux(&p.To, v)
David Chase997a9f32015-08-12 16:38:11 -04003846 case ssa.OpAMD64MOVQstoreidx8, ssa.OpAMD64MOVSDstoreidx8:
3847 p := Prog(v.Op.Asm())
Josh Bleecher Snyder3e3d1622015-07-27 16:36:36 -07003848 p.From.Type = obj.TYPE_REG
3849 p.From.Reg = regnum(v.Args[2])
3850 p.To.Type = obj.TYPE_MEM
3851 p.To.Reg = regnum(v.Args[0])
3852 p.To.Scale = 8
3853 p.To.Index = regnum(v.Args[1])
3854 addAux(&p.To, v)
David Chase997a9f32015-08-12 16:38:11 -04003855 case ssa.OpAMD64MOVSSstoreidx4:
3856 p := Prog(v.Op.Asm())
3857 p.From.Type = obj.TYPE_REG
3858 p.From.Reg = regnum(v.Args[2])
3859 p.To.Type = obj.TYPE_MEM
3860 p.To.Reg = regnum(v.Args[0])
3861 p.To.Scale = 4
3862 p.To.Index = regnum(v.Args[1])
3863 addAux(&p.To, v)
Keith Randalld43f2e32015-10-21 13:13:56 -07003864 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
3865 p := Prog(v.Op.Asm())
3866 p.From.Type = obj.TYPE_CONST
3867 sc := ssa.StoreConst(v.AuxInt)
3868 i := sc.Val()
3869 switch v.Op {
3870 case ssa.OpAMD64MOVBstoreconst:
3871 i = int64(int8(i))
3872 case ssa.OpAMD64MOVWstoreconst:
3873 i = int64(int16(i))
3874 case ssa.OpAMD64MOVLstoreconst:
3875 i = int64(int32(i))
3876 case ssa.OpAMD64MOVQstoreconst:
3877 }
3878 p.From.Offset = i
3879 p.To.Type = obj.TYPE_MEM
3880 p.To.Reg = regnum(v.Args[0])
3881 addAux2(&p.To, v, sc.Off())
David Chase42825882015-08-20 15:14:20 -04003882 case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
3883 ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD,
Todd Neal634b50c2015-09-01 19:05:44 -05003884 ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
David Chase42825882015-08-20 15:14:20 -04003885 ssa.OpAMD64CVTSS2SD, ssa.OpAMD64CVTSD2SS:
3886 opregreg(v.Op.Asm(), regnum(v), regnum(v.Args[0]))
Keith Randall04d6edc2015-09-18 18:23:34 -07003887 case ssa.OpAMD64DUFFZERO:
3888 p := Prog(obj.ADUFFZERO)
3889 p.To.Type = obj.TYPE_ADDR
3890 p.To.Sym = Linksym(Pkglookup("duffzero", Runtimepkg))
3891 p.To.Offset = v.AuxInt
Keith Randall7c4fbb62015-10-19 13:56:55 -07003892 case ssa.OpAMD64MOVOconst:
3893 if v.AuxInt != 0 {
3894 v.Unimplementedf("MOVOconst can only do constant=0")
3895 }
3896 r := regnum(v)
3897 opregreg(x86.AXORPS, r, r)
Keith Randall10462eb2015-10-21 17:18:07 -07003898 case ssa.OpAMD64DUFFCOPY:
3899 p := Prog(obj.ADUFFCOPY)
3900 p.To.Type = obj.TYPE_ADDR
3901 p.To.Sym = Linksym(Pkglookup("duffcopy", Runtimepkg))
3902 p.To.Offset = v.AuxInt
Keith Randall04d6edc2015-09-18 18:23:34 -07003903
Keith Randall7807bda2015-11-10 15:35:36 -08003904 case ssa.OpCopy, ssa.OpAMD64MOVQconvert: // TODO: lower Copy to MOVQ earlier?
Keith Randallf7f604e2015-05-27 14:52:22 -07003905 if v.Type.IsMemory() {
3906 return
3907 }
Keith Randall083a6462015-05-12 11:06:44 -07003908 x := regnum(v.Args[0])
3909 y := regnum(v)
3910 if x != y {
David Chase997a9f32015-08-12 16:38:11 -04003911 opregreg(regMoveByTypeAMD64(v.Type), y, x)
Keith Randall083a6462015-05-12 11:06:44 -07003912 }
Josh Bleecher Snyder0bb2a502015-07-24 14:51:51 -07003913 case ssa.OpLoadReg:
Josh Bleecher Snyder26f135d2015-07-20 15:22:34 -07003914 if v.Type.IsFlags() {
3915 v.Unimplementedf("load flags not implemented: %v", v.LongString())
3916 return
3917 }
David Chase997a9f32015-08-12 16:38:11 -04003918 p := Prog(movSizeByType(v.Type))
Keith Randall02f4d0a2015-11-02 08:10:26 -08003919 n, off := autoVar(v.Args[0])
Keith Randall083a6462015-05-12 11:06:44 -07003920 p.From.Type = obj.TYPE_MEM
Keith Randalld2107fc2015-08-24 02:16:19 -07003921 p.From.Node = n
3922 p.From.Sym = Linksym(n.Sym)
Keith Randall02f4d0a2015-11-02 08:10:26 -08003923 p.From.Offset = off
3924 if n.Class == PPARAM {
3925 p.From.Name = obj.NAME_PARAM
3926 p.From.Offset += n.Xoffset
3927 } else {
3928 p.From.Name = obj.NAME_AUTO
3929 }
Keith Randall083a6462015-05-12 11:06:44 -07003930 p.To.Type = obj.TYPE_REG
3931 p.To.Reg = regnum(v)
David Chase997a9f32015-08-12 16:38:11 -04003932
Josh Bleecher Snyder0bb2a502015-07-24 14:51:51 -07003933 case ssa.OpStoreReg:
Josh Bleecher Snyder26f135d2015-07-20 15:22:34 -07003934 if v.Type.IsFlags() {
3935 v.Unimplementedf("store flags not implemented: %v", v.LongString())
3936 return
3937 }
David Chase997a9f32015-08-12 16:38:11 -04003938 p := Prog(movSizeByType(v.Type))
Keith Randall083a6462015-05-12 11:06:44 -07003939 p.From.Type = obj.TYPE_REG
3940 p.From.Reg = regnum(v.Args[0])
Keith Randall02f4d0a2015-11-02 08:10:26 -08003941 n, off := autoVar(v)
Keith Randall083a6462015-05-12 11:06:44 -07003942 p.To.Type = obj.TYPE_MEM
Keith Randalld2107fc2015-08-24 02:16:19 -07003943 p.To.Node = n
3944 p.To.Sym = Linksym(n.Sym)
Keith Randall02f4d0a2015-11-02 08:10:26 -08003945 p.To.Offset = off
3946 if n.Class == PPARAM {
3947 p.To.Name = obj.NAME_PARAM
3948 p.To.Offset += n.Xoffset
3949 } else {
3950 p.To.Name = obj.NAME_AUTO
3951 }
Keith Randall083a6462015-05-12 11:06:44 -07003952 case ssa.OpPhi:
Keith Randall0b46b422015-08-11 12:51:33 -07003953 // just check to make sure regalloc and stackalloc did it right
3954 if v.Type.IsMemory() {
3955 return
3956 }
Keith Randall083a6462015-05-12 11:06:44 -07003957 f := v.Block.Func
3958 loc := f.RegAlloc[v.ID]
3959 for _, a := range v.Args {
Josh Bleecher Snyder55845232015-08-05 16:43:49 -07003960 if aloc := f.RegAlloc[a.ID]; aloc != loc { // TODO: .Equal() instead?
3961 v.Fatalf("phi arg at different location than phi: %v @ %v, but arg %v @ %v\n%s\n", v, loc, a, aloc, v.Block.Func)
Keith Randall083a6462015-05-12 11:06:44 -07003962 }
3963 }
David Chase997a9f32015-08-12 16:38:11 -04003964 case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64, ssa.OpConstString, ssa.OpConstNil, ssa.OpConstBool,
3965 ssa.OpConst32F, ssa.OpConst64F:
Keith Randall083a6462015-05-12 11:06:44 -07003966 if v.Block.Func.RegAlloc[v.ID] != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07003967 v.Fatalf("const value %v shouldn't have a location", v)
Keith Randall083a6462015-05-12 11:06:44 -07003968 }
David Chase997a9f32015-08-12 16:38:11 -04003969
Keith Randall02f4d0a2015-11-02 08:10:26 -08003970 case ssa.OpInitMem:
Keith Randall083a6462015-05-12 11:06:44 -07003971 // memory arg needs no code
Keith Randall02f4d0a2015-11-02 08:10:26 -08003972 case ssa.OpArg:
3973 // input args need no code
David Chase956f3192015-09-11 16:40:05 -04003974 case ssa.OpAMD64LoweredGetClosurePtr:
3975 // Output is hardwired to DX only,
3976 // and DX contains the closure pointer on
3977 // closure entry, and this "instruction"
3978 // is scheduled to the very beginning
3979 // of the entry block.
Josh Bleecher Snyder3d23afb2015-08-12 11:22:16 -07003980 case ssa.OpAMD64LoweredGetG:
3981 r := regnum(v)
3982 // See the comments in cmd/internal/obj/x86/obj6.go
3983 // near CanUse1InsnTLS for a detailed explanation of these instructions.
3984 if x86.CanUse1InsnTLS(Ctxt) {
3985 // MOVQ (TLS), r
3986 p := Prog(x86.AMOVQ)
3987 p.From.Type = obj.TYPE_MEM
3988 p.From.Reg = x86.REG_TLS
3989 p.To.Type = obj.TYPE_REG
3990 p.To.Reg = r
3991 } else {
3992 // MOVQ TLS, r
3993 // MOVQ (r)(TLS*1), r
3994 p := Prog(x86.AMOVQ)
3995 p.From.Type = obj.TYPE_REG
3996 p.From.Reg = x86.REG_TLS
3997 p.To.Type = obj.TYPE_REG
3998 p.To.Reg = r
3999 q := Prog(x86.AMOVQ)
4000 q.From.Type = obj.TYPE_MEM
4001 q.From.Reg = r
4002 q.From.Index = x86.REG_TLS
4003 q.From.Scale = 1
4004 q.To.Type = obj.TYPE_REG
4005 q.To.Reg = r
4006 }
Keith Randall290d8fc2015-06-10 15:03:06 -07004007 case ssa.OpAMD64CALLstatic:
Keith Randall247786c2015-05-28 10:47:24 -07004008 p := Prog(obj.ACALL)
4009 p.To.Type = obj.TYPE_MEM
4010 p.To.Name = obj.NAME_EXTERN
4011 p.To.Sym = Linksym(v.Aux.(*Sym))
Keith Randalld2107fc2015-08-24 02:16:19 -07004012 if Maxarg < v.AuxInt {
4013 Maxarg = v.AuxInt
4014 }
Keith Randall290d8fc2015-06-10 15:03:06 -07004015 case ssa.OpAMD64CALLclosure:
4016 p := Prog(obj.ACALL)
4017 p.To.Type = obj.TYPE_REG
4018 p.To.Reg = regnum(v.Args[0])
Keith Randalld2107fc2015-08-24 02:16:19 -07004019 if Maxarg < v.AuxInt {
4020 Maxarg = v.AuxInt
4021 }
Keith Randall9569b952015-08-28 22:51:01 -07004022 case ssa.OpAMD64CALLdefer:
4023 p := Prog(obj.ACALL)
4024 p.To.Type = obj.TYPE_MEM
4025 p.To.Name = obj.NAME_EXTERN
4026 p.To.Sym = Linksym(Deferproc.Sym)
4027 if Maxarg < v.AuxInt {
4028 Maxarg = v.AuxInt
4029 }
4030 // defer returns in rax:
4031 // 0 if we should continue executing
4032 // 1 if we should jump to deferreturn call
4033 p = Prog(x86.ATESTL)
4034 p.From.Type = obj.TYPE_REG
4035 p.From.Reg = x86.REG_AX
4036 p.To.Type = obj.TYPE_REG
4037 p.To.Reg = x86.REG_AX
4038 p = Prog(x86.AJNE)
4039 p.To.Type = obj.TYPE_BRANCH
4040 s.deferBranches = append(s.deferBranches, p)
4041 case ssa.OpAMD64CALLgo:
4042 p := Prog(obj.ACALL)
4043 p.To.Type = obj.TYPE_MEM
4044 p.To.Name = obj.NAME_EXTERN
4045 p.To.Sym = Linksym(Newproc.Sym)
4046 if Maxarg < v.AuxInt {
4047 Maxarg = v.AuxInt
4048 }
Keith Randalld24768e2015-09-09 23:56:59 -07004049 case ssa.OpAMD64CALLinter:
4050 p := Prog(obj.ACALL)
4051 p.To.Type = obj.TYPE_REG
4052 p.To.Reg = regnum(v.Args[0])
4053 if Maxarg < v.AuxInt {
4054 Maxarg = v.AuxInt
4055 }
Keith Randall4b803152015-07-29 17:07:09 -07004056 case ssa.OpAMD64NEGQ, ssa.OpAMD64NEGL, ssa.OpAMD64NEGW, ssa.OpAMD64NEGB,
4057 ssa.OpAMD64NOTQ, ssa.OpAMD64NOTL, ssa.OpAMD64NOTW, ssa.OpAMD64NOTB:
Josh Bleecher Snyder93c354b62015-07-30 17:15:16 -07004058 x := regnum(v.Args[0])
4059 r := regnum(v)
4060 if x != r {
4061 p := Prog(regMoveAMD64(v.Type.Size()))
4062 p.From.Type = obj.TYPE_REG
4063 p.From.Reg = x
4064 p.To.Type = obj.TYPE_REG
4065 p.To.Reg = r
4066 }
Alexandru Moșoi954d5ad2015-07-21 16:58:18 +02004067 p := Prog(v.Op.Asm())
4068 p.To.Type = obj.TYPE_REG
Josh Bleecher Snyder93c354b62015-07-30 17:15:16 -07004069 p.To.Reg = r
Keith Randalla329e212015-09-12 13:26:57 -07004070 case ssa.OpAMD64SQRTSD:
4071 p := Prog(v.Op.Asm())
4072 p.From.Type = obj.TYPE_REG
4073 p.From.Reg = regnum(v.Args[0])
4074 p.To.Type = obj.TYPE_REG
4075 p.To.Reg = regnum(v)
Keith Randall8c46aa52015-06-19 21:02:28 -07004076 case ssa.OpSP, ssa.OpSB:
Keith Randallcfc2aa52015-05-18 16:44:20 -07004077 // nothing to do
Josh Bleecher Snydera7940742015-07-20 15:21:49 -07004078 case ssa.OpAMD64SETEQ, ssa.OpAMD64SETNE,
4079 ssa.OpAMD64SETL, ssa.OpAMD64SETLE,
4080 ssa.OpAMD64SETG, ssa.OpAMD64SETGE,
David Chase8e601b22015-08-18 14:39:26 -04004081 ssa.OpAMD64SETGF, ssa.OpAMD64SETGEF,
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004082 ssa.OpAMD64SETB, ssa.OpAMD64SETBE,
David Chase8e601b22015-08-18 14:39:26 -04004083 ssa.OpAMD64SETORD, ssa.OpAMD64SETNAN,
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004084 ssa.OpAMD64SETA, ssa.OpAMD64SETAE:
Josh Bleecher Snydera7940742015-07-20 15:21:49 -07004085 p := Prog(v.Op.Asm())
4086 p.To.Type = obj.TYPE_REG
4087 p.To.Reg = regnum(v)
David Chase8e601b22015-08-18 14:39:26 -04004088
4089 case ssa.OpAMD64SETNEF:
4090 p := Prog(v.Op.Asm())
4091 p.To.Type = obj.TYPE_REG
4092 p.To.Reg = regnum(v)
4093 q := Prog(x86.ASETPS)
4094 q.To.Type = obj.TYPE_REG
4095 q.To.Reg = x86.REG_AX
4096 // TODO AORQ copied from old code generator, why not AORB?
4097 opregreg(x86.AORQ, regnum(v), x86.REG_AX)
4098
4099 case ssa.OpAMD64SETEQF:
4100 p := Prog(v.Op.Asm())
4101 p.To.Type = obj.TYPE_REG
4102 p.To.Reg = regnum(v)
4103 q := Prog(x86.ASETPC)
4104 q.To.Type = obj.TYPE_REG
4105 q.To.Reg = x86.REG_AX
4106 // TODO AANDQ copied from old code generator, why not AANDB?
4107 opregreg(x86.AANDQ, regnum(v), x86.REG_AX)
4108
Keith Randall20550cb2015-07-28 16:04:50 -07004109 case ssa.OpAMD64InvertFlags:
4110 v.Fatalf("InvertFlags should never make it to codegen %v", v)
4111 case ssa.OpAMD64REPSTOSQ:
4112 Prog(x86.AREP)
4113 Prog(x86.ASTOSQ)
Keith Randall10462eb2015-10-21 17:18:07 -07004114 case ssa.OpAMD64REPMOVSQ:
Keith Randall20550cb2015-07-28 16:04:50 -07004115 Prog(x86.AREP)
Keith Randall10462eb2015-10-21 17:18:07 -07004116 Prog(x86.AMOVSQ)
Keith Randalld2107fc2015-08-24 02:16:19 -07004117 case ssa.OpVarDef:
4118 Gvardef(v.Aux.(*Node))
4119 case ssa.OpVarKill:
4120 gvarkill(v.Aux.(*Node))
Keith Randall31115a52015-10-23 19:12:49 -07004121 case ssa.OpAMD64LoweredNilCheck:
4122 // Optimization - if the subsequent block has a load or store
4123 // at the same address, we don't need to issue this instruction.
4124 for _, w := range v.Block.Succs[0].Values {
4125 if len(w.Args) == 0 || !w.Args[len(w.Args)-1].Type.IsMemory() {
4126 // w doesn't use a store - can't be a memory op.
4127 continue
4128 }
4129 if w.Args[len(w.Args)-1] != v.Args[1] {
4130 v.Fatalf("wrong store after nilcheck v=%s w=%s", v, w)
4131 }
4132 switch w.Op {
4133 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload,
4134 ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore:
4135 if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
4136 return
4137 }
Keith Randalld43f2e32015-10-21 13:13:56 -07004138 case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
4139 off := ssa.StoreConst(v.AuxInt).Off()
4140 if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
4141 return
4142 }
Keith Randall31115a52015-10-23 19:12:49 -07004143 }
4144 if w.Type.IsMemory() {
4145 // We can't delay the nil check past the next store.
4146 break
4147 }
4148 }
4149 // Issue a load which will fault if the input is nil.
4150 // TODO: We currently use the 2-byte instruction TESTB AX, (reg).
4151 // Should we use the 3-byte TESTB $0, (reg) instead? It is larger
4152 // but it doesn't have false dependency on AX.
4153 // Or maybe allocate an output register and use MOVL (reg),reg2 ?
4154 // That trades clobbering flags for clobbering a register.
4155 p := Prog(x86.ATESTB)
4156 p.From.Type = obj.TYPE_REG
4157 p.From.Reg = x86.REG_AX
4158 p.To.Type = obj.TYPE_MEM
4159 p.To.Reg = regnum(v.Args[0])
4160 addAux(&p.To, v)
4161 if Debug_checknil != 0 && v.Line > 1 { // v.Line==1 in generated wrappers
4162 Warnl(int(v.Line), "generated nil check")
4163 }
Keith Randall083a6462015-05-12 11:06:44 -07004164 default:
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004165 v.Unimplementedf("genValue not implemented: %s", v.LongString())
Keith Randall083a6462015-05-12 11:06:44 -07004166 }
4167}
4168
David Chase997a9f32015-08-12 16:38:11 -04004169// movSizeByType returns the MOV instruction of the given type.
4170func movSizeByType(t ssa.Type) (asm int) {
4171 // For x86, there's no difference between reg move opcodes
4172 // and memory move opcodes.
4173 asm = regMoveByTypeAMD64(t)
4174 return
Josh Bleecher Snyder0bb2a502015-07-24 14:51:51 -07004175}
4176
Daniel Morsing66b47812015-06-27 15:45:20 +01004177// movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
4178func movZero(as int, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
4179 p := Prog(as)
4180 // TODO: use zero register on archs that support it.
4181 p.From.Type = obj.TYPE_CONST
4182 p.From.Offset = 0
4183 p.To.Type = obj.TYPE_MEM
4184 p.To.Reg = regnum
4185 p.To.Offset = offset
4186 offset += width
4187 nleft = nbytes - width
4188 return nleft, offset
4189}
4190
David Chase8e601b22015-08-18 14:39:26 -04004191var blockJump = [...]struct {
4192 asm, invasm int
4193}{
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004194 ssa.BlockAMD64EQ: {x86.AJEQ, x86.AJNE},
4195 ssa.BlockAMD64NE: {x86.AJNE, x86.AJEQ},
4196 ssa.BlockAMD64LT: {x86.AJLT, x86.AJGE},
4197 ssa.BlockAMD64GE: {x86.AJGE, x86.AJLT},
4198 ssa.BlockAMD64LE: {x86.AJLE, x86.AJGT},
4199 ssa.BlockAMD64GT: {x86.AJGT, x86.AJLE},
4200 ssa.BlockAMD64ULT: {x86.AJCS, x86.AJCC},
4201 ssa.BlockAMD64UGE: {x86.AJCC, x86.AJCS},
4202 ssa.BlockAMD64UGT: {x86.AJHI, x86.AJLS},
4203 ssa.BlockAMD64ULE: {x86.AJLS, x86.AJHI},
David Chase8e601b22015-08-18 14:39:26 -04004204 ssa.BlockAMD64ORD: {x86.AJPC, x86.AJPS},
4205 ssa.BlockAMD64NAN: {x86.AJPS, x86.AJPC},
4206}
4207
4208type floatingEQNEJump struct {
4209 jump, index int
4210}
4211
4212var eqfJumps = [2][2]floatingEQNEJump{
4213 {{x86.AJNE, 1}, {x86.AJPS, 1}}, // next == b.Succs[0]
4214 {{x86.AJNE, 1}, {x86.AJPC, 0}}, // next == b.Succs[1]
4215}
4216var nefJumps = [2][2]floatingEQNEJump{
4217 {{x86.AJNE, 0}, {x86.AJPC, 1}}, // next == b.Succs[0]
4218 {{x86.AJNE, 0}, {x86.AJPS, 0}}, // next == b.Succs[1]
4219}
4220
4221func oneFPJump(b *ssa.Block, jumps *floatingEQNEJump, likely ssa.BranchPrediction, branches []branch) []branch {
4222 p := Prog(jumps.jump)
4223 p.To.Type = obj.TYPE_BRANCH
4224 to := jumps.index
4225 branches = append(branches, branch{p, b.Succs[to]})
4226 if to == 1 {
4227 likely = -likely
4228 }
4229 // liblink reorders the instruction stream as it sees fit.
4230 // Pass along what we know so liblink can make use of it.
4231 // TODO: Once we've fully switched to SSA,
4232 // make liblink leave our output alone.
4233 switch likely {
4234 case ssa.BranchUnlikely:
4235 p.From.Type = obj.TYPE_CONST
4236 p.From.Offset = 0
4237 case ssa.BranchLikely:
4238 p.From.Type = obj.TYPE_CONST
4239 p.From.Offset = 1
4240 }
4241 return branches
4242}
4243
Keith Randall9569b952015-08-28 22:51:01 -07004244func genFPJump(s *genState, b, next *ssa.Block, jumps *[2][2]floatingEQNEJump) {
David Chase8e601b22015-08-18 14:39:26 -04004245 likely := b.Likely
4246 switch next {
4247 case b.Succs[0]:
Keith Randall9569b952015-08-28 22:51:01 -07004248 s.branches = oneFPJump(b, &jumps[0][0], likely, s.branches)
4249 s.branches = oneFPJump(b, &jumps[0][1], likely, s.branches)
David Chase8e601b22015-08-18 14:39:26 -04004250 case b.Succs[1]:
Keith Randall9569b952015-08-28 22:51:01 -07004251 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4252 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
David Chase8e601b22015-08-18 14:39:26 -04004253 default:
Keith Randall9569b952015-08-28 22:51:01 -07004254 s.branches = oneFPJump(b, &jumps[1][0], likely, s.branches)
4255 s.branches = oneFPJump(b, &jumps[1][1], likely, s.branches)
David Chase8e601b22015-08-18 14:39:26 -04004256 q := Prog(obj.AJMP)
4257 q.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004258 s.branches = append(s.branches, branch{q, b.Succs[1]})
David Chase8e601b22015-08-18 14:39:26 -04004259 }
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004260}
4261
Keith Randall9569b952015-08-28 22:51:01 -07004262func (s *genState) genBlock(b, next *ssa.Block) {
Michael Matloob81ccf502015-05-30 01:03:06 -04004263 lineno = b.Line
Keith Randall8d236812015-08-18 15:25:40 -07004264
Keith Randall083a6462015-05-12 11:06:44 -07004265 switch b.Kind {
Keith Randall31115a52015-10-23 19:12:49 -07004266 case ssa.BlockPlain, ssa.BlockCall, ssa.BlockCheck:
Keith Randall083a6462015-05-12 11:06:44 -07004267 if b.Succs[0] != next {
4268 p := Prog(obj.AJMP)
4269 p.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004270 s.branches = append(s.branches, branch{p, b.Succs[0]})
Keith Randall083a6462015-05-12 11:06:44 -07004271 }
4272 case ssa.BlockExit:
Keith Randall5f105732015-09-17 15:19:23 -07004273 Prog(obj.AUNDEF) // tell plive.go that we never reach here
Keith Randall10f38f52015-09-03 09:09:59 -07004274 case ssa.BlockRet:
Keith Randall0ec72b62015-09-08 15:42:53 -07004275 if hasdefer {
Keith Randallca9e4502015-09-08 08:59:57 -07004276 s.deferReturn()
Keith Randall9569b952015-08-28 22:51:01 -07004277 }
Keith Randall083a6462015-05-12 11:06:44 -07004278 Prog(obj.ARET)
Keith Randall8a1f6212015-09-08 21:28:44 -07004279 case ssa.BlockRetJmp:
4280 p := Prog(obj.AJMP)
4281 p.To.Type = obj.TYPE_MEM
4282 p.To.Name = obj.NAME_EXTERN
4283 p.To.Sym = Linksym(b.Aux.(*Sym))
David Chase8e601b22015-08-18 14:39:26 -04004284
4285 case ssa.BlockAMD64EQF:
Keith Randall9569b952015-08-28 22:51:01 -07004286 genFPJump(s, b, next, &eqfJumps)
David Chase8e601b22015-08-18 14:39:26 -04004287
4288 case ssa.BlockAMD64NEF:
Keith Randall9569b952015-08-28 22:51:01 -07004289 genFPJump(s, b, next, &nefJumps)
David Chase8e601b22015-08-18 14:39:26 -04004290
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004291 case ssa.BlockAMD64EQ, ssa.BlockAMD64NE,
4292 ssa.BlockAMD64LT, ssa.BlockAMD64GE,
4293 ssa.BlockAMD64LE, ssa.BlockAMD64GT,
4294 ssa.BlockAMD64ULT, ssa.BlockAMD64UGT,
4295 ssa.BlockAMD64ULE, ssa.BlockAMD64UGE:
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004296 jmp := blockJump[b.Kind]
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004297 likely := b.Likely
4298 var p *obj.Prog
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004299 switch next {
4300 case b.Succs[0]:
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004301 p = Prog(jmp.invasm)
4302 likely *= -1
Keith Randallcfc2aa52015-05-18 16:44:20 -07004303 p.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004304 s.branches = append(s.branches, branch{p, b.Succs[1]})
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004305 case b.Succs[1]:
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004306 p = Prog(jmp.asm)
Keith Randallcfc2aa52015-05-18 16:44:20 -07004307 p.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004308 s.branches = append(s.branches, branch{p, b.Succs[0]})
Josh Bleecher Snyder71b57072015-07-24 12:47:00 -07004309 default:
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004310 p = Prog(jmp.asm)
Keith Randallcfc2aa52015-05-18 16:44:20 -07004311 p.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004312 s.branches = append(s.branches, branch{p, b.Succs[0]})
Keith Randallcfc2aa52015-05-18 16:44:20 -07004313 q := Prog(obj.AJMP)
4314 q.To.Type = obj.TYPE_BRANCH
Keith Randall9569b952015-08-28 22:51:01 -07004315 s.branches = append(s.branches, branch{q, b.Succs[1]})
Keith Randallcfc2aa52015-05-18 16:44:20 -07004316 }
4317
Josh Bleecher Snyderbbf8c5c2015-08-11 17:28:56 -07004318 // liblink reorders the instruction stream as it sees fit.
4319 // Pass along what we know so liblink can make use of it.
4320 // TODO: Once we've fully switched to SSA,
4321 // make liblink leave our output alone.
4322 switch likely {
4323 case ssa.BranchUnlikely:
4324 p.From.Type = obj.TYPE_CONST
4325 p.From.Offset = 0
4326 case ssa.BranchLikely:
4327 p.From.Type = obj.TYPE_CONST
4328 p.From.Offset = 1
4329 }
4330
Keith Randall083a6462015-05-12 11:06:44 -07004331 default:
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004332 b.Unimplementedf("branch not implemented: %s. Control: %s", b.LongString(), b.Control.LongString())
Keith Randall083a6462015-05-12 11:06:44 -07004333 }
Keith Randall083a6462015-05-12 11:06:44 -07004334}
4335
Keith Randallca9e4502015-09-08 08:59:57 -07004336func (s *genState) deferReturn() {
4337 // Deferred calls will appear to be returning to
4338 // the CALL deferreturn(SB) that we are about to emit.
4339 // However, the stack trace code will show the line
4340 // of the instruction byte before the return PC.
4341 // To avoid that being an unrelated instruction,
4342 // insert an actual hardware NOP that will have the right line number.
4343 // This is different from obj.ANOP, which is a virtual no-op
4344 // that doesn't make it into the instruction stream.
4345 s.deferTarget = Pc
4346 Thearch.Ginsnop()
4347 p := Prog(obj.ACALL)
4348 p.To.Type = obj.TYPE_MEM
4349 p.To.Name = obj.NAME_EXTERN
4350 p.To.Sym = Linksym(Deferreturn.Sym)
4351}
4352
Keith Randall8c46aa52015-06-19 21:02:28 -07004353// addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
4354func addAux(a *obj.Addr, v *ssa.Value) {
Keith Randalld43f2e32015-10-21 13:13:56 -07004355 addAux2(a, v, v.AuxInt)
4356}
4357func addAux2(a *obj.Addr, v *ssa.Value, offset int64) {
Keith Randall8c46aa52015-06-19 21:02:28 -07004358 if a.Type != obj.TYPE_MEM {
4359 v.Fatalf("bad addAux addr %s", a)
4360 }
4361 // add integer offset
Keith Randalld43f2e32015-10-21 13:13:56 -07004362 a.Offset += offset
Keith Randall8c46aa52015-06-19 21:02:28 -07004363
4364 // If no additional symbol offset, we're done.
4365 if v.Aux == nil {
4366 return
4367 }
4368 // Add symbol's offset from its base register.
4369 switch sym := v.Aux.(type) {
4370 case *ssa.ExternSymbol:
4371 a.Name = obj.NAME_EXTERN
4372 a.Sym = Linksym(sym.Sym.(*Sym))
4373 case *ssa.ArgSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07004374 n := sym.Node.(*Node)
4375 a.Name = obj.NAME_PARAM
4376 a.Node = n
4377 a.Sym = Linksym(n.Orig.Sym)
4378 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 -07004379 case *ssa.AutoSymbol:
Keith Randalld2107fc2015-08-24 02:16:19 -07004380 n := sym.Node.(*Node)
4381 a.Name = obj.NAME_AUTO
4382 a.Node = n
4383 a.Sym = Linksym(n.Sym)
Keith Randall8c46aa52015-06-19 21:02:28 -07004384 default:
4385 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
4386 }
4387}
4388
Keith Randall582baae2015-11-02 21:28:13 -08004389// extendIndex extends v to a full int width.
Keith Randall2a5e6c42015-07-23 14:35:02 -07004390func (s *state) extendIndex(v *ssa.Value) *ssa.Value {
4391 size := v.Type.Size()
Keith Randall582baae2015-11-02 21:28:13 -08004392 if size == s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004393 return v
4394 }
Keith Randall582baae2015-11-02 21:28:13 -08004395 if size > s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004396 // TODO: truncate 64-bit indexes on 32-bit pointer archs. We'd need to test
4397 // the high word and branch to out-of-bounds failure if it is not 0.
4398 s.Unimplementedf("64->32 index truncation not implemented")
4399 return v
4400 }
4401
4402 // Extend value to the required size
4403 var op ssa.Op
4404 if v.Type.IsSigned() {
Keith Randall582baae2015-11-02 21:28:13 -08004405 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004406 case 14:
4407 op = ssa.OpSignExt8to32
4408 case 18:
4409 op = ssa.OpSignExt8to64
4410 case 24:
4411 op = ssa.OpSignExt16to32
4412 case 28:
4413 op = ssa.OpSignExt16to64
4414 case 48:
4415 op = ssa.OpSignExt32to64
4416 default:
4417 s.Fatalf("bad signed index extension %s", v.Type)
4418 }
4419 } else {
Keith Randall582baae2015-11-02 21:28:13 -08004420 switch 10*size + s.config.IntSize {
Keith Randall2a5e6c42015-07-23 14:35:02 -07004421 case 14:
4422 op = ssa.OpZeroExt8to32
4423 case 18:
4424 op = ssa.OpZeroExt8to64
4425 case 24:
4426 op = ssa.OpZeroExt16to32
4427 case 28:
4428 op = ssa.OpZeroExt16to64
4429 case 48:
4430 op = ssa.OpZeroExt32to64
4431 default:
4432 s.Fatalf("bad unsigned index extension %s", v.Type)
4433 }
4434 }
Keith Randall582baae2015-11-02 21:28:13 -08004435 return s.newValue1(op, Types[TINT], v)
Keith Randall2a5e6c42015-07-23 14:35:02 -07004436}
4437
Keith Randall083a6462015-05-12 11:06:44 -07004438// ssaRegToReg maps ssa register numbers to obj register numbers.
4439var ssaRegToReg = [...]int16{
4440 x86.REG_AX,
4441 x86.REG_CX,
4442 x86.REG_DX,
4443 x86.REG_BX,
4444 x86.REG_SP,
4445 x86.REG_BP,
4446 x86.REG_SI,
4447 x86.REG_DI,
4448 x86.REG_R8,
4449 x86.REG_R9,
4450 x86.REG_R10,
4451 x86.REG_R11,
4452 x86.REG_R12,
4453 x86.REG_R13,
4454 x86.REG_R14,
4455 x86.REG_R15,
Keith Randall8c46aa52015-06-19 21:02:28 -07004456 x86.REG_X0,
4457 x86.REG_X1,
4458 x86.REG_X2,
4459 x86.REG_X3,
4460 x86.REG_X4,
4461 x86.REG_X5,
4462 x86.REG_X6,
4463 x86.REG_X7,
4464 x86.REG_X8,
4465 x86.REG_X9,
4466 x86.REG_X10,
4467 x86.REG_X11,
4468 x86.REG_X12,
4469 x86.REG_X13,
4470 x86.REG_X14,
4471 x86.REG_X15,
4472 0, // SB isn't a real register. We fill an Addr.Reg field with 0 in this case.
Keith Randall083a6462015-05-12 11:06:44 -07004473 // TODO: arch-dependent
4474}
4475
Keith Randall9cb332e2015-07-28 14:19:20 -07004476// regMoveAMD64 returns the register->register move opcode for the given width.
4477// TODO: generalize for all architectures?
4478func regMoveAMD64(width int64) int {
4479 switch width {
4480 case 1:
4481 return x86.AMOVB
4482 case 2:
4483 return x86.AMOVW
4484 case 4:
4485 return x86.AMOVL
4486 case 8:
4487 return x86.AMOVQ
4488 default:
David Chase997a9f32015-08-12 16:38:11 -04004489 panic("bad int register width")
Keith Randall9cb332e2015-07-28 14:19:20 -07004490 }
4491}
4492
David Chase997a9f32015-08-12 16:38:11 -04004493func regMoveByTypeAMD64(t ssa.Type) int {
4494 width := t.Size()
4495 if t.IsFloat() {
4496 switch width {
4497 case 4:
4498 return x86.AMOVSS
4499 case 8:
4500 return x86.AMOVSD
4501 default:
4502 panic("bad float register width")
4503 }
4504 } else {
4505 switch width {
4506 case 1:
4507 return x86.AMOVB
4508 case 2:
4509 return x86.AMOVW
4510 case 4:
4511 return x86.AMOVL
4512 case 8:
4513 return x86.AMOVQ
4514 default:
4515 panic("bad int register width")
4516 }
4517 }
4518
4519 panic("bad register type")
4520}
4521
Keith Randall083a6462015-05-12 11:06:44 -07004522// regnum returns the register (in cmd/internal/obj numbering) to
4523// which v has been allocated. Panics if v is not assigned to a
4524// register.
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07004525// TODO: Make this panic again once it stops happening routinely.
Keith Randall083a6462015-05-12 11:06:44 -07004526func regnum(v *ssa.Value) int16 {
Josh Bleecher Snydere1395492015-08-05 16:06:39 -07004527 reg := v.Block.Func.RegAlloc[v.ID]
4528 if reg == nil {
4529 v.Unimplementedf("nil regnum for value: %s\n%s\n", v.LongString(), v.Block.Func)
4530 return 0
4531 }
4532 return ssaRegToReg[reg.(*ssa.Register).Num]
Keith Randall083a6462015-05-12 11:06:44 -07004533}
4534
Keith Randall02f4d0a2015-11-02 08:10:26 -08004535// autoVar returns a *Node and int64 representing the auto variable and offset within it
4536// where v should be spilled.
4537func autoVar(v *ssa.Value) (*Node, int64) {
4538 loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot)
Keith Randall9094e3a2016-01-04 13:34:54 -08004539 if v.Type.Size() > loc.Type.Size() {
4540 v.Fatalf("spill/restore type %s doesn't fit in slot type %s", v.Type, loc.Type)
4541 }
Keith Randall02f4d0a2015-11-02 08:10:26 -08004542 return loc.N.(*Node), loc.Off
Keith Randall083a6462015-05-12 11:06:44 -07004543}
Keith Randallf7f604e2015-05-27 14:52:22 -07004544
4545// ssaExport exports a bunch of compiler services for the ssa backend.
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004546type ssaExport struct {
4547 log bool
4548 unimplemented bool
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004549 mustImplement bool
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004550}
Keith Randallf7f604e2015-05-27 14:52:22 -07004551
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07004552func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] }
4553func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] }
4554func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] }
4555func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] }
4556func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] }
4557func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] }
4558func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] }
4559func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] }
4560func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] }
David Chase52578582015-08-28 14:24:10 -04004561func (s *ssaExport) TypeFloat32() ssa.Type { return Types[TFLOAT32] }
4562func (s *ssaExport) TypeFloat64() ssa.Type { return Types[TFLOAT64] }
Josh Bleecher Snyder85e03292015-07-30 11:03:05 -07004563func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] }
4564func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] }
4565func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] }
4566func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) }
4567
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07004568// StringData returns a symbol (a *Sym wrapped in an interface) which
4569// is the data component of a global string constant containing s.
4570func (*ssaExport) StringData(s string) interface{} {
Keith Randall8c46aa52015-06-19 21:02:28 -07004571 // TODO: is idealstring correct? It might not matter...
Josh Bleecher Snyder8d31df18a2015-07-24 11:28:12 -07004572 _, data := stringsym(s)
4573 return &ssa.ExternSymbol{Typ: idealstring, Sym: data}
Keith Randallf7f604e2015-05-27 14:52:22 -07004574}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004575
Keith Randallc24681a2015-10-22 14:22:38 -07004576func (e *ssaExport) Auto(t ssa.Type) ssa.GCNode {
Keith Randalld2107fc2015-08-24 02:16:19 -07004577 n := temp(t.(*Type)) // Note: adds new auto to Curfn.Func.Dcl list
4578 e.mustImplement = true // This modifies the input to SSA, so we want to make sure we succeed from here!
4579 return n
4580}
4581
Keith Randall7d612462015-10-22 13:07:38 -07004582func (e *ssaExport) CanSSA(t ssa.Type) bool {
Keith Randall37590bd2015-09-18 22:58:10 -07004583 return canSSAType(t.(*Type))
4584}
4585
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004586// Log logs a message from the compiler.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07004587func (e *ssaExport) Logf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004588 // If e was marked as unimplemented, anything could happen. Ignore.
4589 if e.log && !e.unimplemented {
4590 fmt.Printf(msg, args...)
4591 }
4592}
4593
4594// Fatal reports a compiler error and exits.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07004595func (e *ssaExport) Fatalf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004596 // If e was marked as unimplemented, anything could happen. Ignore.
4597 if !e.unimplemented {
Keith Randall0ec72b62015-09-08 15:42:53 -07004598 Fatalf(msg, args...)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004599 }
4600}
4601
4602// Unimplemented reports that the function cannot be compiled.
4603// It will be removed once SSA work is complete.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07004604func (e *ssaExport) Unimplementedf(msg string, args ...interface{}) {
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004605 if e.mustImplement {
Keith Randall0ec72b62015-09-08 15:42:53 -07004606 Fatalf(msg, args...)
Josh Bleecher Snyderd2982092015-07-22 13:13:53 -07004607 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07004608 const alwaysLog = false // enable to calculate top unimplemented features
4609 if !e.unimplemented && (e.log || alwaysLog) {
4610 // first implementation failure, print explanation
4611 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
4612 }
4613 e.unimplemented = true
4614}
Keith Randallc24681a2015-10-22 14:22:38 -07004615
David Chase729abfa2015-10-26 17:34:06 -04004616// Warnl reports a "warning", which is usually flag-triggered
4617// logging output for the benefit of tests.
4618func (e *ssaExport) Warnl(line int, fmt_ string, args ...interface{}) {
4619 Warnl(line, fmt_, args...)
4620}
4621
4622func (e *ssaExport) Debug_checknil() bool {
4623 return Debug_checknil != 0
4624}
4625
Keith Randallc24681a2015-10-22 14:22:38 -07004626func (n *Node) Typ() ssa.Type {
4627 return n.Type
4628}