1
0
mirror of https://github.com/golang/go synced 2024-10-05 11:41:22 -06:00

[dev.ssa] cmd/compile: clean up comparisons

Add new constant-flags opcodes.  These can be generated from
comparisons that we know the result of, like x&31 < 32.

Constant-fold the constant-flags opcodes into all flag users.

Reorder some CMPxconst args so they read in the comparison direction.

Reorg deadcode removal a bit - it needs to remove the OpCopy ops it
generates when strength-reducing Phi ops.  So it needs to splice out all
the dead blocks and do a copy elimination before it computes live
values.

Change-Id: Ie922602033592ad8212efe4345394973d3b94d9f
Reviewed-on: https://go-review.googlesource.com/18267
Run-TryBot: Keith Randall <khr@golang.org>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Keith Randall 2016-01-05 14:56:26 -08:00
parent 9094e3ada2
commit 3425295e91
8 changed files with 2974 additions and 636 deletions

View File

@ -4108,6 +4108,8 @@ func (s *genState) genValue(v *ssa.Value) {
case ssa.OpAMD64InvertFlags: case ssa.OpAMD64InvertFlags:
v.Fatalf("InvertFlags should never make it to codegen %v", v) v.Fatalf("InvertFlags should never make it to codegen %v", v)
case ssa.OpAMD64FlagEQ, ssa.OpAMD64FlagLT_ULT, ssa.OpAMD64FlagLT_UGT, ssa.OpAMD64FlagGT_ULT, ssa.OpAMD64FlagGT_UGT:
v.Fatalf("Flag* ops should never make it to codegen %v", v)
case ssa.OpAMD64REPSTOSQ: case ssa.OpAMD64REPSTOSQ:
Prog(x86.AREP) Prog(x86.AREP)
Prog(x86.ASTOSQ) Prog(x86.ASTOSQ)

View File

@ -26,4 +26,18 @@ func copyelim(f *Func) {
b.Control = v b.Control = v
} }
} }
// Update named values.
for _, name := range f.Names {
values := f.NamedValues[name]
for i, v := range values {
x := v
for x.Op == OpCopy {
x = x.Args[0]
}
if x != v {
values[i] = v
}
}
}
} }

View File

@ -6,22 +6,14 @@ package ssa
// findlive returns the reachable blocks and live values in f. // findlive returns the reachable blocks and live values in f.
func findlive(f *Func) (reachable []bool, live []bool) { func findlive(f *Func) (reachable []bool, live []bool) {
// After regalloc, consider all blocks and values to be reachable and live. reachable = reachableBlocks(f)
// See the comment at the top of regalloc.go and in deadcode for details. live = liveValues(f, reachable)
if f.RegAlloc != nil { return
reachable = make([]bool, f.NumBlocks()) }
for i := range reachable {
reachable[i] = true
}
live = make([]bool, f.NumValues())
for i := range live {
live[i] = true
}
return reachable, live
}
// Find all reachable basic blocks. // reachableBlocks returns the reachable blocks in f.
reachable = make([]bool, f.NumBlocks()) func reachableBlocks(f *Func) []bool {
reachable := make([]bool, f.NumBlocks())
reachable[f.Entry.ID] = true reachable[f.Entry.ID] = true
p := []*Block{f.Entry} // stack-like worklist p := []*Block{f.Entry} // stack-like worklist
for len(p) > 0 { for len(p) > 0 {
@ -40,10 +32,25 @@ func findlive(f *Func) (reachable []bool, live []bool) {
} }
} }
} }
return reachable
}
// liveValues returns the live values in f.
// reachable is a map from block ID to whether the block is reachable.
func liveValues(f *Func, reachable []bool) []bool {
live := make([]bool, f.NumValues())
// After regalloc, consider all values to be live.
// See the comment at the top of regalloc.go and in deadcode for details.
if f.RegAlloc != nil {
for i := range live {
live[i] = true
}
return live
}
// Find all live values // Find all live values
live = make([]bool, f.NumValues()) // flag to set for each live value var q []*Value // stack-like worklist of unscanned values
var q []*Value // stack-like worklist of unscanned values
// Starting set: all control values of reachable blocks are live. // Starting set: all control values of reachable blocks are live.
for _, b := range f.Blocks { for _, b := range f.Blocks {
@ -72,7 +79,7 @@ func findlive(f *Func) (reachable []bool, live []bool) {
} }
} }
return reachable, live return live
} }
// deadcode removes dead code from f. // deadcode removes dead code from f.
@ -85,27 +92,8 @@ func deadcode(f *Func) {
f.Fatalf("deadcode after regalloc") f.Fatalf("deadcode after regalloc")
} }
reachable, live := findlive(f) // Find reachable blocks.
reachable := reachableBlocks(f)
// Remove dead values from blocks' value list. Return dead
// value ids to the allocator.
for _, b := range f.Blocks {
i := 0
for _, v := range b.Values {
if live[v.ID] {
b.Values[i] = v
i++
} else {
f.vid.put(v.ID)
}
}
// aid GC
tail := b.Values[i:]
for j := range tail {
tail[j] = nil
}
b.Values = b.Values[:i]
}
// Get rid of edges from dead to live code. // Get rid of edges from dead to live code.
for _, b := range f.Blocks { for _, b := range f.Blocks {
@ -131,6 +119,7 @@ func deadcode(f *Func) {
b.Succs[1] = nil b.Succs[1] = nil
b.Succs = b.Succs[:1] b.Succs = b.Succs[:1]
b.Kind = BlockPlain b.Kind = BlockPlain
b.Likely = BranchUnknown
if reachable[c.ID] { if reachable[c.ID] {
// Note: c must be reachable through some other edge. // Note: c must be reachable through some other edge.
@ -138,41 +127,20 @@ func deadcode(f *Func) {
} }
} }
// Remove unreachable blocks. Return dead block ids to allocator. // Splice out any copies introduced during dead block removal.
i := 0 copyelim(f)
for _, b := range f.Blocks {
if reachable[b.ID] { // Find live values.
f.Blocks[i] = b live := liveValues(f, reachable)
i++
} else {
if len(b.Values) > 0 {
b.Fatalf("live values in unreachable block %v: %v", b, b.Values)
}
b.Preds = nil
b.Succs = nil
b.Control = nil
b.Kind = BlockDead
f.bid.put(b.ID)
}
}
// zero remainder to help GC
tail := f.Blocks[i:]
for j := range tail {
tail[j] = nil
}
f.Blocks = f.Blocks[:i]
// Remove dead & duplicate entries from namedValues map. // Remove dead & duplicate entries from namedValues map.
s := newSparseSet(f.NumValues()) s := newSparseSet(f.NumValues())
i = 0 i := 0
for _, name := range f.Names { for _, name := range f.Names {
j := 0 j := 0
s.clear() s.clear()
values := f.NamedValues[name] values := f.NamedValues[name]
for _, v := range values { for _, v := range values {
for v.Op == OpCopy {
v = v.Args[0]
}
if live[v.ID] && !s.contains(v.ID) { if live[v.ID] && !s.contains(v.ID) {
values[j] = v values[j] = v
j++ j++
@ -195,6 +163,50 @@ func deadcode(f *Func) {
} }
f.Names = f.Names[:i] f.Names = f.Names[:i]
// Remove dead values from blocks' value list. Return dead
// value ids to the allocator.
for _, b := range f.Blocks {
i := 0
for _, v := range b.Values {
if live[v.ID] {
b.Values[i] = v
i++
} else {
f.vid.put(v.ID)
}
}
// aid GC
tail := b.Values[i:]
for j := range tail {
tail[j] = nil
}
b.Values = b.Values[:i]
}
// Remove unreachable blocks. Return dead block ids to allocator.
i = 0
for _, b := range f.Blocks {
if reachable[b.ID] {
f.Blocks[i] = b
i++
} else {
if len(b.Values) > 0 {
b.Fatalf("live values in unreachable block %v: %v", b, b.Values)
}
b.Preds = nil
b.Succs = nil
b.Control = nil
b.Kind = BlockDead
f.bid.put(b.ID)
}
}
// zero remainder to help GC
tail := f.Blocks[i:]
for j := range tail {
tail[j] = nil
}
f.Blocks = f.Blocks[:i]
// TODO: renumber Blocks and Values densely? // TODO: renumber Blocks and Values densely?
// TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it? // TODO: save dead Values and Blocks for reuse? Or should we just let GC handle it?
} }

View File

@ -130,73 +130,73 @@
// Unsigned shifts need to return 0 if shift amount is >= width of shifted value. // Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
// result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff) // result = (arg << shift) & (shift >= argbits ? 0 : 0xffffffffffffffff)
// Note: for small shifts we generate 32 bits of mask even when we don't need it all. // Note: for small shifts we generate 32 bits of mask even when we don't need it all.
(Lsh64x64 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst [64] y))) (Lsh64x64 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
(Lsh64x32 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPLconst [64] y))) (Lsh64x32 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
(Lsh64x16 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPWconst [64] y))) (Lsh64x16 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
(Lsh64x8 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPBconst [64] y))) (Lsh64x8 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPBconst y [64])))
(Lsh32x64 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst [32] y))) (Lsh32x64 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
(Lsh32x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst [32] y))) (Lsh32x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
(Lsh32x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst [32] y))) (Lsh32x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
(Lsh32x8 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst [32] y))) (Lsh32x8 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
(Lsh16x64 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPQconst [16] y))) (Lsh16x64 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
(Lsh16x32 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPLconst [16] y))) (Lsh16x32 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
(Lsh16x16 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPWconst [16] y))) (Lsh16x16 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
(Lsh16x8 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPBconst [16] y))) (Lsh16x8 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
(Lsh8x64 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPQconst [8] y))) (Lsh8x64 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
(Lsh8x32 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPLconst [8] y))) (Lsh8x32 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
(Lsh8x16 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPWconst [8] y))) (Lsh8x16 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
(Lsh8x8 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPBconst [8] y))) (Lsh8x8 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
(Lrot64 <t> x [c]) -> (ROLQconst <t> [c&63] x) (Lrot64 <t> x [c]) -> (ROLQconst <t> [c&63] x)
(Lrot32 <t> x [c]) -> (ROLLconst <t> [c&31] x) (Lrot32 <t> x [c]) -> (ROLLconst <t> [c&31] x)
(Lrot16 <t> x [c]) -> (ROLWconst <t> [c&15] x) (Lrot16 <t> x [c]) -> (ROLWconst <t> [c&15] x)
(Lrot8 <t> x [c]) -> (ROLBconst <t> [c&7] x) (Lrot8 <t> x [c]) -> (ROLBconst <t> [c&7] x)
(Rsh64Ux64 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst [64] y))) (Rsh64Ux64 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst y [64])))
(Rsh64Ux32 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPLconst [64] y))) (Rsh64Ux32 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPLconst y [64])))
(Rsh64Ux16 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPWconst [64] y))) (Rsh64Ux16 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPWconst y [64])))
(Rsh64Ux8 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPBconst [64] y))) (Rsh64Ux8 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPBconst y [64])))
(Rsh32Ux64 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPQconst [32] y))) (Rsh32Ux64 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPQconst y [32])))
(Rsh32Ux32 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst [32] y))) (Rsh32Ux32 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst y [32])))
(Rsh32Ux16 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst [32] y))) (Rsh32Ux16 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst y [32])))
(Rsh32Ux8 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPBconst [32] y))) (Rsh32Ux8 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPBconst y [32])))
(Rsh16Ux64 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst [16] y))) (Rsh16Ux64 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst y [16])))
(Rsh16Ux32 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst [16] y))) (Rsh16Ux32 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst y [16])))
(Rsh16Ux16 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst [16] y))) (Rsh16Ux16 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst y [16])))
(Rsh16Ux8 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst [16] y))) (Rsh16Ux8 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst y [16])))
(Rsh8Ux64 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst [8] y))) (Rsh8Ux64 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst y [8])))
(Rsh8Ux32 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst [8] y))) (Rsh8Ux32 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst y [8])))
(Rsh8Ux16 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst [8] y))) (Rsh8Ux16 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst y [8])))
(Rsh8Ux8 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst [8] y))) (Rsh8Ux8 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst y [8])))
// Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value. // Signed right shift needs to return 0/-1 if shift amount is >= width of shifted value.
// We implement this by setting the shift value to -1 (all ones) if the shift value is >= width. // We implement this by setting the shift value to -1 (all ones) if the shift value is >= width.
// Note: for small shift widths we generate 32 bits of mask even when we don't need it all. // Note: for small shift widths we generate 32 bits of mask even when we don't need it all.
(Rsh64x64 <t> x y) -> (SARQ <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [64] y))))) (Rsh64x64 <t> x y) -> (SARQ <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [64])))))
(Rsh64x32 <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [64] y))))) (Rsh64x32 <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [64])))))
(Rsh64x16 <t> x y) -> (SARQ <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [64] y))))) (Rsh64x16 <t> x y) -> (SARQ <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [64])))))
(Rsh64x8 <t> x y) -> (SARQ <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [64] y))))) (Rsh64x8 <t> x y) -> (SARQ <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [64])))))
(Rsh32x64 <t> x y) -> (SARL <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [32] y))))) (Rsh32x64 <t> x y) -> (SARL <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [32])))))
(Rsh32x32 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [32] y))))) (Rsh32x32 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [32])))))
(Rsh32x16 <t> x y) -> (SARL <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [32] y))))) (Rsh32x16 <t> x y) -> (SARL <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [32])))))
(Rsh32x8 <t> x y) -> (SARL <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [32] y))))) (Rsh32x8 <t> x y) -> (SARL <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [32])))))
(Rsh16x64 <t> x y) -> (SARW <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [16] y))))) (Rsh16x64 <t> x y) -> (SARW <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [16])))))
(Rsh16x32 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [16] y))))) (Rsh16x32 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [16])))))
(Rsh16x16 <t> x y) -> (SARW <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [16] y))))) (Rsh16x16 <t> x y) -> (SARW <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [16])))))
(Rsh16x8 <t> x y) -> (SARW <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [16] y))))) (Rsh16x8 <t> x y) -> (SARW <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [16])))))
(Rsh8x64 <t> x y) -> (SARB <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [8] y))))) (Rsh8x64 <t> x y) -> (SARB <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst y [8])))))
(Rsh8x32 <t> x y) -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [8] y))))) (Rsh8x32 <t> x y) -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst y [8])))))
(Rsh8x16 <t> x y) -> (SARB <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [8] y))))) (Rsh8x16 <t> x y) -> (SARB <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst y [8])))))
(Rsh8x8 <t> x y) -> (SARB <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [8] y))))) (Rsh8x8 <t> x y) -> (SARB <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst y [8])))))
(Less64 x y) -> (SETL (CMPQ x y)) (Less64 x y) -> (SETL (CMPQ x y))
(Less32 x y) -> (SETL (CMPL x y)) (Less32 x y) -> (SETL (CMPL x y))
@ -700,23 +700,168 @@
(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no) (EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
(NE (InvertFlags cmp) yes no) -> (NE cmp yes no) (NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
// get rid of overflow code for constant shifts // Constant comparisons.
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds64(d, c) -> (MOVQconst [-1]) (CMPQconst (MOVQconst [x]) [y]) && x==y -> (FlagEQ)
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds64(d, c) -> (MOVQconst [0]) (CMPQconst (MOVQconst [x]) [y]) && x<y && uint64(x)<uint64(y) -> (FlagLT_ULT)
(SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) && inBounds32(d, c) -> (MOVQconst [-1]) (CMPQconst (MOVQconst [x]) [y]) && x<y && uint64(x)>uint64(y) -> (FlagLT_UGT)
(SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) && !inBounds32(d, c) -> (MOVQconst [0]) (CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x)<uint64(y) -> (FlagGT_ULT)
(SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) && inBounds16(d, c) -> (MOVQconst [-1]) (CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT)
(SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) && !inBounds16(d, c) -> (MOVQconst [0]) (CMPLconst (MOVLconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
(SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) && inBounds8(d, c) -> (MOVQconst [-1]) (CMPLconst (MOVLconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
(SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) && !inBounds8(d, c) -> (MOVQconst [0]) (CMPLconst (MOVLconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
(SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds64(d, c) -> (MOVLconst [-1]) (CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
(SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds64(d, c) -> (MOVLconst [0]) (CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
(SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) && inBounds32(d, c) -> (MOVLconst [-1]) (CMPWconst (MOVWconst [x]) [y]) && int16(x)==int16(y) -> (FlagEQ)
(SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) && !inBounds32(d, c) -> (MOVLconst [0]) (CMPWconst (MOVWconst [x]) [y]) && int16(x)<int16(y) && uint16(x)<uint16(y) -> (FlagLT_ULT)
(SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) && inBounds16(d, c) -> (MOVLconst [-1]) (CMPWconst (MOVWconst [x]) [y]) && int16(x)<int16(y) && uint16(x)>uint16(y) -> (FlagLT_UGT)
(SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) && !inBounds16(d, c) -> (MOVLconst [0]) (CMPWconst (MOVWconst [x]) [y]) && int16(x)>int16(y) && uint16(x)<uint16(y) -> (FlagGT_ULT)
(SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) && inBounds8(d, c) -> (MOVLconst [-1]) (CMPWconst (MOVWconst [x]) [y]) && int16(x)>int16(y) && uint16(x)>uint16(y) -> (FlagGT_UGT)
(SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) && !inBounds8(d, c) -> (MOVLconst [0]) (CMPBconst (MOVBconst [x]) [y]) && int8(x)==int8(y) -> (FlagEQ)
(CMPBconst (MOVBconst [x]) [y]) && int8(x)<int8(y) && uint8(x)<uint8(y) -> (FlagLT_ULT)
(CMPBconst (MOVBconst [x]) [y]) && int8(x)<int8(y) && uint8(x)>uint8(y) -> (FlagLT_UGT)
(CMPBconst (MOVBconst [x]) [y]) && int8(x)>int8(y) && uint8(x)<uint8(y) -> (FlagGT_ULT)
(CMPBconst (MOVBconst [x]) [y]) && int8(x)>int8(y) && uint8(x)>uint8(y) -> (FlagGT_UGT)
// Other known comparisons.
(CMPQconst (ANDQconst _ [m]) [n]) && m+1==n && isPowerOfTwo(n) -> (FlagLT_ULT)
(CMPLconst (ANDLconst _ [m]) [n]) && int32(m)+1==int32(n) && isPowerOfTwo(int64(int32(n))) -> (FlagLT_ULT)
(CMPWconst (ANDWconst _ [m]) [n]) && int16(m)+1==int16(n) && isPowerOfTwo(int64(int16(n))) -> (FlagLT_ULT)
(CMPBconst (ANDBconst _ [m]) [n]) && int8(m)+1==int8(n) && isPowerOfTwo(int64(int8(n))) -> (FlagLT_ULT)
// TODO: DIVxU also.
// Absorb flag constants into SBB ops.
(SBBQcarrymask (FlagEQ)) -> (MOVQconst [0])
(SBBQcarrymask (FlagLT_ULT)) -> (MOVQconst [-1])
(SBBQcarrymask (FlagLT_UGT)) -> (MOVQconst [0])
(SBBQcarrymask (FlagGT_ULT)) -> (MOVQconst [-1])
(SBBQcarrymask (FlagGT_UGT)) -> (MOVQconst [0])
(SBBLcarrymask (FlagEQ)) -> (MOVLconst [0])
(SBBLcarrymask (FlagLT_ULT)) -> (MOVLconst [-1])
(SBBLcarrymask (FlagLT_UGT)) -> (MOVLconst [0])
(SBBLcarrymask (FlagGT_ULT)) -> (MOVLconst [-1])
(SBBLcarrymask (FlagGT_UGT)) -> (MOVLconst [0])
// Absorb flag constants into branches.
(EQ (FlagEQ) yes no) -> (First nil yes no)
(EQ (FlagLT_ULT) yes no) -> (First nil no yes)
(EQ (FlagLT_UGT) yes no) -> (First nil no yes)
(EQ (FlagGT_ULT) yes no) -> (First nil no yes)
(EQ (FlagGT_UGT) yes no) -> (First nil no yes)
(NE (FlagEQ) yes no) -> (First nil no yes)
(NE (FlagLT_ULT) yes no) -> (First nil yes no)
(NE (FlagLT_UGT) yes no) -> (First nil yes no)
(NE (FlagGT_ULT) yes no) -> (First nil yes no)
(NE (FlagGT_UGT) yes no) -> (First nil yes no)
(LT (FlagEQ) yes no) -> (First nil no yes)
(LT (FlagLT_ULT) yes no) -> (First nil yes no)
(LT (FlagLT_UGT) yes no) -> (First nil yes no)
(LT (FlagGT_ULT) yes no) -> (First nil no yes)
(LT (FlagGT_UGT) yes no) -> (First nil no yes)
(LE (FlagEQ) yes no) -> (First nil yes no)
(LE (FlagLT_ULT) yes no) -> (First nil yes no)
(LE (FlagLT_UGT) yes no) -> (First nil yes no)
(LE (FlagGT_ULT) yes no) -> (First nil no yes)
(LE (FlagGT_UGT) yes no) -> (First nil no yes)
(GT (FlagEQ) yes no) -> (First nil no yes)
(GT (FlagLT_ULT) yes no) -> (First nil no yes)
(GT (FlagLT_UGT) yes no) -> (First nil no yes)
(GT (FlagGT_ULT) yes no) -> (First nil yes no)
(GT (FlagGT_UGT) yes no) -> (First nil yes no)
(GE (FlagEQ) yes no) -> (First nil yes no)
(GE (FlagLT_ULT) yes no) -> (First nil no yes)
(GE (FlagLT_UGT) yes no) -> (First nil no yes)
(GE (FlagGT_ULT) yes no) -> (First nil yes no)
(GE (FlagGT_UGT) yes no) -> (First nil yes no)
(ULT (FlagEQ) yes no) -> (First nil no yes)
(ULT (FlagLT_ULT) yes no) -> (First nil yes no)
(ULT (FlagLT_UGT) yes no) -> (First nil no yes)
(ULT (FlagGT_ULT) yes no) -> (First nil yes no)
(ULT (FlagGT_UGT) yes no) -> (First nil no yes)
(ULE (FlagEQ) yes no) -> (First nil yes no)
(ULE (FlagLT_ULT) yes no) -> (First nil yes no)
(ULE (FlagLT_UGT) yes no) -> (First nil no yes)
(ULE (FlagGT_ULT) yes no) -> (First nil yes no)
(ULE (FlagGT_UGT) yes no) -> (First nil no yes)
(UGT (FlagEQ) yes no) -> (First nil no yes)
(UGT (FlagLT_ULT) yes no) -> (First nil no yes)
(UGT (FlagLT_UGT) yes no) -> (First nil yes no)
(UGT (FlagGT_ULT) yes no) -> (First nil no yes)
(UGT (FlagGT_UGT) yes no) -> (First nil yes no)
(UGE (FlagEQ) yes no) -> (First nil yes no)
(UGE (FlagLT_ULT) yes no) -> (First nil no yes)
(UGE (FlagLT_UGT) yes no) -> (First nil yes no)
(UGE (FlagGT_ULT) yes no) -> (First nil no yes)
(UGE (FlagGT_UGT) yes no) -> (First nil yes no)
// Absorb flag constants into SETxx ops.
(SETEQ (FlagEQ)) -> (MOVBconst [1])
(SETEQ (FlagLT_ULT)) -> (MOVBconst [0])
(SETEQ (FlagLT_UGT)) -> (MOVBconst [0])
(SETEQ (FlagGT_ULT)) -> (MOVBconst [0])
(SETEQ (FlagGT_UGT)) -> (MOVBconst [0])
(SETNE (FlagEQ)) -> (MOVBconst [0])
(SETNE (FlagLT_ULT)) -> (MOVBconst [1])
(SETNE (FlagLT_UGT)) -> (MOVBconst [1])
(SETNE (FlagGT_ULT)) -> (MOVBconst [1])
(SETNE (FlagGT_UGT)) -> (MOVBconst [1])
(SETL (FlagEQ)) -> (MOVBconst [0])
(SETL (FlagLT_ULT)) -> (MOVBconst [1])
(SETL (FlagLT_UGT)) -> (MOVBconst [1])
(SETL (FlagGT_ULT)) -> (MOVBconst [0])
(SETL (FlagGT_UGT)) -> (MOVBconst [0])
(SETLE (FlagEQ)) -> (MOVBconst [1])
(SETLE (FlagLT_ULT)) -> (MOVBconst [1])
(SETLE (FlagLT_UGT)) -> (MOVBconst [1])
(SETLE (FlagGT_ULT)) -> (MOVBconst [0])
(SETLE (FlagGT_UGT)) -> (MOVBconst [0])
(SETG (FlagEQ)) -> (MOVBconst [0])
(SETG (FlagLT_ULT)) -> (MOVBconst [0])
(SETG (FlagLT_UGT)) -> (MOVBconst [0])
(SETG (FlagGT_ULT)) -> (MOVBconst [1])
(SETG (FlagGT_UGT)) -> (MOVBconst [1])
(SETGE (FlagEQ)) -> (MOVBconst [1])
(SETGE (FlagLT_ULT)) -> (MOVBconst [0])
(SETGE (FlagLT_UGT)) -> (MOVBconst [0])
(SETGE (FlagGT_ULT)) -> (MOVBconst [1])
(SETGE (FlagGT_UGT)) -> (MOVBconst [1])
(SETB (FlagEQ)) -> (MOVBconst [0])
(SETB (FlagLT_ULT)) -> (MOVBconst [1])
(SETB (FlagLT_UGT)) -> (MOVBconst [0])
(SETB (FlagGT_ULT)) -> (MOVBconst [1])
(SETB (FlagGT_UGT)) -> (MOVBconst [0])
(SETBE (FlagEQ)) -> (MOVBconst [1])
(SETBE (FlagLT_ULT)) -> (MOVBconst [1])
(SETBE (FlagLT_UGT)) -> (MOVBconst [0])
(SETBE (FlagGT_ULT)) -> (MOVBconst [1])
(SETBE (FlagGT_UGT)) -> (MOVBconst [0])
(SETA (FlagEQ)) -> (MOVBconst [0])
(SETA (FlagLT_ULT)) -> (MOVBconst [0])
(SETA (FlagLT_UGT)) -> (MOVBconst [1])
(SETA (FlagGT_ULT)) -> (MOVBconst [0])
(SETA (FlagGT_UGT)) -> (MOVBconst [1])
(SETAE (FlagEQ)) -> (MOVBconst [1])
(SETAE (FlagLT_ULT)) -> (MOVBconst [0])
(SETAE (FlagLT_UGT)) -> (MOVBconst [1])
(SETAE (FlagGT_ULT)) -> (MOVBconst [0])
(SETAE (FlagGT_UGT)) -> (MOVBconst [1])
// Remove redundant *const ops // Remove redundant *const ops
(ADDQconst [0] x) -> x (ADDQconst [0] x) -> x

View File

@ -472,6 +472,19 @@ func init() {
// gets correctly ordered with respect to GC safepoints. // gets correctly ordered with respect to GC safepoints.
// arg0=ptr/int arg1=mem, output=int/ptr // arg0=ptr/int arg1=mem, output=int/ptr
{name: "MOVQconvert", reg: gp11nf, asm: "MOVQ"}, {name: "MOVQconvert", reg: gp11nf, asm: "MOVQ"},
// Constant flag values. For any comparison, there are 5 possible
// outcomes: the three from the signed total order (<,==,>) and the
// three from the unsigned total order. The == cases overlap.
// Note: there's a sixth "unordered" outcome for floating-point
// comparisons, but we don't use such a beast yet.
// These ops are for temporary use by rewrite rules. They
// cannot appear in the generated assembly.
{name: "FlagEQ"}, // equal
{name: "FlagLT_ULT"}, // signed < and unsigned <
{name: "FlagLT_UGT"}, // signed < and unsigned >
{name: "FlagGT_UGT"}, // signed > and unsigned <
{name: "FlagGT_ULT"}, // signed > and unsigned >
} }
var AMD64blocks = []blockData{ var AMD64blocks = []blockData{

View File

@ -21,7 +21,7 @@ func checkLower(f *Func) {
continue // lowered continue // lowered
} }
switch v.Op { switch v.Op {
case OpSP, OpSB, OpInitMem, OpArg, OpCopy, OpPhi, OpVarDef, OpVarKill: case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill:
continue // ok not to lower continue // ok not to lower
} }
s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString() s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString()

View File

@ -283,6 +283,11 @@ const (
OpAMD64LoweredGetClosurePtr OpAMD64LoweredGetClosurePtr
OpAMD64LoweredNilCheck OpAMD64LoweredNilCheck
OpAMD64MOVQconvert OpAMD64MOVQconvert
OpAMD64FlagEQ
OpAMD64FlagLT_ULT
OpAMD64FlagLT_UGT
OpAMD64FlagGT_UGT
OpAMD64FlagGT_ULT
OpAdd8 OpAdd8
OpAdd16 OpAdd16
@ -3232,6 +3237,26 @@ var opcodeTable = [...]opInfo{
}, },
}, },
}, },
{
name: "FlagEQ",
reg: regInfo{},
},
{
name: "FlagLT_ULT",
reg: regInfo{},
},
{
name: "FlagLT_UGT",
reg: regInfo{},
},
{
name: "FlagGT_UGT",
reg: regInfo{},
},
{
name: "FlagGT_ULT",
reg: regInfo{},
},
{ {
name: "Add8", name: "Add8",

File diff suppressed because it is too large Load Diff