Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

all: Go 1.21 support #3824

Merged
merged 6 commits into from
Aug 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/build-macos.yml
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v3
Expand Down Expand Up @@ -126,7 +126,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Build TinyGo
run: go install
Expand Down
10 changes: 5 additions & 5 deletions .github/workflows/linux.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ jobs:
# statically linked binary.
runs-on: ubuntu-latest
container:
image: golang:1.20-alpine
image: golang:1.21rc4-alpine
steps:
- name: Install apk dependencies
# tar: needed for actions/cache@v3
Expand Down Expand Up @@ -135,7 +135,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Install wasmtime
run: |
Expand Down Expand Up @@ -177,7 +177,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Install Node.js
uses: actions/setup-node@v3
Expand Down Expand Up @@ -290,7 +290,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v3
Expand Down Expand Up @@ -407,7 +407,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Restore LLVM source cache
uses: actions/cache/restore@v3
Expand Down
8 changes: 4 additions & 4 deletions .github/workflows/windows.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Restore cached LLVM source
uses: actions/cache/restore@v3
Expand Down Expand Up @@ -143,7 +143,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v2
Expand Down Expand Up @@ -173,7 +173,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v2
Expand Down Expand Up @@ -209,7 +209,7 @@ jobs:
- name: Install Go
uses: actions/setup-go@v3
with:
go-version: '1.20'
go-version: '1.21.0-rc.4'
cache: true
- name: Download TinyGo build
uses: actions/download-artifact@v2
Expand Down
14 changes: 11 additions & 3 deletions builder/build.go
Original file line number Diff line number Diff line change
Expand Up @@ -217,19 +217,27 @@ func Build(pkgName, outpath, tmpdir string, config *compileopts.Config) (BuildRe
var packageJobs []*compileJob
packageActionIDJobs := make(map[string]*compileJob)

if config.Options.GlobalValues == nil {
config.Options.GlobalValues = make(map[string]map[string]string)
}
if config.Options.GlobalValues["runtime"]["buildVersion"] == "" {
version := goenv.Version
if strings.HasSuffix(goenv.Version, "-dev") && goenv.GitSha1 != "" {
version += "-" + goenv.GitSha1
}
if config.Options.GlobalValues == nil {
config.Options.GlobalValues = make(map[string]map[string]string)
}
if config.Options.GlobalValues["runtime"] == nil {
config.Options.GlobalValues["runtime"] = make(map[string]string)
}
config.Options.GlobalValues["runtime"]["buildVersion"] = version
}
if config.TestConfig.CompileTestBinary {
// The testing.testBinary is set to "1" when in a test.
// This is needed for testing.Testing() to work correctly.
if config.Options.GlobalValues["testing"] == nil {
config.Options.GlobalValues["testing"] = make(map[string]string)
}
config.Options.GlobalValues["testing"]["testBinary"] = "1"
}

var embedFileObjects []*compileJob
for _, pkg := range lprogram.Sorted() {
Expand Down
2 changes: 1 addition & 1 deletion builder/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func NewConfig(options *compileopts.Options) (*compileopts.Config, error) {
if err != nil {
return nil, err
}
if major != 1 || minor < 18 || minor > 20 {
if major != 1 || minor < 18 || minor > 21 {
// Note: when this gets updated, also update the Go compatibility matrix:
// https://github.com/tinygo-org/tinygo-site/blob/dev/content/docs/reference/go-compat-matrix.md
return nil, fmt.Errorf("requires go version 1.18 through 1.20, got go%d.%d", major, minor)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed a number s/1.20/1.21/

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missed a minor here s/1.20/1.21/l

Expand Down
6 changes: 5 additions & 1 deletion compiler/calls.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,11 @@ const (
// createRuntimeCallCommon creates a runtime call. Use createRuntimeCall or
// createRuntimeInvoke instead.
func (b *builder) createRuntimeCallCommon(fnName string, args []llvm.Value, name string, isInvoke bool) llvm.Value {
fn := b.program.ImportedPackage("runtime").Members[fnName].(*ssa.Function)
member := b.program.ImportedPackage("runtime").Members[fnName]
if member == nil {
panic("unknown runtime call: " + fnName)
}
fn := member.(*ssa.Function)
fnType, llvmFn := b.getFunction(fn)
if llvmFn.IsNil() {
panic("trying to call non-existent function: " + fn.RelString(nil))
Expand Down
57 changes: 57 additions & 0 deletions compiler/compiler.go
Original file line number Diff line number Diff line change
Expand Up @@ -1600,6 +1600,45 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
cplx = b.CreateInsertValue(cplx, r, 0, "")
cplx = b.CreateInsertValue(cplx, i, 1, "")
return cplx, nil
case "clear":
value := argValues[0]
switch typ := argTypes[0].Underlying().(type) {
case *types.Slice:
elementType := b.getLLVMType(typ.Elem())
elementSize := b.targetData.TypeAllocSize(elementType)
elementAlign := b.targetData.ABITypeAlignment(elementType)

// The pointer to the data to be cleared.
llvmBuf := b.CreateExtractValue(value, 0, "buf")
if llvmBuf.Type() != b.i8ptrType { // compatibility with LLVM 14
llvmBuf = b.CreateBitCast(llvmBuf, b.i8ptrType, "")
}

// The length (in bytes) to be cleared.
llvmLen := b.CreateExtractValue(value, 1, "len")
llvmLen = b.CreateMul(llvmLen, llvm.ConstInt(llvmLen.Type(), elementSize, false), "")

// Do the clear operation using the LLVM memset builtin.
// This is also correct for nil slices: in those cases, len will be
// 0 which means the memset call is a no-op (according to the LLVM
// LangRef).
memset := b.getMemsetFunc()
call := b.createCall(memset.GlobalValueType(), memset, []llvm.Value{
llvmBuf, // dest
llvm.ConstInt(b.ctx.Int8Type(), 0, false), // val
llvmLen, // len
llvm.ConstInt(b.ctx.Int1Type(), 0, false), // isVolatile
}, "")
call.AddCallSiteAttribute(1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elementAlign)))

return llvm.Value{}, nil
case *types.Map:
m := argValues[0]
b.createMapClear(m)
return llvm.Value{}, nil
default:
return llvm.Value{}, b.makeError(pos, "unsupported type in clear builtin: "+typ.String())
}
case "copy":
dst := argValues[0]
src := argValues[1]
Expand Down Expand Up @@ -1637,6 +1676,24 @@ func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, c
llvmLen = b.CreateZExt(llvmLen, b.intType, "len.int")
}
return llvmLen, nil
case "min", "max":
// min and max builtins, added in Go 1.21.
// We can simply reuse the existing binop comparison code, which has all
// the edge cases figured out already.
tok := token.LSS
if callName == "max" {
tok = token.GTR
}
result := argValues[0]
typ := argTypes[0]
for _, arg := range argValues[1:] {
cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos)
if err != nil {
return result, err
}
result = b.CreateSelect(cmp, result, arg, "")
}
return result, nil
case "print", "println":
for i, value := range argValues {
if i >= 1 && callName == "println" {
Expand Down
3 changes: 3 additions & 0 deletions compiler/compiler_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,9 @@ func TestCompiler(t *testing.T) {
if goMinor >= 20 {
tests = append(tests, testCase{"go1.20.go", "", ""})
}
if goMinor >= 21 {
tests = append(tests, testCase{"go1.21.go", "", ""})
}

for _, tc := range tests {
name := tc.file
Expand Down
24 changes: 15 additions & 9 deletions compiler/intrinsics.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,7 @@ func (b *builder) createMemoryCopyImpl() {
// regular libc memset calls if they aren't optimized out in a different way.
func (b *builder) createMemoryZeroImpl() {
b.createFunctionStart(true)
fnName := "llvm.memset.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
if llvmutil.Major() < 15 { // compatibility with LLVM 14
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
}
llvmFn := b.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.ctx.Int8Type(), b.uintptrType, b.ctx.Int1Type()}, false)
llvmFn = llvm.AddFunction(b.mod, fnName, fnType)
}
llvmFn := b.getMemsetFunc()
params := []llvm.Value{
b.getValue(b.fn.Params[0], getPos(b.fn)),
llvm.ConstInt(b.ctx.Int8Type(), 0, false),
Expand All @@ -89,6 +81,20 @@ func (b *builder) createMemoryZeroImpl() {
b.CreateRetVoid()
}

// Return the llvm.memset.p0.i8 function declaration.
func (c *compilerContext) getMemsetFunc() llvm.Value {
fnName := "llvm.memset.p0.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
if llvmutil.Major() < 15 { // compatibility with LLVM 14
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(c.uintptrType.IntTypeWidth())
}
llvmFn := c.mod.NamedFunction(fnName)
if llvmFn.IsNil() {
fnType := llvm.FunctionType(c.ctx.VoidType(), []llvm.Type{c.i8ptrType, c.ctx.Int8Type(), c.uintptrType, c.ctx.Int1Type()}, false)
llvmFn = llvm.AddFunction(c.mod, fnName, fnType)
}
return llvmFn
}

// createKeepAlive creates the runtime.KeepAlive function. It is implemented
// using inline assembly.
func (b *builder) createKeepAliveImpl() {
Expand Down
5 changes: 5 additions & 0 deletions compiler/map.go
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,11 @@ func (b *builder) createMapDelete(keyType types.Type, m, key llvm.Value, pos tok
}
}

// Clear the given map.
func (b *builder) createMapClear(m llvm.Value) {
b.createRuntimeCall("hashmapClear", []llvm.Value{m}, "")
}

// createMapIteratorNext lowers the *ssa.Next instruction for iterating over a
// map. It returns a tuple of {bool, key, value} with the result of the
// iteration.
Expand Down
2 changes: 1 addition & 1 deletion compiler/symbol.go
Original file line number Diff line number Diff line change
Expand Up @@ -367,7 +367,7 @@ func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
// The list of allowed types is based on this proposal:
// https://github.com/golang/go/issues/59149
func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
if c.pkg.Path() == "runtime" {
if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" {
// The runtime is a special case. Allow all kinds of parameters
// (importantly, including pointers).
return
Expand Down
65 changes: 65 additions & 0 deletions compiler/testdata/go1.21.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
package main

func min1(a int) int {
return min(a)
}

func min2(a, b int) int {
return min(a, b)
}

func min3(a, b, c int) int {
return min(a, b, c)
}

func min4(a, b, c, d int) int {
return min(a, b, c, d)
}

func minUint8(a, b uint8) uint8 {
return min(a, b)
}

func minUnsigned(a, b uint) uint {
return min(a, b)
}

func minFloat32(a, b float32) float32 {
return min(a, b)
}

func minFloat64(a, b float64) float64 {
return min(a, b)
}

func minString(a, b string) string {
return min(a, b)
}

func maxInt(a, b int) int {
return max(a, b)
}

func maxUint(a, b uint) uint {
return max(a, b)
}

func maxFloat32(a, b float32) float32 {
return max(a, b)
}

func maxString(a, b string) string {
return max(a, b)
}

func clearSlice(s []int) {
clear(s)
}

func clearZeroSizedSlice(s []struct{}) {
clear(s)
}

func clearMap(m map[string]int) {
clear(m)
}
Loading
Loading