2015-03-23 17:02:11 -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.
|
|
|
|
|
|
2016-04-05 15:11:08 +10:00
|
|
|
// +build gen
|
|
|
|
|
|
2015-03-23 17:02:11 -07:00
|
|
|
// This program generates Go code that applies rewrite rules to a Value.
|
|
|
|
|
// The generated code implements a function of type func (v *Value) bool
|
2018-11-02 15:18:43 +00:00
|
|
|
// which reports whether if did something.
|
2015-03-23 17:02:11 -07:00
|
|
|
// Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
|
|
|
|
|
|
|
|
|
|
package main
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
"bufio"
|
|
|
|
|
"bytes"
|
2015-08-12 15:39:16 -07:00
|
|
|
"flag"
|
2015-03-23 17:02:11 -07:00
|
|
|
"fmt"
|
|
|
|
|
"go/format"
|
|
|
|
|
"io"
|
2015-03-26 10:49:03 -07:00
|
|
|
"io/ioutil"
|
2015-03-23 17:02:11 -07:00
|
|
|
"log"
|
|
|
|
|
"os"
|
2015-06-11 21:29:25 -07:00
|
|
|
"regexp"
|
2015-03-23 17:02:11 -07:00
|
|
|
"sort"
|
|
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// rule syntax:
|
2015-10-13 11:08:08 -07:00
|
|
|
// sexpr [&& extra conditions] -> [@block] sexpr
|
2015-03-23 17:02:11 -07:00
|
|
|
//
|
|
|
|
|
// sexpr are s-expressions (lisp-like parenthesized groupings)
|
2017-03-30 03:30:22 +00:00
|
|
|
// sexpr ::= [variable:](opcode sexpr*)
|
2015-03-23 17:02:11 -07:00
|
|
|
// | variable
|
|
|
|
|
// | <type>
|
2015-06-11 21:29:25 -07:00
|
|
|
// | [auxint]
|
|
|
|
|
// | {aux}
|
2015-03-23 17:02:11 -07:00
|
|
|
//
|
|
|
|
|
// aux ::= variable | {code}
|
|
|
|
|
// type ::= variable | {code}
|
|
|
|
|
// variable ::= some token
|
2017-03-30 03:30:22 +00:00
|
|
|
// opcode ::= one of the opcodes from the *Ops.go files
|
2015-03-23 17:02:11 -07:00
|
|
|
|
2016-03-01 23:21:55 +00:00
|
|
|
// extra conditions is just a chunk of Go that evaluates to a boolean. It may use
|
|
|
|
|
// variables declared in the matching sexpr. The variable "v" is predefined to be
|
2015-03-23 17:02:11 -07:00
|
|
|
// the value matched by the entire rule.
|
|
|
|
|
|
|
|
|
|
// If multiple rules match, the first one in file order is selected.
|
|
|
|
|
|
2015-08-12 15:39:16 -07:00
|
|
|
var (
|
|
|
|
|
genLog = flag.Bool("log", false, "generate code that logs; for debugging only")
|
|
|
|
|
)
|
|
|
|
|
|
2015-08-12 13:54:04 -07:00
|
|
|
type Rule struct {
|
2016-04-20 11:17:41 -07:00
|
|
|
rule string
|
|
|
|
|
loc string // file name & line number
|
2015-08-12 13:54:04 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (r Rule) String() string {
|
2016-04-20 11:17:41 -07:00
|
|
|
return fmt.Sprintf("rule %q at %s", r.rule, r.loc)
|
2015-08-12 13:54:04 -07:00
|
|
|
}
|
|
|
|
|
|
2018-02-20 02:18:54 +01:00
|
|
|
func normalizeSpaces(s string) string {
|
|
|
|
|
return strings.Join(strings.Fields(strings.TrimSpace(s)), " ")
|
|
|
|
|
}
|
|
|
|
|
|
2015-08-12 13:54:04 -07:00
|
|
|
// parse returns the matching part of the rule, additional conditions, and the result.
|
|
|
|
|
func (r Rule) parse() (match, cond, result string) {
|
|
|
|
|
s := strings.Split(r.rule, "->")
|
|
|
|
|
if len(s) != 2 {
|
|
|
|
|
log.Fatalf("no arrow in %s", r)
|
|
|
|
|
}
|
2018-02-20 02:18:54 +01:00
|
|
|
match = normalizeSpaces(s[0])
|
|
|
|
|
result = normalizeSpaces(s[1])
|
2015-08-12 13:54:04 -07:00
|
|
|
cond = ""
|
|
|
|
|
if i := strings.Index(match, "&&"); i >= 0 {
|
2018-02-20 02:18:54 +01:00
|
|
|
cond = normalizeSpaces(match[i+2:])
|
|
|
|
|
match = normalizeSpaces(match[:i])
|
2015-08-12 13:54:04 -07:00
|
|
|
}
|
|
|
|
|
return match, cond, result
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-06 16:03:33 -07:00
|
|
|
func genRules(arch arch) {
|
2015-03-23 17:02:11 -07:00
|
|
|
// Open input file.
|
2015-06-06 16:03:33 -07:00
|
|
|
text, err := os.Open(arch.name + ".rules")
|
2015-03-23 17:02:11 -07:00
|
|
|
if err != nil {
|
|
|
|
|
log.Fatalf("can't read rule file: %v", err)
|
|
|
|
|
}
|
|
|
|
|
|
2015-05-28 16:45:33 -07:00
|
|
|
// oprules contains a list of rules for each block and opcode
|
2015-08-12 13:54:04 -07:00
|
|
|
blockrules := map[string][]Rule{}
|
|
|
|
|
oprules := map[string][]Rule{}
|
2015-03-23 17:02:11 -07:00
|
|
|
|
|
|
|
|
// read rule file
|
|
|
|
|
scanner := bufio.NewScanner(text)
|
2015-06-10 10:39:57 -07:00
|
|
|
rule := ""
|
2015-08-12 13:54:04 -07:00
|
|
|
var lineno int
|
2016-04-26 14:09:58 -07:00
|
|
|
var ruleLineno int // line number of "->"
|
2015-03-23 17:02:11 -07:00
|
|
|
for scanner.Scan() {
|
2015-08-12 13:54:04 -07:00
|
|
|
lineno++
|
2015-03-23 17:02:11 -07:00
|
|
|
line := scanner.Text()
|
|
|
|
|
if i := strings.Index(line, "//"); i >= 0 {
|
2016-03-01 23:21:55 +00:00
|
|
|
// Remove comments. Note that this isn't string safe, so
|
|
|
|
|
// it will truncate lines with // inside strings. Oh well.
|
2015-03-23 17:02:11 -07:00
|
|
|
line = line[:i]
|
|
|
|
|
}
|
2015-06-10 10:39:57 -07:00
|
|
|
rule += " " + line
|
|
|
|
|
rule = strings.TrimSpace(rule)
|
|
|
|
|
if rule == "" {
|
2015-03-23 17:02:11 -07:00
|
|
|
continue
|
|
|
|
|
}
|
2015-06-10 10:39:57 -07:00
|
|
|
if !strings.Contains(rule, "->") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
2016-04-26 14:09:58 -07:00
|
|
|
if ruleLineno == 0 {
|
|
|
|
|
ruleLineno = lineno
|
|
|
|
|
}
|
2015-06-10 10:39:57 -07:00
|
|
|
if strings.HasSuffix(rule, "->") {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if unbalanced(rule) {
|
|
|
|
|
continue
|
|
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
|
2016-04-26 14:09:58 -07:00
|
|
|
loc := fmt.Sprintf("%s.rules:%d", arch.name, ruleLineno)
|
2018-01-07 13:23:59 -08:00
|
|
|
for _, rule2 := range expandOr(rule) {
|
|
|
|
|
for _, rule3 := range commute(rule2, arch) {
|
|
|
|
|
r := Rule{rule: rule3, loc: loc}
|
|
|
|
|
if rawop := strings.Split(rule3, " ")[0][1:]; isBlock(rawop, arch) {
|
|
|
|
|
blockrules[rawop] = append(blockrules[rawop], r)
|
|
|
|
|
} else {
|
|
|
|
|
// Do fancier value op matching.
|
|
|
|
|
match, _, _ := r.parse()
|
|
|
|
|
op, oparch, _, _, _, _ := parseValue(match, arch, loc)
|
|
|
|
|
opname := fmt.Sprintf("Op%s%s", oparch, op.name)
|
|
|
|
|
oprules[opname] = append(oprules[opname], r)
|
|
|
|
|
}
|
2017-03-30 03:30:22 +00:00
|
|
|
}
|
2015-05-28 16:45:33 -07:00
|
|
|
}
|
2015-06-10 10:39:57 -07:00
|
|
|
rule = ""
|
2016-04-26 14:09:58 -07:00
|
|
|
ruleLineno = 0
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
|
|
|
|
if err := scanner.Err(); err != nil {
|
|
|
|
|
log.Fatalf("scanner failed: %v\n", err)
|
|
|
|
|
}
|
2015-08-12 13:54:04 -07:00
|
|
|
if unbalanced(rule) {
|
2016-04-20 11:17:41 -07:00
|
|
|
log.Fatalf("%s.rules:%d: unbalanced rule: %v\n", arch.name, lineno, rule)
|
2015-08-12 13:54:04 -07:00
|
|
|
}
|
2015-03-23 17:02:11 -07:00
|
|
|
|
2015-10-26 21:49:31 -07:00
|
|
|
// Order all the ops.
|
|
|
|
|
var ops []string
|
|
|
|
|
for op := range oprules {
|
|
|
|
|
ops = append(ops, op)
|
|
|
|
|
}
|
|
|
|
|
sort.Strings(ops)
|
|
|
|
|
|
2015-03-23 17:02:11 -07:00
|
|
|
// Start output buffer, write header.
|
|
|
|
|
w := new(bytes.Buffer)
|
2017-04-03 17:50:34 +00:00
|
|
|
fmt.Fprintf(w, "// Code generated from gen/%s.rules; DO NOT EDIT.\n", arch.name)
|
2015-06-06 16:03:33 -07:00
|
|
|
fmt.Fprintln(w, "// generated with: cd gen; go run *.go")
|
2016-03-01 10:58:06 -08:00
|
|
|
fmt.Fprintln(w)
|
2015-03-23 17:02:11 -07:00
|
|
|
fmt.Fprintln(w, "package ssa")
|
2018-10-28 11:22:08 -07:00
|
|
|
fmt.Fprintln(w, "import \"fmt\"")
|
2015-08-28 14:24:10 -04:00
|
|
|
fmt.Fprintln(w, "import \"math\"")
|
2017-01-24 09:48:58 +00:00
|
|
|
fmt.Fprintln(w, "import \"cmd/internal/obj\"")
|
2017-04-18 12:53:25 -07:00
|
|
|
fmt.Fprintln(w, "import \"cmd/internal/objabi\"")
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
fmt.Fprintln(w, "import \"cmd/compile/internal/types\"")
|
2018-10-28 11:22:08 -07:00
|
|
|
fmt.Fprintln(w, "var _ = fmt.Println // in case not otherwise used")
|
2017-04-18 12:53:25 -07:00
|
|
|
fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used")
|
|
|
|
|
fmt.Fprintln(w, "var _ = obj.ANOP // in case not otherwise used")
|
|
|
|
|
fmt.Fprintln(w, "var _ = objabi.GOROOT // in case not otherwise used")
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
fmt.Fprintln(w, "var _ = types.TypeMem // in case not otherwise used")
|
2017-04-18 12:53:25 -07:00
|
|
|
fmt.Fprintln(w)
|
2015-08-28 14:24:10 -04:00
|
|
|
|
2017-04-20 15:47:06 -07:00
|
|
|
const chunkSize = 10
|
2015-10-26 21:49:31 -07:00
|
|
|
// Main rewrite routine is a switch on v.Op.
|
2017-03-17 10:50:20 -07:00
|
|
|
fmt.Fprintf(w, "func rewriteValue%s(v *Value) bool {\n", arch.name)
|
2015-03-23 17:02:11 -07:00
|
|
|
fmt.Fprintf(w, "switch v.Op {\n")
|
|
|
|
|
for _, op := range ops {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
fmt.Fprintf(w, "case %s:\n", op)
|
2017-04-20 15:47:06 -07:00
|
|
|
fmt.Fprint(w, "return ")
|
|
|
|
|
for chunk := 0; chunk < len(oprules[op]); chunk += chunkSize {
|
|
|
|
|
if chunk > 0 {
|
|
|
|
|
fmt.Fprint(w, " || ")
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(w, "rewriteValue%s_%s_%d(v)", arch.name, op, chunk)
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintln(w)
|
2015-10-26 21:49:31 -07:00
|
|
|
}
|
|
|
|
|
fmt.Fprintf(w, "}\n")
|
|
|
|
|
fmt.Fprintf(w, "return false\n")
|
|
|
|
|
fmt.Fprintf(w, "}\n")
|
|
|
|
|
|
2016-03-01 23:21:55 +00:00
|
|
|
// Generate a routine per op. Note that we don't make one giant routine
|
2015-10-26 21:49:31 -07:00
|
|
|
// because it is too big for some compilers.
|
|
|
|
|
for _, op := range ops {
|
2017-04-20 15:47:06 -07:00
|
|
|
for chunk := 0; chunk < len(oprules[op]); chunk += chunkSize {
|
|
|
|
|
buf := new(bytes.Buffer)
|
|
|
|
|
var canFail bool
|
|
|
|
|
endchunk := chunk + chunkSize
|
|
|
|
|
if endchunk > len(oprules[op]) {
|
|
|
|
|
endchunk = len(oprules[op])
|
2016-04-29 09:02:27 -07:00
|
|
|
}
|
2017-04-20 15:47:06 -07:00
|
|
|
for i, rule := range oprules[op][chunk:endchunk] {
|
|
|
|
|
match, cond, result := rule.parse()
|
|
|
|
|
fmt.Fprintf(buf, "// match: %s\n", match)
|
|
|
|
|
fmt.Fprintf(buf, "// cond: %s\n", cond)
|
|
|
|
|
fmt.Fprintf(buf, "// result: %s\n", result)
|
|
|
|
|
|
|
|
|
|
canFail = false
|
|
|
|
|
fmt.Fprintf(buf, "for {\n")
|
|
|
|
|
if genMatch(buf, arch, match, rule.loc) {
|
|
|
|
|
canFail = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if cond != "" {
|
|
|
|
|
fmt.Fprintf(buf, "if !(%s) {\nbreak\n}\n", cond)
|
|
|
|
|
canFail = true
|
|
|
|
|
}
|
|
|
|
|
if !canFail && i+chunk != len(oprules[op])-1 {
|
|
|
|
|
log.Fatalf("unconditional rule %s is followed by other rules", match)
|
|
|
|
|
}
|
2015-03-23 17:02:11 -07:00
|
|
|
|
2017-04-20 15:47:06 -07:00
|
|
|
genResult(buf, arch, result, rule.loc)
|
|
|
|
|
if *genLog {
|
|
|
|
|
fmt.Fprintf(buf, "logRule(\"%s\")\n", rule.loc)
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(buf, "return true\n")
|
|
|
|
|
|
|
|
|
|
fmt.Fprintf(buf, "}\n")
|
2016-04-29 09:02:27 -07:00
|
|
|
}
|
2017-04-20 15:47:06 -07:00
|
|
|
if canFail {
|
|
|
|
|
fmt.Fprintf(buf, "return false\n")
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
|
|
|
|
|
2017-04-20 15:47:06 -07:00
|
|
|
body := buf.String()
|
|
|
|
|
// Do a rough match to predict whether we need b, config, fe, and/or types.
|
|
|
|
|
// It's not precise--thus the blank assignments--but it's good enough
|
|
|
|
|
// to avoid generating needless code and doing pointless nil checks.
|
|
|
|
|
hasb := strings.Contains(body, "b.")
|
|
|
|
|
hasconfig := strings.Contains(body, "config.") || strings.Contains(body, "config)")
|
|
|
|
|
hasfe := strings.Contains(body, "fe.")
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
hastyps := strings.Contains(body, "typ.")
|
2017-04-20 15:47:06 -07:00
|
|
|
fmt.Fprintf(w, "func rewriteValue%s_%s_%d(v *Value) bool {\n", arch.name, op, chunk)
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
if hasb || hasconfig || hasfe || hastyps {
|
2017-04-20 15:47:06 -07:00
|
|
|
fmt.Fprintln(w, "b := v.Block")
|
|
|
|
|
fmt.Fprintln(w, "_ = b")
|
2015-08-12 15:39:16 -07:00
|
|
|
}
|
2017-04-20 15:47:06 -07:00
|
|
|
if hasconfig {
|
|
|
|
|
fmt.Fprintln(w, "config := b.Func.Config")
|
|
|
|
|
fmt.Fprintln(w, "_ = config")
|
|
|
|
|
}
|
|
|
|
|
if hasfe {
|
|
|
|
|
fmt.Fprintln(w, "fe := b.Func.fe")
|
|
|
|
|
fmt.Fprintln(w, "_ = fe")
|
|
|
|
|
}
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
if hastyps {
|
|
|
|
|
fmt.Fprintln(w, "typ := &b.Func.Config.Types")
|
|
|
|
|
fmt.Fprintln(w, "_ = typ")
|
2017-04-20 15:47:06 -07:00
|
|
|
}
|
|
|
|
|
fmt.Fprint(w, body)
|
|
|
|
|
fmt.Fprintf(w, "}\n")
|
2017-03-17 16:04:46 -07:00
|
|
|
}
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-01 23:21:55 +00:00
|
|
|
// Generate block rewrite function. There are only a few block types
|
2015-10-26 21:49:31 -07:00
|
|
|
// so we can make this one function with a switch.
|
2017-03-17 10:50:20 -07:00
|
|
|
fmt.Fprintf(w, "func rewriteBlock%s(b *Block) bool {\n", arch.name)
|
|
|
|
|
fmt.Fprintln(w, "config := b.Func.Config")
|
|
|
|
|
fmt.Fprintln(w, "_ = config")
|
2017-03-16 22:42:10 -07:00
|
|
|
fmt.Fprintln(w, "fe := b.Func.fe")
|
2017-03-17 10:50:20 -07:00
|
|
|
fmt.Fprintln(w, "_ = fe")
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
fmt.Fprintln(w, "typ := &config.Types")
|
|
|
|
|
fmt.Fprintln(w, "_ = typ")
|
2015-05-28 16:45:33 -07:00
|
|
|
fmt.Fprintf(w, "switch b.Kind {\n")
|
|
|
|
|
ops = nil
|
|
|
|
|
for op := range blockrules {
|
|
|
|
|
ops = append(ops, op)
|
|
|
|
|
}
|
|
|
|
|
sort.Strings(ops)
|
|
|
|
|
for _, op := range ops {
|
2015-06-06 16:03:33 -07:00
|
|
|
fmt.Fprintf(w, "case %s:\n", blockName(op, arch))
|
2015-05-28 16:45:33 -07:00
|
|
|
for _, rule := range blockrules[op] {
|
2015-08-12 13:54:04 -07:00
|
|
|
match, cond, result := rule.parse()
|
2015-05-28 16:45:33 -07:00
|
|
|
fmt.Fprintf(w, "// match: %s\n", match)
|
|
|
|
|
fmt.Fprintf(w, "// cond: %s\n", cond)
|
|
|
|
|
fmt.Fprintf(w, "// result: %s\n", result)
|
|
|
|
|
|
2016-02-04 19:52:10 +01:00
|
|
|
fmt.Fprintf(w, "for {\n")
|
2015-08-12 13:54:04 -07:00
|
|
|
|
2017-08-09 05:01:26 +00:00
|
|
|
_, _, _, aux, s := extract(match) // remove parens, then split
|
2015-05-28 16:45:33 -07:00
|
|
|
|
|
|
|
|
// check match of control value
|
2017-08-09 05:01:26 +00:00
|
|
|
if s[0] != "nil" {
|
2015-05-28 16:45:33 -07:00
|
|
|
fmt.Fprintf(w, "v := b.Control\n")
|
2017-08-09 05:01:26 +00:00
|
|
|
if strings.Contains(s[0], "(") {
|
|
|
|
|
genMatch0(w, arch, s[0], "v", map[string]struct{}{}, false, rule.loc)
|
2016-03-21 16:18:45 -07:00
|
|
|
} else {
|
2016-08-19 16:35:36 -04:00
|
|
|
fmt.Fprintf(w, "_ = v\n") // in case we don't use v
|
2017-08-09 05:01:26 +00:00
|
|
|
fmt.Fprintf(w, "%s := b.Control\n", s[0])
|
2016-03-21 16:18:45 -07:00
|
|
|
}
|
2015-05-28 16:45:33 -07:00
|
|
|
}
|
2017-08-09 05:01:26 +00:00
|
|
|
if aux != "" {
|
|
|
|
|
fmt.Fprintf(w, "%s := b.Aux\n", aux)
|
|
|
|
|
}
|
2015-05-28 16:45:33 -07:00
|
|
|
|
|
|
|
|
if cond != "" {
|
2016-02-04 19:52:10 +01:00
|
|
|
fmt.Fprintf(w, "if !(%s) {\nbreak\n}\n", cond)
|
2015-05-28 16:45:33 -07:00
|
|
|
}
|
|
|
|
|
|
2016-03-01 23:21:55 +00:00
|
|
|
// Rule matches. Generate result.
|
2017-08-09 05:01:26 +00:00
|
|
|
outop, _, _, aux, t := extract(result) // remove parens, then split
|
|
|
|
|
newsuccs := t[1:]
|
2015-05-28 16:45:33 -07:00
|
|
|
|
2015-08-28 16:45:17 -07:00
|
|
|
// Check if newsuccs is the same set as succs.
|
2017-08-09 05:01:26 +00:00
|
|
|
succs := s[1:]
|
2015-05-28 16:45:33 -07:00
|
|
|
m := map[string]bool{}
|
|
|
|
|
for _, succ := range succs {
|
|
|
|
|
if m[succ] {
|
|
|
|
|
log.Fatalf("can't have a repeat successor name %s in %s", succ, rule)
|
|
|
|
|
}
|
|
|
|
|
m[succ] = true
|
|
|
|
|
}
|
|
|
|
|
for _, succ := range newsuccs {
|
|
|
|
|
if !m[succ] {
|
|
|
|
|
log.Fatalf("unknown successor %s in %s", succ, rule)
|
|
|
|
|
}
|
|
|
|
|
delete(m, succ)
|
|
|
|
|
}
|
2015-08-28 16:45:17 -07:00
|
|
|
if len(m) != 0 {
|
|
|
|
|
log.Fatalf("unmatched successors %v in %s", m, rule)
|
|
|
|
|
}
|
2015-05-28 16:45:33 -07:00
|
|
|
|
2017-08-09 05:01:26 +00:00
|
|
|
fmt.Fprintf(w, "b.Kind = %s\n", blockName(outop, arch))
|
|
|
|
|
if t[0] == "nil" {
|
2016-03-15 20:45:50 -07:00
|
|
|
fmt.Fprintf(w, "b.SetControl(nil)\n")
|
2015-05-28 16:45:33 -07:00
|
|
|
} else {
|
2017-08-09 05:01:26 +00:00
|
|
|
fmt.Fprintf(w, "b.SetControl(%s)\n", genResult0(w, arch, t[0], new(int), false, false, rule.loc))
|
|
|
|
|
}
|
|
|
|
|
if aux != "" {
|
|
|
|
|
fmt.Fprintf(w, "b.Aux = %s\n", aux)
|
|
|
|
|
} else {
|
|
|
|
|
fmt.Fprintln(w, "b.Aux = nil")
|
2015-05-28 16:45:33 -07:00
|
|
|
}
|
2016-04-28 16:52:47 -07:00
|
|
|
|
|
|
|
|
succChanged := false
|
|
|
|
|
for i := 0; i < len(succs); i++ {
|
|
|
|
|
if succs[i] != newsuccs[i] {
|
|
|
|
|
succChanged = true
|
|
|
|
|
}
|
2015-05-28 16:45:33 -07:00
|
|
|
}
|
2016-04-28 16:52:47 -07:00
|
|
|
if succChanged {
|
|
|
|
|
if len(succs) != 2 {
|
|
|
|
|
log.Fatalf("changed successors, len!=2 in %s", rule)
|
|
|
|
|
}
|
|
|
|
|
if succs[0] != newsuccs[1] || succs[1] != newsuccs[0] {
|
|
|
|
|
log.Fatalf("can only handle swapped successors in %s", rule)
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintln(w, "b.swapSuccessors()")
|
2015-05-28 16:45:33 -07:00
|
|
|
}
|
|
|
|
|
|
2015-08-12 15:39:16 -07:00
|
|
|
if *genLog {
|
2016-05-24 15:43:25 -07:00
|
|
|
fmt.Fprintf(w, "logRule(\"%s\")\n", rule.loc)
|
2015-08-12 15:39:16 -07:00
|
|
|
}
|
2015-05-28 16:45:33 -07:00
|
|
|
fmt.Fprintf(w, "return true\n")
|
|
|
|
|
|
|
|
|
|
fmt.Fprintf(w, "}\n")
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(w, "}\n")
|
|
|
|
|
fmt.Fprintf(w, "return false\n")
|
|
|
|
|
fmt.Fprintf(w, "}\n")
|
|
|
|
|
|
2015-03-23 17:02:11 -07:00
|
|
|
// gofmt result
|
|
|
|
|
b := w.Bytes()
|
2015-08-12 15:39:16 -07:00
|
|
|
src, err := format.Source(b)
|
2015-03-23 17:02:11 -07:00
|
|
|
if err != nil {
|
2015-08-12 15:39:16 -07:00
|
|
|
fmt.Printf("%s\n", b)
|
2015-03-23 17:02:11 -07:00
|
|
|
panic(err)
|
|
|
|
|
}
|
|
|
|
|
|
2015-06-06 16:03:33 -07:00
|
|
|
// Write to file
|
2015-08-12 15:39:16 -07:00
|
|
|
err = ioutil.WriteFile("../rewrite"+arch.name+".go", src, 0666)
|
2015-03-26 10:49:03 -07:00
|
|
|
if err != nil {
|
2015-03-23 17:02:11 -07:00
|
|
|
log.Fatalf("can't write output: %v\n", err)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 15:18:43 +00:00
|
|
|
// genMatch reports whether the match can fail.
|
2016-04-29 09:02:27 -07:00
|
|
|
func genMatch(w io.Writer, arch arch, match string, loc string) bool {
|
|
|
|
|
return genMatch0(w, arch, match, "v", map[string]struct{}{}, true, loc)
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
|
|
|
|
|
2016-04-29 09:02:27 -07:00
|
|
|
func genMatch0(w io.Writer, arch arch, match, v string, m map[string]struct{}, top bool, loc string) bool {
|
2016-03-21 16:18:45 -07:00
|
|
|
if match[0] != '(' || match[len(match)-1] != ')' {
|
|
|
|
|
panic("non-compound expr in genMatch0: " + match)
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
2016-04-29 09:02:27 -07:00
|
|
|
canFail := false
|
2015-03-23 17:02:11 -07:00
|
|
|
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
op, oparch, typ, auxint, aux, args := parseValue(match, arch, loc)
|
2016-04-20 11:17:41 -07:00
|
|
|
|
2015-03-23 17:02:11 -07:00
|
|
|
// check op
|
|
|
|
|
if !top {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
fmt.Fprintf(w, "if %s.Op != Op%s%s {\nbreak\n}\n", v, oparch, op.name)
|
2016-04-29 09:02:27 -07:00
|
|
|
canFail = true
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
|
|
|
|
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
if typ != "" {
|
|
|
|
|
if !isVariable(typ) {
|
|
|
|
|
// code. We must match the results of this code.
|
|
|
|
|
fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, typ)
|
|
|
|
|
canFail = true
|
|
|
|
|
} else {
|
|
|
|
|
// variable
|
|
|
|
|
if _, ok := m[typ]; ok {
|
|
|
|
|
// must match previous variable
|
|
|
|
|
fmt.Fprintf(w, "if %s.Type != %s {\nbreak\n}\n", v, typ)
|
2016-04-29 09:02:27 -07:00
|
|
|
canFail = true
|
2015-03-23 17:02:11 -07:00
|
|
|
} else {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
m[typ] = struct{}{}
|
|
|
|
|
fmt.Fprintf(w, "%s := %s.Type\n", typ, v)
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if auxint != "" {
|
|
|
|
|
if !isVariable(auxint) {
|
|
|
|
|
// code
|
|
|
|
|
fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, auxint)
|
|
|
|
|
canFail = true
|
|
|
|
|
} else {
|
|
|
|
|
// variable
|
|
|
|
|
if _, ok := m[auxint]; ok {
|
|
|
|
|
fmt.Fprintf(w, "if %s.AuxInt != %s {\nbreak\n}\n", v, auxint)
|
2016-04-29 09:02:27 -07:00
|
|
|
canFail = true
|
2015-06-11 21:29:25 -07:00
|
|
|
} else {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
m[auxint] = struct{}{}
|
|
|
|
|
fmt.Fprintf(w, "%s := %s.AuxInt\n", auxint, v)
|
2015-06-11 21:29:25 -07:00
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if aux != "" {
|
|
|
|
|
|
|
|
|
|
if !isVariable(aux) {
|
|
|
|
|
// code
|
|
|
|
|
fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, aux)
|
|
|
|
|
canFail = true
|
|
|
|
|
} else {
|
|
|
|
|
// variable
|
|
|
|
|
if _, ok := m[aux]; ok {
|
|
|
|
|
fmt.Fprintf(w, "if %s.Aux != %s {\nbreak\n}\n", v, aux)
|
2016-04-29 09:02:27 -07:00
|
|
|
canFail = true
|
2015-03-23 17:02:11 -07:00
|
|
|
} else {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
m[aux] = struct{}{}
|
|
|
|
|
fmt.Fprintf(w, "%s := %s.Aux\n", aux, v)
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-05-15 09:40:19 -07:00
|
|
|
if n := len(args); n > 1 {
|
|
|
|
|
fmt.Fprintf(w, "_ = %s.Args[%d]\n", v, n-1) // combine some bounds checks
|
|
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
for i, arg := range args {
|
|
|
|
|
if arg == "_" {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if !strings.Contains(arg, "(") {
|
2016-03-21 16:18:45 -07:00
|
|
|
// leaf variable
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
if _, ok := m[arg]; ok {
|
2016-03-21 16:18:45 -07:00
|
|
|
// variable already has a definition. Check whether
|
|
|
|
|
// the old definition and the new definition match.
|
|
|
|
|
// For example, (add x x). Equality is just pointer equality
|
|
|
|
|
// on Values (so cse is important to do before lowering).
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
fmt.Fprintf(w, "if %s != %s.Args[%d] {\nbreak\n}\n", arg, v, i)
|
2016-04-29 09:02:27 -07:00
|
|
|
canFail = true
|
2016-03-21 16:18:45 -07:00
|
|
|
} else {
|
|
|
|
|
// remember that this variable references the given value
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
m[arg] = struct{}{}
|
|
|
|
|
fmt.Fprintf(w, "%s := %s.Args[%d]\n", arg, v, i)
|
2016-03-21 16:18:45 -07:00
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
// compound sexpr
|
|
|
|
|
var argname string
|
2017-10-05 15:49:32 +02:00
|
|
|
colon := strings.Index(arg, ":")
|
|
|
|
|
openparen := strings.Index(arg, "(")
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
if colon >= 0 && openparen >= 0 && colon < openparen {
|
|
|
|
|
// rule-specified name
|
|
|
|
|
argname = arg[:colon]
|
|
|
|
|
arg = arg[colon+1:]
|
2015-03-23 17:02:11 -07:00
|
|
|
} else {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
// autogenerated name
|
|
|
|
|
argname = fmt.Sprintf("%s_%d", v, i)
|
|
|
|
|
}
|
|
|
|
|
fmt.Fprintf(w, "%s := %s.Args[%d]\n", argname, v, i)
|
|
|
|
|
if genMatch0(w, arch, arg, argname, m, false, loc) {
|
|
|
|
|
canFail = true
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
|
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
|
2016-04-20 11:17:41 -07:00
|
|
|
if op.argLength == -1 {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
fmt.Fprintf(w, "if len(%s.Args) != %d {\nbreak\n}\n", v, len(args))
|
2016-04-29 09:02:27 -07:00
|
|
|
canFail = true
|
2016-02-09 19:46:26 +01:00
|
|
|
}
|
2016-04-29 09:02:27 -07:00
|
|
|
return canFail
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
|
|
|
|
|
2016-04-20 11:17:41 -07:00
|
|
|
func genResult(w io.Writer, arch arch, result string, loc string) {
|
2016-02-24 10:29:27 -08:00
|
|
|
move := false
|
2015-10-13 11:08:08 -07:00
|
|
|
if result[0] == '@' {
|
|
|
|
|
// parse @block directive
|
|
|
|
|
s := strings.SplitN(result[1:], " ", 2)
|
2016-02-24 10:29:27 -08:00
|
|
|
fmt.Fprintf(w, "b = %s\n", s[0])
|
2015-10-13 11:08:08 -07:00
|
|
|
result = s[1]
|
2016-02-24 10:29:27 -08:00
|
|
|
move = true
|
2015-10-13 11:08:08 -07:00
|
|
|
}
|
2016-04-20 11:17:41 -07:00
|
|
|
genResult0(w, arch, result, new(int), true, move, loc)
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
2016-04-20 11:17:41 -07:00
|
|
|
func genResult0(w io.Writer, arch arch, result string, alloc *int, top, move bool, loc string) string {
|
2016-02-28 15:51:11 -08:00
|
|
|
// TODO: when generating a constant result, use f.constVal to avoid
|
|
|
|
|
// introducing copies just to clean them up again.
|
2015-03-23 17:02:11 -07:00
|
|
|
if result[0] != '(' {
|
|
|
|
|
// variable
|
2015-05-18 16:44:20 -07:00
|
|
|
if top {
|
2015-08-05 10:33:09 -07:00
|
|
|
// It in not safe in general to move a variable between blocks
|
|
|
|
|
// (and particularly not a phi node).
|
|
|
|
|
// Introduce a copy.
|
2016-02-04 17:21:57 +01:00
|
|
|
fmt.Fprintf(w, "v.reset(OpCopy)\n")
|
2015-08-05 10:33:09 -07:00
|
|
|
fmt.Fprintf(w, "v.Type = %s.Type\n", result)
|
|
|
|
|
fmt.Fprintf(w, "v.AddArg(%s)\n", result)
|
2015-05-18 16:44:20 -07:00
|
|
|
}
|
2015-03-23 17:02:11 -07:00
|
|
|
return result
|
|
|
|
|
}
|
|
|
|
|
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
op, oparch, typ, auxint, aux, args := parseValue(result, arch, loc)
|
2016-04-20 11:17:41 -07:00
|
|
|
|
2016-02-03 20:50:12 +01:00
|
|
|
// Find the type of the variable.
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
typeOverride := typ != ""
|
|
|
|
|
if typ == "" && op.typ != "" {
|
|
|
|
|
typ = typeName(op.typ)
|
2016-02-03 20:50:12 +01:00
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
|
2015-03-23 17:02:11 -07:00
|
|
|
var v string
|
2016-02-24 10:29:27 -08:00
|
|
|
if top && !move {
|
2015-03-23 17:02:11 -07:00
|
|
|
v = "v"
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
fmt.Fprintf(w, "v.reset(Op%s%s)\n", oparch, op.name)
|
2016-02-03 20:50:12 +01:00
|
|
|
if typeOverride {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
fmt.Fprintf(w, "v.Type = %s\n", typ)
|
2016-02-03 20:50:12 +01:00
|
|
|
}
|
2015-03-23 17:02:11 -07:00
|
|
|
} else {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
if typ == "" {
|
2018-05-22 09:12:35 -07:00
|
|
|
log.Fatalf("sub-expression %s (op=Op%s%s) at %s must have a type", result, oparch, op.name, loc)
|
2016-02-03 20:50:12 +01:00
|
|
|
}
|
2015-03-23 17:02:11 -07:00
|
|
|
v = fmt.Sprintf("v%d", *alloc)
|
|
|
|
|
*alloc++
|
2016-12-07 18:14:35 -08:00
|
|
|
fmt.Fprintf(w, "%s := b.NewValue0(v.Pos, Op%s%s, %s)\n", v, oparch, op.name, typ)
|
2016-03-15 20:45:50 -07:00
|
|
|
if move && top {
|
2015-10-13 11:08:08 -07:00
|
|
|
// Rewrite original into a copy
|
2016-02-04 17:21:57 +01:00
|
|
|
fmt.Fprintf(w, "v.reset(OpCopy)\n")
|
2015-10-13 11:08:08 -07:00
|
|
|
fmt.Fprintf(w, "v.AddArg(%s)\n", v)
|
|
|
|
|
}
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
|
|
|
|
|
if auxint != "" {
|
|
|
|
|
fmt.Fprintf(w, "%s.AuxInt = %s\n", v, auxint)
|
2015-03-23 17:02:11 -07:00
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
if aux != "" {
|
|
|
|
|
fmt.Fprintf(w, "%s.Aux = %s\n", v, aux)
|
|
|
|
|
}
|
|
|
|
|
for _, arg := range args {
|
|
|
|
|
x := genResult0(w, arch, arg, alloc, false, move, loc)
|
|
|
|
|
fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
|
2016-04-20 11:17:41 -07:00
|
|
|
}
|
2016-02-03 20:50:12 +01:00
|
|
|
|
2015-03-23 17:02:11 -07:00
|
|
|
return v
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func split(s string) []string {
|
|
|
|
|
var r []string
|
|
|
|
|
|
|
|
|
|
outer:
|
|
|
|
|
for s != "" {
|
2015-05-18 16:44:20 -07:00
|
|
|
d := 0 // depth of ({[<
|
|
|
|
|
var open, close byte // opening and closing markers ({[< or )}]>
|
|
|
|
|
nonsp := false // found a non-space char so far
|
2015-03-23 17:02:11 -07:00
|
|
|
for i := 0; i < len(s); i++ {
|
2015-05-18 16:44:20 -07:00
|
|
|
switch {
|
|
|
|
|
case d == 0 && s[i] == '(':
|
|
|
|
|
open, close = '(', ')'
|
2015-03-23 17:02:11 -07:00
|
|
|
d++
|
2015-05-18 16:44:20 -07:00
|
|
|
case d == 0 && s[i] == '<':
|
|
|
|
|
open, close = '<', '>'
|
|
|
|
|
d++
|
|
|
|
|
case d == 0 && s[i] == '[':
|
|
|
|
|
open, close = '[', ']'
|
|
|
|
|
d++
|
|
|
|
|
case d == 0 && s[i] == '{':
|
|
|
|
|
open, close = '{', '}'
|
|
|
|
|
d++
|
|
|
|
|
case d == 0 && (s[i] == ' ' || s[i] == '\t'):
|
|
|
|
|
if nonsp {
|
2015-03-23 17:02:11 -07:00
|
|
|
r = append(r, strings.TrimSpace(s[:i]))
|
|
|
|
|
s = s[i:]
|
|
|
|
|
continue outer
|
|
|
|
|
}
|
2015-05-18 16:44:20 -07:00
|
|
|
case d > 0 && s[i] == open:
|
|
|
|
|
d++
|
|
|
|
|
case d > 0 && s[i] == close:
|
|
|
|
|
d--
|
2015-03-23 17:02:11 -07:00
|
|
|
default:
|
|
|
|
|
nonsp = true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if d != 0 {
|
|
|
|
|
panic("imbalanced expression: " + s)
|
|
|
|
|
}
|
|
|
|
|
if nonsp {
|
|
|
|
|
r = append(r, strings.TrimSpace(s))
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
return r
|
|
|
|
|
}
|
2015-06-06 16:03:33 -07:00
|
|
|
|
2018-11-02 15:18:43 +00:00
|
|
|
// isBlock reports whether this op is a block opcode.
|
2015-06-06 16:03:33 -07:00
|
|
|
func isBlock(name string, arch arch) bool {
|
|
|
|
|
for _, b := range genericBlocks {
|
|
|
|
|
if b.name == name {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for _, b := range arch.blocks {
|
|
|
|
|
if b.name == name {
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2017-08-09 05:01:26 +00:00
|
|
|
func extract(val string) (op string, typ string, auxint string, aux string, args []string) {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
val = val[1 : len(val)-1] // remove ()
|
|
|
|
|
|
|
|
|
|
// Split val up into regions.
|
|
|
|
|
// Split by spaces/tabs, except those contained in (), {}, [], or <>.
|
|
|
|
|
s := split(val)
|
|
|
|
|
|
|
|
|
|
// Extract restrictions and args.
|
2017-08-09 05:01:26 +00:00
|
|
|
op = s[0]
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
for _, a := range s[1:] {
|
|
|
|
|
switch a[0] {
|
|
|
|
|
case '<':
|
|
|
|
|
typ = a[1 : len(a)-1] // remove <>
|
|
|
|
|
case '[':
|
|
|
|
|
auxint = a[1 : len(a)-1] // remove []
|
|
|
|
|
case '{':
|
|
|
|
|
aux = a[1 : len(a)-1] // remove {}
|
|
|
|
|
default:
|
|
|
|
|
args = append(args, a)
|
|
|
|
|
}
|
|
|
|
|
}
|
2017-08-09 05:01:26 +00:00
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// parseValue parses a parenthesized value from a rule.
|
|
|
|
|
// The value can be from the match or the result side.
|
|
|
|
|
// It returns the op and unparsed strings for typ, auxint, and aux restrictions and for all args.
|
|
|
|
|
// oparch is the architecture that op is located in, or "" for generic.
|
|
|
|
|
func parseValue(val string, arch arch, loc string) (op opData, oparch string, typ string, auxint string, aux string, args []string) {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
// Resolve the op.
|
2017-08-09 05:01:26 +00:00
|
|
|
var s string
|
|
|
|
|
s, typ, auxint, aux, args = extract(val)
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
|
|
|
|
|
// match reports whether x is a good op to select.
|
|
|
|
|
// If strict is true, rule generation might succeed.
|
|
|
|
|
// If strict is false, rule generation has failed,
|
|
|
|
|
// but we're trying to generate a useful error.
|
|
|
|
|
// Doing strict=true then strict=false allows
|
|
|
|
|
// precise op matching while retaining good error messages.
|
|
|
|
|
match := func(x opData, strict bool, archname string) bool {
|
2017-08-09 05:01:26 +00:00
|
|
|
if x.name != s {
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
if x.argLength != -1 && int(x.argLength) != len(args) {
|
|
|
|
|
if strict {
|
|
|
|
|
return false
|
|
|
|
|
} else {
|
2017-08-09 05:01:26 +00:00
|
|
|
log.Printf("%s: op %s (%s) should have %d args, has %d", loc, s, archname, x.argLength, len(args))
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for _, x := range genericOps {
|
|
|
|
|
if match(x, true, "generic") {
|
|
|
|
|
op = x
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if arch.name != "generic" {
|
|
|
|
|
for _, x := range arch.ops {
|
|
|
|
|
if match(x, true, arch.name) {
|
|
|
|
|
if op.name != "" {
|
|
|
|
|
log.Fatalf("%s: matches for op %s found in both generic and %s", loc, op.name, arch.name)
|
|
|
|
|
}
|
|
|
|
|
op = x
|
|
|
|
|
oparch = arch.name
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if op.name == "" {
|
|
|
|
|
// Failed to find the op.
|
|
|
|
|
// Run through everything again with strict=false
|
|
|
|
|
// to generate useful diagnosic messages before failing.
|
|
|
|
|
for _, x := range genericOps {
|
|
|
|
|
match(x, false, "generic")
|
|
|
|
|
}
|
|
|
|
|
for _, x := range arch.ops {
|
|
|
|
|
match(x, false, arch.name)
|
|
|
|
|
}
|
|
|
|
|
log.Fatalf("%s: unknown op %s", loc, s)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Sanity check aux, auxint.
|
|
|
|
|
if auxint != "" {
|
|
|
|
|
switch op.aux {
|
2017-03-13 21:51:08 -04:00
|
|
|
case "Bool", "Int8", "Int16", "Int32", "Int64", "Int128", "Float32", "Float64", "SymOff", "SymValAndOff", "SymInt32", "TypSize":
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
default:
|
|
|
|
|
log.Fatalf("%s: op %s %s can't have auxint", loc, op.name, op.aux)
|
2015-06-06 16:03:33 -07:00
|
|
|
}
|
|
|
|
|
}
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
if aux != "" {
|
|
|
|
|
switch op.aux {
|
2017-08-13 22:36:47 +00:00
|
|
|
case "String", "Sym", "SymOff", "SymValAndOff", "SymInt32", "Typ", "TypSize", "CCop":
|
[dev.ssa] cmd/compile: refactor out rulegen value parsing
Previously, genMatch0 and genResult0 contained
lots of duplication: locating the op, parsing
the value, validation, etc.
Parsing and validation was mixed in with code gen.
Extract a helper, parseValue. It is responsible
for parsing the value, locating the op, and doing
shared validation.
As a bonus (and possibly as my original motivation),
make op selection pay attention to the number
of args present.
This allows arch-specific ops to share a name
with generic ops as long as there is no ambiguity.
It also detects and reports unresolved ambiguity,
unlike before, where it would simply always
pick the generic op, with no warning.
Also use parseValue when generating the top-level
op dispatch, to ensure its opinion about ops
matches genMatch0 and genResult0.
The order of statements in the generated code used
to depend on the exact rule. It is now somewhat
independent of the rule. That is the source
of some of the generated code changes in this CL.
See rewritedec64 and rewritegeneric for examples.
It is a one-time change.
The op dispatch switch and functions used to be
sorted by opname without architecture. The sort
now includes the architecture, leading to further
generated code changes.
See rewriteARM and rewriteAMD64 for examples.
Again, it is a one-time change.
There are no functional changes.
Change-Id: I22c989183ad5651741ebdc0566349c5fd6c6b23c
Reviewed-on: https://go-review.googlesource.com/24649
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
Reviewed-by: Keith Randall <khr@golang.org>
2016-07-01 11:05:29 -07:00
|
|
|
default:
|
|
|
|
|
log.Fatalf("%s: op %s %s can't have aux", loc, op.name, op.aux)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return
|
2015-06-06 16:03:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func blockName(name string, arch arch) string {
|
|
|
|
|
for _, b := range genericBlocks {
|
|
|
|
|
if b.name == name {
|
|
|
|
|
return "Block" + name
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return "Block" + arch.name + name
|
|
|
|
|
}
|
2015-06-10 10:39:57 -07:00
|
|
|
|
2015-09-01 09:16:58 -07:00
|
|
|
// typeName returns the string to use to generate a type.
|
|
|
|
|
func typeName(typ string) string {
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
if typ[0] == '(' {
|
|
|
|
|
ts := strings.Split(typ[1:len(typ)-1], ",")
|
|
|
|
|
if len(ts) != 2 {
|
|
|
|
|
panic("Tuple expect 2 arguments")
|
|
|
|
|
}
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
return "types.NewTuple(" + typeName(ts[0]) + ", " + typeName(ts[1]) + ")"
|
[dev.ssa] cmd/compile: decompose 64-bit integer on ARM
Introduce dec64 rules to (generically) decompose 64-bit integer on
32-bit architectures. 64-bit integer is composed/decomposed with
Int64Make/Hi/Lo ops, as for complex types.
The idea of dealing with Add64 is the following:
(Add64 (Int64Make xh xl) (Int64Make yh yl))
->
(Int64Make
(Add32withcarry xh yh (Select0 (Add32carry xl yl)))
(Select1 (Add32carry xl yl)))
where Add32carry returns a tuple (flags,uint32). Select0 and Select1
read the first and the second component of the tuple, respectively.
The two Add32carry will be CSE'd.
Similarly for multiplication, Mul32uhilo returns a tuple (hi, lo).
Also add support of KeepAlive, to fix build after merge.
Tests addressed_ssa.go, array_ssa.go, break_ssa.go, chan_ssa.go,
cmp_ssa.go, ctl_ssa.go, map_ssa.go, and string_ssa.go in
cmd/compile/internal/gc/testdata passed.
Progress on SSA for ARM. Still not complete.
Updates #15365.
Change-Id: I7867c76785a456312de5d8398a6b3f7ca5a4f7ec
Reviewed-on: https://go-review.googlesource.com/23213
Reviewed-by: Keith Randall <khr@golang.org>
2016-05-18 18:14:36 -04:00
|
|
|
}
|
2015-09-01 09:16:58 -07:00
|
|
|
switch typ {
|
2015-10-21 17:18:07 -07:00
|
|
|
case "Flags", "Mem", "Void", "Int128":
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
return "types.Type" + typ
|
2015-09-01 09:16:58 -07:00
|
|
|
default:
|
cmd/compile: change ssa.Type into *types.Type
When package ssa was created, Type was in package gc.
To avoid circular dependencies, we used an interface (ssa.Type)
to represent type information in SSA.
In the Go 1.9 cycle, gri extricated the Type type from package gc.
As a result, we can now use it in package ssa.
Now, instead of package types depending on package ssa,
it is the other way.
This is a more sensible dependency tree,
and helps compiler performance a bit.
Though this is a big CL, most of the changes are
mechanical and uninteresting.
Interesting bits:
* Add new singleton globals to package types for the special
SSA types Memory, Void, Invalid, Flags, and Int128.
* Add two new Types, TSSA for the special types,
and TTUPLE, for SSA tuple types.
ssa.MakeTuple is now types.NewTuple.
* Move type comparison result constants CMPlt, CMPeq, and CMPgt
to package types.
* We had picked the name "types" in our rules for the handy
list of types provided by ssa.Config. That conflicted with
the types package name, so change it to "typ".
* Update the type comparison routine to handle tuples and special
types inline.
* Teach gc/fmt.go how to print special types.
* We can now eliminate ElemTypes in favor of just Elem,
and probably also some other duplicated Type methods
designed to return ssa.Type instead of *types.Type.
* The ssa tests were using their own dummy types,
and they were not particularly careful about types in general.
Of necessity, this CL switches them to use *types.Type;
it does not make them more type-accurate.
Unfortunately, using types.Type means initializing a bit
of the types universe.
This is prime for refactoring and improvement.
This shrinks ssa.Value; it now fits in a smaller size class
on 64 bit systems. This doesn't have a giant impact,
though, since most Values are preallocated in a chunk.
name old alloc/op new alloc/op delta
Template 37.9MB ± 0% 37.7MB ± 0% -0.57% (p=0.000 n=10+8)
Unicode 28.9MB ± 0% 28.7MB ± 0% -0.52% (p=0.000 n=10+10)
GoTypes 110MB ± 0% 109MB ± 0% -0.88% (p=0.000 n=10+10)
Flate 24.7MB ± 0% 24.6MB ± 0% -0.66% (p=0.000 n=10+10)
GoParser 31.1MB ± 0% 30.9MB ± 0% -0.61% (p=0.000 n=10+9)
Reflect 73.9MB ± 0% 73.4MB ± 0% -0.62% (p=0.000 n=10+8)
Tar 25.8MB ± 0% 25.6MB ± 0% -0.77% (p=0.000 n=9+10)
XML 41.2MB ± 0% 40.9MB ± 0% -0.80% (p=0.000 n=10+10)
[Geo mean] 40.5MB 40.3MB -0.68%
name old allocs/op new allocs/op delta
Template 385k ± 0% 386k ± 0% ~ (p=0.356 n=10+9)
Unicode 343k ± 1% 344k ± 0% ~ (p=0.481 n=10+10)
GoTypes 1.16M ± 0% 1.16M ± 0% -0.16% (p=0.004 n=10+10)
Flate 238k ± 1% 238k ± 1% ~ (p=0.853 n=10+10)
GoParser 320k ± 0% 320k ± 0% ~ (p=0.720 n=10+9)
Reflect 957k ± 0% 957k ± 0% ~ (p=0.460 n=10+8)
Tar 252k ± 0% 252k ± 0% ~ (p=0.133 n=9+10)
XML 400k ± 0% 400k ± 0% ~ (p=0.796 n=10+10)
[Geo mean] 428k 428k -0.01%
Removing all the interface calls helps non-trivially with CPU, though.
name old time/op new time/op delta
Template 178ms ± 4% 173ms ± 3% -2.90% (p=0.000 n=94+96)
Unicode 85.0ms ± 4% 83.9ms ± 4% -1.23% (p=0.000 n=96+96)
GoTypes 543ms ± 3% 528ms ± 3% -2.73% (p=0.000 n=98+96)
Flate 116ms ± 3% 113ms ± 4% -2.34% (p=0.000 n=96+99)
GoParser 144ms ± 3% 140ms ± 4% -2.80% (p=0.000 n=99+97)
Reflect 344ms ± 3% 334ms ± 4% -3.02% (p=0.000 n=100+99)
Tar 106ms ± 5% 103ms ± 4% -3.30% (p=0.000 n=98+94)
XML 198ms ± 5% 192ms ± 4% -2.88% (p=0.000 n=92+95)
[Geo mean] 178ms 173ms -2.65%
name old user-time/op new user-time/op delta
Template 229ms ± 5% 224ms ± 5% -2.36% (p=0.000 n=95+99)
Unicode 107ms ± 6% 106ms ± 5% -1.13% (p=0.001 n=93+95)
GoTypes 696ms ± 4% 679ms ± 4% -2.45% (p=0.000 n=97+99)
Flate 137ms ± 4% 134ms ± 5% -2.66% (p=0.000 n=99+96)
GoParser 176ms ± 5% 172ms ± 8% -2.27% (p=0.000 n=98+100)
Reflect 430ms ± 6% 411ms ± 5% -4.46% (p=0.000 n=100+92)
Tar 128ms ±13% 123ms ±13% -4.21% (p=0.000 n=100+100)
XML 239ms ± 6% 233ms ± 6% -2.50% (p=0.000 n=95+97)
[Geo mean] 220ms 213ms -2.76%
Change-Id: I15c7d6268347f8358e75066dfdbd77db24e8d0c1
Reviewed-on: https://go-review.googlesource.com/42145
Run-TryBot: Josh Bleecher Snyder <josharian@gmail.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
2017-04-28 14:12:28 -07:00
|
|
|
return "typ." + typ
|
2015-09-01 09:16:58 -07:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2018-11-02 15:18:43 +00:00
|
|
|
// unbalanced reports whether there aren't the same number of ( and ) in the string.
|
2015-06-10 10:39:57 -07:00
|
|
|
func unbalanced(s string) bool {
|
|
|
|
|
var left, right int
|
|
|
|
|
for _, c := range s {
|
|
|
|
|
if c == '(' {
|
|
|
|
|
left++
|
|
|
|
|
}
|
|
|
|
|
if c == ')' {
|
|
|
|
|
right++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return left != right
|
|
|
|
|
}
|
2015-06-11 21:29:25 -07:00
|
|
|
|
|
|
|
|
// isVariable reports whether s is a single Go alphanumeric identifier.
|
|
|
|
|
func isVariable(s string) bool {
|
2015-08-18 10:28:58 -07:00
|
|
|
b, err := regexp.MatchString("^[A-Za-z_][A-Za-z_0-9]*$", s)
|
2015-06-11 21:29:25 -07:00
|
|
|
if err != nil {
|
|
|
|
|
panic("bad variable regexp")
|
|
|
|
|
}
|
|
|
|
|
return b
|
|
|
|
|
}
|
2017-03-30 03:30:22 +00:00
|
|
|
|
2018-01-07 13:23:59 -08:00
|
|
|
// opRegexp is a regular expression to find the opcode portion of s-expressions.
|
|
|
|
|
var opRegexp = regexp.MustCompile(`[(]\w*[(](\w+[|])+\w+[)]\w* `)
|
|
|
|
|
|
|
|
|
|
// expandOr converts a rule into multiple rules by expanding | ops.
|
|
|
|
|
func expandOr(r string) []string {
|
|
|
|
|
// Find every occurrence of |-separated things at the opcode position.
|
|
|
|
|
// They look like (MOV(B|W|L|Q|SS|SD)load
|
|
|
|
|
// Note: there might be false positives in parts of rules that are Go code
|
|
|
|
|
// (e.g. && conditions, AuxInt expressions, etc.). There are currently no
|
|
|
|
|
// such false positives, so I'm not too worried about it.
|
|
|
|
|
// Generate rules selecting one case from each |-form.
|
|
|
|
|
|
|
|
|
|
// Count width of |-forms. They must match.
|
|
|
|
|
n := 1
|
|
|
|
|
for _, s := range opRegexp.FindAllString(r, -1) {
|
|
|
|
|
c := strings.Count(s, "|") + 1
|
|
|
|
|
if c == 1 {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if n > 1 && n != c {
|
|
|
|
|
log.Fatalf("'|' count doesn't match in %s: both %d and %d\n", r, n, c)
|
|
|
|
|
}
|
|
|
|
|
n = c
|
|
|
|
|
}
|
|
|
|
|
if n == 1 {
|
|
|
|
|
// No |-form in this rule.
|
|
|
|
|
return []string{r}
|
|
|
|
|
}
|
|
|
|
|
res := make([]string, n)
|
|
|
|
|
for i := 0; i < n; i++ {
|
|
|
|
|
res[i] = opRegexp.ReplaceAllStringFunc(r, func(s string) string {
|
|
|
|
|
if strings.Count(s, "|") == 0 {
|
|
|
|
|
return s
|
|
|
|
|
}
|
|
|
|
|
s = s[1 : len(s)-1] // remove leading "(" and trailing " "
|
|
|
|
|
x, y := strings.Index(s, "("), strings.Index(s, ")")
|
|
|
|
|
return "(" + s[:x] + strings.Split(s[x+1:y], "|")[i] + s[y+1:] + " "
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
return res
|
|
|
|
|
}
|
|
|
|
|
|
2017-03-30 03:30:22 +00:00
|
|
|
// commute returns all equivalent rules to r after applying all possible
|
|
|
|
|
// argument swaps to the commutable ops in r.
|
|
|
|
|
// Potentially exponential, be careful.
|
|
|
|
|
func commute(r string, arch arch) []string {
|
|
|
|
|
match, cond, result := Rule{rule: r}.parse()
|
|
|
|
|
a := commute1(match, varCount(match), arch)
|
|
|
|
|
for i, m := range a {
|
|
|
|
|
if cond != "" {
|
|
|
|
|
m += " && " + cond
|
|
|
|
|
}
|
|
|
|
|
m += " -> " + result
|
|
|
|
|
a[i] = m
|
|
|
|
|
}
|
|
|
|
|
if len(a) == 1 && normalizeWhitespace(r) != normalizeWhitespace(a[0]) {
|
|
|
|
|
fmt.Println(normalizeWhitespace(r))
|
|
|
|
|
fmt.Println(normalizeWhitespace(a[0]))
|
|
|
|
|
panic("commute() is not the identity for noncommuting rule")
|
|
|
|
|
}
|
|
|
|
|
if false && len(a) > 1 {
|
|
|
|
|
fmt.Println(r)
|
|
|
|
|
for _, x := range a {
|
|
|
|
|
fmt.Println(" " + x)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return a
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func commute1(m string, cnt map[string]int, arch arch) []string {
|
|
|
|
|
if m[0] == '<' || m[0] == '[' || m[0] == '{' || isVariable(m) {
|
|
|
|
|
return []string{m}
|
|
|
|
|
}
|
|
|
|
|
// Split up input.
|
|
|
|
|
var prefix string
|
2017-10-05 15:49:32 +02:00
|
|
|
colon := strings.Index(m, ":")
|
2017-03-30 03:30:22 +00:00
|
|
|
if colon >= 0 && isVariable(m[:colon]) {
|
|
|
|
|
prefix = m[:colon+1]
|
|
|
|
|
m = m[colon+1:]
|
|
|
|
|
}
|
|
|
|
|
if m[0] != '(' || m[len(m)-1] != ')' {
|
|
|
|
|
panic("non-compound expr in commute1: " + m)
|
|
|
|
|
}
|
|
|
|
|
s := split(m[1 : len(m)-1])
|
|
|
|
|
op := s[0]
|
|
|
|
|
|
|
|
|
|
// Figure out if the op is commutative or not.
|
|
|
|
|
commutative := false
|
|
|
|
|
for _, x := range genericOps {
|
|
|
|
|
if op == x.name {
|
|
|
|
|
if x.commutative {
|
|
|
|
|
commutative = true
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if arch.name != "generic" {
|
|
|
|
|
for _, x := range arch.ops {
|
|
|
|
|
if op == x.name {
|
|
|
|
|
if x.commutative {
|
|
|
|
|
commutative = true
|
|
|
|
|
}
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
var idx0, idx1 int
|
|
|
|
|
if commutative {
|
|
|
|
|
// Find indexes of two args we can swap.
|
|
|
|
|
for i, arg := range s {
|
|
|
|
|
if i == 0 || arg[0] == '<' || arg[0] == '[' || arg[0] == '{' {
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if idx0 == 0 {
|
|
|
|
|
idx0 = i
|
|
|
|
|
continue
|
|
|
|
|
}
|
|
|
|
|
if idx1 == 0 {
|
|
|
|
|
idx1 = i
|
|
|
|
|
break
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if idx1 == 0 {
|
|
|
|
|
panic("couldn't find first two args of commutative op " + s[0])
|
|
|
|
|
}
|
|
|
|
|
if cnt[s[idx0]] == 1 && cnt[s[idx1]] == 1 || s[idx0] == s[idx1] && cnt[s[idx0]] == 2 {
|
2018-02-20 20:50:20 +00:00
|
|
|
// When we have (Add x y) with no other uses of x and y in the matching rule,
|
2017-03-30 03:30:22 +00:00
|
|
|
// then we can skip the commutative match (Add y x).
|
|
|
|
|
commutative = false
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Recursively commute arguments.
|
|
|
|
|
a := make([][]string, len(s))
|
|
|
|
|
for i, arg := range s {
|
|
|
|
|
a[i] = commute1(arg, cnt, arch)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Choose all possibilities from all args.
|
|
|
|
|
r := crossProduct(a)
|
|
|
|
|
|
|
|
|
|
// If commutative, do that again with its two args reversed.
|
|
|
|
|
if commutative {
|
|
|
|
|
a[idx0], a[idx1] = a[idx1], a[idx0]
|
|
|
|
|
r = append(r, crossProduct(a)...)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Construct result.
|
|
|
|
|
for i, x := range r {
|
|
|
|
|
r[i] = prefix + "(" + x + ")"
|
|
|
|
|
}
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// varCount returns a map which counts the number of occurrences of
|
|
|
|
|
// Value variables in m.
|
|
|
|
|
func varCount(m string) map[string]int {
|
|
|
|
|
cnt := map[string]int{}
|
|
|
|
|
varCount1(m, cnt)
|
|
|
|
|
return cnt
|
|
|
|
|
}
|
|
|
|
|
func varCount1(m string, cnt map[string]int) {
|
|
|
|
|
if m[0] == '<' || m[0] == '[' || m[0] == '{' {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if isVariable(m) {
|
|
|
|
|
cnt[m]++
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
// Split up input.
|
2017-10-05 15:49:32 +02:00
|
|
|
colon := strings.Index(m, ":")
|
2017-03-30 03:30:22 +00:00
|
|
|
if colon >= 0 && isVariable(m[:colon]) {
|
|
|
|
|
cnt[m[:colon]]++
|
|
|
|
|
m = m[colon+1:]
|
|
|
|
|
}
|
|
|
|
|
if m[0] != '(' || m[len(m)-1] != ')' {
|
|
|
|
|
panic("non-compound expr in commute1: " + m)
|
|
|
|
|
}
|
|
|
|
|
s := split(m[1 : len(m)-1])
|
|
|
|
|
for _, arg := range s[1:] {
|
|
|
|
|
varCount1(arg, cnt)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// crossProduct returns all possible values
|
|
|
|
|
// x[0][i] + " " + x[1][j] + " " + ... + " " + x[len(x)-1][k]
|
|
|
|
|
// for all valid values of i, j, ..., k.
|
|
|
|
|
func crossProduct(x [][]string) []string {
|
|
|
|
|
if len(x) == 1 {
|
|
|
|
|
return x[0]
|
|
|
|
|
}
|
|
|
|
|
var r []string
|
|
|
|
|
for _, tail := range crossProduct(x[1:]) {
|
|
|
|
|
for _, first := range x[0] {
|
|
|
|
|
r = append(r, first+" "+tail)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return r
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// normalizeWhitespace replaces 2+ whitespace sequences with a single space.
|
|
|
|
|
func normalizeWhitespace(x string) string {
|
|
|
|
|
x = strings.Join(strings.Fields(x), " ")
|
|
|
|
|
x = strings.Replace(x, "( ", "(", -1)
|
|
|
|
|
x = strings.Replace(x, " )", ")", -1)
|
|
|
|
|
return x
|
|
|
|
|
}
|