mirror of
				https://github.com/golang/go.git
				synced 2025-10-31 08:40:55 +00:00 
			
		
		
		
	cmd/compile: simplify eq and hash function generation
Passes toolstash -cmp. Change-Id: Ie4675e6f713c3bbb90556f5347cbd7268a9c1a5d Reviewed-on: https://go-review.googlesource.com/20357 Run-TryBot: Matthew Dempsky <mdempsky@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
		
							parent
							
								
									e28a890d5e
								
							
						
					
					
						commit
						199cc194ac
					
				
					 1 changed files with 82 additions and 108 deletions
				
			
		|  | @ -144,18 +144,16 @@ func algtype1(t *Type, bad **Type) int { | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		ret := AMEM | 		ret := AMEM | ||||||
| 		var a int | 		for f := t.Type; f != nil; f = f.Down { | ||||||
| 		for t1 := t.Type; t1 != nil; t1 = t1.Down { |  | ||||||
| 			// All fields must be comparable. | 			// All fields must be comparable. | ||||||
| 			a = algtype1(t1.Type, bad) | 			a := algtype1(f.Type, bad) | ||||||
| 
 |  | ||||||
| 			if a == ANOEQ { | 			if a == ANOEQ { | ||||||
| 				return ANOEQ | 				return ANOEQ | ||||||
| 			} | 			} | ||||||
| 
 | 
 | ||||||
| 			// Blank fields, padded fields, fields with non-memory | 			// Blank fields, padded fields, fields with non-memory | ||||||
| 			// equality need special compare. | 			// equality need special compare. | ||||||
| 			if a != AMEM || isblanksym(t1.Sym) || ispaddedfield(t1, t.Width) { | 			if a != AMEM || isblanksym(f.Sym) || ispaddedfield(t, f) { | ||||||
| 				ret = -1 | 				ret = -1 | ||||||
| 				continue | 				continue | ||||||
| 			} | 			} | ||||||
|  | @ -236,58 +234,45 @@ func genhash(sym *Sym, t *Type) { | ||||||
| 
 | 
 | ||||||
| 		fn.Nbody.Append(n) | 		fn.Nbody.Append(n) | ||||||
| 
 | 
 | ||||||
|  | 	case TSTRUCT: | ||||||
| 		// Walk the struct using memhash for runs of AMEM | 		// Walk the struct using memhash for runs of AMEM | ||||||
| 		// and calling specific hash functions for the others. | 		// and calling specific hash functions for the others. | ||||||
| 	case TSTRUCT: | 		for f := t.Type; f != nil; { | ||||||
| 		var call *Node | 			// Skip blank fields. | ||||||
| 		var nx *Node | 			if isblanksym(f.Sym) { | ||||||
| 		var na *Node | 				f = f.Down | ||||||
| 		var hashel *Node | 				continue | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 		t1 := t.Type | 			// Hash non-memory fields with appropriate hash function. | ||||||
| 		for { | 			if algtype1(f.Type, nil) != AMEM { | ||||||
| 			first, size, next := memrun(t, t1) | 				hashel := hashfor(f.Type) | ||||||
| 			t1 = next | 				call := Nod(OCALL, hashel, nil) | ||||||
|  | 				nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages? | ||||||
|  | 				na := Nod(OADDR, nx, nil) | ||||||
|  | 				na.Etype = 1 // no escape to heap | ||||||
|  | 				appendNodeSeqNode(&call.List, na) | ||||||
|  | 				appendNodeSeqNode(&call.List, nh) | ||||||
|  | 				fn.Nbody.Append(Nod(OAS, nh, call)) | ||||||
|  | 				f = f.Down | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			// Run memhash for fields up to this one. | 			// Otherwise, hash a maximal length run of raw memory. | ||||||
| 			if first != nil { | 			size, next := memrun(t, f) | ||||||
| 				hashel = hashmem(first.Type) |  | ||||||
| 
 | 
 | ||||||
| 			// h = hashel(&p.first, size, h) | 			// h = hashel(&p.first, size, h) | ||||||
| 				call = Nod(OCALL, hashel, nil) | 			hashel := hashmem(f.Type) | ||||||
| 
 | 			call := Nod(OCALL, hashel, nil) | ||||||
| 				nx = Nod(OXDOT, np, newname(first.Sym)) // TODO: fields from other packages? | 			nx := Nod(OXDOT, np, newname(f.Sym)) // TODO: fields from other packages? | ||||||
| 				na = Nod(OADDR, nx, nil) | 			na := Nod(OADDR, nx, nil) | ||||||
| 			na.Etype = 1 // no escape to heap | 			na.Etype = 1 // no escape to heap | ||||||
| 			appendNodeSeqNode(&call.List, na) | 			appendNodeSeqNode(&call.List, na) | ||||||
| 			appendNodeSeqNode(&call.List, nh) | 			appendNodeSeqNode(&call.List, nh) | ||||||
| 			appendNodeSeqNode(&call.List, Nodintconst(size)) | 			appendNodeSeqNode(&call.List, Nodintconst(size)) | ||||||
| 			fn.Nbody.Append(Nod(OAS, nh, call)) | 			fn.Nbody.Append(Nod(OAS, nh, call)) | ||||||
| 			} |  | ||||||
| 
 | 
 | ||||||
| 			if t1 == nil { | 			f = next | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 			if isblanksym(t1.Sym) { |  | ||||||
| 				t1 = t1.Down |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			if algtype1(t1.Type, nil) == AMEM { |  | ||||||
| 				// Our memory run might have been stopped by padding or a blank field. |  | ||||||
| 				// If the next field is memory-ish, it could be the start of a new run. |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			hashel = hashfor(t1.Type) |  | ||||||
| 			call = Nod(OCALL, hashel, nil) |  | ||||||
| 			nx = Nod(OXDOT, np, newname(t1.Sym)) // TODO: fields from other packages? |  | ||||||
| 			na = Nod(OADDR, nx, nil) |  | ||||||
| 			na.Etype = 1 // no escape to heap |  | ||||||
| 			appendNodeSeqNode(&call.List, na) |  | ||||||
| 			appendNodeSeqNode(&call.List, nh) |  | ||||||
| 			fn.Nbody.Append(Nod(OAS, nh, call)) |  | ||||||
| 
 |  | ||||||
| 			t1 = t1.Down |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | @ -438,51 +423,41 @@ func geneq(sym *Sym, t *Type) { | ||||||
| 		appendNodeSeqNode(&ret.List, Nodbool(true)) | 		appendNodeSeqNode(&ret.List, Nodbool(true)) | ||||||
| 		fn.Nbody.Append(ret) | 		fn.Nbody.Append(ret) | ||||||
| 
 | 
 | ||||||
| 	// Walk the struct using memequal for runs of AMEM |  | ||||||
| 	// and calling specific equality tests for the others. |  | ||||||
| 	// Skip blank-named fields. |  | ||||||
| 	case TSTRUCT: | 	case TSTRUCT: | ||||||
| 		var conjuncts []*Node | 		var conjuncts []*Node | ||||||
| 
 | 
 | ||||||
| 		t1 := t.Type | 		// Walk the struct using memequal for runs of AMEM | ||||||
| 		for { | 		// and calling specific equality tests for the others. | ||||||
| 			first, size, next := memrun(t, t1) | 		for f := t.Type; f != nil; { | ||||||
| 			t1 = next | 			// Skip blank-named fields. | ||||||
|  | 			if isblanksym(f.Sym) { | ||||||
|  | 				f = f.Down | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
| 
 | 
 | ||||||
| 			// Run memequal for fields up to this one. | 			// Compare non-memory fields with field equality. | ||||||
|  | 			if algtype1(f.Type, nil) != AMEM { | ||||||
|  | 				conjuncts = append(conjuncts, eqfield(np, nq, newname(f.Sym))) | ||||||
|  | 				f = f.Down | ||||||
|  | 				continue | ||||||
|  | 			} | ||||||
|  | 
 | ||||||
|  | 			// Find maximal length run of memory-only fields. | ||||||
|  | 			size, next := memrun(t, f) | ||||||
|  | 
 | ||||||
|  | 			// Run memequal on fields from f to next. | ||||||
| 			// TODO(rsc): All the calls to newname are wrong for | 			// TODO(rsc): All the calls to newname are wrong for | ||||||
| 			// cross-package unexported fields. | 			// cross-package unexported fields. | ||||||
| 			if first != nil { | 			if f.Down == next { | ||||||
| 				if first.Down == t1 { | 				conjuncts = append(conjuncts, eqfield(np, nq, newname(f.Sym))) | ||||||
| 					conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym))) | 			} else if f.Down.Down == next { | ||||||
| 				} else if first.Down.Down == t1 { | 				conjuncts = append(conjuncts, eqfield(np, nq, newname(f.Sym))) | ||||||
| 					conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym))) | 				conjuncts = append(conjuncts, eqfield(np, nq, newname(f.Down.Sym))) | ||||||
| 					first = first.Down |  | ||||||
| 					if !isblanksym(first.Sym) { |  | ||||||
| 						conjuncts = append(conjuncts, eqfield(np, nq, newname(first.Sym))) |  | ||||||
| 					} |  | ||||||
| 			} else { | 			} else { | ||||||
| 				// More than two fields: use memequal. | 				// More than two fields: use memequal. | ||||||
| 					conjuncts = append(conjuncts, eqmem(np, nq, newname(first.Sym), size)) | 				conjuncts = append(conjuncts, eqmem(np, nq, newname(f.Sym), size)) | ||||||
| 			} | 			} | ||||||
| 			} | 			f = next | ||||||
| 
 |  | ||||||
| 			if t1 == nil { |  | ||||||
| 				break |  | ||||||
| 			} |  | ||||||
| 			if isblanksym(t1.Sym) { |  | ||||||
| 				t1 = t1.Down |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 			if algtype1(t1.Type, nil) == AMEM { |  | ||||||
| 				// Our memory run might have been stopped by padding or a blank field. |  | ||||||
| 				// If the next field is memory-ish, it could be the start of a new run. |  | ||||||
| 				continue |  | ||||||
| 			} |  | ||||||
| 
 |  | ||||||
| 			// Check this field, which is not just memory. |  | ||||||
| 			conjuncts = append(conjuncts, eqfield(np, nq, newname(t1.Sym))) |  | ||||||
| 			t1 = t1.Down |  | ||||||
| 		} | 		} | ||||||
| 
 | 
 | ||||||
| 		var and *Node | 		var and *Node | ||||||
|  | @ -584,43 +559,42 @@ func eqmemfunc(size int64, type_ *Type, needsize *int) *Node { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // memrun finds runs of struct fields for which memory-only algs are appropriate. | // memrun finds runs of struct fields for which memory-only algs are appropriate. | ||||||
| // t is the parent struct type, and field is the field at which to start. | // t is the parent struct type, and start is the field that starts the run. | ||||||
| // first is the first field in the memory run. |  | ||||||
| // size is the length in bytes of the memory included in the run. | // size is the length in bytes of the memory included in the run. | ||||||
| // next is the next field after the memory run. | // next is the next field after the memory run. | ||||||
| func memrun(t *Type, field *Type) (first *Type, size int64, next *Type) { | func memrun(t *Type, start *Type) (size int64, next *Type) { | ||||||
| 	var offend int64 | 	var last *Type | ||||||
|  | 	next = start | ||||||
| 	for { | 	for { | ||||||
| 		if field == nil || algtype1(field.Type, nil) != AMEM || isblanksym(field.Sym) { | 		last, next = next, next.Down | ||||||
|  | 		if next == nil { | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 		offend = field.Width + field.Type.Width | 		// Stop run after a padded field. | ||||||
| 		if first == nil { | 		if ispaddedfield(t, last) { | ||||||
| 			first = field |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// If it's a memory field but it's padded, stop here. |  | ||||||
| 		if ispaddedfield(field, t.Width) { |  | ||||||
| 			field = field.Down |  | ||||||
| 			break | 			break | ||||||
| 		} | 		} | ||||||
| 		field = field.Down | 		// Also, stop before a blank or non-memory field. | ||||||
|  | 		if isblanksym(next.Sym) || algtype1(next.Type, nil) != AMEM { | ||||||
|  | 			break | ||||||
| 		} | 		} | ||||||
| 	if first != nil { |  | ||||||
| 		size = offend - first.Width // first.Width is offset |  | ||||||
| 	} | 	} | ||||||
| 	return first, size, field | 	end := last.Width + last.Type.Width | ||||||
|  | 	return end - start.Width, next | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // ispaddedfield reports whether the given field | // ispaddedfield reports whether the given field f, assumed to be | ||||||
| // is followed by padding. For the case where t is | // a field in struct t, is followed by padding. | ||||||
| // the last field, total gives the size of the enclosing struct. | func ispaddedfield(t *Type, f *Type) bool { | ||||||
| func ispaddedfield(t *Type, total int64) bool { | 	if t.Etype != TSTRUCT { | ||||||
| 	if t.Etype != TFIELD { | 		Fatalf("ispaddedfield called non-struct %v", t) | ||||||
| 		Fatalf("ispaddedfield called non-field %v", t) |  | ||||||
| 	} | 	} | ||||||
| 	if t.Down == nil { | 	if f.Etype != TFIELD { | ||||||
| 		return t.Width+t.Type.Width != total | 		Fatalf("ispaddedfield called non-field %v", f) | ||||||
| 	} | 	} | ||||||
| 	return t.Width+t.Type.Width != t.Down.Width | 	end := t.Width | ||||||
|  | 	if f.Down != nil { | ||||||
|  | 		end = f.Down.Width | ||||||
|  | 	} | ||||||
|  | 	return f.Width+f.Type.Width != end | ||||||
| } | } | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Matthew Dempsky
						Matthew Dempsky