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 {
|
if !info.extern {
|
||||||
global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
|
global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
|
||||||
global.SetVisibility(llvm.HiddenVisibility)
|
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.SetVisibility(llvm.HiddenVisibility)
|
||||||
b.llvmFn.SetUnnamedAddr(true)
|
b.llvmFn.SetUnnamedAddr(true)
|
||||||
}
|
}
|
||||||
|
if b.info.section != "" {
|
||||||
|
b.llvmFn.SetSection(b.info.section)
|
||||||
|
}
|
||||||
if b.info.exported && strings.HasPrefix(b.Triple, "wasm") {
|
if b.info.exported && strings.HasPrefix(b.Triple, "wasm") {
|
||||||
// Set the exported name. This is necessary for WebAssembly because
|
// Set the exported name. This is necessary for WebAssembly because
|
||||||
// otherwise the function is not exported.
|
// otherwise the function is not exported.
|
||||||
|
|
|
@ -24,6 +24,7 @@ type functionInfo struct {
|
||||||
module string // go:wasm-module
|
module string // go:wasm-module
|
||||||
importName string // go:linkname, go:export - The name the developer assigns
|
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
|
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
|
exported bool // go:export, CGo
|
||||||
nobounds bool // go:nobounds
|
nobounds bool // go:nobounds
|
||||||
variadic bool // go:variadic (CGo only)
|
variadic bool // go:variadic (CGo only)
|
||||||
|
@ -270,6 +271,10 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
|
||||||
if hasUnsafeImport(f.Pkg.Pkg) {
|
if hasUnsafeImport(f.Pkg.Pkg) {
|
||||||
info.linkName = parts[2]
|
info.linkName = parts[2]
|
||||||
}
|
}
|
||||||
|
case "//go:section":
|
||||||
|
if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
|
||||||
|
info.section = parts[1]
|
||||||
|
}
|
||||||
case "//go:nobounds":
|
case "//go:nobounds":
|
||||||
// Skip bounds checking in this function. Useful for some
|
// Skip bounds checking in this function. Useful for some
|
||||||
// runtime functions.
|
// runtime functions.
|
||||||
|
@ -325,6 +330,7 @@ type globalInfo struct {
|
||||||
linkName string // go:extern
|
linkName string // go:extern
|
||||||
extern bool // go:extern
|
extern bool // go:extern
|
||||||
align int // go:align
|
align int // go:align
|
||||||
|
section string // go:section
|
||||||
}
|
}
|
||||||
|
|
||||||
// loadASTComments loads comments on globals from the AST, for use later in the
|
// 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 {
|
if err == nil {
|
||||||
info.align = align
|
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
|
//go:noinline
|
||||||
func noinlineFunc() {
|
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
|
@extern_global = external global [0 x i8], align 1
|
||||||
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
|
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
|
||||||
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
|
@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*)
|
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
|
||||||
|
|
||||||
|
@ -38,6 +41,19 @@ entry:
|
||||||
ret void
|
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 #0 = { "wasm-export-name"="extern_func" }
|
||||||
attributes #1 = { inlinehint }
|
attributes #1 = { inlinehint }
|
||||||
attributes #2 = { noinline }
|
attributes #2 = { noinline }
|
||||||
|
attributes #3 = { "wasm-export-name"="exportedFunctionInSection" }
|
||||||
|
|
|
@ -11,7 +11,7 @@ import "tinygo.org/x/go-llvm"
|
||||||
func ApplyFunctionSections(mod llvm.Module) {
|
func ApplyFunctionSections(mod llvm.Module) {
|
||||||
llvmFn := mod.FirstFunction()
|
llvmFn := mod.FirstFunction()
|
||||||
for !llvmFn.IsNil() {
|
for !llvmFn.IsNil() {
|
||||||
if !llvmFn.IsDeclaration() {
|
if !llvmFn.IsDeclaration() && llvmFn.Section() == "" {
|
||||||
name := llvmFn.Name()
|
name := llvmFn.Name()
|
||||||
llvmFn.SetSection(".text." + name)
|
llvmFn.SetSection(".text." + name)
|
||||||
}
|
}
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче