diff --git a/compiler/compiler.go b/compiler/compiler.go index 70951c7a..b4cb5dc8 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -629,6 +629,18 @@ func (c *Compiler) parseFuncDecl(f *ir.Function) *Frame { frame.fn.LLVMFn = llvm.AddFunction(c.mod, name, fnType) } + // External/exported functions may not retain pointer values. + // https://golang.org/cmd/cgo/#hdr-Passing_pointers + if f.IsExported() { + nocaptureKind := llvm.AttributeKindID("nocapture") + nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0) + for i, typ := range paramTypes { + if typ.TypeKind() == llvm.PointerTypeKind { + frame.fn.LLVMFn.AddAttributeAtIndex(i+1, nocapture) + } + } + } + return frame } diff --git a/compiler/optimizer.go b/compiler/optimizer.go index d412b97b..4efea247 100644 --- a/compiler/optimizer.go +++ b/compiler/optimizer.go @@ -307,18 +307,6 @@ func (c *Compiler) doesEscape(value llvm.Value) bool { return true } } else if use.IsACallInst() != nilValue { - // Call only escapes when the (pointer) parameter is not marked - // "nocapture". This flag means that the parameter does not escape - // the give function. - if use.CalledValue().IsAFunction() != nilValue { - if use.CalledValue().IsDeclaration() { - // Kind of dirty: assume external functions don't let - // pointers escape. - // TODO: introduce //go:noescape that sets the 'nocapture' - // flag on each input parameter. - continue - } - } if !c.hasFlag(use, value, "nocapture") { return true }