Skip to content

Commit 2bb7081

Browse files
aykevldeadprogram
authored andcommitted
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
1 parent 293f4ea commit 2bb7081

File tree

5 files changed

+58
-1
lines changed

5 files changed

+58
-1
lines changed

compiler/compiler.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -762,6 +762,9 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package
762762
if !info.extern {
763763
global.SetInitializer(llvm.ConstNull(global.Type().ElementType()))
764764
global.SetVisibility(llvm.HiddenVisibility)
765+
if info.section != "" {
766+
global.SetSection(info.section)
767+
}
765768
}
766769
}
767770
}
@@ -787,6 +790,9 @@ func (b *builder) createFunction() {
787790
b.llvmFn.SetVisibility(llvm.HiddenVisibility)
788791
b.llvmFn.SetUnnamedAddr(true)
789792
}
793+
if b.info.section != "" {
794+
b.llvmFn.SetSection(b.info.section)
795+
}
790796
if b.info.exported && strings.HasPrefix(b.Triple, "wasm") {
791797
// Set the exported name. This is necessary for WebAssembly because
792798
// otherwise the function is not exported.

compiler/symbol.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ type functionInfo struct {
2424
module string // go:wasm-module
2525
importName string // go:linkname, go:export - The name the developer assigns
2626
linkName string // go:linkname, go:export - The name that we map for the particular module -> importName
27+
section string // go:section - object file section name
2728
exported bool // go:export, CGo
2829
nobounds bool // go:nobounds
2930
variadic bool // go:variadic (CGo only)
@@ -270,6 +271,10 @@ func (info *functionInfo) parsePragmas(f *ssa.Function) {
270271
if hasUnsafeImport(f.Pkg.Pkg) {
271272
info.linkName = parts[2]
272273
}
274+
case "//go:section":
275+
if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
276+
info.section = parts[1]
277+
}
273278
case "//go:nobounds":
274279
// Skip bounds checking in this function. Useful for some
275280
// runtime functions.
@@ -325,6 +330,7 @@ type globalInfo struct {
325330
linkName string // go:extern
326331
extern bool // go:extern
327332
align int // go:align
333+
section string // go:section
328334
}
329335

330336
// loadASTComments loads comments on globals from the AST, for use later in the
@@ -438,6 +444,10 @@ func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
438444
if err == nil {
439445
info.align = align
440446
}
447+
case "//go:section":
448+
if len(parts) == 2 {
449+
info.section = parts[1]
450+
}
441451
}
442452
}
443453
}

compiler/testdata/pragma.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,28 @@ func inlineFunc() {
3939
//go:noinline
4040
func noinlineFunc() {
4141
}
42+
43+
// This function should have the specified section.
44+
//go:section .special_function_section
45+
func functionInSection() {
46+
}
47+
48+
//export exportedFunctionInSection
49+
//go:section .special_function_section
50+
func exportedFunctionInSection() {
51+
}
52+
53+
// This function should not: it's only a declaration and not a definition.
54+
//go:section .special_function_section
55+
func undefinedFunctionNotInSection()
56+
57+
//go:section .special_global_section
58+
var globalInSection uint32
59+
60+
//go:section .special_global_section
61+
//go:extern undefinedGlobalNotInSection
62+
var undefinedGlobalNotInSection uint32
63+
64+
//go:align 1024
65+
//go:section .global_section
66+
var multipleGlobalPragmas uint32

compiler/testdata/pragma.ll

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@ target triple = "wasm32--wasi"
66
@extern_global = external global [0 x i8], align 1
77
@main.alignedGlobal = hidden global [4 x i32] zeroinitializer, align 32
88
@main.alignedGlobal16 = hidden global [4 x i32] zeroinitializer, align 16
9+
@main.globalInSection = hidden global i32 0, section ".special_global_section", align 4
10+
@undefinedGlobalNotInSection = external global i32, align 4
11+
@main.multipleGlobalPragmas = hidden global i32 0, section ".global_section", align 1024
912

1013
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
1114

@@ -38,6 +41,19 @@ entry:
3841
ret void
3942
}
4043

44+
define hidden void @main.functionInSection(i8* %context, i8* %parentHandle) unnamed_addr section ".special_function_section" {
45+
entry:
46+
ret void
47+
}
48+
49+
define void @exportedFunctionInSection() #3 section ".special_function_section" {
50+
entry:
51+
ret void
52+
}
53+
54+
declare void @main.undefinedFunctionNotInSection(i8*, i8*)
55+
4156
attributes #0 = { "wasm-export-name"="extern_func" }
4257
attributes #1 = { inlinehint }
4358
attributes #2 = { noinline }
59+
attributes #3 = { "wasm-export-name"="exportedFunctionInSection" }

transform/globals.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import "tinygo.org/x/go-llvm"
1111
func ApplyFunctionSections(mod llvm.Module) {
1212
llvmFn := mod.FirstFunction()
1313
for !llvmFn.IsNil() {
14-
if !llvmFn.IsDeclaration() {
14+
if !llvmFn.IsDeclaration() && llvmFn.Section() == "" {
1515
name := llvmFn.Name()
1616
llvmFn.SetSection(".text." + name)
1717
}

0 commit comments

Comments
 (0)