From b0da62903d045f6d3e832ba1181387a1e9ad33f1 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Fri, 29 May 2015 16:20:33 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: Add code to test generated opcode counts Add test handler to count and check generated opcodes. This will be useful for testing that certain optimizations don't regress. Also pass a *Config to the Fun constructor so that compile() works. Change-Id: Iee679e87cf0bc635ddcbe433fc1bd4c1d9c953cc Reviewed-on: https://go-review.googlesource.com/10502 Reviewed-by: Michael Matloob Reviewed-by: Keith Randall --- src/cmd/compile/internal/ssa/deadcode_test.go | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index ced46e524b..f3d5682355 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -9,7 +9,8 @@ import ( ) func TestDeadLoop(t *testing.T) { - fun := Fun("entry", + c := NewConfig("amd64") + fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, ".mem"), Goto("exit")), @@ -38,7 +39,8 @@ func TestDeadLoop(t *testing.T) { } func TestDeadValue(t *testing.T) { - fun := Fun("entry", + c := NewConfig("amd64") + fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, ".mem"), Valu("deadval", OpConst, TypeInt64, int64(37)), @@ -60,7 +62,8 @@ func TestDeadValue(t *testing.T) { } func TestNeverTaken(t *testing.T) { - fun := Fun("entry", + c := NewConfig("amd64") + fun := Fun(c, "entry", Bloc("entry", Valu("cond", OpConst, TypeBool, false), Valu("mem", OpArg, TypeMem, ".mem"), -- cgit v1.3 From a9cec30fdcc549282e0a5d520edb2eaf60f3061a Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 28 May 2015 16:45:33 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: Implement block rewriting rules Change-Id: I47e5349e34fc18118c4d35bf433f875b958cc3e5 Reviewed-on: https://go-review.googlesource.com/10495 Reviewed-by: Alan Donovan --- src/cmd/compile/internal/ssa/TODO | 9 + src/cmd/compile/internal/ssa/block.go | 36 +-- src/cmd/compile/internal/ssa/blockkind_string.go | 24 +- src/cmd/compile/internal/ssa/config.go | 15 +- src/cmd/compile/internal/ssa/deadcode.go | 24 +- src/cmd/compile/internal/ssa/deadcode_test.go | 5 +- src/cmd/compile/internal/ssa/export_test.go | 1 + src/cmd/compile/internal/ssa/fuse.go | 2 +- src/cmd/compile/internal/ssa/generic.go | 57 +++- src/cmd/compile/internal/ssa/lower.go | 92 +----- src/cmd/compile/internal/ssa/lowerAmd64.go | 331 ++++++++++++++++++++- src/cmd/compile/internal/ssa/op.go | 2 +- src/cmd/compile/internal/ssa/op_string.go | 18 +- src/cmd/compile/internal/ssa/opamd64.go | 23 +- src/cmd/compile/internal/ssa/opt.go | 4 +- src/cmd/compile/internal/ssa/rewrite.go | 20 +- src/cmd/compile/internal/ssa/rulegen/generic.rules | 19 ++ .../compile/internal/ssa/rulegen/lower_amd64.rules | 31 +- src/cmd/compile/internal/ssa/rulegen/rulegen.go | 151 ++++++++-- 19 files changed, 658 insertions(+), 206 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO index e3ffdd2692..2ffba17612 100644 --- a/src/cmd/compile/internal/ssa/TODO +++ b/src/cmd/compile/internal/ssa/TODO @@ -34,13 +34,22 @@ Regalloc - Don't spill everything at every basic block boundary. - Allow args and return values to be ssa-able. - Handle 2-address instructions. + - Floating point registers Rewrites - Strength reduction (both arch-indep and arch-dependent?) - Code sequence for shifts >= wordsize - Start another architecture (arm?) + - 64-bit ops on 32-bit machines + - (MOVLstore x m) + to get rid of most of the MOVLQSX. Common-Subexpression Elimination - Make better decision about which value in an equivalence class we should choose to replace other values in that class. - Can we move control values out of their basic block? + +Other + - Make go:generate less painful. Have a subpackage that just has the + generate commands in it? diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go index dcf3676bc2..899d69bc32 100644 --- a/src/cmd/compile/internal/ssa/block.go +++ b/src/cmd/compile/internal/ssa/block.go @@ -48,27 +48,27 @@ type Block struct { // Plain nil [next] // If a boolean Value [then, else] // Call mem [nopanic, panic] (control opcode should be OpCall or OpStaticCall) -type BlockKind int8 +type BlockKind int32 +// block kind ranges const ( - BlockExit BlockKind = iota // 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 + 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 - BlockUnknown - - // 386/amd64 variants of BlockIf that take the flags register as an arg - BlockEQ - BlockNE - BlockLT - BlockLE - BlockGT - BlockGE - BlockULT - BlockULE - BlockUGT - BlockUGE ) //go:generate stringer -type=BlockKind diff --git a/src/cmd/compile/internal/ssa/blockkind_string.go b/src/cmd/compile/internal/ssa/blockkind_string.go index 6204f1948f..60c820c871 100644 --- a/src/cmd/compile/internal/ssa/blockkind_string.go +++ b/src/cmd/compile/internal/ssa/blockkind_string.go @@ -4,13 +4,29 @@ package ssa import "fmt" -const _BlockKind_name = "BlockExitBlockPlainBlockIfBlockCallBlockUnknownBlockEQBlockNEBlockLTBlockLEBlockGTBlockGEBlockULTBlockULEBlockUGTBlockUGE" +const ( + _BlockKind_name_0 = "blockInvalid" + _BlockKind_name_1 = "blockGenericStartBlockExitBlockPlainBlockIfBlockCall" + _BlockKind_name_2 = "blockAMD64StartBlockEQBlockNEBlockLTBlockLEBlockGTBlockGEBlockULTBlockULEBlockUGTBlockUGE" +) -var _BlockKind_index = [...]uint8{0, 9, 19, 26, 35, 47, 54, 61, 68, 75, 82, 89, 97, 105, 113, 121} +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 { - if i < 0 || i+1 >= BlockKind(len(_BlockKind_index)) { + 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) } - return _BlockKind_name[_BlockKind_index[i]:_BlockKind_index[i+1]] } diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 9f1d2a8593..2436554cb5 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -7,10 +7,11 @@ package ssa import "log" type Config struct { - arch string // "amd64", etc. - ptrSize int64 // 4 or 8 - Uintptr Type // pointer arithmetic type - lower func(*Value) bool // lowering function + arch string // "amd64", etc. + ptrSize int64 // 4 or 8 + Uintptr Type // pointer arithmetic type + lowerBlock func(*Block) bool // lowering function + lowerValue func(*Value) bool // lowering function // TODO: more stuff. Compiler flags of interest, ... } @@ -21,10 +22,12 @@ func NewConfig(arch string) *Config { switch arch { case "amd64": c.ptrSize = 8 - c.lower = lowerAmd64 + c.lowerBlock = lowerBlockAMD64 + c.lowerValue = lowerValueAMD64 case "386": c.ptrSize = 4 - c.lower = lowerAmd64 // TODO(khr): full 32-bit support + c.lowerBlock = lowerBlockAMD64 + c.lowerValue = lowerValueAMD64 // TODO(khr): full 32-bit support default: log.Fatalf("arch %s not implemented", arch) } diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index a805861489..ba5d8758d9 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -14,30 +14,10 @@ func deadcode(f *Func) { reachable[f.Entry.ID] = true p := []*Block{f.Entry} // stack-like worklist for len(p) > 0 { - // pop a reachable block + // Pop a reachable block b := p[len(p)-1] p = p[:len(p)-1] - - // constant-fold conditionals - // TODO: rewrite rules instead? - if b.Kind == BlockIf && b.Control.Op == OpConst { - cond := b.Control.Aux.(bool) - var c *Block - if cond { - // then branch is always taken - c = b.Succs[1] - } else { - // else branch is always taken - c = b.Succs[0] - b.Succs[0] = b.Succs[1] - } - b.Succs[1] = nil // aid GC - b.Succs = b.Succs[:1] - removePredecessor(b, c) - b.Kind = BlockPlain - b.Control = nil - } - + // Mark successors as reachable for _, c := range b.Succs { if !reachable[c.ID] { reachable[c.ID] = true diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index f3d5682355..07e017c73a 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -4,9 +4,7 @@ package ssa -import ( - "testing" -) +import "testing" func TestDeadLoop(t *testing.T) { c := NewConfig("amd64") @@ -76,6 +74,7 @@ func TestNeverTaken(t *testing.T) { Exit("mem"))) CheckFunc(fun.f) + Opt(fun.f) Deadcode(fun.f) CheckFunc(fun.f) diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index ab4ab82345..f2e7b0cd10 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -6,4 +6,5 @@ package ssa var CheckFunc = checkFunc var PrintFunc = printFunc +var Opt = opt var Deadcode = deadcode diff --git a/src/cmd/compile/internal/ssa/fuse.go b/src/cmd/compile/internal/ssa/fuse.go index af3e8a8e14..e6bd44d573 100644 --- a/src/cmd/compile/internal/ssa/fuse.go +++ b/src/cmd/compile/internal/ssa/fuse.go @@ -35,7 +35,7 @@ func fuse(f *Func) { } // trash b, just in case - b.Kind = BlockUnknown + b.Kind = blockInvalid b.Values = nil b.Preds = nil b.Succs = nil diff --git a/src/cmd/compile/internal/ssa/generic.go b/src/cmd/compile/internal/ssa/generic.go index 91f9c17d11..dc0323e0c1 100644 --- a/src/cmd/compile/internal/ssa/generic.go +++ b/src/cmd/compile/internal/ssa/generic.go @@ -1,8 +1,8 @@ // autogenerated from rulegen/generic.rules: do not edit! -// generated with: go run rulegen/rulegen.go rulegen/generic.rules genericRules generic.go +// generated with: go run rulegen/rulegen.go rulegen/generic.rules genericBlockRules genericValueRules generic.go package ssa -func genericRules(v *Value) bool { +func genericValueRules(v *Value) bool { switch v.Op { case OpAdd: // match: (Add (Const [c]) (Const [d])) @@ -234,3 +234,56 @@ func genericRules(v *Value) bool { } return false } +func genericBlockRules(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/lower.go b/src/cmd/compile/internal/ssa/lower.go index 44f0b83fa8..ebed4f2607 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -6,12 +6,12 @@ package ssa import "log" -//go:generate go run rulegen/rulegen.go rulegen/lower_amd64.rules lowerAmd64 lowerAmd64.go +//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 - applyRewrite(f, f.Config.lower) + applyRewrite(f, f.Config.lowerBlock, f.Config.lowerValue) // Check for unlowered opcodes, fail if we find one. for _, b := range f.Blocks { @@ -21,92 +21,4 @@ func lower(f *Func) { } } } - - // additional pass for 386/amd64, link condition codes directly to blocks - // TODO: do generically somehow? Special "block" rewrite rules? - for _, b := range f.Blocks { - for { - switch b.Kind { - case BlockIf: - switch b.Control.Op { - case OpSETL: - b.Kind = BlockLT - b.Control = b.Control.Args[0] - continue - case OpSETNE: - b.Kind = BlockNE - b.Control = b.Control.Args[0] - continue - case OpSETB: - b.Kind = BlockULT - b.Control = b.Control.Args[0] - continue - case OpMOVBload: - b.Kind = BlockNE - b.Control = b.NewValue2(OpTESTB, TypeFlags, nil, b.Control, b.Control) - continue - // TODO: others - } - case BlockLT: - if b.Control.Op == OpInvertFlags { - b.Kind = BlockGT - b.Control = b.Control.Args[0] - continue - } - case BlockGT: - if b.Control.Op == OpInvertFlags { - b.Kind = BlockLT - b.Control = b.Control.Args[0] - continue - } - case BlockLE: - if b.Control.Op == OpInvertFlags { - b.Kind = BlockGE - b.Control = b.Control.Args[0] - continue - } - case BlockGE: - if b.Control.Op == OpInvertFlags { - b.Kind = BlockLE - b.Control = b.Control.Args[0] - continue - } - case BlockULT: - if b.Control.Op == OpInvertFlags { - b.Kind = BlockUGT - b.Control = b.Control.Args[0] - continue - } - case BlockUGT: - if b.Control.Op == OpInvertFlags { - b.Kind = BlockULT - b.Control = b.Control.Args[0] - continue - } - case BlockULE: - if b.Control.Op == OpInvertFlags { - b.Kind = BlockUGE - b.Control = b.Control.Args[0] - continue - } - case BlockUGE: - if b.Control.Op == OpInvertFlags { - b.Kind = BlockULE - b.Control = b.Control.Args[0] - continue - } - case BlockEQ: - if b.Control.Op == OpInvertFlags { - b.Control = b.Control.Args[0] - continue - } - case BlockNE: - if b.Control.Op == OpInvertFlags { - b.Control = b.Control.Args[0] - continue - } - } - break - } - } } diff --git a/src/cmd/compile/internal/ssa/lowerAmd64.go b/src/cmd/compile/internal/ssa/lowerAmd64.go index 51cef97b30..a233d42370 100644 --- a/src/cmd/compile/internal/ssa/lowerAmd64.go +++ b/src/cmd/compile/internal/ssa/lowerAmd64.go @@ -1,8 +1,8 @@ // autogenerated from rulegen/lower_amd64.rules: do not edit! -// generated with: go run rulegen/rulegen.go rulegen/lower_amd64.rules lowerAmd64 lowerAmd64.go +// generated with: go run rulegen/rulegen.go rulegen/lower_amd64.rules lowerBlockAMD64 lowerValueAMD64 lowerAmd64.go package ssa -func lowerAmd64(v *Value) bool { +func lowerValueAMD64(v *Value) bool { switch v.Op { case OpADDQ: // match: (ADDQ x (MOVQconst [c])) @@ -644,23 +644,41 @@ func lowerAmd64(v *Value) bool { goto end0429f947ee7ac49ff45a243e461a5290 end0429f947ee7ac49ff45a243e461a5290: ; + case OpSETG: + // match: (SETG (InvertFlags x)) + // cond: + // result: (SETL x) + { + if v.Args[0].Op != OpInvertFlags { + goto endf7586738694c9cd0b74ae28bbadb649f + } + x := v.Args[0].Args[0] + v.Op = OpSETL + v.Aux = nil + v.resetArgs() + v.AddArg(x) + return true + } + goto endf7586738694c9cd0b74ae28bbadb649f + endf7586738694c9cd0b74ae28bbadb649f: + ; case OpSETL: // match: (SETL (InvertFlags x)) // cond: - // result: (SETGE x) + // result: (SETG x) { if v.Args[0].Op != OpInvertFlags { - goto end456c7681d48305698c1ef462d244bdc6 + goto ende33160cd86b9d4d3b77e02fb4658d5d3 } x := v.Args[0].Args[0] - v.Op = OpSETGE + v.Op = OpSETG v.Aux = nil v.resetArgs() v.AddArg(x) return true } - goto end456c7681d48305698c1ef462d244bdc6 - end456c7681d48305698c1ef462d244bdc6: + goto ende33160cd86b9d4d3b77e02fb4658d5d3 + ende33160cd86b9d4d3b77e02fb4658d5d3: ; case OpSHLQ: // match: (SHLQ x (MOVQconst [c])) @@ -771,3 +789,302 @@ func lowerAmd64(v *Value) bool { } return false } +func lowerBlockAMD64(b *Block) bool { + switch b.Kind { + case BlockEQ: + // match: (BlockEQ (InvertFlags cmp) yes no) + // cond: + // result: (BlockEQ cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto endea853c6aba26aace57cc8951d332ebe9 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockEQ + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto endea853c6aba26aace57cc8951d332ebe9 + endea853c6aba26aace57cc8951d332ebe9: + ; + case BlockGE: + // match: (BlockGE (InvertFlags cmp) yes no) + // cond: + // result: (BlockLE cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto end608065f88da8bcb570f716698fd7c5c7 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockLE + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end608065f88da8bcb570f716698fd7c5c7 + end608065f88da8bcb570f716698fd7c5c7: + ; + case BlockGT: + // match: (BlockGT (InvertFlags cmp) yes no) + // cond: + // result: (BlockLT cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto ende1758ce91e7231fd66db6bb988856b14 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockLT + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto ende1758ce91e7231fd66db6bb988856b14 + ende1758ce91e7231fd66db6bb988856b14: + ; + case BlockIf: + // match: (BlockIf (SETL cmp) yes no) + // cond: + // result: (BlockLT cmp yes no) + { + v := b.Control + if v.Op != OpSETL { + goto endc6a5d98127b4b8aff782f6981348c864 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockLT + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto endc6a5d98127b4b8aff782f6981348c864 + endc6a5d98127b4b8aff782f6981348c864: + ; + // match: (BlockIf (SETNE cmp) yes no) + // cond: + // result: (BlockNE cmp yes no) + { + v := b.Control + if v.Op != OpSETNE { + goto end49bd2f760f561c30c85c3342af06753b + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockNE + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end49bd2f760f561c30c85c3342af06753b + end49bd2f760f561c30c85c3342af06753b: + ; + // match: (BlockIf (SETB cmp) yes no) + // cond: + // result: (BlockULT cmp yes no) + { + v := b.Control + if v.Op != OpSETB { + goto end4754c856495bfc5769799890d639a627 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockULT + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end4754c856495bfc5769799890d639a627 + end4754c856495bfc5769799890d639a627: + ; + // match: (BlockIf cond yes no) + // cond: cond.Op == OpMOVBload + // result: (BlockNE (TESTB cond cond) yes no) + { + v := b.Control + cond := v + yes := b.Succs[0] + no := b.Succs[1] + if !(cond.Op == OpMOVBload) { + goto end3a3c83af305cf35c49cb10183b4c6425 + } + b.Kind = BlockNE + v0 := v.Block.NewValue(OpTESTB, TypeInvalid, nil) + v0.Type = TypeFlags + v0.AddArg(cond) + v0.AddArg(cond) + b.Control = v0 + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end3a3c83af305cf35c49cb10183b4c6425 + end3a3c83af305cf35c49cb10183b4c6425: + ; + case BlockLE: + // match: (BlockLE (InvertFlags cmp) yes no) + // cond: + // result: (BlockGE cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto end6e761e611859351c15da0d249c3771f7 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockGE + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end6e761e611859351c15da0d249c3771f7 + end6e761e611859351c15da0d249c3771f7: + ; + case BlockLT: + // match: (BlockLT (InvertFlags cmp) yes no) + // cond: + // result: (BlockGT cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto endb269f9644dffd5a416ba236545ee2524 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockGT + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto endb269f9644dffd5a416ba236545ee2524 + endb269f9644dffd5a416ba236545ee2524: + ; + case BlockNE: + // match: (BlockNE (InvertFlags cmp) yes no) + // cond: + // result: (BlockNE cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto endc41d56a60f8ab211baa2bf0360b7b286 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockNE + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto endc41d56a60f8ab211baa2bf0360b7b286 + endc41d56a60f8ab211baa2bf0360b7b286: + ; + case BlockUGE: + // match: (BlockUGE (InvertFlags cmp) yes no) + // cond: + // result: (BlockULE cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto end9ae511e4f4e81005ae1f3c1e5941ba3c + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockULE + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end9ae511e4f4e81005ae1f3c1e5941ba3c + end9ae511e4f4e81005ae1f3c1e5941ba3c: + ; + case BlockUGT: + // match: (BlockUGT (InvertFlags cmp) yes no) + // cond: + // result: (BlockULT cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto end073724a0ca0ec030715dd33049b647e9 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockULT + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end073724a0ca0ec030715dd33049b647e9 + end073724a0ca0ec030715dd33049b647e9: + ; + case BlockULE: + // match: (BlockULE (InvertFlags cmp) yes no) + // cond: + // result: (BlockUGE cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto end2f53a6da23ace14fb1b9b9896827e62d + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockUGE + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto end2f53a6da23ace14fb1b9b9896827e62d + end2f53a6da23ace14fb1b9b9896827e62d: + ; + case BlockULT: + // match: (BlockULT (InvertFlags cmp) yes no) + // cond: + // result: (BlockUGT cmp yes no) + { + v := b.Control + if v.Op != OpInvertFlags { + goto endbceb44a1ad6c53fb33710fc88be6a679 + } + cmp := v.Args[0] + yes := b.Succs[0] + no := b.Succs[1] + b.Kind = BlockUGT + b.Control = cmp + b.Succs[0] = yes + b.Succs[1] = no + return true + } + goto endbceb44a1ad6c53fb33710fc88be6a679 + endbceb44a1ad6c53fb33710fc88be6a679: + } + return false +} diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 75c655758d..a894e9e16f 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -19,7 +19,7 @@ type Op int32 // Opcode ranges, a generic one and one for each architecture. const ( opInvalid Op = 0 - opGenericBase Op = 1 + 1000*iota + opGenericBase = 1 + 1000*iota opAMD64Base op386Base diff --git a/src/cmd/compile/internal/ssa/op_string.go b/src/cmd/compile/internal/ssa/op_string.go index c8f27bb2e4..2005d332ab 100644 --- a/src/cmd/compile/internal/ssa/op_string.go +++ b/src/cmd/compile/internal/ssa/op_string.go @@ -6,18 +6,14 @@ import "fmt" const ( _Op_name_0 = "opInvalid" - _Op_name_1 = "opGenericBaseOpAddOpSubOpMulOpLshOpRshOpLessOpConstOpArgOpGlobalOpFuncOpFPOpSPOpCopyOpMoveOpPhiOpSliceMakeOpSlicePtrOpSliceLenOpSliceCapOpStringMakeOpStringPtrOpStringLenOpLoadOpStoreOpArrayIndexOpPtrIndexOpIsNonNilOpIsInBoundsOpCallOpStaticCallOpConvertOpConvNopOpOffPtrOpStoreReg8OpLoadReg8OpFwdRefOpGenericEnd" - _Op_name_2 = "opAMD64BaseOpADDQOpADDQconstOpSUBQOpSUBQconstOpMULQOpMULQconstOpSHLQOpSHLQconstOpNEGQOpADDLOpCMPQOpCMPQconstOpTESTQOpTESTBOpSETEQOpSETNEOpSETLOpSETGEOpSETBOpInvertFlagsOpLEAQOpLEAQ2OpLEAQ4OpLEAQ8OpLEAQglobalOpMOVBloadOpMOVBQZXloadOpMOVBQSXloadOpMOVQloadOpMOVQstoreOpMOVQloadidx8OpMOVQstoreidx8OpMOVQloadglobalOpMOVQstoreglobalOpMOVQconstOpREPMOVSB" - _Op_name_3 = "op386Base" - _Op_name_4 = "opMax" + _Op_name_1 = "opGenericStartOpAddOpSubOpMulOpLshOpRshOpLessOpConstOpArgOpGlobalOpFuncOpFPOpSPOpCopyOpMoveOpPhiOpSliceMakeOpSlicePtrOpSliceLenOpSliceCapOpStringMakeOpStringPtrOpStringLenOpLoadOpStoreOpArrayIndexOpPtrIndexOpIsNonNilOpIsInBoundsOpCallOpStaticCallOpConvertOpConvNopOpOffPtrOpStoreReg8OpLoadReg8OpFwdRefOpGenericEnd" + _Op_name_2 = "opAMD64startOpADDQOpADDQconstOpSUBQOpSUBQconstOpMULQOpMULQconstOpSHLQOpSHLQconstOpNEGQOpADDLOpCMPQOpCMPQconstOpTESTQOpTESTBOpSETEQOpSETNEOpSETLOpSETGOpSETGEOpSETBOpInvertFlagsOpLEAQOpLEAQ2OpLEAQ4OpLEAQ8OpLEAQglobalOpMOVBloadOpMOVBQZXloadOpMOVBQSXloadOpMOVQloadOpMOVQstoreOpMOVQloadidx8OpMOVQstoreidx8OpMOVQloadglobalOpMOVQstoreglobalOpMOVQconstOpREPMOVSB" ) var ( _Op_index_0 = [...]uint8{0, 9} - _Op_index_1 = [...]uint16{0, 13, 18, 23, 28, 33, 38, 44, 51, 56, 64, 70, 74, 78, 84, 90, 95, 106, 116, 126, 136, 148, 159, 170, 176, 183, 195, 205, 215, 227, 233, 245, 254, 263, 271, 282, 292, 300, 312} - _Op_index_2 = [...]uint16{0, 11, 17, 28, 34, 45, 51, 62, 68, 79, 85, 91, 97, 108, 115, 122, 129, 136, 142, 149, 155, 168, 174, 181, 188, 195, 207, 217, 230, 243, 253, 264, 278, 293, 309, 326, 337, 347} - _Op_index_3 = [...]uint8{0, 9} - _Op_index_4 = [...]uint8{0, 5} + _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 { @@ -27,13 +23,9 @@ func (i Op) String() string { case 1001 <= i && i <= 1038: i -= 1001 return _Op_name_1[_Op_index_1[i]:_Op_index_1[i+1]] - case 2001 <= i && i <= 2037: + case 2001 <= i && i <= 2038: i -= 2001 return _Op_name_2[_Op_index_2[i]:_Op_index_2[i+1]] - case i == 3001: - return _Op_name_3 - case i == 4001: - return _Op_name_4 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 index 517090992a..665f087b6e 100644 --- a/src/cmd/compile/internal/ssa/opamd64.go +++ b/src/cmd/compile/internal/ssa/opamd64.go @@ -6,6 +6,21 @@ 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 @@ -36,12 +51,16 @@ const ( 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 (OpCMPQ a b)) == (OpCMPQ b a) - // This is a pseudo-op which can't appear in assembly output. + // (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) diff --git a/src/cmd/compile/internal/ssa/opt.go b/src/cmd/compile/internal/ssa/opt.go index ea2bcf0e98..81c1dfcc02 100644 --- a/src/cmd/compile/internal/ssa/opt.go +++ b/src/cmd/compile/internal/ssa/opt.go @@ -6,8 +6,8 @@ package ssa // machine-independent optimization -//go:generate go run rulegen/rulegen.go rulegen/generic.rules genericRules generic.go +//go:generate go run rulegen/rulegen.go rulegen/generic.rules genericBlockRules genericValueRules generic.go func opt(f *Func) { - applyRewrite(f, genericRules) + applyRewrite(f, genericBlockRules, genericValueRules) } diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 671270d7f2..08fad454a9 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -6,10 +6,14 @@ package ssa import "log" -func applyRewrite(f *Func, r func(*Value) bool) { +func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value) bool) { // repeat rewrites until we find no more rewrites + var curb *Block var curv *Value defer func() { + if curb != nil { + log.Printf("panic during rewrite of %s\n", curb.LongString()) + } if curv != nil { log.Printf("panic during rewrite of %s\n", curv.LongString()) // TODO(khr): print source location also @@ -18,6 +22,16 @@ func applyRewrite(f *Func, r func(*Value) bool) { for { change := false for _, b := range f.Blocks { + if b.Control != nil && b.Control.Op == OpCopy { + for b.Control.Op == OpCopy { + b.Control = b.Control.Args[0] + } + } + curb = b + if rb(b) { + change = true + } + curb = nil for _, v := range b.Values { // elide any copies generated during rewriting for i, a := range v.Args { @@ -32,13 +46,13 @@ func applyRewrite(f *Func, r func(*Value) bool) { // apply rewrite function curv = v - if r(v) { + if rv(v) { change = true } + curv = nil } } if !change { - curv = nil return } } diff --git a/src/cmd/compile/internal/ssa/rulegen/generic.rules b/src/cmd/compile/internal/ssa/rulegen/generic.rules index c49d9d9f2e..afc22838dd 100644 --- a/src/cmd/compile/internal/ssa/rulegen/generic.rules +++ b/src/cmd/compile/internal/ssa/rulegen/generic.rules @@ -2,6 +2,22 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// values are specified using the following format: +// (op [aux] arg0 arg1 ...) +// the type and aux fields are optional +// on the matching side +// - the types and aux fields must match if they are specified. +// on the generated side +// - the type of the top-level expression is the same as the one on the left-hand side. +// - the type of any subexpressions must be specified explicitly. +// - aux will be nil if not specified. + +// blocks are specified using the following format: +// (kind controlvalue succ0 succ1 ...) +// controlvalue must be "nil" or a value expression +// succ* fields must be variables +// For now, the generated successors must be a permutation of the matched successors. + // constant folding (Add (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [{c.(int64)+d.(int64)}]) (Mul (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [{c.(int64)*d.(int64)}]) @@ -22,3 +38,6 @@ // big-object moves // TODO: fix size (Store dst (Load 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) diff --git a/src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules b/src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules index dc910b70b1..e86e408525 100644 --- a/src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules +++ b/src/cmd/compile/internal/ssa/rulegen/lower_amd64.rules @@ -2,16 +2,6 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// values are specified using the following format: -// (op [aux] arg0 arg1 ...) -// the type and aux fields are optional -// on the matching side -// - the types and aux fields must match if they are specified. -// on the generated side -// - the type of the top-level expression is the same as the one on the left-hand side. -// - the type of any subexpressions must be specified explicitly. -// - aux will be nil if not specified. - // x86 register conventions: // - Integer types live in the low portion of registers. // Upper portions are correctly extended. @@ -44,6 +34,12 @@ (Const [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 cond cond) yes no) + // Rules below here apply some simple optimizations after lowering. // TODO: Should this be a separate pass? @@ -71,7 +67,8 @@ (ADDQconst [c] (LEAQ8 [d] x y)) -> (LEAQ8 [addOff(c, d)] x y) // reverse ordering of compare instruction -(SETL (InvertFlags x)) -> (SETGE x) +(SETL (InvertFlags x)) -> (SETG x) +(SETG (InvertFlags x)) -> (SETL x) // fold constants into memory operations // Note that this is not always a good idea because if not all the uses of @@ -89,3 +86,15 @@ (MOVQstoreidx8 [off1] (ADDQconst [off2] ptr) idx val mem) -> (MOVQstoreidx8 [addOff(off1, off2)] ptr idx val mem) (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) diff --git a/src/cmd/compile/internal/ssa/rulegen/rulegen.go b/src/cmd/compile/internal/ssa/rulegen/rulegen.go index 4ac930298b..dd99513d96 100644 --- a/src/cmd/compile/internal/ssa/rulegen/rulegen.go +++ b/src/cmd/compile/internal/ssa/rulegen/rulegen.go @@ -7,7 +7,7 @@ // 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 lowerAmd64 lowerAmd64.go" +// Run with something like "go run rulegen.go lower_amd64.rules lowerBlockAmd64 lowerValueAmd64 lowerAmd64.go" package main @@ -47,12 +47,13 @@ import ( // If multiple rules match, the first one in file order is selected. func main() { - if len(os.Args) < 3 || len(os.Args) > 4 { - fmt.Printf("usage: go run rulegen.go []") + if len(os.Args) < 4 || len(os.Args) > 5 { + fmt.Printf("usage: go run rulegen.go []") os.Exit(1) } rulefile := os.Args[1] - rulefn := os.Args[2] + blockfn := os.Args[2] + valuefn := os.Args[3] // Open input file. text, err := os.Open(rulefile) @@ -60,7 +61,8 @@ func main() { log.Fatalf("can't read rule file: %v", err) } - // oprules contains a list of rules for each opcode + // oprules contains a list of rules for each block and opcode + blockrules := map[string][]string{} oprules := map[string][]string{} // read rule file @@ -77,7 +79,11 @@ func main() { continue } op := strings.Split(line, " ")[0][1:] - oprules[op] = append(oprules[op], line) + if strings.HasPrefix(op, "Block") { + blockrules[op] = append(blockrules[op], line) + } else { + oprules[op] = append(oprules[op], line) + } } if err := scanner.Err(); err != nil { log.Fatalf("scanner failed: %v\n", err) @@ -88,7 +94,7 @@ func main() { 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.Fprintln(w, "package ssa") - fmt.Fprintf(w, "func %s(v *Value) bool {\n", rulefn) + fmt.Fprintf(w, "func %s(v *Value) bool {\n", valuefn) // generate code for each rule fmt.Fprintf(w, "switch v.Op {\n") @@ -111,15 +117,15 @@ func main() { if len(s) != 2 { log.Fatalf("no arrow in rule %s", rule) } - lhs := strings.Trim(s[0], " \t") - result := strings.Trim(s[1], " \t\n") + lhs := strings.TrimSpace(s[0]) + result := strings.TrimSpace(s[1]) // split match into matching part and additional condition match := lhs cond := "" if i := strings.Index(match, "&&"); i >= 0 { - cond = strings.Trim(match[i+2:], " \t") - match = strings.Trim(match[:i], " \t") + cond = strings.TrimSpace(match[i+2:]) + match = strings.TrimSpace(match[:i]) } fmt.Fprintf(w, "// match: %s\n", match) @@ -147,6 +153,109 @@ func main() { fmt.Fprintf(w, "return false\n") fmt.Fprintf(w, "}\n") + // Generate block rewrite function. + fmt.Fprintf(w, "func %s(b *Block) bool {\n", blockfn) + fmt.Fprintf(w, "switch b.Kind {\n") + ops = nil + for op := range blockrules { + ops = append(ops, op) + } + sort.Strings(ops) + for _, op := range ops { + fmt.Fprintf(w, "case %s:\n", op) + for _, rule := range blockrules[op] { + rulehash := fmt.Sprintf("%02x", md5.Sum([]byte(rule))) + // split at -> + s := strings.Split(rule, "->") + if len(s) != 2 { + log.Fatalf("no arrow in rule %s", rule) + } + lhs := strings.TrimSpace(s[0]) + result := strings.TrimSpace(s[1]) + + // split match into matching part and additional condition + match := lhs + cond := "" + if i := strings.Index(match, "&&"); i >= 0 { + cond = strings.TrimSpace(match[i+2:]) + match = strings.TrimSpace(match[:i]) + } + + fmt.Fprintf(w, "// match: %s\n", match) + fmt.Fprintf(w, "// cond: %s\n", cond) + fmt.Fprintf(w, "// result: %s\n", result) + + fail := fmt.Sprintf("{\ngoto end%s\n}\n", rulehash) + + fmt.Fprintf(w, "{\n") + s = split(match[1 : len(match)-1]) // remove parens, then split + + // 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) + } + + // assign successor names + succs := s[2:] + for i, a := range succs { + if a != "_" { + fmt.Fprintf(w, "%s := b.Succs[%d]\n", a, i) + } + } + + if cond != "" { + fmt.Fprintf(w, "if !(%s) %s", cond, fail) + } + + // Rule matches. Generate result. + t := split(result[1 : len(result)-1]) // remove parens, then split + newsuccs := t[2:] + + // Check if newsuccs is a subset of succs. + m := map[string]bool{} + for _, succ := range succs { + if m[succ] { + log.Fatalf("can't have a repeat successor name %s in %s", succ, rule) + } + m[succ] = true + } + for _, succ := range newsuccs { + if !m[succ] { + log.Fatalf("unknown successor %s in %s", succ, rule) + } + delete(m, succ) + } + + // Modify predecessor lists for no-longer-reachable blocks + for succ := range m { + fmt.Fprintf(w, "removePredecessor(b, %s)\n", succ) + } + + fmt.Fprintf(w, "b.Kind = %s\n", t[0]) + 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)) + } + if len(newsuccs) < len(succs) { + fmt.Fprintf(w, "b.Succs = b.Succs[:%d]\n", len(newsuccs)) + } + for i, a := range newsuccs { + fmt.Fprintf(w, "b.Succs[%d] = %s\n", i, a) + } + + fmt.Fprintf(w, "return true\n") + + fmt.Fprintf(w, "}\n") + fmt.Fprintf(w, "goto end%s\n", rulehash) // use label + fmt.Fprintf(w, "end%s:;\n", rulehash) + } + } + fmt.Fprintf(w, "}\n") + fmt.Fprintf(w, "return false\n") + fmt.Fprintf(w, "}\n") + // gofmt result b := w.Bytes() b, err = format.Source(b) @@ -155,8 +264,8 @@ func main() { } // Write to a file if given, otherwise stdout. - if len(os.Args) >= 4 { - err = ioutil.WriteFile(os.Args[3], b, 0666) + if len(os.Args) >= 5 { + err = ioutil.WriteFile(os.Args[4], b, 0666) } else { _, err = os.Stdout.Write(b) } @@ -187,7 +296,7 @@ func genMatch0(w io.Writer, match, v, fail string, m map[string]string, top bool // split body up into regions. Split by spaces/tabs, except those // contained in () or {}. - s := split(match[1 : len(match)-1]) + s := split(match[1 : len(match)-1]) // remove parens, then split // check op if !top { @@ -199,7 +308,7 @@ func genMatch0(w io.Writer, match, v, fail string, m map[string]string, top bool for _, a := range s[1:] { if a[0] == '<' { // type restriction - t := a[1 : len(a)-1] + t := a[1 : len(a)-1] // remove <> if t[0] == '{' { // code. We must match the results of this code. fmt.Fprintf(w, "if %s.Type != %s %s", v, t[1:len(t)-1], fail) @@ -215,7 +324,7 @@ func genMatch0(w io.Writer, match, v, fail string, m map[string]string, top bool } } else if a[0] == '[' { // aux restriction - x := a[1 : len(a)-1] + x := a[1 : len(a)-1] // remove [] if x[0] == '{' { // code fmt.Fprintf(w, "if %s.Aux != %s %s", v, x[1:len(x)-1], fail) @@ -254,7 +363,7 @@ func genResult0(w io.Writer, result string, alloc *int, top bool) string { return result } - s := split(result[1 : len(result)-1]) + s := split(result[1 : len(result)-1]) // remove parens, then split var v string var hasType bool if top { @@ -271,17 +380,17 @@ func genResult0(w io.Writer, result string, alloc *int, top bool) string { for _, a := range s[1:] { if a[0] == '<' { // type restriction - t := a[1 : len(a)-1] + t := a[1 : len(a)-1] // remove <> if t[0] == '{' { - t = t[1 : len(t)-1] + t = t[1 : len(t)-1] // remove {} } fmt.Fprintf(w, "%s.Type = %s\n", v, t) hasType = true } else if a[0] == '[' { // aux restriction - x := a[1 : len(a)-1] + x := a[1 : len(a)-1] // remove [] if x[0] == '{' { - x = x[1 : len(x)-1] + x = x[1 : len(x)-1] // remove {} } fmt.Fprintf(w, "%s.Aux = %s\n", v, x) } else if a[0] == '{' { -- cgit v1.3 From 1114a76ae6081242c38614aeb4ff9c37b8be75c4 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 4 Jun 2015 15:18:27 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: Add dummy frontend for testing. Change-Id: Ica26c0297ac7afeb0b5b668cf5f5cd1667c6cc43 Reviewed-on: https://go-review.googlesource.com/10699 Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/ssa/deadcode_test.go | 6 +++--- src/cmd/compile/internal/ssa/export_test.go | 6 ++++++ src/cmd/compile/internal/ssa/func_test.go | 4 ++-- 3 files changed, 11 insertions(+), 5 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index 07e017c73a..10b8976e0f 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -7,7 +7,7 @@ package ssa import "testing" func TestDeadLoop(t *testing.T) { - c := NewConfig("amd64") + c := NewConfig("amd64", DummyFrontend{}) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, ".mem"), @@ -37,7 +37,7 @@ func TestDeadLoop(t *testing.T) { } func TestDeadValue(t *testing.T) { - c := NewConfig("amd64") + c := NewConfig("amd64", DummyFrontend{}) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, ".mem"), @@ -60,7 +60,7 @@ func TestDeadValue(t *testing.T) { } func TestNeverTaken(t *testing.T) { - c := NewConfig("amd64") + c := NewConfig("amd64", DummyFrontend{}) fun := Fun(c, "entry", Bloc("entry", Valu("cond", OpConst, TypeBool, false), diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index f2e7b0cd10..103945a73e 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -8,3 +8,9 @@ var CheckFunc = checkFunc var PrintFunc = printFunc var Opt = opt var Deadcode = deadcode + +type DummyFrontend struct{} + +func (d DummyFrontend) StringSym(s string) interface{} { + return nil +} diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index b66ab24778..c15b167bc1 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -257,7 +257,7 @@ func addEdge(b, c *Block) { } func TestArgs(t *testing.T) { - c := NewConfig("amd64") + c := NewConfig("amd64", DummyFrontend{}) fun := Fun(c, "entry", Bloc("entry", Valu("a", OpConst, TypeInt64, 14), @@ -277,7 +277,7 @@ func TestArgs(t *testing.T) { } func TestEquiv(t *testing.T) { - c := NewConfig("amd64") + c := NewConfig("amd64", DummyFrontend{}) equivalentCases := []struct{ f, g fun }{ // simple case { -- cgit v1.3 From 8f22b5292ffc01ea66bd92fa833d0ec25390173b Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Thu, 11 Jun 2015 21:29:25 -0700 Subject: [dev.ssa] cmd/compiler/internal/ssa: Add auxint field Add an additional int64 auxiliary field to Value. There are two main reasons for doing this: 1) Ints in interfaces require allocation, and we store ints in Aux a lot. 2) I'd like to have both *gc.Sym and int offsets included in lots of operations (e.g. MOVQloadidx8). It will be more efficient to store them as separate fields instead of a pointer to a sym/int pair. It also simplifies a bunch of code. This is just the refactoring. I'll start using this some more in a subsequent changelist. Change-Id: I1ca797ff572553986cf90cab3ac0a0c1d01ad241 Reviewed-on: https://go-review.googlesource.com/10929 Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/gc/ssa.go | 163 +++++---- src/cmd/compile/internal/ssa/deadcode_test.go | 12 +- src/cmd/compile/internal/ssa/deadstore_test.go | 36 +- src/cmd/compile/internal/ssa/func.go | 115 +++++- src/cmd/compile/internal/ssa/func_test.go | 116 +++--- src/cmd/compile/internal/ssa/gen/AMD64.rules | 40 +-- src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 42 +-- src/cmd/compile/internal/ssa/gen/generic.rules | 21 +- src/cmd/compile/internal/ssa/gen/genericOps.go | 8 +- src/cmd/compile/internal/ssa/gen/rulegen.go | 60 ++-- src/cmd/compile/internal/ssa/generic.go | 424 ---------------------- src/cmd/compile/internal/ssa/op.go | 25 -- src/cmd/compile/internal/ssa/regalloc.go | 16 +- src/cmd/compile/internal/ssa/rewrite.go | 7 +- src/cmd/compile/internal/ssa/rewriteAMD64.go | 465 ++++++++++++++----------- src/cmd/compile/internal/ssa/rewritegeneric.go | 162 +++++---- src/cmd/compile/internal/ssa/schedule_test.go | 18 +- src/cmd/compile/internal/ssa/shift_test.go | 16 +- src/cmd/compile/internal/ssa/stackalloc.go | 4 +- src/cmd/compile/internal/ssa/value.go | 9 +- 20 files changed, 756 insertions(+), 1003 deletions(-) delete mode 100644 src/cmd/compile/internal/ssa/generic.go (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index ebb7f44a18..3110fad270 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -38,9 +38,9 @@ func buildssa(fn *Node) *ssa.Func { s.exit = s.f.NewBlock(ssa.BlockExit) // Allocate starting values - s.startmem = s.entryNewValue(ssa.OpArg, ssa.TypeMem, ".mem") - s.fp = s.entryNewValue(ssa.OpFP, s.config.Uintptr, nil) // TODO: use generic pointer type (unsafe.Pointer?) instead - s.sp = s.entryNewValue(ssa.OpSP, s.config.Uintptr, nil) + s.startmem = s.entryNewValue0(ssa.OpArg, ssa.TypeMem) + s.fp = s.entryNewValue0(ssa.OpFP, s.config.Uintptr) // TODO: use generic pointer type (unsafe.Pointer?) instead + s.sp = s.entryNewValue0(ssa.OpSP, s.config.Uintptr) s.vars = map[string]*ssa.Value{} s.labels = map[string]*ssa.Block{} @@ -147,39 +147,59 @@ func (s *state) peekLine() int32 { return s.line[len(s.line)-1] } -// newValue adds a new value with no argueents to the current block. -func (s *state) newValue(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value { - return s.curBlock.NewValue(s.peekLine(), op, t, aux) +// newValue0 adds a new value with no arguments to the current block. +func (s *state) newValue0(op ssa.Op, t ssa.Type) *ssa.Value { + return s.curBlock.NewValue0(s.peekLine(), op, t) +} + +// newValue0A adds a new value with no arguments and an aux value to the current block. +func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value { + return s.curBlock.NewValue0A(s.peekLine(), op, t, aux) } // newValue1 adds a new value with one argument to the current block. -func (s *state) newValue1(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value { - return s.curBlock.NewValue1(s.peekLine(), op, t, aux, arg) +func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value { + return s.curBlock.NewValue1(s.peekLine(), op, t, arg) +} + +// newValue1A adds a new value with one argument and an aux value to the current block. +func (s *state) newValue1A(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value { + return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg) } // newValue2 adds a new value with two arguments to the current block. -func (s *state) newValue2(op ssa.Op, t ssa.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value { - return s.curBlock.NewValue2(s.peekLine(), op, t, aux, arg0, arg1) +func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value { + return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1) } // newValue3 adds a new value with three arguments to the current block. -func (s *state) newValue3(op ssa.Op, t ssa.Type, aux interface{}, arg0, arg1, arg2 *ssa.Value) *ssa.Value { - return s.curBlock.NewValue3(s.peekLine(), op, t, aux, arg0, arg1, arg2) +func (s *state) newValue3(op ssa.Op, t ssa.Type, arg0, arg1, arg2 *ssa.Value) *ssa.Value { + return s.curBlock.NewValue3(s.peekLine(), op, t, arg0, arg1, arg2) } // entryNewValue adds a new value with no arguments to the entry block. -func (s *state) entryNewValue(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value { - return s.f.Entry.NewValue(s.peekLine(), op, t, aux) +func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value { + return s.f.Entry.NewValue0(s.peekLine(), op, t) +} + +// entryNewValue adds a new value with no arguments and an aux value to the entry block. +func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value { + return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux) } // entryNewValue1 adds a new value with one argument to the entry block. -func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, aux interface{}, arg *ssa.Value) *ssa.Value { - return s.f.Entry.NewValue1(s.peekLine(), op, t, aux, arg) +func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value { + return s.f.Entry.NewValue1(s.peekLine(), op, t, arg) +} + +// entryNewValue1 adds a new value with one argument and an auxint value to the entry block. +func (s *state) entryNewValue1I(op ssa.Op, t ssa.Type, auxint int64, arg *ssa.Value) *ssa.Value { + return s.f.Entry.NewValue1I(s.peekLine(), op, t, auxint, arg) } // entryNewValue2 adds a new value with two arguments to the entry block. -func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, aux interface{}, arg0, arg1 *ssa.Value) *ssa.Value { - return s.f.Entry.NewValue2(s.peekLine(), op, t, aux, arg0, arg1) +func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value { + return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1) } // constInt adds a new const int value to the entry block. @@ -234,11 +254,11 @@ func (s *state) stmt(n *Node) { t := n.Left.Type switch { case t.IsString(): - val = s.entryNewValue(ssa.OpConst, n.Left.Type, "") + val = s.entryNewValue0(ssa.OpConst, n.Left.Type) case t.IsInteger(): - val = s.entryNewValue(ssa.OpConst, n.Left.Type, int64(0)) + val = s.entryNewValue0(ssa.OpConst, n.Left.Type) case t.IsBoolean(): - val = s.entryNewValue(ssa.OpConst, n.Left.Type, false) + val = s.entryNewValue0A(ssa.OpConst, n.Left.Type, false) // TODO: store bools as 0/1 in AuxInt? default: log.Fatalf("zero for type %v not implemented", t) } @@ -252,7 +272,7 @@ func (s *state) stmt(n *Node) { } // not ssa-able. Treat as a store. addr := s.addr(n.Left) - s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, nil, addr, val, s.mem()) + s.vars[".mem"] = s.newValue3(ssa.OpStore, ssa.TypeMem, addr, val, s.mem()) case OIF: cond := s.expr(n.Left) b := s.endBlock() @@ -341,20 +361,20 @@ func (s *state) expr(n *Node) *ssa.Value { case ONAME: if n.Class == PFUNC { // "value" of a function is the address of the function's closure - return s.entryNewValue(ssa.OpGlobal, Ptrto(n.Type), funcsym(n.Sym)) + return s.entryNewValue0A(ssa.OpGlobal, Ptrto(n.Type), funcsym(n.Sym)) } s.argOffsets[n.Sym.Name] = n.Xoffset // TODO: remember this another way? if canSSA(n) { return s.variable(n.Sym.Name, n.Type) } addr := s.addr(n) - return s.newValue2(ssa.OpLoad, n.Type, nil, addr, s.mem()) + return s.newValue2(ssa.OpLoad, n.Type, addr, s.mem()) case OLITERAL: switch n.Val().Ctype() { case CTINT: return s.constInt(n.Type, Mpgetfix(n.Val().U.(*Mpint))) case CTSTR: - return s.entryNewValue(ssa.OpConst, n.Type, n.Val().U) + return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U) default: log.Fatalf("unhandled OLITERAL %v", n.Val().Ctype()) return nil @@ -367,24 +387,24 @@ func (s *state) expr(n *Node) *ssa.Value { case OLT: a := s.expr(n.Left) b := s.expr(n.Right) - return s.newValue2(ssa.OpLess, ssa.TypeBool, nil, a, b) + return s.newValue2(ssa.OpLess, ssa.TypeBool, a, b) case OADD: a := s.expr(n.Left) b := s.expr(n.Right) - return s.newValue2(ssa.OpAdd, a.Type, nil, a, b) + return s.newValue2(ssa.OpAdd, a.Type, a, b) case OSUB: // TODO:(khr) fold code for all binary ops together somehow a := s.expr(n.Left) b := s.expr(n.Right) - return s.newValue2(ssa.OpSub, a.Type, nil, a, b) + return s.newValue2(ssa.OpSub, a.Type, a, b) case OLSH: a := s.expr(n.Left) b := s.expr(n.Right) - return s.newValue2(ssa.OpLsh, a.Type, nil, a, b) + return s.newValue2(ssa.OpLsh, a.Type, a, b) case ORSH: a := s.expr(n.Left) b := s.expr(n.Right) - return s.newValue2(ssa.OpRsh, a.Type, nil, a, b) + return s.newValue2(ssa.OpRsh, a.Type, a, b) case OADDR: return s.addr(n.Left) @@ -392,13 +412,13 @@ func (s *state) expr(n *Node) *ssa.Value { case OIND: p := s.expr(n.Left) s.nilCheck(p) - return s.newValue2(ssa.OpLoad, n.Type, nil, p, s.mem()) + return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) case ODOTPTR: p := s.expr(n.Left) s.nilCheck(p) - p = s.newValue2(ssa.OpAdd, p.Type, nil, p, s.constInt(s.config.Uintptr, n.Xoffset)) - return s.newValue2(ssa.OpLoad, n.Type, nil, p, s.mem()) + p = s.newValue2(ssa.OpAdd, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset)) + return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) case OINDEX: if n.Left.Type.Bound >= 0 { // array or string @@ -407,17 +427,17 @@ func (s *state) expr(n *Node) *ssa.Value { var elemtype *Type var len *ssa.Value if n.Left.Type.IsString() { - len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, nil, a) + len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, a) elemtype = Types[TUINT8] } else { len = s.constInt(s.config.Uintptr, n.Left.Type.Bound) elemtype = n.Left.Type.Type } s.boundsCheck(i, len) - return s.newValue2(ssa.OpArrayIndex, elemtype, nil, a, i) + return s.newValue2(ssa.OpArrayIndex, elemtype, a, i) } else { // slice p := s.addr(n) - return s.newValue2(ssa.OpLoad, n.Left.Type.Type, nil, p, s.mem()) + return s.newValue2(ssa.OpLoad, n.Left.Type.Type, p, s.mem()) } case OCALLFUNC: @@ -435,10 +455,10 @@ func (s *state) expr(n *Node) *ssa.Value { bNext := s.f.NewBlock(ssa.BlockPlain) var call *ssa.Value if static { - call = s.newValue1(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem()) + call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, n.Left.Sym, s.mem()) } else { - entry := s.newValue2(ssa.OpLoad, s.config.Uintptr, nil, closure, s.mem()) - call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, nil, entry, closure, s.mem()) + entry := s.newValue2(ssa.OpLoad, s.config.Uintptr, closure, s.mem()) + call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, entry, closure, s.mem()) } b := s.endBlock() b.Kind = ssa.BlockCall @@ -450,8 +470,8 @@ func (s *state) expr(n *Node) *ssa.Value { s.startBlock(bNext) var titer Iter fp := Structfirst(&titer, Getoutarg(n.Left.Type)) - a := s.entryNewValue1(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp) - return s.newValue2(ssa.OpLoad, fp.Type, nil, a, call) + a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp) + return s.newValue2(ssa.OpLoad, fp.Type, a, call) default: log.Fatalf("unhandled expr %s", opnames[n.Op]) return nil @@ -465,10 +485,10 @@ func (s *state) addr(n *Node) *ssa.Value { switch n.Class { case PEXTERN: // global variable - return s.entryNewValue(ssa.OpGlobal, Ptrto(n.Type), n.Sym) + return s.entryNewValue0A(ssa.OpGlobal, Ptrto(n.Type), n.Sym) case PPARAMOUT: // store to parameter slot - return s.entryNewValue1(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.fp) + return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.fp) default: // TODO: address of locals log.Fatalf("variable address of %v not implemented", n) @@ -477,21 +497,21 @@ func (s *state) addr(n *Node) *ssa.Value { case OINDREG: // indirect off a register (TODO: always SP?) // used for storing/loading arguments/returns to/from callees - return s.entryNewValue1(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp) + return s.entryNewValue1I(ssa.OpOffPtr, Ptrto(n.Type), n.Xoffset, s.sp) case OINDEX: if n.Left.Type.Bound >= 0 { // array a := s.addr(n.Left) i := s.expr(n.Right) len := s.constInt(s.config.Uintptr, n.Left.Type.Bound) s.boundsCheck(i, len) - return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), nil, a, i) + return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i) } else { // slice a := s.expr(n.Left) i := s.expr(n.Right) - len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, nil, a) + len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, a) s.boundsCheck(i, len) - p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), nil, a) - return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), nil, p, i) + p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a) + return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i) } default: log.Fatalf("addr: bad op %v", Oconv(int(n.Op), 0)) @@ -524,7 +544,7 @@ func canSSA(n *Node) bool { // nilCheck generates nil pointer checking code. // Starts a new block on return. func (s *state) nilCheck(ptr *ssa.Value) { - c := s.newValue1(ssa.OpIsNonNil, ssa.TypeBool, nil, ptr) + c := s.newValue1(ssa.OpIsNonNil, ssa.TypeBool, ptr) b := s.endBlock() b.Kind = ssa.BlockIf b.Control = c @@ -543,7 +563,7 @@ func (s *state) boundsCheck(idx, len *ssa.Value) { // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero. // bounds check - cmp := s.newValue2(ssa.OpIsInBounds, ssa.TypeBool, nil, idx, len) + cmp := s.newValue2(ssa.OpIsInBounds, ssa.TypeBool, idx, len) b := s.endBlock() b.Kind = ssa.BlockIf b.Control = cmp @@ -562,7 +582,7 @@ func (s *state) variable(name string, t ssa.Type) *ssa.Value { v := s.vars[name] if v == nil { // TODO: get type? Take Sym as arg? - v = s.newValue(ssa.OpFwdRef, t, name) + v = s.newValue0A(ssa.OpFwdRef, t, name) s.vars[name] = v } return v @@ -601,8 +621,8 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name string) *ssa.Va return s.startmem } // variable is live at the entry block. Load it. - addr := s.entryNewValue1(ssa.OpOffPtr, Ptrto(t.(*Type)), s.argOffsets[name], s.fp) - return s.entryNewValue2(ssa.OpLoad, t, nil, addr, s.startmem) + addr := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(t.(*Type)), s.argOffsets[name], s.fp) + return s.entryNewValue2(ssa.OpLoad, t, addr, s.startmem) } var vals []*ssa.Value @@ -613,7 +633,7 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name string) *ssa.Va for i := 1; i < len(vals); i++ { if vals[i] != v0 { // need a phi value - v := b.NewValue(s.peekLine(), ssa.OpPhi, t, nil) + v := b.NewValue0(s.peekLine(), ssa.OpPhi, t) v.AddArgs(vals...) return v } @@ -634,7 +654,7 @@ func (s *state) lookupVarOutgoing(b *ssa.Block, t ssa.Type, name string) *ssa.Va // Make v = copy(w). We need the extra copy to // prevent infinite recursion when looking up the // incoming value of the variable. - v := b.NewValue(s.peekLine(), ssa.OpCopy, t, nil) + v := b.NewValue0(s.peekLine(), ssa.OpCopy, t) m[name] = v v.AddArg(s.lookupVarIncoming(b, t, name)) return v @@ -728,7 +748,7 @@ func genValue(v *ssa.Value) { p := Prog(x86.ALEAQ) p.From.Type = obj.TYPE_MEM p.From.Reg = regnum(v.Args[0]) - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) case ssa.OpAMD64MULQconst: @@ -736,7 +756,7 @@ func genValue(v *ssa.Value) { // has ever been taught to compile imul $c, r1, r2. p := Prog(x86.AIMULQ) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.From3.Type = obj.TYPE_REG p.From3.Reg = regnum(v.Args[0]) p.To.Type = obj.TYPE_REG @@ -756,7 +776,7 @@ func genValue(v *ssa.Value) { } p := Prog(x86.ASUBQ) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = r case ssa.OpAMD64SHLQ: @@ -829,7 +849,7 @@ func genValue(v *ssa.Value) { } p := Prog(x86.ASHLQ) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = r case ssa.OpAMD64SHRQconst: @@ -845,7 +865,7 @@ func genValue(v *ssa.Value) { } p := Prog(x86.ASHRQ) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = r case ssa.OpAMD64SARQconst: @@ -861,7 +881,7 @@ func genValue(v *ssa.Value) { } p := Prog(x86.ASARQ) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = r case ssa.OpAMD64SBBQcarrymask: @@ -921,7 +941,7 @@ func genValue(v *ssa.Value) { p.From.Reg = regnum(v.Args[0]) p.From.Scale = 1 p.From.Index = regnum(v.Args[1]) - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) case ssa.OpAMD64CMPQ: @@ -935,7 +955,7 @@ func genValue(v *ssa.Value) { p.From.Type = obj.TYPE_REG p.From.Reg = regnum(v.Args[0]) p.To.Type = obj.TYPE_CONST - p.To.Offset = v.Aux.(int64) + p.To.Offset = v.AuxInt case ssa.OpAMD64TESTB: p := Prog(x86.ATESTB) p.From.Type = obj.TYPE_REG @@ -946,28 +966,28 @@ func genValue(v *ssa.Value) { x := regnum(v) p := Prog(x86.AMOVQ) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = x case ssa.OpAMD64MOVQload: p := Prog(x86.AMOVQ) p.From.Type = obj.TYPE_MEM p.From.Reg = regnum(v.Args[0]) - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) case ssa.OpAMD64MOVBload: p := Prog(x86.AMOVB) p.From.Type = obj.TYPE_MEM p.From.Reg = regnum(v.Args[0]) - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) case ssa.OpAMD64MOVQloadidx8: p := Prog(x86.AMOVQ) p.From.Type = obj.TYPE_MEM p.From.Reg = regnum(v.Args[0]) - p.From.Offset = v.Aux.(int64) + p.From.Offset = v.AuxInt p.From.Scale = 8 p.From.Index = regnum(v.Args[1]) p.To.Type = obj.TYPE_REG @@ -978,7 +998,7 @@ func genValue(v *ssa.Value) { p.From.Reg = regnum(v.Args[1]) p.To.Type = obj.TYPE_MEM p.To.Reg = regnum(v.Args[0]) - p.To.Offset = v.Aux.(int64) + p.To.Offset = v.AuxInt case ssa.OpCopy: // TODO: lower to MOVQ earlier? if v.Type.IsMemory() { return @@ -1021,14 +1041,13 @@ func genValue(v *ssa.Value) { } case ssa.OpArg: // memory arg needs no code - // TODO: only mem arg goes here. + // TODO: check that only mem arg goes here. case ssa.OpAMD64LEAQglobal: - g := v.Aux.(ssa.GlobalOffset) p := Prog(x86.ALEAQ) p.From.Type = obj.TYPE_MEM p.From.Name = obj.NAME_EXTERN - p.From.Sym = Linksym(g.Global.(*Sym)) - p.From.Offset = g.Offset + p.From.Sym = Linksym(v.Aux.(*Sym)) + p.From.Offset = v.AuxInt p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) case ssa.OpAMD64CALLstatic: diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index 10b8976e0f..edd38e1254 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -10,14 +10,14 @@ func TestDeadLoop(t *testing.T) { c := NewConfig("amd64", DummyFrontend{}) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem")), // dead loop Bloc("deadblock", // dead value in dead block - Valu("deadval", OpConst, TypeBool, true), + Valu("deadval", OpConst, TypeBool, 0, true), If("deadval", "deadblock", "exit"))) CheckFunc(fun.f) @@ -40,8 +40,8 @@ func TestDeadValue(t *testing.T) { c := NewConfig("amd64", DummyFrontend{}) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), - Valu("deadval", OpConst, TypeInt64, int64(37)), + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("deadval", OpConst, TypeInt64, 37, nil), Goto("exit")), Bloc("exit", Exit("mem"))) @@ -63,8 +63,8 @@ func TestNeverTaken(t *testing.T) { c := NewConfig("amd64", DummyFrontend{}) fun := Fun(c, "entry", Bloc("entry", - Valu("cond", OpConst, TypeBool, false), - Valu("mem", OpArg, TypeMem, ".mem"), + Valu("cond", OpConst, TypeBool, 0, false), + Valu("mem", OpArg, TypeMem, 0, ".mem"), If("cond", "then", "else")), Bloc("then", Goto("exit")), diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go index 70b2092ec3..5143afb6cb 100644 --- a/src/cmd/compile/internal/ssa/deadstore_test.go +++ b/src/cmd/compile/internal/ssa/deadstore_test.go @@ -13,13 +13,13 @@ func TestDeadStore(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpArg, TypeMem, ".mem"), - Valu("v", OpConst, TypeBool, true), - Valu("addr1", OpGlobal, ptrType, nil), - Valu("addr2", OpGlobal, ptrType, nil), - Valu("store1", OpStore, TypeMem, nil, "addr1", "v", "start"), - Valu("store2", OpStore, TypeMem, nil, "addr2", "v", "store1"), - Valu("store3", OpStore, TypeMem, nil, "addr1", "v", "store2"), + Valu("start", OpArg, TypeMem, 0, ".mem"), + Valu("v", OpConst, TypeBool, 0, true), + Valu("addr1", OpGlobal, ptrType, 0, nil), + Valu("addr2", OpGlobal, ptrType, 0, nil), + Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"), + Valu("store2", OpStore, TypeMem, 0, nil, "addr2", "v", "store1"), + Valu("store3", OpStore, TypeMem, 0, nil, "addr1", "v", "store2"), Goto("exit")), Bloc("exit", Exit("store3"))) @@ -39,13 +39,13 @@ func TestDeadStorePhi(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpArg, TypeMem, ".mem"), - Valu("v", OpConst, TypeBool, true), - Valu("addr", OpGlobal, ptrType, nil), + Valu("start", OpArg, TypeMem, 0, ".mem"), + Valu("v", OpConst, TypeBool, 0, true), + Valu("addr", OpGlobal, ptrType, 0, nil), Goto("loop")), Bloc("loop", - Valu("phi", OpPhi, TypeMem, nil, "start", "store"), - Valu("store", OpStore, TypeMem, nil, "addr", "v", "phi"), + Valu("phi", OpPhi, TypeMem, 0, nil, "start", "store"), + Valu("store", OpStore, TypeMem, 0, nil, "addr", "v", "phi"), If("v", "loop", "exit")), Bloc("exit", Exit("store"))) @@ -65,12 +65,12 @@ func TestDeadStoreTypes(t *testing.T) { t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"} fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpArg, TypeMem, ".mem"), - Valu("v", OpConst, TypeBool, true), - Valu("addr1", OpGlobal, t1, nil), - Valu("addr2", OpGlobal, t2, nil), - Valu("store1", OpStore, TypeMem, nil, "addr1", "v", "start"), - Valu("store2", OpStore, TypeMem, nil, "addr2", "v", "store1"), + Valu("start", OpArg, TypeMem, 0, ".mem"), + Valu("v", OpConst, TypeBool, 0, true), + Valu("addr1", OpGlobal, t1, 0, nil), + Valu("addr2", OpGlobal, t2, 0, nil), + Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"), + Valu("store2", OpStore, TypeMem, 0, nil, "addr2", "v", "store1"), Goto("exit")), Bloc("exit", Exit("store2"))) diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index 06a2455e87..2e1b5990dc 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -4,6 +4,8 @@ package ssa +import "log" + // A Func represents a Go func declaration (or function literal) and // its body. This package compiles each Func independently. type Func struct { @@ -42,13 +44,12 @@ func (f *Func) NewBlock(kind BlockKind) *Block { return b } -// NewValue returns a new value in the block with no arguments. -func (b *Block) NewValue(line int32, op Op, t Type, aux interface{}) *Value { +// NewValue0 returns a new value in the block with no arguments and zero aux values. +func (b *Block) NewValue0(line int32, op Op, t Type) *Value { v := &Value{ ID: b.Func.vid.get(), Op: op, Type: t, - Aux: aux, Block: b, } v.Args = v.argstorage[:0] @@ -56,8 +57,28 @@ func (b *Block) NewValue(line int32, op Op, t Type, aux interface{}) *Value { return v } -// NewValue1 returns a new value in the block with one argument. -func (b *Block) NewValue1(line int32, op Op, t Type, aux interface{}, arg *Value) *Value { +// NewValue returns a new value in the block with no arguments and an auxint value. +func (b *Block) NewValue0I(line int32, op Op, t Type, auxint int64) *Value { + v := &Value{ + ID: b.Func.vid.get(), + Op: op, + Type: t, + AuxInt: auxint, + Block: b, + } + v.Args = v.argstorage[:0] + b.Values = append(b.Values, v) + return v +} + +// NewValue returns a new value in the block with no arguments and an aux value. +func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value { + if _, ok := aux.(int64); ok { + // Disallow int64 aux values. They should be in the auxint field instead. + // Maybe we want to allow this at some point, but for now we disallow it + // to prevent errors like using NewValue1A instead of NewValue1I. + log.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) + } v := &Value{ ID: b.Func.vid.get(), Op: op, @@ -65,14 +86,57 @@ func (b *Block) NewValue1(line int32, op Op, t Type, aux interface{}, arg *Value Aux: aux, Block: b, } + v.Args = v.argstorage[:0] + b.Values = append(b.Values, v) + return v +} + +// NewValue returns a new value in the block with no arguments and both an auxint and aux values. +func (b *Block) NewValue0IA(line int32, op Op, t Type, auxint int64, aux interface{}) *Value { + v := &Value{ + ID: b.Func.vid.get(), + Op: op, + Type: t, + AuxInt: auxint, + Aux: aux, + Block: b, + } + v.Args = v.argstorage[:0] + b.Values = append(b.Values, v) + return v +} + +// NewValue1 returns a new value in the block with one argument and zero aux values. +func (b *Block) NewValue1(line int32, op Op, t Type, arg *Value) *Value { + v := &Value{ + ID: b.Func.vid.get(), + Op: op, + Type: t, + Block: b, + } v.Args = v.argstorage[:1] v.Args[0] = arg b.Values = append(b.Values, v) return v } -// NewValue2 returns a new value in the block with two arguments. -func (b *Block) NewValue2(line int32, op Op, t Type, aux interface{}, arg0, arg1 *Value) *Value { +// NewValue1I returns a new value in the block with one argument and an auxint value. +func (b *Block) NewValue1I(line int32, op Op, t Type, auxint int64, arg *Value) *Value { + v := &Value{ + ID: b.Func.vid.get(), + Op: op, + Type: t, + AuxInt: auxint, + Block: b, + } + v.Args = v.argstorage[:1] + v.Args[0] = arg + b.Values = append(b.Values, v) + return v +} + +// NewValue1A returns a new value in the block with one argument and an aux value. +func (b *Block) NewValue1A(line int32, op Op, t Type, aux interface{}, arg *Value) *Value { v := &Value{ ID: b.Func.vid.get(), Op: op, @@ -80,6 +144,36 @@ func (b *Block) NewValue2(line int32, op Op, t Type, aux interface{}, arg0, arg1 Aux: aux, Block: b, } + v.Args = v.argstorage[:1] + v.Args[0] = arg + b.Values = append(b.Values, v) + return v +} + +// NewValue1IA returns a new value in the block with one argument and both an auxint and aux values. +func (b *Block) NewValue1IA(line int32, op Op, t Type, auxint int64, aux interface{}, arg *Value) *Value { + v := &Value{ + ID: b.Func.vid.get(), + Op: op, + Type: t, + AuxInt: auxint, + Aux: aux, + Block: b, + } + v.Args = v.argstorage[:1] + v.Args[0] = arg + b.Values = append(b.Values, v) + return v +} + +// NewValue2 returns a new value in the block with two arguments and zero aux values. +func (b *Block) NewValue2(line int32, op Op, t Type, arg0, arg1 *Value) *Value { + v := &Value{ + ID: b.Func.vid.get(), + Op: op, + Type: t, + Block: b, + } v.Args = v.argstorage[:2] v.Args[0] = arg0 v.Args[1] = arg1 @@ -87,13 +181,12 @@ func (b *Block) NewValue2(line int32, op Op, t Type, aux interface{}, arg0, arg1 return v } -// NewValue3 returns a new value in the block with three arguments. -func (b *Block) NewValue3(line int32, op Op, t Type, aux interface{}, arg0, arg1, arg2 *Value) *Value { +// NewValue3 returns a new value in the block with three arguments and zero aux values. +func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *Value { v := &Value{ ID: b.Func.vid.get(), Op: op, Type: t, - Aux: aux, Block: b, } v.Args = []*Value{arg0, arg1, arg2} @@ -104,5 +197,5 @@ func (b *Block) NewValue3(line int32, op Op, t Type, aux interface{}, arg0, arg1 // ConstInt returns an int constant representing its argument. func (f *Func) ConstInt(line int32, t Type, c int64) *Value { // TODO: cache? - return f.Entry.NewValue(line, OpConst, t, c) + return f.Entry.NewValue0I(line, OpConst, t, c) } diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index 3f94589e8b..7cfc7324ac 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -18,12 +18,12 @@ // // fun := Fun("entry", // Bloc("entry", -// Valu("mem", OpArg, TypeMem, ".mem"), +// Valu("mem", OpArg, TypeMem, 0, ".mem"), // Goto("exit")), // Bloc("exit", // Exit("mem")), // Bloc("deadblock", -// Valu("deadval", OpConst, TypeBool, true), +// Valu("deadval", OpConst, TypeBool, 0, true), // If("deadval", "deadblock", "exit"))) // // and the Blocks or Values used in the Func can be accessed @@ -61,7 +61,7 @@ func Equiv(f, g *Func) bool { // Ignore ids. Ops and Types are compared for equality. // TODO(matloob): Make sure types are canonical and can // be compared for equality. - if fv.Op != gv.Op || fv.Type != gv.Type { + if fv.Op != gv.Op || fv.Type != gv.Type || fv.AuxInt != gv.AuxInt { return false } if !reflect.DeepEqual(fv.Aux, gv.Aux) { @@ -149,7 +149,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun { blocks[bloc.name] = b for _, valu := range bloc.valus { // args are filled in the second pass. - values[valu.name] = b.NewValue(0, valu.op, valu.t, valu.aux) + values[valu.name] = b.NewValue0IA(0, valu.op, valu.t, valu.auxint, valu.aux) } } // Connect the blocks together and specify control values. @@ -212,8 +212,8 @@ func Bloc(name string, entries ...interface{}) bloc { } // Valu defines a value in a block. -func Valu(name string, op Op, t Type, aux interface{}, args ...string) valu { - return valu{name, op, t, aux, args} +func Valu(name string, op Op, t Type, auxint int64, aux interface{}, args ...string) valu { + return valu{name, op, t, auxint, aux, args} } // Goto specifies that this is a BlockPlain and names the single successor. @@ -248,11 +248,12 @@ type ctrl struct { } type valu struct { - name string - op Op - t Type - aux interface{} - args []string + name string + op Op + t Type + auxint int64 + aux interface{} + args []string } func addEdge(b, c *Block) { @@ -264,10 +265,10 @@ func TestArgs(t *testing.T) { c := NewConfig("amd64", DummyFrontend{}) fun := Fun(c, "entry", Bloc("entry", - Valu("a", OpConst, TypeInt64, 14), - Valu("b", OpConst, TypeInt64, 26), - Valu("sum", OpAdd, TypeInt64, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, ".mem"), + Valu("a", OpConst, TypeInt64, 14, nil), + Valu("b", OpConst, TypeInt64, 26, nil), + Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))) @@ -287,19 +288,19 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("a", OpConst, TypeInt64, 14), - Valu("b", OpConst, TypeInt64, 26), - Valu("sum", OpAdd, TypeInt64, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, ".mem"), + Valu("a", OpConst, TypeInt64, 14, nil), + Valu("b", OpConst, TypeInt64, 26, nil), + Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("a", OpConst, TypeInt64, 14), - Valu("b", OpConst, TypeInt64, 26), - Valu("sum", OpAdd, TypeInt64, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, ".mem"), + Valu("a", OpConst, TypeInt64, 14, nil), + Valu("b", OpConst, TypeInt64, 26, nil), + Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -308,10 +309,10 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("a", OpConst, TypeInt64, 14), - Valu("b", OpConst, TypeInt64, 26), - Valu("sum", OpAdd, TypeInt64, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, ".mem"), + Valu("a", OpConst, TypeInt64, 14, nil), + Valu("b", OpConst, TypeInt64, 26, nil), + Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -319,10 +320,10 @@ func TestEquiv(t *testing.T) { Bloc("exit", Exit("mem")), Bloc("entry", - Valu("a", OpConst, TypeInt64, 14), - Valu("b", OpConst, TypeInt64, 26), - Valu("sum", OpAdd, TypeInt64, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, ".mem"), + Valu("a", OpConst, TypeInt64, 14, nil), + Valu("b", OpConst, TypeInt64, 26, nil), + Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit"))), }, } @@ -339,58 +340,71 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), Exit("mem"))), }, // value order changed { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), - Valu("b", OpConst, TypeInt64, 26), - Valu("a", OpConst, TypeInt64, 14), + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("b", OpConst, TypeInt64, 26, nil), + Valu("a", OpConst, TypeInt64, 14, nil), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), - Valu("a", OpConst, TypeInt64, 14), - Valu("b", OpConst, TypeInt64, 26), + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("a", OpConst, TypeInt64, 14, nil), + Valu("b", OpConst, TypeInt64, 26, nil), + Exit("mem"))), + }, + // value auxint different + { + Fun(c, "entry", + Bloc("entry", + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("a", OpConst, TypeInt64, 14, nil), + Exit("mem"))), + Fun(c, "entry", + Bloc("entry", + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("a", OpConst, TypeInt64, 26, nil), Exit("mem"))), }, // value aux different { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), - Valu("a", OpConst, TypeInt64, 14), + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("a", OpConst, TypeInt64, 0, 14), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), - Valu("a", OpConst, TypeInt64, 26), + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("a", OpConst, TypeInt64, 0, 26), Exit("mem"))), }, // value args different { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), - Valu("a", OpConst, TypeInt64, 14), - Valu("b", OpConst, TypeInt64, 26), - Valu("sum", OpAdd, TypeInt64, nil, "a", "b"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("a", OpConst, TypeInt64, 14, nil), + Valu("b", OpConst, TypeInt64, 26, nil), + Valu("sum", OpAdd, TypeInt64, 0, nil, "a", "b"), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), - Valu("a", OpConst, TypeInt64, 0), - Valu("b", OpConst, TypeInt64, 14), - Valu("sum", OpAdd, TypeInt64, nil, "b", "a"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("a", OpConst, TypeInt64, 0, nil), + Valu("b", OpConst, TypeInt64, 14, nil), + Valu("sum", OpAdd, TypeInt64, 0, nil, "b", "a"), Exit("mem"))), }, } diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index e9744aed9c..58ab25b392 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -23,30 +23,30 @@ // mask = shift >= 64 ? 0 : 0xffffffffffffffff // result = mask & arg << shift (Lsh x y) && is64BitInt(t) -> - (ANDQ (SHLQ x y) (SBBQcarrymask (CMPQconst [int64(64)] y))) + (ANDQ (SHLQ x y) (SBBQcarrymask (CMPQconst [64] y))) (Rsh x y) && is64BitInt(t) && !t.IsSigned() -> - (ANDQ (SHRQ x y) (SBBQcarrymask (CMPQconst [int64(64)] y))) + (ANDQ (SHRQ x y) (SBBQcarrymask (CMPQconst [64] y))) // Note: signed right shift needs to return 0/-1 if shift amount is >= 64. // if shift > 63 { shift = 63 } // result = arg >> shift (Rsh x y) && is64BitInt(t) && t.IsSigned() -> (SARQ x (CMOVQCC - (CMPQconst [int64(64)] y) - (Const [int64(63)]) + (CMPQconst [64] y) + (Const [63]) y)) (Less x y) && is64BitInt(v.Args[0].Type) && isSigned(v.Args[0].Type) -> (SETL (CMPQ x y)) -(Load ptr mem) && t.IsBoolean() -> (MOVBload [int64(0)] ptr mem) -(Load ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVQload [int64(0)] ptr mem) -(Store ptr val mem) && (is64BitInt(val.Type) || isPtr(val.Type)) -> (MOVQstore [int64(0)] ptr val mem) +(Load ptr mem) && t.IsBoolean() -> (MOVBload ptr mem) +(Load ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVQload ptr mem) +(Store ptr val mem) && (is64BitInt(val.Type) || isPtr(val.Type)) -> (MOVQstore ptr val mem) // checks (IsNonNil p) -> (SETNE (TESTQ p p)) (IsInBounds idx len) -> (SETB (CMPQ idx len)) -(Move [size] dst src mem) -> (REPMOVSB dst src (Const [size.(int64)]) mem) +(Move [size] dst src mem) -> (REPMOVSB dst src (Const [size]) mem) (OffPtr [off] ptr) -> (ADDQconst [off] ptr) @@ -65,14 +65,14 @@ // TODO: Should this be a separate pass? // global loads/stores -(Global [sym]) -> (LEAQglobal [GlobalOffset{sym,0}]) +(Global {sym}) -> (LEAQglobal {sym}) // fold constants into instructions (ADDQ x (MOVQconst [c])) -> (ADDQconst [c] x) // TODO: restrict c to int32 range? (ADDQ (MOVQconst [c]) x) -> (ADDQconst [c] x) (SUBQ x (MOVQconst [c])) -> (SUBQconst x [c]) (SUBQ (MOVQconst [c]) x) -> (NEGQ (SUBQconst x [c])) -(MULQ x (MOVQconst [c])) && c.(int64) == int64(int32(c.(int64))) -> (MULQconst [c] x) +(MULQ x (MOVQconst [c])) && c == int64(int32(c)) -> (MULQconst [c] x) (MULQ (MOVQconst [c]) x) -> (MULQconst [c] x) (ANDQ x (MOVQconst [c])) -> (ANDQconst [c] x) (ANDQ (MOVQconst [c]) x) -> (ANDQconst [c] x) @@ -84,11 +84,11 @@ // strength reduction // TODO: do this a lot more generically -(MULQconst [c] x) && c.(int64) == 8 -> (SHLQconst [int64(3)] x) -(MULQconst [c] x) && c.(int64) == 64 -> (SHLQconst [int64(5)] x) +(MULQconst [8] x) -> (SHLQconst [3] x) +(MULQconst [64] x) -> (SHLQconst [5] x) // fold add/shift into leaq -(ADDQ x (SHLQconst [shift] y)) && shift.(int64) == 3 -> (LEAQ8 [int64(0)] x y) +(ADDQ x (SHLQconst [3] y)) -> (LEAQ8 x y) (ADDQconst [c] (LEAQ8 [d] x y)) -> (LEAQ8 [addOff(c, d)] x y) // reverse ordering of compare instruction @@ -110,7 +110,7 @@ (MOVQloadidx8 [off1] (ADDQconst [off2] ptr) idx mem) -> (MOVQloadidx8 [addOff(off1, off2)] ptr idx mem) (MOVQstoreidx8 [off1] (ADDQconst [off2] ptr) idx val mem) -> (MOVQstoreidx8 [addOff(off1, off2)] ptr idx val mem) -(ADDQconst [off] x) && off.(int64) == 0 -> (Copy x) +(ADDQconst [0] x) -> (Copy x) // Absorb InvertFlags into branches. (LT (InvertFlags cmp) yes no) -> (GT cmp yes no) @@ -125,9 +125,9 @@ (NE (InvertFlags cmp) yes no) -> (NE cmp yes no) // get rid of >=64 code for constant shifts -(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds(d.(int64), c.(int64)) -> (Const [int64(-1)]) -(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds(d.(int64), c.(int64)) -> (Const [int64(0)]) -(ANDQconst [c] _) && c.(int64) == 0 -> (MOVQconst [int64(0)]) -(ANDQconst [c] x) && c.(int64) == -1 -> (Copy x) -(CMOVQCC (CMPQconst [c] (MOVQconst [d])) _ x) && inBounds(d.(int64), c.(int64)) -> (Copy x) -(CMOVQCC (CMPQconst [c] (MOVQconst [d])) x _) && !inBounds(d.(int64), c.(int64)) -> (Copy x) +(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds(d, c) -> (Const [-1]) +(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds(d, c) -> (Const [0]) +(ANDQconst [0] _) -> (MOVQconst [0]) +(ANDQconst [-1] x) -> (Copy x) +(CMOVQCC (CMPQconst [c] (MOVQconst [d])) _ x) && inBounds(d, c) -> (Copy x) +(CMOVQCC (CMPQconst [c] (MOVQconst [d])) x _) && !inBounds(d, c) -> (Copy x) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index bcb07392c7..13aff4cba7 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -93,24 +93,24 @@ func init() { // 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: "ADDQconst", reg: gp11}, // arg0 + auxint {name: "SUBQ", reg: gp21}, // arg0 - arg1 - {name: "SUBQconst", reg: gp11}, // arg0 - aux.(int64) + {name: "SUBQconst", reg: gp11}, // arg0 - auxint {name: "MULQ", reg: gp21}, // arg0 * arg1 - {name: "MULQconst", reg: gp11}, // arg0 * aux.(int64) + {name: "MULQconst", reg: gp11}, // arg0 * auxint {name: "ANDQ", reg: gp21}, // arg0 & arg1 - {name: "ANDQconst", reg: gp11}, // arg0 & aux.(int64) + {name: "ANDQconst", reg: gp11}, // arg0 & auxint {name: "SHLQ", reg: gp21shift}, // arg0 << arg1, shift amount is mod 64 - {name: "SHLQconst", reg: gp11}, // arg0 << aux.(int64), shift amount 0-63 + {name: "SHLQconst", reg: gp11}, // arg0 << auxint, shift amount 0-63 {name: "SHRQ", reg: gp21shift}, // unsigned arg0 >> arg1, shift amount is mod 64 - {name: "SHRQconst", reg: gp11}, // unsigned arg0 >> aux.(int64), shift amount 0-63 + {name: "SHRQconst", reg: gp11}, // unsigned arg0 >> auxint, shift amount 0-63 {name: "SARQ", reg: gp21shift}, // signed arg0 >> arg1, shift amount is mod 64 - {name: "SARQconst", reg: gp11}, // signed arg0 >> aux.(int64), shift amount 0-63 + {name: "SARQconst", reg: gp11}, // signed arg0 >> auxint, 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: "CMPQconst", reg: gp1flags}, // arg0 compare to auxint {name: "TESTQ", reg: gp2flags}, // (arg0 & arg1) compare to 0 {name: "TESTB", reg: gp2flags}, // (arg0 & arg1) compare to 0 @@ -125,21 +125,21 @@ func init() { {name: "CMOVQCC", reg: cmov}, // carry clear - {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: "MOVQconst", reg: gp01}, // auxint + {name: "LEAQ", reg: gp21}, // arg0 + arg1 + auxint + {name: "LEAQ2", reg: gp21}, // arg0 + 2*arg1 + auxint + {name: "LEAQ4", reg: gp21}, // arg0 + 4*arg1 + auxint + {name: "LEAQ8", reg: gp21}, // arg0 + 8*arg1 + auxint + {name: "LEAQglobal", reg: gp01}, // no args. address of aux.(*gc.Sym) - {name: "MOVBload", reg: gpload}, // load byte from arg0+aux.(int64). arg1=mem + {name: "MOVBload", reg: gpload}, // load byte from arg0+auxint. 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 + {name: "MOVQload", reg: gpload}, // load 8 bytes from arg0+auxint. arg1=mem + {name: "MOVQloadidx8", reg: gploadidx}, // load 8 bytes from arg0+8*arg1+auxint. arg2=mem + {name: "MOVBstore", reg: gpstore}, // store byte in arg1 to arg0+auxint. arg2=mem + {name: "MOVQstore", reg: gpstore}, // store 8 bytes in arg1 to arg0+auxint. arg2=mem + {name: "MOVQstoreidx8", reg: gpstoreidx}, // store 8 bytes in arg2 to arg0+8*arg1+auxint. arg3=mem // Load/store from global. Same as the above loads, but arg0 is missing and // aux is a GlobalOffset instead of an int64. @@ -147,7 +147,7 @@ func init() { {name: "MOVQstoreglobal"}, // store arg0 to aux.(GlobalOffset). arg1=memory, returns memory. //TODO: set register clobber to everything? - {name: "CALLstatic"}, // call static function. arg0=mem, returns mem + {name: "CALLstatic"}, // call static function aux.(*gc.Sym). arg0=mem, returns mem {name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, 0, nil}}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem returns mem {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 diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index b01952f402..e0bba1706f 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -3,13 +3,14 @@ // license that can be found in the LICENSE file. // values are specified using the following format: -// (op [aux] arg0 arg1 ...) +// (op [auxint] {aux} arg0 arg1 ...) // the type and aux fields are optional // on the matching side -// - the types and aux fields must match if they are specified. +// - the type, aux, and auxint fields must match if they are specified. // on the generated side // - the type of the top-level expression is the same as the one on the left-hand side. // - the type of any subexpressions must be specified explicitly. +// - auxint will be 0 if not specified. // - aux will be nil if not specified. // blocks are specified using the following format: @@ -19,15 +20,15 @@ // For now, the generated successors must be a permutation of the matched successors. // constant folding -(Add (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [{c.(int64)+d.(int64)}]) -(Mul (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [{c.(int64)*d.(int64)}]) -(IsInBounds (Const [c]) (Const [d])) -> (Const [inBounds(c.(int64),d.(int64))]) +(Add (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [c+d]) +(Mul (Const [c]) (Const [d])) && is64BitInt(t) -> (Const [c*d]) +(IsInBounds (Const [c]) (Const [d])) -> (Const {inBounds(c,d)}) // tear apart slices // TODO: anything that generates a slice needs to go in here. (SlicePtr (Load ptr mem)) -> (Load ptr mem) -(SliceLen (Load ptr mem)) -> (Load (Add ptr (Const [int64(config.ptrSize)])) mem) -(SliceCap (Load ptr mem)) -> (Load (Add ptr (Const [int64(config.ptrSize*2)])) mem) +(SliceLen (Load ptr mem)) -> (Load (Add ptr (Const [config.ptrSize])) mem) +(SliceCap (Load ptr mem)) -> (Load (Add ptr (Const [config.ptrSize*2])) mem) // indexing operations // Note: bounds check has already been done @@ -39,11 +40,11 @@ (Store dst (Load src mem) mem) && t.Size() > 8 -> (Move [t.Size()] dst src mem) // string ops -(Const [s]) && t.IsString() -> (StringMake (OffPtr [2*config.ptrSize] (Global [config.fe.StringSym(s.(string))])) (Const [int64(len(s.(string)))])) // TODO: ptr +(Const {s}) && t.IsString() -> (StringMake (OffPtr [2*config.ptrSize] (Global {config.fe.StringSym(s.(string))})) (Const [int64(len(s.(string)))])) // TODO: ptr (Load ptr mem) && t.IsString() -> (StringMake (Load ptr mem) (Load (OffPtr [config.ptrSize] ptr) mem)) (StringPtr (StringMake ptr _)) -> ptr (StringLen (StringMake _ len)) -> len (Store dst str mem) && str.Type.IsString() -> (Store (OffPtr [config.ptrSize] dst) (StringLen str) (Store dst (StringPtr str) mem)) -(If (Const [c]) yes no) && c.(bool) -> (Plain nil yes) -(If (Const [c]) yes no) && !c.(bool) -> (Plain nil no) +(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 index 4a691929b5..c168f2af05 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -37,9 +37,9 @@ var genericOps = []opData{ {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. + {name: "Load"}, // Load from arg0. arg1=memory + {name: "Store"}, // Store arg1 to arg0. arg2=memory. Returns memory. + {name: "Move"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=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 @@ -58,7 +58,7 @@ var genericOps = []opData{ // 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) + {name: "OffPtr"}, // arg0 + auxint (arg0 and result are pointers) // Slices {name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go index 4f689199a0..1a4b2c1b85 100644 --- a/src/cmd/compile/internal/ssa/gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/gen/rulegen.go @@ -19,6 +19,7 @@ import ( "io/ioutil" "log" "os" + "regexp" "sort" "strings" ) @@ -29,9 +30,9 @@ import ( // sexpr are s-expressions (lisp-like parenthesized groupings) // sexpr ::= (opcode sexpr*) // | variable -// | [aux] // | -// | {code} +// | [auxint] +// | {aux} // // aux ::= variable | {code} // type ::= variable | {code} @@ -310,9 +311,9 @@ func genMatch0(w io.Writer, arch arch, match, v, fail string, m map[string]strin if a[0] == '<' { // type restriction t := a[1 : len(a)-1] // remove <> - if t[0] == '{' { + if !isVariable(t) { // code. We must match the results of this code. - fmt.Fprintf(w, "if %s.Type != %s %s", v, t[1:len(t)-1], fail) + fmt.Fprintf(w, "if %s.Type != %s %s", v, t, fail) } else { // variable if u, ok := m[t]; ok { @@ -324,11 +325,26 @@ func genMatch0(w io.Writer, arch arch, match, v, fail string, m map[string]strin } } } else if a[0] == '[' { - // aux restriction + // auxint restriction x := a[1 : len(a)-1] // remove [] - if x[0] == '{' { + if !isVariable(x) { // code - fmt.Fprintf(w, "if %s.Aux != %s %s", v, x[1:len(x)-1], fail) + fmt.Fprintf(w, "if %s.AuxInt != %s %s", v, x, fail) + } else { + // variable + if y, ok := m[x]; ok { + fmt.Fprintf(w, "if %s.AuxInt != %s %s", v, y, fail) + } else { + m[x] = v + ".AuxInt" + fmt.Fprintf(w, "%s := %s.AuxInt\n", x, v) + } + } + } else if a[0] == '{' { + // auxint restriction + x := a[1 : len(a)-1] // remove {} + if !isVariable(x) { + // code + fmt.Fprintf(w, "if %s.Aux != %s %s", v, x, fail) } else { // variable if y, ok := m[x]; ok { @@ -338,9 +354,6 @@ func genMatch0(w io.Writer, arch arch, match, v, fail string, m map[string]strin fmt.Fprintf(w, "%s := %s.Aux\n", x, v) } } - } else if a[0] == '{' { - fmt.Fprintf(w, "if %s.Args[%d] != %s %s", v, argnum, a[1:len(a)-1], fail) - argnum++ } else { // variable or sexpr genMatch0(w, arch, a, fmt.Sprintf("%s.Args[%d]", v, argnum), fail, m, false) @@ -357,6 +370,7 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top bool) str // variable if top { fmt.Fprintf(w, "v.Op = %s.Op\n", result) + fmt.Fprintf(w, "v.AuxInt = %s.AuxInt\n", result) fmt.Fprintf(w, "v.Aux = %s.Aux\n", result) fmt.Fprintf(w, "v.resetArgs()\n") fmt.Fprintf(w, "v.AddArgs(%s.Args...)\n", result) @@ -370,32 +384,29 @@ func genResult0(w io.Writer, arch arch, result string, alloc *int, top bool) str if top { v = "v" fmt.Fprintf(w, "v.Op = %s\n", opName(s[0], arch)) + fmt.Fprintf(w, "v.AuxInt = 0\n") 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(v.Line, %s, TypeInvalid, nil)\n", v, opName(s[0], arch)) + fmt.Fprintf(w, "%s := v.Block.NewValue0(v.Line, %s, TypeInvalid)\n", v, opName(s[0], arch)) } for _, a := range s[1:] { if a[0] == '<' { // type restriction t := a[1 : len(a)-1] // remove <> - if t[0] == '{' { - t = t[1 : len(t)-1] // remove {} - } fmt.Fprintf(w, "%s.Type = %s\n", v, t) hasType = true } else if a[0] == '[' { - // aux restriction + // auxint restriction x := a[1 : len(a)-1] // remove [] - if x[0] == '{' { - x = x[1 : len(x)-1] // remove {} - } - fmt.Fprintf(w, "%s.Aux = %s\n", v, x) + fmt.Fprintf(w, "%s.AuxInt = %s\n", v, x) } else if a[0] == '{' { - fmt.Fprintf(w, "%s.AddArg(%s)\n", v, a[1:len(a)-1]) + // aux restriction + x := a[1 : len(a)-1] // remove {} + fmt.Fprintf(w, "%s.Aux = %s\n", v, x) } else { // regular argument (sexpr or variable) x := genResult0(w, arch, a, alloc, false) @@ -504,3 +515,12 @@ func unbalanced(s string) bool { } return left != right } + +// isVariable reports whether s is a single Go alphanumeric identifier. +func isVariable(s string) bool { + b, err := regexp.MatchString("[A-Za-z_][A-Za-z_0-9]*", s) + if err != nil { + panic("bad variable regexp") + } + return b +} diff --git a/src/cmd/compile/internal/ssa/generic.go b/src/cmd/compile/internal/ssa/generic.go deleted file mode 100644 index ebbb1327d4..0000000000 --- a/src/cmd/compile/internal/ssa/generic.go +++ /dev/null @@ -1,424 +0,0 @@ -// autogenerated from rulegen/generic.rules: do not edit! -// generated with: go run rulegen/rulegen.go rulegen/generic.rules genericBlockRules genericValueRules generic.go -package ssa - -func genericValueRules(v *Value, config *Config) bool { - switch v.Op { - case OpAdd: - // match: (Add (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 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(v.Line, 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 [s]) - // cond: t.IsString() - // result: (StringMake (OffPtr [2*config.ptrSize] (Global [config.fe.StringSym(s.(string))])) (Const [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(v.Line, OpOffPtr, TypeInvalid, nil) - v0.Type = TypeBytePtr - v0.Aux = 2 * config.ptrSize - v1 := v.Block.NewValue(v.Line, OpGlobal, TypeInvalid, nil) - v1.Type = TypeBytePtr - v1.Aux = config.fe.StringSym(s.(string)) - v0.AddArg(v1) - v.AddArg(v0) - v2 := v.Block.NewValue(v.Line, 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 ptr mem) - // cond: t.IsString() - // result: (StringMake (Load ptr mem) (Load (OffPtr [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(v.Line, OpLoad, TypeInvalid, nil) - v0.Type = TypeBytePtr - v0.AddArg(ptr) - v0.AddArg(mem) - v.AddArg(v0) - v1 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil) - v1.Type = config.Uintptr - v2 := v.Block.NewValue(v.Line, 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 (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 ptr idx) - // cond: - // result: (Add ptr (Mul idx (Const [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(v.Line, OpMul, TypeInvalid, nil) - v0.Type = config.Uintptr - v0.AddArg(idx) - v1 := v.Block.NewValue(v.Line, 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 (Const [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(v.Line, OpAdd, TypeInvalid, nil) - v0.Type = ptr.Type - v0.AddArg(ptr) - v1 := v.Block.NewValue(v.Line, 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 (Const [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(v.Line, OpAdd, TypeInvalid, nil) - v0.Type = ptr.Type - v0.AddArg(ptr) - v1 := v.Block.NewValue(v.Line, 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 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 [config.ptrSize] dst) (StringLen str) (Store dst (StringPtr 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(v.Line, OpOffPtr, TypeInvalid, nil) - v0.Type = TypeBytePtr - v0.Aux = config.ptrSize - v0.AddArg(dst) - v.AddArg(v0) - v1 := v.Block.NewValue(v.Line, OpStringLen, TypeInvalid, nil) - v1.Type = config.Uintptr - v1.AddArg(str) - v.AddArg(v1) - v2 := v.Block.NewValue(v.Line, OpStore, TypeInvalid, nil) - v2.Type = TypeMem - v2.AddArg(dst) - v3 := v.Block.NewValue(v.Line, 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 genericBlockRules(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 19a3fddd49..1103a67d0b 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -4,11 +4,6 @@ package ssa -import ( - "fmt" - "log" -) - // 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. @@ -17,26 +12,6 @@ import ( // for each architecture. type Op int32 -// GlobalOffset represents a fixed offset within a global variable -type GlobalOffset struct { - Global interface{} // holds a *gc.Sym - Offset int64 -} - -// offset adds x to the location specified by g and returns it. -func (g GlobalOffset) offset(x int64) GlobalOffset { - y := g.Offset - z := x + y - if x^y >= 0 && x^z < 0 { - log.Panicf("offset overflow %d %d\n", x, y) - } - return GlobalOffset{g.Global, z} -} - -func (g GlobalOffset) String() string { - return fmt.Sprintf("%v+%d", g.Global, g.Offset) -} - type opInfo struct { name string reg regInfo diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index ed80a5b97d..6f7d619247 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -262,25 +262,23 @@ func regalloc(f *Func) { if len(w.Args) == 0 { // Materialize w if w.Op == OpFP || w.Op == OpSP || w.Op == OpGlobal { - c = b.NewValue1(w.Line, OpCopy, w.Type, nil, w) + c = b.NewValue1(w.Line, OpCopy, w.Type, w) } else { - c = b.NewValue(w.Line, w.Op, w.Type, w.Aux) + c = b.NewValue0IA(w.Line, w.Op, w.Type, w.AuxInt, w.Aux) } } else if len(w.Args) == 1 && (w.Args[0].Op == OpFP || w.Args[0].Op == OpSP || w.Args[0].Op == OpGlobal) { // Materialize offsets from SP/FP/Global - c = b.NewValue1(w.Line, w.Op, w.Type, w.Aux, w.Args[0]) + c = b.NewValue1IA(w.Line, w.Op, w.Type, w.AuxInt, w.Aux, w.Args[0]) } else if wreg != 0 { // Copy from another register. // Typically just an optimization, but this is // required if w is dirty. s := pickReg(wreg) // inv: s != r - c = b.NewValue(w.Line, OpCopy, w.Type, nil) - c.AddArg(regs[s].c) + c = b.NewValue1(w.Line, OpCopy, w.Type, regs[s].c) } else { // Load from home location - c = b.NewValue(w.Line, OpLoadReg8, w.Type, nil) - c.AddArg(w) + c = b.NewValue1(w.Line, OpLoadReg8, w.Type, w) } home = setloc(home, c, ®isters[r]) // Remember what we did @@ -337,7 +335,7 @@ func regalloc(f *Func) { } // Reissue v with new op, with r as its home. - c := b.NewValue(v.Line, v.Op, v.Type, v.Aux) + c := b.NewValue0IA(v.Line, v.Op, v.Type, v.AuxInt, v.Aux) c.AddArgs(v.Args...) home = setloc(home, c, ®isters[r]) @@ -406,7 +404,7 @@ func addPhiCopies(f *Func) { } for i, w := range v.Args { c := b.Preds[i] - cpy := c.NewValue1(w.Line, OpCopy, v.Type, nil, w) + cpy := c.NewValue1(w.Line, OpCopy, v.Type, w) v.Args[i] = cpy } } diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index fd0fc7e1a7..08ee7a9824 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -82,11 +82,8 @@ func typeSize(t Type) int64 { return t.Size() } -// addOff adds two offset aux values. Each should be an int64. Fails if wraparound happens. -func addOff(a, b interface{}) interface{} { - return addOffset(a.(int64), b.(int64)) -} -func addOffset(x, y int64) int64 { +// addOff adds two int64 offsets. Fails if wraparound happens. +func addOff(x, y int64) int64 { z := x + y // x and y have same sign and z has a different sign => overflow if x^y >= 0 && x^z < 0 { diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index f57cf7f333..d466e154e7 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -13,11 +13,12 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[1].Op != OpAMD64MOVQconst { goto endacffd55e74ee0ff59ad58a18ddfc9973 } - c := v.Args[1].Aux + c := v.Args[1].AuxInt v.Op = OpAMD64ADDQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c + v.AuxInt = c v.AddArg(x) return true } @@ -31,58 +32,59 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[0].Op != OpAMD64MOVQconst { goto end7166f476d744ab7a51125959d3d3c7e2 } - c := v.Args[0].Aux + c := v.Args[0].AuxInt x := v.Args[1] v.Op = OpAMD64ADDQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c + v.AuxInt = c v.AddArg(x) return true } goto end7166f476d744ab7a51125959d3d3c7e2 end7166f476d744ab7a51125959d3d3c7e2: ; - // match: (ADDQ x (SHLQconst [shift] y)) - // cond: shift.(int64) == 3 - // result: (LEAQ8 [int64(0)] x y) + // match: (ADDQ x (SHLQconst [3] y)) + // cond: + // result: (LEAQ8 x y) { x := v.Args[0] if v.Args[1].Op != OpAMD64SHLQconst { - goto endaf4f724e1e17f2b116d336c07da0165d + goto endc02313d35a0525d1d680cd58992e820d } - shift := v.Args[1].Aux - y := v.Args[1].Args[0] - if !(shift.(int64) == 3) { - goto endaf4f724e1e17f2b116d336c07da0165d + if v.Args[1].AuxInt != 3 { + goto endc02313d35a0525d1d680cd58992e820d } + y := v.Args[1].Args[0] v.Op = OpAMD64LEAQ8 + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = int64(0) v.AddArg(x) v.AddArg(y) return true } - goto endaf4f724e1e17f2b116d336c07da0165d - endaf4f724e1e17f2b116d336c07da0165d: + goto endc02313d35a0525d1d680cd58992e820d + endc02313d35a0525d1d680cd58992e820d: ; case OpAMD64ADDQconst: // match: (ADDQconst [c] (LEAQ8 [d] x y)) // cond: // result: (LEAQ8 [addOff(c, d)] x y) { - c := v.Aux + c := v.AuxInt if v.Args[0].Op != OpAMD64LEAQ8 { goto ende2cc681c9abf9913288803fb1b39e639 } - d := v.Args[0].Aux + d := v.Args[0].AuxInt x := v.Args[0].Args[0] y := v.Args[0].Args[1] v.Op = OpAMD64LEAQ8 + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = addOff(c, d) + v.AuxInt = addOff(c, d) v.AddArg(x) v.AddArg(y) return true @@ -90,23 +92,23 @@ func rewriteValueAMD64(v *Value, config *Config) bool { goto ende2cc681c9abf9913288803fb1b39e639 ende2cc681c9abf9913288803fb1b39e639: ; - // match: (ADDQconst [off] x) - // cond: off.(int64) == 0 + // match: (ADDQconst [0] x) + // cond: // result: (Copy x) { - off := v.Aux - x := v.Args[0] - if !(off.(int64) == 0) { - goto endfa1c7cc5ac4716697e891376787f86ce + if v.AuxInt != 0 { + goto end288952f259d4a1842f1e8d5c389b3f28 } + x := v.Args[0] v.Op = OpCopy + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) return true } - goto endfa1c7cc5ac4716697e891376787f86ce - endfa1c7cc5ac4716697e891376787f86ce: + goto end288952f259d4a1842f1e8d5c389b3f28 + end288952f259d4a1842f1e8d5c389b3f28: ; case OpAMD64ANDQ: // match: (ANDQ x (MOVQconst [c])) @@ -117,11 +119,12 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[1].Op != OpAMD64MOVQconst { goto endb98096e3bbb90933e39c88bf41c688a9 } - c := v.Args[1].Aux + c := v.Args[1].AuxInt v.Op = OpAMD64ANDQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c + v.AuxInt = c v.AddArg(x) return true } @@ -135,12 +138,13 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[0].Op != OpAMD64MOVQconst { goto endd313fd1897a0d2bc79eff70159a81b6b } - c := v.Args[0].Aux + c := v.Args[0].AuxInt x := v.Args[1] v.Op = OpAMD64ANDQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c + v.AuxInt = c v.AddArg(x) return true } @@ -148,40 +152,40 @@ func rewriteValueAMD64(v *Value, config *Config) bool { endd313fd1897a0d2bc79eff70159a81b6b: ; case OpAMD64ANDQconst: - // match: (ANDQconst [c] _) - // cond: c.(int64) == 0 - // result: (MOVQconst [int64(0)]) + // match: (ANDQconst [0] _) + // cond: + // result: (MOVQconst [0]) { - c := v.Aux - if !(c.(int64) == 0) { - goto end383ada81cd8ffa88918387cd221acf5c + if v.AuxInt != 0 { + goto endf2afa4d9d31c344d6638dcdced383cf1 } v.Op = OpAMD64MOVQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = int64(0) + v.AuxInt = 0 return true } - goto end383ada81cd8ffa88918387cd221acf5c - end383ada81cd8ffa88918387cd221acf5c: + goto endf2afa4d9d31c344d6638dcdced383cf1 + endf2afa4d9d31c344d6638dcdced383cf1: ; - // match: (ANDQconst [c] x) - // cond: c.(int64) == -1 + // match: (ANDQconst [-1] x) + // cond: // result: (Copy x) { - c := v.Aux - x := v.Args[0] - if !(c.(int64) == -1) { - goto end90aef368f20963a6ba27b3e9317ccf03 + if v.AuxInt != -1 { + goto end646afc7b328db89ad16ebfa156ae26e5 } + x := v.Args[0] v.Op = OpCopy + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) return true } - goto end90aef368f20963a6ba27b3e9317ccf03 - end90aef368f20963a6ba27b3e9317ccf03: + goto end646afc7b328db89ad16ebfa156ae26e5 + end646afc7b328db89ad16ebfa156ae26e5: ; case OpAdd: // match: (Add x y) @@ -195,6 +199,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { goto endf031c523d7dd08e4b8e7010a94cd94c9 } v.Op = OpAMD64ADDQ + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) @@ -215,6 +220,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { goto end35a02a1587264e40cf1055856ff8445a } v.Op = OpAMD64ADDL + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) @@ -226,54 +232,56 @@ func rewriteValueAMD64(v *Value, config *Config) bool { ; case OpAMD64CMOVQCC: // match: (CMOVQCC (CMPQconst [c] (MOVQconst [d])) _ x) - // cond: inBounds(d.(int64), c.(int64)) + // cond: inBounds(d, c) // result: (Copy x) { if v.Args[0].Op != OpAMD64CMPQconst { - goto endb8f4f98b06c41e559bf0323e798c147a + goto endd5357f3fd5516dcc859c8c5b3c9efaa4 } - c := v.Args[0].Aux + c := v.Args[0].AuxInt if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto endb8f4f98b06c41e559bf0323e798c147a + goto endd5357f3fd5516dcc859c8c5b3c9efaa4 } - d := v.Args[0].Args[0].Aux + d := v.Args[0].Args[0].AuxInt x := v.Args[2] - if !(inBounds(d.(int64), c.(int64))) { - goto endb8f4f98b06c41e559bf0323e798c147a + if !(inBounds(d, c)) { + goto endd5357f3fd5516dcc859c8c5b3c9efaa4 } v.Op = OpCopy + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) return true } - goto endb8f4f98b06c41e559bf0323e798c147a - endb8f4f98b06c41e559bf0323e798c147a: + goto endd5357f3fd5516dcc859c8c5b3c9efaa4 + endd5357f3fd5516dcc859c8c5b3c9efaa4: ; // match: (CMOVQCC (CMPQconst [c] (MOVQconst [d])) x _) - // cond: !inBounds(d.(int64), c.(int64)) + // cond: !inBounds(d, c) // result: (Copy x) { if v.Args[0].Op != OpAMD64CMPQconst { - goto end29407b5c4731ac24b4c25600752cb895 + goto end6ad8b1758415a9afe758272b34970d5d } - c := v.Args[0].Aux + c := v.Args[0].AuxInt if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto end29407b5c4731ac24b4c25600752cb895 + goto end6ad8b1758415a9afe758272b34970d5d } - d := v.Args[0].Args[0].Aux + d := v.Args[0].Args[0].AuxInt x := v.Args[1] - if !(!inBounds(d.(int64), c.(int64))) { - goto end29407b5c4731ac24b4c25600752cb895 + if !(!inBounds(d, c)) { + goto end6ad8b1758415a9afe758272b34970d5d } v.Op = OpCopy + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) return true } - goto end29407b5c4731ac24b4c25600752cb895 - end29407b5c4731ac24b4c25600752cb895: + goto end6ad8b1758415a9afe758272b34970d5d + end6ad8b1758415a9afe758272b34970d5d: ; case OpAMD64CMPQ: // match: (CMPQ x (MOVQconst [c])) @@ -284,12 +292,13 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[1].Op != OpAMD64MOVQconst { goto end32ef1328af280ac18fa8045a3502dae9 } - c := v.Args[1].Aux + c := v.Args[1].AuxInt v.Op = OpAMD64CMPQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) - v.Aux = c + v.AuxInt = c return true } goto end32ef1328af280ac18fa8045a3502dae9 @@ -302,15 +311,16 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[0].Op != OpAMD64MOVQconst { goto endf8ca12fe79290bc82b11cfa463bc9413 } - c := v.Args[0].Aux + c := v.Args[0].AuxInt x := v.Args[1] v.Op = OpAMD64InvertFlags + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpAMD64CMPQconst, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) v0.Type = TypeFlags v0.AddArg(x) - v0.Aux = c + v0.AuxInt = c v.AddArg(v0) return true } @@ -326,6 +336,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { closure := v.Args[1] mem := v.Args[2] v.Op = OpAMD64CALLclosure + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(entry) @@ -342,33 +353,35 @@ func rewriteValueAMD64(v *Value, config *Config) bool { // result: (MOVQconst [val]) { t := v.Type - val := v.Aux + val := v.AuxInt if !(is64BitInt(t)) { goto end7f5c5b34093fbc6860524cb803ee51bf } v.Op = OpAMD64MOVQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = val + v.AuxInt = val return true } goto end7f5c5b34093fbc6860524cb803ee51bf end7f5c5b34093fbc6860524cb803ee51bf: ; case OpGlobal: - // match: (Global [sym]) + // match: (Global {sym}) // cond: - // result: (LEAQglobal [GlobalOffset{sym,0}]) + // result: (LEAQglobal {sym}) { sym := v.Aux v.Op = OpAMD64LEAQglobal + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = GlobalOffset{sym, 0} + v.Aux = sym return true } - goto end3a3c76fac0e2e53c0e1c60b9524e6f1c - end3a3c76fac0e2e53c0e1c60b9524e6f1c: + goto end8f47b6f351fecaeded45abbe5c2beec0 + end8f47b6f351fecaeded45abbe5c2beec0: ; case OpIsInBounds: // match: (IsInBounds idx len) @@ -378,9 +391,10 @@ func rewriteValueAMD64(v *Value, config *Config) bool { idx := v.Args[0] len := v.Args[1] v.Op = OpAMD64SETB + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpAMD64CMPQ, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAMD64CMPQ, TypeInvalid) v0.Type = TypeFlags v0.AddArg(idx) v0.AddArg(len) @@ -397,9 +411,10 @@ func rewriteValueAMD64(v *Value, config *Config) bool { { p := v.Args[0] v.Op = OpAMD64SETNE + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpAMD64TESTQ, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAMD64TESTQ, TypeInvalid) v0.Type = TypeFlags v0.AddArg(p) v0.AddArg(p) @@ -420,9 +435,10 @@ func rewriteValueAMD64(v *Value, config *Config) bool { goto endcecf13a952d4c6c2383561c7d68a3cf9 } v.Op = OpAMD64SETL + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpAMD64CMPQ, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAMD64CMPQ, TypeInvalid) v0.Type = TypeFlags v0.AddArg(x) v0.AddArg(y) @@ -435,94 +451,96 @@ func rewriteValueAMD64(v *Value, config *Config) bool { case OpLoad: // match: (Load ptr mem) // cond: t.IsBoolean() - // result: (MOVBload [int64(0)] ptr mem) + // result: (MOVBload ptr mem) { t := v.Type ptr := v.Args[0] mem := v.Args[1] if !(t.IsBoolean()) { - goto end73f21632e56c3614902d3c29c82dc4ea + goto endc119e594c7f8e8ce5ff97c00b501dba0 } v.Op = OpAMD64MOVBload + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = int64(0) v.AddArg(ptr) v.AddArg(mem) return true } - goto end73f21632e56c3614902d3c29c82dc4ea - end73f21632e56c3614902d3c29c82dc4ea: + goto endc119e594c7f8e8ce5ff97c00b501dba0 + endc119e594c7f8e8ce5ff97c00b501dba0: ; // match: (Load ptr mem) // cond: (is64BitInt(t) || isPtr(t)) - // result: (MOVQload [int64(0)] ptr mem) + // result: (MOVQload ptr mem) { t := v.Type ptr := v.Args[0] mem := v.Args[1] if !(is64BitInt(t) || isPtr(t)) { - goto end581ce5a20901df1b8143448ba031685b + goto end7c4c53acf57ebc5f03273652ba1d5934 } v.Op = OpAMD64MOVQload + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = int64(0) v.AddArg(ptr) v.AddArg(mem) return true } - goto end581ce5a20901df1b8143448ba031685b - end581ce5a20901df1b8143448ba031685b: + goto end7c4c53acf57ebc5f03273652ba1d5934 + end7c4c53acf57ebc5f03273652ba1d5934: ; case OpLsh: // match: (Lsh x y) // cond: is64BitInt(t) - // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPQconst [int64(64)] y))) + // result: (ANDQ (SHLQ x y) (SBBQcarrymask (CMPQconst [64] y))) { t := v.Type x := v.Args[0] y := v.Args[1] if !(is64BitInt(t)) { - goto end7002b6d4becf7d1247e3756641ccb0c2 + goto end5d9e2211940fbc82536685578cf37d08 } v.Op = OpAMD64ANDQ + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpAMD64SHLQ, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAMD64SHLQ, TypeInvalid) v0.Type = t v0.AddArg(x) v0.AddArg(y) v.AddArg(v0) - v1 := v.Block.NewValue(v.Line, OpAMD64SBBQcarrymask, TypeInvalid, nil) + v1 := v.Block.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t - v2 := v.Block.NewValue(v.Line, OpAMD64CMPQconst, TypeInvalid, nil) + v2 := v.Block.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) v2.Type = TypeFlags - v2.Aux = int64(64) + v2.AuxInt = 64 v2.AddArg(y) v1.AddArg(v2) v.AddArg(v1) return true } - goto end7002b6d4becf7d1247e3756641ccb0c2 - end7002b6d4becf7d1247e3756641ccb0c2: + goto end5d9e2211940fbc82536685578cf37d08 + end5d9e2211940fbc82536685578cf37d08: ; case OpAMD64MOVQload: // match: (MOVQload [off1] (ADDQconst [off2] ptr) mem) // cond: // result: (MOVQload [addOff(off1, off2)] ptr mem) { - off1 := v.Aux + off1 := v.AuxInt if v.Args[0].Op != OpAMD64ADDQconst { goto end843d29b538c4483b432b632e5666d6e3 } - off2 := v.Args[0].Aux + off2 := v.Args[0].AuxInt ptr := v.Args[0].Args[0] mem := v.Args[1] v.Op = OpAMD64MOVQload + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = addOff(off1, off2) + v.AuxInt = addOff(off1, off2) v.AddArg(ptr) v.AddArg(mem) return true @@ -534,18 +552,19 @@ func rewriteValueAMD64(v *Value, config *Config) bool { // cond: // result: (MOVQloadidx8 [addOff(off1, off2)] ptr idx mem) { - off1 := v.Aux + off1 := v.AuxInt if v.Args[0].Op != OpAMD64LEAQ8 { goto end02f5ad148292c46463e7c20d3b821735 } - off2 := v.Args[0].Aux + off2 := v.Args[0].AuxInt ptr := v.Args[0].Args[0] idx := v.Args[0].Args[1] mem := v.Args[1] v.Op = OpAMD64MOVQloadidx8 + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = addOff(off1, off2) + v.AuxInt = addOff(off1, off2) v.AddArg(ptr) v.AddArg(idx) v.AddArg(mem) @@ -559,18 +578,19 @@ func rewriteValueAMD64(v *Value, config *Config) bool { // cond: // result: (MOVQloadidx8 [addOff(off1, off2)] ptr idx mem) { - off1 := v.Aux + off1 := v.AuxInt if v.Args[0].Op != OpAMD64ADDQconst { goto ende81e44bcfb11f90916ccb440c590121f } - off2 := v.Args[0].Aux + off2 := v.Args[0].AuxInt ptr := v.Args[0].Args[0] idx := v.Args[1] mem := v.Args[2] v.Op = OpAMD64MOVQloadidx8 + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = addOff(off1, off2) + v.AuxInt = addOff(off1, off2) v.AddArg(ptr) v.AddArg(idx) v.AddArg(mem) @@ -584,18 +604,19 @@ func rewriteValueAMD64(v *Value, config *Config) bool { // cond: // result: (MOVQstore [addOff(off1, off2)] ptr val mem) { - off1 := v.Aux + off1 := v.AuxInt if v.Args[0].Op != OpAMD64ADDQconst { goto end2108c693a43c79aed10b9246c39c80aa } - off2 := v.Args[0].Aux + off2 := v.Args[0].AuxInt ptr := v.Args[0].Args[0] val := v.Args[1] mem := v.Args[2] v.Op = OpAMD64MOVQstore + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = addOff(off1, off2) + v.AuxInt = addOff(off1, off2) v.AddArg(ptr) v.AddArg(val) v.AddArg(mem) @@ -608,19 +629,20 @@ func rewriteValueAMD64(v *Value, config *Config) bool { // cond: // result: (MOVQstoreidx8 [addOff(off1, off2)] ptr idx val mem) { - off1 := v.Aux + off1 := v.AuxInt if v.Args[0].Op != OpAMD64LEAQ8 { goto endce1db8c8d37c8397c500a2068a65c215 } - off2 := v.Args[0].Aux + off2 := v.Args[0].AuxInt ptr := v.Args[0].Args[0] idx := v.Args[0].Args[1] val := v.Args[1] mem := v.Args[2] v.Op = OpAMD64MOVQstoreidx8 + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = addOff(off1, off2) + v.AuxInt = addOff(off1, off2) v.AddArg(ptr) v.AddArg(idx) v.AddArg(val) @@ -635,19 +657,20 @@ func rewriteValueAMD64(v *Value, config *Config) bool { // cond: // result: (MOVQstoreidx8 [addOff(off1, off2)] ptr idx val mem) { - off1 := v.Aux + off1 := v.AuxInt if v.Args[0].Op != OpAMD64ADDQconst { goto end01c970657b0fdefeab82458c15022163 } - off2 := v.Args[0].Aux + off2 := v.Args[0].AuxInt ptr := v.Args[0].Args[0] idx := v.Args[1] val := v.Args[2] mem := v.Args[3] v.Op = OpAMD64MOVQstoreidx8 + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = addOff(off1, off2) + v.AuxInt = addOff(off1, off2) v.AddArg(ptr) v.AddArg(idx) v.AddArg(val) @@ -659,26 +682,27 @@ func rewriteValueAMD64(v *Value, config *Config) bool { ; case OpAMD64MULQ: // match: (MULQ x (MOVQconst [c])) - // cond: c.(int64) == int64(int32(c.(int64))) + // cond: c == int64(int32(c)) // result: (MULQconst [c] x) { x := v.Args[0] if v.Args[1].Op != OpAMD64MOVQconst { - goto ende8c09b194fcde7d9cdc69f2deff86304 + goto end680a32a37babfff4bfa7d23be592a131 } - c := v.Args[1].Aux - if !(c.(int64) == int64(int32(c.(int64)))) { - goto ende8c09b194fcde7d9cdc69f2deff86304 + c := v.Args[1].AuxInt + if !(c == int64(int32(c))) { + goto end680a32a37babfff4bfa7d23be592a131 } v.Op = OpAMD64MULQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c + v.AuxInt = c v.AddArg(x) return true } - goto ende8c09b194fcde7d9cdc69f2deff86304 - ende8c09b194fcde7d9cdc69f2deff86304: + goto end680a32a37babfff4bfa7d23be592a131 + end680a32a37babfff4bfa7d23be592a131: ; // match: (MULQ (MOVQconst [c]) x) // cond: @@ -687,12 +711,13 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[0].Op != OpAMD64MOVQconst { goto endc6e18d6968175d6e58eafa6dcf40c1b8 } - c := v.Args[0].Aux + c := v.Args[0].AuxInt x := v.Args[1] v.Op = OpAMD64MULQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c + v.AuxInt = c v.AddArg(x) return true } @@ -700,67 +725,68 @@ func rewriteValueAMD64(v *Value, config *Config) bool { endc6e18d6968175d6e58eafa6dcf40c1b8: ; case OpAMD64MULQconst: - // match: (MULQconst [c] x) - // cond: c.(int64) == 8 - // result: (SHLQconst [int64(3)] x) + // match: (MULQconst [8] x) + // cond: + // result: (SHLQconst [3] x) { - c := v.Aux - x := v.Args[0] - if !(c.(int64) == 8) { - goto end7e16978c56138324ff2abf91fd6d94d4 + if v.AuxInt != 8 { + goto ende8d313a52a134fb2e1c0beb54ea599fd } + x := v.Args[0] v.Op = OpAMD64SHLQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = int64(3) + v.AuxInt = 3 v.AddArg(x) return true } - goto end7e16978c56138324ff2abf91fd6d94d4 - end7e16978c56138324ff2abf91fd6d94d4: + goto ende8d313a52a134fb2e1c0beb54ea599fd + ende8d313a52a134fb2e1c0beb54ea599fd: ; - // match: (MULQconst [c] x) - // cond: c.(int64) == 64 - // result: (SHLQconst [int64(5)] x) + // match: (MULQconst [64] x) + // cond: + // result: (SHLQconst [5] x) { - c := v.Aux - x := v.Args[0] - if !(c.(int64) == 64) { - goto end2c7a02f230e4b311ac3a4e22f70a4f08 + if v.AuxInt != 64 { + goto end75c0c250c703f89e6c43d718dd5ea3c0 } + x := v.Args[0] v.Op = OpAMD64SHLQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = int64(5) + v.AuxInt = 5 v.AddArg(x) return true } - goto end2c7a02f230e4b311ac3a4e22f70a4f08 - end2c7a02f230e4b311ac3a4e22f70a4f08: + goto end75c0c250c703f89e6c43d718dd5ea3c0 + end75c0c250c703f89e6c43d718dd5ea3c0: ; case OpMove: // match: (Move [size] dst src mem) // cond: - // result: (REPMOVSB dst src (Const [size.(int64)]) mem) + // result: (REPMOVSB dst src (Const [size]) mem) { - size := v.Aux + size := v.AuxInt dst := v.Args[0] src := v.Args[1] mem := v.Args[2] v.Op = OpAMD64REPMOVSB + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(dst) v.AddArg(src) - v0 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) v0.Type = TypeUInt64 - v0.Aux = size.(int64) + v0.AuxInt = size v.AddArg(v0) v.AddArg(mem) return true } - goto end48909259b265a6bb2a076bc2c2dc7d1f - end48909259b265a6bb2a076bc2c2dc7d1f: + goto end1b2d226705fd31dbbe74e3286af178ea + end1b2d226705fd31dbbe74e3286af178ea: ; case OpMul: // match: (Mul x y) @@ -774,6 +800,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { goto endfab0d598f376ecba45a22587d50f7aff } v.Op = OpAMD64MULQ + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) @@ -788,12 +815,13 @@ func rewriteValueAMD64(v *Value, config *Config) bool { // cond: // result: (ADDQconst [off] ptr) { - off := v.Aux + off := v.AuxInt ptr := v.Args[0] v.Op = OpAMD64ADDQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = off + v.AuxInt = off v.AddArg(ptr) return true } @@ -803,67 +831,69 @@ func rewriteValueAMD64(v *Value, config *Config) bool { case OpRsh: // match: (Rsh x y) // cond: is64BitInt(t) && !t.IsSigned() - // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPQconst [int64(64)] y))) + // result: (ANDQ (SHRQ x y) (SBBQcarrymask (CMPQconst [64] y))) { t := v.Type x := v.Args[0] y := v.Args[1] if !(is64BitInt(t) && !t.IsSigned()) { - goto end9463ddaa21c75f8e15cb9f31472a2e23 + goto ende3e068773b8e6def1eaedb4f404ca6e5 } v.Op = OpAMD64ANDQ + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpAMD64SHRQ, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAMD64SHRQ, TypeInvalid) v0.Type = t v0.AddArg(x) v0.AddArg(y) v.AddArg(v0) - v1 := v.Block.NewValue(v.Line, OpAMD64SBBQcarrymask, TypeInvalid, nil) + v1 := v.Block.NewValue0(v.Line, OpAMD64SBBQcarrymask, TypeInvalid) v1.Type = t - v2 := v.Block.NewValue(v.Line, OpAMD64CMPQconst, TypeInvalid, nil) + v2 := v.Block.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) v2.Type = TypeFlags - v2.Aux = int64(64) + v2.AuxInt = 64 v2.AddArg(y) v1.AddArg(v2) v.AddArg(v1) return true } - goto end9463ddaa21c75f8e15cb9f31472a2e23 - end9463ddaa21c75f8e15cb9f31472a2e23: + goto ende3e068773b8e6def1eaedb4f404ca6e5 + ende3e068773b8e6def1eaedb4f404ca6e5: ; // match: (Rsh x y) // cond: is64BitInt(t) && t.IsSigned() - // result: (SARQ x (CMOVQCC (CMPQconst [int64(64)] y) (Const [int64(63)]) y)) + // result: (SARQ x (CMOVQCC (CMPQconst [64] y) (Const [63]) y)) { t := v.Type x := v.Args[0] y := v.Args[1] if !(is64BitInt(t) && t.IsSigned()) { - goto endd297b9e569ac90bf815bd4c425d3b770 + goto end901ea4851cd5d2277a1ca1bee8f69d59 } v.Op = OpAMD64SARQ + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.Type = t v.AddArg(x) - v0 := v.Block.NewValue(v.Line, OpAMD64CMOVQCC, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAMD64CMOVQCC, TypeInvalid) v0.Type = t - v1 := v.Block.NewValue(v.Line, OpAMD64CMPQconst, TypeInvalid, nil) + v1 := v.Block.NewValue0(v.Line, OpAMD64CMPQconst, TypeInvalid) v1.Type = TypeFlags - v1.Aux = int64(64) + v1.AuxInt = 64 v1.AddArg(y) v0.AddArg(v1) - v2 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil) + v2 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) v2.Type = t - v2.Aux = int64(63) + v2.AuxInt = 63 v0.AddArg(v2) v0.AddArg(y) v.AddArg(v0) return true } - goto endd297b9e569ac90bf815bd4c425d3b770 - endd297b9e569ac90bf815bd4c425d3b770: + goto end901ea4851cd5d2277a1ca1bee8f69d59 + end901ea4851cd5d2277a1ca1bee8f69d59: ; case OpAMD64SARQ: // match: (SARQ x (MOVQconst [c])) @@ -874,11 +904,12 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[1].Op != OpAMD64MOVQconst { goto end031712b4008075e25a5827dcb8dd3ebb } - c := v.Args[1].Aux + c := v.Args[1].AuxInt v.Op = OpAMD64SARQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c + v.AuxInt = c v.AddArg(x) return true } @@ -887,52 +918,54 @@ func rewriteValueAMD64(v *Value, config *Config) bool { ; case OpAMD64SBBQcarrymask: // match: (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) - // cond: inBounds(d.(int64), c.(int64)) - // result: (Const [int64(-1)]) + // cond: inBounds(d, c) + // result: (Const [-1]) { if v.Args[0].Op != OpAMD64CMPQconst { - goto end35e369f67ebb9423a1d36a808a16777c + goto endf67d323ecef000dbcd15d7e031c3475e } - c := v.Args[0].Aux + c := v.Args[0].AuxInt if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto end35e369f67ebb9423a1d36a808a16777c + goto endf67d323ecef000dbcd15d7e031c3475e } - d := v.Args[0].Args[0].Aux - if !(inBounds(d.(int64), c.(int64))) { - goto end35e369f67ebb9423a1d36a808a16777c + d := v.Args[0].Args[0].AuxInt + if !(inBounds(d, c)) { + goto endf67d323ecef000dbcd15d7e031c3475e } v.Op = OpConst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = int64(-1) + v.AuxInt = -1 return true } - goto end35e369f67ebb9423a1d36a808a16777c - end35e369f67ebb9423a1d36a808a16777c: + goto endf67d323ecef000dbcd15d7e031c3475e + endf67d323ecef000dbcd15d7e031c3475e: ; // match: (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) - // cond: !inBounds(d.(int64), c.(int64)) - // result: (Const [int64(0)]) + // cond: !inBounds(d, c) + // result: (Const [0]) { if v.Args[0].Op != OpAMD64CMPQconst { - goto end5c767fada028c1cc96210af2cf098aff + goto end4157ddea9c4f71bfabfd6fa50e1208ed } - c := v.Args[0].Aux + c := v.Args[0].AuxInt if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto end5c767fada028c1cc96210af2cf098aff + goto end4157ddea9c4f71bfabfd6fa50e1208ed } - d := v.Args[0].Args[0].Aux - if !(!inBounds(d.(int64), c.(int64))) { - goto end5c767fada028c1cc96210af2cf098aff + d := v.Args[0].Args[0].AuxInt + if !(!inBounds(d, c)) { + goto end4157ddea9c4f71bfabfd6fa50e1208ed } v.Op = OpConst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = int64(0) + v.AuxInt = 0 return true } - goto end5c767fada028c1cc96210af2cf098aff - end5c767fada028c1cc96210af2cf098aff: + goto end4157ddea9c4f71bfabfd6fa50e1208ed + end4157ddea9c4f71bfabfd6fa50e1208ed: ; case OpAMD64SETG: // match: (SETG (InvertFlags x)) @@ -944,6 +977,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { } x := v.Args[0].Args[0] v.Op = OpAMD64SETL + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) @@ -962,6 +996,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { } x := v.Args[0].Args[0] v.Op = OpAMD64SETG + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) @@ -979,11 +1014,12 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[1].Op != OpAMD64MOVQconst { goto endcca412bead06dc3d56ef034a82d184d6 } - c := v.Args[1].Aux + c := v.Args[1].AuxInt v.Op = OpAMD64SHLQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c + v.AuxInt = c v.AddArg(x) return true } @@ -999,11 +1035,12 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[1].Op != OpAMD64MOVQconst { goto endbb0d3a04dd2b810cb3dbdf7ef665f22b } - c := v.Args[1].Aux + c := v.Args[1].AuxInt v.Op = OpAMD64SHRQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c + v.AuxInt = c v.AddArg(x) return true } @@ -1019,12 +1056,13 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[1].Op != OpAMD64MOVQconst { goto end5a74a63bd9ad15437717c6df3b25eebb } - c := v.Args[1].Aux + c := v.Args[1].AuxInt v.Op = OpAMD64SUBQconst + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) - v.Aux = c + v.AuxInt = c return true } goto end5a74a63bd9ad15437717c6df3b25eebb @@ -1038,15 +1076,16 @@ func rewriteValueAMD64(v *Value, config *Config) bool { if v.Args[0].Op != OpAMD64MOVQconst { goto end78e66b6fc298684ff4ac8aec5ce873c9 } - c := v.Args[0].Aux + c := v.Args[0].AuxInt x := v.Args[1] v.Op = OpAMD64NEGQ + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpAMD64SUBQconst, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAMD64SUBQconst, TypeInvalid) v0.Type = t v0.AddArg(x) - v0.Aux = c + v0.AuxInt = c v.AddArg(v0) return true } @@ -1058,12 +1097,13 @@ func rewriteValueAMD64(v *Value, config *Config) bool { // cond: // result: (CALLstatic [target] mem) { - target := v.Aux + target := v.AuxInt mem := v.Args[0] v.Op = OpAMD64CALLstatic + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = target + v.AuxInt = target v.AddArg(mem) return true } @@ -1073,25 +1113,25 @@ func rewriteValueAMD64(v *Value, config *Config) bool { case OpStore: // match: (Store ptr val mem) // cond: (is64BitInt(val.Type) || isPtr(val.Type)) - // result: (MOVQstore [int64(0)] ptr val mem) + // result: (MOVQstore ptr val mem) { ptr := v.Args[0] val := v.Args[1] mem := v.Args[2] if !(is64BitInt(val.Type) || isPtr(val.Type)) { - goto end9680b43f504bc06f9fab000823ce471a + goto endbaeb60123806948cd2433605820d5af1 } v.Op = OpAMD64MOVQstore + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = int64(0) v.AddArg(ptr) v.AddArg(val) v.AddArg(mem) return true } - goto end9680b43f504bc06f9fab000823ce471a - end9680b43f504bc06f9fab000823ce471a: + goto endbaeb60123806948cd2433605820d5af1 + endbaeb60123806948cd2433605820d5af1: ; case OpSub: // match: (Sub x y) @@ -1105,6 +1145,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { goto ende6ef29f885a8ecf3058212bb95917323 } v.Op = OpAMD64SUBQ + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(x) @@ -1254,7 +1295,7 @@ func rewriteBlockAMD64(b *Block) bool { goto end7e22019fb0effc80f85c05ea30bdb5d9 } b.Kind = BlockAMD64NE - v0 := v.Block.NewValue(v.Line, OpAMD64TESTB, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAMD64TESTB, TypeInvalid) v0.Type = TypeFlags v0.AddArg(cond) v0.AddArg(cond) diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index e38439de14..0ecc436343 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -7,28 +7,29 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpAdd: // match: (Add (Const [c]) (Const [d])) // cond: is64BitInt(t) - // result: (Const [{c.(int64)+d.(int64)}]) + // result: (Const [c+d]) { t := v.Type if v.Args[0].Op != OpConst { - goto end8d047ed0ae9537b840adc79ea82c6e05 + goto end279f4ea85ed10e5ffc5b53f9e060529b } - c := v.Args[0].Aux + c := v.Args[0].AuxInt if v.Args[1].Op != OpConst { - goto end8d047ed0ae9537b840adc79ea82c6e05 + goto end279f4ea85ed10e5ffc5b53f9e060529b } - d := v.Args[1].Aux + d := v.Args[1].AuxInt if !(is64BitInt(t)) { - goto end8d047ed0ae9537b840adc79ea82c6e05 + goto end279f4ea85ed10e5ffc5b53f9e060529b } v.Op = OpConst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c.(int64) + d.(int64) + v.AuxInt = c + d return true } - goto end8d047ed0ae9537b840adc79ea82c6e05 - end8d047ed0ae9537b840adc79ea82c6e05: + goto end279f4ea85ed10e5ffc5b53f9e060529b + end279f4ea85ed10e5ffc5b53f9e060529b: ; case OpArrayIndex: // match: (ArrayIndex (Load ptr mem) idx) @@ -42,9 +43,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool { mem := v.Args[0].Args[1] idx := v.Args[1] v.Op = OpLoad + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpPtrIndex, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpPtrIndex, TypeInvalid) v0.Type = ptr.Type.Elem().Elem().PtrTo() v0.AddArg(ptr) v0.AddArg(idx) @@ -56,56 +58,58 @@ func rewriteValuegeneric(v *Value, config *Config) bool { end3809f4c52270a76313e4ea26e6f0b753: ; case OpConst: - // match: (Const [s]) + // match: (Const {s}) // cond: t.IsString() - // result: (StringMake (OffPtr [2*config.ptrSize] (Global [config.fe.StringSym(s.(string))])) (Const [int64(len(s.(string)))])) + // result: (StringMake (OffPtr [2*config.ptrSize] (Global {config.fe.StringSym(s.(string))})) (Const [int64(len(s.(string)))])) { t := v.Type s := v.Aux if !(t.IsString()) { - goto end8442aa5b3f4e5b840055475883110372 + goto end6d6321106a054a5984b2ed0acec52a5b } v.Op = OpStringMake + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid) v0.Type = TypeBytePtr - v0.Aux = 2 * config.ptrSize - v1 := v.Block.NewValue(v.Line, OpGlobal, TypeInvalid, nil) + v0.AuxInt = 2 * config.ptrSize + v1 := v.Block.NewValue0(v.Line, OpGlobal, TypeInvalid) v1.Type = TypeBytePtr v1.Aux = config.fe.StringSym(s.(string)) v0.AddArg(v1) v.AddArg(v0) - v2 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil) + v2 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) v2.Type = config.Uintptr - v2.Aux = int64(len(s.(string))) + v2.AuxInt = int64(len(s.(string))) v.AddArg(v2) return true } - goto end8442aa5b3f4e5b840055475883110372 - end8442aa5b3f4e5b840055475883110372: + goto end6d6321106a054a5984b2ed0acec52a5b + end6d6321106a054a5984b2ed0acec52a5b: ; case OpIsInBounds: // match: (IsInBounds (Const [c]) (Const [d])) // cond: - // result: (Const [inBounds(c.(int64),d.(int64))]) + // result: (Const {inBounds(c,d)}) { if v.Args[0].Op != OpConst { - goto enddbd1a394d9b71ee64335361b8384865c + goto enda96ccac78df2d17ae96c8baf2af2e189 } - c := v.Args[0].Aux + c := v.Args[0].AuxInt if v.Args[1].Op != OpConst { - goto enddbd1a394d9b71ee64335361b8384865c + goto enda96ccac78df2d17ae96c8baf2af2e189 } - d := v.Args[1].Aux + d := v.Args[1].AuxInt v.Op = OpConst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = inBounds(c.(int64), d.(int64)) + v.Aux = inBounds(c, d) return true } - goto enddbd1a394d9b71ee64335361b8384865c - enddbd1a394d9b71ee64335361b8384865c: + goto enda96ccac78df2d17ae96c8baf2af2e189 + enda96ccac78df2d17ae96c8baf2af2e189: ; case OpLoad: // match: (Load ptr mem) @@ -119,18 +123,19 @@ func rewriteValuegeneric(v *Value, config *Config) bool { goto endd0afd003b70d726a1c5bbaf51fe06182 } v.Op = OpStringMake + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid) v0.Type = TypeBytePtr v0.AddArg(ptr) v0.AddArg(mem) v.AddArg(v0) - v1 := v.Block.NewValue(v.Line, OpLoad, TypeInvalid, nil) + v1 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid) v1.Type = config.Uintptr - v2 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil) + v2 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid) v2.Type = TypeBytePtr - v2.Aux = config.ptrSize + v2.AuxInt = config.ptrSize v2.AddArg(ptr) v1.AddArg(v2) v1.AddArg(mem) @@ -143,28 +148,29 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpMul: // match: (Mul (Const [c]) (Const [d])) // cond: is64BitInt(t) - // result: (Const [{c.(int64)*d.(int64)}]) + // result: (Const [c*d]) { t := v.Type if v.Args[0].Op != OpConst { - goto end776610f88cf04f438242d76ed2b14f1c + goto endd82095c6a872974522d33aaff1ee07be } - c := v.Args[0].Aux + c := v.Args[0].AuxInt if v.Args[1].Op != OpConst { - goto end776610f88cf04f438242d76ed2b14f1c + goto endd82095c6a872974522d33aaff1ee07be } - d := v.Args[1].Aux + d := v.Args[1].AuxInt if !(is64BitInt(t)) { - goto end776610f88cf04f438242d76ed2b14f1c + goto endd82095c6a872974522d33aaff1ee07be } v.Op = OpConst + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = c.(int64) * d.(int64) + v.AuxInt = c * d return true } - goto end776610f88cf04f438242d76ed2b14f1c - end776610f88cf04f438242d76ed2b14f1c: + goto endd82095c6a872974522d33aaff1ee07be + endd82095c6a872974522d33aaff1ee07be: ; case OpPtrIndex: // match: (PtrIndex ptr idx) @@ -175,15 +181,16 @@ func rewriteValuegeneric(v *Value, config *Config) bool { ptr := v.Args[0] idx := v.Args[1] v.Op = OpAdd + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(ptr) - v0 := v.Block.NewValue(v.Line, OpMul, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpMul, TypeInvalid) v0.Type = config.Uintptr v0.AddArg(idx) - v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil) + v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) v1.Type = config.Uintptr - v1.Aux = t.Elem().Size() + v1.AuxInt = t.Elem().Size() v0.AddArg(v1) v.AddArg(v0) return true @@ -194,56 +201,58 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpSliceCap: // match: (SliceCap (Load ptr mem)) // cond: - // result: (Load (Add ptr (Const [int64(config.ptrSize*2)])) mem) + // result: (Load (Add ptr (Const [config.ptrSize*2])) mem) { if v.Args[0].Op != OpLoad { - goto endc871dcd9a720b4290c9cae78fe147c8a + goto end919cfa3d3539eb2e06a435d5f89654b9 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] v.Op = OpLoad + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAdd, TypeInvalid) v0.Type = ptr.Type v0.AddArg(ptr) - v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil) + v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) v1.Type = config.Uintptr - v1.Aux = int64(config.ptrSize * 2) + v1.AuxInt = config.ptrSize * 2 v0.AddArg(v1) v.AddArg(v0) v.AddArg(mem) return true } - goto endc871dcd9a720b4290c9cae78fe147c8a - endc871dcd9a720b4290c9cae78fe147c8a: + goto end919cfa3d3539eb2e06a435d5f89654b9 + end919cfa3d3539eb2e06a435d5f89654b9: ; case OpSliceLen: // match: (SliceLen (Load ptr mem)) // cond: - // result: (Load (Add ptr (Const [int64(config.ptrSize)])) mem) + // result: (Load (Add ptr (Const [config.ptrSize])) mem) { if v.Args[0].Op != OpLoad { - goto end1eec05e44f5fc8944e7c176f98a74d92 + goto end3d74a5ef07180a709a91052da88bcd01 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] v.Op = OpLoad + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpAdd, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpAdd, TypeInvalid) v0.Type = ptr.Type v0.AddArg(ptr) - v1 := v.Block.NewValue(v.Line, OpConst, TypeInvalid, nil) + v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) v1.Type = config.Uintptr - v1.Aux = int64(config.ptrSize) + v1.AuxInt = config.ptrSize v0.AddArg(v1) v.AddArg(v0) v.AddArg(mem) return true } - goto end1eec05e44f5fc8944e7c176f98a74d92 - end1eec05e44f5fc8944e7c176f98a74d92: + goto end3d74a5ef07180a709a91052da88bcd01 + end3d74a5ef07180a709a91052da88bcd01: ; case OpSlicePtr: // match: (SlicePtr (Load ptr mem)) @@ -256,6 +265,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool { ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] v.Op = OpLoad + v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AddArg(ptr) @@ -284,9 +294,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool { goto end324ffb6d2771808da4267f62c854e9c8 } v.Op = OpMove + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = t.Size() + v.AuxInt = t.Size() v.AddArg(dst) v.AddArg(src) v.AddArg(mem) @@ -306,21 +317,22 @@ func rewriteValuegeneric(v *Value, config *Config) bool { goto end410559d97aed8018f820cd88723de442 } v.Op = OpStore + v.AuxInt = 0 v.Aux = nil v.resetArgs() - v0 := v.Block.NewValue(v.Line, OpOffPtr, TypeInvalid, nil) + v0 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid) v0.Type = TypeBytePtr - v0.Aux = config.ptrSize + v0.AuxInt = config.ptrSize v0.AddArg(dst) v.AddArg(v0) - v1 := v.Block.NewValue(v.Line, OpStringLen, TypeInvalid, nil) + v1 := v.Block.NewValue0(v.Line, OpStringLen, TypeInvalid) v1.Type = config.Uintptr v1.AddArg(str) v.AddArg(v1) - v2 := v.Block.NewValue(v.Line, OpStore, TypeInvalid, nil) + v2 := v.Block.NewValue0(v.Line, OpStore, TypeInvalid) v2.Type = TypeMem v2.AddArg(dst) - v3 := v.Block.NewValue(v.Line, OpStringPtr, TypeInvalid, nil) + v3 := v.Block.NewValue0(v.Line, OpStringPtr, TypeInvalid) v3.Type = TypeBytePtr v3.AddArg(str) v2.AddArg(v3) @@ -341,6 +353,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool { } len := v.Args[0].Args[1] v.Op = len.Op + v.AuxInt = len.AuxInt v.Aux = len.Aux v.resetArgs() v.AddArgs(len.Args...) @@ -359,6 +372,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool { } ptr := v.Args[0].Args[0] v.Op = ptr.Op + v.AuxInt = ptr.AuxInt v.Aux = ptr.Aux v.resetArgs() v.AddArgs(ptr.Args...) @@ -372,19 +386,19 @@ func rewriteValuegeneric(v *Value, config *Config) bool { func rewriteBlockgeneric(b *Block) bool { switch b.Kind { case BlockIf: - // match: (If (Const [c]) yes no) + // match: (If (Const {c}) yes no) // cond: c.(bool) // result: (Plain nil yes) { v := b.Control if v.Op != OpConst { - goto end60cde11c1be8092f493d9cda982445ca + goto end915e334b6388fed7d63e09aa69ecb05c } c := v.Aux yes := b.Succs[0] no := b.Succs[1] if !(c.(bool)) { - goto end60cde11c1be8092f493d9cda982445ca + goto end915e334b6388fed7d63e09aa69ecb05c } removePredecessor(b, no) b.Kind = BlockPlain @@ -393,22 +407,22 @@ func rewriteBlockgeneric(b *Block) bool { b.Succs[0] = yes return true } - goto end60cde11c1be8092f493d9cda982445ca - end60cde11c1be8092f493d9cda982445ca: + goto end915e334b6388fed7d63e09aa69ecb05c + end915e334b6388fed7d63e09aa69ecb05c: ; - // match: (If (Const [c]) yes no) + // match: (If (Const {c}) yes no) // cond: !c.(bool) // result: (Plain nil no) { v := b.Control if v.Op != OpConst { - goto endf2a5efbfd2d40dead087c33685c8f30b + goto end6452ee3a5bb02c708bddc3181c3ea3cb } c := v.Aux yes := b.Succs[0] no := b.Succs[1] if !(!c.(bool)) { - goto endf2a5efbfd2d40dead087c33685c8f30b + goto end6452ee3a5bb02c708bddc3181c3ea3cb } removePredecessor(b, yes) b.Kind = BlockPlain @@ -417,8 +431,8 @@ func rewriteBlockgeneric(b *Block) bool { b.Succs[0] = no return true } - goto endf2a5efbfd2d40dead087c33685c8f30b - endf2a5efbfd2d40dead087c33685c8f30b: + goto end6452ee3a5bb02c708bddc3181c3ea3cb + end6452ee3a5bb02c708bddc3181c3ea3cb: } return false } diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go index 4830f79628..a7c33d9d59 100644 --- a/src/cmd/compile/internal/ssa/schedule_test.go +++ b/src/cmd/compile/internal/ssa/schedule_test.go @@ -11,15 +11,15 @@ func TestSchedule(t *testing.T) { cases := []fun{ Fun(c, "entry", Bloc("entry", - Valu("mem0", OpArg, TypeMem, ".mem"), - Valu("ptr", OpConst, TypeInt64, 0xABCD), - Valu("v", OpConst, TypeInt64, 12), - Valu("mem1", OpStore, TypeMem, 32, "ptr", "v", "mem0"), - Valu("mem2", OpStore, TypeMem, 32, "ptr", "v", "mem1"), - Valu("mem3", OpStore, TypeInt64, "ptr", "sum", "mem2"), - Valu("l1", OpLoad, TypeInt64, 16, "ptr", "mem1"), - Valu("l2", OpLoad, TypeInt64, 8, "ptr", "mem2"), - Valu("sum", OpAdd, TypeInt64, "l1", "l2"), + Valu("mem0", OpArg, TypeMem, 0, ".mem"), + Valu("ptr", OpConst, TypeInt64, 0xABCD, nil), + Valu("v", OpConst, TypeInt64, 12, nil), + Valu("mem1", OpStore, TypeMem, 0, nil, "ptr", "v", "mem0"), + Valu("mem2", OpStore, TypeMem, 0, nil, "ptr", "v", "mem1"), + Valu("mem3", OpStore, TypeInt64, 0, nil, "ptr", "sum", "mem2"), + Valu("l1", OpLoad, TypeInt64, 0, nil, "ptr", "mem1"), + Valu("l2", OpLoad, TypeInt64, 0, nil, "ptr", "mem2"), + Valu("sum", OpAdd, TypeInt64, 0, nil, "l1", "l2"), Goto("exit")), Bloc("exit", Exit("mem3"))), diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index bba4f782dc..b4b4f47ff0 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -28,14 +28,14 @@ func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun { ptyp := &TypeImpl{Size_: 8, Ptr: true, Name: "ptr"} fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, ".mem"), - Valu("FP", OpFP, TypeUInt64, nil), - Valu("argptr", OpOffPtr, ptyp, int64(8), "FP"), - Valu("resptr", OpOffPtr, ptyp, int64(16), "FP"), - Valu("load", OpLoad, typ, nil, "argptr", "mem"), - Valu("c", OpConst, TypeUInt64, amount), - Valu("shift", op, typ, nil, "load", "c"), - Valu("store", OpStore, TypeMem, nil, "resptr", "shift", "mem"), + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("FP", OpFP, TypeUInt64, 0, nil), + Valu("argptr", OpOffPtr, ptyp, 8, nil, "FP"), + Valu("resptr", OpOffPtr, ptyp, 16, nil, "FP"), + Valu("load", OpLoad, typ, 0, nil, "argptr", "mem"), + Valu("c", OpConst, TypeUInt64, amount, nil), + Valu("shift", op, typ, 0, nil, "load", "c"), + Valu("store", OpStore, TypeMem, 0, nil, "resptr", "shift", "mem"), Exit("store"))) Compile(fun.f) return fun diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index d47c8c7b02..cb1688f51c 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -92,14 +92,14 @@ func stackalloc(f *Func) { case OpAMD64ADDQ: // (ADDQ (FP) x) -> (LEAQ [n] (SP) x) v.Op = OpAMD64LEAQ - v.Aux = n + v.AuxInt = n 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) } // eg: (MOVQload [c] (FP) mem) -> (MOVQload [c+n] (SP) mem) - v.Aux = addOffset(v.Aux.(int64), n) + v.AuxInt = addOff(v.AuxInt, 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 f249bba43e..3ed1f3c2b9 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -22,7 +22,9 @@ type Value struct { Type Type // Auxiliary info for this value. The type of this information depends on the opcode and type. - Aux interface{} + // AuxInt is used for integer values, Aux is used for other values. + AuxInt int64 + Aux interface{} // Arguments of this value Args []*Value @@ -53,8 +55,11 @@ func (v *Value) String() string { func (v *Value) LongString() string { s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String()) s += " <" + v.Type.String() + ">" + if v.AuxInt != 0 { + s += fmt.Sprintf(" [%d]", v.AuxInt) + } if v.Aux != nil { - s += fmt.Sprintf(" [%v]", v.Aux) + s += fmt.Sprintf(" {%v}", v.Aux) } for _, a := range v.Args { s += fmt.Sprintf(" %v", a) -- cgit v1.3 From 8c6abfeacb27f1bcce8fb01f7da95950590943e3 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Fri, 12 Jun 2015 11:01:13 -0700 Subject: [dev.ssa] cmd/compile/ssa: separate logging, work in progress, and fatal errors The SSA implementation logs for three purposes: * debug logging * fatal errors * unimplemented features Separating these three uses lets us attempt an SSA implementation for all functions, not just _ssa functions. This turns the entire standard library into a compilation test, and makes it easy to figure out things like "how much coverage does SSA have now" and "what should we do next to get more coverage?". Functions called _ssa are still special. They log profusely by default and the output of the SSA implementation is used. For all other functions, logging is off, and the implementation is built and discarded, due to lack of support for the runtime. While we're here, fix a few minor bugs and add some extra Unimplementeds to allow all.bash to pass. As of now, SSA handles 20.79% of the functions in the standard library (689 of 3314). The top missing features are: 10.03% 2597 SSA unimplemented: zero for type error not implemented 7.79% 2016 SSA unimplemented: addr: bad op DOTPTR 7.33% 1898 SSA unimplemented: unhandled expr EQ 6.10% 1579 SSA unimplemented: unhandled expr OROR 4.91% 1271 SSA unimplemented: unhandled expr NE 4.49% 1163 SSA unimplemented: unhandled expr LROT 4.00% 1036 SSA unimplemented: unhandled expr LEN 3.56% 923 SSA unimplemented: unhandled stmt CALLFUNC 2.37% 615 SSA unimplemented: zero for type []byte not implemented 1.90% 492 SSA unimplemented: unhandled stmt CALLMETH 1.74% 450 SSA unimplemented: unhandled expr CALLINTER 1.74% 450 SSA unimplemented: unhandled expr DOT 1.71% 444 SSA unimplemented: unhandled expr ANDAND 1.65% 426 SSA unimplemented: unhandled expr CLOSUREVAR 1.54% 400 SSA unimplemented: unhandled expr CALLMETH 1.51% 390 SSA unimplemented: unhandled stmt SWITCH 1.47% 380 SSA unimplemented: unhandled expr CONV 1.33% 345 SSA unimplemented: addr: bad op * 1.30% 336 SSA unimplemented: unhandled OLITERAL 6 Change-Id: I4ca07951e276714dc13c31de28640aead17a1be7 Reviewed-on: https://go-review.googlesource.com/11160 Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/pgen.go | 13 +-- src/cmd/compile/internal/gc/ssa.go | 126 ++++++++++++++++++++----- src/cmd/compile/internal/ssa/TODO | 1 - src/cmd/compile/internal/ssa/block.go | 4 + src/cmd/compile/internal/ssa/check.go | 44 +++++---- src/cmd/compile/internal/ssa/compile.go | 13 +-- src/cmd/compile/internal/ssa/config.go | 18 +++- src/cmd/compile/internal/ssa/deadcode.go | 6 +- src/cmd/compile/internal/ssa/deadcode_test.go | 6 +- src/cmd/compile/internal/ssa/deadstore.go | 6 +- src/cmd/compile/internal/ssa/deadstore_test.go | 6 +- src/cmd/compile/internal/ssa/dom.go | 6 +- src/cmd/compile/internal/ssa/export_test.go | 12 ++- src/cmd/compile/internal/ssa/func.go | 8 +- src/cmd/compile/internal/ssa/func_test.go | 14 +-- src/cmd/compile/internal/ssa/gen/generic.rules | 2 +- src/cmd/compile/internal/ssa/layout.go | 4 +- src/cmd/compile/internal/ssa/lower.go | 4 +- src/cmd/compile/internal/ssa/print.go | 3 +- src/cmd/compile/internal/ssa/regalloc.go | 10 +- src/cmd/compile/internal/ssa/rewrite.go | 11 +-- src/cmd/compile/internal/ssa/rewritegeneric.go | 10 +- src/cmd/compile/internal/ssa/schedule_test.go | 2 +- src/cmd/compile/internal/ssa/shift_test.go | 2 +- src/cmd/compile/internal/ssa/stackalloc.go | 8 +- src/cmd/compile/internal/ssa/value.go | 4 + 26 files changed, 211 insertions(+), 132 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index e6b670f7a2..6a6c213b84 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -355,6 +355,7 @@ func compile(fn *Node) { var gcargs *Sym var gclocals *Sym var ssafn *ssa.Func + var usessa bool if fn.Nbody == nil { if pure_go != 0 || strings.HasPrefix(fn.Func.Nname.Sym.Name, "init.") { Yyerror("missing function body for %q", fn.Func.Nname.Sym.Name) @@ -406,13 +407,9 @@ func compile(fn *Node) { goto ret } - // Build an SSA backend function - { - name := Curfn.Func.Nname.Sym.Name - if len(name) > 4 && name[len(name)-4:] == "_ssa" { - ssafn = buildssa(Curfn) - } - } + // Build an SSA backend function. + // TODO: get rid of usessa. + ssafn, usessa = buildssa(Curfn) continpc = nil breakpc = nil @@ -475,7 +472,7 @@ func compile(fn *Node) { } } - if ssafn != nil { + if ssafn != nil && usessa { genssa(ssafn, ptxt, gcargs, gclocals) return } diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index f2dbabe6ad..1218a23488 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -5,26 +5,48 @@ package gc import ( - "log" + "fmt" "cmd/compile/internal/ssa" "cmd/internal/obj" "cmd/internal/obj/x86" // TODO: remove ) -func buildssa(fn *Node) *ssa.Func { - dumplist("buildssa-enter", fn.Func.Enter) - dumplist("buildssa-body", fn.Nbody) +// buildssa builds an SSA function +// and reports whether it should be used. +// Once the SSA implementation is complete, +// it will never return nil, and the bool can be removed. +func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { + name := fn.Func.Nname.Sym.Name + usessa = len(name) > 4 && name[len(name)-4:] == "_ssa" + + if usessa { + dumplist("buildssa-enter", fn.Func.Enter) + dumplist("buildssa-body", fn.Nbody) + } var s state - s.pushLine(fn.Lineno) defer s.popLine() // TODO(khr): build config just once at the start of the compiler binary - s.config = ssa.NewConfig(Thearch.Thestring, ssaExport{}) + + var e ssaExport + e.log = usessa + s.config = ssa.NewConfig(Thearch.Thestring, &e) s.f = s.config.NewFunc() - s.f.Name = fn.Func.Nname.Sym.Name + s.f.Name = name + + // If SSA support for the function is incomplete, + // assume that any panics are due to violated + // invariants. Swallow them silently. + defer func() { + if err := recover(); err != nil { + if !e.unimplemented { + panic(err) + } + } + }() // We construct SSA using an algorithm similar to // Brau, Buchwald, Hack, Leißa, Mallon, and Zwinkau @@ -67,7 +89,15 @@ func buildssa(fn *Node) *ssa.Func { // Main call to ssa package to compile function ssa.Compile(s.f) - return s.f + // Calculate stats about what percentage of functions SSA handles. + if false { + fmt.Printf("SSA implemented: %t\n", !e.unimplemented) + } + + if e.unimplemented { + return nil, false + } + return s.f, usessa // TODO: return s.f, true once runtime support is in (gc maps, write barriers, etc.) } type state struct { @@ -105,10 +135,13 @@ type state struct { line []int32 } +func (s *state) Fatal(msg string, args ...interface{}) { s.config.Fatal(msg, args...) } +func (s *state) Unimplemented(msg string, args ...interface{}) { s.config.Unimplemented(msg, args...) } + // startBlock sets the current block we're generating code in to b. func (s *state) startBlock(b *ssa.Block) { if s.curBlock != nil { - log.Fatalf("starting block %v when block %v has not ended", b, s.curBlock) + s.Fatal("starting block %v when block %v has not ended", b, s.curBlock) } s.curBlock = b s.vars = map[string]*ssa.Value{} @@ -230,7 +263,7 @@ func (s *state) stmt(n *Node) { return } if compiling_runtime != 0 { - log.Fatalf("%v escapes to heap, not allowed in runtime.", n) + Fatal("%v escapes to heap, not allowed in runtime.", n) } // TODO: the old pass hides the details of PHEAP @@ -260,6 +293,9 @@ func (s *state) stmt(n *Node) { // next we work on the label's target block s.startBlock(t) } + if n.Op == OGOTO && s.curBlock == nil { + s.Unimplemented("goto at start of function; see test/goto.go") + } case OAS, OASWB: s.assign(n.Op, n.Left, n.Right) @@ -317,6 +353,9 @@ func (s *state) stmt(n *Node) { // generate code to test condition // TODO(khr): Left == nil exception + if n.Left == nil { + s.Unimplemented("cond n.Left == nil: %v", n) + } s.startBlock(bCond) cond := s.expr(n.Left) b = s.endBlock() @@ -342,7 +381,7 @@ func (s *state) stmt(n *Node) { // TODO(khr): ??? anything to do here? Only for addrtaken variables? // Maybe just link it in the store chain? default: - log.Fatalf("unhandled stmt %s", opnames[n.Op]) + s.Unimplemented("unhandled stmt %s", opnames[n.Op]) } } @@ -370,7 +409,7 @@ func (s *state) expr(n *Node) *ssa.Value { case CTSTR: return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U) default: - log.Fatalf("unhandled OLITERAL %v", n.Val().Ctype()) + s.Unimplemented("unhandled OLITERAL %v", n.Val().Ctype()) return nil } case OCONVNOP: @@ -474,7 +513,7 @@ func (s *state) expr(n *Node) *ssa.Value { a := s.entryNewValue1I(ssa.OpOffPtr, Ptrto(fp.Type), fp.Width, s.sp) return s.newValue2(ssa.OpLoad, fp.Type, a, call) default: - log.Fatalf("unhandled expr %s", opnames[n.Op]) + s.Unimplemented("unhandled expr %s", opnames[n.Op]) return nil } } @@ -494,7 +533,7 @@ func (s *state) assign(op uint8, left *Node, right *Node) { case t.IsBoolean(): val = s.entryNewValue0A(ssa.OpConst, left.Type, false) // TODO: store bools as 0/1 in AuxInt? default: - log.Fatalf("zero for type %v not implemented", t) + s.Unimplemented("zero for type %v not implemented", t) } } else { val = s.expr(right) @@ -524,7 +563,7 @@ func (s *state) addr(n *Node) *ssa.Value { return s.expr(n.Name.Heapaddr) default: // TODO: address of locals - log.Fatalf("variable address of %v not implemented", n) + s.Unimplemented("variable address of %v not implemented", n) return nil } case OINDREG: @@ -547,7 +586,7 @@ func (s *state) addr(n *Node) *ssa.Value { return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i) } default: - log.Fatalf("addr: bad op %v", Oconv(int(n.Op), 0)) + s.Unimplemented("addr: bad op %v", Oconv(int(n.Op), 0)) return nil } } @@ -556,7 +595,7 @@ func (s *state) addr(n *Node) *ssa.Value { // n must be an ONAME. func canSSA(n *Node) bool { if n.Op != ONAME { - log.Fatalf("canSSA passed a non-ONAME %s %v", Oconv(int(n.Op), 0), n) + Fatal("canSSA passed a non-ONAME %s %v", Oconv(int(n.Op), 0), n) } if n.Addrtaken { return false @@ -610,7 +649,7 @@ func (s *state) boundsCheck(idx, len *ssa.Value) { // variable returns the value of a variable at the current location. func (s *state) variable(name string, t ssa.Type) *ssa.Value { if s.curBlock == nil { - log.Fatalf("nil curblock!") + s.Fatal("nil curblock!") } v := s.vars[name] if v == nil { @@ -662,6 +701,10 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name string) *ssa.Va for _, p := range b.Preds { vals = append(vals, s.lookupVarOutgoing(p, t, name)) } + if len(vals) == 0 { + s.Unimplemented("TODO: Handle fixedbugs/bug076.go") + return nil + } v0 := vals[0] for i := 1; i < len(vals); i++ { if vals[i] != v0 { @@ -822,11 +865,14 @@ func genValue(v *ssa.Value) { p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) case ssa.OpAMD64MULQconst: + v.Unimplemented("IMULQ doasm") + return // TODO: this isn't right. doasm fails on it. I don't think obj // has ever been taught to compile imul $c, r1, r2. p := Prog(x86.AIMULQ) p.From.Type = obj.TYPE_CONST p.From.Offset = v.AuxInt + p.From3 = new(obj.Addr) p.From3.Type = obj.TYPE_REG p.From3.Reg = regnum(v.Args[0]) p.To.Type = obj.TYPE_REG @@ -854,7 +900,7 @@ func genValue(v *ssa.Value) { r := regnum(v) if x != r { if r == x86.REG_CX { - log.Fatalf("can't implement %s, target and shift both in CX", v.LongString()) + v.Fatal("can't implement %s, target and shift both in CX", v.LongString()) } p := Prog(x86.AMOVQ) p.From.Type = obj.TYPE_REG @@ -1003,12 +1049,12 @@ func genValue(v *ssa.Value) { loc := f.RegAlloc[v.ID] for _, a := range v.Args { if f.RegAlloc[a.ID] != loc { // TODO: .Equal() instead? - log.Fatalf("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID]) + v.Fatal("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID]) } } case ssa.OpConst: if v.Block.Func.RegAlloc[v.ID] != nil { - log.Fatalf("const value %v shouldn't have a location", v) + v.Fatal("const value %v shouldn't have a location", v) } case ssa.OpArg: // memory arg needs no code @@ -1033,7 +1079,7 @@ func genValue(v *ssa.Value) { case ssa.OpFP, ssa.OpSP: // nothing to do default: - log.Fatalf("value %s not implemented", v.LongString()) + v.Unimplemented("value %s not implemented", v.LongString()) } } @@ -1141,7 +1187,7 @@ func genBlock(b, next *ssa.Block, branches []branch) []branch { } default: - log.Fatalf("branch %s not implemented", b.LongString()) + b.Unimplemented("branch %s not implemented", b.LongString()) } return branches } @@ -1183,10 +1229,40 @@ func localOffset(v *ssa.Value) int64 { } // ssaExport exports a bunch of compiler services for the ssa backend. -type ssaExport struct{} +type ssaExport struct { + log bool + unimplemented bool +} // StringSym returns a symbol (a *Sym wrapped in an interface) which // is a global string constant containing s. -func (serv ssaExport) StringSym(s string) interface{} { +func (*ssaExport) StringSym(s string) interface{} { return stringsym(s) } + +// Log logs a message from the compiler. +func (e *ssaExport) Log(msg string, args ...interface{}) { + // If e was marked as unimplemented, anything could happen. Ignore. + if e.log && !e.unimplemented { + fmt.Printf(msg, args...) + } +} + +// Fatal reports a compiler error and exits. +func (e *ssaExport) Fatal(msg string, args ...interface{}) { + // If e was marked as unimplemented, anything could happen. Ignore. + if !e.unimplemented { + Fatal(msg, args...) + } +} + +// Unimplemented reports that the function cannot be compiled. +// It will be removed once SSA work is complete. +func (e *ssaExport) Unimplemented(msg string, args ...interface{}) { + const alwaysLog = false // enable to calculate top unimplemented features + if !e.unimplemented && (e.log || alwaysLog) { + // first implementation failure, print explanation + fmt.Printf("SSA unimplemented: "+msg+"\n", args...) + } + e.unimplemented = true +} diff --git a/src/cmd/compile/internal/ssa/TODO b/src/cmd/compile/internal/ssa/TODO index e9b7553534..64b581fac0 100644 --- a/src/cmd/compile/internal/ssa/TODO +++ b/src/cmd/compile/internal/ssa/TODO @@ -42,7 +42,6 @@ Common-Subexpression Elimination - Can we move control values out of their basic block? Other - - Use gc.Fatal for errors. Add a callback to Frontend? - Write barriers - For testing, do something more sophisticated than checkOpcodeCounts. Michael Matloob suggests using a similar diff --git a/src/cmd/compile/internal/ssa/block.go b/src/cmd/compile/internal/ssa/block.go index db16fb4a53..e0d5c1a55e 100644 --- a/src/cmd/compile/internal/ssa/block.go +++ b/src/cmd/compile/internal/ssa/block.go @@ -69,3 +69,7 @@ func (b *Block) LongString() string { } return s } + +func (b *Block) Log(msg string, args ...interface{}) { b.Func.Log(msg, args...) } +func (b *Block) Fatal(msg string, args ...interface{}) { b.Func.Fatal(msg, args...) } +func (b *Block) Unimplemented(msg string, args ...interface{}) { b.Func.Unimplemented(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 667313ad9f..230d0ec111 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -4,8 +4,6 @@ package ssa -import "log" - // checkFunc checks invariants of f. func checkFunc(f *Func) { blockMark := make([]bool, f.NumBlocks()) @@ -13,17 +11,17 @@ func checkFunc(f *Func) { for _, b := range f.Blocks { if blockMark[b.ID] { - log.Panicf("block %s appears twice in %s!", b, f.Name) + f.Fatal("block %s appears twice in %s!", b, f.Name) } blockMark[b.ID] = true if b.Func != f { - log.Panicf("%s.Func=%s, want %s", b, b.Func.Name, f.Name) + f.Fatal("%s.Func=%s, want %s", b, b.Func.Name, f.Name) } for i, c := range b.Succs { for j, d := range b.Succs { if i != j && c == d { - log.Panicf("%s.Succs has duplicate block %s", b, c) + f.Fatal("%s.Succs has duplicate block %s", b, c) } } } @@ -46,64 +44,64 @@ func checkFunc(f *Func) { } } if !found { - log.Panicf("block %s is not a succ of its pred block %s", b, p) + f.Fatal("block %s is not a succ of its pred block %s", b, p) } } switch b.Kind { case BlockExit: if len(b.Succs) != 0 { - log.Panicf("exit block %s has successors", b) + f.Fatal("exit block %s has successors", b) } if b.Control == nil { - log.Panicf("exit block %s has no control value", b) + f.Fatal("exit block %s has no control value", b) } if !b.Control.Type.IsMemory() { - log.Panicf("exit block %s has non-memory control value %s", b, b.Control.LongString()) + f.Fatal("exit block %s has non-memory control value %s", b, b.Control.LongString()) } case BlockPlain: if len(b.Succs) != 1 { - log.Panicf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs)) + f.Fatal("plain block %s len(Succs)==%d, want 1", b, len(b.Succs)) } if b.Control != nil { - log.Panicf("plain block %s has non-nil control %s", b, b.Control.LongString()) + f.Fatal("plain block %s has non-nil control %s", b, b.Control.LongString()) } case BlockIf: if len(b.Succs) != 2 { - log.Panicf("if block %s len(Succs)==%d, want 2", b, len(b.Succs)) + f.Fatal("if block %s len(Succs)==%d, want 2", b, len(b.Succs)) } if b.Control == nil { - log.Panicf("if block %s has no control value", b) + f.Fatal("if block %s has no control value", b) } if !b.Control.Type.IsBoolean() { - log.Panicf("if block %s has non-bool control value %s", b, b.Control.LongString()) + f.Fatal("if block %s has non-bool control value %s", b, b.Control.LongString()) } case BlockCall: if len(b.Succs) != 2 { - log.Panicf("call block %s len(Succs)==%d, want 2", b, len(b.Succs)) + f.Fatal("call block %s len(Succs)==%d, want 2", b, len(b.Succs)) } if b.Control == nil { - log.Panicf("call block %s has no control value", b) + f.Fatal("call block %s has no control value", b) } if !b.Control.Type.IsMemory() { - log.Panicf("call block %s has non-memory control value %s", b, b.Control.LongString()) + f.Fatal("call block %s has non-memory control value %s", b, b.Control.LongString()) } if b.Succs[1].Kind != BlockExit { - log.Panicf("exception edge from call block %s does not go to exit but %s", b, b.Succs[1]) + f.Fatal("exception edge from call block %s does not go to exit but %s", b, b.Succs[1]) } } for _, v := range b.Values { if valueMark[v.ID] { - log.Panicf("value %s appears twice!", v.LongString()) + f.Fatal("value %s appears twice!", v.LongString()) } valueMark[v.ID] = true if v.Block != b { - log.Panicf("%s.block != %s", v, b) + f.Fatal("%s.block != %s", v, b) } if v.Op == OpPhi && len(v.Args) != len(b.Preds) { - log.Panicf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b) + f.Fatal("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b) } // TODO: check for cycles in values @@ -113,12 +111,12 @@ func checkFunc(f *Func) { for _, id := range f.bid.free { if blockMark[id] { - log.Panicf("used block b%d in free list", id) + f.Fatal("used block b%d in free list", id) } } for _, id := range f.vid.free { if valueMark[id] { - log.Panicf("used value v%d in free list", id) + f.Fatal("used value v%d in free list", id) } } } diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index 02c9b5a4a9..896be01b68 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -4,10 +4,7 @@ package ssa -import ( - "fmt" - "log" -) +import "log" // Compile is the main entry point for this package. // Compile modifies f so that on return: @@ -18,13 +15,13 @@ import ( func Compile(f *Func) { // TODO: debugging - set flags to control verbosity of compiler, // which phases to dump IR before/after, etc. - fmt.Printf("compiling %s\n", f.Name) + f.Log("compiling %s\n", f.Name) // hook to print function & phase if panic happens phaseName := "init" defer func() { if phaseName != "" { - fmt.Printf("panic during %s while compiling %s\n", phaseName, f.Name) + f.Fatal("panic during %s while compiling %s\n", phaseName, f.Name) } }() @@ -33,9 +30,9 @@ func Compile(f *Func) { checkFunc(f) for _, p := range passes { phaseName = p.name - fmt.Printf(" pass %s begin\n", p.name) + f.Log(" pass %s begin\n", p.name) p.fn(f) - fmt.Printf(" pass %s end\n", p.name) + f.Log(" pass %s end\n", p.name) printFunc(f) checkFunc(f) } diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index db2d80a7c4..60c1a5a50b 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -4,8 +4,6 @@ package ssa -import "log" - type Config struct { arch string // "amd64", etc. ptrSize int64 // 4 or 8 @@ -22,6 +20,16 @@ type Frontend interface { // Strings are laid out in read-only memory with one word of pointer, // one word of length, then the contents of the string. StringSym(string) interface{} // returns *gc.Sym + + // Log logs a message from the compiler. + Log(string, ...interface{}) + + // Fatal reports a compiler error and exits. + Fatal(string, ...interface{}) + + // Unimplemented reports that the function cannot be compiled. + // It will be removed once SSA work is complete. + Unimplemented(msg string, args ...interface{}) } // NewConfig returns a new configuration object for the given architecture. @@ -37,7 +45,7 @@ func NewConfig(arch string, fe Frontend) *Config { c.lowerBlock = rewriteBlockAMD64 c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support default: - log.Fatalf("arch %s not implemented", arch) + fe.Unimplemented("arch %s not implemented", arch) } // cache the intptr type in the config @@ -55,5 +63,9 @@ func (c *Config) NewFunc() *Func { return &Func{Config: c} } +func (c *Config) Log(msg string, args ...interface{}) { c.fe.Log(msg, args...) } +func (c *Config) Fatal(msg string, args ...interface{}) { c.fe.Fatal(msg, args...) } +func (c *Config) Unimplemented(msg string, args ...interface{}) { c.fe.Unimplemented(msg, args...) } + // TODO(khr): do we really need a separate Config, or can we just // store all its fields inside a Func? diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 1a5589cd0a..f4884520de 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -4,8 +4,6 @@ package ssa -import "log" - // deadcode removes dead code from f. func deadcode(f *Func) { @@ -82,7 +80,7 @@ func deadcode(f *Func) { i++ } else { if len(b.Values) > 0 { - log.Panicf("live values in unreachable block %v: %v", b, b.Values) + b.Fatal("live values in unreachable block %v: %v", b, b.Values) } f.bid.put(b.ID) } @@ -105,7 +103,7 @@ func removePredecessor(b, c *Block) { if n == 0 { // c is now dead - don't bother working on it if c.Preds[0] != b { - log.Panicf("%s.Preds[0]==%s, want %s", c, c.Preds[0], b) + b.Fatal("%s.Preds[0]==%s, want %s", c, c.Preds[0], b) } return } diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index edd38e1254..ff9e6800da 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -7,7 +7,7 @@ package ssa import "testing" func TestDeadLoop(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -37,7 +37,7 @@ func TestDeadLoop(t *testing.T) { } func TestDeadValue(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -60,7 +60,7 @@ func TestDeadValue(t *testing.T) { } func TestNeverTaken(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", Valu("cond", OpConst, TypeBool, 0, false), diff --git a/src/cmd/compile/internal/ssa/deadstore.go b/src/cmd/compile/internal/ssa/deadstore.go index b02b35460a..e4d73e7226 100644 --- a/src/cmd/compile/internal/ssa/deadstore.go +++ b/src/cmd/compile/internal/ssa/deadstore.go @@ -4,8 +4,6 @@ package ssa -import "log" - // dse does dead-store elimination on the Function. // Dead stores are those which are unconditionally followed by // another store to the same location, with no intervening load. @@ -58,12 +56,12 @@ func dse(f *Func) { continue } if last != nil { - log.Fatalf("two final stores - simultaneous live stores", last, v) + b.Fatal("two final stores - simultaneous live stores", last, v) } last = v } if last == nil { - log.Fatalf("no last store found - cycle?") + b.Fatal("no last store found - cycle?") } // Walk backwards looking for dead stores. Keep track of shadowed addresses. diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go index 5143afb6cb..48ea066aa3 100644 --- a/src/cmd/compile/internal/ssa/deadstore_test.go +++ b/src/cmd/compile/internal/ssa/deadstore_test.go @@ -9,7 +9,7 @@ import ( ) func TestDeadStore(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", @@ -35,7 +35,7 @@ func TestDeadStore(t *testing.T) { } func TestDeadStorePhi(t *testing.T) { // make sure we don't get into an infinite loop with phi values. - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", @@ -60,7 +60,7 @@ func TestDeadStoreTypes(t *testing.T) { // stronger restriction, that one store can't shadow another unless the // types of the address fields are identical (where identicalness is // decided by the CSE pass). - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) t1 := &TypeImpl{Size_: 8, Ptr: true, Name: "t1"} t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"} fun := Fun(c, "entry", diff --git a/src/cmd/compile/internal/ssa/dom.go b/src/cmd/compile/internal/ssa/dom.go index aaf3ab3da1..fac2798a60 100644 --- a/src/cmd/compile/internal/ssa/dom.go +++ b/src/cmd/compile/internal/ssa/dom.go @@ -7,8 +7,6 @@ package ssa // This file contains code to compute the dominator tree // of a control-flow graph. -import "log" - // postorder computes a postorder traversal ordering for the // basic blocks in f. Unreachable blocks will not appear. func postorder(f *Func) []*Block { @@ -47,7 +45,7 @@ func postorder(f *Func) []*Block { } } default: - log.Fatalf("bad stack state %v %d", b, mark[b.ID]) + b.Fatal("bad stack state %v %d", b, mark[b.ID]) } } return order @@ -73,7 +71,7 @@ func dominators(f *Func) []*Block { // Make the entry block a self-loop idom[f.Entry.ID] = f.Entry if postnum[f.Entry.ID] != len(post)-1 { - log.Fatalf("entry block %v not last in postorder", f.Entry) + f.Fatal("entry block %v not last in postorder", f.Entry) } // Compute relaxation of idom entries diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index 103945a73e..6b006e9238 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -4,13 +4,21 @@ package ssa +import "testing" + var CheckFunc = checkFunc var PrintFunc = printFunc var Opt = opt var Deadcode = deadcode -type DummyFrontend struct{} +type DummyFrontend struct { + t *testing.T +} -func (d DummyFrontend) StringSym(s string) interface{} { +func (DummyFrontend) StringSym(s string) interface{} { return nil } + +func (d DummyFrontend) Log(msg string, args ...interface{}) { d.t.Logf(msg, args...) } +func (d DummyFrontend) Fatal(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } +func (d DummyFrontend) Unimplemented(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index d73e0ea9e0..56bee1aa3f 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -4,8 +4,6 @@ package ssa -import "log" - // A Func represents a Go func declaration (or function literal) and // its body. This package compiles each Func independently. type Func struct { @@ -79,7 +77,7 @@ func (b *Block) NewValue0A(line int32, op Op, t Type, aux interface{}) *Value { // Disallow int64 aux values. They should be in the auxint field instead. // Maybe we want to allow this at some point, but for now we disallow it // to prevent errors like using NewValue1A instead of NewValue1I. - log.Fatalf("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) + b.Fatal("aux field has int64 type op=%s type=%s aux=%v", op, t, aux) } v := &Value{ ID: b.Func.vid.get(), @@ -209,3 +207,7 @@ func (f *Func) ConstInt(line int32, t Type, c int64) *Value { // TODO: cache? return f.Entry.NewValue0I(line, OpConst, t, c) } + +func (f *Func) Log(msg string, args ...interface{}) { f.Config.Log(msg, args...) } +func (f *Func) Fatal(msg string, args ...interface{}) { f.Config.Fatal(msg, args...) } +func (f *Func) Unimplemented(msg string, args ...interface{}) { f.Config.Unimplemented(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index 7cfc7324ac..b52d470e24 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -37,7 +37,7 @@ package ssa // the parser can be used instead of Fun. import ( - "log" + "fmt" "reflect" "testing" ) @@ -161,7 +161,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun { if c.control != "" { cval, ok := values[c.control] if !ok { - log.Panicf("control value for block %s missing", bloc.name) + f.Fatal("control value for block %s missing", bloc.name) } b.Control = cval } @@ -171,7 +171,7 @@ func Fun(c *Config, entry string, blocs ...bloc) fun { for _, arg := range valu.args { a, ok := values[arg] if !ok { - log.Panicf("arg %s missing for value %s in block %s", + b.Fatal("arg %s missing for value %s in block %s", arg, valu.name, bloc.name) } v.AddArg(a) @@ -197,7 +197,7 @@ func Bloc(name string, entries ...interface{}) bloc { case ctrl: // there should be exactly one Ctrl entry. if seenCtrl { - log.Panicf("already seen control for block %s", name) + panic(fmt.Sprintf("already seen control for block %s", name)) } b.control = v seenCtrl = true @@ -206,7 +206,7 @@ func Bloc(name string, entries ...interface{}) bloc { } } if !seenCtrl { - log.Panicf("block %s doesn't have control", b.name) + panic(fmt.Sprintf("block %s doesn't have control", b.name)) } return b } @@ -262,7 +262,7 @@ func addEdge(b, c *Block) { } func TestArgs(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", Valu("a", OpConst, TypeInt64, 14, nil), @@ -282,7 +282,7 @@ func TestArgs(t *testing.T) { } func TestEquiv(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) equivalentCases := []struct{ f, g fun }{ // simple case { diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index e0bba1706f..9d08a35f1f 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -32,7 +32,7 @@ // indexing operations // Note: bounds check has already been done -(ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex ptr idx) mem) +(ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex ptr idx) mem) (PtrIndex ptr idx) -> (Add ptr (Mul idx (Const [t.Elem().Size()]))) // big-object moves diff --git a/src/cmd/compile/internal/ssa/layout.go b/src/cmd/compile/internal/ssa/layout.go index 7123397c4c..0a271b39ad 100644 --- a/src/cmd/compile/internal/ssa/layout.go +++ b/src/cmd/compile/internal/ssa/layout.go @@ -4,8 +4,6 @@ package ssa -import "log" - // layout orders basic blocks in f with the goal of minimizing control flow instructions. // After this phase returns, the order of f.Blocks matters and is the order // in which those blocks will appear in the assembly output. @@ -82,7 +80,7 @@ blockloop: continue blockloop } } - log.Panicf("no block available for layout") + b.Fatal("no block available for layout") } f.Blocks = order } diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index 2ca1db784e..768ac124be 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -4,8 +4,6 @@ package ssa -import "log" - // convert to machine-dependent ops func lower(f *Func) { // repeat rewrites until we find no more rewrites @@ -15,7 +13,7 @@ func lower(f *Func) { for _, b := range f.Blocks { for _, v := range b.Values { 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()) + f.Unimplemented("%s not lowered", v.LongString()) } } } diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go index b9a958c18e..c1b97d2b8f 100644 --- a/src/cmd/compile/internal/ssa/print.go +++ b/src/cmd/compile/internal/ssa/print.go @@ -8,11 +8,10 @@ import ( "bytes" "fmt" "io" - "os" ) func printFunc(f *Func) { - fprintFunc(os.Stdout, f) + f.Log("%s", f.String()) } func (f *Func) String() string { diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 6f7d619247..d1489b20f2 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -4,11 +4,7 @@ package ssa -import ( - "fmt" - "log" - "sort" -) +import "sort" func setloc(home []Location, v *Value, loc Location) []Location { for v.ID >= ID(len(home)) { @@ -353,7 +349,7 @@ func regalloc(f *Func) { if b.Kind == BlockCall { call = b.Control if call != b.Values[len(b.Values)-1] { - log.Fatalf("call not at end of block %b %v", b, call) + b.Fatal("call not at end of block %b %v", b, call) } b.Values = b.Values[:len(b.Values)-1] // TODO: do this for all control types? @@ -423,7 +419,7 @@ func live(f *Func) [][]ID { t := newSparseSet(f.NumValues()) for { for _, b := range f.Blocks { - fmt.Printf("live %s %v\n", b, live[b.ID]) + f.Log("live %s %v\n", b, live[b.ID]) } changed := false diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 77aa2b07b4..2bfd3813ed 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -4,7 +4,7 @@ package ssa -import "log" +import "fmt" func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) { // repeat rewrites until we find no more rewrites @@ -12,11 +12,10 @@ func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) var curv *Value defer func() { if curb != nil { - log.Printf("panic during rewrite of block %s\n", curb.LongString()) + curb.Fatal("panic during rewrite of block %s\n", curb.LongString()) } if curv != nil { - log.Printf("panic during rewrite of value %s\n", curv.LongString()) - panic("rewrite failed") + curv.Fatal("panic during rewrite of value %s\n", curv.LongString()) // TODO(khr): print source location also } }() @@ -90,12 +89,12 @@ func typeSize(t Type) int64 { return t.Size() } -// addOff adds two int64 offsets. Fails if wraparound happens. +// addOff adds two int64 offsets. Fails if wraparound happens. func addOff(x, y int64) int64 { z := x + y // x and y have same sign and z has a different sign => overflow if x^y >= 0 && x^z < 0 { - log.Panicf("offset overflow %d %d\n", x, y) + panic(fmt.Sprintf("offset overflow %d %d", x, y)) } return z } diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 0ecc436343..ac4f009881 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -34,10 +34,10 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpArrayIndex: // match: (ArrayIndex (Load ptr mem) idx) // cond: - // result: (Load (PtrIndex ptr idx) mem) + // result: (Load (PtrIndex ptr idx) mem) { if v.Args[0].Op != OpLoad { - goto end3809f4c52270a76313e4ea26e6f0b753 + goto end4894dd7b58383fee5f8a92be08437c33 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] @@ -47,15 +47,15 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v.Aux = nil v.resetArgs() v0 := v.Block.NewValue0(v.Line, OpPtrIndex, TypeInvalid) - v0.Type = ptr.Type.Elem().Elem().PtrTo() + v0.Type = v.Type.PtrTo() v0.AddArg(ptr) v0.AddArg(idx) v.AddArg(v0) v.AddArg(mem) return true } - goto end3809f4c52270a76313e4ea26e6f0b753 - end3809f4c52270a76313e4ea26e6f0b753: + goto end4894dd7b58383fee5f8a92be08437c33 + end4894dd7b58383fee5f8a92be08437c33: ; case OpConst: // match: (Const {s}) diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go index a7c33d9d59..a9432579f7 100644 --- a/src/cmd/compile/internal/ssa/schedule_test.go +++ b/src/cmd/compile/internal/ssa/schedule_test.go @@ -7,7 +7,7 @@ package ssa import "testing" func TestSchedule(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) cases := []fun{ Fun(c, "entry", Bloc("entry", diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index b4b4f47ff0..52ddbbe42d 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -9,7 +9,7 @@ import ( ) func TestShiftConstAMD64(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{}) + c := NewConfig("amd64", DummyFrontend{t}) fun := makeConstShiftFunc(c, 18, OpLsh, TypeUInt64) checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0}) fun = makeConstShiftFunc(c, 66, OpLsh, TypeUInt64) diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 5db7316dca..452d0c75a1 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -4,8 +4,6 @@ package ssa -import "log" - // stackalloc allocates storage in the stack frame for // all Values that did not get a register. func stackalloc(f *Func) { @@ -79,7 +77,7 @@ func stackalloc(f *Func) { for _, v := range b.Values { if v.Op == OpFP { if fp != nil { - log.Panicf("multiple FP ops: %s %s", fp, v) + b.Fatal("multiple FP ops: %s %s", fp, v) } fp = v } @@ -99,12 +97,12 @@ func stackalloc(f *Func) { case OpAMD64LEAQ, OpAMD64MOVQload, OpAMD64MOVQstore, OpAMD64MOVLload, OpAMD64MOVLstore, OpAMD64MOVWload, OpAMD64MOVWstore, OpAMD64MOVBload, OpAMD64MOVBstore, 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) + f.Fatal("can't do FP->SP adjust on index slot of load %s", v.Op) } // eg: (MOVQload [c] (FP) mem) -> (MOVQload [c+n] (SP) mem) v.AuxInt = addOff(v.AuxInt, n) default: - log.Panicf("can't do FP->SP adjust on %s", v.Op) + f.Unimplemented("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 3ed1f3c2b9..bfba8dc369 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -106,3 +106,7 @@ func (v *Value) resetArgs() { v.argstorage[1] = nil v.Args = v.argstorage[:0] } + +func (v *Value) Log(msg string, args ...interface{}) { v.Block.Log(msg, args...) } +func (v *Value) Fatal(msg string, args ...interface{}) { v.Block.Fatal(msg, args...) } +func (v *Value) Unimplemented(msg string, args ...interface{}) { v.Block.Unimplemented(msg, args...) } -- cgit v1.3 From 9b048527db4122732795211291a02357d995c898 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 9 Jul 2015 21:24:12 -0600 Subject: [dev.ssa] cmd/compile/ssa: handle nested dead blocks removePredecessor can change which blocks are live. However, it cannot remove dead blocks from the function's slice of blocks because removePredecessor may have been called from within a function doing a walk of the blocks. CL 11879 did not handle this correctly and broke the build. To fix this, mark the block as dead but leave its actual removal for a deadcode pass. Blocks that are dead must have no successors, predecessors, values, or control values, so they will generally be ignored by other passes. To be safe, we add a deadcode pass after the opt pass, which is the only other pass that calls removePredecessor. Two alternatives that I considered and discarded: (1) Make all call sites aware of the fact that removePrecessor might make arbitrary changes to the list of blocks. This will needlessly complicate callers. (2) Handle the things that can go wrong in practice when we encounter a dead-but-not-removed block. CL 11930 takes this approach (and the tests are stolen from that CL). However, this is just patching over the problem. Change-Id: Icf0687b0a8148ce5e96b2988b668804411b05bd8 Reviewed-on: https://go-review.googlesource.com/12004 Reviewed-by: Todd Neal Reviewed-by: Michael Matloob --- src/cmd/compile/internal/ssa/check.go | 13 +++++++++ src/cmd/compile/internal/ssa/compile.go | 1 + src/cmd/compile/internal/ssa/deadcode.go | 8 ++++-- src/cmd/compile/internal/ssa/deadcode_test.go | 39 ++++++++++++++++++++++++++ src/cmd/compile/internal/ssa/gen/genericOps.go | 1 + src/cmd/compile/internal/ssa/opGen.go | 2 ++ src/cmd/compile/internal/ssa/rewrite.go | 3 ++ 7 files changed, 64 insertions(+), 3 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index a27e1bc653..4fe59e08d1 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -59,6 +59,19 @@ func checkFunc(f *Func) { if !b.Control.Type.IsMemory() { f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString()) } + case BlockDead: + if len(b.Succs) != 0 { + f.Fatalf("dead block %s has successors", b) + } + if len(b.Preds) != 0 { + f.Fatalf("dead block %s has predecessors", b) + } + if len(b.Values) != 0 { + f.Fatalf("dead block %s has values", b) + } + if b.Control != nil { + f.Fatalf("dead block %s has a control value", b) + } case BlockPlain: if len(b.Succs) != 1 { f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs)) diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index b02c10a745..4a6c2a9404 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -51,6 +51,7 @@ var passes = [...]pass{ {"phielim", phielim}, {"copyelim", copyelim}, {"opt", opt}, + {"opt deadcode", deadcode}, // remove any blocks orphaned during opt {"generic cse", cse}, {"nilcheckelim", nilcheckelim}, {"generic deadcode", deadcode}, diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index a5d0fe0f34..2be7b8ebaf 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -96,7 +96,7 @@ func deadcode(f *Func) { // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? } -// There was an edge b->c. It has been removed from b's successors. +// There was an edge b->c. c has been removed from b's successors. // Fix up c to handle that fact. func (f *Func) removePredecessor(b, c *Block) { work := [][2]*Block{{b, c}} @@ -105,8 +105,6 @@ func (f *Func) removePredecessor(b, c *Block) { b, c := work[0][0], work[0][1] work = work[1:] - n := len(c.Preds) - 1 - // find index of b in c's predecessor list var i int for j, p := range c.Preds { @@ -116,6 +114,7 @@ func (f *Func) removePredecessor(b, c *Block) { } } + n := len(c.Preds) - 1 c.Preds[i] = c.Preds[n] c.Preds[n] = nil // aid GC c.Preds = c.Preds[:n] @@ -143,6 +142,9 @@ func (f *Func) removePredecessor(b, c *Block) { for _, succ := range c.Succs { work = append(work, [2]*Block{c, succ}) } + c.Succs = nil + c.Kind = BlockDead + c.Control = nil } } } diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index ff9e6800da..c63b8e4106 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -93,3 +93,42 @@ func TestNeverTaken(t *testing.T) { } } + +func TestNestedDeadBlocks(t *testing.T) { + c := NewConfig("amd64", DummyFrontend{t}) + fun := Fun(c, "entry", + Bloc("entry", + Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("cond", OpConst, TypeBool, 0, false), + If("cond", "b2", "b4")), + Bloc("b2", + If("cond", "b3", "b4")), + Bloc("b3", + If("cond", "b3", "b4")), + Bloc("b4", + If("cond", "b3", "exit")), + Bloc("exit", + Exit("mem"))) + + CheckFunc(fun.f) + Opt(fun.f) + CheckFunc(fun.f) + Deadcode(fun.f) + CheckFunc(fun.f) + if fun.blocks["entry"].Kind != BlockPlain { + t.Errorf("if(false) not simplified") + } + for _, b := range fun.f.Blocks { + if b == fun.blocks["b2"] { + t.Errorf("b2 block still present") + } + if b == fun.blocks["b3"] { + t.Errorf("b3 block still present") + } + for _, v := range b.Values { + if v == fun.values["cond"] { + t.Errorf("constant condition still present") + } + } + } +} diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index a6e6c93fc5..c410cc4f02 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -105,6 +105,7 @@ var genericOps = []opData{ var genericBlocks = []blockData{ {name: "Exit"}, // no successors. There should only be 1 of these. + {name: "Dead"}, // no successors; determined to be dead but not yet removed {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 diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index a6fb0b06e2..3769cfeb86 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -19,6 +19,7 @@ const ( BlockAMD64UGE BlockExit + BlockDead BlockPlain BlockIf BlockCall @@ -39,6 +40,7 @@ var blockString = [...]string{ BlockAMD64UGE: "UGE", BlockExit: "Exit", + BlockDead: "Dead", BlockPlain: "Plain", BlockIf: "If", BlockCall: "Call", diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index b2c45969e4..306fe1274e 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -23,6 +23,9 @@ func applyRewrite(f *Func, rb func(*Block) bool, rv func(*Value, *Config) bool) for { change := false for _, b := range f.Blocks { + if b.Kind == BlockDead { + continue + } if b.Control != nil && b.Control.Op == OpCopy { for b.Control.Op == OpCopy { b.Control = b.Control.Args[0] -- cgit v1.3 From 9cb332efd445a7e0672b96f9bc703c93f02879a5 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Tue, 28 Jul 2015 14:19:20 -0700 Subject: [dev.ssa] cmd/compile/internal/ssa: Split OpConst into an OpConst8, OpConst16, ... Convert the polymorphic OpConst into monomorphic variants. Change-Id: I90bb8894fbac04ca5e5484ea260c131ef8b506fb Reviewed-on: https://go-review.googlesource.com/12798 Reviewed-by: Josh Bleecher Snyder --- src/cmd/compile/internal/gc/ssa.go | 124 +++++++++++--- src/cmd/compile/internal/ssa/deadcode_test.go | 8 +- src/cmd/compile/internal/ssa/deadstore_test.go | 6 +- src/cmd/compile/internal/ssa/dom_test.go | 28 +-- src/cmd/compile/internal/ssa/func.go | 20 ++- src/cmd/compile/internal/ssa/func_test.go | 46 ++--- src/cmd/compile/internal/ssa/gen/AMD64.rules | 30 ++-- src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 16 +- src/cmd/compile/internal/ssa/gen/generic.rules | 30 ++-- src/cmd/compile/internal/ssa/gen/genericOps.go | 10 +- src/cmd/compile/internal/ssa/gen/rulegen.go | 3 + src/cmd/compile/internal/ssa/opGen.go | 70 +++++++- src/cmd/compile/internal/ssa/rewriteAMD64.go | 226 ++++++++++++++++--------- src/cmd/compile/internal/ssa/rewritegeneric.go | 218 ++++++++++++------------ src/cmd/compile/internal/ssa/schedule_test.go | 4 +- src/cmd/compile/internal/ssa/shift_test.go | 2 +- 16 files changed, 537 insertions(+), 304 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 6866f4942e..e26412cf46 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -347,9 +347,33 @@ func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ss return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1) } -// constInt adds a new const int value to the entry block. +// constInt* routines add a new const int value to the entry block. +func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value { + return s.f.ConstInt8(s.peekLine(), t, c) +} +func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value { + return s.f.ConstInt16(s.peekLine(), t, c) +} +func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value { + return s.f.ConstInt32(s.peekLine(), t, c) +} +func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value { + return s.f.ConstInt64(s.peekLine(), t, c) +} +func (s *state) constIntPtr(t ssa.Type, c int64) *ssa.Value { + if s.config.PtrSize == 4 && int64(int32(c)) != c { + s.Fatalf("pointer constant too big %d", c) + } + return s.f.ConstIntPtr(s.peekLine(), t, c) +} func (s *state) constInt(t ssa.Type, c int64) *ssa.Value { - return s.f.ConstInt(s.peekLine(), t, c) + if s.config.IntSize == 8 { + return s.constInt64(t, c) + } + if int64(int32(c)) != c { + s.Fatalf("integer constant too big %d", c) + } + return s.constInt32(t, int32(c)) } // ssaStmtList converts the statement n to SSA and adds it to s. @@ -584,7 +608,7 @@ func (s *state) stmt(n *Node) { if n.Left != nil { cond = s.expr(n.Left) } else { - cond = s.entryNewValue0A(ssa.OpConst, Types[TBOOL], true) + cond = s.entryNewValue0A(ssa.OpConstBool, Types[TBOOL], true) } b = s.endBlock() b.Kind = ssa.BlockIf @@ -862,11 +886,26 @@ func (s *state) expr(n *Node) *ssa.Value { case OLITERAL: switch n.Val().Ctype() { case CTINT: - return s.constInt(n.Type, Mpgetfix(n.Val().U.(*Mpint))) - case CTSTR, CTBOOL: - return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U) + i := Mpgetfix(n.Val().U.(*Mpint)) + switch n.Type.Size() { + case 1: + return s.constInt8(n.Type, int8(i)) + case 2: + return s.constInt16(n.Type, int16(i)) + case 4: + return s.constInt32(n.Type, int32(i)) + case 8: + return s.constInt64(n.Type, i) + default: + s.Fatalf("bad integer size %d", n.Type.Size()) + return nil + } + case CTSTR: + return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U) + case CTBOOL: + return s.entryNewValue0A(ssa.OpConstBool, n.Type, n.Val().U) case CTNIL: - return s.entryNewValue0(ssa.OpConst, n.Type) + return s.entryNewValue0(ssa.OpConstNil, n.Type) default: s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype()) return nil @@ -1020,7 +1059,7 @@ func (s *state) expr(n *Node) *ssa.Value { case ODOTPTR: p := s.expr(n.Left) s.nilCheck(p) - p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset)) + p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(s.config.Uintptr, n.Xoffset)) return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) case OINDEX: @@ -1031,10 +1070,10 @@ func (s *state) expr(n *Node) *ssa.Value { var elemtype *Type var len *ssa.Value if n.Left.Type.IsString() { - len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, a) + len = s.newValue1(ssa.OpStringLen, s.config.Int, a) elemtype = Types[TUINT8] } else { - len = s.constInt(s.config.Uintptr, n.Left.Type.Bound) + len = s.constInt(s.config.Int, n.Left.Type.Bound) elemtype = n.Left.Type.Type } s.boundsCheck(i, len) @@ -1149,12 +1188,25 @@ func (s *state) assign(op uint8, left *Node, right *Node) { // zeroVal returns the zero value for type t. func (s *state) zeroVal(t *Type) *ssa.Value { switch { + case t.IsInteger(): + switch t.Size() { + case 1: + return s.constInt8(t, 0) + case 2: + return s.constInt16(t, 0) + case 4: + return s.constInt32(t, 0) + case 8: + return s.constInt64(t, 0) + default: + s.Fatalf("bad sized integer type %s", t) + } case t.IsString(): - return s.entryNewValue0A(ssa.OpConst, t, "") - case t.IsInteger() || t.IsPtr(): - return s.entryNewValue0(ssa.OpConst, t) + return s.entryNewValue0A(ssa.OpConstString, t, "") + case t.IsPtr(): + return s.entryNewValue0(ssa.OpConstNil, t) case t.IsBoolean(): - return s.entryNewValue0A(ssa.OpConst, t, false) // TODO: store bools as 0/1 in AuxInt? + return s.entryNewValue0A(ssa.OpConstBool, t, false) // TODO: store bools as 0/1 in AuxInt? } s.Unimplementedf("zero for type %v not implemented", t) return nil @@ -1212,7 +1264,7 @@ func (s *state) addr(n *Node) *ssa.Value { a := s.addr(n.Left) i := s.expr(n.Right) i = s.extendIndex(i) - len := s.constInt(s.config.Uintptr, n.Left.Type.Bound) + len := s.constInt(s.config.Int, n.Left.Type.Bound) s.boundsCheck(i, len) return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i) } @@ -1222,11 +1274,11 @@ func (s *state) addr(n *Node) *ssa.Value { return p case ODOT: p := s.addr(n.Left) - return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset)) + return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(s.config.Uintptr, n.Xoffset)) case ODOTPTR: p := s.expr(n.Left) s.nilCheck(p) - return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset)) + return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(s.config.Uintptr, n.Xoffset)) default: s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0)) return nil @@ -1570,7 +1622,7 @@ func genValue(v *ssa.Value) { x := regnum(v.Args[0]) y := regnum(v.Args[1]) if x != r && y != r { - p := Prog(x86.AMOVQ) + p := Prog(regMoveAMD64(v.Type.Size())) p.From.Type = obj.TYPE_REG p.From.Reg = x p.To.Type = obj.TYPE_REG @@ -1731,11 +1783,22 @@ func genValue(v *ssa.Value) { p.From.Reg = regnum(v.Args[0]) p.To.Type = obj.TYPE_CONST p.To.Offset = v.AuxInt - case ssa.OpAMD64MOVQconst: + case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst: x := regnum(v) - p := Prog(x86.AMOVQ) + p := Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST - p.From.Offset = v.AuxInt + var i int64 + switch v.Op { + case ssa.OpAMD64MOVBconst: + i = int64(int8(v.AuxInt)) + case ssa.OpAMD64MOVWconst: + i = int64(int16(v.AuxInt)) + case ssa.OpAMD64MOVLconst: + i = int64(int32(v.AuxInt)) + case ssa.OpAMD64MOVQconst: + i = v.AuxInt + } + p.From.Offset = i p.To.Type = obj.TYPE_REG p.To.Reg = x case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload: @@ -1836,7 +1899,7 @@ func genValue(v *ssa.Value) { v.Fatalf("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID]) } } - case ssa.OpConst: + case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64, ssa.OpConstString, ssa.OpConstNil, ssa.OpConstBool: if v.Block.Func.RegAlloc[v.ID] != nil { v.Fatalf("const value %v shouldn't have a location", v) } @@ -2079,6 +2142,23 @@ var ssaRegToReg = [...]int16{ // TODO: arch-dependent } +// regMoveAMD64 returns the register->register move opcode for the given width. +// TODO: generalize for all architectures? +func regMoveAMD64(width int64) int { + switch width { + case 1: + return x86.AMOVB + case 2: + return x86.AMOVW + case 4: + return x86.AMOVL + case 8: + return x86.AMOVQ + default: + panic("bad register width") + } +} + // regnum returns the register (in cmd/internal/obj numbering) to // which v has been allocated. Panics if v is not assigned to a // register. diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index c63b8e4106..9ec8959571 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -17,7 +17,7 @@ func TestDeadLoop(t *testing.T) { // dead loop Bloc("deadblock", // dead value in dead block - Valu("deadval", OpConst, TypeBool, 0, true), + Valu("deadval", OpConstBool, TypeBool, 0, true), If("deadval", "deadblock", "exit"))) CheckFunc(fun.f) @@ -41,7 +41,7 @@ func TestDeadValue(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("deadval", OpConst, TypeInt64, 37, nil), + Valu("deadval", OpConst64, TypeInt64, 37, nil), Goto("exit")), Bloc("exit", Exit("mem"))) @@ -63,7 +63,7 @@ func TestNeverTaken(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", - Valu("cond", OpConst, TypeBool, 0, false), + Valu("cond", OpConstBool, TypeBool, 0, false), Valu("mem", OpArg, TypeMem, 0, ".mem"), If("cond", "then", "else")), Bloc("then", @@ -99,7 +99,7 @@ func TestNestedDeadBlocks(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("cond", OpConst, TypeBool, 0, false), + Valu("cond", OpConstBool, TypeBool, 0, false), If("cond", "b2", "b4")), Bloc("b2", If("cond", "b3", "b4")), diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go index 3b29e1c430..5b318eb2d2 100644 --- a/src/cmd/compile/internal/ssa/deadstore_test.go +++ b/src/cmd/compile/internal/ssa/deadstore_test.go @@ -15,7 +15,7 @@ func TestDeadStore(t *testing.T) { Bloc("entry", Valu("start", OpArg, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), - Valu("v", OpConst, TypeBool, 0, true), + Valu("v", OpConstBool, TypeBool, 0, true), Valu("addr1", OpAddr, ptrType, 0, nil, "sb"), Valu("addr2", OpAddr, ptrType, 0, nil, "sb"), Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"), @@ -42,7 +42,7 @@ func TestDeadStorePhi(t *testing.T) { Bloc("entry", Valu("start", OpArg, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), - Valu("v", OpConst, TypeBool, 0, true), + Valu("v", OpConstBool, TypeBool, 0, true), Valu("addr", OpAddr, ptrType, 0, nil, "sb"), Goto("loop")), Bloc("loop", @@ -69,7 +69,7 @@ func TestDeadStoreTypes(t *testing.T) { Bloc("entry", Valu("start", OpArg, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), - Valu("v", OpConst, TypeBool, 0, true), + Valu("v", OpConstBool, TypeBool, 0, true), Valu("addr1", OpAddr, t1, 0, nil, "sb"), Valu("addr2", OpAddr, t2, 0, nil, "sb"), Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"), diff --git a/src/cmd/compile/internal/ssa/dom_test.go b/src/cmd/compile/internal/ssa/dom_test.go index 5209e307b7..1f3124167a 100644 --- a/src/cmd/compile/internal/ssa/dom_test.go +++ b/src/cmd/compile/internal/ssa/dom_test.go @@ -44,7 +44,7 @@ func genFwdBack(size int) []bloc { blocs = append(blocs, Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 0, true), Goto(blockn(0)), ), ) @@ -74,7 +74,7 @@ func genManyPred(size int) []bloc { blocs = append(blocs, Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 0, true), Goto(blockn(0)), ), ) @@ -85,15 +85,15 @@ func genManyPred(size int) []bloc { switch i % 3 { case 0: blocs = append(blocs, Bloc(blockn(i), - Valu("a", OpConst, TypeBool, 0, true), + Valu("a", OpConstBool, TypeBool, 0, true), Goto(blockn(i+1)))) case 1: blocs = append(blocs, Bloc(blockn(i), - Valu("a", OpConst, TypeBool, 0, true), + Valu("a", OpConstBool, TypeBool, 0, true), If("p", blockn(i+1), blockn(0)))) case 2: blocs = append(blocs, Bloc(blockn(i), - Valu("a", OpConst, TypeBool, 0, true), + Valu("a", OpConstBool, TypeBool, 0, true), If("p", blockn(i+1), blockn(size)))) } } @@ -112,7 +112,7 @@ func genMaxPred(size int) []bloc { blocs = append(blocs, Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 0, true), Goto(blockn(0)), ), ) @@ -137,14 +137,14 @@ func genMaxPredValue(size int) []bloc { blocs = append(blocs, Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 0, true), Goto(blockn(0)), ), ) for i := 0; i < size; i++ { blocs = append(blocs, Bloc(blockn(i), - Valu("a", OpConst, TypeBool, 0, true), + Valu("a", OpConstBool, TypeBool, 0, true), If("p", blockn(i+1), "exit"))) } @@ -267,7 +267,7 @@ func TestDominatorsMultPredFwd(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 0, true), If("p", "a", "c")), Bloc("a", If("p", "b", "c")), @@ -295,7 +295,7 @@ func TestDominatorsDeadCode(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, false), + Valu("p", OpConstBool, TypeBool, 0, false), If("p", "b3", "b5")), Bloc("b2", Exit("mem")), Bloc("b3", Goto("b2")), @@ -318,7 +318,7 @@ func TestDominatorsMultPredRev(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 0, true), Goto("a")), Bloc("a", If("p", "b", "entry")), @@ -346,7 +346,7 @@ func TestDominatorsMultPred(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 0, true), If("p", "a", "c")), Bloc("a", If("p", "b", "c")), @@ -374,7 +374,7 @@ func TestPostDominators(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 0, true), If("p", "a", "c")), Bloc("a", If("p", "b", "c")), @@ -401,7 +401,7 @@ func TestInfiniteLoop(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConst, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 0, true), Goto("a")), Bloc("a", Goto("b")), diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index e0f7c9ff60..ce13075f19 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -248,9 +248,25 @@ func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *V } // ConstInt returns an int constant representing its argument. -func (f *Func) ConstInt(line int32, t Type, c int64) *Value { +func (f *Func) ConstInt8(line int32, t Type, c int8) *Value { // TODO: cache? - return f.Entry.NewValue0I(line, OpConst, t, c) + return f.Entry.NewValue0I(line, OpConst8, t, int64(c)) +} +func (f *Func) ConstInt16(line int32, t Type, c int16) *Value { + // TODO: cache? + return f.Entry.NewValue0I(line, OpConst16, t, int64(c)) +} +func (f *Func) ConstInt32(line int32, t Type, c int32) *Value { + // TODO: cache? + return f.Entry.NewValue0I(line, OpConst32, t, int64(c)) +} +func (f *Func) ConstInt64(line int32, t Type, c int64) *Value { + // TODO: cache? + return f.Entry.NewValue0I(line, OpConst64, t, c) +} +func (f *Func) ConstIntPtr(line int32, t Type, c int64) *Value { + // TODO: cache? + return f.Entry.NewValue0I(line, OpConstPtr, t, c) } func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index edea8f78d1..dda96317fe 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -23,7 +23,7 @@ // Bloc("exit", // Exit("mem")), // Bloc("deadblock", -// Valu("deadval", OpConst, TypeBool, 0, true), +// Valu("deadval", OpConstBool, TypeBool, 0, true), // If("deadval", "deadblock", "exit"))) // // and the Blocks or Values used in the Func can be accessed @@ -265,8 +265,8 @@ func TestArgs(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}) fun := Fun(c, "entry", Bloc("entry", - Valu("a", OpConst, TypeInt64, 14, nil), - Valu("b", OpConst, TypeInt64, 26, nil), + Valu("a", OpConst64, TypeInt64, 14, nil), + Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), @@ -288,8 +288,8 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("a", OpConst, TypeInt64, 14, nil), - Valu("b", OpConst, TypeInt64, 26, nil), + Valu("a", OpConst64, TypeInt64, 14, nil), + Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), @@ -297,8 +297,8 @@ func TestEquiv(t *testing.T) { Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("a", OpConst, TypeInt64, 14, nil), - Valu("b", OpConst, TypeInt64, 26, nil), + Valu("a", OpConst64, TypeInt64, 14, nil), + Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), @@ -309,8 +309,8 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("a", OpConst, TypeInt64, 14, nil), - Valu("b", OpConst, TypeInt64, 26, nil), + Valu("a", OpConst64, TypeInt64, 14, nil), + Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit")), @@ -320,8 +320,8 @@ func TestEquiv(t *testing.T) { Bloc("exit", Exit("mem")), Bloc("entry", - Valu("a", OpConst, TypeInt64, 14, nil), - Valu("b", OpConst, TypeInt64, 26, nil), + Valu("a", OpConst64, TypeInt64, 14, nil), + Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("mem", OpArg, TypeMem, 0, ".mem"), Goto("exit"))), @@ -354,14 +354,14 @@ func TestEquiv(t *testing.T) { Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("b", OpConst, TypeInt64, 26, nil), - Valu("a", OpConst, TypeInt64, 14, nil), + Valu("b", OpConst64, TypeInt64, 26, nil), + Valu("a", OpConst64, TypeInt64, 14, nil), Exit("mem"))), Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("a", OpConst, TypeInt64, 14, nil), - Valu("b", OpConst, TypeInt64, 26, nil), + Valu("a", OpConst64, TypeInt64, 14, nil), + Valu("b", OpConst64, TypeInt64, 26, nil), Exit("mem"))), }, // value auxint different @@ -369,12 +369,12 @@ func TestEquiv(t *testing.T) { Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("a", OpConst, TypeInt64, 14, nil), + Valu("a", OpConst64, TypeInt64, 14, nil), Exit("mem"))), Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("a", OpConst, TypeInt64, 26, nil), + Valu("a", OpConst64, TypeInt64, 26, nil), Exit("mem"))), }, // value aux different @@ -382,12 +382,12 @@ func TestEquiv(t *testing.T) { Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("a", OpConst, TypeInt64, 0, 14), + Valu("a", OpConst64, TypeInt64, 0, 14), Exit("mem"))), Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("a", OpConst, TypeInt64, 0, 26), + Valu("a", OpConst64, TypeInt64, 0, 26), Exit("mem"))), }, // value args different @@ -395,15 +395,15 @@ func TestEquiv(t *testing.T) { Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("a", OpConst, TypeInt64, 14, nil), - Valu("b", OpConst, TypeInt64, 26, nil), + Valu("a", OpConst64, TypeInt64, 14, nil), + Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Exit("mem"))), Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("a", OpConst, TypeInt64, 0, nil), - Valu("b", OpConst, TypeInt64, 14, nil), + Valu("a", OpConst64, TypeInt64, 0, nil), + Valu("b", OpConst64, TypeInt64, 14, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "b", "a"), Exit("mem"))), }, diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index d881aaa693..5680dc58e3 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -82,7 +82,7 @@ (Rsh64 x y) && y.Type.Size() == 8 -> (SARQ x (CMOVQCC (CMPQconst [64] y) - (Const [63]) + (MOVQconst [63]) y)) (Less64 x y) -> (SETL (CMPQ x y)) @@ -116,16 +116,20 @@ (IsNonNil p) -> (SETNE (TESTQ p p)) (IsInBounds idx len) -> (SETB (CMPQ idx len)) -(Move [size] dst src mem) -> (REPMOVSB dst src (Const [size]) mem) +(Move [size] dst src mem) -> (REPMOVSB dst src (MOVQconst [size]) mem) (Not x) -> (XORQconst [1] x) (OffPtr [off] ptr) -> (ADDQconst [off] ptr) -(Const [val]) && t.IsInteger() -> (MOVQconst [val]) -(Const ) && t.IsPtr() -> (MOVQconst [0]) // nil is the only const pointer -(Const ) && t.IsBoolean() && !v.Aux.(bool) -> (MOVQconst [0]) -(Const ) && t.IsBoolean() && v.Aux.(bool) -> (MOVQconst [1]) +(Const8 [val]) -> (MOVBconst [val]) +(Const16 [val]) -> (MOVWconst [val]) +(Const32 [val]) -> (MOVLconst [val]) +(Const64 [val]) -> (MOVQconst [val]) +(ConstPtr [val]) -> (MOVQconst [val]) +(ConstNil) -> (MOVQconst [0]) +(ConstBool {b}) && !b.(bool) -> (MOVBconst [0]) +(ConstBool {b}) && b.(bool) -> (MOVBconst [1]) (Addr {sym} base) -> (LEAQ {sym} base) @@ -226,15 +230,15 @@ // lower Zero instructions with word sizes (Zero [0] _ mem) -> (Copy mem) -(Zero [1] destptr mem) -> (MOVBstore destptr (Const [0]) mem) -(Zero [2] destptr mem) -> (MOVWstore destptr (Const [0]) mem) -(Zero [4] destptr mem) -> (MOVLstore destptr (Const [0]) mem) -(Zero [8] destptr mem) -> (MOVQstore destptr (Const [0]) mem) +(Zero [1] destptr mem) -> (MOVBstore destptr (MOVBconst [0]) mem) +(Zero [2] destptr mem) -> (MOVWstore destptr (MOVWconst [0]) mem) +(Zero [4] destptr mem) -> (MOVLstore destptr (MOVLconst [0]) mem) +(Zero [8] destptr mem) -> (MOVQstore destptr (MOVQconst [0]) mem) // rewrite anything less than 4 words into a series of MOV[BWLQ] $0, ptr(off) instructions (Zero [size] destptr mem) && size < 4*8 -> (MOVXzero [size] destptr mem) // Use STOSQ to zero memory. Rewrite this into storing the words with REPSTOSQ and then filling in the remainder with linear moves -(Zero [size] destptr mem) && size >= 4*8 -> (Zero [size%8] (OffPtr [size-(size%8)] destptr) (REPSTOSQ destptr (Const [size/8]) mem)) +(Zero [size] destptr mem) && size >= 4*8 -> (Zero [size%8] (OffPtr [size-(size%8)] destptr) (REPSTOSQ destptr (MOVQconst [size/8]) mem)) // Absorb InvertFlags into branches. (LT (InvertFlags cmp) yes no) -> (GT cmp yes no) @@ -249,8 +253,8 @@ (NE (InvertFlags cmp) yes no) -> (NE cmp yes no) // get rid of >=64 code for constant shifts -(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds(d, c) -> (Const [-1]) -(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds(d, c) -> (Const [0]) +(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds(d, c) -> (MOVQconst [-1]) +(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds(d, c) -> (MOVQconst [0]) (ANDQconst [0] _) -> (MOVQconst [0]) (ANDQconst [-1] x) -> (Copy x) (CMOVQCC (CMPQconst [c] (MOVQconst [d])) _ x) && inBounds(d, c) -> (Copy x) diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 9b5c302217..40f7b1680f 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -138,12 +138,16 @@ func init() { {name: "MOVLQSX", reg: gp11, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64 {name: "MOVLQZX", reg: gp11, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64 - {name: "MOVQconst", reg: gp01}, // auxint - {name: "LEAQ", reg: gp11sb}, // arg0 + auxint + offset encoded in aux - {name: "LEAQ1", reg: gp21sb}, // arg0 + arg1 + auxint - {name: "LEAQ2", reg: gp21sb}, // arg0 + 2*arg1 + auxint - {name: "LEAQ4", reg: gp21sb}, // arg0 + 4*arg1 + auxint - {name: "LEAQ8", reg: gp21sb}, // arg0 + 8*arg1 + auxint + {name: "MOVBconst", reg: gp01, asm: "MOVB"}, // 8 low bits of auxint + {name: "MOVWconst", reg: gp01, asm: "MOVW"}, // 16 low bits of auxint + {name: "MOVLconst", reg: gp01, asm: "MOVL"}, // 32 low bits of auxint + {name: "MOVQconst", reg: gp01, asm: "MOVQ"}, // auxint + + {name: "LEAQ", reg: gp11sb}, // arg0 + auxint + offset encoded in aux + {name: "LEAQ1", reg: gp21sb}, // arg0 + arg1 + auxint + {name: "LEAQ2", reg: gp21sb}, // arg0 + 2*arg1 + auxint + {name: "LEAQ4", reg: gp21sb}, // arg0 + 4*arg1 + auxint + {name: "LEAQ8", reg: gp21sb}, // arg0 + 8*arg1 + auxint {name: "MOVBload", reg: gpload, asm: "MOVB"}, // load byte from arg0+auxint. arg1=mem {name: "MOVBQSXload", reg: gpload, asm: "MOVBQSX"}, // ditto, extend to int64 diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index d13466f06a..49c70af4cc 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -20,31 +20,31 @@ // For now, the generated successors must be a permutation of the matched successors. // constant folding -(Add64 (Const [c]) (Const [d])) -> (Const [c+d]) -(AddPtr (Const [c]) (Const [d])) -> (Const [c+d]) -(Mul64 (Const [c]) (Const [d])) -> (Const [c*d]) -(MulPtr (Const [c]) (Const [d])) -> (Const [c*d]) -(IsInBounds (Const [c]) (Const [d])) -> (Const {inBounds(c,d)}) +(Add64 (Const64 [c]) (Const64 [d])) -> (Const64 [c+d]) +(AddPtr (ConstPtr [c]) (ConstPtr [d])) -> (ConstPtr [c+d]) +(Mul64 (Const64 [c]) (Const64 [d])) -> (Const64 [c*d]) +(MulPtr (ConstPtr [c]) (ConstPtr [d])) -> (ConstPtr [c*d]) +(IsInBounds (ConstPtr [c]) (ConstPtr [d])) -> (ConstPtr {inBounds(c,d)}) // tear apart slices // TODO: anything that generates a slice needs to go in here. (SlicePtr (Load ptr mem)) -> (Load ptr mem) -(SliceLen (Load ptr mem)) -> (Load (AddPtr ptr (Const [config.PtrSize])) mem) -(SliceCap (Load ptr mem)) -> (Load (AddPtr ptr (Const [config.PtrSize*2])) mem) +(SliceLen (Load ptr mem)) -> (Load (AddPtr ptr (ConstPtr [config.PtrSize])) mem) +(SliceCap (Load ptr mem)) -> (Load (AddPtr ptr (ConstPtr [config.PtrSize*2])) mem) // slice and interface comparisons // the frontend ensures that we can only compare against nil // start by putting nil on the right to simplify the other rules -(EqFat x y) && x.Op == OpConst && y.Op != OpConst -> (EqFat y x) -(NeqFat x y) && x.Op == OpConst && y.Op != OpConst -> (NeqFat y x) +(EqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (EqFat y x) +(NeqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (NeqFat y x) // it suffices to check the first word (backing array for slices, dynamic type for interfaces) -(EqFat (Load ptr mem) y) && y.Op == OpConst -> (EqPtr (Load ptr mem) (Const [0])) -(NeqFat (Load ptr mem) y) && y.Op == OpConst -> (NeqPtr (Load ptr mem) (Const [0])) +(EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load ptr mem) (ConstPtr [0])) +(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load ptr mem) (ConstPtr [0])) // indexing operations // Note: bounds check has already been done (ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex ptr idx) mem) -(PtrIndex ptr idx) -> (AddPtr ptr (MulPtr idx (Const [t.Elem().Size()]))) +(PtrIndex ptr idx) -> (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()]))) (StructSelect [idx] (Load ptr mem)) -> (Load (OffPtr [idx] ptr) mem) // big-object moves @@ -52,12 +52,12 @@ (Store dst (Load src mem) mem) && t.Size() > 8 -> (Move [t.Size()] dst src mem) // string ops -(Const {s}) && t.IsString() -> (StringMake (Addr {config.fe.StringData(s.(string))} (SB )) (Const [int64(len(s.(string)))])) +(ConstString {s}) -> (StringMake (Addr {config.fe.StringData(s.(string))} (SB )) (ConstPtr [int64(len(s.(string)))])) (Load ptr mem) && t.IsString() -> (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) (StringPtr (StringMake ptr _)) -> ptr (StringLen (StringMake _ len)) -> len (Store dst str mem) && str.Type.IsString() -> (Store (OffPtr [config.PtrSize] dst) (StringLen str) (Store dst (StringPtr str) mem)) (If (Not cond) yes no) -> (If cond no yes) -(If (Const {c}) yes no) && c.(bool) -> (Plain nil yes) -(If (Const {c}) yes no) && !c.(bool) -> (Plain nil no) +(If (ConstBool {c}) yes no) && c.(bool) -> (Plain nil yes) +(If (ConstBool {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 index 2dcaa67bd1..732641319f 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -115,7 +115,15 @@ var genericOps = []opData{ // in the AuxInt field as an int64 (including int, uint64, etc.). // For integer types smaller than 64 bits, only the low-order // bits of the AuxInt field matter. - {name: "Const"}, + {name: "ConstBool"}, + {name: "ConstString"}, + {name: "ConstNil"}, + {name: "Const8"}, + {name: "Const16"}, + {name: "Const32"}, + {name: "Const64"}, + {name: "ConstPtr"}, // pointer-sized integer constant + // TODO: Const32F, ... // Constant-like things {name: "Arg"}, // memory input to the function. diff --git a/src/cmd/compile/internal/ssa/gen/rulegen.go b/src/cmd/compile/internal/ssa/gen/rulegen.go index 8dca0bca1f..03cbf7cd57 100644 --- a/src/cmd/compile/internal/ssa/gen/rulegen.go +++ b/src/cmd/compile/internal/ssa/gen/rulegen.go @@ -81,6 +81,9 @@ func genRules(arch arch) { continue } op := strings.Split(rule, " ")[0][1:] + if op[len(op)-1] == ')' { + op = op[:len(op)-1] // rule has only opcode, e.g. (ConstNil) -> ... + } if isBlock(op, arch) { blockrules[op] = append(blockrules[op], rule) } else { diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 0d56e647af..358459ea8e 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -85,6 +85,9 @@ const ( OpAMD64MOVWQZX OpAMD64MOVLQSX OpAMD64MOVLQZX + OpAMD64MOVBconst + OpAMD64MOVWconst + OpAMD64MOVLconst OpAMD64MOVQconst OpAMD64LEAQ OpAMD64LEAQ1 @@ -214,7 +217,14 @@ const ( OpNeg64 OpPhi OpCopy - OpConst + OpConstBool + OpConstString + OpConstNil + OpConst8 + OpConst16 + OpConst32 + OpConst64 + OpConstPtr OpArg OpAddr OpSP @@ -685,8 +695,36 @@ var opcodeTable = [...]opInfo{ }, }, }, + { + name: "MOVBconst", + asm: x86.AMOVB, + reg: regInfo{ + outputs: []regMask{ + 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + }, + }, + }, + { + name: "MOVWconst", + asm: x86.AMOVW, + reg: regInfo{ + outputs: []regMask{ + 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + }, + }, + }, + { + name: "MOVLconst", + asm: x86.AMOVL, + reg: regInfo{ + outputs: []regMask{ + 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 + }, + }, + }, { name: "MOVQconst", + asm: x86.AMOVQ, reg: regInfo{ outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1546,7 +1584,35 @@ var opcodeTable = [...]opInfo{ generic: true, }, { - name: "Const", + name: "ConstBool", + generic: true, + }, + { + name: "ConstString", + generic: true, + }, + { + name: "ConstNil", + generic: true, + }, + { + name: "Const8", + generic: true, + }, + { + name: "Const16", + generic: true, + }, + { + name: "Const32", + generic: true, + }, + { + name: "Const64", + generic: true, + }, + { + name: "ConstPtr", generic: true, }, { diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index c21f3ab7a7..abf504e6b4 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -492,16 +492,44 @@ func rewriteValueAMD64(v *Value, config *Config) bool { goto endfd75d26316012d86cb71d0dd1214259b endfd75d26316012d86cb71d0dd1214259b: ; - case OpConst: - // match: (Const [val]) - // cond: t.IsInteger() + case OpConst16: + // match: (Const16 [val]) + // cond: + // result: (MOVWconst [val]) + { + val := v.AuxInt + v.Op = OpAMD64MOVWconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = val + return true + } + goto end2c6c92f297873b8ac12bd035d56d001e + end2c6c92f297873b8ac12bd035d56d001e: + ; + case OpConst32: + // match: (Const32 [val]) + // cond: + // result: (MOVLconst [val]) + { + val := v.AuxInt + v.Op = OpAMD64MOVLconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = val + return true + } + goto enddae5807662af67143a3ac3ad9c63bae5 + enddae5807662af67143a3ac3ad9c63bae5: + ; + case OpConst64: + // match: (Const64 [val]) + // cond: // result: (MOVQconst [val]) { - t := v.Type val := v.AuxInt - if !(t.IsInteger()) { - goto end4c8bfe9df26fc5aa2bd76b211792732a - } v.Op = OpAMD64MOVQconst v.AuxInt = 0 v.Aux = nil @@ -509,35 +537,67 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.AuxInt = val return true } - goto end4c8bfe9df26fc5aa2bd76b211792732a - end4c8bfe9df26fc5aa2bd76b211792732a: + goto endc630434ae7f143ab69d5f482a9b52b5f + endc630434ae7f143ab69d5f482a9b52b5f: ; - // match: (Const ) - // cond: t.IsPtr() - // result: (MOVQconst [0]) + case OpConst8: + // match: (Const8 [val]) + // cond: + // result: (MOVBconst [val]) { - t := v.Type - if !(t.IsPtr()) { - goto endd23abe8d7061f11c260b162e24eec060 + val := v.AuxInt + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = val + return true + } + goto end200524c722ed14ca935ba47f8f30327d + end200524c722ed14ca935ba47f8f30327d: + ; + case OpConstBool: + // match: (ConstBool {b}) + // cond: !b.(bool) + // result: (MOVBconst [0]) + { + b := v.Aux + if !(!b.(bool)) { + goto end876159ea073d2dcefcc251667c1a7780 } - v.Op = OpAMD64MOVQconst + v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = 0 return true } - goto endd23abe8d7061f11c260b162e24eec060 - endd23abe8d7061f11c260b162e24eec060: + goto end876159ea073d2dcefcc251667c1a7780 + end876159ea073d2dcefcc251667c1a7780: ; - // match: (Const ) - // cond: t.IsBoolean() && !v.Aux.(bool) - // result: (MOVQconst [0]) + // match: (ConstBool {b}) + // cond: b.(bool) + // result: (MOVBconst [1]) { - t := v.Type - if !(t.IsBoolean() && !v.Aux.(bool)) { - goto end7b1347fd0902b990ee1e49145c7e8c31 + b := v.Aux + if !(b.(bool)) { + goto end0dacad3f7cad53905aad5303391447f6 } + v.Op = OpAMD64MOVBconst + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v.AuxInt = 1 + return true + } + goto end0dacad3f7cad53905aad5303391447f6 + end0dacad3f7cad53905aad5303391447f6: + ; + case OpConstNil: + // match: (ConstNil) + // cond: + // result: (MOVQconst [0]) + { v.Op = OpAMD64MOVQconst v.AuxInt = 0 v.Aux = nil @@ -545,26 +605,24 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.AuxInt = 0 return true } - goto end7b1347fd0902b990ee1e49145c7e8c31 - end7b1347fd0902b990ee1e49145c7e8c31: + goto endea557d921056c25b945a49649e4b9b91 + endea557d921056c25b945a49649e4b9b91: ; - // match: (Const ) - // cond: t.IsBoolean() && v.Aux.(bool) - // result: (MOVQconst [1]) + case OpConstPtr: + // match: (ConstPtr [val]) + // cond: + // result: (MOVQconst [val]) { - t := v.Type - if !(t.IsBoolean() && v.Aux.(bool)) { - goto ende0d1c954b5ab5af7227bff9635774f1c - } + val := v.AuxInt v.Op = OpAMD64MOVQconst v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AuxInt = 1 + v.AuxInt = val return true } - goto ende0d1c954b5ab5af7227bff9635774f1c - ende0d1c954b5ab5af7227bff9635774f1c: + goto endc395c0a53eeccf597e225a07b53047d1 + endc395c0a53eeccf597e225a07b53047d1: ; case OpConvNop: // match: (ConvNop x) @@ -1527,7 +1585,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { case OpMove: // match: (Move [size] dst src mem) // cond: - // result: (REPMOVSB dst src (Const [size]) mem) + // result: (REPMOVSB dst src (MOVQconst [size]) mem) { size := v.AuxInt dst := v.Args[0] @@ -1539,15 +1597,15 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.resetArgs() v.AddArg(dst) v.AddArg(src) - v0 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v0 := v.Block.NewValue0(v.Line, OpAMD64MOVQconst, TypeInvalid) v0.Type = TypeUInt64 v0.AuxInt = size v.AddArg(v0) v.AddArg(mem) return true } - goto end1b2d226705fd31dbbe74e3286af178ea - end1b2d226705fd31dbbe74e3286af178ea: + goto end2aab774aedae2c616ee88bfa87cdf30e + end2aab774aedae2c616ee88bfa87cdf30e: ; case OpMul16: // match: (Mul16 x y) @@ -1846,13 +1904,13 @@ func rewriteValueAMD64(v *Value, config *Config) bool { case OpRsh64: // match: (Rsh64 x y) // cond: y.Type.Size() == 8 - // result: (SARQ x (CMOVQCC (CMPQconst [64] y) (Const [63]) y)) + // result: (SARQ x (CMOVQCC (CMPQconst [64] y) (MOVQconst [63]) y)) { t := v.Type x := v.Args[0] y := v.Args[1] if !(y.Type.Size() == 8) { - goto end16bda9bd1611d415969fdbec55ed4330 + goto endd5f88a8c4f11e0e844b35fd8677bd940 } v.Op = OpAMD64SARQ v.AuxInt = 0 @@ -1867,7 +1925,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v1.AuxInt = 64 v1.AddArg(y) v0.AddArg(v1) - v2 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v2 := v.Block.NewValue0(v.Line, OpAMD64MOVQconst, TypeInvalid) v2.Type = t v2.AuxInt = 63 v0.AddArg(v2) @@ -1875,8 +1933,8 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.AddArg(v0) return true } - goto end16bda9bd1611d415969fdbec55ed4330 - end16bda9bd1611d415969fdbec55ed4330: + goto endd5f88a8c4f11e0e844b35fd8677bd940 + endd5f88a8c4f11e0e844b35fd8677bd940: ; case OpRsh64U: // match: (Rsh64U x y) @@ -1935,53 +1993,53 @@ func rewriteValueAMD64(v *Value, config *Config) bool { case OpAMD64SBBQcarrymask: // match: (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) // cond: inBounds(d, c) - // result: (Const [-1]) + // result: (MOVQconst [-1]) { if v.Args[0].Op != OpAMD64CMPQconst { - goto endf67d323ecef000dbcd15d7e031c3475e + goto end378de7e659770f877c08b6b269073069 } c := v.Args[0].AuxInt if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto endf67d323ecef000dbcd15d7e031c3475e + goto end378de7e659770f877c08b6b269073069 } d := v.Args[0].Args[0].AuxInt if !(inBounds(d, c)) { - goto endf67d323ecef000dbcd15d7e031c3475e + goto end378de7e659770f877c08b6b269073069 } - v.Op = OpConst + v.Op = OpAMD64MOVQconst v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = -1 return true } - goto endf67d323ecef000dbcd15d7e031c3475e - endf67d323ecef000dbcd15d7e031c3475e: + goto end378de7e659770f877c08b6b269073069 + end378de7e659770f877c08b6b269073069: ; // match: (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) // cond: !inBounds(d, c) - // result: (Const [0]) + // result: (MOVQconst [0]) { if v.Args[0].Op != OpAMD64CMPQconst { - goto end4157ddea9c4f71bfabfd6fa50e1208ed + goto enda7bfd1974bf83ca79653c560a718a86c } c := v.Args[0].AuxInt if v.Args[0].Args[0].Op != OpAMD64MOVQconst { - goto end4157ddea9c4f71bfabfd6fa50e1208ed + goto enda7bfd1974bf83ca79653c560a718a86c } d := v.Args[0].Args[0].AuxInt if !(!inBounds(d, c)) { - goto end4157ddea9c4f71bfabfd6fa50e1208ed + goto enda7bfd1974bf83ca79653c560a718a86c } - v.Op = OpConst + v.Op = OpAMD64MOVQconst v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = 0 return true } - goto end4157ddea9c4f71bfabfd6fa50e1208ed - end4157ddea9c4f71bfabfd6fa50e1208ed: + goto enda7bfd1974bf83ca79653c560a718a86c + enda7bfd1974bf83ca79653c560a718a86c: ; case OpAMD64SETA: // match: (SETA (InvertFlags x)) @@ -2676,10 +2734,10 @@ func rewriteValueAMD64(v *Value, config *Config) bool { ; // match: (Zero [1] destptr mem) // cond: - // result: (MOVBstore destptr (Const [0]) mem) + // result: (MOVBstore destptr (MOVBconst [0]) mem) { if v.AuxInt != 1 { - goto end09ec7b1fc5ad40534e0e25c896323f5c + goto end16839f51d2e9cf9548f216848406bd97 } destptr := v.Args[0] mem := v.Args[1] @@ -2688,22 +2746,22 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.Aux = nil v.resetArgs() v.AddArg(destptr) - v0 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v0 := v.Block.NewValue0(v.Line, OpAMD64MOVBconst, TypeInvalid) v0.Type = TypeInt8 v0.AuxInt = 0 v.AddArg(v0) v.AddArg(mem) return true } - goto end09ec7b1fc5ad40534e0e25c896323f5c - end09ec7b1fc5ad40534e0e25c896323f5c: + goto end16839f51d2e9cf9548f216848406bd97 + end16839f51d2e9cf9548f216848406bd97: ; // match: (Zero [2] destptr mem) // cond: - // result: (MOVWstore destptr (Const [0]) mem) + // result: (MOVWstore destptr (MOVWconst [0]) mem) { if v.AuxInt != 2 { - goto end2dee246789dbd305bb1eaec768bdae14 + goto enddc4a090329efde9ca19983ad18174cbb } destptr := v.Args[0] mem := v.Args[1] @@ -2712,22 +2770,22 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.Aux = nil v.resetArgs() v.AddArg(destptr) - v0 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v0 := v.Block.NewValue0(v.Line, OpAMD64MOVWconst, TypeInvalid) v0.Type = TypeInt16 v0.AuxInt = 0 v.AddArg(v0) v.AddArg(mem) return true } - goto end2dee246789dbd305bb1eaec768bdae14 - end2dee246789dbd305bb1eaec768bdae14: + goto enddc4a090329efde9ca19983ad18174cbb + enddc4a090329efde9ca19983ad18174cbb: ; // match: (Zero [4] destptr mem) // cond: - // result: (MOVLstore destptr (Const [0]) mem) + // result: (MOVLstore destptr (MOVLconst [0]) mem) { if v.AuxInt != 4 { - goto ende2bf4ecf21bc9e76700a9c5f62546e78 + goto end365a027b67399ad8d5d2d5eca847f7d8 } destptr := v.Args[0] mem := v.Args[1] @@ -2736,22 +2794,22 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.Aux = nil v.resetArgs() v.AddArg(destptr) - v0 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v0 := v.Block.NewValue0(v.Line, OpAMD64MOVLconst, TypeInvalid) v0.Type = TypeInt32 v0.AuxInt = 0 v.AddArg(v0) v.AddArg(mem) return true } - goto ende2bf4ecf21bc9e76700a9c5f62546e78 - ende2bf4ecf21bc9e76700a9c5f62546e78: + goto end365a027b67399ad8d5d2d5eca847f7d8 + end365a027b67399ad8d5d2d5eca847f7d8: ; // match: (Zero [8] destptr mem) // cond: - // result: (MOVQstore destptr (Const [0]) mem) + // result: (MOVQstore destptr (MOVQconst [0]) mem) { if v.AuxInt != 8 { - goto enda65d5d60783daf9b9405f04c44f7adaf + goto end5808a5e9c68555a82c3514db39017e56 } destptr := v.Args[0] mem := v.Args[1] @@ -2760,15 +2818,15 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.Aux = nil v.resetArgs() v.AddArg(destptr) - v0 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v0 := v.Block.NewValue0(v.Line, OpAMD64MOVQconst, TypeInvalid) v0.Type = TypeInt64 v0.AuxInt = 0 v.AddArg(v0) v.AddArg(mem) return true } - goto enda65d5d60783daf9b9405f04c44f7adaf - enda65d5d60783daf9b9405f04c44f7adaf: + goto end5808a5e9c68555a82c3514db39017e56 + end5808a5e9c68555a82c3514db39017e56: ; // match: (Zero [size] destptr mem) // cond: size < 4*8 @@ -2794,13 +2852,13 @@ func rewriteValueAMD64(v *Value, config *Config) bool { ; // match: (Zero [size] destptr mem) // cond: size >= 4*8 - // result: (Zero [size%8] (OffPtr [size-(size%8)] destptr) (REPSTOSQ destptr (Const [size/8]) mem)) + // result: (Zero [size%8] (OffPtr [size-(size%8)] destptr) (REPSTOSQ destptr (MOVQconst [size/8]) mem)) { size := v.AuxInt destptr := v.Args[0] mem := v.Args[1] if !(size >= 4*8) { - goto end7a358169d20d6834b21f2e03fbf351b2 + goto endb3058a90f909821d5689fb358519828b } v.Op = OpZero v.AuxInt = 0 @@ -2815,7 +2873,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v1 := v.Block.NewValue0(v.Line, OpAMD64REPSTOSQ, TypeInvalid) v1.Type = TypeMem v1.AddArg(destptr) - v2 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v2 := v.Block.NewValue0(v.Line, OpAMD64MOVQconst, TypeInvalid) v2.Type = TypeUInt64 v2.AuxInt = size / 8 v1.AddArg(v2) @@ -2823,8 +2881,8 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.AddArg(v1) return true } - goto end7a358169d20d6834b21f2e03fbf351b2 - end7a358169d20d6834b21f2e03fbf351b2: + goto endb3058a90f909821d5689fb358519828b + endb3058a90f909821d5689fb358519828b: ; case OpZeroExt16to32: // match: (ZeroExt16to32 x) diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 2c2a48693a..8fa3b6ded1 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -5,50 +5,50 @@ package ssa func rewriteValuegeneric(v *Value, config *Config) bool { switch v.Op { case OpAdd64: - // match: (Add64 (Const [c]) (Const [d])) + // match: (Add64 (Const64 [c]) (Const64 [d])) // cond: - // result: (Const [c+d]) + // result: (Const64 [c+d]) { - if v.Args[0].Op != OpConst { - goto endd2f4bfaaf6c937171a287b73e5c2f73e + if v.Args[0].Op != OpConst64 { + goto end8c46df6f85a11cb1d594076b0e467908 } c := v.Args[0].AuxInt - if v.Args[1].Op != OpConst { - goto endd2f4bfaaf6c937171a287b73e5c2f73e + if v.Args[1].Op != OpConst64 { + goto end8c46df6f85a11cb1d594076b0e467908 } d := v.Args[1].AuxInt - v.Op = OpConst + v.Op = OpConst64 v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = c + d return true } - goto endd2f4bfaaf6c937171a287b73e5c2f73e - endd2f4bfaaf6c937171a287b73e5c2f73e: + goto end8c46df6f85a11cb1d594076b0e467908 + end8c46df6f85a11cb1d594076b0e467908: ; case OpAddPtr: - // match: (AddPtr (Const [c]) (Const [d])) + // match: (AddPtr (ConstPtr [c]) (ConstPtr [d])) // cond: - // result: (Const [c+d]) + // result: (ConstPtr [c+d]) { - if v.Args[0].Op != OpConst { - goto end67284cb7ae441d6c763096b49a3569a3 + if v.Args[0].Op != OpConstPtr { + goto end145c1aec793b2befff34bc8983b48a38 } c := v.Args[0].AuxInt - if v.Args[1].Op != OpConst { - goto end67284cb7ae441d6c763096b49a3569a3 + if v.Args[1].Op != OpConstPtr { + goto end145c1aec793b2befff34bc8983b48a38 } d := v.Args[1].AuxInt - v.Op = OpConst + v.Op = OpConstPtr v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = c + d return true } - goto end67284cb7ae441d6c763096b49a3569a3 - end67284cb7ae441d6c763096b49a3569a3: + goto end145c1aec793b2befff34bc8983b48a38 + end145c1aec793b2befff34bc8983b48a38: ; case OpArrayIndex: // match: (ArrayIndex (Load ptr mem) idx) @@ -76,16 +76,12 @@ func rewriteValuegeneric(v *Value, config *Config) bool { goto end4894dd7b58383fee5f8a92be08437c33 end4894dd7b58383fee5f8a92be08437c33: ; - case OpConst: - // match: (Const {s}) - // cond: t.IsString() - // result: (StringMake (Addr {config.fe.StringData(s.(string))} (SB )) (Const [int64(len(s.(string)))])) + case OpConstString: + // match: (ConstString {s}) + // cond: + // result: (StringMake (Addr {config.fe.StringData(s.(string))} (SB )) (ConstPtr [int64(len(s.(string)))])) { - t := v.Type s := v.Aux - if !(t.IsString()) { - goto enda6f250a3c775ae5a239ece8074b46cea - } v.Op = OpStringMake v.AuxInt = 0 v.Aux = nil @@ -97,24 +93,24 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v1.Type = config.Uintptr v0.AddArg(v1) v.AddArg(v0) - v2 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v2 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) v2.Type = config.Uintptr v2.AuxInt = int64(len(s.(string))) v.AddArg(v2) return true } - goto enda6f250a3c775ae5a239ece8074b46cea - enda6f250a3c775ae5a239ece8074b46cea: + goto end1a01fc02fad8727f9a3b716cfdac3a44 + end1a01fc02fad8727f9a3b716cfdac3a44: ; case OpEqFat: // match: (EqFat x y) - // cond: x.Op == OpConst && y.Op != OpConst + // cond: x.Op == OpConstNil && y.Op != OpConstNil // result: (EqFat y x) { x := v.Args[0] y := v.Args[1] - if !(x.Op == OpConst && y.Op != OpConst) { - goto end4540bddcf0fc8e4b71fac6e9edbb8eec + if !(x.Op == OpConstNil && y.Op != OpConstNil) { + goto endcea7f7399afcff860c54d82230a9a934 } v.Op = OpEqFat v.AuxInt = 0 @@ -124,21 +120,20 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v.AddArg(x) return true } - goto end4540bddcf0fc8e4b71fac6e9edbb8eec - end4540bddcf0fc8e4b71fac6e9edbb8eec: + goto endcea7f7399afcff860c54d82230a9a934 + endcea7f7399afcff860c54d82230a9a934: ; - // match: (EqFat (Load ptr mem) y) - // cond: y.Op == OpConst - // result: (EqPtr (Load ptr mem) (Const [0])) + // match: (EqFat (Load ptr mem) (ConstNil)) + // cond: + // result: (EqPtr (Load ptr mem) (ConstPtr [0])) { if v.Args[0].Op != OpLoad { - goto end779b0e24e33d8eff668c368b90387caa + goto end2597220d1792c84d362da7901d2065d2 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] - y := v.Args[1] - if !(y.Op == OpConst) { - goto end779b0e24e33d8eff668c368b90387caa + if v.Args[1].Op != OpConstNil { + goto end2597220d1792c84d362da7901d2065d2 } v.Op = OpEqPtr v.AuxInt = 0 @@ -149,37 +144,37 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v0.AddArg(ptr) v0.AddArg(mem) v.AddArg(v0) - v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) v1.Type = config.Uintptr v1.AuxInt = 0 v.AddArg(v1) return true } - goto end779b0e24e33d8eff668c368b90387caa - end779b0e24e33d8eff668c368b90387caa: + goto end2597220d1792c84d362da7901d2065d2 + end2597220d1792c84d362da7901d2065d2: ; case OpIsInBounds: - // match: (IsInBounds (Const [c]) (Const [d])) + // match: (IsInBounds (ConstPtr [c]) (ConstPtr [d])) // cond: - // result: (Const {inBounds(c,d)}) + // result: (ConstPtr {inBounds(c,d)}) { - if v.Args[0].Op != OpConst { - goto enda96ccac78df2d17ae96c8baf2af2e189 + if v.Args[0].Op != OpConstPtr { + goto enddfd340bc7103ca323354aec96b113c23 } c := v.Args[0].AuxInt - if v.Args[1].Op != OpConst { - goto enda96ccac78df2d17ae96c8baf2af2e189 + if v.Args[1].Op != OpConstPtr { + goto enddfd340bc7103ca323354aec96b113c23 } d := v.Args[1].AuxInt - v.Op = OpConst + v.Op = OpConstPtr v.AuxInt = 0 v.Aux = nil v.resetArgs() v.Aux = inBounds(c, d) return true } - goto enda96ccac78df2d17ae96c8baf2af2e189 - enda96ccac78df2d17ae96c8baf2af2e189: + goto enddfd340bc7103ca323354aec96b113c23 + enddfd340bc7103ca323354aec96b113c23: ; case OpLoad: // match: (Load ptr mem) @@ -216,60 +211,60 @@ func rewriteValuegeneric(v *Value, config *Config) bool { endce3ba169a57b8a9f6b12751d49b4e23a: ; case OpMul64: - // match: (Mul64 (Const [c]) (Const [d])) + // match: (Mul64 (Const64 [c]) (Const64 [d])) // cond: - // result: (Const [c*d]) + // result: (Const64 [c*d]) { - if v.Args[0].Op != OpConst { - goto endf4ba5346dc8a624781afaa68a8096a9a + if v.Args[0].Op != OpConst64 { + goto end7aea1048b5d1230974b97f17238380ae } c := v.Args[0].AuxInt - if v.Args[1].Op != OpConst { - goto endf4ba5346dc8a624781afaa68a8096a9a + if v.Args[1].Op != OpConst64 { + goto end7aea1048b5d1230974b97f17238380ae } d := v.Args[1].AuxInt - v.Op = OpConst + v.Op = OpConst64 v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = c * d return true } - goto endf4ba5346dc8a624781afaa68a8096a9a - endf4ba5346dc8a624781afaa68a8096a9a: + goto end7aea1048b5d1230974b97f17238380ae + end7aea1048b5d1230974b97f17238380ae: ; case OpMulPtr: - // match: (MulPtr (Const [c]) (Const [d])) + // match: (MulPtr (ConstPtr [c]) (ConstPtr [d])) // cond: - // result: (Const [c*d]) + // result: (ConstPtr [c*d]) { - if v.Args[0].Op != OpConst { - goto end10541de7ea2bce703c1e372ac9a271e7 + if v.Args[0].Op != OpConstPtr { + goto end808c190f346658bb1ad032bf37a1059f } c := v.Args[0].AuxInt - if v.Args[1].Op != OpConst { - goto end10541de7ea2bce703c1e372ac9a271e7 + if v.Args[1].Op != OpConstPtr { + goto end808c190f346658bb1ad032bf37a1059f } d := v.Args[1].AuxInt - v.Op = OpConst + v.Op = OpConstPtr v.AuxInt = 0 v.Aux = nil v.resetArgs() v.AuxInt = c * d return true } - goto end10541de7ea2bce703c1e372ac9a271e7 - end10541de7ea2bce703c1e372ac9a271e7: + goto end808c190f346658bb1ad032bf37a1059f + end808c190f346658bb1ad032bf37a1059f: ; case OpNeqFat: // match: (NeqFat x y) - // cond: x.Op == OpConst && y.Op != OpConst + // cond: x.Op == OpConstNil && y.Op != OpConstNil // result: (NeqFat y x) { x := v.Args[0] y := v.Args[1] - if !(x.Op == OpConst && y.Op != OpConst) { - goto end5d2a9d3aa52fb6866825f35ac65c7cfd + if !(x.Op == OpConstNil && y.Op != OpConstNil) { + goto end94c68f7dc30c66ed42e507e01c4e5dc7 } v.Op = OpNeqFat v.AuxInt = 0 @@ -279,21 +274,20 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v.AddArg(x) return true } - goto end5d2a9d3aa52fb6866825f35ac65c7cfd - end5d2a9d3aa52fb6866825f35ac65c7cfd: + goto end94c68f7dc30c66ed42e507e01c4e5dc7 + end94c68f7dc30c66ed42e507e01c4e5dc7: ; - // match: (NeqFat (Load ptr mem) y) - // cond: y.Op == OpConst - // result: (NeqPtr (Load ptr mem) (Const [0])) + // match: (NeqFat (Load ptr mem) (ConstNil)) + // cond: + // result: (NeqPtr (Load ptr mem) (ConstPtr [0])) { if v.Args[0].Op != OpLoad { - goto endf2f18052c2d999a7ac883c441c3b7ade + goto end03a0fc8dde062c55439174f70c19e6ce } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] - y := v.Args[1] - if !(y.Op == OpConst) { - goto endf2f18052c2d999a7ac883c441c3b7ade + if v.Args[1].Op != OpConstNil { + goto end03a0fc8dde062c55439174f70c19e6ce } v.Op = OpNeqPtr v.AuxInt = 0 @@ -304,19 +298,19 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v0.AddArg(ptr) v0.AddArg(mem) v.AddArg(v0) - v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) v1.Type = config.Uintptr v1.AuxInt = 0 v.AddArg(v1) return true } - goto endf2f18052c2d999a7ac883c441c3b7ade - endf2f18052c2d999a7ac883c441c3b7ade: + goto end03a0fc8dde062c55439174f70c19e6ce + end03a0fc8dde062c55439174f70c19e6ce: ; case OpPtrIndex: // match: (PtrIndex ptr idx) // cond: - // result: (AddPtr ptr (MulPtr idx (Const [t.Elem().Size()]))) + // result: (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()]))) { t := v.Type ptr := v.Args[0] @@ -329,23 +323,23 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v0 := v.Block.NewValue0(v.Line, OpMulPtr, TypeInvalid) v0.Type = config.Uintptr v0.AddArg(idx) - v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) v1.Type = config.Uintptr v1.AuxInt = t.Elem().Size() v0.AddArg(v1) v.AddArg(v0) return true } - goto endb39bbe157d1791123f6083b2cfc59ddc - endb39bbe157d1791123f6083b2cfc59ddc: + goto endfb3e605edaa4c3c0684c4fa9c8f150ee + endfb3e605edaa4c3c0684c4fa9c8f150ee: ; case OpSliceCap: // match: (SliceCap (Load ptr mem)) // cond: - // result: (Load (AddPtr ptr (Const [config.PtrSize*2])) mem) + // result: (Load (AddPtr ptr (ConstPtr [config.PtrSize*2])) mem) { if v.Args[0].Op != OpLoad { - goto end83c0ff7760465a4184bad9e4b47f7be8 + goto end18c7acae3d96b30b9e5699194df4a687 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] @@ -356,7 +350,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v0 := v.Block.NewValue0(v.Line, OpAddPtr, TypeInvalid) v0.Type = ptr.Type v0.AddArg(ptr) - v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) v1.Type = config.Uintptr v1.AuxInt = config.PtrSize * 2 v0.AddArg(v1) @@ -364,16 +358,16 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v.AddArg(mem) return true } - goto end83c0ff7760465a4184bad9e4b47f7be8 - end83c0ff7760465a4184bad9e4b47f7be8: + goto end18c7acae3d96b30b9e5699194df4a687 + end18c7acae3d96b30b9e5699194df4a687: ; case OpSliceLen: // match: (SliceLen (Load ptr mem)) // cond: - // result: (Load (AddPtr ptr (Const [config.PtrSize])) mem) + // result: (Load (AddPtr ptr (ConstPtr [config.PtrSize])) mem) { if v.Args[0].Op != OpLoad { - goto end20579b262d017d875d579683996f0ef9 + goto end2dc65aee31bb0d91847032be777777d2 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] @@ -384,7 +378,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v0 := v.Block.NewValue0(v.Line, OpAddPtr, TypeInvalid) v0.Type = ptr.Type v0.AddArg(ptr) - v1 := v.Block.NewValue0(v.Line, OpConst, TypeInvalid) + v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) v1.Type = config.Uintptr v1.AuxInt = config.PtrSize v0.AddArg(v1) @@ -392,8 +386,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v.AddArg(mem) return true } - goto end20579b262d017d875d579683996f0ef9 - end20579b262d017d875d579683996f0ef9: + goto end2dc65aee31bb0d91847032be777777d2 + end2dc65aee31bb0d91847032be777777d2: ; case OpSlicePtr: // match: (SlicePtr (Load ptr mem)) @@ -573,19 +567,19 @@ func rewriteBlockgeneric(b *Block) bool { goto endebe19c1c3c3bec068cdb2dd29ef57f96 endebe19c1c3c3bec068cdb2dd29ef57f96: ; - // match: (If (Const {c}) yes no) + // match: (If (ConstBool {c}) yes no) // cond: c.(bool) // result: (Plain nil yes) { v := b.Control - if v.Op != OpConst { - goto end915e334b6388fed7d63e09aa69ecb05c + if v.Op != OpConstBool { + goto end9ff0273f9b1657f4afc287562ca889f0 } c := v.Aux yes := b.Succs[0] no := b.Succs[1] if !(c.(bool)) { - goto end915e334b6388fed7d63e09aa69ecb05c + goto end9ff0273f9b1657f4afc287562ca889f0 } v.Block.Func.removePredecessor(b, no) b.Kind = BlockPlain @@ -594,22 +588,22 @@ func rewriteBlockgeneric(b *Block) bool { b.Succs[0] = yes return true } - goto end915e334b6388fed7d63e09aa69ecb05c - end915e334b6388fed7d63e09aa69ecb05c: + goto end9ff0273f9b1657f4afc287562ca889f0 + end9ff0273f9b1657f4afc287562ca889f0: ; - // match: (If (Const {c}) yes no) + // match: (If (ConstBool {c}) yes no) // cond: !c.(bool) // result: (Plain nil no) { v := b.Control - if v.Op != OpConst { - goto end6452ee3a5bb02c708bddc3181c3ea3cb + if v.Op != OpConstBool { + goto endf401a4553c3c7c6bed64801da7bba076 } c := v.Aux yes := b.Succs[0] no := b.Succs[1] if !(!c.(bool)) { - goto end6452ee3a5bb02c708bddc3181c3ea3cb + goto endf401a4553c3c7c6bed64801da7bba076 } v.Block.Func.removePredecessor(b, yes) b.Kind = BlockPlain @@ -618,8 +612,8 @@ func rewriteBlockgeneric(b *Block) bool { b.Succs[0] = no return true } - goto end6452ee3a5bb02c708bddc3181c3ea3cb - end6452ee3a5bb02c708bddc3181c3ea3cb: + goto endf401a4553c3c7c6bed64801da7bba076 + endf401a4553c3c7c6bed64801da7bba076: } return false } diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go index 3a89483a9a..e724871bd0 100644 --- a/src/cmd/compile/internal/ssa/schedule_test.go +++ b/src/cmd/compile/internal/ssa/schedule_test.go @@ -12,8 +12,8 @@ func TestSchedule(t *testing.T) { Fun(c, "entry", Bloc("entry", Valu("mem0", OpArg, TypeMem, 0, ".mem"), - Valu("ptr", OpConst, TypeInt64, 0xABCD, nil), - Valu("v", OpConst, TypeInt64, 12, nil), + Valu("ptr", OpConst64, TypeInt64, 0xABCD, nil), + Valu("v", OpConst64, TypeInt64, 12, nil), Valu("mem1", OpStore, TypeMem, 0, nil, "ptr", "v", "mem0"), Valu("mem2", OpStore, TypeMem, 0, nil, "ptr", "v", "mem1"), Valu("mem3", OpStore, TypeInt64, 0, nil, "ptr", "sum", "mem2"), diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index cde48d355a..c32e48d93f 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -33,7 +33,7 @@ func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun { Valu("argptr", OpOffPtr, ptyp, 8, nil, "SP"), Valu("resptr", OpOffPtr, ptyp, 16, nil, "SP"), Valu("load", OpLoad, typ, 0, nil, "argptr", "mem"), - Valu("c", OpConst, TypeUInt64, amount, nil), + Valu("c", OpConst64, TypeUInt64, amount, nil), Valu("shift", op, typ, 0, nil, "load", "c"), Valu("store", OpStore, TypeMem, 0, nil, "resptr", "shift", "mem"), Exit("store"))) -- cgit v1.3 From 85e0329fbc03df4165550611f3724d9ebcaa34a8 Mon Sep 17 00:00:00 2001 From: Josh Bleecher Snyder Date: Thu, 30 Jul 2015 11:03:05 -0700 Subject: [dev.ssa] cmd/compile: move most types outside SSA The only types that remain in the ssa package are special compiler-only types. Change-Id: If957abf128ec0778910d67666c297f97f183b7ee Reviewed-on: https://go-review.googlesource.com/12933 Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/ssa.go | 52 +++++++++----- src/cmd/compile/internal/ssa/config.go | 36 ++++++---- src/cmd/compile/internal/ssa/deadcode_test.go | 8 +-- src/cmd/compile/internal/ssa/deadstore_test.go | 6 +- src/cmd/compile/internal/ssa/dom_test.go | 16 ++--- src/cmd/compile/internal/ssa/export_test.go | 20 ++++++ src/cmd/compile/internal/ssa/func_test.go | 4 +- src/cmd/compile/internal/ssa/gen/AMD64.rules | 12 ++-- src/cmd/compile/internal/ssa/gen/generic.rules | 16 ++--- src/cmd/compile/internal/ssa/rewriteAMD64.go | 60 ++++++++-------- src/cmd/compile/internal/ssa/rewritegeneric.go | 98 +++++++++++++------------- src/cmd/compile/internal/ssa/schedule_test.go | 2 +- src/cmd/compile/internal/ssa/shift_test.go | 2 +- src/cmd/compile/internal/ssa/type.go | 67 ++++++------------ src/cmd/compile/internal/ssa/type_test.go | 55 +++++++++++++++ 15 files changed, 262 insertions(+), 192 deletions(-) create mode 100644 src/cmd/compile/internal/ssa/type_test.go (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index c292e4e014..4db33a84a7 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -67,8 +67,8 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { s.labels = map[string]*ssaLabel{} s.labeledNodes = map[*Node]*ssaLabel{} s.startmem = s.entryNewValue0(ssa.OpArg, ssa.TypeMem) - s.sp = s.entryNewValue0(ssa.OpSP, s.config.Uintptr) // TODO: use generic pointer type (unsafe.Pointer?) instead - s.sb = s.entryNewValue0(ssa.OpSB, s.config.Uintptr) + s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead + s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR]) // Generate addresses of local declarations s.decladdrs = map[*Node]*ssa.Value{} @@ -90,8 +90,8 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { } } // nodfp is a special argument which is the function's FP. - aux := &ssa.ArgSymbol{Typ: s.config.Uintptr, Offset: 0, Sym: nodfp.Sym} - s.decladdrs[nodfp] = s.entryNewValue1A(ssa.OpAddr, s.config.Uintptr, aux, s.sp) + aux := &ssa.ArgSymbol{Typ: Types[TUINTPTR], Offset: 0, Sym: nodfp.Sym} + s.decladdrs[nodfp] = s.entryNewValue1A(ssa.OpAddr, Types[TUINTPTR], aux, s.sp) // Convert the AST-based IR to the SSA-based IR s.startBlock(s.f.Entry) @@ -1131,7 +1131,7 @@ func (s *state) expr(n *Node) *ssa.Value { case OLT, OEQ, ONE, OLE, OGE, OGT: a := s.expr(n.Left) b := s.expr(n.Right) - return s.newValue2(s.ssaOp(n.Op, n.Left.Type), ssa.TypeBool, a, b) + return s.newValue2(s.ssaOp(n.Op, n.Left.Type), Types[TBOOL], a, b) case OADD, OAND, OMUL, OOR, OSUB, OXOR: a := s.expr(n.Left) b := s.expr(n.Right) @@ -1209,7 +1209,7 @@ func (s *state) expr(n *Node) *ssa.Value { case ODOTPTR: p := s.expr(n.Left) s.nilCheck(p) - p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(s.config.Uintptr, n.Xoffset)) + p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(Types[TUINTPTR], n.Xoffset)) return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) case OINDEX: @@ -1220,10 +1220,10 @@ func (s *state) expr(n *Node) *ssa.Value { var elemtype *Type var len *ssa.Value if n.Left.Type.IsString() { - len = s.newValue1(ssa.OpStringLen, s.config.Int, a) + len = s.newValue1(ssa.OpStringLen, Types[TINT], a) elemtype = Types[TUINT8] } else { - len = s.constInt(s.config.Int, n.Left.Type.Bound) + len = s.constInt(Types[TINT], n.Left.Type.Bound) elemtype = n.Left.Type.Type } s.boundsCheck(i, len) @@ -1240,11 +1240,11 @@ func (s *state) expr(n *Node) *ssa.Value { if n.Op == OCAP { op = ssa.OpSliceCap } - return s.newValue1(op, s.config.Int, s.expr(n.Left)) + return s.newValue1(op, Types[TINT], s.expr(n.Left)) case n.Left.Type.IsString(): // string; not reachable for OCAP - return s.newValue1(ssa.OpStringLen, s.config.Int, s.expr(n.Left)) + return s.newValue1(ssa.OpStringLen, Types[TINT], s.expr(n.Left)) default: // array - return s.constInt(s.config.Int, n.Left.Type.Bound) + return s.constInt(Types[TINT], n.Left.Type.Bound) } case OCALLFUNC, OCALLMETH: @@ -1281,7 +1281,7 @@ func (s *state) expr(n *Node) *ssa.Value { if static { call = s.newValue1A(ssa.OpStaticCall, ssa.TypeMem, left.Sym, s.mem()) } else { - entry := s.newValue2(ssa.OpLoad, s.config.Uintptr, closure, s.mem()) + entry := s.newValue2(ssa.OpLoad, Types[TUINTPTR], closure, s.mem()) call = s.newValue3(ssa.OpClosureCall, ssa.TypeMem, entry, closure, s.mem()) } dowidth(left.Type) @@ -1418,7 +1418,7 @@ func (s *state) addr(n *Node) *ssa.Value { a := s.expr(n.Left) i := s.expr(n.Right) i = s.extendIndex(i) - len := s.newValue1(ssa.OpSliceLen, s.config.Uintptr, a) + len := s.newValue1(ssa.OpSliceLen, Types[TUINTPTR], a) s.boundsCheck(i, len) p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a) return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i) @@ -1426,7 +1426,7 @@ func (s *state) addr(n *Node) *ssa.Value { a := s.addr(n.Left) i := s.expr(n.Right) i = s.extendIndex(i) - len := s.constInt(s.config.Int, n.Left.Type.Bound) + len := s.constInt(Types[TINT], n.Left.Type.Bound) s.boundsCheck(i, len) return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i) } @@ -1436,11 +1436,11 @@ func (s *state) addr(n *Node) *ssa.Value { return p case ODOT: p := s.addr(n.Left) - return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(s.config.Uintptr, n.Xoffset)) + return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(Types[TUINTPTR], n.Xoffset)) case ODOTPTR: p := s.expr(n.Left) s.nilCheck(p) - return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(s.config.Uintptr, n.Xoffset)) + return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(Types[TUINTPTR], n.Xoffset)) default: s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0)) return nil @@ -1477,7 +1477,7 @@ func canSSA(n *Node) bool { // Used only for automatically inserted nil checks, // not for user code like 'x != nil'. func (s *state) nilCheck(ptr *ssa.Value) { - c := s.newValue1(ssa.OpIsNonNil, ssa.TypeBool, ptr) + c := s.newValue1(ssa.OpIsNonNil, Types[TBOOL], ptr) b := s.endBlock() b.Kind = ssa.BlockIf b.Control = c @@ -1496,7 +1496,7 @@ func (s *state) boundsCheck(idx, len *ssa.Value) { // TODO: if index is 64-bit and we're compiling to 32-bit, check that high 32 bits are zero. // bounds check - cmp := s.newValue2(ssa.OpIsInBounds, ssa.TypeBool, idx, len) + cmp := s.newValue2(ssa.OpIsInBounds, Types[TBOOL], idx, len) b := s.endBlock() b.Kind = ssa.BlockIf b.Control = cmp @@ -2288,7 +2288,7 @@ func (s *state) extendIndex(v *ssa.Value) *ssa.Value { s.Fatalf("bad unsigned index extension %s", v.Type) } } - return s.newValue1(op, s.config.Uintptr, v) + return s.newValue1(op, Types[TUINTPTR], v) } // ssaRegToReg maps ssa register numbers to obj register numbers. @@ -2374,6 +2374,20 @@ type ssaExport struct { mustImplement bool } +func (s *ssaExport) TypeBool() ssa.Type { return Types[TBOOL] } +func (s *ssaExport) TypeInt8() ssa.Type { return Types[TINT8] } +func (s *ssaExport) TypeInt16() ssa.Type { return Types[TINT16] } +func (s *ssaExport) TypeInt32() ssa.Type { return Types[TINT32] } +func (s *ssaExport) TypeInt64() ssa.Type { return Types[TINT64] } +func (s *ssaExport) TypeUInt8() ssa.Type { return Types[TUINT8] } +func (s *ssaExport) TypeUInt16() ssa.Type { return Types[TUINT16] } +func (s *ssaExport) TypeUInt32() ssa.Type { return Types[TUINT32] } +func (s *ssaExport) TypeUInt64() ssa.Type { return Types[TUINT64] } +func (s *ssaExport) TypeInt() ssa.Type { return Types[TINT] } +func (s *ssaExport) TypeUintptr() ssa.Type { return Types[TUINTPTR] } +func (s *ssaExport) TypeString() ssa.Type { return Types[TSTRING] } +func (s *ssaExport) TypeBytePtr() ssa.Type { return Ptrto(Types[TUINT8]) } + // StringData returns a symbol (a *Sym wrapped in an interface) which // is the data component of a global string constant containing s. func (*ssaExport) StringData(s string) interface{} { diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index cabf62e463..8aea59d13c 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -5,11 +5,9 @@ package ssa type Config struct { - arch string // "amd64", etc. - IntSize int64 // 4 or 8 - PtrSize int64 // 4 or 8 - Uintptr Type // pointer arithmetic type - Int Type + arch string // "amd64", etc. + IntSize int64 // 4 or 8 + PtrSize int64 // 4 or 8 lowerBlock func(*Block) bool // lowering function lowerValue func(*Value, *Config) bool // lowering function fe Frontend // callbacks into compiler frontend @@ -17,7 +15,25 @@ type Config struct { // TODO: more stuff. Compiler flags of interest, ... } +type TypeSource interface { + TypeBool() Type + TypeInt8() Type + TypeInt16() Type + TypeInt32() Type + TypeInt64() Type + TypeUInt8() Type + TypeUInt16() Type + TypeUInt32() Type + TypeUInt64() Type + TypeInt() Type + TypeUintptr() Type + TypeString() Type + TypeBytePtr() Type // TODO: use unsafe.Pointer instead? +} + type Frontend interface { + TypeSource + // StringData returns a symbol pointing to the given string's contents. StringData(string) interface{} // returns *gc.Sym @@ -50,16 +66,6 @@ func NewConfig(arch string, fe Frontend) *Config { fe.Unimplementedf("arch %s not implemented", arch) } - // cache the frequently-used types in the config - c.Uintptr = TypeUInt32 - c.Int = TypeInt32 - if c.PtrSize == 8 { - c.Uintptr = TypeUInt64 - } - if c.IntSize == 8 { - c.Int = TypeInt64 - } - return c } diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index 9ec8959571..ef42d74f4d 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -7,7 +7,7 @@ package ssa import "testing" func TestDeadLoop(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -37,7 +37,7 @@ func TestDeadLoop(t *testing.T) { } func TestDeadValue(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -60,7 +60,7 @@ func TestDeadValue(t *testing.T) { } func TestNeverTaken(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("cond", OpConstBool, TypeBool, 0, false), @@ -95,7 +95,7 @@ func TestNeverTaken(t *testing.T) { } func TestNestedDeadBlocks(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go index 5b318eb2d2..8c0a875cad 100644 --- a/src/cmd/compile/internal/ssa/deadstore_test.go +++ b/src/cmd/compile/internal/ssa/deadstore_test.go @@ -9,7 +9,7 @@ import ( ) func TestDeadStore(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", @@ -36,7 +36,7 @@ func TestDeadStore(t *testing.T) { } func TestDeadStorePhi(t *testing.T) { // make sure we don't get into an infinite loop with phi values. - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", @@ -62,7 +62,7 @@ func TestDeadStoreTypes(t *testing.T) { // stronger restriction, that one store can't shadow another unless the // types of the address fields are identical (where identicalness is // decided by the CSE pass). - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) t1 := &TypeImpl{Size_: 8, Ptr: true, Name: "t1"} t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"} fun := Fun(c, "entry", diff --git a/src/cmd/compile/internal/ssa/dom_test.go b/src/cmd/compile/internal/ssa/dom_test.go index 1f3124167a..6cd2ff440c 100644 --- a/src/cmd/compile/internal/ssa/dom_test.go +++ b/src/cmd/compile/internal/ssa/dom_test.go @@ -220,7 +220,7 @@ func verifyDominators(t *testing.T, fut fun, domFn domFunc, doms map[string]stri } func TestDominatorsSingleBlock(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -235,7 +235,7 @@ func TestDominatorsSingleBlock(t *testing.T) { } func TestDominatorsSimple(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -263,7 +263,7 @@ func TestDominatorsSimple(t *testing.T) { } func TestDominatorsMultPredFwd(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -291,7 +291,7 @@ func TestDominatorsMultPredFwd(t *testing.T) { } func TestDominatorsDeadCode(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -314,7 +314,7 @@ func TestDominatorsDeadCode(t *testing.T) { } func TestDominatorsMultPredRev(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -342,7 +342,7 @@ func TestDominatorsMultPredRev(t *testing.T) { } func TestDominatorsMultPred(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -370,7 +370,7 @@ func TestDominatorsMultPred(t *testing.T) { } func TestPostDominators(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), @@ -396,7 +396,7 @@ func TestPostDominators(t *testing.T) { } func TestInfiniteLoop(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) // note lack of an exit block fun := Fun(c, "entry", Bloc("entry", diff --git a/src/cmd/compile/internal/ssa/export_test.go b/src/cmd/compile/internal/ssa/export_test.go index d13729efbf..d2e8216b5d 100644 --- a/src/cmd/compile/internal/ssa/export_test.go +++ b/src/cmd/compile/internal/ssa/export_test.go @@ -11,6 +11,12 @@ var PrintFunc = printFunc var Opt = opt var Deadcode = deadcode +func testConfig(t *testing.T) *Config { + return NewConfig("amd64", DummyFrontend{t}) +} + +// DummyFrontend is a test-only frontend. +// It assumes 64 bit integers and pointers. type DummyFrontend struct { t testing.TB } @@ -22,3 +28,17 @@ func (DummyFrontend) StringData(s string) interface{} { func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) } func (d DummyFrontend) Fatalf(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } func (d DummyFrontend) Unimplementedf(msg string, args ...interface{}) { d.t.Fatalf(msg, args...) } + +func (d DummyFrontend) TypeBool() Type { return TypeBool } +func (d DummyFrontend) TypeInt8() Type { return TypeInt8 } +func (d DummyFrontend) TypeInt16() Type { return TypeInt16 } +func (d DummyFrontend) TypeInt32() Type { return TypeInt32 } +func (d DummyFrontend) TypeInt64() Type { return TypeInt64 } +func (d DummyFrontend) TypeUInt8() Type { return TypeUInt8 } +func (d DummyFrontend) TypeUInt16() Type { return TypeUInt16 } +func (d DummyFrontend) TypeUInt32() Type { return TypeUInt32 } +func (d DummyFrontend) TypeUInt64() Type { return TypeUInt64 } +func (d DummyFrontend) TypeInt() Type { return TypeInt64 } +func (d DummyFrontend) TypeUintptr() Type { return TypeUInt64 } +func (d DummyFrontend) TypeString() Type { panic("unimplemented") } +func (d DummyFrontend) TypeBytePtr() Type { return TypeBytePtr } diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index dda96317fe..4bdc84bd4c 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -262,7 +262,7 @@ func addEdge(b, c *Block) { } func TestArgs(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", Valu("a", OpConst64, TypeInt64, 14, nil), @@ -282,7 +282,7 @@ func TestArgs(t *testing.T) { } func TestEquiv(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) equivalentCases := []struct{ f, g fun }{ // simple case { diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 1630e13213..d0f5e5b073 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -211,7 +211,7 @@ (IsNonNil p) -> (SETNE (TESTQ p p)) (IsInBounds idx len) -> (SETB (CMPQ idx len)) -(Move [size] dst src mem) -> (REPMOVSB dst src (MOVQconst [size]) mem) +(Move [size] dst src mem) -> (REPMOVSB dst src (MOVQconst [size]) mem) (Not x) -> (XORBconst [1] x) @@ -391,15 +391,15 @@ // lower Zero instructions with word sizes (Zero [0] _ mem) -> (Copy mem) -(Zero [1] destptr mem) -> (MOVBstore destptr (MOVBconst [0]) mem) -(Zero [2] destptr mem) -> (MOVWstore destptr (MOVWconst [0]) mem) -(Zero [4] destptr mem) -> (MOVLstore destptr (MOVLconst [0]) mem) -(Zero [8] destptr mem) -> (MOVQstore destptr (MOVQconst [0]) mem) +(Zero [1] destptr mem) -> (MOVBstore destptr (MOVBconst [0]) mem) +(Zero [2] destptr mem) -> (MOVWstore destptr (MOVWconst [0]) mem) +(Zero [4] destptr mem) -> (MOVLstore destptr (MOVLconst [0]) mem) +(Zero [8] destptr mem) -> (MOVQstore destptr (MOVQconst [0]) mem) // rewrite anything less than 4 words into a series of MOV[BWLQ] $0, ptr(off) instructions (Zero [size] destptr mem) && size < 4*8 -> (MOVXzero [size] destptr mem) // Use STOSQ to zero memory. Rewrite this into storing the words with REPSTOSQ and then filling in the remainder with linear moves -(Zero [size] destptr mem) && size >= 4*8 -> (Zero [size%8] (OffPtr [size-(size%8)] destptr) (REPSTOSQ destptr (MOVQconst [size/8]) mem)) +(Zero [size] destptr mem) && size >= 4*8 -> (Zero [size%8] (OffPtr [size-(size%8)] destptr) (REPSTOSQ destptr (MOVQconst [size/8]) mem)) // Absorb InvertFlags into branches. (LT (InvertFlags cmp) yes no) -> (GT cmp yes no) diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index 49c70af4cc..6a8952d6cb 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -29,8 +29,8 @@ // tear apart slices // TODO: anything that generates a slice needs to go in here. (SlicePtr (Load ptr mem)) -> (Load ptr mem) -(SliceLen (Load ptr mem)) -> (Load (AddPtr ptr (ConstPtr [config.PtrSize])) mem) -(SliceCap (Load ptr mem)) -> (Load (AddPtr ptr (ConstPtr [config.PtrSize*2])) mem) +(SliceLen (Load ptr mem)) -> (Load (AddPtr ptr (ConstPtr [config.PtrSize])) mem) +(SliceCap (Load ptr mem)) -> (Load (AddPtr ptr (ConstPtr [config.PtrSize*2])) mem) // slice and interface comparisons // the frontend ensures that we can only compare against nil @@ -38,13 +38,13 @@ (EqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (EqFat y x) (NeqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (NeqFat y x) // it suffices to check the first word (backing array for slices, dynamic type for interfaces) -(EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load ptr mem) (ConstPtr [0])) -(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load ptr mem) (ConstPtr [0])) +(EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load ptr mem) (ConstPtr [0])) +(NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load ptr mem) (ConstPtr [0])) // indexing operations // Note: bounds check has already been done (ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex ptr idx) mem) -(PtrIndex ptr idx) -> (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()]))) +(PtrIndex ptr idx) -> (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()]))) (StructSelect [idx] (Load ptr mem)) -> (Load (OffPtr [idx] ptr) mem) // big-object moves @@ -52,11 +52,11 @@ (Store dst (Load src mem) mem) && t.Size() > 8 -> (Move [t.Size()] dst src mem) // string ops -(ConstString {s}) -> (StringMake (Addr {config.fe.StringData(s.(string))} (SB )) (ConstPtr [int64(len(s.(string)))])) -(Load ptr mem) && t.IsString() -> (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) +(ConstString {s}) -> (StringMake (Addr {config.fe.StringData(s.(string))} (SB )) (ConstPtr [int64(len(s.(string)))])) +(Load ptr mem) && t.IsString() -> (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) (StringPtr (StringMake ptr _)) -> ptr (StringLen (StringMake _ len)) -> len -(Store dst str mem) && str.Type.IsString() -> (Store (OffPtr [config.PtrSize] dst) (StringLen str) (Store dst (StringPtr str) mem)) +(Store dst str mem) && str.Type.IsString() -> (Store (OffPtr [config.PtrSize] dst) (StringLen str) (Store dst (StringPtr str) mem)) (If (Not cond) yes no) -> (If cond no yes) (If (ConstBool {c}) yes no) && c.(bool) -> (Plain nil yes) diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index f06227e749..9e4f133f3b 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -3392,7 +3392,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { case OpMove: // match: (Move [size] dst src mem) // cond: - // result: (REPMOVSB dst src (MOVQconst [size]) mem) + // result: (REPMOVSB dst src (MOVQconst [size]) mem) { size := v.AuxInt dst := v.Args[0] @@ -3405,14 +3405,14 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.AddArg(dst) v.AddArg(src) v0 := v.Block.NewValue0(v.Line, OpAMD64MOVQconst, TypeInvalid) - v0.Type = TypeUInt64 + v0.Type = config.Frontend().TypeUInt64() v0.AuxInt = size v.AddArg(v0) v.AddArg(mem) return true } - goto end2aab774aedae2c616ee88bfa87cdf30e - end2aab774aedae2c616ee88bfa87cdf30e: + goto end4dd156b33beb9981378c91e46f055a56 + end4dd156b33beb9981378c91e46f055a56: ; case OpMul16: // match: (Mul16 x y) @@ -6919,10 +6919,10 @@ func rewriteValueAMD64(v *Value, config *Config) bool { ; // match: (Zero [1] destptr mem) // cond: - // result: (MOVBstore destptr (MOVBconst [0]) mem) + // result: (MOVBstore destptr (MOVBconst [0]) mem) { if v.AuxInt != 1 { - goto end16839f51d2e9cf9548f216848406bd97 + goto end56bcaef03cce4d15c03efff669bb5585 } destptr := v.Args[0] mem := v.Args[1] @@ -6932,21 +6932,21 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.resetArgs() v.AddArg(destptr) v0 := v.Block.NewValue0(v.Line, OpAMD64MOVBconst, TypeInvalid) - v0.Type = TypeInt8 + v0.Type = config.Frontend().TypeInt8() v0.AuxInt = 0 v.AddArg(v0) v.AddArg(mem) return true } - goto end16839f51d2e9cf9548f216848406bd97 - end16839f51d2e9cf9548f216848406bd97: + goto end56bcaef03cce4d15c03efff669bb5585 + end56bcaef03cce4d15c03efff669bb5585: ; // match: (Zero [2] destptr mem) // cond: - // result: (MOVWstore destptr (MOVWconst [0]) mem) + // result: (MOVWstore destptr (MOVWconst [0]) mem) { if v.AuxInt != 2 { - goto enddc4a090329efde9ca19983ad18174cbb + goto endf52f08f1f7b0ae220c4cfca6586a8586 } destptr := v.Args[0] mem := v.Args[1] @@ -6956,21 +6956,21 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.resetArgs() v.AddArg(destptr) v0 := v.Block.NewValue0(v.Line, OpAMD64MOVWconst, TypeInvalid) - v0.Type = TypeInt16 + v0.Type = config.Frontend().TypeInt16() v0.AuxInt = 0 v.AddArg(v0) v.AddArg(mem) return true } - goto enddc4a090329efde9ca19983ad18174cbb - enddc4a090329efde9ca19983ad18174cbb: + goto endf52f08f1f7b0ae220c4cfca6586a8586 + endf52f08f1f7b0ae220c4cfca6586a8586: ; // match: (Zero [4] destptr mem) // cond: - // result: (MOVLstore destptr (MOVLconst [0]) mem) + // result: (MOVLstore destptr (MOVLconst [0]) mem) { if v.AuxInt != 4 { - goto end365a027b67399ad8d5d2d5eca847f7d8 + goto end41c91e0c7a23e233de77812b5264fd10 } destptr := v.Args[0] mem := v.Args[1] @@ -6980,21 +6980,21 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.resetArgs() v.AddArg(destptr) v0 := v.Block.NewValue0(v.Line, OpAMD64MOVLconst, TypeInvalid) - v0.Type = TypeInt32 + v0.Type = config.Frontend().TypeInt32() v0.AuxInt = 0 v.AddArg(v0) v.AddArg(mem) return true } - goto end365a027b67399ad8d5d2d5eca847f7d8 - end365a027b67399ad8d5d2d5eca847f7d8: + goto end41c91e0c7a23e233de77812b5264fd10 + end41c91e0c7a23e233de77812b5264fd10: ; // match: (Zero [8] destptr mem) // cond: - // result: (MOVQstore destptr (MOVQconst [0]) mem) + // result: (MOVQstore destptr (MOVQconst [0]) mem) { if v.AuxInt != 8 { - goto end5808a5e9c68555a82c3514db39017e56 + goto end157ad586af643d8dac6cc84a776000ca } destptr := v.Args[0] mem := v.Args[1] @@ -7004,14 +7004,14 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.resetArgs() v.AddArg(destptr) v0 := v.Block.NewValue0(v.Line, OpAMD64MOVQconst, TypeInvalid) - v0.Type = TypeInt64 + v0.Type = config.Frontend().TypeInt64() v0.AuxInt = 0 v.AddArg(v0) v.AddArg(mem) return true } - goto end5808a5e9c68555a82c3514db39017e56 - end5808a5e9c68555a82c3514db39017e56: + goto end157ad586af643d8dac6cc84a776000ca + end157ad586af643d8dac6cc84a776000ca: ; // match: (Zero [size] destptr mem) // cond: size < 4*8 @@ -7037,13 +7037,13 @@ func rewriteValueAMD64(v *Value, config *Config) bool { ; // match: (Zero [size] destptr mem) // cond: size >= 4*8 - // result: (Zero [size%8] (OffPtr [size-(size%8)] destptr) (REPSTOSQ destptr (MOVQconst [size/8]) mem)) + // result: (Zero [size%8] (OffPtr [size-(size%8)] destptr) (REPSTOSQ destptr (MOVQconst [size/8]) mem)) { size := v.AuxInt destptr := v.Args[0] mem := v.Args[1] if !(size >= 4*8) { - goto endb3058a90f909821d5689fb358519828b + goto end84c39fe2e8d40e0042a10741a0ef16bd } v.Op = OpZero v.AuxInt = 0 @@ -7051,7 +7051,7 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v.resetArgs() v.AuxInt = size % 8 v0 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v0.Type = TypeUInt64 + v0.Type = config.Frontend().TypeUInt64() v0.AuxInt = size - (size % 8) v0.AddArg(destptr) v.AddArg(v0) @@ -7059,15 +7059,15 @@ func rewriteValueAMD64(v *Value, config *Config) bool { v1.Type = TypeMem v1.AddArg(destptr) v2 := v.Block.NewValue0(v.Line, OpAMD64MOVQconst, TypeInvalid) - v2.Type = TypeUInt64 + v2.Type = config.Frontend().TypeUInt64() v2.AuxInt = size / 8 v1.AddArg(v2) v1.AddArg(mem) v.AddArg(v1) return true } - goto endb3058a90f909821d5689fb358519828b - endb3058a90f909821d5689fb358519828b: + goto end84c39fe2e8d40e0042a10741a0ef16bd + end84c39fe2e8d40e0042a10741a0ef16bd: ; case OpZeroExt16to32: // match: (ZeroExt16to32 x) diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 8fa3b6ded1..7d889b89f1 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -79,7 +79,7 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpConstString: // match: (ConstString {s}) // cond: - // result: (StringMake (Addr {config.fe.StringData(s.(string))} (SB )) (ConstPtr [int64(len(s.(string)))])) + // result: (StringMake (Addr {config.fe.StringData(s.(string))} (SB )) (ConstPtr [int64(len(s.(string)))])) { s := v.Aux v.Op = OpStringMake @@ -87,20 +87,20 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v.Aux = nil v.resetArgs() v0 := v.Block.NewValue0(v.Line, OpAddr, TypeInvalid) - v0.Type = TypeBytePtr + v0.Type = config.Frontend().TypeBytePtr() v0.Aux = config.fe.StringData(s.(string)) v1 := v.Block.NewValue0(v.Line, OpSB, TypeInvalid) - v1.Type = config.Uintptr + v1.Type = config.Frontend().TypeUintptr() v0.AddArg(v1) v.AddArg(v0) v2 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) - v2.Type = config.Uintptr + v2.Type = config.Frontend().TypeUintptr() v2.AuxInt = int64(len(s.(string))) v.AddArg(v2) return true } - goto end1a01fc02fad8727f9a3b716cfdac3a44 - end1a01fc02fad8727f9a3b716cfdac3a44: + goto end68cc91679848c7c30bd8b0a8ed533843 + end68cc91679848c7c30bd8b0a8ed533843: ; case OpEqFat: // match: (EqFat x y) @@ -125,33 +125,33 @@ func rewriteValuegeneric(v *Value, config *Config) bool { ; // match: (EqFat (Load ptr mem) (ConstNil)) // cond: - // result: (EqPtr (Load ptr mem) (ConstPtr [0])) + // result: (EqPtr (Load ptr mem) (ConstPtr [0])) { if v.Args[0].Op != OpLoad { - goto end2597220d1792c84d362da7901d2065d2 + goto end540dc8dfbc66adcd3db2d7e819c534f6 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] if v.Args[1].Op != OpConstNil { - goto end2597220d1792c84d362da7901d2065d2 + goto end540dc8dfbc66adcd3db2d7e819c534f6 } v.Op = OpEqPtr v.AuxInt = 0 v.Aux = nil v.resetArgs() v0 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid) - v0.Type = config.Uintptr + v0.Type = config.Frontend().TypeUintptr() v0.AddArg(ptr) v0.AddArg(mem) v.AddArg(v0) v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) - v1.Type = config.Uintptr + v1.Type = config.Frontend().TypeUintptr() v1.AuxInt = 0 v.AddArg(v1) return true } - goto end2597220d1792c84d362da7901d2065d2 - end2597220d1792c84d362da7901d2065d2: + goto end540dc8dfbc66adcd3db2d7e819c534f6 + end540dc8dfbc66adcd3db2d7e819c534f6: ; case OpIsInBounds: // match: (IsInBounds (ConstPtr [c]) (ConstPtr [d])) @@ -179,27 +179,27 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpLoad: // match: (Load ptr mem) // cond: t.IsString() - // result: (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) + // result: (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) { t := v.Type ptr := v.Args[0] mem := v.Args[1] if !(t.IsString()) { - goto endce3ba169a57b8a9f6b12751d49b4e23a + goto end18afa4a6fdd6d0b92ed292840898c8f6 } v.Op = OpStringMake v.AuxInt = 0 v.Aux = nil v.resetArgs() v0 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid) - v0.Type = TypeBytePtr + v0.Type = config.Frontend().TypeBytePtr() v0.AddArg(ptr) v0.AddArg(mem) v.AddArg(v0) v1 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid) - v1.Type = config.Uintptr + v1.Type = config.Frontend().TypeUintptr() v2 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v2.Type = TypeBytePtr + v2.Type = config.Frontend().TypeBytePtr() v2.AuxInt = config.PtrSize v2.AddArg(ptr) v1.AddArg(v2) @@ -207,8 +207,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v.AddArg(v1) return true } - goto endce3ba169a57b8a9f6b12751d49b4e23a - endce3ba169a57b8a9f6b12751d49b4e23a: + goto end18afa4a6fdd6d0b92ed292840898c8f6 + end18afa4a6fdd6d0b92ed292840898c8f6: ; case OpMul64: // match: (Mul64 (Const64 [c]) (Const64 [d])) @@ -279,38 +279,38 @@ func rewriteValuegeneric(v *Value, config *Config) bool { ; // match: (NeqFat (Load ptr mem) (ConstNil)) // cond: - // result: (NeqPtr (Load ptr mem) (ConstPtr [0])) + // result: (NeqPtr (Load ptr mem) (ConstPtr [0])) { if v.Args[0].Op != OpLoad { - goto end03a0fc8dde062c55439174f70c19e6ce + goto end67d723bb0f39a5c897816abcf411e5cf } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] if v.Args[1].Op != OpConstNil { - goto end03a0fc8dde062c55439174f70c19e6ce + goto end67d723bb0f39a5c897816abcf411e5cf } v.Op = OpNeqPtr v.AuxInt = 0 v.Aux = nil v.resetArgs() v0 := v.Block.NewValue0(v.Line, OpLoad, TypeInvalid) - v0.Type = config.Uintptr + v0.Type = config.Frontend().TypeUintptr() v0.AddArg(ptr) v0.AddArg(mem) v.AddArg(v0) v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) - v1.Type = config.Uintptr + v1.Type = config.Frontend().TypeUintptr() v1.AuxInt = 0 v.AddArg(v1) return true } - goto end03a0fc8dde062c55439174f70c19e6ce - end03a0fc8dde062c55439174f70c19e6ce: + goto end67d723bb0f39a5c897816abcf411e5cf + end67d723bb0f39a5c897816abcf411e5cf: ; case OpPtrIndex: // match: (PtrIndex ptr idx) // cond: - // result: (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()]))) + // result: (AddPtr ptr (MulPtr idx (ConstPtr [t.Elem().Size()]))) { t := v.Type ptr := v.Args[0] @@ -321,25 +321,25 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v.resetArgs() v.AddArg(ptr) v0 := v.Block.NewValue0(v.Line, OpMulPtr, TypeInvalid) - v0.Type = config.Uintptr + v0.Type = config.Frontend().TypeUintptr() v0.AddArg(idx) v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) - v1.Type = config.Uintptr + v1.Type = config.Frontend().TypeUintptr() v1.AuxInt = t.Elem().Size() v0.AddArg(v1) v.AddArg(v0) return true } - goto endfb3e605edaa4c3c0684c4fa9c8f150ee - endfb3e605edaa4c3c0684c4fa9c8f150ee: + goto endf7546737f42c76a99699f241d41f491a + endf7546737f42c76a99699f241d41f491a: ; case OpSliceCap: // match: (SliceCap (Load ptr mem)) // cond: - // result: (Load (AddPtr ptr (ConstPtr [config.PtrSize*2])) mem) + // result: (Load (AddPtr ptr (ConstPtr [config.PtrSize*2])) mem) { if v.Args[0].Op != OpLoad { - goto end18c7acae3d96b30b9e5699194df4a687 + goto end6696811bf6bd45e505d24c1a15c68e70 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] @@ -351,23 +351,23 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v0.Type = ptr.Type v0.AddArg(ptr) v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) - v1.Type = config.Uintptr + v1.Type = config.Frontend().TypeUintptr() v1.AuxInt = config.PtrSize * 2 v0.AddArg(v1) v.AddArg(v0) v.AddArg(mem) return true } - goto end18c7acae3d96b30b9e5699194df4a687 - end18c7acae3d96b30b9e5699194df4a687: + goto end6696811bf6bd45e505d24c1a15c68e70 + end6696811bf6bd45e505d24c1a15c68e70: ; case OpSliceLen: // match: (SliceLen (Load ptr mem)) // cond: - // result: (Load (AddPtr ptr (ConstPtr [config.PtrSize])) mem) + // result: (Load (AddPtr ptr (ConstPtr [config.PtrSize])) mem) { if v.Args[0].Op != OpLoad { - goto end2dc65aee31bb0d91847032be777777d2 + goto end9844ce3e290e81355493141e653e37d5 } ptr := v.Args[0].Args[0] mem := v.Args[0].Args[1] @@ -379,15 +379,15 @@ func rewriteValuegeneric(v *Value, config *Config) bool { v0.Type = ptr.Type v0.AddArg(ptr) v1 := v.Block.NewValue0(v.Line, OpConstPtr, TypeInvalid) - v1.Type = config.Uintptr + v1.Type = config.Frontend().TypeUintptr() v1.AuxInt = config.PtrSize v0.AddArg(v1) v.AddArg(v0) v.AddArg(mem) return true } - goto end2dc65aee31bb0d91847032be777777d2 - end2dc65aee31bb0d91847032be777777d2: + goto end9844ce3e290e81355493141e653e37d5 + end9844ce3e290e81355493141e653e37d5: ; case OpSlicePtr: // match: (SlicePtr (Load ptr mem)) @@ -443,40 +443,40 @@ func rewriteValuegeneric(v *Value, config *Config) bool { ; // match: (Store dst str mem) // cond: str.Type.IsString() - // result: (Store (OffPtr [config.PtrSize] dst) (StringLen str) (Store dst (StringPtr str) mem)) + // result: (Store (OffPtr [config.PtrSize] dst) (StringLen str) (Store dst (StringPtr str) mem)) { dst := v.Args[0] str := v.Args[1] mem := v.Args[2] if !(str.Type.IsString()) { - goto endb47e037c1e5ac54c3a41d53163d8aef6 + goto enddf0c5a150f4b4bf6715fd2bd4bb4cc20 } v.Op = OpStore v.AuxInt = 0 v.Aux = nil v.resetArgs() v0 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v0.Type = TypeBytePtr + v0.Type = config.Frontend().TypeBytePtr() v0.AuxInt = config.PtrSize v0.AddArg(dst) v.AddArg(v0) v1 := v.Block.NewValue0(v.Line, OpStringLen, TypeInvalid) - v1.Type = config.Uintptr + v1.Type = config.Frontend().TypeUintptr() v1.AddArg(str) v.AddArg(v1) v2 := v.Block.NewValue0(v.Line, OpStore, TypeInvalid) v2.Type = TypeMem v2.AddArg(dst) v3 := v.Block.NewValue0(v.Line, OpStringPtr, TypeInvalid) - v3.Type = TypeBytePtr + v3.Type = config.Frontend().TypeBytePtr() v3.AddArg(str) v2.AddArg(v3) v2.AddArg(mem) v.AddArg(v2) return true } - goto endb47e037c1e5ac54c3a41d53163d8aef6 - endb47e037c1e5ac54c3a41d53163d8aef6: + goto enddf0c5a150f4b4bf6715fd2bd4bb4cc20 + enddf0c5a150f4b4bf6715fd2bd4bb4cc20: ; case OpStringLen: // match: (StringLen (StringMake _ len)) diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go index e724871bd0..45f3dbcac5 100644 --- a/src/cmd/compile/internal/ssa/schedule_test.go +++ b/src/cmd/compile/internal/ssa/schedule_test.go @@ -7,7 +7,7 @@ package ssa import "testing" func TestSchedule(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) cases := []fun{ Fun(c, "entry", Bloc("entry", diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index 3bb26cda0b..fc26ab82ca 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -9,7 +9,7 @@ import ( ) func TestShiftConstAMD64(t *testing.T) { - c := NewConfig("amd64", DummyFrontend{t}) + c := testConfig(t) fun := makeConstShiftFunc(c, 18, OpLsh64x64, TypeUInt64) checkOpcodeCounts(t, fun.f, map[Op]int{OpAMD64SHLQconst: 1, OpAMD64CMPQconst: 0, OpAMD64ANDQconst: 0}) fun = makeConstShiftFunc(c, 66, OpLsh64x64, TypeUInt64) diff --git a/src/cmd/compile/internal/ssa/type.go b/src/cmd/compile/internal/ssa/type.go index 370137da71..d6e8384cf0 100644 --- a/src/cmd/compile/internal/ssa/type.go +++ b/src/cmd/compile/internal/ssa/type.go @@ -29,39 +29,29 @@ type Type interface { Equal(Type) bool } -// Stub implementation for now, until we are completely using ../gc:Type -type TypeImpl struct { - Size_ int64 - Align int64 - Boolean bool - Integer bool - Signed bool - Float bool - Ptr bool - string bool - +// Special compiler-only types. +type CompilerType struct { + Name string Memory bool Flags bool - - Name string } -func (t *TypeImpl) Size() int64 { return t.Size_ } -func (t *TypeImpl) Alignment() int64 { return t.Align } -func (t *TypeImpl) IsBoolean() bool { return t.Boolean } -func (t *TypeImpl) IsInteger() bool { return t.Integer } -func (t *TypeImpl) IsSigned() bool { return t.Signed } -func (t *TypeImpl) IsFloat() bool { return t.Float } -func (t *TypeImpl) IsPtr() bool { return t.Ptr } -func (t *TypeImpl) IsString() bool { return t.string } -func (t *TypeImpl) IsMemory() bool { return t.Memory } -func (t *TypeImpl) IsFlags() bool { return t.Flags } -func (t *TypeImpl) String() string { return t.Name } -func (t *TypeImpl) Elem() Type { panic("not implemented"); return nil } -func (t *TypeImpl) PtrTo() Type { panic("not implemented"); return nil } +func (t *CompilerType) Size() int64 { return 0 } +func (t *CompilerType) Alignment() int64 { return 0 } +func (t *CompilerType) IsBoolean() bool { return false } +func (t *CompilerType) IsInteger() bool { return false } +func (t *CompilerType) IsSigned() bool { return false } +func (t *CompilerType) IsFloat() bool { return false } +func (t *CompilerType) IsPtr() bool { return false } +func (t *CompilerType) IsString() bool { return false } +func (t *CompilerType) IsMemory() bool { return t.Memory } +func (t *CompilerType) IsFlags() bool { return t.Flags } +func (t *CompilerType) String() string { return t.Name } +func (t *CompilerType) Elem() Type { panic("not implemented") } +func (t *CompilerType) PtrTo() Type { panic("not implemented") } -func (t *TypeImpl) Equal(u Type) bool { - x, ok := u.(*TypeImpl) +func (t *CompilerType) Equal(u Type) bool { + x, ok := u.(*CompilerType) if !ok { return false } @@ -69,22 +59,7 @@ func (t *TypeImpl) Equal(u Type) bool { } var ( - // shortcuts for commonly used basic types - TypeInt8 = &TypeImpl{Size_: 1, Align: 1, Integer: true, Signed: true, Name: "int8"} - TypeInt16 = &TypeImpl{Size_: 2, Align: 2, Integer: true, Signed: true, Name: "int16"} - TypeInt32 = &TypeImpl{Size_: 4, Align: 4, Integer: true, Signed: true, Name: "int32"} - TypeInt64 = &TypeImpl{Size_: 8, Align: 8, Integer: true, Signed: true, Name: "int64"} - TypeUInt8 = &TypeImpl{Size_: 1, Align: 1, Integer: true, Name: "uint8"} - TypeUInt16 = &TypeImpl{Size_: 2, Align: 2, Integer: true, Name: "uint16"} - TypeUInt32 = &TypeImpl{Size_: 4, Align: 4, Integer: true, Name: "uint32"} - TypeUInt64 = &TypeImpl{Size_: 8, Align: 8, Integer: true, Name: "uint64"} - TypeBool = &TypeImpl{Size_: 1, Align: 1, Boolean: true, Name: "bool"} - //TypeString = types.Typ[types.String] - TypeBytePtr = &TypeImpl{Size_: 8, Align: 8, Ptr: true, Name: "*byte"} - - TypeInvalid = &TypeImpl{Name: "invalid"} - - // Additional compiler-only types go here. - TypeMem = &TypeImpl{Memory: true, Name: "mem"} - TypeFlags = &TypeImpl{Flags: true, Name: "flags"} + TypeInvalid = &CompilerType{Name: "invalid"} + TypeMem = &CompilerType{Name: "mem", Memory: true} + TypeFlags = &CompilerType{Name: "flags", Flags: true} ) diff --git a/src/cmd/compile/internal/ssa/type_test.go b/src/cmd/compile/internal/ssa/type_test.go new file mode 100644 index 0000000000..6f8dd6d937 --- /dev/null +++ b/src/cmd/compile/internal/ssa/type_test.go @@ -0,0 +1,55 @@ +// 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 + +// Stub implementation used for testing. +type TypeImpl struct { + Size_ int64 + Align int64 + Boolean bool + Integer bool + Signed bool + Float bool + Ptr bool + string bool + + Name string +} + +func (t *TypeImpl) Size() int64 { return t.Size_ } +func (t *TypeImpl) Alignment() int64 { return t.Align } +func (t *TypeImpl) IsBoolean() bool { return t.Boolean } +func (t *TypeImpl) IsInteger() bool { return t.Integer } +func (t *TypeImpl) IsSigned() bool { return t.Signed } +func (t *TypeImpl) IsFloat() bool { return t.Float } +func (t *TypeImpl) IsPtr() bool { return t.Ptr } +func (t *TypeImpl) IsString() bool { return t.string } +func (t *TypeImpl) IsMemory() bool { return false } +func (t *TypeImpl) IsFlags() bool { return false } +func (t *TypeImpl) String() string { return t.Name } +func (t *TypeImpl) Elem() Type { panic("not implemented") } +func (t *TypeImpl) PtrTo() Type { panic("not implemented") } + +func (t *TypeImpl) Equal(u Type) bool { + x, ok := u.(*TypeImpl) + if !ok { + return false + } + return x == t +} + +var ( + // shortcuts for commonly used basic types + TypeInt8 = &TypeImpl{Size_: 1, Align: 1, Integer: true, Signed: true, Name: "int8"} + TypeInt16 = &TypeImpl{Size_: 2, Align: 2, Integer: true, Signed: true, Name: "int16"} + TypeInt32 = &TypeImpl{Size_: 4, Align: 4, Integer: true, Signed: true, Name: "int32"} + TypeInt64 = &TypeImpl{Size_: 8, Align: 8, Integer: true, Signed: true, Name: "int64"} + TypeUInt8 = &TypeImpl{Size_: 1, Align: 1, Integer: true, Name: "uint8"} + TypeUInt16 = &TypeImpl{Size_: 2, Align: 2, Integer: true, Name: "uint16"} + TypeUInt32 = &TypeImpl{Size_: 4, Align: 4, Integer: true, Name: "uint32"} + TypeUInt64 = &TypeImpl{Size_: 8, Align: 8, Integer: true, Name: "uint64"} + TypeBool = &TypeImpl{Size_: 1, Align: 1, Boolean: true, Name: "bool"} + TypeBytePtr = &TypeImpl{Size_: 8, Align: 8, Ptr: true, Name: "*byte"} +) -- cgit v1.3 From 991036aef38cea57c2a7ef02220754d93799c489 Mon Sep 17 00:00:00 2001 From: Todd Neal Date: Thu, 3 Sep 2015 18:24:22 -0500 Subject: [dev.ssa] cmd/compile: store bools in AuxInt Store bools in AuxInt to reduce allocations. Change-Id: Ibd26db67fca5e1e2803f53d7ef094897968b704b Reviewed-on: https://go-review.googlesource.com/14276 Reviewed-by: Keith Randall --- src/cmd/compile/internal/gc/ssa.go | 24 +++- src/cmd/compile/internal/ssa/check.go | 5 + src/cmd/compile/internal/ssa/deadcode_test.go | 6 +- src/cmd/compile/internal/ssa/deadstore_test.go | 6 +- src/cmd/compile/internal/ssa/dom_test.go | 28 ++--- src/cmd/compile/internal/ssa/gen/AMD64.rules | 3 +- src/cmd/compile/internal/ssa/gen/generic.rules | 28 ++--- src/cmd/compile/internal/ssa/rewrite.go | 8 ++ src/cmd/compile/internal/ssa/rewriteAMD64.go | 35 ++---- src/cmd/compile/internal/ssa/rewritegeneric.go | 164 ++++++++++++------------- 10 files changed, 156 insertions(+), 151 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index c2ad49e954..340b7daa52 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -302,6 +302,11 @@ func (s *state) newValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value { return s.curBlock.NewValue0A(s.peekLine(), op, t, aux) } +// newValue0I adds a new value with no arguments and an auxint value to the current block. +func (s *state) newValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value { + return s.curBlock.NewValue0I(s.peekLine(), op, t, auxint) +} + // newValue1 adds a new value with one argument to the current block. func (s *state) newValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value { return s.curBlock.NewValue1(s.peekLine(), op, t, arg) @@ -337,16 +342,21 @@ func (s *state) newValue3I(op ssa.Op, t ssa.Type, aux int64, arg0, arg1, arg2 *s return s.curBlock.NewValue3I(s.peekLine(), op, t, aux, arg0, arg1, arg2) } -// entryNewValue adds a new value with no arguments to the entry block. +// entryNewValue0 adds a new value with no arguments to the entry block. func (s *state) entryNewValue0(op ssa.Op, t ssa.Type) *ssa.Value { return s.f.Entry.NewValue0(s.peekLine(), op, t) } -// entryNewValue adds a new value with no arguments and an aux value to the entry block. +// entryNewValue0A adds a new value with no arguments and an aux value to the entry block. func (s *state) entryNewValue0A(op ssa.Op, t ssa.Type, aux interface{}) *ssa.Value { return s.f.Entry.NewValue0A(s.peekLine(), op, t, aux) } +// entryNewValue0I adds a new value with no arguments and an auxint value to the entry block. +func (s *state) entryNewValue0I(op ssa.Op, t ssa.Type, auxint int64) *ssa.Value { + return s.f.Entry.NewValue0I(s.peekLine(), op, t, auxint) +} + // entryNewValue1 adds a new value with one argument to the entry block. func (s *state) entryNewValue1(op ssa.Op, t ssa.Type, arg *ssa.Value) *ssa.Value { return s.f.Entry.NewValue1(s.peekLine(), op, t, arg) @@ -635,7 +645,7 @@ func (s *state) stmt(n *Node) { if n.Left != nil { cond = s.expr(n.Left) } else { - cond = s.entryNewValue0A(ssa.OpConstBool, Types[TBOOL], true) + cond = s.entryNewValue0I(ssa.OpConstBool, Types[TBOOL], 1) // 1 = true } b = s.endBlock() b.Kind = ssa.BlockIf @@ -1103,7 +1113,11 @@ func (s *state) expr(n *Node) *ssa.Value { case CTSTR: return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U) case CTBOOL: - return s.entryNewValue0A(ssa.OpConstBool, n.Type, n.Val().U) + if n.Val().U.(bool) { + return s.entryNewValue0I(ssa.OpConstBool, n.Type, 1) // 1 = true + } else { + return s.entryNewValue0I(ssa.OpConstBool, n.Type, 0) // 0 = false + } case CTNIL: t := n.Type switch { @@ -1882,7 +1896,7 @@ func (s *state) zeroVal(t *Type) *ssa.Value { case t.IsPtr(): return s.entryNewValue0(ssa.OpConstNil, t) case t.IsBoolean(): - return s.entryNewValue0A(ssa.OpConstBool, t, false) // TODO: store bools as 0/1 in AuxInt? + return s.entryNewValue0I(ssa.OpConstBool, t, 0) // 0 = false case t.IsInterface(): return s.entryNewValue0(ssa.OpConstInterface, t) case t.IsSlice(): diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 68ba25a272..a7249a4c54 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -122,6 +122,11 @@ func checkFunc(f *Func) { } for _, v := range b.Values { + + if _, ok := v.Aux.(bool); ok { + f.Fatalf("value %v has a bool Aux value, should be AuxInt", v.LongString()) + } + for _, arg := range v.Args { if arg == nil { f.Fatalf("value %v has nil arg", v.LongString()) diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index ef42d74f4d..7f491c77f9 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -17,7 +17,7 @@ func TestDeadLoop(t *testing.T) { // dead loop Bloc("deadblock", // dead value in dead block - Valu("deadval", OpConstBool, TypeBool, 0, true), + Valu("deadval", OpConstBool, TypeBool, 1, nil), If("deadval", "deadblock", "exit"))) CheckFunc(fun.f) @@ -63,7 +63,7 @@ func TestNeverTaken(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("cond", OpConstBool, TypeBool, 0, false), + Valu("cond", OpConstBool, TypeBool, 0, nil), Valu("mem", OpArg, TypeMem, 0, ".mem"), If("cond", "then", "else")), Bloc("then", @@ -99,7 +99,7 @@ func TestNestedDeadBlocks(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("cond", OpConstBool, TypeBool, 0, false), + Valu("cond", OpConstBool, TypeBool, 0, nil), If("cond", "b2", "b4")), Bloc("b2", If("cond", "b3", "b4")), diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go index 0f295296bd..159ac4e439 100644 --- a/src/cmd/compile/internal/ssa/deadstore_test.go +++ b/src/cmd/compile/internal/ssa/deadstore_test.go @@ -14,7 +14,7 @@ func TestDeadStore(t *testing.T) { Bloc("entry", Valu("start", OpArg, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), - Valu("v", OpConstBool, TypeBool, 0, true), + Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr1", OpAddr, ptrType, 0, nil, "sb"), Valu("addr2", OpAddr, ptrType, 0, nil, "sb"), Valu("addr3", OpAddr, ptrType, 0, nil, "sb"), @@ -49,7 +49,7 @@ func TestDeadStorePhi(t *testing.T) { Bloc("entry", Valu("start", OpArg, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), - Valu("v", OpConstBool, TypeBool, 0, true), + Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr", OpAddr, ptrType, 0, nil, "sb"), Goto("loop")), Bloc("loop", @@ -76,7 +76,7 @@ func TestDeadStoreTypes(t *testing.T) { Bloc("entry", Valu("start", OpArg, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), - Valu("v", OpConstBool, TypeBool, 0, true), + Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr1", OpAddr, t1, 0, nil, "sb"), Valu("addr2", OpAddr, t2, 0, nil, "sb"), Valu("store1", OpStore, TypeMem, 1, nil, "addr1", "v", "start"), diff --git a/src/cmd/compile/internal/ssa/dom_test.go b/src/cmd/compile/internal/ssa/dom_test.go index e125907929..b46dcebc72 100644 --- a/src/cmd/compile/internal/ssa/dom_test.go +++ b/src/cmd/compile/internal/ssa/dom_test.go @@ -44,7 +44,7 @@ func genFwdBack(size int) []bloc { blocs = append(blocs, Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), ) @@ -74,7 +74,7 @@ func genManyPred(size int) []bloc { blocs = append(blocs, Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), ) @@ -85,15 +85,15 @@ func genManyPred(size int) []bloc { switch i % 3 { case 0: blocs = append(blocs, Bloc(blockn(i), - Valu("a", OpConstBool, TypeBool, 0, true), + Valu("a", OpConstBool, TypeBool, 1, nil), Goto(blockn(i+1)))) case 1: blocs = append(blocs, Bloc(blockn(i), - Valu("a", OpConstBool, TypeBool, 0, true), + Valu("a", OpConstBool, TypeBool, 1, nil), If("p", blockn(i+1), blockn(0)))) case 2: blocs = append(blocs, Bloc(blockn(i), - Valu("a", OpConstBool, TypeBool, 0, true), + Valu("a", OpConstBool, TypeBool, 1, nil), If("p", blockn(i+1), blockn(size)))) } } @@ -112,7 +112,7 @@ func genMaxPred(size int) []bloc { blocs = append(blocs, Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), ) @@ -137,14 +137,14 @@ func genMaxPredValue(size int) []bloc { blocs = append(blocs, Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), ) for i := 0; i < size; i++ { blocs = append(blocs, Bloc(blockn(i), - Valu("a", OpConstBool, TypeBool, 0, true), + Valu("a", OpConstBool, TypeBool, 1, nil), If("p", blockn(i+1), "exit"))) } @@ -267,7 +267,7 @@ func TestDominatorsMultPredFwd(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", If("p", "b", "c")), @@ -295,7 +295,7 @@ func TestDominatorsDeadCode(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, false), + Valu("p", OpConstBool, TypeBool, 0, nil), If("p", "b3", "b5")), Bloc("b2", Exit("mem")), Bloc("b3", Goto("b2")), @@ -320,7 +320,7 @@ func TestDominatorsMultPredRev(t *testing.T) { Goto("first")), Bloc("first", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 1, nil), Goto("a")), Bloc("a", If("p", "b", "first")), @@ -349,7 +349,7 @@ func TestDominatorsMultPred(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", If("p", "b", "c")), @@ -377,7 +377,7 @@ func TestPostDominators(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", If("p", "b", "c")), @@ -404,7 +404,7 @@ func TestInfiniteLoop(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("mem", OpArg, TypeMem, 0, ".mem"), - Valu("p", OpConstBool, TypeBool, 0, true), + Valu("p", OpConstBool, TypeBool, 1, nil), Goto("a")), Bloc("a", Goto("b")), diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index e8dc5cee72..8e1a8a09b1 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -303,8 +303,7 @@ (Const64F {val}) -> (MOVSDconst {val}) (ConstPtr [val]) -> (MOVQconst [val]) (ConstNil) -> (MOVQconst [0]) -(ConstBool {b}) && !b.(bool) -> (MOVBconst [0]) -(ConstBool {b}) && b.(bool) -> (MOVBconst [1]) +(ConstBool [b]) -> (MOVBconst [b]) (Addr {sym} base) -> (LEAQ {sym} base) diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index e0b49180f9..8d7b069c67 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -24,18 +24,18 @@ (AddPtr (ConstPtr [c]) (ConstPtr [d])) -> (ConstPtr [c+d]) (Mul64 (Const64 [c]) (Const64 [d])) -> (Const64 [c*d]) (MulPtr (ConstPtr [c]) (ConstPtr [d])) -> (ConstPtr [c*d]) -(IsInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool {inBounds32(c,d)}) -(IsInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool {inBounds64(c,d)}) -(IsInBounds (ConstPtr [c]) (ConstPtr [d])) && config.PtrSize == 4 -> (ConstBool {inBounds32(c,d)}) -(IsInBounds (ConstPtr [c]) (ConstPtr [d])) && config.PtrSize == 8 -> (ConstBool {inBounds64(c,d)}) -(Eq64 x x) -> (ConstBool {true}) -(Eq32 x x) -> (ConstBool {true}) -(Eq16 x x) -> (ConstBool {true}) -(Eq8 x x) -> (ConstBool {true}) -(Neq64 x x) -> (ConstBool {false}) -(Neq32 x x) -> (ConstBool {false}) -(Neq16 x x) -> (ConstBool {false}) -(Neq8 x x) -> (ConstBool {false}) +(IsInBounds (Const32 [c]) (Const32 [d])) -> (ConstBool [b2i(inBounds32(c,d))]) +(IsInBounds (Const64 [c]) (Const64 [d])) -> (ConstBool [b2i(inBounds64(c,d))]) +(IsInBounds (ConstPtr [c]) (ConstPtr [d])) && config.PtrSize == 4 -> (ConstBool [b2i(inBounds32(c,d))]) +(IsInBounds (ConstPtr [c]) (ConstPtr [d])) && config.PtrSize == 8 -> (ConstBool [b2i(inBounds64(c,d))]) +(Eq64 x x) -> (ConstBool [1]) +(Eq32 x x) -> (ConstBool [1]) +(Eq16 x x) -> (ConstBool [1]) +(Eq8 x x) -> (ConstBool [1]) +(Neq64 x x) -> (ConstBool [0]) +(Neq32 x x) -> (ConstBool [0]) +(Neq16 x x) -> (ConstBool [0]) +(Neq8 x x) -> (ConstBool [0]) // simplifications (Or64 x x) -> x @@ -177,5 +177,5 @@ (If (IsNonNil (GetG)) yes no) -> (First nil yes no) (If (Not cond) yes no) -> (If cond no yes) -(If (ConstBool {c}) yes no) && c.(bool) -> (First nil yes no) -(If (ConstBool {c}) yes no) && !c.(bool) -> (First nil no yes) +(If (ConstBool [c]) yes no) && c == 1 -> (First nil yes no) +(If (ConstBool [c]) yes no) && c == 0 -> (First nil no yes) diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index f2c8972c14..2742a5cc3b 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -162,3 +162,11 @@ func isPowerOfTwo(n int64) bool { func is32Bit(n int64) bool { return n == int64(int32(n)) } + +// b2i translates a boolean value to 0 or 1 for assigning to auxInt. +func b2i(b bool) int64 { + if b { + return 1 + } + return 0 +} diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 366a195a3d..f449892a8a 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -1624,41 +1624,20 @@ func rewriteValueAMD64(v *Value, config *Config) bool { end200524c722ed14ca935ba47f8f30327d: ; case OpConstBool: - // match: (ConstBool {b}) - // cond: !b.(bool) - // result: (MOVBconst [0]) - { - b := v.Aux - if !(!b.(bool)) { - goto end876159ea073d2dcefcc251667c1a7780 - } - v.Op = OpAMD64MOVBconst - v.AuxInt = 0 - v.Aux = nil - v.resetArgs() - v.AuxInt = 0 - return true - } - goto end876159ea073d2dcefcc251667c1a7780 - end876159ea073d2dcefcc251667c1a7780: - ; - // match: (ConstBool {b}) - // cond: b.(bool) - // result: (MOVBconst [1]) + // match: (ConstBool [b]) + // cond: + // result: (MOVBconst [b]) { - b := v.Aux - if !(b.(bool)) { - goto end0dacad3f7cad53905aad5303391447f6 - } + b := v.AuxInt v.Op = OpAMD64MOVBconst v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.AuxInt = 1 + v.AuxInt = b return true } - goto end0dacad3f7cad53905aad5303391447f6 - end0dacad3f7cad53905aad5303391447f6: + goto end6d919011283330dcbcb3826f0adc6793 + end6d919011283330dcbcb3826f0adc6793: ; case OpConstNil: // match: (ConstNil) diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index ca771d75ae..3a068058ee 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -354,78 +354,78 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpEq16: // match: (Eq16 x x) // cond: - // result: (ConstBool {true}) + // result: (ConstBool [1]) { x := v.Args[0] if v.Args[1] != x { - goto enda503589f9b617e708a5ad3ddb047809f + goto end0c0fe5fdfba3821add3448fd3f1fc6b7 } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = true + v.AuxInt = 1 return true } - goto enda503589f9b617e708a5ad3ddb047809f - enda503589f9b617e708a5ad3ddb047809f: + goto end0c0fe5fdfba3821add3448fd3f1fc6b7 + end0c0fe5fdfba3821add3448fd3f1fc6b7: ; case OpEq32: // match: (Eq32 x x) // cond: - // result: (ConstBool {true}) + // result: (ConstBool [1]) { x := v.Args[0] if v.Args[1] != x { - goto endc94ae3b97d0090257b02152e437b3e17 + goto end6da547ec4ee93d787434f3bda873e4a0 } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = true + v.AuxInt = 1 return true } - goto endc94ae3b97d0090257b02152e437b3e17 - endc94ae3b97d0090257b02152e437b3e17: + goto end6da547ec4ee93d787434f3bda873e4a0 + end6da547ec4ee93d787434f3bda873e4a0: ; case OpEq64: // match: (Eq64 x x) // cond: - // result: (ConstBool {true}) + // result: (ConstBool [1]) { x := v.Args[0] if v.Args[1] != x { - goto end4d21cead60174989467a9c8202dbb91d + goto endb1d471cc503ba8bb05440f01dbf33d81 } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = true + v.AuxInt = 1 return true } - goto end4d21cead60174989467a9c8202dbb91d - end4d21cead60174989467a9c8202dbb91d: + goto endb1d471cc503ba8bb05440f01dbf33d81 + endb1d471cc503ba8bb05440f01dbf33d81: ; case OpEq8: // match: (Eq8 x x) // cond: - // result: (ConstBool {true}) + // result: (ConstBool [1]) { x := v.Args[0] if v.Args[1] != x { - goto end73dce8bba164e4f4a1dd701bf8cfb362 + goto enda66da0d3e7e51624ee46527727c48a9a } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = true + v.AuxInt = 1 return true } - goto end73dce8bba164e4f4a1dd701bf8cfb362 - end73dce8bba164e4f4a1dd701bf8cfb362: + goto enda66da0d3e7e51624ee46527727c48a9a + enda66da0d3e7e51624ee46527727c48a9a: ; case OpEqFat: // match: (EqFat x y) @@ -521,97 +521,97 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpIsInBounds: // match: (IsInBounds (Const32 [c]) (Const32 [d])) // cond: - // result: (ConstBool {inBounds32(c,d)}) + // result: (ConstBool [b2i(inBounds32(c,d))]) { if v.Args[0].Op != OpConst32 { - goto endc3396bf88b56276e1691abe62811dba5 + goto endf0a2ecfe84b293de6ff0919e45d19d9d } c := v.Args[0].AuxInt if v.Args[1].Op != OpConst32 { - goto endc3396bf88b56276e1691abe62811dba5 + goto endf0a2ecfe84b293de6ff0919e45d19d9d } d := v.Args[1].AuxInt v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = inBounds32(c, d) + v.AuxInt = b2i(inBounds32(c, d)) return true } - goto endc3396bf88b56276e1691abe62811dba5 - endc3396bf88b56276e1691abe62811dba5: + goto endf0a2ecfe84b293de6ff0919e45d19d9d + endf0a2ecfe84b293de6ff0919e45d19d9d: ; // match: (IsInBounds (Const64 [c]) (Const64 [d])) // cond: - // result: (ConstBool {inBounds64(c,d)}) + // result: (ConstBool [b2i(inBounds64(c,d))]) { if v.Args[0].Op != OpConst64 { - goto end0b4b8178a54662835b00bfa503cf879a + goto end4b406f402c135f50f71effcc904ecb2b } c := v.Args[0].AuxInt if v.Args[1].Op != OpConst64 { - goto end0b4b8178a54662835b00bfa503cf879a + goto end4b406f402c135f50f71effcc904ecb2b } d := v.Args[1].AuxInt v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = inBounds64(c, d) + v.AuxInt = b2i(inBounds64(c, d)) return true } - goto end0b4b8178a54662835b00bfa503cf879a - end0b4b8178a54662835b00bfa503cf879a: + goto end4b406f402c135f50f71effcc904ecb2b + end4b406f402c135f50f71effcc904ecb2b: ; // match: (IsInBounds (ConstPtr [c]) (ConstPtr [d])) // cond: config.PtrSize == 4 - // result: (ConstBool {inBounds32(c,d)}) + // result: (ConstBool [b2i(inBounds32(c,d))]) { if v.Args[0].Op != OpConstPtr { - goto end2c6938f68a67e08dbd96edb1e693e549 + goto end4323278ec7a053034fcf7033697d7b3b } c := v.Args[0].AuxInt if v.Args[1].Op != OpConstPtr { - goto end2c6938f68a67e08dbd96edb1e693e549 + goto end4323278ec7a053034fcf7033697d7b3b } d := v.Args[1].AuxInt if !(config.PtrSize == 4) { - goto end2c6938f68a67e08dbd96edb1e693e549 + goto end4323278ec7a053034fcf7033697d7b3b } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = inBounds32(c, d) + v.AuxInt = b2i(inBounds32(c, d)) return true } - goto end2c6938f68a67e08dbd96edb1e693e549 - end2c6938f68a67e08dbd96edb1e693e549: + goto end4323278ec7a053034fcf7033697d7b3b + end4323278ec7a053034fcf7033697d7b3b: ; // match: (IsInBounds (ConstPtr [c]) (ConstPtr [d])) // cond: config.PtrSize == 8 - // result: (ConstBool {inBounds64(c,d)}) + // result: (ConstBool [b2i(inBounds64(c,d))]) { if v.Args[0].Op != OpConstPtr { - goto end84d6ae817944985f572ecaac51999d6c + goto endb550b8814df20b5eeda4f43cc94e902b } c := v.Args[0].AuxInt if v.Args[1].Op != OpConstPtr { - goto end84d6ae817944985f572ecaac51999d6c + goto endb550b8814df20b5eeda4f43cc94e902b } d := v.Args[1].AuxInt if !(config.PtrSize == 8) { - goto end84d6ae817944985f572ecaac51999d6c + goto endb550b8814df20b5eeda4f43cc94e902b } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = inBounds64(c, d) + v.AuxInt = b2i(inBounds64(c, d)) return true } - goto end84d6ae817944985f572ecaac51999d6c - end84d6ae817944985f572ecaac51999d6c: + goto endb550b8814df20b5eeda4f43cc94e902b + endb550b8814df20b5eeda4f43cc94e902b: ; case OpLoad: // match: (Load ptr mem) @@ -837,78 +837,78 @@ func rewriteValuegeneric(v *Value, config *Config) bool { case OpNeq16: // match: (Neq16 x x) // cond: - // result: (ConstBool {false}) + // result: (ConstBool [0]) { x := v.Args[0] if v.Args[1] != x { - goto end192755dd3c2be992e9d3deb53794a8d2 + goto ende76a50b524aeb16c7aeccf5f5cc60c06 } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = false + v.AuxInt = 0 return true } - goto end192755dd3c2be992e9d3deb53794a8d2 - end192755dd3c2be992e9d3deb53794a8d2: + goto ende76a50b524aeb16c7aeccf5f5cc60c06 + ende76a50b524aeb16c7aeccf5f5cc60c06: ; case OpNeq32: // match: (Neq32 x x) // cond: - // result: (ConstBool {false}) + // result: (ConstBool [0]) { x := v.Args[0] if v.Args[1] != x { - goto endeb23619fc85950a8df7b31126252c4dd + goto end3713a608cffd29b40ff7c3b3f2585cbb } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = false + v.AuxInt = 0 return true } - goto endeb23619fc85950a8df7b31126252c4dd - endeb23619fc85950a8df7b31126252c4dd: + goto end3713a608cffd29b40ff7c3b3f2585cbb + end3713a608cffd29b40ff7c3b3f2585cbb: ; case OpNeq64: // match: (Neq64 x x) // cond: - // result: (ConstBool {false}) + // result: (ConstBool [0]) { x := v.Args[0] if v.Args[1] != x { - goto endfc6eea780fb4056afb9e4287076da60c + goto end3601ad382705ea12b79d2008c1e5725c } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = false + v.AuxInt = 0 return true } - goto endfc6eea780fb4056afb9e4287076da60c - endfc6eea780fb4056afb9e4287076da60c: + goto end3601ad382705ea12b79d2008c1e5725c + end3601ad382705ea12b79d2008c1e5725c: ; case OpNeq8: // match: (Neq8 x x) // cond: - // result: (ConstBool {false}) + // result: (ConstBool [0]) { x := v.Args[0] if v.Args[1] != x { - goto endcccf700d93c6d57765b80f92f7b3fa81 + goto end09a0deaf3c42627d0d2d3efa96e30745 } v.Op = OpConstBool v.AuxInt = 0 v.Aux = nil v.resetArgs() - v.Aux = false + v.AuxInt = 0 return true } - goto endcccf700d93c6d57765b80f92f7b3fa81 - endcccf700d93c6d57765b80f92f7b3fa81: + goto end09a0deaf3c42627d0d2d3efa96e30745 + end09a0deaf3c42627d0d2d3efa96e30745: ; case OpNeqFat: // match: (NeqFat x y) @@ -1620,19 +1620,19 @@ func rewriteBlockgeneric(b *Block) bool { goto endebe19c1c3c3bec068cdb2dd29ef57f96 endebe19c1c3c3bec068cdb2dd29ef57f96: ; - // match: (If (ConstBool {c}) yes no) - // cond: c.(bool) + // match: (If (ConstBool [c]) yes no) + // cond: c == 1 // result: (First nil yes no) { v := b.Control if v.Op != OpConstBool { - goto end7a20763049489cdb40bb1eaa57d113d8 + goto endc58ecbb85af78c0d58bb232ca86b67a4 } - c := v.Aux + c := v.AuxInt yes := b.Succs[0] no := b.Succs[1] - if !(c.(bool)) { - goto end7a20763049489cdb40bb1eaa57d113d8 + if !(c == 1) { + goto endc58ecbb85af78c0d58bb232ca86b67a4 } b.Kind = BlockFirst b.Control = nil @@ -1640,22 +1640,22 @@ func rewriteBlockgeneric(b *Block) bool { b.Succs[1] = no return true } - goto end7a20763049489cdb40bb1eaa57d113d8 - end7a20763049489cdb40bb1eaa57d113d8: + goto endc58ecbb85af78c0d58bb232ca86b67a4 + endc58ecbb85af78c0d58bb232ca86b67a4: ; - // match: (If (ConstBool {c}) yes no) - // cond: !c.(bool) + // match: (If (ConstBool [c]) yes no) + // cond: c == 0 // result: (First nil no yes) { v := b.Control if v.Op != OpConstBool { - goto end3ecbf5b2cc1f0a08444d8ab1871a829c + goto end4c3e297e275dd7e2e67f8ccd348c4bb5 } - c := v.Aux + c := v.AuxInt yes := b.Succs[0] no := b.Succs[1] - if !(!c.(bool)) { - goto end3ecbf5b2cc1f0a08444d8ab1871a829c + if !(c == 0) { + goto end4c3e297e275dd7e2e67f8ccd348c4bb5 } b.Kind = BlockFirst b.Control = nil @@ -1664,8 +1664,8 @@ func rewriteBlockgeneric(b *Block) bool { b.Likely *= -1 return true } - goto end3ecbf5b2cc1f0a08444d8ab1871a829c - end3ecbf5b2cc1f0a08444d8ab1871a829c: + goto end4c3e297e275dd7e2e67f8ccd348c4bb5 + end4c3e297e275dd7e2e67f8ccd348c4bb5: } return false } -- cgit v1.3 From 02f4d0a130ba95d7a03418c3ef308d7d21b34af3 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Mon, 2 Nov 2015 08:10:26 -0800 Subject: [dev.ssa] cmd/compile: start arguments as spilled Declare a function's arguments as having already been spilled so their use just requires a restore. Allow spill locations to be portions of larger objects the stack. Required to load portions of compound input arguments. Rename the memory input to InputMem. Use Arg for the pre-spilled argument values. Change-Id: I8fe2a03ffbba1022d98bfae2052b376b96d32dda Reviewed-on: https://go-review.googlesource.com/16536 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: David Chase --- src/cmd/compile/internal/gc/pgen.go | 3 + src/cmd/compile/internal/gc/ssa.go | 54 +++++-- src/cmd/compile/internal/ssa/compile.go | 2 +- src/cmd/compile/internal/ssa/config.go | 2 +- src/cmd/compile/internal/ssa/deadcode.go | 34 ++-- src/cmd/compile/internal/ssa/deadcode_test.go | 8 +- src/cmd/compile/internal/ssa/deadstore_test.go | 6 +- src/cmd/compile/internal/ssa/decompose.go | 69 ++++++++- src/cmd/compile/internal/ssa/dom_test.go | 26 ++-- src/cmd/compile/internal/ssa/func.go | 7 +- src/cmd/compile/internal/ssa/func_test.go | 32 ++-- src/cmd/compile/internal/ssa/gen/generic.rules | 45 ++++-- src/cmd/compile/internal/ssa/gen/genericOps.go | 3 +- src/cmd/compile/internal/ssa/html.go | 4 + src/cmd/compile/internal/ssa/location.go | 14 +- src/cmd/compile/internal/ssa/lower.go | 2 +- src/cmd/compile/internal/ssa/nilcheck_test.go | 20 +-- src/cmd/compile/internal/ssa/opGen.go | 5 + src/cmd/compile/internal/ssa/print.go | 8 + src/cmd/compile/internal/ssa/regalloc.go | 10 ++ src/cmd/compile/internal/ssa/regalloc_test.go | 2 +- src/cmd/compile/internal/ssa/rewritegeneric.go | 206 +++++++++++++++++++++---- src/cmd/compile/internal/ssa/schedule_test.go | 2 +- src/cmd/compile/internal/ssa/shift_test.go | 2 +- src/cmd/compile/internal/ssa/stackalloc.go | 34 ++-- src/cmd/compile/internal/ssa/tighten.go | 4 +- src/runtime/runtime-gdb_test.go | 7 - 27 files changed, 470 insertions(+), 141 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/gc/pgen.go b/src/cmd/compile/internal/gc/pgen.go index 87e99df2e6..c8f2059543 100644 --- a/src/cmd/compile/internal/gc/pgen.go +++ b/src/cmd/compile/internal/gc/pgen.go @@ -484,6 +484,9 @@ func compile(fn *Node) { if ssafn != nil && usessa { genssa(ssafn, ptxt, gcargs, gclocals) + if Curfn.Func.Endlineno != 0 { + lineno = Curfn.Func.Endlineno + } return } Genlist(Curfn.Func.Enter) diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 5a8e43dedb..2c935b7247 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -97,7 +97,7 @@ func buildssa(fn *Node) (ssafn *ssa.Func, usessa bool) { // Allocate starting values s.labels = map[string]*ssaLabel{} s.labeledNodes = map[*Node]*ssaLabel{} - s.startmem = s.entryNewValue0(ssa.OpArg, ssa.TypeMem) + s.startmem = s.entryNewValue0(ssa.OpInitMem, ssa.TypeMem) s.sp = s.entryNewValue0(ssa.OpSP, Types[TUINTPTR]) // TODO: use generic pointer type (unsafe.Pointer?) instead s.sb = s.entryNewValue0(ssa.OpSB, Types[TUINTPTR]) @@ -3168,6 +3168,12 @@ func (s *state) lookupVarIncoming(b *ssa.Block, t ssa.Type, name *Node) *ssa.Val if name == &memVar { return s.startmem } + if canSSA(name) { + v := s.entryNewValue0A(ssa.OpArg, t, name) + // v starts with AuxInt == 0. + s.addNamedValue(name, v) + return v + } // variable is live at the entry block. Load it. addr := s.decladdrs[name] if addr == nil { @@ -3239,18 +3245,21 @@ func (s *state) addNamedValue(n *Node, v *ssa.Value) { // Don't track autotmp_ variables. return } - if n.Class == PPARAM || n.Class == PPARAMOUT { - // TODO: Remove this + if n.Class == PAUTO && (v.Type.IsString() || v.Type.IsSlice() || v.Type.IsInterface()) { + // TODO: can't handle auto compound objects with pointers yet. + // The live variable analysis barfs because we don't put VARDEF + // pseudos in the right place when we spill to these nodes. return } if n.Class == PAUTO && n.Xoffset != 0 { s.Fatalf("AUTO var with offset %s %d", n, n.Xoffset) } - values, ok := s.f.NamedValues[n] + loc := ssa.LocalSlot{N: n, Type: n.Type, Off: 0} + values, ok := s.f.NamedValues[loc] if !ok { - s.f.Names = append(s.f.Names, n) + s.f.Names = append(s.f.Names, loc) } - s.f.NamedValues[n] = append(values, v) + s.f.NamedValues[loc] = append(values, v) } // an unresolved branch @@ -3873,11 +3882,17 @@ func (s *genState) genValue(v *ssa.Value) { return } p := Prog(movSizeByType(v.Type)) - n := autoVar(v.Args[0]) + n, off := autoVar(v.Args[0]) p.From.Type = obj.TYPE_MEM - p.From.Name = obj.NAME_AUTO p.From.Node = n p.From.Sym = Linksym(n.Sym) + p.From.Offset = off + if n.Class == PPARAM { + p.From.Name = obj.NAME_PARAM + p.From.Offset += n.Xoffset + } else { + p.From.Name = obj.NAME_AUTO + } p.To.Type = obj.TYPE_REG p.To.Reg = regnum(v) @@ -3889,11 +3904,17 @@ func (s *genState) genValue(v *ssa.Value) { p := Prog(movSizeByType(v.Type)) p.From.Type = obj.TYPE_REG p.From.Reg = regnum(v.Args[0]) - n := autoVar(v) + n, off := autoVar(v) p.To.Type = obj.TYPE_MEM - p.To.Name = obj.NAME_AUTO p.To.Node = n p.To.Sym = Linksym(n.Sym) + p.To.Offset = off + if n.Class == PPARAM { + p.To.Name = obj.NAME_PARAM + p.To.Offset += n.Xoffset + } else { + p.To.Name = obj.NAME_AUTO + } case ssa.OpPhi: // just check to make sure regalloc and stackalloc did it right if v.Type.IsMemory() { @@ -3912,9 +3933,10 @@ func (s *genState) genValue(v *ssa.Value) { v.Fatalf("const value %v shouldn't have a location", v) } - case ssa.OpArg: + case ssa.OpInitMem: // memory arg needs no code - // TODO: check that only mem arg goes here. + case ssa.OpArg: + // input args need no code case ssa.OpAMD64LoweredGetClosurePtr: // Output is hardwired to DX only, // and DX contains the closure pointer on @@ -4476,9 +4498,11 @@ func regnum(v *ssa.Value) int16 { return ssaRegToReg[reg.(*ssa.Register).Num] } -// autoVar returns a *Node representing the auto variable assigned to v. -func autoVar(v *ssa.Value) *Node { - return v.Block.Func.RegAlloc[v.ID].(*ssa.LocalSlot).N.(*Node) +// autoVar returns a *Node and int64 representing the auto variable and offset within it +// where v should be spilled. +func autoVar(v *ssa.Value) (*Node, int64) { + loc := v.Block.Func.RegAlloc[v.ID].(ssa.LocalSlot) + return loc.N.(*Node), loc.Off } // ssaExport exports a bunch of compiler services for the ssa backend. diff --git a/src/cmd/compile/internal/ssa/compile.go b/src/cmd/compile/internal/ssa/compile.go index af672eea99..01238f24ca 100644 --- a/src/cmd/compile/internal/ssa/compile.go +++ b/src/cmd/compile/internal/ssa/compile.go @@ -83,8 +83,8 @@ type pass struct { var passes = [...]pass{ {"phielim", phielim}, {"copyelim", copyelim}, - {"decompose", decompose}, {"early deadcode", deadcode}, // remove generated dead code to avoid doing pointless work during opt + {"decompose", decompose}, {"opt", opt}, {"opt deadcode", deadcode}, // remove any blocks orphaned during opt {"generic cse", cse}, diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 014c960267..6d3a949a6a 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -103,7 +103,7 @@ func (c *Config) Frontend() Frontend { return c.fe } // NewFunc returns a new, empty function object func (c *Config) NewFunc() *Func { // TODO(khr): should this function take name, type, etc. as arguments? - return &Func{Config: c, NamedValues: map[GCNode][]*Value{}} + return &Func{Config: c, NamedValues: map[LocalSlot][]*Value{}} } func (c *Config) Logf(msg string, args ...interface{}) { c.fe.Logf(msg, args...) } diff --git a/src/cmd/compile/internal/ssa/deadcode.go b/src/cmd/compile/internal/ssa/deadcode.go index 3351589fda..e9d6525701 100644 --- a/src/cmd/compile/internal/ssa/deadcode.go +++ b/src/cmd/compile/internal/ssa/deadcode.go @@ -162,24 +162,38 @@ func deadcode(f *Func) { } f.Blocks = f.Blocks[:i] - // Remove dead entries from namedValues map. - for name, values := range f.NamedValues { - i := 0 + // Remove dead & duplicate entries from namedValues map. + s := newSparseSet(f.NumValues()) + i = 0 + for _, name := range f.Names { + j := 0 + s.clear() + values := f.NamedValues[name] for _, v := range values { for v.Op == OpCopy { v = v.Args[0] } - if live[v.ID] { - values[i] = v - i++ + if live[v.ID] && !s.contains(v.ID) { + values[j] = v + j++ + s.add(v.ID) } } - f.NamedValues[name] = values[:i] - tail := values[i:] - for j := range tail { - tail[j] = nil + if j == 0 { + delete(f.NamedValues, name) + } else { + f.Names[i] = name + i++ + for k := len(values) - 1; k >= j; k-- { + values[k] = nil + } + f.NamedValues[name] = values[:j] } } + for k := len(f.Names) - 1; k >= i; k-- { + f.Names[k] = LocalSlot{} + } + f.Names = f.Names[:i] // TODO: renumber Blocks and Values densely? // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index 7f491c77f9..c59d77ea60 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -10,7 +10,7 @@ func TestDeadLoop(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem")), @@ -40,7 +40,7 @@ func TestDeadValue(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("deadval", OpConst64, TypeInt64, 37, nil), Goto("exit")), Bloc("exit", @@ -64,7 +64,7 @@ func TestNeverTaken(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("cond", OpConstBool, TypeBool, 0, nil), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), If("cond", "then", "else")), Bloc("then", Goto("exit")), @@ -98,7 +98,7 @@ func TestNestedDeadBlocks(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("cond", OpConstBool, TypeBool, 0, nil), If("cond", "b2", "b4")), Bloc("b2", diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go index 159ac4e439..4514c99004 100644 --- a/src/cmd/compile/internal/ssa/deadstore_test.go +++ b/src/cmd/compile/internal/ssa/deadstore_test.go @@ -12,7 +12,7 @@ func TestDeadStore(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpArg, TypeMem, 0, ".mem"), + Valu("start", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr1", OpAddr, ptrType, 0, nil, "sb"), @@ -47,7 +47,7 @@ func TestDeadStorePhi(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpArg, TypeMem, 0, ".mem"), + Valu("start", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr", OpAddr, ptrType, 0, nil, "sb"), @@ -74,7 +74,7 @@ func TestDeadStoreTypes(t *testing.T) { t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"} fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpArg, TypeMem, 0, ".mem"), + Valu("start", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr1", OpAddr, t1, 0, nil, "sb"), diff --git a/src/cmd/compile/internal/ssa/decompose.go b/src/cmd/compile/internal/ssa/decompose.go index 2057d8ea5c..c8a1df281a 100644 --- a/src/cmd/compile/internal/ssa/decompose.go +++ b/src/cmd/compile/internal/ssa/decompose.go @@ -29,8 +29,75 @@ func decompose(f *Func) { } } } - // TODO: decompose complex? // TODO: decompose 64-bit ops on 32-bit archs? + + // Split up named values into their components. + // NOTE: the component values we are making are dead at this point. + // We must do the opt pass before any deadcode elimination or we will + // lose the name->value correspondence. + for _, name := range f.Names { + t := name.Type + switch { + case t.IsComplex(): + var elemType Type + if t.Size() == 16 { + elemType = f.Config.fe.TypeFloat64() + } else { + elemType = f.Config.fe.TypeFloat32() + } + rName := LocalSlot{name.N, elemType, name.Off} + iName := LocalSlot{name.N, elemType, name.Off + elemType.Size()} + f.Names = append(f.Names, rName, iName) + for _, v := range f.NamedValues[name] { + r := v.Block.NewValue1(v.Line, OpComplexReal, elemType, v) + i := v.Block.NewValue1(v.Line, OpComplexImag, elemType, v) + f.NamedValues[rName] = append(f.NamedValues[rName], r) + f.NamedValues[iName] = append(f.NamedValues[iName], i) + } + case t.IsString(): + ptrType := f.Config.fe.TypeBytePtr() + lenType := f.Config.fe.TypeInt() + ptrName := LocalSlot{name.N, ptrType, name.Off} + lenName := LocalSlot{name.N, lenType, name.Off + f.Config.PtrSize} + f.Names = append(f.Names, ptrName, lenName) + for _, v := range f.NamedValues[name] { + ptr := v.Block.NewValue1(v.Line, OpStringPtr, ptrType, v) + len := v.Block.NewValue1(v.Line, OpStringLen, lenType, v) + f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr) + f.NamedValues[lenName] = append(f.NamedValues[lenName], len) + } + case t.IsSlice(): + ptrType := f.Config.fe.TypeBytePtr() + lenType := f.Config.fe.TypeInt() + ptrName := LocalSlot{name.N, ptrType, name.Off} + lenName := LocalSlot{name.N, lenType, name.Off + f.Config.PtrSize} + capName := LocalSlot{name.N, lenType, name.Off + 2*f.Config.PtrSize} + f.Names = append(f.Names, ptrName, lenName, capName) + for _, v := range f.NamedValues[name] { + ptr := v.Block.NewValue1(v.Line, OpSlicePtr, ptrType, v) + len := v.Block.NewValue1(v.Line, OpSliceLen, lenType, v) + cap := v.Block.NewValue1(v.Line, OpSliceCap, lenType, v) + f.NamedValues[ptrName] = append(f.NamedValues[ptrName], ptr) + f.NamedValues[lenName] = append(f.NamedValues[lenName], len) + f.NamedValues[capName] = append(f.NamedValues[capName], cap) + } + case t.IsInterface(): + ptrType := f.Config.fe.TypeBytePtr() + typeName := LocalSlot{name.N, ptrType, name.Off} + dataName := LocalSlot{name.N, ptrType, name.Off + f.Config.PtrSize} + f.Names = append(f.Names, typeName, dataName) + for _, v := range f.NamedValues[name] { + typ := v.Block.NewValue1(v.Line, OpITab, ptrType, v) + data := v.Block.NewValue1(v.Line, OpIData, ptrType, v) + f.NamedValues[typeName] = append(f.NamedValues[typeName], typ) + f.NamedValues[dataName] = append(f.NamedValues[dataName], data) + } + //case t.IsStruct(): + // TODO + case t.Size() > f.Config.IntSize: + f.Unimplementedf("undecomposed type %s", t) + } + } } func decomposeStringPhi(v *Value) { diff --git a/src/cmd/compile/internal/ssa/dom_test.go b/src/cmd/compile/internal/ssa/dom_test.go index eff7205fa3..84e0093799 100644 --- a/src/cmd/compile/internal/ssa/dom_test.go +++ b/src/cmd/compile/internal/ssa/dom_test.go @@ -20,7 +20,7 @@ func genLinear(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto(blockn(0)), ), ) @@ -43,7 +43,7 @@ func genFwdBack(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -73,7 +73,7 @@ func genManyPred(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -111,7 +111,7 @@ func genMaxPred(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -136,7 +136,7 @@ func genMaxPredValue(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -223,7 +223,7 @@ func TestDominatorsSingleBlock(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Exit("mem"))) doms := map[string]string{} @@ -238,7 +238,7 @@ func TestDominatorsSimple(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("a")), Bloc("a", Goto("b")), @@ -266,7 +266,7 @@ func TestDominatorsMultPredFwd(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", @@ -294,7 +294,7 @@ func TestDominatorsDeadCode(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 0, nil), If("p", "b3", "b5")), Bloc("b2", Exit("mem")), @@ -319,7 +319,7 @@ func TestDominatorsMultPredRev(t *testing.T) { Bloc("entry", Goto("first")), Bloc("first", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto("a")), Bloc("a", @@ -348,7 +348,7 @@ func TestDominatorsMultPred(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", @@ -376,7 +376,7 @@ func TestPostDominators(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", @@ -403,7 +403,7 @@ func TestInfiniteLoop(t *testing.T) { // note lack of an exit block fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("p", OpConstBool, TypeBool, 1, nil), Goto("a")), Bloc("a", diff --git a/src/cmd/compile/internal/ssa/func.go b/src/cmd/compile/internal/ssa/func.go index ce11b184f6..e5fbfdb5ff 100644 --- a/src/cmd/compile/internal/ssa/func.go +++ b/src/cmd/compile/internal/ssa/func.go @@ -26,12 +26,11 @@ type Func struct { // when register allocation is done, maps value ids to locations RegAlloc []Location - // map from *gc.Node to set of Values that represent that Node. - // The Node must be an ONAME with PPARAM, PPARAMOUT, or PAUTO class. - NamedValues map[GCNode][]*Value + // map from LocalSlot to set of Values that we want to store in that slot. + NamedValues map[LocalSlot][]*Value // Names is a copy of NamedValues.Keys. We keep a separate list // of keys to make iteration order deterministic. - Names []GCNode + Names []LocalSlot } // NumBlocks returns an integer larger than the id of any Block in the Func. diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index dc5d220db8..d35690a30c 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -18,7 +18,7 @@ // // fun := Fun("entry", // Bloc("entry", -// Valu("mem", OpArg, TypeMem, 0, ".mem"), +// Valu("mem", OpInitMem, TypeMem, 0, ".mem"), // Goto("exit")), // Bloc("exit", // Exit("mem")), @@ -263,7 +263,7 @@ func TestArgs(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))) @@ -286,7 +286,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -295,7 +295,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -307,7 +307,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -318,7 +318,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit"))), }, } @@ -335,26 +335,26 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Goto("exit")), Bloc("exit", Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Exit("mem"))), }, // value order changed { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("a", OpConst64, TypeInt64, 14, nil), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Exit("mem"))), @@ -363,12 +363,12 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 14, nil), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 26, nil), Exit("mem"))), }, @@ -376,12 +376,12 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 0, 14), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 0, 26), Exit("mem"))), }, @@ -389,14 +389,14 @@ func TestEquiv(t *testing.T) { { Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Exit("mem"))), Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("a", OpConst64, TypeInt64, 0, nil), Valu("b", OpConst64, TypeInt64, 14, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "b", "a"), diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules index bb347aea8b..9c1da92b7e 100644 --- a/src/cmd/compile/internal/ssa/gen/generic.rules +++ b/src/cmd/compile/internal/ssa/gen/generic.rules @@ -188,12 +188,12 @@ (Load ptr mem) && t.IsString() -> (StringMake (Load ptr mem) - (Load - (OffPtr [config.PtrSize] ptr) + (Load + (OffPtr [config.PtrSize] ptr) mem)) (Store [2*config.PtrSize] dst (StringMake ptr len) mem) -> (Store [config.PtrSize] - (OffPtr [config.PtrSize] dst) + (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem)) @@ -215,18 +215,18 @@ (Load ptr mem) && t.IsSlice() -> (SliceMake (Load ptr mem) - (Load - (OffPtr [config.PtrSize] ptr) + (Load + (OffPtr [config.PtrSize] ptr) mem) - (Load - (OffPtr [2*config.PtrSize] ptr) + (Load + (OffPtr [2*config.PtrSize] ptr) mem)) (Store [3*config.PtrSize] dst (SliceMake ptr len cap) mem) -> (Store [config.PtrSize] - (OffPtr [2*config.PtrSize] dst) + (OffPtr [2*config.PtrSize] dst) cap (Store [config.PtrSize] - (OffPtr [config.PtrSize] dst) + (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem))) @@ -261,3 +261,30 @@ // Get rid of Convert ops for pointer arithmetic on unsafe.Pointer. (Convert (Add64 (Convert ptr) off)) -> (Add64 ptr off) + +// Decompose compound argument values +(Arg {n} [off]) && v.Type.IsString() -> + (StringMake + (Arg {n} [off]) + (Arg {n} [off+config.PtrSize])) + +(Arg {n} [off]) && v.Type.IsSlice() -> + (SliceMake + (Arg {n} [off]) + (Arg {n} [off+config.PtrSize]) + (Arg {n} [off+2*config.PtrSize])) + +(Arg {n} [off]) && v.Type.IsInterface() -> + (IMake + (Arg {n} [off]) + (Arg {n} [off+config.PtrSize])) + +(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 16 -> + (ComplexMake + (Arg {n} [off]) + (Arg {n} [off+8])) + +(Arg {n} [off]) && v.Type.IsComplex() && v.Type.Size() == 8 -> + (ComplexMake + (Arg {n} [off]) + (Arg {n} [off+4])) diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 162ee0dab4..8eb10a7d9b 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -260,7 +260,8 @@ var genericOps = []opData{ // TODO: Const32F, ... // Constant-like things - {name: "Arg"}, // memory input to the function. + {name: "InitMem"}, // memory input to the function. + {name: "Arg"}, // argument to the function. aux=GCNode of arg, off = offset in that arg. // The address of a variable. arg0 is the base pointer (SB or SP, depending // on whether it is a global or stack variable). The Aux field identifies the diff --git a/src/cmd/compile/internal/ssa/html.go b/src/cmd/compile/internal/ssa/html.go index 68a432c676..9b8fc3750b 100644 --- a/src/cmd/compile/internal/ssa/html.go +++ b/src/cmd/compile/internal/ssa/html.go @@ -472,3 +472,7 @@ func (p htmlFuncPrinter) startDepCycle() { func (p htmlFuncPrinter) endDepCycle() { fmt.Fprintln(p.w, "") } + +func (p htmlFuncPrinter) named(n LocalSlot, vals []*Value) { + // TODO +} diff --git a/src/cmd/compile/internal/ssa/location.go b/src/cmd/compile/internal/ssa/location.go index 0f9fb33eeb..85f525565b 100644 --- a/src/cmd/compile/internal/ssa/location.go +++ b/src/cmd/compile/internal/ssa/location.go @@ -4,6 +4,8 @@ package ssa +import "fmt" + // A place that an ssa variable can reside. type Location interface { Name() string // name to use in assembly templates: %rax, 16(%rsp), ... @@ -21,10 +23,16 @@ func (r *Register) Name() string { } // A LocalSlot is a location in the stack frame. +// It is (possibly a subpiece of) a PPARAM, PPARAMOUT, or PAUTO ONAME node. type LocalSlot struct { - N GCNode // a *gc.Node for an auto variable + N GCNode // an ONAME *gc.Node representing a variable on the stack + Type Type // type of slot + Off int64 // offset of slot in N } -func (s *LocalSlot) Name() string { - return s.N.String() +func (s LocalSlot) Name() string { + if s.Off == 0 { + return fmt.Sprintf("%s[%s]", s.N, s.Type) + } + return fmt.Sprintf("%s+%d[%s]", s.N, s.Off, s.Type) } diff --git a/src/cmd/compile/internal/ssa/lower.go b/src/cmd/compile/internal/ssa/lower.go index 9c28bd10a5..bf3c15f78b 100644 --- a/src/cmd/compile/internal/ssa/lower.go +++ b/src/cmd/compile/internal/ssa/lower.go @@ -21,7 +21,7 @@ func checkLower(f *Func) { continue // lowered } switch v.Op { - case OpSP, OpSB, OpArg, OpCopy, OpPhi, OpVarDef, OpVarKill: + case OpSP, OpSB, OpInitMem, OpArg, OpCopy, OpPhi, OpVarDef, OpVarKill: continue // ok not to lower } s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString() diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go index 8f32f32b1d..d4a55c0855 100644 --- a/src/cmd/compile/internal/ssa/nilcheck_test.go +++ b/src/cmd/compile/internal/ssa/nilcheck_test.go @@ -21,7 +21,7 @@ func benchmarkNilCheckDeep(b *testing.B, depth int) { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto(blockn(0)), ), @@ -67,7 +67,7 @@ func TestNilcheckSimple(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -104,7 +104,7 @@ func TestNilcheckDomOrder(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -140,7 +140,7 @@ func TestNilcheckAddr(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -173,7 +173,7 @@ func TestNilcheckAddPtr(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -207,7 +207,7 @@ func TestNilcheckPhi(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("sp", OpSP, TypeInvalid, 0, nil), Valu("baddr", OpAddr, TypeBool, 0, "b", "sp"), @@ -251,7 +251,7 @@ func TestNilcheckKeepRemove(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -299,7 +299,7 @@ func TestNilcheckInFalseBranch(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -350,7 +350,7 @@ func TestNilcheckUser(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -389,7 +389,7 @@ func TestNilcheckBug(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 400f59e174..d043e076ea 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -475,6 +475,7 @@ const ( OpConst64F OpConstInterface OpConstSlice + OpInitMem OpArg OpAddr OpSP @@ -3987,6 +3988,10 @@ var opcodeTable = [...]opInfo{ name: "ConstSlice", generic: true, }, + { + name: "InitMem", + generic: true, + }, { name: "Arg", generic: true, diff --git a/src/cmd/compile/internal/ssa/print.go b/src/cmd/compile/internal/ssa/print.go index 192dc83b39..b61e6f1cc7 100644 --- a/src/cmd/compile/internal/ssa/print.go +++ b/src/cmd/compile/internal/ssa/print.go @@ -28,6 +28,7 @@ type funcPrinter interface { value(v *Value, live bool) startDepCycle() endDepCycle() + named(n LocalSlot, vals []*Value) } type stringFuncPrinter struct { @@ -73,6 +74,10 @@ func (p stringFuncPrinter) startDepCycle() { func (p stringFuncPrinter) endDepCycle() {} +func (p stringFuncPrinter) named(n LocalSlot, vals []*Value) { + fmt.Fprintf(p.w, "name %s: %v\n", n.Name(), vals) +} + func fprintFunc(p funcPrinter, f *Func) { reachable, live := findlive(f) p.header(f) @@ -136,4 +141,7 @@ func fprintFunc(p funcPrinter, f *Func) { p.endBlock(b) } + for name, vals := range f.NamedValues { + p.named(name, vals) + } } diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index 89deb14a4a..a751d66988 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -759,6 +759,16 @@ func (s *regAllocState) regalloc(f *Func) { pc++ continue } + if v.Op == OpArg { + // Args are "pre-spilled" values. We don't allocate + // any register here. We just set up the spill pointer to + // point at itself and any later user will restore it to use it. + s.values[v.ID].spill = v + s.values[v.ID].spillUsed = true // use is guaranteed + b.Values = append(b.Values, v) + pc++ + continue + } s.clearUses(pc*2 - 1) regspec := opcodeTable[v.Op].reg if regDebug { diff --git a/src/cmd/compile/internal/ssa/regalloc_test.go b/src/cmd/compile/internal/ssa/regalloc_test.go index dcd253ea14..08260fbbbb 100644 --- a/src/cmd/compile/internal/ssa/regalloc_test.go +++ b/src/cmd/compile/internal/ssa/regalloc_test.go @@ -10,7 +10,7 @@ func TestLiveControlOps(t *testing.T) { c := testConfig(t) f := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("x", OpAMD64MOVBconst, TypeInt8, 0, 1), Valu("y", OpAMD64MOVBconst, TypeInt8, 0, 2), Valu("a", OpAMD64TESTB, TypeBool, 0, nil, "x", "y"), diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go index 2448b43547..c349603583 100644 --- a/src/cmd/compile/internal/ssa/rewritegeneric.go +++ b/src/cmd/compile/internal/ssa/rewritegeneric.go @@ -23,6 +23,8 @@ func rewriteValuegeneric(v *Value, config *Config) bool { return rewriteValuegeneric_OpAnd64(v, config) case OpAnd8: return rewriteValuegeneric_OpAnd8(v, config) + case OpArg: + return rewriteValuegeneric_OpArg(v, config) case OpArrayIndex: return rewriteValuegeneric_OpArrayIndex(v, config) case OpCom16: @@ -402,6 +404,156 @@ endeaf127389bd0d4b0e0e297830f8f463b: ; return false } +func rewriteValuegeneric_OpArg(v *Value, config *Config) bool { + b := v.Block + _ = b + // match: (Arg {n} [off]) + // cond: v.Type.IsString() + // result: (StringMake (Arg {n} [off]) (Arg {n} [off+config.PtrSize])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsString()) { + goto end939d3f946bf61eb85b46b374e7afa9e9 + } + v.Op = OpStringMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeBytePtr() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeInt() + v1.Aux = n + v1.AuxInt = off + config.PtrSize + v.AddArg(v1) + return true + } + goto end939d3f946bf61eb85b46b374e7afa9e9 +end939d3f946bf61eb85b46b374e7afa9e9: + ; + // match: (Arg {n} [off]) + // cond: v.Type.IsSlice() + // result: (SliceMake (Arg {n} [off]) (Arg {n} [off+config.PtrSize]) (Arg {n} [off+2*config.PtrSize])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsSlice()) { + goto endab4b93ad3b1cf55e5bf25d1fd9cd498e + } + v.Op = OpSliceMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeBytePtr() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeInt() + v1.Aux = n + v1.AuxInt = off + config.PtrSize + v.AddArg(v1) + v2 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v2.Type = config.fe.TypeInt() + v2.Aux = n + v2.AuxInt = off + 2*config.PtrSize + v.AddArg(v2) + return true + } + goto endab4b93ad3b1cf55e5bf25d1fd9cd498e +endab4b93ad3b1cf55e5bf25d1fd9cd498e: + ; + // match: (Arg {n} [off]) + // cond: v.Type.IsInterface() + // result: (IMake (Arg {n} [off]) (Arg {n} [off+config.PtrSize])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsInterface()) { + goto end851de8e588a39e81b4e2aef06566bf3e + } + v.Op = OpIMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeBytePtr() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeBytePtr() + v1.Aux = n + v1.AuxInt = off + config.PtrSize + v.AddArg(v1) + return true + } + goto end851de8e588a39e81b4e2aef06566bf3e +end851de8e588a39e81b4e2aef06566bf3e: + ; + // match: (Arg {n} [off]) + // cond: v.Type.IsComplex() && v.Type.Size() == 16 + // result: (ComplexMake (Arg {n} [off]) (Arg {n} [off+8])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsComplex() && v.Type.Size() == 16) { + goto end0988fc6a62c810b2f4976cb6cf44387f + } + v.Op = OpComplexMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeFloat64() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeFloat64() + v1.Aux = n + v1.AuxInt = off + 8 + v.AddArg(v1) + return true + } + goto end0988fc6a62c810b2f4976cb6cf44387f +end0988fc6a62c810b2f4976cb6cf44387f: + ; + // match: (Arg {n} [off]) + // cond: v.Type.IsComplex() && v.Type.Size() == 8 + // result: (ComplexMake (Arg {n} [off]) (Arg {n} [off+4])) + { + n := v.Aux + off := v.AuxInt + if !(v.Type.IsComplex() && v.Type.Size() == 8) { + goto enda348e93e0036873dd7089a2939c22e3e + } + v.Op = OpComplexMake + v.AuxInt = 0 + v.Aux = nil + v.resetArgs() + v0 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v0.Type = config.fe.TypeFloat32() + v0.Aux = n + v0.AuxInt = off + v.AddArg(v0) + v1 := b.NewValue0(v.Line, OpArg, TypeInvalid) + v1.Type = config.fe.TypeFloat32() + v1.Aux = n + v1.AuxInt = off + 4 + v.AddArg(v1) + return true + } + goto enda348e93e0036873dd7089a2939c22e3e +enda348e93e0036873dd7089a2939c22e3e: + ; + return false +} func rewriteValuegeneric_OpArrayIndex(v *Value, config *Config) bool { b := v.Block _ = b @@ -2115,13 +2267,13 @@ end1b106f89e0e3e26c613b957a7c98d8ad: ; // match: (Load ptr mem) // cond: t.IsString() - // result: (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) + // result: (StringMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem)) { t := v.Type ptr := v.Args[0] mem := v.Args[1] if !(t.IsString()) { - goto end7c75255555bf9dd796298d9f6eaf9cf2 + goto enddd15a6f3d53a6ce7a19d4e181dd1c13a } v.Op = OpStringMake v.AuxInt = 0 @@ -2133,9 +2285,9 @@ end1b106f89e0e3e26c613b957a7c98d8ad: v0.AddArg(mem) v.AddArg(v0) v1 := b.NewValue0(v.Line, OpLoad, TypeInvalid) - v1.Type = config.fe.TypeUintptr() + v1.Type = config.fe.TypeInt() v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v2.Type = config.fe.TypeUintptr().PtrTo() + v2.Type = config.fe.TypeInt().PtrTo() v2.AuxInt = config.PtrSize v2.AddArg(ptr) v1.AddArg(v2) @@ -2143,18 +2295,18 @@ end1b106f89e0e3e26c613b957a7c98d8ad: v.AddArg(v1) return true } - goto end7c75255555bf9dd796298d9f6eaf9cf2 -end7c75255555bf9dd796298d9f6eaf9cf2: + goto enddd15a6f3d53a6ce7a19d4e181dd1c13a +enddd15a6f3d53a6ce7a19d4e181dd1c13a: ; // match: (Load ptr mem) // cond: t.IsSlice() - // result: (SliceMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem) (Load (OffPtr [2*config.PtrSize] ptr) mem)) + // result: (SliceMake (Load ptr mem) (Load (OffPtr [config.PtrSize] ptr) mem) (Load (OffPtr [2*config.PtrSize] ptr) mem)) { t := v.Type ptr := v.Args[0] mem := v.Args[1] if !(t.IsSlice()) { - goto end12c46556d962198680eb3238859e3016 + goto end65e8b0055aa7491b9b6066d9fe1b2c13 } v.Op = OpSliceMake v.AuxInt = 0 @@ -2166,18 +2318,18 @@ end7c75255555bf9dd796298d9f6eaf9cf2: v0.AddArg(mem) v.AddArg(v0) v1 := b.NewValue0(v.Line, OpLoad, TypeInvalid) - v1.Type = config.fe.TypeUintptr() + v1.Type = config.fe.TypeInt() v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v2.Type = config.fe.TypeUintptr().PtrTo() + v2.Type = config.fe.TypeInt().PtrTo() v2.AuxInt = config.PtrSize v2.AddArg(ptr) v1.AddArg(v2) v1.AddArg(mem) v.AddArg(v1) v3 := b.NewValue0(v.Line, OpLoad, TypeInvalid) - v3.Type = config.fe.TypeUintptr() + v3.Type = config.fe.TypeInt() v4 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v4.Type = config.fe.TypeUintptr().PtrTo() + v4.Type = config.fe.TypeInt().PtrTo() v4.AuxInt = 2 * config.PtrSize v4.AddArg(ptr) v3.AddArg(v4) @@ -2185,8 +2337,8 @@ end7c75255555bf9dd796298d9f6eaf9cf2: v.AddArg(v3) return true } - goto end12c46556d962198680eb3238859e3016 -end12c46556d962198680eb3238859e3016: + goto end65e8b0055aa7491b9b6066d9fe1b2c13 +end65e8b0055aa7491b9b6066d9fe1b2c13: ; // match: (Load ptr mem) // cond: t.IsInterface() @@ -2916,14 +3068,14 @@ end3851a482d7bd37a93c4d81581e85b3ab: ; // match: (Store [2*config.PtrSize] dst (StringMake ptr len) mem) // cond: - // result: (Store [config.PtrSize] (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem)) + // result: (Store [config.PtrSize] (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem)) { if v.AuxInt != 2*config.PtrSize { - goto end12abe4021d24e76ed56d64b18730bffb + goto endd3a6ecebdad5899570a79fe5c62f34f1 } dst := v.Args[0] if v.Args[1].Op != OpStringMake { - goto end12abe4021d24e76ed56d64b18730bffb + goto endd3a6ecebdad5899570a79fe5c62f34f1 } ptr := v.Args[1].Args[0] len := v.Args[1].Args[1] @@ -2934,7 +3086,7 @@ end3851a482d7bd37a93c4d81581e85b3ab: v.resetArgs() v.AuxInt = config.PtrSize v0 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v0.Type = config.fe.TypeUintptr().PtrTo() + v0.Type = config.fe.TypeInt().PtrTo() v0.AuxInt = config.PtrSize v0.AddArg(dst) v.AddArg(v0) @@ -2948,19 +3100,19 @@ end3851a482d7bd37a93c4d81581e85b3ab: v.AddArg(v1) return true } - goto end12abe4021d24e76ed56d64b18730bffb -end12abe4021d24e76ed56d64b18730bffb: + goto endd3a6ecebdad5899570a79fe5c62f34f1 +endd3a6ecebdad5899570a79fe5c62f34f1: ; // match: (Store [3*config.PtrSize] dst (SliceMake ptr len cap) mem) // cond: - // result: (Store [config.PtrSize] (OffPtr [2*config.PtrSize] dst) cap (Store [config.PtrSize] (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem))) + // result: (Store [config.PtrSize] (OffPtr [2*config.PtrSize] dst) cap (Store [config.PtrSize] (OffPtr [config.PtrSize] dst) len (Store [config.PtrSize] dst ptr mem))) { if v.AuxInt != 3*config.PtrSize { - goto end7498d25e17db5398cf073a8590e35cc2 + goto endd5cc8c3dad7d24c845b0b88fc51487ae } dst := v.Args[0] if v.Args[1].Op != OpSliceMake { - goto end7498d25e17db5398cf073a8590e35cc2 + goto endd5cc8c3dad7d24c845b0b88fc51487ae } ptr := v.Args[1].Args[0] len := v.Args[1].Args[1] @@ -2972,7 +3124,7 @@ end12abe4021d24e76ed56d64b18730bffb: v.resetArgs() v.AuxInt = config.PtrSize v0 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v0.Type = config.fe.TypeUintptr().PtrTo() + v0.Type = config.fe.TypeInt().PtrTo() v0.AuxInt = 2 * config.PtrSize v0.AddArg(dst) v.AddArg(v0) @@ -2980,7 +3132,7 @@ end12abe4021d24e76ed56d64b18730bffb: v1 := b.NewValue0(v.Line, OpStore, TypeInvalid) v1.AuxInt = config.PtrSize v2 := b.NewValue0(v.Line, OpOffPtr, TypeInvalid) - v2.Type = config.fe.TypeUintptr().PtrTo() + v2.Type = config.fe.TypeInt().PtrTo() v2.AuxInt = config.PtrSize v2.AddArg(dst) v1.AddArg(v2) @@ -2996,8 +3148,8 @@ end12abe4021d24e76ed56d64b18730bffb: v.AddArg(v1) return true } - goto end7498d25e17db5398cf073a8590e35cc2 -end7498d25e17db5398cf073a8590e35cc2: + goto endd5cc8c3dad7d24c845b0b88fc51487ae +endd5cc8c3dad7d24c845b0b88fc51487ae: ; // match: (Store [2*config.PtrSize] dst (IMake itab data) mem) // cond: diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go index 7f62ab9e3b..30c029ef7c 100644 --- a/src/cmd/compile/internal/ssa/schedule_test.go +++ b/src/cmd/compile/internal/ssa/schedule_test.go @@ -11,7 +11,7 @@ func TestSchedule(t *testing.T) { cases := []fun{ Fun(c, "entry", Bloc("entry", - Valu("mem0", OpArg, TypeMem, 0, ".mem"), + Valu("mem0", OpInitMem, TypeMem, 0, ".mem"), Valu("ptr", OpConst64, TypeInt64, 0xABCD, nil), Valu("v", OpConst64, TypeInt64, 12, nil), Valu("mem1", OpStore, TypeMem, 8, nil, "ptr", "v", "mem0"), diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index 611b418b6d..9e7f0585a6 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -28,7 +28,7 @@ func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun { ptyp := &TypeImpl{Size_: 8, Ptr: true, Name: "ptr"} fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpArg, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, ".mem"), Valu("SP", OpSP, TypeUInt64, 0, nil), Valu("argptr", OpOffPtr, ptyp, 8, nil, "SP"), Valu("resptr", OpOffPtr, ptyp, 16, nil, "SP"), diff --git a/src/cmd/compile/internal/ssa/stackalloc.go b/src/cmd/compile/internal/ssa/stackalloc.go index 793162a797..3eb5c3cf4a 100644 --- a/src/cmd/compile/internal/ssa/stackalloc.go +++ b/src/cmd/compile/internal/ssa/stackalloc.go @@ -44,6 +44,13 @@ func stackalloc(f *Func) { } case v.Op == OpLoadReg: s.add(v.Args[0].ID) + case v.Op == OpArg: + // This is an input argument which is pre-spilled. It is kind of + // like a StoreReg, but we don't remove v.ID here because we want + // this value to appear live even before this point. Being live + // all the way to the start of the entry block prevents other + // values from being allocated to the same slot and clobbering + // the input value before we have a chance to load it. } } } @@ -51,7 +58,7 @@ func stackalloc(f *Func) { // Build map from values to their names, if any. // A value may be associated with more than one name (e.g. after // the assignment i=j). This step picks one name per value arbitrarily. - names := make([]GCNode, f.NumValues()) + names := make([]LocalSlot, f.NumValues()) for _, name := range f.Names { // Note: not "range f.NamedValues" above, because // that would be nondeterministic. @@ -74,9 +81,17 @@ func stackalloc(f *Func) { } } + // Allocate args to their assigned locations. + for _, v := range f.Entry.Values { + if v.Op != OpArg { + continue + } + f.setHome(v, LocalSlot{v.Aux.(GCNode), v.Type, v.AuxInt}) + } + // For each type, we keep track of all the stack slots we // have allocated for that type. - locations := map[Type][]*LocalSlot{} + locations := map[Type][]LocalSlot{} // Each time we assign a stack slot to a value v, we remember // the slot we used via an index into locations[v.Type]. @@ -99,16 +114,16 @@ func stackalloc(f *Func) { // If this is a named value, try to use the name as // the spill location. - var name GCNode + var name LocalSlot if v.Op == OpStoreReg { name = names[v.Args[0].ID] } else { name = names[v.ID] } - if name != nil && v.Type.Equal(name.Typ()) { + if name.N != nil && v.Type.Equal(name.Type) { for _, id := range interfere[v.ID] { h := f.getHome(id) - if h != nil && h.(*LocalSlot).N == name { + if h != nil && h.(LocalSlot) == name { // A variable can interfere with itself. // It is rare, but but it can happen. goto noname @@ -118,17 +133,16 @@ func stackalloc(f *Func) { for _, a := range v.Args { for _, id := range interfere[a.ID] { h := f.getHome(id) - if h != nil && h.(*LocalSlot).N == name { + if h != nil && h.(LocalSlot) == name { goto noname } } } } - loc := &LocalSlot{name} - f.setHome(v, loc) + f.setHome(v, name) if v.Op == OpPhi { for _, a := range v.Args { - f.setHome(a, loc) + f.setHome(a, name) } } continue @@ -169,7 +183,7 @@ func stackalloc(f *Func) { } // If there is no unused stack slot, allocate a new one. if i == len(locs) { - locs = append(locs, &LocalSlot{f.Config.fe.Auto(v.Type)}) + locs = append(locs, LocalSlot{N: f.Config.fe.Auto(v.Type), Type: v.Type, Off: 0}) locations[v.Type] = locs } // Use the stack variable at that index for v. diff --git a/src/cmd/compile/internal/ssa/tighten.go b/src/cmd/compile/internal/ssa/tighten.go index 4fa26d2d18..6726c06e76 100644 --- a/src/cmd/compile/internal/ssa/tighten.go +++ b/src/cmd/compile/internal/ssa/tighten.go @@ -54,8 +54,8 @@ func tighten(f *Func) { for _, b := range f.Blocks { for i := 0; i < len(b.Values); i++ { v := b.Values[i] - if v.Op == OpPhi || v.Op == OpGetClosurePtr || v.Op == OpConvert { - // GetClosurePtr must stay in entry block. + if v.Op == OpPhi || v.Op == OpGetClosurePtr || v.Op == OpConvert || v.Op == OpArg { + // GetClosurePtr & Arg must stay in entry block. // OpConvert must not float over call sites. // TODO do we instead need a dependence edge of some sort for OpConvert? // Would memory do the trick, or do we need something else that relates diff --git a/src/runtime/runtime-gdb_test.go b/src/runtime/runtime-gdb_test.go index 2843633ee1..48567f1b9c 100644 --- a/src/runtime/runtime-gdb_test.go +++ b/src/runtime/runtime-gdb_test.go @@ -94,9 +94,6 @@ func TestGdbPython(t *testing.T) { "-ex", "echo END\n", "-ex", "echo BEGIN print strvar\n", "-ex", "print strvar", - "-ex", "echo END\n", - "-ex", "echo BEGIN print ptrvar\n", - "-ex", "print ptrvar", "-ex", "echo END\n"} // without framepointer, gdb cannot backtrace our non-standard @@ -151,10 +148,6 @@ func TestGdbPython(t *testing.T) { t.Fatalf("print strvar failed: %s", bl) } - if bl := blocks["print ptrvar"]; !strVarRe.MatchString(bl) { - t.Fatalf("print ptrvar failed: %s", bl) - } - btGoroutineRe := regexp.MustCompile(`^#0\s+runtime.+at`) if bl := blocks["goroutine 2 bt"]; canBackTrace && !btGoroutineRe.MatchString(bl) { t.Fatalf("goroutine 2 bt failed: %s", bl) -- cgit v1.3 From 16b1fce9217886797940247f6ffce57e119c3e47 Mon Sep 17 00:00:00 2001 From: Keith Randall Date: Sun, 31 Jan 2016 11:39:39 -0800 Subject: [dev.ssa] cmd/compile: add aux typing, flags to ops Add the aux type to opcodes. Add rematerializeable as a flag. Change-Id: I906e19281498f3ee51bb136299bf26e13a54b2ec Reviewed-on: https://go-review.googlesource.com/19088 Run-TryBot: Keith Randall TryBot-Result: Gobot Gobot Reviewed-by: Todd Neal --- src/cmd/compile/internal/gc/ssa.go | 8 +- src/cmd/compile/internal/ssa/check.go | 24 +- src/cmd/compile/internal/ssa/deadcode_test.go | 8 +- src/cmd/compile/internal/ssa/deadstore_test.go | 6 +- src/cmd/compile/internal/ssa/dom_test.go | 26 +- src/cmd/compile/internal/ssa/func_test.go | 34 +- src/cmd/compile/internal/ssa/gen/AMD64Ops.go | 308 ++++++------- src/cmd/compile/internal/ssa/gen/genericOps.go | 80 ++-- src/cmd/compile/internal/ssa/gen/main.go | 21 +- src/cmd/compile/internal/ssa/nilcheck_test.go | 20 +- src/cmd/compile/internal/ssa/op.go | 26 +- src/cmd/compile/internal/ssa/opGen.go | 509 ++++++++++++++-------- src/cmd/compile/internal/ssa/passbm_test.go | 2 +- src/cmd/compile/internal/ssa/regalloc.go | 27 +- src/cmd/compile/internal/ssa/regalloc_test.go | 6 +- src/cmd/compile/internal/ssa/schedule_test.go | 2 +- src/cmd/compile/internal/ssa/shift_test.go | 2 +- src/cmd/compile/internal/ssa/shortcircuit_test.go | 2 +- src/cmd/compile/internal/ssa/value.go | 72 ++- 19 files changed, 696 insertions(+), 487 deletions(-) (limited to 'src/cmd/compile/internal/ssa/deadcode_test.go') diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go index 458bccb8dc..59993c23dd 100644 --- a/src/cmd/compile/internal/gc/ssa.go +++ b/src/cmd/compile/internal/gc/ssa.go @@ -4022,11 +4022,11 @@ func (s *genState) genValue(v *ssa.Value) { var i int64 switch v.Op { case ssa.OpAMD64MOVBconst: - i = int64(int8(v.AuxInt)) + i = int64(v.AuxInt8()) case ssa.OpAMD64MOVWconst: - i = int64(int16(v.AuxInt)) + i = int64(v.AuxInt16()) case ssa.OpAMD64MOVLconst: - i = int64(int32(v.AuxInt)) + i = int64(v.AuxInt32()) case ssa.OpAMD64MOVQconst: i = v.AuxInt } @@ -4116,7 +4116,7 @@ func (s *genState) genValue(v *ssa.Value) { case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst: p := Prog(v.Op.Asm()) p.From.Type = obj.TYPE_CONST - sc := ssa.ValAndOff(v.AuxInt) + sc := v.AuxValAndOff() i := sc.Val() switch v.Op { case ssa.OpAMD64MOVBstoreconst: diff --git a/src/cmd/compile/internal/ssa/check.go b/src/cmd/compile/internal/ssa/check.go index 1c36160f8f..220877242c 100644 --- a/src/cmd/compile/internal/ssa/check.go +++ b/src/cmd/compile/internal/ssa/check.go @@ -148,9 +148,27 @@ func checkFunc(f *Func) { } for _, v := range b.Values { - switch v.Aux.(type) { - case bool, float32, float64: - f.Fatalf("value %v has an Aux value of type %T, should be AuxInt", v.LongString(), v.Aux) + + // Check to make sure aux values make sense. + canHaveAux := false + canHaveAuxInt := false + switch opcodeTable[v.Op].auxType { + case auxNone: + case auxBool, auxInt8, auxInt16, auxInt32, auxInt64, auxFloat: + canHaveAuxInt = true + case auxString, auxSym: + canHaveAux = true + case auxSymOff, auxSymValAndOff: + canHaveAuxInt = true + canHaveAux = true + default: + f.Fatalf("unknown aux type for %s", v.Op) + } + if !canHaveAux && v.Aux != nil { + f.Fatalf("value %v has an Aux value %v but shouldn't", v.LongString(), v.Aux) + } + if !canHaveAuxInt && v.AuxInt != 0 { + f.Fatalf("value %v has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt) } for _, arg := range v.Args { diff --git a/src/cmd/compile/internal/ssa/deadcode_test.go b/src/cmd/compile/internal/ssa/deadcode_test.go index c59d77ea60..24934d5ac4 100644 --- a/src/cmd/compile/internal/ssa/deadcode_test.go +++ b/src/cmd/compile/internal/ssa/deadcode_test.go @@ -10,7 +10,7 @@ func TestDeadLoop(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Goto("exit")), Bloc("exit", Exit("mem")), @@ -40,7 +40,7 @@ func TestDeadValue(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("deadval", OpConst64, TypeInt64, 37, nil), Goto("exit")), Bloc("exit", @@ -64,7 +64,7 @@ func TestNeverTaken(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", Valu("cond", OpConstBool, TypeBool, 0, nil), - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), If("cond", "then", "else")), Bloc("then", Goto("exit")), @@ -98,7 +98,7 @@ func TestNestedDeadBlocks(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("cond", OpConstBool, TypeBool, 0, nil), If("cond", "b2", "b4")), Bloc("b2", diff --git a/src/cmd/compile/internal/ssa/deadstore_test.go b/src/cmd/compile/internal/ssa/deadstore_test.go index 4514c99004..9ded8bd6e6 100644 --- a/src/cmd/compile/internal/ssa/deadstore_test.go +++ b/src/cmd/compile/internal/ssa/deadstore_test.go @@ -12,7 +12,7 @@ func TestDeadStore(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr", Elem_: elemType} // dummy for testing fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpInitMem, TypeMem, 0, ".mem"), + Valu("start", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr1", OpAddr, ptrType, 0, nil, "sb"), @@ -47,7 +47,7 @@ func TestDeadStorePhi(t *testing.T) { ptrType := &TypeImpl{Size_: 8, Ptr: true, Name: "testptr"} // dummy for testing fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpInitMem, TypeMem, 0, ".mem"), + Valu("start", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr", OpAddr, ptrType, 0, nil, "sb"), @@ -74,7 +74,7 @@ func TestDeadStoreTypes(t *testing.T) { t2 := &TypeImpl{Size_: 4, Ptr: true, Name: "t2"} fun := Fun(c, "entry", Bloc("entry", - Valu("start", OpInitMem, TypeMem, 0, ".mem"), + Valu("start", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("v", OpConstBool, TypeBool, 1, nil), Valu("addr1", OpAddr, t1, 0, nil, "sb"), diff --git a/src/cmd/compile/internal/ssa/dom_test.go b/src/cmd/compile/internal/ssa/dom_test.go index 7174f10e4d..0328655b6a 100644 --- a/src/cmd/compile/internal/ssa/dom_test.go +++ b/src/cmd/compile/internal/ssa/dom_test.go @@ -20,7 +20,7 @@ func genLinear(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Goto(blockn(0)), ), ) @@ -43,7 +43,7 @@ func genFwdBack(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -73,7 +73,7 @@ func genManyPred(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -111,7 +111,7 @@ func genMaxPred(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -136,7 +136,7 @@ func genMaxPredValue(size int) []bloc { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 1, nil), Goto(blockn(0)), ), @@ -223,7 +223,7 @@ func TestDominatorsSingleBlock(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Exit("mem"))) doms := map[string]string{} @@ -238,7 +238,7 @@ func TestDominatorsSimple(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Goto("a")), Bloc("a", Goto("b")), @@ -266,7 +266,7 @@ func TestDominatorsMultPredFwd(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", @@ -294,7 +294,7 @@ func TestDominatorsDeadCode(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 0, nil), If("p", "b3", "b5")), Bloc("b2", Exit("mem")), @@ -319,7 +319,7 @@ func TestDominatorsMultPredRev(t *testing.T) { Bloc("entry", Goto("first")), Bloc("first", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 1, nil), Goto("a")), Bloc("a", @@ -348,7 +348,7 @@ func TestDominatorsMultPred(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", @@ -376,7 +376,7 @@ func TestPostDominators(t *testing.T) { c := testConfig(t) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 1, nil), If("p", "a", "c")), Bloc("a", @@ -403,7 +403,7 @@ func TestInfiniteLoop(t *testing.T) { // note lack of an exit block fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("p", OpConstBool, TypeBool, 1, nil), Goto("a")), Bloc("a", diff --git a/src/cmd/compile/internal/ssa/func_test.go b/src/cmd/compile/internal/ssa/func_test.go index 590804182a..53213d2c11 100644 --- a/src/cmd/compile/internal/ssa/func_test.go +++ b/src/cmd/compile/internal/ssa/func_test.go @@ -6,7 +6,7 @@ // As an example, the following func // // b1: -// v1 = Arg [.mem] +// v1 = InitMem // Plain -> b2 // b2: // Exit v1 @@ -18,7 +18,7 @@ // // fun := Fun("entry", // Bloc("entry", -// Valu("mem", OpInitMem, TypeMem, 0, ".mem"), +// Valu("mem", OpInitMem, TypeMem, 0, nil), // Goto("exit")), // Bloc("exit", // Exit("mem")), @@ -267,7 +267,7 @@ func TestArgs(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Goto("exit")), Bloc("exit", Exit("mem"))) @@ -289,7 +289,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -298,7 +298,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -310,7 +310,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Goto("exit")), Bloc("exit", Exit("mem"))), @@ -321,7 +321,7 @@ func TestEquiv(t *testing.T) { Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Goto("exit"))), }, } @@ -338,26 +338,26 @@ func TestEquiv(t *testing.T) { { Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Goto("exit")), Bloc("exit", Exit("mem"))), Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Exit("mem"))), }, // value order changed { Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("a", OpConst64, TypeInt64, 14, nil), Exit("mem"))), Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Exit("mem"))), @@ -366,12 +366,12 @@ func TestEquiv(t *testing.T) { { Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("a", OpConst64, TypeInt64, 14, nil), Exit("mem"))), Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("a", OpConst64, TypeInt64, 26, nil), Exit("mem"))), }, @@ -379,12 +379,12 @@ func TestEquiv(t *testing.T) { { Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("a", OpConst64, TypeInt64, 0, 14), Exit("mem"))), Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("a", OpConst64, TypeInt64, 0, 26), Exit("mem"))), }, @@ -392,14 +392,14 @@ func TestEquiv(t *testing.T) { { Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("a", OpConst64, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 26, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Exit("mem"))), Fun(testConfig(t), "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("a", OpConst64, TypeInt64, 0, nil), Valu("b", OpConst64, TypeInt64, 14, nil), Valu("sum", OpAdd64, TypeInt64, 0, nil, "b", "a"), diff --git a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go index 10c5d2b227..1cf44f148f 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/AMD64Ops.go @@ -152,45 +152,45 @@ func init() { {name: "DIVSS", reg: fp21x15, asm: "DIVSS"}, // fp32 div {name: "DIVSD", reg: fp21x15, asm: "DIVSD"}, // fp64 div - {name: "MOVSSload", reg: fpload, asm: "MOVSS"}, // fp32 load - {name: "MOVSDload", reg: fpload, asm: "MOVSD"}, // fp64 load - {name: "MOVSSconst", reg: fp01, asm: "MOVSS"}, // fp32 constant - {name: "MOVSDconst", reg: fp01, asm: "MOVSD"}, // fp64 constant - {name: "MOVSSloadidx4", reg: fploadidx, asm: "MOVSS"}, // fp32 load - {name: "MOVSDloadidx8", reg: fploadidx, asm: "MOVSD"}, // fp64 load - - {name: "MOVSSstore", reg: fpstore, asm: "MOVSS"}, // fp32 store - {name: "MOVSDstore", reg: fpstore, asm: "MOVSD"}, // fp64 store - {name: "MOVSSstoreidx4", reg: fpstoreidx, asm: "MOVSS"}, // fp32 indexed by 4i store - {name: "MOVSDstoreidx8", reg: fpstoreidx, asm: "MOVSD"}, // fp64 indexed by 8i store + {name: "MOVSSload", reg: fpload, asm: "MOVSS", aux: "SymOff"}, // fp32 load + {name: "MOVSDload", reg: fpload, asm: "MOVSD", aux: "SymOff"}, // fp64 load + {name: "MOVSSconst", reg: fp01, asm: "MOVSS", aux: "Float", rematerializeable: true}, // fp32 constant + {name: "MOVSDconst", reg: fp01, asm: "MOVSD", aux: "Float", rematerializeable: true}, // fp64 constant + {name: "MOVSSloadidx4", reg: fploadidx, asm: "MOVSS", aux: "SymOff"}, // fp32 load + {name: "MOVSDloadidx8", reg: fploadidx, asm: "MOVSD", aux: "SymOff"}, // fp64 load + + {name: "MOVSSstore", reg: fpstore, asm: "MOVSS", aux: "SymOff"}, // fp32 store + {name: "MOVSDstore", reg: fpstore, asm: "MOVSD", aux: "SymOff"}, // fp64 store + {name: "MOVSSstoreidx4", reg: fpstoreidx, asm: "MOVSS", aux: "SymOff"}, // fp32 indexed by 4i store + {name: "MOVSDstoreidx8", reg: fpstoreidx, asm: "MOVSD", aux: "SymOff"}, // fp64 indexed by 8i store // binary ops - {name: "ADDQ", reg: gp21, asm: "ADDQ"}, // arg0 + arg1 - {name: "ADDL", reg: gp21, asm: "ADDL"}, // arg0 + arg1 - {name: "ADDW", reg: gp21, asm: "ADDW"}, // arg0 + arg1 - {name: "ADDB", reg: gp21, asm: "ADDB"}, // arg0 + arg1 - {name: "ADDQconst", reg: gp11, asm: "ADDQ", typ: "UInt64"}, // arg0 + auxint - {name: "ADDLconst", reg: gp11, asm: "ADDL"}, // arg0 + auxint - {name: "ADDWconst", reg: gp11, asm: "ADDW"}, // arg0 + auxint - {name: "ADDBconst", reg: gp11, asm: "ADDB"}, // arg0 + auxint - - {name: "SUBQ", reg: gp21, asm: "SUBQ"}, // arg0 - arg1 - {name: "SUBL", reg: gp21, asm: "SUBL"}, // arg0 - arg1 - {name: "SUBW", reg: gp21, asm: "SUBW"}, // arg0 - arg1 - {name: "SUBB", reg: gp21, asm: "SUBB"}, // arg0 - arg1 - {name: "SUBQconst", reg: gp11, asm: "SUBQ"}, // arg0 - auxint - {name: "SUBLconst", reg: gp11, asm: "SUBL"}, // arg0 - auxint - {name: "SUBWconst", reg: gp11, asm: "SUBW"}, // arg0 - auxint - {name: "SUBBconst", reg: gp11, asm: "SUBB"}, // arg0 - auxint - - {name: "MULQ", reg: gp21, asm: "IMULQ"}, // arg0 * arg1 - {name: "MULL", reg: gp21, asm: "IMULL"}, // arg0 * arg1 - {name: "MULW", reg: gp21, asm: "IMULW"}, // arg0 * arg1 - {name: "MULB", reg: gp21, asm: "IMULW"}, // arg0 * arg1 - {name: "MULQconst", reg: gp11, asm: "IMULQ"}, // arg0 * auxint - {name: "MULLconst", reg: gp11, asm: "IMULL"}, // arg0 * auxint - {name: "MULWconst", reg: gp11, asm: "IMULW"}, // arg0 * auxint - {name: "MULBconst", reg: gp11, asm: "IMULW"}, // arg0 * auxint + {name: "ADDQ", reg: gp21, asm: "ADDQ"}, // arg0 + arg1 + {name: "ADDL", reg: gp21, asm: "ADDL"}, // arg0 + arg1 + {name: "ADDW", reg: gp21, asm: "ADDW"}, // arg0 + arg1 + {name: "ADDB", reg: gp21, asm: "ADDB"}, // arg0 + arg1 + {name: "ADDQconst", reg: gp11, asm: "ADDQ", aux: "Int64", typ: "UInt64"}, // arg0 + auxint + {name: "ADDLconst", reg: gp11, asm: "ADDL", aux: "Int32"}, // arg0 + auxint + {name: "ADDWconst", reg: gp11, asm: "ADDW", aux: "Int16"}, // arg0 + auxint + {name: "ADDBconst", reg: gp11, asm: "ADDB", aux: "Int8"}, // arg0 + auxint + + {name: "SUBQ", reg: gp21, asm: "SUBQ"}, // arg0 - arg1 + {name: "SUBL", reg: gp21, asm: "SUBL"}, // arg0 - arg1 + {name: "SUBW", reg: gp21, asm: "SUBW"}, // arg0 - arg1 + {name: "SUBB", reg: gp21, asm: "SUBB"}, // arg0 - arg1 + {name: "SUBQconst", reg: gp11, asm: "SUBQ", aux: "Int64"}, // arg0 - auxint + {name: "SUBLconst", reg: gp11, asm: "SUBL", aux: "Int32"}, // arg0 - auxint + {name: "SUBWconst", reg: gp11, asm: "SUBW", aux: "Int16"}, // arg0 - auxint + {name: "SUBBconst", reg: gp11, asm: "SUBB", aux: "Int8"}, // arg0 - auxint + + {name: "MULQ", reg: gp21, asm: "IMULQ"}, // arg0 * arg1 + {name: "MULL", reg: gp21, asm: "IMULL"}, // arg0 * arg1 + {name: "MULW", reg: gp21, asm: "IMULW"}, // arg0 * arg1 + {name: "MULB", reg: gp21, asm: "IMULW"}, // arg0 * arg1 + {name: "MULQconst", reg: gp11, asm: "IMULQ", aux: "Int64"}, // arg0 * auxint + {name: "MULLconst", reg: gp11, asm: "IMULL", aux: "Int32"}, // arg0 * auxint + {name: "MULWconst", reg: gp11, asm: "IMULW", aux: "Int16"}, // arg0 * auxint + {name: "MULBconst", reg: gp11, asm: "IMULW", aux: "Int8"}, // arg0 * auxint {name: "HMULL", reg: gp11hmul, asm: "IMULL"}, // (arg0 * arg1) >> width {name: "HMULW", reg: gp11hmul, asm: "IMULW"}, // (arg0 * arg1) >> width @@ -213,86 +213,86 @@ func init() { {name: "MODLU", reg: gp11mod, asm: "DIVL"}, // arg0 % arg1 {name: "MODWU", reg: gp11mod, asm: "DIVW"}, // arg0 % arg1 - {name: "ANDQ", reg: gp21, asm: "ANDQ"}, // arg0 & arg1 - {name: "ANDL", reg: gp21, asm: "ANDL"}, // arg0 & arg1 - {name: "ANDW", reg: gp21, asm: "ANDW"}, // arg0 & arg1 - {name: "ANDB", reg: gp21, asm: "ANDB"}, // arg0 & arg1 - {name: "ANDQconst", reg: gp11, asm: "ANDQ"}, // arg0 & auxint - {name: "ANDLconst", reg: gp11, asm: "ANDL"}, // arg0 & auxint - {name: "ANDWconst", reg: gp11, asm: "ANDW"}, // arg0 & auxint - {name: "ANDBconst", reg: gp11, asm: "ANDB"}, // arg0 & auxint - - {name: "ORQ", reg: gp21, asm: "ORQ"}, // arg0 | arg1 - {name: "ORL", reg: gp21, asm: "ORL"}, // arg0 | arg1 - {name: "ORW", reg: gp21, asm: "ORW"}, // arg0 | arg1 - {name: "ORB", reg: gp21, asm: "ORB"}, // arg0 | arg1 - {name: "ORQconst", reg: gp11, asm: "ORQ"}, // arg0 | auxint - {name: "ORLconst", reg: gp11, asm: "ORL"}, // arg0 | auxint - {name: "ORWconst", reg: gp11, asm: "ORW"}, // arg0 | auxint - {name: "ORBconst", reg: gp11, asm: "ORB"}, // arg0 | auxint - - {name: "XORQ", reg: gp21, asm: "XORQ"}, // arg0 ^ arg1 - {name: "XORL", reg: gp21, asm: "XORL"}, // arg0 ^ arg1 - {name: "XORW", reg: gp21, asm: "XORW"}, // arg0 ^ arg1 - {name: "XORB", reg: gp21, asm: "XORB"}, // arg0 ^ arg1 - {name: "XORQconst", reg: gp11, asm: "XORQ"}, // arg0 ^ auxint - {name: "XORLconst", reg: gp11, asm: "XORL"}, // arg0 ^ auxint - {name: "XORWconst", reg: gp11, asm: "XORW"}, // arg0 ^ auxint - {name: "XORBconst", reg: gp11, asm: "XORB"}, // arg0 ^ auxint - - {name: "CMPQ", reg: gp2flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to arg1 - {name: "CMPL", reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1 - {name: "CMPW", reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1 - {name: "CMPB", reg: gp2flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to arg1 - {name: "CMPQconst", reg: gp1flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to auxint - {name: "CMPLconst", reg: gp1flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to auxint - {name: "CMPWconst", reg: gp1flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to auxint - {name: "CMPBconst", reg: gp1flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to auxint + {name: "ANDQ", reg: gp21, asm: "ANDQ"}, // arg0 & arg1 + {name: "ANDL", reg: gp21, asm: "ANDL"}, // arg0 & arg1 + {name: "ANDW", reg: gp21, asm: "ANDW"}, // arg0 & arg1 + {name: "ANDB", reg: gp21, asm: "ANDB"}, // arg0 & arg1 + {name: "ANDQconst", reg: gp11, asm: "ANDQ", aux: "Int64"}, // arg0 & auxint + {name: "ANDLconst", reg: gp11, asm: "ANDL", aux: "Int32"}, // arg0 & auxint + {name: "ANDWconst", reg: gp11, asm: "ANDW", aux: "Int16"}, // arg0 & auxint + {name: "ANDBconst", reg: gp11, asm: "ANDB", aux: "Int8"}, // arg0 & auxint + + {name: "ORQ", reg: gp21, asm: "ORQ"}, // arg0 | arg1 + {name: "ORL", reg: gp21, asm: "ORL"}, // arg0 | arg1 + {name: "ORW", reg: gp21, asm: "ORW"}, // arg0 | arg1 + {name: "ORB", reg: gp21, asm: "ORB"}, // arg0 | arg1 + {name: "ORQconst", reg: gp11, asm: "ORQ", aux: "Int64"}, // arg0 | auxint + {name: "ORLconst", reg: gp11, asm: "ORL", aux: "Int32"}, // arg0 | auxint + {name: "ORWconst", reg: gp11, asm: "ORW", aux: "Int16"}, // arg0 | auxint + {name: "ORBconst", reg: gp11, asm: "ORB", aux: "Int8"}, // arg0 | auxint + + {name: "XORQ", reg: gp21, asm: "XORQ"}, // arg0 ^ arg1 + {name: "XORL", reg: gp21, asm: "XORL"}, // arg0 ^ arg1 + {name: "XORW", reg: gp21, asm: "XORW"}, // arg0 ^ arg1 + {name: "XORB", reg: gp21, asm: "XORB"}, // arg0 ^ arg1 + {name: "XORQconst", reg: gp11, asm: "XORQ", aux: "Int64"}, // arg0 ^ auxint + {name: "XORLconst", reg: gp11, asm: "XORL", aux: "Int32"}, // arg0 ^ auxint + {name: "XORWconst", reg: gp11, asm: "XORW", aux: "Int16"}, // arg0 ^ auxint + {name: "XORBconst", reg: gp11, asm: "XORB", aux: "Int8"}, // arg0 ^ auxint + + {name: "CMPQ", reg: gp2flags, asm: "CMPQ", typ: "Flags"}, // arg0 compare to arg1 + {name: "CMPL", reg: gp2flags, asm: "CMPL", typ: "Flags"}, // arg0 compare to arg1 + {name: "CMPW", reg: gp2flags, asm: "CMPW", typ: "Flags"}, // arg0 compare to arg1 + {name: "CMPB", reg: gp2flags, asm: "CMPB", typ: "Flags"}, // arg0 compare to arg1 + {name: "CMPQconst", reg: gp1flags, asm: "CMPQ", typ: "Flags", aux: "Int64"}, // arg0 compare to auxint + {name: "CMPLconst", reg: gp1flags, asm: "CMPL", typ: "Flags", aux: "Int32"}, // arg0 compare to auxint + {name: "CMPWconst", reg: gp1flags, asm: "CMPW", typ: "Flags", aux: "Int16"}, // arg0 compare to auxint + {name: "CMPBconst", reg: gp1flags, asm: "CMPB", typ: "Flags", aux: "Int8"}, // arg0 compare to auxint {name: "UCOMISS", reg: fp2flags, asm: "UCOMISS", typ: "Flags"}, // arg0 compare to arg1, f32 {name: "UCOMISD", reg: fp2flags, asm: "UCOMISD", typ: "Flags"}, // arg0 compare to arg1, f64 - {name: "TESTQ", reg: gp2flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & arg1) compare to 0 - {name: "TESTL", reg: gp2flags, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0 - {name: "TESTW", reg: gp2flags, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0 - {name: "TESTB", reg: gp2flags, asm: "TESTB", typ: "Flags"}, // (arg0 & arg1) compare to 0 - {name: "TESTQconst", reg: gp1flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & auxint) compare to 0 - {name: "TESTLconst", reg: gp1flags, asm: "TESTL", typ: "Flags"}, // (arg0 & auxint) compare to 0 - {name: "TESTWconst", reg: gp1flags, asm: "TESTW", typ: "Flags"}, // (arg0 & auxint) compare to 0 - {name: "TESTBconst", reg: gp1flags, asm: "TESTB", typ: "Flags"}, // (arg0 & auxint) compare to 0 - - {name: "SHLQ", reg: gp21shift, asm: "SHLQ"}, // arg0 << arg1, shift amount is mod 64 - {name: "SHLL", reg: gp21shift, asm: "SHLL"}, // arg0 << arg1, shift amount is mod 32 - {name: "SHLW", reg: gp21shift, asm: "SHLW"}, // arg0 << arg1, shift amount is mod 32 - {name: "SHLB", reg: gp21shift, asm: "SHLB"}, // arg0 << arg1, shift amount is mod 32 - {name: "SHLQconst", reg: gp11, asm: "SHLQ"}, // arg0 << auxint, shift amount 0-63 - {name: "SHLLconst", reg: gp11, asm: "SHLL"}, // arg0 << auxint, shift amount 0-31 - {name: "SHLWconst", reg: gp11, asm: "SHLW"}, // arg0 << auxint, shift amount 0-31 - {name: "SHLBconst", reg: gp11, asm: "SHLB"}, // arg0 << auxint, shift amount 0-31 + {name: "TESTQ", reg: gp2flags, asm: "TESTQ", typ: "Flags"}, // (arg0 & arg1) compare to 0 + {name: "TESTL", reg: gp2flags, asm: "TESTL", typ: "Flags"}, // (arg0 & arg1) compare to 0 + {name: "TESTW", reg: gp2flags, asm: "TESTW", typ: "Flags"}, // (arg0 & arg1) compare to 0 + {name: "TESTB", reg: gp2flags, asm: "TESTB", typ: "Flags"}, // (arg0 & arg1) compare to 0 + {name: "TESTQconst", reg: gp1flags, asm: "TESTQ", typ: "Flags", aux: "Int64"}, // (arg0 & auxint) compare to 0 + {name: "TESTLconst", reg: gp1flags, asm: "TESTL", typ: "Flags", aux: "Int32"}, // (arg0 & auxint) compare to 0 + {name: "TESTWconst", reg: gp1flags, asm: "TESTW", typ: "Flags", aux: "Int16"}, // (arg0 & auxint) compare to 0 + {name: "TESTBconst", reg: gp1flags, asm: "TESTB", typ: "Flags", aux: "Int8"}, // (arg0 & auxint) compare to 0 + + {name: "SHLQ", reg: gp21shift, asm: "SHLQ"}, // arg0 << arg1, shift amount is mod 64 + {name: "SHLL", reg: gp21shift, asm: "SHLL"}, // arg0 << arg1, shift amount is mod 32 + {name: "SHLW", reg: gp21shift, asm: "SHLW"}, // arg0 << arg1, shift amount is mod 32 + {name: "SHLB", reg: gp21shift, asm: "SHLB"}, // arg0 << arg1, shift amount is mod 32 + {name: "SHLQconst", reg: gp11, asm: "SHLQ", aux: "Int64"}, // arg0 << auxint, shift amount 0-63 + {name: "SHLLconst", reg: gp11, asm: "SHLL", aux: "Int32"}, // arg0 << auxint, shift amount 0-31 + {name: "SHLWconst", reg: gp11, asm: "SHLW", aux: "Int16"}, // arg0 << auxint, shift amount 0-31 + {name: "SHLBconst", reg: gp11, asm: "SHLB", aux: "Int8"}, // arg0 << auxint, shift amount 0-31 // Note: x86 is weird, the 16 and 8 byte shifts still use all 5 bits of shift amount! - {name: "SHRQ", reg: gp21shift, asm: "SHRQ"}, // unsigned arg0 >> arg1, shift amount is mod 64 - {name: "SHRL", reg: gp21shift, asm: "SHRL"}, // unsigned arg0 >> arg1, shift amount is mod 32 - {name: "SHRW", reg: gp21shift, asm: "SHRW"}, // unsigned arg0 >> arg1, shift amount is mod 32 - {name: "SHRB", reg: gp21shift, asm: "SHRB"}, // unsigned arg0 >> arg1, shift amount is mod 32 - {name: "SHRQconst", reg: gp11, asm: "SHRQ"}, // unsigned arg0 >> auxint, shift amount 0-63 - {name: "SHRLconst", reg: gp11, asm: "SHRL"}, // unsigned arg0 >> auxint, shift amount 0-31 - {name: "SHRWconst", reg: gp11, asm: "SHRW"}, // unsigned arg0 >> auxint, shift amount 0-31 - {name: "SHRBconst", reg: gp11, asm: "SHRB"}, // unsigned arg0 >> auxint, shift amount 0-31 - - {name: "SARQ", reg: gp21shift, asm: "SARQ"}, // signed arg0 >> arg1, shift amount is mod 64 - {name: "SARL", reg: gp21shift, asm: "SARL"}, // signed arg0 >> arg1, shift amount is mod 32 - {name: "SARW", reg: gp21shift, asm: "SARW"}, // signed arg0 >> arg1, shift amount is mod 32 - {name: "SARB", reg: gp21shift, asm: "SARB"}, // signed arg0 >> arg1, shift amount is mod 32 - {name: "SARQconst", reg: gp11, asm: "SARQ"}, // signed arg0 >> auxint, shift amount 0-63 - {name: "SARLconst", reg: gp11, asm: "SARL"}, // signed arg0 >> auxint, shift amount 0-31 - {name: "SARWconst", reg: gp11, asm: "SARW"}, // signed arg0 >> auxint, shift amount 0-31 - {name: "SARBconst", reg: gp11, asm: "SARB"}, // signed arg0 >> auxint, shift amount 0-31 - - {name: "ROLQconst", reg: gp11, asm: "ROLQ"}, // arg0 rotate left auxint, rotate amount 0-63 - {name: "ROLLconst", reg: gp11, asm: "ROLL"}, // arg0 rotate left auxint, rotate amount 0-31 - {name: "ROLWconst", reg: gp11, asm: "ROLW"}, // arg0 rotate left auxint, rotate amount 0-15 - {name: "ROLBconst", reg: gp11, asm: "ROLB"}, // arg0 rotate left auxint, rotate amount 0-7 + {name: "SHRQ", reg: gp21shift, asm: "SHRQ"}, // unsigned arg0 >> arg1, shift amount is mod 64 + {name: "SHRL", reg: gp21shift, asm: "SHRL"}, // unsigned arg0 >> arg1, shift amount is mod 32 + {name: "SHRW", reg: gp21shift, asm: "SHRW"}, // unsigned arg0 >> arg1, shift amount is mod 32 + {name: "SHRB", reg: gp21shift, asm: "SHRB"}, // unsigned arg0 >> arg1, shift amount is mod 32 + {name: "SHRQconst", reg: gp11, asm: "SHRQ", aux: "Int64"}, // unsigned arg0 >> auxint, shift amount 0-63 + {name: "SHRLconst", reg: gp11, asm: "SHRL", aux: "Int32"}, // unsigned arg0 >> auxint, shift amount 0-31 + {name: "SHRWconst", reg: gp11, asm: "SHRW", aux: "Int16"}, // unsigned arg0 >> auxint, shift amount 0-31 + {name: "SHRBconst", reg: gp11, asm: "SHRB", aux: "Int8"}, // unsigned arg0 >> auxint, shift amount 0-31 + + {name: "SARQ", reg: gp21shift, asm: "SARQ"}, // signed arg0 >> arg1, shift amount is mod 64 + {name: "SARL", reg: gp21shift, asm: "SARL"}, // signed arg0 >> arg1, shift amount is mod 32 + {name: "SARW", reg: gp21shift, asm: "SARW"}, // signed arg0 >> arg1, shift amount is mod 32 + {name: "SARB", reg: gp21shift, asm: "SARB"}, // signed arg0 >> arg1, shift amount is mod 32 + {name: "SARQconst", reg: gp11, asm: "SARQ", aux: "Int64"}, // signed arg0 >> auxint, shift amount 0-63 + {name: "SARLconst", reg: gp11, asm: "SARL", aux: "Int32"}, // signed arg0 >> auxint, shift amount 0-31 + {name: "SARWconst", reg: gp11, asm: "SARW", aux: "Int16"}, // signed arg0 >> auxint, shift amount 0-31 + {name: "SARBconst", reg: gp11, asm: "SARB", aux: "Int8"}, // signed arg0 >> auxint, shift amount 0-31 + + {name: "ROLQconst", reg: gp11, asm: "ROLQ", aux: "Int64"}, // arg0 rotate left auxint, rotate amount 0-63 + {name: "ROLLconst", reg: gp11, asm: "ROLL", aux: "Int32"}, // arg0 rotate left auxint, rotate amount 0-31 + {name: "ROLWconst", reg: gp11, asm: "ROLW", aux: "Int16"}, // arg0 rotate left auxint, rotate amount 0-15 + {name: "ROLBconst", reg: gp11, asm: "ROLB", aux: "Int8"}, // arg0 rotate left auxint, rotate amount 0-7 // unary ops {name: "NEGQ", reg: gp11, asm: "NEGQ"}, // -arg0 @@ -339,10 +339,10 @@ func init() { {name: "MOVLQSX", reg: gp11nf, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64 {name: "MOVLQZX", reg: gp11nf, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64 - {name: "MOVBconst", reg: gp01, asm: "MOVB", typ: "UInt8"}, // 8 low bits of auxint - {name: "MOVWconst", reg: gp01, asm: "MOVW", typ: "UInt16"}, // 16 low bits of auxint - {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32"}, // 32 low bits of auxint - {name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64"}, // auxint + {name: "MOVBconst", reg: gp01, asm: "MOVB", typ: "UInt8", aux: "Int8", rematerializeable: true}, // 8 low bits of auxint + {name: "MOVWconst", reg: gp01, asm: "MOVW", typ: "UInt16", aux: "Int16", rematerializeable: true}, // 16 low bits of auxint + {name: "MOVLconst", reg: gp01, asm: "MOVL", typ: "UInt32", aux: "Int32", rematerializeable: true}, // 32 low bits of auxint + {name: "MOVQconst", reg: gp01, asm: "MOVQ", typ: "UInt64", aux: "Int64", rematerializeable: true}, // auxint {name: "CVTTSD2SL", reg: fpgp, asm: "CVTTSD2SL"}, // convert float64 to int32 {name: "CVTTSD2SQ", reg: fpgp, asm: "CVTTSD2SQ"}, // convert float64 to int64 @@ -357,44 +357,44 @@ func init() { {name: "PXOR", reg: fp21, asm: "PXOR"}, // exclusive or, applied to X regs for float negation. - {name: "LEAQ", reg: gp11sb}, // arg0 + auxint + offset encoded in aux - {name: "LEAQ1", reg: gp21sb}, // arg0 + arg1 + auxint - {name: "LEAQ2", reg: gp21sb}, // arg0 + 2*arg1 + auxint - {name: "LEAQ4", reg: gp21sb}, // arg0 + 4*arg1 + auxint - {name: "LEAQ8", reg: gp21sb}, // arg0 + 8*arg1 + auxint + {name: "LEAQ", reg: gp11sb, aux: "SymOff", rematerializeable: true}, // arg0 + auxint + offset encoded in aux + {name: "LEAQ1", reg: gp21sb, aux: "SymOff"}, // arg0 + arg1 + auxint + aux + {name: "LEAQ2", reg: gp21sb, aux: "SymOff"}, // arg0 + 2*arg1 + auxint + aux + {name: "LEAQ4", reg: gp21sb, aux: "SymOff"}, // arg0 + 4*arg1 + auxint + aux + {name: "LEAQ8", reg: gp21sb, aux: "SymOff"}, // arg0 + 8*arg1 + auxint + aux // auxint+aux == add auxint and the offset of the symbol in aux (if any) to the effective address - {name: "MOVBload", reg: gpload, asm: "MOVB", typ: "UInt8"}, // load byte from arg0+auxint+aux. arg1=mem - {name: "MOVBQSXload", reg: gpload, asm: "MOVBQSX"}, // ditto, extend to int64 - {name: "MOVBQZXload", reg: gpload, asm: "MOVBQZX"}, // ditto, extend to uint64 - {name: "MOVWload", reg: gpload, asm: "MOVW", typ: "UInt16"}, // load 2 bytes from arg0+auxint+aux. arg1=mem - {name: "MOVWQSXload", reg: gpload, asm: "MOVWQSX"}, // ditto, extend to int64 - {name: "MOVWQZXload", reg: gpload, asm: "MOVWQZX"}, // ditto, extend to uint64 - {name: "MOVLload", reg: gpload, asm: "MOVL", typ: "UInt32"}, // load 4 bytes from arg0+auxint+aux. arg1=mem - {name: "MOVLQSXload", reg: gpload, asm: "MOVLQSX"}, // ditto, extend to int64 - {name: "MOVLQZXload", reg: gpload, asm: "MOVLQZX"}, // ditto, extend to uint64 - {name: "MOVQload", reg: gpload, asm: "MOVQ", typ: "UInt64"}, // load 8 bytes from arg0+auxint+aux. arg1=mem - {name: "MOVQloadidx8", reg: gploadidx, asm: "MOVQ"}, // load 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem - {name: "MOVBstore", reg: gpstore, asm: "MOVB", typ: "Mem"}, // store byte in arg1 to arg0+auxint+aux. arg2=mem - {name: "MOVWstore", reg: gpstore, asm: "MOVW", typ: "Mem"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem - {name: "MOVLstore", reg: gpstore, asm: "MOVL", typ: "Mem"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem - {name: "MOVQstore", reg: gpstore, asm: "MOVQ", typ: "Mem"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem - - {name: "MOVBstoreidx1", reg: gpstoreidx, asm: "MOVB"}, // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem - {name: "MOVWstoreidx2", reg: gpstoreidx, asm: "MOVW"}, // store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem - {name: "MOVLstoreidx4", reg: gpstoreidx, asm: "MOVL"}, // store 4 bytes in arg2 to arg0+4*arg1+auxint+aux. arg3=mem - {name: "MOVQstoreidx8", reg: gpstoreidx, asm: "MOVQ"}, // store 8 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem - - {name: "MOVOload", reg: fpload, asm: "MOVUPS", typ: "Int128"}, // load 16 bytes from arg0+auxint+aux. arg1=mem - {name: "MOVOstore", reg: fpstore, asm: "MOVUPS", typ: "Mem"}, // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVBload", reg: gpload, asm: "MOVB", aux: "SymOff", typ: "UInt8"}, // load byte from arg0+auxint+aux. arg1=mem + {name: "MOVBQSXload", reg: gpload, asm: "MOVBQSX", aux: "SymOff"}, // ditto, extend to int64 + {name: "MOVBQZXload", reg: gpload, asm: "MOVBQZX", aux: "SymOff"}, // ditto, extend to uint64 + {name: "MOVWload", reg: gpload, asm: "MOVW", aux: "SymOff", typ: "UInt16"}, // load 2 bytes from arg0+auxint+aux. arg1=mem + {name: "MOVWQSXload", reg: gpload, asm: "MOVWQSX", aux: "SymOff"}, // ditto, extend to int64 + {name: "MOVWQZXload", reg: gpload, asm: "MOVWQZX", aux: "SymOff"}, // ditto, extend to uint64 + {name: "MOVLload", reg: gpload, asm: "MOVL", aux: "SymOff", typ: "UInt32"}, // load 4 bytes from arg0+auxint+aux. arg1=mem + {name: "MOVLQSXload", reg: gpload, asm: "MOVLQSX", aux: "SymOff"}, // ditto, extend to int64 + {name: "MOVLQZXload", reg: gpload, asm: "MOVLQZX", aux: "SymOff"}, // ditto, extend to uint64 + {name: "MOVQload", reg: gpload, asm: "MOVQ", aux: "SymOff", typ: "UInt64"}, // load 8 bytes from arg0+auxint+aux. arg1=mem + {name: "MOVQloadidx8", reg: gploadidx, asm: "MOVQ", aux: "SymOff"}, // load 8 bytes from arg0+8*arg1+auxint+aux. arg2=mem + {name: "MOVBstore", reg: gpstore, asm: "MOVB", aux: "SymOff", typ: "Mem"}, // store byte in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVWstore", reg: gpstore, asm: "MOVW", aux: "SymOff", typ: "Mem"}, // store 2 bytes in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVLstore", reg: gpstore, asm: "MOVL", aux: "SymOff", typ: "Mem"}, // store 4 bytes in arg1 to arg0+auxint+aux. arg2=mem + {name: "MOVQstore", reg: gpstore, asm: "MOVQ", aux: "SymOff", typ: "Mem"}, // store 8 bytes in arg1 to arg0+auxint+aux. arg2=mem + + {name: "MOVBstoreidx1", reg: gpstoreidx, asm: "MOVB", aux: "SymOff"}, // store byte in arg2 to arg0+arg1+auxint+aux. arg3=mem + {name: "MOVWstoreidx2", reg: gpstoreidx, asm: "MOVW", aux: "SymOff"}, // store 2 bytes in arg2 to arg0+2*arg1+auxint+aux. arg3=mem + {name: "MOVLstoreidx4", reg: gpstoreidx, asm: "MOVL", aux: "SymOff"}, // store 4 bytes in arg2 to arg0+4*arg1+auxint+aux. arg3=mem + {name: "MOVQstoreidx8", reg: gpstoreidx, asm: "MOVQ", aux: "SymOff"}, // store 8 bytes in arg2 to arg0+8*arg1+auxint+aux. arg3=mem + + {name: "MOVOload", reg: fpload, asm: "MOVUPS", aux: "SymOff", typ: "Int128"}, // load 16 bytes from arg0+auxint+aux. arg1=mem + {name: "MOVOstore", reg: fpstore, asm: "MOVUPS", aux: "SymOff", typ: "Mem"}, // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem // For storeconst ops, the AuxInt field encodes both // the value to store and an address offset of the store. // Cast AuxInt to a ValAndOff to extract Val and Off fields. - {name: "MOVBstoreconst", reg: gpstoreconst, asm: "MOVB", typ: "Mem"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux. arg1=mem - {name: "MOVWstoreconst", reg: gpstoreconst, asm: "MOVW", typ: "Mem"}, // store low 2 bytes of ... - {name: "MOVLstoreconst", reg: gpstoreconst, asm: "MOVL", typ: "Mem"}, // store low 4 bytes of ... - {name: "MOVQstoreconst", reg: gpstoreconst, asm: "MOVQ", typ: "Mem"}, // store 8 bytes of ... + {name: "MOVBstoreconst", reg: gpstoreconst, asm: "MOVB", aux: "SymValAndOff", typ: "Mem"}, // store low byte of ValAndOff(AuxInt).Val() to arg0+ValAndOff(AuxInt).Off()+aux. arg1=mem + {name: "MOVWstoreconst", reg: gpstoreconst, asm: "MOVW", aux: "SymValAndOff", typ: "Mem"}, // store low 2 bytes of ... + {name: "MOVLstoreconst", reg: gpstoreconst, asm: "MOVL", aux: "SymValAndOff", typ: "Mem"}, // store low 4 bytes of ... + {name: "MOVQstoreconst", reg: gpstoreconst, asm: "MOVQ", aux: "SymValAndOff", typ: "Mem"}, // store 8 bytes of ... // arg0 = (duff-adjusted) pointer to start of memory to zero // arg1 = value to store (will always be zero) @@ -403,12 +403,13 @@ func init() { // returns mem { name: "DUFFZERO", + aux: "Int64", reg: regInfo{ inputs: []regMask{buildReg("DI"), buildReg("X0")}, clobbers: buildReg("DI FLAGS"), }, }, - {name: "MOVOconst", reg: regInfo{nil, 0, []regMask{fp}}, typ: "Int128"}, + {name: "MOVOconst", reg: regInfo{nil, 0, []regMask{fp}}, typ: "Int128", rematerializeable: true}, // arg0 = address of memory to zero // arg1 = # of 8-byte words to zero @@ -423,11 +424,11 @@ func init() { }, }, - {name: "CALLstatic", reg: regInfo{clobbers: callerSave}}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem - {name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, callerSave, nil}}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem - {name: "CALLdefer", reg: regInfo{clobbers: callerSave}}, // call deferproc. arg0=mem, auxint=argsize, returns mem - {name: "CALLgo", reg: regInfo{clobbers: callerSave}}, // call newproc. arg0=mem, auxint=argsize, returns mem - {name: "CALLinter", reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem + {name: "CALLstatic", reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem + {name: "CALLclosure", reg: regInfo{[]regMask{gpsp, buildReg("DX"), 0}, callerSave, nil}, aux: "Int64"}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem + {name: "CALLdefer", reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call deferproc. arg0=mem, auxint=argsize, returns mem + {name: "CALLgo", reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call newproc. arg0=mem, auxint=argsize, returns mem + {name: "CALLinter", reg: regInfo{inputs: []regMask{gp}, clobbers: callerSave}, aux: "Int64"}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem // arg0 = destination pointer // arg1 = source pointer @@ -436,6 +437,7 @@ func init() { // returns memory { name: "DUFFCOPY", + aux: "Int64", reg: regInfo{ inputs: []regMask{buildReg("DI"), buildReg("SI")}, clobbers: buildReg("DI SI X0 FLAGS"), // uses X0 as a temporary diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go index 36dd58cd1d..3c7aa84ee3 100644 --- a/src/cmd/compile/internal/ssa/gen/genericOps.go +++ b/src/cmd/compile/internal/ssa/gen/genericOps.go @@ -148,10 +148,10 @@ var genericOps = []opData{ // for rotates is hashing and crypto code with constant // distance, rotate instructions are only substituted // when arg1 is a constant between 1 and A-1, inclusive. - {name: "Lrot8"}, - {name: "Lrot16"}, - {name: "Lrot32"}, - {name: "Lrot64"}, + {name: "Lrot8", aux: "Int64"}, + {name: "Lrot16", aux: "Int64"}, + {name: "Lrot32", aux: "Int64"}, + {name: "Lrot64", aux: "Int64"}, // 2-input comparisons {name: "Eq8"}, // arg0 == arg1 @@ -247,46 +247,46 @@ var genericOps = []opData{ // constants. Constant values are stored in the aux or // auxint fields. - {name: "ConstBool"}, // auxint is 0 for false and 1 for true - {name: "ConstString"}, // value is aux.(string) - {name: "ConstNil", typ: "BytePtr"}, // nil pointer - {name: "Const8"}, // value is low 8 bits of auxint - {name: "Const16"}, // value is low 16 bits of auxint - {name: "Const32"}, // value is low 32 bits of auxint - {name: "Const64"}, // value is auxint - {name: "Const32F"}, // value is math.Float64frombits(uint64(auxint)) - {name: "Const64F"}, // value is math.Float64frombits(uint64(auxint)) - {name: "ConstInterface"}, // nil interface - {name: "ConstSlice"}, // nil slice + {name: "ConstBool", aux: "Bool"}, // auxint is 0 for false and 1 for true + {name: "ConstString", aux: "String"}, // value is aux.(string) + {name: "ConstNil", typ: "BytePtr"}, // nil pointer + {name: "Const8", aux: "Int8"}, // value is low 8 bits of auxint + {name: "Const16", aux: "Int16"}, // value is low 16 bits of auxint + {name: "Const32", aux: "Int32"}, // value is low 32 bits of auxint + {name: "Const64", aux: "Int64"}, // value is auxint + {name: "Const32F", aux: "Float"}, // value is math.Float64frombits(uint64(auxint)) + {name: "Const64F", aux: "Float"}, // value is math.Float64frombits(uint64(auxint)) + {name: "ConstInterface"}, // nil interface + {name: "ConstSlice"}, // nil slice // Constant-like things - {name: "InitMem"}, // memory input to the function. - {name: "Arg"}, // argument to the function. aux=GCNode of arg, off = offset in that arg. + {name: "InitMem"}, // memory input to the function. + {name: "Arg", aux: "SymOff"}, // argument to the function. aux=GCNode of arg, off = offset in that arg. // The address of a variable. arg0 is the base pointer (SB or SP, depending // on whether it is a global or stack variable). The Aux field identifies the // variable. It will be either an *ExternSymbol (with arg0=SB), *ArgSymbol (arg0=SP), // or *AutoSymbol (arg0=SP). - {name: "Addr"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable. + {name: "Addr", aux: "Sym"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable. {name: "SP"}, // stack pointer {name: "SB", typ: "Uintptr"}, // static base pointer (a.k.a. globals pointer) - {name: "Func"}, // entry address of a function + {name: "Func", aux: "Sym"}, // entry address of a function // Memory operations - {name: "Load"}, // Load from arg0. arg1=memory - {name: "Store", typ: "Mem"}, // Store arg1 to arg0. arg2=memory, auxint=size. Returns memory. - {name: "Move"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size. Returns memory. - {name: "Zero"}, // arg0=destptr, arg1=mem, auxint=size. Returns memory. + {name: "Load"}, // Load from arg0. arg1=memory + {name: "Store", typ: "Mem", aux: "Int64"}, // Store arg1 to arg0. arg2=memory, auxint=size. Returns memory. + {name: "Move", aux: "Int64"}, // arg0=destptr, arg1=srcptr, arg2=mem, auxint=size. Returns memory. + {name: "Zero", aux: "Int64"}, // arg0=destptr, arg1=mem, auxint=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: "ClosureCall"}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory. - {name: "StaticCall"}, // call function aux.(*gc.Sym), arg0=memory. auxint=arg size. Returns memory. - {name: "DeferCall"}, // defer call. arg0=memory, auxint=arg size. Returns memory. - {name: "GoCall"}, // go call. arg0=memory, auxint=arg size. Returns memory. - {name: "InterCall"}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory. + {name: "ClosureCall", aux: "Int64"}, // arg0=code pointer, arg1=context ptr, arg2=memory. auxint=arg size. Returns memory. + {name: "StaticCall", aux: "SymOff"}, // call function aux.(*gc.Sym), arg0=memory. auxint=arg size. Returns memory. + {name: "DeferCall", aux: "Int64"}, // defer call. arg0=memory, auxint=arg size. Returns memory. + {name: "GoCall", aux: "Int64"}, // go call. arg0=memory, auxint=arg size. Returns memory. + {name: "InterCall", aux: "Int64"}, // interface call. arg0=code pointer, arg1=memory, auxint=arg size. Returns memory. // Conversions: signed extensions, zero (unsigned) extensions, truncations {name: "SignExt8to16", typ: "Int16"}, @@ -330,9 +330,9 @@ var genericOps = []opData{ {name: "GetClosurePtr"}, // get closure pointer from dedicated register // 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 + auxint (arg0 and result are pointers) + {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", aux: "Int64"}, // arg0 + auxint (arg0 and result are pointers) // Slices {name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap @@ -356,12 +356,12 @@ var genericOps = []opData{ {name: "IData"}, // arg0=interface, returns data field // Structs - {name: "StructMake0"}, // Returns struct with 0 fields. - {name: "StructMake1"}, // arg0=field0. Returns struct. - {name: "StructMake2"}, // arg0,arg1=field0,field1. Returns struct. - {name: "StructMake3"}, // arg0..2=field0..2. Returns struct. - {name: "StructMake4"}, // arg0..3=field0..3. Returns struct. - {name: "StructSelect"}, // arg0=struct, auxint=field index. Returns the auxint'th field. + {name: "StructMake0"}, // Returns struct with 0 fields. + {name: "StructMake1"}, // arg0=field0. Returns struct. + {name: "StructMake2"}, // arg0,arg1=field0,field1. Returns struct. + {name: "StructMake3"}, // arg0..2=field0..2. Returns struct. + {name: "StructMake4"}, // arg0..3=field0..3. Returns struct. + {name: "StructSelect", aux: "Int64"}, // arg0=struct, auxint=field index. Returns the auxint'th field. // Spill&restore ops for the register allocator. These are // semantically identical to OpCopy; they do not take/return @@ -376,9 +376,9 @@ var genericOps = []opData{ // Unknown value. Used for Values whose values don't matter because they are dead code. {name: "Unknown"}, - {name: "VarDef", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem - {name: "VarKill"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem - {name: "VarLive"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem + {name: "VarDef", aux: "Sym", typ: "Mem"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem + {name: "VarKill", aux: "Sym"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem + {name: "VarLive", aux: "Sym"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem } // kind control successors implicit exit diff --git a/src/cmd/compile/internal/ssa/gen/main.go b/src/cmd/compile/internal/ssa/gen/main.go index c869de82e7..f8f6c8b5f6 100644 --- a/src/cmd/compile/internal/ssa/gen/main.go +++ b/src/cmd/compile/internal/ssa/gen/main.go @@ -26,10 +26,12 @@ type arch struct { } type opData struct { - name string - reg regInfo - asm string - typ string // default result type + name string + reg regInfo + asm string + typ string // default result type + aux string + rematerializeable bool } type blockData struct { @@ -117,6 +119,17 @@ func genOp() { for _, v := range a.ops { fmt.Fprintln(w, "{") fmt.Fprintf(w, "name:\"%s\",\n", v.name) + + // flags + if v.aux != "" { + fmt.Fprintf(w, "auxType: aux%s,\n", v.aux) + } + if v.rematerializeable { + if v.reg.clobbers != 0 { + log.Fatalf("%s is rematerializeable and clobbers registers", v.name) + } + fmt.Fprintln(w, "rematerializeable: true,") + } if a.name == "generic" { fmt.Fprintln(w, "generic:true,") fmt.Fprintln(w, "},") // close op diff --git a/src/cmd/compile/internal/ssa/nilcheck_test.go b/src/cmd/compile/internal/ssa/nilcheck_test.go index c4aff58d76..14955e77d8 100644 --- a/src/cmd/compile/internal/ssa/nilcheck_test.go +++ b/src/cmd/compile/internal/ssa/nilcheck_test.go @@ -21,7 +21,7 @@ func benchmarkNilCheckDeep(b *testing.B, depth int) { var blocs []bloc blocs = append(blocs, Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto(blockn(0)), ), @@ -67,7 +67,7 @@ func TestNilcheckSimple(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -104,7 +104,7 @@ func TestNilcheckDomOrder(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -140,7 +140,7 @@ func TestNilcheckAddr(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -173,7 +173,7 @@ func TestNilcheckAddPtr(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -207,7 +207,7 @@ func TestNilcheckPhi(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("sp", OpSP, TypeInvalid, 0, nil), Valu("baddr", OpAddr, TypeBool, 0, "b", "sp"), @@ -251,7 +251,7 @@ func TestNilcheckKeepRemove(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -299,7 +299,7 @@ func TestNilcheckInFalseBranch(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -350,7 +350,7 @@ func TestNilcheckUser(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", @@ -389,7 +389,7 @@ func TestNilcheckBug(t *testing.T) { c := NewConfig("amd64", DummyFrontend{t}, nil, true) fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto("checkPtr")), Bloc("checkPtr", diff --git a/src/cmd/compile/internal/ssa/op.go b/src/cmd/compile/internal/ssa/op.go index 526722f7bc..a868fdbb6f 100644 --- a/src/cmd/compile/internal/ssa/op.go +++ b/src/cmd/compile/internal/ssa/op.go @@ -15,10 +15,12 @@ import "fmt" type Op int32 type opInfo struct { - name string - asm int - reg regInfo - generic bool // this is a generic (arch-independent) opcode + name string + asm int + reg regInfo + auxType auxType + generic bool // this is a generic (arch-independent) opcode + rematerializeable bool // this op is rematerializeable } type inputInfo struct { @@ -32,6 +34,22 @@ type regInfo struct { outputs []regMask // NOTE: values can only have 1 output for now. } +type auxType int8 + +const ( + auxNone auxType = iota + auxBool // auxInt is 0/1 for false/true + auxInt8 // auxInt is an 8-bit integer + auxInt16 // auxInt is a 16-bit integer + auxInt32 // auxInt is a 32-bit integer + auxInt64 // auxInt is a 64-bit integer + auxFloat // auxInt is a float64 (encoded with math.Float64bits) + auxString // auxInt is a string + auxSym // aux is a symbol + auxSymOff // aux is a symbol, auxInt is an offset + auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff +) + // A ValAndOff is used by the several opcodes. It holds // both a value and a pointer offset. // A ValAndOff is intended to be encoded into an AuxInt field. diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 8c6c731969..089adfdec2 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -680,8 +680,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSSload", - asm: x86.AMOVSS, + name: "MOVSSload", + auxType: auxSymOff, + asm: x86.AMOVSS, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -692,8 +693,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSDload", - asm: x86.AMOVSD, + name: "MOVSDload", + auxType: auxSymOff, + asm: x86.AMOVSD, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -704,8 +706,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSSconst", - asm: x86.AMOVSS, + name: "MOVSSconst", + auxType: auxFloat, + rematerializeable: true, + asm: x86.AMOVSS, reg: regInfo{ outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -713,8 +717,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSDconst", - asm: x86.AMOVSD, + name: "MOVSDconst", + auxType: auxFloat, + rematerializeable: true, + asm: x86.AMOVSD, reg: regInfo{ outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -722,8 +728,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSSloadidx4", - asm: x86.AMOVSS, + name: "MOVSSloadidx4", + auxType: auxSymOff, + asm: x86.AMOVSS, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -735,8 +742,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSDloadidx8", - asm: x86.AMOVSD, + name: "MOVSDloadidx8", + auxType: auxSymOff, + asm: x86.AMOVSD, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -748,8 +756,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSSstore", - asm: x86.AMOVSS, + name: "MOVSSstore", + auxType: auxSymOff, + asm: x86.AMOVSS, reg: regInfo{ inputs: []inputInfo{ {1, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -758,8 +767,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSDstore", - asm: x86.AMOVSD, + name: "MOVSDstore", + auxType: auxSymOff, + asm: x86.AMOVSD, reg: regInfo{ inputs: []inputInfo{ {1, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -768,8 +778,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSSstoreidx4", - asm: x86.AMOVSS, + name: "MOVSSstoreidx4", + auxType: auxSymOff, + asm: x86.AMOVSS, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -779,8 +790,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVSDstoreidx8", - asm: x86.AMOVSD, + name: "MOVSDstoreidx8", + auxType: auxSymOff, + asm: x86.AMOVSD, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -846,8 +858,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDQconst", - asm: x86.AADDQ, + name: "ADDQconst", + auxType: auxInt64, + asm: x86.AADDQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -859,8 +872,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDLconst", - asm: x86.AADDL, + name: "ADDLconst", + auxType: auxInt32, + asm: x86.AADDL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -872,8 +886,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDWconst", - asm: x86.AADDW, + name: "ADDWconst", + auxType: auxInt16, + asm: x86.AADDW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -885,8 +900,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ADDBconst", - asm: x86.AADDB, + name: "ADDBconst", + auxType: auxInt8, + asm: x86.AADDB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -954,8 +970,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBQconst", - asm: x86.ASUBQ, + name: "SUBQconst", + auxType: auxInt64, + asm: x86.ASUBQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -967,8 +984,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBLconst", - asm: x86.ASUBL, + name: "SUBLconst", + auxType: auxInt32, + asm: x86.ASUBL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -980,8 +998,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBWconst", - asm: x86.ASUBW, + name: "SUBWconst", + auxType: auxInt16, + asm: x86.ASUBW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -993,8 +1012,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SUBBconst", - asm: x86.ASUBB, + name: "SUBBconst", + auxType: auxInt8, + asm: x86.ASUBB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1062,8 +1082,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULQconst", - asm: x86.AIMULQ, + name: "MULQconst", + auxType: auxInt64, + asm: x86.AIMULQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1075,8 +1096,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULLconst", - asm: x86.AIMULL, + name: "MULLconst", + auxType: auxInt32, + asm: x86.AIMULL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1088,8 +1110,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULWconst", - asm: x86.AIMULW, + name: "MULWconst", + auxType: auxInt16, + asm: x86.AIMULW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1101,8 +1124,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MULBconst", - asm: x86.AIMULW, + name: "MULBconst", + auxType: auxInt8, + asm: x86.AIMULW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1422,8 +1446,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDQconst", - asm: x86.AANDQ, + name: "ANDQconst", + auxType: auxInt64, + asm: x86.AANDQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1435,8 +1460,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDLconst", - asm: x86.AANDL, + name: "ANDLconst", + auxType: auxInt32, + asm: x86.AANDL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1448,8 +1474,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDWconst", - asm: x86.AANDW, + name: "ANDWconst", + auxType: auxInt16, + asm: x86.AANDW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1461,8 +1488,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ANDBconst", - asm: x86.AANDB, + name: "ANDBconst", + auxType: auxInt8, + asm: x86.AANDB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1530,8 +1558,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORQconst", - asm: x86.AORQ, + name: "ORQconst", + auxType: auxInt64, + asm: x86.AORQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1543,8 +1572,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORLconst", - asm: x86.AORL, + name: "ORLconst", + auxType: auxInt32, + asm: x86.AORL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1556,8 +1586,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORWconst", - asm: x86.AORW, + name: "ORWconst", + auxType: auxInt16, + asm: x86.AORW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1569,8 +1600,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ORBconst", - asm: x86.AORB, + name: "ORBconst", + auxType: auxInt8, + asm: x86.AORB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1638,8 +1670,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORQconst", - asm: x86.AXORQ, + name: "XORQconst", + auxType: auxInt64, + asm: x86.AXORQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1651,8 +1684,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORLconst", - asm: x86.AXORL, + name: "XORLconst", + auxType: auxInt32, + asm: x86.AXORL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1664,8 +1698,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORWconst", - asm: x86.AXORW, + name: "XORWconst", + auxType: auxInt16, + asm: x86.AXORW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1677,8 +1712,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "XORBconst", - asm: x86.AXORB, + name: "XORBconst", + auxType: auxInt8, + asm: x86.AXORB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1742,8 +1778,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMPQconst", - asm: x86.ACMPQ, + name: "CMPQconst", + auxType: auxInt64, + asm: x86.ACMPQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1754,8 +1791,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMPLconst", - asm: x86.ACMPL, + name: "CMPLconst", + auxType: auxInt32, + asm: x86.ACMPL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1766,8 +1804,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMPWconst", - asm: x86.ACMPW, + name: "CMPWconst", + auxType: auxInt16, + asm: x86.ACMPW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1778,8 +1817,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CMPBconst", - asm: x86.ACMPB, + name: "CMPBconst", + auxType: auxInt8, + asm: x86.ACMPB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1868,8 +1908,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "TESTQconst", - asm: x86.ATESTQ, + name: "TESTQconst", + auxType: auxInt64, + asm: x86.ATESTQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1880,8 +1921,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "TESTLconst", - asm: x86.ATESTL, + name: "TESTLconst", + auxType: auxInt32, + asm: x86.ATESTL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1892,8 +1934,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "TESTWconst", - asm: x86.ATESTW, + name: "TESTWconst", + auxType: auxInt16, + asm: x86.ATESTW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1904,8 +1947,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "TESTBconst", - asm: x86.ATESTB, + name: "TESTBconst", + auxType: auxInt8, + asm: x86.ATESTB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1972,8 +2016,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLQconst", - asm: x86.ASHLQ, + name: "SHLQconst", + auxType: auxInt64, + asm: x86.ASHLQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1985,8 +2030,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLLconst", - asm: x86.ASHLL, + name: "SHLLconst", + auxType: auxInt32, + asm: x86.ASHLL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -1998,8 +2044,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLWconst", - asm: x86.ASHLW, + name: "SHLWconst", + auxType: auxInt16, + asm: x86.ASHLW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2011,8 +2058,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHLBconst", - asm: x86.ASHLB, + name: "SHLBconst", + auxType: auxInt8, + asm: x86.ASHLB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2080,8 +2128,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRQconst", - asm: x86.ASHRQ, + name: "SHRQconst", + auxType: auxInt64, + asm: x86.ASHRQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2093,8 +2142,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRLconst", - asm: x86.ASHRL, + name: "SHRLconst", + auxType: auxInt32, + asm: x86.ASHRL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2106,8 +2156,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRWconst", - asm: x86.ASHRW, + name: "SHRWconst", + auxType: auxInt16, + asm: x86.ASHRW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2119,8 +2170,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SHRBconst", - asm: x86.ASHRB, + name: "SHRBconst", + auxType: auxInt8, + asm: x86.ASHRB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2188,8 +2240,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARQconst", - asm: x86.ASARQ, + name: "SARQconst", + auxType: auxInt64, + asm: x86.ASARQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2201,8 +2254,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARLconst", - asm: x86.ASARL, + name: "SARLconst", + auxType: auxInt32, + asm: x86.ASARL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2214,8 +2268,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARWconst", - asm: x86.ASARW, + name: "SARWconst", + auxType: auxInt16, + asm: x86.ASARW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2227,8 +2282,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "SARBconst", - asm: x86.ASARB, + name: "SARBconst", + auxType: auxInt8, + asm: x86.ASARB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2240,8 +2296,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ROLQconst", - asm: x86.AROLQ, + name: "ROLQconst", + auxType: auxInt64, + asm: x86.AROLQ, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2253,8 +2310,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ROLLconst", - asm: x86.AROLL, + name: "ROLLconst", + auxType: auxInt32, + asm: x86.AROLL, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2266,8 +2324,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ROLWconst", - asm: x86.AROLW, + name: "ROLWconst", + auxType: auxInt16, + asm: x86.AROLW, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2279,8 +2338,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "ROLBconst", - asm: x86.AROLB, + name: "ROLBconst", + auxType: auxInt8, + asm: x86.AROLB, reg: regInfo{ inputs: []inputInfo{ {0, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2698,8 +2758,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBconst", - asm: x86.AMOVB, + name: "MOVBconst", + auxType: auxInt8, + rematerializeable: true, + asm: x86.AMOVB, reg: regInfo{ outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2707,8 +2769,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWconst", - asm: x86.AMOVW, + name: "MOVWconst", + auxType: auxInt16, + rematerializeable: true, + asm: x86.AMOVW, reg: regInfo{ outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2716,8 +2780,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLconst", - asm: x86.AMOVL, + name: "MOVLconst", + auxType: auxInt32, + rematerializeable: true, + asm: x86.AMOVL, reg: regInfo{ outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2725,8 +2791,10 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVQconst", - asm: x86.AMOVQ, + name: "MOVQconst", + auxType: auxInt64, + rematerializeable: true, + asm: x86.AMOVQ, reg: regInfo{ outputs: []regMask{ 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2867,7 +2935,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAQ", + name: "LEAQ", + auxType: auxSymOff, + rematerializeable: true, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -2878,7 +2948,8 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAQ1", + name: "LEAQ1", + auxType: auxSymOff, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2890,7 +2961,8 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAQ2", + name: "LEAQ2", + auxType: auxSymOff, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2902,7 +2974,8 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAQ4", + name: "LEAQ4", + auxType: auxSymOff, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2914,7 +2987,8 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "LEAQ8", + name: "LEAQ8", + auxType: auxSymOff, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -2926,8 +3000,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBload", - asm: x86.AMOVB, + name: "MOVBload", + auxType: auxSymOff, + asm: x86.AMOVB, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -2938,8 +3013,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBQSXload", - asm: x86.AMOVBQSX, + name: "MOVBQSXload", + auxType: auxSymOff, + asm: x86.AMOVBQSX, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -2950,8 +3026,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBQZXload", - asm: x86.AMOVBQZX, + name: "MOVBQZXload", + auxType: auxSymOff, + asm: x86.AMOVBQZX, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -2962,8 +3039,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWload", - asm: x86.AMOVW, + name: "MOVWload", + auxType: auxSymOff, + asm: x86.AMOVW, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -2974,8 +3052,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWQSXload", - asm: x86.AMOVWQSX, + name: "MOVWQSXload", + auxType: auxSymOff, + asm: x86.AMOVWQSX, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -2986,8 +3065,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWQZXload", - asm: x86.AMOVWQZX, + name: "MOVWQZXload", + auxType: auxSymOff, + asm: x86.AMOVWQZX, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -2998,8 +3078,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLload", - asm: x86.AMOVL, + name: "MOVLload", + auxType: auxSymOff, + asm: x86.AMOVL, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -3010,8 +3091,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLQSXload", - asm: x86.AMOVLQSX, + name: "MOVLQSXload", + auxType: auxSymOff, + asm: x86.AMOVLQSX, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -3022,8 +3104,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLQZXload", - asm: x86.AMOVLQZX, + name: "MOVLQZXload", + auxType: auxSymOff, + asm: x86.AMOVLQZX, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -3034,8 +3117,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVQload", - asm: x86.AMOVQ, + name: "MOVQload", + auxType: auxSymOff, + asm: x86.AMOVQ, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -3046,8 +3130,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVQloadidx8", - asm: x86.AMOVQ, + name: "MOVQloadidx8", + auxType: auxSymOff, + asm: x86.AMOVQ, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3059,8 +3144,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBstore", - asm: x86.AMOVB, + name: "MOVBstore", + auxType: auxSymOff, + asm: x86.AMOVB, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3069,8 +3155,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWstore", - asm: x86.AMOVW, + name: "MOVWstore", + auxType: auxSymOff, + asm: x86.AMOVW, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3079,8 +3166,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLstore", - asm: x86.AMOVL, + name: "MOVLstore", + auxType: auxSymOff, + asm: x86.AMOVL, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3089,8 +3177,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVQstore", - asm: x86.AMOVQ, + name: "MOVQstore", + auxType: auxSymOff, + asm: x86.AMOVQ, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3099,8 +3188,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBstoreidx1", - asm: x86.AMOVB, + name: "MOVBstoreidx1", + auxType: auxSymOff, + asm: x86.AMOVB, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3110,8 +3200,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWstoreidx2", - asm: x86.AMOVW, + name: "MOVWstoreidx2", + auxType: auxSymOff, + asm: x86.AMOVW, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3121,8 +3212,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLstoreidx4", - asm: x86.AMOVL, + name: "MOVLstoreidx4", + auxType: auxSymOff, + asm: x86.AMOVL, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3132,8 +3224,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVQstoreidx8", - asm: x86.AMOVQ, + name: "MOVQstoreidx8", + auxType: auxSymOff, + asm: x86.AMOVQ, reg: regInfo{ inputs: []inputInfo{ {1, 65535}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3143,8 +3236,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVOload", - asm: x86.AMOVUPS, + name: "MOVOload", + auxType: auxSymOff, + asm: x86.AMOVUPS, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -3155,8 +3249,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVOstore", - asm: x86.AMOVUPS, + name: "MOVOstore", + auxType: auxSymOff, + asm: x86.AMOVUPS, reg: regInfo{ inputs: []inputInfo{ {1, 4294901760}, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -3165,8 +3260,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVBstoreconst", - asm: x86.AMOVB, + name: "MOVBstoreconst", + auxType: auxSymValAndOff, + asm: x86.AMOVB, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -3174,8 +3270,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVWstoreconst", - asm: x86.AMOVW, + name: "MOVWstoreconst", + auxType: auxSymValAndOff, + asm: x86.AMOVW, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -3183,8 +3280,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVLstoreconst", - asm: x86.AMOVL, + name: "MOVLstoreconst", + auxType: auxSymValAndOff, + asm: x86.AMOVL, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -3192,8 +3290,9 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVQstoreconst", - asm: x86.AMOVQ, + name: "MOVQstoreconst", + auxType: auxSymValAndOff, + asm: x86.AMOVQ, reg: regInfo{ inputs: []inputInfo{ {0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB @@ -3201,7 +3300,8 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DUFFZERO", + name: "DUFFZERO", + auxType: auxInt64, reg: regInfo{ inputs: []inputInfo{ {0, 128}, // .DI @@ -3211,7 +3311,8 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "MOVOconst", + name: "MOVOconst", + rematerializeable: true, reg: regInfo{ outputs: []regMask{ 4294901760, // .X0 .X1 .X2 .X3 .X4 .X5 .X6 .X7 .X8 .X9 .X10 .X11 .X12 .X13 .X14 .X15 @@ -3230,13 +3331,15 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CALLstatic", + name: "CALLstatic", + auxType: auxSymOff, reg: regInfo{ clobbers: 12884901871, // .AX .CX .DX .BX .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 .FLAGS }, }, { - name: "CALLclosure", + name: "CALLclosure", + auxType: auxInt64, reg: regInfo{ inputs: []inputInfo{ {1, 4}, // .DX @@ -3246,19 +3349,22 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "CALLdefer", + name: "CALLdefer", + auxType: auxInt64, reg: regInfo{ clobbers: 12884901871, // .AX .CX .DX .BX .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 .FLAGS }, }, { - name: "CALLgo", + name: "CALLgo", + auxType: auxInt64, reg: regInfo{ clobbers: 12884901871, // .AX .CX .DX .BX .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 .FLAGS }, }, { - name: "CALLinter", + name: "CALLinter", + auxType: auxInt64, reg: regInfo{ inputs: []inputInfo{ {0, 65519}, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 @@ -3267,7 +3373,8 @@ var opcodeTable = [...]opInfo{ }, }, { - name: "DUFFCOPY", + name: "DUFFCOPY", + auxType: auxInt64, reg: regInfo{ inputs: []inputInfo{ {0, 128}, // .DI @@ -3767,18 +3874,22 @@ var opcodeTable = [...]opInfo{ }, { name: "Lrot8", + auxType: auxInt64, generic: true, }, { name: "Lrot16", + auxType: auxInt64, generic: true, }, { name: "Lrot32", + auxType: auxInt64, generic: true, }, { name: "Lrot64", + auxType: auxInt64, generic: true, }, { @@ -4075,10 +4186,12 @@ var opcodeTable = [...]opInfo{ }, { name: "ConstBool", + auxType: auxBool, generic: true, }, { name: "ConstString", + auxType: auxString, generic: true, }, { @@ -4087,26 +4200,32 @@ var opcodeTable = [...]opInfo{ }, { name: "Const8", + auxType: auxInt8, generic: true, }, { name: "Const16", + auxType: auxInt16, generic: true, }, { name: "Const32", + auxType: auxInt32, generic: true, }, { name: "Const64", + auxType: auxInt64, generic: true, }, { name: "Const32F", + auxType: auxFloat, generic: true, }, { name: "Const64F", + auxType: auxFloat, generic: true, }, { @@ -4123,10 +4242,12 @@ var opcodeTable = [...]opInfo{ }, { name: "Arg", + auxType: auxSymOff, generic: true, }, { name: "Addr", + auxType: auxSym, generic: true, }, { @@ -4139,6 +4260,7 @@ var opcodeTable = [...]opInfo{ }, { name: "Func", + auxType: auxSym, generic: true, }, { @@ -4147,34 +4269,42 @@ var opcodeTable = [...]opInfo{ }, { name: "Store", + auxType: auxInt64, generic: true, }, { name: "Move", + auxType: auxInt64, generic: true, }, { name: "Zero", + auxType: auxInt64, generic: true, }, { name: "ClosureCall", + auxType: auxInt64, generic: true, }, { name: "StaticCall", + auxType: auxSymOff, generic: true, }, { name: "DeferCall", + auxType: auxInt64, generic: true, }, { name: "GoCall", + auxType: auxInt64, generic: true, }, { name: "InterCall", + auxType: auxInt64, generic: true, }, { @@ -4323,6 +4453,7 @@ var opcodeTable = [...]opInfo{ }, { name: "OffPtr", + auxType: auxInt64, generic: true, }, { @@ -4399,6 +4530,7 @@ var opcodeTable = [...]opInfo{ }, { name: "StructSelect", + auxType: auxInt64, generic: true, }, { @@ -4419,14 +4551,17 @@ var opcodeTable = [...]opInfo{ }, { name: "VarDef", + auxType: auxSym, generic: true, }, { name: "VarKill", + auxType: auxSym, generic: true, }, { name: "VarLive", + auxType: auxSym, generic: true, }, } diff --git a/src/cmd/compile/internal/ssa/passbm_test.go b/src/cmd/compile/internal/ssa/passbm_test.go index 9b11ff1256..8dff17a5b4 100644 --- a/src/cmd/compile/internal/ssa/passbm_test.go +++ b/src/cmd/compile/internal/ssa/passbm_test.go @@ -68,7 +68,7 @@ func genFunction(size int) []bloc { valn := func(s string, m, n int) string { return fmt.Sprintf("%s%d-%d", s, m, n) } blocs = append(blocs, Bloc("entry", - Valu(valn("store", 0, 4), OpArg, TypeMem, 0, ".mem"), + Valu(valn("store", 0, 4), OpInitMem, TypeMem, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil), Goto(blockn(1)), ), diff --git a/src/cmd/compile/internal/ssa/regalloc.go b/src/cmd/compile/internal/ssa/regalloc.go index e1f8dd1935..bfb6f7da76 100644 --- a/src/cmd/compile/internal/ssa/regalloc.go +++ b/src/cmd/compile/internal/ssa/regalloc.go @@ -1481,31 +1481,16 @@ func (e *edgeState) findRegFor(typ Type) Location { } func (v *Value) rematerializeable() bool { - // TODO: add a flags field to opInfo for this test? - regspec := opcodeTable[v.Op].reg - - // rematerializeable ops must be able to fill any register. - outputs := regspec.outputs - if len(outputs) == 0 || countRegs(outputs[0]) <= 1 { - // Note: this case handles OpAMD64LoweredGetClosurePtr - // which can't be moved. + if !opcodeTable[v.Op].rematerializeable { return false } - - // We can't rematerialize instructions which - // clobber the flags register. - if regspec.clobbers&flagRegMask != 0 { - return false - } - - if len(v.Args) == 0 { - return true - } - if len(v.Args) == 1 && (v.Args[0].Op == OpSP || v.Args[0].Op == OpSB) { + for _, a := range v.Args { // SP and SB (generated by OpSP and OpSB) are always available. - return true + if a.Op != OpSP && a.Op != OpSB { + return false + } } - return false + return true } type liveInfo struct { diff --git a/src/cmd/compile/internal/ssa/regalloc_test.go b/src/cmd/compile/internal/ssa/regalloc_test.go index 596a920858..6f3f690f1e 100644 --- a/src/cmd/compile/internal/ssa/regalloc_test.go +++ b/src/cmd/compile/internal/ssa/regalloc_test.go @@ -10,9 +10,9 @@ func TestLiveControlOps(t *testing.T) { c := testConfig(t) f := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), - Valu("x", OpAMD64MOVBconst, TypeInt8, 0, 1), - Valu("y", OpAMD64MOVBconst, TypeInt8, 0, 2), + Valu("mem", OpInitMem, TypeMem, 0, nil), + Valu("x", OpAMD64MOVBconst, TypeInt8, 1, nil), + Valu("y", OpAMD64MOVBconst, TypeInt8, 2, nil), Valu("a", OpAMD64TESTB, TypeFlags, 0, nil, "x", "y"), Valu("b", OpAMD64TESTB, TypeFlags, 0, nil, "y", "x"), Eq("a", "if", "exit"), diff --git a/src/cmd/compile/internal/ssa/schedule_test.go b/src/cmd/compile/internal/ssa/schedule_test.go index 30c029ef7c..0ff57e3689 100644 --- a/src/cmd/compile/internal/ssa/schedule_test.go +++ b/src/cmd/compile/internal/ssa/schedule_test.go @@ -11,7 +11,7 @@ func TestSchedule(t *testing.T) { cases := []fun{ Fun(c, "entry", Bloc("entry", - Valu("mem0", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem0", OpInitMem, TypeMem, 0, nil), Valu("ptr", OpConst64, TypeInt64, 0xABCD, nil), Valu("v", OpConst64, TypeInt64, 12, nil), Valu("mem1", OpStore, TypeMem, 8, nil, "ptr", "v", "mem0"), diff --git a/src/cmd/compile/internal/ssa/shift_test.go b/src/cmd/compile/internal/ssa/shift_test.go index 68d5f2ef70..8d5e62f070 100644 --- a/src/cmd/compile/internal/ssa/shift_test.go +++ b/src/cmd/compile/internal/ssa/shift_test.go @@ -34,7 +34,7 @@ func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun { ptyp := &TypeImpl{Size_: 8, Ptr: true, Name: "ptr"} fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("SP", OpSP, TypeUInt64, 0, nil), Valu("argptr", OpOffPtr, ptyp, 8, nil, "SP"), Valu("resptr", OpOffPtr, ptyp, 16, nil, "SP"), diff --git a/src/cmd/compile/internal/ssa/shortcircuit_test.go b/src/cmd/compile/internal/ssa/shortcircuit_test.go index d518dfbabf..f208801fc1 100644 --- a/src/cmd/compile/internal/ssa/shortcircuit_test.go +++ b/src/cmd/compile/internal/ssa/shortcircuit_test.go @@ -11,7 +11,7 @@ func TestShortCircuit(t *testing.T) { fun := Fun(c, "entry", Bloc("entry", - Valu("mem", OpInitMem, TypeMem, 0, ".mem"), + Valu("mem", OpInitMem, TypeMem, 0, nil), Valu("arg1", OpArg, TypeInt64, 0, nil), Valu("arg2", OpArg, TypeInt64, 0, nil), Valu("arg3", OpArg, TypeInt64, 0, nil), diff --git a/src/cmd/compile/internal/ssa/value.go b/src/cmd/compile/internal/ssa/value.go index e338c4435b..af6bb3b97e 100644 --- a/src/cmd/compile/internal/ssa/value.go +++ b/src/cmd/compile/internal/ssa/value.go @@ -57,34 +57,72 @@ func (v *Value) String() string { return fmt.Sprintf("v%d", v.ID) } +func (v *Value) AuxInt8() int8 { + if opcodeTable[v.Op].auxType != auxInt8 { + v.Fatalf("op %s doesn't have an int8 aux field", v.Op) + } + return int8(v.AuxInt) +} + +func (v *Value) AuxInt16() int16 { + if opcodeTable[v.Op].auxType != auxInt16 { + v.Fatalf("op %s doesn't have an int16 aux field", v.Op) + } + return int16(v.AuxInt) +} + +func (v *Value) AuxInt32() int32 { + if opcodeTable[v.Op].auxType != auxInt32 { + v.Fatalf("op %s doesn't have an int32 aux field", v.Op) + } + return int32(v.AuxInt) +} +func (v *Value) AuxFloat() float64 { + if opcodeTable[v.Op].auxType != auxFloat { + v.Fatalf("op %s doesn't have a float aux field", v.Op) + } + return math.Float64frombits(uint64(v.AuxInt)) +} +func (v *Value) AuxValAndOff() ValAndOff { + if opcodeTable[v.Op].auxType != auxSymValAndOff { + v.Fatalf("op %s doesn't have a ValAndOff aux field", v.Op) + } + return ValAndOff(v.AuxInt) +} + // long form print. v# = opcode [aux] args [: reg] func (v *Value) LongString() string { s := fmt.Sprintf("v%d = %s", v.ID, v.Op.String()) s += " <" + v.Type.String() + ">" - // TODO: use some operator property flags to decide - // what is encoded in the AuxInt field. - switch v.Op { - case OpConst32F, OpConst64F: - s += fmt.Sprintf(" [%g]", math.Float64frombits(uint64(v.AuxInt))) - case OpConstBool: + switch opcodeTable[v.Op].auxType { + case auxBool: if v.AuxInt == 0 { s += " [false]" } else { s += " [true]" } - case OpAMD64MOVBstoreconst, OpAMD64MOVWstoreconst, OpAMD64MOVLstoreconst, OpAMD64MOVQstoreconst: - s += fmt.Sprintf(" [%s]", ValAndOff(v.AuxInt)) - default: - if v.AuxInt != 0 { - s += fmt.Sprintf(" [%d]", v.AuxInt) + case auxInt8: + s += fmt.Sprintf(" [%d]", v.AuxInt8()) + case auxInt16: + s += fmt.Sprintf(" [%d]", v.AuxInt16()) + case auxInt32: + s += fmt.Sprintf(" [%d]", v.AuxInt32()) + case auxInt64: + s += fmt.Sprintf(" [%d]", v.AuxInt) + case auxFloat: + s += fmt.Sprintf(" [%g]", v.AuxFloat()) + case auxString: + s += fmt.Sprintf(" {%s}", v.Aux) + case auxSymOff: + if v.Aux != nil { + s += fmt.Sprintf(" {%s}", v.Aux) } - } - if v.Aux != nil { - if _, ok := v.Aux.(string); ok { - s += fmt.Sprintf(" {%q}", v.Aux) - } else { - s += fmt.Sprintf(" {%v}", v.Aux) + s += fmt.Sprintf(" [%s]", v.AuxInt) + case auxSymValAndOff: + if v.Aux != nil { + s += fmt.Sprintf(" {%s}", v.Aux) } + s += fmt.Sprintf(" [%s]", v.AuxValAndOff()) } for _, a := range v.Args { s += fmt.Sprintf(" %v", a) -- cgit v1.3