Commit 9cb332ef authored by Keith Randall's avatar Keith Randall

[dev.ssa] cmd/compile/internal/ssa: Split OpConst into an OpConst8, OpConst16, ...

Convert the polymorphic OpConst into monomorphic variants.

Change-Id: I90bb8894fbac04ca5e5484ea260c131ef8b506fb
Reviewed-on: https://go-review.googlesource.com/12798Reviewed-by: default avatarJosh Bleecher Snyder <josharian@gmail.com>
parent 25d19168
...@@ -347,9 +347,33 @@ func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ss ...@@ -347,9 +347,33 @@ func (s *state) entryNewValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ss
return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1) return s.f.Entry.NewValue2(s.peekLine(), op, t, arg0, arg1)
} }
// constInt adds a new const int value to the entry block. // constInt* routines add a new const int value to the entry block.
func (s *state) constInt8(t ssa.Type, c int8) *ssa.Value {
return s.f.ConstInt8(s.peekLine(), t, c)
}
func (s *state) constInt16(t ssa.Type, c int16) *ssa.Value {
return s.f.ConstInt16(s.peekLine(), t, c)
}
func (s *state) constInt32(t ssa.Type, c int32) *ssa.Value {
return s.f.ConstInt32(s.peekLine(), t, c)
}
func (s *state) constInt64(t ssa.Type, c int64) *ssa.Value {
return s.f.ConstInt64(s.peekLine(), t, c)
}
func (s *state) constIntPtr(t ssa.Type, c int64) *ssa.Value {
if s.config.PtrSize == 4 && int64(int32(c)) != c {
s.Fatalf("pointer constant too big %d", c)
}
return s.f.ConstIntPtr(s.peekLine(), t, c)
}
func (s *state) constInt(t ssa.Type, c int64) *ssa.Value { func (s *state) constInt(t ssa.Type, c int64) *ssa.Value {
return s.f.ConstInt(s.peekLine(), t, c) if s.config.IntSize == 8 {
return s.constInt64(t, c)
}
if int64(int32(c)) != c {
s.Fatalf("integer constant too big %d", c)
}
return s.constInt32(t, int32(c))
} }
// ssaStmtList converts the statement n to SSA and adds it to s. // ssaStmtList converts the statement n to SSA and adds it to s.
...@@ -584,7 +608,7 @@ func (s *state) stmt(n *Node) { ...@@ -584,7 +608,7 @@ func (s *state) stmt(n *Node) {
if n.Left != nil { if n.Left != nil {
cond = s.expr(n.Left) cond = s.expr(n.Left)
} else { } else {
cond = s.entryNewValue0A(ssa.OpConst, Types[TBOOL], true) cond = s.entryNewValue0A(ssa.OpConstBool, Types[TBOOL], true)
} }
b = s.endBlock() b = s.endBlock()
b.Kind = ssa.BlockIf b.Kind = ssa.BlockIf
...@@ -862,11 +886,26 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -862,11 +886,26 @@ func (s *state) expr(n *Node) *ssa.Value {
case OLITERAL: case OLITERAL:
switch n.Val().Ctype() { switch n.Val().Ctype() {
case CTINT: case CTINT:
return s.constInt(n.Type, Mpgetfix(n.Val().U.(*Mpint))) i := Mpgetfix(n.Val().U.(*Mpint))
case CTSTR, CTBOOL: switch n.Type.Size() {
return s.entryNewValue0A(ssa.OpConst, n.Type, n.Val().U) case 1:
return s.constInt8(n.Type, int8(i))
case 2:
return s.constInt16(n.Type, int16(i))
case 4:
return s.constInt32(n.Type, int32(i))
case 8:
return s.constInt64(n.Type, i)
default:
s.Fatalf("bad integer size %d", n.Type.Size())
return nil
}
case CTSTR:
return s.entryNewValue0A(ssa.OpConstString, n.Type, n.Val().U)
case CTBOOL:
return s.entryNewValue0A(ssa.OpConstBool, n.Type, n.Val().U)
case CTNIL: case CTNIL:
return s.entryNewValue0(ssa.OpConst, n.Type) return s.entryNewValue0(ssa.OpConstNil, n.Type)
default: default:
s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype()) s.Unimplementedf("unhandled OLITERAL %v", n.Val().Ctype())
return nil return nil
...@@ -1020,7 +1059,7 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -1020,7 +1059,7 @@ func (s *state) expr(n *Node) *ssa.Value {
case ODOTPTR: case ODOTPTR:
p := s.expr(n.Left) p := s.expr(n.Left)
s.nilCheck(p) s.nilCheck(p)
p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset)) p = s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(s.config.Uintptr, n.Xoffset))
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem()) return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
case OINDEX: case OINDEX:
...@@ -1031,10 +1070,10 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -1031,10 +1070,10 @@ func (s *state) expr(n *Node) *ssa.Value {
var elemtype *Type var elemtype *Type
var len *ssa.Value var len *ssa.Value
if n.Left.Type.IsString() { if n.Left.Type.IsString() {
len = s.newValue1(ssa.OpStringLen, s.config.Uintptr, a) len = s.newValue1(ssa.OpStringLen, s.config.Int, a)
elemtype = Types[TUINT8] elemtype = Types[TUINT8]
} else { } else {
len = s.constInt(s.config.Uintptr, n.Left.Type.Bound) len = s.constInt(s.config.Int, n.Left.Type.Bound)
elemtype = n.Left.Type.Type elemtype = n.Left.Type.Type
} }
s.boundsCheck(i, len) s.boundsCheck(i, len)
...@@ -1149,12 +1188,25 @@ func (s *state) assign(op uint8, left *Node, right *Node) { ...@@ -1149,12 +1188,25 @@ func (s *state) assign(op uint8, left *Node, right *Node) {
// zeroVal returns the zero value for type t. // zeroVal returns the zero value for type t.
func (s *state) zeroVal(t *Type) *ssa.Value { func (s *state) zeroVal(t *Type) *ssa.Value {
switch { switch {
case t.IsInteger():
switch t.Size() {
case 1:
return s.constInt8(t, 0)
case 2:
return s.constInt16(t, 0)
case 4:
return s.constInt32(t, 0)
case 8:
return s.constInt64(t, 0)
default:
s.Fatalf("bad sized integer type %s", t)
}
case t.IsString(): case t.IsString():
return s.entryNewValue0A(ssa.OpConst, t, "") return s.entryNewValue0A(ssa.OpConstString, t, "")
case t.IsInteger() || t.IsPtr(): case t.IsPtr():
return s.entryNewValue0(ssa.OpConst, t) return s.entryNewValue0(ssa.OpConstNil, t)
case t.IsBoolean(): case t.IsBoolean():
return s.entryNewValue0A(ssa.OpConst, t, false) // TODO: store bools as 0/1 in AuxInt? return s.entryNewValue0A(ssa.OpConstBool, t, false) // TODO: store bools as 0/1 in AuxInt?
} }
s.Unimplementedf("zero for type %v not implemented", t) s.Unimplementedf("zero for type %v not implemented", t)
return nil return nil
...@@ -1212,7 +1264,7 @@ func (s *state) addr(n *Node) *ssa.Value { ...@@ -1212,7 +1264,7 @@ func (s *state) addr(n *Node) *ssa.Value {
a := s.addr(n.Left) a := s.addr(n.Left)
i := s.expr(n.Right) i := s.expr(n.Right)
i = s.extendIndex(i) i = s.extendIndex(i)
len := s.constInt(s.config.Uintptr, n.Left.Type.Bound) len := s.constInt(s.config.Int, n.Left.Type.Bound)
s.boundsCheck(i, len) s.boundsCheck(i, len)
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i) return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
} }
...@@ -1222,11 +1274,11 @@ func (s *state) addr(n *Node) *ssa.Value { ...@@ -1222,11 +1274,11 @@ func (s *state) addr(n *Node) *ssa.Value {
return p return p
case ODOT: case ODOT:
p := s.addr(n.Left) p := s.addr(n.Left)
return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset)) return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(s.config.Uintptr, n.Xoffset))
case ODOTPTR: case ODOTPTR:
p := s.expr(n.Left) p := s.expr(n.Left)
s.nilCheck(p) s.nilCheck(p)
return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constInt(s.config.Uintptr, n.Xoffset)) return s.newValue2(ssa.OpAddPtr, p.Type, p, s.constIntPtr(s.config.Uintptr, n.Xoffset))
default: default:
s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0)) s.Unimplementedf("addr: bad op %v", Oconv(int(n.Op), 0))
return nil return nil
...@@ -1570,7 +1622,7 @@ func genValue(v *ssa.Value) { ...@@ -1570,7 +1622,7 @@ func genValue(v *ssa.Value) {
x := regnum(v.Args[0]) x := regnum(v.Args[0])
y := regnum(v.Args[1]) y := regnum(v.Args[1])
if x != r && y != r { if x != r && y != r {
p := Prog(x86.AMOVQ) p := Prog(regMoveAMD64(v.Type.Size()))
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = x p.From.Reg = x
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
...@@ -1731,11 +1783,22 @@ func genValue(v *ssa.Value) { ...@@ -1731,11 +1783,22 @@ func genValue(v *ssa.Value) {
p.From.Reg = regnum(v.Args[0]) p.From.Reg = regnum(v.Args[0])
p.To.Type = obj.TYPE_CONST p.To.Type = obj.TYPE_CONST
p.To.Offset = v.AuxInt p.To.Offset = v.AuxInt
case ssa.OpAMD64MOVQconst: case ssa.OpAMD64MOVBconst, ssa.OpAMD64MOVWconst, ssa.OpAMD64MOVLconst, ssa.OpAMD64MOVQconst:
x := regnum(v) x := regnum(v)
p := Prog(x86.AMOVQ) p := Prog(v.Op.Asm())
p.From.Type = obj.TYPE_CONST p.From.Type = obj.TYPE_CONST
p.From.Offset = v.AuxInt var i int64
switch v.Op {
case ssa.OpAMD64MOVBconst:
i = int64(int8(v.AuxInt))
case ssa.OpAMD64MOVWconst:
i = int64(int16(v.AuxInt))
case ssa.OpAMD64MOVLconst:
i = int64(int32(v.AuxInt))
case ssa.OpAMD64MOVQconst:
i = v.AuxInt
}
p.From.Offset = i
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = x p.To.Reg = x
case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload: case ssa.OpAMD64MOVQload, ssa.OpAMD64MOVLload, ssa.OpAMD64MOVWload, ssa.OpAMD64MOVBload, ssa.OpAMD64MOVBQSXload, ssa.OpAMD64MOVBQZXload:
...@@ -1836,7 +1899,7 @@ func genValue(v *ssa.Value) { ...@@ -1836,7 +1899,7 @@ func genValue(v *ssa.Value) {
v.Fatalf("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID]) v.Fatalf("phi arg at different location than phi %v %v %v %v", v, loc, a, f.RegAlloc[a.ID])
} }
} }
case ssa.OpConst: case ssa.OpConst8, ssa.OpConst16, ssa.OpConst32, ssa.OpConst64, ssa.OpConstString, ssa.OpConstNil, ssa.OpConstBool:
if v.Block.Func.RegAlloc[v.ID] != nil { if v.Block.Func.RegAlloc[v.ID] != nil {
v.Fatalf("const value %v shouldn't have a location", v) v.Fatalf("const value %v shouldn't have a location", v)
} }
...@@ -2079,6 +2142,23 @@ var ssaRegToReg = [...]int16{ ...@@ -2079,6 +2142,23 @@ var ssaRegToReg = [...]int16{
// TODO: arch-dependent // TODO: arch-dependent
} }
// regMoveAMD64 returns the register->register move opcode for the given width.
// TODO: generalize for all architectures?
func regMoveAMD64(width int64) int {
switch width {
case 1:
return x86.AMOVB
case 2:
return x86.AMOVW
case 4:
return x86.AMOVL
case 8:
return x86.AMOVQ
default:
panic("bad register width")
}
}
// regnum returns the register (in cmd/internal/obj numbering) to // regnum returns the register (in cmd/internal/obj numbering) to
// which v has been allocated. Panics if v is not assigned to a // which v has been allocated. Panics if v is not assigned to a
// register. // register.
......
...@@ -17,7 +17,7 @@ func TestDeadLoop(t *testing.T) { ...@@ -17,7 +17,7 @@ func TestDeadLoop(t *testing.T) {
// dead loop // dead loop
Bloc("deadblock", Bloc("deadblock",
// dead value in dead block // dead value in dead block
Valu("deadval", OpConst, TypeBool, 0, true), Valu("deadval", OpConstBool, TypeBool, 0, true),
If("deadval", "deadblock", "exit"))) If("deadval", "deadblock", "exit")))
CheckFunc(fun.f) CheckFunc(fun.f)
...@@ -41,7 +41,7 @@ func TestDeadValue(t *testing.T) { ...@@ -41,7 +41,7 @@ func TestDeadValue(t *testing.T) {
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("deadval", OpConst, TypeInt64, 37, nil), Valu("deadval", OpConst64, TypeInt64, 37, nil),
Goto("exit")), Goto("exit")),
Bloc("exit", Bloc("exit",
Exit("mem"))) Exit("mem")))
...@@ -63,7 +63,7 @@ func TestNeverTaken(t *testing.T) { ...@@ -63,7 +63,7 @@ func TestNeverTaken(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}) c := NewConfig("amd64", DummyFrontend{t})
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("cond", OpConst, TypeBool, 0, false), Valu("cond", OpConstBool, TypeBool, 0, false),
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
If("cond", "then", "else")), If("cond", "then", "else")),
Bloc("then", Bloc("then",
...@@ -99,7 +99,7 @@ func TestNestedDeadBlocks(t *testing.T) { ...@@ -99,7 +99,7 @@ func TestNestedDeadBlocks(t *testing.T) {
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("cond", OpConst, TypeBool, 0, false), Valu("cond", OpConstBool, TypeBool, 0, false),
If("cond", "b2", "b4")), If("cond", "b2", "b4")),
Bloc("b2", Bloc("b2",
If("cond", "b3", "b4")), If("cond", "b3", "b4")),
......
...@@ -15,7 +15,7 @@ func TestDeadStore(t *testing.T) { ...@@ -15,7 +15,7 @@ func TestDeadStore(t *testing.T) {
Bloc("entry", Bloc("entry",
Valu("start", OpArg, TypeMem, 0, ".mem"), Valu("start", OpArg, TypeMem, 0, ".mem"),
Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil),
Valu("v", OpConst, TypeBool, 0, true), Valu("v", OpConstBool, TypeBool, 0, true),
Valu("addr1", OpAddr, ptrType, 0, nil, "sb"), Valu("addr1", OpAddr, ptrType, 0, nil, "sb"),
Valu("addr2", OpAddr, ptrType, 0, nil, "sb"), Valu("addr2", OpAddr, ptrType, 0, nil, "sb"),
Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"), Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"),
...@@ -42,7 +42,7 @@ func TestDeadStorePhi(t *testing.T) { ...@@ -42,7 +42,7 @@ func TestDeadStorePhi(t *testing.T) {
Bloc("entry", Bloc("entry",
Valu("start", OpArg, TypeMem, 0, ".mem"), Valu("start", OpArg, TypeMem, 0, ".mem"),
Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil),
Valu("v", OpConst, TypeBool, 0, true), Valu("v", OpConstBool, TypeBool, 0, true),
Valu("addr", OpAddr, ptrType, 0, nil, "sb"), Valu("addr", OpAddr, ptrType, 0, nil, "sb"),
Goto("loop")), Goto("loop")),
Bloc("loop", Bloc("loop",
...@@ -69,7 +69,7 @@ func TestDeadStoreTypes(t *testing.T) { ...@@ -69,7 +69,7 @@ func TestDeadStoreTypes(t *testing.T) {
Bloc("entry", Bloc("entry",
Valu("start", OpArg, TypeMem, 0, ".mem"), Valu("start", OpArg, TypeMem, 0, ".mem"),
Valu("sb", OpSB, TypeInvalid, 0, nil), Valu("sb", OpSB, TypeInvalid, 0, nil),
Valu("v", OpConst, TypeBool, 0, true), Valu("v", OpConstBool, TypeBool, 0, true),
Valu("addr1", OpAddr, t1, 0, nil, "sb"), Valu("addr1", OpAddr, t1, 0, nil, "sb"),
Valu("addr2", OpAddr, t2, 0, nil, "sb"), Valu("addr2", OpAddr, t2, 0, nil, "sb"),
Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"), Valu("store1", OpStore, TypeMem, 0, nil, "addr1", "v", "start"),
......
...@@ -44,7 +44,7 @@ func genFwdBack(size int) []bloc { ...@@ -44,7 +44,7 @@ func genFwdBack(size int) []bloc {
blocs = append(blocs, blocs = append(blocs,
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, true), Valu("p", OpConstBool, TypeBool, 0, true),
Goto(blockn(0)), Goto(blockn(0)),
), ),
) )
...@@ -74,7 +74,7 @@ func genManyPred(size int) []bloc { ...@@ -74,7 +74,7 @@ func genManyPred(size int) []bloc {
blocs = append(blocs, blocs = append(blocs,
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, true), Valu("p", OpConstBool, TypeBool, 0, true),
Goto(blockn(0)), Goto(blockn(0)),
), ),
) )
...@@ -85,15 +85,15 @@ func genManyPred(size int) []bloc { ...@@ -85,15 +85,15 @@ func genManyPred(size int) []bloc {
switch i % 3 { switch i % 3 {
case 0: case 0:
blocs = append(blocs, Bloc(blockn(i), blocs = append(blocs, Bloc(blockn(i),
Valu("a", OpConst, TypeBool, 0, true), Valu("a", OpConstBool, TypeBool, 0, true),
Goto(blockn(i+1)))) Goto(blockn(i+1))))
case 1: case 1:
blocs = append(blocs, Bloc(blockn(i), blocs = append(blocs, Bloc(blockn(i),
Valu("a", OpConst, TypeBool, 0, true), Valu("a", OpConstBool, TypeBool, 0, true),
If("p", blockn(i+1), blockn(0)))) If("p", blockn(i+1), blockn(0))))
case 2: case 2:
blocs = append(blocs, Bloc(blockn(i), blocs = append(blocs, Bloc(blockn(i),
Valu("a", OpConst, TypeBool, 0, true), Valu("a", OpConstBool, TypeBool, 0, true),
If("p", blockn(i+1), blockn(size)))) If("p", blockn(i+1), blockn(size))))
} }
} }
...@@ -112,7 +112,7 @@ func genMaxPred(size int) []bloc { ...@@ -112,7 +112,7 @@ func genMaxPred(size int) []bloc {
blocs = append(blocs, blocs = append(blocs,
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, true), Valu("p", OpConstBool, TypeBool, 0, true),
Goto(blockn(0)), Goto(blockn(0)),
), ),
) )
...@@ -137,14 +137,14 @@ func genMaxPredValue(size int) []bloc { ...@@ -137,14 +137,14 @@ func genMaxPredValue(size int) []bloc {
blocs = append(blocs, blocs = append(blocs,
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, true), Valu("p", OpConstBool, TypeBool, 0, true),
Goto(blockn(0)), Goto(blockn(0)),
), ),
) )
for i := 0; i < size; i++ { for i := 0; i < size; i++ {
blocs = append(blocs, Bloc(blockn(i), blocs = append(blocs, Bloc(blockn(i),
Valu("a", OpConst, TypeBool, 0, true), Valu("a", OpConstBool, TypeBool, 0, true),
If("p", blockn(i+1), "exit"))) If("p", blockn(i+1), "exit")))
} }
...@@ -267,7 +267,7 @@ func TestDominatorsMultPredFwd(t *testing.T) { ...@@ -267,7 +267,7 @@ func TestDominatorsMultPredFwd(t *testing.T) {
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, true), Valu("p", OpConstBool, TypeBool, 0, true),
If("p", "a", "c")), If("p", "a", "c")),
Bloc("a", Bloc("a",
If("p", "b", "c")), If("p", "b", "c")),
...@@ -295,7 +295,7 @@ func TestDominatorsDeadCode(t *testing.T) { ...@@ -295,7 +295,7 @@ func TestDominatorsDeadCode(t *testing.T) {
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, false), Valu("p", OpConstBool, TypeBool, 0, false),
If("p", "b3", "b5")), If("p", "b3", "b5")),
Bloc("b2", Exit("mem")), Bloc("b2", Exit("mem")),
Bloc("b3", Goto("b2")), Bloc("b3", Goto("b2")),
...@@ -318,7 +318,7 @@ func TestDominatorsMultPredRev(t *testing.T) { ...@@ -318,7 +318,7 @@ func TestDominatorsMultPredRev(t *testing.T) {
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, true), Valu("p", OpConstBool, TypeBool, 0, true),
Goto("a")), Goto("a")),
Bloc("a", Bloc("a",
If("p", "b", "entry")), If("p", "b", "entry")),
...@@ -346,7 +346,7 @@ func TestDominatorsMultPred(t *testing.T) { ...@@ -346,7 +346,7 @@ func TestDominatorsMultPred(t *testing.T) {
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, true), Valu("p", OpConstBool, TypeBool, 0, true),
If("p", "a", "c")), If("p", "a", "c")),
Bloc("a", Bloc("a",
If("p", "b", "c")), If("p", "b", "c")),
...@@ -374,7 +374,7 @@ func TestPostDominators(t *testing.T) { ...@@ -374,7 +374,7 @@ func TestPostDominators(t *testing.T) {
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, true), Valu("p", OpConstBool, TypeBool, 0, true),
If("p", "a", "c")), If("p", "a", "c")),
Bloc("a", Bloc("a",
If("p", "b", "c")), If("p", "b", "c")),
...@@ -401,7 +401,7 @@ func TestInfiniteLoop(t *testing.T) { ...@@ -401,7 +401,7 @@ func TestInfiniteLoop(t *testing.T) {
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("p", OpConst, TypeBool, 0, true), Valu("p", OpConstBool, TypeBool, 0, true),
Goto("a")), Goto("a")),
Bloc("a", Bloc("a",
Goto("b")), Goto("b")),
......
...@@ -248,9 +248,25 @@ func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *V ...@@ -248,9 +248,25 @@ func (b *Block) NewValue3(line int32, op Op, t Type, arg0, arg1, arg2 *Value) *V
} }
// ConstInt returns an int constant representing its argument. // ConstInt returns an int constant representing its argument.
func (f *Func) ConstInt(line int32, t Type, c int64) *Value { func (f *Func) ConstInt8(line int32, t Type, c int8) *Value {
// TODO: cache? // TODO: cache?
return f.Entry.NewValue0I(line, OpConst, t, c) return f.Entry.NewValue0I(line, OpConst8, t, int64(c))
}
func (f *Func) ConstInt16(line int32, t Type, c int16) *Value {
// TODO: cache?
return f.Entry.NewValue0I(line, OpConst16, t, int64(c))
}
func (f *Func) ConstInt32(line int32, t Type, c int32) *Value {
// TODO: cache?
return f.Entry.NewValue0I(line, OpConst32, t, int64(c))
}
func (f *Func) ConstInt64(line int32, t Type, c int64) *Value {
// TODO: cache?
return f.Entry.NewValue0I(line, OpConst64, t, c)
}
func (f *Func) ConstIntPtr(line int32, t Type, c int64) *Value {
// TODO: cache?
return f.Entry.NewValue0I(line, OpConstPtr, t, c)
} }
func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) } func (f *Func) Logf(msg string, args ...interface{}) { f.Config.Logf(msg, args...) }
......
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
// Bloc("exit", // Bloc("exit",
// Exit("mem")), // Exit("mem")),
// Bloc("deadblock", // Bloc("deadblock",
// Valu("deadval", OpConst, TypeBool, 0, true), // Valu("deadval", OpConstBool, TypeBool, 0, true),
// If("deadval", "deadblock", "exit"))) // If("deadval", "deadblock", "exit")))
// //
// and the Blocks or Values used in the Func can be accessed // and the Blocks or Values used in the Func can be accessed
...@@ -265,8 +265,8 @@ func TestArgs(t *testing.T) { ...@@ -265,8 +265,8 @@ func TestArgs(t *testing.T) {
c := NewConfig("amd64", DummyFrontend{t}) c := NewConfig("amd64", DummyFrontend{t})
fun := Fun(c, "entry", fun := Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("a", OpConst, TypeInt64, 14, nil), Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst, TypeInt64, 26, nil), Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Goto("exit")), Goto("exit")),
...@@ -288,8 +288,8 @@ func TestEquiv(t *testing.T) { ...@@ -288,8 +288,8 @@ func TestEquiv(t *testing.T) {
{ {
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("a", OpConst, TypeInt64, 14, nil), Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst, TypeInt64, 26, nil), Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Goto("exit")), Goto("exit")),
...@@ -297,8 +297,8 @@ func TestEquiv(t *testing.T) { ...@@ -297,8 +297,8 @@ func TestEquiv(t *testing.T) {
Exit("mem"))), Exit("mem"))),
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("a", OpConst, TypeInt64, 14, nil), Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst, TypeInt64, 26, nil), Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Goto("exit")), Goto("exit")),
...@@ -309,8 +309,8 @@ func TestEquiv(t *testing.T) { ...@@ -309,8 +309,8 @@ func TestEquiv(t *testing.T) {
{ {
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("a", OpConst, TypeInt64, 14, nil), Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst, TypeInt64, 26, nil), Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Goto("exit")), Goto("exit")),
...@@ -320,8 +320,8 @@ func TestEquiv(t *testing.T) { ...@@ -320,8 +320,8 @@ func TestEquiv(t *testing.T) {
Bloc("exit", Bloc("exit",
Exit("mem")), Exit("mem")),
Bloc("entry", Bloc("entry",
Valu("a", OpConst, TypeInt64, 14, nil), Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst, TypeInt64, 26, nil), Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Goto("exit"))), Goto("exit"))),
...@@ -354,14 +354,14 @@ func TestEquiv(t *testing.T) { ...@@ -354,14 +354,14 @@ func TestEquiv(t *testing.T) {
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("b", OpConst, TypeInt64, 26, nil), Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("a", OpConst, TypeInt64, 14, nil), Valu("a", OpConst64, TypeInt64, 14, nil),
Exit("mem"))), Exit("mem"))),
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("a", OpConst, TypeInt64, 14, nil), Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst, TypeInt64, 26, nil), Valu("b", OpConst64, TypeInt64, 26, nil),
Exit("mem"))), Exit("mem"))),
}, },
// value auxint different // value auxint different
...@@ -369,12 +369,12 @@ func TestEquiv(t *testing.T) { ...@@ -369,12 +369,12 @@ func TestEquiv(t *testing.T) {
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("a", OpConst, TypeInt64, 14, nil), Valu("a", OpConst64, TypeInt64, 14, nil),
Exit("mem"))), Exit("mem"))),
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("a", OpConst, TypeInt64, 26, nil), Valu("a", OpConst64, TypeInt64, 26, nil),
Exit("mem"))), Exit("mem"))),
}, },
// value aux different // value aux different
...@@ -382,12 +382,12 @@ func TestEquiv(t *testing.T) { ...@@ -382,12 +382,12 @@ func TestEquiv(t *testing.T) {
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("a", OpConst, TypeInt64, 0, 14), Valu("a", OpConst64, TypeInt64, 0, 14),
Exit("mem"))), Exit("mem"))),
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("a", OpConst, TypeInt64, 0, 26), Valu("a", OpConst64, TypeInt64, 0, 26),
Exit("mem"))), Exit("mem"))),
}, },
// value args different // value args different
...@@ -395,15 +395,15 @@ func TestEquiv(t *testing.T) { ...@@ -395,15 +395,15 @@ func TestEquiv(t *testing.T) {
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("a", OpConst, TypeInt64, 14, nil), Valu("a", OpConst64, TypeInt64, 14, nil),
Valu("b", OpConst, TypeInt64, 26, nil), Valu("b", OpConst64, TypeInt64, 26, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"), Valu("sum", OpAdd64, TypeInt64, 0, nil, "a", "b"),
Exit("mem"))), Exit("mem"))),
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem", OpArg, TypeMem, 0, ".mem"), Valu("mem", OpArg, TypeMem, 0, ".mem"),
Valu("a", OpConst, TypeInt64, 0, nil), Valu("a", OpConst64, TypeInt64, 0, nil),
Valu("b", OpConst, TypeInt64, 14, nil), Valu("b", OpConst64, TypeInt64, 14, nil),
Valu("sum", OpAdd64, TypeInt64, 0, nil, "b", "a"), Valu("sum", OpAdd64, TypeInt64, 0, nil, "b", "a"),
Exit("mem"))), Exit("mem"))),
}, },
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
(Rsh64 <t> x y) && y.Type.Size() == 8 -> (Rsh64 <t> x y) && y.Type.Size() == 8 ->
(SARQ <t> x (CMOVQCC <t> (SARQ <t> x (CMOVQCC <t>
(CMPQconst <TypeFlags> [64] y) (CMPQconst <TypeFlags> [64] y)
(Const <t> [63]) (MOVQconst <t> [63])
y)) y))
(Less64 x y) -> (SETL (CMPQ <TypeFlags> x y)) (Less64 x y) -> (SETL (CMPQ <TypeFlags> x y))
...@@ -116,16 +116,20 @@ ...@@ -116,16 +116,20 @@
(IsNonNil p) -> (SETNE (TESTQ <TypeFlags> p p)) (IsNonNil p) -> (SETNE (TESTQ <TypeFlags> p p))
(IsInBounds idx len) -> (SETB (CMPQ <TypeFlags> idx len)) (IsInBounds idx len) -> (SETB (CMPQ <TypeFlags> idx len))
(Move [size] dst src mem) -> (REPMOVSB dst src (Const <TypeUInt64> [size]) mem) (Move [size] dst src mem) -> (REPMOVSB dst src (MOVQconst <TypeUInt64> [size]) mem)
(Not x) -> (XORQconst [1] x) (Not x) -> (XORQconst [1] x)
(OffPtr [off] ptr) -> (ADDQconst [off] ptr) (OffPtr [off] ptr) -> (ADDQconst [off] ptr)
(Const <t> [val]) && t.IsInteger() -> (MOVQconst [val]) (Const8 [val]) -> (MOVBconst [val])
(Const <t>) && t.IsPtr() -> (MOVQconst [0]) // nil is the only const pointer (Const16 [val]) -> (MOVWconst [val])
(Const <t>) && t.IsBoolean() && !v.Aux.(bool) -> (MOVQconst [0]) (Const32 [val]) -> (MOVLconst [val])
(Const <t>) && t.IsBoolean() && v.Aux.(bool) -> (MOVQconst [1]) (Const64 [val]) -> (MOVQconst [val])
(ConstPtr [val]) -> (MOVQconst [val])
(ConstNil) -> (MOVQconst [0])
(ConstBool {b}) && !b.(bool) -> (MOVBconst [0])
(ConstBool {b}) && b.(bool) -> (MOVBconst [1])
(Addr {sym} base) -> (LEAQ {sym} base) (Addr {sym} base) -> (LEAQ {sym} base)
...@@ -226,15 +230,15 @@ ...@@ -226,15 +230,15 @@
// lower Zero instructions with word sizes // lower Zero instructions with word sizes
(Zero [0] _ mem) -> (Copy mem) (Zero [0] _ mem) -> (Copy mem)
(Zero [1] destptr mem) -> (MOVBstore destptr (Const <TypeInt8> [0]) mem) (Zero [1] destptr mem) -> (MOVBstore destptr (MOVBconst <TypeInt8> [0]) mem)
(Zero [2] destptr mem) -> (MOVWstore destptr (Const <TypeInt16> [0]) mem) (Zero [2] destptr mem) -> (MOVWstore destptr (MOVWconst <TypeInt16> [0]) mem)
(Zero [4] destptr mem) -> (MOVLstore destptr (Const <TypeInt32> [0]) mem) (Zero [4] destptr mem) -> (MOVLstore destptr (MOVLconst <TypeInt32> [0]) mem)
(Zero [8] destptr mem) -> (MOVQstore destptr (Const <TypeInt64> [0]) mem) (Zero [8] destptr mem) -> (MOVQstore destptr (MOVQconst <TypeInt64> [0]) mem)
// rewrite anything less than 4 words into a series of MOV[BWLQ] $0, ptr(off) instructions // rewrite anything less than 4 words into a series of MOV[BWLQ] $0, ptr(off) instructions
(Zero [size] destptr mem) && size < 4*8 -> (MOVXzero [size] destptr mem) (Zero [size] destptr mem) && size < 4*8 -> (MOVXzero [size] destptr mem)
// Use STOSQ to zero memory. Rewrite this into storing the words with REPSTOSQ and then filling in the remainder with linear moves // Use STOSQ to zero memory. Rewrite this into storing the words with REPSTOSQ and then filling in the remainder with linear moves
(Zero [size] destptr mem) && size >= 4*8 -> (Zero [size%8] (OffPtr <TypeUInt64> [size-(size%8)] destptr) (REPSTOSQ <TypeMem> destptr (Const <TypeUInt64> [size/8]) mem)) (Zero [size] destptr mem) && size >= 4*8 -> (Zero [size%8] (OffPtr <TypeUInt64> [size-(size%8)] destptr) (REPSTOSQ <TypeMem> destptr (MOVQconst <TypeUInt64> [size/8]) mem))
// Absorb InvertFlags into branches. // Absorb InvertFlags into branches.
(LT (InvertFlags cmp) yes no) -> (GT cmp yes no) (LT (InvertFlags cmp) yes no) -> (GT cmp yes no)
...@@ -249,8 +253,8 @@ ...@@ -249,8 +253,8 @@
(NE (InvertFlags cmp) yes no) -> (NE cmp yes no) (NE (InvertFlags cmp) yes no) -> (NE cmp yes no)
// get rid of >=64 code for constant shifts // get rid of >=64 code for constant shifts
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds(d, c) -> (Const [-1]) (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && inBounds(d, c) -> (MOVQconst [-1])
(SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds(d, c) -> (Const [0]) (SBBQcarrymask (CMPQconst [c] (MOVQconst [d]))) && !inBounds(d, c) -> (MOVQconst [0])
(ANDQconst [0] _) -> (MOVQconst [0]) (ANDQconst [0] _) -> (MOVQconst [0])
(ANDQconst [-1] x) -> (Copy x) (ANDQconst [-1] x) -> (Copy x)
(CMOVQCC (CMPQconst [c] (MOVQconst [d])) _ x) && inBounds(d, c) -> (Copy x) (CMOVQCC (CMPQconst [c] (MOVQconst [d])) _ x) && inBounds(d, c) -> (Copy x)
......
...@@ -138,12 +138,16 @@ func init() { ...@@ -138,12 +138,16 @@ func init() {
{name: "MOVLQSX", reg: gp11, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64 {name: "MOVLQSX", reg: gp11, asm: "MOVLQSX"}, // sign extend arg0 from int32 to int64
{name: "MOVLQZX", reg: gp11, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64 {name: "MOVLQZX", reg: gp11, asm: "MOVLQZX"}, // zero extend arg0 from int32 to int64
{name: "MOVQconst", reg: gp01}, // auxint {name: "MOVBconst", reg: gp01, asm: "MOVB"}, // 8 low bits of auxint
{name: "LEAQ", reg: gp11sb}, // arg0 + auxint + offset encoded in aux {name: "MOVWconst", reg: gp01, asm: "MOVW"}, // 16 low bits of auxint
{name: "LEAQ1", reg: gp21sb}, // arg0 + arg1 + auxint {name: "MOVLconst", reg: gp01, asm: "MOVL"}, // 32 low bits of auxint
{name: "LEAQ2", reg: gp21sb}, // arg0 + 2*arg1 + auxint {name: "MOVQconst", reg: gp01, asm: "MOVQ"}, // auxint
{name: "LEAQ4", reg: gp21sb}, // arg0 + 4*arg1 + auxint
{name: "LEAQ8", reg: gp21sb}, // arg0 + 8*arg1 + auxint {name: "LEAQ", reg: gp11sb}, // arg0 + auxint + offset encoded in aux
{name: "LEAQ1", reg: gp21sb}, // arg0 + arg1 + auxint
{name: "LEAQ2", reg: gp21sb}, // arg0 + 2*arg1 + auxint
{name: "LEAQ4", reg: gp21sb}, // arg0 + 4*arg1 + auxint
{name: "LEAQ8", reg: gp21sb}, // arg0 + 8*arg1 + auxint
{name: "MOVBload", reg: gpload, asm: "MOVB"}, // load byte from arg0+auxint. arg1=mem {name: "MOVBload", reg: gpload, asm: "MOVB"}, // load byte from arg0+auxint. arg1=mem
{name: "MOVBQSXload", reg: gpload, asm: "MOVBQSX"}, // ditto, extend to int64 {name: "MOVBQSXload", reg: gpload, asm: "MOVBQSX"}, // ditto, extend to int64
......
...@@ -20,31 +20,31 @@ ...@@ -20,31 +20,31 @@
// For now, the generated successors must be a permutation of the matched successors. // For now, the generated successors must be a permutation of the matched successors.
// constant folding // constant folding
(Add64 (Const [c]) (Const [d])) -> (Const [c+d]) (Add64 (Const64 [c]) (Const64 [d])) -> (Const64 [c+d])
(AddPtr (Const [c]) (Const [d])) -> (Const [c+d]) (AddPtr (ConstPtr [c]) (ConstPtr [d])) -> (ConstPtr [c+d])
(Mul64 (Const [c]) (Const [d])) -> (Const [c*d]) (Mul64 (Const64 [c]) (Const64 [d])) -> (Const64 [c*d])
(MulPtr (Const [c]) (Const [d])) -> (Const [c*d]) (MulPtr (ConstPtr [c]) (ConstPtr [d])) -> (ConstPtr [c*d])
(IsInBounds (Const [c]) (Const [d])) -> (Const {inBounds(c,d)}) (IsInBounds (ConstPtr [c]) (ConstPtr [d])) -> (ConstPtr {inBounds(c,d)})
// tear apart slices // tear apart slices
// TODO: anything that generates a slice needs to go in here. // TODO: anything that generates a slice needs to go in here.
(SlicePtr (Load ptr mem)) -> (Load ptr mem) (SlicePtr (Load ptr mem)) -> (Load ptr mem)
(SliceLen (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (Const <config.Uintptr> [config.PtrSize])) mem) (SliceLen (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (ConstPtr <config.Uintptr> [config.PtrSize])) mem)
(SliceCap (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (Const <config.Uintptr> [config.PtrSize*2])) mem) (SliceCap (Load ptr mem)) -> (Load (AddPtr <ptr.Type> ptr (ConstPtr <config.Uintptr> [config.PtrSize*2])) mem)
// slice and interface comparisons // slice and interface comparisons
// the frontend ensures that we can only compare against nil // the frontend ensures that we can only compare against nil
// start by putting nil on the right to simplify the other rules // start by putting nil on the right to simplify the other rules
(EqFat x y) && x.Op == OpConst && y.Op != OpConst -> (EqFat y x) (EqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (EqFat y x)
(NeqFat x y) && x.Op == OpConst && y.Op != OpConst -> (NeqFat y x) (NeqFat x y) && x.Op == OpConstNil && y.Op != OpConstNil -> (NeqFat y x)
// it suffices to check the first word (backing array for slices, dynamic type for interfaces) // it suffices to check the first word (backing array for slices, dynamic type for interfaces)
(EqFat (Load ptr mem) y) && y.Op == OpConst -> (EqPtr (Load <config.Uintptr> ptr mem) (Const <config.Uintptr> [0])) (EqFat (Load ptr mem) (ConstNil)) -> (EqPtr (Load <config.Uintptr> ptr mem) (ConstPtr <config.Uintptr> [0]))
(NeqFat (Load ptr mem) y) && y.Op == OpConst -> (NeqPtr (Load <config.Uintptr> ptr mem) (Const <config.Uintptr> [0])) (NeqFat (Load ptr mem) (ConstNil)) -> (NeqPtr (Load <config.Uintptr> ptr mem) (ConstPtr <config.Uintptr> [0]))
// indexing operations // indexing operations
// Note: bounds check has already been done // Note: bounds check has already been done
(ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex <v.Type.PtrTo()> ptr idx) mem) (ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex <v.Type.PtrTo()> ptr idx) mem)
(PtrIndex <t> ptr idx) -> (AddPtr ptr (MulPtr <config.Uintptr> idx (Const <config.Uintptr> [t.Elem().Size()]))) (PtrIndex <t> ptr idx) -> (AddPtr ptr (MulPtr <config.Uintptr> idx (ConstPtr <config.Uintptr> [t.Elem().Size()])))
(StructSelect [idx] (Load ptr mem)) -> (Load (OffPtr <v.Type.PtrTo()> [idx] ptr) mem) (StructSelect [idx] (Load ptr mem)) -> (Load (OffPtr <v.Type.PtrTo()> [idx] ptr) mem)
// big-object moves // big-object moves
...@@ -52,12 +52,12 @@ ...@@ -52,12 +52,12 @@
(Store dst (Load <t> src mem) mem) && t.Size() > 8 -> (Move [t.Size()] dst src mem) (Store dst (Load <t> src mem) mem) && t.Size() > 8 -> (Move [t.Size()] dst src mem)
// string ops // string ops
(Const <t> {s}) && t.IsString() -> (StringMake (Addr <TypeBytePtr> {config.fe.StringData(s.(string))} (SB <config.Uintptr>)) (Const <config.Uintptr> [int64(len(s.(string)))])) (ConstString {s}) -> (StringMake (Addr <TypeBytePtr> {config.fe.StringData(s.(string))} (SB <config.Uintptr>)) (ConstPtr <config.Uintptr> [int64(len(s.(string)))]))
(Load <t> ptr mem) && t.IsString() -> (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.PtrSize] ptr) mem)) (Load <t> ptr mem) && t.IsString() -> (StringMake (Load <TypeBytePtr> ptr mem) (Load <config.Uintptr> (OffPtr <TypeBytePtr> [config.PtrSize] ptr) mem))
(StringPtr (StringMake ptr _)) -> ptr (StringPtr (StringMake ptr _)) -> ptr
(StringLen (StringMake _ len)) -> len (StringLen (StringMake _ len)) -> len
(Store dst str mem) && str.Type.IsString() -> (Store (OffPtr <TypeBytePtr> [config.PtrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem)) (Store dst str mem) && str.Type.IsString() -> (Store (OffPtr <TypeBytePtr> [config.PtrSize] dst) (StringLen <config.Uintptr> str) (Store <TypeMem> dst (StringPtr <TypeBytePtr> str) mem))
(If (Not cond) yes no) -> (If cond no yes) (If (Not cond) yes no) -> (If cond no yes)
(If (Const {c}) yes no) && c.(bool) -> (Plain nil yes) (If (ConstBool {c}) yes no) && c.(bool) -> (Plain nil yes)
(If (Const {c}) yes no) && !c.(bool) -> (Plain nil no) (If (ConstBool {c}) yes no) && !c.(bool) -> (Plain nil no)
...@@ -115,7 +115,15 @@ var genericOps = []opData{ ...@@ -115,7 +115,15 @@ var genericOps = []opData{
// in the AuxInt field as an int64 (including int, uint64, etc.). // in the AuxInt field as an int64 (including int, uint64, etc.).
// For integer types smaller than 64 bits, only the low-order // For integer types smaller than 64 bits, only the low-order
// bits of the AuxInt field matter. // bits of the AuxInt field matter.
{name: "Const"}, {name: "ConstBool"},
{name: "ConstString"},
{name: "ConstNil"},
{name: "Const8"},
{name: "Const16"},
{name: "Const32"},
{name: "Const64"},
{name: "ConstPtr"}, // pointer-sized integer constant
// TODO: Const32F, ...
// Constant-like things // Constant-like things
{name: "Arg"}, // memory input to the function. {name: "Arg"}, // memory input to the function.
......
...@@ -81,6 +81,9 @@ func genRules(arch arch) { ...@@ -81,6 +81,9 @@ func genRules(arch arch) {
continue continue
} }
op := strings.Split(rule, " ")[0][1:] op := strings.Split(rule, " ")[0][1:]
if op[len(op)-1] == ')' {
op = op[:len(op)-1] // rule has only opcode, e.g. (ConstNil) -> ...
}
if isBlock(op, arch) { if isBlock(op, arch) {
blockrules[op] = append(blockrules[op], rule) blockrules[op] = append(blockrules[op], rule)
} else { } else {
......
...@@ -85,6 +85,9 @@ const ( ...@@ -85,6 +85,9 @@ const (
OpAMD64MOVWQZX OpAMD64MOVWQZX
OpAMD64MOVLQSX OpAMD64MOVLQSX
OpAMD64MOVLQZX OpAMD64MOVLQZX
OpAMD64MOVBconst
OpAMD64MOVWconst
OpAMD64MOVLconst
OpAMD64MOVQconst OpAMD64MOVQconst
OpAMD64LEAQ OpAMD64LEAQ
OpAMD64LEAQ1 OpAMD64LEAQ1
...@@ -214,7 +217,14 @@ const ( ...@@ -214,7 +217,14 @@ const (
OpNeg64 OpNeg64
OpPhi OpPhi
OpCopy OpCopy
OpConst OpConstBool
OpConstString
OpConstNil
OpConst8
OpConst16
OpConst32
OpConst64
OpConstPtr
OpArg OpArg
OpAddr OpAddr
OpSP OpSP
...@@ -685,8 +695,36 @@ var opcodeTable = [...]opInfo{ ...@@ -685,8 +695,36 @@ var opcodeTable = [...]opInfo{
}, },
}, },
}, },
{
name: "MOVBconst",
asm: x86.AMOVB,
reg: regInfo{
outputs: []regMask{
65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
},
},
},
{
name: "MOVWconst",
asm: x86.AMOVW,
reg: regInfo{
outputs: []regMask{
65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
},
},
},
{
name: "MOVLconst",
asm: x86.AMOVL,
reg: regInfo{
outputs: []regMask{
65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
},
},
},
{ {
name: "MOVQconst", name: "MOVQconst",
asm: x86.AMOVQ,
reg: regInfo{ reg: regInfo{
outputs: []regMask{ outputs: []regMask{
65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15 65519, // .AX .CX .DX .BX .BP .SI .DI .R8 .R9 .R10 .R11 .R12 .R13 .R14 .R15
...@@ -1546,7 +1584,35 @@ var opcodeTable = [...]opInfo{ ...@@ -1546,7 +1584,35 @@ var opcodeTable = [...]opInfo{
generic: true, generic: true,
}, },
{ {
name: "Const", name: "ConstBool",
generic: true,
},
{
name: "ConstString",
generic: true,
},
{
name: "ConstNil",
generic: true,
},
{
name: "Const8",
generic: true,
},
{
name: "Const16",
generic: true,
},
{
name: "Const32",
generic: true,
},
{
name: "Const64",
generic: true,
},
{
name: "ConstPtr",
generic: true, generic: true,
}, },
{ {
......
...@@ -12,8 +12,8 @@ func TestSchedule(t *testing.T) { ...@@ -12,8 +12,8 @@ func TestSchedule(t *testing.T) {
Fun(c, "entry", Fun(c, "entry",
Bloc("entry", Bloc("entry",
Valu("mem0", OpArg, TypeMem, 0, ".mem"), Valu("mem0", OpArg, TypeMem, 0, ".mem"),
Valu("ptr", OpConst, TypeInt64, 0xABCD, nil), Valu("ptr", OpConst64, TypeInt64, 0xABCD, nil),
Valu("v", OpConst, TypeInt64, 12, nil), Valu("v", OpConst64, TypeInt64, 12, nil),
Valu("mem1", OpStore, TypeMem, 0, nil, "ptr", "v", "mem0"), Valu("mem1", OpStore, TypeMem, 0, nil, "ptr", "v", "mem0"),
Valu("mem2", OpStore, TypeMem, 0, nil, "ptr", "v", "mem1"), Valu("mem2", OpStore, TypeMem, 0, nil, "ptr", "v", "mem1"),
Valu("mem3", OpStore, TypeInt64, 0, nil, "ptr", "sum", "mem2"), Valu("mem3", OpStore, TypeInt64, 0, nil, "ptr", "sum", "mem2"),
......
...@@ -33,7 +33,7 @@ func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun { ...@@ -33,7 +33,7 @@ func makeConstShiftFunc(c *Config, amount int64, op Op, typ Type) fun {
Valu("argptr", OpOffPtr, ptyp, 8, nil, "SP"), Valu("argptr", OpOffPtr, ptyp, 8, nil, "SP"),
Valu("resptr", OpOffPtr, ptyp, 16, nil, "SP"), Valu("resptr", OpOffPtr, ptyp, 16, nil, "SP"),
Valu("load", OpLoad, typ, 0, nil, "argptr", "mem"), Valu("load", OpLoad, typ, 0, nil, "argptr", "mem"),
Valu("c", OpConst, TypeUInt64, amount, nil), Valu("c", OpConst64, TypeUInt64, amount, nil),
Valu("shift", op, typ, 0, nil, "load", "c"), Valu("shift", op, typ, 0, nil, "load", "c"),
Valu("store", OpStore, TypeMem, 0, nil, "resptr", "shift", "mem"), Valu("store", OpStore, TypeMem, 0, nil, "resptr", "shift", "mem"),
Exit("store"))) Exit("store")))
......
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