blob: cff1ea71dc867cad8ef14597bad5a2f839fd59df [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 Snyder8c6abfe2015-06-12 11:01:13 -07008 "fmt"
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -06009 "strings"
Keith Randalld2fd43a2015-04-15 15:51:25 -070010
Keith Randall067e8df2015-05-28 13:49:20 -070011 "cmd/compile/internal/ssa"
Keith Randall083a6462015-05-12 11:06:44 -070012 "cmd/internal/obj"
Keith Randall8c46aa52015-06-19 21:02:28 -070013 "cmd/internal/obj/x86"
Keith Randalld2fd43a2015-04-15 15:51:25 -070014)
15
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070016// buildssa builds an SSA function
17// and reports whether it should be used.
18// Once the SSA implementation is complete,
19// it will never return nil, and the bool can be removed.
20func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
21 name := fn.Func.Nname.Sym.Name
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -060022 usessa = strings.HasSuffix(name, "_ssa")
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070023
24 if usessa {
25 dumplist("buildssa-enter", fn.Func.Enter)
26 dumplist("buildssa-body", fn.Nbody)
27 }
Keith Randalld2fd43a2015-04-15 15:51:25 -070028
Keith Randallcfc2aa52015-05-18 16:44:20 -070029 var s state
Michael Matloob81ccf502015-05-30 01:03:06 -040030 s.pushLine(fn.Lineno)
31 defer s.popLine()
32
Keith Randalld2fd43a2015-04-15 15:51:25 -070033 // TODO(khr): build config just once at the start of the compiler binary
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070034
35 var e ssaExport
36 e.log = usessa
37 s.config = ssa.NewConfig(Thearch.Thestring, &e)
Keith Randalld2fd43a2015-04-15 15:51:25 -070038 s.f = s.config.NewFunc()
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070039 s.f.Name = name
40
41 // If SSA support for the function is incomplete,
42 // assume that any panics are due to violated
43 // invariants. Swallow them silently.
44 defer func() {
45 if err := recover(); err != nil {
46 if !e.unimplemented {
47 panic(err)
48 }
49 }
50 }()
Keith Randalld2fd43a2015-04-15 15:51:25 -070051
52 // We construct SSA using an algorithm similar to
53 // Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau
54 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
55 // TODO: check this comment
56
57 // Allocate starting block
58 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
59
60 // Allocate exit block
61 s.exit = s.f.NewBlock(ssa.BlockExit)
62
Keith Randallcfc2aa52015-05-18 16:44:20 -070063 // Allocate starting values
Keith Randall8c46aa52015-06-19 21:02:28 -070064 s.vars = map[*Node]*ssa.Value{}
Keith Randalld2fd43a2015-04-15 15:51:25 -070065 s.labels = map[string]*ssa.Block{}
Keith Randall8c46aa52015-06-19 21:02:28 -070066 s.startmem = s.entryNewValue0(ssa.OpArg, ssa.TypeMem)
67 s.sp = s.entryNewValue0(ssa.OpSP, s.config.Uintptr) // TODO: use generic pointer type (unsafe.Pointer?) instead
68 s.sb = s.entryNewValue0(ssa.OpSB, s.config.Uintptr)
69
70 // Generate addresses of local declarations
71 s.decladdrs = map[*Node]*ssa.Value{}
72 for d := fn.Func.Dcl; d != nil; d = d.Next {
73 n := d.N
74 switch n.Class {
75 case PPARAM, PPARAMOUT:
76 aux := &ssa.ArgSymbol{Typ: n.Type, Offset: n.Xoffset, Sym: n.Sym}
77 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
78 case PAUTO:
79 aux := &ssa.AutoSymbol{Typ: n.Type, Offset: -1, Sym: n.Sym} // offset TBD by SSA pass
80 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
Daniel Morsingbe2a3e22015-07-01 20:37:25 +010081 default:
82 str := ""
83 if n.Class&PHEAP != 0 {
84 str = ",heap"
85 }
86 s.Unimplementedf("local variable %v with class %s%s unimplemented", n, classnames[n.Class&^PHEAP], str)
Keith Randall8c46aa52015-06-19 21:02:28 -070087 }
88 }
89 // nodfp is a special argument which is the function's FP.
90 aux := &ssa.ArgSymbol{Typ: s.config.Uintptr, Offset: 0, Sym: nodfp.Sym}
91 s.decladdrs[nodfp] = s.entryNewValue1A(ssa.OpAddr, s.config.Uintptr, aux, s.sp)
Keith Randalld2fd43a2015-04-15 15:51:25 -070092
93 // Convert the AST-based IR to the SSA-based IR
94 s.startBlock(s.f.Entry)
Keith Randallf7f604e2015-05-27 14:52:22 -070095 s.stmtList(fn.Func.Enter)
Keith Randalld2fd43a2015-04-15 15:51:25 -070096 s.stmtList(fn.Nbody)
97
Keith Randallcfc2aa52015-05-18 16:44:20 -070098 // fallthrough to exit
99 if b := s.endBlock(); b != nil {
100 addEdge(b, s.exit)
101 }
102
Keith Randalld2fd43a2015-04-15 15:51:25 -0700103 // Finish up exit block
104 s.startBlock(s.exit)
105 s.exit.Control = s.mem()
106 s.endBlock()
107
108 // Link up variable uses to variable definitions
109 s.linkForwardReferences()
110
Keith Randall083a6462015-05-12 11:06:44 -0700111 // Main call to ssa package to compile function
Keith Randalld2fd43a2015-04-15 15:51:25 -0700112 ssa.Compile(s.f)
113
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700114 // Calculate stats about what percentage of functions SSA handles.
115 if false {
116 fmt.Printf("SSA implemented: %t\n", !e.unimplemented)
117 }
118
119 if e.unimplemented {
120 return nil, false
121 }
122 return s.f, usessa // TODO: return s.f, true once runtime support is in (gc maps, write barriers, etc.)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700123}
124
Keith Randallcfc2aa52015-05-18 16:44:20 -0700125type state struct {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700126 // configuration (arch) information
127 config *ssa.Config
128
129 // function we're building
130 f *ssa.Func
131
132 // exit block that "return" jumps to (and panics jump to)
133 exit *ssa.Block
134
135 // the target block for each label in f
136 labels map[string]*ssa.Block
137
138 // current location where we're interpreting the AST
139 curBlock *ssa.Block
140
Keith Randall8c46aa52015-06-19 21:02:28 -0700141 // variable assignments in the current block (map from variable symbol to ssa value)
142 // *Node is the unique identifier (an ONAME Node) for the variable.
143 vars map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700144
145 // all defined variables at the end of each block. Indexed by block ID.
Keith Randall8c46aa52015-06-19 21:02:28 -0700146 defvars []map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700147
Keith Randall8c46aa52015-06-19 21:02:28 -0700148 // addresses of PPARAM, PPARAMOUT, and PAUTO variables.
149 decladdrs map[*Node]*ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700150
151 // starting values. Memory, frame pointer, and stack pointer
152 startmem *ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700153 sp *ssa.Value
Keith Randall8c46aa52015-06-19 21:02:28 -0700154 sb *ssa.Value
Michael Matloob81ccf502015-05-30 01:03:06 -0400155
156 // line number stack. The current line number is top of stack
157 line []int32
Keith Randalld2fd43a2015-04-15 15:51:25 -0700158}
159
Josh Bleecher Snyder1edf4892015-07-03 20:29:11 -0700160func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700161func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(msg, args...) }
162func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimplementedf(msg, args...) }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700163
Keith Randall8c46aa52015-06-19 21:02:28 -0700164// dummy node for the memory variable
165var memvar = Node{Op: ONAME, Sym: &Sym{Name: "mem"}}
166
Keith Randalld2fd43a2015-04-15 15:51:25 -0700167// startBlock sets the current block we're generating code in to b.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700168func (s *state) startBlock(b *ssa.Block) {
169 if s.curBlock != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700170 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700171 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700172 s.curBlock = b
Keith Randall8c46aa52015-06-19 21:02:28 -0700173 s.vars = map[*Node]*ssa.Value{}
Keith Randalld2fd43a2015-04-15 15:51:25 -0700174}
175
176// endBlock marks the end of generating code for the current block.
177// Returns the (former) current block. Returns nil if there is no current
178// block, i.e. if no code flows to the current execution point.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700179func (s *state) endBlock() *ssa.Block {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700180 b := s.curBlock
181 if b == nil {
182 return nil
183 }
184 for len(s.defvars) <= int(b.ID) {
185 s.defvars = append(s.defvars, nil)
186 }
187 s.defvars[b.ID] = s.vars
188 s.curBlock = nil
189 s.vars = nil
Michael Matloob81ccf502015-05-30 01:03:06 -0400190 b.Line = s.peekLine()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700191 return b
192}
193
Michael Matloob81ccf502015-05-30 01:03:06 -0400194// pushLine pushes a line number on the line number stack.
195func (s *state) pushLine(line int32) {
196 s.line = append(s.line, line)
197}
198
199// popLine pops the top of the line number stack.
200func (s *state) popLine() {
201 s.line = s.line[:len(s.line)-1]
202}
203
204// peekLine peek the top of the line number stack.
205func (s *state) peekLine() int32 {
206 return s.line[len(s.line)-1]
207}
208
Keith Randall8f22b522015-06-11 21:29:25 -0700209// newValue0 adds a new value with no arguments to the current block.
210func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
211 return s.curBlock.NewValue0(s.peekLine(), op, t)
212}
213
214// newValue0A adds a new value with no arguments and an aux value to the current block.
215func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
216 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400217}
218
219// newValue1 adds a new value with one argument to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700220func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
221 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
222}
223
224// newValue1A adds a new value with one argument and an aux value to the current block.
225func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
226 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400227}
228
229// newValue2 adds a new value with two arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700230func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
231 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400232}
233
Daniel Morsing66b47812015-06-27 15:45:20 +0100234// newValue2I adds a new value with two arguments and an auxint value to the current block.
235func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
236 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
237}
238
Michael Matloob81ccf502015-05-30 01:03:06 -0400239// newValue3 adds a new value with three arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700240func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
241 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
Michael Matloob81ccf502015-05-30 01:03:06 -0400242}
243
244// entryNewValue adds a new value with no arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700245func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
246 return s.f.Entry.NewValue0(s.peekLine(), op, t)
247}
248
249// entryNewValue adds a new value with no arguments and an aux value to the entry block.
250func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
251 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400252}
253
254// entryNewValue1 adds a new value with one argument to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700255func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
256 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
257}
258
259// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
260func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
261 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400262}
263
Keith Randall8c46aa52015-06-19 21:02:28 -0700264// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
265func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
266 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
267}
268
Michael Matloob81ccf502015-05-30 01:03:06 -0400269// entryNewValue2 adds a new value with two arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700270func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
271 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400272}
273
274// constInt adds a new const int value to the entry block.
275func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
276 return s.f.ConstInt(s.peekLine(), t, c)
277}
278
Keith Randalld2fd43a2015-04-15 15:51:25 -0700279// ssaStmtList converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700280func (s *state) stmtList(l *NodeList) {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700281 for ; l != nil; l = l.Next {
282 s.stmt(l.N)
283 }
284}
285
286// ssaStmt converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700287func (s *state) stmt(n *Node) {
Michael Matloob81ccf502015-05-30 01:03:06 -0400288 s.pushLine(n.Lineno)
289 defer s.popLine()
290
Keith Randalld2fd43a2015-04-15 15:51:25 -0700291 s.stmtList(n.Ninit)
292 switch n.Op {
293
294 case OBLOCK:
295 s.stmtList(n.List)
296
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600297 case OEMPTY:
298
Keith Randalld2fd43a2015-04-15 15:51:25 -0700299 case ODCL:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100300 if n.Left.Class&PHEAP == 0 {
301 return
302 }
303 if compiling_runtime != 0 {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700304 Fatal("%v escapes to heap, not allowed in runtime.", n)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100305 }
306
307 // TODO: the old pass hides the details of PHEAP
308 // variables behind ONAME nodes. Figure out if it's better
309 // to rewrite the tree and make the heapaddr construct explicit
310 // or to keep this detail hidden behind the scenes.
311 palloc := prealloc[n.Left]
312 if palloc == nil {
313 palloc = callnew(n.Left.Type)
314 prealloc[n.Left] = palloc
315 }
316 s.assign(OAS, n.Left.Name.Heapaddr, palloc)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700317
318 case OLABEL, OGOTO:
319 // get block at label, or make one
320 t := s.labels[n.Left.Sym.Name]
321 if t == nil {
322 t = s.f.NewBlock(ssa.BlockPlain)
323 s.labels[n.Left.Sym.Name] = t
324 }
325 // go to that label (we pretend "label:" is preceded by "goto label")
Keith Randall0ad9c8c2015-06-12 16:24:33 -0700326 if b := s.endBlock(); b != nil {
327 addEdge(b, t)
328 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700329
330 if n.Op == OLABEL {
331 // next we work on the label's target block
332 s.startBlock(t)
333 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700334 if n.Op == OGOTO && s.curBlock == nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700335 s.Unimplementedf("goto at start of function; see test/goto.go")
Josh Bleecher Snyderd465f042015-07-04 13:01:04 -0700336 panic("stop compiling here, on pain of infinite loops")
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700337 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700338
Keith Randall290d8fc2015-06-10 15:03:06 -0700339 case OAS, OASWB:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100340 s.assign(n.Op, n.Left, n.Right)
341
Keith Randalld2fd43a2015-04-15 15:51:25 -0700342 case OIF:
Keith Randalle707fbe2015-06-11 10:20:39 -0700343 cond := s.expr(n.Left)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700344 b := s.endBlock()
345 b.Kind = ssa.BlockIf
346 b.Control = cond
347 // TODO(khr): likely direction
348
349 bThen := s.f.NewBlock(ssa.BlockPlain)
350 bEnd := s.f.NewBlock(ssa.BlockPlain)
351 var bElse *ssa.Block
352
Keith Randalle707fbe2015-06-11 10:20:39 -0700353 if n.Rlist == nil {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700354 addEdge(b, bThen)
355 addEdge(b, bEnd)
356 } else {
357 bElse = s.f.NewBlock(ssa.BlockPlain)
358 addEdge(b, bThen)
359 addEdge(b, bElse)
360 }
361
362 s.startBlock(bThen)
363 s.stmtList(n.Nbody)
364 b = s.endBlock()
365 if b != nil {
366 addEdge(b, bEnd)
367 }
368
Keith Randalle707fbe2015-06-11 10:20:39 -0700369 if n.Rlist != nil {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700370 s.startBlock(bElse)
Keith Randalle707fbe2015-06-11 10:20:39 -0700371 s.stmtList(n.Rlist)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700372 b = s.endBlock()
373 if b != nil {
374 addEdge(b, bEnd)
375 }
376 }
377 s.startBlock(bEnd)
378
379 case ORETURN:
380 s.stmtList(n.List)
381 b := s.endBlock()
382 addEdge(b, s.exit)
383
384 case OFOR:
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700385 // OFOR: for Ninit; Left; Right { Nbody }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700386 bCond := s.f.NewBlock(ssa.BlockPlain)
387 bBody := s.f.NewBlock(ssa.BlockPlain)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700388 bIncr := s.f.NewBlock(ssa.BlockPlain)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700389 bEnd := s.f.NewBlock(ssa.BlockPlain)
390
391 // first, jump to condition test
392 b := s.endBlock()
393 addEdge(b, bCond)
394
395 // generate code to test condition
Keith Randalld2fd43a2015-04-15 15:51:25 -0700396 s.startBlock(bCond)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700397 var cond *ssa.Value
398 if n.Left != nil {
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700399 cond = s.expr(n.Left)
400 } else {
401 cond = s.entryNewValue0A(ssa.OpConst, Types[TBOOL], true)
402 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700403 b = s.endBlock()
404 b.Kind = ssa.BlockIf
405 b.Control = cond
406 // TODO(khr): likely direction
407 addEdge(b, bBody)
408 addEdge(b, bEnd)
409
410 // generate body
411 s.startBlock(bBody)
412 s.stmtList(n.Nbody)
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700413 if b := s.endBlock(); b != nil {
414 addEdge(b, bIncr)
415 }
416
417 // generate incr
418 s.startBlock(bIncr)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700419 if n.Right != nil {
420 s.stmt(n.Right)
421 }
Josh Bleecher Snyder51738682015-07-06 15:29:39 -0700422 if b := s.endBlock(); b != nil {
Josh Bleecher Snyder6c140592015-07-04 09:07:54 -0700423 addEdge(b, bCond)
424 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700425 s.startBlock(bEnd)
426
Michael Matloob2aabacd2015-06-16 17:58:03 -0700427 case OCALLFUNC:
428 s.expr(n)
429
Keith Randalld2fd43a2015-04-15 15:51:25 -0700430 case OVARKILL:
431 // TODO(khr): ??? anything to do here? Only for addrtaken variables?
432 // Maybe just link it in the store chain?
433 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700434 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -0700435 }
436}
437
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700438var binOpToSSA = [...]ssa.Op{
439 // Comparisons
440 OEQ: ssa.OpEq,
441 ONE: ssa.OpNeq,
442 OLT: ssa.OpLess,
443 OLE: ssa.OpLeq,
444 OGT: ssa.OpGreater,
445 OGE: ssa.OpGeq,
446 // Arithmetic
447 OADD: ssa.OpAdd,
448 OSUB: ssa.OpSub,
449 OLSH: ssa.OpLsh,
450 ORSH: ssa.OpRsh,
451}
452
Keith Randalld2fd43a2015-04-15 15:51:25 -0700453// expr converts the expression n to ssa, adds it to s and returns the ssa result.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700454func (s *state) expr(n *Node) *ssa.Value {
Michael Matloob81ccf502015-05-30 01:03:06 -0400455 s.pushLine(n.Lineno)
456 defer s.popLine()
457
Keith Randall06f32922015-07-11 11:39:12 -0700458 s.stmtList(n.Ninit)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700459 switch n.Op {
460 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -0700461 if n.Class == PFUNC {
462 // "value" of a function is the address of the function's closure
Keith Randall8c46aa52015-06-19 21:02:28 -0700463 sym := funcsym(n.Sym)
464 aux := &ssa.ExternSymbol{n.Type, sym}
465 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
Keith Randall23df95b2015-05-12 15:16:52 -0700466 }
Keith Randall290d8fc2015-06-10 15:03:06 -0700467 if canSSA(n) {
Keith Randall8c46aa52015-06-19 21:02:28 -0700468 return s.variable(n, n.Type)
Keith Randall290d8fc2015-06-10 15:03:06 -0700469 }
470 addr := s.addr(n)
Keith Randall8f22b522015-06-11 21:29:25 -0700471 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -0700472 case OLITERAL:
Keith Randalle707fbe2015-06-11 10:20:39 -0700473 switch n.Val().Ctype() {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700474 case CTINT:
Keith Randalle707fbe2015-06-11 10:20:39 -0700475 return s.constInt(n.Type, Mpgetfix(n.Val().U.(*Mpint)))
Josh Bleecher Snyder7d10a2c2015-07-06 14:13:17 -0700476 case CTSTR, CTBOOL:
Keith Randall8f22b522015-06-11 21:29:25 -0700477 return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700478 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700479 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
Keith Randalld2fd43a2015-04-15 15:51:25 -0700480 return nil
481 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -0700482 case OCONVNOP:
483 x := s.expr(n.Left)
Michael Matloobea5cd682015-06-14 10:27:50 -0700484 return s.newValue1(ssa.OpConvNop, n.Type, x)
Michael Matloob73054f52015-06-14 11:38:46 -0700485 case OCONV:
486 x := s.expr(n.Left)
487 return s.newValue1(ssa.OpConvert, n.Type, x)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700488
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700489 // binary ops
490 case OLT, OEQ, ONE, OLE, OGE, OGT:
Keith Randalld2fd43a2015-04-15 15:51:25 -0700491 a := s.expr(n.Left)
492 b := s.expr(n.Right)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700493 return s.newValue2(binOpToSSA[n.Op], ssa.TypeBool, a, b)
494 case OADD, OSUB, OLSH, ORSH:
Keith Randalld2fd43a2015-04-15 15:51:25 -0700495 a := s.expr(n.Left)
496 b := s.expr(n.Right)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700497 return s.newValue2(binOpToSSA[n.Op], a.Type, a, b)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700498
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -0600499 // unary ops
500 case ONOT:
501 a := s.expr(n.Left)
502 return s.newValue1(ssa.OpNot, a.Type, a)
503
Keith Randallcfc2aa52015-05-18 16:44:20 -0700504 case OADDR:
505 return s.addr(n.Left)
506
Keith Randalld2fd43a2015-04-15 15:51:25 -0700507 case OIND:
508 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700509 s.nilCheck(p)
Keith Randall8f22b522015-06-11 21:29:25 -0700510 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -0700511
Keith Randalld2fd43a2015-04-15 15:51:25 -0700512 case ODOTPTR:
513 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700514 s.nilCheck(p)
Keith Randall8f22b522015-06-11 21:29:25 -0700515 p = s.newValue2(ssa.OpAdd, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset))
516 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -0700517
518 case OINDEX:
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700519 if n.Left.Type.Bound >= 0 { // array or string
Keith Randallcfc2aa52015-05-18 16:44:20 -0700520 a := s.expr(n.Left)
521 i := s.expr(n.Right)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700522 var elemtype *Type
523 var len *ssa.Value
524 if n.Left.Type.IsString() {
Keith Randall8f22b522015-06-11 21:29:25 -0700525 len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, a)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700526 elemtype = Types[TUINT8]
527 } else {
Michael Matloob81ccf502015-05-30 01:03:06 -0400528 len = s.constInt(s.config.Uintptr, n.Left.Type.Bound)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700529 elemtype = n.Left.Type.Type
530 }
531 s.boundsCheck(i, len)
Keith Randall8f22b522015-06-11 21:29:25 -0700532 return s.newValue2(ssa.OpArrayIndex, elemtype, a, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700533 } else { // slice
534 p := s.addr(n)
Keith Randall8f22b522015-06-11 21:29:25 -0700535 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -0700536 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700537
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600538 case OLEN, OCAP:
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -0700539 switch {
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600540 case n.Left.Type.IsSlice():
541 op := ssa.OpSliceLen
542 if n.Op == OCAP {
543 op = ssa.OpSliceCap
544 }
545 return s.newValue1(op, s.config.Int, s.expr(n.Left))
546 case n.Left.Type.IsString(): // string; not reachable for OCAP
547 return s.newValue1(ssa.OpStringLen, s.config.Int, s.expr(n.Left))
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -0700548 default: // array
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600549 return s.constInt(s.config.Int, n.Left.Type.Bound)
Josh Bleecher Snydercc3f0312015-07-03 18:41:28 -0700550 }
551
Keith Randalld2fd43a2015-04-15 15:51:25 -0700552 case OCALLFUNC:
Keith Randall290d8fc2015-06-10 15:03:06 -0700553 static := n.Left.Op == ONAME && n.Left.Class == PFUNC
554
555 // evaluate closure
556 var closure *ssa.Value
557 if !static {
558 closure = s.expr(n.Left)
559 }
560
Keith Randalld2fd43a2015-04-15 15:51:25 -0700561 // run all argument assignments
Keith Randalld2fd43a2015-04-15 15:51:25 -0700562 s.stmtList(n.List)
563
Keith Randalld2fd43a2015-04-15 15:51:25 -0700564 bNext := s.f.NewBlock(ssa.BlockPlain)
Keith Randall290d8fc2015-06-10 15:03:06 -0700565 var call *ssa.Value
566 if static {
Keith Randall8f22b522015-06-11 21:29:25 -0700567 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem())
Keith Randall290d8fc2015-06-10 15:03:06 -0700568 } else {
Keith Randall8f22b522015-06-11 21:29:25 -0700569 entry := s.newValue2(ssa.OpLoad, s.config.Uintptr, closure, s.mem())
570 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, entry, closure, s.mem())
Keith Randall290d8fc2015-06-10 15:03:06 -0700571 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700572 b := s.endBlock()
573 b.Kind = ssa.BlockCall
574 b.Control = call
575 addEdge(b, bNext)
576 addEdge(b, s.exit)
577
578 // read result from stack at the start of the fallthrough block
579 s.startBlock(bNext)
580 var titer Iter
581 fp := Structfirst(&titer, Getoutarg(n.Left.Type))
Michael Matloob2aabacd2015-06-16 17:58:03 -0700582 if fp == nil {
583 // CALLFUNC has no return value. Continue with the next statement.
584 return nil
585 }
Keith Randall8f22b522015-06-11 21:29:25 -0700586 a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
587 return s.newValue2(ssa.OpLoad, fp.Type, a, call)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700588 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700589 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -0700590 return nil
591 }
592}
593
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100594func (s *state) assign(op uint8, left *Node, right *Node) {
595 // TODO: do write barrier
596 // if op == OASWB
597 var val *ssa.Value
598 if right == nil {
599 // right == nil means use the zero value of the assigned type.
600 t := left.Type
Daniel Morsing66b47812015-06-27 15:45:20 +0100601 if !canSSA(left) {
602 // if we can't ssa this memory, treat it as just zeroing out the backing memory
603 addr := s.addr(left)
604 s.vars[&memvar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
605 return
606 }
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100607 switch {
608 case t.IsString():
Josh Bleecher Snydera5c3b662015-06-16 16:16:23 -0700609 val = s.entryNewValue0A(ssa.OpConst, left.Type, "")
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100610 case t.IsInteger():
611 val = s.entryNewValue0(ssa.OpConst, left.Type)
612 case t.IsBoolean():
613 val = s.entryNewValue0A(ssa.OpConst, left.Type, false) // TODO: store bools as 0/1 in AuxInt?
614 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700615 s.Unimplementedf("zero for type %v not implemented", t)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100616 }
617 } else {
618 val = s.expr(right)
619 }
620 if left.Op == ONAME && canSSA(left) {
621 // Update variable assignment.
Keith Randall8c46aa52015-06-19 21:02:28 -0700622 s.vars[left] = val
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100623 return
624 }
625 // not ssa-able. Treat as a store.
626 addr := s.addr(left)
Keith Randall8c46aa52015-06-19 21:02:28 -0700627 s.vars[&memvar] = s.newValue3(ssa.OpStore, ssa.TypeMem, addr, val, s.mem())
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100628}
629
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700630// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700631func (s *state) addr(n *Node) *ssa.Value {
632 switch n.Op {
633 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -0700634 switch n.Class {
635 case PEXTERN:
Keith Randallcfc2aa52015-05-18 16:44:20 -0700636 // global variable
Keith Randall8c46aa52015-06-19 21:02:28 -0700637 aux := &ssa.ExternSymbol{n.Type, n.Sym}
638 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
639 case PPARAM, PPARAMOUT, PAUTO:
640 // parameter/result slot or local variable
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -0700641 v := s.decladdrs[n]
642 if v == nil {
Josh Bleecher Snyder0a133cdd2015-07-03 20:28:56 -0700643 if flag_race != 0 && n.String() == ".fp" {
644 s.Unimplementedf("race detector mishandles nodfp")
645 }
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -0700646 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
647 }
648 return v
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100649 case PAUTO | PHEAP:
650 return s.expr(n.Name.Heapaddr)
Keith Randall290d8fc2015-06-10 15:03:06 -0700651 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700652 s.Unimplementedf("variable address of %v not implemented", n)
Keith Randall290d8fc2015-06-10 15:03:06 -0700653 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -0700654 }
Keith Randallcfc2aa52015-05-18 16:44:20 -0700655 case OINDREG:
656 // indirect off a register (TODO: always SP?)
657 // used for storing/loading arguments/returns to/from callees
Keith Randall8f22b522015-06-11 21:29:25 -0700658 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700659 case OINDEX:
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600660 if n.Left.Type.IsSlice() {
Keith Randallcfc2aa52015-05-18 16:44:20 -0700661 a := s.expr(n.Left)
662 i := s.expr(n.Right)
Keith Randall8f22b522015-06-11 21:29:25 -0700663 len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, a)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700664 s.boundsCheck(i, len)
Keith Randall8f22b522015-06-11 21:29:25 -0700665 p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a)
666 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i)
Brad Fitzpatrick7af53d92015-07-10 10:47:28 -0600667 } else { // array
668 a := s.addr(n.Left)
669 i := s.expr(n.Right)
670 len := s.constInt(s.config.Uintptr, n.Left.Type.Bound)
671 s.boundsCheck(i, len)
672 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700673 }
674 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700675 s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0))
Keith Randallcfc2aa52015-05-18 16:44:20 -0700676 return nil
677 }
678}
679
Keith Randall290d8fc2015-06-10 15:03:06 -0700680// canSSA reports whether n is SSA-able.
681// n must be an ONAME.
682func canSSA(n *Node) bool {
683 if n.Op != ONAME {
Daniel Morsing66b47812015-06-27 15:45:20 +0100684 return false
Keith Randall290d8fc2015-06-10 15:03:06 -0700685 }
686 if n.Addrtaken {
687 return false
688 }
689 if n.Class&PHEAP != 0 {
690 return false
691 }
692 if n.Class == PEXTERN {
693 return false
694 }
695 if n.Class == PPARAMOUT {
696 return false
697 }
Daniel Morsing66b47812015-06-27 15:45:20 +0100698 if Isfat(n.Type) {
699 return false
700 }
Keith Randall290d8fc2015-06-10 15:03:06 -0700701 return true
702 // TODO: try to make more variables SSAable.
703}
704
Keith Randallcfc2aa52015-05-18 16:44:20 -0700705// nilCheck generates nil pointer checking code.
706// Starts a new block on return.
707func (s *state) nilCheck(ptr *ssa.Value) {
Keith Randall8f22b522015-06-11 21:29:25 -0700708 c := s.newValue1(ssa.OpIsNonNil, ssa.TypeBool, ptr)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700709 b := s.endBlock()
710 b.Kind = ssa.BlockIf
711 b.Control = c
712 bNext := s.f.NewBlock(ssa.BlockPlain)
713 addEdge(b, bNext)
714 addEdge(b, s.exit)
715 s.startBlock(bNext)
716 // TODO(khr): Don't go directly to exit. Go to a stub that calls panicmem first.
717 // TODO: implicit nil checks somehow?
718}
719
720// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
721// Starts a new block on return.
722func (s *state) boundsCheck(idx, len *ssa.Value) {
723 // TODO: convert index to full width?
724 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
725
726 // bounds check
Keith Randall8f22b522015-06-11 21:29:25 -0700727 cmp := s.newValue2(ssa.OpIsInBounds, ssa.TypeBool, idx, len)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700728 b := s.endBlock()
729 b.Kind = ssa.BlockIf
730 b.Control = cmp
731 bNext := s.f.NewBlock(ssa.BlockPlain)
732 addEdge(b, bNext)
733 addEdge(b, s.exit)
734 // TODO: don't go directly to s.exit. Go to a stub that calls panicindex first.
735 s.startBlock(bNext)
736}
737
Keith Randalld2fd43a2015-04-15 15:51:25 -0700738// variable returns the value of a variable at the current location.
Keith Randall8c46aa52015-06-19 21:02:28 -0700739func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700740 if s.curBlock == nil {
Josh Bleecher Snyder44be0e92015-06-24 13:29:05 -0700741 // Unimplemented instead of Fatal because fixedbugs/bug303.go
742 // demonstrates a case in which this appears to happen legitimately.
743 // TODO: decide on the correct behavior here.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700744 s.Unimplementedf("nil curblock adding variable %v (%v)", name, t)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700745 }
746 v := s.vars[name]
747 if v == nil {
748 // TODO: get type? Take Sym as arg?
Keith Randall8f22b522015-06-11 21:29:25 -0700749 v = s.newValue0A(ssa.OpFwdRef, t, name)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700750 s.vars[name] = v
751 }
752 return v
753}
754
Keith Randallcfc2aa52015-05-18 16:44:20 -0700755func (s *state) mem() *ssa.Value {
Keith Randall8c46aa52015-06-19 21:02:28 -0700756 return s.variable(&memvar, ssa.TypeMem)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700757}
758
Keith Randallcfc2aa52015-05-18 16:44:20 -0700759func (s *state) linkForwardReferences() {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700760 // Build ssa graph. Each variable on its first use in a basic block
761 // leaves a FwdRef in that block representing the incoming value
762 // of that variable. This function links that ref up with possible definitions,
763 // inserting Phi values as needed. This is essentially the algorithm
764 // described by Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
765 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
766 for _, b := range s.f.Blocks {
767 for _, v := range b.Values {
768 if v.Op != ssa.OpFwdRef {
769 continue
770 }
Keith Randall8c46aa52015-06-19 21:02:28 -0700771 name := v.Aux.(*Node)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700772 v.Op = ssa.OpCopy
773 v.Aux = nil
774 v.SetArgs1(s.lookupVarIncoming(b, v.Type, name))
775 }
776 }
777}
778
779// lookupVarIncoming finds the variable's value at the start of block b.
Keith Randall8c46aa52015-06-19 21:02:28 -0700780func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700781 // TODO(khr): have lookupVarIncoming overwrite the fwdRef or copy it
782 // will be used in, instead of having the result used in a copy value.
783 if b == s.f.Entry {
Keith Randall8c46aa52015-06-19 21:02:28 -0700784 if name == &memvar {
Keith Randallcfc2aa52015-05-18 16:44:20 -0700785 return s.startmem
Keith Randalld2fd43a2015-04-15 15:51:25 -0700786 }
787 // variable is live at the entry block. Load it.
Keith Randall8c46aa52015-06-19 21:02:28 -0700788 addr := s.decladdrs[name]
789 if addr == nil {
790 // TODO: closure args reach here.
791 s.Unimplementedf("variable %s not found", name)
792 }
793 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
794 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
795 }
Keith Randall8f22b522015-06-11 21:29:25 -0700796 return s.entryNewValue2(ssa.OpLoad, t, addr, s.startmem)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700797 }
798 var vals []*ssa.Value
799 for _, p := range b.Preds {
800 vals = append(vals, s.lookupVarOutgoing(p, t, name))
801 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700802 if len(vals) == 0 {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700803 s.Unimplementedf("TODO: Handle fixedbugs/bug076.go")
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700804 return nil
805 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700806 v0 := vals[0]
807 for i := 1; i < len(vals); i++ {
808 if vals[i] != v0 {
809 // need a phi value
Keith Randall8f22b522015-06-11 21:29:25 -0700810 v := b.NewValue0(s.peekLine(), ssa.OpPhi, t)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700811 v.AddArgs(vals...)
812 return v
813 }
814 }
815 return v0
816}
817
818// lookupVarOutgoing finds the variable's value at the end of block b.
Keith Randall8c46aa52015-06-19 21:02:28 -0700819func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700820 m := s.defvars[b.ID]
821 if v, ok := m[name]; ok {
822 return v
823 }
824 // The variable is not defined by b and we haven't
825 // looked it up yet. Generate v, a copy value which
826 // will be the outgoing value of the variable. Then
827 // look up w, the incoming value of the variable.
828 // Make v = copy(w). We need the extra copy to
829 // prevent infinite recursion when looking up the
830 // incoming value of the variable.
Keith Randall8f22b522015-06-11 21:29:25 -0700831 v := b.NewValue0(s.peekLine(), ssa.OpCopy, t)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700832 m[name] = v
833 v.AddArg(s.lookupVarIncoming(b, t, name))
834 return v
835}
836
837// TODO: the above mutually recursive functions can lead to very deep stacks. Fix that.
838
839// addEdge adds an edge from b to c.
840func addEdge(b, c *ssa.Block) {
841 b.Succs = append(b.Succs, c)
842 c.Preds = append(c.Preds, b)
843}
Keith Randall083a6462015-05-12 11:06:44 -0700844
845// an unresolved branch
846type branch struct {
847 p *obj.Prog // branch instruction
848 b *ssa.Block // target
849}
850
851// genssa appends entries to ptxt for each instruction in f.
852// gcargs and gclocals are filled in with pointer maps for the frame.
853func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
854 // TODO: line numbers
Keith Randall083a6462015-05-12 11:06:44 -0700855
Keith Randall247786c2015-05-28 10:47:24 -0700856 if f.FrameSize > 1<<31 {
Keith Randall083a6462015-05-12 11:06:44 -0700857 Yyerror("stack frame too large (>2GB)")
858 return
859 }
Keith Randall083a6462015-05-12 11:06:44 -0700860
861 ptxt.To.Type = obj.TYPE_TEXTSIZE
862 ptxt.To.Val = int32(Rnd(Curfn.Type.Argwid, int64(Widthptr))) // arg size
Keith Randall247786c2015-05-28 10:47:24 -0700863 ptxt.To.Offset = f.FrameSize - 8 // TODO: arch-dependent
Keith Randall083a6462015-05-12 11:06:44 -0700864
865 // Remember where each block starts.
866 bstart := make([]*obj.Prog, f.NumBlocks())
867
868 // Remember all the branch instructions we've seen
869 // and where they would like to go
870 var branches []branch
871
872 // Emit basic blocks
873 for i, b := range f.Blocks {
874 bstart[b.ID] = Pc
875 // Emit values in block
876 for _, v := range b.Values {
Keith Randall247786c2015-05-28 10:47:24 -0700877 genValue(v)
Keith Randall083a6462015-05-12 11:06:44 -0700878 }
879 // Emit control flow instructions for block
880 var next *ssa.Block
881 if i < len(f.Blocks)-1 {
882 next = f.Blocks[i+1]
883 }
884 branches = genBlock(b, next, branches)
885 }
886
887 // Resolve branches
888 for _, br := range branches {
889 br.p.To.Val = bstart[br.b.ID]
890 }
891
892 Pc.As = obj.ARET // overwrite AEND
893
894 // TODO: liveness
895 // TODO: gcargs
896 // TODO: gclocals
897
898 // TODO: dump frame if -f
899
900 // Emit garbage collection symbols. TODO: put something in them
Keith Randallf7f604e2015-05-27 14:52:22 -0700901 //liveness(Curfn, ptxt, gcargs, gclocals)
902 duint32(gcargs, 0, 0)
903 ggloblsym(gcargs, 4, obj.RODATA|obj.DUPOK)
904 duint32(gclocals, 0, 0)
905 ggloblsym(gclocals, 4, obj.RODATA|obj.DUPOK)
Keith Randall083a6462015-05-12 11:06:44 -0700906}
907
Keith Randall247786c2015-05-28 10:47:24 -0700908func genValue(v *ssa.Value) {
Michael Matloob81ccf502015-05-30 01:03:06 -0400909 lineno = v.Line
Keith Randall083a6462015-05-12 11:06:44 -0700910 switch v.Op {
Keith Randall0dca7352015-06-06 16:03:33 -0700911 case ssa.OpAMD64ADDQ:
Keith Randall083a6462015-05-12 11:06:44 -0700912 // TODO: use addq instead of leaq if target is in the right register.
913 p := Prog(x86.ALEAQ)
914 p.From.Type = obj.TYPE_MEM
915 p.From.Reg = regnum(v.Args[0])
916 p.From.Scale = 1
917 p.From.Index = regnum(v.Args[1])
918 p.To.Type = obj.TYPE_REG
919 p.To.Reg = regnum(v)
Michael Matloob73054f52015-06-14 11:38:46 -0700920 case ssa.OpAMD64ADDL:
921 p := Prog(x86.ALEAL)
922 p.From.Type = obj.TYPE_MEM
923 p.From.Reg = regnum(v.Args[0])
924 p.From.Scale = 1
925 p.From.Index = regnum(v.Args[1])
926 p.To.Type = obj.TYPE_REG
927 p.To.Reg = regnum(v)
928 case ssa.OpAMD64ADDW:
929 p := Prog(x86.ALEAW)
930 p.From.Type = obj.TYPE_MEM
931 p.From.Reg = regnum(v.Args[0])
932 p.From.Scale = 1
933 p.From.Index = regnum(v.Args[1])
934 p.To.Type = obj.TYPE_REG
935 p.To.Reg = regnum(v)
936 case ssa.OpAMD64ADDB, ssa.OpAMD64ANDQ:
937 r := regnum(v)
938 x := regnum(v.Args[0])
939 y := regnum(v.Args[1])
940 if x != r && y != r {
941 p := Prog(x86.AMOVQ)
942 p.From.Type = obj.TYPE_REG
943 p.From.Reg = x
944 p.To.Type = obj.TYPE_REG
945 p.To.Reg = r
946 x = r
947 }
948 p := Prog(v.Op.Asm())
949 p.From.Type = obj.TYPE_REG
950 p.To.Type = obj.TYPE_REG
951 p.To.Reg = r
952 if x == r {
953 p.From.Reg = y
954 } else {
955 p.From.Reg = x
956 }
Keith Randall0dca7352015-06-06 16:03:33 -0700957 case ssa.OpAMD64ADDQconst:
Keith Randall083a6462015-05-12 11:06:44 -0700958 // TODO: use addq instead of leaq if target is in the right register.
959 p := Prog(x86.ALEAQ)
960 p.From.Type = obj.TYPE_MEM
961 p.From.Reg = regnum(v.Args[0])
Keith Randall8f22b522015-06-11 21:29:25 -0700962 p.From.Offset = v.AuxInt
Keith Randall083a6462015-05-12 11:06:44 -0700963 p.To.Type = obj.TYPE_REG
964 p.To.Reg = regnum(v)
Keith Randall0dca7352015-06-06 16:03:33 -0700965 case ssa.OpAMD64MULQconst:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700966 v.Unimplementedf("IMULQ doasm")
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700967 return
Keith Randall247786c2015-05-28 10:47:24 -0700968 // TODO: this isn't right. doasm fails on it. I don't think obj
969 // has ever been taught to compile imul $c, r1, r2.
970 p := Prog(x86.AIMULQ)
971 p.From.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -0700972 p.From.Offset = v.AuxInt
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700973 p.From3 = new(obj.Addr)
Keith Randall247786c2015-05-28 10:47:24 -0700974 p.From3.Type = obj.TYPE_REG
975 p.From3.Reg = regnum(v.Args[0])
976 p.To.Type = obj.TYPE_REG
977 p.To.Reg = regnum(v)
Keith Randall0dca7352015-06-06 16:03:33 -0700978 case ssa.OpAMD64SUBQconst:
Keith Randall083a6462015-05-12 11:06:44 -0700979 // This code compensates for the fact that the register allocator
980 // doesn't understand 2-address instructions yet. TODO: fix that.
981 x := regnum(v.Args[0])
982 r := regnum(v)
983 if x != r {
984 p := Prog(x86.AMOVQ)
985 p.From.Type = obj.TYPE_REG
986 p.From.Reg = x
987 p.To.Type = obj.TYPE_REG
988 p.To.Reg = r
989 x = r
990 }
991 p := Prog(x86.ASUBQ)
992 p.From.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -0700993 p.From.Offset = v.AuxInt
Keith Randall083a6462015-05-12 11:06:44 -0700994 p.To.Type = obj.TYPE_REG
995 p.To.Reg = r
Michael Matloob703ef062015-06-16 11:11:16 -0700996 case ssa.OpAMD64SHLQ, ssa.OpAMD64SHRQ, ssa.OpAMD64SARQ:
Keith Randall6f188472015-06-10 10:39:57 -0700997 x := regnum(v.Args[0])
998 r := regnum(v)
999 if x != r {
1000 if r == x86.REG_CX {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001001 v.Fatalf("can't implement %s, target and shift both in CX", v.LongString())
Keith Randall6f188472015-06-10 10:39:57 -07001002 }
1003 p := Prog(x86.AMOVQ)
1004 p.From.Type = obj.TYPE_REG
1005 p.From.Reg = x
1006 p.To.Type = obj.TYPE_REG
1007 p.To.Reg = r
1008 x = r
1009 }
Michael Matloob703ef062015-06-16 11:11:16 -07001010 p := Prog(v.Op.Asm())
Keith Randall6f188472015-06-10 10:39:57 -07001011 p.From.Type = obj.TYPE_REG
1012 p.From.Reg = regnum(v.Args[1]) // should be CX
1013 p.To.Type = obj.TYPE_REG
1014 p.To.Reg = r
Michael Matloob703ef062015-06-16 11:11:16 -07001015 case ssa.OpAMD64SHLQconst, ssa.OpAMD64SHRQconst, ssa.OpAMD64SARQconst:
Keith Randall247786c2015-05-28 10:47:24 -07001016 x := regnum(v.Args[0])
1017 r := regnum(v)
1018 if x != r {
1019 p := Prog(x86.AMOVQ)
1020 p.From.Type = obj.TYPE_REG
1021 p.From.Reg = x
1022 p.To.Type = obj.TYPE_REG
1023 p.To.Reg = r
1024 x = r
1025 }
Michael Matloob703ef062015-06-16 11:11:16 -07001026 p := Prog(v.Op.Asm())
Keith Randall247786c2015-05-28 10:47:24 -07001027 p.From.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -07001028 p.From.Offset = v.AuxInt
Keith Randall247786c2015-05-28 10:47:24 -07001029 p.To.Type = obj.TYPE_REG
Keith Randalldbd83c42015-06-28 06:08:50 -07001030 p.To.Reg = r
Keith Randall6f188472015-06-10 10:39:57 -07001031 case ssa.OpAMD64SBBQcarrymask:
1032 r := regnum(v)
1033 p := Prog(x86.ASBBQ)
1034 p.From.Type = obj.TYPE_REG
1035 p.From.Reg = r
1036 p.To.Type = obj.TYPE_REG
1037 p.To.Reg = r
1038 case ssa.OpAMD64CMOVQCC:
1039 r := regnum(v)
1040 x := regnum(v.Args[1])
1041 y := regnum(v.Args[2])
1042 if x != r && y != r {
1043 p := Prog(x86.AMOVQ)
1044 p.From.Type = obj.TYPE_REG
1045 p.From.Reg = x
1046 p.To.Type = obj.TYPE_REG
1047 p.To.Reg = r
1048 x = r
1049 }
1050 var p *obj.Prog
1051 if x == r {
1052 p = Prog(x86.ACMOVQCS)
1053 p.From.Reg = y
1054 } else {
1055 p = Prog(x86.ACMOVQCC)
1056 p.From.Reg = x
1057 }
1058 p.From.Type = obj.TYPE_REG
1059 p.To.Type = obj.TYPE_REG
1060 p.To.Reg = r
Keith Randall8c46aa52015-06-19 21:02:28 -07001061 case ssa.OpAMD64LEAQ1:
Keith Randall247786c2015-05-28 10:47:24 -07001062 p := Prog(x86.ALEAQ)
1063 p.From.Type = obj.TYPE_MEM
1064 p.From.Reg = regnum(v.Args[0])
1065 p.From.Scale = 1
1066 p.From.Index = regnum(v.Args[1])
Keith Randall8c46aa52015-06-19 21:02:28 -07001067 addAux(&p.From, v)
1068 p.To.Type = obj.TYPE_REG
1069 p.To.Reg = regnum(v)
1070 case ssa.OpAMD64LEAQ:
1071 p := Prog(x86.ALEAQ)
1072 p.From.Type = obj.TYPE_MEM
1073 p.From.Reg = regnum(v.Args[0])
1074 addAux(&p.From, v)
Keith Randall247786c2015-05-28 10:47:24 -07001075 p.To.Type = obj.TYPE_REG
1076 p.To.Reg = regnum(v)
Michael Matloob703ef062015-06-16 11:11:16 -07001077 case ssa.OpAMD64CMPQ, ssa.OpAMD64TESTB, ssa.OpAMD64TESTQ:
1078 p := Prog(v.Op.Asm())
Keith Randall083a6462015-05-12 11:06:44 -07001079 p.From.Type = obj.TYPE_REG
Keith Randallcfc2aa52015-05-18 16:44:20 -07001080 p.From.Reg = regnum(v.Args[0])
Keith Randall083a6462015-05-12 11:06:44 -07001081 p.To.Type = obj.TYPE_REG
Keith Randallcfc2aa52015-05-18 16:44:20 -07001082 p.To.Reg = regnum(v.Args[1])
Keith Randall0dca7352015-06-06 16:03:33 -07001083 case ssa.OpAMD64CMPQconst:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001084 p := Prog(x86.ACMPQ)
1085 p.From.Type = obj.TYPE_REG
1086 p.From.Reg = regnum(v.Args[0])
1087 p.To.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -07001088 p.To.Offset = v.AuxInt
Keith Randall0dca7352015-06-06 16:03:33 -07001089 case ssa.OpAMD64MOVQconst:
Keith Randall083a6462015-05-12 11:06:44 -07001090 x := regnum(v)
1091 p := Prog(x86.AMOVQ)
1092 p.From.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -07001093 p.From.Offset = v.AuxInt
Keith Randall083a6462015-05-12 11:06:44 -07001094 p.To.Type = obj.TYPE_REG
1095 p.To.Reg = x
Michael Matloob73054f52015-06-14 11:38:46 -07001096 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload:
Michael Matloob703ef062015-06-16 11:11:16 -07001097 p := Prog(v.Op.Asm())
Keith Randallcfc2aa52015-05-18 16:44:20 -07001098 p.From.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07001099 p.From.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07001100 addAux(&p.From, v)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001101 p.To.Type = obj.TYPE_REG
1102 p.To.Reg = regnum(v)
Keith Randall0dca7352015-06-06 16:03:33 -07001103 case ssa.OpAMD64MOVQloadidx8:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001104 p := Prog(x86.AMOVQ)
1105 p.From.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07001106 p.From.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07001107 addAux(&p.From, v)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001108 p.From.Scale = 8
1109 p.From.Index = regnum(v.Args[1])
1110 p.To.Type = obj.TYPE_REG
1111 p.To.Reg = regnum(v)
Michael Matloob73054f52015-06-14 11:38:46 -07001112 case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore:
1113 p := Prog(v.Op.Asm())
Keith Randall083a6462015-05-12 11:06:44 -07001114 p.From.Type = obj.TYPE_REG
Keith Randallcfc2aa52015-05-18 16:44:20 -07001115 p.From.Reg = regnum(v.Args[1])
Keith Randall083a6462015-05-12 11:06:44 -07001116 p.To.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07001117 p.To.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07001118 addAux(&p.To, v)
Michael Matloob73054f52015-06-14 11:38:46 -07001119 case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX:
1120 p := Prog(v.Op.Asm())
1121 p.From.Type = obj.TYPE_REG
1122 p.From.Reg = regnum(v.Args[0])
1123 p.To.Type = obj.TYPE_REG
1124 p.To.Reg = regnum(v)
Daniel Morsing66b47812015-06-27 15:45:20 +01001125 case ssa.OpAMD64MOVXzero:
1126 nb := v.AuxInt
1127 offset := int64(0)
1128 reg := regnum(v.Args[0])
1129 for nb >= 8 {
1130 nb, offset = movZero(x86.AMOVQ, 8, nb, offset, reg)
1131 }
1132 for nb >= 4 {
1133 nb, offset = movZero(x86.AMOVL, 4, nb, offset, reg)
1134 }
1135 for nb >= 2 {
1136 nb, offset = movZero(x86.AMOVW, 2, nb, offset, reg)
1137 }
1138 for nb >= 1 {
1139 nb, offset = movZero(x86.AMOVB, 1, nb, offset, reg)
1140 }
Keith Randallf7f604e2015-05-27 14:52:22 -07001141 case ssa.OpCopy: // TODO: lower to MOVQ earlier?
1142 if v.Type.IsMemory() {
1143 return
1144 }
Keith Randall083a6462015-05-12 11:06:44 -07001145 x := regnum(v.Args[0])
1146 y := regnum(v)
1147 if x != y {
1148 p := Prog(x86.AMOVQ)
1149 p.From.Type = obj.TYPE_REG
1150 p.From.Reg = x
1151 p.To.Type = obj.TYPE_REG
1152 p.To.Reg = y
1153 }
1154 case ssa.OpLoadReg8:
1155 p := Prog(x86.AMOVQ)
1156 p.From.Type = obj.TYPE_MEM
1157 p.From.Reg = x86.REG_SP
Keith Randall247786c2015-05-28 10:47:24 -07001158 p.From.Offset = localOffset(v.Args[0])
Keith Randall083a6462015-05-12 11:06:44 -07001159 p.To.Type = obj.TYPE_REG
1160 p.To.Reg = regnum(v)
1161 case ssa.OpStoreReg8:
1162 p := Prog(x86.AMOVQ)
1163 p.From.Type = obj.TYPE_REG
1164 p.From.Reg = regnum(v.Args[0])
1165 p.To.Type = obj.TYPE_MEM
1166 p.To.Reg = x86.REG_SP
Keith Randall247786c2015-05-28 10:47:24 -07001167 p.To.Offset = localOffset(v)
Keith Randall083a6462015-05-12 11:06:44 -07001168 case ssa.OpPhi:
1169 // just check to make sure regalloc did it right
1170 f := v.Block.Func
1171 loc := f.RegAlloc[v.ID]
1172 for _, a := range v.Args {
1173 if f.RegAlloc[a.ID] != loc { // TODO: .Equal() instead?
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001174 v.Fatalf("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID])
Keith Randall083a6462015-05-12 11:06:44 -07001175 }
1176 }
1177 case ssa.OpConst:
1178 if v.Block.Func.RegAlloc[v.ID] != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001179 v.Fatalf("const value %v shouldn't have a location", v)
Keith Randall083a6462015-05-12 11:06:44 -07001180 }
1181 case ssa.OpArg:
1182 // memory arg needs no code
Keith Randall8f22b522015-06-11 21:29:25 -07001183 // TODO: check that only mem arg goes here.
Keith Randall290d8fc2015-06-10 15:03:06 -07001184 case ssa.OpAMD64CALLstatic:
Keith Randall247786c2015-05-28 10:47:24 -07001185 p := Prog(obj.ACALL)
1186 p.To.Type = obj.TYPE_MEM
1187 p.To.Name = obj.NAME_EXTERN
1188 p.To.Sym = Linksym(v.Aux.(*Sym))
Keith Randall290d8fc2015-06-10 15:03:06 -07001189 case ssa.OpAMD64CALLclosure:
1190 p := Prog(obj.ACALL)
1191 p.To.Type = obj.TYPE_REG
1192 p.To.Reg = regnum(v.Args[0])
Brad Fitzpatrickd9c72d72015-07-10 11:25:48 -06001193 case ssa.OpAMD64XORQconst:
1194 p := Prog(x86.AXORQ)
1195 p.From.Type = obj.TYPE_CONST
1196 p.From.Offset = v.AuxInt
1197 p.To.Type = obj.TYPE_REG
1198 p.To.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07001199 case ssa.OpSP, ssa.OpSB:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001200 // nothing to do
Keith Randall083a6462015-05-12 11:06:44 -07001201 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001202 v.Unimplementedf("value %s not implemented", v.LongString())
Keith Randall083a6462015-05-12 11:06:44 -07001203 }
1204}
1205
Daniel Morsing66b47812015-06-27 15:45:20 +01001206// movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
1207func movZero(as int, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
1208 p := Prog(as)
1209 // TODO: use zero register on archs that support it.
1210 p.From.Type = obj.TYPE_CONST
1211 p.From.Offset = 0
1212 p.To.Type = obj.TYPE_MEM
1213 p.To.Reg = regnum
1214 p.To.Offset = offset
1215 offset += width
1216 nleft = nbytes - width
1217 return nleft, offset
1218}
1219
Keith Randall083a6462015-05-12 11:06:44 -07001220func genBlock(b, next *ssa.Block, branches []branch) []branch {
Michael Matloob81ccf502015-05-30 01:03:06 -04001221 lineno = b.Line
Keith Randall083a6462015-05-12 11:06:44 -07001222 switch b.Kind {
1223 case ssa.BlockPlain:
1224 if b.Succs[0] != next {
1225 p := Prog(obj.AJMP)
1226 p.To.Type = obj.TYPE_BRANCH
1227 branches = append(branches, branch{p, b.Succs[0]})
1228 }
1229 case ssa.BlockExit:
1230 Prog(obj.ARET)
Keith Randall247786c2015-05-28 10:47:24 -07001231 case ssa.BlockCall:
1232 if b.Succs[0] != next {
1233 p := Prog(obj.AJMP)
1234 p.To.Type = obj.TYPE_BRANCH
1235 branches = append(branches, branch{p, b.Succs[0]})
1236 }
Keith Randall0dca7352015-06-06 16:03:33 -07001237 case ssa.BlockAMD64EQ:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001238 if b.Succs[0] == next {
1239 p := Prog(x86.AJNE)
1240 p.To.Type = obj.TYPE_BRANCH
1241 branches = append(branches, branch{p, b.Succs[1]})
1242 } else if b.Succs[1] == next {
1243 p := Prog(x86.AJEQ)
1244 p.To.Type = obj.TYPE_BRANCH
1245 branches = append(branches, branch{p, b.Succs[0]})
1246 } else {
1247 p := Prog(x86.AJEQ)
1248 p.To.Type = obj.TYPE_BRANCH
1249 branches = append(branches, branch{p, b.Succs[0]})
1250 q := Prog(obj.AJMP)
1251 q.To.Type = obj.TYPE_BRANCH
1252 branches = append(branches, branch{q, b.Succs[1]})
1253 }
Keith Randall0dca7352015-06-06 16:03:33 -07001254 case ssa.BlockAMD64NE:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001255 if b.Succs[0] == next {
1256 p := Prog(x86.AJEQ)
1257 p.To.Type = obj.TYPE_BRANCH
1258 branches = append(branches, branch{p, b.Succs[1]})
1259 } else if b.Succs[1] == next {
1260 p := Prog(x86.AJNE)
1261 p.To.Type = obj.TYPE_BRANCH
1262 branches = append(branches, branch{p, b.Succs[0]})
1263 } else {
1264 p := Prog(x86.AJNE)
1265 p.To.Type = obj.TYPE_BRANCH
1266 branches = append(branches, branch{p, b.Succs[0]})
1267 q := Prog(obj.AJMP)
1268 q.To.Type = obj.TYPE_BRANCH
1269 branches = append(branches, branch{q, b.Succs[1]})
1270 }
Keith Randall0dca7352015-06-06 16:03:33 -07001271 case ssa.BlockAMD64LT:
Keith Randall083a6462015-05-12 11:06:44 -07001272 if b.Succs[0] == next {
1273 p := Prog(x86.AJGE)
1274 p.To.Type = obj.TYPE_BRANCH
1275 branches = append(branches, branch{p, b.Succs[1]})
1276 } else if b.Succs[1] == next {
1277 p := Prog(x86.AJLT)
1278 p.To.Type = obj.TYPE_BRANCH
1279 branches = append(branches, branch{p, b.Succs[0]})
1280 } else {
1281 p := Prog(x86.AJLT)
1282 p.To.Type = obj.TYPE_BRANCH
1283 branches = append(branches, branch{p, b.Succs[0]})
1284 q := Prog(obj.AJMP)
1285 q.To.Type = obj.TYPE_BRANCH
1286 branches = append(branches, branch{q, b.Succs[1]})
1287 }
Keith Randall0dca7352015-06-06 16:03:33 -07001288 case ssa.BlockAMD64ULT:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001289 if b.Succs[0] == next {
1290 p := Prog(x86.AJCC)
1291 p.To.Type = obj.TYPE_BRANCH
1292 branches = append(branches, branch{p, b.Succs[1]})
1293 } else if b.Succs[1] == next {
1294 p := Prog(x86.AJCS)
1295 p.To.Type = obj.TYPE_BRANCH
1296 branches = append(branches, branch{p, b.Succs[0]})
1297 } else {
1298 p := Prog(x86.AJCS)
1299 p.To.Type = obj.TYPE_BRANCH
1300 branches = append(branches, branch{p, b.Succs[0]})
1301 q := Prog(obj.AJMP)
1302 q.To.Type = obj.TYPE_BRANCH
1303 branches = append(branches, branch{q, b.Succs[1]})
1304 }
Keith Randall0dca7352015-06-06 16:03:33 -07001305 case ssa.BlockAMD64UGT:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001306 if b.Succs[0] == next {
1307 p := Prog(x86.AJLS)
1308 p.To.Type = obj.TYPE_BRANCH
1309 branches = append(branches, branch{p, b.Succs[1]})
1310 } else if b.Succs[1] == next {
1311 p := Prog(x86.AJHI)
1312 p.To.Type = obj.TYPE_BRANCH
1313 branches = append(branches, branch{p, b.Succs[0]})
1314 } else {
1315 p := Prog(x86.AJHI)
1316 p.To.Type = obj.TYPE_BRANCH
1317 branches = append(branches, branch{p, b.Succs[0]})
1318 q := Prog(obj.AJMP)
1319 q.To.Type = obj.TYPE_BRANCH
1320 branches = append(branches, branch{q, b.Succs[1]})
1321 }
1322
Keith Randall083a6462015-05-12 11:06:44 -07001323 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001324 b.Unimplementedf("branch %s not implemented", b.LongString())
Keith Randall083a6462015-05-12 11:06:44 -07001325 }
1326 return branches
1327}
1328
Keith Randall8c46aa52015-06-19 21:02:28 -07001329// addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
1330func addAux(a *obj.Addr, v *ssa.Value) {
1331 if a.Type != obj.TYPE_MEM {
1332 v.Fatalf("bad addAux addr %s", a)
1333 }
1334 // add integer offset
1335 a.Offset += v.AuxInt
1336
1337 // If no additional symbol offset, we're done.
1338 if v.Aux == nil {
1339 return
1340 }
1341 // Add symbol's offset from its base register.
1342 switch sym := v.Aux.(type) {
1343 case *ssa.ExternSymbol:
1344 a.Name = obj.NAME_EXTERN
1345 a.Sym = Linksym(sym.Sym.(*Sym))
1346 case *ssa.ArgSymbol:
1347 a.Offset += v.Block.Func.FrameSize + sym.Offset
1348 case *ssa.AutoSymbol:
1349 if sym.Offset == -1 {
1350 v.Fatalf("auto symbol %s offset not calculated", sym.Sym)
1351 }
1352 a.Offset += sym.Offset
1353 default:
1354 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
1355 }
1356}
1357
Keith Randall083a6462015-05-12 11:06:44 -07001358// ssaRegToReg maps ssa register numbers to obj register numbers.
1359var ssaRegToReg = [...]int16{
1360 x86.REG_AX,
1361 x86.REG_CX,
1362 x86.REG_DX,
1363 x86.REG_BX,
1364 x86.REG_SP,
1365 x86.REG_BP,
1366 x86.REG_SI,
1367 x86.REG_DI,
1368 x86.REG_R8,
1369 x86.REG_R9,
1370 x86.REG_R10,
1371 x86.REG_R11,
1372 x86.REG_R12,
1373 x86.REG_R13,
1374 x86.REG_R14,
1375 x86.REG_R15,
Keith Randall8c46aa52015-06-19 21:02:28 -07001376 x86.REG_X0,
1377 x86.REG_X1,
1378 x86.REG_X2,
1379 x86.REG_X3,
1380 x86.REG_X4,
1381 x86.REG_X5,
1382 x86.REG_X6,
1383 x86.REG_X7,
1384 x86.REG_X8,
1385 x86.REG_X9,
1386 x86.REG_X10,
1387 x86.REG_X11,
1388 x86.REG_X12,
1389 x86.REG_X13,
1390 x86.REG_X14,
1391 x86.REG_X15,
1392 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 -07001393 // TODO: arch-dependent
1394}
1395
1396// regnum returns the register (in cmd/internal/obj numbering) to
1397// which v has been allocated. Panics if v is not assigned to a
1398// register.
1399func regnum(v *ssa.Value) int16 {
1400 return ssaRegToReg[v.Block.Func.RegAlloc[v.ID].(*ssa.Register).Num]
1401}
1402
1403// localOffset returns the offset below the frame pointer where
1404// a stack-allocated local has been allocated. Panics if v
1405// is not assigned to a local slot.
1406func localOffset(v *ssa.Value) int64 {
1407 return v.Block.Func.RegAlloc[v.ID].(*ssa.LocalSlot).Idx
1408}
Keith Randallf7f604e2015-05-27 14:52:22 -07001409
1410// ssaExport exports a bunch of compiler services for the ssa backend.
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001411type ssaExport struct {
1412 log bool
1413 unimplemented bool
1414}
Keith Randallf7f604e2015-05-27 14:52:22 -07001415
1416// StringSym returns a symbol (a *Sym wrapped in an interface) which
1417// is a global string constant containing s.
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001418func (*ssaExport) StringSym(s string) interface{} {
Keith Randall8c46aa52015-06-19 21:02:28 -07001419 // TODO: is idealstring correct? It might not matter...
Keith Randallc9372612015-06-30 21:16:51 -07001420 hdr, _ := stringsym(s)
1421 return &ssa.ExternSymbol{Typ: idealstring, Sym: hdr}
Keith Randallf7f604e2015-05-27 14:52:22 -07001422}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001423
1424// Log logs a message from the compiler.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001425func (e *ssaExport) Logf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001426 // If e was marked as unimplemented, anything could happen. Ignore.
1427 if e.log && !e.unimplemented {
1428 fmt.Printf(msg, args...)
1429 }
1430}
1431
1432// Fatal reports a compiler error and exits.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001433func (e *ssaExport) Fatalf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001434 // If e was marked as unimplemented, anything could happen. Ignore.
1435 if !e.unimplemented {
1436 Fatal(msg, args...)
1437 }
1438}
1439
1440// Unimplemented reports that the function cannot be compiled.
1441// It will be removed once SSA work is complete.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001442func (e *ssaExport) Unimplementedf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001443 const alwaysLog = false // enable to calculate top unimplemented features
1444 if !e.unimplemented && (e.log || alwaysLog) {
1445 // first implementation failure, print explanation
1446 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
1447 }
1448 e.unimplemented = true
1449}