Skip to content

Commit 6e20094

Browse files
tshortel-osoMasonProtter
authored
Basic rewrite for GPUCompiler (#46)
* Basic rewrite using @jpsamaroo's generate_shlib_fptr. * update, remove junk, fix tests, use `gcc` for linking * remove windows from CI * note that this doesn't work on windows * fix `compile`, add `native_code_llvm`, `native_code_typed` * clarify fib problem, add LoopVectorization test :) * add tests for stack allocated mutable arrays * test on version 1.7 * rename `compile` to `native_llvm_module` Co-authored-by: Jorge Alberto Vieyra Salas <ursus.est@gmail.com> Co-authored-by: Mason Protter <mason.protter@icloud.com>
1 parent 9deca58 commit 6e20094

30 files changed

Lines changed: 458 additions & 1818 deletions

.appveyor.yml

Lines changed: 0 additions & 31 deletions
This file was deleted.

.github/workflows/ci.yml

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,11 @@ jobs:
1010
fail-fast: false
1111
matrix:
1212
version:
13-
- '1.3'
13+
- '1.7'
1414
- 'nightly'
1515
os:
1616
- ubuntu-latest
17-
# - macOS-latest
18-
- windows-latest
17+
- macOS-latest
1918
arch:
2019
- x64
2120
steps:

.gitignore

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,8 @@
22
*.jl.cov
33
*.jl.mem
44
.DS_Store
5-
Manifest.toml
6-
!helpers/Manifest.toml
75
/dev/
86
/test/standalone
9-
/test/Manifest.toml
107
/test/test.*
118

129
test.o

.travis.yml

Lines changed: 0 additions & 24 deletions
This file was deleted.

Manifest.toml

