Skip to content

Commit

Permalink
go/ir: add SliceToArrayPointer op
Browse files Browse the repository at this point in the history
This is a backport of golang.org/cl/333749 and golang.org/cl/348511.

Updates: gh-1045
Closes: gh-1081 [via git-merge-pr]
Co-authored-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
(cherry picked from commit 61e00c9)
  • Loading branch information
dominikh committed Nov 11, 2021
1 parent f9cde0a commit c8e3104
Show file tree
Hide file tree
Showing 9 changed files with 125 additions and 65 deletions.
7 changes: 7 additions & 0 deletions analysis/facts/nilness/nilness.go
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,13 @@ func impl(pass *analysis.Pass, fn *ir.Function, seenFns map[*ir.Function]struct{
return mightReturnNil(v.X)
case *ir.Convert:
return mightReturnNil(v.X)
case *ir.SliceToArrayPointer:
if v.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Len() == 0 {
return mightReturnNil(v.X)
} else {
// converting a slice to an array pointer of length > 0 panics if the slice is nil
return neverNil
}
case *ir.Slice:
return mightReturnNil(v.X)
case *ir.Phi:
Expand Down
36 changes: 36 additions & 0 deletions analysis/facts/nilness/testdata/src/Nilness/Nilness.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,3 +101,39 @@ func fn20() *int {
}
return nil
}

func fn21() *[5]int { // want fn21:`never returns nil: \[never\]`
var x []int
return (*[5]int)(x)
}

func fn22() *[0]int {
var x []int
return (*[0]int)(x)
}

func fn23() *[5]int { // want fn23:`never returns nil: \[never\]`
var x []int
type T [5]int
ret := (*T)(x)
return (*[5]int)(ret)
}

func fn24() *[0]int {
var x []int
type T [0]int
ret := (*T)(x)
return (*[0]int)(ret)
}

func fn25() *[5]int { // want fn25:`never returns nil: \[never\]`
var x []int
type T *[5]int
return (T)(x)
}

func fn26() *[0]int {
var x []int
type T *[0]int
return (T)(x)
}
2 changes: 1 addition & 1 deletion go/ir/UPSTREAM
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,5 @@ The changes are too many to list here, and it is best to consider this package i
Upstream changes still get applied when they address bugs in portions of code we have inherited.

The last upstream commit we've looked at was:
640c1dea83015e5271a001c99370762fc63dc280
915f6209478fe61eb90dbe155a8a1c58655b931f

99 changes: 50 additions & 49 deletions go/ir/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,55 +49,56 @@
// concrete type which of these interfaces it implements.
//
// Value? Instruction? Member?
// *Alloc ✔ ✔
// *BinOp ✔ ✔
// *BlankStore ✔
// *Builtin ✔
// *Call ✔ ✔
// *ChangeInterface ✔ ✔
// *ChangeType ✔ ✔
// *Const ✔ ✔
// *Convert ✔ ✔
// *DebugRef ✔
// *Defer ✔ ✔
// *Extract ✔ ✔
// *Field ✔ ✔
// *FieldAddr ✔ ✔
// *FreeVar ✔
// *Function ✔ ✔ (func)
// *Global ✔ ✔ (var)
// *Go ✔ ✔
// *If ✔
// *Index ✔ ✔
// *IndexAddr ✔ ✔
// *Jump ✔
// *Load ✔ ✔
// *MakeChan ✔ ✔
// *MakeClosure ✔ ✔
// *MakeInterface ✔ ✔
// *MakeMap ✔ ✔
// *MakeSlice ✔ ✔
// *MapLookup ✔ ✔
// *MapUpdate ✔ ✔
// *NamedConst ✔ (const)
// *Next ✔ ✔
// *Panic ✔
// *Parameter ✔ ✔
// *Phi ✔ ✔
// *Range ✔ ✔
// *Recv ✔ ✔
// *Return ✔
// *RunDefers ✔
// *Select ✔ ✔
// *Send ✔ ✔
// *Sigma ✔ ✔
// *Slice ✔ ✔
// *Store ✔ ✔
// *StringLookup ✔ ✔
// *Type ✔ (type)
// *TypeAssert ✔ ✔
// *UnOp ✔ ✔
// *Unreachable ✔
// *Alloc ✔ ✔
// *BinOp ✔ ✔
// *BlankStore ✔
// *Builtin ✔
// *Call ✔ ✔
// *ChangeInterface ✔ ✔
// *ChangeType ✔ ✔
// *Const ✔ ✔
// *Convert ✔ ✔
// *DebugRef ✔
// *Defer ✔ ✔
// *Extract ✔ ✔
// *Field ✔ ✔
// *FieldAddr ✔ ✔
// *FreeVar ✔
// *Function ✔ ✔ (func)
// *Global ✔ ✔ (var)
// *Go ✔ ✔
// *If ✔
// *Index ✔ ✔
// *IndexAddr ✔ ✔
// *Jump ✔
// *Load ✔ ✔
// *MakeChan ✔ ✔
// *MakeClosure ✔ ✔
// *MakeInterface ✔ ✔
// *MakeMap ✔ ✔
// *MakeSlice ✔ ✔
// *MapLookup ✔ ✔
// *MapUpdate ✔ ✔
// *NamedConst ✔ (const)
// *Next ✔ ✔
// *Panic ✔
// *Parameter ✔ ✔
// *Phi ✔ ✔
// *Range ✔ ✔
// *Recv ✔ ✔
// *Return ✔
// *RunDefers ✔
// *Select ✔ ✔
// *Send ✔ ✔
// *Sigma ✔ ✔
// *Slice ✔ ✔
// *SliceToArrayPointer ✔ ✔
// *Store ✔ ✔
// *StringLookup ✔ ✔
// *Type ✔ (type)
// *TypeAssert ✔ ✔
// *UnOp ✔ ✔
// *Unreachable ✔
//
// Other key types in this package include: Program, Package, Function
// and BasicBlock.
Expand Down
4 changes: 2 additions & 2 deletions go/ir/emit.go
Original file line number Diff line number Diff line change
Expand Up @@ -239,8 +239,8 @@ func emitConv(f *Function, val Value, typ types.Type, source ast.Node) Value {
// Conversion from slice to array pointer?
if slice, ok := ut_src.(*types.Slice); ok {
if ptr, ok := ut_dst.(*types.Pointer); ok {
if arr, ok := ptr.Elem().(*types.Array); ok && types.Identical(slice.Elem(), arr.Elem()) {
c := &Convert{X: val}
if arr, ok := ptr.Elem().Underlying().(*types.Array); ok && types.Identical(slice.Elem(), arr.Elem()) {
c := &SliceToArrayPointer{X: val}
c.setType(ut_dst)
return f.emit(c, source)
}
Expand Down
9 changes: 5 additions & 4 deletions go/ir/print.go
Original file line number Diff line number Diff line change
Expand Up @@ -162,10 +162,11 @@ func printConv(prefix string, v, x Value) string {
relName(x, v.(Instruction)))
}

func (v *ChangeType) String() string { return printConv("ChangeType", v, v.X) }
func (v *Convert) String() string { return printConv("Convert", v, v.X) }
func (v *ChangeInterface) String() string { return printConv("ChangeInterface", v, v.X) }
func (v *MakeInterface) String() string { return printConv("MakeInterface", v, v.X) }
func (v *ChangeType) String() string { return printConv("ChangeType", v, v.X) }
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 *MakeInterface) String() string { return printConv("MakeInterface", v, v.X) }

func (v *MakeClosure) String() string {
from := v.Parent().pkg()
Expand Down
8 changes: 1 addition & 7 deletions go/ir/sanity.go
Original file line number Diff line number Diff line change
Expand Up @@ -141,14 +141,8 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
case *Call:
case *ChangeInterface:
case *ChangeType:
case *SliceToArrayPointer:
case *Convert:
if _, ok := instr.X.Type().Underlying().(*types.Slice); ok {
if ptr, ok := instr.Type().Underlying().(*types.Pointer); ok {
if _, ok := ptr.Elem().(*types.Array); ok {
break
}
}
}
if _, ok := instr.X.Type().Underlying().(*types.Basic); !ok {
if _, ok := instr.Type().Underlying().(*types.Basic); !ok {
s.errorf("convert %s -> %s: at least one type must be basic", instr.X.Type(), instr.Type())
Expand Down
21 changes: 20 additions & 1 deletion go/ir/ssa.go
Original file line number Diff line number Diff line change
Expand Up @@ -729,9 +729,10 @@ type ChangeType struct {
// - between pointers and unsafe.Pointer.
// - between unsafe.Pointer and uintptr.
// - from (Unicode) integer to (UTF-8) string.
// - from slice to array pointer.
// A conversion may imply a type name change also.
//
// This operation cannot fail dynamically.
//
// Conversions of untyped string/number/bool constants to a specific
// representation are eliminated during IR construction.
//
Expand Down Expand Up @@ -763,6 +764,20 @@ type ChangeInterface struct {
X Value
}

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

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

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

func (s *DebugRef) Operands(rands []*Value) []*Value {
return append(rands, &s.X)
}
Expand Down
4 changes: 3 additions & 1 deletion unused/unused.go
Original file line number Diff line number Diff line change
Expand Up @@ -1661,8 +1661,10 @@ func (g *graph) instructions(fn *ir.Function) {
// nothing to do
case *ir.ConstantSwitch:
// nothing to do
case *ir.SliceToArrayPointer:
// nothing to do
default:
panic(fmt.Sprintf("unreachable: %T", instr))
lint.ExhaustiveTypeSwitch(instr)
}
}
}
Expand Down

0 comments on commit c8e3104

Please sign in to comment.