| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | // Copyright 2015 The Go Authors. All rights reserved. | 
					
						
							|  |  |  | // Use of this source code is governed by a BSD-style | 
					
						
							|  |  |  | // license that can be found in the LICENSE file. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package gc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 	"fmt" | 
					
						
							| 
									
										
										
										
											2015-07-10 10:47:28 -06:00
										 |  |  | 	"strings" | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-28 13:49:20 -07:00
										 |  |  | 	"cmd/compile/internal/ssa" | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	"cmd/internal/obj" | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	"cmd/internal/obj/x86" | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | // buildssa builds an SSA function | 
					
						
							|  |  |  | // and reports whether it should be used. | 
					
						
							|  |  |  | // Once the SSA implementation is complete, | 
					
						
							|  |  |  | // it will never return nil, and the bool can be removed. | 
					
						
							|  |  |  | func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { | 
					
						
							|  |  |  | 	name := fn.Func.Nname.Sym.Name | 
					
						
							| 
									
										
										
										
											2015-07-10 10:47:28 -06:00
										 |  |  | 	usessa = strings.HasSuffix(name, "_ssa") | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if usessa { | 
					
						
							|  |  |  | 		dumplist("buildssa-enter", fn.Func.Enter) | 
					
						
							|  |  |  | 		dumplist("buildssa-body", fn.Nbody) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 	var s state | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | 	s.pushLine(fn.Lineno) | 
					
						
							|  |  |  | 	defer s.popLine() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	// TODO(khr): build config just once at the start of the compiler binary | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var e ssaExport | 
					
						
							|  |  |  | 	e.log = usessa | 
					
						
							|  |  |  | 	s.config = ssa.NewConfig(Thearch.Thestring, &e) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	s.f = s.config.NewFunc() | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 	s.f.Name = name | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If SSA support for the function is incomplete, | 
					
						
							|  |  |  | 	// assume that any panics are due to violated | 
					
						
							|  |  |  | 	// invariants. Swallow them silently. | 
					
						
							|  |  |  | 	defer func() { | 
					
						
							|  |  |  | 		if err := recover(); err != nil { | 
					
						
							|  |  |  | 			if !e.unimplemented { | 
					
						
							|  |  |  | 				panic(err) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}() | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// We construct SSA using an algorithm similar to | 
					
						
							|  |  |  | 	// Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau | 
					
						
							|  |  |  | 	// http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf | 
					
						
							|  |  |  | 	// TODO: check this comment | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Allocate starting block | 
					
						
							|  |  |  | 	s.f.Entry = s.f.NewBlock(ssa.BlockPlain) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Allocate exit block | 
					
						
							|  |  |  | 	s.exit = s.f.NewBlock(ssa.BlockExit) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 	// Allocate starting values | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	s.vars = map[*Node]*ssa.Value{} | 
					
						
							|  |  |  | 	s.labels = map[string]*ssa.Block{} | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 	s.startmem = s.entryNewValue0(ssa.OpArg, ssa.TypeMem) | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	s.sp = s.entryNewValue0(ssa.OpSP, s.config.Uintptr) // TODO: use generic pointer type (unsafe.Pointer?) instead | 
					
						
							|  |  |  | 	s.sb = s.entryNewValue0(ssa.OpSB, s.config.Uintptr) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	// Generate addresses of local declarations | 
					
						
							|  |  |  | 	s.decladdrs = map[*Node]*ssa.Value{} | 
					
						
							|  |  |  | 	for d := fn.Func.Dcl; d != nil; d = d.Next { | 
					
						
							|  |  |  | 		n := d.N | 
					
						
							|  |  |  | 		switch n.Class { | 
					
						
							|  |  |  | 		case PPARAM, PPARAMOUT: | 
					
						
							|  |  |  | 			aux := &ssa.ArgSymbol{Typ: n.Type, Offset: n.Xoffset, Sym: n.Sym} | 
					
						
							|  |  |  | 			s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp) | 
					
						
							|  |  |  | 		case PAUTO: | 
					
						
							|  |  |  | 			aux := &ssa.AutoSymbol{Typ: n.Type, Offset: -1, Sym: n.Sym} // offset TBD by SSA pass | 
					
						
							|  |  |  | 			s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sp) | 
					
						
							| 
									
										
										
										
											2015-07-01 20:37:25 +01:00
										 |  |  | 		default: | 
					
						
							|  |  |  | 			str := "" | 
					
						
							|  |  |  | 			if n.Class&PHEAP != 0 { | 
					
						
							|  |  |  | 				str = ",heap" | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			s.Unimplementedf("local variable %v with class %s%s unimplemented", n, classnames[n.Class&^PHEAP], str) | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// nodfp is a special argument which is the function's FP. | 
					
						
							|  |  |  | 	aux := &ssa.ArgSymbol{Typ: s.config.Uintptr, Offset: 0, Sym: nodfp.Sym} | 
					
						
							|  |  |  | 	s.decladdrs[nodfp] = s.entryNewValue1A(ssa.OpAddr, s.config.Uintptr, aux, s.sp) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Convert the AST-based IR to the SSA-based IR | 
					
						
							|  |  |  | 	s.startBlock(s.f.Entry) | 
					
						
							| 
									
										
										
										
											2015-05-27 14:52:22 -07:00
										 |  |  | 	s.stmtList(fn.Func.Enter) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	s.stmtList(fn.Nbody) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 	// fallthrough to exit | 
					
						
							|  |  |  | 	if b := s.endBlock(); b != nil { | 
					
						
							|  |  |  | 		addEdge(b, s.exit) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	// Finish up exit block | 
					
						
							|  |  |  | 	s.startBlock(s.exit) | 
					
						
							|  |  |  | 	s.exit.Control = s.mem() | 
					
						
							|  |  |  | 	s.endBlock() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Link up variable uses to variable definitions | 
					
						
							|  |  |  | 	s.linkForwardReferences() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	// Main call to ssa package to compile function | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	ssa.Compile(s.f) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 	// Calculate stats about what percentage of functions SSA handles. | 
					
						
							|  |  |  | 	if false { | 
					
						
							|  |  |  | 		fmt.Printf("SSA implemented: %t\n", !e.unimplemented) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if e.unimplemented { | 
					
						
							|  |  |  | 		return nil, false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return s.f, usessa // TODO: return s.f, true once runtime support is in (gc maps, write barriers, etc.) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | type state struct { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	// configuration (arch) information | 
					
						
							|  |  |  | 	config *ssa.Config | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// function we're building | 
					
						
							|  |  |  | 	f *ssa.Func | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// exit block that "return" jumps to (and panics jump to) | 
					
						
							|  |  |  | 	exit *ssa.Block | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// the target block for each label in f | 
					
						
							|  |  |  | 	labels map[string]*ssa.Block | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// current location where we're interpreting the AST | 
					
						
							|  |  |  | 	curBlock *ssa.Block | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	// variable assignments in the current block (map from variable symbol to ssa value) | 
					
						
							|  |  |  | 	// *Node is the unique identifier (an ONAME Node) for the variable. | 
					
						
							|  |  |  | 	vars map[*Node]*ssa.Value | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// all defined variables at the end of each block.  Indexed by block ID. | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	defvars []map[*Node]*ssa.Value | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	// addresses of PPARAM, PPARAMOUT, and PAUTO variables. | 
					
						
							|  |  |  | 	decladdrs map[*Node]*ssa.Value | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// starting values.  Memory, frame pointer, and stack pointer | 
					
						
							|  |  |  | 	startmem *ssa.Value | 
					
						
							|  |  |  | 	sp       *ssa.Value | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	sb       *ssa.Value | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// line number stack.  The current line number is top of stack | 
					
						
							|  |  |  | 	line []int32 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-03 20:29:11 -07:00
										 |  |  | func (s *state) Logf(msg string, args ...interface{})           { s.config.Logf(msg, args...) } | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | func (s *state) Fatalf(msg string, args ...interface{})         { s.config.Fatalf(msg, args...) } | 
					
						
							|  |  |  | func (s *state) Unimplementedf(msg string, args ...interface{}) { s.config.Unimplementedf(msg, args...) } | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | // dummy node for the memory variable | 
					
						
							|  |  |  | var memvar = Node{Op: ONAME, Sym: &Sym{Name: "mem"}} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | // startBlock sets the current block we're generating code in to b. | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | func (s *state) startBlock(b *ssa.Block) { | 
					
						
							|  |  |  | 	if s.curBlock != nil { | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 		s.Fatalf("starting block %v when block %v has not ended", b, s.curBlock) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	s.curBlock = b | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	s.vars = map[*Node]*ssa.Value{} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // endBlock marks the end of generating code for the current block. | 
					
						
							|  |  |  | // Returns the (former) current block.  Returns nil if there is no current | 
					
						
							|  |  |  | // block, i.e. if no code flows to the current execution point. | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | func (s *state) endBlock() *ssa.Block { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	b := s.curBlock | 
					
						
							|  |  |  | 	if b == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for len(s.defvars) <= int(b.ID) { | 
					
						
							|  |  |  | 		s.defvars = append(s.defvars, nil) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	s.defvars[b.ID] = s.vars | 
					
						
							|  |  |  | 	s.curBlock = nil | 
					
						
							|  |  |  | 	s.vars = nil | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | 	b.Line = s.peekLine() | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	return b | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | // pushLine pushes a line number on the line number stack. | 
					
						
							|  |  |  | func (s *state) pushLine(line int32) { | 
					
						
							|  |  |  | 	s.line = append(s.line, line) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // popLine pops the top of the line number stack. | 
					
						
							|  |  |  | func (s *state) popLine() { | 
					
						
							|  |  |  | 	s.line = s.line[:len(s.line)-1] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // peekLine peek the top of the line number stack. | 
					
						
							|  |  |  | func (s *state) peekLine() int32 { | 
					
						
							|  |  |  | 	return s.line[len(s.line)-1] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | // newValue0 adds a new value with no arguments to the current block. | 
					
						
							|  |  |  | func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value { | 
					
						
							|  |  |  | 	return s.curBlock.NewValue0(s.peekLine(), op, t) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newValue0A adds a new value with no arguments and an aux value to the current block. | 
					
						
							|  |  |  | func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value { | 
					
						
							|  |  |  | 	return s.curBlock.NewValue0A(s.peekLine(), op, t, aux) | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newValue1 adds a new value with one argument to the current block. | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value { | 
					
						
							|  |  |  | 	return s.curBlock.NewValue1(s.peekLine(), op, t, arg) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newValue1A adds a new value with one argument and an aux value to the current block. | 
					
						
							|  |  |  | func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value { | 
					
						
							|  |  |  | 	return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg) | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // newValue2 adds a new value with two arguments to the current block. | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value { | 
					
						
							|  |  |  | 	return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1) | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-27 15:45:20 +01:00
										 |  |  | // newValue2I adds a new value with two arguments and an auxint value to the current block. | 
					
						
							|  |  |  | func (s *state) newValue2I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1 *ssa.Value) *ssa.Value { | 
					
						
							|  |  |  | 	return s.curBlock.NewValue2I(s.peekLine(), op, t, aux, arg0, arg1) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | // newValue3 adds a new value with three arguments to the current block. | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value { | 
					
						
							|  |  |  | 	return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2) | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // entryNewValue adds a new value with no arguments to the entry block. | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value { | 
					
						
							|  |  |  | 	return s.f.Entry.NewValue0(s.peekLine(), op, t) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // entryNewValue adds a new value with no arguments and an aux value to the entry block. | 
					
						
							|  |  |  | func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value { | 
					
						
							|  |  |  | 	return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux) | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // entryNewValue1 adds a new value with one argument to the entry block. | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value { | 
					
						
							|  |  |  | 	return s.f.Entry.NewValue1(s.peekLine(), op, t, arg) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // entryNewValue1 adds a new value with one argument and an auxint value to the entry block. | 
					
						
							|  |  |  | func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value { | 
					
						
							|  |  |  | 	return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg) | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | // entryNewValue1A adds a new value with one argument and an aux value to the entry block. | 
					
						
							|  |  |  | func (s *state) entryNewValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value { | 
					
						
							|  |  |  | 	return s.f.Entry.NewValue1A(s.peekLine(), op, t, aux, arg) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | // entryNewValue2 adds a new value with two arguments to the entry block. | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value { | 
					
						
							|  |  |  | 	return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1) | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // constInt adds a new const int value to the entry block. | 
					
						
							|  |  |  | func (s *state) constInt(t ssa.Type, c int64) *ssa.Value { | 
					
						
							|  |  |  | 	return s.f.ConstInt(s.peekLine(), t, c) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | // ssaStmtList converts the statement n to SSA and adds it to s. | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | func (s *state) stmtList(l *NodeList) { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	for ; l != nil; l = l.Next { | 
					
						
							|  |  |  | 		s.stmt(l.N) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // ssaStmt converts the statement n to SSA and adds it to s. | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | func (s *state) stmt(n *Node) { | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | 	s.pushLine(n.Lineno) | 
					
						
							|  |  |  | 	defer s.popLine() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	s.stmtList(n.Ninit) | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case OBLOCK: | 
					
						
							|  |  |  | 		s.stmtList(n.List) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-12 14:37:01 +01:00
										 |  |  | 	case OEMPTY, ODCLCONST, ODCLTYPE: | 
					
						
							| 
									
										
										
										
											2015-07-10 10:47:28 -06:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	case ODCL: | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | 		if n.Left.Class&PHEAP == 0 { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if compiling_runtime != 0 { | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 			Fatal("%v escapes to heap, not allowed in runtime.", n) | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// TODO: the old pass hides the details of PHEAP | 
					
						
							|  |  |  | 		// variables behind ONAME nodes. Figure out if it's better | 
					
						
							|  |  |  | 		// to rewrite the tree and make the heapaddr construct explicit | 
					
						
							|  |  |  | 		// or to keep this detail hidden behind the scenes. | 
					
						
							|  |  |  | 		palloc := prealloc[n.Left] | 
					
						
							|  |  |  | 		if palloc == nil { | 
					
						
							|  |  |  | 			palloc = callnew(n.Left.Type) | 
					
						
							|  |  |  | 			prealloc[n.Left] = palloc | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		s.assign(OAS, n.Left.Name.Heapaddr, palloc) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	case OLABEL, OGOTO: | 
					
						
							| 
									
										
										
										
											2015-07-12 11:52:09 -07:00
										 |  |  | 		if n.Op == OLABEL && isblanksym(n.Left.Sym) { | 
					
						
							|  |  |  | 			// Empty identifier is valid but useless. | 
					
						
							|  |  |  | 			// See issues 11589, 11593. | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		// get block at label, or make one | 
					
						
							|  |  |  | 		t := s.labels[n.Left.Sym.Name] | 
					
						
							|  |  |  | 		if t == nil { | 
					
						
							|  |  |  | 			t = s.f.NewBlock(ssa.BlockPlain) | 
					
						
							|  |  |  | 			s.labels[n.Left.Sym.Name] = t | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// go to that label (we pretend "label:" is preceded by "goto label") | 
					
						
							| 
									
										
										
										
											2015-06-12 16:24:33 -07:00
										 |  |  | 		if b := s.endBlock(); b != nil { | 
					
						
							|  |  |  | 			addEdge(b, t) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if n.Op == OLABEL { | 
					
						
							|  |  |  | 			// next we work on the label's target block | 
					
						
							|  |  |  | 			s.startBlock(t) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 		if n.Op == OGOTO && s.curBlock == nil { | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 			s.Unimplementedf("goto at start of function; see test/goto.go") | 
					
						
							| 
									
										
										
										
											2015-07-04 13:01:04 -07:00
										 |  |  | 			panic("stop compiling here, on pain of infinite loops") | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 	case OAS, OASWB: | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | 		s.assign(n.Op, n.Left, n.Right) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	case OIF: | 
					
						
							| 
									
										
										
										
											2015-06-11 10:20:39 -07:00
										 |  |  | 		cond := s.expr(n.Left) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		b := s.endBlock() | 
					
						
							|  |  |  | 		b.Kind = ssa.BlockIf | 
					
						
							|  |  |  | 		b.Control = cond | 
					
						
							|  |  |  | 		// TODO(khr): likely direction | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bThen := s.f.NewBlock(ssa.BlockPlain) | 
					
						
							|  |  |  | 		bEnd := s.f.NewBlock(ssa.BlockPlain) | 
					
						
							|  |  |  | 		var bElse *ssa.Block | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 10:20:39 -07:00
										 |  |  | 		if n.Rlist == nil { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 			addEdge(b, bThen) | 
					
						
							|  |  |  | 			addEdge(b, bEnd) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			bElse = s.f.NewBlock(ssa.BlockPlain) | 
					
						
							|  |  |  | 			addEdge(b, bThen) | 
					
						
							|  |  |  | 			addEdge(b, bElse) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		s.startBlock(bThen) | 
					
						
							|  |  |  | 		s.stmtList(n.Nbody) | 
					
						
							|  |  |  | 		b = s.endBlock() | 
					
						
							|  |  |  | 		if b != nil { | 
					
						
							|  |  |  | 			addEdge(b, bEnd) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-11 10:20:39 -07:00
										 |  |  | 		if n.Rlist != nil { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 			s.startBlock(bElse) | 
					
						
							| 
									
										
										
										
											2015-06-11 10:20:39 -07:00
										 |  |  | 			s.stmtList(n.Rlist) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 			b = s.endBlock() | 
					
						
							|  |  |  | 			if b != nil { | 
					
						
							|  |  |  | 				addEdge(b, bEnd) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		s.startBlock(bEnd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case ORETURN: | 
					
						
							|  |  |  | 		s.stmtList(n.List) | 
					
						
							|  |  |  | 		b := s.endBlock() | 
					
						
							|  |  |  | 		addEdge(b, s.exit) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case OFOR: | 
					
						
							| 
									
										
										
										
											2015-07-06 15:29:39 -07:00
										 |  |  | 		// OFOR: for Ninit; Left; Right { Nbody } | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		bCond := s.f.NewBlock(ssa.BlockPlain) | 
					
						
							|  |  |  | 		bBody := s.f.NewBlock(ssa.BlockPlain) | 
					
						
							| 
									
										
										
										
											2015-07-06 15:29:39 -07:00
										 |  |  | 		bIncr := s.f.NewBlock(ssa.BlockPlain) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		bEnd := s.f.NewBlock(ssa.BlockPlain) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// first, jump to condition test | 
					
						
							|  |  |  | 		b := s.endBlock() | 
					
						
							|  |  |  | 		addEdge(b, bCond) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// generate code to test condition | 
					
						
							|  |  |  | 		s.startBlock(bCond) | 
					
						
							| 
									
										
										
										
											2015-07-06 15:29:39 -07:00
										 |  |  | 		var cond *ssa.Value | 
					
						
							|  |  |  | 		if n.Left != nil { | 
					
						
							|  |  |  | 			cond = s.expr(n.Left) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			cond = s.entryNewValue0A(ssa.OpConst, Types[TBOOL], true) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		b = s.endBlock() | 
					
						
							|  |  |  | 		b.Kind = ssa.BlockIf | 
					
						
							|  |  |  | 		b.Control = cond | 
					
						
							|  |  |  | 		// TODO(khr): likely direction | 
					
						
							|  |  |  | 		addEdge(b, bBody) | 
					
						
							|  |  |  | 		addEdge(b, bEnd) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// generate body | 
					
						
							|  |  |  | 		s.startBlock(bBody) | 
					
						
							|  |  |  | 		s.stmtList(n.Nbody) | 
					
						
							| 
									
										
										
										
											2015-07-06 15:29:39 -07:00
										 |  |  | 		if b := s.endBlock(); b != nil { | 
					
						
							|  |  |  | 			addEdge(b, bIncr) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// generate incr | 
					
						
							|  |  |  | 		s.startBlock(bIncr) | 
					
						
							| 
									
										
										
										
											2015-06-24 17:48:22 -07:00
										 |  |  | 		if n.Right != nil { | 
					
						
							|  |  |  | 			s.stmt(n.Right) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-07-06 15:29:39 -07:00
										 |  |  | 		if b := s.endBlock(); b != nil { | 
					
						
							| 
									
										
										
										
											2015-07-04 09:07:54 -07:00
										 |  |  | 			addEdge(b, bCond) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		s.startBlock(bEnd) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 17:58:03 -07:00
										 |  |  | 	case OCALLFUNC: | 
					
						
							|  |  |  | 		s.expr(n) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	case OVARKILL: | 
					
						
							|  |  |  | 		// TODO(khr): ??? anything to do here?  Only for addrtaken variables? | 
					
						
							|  |  |  | 		// Maybe just link it in the store chain? | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 		s.Unimplementedf("unhandled stmt %s", opnames[n.Op]) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-24 17:48:22 -07:00
										 |  |  | var binOpToSSA = [...]ssa.Op{ | 
					
						
							|  |  |  | 	// Comparisons | 
					
						
							|  |  |  | 	OEQ: ssa.OpEq, | 
					
						
							|  |  |  | 	ONE: ssa.OpNeq, | 
					
						
							|  |  |  | 	OLT: ssa.OpLess, | 
					
						
							|  |  |  | 	OLE: ssa.OpLeq, | 
					
						
							|  |  |  | 	OGT: ssa.OpGreater, | 
					
						
							|  |  |  | 	OGE: ssa.OpGeq, | 
					
						
							|  |  |  | 	// Arithmetic | 
					
						
							|  |  |  | 	OADD: ssa.OpAdd, | 
					
						
							|  |  |  | 	OSUB: ssa.OpSub, | 
					
						
							|  |  |  | 	OLSH: ssa.OpLsh, | 
					
						
							|  |  |  | 	ORSH: ssa.OpRsh, | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | // expr converts the expression n to ssa, adds it to s and returns the ssa result. | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | func (s *state) expr(n *Node) *ssa.Value { | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | 	s.pushLine(n.Lineno) | 
					
						
							|  |  |  | 	defer s.popLine() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-11 11:39:12 -07:00
										 |  |  | 	s.stmtList(n.Ninit) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	switch n.Op { | 
					
						
							|  |  |  | 	case ONAME: | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 		if n.Class == PFUNC { | 
					
						
							|  |  |  | 			// "value" of a function is the address of the function's closure | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 			sym := funcsym(n.Sym) | 
					
						
							|  |  |  | 			aux := &ssa.ExternSymbol{n.Type, sym} | 
					
						
							|  |  |  | 			return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb) | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if canSSA(n) { | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 			return s.variable(n, n.Type) | 
					
						
							| 
									
										
										
										
											2015-05-12 15:16:52 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 		addr := s.addr(n) | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	case OLITERAL: | 
					
						
							| 
									
										
										
										
											2015-06-11 10:20:39 -07:00
										 |  |  | 		switch n.Val().Ctype() { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		case CTINT: | 
					
						
							| 
									
										
										
										
											2015-06-11 10:20:39 -07:00
										 |  |  | 			return s.constInt(n.Type, Mpgetfix(n.Val().U.(*Mpint))) | 
					
						
							| 
									
										
										
										
											2015-07-06 14:13:17 -07:00
										 |  |  | 		case CTSTR, CTBOOL: | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 			return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 			s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype()) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-12 16:24:33 -07:00
										 |  |  | 	case OCONVNOP: | 
					
						
							|  |  |  | 		x := s.expr(n.Left) | 
					
						
							| 
									
										
										
										
											2015-06-14 10:27:50 -07:00
										 |  |  | 		return s.newValue1(ssa.OpConvNop, n.Type, x) | 
					
						
							| 
									
										
										
										
											2015-06-14 11:38:46 -07:00
										 |  |  | 	case OCONV: | 
					
						
							|  |  |  | 		x := s.expr(n.Left) | 
					
						
							|  |  |  | 		return s.newValue1(ssa.OpConvert, n.Type, x) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-24 17:48:22 -07:00
										 |  |  | 	// binary ops | 
					
						
							|  |  |  | 	case OLT, OEQ, ONE, OLE, OGE, OGT: | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		a := s.expr(n.Left) | 
					
						
							|  |  |  | 		b := s.expr(n.Right) | 
					
						
							| 
									
										
										
										
											2015-06-24 17:48:22 -07:00
										 |  |  | 		return s.newValue2(binOpToSSA[n.Op], ssa.TypeBool, a, b) | 
					
						
							|  |  |  | 	case OADD, OSUB, OLSH, ORSH: | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		a := s.expr(n.Left) | 
					
						
							|  |  |  | 		b := s.expr(n.Right) | 
					
						
							| 
									
										
										
										
											2015-06-24 17:48:22 -07:00
										 |  |  | 		return s.newValue2(binOpToSSA[n.Op], a.Type, a, b) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-10 11:25:48 -06:00
										 |  |  | 	// unary ops | 
					
						
							|  |  |  | 	case ONOT: | 
					
						
							|  |  |  | 		a := s.expr(n.Left) | 
					
						
							|  |  |  | 		return s.newValue1(ssa.OpNot, a.Type, a) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 	case OADDR: | 
					
						
							|  |  |  | 		return s.addr(n.Left) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	case OIND: | 
					
						
							|  |  |  | 		p := s.expr(n.Left) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		s.nilCheck(p) | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	case ODOTPTR: | 
					
						
							|  |  |  | 		p := s.expr(n.Left) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		s.nilCheck(p) | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		p = s.newValue2(ssa.OpAdd, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset)) | 
					
						
							|  |  |  | 		return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	case OINDEX: | 
					
						
							| 
									
										
										
										
											2015-06-02 09:16:22 -07:00
										 |  |  | 		if n.Left.Type.Bound >= 0 { // array or string | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 			a := s.expr(n.Left) | 
					
						
							|  |  |  | 			i := s.expr(n.Right) | 
					
						
							| 
									
										
										
										
											2015-06-02 09:16:22 -07:00
										 |  |  | 			var elemtype *Type | 
					
						
							|  |  |  | 			var len *ssa.Value | 
					
						
							|  |  |  | 			if n.Left.Type.IsString() { | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 				len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, a) | 
					
						
							| 
									
										
										
										
											2015-06-02 09:16:22 -07:00
										 |  |  | 				elemtype = Types[TUINT8] | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | 				len = s.constInt(s.config.Uintptr, n.Left.Type.Bound) | 
					
						
							| 
									
										
										
										
											2015-06-02 09:16:22 -07:00
										 |  |  | 				elemtype = n.Left.Type.Type | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			s.boundsCheck(i, len) | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 			return s.newValue2(ssa.OpArrayIndex, elemtype, a, i) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		} else { // slice | 
					
						
							|  |  |  | 			p := s.addr(n) | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 			return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem()) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-10 10:47:28 -06:00
										 |  |  | 	case OLEN, OCAP: | 
					
						
							| 
									
										
										
										
											2015-07-03 18:41:28 -07:00
										 |  |  | 		switch { | 
					
						
							| 
									
										
										
										
											2015-07-10 10:47:28 -06:00
										 |  |  | 		case n.Left.Type.IsSlice(): | 
					
						
							|  |  |  | 			op := ssa.OpSliceLen | 
					
						
							|  |  |  | 			if n.Op == OCAP { | 
					
						
							|  |  |  | 				op = ssa.OpSliceCap | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return s.newValue1(op, s.config.Int, s.expr(n.Left)) | 
					
						
							|  |  |  | 		case n.Left.Type.IsString(): // string; not reachable for OCAP | 
					
						
							|  |  |  | 			return s.newValue1(ssa.OpStringLen, s.config.Int, s.expr(n.Left)) | 
					
						
							| 
									
										
										
										
											2015-07-03 18:41:28 -07:00
										 |  |  | 		default: // array | 
					
						
							| 
									
										
										
										
											2015-07-10 10:47:28 -06:00
										 |  |  | 			return s.constInt(s.config.Int, n.Left.Type.Bound) | 
					
						
							| 
									
										
										
										
											2015-07-03 18:41:28 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	case OCALLFUNC: | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 		static := n.Left.Op == ONAME && n.Left.Class == PFUNC | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// evaluate closure | 
					
						
							|  |  |  | 		var closure *ssa.Value | 
					
						
							|  |  |  | 		if !static { | 
					
						
							|  |  |  | 			closure = s.expr(n.Left) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		// run all argument assignments | 
					
						
							|  |  |  | 		s.stmtList(n.List) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		bNext := s.f.NewBlock(ssa.BlockPlain) | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 		var call *ssa.Value | 
					
						
							|  |  |  | 		if static { | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 			call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem()) | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 			entry := s.newValue2(ssa.OpLoad, s.config.Uintptr, closure, s.mem()) | 
					
						
							|  |  |  | 			call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, entry, closure, s.mem()) | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		b := s.endBlock() | 
					
						
							|  |  |  | 		b.Kind = ssa.BlockCall | 
					
						
							|  |  |  | 		b.Control = call | 
					
						
							|  |  |  | 		addEdge(b, bNext) | 
					
						
							|  |  |  | 		addEdge(b, s.exit) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// read result from stack at the start of the fallthrough block | 
					
						
							|  |  |  | 		s.startBlock(bNext) | 
					
						
							|  |  |  | 		var titer Iter | 
					
						
							|  |  |  | 		fp := Structfirst(&titer, Getoutarg(n.Left.Type)) | 
					
						
							| 
									
										
										
										
											2015-06-16 17:58:03 -07:00
										 |  |  | 		if fp == nil { | 
					
						
							|  |  |  | 			// CALLFUNC has no return value. Continue with the next statement. | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp) | 
					
						
							|  |  |  | 		return s.newValue2(ssa.OpLoad, fp.Type, a, call) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 		s.Unimplementedf("unhandled expr %s", opnames[n.Op]) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | func (s *state) assign(op uint8, left *Node, right *Node) { | 
					
						
							|  |  |  | 	// TODO: do write barrier | 
					
						
							|  |  |  | 	// if op == OASWB | 
					
						
							|  |  |  | 	var val *ssa.Value | 
					
						
							|  |  |  | 	if right == nil { | 
					
						
							|  |  |  | 		// right == nil means use the zero value of the assigned type. | 
					
						
							|  |  |  | 		t := left.Type | 
					
						
							| 
									
										
										
										
											2015-06-27 15:45:20 +01:00
										 |  |  | 		if !canSSA(left) { | 
					
						
							|  |  |  | 			// if we can't ssa this memory, treat it as just zeroing out the backing memory | 
					
						
							|  |  |  | 			addr := s.addr(left) | 
					
						
							|  |  |  | 			s.vars[&memvar] = s.newValue2I(ssa.OpZero, ssa.TypeMem, t.Size(), addr, s.mem()) | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case t.IsString(): | 
					
						
							| 
									
										
										
										
											2015-06-16 16:16:23 -07:00
										 |  |  | 			val = s.entryNewValue0A(ssa.OpConst, left.Type, "") | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | 		case t.IsInteger(): | 
					
						
							|  |  |  | 			val = s.entryNewValue0(ssa.OpConst, left.Type) | 
					
						
							|  |  |  | 		case t.IsBoolean(): | 
					
						
							|  |  |  | 			val = s.entryNewValue0A(ssa.OpConst, left.Type, false) // TODO: store bools as 0/1 in AuxInt? | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 			s.Unimplementedf("zero for type %v not implemented", t) | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		val = s.expr(right) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if left.Op == ONAME && canSSA(left) { | 
					
						
							|  |  |  | 		// Update variable assignment. | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 		s.vars[left] = val | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// not ssa-able.  Treat as a store. | 
					
						
							|  |  |  | 	addr := s.addr(left) | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	s.vars[&memvar] = s.newValue3(ssa.OpStore, ssa.TypeMem, addr, val, s.mem()) | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-02 09:16:22 -07:00
										 |  |  | // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result. | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | func (s *state) addr(n *Node) *ssa.Value { | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							|  |  |  | 	case ONAME: | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 		switch n.Class { | 
					
						
							|  |  |  | 		case PEXTERN: | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 			// global variable | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 			aux := &ssa.ExternSymbol{n.Type, n.Sym} | 
					
						
							|  |  |  | 			return s.entryNewValue1A(ssa.OpAddr, Ptrto(n.Type), aux, s.sb) | 
					
						
							|  |  |  | 		case PPARAM, PPARAMOUT, PAUTO: | 
					
						
							|  |  |  | 			// parameter/result slot or local variable | 
					
						
							| 
									
										
										
										
											2015-06-29 11:56:28 -07:00
										 |  |  | 			v := s.decladdrs[n] | 
					
						
							|  |  |  | 			if v == nil { | 
					
						
							| 
									
										
										
										
											2015-07-03 20:28:56 -07:00
										 |  |  | 				if flag_race != 0 && n.String() == ".fp" { | 
					
						
							|  |  |  | 					s.Unimplementedf("race detector mishandles nodfp") | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-06-29 11:56:28 -07:00
										 |  |  | 				s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return v | 
					
						
							| 
									
										
										
										
											2015-06-12 14:23:29 +01:00
										 |  |  | 		case PAUTO | PHEAP: | 
					
						
							|  |  |  | 			return s.expr(n.Name.Heapaddr) | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 			s.Unimplementedf("variable address of %v not implemented", n) | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 			return nil | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	case OINDREG: | 
					
						
							|  |  |  | 		// indirect off a register (TODO: always SP?) | 
					
						
							|  |  |  | 		// used for storing/loading arguments/returns to/from callees | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 	case OINDEX: | 
					
						
							| 
									
										
										
										
											2015-07-10 10:47:28 -06:00
										 |  |  | 		if n.Left.Type.IsSlice() { | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 			a := s.expr(n.Left) | 
					
						
							|  |  |  | 			i := s.expr(n.Right) | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 			len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, a) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 			s.boundsCheck(i, len) | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 			p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a) | 
					
						
							|  |  |  | 			return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i) | 
					
						
							| 
									
										
										
										
											2015-07-10 10:47:28 -06:00
										 |  |  | 		} else { // array | 
					
						
							|  |  |  | 			a := s.addr(n.Left) | 
					
						
							|  |  |  | 			i := s.expr(n.Right) | 
					
						
							|  |  |  | 			len := s.constInt(s.config.Uintptr, n.Left.Type.Bound) | 
					
						
							|  |  |  | 			s.boundsCheck(i, len) | 
					
						
							|  |  |  | 			return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 		s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0)) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | // canSSA reports whether n is SSA-able. | 
					
						
							|  |  |  | // n must be an ONAME. | 
					
						
							|  |  |  | func canSSA(n *Node) bool { | 
					
						
							|  |  |  | 	if n.Op != ONAME { | 
					
						
							| 
									
										
										
										
											2015-06-27 15:45:20 +01:00
										 |  |  | 		return false | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	if n.Addrtaken { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.Class&PHEAP != 0 { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.Class == PEXTERN { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if n.Class == PPARAMOUT { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-27 15:45:20 +01:00
										 |  |  | 	if Isfat(n.Type) { | 
					
						
							|  |  |  | 		return false | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 	return true | 
					
						
							|  |  |  | 	// TODO: try to make more variables SSAable. | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | // nilCheck generates nil pointer checking code. | 
					
						
							|  |  |  | // Starts a new block on return. | 
					
						
							|  |  |  | func (s *state) nilCheck(ptr *ssa.Value) { | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 	c := s.newValue1(ssa.OpIsNonNil, ssa.TypeBool, ptr) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 	b := s.endBlock() | 
					
						
							|  |  |  | 	b.Kind = ssa.BlockIf | 
					
						
							|  |  |  | 	b.Control = c | 
					
						
							|  |  |  | 	bNext := s.f.NewBlock(ssa.BlockPlain) | 
					
						
							|  |  |  | 	addEdge(b, bNext) | 
					
						
							|  |  |  | 	addEdge(b, s.exit) | 
					
						
							|  |  |  | 	s.startBlock(bNext) | 
					
						
							|  |  |  | 	// TODO(khr): Don't go directly to exit.  Go to a stub that calls panicmem first. | 
					
						
							|  |  |  | 	// TODO: implicit nil checks somehow? | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // boundsCheck generates bounds checking code.  Checks if 0 <= idx < len, branches to exit if not. | 
					
						
							|  |  |  | // Starts a new block on return. | 
					
						
							|  |  |  | func (s *state) boundsCheck(idx, len *ssa.Value) { | 
					
						
							|  |  |  | 	// TODO: convert index to full width? | 
					
						
							|  |  |  | 	// TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// bounds check | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 	cmp := s.newValue2(ssa.OpIsInBounds, ssa.TypeBool, idx, len) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 	b := s.endBlock() | 
					
						
							|  |  |  | 	b.Kind = ssa.BlockIf | 
					
						
							|  |  |  | 	b.Control = cmp | 
					
						
							|  |  |  | 	bNext := s.f.NewBlock(ssa.BlockPlain) | 
					
						
							|  |  |  | 	addEdge(b, bNext) | 
					
						
							|  |  |  | 	addEdge(b, s.exit) | 
					
						
							|  |  |  | 	// TODO: don't go directly to s.exit.  Go to a stub that calls panicindex first. | 
					
						
							|  |  |  | 	s.startBlock(bNext) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | // variable returns the value of a variable at the current location. | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | func (s *state) variable(name *Node, t ssa.Type) *ssa.Value { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	if s.curBlock == nil { | 
					
						
							| 
									
										
										
										
											2015-06-24 13:29:05 -07:00
										 |  |  | 		// Unimplemented instead of Fatal because fixedbugs/bug303.go | 
					
						
							|  |  |  | 		// demonstrates a case in which this appears to happen legitimately. | 
					
						
							|  |  |  | 		// TODO: decide on the correct behavior here. | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 		s.Unimplementedf("nil curblock adding variable %v (%v)", name, t) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	v := s.vars[name] | 
					
						
							|  |  |  | 	if v == nil { | 
					
						
							|  |  |  | 		// TODO: get type?  Take Sym as arg? | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		v = s.newValue0A(ssa.OpFwdRef, t, name) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		s.vars[name] = v | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return v | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | func (s *state) mem() *ssa.Value { | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	return s.variable(&memvar, ssa.TypeMem) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | func (s *state) linkForwardReferences() { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	// Build ssa graph.  Each variable on its first use in a basic block | 
					
						
							|  |  |  | 	// leaves a FwdRef in that block representing the incoming value | 
					
						
							|  |  |  | 	// of that variable.  This function links that ref up with possible definitions, | 
					
						
							|  |  |  | 	// inserting Phi values as needed.  This is essentially the algorithm | 
					
						
							|  |  |  | 	// described by Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau: | 
					
						
							|  |  |  | 	// http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf | 
					
						
							|  |  |  | 	for _, b := range s.f.Blocks { | 
					
						
							|  |  |  | 		for _, v := range b.Values { | 
					
						
							|  |  |  | 			if v.Op != ssa.OpFwdRef { | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 			name := v.Aux.(*Node) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 			v.Op = ssa.OpCopy | 
					
						
							|  |  |  | 			v.Aux = nil | 
					
						
							|  |  |  | 			v.SetArgs1(s.lookupVarIncoming(b, v.Type, name)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // lookupVarIncoming finds the variable's value at the start of block b. | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	// TODO(khr): have lookupVarIncoming overwrite the fwdRef or copy it | 
					
						
							|  |  |  | 	// will be used in, instead of having the result used in a copy value. | 
					
						
							|  |  |  | 	if b == s.f.Entry { | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 		if name == &memvar { | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 			return s.startmem | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		// variable is live at the entry block.  Load it. | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 		addr := s.decladdrs[name] | 
					
						
							|  |  |  | 		if addr == nil { | 
					
						
							|  |  |  | 			// TODO: closure args reach here. | 
					
						
							|  |  |  | 			s.Unimplementedf("variable %s not found", name) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if _, ok := addr.Aux.(*ssa.ArgSymbol); !ok { | 
					
						
							|  |  |  | 			s.Fatalf("variable live at start of function %s is not an argument %s", b.Func.Name, name) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		return s.entryNewValue2(ssa.OpLoad, t, addr, s.startmem) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	var vals []*ssa.Value | 
					
						
							|  |  |  | 	for _, p := range b.Preds { | 
					
						
							|  |  |  | 		vals = append(vals, s.lookupVarOutgoing(p, t, name)) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 	if len(vals) == 0 { | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 		s.Unimplementedf("TODO: Handle fixedbugs/bug076.go") | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	v0 := vals[0] | 
					
						
							|  |  |  | 	for i := 1; i < len(vals); i++ { | 
					
						
							|  |  |  | 		if vals[i] != v0 { | 
					
						
							|  |  |  | 			// need a phi value | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 			v := b.NewValue0(s.peekLine(), ssa.OpPhi, t) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 			v.AddArgs(vals...) | 
					
						
							|  |  |  | 			return v | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return v0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // lookupVarOutgoing finds the variable's value at the end of block b. | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name *Node) *ssa.Value { | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	m := s.defvars[b.ID] | 
					
						
							|  |  |  | 	if v, ok := m[name]; ok { | 
					
						
							|  |  |  | 		return v | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// The variable is not defined by b and we haven't | 
					
						
							|  |  |  | 	// looked it up yet.  Generate v, a copy value which | 
					
						
							|  |  |  | 	// will be the outgoing value of the variable.  Then | 
					
						
							|  |  |  | 	// look up w, the incoming value of the variable. | 
					
						
							|  |  |  | 	// Make v = copy(w).  We need the extra copy to | 
					
						
							|  |  |  | 	// prevent infinite recursion when looking up the | 
					
						
							|  |  |  | 	// incoming value of the variable. | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 	v := b.NewValue0(s.peekLine(), ssa.OpCopy, t) | 
					
						
							| 
									
										
										
										
											2015-04-15 15:51:25 -07:00
										 |  |  | 	m[name] = v | 
					
						
							|  |  |  | 	v.AddArg(s.lookupVarIncoming(b, t, name)) | 
					
						
							|  |  |  | 	return v | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TODO: the above mutually recursive functions can lead to very deep stacks.  Fix that. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // addEdge adds an edge from b to c. | 
					
						
							|  |  |  | func addEdge(b, c *ssa.Block) { | 
					
						
							|  |  |  | 	b.Succs = append(b.Succs, c) | 
					
						
							|  |  |  | 	c.Preds = append(c.Preds, b) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // an unresolved branch | 
					
						
							|  |  |  | type branch struct { | 
					
						
							|  |  |  | 	p *obj.Prog  // branch instruction | 
					
						
							|  |  |  | 	b *ssa.Block // target | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // genssa appends entries to ptxt for each instruction in f. | 
					
						
							|  |  |  | // gcargs and gclocals are filled in with pointer maps for the frame. | 
					
						
							|  |  |  | func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { | 
					
						
							|  |  |  | 	// TODO: line numbers | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if f.FrameSize > 1<<31 { | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		Yyerror("stack frame too large (>2GB)") | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ptxt.To.Type = obj.TYPE_TEXTSIZE | 
					
						
							|  |  |  | 	ptxt.To.Val = int32(Rnd(Curfn.Type.Argwid, int64(Widthptr))) // arg size | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 	ptxt.To.Offset = f.FrameSize - 8                             // TODO: arch-dependent | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Remember where each block starts. | 
					
						
							|  |  |  | 	bstart := make([]*obj.Prog, f.NumBlocks()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Remember all the branch instructions we've seen | 
					
						
							|  |  |  | 	// and where they would like to go | 
					
						
							|  |  |  | 	var branches []branch | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Emit basic blocks | 
					
						
							|  |  |  | 	for i, b := range f.Blocks { | 
					
						
							|  |  |  | 		bstart[b.ID] = Pc | 
					
						
							|  |  |  | 		// Emit values in block | 
					
						
							|  |  |  | 		for _, v := range b.Values { | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 			genValue(v) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		// Emit control flow instructions for block | 
					
						
							|  |  |  | 		var next *ssa.Block | 
					
						
							|  |  |  | 		if i < len(f.Blocks)-1 { | 
					
						
							|  |  |  | 			next = f.Blocks[i+1] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		branches = genBlock(b, next, branches) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Resolve branches | 
					
						
							|  |  |  | 	for _, br := range branches { | 
					
						
							|  |  |  | 		br.p.To.Val = bstart[br.b.ID] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Pc.As = obj.ARET // overwrite AEND | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO: liveness | 
					
						
							|  |  |  | 	// TODO: gcargs | 
					
						
							|  |  |  | 	// TODO: gclocals | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// TODO: dump frame if -f | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Emit garbage collection symbols.  TODO: put something in them | 
					
						
							| 
									
										
										
										
											2015-05-27 14:52:22 -07:00
										 |  |  | 	//liveness(Curfn, ptxt, gcargs, gclocals) | 
					
						
							|  |  |  | 	duint32(gcargs, 0, 0) | 
					
						
							|  |  |  | 	ggloblsym(gcargs, 4, obj.RODATA|obj.DUPOK) | 
					
						
							|  |  |  | 	duint32(gclocals, 0, 0) | 
					
						
							|  |  |  | 	ggloblsym(gclocals, 4, obj.RODATA|obj.DUPOK) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | func genValue(v *ssa.Value) { | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | 	lineno = v.Line | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	switch v.Op { | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.OpAMD64ADDQ: | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		// TODO: use addq instead of leaq if target is in the right register. | 
					
						
							|  |  |  | 		p := Prog(x86.ALEAQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		p.From.Scale = 1 | 
					
						
							|  |  |  | 		p.From.Index = regnum(v.Args[1]) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							| 
									
										
										
										
											2015-06-14 11:38:46 -07:00
										 |  |  | 	case ssa.OpAMD64ADDL: | 
					
						
							|  |  |  | 		p := Prog(x86.ALEAL) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		p.From.Scale = 1 | 
					
						
							|  |  |  | 		p.From.Index = regnum(v.Args[1]) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							|  |  |  | 	case ssa.OpAMD64ADDW: | 
					
						
							|  |  |  | 		p := Prog(x86.ALEAW) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		p.From.Scale = 1 | 
					
						
							|  |  |  | 		p.From.Index = regnum(v.Args[1]) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							|  |  |  | 	case ssa.OpAMD64ADDB, ssa.OpAMD64ANDQ: | 
					
						
							|  |  |  | 		r := regnum(v) | 
					
						
							|  |  |  | 		x := regnum(v.Args[0]) | 
					
						
							|  |  |  | 		y := regnum(v.Args[1]) | 
					
						
							|  |  |  | 		if x != r && y != r { | 
					
						
							|  |  |  | 			p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 			p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.From.Reg = x | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.To.Reg = r | 
					
						
							|  |  |  | 			x = r | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		p := Prog(v.Op.Asm()) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = r | 
					
						
							|  |  |  | 		if x == r { | 
					
						
							|  |  |  | 			p.From.Reg = y | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			p.From.Reg = x | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.OpAMD64ADDQconst: | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		// TODO: use addq instead of leaq if target is in the right register. | 
					
						
							|  |  |  | 		p := Prog(x86.ALEAQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		p.From.Offset = v.AuxInt | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.OpAMD64MULQconst: | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 		v.Unimplementedf("IMULQ doasm") | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 		return | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		// TODO: this isn't right.  doasm fails on it.  I don't think obj | 
					
						
							|  |  |  | 		// has ever been taught to compile imul $c, r1, r2. | 
					
						
							|  |  |  | 		p := Prog(x86.AIMULQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_CONST | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		p.From.Offset = v.AuxInt | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 		p.From3 = new(obj.Addr) | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		p.From3.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.From3.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.OpAMD64SUBQconst: | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		// This code compensates for the fact that the register allocator | 
					
						
							|  |  |  | 		// doesn't understand 2-address instructions yet.  TODO: fix that. | 
					
						
							|  |  |  | 		x := regnum(v.Args[0]) | 
					
						
							|  |  |  | 		r := regnum(v) | 
					
						
							|  |  |  | 		if x != r { | 
					
						
							|  |  |  | 			p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 			p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.From.Reg = x | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.To.Reg = r | 
					
						
							|  |  |  | 			x = r | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		p := Prog(x86.ASUBQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_CONST | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		p.From.Offset = v.AuxInt | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = r | 
					
						
							| 
									
										
										
										
											2015-06-16 11:11:16 -07:00
										 |  |  | 	case ssa.OpAMD64SHLQ, ssa.OpAMD64SHRQ, ssa.OpAMD64SARQ: | 
					
						
							| 
									
										
										
										
											2015-06-10 10:39:57 -07:00
										 |  |  | 		x := regnum(v.Args[0]) | 
					
						
							|  |  |  | 		r := regnum(v) | 
					
						
							|  |  |  | 		if x != r { | 
					
						
							|  |  |  | 			if r == x86.REG_CX { | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 				v.Fatalf("can't implement %s, target and shift both in CX", v.LongString()) | 
					
						
							| 
									
										
										
										
											2015-06-10 10:39:57 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 			p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 			p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.From.Reg = x | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.To.Reg = r | 
					
						
							|  |  |  | 			x = r | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-16 11:11:16 -07:00
										 |  |  | 		p := Prog(v.Op.Asm()) | 
					
						
							| 
									
										
										
										
											2015-06-10 10:39:57 -07:00
										 |  |  | 		p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[1]) // should be CX | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = r | 
					
						
							| 
									
										
										
										
											2015-06-16 11:11:16 -07:00
										 |  |  | 	case ssa.OpAMD64SHLQconst, ssa.OpAMD64SHRQconst, ssa.OpAMD64SARQconst: | 
					
						
							| 
									
										
										
										
											2015-06-10 10:39:57 -07:00
										 |  |  | 		x := regnum(v.Args[0]) | 
					
						
							|  |  |  | 		r := regnum(v) | 
					
						
							|  |  |  | 		if x != r { | 
					
						
							|  |  |  | 			p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 			p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.From.Reg = x | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.To.Reg = r | 
					
						
							|  |  |  | 			x = r | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-16 11:11:16 -07:00
										 |  |  | 		p := Prog(v.Op.Asm()) | 
					
						
							| 
									
										
										
										
											2015-06-10 10:39:57 -07:00
										 |  |  | 		p.From.Type = obj.TYPE_CONST | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		p.From.Offset = v.AuxInt | 
					
						
							| 
									
										
										
										
											2015-06-10 10:39:57 -07:00
										 |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							| 
									
										
										
										
											2015-06-28 06:08:50 -07:00
										 |  |  | 		p.To.Reg = r | 
					
						
							| 
									
										
										
										
											2015-06-10 10:39:57 -07:00
										 |  |  | 	case ssa.OpAMD64SBBQcarrymask: | 
					
						
							|  |  |  | 		r := regnum(v) | 
					
						
							|  |  |  | 		p := Prog(x86.ASBBQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.From.Reg = r | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = r | 
					
						
							|  |  |  | 	case ssa.OpAMD64CMOVQCC: | 
					
						
							|  |  |  | 		r := regnum(v) | 
					
						
							|  |  |  | 		x := regnum(v.Args[1]) | 
					
						
							|  |  |  | 		y := regnum(v.Args[2]) | 
					
						
							|  |  |  | 		if x != r && y != r { | 
					
						
							|  |  |  | 			p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 			p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.From.Reg = x | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.To.Reg = r | 
					
						
							|  |  |  | 			x = r | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var p *obj.Prog | 
					
						
							|  |  |  | 		if x == r { | 
					
						
							|  |  |  | 			p = Prog(x86.ACMOVQCS) | 
					
						
							|  |  |  | 			p.From.Reg = y | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			p = Prog(x86.ACMOVQCC) | 
					
						
							|  |  |  | 			p.From.Reg = x | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = r | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	case ssa.OpAMD64LEAQ1: | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		p := Prog(x86.ALEAQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		p.From.Scale = 1 | 
					
						
							|  |  |  | 		p.From.Index = regnum(v.Args[1]) | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 		addAux(&p.From, v) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							|  |  |  | 	case ssa.OpAMD64LEAQ: | 
					
						
							|  |  |  | 		p := Prog(x86.ALEAQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		addAux(&p.From, v) | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							| 
									
										
										
										
											2015-06-16 11:11:16 -07:00
										 |  |  | 	case ssa.OpAMD64CMPQ, ssa.OpAMD64TESTB, ssa.OpAMD64TESTQ: | 
					
						
							|  |  |  | 		p := Prog(v.Op.Asm()) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		p.From.Type = obj.TYPE_REG | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v.Args[1]) | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.OpAMD64CMPQconst: | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		p := Prog(x86.ACMPQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_CONST | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		p.To.Offset = v.AuxInt | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.OpAMD64MOVQconst: | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		x := regnum(v) | 
					
						
							|  |  |  | 		p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_CONST | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		p.From.Offset = v.AuxInt | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = x | 
					
						
							| 
									
										
										
										
											2015-06-14 11:38:46 -07:00
										 |  |  | 	case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload: | 
					
						
							| 
									
										
										
										
											2015-06-16 11:11:16 -07:00
										 |  |  | 		p := Prog(v.Op.Asm()) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		p.From.Type = obj.TYPE_MEM | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 		addAux(&p.From, v) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.OpAMD64MOVQloadidx8: | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_MEM | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 		addAux(&p.From, v) | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		p.From.Scale = 8 | 
					
						
							|  |  |  | 		p.From.Index = regnum(v.Args[1]) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							| 
									
										
										
										
											2015-06-14 11:38:46 -07:00
										 |  |  | 	case ssa.OpAMD64MOVQstore, ssa.OpAMD64MOVLstore, ssa.OpAMD64MOVWstore, ssa.OpAMD64MOVBstore: | 
					
						
							|  |  |  | 		p := Prog(v.Op.Asm()) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		p.From.Type = obj.TYPE_REG | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		p.From.Reg = regnum(v.Args[1]) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		p.To.Type = obj.TYPE_MEM | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		p.To.Reg = regnum(v.Args[0]) | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 		addAux(&p.To, v) | 
					
						
							| 
									
										
										
										
											2015-06-14 11:38:46 -07:00
										 |  |  | 	case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX: | 
					
						
							|  |  |  | 		p := Prog(v.Op.Asm()) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							| 
									
										
										
										
											2015-06-27 15:45:20 +01:00
										 |  |  | 	case ssa.OpAMD64MOVXzero: | 
					
						
							|  |  |  | 		nb := v.AuxInt | 
					
						
							|  |  |  | 		offset := int64(0) | 
					
						
							|  |  |  | 		reg := regnum(v.Args[0]) | 
					
						
							|  |  |  | 		for nb >= 8 { | 
					
						
							|  |  |  | 			nb, offset = movZero(x86.AMOVQ, 8, nb, offset, reg) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for nb >= 4 { | 
					
						
							|  |  |  | 			nb, offset = movZero(x86.AMOVL, 4, nb, offset, reg) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for nb >= 2 { | 
					
						
							|  |  |  | 			nb, offset = movZero(x86.AMOVW, 2, nb, offset, reg) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		for nb >= 1 { | 
					
						
							|  |  |  | 			nb, offset = movZero(x86.AMOVB, 1, nb, offset, reg) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-05-27 14:52:22 -07:00
										 |  |  | 	case ssa.OpCopy: // TODO: lower to MOVQ earlier? | 
					
						
							|  |  |  | 		if v.Type.IsMemory() { | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		x := regnum(v.Args[0]) | 
					
						
							|  |  |  | 		y := regnum(v) | 
					
						
							|  |  |  | 		if x != y { | 
					
						
							|  |  |  | 			p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 			p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.From.Reg = x | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 			p.To.Reg = y | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case ssa.OpLoadReg8: | 
					
						
							|  |  |  | 		p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 		p.From.Reg = x86.REG_SP | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		p.From.Offset = localOffset(v.Args[0]) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v) | 
					
						
							|  |  |  | 	case ssa.OpStoreReg8: | 
					
						
							|  |  |  | 		p := Prog(x86.AMOVQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.From.Reg = regnum(v.Args[0]) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 		p.To.Reg = x86.REG_SP | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		p.To.Offset = localOffset(v) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	case ssa.OpPhi: | 
					
						
							|  |  |  | 		// just check to make sure regalloc did it right | 
					
						
							|  |  |  | 		f := v.Block.Func | 
					
						
							|  |  |  | 		loc := f.RegAlloc[v.ID] | 
					
						
							|  |  |  | 		for _, a := range v.Args { | 
					
						
							|  |  |  | 			if f.RegAlloc[a.ID] != loc { // TODO: .Equal() instead? | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 				v.Fatalf("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID]) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case ssa.OpConst: | 
					
						
							|  |  |  | 		if v.Block.Func.RegAlloc[v.ID] != nil { | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 			v.Fatalf("const value %v shouldn't have a location", v) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	case ssa.OpArg: | 
					
						
							|  |  |  | 		// memory arg needs no code | 
					
						
							| 
									
										
										
										
											2015-06-11 21:29:25 -07:00
										 |  |  | 		// TODO: check that only mem arg goes here. | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 	case ssa.OpAMD64CALLstatic: | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 		p := Prog(obj.ACALL) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 		p.To.Name = obj.NAME_EXTERN | 
					
						
							|  |  |  | 		p.To.Sym = Linksym(v.Aux.(*Sym)) | 
					
						
							| 
									
										
										
										
											2015-06-10 15:03:06 -07:00
										 |  |  | 	case ssa.OpAMD64CALLclosure: | 
					
						
							|  |  |  | 		p := Prog(obj.ACALL) | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v.Args[0]) | 
					
						
							| 
									
										
										
										
											2015-07-10 11:25:48 -06:00
										 |  |  | 	case ssa.OpAMD64XORQconst: | 
					
						
							|  |  |  | 		p := Prog(x86.AXORQ) | 
					
						
							|  |  |  | 		p.From.Type = obj.TYPE_CONST | 
					
						
							|  |  |  | 		p.From.Offset = v.AuxInt | 
					
						
							|  |  |  | 		p.To.Type = obj.TYPE_REG | 
					
						
							|  |  |  | 		p.To.Reg = regnum(v.Args[0]) | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	case ssa.OpSP, ssa.OpSB: | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		// nothing to do | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 		v.Unimplementedf("value %s not implemented", v.LongString()) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-27 15:45:20 +01:00
										 |  |  | // movZero generates a register indirect move with a 0 immediate and keeps track of bytes left and next offset | 
					
						
							|  |  |  | func movZero(as int, width int64, nbytes int64, offset int64, regnum int16) (nleft int64, noff int64) { | 
					
						
							|  |  |  | 	p := Prog(as) | 
					
						
							|  |  |  | 	// TODO: use zero register on archs that support it. | 
					
						
							|  |  |  | 	p.From.Type = obj.TYPE_CONST | 
					
						
							|  |  |  | 	p.From.Offset = 0 | 
					
						
							|  |  |  | 	p.To.Type = obj.TYPE_MEM | 
					
						
							|  |  |  | 	p.To.Reg = regnum | 
					
						
							|  |  |  | 	p.To.Offset = offset | 
					
						
							|  |  |  | 	offset += width | 
					
						
							|  |  |  | 	nleft = nbytes - width | 
					
						
							|  |  |  | 	return nleft, offset | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | func genBlock(b, next *ssa.Block, branches []branch) []branch { | 
					
						
							| 
									
										
										
										
											2015-05-30 01:03:06 -04:00
										 |  |  | 	lineno = b.Line | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	switch b.Kind { | 
					
						
							|  |  |  | 	case ssa.BlockPlain: | 
					
						
							|  |  |  | 		if b.Succs[0] != next { | 
					
						
							|  |  |  | 			p := Prog(obj.AJMP) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	case ssa.BlockExit: | 
					
						
							|  |  |  | 		Prog(obj.ARET) | 
					
						
							| 
									
										
										
										
											2015-05-28 10:47:24 -07:00
										 |  |  | 	case ssa.BlockCall: | 
					
						
							|  |  |  | 		if b.Succs[0] != next { | 
					
						
							|  |  |  | 			p := Prog(obj.AJMP) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.BlockAMD64EQ: | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		if b.Succs[0] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJNE) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[1]}) | 
					
						
							|  |  |  | 		} else if b.Succs[1] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJEQ) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			p := Prog(x86.AJEQ) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 			q := Prog(obj.AJMP) | 
					
						
							|  |  |  | 			q.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{q, b.Succs[1]}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.BlockAMD64NE: | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		if b.Succs[0] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJEQ) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[1]}) | 
					
						
							|  |  |  | 		} else if b.Succs[1] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJNE) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			p := Prog(x86.AJNE) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 			q := Prog(obj.AJMP) | 
					
						
							|  |  |  | 			q.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{q, b.Succs[1]}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.BlockAMD64LT: | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 		if b.Succs[0] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJGE) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[1]}) | 
					
						
							|  |  |  | 		} else if b.Succs[1] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJLT) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			p := Prog(x86.AJLT) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 			q := Prog(obj.AJMP) | 
					
						
							|  |  |  | 			q.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{q, b.Succs[1]}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.BlockAMD64ULT: | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		if b.Succs[0] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJCC) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[1]}) | 
					
						
							|  |  |  | 		} else if b.Succs[1] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJCS) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			p := Prog(x86.AJCS) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 			q := Prog(obj.AJMP) | 
					
						
							|  |  |  | 			q.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{q, b.Succs[1]}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-06-06 16:03:33 -07:00
										 |  |  | 	case ssa.BlockAMD64UGT: | 
					
						
							| 
									
										
										
										
											2015-05-18 16:44:20 -07:00
										 |  |  | 		if b.Succs[0] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJLS) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[1]}) | 
					
						
							|  |  |  | 		} else if b.Succs[1] == next { | 
					
						
							|  |  |  | 			p := Prog(x86.AJHI) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			p := Prog(x86.AJHI) | 
					
						
							|  |  |  | 			p.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{p, b.Succs[0]}) | 
					
						
							|  |  |  | 			q := Prog(obj.AJMP) | 
					
						
							|  |  |  | 			q.To.Type = obj.TYPE_BRANCH | 
					
						
							|  |  |  | 			branches = append(branches, branch{q, b.Succs[1]}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | 		b.Unimplementedf("branch %s not implemented", b.LongString()) | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return branches | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | // addAux adds the offset in the aux fields (AuxInt and Aux) of v to a. | 
					
						
							|  |  |  | func addAux(a *obj.Addr, v *ssa.Value) { | 
					
						
							|  |  |  | 	if a.Type != obj.TYPE_MEM { | 
					
						
							|  |  |  | 		v.Fatalf("bad addAux addr %s", a) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// add integer offset | 
					
						
							|  |  |  | 	a.Offset += v.AuxInt | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// If no additional symbol offset, we're done. | 
					
						
							|  |  |  | 	if v.Aux == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Add symbol's offset from its base register. | 
					
						
							|  |  |  | 	switch sym := v.Aux.(type) { | 
					
						
							|  |  |  | 	case *ssa.ExternSymbol: | 
					
						
							|  |  |  | 		a.Name = obj.NAME_EXTERN | 
					
						
							|  |  |  | 		a.Sym = Linksym(sym.Sym.(*Sym)) | 
					
						
							|  |  |  | 	case *ssa.ArgSymbol: | 
					
						
							|  |  |  | 		a.Offset += v.Block.Func.FrameSize + sym.Offset | 
					
						
							|  |  |  | 	case *ssa.AutoSymbol: | 
					
						
							|  |  |  | 		if sym.Offset == -1 { | 
					
						
							|  |  |  | 			v.Fatalf("auto symbol %s offset not calculated", sym.Sym) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		a.Offset += sym.Offset | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 		v.Fatalf("aux in %s not implemented %#v", v, v.Aux) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | // ssaRegToReg maps ssa register numbers to obj register numbers. | 
					
						
							|  |  |  | var ssaRegToReg = [...]int16{ | 
					
						
							|  |  |  | 	x86.REG_AX, | 
					
						
							|  |  |  | 	x86.REG_CX, | 
					
						
							|  |  |  | 	x86.REG_DX, | 
					
						
							|  |  |  | 	x86.REG_BX, | 
					
						
							|  |  |  | 	x86.REG_SP, | 
					
						
							|  |  |  | 	x86.REG_BP, | 
					
						
							|  |  |  | 	x86.REG_SI, | 
					
						
							|  |  |  | 	x86.REG_DI, | 
					
						
							|  |  |  | 	x86.REG_R8, | 
					
						
							|  |  |  | 	x86.REG_R9, | 
					
						
							|  |  |  | 	x86.REG_R10, | 
					
						
							|  |  |  | 	x86.REG_R11, | 
					
						
							|  |  |  | 	x86.REG_R12, | 
					
						
							|  |  |  | 	x86.REG_R13, | 
					
						
							|  |  |  | 	x86.REG_R14, | 
					
						
							|  |  |  | 	x86.REG_R15, | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	x86.REG_X0, | 
					
						
							|  |  |  | 	x86.REG_X1, | 
					
						
							|  |  |  | 	x86.REG_X2, | 
					
						
							|  |  |  | 	x86.REG_X3, | 
					
						
							|  |  |  | 	x86.REG_X4, | 
					
						
							|  |  |  | 	x86.REG_X5, | 
					
						
							|  |  |  | 	x86.REG_X6, | 
					
						
							|  |  |  | 	x86.REG_X7, | 
					
						
							|  |  |  | 	x86.REG_X8, | 
					
						
							|  |  |  | 	x86.REG_X9, | 
					
						
							|  |  |  | 	x86.REG_X10, | 
					
						
							|  |  |  | 	x86.REG_X11, | 
					
						
							|  |  |  | 	x86.REG_X12, | 
					
						
							|  |  |  | 	x86.REG_X13, | 
					
						
							|  |  |  | 	x86.REG_X14, | 
					
						
							|  |  |  | 	x86.REG_X15, | 
					
						
							|  |  |  | 	0, // SB isn't a real register.  We fill an Addr.Reg field with 0 in this case. | 
					
						
							| 
									
										
										
										
											2015-05-12 11:06:44 -07:00
										 |  |  | 	// TODO: arch-dependent | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // regnum returns the register (in cmd/internal/obj numbering) to | 
					
						
							|  |  |  | // which v has been allocated.  Panics if v is not assigned to a | 
					
						
							|  |  |  | // register. | 
					
						
							|  |  |  | func regnum(v *ssa.Value) int16 { | 
					
						
							|  |  |  | 	return ssaRegToReg[v.Block.Func.RegAlloc[v.ID].(*ssa.Register).Num] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // localOffset returns the offset below the frame pointer where | 
					
						
							|  |  |  | // a stack-allocated local has been allocated.  Panics if v | 
					
						
							|  |  |  | // is not assigned to a local slot. | 
					
						
							|  |  |  | func localOffset(v *ssa.Value) int64 { | 
					
						
							|  |  |  | 	return v.Block.Func.RegAlloc[v.ID].(*ssa.LocalSlot).Idx | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-27 14:52:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // ssaExport exports a bunch of compiler services for the ssa backend. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | type ssaExport struct { | 
					
						
							|  |  |  | 	log           bool | 
					
						
							|  |  |  | 	unimplemented bool | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2015-05-27 14:52:22 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // StringSym returns a symbol (a *Sym wrapped in an interface) which | 
					
						
							|  |  |  | // is a global string constant containing s. | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | func (*ssaExport) StringSym(s string) interface{} { | 
					
						
							| 
									
										
										
										
											2015-06-19 21:02:28 -07:00
										 |  |  | 	// TODO: is idealstring correct?  It might not matter... | 
					
						
							| 
									
										
										
										
											2015-06-30 21:16:51 -07:00
										 |  |  | 	hdr, _ := stringsym(s) | 
					
						
							|  |  |  | 	return &ssa.ExternSymbol{Typ: idealstring, Sym: hdr} | 
					
						
							| 
									
										
										
										
											2015-05-27 14:52:22 -07:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Log logs a message from the compiler. | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | func (e *ssaExport) Logf(msg string, args ...interface{}) { | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 	// If e was marked as unimplemented, anything could happen. Ignore. | 
					
						
							|  |  |  | 	if e.log && !e.unimplemented { | 
					
						
							|  |  |  | 		fmt.Printf(msg, args...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Fatal reports a compiler error and exits. | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | func (e *ssaExport) Fatalf(msg string, args ...interface{}) { | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 	// If e was marked as unimplemented, anything could happen. Ignore. | 
					
						
							|  |  |  | 	if !e.unimplemented { | 
					
						
							|  |  |  | 		Fatal(msg, args...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Unimplemented reports that the function cannot be compiled. | 
					
						
							|  |  |  | // It will be removed once SSA work is complete. | 
					
						
							| 
									
										
										
										
											2015-06-24 14:03:39 -07:00
										 |  |  | func (e *ssaExport) Unimplementedf(msg string, args ...interface{}) { | 
					
						
							| 
									
										
										
										
											2015-06-12 11:01:13 -07:00
										 |  |  | 	const alwaysLog = false // enable to calculate top unimplemented features | 
					
						
							|  |  |  | 	if !e.unimplemented && (e.log || alwaysLog) { | 
					
						
							|  |  |  | 		// first implementation failure, print explanation | 
					
						
							|  |  |  | 		fmt.Printf("SSA unimplemented: "+msg+"\n", args...) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	e.unimplemented = true | 
					
						
							|  |  |  | } |