Skip to content

Commit 721414f

Browse files
committed
ci: add support for LLVM 15
Also switch to LLVM 15 for builds with a system-installed LLVM.
1 parent e857a61 commit 721414f

File tree

14 files changed

+115
-31
lines changed

14 files changed

+115
-31
lines changed

.circleci/config.yml

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -118,12 +118,12 @@ jobs:
118118
steps:
119119
- test-linux:
120120
llvm: "14"
121-
test-llvm14-go119:
121+
test-llvm15-go119:
122122
docker:
123-
- image: golang:1.19beta1-buster
123+
- image: golang:1.19-buster
124124
steps:
125125
- test-linux:
126-
llvm: "14"
126+
llvm: "15"
127127
fmt-check: false
128128

129129
workflows:
@@ -132,6 +132,6 @@ workflows:
132132
# This tests our lowest supported versions of Go and LLVM, to make sure at
133133
# least the smoke tests still pass.
134134
- test-llvm14-go118
135-
# This tests a beta version of Go. It should be removed once regular
136-
# release builds are built using this version.
137-
- test-llvm14-go119
135+
# This tests a newer version of Go and LLVM. It should be removed once
136+
# regular release builds are built using these versions.
137+
- test-llvm15-go119

.github/workflows/build-macos.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,7 @@ jobs:
108108
- name: Install LLVM
109109
shell: bash
110110
run: |
111-
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@14
111+
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@14 # TODO: use LLVM 15
112112
- name: Checkout
113113
uses: actions/checkout@v2
114114
- name: Install Go
@@ -117,6 +117,6 @@ jobs:
117117
go-version: '1.18'
118118
cache: true
119119
- name: Build TinyGo
120-
run: go install
120+
run: go install -tags=llvm14 # TODO: remove -tags=llvm14
121121
- name: Check binary
122122
run: tinygo version

cgo/libclang_config_llvm14.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
//go:build !byollvm
2-
// +build !byollvm
1+
//go:build !byollvm && llvm14
2+
// +build !byollvm,llvm14
33

44
package cgo
55

cgo/libclang_config_llvm15.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
//go:build !byollvm && !llvm14
2+
// +build !byollvm,!llvm14
3+
4+
package cgo
5+
6+
/*
7+
#cgo linux CFLAGS: -I/usr/lib/llvm-15/include
8+
#cgo darwin,amd64 CFLAGS: -I/usr/local/opt/llvm@15/include
9+
#cgo darwin,arm64 CFLAGS: -I/opt/homebrew/opt/llvm@15/include
10+
#cgo freebsd CFLAGS: -I/usr/local/llvm15/include
11+
#cgo linux LDFLAGS: -L/usr/lib/llvm-15/lib -lclang
12+
#cgo darwin,amd64 LDFLAGS: -L/usr/local/opt/llvm@15/lib -lclang -lffi
13+
#cgo darwin,arm64 LDFLAGS: -L/opt/homebrew/opt/llvm@15/lib -lclang -lffi
14+
#cgo freebsd LDFLAGS: -L/usr/local/llvm15/lib -lclang
15+
*/
16+
import "C"

compiler/intrinsics.go

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"strconv"
88
"strings"
99

10+
"github.com/tinygo-org/tinygo/compiler/llvmutil"
1011
"tinygo.org/x/go-llvm"
1112
)
1213

@@ -44,7 +45,10 @@ func (b *builder) defineIntrinsicFunction() {
4445
// and will otherwise be lowered to regular libc memcpy/memmove calls.
4546
func (b *builder) createMemoryCopyImpl() {
4647
b.createFunctionStart(true)
47-
fnName := "llvm." + b.fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
48+
fnName := "llvm." + b.fn.Name() + ".p0.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
49+
if llvmutil.Major() < 15 { // compatibility with LLVM 14
50+
fnName = "llvm." + b.fn.Name() + ".p0i8.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
51+
}
4852
llvmFn := b.mod.NamedFunction(fnName)
4953
if llvmFn.IsNil() {
5054
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.i8ptrType, b.uintptrType, b.ctx.Int1Type()}, false)
@@ -64,7 +68,10 @@ func (b *builder) createMemoryCopyImpl() {
6468
// regular libc memset calls if they aren't optimized out in a different way.
6569
func (b *builder) createMemoryZeroImpl() {
6670
b.createFunctionStart(true)
67-
fnName := "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
71+
fnName := "llvm.memset.p0.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
72+
if llvmutil.Major() < 15 { // compatibility with LLVM 14
73+
fnName = "llvm.memset.p0i8.i" + strconv.Itoa(b.uintptrType.IntTypeWidth())
74+
}
6875
llvmFn := b.mod.NamedFunction(fnName)
6976
if llvmFn.IsNil() {
7077
fnType := llvm.FunctionType(b.ctx.VoidType(), []llvm.Type{b.i8ptrType, b.ctx.Int8Type(), b.uintptrType, b.ctx.Int1Type()}, false)

compiler/llvmutil/llvm.go

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,22 @@
77
// places would be a big risk if only one of them is updated.
88
package llvmutil
99

10-
import "tinygo.org/x/go-llvm"
10+
import (
11+
"strconv"
12+
"strings"
13+
14+
"tinygo.org/x/go-llvm"
15+
)
16+
17+
// Major returns the LLVM major version.
18+
func Major() int {
19+
llvmMajor, err := strconv.Atoi(strings.SplitN(llvm.Version, ".", 2)[0])
20+
if err != nil {
21+
// sanity check, should be unreachable
22+
panic("could not parse LLVM version: " + err.Error())
23+
}
24+
return llvmMajor
25+
}
1126

1227
// CreateEntryBlockAlloca creates a new alloca in the entry block, even though
1328
// the IR builder is located elsewhere. It assumes that the insert point is
@@ -78,25 +93,33 @@ func EmitLifetimeEnd(builder llvm.Builder, mod llvm.Module, ptr, size llvm.Value
7893
// getLifetimeStartFunc returns the llvm.lifetime.start intrinsic and creates it
7994
// first if it doesn't exist yet.
8095
func getLifetimeStartFunc(mod llvm.Module) (llvm.Type, llvm.Value) {
81-
fn := mod.NamedFunction("llvm.lifetime.start.p0i8")
96+
fnName := "llvm.lifetime.start.p0"
97+
if Major() < 15 { // compatibility with LLVM 14
98+
fnName = "llvm.lifetime.start.p0i8"
99+
}
100+
fn := mod.NamedFunction(fnName)
82101
ctx := mod.Context()
83102
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
84103
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), i8ptrType}, false)
85104
if fn.IsNil() {
86-
fn = llvm.AddFunction(mod, "llvm.lifetime.start.p0i8", fnType)
105+
fn = llvm.AddFunction(mod, fnName, fnType)
87106
}
88107
return fnType, fn
89108
}
90109

91110
// getLifetimeEndFunc returns the llvm.lifetime.end intrinsic and creates it
92111
// first if it doesn't exist yet.
93112
func getLifetimeEndFunc(mod llvm.Module) (llvm.Type, llvm.Value) {
94-
fn := mod.NamedFunction("llvm.lifetime.end.p0i8")
113+
fnName := "llvm.lifetime.end.p0"
114+
if Major() < 15 {
115+
fnName = "llvm.lifetime.end.p0i8"
116+
}
117+
fn := mod.NamedFunction(fnName)
95118
ctx := mod.Context()
96119
i8ptrType := llvm.PointerType(ctx.Int8Type(), 0)
97120
fnType := llvm.FunctionType(ctx.VoidType(), []llvm.Type{ctx.Int64Type(), i8ptrType}, false)
98121
if fn.IsNil() {
99-
fn = llvm.AddFunction(mod, "llvm.lifetime.end.p0i8", fnType)
122+
fn = llvm.AddFunction(mod, fnName, fnType)
100123
}
101124
return fnType, fn
102125
}

compiler/symbol.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import (
1010
"strconv"
1111
"strings"
1212

13+
"github.com/tinygo-org/tinygo/compiler/llvmutil"
1314
"github.com/tinygo-org/tinygo/loader"
1415
"golang.org/x/tools/go/ssa"
1516
"tinygo.org/x/go-llvm"
@@ -353,7 +354,15 @@ func (c *compilerContext) addStandardDefinedAttributes(llvmFn llvm.Value) {
353354
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0))
354355
if strings.Split(c.Triple, "-")[0] == "x86_64" {
355356
// Required by the ABI.
356-
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("uwtable"), 0))
357+
if llvmutil.Major() < 15 {
358+
// Needed for LLVM 14 support.
359+
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("uwtable"), 0))
360+
} else {
361+
// The uwtable has two possible values: sync (1) or async (2). We
362+
// use sync because we currently don't use async unwind tables.
363+
// For details, see: https://llvm.org/docs/LangRef.html#function-attributes
364+
llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("uwtable"), 1))
365+
}
357366
}
358367
}
359368

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ require (
1717
golang.org/x/sys v0.0.0-20220829200755-d48e67d00261
1818
golang.org/x/tools v0.1.11
1919
gopkg.in/yaml.v2 v2.4.0
20-
tinygo.org/x/go-llvm v0.0.0-20220922113433-4b5ad7ff76ec
20+
tinygo.org/x/go-llvm v0.0.0-20220922115213-dcb078a26266
2121
)
2222

