From 293f4ea7bc9858c219c75bd3c2bc88dea1d42b99 Mon Sep 17 00:00:00 2001 From: Ayke van Laethem Date: Tue, 30 Mar 2021 13:41:29 +0200 Subject: [PATCH] compiler: add tests for pragmas These pragmas weren't really tested anywhere, except that some code might break if they are not properly applied. These tests make it easy to see they work correctly and also provide a logical place to add new pragma tests. I've also made a slight change to how functions and globals are created: with the change they're also created in the IR even if they're not referenced. This makes testing easier. --- compiler/compiler.go | 6 +++--- compiler/compiler_test.go | 1 + compiler/testdata/pragma.go | 41 +++++++++++++++++++++++++++++++++++ compiler/testdata/pragma.ll | 43 +++++++++++++++++++++++++++++++++++++ 4 files changed, 88 insertions(+), 3 deletions(-) create mode 100644 compiler/testdata/pragma.go create mode 100644 compiler/testdata/pragma.ll diff --git a/compiler/compiler.go b/compiler/compiler.go index 925b61bf..a34d9848 100644 --- a/compiler/compiler.go +++ b/compiler/compiler.go @@ -715,11 +715,11 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package member := pkg.Members[name] switch member := member.(type) { case *ssa.Function: + // Create the function definition. + b := newBuilder(c, irbuilder, member) if member.Blocks == nil { continue // external function } - // Create the function definition. - b := newBuilder(c, irbuilder, member) b.createFunction() case *ssa.Type: if types.IsInterface(member.Type()) { @@ -758,8 +758,8 @@ func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package case *ssa.Global: // Global variable. info := c.getGlobalInfo(member) + global := c.getGlobal(member) if !info.extern { - global := c.getGlobal(member) global.SetInitializer(llvm.ConstNull(global.Type().ElementType())) global.SetVisibility(llvm.HiddenVisibility) } diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go index 4149e149..45d5b8c3 100644 --- a/compiler/compiler_test.go +++ b/compiler/compiler_test.go @@ -45,6 +45,7 @@ func TestCompiler(t *testing.T) { {"float.go", ""}, {"interface.go", ""}, {"func.go", ""}, + {"pragma.go", ""}, {"goroutine.go", "wasm"}, {"goroutine.go", "cortex-m-qemu"}, } diff --git a/compiler/testdata/pragma.go b/compiler/testdata/pragma.go new file mode 100644 index 00000000..505e78a9 --- /dev/null +++ b/compiler/testdata/pragma.go @@ -0,0 +1,41 @@ +package main + +import _ "unsafe" + +// Creates an external global with name extern_global. +//go:extern extern_global +var externGlobal [0]byte + +// Creates a +//go:align 32 +var alignedGlobal [4]uint32 + +// Test conflicting pragmas (the last one counts). +//go:align 64 +//go:align 16 +var alignedGlobal16 [4]uint32 + +// Test exported functions. +//export extern_func +func externFunc() { +} + +// Define a function in a different package using go:linkname. +//go:linkname withLinkageName1 somepkg.someFunction1 +func withLinkageName1() { +} + +// Import a function from a different package using go:linkname. +//go:linkname withLinkageName2 somepkg.someFunction2 +func withLinkageName2() + +// Function has an 'inline hint', similar to the inline keyword in C. +//go:inline +func inlineFunc() { +} + +// Function should never be inlined, equivalent to GCC +// __attribute__((noinline)). +//go:noinline +func noinlineFunc() { +} diff --git a/compiler/testdata/pragma.ll b/compiler/testdata/pragma.ll new file mode 100644 index 00000000..0fdc753e --- /dev/null +++ b/compiler/testdata/pragma.ll @@ -0,0 +1,43 @@ +; ModuleID = 'pragma.go' +source_filename = "pragma.go" +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +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 + +declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) + +define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr { +entry: + ret void +} + +define void @extern_func() #0 { +entry: + ret void +} + +define hidden void @somepkg.someFunction1(i8* %context, i8* %parentHandle) unnamed_addr { +entry: + ret void +} + +declare void @somepkg.someFunction2(i8*, i8*) + +; Function Attrs: inlinehint +define hidden void @main.inlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #1 { +entry: + ret void +} + +; Function Attrs: noinline +define hidden void @main.noinlineFunc(i8* %context, i8* %parentHandle) unnamed_addr #2 { +entry: + ret void +} + +attributes #0 = { "wasm-export-name"="extern_func" } +attributes #1 = { inlinehint } +attributes #2 = { noinline }