[dev.ssa] cmd/compile/internal/ssa: autogenerate opcodes
Revamp autogeneration. Get rid of gogenerate commands, they are more
trouble than they are worth. (If the code won't compile, gogenerate
doesn't work.)
Generate opcode enums & tables. This means we only have to specify
opcodes in one place instead of two.
Add arch prefixes to opcodes so they will be globally unique.
Change-Id: I175d0a89b701b2377bbe699f3756731b7c9f5a9f
Reviewed-on: https://go-review.googlesource.com/10812
Reviewed-by: Alan Donovan <adonovan@google.com>
diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go
index 899d69b..85d73bb 100644
--- a/src/cmd/compile/internal/ssa/block.go
+++ b/src/cmd/compile/internal/ssa/block.go
@@ -4,10 +4,7 @@
package ssa
-import (
- "fmt"
- "strings"
-)
+import "fmt"
// Block represents a basic block in the control flow graph of a function.
type Block struct {
@@ -50,29 +47,6 @@
// Call mem [nopanic, panic] (control opcode should be OpCall or OpStaticCall)
type BlockKind int32
-// block kind ranges
-const (
- blockInvalid BlockKind = 0
- blockGenericBase = 1 + 100*iota
- blockAMD64Base
- block386Base
-
- blockMax // sentinel
-)
-
-// generic block kinds
-const (
- blockGenericStart BlockKind = blockGenericBase + iota
-
- BlockExit // no successors. There should only be 1 of these.
- BlockPlain // a single successor
- BlockIf // 2 successors, if control goto Succs[0] else goto Succs[1]
- BlockCall // 2 successors, normal return and panic
- // TODO(khr): BlockPanic for the built-in panic call, has 1 edge to the exit block
-)
-
-//go:generate stringer -type=BlockKind
-
// short form print
func (b *Block) String() string {
return fmt.Sprintf("b%d", b.ID)
@@ -80,7 +54,7 @@
// long form print
func (b *Block) LongString() string {
- s := strings.TrimPrefix(b.Kind.String(), "Block")
+ s := b.Kind.String()
if b.Control != nil {
s += fmt.Sprintf(" %s", b.Control)
}
diff --git a/src/cmd/compile/internal/ssa/blockkind_string.go b/src/cmd/compile/internal/ssa/blockkind_string.go
deleted file mode 100644
index 60c820c..0000000
--- a/src/cmd/compile/internal/ssa/blockkind_string.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// generated by stringer -type=BlockKind; DO NOT EDIT
-
-package ssa
-
-import "fmt"
-
-const (
- _BlockKind_name_0 = "blockInvalid"
- _BlockKind_name_1 = "blockGenericStartBlockExitBlockPlainBlockIfBlockCall"
- _BlockKind_name_2 = "blockAMD64StartBlockEQBlockNEBlockLTBlockLEBlockGTBlockGEBlockULTBlockULEBlockUGTBlockUGE"
-)
-
-var (
- _BlockKind_index_0 = [...]uint8{0, 12}
- _BlockKind_index_1 = [...]uint8{0, 17, 26, 36, 43, 52}
- _BlockKind_index_2 = [...]uint8{0, 15, 22, 29, 36, 43, 50, 57, 65, 73, 81, 89}
-)
-
-func (i BlockKind) String() string {
- switch {
- case i == 0:
- return _BlockKind_name_0
- case 101 <= i && i <= 105:
- i -= 101
- return _BlockKind_name_1[_BlockKind_index_1[i]:_BlockKind_index_1[i+1]]
- case 201 <= i && i <= 211:
- i -= 201
- return _BlockKind_name_2[_BlockKind_index_2[i]:_BlockKind_index_2[i+1]]
- default:
- return fmt.Sprintf("BlockKind(%d)", i)
- }
-}
diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go
index 7c5e07e..db2d80a 100644
--- a/src/cmd/compile/internal/ssa/config.go
+++ b/src/cmd/compile/internal/ssa/config.go
@@ -30,12 +30,12 @@
switch arch {
case "amd64":
c.ptrSize = 8
- c.lowerBlock = lowerBlockAMD64
- c.lowerValue = lowerValueAMD64
+ c.lowerBlock = rewriteBlockAMD64
+ c.lowerValue = rewriteValueAMD64
case "386":
c.ptrSize = 4
- c.lowerBlock = lowerBlockAMD64
- c.lowerValue = lowerValueAMD64 // TODO(khr): full 32-bit support
+ c.lowerBlock = rewriteBlockAMD64
+ c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support
default:
log.Fatalf("arch %s not implemented", arch)
}
diff --git a/src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules
similarity index 81%
rename from src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules
rename to src/cmd/compile/internal/ssa/gen/AMD64.rules
index e86e408..c4ff744 100644
--- a/src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules
+++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules
@@ -35,10 +35,10 @@
(Const <t> [val]) && is64BitInt(t) -> (MOVQconst [val])
// block rewrites
-(BlockIf (SETL cmp) yes no) -> (BlockLT cmp yes no)
-(BlockIf (SETNE cmp) yes no) -> (BlockNE cmp yes no)
-(BlockIf (SETB cmp) yes no) -> (BlockULT cmp yes no)
-(BlockIf cond yes no) && cond.Op == OpMOVBload -> (BlockNE (TESTB <TypeFlags> cond cond) yes no)
+(If (SETL cmp) yes no) -> (LT cmp yes no)
+(If (SETNE cmp) yes no) -> (NE cmp yes no)
+(If (SETB cmp) yes no) -> (ULT cmp yes no)
+(If cond yes no) && cond.Op == OpAMD64MOVBload -> (NE (TESTB <TypeFlags> cond cond) yes no)
// Rules below here apply some simple optimizations after lowering.
// TODO: Should this be a separate pass?
@@ -88,13 +88,13 @@
(ADDQconst [off] x) && off.(int64) == 0 -> (Copy x)
// Absorb InvertFlags into branches.
-(BlockLT (InvertFlags cmp) yes no) -> (BlockGT cmp yes no)
-(BlockGT (InvertFlags cmp) yes no) -> (BlockLT cmp yes no)
-(BlockLE (InvertFlags cmp) yes no) -> (BlockGE cmp yes no)
-(BlockGE (InvertFlags cmp) yes no) -> (BlockLE cmp yes no)
-(BlockULT (InvertFlags cmp) yes no) -> (BlockUGT cmp yes no)
-(BlockUGT (InvertFlags cmp) yes no) -> (BlockULT cmp yes no)
-(BlockULE (InvertFlags cmp) yes no) -> (BlockUGE cmp yes no)
-(BlockUGE (InvertFlags cmp) yes no) -> (BlockULE cmp yes no)
-(BlockEQ (InvertFlags cmp) yes no) -> (BlockEQ cmp yes no)
-(BlockNE (InvertFlags cmp) yes no) -> (BlockNE cmp yes no)
+(LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
+(GT (InvertFlags cmp) yes no) -> (LT cmp yes no)
+(LE (InvertFlags cmp) yes no) -> (GE cmp yes no)
+(GE (InvertFlags cmp) yes no) -> (LE cmp yes no)
+(ULT (InvertFlags cmp) yes no) -> (UGT cmp yes no)
+(UGT (InvertFlags cmp) yes no) -> (ULT cmp yes no)
+(ULE (InvertFlags cmp) yes no) -> (UGE cmp yes no)
+(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
+(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
+(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
new file mode 100644
index 0000000..38d1e87
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go
@@ -0,0 +1,161 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import "strings"
+
+// copied from ../../amd64/reg.go
+var regNamesAMD64 = []string{
+ ".AX",
+ ".CX",
+ ".DX",
+ ".BX",
+ ".SP",
+ ".BP",
+ ".SI",
+ ".DI",
+ ".R8",
+ ".R9",
+ ".R10",
+ ".R11",
+ ".R12",
+ ".R13",
+ ".R14",
+ ".R15",
+ ".X0",
+ ".X1",
+ ".X2",
+ ".X3",
+ ".X4",
+ ".X5",
+ ".X6",
+ ".X7",
+ ".X8",
+ ".X9",
+ ".X10",
+ ".X11",
+ ".X12",
+ ".X13",
+ ".X14",
+ ".X15",
+
+ // pseudo-registers
+ ".FP",
+ ".FLAGS",
+}
+
+func init() {
+ // Make map from reg names to reg integers.
+ if len(regNamesAMD64) > 64 {
+ panic("too many registers")
+ }
+ num := map[string]int{}
+ for i, name := range regNamesAMD64 {
+ if name[0] != '.' {
+ panic("register name " + name + " does not start with '.'")
+ }
+ num[name[1:]] = i
+ }
+ buildReg := func(s string) regMask {
+ m := regMask(0)
+ for _, r := range strings.Split(s, " ") {
+ if n, ok := num[r]; ok {
+ m |= regMask(1) << uint(n)
+ continue
+ }
+ panic("register " + r + " not found")
+ }
+ return m
+ }
+
+ gp := buildReg("AX CX DX BX BP SI DI R8 R9 R10 R11 R12 R13 R14 R15")
+ gpsp := gp | buildReg("SP FP")
+ gp01 := regInfo{[]regMask{}, 0, []regMask{gp}}
+ gp11 := regInfo{[]regMask{gpsp}, 0, []regMask{gp}}
+ gp21 := regInfo{[]regMask{gpsp, gpsp}, 0, []regMask{gp}}
+ gp21shift := regInfo{[]regMask{gpsp, buildReg("CX")}, 0, []regMask{gp}}
+ gp2flags := regInfo{[]regMask{gpsp, gpsp}, 0, []regMask{buildReg("FLAGS")}}
+ gp1flags := regInfo{[]regMask{gpsp}, 0, []regMask{buildReg("FLAGS")}}
+ gpload := regInfo{[]regMask{gpsp, 0}, 0, []regMask{gp}}
+ gploadidx := regInfo{[]regMask{gpsp, gpsp, 0}, 0, []regMask{gp}}
+ gpstore := regInfo{[]regMask{gpsp, gpsp, 0}, 0, nil}
+ gpstoreidx := regInfo{[]regMask{gpsp, gpsp, gpsp, 0}, 0, nil}
+ flagsgp := regInfo{[]regMask{buildReg("FLAGS")}, 0, []regMask{gp}}
+
+ // Suffixes encode the bit width of various instructions.
+ // Q = 64 bit, L = 32 bit, W = 16 bit, B = 8 bit
+
+ // TODO: 2-address instructions. Mark ops as needing matching input/output regs.
+ var AMD64ops = []opData{
+ {name: "ADDQ", reg: gp21}, // arg0 + arg1
+ {name: "ADDQconst", reg: gp11}, // arg0 + aux.(int64)
+ {name: "SUBQ", reg: gp21}, // arg0 - arg1
+ {name: "SUBQconst", reg: gp11}, // arg0 - aux.(int64)
+ {name: "MULQ", reg: gp21}, // arg0 * arg1
+ {name: "MULQconst", reg: gp11}, // arg0 * aux.(int64)
+ {name: "SHLQ", reg: gp21shift}, // arg0 << arg1, shift amount is mod 64
+ {name: "SHLQconst", reg: gp11}, // arg0 << aux.(int64), shift amount 0-63
+ {name: "NEGQ", reg: gp11}, // -arg0
+
+ {name: "CMPQ", reg: gp2flags}, // arg0 compare to arg1
+ {name: "CMPQconst", reg: gp1flags}, // arg0 compare to aux.(int64)
+ {name: "TESTQ", reg: gp2flags}, // (arg0 & arg1) compare to 0
+ {name: "TESTB", reg: gp2flags}, // (arg0 & arg1) compare to 0
+
+ {name: "SETEQ", reg: flagsgp}, // extract == condition from arg0
+ {name: "SETNE", reg: flagsgp}, // extract != condition from arg0
+ {name: "SETL", reg: flagsgp}, // extract signed < condition from arg0
+ {name: "SETG", reg: flagsgp}, // extract signed > condition from arg0
+ {name: "SETGE", reg: flagsgp}, // extract signed >= condition from arg0
+ {name: "SETB", reg: flagsgp}, // extract unsigned < condition from arg0
+
+ {name: "MOVQconst", reg: gp01}, // aux.(int64)
+ {name: "LEAQ", reg: gp21}, // arg0 + arg1 + aux.(int64)
+ {name: "LEAQ2", reg: gp21}, // arg0 + 2*arg1 + aux.(int64)
+ {name: "LEAQ4", reg: gp21}, // arg0 + 4*arg1 + aux.(int64)
+ {name: "LEAQ8", reg: gp21}, // arg0 + 8*arg1 + aux.(int64)
+ {name: "LEAQglobal", reg: gp01}, // no args. address of aux.(GlobalOffset)
+
+ {name: "MOVBload", reg: gpload}, // load byte from arg0+aux.(int64). arg1=mem
+ {name: "MOVBQZXload", reg: gpload}, // ditto, extend to uint64
+ {name: "MOVBQSXload", reg: gpload}, // ditto, extend to int64
+ {name: "MOVQload", reg: gpload}, // load 8 bytes from arg0+aux.(int64). arg1=mem
+ {name: "MOVQloadidx8", reg: gploadidx}, // load 8 bytes from arg0+8*arg1+aux.(int64). arg2=mem
+ {name: "MOVBstore", reg: gpstore}, // store byte in arg1 to arg0+aux.(int64). arg2=mem
+ {name: "MOVQstore", reg: gpstore}, // store 8 bytes in arg1 to arg0+aux.(int64). arg2=mem
+ {name: "MOVQstoreidx8", reg: gpstoreidx}, // store 8 bytes in arg2 to arg0+8*arg1+aux.(int64). arg3=mem
+
+ // Load/store from global. Same as the above loads, but arg0 is missing and
+ // aux is a GlobalOffset instead of an int64.
+ {name: "MOVQloadglobal"}, // Load from aux.(GlobalOffset). arg0 = memory
+ {name: "MOVQstoreglobal"}, // store arg0 to aux.(GlobalOffset). arg1=memory, returns memory.
+
+ {name: "REPMOVSB", reg: regInfo{[]regMask{buildReg("DI"), buildReg("SI"), buildReg("CX")}, buildReg("DI SI CX"), nil}}, // move arg2 bytes from arg1 to arg0. arg3=mem, returns memory
+
+ {name: "ADDL", reg: gp21}, // arg0+arg1
+
+ // (InvertFlags (CMPQ a b)) == (CMPQ b a)
+ // So if we want (SETL (CMPQ a b)) but we can't do that because a is a constant,
+ // then we do (SETL (InvertFlags (CMPQ b a))) instead.
+ // Rewrites will convert this to (SETG (CMPQ b a)).
+ // InvertFlags is a pseudo-op which can't appear in assembly output.
+ {name: "InvertFlags"}, // reverse direction of arg0
+ }
+
+ var AMD64blocks = []blockData{
+ {name: "EQ"},
+ {name: "NE"},
+ {name: "LT"},
+ {name: "LE"},
+ {name: "GT"},
+ {name: "GE"},
+ {name: "ULT"},
+ {name: "ULE"},
+ {name: "UGT"},
+ {name: "UGE"},
+ }
+
+ archs = append(archs, arch{"AMD64", AMD64ops, AMD64blocks})
+}
diff --git a/src/cmd/compile/internal/ssa/gen/README b/src/cmd/compile/internal/ssa/gen/README
new file mode 100644
index 0000000..6731b97
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/README
@@ -0,0 +1,7 @@
+// 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.
+
+This package generates opcode tables, rewrite rules, etc. for the ssa compiler.
+Run it with:
+ go run *.go
diff --git a/src/cmd/compile/internal/ssa/rulegen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
similarity index 94%
rename from src/cmd/compile/internal/ssa/rulegen/generic.rules
rename to src/cmd/compile/internal/ssa/gen/generic.rules
index 21e5f72..b01952f 100644
--- a/src/cmd/compile/internal/ssa/rulegen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -38,12 +38,12 @@
// TODO: fix size
(Store dst (Load <t> src mem) mem) && t.Size() > 8 -> (Move [t.Size()] dst src mem)
-(BlockIf (Const [c]) yes no) && c.(bool) -> (BlockPlain nil yes)
-(BlockIf (Const [c]) yes no) && !c.(bool) -> (BlockPlain nil no)
-
// string ops
(Const <t> [s]) && t.IsString() -> (StringMake (OffPtr <TypeBytePtr> [2*config.ptrSize] (Global <TypeBytePtr> [config.fe.StringSym(s.(string))])) (Const <config.Uintptr> [int64(len(s.(string)))])) // TODO: ptr
(Load <t> ptr mem) && t.IsString() -> (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.ptrSize] ptr) mem))
(StringPtr (StringMake ptr _)) -> ptr
(StringLen (StringMake _ len)) -> len
(Store dst str mem) && str.Type.IsString() -> (Store (OffPtr <TypeBytePtr> [config.ptrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
+
+(If (Const [c]) yes no) && c.(bool) -> (Plain nil yes)
+(If (Const [c]) yes no) && !c.(bool) -> (Plain nil no)
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
new file mode 100644
index 0000000..e8c3cbe
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -0,0 +1,104 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+var genericOps = []opData{
+ // 2-input arithmetic
+ // Types must be consistent with Go typing. Add, for example, must take two values
+ // of the same type and produces that same type.
+ {name: "Add"}, // arg0 + arg1
+ {name: "Sub"}, // arg0 - arg1
+ {name: "Mul"}, // arg0 * arg1
+ {name: "Lsh"}, // arg0 << arg1
+ {name: "Rsh"}, // arg0 >> arg1 (signed/unsigned depending on signedness of type)
+
+ // 2-input comparisons
+ {name: "Less"}, // arg0 < arg1
+
+ // Data movement
+ {name: "Phi"}, // select an argument based on which predecessor block we came from
+ {name: "Copy"}, // output = arg0
+
+ // constants. Constant values are stored in the aux field.
+ // booleans have a bool aux field, strings have a string aux
+ // field, and so on. All integer types store their value
+ // in the aux field as an int64 (including int, uint64, etc.).
+ // We could store int8 as an int8, but that won't work for int,
+ // as it may be different widths on the host and target.
+ {name: "Const"},
+
+ // Constant-like things
+ {name: "Arg"}, // address of a function parameter/result. Memory input is an arg called ".mem". aux is a string (TODO: make it something other than a string?)
+ {name: "Global"}, // the address of a global variable aux.(*gc.Sym)
+ {name: "SP"}, // stack pointer
+ {name: "FP"}, // frame pointer
+ {name: "Func"}, // entry address of a function
+
+ // Memory operations
+ {name: "Load"}, // Load from arg0+aux.(int64). arg1=memory
+ {name: "Store"}, // Store arg1 to arg0+aux.(int64). arg2=memory. Returns memory.
+ {name: "Move"}, // arg0=destptr, arg1=srcptr, arg2=mem, aux.(int64)=size. Returns memory.
+
+ // Function calls. Arguments to the call have already been written to the stack.
+ // Return values appear on the stack. The method receiver, if any, is treated
+ // as a phantom first argument.
+ {name: "Call"}, // arg0=code pointer, arg1=context ptr, arg2=memory. Returns memory.
+ {name: "StaticCall"}, // call function aux.(*gc.Sym), arg0=memory. Returns memory.
+
+ // Conversions
+ {name: "Convert"}, // convert arg0 to another type
+ {name: "ConvNop"}, // interpret arg0 as another type
+
+ // Safety checks
+ {name: "IsNonNil"}, // arg0 != nil
+ {name: "IsInBounds"}, // 0 <= arg0 < arg1
+
+ // Indexing operations
+ {name: "ArrayIndex"}, // arg0=array, arg1=index. Returns a[i]
+ {name: "PtrIndex"}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
+ {name: "OffPtr"}, // arg0 + aux.(int64) (arg0 and result are pointers)
+
+ // Slices
+ {name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap
+ {name: "SlicePtr"}, // ptr(arg0)
+ {name: "SliceLen"}, // len(arg0)
+ {name: "SliceCap"}, // cap(arg0)
+
+ // Strings
+ {name: "StringMake"}, // arg0=ptr, arg1=len
+ {name: "StringPtr"}, // ptr(arg0)
+ {name: "StringLen"}, // len(arg0)
+
+ // Spill&restore ops for the register allocator. These are
+ // semantically identical to OpCopy; they do not take/return
+ // stores like regular memory ops do. We can get away without memory
+ // args because we know there is no aliasing of spill slots on the stack.
+ // TODO: remove these, make them arch-specific ops stored
+ // in the fields of Config instead.
+ {name: "StoreReg8"},
+ {name: "LoadReg8"},
+
+ // Used during ssa construction. Like Copy, but the arg has not been specified yet.
+ {name: "FwdRef"},
+}
+
+// kind control successors
+// ------------------------------------------
+// Exit return mem []
+// Plain nil [next]
+// If a boolean Value [then, else]
+// Call mem [nopanic, panic] (control opcode should be OpCall or OpStaticCall)
+
+var genericBlocks = []blockData{
+ {name: "Exit"}, // no successors. There should only be 1 of these.
+ {name: "Plain"}, // a single successor
+ {name: "If"}, // 2 successors, if control goto Succs[0] else goto Succs[1]
+ {name: "Call"}, // 2 successors, normal return and panic
+ // TODO(khr): BlockPanic for the built-in panic call, has 1 edge to the exit block
+}
+
+func init() {
+ archs = append(archs, arch{"generic", genericOps, genericBlocks})
+}
diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go
new file mode 100644
index 0000000..56b47bd
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/gen/main.go
@@ -0,0 +1,146 @@
+// 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.
+
+// The gen command generates Go code (in the parent directory) for all
+// the architecture-specific opcodes, blocks, and rewrites.
+
+package main
+
+import (
+ "bytes"
+ "fmt"
+ "go/format"
+ "io/ioutil"
+ "log"
+)
+
+type arch struct {
+ name string
+ ops []opData
+ blocks []blockData
+}
+
+type opData struct {
+ name string
+ reg regInfo
+}
+
+type blockData struct {
+ name string
+}
+
+type regInfo struct {
+ inputs []regMask
+ clobbers regMask
+ outputs []regMask
+}
+
+type regMask uint64
+
+var archs []arch
+
+func main() {
+ genOp()
+ genLower()
+}
+func genOp() {
+ w := new(bytes.Buffer)
+ fmt.Fprintf(w, "// autogenerated: do not edit!\n")
+ fmt.Fprintf(w, "// generated from gen/*Ops.go\n")
+ fmt.Fprintln(w, "package ssa")
+
+ // generate Block* declarations
+ fmt.Fprintln(w, "const (")
+ fmt.Fprintln(w, "blockInvalid BlockKind = iota")
+ for _, a := range archs {
+ fmt.Fprintln(w)
+ for _, d := range a.blocks {
+ fmt.Fprintf(w, "Block%s%s\n", a.Name(), d.name)
+ }
+ }
+ fmt.Fprintln(w, ")")
+
+ // generate block kind string method
+ fmt.Fprintln(w, "var blockString = [...]string{")
+ fmt.Fprintln(w, "blockInvalid:\"BlockInvalid\",")
+ for _, a := range archs {
+ fmt.Fprintln(w)
+ for _, b := range a.blocks {
+ fmt.Fprintf(w, "Block%s%s:\"%s\",\n", a.Name(), b.name, b.name)
+ }
+ }
+ fmt.Fprintln(w, "}")
+ fmt.Fprintln(w, "func (k BlockKind) String() string {return blockString[k]}")
+
+ // generate Op* declarations
+ fmt.Fprintln(w, "const (")
+ fmt.Fprintln(w, "OpInvalid Op = iota")
+ for _, a := range archs {
+ fmt.Fprintln(w)
+ for _, v := range a.ops {
+ fmt.Fprintf(w, "Op%s%s\n", a.Name(), v.name)
+ }
+ }
+ fmt.Fprintln(w, ")")
+
+ // generate OpInfo table
+ fmt.Fprintln(w, "var opcodeTable = [...]opInfo{")
+ fmt.Fprintln(w, " { name: \"OpInvalid\" },")
+ for _, a := range archs {
+ fmt.Fprintln(w)
+ for _, v := range a.ops {
+ fmt.Fprintln(w, "{")
+ fmt.Fprintf(w, "name:\"%s\",\n", v.name)
+ fmt.Fprintln(w, "reg:regInfo{")
+ fmt.Fprintln(w, "inputs: []regMask{")
+ for _, r := range v.reg.inputs {
+ fmt.Fprintf(w, "%d,\n", r)
+ }
+ fmt.Fprintln(w, "},")
+ fmt.Fprintf(w, "clobbers: %d,\n", v.reg.clobbers)
+ fmt.Fprintln(w, "outputs: []regMask{")
+ for _, r := range v.reg.outputs {
+ fmt.Fprintf(w, "%d,\n", r)
+ }
+ fmt.Fprintln(w, "},")
+ fmt.Fprintln(w, "},")
+ if a.name == "generic" {
+ fmt.Fprintln(w, "generic:true,")
+ }
+ fmt.Fprintln(w, "},")
+ }
+ }
+ fmt.Fprintln(w, "}")
+
+ // generate op string method
+ fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
+
+ // gofmt result
+ b := w.Bytes()
+ var err error
+ b, err = format.Source(b)
+ if err != nil {
+ panic(err)
+ }
+
+ err = ioutil.WriteFile("../opGen.go", b, 0666)
+ if err != nil {
+ log.Fatalf("can't write output: %v\n", err)
+ }
+}
+
+// Name returns the name of the architecture for use in Op* and Block* enumerations.
+func (a arch) Name() string {
+ s := a.name
+ if s == "generic" {
+ s = ""
+ }
+ return s
+}
+
+func genLower() {
+ for _, a := range archs {
+ genRules(a)
+ }
+}
diff --git a/src/cmd/compile/internal/ssa/rulegen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go
similarity index 80%
rename from src/cmd/compile/internal/ssa/rulegen/rulegen.go
rename to src/cmd/compile/internal/ssa/gen/rulegen.go
index b0916fa..5edf178 100644
--- a/src/cmd/compile/internal/ssa/rulegen/rulegen.go
+++ b/src/cmd/compile/internal/ssa/gen/rulegen.go
@@ -7,8 +7,6 @@
// which returns true iff if did something.
// Ideas stolen from Swift: http://www.hpl.hp.com/techreports/Compaq-DEC/WRL-2000-2.html
-// Run with something like "go run rulegen.go lower_amd64.rules lowerBlockAmd64 lowerValueAmd64 lowerAmd64.go"
-
package main
import (
@@ -46,17 +44,9 @@
// If multiple rules match, the first one in file order is selected.
-func main() {
- if len(os.Args) < 4 || len(os.Args) > 5 {
- fmt.Printf("usage: go run rulegen.go <rule file> <block function name> <value function name> [<output file>]")
- os.Exit(1)
- }
- rulefile := os.Args[1]
- blockfn := os.Args[2]
- valuefn := os.Args[3]
-
+func genRules(arch arch) {
// Open input file.
- text, err := os.Open(rulefile)
+ text, err := os.Open(arch.name + ".rules")
if err != nil {
log.Fatalf("can't read rule file: %v", err)
}
@@ -79,7 +69,7 @@
continue
}
op := strings.Split(line, " ")[0][1:]
- if strings.HasPrefix(op, "Block") {
+ if isBlock(op, arch) {
blockrules[op] = append(blockrules[op], line)
} else {
oprules[op] = append(oprules[op], line)
@@ -91,10 +81,10 @@
// Start output buffer, write header.
w := new(bytes.Buffer)
- fmt.Fprintf(w, "// autogenerated from %s: do not edit!\n", rulefile)
- fmt.Fprintf(w, "// generated with: go run rulegen/rulegen.go %s\n", strings.Join(os.Args[1:], " "))
+ fmt.Fprintf(w, "// autogenerated from gen/%s.rules: do not edit!\n", arch.name)
+ fmt.Fprintln(w, "// generated with: cd gen; go run *.go")
fmt.Fprintln(w, "package ssa")
- fmt.Fprintf(w, "func %s(v *Value, config *Config) bool {\n", valuefn)
+ fmt.Fprintf(w, "func rewriteValue%s(v *Value, config *Config) bool {\n", arch.name)
// generate code for each rule
fmt.Fprintf(w, "switch v.Op {\n")
@@ -104,7 +94,7 @@
}
sort.Strings(ops)
for _, op := range ops {
- fmt.Fprintf(w, "case Op%s:\n", op)
+ fmt.Fprintf(w, "case %s:\n", opName(op, arch))
for _, rule := range oprules[op] {
// Note: we use a hash to identify the rule so that its
// identity is invariant to adding/removing rules elsewhere
@@ -135,13 +125,13 @@
fail := fmt.Sprintf("{\ngoto end%s\n}\n", rulehash)
fmt.Fprintf(w, "{\n")
- genMatch(w, match, fail)
+ genMatch(w, arch, match, fail)
if cond != "" {
fmt.Fprintf(w, "if !(%s) %s", cond, fail)
}
- genResult(w, result)
+ genResult(w, arch, result)
fmt.Fprintf(w, "return true\n")
fmt.Fprintf(w, "}\n")
@@ -154,7 +144,7 @@
fmt.Fprintf(w, "}\n")
// Generate block rewrite function.
- fmt.Fprintf(w, "func %s(b *Block) bool {\n", blockfn)
+ fmt.Fprintf(w, "func rewriteBlock%s(b *Block) bool {\n", arch.name)
fmt.Fprintf(w, "switch b.Kind {\n")
ops = nil
for op := range blockrules {
@@ -162,7 +152,7 @@
}
sort.Strings(ops)
for _, op := range ops {
- fmt.Fprintf(w, "case %s:\n", op)
+ fmt.Fprintf(w, "case %s:\n", blockName(op, arch))
for _, rule := range blockrules[op] {
rulehash := fmt.Sprintf("%02x", md5.Sum([]byte(rule)))
// split at ->
@@ -193,7 +183,7 @@
// check match of control value
if s[1] != "nil" {
fmt.Fprintf(w, "v := b.Control\n")
- genMatch0(w, s[1], "v", fail, map[string]string{}, false)
+ genMatch0(w, arch, s[1], "v", fail, map[string]string{}, false)
}
// assign successor names
@@ -232,11 +222,11 @@
fmt.Fprintf(w, "removePredecessor(b, %s)\n", succ)
}
- fmt.Fprintf(w, "b.Kind = %s\n", t[0])
+ fmt.Fprintf(w, "b.Kind = %s\n", blockName(t[0], arch))
if t[1] == "nil" {
fmt.Fprintf(w, "b.Control = nil\n")
} else {
- fmt.Fprintf(w, "b.Control = %s\n", genResult0(w, t[1], new(int), false))
+ fmt.Fprintf(w, "b.Control = %s\n", genResult0(w, arch, t[1], new(int), false))
}
if len(newsuccs) < len(succs) {
fmt.Fprintf(w, "b.Succs = b.Succs[:%d]\n", len(newsuccs))
@@ -263,22 +253,18 @@
panic(err)
}
- // Write to a file if given, otherwise stdout.
- if len(os.Args) >= 5 {
- err = ioutil.WriteFile(os.Args[4], b, 0666)
- } else {
- _, err = os.Stdout.Write(b)
- }
+ // Write to file
+ err = ioutil.WriteFile("../rewrite"+arch.name+".go", b, 0666)
if err != nil {
log.Fatalf("can't write output: %v\n", err)
}
}
-func genMatch(w io.Writer, match, fail string) {
- genMatch0(w, match, "v", fail, map[string]string{}, true)
+func genMatch(w io.Writer, arch arch, match, fail string) {
+ genMatch0(w, arch, match, "v", fail, map[string]string{}, true)
}
-func genMatch0(w io.Writer, match, v, fail string, m map[string]string, top bool) {
+func genMatch0(w io.Writer, arch arch, match, v, fail string, m map[string]string, top bool) {
if match[0] != '(' {
if x, ok := m[match]; ok {
// variable already has a definition. Check whether
@@ -303,7 +289,7 @@
// check op
if !top {
- fmt.Fprintf(w, "if %s.Op != Op%s %s", v, s[0], fail)
+ fmt.Fprintf(w, "if %s.Op != %s %s", v, opName(s[0], arch), fail)
}
// check type/aux/args
@@ -345,16 +331,16 @@
argnum++
} else {
// variable or sexpr
- genMatch0(w, a, fmt.Sprintf("%s.Args[%d]", v, argnum), fail, m, false)
+ genMatch0(w, arch, a, fmt.Sprintf("%s.Args[%d]", v, argnum), fail, m, false)
argnum++
}
}
}
-func genResult(w io.Writer, result string) {
- genResult0(w, result, new(int), true)
+func genResult(w io.Writer, arch arch, result string) {
+ genResult0(w, arch, result, new(int), true)
}
-func genResult0(w io.Writer, result string, alloc *int, top bool) string {
+func genResult0(w io.Writer, arch arch, result string, alloc *int, top bool) string {
if result[0] != '(' {
// variable
if top {
@@ -371,14 +357,14 @@
var hasType bool
if top {
v = "v"
- fmt.Fprintf(w, "v.Op = Op%s\n", s[0])
+ fmt.Fprintf(w, "v.Op = %s\n", opName(s[0], arch))
fmt.Fprintf(w, "v.Aux = nil\n")
fmt.Fprintf(w, "v.resetArgs()\n")
hasType = true
} else {
v = fmt.Sprintf("v%d", *alloc)
*alloc++
- fmt.Fprintf(w, "%s := v.Block.NewValue(Op%s, TypeInvalid, nil)\n", v, s[0])
+ fmt.Fprintf(w, "%s := v.Block.NewValue(%s, TypeInvalid, nil)\n", v, opName(s[0], arch))
}
for _, a := range s[1:] {
if a[0] == '<' {
@@ -400,7 +386,7 @@
fmt.Fprintf(w, "%s.AddArg(%s)\n", v, a[1:len(a)-1])
} else {
// regular argument (sexpr or variable)
- x := genResult0(w, a, alloc, false)
+ x := genResult0(w, arch, a, alloc, false)
fmt.Fprintf(w, "%s.AddArg(%s)\n", v, x)
}
}
@@ -456,3 +442,39 @@
}
return r
}
+
+// isBlock returns true if this op is a block opcode.
+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
+}
+
+// opName converts from an op name specified in a rule file to an Op enum.
+// if the name matches a generic op, returns "Op" plus the specified name.
+// Otherwise, returns "Op" plus arch name plus op name.
+func opName(name string, arch arch) string {
+ for _, op := range genericOps {
+ if op.name == name {
+ return "Op" + name
+ }
+ }
+ return "Op" + arch.name + name
+}
+
+func blockName(name string, arch arch) string {
+ for _, b := range genericBlocks {
+ if b.name == name {
+ return "Block" + name
+ }
+ }
+ return "Block" + arch.name + name
+}
diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go
index ebed4f2..2ca1db7 100644
--- a/src/cmd/compile/internal/ssa/lower.go
+++ b/src/cmd/compile/internal/ssa/lower.go
@@ -6,8 +6,6 @@
import "log"
-//go:generate go run rulegen/rulegen.go rulegen/lower_amd64.rules lowerBlockAMD64 lowerValueAMD64 lowerAmd64.go
-
// convert to machine-dependent ops
func lower(f *Func) {
// repeat rewrites until we find no more rewrites
@@ -16,7 +14,7 @@
// Check for unlowered opcodes, fail if we find one.
for _, b := range f.Blocks {
for _, v := range b.Values {
- if v.Op < OpGenericEnd && v.Op != OpFP && v.Op != OpSP && v.Op != OpArg && v.Op != OpCopy && v.Op != OpPhi {
+ if opcodeTable[v.Op].generic && v.Op != OpFP && v.Op != OpSP && v.Op != OpArg && v.Op != OpCopy && v.Op != OpPhi {
log.Panicf("%s not lowered", v.LongString())
}
}
diff --git a/src/cmd/compile/internal/ssa/lowergeneric.go b/src/cmd/compile/internal/ssa/lowergeneric.go
new file mode 100644
index 0000000..1ac276a
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/lowergeneric.go
@@ -0,0 +1,289 @@
+// autogenerated from generic.rules: do not edit!
+// generated with: go run rulegen/rulegen.go
+package ssa
+
+func lowerValuegeneric(v *Value) bool {
+ switch v.Op {
+ case OpAdd:
+ // match: (Add <t> (Const [c]) (Const [d]))
+ // cond: is64BitInt(t)
+ // result: (Const [{c.(int64)+d.(int64)}])
+ {
+ t := v.Type
+ if v.Args[0].Op != OpConst {
+ goto end8d047ed0ae9537b840adc79ea82c6e05
+ }
+ c := v.Args[0].Aux
+ if v.Args[1].Op != OpConst {
+ goto end8d047ed0ae9537b840adc79ea82c6e05
+ }
+ d := v.Args[1].Aux
+ if !(is64BitInt(t)) {
+ goto end8d047ed0ae9537b840adc79ea82c6e05
+ }
+ v.Op = OpConst
+ v.Aux = nil
+ v.resetArgs()
+ v.Aux = c.(int64) + d.(int64)
+ return true
+ }
+ goto end8d047ed0ae9537b840adc79ea82c6e05
+ end8d047ed0ae9537b840adc79ea82c6e05:
+ ;
+ case OpArrayIndex:
+ // match: (ArrayIndex (Load ptr mem) idx)
+ // cond:
+ // result: (Load (PtrIndex <ptr.Type.Elem().Elem().PtrTo()> ptr idx) mem)
+ {
+ if v.Args[0].Op != OpLoad {
+ goto end3809f4c52270a76313e4ea26e6f0b753
+ }
+ ptr := v.Args[0].Args[0]
+ mem := v.Args[0].Args[1]
+ idx := v.Args[1]
+ v.Op = OpLoad
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue(OpPtrIndex, TypeInvalid, nil)
+ v0.Type = ptr.Type.Elem().Elem().PtrTo()
+ v0.AddArg(ptr)
+ v0.AddArg(idx)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ goto end3809f4c52270a76313e4ea26e6f0b753
+ end3809f4c52270a76313e4ea26e6f0b753:
+ ;
+ case OpIsInBounds:
+ // match: (IsInBounds (Const [c]) (Const [d]))
+ // cond:
+ // result: (Const [inBounds(c.(int64),d.(int64))])
+ {
+ if v.Args[0].Op != OpConst {
+ goto enddbd1a394d9b71ee64335361b8384865c
+ }
+ c := v.Args[0].Aux
+ if v.Args[1].Op != OpConst {
+ goto enddbd1a394d9b71ee64335361b8384865c
+ }
+ d := v.Args[1].Aux
+ v.Op = OpConst
+ v.Aux = nil
+ v.resetArgs()
+ v.Aux = inBounds(c.(int64), d.(int64))
+ return true
+ }
+ goto enddbd1a394d9b71ee64335361b8384865c
+ enddbd1a394d9b71ee64335361b8384865c:
+ ;
+ case OpMul:
+ // match: (Mul <t> (Const [c]) (Const [d]))
+ // cond: is64BitInt(t)
+ // result: (Const [{c.(int64)*d.(int64)}])
+ {
+ t := v.Type
+ if v.Args[0].Op != OpConst {
+ goto end776610f88cf04f438242d76ed2b14f1c
+ }
+ c := v.Args[0].Aux
+ if v.Args[1].Op != OpConst {
+ goto end776610f88cf04f438242d76ed2b14f1c
+ }
+ d := v.Args[1].Aux
+ if !(is64BitInt(t)) {
+ goto end776610f88cf04f438242d76ed2b14f1c
+ }
+ v.Op = OpConst
+ v.Aux = nil
+ v.resetArgs()
+ v.Aux = c.(int64) * d.(int64)
+ return true
+ }
+ goto end776610f88cf04f438242d76ed2b14f1c
+ end776610f88cf04f438242d76ed2b14f1c:
+ ;
+ case OpPtrIndex:
+ // match: (PtrIndex <t> ptr idx)
+ // cond:
+ // result: (Add ptr (Mul <v.Block.Func.Config.Uintptr> idx (Const <v.Block.Func.Config.Uintptr> [t.Elem().Size()])))
+ {
+ t := v.Type
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v.Op = OpAdd
+ v.Aux = nil
+ v.resetArgs()
+ v.AddArg(ptr)
+ v0 := v.Block.NewValue(OpMul, TypeInvalid, nil)
+ v0.Type = v.Block.Func.Config.Uintptr
+ v0.AddArg(idx)
+ v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
+ v1.Type = v.Block.Func.Config.Uintptr
+ v1.Aux = t.Elem().Size()
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ goto end383c68c41e72d22ef00c4b7b0fddcbb8
+ end383c68c41e72d22ef00c4b7b0fddcbb8:
+ ;
+ case OpSliceCap:
+ // match: (SliceCap (Load ptr mem))
+ // cond:
+ // result: (Load (Add <ptr.Type> ptr (Const <v.Block.Func.Config.Uintptr> [int64(v.Block.Func.Config.ptrSize*2)])) mem)
+ {
+ if v.Args[0].Op != OpLoad {
+ goto endbf1d4db93c4664ed43be3f73afb4dfa3
+ }
+ ptr := v.Args[0].Args[0]
+ mem := v.Args[0].Args[1]
+ v.Op = OpLoad
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue(OpAdd, TypeInvalid, nil)
+ v0.Type = ptr.Type
+ v0.AddArg(ptr)
+ v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
+ v1.Type = v.Block.Func.Config.Uintptr
+ v1.Aux = int64(v.Block.Func.Config.ptrSize * 2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ goto endbf1d4db93c4664ed43be3f73afb4dfa3
+ endbf1d4db93c4664ed43be3f73afb4dfa3:
+ ;
+ case OpSliceLen:
+ // match: (SliceLen (Load ptr mem))
+ // cond:
+ // result: (Load (Add <ptr.Type> ptr (Const <v.Block.Func.Config.Uintptr> [int64(v.Block.Func.Config.ptrSize)])) mem)
+ {
+ if v.Args[0].Op != OpLoad {
+ goto end9190b1ecbda4c5dd6d3e05d2495fb297
+ }
+ ptr := v.Args[0].Args[0]
+ mem := v.Args[0].Args[1]
+ v.Op = OpLoad
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue(OpAdd, TypeInvalid, nil)
+ v0.Type = ptr.Type
+ v0.AddArg(ptr)
+ v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
+ v1.Type = v.Block.Func.Config.Uintptr
+ v1.Aux = int64(v.Block.Func.Config.ptrSize)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ goto end9190b1ecbda4c5dd6d3e05d2495fb297
+ end9190b1ecbda4c5dd6d3e05d2495fb297:
+ ;
+ case OpSlicePtr:
+ // match: (SlicePtr (Load ptr mem))
+ // cond:
+ // result: (Load ptr mem)
+ {
+ if v.Args[0].Op != OpLoad {
+ goto end459613b83f95b65729d45c2ed663a153
+ }
+ ptr := v.Args[0].Args[0]
+ mem := v.Args[0].Args[1]
+ v.Op = OpLoad
+ v.Aux = nil
+ v.resetArgs()
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ goto end459613b83f95b65729d45c2ed663a153
+ end459613b83f95b65729d45c2ed663a153:
+ ;
+ case OpStore:
+ // match: (Store dst (Load <t> src mem) mem)
+ // cond: t.Size() > 8
+ // result: (Move [t.Size()] dst src mem)
+ {
+ dst := v.Args[0]
+ if v.Args[1].Op != OpLoad {
+ goto end324ffb6d2771808da4267f62c854e9c8
+ }
+ t := v.Args[1].Type
+ src := v.Args[1].Args[0]
+ mem := v.Args[1].Args[1]
+ if v.Args[2] != v.Args[1].Args[1] {
+ goto end324ffb6d2771808da4267f62c854e9c8
+ }
+ if !(t.Size() > 8) {
+ goto end324ffb6d2771808da4267f62c854e9c8
+ }
+ v.Op = OpMove
+ v.Aux = nil
+ v.resetArgs()
+ v.Aux = t.Size()
+ v.AddArg(dst)
+ v.AddArg(src)
+ v.AddArg(mem)
+ return true
+ }
+ goto end324ffb6d2771808da4267f62c854e9c8
+ end324ffb6d2771808da4267f62c854e9c8:
+ }
+ return false
+}
+func lowerBlockgeneric(b *Block) bool {
+ switch b.Kind {
+ case BlockIf:
+ // match: (BlockIf (Const [c]) yes no)
+ // cond: c.(bool)
+ // result: (BlockPlain nil yes)
+ {
+ v := b.Control
+ if v.Op != OpConst {
+ goto endbe39807508a6192b4022c7293eb6e114
+ }
+ c := v.Aux
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ if !(c.(bool)) {
+ goto endbe39807508a6192b4022c7293eb6e114
+ }
+ removePredecessor(b, no)
+ b.Kind = BlockPlain
+ b.Control = nil
+ b.Succs = b.Succs[:1]
+ b.Succs[0] = yes
+ return true
+ }
+ goto endbe39807508a6192b4022c7293eb6e114
+ endbe39807508a6192b4022c7293eb6e114:
+ ;
+ // match: (BlockIf (Const [c]) yes no)
+ // cond: !c.(bool)
+ // result: (BlockPlain nil no)
+ {
+ v := b.Control
+ if v.Op != OpConst {
+ goto end69ac35957ebe0a77a5ef5103c1f79fbf
+ }
+ c := v.Aux
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ if !(!c.(bool)) {
+ goto end69ac35957ebe0a77a5ef5103c1f79fbf
+ }
+ removePredecessor(b, yes)
+ b.Kind = BlockPlain
+ b.Control = nil
+ b.Succs = b.Succs[:1]
+ b.Succs[0] = no
+ return true
+ }
+ goto end69ac35957ebe0a77a5ef5103c1f79fbf
+ end69ac35957ebe0a77a5ef5103c1f79fbf:
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go
index c8bd3d2..19a3fdd 100644
--- a/src/cmd/compile/internal/ssa/op.go
+++ b/src/cmd/compile/internal/ssa/op.go
@@ -12,95 +12,11 @@
// An Op encodes the specific operation that a Value performs.
// Opcodes' semantics can be modified by the type and aux fields of the Value.
// For instance, OpAdd can be 32 or 64 bit, signed or unsigned, float or complex, depending on Value.Type.
-// Semantics of each op are described below.
-//
-// Ops come in two flavors, architecture-independent and architecture-dependent.
-// Architecture-independent opcodes appear in this file.
-// Architecture-dependent opcodes appear in op{arch}.go files.
+// Semantics of each op are described in the opcode files in gen/*Ops.go.
+// There is one file for generic (architecture-independent) ops and one file
+// for each architecture.
type Op int32
-// Opcode ranges, a generic one and one for each architecture.
-const (
- opInvalid Op = 0
- opGenericBase = 1 + 1000*iota
- opAMD64Base
- op386Base
-
- opMax // sentinel
-)
-
-// Generic opcodes
-const (
- opGenericStart Op = opGenericBase + iota
-
- // 2-input arithmetic
- OpAdd // arg0 + arg1
- OpSub // arg0 - arg1
- OpMul // arg0 * arg1
- OpLsh // arg0 << arg1
- OpRsh // arg0 >> arg1 (signed/unsigned depending on signedness of type)
-
- // 2-input comparisons
- OpLess // arg0 < arg1
-
- // constants. Constant values are stored in the aux field.
- // booleans have a bool aux field, strings have a string aux
- // field, and so on. All integer types store their value
- // in the aux field as an int64 (including int, uint64, etc.).
- // We could store int8 as an int8, but that won't work for int,
- // as it may be different widths on the host and target.
- OpConst
-
- OpArg // address of a function parameter/result. Memory input is an arg called ".mem". aux is a string (TODO: make it something other than a string?)
- OpGlobal // the address of a global variable aux.(*gc.Sym)
- OpFunc // entry address of a function
- OpFP // frame pointer
- OpSP // stack pointer
-
- OpCopy // output = arg0
- OpMove // arg0=destptr, arg1=srcptr, arg2=mem, aux.(int64)=size. Returns memory.
- OpPhi // select an argument based on which predecessor block we came from
-
- OpSliceMake // arg0=ptr, arg1=len, arg2=cap
- OpSlicePtr // ptr(arg0)
- OpSliceLen // len(arg0)
- OpSliceCap // cap(arg0)
-
- OpStringMake // arg0=ptr, arg1=len
- OpStringPtr // ptr(arg0)
- OpStringLen // len(arg0)
-
- OpLoad // Load from arg0. arg1=memory
- OpStore // Store arg1 to arg0. arg2=memory. Returns memory.
- OpArrayIndex // arg0=array, arg1=index. Returns a[i]
- OpPtrIndex // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
- OpIsNonNil // arg0 != nil
- OpIsInBounds // 0 <= arg0 < arg1
-
- // function calls. Arguments to the call have already been written to the stack.
- // Return values appear on the stack. The method receiver, if any, is treated
- // as a phantom first argument.
- OpCall // arg0=code pointer, arg1=context ptr, arg2=memory. Returns memory.
- OpStaticCall // call function aux.(*gc.Sym), arg0=memory. Returns memory.
-
- OpConvert // convert arg0 to another type
- OpConvNop // interpret arg0 as another type
-
- OpOffPtr // arg0 + aux.(int64) (arg0 and result are pointers)
-
- // spill&restore ops for the register allocator. These are
- // semantically identical to OpCopy; they do not take/return
- // stores like regular memory ops do. We can get away without memory
- // args because we know there is no aliasing of spill slots on the stack.
- OpStoreReg8
- OpLoadReg8
-
- // used during ssa construction. Like OpCopy, but the arg has not been specified yet.
- OpFwdRef
-
- OpGenericEnd
-)
-
// GlobalOffset represents a fixed offset within a global variable
type GlobalOffset struct {
Global interface{} // holds a *gc.Sym
@@ -121,86 +37,14 @@
return fmt.Sprintf("%v+%d", g.Global, g.Offset)
}
-//go:generate stringer -type=Op
-
type opInfo struct {
- flags int32
-
- // returns a reg constraint for the instruction. [0] gives a reg constraint
- // for each input, [1] gives a reg constraint for each output. (Values have
- // exactly one output for now)
- reg [2][]regMask
+ name string
+ reg regInfo
+ generic bool // this is a generic (arch-independent) opcode
}
-const (
- // possible properties of opcodes
- OpFlagCommutative int32 = 1 << iota
-)
-
-// Opcodes that represent the input Go program
-var genericTable = map[Op]opInfo{
- // the unknown op is used only during building and should not appear in a
- // fully formed ssa representation.
-
- OpAdd: {flags: OpFlagCommutative},
- OpSub: {},
- OpMul: {flags: OpFlagCommutative},
- OpLess: {},
-
- OpConst: {}, // aux matches the type (e.g. bool, int64 float64)
- OpArg: {}, // aux is the name of the input variable. Currently only ".mem" is used
- OpGlobal: {}, // address of a global variable
- OpFunc: {},
- OpCopy: {},
- OpPhi: {},
-
- OpConvNop: {}, // aux is the type to convert to
-
- /*
- // build and take apart slices
- {name: "slicemake"}, // (ptr,len,cap) -> slice
- {name: "sliceptr"}, // pointer part of slice
- {name: "slicelen"}, // length part of slice
- {name: "slicecap"}, // capacity part of slice
-
- // build and take apart strings
- {name: "stringmake"}, // (ptr,len) -> string
- {name: "stringptr"}, // pointer part of string
- {name: "stringlen"}, // length part of string
-
- // operations on arrays/slices/strings
- {name: "slice"}, // (s, i, j) -> s[i:j]
- {name: "index"}, // (mem, ptr, idx) -> val
- {name: "indexaddr"}, // (ptr, idx) -> ptr
-
- // loads & stores
- {name: "load"}, // (mem, check, ptr) -> val
- {name: "store"}, // (mem, check, ptr, val) -> mem
-
- // checks
- {name: "checknil"}, // (mem, ptr) -> check
- {name: "checkbound"}, // (mem, idx, len) -> check
-
- // functions
- {name: "call"},
-
- // builtins
- {name: "len"},
- {name: "convert"},
-
- // tuples
- {name: "tuple"}, // build a tuple out of its arguments
- {name: "extract"}, // aux is an int64. Extract that index out of a tuple
- {name: "extractsuffix"}, // aux is an int64. Slice a tuple with [aux:]
-
- */
-}
-
-// table of opcodes, indexed by opcode ID
-var opcodeTable [opMax]opInfo
-
-func init() {
- for op, info := range genericTable {
- opcodeTable[op] = info
- }
+type regInfo struct {
+ inputs []regMask
+ clobbers regMask
+ outputs []regMask // NOTE: values can only have 1 output for now.
}
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
new file mode 100644
index 0000000..604f096
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -0,0 +1,916 @@
+// autogenerated: do not edit!
+// generated from gen/*Ops.go
+package ssa
+
+const (
+ blockInvalid BlockKind = iota
+
+ BlockAMD64EQ
+ BlockAMD64NE
+ BlockAMD64LT
+ BlockAMD64LE
+ BlockAMD64GT
+ BlockAMD64GE
+ BlockAMD64ULT
+ BlockAMD64ULE
+ BlockAMD64UGT
+ BlockAMD64UGE
+
+ BlockExit
+ BlockPlain
+ BlockIf
+ BlockCall
+)
+
+var blockString = [...]string{
+ blockInvalid: "BlockInvalid",
+
+ BlockAMD64EQ: "EQ",
+ BlockAMD64NE: "NE",
+ BlockAMD64LT: "LT",
+ BlockAMD64LE: "LE",
+ BlockAMD64GT: "GT",
+ BlockAMD64GE: "GE",
+ BlockAMD64ULT: "ULT",
+ BlockAMD64ULE: "ULE",
+ BlockAMD64UGT: "UGT",
+ BlockAMD64UGE: "UGE",
+
+ BlockExit: "Exit",
+ BlockPlain: "Plain",
+ BlockIf: "If",
+ BlockCall: "Call",
+}
+
+func (k BlockKind) String() string { return blockString[k] }
+
+const (
+ OpInvalid Op = iota
+
+ OpAMD64ADDQ
+ OpAMD64ADDQconst
+ OpAMD64SUBQ
+ OpAMD64SUBQconst
+ OpAMD64MULQ
+ OpAMD64MULQconst
+ OpAMD64SHLQ
+ OpAMD64SHLQconst
+ OpAMD64NEGQ
+ OpAMD64CMPQ
+ OpAMD64CMPQconst
+ OpAMD64TESTQ
+ OpAMD64TESTB
+ OpAMD64SETEQ
+ OpAMD64SETNE
+ OpAMD64SETL
+ OpAMD64SETG
+ OpAMD64SETGE
+ OpAMD64SETB
+ OpAMD64MOVQconst
+ OpAMD64LEAQ
+ OpAMD64LEAQ2
+ OpAMD64LEAQ4
+ OpAMD64LEAQ8
+ OpAMD64LEAQglobal
+ OpAMD64MOVBload
+ OpAMD64MOVBQZXload
+ OpAMD64MOVBQSXload
+ OpAMD64MOVQload
+ OpAMD64MOVQloadidx8
+ OpAMD64MOVBstore
+ OpAMD64MOVQstore
+ OpAMD64MOVQstoreidx8
+ OpAMD64MOVQloadglobal
+ OpAMD64MOVQstoreglobal
+ OpAMD64REPMOVSB
+ OpAMD64ADDL
+ OpAMD64InvertFlags
+
+ OpAdd
+ OpSub
+ OpMul
+ OpLsh
+ OpRsh
+ OpLess
+ OpPhi
+ OpCopy
+ OpConst
+ OpArg
+ OpGlobal
+ OpSP
+ OpFP
+ OpFunc
+ OpLoad
+ OpStore
+ OpMove
+ OpCall
+ OpStaticCall
+ OpConvert
+ OpConvNop
+ OpIsNonNil
+ OpIsInBounds
+ OpArrayIndex
+ OpPtrIndex
+ OpOffPtr
+ OpSliceMake
+ OpSlicePtr
+ OpSliceLen
+ OpSliceCap
+ OpStringMake
+ OpStringPtr
+ OpStringLen
+ OpStoreReg8
+ OpLoadReg8
+ OpFwdRef
+)
+
+var opcodeTable = [...]opInfo{
+ {name: "OpInvalid"},
+
+ {
+ name: "ADDQ",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "ADDQconst",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "SUBQ",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "SUBQconst",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "MULQ",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "MULQconst",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "SHLQ",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 2,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "SHLQconst",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "NEGQ",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "CMPQ",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 8589934592,
+ },
+ },
+ },
+ {
+ name: "CMPQconst",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 8589934592,
+ },
+ },
+ },
+ {
+ name: "TESTQ",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 8589934592,
+ },
+ },
+ },
+ {
+ name: "TESTB",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 8589934592,
+ },
+ },
+ },
+ {
+ name: "SETEQ",
+ reg: regInfo{
+ inputs: []regMask{
+ 8589934592,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "SETNE",
+ reg: regInfo{
+ inputs: []regMask{
+ 8589934592,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "SETL",
+ reg: regInfo{
+ inputs: []regMask{
+ 8589934592,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "SETG",
+ reg: regInfo{
+ inputs: []regMask{
+ 8589934592,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "SETGE",
+ reg: regInfo{
+ inputs: []regMask{
+ 8589934592,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "SETB",
+ reg: regInfo{
+ inputs: []regMask{
+ 8589934592,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "MOVQconst",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "LEAQ",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "LEAQ2",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "LEAQ4",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "LEAQ8",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "LEAQglobal",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "MOVBload",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 0,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "MOVBQZXload",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 0,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "MOVBQSXload",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 0,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "MOVQload",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 0,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "MOVQloadidx8",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ 0,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "MOVBstore",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ 0,
+ },
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ },
+ {
+ name: "MOVQstore",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ 0,
+ },
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ },
+ {
+ name: "MOVQstoreidx8",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ 4295032831,
+ 0,
+ },
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ },
+ {
+ name: "MOVQloadglobal",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ },
+ {
+ name: "MOVQstoreglobal",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ },
+ {
+ name: "REPMOVSB",
+ reg: regInfo{
+ inputs: []regMask{
+ 128,
+ 64,
+ 2,
+ },
+ clobbers: 194,
+ outputs: []regMask{},
+ },
+ },
+ {
+ name: "ADDL",
+ reg: regInfo{
+ inputs: []regMask{
+ 4295032831,
+ 4295032831,
+ },
+ clobbers: 0,
+ outputs: []regMask{
+ 65519,
+ },
+ },
+ },
+ {
+ name: "InvertFlags",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ },
+
+ {
+ name: "Add",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Sub",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Mul",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Lsh",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Rsh",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Less",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Phi",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Copy",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Const",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Arg",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Global",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "SP",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "FP",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Func",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Load",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Store",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Move",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Call",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "StaticCall",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "Convert",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "ConvNop",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "IsNonNil",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "IsInBounds",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "ArrayIndex",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "PtrIndex",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "OffPtr",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "SliceMake",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "SlicePtr",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "SliceLen",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "SliceCap",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "StringMake",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "StringPtr",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "StringLen",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "StoreReg8",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "LoadReg8",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
+ name: "FwdRef",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+}
+
+func (o Op) String() string { return opcodeTable[o].name }
diff --git a/src/cmd/compile/internal/ssa/op_string.go b/src/cmd/compile/internal/ssa/op_string.go
deleted file mode 100644
index 2005d33..0000000
--- a/src/cmd/compile/internal/ssa/op_string.go
+++ /dev/null
@@ -1,32 +0,0 @@
-// generated by stringer -type=Op; DO NOT EDIT
-
-package ssa
-
-import "fmt"
-
-const (
- _Op_name_0 = "opInvalid"
- _Op_name_1 = "opGenericStartOpAddOpSubOpMulOpLshOpRshOpLessOpConstOpArgOpGlobalOpFuncOpFPOpSPOpCopyOpMoveOpPhiOpSliceMakeOpSlicePtrOpSliceLenOpSliceCapOpStringMakeOpStringPtrOpStringLenOpLoadOpStoreOpArrayIndexOpPtrIndexOpIsNonNilOpIsInBoundsOpCallOpStaticCallOpConvertOpConvNopOpOffPtrOpStoreReg8OpLoadReg8OpFwdRefOpGenericEnd"
- _Op_name_2 = "opAMD64startOpADDQOpADDQconstOpSUBQOpSUBQconstOpMULQOpMULQconstOpSHLQOpSHLQconstOpNEGQOpADDLOpCMPQOpCMPQconstOpTESTQOpTESTBOpSETEQOpSETNEOpSETLOpSETGOpSETGEOpSETBOpInvertFlagsOpLEAQOpLEAQ2OpLEAQ4OpLEAQ8OpLEAQglobalOpMOVBloadOpMOVBQZXloadOpMOVBQSXloadOpMOVQloadOpMOVQstoreOpMOVQloadidx8OpMOVQstoreidx8OpMOVQloadglobalOpMOVQstoreglobalOpMOVQconstOpREPMOVSB"
-)
-
-var (
- _Op_index_0 = [...]uint8{0, 9}
- _Op_index_1 = [...]uint16{0, 14, 19, 24, 29, 34, 39, 45, 52, 57, 65, 71, 75, 79, 85, 91, 96, 107, 117, 127, 137, 149, 160, 171, 177, 184, 196, 206, 216, 228, 234, 246, 255, 264, 272, 283, 293, 301, 313}
- _Op_index_2 = [...]uint16{0, 12, 18, 29, 35, 46, 52, 63, 69, 80, 86, 92, 98, 109, 116, 123, 130, 137, 143, 149, 156, 162, 175, 181, 188, 195, 202, 214, 224, 237, 250, 260, 271, 285, 300, 316, 333, 344, 354}
-)
-
-func (i Op) String() string {
- switch {
- case i == 0:
- return _Op_name_0
- case 1001 <= i && i <= 1038:
- i -= 1001
- return _Op_name_1[_Op_index_1[i]:_Op_index_1[i+1]]
- case 2001 <= i && i <= 2038:
- i -= 2001
- return _Op_name_2[_Op_index_2[i]:_Op_index_2[i+1]]
- default:
- return fmt.Sprintf("Op(%d)", i)
- }
-}
diff --git a/src/cmd/compile/internal/ssa/opamd64.go b/src/cmd/compile/internal/ssa/opamd64.go
deleted file mode 100644
index 665f087b..0000000
--- a/src/cmd/compile/internal/ssa/opamd64.go
+++ /dev/null
@@ -1,196 +0,0 @@
-// Copyright 2015 The Go Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style
-// license that can be found in the LICENSE file.
-
-package ssa
-
-// amd64-specific opcodes
-
-const (
- blockAMD64Start BlockKind = blockAMD64Base + iota
-
- BlockEQ
- BlockNE
- BlockLT
- BlockLE
- BlockGT
- BlockGE
- BlockULT
- BlockULE
- BlockUGT
- BlockUGE
-)
-
-const (
- opAMD64start Op = opAMD64Base + iota
-
- // Suffixes encode the bit width of various instructions.
- // Q = 64 bit, L = 32 bit, W = 16 bit, B = 8 bit
-
- // arithmetic
- OpADDQ // arg0 + arg1
- OpADDQconst // arg + aux.(int64)
- OpSUBQ // arg0 - arg1
- OpSUBQconst // arg - aux.(int64)
- OpMULQ // arg0 * arg1
- OpMULQconst // arg * aux.(int64)
- OpSHLQ // arg0 << arg1
- OpSHLQconst // arg << aux.(int64)
- OpNEGQ // -arg
- OpADDL // arg0 + arg1
-
- // Flags value generation.
- // We pretend the flags type is an opaque thing that comparisons generate
- // and from which we can extract boolean conditions like <, ==, etc.
- OpCMPQ // arg0 compare to arg1
- OpCMPQconst // arg0 compare to aux.(int64)
- OpTESTQ // (arg0 & arg1) compare to 0
- OpTESTB // (arg0 & arg1) compare to 0
-
- // These opcodes extract a particular boolean condition from a flags value.
- OpSETEQ // extract == condition from arg0
- OpSETNE // extract != condition from arg0
- OpSETL // extract signed < condition from arg0
- OpSETG // extract signed > condition from arg0
- OpSETGE // extract signed >= condition from arg0
- OpSETB // extract unsigned < condition from arg0
-
- // InvertFlags reverses the direction of a flags type interpretation:
- // (InvertFlags (CMPQ a b)) == (CMPQ b a)
- // So if we want (SETL (CMPQ a b)) but we can't do that because a is a constant,
- // then we do (SETL (InvertFlags (CMPQ b a))) instead.
- // Rewrites will convert this to (SETG (CMPQ b a)).
- // InvertFlags is a pseudo-op which can't appear in assembly output.
- OpInvertFlags // reverse direction of arg0
-
- OpLEAQ // arg0 + arg1 + aux.(int64)
- OpLEAQ2 // arg0 + 2*arg1 + aux.(int64)
- OpLEAQ4 // arg0 + 4*arg1 + aux.(int64)
- OpLEAQ8 // arg0 + 8*arg1 + aux.(int64)
- OpLEAQglobal // no args. address of aux.(GlobalOffset)
-
- // Load/store from general address
- OpMOVBload // Load from arg0+aux.(int64). arg1=memory
- OpMOVBQZXload
- OpMOVBQSXload
- OpMOVQload
- OpMOVQstore // Store arg1 to arg0+aux.(int64). arg2=memory, returns memory.
- OpMOVQloadidx8 // Load from arg0+arg1*8+aux.(int64). arg2=memory
- OpMOVQstoreidx8 // Store arg2 to arg0+arg1*8+aux.(int64). arg3=memory, returns memory.
-
- // Load/store from global. Same as the above loads, but arg0 is missing and aux is a GlobalOffset instead of an int64.
- OpMOVQloadglobal // arg0 = memory
- OpMOVQstoreglobal // store arg0. arg1=memory, returns memory.
-
- // materialize a constant into a register
- OpMOVQconst // (takes no arguments)
-
- // move memory
- OpREPMOVSB // arg0=destptr, arg1=srcptr, arg2=len, arg3=mem
-)
-
-type regMask uint64
-
-var regsAMD64 = [...]string{
- "AX",
- "CX",
- "DX",
- "BX",
- "SP",
- "BP",
- "SI",
- "DI",
- "R8",
- "R9",
- "R10",
- "R11",
- "R12",
- "R13",
- "R14",
- "R15",
-
- // pseudo registers
- "FP",
- "FLAGS",
- "OVERWRITE0", // the same register as the first input
-}
-
-var gp regMask = 0x1ffff // all integer registers including SP&FP
-var gpout regMask = 0xffef // integer registers not including SP&FP
-var cx regMask = 1 << 1
-var si regMask = 1 << 6
-var di regMask = 1 << 7
-var flags regMask = 1 << 17
-
-var (
- // gp = general purpose (integer) registers
- gp21 = [2][]regMask{{gp, gp}, {gpout}} // 2 input, 1 output
- gp11 = [2][]regMask{{gp}, {gpout}} // 1 input, 1 output
- gp01 = [2][]regMask{{}, {gpout}} // 0 input, 1 output
- shift = [2][]regMask{{gp, cx}, {gpout}} // shift operations
- gp2_flags = [2][]regMask{{gp, gp}, {flags}} // generate flags from 2 gp regs
- gp1_flags = [2][]regMask{{gp}, {flags}} // generate flags from 1 gp reg
-
- gpload = [2][]regMask{{gp, 0}, {gpout}}
- gploadidx = [2][]regMask{{gp, gp, 0}, {gpout}}
- gpstore = [2][]regMask{{gp, gp, 0}, {0}}
- gpstoreidx = [2][]regMask{{gp, gp, gp, 0}, {0}}
-
- gpload_stack = [2][]regMask{{0}, {gpout}}
- gpstore_stack = [2][]regMask{{gp, 0}, {0}}
-)
-
-// Opcodes that appear in an output amd64 program
-var amd64Table = map[Op]opInfo{
- OpADDQ: {flags: OpFlagCommutative, reg: gp21}, // TODO: overwrite
- OpADDQconst: {reg: gp11}, // aux = int64 constant to add
- OpSUBQ: {reg: gp21},
- OpSUBQconst: {reg: gp11},
- OpMULQ: {reg: gp21},
- OpMULQconst: {reg: gp11},
- OpSHLQ: {reg: gp21},
- OpSHLQconst: {reg: gp11},
-
- OpCMPQ: {reg: gp2_flags}, // compute arg[0]-arg[1] and produce flags
- OpCMPQconst: {reg: gp1_flags},
- OpTESTQ: {reg: gp2_flags},
- OpTESTB: {reg: gp2_flags},
-
- OpLEAQ: {flags: OpFlagCommutative, reg: gp21}, // aux = int64 constant to add
- OpLEAQ2: {},
- OpLEAQ4: {},
- OpLEAQ8: {},
- OpLEAQglobal: {reg: gp01},
-
- // loads and stores
- OpMOVBload: {reg: gpload},
- OpMOVQload: {reg: gpload},
- OpMOVQstore: {reg: gpstore},
- OpMOVQloadidx8: {reg: gploadidx},
- OpMOVQstoreidx8: {reg: gpstoreidx},
-
- OpMOVQconst: {reg: gp01},
-
- OpStaticCall: {},
-
- OpCopy: {reg: gp11}, // TODO: make arch-specific
- OpConvNop: {reg: gp11}, // TODO: make arch-specific. Or get rid of this altogether.
-
- // convert from flags back to boolean
- OpSETL: {},
-
- // ops for spilling of registers
- // unlike regular loads & stores, these take no memory argument.
- // They are just like OpCopy but we use them during register allocation.
- // TODO: different widths, float
- OpLoadReg8: {},
- OpStoreReg8: {},
-
- OpREPMOVSB: {reg: [2][]regMask{{di, si, cx, 0}, {0}}}, // TODO: record that si/di/cx are clobbered
-}
-
-func init() {
- for op, info := range amd64Table {
- opcodeTable[op] = info
- }
-}
diff --git a/src/cmd/compile/internal/ssa/opt.go b/src/cmd/compile/internal/ssa/opt.go
index 81c1dfc..6e91fd7 100644
--- a/src/cmd/compile/internal/ssa/opt.go
+++ b/src/cmd/compile/internal/ssa/opt.go
@@ -5,9 +5,6 @@
package ssa
// machine-independent optimization
-
-//go:generate go run rulegen/rulegen.go rulegen/generic.rules genericBlockRules genericValueRules generic.go
-
func opt(f *Func) {
- applyRewrite(f, genericBlockRules, genericValueRules)
+ applyRewrite(f, rewriteBlockgeneric, rewriteValuegeneric)
}
diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go
index 8da969b..8390084 100644
--- a/src/cmd/compile/internal/ssa/regalloc.go
+++ b/src/cmd/compile/internal/ssa/regalloc.go
@@ -20,8 +20,10 @@
type register uint
+type regMask uint64
+
// TODO: make arch-dependent
-var numRegs register = 32
+var numRegs register = 64
var registers = [...]Register{
Register{0, "AX"},
@@ -40,12 +42,26 @@
Register{13, "R13"},
Register{14, "R14"},
Register{15, "R15"},
+ Register{16, "X0"},
+ Register{17, "X1"},
+ Register{18, "X2"},
+ Register{19, "X3"},
+ Register{20, "X4"},
+ Register{21, "X5"},
+ Register{22, "X6"},
+ Register{23, "X7"},
+ Register{24, "X8"},
+ Register{25, "X9"},
+ Register{26, "X10"},
+ Register{27, "X11"},
+ Register{28, "X12"},
+ Register{29, "X13"},
+ Register{30, "X14"},
+ Register{31, "X15"},
+ Register{32, "FP"}, // pseudo-register, actually a constant offset from SP
+ Register{33, "FLAGS"},
- // TODO X0, ...
// TODO: make arch-dependent
- Register{16, "FP"}, // pseudo-register, actually a constant offset from SP
- Register{17, "FLAGS"},
- Register{18, "OVERWRITE"},
}
// countRegs returns the number of set bits in the register mask.
@@ -98,7 +114,7 @@
home = setloc(home, v, ®isters[4]) // TODO: arch-dependent
case OpFP:
fp = v
- home = setloc(home, v, ®isters[16]) // TODO: arch-dependent
+ home = setloc(home, v, ®isters[32]) // TODO: arch-dependent
}
}
@@ -135,7 +151,7 @@
// TODO: hack: initialize fixed registers
regs[4] = regInfo{sp, sp, false}
- regs[16] = regInfo{fp, fp, false}
+ regs[32] = regInfo{fp, fp, false}
var used regMask // has a 1 for each non-nil entry in regs
var dirty regMask // has a 1 for each dirty entry in regs
@@ -155,8 +171,12 @@
// - definition of v. c will be identical to v but will live in
// a register. v will be modified into a spill of c.
regspec := opcodeTable[v.Op].reg
- inputs := regspec[0]
- outputs := regspec[1]
+ if v.Op == OpCopy || v.Op == OpConvNop {
+ // TODO: make this less of a hack
+ regspec = opcodeTable[OpAMD64ADDQconst].reg
+ }
+ inputs := regspec.inputs
+ outputs := regspec.outputs
if len(inputs) == 0 && len(outputs) == 0 {
// No register allocation required (or none specified yet)
b.Values = append(b.Values, v)
@@ -177,7 +197,7 @@
// nospill contains registers that we can't spill because
// we already set them up for use by the current instruction.
var nospill regMask
- nospill |= 0x10010 // SP and FP can't be spilled (TODO: arch-specific)
+ nospill |= 0x100000010 // SP and FP can't be spilled (TODO: arch-specific)
// Move inputs into registers
for _, o := range order {
@@ -278,6 +298,8 @@
nospill |= regMask(1) << r
}
+ // TODO: do any clobbering
+
// pick a register for v itself.
if len(outputs) > 1 {
panic("can't do multi-output yet")
diff --git a/src/cmd/compile/internal/ssa/lowerAmd64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go
similarity index 73%
rename from src/cmd/compile/internal/ssa/lowerAmd64.go
rename to src/cmd/compile/internal/ssa/rewriteAMD64.go
index 6b5ff3e..d49245a 100644
--- a/src/cmd/compile/internal/ssa/lowerAmd64.go
+++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go
@@ -1,20 +1,20 @@
-// autogenerated from rulegen/lower_amd64.rules: do not edit!
-// generated with: go run rulegen/rulegen.go rulegen/lower_amd64.rules lowerBlockAMD64 lowerValueAMD64 lowerAmd64.go
+// autogenerated from gen/AMD64.rules: do not edit!
+// generated with: cd gen; go run *.go
package ssa
-func lowerValueAMD64(v *Value, config *Config) bool {
+func rewriteValueAMD64(v *Value, config *Config) bool {
switch v.Op {
- case OpADDQ:
+ case OpAMD64ADDQ:
// match: (ADDQ x (MOVQconst [c]))
// cond:
// result: (ADDQconst [c] x)
{
x := v.Args[0]
- if v.Args[1].Op != OpMOVQconst {
+ if v.Args[1].Op != OpAMD64MOVQconst {
goto endacffd55e74ee0ff59ad58a18ddfc9973
}
c := v.Args[1].Aux
- v.Op = OpADDQconst
+ v.Op = OpAMD64ADDQconst
v.Aux = nil
v.resetArgs()
v.Aux = c
@@ -28,12 +28,12 @@
// cond:
// result: (ADDQconst [c] x)
{
- if v.Args[0].Op != OpMOVQconst {
+ if v.Args[0].Op != OpAMD64MOVQconst {
goto end7166f476d744ab7a51125959d3d3c7e2
}
c := v.Args[0].Aux
x := v.Args[1]
- v.Op = OpADDQconst
+ v.Op = OpAMD64ADDQconst
v.Aux = nil
v.resetArgs()
v.Aux = c
@@ -48,7 +48,7 @@
// result: (LEAQ8 [int64(0)] x y)
{
x := v.Args[0]
- if v.Args[1].Op != OpSHLQconst {
+ if v.Args[1].Op != OpAMD64SHLQconst {
goto endaf4f724e1e17f2b116d336c07da0165d
}
shift := v.Args[1].Aux
@@ -56,7 +56,7 @@
if !(shift.(int64) == 3) {
goto endaf4f724e1e17f2b116d336c07da0165d
}
- v.Op = OpLEAQ8
+ v.Op = OpAMD64LEAQ8
v.Aux = nil
v.resetArgs()
v.Aux = int64(0)
@@ -67,19 +67,19 @@
goto endaf4f724e1e17f2b116d336c07da0165d
endaf4f724e1e17f2b116d336c07da0165d:
;
- case OpADDQconst:
+ case OpAMD64ADDQconst:
// match: (ADDQconst [c] (LEAQ8 [d] x y))
// cond:
// result: (LEAQ8 [addOff(c, d)] x y)
{
c := v.Aux
- if v.Args[0].Op != OpLEAQ8 {
+ if v.Args[0].Op != OpAMD64LEAQ8 {
goto ende2cc681c9abf9913288803fb1b39e639
}
d := v.Args[0].Aux
x := v.Args[0].Args[0]
y := v.Args[0].Args[1]
- v.Op = OpLEAQ8
+ v.Op = OpAMD64LEAQ8
v.Aux = nil
v.resetArgs()
v.Aux = addOff(c, d)
@@ -119,7 +119,7 @@
if !(is64BitInt(t) || isPtr(t)) {
goto endf031c523d7dd08e4b8e7010a94cd94c9
}
- v.Op = OpADDQ
+ v.Op = OpAMD64ADDQ
v.Aux = nil
v.resetArgs()
v.AddArg(x)
@@ -139,7 +139,7 @@
if !(is32BitInt(t)) {
goto end35a02a1587264e40cf1055856ff8445a
}
- v.Op = OpADDL
+ v.Op = OpAMD64ADDL
v.Aux = nil
v.resetArgs()
v.AddArg(x)
@@ -149,17 +149,17 @@
goto end35a02a1587264e40cf1055856ff8445a
end35a02a1587264e40cf1055856ff8445a:
;
- case OpCMPQ:
+ case OpAMD64CMPQ:
// match: (CMPQ x (MOVQconst [c]))
// cond:
// result: (CMPQconst x [c])
{
x := v.Args[0]
- if v.Args[1].Op != OpMOVQconst {
+ if v.Args[1].Op != OpAMD64MOVQconst {
goto end32ef1328af280ac18fa8045a3502dae9
}
c := v.Args[1].Aux
- v.Op = OpCMPQconst
+ v.Op = OpAMD64CMPQconst
v.Aux = nil
v.resetArgs()
v.AddArg(x)
@@ -173,15 +173,15 @@
// cond:
// result: (InvertFlags (CMPQconst <TypeFlags> x [c]))
{
- if v.Args[0].Op != OpMOVQconst {
+ if v.Args[0].Op != OpAMD64MOVQconst {
goto endf8ca12fe79290bc82b11cfa463bc9413
}
c := v.Args[0].Aux
x := v.Args[1]
- v.Op = OpInvertFlags
+ v.Op = OpAMD64InvertFlags
v.Aux = nil
v.resetArgs()
- v0 := v.Block.NewValue(OpCMPQconst, TypeInvalid, nil)
+ v0 := v.Block.NewValue(OpAMD64CMPQconst, TypeInvalid, nil)
v0.Type = TypeFlags
v0.AddArg(x)
v0.Aux = c
@@ -201,7 +201,7 @@
if !(is64BitInt(t)) {
goto end7f5c5b34093fbc6860524cb803ee51bf
}
- v.Op = OpMOVQconst
+ v.Op = OpAMD64MOVQconst
v.Aux = nil
v.resetArgs()
v.Aux = val
@@ -216,7 +216,7 @@
// result: (LEAQglobal [GlobalOffset{sym,0}])
{
sym := v.Aux
- v.Op = OpLEAQglobal
+ v.Op = OpAMD64LEAQglobal
v.Aux = nil
v.resetArgs()
v.Aux = GlobalOffset{sym, 0}
@@ -232,10 +232,10 @@
{
idx := v.Args[0]
len := v.Args[1]
- v.Op = OpSETB
+ v.Op = OpAMD64SETB
v.Aux = nil
v.resetArgs()
- v0 := v.Block.NewValue(OpCMPQ, TypeInvalid, nil)
+ v0 := v.Block.NewValue(OpAMD64CMPQ, TypeInvalid, nil)
v0.Type = TypeFlags
v0.AddArg(idx)
v0.AddArg(len)
@@ -251,10 +251,10 @@
// result: (SETNE (TESTQ <TypeFlags> p p))
{
p := v.Args[0]
- v.Op = OpSETNE
+ v.Op = OpAMD64SETNE
v.Aux = nil
v.resetArgs()
- v0 := v.Block.NewValue(OpTESTQ, TypeInvalid, nil)
+ v0 := v.Block.NewValue(OpAMD64TESTQ, TypeInvalid, nil)
v0.Type = TypeFlags
v0.AddArg(p)
v0.AddArg(p)
@@ -274,10 +274,10 @@
if !(is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type)) {
goto endcecf13a952d4c6c2383561c7d68a3cf9
}
- v.Op = OpSETL
+ v.Op = OpAMD64SETL
v.Aux = nil
v.resetArgs()
- v0 := v.Block.NewValue(OpCMPQ, TypeInvalid, nil)
+ v0 := v.Block.NewValue(OpAMD64CMPQ, TypeInvalid, nil)
v0.Type = TypeFlags
v0.AddArg(x)
v0.AddArg(y)
@@ -298,7 +298,7 @@
if !(t.IsBoolean()) {
goto end73f21632e56c3614902d3c29c82dc4ea
}
- v.Op = OpMOVBload
+ v.Op = OpAMD64MOVBload
v.Aux = nil
v.resetArgs()
v.Aux = int64(0)
@@ -319,7 +319,7 @@
if !(is64BitInt(t) || isPtr(t)) {
goto end581ce5a20901df1b8143448ba031685b
}
- v.Op = OpMOVQload
+ v.Op = OpAMD64MOVQload
v.Aux = nil
v.resetArgs()
v.Aux = int64(0)
@@ -341,7 +341,7 @@
if !(is64BitInt(t)) {
goto end9f05c9539e51db6ad557989e0c822e9b
}
- v.Op = OpSHLQ
+ v.Op = OpAMD64SHLQ
v.Aux = nil
v.resetArgs()
v.AddArg(x)
@@ -351,19 +351,19 @@
goto end9f05c9539e51db6ad557989e0c822e9b
end9f05c9539e51db6ad557989e0c822e9b:
;
- case OpMOVQload:
+ case OpAMD64MOVQload:
// match: (MOVQload [off1] (ADDQconst [off2] ptr) mem)
// cond:
// result: (MOVQload [addOff(off1, off2)] ptr mem)
{
off1 := v.Aux
- if v.Args[0].Op != OpADDQconst {
+ if v.Args[0].Op != OpAMD64ADDQconst {
goto end843d29b538c4483b432b632e5666d6e3
}
off2 := v.Args[0].Aux
ptr := v.Args[0].Args[0]
mem := v.Args[1]
- v.Op = OpMOVQload
+ v.Op = OpAMD64MOVQload
v.Aux = nil
v.resetArgs()
v.Aux = addOff(off1, off2)
@@ -379,14 +379,14 @@
// result: (MOVQloadidx8 [addOff(off1, off2)] ptr idx mem)
{
off1 := v.Aux
- if v.Args[0].Op != OpLEAQ8 {
+ if v.Args[0].Op != OpAMD64LEAQ8 {
goto end02f5ad148292c46463e7c20d3b821735
}
off2 := v.Args[0].Aux
ptr := v.Args[0].Args[0]
idx := v.Args[0].Args[1]
mem := v.Args[1]
- v.Op = OpMOVQloadidx8
+ v.Op = OpAMD64MOVQloadidx8
v.Aux = nil
v.resetArgs()
v.Aux = addOff(off1, off2)
@@ -398,20 +398,20 @@
goto end02f5ad148292c46463e7c20d3b821735
end02f5ad148292c46463e7c20d3b821735:
;
- case OpMOVQloadidx8:
+ case OpAMD64MOVQloadidx8:
// match: (MOVQloadidx8 [off1] (ADDQconst [off2] ptr) idx mem)
// cond:
// result: (MOVQloadidx8 [addOff(off1, off2)] ptr idx mem)
{
off1 := v.Aux
- if v.Args[0].Op != OpADDQconst {
+ if v.Args[0].Op != OpAMD64ADDQconst {
goto ende81e44bcfb11f90916ccb440c590121f
}
off2 := v.Args[0].Aux
ptr := v.Args[0].Args[0]
idx := v.Args[1]
mem := v.Args[2]
- v.Op = OpMOVQloadidx8
+ v.Op = OpAMD64MOVQloadidx8
v.Aux = nil
v.resetArgs()
v.Aux = addOff(off1, off2)
@@ -423,20 +423,20 @@
goto ende81e44bcfb11f90916ccb440c590121f
ende81e44bcfb11f90916ccb440c590121f:
;
- case OpMOVQstore:
+ case OpAMD64MOVQstore:
// match: (MOVQstore [off1] (ADDQconst [off2] ptr) val mem)
// cond:
// result: (MOVQstore [addOff(off1, off2)] ptr val mem)
{
off1 := v.Aux
- if v.Args[0].Op != OpADDQconst {
+ if v.Args[0].Op != OpAMD64ADDQconst {
goto end2108c693a43c79aed10b9246c39c80aa
}
off2 := v.Args[0].Aux
ptr := v.Args[0].Args[0]
val := v.Args[1]
mem := v.Args[2]
- v.Op = OpMOVQstore
+ v.Op = OpAMD64MOVQstore
v.Aux = nil
v.resetArgs()
v.Aux = addOff(off1, off2)
@@ -453,7 +453,7 @@
// result: (MOVQstoreidx8 [addOff(off1, off2)] ptr idx val mem)
{
off1 := v.Aux
- if v.Args[0].Op != OpLEAQ8 {
+ if v.Args[0].Op != OpAMD64LEAQ8 {
goto endce1db8c8d37c8397c500a2068a65c215
}
off2 := v.Args[0].Aux
@@ -461,7 +461,7 @@
idx := v.Args[0].Args[1]
val := v.Args[1]
mem := v.Args[2]
- v.Op = OpMOVQstoreidx8
+ v.Op = OpAMD64MOVQstoreidx8
v.Aux = nil
v.resetArgs()
v.Aux = addOff(off1, off2)
@@ -474,13 +474,13 @@
goto endce1db8c8d37c8397c500a2068a65c215
endce1db8c8d37c8397c500a2068a65c215:
;
- case OpMOVQstoreidx8:
+ case OpAMD64MOVQstoreidx8:
// match: (MOVQstoreidx8 [off1] (ADDQconst [off2] ptr) idx val mem)
// cond:
// result: (MOVQstoreidx8 [addOff(off1, off2)] ptr idx val mem)
{
off1 := v.Aux
- if v.Args[0].Op != OpADDQconst {
+ if v.Args[0].Op != OpAMD64ADDQconst {
goto end01c970657b0fdefeab82458c15022163
}
off2 := v.Args[0].Aux
@@ -488,7 +488,7 @@
idx := v.Args[1]
val := v.Args[2]
mem := v.Args[3]
- v.Op = OpMOVQstoreidx8
+ v.Op = OpAMD64MOVQstoreidx8
v.Aux = nil
v.resetArgs()
v.Aux = addOff(off1, off2)
@@ -501,20 +501,20 @@
goto end01c970657b0fdefeab82458c15022163
end01c970657b0fdefeab82458c15022163:
;
- case OpMULQ:
+ case OpAMD64MULQ:
// match: (MULQ x (MOVQconst [c]))
// cond: c.(int64) == int64(int32(c.(int64)))
// result: (MULQconst [c] x)
{
x := v.Args[0]
- if v.Args[1].Op != OpMOVQconst {
+ if v.Args[1].Op != OpAMD64MOVQconst {
goto ende8c09b194fcde7d9cdc69f2deff86304
}
c := v.Args[1].Aux
if !(c.(int64) == int64(int32(c.(int64)))) {
goto ende8c09b194fcde7d9cdc69f2deff86304
}
- v.Op = OpMULQconst
+ v.Op = OpAMD64MULQconst
v.Aux = nil
v.resetArgs()
v.Aux = c
@@ -528,12 +528,12 @@
// cond:
// result: (MULQconst [c] x)
{
- if v.Args[0].Op != OpMOVQconst {
+ if v.Args[0].Op != OpAMD64MOVQconst {
goto endc6e18d6968175d6e58eafa6dcf40c1b8
}
c := v.Args[0].Aux
x := v.Args[1]
- v.Op = OpMULQconst
+ v.Op = OpAMD64MULQconst
v.Aux = nil
v.resetArgs()
v.Aux = c
@@ -543,7 +543,7 @@
goto endc6e18d6968175d6e58eafa6dcf40c1b8
endc6e18d6968175d6e58eafa6dcf40c1b8:
;
- case OpMULQconst:
+ case OpAMD64MULQconst:
// match: (MULQconst [c] x)
// cond: c.(int64) == 8
// result: (SHLQconst [int64(3)] x)
@@ -553,7 +553,7 @@
if !(c.(int64) == 8) {
goto end7e16978c56138324ff2abf91fd6d94d4
}
- v.Op = OpSHLQconst
+ v.Op = OpAMD64SHLQconst
v.Aux = nil
v.resetArgs()
v.Aux = int64(3)
@@ -572,7 +572,7 @@
if !(c.(int64) == 64) {
goto end2c7a02f230e4b311ac3a4e22f70a4f08
}
- v.Op = OpSHLQconst
+ v.Op = OpAMD64SHLQconst
v.Aux = nil
v.resetArgs()
v.Aux = int64(5)
@@ -591,7 +591,7 @@
dst := v.Args[0]
src := v.Args[1]
mem := v.Args[2]
- v.Op = OpREPMOVSB
+ v.Op = OpAMD64REPMOVSB
v.Aux = nil
v.resetArgs()
v.AddArg(dst)
@@ -617,7 +617,7 @@
if !(is64BitInt(t)) {
goto endfab0d598f376ecba45a22587d50f7aff
}
- v.Op = OpMULQ
+ v.Op = OpAMD64MULQ
v.Aux = nil
v.resetArgs()
v.AddArg(x)
@@ -634,7 +634,7 @@
{
off := v.Aux
ptr := v.Args[0]
- v.Op = OpADDQconst
+ v.Op = OpAMD64ADDQconst
v.Aux = nil
v.resetArgs()
v.Aux = off
@@ -644,16 +644,16 @@
goto end0429f947ee7ac49ff45a243e461a5290
end0429f947ee7ac49ff45a243e461a5290:
;
- case OpSETG:
+ case OpAMD64SETG:
// match: (SETG (InvertFlags x))
// cond:
// result: (SETL x)
{
- if v.Args[0].Op != OpInvertFlags {
+ if v.Args[0].Op != OpAMD64InvertFlags {
goto endf7586738694c9cd0b74ae28bbadb649f
}
x := v.Args[0].Args[0]
- v.Op = OpSETL
+ v.Op = OpAMD64SETL
v.Aux = nil
v.resetArgs()
v.AddArg(x)
@@ -662,16 +662,16 @@
goto endf7586738694c9cd0b74ae28bbadb649f
endf7586738694c9cd0b74ae28bbadb649f:
;
- case OpSETL:
+ case OpAMD64SETL:
// match: (SETL (InvertFlags x))
// cond:
// result: (SETG x)
{
- if v.Args[0].Op != OpInvertFlags {
+ if v.Args[0].Op != OpAMD64InvertFlags {
goto ende33160cd86b9d4d3b77e02fb4658d5d3
}
x := v.Args[0].Args[0]
- v.Op = OpSETG
+ v.Op = OpAMD64SETG
v.Aux = nil
v.resetArgs()
v.AddArg(x)
@@ -680,17 +680,17 @@
goto ende33160cd86b9d4d3b77e02fb4658d5d3
ende33160cd86b9d4d3b77e02fb4658d5d3:
;
- case OpSHLQ:
+ case OpAMD64SHLQ:
// match: (SHLQ x (MOVQconst [c]))
// cond:
// result: (SHLQconst [c] x)
{
x := v.Args[0]
- if v.Args[1].Op != OpMOVQconst {
+ if v.Args[1].Op != OpAMD64MOVQconst {
goto endcca412bead06dc3d56ef034a82d184d6
}
c := v.Args[1].Aux
- v.Op = OpSHLQconst
+ v.Op = OpAMD64SHLQconst
v.Aux = nil
v.resetArgs()
v.Aux = c
@@ -700,17 +700,17 @@
goto endcca412bead06dc3d56ef034a82d184d6
endcca412bead06dc3d56ef034a82d184d6:
;
- case OpSUBQ:
+ case OpAMD64SUBQ:
// match: (SUBQ x (MOVQconst [c]))
// cond:
// result: (SUBQconst x [c])
{
x := v.Args[0]
- if v.Args[1].Op != OpMOVQconst {
+ if v.Args[1].Op != OpAMD64MOVQconst {
goto end5a74a63bd9ad15437717c6df3b25eebb
}
c := v.Args[1].Aux
- v.Op = OpSUBQconst
+ v.Op = OpAMD64SUBQconst
v.Aux = nil
v.resetArgs()
v.AddArg(x)
@@ -725,15 +725,15 @@
// result: (NEGQ (SUBQconst <t> x [c]))
{
t := v.Type
- if v.Args[0].Op != OpMOVQconst {
+ if v.Args[0].Op != OpAMD64MOVQconst {
goto end78e66b6fc298684ff4ac8aec5ce873c9
}
c := v.Args[0].Aux
x := v.Args[1]
- v.Op = OpNEGQ
+ v.Op = OpAMD64NEGQ
v.Aux = nil
v.resetArgs()
- v0 := v.Block.NewValue(OpSUBQconst, TypeInvalid, nil)
+ v0 := v.Block.NewValue(OpAMD64SUBQconst, TypeInvalid, nil)
v0.Type = t
v0.AddArg(x)
v0.Aux = c
@@ -754,7 +754,7 @@
if !(is64BitInt(val.Type) || isPtr(val.Type)) {
goto end9680b43f504bc06f9fab000823ce471a
}
- v.Op = OpMOVQstore
+ v.Op = OpAMD64MOVQstore
v.Aux = nil
v.resetArgs()
v.Aux = int64(0)
@@ -777,7 +777,7 @@
if !(is64BitInt(t)) {
goto ende6ef29f885a8ecf3058212bb95917323
}
- v.Op = OpSUBQ
+ v.Op = OpAMD64SUBQ
v.Aux = nil
v.resetArgs()
v.AddArg(x)
@@ -789,145 +789,145 @@
}
return false
}
-func lowerBlockAMD64(b *Block) bool {
+func rewriteBlockAMD64(b *Block) bool {
switch b.Kind {
- case BlockEQ:
- // match: (BlockEQ (InvertFlags cmp) yes no)
+ case BlockAMD64EQ:
+ // match: (EQ (InvertFlags cmp) yes no)
// cond:
- // result: (BlockEQ cmp yes no)
+ // result: (EQ cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto endea853c6aba26aace57cc8951d332ebe9
+ if v.Op != OpAMD64InvertFlags {
+ goto end6b8e9afc73b1c4d528f31a60d2575fae
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockEQ
+ b.Kind = BlockAMD64EQ
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto endea853c6aba26aace57cc8951d332ebe9
- endea853c6aba26aace57cc8951d332ebe9:
+ goto end6b8e9afc73b1c4d528f31a60d2575fae
+ end6b8e9afc73b1c4d528f31a60d2575fae:
;
- case BlockGE:
- // match: (BlockGE (InvertFlags cmp) yes no)
+ case BlockAMD64GE:
+ // match: (GE (InvertFlags cmp) yes no)
// cond:
- // result: (BlockLE cmp yes no)
+ // result: (LE cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto end608065f88da8bcb570f716698fd7c5c7
+ if v.Op != OpAMD64InvertFlags {
+ goto end0610f000a6988ee8310307ec2ea138f8
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockLE
+ b.Kind = BlockAMD64LE
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto end608065f88da8bcb570f716698fd7c5c7
- end608065f88da8bcb570f716698fd7c5c7:
+ goto end0610f000a6988ee8310307ec2ea138f8
+ end0610f000a6988ee8310307ec2ea138f8:
;
- case BlockGT:
- // match: (BlockGT (InvertFlags cmp) yes no)
+ case BlockAMD64GT:
+ // match: (GT (InvertFlags cmp) yes no)
// cond:
- // result: (BlockLT cmp yes no)
+ // result: (LT cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto ende1758ce91e7231fd66db6bb988856b14
+ if v.Op != OpAMD64InvertFlags {
+ goto endf60c0660b6a8aa9565c97fc87f04eb34
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockLT
+ b.Kind = BlockAMD64LT
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto ende1758ce91e7231fd66db6bb988856b14
- ende1758ce91e7231fd66db6bb988856b14:
+ goto endf60c0660b6a8aa9565c97fc87f04eb34
+ endf60c0660b6a8aa9565c97fc87f04eb34:
;
case BlockIf:
- // match: (BlockIf (SETL cmp) yes no)
+ // match: (If (SETL cmp) yes no)
// cond:
- // result: (BlockLT cmp yes no)
+ // result: (LT cmp yes no)
{
v := b.Control
- if v.Op != OpSETL {
- goto endc6a5d98127b4b8aff782f6981348c864
+ if v.Op != OpAMD64SETL {
+ goto ende4d36879bb8e1bd8facaa8c91ba99dcc
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockLT
+ b.Kind = BlockAMD64LT
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto endc6a5d98127b4b8aff782f6981348c864
- endc6a5d98127b4b8aff782f6981348c864:
+ goto ende4d36879bb8e1bd8facaa8c91ba99dcc
+ ende4d36879bb8e1bd8facaa8c91ba99dcc:
;
- // match: (BlockIf (SETNE cmp) yes no)
+ // match: (If (SETNE cmp) yes no)
// cond:
- // result: (BlockNE cmp yes no)
+ // result: (NE cmp yes no)
{
v := b.Control
- if v.Op != OpSETNE {
- goto end49bd2f760f561c30c85c3342af06753b
+ if v.Op != OpAMD64SETNE {
+ goto end5ff1403aaf7b543bc454177ab584e4f5
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockNE
+ b.Kind = BlockAMD64NE
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto end49bd2f760f561c30c85c3342af06753b
- end49bd2f760f561c30c85c3342af06753b:
+ goto end5ff1403aaf7b543bc454177ab584e4f5
+ end5ff1403aaf7b543bc454177ab584e4f5:
;
- // match: (BlockIf (SETB cmp) yes no)
+ // match: (If (SETB cmp) yes no)
// cond:
- // result: (BlockULT cmp yes no)
+ // result: (ULT cmp yes no)
{
v := b.Control
- if v.Op != OpSETB {
- goto end4754c856495bfc5769799890d639a627
+ if v.Op != OpAMD64SETB {
+ goto end04935012db9defeafceef8175f803ea2
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockULT
+ b.Kind = BlockAMD64ULT
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto end4754c856495bfc5769799890d639a627
- end4754c856495bfc5769799890d639a627:
+ goto end04935012db9defeafceef8175f803ea2
+ end04935012db9defeafceef8175f803ea2:
;
- // match: (BlockIf cond yes no)
- // cond: cond.Op == OpMOVBload
- // result: (BlockNE (TESTB <TypeFlags> cond cond) yes no)
+ // match: (If cond yes no)
+ // cond: cond.Op == OpAMD64MOVBload
+ // result: (NE (TESTB <TypeFlags> cond cond) yes no)
{
v := b.Control
cond := v
yes := b.Succs[0]
no := b.Succs[1]
- if !(cond.Op == OpMOVBload) {
- goto end3a3c83af305cf35c49cb10183b4c6425
+ if !(cond.Op == OpAMD64MOVBload) {
+ goto end7e22019fb0effc80f85c05ea30bdb5d9
}
- b.Kind = BlockNE
- v0 := v.Block.NewValue(OpTESTB, TypeInvalid, nil)
+ b.Kind = BlockAMD64NE
+ v0 := v.Block.NewValue(OpAMD64TESTB, TypeInvalid, nil)
v0.Type = TypeFlags
v0.AddArg(cond)
v0.AddArg(cond)
@@ -936,155 +936,155 @@
b.Succs[1] = no
return true
}
- goto end3a3c83af305cf35c49cb10183b4c6425
- end3a3c83af305cf35c49cb10183b4c6425:
+ goto end7e22019fb0effc80f85c05ea30bdb5d9
+ end7e22019fb0effc80f85c05ea30bdb5d9:
;
- case BlockLE:
- // match: (BlockLE (InvertFlags cmp) yes no)
+ case BlockAMD64LE:
+ // match: (LE (InvertFlags cmp) yes no)
// cond:
- // result: (BlockGE cmp yes no)
+ // result: (GE cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto end6e761e611859351c15da0d249c3771f7
+ if v.Op != OpAMD64InvertFlags {
+ goto end0d49d7d087fe7578e8015cf13dae37e3
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockGE
+ b.Kind = BlockAMD64GE
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto end6e761e611859351c15da0d249c3771f7
- end6e761e611859351c15da0d249c3771f7:
+ goto end0d49d7d087fe7578e8015cf13dae37e3
+ end0d49d7d087fe7578e8015cf13dae37e3:
;
- case BlockLT:
- // match: (BlockLT (InvertFlags cmp) yes no)
+ case BlockAMD64LT:
+ // match: (LT (InvertFlags cmp) yes no)
// cond:
- // result: (BlockGT cmp yes no)
+ // result: (GT cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto endb269f9644dffd5a416ba236545ee2524
+ if v.Op != OpAMD64InvertFlags {
+ goto end6a408cde0fee0ae7b7da0443c8d902bf
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockGT
+ b.Kind = BlockAMD64GT
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto endb269f9644dffd5a416ba236545ee2524
- endb269f9644dffd5a416ba236545ee2524:
+ goto end6a408cde0fee0ae7b7da0443c8d902bf
+ end6a408cde0fee0ae7b7da0443c8d902bf:
;
- case BlockNE:
- // match: (BlockNE (InvertFlags cmp) yes no)
+ case BlockAMD64NE:
+ // match: (NE (InvertFlags cmp) yes no)
// cond:
- // result: (BlockNE cmp yes no)
+ // result: (NE cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto endc41d56a60f8ab211baa2bf0360b7b286
+ if v.Op != OpAMD64InvertFlags {
+ goto end713001aba794e50b582fbff930e110af
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockNE
+ b.Kind = BlockAMD64NE
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto endc41d56a60f8ab211baa2bf0360b7b286
- endc41d56a60f8ab211baa2bf0360b7b286:
+ goto end713001aba794e50b582fbff930e110af
+ end713001aba794e50b582fbff930e110af:
;
- case BlockUGE:
- // match: (BlockUGE (InvertFlags cmp) yes no)
+ case BlockAMD64UGE:
+ // match: (UGE (InvertFlags cmp) yes no)
// cond:
- // result: (BlockULE cmp yes no)
+ // result: (ULE cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto end9ae511e4f4e81005ae1f3c1e5941ba3c
+ if v.Op != OpAMD64InvertFlags {
+ goto ende3e4ddc183ca1a46598b11c2d0d13966
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockULE
+ b.Kind = BlockAMD64ULE
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto end9ae511e4f4e81005ae1f3c1e5941ba3c
- end9ae511e4f4e81005ae1f3c1e5941ba3c:
+ goto ende3e4ddc183ca1a46598b11c2d0d13966
+ ende3e4ddc183ca1a46598b11c2d0d13966:
;
- case BlockUGT:
- // match: (BlockUGT (InvertFlags cmp) yes no)
+ case BlockAMD64UGT:
+ // match: (UGT (InvertFlags cmp) yes no)
// cond:
- // result: (BlockULT cmp yes no)
+ // result: (ULT cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto end073724a0ca0ec030715dd33049b647e9
+ if v.Op != OpAMD64InvertFlags {
+ goto end49818853af2e5251175d06c62768cae7
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockULT
+ b.Kind = BlockAMD64ULT
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto end073724a0ca0ec030715dd33049b647e9
- end073724a0ca0ec030715dd33049b647e9:
+ goto end49818853af2e5251175d06c62768cae7
+ end49818853af2e5251175d06c62768cae7:
;
- case BlockULE:
- // match: (BlockULE (InvertFlags cmp) yes no)
+ case BlockAMD64ULE:
+ // match: (ULE (InvertFlags cmp) yes no)
// cond:
- // result: (BlockUGE cmp yes no)
+ // result: (UGE cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto end2f53a6da23ace14fb1b9b9896827e62d
+ if v.Op != OpAMD64InvertFlags {
+ goto endd6698aac0d67261293b558c95ea17b4f
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockUGE
+ b.Kind = BlockAMD64UGE
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto end2f53a6da23ace14fb1b9b9896827e62d
- end2f53a6da23ace14fb1b9b9896827e62d:
+ goto endd6698aac0d67261293b558c95ea17b4f
+ endd6698aac0d67261293b558c95ea17b4f:
;
- case BlockULT:
- // match: (BlockULT (InvertFlags cmp) yes no)
+ case BlockAMD64ULT:
+ // match: (ULT (InvertFlags cmp) yes no)
// cond:
- // result: (BlockUGT cmp yes no)
+ // result: (UGT cmp yes no)
{
v := b.Control
- if v.Op != OpInvertFlags {
- goto endbceb44a1ad6c53fb33710fc88be6a679
+ if v.Op != OpAMD64InvertFlags {
+ goto end35105dbc9646f02577167e45ae2f2fd2
}
cmp := v.Args[0]
yes := b.Succs[0]
no := b.Succs[1]
- b.Kind = BlockUGT
+ b.Kind = BlockAMD64UGT
b.Control = cmp
b.Succs[0] = yes
b.Succs[1] = no
return true
}
- goto endbceb44a1ad6c53fb33710fc88be6a679
- endbceb44a1ad6c53fb33710fc88be6a679:
+ goto end35105dbc9646f02577167e45ae2f2fd2
+ end35105dbc9646f02577167e45ae2f2fd2:
}
return false
}
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
new file mode 100644
index 0000000..e9552e6
--- /dev/null
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -0,0 +1,424 @@
+// autogenerated from gen/generic.rules: do not edit!
+// generated with: cd gen; go run *.go
+package ssa
+
+func rewriteValuegeneric(v *Value, config *Config) bool {
+ switch v.Op {
+ case OpAdd:
+ // match: (Add <t> (Const [c]) (Const [d]))
+ // cond: is64BitInt(t)
+ // result: (Const [{c.(int64)+d.(int64)}])
+ {
+ t := v.Type
+ if v.Args[0].Op != OpConst {
+ goto end8d047ed0ae9537b840adc79ea82c6e05
+ }
+ c := v.Args[0].Aux
+ if v.Args[1].Op != OpConst {
+ goto end8d047ed0ae9537b840adc79ea82c6e05
+ }
+ d := v.Args[1].Aux
+ if !(is64BitInt(t)) {
+ goto end8d047ed0ae9537b840adc79ea82c6e05
+ }
+ v.Op = OpConst
+ v.Aux = nil
+ v.resetArgs()
+ v.Aux = c.(int64) + d.(int64)
+ return true
+ }
+ goto end8d047ed0ae9537b840adc79ea82c6e05
+ end8d047ed0ae9537b840adc79ea82c6e05:
+ ;
+ case OpArrayIndex:
+ // match: (ArrayIndex (Load ptr mem) idx)
+ // cond:
+ // result: (Load (PtrIndex <ptr.Type.Elem().Elem().PtrTo()> ptr idx) mem)
+ {
+ if v.Args[0].Op != OpLoad {
+ goto end3809f4c52270a76313e4ea26e6f0b753
+ }
+ ptr := v.Args[0].Args[0]
+ mem := v.Args[0].Args[1]
+ idx := v.Args[1]
+ v.Op = OpLoad
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue(OpPtrIndex, TypeInvalid, nil)
+ v0.Type = ptr.Type.Elem().Elem().PtrTo()
+ v0.AddArg(ptr)
+ v0.AddArg(idx)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ goto end3809f4c52270a76313e4ea26e6f0b753
+ end3809f4c52270a76313e4ea26e6f0b753:
+ ;
+ case OpConst:
+ // match: (Const <t> [s])
+ // cond: t.IsString()
+ // result: (StringMake (OffPtr <TypeBytePtr> [2*config.ptrSize] (Global <TypeBytePtr> [config.fe.StringSym(s.(string))])) (Const <config.Uintptr> [int64(len(s.(string)))]))
+ {
+ t := v.Type
+ s := v.Aux
+ if !(t.IsString()) {
+ goto end8442aa5b3f4e5b840055475883110372
+ }
+ v.Op = OpStringMake
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue(OpOffPtr, TypeInvalid, nil)
+ v0.Type = TypeBytePtr
+ v0.Aux = 2 * config.ptrSize
+ v1 := v.Block.NewValue(OpGlobal, TypeInvalid, nil)
+ v1.Type = TypeBytePtr
+ v1.Aux = config.fe.StringSym(s.(string))
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v2 := v.Block.NewValue(OpConst, TypeInvalid, nil)
+ v2.Type = config.Uintptr
+ v2.Aux = int64(len(s.(string)))
+ v.AddArg(v2)
+ return true
+ }
+ goto end8442aa5b3f4e5b840055475883110372
+ end8442aa5b3f4e5b840055475883110372:
+ ;
+ case OpIsInBounds:
+ // match: (IsInBounds (Const [c]) (Const [d]))
+ // cond:
+ // result: (Const [inBounds(c.(int64),d.(int64))])
+ {
+ if v.Args[0].Op != OpConst {
+ goto enddbd1a394d9b71ee64335361b8384865c
+ }
+ c := v.Args[0].Aux
+ if v.Args[1].Op != OpConst {
+ goto enddbd1a394d9b71ee64335361b8384865c
+ }
+ d := v.Args[1].Aux
+ v.Op = OpConst
+ v.Aux = nil
+ v.resetArgs()
+ v.Aux = inBounds(c.(int64), d.(int64))
+ return true
+ }
+ goto enddbd1a394d9b71ee64335361b8384865c
+ enddbd1a394d9b71ee64335361b8384865c:
+ ;
+ case OpLoad:
+ // match: (Load <t> ptr mem)
+ // cond: t.IsString()
+ // result: (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.ptrSize] ptr) mem))
+ {
+ t := v.Type
+ ptr := v.Args[0]
+ mem := v.Args[1]
+ if !(t.IsString()) {
+ goto endd0afd003b70d726a1c5bbaf51fe06182
+ }
+ v.Op = OpStringMake
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue(OpLoad, TypeInvalid, nil)
+ v0.Type = TypeBytePtr
+ v0.AddArg(ptr)
+ v0.AddArg(mem)
+ v.AddArg(v0)
+ v1 := v.Block.NewValue(OpLoad, TypeInvalid, nil)
+ v1.Type = config.Uintptr
+ v2 := v.Block.NewValue(OpOffPtr, TypeInvalid, nil)
+ v2.Type = TypeBytePtr
+ v2.Aux = config.ptrSize
+ v2.AddArg(ptr)
+ v1.AddArg(v2)
+ v1.AddArg(mem)
+ v.AddArg(v1)
+ return true
+ }
+ goto endd0afd003b70d726a1c5bbaf51fe06182
+ endd0afd003b70d726a1c5bbaf51fe06182:
+ ;
+ case OpMul:
+ // match: (Mul <t> (Const [c]) (Const [d]))
+ // cond: is64BitInt(t)
+ // result: (Const [{c.(int64)*d.(int64)}])
+ {
+ t := v.Type
+ if v.Args[0].Op != OpConst {
+ goto end776610f88cf04f438242d76ed2b14f1c
+ }
+ c := v.Args[0].Aux
+ if v.Args[1].Op != OpConst {
+ goto end776610f88cf04f438242d76ed2b14f1c
+ }
+ d := v.Args[1].Aux
+ if !(is64BitInt(t)) {
+ goto end776610f88cf04f438242d76ed2b14f1c
+ }
+ v.Op = OpConst
+ v.Aux = nil
+ v.resetArgs()
+ v.Aux = c.(int64) * d.(int64)
+ return true
+ }
+ goto end776610f88cf04f438242d76ed2b14f1c
+ end776610f88cf04f438242d76ed2b14f1c:
+ ;
+ case OpPtrIndex:
+ // match: (PtrIndex <t> ptr idx)
+ // cond:
+ // result: (Add ptr (Mul <config.Uintptr> idx (Const <config.Uintptr> [t.Elem().Size()])))
+ {
+ t := v.Type
+ ptr := v.Args[0]
+ idx := v.Args[1]
+ v.Op = OpAdd
+ v.Aux = nil
+ v.resetArgs()
+ v.AddArg(ptr)
+ v0 := v.Block.NewValue(OpMul, TypeInvalid, nil)
+ v0.Type = config.Uintptr
+ v0.AddArg(idx)
+ v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
+ v1.Type = config.Uintptr
+ v1.Aux = t.Elem().Size()
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ return true
+ }
+ goto end88c7c383675420d1581daeb899039fa8
+ end88c7c383675420d1581daeb899039fa8:
+ ;
+ case OpSliceCap:
+ // match: (SliceCap (Load ptr mem))
+ // cond:
+ // result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [int64(config.ptrSize*2)])) mem)
+ {
+ if v.Args[0].Op != OpLoad {
+ goto endc871dcd9a720b4290c9cae78fe147c8a
+ }
+ ptr := v.Args[0].Args[0]
+ mem := v.Args[0].Args[1]
+ v.Op = OpLoad
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue(OpAdd, TypeInvalid, nil)
+ v0.Type = ptr.Type
+ v0.AddArg(ptr)
+ v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
+ v1.Type = config.Uintptr
+ v1.Aux = int64(config.ptrSize * 2)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ goto endc871dcd9a720b4290c9cae78fe147c8a
+ endc871dcd9a720b4290c9cae78fe147c8a:
+ ;
+ case OpSliceLen:
+ // match: (SliceLen (Load ptr mem))
+ // cond:
+ // result: (Load (Add <ptr.Type> ptr (Const <config.Uintptr> [int64(config.ptrSize)])) mem)
+ {
+ if v.Args[0].Op != OpLoad {
+ goto end1eec05e44f5fc8944e7c176f98a74d92
+ }
+ ptr := v.Args[0].Args[0]
+ mem := v.Args[0].Args[1]
+ v.Op = OpLoad
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue(OpAdd, TypeInvalid, nil)
+ v0.Type = ptr.Type
+ v0.AddArg(ptr)
+ v1 := v.Block.NewValue(OpConst, TypeInvalid, nil)
+ v1.Type = config.Uintptr
+ v1.Aux = int64(config.ptrSize)
+ v0.AddArg(v1)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ goto end1eec05e44f5fc8944e7c176f98a74d92
+ end1eec05e44f5fc8944e7c176f98a74d92:
+ ;
+ case OpSlicePtr:
+ // match: (SlicePtr (Load ptr mem))
+ // cond:
+ // result: (Load ptr mem)
+ {
+ if v.Args[0].Op != OpLoad {
+ goto end459613b83f95b65729d45c2ed663a153
+ }
+ ptr := v.Args[0].Args[0]
+ mem := v.Args[0].Args[1]
+ v.Op = OpLoad
+ v.Aux = nil
+ v.resetArgs()
+ v.AddArg(ptr)
+ v.AddArg(mem)
+ return true
+ }
+ goto end459613b83f95b65729d45c2ed663a153
+ end459613b83f95b65729d45c2ed663a153:
+ ;
+ case OpStore:
+ // match: (Store dst (Load <t> src mem) mem)
+ // cond: t.Size() > 8
+ // result: (Move [t.Size()] dst src mem)
+ {
+ dst := v.Args[0]
+ if v.Args[1].Op != OpLoad {
+ goto end324ffb6d2771808da4267f62c854e9c8
+ }
+ t := v.Args[1].Type
+ src := v.Args[1].Args[0]
+ mem := v.Args[1].Args[1]
+ if v.Args[2] != v.Args[1].Args[1] {
+ goto end324ffb6d2771808da4267f62c854e9c8
+ }
+ if !(t.Size() > 8) {
+ goto end324ffb6d2771808da4267f62c854e9c8
+ }
+ v.Op = OpMove
+ v.Aux = nil
+ v.resetArgs()
+ v.Aux = t.Size()
+ v.AddArg(dst)
+ v.AddArg(src)
+ v.AddArg(mem)
+ return true
+ }
+ goto end324ffb6d2771808da4267f62c854e9c8
+ end324ffb6d2771808da4267f62c854e9c8:
+ ;
+ // match: (Store dst str mem)
+ // cond: str.Type.IsString()
+ // result: (Store (OffPtr <TypeBytePtr> [config.ptrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
+ {
+ dst := v.Args[0]
+ str := v.Args[1]
+ mem := v.Args[2]
+ if !(str.Type.IsString()) {
+ goto end410559d97aed8018f820cd88723de442
+ }
+ v.Op = OpStore
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue(OpOffPtr, TypeInvalid, nil)
+ v0.Type = TypeBytePtr
+ v0.Aux = config.ptrSize
+ v0.AddArg(dst)
+ v.AddArg(v0)
+ v1 := v.Block.NewValue(OpStringLen, TypeInvalid, nil)
+ v1.Type = config.Uintptr
+ v1.AddArg(str)
+ v.AddArg(v1)
+ v2 := v.Block.NewValue(OpStore, TypeInvalid, nil)
+ v2.Type = TypeMem
+ v2.AddArg(dst)
+ v3 := v.Block.NewValue(OpStringPtr, TypeInvalid, nil)
+ v3.Type = TypeBytePtr
+ v3.AddArg(str)
+ v2.AddArg(v3)
+ v2.AddArg(mem)
+ v.AddArg(v2)
+ return true
+ }
+ goto end410559d97aed8018f820cd88723de442
+ end410559d97aed8018f820cd88723de442:
+ ;
+ case OpStringLen:
+ // match: (StringLen (StringMake _ len))
+ // cond:
+ // result: len
+ {
+ if v.Args[0].Op != OpStringMake {
+ goto end0d922460b7e5ca88324034f4bd6c027c
+ }
+ len := v.Args[0].Args[1]
+ v.Op = len.Op
+ v.Aux = len.Aux
+ v.resetArgs()
+ v.AddArgs(len.Args...)
+ return true
+ }
+ goto end0d922460b7e5ca88324034f4bd6c027c
+ end0d922460b7e5ca88324034f4bd6c027c:
+ ;
+ case OpStringPtr:
+ // match: (StringPtr (StringMake ptr _))
+ // cond:
+ // result: ptr
+ {
+ if v.Args[0].Op != OpStringMake {
+ goto end061edc5d85c73ad909089af2556d9380
+ }
+ ptr := v.Args[0].Args[0]
+ v.Op = ptr.Op
+ v.Aux = ptr.Aux
+ v.resetArgs()
+ v.AddArgs(ptr.Args...)
+ return true
+ }
+ goto end061edc5d85c73ad909089af2556d9380
+ end061edc5d85c73ad909089af2556d9380:
+ }
+ return false
+}
+func rewriteBlockgeneric(b *Block) bool {
+ switch b.Kind {
+ case BlockIf:
+ // match: (If (Const [c]) yes no)
+ // cond: c.(bool)
+ // result: (Plain nil yes)
+ {
+ v := b.Control
+ if v.Op != OpConst {
+ goto end60cde11c1be8092f493d9cda982445ca
+ }
+ c := v.Aux
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ if !(c.(bool)) {
+ goto end60cde11c1be8092f493d9cda982445ca
+ }
+ removePredecessor(b, no)
+ b.Kind = BlockPlain
+ b.Control = nil
+ b.Succs = b.Succs[:1]
+ b.Succs[0] = yes
+ return true
+ }
+ goto end60cde11c1be8092f493d9cda982445ca
+ end60cde11c1be8092f493d9cda982445ca:
+ ;
+ // match: (If (Const [c]) yes no)
+ // cond: !c.(bool)
+ // result: (Plain nil no)
+ {
+ v := b.Control
+ if v.Op != OpConst {
+ goto endf2a5efbfd2d40dead087c33685c8f30b
+ }
+ c := v.Aux
+ yes := b.Succs[0]
+ no := b.Succs[1]
+ if !(!c.(bool)) {
+ goto endf2a5efbfd2d40dead087c33685c8f30b
+ }
+ removePredecessor(b, yes)
+ b.Kind = BlockPlain
+ b.Control = nil
+ b.Succs = b.Succs[:1]
+ b.Succs[0] = no
+ return true
+ }
+ goto endf2a5efbfd2d40dead087c33685c8f30b
+ endf2a5efbfd2d40dead087c33685c8f30b:
+ }
+ return false
+}
diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go
index dd55d96..a4ce343 100644
--- a/src/cmd/compile/internal/ssa/stackalloc.go
+++ b/src/cmd/compile/internal/ssa/stackalloc.go
@@ -91,12 +91,12 @@
}
// TODO: do this with arch-specific rewrite rules somehow?
switch v.Op {
- case OpADDQ:
+ case OpAMD64ADDQ:
// (ADDQ (FP) x) -> (LEAQ [n] (SP) x)
- v.Op = OpLEAQ
+ v.Op = OpAMD64LEAQ
v.Aux = n
- case OpLEAQ, OpMOVQload, OpMOVQstore, OpMOVBload, OpMOVQloadidx8:
- if v.Op == OpMOVQloadidx8 && i == 1 {
+ case OpAMD64LEAQ, OpAMD64MOVQload, OpAMD64MOVQstore, OpAMD64MOVBload, OpAMD64MOVQloadidx8:
+ if v.Op == OpAMD64MOVQloadidx8 && i == 1 {
// Note: we could do it, but it is probably an error
log.Panicf("can't do FP->SP adjust on index slot of load %s", v.Op)
}
@@ -104,6 +104,7 @@
v.Aux = addOffset(v.Aux.(int64), n)
default:
log.Panicf("can't do FP->SP adjust on %s", v.Op)
+ // TODO: OpCopy -> ADDQ
}
}
}
diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go
index dab6239..08e368a 100644
--- a/src/cmd/compile/internal/ssa/value.go
+++ b/src/cmd/compile/internal/ssa/value.go
@@ -4,10 +4,7 @@
package ssa
-import (
- "fmt"
- "strings"
-)
+import "fmt"
// A Value represents a value in the SSA representation of the program.
// The ID and Type fields must not be modified. The remainder may be modified
@@ -51,7 +48,7 @@
// long form print. v# = opcode <type> [aux] args [: reg]
func (v *Value) LongString() string {
- s := fmt.Sprintf("v%d = %s", v.ID, strings.TrimPrefix(v.Op.String(), "Op"))
+ s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String())
s += " <" + v.Type.String() + ">"
if v.Aux != nil {
s += fmt.Sprintf(" [%v]", v.Aux)