Commit d43f2e37 authored by Keith Randall's avatar Keith Randall

[dev.ssa] cmd/compile: introduce storeconst ops

Introduce opcodes that store a constant value.
AuxInt now needs to hold both the value to be stored and the
constant offset at which to store it.  Introduce a StoreConst
type to help encode/decode these parts to/from an AuxInt.

Change-Id: I1631883abe035cff4b16368683e1eb3d2ccb674d
Reviewed-on: https://go-review.googlesource.com/16170Reviewed-by: default avatarJosh Bleecher Snyder <josharian@gmail.com>
parent cd01c0be
...@@ -3747,6 +3747,24 @@ func (s *genState) genValue(v *ssa.Value) { ...@@ -3747,6 +3747,24 @@ func (s *genState) genValue(v *ssa.Value) {
p.To.Scale = 4 p.To.Scale = 4
p.To.Index = regnum(v.Args[1]) p.To.Index = regnum(v.Args[1])
addAux(&p.To, v) addAux(&p.To, v)
case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
p := Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST
sc := ssa.StoreConst(v.AuxInt)
i := sc.Val()
switch v.Op {
case ssa.OpAMD64MOVBstoreconst:
i = int64(int8(i))
case ssa.OpAMD64MOVWstoreconst:
i = int64(int16(i))
case ssa.OpAMD64MOVLstoreconst:
i = int64(int32(i))
case ssa.OpAMD64MOVQstoreconst:
}
p.From.Offset = i
p.To.Type = obj.TYPE_MEM
p.To.Reg = regnum(v.Args[0])
addAux2(&p.To, v, sc.Off())
case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX, case ssa.OpAMD64MOVLQSX, ssa.OpAMD64MOVWQSX, ssa.OpAMD64MOVBQSX, ssa.OpAMD64MOVLQZX, ssa.OpAMD64MOVWQZX, ssa.OpAMD64MOVBQZX,
ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD, ssa.OpAMD64CVTSL2SS, ssa.OpAMD64CVTSL2SD, ssa.OpAMD64CVTSQ2SS, ssa.OpAMD64CVTSQ2SD,
ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ, ssa.OpAMD64CVTTSS2SL, ssa.OpAMD64CVTTSD2SL, ssa.OpAMD64CVTTSS2SQ, ssa.OpAMD64CVTTSD2SQ,
...@@ -3990,6 +4008,11 @@ func (s *genState) genValue(v *ssa.Value) { ...@@ -3990,6 +4008,11 @@ func (s *genState) genValue(v *ssa.Value) {
if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage { if w.Args[0] == v.Args[0] && w.Aux == nil && w.AuxInt >= 0 && w.AuxInt < minZeroPage {
return return
} }
case ssa.OpAMD64MOVQstoreconst, ssa.OpAMD64MOVLstoreconst, ssa.OpAMD64MOVWstoreconst, ssa.OpAMD64MOVBstoreconst:
off := ssa.StoreConst(v.AuxInt).Off()
if w.Args[0] == v.Args[0] && w.Aux == nil && off >= 0 && off < minZeroPage {
return
}
} }
if w.Type.IsMemory() { if w.Type.IsMemory() {
// We can't delay the nil check past the next store. // We can't delay the nil check past the next store.
...@@ -4202,11 +4225,14 @@ func (s *genState) deferReturn() { ...@@ -4202,11 +4225,14 @@ func (s *genState) deferReturn() {
// addAux adds the offset in the aux fields (AuxInt and Aux) of v to a. // addAux adds the offset in the aux fields (AuxInt and Aux) of v to a.
func addAux(a *obj.Addr, v *ssa.Value) { func addAux(a *obj.Addr, v *ssa.Value) {
addAux2(a, v, v.AuxInt)
}
func addAux2(a *obj.Addr, v *ssa.Value, offset int64) {
if a.Type != obj.TYPE_MEM { if a.Type != obj.TYPE_MEM {
v.Fatalf("bad addAux addr %s", a) v.Fatalf("bad addAux addr %s", a)
} }
// add integer offset // add integer offset
a.Offset += v.AuxInt a.Offset += offset
// If no additional symbol offset, we're done. // If no additional symbol offset, we're done.
if v.Aux == nil { if v.Aux == nil {
......
...@@ -557,6 +557,26 @@ ...@@ -557,6 +557,26 @@
(MOVSDstore [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVSDstore [addOff(off1, off2)] {sym} ptr val mem) (MOVSDstore [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVSDstore [addOff(off1, off2)] {sym} ptr val mem)
(MOVOstore [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVOstore [addOff(off1, off2)] {sym} ptr val mem) (MOVOstore [off1] {sym} (ADDQconst [off2] ptr) val mem) -> (MOVOstore [addOff(off1, off2)] {sym} ptr val mem)
// Fold constants into stores.
(MOVQstore [off] {sym} ptr (MOVQconst [c]) mem) && validStoreConst(c,off) ->
(MOVQstoreconst [makeStoreConst(c,off)] {sym} ptr mem)
(MOVLstore [off] {sym} ptr (MOVLconst [c]) mem) && validStoreConstOff(off) ->
(MOVLstoreconst [makeStoreConst(int64(int32(c)),off)] {sym} ptr mem)
(MOVWstore [off] {sym} ptr (MOVWconst [c]) mem) && validStoreConstOff(off) ->
(MOVWstoreconst [makeStoreConst(int64(int16(c)),off)] {sym} ptr mem)
(MOVBstore [off] {sym} ptr (MOVBconst [c]) mem) && validStoreConstOff(off) ->
(MOVBstoreconst [makeStoreConst(int64(int8(c)),off)] {sym} ptr mem)
// Fold address offsets into constant stores.
(MOVQstoreconst [sc] {s} (ADDQconst [off] ptr) mem) && StoreConst(sc).canAdd(off) ->
(MOVQstoreconst [StoreConst(sc).add(off)] {s} ptr mem)
(MOVLstoreconst [sc] {s} (ADDQconst [off] ptr) mem) && StoreConst(sc).canAdd(off) ->
(MOVLstoreconst [StoreConst(sc).add(off)] {s} ptr mem)
(MOVWstoreconst [sc] {s} (ADDQconst [off] ptr) mem) && StoreConst(sc).canAdd(off) ->
(MOVWstoreconst [StoreConst(sc).add(off)] {s} ptr mem)
(MOVBstoreconst [sc] {s} (ADDQconst [off] ptr) mem) && StoreConst(sc).canAdd(off) ->
(MOVBstoreconst [StoreConst(sc).add(off)] {s} ptr mem)
// We need to fold LEAQ into the MOVx ops so that the live variable analysis knows // We need to fold LEAQ into the MOVx ops so that the live variable analysis knows
// what variables are being read/written by the ops. // what variables are being read/written by the ops.
(MOVQload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) -> (MOVQload [off1] {sym1} (LEAQ [off2] {sym2} base) mem) && canMergeSym(sym1, sym2) ->
...@@ -589,6 +609,15 @@ ...@@ -589,6 +609,15 @@
(MOVOstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) -> (MOVOstore [off1] {sym1} (LEAQ [off2] {sym2} base) val mem) && canMergeSym(sym1, sym2) ->
(MOVOstore [addOff(off1,off2)] {mergeSym(sym1,sym2)} base val mem) (MOVOstore [addOff(off1,off2)] {mergeSym(sym1,sym2)} base val mem)
(MOVQstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && StoreConst(sc).canAdd(off) ->
(MOVQstoreconst [StoreConst(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
(MOVLstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && StoreConst(sc).canAdd(off) ->
(MOVLstoreconst [StoreConst(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
(MOVWstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && StoreConst(sc).canAdd(off) ->
(MOVWstoreconst [StoreConst(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
(MOVBstoreconst [sc] {sym1} (LEAQ [off] {sym2} ptr) mem) && canMergeSym(sym1, sym2) && StoreConst(sc).canAdd(off) ->
(MOVBstoreconst [StoreConst(sc).add(off)] {mergeSym(sym1, sym2)} ptr mem)
// indexed loads and stores // indexed loads and stores
(MOVQloadidx8 [off1] {sym} (ADDQconst [off2] ptr) idx mem) -> (MOVQloadidx8 [addOff(off1, off2)] {sym} ptr idx mem) (MOVQloadidx8 [off1] {sym} (ADDQconst [off2] ptr) idx mem) -> (MOVQloadidx8 [addOff(off1, off2)] {sym} ptr idx mem)
(MOVQstoreidx8 [off1] {sym} (ADDQconst [off2] ptr) idx val mem) -> (MOVQstoreidx8 [addOff(off1, off2)] {sym} ptr idx val mem) (MOVQstoreidx8 [off1] {sym} (ADDQconst [off2] ptr) idx val mem) -> (MOVQstoreidx8 [addOff(off1, off2)] {sym} ptr idx val mem)
...@@ -616,42 +645,42 @@ ...@@ -616,42 +645,42 @@
// lower Zero instructions with word sizes // lower Zero instructions with word sizes
(Zero [0] _ mem) -> mem (Zero [0] _ mem) -> mem
(Zero [1] destptr mem) -> (MOVBstore destptr (MOVBconst [0]) mem) (Zero [1] destptr mem) -> (MOVBstoreconst [0] destptr mem)
(Zero [2] destptr mem) -> (MOVWstore destptr (MOVWconst [0]) mem) (Zero [2] destptr mem) -> (MOVWstoreconst [0] destptr mem)
(Zero [4] destptr mem) -> (MOVLstore destptr (MOVLconst [0]) mem) (Zero [4] destptr mem) -> (MOVLstoreconst [0] destptr mem)
(Zero [8] destptr mem) -> (MOVQstore destptr (MOVQconst [0]) mem) (Zero [8] destptr mem) -> (MOVQstoreconst [0] destptr mem)
(Zero [3] destptr mem) -> (Zero [3] destptr mem) ->
(MOVBstore (ADDQconst [2] destptr) (MOVBconst [0]) (MOVBstoreconst [makeStoreConst(0,2)] destptr
(MOVWstore destptr (MOVWconst [0]) mem)) (MOVWstoreconst [0] destptr mem))
(Zero [5] destptr mem) -> (Zero [5] destptr mem) ->
(MOVBstore (ADDQconst [4] destptr) (MOVBconst [0]) (MOVBstoreconst [makeStoreConst(0,4)] destptr
(MOVLstore destptr (MOVLconst [0]) mem)) (MOVLstoreconst [0] destptr mem))
(Zero [6] destptr mem) -> (Zero [6] destptr mem) ->
(MOVWstore (ADDQconst [4] destptr) (MOVWconst [0]) (MOVWstoreconst [makeStoreConst(0,4)] destptr
(MOVLstore destptr (MOVLconst [0]) mem)) (MOVLstoreconst [0] destptr mem))
(Zero [7] destptr mem) -> (Zero [7] destptr mem) ->
(MOVLstore (ADDQconst [3] destptr) (MOVLconst [0]) (MOVLstoreconst [makeStoreConst(0,3)] destptr
(MOVLstore destptr (MOVLconst [0]) mem)) (MOVLstoreconst [0] destptr mem))
// Strip off any fractional word zeroing. // Strip off any fractional word zeroing.
(Zero [size] destptr mem) && size%8 != 0 && size > 8 -> (Zero [size] destptr mem) && size%8 != 0 && size > 8 ->
(Zero [size-size%8] (ADDQconst destptr [size%8]) (Zero [size-size%8] (ADDQconst destptr [size%8])
(MOVQstore destptr (MOVQconst [0]) mem)) (MOVQstoreconst [0] destptr mem))
// Zero small numbers of words directly. // Zero small numbers of words directly.
(Zero [16] destptr mem) -> (Zero [16] destptr mem) ->
(MOVQstore (ADDQconst [8] destptr) (MOVQconst [0]) (MOVQstoreconst [makeStoreConst(0,8)] destptr
(MOVQstore destptr (MOVQconst [0]) mem)) (MOVQstoreconst [0] destptr mem))
(Zero [24] destptr mem) -> (Zero [24] destptr mem) ->
(MOVQstore (ADDQconst [16] destptr) (MOVQconst [0]) (MOVQstoreconst [makeStoreConst(0,16)] destptr
(MOVQstore (ADDQconst [8] destptr) (MOVQconst [0]) (MOVQstoreconst [makeStoreConst(0,8)] destptr
(MOVQstore destptr (MOVQconst [0]) mem))) (MOVQstoreconst [0] destptr mem)))
(Zero [32] destptr mem) -> (Zero [32] destptr mem) ->
(MOVQstore (ADDQconst [24] destptr) (MOVQconst [0]) (MOVQstoreconst [makeStoreConst(0,24)] destptr
(MOVQstore (ADDQconst [16] destptr) (MOVQconst [0]) (MOVQstoreconst [makeStoreConst(0,16)] destptr
(MOVQstore (ADDQconst [8] destptr) (MOVQconst [0]) (MOVQstoreconst [makeStoreConst(0,8)] destptr
(MOVQstore destptr (MOVQconst [0]) mem)))) (MOVQstoreconst [0] destptr mem))))
// Medium zeroing uses a duff device. // Medium zeroing uses a duff device.
(Zero [size] destptr mem) && size <= 1024 && size%8 == 0 && size%16 != 0 -> (Zero [size] destptr mem) && size <= 1024 && size%8 == 0 && size%16 != 0 ->
......
...@@ -116,8 +116,9 @@ func init() { ...@@ -116,8 +116,9 @@ func init() {
gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly} gpload = regInfo{inputs: []regMask{gpspsb, 0}, outputs: gponly}
gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly} gploadidx = regInfo{inputs: []regMask{gpspsb, gpsp, 0}, outputs: gponly}
gpstore = regInfo{inputs: []regMask{gpspsb, gpsp, 0}} gpstore = regInfo{inputs: []regMask{gpspsb, gpsp, 0}}
gpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, gpsp, 0}} gpstoreconst = regInfo{inputs: []regMask{gpspsb, 0}}
gpstoreidx = regInfo{inputs: []regMask{gpspsb, gpsp, gpsp, 0}}
fp01 = regInfo{inputs: []regMask{}, outputs: fponly} fp01 = regInfo{inputs: []regMask{}, outputs: fponly}
fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly} fp21 = regInfo{inputs: []regMask{fp, fp}, outputs: fponly}
...@@ -382,6 +383,14 @@ func init() { ...@@ -382,6 +383,14 @@ func init() {
{name: "MOVOload", reg: fpload, asm: "MOVUPS", typ: "Int128"}, // load 16 bytes from arg0+auxint+aux. arg1=mem {name: "MOVOload", reg: fpload, asm: "MOVUPS", typ: "Int128"}, // load 16 bytes from arg0+auxint+aux. arg1=mem
{name: "MOVOstore", reg: fpstore, asm: "MOVUPS", typ: "Mem"}, // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem {name: "MOVOstore", reg: fpstore, asm: "MOVUPS", typ: "Mem"}, // store 16 bytes in arg1 to arg0+auxint+aux. arg2=mem
// For storeconst ops, the AuxInt field encodes both
// the value to store and an address offset of the store.
// Cast AuxInt to a StoreConst to extract Val and Off fields.
{name: "MOVBstoreconst", reg: gpstoreconst, asm: "MOVB", typ: "Mem"}, // store low byte of StoreConst(AuxInt).Val() to arg0+StoreConst(AuxInt).Off()+aux. arg1=mem
{name: "MOVWstoreconst", reg: gpstoreconst, asm: "MOVW", typ: "Mem"}, // store low 2 bytes of ...
{name: "MOVLstoreconst", reg: gpstoreconst, asm: "MOVL", typ: "Mem"}, // store low 4 bytes of ...
{name: "MOVQstoreconst", reg: gpstoreconst, asm: "MOVQ", typ: "Mem"}, // store 8 bytes of ...
// arg0 = (duff-adjusted) pointer to start of memory to zero // arg0 = (duff-adjusted) pointer to start of memory to zero
// arg1 = value to store (will always be zero) // arg1 = value to store (will always be zero)
// arg2 = mem // arg2 = mem
......
...@@ -29,3 +29,58 @@ type regInfo struct { ...@@ -29,3 +29,58 @@ type regInfo struct {
clobbers regMask clobbers regMask
outputs []regMask // NOTE: values can only have 1 output for now. outputs []regMask // NOTE: values can only have 1 output for now.
} }
// A StoreConst is used by the MOVXstoreconst opcodes. It holds
// both the value to store and an offset from the store pointer.
// A StoreConst is intended to be encoded into an AuxInt field.
// The zero StoreConst encodes a value of 0 and an offset of 0.
// The high 32 bits hold a value to be stored.
// The low 32 bits hold a pointer offset.
type StoreConst int64
func (sc StoreConst) Val() int64 {
return int64(sc) >> 32
}
func (sc StoreConst) Off() int64 {
return int64(int32(sc))
}
func (sc StoreConst) Int64() int64 {
return int64(sc)
}
// validStoreConstOff reports whether the offset can be used
// as an argument to makeStoreConst.
func validStoreConstOff(off int64) bool {
return off == int64(int32(off))
}
// validStoreConst reports whether we can fit the value and offset into
// a StoreConst value.
func validStoreConst(val, off int64) bool {
if val != int64(int32(val)) {
return false
}
if !validStoreConstOff(off) {
return false
}
return true
}
// encode encodes a StoreConst into an int64 suitable for storing in an AuxInt field.
func makeStoreConst(val, off int64) int64 {
if !validStoreConst(val, off) {
panic("invalid makeStoreConst")
}
return StoreConst(val<<32 + int64(uint32(off))).Int64()
}
func (sc StoreConst) canAdd(off int64) bool {
newoff := sc.Off() + off
return newoff == int64(int32(newoff))
}
func (sc StoreConst) add(off int64) int64 {
if !sc.canAdd(off) {
panic("invalid StoreConst.add")
}
return makeStoreConst(sc.Val(), sc.Off()+off)
}
...@@ -264,6 +264,10 @@ const ( ...@@ -264,6 +264,10 @@ const (
OpAMD64MOVQstoreidx8 OpAMD64MOVQstoreidx8
OpAMD64MOVOload OpAMD64MOVOload
OpAMD64MOVOstore OpAMD64MOVOstore
OpAMD64MOVBstoreconst
OpAMD64MOVWstoreconst
OpAMD64MOVLstoreconst
OpAMD64MOVQstoreconst
OpAMD64DUFFZERO OpAMD64DUFFZERO
OpAMD64MOVOconst OpAMD64MOVOconst
OpAMD64REPSTOSQ OpAMD64REPSTOSQ
...@@ -3064,6 +3068,42 @@ var opcodeTable = [...]opInfo{ ...@@ -3064,6 +3068,42 @@ var opcodeTable = [...]opInfo{
}, },
}, },
}, },
{
name: "MOVBstoreconst",
asm: x86.AMOVB,
reg: regInfo{
inputs: []inputInfo{
{0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB
},
},
},
{
name: "MOVWstoreconst",
asm: x86.AMOVW,
reg: regInfo{
inputs: []inputInfo{
{0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB
},
},
},
{
name: "MOVLstoreconst",
asm: x86.AMOVL,
reg: regInfo{
inputs: []inputInfo{
{0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB
},
},
},
{
name: "MOVQstoreconst",
asm: x86.AMOVQ,
reg: regInfo{
inputs: []inputInfo{
{0, 4295032831}, // .AX .CX .DX .BX .SP .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 .SB
},
},
},
{ {
name: "DUFFZERO", name: "DUFFZERO",
reg: regInfo{ reg: regInfo{
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment