cmd/compile: use ISEL, cleanup use of zero & extensions

Abandoned earlier efforts to expose zero register,
but left it in numbering to decrease squirrelyness of
register allocator.

ISELrelOp used in code generation of bool := x relOp y.
Some patterns added to better elide zero case and
some sign extension.

Updates: #17109

Change-Id: Ida7839f0023ca8f0ffddc0545f0ac269e65b05d9
Reviewed-on: https://go-review.googlesource.com/29380
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Keith Randall <khr@golang.org>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
David Chase 2016-09-16 15:02:47 -07:00
parent dcbbd319e9
commit cddddbc623
12 changed files with 826 additions and 543 deletions

View File

@ -336,6 +336,9 @@ const (
// Instruction updates whichever of from/to is type D_OREG. (ppc64) // Instruction updates whichever of from/to is type D_OREG. (ppc64)
PostInc = 1 << 29 PostInc = 1 << 29
// Optional 3rd input operand, only ever read.
From3Read = 1 << 30
) )
type Arch struct { type Arch struct {

View File

@ -624,6 +624,20 @@ func progeffects(prog *obj.Prog, vars []*Node, uevar bvec, varkill bvec, avarini
} }
} }
if info.Flags&From3Read != 0 {
from := prog.From3
if from.Node != nil && from.Sym != nil {
n := from.Node.(*Node)
if pos := liveIndex(n, vars); pos >= 0 {
if n.Addrtaken {
bvset(avarinit, pos)
} else {
bvset(uevar, pos)
}
}
}
}
if info.Flags&(RightRead|RightWrite|RightAddr) != 0 { if info.Flags&(RightRead|RightWrite|RightAddr) != 0 {
to := &prog.To to := &prog.To
if to.Node != nil && to.Sym != nil { if to.Node != nil && to.Sym != nil {

View File

@ -100,6 +100,8 @@ var progtable = [ppc64.ALAST & obj.AMask]gc.ProgInfo{
ppc64.AMOVHZ & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv}, ppc64.AMOVHZ & obj.AMask: {Flags: gc.SizeW | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
ppc64.AMOVW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv}, ppc64.AMOVW & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},
ppc64.AISEL & obj.AMask: {Flags: gc.SizeQ | gc.RegRead | gc.From3Read | gc.RightWrite},
// there is no AMOVWU. // there is no AMOVWU.
ppc64.AMOVWZU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc}, ppc64.AMOVWZU & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv | gc.PostInc},
ppc64.AMOVWZ & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv}, ppc64.AMOVWZ & obj.AMask: {Flags: gc.SizeL | gc.LeftRead | gc.RightWrite | gc.Move | gc.Conv},

View File

@ -26,6 +26,28 @@ var condOps = map[ssa.Op]obj.As{
ssa.OpPPC64FGreaterEqual: ppc64.ABGT, // 2 branches for FCMP >=, second is BEQ ssa.OpPPC64FGreaterEqual: ppc64.ABGT, // 2 branches for FCMP >=, second is BEQ
} }
// iselOp encodes mapping of comparison operations onto ISEL operands
type iselOp struct {
cond int64
valueIfCond int // if cond is true, the value to return (0 or 1)
}
// Input registers to ISEL used for comparison. Index 0 is zero, 1 is (will be) 1
var iselRegs = [2]int16{ppc64.REG_R0, ppc64.REGTMP}
var iselOps = map[ssa.Op]iselOp{
ssa.OpPPC64Equal: iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 1},
ssa.OpPPC64NotEqual: iselOp{cond: ppc64.C_COND_EQ, valueIfCond: 0},
ssa.OpPPC64LessThan: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
ssa.OpPPC64GreaterEqual: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 0},
ssa.OpPPC64GreaterThan: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
ssa.OpPPC64LessEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 0},
ssa.OpPPC64FLessThan: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1},
ssa.OpPPC64FGreaterThan: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1},
ssa.OpPPC64FLessEqual: iselOp{cond: ppc64.C_COND_LT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
ssa.OpPPC64FGreaterEqual: iselOp{cond: ppc64.C_COND_GT, valueIfCond: 1}, // 2 comparisons, 2nd is EQ
}
// markMoves marks any MOVXconst ops that need to avoid clobbering flags. // markMoves marks any MOVXconst ops that need to avoid clobbering flags.
func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) { func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
// flive := b.FlagsLiveAtEnd // flive := b.FlagsLiveAtEnd
@ -34,7 +56,7 @@ func ssaMarkMoves(s *gc.SSAGenState, b *ssa.Block) {
// } // }
// for i := len(b.Values) - 1; i >= 0; i-- { // for i := len(b.Values) - 1; i >= 0; i-- {
// v := b.Values[i] // v := b.Values[i]
// if flive && (v.Op == ssa.OpPPC64MOVWconst || v.Op == ssa.OpPPC64MOVDconst) { // if flive && (v.Op == v.Op == ssa.OpPPC64MOVDconst) {
// // The "mark" is any non-nil Aux value. // // The "mark" is any non-nil Aux value.
// v.Aux = v // v.Aux = v
// } // }
@ -120,6 +142,17 @@ func scratchFpMem(s *gc.SSAGenState, a *obj.Addr) {
a.Reg = ppc64.REGSP a.Reg = ppc64.REGSP
} }
func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) {
r := v.Reg()
p := gc.Prog(ppc64.AISEL)
p.To.Type = obj.TYPE_REG
p.To.Reg = r
p.Reg = r1
p.From3 = &obj.Addr{Type: obj.TYPE_REG, Reg: r2}
p.From.Type = obj.TYPE_CONST
p.From.Offset = cr
}
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
s.SetLineno(v.Line) s.SetLineno(v.Line)
switch v.Op { switch v.Op {
@ -382,7 +415,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg) v.Fatalf("bad reg %s for symbol type %T, want %s", reg, v.Aux, wantreg)
} }
case ssa.OpPPC64MOVDconst, ssa.OpPPC64MOVWconst: case ssa.OpPPC64MOVDconst:
p := gc.Prog(v.Op.Asm()) p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt p.From.Offset = v.AuxInt
@ -418,7 +451,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload, ssa.OpPPC64MOVBload, ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload: case ssa.OpPPC64MOVDload, ssa.OpPPC64MOVWload, ssa.OpPPC64MOVHload, ssa.OpPPC64MOVWZload, ssa.OpPPC64MOVBZload, ssa.OpPPC64MOVHZload:
p := gc.Prog(v.Op.Asm()) p := gc.Prog(v.Op.Asm())
p.From.Type = obj.TYPE_MEM p.From.Type = obj.TYPE_MEM
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()
@ -465,25 +498,18 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
ssa.OpPPC64GreaterThan, ssa.OpPPC64GreaterThan,
ssa.OpPPC64FGreaterThan, ssa.OpPPC64FGreaterThan,
ssa.OpPPC64GreaterEqual: ssa.OpPPC64GreaterEqual:
// On Power7 or later, can use isel instruction: // On Power7 or later, can use isel instruction:
// for a < b, a > b, a = b: // for a < b, a > b, a = b:
// rt := 1 // rtmp := 1
// isel rt,rt,r0,cond // isel rt,rtmp,r0,cond // rt is target in ppc asm
// for a >= b, a <= b, a != b: // for a >= b, a <= b, a != b:
// rt := 1 // rtmp := 1
// isel rt,0,rt,!cond // isel rt,0,rtmp,!cond // rt is target in ppc asm
// However, PPCbe support is for older machines than that, if v.Block.Func.Config.OldArch {
// and isel (which looks a lot like fsel) isn't recognized p := gc.Prog(ppc64.AMOVD)
// yet by the Go assembler. So for now, use the old instruction
// sequence, which we'll need anyway.
// TODO: add support for isel on PPCle and use it.
// generate boolean values
// use conditional move
p := gc.Prog(ppc64.AMOVW)
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = 1 p.From.Offset = 1
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
@ -492,7 +518,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
pb := gc.Prog(condOps[v.Op]) pb := gc.Prog(condOps[v.Op])
pb.To.Type = obj.TYPE_BRANCH pb.To.Type = obj.TYPE_BRANCH
p = gc.Prog(ppc64.AMOVW) p = gc.Prog(ppc64.AMOVD)
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = 0 p.From.Offset = 0
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
@ -500,10 +526,21 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p = gc.Prog(obj.ANOP) p = gc.Prog(obj.ANOP)
gc.Patch(pb, p) gc.Patch(pb, p)
break
}
// Modern PPC uses ISEL
p := gc.Prog(ppc64.AMOVD)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 1
p.To.Type = obj.TYPE_REG
p.To.Reg = iselRegs[1]
iop := iselOps[v.Op]
ssaGenISEL(v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
case ssa.OpPPC64FLessEqual, // These include a second branch for EQ -- dealing with NaN prevents REL= to !REL conversion case ssa.OpPPC64FLessEqual, // These include a second branch for EQ -- dealing with NaN prevents REL= to !REL conversion
ssa.OpPPC64FGreaterEqual: ssa.OpPPC64FGreaterEqual:
if v.Block.Func.Config.OldArch {
p := gc.Prog(ppc64.AMOVW) p := gc.Prog(ppc64.AMOVW)
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = 1 p.From.Offset = 1
@ -524,6 +561,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p = gc.Prog(obj.ANOP) p = gc.Prog(obj.ANOP)
gc.Patch(pb0, p) gc.Patch(pb0, p)
gc.Patch(pb1, p) gc.Patch(pb1, p)
break
}
// Modern PPC uses ISEL
p := gc.Prog(ppc64.AMOVD)
p.From.Type = obj.TYPE_CONST
p.From.Offset = 1
p.To.Type = obj.TYPE_REG
p.To.Reg = iselRegs[1]
iop := iselOps[v.Op]
ssaGenISEL(v, iop.cond, iselRegs[iop.valueIfCond], iselRegs[1-iop.valueIfCond])
ssaGenISEL(v, ppc64.C_COND_EQ, iselRegs[1], v.Reg())
case ssa.OpPPC64LoweredZero: case ssa.OpPPC64LoweredZero:
// Similar to how this is done on ARM, // Similar to how this is done on ARM,

View File

@ -32,8 +32,9 @@ type Config struct {
noDuffDevice bool // Don't use Duff's device noDuffDevice bool // Don't use Duff's device
nacl bool // GOOS=nacl nacl bool // GOOS=nacl
use387 bool // GO386=387 use387 bool // GO386=387
OldArch bool // True for older versions of architecture, e.g. true for PPC64BE, false for PPC64LE
NeedsFpScratch bool // No direct move between GP and FP register sets NeedsFpScratch bool // No direct move between GP and FP register sets
DebugTest bool // as a debugging aid for binary search using GOSSAHASH, make buggy new code conditional on this DebugTest bool // default true unless $GOSSAHASH != ""; as a debugging aid, make new code conditional on this and use GOSSAHASH to binary search for failing cases
sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score sparsePhiCutoff uint64 // Sparse phi location algorithm used above this #blocks*#variables score
curFunc *Func curFunc *Func
@ -180,7 +181,10 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
c.FPReg = framepointerRegARM64 c.FPReg = framepointerRegARM64
c.hasGReg = true c.hasGReg = true
c.noDuffDevice = obj.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend c.noDuffDevice = obj.GOOS == "darwin" // darwin linker cannot handle BR26 reloc with non-zero addend
case "ppc64le", "ppc64": case "ppc64":
c.OldArch = true
fallthrough
case "ppc64le":
c.IntSize = 8 c.IntSize = 8
c.PtrSize = 8 c.PtrSize = 8
c.lowerBlock = rewriteBlockPPC64 c.lowerBlock = rewriteBlockPPC64

View File

@ -149,14 +149,14 @@
// (MaskIfNotCarry CarrySet) -> -1 // (MaskIfNotCarry CarrySet) -> -1
// Lowering constants // Lowering constants
(Const8 [val]) -> (MOVWconst [val]) (Const8 [val]) -> (MOVDconst [val])
(Const16 [val]) -> (MOVWconst [val]) (Const16 [val]) -> (MOVDconst [val])
(Const32 [val]) -> (MOVWconst [val]) (Const32 [val]) -> (MOVDconst [val])
(Const64 [val]) -> (MOVDconst [val]) (Const64 [val]) -> (MOVDconst [val])
(Const32F [val]) -> (FMOVSconst [val]) (Const32F [val]) -> (FMOVSconst [val])
(Const64F [val]) -> (FMOVDconst [val]) (Const64F [val]) -> (FMOVDconst [val])
(ConstNil) -> (MOVDconst [0]) (ConstNil) -> (MOVDconst [0])
(ConstBool [b]) -> (MOVWconst [b]) (ConstBool [b]) -> (MOVDconst [b])
(Addr {sym} base) -> (MOVDaddr {sym} base) (Addr {sym} base) -> (MOVDaddr {sym} base)
// (Addr {sym} base) -> (ADDconst {sym} base) // (Addr {sym} base) -> (ADDconst {sym} base)
@ -326,23 +326,18 @@
(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)
// (FLT (InvertFlags cmp) yes no) -> (FGT cmp yes no)
// (FGT (InvertFlags cmp) yes no) -> (FLT cmp yes no)
// (FLE (InvertFlags cmp) yes no) -> (FGE cmp yes no)
// (FGE (InvertFlags cmp) yes no) -> (FLE cmp yes no)
// constant comparisons // constant comparisons
(CMPWconst (MOVWconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ) (CMPWconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
(CMPWconst (MOVWconst [x]) [y]) && int32(x)<int32(y) -> (FlagLT) (CMPWconst (MOVDconst [x]) [y]) && int32(x)<int32(y) -> (FlagLT)
(CMPWconst (MOVWconst [x]) [y]) && int32(x)>int32(y) -> (FlagGT) (CMPWconst (MOVDconst [x]) [y]) && int32(x)>int32(y) -> (FlagGT)
(CMPconst (MOVDconst [x]) [y]) && int64(x)==int64(y) -> (FlagEQ) (CMPconst (MOVDconst [x]) [y]) && int64(x)==int64(y) -> (FlagEQ)
(CMPconst (MOVDconst [x]) [y]) && int64(x)<int64(y) -> (FlagLT) (CMPconst (MOVDconst [x]) [y]) && int64(x)<int64(y) -> (FlagLT)
(CMPconst (MOVDconst [x]) [y]) && int64(x)>int64(y) -> (FlagGT) (CMPconst (MOVDconst [x]) [y]) && int64(x)>int64(y) -> (FlagGT)
(CMPWUconst (MOVWconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ) (CMPWUconst (MOVDconst [x]) [y]) && int32(x)==int32(y) -> (FlagEQ)
(CMPWUconst (MOVWconst [x]) [y]) && uint32(x)<uint32(y) -> (FlagLT) (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)<uint32(y) -> (FlagLT)
(CMPWUconst (MOVWconst [x]) [y]) && uint32(x)>uint32(y) -> (FlagGT) (CMPWUconst (MOVDconst [x]) [y]) && uint32(x)>uint32(y) -> (FlagGT)
(CMPUconst (MOVDconst [x]) [y]) && int64(x)==int64(y) -> (FlagEQ) (CMPUconst (MOVDconst [x]) [y]) && int64(x)==int64(y) -> (FlagEQ)
(CMPUconst (MOVDconst [x]) [y]) && uint64(x)<uint64(y) -> (FlagLT) (CMPUconst (MOVDconst [x]) [y]) && uint64(x)<uint64(y) -> (FlagLT)
@ -355,29 +350,29 @@
//(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) -> (FlagLT) //(CMPconst (SRLconst _ [c]) [n]) && 0 <= n && 0 < c && c <= 32 && (1<<uint32(32-c)) <= uint32(n) -> (FlagLT)
// absorb flag constants into boolean values // absorb flag constants into boolean values
(Equal (FlagEQ)) -> (MOVWconst [1]) (Equal (FlagEQ)) -> (MOVDconst [1])
(Equal (FlagLT)) -> (MOVWconst [0]) (Equal (FlagLT)) -> (MOVDconst [0])
(Equal (FlagGT)) -> (MOVWconst [0]) (Equal (FlagGT)) -> (MOVDconst [0])
(NotEqual (FlagEQ)) -> (MOVWconst [0]) (NotEqual (FlagEQ)) -> (MOVDconst [0])
(NotEqual (FlagLT)) -> (MOVWconst [1]) (NotEqual (FlagLT)) -> (MOVDconst [1])
(NotEqual (FlagGT)) -> (MOVWconst [1]) (NotEqual (FlagGT)) -> (MOVDconst [1])
(LessThan (FlagEQ)) -> (MOVWconst [0]) (LessThan (FlagEQ)) -> (MOVDconst [0])
(LessThan (FlagLT)) -> (MOVWconst [1]) (LessThan (FlagLT)) -> (MOVDconst [1])
(LessThan (FlagGT)) -> (MOVWconst [0]) (LessThan (FlagGT)) -> (MOVDconst [0])
(LessEqual (FlagEQ)) -> (MOVWconst [1]) (LessEqual (FlagEQ)) -> (MOVDconst [1])
(LessEqual (FlagLT)) -> (MOVWconst [1]) (LessEqual (FlagLT)) -> (MOVDconst [1])
(LessEqual (FlagGT)) -> (MOVWconst [0]) (LessEqual (FlagGT)) -> (MOVDconst [0])
(GreaterThan (FlagEQ)) -> (MOVWconst [0]) (GreaterThan (FlagEQ)) -> (MOVDconst [0])
(GreaterThan (FlagLT)) -> (MOVWconst [0]) (GreaterThan (FlagLT)) -> (MOVDconst [0])
(GreaterThan (FlagGT)) -> (MOVWconst [1]) (GreaterThan (FlagGT)) -> (MOVDconst [1])
(GreaterEqual (FlagEQ)) -> (MOVWconst [1]) (GreaterEqual (FlagEQ)) -> (MOVDconst [1])
(GreaterEqual (FlagLT)) -> (MOVWconst [0]) (GreaterEqual (FlagLT)) -> (MOVDconst [0])
(GreaterEqual (FlagGT)) -> (MOVWconst [1]) (GreaterEqual (FlagGT)) -> (MOVDconst [1])
// absorb InvertFlags into boolean values // absorb InvertFlags into boolean values
(Equal (InvertFlags x)) -> (Equal x) (Equal (InvertFlags x)) -> (Equal x)
@ -387,19 +382,14 @@
(LessEqual (InvertFlags x)) -> (GreaterEqual x) (LessEqual (InvertFlags x)) -> (GreaterEqual x)
(GreaterEqual (InvertFlags x)) -> (LessEqual x) (GreaterEqual (InvertFlags x)) -> (LessEqual x)
// (FLessThan (InvertFlags x)) -> (FGreaterThan x)
// (FGreaterThan (InvertFlags x)) -> (FLessThan x)
// (FLessEqual (InvertFlags x)) -> (FGreaterEqual x)
// (FGreaterEqual (InvertFlags x)) -> (FLessEqual x)
// Lowering loads // Lowering loads
(Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem) (Load <t> ptr mem) && (is64BitInt(t) || isPtr(t)) -> (MOVDload ptr mem)
(Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem) (Load <t> ptr mem) && is32BitInt(t) && isSigned(t) -> (MOVWload ptr mem)
(Load <t> ptr mem) && is32BitInt(t) && !isSigned(t) -> (MOVWZload ptr mem) (Load <t> ptr mem) && is32BitInt(t) && !isSigned(t) -> (MOVWZload ptr mem)
(Load <t> ptr mem) && is16BitInt(t) && isSigned(t) -> (MOVHload ptr mem) (Load <t> ptr mem) && is16BitInt(t) && isSigned(t) -> (MOVHload ptr mem)
(Load <t> ptr mem) && is16BitInt(t) && !isSigned(t) -> (MOVHZload ptr mem) (Load <t> ptr mem) && is16BitInt(t) && !isSigned(t) -> (MOVHZload ptr mem)
(Load <t> ptr mem) && (t.IsBoolean() || (is8BitInt(t) && isSigned(t))) -> (MOVBload ptr mem) (Load <t> ptr mem) && t.IsBoolean() -> (MOVBZload ptr mem)
(Load <t> ptr mem) && is8BitInt(t) && isSigned(t) -> (MOVBreg (MOVBZload ptr mem)) // PPC has no signed-byte load.
(Load <t> ptr mem) && is8BitInt(t) && !isSigned(t) -> (MOVBZload ptr mem) (Load <t> ptr mem) && is8BitInt(t) && !isSigned(t) -> (MOVBZload ptr mem)
(Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem) (Load <t> ptr mem) && is32BitFloat(t) -> (FMOVSload ptr mem)
@ -533,6 +523,15 @@
(ADD (MOVDconst [c]) x) && is32Bit(c) -> (ADDconst [c] x) (ADD (MOVDconst [c]) x) && is32Bit(c) -> (ADDconst [c] x)
(ADD x (MOVDconst [c])) && is32Bit(c) -> (ADDconst [c] x) (ADD x (MOVDconst [c])) && is32Bit(c) -> (ADDconst [c] x)
(ADDconst [c] (ADDconst [d] x)) && is32Bit(c+d) -> (ADDconst [c+d] x) (ADDconst [c] (ADDconst [d] x)) && is32Bit(c+d) -> (ADDconst [c+d] x)
(ADDconst [0] x) -> x
(ANDconst [-1] x) -> x
(ANDconst [0] _) -> (MOVDconst [0])
(XORconst [0] x) -> x
(XOR (MOVDconst [0]) x) -> x
(XOR x (MOVDconst [0])) -> x
(ADD (MOVDconst [0]) x) -> x
(ADD x (MOVDconst [0])) -> x
// Fold offsets for stores. // Fold offsets for stores.
(MOVDstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(off1+off2) -> (MOVDstore [off1+off2] {sym} x val mem) (MOVDstore [off1] {sym} (ADDconst [off2] x) val mem) && is16Bit(off1+off2) -> (MOVDstore [off1+off2] {sym} x val mem)
@ -557,8 +556,6 @@
(FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) -> (FMOVDstore [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (FMOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVBZload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) -> (MOVBZload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVBZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVBZload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) -> (MOVHload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
@ -585,7 +582,6 @@
(MOVWZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVWZload [off1+off2] {sym} x mem) (MOVWZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVWZload [off1+off2] {sym} x mem)
(MOVHload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVHload [off1+off2] {sym} x mem) (MOVHload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVHload [off1+off2] {sym} x mem)
(MOVHZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVHZload [off1+off2] {sym} x mem) (MOVHZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVHZload [off1+off2] {sym} x mem)
(MOVBload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVBload [off1+off2] {sym} x mem)
(MOVBZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVBZload [off1+off2] {sym} x mem) (MOVBZload [off1] {sym} (ADDconst [off2] x) mem) && is16Bit(off1+off2) -> (MOVBZload [off1+off2] {sym} x mem)
// Store of zero -> storezero // Store of zero -> storezero
@ -630,6 +626,16 @@
// Note that MOV??reg returns a 64-bit int, x is not necessarily that wide // Note that MOV??reg returns a 64-bit int, x is not necessarily that wide
// This may interact with other patterns in the future. (Compare with arm64) // This may interact with other patterns in the future. (Compare with arm64)
(MOVBZreg x:(MOVBZload _ _)) -> x (MOVBZreg x:(MOVBZload _ _)) -> x
(MOVBreg x:(MOVBload _ _)) -> x
(MOVHZreg x:(MOVHZload _ _)) -> x (MOVHZreg x:(MOVHZload _ _)) -> x
(MOVHreg x:(MOVHload _ _)) -> x (MOVHreg x:(MOVHload _ _)) -> x
(MOVBZreg (MOVDconst [c])) -> (MOVDconst [int64(uint8(c))])
(MOVBreg (MOVDconst [c])) -> (MOVDconst [int64(int8(c))])
(MOVHZreg (MOVDconst [c])) -> (MOVDconst [int64(uint16(c))])
(MOVHreg (MOVDconst [c])) -> (MOVDconst [int64(int16(c))])
(MOVBstore [off] {sym} ptr (MOVBreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
(MOVBstore [off] {sym} ptr (MOVBZreg x) mem) -> (MOVBstore [off] {sym} ptr x mem)
(MOVHstore [off] {sym} ptr (MOVHreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)
(MOVHstore [off] {sym} ptr (MOVHZreg x) mem) -> (MOVHstore [off] {sym} ptr x mem)

View File

@ -17,7 +17,7 @@ import "strings"
// register (R31). // register (R31).
var regNamesPPC64 = []string{ var regNamesPPC64 = []string{
// "R0", // REGZERO "R0", // REGZERO, not used, but simplifies counting in regalloc
"SP", // REGSP "SP", // REGSP
"SB", // REGSB "SB", // REGSB
"R3", "R3",
@ -233,7 +233,6 @@ func init() {
{name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"}, // zero extend uint16 to uint64 {name: "MOVHZreg", argLength: 1, reg: gp11, asm: "MOVHZ", typ: "Int64"}, // zero extend uint16 to uint64
{name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", typ: "Int64"}, // sign extend int32 to int64 {name: "MOVWreg", argLength: 1, reg: gp11, asm: "MOVW", typ: "Int64"}, // sign extend int32 to int64
{name: "MOVWZreg", argLength: 1, reg: gp11, asm: "MOVWZ", typ: "Int64"}, // zero extend uint32 to uint64 {name: "MOVWZreg", argLength: 1, reg: gp11, asm: "MOVWZ", typ: "Int64"}, // zero extend uint32 to uint64
{name: "MOVBload", argLength: 2, reg: gpload, asm: "MOVB", aux: "SymOff", typ: "Int8", faultOnNilArg0: true}, // sign extend int8 to int64
{name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true}, // zero extend uint8 to uint64 {name: "MOVBZload", argLength: 2, reg: gpload, asm: "MOVBZ", aux: "SymOff", typ: "UInt8", faultOnNilArg0: true}, // zero extend uint8 to uint64
{name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true}, // sign extend int16 to int64 {name: "MOVHload", argLength: 2, reg: gpload, asm: "MOVH", aux: "SymOff", typ: "Int16", faultOnNilArg0: true}, // sign extend int16 to int64
{name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true}, // zero extend uint16 to uint64 {name: "MOVHZload", argLength: 2, reg: gpload, asm: "MOVHZ", aux: "SymOff", typ: "UInt16", faultOnNilArg0: true}, // zero extend uint16 to uint64
@ -258,7 +257,6 @@ func init() {
{name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB {name: "MOVDaddr", argLength: 1, reg: regInfo{inputs: []regMask{sp | sb}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVD", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
{name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", rematerializeable: true}, // {name: "MOVDconst", argLength: 0, reg: gp01, aux: "Int64", asm: "MOVD", rematerializeable: true}, //
{name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", rematerializeable: true}, // 32 low bits of auxint
{name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true}, // {name: "FMOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "FMOVD", rematerializeable: true}, //
{name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float32", asm: "FMOVS", rematerializeable: true}, // {name: "FMOVSconst", argLength: 0, reg: fp01, aux: "Float32", asm: "FMOVS", rematerializeable: true}, //
{name: "FCMPU", argLength: 2, reg: fp2cr, asm: "FCMPU", typ: "Flags"}, {name: "FCMPU", argLength: 2, reg: fp2cr, asm: "FCMPU", typ: "Flags"},

File diff suppressed because it is too large Load Diff

View File

@ -485,7 +485,7 @@ func (s *regAllocState) init(f *Func) {
if s.f.Config.ctxt.Flag_shared { if s.f.Config.ctxt.Flag_shared {
switch s.f.Config.arch { switch s.f.Config.arch {
case "ppc64le": // R2 already reserved. case "ppc64le": // R2 already reserved.
s.allocatable &^= 1 << 11 // R12 -- R0 is skipped in PPC64Ops.go s.allocatable &^= 1 << 12 // R12
} }
} }
if s.f.Config.ctxt.Flag_dynlink { if s.f.Config.ctxt.Flag_dynlink {
@ -495,7 +495,7 @@ func (s *regAllocState) init(f *Func) {
case "arm": case "arm":
s.allocatable &^= 1 << 9 // R9 s.allocatable &^= 1 << 9 // R9
case "ppc64le": // R2 already reserved. case "ppc64le": // R2 already reserved.
s.allocatable &^= 1 << 11 // R12 -- R0 is skipped in PPC64Ops.go s.allocatable &^= 1 << 12 // R12
case "arm64": case "arm64":
// nothing to do? // nothing to do?
case "386": case "386":
@ -813,7 +813,9 @@ func (s *regAllocState) regalloc(f *Func) {
continue continue
} }
a := v.Args[idx] a := v.Args[idx]
m := s.values[a.ID].regs &^ phiUsed // Some instructions target not-allocatable registers.
// They're not suitable for further (phi-function) allocation.
m := s.values[a.ID].regs &^ phiUsed & s.allocatable
if m != 0 { if m != 0 {
r := pickReg(m) r := pickReg(m)
s.freeReg(r) s.freeReg(r)
@ -1942,7 +1944,7 @@ func (e *edgeState) processDest(loc Location, vid ID, splice **Value, line int32
var x *Value var x *Value
if c == nil { if c == nil {
if !e.s.values[vid].rematerializeable { if !e.s.values[vid].rematerializeable {
e.s.f.Fatalf("can't find source for %s->%s: v%d\n", e.p, e.b, vid) e.s.f.Fatalf("can't find source for %s->%s: %s\n", e.p, e.b, v.LongString())
} }
if dstReg { if dstReg {
x = v.copyInto(e.p) x = v.copyInto(e.p)

View File

@ -356,6 +356,15 @@ func clobber(v *Value) bool {
return true return true
} }
// noteRule is an easy way to track if a rule is matched when writing
// new ones. Make the rule of interest also conditional on
// noteRule("note to self: rule of interest matched")
// and that message will print when the rule matches.
func noteRule(s string) bool {
println(s)
return true
}
// logRule logs the use of the rule s. This will only be enabled if // logRule logs the use of the rule s. This will only be enabled if
// rewrite rules were generated with the -log option, see gen/rulegen.go. // rewrite rules were generated with the -log option, see gen/rulegen.go.
func logRule(s string) { func logRule(s string) {

View File

@ -342,6 +342,8 @@ func rewriteValuePPC64(v *Value, config *Config) bool {
return rewriteValuePPC64_OpPPC64ADD(v, config) return rewriteValuePPC64_OpPPC64ADD(v, config)
case OpPPC64ADDconst: case OpPPC64ADDconst:
return rewriteValuePPC64_OpPPC64ADDconst(v, config) return rewriteValuePPC64_OpPPC64ADDconst(v, config)
case OpPPC64ANDconst:
return rewriteValuePPC64_OpPPC64ANDconst(v, config)
case OpPPC64CMPUconst: case OpPPC64CMPUconst:
return rewriteValuePPC64_OpPPC64CMPUconst(v, config) return rewriteValuePPC64_OpPPC64CMPUconst(v, config)
case OpPPC64CMPWUconst: case OpPPC64CMPWUconst:
@ -372,8 +374,6 @@ func rewriteValuePPC64(v *Value, config *Config) bool {
return rewriteValuePPC64_OpPPC64MOVBZload(v, config) return rewriteValuePPC64_OpPPC64MOVBZload(v, config)
case OpPPC64MOVBZreg: case OpPPC64MOVBZreg:
return rewriteValuePPC64_OpPPC64MOVBZreg(v, config) return rewriteValuePPC64_OpPPC64MOVBZreg(v, config)
case OpPPC64MOVBload:
return rewriteValuePPC64_OpPPC64MOVBload(v, config)
case OpPPC64MOVBreg: case OpPPC64MOVBreg:
return rewriteValuePPC64_OpPPC64MOVBreg(v, config) return rewriteValuePPC64_OpPPC64MOVBreg(v, config)
case OpPPC64MOVBstore: case OpPPC64MOVBstore:
@ -408,6 +408,10 @@ func rewriteValuePPC64(v *Value, config *Config) bool {
return rewriteValuePPC64_OpPPC64MOVWstorezero(v, config) return rewriteValuePPC64_OpPPC64MOVWstorezero(v, config)
case OpPPC64NotEqual: case OpPPC64NotEqual:
return rewriteValuePPC64_OpPPC64NotEqual(v, config) return rewriteValuePPC64_OpPPC64NotEqual(v, config)
case OpPPC64XOR:
return rewriteValuePPC64_OpPPC64XOR(v, config)
case OpPPC64XORconst:
return rewriteValuePPC64_OpPPC64XORconst(v, config)
case OpRsh16Ux16: case OpRsh16Ux16:
return rewriteValuePPC64_OpRsh16Ux16(v, config) return rewriteValuePPC64_OpRsh16Ux16(v, config)
case OpRsh16Ux32: case OpRsh16Ux32:
@ -851,10 +855,10 @@ func rewriteValuePPC64_OpConst16(v *Value, config *Config) bool {
_ = b _ = b
// match: (Const16 [val]) // match: (Const16 [val])
// cond: // cond:
// result: (MOVWconst [val]) // result: (MOVDconst [val])
for { for {
val := v.AuxInt val := v.AuxInt
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = val v.AuxInt = val
return true return true
} }
@ -864,10 +868,10 @@ func rewriteValuePPC64_OpConst32(v *Value, config *Config) bool {
_ = b _ = b
// match: (Const32 [val]) // match: (Const32 [val])
// cond: // cond:
// result: (MOVWconst [val]) // result: (MOVDconst [val])
for { for {
val := v.AuxInt val := v.AuxInt
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = val v.AuxInt = val
return true return true
} }
@ -916,10 +920,10 @@ func rewriteValuePPC64_OpConst8(v *Value, config *Config) bool {
_ = b _ = b
// match: (Const8 [val]) // match: (Const8 [val])
// cond: // cond:
// result: (MOVWconst [val]) // result: (MOVDconst [val])
for { for {
val := v.AuxInt val := v.AuxInt
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = val v.AuxInt = val
return true return true
} }
@ -929,10 +933,10 @@ func rewriteValuePPC64_OpConstBool(v *Value, config *Config) bool {
_ = b _ = b
// match: (ConstBool [b]) // match: (ConstBool [b])
// cond: // cond:
// result: (MOVWconst [b]) // result: (MOVDconst [b])
for { for {
b := v.AuxInt b := v.AuxInt
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = b v.AuxInt = b
return true return true
} }
@ -2551,21 +2555,38 @@ func rewriteValuePPC64_OpLoad(v *Value, config *Config) bool {
return true return true
} }
// match: (Load <t> ptr mem) // match: (Load <t> ptr mem)
// cond: (t.IsBoolean() || (is8BitInt(t) && isSigned(t))) // cond: t.IsBoolean()
// result: (MOVBload ptr mem) // result: (MOVBZload ptr mem)
for { for {
t := v.Type t := v.Type
ptr := v.Args[0] ptr := v.Args[0]
mem := v.Args[1] mem := v.Args[1]
if !(t.IsBoolean() || (is8BitInt(t) && isSigned(t))) { if !(t.IsBoolean()) {
break break
} }
v.reset(OpPPC64MOVBload) v.reset(OpPPC64MOVBZload)
v.AddArg(ptr) v.AddArg(ptr)
v.AddArg(mem) v.AddArg(mem)
return true return true
} }
// match: (Load <t> ptr mem) // match: (Load <t> ptr mem)
// cond: is8BitInt(t) && isSigned(t)
// result: (MOVBreg (MOVBZload ptr mem))
for {
t := v.Type
ptr := v.Args[0]
mem := v.Args[1]
if !(is8BitInt(t) && isSigned(t)) {
break
}
v.reset(OpPPC64MOVBreg)
v0 := b.NewValue0(v.Line, OpPPC64MOVBZload, config.fe.TypeUInt8())
v0.AddArg(ptr)
v0.AddArg(mem)
v.AddArg(v0)
return true
}
// match: (Load <t> ptr mem)
// cond: is8BitInt(t) && !isSigned(t) // cond: is8BitInt(t) && !isSigned(t)
// result: (MOVBZload ptr mem) // result: (MOVBZload ptr mem)
for { for {
@ -4014,6 +4035,40 @@ func rewriteValuePPC64_OpPPC64ADD(v *Value, config *Config) bool {
v.AddArg(x) v.AddArg(x)
return true return true
} }
// match: (ADD (MOVDconst [0]) x)
// cond:
// result: x
for {
v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVDconst {
break
}
if v_0.AuxInt != 0 {
break
}
x := v.Args[1]
v.reset(OpCopy)
v.Type = x.Type
v.AddArg(x)
return true
}
// match: (ADD x (MOVDconst [0]))
// cond:
// result: x
for {
x := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpPPC64MOVDconst {
break
}
if v_1.AuxInt != 0 {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.AddArg(x)
return true
}
return false return false
} }
func rewriteValuePPC64_OpPPC64ADDconst(v *Value, config *Config) bool { func rewriteValuePPC64_OpPPC64ADDconst(v *Value, config *Config) bool {
@ -4038,6 +4093,48 @@ func rewriteValuePPC64_OpPPC64ADDconst(v *Value, config *Config) bool {
v.AddArg(x) v.AddArg(x)
return true return true
} }
// match: (ADDconst [0] x)
// cond:
// result: x
for {
if v.AuxInt != 0 {
break
}
x := v.Args[0]
v.reset(OpCopy)
v.Type = x.Type
v.AddArg(x)
return true
}
return false
}
func rewriteValuePPC64_OpPPC64ANDconst(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (ANDconst [-1] x)
// cond:
// result: x
for {
if v.AuxInt != -1 {
break
}
x := v.Args[0]
v.reset(OpCopy)
v.Type = x.Type
v.AddArg(x)
return true
}
// match: (ANDconst [0] _)
// cond:
// result: (MOVDconst [0])
for {
if v.AuxInt != 0 {
break
}
v.reset(OpPPC64MOVDconst)
v.AuxInt = 0
return true
}
return false return false
} }
func rewriteValuePPC64_OpPPC64CMPUconst(v *Value, config *Config) bool { func rewriteValuePPC64_OpPPC64CMPUconst(v *Value, config *Config) bool {
@ -4096,13 +4193,13 @@ func rewriteValuePPC64_OpPPC64CMPUconst(v *Value, config *Config) bool {
func rewriteValuePPC64_OpPPC64CMPWUconst(v *Value, config *Config) bool { func rewriteValuePPC64_OpPPC64CMPWUconst(v *Value, config *Config) bool {
b := v.Block b := v.Block
_ = b _ = b
// match: (CMPWUconst (MOVWconst [x]) [y]) // match: (CMPWUconst (MOVDconst [x]) [y])
// cond: int32(x)==int32(y) // cond: int32(x)==int32(y)
// result: (FlagEQ) // result: (FlagEQ)
for { for {
y := v.AuxInt y := v.AuxInt
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVWconst { if v_0.Op != OpPPC64MOVDconst {
break break
} }
x := v_0.AuxInt x := v_0.AuxInt
@ -4112,13 +4209,13 @@ func rewriteValuePPC64_OpPPC64CMPWUconst(v *Value, config *Config) bool {
v.reset(OpPPC64FlagEQ) v.reset(OpPPC64FlagEQ)
return true return true
} }
// match: (CMPWUconst (MOVWconst [x]) [y]) // match: (CMPWUconst (MOVDconst [x]) [y])
// cond: uint32(x)<uint32(y) // cond: uint32(x)<uint32(y)
// result: (FlagLT) // result: (FlagLT)
for { for {
y := v.AuxInt y := v.AuxInt
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVWconst { if v_0.Op != OpPPC64MOVDconst {
break break
} }
x := v_0.AuxInt x := v_0.AuxInt
@ -4128,13 +4225,13 @@ func rewriteValuePPC64_OpPPC64CMPWUconst(v *Value, config *Config) bool {
v.reset(OpPPC64FlagLT) v.reset(OpPPC64FlagLT)
return true return true
} }
// match: (CMPWUconst (MOVWconst [x]) [y]) // match: (CMPWUconst (MOVDconst [x]) [y])
// cond: uint32(x)>uint32(y) // cond: uint32(x)>uint32(y)
// result: (FlagGT) // result: (FlagGT)
for { for {
y := v.AuxInt y := v.AuxInt
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVWconst { if v_0.Op != OpPPC64MOVDconst {
break break
} }
x := v_0.AuxInt x := v_0.AuxInt
@ -4149,13 +4246,13 @@ func rewriteValuePPC64_OpPPC64CMPWUconst(v *Value, config *Config) bool {
func rewriteValuePPC64_OpPPC64CMPWconst(v *Value, config *Config) bool { func rewriteValuePPC64_OpPPC64CMPWconst(v *Value, config *Config) bool {
b := v.Block b := v.Block
_ = b _ = b
// match: (CMPWconst (MOVWconst [x]) [y]) // match: (CMPWconst (MOVDconst [x]) [y])
// cond: int32(x)==int32(y) // cond: int32(x)==int32(y)
// result: (FlagEQ) // result: (FlagEQ)
for { for {
y := v.AuxInt y := v.AuxInt
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVWconst { if v_0.Op != OpPPC64MOVDconst {
break break
} }
x := v_0.AuxInt x := v_0.AuxInt
@ -4165,13 +4262,13 @@ func rewriteValuePPC64_OpPPC64CMPWconst(v *Value, config *Config) bool {
v.reset(OpPPC64FlagEQ) v.reset(OpPPC64FlagEQ)
return true return true
} }
// match: (CMPWconst (MOVWconst [x]) [y]) // match: (CMPWconst (MOVDconst [x]) [y])
// cond: int32(x)<int32(y) // cond: int32(x)<int32(y)
// result: (FlagLT) // result: (FlagLT)
for { for {
y := v.AuxInt y := v.AuxInt
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVWconst { if v_0.Op != OpPPC64MOVDconst {
break break
} }
x := v_0.AuxInt x := v_0.AuxInt
@ -4181,13 +4278,13 @@ func rewriteValuePPC64_OpPPC64CMPWconst(v *Value, config *Config) bool {
v.reset(OpPPC64FlagLT) v.reset(OpPPC64FlagLT)
return true return true
} }
// match: (CMPWconst (MOVWconst [x]) [y]) // match: (CMPWconst (MOVDconst [x]) [y])
// cond: int32(x)>int32(y) // cond: int32(x)>int32(y)
// result: (FlagGT) // result: (FlagGT)
for { for {
y := v.AuxInt y := v.AuxInt
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVWconst { if v_0.Op != OpPPC64MOVDconst {
break break
} }
x := v_0.AuxInt x := v_0.AuxInt
@ -4257,37 +4354,37 @@ func rewriteValuePPC64_OpPPC64Equal(v *Value, config *Config) bool {
_ = b _ = b
// match: (Equal (FlagEQ)) // match: (Equal (FlagEQ))
// cond: // cond:
// result: (MOVWconst [1]) // result: (MOVDconst [1])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagEQ { if v_0.Op != OpPPC64FlagEQ {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
// match: (Equal (FlagLT)) // match: (Equal (FlagLT))
// cond: // cond:
// result: (MOVWconst [0]) // result: (MOVDconst [0])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagLT { if v_0.Op != OpPPC64FlagLT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 0 v.AuxInt = 0
return true return true
} }
// match: (Equal (FlagGT)) // match: (Equal (FlagGT))
// cond: // cond:
// result: (MOVWconst [0]) // result: (MOVDconst [0])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagGT { if v_0.Op != OpPPC64FlagGT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 0 v.AuxInt = 0
return true return true
} }
@ -4527,37 +4624,37 @@ func rewriteValuePPC64_OpPPC64GreaterEqual(v *Value, config *Config) bool {
_ = b _ = b
// match: (GreaterEqual (FlagEQ)) // match: (GreaterEqual (FlagEQ))
// cond: // cond:
// result: (MOVWconst [1]) // result: (MOVDconst [1])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagEQ { if v_0.Op != OpPPC64FlagEQ {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
// match: (GreaterEqual (FlagLT)) // match: (GreaterEqual (FlagLT))
// cond: // cond:
// result: (MOVWconst [0]) // result: (MOVDconst [0])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagLT { if v_0.Op != OpPPC64FlagLT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 0 v.AuxInt = 0
return true return true
} }
// match: (GreaterEqual (FlagGT)) // match: (GreaterEqual (FlagGT))
// cond: // cond:
// result: (MOVWconst [1]) // result: (MOVDconst [1])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagGT { if v_0.Op != OpPPC64FlagGT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
@ -4581,37 +4678,37 @@ func rewriteValuePPC64_OpPPC64GreaterThan(v *Value, config *Config) bool {
_ = b _ = b
// match: (GreaterThan (FlagEQ)) // match: (GreaterThan (FlagEQ))
// cond: // cond:
// result: (MOVWconst [0]) // result: (MOVDconst [0])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagEQ { if v_0.Op != OpPPC64FlagEQ {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 0 v.AuxInt = 0
return true return true
} }
// match: (GreaterThan (FlagLT)) // match: (GreaterThan (FlagLT))
// cond: // cond:
// result: (MOVWconst [0]) // result: (MOVDconst [0])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagLT { if v_0.Op != OpPPC64FlagLT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 0 v.AuxInt = 0
return true return true
} }
// match: (GreaterThan (FlagGT)) // match: (GreaterThan (FlagGT))
// cond: // cond:
// result: (MOVWconst [1]) // result: (MOVDconst [1])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagGT { if v_0.Op != OpPPC64FlagGT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
@ -4635,37 +4732,37 @@ func rewriteValuePPC64_OpPPC64LessEqual(v *Value, config *Config) bool {
_ = b _ = b
// match: (LessEqual (FlagEQ)) // match: (LessEqual (FlagEQ))
// cond: // cond:
// result: (MOVWconst [1]) // result: (MOVDconst [1])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagEQ { if v_0.Op != OpPPC64FlagEQ {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
// match: (LessEqual (FlagLT)) // match: (LessEqual (FlagLT))
// cond: // cond:
// result: (MOVWconst [1]) // result: (MOVDconst [1])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagLT { if v_0.Op != OpPPC64FlagLT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
// match: (LessEqual (FlagGT)) // match: (LessEqual (FlagGT))
// cond: // cond:
// result: (MOVWconst [0]) // result: (MOVDconst [0])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagGT { if v_0.Op != OpPPC64FlagGT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 0 v.AuxInt = 0
return true return true
} }
@ -4689,37 +4786,37 @@ func rewriteValuePPC64_OpPPC64LessThan(v *Value, config *Config) bool {
_ = b _ = b
// match: (LessThan (FlagEQ)) // match: (LessThan (FlagEQ))
// cond: // cond:
// result: (MOVWconst [0]) // result: (MOVDconst [0])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagEQ { if v_0.Op != OpPPC64FlagEQ {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 0 v.AuxInt = 0
return true return true
} }
// match: (LessThan (FlagLT)) // match: (LessThan (FlagLT))
// cond: // cond:
// result: (MOVWconst [1]) // result: (MOVDconst [1])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagLT { if v_0.Op != OpPPC64FlagLT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
// match: (LessThan (FlagGT)) // match: (LessThan (FlagGT))
// cond: // cond:
// result: (MOVWconst [0]) // result: (MOVDconst [0])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagGT { if v_0.Op != OpPPC64FlagGT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 0 v.AuxInt = 0
return true return true
} }
@ -4806,56 +4903,17 @@ func rewriteValuePPC64_OpPPC64MOVBZreg(v *Value, config *Config) bool {
v.AddArg(x) v.AddArg(x)
return true return true
} }
return false // match: (MOVBZreg (MOVDconst [c]))
} // cond:
func rewriteValuePPC64_OpPPC64MOVBload(v *Value, config *Config) bool { // result: (MOVDconst [int64(uint8(c))])
b := v.Block
_ = b
// match: (MOVBload [off1] {sym1} (MOVDaddr [off2] {sym2} ptr) mem)
// cond: canMergeSym(sym1,sym2)
// result: (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
for { for {
off1 := v.AuxInt
sym1 := v.Aux
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVDaddr { if v_0.Op != OpPPC64MOVDconst {
break break
} }
off2 := v_0.AuxInt c := v_0.AuxInt
sym2 := v_0.Aux v.reset(OpPPC64MOVDconst)
ptr := v_0.Args[0] v.AuxInt = int64(uint8(c))
mem := v.Args[1]
if !(canMergeSym(sym1, sym2)) {
break
}
v.reset(OpPPC64MOVBload)
v.AuxInt = off1 + off2
v.Aux = mergeSym(sym1, sym2)
v.AddArg(ptr)
v.AddArg(mem)
return true
}
// match: (MOVBload [off1] {sym} (ADDconst [off2] x) mem)
// cond: is16Bit(off1+off2)
// result: (MOVBload [off1+off2] {sym} x mem)
for {
off1 := v.AuxInt
sym := v.Aux
v_0 := v.Args[0]
if v_0.Op != OpPPC64ADDconst {
break
}
off2 := v_0.AuxInt
x := v_0.Args[0]
mem := v.Args[1]
if !(is16Bit(off1 + off2)) {
break
}
v.reset(OpPPC64MOVBload)
v.AuxInt = off1 + off2
v.Aux = sym
v.AddArg(x)
v.AddArg(mem)
return true return true
} }
return false return false
@ -4863,17 +4921,17 @@ func rewriteValuePPC64_OpPPC64MOVBload(v *Value, config *Config) bool {
func rewriteValuePPC64_OpPPC64MOVBreg(v *Value, config *Config) bool { func rewriteValuePPC64_OpPPC64MOVBreg(v *Value, config *Config) bool {
b := v.Block b := v.Block
_ = b _ = b
// match: (MOVBreg x:(MOVBload _ _)) // match: (MOVBreg (MOVDconst [c]))
// cond: // cond:
// result: x // result: (MOVDconst [int64(int8(c))])
for { for {
x := v.Args[0] v_0 := v.Args[0]
if x.Op != OpPPC64MOVBload { if v_0.Op != OpPPC64MOVDconst {
break break
} }
v.reset(OpCopy) c := v_0.AuxInt
v.Type = x.Type v.reset(OpPPC64MOVDconst)
v.AddArg(x) v.AuxInt = int64(int8(c))
return true return true
} }
return false return false
@ -4955,6 +5013,48 @@ func rewriteValuePPC64_OpPPC64MOVBstore(v *Value, config *Config) bool {
v.AddArg(mem) v.AddArg(mem)
return true return true
} }
// match: (MOVBstore [off] {sym} ptr (MOVBreg x) mem)
// cond:
// result: (MOVBstore [off] {sym} ptr x mem)
for {
off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpPPC64MOVBreg {
break
}
x := v_1.Args[0]
mem := v.Args[2]
v.reset(OpPPC64MOVBstore)
v.AuxInt = off
v.Aux = sym
v.AddArg(ptr)
v.AddArg(x)
v.AddArg(mem)
return true
}
// match: (MOVBstore [off] {sym} ptr (MOVBZreg x) mem)
// cond:
// result: (MOVBstore [off] {sym} ptr x mem)
for {
off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpPPC64MOVBZreg {
break
}
x := v_1.Args[0]
mem := v.Args[2]
v.reset(OpPPC64MOVBstore)
v.AuxInt = off
v.Aux = sym
v.AddArg(ptr)
v.AddArg(x)
v.AddArg(mem)
return true
}
return false return false
} }
func rewriteValuePPC64_OpPPC64MOVBstorezero(v *Value, config *Config) bool { func rewriteValuePPC64_OpPPC64MOVBstorezero(v *Value, config *Config) bool {
@ -5212,6 +5312,19 @@ func rewriteValuePPC64_OpPPC64MOVHZreg(v *Value, config *Config) bool {
v.AddArg(x) v.AddArg(x)
return true return true
} }
// match: (MOVHZreg (MOVDconst [c]))
// cond:
// result: (MOVDconst [int64(uint16(c))])
for {
v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVDconst {
break
}
c := v_0.AuxInt
v.reset(OpPPC64MOVDconst)
v.AuxInt = int64(uint16(c))
return true
}
return false return false
} }
func rewriteValuePPC64_OpPPC64MOVHload(v *Value, config *Config) bool { func rewriteValuePPC64_OpPPC64MOVHload(v *Value, config *Config) bool {
@ -5282,6 +5395,19 @@ func rewriteValuePPC64_OpPPC64MOVHreg(v *Value, config *Config) bool {
v.AddArg(x) v.AddArg(x)
return true return true
} }
// match: (MOVHreg (MOVDconst [c]))
// cond:
// result: (MOVDconst [int64(int16(c))])
for {
v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVDconst {
break
}
c := v_0.AuxInt
v.reset(OpPPC64MOVDconst)
v.AuxInt = int64(int16(c))
return true
}
return false return false
} }
func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool { func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool {
@ -5361,6 +5487,48 @@ func rewriteValuePPC64_OpPPC64MOVHstore(v *Value, config *Config) bool {
v.AddArg(mem) v.AddArg(mem)
return true return true
} }
// match: (MOVHstore [off] {sym} ptr (MOVHreg x) mem)
// cond:
// result: (MOVHstore [off] {sym} ptr x mem)
for {
off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpPPC64MOVHreg {
break
}
x := v_1.Args[0]
mem := v.Args[2]
v.reset(OpPPC64MOVHstore)
v.AuxInt = off
v.Aux = sym
v.AddArg(ptr)
v.AddArg(x)
v.AddArg(mem)
return true
}
// match: (MOVHstore [off] {sym} ptr (MOVHZreg x) mem)
// cond:
// result: (MOVHstore [off] {sym} ptr x mem)
for {
off := v.AuxInt
sym := v.Aux
ptr := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpPPC64MOVHZreg {
break
}
x := v_1.Args[0]
mem := v.Args[2]
v.reset(OpPPC64MOVHstore)
v.AuxInt = off
v.Aux = sym
v.AddArg(ptr)
v.AddArg(x)
v.AddArg(mem)
return true
}
return false return false
} }
func rewriteValuePPC64_OpPPC64MOVHstorezero(v *Value, config *Config) bool { func rewriteValuePPC64_OpPPC64MOVHstorezero(v *Value, config *Config) bool {
@ -5607,37 +5775,37 @@ func rewriteValuePPC64_OpPPC64NotEqual(v *Value, config *Config) bool {
_ = b _ = b
// match: (NotEqual (FlagEQ)) // match: (NotEqual (FlagEQ))
// cond: // cond:
// result: (MOVWconst [0]) // result: (MOVDconst [0])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagEQ { if v_0.Op != OpPPC64FlagEQ {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 0 v.AuxInt = 0
return true return true
} }
// match: (NotEqual (FlagLT)) // match: (NotEqual (FlagLT))
// cond: // cond:
// result: (MOVWconst [1]) // result: (MOVDconst [1])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagLT { if v_0.Op != OpPPC64FlagLT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
// match: (NotEqual (FlagGT)) // match: (NotEqual (FlagGT))
// cond: // cond:
// result: (MOVWconst [1]) // result: (MOVDconst [1])
for { for {
v_0 := v.Args[0] v_0 := v.Args[0]
if v_0.Op != OpPPC64FlagGT { if v_0.Op != OpPPC64FlagGT {
break break
} }
v.reset(OpPPC64MOVWconst) v.reset(OpPPC64MOVDconst)
v.AuxInt = 1 v.AuxInt = 1
return true return true
} }
@ -5656,6 +5824,63 @@ func rewriteValuePPC64_OpPPC64NotEqual(v *Value, config *Config) bool {
} }
return false return false
} }
func rewriteValuePPC64_OpPPC64XOR(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (XOR (MOVDconst [0]) x)
// cond:
// result: x
for {
v_0 := v.Args[0]
if v_0.Op != OpPPC64MOVDconst {
break
}
if v_0.AuxInt != 0 {
break
}
x := v.Args[1]
v.reset(OpCopy)
v.Type = x.Type
v.AddArg(x)
return true
}
// match: (XOR x (MOVDconst [0]))
// cond:
// result: x
for {
x := v.Args[0]
v_1 := v.Args[1]
if v_1.Op != OpPPC64MOVDconst {
break
}
if v_1.AuxInt != 0 {
break
}
v.reset(OpCopy)
v.Type = x.Type
v.AddArg(x)
return true
}
return false
}
func rewriteValuePPC64_OpPPC64XORconst(v *Value, config *Config) bool {
b := v.Block
_ = b
// match: (XORconst [0] x)
// cond:
// result: x
for {
if v.AuxInt != 0 {
break
}
x := v.Args[0]
v.reset(OpCopy)
v.Type = x.Type
v.AddArg(x)
return true
}
return false
}
func rewriteValuePPC64_OpRsh16Ux16(v *Value, config *Config) bool { func rewriteValuePPC64_OpRsh16Ux16(v *Value, config *Config) bool {
b := v.Block b := v.Block
_ = b _ = b

View File

@ -219,7 +219,7 @@ const (
C_COND_LT = iota // 0 result is negative C_COND_LT = iota // 0 result is negative
C_COND_GT // 1 result is positive C_COND_GT // 1 result is positive
C_COND_EQ // 2 result is zero C_COND_EQ // 2 result is zero
C_COND_SO // 3 summary overflow C_COND_SO // 3 summary overflow or FP compare w/ NaN
) )
const ( const (
@ -300,8 +300,8 @@ const (
ABLE // not GT = L/E/U ABLE // not GT = L/E/U
ABLT ABLT
ABNE // not EQ = L/G/U ABNE // not EQ = L/G/U
ABVC // apparently Unordered-clear ABVC // Unordered-clear
ABVS // apparently Unordered-set ABVS // Unordered-set
ACMP ACMP
ACMPU ACMPU
ACNTLZW ACNTLZW