mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: ARM comparisons with 0 incorrect on overflow
Some ARM rewriting rules convert 'comparing to zero' conditions of if statements to a simplified version utilizing CMN and CMP instructions to branch over condition flags, in order to save one Add or Sub caculation. Such optimizations lead to wrong branching in case an overflow/underflow occurs when executing CMN or CMP. Fix the issue by introducing new block opcodes that don't honor the overflow/underflow flag: Block-Op Meaning ARM condition codes 1. LTnoov less than MI 2. GEnoov greater than or equal PL 3. LEnoov less than or equal MI || EQ 4. GTnoov greater than NEQ & PL The patch also adds a few test cases to cover scenarios that are specific to ARM and fine-tunes the code generation tests for 'x-const'. For more details please refer to the previous fix on 64-bit ARM: https://go-review.googlesource.com/c/go/+/233097 Go1 perf, 'old' is the non-optimized version, that is removing all concerned rewriting rules. name old time/op new time/op delta BinaryTree17-8 7.73s ± 0% 7.81s ± 0% +0.97% (p=0.000 n=7+8) Fannkuch11-8 7.06s ± 0% 7.00s ± 0% -0.83% (p=0.000 n=8+8) FmtFprintfEmpty-8 181ns ± 1% 183ns ± 1% +1.31% (p=0.001 n=8+8) FmtFprintfString-8 319ns ± 1% 325ns ± 2% +1.71% (p=0.009 n=7+8) FmtFprintfInt-8 358ns ± 1% 359ns ± 1% ~ (p=0.293 n=7+7) FmtFprintfIntInt-8 459ns ± 3% 456ns ± 1% ~ (p=0.869 n=8+8) FmtFprintfPrefixedInt-8 535ns ± 4% 538ns ± 4% ~ (p=0.572 n=8+8) FmtFprintfFloat-8 1.01µs ± 2% 1.01µs ± 2% ~ (p=0.625 n=8+8) FmtManyArgs-8 1.93µs ± 2% 1.93µs ± 1% ~ (p=0.979 n=8+7) GobDecode-8 16.1ms ± 1% 16.5ms ± 1% +2.32% (p=0.000 n=8+8) GobEncode-8 15.9ms ± 0% 15.8ms ± 1% -1.00% (p=0.000 n=8+7) Gzip-8 690ms ± 1% 670ms ± 0% -2.90% (p=0.000 n=8+8) Gunzip-8 109ms ± 1% 109ms ± 1% ~ (p=0.694 n=7+8) HTTPClientServer-8 149µs ± 3% 146µs ± 2% -1.70% (p=0.028 n=8+8) JSONEncode-8 50.5ms ± 1% 49.2ms ± 0% -2.60% (p=0.001 n=7+7) JSONDecode-8 135ms ± 2% 137ms ± 1% ~ (p=0.054 n=8+7) Mandelbrot200-8 951ms ± 0% 952ms ± 0% ~ (p=0.852 n=6+8) GoParse-8 9.47ms ± 1% 9.66ms ± 1% +2.01% (p=0.000 n=8+8) RegexpMatchEasy0_32-8 288ns ± 2% 277ns ± 2% -3.61% (p=0.000 n=8+8) RegexpMatchEasy0_1K-8 1.66µs ± 1% 1.69µs ± 2% +2.21% (p=0.001 n=7+7) RegexpMatchEasy1_32-8 334ns ± 1% 305ns ± 2% -8.86% (p=0.000 n=8+8) RegexpMatchEasy1_1K-8 2.14µs ± 2% 2.15µs ± 0% ~ (p=0.099 n=8+8) RegexpMatchMedium_32-8 13.3ns ± 1% 13.3ns ± 0% ~ (p=1.000 n=7+7) RegexpMatchMedium_1K-8 81.1µs ± 3% 80.7µs ± 1% ~ (p=0.955 n=7+8) RegexpMatchHard_32-8 4.26µs ± 0% 4.26µs ± 0% ~ (p=0.933 n=7+8) RegexpMatchHard_1K-8 124µs ± 0% 124µs ± 0% +0.31% (p=0.000 n=8+8) Revcomp-8 14.7ms ± 2% 14.5ms ± 1% -1.66% (p=0.003 n=8+8) Template-8 197ms ± 2% 200ms ± 3% +1.62% (p=0.021 n=8+8) TimeParse-8 1.33µs ± 1% 1.30µs ± 1% -1.86% (p=0.002 n=8+8) TimeFormat-8 3.04µs ± 1% 3.02µs ± 0% -0.60% (p=0.000 n=8+8) name old speed new speed delta GobDecode-8 47.6MB/s ± 1% 46.5MB/s ± 1% -2.28% (p=0.000 n=8+8) GobEncode-8 48.1MB/s ± 0% 48.6MB/s ± 1% +1.02% (p=0.000 n=8+7) Gzip-8 28.1MB/s ± 1% 29.0MB/s ± 0% +2.97% (p=0.000 n=8+8) Gunzip-8 178MB/s ± 1% 179MB/s ± 2% ~ (p=0.694 n=7+8) JSONEncode-8 38.4MB/s ± 1% 39.4MB/s ± 0% +2.67% (p=0.001 n=7+7) JSONDecode-8 14.3MB/s ± 2% 14.2MB/s ± 1% -0.81% (p=0.043 n=8+7) GoParse-8 6.12MB/s ± 1% 5.99MB/s ± 1% -2.00% (p=0.000 n=8+8) RegexpMatchEasy0_32-8 111MB/s ± 2% 115MB/s ± 2% +3.77% (p=0.000 n=8+8) RegexpMatchEasy0_1K-8 618MB/s ± 1% 604MB/s ± 2% -2.16% (p=0.001 n=7+7) RegexpMatchEasy1_32-8 95.7MB/s ± 1% 105.1MB/s ± 2% +9.76% (p=0.000 n=8+8) RegexpMatchEasy1_1K-8 479MB/s ± 2% 477MB/s ± 0% ~ (p=0.105 n=8+8) RegexpMatchMedium_32-8 75.2MB/s ± 1% 75.2MB/s ± 0% ~ (p=0.247 n=7+7) RegexpMatchMedium_1K-8 12.6MB/s ± 3% 12.7MB/s ± 1% ~ (p=0.538 n=7+8) RegexpMatchHard_32-8 7.52MB/s ± 0% 7.52MB/s ± 0% ~ (p=0.968 n=7+8) RegexpMatchHard_1K-8 8.26MB/s ± 0% 8.24MB/s ± 0% -0.30% (p=0.001 n=8+8) Revcomp-8 173MB/s ± 2% 176MB/s ± 1% +1.68% (p=0.003 n=8+8) Template-8 9.85MB/s ± 2% 9.69MB/s ± 3% -1.59% (p=0.021 n=8+8) Fixes #39303 Updates #38740 Change-Id: I0a5f87bfda679f66414c0041ace2ca2e28363f36 Reviewed-on: https://go-review.googlesource.com/c/go/+/236637 Run-TryBot: Keith Randall <khr@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Keith Randall <khr@golang.org>
This commit is contained in:
parent
bdcf33f1c0
commit
e031318ca6
8 changed files with 418 additions and 259 deletions
|
|
@ -140,6 +140,7 @@ var knownFormats = map[string]string{
|
||||||
"float64 %.3f": "",
|
"float64 %.3f": "",
|
||||||
"float64 %.6g": "",
|
"float64 %.6g": "",
|
||||||
"float64 %g": "",
|
"float64 %g": "",
|
||||||
|
"int %#x": "",
|
||||||
"int %-12d": "",
|
"int %-12d": "",
|
||||||
"int %-6d": "",
|
"int %-6d": "",
|
||||||
"int %-8o": "",
|
"int %-8o": "",
|
||||||
|
|
@ -203,6 +204,7 @@ var knownFormats = map[string]string{
|
||||||
"uint64 %b": "",
|
"uint64 %b": "",
|
||||||
"uint64 %d": "",
|
"uint64 %d": "",
|
||||||
"uint64 %x": "",
|
"uint64 %x": "",
|
||||||
|
"uint8 %#x": "",
|
||||||
"uint8 %d": "",
|
"uint8 %d": "",
|
||||||
"uint8 %v": "",
|
"uint8 %v": "",
|
||||||
"uint8 %x": "",
|
"uint8 %x": "",
|
||||||
|
|
|
||||||
|
|
@ -898,6 +898,20 @@ var blockJump = map[ssa.BlockKind]struct {
|
||||||
ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
|
ssa.BlockARMUGE: {arm.ABHS, arm.ABLO},
|
||||||
ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
|
ssa.BlockARMUGT: {arm.ABHI, arm.ABLS},
|
||||||
ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
|
ssa.BlockARMULE: {arm.ABLS, arm.ABHI},
|
||||||
|
ssa.BlockARMLTnoov: {arm.ABMI, arm.ABPL},
|
||||||
|
ssa.BlockARMGEnoov: {arm.ABPL, arm.ABMI},
|
||||||
|
}
|
||||||
|
|
||||||
|
// To model a 'LEnoov' ('<=' without overflow checking) branching
|
||||||
|
var leJumps = [2][2]gc.IndexJump{
|
||||||
|
{{Jump: arm.ABEQ, Index: 0}, {Jump: arm.ABPL, Index: 1}}, // next == b.Succs[0]
|
||||||
|
{{Jump: arm.ABMI, Index: 0}, {Jump: arm.ABEQ, Index: 0}}, // next == b.Succs[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
// To model a 'GTnoov' ('>' without overflow checking) branching
|
||||||
|
var gtJumps = [2][2]gc.IndexJump{
|
||||||
|
{{Jump: arm.ABMI, Index: 1}, {Jump: arm.ABEQ, Index: 1}}, // next == b.Succs[0]
|
||||||
|
{{Jump: arm.ABEQ, Index: 1}, {Jump: arm.ABPL, Index: 0}}, // next == b.Succs[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||||
|
|
@ -941,7 +955,8 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||||
ssa.BlockARMLT, ssa.BlockARMGE,
|
ssa.BlockARMLT, ssa.BlockARMGE,
|
||||||
ssa.BlockARMLE, ssa.BlockARMGT,
|
ssa.BlockARMLE, ssa.BlockARMGT,
|
||||||
ssa.BlockARMULT, ssa.BlockARMUGT,
|
ssa.BlockARMULT, ssa.BlockARMUGT,
|
||||||
ssa.BlockARMULE, ssa.BlockARMUGE:
|
ssa.BlockARMULE, ssa.BlockARMUGE,
|
||||||
|
ssa.BlockARMLTnoov, ssa.BlockARMGEnoov:
|
||||||
jmp := blockJump[b.Kind]
|
jmp := blockJump[b.Kind]
|
||||||
switch next {
|
switch next {
|
||||||
case b.Succs[0].Block():
|
case b.Succs[0].Block():
|
||||||
|
|
@ -958,6 +973,12 @@ func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ssa.BlockARMLEnoov:
|
||||||
|
s.CombJump(b, next, &leJumps)
|
||||||
|
|
||||||
|
case ssa.BlockARMGTnoov:
|
||||||
|
s.CombJump(b, next, >Jumps)
|
||||||
|
|
||||||
default:
|
default:
|
||||||
b.Fatalf("branch not implemented: %s", b.LongString())
|
b.Fatalf("branch not implemented: %s", b.LongString())
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -704,6 +704,10 @@
|
||||||
(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
|
(UGE (InvertFlags cmp) yes no) -> (ULE cmp yes no)
|
||||||
(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)
|
||||||
|
(LTnoov (InvertFlags cmp) yes no) => (GTnoov cmp yes no)
|
||||||
|
(GEnoov (InvertFlags cmp) yes no) => (LEnoov cmp yes no)
|
||||||
|
(LEnoov (InvertFlags cmp) yes no) => (GEnoov cmp yes no)
|
||||||
|
(GTnoov (InvertFlags cmp) yes no) => (LTnoov cmp yes no)
|
||||||
|
|
||||||
// absorb flag constants into boolean values
|
// absorb flag constants into boolean values
|
||||||
(Equal (FlagEQ)) -> (MOVWconst [1])
|
(Equal (FlagEQ)) -> (MOVWconst [1])
|
||||||
|
|
@ -1417,42 +1421,42 @@
|
||||||
(NE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftLLreg x y z) yes no)
|
(NE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftLLreg x y z) yes no)
|
||||||
(NE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRLreg x y z) yes no)
|
(NE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRLreg x y z) yes no)
|
||||||
(NE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRAreg x y z) yes no)
|
(NE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (NE (TEQshiftRAreg x y z) yes no)
|
||||||
(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LT (CMP x y) yes no)
|
(LT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LTnoov (CMP x y) yes no)
|
||||||
(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LT (CMP a (MUL <x.Type> x y)) yes no)
|
(LT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LTnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||||
(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LT (CMPconst [c] x) yes no)
|
(LT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMPconst [c] x) yes no)
|
||||||
(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftLL x y [c]) yes no)
|
(LT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLL x y [c]) yes no)
|
||||||
(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRL x y [c]) yes no)
|
(LT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRL x y [c]) yes no)
|
||||||
(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMPshiftRA x y [c]) yes no)
|
(LT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRA x y [c]) yes no)
|
||||||
(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftLLreg x y z) yes no)
|
(LT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftLLreg x y z) yes no)
|
||||||
(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRLreg x y z) yes no)
|
(LT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRLreg x y z) yes no)
|
||||||
(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMPshiftRAreg x y z) yes no)
|
(LT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMPshiftRAreg x y z) yes no)
|
||||||
(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LE (CMP x y) yes no)
|
(LE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (LEnoov (CMP x y) yes no)
|
||||||
(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LE (CMP a (MUL <x.Type> x y)) yes no)
|
(LE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (LEnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||||
(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LE (CMPconst [c] x) yes no)
|
(LE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMPconst [c] x) yes no)
|
||||||
(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftLL x y [c]) yes no)
|
(LE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLL x y [c]) yes no)
|
||||||
(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRL x y [c]) yes no)
|
(LE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRL x y [c]) yes no)
|
||||||
(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMPshiftRA x y [c]) yes no)
|
(LE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRA x y [c]) yes no)
|
||||||
(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftLLreg x y z) yes no)
|
(LE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftLLreg x y z) yes no)
|
||||||
(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRLreg x y z) yes no)
|
(LE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRLreg x y z) yes no)
|
||||||
(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMPshiftRAreg x y z) yes no)
|
(LE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMPshiftRAreg x y z) yes no)
|
||||||
(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LT (CMN x y) yes no)
|
(LT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LTnoov (CMN x y) yes no)
|
||||||
(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LT (CMN a (MUL <x.Type> x y)) yes no)
|
(LT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LTnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||||
(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LT (CMNconst [c] x) yes no)
|
(LT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LTnoov (CMNconst [c] x) yes no)
|
||||||
(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftLL x y [c]) yes no)
|
(LT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLL x y [c]) yes no)
|
||||||
(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRL x y [c]) yes no)
|
(LT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRL x y [c]) yes no)
|
||||||
(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LT (CMNshiftRA x y [c]) yes no)
|
(LT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRA x y [c]) yes no)
|
||||||
(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftLLreg x y z) yes no)
|
(LT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftLLreg x y z) yes no)
|
||||||
(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRLreg x y z) yes no)
|
(LT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRLreg x y z) yes no)
|
||||||
(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LT (CMNshiftRAreg x y z) yes no)
|
(LT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LTnoov (CMNshiftRAreg x y z) yes no)
|
||||||
(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LE (CMN x y) yes no)
|
(LE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (LEnoov (CMN x y) yes no)
|
||||||
(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LE (CMN a (MUL <x.Type> x y)) yes no)
|
(LE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (LEnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||||
(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LE (CMNconst [c] x) yes no)
|
(LE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (LEnoov (CMNconst [c] x) yes no)
|
||||||
(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftLL x y [c]) yes no)
|
(LE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLL x y [c]) yes no)
|
||||||
(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRL x y [c]) yes no)
|
(LE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRL x y [c]) yes no)
|
||||||
(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LE (CMNshiftRA x y [c]) yes no)
|
(LE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRA x y [c]) yes no)
|
||||||
(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftLLreg x y z) yes no)
|
(LE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftLLreg x y z) yes no)
|
||||||
(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRLreg x y z) yes no)
|
(LE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRLreg x y z) yes no)
|
||||||
(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (CMNshiftRAreg x y z) yes no)
|
(LE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (LEnoov (CMNshiftRAreg x y z) yes no)
|
||||||
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LT (TST x y) yes no)
|
(LT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (LT (TST x y) yes no)
|
||||||
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LT (TSTconst [c] x) yes no)
|
(LT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (LT (TSTconst [c] x) yes no)
|
||||||
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftLL x y [c]) yes no)
|
(LT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (LT (TSTshiftLL x y [c]) yes no)
|
||||||
|
|
@ -1485,43 +1489,43 @@
|
||||||
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftLLreg x y z) yes no)
|
(LE (CMPconst [0] l:(XORshiftLLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftLLreg x y z) yes no)
|
||||||
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRLreg x y z) yes no)
|
(LE (CMPconst [0] l:(XORshiftRLreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRLreg x y z) yes no)
|
||||||
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRAreg x y z) yes no)
|
(LE (CMPconst [0] l:(XORshiftRAreg x y z)) yes no) && l.Uses==1 -> (LE (TEQshiftRAreg x y z) yes no)
|
||||||
(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GT (CMP x y) yes no)
|
(GT (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GTnoov (CMP x y) yes no)
|
||||||
(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GT (CMP a (MUL <x.Type> x y)) yes no)
|
(GT (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GTnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||||
(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GT (CMPconst [c] x) yes no)
|
(GT (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMPconst [c] x) yes no)
|
||||||
(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftLL x y [c]) yes no)
|
(GT (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLL x y [c]) yes no)
|
||||||
(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRL x y [c]) yes no)
|
(GT (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRL x y [c]) yes no)
|
||||||
(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMPshiftRA x y [c]) yes no)
|
(GT (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRA x y [c]) yes no)
|
||||||
(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftLLreg x y z) yes no)
|
(GT (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftLLreg x y z) yes no)
|
||||||
(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRLreg x y z) yes no)
|
(GT (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRLreg x y z) yes no)
|
||||||
(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMPshiftRAreg x y z) yes no)
|
(GT (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMPshiftRAreg x y z) yes no)
|
||||||
(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GE (CMP x y) yes no)
|
(GE (CMPconst [0] l:(SUB x y)) yes no) && l.Uses==1 -> (GEnoov (CMP x y) yes no)
|
||||||
(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GE (CMP a (MUL <x.Type> x y)) yes no)
|
(GE (CMPconst [0] l:(MULS x y a)) yes no) && l.Uses==1 -> (GEnoov (CMP a (MUL <x.Type> x y)) yes no)
|
||||||
(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GE (CMPconst [c] x) yes no)
|
(GE (CMPconst [0] l:(SUBconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMPconst [c] x) yes no)
|
||||||
(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftLL x y [c]) yes no)
|
(GE (CMPconst [0] l:(SUBshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLL x y [c]) yes no)
|
||||||
(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRL x y [c]) yes no)
|
(GE (CMPconst [0] l:(SUBshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRL x y [c]) yes no)
|
||||||
(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMPshiftRA x y [c]) yes no)
|
(GE (CMPconst [0] l:(SUBshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRA x y [c]) yes no)
|
||||||
(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftLLreg x y z) yes no)
|
(GE (CMPconst [0] l:(SUBshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftLLreg x y z) yes no)
|
||||||
(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRLreg x y z) yes no)
|
(GE (CMPconst [0] l:(SUBshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRLreg x y z) yes no)
|
||||||
(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMPshiftRAreg x y z) yes no)
|
(GE (CMPconst [0] l:(SUBshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMPshiftRAreg x y z) yes no)
|
||||||
(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GT (CMN x y) yes no)
|
(GT (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GTnoov (CMN x y) yes no)
|
||||||
(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GT (CMNconst [c] x) yes no)
|
(GT (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GTnoov (CMNconst [c] x) yes no)
|
||||||
(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftLL x y [c]) yes no)
|
(GT (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLL x y [c]) yes no)
|
||||||
(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRL x y [c]) yes no)
|
(GT (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRL x y [c]) yes no)
|
||||||
(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GT (CMNshiftRA x y [c]) yes no)
|
(GT (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRA x y [c]) yes no)
|
||||||
(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftLLreg x y z) yes no)
|
(GT (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftLLreg x y z) yes no)
|
||||||
(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRLreg x y z) yes no)
|
(GT (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRLreg x y z) yes no)
|
||||||
(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GT (CMNshiftRAreg x y z) yes no)
|
(GT (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GTnoov (CMNshiftRAreg x y z) yes no)
|
||||||
(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GE (CMN x y) yes no)
|
(GE (CMPconst [0] l:(ADD x y)) yes no) && l.Uses==1 -> (GEnoov (CMN x y) yes no)
|
||||||
(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GE (CMN a (MUL <x.Type> x y)) yes no)
|
(GE (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GEnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||||
(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GE (CMNconst [c] x) yes no)
|
(GE (CMPconst [0] l:(ADDconst [c] x)) yes no) && l.Uses==1 -> (GEnoov (CMNconst [c] x) yes no)
|
||||||
(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftLL x y [c]) yes no)
|
(GE (CMPconst [0] l:(ADDshiftLL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLL x y [c]) yes no)
|
||||||
(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRL x y [c]) yes no)
|
(GE (CMPconst [0] l:(ADDshiftRL x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRL x y [c]) yes no)
|
||||||
(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GE (CMNshiftRA x y [c]) yes no)
|
(GE (CMPconst [0] l:(ADDshiftRA x y [c])) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRA x y [c]) yes no)
|
||||||
(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftLLreg x y z) yes no)
|
(GE (CMPconst [0] l:(ADDshiftLLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftLLreg x y z) yes no)
|
||||||
(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRLreg x y z) yes no)
|
(GE (CMPconst [0] l:(ADDshiftRLreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRLreg x y z) yes no)
|
||||||
(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GE (CMNshiftRAreg x y z) yes no)
|
(GE (CMPconst [0] l:(ADDshiftRAreg x y z)) yes no) && l.Uses==1 -> (GEnoov (CMNshiftRAreg x y z) yes no)
|
||||||
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GT (TST x y) yes no)
|
(GT (CMPconst [0] l:(AND x y)) yes no) && l.Uses==1 -> (GT (TST x y) yes no)
|
||||||
(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GT (CMN a (MUL <x.Type> x y)) yes no)
|
(GT (CMPconst [0] l:(MULA x y a)) yes no) && l.Uses==1 -> (GTnoov (CMN a (MUL <x.Type> x y)) yes no)
|
||||||
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GT (TSTconst [c] x) yes no)
|
(GT (CMPconst [0] l:(ANDconst [c] x)) yes no) && l.Uses==1 -> (GT (TSTconst [c] x) yes no)
|
||||||
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftLL x y [c]) yes no)
|
(GT (CMPconst [0] l:(ANDshiftLL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftLL x y [c]) yes no)
|
||||||
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftRL x y [c]) yes no)
|
(GT (CMPconst [0] l:(ANDshiftRL x y [c])) yes no) && l.Uses==1 -> (GT (TSTshiftRL x y [c]) yes no)
|
||||||
|
|
|
||||||
|
|
@ -584,6 +584,10 @@ func init() {
|
||||||
{name: "ULE", controls: 1},
|
{name: "ULE", controls: 1},
|
||||||
{name: "UGT", controls: 1},
|
{name: "UGT", controls: 1},
|
||||||
{name: "UGE", controls: 1},
|
{name: "UGE", controls: 1},
|
||||||
|
{name: "LTnoov", controls: 1}, // 'LT' but without honoring overflow
|
||||||
|
{name: "LEnoov", controls: 1}, // 'LE' but without honoring overflow
|
||||||
|
{name: "GTnoov", controls: 1}, // 'GT' but without honoring overflow
|
||||||
|
{name: "GEnoov", controls: 1}, // 'GE' but without honoring overflow
|
||||||
}
|
}
|
||||||
|
|
||||||
archs = append(archs, arch{
|
archs = append(archs, arch{
|
||||||
|
|
|
||||||
|
|
@ -61,6 +61,10 @@ const (
|
||||||
BlockARMULE
|
BlockARMULE
|
||||||
BlockARMUGT
|
BlockARMUGT
|
||||||
BlockARMUGE
|
BlockARMUGE
|
||||||
|
BlockARMLTnoov
|
||||||
|
BlockARMLEnoov
|
||||||
|
BlockARMGTnoov
|
||||||
|
BlockARMGEnoov
|
||||||
|
|
||||||
BlockARM64EQ
|
BlockARM64EQ
|
||||||
BlockARM64NE
|
BlockARM64NE
|
||||||
|
|
@ -195,6 +199,10 @@ var blockString = [...]string{
|
||||||
BlockARMULE: "ULE",
|
BlockARMULE: "ULE",
|
||||||
BlockARMUGT: "UGT",
|
BlockARMUGT: "UGT",
|
||||||
BlockARMUGE: "UGE",
|
BlockARMUGE: "UGE",
|
||||||
|
BlockARMLTnoov: "LTnoov",
|
||||||
|
BlockARMLEnoov: "LEnoov",
|
||||||
|
BlockARMGTnoov: "GTnoov",
|
||||||
|
BlockARMGEnoov: "GEnoov",
|
||||||
|
|
||||||
BlockARM64EQ: "EQ",
|
BlockARM64EQ: "EQ",
|
||||||
BlockARM64NE: "NE",
|
BlockARM64NE: "NE",
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -7,7 +7,6 @@ package ssa
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"runtime"
|
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
@ -18,6 +17,7 @@ var (
|
||||||
y64 int64 = math.MinInt64 + 1
|
y64 int64 = math.MinInt64 + 1
|
||||||
x32 int32 = math.MaxInt32 - 2
|
x32 int32 = math.MaxInt32 - 2
|
||||||
x32b int32 = math.MaxInt32 - 2
|
x32b int32 = math.MaxInt32 - 2
|
||||||
|
x32c int32 = math.MaxInt32 - 2
|
||||||
y32 int32 = math.MinInt32 + 1
|
y32 int32 = math.MinInt32 + 1
|
||||||
one64 int64 = 1
|
one64 int64 = 1
|
||||||
one32 int32 = 1
|
one32 int32 = 1
|
||||||
|
|
@ -25,6 +25,8 @@ var (
|
||||||
v64_n int64 = -11
|
v64_n int64 = -11
|
||||||
v32 int32 = 11
|
v32 int32 = 11
|
||||||
v32_n int32 = -11
|
v32_n int32 = -11
|
||||||
|
uv32 uint32 = 19
|
||||||
|
uz uint8 = 1 // for lowering to SLL/SRL/SRA
|
||||||
)
|
)
|
||||||
|
|
||||||
var crTests = []struct {
|
var crTests = []struct {
|
||||||
|
|
@ -39,6 +41,8 @@ var crTests = []struct {
|
||||||
{"MAddVar32", testMAddVar32},
|
{"MAddVar32", testMAddVar32},
|
||||||
{"MSubVar64", testMSubVar64},
|
{"MSubVar64", testMSubVar64},
|
||||||
{"MSubVar32", testMSubVar32},
|
{"MSubVar32", testMSubVar32},
|
||||||
|
{"AddShift32", testAddShift32},
|
||||||
|
{"SubShift32", testSubShift32},
|
||||||
}
|
}
|
||||||
|
|
||||||
var crBenches = []struct {
|
var crBenches = []struct {
|
||||||
|
|
@ -58,9 +62,6 @@ var crBenches = []struct {
|
||||||
// and machine code sequences are covered.
|
// and machine code sequences are covered.
|
||||||
// It's for arm64 initially, please see https://github.com/golang/go/issues/38740
|
// It's for arm64 initially, please see https://github.com/golang/go/issues/38740
|
||||||
func TestCondRewrite(t *testing.T) {
|
func TestCondRewrite(t *testing.T) {
|
||||||
if runtime.GOARCH == "arm" {
|
|
||||||
t.Skip("fix on arm expected!")
|
|
||||||
}
|
|
||||||
for _, test := range crTests {
|
for _, test := range crTests {
|
||||||
t.Run(test.name, test.tf)
|
t.Run(test.name, test.tf)
|
||||||
}
|
}
|
||||||
|
|
@ -408,6 +409,66 @@ func testMSubVar32(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 32-bit ADDshift, pick up 1~2 scenarios randomly for each condition
|
||||||
|
func testAddShift32(t *testing.T) {
|
||||||
|
if x32+v32<<1 < 0 {
|
||||||
|
} else {
|
||||||
|
t.Errorf("'%#x + %#x<<%#x < 0' failed", x32, v32, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x32+v32>>1 <= 0 {
|
||||||
|
} else {
|
||||||
|
t.Errorf("'%#x + %#x>>%#x <= 0' failed", x32, v32, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x32+int32(uv32>>1) > 0 {
|
||||||
|
t.Errorf("'%#x + int32(%#x>>%#x) > 0' failed", x32, uv32, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x32+v32<<uz >= 0 {
|
||||||
|
t.Errorf("'%#x + %#x<<%#x >= 0' failed", x32, v32, uz)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x32+v32>>uz > 0 {
|
||||||
|
t.Errorf("'%#x + %#x>>%#x > 0' failed", x32, v32, uz)
|
||||||
|
}
|
||||||
|
|
||||||
|
if x32+int32(uv32>>uz) < 0 {
|
||||||
|
} else {
|
||||||
|
t.Errorf("'%#x + int32(%#x>>%#x) < 0' failed", x32, uv32, uz)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 32-bit SUBshift, pick up 1~2 scenarios randomly for each condition
|
||||||
|
func testSubShift32(t *testing.T) {
|
||||||
|
if y32-v32<<1 > 0 {
|
||||||
|
} else {
|
||||||
|
t.Errorf("'%#x - %#x<<%#x > 0' failed", y32, v32, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if y32-v32>>1 < 0 {
|
||||||
|
t.Errorf("'%#x - %#x>>%#x < 0' failed", y32, v32, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if y32-int32(uv32>>1) >= 0 {
|
||||||
|
} else {
|
||||||
|
t.Errorf("'%#x - int32(%#x>>%#x) >= 0' failed", y32, uv32, 1)
|
||||||
|
}
|
||||||
|
|
||||||
|
if y32-v32<<uz < 0 {
|
||||||
|
t.Errorf("'%#x - %#x<<%#x < 0' failed", y32, v32, uz)
|
||||||
|
}
|
||||||
|
|
||||||
|
if y32-v32>>uz >= 0 {
|
||||||
|
} else {
|
||||||
|
t.Errorf("'%#x - %#x>>%#x >= 0' failed", y32, v32, uz)
|
||||||
|
}
|
||||||
|
|
||||||
|
if y32-int32(uv32>>uz) <= 0 {
|
||||||
|
t.Errorf("'%#x - int32(%#x>>%#x) <= 0' failed", y32, uv32, uz)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var rnd = rand.New(rand.NewSource(0))
|
var rnd = rand.New(rand.NewSource(0))
|
||||||
var sink int64
|
var sink int64
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -253,6 +253,8 @@ func CmpLogicalToZero(a, b, c uint32, d, e uint64) uint64 {
|
||||||
// 'comparing to zero' expressions
|
// 'comparing to zero' expressions
|
||||||
|
|
||||||
// var + const
|
// var + const
|
||||||
|
// 'x-const' might be canonicalized to 'x+(-const)', so we check both
|
||||||
|
// CMN and CMP for subtraction expressions to make the pattern robust.
|
||||||
func CmpToZero_ex1(a int64, e int32) int {
|
func CmpToZero_ex1(a int64, e int32) int {
|
||||||
// arm64:`CMN`,-`ADD`,`(BMI|BPL)`
|
// arm64:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||||
if a+3 < 0 {
|
if a+3 < 0 {
|
||||||
|
|
@ -269,37 +271,41 @@ func CmpToZero_ex1(a int64, e int32) int {
|
||||||
return 2
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMP`,-`SUB`,`(BMI|BPL)`
|
// arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)`
|
||||||
if a-7 < 0 {
|
if a-7 < 0 {
|
||||||
return 3
|
return 3
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMP`,-`SUB`,`(BMI|BPL)`
|
// arm64:`CMP|CMN`,-`(ADD|SUB)`,`(BMI|BPL)`
|
||||||
if a-11 >= 0 {
|
if a-11 >= 0 {
|
||||||
return 4
|
return 4
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMP`,-`SUB`,`BEQ`,`(BMI|BPL)`
|
// arm64:`CMP|CMN`,-`(ADD|SUB)`,`BEQ`,`(BMI|BPL)`
|
||||||
if a-19 > 0 {
|
if a-19 > 0 {
|
||||||
return 4
|
return 4
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||||
|
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||||
if e+3 < 0 {
|
if e+3 < 0 {
|
||||||
return 5
|
return 5
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||||
|
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||||
if e+13 >= 0 {
|
if e+13 >= 0 {
|
||||||
return 6
|
return 6
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMPW`,-`SUBW`,`(BMI|BPL)`
|
// arm64:`CMPW|CMNW`,`(BMI|BPL)`
|
||||||
|
// arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)`
|
||||||
if e-7 < 0 {
|
if e-7 < 0 {
|
||||||
return 7
|
return 7
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMPW`,-`SUBW`,`(BMI|BPL)`
|
// arm64:`CMPW|CMNW`,`(BMI|BPL)`
|
||||||
|
// arm:`CMP|CMN`, -`(ADD|SUB)`, `(BMI|BPL)`
|
||||||
if e-11 >= 0 {
|
if e-11 >= 0 {
|
||||||
return 8
|
return 8
|
||||||
}
|
}
|
||||||
|
|
@ -326,11 +332,13 @@ func CmpToZero_ex2(a, b, c int64, e, f, g int32) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||||
|
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||||
if e+f < 0 {
|
if e+f < 0 {
|
||||||
return 5
|
return 5
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
// arm64:`CMNW`,-`ADDW`,`(BMI|BPL)`
|
||||||
|
// arm:`CMN`,-`ADD`,`(BMI|BPL)`
|
||||||
if f+g >= 0 {
|
if f+g >= 0 {
|
||||||
return 6
|
return 6
|
||||||
}
|
}
|
||||||
|
|
@ -350,11 +358,13 @@ func CmpToZero_ex3(a, b, c, d int64, e, f, g, h int32) int {
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
|
// arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
|
||||||
|
// arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)`
|
||||||
if e+f*g > 0 {
|
if e+f*g > 0 {
|
||||||
return 5
|
return 5
|
||||||
}
|
}
|
||||||
|
|
||||||
// arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
|
// arm64:`CMNW`,-`MADDW`,`MULW`,`BEQ`,`(BMI|BPL)`
|
||||||
|
// arm:`CMN`,-`MULA`,`MUL`,`BEQ`,`(BMI|BPL)`
|
||||||
if f+g*h <= 0 {
|
if f+g*h <= 0 {
|
||||||
return 6
|
return 6
|
||||||
}
|
}
|
||||||
|
|
@ -384,3 +394,16 @@ func CmpToZero_ex4(a, b, c, d int64, e, f, g, h int32) int {
|
||||||
}
|
}
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func CmpToZero_ex5(e, f int32, u uint32) int {
|
||||||
|
// arm:`CMN`,-`ADD`,`BEQ`,`(BMI|BPL)`
|
||||||
|
if e+f<<1 > 0 {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// arm:`CMP`,-`SUB`,`(BMI|BPL)`
|
||||||
|
if f-int32(u>>2) >= 0 {
|
||||||
|
return 2
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue