| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | // Copyright 2009 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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-22 09:51:12 +09:00
										 |  |  | // select | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | func typecheckselect(sel *Node) { | 
					
						
							|  |  |  | 	var ncase *Node | 
					
						
							|  |  |  | 	var n *Node | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-02 14:22:05 -05:00
										 |  |  | 	var def *Node | 
					
						
							| 
									
										
										
										
											2016-03-02 17:34:42 -08:00
										 |  |  | 	lno := setlineno(sel) | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	count := 0 | 
					
						
							| 
									
										
										
										
											2016-03-08 10:26:20 -08:00
										 |  |  | 	typechecklist(sel.Ninit.Slice(), Etop) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	for _, n1 := range sel.List.Slice() { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		count++ | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		ncase = n1 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		setlineno(ncase) | 
					
						
							|  |  |  | 		if ncase.Op != OXCASE { | 
					
						
							| 
									
										
										
										
											2016-03-07 08:23:55 -08:00
										 |  |  | 			Fatalf("typecheckselect %v", Oconv(ncase.Op, 0)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		if ncase.List.Len() == 0 { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			// default | 
					
						
							|  |  |  | 			if def != nil { | 
					
						
							|  |  |  | 				Yyerror("multiple defaults in select (first at %v)", def.Line()) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				def = ncase | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		} else if ncase.List.Len() > 1 { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			Yyerror("select cases cannot be lists") | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 			n = typecheck(ncase.List.Addr(0), Etop) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			ncase.Left = n | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			ncase.List.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			setlineno(n) | 
					
						
							|  |  |  | 			switch n.Op { | 
					
						
							|  |  |  | 			default: | 
					
						
							|  |  |  | 				Yyerror("select case must be receive, send or assign recv") | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// convert x = <-c into OSELRECV(x, <-c). | 
					
						
							|  |  |  | 			// remove implicit conversions; the eventual assignment | 
					
						
							|  |  |  | 			// will reintroduce them. | 
					
						
							|  |  |  | 			case OAS: | 
					
						
							| 
									
										
										
										
											2015-03-06 21:18:41 +11:00
										 |  |  | 				if (n.Right.Op == OCONVNOP || n.Right.Op == OCONVIFACE) && n.Right.Implicit { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 					n.Right = n.Right.Left | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if n.Right.Op != ORECV { | 
					
						
							|  |  |  | 					Yyerror("select assignment must have receive on right hand side") | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				n.Op = OSELRECV | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// convert x, ok = <-c into OSELRECV2(x, <-c) with ntest=ok | 
					
						
							|  |  |  | 			case OAS2RECV: | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 				if n.Rlist.First().Op != ORECV { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 					Yyerror("select assignment must have receive on right hand side") | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				n.Op = OSELRECV2 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 				n.Left = n.List.First() | 
					
						
							| 
									
										
										
										
											2016-03-10 10:13:42 -08:00
										 |  |  | 				n.List.Set1(n.List.Second()) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 				n.Right = n.Rlist.First() | 
					
						
							|  |  |  | 				n.Rlist.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// convert <-c into OSELRECV(N, <-c) | 
					
						
							|  |  |  | 			case ORECV: | 
					
						
							|  |  |  | 				n = Nod(OSELRECV, nil, n) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				n.Typecheck = 1 | 
					
						
							|  |  |  | 				ncase.Left = n | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			case OSEND: | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 10:26:20 -08:00
										 |  |  | 		typechecklist(ncase.Nbody.Slice(), Etop) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sel.Xoffset = int64(count) | 
					
						
							| 
									
										
										
										
											2016-03-02 17:34:42 -08:00
										 |  |  | 	lineno = lno | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func walkselect(sel *Node) { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	if sel.List.Len() == 0 && sel.Xoffset != 0 { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 		Fatalf("double walkselect") // already rewrote | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 17:34:42 -08:00
										 |  |  | 	lno := setlineno(sel) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	i := sel.List.Len() | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// optimization: zero-case select | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	var init []*Node | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	var r *Node | 
					
						
							|  |  |  | 	var n *Node | 
					
						
							|  |  |  | 	var var_ *Node | 
					
						
							|  |  |  | 	var selv *Node | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	if i == 0 { | 
					
						
							| 
									
										
										
										
											2016-03-10 10:13:42 -08:00
										 |  |  | 		sel.Nbody.Set1(mkcall("block", nil, nil)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		goto out | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// optimization: one-case select: single op. | 
					
						
							| 
									
										
										
										
											2015-10-22 09:51:12 +09:00
										 |  |  | 	// TODO(rsc): Reenable optimization once order.go can handle it. | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	// golang.org/issue/7672. | 
					
						
							|  |  |  | 	if i == 1 { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		cas := sel.List.First() | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		setlineno(cas) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		l := cas.Ninit.Slice() | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		if cas.Left != nil { // not default: | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			n := cas.Left | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			l = append(l, n.Ninit.Slice()...) | 
					
						
							|  |  |  | 			n.Ninit.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			var ch *Node | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			switch n.Op { | 
					
						
							|  |  |  | 			default: | 
					
						
							| 
									
										
										
										
											2016-03-07 08:23:55 -08:00
										 |  |  | 				Fatalf("select %v", Oconv(n.Op, 0)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// ok already | 
					
						
							|  |  |  | 			case OSEND: | 
					
						
							|  |  |  | 				ch = n.Left | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 			case OSELRECV, OSELRECV2: | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 				ch = n.Right.Left | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 				if n.Op == OSELRECV || n.List.Len() == 0 { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 					if n.Left == nil { | 
					
						
							|  |  |  | 						n = n.Right | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						n.Op = OAS | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					break | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if n.Left == nil { | 
					
						
							|  |  |  | 					typecheck(&nblank, Erv|Easgn) | 
					
						
							|  |  |  | 					n.Left = nblank | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				n.Op = OAS2 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 				n.List.Set(append([]*Node{n.Left}, n.List.Slice()...)) | 
					
						
							| 
									
										
										
										
											2016-03-10 10:13:42 -08:00
										 |  |  | 				n.Rlist.Set1(n.Right) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 				n.Right = nil | 
					
						
							|  |  |  | 				n.Left = nil | 
					
						
							|  |  |  | 				n.Typecheck = 0 | 
					
						
							|  |  |  | 				typecheck(&n, Etop) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// if ch == nil { block() }; n; | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			a := Nod(OIF, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-26 21:30:20 -04:00
										 |  |  | 			a.Left = Nod(OEQ, ch, nodnil()) | 
					
						
							| 
									
										
										
										
											2016-03-07 22:54:46 -08:00
										 |  |  | 			var ln Nodes | 
					
						
							|  |  |  | 			ln.Set(l) | 
					
						
							| 
									
										
										
										
											2016-03-10 10:13:42 -08:00
										 |  |  | 			a.Nbody.Set1(mkcall("block", nil, &ln)) | 
					
						
							| 
									
										
										
										
											2016-03-07 22:54:46 -08:00
										 |  |  | 			l = ln.Slice() | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			typecheck(&a, Etop) | 
					
						
							| 
									
										
										
										
											2016-03-04 16:13:17 -08:00
										 |  |  | 			l = append(l, a) | 
					
						
							|  |  |  | 			l = append(l, n) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-04 16:13:17 -08:00
										 |  |  | 		l = append(l, cas.Nbody.Slice()...) | 
					
						
							|  |  |  | 		sel.Nbody.Set(l) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		goto out | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// convert case value arguments to addresses. | 
					
						
							|  |  |  | 	// this rewrite is used by both the general code and the next optimization. | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 	for _, cas := range sel.List.Slice() { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		setlineno(cas) | 
					
						
							|  |  |  | 		n = cas.Left | 
					
						
							|  |  |  | 		if n == nil { | 
					
						
							|  |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		switch n.Op { | 
					
						
							|  |  |  | 		case OSEND: | 
					
						
							|  |  |  | 			n.Right = Nod(OADDR, n.Right, nil) | 
					
						
							|  |  |  | 			typecheck(&n.Right, Erv) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 		case OSELRECV, OSELRECV2: | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			if n.Op == OSELRECV2 && n.List.Len() == 0 { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 				n.Op = OSELRECV | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if n.Op == OSELRECV2 { | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 				n.List.SetIndex(0, Nod(OADDR, n.List.First(), nil)) | 
					
						
							|  |  |  | 				typecheck(n.List.Addr(0), Erv) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if n.Left == nil { | 
					
						
							|  |  |  | 				n.Left = nodnil() | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				n.Left = Nod(OADDR, n.Left, nil) | 
					
						
							|  |  |  | 				typecheck(&n.Left, Erv) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// optimization: two-case select but one is default: single non-blocking op. | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	if i == 2 && (sel.List.First().Left == nil || sel.List.Second().Left == nil) { | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 		var cas *Node | 
					
						
							|  |  |  | 		var dflt *Node | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		if sel.List.First().Left == nil { | 
					
						
							|  |  |  | 			cas = sel.List.Second() | 
					
						
							|  |  |  | 			dflt = sel.List.First() | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			dflt = sel.List.Second() | 
					
						
							| 
									
										
										
										
											2016-03-09 20:29:21 -08:00
										 |  |  | 			cas = sel.List.First() | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 		n := cas.Left | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		setlineno(n) | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 		r := Nod(OIF, nil, nil) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		r.Ninit.Set(cas.Ninit.Slice()) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		switch n.Op { | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2016-03-07 08:23:55 -08:00
										 |  |  | 			Fatalf("select %v", Oconv(n.Op, 0)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// if selectnbsend(c, v) { body } else { default body } | 
					
						
							|  |  |  | 		case OSEND: | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			ch := n.Left | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-26 21:30:20 -04:00
										 |  |  | 			r.Left = mkcall1(chanfn("selectnbsend", 2, ch.Type), Types[TBOOL], &r.Ninit, typename(ch.Type), ch, n.Right) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// if c != nil && selectnbrecv(&v, c) { body } else { default body } | 
					
						
							|  |  |  | 		case OSELRECV: | 
					
						
							|  |  |  | 			r = Nod(OIF, nil, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			r.Ninit.Set(cas.Ninit.Slice()) | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			ch := n.Right.Left | 
					
						
							| 
									
										
										
										
											2015-05-26 21:30:20 -04:00
										 |  |  | 			r.Left = mkcall1(chanfn("selectnbrecv", 2, ch.Type), Types[TBOOL], &r.Ninit, typename(ch.Type), n.Left, ch) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// if c != nil && selectnbrecv2(&v, c) { body } else { default body } | 
					
						
							|  |  |  | 		case OSELRECV2: | 
					
						
							|  |  |  | 			r = Nod(OIF, nil, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			r.Ninit.Set(cas.Ninit.Slice()) | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			ch := n.Right.Left | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			r.Left = mkcall1(chanfn("selectnbrecv2", 2, ch.Type), Types[TBOOL], &r.Ninit, typename(ch.Type), n.Left, n.List.First(), ch) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-26 21:30:20 -04:00
										 |  |  | 		typecheck(&r.Left, Erv) | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 		r.Nbody.Set(cas.Nbody.Slice()) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		r.Rlist.Set(append(dflt.Ninit.Slice(), dflt.Nbody.Slice()...)) | 
					
						
							| 
									
										
										
										
											2016-03-10 10:13:42 -08:00
										 |  |  | 		sel.Nbody.Set1(r) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		goto out | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	init = sel.Ninit.Slice() | 
					
						
							|  |  |  | 	sel.Ninit.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// generate sel-struct | 
					
						
							|  |  |  | 	setlineno(sel) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	selv = temp(selecttype(int32(sel.Xoffset))) | 
					
						
							|  |  |  | 	r = Nod(OAS, selv, nil) | 
					
						
							|  |  |  | 	typecheck(&r, Etop) | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	init = append(init, r) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	var_ = conv(conv(Nod(OADDR, selv, nil), Types[TUNSAFEPTR]), Ptrto(Types[TUINT8])) | 
					
						
							|  |  |  | 	r = mkcall("newselect", nil, nil, var_, Nodintconst(selv.Type.Width), Nodintconst(sel.Xoffset)) | 
					
						
							|  |  |  | 	typecheck(&r, Etop) | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	init = append(init, r) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	// register cases | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 	for _, cas := range sel.List.Slice() { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		setlineno(cas) | 
					
						
							|  |  |  | 		n = cas.Left | 
					
						
							|  |  |  | 		r = Nod(OIF, nil, nil) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		r.Ninit.Set(cas.Ninit.Slice()) | 
					
						
							|  |  |  | 		cas.Ninit.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		if n != nil { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			r.Ninit.AppendNodes(&n.Ninit) | 
					
						
							|  |  |  | 			n.Ninit.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if n == nil { | 
					
						
							|  |  |  | 			// selectdefault(sel *byte); | 
					
						
							| 
									
										
										
										
											2015-05-26 21:30:20 -04:00
										 |  |  | 			r.Left = mkcall("selectdefault", Types[TBOOL], &r.Ninit, var_) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			switch n.Op { | 
					
						
							|  |  |  | 			default: | 
					
						
							| 
									
										
										
										
											2016-03-07 08:23:55 -08:00
										 |  |  | 				Fatalf("select %v", Oconv(n.Op, 0)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// selectsend(sel *byte, hchan *chan any, elem *any) (selected bool); | 
					
						
							|  |  |  | 			case OSEND: | 
					
						
							| 
									
										
										
										
											2015-05-26 21:30:20 -04:00
										 |  |  | 				r.Left = mkcall1(chanfn("selectsend", 2, n.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Left, n.Right) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// selectrecv(sel *byte, hchan *chan any, elem *any) (selected bool); | 
					
						
							|  |  |  | 			case OSELRECV: | 
					
						
							| 
									
										
										
										
											2015-05-26 21:30:20 -04:00
										 |  |  | 				r.Left = mkcall1(chanfn("selectrecv", 2, n.Right.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Right.Left, n.Left) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// selectrecv2(sel *byte, hchan *chan any, elem *any, received *bool) (selected bool); | 
					
						
							|  |  |  | 			case OSELRECV2: | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 				r.Left = mkcall1(chanfn("selectrecv2", 2, n.Right.Left.Type), Types[TBOOL], &r.Ninit, var_, n.Right.Left, n.Left, n.List.First()) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// selv is no longer alive after use. | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 		r.Nbody.Append(Nod(OVARKILL, selv, nil)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-07 22:54:46 -08:00
										 |  |  | 		r.Nbody.AppendNodes(&cas.Nbody) | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 		r.Nbody.Append(Nod(OBREAK, nil, nil)) | 
					
						
							|  |  |  | 		init = append(init, r) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// run the select | 
					
						
							|  |  |  | 	setlineno(sel) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	init = append(init, mkcall("selectgo", nil, nil, var_)) | 
					
						
							|  |  |  | 	sel.Nbody.Set(init) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | out: | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	sel.List.Set(nil) | 
					
						
							| 
									
										
										
										
											2016-03-07 22:54:46 -08:00
										 |  |  | 	walkstmtlist(sel.Nbody.Slice()) | 
					
						
							| 
									
										
										
										
											2016-03-02 17:34:42 -08:00
										 |  |  | 	lineno = lno | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-23 07:46:01 +00:00
										 |  |  | // Keep in sync with src/runtime/runtime2.go and src/runtime/select.go. | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | func selecttype(size int32) *Type { | 
					
						
							| 
									
										
										
										
											2016-02-23 07:46:01 +00:00
										 |  |  | 	// TODO(dvyukov): it's possible to generate SudoG and Scase only once | 
					
						
							|  |  |  | 	// and then cache; and also cache Select per size. | 
					
						
							|  |  |  | 	sudog := Nod(OTSTRUCT, nil, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("g")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							|  |  |  | 	sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("selectdone")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							|  |  |  | 	sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("next")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							|  |  |  | 	sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("prev")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							|  |  |  | 	sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							|  |  |  | 	sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64]))) | 
					
						
							|  |  |  | 	sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("nrelease")), typenod(Types[TINT32]))) | 
					
						
							|  |  |  | 	sudog.List.Append(Nod(ODCLFIELD, newname(Lookup("waitlink")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							| 
									
										
										
										
											2016-02-23 07:46:01 +00:00
										 |  |  | 	typecheck(&sudog, Etype) | 
					
						
							|  |  |  | 	sudog.Type.Noalg = true | 
					
						
							|  |  |  | 	sudog.Type.Local = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	scase := Nod(OTSTRUCT, nil, nil) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("elem")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							|  |  |  | 	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("chan")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							|  |  |  | 	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("pc")), typenod(Types[TUINTPTR]))) | 
					
						
							|  |  |  | 	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("kind")), typenod(Types[TUINT16]))) | 
					
						
							|  |  |  | 	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("so")), typenod(Types[TUINT16]))) | 
					
						
							|  |  |  | 	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("receivedp")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							|  |  |  | 	scase.List.Append(Nod(ODCLFIELD, newname(Lookup("releasetime")), typenod(Types[TUINT64]))) | 
					
						
							| 
									
										
										
										
											2016-02-23 07:46:01 +00:00
										 |  |  | 	typecheck(&scase, Etype) | 
					
						
							|  |  |  | 	scase.Type.Noalg = true | 
					
						
							|  |  |  | 	scase.Type.Local = true | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	sel := Nod(OTSTRUCT, nil, nil) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("tcase")), typenod(Types[TUINT16]))) | 
					
						
							|  |  |  | 	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("ncase")), typenod(Types[TUINT16]))) | 
					
						
							|  |  |  | 	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("pollorder")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							|  |  |  | 	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("lockorder")), typenod(Ptrto(Types[TUINT8])))) | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	arr := Nod(OTARRAY, Nodintconst(int64(size)), scase) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("scase")), arr)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	arr = Nod(OTARRAY, Nodintconst(int64(size)), typenod(Ptrto(Types[TUINT8]))) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("lockorderarr")), arr)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	arr = Nod(OTARRAY, Nodintconst(int64(size)), typenod(Types[TUINT16])) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	sel.List.Append(Nod(ODCLFIELD, newname(Lookup("pollorderarr")), arr)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	typecheck(&sel, Etype) | 
					
						
							| 
									
										
										
										
											2015-09-08 03:51:30 +02:00
										 |  |  | 	sel.Type.Noalg = true | 
					
						
							| 
									
										
										
										
											2015-03-10 09:58:01 +11:00
										 |  |  | 	sel.Type.Local = true | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return sel.Type | 
					
						
							|  |  |  | } |