1
0
mirror of https://github.com/golang/go synced 2024-10-03 03:11:21 -06:00

[dev.ssa] cmd/compile: use shifted and indexed ops in SSA for ARM

This CL implements the following optimizations for ARM:
- use shifted ops (e.g. ADD R1<<2, R2) and indexed load/stores
- break up shift ops. Shifts used to be one SSA op that generates
  multiple instructions. We break them up to multiple ops, which
  allows constant folding and CSE for comparisons. Conditional moves
  are introduced for this.
- simplify zero/sign-extension ops.

Updates #15365.

Change-Id: I55e262a776a7ef2a1505d75e04d1208913c35d39
Reviewed-on: https://go-review.googlesource.com/24512
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
Cherry Zhang 2016-06-17 10:34:06 -04:00
parent 14cf6e2083
commit 8cc3f4a17e
7 changed files with 11557 additions and 225 deletions

View File

@ -5,6 +5,7 @@
package arm
import (
"fmt"
"math"
"cmd/compile/internal/gc"
@ -108,6 +109,57 @@ func storeByType(t ssa.Type) obj.As {
panic("bad store type")
}
// shift type is used as Offset in obj.TYPE_SHIFT operands to encode shifted register operands
type shift int64
// copied from ../../../internal/obj/util.go:/TYPE_SHIFT
func (v shift) String() string {
op := "<<>>->@>"[((v>>5)&3)<<1:]
if v&(1<<4) != 0 {
// register shift
return fmt.Sprintf("R%d%c%cR%d", v&15, op[0], op[1], (v>>8)&15)
} else {
// constant shift
return fmt.Sprintf("R%d%c%c%d", v&15, op[0], op[1], (v>>7)&31)
}
}
// makeshift encodes a register shifted by a constant
func makeshift(reg int16, typ int64, s int64) shift {
return shift(int64(reg&0xf) | typ | (s&31)<<7)
}
// genshift generates a Prog for r = r0 op (r1 shifted by s)
func genshift(as obj.As, r0, r1, r int16, typ int64, s int64) *obj.Prog {
p := gc.Prog(as)
p.From.Type = obj.TYPE_SHIFT
p.From.Offset = int64(makeshift(r1, typ, s))
p.Reg = r0
if r != 0 {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
}
return p
}
// makeregshift encodes a register shifted by a register
func makeregshift(r1 int16, typ int64, r2 int16) shift {
return shift(int64(r1&0xf) | typ | int64(r2&0xf)<<8 | 1<<4)
}
// genregshift generates a Prog for r = r0 op (r1 shifted by r2)
func genregshift(as obj.As, r0, r1, r2, r int16, typ int64) *obj.Prog {
p := gc.Prog(as)
p.From.Type = obj.TYPE_SHIFT
p.From.Offset = int64(makeregshift(r1, typ, r2))
p.Reg = r0
if r != 0 {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
}
return p
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line)
switch v.Op {
@ -237,45 +289,27 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case ssa.OpARMSLL,
ssa.OpARMSRL:
// ARM shift instructions uses only the low-order byte of the shift amount
// generate conditional instructions to deal with large shifts
// CMP $32, Rarg1
// SLL Rarg1, Rarg0, Rdst
// MOVW.HS $0, Rdst
ssa.OpARMSRL,
ssa.OpARMSRA:
r := gc.SSARegNum(v)
r1 := gc.SSARegNum(v.Args[0])
r2 := gc.SSARegNum(v.Args[1])
p := gc.Prog(arm.ACMP)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 32
p.Reg = r2
p = gc.Prog(v.Op.Asm())
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = r2
p.Reg = r1
p.To.Type = obj.TYPE_REG
p.To.Reg = r
p = gc.Prog(arm.AMOVW)
p.Scond = arm.C_SCOND_HS
p.From.Type = obj.TYPE_CONST
p.From.Offset = 0
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case ssa.OpARMSRA:
case ssa.OpARMSRAcond:
// ARM shift instructions uses only the low-order byte of the shift amount
// generate conditional instructions to deal with large shifts
// CMP $32, Rarg1
// flag is already set
// SRA.HS $31, Rarg0, Rdst // shift 31 bits to get the sign bit
// SRA.LO Rarg1, Rarg0, Rdst
r := gc.SSARegNum(v)
r1 := gc.SSARegNum(v.Args[0])
r2 := gc.SSARegNum(v.Args[1])
p := gc.Prog(arm.ACMP)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 32
p.Reg = r2
p = gc.Prog(arm.ASRA)
p := gc.Prog(arm.ASRA)
p.Scond = arm.C_SCOND_HS
p.From.Type = obj.TYPE_CONST
p.From.Offset = 31
@ -319,11 +353,115 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpARMSRRconst:
p := gc.Prog(arm.AMOVW)
p.From.Type = obj.TYPE_SHIFT
p.From.Offset = int64(gc.SSARegNum(v.Args[0])&0xf) | arm.SHIFT_RR | (v.AuxInt&31)<<7
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
genshift(arm.AMOVW, 0, gc.SSARegNum(v.Args[0]), gc.SSARegNum(v), arm.SHIFT_RR, v.AuxInt)
case ssa.OpARMADDshiftLL,
ssa.OpARMADCshiftLL,
ssa.OpARMSUBshiftLL,
ssa.OpARMSBCshiftLL,
ssa.OpARMRSBshiftLL,
ssa.OpARMRSCshiftLL,
ssa.OpARMANDshiftLL,
ssa.OpARMORshiftLL,
ssa.OpARMXORshiftLL,
ssa.OpARMBICshiftLL:
genshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_LL, v.AuxInt)
case ssa.OpARMADDSshiftLL,
ssa.OpARMSUBSshiftLL,
ssa.OpARMRSBSshiftLL:
p := genshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_LL, v.AuxInt)
p.Scond = arm.C_SBIT
case ssa.OpARMADDshiftRL,
ssa.OpARMADCshiftRL,
ssa.OpARMSUBshiftRL,
ssa.OpARMSBCshiftRL,
ssa.OpARMRSBshiftRL,
ssa.OpARMRSCshiftRL,
ssa.OpARMANDshiftRL,
ssa.OpARMORshiftRL,
ssa.OpARMXORshiftRL,
ssa.OpARMBICshiftRL:
genshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_LR, v.AuxInt)
case ssa.OpARMADDSshiftRL,
ssa.OpARMSUBSshiftRL,
ssa.OpARMRSBSshiftRL:
p := genshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_LR, v.AuxInt)
p.Scond = arm.C_SBIT
case ssa.OpARMADDshiftRA,
ssa.OpARMADCshiftRA,
ssa.OpARMSUBshiftRA,
ssa.OpARMSBCshiftRA,
ssa.OpARMRSBshiftRA,
ssa.OpARMRSCshiftRA,
ssa.OpARMANDshiftRA,
ssa.OpARMORshiftRA,
ssa.OpARMXORshiftRA,
ssa.OpARMBICshiftRA:
genshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_AR, v.AuxInt)
case ssa.OpARMADDSshiftRA,
ssa.OpARMSUBSshiftRA,
ssa.OpARMRSBSshiftRA:
p := genshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_AR, v.AuxInt)
p.Scond = arm.C_SBIT
case ssa.OpARMMVNshiftLL:
genshift(v.Op.Asm(), 0, gc.SSARegNum(v.Args[0]), gc.SSARegNum(v), arm.SHIFT_LL, v.AuxInt)
case ssa.OpARMMVNshiftRL:
genshift(v.Op.Asm(), 0, gc.SSARegNum(v.Args[0]), gc.SSARegNum(v), arm.SHIFT_LR, v.AuxInt)
case ssa.OpARMMVNshiftRA:
genshift(v.Op.Asm(), 0, gc.SSARegNum(v.Args[0]), gc.SSARegNum(v), arm.SHIFT_AR, v.AuxInt)
case ssa.OpARMMVNshiftLLreg:
genregshift(v.Op.Asm(), 0, gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_LL)
case ssa.OpARMMVNshiftRLreg:
genregshift(v.Op.Asm(), 0, gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_LR)
case ssa.OpARMMVNshiftRAreg:
genregshift(v.Op.Asm(), 0, gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_AR)
case ssa.OpARMADDshiftLLreg,
ssa.OpARMADCshiftLLreg,
ssa.OpARMSUBshiftLLreg,
ssa.OpARMSBCshiftLLreg,
ssa.OpARMRSBshiftLLreg,
ssa.OpARMRSCshiftLLreg,
ssa.OpARMANDshiftLLreg,
ssa.OpARMORshiftLLreg,
ssa.OpARMXORshiftLLreg,
ssa.OpARMBICshiftLLreg:
genregshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[2]), gc.SSARegNum(v), arm.SHIFT_LL)
case ssa.OpARMADDSshiftLLreg,
ssa.OpARMSUBSshiftLLreg,
ssa.OpARMRSBSshiftLLreg:
p := genregshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[2]), gc.SSARegNum(v), arm.SHIFT_LL)
p.Scond = arm.C_SBIT
case ssa.OpARMADDshiftRLreg,
ssa.OpARMADCshiftRLreg,
ssa.OpARMSUBshiftRLreg,
ssa.OpARMSBCshiftRLreg,
ssa.OpARMRSBshiftRLreg,
ssa.OpARMRSCshiftRLreg,
ssa.OpARMANDshiftRLreg,
ssa.OpARMORshiftRLreg,
ssa.OpARMXORshiftRLreg,
ssa.OpARMBICshiftRLreg:
genregshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[2]), gc.SSARegNum(v), arm.SHIFT_LR)
case ssa.OpARMADDSshiftRLreg,
ssa.OpARMSUBSshiftRLreg,
ssa.OpARMRSBSshiftRLreg:
p := genregshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[2]), gc.SSARegNum(v), arm.SHIFT_LR)
p.Scond = arm.C_SBIT
case ssa.OpARMADDshiftRAreg,
ssa.OpARMADCshiftRAreg,
ssa.OpARMSUBshiftRAreg,
ssa.OpARMSBCshiftRAreg,
ssa.OpARMRSBshiftRAreg,
ssa.OpARMRSCshiftRAreg,
ssa.OpARMANDshiftRAreg,
ssa.OpARMORshiftRAreg,
ssa.OpARMXORshiftRAreg,
ssa.OpARMBICshiftRAreg:
genregshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[2]), gc.SSARegNum(v), arm.SHIFT_AR)
case ssa.OpARMADDSshiftRAreg,
ssa.OpARMSUBSshiftRAreg,
ssa.OpARMRSBSshiftRAreg:
p := genregshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[2]), gc.SSARegNum(v), arm.SHIFT_AR)
p.Scond = arm.C_SBIT
case ssa.OpARMHMUL,
ssa.OpARMHMULU:
// 32-bit high multiplication
@ -385,6 +523,18 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
p.Reg = gc.SSARegNum(v.Args[0])
case ssa.OpARMCMPshiftLL:
genshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), 0, arm.SHIFT_LL, v.AuxInt)
case ssa.OpARMCMPshiftRL:
genshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), 0, arm.SHIFT_LR, v.AuxInt)
case ssa.OpARMCMPshiftRA:
genshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), 0, arm.SHIFT_AR, v.AuxInt)
case ssa.OpARMCMPshiftLLreg:
genregshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[2]), 0, arm.SHIFT_LL)
case ssa.OpARMCMPshiftRLreg:
genregshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[2]), 0, arm.SHIFT_LR)
case ssa.OpARMCMPshiftRAreg:
genregshift(v.Op.Asm(), gc.SSARegNum(v.Args[0]), gc.SSARegNum(v.Args[1]), gc.SSARegNum(v.Args[2]), 0, arm.SHIFT_AR)
case ssa.OpARMMOVWaddr:
p := gc.Prog(arm.AMOVW)
p.From.Type = obj.TYPE_ADDR
@ -440,11 +590,72 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Type = obj.TYPE_MEM
p.To.Reg = gc.SSARegNum(v.Args[0])
gc.AddAux(&p.To, v)
case ssa.OpARMMOVWloadidx:
// this is just shift 0 bits
fallthrough
case ssa.OpARMMOVWloadshiftLL:
p := genshift(v.Op.Asm(), 0, gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_LL, v.AuxInt)
p.From.Reg = gc.SSARegNum(v.Args[0])
case ssa.OpARMMOVWloadshiftRL:
p := genshift(v.Op.Asm(), 0, gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_LR, v.AuxInt)
p.From.Reg = gc.SSARegNum(v.Args[0])
case ssa.OpARMMOVWloadshiftRA:
p := genshift(v.Op.Asm(), 0, gc.SSARegNum(v.Args[1]), gc.SSARegNum(v), arm.SHIFT_AR, v.AuxInt)
p.From.Reg = gc.SSARegNum(v.Args[0])
case ssa.OpARMMOVWstoreidx:
// this is just shift 0 bits
fallthrough
case ssa.OpARMMOVWstoreshiftLL:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = gc.SSARegNum(v.Args[2])
p.To.Type = obj.TYPE_SHIFT
p.To.Reg = gc.SSARegNum(v.Args[0])
p.To.Offset = int64(makeshift(gc.SSARegNum(v.Args[1]), arm.SHIFT_LL, v.AuxInt))
case ssa.OpARMMOVWstoreshiftRL:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = gc.SSARegNum(v.Args[2])
p.To.Type = obj.TYPE_SHIFT
p.To.Reg = gc.SSARegNum(v.Args[0])
p.To.Offset = int64(makeshift(gc.SSARegNum(v.Args[1]), arm.SHIFT_LR, v.AuxInt))
case ssa.OpARMMOVWstoreshiftRA:
p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_REG
p.From.Reg = gc.SSARegNum(v.Args[2])
p.To.Type = obj.TYPE_SHIFT
p.To.Reg = gc.SSARegNum(v.Args[0])
p.To.Offset = int64(makeshift(gc.SSARegNum(v.Args[1]), arm.SHIFT_AR, v.AuxInt))
case ssa.OpARMMOVBreg,
ssa.OpARMMOVBUreg,
ssa.OpARMMOVHreg,
ssa.OpARMMOVHUreg,
ssa.OpARMMVN,
ssa.OpARMMOVHUreg:
a := v.Args[0]
for a.Op == ssa.OpCopy || a.Op == ssa.OpARMMOVWreg {
a = a.Args[0]
}
if a.Op == ssa.OpLoadReg {
t := a.Type
switch {
case v.Op == ssa.OpARMMOVBreg && t.Size() == 1 && t.IsSigned(),
v.Op == ssa.OpARMMOVBUreg && t.Size() == 1 && !t.IsSigned(),
v.Op == ssa.OpARMMOVHreg && t.Size() == 2 && t.IsSigned(),
v.Op == ssa.OpARMMOVHUreg && t.Size() == 2 && !t.IsSigned():
// arg is a proper-typed load, already zero/sign-extended, don't extend again
if gc.SSARegNum(v) == gc.SSARegNum(v.Args[0]) {
return
}
p := gc.Prog(arm.AMOVW)
p.From.Type = obj.TYPE_REG
p.From.Reg = gc.SSARegNum(v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
return
default:
}
}
fallthrough
case ssa.OpARMMVN,
ssa.OpARMSQRTD,
ssa.OpARMMOVWF,
ssa.OpARMMOVWD,
@ -467,6 +678,20 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Reg = gc.SSARegNum(v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpARMCMOVWHSconst:
p := gc.Prog(arm.AMOVW)
p.Scond = arm.C_SCOND_HS
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpARMCMOVWLSconst:
p := gc.Prog(arm.AMOVW)
p.Scond = arm.C_SCOND_LS
p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpARMCALLstatic:
if v.Aux.(*gc.Sym) == gc.Deferreturn.Sym {
// Deferred calls will appear to be returning to
@ -657,24 +882,6 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p4 := gc.Prog(arm.ABLT)
p4.To.Type = obj.TYPE_BRANCH
gc.Patch(p4, p)
case ssa.OpARMLoweredZeromask:
// int32(arg0>>1 - arg0) >> 31
// RSB r0>>1, r0, r
// SRA $31, r, r
r0 := gc.SSARegNum(v.Args[0])
r := gc.SSARegNum(v)
p := gc.Prog(arm.ARSB)
p.From.Type = obj.TYPE_SHIFT
p.From.Offset = int64(r0&0xf) | arm.SHIFT_LR | 1<<7 // unsigned r0>>1
p.Reg = r0
p.To.Type = obj.TYPE_REG
p.To.Reg = r
p = gc.Prog(arm.ASRA)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 31
p.Reg = r
p.To.Type = obj.TYPE_REG
p.To.Reg = r
case ssa.OpVarDef:
gc.Gvardef(v.Aux.(*gc.Node))
case ssa.OpVarKill:

View File

@ -553,6 +553,445 @@ func testOrPhi() {
}
}
//go:noinline
func addshiftLL_ssa(a, b uint32) uint32 {
return a + b<<3
}
//go:noinline
func subshiftLL_ssa(a, b uint32) uint32 {
return a - b<<3
}
//go:noinline
func rsbshiftLL_ssa(a, b uint32) uint32 {
return a<<3 - b
}
//go:noinline
func andshiftLL_ssa(a, b uint32) uint32 {
return a & (b << 3)
}
//go:noinline
func orshiftLL_ssa(a, b uint32) uint32 {
return a | b<<3
}
//go:noinline
func xorshiftLL_ssa(a, b uint32) uint32 {
return a ^ b<<3
}
//go:noinline
func bicshiftLL_ssa(a, b uint32) uint32 {
return a &^ (b << 3)
}
//go:noinline
func notshiftLL_ssa(a uint32) uint32 {
return ^(a << 3)
}
//go:noinline
func addshiftRL_ssa(a, b uint32) uint32 {
return a + b>>3
}
//go:noinline
func subshiftRL_ssa(a, b uint32) uint32 {
return a - b>>3
}
//go:noinline
func rsbshiftRL_ssa(a, b uint32) uint32 {
return a>>3 - b
}
//go:noinline
func andshiftRL_ssa(a, b uint32) uint32 {
return a & (b >> 3)
}
//go:noinline
func orshiftRL_ssa(a, b uint32) uint32 {
return a | b>>3
}
//go:noinline
func xorshiftRL_ssa(a, b uint32) uint32 {
return a ^ b>>3
}
//go:noinline
func bicshiftRL_ssa(a, b uint32) uint32 {
return a &^ (b >> 3)
}
//go:noinline
func notshiftRL_ssa(a uint32) uint32 {
return ^(a >> 3)
}
//go:noinline
func addshiftRA_ssa(a, b int32) int32 {
return a + b>>3
}
//go:noinline
func subshiftRA_ssa(a, b int32) int32 {
return a - b>>3
}
//go:noinline
func rsbshiftRA_ssa(a, b int32) int32 {
return a>>3 - b
}
//go:noinline
func andshiftRA_ssa(a, b int32) int32 {
return a & (b >> 3)
}
//go:noinline
func orshiftRA_ssa(a, b int32) int32 {
return a | b>>3
}
//go:noinline
func xorshiftRA_ssa(a, b int32) int32 {
return a ^ b>>3
}
//go:noinline
func bicshiftRA_ssa(a, b int32) int32 {
return a &^ (b >> 3)
}
//go:noinline
func notshiftRA_ssa(a int32) int32 {
return ^(a >> 3)
}
//go:noinline
func addshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
return a + b<<s
}
//go:noinline
func subshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
return a - b<<s
}
//go:noinline
func rsbshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
return a<<s - b
}
//go:noinline
func andshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
return a & (b << s)
}
//go:noinline
func orshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
return a | b<<s
}
//go:noinline
func xorshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
return a ^ b<<s
}
//go:noinline
func bicshiftLLreg_ssa(a, b uint32, s uint8) uint32 {
return a &^ (b << s)
}
//go:noinline
func notshiftLLreg_ssa(a uint32, s uint8) uint32 {
return ^(a << s)
}
//go:noinline
func addshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
return a + b>>s
}
//go:noinline
func subshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
return a - b>>s
}
//go:noinline
func rsbshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
return a>>s - b
}
//go:noinline
func andshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
return a & (b >> s)
}
//go:noinline
func orshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
return a | b>>s
}
//go:noinline
func xorshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
return a ^ b>>s
}
//go:noinline
func bicshiftRLreg_ssa(a, b uint32, s uint8) uint32 {
return a &^ (b >> s)
}
//go:noinline
func notshiftRLreg_ssa(a uint32, s uint8) uint32 {
return ^(a >> s)
}
//go:noinline
func addshiftRAreg_ssa(a, b int32, s uint8) int32 {
return a + b>>s
}
//go:noinline
func subshiftRAreg_ssa(a, b int32, s uint8) int32 {
return a - b>>s
}
//go:noinline
func rsbshiftRAreg_ssa(a, b int32, s uint8) int32 {
return a>>s - b
}
//go:noinline
func andshiftRAreg_ssa(a, b int32, s uint8) int32 {
return a & (b >> s)
}
//go:noinline
func orshiftRAreg_ssa(a, b int32, s uint8) int32 {
return a | b>>s
}
//go:noinline
func xorshiftRAreg_ssa(a, b int32, s uint8) int32 {
return a ^ b>>s
}
//go:noinline
func bicshiftRAreg_ssa(a, b int32, s uint8) int32 {
return a &^ (b >> s)
}
//go:noinline
func notshiftRAreg_ssa(a int32, s uint8) int32 {
return ^(a >> s)
}
// test ARM shifted ops
func testShiftedOps() {
a, b := uint32(10), uint32(42)
if want, got := a+b<<3, addshiftLL_ssa(a, b); got != want {
println("addshiftLL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a-b<<3, subshiftLL_ssa(a, b); got != want {
println("subshiftLL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a<<3-b, rsbshiftLL_ssa(a, b); got != want {
println("rsbshiftLL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a&(b<<3), andshiftLL_ssa(a, b); got != want {
println("andshiftLL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a|b<<3, orshiftLL_ssa(a, b); got != want {
println("orshiftLL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a^b<<3, xorshiftLL_ssa(a, b); got != want {
println("xorshiftLL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a&^(b<<3), bicshiftLL_ssa(a, b); got != want {
println("bicshiftLL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := ^(a << 3), notshiftLL_ssa(a); got != want {
println("notshiftLL_ssa(10) =", got, " want ", want)
failed = true
}
if want, got := a+b>>3, addshiftRL_ssa(a, b); got != want {
println("addshiftRL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a-b>>3, subshiftRL_ssa(a, b); got != want {
println("subshiftRL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a>>3-b, rsbshiftRL_ssa(a, b); got != want {
println("rsbshiftRL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a&(b>>3), andshiftRL_ssa(a, b); got != want {
println("andshiftRL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a|b>>3, orshiftRL_ssa(a, b); got != want {
println("orshiftRL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a^b>>3, xorshiftRL_ssa(a, b); got != want {
println("xorshiftRL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := a&^(b>>3), bicshiftRL_ssa(a, b); got != want {
println("bicshiftRL_ssa(10, 42) =", got, " want ", want)
failed = true
}
if want, got := ^(a >> 3), notshiftRL_ssa(a); got != want {
println("notshiftRL_ssa(10) =", got, " want ", want)
failed = true
}
c, d := int32(10), int32(-42)
if want, got := c+d>>3, addshiftRA_ssa(c, d); got != want {
println("addshiftRA_ssa(10, -42) =", got, " want ", want)
failed = true
}
if want, got := c-d>>3, subshiftRA_ssa(c, d); got != want {
println("subshiftRA_ssa(10, -42) =", got, " want ", want)
failed = true
}
if want, got := c>>3-d, rsbshiftRA_ssa(c, d); got != want {
println("rsbshiftRA_ssa(10, -42) =", got, " want ", want)
failed = true
}
if want, got := c&(d>>3), andshiftRA_ssa(c, d); got != want {
println("andshiftRA_ssa(10, -42) =", got, " want ", want)
failed = true
}
if want, got := c|d>>3, orshiftRA_ssa(c, d); got != want {
println("orshiftRA_ssa(10, -42) =", got, " want ", want)
failed = true
}
if want, got := c^d>>3, xorshiftRA_ssa(c, d); got != want {
println("xorshiftRA_ssa(10, -42) =", got, " want ", want)
failed = true
}
if want, got := c&^(d>>3), bicshiftRA_ssa(c, d); got != want {
println("bicshiftRA_ssa(10, -42) =", got, " want ", want)
failed = true
}
if want, got := ^(d >> 3), notshiftRA_ssa(d); got != want {
println("notshiftRA_ssa(-42) =", got, " want ", want)
failed = true
}
s := uint8(3)
if want, got := a+b<<s, addshiftLLreg_ssa(a, b, s); got != want {
println("addshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a-b<<s, subshiftLLreg_ssa(a, b, s); got != want {
println("subshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a<<s-b, rsbshiftLLreg_ssa(a, b, s); got != want {
println("rsbshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a&(b<<s), andshiftLLreg_ssa(a, b, s); got != want {
println("andshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a|b<<s, orshiftLLreg_ssa(a, b, s); got != want {
println("orshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a^b<<s, xorshiftLLreg_ssa(a, b, s); got != want {
println("xorshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a&^(b<<s), bicshiftLLreg_ssa(a, b, s); got != want {
println("bicshiftLLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := ^(a << s), notshiftLLreg_ssa(a, s); got != want {
println("notshiftLLreg_ssa(10) =", got, " want ", want)
failed = true
}
if want, got := a+b>>s, addshiftRLreg_ssa(a, b, s); got != want {
println("addshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a-b>>s, subshiftRLreg_ssa(a, b, s); got != want {
println("subshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a>>s-b, rsbshiftRLreg_ssa(a, b, s); got != want {
println("rsbshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a&(b>>s), andshiftRLreg_ssa(a, b, s); got != want {
println("andshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a|b>>s, orshiftRLreg_ssa(a, b, s); got != want {
println("orshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a^b>>s, xorshiftRLreg_ssa(a, b, s); got != want {
println("xorshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := a&^(b>>s), bicshiftRLreg_ssa(a, b, s); got != want {
println("bicshiftRLreg_ssa(10, 42, 3) =", got, " want ", want)
failed = true
}
if want, got := ^(a >> s), notshiftRLreg_ssa(a, s); got != want {
println("notshiftRLreg_ssa(10) =", got, " want ", want)
failed = true
}
if want, got := c+d>>s, addshiftRAreg_ssa(c, d, s); got != want {
println("addshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
failed = true
}
if want, got := c-d>>s, subshiftRAreg_ssa(c, d, s); got != want {
println("subshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
failed = true
}
if want, got := c>>s-d, rsbshiftRAreg_ssa(c, d, s); got != want {
println("rsbshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
failed = true
}
if want, got := c&(d>>s), andshiftRAreg_ssa(c, d, s); got != want {
println("andshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
failed = true
}
if want, got := c|d>>s, orshiftRAreg_ssa(c, d, s); got != want {
println("orshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
failed = true
}
if want, got := c^d>>s, xorshiftRAreg_ssa(c, d, s); got != want {
println("xorshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
failed = true
}
if want, got := c&^(d>>s), bicshiftRAreg_ssa(c, d, s); got != want {
println("bicshiftRAreg_ssa(10, -42, 3) =", got, " want ", want)
failed = true
}
if want, got := ^(d >> s), notshiftRAreg_ssa(d, s); got != want {
println("notshiftRAreg_ssa(-42, 3) =", got, " want ", want)
failed = true
}
}
var failed = false
func main() {
@ -573,6 +1012,7 @@ func main() {
testLoadCombine()
testLoadSymCombine()
testShiftRemoval()
testShiftedOps()
if failed {
panic("failed")

View File

@ -87,40 +87,42 @@
(Not x) -> (XORconst [1] x)
// shifts
(Lsh32x32 x y) -> (SLL x y)
(Lsh32x16 x y) -> (SLL x (ZeroExt16to32 y))
// hardware instruction uses only the low byte of the shift
// we compare to 256 to ensure Go semantics for large shifts
(Lsh32x32 x y) -> (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
(Lsh32x16 x y) -> (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
(Lsh32x8 x y) -> (SLL x (ZeroExt8to32 y))
(Lsh16x32 x y) -> (SLL x y)
(Lsh16x16 x y) -> (SLL x (ZeroExt16to32 y))
(Lsh16x32 x y) -> (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
(Lsh16x16 x y) -> (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
(Lsh16x8 x y) -> (SLL x (ZeroExt8to32 y))
(Lsh8x32 x y) -> (SLL x y)
(Lsh8x16 x y) -> (SLL x (ZeroExt16to32 y))
(Lsh8x32 x y) -> (CMOVWHSconst (SLL <x.Type> x y) (CMPconst [256] y) [0])
(Lsh8x16 x y) -> (CMOVWHSconst (SLL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
(Lsh8x8 x y) -> (SLL x (ZeroExt8to32 y))
(Rsh32Ux32 x y) -> (SRL x y)
(Rsh32Ux16 x y) -> (SRL x (ZeroExt16to32 y))
(Rsh32Ux32 x y) -> (CMOVWHSconst (SRL <x.Type> x y) (CMPconst [256] y) [0])
(Rsh32Ux16 x y) -> (CMOVWHSconst (SRL <x.Type> x (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
(Rsh32Ux8 x y) -> (SRL x (ZeroExt8to32 y))
(Rsh16Ux32 x y) -> (SRL (ZeroExt16to32 x) y)
(Rsh16Ux16 x y) -> (SRL (ZeroExt16to32 x) (ZeroExt16to32 y))
(Rsh16Ux32 x y) -> (CMOVWHSconst (SRL <x.Type> (ZeroExt16to32 x) y) (CMPconst [256] y) [0])
(Rsh16Ux16 x y) -> (CMOVWHSconst (SRL <x.Type> (ZeroExt16to32 x) (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
(Rsh16Ux8 x y) -> (SRL (ZeroExt16to32 x) (ZeroExt8to32 y))
(Rsh8Ux32 x y) -> (SRL (ZeroExt8to32 x) y)
(Rsh8Ux16 x y) -> (SRL (ZeroExt8to32 x) (ZeroExt16to32 y))
(Rsh8Ux32 x y) -> (CMOVWHSconst (SRL <x.Type> (ZeroExt8to32 x) y) (CMPconst [256] y) [0])
(Rsh8Ux16 x y) -> (CMOVWHSconst (SRL <x.Type> (ZeroExt8to32 x) (ZeroExt16to32 y)) (CMPconst [256] (ZeroExt16to32 y)) [0])
(Rsh8Ux8 x y) -> (SRL (ZeroExt8to32 x) (ZeroExt8to32 y))
(Rsh32x32 x y) -> (SRA x y)
(Rsh32x16 x y) -> (SRA x (ZeroExt16to32 y))
(Rsh32x32 x y) -> (SRAcond x y (CMPconst [256] y))
(Rsh32x16 x y) -> (SRAcond x (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
(Rsh32x8 x y) -> (SRA x (ZeroExt8to32 y))
(Rsh16x32 x y) -> (SRA (SignExt16to32 x) y)
(Rsh16x16 x y) -> (SRA (SignExt16to32 x) (ZeroExt16to32 y))
(Rsh16x32 x y) -> (SRAcond (SignExt16to32 x) y (CMPconst [256] y))
(Rsh16x16 x y) -> (SRAcond (SignExt16to32 x) (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
(Rsh16x8 x y) -> (SRA (SignExt16to32 x) (ZeroExt8to32 y))
(Rsh8x32 x y) -> (SRA (SignExt8to32 x) y)
(Rsh8x16 x y) -> (SRA (SignExt8to32 x) (ZeroExt16to32 y))
(Rsh8x32 x y) -> (SRAcond (SignExt8to32 x) y (CMPconst [256] y))
(Rsh8x16 x y) -> (SRAcond (SignExt8to32 x) (ZeroExt16to32 y) (CMPconst [256] (ZeroExt16to32 y)))
(Rsh8x8 x y) -> (SRA (SignExt8to32 x) (ZeroExt8to32 y))
// constant shifts
@ -177,7 +179,7 @@
(SignExt16to32 x) -> (MOVHreg x)
(Signmask x) -> (SRAconst x [31])
(Zeromask x) -> (LoweredZeromask x)
(Zeromask x) -> (SRAconst (RSBshiftRL <config.fe.TypeInt32()> x x [1]) [31]) // sign bit of uint32(x)>>1 - x
// float <-> int conversion
(Cvt32to32F x) -> (MOVWF x)
@ -452,6 +454,11 @@
(MOVFload [off] {sym} ptr (MOVFstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVDload [off] {sym} ptr (MOVDstore [off2] {sym2} ptr2 x _)) && sym == sym2 && off == off2 && isSamePtr(ptr, ptr2) -> x
(MOVWloadidx ptr idx (MOVWstoreidx ptr2 idx x _)) && isSamePtr(ptr, ptr2) -> x
(MOVWloadshiftLL ptr idx [c] (MOVWstoreshiftLL ptr2 idx [d] x _)) && c==d && isSamePtr(ptr, ptr2) -> x
(MOVWloadshiftRL ptr idx [c] (MOVWstoreshiftRL ptr2 idx [d] x _)) && c==d && isSamePtr(ptr, ptr2) -> x
(MOVWloadshiftRA ptr idx [c] (MOVWstoreshiftRA ptr2 idx [d] x _)) && c==d && isSamePtr(ptr, ptr2) -> x
// fold constant into arithmatic ops
(ADD (MOVWconst [c]) x) -> (ADDconst [c] x)
(ADD x (MOVWconst [c])) -> (ADDconst [c] x)
@ -485,9 +492,6 @@
(CMP x (MOVWconst [c])) -> (CMPconst [c] x)
(CMP (MOVWconst [c]) x) -> (InvertFlags (CMPconst [c] x))
(LoweredZeromask (MOVWconst [0])) -> (MOVWconst [0])
(LoweredZeromask (MOVWconst [c])) && c != 0 -> (MOVWconst [0xffffffff])
// don't extend after proper load
// MOVWreg instruction is not emitted if src and dst registers are same, but it ensures the type.
(MOVBreg x:(MOVBload _ _)) -> (MOVWreg x)
@ -504,6 +508,15 @@
(MOVBreg (ANDconst [c] x)) && c & 0x80 == 0 -> (ANDconst [c&0x7f] x)
(MOVHreg (ANDconst [c] x)) && c & 0x8000 == 0 -> (ANDconst [c&0x7fff] x)
// fold double extensions
(MOVBreg x:(MOVBreg _)) -> (MOVWreg x)
(MOVBUreg x:(MOVBUreg _)) -> (MOVWreg x)
(MOVHreg x:(MOVBreg _)) -> (MOVWreg x)
(MOVHreg x:(MOVBUreg _)) -> (MOVWreg x)
(MOVHreg x:(MOVHreg _)) -> (MOVWreg x)
(MOVHUreg x:(MOVBUreg _)) -> (MOVWreg x)
(MOVHUreg x:(MOVHUreg _)) -> (MOVWreg x)
// don't extend before store
(MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
(MOVBstore [off] {sym} ptr (MOVBUreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
@ -513,25 +526,49 @@
(MOVHstore [off] {sym} ptr (MOVHUreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
// mul by constant
(MUL x (MOVWconst [-1])) -> (RSBconst [0] x)
(MUL x (MOVWconst [c])) && int32(c) == -1 -> (RSBconst [0] x)
(MUL _ (MOVWconst [0])) -> (MOVWconst [0])
(MUL x (MOVWconst [1])) -> x
(MUL x (MOVWconst [c])) && isPowerOfTwo(c) -> (SLLconst [log2(c)] x)
(MUL x (MOVWconst [c])) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADDshiftLL x x [log2(c-1)])
(MUL x (MOVWconst [c])) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (RSBshiftLL x x [log2(c+1)])
(MUL x (MOVWconst [c])) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
(MUL x (MOVWconst [c])) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
(MUL x (MOVWconst [c])) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (SLLconst [log2(c/7)] (RSBshiftLL <x.Type> x x [3]))
(MUL x (MOVWconst [c])) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
(MUL (MOVWconst [-1]) x) -> (RSBconst [0] x)
(MUL (MOVWconst [c]) x) && int32(c) == -1 -> (RSBconst [0] x)
(MUL (MOVWconst [0]) _) -> (MOVWconst [0])
(MUL (MOVWconst [1]) x) -> x
(MUL (MOVWconst [c]) x) && isPowerOfTwo(c) -> (SLLconst [log2(c)] x)
(MUL (MOVWconst [c]) x) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADDshiftLL x x [log2(c-1)])
(MUL (MOVWconst [c]) x) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (RSBshiftLL x x [log2(c+1)])
(MUL (MOVWconst [c]) x) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (SLLconst [log2(c/3)] (ADDshiftLL <x.Type> x x [1]))
(MUL (MOVWconst [c]) x) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (SLLconst [log2(c/5)] (ADDshiftLL <x.Type> x x [2]))
(MUL (MOVWconst [c]) x) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (SLLconst [log2(c/7)] (RSBshiftLL <x.Type> x x [3]))
(MUL (MOVWconst [c]) x) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (SLLconst [log2(c/9)] (ADDshiftLL <x.Type> x x [3]))
(MULA x (MOVWconst [-1]) a) -> (SUB a x)
(MULA x (MOVWconst [c]) a) && int32(c) == -1 -> (SUB a x)
(MULA _ (MOVWconst [0]) a) -> a
(MULA x (MOVWconst [1]) a) -> (ADD x a)
(MULA x (MOVWconst [c]) a) && isPowerOfTwo(c) -> (ADD (SLLconst <x.Type> [log2(c)] x) a)
(MULA x (MOVWconst [c]) a) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADD (ADDshiftLL <x.Type> x x [log2(c-1)]) a)
(MULA x (MOVWconst [c]) a) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (ADD (RSBshiftLL <x.Type> x x [log2(c+1)]) a)
(MULA x (MOVWconst [c]) a) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/3)] (ADDshiftLL <x.Type> x x [1])) a)
(MULA x (MOVWconst [c]) a) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])) a)
(MULA x (MOVWconst [c]) a) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/7)] (RSBshiftLL <x.Type> x x [3])) a)
(MULA x (MOVWconst [c]) a) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])) a)
(MULA (MOVWconst [-1]) x a) -> (SUB a x)
(MULA (MOVWconst [c]) x a) && int32(c) == -1 -> (SUB a x)
(MULA (MOVWconst [0]) _ a) -> a
(MULA (MOVWconst [1]) x a) -> (ADD x a)
(MULA (MOVWconst [c]) x a) && isPowerOfTwo(c) -> (ADD (SLLconst <x.Type> [log2(c)] x) a)
(MULA (MOVWconst [c]) x a) && isPowerOfTwo(c-1) && int32(c) >= 3 -> (ADD (ADDshiftLL <x.Type> x x [log2(c-1)]) a)
(MULA (MOVWconst [c]) x a) && isPowerOfTwo(c+1) && int32(c) >= 7 -> (ADD (RSBshiftLL <x.Type> x x [log2(c+1)]) a)
(MULA (MOVWconst [c]) x a) && c%3 == 0 && isPowerOfTwo(c/3) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/3)] (ADDshiftLL <x.Type> x x [1])) a)
(MULA (MOVWconst [c]) x a) && c%5 == 0 && isPowerOfTwo(c/5) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/5)] (ADDshiftLL <x.Type> x x [2])) a)
(MULA (MOVWconst [c]) x a) && c%7 == 0 && isPowerOfTwo(c/7) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/7)] (RSBshiftLL <x.Type> x x [3])) a)
(MULA (MOVWconst [c]) x a) && c%9 == 0 && isPowerOfTwo(c/9) && is32Bit(c) -> (ADD (SLLconst <x.Type> [log2(c/9)] (ADDshiftLL <x.Type> x x [3])) a)
// div by constant
(DIVU x (MOVWconst [1])) -> x
@ -696,6 +733,28 @@
(GreaterEqual (InvertFlags x)) -> (LessEqual x)
(GreaterEqualU (InvertFlags x)) -> (LessEqualU x)
// absorb flag constants into conditional instructions
(CMOVWLSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
(CMOVWLSconst _ (FlagLT_ULT) [c]) -> (MOVWconst [c])
(CMOVWLSconst x (FlagLT_UGT)) -> x
(CMOVWLSconst _ (FlagGT_ULT) [c]) -> (MOVWconst [c])
(CMOVWLSconst x (FlagGT_UGT)) -> x
(CMOVWHSconst _ (FlagEQ) [c]) -> (MOVWconst [c])
(CMOVWHSconst x (FlagLT_ULT)) -> x
(CMOVWHSconst _ (FlagLT_UGT) [c]) -> (MOVWconst [c])
(CMOVWHSconst x (FlagGT_ULT)) -> x
(CMOVWHSconst _ (FlagGT_UGT) [c]) -> (MOVWconst [c])
(CMOVWLSconst x (InvertFlags flags) [c]) -> (CMOVWHSconst x flags [c])
(CMOVWHSconst x (InvertFlags flags) [c]) -> (CMOVWLSconst x flags [c])
(SRAcond x _ (FlagEQ)) -> (SRAconst x [31])
(SRAcond x y (FlagLT_ULT)) -> (SRA x y)
(SRAcond x _ (FlagLT_UGT)) -> (SRAconst x [31])
(SRAcond x y (FlagGT_ULT)) -> (SRA x y)
(SRAcond x _ (FlagGT_UGT)) -> (SRAconst x [31])
// remove redundant *const ops
(ADDconst [0] x) -> x
(SUBconst [0] x) -> x
@ -741,10 +800,377 @@
(XORconst [c] (XORconst [d] x)) -> (XORconst [c^d] x)
(BICconst [c] (MOVWconst [d])) -> (MOVWconst [d&^c])
(MVN (MOVWconst [c])) -> (MOVWconst [^c])
(MOVBreg (MOVWconst [c])) -> (MOVWconst [int64(int8(c))])
(MOVBUreg (MOVWconst [c])) -> (MOVWconst [int64(uint8(c))])
(MOVHreg (MOVWconst [c])) -> (MOVWconst [int64(int16(c))])
(MOVHUreg (MOVWconst [c])) -> (MOVWconst [int64(uint16(c))])
(MOVWreg (MOVWconst [c])) -> (MOVWconst [c])
// absorb shifts into ops
(ADD x (SLLconst [c] y)) -> (ADDshiftLL x y [c])
(ADD (SLLconst [c] y) x) -> (ADDshiftLL x y [c])
(ADD x (SRLconst [c] y)) -> (ADDshiftRL x y [c])
(ADD (SRLconst [c] y) x) -> (ADDshiftRL x y [c])
(ADD x (SRAconst [c] y)) -> (ADDshiftRA x y [c])
(ADD (SRAconst [c] y) x) -> (ADDshiftRA x y [c])
(ADD x (SLL y z)) -> (ADDshiftLLreg x y z)
(ADD (SLL y z) x) -> (ADDshiftLLreg x y z)
(ADD x (SRL y z)) -> (ADDshiftRLreg x y z)
(ADD (SRL y z) x) -> (ADDshiftRLreg x y z)
(ADD x (SRA y z)) -> (ADDshiftRAreg x y z)
(ADD (SRA y z) x) -> (ADDshiftRAreg x y z)
(ADC x (SLLconst [c] y) flags) -> (ADCshiftLL x y [c] flags)
(ADC (SLLconst [c] y) x flags) -> (ADCshiftLL x y [c] flags)
(ADC x (SRLconst [c] y) flags) -> (ADCshiftRL x y [c] flags)
(ADC (SRLconst [c] y) x flags) -> (ADCshiftRL x y [c] flags)
(ADC x (SRAconst [c] y) flags) -> (ADCshiftRA x y [c] flags)
(ADC (SRAconst [c] y) x flags) -> (ADCshiftRA x y [c] flags)
(ADC x (SLL y z) flags) -> (ADCshiftLLreg x y z flags)
(ADC (SLL y z) x flags) -> (ADCshiftLLreg x y z flags)
(ADC x (SRL y z) flags) -> (ADCshiftRLreg x y z flags)
(ADC (SRL y z) x flags) -> (ADCshiftRLreg x y z flags)
(ADC x (SRA y z) flags) -> (ADCshiftRAreg x y z flags)
(ADC (SRA y z) x flags) -> (ADCshiftRAreg x y z flags)
(ADDS x (SLLconst [c] y)) -> (ADDSshiftLL x y [c])
(ADDS (SLLconst [c] y) x) -> (ADDSshiftLL x y [c])
(ADDS x (SRLconst [c] y)) -> (ADDSshiftRL x y [c])
(ADDS (SRLconst [c] y) x) -> (ADDSshiftRL x y [c])
(ADDS x (SRAconst [c] y)) -> (ADDSshiftRA x y [c])
(ADDS (SRAconst [c] y) x) -> (ADDSshiftRA x y [c])
(ADDS x (SLL y z)) -> (ADDSshiftLLreg x y z)
(ADDS (SLL y z) x) -> (ADDSshiftLLreg x y z)
(ADDS x (SRL y z)) -> (ADDSshiftRLreg x y z)
(ADDS (SRL y z) x) -> (ADDSshiftRLreg x y z)
(ADDS x (SRA y z)) -> (ADDSshiftRAreg x y z)
(ADDS (SRA y z) x) -> (ADDSshiftRAreg x y z)
(SUB x (SLLconst [c] y)) -> (SUBshiftLL x y [c])
(SUB (SLLconst [c] y) x) -> (RSBshiftLL x y [c])
(SUB x (SRLconst [c] y)) -> (SUBshiftRL x y [c])
(SUB (SRLconst [c] y) x) -> (RSBshiftRL x y [c])
(SUB x (SRAconst [c] y)) -> (SUBshiftRA x y [c])
(SUB (SRAconst [c] y) x) -> (RSBshiftRA x y [c])
(SUB x (SLL y z)) -> (SUBshiftLLreg x y z)
(SUB (SLL y z) x) -> (RSBshiftLLreg x y z)
(SUB x (SRL y z)) -> (SUBshiftRLreg x y z)
(SUB (SRL y z) x) -> (RSBshiftRLreg x y z)
(SUB x (SRA y z)) -> (SUBshiftRAreg x y z)
(SUB (SRA y z) x) -> (RSBshiftRAreg x y z)
(SBC x (SLLconst [c] y) flags) -> (SBCshiftLL x y [c] flags)
(SBC (SLLconst [c] y) x flags) -> (RSCshiftLL x y [c] flags)
(SBC x (SRLconst [c] y) flags) -> (SBCshiftRL x y [c] flags)
(SBC (SRLconst [c] y) x flags) -> (RSCshiftRL x y [c] flags)
(SBC x (SRAconst [c] y) flags) -> (SBCshiftRA x y [c] flags)
(SBC (SRAconst [c] y) x flags) -> (RSCshiftRA x y [c] flags)
(SBC x (SLL y z) flags) -> (SBCshiftLLreg x y z flags)
(SBC (SLL y z) x flags) -> (RSCshiftLLreg x y z flags)
(SBC x (SRL y z) flags) -> (SBCshiftRLreg x y z flags)
(SBC (SRL y z) x flags) -> (RSCshiftRLreg x y z flags)
(SBC x (SRA y z) flags) -> (SBCshiftRAreg x y z flags)
(SBC (SRA y z) x flags) -> (RSCshiftRAreg x y z flags)
(SUBS x (SLLconst [c] y)) -> (SUBSshiftLL x y [c])
(SUBS (SLLconst [c] y) x) -> (RSBSshiftLL x y [c])
(SUBS x (SRLconst [c] y)) -> (SUBSshiftRL x y [c])
(SUBS (SRLconst [c] y) x) -> (RSBSshiftRL x y [c])
(SUBS x (SRAconst [c] y)) -> (SUBSshiftRA x y [c])
(SUBS (SRAconst [c] y) x) -> (RSBSshiftRA x y [c])
(SUBS x (SLL y z)) -> (SUBSshiftLLreg x y z)
(SUBS (SLL y z) x) -> (RSBSshiftLLreg x y z)
(SUBS x (SRL y z)) -> (SUBSshiftRLreg x y z)
(SUBS (SRL y z) x) -> (RSBSshiftRLreg x y z)
(SUBS x (SRA y z)) -> (SUBSshiftRAreg x y z)
(SUBS (SRA y z) x) -> (RSBSshiftRAreg x y z)
(RSB x (SLLconst [c] y)) -> (RSBshiftLL x y [c])
(RSB (SLLconst [c] y) x) -> (SUBshiftLL x y [c])
(RSB x (SRLconst [c] y)) -> (RSBshiftRL x y [c])
(RSB (SRLconst [c] y) x) -> (SUBshiftRL x y [c])
(RSB x (SRAconst [c] y)) -> (RSBshiftRA x y [c])
(RSB (SRAconst [c] y) x) -> (SUBshiftRA x y [c])
(RSB x (SLL y z)) -> (RSBshiftLLreg x y z)
(RSB (SLL y z) x) -> (SUBshiftLLreg x y z)
(RSB x (SRL y z)) -> (RSBshiftRLreg x y z)
(RSB (SRL y z) x) -> (SUBshiftRLreg x y z)
(RSB x (SRA y z)) -> (RSBshiftRAreg x y z)
(RSB (SRA y z) x) -> (SUBshiftRAreg x y z)
(AND x (SLLconst [c] y)) -> (ANDshiftLL x y [c])
(AND (SLLconst [c] y) x) -> (ANDshiftLL x y [c])
(AND x (SRLconst [c] y)) -> (ANDshiftRL x y [c])
(AND (SRLconst [c] y) x) -> (ANDshiftRL x y [c])
(AND x (SRAconst [c] y)) -> (ANDshiftRA x y [c])
(AND (SRAconst [c] y) x) -> (ANDshiftRA x y [c])
(AND x (SLL y z)) -> (ANDshiftLLreg x y z)
(AND (SLL y z) x) -> (ANDshiftLLreg x y z)
(AND x (SRL y z)) -> (ANDshiftRLreg x y z)
(AND (SRL y z) x) -> (ANDshiftRLreg x y z)
(AND x (SRA y z)) -> (ANDshiftRAreg x y z)
(AND (SRA y z) x) -> (ANDshiftRAreg x y z)
(OR x (SLLconst [c] y)) -> (ORshiftLL x y [c])
(OR (SLLconst [c] y) x) -> (ORshiftLL x y [c])
(OR x (SRLconst [c] y)) -> (ORshiftRL x y [c])
(OR (SRLconst [c] y) x) -> (ORshiftRL x y [c])
(OR x (SRAconst [c] y)) -> (ORshiftRA x y [c])
(OR (SRAconst [c] y) x) -> (ORshiftRA x y [c])
(OR x (SLL y z)) -> (ORshiftLLreg x y z)
(OR (SLL y z) x) -> (ORshiftLLreg x y z)
(OR x (SRL y z)) -> (ORshiftRLreg x y z)
(OR (SRL y z) x) -> (ORshiftRLreg x y z)
(OR x (SRA y z)) -> (ORshiftRAreg x y z)
(OR (SRA y z) x) -> (ORshiftRAreg x y z)
(XOR x (SLLconst [c] y)) -> (XORshiftLL x y [c])
(XOR (SLLconst [c] y) x) -> (XORshiftLL x y [c])
(XOR x (SRLconst [c] y)) -> (XORshiftRL x y [c])
(XOR (SRLconst [c] y) x) -> (XORshiftRL x y [c])
(XOR x (SRAconst [c] y)) -> (XORshiftRA x y [c])
(XOR (SRAconst [c] y) x) -> (XORshiftRA x y [c])
(XOR x (SLL y z)) -> (XORshiftLLreg x y z)
(XOR (SLL y z) x) -> (XORshiftLLreg x y z)
(XOR x (SRL y z)) -> (XORshiftRLreg x y z)
(XOR (SRL y z) x) -> (XORshiftRLreg x y z)
(XOR x (SRA y z)) -> (XORshiftRAreg x y z)
(XOR (SRA y z) x) -> (XORshiftRAreg x y z)
(BIC x (SLLconst [c] y)) -> (BICshiftLL x y [c])
(BIC x (SRLconst [c] y)) -> (BICshiftRL x y [c])
(BIC x (SRAconst [c] y)) -> (BICshiftRA x y [c])
(BIC x (SLL y z)) -> (BICshiftLLreg x y z)
(BIC x (SRL y z)) -> (BICshiftRLreg x y z)
(BIC x (SRA y z)) -> (BICshiftRAreg x y z)
(MVN (SLLconst [c] x)) -> (MVNshiftLL x [c])
(MVN (SRLconst [c] x)) -> (MVNshiftRL x [c])
(MVN (SRAconst [c] x)) -> (MVNshiftRA x [c])
(MVN (SLL x y)) -> (MVNshiftLLreg x y)
(MVN (SRL x y)) -> (MVNshiftRLreg x y)
(MVN (SRA x y)) -> (MVNshiftRAreg x y)
(CMP x (SLLconst [c] y)) -> (CMPshiftLL x y [c])
(CMP (SLLconst [c] y) x) -> (InvertFlags (CMPshiftLL x y [c]))
(CMP x (SRLconst [c] y)) -> (CMPshiftRL x y [c])
(CMP (SRLconst [c] y) x) -> (InvertFlags (CMPshiftRL x y [c]))
(CMP x (SRAconst [c] y)) -> (CMPshiftRA x y [c])
(CMP (SRAconst [c] y) x) -> (InvertFlags (CMPshiftRA x y [c]))
(CMP x (SLL y z)) -> (CMPshiftLLreg x y z)
(CMP (SLL y z) x) -> (InvertFlags (CMPshiftLLreg x y z))
(CMP x (SRL y z)) -> (CMPshiftRLreg x y z)
(CMP (SRL y z) x) -> (InvertFlags (CMPshiftRLreg x y z))
(CMP x (SRA y z)) -> (CMPshiftRAreg x y z)
(CMP (SRA y z) x) -> (InvertFlags (CMPshiftRAreg x y z))
// prefer *const ops to *shift ops
(ADDshiftLL (MOVWconst [c]) x [d]) -> (ADDconst [c] (SLLconst <x.Type> x [d]))
(ADDshiftRL (MOVWconst [c]) x [d]) -> (ADDconst [c] (SRLconst <x.Type> x [d]))
(ADDshiftRA (MOVWconst [c]) x [d]) -> (ADDconst [c] (SRAconst <x.Type> x [d]))
(ADCshiftLL (MOVWconst [c]) x [d] flags) -> (ADCconst [c] (SLLconst <x.Type> x [d]) flags)
(ADCshiftRL (MOVWconst [c]) x [d] flags) -> (ADCconst [c] (SRLconst <x.Type> x [d]) flags)
(ADCshiftRA (MOVWconst [c]) x [d] flags) -> (ADCconst [c] (SRAconst <x.Type> x [d]) flags)
(ADDSshiftLL (MOVWconst [c]) x [d]) -> (ADDSconst [c] (SLLconst <x.Type> x [d]))
(ADDSshiftRL (MOVWconst [c]) x [d]) -> (ADDSconst [c] (SRLconst <x.Type> x [d]))
(ADDSshiftRA (MOVWconst [c]) x [d]) -> (ADDSconst [c] (SRAconst <x.Type> x [d]))
(SUBshiftLL (MOVWconst [c]) x [d]) -> (RSBconst [c] (SLLconst <x.Type> x [d]))
(SUBshiftRL (MOVWconst [c]) x [d]) -> (RSBconst [c] (SRLconst <x.Type> x [d]))
(SUBshiftRA (MOVWconst [c]) x [d]) -> (RSBconst [c] (SRAconst <x.Type> x [d]))
(SBCshiftLL (MOVWconst [c]) x [d] flags) -> (RSCconst [c] (SLLconst <x.Type> x [d]) flags)
(SBCshiftRL (MOVWconst [c]) x [d] flags) -> (RSCconst [c] (SRLconst <x.Type> x [d]) flags)
(SBCshiftRA (MOVWconst [c]) x [d] flags) -> (RSCconst [c] (SRAconst <x.Type> x [d]) flags)
(SUBSshiftLL (MOVWconst [c]) x [d]) -> (RSBSconst [c] (SLLconst <x.Type> x [d]))
(SUBSshiftRL (MOVWconst [c]) x [d]) -> (RSBSconst [c] (SRLconst <x.Type> x [d]))
(SUBSshiftRA (MOVWconst [c]) x [d]) -> (RSBSconst [c] (SRAconst <x.Type> x [d]))
(RSBshiftLL (MOVWconst [c]) x [d]) -> (SUBconst [c] (SLLconst <x.Type> x [d]))
(RSBshiftRL (MOVWconst [c]) x [d]) -> (SUBconst [c] (SRLconst <x.Type> x [d]))
(RSBshiftRA (MOVWconst [c]) x [d]) -> (SUBconst [c] (SRAconst <x.Type> x [d]))
(RSCshiftLL (MOVWconst [c]) x [d] flags) -> (SBCconst [c] (SLLconst <x.Type> x [d]) flags)
(RSCshiftRL (MOVWconst [c]) x [d] flags) -> (SBCconst [c] (SRLconst <x.Type> x [d]) flags)
(RSCshiftRA (MOVWconst [c]) x [d] flags) -> (SBCconst [c] (SRAconst <x.Type> x [d]) flags)
(RSBSshiftLL (MOVWconst [c]) x [d]) -> (SUBSconst [c] (SLLconst <x.Type> x [d]))
(RSBSshiftRL (MOVWconst [c]) x [d]) -> (SUBSconst [c] (SRLconst <x.Type> x [d]))
(RSBSshiftRA (MOVWconst [c]) x [d]) -> (SUBSconst [c] (SRAconst <x.Type> x [d]))
(ANDshiftLL (MOVWconst [c]) x [d]) -> (ANDconst [c] (SLLconst <x.Type> x [d]))
(ANDshiftRL (MOVWconst [c]) x [d]) -> (ANDconst [c] (SRLconst <x.Type> x [d]))
(ANDshiftRA (MOVWconst [c]) x [d]) -> (ANDconst [c] (SRAconst <x.Type> x [d]))
(ORshiftLL (MOVWconst [c]) x [d]) -> (ORconst [c] (SLLconst <x.Type> x [d]))
(ORshiftRL (MOVWconst [c]) x [d]) -> (ORconst [c] (SRLconst <x.Type> x [d]))
(ORshiftRA (MOVWconst [c]) x [d]) -> (ORconst [c] (SRAconst <x.Type> x [d]))
(XORshiftLL (MOVWconst [c]) x [d]) -> (XORconst [c] (SLLconst <x.Type> x [d]))
(XORshiftRL (MOVWconst [c]) x [d]) -> (XORconst [c] (SRLconst <x.Type> x [d]))
(XORshiftRA (MOVWconst [c]) x [d]) -> (XORconst [c] (SRAconst <x.Type> x [d]))
(CMPshiftLL (MOVWconst [c]) x [d]) -> (InvertFlags (CMPconst [c] (SLLconst <x.Type> x [d])))
(CMPshiftRL (MOVWconst [c]) x [d]) -> (InvertFlags (CMPconst [c] (SRLconst <x.Type> x [d])))
(CMPshiftRA (MOVWconst [c]) x [d]) -> (InvertFlags (CMPconst [c] (SRAconst <x.Type> x [d])))
(ADDshiftLLreg (MOVWconst [c]) x y) -> (ADDconst [c] (SLL <x.Type> x y))
(ADDshiftRLreg (MOVWconst [c]) x y) -> (ADDconst [c] (SRL <x.Type> x y))
(ADDshiftRAreg (MOVWconst [c]) x y) -> (ADDconst [c] (SRA <x.Type> x y))
(ADCshiftLLreg (MOVWconst [c]) x y flags) -> (ADCconst [c] (SLL <x.Type> x y) flags)
(ADCshiftRLreg (MOVWconst [c]) x y flags) -> (ADCconst [c] (SRL <x.Type> x y) flags)
(ADCshiftRAreg (MOVWconst [c]) x y flags) -> (ADCconst [c] (SRA <x.Type> x y) flags)
(ADDSshiftLLreg (MOVWconst [c]) x y) -> (ADDSconst [c] (SLL <x.Type> x y))
(ADDSshiftRLreg (MOVWconst [c]) x y) -> (ADDSconst [c] (SRL <x.Type> x y))
(ADDSshiftRAreg (MOVWconst [c]) x y) -> (ADDSconst [c] (SRA <x.Type> x y))
(SUBshiftLLreg (MOVWconst [c]) x y) -> (RSBconst [c] (SLL <x.Type> x y))
(SUBshiftRLreg (MOVWconst [c]) x y) -> (RSBconst [c] (SRL <x.Type> x y))
(SUBshiftRAreg (MOVWconst [c]) x y) -> (RSBconst [c] (SRA <x.Type> x y))
(SBCshiftLLreg (MOVWconst [c]) x y flags) -> (RSCconst [c] (SLL <x.Type> x y) flags)
(SBCshiftRLreg (MOVWconst [c]) x y flags) -> (RSCconst [c] (SRL <x.Type> x y) flags)
(SBCshiftRAreg (MOVWconst [c]) x y flags) -> (RSCconst [c] (SRA <x.Type> x y) flags)
(SUBSshiftLLreg (MOVWconst [c]) x y) -> (RSBSconst [c] (SLL <x.Type> x y))
(SUBSshiftRLreg (MOVWconst [c]) x y) -> (RSBSconst [c] (SRL <x.Type> x y))
(SUBSshiftRAreg (MOVWconst [c]) x y) -> (RSBSconst [c] (SRA <x.Type> x y))
(RSBshiftLLreg (MOVWconst [c]) x y) -> (SUBconst [c] (SLL <x.Type> x y))
(RSBshiftRLreg (MOVWconst [c]) x y) -> (SUBconst [c] (SRL <x.Type> x y))
(RSBshiftRAreg (MOVWconst [c]) x y) -> (SUBconst [c] (SRA <x.Type> x y))
(RSCshiftLLreg (MOVWconst [c]) x y flags) -> (SBCconst [c] (SLL <x.Type> x y) flags)
(RSCshiftRLreg (MOVWconst [c]) x y flags) -> (SBCconst [c] (SRL <x.Type> x y) flags)
(RSCshiftRAreg (MOVWconst [c]) x y flags) -> (SBCconst [c] (SRA <x.Type> x y) flags)
(RSBSshiftLLreg (MOVWconst [c]) x y) -> (SUBSconst [c] (SLL <x.Type> x y))
(RSBSshiftRLreg (MOVWconst [c]) x y) -> (SUBSconst [c] (SRL <x.Type> x y))
(RSBSshiftRAreg (MOVWconst [c]) x y) -> (SUBSconst [c] (SRA <x.Type> x y))
(ANDshiftLLreg (MOVWconst [c]) x y) -> (ANDconst [c] (SLL <x.Type> x y))
(ANDshiftRLreg (MOVWconst [c]) x y) -> (ANDconst [c] (SRL <x.Type> x y))
(ANDshiftRAreg (MOVWconst [c]) x y) -> (ANDconst [c] (SRA <x.Type> x y))
(ORshiftLLreg (MOVWconst [c]) x y) -> (ORconst [c] (SLL <x.Type> x y))
(ORshiftRLreg (MOVWconst [c]) x y) -> (ORconst [c] (SRL <x.Type> x y))
(ORshiftRAreg (MOVWconst [c]) x y) -> (ORconst [c] (SRA <x.Type> x y))
(XORshiftLLreg (MOVWconst [c]) x y) -> (XORconst [c] (SLL <x.Type> x y))
(XORshiftRLreg (MOVWconst [c]) x y) -> (XORconst [c] (SRL <x.Type> x y))
(XORshiftRAreg (MOVWconst [c]) x y) -> (XORconst [c] (SRA <x.Type> x y))
(CMPshiftLLreg (MOVWconst [c]) x y) -> (InvertFlags (CMPconst [c] (SLL <x.Type> x y)))
(CMPshiftRLreg (MOVWconst [c]) x y) -> (InvertFlags (CMPconst [c] (SRL <x.Type> x y)))
(CMPshiftRAreg (MOVWconst [c]) x y) -> (InvertFlags (CMPconst [c] (SRA <x.Type> x y)))
// constant folding in *shift ops
(ADDshiftLL x (MOVWconst [c]) [d]) -> (ADDconst x [int64(uint32(c)<<uint64(d))])
(ADDshiftRL x (MOVWconst [c]) [d]) -> (ADDconst x [int64(uint32(c)>>uint64(d))])
(ADDshiftRA x (MOVWconst [c]) [d]) -> (ADDconst x [int64(int32(c)>>uint64(d))])
(ADCshiftLL x (MOVWconst [c]) [d] flags) -> (ADCconst x [int64(uint32(c)<<uint64(d))] flags)
(ADCshiftRL x (MOVWconst [c]) [d] flags) -> (ADCconst x [int64(uint32(c)>>uint64(d))] flags)
(ADCshiftRA x (MOVWconst [c]) [d] flags) -> (ADCconst x [int64(int32(c)>>uint64(d))] flags)
(ADDSshiftLL x (MOVWconst [c]) [d]) -> (ADDSconst x [int64(uint32(c)<<uint64(d))])
(ADDSshiftRL x (MOVWconst [c]) [d]) -> (ADDSconst x [int64(uint32(c)>>uint64(d))])
(ADDSshiftRA x (MOVWconst [c]) [d]) -> (ADDSconst x [int64(int32(c)>>uint64(d))])
(SUBshiftLL x (MOVWconst [c]) [d]) -> (SUBconst x [int64(uint32(c)<<uint64(d))])
(SUBshiftRL x (MOVWconst [c]) [d]) -> (SUBconst x [int64(uint32(c)>>uint64(d))])
(SUBshiftRA x (MOVWconst [c]) [d]) -> (SUBconst x [int64(int32(c)>>uint64(d))])
(SBCshiftLL x (MOVWconst [c]) [d] flags) -> (SBCconst x [int64(uint32(c)<<uint64(d))] flags)
(SBCshiftRL x (MOVWconst [c]) [d] flags) -> (SBCconst x [int64(uint32(c)>>uint64(d))] flags)
(SBCshiftRA x (MOVWconst [c]) [d] flags) -> (SBCconst x [int64(int32(c)>>uint64(d))] flags)
(SUBSshiftLL x (MOVWconst [c]) [d]) -> (SUBSconst x [int64(uint32(c)<<uint64(d))])
(SUBSshiftRL x (MOVWconst [c]) [d]) -> (SUBSconst x [int64(uint32(c)>>uint64(d))])
(SUBSshiftRA x (MOVWconst [c]) [d]) -> (SUBSconst x [int64(int32(c)>>uint64(d))])
(RSBshiftLL x (MOVWconst [c]) [d]) -> (RSBconst x [int64(uint32(c)<<uint64(d))])
(RSBshiftRL x (MOVWconst [c]) [d]) -> (RSBconst x [int64(uint32(c)>>uint64(d))])
(RSBshiftRA x (MOVWconst [c]) [d]) -> (RSBconst x [int64(int32(c)>>uint64(d))])
(RSCshiftLL x (MOVWconst [c]) [d] flags) -> (RSCconst x [int64(uint32(c)<<uint64(d))] flags)
(RSCshiftRL x (MOVWconst [c]) [d] flags) -> (RSCconst x [int64(uint32(c)>>uint64(d))] flags)
(RSCshiftRA x (MOVWconst [c]) [d] flags) -> (RSCconst x [int64(int32(c)>>uint64(d))] flags)
(RSBSshiftLL x (MOVWconst [c]) [d]) -> (RSBSconst x [int64(uint32(c)<<uint64(d))])
(RSBSshiftRL x (MOVWconst [c]) [d]) -> (RSBSconst x [int64(uint32(c)>>uint64(d))])
(RSBSshiftRA x (MOVWconst [c]) [d]) -> (RSBSconst x [int64(int32(c)>>uint64(d))])
(ANDshiftLL x (MOVWconst [c]) [d]) -> (ANDconst x [int64(uint32(c)<<uint64(d))])
(ANDshiftRL x (MOVWconst [c]) [d]) -> (ANDconst x [int64(uint32(c)>>uint64(d))])
(ANDshiftRA x (MOVWconst [c]) [d]) -> (ANDconst x [int64(int32(c)>>uint64(d))])
(ORshiftLL x (MOVWconst [c]) [d]) -> (ORconst x [int64(uint32(c)<<uint64(d))])
(ORshiftRL x (MOVWconst [c]) [d]) -> (ORconst x [int64(uint32(c)>>uint64(d))])
(ORshiftRA x (MOVWconst [c]) [d]) -> (ORconst x [int64(int32(c)>>uint64(d))])
(XORshiftLL x (MOVWconst [c]) [d]) -> (XORconst x [int64(uint32(c)<<uint64(d))])
(XORshiftRL x (MOVWconst [c]) [d]) -> (XORconst x [int64(uint32(c)>>uint64(d))])
(XORshiftRA x (MOVWconst [c]) [d]) -> (XORconst x [int64(int32(c)>>uint64(d))])
(BICshiftLL x (MOVWconst [c]) [d]) -> (BICconst x [int64(uint32(c)<<uint64(d))])
(BICshiftRL x (MOVWconst [c]) [d]) -> (BICconst x [int64(uint32(c)>>uint64(d))])
(BICshiftRA x (MOVWconst [c]) [d]) -> (BICconst x [int64(int32(c)>>uint64(d))])
(MVNshiftLL (MOVWconst [c]) [d]) -> (MOVWconst [^int64(uint32(c)<<uint64(d))])
(MVNshiftRL (MOVWconst [c]) [d]) -> (MOVWconst [^int64(uint32(c)>>uint64(d))])
(MVNshiftRA (MOVWconst [c]) [d]) -> (MOVWconst [^int64(int32(c)>>uint64(d))])
(CMPshiftLL x (MOVWconst [c]) [d]) -> (CMPconst x [int64(uint32(c)<<uint64(d))])
(CMPshiftRL x (MOVWconst [c]) [d]) -> (CMPconst x [int64(uint32(c)>>uint64(d))])
(CMPshiftRA x (MOVWconst [c]) [d]) -> (CMPconst x [int64(int32(c)>>uint64(d))])
(ADDshiftLLreg x y (MOVWconst [c])) -> (ADDshiftLL x y [c])
(ADDshiftRLreg x y (MOVWconst [c])) -> (ADDshiftRL x y [c])
(ADDshiftRAreg x y (MOVWconst [c])) -> (ADDshiftRA x y [c])
(ADCshiftLLreg x y (MOVWconst [c]) flags) -> (ADCshiftLL x y [c] flags)
(ADCshiftRLreg x y (MOVWconst [c]) flags) -> (ADCshiftRL x y [c] flags)
(ADCshiftRAreg x y (MOVWconst [c]) flags) -> (ADCshiftRA x y [c] flags)
(ADDSshiftLLreg x y (MOVWconst [c])) -> (ADDSshiftLL x y [c])
(ADDSshiftRLreg x y (MOVWconst [c])) -> (ADDSshiftRL x y [c])
(ADDSshiftRAreg x y (MOVWconst [c])) -> (ADDSshiftRA x y [c])
(SUBshiftLLreg x y (MOVWconst [c])) -> (SUBshiftLL x y [c])
(SUBshiftRLreg x y (MOVWconst [c])) -> (SUBshiftRL x y [c])
(SUBshiftRAreg x y (MOVWconst [c])) -> (SUBshiftRA x y [c])
(SBCshiftLLreg x y (MOVWconst [c]) flags) -> (SBCshiftLL x y [c] flags)
(SBCshiftRLreg x y (MOVWconst [c]) flags) -> (SBCshiftRL x y [c] flags)
(SBCshiftRAreg x y (MOVWconst [c]) flags) -> (SBCshiftRA x y [c] flags)
(SUBSshiftLLreg x y (MOVWconst [c])) -> (SUBSshiftLL x y [c])
(SUBSshiftRLreg x y (MOVWconst [c])) -> (SUBSshiftRL x y [c])
(SUBSshiftRAreg x y (MOVWconst [c])) -> (SUBSshiftRA x y [c])
(RSBshiftLLreg x y (MOVWconst [c])) -> (RSBshiftLL x y [c])
(RSBshiftRLreg x y (MOVWconst [c])) -> (RSBshiftRL x y [c])
(RSBshiftRAreg x y (MOVWconst [c])) -> (RSBshiftRA x y [c])
(RSCshiftLLreg x y (MOVWconst [c]) flags) -> (RSCshiftLL x y [c] flags)
(RSCshiftRLreg x y (MOVWconst [c]) flags) -> (RSCshiftRL x y [c] flags)
(RSCshiftRAreg x y (MOVWconst [c]) flags) -> (RSCshiftRA x y [c] flags)
(RSBSshiftLLreg x y (MOVWconst [c])) -> (RSBSshiftLL x y [c])
(RSBSshiftRLreg x y (MOVWconst [c])) -> (RSBSshiftRL x y [c])
(RSBSshiftRAreg x y (MOVWconst [c])) -> (RSBSshiftRA x y [c])
(ANDshiftLLreg x y (MOVWconst [c])) -> (ANDshiftLL x y [c])
(ANDshiftRLreg x y (MOVWconst [c])) -> (ANDshiftRL x y [c])
(ANDshiftRAreg x y (MOVWconst [c])) -> (ANDshiftRA x y [c])
(ORshiftLLreg x y (MOVWconst [c])) -> (ORshiftLL x y [c])
(ORshiftRLreg x y (MOVWconst [c])) -> (ORshiftRL x y [c])
(ORshiftRAreg x y (MOVWconst [c])) -> (ORshiftRA x y [c])
(XORshiftLLreg x y (MOVWconst [c])) -> (XORshiftLL x y [c])
(XORshiftRLreg x y (MOVWconst [c])) -> (XORshiftRL x y [c])
(XORshiftRAreg x y (MOVWconst [c])) -> (XORshiftRA x y [c])
(BICshiftLLreg x y (MOVWconst [c])) -> (BICshiftLL x y [c])
(BICshiftRLreg x y (MOVWconst [c])) -> (BICshiftRL x y [c])
(BICshiftRAreg x y (MOVWconst [c])) -> (BICshiftRA x y [c])
(MVNshiftLLreg x (MOVWconst [c])) -> (MVNshiftLL x [c])
(MVNshiftRLreg x (MOVWconst [c])) -> (MVNshiftRL x [c])
(MVNshiftRAreg x (MOVWconst [c])) -> (MVNshiftRA x [c])
(CMPshiftLLreg x y (MOVWconst [c])) -> (CMPshiftLL x y [c])
(CMPshiftRLreg x y (MOVWconst [c])) -> (CMPshiftRL x y [c])
(CMPshiftRAreg x y (MOVWconst [c])) -> (CMPshiftRA x y [c])
// use indexed loads and stores
(MOVWload [0] {sym} (ADD ptr idx) mem) && sym == nil -> (MOVWloadidx ptr idx mem)
(MOVWstore [0] {sym} (ADD ptr idx) val mem) && sym == nil -> (MOVWstoreidx ptr idx val mem)
(MOVWload [0] {sym} (ADDshiftLL ptr idx [c]) mem) && sym == nil -> (MOVWloadshiftLL ptr idx [c] mem)
(MOVWload [0] {sym} (ADDshiftRL ptr idx [c]) mem) && sym == nil -> (MOVWloadshiftRL ptr idx [c] mem)
(MOVWload [0] {sym} (ADDshiftRA ptr idx [c]) mem) && sym == nil -> (MOVWloadshiftRA ptr idx [c] mem)
(MOVWstore [0] {sym} (ADDshiftLL ptr idx [c]) val mem) && sym == nil -> (MOVWstoreshiftLL ptr idx [c] val mem)
(MOVWstore [0] {sym} (ADDshiftRL ptr idx [c]) val mem) && sym == nil -> (MOVWstoreshiftRL ptr idx [c] val mem)
(MOVWstore [0] {sym} (ADDshiftRA ptr idx [c]) val mem) && sym == nil -> (MOVWstoreshiftRA ptr idx [c] val mem)
// constant folding in indexed loads and stores
(MOVWloadidx ptr (MOVWconst [c]) mem) -> (MOVWload [c] ptr mem)
(MOVWloadidx (MOVWconst [c]) ptr mem) -> (MOVWload [c] ptr mem)
(MOVWstoreidx ptr (MOVWconst [c]) val mem) -> (MOVWstore [c] ptr val mem)
(MOVWstoreidx (MOVWconst [c]) ptr val mem) -> (MOVWstore [c] ptr val mem)
(MOVWloadidx ptr (SLLconst idx [c]) mem) -> (MOVWloadshiftLL ptr idx [c] mem)
(MOVWloadidx (SLLconst idx [c]) ptr mem) -> (MOVWloadshiftLL ptr idx [c] mem)
(MOVWloadidx ptr (SRLconst idx [c]) mem) -> (MOVWloadshiftRL ptr idx [c] mem)
(MOVWloadidx (SRLconst idx [c]) ptr mem) -> (MOVWloadshiftRL ptr idx [c] mem)
(MOVWloadidx ptr (SRAconst idx [c]) mem) -> (MOVWloadshiftRA ptr idx [c] mem)
(MOVWloadidx (SRAconst idx [c]) ptr mem) -> (MOVWloadshiftRA ptr idx [c] mem)
(MOVWstoreidx ptr (SLLconst idx [c]) val mem) -> (MOVWstoreshiftLL ptr idx [c] val mem)
(MOVWstoreidx (SLLconst idx [c]) ptr val mem) -> (MOVWstoreshiftLL ptr idx [c] val mem)
(MOVWstoreidx ptr (SRLconst idx [c]) val mem) -> (MOVWstoreshiftRL ptr idx [c] val mem)
(MOVWstoreidx (SRLconst idx [c]) ptr val mem) -> (MOVWstoreshiftRL ptr idx [c] val mem)
(MOVWstoreidx ptr (SRAconst idx [c]) val mem) -> (MOVWstoreshiftRA ptr idx [c] val mem)
(MOVWstoreidx (SRAconst idx [c]) ptr val mem) -> (MOVWstoreshiftRA ptr idx [c] val mem)
(MOVWloadshiftLL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)<<uint64(d))] ptr mem)
(MOVWloadshiftRL ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(uint32(c)>>uint64(d))] ptr mem)
(MOVWloadshiftRA ptr (MOVWconst [c]) [d] mem) -> (MOVWload [int64(int32(c)>>uint64(d))] ptr mem)
(MOVWstoreshiftLL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)<<uint64(d))] ptr val mem)
(MOVWstoreshiftRL ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(uint32(c)>>uint64(d))] ptr val mem)
(MOVWstoreshiftRA ptr (MOVWconst [c]) [d] val mem) -> (MOVWstore [int64(int32(c)>>uint64(d))] ptr val mem)
// generic simplifications
(ADD x (RSBconst [0] y)) -> (SUB x y)
(ADD (RSBconst [0] y) x) -> (SUB x y)
(SUB x x) -> (MOVWconst [0])
(RSB x x) -> (MOVWconst [0])
(AND x x) -> x
(OR x x) -> x
(XOR x x) -> (MOVWconst [0])
@ -754,3 +1180,26 @@
(ADD a (MUL x y)) -> (MULA x y a)
(AND x (MVN y)) -> (BIC x y)
// simplification with *shift ops
(SUBshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVWconst [0])
(SUBshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVWconst [0])
(SUBshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVWconst [0])
(RSBshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVWconst [0])
(RSBshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVWconst [0])
(RSBshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVWconst [0])
(ANDshiftLL x y:(SLLconst x [c]) [d]) && c==d -> y
(ANDshiftRL x y:(SRLconst x [c]) [d]) && c==d -> y
(ANDshiftRA x y:(SRAconst x [c]) [d]) && c==d -> y
(ORshiftLL x y:(SLLconst x [c]) [d]) && c==d -> y
(ORshiftRL x y:(SRLconst x [c]) [d]) && c==d -> y
(ORshiftRA x y:(SRAconst x [c]) [d]) && c==d -> y
(XORshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVWconst [0])
(XORshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVWconst [0])
(XORshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVWconst [0])
(BICshiftLL x (SLLconst x [c]) [d]) && c==d -> (MOVWconst [0])
(BICshiftRL x (SRLconst x [c]) [d]) && c==d -> (MOVWconst [0])
(BICshiftRA x (SRAconst x [c]) [d]) && c==d -> (MOVWconst [0])
(AND x (MVNshiftLL y [c])) -> (BICshiftLL x y [c])
(AND x (MVNshiftRL y [c])) -> (BICshiftRL x y [c])
(AND x (MVNshiftRA y [c])) -> (BICshiftRA x y [c])

View File

@ -110,8 +110,13 @@ func init() {
gp2flags = regInfo{inputs: []regMask{gpg, gpg}, outputs: []regMask{flags}}
gp2flags1 = regInfo{inputs: []regMask{gp, gp, flags}, outputs: []regMask{gp}}
gp31 = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}}
gp31cf = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{gp}, clobbers: flags} // cf: clobbers flags
gp3flags = regInfo{inputs: []regMask{gp, gp, gp}, outputs: []regMask{flags}}
gp3flags1 = regInfo{inputs: []regMask{gp, gp, gp, flags}, outputs: []regMask{gp}}
gpload = regInfo{inputs: []regMask{gpspsbg}, outputs: []regMask{gp}}
gpstore = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{}}
gp2load = regInfo{inputs: []regMask{gpspsbg, gpg}, outputs: []regMask{gp}}
gp2store = regInfo{inputs: []regMask{gpspsbg, gpg, gpg}, outputs: []regMask{}}
fp01 = regInfo{inputs: []regMask{}, outputs: []regMask{fp}}
fp11 = regInfo{inputs: []regMask{fp}, outputs: []regMask{fp}}
fpgp = regInfo{inputs: []regMask{fp}, outputs: []regMask{gp}}
@ -176,14 +181,105 @@ func init() {
{name: "SQRTD", argLength: 1, reg: fp11, asm: "SQRTD"}, // sqrt(arg0), float64
// shifts
{name: "SLL", argLength: 2, reg: gp21cf, asm: "SLL"}, // arg0 << arg1, results 0 for large shift
{name: "SLL", argLength: 2, reg: gp21, asm: "SLL"}, // arg0 << arg1, shift amount is mod 256
{name: "SLLconst", argLength: 1, reg: gp11, asm: "SLL", aux: "Int32"}, // arg0 << auxInt
{name: "SRL", argLength: 2, reg: gp21cf, asm: "SRL"}, // arg0 >> arg1, unsigned, results 0 for large shift
{name: "SRL", argLength: 2, reg: gp21, asm: "SRL"}, // arg0 >> arg1, unsigned, shift amount is mod 256
{name: "SRLconst", argLength: 1, reg: gp11, asm: "SRL", aux: "Int32"}, // arg0 >> auxInt, unsigned
{name: "SRA", argLength: 2, reg: gp21cf, asm: "SRA"}, // arg0 >> arg1, signed, results 0/-1 for large shift
{name: "SRA", argLength: 2, reg: gp21cf, asm: "SRA"}, // arg0 >> arg1, signed, shift amount is mod 256
{name: "SRAconst", argLength: 1, reg: gp11, asm: "SRA", aux: "Int32"}, // arg0 >> auxInt, signed
{name: "SRRconst", argLength: 1, reg: gp11, aux: "Int32"}, // arg0 right rotate by auxInt bits
{name: "ADDshiftLL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1<<auxInt
{name: "ADDshiftRL", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, unsigned shift
{name: "ADDshiftRA", argLength: 2, reg: gp21, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, signed shift
{name: "SUBshiftLL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int32"}, // arg0 - arg1<<auxInt
{name: "SUBshiftRL", argLength: 2, reg: gp21, asm: "SUB", aux: "Int32"}, // arg0 - arg1>>auxInt, unsigned shift
{name: "SUBshiftRA", argLength: 2, reg: gp21, asm: "SUB", aux: "Int32"}, // arg0 - arg1>>auxInt, signed shift
{name: "RSBshiftLL", argLength: 2, reg: gp21, asm: "RSB", aux: "Int32"}, // arg1<<auxInt - arg0
{name: "RSBshiftRL", argLength: 2, reg: gp21, asm: "RSB", aux: "Int32"}, // arg1>>auxInt - arg0, unsigned shift
{name: "RSBshiftRA", argLength: 2, reg: gp21, asm: "RSB", aux: "Int32"}, // arg1>>auxInt - arg0, signed shift
{name: "ANDshiftLL", argLength: 2, reg: gp21, asm: "AND", aux: "Int32"}, // arg0 & (arg1<<auxInt)
{name: "ANDshiftRL", argLength: 2, reg: gp21, asm: "AND", aux: "Int32"}, // arg0 & (arg1>>auxInt), unsigned shift
{name: "ANDshiftRA", argLength: 2, reg: gp21, asm: "AND", aux: "Int32"}, // arg0 & (arg1>>auxInt), signed shift
{name: "ORshiftLL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int32"}, // arg0 | arg1<<auxInt
{name: "ORshiftRL", argLength: 2, reg: gp21, asm: "ORR", aux: "Int32"}, // arg0 | arg1>>auxInt, unsigned shift
{name: "ORshiftRA", argLength: 2, reg: gp21, asm: "ORR", aux: "Int32"}, // arg0 | arg1>>auxInt, signed shift
{name: "XORshiftLL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int32"}, // arg0 ^ arg1<<auxInt
{name: "XORshiftRL", argLength: 2, reg: gp21, asm: "EOR", aux: "Int32"}, // arg0 ^ arg1>>auxInt, unsigned shift
{name: "XORshiftRA", argLength: 2, reg: gp21, asm: "EOR", aux: "Int32"}, // arg0 ^ arg1>>auxInt, signed shift
{name: "BICshiftLL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int32"}, // arg0 &^ (arg1<<auxInt)
{name: "BICshiftRL", argLength: 2, reg: gp21, asm: "BIC", aux: "Int32"}, // arg0 &^ (arg1>>auxInt), unsigned shift
{name: "BICshiftRA", argLength: 2, reg: gp21, asm: "BIC", aux: "Int32"}, // arg0 &^ (arg1>>auxInt), signed shift
{name: "MVNshiftLL", argLength: 1, reg: gp11, asm: "MVN", aux: "Int32"}, // ^(arg0<<auxInt)
{name: "MVNshiftRL", argLength: 1, reg: gp11, asm: "MVN", aux: "Int32"}, // ^(arg0>>auxInt), unsigned shift
{name: "MVNshiftRA", argLength: 1, reg: gp11, asm: "MVN", aux: "Int32"}, // ^(arg0>>auxInt), signed shift
{name: "ADCshiftLL", argLength: 3, reg: gp2flags1, asm: "ADC", aux: "Int32"}, // arg0 + arg1<<auxInt + carry, arg2=flags
{name: "ADCshiftRL", argLength: 3, reg: gp2flags1, asm: "ADC", aux: "Int32"}, // arg0 + arg1>>auxInt + carry, unsigned shift, arg2=flags
{name: "ADCshiftRA", argLength: 3, reg: gp2flags1, asm: "ADC", aux: "Int32"}, // arg0 + arg1>>auxInt + carry, signed shift, arg2=flags
{name: "SBCshiftLL", argLength: 3, reg: gp2flags1, asm: "SBC", aux: "Int32"}, // arg0 - arg1<<auxInt - carry, arg2=flags
{name: "SBCshiftRL", argLength: 3, reg: gp2flags1, asm: "SBC", aux: "Int32"}, // arg0 - arg1>>auxInt - carry, unsigned shift, arg2=flags
{name: "SBCshiftRA", argLength: 3, reg: gp2flags1, asm: "SBC", aux: "Int32"}, // arg0 - arg1>>auxInt - carry, signed shift, arg2=flags
{name: "RSCshiftLL", argLength: 3, reg: gp2flags1, asm: "RSC", aux: "Int32"}, // arg1<<auxInt - arg0 - carry, arg2=flags
{name: "RSCshiftRL", argLength: 3, reg: gp2flags1, asm: "RSC", aux: "Int32"}, // arg1>>auxInt - arg0 - carry, unsigned shift, arg2=flags
{name: "RSCshiftRA", argLength: 3, reg: gp2flags1, asm: "RSC", aux: "Int32"}, // arg1>>auxInt - arg0 - carry, signed shift, arg2=flags
{name: "ADDSshiftLL", argLength: 2, reg: gp21cf, asm: "ADD", aux: "Int32"}, // arg0 + arg1<<auxInt, set carry flag
{name: "ADDSshiftRL", argLength: 2, reg: gp21cf, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, unsigned shift, set carry flag
{name: "ADDSshiftRA", argLength: 2, reg: gp21cf, asm: "ADD", aux: "Int32"}, // arg0 + arg1>>auxInt, signed shift, set carry flag
{name: "SUBSshiftLL", argLength: 2, reg: gp21cf, asm: "SUB", aux: "Int32"}, // arg0 - arg1<<auxInt, set carry flag
{name: "SUBSshiftRL", argLength: 2, reg: gp21cf, asm: "SUB", aux: "Int32"}, // arg0 - arg1>>auxInt, unsigned shift, set carry flag
{name: "SUBSshiftRA", argLength: 2, reg: gp21cf, asm: "SUB", aux: "Int32"}, // arg0 - arg1>>auxInt, signed shift, set carry flag
{name: "RSBSshiftLL", argLength: 2, reg: gp21cf, asm: "RSB", aux: "Int32"}, // arg1<<auxInt - arg0, set carry flag
{name: "RSBSshiftRL", argLength: 2, reg: gp21cf, asm: "RSB", aux: "Int32"}, // arg1>>auxInt - arg0, unsigned shift, set carry flag
{name: "RSBSshiftRA", argLength: 2, reg: gp21cf, asm: "RSB", aux: "Int32"}, // arg1>>auxInt - arg0, signed shift, set carry flag
{name: "ADDshiftLLreg", argLength: 3, reg: gp31, asm: "ADD"}, // arg0 + arg1<<arg2
{name: "ADDshiftRLreg", argLength: 3, reg: gp31, asm: "ADD"}, // arg0 + arg1>>arg2, unsigned shift
{name: "ADDshiftRAreg", argLength: 3, reg: gp31, asm: "ADD"}, // arg0 + arg1>>arg2, signed shift
{name: "SUBshiftLLreg", argLength: 3, reg: gp31, asm: "SUB"}, // arg0 - arg1<<arg2
{name: "SUBshiftRLreg", argLength: 3, reg: gp31, asm: "SUB"}, // arg0 - arg1>>arg2, unsigned shift
{name: "SUBshiftRAreg", argLength: 3, reg: gp31, asm: "SUB"}, // arg0 - arg1>>arg2, signed shift
{name: "RSBshiftLLreg", argLength: 3, reg: gp31, asm: "RSB"}, // arg1<<arg2 - arg0
{name: "RSBshiftRLreg", argLength: 3, reg: gp31, asm: "RSB"}, // arg1>>arg2 - arg0, unsigned shift
{name: "RSBshiftRAreg", argLength: 3, reg: gp31, asm: "RSB"}, // arg1>>arg2 - arg0, signed shift
{name: "ANDshiftLLreg", argLength: 3, reg: gp31, asm: "AND"}, // arg0 & (arg1<<arg2)
{name: "ANDshiftRLreg", argLength: 3, reg: gp31, asm: "AND"}, // arg0 & (arg1>>arg2), unsigned shift
{name: "ANDshiftRAreg", argLength: 3, reg: gp31, asm: "AND"}, // arg0 & (arg1>>arg2), signed shift
{name: "ORshiftLLreg", argLength: 3, reg: gp31, asm: "ORR"}, // arg0 | arg1<<arg2
{name: "ORshiftRLreg", argLength: 3, reg: gp31, asm: "ORR"}, // arg0 | arg1>>arg2, unsigned shift
{name: "ORshiftRAreg", argLength: 3, reg: gp31, asm: "ORR"}, // arg0 | arg1>>arg2, signed shift
{name: "XORshiftLLreg", argLength: 3, reg: gp31, asm: "EOR"}, // arg0 ^ arg1<<arg2
{name: "XORshiftRLreg", argLength: 3, reg: gp31, asm: "EOR"}, // arg0 ^ arg1>>arg2, unsigned shift
{name: "XORshiftRAreg", argLength: 3, reg: gp31, asm: "EOR"}, // arg0 ^ arg1>>arg2, signed shift
{name: "BICshiftLLreg", argLength: 3, reg: gp31, asm: "BIC"}, // arg0 &^ (arg1<<arg2)
{name: "BICshiftRLreg", argLength: 3, reg: gp31, asm: "BIC"}, // arg0 &^ (arg1>>arg2), unsigned shift
{name: "BICshiftRAreg", argLength: 3, reg: gp31, asm: "BIC"}, // arg0 &^ (arg1>>arg2), signed shift
{name: "MVNshiftLLreg", argLength: 2, reg: gp21, asm: "MVN"}, // ^(arg0<<arg1)
{name: "MVNshiftRLreg", argLength: 2, reg: gp21, asm: "MVN"}, // ^(arg0>>arg1), unsigned shift
{name: "MVNshiftRAreg", argLength: 2, reg: gp21, asm: "MVN"}, // ^(arg0>>arg1), signed shift
{name: "ADCshiftLLreg", argLength: 4, reg: gp3flags1, asm: "ADC"}, // arg0 + arg1<<arg2 + carry, arg3=flags
{name: "ADCshiftRLreg", argLength: 4, reg: gp3flags1, asm: "ADC"}, // arg0 + arg1>>arg2 + carry, unsigned shift, arg3=flags
{name: "ADCshiftRAreg", argLength: 4, reg: gp3flags1, asm: "ADC"}, // arg0 + arg1>>arg2 + carry, signed shift, arg3=flags
{name: "SBCshiftLLreg", argLength: 4, reg: gp3flags1, asm: "SBC"}, // arg0 - arg1<<arg2 - carry, arg3=flags
{name: "SBCshiftRLreg", argLength: 4, reg: gp3flags1, asm: "SBC"}, // arg0 - arg1>>arg2 - carry, unsigned shift, arg3=flags
{name: "SBCshiftRAreg", argLength: 4, reg: gp3flags1, asm: "SBC"}, // arg0 - arg1>>arg2 - carry, signed shift, arg3=flags
{name: "RSCshiftLLreg", argLength: 4, reg: gp3flags1, asm: "RSC"}, // arg1<<arg2 - arg0 - carry, arg3=flags
{name: "RSCshiftRLreg", argLength: 4, reg: gp3flags1, asm: "RSC"}, // arg1>>arg2 - arg0 - carry, unsigned shift, arg3=flags
{name: "RSCshiftRAreg", argLength: 4, reg: gp3flags1, asm: "RSC"}, // arg1>>arg2 - arg0 - carry, signed shift, arg3=flags
{name: "ADDSshiftLLreg", argLength: 3, reg: gp31cf, asm: "ADD"}, // arg0 + arg1<<arg2, set carry flag
{name: "ADDSshiftRLreg", argLength: 3, reg: gp31cf, asm: "ADD"}, // arg0 + arg1>>arg2, unsigned shift, set carry flag
{name: "ADDSshiftRAreg", argLength: 3, reg: gp31cf, asm: "ADD"}, // arg0 + arg1>>arg2, signed shift, set carry flag
{name: "SUBSshiftLLreg", argLength: 3, reg: gp31cf, asm: "SUB"}, // arg0 - arg1<<arg2, set carry flag
{name: "SUBSshiftRLreg", argLength: 3, reg: gp31cf, asm: "SUB"}, // arg0 - arg1>>arg2, unsigned shift, set carry flag
{name: "SUBSshiftRAreg", argLength: 3, reg: gp31cf, asm: "SUB"}, // arg0 - arg1>>arg2, signed shift, set carry flag
{name: "RSBSshiftLLreg", argLength: 3, reg: gp31cf, asm: "RSB"}, // arg1<<arg2 - arg0, set carry flag
{name: "RSBSshiftRLreg", argLength: 3, reg: gp31cf, asm: "RSB"}, // arg1>>arg2 - arg0, unsigned shift, set carry flag
{name: "RSBSshiftRAreg", argLength: 3, reg: gp31cf, asm: "RSB"}, // arg1>>arg2 - arg0, signed shift, set carry flag
// comparisons
{name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
{name: "CMPconst", argLength: 1, reg: gp1flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to auxInt
{name: "CMN", argLength: 2, reg: gp2flags, asm: "CMN", typ: "Flags"}, // arg0 compare to -arg1
@ -195,6 +291,15 @@ func init() {
{name: "CMPF", argLength: 2, reg: fp2flags, asm: "CMPF", typ: "Flags"}, // arg0 compare to arg1, float32
{name: "CMPD", argLength: 2, reg: fp2flags, asm: "CMPD", typ: "Flags"}, // arg0 compare to arg1, float64
{name: "CMPshiftLL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to arg1<<auxInt
{name: "CMPshiftRL", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to arg1>>auxInt, unsigned shift
{name: "CMPshiftRA", argLength: 2, reg: gp2flags, asm: "CMP", aux: "Int32", typ: "Flags"}, // arg0 compare to arg1>>auxInt, signed shift
{name: "CMPshiftLLreg", argLength: 3, reg: gp3flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1<<arg2
{name: "CMPshiftRLreg", argLength: 3, reg: gp3flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1>>arg2, unsigned shift
{name: "CMPshiftRAreg", argLength: 3, reg: gp3flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1>>arg2, signed shift
// moves
{name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", typ: "UInt32", rematerializeable: true}, // 32 low bits of auxint
{name: "MOVFconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVF", typ: "Float32", rematerializeable: true}, // auxint as 64-bit float, convert to 32-bit float
{name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
@ -215,6 +320,16 @@ func init() {
{name: "MOVFstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVF", typ: "Mem"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "MOVDstore", argLength: 3, reg: fpstore, aux: "SymOff", asm: "MOVD", typ: "Mem"}, // store 8 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
{name: "MOVWloadidx", argLength: 3, reg: gp2load, asm: "MOVW"}, // load from arg0 + arg1. arg2=mem
{name: "MOVWloadshiftLL", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32"}, // load from arg0 + arg1<<auxInt. arg2=mem
{name: "MOVWloadshiftRL", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32"}, // load from arg0 + arg1>>auxInt, unsigned shift. arg2=mem
{name: "MOVWloadshiftRA", argLength: 3, reg: gp2load, asm: "MOVW", aux: "Int32"}, // load from arg0 + arg1>>auxInt, signed shift. arg2=mem
{name: "MOVWstoreidx", argLength: 4, reg: gp2store, asm: "MOVW"}, // store arg2 to arg0 + arg1. arg3=mem
{name: "MOVWstoreshiftLL", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32"}, // store arg2 to arg0 + arg1<<auxInt. arg3=mem
{name: "MOVWstoreshiftRL", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32"}, // store arg2 to arg0 + arg1>>auxInt, unsigned shift. arg3=mem
{name: "MOVWstoreshiftRA", argLength: 4, reg: gp2store, asm: "MOVW", aux: "Int32"}, // store arg2 to arg0 + arg1>>auxInt, signed shift. arg3=mem
{name: "MOVBreg", argLength: 1, reg: gp11, asm: "MOVBS"}, // move from arg0, sign-extended from byte
{name: "MOVBUreg", argLength: 1, reg: gp11, asm: "MOVBU"}, // move from arg0, unsign-extended from byte
{name: "MOVHreg", argLength: 1, reg: gp11, asm: "MOVHS"}, // move from arg0, sign-extended from half
@ -232,6 +347,12 @@ func init() {
{name: "MOVFD", argLength: 1, reg: fp11, asm: "MOVFD"}, // float32 -> float64
{name: "MOVDF", argLength: 1, reg: fp11, asm: "MOVDF"}, // float64 -> float32
// conditional instructions, for lowering shifts
{name: "CMOVWHSconst", argLength: 2, reg: gp1flags1, asm: "MOVW", aux: "Int32", resultInArg0: true}, // replace arg0 w/ const if flags indicates HS, arg1=flags
{name: "CMOVWLSconst", argLength: 2, reg: gp1flags1, asm: "MOVW", aux: "Int32", resultInArg0: true}, // replace arg0 w/ const if flags indicates LS, arg1=flags
{name: "SRAcond", argLength: 3, reg: gp2flags1, asm: "SRA"}, // arg0 >> 31 if flags indicates HS, arg0 >> arg1 otherwise, signed shift, arg2=flags
// function calls
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
{name: "CALLclosure", argLength: 3, reg: regInfo{inputs: []regMask{gpsp, buildReg("R7"), 0}, clobbers: callerSave}, aux: "Int64"}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem
{name: "CALLdefer", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "Int64"}, // call deferproc. arg0=mem, auxint=argsize, returns mem
@ -256,8 +377,6 @@ func init() {
{name: "LoweredSelect0", argLength: 1, reg: regInfo{inputs: []regMask{}, outputs: []regMask{buildReg("R0")}}}, // the first component of a tuple, implicitly in R0, arg0=tuple
{name: "LoweredSelect1", argLength: 1, reg: regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}, resultInArg0: true}, // the second component of a tuple, arg0=tuple
{name: "LoweredZeromask", argLength: 1, reg: gp11}, // 0 if arg0 == 1, 0xffffffff if arg0 != 0
// duffzero (must be 4-byte aligned)
// arg0 = address of memory to zero (in R1, changed as side effect)
// arg1 = value to store (always zero)

View File

@ -157,7 +157,13 @@ func (op Op) isTupleGenerator() bool {
switch op {
case OpAdd32carry, OpSub32carry, OpMul32uhilo,
OpARMADDS, OpARMSUBS, OpARMMULLU,
OpARMADDSconst, OpARMSUBSconst, OpARMRSBSconst:
OpARMADDSconst, OpARMSUBSconst, OpARMRSBSconst,
OpARMADDSshiftLL, OpARMSUBSshiftLL, OpARMRSBSshiftLL,
OpARMADDSshiftRL, OpARMSUBSshiftRL, OpARMRSBSshiftRL,
OpARMADDSshiftRA, OpARMSUBSshiftRA, OpARMRSBSshiftRA,
OpARMADDSshiftLLreg, OpARMSUBSshiftLLreg, OpARMRSBSshiftLLreg,
OpARMADDSshiftRLreg, OpARMSUBSshiftRLreg, OpARMRSBSshiftRLreg,
OpARMADDSshiftRAreg, OpARMSUBSshiftRAreg, OpARMRSBSshiftRAreg:
return true
}
return false

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff