compiler: add function and global section pragmas
This patch adds a new pragma for functions and globals to set the section name. This can be useful to place a function or global in a special device specific section, for example: * Functions may be placed in RAM to make them run faster, or in flash (if RAM is the default) to not let them take up RAM. * DMA memory may only be placed in a special memory area. * Some RAM may be faster than other RAM, and some globals may be performance critical thus placing them in this special RAM area can help. * Some (large) global variables may need to be placed in external RAM, which can be done by placing them in a special section. To use it, you have to place a function or global in a special section, for example: //go:section .externalram var externalRAMBuffer [1024]byte This can then be placed in a special section of the linker script, for example something like this: .bss.extram (NOLOAD) : { *(.externalram) } > ERAM
Этот коммит содержится в:
родитель
293f4ea7bc
коммит
2bb70812a8
5 изменённых файлов: 58 добавлений и 1 удалений
|
@ -762,6 +762,9 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
|
|||
if !info.extern {
|
||||
global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
|
||||
global.SetVisibility(llvm.HiddenVisibility)
|
||||
if info.section != "" {
|
||||
global.SetSection(info.section)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -787,6 +790,9 @@ func (b *builder) createFunction() {
|
|||
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
|
||||
b.llvmFn.SetUnnamedAddr(true)
|
||||
}
|
||||
if b.info.section != "" {
|
||||
b.llvmFn.SetSection(b.info.section)
|
||||
}
|
||||
if b.info.exported && strings.HasPrefix(b.Triple, "wasm") {
|
||||
// Set the exported name. This is necessary for WebAssembly because
|
||||
// otherwise the function is not exported.
|
||||
|
|
|
@ -24,6 +24,7 @@ type functionInfo struct {
|
|||
module string // go:wasm-module
|
||||
importName string // go:linkname, go:export - The name the developer assigns
|
||||
linkName string // go:linkname, go:export - The name that we map for the particular module -> importName
|
||||
section string // go:section - object file section name
|
||||
exported bool // go:export, CGo
|
||||
nobounds bool // go:nobounds
|
||||
variadic bool // go:variadic (CGo only)
|
||||
|
@ -270,6 +271,10 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
|||
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||
info.linkName = parts[2]
|
||||
}
|
||||
case "//go:section":
|
||||
if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
|
||||
info.section = parts[1]
|
||||
}
|
||||
case "//go:nobounds":
|
||||
// Skip bounds checking in this function. Useful for some
|
||||
// runtime functions.
|
||||
|
@ -325,6 +330,7 @@ type globalInfo struct {
|
|||
linkName string // go:extern
|
||||
extern bool // go:extern
|
||||
align int // go:align
|
||||
section string // go:section
|
||||
}
|
||||
|
||||
// loadASTComments loads comments on globals from the AST, for use later in the
|
||||
|
@ -438,6 +444,10 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
|
|||
if err == nil {
|
||||
info.align = align
|
||||
}
|
||||
case "//go:section":
|
||||
if len(parts) == 2 {
|
||||
info.section = parts[1]
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
25
compiler/testdata/pragma.go
предоставленный
25
compiler/testdata/pragma.go
предоставленный
|
@ -39,3 +39,28 @@ func inlineFunc() {
|
|||
//go:noinline
|
||||
func noinlineFunc() {
|
||||
}
|
||||
|
||||
// This function should have the specified section.
|
||||
//go:section .special_function_section
|
||||
func functionInSection() {
|
||||
}
|
||||
|
||||
//export exportedFunctionInSection
|
||||
//go:section .special_function_section
|
||||
func exportedFunctionInSection() {
|
||||
}
|
||||
|
||||
// This function should not: it's only a declaration and not a definition.
|
||||
//go:section .special_function_section
|
||||
func undefinedFunctionNotInSection()
|
||||
|
||||
//go:section .special_global_section
|
||||
var globalInSection uint32
|
||||
|
||||
//go:section .special_global_section
|
||||
//go:extern undefinedGlobalNotInSection
|
||||
var undefinedGlobalNotInSection uint32
|
||||
|
||||
//go:align 1024
|
||||
//go:section .global_section
|
||||
var multipleGlobalPragmas uint32
|
||||
|
|
16
compiler/testdata/pragma.ll
предоставленный
16
compiler/testdata/pragma.ll
предоставленный
|
@ -6,6 +6,9 @@ target triple = "wasm32--wasi"
|
|||
@extern_global = external global [0 x i8], align 1
|
||||
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
|
||||
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
|
||||
@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4
|
||||
@undefinedGlobalNotInSection = external global i32, align 4
|
||||
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
|
||||
|
||||
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||
|
||||
|
@ -38,6 +41,19 @@ entry:
|
|||
ret void
|
||||
}
|
||||
|
||||
define hidden void @main.functionInSection(i8* %context, i8* %parentHandle) unnamed_addr section ".special_function_section" {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @exportedFunctionInSection() #3 section ".special_function_section" {
|
||||
entry:
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @main.undefinedFunctionNotInSection(i8*, i8*)
|
||||
|
||||
attributes #0 = { "wasm-export-name"="extern_func" }
|
||||
attributes #1 = { inlinehint }
|
||||
attributes #2 = { noinline }
|
||||
attributes #3 = { "wasm-export-name"="exportedFunctionInSection" }
|
||||
|
|
|
@ -11,7 +11,7 @@ import "tinygo.org/x/go-llvm"
|
|||
func ApplyFunctionSections(mod llvm.Module) {
|
||||
llvmFn := mod.FirstFunction()
|
||||
for !llvmFn.IsNil() {
|
||||
if !llvmFn.IsDeclaration() {
|
||||
if !llvmFn.IsDeclaration() && llvmFn.Section() == "" {
|
||||
name := llvmFn.Name()
|
||||
llvmFn.SetSection(".text." + name)
|
||||
}
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче