[dev.ssa] cmd/compile/internal/ssa: implement ODOT
Implement ODOT. Similar to ArrayIndex, StructSelect selects a field
out of a larger Value.
We may need more ways to rewrite StructSelect, but StructSelect/Load
is the typical way it is used.
Change-Id: Ida7b8aab3298f4754eaf9fee733974cf8736e45d
Reviewed-on: https://go-review.googlesource.com/12265
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
diff --git a/src/cmd/compile/internal/gc/ssa.go b/src/cmd/compile/internal/gc/ssa.go
index 3ad21a6..2ba1ddb 100644
--- a/src/cmd/compile/internal/gc/ssa.go
+++ b/src/cmd/compile/internal/gc/ssa.go
@@ -226,6 +226,11 @@
return s.curBlock.NewValue1A(s.peekLine(), op, t, aux, arg)
}
+// newValue1I adds a new value with one argument and an auxint value to the current block.
+func (s *state) newValue1I(op ssa.Op, t ssa.Type, aux int64, arg *ssa.Value) *ssa.Value {
+ return s.curBlock.NewValue1I(s.peekLine(), op, t, aux, arg)
+}
+
// newValue2 adds a new value with two arguments to the current block.
func (s *state) newValue2(op ssa.Op, t ssa.Type, arg0, arg1 *ssa.Value) *ssa.Value {
return s.curBlock.NewValue2(s.peekLine(), op, t, arg0, arg1)
@@ -556,6 +561,10 @@
s.nilCheck(p)
return s.newValue2(ssa.OpLoad, n.Type, p, s.mem())
+ case ODOT:
+ v := s.expr(n.Left)
+ return s.newValue1I(ssa.OpStructSelect, n.Type, n.Xoffset, v)
+
case ODOTPTR:
p := s.expr(n.Left)
s.nilCheck(p)
diff --git a/src/cmd/compile/internal/ssa/gen/generic.rules b/src/cmd/compile/internal/ssa/gen/generic.rules
index 9f11a60..a906ec6 100644
--- a/src/cmd/compile/internal/ssa/gen/generic.rules
+++ b/src/cmd/compile/internal/ssa/gen/generic.rules
@@ -34,6 +34,7 @@
// Note: bounds check has already been done
(ArrayIndex (Load ptr mem) idx) -> (Load (PtrIndex <v.Type.PtrTo()> ptr idx) mem)
(PtrIndex <t> ptr idx) -> (Add ptr (Mul <config.Uintptr> idx (Const <config.Uintptr> [t.Elem().Size()])))
+(StructSelect [idx] (Load ptr mem)) -> (Load (OffPtr <v.Type.PtrTo()> [idx] ptr) mem)
// big-object moves
// TODO: fix size
diff --git a/src/cmd/compile/internal/ssa/gen/genericOps.go b/src/cmd/compile/internal/ssa/gen/genericOps.go
index 9155e00..0af7df1 100644
--- a/src/cmd/compile/internal/ssa/gen/genericOps.go
+++ b/src/cmd/compile/internal/ssa/gen/genericOps.go
@@ -71,9 +71,10 @@
{name: "IsInBounds"}, // 0 <= arg0 < arg1
// Indexing operations
- {name: "ArrayIndex"}, // arg0=array, arg1=index. Returns a[i]
- {name: "PtrIndex"}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
- {name: "OffPtr"}, // arg0 + auxint (arg0 and result are pointers)
+ {name: "ArrayIndex"}, // arg0=array, arg1=index. Returns a[i]
+ {name: "PtrIndex"}, // arg0=ptr, arg1=index. Computes ptr+sizeof(*v.type)*index, where index is extended to ptrwidth type
+ {name: "OffPtr"}, // arg0 + auxint (arg0 and result are pointers)
+ {name: "StructSelect"}, // arg0=struct, auxint=field offset. Returns field at that offset (size=size of result type)
// Slices
{name: "SliceMake"}, // arg0=ptr, arg1=len, arg2=cap
diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go
index 494f4ec..74d30e1 100644
--- a/src/cmd/compile/internal/ssa/opGen.go
+++ b/src/cmd/compile/internal/ssa/opGen.go
@@ -146,6 +146,7 @@
OpArrayIndex
OpPtrIndex
OpOffPtr
+ OpStructSelect
OpSliceMake
OpSlicePtr
OpSliceLen
@@ -1233,6 +1234,15 @@
generic: true,
},
{
+ name: "StructSelect",
+ reg: regInfo{
+ inputs: []regMask{},
+ clobbers: 0,
+ outputs: []regMask{},
+ },
+ generic: true,
+ },
+ {
name: "SliceMake",
reg: regInfo{
inputs: []regMask{},
diff --git a/src/cmd/compile/internal/ssa/rewritegeneric.go b/src/cmd/compile/internal/ssa/rewritegeneric.go
index 78cb2c8..ca523ee 100644
--- a/src/cmd/compile/internal/ssa/rewritegeneric.go
+++ b/src/cmd/compile/internal/ssa/rewritegeneric.go
@@ -383,6 +383,32 @@
}
goto end061edc5d85c73ad909089af2556d9380
end061edc5d85c73ad909089af2556d9380:
+ ;
+ case OpStructSelect:
+ // match: (StructSelect [idx] (Load ptr mem))
+ // cond:
+ // result: (Load (OffPtr <v.Type.PtrTo()> [idx] ptr) mem)
+ {
+ idx := v.AuxInt
+ if v.Args[0].Op != OpLoad {
+ goto end16fdb45e1dd08feb36e3cc3fb5ed8935
+ }
+ ptr := v.Args[0].Args[0]
+ mem := v.Args[0].Args[1]
+ v.Op = OpLoad
+ v.AuxInt = 0
+ v.Aux = nil
+ v.resetArgs()
+ v0 := v.Block.NewValue0(v.Line, OpOffPtr, TypeInvalid)
+ v0.Type = v.Type.PtrTo()
+ v0.AuxInt = idx
+ v0.AddArg(ptr)
+ v.AddArg(v0)
+ v.AddArg(mem)
+ return true
+ }
+ goto end16fdb45e1dd08feb36e3cc3fb5ed8935
+ end16fdb45e1dd08feb36e3cc3fb5ed8935:
}
return false
}