compiler: add "target-cpu" and "target-features" attributes

This matches Clang, and with that, it adds support for inlining between
Go and C because LLVM only allows inlining if the "target-cpu" and
"target-features" string attributes match.

For example, take a look at the following code:

    // int add(int a, int b) {
    //   return a + b;
    // }
    import "C"

    func main() {
        println(C.add(3, 5))
    }

The 'add' function is not inlined into the main function before this
commit, but after it, it can be inlined and trivially be optimized to
`println(8)`.
Этот коммит содержится в:
Ayke van Laethem 2021-11-07 15:33:44 +01:00 коммит произвёл Ron Evans
родитель 78fec3719f
коммит cf640290a3
6 изменённых файлов: 23 добавлений и 7 удалений

Просмотреть файл

@ -23,7 +23,7 @@ import (
// Version of the compiler pacakge. Must be incremented each time the compiler // Version of the compiler pacakge. Must be incremented each time the compiler
// package changes in a way that affects the generated LLVM module. // package changes in a way that affects the generated LLVM module.
// This version is independent of the TinyGo version number. // This version is independent of the TinyGo version number.
const Version = 24 // last change: add layout param to runtime.alloc calls const Version = 25 // last change: add "target-cpu" and "target-features" attributes
func init() { func init() {
llvm.InitializeAllTargets() llvm.InitializeAllTargets()

Просмотреть файл

@ -346,6 +346,12 @@ func (c *compilerContext) addStandardDeclaredAttributes(llvmFn llvm.Value) {
attr := c.ctx.CreateEnumAttribute(kind, 0) attr := c.ctx.CreateEnumAttribute(kind, 0)
llvmFn.AddFunctionAttr(attr) llvmFn.AddFunctionAttr(attr)
} }
if c.CPU != "" {
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("target-cpu", c.CPU))
}
if c.Features != "" {
llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("target-features", c.Features))
}
} }
// addStandardDefinedAttributes adds the set of attributes that are added to // addStandardDefinedAttributes adds the set of attributes that are added to

Просмотреть файл

@ -3,7 +3,6 @@ package transform_test
import ( import (
"testing" "testing"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/transform" "github.com/tinygo-org/tinygo/transform"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@ -11,7 +10,7 @@ import (
func TestInterfaceLowering(t *testing.T) { func TestInterfaceLowering(t *testing.T) {
t.Parallel() t.Parallel()
testTransform(t, "testdata/interface", func(mod llvm.Module) { testTransform(t, "testdata/interface", func(mod llvm.Module) {
err := transform.LowerInterfaces(mod, &compileopts.Config{Options: &compileopts.Options{Opt: "2"}}) err := transform.LowerInterfaces(mod, defaultTestConfig)
if err != nil { if err != nil {
t.Error(err) t.Error(err)
} }

Просмотреть файл

@ -21,11 +21,18 @@ import (
// attributes to a function. For example, it adds optsize when requested from // attributes to a function. For example, it adds optsize when requested from
// the -opt= compiler flag. // the -opt= compiler flag.
func AddStandardAttributes(fn llvm.Value, config *compileopts.Config) { func AddStandardAttributes(fn llvm.Value, config *compileopts.Config) {
ctx := fn.Type().Context()
_, sizeLevel, _ := config.OptLevels() _, sizeLevel, _ := config.OptLevels()
if sizeLevel >= 1 { if sizeLevel >= 1 {
fn.AddFunctionAttr(fn.Type().Context().CreateEnumAttribute(llvm.AttributeKindID("optsize"), 0)) fn.AddFunctionAttr(ctx.CreateEnumAttribute(llvm.AttributeKindID("optsize"), 0))
} }
if sizeLevel >= 2 { if sizeLevel >= 2 {
fn.AddFunctionAttr(fn.Type().Context().CreateEnumAttribute(llvm.AttributeKindID("minsize"), 0)) fn.AddFunctionAttr(ctx.CreateEnumAttribute(llvm.AttributeKindID("minsize"), 0))
}
if config.CPU() != "" {
fn.AddFunctionAttr(ctx.CreateStringAttribute("target-cpu", config.CPU()))
}
if config.Features() != "" {
fn.AddFunctionAttr(ctx.CreateStringAttribute("target-features", config.Features()))
} }
} }

Просмотреть файл

@ -21,6 +21,11 @@ import (
var update = flag.Bool("update", false, "update transform package tests") var update = flag.Bool("update", false, "update transform package tests")
var defaultTestConfig = &compileopts.Config{
Target: &compileopts.TargetSpec{},
Options: &compileopts.Options{Opt: "2"},
}
// testTransform runs a transformation pass on an input file (pathPrefix+".ll") // testTransform runs a transformation pass on an input file (pathPrefix+".ll")
// and checks whether it matches the expected output (pathPrefix+".out.ll"). The // and checks whether it matches the expected output (pathPrefix+".out.ll"). The
// output is compared with a fuzzy match that ignores some irrelevant lines such // output is compared with a fuzzy match that ignores some irrelevant lines such

Просмотреть файл

@ -3,7 +3,6 @@ package transform_test
import ( import (
"testing" "testing"
"github.com/tinygo-org/tinygo/compileopts"
"github.com/tinygo-org/tinygo/transform" "github.com/tinygo-org/tinygo/transform"
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
@ -12,7 +11,7 @@ func TestWasmABI(t *testing.T) {
t.Parallel() t.Parallel()
testTransform(t, "testdata/wasm-abi", func(mod llvm.Module) { testTransform(t, "testdata/wasm-abi", func(mod llvm.Module) {
// Run ABI change pass. // Run ABI change pass.
err := transform.ExternalInt64AsPtr(mod, &compileopts.Config{Options: &compileopts.Options{Opt: "2"}}) err := transform.ExternalInt64AsPtr(mod, defaultTestConfig)
if err != nil { if err != nil {
t.Errorf("failed to change wasm ABI: %v", err) t.Errorf("failed to change wasm ABI: %v", err)
} }