Lines changed: 158 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,158 @@
1+
# This file is machine-generated - editing it directly is not advised
2+
3+
manifest_format = "2.0"
4+
5+
[[deps.ArgTools]]
6+
uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f"
7+
8+
[[deps.Artifacts]]
9+
uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33"
10+
11+
[[deps.Base64]]
12+
uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f"
13+
14+
[[deps.CEnum]]
15+
git-tree-sha1 = "215a9aa4a1f23fbd05b92769fdd62559488d70e9"
16+
uuid = "fa961155-64e5-5f13-b03f-caf6b980ea82"
17+
version = "0.4.1"
18+
19+
[[deps.Dates]]
20+
deps = ["Printf"]
21+
uuid = "ade2ca70-3891-5945-98fb-dc099432e06a"
22+
23+
[[deps.Downloads]]
24+
deps = ["ArgTools", "LibCURL", "NetworkOptions"]
25+
uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6"
26+
27+
[[deps.ExprTools]]
28+
git-tree-sha1 = "56559bbef6ca5ea0c0818fa5c90320398a6fbf8d"
29+
uuid = "e2ba6199-217a-4e67-a87a-7c52f15ade04"
30+
version = "0.1.8"
31+
32+
[[deps.GPUCompiler]]
33+
deps = ["ExprTools", "InteractiveUtils", "LLVM", "Libdl", "Logging", "TimerOutputs", "UUIDs"]
34+
git-tree-sha1 = "abd824e1f2ecd18d33811629c781441e94a24e81"
35+
uuid = "61eb1bfa-7361-4325-ad38-22787b887f55"
36+
version = "0.13.11"
37+
38+
[[deps.InteractiveUtils]]
39+
deps = ["Markdown"]
40+
uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240"
41+
42+
[[deps.JLLWrappers]]
43+
deps = ["Preferences"]
44+
git-tree-sha1 = "abc9885a7ca2052a736a600f7fa66209f96506e1"
45+
uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210"
46+
version = "1.4.1"
47+
48+
[[deps.LLVM]]
49+
deps = ["CEnum", "LLVMExtra_jll", "Libdl", "Printf", "Unicode"]
50+
git-tree-sha1 = "f8dcd7adfda0dddaf944e62476d823164cccc217"
51+
uuid = "929cbde3-209d-540e-8aea-75f648917ca0"
52+
version = "4.7.1"
53+
54+
[[deps.LLVMExtra_jll]]
55+
deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"]
56+
git-tree-sha1 = "62115afed394c016c2d3096c5b85c407b48be96b"
57+
uuid = "dad2f222-ce93-54a1-a47d-0025e8a3acab"
58+
version = "0.0.13+1"
59+
60+
[[deps.LibCURL]]
61+
deps = ["LibCURL_jll", "MozillaCACerts_jll"]
62+
uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21"
63+
64+
[[deps.LibCURL_jll]]
65+
deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"]
66+
uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0"
67+
68+
[[deps.LibGit2]]
69+
deps = ["Base64", "NetworkOptions", "Printf", "SHA"]
70+
uuid = "76f85450-5226-5b5a-8eaa-529ad045b433"
71+
72+
[[deps.LibSSH2_jll]]
73+
deps = ["Artifacts", "Libdl", "MbedTLS_jll"]
74+
uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8"
75+
76+
[[deps.Libdl]]
77+
uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
78+
79+
[[deps.Logging]]
80+
uuid = "56ddb016-857b-54e1-b83d-db4d58db5568"
81+
82+
[[deps.Markdown]]
83+
deps = ["Base64"]
84+
uuid = "d6f4376e-aef5-505a-96c1-9c027394607a"
85+
86+
[[deps.MbedTLS_jll]]
87+
deps = ["Artifacts", "Libdl"]
88+
uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1"
89+
90+
[[deps.MozillaCACerts_jll]]
91+
uuid = "14a3606d-f60d-562e-9121-12d972cd8159"
92+
93+
[[deps.NetworkOptions]]
94+
uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908"
95+
96+
[[deps.Pkg]]
97+
deps = ["Artifacts", "Dates", "Downloads", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"]
98+
uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f"
99+
100+
[[deps.Preferences]]
101+
deps = ["TOML"]
102+
git-tree-sha1 = "2cf929d64681236a2e074ffafb8d568733d2e6af"
103+
uuid = "21216c6a-2e73-6563-6e65-726566657250"
104+
version = "1.2.3"
105+
106+
[[deps.Printf]]
107+
deps = ["Unicode"]
108+
uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7"
109+
110+
[[deps.REPL]]
111+
deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"]
112+
uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb"
113+
114+
[[deps.Random]]
115+
deps = ["SHA", "Serialization"]
116+
uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c"
117+
118+
[[deps.SHA]]
119+
uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce"
120+
121+
[[deps.Serialization]]
122+
uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b"
123+
124+
[[deps.Sockets]]
125+
uuid = "6462fe0b-24de-5631-8697-dd941f90decc"
126+
127+
[[deps.TOML]]
128+
deps = ["Dates"]
129+
uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76"
130+
131+
[[deps.Tar]]
132+
deps = ["ArgTools", "SHA"]
133+
uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e"
134+
135+
[[deps.TimerOutputs]]
136+
deps = ["ExprTools", "Printf"]
137+
git-tree-sha1 = "97e999be94a7147d0609d0b9fc9feca4bf24d76b"
138+
uuid = "a759f4b9-e2f1-59dc-863e-4aeb61b1ea8f"
139+
version = "0.5.15"
140+
141+
[[deps.UUIDs]]
142+
deps = ["Random", "SHA"]
143+
uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4"
144+
145+
[[deps.Unicode]]
146+
uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5"
147+
148+
[[deps.Zlib_jll]]
149+
deps = ["Libdl"]
150+
uuid = "83775a58-1f1d-513f-b197-d71354ab007a"
151+
152+
[[deps.nghttp2_jll]]
153+
deps = ["Artifacts", "Libdl"]
154+
uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d"
155+
156+
[[deps.p7zip_jll]]
157+
deps = ["Artifacts", "Libdl"]
158+
uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0"

Project.toml

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,17 @@
11
name = "StaticCompiler"
22
uuid = "81625895-6c0f-48fc-b932-11a18313743c"
33
authors = ["Tom Short"]
4-
version = "0.1.0"
4+
version = "0.2.0"
55

66
[deps]
7-
Cassette = "7057c7e9-c182-5462-911a-8362d720325c"
8-
DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8"
7+
GPUCompiler = "61eb1bfa-7361-4325-ad38-22787b887f55"
98
LLVM = "929cbde3-209d-540e-8aea-75f648917ca0"
109
Libdl = "8f399da3-3557-5675-b5ff-fb832c97cbdb"
11-
MacroTools = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09"
12-
TypedCodeUtils = "687fb87b-adea-59d5-9be9-82253b54685d"
1310

1411
[compat]
15-
DataStructures = "0.17"
16-
Cassette = "0.3"
17-
LLVM = "1.3"
18-
TypedCodeUtils = "0.1"
19-
MacroTools = "0.5"
20-
julia = "1.2"
12+
julia = "1.7"
13+
GPUCompiler = "0.13"
14+
LLVM = "4"
2115

2216
[extras]
2317
Formatting = "59287772-0a20-5a39-b81b-1366585eb4c0"

README.md

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -9,52 +9,38 @@
99
This is an experimental package to compile Julia code to standalone libraries. A system image is not needed. It is also meant for cross compilation, so Julia code can be compiled for other targets, including WebAssembly and embedded targets.
1010

1111
## Installation and Usage
12+
1213
```julia
1314
using Pkg
1415
Pkg.add(PackageSpec( url = "https://github.com/tshort/StaticCompiler.jl", rev = "master"))
1516
```
16-
```julia
17-
using StaticCompiler
18-
```
19-
**Documentation**: [![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://tshort.github.io/StaticCompiler.jl/dev)
20-
21-
## Approach
22-
This package uses the [LLVM package](https://github.com/maleadt/LLVM.jl) to generate code in the same fashion as [CUDAnative](https://github.com/JuliaGPU/CUDAnative.jl).
23-
24-
Some of the key details of this approach are:
25-
26-
* **ccalls and cglobal** -- When Julia compiles code CUDAnative style, `ccall` and `cglobal` references get compiled to a direct pointer. `StaticCompiler` converts these to symbol references for later linking. For `ccall` with a tuple call to a symbol in a library, `Cassette` is used to convert that to just a symbol reference (no dynamic library loading).
27-
28-
* **Global variables** -- A lot of code gets compiled with global variables, and these get compiled to a direct pointer. `StaticCompiler` includes a basic serialize/deserialize approach. Right now, this is fairly basic, and it takes shortcuts for some objects by swapping in wrong types. This can work because many times, the objects are not really used in the code. Finding the global variable can be a little tricky because the pointer is converted to a Julia object with `unsafe_pointer_to_objref`, and that segfaults for some addresses. How to best handle cases like that is still to be determined.
29-
30-
* **Initialization** -- If libjulia is used, some init code needs to be run to set up garbage collection and other things. For this, a basic `blank.ji` file is used to feed `jl_init_with_image`.
31-
32-
Long term, a better approach may be to use Julia's standard compilation techniques with "tree shaking" to generate a reduced system image (see [here](https://github.com/JuliaLang/julia/issues/33670)).
33-
34-
## Example
35-
The API still needs work, but here is the general approach right now:
3617

3718
```julia
3819
using StaticCompiler
39-
m = irgen(cos, Tuple{Float64})
40-
write(m, "cos.bc")
41-
write_object(m, "cos.o")
42-
```
20+
f(x) = 2x
4321

44-
`cos.o` should contain a function called `cos`. From there, you need to convert to link as needed with `libjulia`.
22+
# compile `f` and return an LLVM module
23+
m = compile(f, (Int,))
4524

46-
See the `test` directory for more information and types of code that currently run. The most advanced example that works is a call to an ODE solution using modified code from [ODE.jl](https://github.com/JuliaDiffEq/ODE.jl). For information on compiling and linking to an executable, see [test/standalone-exe.jl](./test/standalone-exe.jl).
25+
# compile `f` and write to a shared library ("f.so" or "f.dll")
26+
generate_shlib(f, (Int,), "libf")
27+
# find a function pointer for this shared library
28+
fptr = generate_shlib_fptr("libf", "f")
29+
@ccall $fptr(2::Int)::Int
4730

48-
## Known limitations
49-
50-
* It won't work for recursive code. Jameson's [codegen-norecursion](https://github.com/JuliaLang/julia/tree/jn/codegen-norecursion) should fix that when merged.
51-
52-
* `cfunction` is not supported.
31+
# do this in one step (this time with a temporary shared library)
32+
fptr = generate_shlib_fptr(f, (Int,))
33+
@ccall $fptr(2::Int)::Int
34+
```
5335

54-
* Generic code that uses `jl_apply_generic` does not work. One strategy for this is to use Cassette to swap out known code that uses dynamic calls. Another approach is to write something like `jl_apply_generic` to implement dynamic calls.
36+
## Approach
5537

56-
* The use of Cassette makes it more difficult for Julia to infer some things, and only type-stable code can be statically compiled with this approach.
38+
This package uses the [GPUCompiler package](https://github.com/JuliaGPU/GPUCompiler.jl) to generate code.
5739

58-
* It's only been tested on Linux and Windows.
40+
## Limitations
5941

60-
Finally, this whole approach is young and likely brittle. Do not expect it to work for your code.
42+
* This package currently requires that you have `gcc` installed and in your system's `PATH`. This is probably pretty easy to fix, we only use `gcc` for linking. In theory Clang_jll or LLVM_full_jll should be able to do this, and be managed through Julia's package manager.
43+
* No heap allocations (e.g. creating an array or a string) are allowed inside a statically compiled function body. If you try to run such a function, you will get a segfault.
44+
** It's sometimes possible you won't get a segfault if you define and run the function in the same session, but trying to call the compiled function in a new julia session will definitely segfault.
45+
* Lots of other limitations too. E.g. there's an example in tests/runtests.jl where summing a vector of `Complex{Float32}` is fine, but segfaults on `Complex{Float64}`.
46+
* Doesn't currently work on Windows

docs/src/backend.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@ Pages = ["backend.md"]
77
```@autodocs
88
Modules = [StaticCompiler]
99
Pages = readdir("../src")
10-
```
10+
```

docs/src/helpers.md

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +0,0 @@
1-
# Helpers
2-
Note that the helpers defined here are used in tests, and they are useful to test out code in the REPL.
3-
4-
```julia
5-
twox(x) = 2x
6-
# run code in the REPL
7-
@jlrun twox(3)
8-
# compile to an executable in a `standalone` directory
9-
exegen([ (twox, Tuple{Int}, 4) ])
10-
```
11-
12-
These are not meant to be a permanent part of the API. They are just for testing.
13-
14-
15-
```@index
16-
Modules = [StaticCompiler]
17-
Pages = ["helpers.md"]
18-
```
19-
20-
```@autodocs
21-
Modules = [StaticCompiler]
22-
Pages = readdir("../src/helpers")
23-
```

0 commit comments

Comments
 (0)