@@ -154,9 +154,18 @@ func valueEscapesAt(value llvm.Value) llvm.Value {
154154 return use
155155 }
156156 case llvm .Call :
157- if ! hasFlag (use , value , "nocapture" ) {
158- return use
157+ if hasFlag (use , value , "nocapture" ) {
158+ break
159+ }
160+ // If built-in append function escapes its first argument if and
161+ // only if the returned slice pointer escapes.
162+ if fn := use .CalledValue (); ! fn .IsAFunction ().IsNil () && fn .Name () == "runtime.sliceAppend" {
163+ if at := elemEscapesAt (use , 0 ); ! at .IsNil () {
164+ return at
165+ }
166+ break
159167 }
168+ return use
160169 case llvm .ICmp :
161170 // Comparing pointers don't let the pointer escape.
162171 // This is often a compiler-inserted nil check.
@@ -170,6 +179,32 @@ func valueEscapesAt(value llvm.Value) llvm.Value {
170179 return llvm.Value {}
171180}
172181
182+ // elemEscapesAt is like valueEscapesAt, but for an element of a tuple value.
183+ func elemEscapesAt (value llvm.Value , elemIndex uint32 ) llvm.Value {
184+ uses := getUses (value )
185+ for _ , use := range uses {
186+ if use .IsAInstruction ().IsNil () {
187+ panic ("expected instruction use" )
188+ }
189+ switch use .InstructionOpcode () {
190+ case llvm .ExtractValue :
191+ for _ , ind := range use .Indices () {
192+ if ind == elemIndex {
193+ if at := valueEscapesAt (use ); ! at .IsNil () {
194+ return at
195+ }
196+ break
197+ }
198+ }
199+ default :
200+ if at := valueEscapesAt (use ); ! at .IsNil () {
201+ return at
202+ }
203+ }
204+ }
205+ return llvm.Value {}
206+ }
207+
173208// logAlloc prints a message to stderr explaining why the given object had to be
174209// allocated on the heap.
175210func logAlloc (logger func (token.Position , string ), allocCall llvm.Value , reason string ) {
0 commit comments