From 7ed6b45149fdcff29f3149b8bc5a5d7fc857077d Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Sun, 7 Jul 2019 15:51:52 +0200 Subject: [PATCH] compiler: add the //go:noinline pragma This is directly useful to avoid some unsafety around runtime.alloc and should be useful in general. This pragma has the same form as in the main Go compiler: https://github.com/golang/go/issues/12312 --- compiler/compiler.go | 4 ++++ ir/ir.go | 6 ++++++ src/runtime/gc_conservative.go | 1 + 3 files changed, 11 insertions(+) diff --git a/compiler/compiler.go b/compiler/compiler.go index 82aaee36..1800f462 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -865,6 +865,10 @@ func (c *Compiler) parseFunc(frame *Frame) { // Add LLVM inline hint to functions with //go:inline pragma. inline := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("inlinehint"), 0) frame.fn.LLVMFn.AddFunctionAttr(inline) + case ir.InlineNone: + // Add LLVM attribute to always avoid inlining this function. + noinline := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noinline"), 0) + frame.fn.LLVMFn.AddFunctionAttr(noinline) } // Add debug info, if needed. diff --git a/ir/ir.go b/ir/ir.go index d9d5764e..f6917356 100644 --- a/ir/ir.go +++ b/ir/ir.go @@ -56,6 +56,10 @@ const ( // //go:inline). The compiler will be more likely to inline this function, // but it is not a guarantee. InlineHint + + // Don't inline, just like the GCC noinline attribute. Signalled using + // //go:noinline. + InlineNone ) // Create and initialize a new *Program from a *ssa.Program. @@ -227,6 +231,8 @@ func (f *Function) parsePragmas() { f.exported = true case "//go:inline": f.inline = InlineHint + case "//go:noinline": + f.inline = InlineNone case "//go:interrupt": if len(parts) != 2 { continue diff --git a/src/runtime/gc_conservative.go b/src/runtime/gc_conservative.go index c8cb535a..6b5b7a5c 100644 --- a/src/runtime/gc_conservative.go +++ b/src/runtime/gc_conservative.go @@ -203,6 +203,7 @@ func init() { // alloc tries to find some free space on the heap, possibly doing a garbage // collection cycle if needed. If no space is free, it panics. +//go:noinline func alloc(size uintptr) unsafe.Pointer { if size == 0 { return unsafe.Pointer(&zeroSizedAlloc)