mirror of
				https://github.com/golang/go.git
				synced 2025-11-04 02:30:57 +00:00 
			
		
		
		
	[dev.ssa] cmd/compile: enhance SSA filtering, add OpConvert
Modified GOSSA{HASH.PKG} environment variable filters to
make it easier to make/run with all SSA for testing.
Disable attempts at SSA for architectures that are not
amd64 (avoid spurious errors/unimplementeds.)
Removed easy out for unimplemented features.
Add convert op for proper liveness in presence of uintptr
to/from unsafe.Pointer conversions.
Tweaked stack sizes to get a pass on windows;
1024 instead 768, was observed to pass at least once.
Change-Id: Ida3800afcda67d529e3b1cf48ca4a3f0fa48b2c5
Reviewed-on: https://go-review.googlesource.com/16201
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: David Chase <drchase@google.com>
			
			
This commit is contained in:
		
							parent
							
								
									3abb844108
								
							
						
					
					
						commit
						e99dd52066
					
				
					 12 changed files with 105 additions and 43 deletions
				
			
		| 
						 | 
					@ -414,7 +414,9 @@ func compile(fn *Node) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Build an SSA backend function.
 | 
						// Build an SSA backend function.
 | 
				
			||||||
	// TODO: get rid of usessa.
 | 
						// TODO: get rid of usessa.
 | 
				
			||||||
	ssafn, usessa = buildssa(Curfn)
 | 
						if Thearch.Thestring == "amd64" {
 | 
				
			||||||
 | 
							ssafn, usessa = buildssa(Curfn)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	continpc = nil
 | 
						continpc = nil
 | 
				
			||||||
	breakpc = nil
 | 
						breakpc = nil
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -24,8 +24,32 @@ import (
 | 
				
			||||||
// it will never return nil, and the bool can be removed.
 | 
					// it will never return nil, and the bool can be removed.
 | 
				
			||||||
func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
 | 
					func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
 | 
				
			||||||
	name := fn.Func.Nname.Sym.Name
 | 
						name := fn.Func.Nname.Sym.Name
 | 
				
			||||||
 | 
						gossahash := os.Getenv("GOSSAHASH")
 | 
				
			||||||
	usessa = strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
 | 
						usessa = strings.HasSuffix(name, "_ssa") || strings.Contains(name, "_ssa.") || name == os.Getenv("GOSSAFUNC")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Environment variable control of SSA CG
 | 
				
			||||||
 | 
						// 1. IF GOSSAFUNC == current function name THEN
 | 
				
			||||||
 | 
						//       compile this function with SSA and log output to ssa.html
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 2. IF GOSSAHASH == "y" or "Y" THEN
 | 
				
			||||||
 | 
						//       compile this function (and everything else) with SSA
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 3. IF GOSSAHASH == "" THEN
 | 
				
			||||||
 | 
						//       IF GOSSAPKG == current package name THEN
 | 
				
			||||||
 | 
						//          compile this function (and everything in this package) with SSA
 | 
				
			||||||
 | 
						//       ELSE
 | 
				
			||||||
 | 
						//          use the old back end for this function.
 | 
				
			||||||
 | 
						//       This is for compatibility with existing test harness and should go away.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// 4. IF GOSSAHASH is a suffix of the binary-rendered SHA1 hash of the function name THEN
 | 
				
			||||||
 | 
						//          compile this function with SSA
 | 
				
			||||||
 | 
						//       ELSE
 | 
				
			||||||
 | 
						//          compile this function with the old back end.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Plan is for 3 to be remove, and the 2) dependence on GOSSAHASH changes
 | 
				
			||||||
 | 
						// from "y"/"Y" to empty -- then SSA is default, and is disabled by setting
 | 
				
			||||||
 | 
						// GOSSAHASH to a value that is neither 0 nor 1 (e.g., "N" or "X")
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if usessa {
 | 
						if usessa {
 | 
				
			||||||
		fmt.Println("generating SSA for", name)
 | 
							fmt.Println("generating SSA for", name)
 | 
				
			||||||
		dumplist("buildssa-enter", fn.Func.Enter)
 | 
							dumplist("buildssa-enter", fn.Func.Enter)
 | 
				
			||||||
| 
						 | 
					@ -58,17 +82,6 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
	}()
 | 
						}()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// 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)
 | 
					 | 
				
			||||||
			}
 | 
					 | 
				
			||||||
		}
 | 
					 | 
				
			||||||
	}()
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// We construct SSA using an algorithm similar to
 | 
						// We construct SSA using an algorithm similar to
 | 
				
			||||||
	// Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau
 | 
						// Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau
 | 
				
			||||||
	// http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
 | 
						// http://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
 | 
				
			||||||
| 
						 | 
					@ -167,27 +180,17 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
 | 
				
			||||||
	// Main call to ssa package to compile function
 | 
						// Main call to ssa package to compile function
 | 
				
			||||||
	ssa.Compile(s.f)
 | 
						ssa.Compile(s.f)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Calculate stats about what percentage of functions SSA handles.
 | 
						if usessa || gossahash == "y" || gossahash == "Y" {
 | 
				
			||||||
	if false {
 | 
					 | 
				
			||||||
		fmt.Printf("SSA implemented: %t\n", !e.unimplemented)
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if e.unimplemented {
 | 
					 | 
				
			||||||
		return nil, false
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	// TODO: enable codegen more broadly once the codegen stabilizes
 | 
					 | 
				
			||||||
	// and runtime support is in (gc maps, write barriers, etc.)
 | 
					 | 
				
			||||||
	if usessa {
 | 
					 | 
				
			||||||
		return s.f, true
 | 
							return s.f, true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if localpkg.Name != os.Getenv("GOSSAPKG") {
 | 
						if gossahash == "" {
 | 
				
			||||||
		return s.f, false
 | 
							if localpkg.Name != os.Getenv("GOSSAPKG") {
 | 
				
			||||||
	}
 | 
								return s.f, false
 | 
				
			||||||
	if os.Getenv("GOSSAHASH") == "" {
 | 
							}
 | 
				
			||||||
		// Use everything in the package
 | 
							// Use everything in the package
 | 
				
			||||||
		return s.f, true
 | 
							return s.f, true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Check the hash of the name against a partial input hash.
 | 
						// Check the hash of the name against a partial input hash.
 | 
				
			||||||
	// We use this feature to do a binary search within a package to
 | 
						// We use this feature to do a binary search within a package to
 | 
				
			||||||
	// find a function that is incorrectly compiled.
 | 
						// find a function that is incorrectly compiled.
 | 
				
			||||||
| 
						 | 
					@ -195,10 +198,26 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) {
 | 
				
			||||||
	for _, b := range sha1.Sum([]byte(name)) {
 | 
						for _, b := range sha1.Sum([]byte(name)) {
 | 
				
			||||||
		hstr += fmt.Sprintf("%08b", b)
 | 
							hstr += fmt.Sprintf("%08b", b)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
	if strings.HasSuffix(hstr, os.Getenv("GOSSAHASH")) {
 | 
					
 | 
				
			||||||
 | 
						if strings.HasSuffix(hstr, gossahash) {
 | 
				
			||||||
		fmt.Printf("GOSSAHASH triggered %s\n", name)
 | 
							fmt.Printf("GOSSAHASH triggered %s\n", name)
 | 
				
			||||||
		return s.f, true
 | 
							return s.f, true
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						// Iteratively try additional hashes to allow tests for multi-point
 | 
				
			||||||
 | 
						// failure.
 | 
				
			||||||
 | 
						for i := 0; true; i++ {
 | 
				
			||||||
 | 
							ev := fmt.Sprintf("GOSSAHASH%d", i)
 | 
				
			||||||
 | 
							evv := os.Getenv(ev)
 | 
				
			||||||
 | 
							if evv == "" {
 | 
				
			||||||
 | 
								break
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							if strings.HasSuffix(hstr, evv) {
 | 
				
			||||||
 | 
								fmt.Printf("%s triggered %s\n", ev, name)
 | 
				
			||||||
 | 
								return s.f, true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return s.f, false
 | 
						return s.f, false
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1353,6 +1372,15 @@ func (s *state) expr(n *Node) *ssa.Value {
 | 
				
			||||||
		// Assume everything will work out, so set up our return value.
 | 
							// Assume everything will work out, so set up our return value.
 | 
				
			||||||
		// Anything interesting that happens from here is a fatal.
 | 
							// Anything interesting that happens from here is a fatal.
 | 
				
			||||||
		x := s.expr(n.Left)
 | 
							x := s.expr(n.Left)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							// Special case for not confusing GC and liveness.
 | 
				
			||||||
 | 
							// We don't want pointers accidentally classified
 | 
				
			||||||
 | 
							// as not-pointers or vice-versa because of copy
 | 
				
			||||||
 | 
							// elision.
 | 
				
			||||||
 | 
							if to.IsPtr() != from.IsPtr() {
 | 
				
			||||||
 | 
								return s.newValue1(ssa.OpConvert, to, x)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
 | 
							v := s.newValue1(ssa.OpCopy, to, x) // ensure that v has the right type
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// CONVNOP closure
 | 
							// CONVNOP closure
 | 
				
			||||||
| 
						 | 
					@ -1364,6 +1392,7 @@ func (s *state) expr(n *Node) *ssa.Value {
 | 
				
			||||||
		if from.Etype == to.Etype {
 | 
							if from.Etype == to.Etype {
 | 
				
			||||||
			return v
 | 
								return v
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		// unsafe.Pointer <--> *T
 | 
							// unsafe.Pointer <--> *T
 | 
				
			||||||
		if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
 | 
							if to.Etype == TUNSAFEPTR && from.IsPtr() || from.Etype == TUNSAFEPTR && to.IsPtr() {
 | 
				
			||||||
			return v
 | 
								return v
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -281,6 +281,9 @@
 | 
				
			||||||
(Store [2] ptr val mem) -> (MOVWstore ptr val mem)
 | 
					(Store [2] ptr val mem) -> (MOVWstore ptr val mem)
 | 
				
			||||||
(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
 | 
					(Store [1] ptr val mem) -> (MOVBstore ptr val mem)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// We want this to stick out so the to/from ptr conversion is obvious
 | 
				
			||||||
 | 
					(Convert <t> x) -> (LEAQ <t> x)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// checks
 | 
					// checks
 | 
				
			||||||
(IsNonNil p) -> (SETNE (TESTQ p p))
 | 
					(IsNonNil p) -> (SETNE (TESTQ p p))
 | 
				
			||||||
(IsInBounds idx len) -> (SETB (CMPQ idx len))
 | 
					(IsInBounds idx len) -> (SETB (CMPQ idx len))
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -237,8 +237,9 @@ var genericOps = []opData{
 | 
				
			||||||
	{name: "Sqrt"}, // sqrt(arg0), float64 only
 | 
						{name: "Sqrt"}, // sqrt(arg0), float64 only
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// Data movement
 | 
						// Data movement
 | 
				
			||||||
	{name: "Phi"},  // select an argument based on which predecessor block we came from
 | 
						{name: "Phi"},     // select an argument based on which predecessor block we came from
 | 
				
			||||||
	{name: "Copy"}, // output = arg0
 | 
						{name: "Copy"},    // output = arg0
 | 
				
			||||||
 | 
						{name: "Convert"}, // output = arg0 -- a copy that converts to/from a pointer
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// constants.  Constant values are stored in the aux field.
 | 
						// constants.  Constant values are stored in the aux field.
 | 
				
			||||||
	// booleans have a bool aux field, strings have a string aux
 | 
						// booleans have a bool aux field, strings have a string aux
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -455,6 +455,7 @@ const (
 | 
				
			||||||
	OpSqrt
 | 
						OpSqrt
 | 
				
			||||||
	OpPhi
 | 
						OpPhi
 | 
				
			||||||
	OpCopy
 | 
						OpCopy
 | 
				
			||||||
 | 
						OpConvert
 | 
				
			||||||
	OpConstBool
 | 
						OpConstBool
 | 
				
			||||||
	OpConstString
 | 
						OpConstString
 | 
				
			||||||
	OpConstNil
 | 
						OpConstNil
 | 
				
			||||||
| 
						 | 
					@ -3866,6 +3867,10 @@ var opcodeTable = [...]opInfo{
 | 
				
			||||||
		name:    "Copy",
 | 
							name:    "Copy",
 | 
				
			||||||
		generic: true,
 | 
							generic: true,
 | 
				
			||||||
	},
 | 
						},
 | 
				
			||||||
 | 
						{
 | 
				
			||||||
 | 
							name:    "Convert",
 | 
				
			||||||
 | 
							generic: true,
 | 
				
			||||||
 | 
						},
 | 
				
			||||||
	{
 | 
						{
 | 
				
			||||||
		name:    "ConstBool",
 | 
							name:    "ConstBool",
 | 
				
			||||||
		generic: true,
 | 
							generic: true,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1670,6 +1670,24 @@ func rewriteValueAMD64(v *Value, config *Config) bool {
 | 
				
			||||||
		goto endc395c0a53eeccf597e225a07b53047d1
 | 
							goto endc395c0a53eeccf597e225a07b53047d1
 | 
				
			||||||
	endc395c0a53eeccf597e225a07b53047d1:
 | 
						endc395c0a53eeccf597e225a07b53047d1:
 | 
				
			||||||
		;
 | 
							;
 | 
				
			||||||
 | 
						case OpConvert:
 | 
				
			||||||
 | 
							// match: (Convert <t> x)
 | 
				
			||||||
 | 
							// cond:
 | 
				
			||||||
 | 
							// result: (LEAQ <t> x)
 | 
				
			||||||
 | 
							{
 | 
				
			||||||
 | 
								t := v.Type
 | 
				
			||||||
 | 
								x := v.Args[0]
 | 
				
			||||||
 | 
								v.Op = OpAMD64LEAQ
 | 
				
			||||||
 | 
								v.AuxInt = 0
 | 
				
			||||||
 | 
								v.Aux = nil
 | 
				
			||||||
 | 
								v.resetArgs()
 | 
				
			||||||
 | 
								v.Type = t
 | 
				
			||||||
 | 
								v.AddArg(x)
 | 
				
			||||||
 | 
								return true
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
							goto end1cac40a6074914d6ae3d4aa039a625ed
 | 
				
			||||||
 | 
						end1cac40a6074914d6ae3d4aa039a625ed:
 | 
				
			||||||
 | 
							;
 | 
				
			||||||
	case OpCvt32Fto32:
 | 
						case OpCvt32Fto32:
 | 
				
			||||||
		// match: (Cvt32Fto32 x)
 | 
							// match: (Cvt32Fto32 x)
 | 
				
			||||||
		// cond:
 | 
							// cond:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -54,8 +54,12 @@ func tighten(f *Func) {
 | 
				
			||||||
		for _, b := range f.Blocks {
 | 
							for _, b := range f.Blocks {
 | 
				
			||||||
			for i := 0; i < len(b.Values); i++ {
 | 
								for i := 0; i < len(b.Values); i++ {
 | 
				
			||||||
				v := b.Values[i]
 | 
									v := b.Values[i]
 | 
				
			||||||
				if v.Op == OpPhi || v.Op == OpGetClosurePtr {
 | 
									if v.Op == OpPhi || v.Op == OpGetClosurePtr || v.Op == OpConvert {
 | 
				
			||||||
					// GetClosurePtr must stay in entry block
 | 
										// GetClosurePtr must stay in entry block.
 | 
				
			||||||
 | 
										// OpConvert must not float over call sites.
 | 
				
			||||||
 | 
										// TODO do we instead need a dependence edge of some sort for OpConvert?
 | 
				
			||||||
 | 
										// Would memory do the trick, or do we need something else that relates
 | 
				
			||||||
 | 
										// to safe point operations?
 | 
				
			||||||
					continue
 | 
										continue
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
				if len(v.Args) > 0 && v.Args[len(v.Args)-1].Type.IsMemory() {
 | 
									if len(v.Args) > 0 && v.Args[len(v.Args)-1].Type.IsMemory() {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										5
									
								
								src/cmd/dist/test.go
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										5
									
								
								src/cmd/dist/test.go
									
										
									
									
										vendored
									
									
								
							| 
						 | 
					@ -278,11 +278,6 @@ func (t *tester) registerStdTest(pkg string) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
// TODO: Remove when SSA codegen is used by default.
 | 
					// TODO: Remove when SSA codegen is used by default.
 | 
				
			||||||
func (t *tester) registerSSATest(pkg string) {
 | 
					func (t *tester) registerSSATest(pkg string) {
 | 
				
			||||||
	switch pkg {
 | 
					 | 
				
			||||||
	// known failures
 | 
					 | 
				
			||||||
	case "runtime":
 | 
					 | 
				
			||||||
		return
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
	t.tests = append(t.tests, distTest{
 | 
						t.tests = append(t.tests, distTest{
 | 
				
			||||||
		name:    "go_test_ssa:" + pkg,
 | 
							name:    "go_test_ssa:" + pkg,
 | 
				
			||||||
		heading: "Testing packages with SSA codegen.",
 | 
							heading: "Testing packages with SSA codegen.",
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,7 +41,7 @@ const (
 | 
				
			||||||
	STACKSYSTEM = 0
 | 
						STACKSYSTEM = 0
 | 
				
			||||||
	StackSystem = STACKSYSTEM
 | 
						StackSystem = STACKSYSTEM
 | 
				
			||||||
	StackBig    = 4096
 | 
						StackBig    = 4096
 | 
				
			||||||
	StackGuard  = 640*stackGuardMultiplier + StackSystem
 | 
						StackGuard  = 1024*stackGuardMultiplier + StackSystem
 | 
				
			||||||
	StackSmall  = 128
 | 
						StackSmall  = 128
 | 
				
			||||||
	StackLimit  = StackGuard - StackSystem - StackSmall
 | 
						StackLimit  = StackGuard - StackSystem - StackSmall
 | 
				
			||||||
)
 | 
					)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -385,6 +385,9 @@ func Dconv(p *Prog, a *Addr) string {
 | 
				
			||||||
		if a.Index != REG_NONE {
 | 
							if a.Index != REG_NONE {
 | 
				
			||||||
			str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
 | 
								str += fmt.Sprintf("(%v*%d)", Rconv(int(a.Index)), int(a.Scale))
 | 
				
			||||||
		}
 | 
							}
 | 
				
			||||||
 | 
							if p.As == ATYPE && a.Gotype != nil {
 | 
				
			||||||
 | 
								str += fmt.Sprintf("%s", a.Gotype.Name)
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	case TYPE_CONST:
 | 
						case TYPE_CONST:
 | 
				
			||||||
		if a.Reg != 0 {
 | 
							if a.Reg != 0 {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -86,7 +86,7 @@ const (
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// The stack guard is a pointer this many bytes above the
 | 
						// The stack guard is a pointer this many bytes above the
 | 
				
			||||||
	// bottom of the stack.
 | 
						// bottom of the stack.
 | 
				
			||||||
	_StackGuard = 640*stackGuardMultiplier + _StackSystem
 | 
						_StackGuard = 1024*stackGuardMultiplier + _StackSystem
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	// After a stack split check the SP is allowed to be this
 | 
						// After a stack split check the SP is allowed to be this
 | 
				
			||||||
	// many bytes below the stack guard.  This saves an instruction
 | 
						// many bytes below the stack guard.  This saves an instruction
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -9,6 +9,7 @@ package main
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import (
 | 
					import (
 | 
				
			||||||
	"bytes"
 | 
						"bytes"
 | 
				
			||||||
 | 
						"cmd/internal/obj"
 | 
				
			||||||
	"fmt"
 | 
						"fmt"
 | 
				
			||||||
	"io/ioutil"
 | 
						"io/ioutil"
 | 
				
			||||||
	"log"
 | 
						"log"
 | 
				
			||||||
| 
						 | 
					@ -285,12 +286,13 @@ TestCases:
 | 
				
			||||||
				// Instead of rewriting the test cases above, adjust
 | 
									// Instead of rewriting the test cases above, adjust
 | 
				
			||||||
				// the first stack frame to use up the extra bytes.
 | 
									// the first stack frame to use up the extra bytes.
 | 
				
			||||||
				if i == 0 {
 | 
									if i == 0 {
 | 
				
			||||||
					size += 512 - 128
 | 
										size += (obj.StackGuard - 128) - 128
 | 
				
			||||||
					// Noopt builds have a larger stackguard.
 | 
										// Noopt builds have a larger stackguard.
 | 
				
			||||||
					// See ../cmd/dist/buildruntime.go:stackGuardMultiplier
 | 
										// See ../src/cmd/dist/buildruntime.go:stackGuardMultiplier
 | 
				
			||||||
 | 
										// This increase is included in obj.StackGuard
 | 
				
			||||||
					for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
 | 
										for _, s := range strings.Split(os.Getenv("GO_GCFLAGS"), " ") {
 | 
				
			||||||
						if s == "-N" {
 | 
											if s == "-N" {
 | 
				
			||||||
							size += 640
 | 
												size += obj.StackGuard
 | 
				
			||||||
						}
 | 
											}
 | 
				
			||||||
					}
 | 
										}
 | 
				
			||||||
				}
 | 
									}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue