diff --git a/compiler/compiler.go b/compiler/compiler.go index bf897537..ba8d77ac 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -1135,6 +1135,9 @@ func (c *Compiler) parseFunc(frame *Frame) error { if !frame.fn.IsExported() { frame.fn.LLVMFn.SetLinkage(llvm.InternalLinkage) } + if frame.fn.IsInterrupt() && strings.HasPrefix(c.Triple, "avr") { + frame.fn.LLVMFn.SetFunctionCallConv(85) // CallingConv::AVR_SIGNAL + } if c.Debug { pos := c.ir.Program.Fset.Position(frame.fn.Pos()) diff --git a/ir/ir.go b/ir/ir.go index 9f0fc814..76dce610 100644 --- a/ir/ir.go +++ b/ir/ir.go @@ -40,11 +40,12 @@ type Program struct { type Function struct { *ssa.Function LLVMFn llvm.Value - linkName string // go:linkname or go:export pragma + linkName string // go:linkname, go:export, go:interrupt exported bool // go:export - nobounds bool // go:nobounds pragma + nobounds bool // go:nobounds blocking bool // calculated by AnalyseBlockingRecursive flag bool // used by dead code elimination + interrupt bool // go:interrupt addressTaken bool // used as function pointer, calculated by AnalyseFunctionPointers parents []*Function // calculated by AnalyseCallgraph children []*Function // calculated by AnalyseCallgraph @@ -298,6 +299,18 @@ func (f *Function) parsePragmas() { } f.linkName = parts[1] f.exported = true + case "//go:interrupt": + if len(parts) != 2 { + continue + } + name := parts[1] + if strings.HasSuffix(name, "_vect") { + // AVR vector naming + name = "__vector_" + name[:len(name)-5] + } + f.linkName = name + f.exported = true + f.interrupt = true case "//go:linkname": if len(parts) != 3 || parts[1] != f.Name() { continue @@ -331,6 +344,14 @@ func (f *Function) IsExported() bool { return f.exported } +// Return true for functions annotated with //go:interrupt. The function name is +// already customized in LinkName() to hook up in the interrupt vector. +// +// On some platforms (like AVR), interrupts need a special compiler flag. +func (f *Function) IsInterrupt() bool { + return f.exported +} + // Return the link name for this function. func (f *Function) LinkName() string { if f.linkName != "" { diff --git a/ir/passes.go b/ir/passes.go index 87175fae..9955658f 100644 --- a/ir/passes.go +++ b/ir/passes.go @@ -266,7 +266,7 @@ func (p *Program) SimpleDCE() { p.GetFunction(main).flag = true worklist := []*ssa.Function{main} for _, f := range p.Functions { - if f.Synthetic == "package initializer" || f.Pkg == runtimePkg { + if f.exported || f.Synthetic == "package initializer" || f.Pkg == runtimePkg { if f.flag || isCGoInternal(f.Name()) { continue }