diff --git a/compiler/compiler.go b/compiler/compiler.go index a31c4d7d..5f09e54a 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -828,6 +828,14 @@ func (c *Compiler) parseFunc(frame *Frame) { frame.fn.LLVMFn.SetFunctionCallConv(85) // CallingConv::AVR_SIGNAL } + // Some functions have a pragma controlling the inlining level. + switch frame.fn.Inline() { + case ir.InlineHint: + // Add LLVM inline hint to functions with //go:inline pragma. + inline := c.ctx.CreateEnumAttribute(llvm.AttributeKindID("inlinehint"), 0) + frame.fn.LLVMFn.AddFunctionAttr(inline) + } + // Add debug info, if needed. if c.Debug { if frame.fn.Synthetic == "package initializer" { diff --git a/ir/ir.go b/ir/ir.go index 3e93e243..27a7b0fa 100644 --- a/ir/ir.go +++ b/ir/ir.go @@ -33,11 +33,12 @@ type Program struct { type Function struct { *ssa.Function LLVMFn llvm.Value - linkName string // go:linkname, go:export, go:interrupt - exported bool // go:export - nobounds bool // go:nobounds - flag bool // used by dead code elimination - interrupt bool // go:interrupt + linkName string // go:linkname, go:export, go:interrupt + exported bool // go:export + nobounds bool // go:nobounds + flag bool // used by dead code elimination + interrupt bool // go:interrupt + inline InlineType // go:inline } // Global variable, possibly constant. @@ -69,6 +70,21 @@ type Interface struct { Type *types.Interface } +type InlineType int + +// How much to inline. +const ( + // Default behavior. The compiler decides for itself whether any given + // function will be inlined. Whether any function is inlined depends on the + // optimization level. + InlineDefault InlineType = iota + + // Inline hint, just like the C inline keyword (signalled using + // //go:inline). The compiler will be more likely to inline this function, + // but it is not a guarantee. + InlineHint +) + // Create and initialize a new *Program from a *ssa.Program. func NewProgram(lprogram *loader.Program, mainPath string) *Program { comments := map[string]*ast.CommentGroup{} @@ -279,6 +295,8 @@ func (f *Function) parsePragmas() { } f.linkName = parts[1] f.exported = true + case "//go:inline": + f.inline = InlineHint case "//go:interrupt": if len(parts) != 2 { continue @@ -332,6 +350,11 @@ func (f *Function) IsInterrupt() bool { return f.interrupt } +// Return the inline directive of this function. +func (f *Function) Inline() InlineType { + return f.inline +} + // Return the link name for this function. func (f *Function) LinkName() string { if f.linkName != "" {