blob: 9ad28900032a898c209ae2a609556755e3a710f5 [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"
Keith Randalld2fd43a2015-04-15 15:51:25 -07009
Keith Randall067e8df2015-05-28 13:49:20 -070010 "cmd/compile/internal/ssa"
Keith Randall083a6462015-05-12 11:06:44 -070011 "cmd/internal/obj"
Keith Randall8c46aa52015-06-19 21:02:28 -070012 "cmd/internal/obj/x86"
Keith Randalld2fd43a2015-04-15 15:51:25 -070013)
14
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070015// buildssa builds an SSA function
16// and reports whether it should be used.
17// Once the SSA implementation is complete,
18// it will never return nil, and the bool can be removed.
19func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
20 name := fn.Func.Nname.Sym.Name
21 usessa = len(name) > 4 && name[len(name)-4:] == "_ssa"
22
23 if usessa {
24 dumplist("buildssa-enter", fn.Func.Enter)
25 dumplist("buildssa-body", fn.Nbody)
26 }
Keith Randalld2fd43a2015-04-15 15:51:25 -070027
Keith Randallcfc2aa52015-05-18 16:44:20 -070028 var s state
Michael Matloob81ccf502015-05-30 01:03:06 -040029 s.pushLine(fn.Lineno)
30 defer s.popLine()
31
Keith Randalld2fd43a2015-04-15 15:51:25 -070032 // TODO(khr): build config just once at the start of the compiler binary
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070033
34 var e ssaExport
35 e.log = usessa
36 s.config = ssa.NewConfig(Thearch.Thestring, &e)
Keith Randalld2fd43a2015-04-15 15:51:25 -070037 s.f = s.config.NewFunc()
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -070038 s.f.Name = name
39
40 // If SSA support for the function is incomplete,
41 // assume that any panics are due to violated
42 // invariants. Swallow them silently.
43 defer func() {
44 if err := recover(); err != nil {
45 if !e.unimplemented {
46 panic(err)
47 }
48 }
49 }()
Keith Randalld2fd43a2015-04-15 15:51:25 -070050
51 // We construct SSA using an algorithm similar to
52 // Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau
53 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
54 // TODO: check this comment
55
56 // Allocate starting block
57 s.f.Entry = s.f.NewBlock(ssa.BlockPlain)
58
59 // Allocate exit block
60 s.exit = s.f.NewBlock(ssa.BlockExit)
61
Keith Randallcfc2aa52015-05-18 16:44:20 -070062 // Allocate starting values
Keith Randall8c46aa52015-06-19 21:02:28 -070063 s.vars = map[*Node]*ssa.Value{}
Keith Randalld2fd43a2015-04-15 15:51:25 -070064 s.labels = map[string]*ssa.Block{}
Keith Randall8c46aa52015-06-19 21:02:28 -070065 s.startmem = s.entryNewValue0(ssa.OpArg, ssa.TypeMem)
66 s.sp = s.entryNewValue0(ssa.OpSP, s.config.Uintptr) // TODO: use generic pointer type (unsafe.Pointer?) instead
67 s.sb = s.entryNewValue0(ssa.OpSB, s.config.Uintptr)
68
69 // Generate addresses of local declarations
70 s.decladdrs = map[*Node]*ssa.Value{}
71 for d := fn.Func.Dcl; d != nil; d = d.Next {
72 n := d.N
73 switch n.Class {
74 case PPARAM, PPARAMOUT:
75 aux := &ssa.ArgSymbol{Typ: n.Type, Offset: n.Xoffset, Sym: n.Sym}
76 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
77 case PAUTO:
78 aux := &ssa.AutoSymbol{Typ: n.Type, Offset: -1, Sym: n.Sym} // offset TBD by SSA pass
79 s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp)
Daniel Morsingbe2a3e22015-07-01 20:37:25 +010080 default:
81 str := ""
82 if n.Class&PHEAP != 0 {
83 str = ",heap"
84 }
85 s.Unimplementedf("local variable %v with class %s%s unimplemented", n, classnames[n.Class&^PHEAP], str)
Keith Randall8c46aa52015-06-19 21:02:28 -070086 }
87 }
88 // nodfp is a special argument which is the function's FP.
89 aux := &ssa.ArgSymbol{Typ: s.config.Uintptr, Offset: 0, Sym: nodfp.Sym}
90 s.decladdrs[nodfp] = s.entryNewValue1A(ssa.OpAddr, s.config.Uintptr, aux, s.sp)
Keith Randalld2fd43a2015-04-15 15:51:25 -070091
92 // Convert the AST-based IR to the SSA-based IR
93 s.startBlock(s.f.Entry)
Keith Randallf7f604e2015-05-27 14:52:22 -070094 s.stmtList(fn.Func.Enter)
Keith Randalld2fd43a2015-04-15 15:51:25 -070095 s.stmtList(fn.Nbody)
96
Keith Randallcfc2aa52015-05-18 16:44:20 -070097 // fallthrough to exit
98 if b := s.endBlock(); b != nil {
99 addEdge(b, s.exit)
100 }
101
Keith Randalld2fd43a2015-04-15 15:51:25 -0700102 // Finish up exit block
103 s.startBlock(s.exit)
104 s.exit.Control = s.mem()
105 s.endBlock()
106
107 // Link up variable uses to variable definitions
108 s.linkForwardReferences()
109
Keith Randall083a6462015-05-12 11:06:44 -0700110 // Main call to ssa package to compile function
Keith Randalld2fd43a2015-04-15 15:51:25 -0700111 ssa.Compile(s.f)
112
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700113 // Calculate stats about what percentage of functions SSA handles.
114 if false {
115 fmt.Printf("SSA implemented: %t\n", !e.unimplemented)
116 }
117
118 if e.unimplemented {
119 return nil, false
120 }
121 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 -0700122}
123
Keith Randallcfc2aa52015-05-18 16:44:20 -0700124type state struct {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700125 // configuration (arch) information
126 config *ssa.Config
127
128 // function we're building
129 f *ssa.Func
130
131 // exit block that "return" jumps to (and panics jump to)
132 exit *ssa.Block
133
134 // the target block for each label in f
135 labels map[string]*ssa.Block
136
137 // current location where we're interpreting the AST
138 curBlock *ssa.Block
139
Keith Randall8c46aa52015-06-19 21:02:28 -0700140 // variable assignments in the current block (map from variable symbol to ssa value)
141 // *Node is the unique identifier (an ONAME Node) for the variable.
142 vars map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700143
144 // all defined variables at the end of each block. Indexed by block ID.
Keith Randall8c46aa52015-06-19 21:02:28 -0700145 defvars []map[*Node]*ssa.Value
Keith Randalld2fd43a2015-04-15 15:51:25 -0700146
Keith Randall8c46aa52015-06-19 21:02:28 -0700147 // addresses of PPARAM, PPARAMOUT, and PAUTO variables.
148 decladdrs map[*Node]*ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700149
150 // starting values. Memory, frame pointer, and stack pointer
151 startmem *ssa.Value
Keith Randallcfc2aa52015-05-18 16:44:20 -0700152 sp *ssa.Value
Keith Randall8c46aa52015-06-19 21:02:28 -0700153 sb *ssa.Value
Michael Matloob81ccf502015-05-30 01:03:06 -0400154
155 // line number stack. The current line number is top of stack
156 line []int32
Keith Randalld2fd43a2015-04-15 15:51:25 -0700157}
158
Josh Bleecher Snyder1edf4892015-07-03 20:29:11 -0700159func (s *state) Logf(msg string, args ...interface{}) { s.config.Logf(msg, args...) }
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700160func (s *state) Fatalf(msg string, args ...interface{}) { s.config.Fatalf(msg, args...) }
161func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimplementedf(msg, args...) }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700162
Keith Randall8c46aa52015-06-19 21:02:28 -0700163// dummy node for the memory variable
164var memvar = Node{Op: ONAME, Sym: &Sym{Name: "mem"}}
165
Keith Randalld2fd43a2015-04-15 15:51:25 -0700166// startBlock sets the current block we're generating code in to b.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700167func (s *state) startBlock(b *ssa.Block) {
168 if s.curBlock != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700169 s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700170 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700171 s.curBlock = b
Keith Randall8c46aa52015-06-19 21:02:28 -0700172 s.vars = map[*Node]*ssa.Value{}
Keith Randalld2fd43a2015-04-15 15:51:25 -0700173}
174
175// endBlock marks the end of generating code for the current block.
176// Returns the (former) current block. Returns nil if there is no current
177// block, i.e. if no code flows to the current execution point.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700178func (s *state) endBlock() *ssa.Block {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700179 b := s.curBlock
180 if b == nil {
181 return nil
182 }
183 for len(s.defvars) <= int(b.ID) {
184 s.defvars = append(s.defvars, nil)
185 }
186 s.defvars[b.ID] = s.vars
187 s.curBlock = nil
188 s.vars = nil
Michael Matloob81ccf502015-05-30 01:03:06 -0400189 b.Line = s.peekLine()
Keith Randalld2fd43a2015-04-15 15:51:25 -0700190 return b
191}
192
Michael Matloob81ccf502015-05-30 01:03:06 -0400193// pushLine pushes a line number on the line number stack.
194func (s *state) pushLine(line int32) {
195 s.line = append(s.line, line)
196}
197
198// popLine pops the top of the line number stack.
199func (s *state) popLine() {
200 s.line = s.line[:len(s.line)-1]
201}
202
203// peekLine peek the top of the line number stack.
204func (s *state) peekLine() int32 {
205 return s.line[len(s.line)-1]
206}
207
Keith Randall8f22b522015-06-11 21:29:25 -0700208// newValue0 adds a new value with no arguments to the current block.
209func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value {
210 return s.curBlock.NewValue0(s.peekLine(), op, t)
211}
212
213// newValue0A adds a new value with no arguments and an aux value to the current block.
214func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
215 return s.curBlock.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400216}
217
218// newValue1 adds a new value with one argument to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700219func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
220 return s.curBlock.NewValue1(s.peekLine(), op, t, arg)
221}
222
223// newValue1A adds a new value with one argument and an aux value to the current block.
224func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
225 return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400226}
227
228// newValue2 adds a new value with two arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700229func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
230 return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400231}
232
Daniel Morsing66b47812015-06-27 15:45:20 +0100233// newValue2I adds a new value with two arguments and an auxint value to the current block.
234func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value {
235 return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1)
236}
237
Michael Matloob81ccf502015-05-30 01:03:06 -0400238// newValue3 adds a new value with three arguments to the current block.
Keith Randall8f22b522015-06-11 21:29:25 -0700239func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value {
240 return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2)
Michael Matloob81ccf502015-05-30 01:03:06 -0400241}
242
243// entryNewValue adds a new value with no arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700244func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value {
245 return s.f.Entry.NewValue0(s.peekLine(), op, t)
246}
247
248// entryNewValue adds a new value with no arguments and an aux value to the entry block.
249func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value {
250 return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux)
Michael Matloob81ccf502015-05-30 01:03:06 -0400251}
252
253// entryNewValue1 adds a new value with one argument to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700254func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value {
255 return s.f.Entry.NewValue1(s.peekLine(), op, t, arg)
256}
257
258// entryNewValue1 adds a new value with one argument and an auxint value to the entry block.
259func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value {
260 return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg)
Michael Matloob81ccf502015-05-30 01:03:06 -0400261}
262
Keith Randall8c46aa52015-06-19 21:02:28 -0700263// entryNewValue1A adds a new value with one argument and an aux value to the entry block.
264func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value {
265 return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg)
266}
267
Michael Matloob81ccf502015-05-30 01:03:06 -0400268// entryNewValue2 adds a new value with two arguments to the entry block.
Keith Randall8f22b522015-06-11 21:29:25 -0700269func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
270 return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
Michael Matloob81ccf502015-05-30 01:03:06 -0400271}
272
273// constInt adds a new const int value to the entry block.
274func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
275 return s.f.ConstInt(s.peekLine(), t, c)
276}
277
Keith Randalld2fd43a2015-04-15 15:51:25 -0700278// ssaStmtList converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700279func (s *state) stmtList(l *NodeList) {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700280 for ; l != nil; l = l.Next {
281 s.stmt(l.N)
282 }
283}
284
285// ssaStmt converts the statement n to SSA and adds it to s.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700286func (s *state) stmt(n *Node) {
Michael Matloob81ccf502015-05-30 01:03:06 -0400287 s.pushLine(n.Lineno)
288 defer s.popLine()
289
Keith Randalld2fd43a2015-04-15 15:51:25 -0700290 s.stmtList(n.Ninit)
291 switch n.Op {
292
293 case OBLOCK:
294 s.stmtList(n.List)
295
296 case ODCL:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100297 if n.Left.Class&PHEAP == 0 {
298 return
299 }
300 if compiling_runtime != 0 {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700301 Fatal("%v escapes to heap, not allowed in runtime.", n)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100302 }
303
304 // TODO: the old pass hides the details of PHEAP
305 // variables behind ONAME nodes. Figure out if it's better
306 // to rewrite the tree and make the heapaddr construct explicit
307 // or to keep this detail hidden behind the scenes.
308 palloc := prealloc[n.Left]
309 if palloc == nil {
310 palloc = callnew(n.Left.Type)
311 prealloc[n.Left] = palloc
312 }
313 s.assign(OAS, n.Left.Name.Heapaddr, palloc)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700314
315 case OLABEL, OGOTO:
316 // get block at label, or make one
317 t := s.labels[n.Left.Sym.Name]
318 if t == nil {
319 t = s.f.NewBlock(ssa.BlockPlain)
320 s.labels[n.Left.Sym.Name] = t
321 }
322 // go to that label (we pretend "label:" is preceded by "goto label")
Keith Randall0ad9c8c2015-06-12 16:24:33 -0700323 if b := s.endBlock(); b != nil {
324 addEdge(b, t)
325 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700326
327 if n.Op == OLABEL {
328 // next we work on the label's target block
329 s.startBlock(t)
330 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700331 if n.Op == OGOTO && s.curBlock == nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700332 s.Unimplementedf("goto at start of function; see test/goto.go")
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700333 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700334
Keith Randall290d8fc2015-06-10 15:03:06 -0700335 case OAS, OASWB:
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100336 s.assign(n.Op, n.Left, n.Right)
337
Keith Randalld2fd43a2015-04-15 15:51:25 -0700338 case OIF:
Keith Randalle707fbe2015-06-11 10:20:39 -0700339 cond := s.expr(n.Left)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700340 b := s.endBlock()
341 b.Kind = ssa.BlockIf
342 b.Control = cond
343 // TODO(khr): likely direction
344
345 bThen := s.f.NewBlock(ssa.BlockPlain)
346 bEnd := s.f.NewBlock(ssa.BlockPlain)
347 var bElse *ssa.Block
348
Keith Randalle707fbe2015-06-11 10:20:39 -0700349 if n.Rlist == nil {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700350 addEdge(b, bThen)
351 addEdge(b, bEnd)
352 } else {
353 bElse = s.f.NewBlock(ssa.BlockPlain)
354 addEdge(b, bThen)
355 addEdge(b, bElse)
356 }
357
358 s.startBlock(bThen)
359 s.stmtList(n.Nbody)
360 b = s.endBlock()
361 if b != nil {
362 addEdge(b, bEnd)
363 }
364
Keith Randalle707fbe2015-06-11 10:20:39 -0700365 if n.Rlist != nil {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700366 s.startBlock(bElse)
Keith Randalle707fbe2015-06-11 10:20:39 -0700367 s.stmtList(n.Rlist)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700368 b = s.endBlock()
369 if b != nil {
370 addEdge(b, bEnd)
371 }
372 }
373 s.startBlock(bEnd)
374
375 case ORETURN:
376 s.stmtList(n.List)
377 b := s.endBlock()
378 addEdge(b, s.exit)
379
380 case OFOR:
381 bCond := s.f.NewBlock(ssa.BlockPlain)
382 bBody := s.f.NewBlock(ssa.BlockPlain)
383 bEnd := s.f.NewBlock(ssa.BlockPlain)
384
385 // first, jump to condition test
386 b := s.endBlock()
387 addEdge(b, bCond)
388
389 // generate code to test condition
Keith Randalle707fbe2015-06-11 10:20:39 -0700390 // TODO(khr): Left == nil exception
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700391 if n.Left == nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700392 s.Unimplementedf("cond n.Left == nil: %v", n)
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700393 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700394 s.startBlock(bCond)
Keith Randall7b858012015-06-25 20:01:45 -0700395 s.stmtList(n.Left.Ninit)
Keith Randalle707fbe2015-06-11 10:20:39 -0700396 cond := s.expr(n.Left)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700397 b = s.endBlock()
398 b.Kind = ssa.BlockIf
399 b.Control = cond
400 // TODO(khr): likely direction
401 addEdge(b, bBody)
402 addEdge(b, bEnd)
403
404 // generate body
405 s.startBlock(bBody)
406 s.stmtList(n.Nbody)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700407 if n.Right != nil {
408 s.stmt(n.Right)
409 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700410 b = s.endBlock()
411 addEdge(b, bCond)
412
413 s.startBlock(bEnd)
414
Michael Matloob2aabacd2015-06-16 17:58:03 -0700415 case OCALLFUNC:
416 s.expr(n)
417
Keith Randalld2fd43a2015-04-15 15:51:25 -0700418 case OVARKILL:
419 // TODO(khr): ??? anything to do here? Only for addrtaken variables?
420 // Maybe just link it in the store chain?
421 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700422 s.Unimplementedf("unhandled stmt %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -0700423 }
424}
425
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700426var binOpToSSA = [...]ssa.Op{
427 // Comparisons
428 OEQ: ssa.OpEq,
429 ONE: ssa.OpNeq,
430 OLT: ssa.OpLess,
431 OLE: ssa.OpLeq,
432 OGT: ssa.OpGreater,
433 OGE: ssa.OpGeq,
434 // Arithmetic
435 OADD: ssa.OpAdd,
436 OSUB: ssa.OpSub,
437 OLSH: ssa.OpLsh,
438 ORSH: ssa.OpRsh,
439}
440
Keith Randalld2fd43a2015-04-15 15:51:25 -0700441// expr converts the expression n to ssa, adds it to s and returns the ssa result.
Keith Randallcfc2aa52015-05-18 16:44:20 -0700442func (s *state) expr(n *Node) *ssa.Value {
Michael Matloob81ccf502015-05-30 01:03:06 -0400443 s.pushLine(n.Lineno)
444 defer s.popLine()
445
Keith Randalld2fd43a2015-04-15 15:51:25 -0700446 switch n.Op {
447 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -0700448 if n.Class == PFUNC {
449 // "value" of a function is the address of the function's closure
Keith Randall8c46aa52015-06-19 21:02:28 -0700450 sym := funcsym(n.Sym)
451 aux := &ssa.ExternSymbol{n.Type, sym}
452 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
Keith Randall23df95b2015-05-12 15:16:52 -0700453 }
Keith Randall290d8fc2015-06-10 15:03:06 -0700454 if canSSA(n) {
Keith Randall8c46aa52015-06-19 21:02:28 -0700455 return s.variable(n, n.Type)
Keith Randall290d8fc2015-06-10 15:03:06 -0700456 }
457 addr := s.addr(n)
Keith Randall8f22b522015-06-11 21:29:25 -0700458 return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -0700459 case OLITERAL:
Keith Randalle707fbe2015-06-11 10:20:39 -0700460 switch n.Val().Ctype() {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700461 case CTINT:
Keith Randalle707fbe2015-06-11 10:20:39 -0700462 return s.constInt(n.Type, Mpgetfix(n.Val().U.(*Mpint)))
Keith Randallf7f604e2015-05-27 14:52:22 -0700463 case CTSTR:
Keith Randall8f22b522015-06-11 21:29:25 -0700464 return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700465 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700466 s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
Keith Randalld2fd43a2015-04-15 15:51:25 -0700467 return nil
468 }
Keith Randall0ad9c8c2015-06-12 16:24:33 -0700469 case OCONVNOP:
470 x := s.expr(n.Left)
Michael Matloobea5cd682015-06-14 10:27:50 -0700471 return s.newValue1(ssa.OpConvNop, n.Type, x)
Michael Matloob73054f52015-06-14 11:38:46 -0700472 case OCONV:
473 x := s.expr(n.Left)
474 return s.newValue1(ssa.OpConvert, n.Type, x)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700475
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700476 // binary ops
477 case OLT, OEQ, ONE, OLE, OGE, OGT:
Keith Randalld2fd43a2015-04-15 15:51:25 -0700478 a := s.expr(n.Left)
479 b := s.expr(n.Right)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700480 return s.newValue2(binOpToSSA[n.Op], ssa.TypeBool, a, b)
481 case OADD, OSUB, OLSH, ORSH:
Keith Randalld2fd43a2015-04-15 15:51:25 -0700482 a := s.expr(n.Left)
483 b := s.expr(n.Right)
Josh Bleecher Snyder46815b92015-06-24 17:48:22 -0700484 return s.newValue2(binOpToSSA[n.Op], a.Type, a, b)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700485
Keith Randallcfc2aa52015-05-18 16:44:20 -0700486 case OADDR:
487 return s.addr(n.Left)
488
Keith Randalld2fd43a2015-04-15 15:51:25 -0700489 case OIND:
490 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700491 s.nilCheck(p)
Keith Randall8f22b522015-06-11 21:29:25 -0700492 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -0700493
Keith Randalld2fd43a2015-04-15 15:51:25 -0700494 case ODOTPTR:
495 p := s.expr(n.Left)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700496 s.nilCheck(p)
Keith Randall8f22b522015-06-11 21:29:25 -0700497 p = s.newValue2(ssa.OpAdd, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset))
498 return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
Keith Randalld2fd43a2015-04-15 15:51:25 -0700499
500 case OINDEX:
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700501 if n.Left.Type.Bound >= 0 { // array or string
Keith Randallcfc2aa52015-05-18 16:44:20 -0700502 a := s.expr(n.Left)
503 i := s.expr(n.Right)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700504 var elemtype *Type
505 var len *ssa.Value
506 if n.Left.Type.IsString() {
Keith Randall8f22b522015-06-11 21:29:25 -0700507 len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, a)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700508 elemtype = Types[TUINT8]
509 } else {
Michael Matloob81ccf502015-05-30 01:03:06 -0400510 len = s.constInt(s.config.Uintptr, n.Left.Type.Bound)
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700511 elemtype = n.Left.Type.Type
512 }
513 s.boundsCheck(i, len)
Keith Randall8f22b522015-06-11 21:29:25 -0700514 return s.newValue2(ssa.OpArrayIndex, elemtype, a, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700515 } else { // slice
516 p := s.addr(n)
Keith Randall8f22b522015-06-11 21:29:25 -0700517 return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem())
Keith Randallcfc2aa52015-05-18 16:44:20 -0700518 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700519
520 case OCALLFUNC:
Keith Randall290d8fc2015-06-10 15:03:06 -0700521 static := n.Left.Op == ONAME && n.Left.Class == PFUNC
522
523 // evaluate closure
524 var closure *ssa.Value
525 if !static {
526 closure = s.expr(n.Left)
527 }
528
Keith Randalld2fd43a2015-04-15 15:51:25 -0700529 // run all argument assignments
Keith Randalld2fd43a2015-04-15 15:51:25 -0700530 s.stmtList(n.List)
531
Keith Randalld2fd43a2015-04-15 15:51:25 -0700532 bNext := s.f.NewBlock(ssa.BlockPlain)
Keith Randall290d8fc2015-06-10 15:03:06 -0700533 var call *ssa.Value
534 if static {
Keith Randall8f22b522015-06-11 21:29:25 -0700535 call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem())
Keith Randall290d8fc2015-06-10 15:03:06 -0700536 } else {
Keith Randall8f22b522015-06-11 21:29:25 -0700537 entry := s.newValue2(ssa.OpLoad, s.config.Uintptr, closure, s.mem())
538 call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, entry, closure, s.mem())
Keith Randall290d8fc2015-06-10 15:03:06 -0700539 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700540 b := s.endBlock()
541 b.Kind = ssa.BlockCall
542 b.Control = call
543 addEdge(b, bNext)
544 addEdge(b, s.exit)
545
546 // read result from stack at the start of the fallthrough block
547 s.startBlock(bNext)
548 var titer Iter
549 fp := Structfirst(&titer, Getoutarg(n.Left.Type))
Michael Matloob2aabacd2015-06-16 17:58:03 -0700550 if fp == nil {
551 // CALLFUNC has no return value. Continue with the next statement.
552 return nil
553 }
Keith Randall8f22b522015-06-11 21:29:25 -0700554 a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp)
555 return s.newValue2(ssa.OpLoad, fp.Type, a, call)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700556 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700557 s.Unimplementedf("unhandled expr %s", opnames[n.Op])
Keith Randalld2fd43a2015-04-15 15:51:25 -0700558 return nil
559 }
560}
561
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100562func (s *state) assign(op uint8, left *Node, right *Node) {
563 // TODO: do write barrier
564 // if op == OASWB
565 var val *ssa.Value
566 if right == nil {
567 // right == nil means use the zero value of the assigned type.
568 t := left.Type
Daniel Morsing66b47812015-06-27 15:45:20 +0100569 if !canSSA(left) {
570 // if we can't ssa this memory, treat it as just zeroing out the backing memory
571 addr := s.addr(left)
572 s.vars[&memvar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem())
573 return
574 }
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100575 switch {
576 case t.IsString():
Josh Bleecher Snydera5c3b662015-06-16 16:16:23 -0700577 val = s.entryNewValue0A(ssa.OpConst, left.Type, "")
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100578 case t.IsInteger():
579 val = s.entryNewValue0(ssa.OpConst, left.Type)
580 case t.IsBoolean():
581 val = s.entryNewValue0A(ssa.OpConst, left.Type, false) // TODO: store bools as 0/1 in AuxInt?
582 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700583 s.Unimplementedf("zero for type %v not implemented", t)
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100584 }
585 } else {
586 val = s.expr(right)
587 }
588 if left.Op == ONAME && canSSA(left) {
589 // Update variable assignment.
Keith Randall8c46aa52015-06-19 21:02:28 -0700590 s.vars[left] = val
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100591 return
592 }
593 // not ssa-able. Treat as a store.
594 addr := s.addr(left)
Keith Randall8c46aa52015-06-19 21:02:28 -0700595 s.vars[&memvar] = s.newValue3(ssa.OpStore, ssa.TypeMem, addr, val, s.mem())
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100596}
597
Josh Bleecher Snydere00d6092015-06-02 09:16:22 -0700598// 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 -0700599func (s *state) addr(n *Node) *ssa.Value {
600 switch n.Op {
601 case ONAME:
Keith Randall290d8fc2015-06-10 15:03:06 -0700602 switch n.Class {
603 case PEXTERN:
Keith Randallcfc2aa52015-05-18 16:44:20 -0700604 // global variable
Keith Randall8c46aa52015-06-19 21:02:28 -0700605 aux := &ssa.ExternSymbol{n.Type, n.Sym}
606 return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb)
607 case PPARAM, PPARAMOUT, PAUTO:
608 // parameter/result slot or local variable
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -0700609 v := s.decladdrs[n]
610 if v == nil {
Josh Bleecher Snyder0a133cdd2015-07-03 20:28:56 -0700611 if flag_race != 0 && n.String() == ".fp" {
612 s.Unimplementedf("race detector mishandles nodfp")
613 }
Josh Bleecher Snyder596ddf42015-06-29 11:56:28 -0700614 s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
615 }
616 return v
Daniel Morsingc31b6dd2015-06-12 14:23:29 +0100617 case PAUTO | PHEAP:
618 return s.expr(n.Name.Heapaddr)
Keith Randall290d8fc2015-06-10 15:03:06 -0700619 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700620 s.Unimplementedf("variable address of %v not implemented", n)
Keith Randall290d8fc2015-06-10 15:03:06 -0700621 return nil
Keith Randallcfc2aa52015-05-18 16:44:20 -0700622 }
Keith Randallcfc2aa52015-05-18 16:44:20 -0700623 case OINDREG:
624 // indirect off a register (TODO: always SP?)
625 // used for storing/loading arguments/returns to/from callees
Keith Randall8f22b522015-06-11 21:29:25 -0700626 return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700627 case OINDEX:
628 if n.Left.Type.Bound >= 0 { // array
629 a := s.addr(n.Left)
630 i := s.expr(n.Right)
Michael Matloob81ccf502015-05-30 01:03:06 -0400631 len := s.constInt(s.config.Uintptr, n.Left.Type.Bound)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700632 s.boundsCheck(i, len)
Keith Randall8f22b522015-06-11 21:29:25 -0700633 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700634 } else { // slice
635 a := s.expr(n.Left)
636 i := s.expr(n.Right)
Keith Randall8f22b522015-06-11 21:29:25 -0700637 len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, a)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700638 s.boundsCheck(i, len)
Keith Randall8f22b522015-06-11 21:29:25 -0700639 p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a)
640 return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700641 }
642 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700643 s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0))
Keith Randallcfc2aa52015-05-18 16:44:20 -0700644 return nil
645 }
646}
647
Keith Randall290d8fc2015-06-10 15:03:06 -0700648// canSSA reports whether n is SSA-able.
649// n must be an ONAME.
650func canSSA(n *Node) bool {
651 if n.Op != ONAME {
Daniel Morsing66b47812015-06-27 15:45:20 +0100652 return false
Keith Randall290d8fc2015-06-10 15:03:06 -0700653 }
654 if n.Addrtaken {
655 return false
656 }
657 if n.Class&PHEAP != 0 {
658 return false
659 }
660 if n.Class == PEXTERN {
661 return false
662 }
663 if n.Class == PPARAMOUT {
664 return false
665 }
Daniel Morsing66b47812015-06-27 15:45:20 +0100666 if Isfat(n.Type) {
667 return false
668 }
Keith Randall290d8fc2015-06-10 15:03:06 -0700669 return true
670 // TODO: try to make more variables SSAable.
671}
672
Keith Randallcfc2aa52015-05-18 16:44:20 -0700673// nilCheck generates nil pointer checking code.
674// Starts a new block on return.
675func (s *state) nilCheck(ptr *ssa.Value) {
Keith Randall8f22b522015-06-11 21:29:25 -0700676 c := s.newValue1(ssa.OpIsNonNil, ssa.TypeBool, ptr)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700677 b := s.endBlock()
678 b.Kind = ssa.BlockIf
679 b.Control = c
680 bNext := s.f.NewBlock(ssa.BlockPlain)
681 addEdge(b, bNext)
682 addEdge(b, s.exit)
683 s.startBlock(bNext)
684 // TODO(khr): Don't go directly to exit. Go to a stub that calls panicmem first.
685 // TODO: implicit nil checks somehow?
686}
687
688// boundsCheck generates bounds checking code. Checks if 0 <= idx < len, branches to exit if not.
689// Starts a new block on return.
690func (s *state) boundsCheck(idx, len *ssa.Value) {
691 // TODO: convert index to full width?
692 // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero.
693
694 // bounds check
Keith Randall8f22b522015-06-11 21:29:25 -0700695 cmp := s.newValue2(ssa.OpIsInBounds, ssa.TypeBool, idx, len)
Keith Randallcfc2aa52015-05-18 16:44:20 -0700696 b := s.endBlock()
697 b.Kind = ssa.BlockIf
698 b.Control = cmp
699 bNext := s.f.NewBlock(ssa.BlockPlain)
700 addEdge(b, bNext)
701 addEdge(b, s.exit)
702 // TODO: don't go directly to s.exit. Go to a stub that calls panicindex first.
703 s.startBlock(bNext)
704}
705
Keith Randalld2fd43a2015-04-15 15:51:25 -0700706// variable returns the value of a variable at the current location.
Keith Randall8c46aa52015-06-19 21:02:28 -0700707func (s *state) variable(name *Node, t ssa.Type) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700708 if s.curBlock == nil {
Josh Bleecher Snyder44be0e92015-06-24 13:29:05 -0700709 // Unimplemented instead of Fatal because fixedbugs/bug303.go
710 // demonstrates a case in which this appears to happen legitimately.
711 // TODO: decide on the correct behavior here.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700712 s.Unimplementedf("nil curblock adding variable %v (%v)", name, t)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700713 }
714 v := s.vars[name]
715 if v == nil {
716 // TODO: get type? Take Sym as arg?
Keith Randall8f22b522015-06-11 21:29:25 -0700717 v = s.newValue0A(ssa.OpFwdRef, t, name)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700718 s.vars[name] = v
719 }
720 return v
721}
722
Keith Randallcfc2aa52015-05-18 16:44:20 -0700723func (s *state) mem() *ssa.Value {
Keith Randall8c46aa52015-06-19 21:02:28 -0700724 return s.variable(&memvar, ssa.TypeMem)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700725}
726
Keith Randallcfc2aa52015-05-18 16:44:20 -0700727func (s *state) linkForwardReferences() {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700728 // Build ssa graph. Each variable on its first use in a basic block
729 // leaves a FwdRef in that block representing the incoming value
730 // of that variable. This function links that ref up with possible definitions,
731 // inserting Phi values as needed. This is essentially the algorithm
732 // described by Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau:
733 // http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
734 for _, b := range s.f.Blocks {
735 for _, v := range b.Values {
736 if v.Op != ssa.OpFwdRef {
737 continue
738 }
Keith Randall8c46aa52015-06-19 21:02:28 -0700739 name := v.Aux.(*Node)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700740 v.Op = ssa.OpCopy
741 v.Aux = nil
742 v.SetArgs1(s.lookupVarIncoming(b, v.Type, name))
743 }
744 }
745}
746
747// lookupVarIncoming finds the variable's value at the start of block b.
Keith Randall8c46aa52015-06-19 21:02:28 -0700748func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700749 // TODO(khr): have lookupVarIncoming overwrite the fwdRef or copy it
750 // will be used in, instead of having the result used in a copy value.
751 if b == s.f.Entry {
Keith Randall8c46aa52015-06-19 21:02:28 -0700752 if name == &memvar {
Keith Randallcfc2aa52015-05-18 16:44:20 -0700753 return s.startmem
Keith Randalld2fd43a2015-04-15 15:51:25 -0700754 }
755 // variable is live at the entry block. Load it.
Keith Randall8c46aa52015-06-19 21:02:28 -0700756 addr := s.decladdrs[name]
757 if addr == nil {
758 // TODO: closure args reach here.
759 s.Unimplementedf("variable %s not found", name)
760 }
761 if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok {
762 s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name)
763 }
Keith Randall8f22b522015-06-11 21:29:25 -0700764 return s.entryNewValue2(ssa.OpLoad, t, addr, s.startmem)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700765 }
766 var vals []*ssa.Value
767 for _, p := range b.Preds {
768 vals = append(vals, s.lookupVarOutgoing(p, t, name))
769 }
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700770 if len(vals) == 0 {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700771 s.Unimplementedf("TODO: Handle fixedbugs/bug076.go")
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700772 return nil
773 }
Keith Randalld2fd43a2015-04-15 15:51:25 -0700774 v0 := vals[0]
775 for i := 1; i < len(vals); i++ {
776 if vals[i] != v0 {
777 // need a phi value
Keith Randall8f22b522015-06-11 21:29:25 -0700778 v := b.NewValue0(s.peekLine(), ssa.OpPhi, t)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700779 v.AddArgs(vals...)
780 return v
781 }
782 }
783 return v0
784}
785
786// lookupVarOutgoing finds the variable's value at the end of block b.
Keith Randall8c46aa52015-06-19 21:02:28 -0700787func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value {
Keith Randalld2fd43a2015-04-15 15:51:25 -0700788 m := s.defvars[b.ID]
789 if v, ok := m[name]; ok {
790 return v
791 }
792 // The variable is not defined by b and we haven't
793 // looked it up yet. Generate v, a copy value which
794 // will be the outgoing value of the variable. Then
795 // look up w, the incoming value of the variable.
796 // Make v = copy(w). We need the extra copy to
797 // prevent infinite recursion when looking up the
798 // incoming value of the variable.
Keith Randall8f22b522015-06-11 21:29:25 -0700799 v := b.NewValue0(s.peekLine(), ssa.OpCopy, t)
Keith Randalld2fd43a2015-04-15 15:51:25 -0700800 m[name] = v
801 v.AddArg(s.lookupVarIncoming(b, t, name))
802 return v
803}
804
805// TODO: the above mutually recursive functions can lead to very deep stacks. Fix that.
806
807// addEdge adds an edge from b to c.
808func addEdge(b, c *ssa.Block) {
809 b.Succs = append(b.Succs, c)
810 c.Preds = append(c.Preds, b)
811}
Keith Randall083a6462015-05-12 11:06:44 -0700812
813// an unresolved branch
814type branch struct {
815 p *obj.Prog // branch instruction
816 b *ssa.Block // target
817}
818
819// genssa appends entries to ptxt for each instruction in f.
820// gcargs and gclocals are filled in with pointer maps for the frame.
821func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
822 // TODO: line numbers
Keith Randall083a6462015-05-12 11:06:44 -0700823
Keith Randall247786c2015-05-28 10:47:24 -0700824 if f.FrameSize > 1<<31 {
Keith Randall083a6462015-05-12 11:06:44 -0700825 Yyerror("stack frame too large (>2GB)")
826 return
827 }
Keith Randall083a6462015-05-12 11:06:44 -0700828
829 ptxt.To.Type = obj.TYPE_TEXTSIZE
830 ptxt.To.Val = int32(Rnd(Curfn.Type.Argwid, int64(Widthptr))) // arg size
Keith Randall247786c2015-05-28 10:47:24 -0700831 ptxt.To.Offset = f.FrameSize - 8 // TODO: arch-dependent
Keith Randall083a6462015-05-12 11:06:44 -0700832
833 // Remember where each block starts.
834 bstart := make([]*obj.Prog, f.NumBlocks())
835
836 // Remember all the branch instructions we've seen
837 // and where they would like to go
838 var branches []branch
839
840 // Emit basic blocks
841 for i, b := range f.Blocks {
842 bstart[b.ID] = Pc
843 // Emit values in block
844 for _, v := range b.Values {
Keith Randall247786c2015-05-28 10:47:24 -0700845 genValue(v)
Keith Randall083a6462015-05-12 11:06:44 -0700846 }
847 // Emit control flow instructions for block
848 var next *ssa.Block
849 if i < len(f.Blocks)-1 {
850 next = f.Blocks[i+1]
851 }
852 branches = genBlock(b, next, branches)
853 }
854
855 // Resolve branches
856 for _, br := range branches {
857 br.p.To.Val = bstart[br.b.ID]
858 }
859
860 Pc.As = obj.ARET // overwrite AEND
861
862 // TODO: liveness
863 // TODO: gcargs
864 // TODO: gclocals
865
866 // TODO: dump frame if -f
867
868 // Emit garbage collection symbols. TODO: put something in them
Keith Randallf7f604e2015-05-27 14:52:22 -0700869 //liveness(Curfn, ptxt, gcargs, gclocals)
870 duint32(gcargs, 0, 0)
871 ggloblsym(gcargs, 4, obj.RODATA|obj.DUPOK)
872 duint32(gclocals, 0, 0)
873 ggloblsym(gclocals, 4, obj.RODATA|obj.DUPOK)
Keith Randall083a6462015-05-12 11:06:44 -0700874}
875
Keith Randall247786c2015-05-28 10:47:24 -0700876func genValue(v *ssa.Value) {
Michael Matloob81ccf502015-05-30 01:03:06 -0400877 lineno = v.Line
Keith Randall083a6462015-05-12 11:06:44 -0700878 switch v.Op {
Keith Randall0dca7352015-06-06 16:03:33 -0700879 case ssa.OpAMD64ADDQ:
Keith Randall083a6462015-05-12 11:06:44 -0700880 // TODO: use addq instead of leaq if target is in the right register.
881 p := Prog(x86.ALEAQ)
882 p.From.Type = obj.TYPE_MEM
883 p.From.Reg = regnum(v.Args[0])
884 p.From.Scale = 1
885 p.From.Index = regnum(v.Args[1])
886 p.To.Type = obj.TYPE_REG
887 p.To.Reg = regnum(v)
Michael Matloob73054f52015-06-14 11:38:46 -0700888 case ssa.OpAMD64ADDL:
889 p := Prog(x86.ALEAL)
890 p.From.Type = obj.TYPE_MEM
891 p.From.Reg = regnum(v.Args[0])
892 p.From.Scale = 1
893 p.From.Index = regnum(v.Args[1])
894 p.To.Type = obj.TYPE_REG
895 p.To.Reg = regnum(v)
896 case ssa.OpAMD64ADDW:
897 p := Prog(x86.ALEAW)
898 p.From.Type = obj.TYPE_MEM
899 p.From.Reg = regnum(v.Args[0])
900 p.From.Scale = 1
901 p.From.Index = regnum(v.Args[1])
902 p.To.Type = obj.TYPE_REG
903 p.To.Reg = regnum(v)
904 case ssa.OpAMD64ADDB, ssa.OpAMD64ANDQ:
905 r := regnum(v)
906 x := regnum(v.Args[0])
907 y := regnum(v.Args[1])
908 if x != r && y != r {
909 p := Prog(x86.AMOVQ)
910 p.From.Type = obj.TYPE_REG
911 p.From.Reg = x
912 p.To.Type = obj.TYPE_REG
913 p.To.Reg = r
914 x = r
915 }
916 p := Prog(v.Op.Asm())
917 p.From.Type = obj.TYPE_REG
918 p.To.Type = obj.TYPE_REG
919 p.To.Reg = r
920 if x == r {
921 p.From.Reg = y
922 } else {
923 p.From.Reg = x
924 }
Keith Randall0dca7352015-06-06 16:03:33 -0700925 case ssa.OpAMD64ADDQconst:
Keith Randall083a6462015-05-12 11:06:44 -0700926 // TODO: use addq instead of leaq if target is in the right register.
927 p := Prog(x86.ALEAQ)
928 p.From.Type = obj.TYPE_MEM
929 p.From.Reg = regnum(v.Args[0])
Keith Randall8f22b522015-06-11 21:29:25 -0700930 p.From.Offset = v.AuxInt
Keith Randall083a6462015-05-12 11:06:44 -0700931 p.To.Type = obj.TYPE_REG
932 p.To.Reg = regnum(v)
Keith Randall0dca7352015-06-06 16:03:33 -0700933 case ssa.OpAMD64MULQconst:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700934 v.Unimplementedf("IMULQ doasm")
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700935 return
Keith Randall247786c2015-05-28 10:47:24 -0700936 // TODO: this isn't right. doasm fails on it. I don't think obj
937 // has ever been taught to compile imul $c, r1, r2.
938 p := Prog(x86.AIMULQ)
939 p.From.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -0700940 p.From.Offset = v.AuxInt
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -0700941 p.From3 = new(obj.Addr)
Keith Randall247786c2015-05-28 10:47:24 -0700942 p.From3.Type = obj.TYPE_REG
943 p.From3.Reg = regnum(v.Args[0])
944 p.To.Type = obj.TYPE_REG
945 p.To.Reg = regnum(v)
Keith Randall0dca7352015-06-06 16:03:33 -0700946 case ssa.OpAMD64SUBQconst:
Keith Randall083a6462015-05-12 11:06:44 -0700947 // This code compensates for the fact that the register allocator
948 // doesn't understand 2-address instructions yet. TODO: fix that.
949 x := regnum(v.Args[0])
950 r := regnum(v)
951 if x != r {
952 p := Prog(x86.AMOVQ)
953 p.From.Type = obj.TYPE_REG
954 p.From.Reg = x
955 p.To.Type = obj.TYPE_REG
956 p.To.Reg = r
957 x = r
958 }
959 p := Prog(x86.ASUBQ)
960 p.From.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -0700961 p.From.Offset = v.AuxInt
Keith Randall083a6462015-05-12 11:06:44 -0700962 p.To.Type = obj.TYPE_REG
963 p.To.Reg = r
Michael Matloob703ef062015-06-16 11:11:16 -0700964 case ssa.OpAMD64SHLQ, ssa.OpAMD64SHRQ, ssa.OpAMD64SARQ:
Keith Randall6f188472015-06-10 10:39:57 -0700965 x := regnum(v.Args[0])
966 r := regnum(v)
967 if x != r {
968 if r == x86.REG_CX {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -0700969 v.Fatalf("can't implement %s, target and shift both in CX", v.LongString())
Keith Randall6f188472015-06-10 10:39:57 -0700970 }
971 p := Prog(x86.AMOVQ)
972 p.From.Type = obj.TYPE_REG
973 p.From.Reg = x
974 p.To.Type = obj.TYPE_REG
975 p.To.Reg = r
976 x = r
977 }
Michael Matloob703ef062015-06-16 11:11:16 -0700978 p := Prog(v.Op.Asm())
Keith Randall6f188472015-06-10 10:39:57 -0700979 p.From.Type = obj.TYPE_REG
980 p.From.Reg = regnum(v.Args[1]) // should be CX
981 p.To.Type = obj.TYPE_REG
982 p.To.Reg = r
Michael Matloob703ef062015-06-16 11:11:16 -0700983 case ssa.OpAMD64SHLQconst, ssa.OpAMD64SHRQconst, ssa.OpAMD64SARQconst:
Keith Randall247786c2015-05-28 10:47:24 -0700984 x := regnum(v.Args[0])
985 r := regnum(v)
986 if x != r {
987 p := Prog(x86.AMOVQ)
988 p.From.Type = obj.TYPE_REG
989 p.From.Reg = x
990 p.To.Type = obj.TYPE_REG
991 p.To.Reg = r
992 x = r
993 }
Michael Matloob703ef062015-06-16 11:11:16 -0700994 p := Prog(v.Op.Asm())
Keith Randall247786c2015-05-28 10:47:24 -0700995 p.From.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -0700996 p.From.Offset = v.AuxInt
Keith Randall247786c2015-05-28 10:47:24 -0700997 p.To.Type = obj.TYPE_REG
Keith Randalldbd83c42015-06-28 06:08:50 -0700998 p.To.Reg = r
Keith Randall6f188472015-06-10 10:39:57 -0700999 case ssa.OpAMD64SBBQcarrymask:
1000 r := regnum(v)
1001 p := Prog(x86.ASBBQ)
1002 p.From.Type = obj.TYPE_REG
1003 p.From.Reg = r
1004 p.To.Type = obj.TYPE_REG
1005 p.To.Reg = r
1006 case ssa.OpAMD64CMOVQCC:
1007 r := regnum(v)
1008 x := regnum(v.Args[1])
1009 y := regnum(v.Args[2])
1010 if x != r && y != r {
1011 p := Prog(x86.AMOVQ)
1012 p.From.Type = obj.TYPE_REG
1013 p.From.Reg = x
1014 p.To.Type = obj.TYPE_REG
1015 p.To.Reg = r
1016 x = r
1017 }
1018 var p *obj.Prog
1019 if x == r {
1020 p = Prog(x86.ACMOVQCS)
1021 p.From.Reg = y
1022 } else {
1023 p = Prog(x86.ACMOVQCC)
1024 p.From.Reg = x
1025 }
1026 p.From.Type = obj.TYPE_REG
1027 p.To.Type = obj.TYPE_REG
1028 p.To.Reg = r
Keith Randall8c46aa52015-06-19 21:02:28 -07001029 case ssa.OpAMD64LEAQ1:
Keith Randall247786c2015-05-28 10:47:24 -07001030 p := Prog(x86.ALEAQ)
1031 p.From.Type = obj.TYPE_MEM
1032 p.From.Reg = regnum(v.Args[0])
1033 p.From.Scale = 1
1034 p.From.Index = regnum(v.Args[1])
Keith Randall8c46aa52015-06-19 21:02:28 -07001035 addAux(&p.From, v)
1036 p.To.Type = obj.TYPE_REG
1037 p.To.Reg = regnum(v)
1038 case ssa.OpAMD64LEAQ:
1039 p := Prog(x86.ALEAQ)
1040 p.From.Type = obj.TYPE_MEM
1041 p.From.Reg = regnum(v.Args[0])
1042 addAux(&p.From, v)
Keith Randall247786c2015-05-28 10:47:24 -07001043 p.To.Type = obj.TYPE_REG
1044 p.To.Reg = regnum(v)
Michael Matloob703ef062015-06-16 11:11:16 -07001045 case ssa.OpAMD64CMPQ, ssa.OpAMD64TESTB, ssa.OpAMD64TESTQ:
1046 p := Prog(v.Op.Asm())
Keith Randall083a6462015-05-12 11:06:44 -07001047 p.From.Type = obj.TYPE_REG
Keith Randallcfc2aa52015-05-18 16:44:20 -07001048 p.From.Reg = regnum(v.Args[0])
Keith Randall083a6462015-05-12 11:06:44 -07001049 p.To.Type = obj.TYPE_REG
Keith Randallcfc2aa52015-05-18 16:44:20 -07001050 p.To.Reg = regnum(v.Args[1])
Keith Randall0dca7352015-06-06 16:03:33 -07001051 case ssa.OpAMD64CMPQconst:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001052 p := Prog(x86.ACMPQ)
1053 p.From.Type = obj.TYPE_REG
1054 p.From.Reg = regnum(v.Args[0])
1055 p.To.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -07001056 p.To.Offset = v.AuxInt
Keith Randall0dca7352015-06-06 16:03:33 -07001057 case ssa.OpAMD64MOVQconst:
Keith Randall083a6462015-05-12 11:06:44 -07001058 x := regnum(v)
1059 p := Prog(x86.AMOVQ)
1060 p.From.Type = obj.TYPE_CONST
Keith Randall8f22b522015-06-11 21:29:25 -07001061 p.From.Offset = v.AuxInt
Keith Randall083a6462015-05-12 11:06:44 -07001062 p.To.Type = obj.TYPE_REG
1063 p.To.Reg = x
Michael Matloob73054f52015-06-14 11:38:46 -07001064 case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload:
Michael Matloob703ef062015-06-16 11:11:16 -07001065 p := Prog(v.Op.Asm())
Keith Randallcfc2aa52015-05-18 16:44:20 -07001066 p.From.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07001067 p.From.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07001068 addAux(&p.From, v)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001069 p.To.Type = obj.TYPE_REG
1070 p.To.Reg = regnum(v)
Keith Randall0dca7352015-06-06 16:03:33 -07001071 case ssa.OpAMD64MOVQloadidx8:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001072 p := Prog(x86.AMOVQ)
1073 p.From.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07001074 p.From.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07001075 addAux(&p.From, v)
Keith Randallcfc2aa52015-05-18 16:44:20 -07001076 p.From.Scale = 8
1077 p.From.Index = regnum(v.Args[1])
1078 p.To.Type = obj.TYPE_REG
1079 p.To.Reg = regnum(v)
Michael Matloob73054f52015-06-14 11:38:46 -07001080 case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore:
1081 p := Prog(v.Op.Asm())
Keith Randall083a6462015-05-12 11:06:44 -07001082 p.From.Type = obj.TYPE_REG
Keith Randallcfc2aa52015-05-18 16:44:20 -07001083 p.From.Reg = regnum(v.Args[1])
Keith Randall083a6462015-05-12 11:06:44 -07001084 p.To.Type = obj.TYPE_MEM
Keith Randall247786c2015-05-28 10:47:24 -07001085 p.To.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07001086 addAux(&p.To, v)
Michael Matloob73054f52015-06-14 11:38:46 -07001087 case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX:
1088 p := Prog(v.Op.Asm())
1089 p.From.Type = obj.TYPE_REG
1090 p.From.Reg = regnum(v.Args[0])
1091 p.To.Type = obj.TYPE_REG
1092 p.To.Reg = regnum(v)
Daniel Morsing66b47812015-06-27 15:45:20 +01001093 case ssa.OpAMD64MOVXzero:
1094 nb := v.AuxInt
1095 offset := int64(0)
1096 reg := regnum(v.Args[0])
1097 for nb >= 8 {
1098 nb, offset = movZero(x86.AMOVQ, 8, nb, offset, reg)
1099 }
1100 for nb >= 4 {
1101 nb, offset = movZero(x86.AMOVL, 4, nb, offset, reg)
1102 }
1103 for nb >= 2 {
1104 nb, offset = movZero(x86.AMOVW, 2, nb, offset, reg)
1105 }
1106 for nb >= 1 {
1107 nb, offset = movZero(x86.AMOVB, 1, nb, offset, reg)
1108 }
Keith Randallf7f604e2015-05-27 14:52:22 -07001109 case ssa.OpCopy: // TODO: lower to MOVQ earlier?
1110 if v.Type.IsMemory() {
1111 return
1112 }
Keith Randall083a6462015-05-12 11:06:44 -07001113 x := regnum(v.Args[0])
1114 y := regnum(v)
1115 if x != y {
1116 p := Prog(x86.AMOVQ)
1117 p.From.Type = obj.TYPE_REG
1118 p.From.Reg = x
1119 p.To.Type = obj.TYPE_REG
1120 p.To.Reg = y
1121 }
1122 case ssa.OpLoadReg8:
1123 p := Prog(x86.AMOVQ)
1124 p.From.Type = obj.TYPE_MEM
1125 p.From.Reg = x86.REG_SP
Keith Randall247786c2015-05-28 10:47:24 -07001126 p.From.Offset = localOffset(v.Args[0])
Keith Randall083a6462015-05-12 11:06:44 -07001127 p.To.Type = obj.TYPE_REG
1128 p.To.Reg = regnum(v)
1129 case ssa.OpStoreReg8:
1130 p := Prog(x86.AMOVQ)
1131 p.From.Type = obj.TYPE_REG
1132 p.From.Reg = regnum(v.Args[0])
1133 p.To.Type = obj.TYPE_MEM
1134 p.To.Reg = x86.REG_SP
Keith Randall247786c2015-05-28 10:47:24 -07001135 p.To.Offset = localOffset(v)
Keith Randall083a6462015-05-12 11:06:44 -07001136 case ssa.OpPhi:
1137 // just check to make sure regalloc did it right
1138 f := v.Block.Func
1139 loc := f.RegAlloc[v.ID]
1140 for _, a := range v.Args {
1141 if f.RegAlloc[a.ID] != loc { // TODO: .Equal() instead?
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001142 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 -07001143 }
1144 }
1145 case ssa.OpConst:
1146 if v.Block.Func.RegAlloc[v.ID] != nil {
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001147 v.Fatalf("const value %v shouldn't have a location", v)
Keith Randall083a6462015-05-12 11:06:44 -07001148 }
1149 case ssa.OpArg:
1150 // memory arg needs no code
Keith Randall8f22b522015-06-11 21:29:25 -07001151 // TODO: check that only mem arg goes here.
Keith Randall290d8fc2015-06-10 15:03:06 -07001152 case ssa.OpAMD64CALLstatic:
Keith Randall247786c2015-05-28 10:47:24 -07001153 p := Prog(obj.ACALL)
1154 p.To.Type = obj.TYPE_MEM
1155 p.To.Name = obj.NAME_EXTERN
1156 p.To.Sym = Linksym(v.Aux.(*Sym))
Keith Randall290d8fc2015-06-10 15:03:06 -07001157 case ssa.OpAMD64CALLclosure:
1158 p := Prog(obj.ACALL)
1159 p.To.Type = obj.TYPE_REG
1160 p.To.Reg = regnum(v.Args[0])
Keith Randall8c46aa52015-06-19 21:02:28 -07001161 case ssa.OpSP, ssa.OpSB:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001162 // nothing to do
Keith Randall083a6462015-05-12 11:06:44 -07001163 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001164 v.Unimplementedf("value %s not implemented", v.LongString())
Keith Randall083a6462015-05-12 11:06:44 -07001165 }
1166}
1167
Daniel Morsing66b47812015-06-27 15:45:20 +01001168// movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset
1169func movZero(as int, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) {
1170 p := Prog(as)
1171 // TODO: use zero register on archs that support it.
1172 p.From.Type = obj.TYPE_CONST
1173 p.From.Offset = 0
1174 p.To.Type = obj.TYPE_MEM
1175 p.To.Reg = regnum
1176 p.To.Offset = offset
1177 offset += width
1178 nleft = nbytes - width
1179 return nleft, offset
1180}
1181
Keith Randall083a6462015-05-12 11:06:44 -07001182func genBlock(b, next *ssa.Block, branches []branch) []branch {
Michael Matloob81ccf502015-05-30 01:03:06 -04001183 lineno = b.Line
Keith Randall083a6462015-05-12 11:06:44 -07001184 switch b.Kind {
1185 case ssa.BlockPlain:
1186 if b.Succs[0] != next {
1187 p := Prog(obj.AJMP)
1188 p.To.Type = obj.TYPE_BRANCH
1189 branches = append(branches, branch{p, b.Succs[0]})
1190 }
1191 case ssa.BlockExit:
1192 Prog(obj.ARET)
Keith Randall247786c2015-05-28 10:47:24 -07001193 case ssa.BlockCall:
1194 if b.Succs[0] != next {
1195 p := Prog(obj.AJMP)
1196 p.To.Type = obj.TYPE_BRANCH
1197 branches = append(branches, branch{p, b.Succs[0]})
1198 }
Keith Randall0dca7352015-06-06 16:03:33 -07001199 case ssa.BlockAMD64EQ:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001200 if b.Succs[0] == next {
1201 p := Prog(x86.AJNE)
1202 p.To.Type = obj.TYPE_BRANCH
1203 branches = append(branches, branch{p, b.Succs[1]})
1204 } else if b.Succs[1] == next {
1205 p := Prog(x86.AJEQ)
1206 p.To.Type = obj.TYPE_BRANCH
1207 branches = append(branches, branch{p, b.Succs[0]})
1208 } else {
1209 p := Prog(x86.AJEQ)
1210 p.To.Type = obj.TYPE_BRANCH
1211 branches = append(branches, branch{p, b.Succs[0]})
1212 q := Prog(obj.AJMP)
1213 q.To.Type = obj.TYPE_BRANCH
1214 branches = append(branches, branch{q, b.Succs[1]})
1215 }
Keith Randall0dca7352015-06-06 16:03:33 -07001216 case ssa.BlockAMD64NE:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001217 if b.Succs[0] == next {
1218 p := Prog(x86.AJEQ)
1219 p.To.Type = obj.TYPE_BRANCH
1220 branches = append(branches, branch{p, b.Succs[1]})
1221 } else if b.Succs[1] == next {
1222 p := Prog(x86.AJNE)
1223 p.To.Type = obj.TYPE_BRANCH
1224 branches = append(branches, branch{p, b.Succs[0]})
1225 } else {
1226 p := Prog(x86.AJNE)
1227 p.To.Type = obj.TYPE_BRANCH
1228 branches = append(branches, branch{p, b.Succs[0]})
1229 q := Prog(obj.AJMP)
1230 q.To.Type = obj.TYPE_BRANCH
1231 branches = append(branches, branch{q, b.Succs[1]})
1232 }
Keith Randall0dca7352015-06-06 16:03:33 -07001233 case ssa.BlockAMD64LT:
Keith Randall083a6462015-05-12 11:06:44 -07001234 if b.Succs[0] == next {
1235 p := Prog(x86.AJGE)
1236 p.To.Type = obj.TYPE_BRANCH
1237 branches = append(branches, branch{p, b.Succs[1]})
1238 } else if b.Succs[1] == next {
1239 p := Prog(x86.AJLT)
1240 p.To.Type = obj.TYPE_BRANCH
1241 branches = append(branches, branch{p, b.Succs[0]})
1242 } else {
1243 p := Prog(x86.AJLT)
1244 p.To.Type = obj.TYPE_BRANCH
1245 branches = append(branches, branch{p, b.Succs[0]})
1246 q := Prog(obj.AJMP)
1247 q.To.Type = obj.TYPE_BRANCH
1248 branches = append(branches, branch{q, b.Succs[1]})
1249 }
Keith Randall0dca7352015-06-06 16:03:33 -07001250 case ssa.BlockAMD64ULT:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001251 if b.Succs[0] == next {
1252 p := Prog(x86.AJCC)
1253 p.To.Type = obj.TYPE_BRANCH
1254 branches = append(branches, branch{p, b.Succs[1]})
1255 } else if b.Succs[1] == next {
1256 p := Prog(x86.AJCS)
1257 p.To.Type = obj.TYPE_BRANCH
1258 branches = append(branches, branch{p, b.Succs[0]})
1259 } else {
1260 p := Prog(x86.AJCS)
1261 p.To.Type = obj.TYPE_BRANCH
1262 branches = append(branches, branch{p, b.Succs[0]})
1263 q := Prog(obj.AJMP)
1264 q.To.Type = obj.TYPE_BRANCH
1265 branches = append(branches, branch{q, b.Succs[1]})
1266 }
Keith Randall0dca7352015-06-06 16:03:33 -07001267 case ssa.BlockAMD64UGT:
Keith Randallcfc2aa52015-05-18 16:44:20 -07001268 if b.Succs[0] == next {
1269 p := Prog(x86.AJLS)
1270 p.To.Type = obj.TYPE_BRANCH
1271 branches = append(branches, branch{p, b.Succs[1]})
1272 } else if b.Succs[1] == next {
1273 p := Prog(x86.AJHI)
1274 p.To.Type = obj.TYPE_BRANCH
1275 branches = append(branches, branch{p, b.Succs[0]})
1276 } else {
1277 p := Prog(x86.AJHI)
1278 p.To.Type = obj.TYPE_BRANCH
1279 branches = append(branches, branch{p, b.Succs[0]})
1280 q := Prog(obj.AJMP)
1281 q.To.Type = obj.TYPE_BRANCH
1282 branches = append(branches, branch{q, b.Succs[1]})
1283 }
1284
Keith Randall083a6462015-05-12 11:06:44 -07001285 default:
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001286 b.Unimplementedf("branch %s not implemented", b.LongString())
Keith Randall083a6462015-05-12 11:06:44 -07001287 }
1288 return branches
1289}
1290
Keith Randall8c46aa52015-06-19 21:02:28 -07001291// addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
1292func addAux(a *obj.Addr, v *ssa.Value) {
1293 if a.Type != obj.TYPE_MEM {
1294 v.Fatalf("bad addAux addr %s", a)
1295 }
1296 // add integer offset
1297 a.Offset += v.AuxInt
1298
1299 // If no additional symbol offset, we're done.
1300 if v.Aux == nil {
1301 return
1302 }
1303 // Add symbol's offset from its base register.
1304 switch sym := v.Aux.(type) {
1305 case *ssa.ExternSymbol:
1306 a.Name = obj.NAME_EXTERN
1307 a.Sym = Linksym(sym.Sym.(*Sym))
1308 case *ssa.ArgSymbol:
1309 a.Offset += v.Block.Func.FrameSize + sym.Offset
1310 case *ssa.AutoSymbol:
1311 if sym.Offset == -1 {
1312 v.Fatalf("auto symbol %s offset not calculated", sym.Sym)
1313 }
1314 a.Offset += sym.Offset
1315 default:
1316 v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
1317 }
1318}
1319
Keith Randall083a6462015-05-12 11:06:44 -07001320// ssaRegToReg maps ssa register numbers to obj register numbers.
1321var ssaRegToReg = [...]int16{
1322 x86.REG_AX,
1323 x86.REG_CX,
1324 x86.REG_DX,
1325 x86.REG_BX,
1326 x86.REG_SP,
1327 x86.REG_BP,
1328 x86.REG_SI,
1329 x86.REG_DI,
1330 x86.REG_R8,
1331 x86.REG_R9,
1332 x86.REG_R10,
1333 x86.REG_R11,
1334 x86.REG_R12,
1335 x86.REG_R13,
1336 x86.REG_R14,
1337 x86.REG_R15,
Keith Randall8c46aa52015-06-19 21:02:28 -07001338 x86.REG_X0,
1339 x86.REG_X1,
1340 x86.REG_X2,
1341 x86.REG_X3,
1342 x86.REG_X4,
1343 x86.REG_X5,
1344 x86.REG_X6,
1345 x86.REG_X7,
1346 x86.REG_X8,
1347 x86.REG_X9,
1348 x86.REG_X10,
1349 x86.REG_X11,
1350 x86.REG_X12,
1351 x86.REG_X13,
1352 x86.REG_X14,
1353 x86.REG_X15,
1354 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 -07001355 // TODO: arch-dependent
1356}
1357
1358// regnum returns the register (in cmd/internal/obj numbering) to
1359// which v has been allocated. Panics if v is not assigned to a
1360// register.
1361func regnum(v *ssa.Value) int16 {
1362 return ssaRegToReg[v.Block.Func.RegAlloc[v.ID].(*ssa.Register).Num]
1363}
1364
1365// localOffset returns the offset below the frame pointer where
1366// a stack-allocated local has been allocated. Panics if v
1367// is not assigned to a local slot.
1368func localOffset(v *ssa.Value) int64 {
1369 return v.Block.Func.RegAlloc[v.ID].(*ssa.LocalSlot).Idx
1370}
Keith Randallf7f604e2015-05-27 14:52:22 -07001371
1372// ssaExport exports a bunch of compiler services for the ssa backend.
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001373type ssaExport struct {
1374 log bool
1375 unimplemented bool
1376}
Keith Randallf7f604e2015-05-27 14:52:22 -07001377
1378// StringSym returns a symbol (a *Sym wrapped in an interface) which
1379// is a global string constant containing s.
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001380func (*ssaExport) StringSym(s string) interface{} {
Keith Randall8c46aa52015-06-19 21:02:28 -07001381 // TODO: is idealstring correct? It might not matter...
Keith Randallc9372612015-06-30 21:16:51 -07001382 hdr, _ := stringsym(s)
1383 return &ssa.ExternSymbol{Typ: idealstring, Sym: hdr}
Keith Randallf7f604e2015-05-27 14:52:22 -07001384}
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001385
1386// Log logs a message from the compiler.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001387func (e *ssaExport) Logf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001388 // If e was marked as unimplemented, anything could happen. Ignore.
1389 if e.log && !e.unimplemented {
1390 fmt.Printf(msg, args...)
1391 }
1392}
1393
1394// Fatal reports a compiler error and exits.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001395func (e *ssaExport) Fatalf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001396 // If e was marked as unimplemented, anything could happen. Ignore.
1397 if !e.unimplemented {
1398 Fatal(msg, args...)
1399 }
1400}
1401
1402// Unimplemented reports that the function cannot be compiled.
1403// It will be removed once SSA work is complete.
Josh Bleecher Snyder37ddc272015-06-24 14:03:39 -07001404func (e *ssaExport) Unimplementedf(msg string, args ...interface{}) {
Josh Bleecher Snyder8c6abfe2015-06-12 11:01:13 -07001405 const alwaysLog = false // enable to calculate top unimplemented features
1406 if !e.unimplemented && (e.log || alwaysLog) {
1407 // first implementation failure, print explanation
1408 fmt.Printf("SSA unimplemented: "+msg+"\n", args...)
1409 }
1410 e.unimplemented = true
1411}