2323
require (

go.sum

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -64,5 +64,5 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
6464
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
6565
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
6666
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo=
67-
tinygo.org/x/go-llvm v0.0.0-20220922113433-4b5ad7ff76ec h1:FYtAFrw/YQPc644uNN65dW50FrEuVNaPBf70x23ApY4=
68-
tinygo.org/x/go-llvm v0.0.0-20220922113433-4b5ad7ff76ec/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=
67+
tinygo.org/x/go-llvm v0.0.0-20220922115213-dcb078a26266 h1:vg4sYKEM+w6epr5S1nXqP/7UhMYcc8nRt7Ohkq28rok=
68+
tinygo.org/x/go-llvm v0.0.0-20220922115213-dcb078a26266/go.mod h1:GFbusT2VTA4I+l4j80b17KFK+6whv69Wtny5U+T8RR0=

interp/interpreter.go

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
356356
default:
357357
panic("unknown integer type width")
358358
}
359-
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0i8.p0i8.") || strings.HasPrefix(callFn.name, "llvm.memmove.p0i8.p0i8."):
359+
case strings.HasPrefix(callFn.name, "llvm.memcpy.p0") || strings.HasPrefix(callFn.name, "llvm.memmove.p0"):
360360
// Copy a block of memory from one pointer to another.
361361
dst, err := operands[1].asPointer(r)
362362
if err != nil {
@@ -496,7 +496,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
496496
typecodeID := typecodeIDBitCast.Operand(0).Initializer()
497497

498498
// Load the method set, which is part of the typecodeID object.
499-
methodSet := r.builder.CreateExtractValue(typecodeID, 2, "").Operand(0).Initializer()
499+
methodSet := stripPointerCasts(r.builder.CreateExtractValue(typecodeID, 2, "")).Initializer()
500500

501501
// We don't need to load the interface method set.
502502

@@ -1087,3 +1087,15 @@ func intPredicateString(predicate llvm.IntPredicate) string {
10871087
return "cmp?"
10881088
}
10891089
}
1090+
1091+
// Strip some pointer casts. This is probably unnecessary once support for
1092+
// LLVM 14 (non-opaque pointers) is dropped.
1093+
func stripPointerCasts(value llvm.Value) llvm.Value {
1094+
if !value.IsAConstantExpr().IsNil() {
1095+
switch value.Opcode() {
1096+
case llvm.GetElementPtr, llvm.BitCast:
1097+
return stripPointerCasts(value.Operand(0))
1098+
}
1099+
}
1100+
return value
1101+
}

0 commit comments

Comments
 (0)