Skip to content

Commit

Permalink
go/ir: add SliceToArray op
Browse files Browse the repository at this point in the history
Closes gh-1335
  • Loading branch information
dominikh committed Dec 8, 2022
1 parent 4229c3d commit 39b8ce7
Show file tree
Hide file tree
Showing 7 changed files with 47 additions and 1 deletion.
1 change: 1 addition & 0 deletions go/ir/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@
// *Sigma ✔ ✔
// *Slice ✔ ✔
// *SliceToArrayPointer ✔ ✔
// *SliceToArray ✔ ✔
// *Store ✔ ✔
// *StringLookup ✔ ✔
// *Type ✔ (type)
Expand Down
19 changes: 19 additions & 0 deletions go/ir/emit.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,6 +279,25 @@ func emitConv(f *Function, val Value, t_dst types.Type, source ast.Node) Value {
return f.emit(c, source)
}

// Conversion from slice to array. This is almost the same as converting from slice to array pointer, then
// dereferencing the pointer. Except that a nil slice can be converted to [0]T, whereas converting a nil slice to
// (*[0]T) results in a nil pointer, dereferencing which would panic. To hide the extra branching we use a dedicated
// instruction, SliceToArray.
if tset_src.All(func(termSrc *types.Term) bool {
return tset_dst.All(func(termDst *types.Term) bool {
if slice, ok := termSrc.Type().Underlying().(*types.Slice); ok {
if arr, ok := termDst.Type().Underlying().(*types.Array); ok && types.Identical(slice.Elem(), arr.Elem()) {
return true
}
}
return false
})
}) {
c := &SliceToArray{X: val}
c.setType(t_dst)
return f.emit(c, source)
}

// A representation-changing conversion?
// At least one of {ut_src,ut_dst} must be *Basic.
// (The other may be []byte or []rune.)
Expand Down
4 changes: 4 additions & 0 deletions go/ir/lift.go
Original file line number Diff line number Diff line change
Expand Up @@ -1488,6 +1488,10 @@ func splitOnNewInformation(u *BasicBlock, renaming *StackMap) {
// A slice to array pointer conversion tells us the minimum length of the slice
rename(instr.X, instr, CopyInfoUnspecified, i)
i++
case *SliceToArray:
// A slice to array conversion tells us the minimum length of the slice
rename(instr.X, instr, CopyInfoUnspecified, i)
i++
case *Slice:
// Slicing tells us about some of the bounds
off := 0
Expand Down
1 change: 1 addition & 0 deletions go/ir/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ func (v *ChangeType) String() string { return printConv("ChangeType", v
func (v *Convert) String() string { return printConv("Convert", v, v.X) }
func (v *ChangeInterface) String() string { return printConv("ChangeInterface", v, v.X) }
func (v *SliceToArrayPointer) String() string { return printConv("SliceToArrayPointer", v, v.X) }
func (v *SliceToArray) String() string { return printConv("SliceToArray", v, v.X) }
func (v *MakeInterface) String() string { return printConv("MakeInterface", v, v.X) }

func (v *MakeClosure) String() string {
Expand Down
1 change: 1 addition & 0 deletions go/ir/sanity.go
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
case *ChangeInterface:
case *ChangeType:
case *SliceToArrayPointer:
case *SliceToArray:
case *Convert:
if _, ok := instr.X.Type().Underlying().(*types.Basic); !ok {
if _, ok := instr.Type().Underlying().(*types.Basic); !ok {
Expand Down
20 changes: 19 additions & 1 deletion go/ir/ssa.go
Original file line number Diff line number Diff line change
Expand Up @@ -927,13 +927,27 @@ type ChangeInterface struct {
// from an explicit conversion in the source.
//
// Example printed form:
// t1 = SliceToArrayPointer <*[4]byte> t1
//
// t2 = SliceToArrayPointer <*[4]byte> t1
type SliceToArrayPointer struct {
register
X Value
}

// The SliceToArray instruction yields the conversion of slice X to
// array.
//
// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
// from an explicit conversion in the source.
//
// Example printed form:
//
// t2 = SliceToArray <[4]byte> t1
type SliceToArray struct {
register
X Value
}

// MakeInterface constructs an instance of an interface type from a
// value of a concrete type.
//
Expand Down Expand Up @@ -1911,6 +1925,10 @@ func (v *SliceToArrayPointer) Operands(rands []*Value) []*Value {
return append(rands, &v.X)
}

func (v *SliceToArray) Operands(rands []*Value) []*Value {
return append(rands, &v.X)
}

func (s *DebugRef) Operands(rands []*Value) []*Value {
return append(rands, &s.X)
}
Expand Down
2 changes: 2 additions & 0 deletions unused/unused.go
Original file line number Diff line number Diff line change
Expand Up @@ -1789,6 +1789,8 @@ func (g *graph) instructions(fn *ir.Function) {
// nothing to do
case *ir.SliceToArrayPointer:
// nothing to do
case *ir.SliceToArray:
// nothing to do
case *ir.CompositeValue:
if t, ok := typeutil.CoreType(instr.Type()).(*types.Struct); ok {
for i := 0; i < len(instr.Values); i++ {
Expand Down

0 comments on commit 39b8ce7

Please sign in to comment.