mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile/internal: Optimization with RBIT and REV
By checking GOARM in ssa/gen/ARM.rules, each intermediate operator can be implemented via different instruction serials. It is up to the user to choose between compitability and efficiency. The Bswap32(x) is optimized to REV(x) when GOARM >= 6. The CTZ(x) is optimized to CLZ(RBIT x) when GOARM == 7. Change-Id: Ie9ee645fa39333fa79ad84ed4d1cefac30422814 Reviewed-on: https://go-review.googlesource.com/35610 Run-TryBot: Cherry Zhang <cherryyz@google.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
4a1140472b
commit
8577f81a10
16 changed files with 105 additions and 7 deletions
|
|
@ -582,6 +582,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||||
fallthrough
|
fallthrough
|
||||||
case ssa.OpARMMVN,
|
case ssa.OpARMMVN,
|
||||||
ssa.OpARMCLZ,
|
ssa.OpARMCLZ,
|
||||||
|
ssa.OpARMREV,
|
||||||
|
ssa.OpARMRBIT,
|
||||||
ssa.OpARMSQRTD,
|
ssa.OpARMSQRTD,
|
||||||
ssa.OpARMNEGF,
|
ssa.OpARMNEGF,
|
||||||
ssa.OpARMNEGD,
|
ssa.OpARMNEGD,
|
||||||
|
|
|
||||||
|
|
@ -87,14 +87,17 @@
|
||||||
|
|
||||||
(Sqrt x) -> (SQRTD x)
|
(Sqrt x) -> (SQRTD x)
|
||||||
|
|
||||||
// count trailing zero
|
// count trailing zero for ARMv5 and ARMv6
|
||||||
// 32 - CLZ(x&-x - 1)
|
// 32 - CLZ(x&-x - 1)
|
||||||
(Ctz32 <t> x) -> (RSBconst [32] (CLZ <t> (SUBconst <t> (AND <t> x (RSBconst <t> [0] x)) [1])))
|
(Ctz32 <t> x) && obj.GOARM<=6 -> (RSBconst [32] (CLZ <t> (SUBconst <t> (AND <t> x (RSBconst <t> [0] x)) [1])))
|
||||||
|
|
||||||
|
// count trailing zero for ARMv7
|
||||||
|
(Ctz32 <t> x) && obj.GOARM==7 -> (CLZ <t> (RBIT <t> x))
|
||||||
|
|
||||||
// bit length
|
// bit length
|
||||||
(BitLen32 <t> x) -> (RSBconst [32] (CLZ <t> x))
|
(BitLen32 <t> x) -> (RSBconst [32] (CLZ <t> x))
|
||||||
|
|
||||||
// byte swap
|
// byte swap for ARMv5
|
||||||
// let (a, b, c, d) be the bytes of x from high to low
|
// let (a, b, c, d) be the bytes of x from high to low
|
||||||
// t1 = x right rotate 16 bits -- (c, d, a, b )
|
// t1 = x right rotate 16 bits -- (c, d, a, b )
|
||||||
// t2 = x ^ t1 -- (a^c, b^d, a^c, b^d)
|
// t2 = x ^ t1 -- (a^c, b^d, a^c, b^d)
|
||||||
|
|
@ -103,11 +106,14 @@
|
||||||
// t5 = x right rotate 8 bits -- (d, a, b, c )
|
// t5 = x right rotate 8 bits -- (d, a, b, c )
|
||||||
// result = t4 ^ t5 -- (d, c, b, a )
|
// result = t4 ^ t5 -- (d, c, b, a )
|
||||||
// using shifted ops this can be done in 4 instructions.
|
// using shifted ops this can be done in 4 instructions.
|
||||||
(Bswap32 <t> x) ->
|
(Bswap32 <t> x) && obj.GOARM==5 ->
|
||||||
(XOR <t>
|
(XOR <t>
|
||||||
(SRLconst <t> (BICconst <t> (XOR <t> x (SRRconst <t> [16] x)) [0xff0000]) [8])
|
(SRLconst <t> (BICconst <t> (XOR <t> x (SRRconst <t> [16] x)) [0xff0000]) [8])
|
||||||
(SRRconst <t> x [8]))
|
(SRRconst <t> x [8]))
|
||||||
|
|
||||||
|
// byte swap for ARMv6 and above
|
||||||
|
(Bswap32 x) && obj.GOARM>=6 -> (REV x)
|
||||||
|
|
||||||
// boolean ops -- booleans are represented with 0=false, 1=true
|
// boolean ops -- booleans are represented with 0=false, 1=true
|
||||||
(AndB x y) -> (AND x y)
|
(AndB x y) -> (AND x y)
|
||||||
(OrB x y) -> (OR x y)
|
(OrB x y) -> (OR x y)
|
||||||
|
|
|
||||||
|
|
@ -197,7 +197,9 @@ func init() {
|
||||||
{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64
|
{name: "NEGD", argLength: 1, reg: fp11, asm: "NEGD"}, // -arg0, float64
|
||||||
{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
|
{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
|
||||||
|
|
||||||
{name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"}, // count leading zero
|
{name: "CLZ", argLength: 1, reg: gp11, asm: "CLZ"}, // count leading zero
|
||||||
|
{name: "REV", argLength: 1, reg: gp11, asm: "REV"}, // reverse byte order
|
||||||
|
{name: "RBIT", argLength: 1, reg: gp11, asm: "RBIT"}, // reverse bit order
|
||||||
|
|
||||||
// shifts
|
// shifts
|
||||||
{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 256
|
{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 256
|
||||||
|
|
|
||||||
|
|
@ -153,7 +153,9 @@ func genRules(arch arch) {
|
||||||
fmt.Fprintln(w)
|
fmt.Fprintln(w)
|
||||||
fmt.Fprintln(w, "package ssa")
|
fmt.Fprintln(w, "package ssa")
|
||||||
fmt.Fprintln(w, "import \"math\"")
|
fmt.Fprintln(w, "import \"math\"")
|
||||||
|
fmt.Fprintln(w, "import \"cmd/internal/obj\"")
|
||||||
fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used")
|
fmt.Fprintln(w, "var _ = math.MinInt8 // in case not otherwise used")
|
||||||
|
fmt.Fprintln(w, "var _ = obj.ANOP // in case not otherwise used")
|
||||||
|
|
||||||
// Main rewrite routine is a switch on v.Op.
|
// Main rewrite routine is a switch on v.Op.
|
||||||
fmt.Fprintf(w, "func rewriteValue%s(v *Value) bool {\n", arch.name)
|
fmt.Fprintf(w, "func rewriteValue%s(v *Value) bool {\n", arch.name)
|
||||||
|
|
|
||||||
|
|
@ -696,6 +696,8 @@ const (
|
||||||
OpARMNEGD
|
OpARMNEGD
|
||||||
OpARMSQRTD
|
OpARMSQRTD
|
||||||
OpARMCLZ
|
OpARMCLZ
|
||||||
|
OpARMREV
|
||||||
|
OpARMRBIT
|
||||||
OpARMSLL
|
OpARMSLL
|
||||||
OpARMSLLconst
|
OpARMSLLconst
|
||||||
OpARMSRL
|
OpARMSRL
|
||||||
|
|
@ -8443,6 +8445,32 @@ var opcodeTable = [...]opInfo{
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "REV",
|
||||||
|
argLen: 1,
|
||||||
|
asm: arm.AREV,
|
||||||
|
reg: regInfo{
|
||||||
|
inputs: []inputInfo{
|
||||||
|
{0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
|
||||||
|
},
|
||||||
|
outputs: []outputInfo{
|
||||||
|
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "RBIT",
|
||||||
|
argLen: 1,
|
||||||
|
asm: arm.ARBIT,
|
||||||
|
reg: regInfo{
|
||||||
|
inputs: []inputInfo{
|
||||||
|
{0, 22527}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 g R12 R14
|
||||||
|
},
|
||||||
|
outputs: []outputInfo{
|
||||||
|
{0, 21503}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 R14
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
{
|
{
|
||||||
name: "SLL",
|
name: "SLL",
|
||||||
argLen: 2,
|
argLen: 2,
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValue386(v *Value) bool {
|
func rewriteValue386(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case Op386ADCL:
|
case Op386ADCL:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValueAMD64(v *Value) bool {
|
func rewriteValueAMD64(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpAMD64ADDL:
|
case OpAMD64ADDL:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValueARM(v *Value) bool {
|
func rewriteValueARM(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpARMADC:
|
case OpARMADC:
|
||||||
|
|
@ -12904,11 +12906,14 @@ func rewriteValueARM_OpBswap32(v *Value) bool {
|
||||||
b := v.Block
|
b := v.Block
|
||||||
_ = b
|
_ = b
|
||||||
// match: (Bswap32 <t> x)
|
// match: (Bswap32 <t> x)
|
||||||
// cond:
|
// cond: obj.GOARM==5
|
||||||
// result: (XOR <t> (SRLconst <t> (BICconst <t> (XOR <t> x (SRRconst <t> [16] x)) [0xff0000]) [8]) (SRRconst <t> x [8]))
|
// result: (XOR <t> (SRLconst <t> (BICconst <t> (XOR <t> x (SRRconst <t> [16] x)) [0xff0000]) [8]) (SRRconst <t> x [8]))
|
||||||
for {
|
for {
|
||||||
t := v.Type
|
t := v.Type
|
||||||
x := v.Args[0]
|
x := v.Args[0]
|
||||||
|
if !(obj.GOARM == 5) {
|
||||||
|
break
|
||||||
|
}
|
||||||
v.reset(OpARMXOR)
|
v.reset(OpARMXOR)
|
||||||
v.Type = t
|
v.Type = t
|
||||||
v0 := b.NewValue0(v.Pos, OpARMSRLconst, t)
|
v0 := b.NewValue0(v.Pos, OpARMSRLconst, t)
|
||||||
|
|
@ -12930,6 +12935,19 @@ func rewriteValueARM_OpBswap32(v *Value) bool {
|
||||||
v.AddArg(v4)
|
v.AddArg(v4)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// match: (Bswap32 x)
|
||||||
|
// cond: obj.GOARM>=6
|
||||||
|
// result: (REV x)
|
||||||
|
for {
|
||||||
|
x := v.Args[0]
|
||||||
|
if !(obj.GOARM >= 6) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v.reset(OpARMREV)
|
||||||
|
v.AddArg(x)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
func rewriteValueARM_OpClosureCall(v *Value) bool {
|
func rewriteValueARM_OpClosureCall(v *Value) bool {
|
||||||
// match: (ClosureCall [argwid] entry closure mem)
|
// match: (ClosureCall [argwid] entry closure mem)
|
||||||
|
|
@ -13074,11 +13092,14 @@ func rewriteValueARM_OpCtz32(v *Value) bool {
|
||||||
b := v.Block
|
b := v.Block
|
||||||
_ = b
|
_ = b
|
||||||
// match: (Ctz32 <t> x)
|
// match: (Ctz32 <t> x)
|
||||||
// cond:
|
// cond: obj.GOARM<=6
|
||||||
// result: (RSBconst [32] (CLZ <t> (SUBconst <t> (AND <t> x (RSBconst <t> [0] x)) [1])))
|
// result: (RSBconst [32] (CLZ <t> (SUBconst <t> (AND <t> x (RSBconst <t> [0] x)) [1])))
|
||||||
for {
|
for {
|
||||||
t := v.Type
|
t := v.Type
|
||||||
x := v.Args[0]
|
x := v.Args[0]
|
||||||
|
if !(obj.GOARM <= 6) {
|
||||||
|
break
|
||||||
|
}
|
||||||
v.reset(OpARMRSBconst)
|
v.reset(OpARMRSBconst)
|
||||||
v.AuxInt = 32
|
v.AuxInt = 32
|
||||||
v0 := b.NewValue0(v.Pos, OpARMCLZ, t)
|
v0 := b.NewValue0(v.Pos, OpARMCLZ, t)
|
||||||
|
|
@ -13095,6 +13116,23 @@ func rewriteValueARM_OpCtz32(v *Value) bool {
|
||||||
v.AddArg(v0)
|
v.AddArg(v0)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
// match: (Ctz32 <t> x)
|
||||||
|
// cond: obj.GOARM==7
|
||||||
|
// result: (CLZ <t> (RBIT <t> x))
|
||||||
|
for {
|
||||||
|
t := v.Type
|
||||||
|
x := v.Args[0]
|
||||||
|
if !(obj.GOARM == 7) {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
v.reset(OpARMCLZ)
|
||||||
|
v.Type = t
|
||||||
|
v0 := b.NewValue0(v.Pos, OpARMRBIT, t)
|
||||||
|
v0.AddArg(x)
|
||||||
|
v.AddArg(v0)
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
return false
|
||||||
}
|
}
|
||||||
func rewriteValueARM_OpCvt32Fto32(v *Value) bool {
|
func rewriteValueARM_OpCvt32Fto32(v *Value) bool {
|
||||||
// match: (Cvt32Fto32 x)
|
// match: (Cvt32Fto32 x)
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValueARM64(v *Value) bool {
|
func rewriteValueARM64(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpARM64ADD:
|
case OpARM64ADD:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValueMIPS(v *Value) bool {
|
func rewriteValueMIPS(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpAdd16:
|
case OpAdd16:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValueMIPS64(v *Value) bool {
|
func rewriteValueMIPS64(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpAdd16:
|
case OpAdd16:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValuePPC64(v *Value) bool {
|
func rewriteValuePPC64(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpAdd16:
|
case OpAdd16:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValueS390X(v *Value) bool {
|
func rewriteValueS390X(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpAdd16:
|
case OpAdd16:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValuedec(v *Value) bool {
|
func rewriteValuedec(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpComplexImag:
|
case OpComplexImag:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValuedec64(v *Value) bool {
|
func rewriteValuedec64(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpAdd64:
|
case OpAdd64:
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,10 @@
|
||||||
package ssa
|
package ssa
|
||||||
|
|
||||||
import "math"
|
import "math"
|
||||||
|
import "cmd/internal/obj"
|
||||||
|
|
||||||
var _ = math.MinInt8 // in case not otherwise used
|
var _ = math.MinInt8 // in case not otherwise used
|
||||||
|
var _ = obj.ANOP // in case not otherwise used
|
||||||
func rewriteValuegeneric(v *Value) bool {
|
func rewriteValuegeneric(v *Value) bool {
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpAdd16:
|
case OpAdd16:
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue