mirror of
https://github.com/golang/go.git
synced 2025-05-28 02:41:30 +00:00
cmd/compile: start on ARM port
Start working on arm port. Gets close to correct code for fibonacci: func fib(n int) int { if n < 2 { return n } return fib(n-1) + fib(n-2) } Still a lot to do, but this is a good starting point. Cleaned up some arch-specific dependencies in regalloc. Change-Id: I4301c6c31a8402168e50dcfee8bcf7aee73ea9d5 Reviewed-on: https://go-review.googlesource.com/21000 Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
44d3f89e99
commit
4c9a470d46
@ -6,6 +6,7 @@ package arm
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/compile/internal/ssa"
|
||||
"cmd/internal/obj/arm"
|
||||
)
|
||||
|
||||
@ -65,6 +66,11 @@ func Main() {
|
||||
gc.Thearch.Doregbits = doregbits
|
||||
gc.Thearch.Regnames = regnames
|
||||
|
||||
gc.Thearch.SSARegToReg = ssaRegToReg
|
||||
gc.Thearch.SSAMarkMoves = func(s *gc.SSAGenState, b *ssa.Block) {}
|
||||
gc.Thearch.SSAGenValue = ssaGenValue
|
||||
gc.Thearch.SSAGenBlock = ssaGenBlock
|
||||
|
||||
gc.Main()
|
||||
gc.Exit(0)
|
||||
}
|
||||
|
152
src/cmd/compile/internal/arm/ssa.go
Normal file
152
src/cmd/compile/internal/arm/ssa.go
Normal file
@ -0,0 +1,152 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package arm
|
||||
|
||||
import (
|
||||
"cmd/compile/internal/gc"
|
||||
"cmd/compile/internal/ssa"
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm"
|
||||
)
|
||||
|
||||
var ssaRegToReg = []int16{
|
||||
arm.REG_R0,
|
||||
arm.REG_R1,
|
||||
arm.REG_R2,
|
||||
arm.REG_R3,
|
||||
arm.REGSP, // aka R13
|
||||
}
|
||||
|
||||
func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
|
||||
s.SetLineno(v.Line)
|
||||
switch v.Op {
|
||||
case ssa.OpInitMem:
|
||||
// memory arg needs no code
|
||||
case ssa.OpArg:
|
||||
// input args need no code
|
||||
case ssa.OpSP, ssa.OpSB:
|
||||
// nothing to do
|
||||
case ssa.OpCopy:
|
||||
case ssa.OpLoadReg:
|
||||
// TODO: by type
|
||||
p := gc.Prog(arm.AMOVW)
|
||||
n, off := gc.AutoVar(v.Args[0])
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Node = n
|
||||
p.From.Sym = gc.Linksym(n.Sym)
|
||||
p.From.Offset = off
|
||||
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
|
||||
p.From.Name = obj.NAME_PARAM
|
||||
p.From.Offset += n.Xoffset
|
||||
} else {
|
||||
p.From.Name = obj.NAME_AUTO
|
||||
}
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = gc.SSARegNum(v)
|
||||
|
||||
case ssa.OpStoreReg:
|
||||
// TODO: by type
|
||||
p := gc.Prog(arm.AMOVW)
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = gc.SSARegNum(v.Args[0])
|
||||
n, off := gc.AutoVar(v)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Node = n
|
||||
p.To.Sym = gc.Linksym(n.Sym)
|
||||
p.To.Offset = off
|
||||
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
|
||||
p.To.Name = obj.NAME_PARAM
|
||||
p.To.Offset += n.Xoffset
|
||||
} else {
|
||||
p.To.Name = obj.NAME_AUTO
|
||||
}
|
||||
case ssa.OpARMADD:
|
||||
r := gc.SSARegNum(v)
|
||||
r1 := gc.SSARegNum(v.Args[0])
|
||||
r2 := gc.SSARegNum(v.Args[1])
|
||||
p := gc.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = r1
|
||||
p.Reg = r2
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = r
|
||||
case ssa.OpARMADDconst:
|
||||
p := gc.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = v.AuxInt
|
||||
if v.Aux != nil {
|
||||
panic("can't handle symbolic constant yet")
|
||||
}
|
||||
p.Reg = gc.SSARegNum(v.Args[0])
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = gc.SSARegNum(v)
|
||||
case ssa.OpARMMOVWconst:
|
||||
p := gc.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_CONST
|
||||
p.From.Offset = v.AuxInt2Int64()
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = gc.SSARegNum(v)
|
||||
case ssa.OpARMCMP:
|
||||
p := gc.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = gc.SSARegNum(v.Args[0])
|
||||
p.Reg = gc.SSARegNum(v.Args[1])
|
||||
case ssa.OpARMMOVWload:
|
||||
p := gc.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_MEM
|
||||
p.From.Reg = gc.SSARegNum(v.Args[0])
|
||||
gc.AddAux(&p.From, v)
|
||||
p.To.Type = obj.TYPE_REG
|
||||
p.To.Reg = gc.SSARegNum(v)
|
||||
case ssa.OpARMMOVWstore:
|
||||
p := gc.Prog(v.Op.Asm())
|
||||
p.From.Type = obj.TYPE_REG
|
||||
p.From.Reg = gc.SSARegNum(v.Args[1])
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Reg = gc.SSARegNum(v.Args[0])
|
||||
gc.AddAux(&p.To, v)
|
||||
case ssa.OpARMCALLstatic:
|
||||
// TODO: deferreturn
|
||||
p := gc.Prog(obj.ACALL)
|
||||
p.To.Type = obj.TYPE_MEM
|
||||
p.To.Name = obj.NAME_EXTERN
|
||||
p.To.Sym = gc.Linksym(v.Aux.(*gc.Sym))
|
||||
if gc.Maxarg < v.AuxInt {
|
||||
gc.Maxarg = v.AuxInt
|
||||
}
|
||||
case ssa.OpVarDef:
|
||||
gc.Gvardef(v.Aux.(*gc.Node))
|
||||
case ssa.OpVarKill:
|
||||
gc.Gvarkill(v.Aux.(*gc.Node))
|
||||
case ssa.OpVarLive:
|
||||
gc.Gvarlive(v.Aux.(*gc.Node))
|
||||
case ssa.OpARMLessThan:
|
||||
v.Fatalf("pseudo-op made it to output: %s", v.LongString())
|
||||
default:
|
||||
v.Unimplementedf("genValue not implemented: %s", v.LongString())
|
||||
}
|
||||
}
|
||||
|
||||
func ssaGenBlock(s *gc.SSAGenState, b, next *ssa.Block) {
|
||||
s.SetLineno(b.Line)
|
||||
|
||||
switch b.Kind {
|
||||
case ssa.BlockCall:
|
||||
if b.Succs[0] != next {
|
||||
p := gc.Prog(obj.AJMP)
|
||||
p.To.Type = obj.TYPE_BRANCH
|
||||
s.Branches = append(s.Branches, gc.Branch{p, b.Succs[0]})
|
||||
}
|
||||
case ssa.BlockRet:
|
||||
gc.Prog(obj.ARET)
|
||||
case ssa.BlockARMLT:
|
||||
p := gc.Prog(arm.ABGE)
|
||||
p.To.Type = obj.TYPE_BRANCH
|
||||
s.Branches = append(s.Branches, gc.Branch{p, b.Succs[0]})
|
||||
p = gc.Prog(obj.AJMP)
|
||||
p.To.Type = obj.TYPE_BRANCH
|
||||
s.Branches = append(s.Branches, gc.Branch{p, b.Succs[1]})
|
||||
}
|
||||
}
|
@ -30,8 +30,14 @@ func initssa() *ssa.Config {
|
||||
}
|
||||
|
||||
func shouldssa(fn *Node) bool {
|
||||
if Thearch.Thestring != "amd64" {
|
||||
return false
|
||||
switch Thearch.Thestring {
|
||||
default:
|
||||
// Only available for testing.
|
||||
if os.Getenv("SSATEST") == "" {
|
||||
return false
|
||||
}
|
||||
// Generally available.
|
||||
case "amd64":
|
||||
}
|
||||
if !ssaEnabled {
|
||||
return false
|
||||
|
@ -18,6 +18,7 @@ type Config struct {
|
||||
PtrSize int64 // 4 or 8
|
||||
lowerBlock func(*Block) bool // lowering function
|
||||
lowerValue func(*Value, *Config) bool // lowering function
|
||||
registers []Register // machine registers
|
||||
fe Frontend // callbacks into compiler frontend
|
||||
HTML *HTMLWriter // html writer, for debugging
|
||||
ctxt *obj.Link // Generic arch information
|
||||
@ -112,11 +113,18 @@ func NewConfig(arch string, fe Frontend, ctxt *obj.Link, optimize bool) *Config
|
||||
c.PtrSize = 8
|
||||
c.lowerBlock = rewriteBlockAMD64
|
||||
c.lowerValue = rewriteValueAMD64
|
||||
c.registers = registersAMD64[:]
|
||||
case "386":
|
||||
c.IntSize = 4
|
||||
c.PtrSize = 4
|
||||
c.lowerBlock = rewriteBlockAMD64
|
||||
c.lowerValue = rewriteValueAMD64 // TODO(khr): full 32-bit support
|
||||
case "arm":
|
||||
c.IntSize = 4
|
||||
c.PtrSize = 4
|
||||
c.lowerBlock = rewriteBlockARM
|
||||
c.lowerValue = rewriteValueARM
|
||||
c.registers = registersARM[:]
|
||||
default:
|
||||
fe.Unimplementedf(0, "arch %s not implemented", arch)
|
||||
}
|
||||
|
32
src/cmd/compile/internal/ssa/gen/ARM.rules
Normal file
32
src/cmd/compile/internal/ssa/gen/ARM.rules
Normal file
@ -0,0 +1,32 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
(Add32 x y) -> (ADD x y)
|
||||
|
||||
(Const32 [val]) -> (MOVWconst [val])
|
||||
|
||||
(Less32 x y) -> (LessThan (CMP x y))
|
||||
|
||||
(OffPtr [off] ptr) -> (ADD (MOVWconst <config.Frontend().TypeInt32()> [off]) ptr)
|
||||
|
||||
(Addr {sym} base) -> (ADDconst {sym} base)
|
||||
|
||||
(Load <t> ptr mem) && is32BitInt(t) -> (MOVWload ptr mem)
|
||||
(Store [4] ptr val mem) -> (MOVWstore ptr val mem)
|
||||
|
||||
(StaticCall [argwid] {target} mem) -> (CALLstatic [argwid] {target} mem)
|
||||
|
||||
// Absorb LessThan into blocks.
|
||||
(If (LessThan cc) yes no) -> (LT cc yes no)
|
||||
|
||||
|
||||
|
||||
// Optimizations
|
||||
|
||||
(ADD (MOVWconst [c]) x) -> (ADDconst [c] x)
|
||||
(ADD x (MOVWconst [c])) -> (ADDconst [c] x)
|
||||
(MOVWload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
(MOVWstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem) && canMergeSym(sym1,sym2) ->
|
||||
(MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
66
src/cmd/compile/internal/ssa/gen/ARMOps.go
Normal file
66
src/cmd/compile/internal/ssa/gen/ARMOps.go
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2016 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package main
|
||||
|
||||
func init() {
|
||||
var (
|
||||
gp01 = regInfo{inputs: []regMask{}, outputs: []regMask{31}}
|
||||
gp11 = regInfo{inputs: []regMask{31}, outputs: []regMask{31}}
|
||||
gp21 = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{31}}
|
||||
gp2flags = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{32}}
|
||||
gpload = regInfo{inputs: []regMask{31}, outputs: []regMask{31}}
|
||||
gpstore = regInfo{inputs: []regMask{31, 31}, outputs: []regMask{}}
|
||||
flagsgp = regInfo{inputs: []regMask{32}, outputs: []regMask{31}}
|
||||
callerSave = regMask(15)
|
||||
)
|
||||
ops := []opData{
|
||||
{name: "ADD", argLength: 2, reg: gp21, asm: "ADD", commutative: true}, // arg0 + arg1
|
||||
{name: "ADDconst", argLength: 1, reg: gp11, asm: "ADD", aux: "SymOff"}, // arg0 + auxInt + aux.(*gc.Sym)
|
||||
|
||||
{name: "MOVWconst", argLength: 0, reg: gp01, aux: "Int32", asm: "MOVW", rematerializeable: true}, // 32 low bits of auxint
|
||||
|
||||
{name: "CMP", argLength: 2, reg: gp2flags, asm: "CMP", typ: "Flags"}, // arg0 compare to arg1
|
||||
|
||||
{name: "MOVWload", argLength: 2, reg: gpload, asm: "MOVW"}, // load from arg0 + auxInt + aux. arg1=mem.
|
||||
{name: "MOVWstore", argLength: 3, reg: gpstore, asm: "MOVW"}, // store 4 bytes of arg1 to arg0 + auxInt + aux. arg2=mem.
|
||||
|
||||
{name: "CALLstatic", argLength: 1, reg: regInfo{clobbers: callerSave}, aux: "SymOff"}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem
|
||||
|
||||
// pseudo-ops
|
||||
{name: "LessThan", argLength: 2, reg: flagsgp}, // bool, 1 flags encode x<y 0 otherwise.
|
||||
}
|
||||
|
||||
blocks := []blockData{
|
||||
{name: "EQ"},
|
||||
{name: "NE"},
|
||||
{name: "LT"},
|
||||
{name: "LE"},
|
||||
{name: "GT"},
|
||||
{name: "GE"},
|
||||
{name: "ULT"},
|
||||
{name: "ULE"},
|
||||
{name: "UGT"},
|
||||
{name: "UGE"},
|
||||
}
|
||||
|
||||
regNames := []string{
|
||||
"R0",
|
||||
"R1",
|
||||
"R2",
|
||||
"R3",
|
||||
"SP",
|
||||
"FLAGS",
|
||||
"SB",
|
||||
}
|
||||
|
||||
archs = append(archs, arch{
|
||||
name: "ARM",
|
||||
pkg: "cmd/internal/obj/arm",
|
||||
genfile: "../../arm/ssa.go",
|
||||
ops: ops,
|
||||
blocks: blocks,
|
||||
regnames: regNames,
|
||||
})
|
||||
}
|
@ -10,8 +10,9 @@ var decBlocks = []blockData{}
|
||||
|
||||
func init() {
|
||||
archs = append(archs, arch{
|
||||
name: "dec",
|
||||
ops: decOps,
|
||||
blocks: decBlocks,
|
||||
name: "dec",
|
||||
ops: decOps,
|
||||
blocks: decBlocks,
|
||||
generic: true,
|
||||
})
|
||||
}
|
||||
|
@ -414,8 +414,9 @@ var genericBlocks = []blockData{
|
||||
|
||||
func init() {
|
||||
archs = append(archs, arch{
|
||||
name: "generic",
|
||||
ops: genericOps,
|
||||
blocks: genericBlocks,
|
||||
name: "generic",
|
||||
ops: genericOps,
|
||||
blocks: genericBlocks,
|
||||
generic: true,
|
||||
})
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ type arch struct {
|
||||
ops []opData
|
||||
blocks []blockData
|
||||
regnames []string
|
||||
generic bool
|
||||
}
|
||||
|
||||
type opData struct {
|
||||
@ -205,6 +206,18 @@ func genOp() {
|
||||
// generate op string method
|
||||
fmt.Fprintln(w, "func (o Op) String() string {return opcodeTable[o].name }")
|
||||
|
||||
// generate registers
|
||||
for _, a := range archs {
|
||||
if a.generic {
|
||||
continue
|
||||
}
|
||||
fmt.Fprintf(w, "var registers%s = [...]Register {\n", a.name)
|
||||
for i, r := range a.regnames {
|
||||
fmt.Fprintf(w, " {%d, \"%s\"},\n", i, r)
|
||||
}
|
||||
fmt.Fprintln(w, "}")
|
||||
}
|
||||
|
||||
// gofmt result
|
||||
b := w.Bytes()
|
||||
var err error
|
||||
|
@ -55,6 +55,8 @@ const (
|
||||
auxSym // aux is a symbol
|
||||
auxSymOff // aux is a symbol, auxInt is an offset
|
||||
auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff
|
||||
|
||||
auxSymInt32 // aux is a symbol, auxInt is a 32-bit integer
|
||||
)
|
||||
|
||||
// A ValAndOff is used by the several opcodes. It holds
|
||||
|
@ -5,6 +5,7 @@ package ssa
|
||||
|
||||
import (
|
||||
"cmd/internal/obj"
|
||||
"cmd/internal/obj/arm"
|
||||
"cmd/internal/obj/x86"
|
||||
)
|
||||
|
||||
@ -26,6 +27,17 @@ const (
|
||||
BlockAMD64ORD
|
||||
BlockAMD64NAN
|
||||
|
||||
BlockARMEQ
|
||||
BlockARMNE
|
||||
BlockARMLT
|
||||
BlockARMLE
|
||||
BlockARMGT
|
||||
BlockARMGE
|
||||
BlockARMULT
|
||||
BlockARMULE
|
||||
BlockARMUGT
|
||||
BlockARMUGE
|
||||
|
||||
BlockPlain
|
||||
BlockIf
|
||||
BlockCall
|
||||
@ -56,6 +68,17 @@ var blockString = [...]string{
|
||||
BlockAMD64ORD: "ORD",
|
||||
BlockAMD64NAN: "NAN",
|
||||
|
||||
BlockARMEQ: "EQ",
|
||||
BlockARMNE: "NE",
|
||||
BlockARMLT: "LT",
|
||||
BlockARMLE: "LE",
|
||||
BlockARMGT: "GT",
|
||||
BlockARMGE: "GE",
|
||||
BlockARMULT: "ULT",
|
||||
BlockARMULE: "ULE",
|
||||
BlockARMUGT: "UGT",
|
||||
BlockARMUGE: "UGE",
|
||||
|
||||
BlockPlain: "Plain",
|
||||
BlockIf: "If",
|
||||
BlockCall: "Call",
|
||||
@ -309,6 +332,15 @@ const (
|
||||
OpAMD64FlagGT_UGT
|
||||
OpAMD64FlagGT_ULT
|
||||
|
||||
OpARMADD
|
||||
OpARMADDconst
|
||||
OpARMMOVWconst
|
||||
OpARMCMP
|
||||
OpARMMOVWload
|
||||
OpARMMOVWstore
|
||||
OpARMCALLstatic
|
||||
OpARMLessThan
|
||||
|
||||
OpAdd8
|
||||
OpAdd16
|
||||
OpAdd32
|
||||
@ -3915,6 +3947,106 @@ var opcodeTable = [...]opInfo{
|
||||
reg: regInfo{},
|
||||
},
|
||||
|
||||
{
|
||||
name: "ADD",
|
||||
argLen: 2,
|
||||
commutative: true,
|
||||
asm: arm.AADD,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 31}, // R0 R1 R2 R3 SP
|
||||
{1, 31}, // R0 R1 R2 R3 SP
|
||||
},
|
||||
outputs: []regMask{
|
||||
31, // R0 R1 R2 R3 SP
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ADDconst",
|
||||
auxType: auxSymOff,
|
||||
argLen: 1,
|
||||
asm: arm.AADD,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 31}, // R0 R1 R2 R3 SP
|
||||
},
|
||||
outputs: []regMask{
|
||||
31, // R0 R1 R2 R3 SP
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MOVWconst",
|
||||
auxType: auxInt32,
|
||||
argLen: 0,
|
||||
rematerializeable: true,
|
||||
asm: arm.AMOVW,
|
||||
reg: regInfo{
|
||||
outputs: []regMask{
|
||||
31, // R0 R1 R2 R3 SP
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CMP",
|
||||
argLen: 2,
|
||||
asm: arm.ACMP,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 31}, // R0 R1 R2 R3 SP
|
||||
{1, 31}, // R0 R1 R2 R3 SP
|
||||
},
|
||||
outputs: []regMask{
|
||||
32, // FLAGS
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MOVWload",
|
||||
argLen: 2,
|
||||
asm: arm.AMOVW,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 31}, // R0 R1 R2 R3 SP
|
||||
},
|
||||
outputs: []regMask{
|
||||
31, // R0 R1 R2 R3 SP
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "MOVWstore",
|
||||
argLen: 3,
|
||||
asm: arm.AMOVW,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 31}, // R0 R1 R2 R3 SP
|
||||
{1, 31}, // R0 R1 R2 R3 SP
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "CALLstatic",
|
||||
auxType: auxSymOff,
|
||||
argLen: 1,
|
||||
reg: regInfo{
|
||||
clobbers: 15, // R0 R1 R2 R3
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "LessThan",
|
||||
argLen: 2,
|
||||
reg: regInfo{
|
||||
inputs: []inputInfo{
|
||||
{0, 32}, // FLAGS
|
||||
},
|
||||
outputs: []regMask{
|
||||
31, // R0 R1 R2 R3 SP
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
name: "Add8",
|
||||
argLen: 2,
|
||||
@ -5343,3 +5475,49 @@ var opcodeTable = [...]opInfo{
|
||||
|
||||
func (o Op) Asm() obj.As { return opcodeTable[o].asm }
|
||||
func (o Op) String() string { return opcodeTable[o].name }
|
||||
|
||||
var registersAMD64 = [...]Register{
|
||||
{0, "AX"},
|
||||
{1, "CX"},
|
||||
{2, "DX"},
|
||||
{3, "BX"},
|
||||
{4, "SP"},
|
||||
{5, "BP"},
|
||||
{6, "SI"},
|
||||
{7, "DI"},
|
||||
{8, "R8"},
|
||||
{9, "R9"},
|
||||
{10, "R10"},
|
||||
{11, "R11"},
|
||||
{12, "R12"},
|
||||
{13, "R13"},
|
||||
{14, "R14"},
|
||||
{15, "R15"},
|
||||
{16, "X0"},
|
||||
{17, "X1"},
|
||||
{18, "X2"},
|
||||
{19, "X3"},
|
||||
{20, "X4"},
|
||||
{21, "X5"},
|
||||
{22, "X6"},
|
||||
{23, "X7"},
|
||||
{24, "X8"},
|
||||
{25, "X9"},
|
||||
{26, "X10"},
|
||||
{27, "X11"},
|
||||
{28, "X12"},
|
||||
{29, "X13"},
|
||||
{30, "X14"},
|
||||
{31, "X15"},
|
||||
{32, "SB"},
|
||||
{33, "FLAGS"},
|
||||
}
|
||||
var registersARM = [...]Register{
|
||||
{0, "R0"},
|
||||
{1, "R1"},
|
||||
{2, "R2"},
|
||||
{3, "R3"},
|
||||
{4, "SP"},
|
||||
{5, "FLAGS"},
|
||||
{6, "SB"},
|
||||
}
|
||||
|
@ -129,10 +129,11 @@ type regMask uint64
|
||||
|
||||
func (m regMask) String() string {
|
||||
s := ""
|
||||
for r := register(0); r < numRegs; r++ {
|
||||
for r := register(0); m != 0; r++ {
|
||||
if m>>r&1 == 0 {
|
||||
continue
|
||||
}
|
||||
m &^= regMask(1) << r
|
||||
if s != "" {
|
||||
s += " "
|
||||
}
|
||||
@ -141,47 +142,6 @@ func (m regMask) String() string {
|
||||
return s
|
||||
}
|
||||
|
||||
// TODO: make arch-dependent
|
||||
var numRegs register = 64
|
||||
|
||||
var registers = [...]Register{
|
||||
Register{0, "AX"},
|
||||
Register{1, "CX"},
|
||||
Register{2, "DX"},
|
||||
Register{3, "BX"},
|
||||
Register{4, "SP"},
|
||||
Register{5, "BP"},
|
||||
Register{6, "SI"},
|
||||
Register{7, "DI"},
|
||||
Register{8, "R8"},
|
||||
Register{9, "R9"},
|
||||
Register{10, "R10"},
|
||||
Register{11, "R11"},
|
||||
Register{12, "R12"},
|
||||
Register{13, "R13"},
|
||||
Register{14, "R14"},
|
||||
Register{15, "R15"},
|
||||
Register{16, "X0"},
|
||||
Register{17, "X1"},
|
||||
Register{18, "X2"},
|
||||
Register{19, "X3"},
|
||||
Register{20, "X4"},
|
||||
Register{21, "X5"},
|
||||
Register{22, "X6"},
|
||||
Register{23, "X7"},
|
||||
Register{24, "X8"},
|
||||
Register{25, "X9"},
|
||||
Register{26, "X10"},
|
||||
Register{27, "X11"},
|
||||
Register{28, "X12"},
|
||||
Register{29, "X13"},
|
||||
Register{30, "X14"},
|
||||
Register{31, "X15"},
|
||||
Register{32, "SB"}, // pseudo-register for global base pointer (aka %rip)
|
||||
|
||||
// TODO: make arch-dependent
|
||||
}
|
||||
|
||||
// countRegs returns the number of set bits in the register mask.
|
||||
func countRegs(r regMask) int {
|
||||
n := 0
|
||||
@ -231,6 +191,11 @@ type regState struct {
|
||||
type regAllocState struct {
|
||||
f *Func
|
||||
|
||||
registers []Register
|
||||
numRegs register
|
||||
SPReg register
|
||||
SBReg register
|
||||
|
||||
// for each block, its primary predecessor.
|
||||
// A predecessor of b is primary if it is the closest
|
||||
// predecessor that appears before b in the layout order.
|
||||
@ -298,7 +263,7 @@ func (s *regAllocState) freeReg(r register) {
|
||||
|
||||
// Mark r as unused.
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf("freeReg %s (dump %s/%s)\n", registers[r].Name(), v, s.regs[r].c)
|
||||
fmt.Printf("freeReg %s (dump %s/%s)\n", s.registers[r].Name(), v, s.regs[r].c)
|
||||
}
|
||||
s.regs[r] = regState{}
|
||||
s.values[v.ID].regs &^= regMask(1) << r
|
||||
@ -328,7 +293,7 @@ func (s *regAllocState) setOrig(c *Value, v *Value) {
|
||||
// r must be unused.
|
||||
func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf("assignReg %s %s/%s\n", registers[r].Name(), v, c)
|
||||
fmt.Printf("assignReg %s %s/%s\n", s.registers[r].Name(), v, c)
|
||||
}
|
||||
if s.regs[r].v != nil {
|
||||
s.f.Fatalf("tried to assign register %d to %s/%s but it is already used by %s", r, v, c, s.regs[r].v)
|
||||
@ -338,7 +303,7 @@ func (s *regAllocState) assignReg(r register, v *Value, c *Value) {
|
||||
s.regs[r] = regState{v, c}
|
||||
s.values[v.ID].regs |= regMask(1) << r
|
||||
s.used |= regMask(1) << r
|
||||
s.f.setHome(c, ®isters[r])
|
||||
s.f.setHome(c, &s.registers[r])
|
||||
}
|
||||
|
||||
// allocReg chooses a register for v from the set of registers in mask.
|
||||
@ -377,14 +342,14 @@ func (s *regAllocState) allocReg(v *Value, mask regMask) register {
|
||||
|
||||
// SP and SB are allocated specially. No regular value should
|
||||
// be allocated to them.
|
||||
mask &^= 1<<4 | 1<<32
|
||||
mask &^= 1<<s.SPReg | 1<<s.SBReg
|
||||
|
||||
// Find a register to spill. We spill the register containing the value
|
||||
// whose next use is as far in the future as possible.
|
||||
// https://en.wikipedia.org/wiki/Page_replacement_algorithm#The_theoretically_optimal_page_replacement_algorithm
|
||||
var r register
|
||||
maxuse := int32(-1)
|
||||
for t := register(0); t < numRegs; t++ {
|
||||
for t := register(0); t < s.numRegs; t++ {
|
||||
if mask>>t&1 == 0 {
|
||||
continue
|
||||
}
|
||||
@ -425,10 +390,10 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
|
||||
}
|
||||
|
||||
if v.Op != OpSP {
|
||||
mask &^= 1 << 4 // dont' spill SP
|
||||
mask &^= 1 << s.SPReg // dont' spill SP
|
||||
}
|
||||
if v.Op != OpSB {
|
||||
mask &^= 1 << 32 // don't spill SB
|
||||
mask &^= 1 << s.SBReg // don't spill SB
|
||||
}
|
||||
mask &^= s.reserved()
|
||||
|
||||
@ -469,12 +434,22 @@ func (s *regAllocState) allocValToReg(v *Value, mask regMask, nospill bool, line
|
||||
}
|
||||
|
||||
func (s *regAllocState) init(f *Func) {
|
||||
if numRegs > noRegister || numRegs > register(unsafe.Sizeof(regMask(0))*8) {
|
||||
s.registers = f.Config.registers
|
||||
s.numRegs = register(len(s.registers))
|
||||
if s.numRegs > noRegister || s.numRegs > register(unsafe.Sizeof(regMask(0))*8) {
|
||||
panic("too many registers")
|
||||
}
|
||||
for r := register(0); r < s.numRegs; r++ {
|
||||
if s.registers[r].Name() == "SP" {
|
||||
s.SPReg = r
|
||||
}
|
||||
if s.registers[r].Name() == "SB" {
|
||||
s.SBReg = r
|
||||
}
|
||||
}
|
||||
|
||||
s.f = f
|
||||
s.regs = make([]regState, numRegs)
|
||||
s.regs = make([]regState, s.numRegs)
|
||||
s.values = make([]valState, f.NumValues())
|
||||
s.orig = make([]*Value, f.NumValues())
|
||||
for _, b := range f.Blocks {
|
||||
@ -663,7 +638,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
// Drop any values which are no longer live.
|
||||
// This may happen because at the end of p, a value may be
|
||||
// live but only used by some other successor of p.
|
||||
for r := register(0); r < numRegs; r++ {
|
||||
for r := register(0); r < s.numRegs; r++ {
|
||||
v := s.regs[r].v
|
||||
if v != nil && !liveSet.contains(v.ID) {
|
||||
s.freeReg(r)
|
||||
@ -687,7 +662,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf("starting merge block %s with end state of %s:\n", b, p)
|
||||
for _, x := range s.endRegs[p.ID] {
|
||||
fmt.Printf(" %s: orig:%s cache:%s\n", registers[x.r].Name(), x.v, x.c)
|
||||
fmt.Printf(" %s: orig:%s cache:%s\n", s.registers[x.r].Name(), x.v, x.c)
|
||||
}
|
||||
}
|
||||
|
||||
@ -769,7 +744,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
|
||||
// Save the starting state for use by merge edges.
|
||||
var regList []startReg
|
||||
for r := register(0); r < numRegs; r++ {
|
||||
for r := register(0); r < s.numRegs; r++ {
|
||||
v := s.regs[r].v
|
||||
if v == nil {
|
||||
continue
|
||||
@ -786,7 +761,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
if s.f.pass.debug > regDebug {
|
||||
fmt.Printf("after phis\n")
|
||||
for _, x := range s.startRegs[b.ID] {
|
||||
fmt.Printf(" %s: v%d\n", registers[x.r].Name(), x.vid)
|
||||
fmt.Printf(" %s: v%d\n", s.registers[x.r].Name(), x.vid)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -866,13 +841,13 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
f.Fatalf("phi %s not at start of block", v)
|
||||
}
|
||||
if v.Op == OpSP {
|
||||
s.assignReg(4, v, v) // TODO: arch-dependent
|
||||
s.assignReg(s.SPReg, v, v)
|
||||
b.Values = append(b.Values, v)
|
||||
s.advanceUses(v)
|
||||
continue
|
||||
}
|
||||
if v.Op == OpSB {
|
||||
s.assignReg(32, v, v) // TODO: arch-dependent
|
||||
s.assignReg(s.SBReg, v, v)
|
||||
b.Values = append(b.Values, v)
|
||||
s.advanceUses(v)
|
||||
continue
|
||||
@ -1030,7 +1005,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
// Save end-of-block register state.
|
||||
// First count how many, this cuts allocations in half.
|
||||
k := 0
|
||||
for r := register(0); r < numRegs; r++ {
|
||||
for r := register(0); r < s.numRegs; r++ {
|
||||
v := s.regs[r].v
|
||||
if v == nil {
|
||||
continue
|
||||
@ -1038,7 +1013,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
k++
|
||||
}
|
||||
regList := make([]endReg, 0, k)
|
||||
for r := register(0); r < numRegs; r++ {
|
||||
for r := register(0); r < s.numRegs; r++ {
|
||||
v := s.regs[r].v
|
||||
if v == nil {
|
||||
continue
|
||||
@ -1053,7 +1028,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||
for _, x := range s.live[b.ID] {
|
||||
liveSet.add(x.ID)
|
||||
}
|
||||
for r := register(0); r < numRegs; r++ {
|
||||
for r := register(0); r < s.numRegs; r++ {
|
||||
v := s.regs[r].v
|
||||
if v == nil {
|
||||
continue
|
||||
@ -1214,7 +1189,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
|
||||
|
||||
// Live registers can be sources.
|
||||
for _, x := range srcReg {
|
||||
e.set(®isters[x.r], x.v.ID, x.c, false)
|
||||
e.set(&e.s.registers[x.r], x.v.ID, x.c, false)
|
||||
}
|
||||
// So can all of the spill locations.
|
||||
for _, spillID := range stacklive {
|
||||
@ -1226,7 +1201,7 @@ func (e *edgeState) setup(idx int, srcReg []endReg, dstReg []startReg, stacklive
|
||||
// Figure out all the destinations we need.
|
||||
dsts := e.destinations[:0]
|
||||
for _, x := range dstReg {
|
||||
dsts = append(dsts, dstRecord{®isters[x.r], x.vid, nil})
|
||||
dsts = append(dsts, dstRecord{&e.s.registers[x.r], x.vid, nil})
|
||||
}
|
||||
// Phis need their args to end up in a specific location.
|
||||
for _, v := range e.b.Values {
|
||||
@ -1519,15 +1494,15 @@ func (e *edgeState) findRegFor(typ Type) Location {
|
||||
// 3) a non-unique register
|
||||
x := m &^ e.usedRegs
|
||||
if x != 0 {
|
||||
return ®isters[pickReg(x)]
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
x = m &^ e.uniqueRegs &^ e.finalRegs
|
||||
if x != 0 {
|
||||
return ®isters[pickReg(x)]
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
x = m &^ e.uniqueRegs
|
||||
if x != 0 {
|
||||
return ®isters[pickReg(x)]
|
||||
return &e.s.registers[pickReg(x)]
|
||||
}
|
||||
|
||||
// No register is available. Allocate a temp location to spill a register to.
|
||||
|
294
src/cmd/compile/internal/ssa/rewriteARM.go
Normal file
294
src/cmd/compile/internal/ssa/rewriteARM.go
Normal file
@ -0,0 +1,294 @@
|
||||
// autogenerated from gen/ARM.rules: do not edit!
|
||||
// generated with: cd gen; go run *.go
|
||||
|
||||
package ssa
|
||||
|
||||
import "math"
|
||||
|
||||
var _ = math.MinInt8 // in case not otherwise used
|
||||
func rewriteValueARM(v *Value, config *Config) bool {
|
||||
switch v.Op {
|
||||
case OpARMADD:
|
||||
return rewriteValueARM_OpARMADD(v, config)
|
||||
case OpAdd32:
|
||||
return rewriteValueARM_OpAdd32(v, config)
|
||||
case OpAddr:
|
||||
return rewriteValueARM_OpAddr(v, config)
|
||||
case OpConst32:
|
||||
return rewriteValueARM_OpConst32(v, config)
|
||||
case OpLess32:
|
||||
return rewriteValueARM_OpLess32(v, config)
|
||||
case OpLoad:
|
||||
return rewriteValueARM_OpLoad(v, config)
|
||||
case OpARMMOVWload:
|
||||
return rewriteValueARM_OpARMMOVWload(v, config)
|
||||
case OpARMMOVWstore:
|
||||
return rewriteValueARM_OpARMMOVWstore(v, config)
|
||||
case OpOffPtr:
|
||||
return rewriteValueARM_OpOffPtr(v, config)
|
||||
case OpStaticCall:
|
||||
return rewriteValueARM_OpStaticCall(v, config)
|
||||
case OpStore:
|
||||
return rewriteValueARM_OpStore(v, config)
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpARMADD(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (ADD (MOVWconst [c]) x)
|
||||
// cond:
|
||||
// result: (ADDconst [c] x)
|
||||
for {
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpARMMOVWconst {
|
||||
break
|
||||
}
|
||||
c := v_0.AuxInt
|
||||
x := v.Args[1]
|
||||
v.reset(OpARMADDconst)
|
||||
v.AuxInt = c
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
// match: (ADD x (MOVWconst [c]))
|
||||
// cond:
|
||||
// result: (ADDconst [c] x)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
v_1 := v.Args[1]
|
||||
if v_1.Op != OpARMMOVWconst {
|
||||
break
|
||||
}
|
||||
c := v_1.AuxInt
|
||||
v.reset(OpARMADDconst)
|
||||
v.AuxInt = c
|
||||
v.AddArg(x)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpAdd32(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (Add32 x y)
|
||||
// cond:
|
||||
// result: (ADD x y)
|
||||
for {
|
||||
x := v.Args[0]
|
||||
y := v.Args[1]
|
||||
v.reset(OpARMADD)
|
||||
v.AddArg(x)
|
||||
v.AddArg(y)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpAddr(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (Addr {sym} base)
|
||||
// cond:
|
||||
// result: (ADDconst {sym} base)
|
||||
for {
|
||||
sym := v.Aux
|
||||
base := v.Args[0]
|
||||
v.reset(OpARMADDconst)
|
||||
v.Aux = sym
|
||||
v.AddArg(base)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpConst32(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (Const32 [val])
|
||||
// cond:
|
||||
// result: (MOVWconst [val])
|
||||
for {
|
||||
val := v.AuxInt
|
||||
v.reset(OpARMMOVWconst)
|
||||
v.AuxInt = val
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpLess32(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (Less32 x y)
|
||||
// cond:
|
||||
// result: (LessThan (CMP x y))
|
||||
for {
|
||||
x := v.Args[0]
|
||||
y := v.Args[1]
|
||||
v.reset(OpARMLessThan)
|
||||
v0 := b.NewValue0(v.Line, OpARMCMP, TypeFlags)
|
||||
v0.AddArg(x)
|
||||
v0.AddArg(y)
|
||||
v.AddArg(v0)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpLoad(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (Load <t> ptr mem)
|
||||
// cond: is32BitInt(t)
|
||||
// result: (MOVWload ptr mem)
|
||||
for {
|
||||
t := v.Type
|
||||
ptr := v.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(is32BitInt(t)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARMMOVWload)
|
||||
v.AddArg(ptr)
|
||||
v.AddArg(mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpARMMOVWload(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWload [off1] {sym1} (ADDconst [off2] {sym2} ptr) mem)
|
||||
// cond: canMergeSym(sym1,sym2)
|
||||
// result: (MOVWload [off1+off2] {mergeSym(sym1,sym2)} ptr mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
sym1 := v.Aux
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpARMADDconst {
|
||||
break
|
||||
}
|
||||
off2 := v_0.AuxInt
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
mem := v.Args[1]
|
||||
if !(canMergeSym(sym1, sym2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARMMOVWload)
|
||||
v.AuxInt = off1 + off2
|
||||
v.Aux = mergeSym(sym1, sym2)
|
||||
v.AddArg(ptr)
|
||||
v.AddArg(mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpARMMOVWstore(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (MOVWstore [off1] {sym1} (ADDconst [off2] {sym2} ptr) val mem)
|
||||
// cond: canMergeSym(sym1,sym2)
|
||||
// result: (MOVWstore [off1+off2] {mergeSym(sym1,sym2)} ptr val mem)
|
||||
for {
|
||||
off1 := v.AuxInt
|
||||
sym1 := v.Aux
|
||||
v_0 := v.Args[0]
|
||||
if v_0.Op != OpARMADDconst {
|
||||
break
|
||||
}
|
||||
off2 := v_0.AuxInt
|
||||
sym2 := v_0.Aux
|
||||
ptr := v_0.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
if !(canMergeSym(sym1, sym2)) {
|
||||
break
|
||||
}
|
||||
v.reset(OpARMMOVWstore)
|
||||
v.AuxInt = off1 + off2
|
||||
v.Aux = mergeSym(sym1, sym2)
|
||||
v.AddArg(ptr)
|
||||
v.AddArg(val)
|
||||
v.AddArg(mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpOffPtr(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (OffPtr [off] ptr)
|
||||
// cond:
|
||||
// result: (ADD (MOVWconst <config.Frontend().TypeInt32()> [off]) ptr)
|
||||
for {
|
||||
off := v.AuxInt
|
||||
ptr := v.Args[0]
|
||||
v.reset(OpARMADD)
|
||||
v0 := b.NewValue0(v.Line, OpARMMOVWconst, config.Frontend().TypeInt32())
|
||||
v0.AuxInt = off
|
||||
v.AddArg(v0)
|
||||
v.AddArg(ptr)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpStaticCall(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (StaticCall [argwid] {target} mem)
|
||||
// cond:
|
||||
// result: (CALLstatic [argwid] {target} mem)
|
||||
for {
|
||||
argwid := v.AuxInt
|
||||
target := v.Aux
|
||||
mem := v.Args[0]
|
||||
v.reset(OpARMCALLstatic)
|
||||
v.AuxInt = argwid
|
||||
v.Aux = target
|
||||
v.AddArg(mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteValueARM_OpStore(v *Value, config *Config) bool {
|
||||
b := v.Block
|
||||
_ = b
|
||||
// match: (Store [4] ptr val mem)
|
||||
// cond:
|
||||
// result: (MOVWstore ptr val mem)
|
||||
for {
|
||||
if v.AuxInt != 4 {
|
||||
break
|
||||
}
|
||||
ptr := v.Args[0]
|
||||
val := v.Args[1]
|
||||
mem := v.Args[2]
|
||||
v.reset(OpARMMOVWstore)
|
||||
v.AddArg(ptr)
|
||||
v.AddArg(val)
|
||||
v.AddArg(mem)
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
func rewriteBlockARM(b *Block) bool {
|
||||
switch b.Kind {
|
||||
case BlockIf:
|
||||
// match: (If (LessThan cc) yes no)
|
||||
// cond:
|
||||
// result: (LT cc yes no)
|
||||
for {
|
||||
v := b.Control
|
||||
if v.Op != OpARMLessThan {
|
||||
break
|
||||
}
|
||||
cc := v.Args[0]
|
||||
yes := b.Succs[0]
|
||||
no := b.Succs[1]
|
||||
b.Kind = BlockARMLT
|
||||
b.SetControl(cc)
|
||||
b.Succs[0] = yes
|
||||
b.Succs[1] = no
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user