Commit c40dcff2 authored by Cherry Zhang's avatar Cherry Zhang

[dev.ssa] cmd/compile: use MOVWaddr for address on ARM

Introduce an op MOVWaddr for addresses on ARM, instead of overuse
ADDconst.

Mark MOVWaddr as rematerializable. This fixes a liveness problem: if
it were not rematerializable, the address of a variable may be spilled
and later use of the address may just load the spilled value without
mentioning the variable, and the liveness code may think it is dead
prematurely.

Update #15365.

Change-Id: Ib0b0fa826bdb75c9e6bb362b95c6cf132cc6b1c0
Reviewed-on: https://go-review.googlesource.com/23942Reviewed-by: default avatarDavid Chase <drchase@google.com>
parent e3a6d008
...@@ -295,37 +295,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -295,37 +295,8 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.Reg = r1 p.Reg = r1
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = r p.To.Reg = r
case ssa.OpARMADDconst: case ssa.OpARMADDconst,
if v.Aux != nil { ssa.OpARMSUBconst,
switch v.Aux.(type) {
default:
v.Fatalf("aux is of unknown type %T", v.Aux)
case *ssa.ExternSymbol:
reg := v.Args[0].Block.Func.RegAlloc[v.Args[0].ID].(*ssa.Register)
if reg.Name() != "SB" {
v.Fatalf("extern symbol with non-SB base register %s", reg.Name())
}
case *ssa.ArgSymbol,
*ssa.AutoSymbol:
reg := v.Args[0].Block.Func.RegAlloc[v.Args[0].ID].(*ssa.Register)
if reg.Name() != "SP" {
v.Fatalf("arg/auto symbol with non-SP base register %s", reg.Name())
}
}
// MOVW $sym+off(base), R
// the assembler expands it as the following:
// - base is SP: add constant offset to SP (R13)
// when constant is large, tmp register (R11) may be used
// - base is SB: load external address from constant pool (use relocation)
p := gc.Prog(arm.AMOVW)
p.From.Type = obj.TYPE_ADDR
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
break
}
fallthrough
case ssa.OpARMSUBconst,
ssa.OpARMRSBconst, ssa.OpARMRSBconst,
ssa.OpARMANDconst, ssa.OpARMANDconst,
ssa.OpARMORconst, ssa.OpARMORconst,
...@@ -407,6 +378,46 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -407,6 +378,46 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt p.From.Offset = v.AuxInt
p.Reg = gc.SSARegNum(v.Args[0]) p.Reg = gc.SSARegNum(v.Args[0])
case ssa.OpARMMOVWaddr:
if v.Aux == nil {
// MOVW $off(SP), R
reg := v.Args[0].Block.Func.RegAlloc[v.Args[0].ID].(*ssa.Register)
if reg.Name() != "SP" {
v.Fatalf("arg/auto symbol with non-SP base register %s", reg.Name())
}
p := gc.Prog(arm.AMOVW)
p.From.Type = obj.TYPE_ADDR
p.From.Reg = arm.REGSP
p.From.Offset = v.AuxInt
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
break
}
// MOVW $sym+off(base), R
// the assembler expands it as the following:
// - base is SP: add constant offset to SP (R13)
// when constant is large, tmp register (R11) may be used
// - base is SB: load external address from constant pool (use relocation)
switch v.Aux.(type) {
default:
v.Fatalf("aux is of unknown type %T", v.Aux)
case *ssa.ExternSymbol:
reg := v.Args[0].Block.Func.RegAlloc[v.Args[0].ID].(*ssa.Register)
if reg.Name() != "SB" {
v.Fatalf("extern symbol with non-SB base register %s", reg.Name())
}
case *ssa.ArgSymbol,
*ssa.AutoSymbol:
reg := v.Args[0].Block.Func.RegAlloc[v.Args[0].ID].(*ssa.Register)
if reg.Name() != "SP" {
v.Fatalf("arg/auto symbol with non-SP base register %s", reg.Name())
}
}
p := gc.Prog(arm.AMOVW)
p.From.Type = obj.TYPE_ADDR
gc.AddAux(&p.From, v)
p.To.Type = obj.TYPE_REG
p.To.Reg = gc.SSARegNum(v)
case ssa.OpARMMOVBload, case ssa.OpARMMOVBload,
ssa.OpARMMOVBUload, ssa.OpARMMOVBUload,
ssa.OpARMMOVHload, ssa.OpARMMOVHload,
......
...@@ -246,9 +246,10 @@ ...@@ -246,9 +246,10 @@
(Geq16U x y) -> (GreaterEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y))) (Geq16U x y) -> (GreaterEqualU (CMP (ZeroExt16to32 x) (ZeroExt16to32 y)))
(Geq32U x y) -> (GreaterEqualU (CMP x y)) (Geq32U x y) -> (GreaterEqualU (CMP x y))
(OffPtr [off] ptr) -> (ADD (MOVWconst <config.Frontend().TypeInt32()> [off]) ptr) (OffPtr [off] ptr:(SP)) -> (MOVWaddr [off] ptr)
(OffPtr [off] ptr) -> (ADDconst [off] ptr)
(Addr {sym} base) -> (ADDconst {sym} base) (Addr {sym} base) -> (MOVWaddr {sym} base)
// loads // loads
(Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem) (Load <t> ptr mem) && t.IsBoolean() -> (MOVBUload ptr mem)
...@@ -369,31 +370,47 @@ ...@@ -369,31 +370,47 @@
(ADD (MOVWconst [c]) x) -> (ADDconst [c] x) (ADD (MOVWconst [c]) x) -> (ADDconst [c] x)
(ADD x (MOVWconst [c])) -> (ADDconst [c] x) (ADD x (MOVWconst [c])) -> (ADDconst [c] x)
(MOVBload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) -> (ADDconst [off1] (MOVWaddr [off2] {sym} ptr)) -> (MOVWaddr [off1+off2] {sym} ptr)
(MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVBUload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) -> (MOVBload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBload [off1+off2] {sym} ptr mem)
(MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVBUload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVBUload [off1+off2] {sym} ptr mem)
(MOVHload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) -> (MOVHload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVHload [off1+off2] {sym} ptr mem)
(MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVHUload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVHUload [off1+off2] {sym} ptr mem)
(MOVHUload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) -> (MOVWload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVWload [off1+off2] {sym} ptr mem)
(MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVFload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVFload [off1+off2] {sym} ptr mem)
(MOVWload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) -> (MOVDload [off1] {sym} (ADDconst [off2] ptr) mem) -> (MOVDload [off1+off2] {sym} ptr mem)
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVFload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) -> (MOVBstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVBstore [off1+off2] {sym} ptr val mem)
(MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVHstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVHstore [off1+off2] {sym} ptr val mem)
(MOVDload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) -> (MOVWstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVWstore [off1+off2] {sym} ptr val mem)
(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem) (MOVFstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVFstore [off1+off2] {sym} ptr val mem)
(MOVDstore [off1] {sym} (ADDconst [off2] ptr) val mem) -> (MOVDstore [off1+off2] {sym} ptr val mem)
(MOVBstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVBload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVHstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) -> (MOVBload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVBUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVWstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) -> (MOVBUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVHload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVFstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) -> (MOVHload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVHUload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVDstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) -> (MOVHUload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem) (MOVWload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVFload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVFload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVDload [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
(MOVDload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
(MOVBstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(MOVBstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(MOVHstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(MOVHstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(MOVWstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(MOVFstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(MOVFstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(MOVDstore [off1] {sym1} (MOVWaddr [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
(MOVDstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
(ADD (MUL x y) a) -> (MULA x y a) (ADD (MUL x y) a) -> (MULA x y a)
(ADD a (MUL x y)) -> (MULA x y a) (ADD a (MUL x y)) -> (MULA x y a)
...@@ -99,7 +99,7 @@ func init() { ...@@ -99,7 +99,7 @@ func init() {
var ( var (
gp01 = regInfo{inputs: []regMask{}, outputs: []regMask{gp}} gp01 = regInfo{inputs: []regMask{}, outputs: []regMask{gp}}
gp11 = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}} gp11 = regInfo{inputs: []regMask{gp}, outputs: []regMask{gp}}
gp11sb = regInfo{inputs: []regMask{gpspsb}, outputs: []regMask{gp}} gp11sp = regInfo{inputs: []regMask{gpsp}, outputs: []regMask{gp}}
gp1flags = regInfo{inputs: []regMask{gp}, outputs: []regMask{flags}} gp1flags = regInfo{inputs: []regMask{gp}, outputs: []regMask{flags}}
gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}} gp21 = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}}
gp21cf = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}, clobbers: flags} // cf: clobbers flags gp21cf = regInfo{inputs: []regMask{gp, gp}, outputs: []regMask{gp}, clobbers: flags} // cf: clobbers flags
...@@ -121,7 +121,7 @@ func init() { ...@@ -121,7 +121,7 @@ func init() {
ops := []opData{ ops := []opData{
// binary ops // binary ops
{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1 {name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1
{name: "ADDconst", argLength: 1, reg: gp11sb, asm: "ADD", aux: "SymOff"}, // arg0 + auxInt + aux.(*gc.Sym) {name: "ADDconst", argLength: 1, reg: gp11sp, asm: "ADD", aux: "Int32"}, // arg0 + auxInt
{name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0 - arg1 {name: "SUB", argLength: 2, reg: gp21, asm: "SUB"}, // arg0 - arg1
{name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int32"}, // arg0 - auxInt {name: "SUBconst", argLength: 1, reg: gp11, asm: "SUB", aux: "Int32"}, // arg0 - auxInt
{name: "RSB", argLength: 2, reg: gp21, asm: "RSB"}, // arg1 - arg0 {name: "RSB", argLength: 2, reg: gp21, asm: "RSB"}, // arg1 - arg0
...@@ -189,6 +189,8 @@ func init() { ...@@ -189,6 +189,8 @@ func init() {
{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: "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 {name: "MOVDconst", argLength: 0, reg: fp01, aux: "Float64", asm: "MOVD", typ: "Float64", rematerializeable: true}, // auxint as 64-bit float
{name: "MOVWaddr", argLength: 1, reg: regInfo{inputs: []regMask{buildReg("SP") | buildReg("SB")}, outputs: []regMask{gp}}, aux: "SymOff", asm: "MOVW", rematerializeable: true}, // arg0 + auxInt + aux.(*gc.Sym), arg0=SP/SB
{name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8"}, // load from arg0 + auxInt + aux. arg1=mem. {name: "MOVBload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVB", typ: "Int8"}, // load from arg0 + auxInt + aux. arg1=mem.
{name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8"}, // load from arg0 + auxInt + aux. arg1=mem. {name: "MOVBUload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVBU", typ: "UInt8"}, // load from arg0 + auxInt + aux. arg1=mem.
{name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16"}, // load from arg0 + auxInt + aux. arg1=mem. {name: "MOVHload", argLength: 2, reg: gpload, aux: "SymOff", asm: "MOVH", typ: "Int16"}, // load from arg0 + auxInt + aux. arg1=mem.
......
...@@ -380,6 +380,7 @@ const ( ...@@ -380,6 +380,7 @@ const (
OpARMMOVWconst OpARMMOVWconst
OpARMMOVFconst OpARMMOVFconst
OpARMMOVDconst OpARMMOVDconst
OpARMMOVWaddr
OpARMMOVBload OpARMMOVBload
OpARMMOVBUload OpARMMOVBUload
OpARMMOVHload OpARMMOVHload
...@@ -3932,12 +3933,12 @@ var opcodeTable = [...]opInfo{ ...@@ -3932,12 +3933,12 @@ var opcodeTable = [...]opInfo{
}, },
{ {
name: "ADDconst", name: "ADDconst",
auxType: auxSymOff, auxType: auxInt32,
argLen: 1, argLen: 1,
asm: arm.AADD, asm: arm.AADD,
reg: regInfo{ reg: regInfo{
inputs: []inputInfo{ inputs: []inputInfo{
{0, 8589947903}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 SP SB {0, 13311}, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 SP
}, },
outputs: []regMask{ outputs: []regMask{
5119, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12 5119, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12
...@@ -4733,6 +4734,21 @@ var opcodeTable = [...]opInfo{ ...@@ -4733,6 +4734,21 @@ var opcodeTable = [...]opInfo{
}, },
}, },
}, },
{
name: "MOVWaddr",
auxType: auxSymOff,
argLen: 1,
rematerializeable: true,
asm: arm.AMOVW,
reg: regInfo{
inputs: []inputInfo{
{0, 8589942784}, // SP SB
},
outputs: []regMask{
5119, // R0 R1 R2 R3 R4 R5 R6 R7 R8 R9 R12
},
},
},
{ {
name: "MOVBload", name: "MOVBload",
auxType: auxSymOff, auxType: auxSymOff,
......
This diff is collapsed.
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