mirror of
https://github.com/golang/go
synced 2024-10-05 07:21:25 -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:
parent
9094e3ada2
commit
3425295e91
@ -4108,6 +4108,8 @@ func (s *genState) genValue(v *ssa.Value) {
|
||||
|
||||
case ssa.OpAMD64InvertFlags:
|
||||
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:
|
||||
Prog(x86.AREP)
|
||||
Prog(x86.ASTOSQ)
|
||||
|
@ -26,4 +26,18 @@ func copyelim(f *Func) {
|
||||
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
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -6,22 +6,14 @@ package ssa
|
||||
|
||||
// findlive returns the reachable blocks and live values in f.
|
||||
func findlive(f *Func) (reachable []bool, live []bool) {
|
||||
// After regalloc, consider all blocks and values to be reachable and live.
|
||||
// See the comment at the top of regalloc.go and in deadcode for details.
|
||||
if f.RegAlloc != nil {
|
||||
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
|
||||
}
|
||||
reachable = reachableBlocks(f)
|
||||
live = liveValues(f, reachable)
|
||||
return
|
||||
}
|
||||
|
||||
// Find all reachable basic blocks.
|
||||
reachable = make([]bool, f.NumBlocks())
|
||||
// reachableBlocks returns the reachable blocks in f.
|
||||
func reachableBlocks(f *Func) []bool {
|
||||
reachable := make([]bool, f.NumBlocks())
|
||||
reachable[f.Entry.ID] = true
|
||||
p := []*Block{f.Entry} // stack-like worklist
|
||||
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
|
||||
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.
|
||||
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.
|
||||
@ -85,27 +92,8 @@ func deadcode(f *Func) {
|
||||
f.Fatalf("deadcode after regalloc")
|
||||
}
|
||||
|
||||
reachable, live := findlive(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]
|
||||
}
|
||||
// Find reachable blocks.
|
||||
reachable := reachableBlocks(f)
|
||||
|
||||
// Get rid of edges from dead to live code.
|
||||
for _, b := range f.Blocks {
|
||||
@ -131,6 +119,7 @@ func deadcode(f *Func) {
|
||||
b.Succs[1] = nil
|
||||
b.Succs = b.Succs[:1]
|
||||
b.Kind = BlockPlain
|
||||
b.Likely = BranchUnknown
|
||||
|
||||
if reachable[c.ID] {
|
||||
// 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.
|
||||
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]
|
||||
// Splice out any copies introduced during dead block removal.
|
||||
copyelim(f)
|
||||
|
||||
// Find live values.
|
||||
live := liveValues(f, reachable)
|
||||
|
||||
// Remove dead & duplicate entries from namedValues map.
|
||||
s := newSparseSet(f.NumValues())
|
||||
i = 0
|
||||
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] && !s.contains(v.ID) {
|
||||
values[j] = v
|
||||
j++
|
||||
@ -195,6 +163,50 @@ func deadcode(f *Func) {
|
||||
}
|
||||
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: save dead Values and Blocks for reuse? Or should we just let GC handle it?
|
||||
}
|
||||
|
@ -130,73 +130,73 @@
|
||||
// Unsigned shifts need to return 0 if shift amount is >= width of shifted value.
|
||||
// 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.
|
||||
(Lsh64x64 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPQconst [64] y)))
|
||||
(Lsh64x32 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPLconst [64] y)))
|
||||
(Lsh64x16 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPWconst [64] y)))
|
||||
(Lsh64x8 <t> x y) -> (ANDQ (SHLQ <t> x y) (SBBQcarrymask <t> (CMPBconst [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 y [64])))
|
||||
(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 y [64])))
|
||||
|
||||
(Lsh32x64 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPQconst [32] y)))
|
||||
(Lsh32x32 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPLconst [32] y)))
|
||||
(Lsh32x16 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPWconst [32] y)))
|
||||
(Lsh32x8 <t> x y) -> (ANDL (SHLL <t> x y) (SBBLcarrymask <t> (CMPBconst [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 y [32])))
|
||||
(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 y [32])))
|
||||
|
||||
(Lsh16x64 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPQconst [16] y)))
|
||||
(Lsh16x32 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPLconst [16] y)))
|
||||
(Lsh16x16 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPWconst [16] y)))
|
||||
(Lsh16x8 <t> x y) -> (ANDW (SHLW <t> x y) (SBBLcarrymask <t> (CMPBconst [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 y [16])))
|
||||
(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 y [16])))
|
||||
|
||||
(Lsh8x64 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPQconst [8] y)))
|
||||
(Lsh8x32 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPLconst [8] y)))
|
||||
(Lsh8x16 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPWconst [8] y)))
|
||||
(Lsh8x8 <t> x y) -> (ANDB (SHLB <t> x y) (SBBLcarrymask <t> (CMPBconst [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 y [8])))
|
||||
(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 y [8])))
|
||||
|
||||
(Lrot64 <t> x [c]) -> (ROLQconst <t> [c&63] x)
|
||||
(Lrot32 <t> x [c]) -> (ROLLconst <t> [c&31] x)
|
||||
(Lrot16 <t> x [c]) -> (ROLWconst <t> [c&15] x)
|
||||
(Lrot8 <t> x [c]) -> (ROLBconst <t> [c&7] x)
|
||||
|
||||
(Rsh64Ux64 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPQconst [64] y)))
|
||||
(Rsh64Ux32 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPLconst [64] y)))
|
||||
(Rsh64Ux16 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPWconst [64] y)))
|
||||
(Rsh64Ux8 <t> x y) -> (ANDQ (SHRQ <t> x y) (SBBQcarrymask <t> (CMPBconst [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 y [64])))
|
||||
(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 y [64])))
|
||||
|
||||
(Rsh32Ux64 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPQconst [32] y)))
|
||||
(Rsh32Ux32 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPLconst [32] y)))
|
||||
(Rsh32Ux16 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPWconst [32] y)))
|
||||
(Rsh32Ux8 <t> x y) -> (ANDL (SHRL <t> x y) (SBBLcarrymask <t> (CMPBconst [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 y [32])))
|
||||
(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 y [32])))
|
||||
|
||||
(Rsh16Ux64 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPQconst [16] y)))
|
||||
(Rsh16Ux32 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPLconst [16] y)))
|
||||
(Rsh16Ux16 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPWconst [16] y)))
|
||||
(Rsh16Ux8 <t> x y) -> (ANDW (SHRW <t> x y) (SBBLcarrymask <t> (CMPBconst [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 y [16])))
|
||||
(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 y [16])))
|
||||
|
||||
(Rsh8Ux64 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPQconst [8] y)))
|
||||
(Rsh8Ux32 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPLconst [8] y)))
|
||||
(Rsh8Ux16 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPWconst [8] y)))
|
||||
(Rsh8Ux8 <t> x y) -> (ANDB (SHRB <t> x y) (SBBLcarrymask <t> (CMPBconst [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 y [8])))
|
||||
(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 y [8])))
|
||||
|
||||
// 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.
|
||||
// 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)))))
|
||||
(Rsh64x32 <t> x y) -> (SARQ <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [64] y)))))
|
||||
(Rsh64x16 <t> x y) -> (SARQ <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [64] y)))))
|
||||
(Rsh64x8 <t> x y) -> (SARQ <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [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 y [64])))))
|
||||
(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 y [64])))))
|
||||
|
||||
(Rsh32x64 <t> x y) -> (SARL <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [32] y)))))
|
||||
(Rsh32x32 <t> x y) -> (SARL <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [32] y)))))
|
||||
(Rsh32x16 <t> x y) -> (SARL <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [32] y)))))
|
||||
(Rsh32x8 <t> x y) -> (SARL <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [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 y [32])))))
|
||||
(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 y [32])))))
|
||||
|
||||
(Rsh16x64 <t> x y) -> (SARW <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [16] y)))))
|
||||
(Rsh16x32 <t> x y) -> (SARW <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [16] y)))))
|
||||
(Rsh16x16 <t> x y) -> (SARW <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [16] y)))))
|
||||
(Rsh16x8 <t> x y) -> (SARW <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [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 y [16])))))
|
||||
(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 y [16])))))
|
||||
|
||||
(Rsh8x64 <t> x y) -> (SARB <t> x (ORQ <y.Type> y (NOTQ <y.Type> (SBBQcarrymask <y.Type> (CMPQconst [8] y)))))
|
||||
(Rsh8x32 <t> x y) -> (SARB <t> x (ORL <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPLconst [8] y)))))
|
||||
(Rsh8x16 <t> x y) -> (SARB <t> x (ORW <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPWconst [8] y)))))
|
||||
(Rsh8x8 <t> x y) -> (SARB <t> x (ORB <y.Type> y (NOTL <y.Type> (SBBLcarrymask <y.Type> (CMPBconst [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 y [8])))))
|
||||
(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 y [8])))))
|
||||
|
||||
(Less64 x y) -> (SETL (CMPQ x y))
|
||||
(Less32 x y) -> (SETL (CMPL x y))
|
||||
@ -700,23 +700,168 @@
|
||||
(EQ (InvertFlags cmp) yes no) -> (EQ cmp yes no)
|
||||
(NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
|
||||
|
||||
// get rid of overflow code for constant shifts
|
||||
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds64(d, c) -> (MOVQconst [-1])
|
||||
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds64(d, c) -> (MOVQconst [0])
|
||||
(SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) && inBounds32(d, c) -> (MOVQconst [-1])
|
||||
(SBBQcarrymask (CMPLconst [c] (MOVLconst [d]))) && !inBounds32(d, c) -> (MOVQconst [0])
|
||||
(SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) && inBounds16(d, c) -> (MOVQconst [-1])
|
||||
(SBBQcarrymask (CMPWconst [c] (MOVWconst [d]))) && !inBounds16(d, c) -> (MOVQconst [0])
|
||||
(SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) && inBounds8(d, c) -> (MOVQconst [-1])
|
||||
(SBBQcarrymask (CMPBconst [c] (MOVBconst [d]))) && !inBounds8(d, c) -> (MOVQconst [0])
|
||||
(SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds64(d, c) -> (MOVLconst [-1])
|
||||
(SBBLcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds64(d, c) -> (MOVLconst [0])
|
||||
(SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) && inBounds32(d, c) -> (MOVLconst [-1])
|
||||
(SBBLcarrymask (CMPLconst [c] (MOVLconst [d]))) && !inBounds32(d, c) -> (MOVLconst [0])
|
||||
(SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) && inBounds16(d, c) -> (MOVLconst [-1])
|
||||
(SBBLcarrymask (CMPWconst [c] (MOVWconst [d]))) && !inBounds16(d, c) -> (MOVLconst [0])
|
||||
(SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) && inBounds8(d, c) -> (MOVLconst [-1])
|
||||
(SBBLcarrymask (CMPBconst [c] (MOVBconst [d]))) && !inBounds8(d, c) -> (MOVLconst [0])
|
||||
// Constant comparisons.
|
||||
(CMPQconst (MOVQconst [x]) [y]) && x==y -> (FlagEQ)
|
||||
(CMPQconst (MOVQconst [x]) [y]) && x<y && uint64(x)<uint64(y) -> (FlagLT_ULT)
|
||||
(CMPQconst (MOVQconst [x]) [y]) && x<y && uint64(x)>uint64(y) -> (FlagLT_UGT)
|
||||
(CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x)<uint64(y) -> (FlagGT_ULT)
|
||||
(CMPQconst (MOVQconst [x]) [y]) && x>y && uint64(x)>uint64(y) -> (FlagGT_UGT)
|
||||
(CMPLconst (MOVLconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
|
||||
(CMPLconst (MOVLconst [x]) [y]) && int32(x)<int32(y) && uint32(x)<uint32(y) -> (FlagLT_ULT)
|
||||
(CMPLconst (MOVLconst [x]) [y]) && int32(x)<int32(y) && uint32(x)>uint32(y) -> (FlagLT_UGT)
|
||||
(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)<uint32(y) -> (FlagGT_ULT)
|
||||
(CMPLconst (MOVLconst [x]) [y]) && int32(x)>int32(y) && uint32(x)>uint32(y) -> (FlagGT_UGT)
|
||||
(CMPWconst (MOVWconst [x]) [y]) && int16(x)==int16(y) -> (FlagEQ)
|
||||
(CMPWconst (MOVWconst [x]) [y]) && int16(x)<int16(y) && uint16(x)<uint16(y) -> (FlagLT_ULT)
|
||||
(CMPWconst (MOVWconst [x]) [y]) && int16(x)<int16(y) && uint16(x)>uint16(y) -> (FlagLT_UGT)
|
||||
(CMPWconst (MOVWconst [x]) [y]) && int16(x)>int16(y) && uint16(x)<uint16(y) -> (FlagGT_ULT)
|
||||
(CMPWconst (MOVWconst [x]) [y]) && int16(x)>int16(y) && uint16(x)>uint16(y) -> (FlagGT_UGT)
|
||||
(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
|
||||
(ADDQconst [0] x) -> x
|
||||
|
@ -472,6 +472,19 @@ func init() {
|
||||
// gets correctly ordered with respect to GC safepoints.
|
||||
// arg0=ptr/int arg1=mem, output=int/ptr
|
||||
{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{
|
||||
|
@ -21,7 +21,7 @@ func checkLower(f *Func) {
|
||||
continue // lowered
|
||||
}
|
||||
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
|
||||
}
|
||||
s := "not lowered: " + v.Op.String() + " " + v.Type.SimpleString()
|
||||
|
@ -283,6 +283,11 @@ const (
|
||||
OpAMD64LoweredGetClosurePtr
|
||||
OpAMD64LoweredNilCheck
|
||||
OpAMD64MOVQconvert
|
||||
OpAMD64FlagEQ
|
||||
OpAMD64FlagLT_ULT
|
||||
OpAMD64FlagLT_UGT
|
||||
OpAMD64FlagGT_UGT
|
||||
OpAMD64FlagGT_ULT
|
||||
|
||||
OpAdd8
|
||||
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",
|
||||
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user