Compare commits
1290 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8fc97794e8 | ||
|
|
df2ba37687 | ||
|
|
85b16b2a54 | ||
|
|
eeabc6b61a | ||
|
|
2b3dafed61 | ||
|
|
7232fc36ab | ||
|
|
a8e1fd1054 | ||
|
|
c248a50338 | ||
|
|
fa0ca23798 | ||
|
|
ed224cf912 | ||
|
|
b51df25371 | ||
|
|
db8cc8eb7b | ||
|
|
a027e9fe14 | ||
|
|
b882ca809a | ||
|
|
daf0a9dc9a | ||
|
|
f2dafa7544 | ||
|
|
7fe22875a6 | ||
|
|
3da3c8ecd8 | ||
|
|
1cf57508b0 | ||
|
|
f8bacfcc67 | ||
|
|
9daa77c1a4 | ||
|
|
c4775dd313 | ||
|
|
ae87cb031e | ||
|
|
3c049f25ee | ||
|
|
85a90b62b7 | ||
|
|
10b0124951 | ||
|
|
c0d7ff9543 | ||
|
|
74012d4869 | ||
|
|
830c40440f | ||
|
|
21a2f71ad9 | ||
|
|
cf75e3e664 | ||
|
|
ffc307323a | ||
|
|
ff0aec28c5 | ||
|
|
31394b03ae | ||
|
|
2ab93cb385 | ||
|
|
172b396dc9 | ||
|
|
9b82d08087 | ||
|
|
410617f73b | ||
|
|
ade0d38a7c | ||
|
|
3ce55a2ac4 | ||
|
|
cc6e4dbec0 | ||
|
|
2935ae7bf1 | ||
|
|
96e418e63b | ||
|
|
e4a84dcfe9 | ||
|
|
9ea91cfce3 | ||
|
|
8c7f0cf988 | ||
|
|
afa9a00259 | ||
|
|
a0ee11c300 | ||
|
|
6e02dace18 | ||
|
|
93bac6f26f | ||
|
|
8657fbd810 | ||
|
|
68203be004 | ||
|
|
b2323ef2e7 | ||
|
|
70b017fb72 | ||
|
|
607e3bbc11 | ||
|
|
315c9285de | ||
|
|
c22427b8fd | ||
|
|
2fcfac9e84 | ||
|
|
7cc857233f | ||
|
|
f85aa09784 | ||
|
|
0b0cecc2a9 | ||
|
|
3b5b9c9587 | ||
|
|
cbe190fa70 | ||
|
|
9156466351 | ||
|
|
f79caf095d | ||
|
|
d31dcd13fc | ||
|
|
552224bbfe | ||
|
|
5ba01674fb | ||
|
|
7390afc5e1 | ||
|
|
85ec23d552 | ||
|
|
007064c0ac | ||
|
|
fd53756170 | ||
|
|
9e6dd9f23d | ||
|
|
ef8be6c7c2 | ||
|
|
de4b5b70da | ||
|
|
9edeee4b3f | ||
|
|
767a0cc1fd | ||
|
|
ae09247e34 | ||
|
|
a3ea4798bc | ||
|
|
af54a22d16 | ||
|
|
b026bfc71b | ||
|
|
80d80ad8aa | ||
|
|
dbecf33924 | ||
|
|
2b08e3604d | ||
|
|
7d3a672c2b | ||
|
|
022e46ae38 | ||
|
|
3f930d228e | ||
|
|
5eba370f7b | ||
|
|
e138951e9e | ||
|
|
5cd18d7275 | ||
|
|
d7ff5a53a7 | ||
|
|
aa14bb6fdf | ||
|
|
c275f682a9 | ||
|
|
08894025bc | ||
|
|
b063a48520 | ||
|
|
858d38d314 | ||
|
|
f5875d09e9 | ||
|
|
34db181686 | ||
|
|
be55ea2b0b | ||
|
|
aa0dd4d10d | ||
|
|
39533e4209 | ||
|
|
4bba3bf1d2 | ||
|
|
2d29d1549a | ||
|
|
c7a078f17f | ||
|
|
2cf92037e9 | ||
|
|
452ee7a103 | ||
|
|
68f70af2f3 | ||
|
|
11682e487e | ||
|
|
4d006230f9 | ||
|
|
a32f4bb05c | ||
|
|
6d4e260127 | ||
|
|
45404b5bcf | ||
|
|
861551b2ba | ||
|
|
aac820a8d5 | ||
|
|
a5ff25b0fe | ||
|
|
b81638794f | ||
|
|
88cfeb2791 | ||
|
|
d0b57535ed | ||
|
|
528add4702 | ||
|
|
dd47971877 | ||
|
|
d51a99c8e2 | ||
|
|
e192f01dc3 | ||
|
|
aedaf57249 | ||
|
|
222e58e76e | ||
|
|
c8fc80f4a0 | ||
|
|
1ed180887d | ||
|
|
d6a38a567f | ||
|
|
ae9c3276bc | ||
|
|
35d34cd4e8 | ||
|
|
4f45824632 | ||
|
|
532da174dd | ||
|
|
dbe13feba2 | ||
|
|
1c93061a7f | ||
|
|
0e371930e6 | ||
|
|
06bd748bd6 | ||
|
|
b64775772b | ||
|
|
5f76314085 | ||
|
|
57588ea936 | ||
|
|
3f344b55bb | ||
|
|
e4ae0980b4 | ||
|
|
e41da0d697 | ||
|
|
ce3955d393 | ||
|
|
22a2cc564f | ||
|
|
2b19513a05 | ||
|
|
60f8fe6f41 | ||
|
|
a2fd010521 | ||
|
|
a36d5b6302 | ||
|
|
2c14dc16dd | ||
|
|
4c7f3f7972 | ||
|
|
794df59265 | ||
|
|
3dd71713c2 | ||
|
|
c0777d1a0a | ||
|
|
55392cb047 | ||
|
|
070eedda18 | ||
|
|
ae6ec78dc3 | ||
|
|
9fe1b2a565 | ||
|
|
f374419be3 | ||
|
|
0ff25cb116 | ||
|
|
d7e50f352a | ||
|
|
aa9254eeb0 | ||
|
|
c1eba336a8 | ||
|
|
a5d7fc484a | ||
|
|
7a294e6d4e | ||
|
|
2f79417d0d | ||
|
|
73b42f924d | ||
|
|
ccf915e798 | ||
|
|
62ffa14f10 | ||
|
|
5d7840a34c | ||
|
|
fd14f6ff73 | ||
|
|
88962f9358 | ||
|
|
5bec1729f1 | ||
|
|
f3662fc152 | ||
|
|
c5047186dd | ||
|
|
1e39bd8336 | ||
|
|
e58de234ac | ||
|
|
903cc181c4 | ||
|
|
2183a098c3 | ||
|
|
1d4cba9180 | ||
|
|
ed724c5280 | ||
|
|
fbd13ac42c | ||
|
|
ea6eab557b | ||
|
|
a1cb2a0589 | ||
|
|
5de5a8ca94 | ||
|
|
274026d338 | ||
|
|
3875bc34bd | ||
|
|
8db3ccce2e | ||
|
|
34bb6fd851 | ||
|
|
ffa74db136 | ||
|
|
66f2cbb91f | ||
|
|
a57d49b057 | ||
|
|
7b41a0ff16 | ||
|
|
4ca50f8973 | ||
|
|
abe2c6870b | ||
|
|
c0ae681d69 | ||
|
|
b4745c0134 | ||
|
|
d369a6429e | ||
|
|
af3e326178 | ||
|
|
8e256a2d5d | ||
|
|
bdcbd9008d | ||
|
|
453faa6a76 | ||
|
|
b0941faf88 | ||
|
|
91ba215568 | ||
|
|
be32f4072e | ||
|
|
bcb217c1da | ||
|
|
490a16a8df | ||
|
|
28d8c56534 | ||
|
|
46423ed166 | ||
|
|
4286a510b4 | ||
|
|
8d193ab39f | ||
|
|
439e377111 | ||
|
|
28ebce6b65 | ||
|
|
2ccd1625e7 | ||
|
|
e05e61a59b | ||
|
|
4660eae8c7 | ||
|
|
e55e90db1a | ||
|
|
23da63767c | ||
|
|
13b19c35c6 | ||
|
|
7e25ec1ac3 | ||
|
|
ab1d05642e | ||
|
|
079b28fddf | ||
|
|
d52d62badb | ||
|
|
fa53135c8a | ||
|
|
d6a3f9fd8f | ||
|
|
75ca4af74e | ||
|
|
dc5fc6bdc2 | ||
|
|
67f8ee61a4 | ||
|
|
2153cf39b5 | ||
|
|
0ead82ae21 | ||
|
|
98d4cf7585 | ||
|
|
3259536411 | ||
|
|
f3a79cc779 | ||
|
|
c45c6dbe67 | ||
|
|
a1518c33af | ||
|
|
a9f7cdb630 | ||
|
|
6f678294a0 | ||
|
|
de07abee98 | ||
|
|
437edefa0c | ||
|
|
f5b36ecbac | ||
|
|
8772c85964 | ||
|
|
a31454327a | ||
|
|
9e55cb114c | ||
|
|
04416a67d3 | ||
|
|
dd2cdaf49a | ||
|
|
8c45eb7524 | ||
|
|
c20bea50e3 | ||
|
|
fe18c35dab | ||
|
|
f6ef6abdf1 | ||
|
|
43a6837e81 | ||
|
|
dc4b933000 | ||
|
|
c90703dc13 | ||
|
|
2165941026 | ||
|
|
4a28893171 | ||
|
|
369581976a | ||
|
|
7fef683980 | ||
|
|
8358f68086 | ||
|
|
0aa6b03c2a | ||
|
|
44f8c98660 | ||
|
|
188ec6ea1d | ||
|
|
8169d8509f | ||
|
|
e217d39882 | ||
|
|
887ee0fd41 | ||
|
|
137e93319e | ||
|
|
48a1384197 | ||
|
|
8aed4d634b | ||
|
|
fd0cb4c458 | ||
|
|
82735f0fab | ||
|
|
1d3710afd8 | ||
|
|
e8ae92f4d4 | ||
|
|
b2e54a0590 | ||
|
|
d64d220b49 | ||
|
|
2523a95a9a | ||
|
|
207c41581c | ||
|
|
6fc4a3ed04 | ||
|
|
2fabb6951e | ||
|
|
8c2f5f91d5 | ||
|
|
7443d41444 | ||
|
|
4421734da1 | ||
|
|
4385ca0966 | ||
|
|
57fa592a13 | ||
|
|
1298118b59 | ||
|
|
3f2cb40cc1 | ||
|
|
5448abb304 | ||
|
|
892fab5455 | ||
|
|
ef3619350d | ||
|
|
846fb3e7f3 | ||
|
|
e00e9ba5aa | ||
|
|
f41511047e | ||
|
|
16352df5b1 | ||
|
|
5238c2457d | ||
|
|
4d57f414f5 | ||
|
|
6305088cb0 | ||
|
|
e2db1cd425 | ||
|
|
16561a8e84 | ||
|
|
cae1b3ebd4 | ||
|
|
e68737dcfb | ||
|
|
00448d23c0 | ||
|
|
272ae547ef | ||
|
|
3fd688191c | ||
|
|
5c0b6f2225 | ||
|
|
cc530e3446 | ||
|
|
fdc1d46b89 | ||
|
|
5dce677091 | ||
|
|
d0fb5a4b04 | ||
|
|
e27daed0ec | ||
|
|
d2183a8b32 | ||
|
|
0b2d6407dd | ||
|
|
ec1b1ffe16 | ||
|
|
32a66be555 | ||
|
|
c090c34491 | ||
|
|
4f7d3ad76c | ||
|
|
ce81872686 | ||
|
|
2314c41103 | ||
|
|
df39b66e11 | ||
|
|
adeb5de19f | ||
|
|
26312e0c0e | ||
|
|
cd6d4021b1 | ||
|
|
24d345a970 | ||
|
|
b4fd4a0c38 | ||
|
|
451e695006 | ||
|
|
26b771f9f9 | ||
|
|
0679aedb7e | ||
|
|
bfa4e08a4e | ||
|
|
c1185a34aa | ||
|
|
be0ce57375 | ||
|
|
b204b90ffc | ||
|
|
364b6938a5 | ||
|
|
e188925d2b | ||
|
|
10a47cdbbb | ||
|
|
67014ae4f8 | ||
|
|
b93fc3f028 | ||
|
|
b6e5980510 | ||
|
|
79e8921f76 | ||
|
|
34fe3ca4fc | ||
|
|
f26311c60e | ||
|
|
43f9907af7 | ||
|
|
0e6f5d154e | ||
|
|
7042dd8447 | ||
|
|
05031e0979 | ||
|
|
28b3f6780c | ||
|
|
f8335c6df9 | ||
|
|
9dcdc1f8f3 | ||
|
|
9ae7d4f2bf | ||
|
|
c158169bdf | ||
|
|
e4c1285eaf | ||
|
|
02a5375503 | ||
|
|
32883b4e18 | ||
|
|
6d585e88a4 | ||
|
|
73570b5628 | ||
|
|
e7fcb068d9 | ||
|
|
a137a70278 | ||
|
|
72113991a8 | ||
|
|
a04fb8e7de | ||
|
|
ca2f30cd61 | ||
|
|
ebfad05e3f | ||
|
|
f54ea9d978 | ||
|
|
d4c84cee19 | ||
|
|
4da59cdc97 | ||
|
|
d4e7eb5888 | ||
|
|
f8b0a7105b | ||
|
|
aecde91d33 | ||
|
|
870dde232a | ||
|
|
f7d7f81c49 | ||
|
|
1f04c61482 | ||
|
|
5d957a6b7c | ||
|
|
94f61b0a0c | ||
|
|
de6535b722 | ||
|
|
6dd18e4328 | ||
|
|
c46e4453c7 | ||
|
|
2e6312ec03 | ||
|
|
1566a834e1 | ||
|
|
607deaa3c4 | ||
|
|
686186d5ba | ||
|
|
0c1ef72285 | ||
|
|
d6bd12cfcd | ||
|
|
4a1712f4cd | ||
|
|
b4e298230d | ||
|
|
6cb42a4251 | ||
|
|
3ead4b4d4b | ||
|
|
3c0e321538 | ||
|
|
1f67434c8c | ||
|
|
6058b9851c | ||
|
|
c586319978 | ||
|
|
0591fe0e8b | ||
|
|
dabe3b17e6 | ||
|
|
fbf50d45cb | ||
|
|
d59075e897 | ||
|
|
2b491179f7 | ||
|
|
a62d17b1b1 | ||
|
|
2431758218 | ||
|
|
b94586fdf4 | ||
|
|
a6b83d77bd | ||
|
|
43c55b36c8 | ||
|
|
24c7928c4b | ||
|
|
8c876c302a | ||
|
|
778a4373ae | ||
|
|
7a15cf1157 | ||
|
|
54e3210d7e | ||
|
|
a3197c12a8 | ||
|
|
e7de841939 | ||
|
|
29ba00f370 | ||
|
|
e35d70f338 | ||
|
|
0271c65ca2 | ||
|
|
e604524301 | ||
|
|
298831d987 | ||
|
|
3b2e97a729 | ||
|
|
edaba44c87 | ||
|
|
dc2dc910e8 | ||
|
|
96bf260ce9 | ||
|
|
115ea4ccbb | ||
|
|
3fb400beb4 | ||
|
|
6442279a44 | ||
|
|
592500cb0c | ||
|
|
98f3e45c0a | ||
|
|
e365196ee3 | ||
|
|
f656499c23 | ||
|
|
180c019d2e | ||
|
|
7db50921bc | ||
|
|
257b3f3ee6 | ||
|
|
f7c69b6baf | ||
|
|
89a3b84ea1 | ||
|
|
bec29f99e6 | ||
|
|
72274bda82 | ||
|
|
04b62a62cb | ||
|
|
ab7329d3eb | ||
|
|
a819796ce2 | ||
|
|
8c6cdcc97e | ||
|
|
bf0148e047 | ||
|
|
bcf44b8ab2 | ||
|
|
ebc9711309 | ||
|
|
4097f90938 | ||
|
|
d73f77affc | ||
|
|
b4794dc541 | ||
|
|
5ee156057e | ||
|
|
68a63bb280 | ||
|
|
815677863f | ||
|
|
df2f13c9b6 | ||
|
|
3984037c98 | ||
|
|
9c8570b37d | ||
|
|
f7cddb81df | ||
|
|
dc1fbbf796 | ||
|
|
7b7b4e5f22 | ||
|
|
8c9b0285e4 | ||
|
|
3ff5caef94 | ||
|
|
4a3446a0a5 | ||
|
|
6f6d9b39ba | ||
|
|
7d2f68c5e4 | ||
|
|
5416e92dbf | ||
|
|
340b5bd165 | ||
|
|
fbd15a81b4 | ||
|
|
039d0abce2 | ||
|
|
aefb65b1b8 | ||
|
|
f7c322c311 | ||
|
|
b5507f79e4 | ||
|
|
a2703ce51b | ||
|
|
d48b12aa09 | ||
|
|
452c1fbfd4 | ||
|
|
f77fd2a944 | ||
|
|
2b1da5b231 | ||
|
|
1b48b98e22 | ||
|
|
4af872ddd5 | ||
|
|
6614107192 | ||
|
|
09e1f9addf | ||
|
|
baf282ecb2 | ||
|
|
6022b32227 | ||
|
|
9e9b08a5a3 | ||
|
|
8147b974aa | ||
|
|
0a5a0ef319 | ||
|
|
00c73b8388 | ||
|
|
dcb8eb7d6d | ||
|
|
7f11651311 | ||
|
|
71518b025d | ||
|
|
287722b1d2 | ||
|
|
3a6f5dd4ee | ||
|
|
4aa3d321fa | ||
|
|
abb04b177c | ||
|
|
764e0f0e7f | ||
|
|
b668175c62 | ||
|
|
5011c394d7 | ||
|
|
994502077a | ||
|
|
7d8bed16b0 | ||
|
|
a45be62b68 | ||
|
|
e0a25b5098 | ||
|
|
fa712aa3a0 | ||
|
|
1599ba0294 | ||
|
|
94d567bf8f | ||
|
|
17f17bcc9e | ||
|
|
12c262621e | ||
|
|
dd35f2c14d | ||
|
|
66a9fd928a | ||
|
|
da82e5dd04 | ||
|
|
98498c9180 | ||
|
|
7b0ed42d3b | ||
|
|
3e4fbde0b4 | ||
|
|
7b0d23f91f | ||
|
|
08d00fa234 | ||
|
|
2e32d9806f | ||
|
|
6e73fbf65e | ||
|
|
b9f74d349c | ||
|
|
5e45e38481 | ||
|
|
78b8455bba | ||
|
|
6f71885aa2 | ||
|
|
e107567997 | ||
|
|
8d42acec16 | ||
|
|
33d73eaecd | ||
|
|
47b20b01d0 | ||
|
|
b94cf700b4 | ||
|
|
a26d30be3c | ||
|
|
ec1cca7ca4 | ||
|
|
0c321c8c98 | ||
|
|
7a54967bee | ||
|
|
f3b6d25aaa | ||
|
|
419133d3e1 | ||
|
|
1402ff371e | ||
|
|
ee2d67c151 | ||
|
|
a8f1db0db1 | ||
|
|
4abcbb9b51 | ||
|
|
e33dd8acc3 | ||
|
|
64e96cc101 | ||
|
|
1aaa737dd6 | ||
|
|
31e3fc9060 | ||
|
|
b70b868552 | ||
|
|
7235357ef5 | ||
|
|
18eecbe9f4 | ||
|
|
505525134f | ||
|
|
7dd740f51a | ||
|
|
3d590f8eb6 | ||
|
|
42a5c6a19f | ||
|
|
2c4f6063a6 | ||
|
|
845767b1d7 | ||
|
|
3e144af127 | ||
|
|
45f470e3a7 | ||
|
|
42a5c60af6 | ||
|
|
29cebd1e1f | ||
|
|
4450f5a084 | ||
|
|
b8230e144a | ||
|
|
d500902eff | ||
|
|
b787de0163 | ||
|
|
2f0d525c2e | ||
|
|
3f0c65ebb2 | ||
|
|
f33796797d | ||
|
|
68a09b9804 | ||
|
|
5e5d149ca5 | ||
|
|
bdf1c275c4 | ||
|
|
439a69f413 | ||
|
|
a14974fbf2 | ||
|
|
1ecd9af2e1 | ||
|
|
c8cc2dac04 | ||
|
|
60dd33b48f | ||
|
|
8b7d8b7786 | ||
|
|
fb7ea7810e | ||
|
|
508e16aa80 | ||
|
|
a057db8756 | ||
|
|
a1c588bde8 | ||
|
|
9b17fdeae2 | ||
|
|
29c0c737ed | ||
|
|
be6986a7f6 | ||
|
|
63c03bb28c | ||
|
|
758f5b27c3 | ||
|
|
32bfb3d57e | ||
|
|
6bd8822a90 | ||
|
|
abf461a049 | ||
|
|
4e98055b9c | ||
|
|
e6ab5bd86d | ||
|
|
02e0651eab | ||
|
|
93be634673 | ||
|
|
a1978f661b | ||
|
|
9bda864fed | ||
|
|
b6903c6b99 | ||
|
|
1e7394135d | ||
|
|
61ccaab55b | ||
|
|
f17c3c52c4 | ||
|
|
f16e721d01 | ||
|
|
6dfdca2d19 | ||
|
|
ee848e66ac | ||
|
|
91e1fa6aff | ||
|
|
6049cf9047 | ||
|
|
e91366c328 | ||
|
|
d6a5aaf4ad | ||
|
|
fcf3f2abc7 | ||
|
|
ae77622026 | ||
|
|
878b395e20 | ||
|
|
92aee9b69c | ||
|
|
fe10ddc720 | ||
|
|
46899f042f | ||
|
|
d4249da131 | ||
|
|
6cae018066 | ||
|
|
95c1886df5 | ||
|
|
fbd8cb07ea | ||
|
|
4868903844 | ||
|
|
62e721b1c8 | ||
|
|
1ceaf1df22 | ||
|
|
21c9f7b7fb | ||
|
|
f5526f73c7 | ||
|
|
15fad2e841 | ||
|
|
3ecb43072d | ||
|
|
2fce2318ed | ||
|
|
226fd29af8 | ||
|
|
c48b39baab | ||
|
|
ed19a6960e | ||
|
|
11b4de63ee | ||
|
|
b9d1d52ab3 | ||
|
|
fe548e580d | ||
|
|
fd7d2765c8 | ||
|
|
a226a70383 | ||
|
|
519e69a7f8 | ||
|
|
3d599f8044 | ||
|
|
bbf0393008 | ||
|
|
f1a4af013a | ||
|
|
05af9f9810 | ||
|
|
f68aada9f8 | ||
|
|
52d60d9623 | ||
|
|
2ddf8a44bc | ||
|
|
281fbc2bee | ||
|
|
c174568081 | ||
|
|
f4a519c824 | ||
|
|
62e4e2f716 | ||
|
|
193e6dfc93 | ||
|
|
7596658e6c | ||
|
|
73d6bd8400 | ||
|
|
922fabd935 | ||
|
|
2f3d267439 | ||
|
|
bdaf7ff30b | ||
|
|
cfca98512a | ||
|
|
23d9e86c46 | ||
|
|
6ac6fb0192 | ||
|
|
aaa36b9d3b | ||
|
|
2c799a8ccf | ||
|
|
56a5a7d72e | ||
|
|
410f9dd759 | ||
|
|
ba45217756 | ||
|
|
5a5929048d | ||
|
|
bfc3c7fbf9 | ||
|
|
e151bd4cd1 | ||
|
|
bfe68520f4 | ||
|
|
45734c0b5c | ||
|
|
d689062fc3 | ||
|
|
881574ed39 | ||
|
|
0bd5aa873b | ||
|
|
51f3ac2376 | ||
|
|
e5802853c0 | ||
|
|
edb5e36916 | ||
|
|
33ba94e784 | ||
|
|
9c969e0026 | ||
|
|
858622a98d | ||
|
|
c673489461 | ||
|
|
53a39b6947 | ||
|
|
8f82d86a5d | ||
|
|
f607cd8bad | ||
|
|
5b0965dc53 | ||
|
|
0db78100cd | ||
|
|
2196f2259f | ||
|
|
55814cbda4 | ||
|
|
6fb48023f2 | ||
|
|
76c1800a53 | ||
|
|
3b2f01e974 | ||
|
|
db141e1f3f | ||
|
|
8ca8824165 | ||
|
|
2e49161415 | ||
|
|
e5f38a6fc1 | ||
|
|
8c105d87c1 | ||
|
|
8c2946a41b | ||
|
|
4f21915f35 | ||
|
|
585bdb549f | ||
|
|
8091c9e737 | ||
|
|
fc504e18d2 | ||
|
|
90c76bb992 | ||
|
|
3da1aa3ec6 | ||
|
|
0a0d72e016 | ||
|
|
550889808a | ||
|
|
1c1da6433a | ||
|
|
963d7958ea | ||
|
|
7031247614 | ||
|
|
07738e13ef | ||
|
|
3ab96aa1ee | ||
|
|
bdd3f6ed44 | ||
|
|
3328847e27 | ||
|
|
4a6f072361 | ||
|
|
5bbcdd121a | ||
|
|
8e89dc8aa9 | ||
|
|
c458b726b4 | ||
|
|
c0a156f347 | ||
|
|
8e12cd6b02 | ||
|
|
a6f92b8ff9 | ||
|
|
cdb1cf1b63 | ||
|
|
877b397e04 | ||
|
|
df13e3ab82 | ||
|
|
8536fe4987 | ||
|
|
eba08334d1 | ||
|
|
165a99fd83 | ||
|
|
6754a9f3da | ||
|
|
12b0d81dda | ||
|
|
95da7c1c87 | ||
|
|
c903785864 | ||
|
|
eae94c5f23 | ||
|
|
ddabfdca3d | ||
|
|
5cf6a30027 | ||
|
|
91c9b4e168 | ||
|
|
914a0c60b0 | ||
|
|
773fb7c75b | ||
|
|
afe20ffe92 | ||
|
|
0b72c0b25c | ||
|
|
f06899303c | ||
|
|
b121d1730b | ||
|
|
5d570b5140 | ||
|
|
980a537930 | ||
|
|
d700c78f6c | ||
|
|
c7abc03fee | ||
|
|
9f243563b9 | ||
|
|
5eac8d860a | ||
|
|
1c8f860b6e | ||
|
|
1226308f3d | ||
|
|
40dd25c122 | ||
|
|
fa71885cf9 | ||
|
|
2a7be0eabb | ||
|
|
ab7c828cfa | ||
|
|
e6f8cfb16c | ||
|
|
0283a42273 | ||
|
|
d1a6d29fdd | ||
|
|
ee15aa888f | ||
|
|
3cc975813d | ||
|
|
f226177bca | ||
|
|
995478adac | ||
|
|
62915d5af5 | ||
|
|
825e2eec51 | ||
|
|
b7f2bae2ef | ||
|
|
9b4701fed7 | ||
|
|
937e55eb46 | ||
|
|
7c003e9e7a | ||
|
|
f0f973eb00 | ||
|
|
f399dd3498 | ||
|
|
d2e5bb99ef | ||
|
|
77eeea95c7 | ||
|
|
056ad51c24 | ||
|
|
97e38255c6 | ||
|
|
88004cac76 | ||
|
|
1162a5f916 | ||
|
|
418c37dd52 | ||
|
|
b66827998d | ||
|
|
b195656900 | ||
|
|
2628ee98f3 | ||
|
|
176c0b2d36 | ||
|
|
4986592dd7 | ||
|
|
a4c4324ba3 | ||
|
|
6442ab2f20 | ||
|
|
c19786bdfb | ||
|
|
1b498128ef | ||
|
|
556939139b | ||
|
|
d5dfd37385 | ||
|
|
508b4d648d | ||
|
|
163813145d | ||
|
|
5baa1aaa2a | ||
|
|
59b7d5a9f4 | ||
|
|
bbd1187a9c | ||
|
|
3f65ae39af | ||
|
|
8bac9853fa | ||
|
|
301a6736ac | ||
|
|
55ee21421e | ||
|
|
1a4ca389cd | ||
|
|
27cfeefef1 | ||
|
|
cc357b2b7d | ||
|
|
6335ac6a47 | ||
|
|
e61ebb4eb9 | ||
|
|
a6b8edde62 | ||
|
|
a4450db277 | ||
|
|
b7e38e95f0 | ||
|
|
cda572fd59 | ||
|
|
af4a0ffa21 | ||
|
|
f786c86f77 | ||
|
|
55365b1d17 | ||
|
|
d605c850b7 | ||
|
|
5bb33ce420 | ||
|
|
39268c681f | ||
|
|
a2b82c18d7 | ||
|
|
83a9ab44bd | ||
|
|
3bf3a276de | ||
|
|
9a7fbaee00 | ||
|
|
6ed01f24be | ||
|
|
04428c5aed | ||
|
|
ba8e48be38 | ||
|
|
bc2613c42b | ||
|
|
ac71a45b3b | ||
|
|
30425a194e | ||
|
|
63e678928b | ||
|
|
e32896137e | ||
|
|
0787909045 | ||
|
|
1acfb53c4c | ||
|
|
46c7e53ca1 | ||
|
|
7228709616 | ||
|
|
2ca5d39f7d | ||
|
|
08583463be | ||
|
|
84d3f6ac9c | ||
|
|
0f8fc7bdee | ||
|
|
cc0ae5e229 | ||
|
|
5750447826 | ||
|
|
908f0047f8 | ||
|
|
e533903cee | ||
|
|
1be8052caa | ||
|
|
668ce4bd2d | ||
|
|
e7fd038493 | ||
|
|
03edb3bbbe | ||
|
|
307a1a295a | ||
|
|
446df58e92 | ||
|
|
1ad5caba93 | ||
|
|
9eddc0e4f0 | ||
|
|
087ba0d81d | ||
|
|
3c5cd8f38f | ||
|
|
367743530f | ||
|
|
7370ce2793 | ||
|
|
ba61b42ef5 | ||
|
|
f7e362dd90 | ||
|
|
66da072fd7 | ||
|
|
d763534208 | ||
|
|
ad05898543 | ||
|
|
f930f7878d | ||
|
|
d6a75c411b | ||
|
|
568a71e0dc | ||
|
|
c92e9aac2c | ||
|
|
3012c4a3ff | ||
|
|
ebe338ac9a | ||
|
|
a45523a48c | ||
|
|
5bfeea67d7 | ||
|
|
f35f15d36c | ||
|
|
057af792df | ||
|
|
41a850e7b2 | ||
|
|
6be70390a6 | ||
|
|
1cfe3ee9f8 | ||
|
|
c1927c985a | ||
|
|
309f42994b | ||
|
|
feb28ecace | ||
|
|
00f74b7f0a | ||
|
|
fcc0e1776b | ||
|
|
a5ec755c28 | ||
|
|
98945926ca | ||
|
|
d3e3767df4 | ||
|
|
de1281bb66 | ||
|
|
07e55c3d89 | ||
|
|
6e4ebeddf4 | ||
|
|
2b9fb88bf0 | ||
|
|
022965b9c7 | ||
|
|
6278718a24 | ||
|
|
1675daafcd | ||
|
|
ed5b6edf52 | ||
|
|
638caa355c | ||
|
|
78b2f9b455 | ||
|
|
2a35ffcc27 | ||
|
|
5eae8f9af6 | ||
|
|
25381e20d2 | ||
|
|
fc35ff5cd1 | ||
|
|
b10d00b426 | ||
|
|
c634dc25b4 | ||
|
|
2fb4561bf8 | ||
|
|
f167c6dcca | ||
|
|
555ace9e2e | ||
|
|
d07ffb36ad | ||
|
|
9e2b8b77c9 | ||
|
|
29e4af4fb2 | ||
|
|
91513a12b4 | ||
|
|
ee3f55dd41 | ||
|
|
c2e5a78076 | ||
|
|
da3ac3e93d | ||
|
|
278ebbc9bd | ||
|
|
546f93147e | ||
|
|
3e7bfbb45c | ||
|
|
c2cf0443ef | ||
|
|
59d68c6438 | ||
|
|
e0ee199bf1 | ||
|
|
c1bf895674 | ||
|
|
ea4d92e671 | ||
|
|
e3f56105d4 | ||
|
|
c447a87605 | ||
|
|
584e5b1f01 | ||
|
|
207dc4c112 | ||
|
|
6a3581f7a3 | ||
|
|
11e74975b3 | ||
|
|
75ef9ec524 | ||
|
|
9b742e777b | ||
|
|
5d93565e16 | ||
|
|
cebfe5c95b | ||
|
|
7881f3a53b | ||
|
|
56269bd52b | ||
|
|
68c43a2cc9 | ||
|
|
120b507c75 | ||
|
|
44fe7e8dc4 | ||
|
|
75d679f141 | ||
|
|
e9570f2400 | ||
|
|
5b8567310c | ||
|
|
f882221db3 | ||
|
|
8c4d7bd641 | ||
|
|
6a78695fde | ||
|
|
73ad16dedd | ||
|
|
dd98112c5a | ||
|
|
47521d3579 | ||
|
|
0c31300578 | ||
|
|
6340ff7da0 | ||
|
|
b66cb49d80 | ||
|
|
c884184220 | ||
|
|
091fee61e0 | ||
|
|
172a268e77 | ||
|
|
924715fe34 | ||
|
|
35a73b4cde | ||
|
|
238f9593f9 | ||
|
|
9e8b5703dc | ||
|
|
d8bd8be57e | ||
|
|
a4d4e8b3a9 | ||
|
|
703dd17e33 | ||
|
|
bc654a462e | ||
|
|
11535825c0 | ||
|
|
196df40c99 | ||
|
|
7aee6c3a15 | ||
|
|
372b566d23 | ||
|
|
9550354442 | ||
|
|
95c3ddfc39 | ||
|
|
bf4f2b6fa0 | ||
|
|
d3f75a92ad | ||
|
|
369495c8d3 | ||
|
|
dd52f71069 | ||
|
|
af8e2bc19d | ||
|
|
947e5591ea | ||
|
|
521376e8e8 | ||
|
|
55c0adb23d | ||
|
|
b20ad7047f | ||
|
|
fa3149c660 | ||
|
|
1463ed4835 | ||
|
|
b959de18d5 | ||
|
|
edac3f73c2 | ||
|
|
388b19eed5 | ||
|
|
a337136389 | ||
|
|
31d5a8ac10 | ||
|
|
46527f56ce | ||
|
|
a575c17eca | ||
|
|
a6ea3b1e6f | ||
|
|
4d2ad842a4 | ||
|
|
ce0f5f3797 | ||
|
|
9e0d22ac90 | ||
|
|
ddc2c56115 | ||
|
|
acfbe6902a | ||
|
|
f7dfab481b | ||
|
|
23692430d5 | ||
|
|
03fe594339 | ||
|
|
45babef689 | ||
|
|
9ac0450255 | ||
|
|
b1d55f657d | ||
|
|
aac5e7b3cd | ||
|
|
791634c377 | ||
|
|
090149eab6 | ||
|
|
acecbf587d | ||
|
|
4ef46971d0 | ||
|
|
2e3cc49782 | ||
|
|
8a0189b079 | ||
|
|
0edd7f6df0 | ||
|
|
0b058bc2e8 | ||
|
|
f9ef9cab81 | ||
|
|
fbb2150d88 | ||
|
|
0912f1f509 | ||
|
|
64c13fa9ae | ||
|
|
2a5f9d9641 | ||
|
|
6c32fe87e6 | ||
|
|
09e9cc99d3 | ||
|
|
94a7ee024a | ||
|
|
a2d7a8c978 | ||
|
|
15499ddc14 | ||
|
|
97cb312386 | ||
|
|
92827a1f04 | ||
|
|
00222c7808 | ||
|
|
427d87be68 | ||
|
|
2560a333b6 | ||
|
|
c6b76db789 | ||
|
|
1414853fce | ||
|
|
cbe384a3be | ||
|
|
cca46573ea | ||
|
|
2589c23998 | ||
|
|
29830865d9 | ||
|
|
35dbc7b0b5 | ||
|
|
cd266213ce | ||
|
|
875eadeb19 | ||
|
|
67896c63a7 | ||
|
|
c643f734e9 | ||
|
|
31d91f5e87 | ||
|
|
2a92f1bc55 | ||
|
|
d9db5528f5 | ||
|
|
22a4ffb78b | ||
|
|
1fb37c37fe | ||
|
|
aae663e5e5 | ||
|
|
e985eda857 | ||
|
|
c9cc7ad9f7 | ||
|
|
65f88cc64e | ||
|
|
374ff92444 | ||
|
|
6d56a60d2b | ||
|
|
75aea37ced | ||
|
|
b133f70b6b | ||
|
|
093af00bbe | ||
|
|
f1da2613be | ||
|
|
1800c52c04 | ||
|
|
329f65a1ad | ||
|
|
d4dd0c00ff | ||
|
|
d9a24f5ac2 | ||
|
|
a13d9a92bd | ||
|
|
2b70bb60a9 | ||
|
|
48737e361a | ||
|
|
8e9f019f82 | ||
|
|
f6a7815837 | ||
|
|
5016de56fe | ||
|
|
879e4a0061 | ||
|
|
6eaf21e5a6 | ||
|
|
b0b38c02b2 | ||
|
|
cd8e1f2080 | ||
|
|
6cc58c194f | ||
|
|
14cf646c47 | ||
|
|
d49197cbe9 | ||
|
|
1687faa438 | ||
|
|
f0e3e556cf | ||
|
|
c9e8709490 | ||
|
|
52dcfaa452 | ||
|
|
9b5a30896d | ||
|
|
4e1450bbb5 | ||
|
|
d478efe444 | ||
|
|
dacb662d99 | ||
|
|
f8cd76bd92 | ||
|
|
6392fd41c6 | ||
|
|
9d91152f01 | ||
|
|
13972c932b | ||
|
|
81ec9017fc | ||
|
|
79b11b9f51 | ||
|
|
d474a051fd | ||
|
|
073cac8530 | ||
|
|
bc3dca45e7 | ||
|
|
ff36c3dfae | ||
|
|
5a5d86ccc3 | ||
|
|
942b1f5159 | ||
|
|
c93fce87da | ||
|
|
1038b06510 | ||
|
|
f8de6022dc | ||
|
|
a8ead2543d | ||
|
|
db856c4391 | ||
|
|
68949c28c8 | ||
|
|
cf67795ff4 | ||
|
|
1136526e4c | ||
|
|
0edeb5cfd0 | ||
|
|
bc7412f6c9 | ||
|
|
025cff9494 | ||
|
|
445e7154e8 | ||
|
|
4eb7e4000b | ||
|
|
028c6cdf50 | ||
|
|
b08ae1dff3 | ||
|
|
37e7d66343 | ||
|
|
e6d06cc278 | ||
|
|
017fd150cd | ||
|
|
ea7e1de833 | ||
|
|
c2767be178 | ||
|
|
c60be43ac6 | ||
|
|
c373a5b505 | ||
|
|
da20aea408 | ||
|
|
973b5b90dc | ||
|
|
cffb5e9539 | ||
|
|
4b35586566 | ||
|
|
1e075d4830 | ||
|
|
c81b5b5df9 | ||
|
|
80b2b8d061 | ||
|
|
d1a7f63797 | ||
|
|
92359dd03b | ||
|
|
d1430c9f5a | ||
|
|
7feca4478e | ||
|
|
02b1d5ed84 | ||
|
|
99d74ce4b6 | ||
|
|
355094c7e2 | ||
|
|
7f61989869 | ||
|
|
7223ff004a | ||
|
|
df333fb144 | ||
|
|
5c08c55957 | ||
|
|
26b812a62a | ||
|
|
cd3d9c709f | ||
|
|
9da90e7ecf | ||
|
|
f17a4ca1de | ||
|
|
8ab662b373 | ||
|
|
fb839da81e | ||
|
|
244da4b10a | ||
|
|
c0c5271172 | ||
|
|
0066f8bd3f | ||
|
|
be9d209622 | ||
|
|
2bbd828f3a | ||
|
|
4f1b6e95a1 | ||
|
|
87ca3a39dc | ||
|
|
d7df46d578 | ||
|
|
489cbc4782 | ||
|
|
3c33a1d05e | ||
|
|
067cf0cba6 | ||
|
|
03a194a514 | ||
|
|
bdf45c0fcb | ||
|
|
6f679c05a3 | ||
|
|
0b131bd957 | ||
|
|
ebf4c80aff | ||
|
|
18a63e226a | ||
|
|
92f56a2f90 | ||
|
|
926e2d4a2e | ||
|
|
5d1d51dd58 | ||
|
|
52018cd424 | ||
|
|
e9153defee | ||
|
|
889fc8b6a9 | ||
|
|
9b9da3133d | ||
|
|
1c8edb0387 | ||
|
|
c0ef1598c9 | ||
|
|
bc1acee6f5 | ||
|
|
9f25d73826 | ||
|
|
f07a62d136 | ||
|
|
06d6b447e4 | ||
|
|
1cff02e4cc | ||
|
|
809a400f57 | ||
|
|
f1bb42f554 | ||
|
|
4fd8f84536 | ||
|
|
223c24450e | ||
|
|
8a7ddf4dc2 | ||
|
|
08217e5a5a | ||
|
|
424dbd9261 | ||
|
|
b615ada2c3 | ||
|
|
20a47873d0 | ||
|
|
d87ce1a124 | ||
|
|
91d012d33d | ||
|
|
330cb22351 | ||
|
|
236debab33 | ||
|
|
13a1c8ac4b | ||
|
|
29fad7b397 | ||
|
|
8eeac8a26d | ||
|
|
133d41d748 | ||
|
|
d444123062 | ||
|
|
4a5c8d3fbb | ||
|
|
afd3d40348 | ||
|
|
85da86a4f1 | ||
|
|
72d4f0f7f8 | ||
|
|
192b479f18 | ||
|
|
3e6dfa3c05 | ||
|
|
5bd28a1e9e | ||
|
|
a23a2601e4 | ||
|
|
3220b629c7 | ||
|
|
9cf122c31a | ||
|
|
75d513a78a | ||
|
|
3cbe4aac87 | ||
|
|
3e47a977e4 | ||
|
|
40855c2d2a | ||
|
|
b2319eda66 | ||
|
|
5c5b8e62e5 | ||
|
|
fbb1f89ab3 | ||
|
|
25b104cf13 | ||
|
|
be1599b418 | ||
|
|
d462e548b1 | ||
|
|
df1e4708f5 | ||
|
|
cf02f4a34f | ||
|
|
480cf09177 | ||
|
|
52a64a7770 | ||
|
|
8d3cb246c2 | ||
|
|
8f15fd45f2 | ||
|
|
afd02b3d78 | ||
|
|
aa1d0b307b | ||
|
|
8a09d8b442 | ||
|
|
7b99470bfa | ||
|
|
30192da7cf | ||
|
|
66337e0975 | ||
|
|
6e4a44438b | ||
|
|
3cc3b864af | ||
|
|
62f6542ca9 | ||
|
|
8c25848e1b | ||
|
|
e112d8277f | ||
|
|
014d0262da | ||
|
|
8ae97f73d0 | ||
|
|
666808b427 | ||
|
|
f208db48a1 | ||
|
|
673b9d9a5c | ||
|
|
ed8ffb228b | ||
|
|
d5a3ff6fb9 | ||
|
|
d3fddfb634 | ||
|
|
f7a54e3377 | ||
|
|
d62bf858dd | ||
|
|
ae0906d322 | ||
|
|
c6cb2931e1 | ||
|
|
0eac576171 | ||
|
|
0ee96db260 | ||
|
|
40a9e00d4c | ||
|
|
d8615330ad | ||
|
|
02afd1d73a | ||
|
|
4eedb4fb69 | ||
|
|
2d6869bdbd | ||
|
|
c0a9848cfb | ||
|
|
40cc7b2a85 | ||
|
|
dfaae24fea | ||
|
|
839ad8ba2b | ||
|
|
e757c66354 | ||
|
|
3ec6da002a | ||
|
|
190b029154 | ||
|
|
0bfc269652 | ||
|
|
b5961f0807 | ||
|
|
a792e312db | ||
|
|
04f81f3dbb | ||
|
|
91401c4571 | ||
|
|
18fe26e853 | ||
|
|
f895ca1fe6 | ||
|
|
ad28ed3154 | ||
|
|
f64abf37ab | ||
|
|
acc5de8d14 | ||
|
|
85bb1302ca | ||
|
|
fc893ba498 | ||
|
|
7527b326d7 | ||
|
|
a6d31ad8b8 | ||
|
|
664c3fcce3 | ||
|
|
e1d1d6a2d9 | ||
|
|
8c1b8ad945 | ||
|
|
ae5efdf16c | ||
|
|
2b82af519c | ||
|
|
7a347d4563 | ||
|
|
1610894a80 | ||
|
|
4eb2ddaf15 | ||
|
|
99a86d8d4e | ||
|
|
637db665c3 | ||
|
|
bb1da81a01 | ||
|
|
d4ddc61a9f | ||
|
|
6ebbc92c4f | ||
|
|
b45172bef1 | ||
|
|
695d3f3327 | ||
|
|
7979cfcb06 | ||
|
|
2986cb0c5f | ||
|
|
5a175955a9 | ||
|
|
cb507f43a7 | ||
|
|
8b148d72c2 | ||
|
|
616596e571 | ||
|
|
2849fe4841 | ||
|
|
98065e80d0 | ||
|
|
286b520d83 | ||
|
|
769b93a277 | ||
|
|
c30ed1b3c8 | ||
|
|
78d7f984d1 | ||
|
|
e88f7e6659 | ||
|
|
e8ff879943 | ||
|
|
f09d5bd155 | ||
|
|
53e73fc622 | ||
|
|
ba94d6f04e | ||
|
|
449f91ab14 | ||
|
|
70623dd554 | ||
|
|
35dc6dcd85 | ||
|
|
41dfafe957 | ||
|
|
2cc1bdee19 | ||
|
|
eb4146d80d | ||
|
|
0d68066086 | ||
|
|
7039cb3bc2 | ||
|
|
510f2f4769 | ||
|
|
5415f68c1b | ||
|
|
475f0fa2ff | ||
|
|
c58b1140d8 | ||
|
|
c97c1e97b9 | ||
|
|
ba3d82e5e5 | ||
|
|
d432899b42 | ||
|
|
08da38a609 | ||
|
|
6a3eb2f2f9 | ||
|
|
6a02c3ac4c | ||
|
|
f1761c0c9c | ||
|
|
39076c75cf | ||
|
|
3be8cacc24 | ||
|
|
46a9df47e4 | ||
|
|
d44a31cc62 | ||
|
|
00b2fd1479 | ||
|
|
5f08e7a612 | ||
|
|
5c8725373a | ||
|
|
c455f6e730 | ||
|
|
3cc83b8ec4 | ||
|
|
f74de76d70 | ||
|
|
ea8ddc6451 | ||
|
|
5f36c37cf2 | ||
|
|
2ad2873278 | ||
|
|
3855895808 | ||
|
|
f86cd74a98 | ||
|
|
1e6ecbadcd | ||
|
|
33716a3385 | ||
|
|
252f0bf967 | ||
|
|
2c3e1d1055 | ||
|
|
aafa639bf1 | ||
|
|
815a8a74fc | ||
|
|
840ea80e20 | ||
|
|
773ae2c8c6 | ||
|
|
4aadb4b86f | ||
|
|
91d1d71f6d | ||
|
|
a3d6a94600 | ||
|
|
43ae7a23b2 | ||
|
|
b6005886fa | ||
|
|
28dd34a136 | ||
|
|
3a3c263203 | ||
|
|
87b7ecd1d6 | ||
|
|
f5a309b5ad | ||
|
|
0f00add402 | ||
|
|
1014fa53dd | ||
|
|
04568835bd | ||
|
|
e4f8edc07c | ||
|
|
a8533d1677 | ||
|
|
edcb66afb7 |
92
.github/workflows/go.yml
vendored
92
.github/workflows/go.yml
vendored
@@ -5,51 +5,45 @@ name: Go
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
branches: [ "*" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
branches: [ "*" ]
|
||||
|
||||
jobs:
|
||||
|
||||
test-macos:
|
||||
runs-on: macos-latest
|
||||
test:
|
||||
strategy:
|
||||
matrix:
|
||||
llvm: [17]
|
||||
# os: [macos-latest, ubuntu-latest]
|
||||
os: [macos-latest]
|
||||
llvm: [18]
|
||||
runs-on: ${{ matrix.os }}
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Update Homebrew
|
||||
if: matrix.llvm == 17 # needed as long as LLVM 17 is still fresh
|
||||
# needed as long as LLVM 18 is still fresh
|
||||
if: matrix.llvm == 18 && startsWith(matrix.os, 'macos')
|
||||
run: brew update
|
||||
- name: Install LLVM ${{ matrix.llvm }}
|
||||
run: HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }}
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '1.20'
|
||||
|
||||
- name: Build
|
||||
run: go build -v ./...
|
||||
|
||||
- name: Test
|
||||
run: go test -v ./...
|
||||
|
||||
test-linux:
|
||||
runs-on: ubuntu-20.04
|
||||
strategy:
|
||||
matrix:
|
||||
llvm: [17]
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
- name: Install LLVM ${{ matrix.llvm }}
|
||||
- name: Install LLVM ${{ matrix.llvm }} and bdw-gc
|
||||
if: startsWith(matrix.os, 'macos')
|
||||
run: |
|
||||
echo 'deb http://apt.llvm.org/focal/ llvm-toolchain-focal-${{ matrix.llvm }} main' | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
HOMEBREW_NO_AUTO_UPDATE=1 brew install llvm@${{ matrix.llvm }} bdw-gc
|
||||
echo `brew --prefix llvm@${{ matrix.llvm }}`/bin >> $GITHUB_PATH
|
||||
- name: Install LLVM ${{ matrix.llvm }} and libgc-dev
|
||||
if: startsWith(matrix.os, 'ubuntu')
|
||||
run: |
|
||||
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-${{ matrix.llvm }} main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update
|
||||
sudo apt-get install --no-install-recommends llvm-${{ matrix.llvm }}-dev
|
||||
sudo apt-get install -y llvm-${{ matrix.llvm }}-dev clang-${{ matrix.llvm }} lld-${{ matrix.llvm }} pkg-config libgc-dev libcjson-dev libsqlite3-dev python3.11-dev
|
||||
echo /usr/lib/llvm-${{ matrix.llvm }}/bin >> $GITHUB_PATH
|
||||
|
||||
- name: Clang information
|
||||
run: |
|
||||
echo $PATH
|
||||
which clang
|
||||
clang --version
|
||||
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
@@ -60,4 +54,40 @@ jobs:
|
||||
run: go build -v ./...
|
||||
|
||||
- name: Test
|
||||
if: matrix.os != 'macos-latest'
|
||||
run: go test -v ./...
|
||||
|
||||
- name: Test with coverage
|
||||
if: matrix.os == 'macos-latest'
|
||||
run: go test -v -coverprofile="coverage.txt" -covermode=atomic ./...
|
||||
|
||||
- name: Install
|
||||
run: go install ./...
|
||||
|
||||
- name: LLGO tests
|
||||
if: matrix.os != 'ubuntu-latest'
|
||||
run: |
|
||||
echo "Test result on ${{ matrix.os }} with LLVM ${{ matrix.llvm }}" > result.md
|
||||
LLGOROOT=$PWD bash .github/workflows/test_llgo.sh
|
||||
|
||||
- name: Test _demo and _pydemo
|
||||
run: |
|
||||
set +e
|
||||
LLGOROOT=$PWD bash .github/workflows/test_demo.sh
|
||||
exit 0
|
||||
|
||||
- name: Show test result
|
||||
run: cat result.md
|
||||
|
||||
- name: PR comment with test result
|
||||
uses: thollander/actions-comment-pull-request@v2
|
||||
if: false
|
||||
with:
|
||||
filePath: result.md
|
||||
comment_tag: test-result-on-${{ matrix.os }}-with-llvm-${{ matrix.llvm }}
|
||||
|
||||
- name: Upload coverage reports to Codecov
|
||||
uses: codecov/codecov-action@v4
|
||||
with:
|
||||
token: ${{ secrets.CODECOV_TOKEN }}
|
||||
slug: goplus/llgo
|
||||
|
||||
40
.github/workflows/populate_darwin_sysroot.sh
vendored
Executable file
40
.github/workflows/populate_darwin_sysroot.sh
vendored
Executable file
@@ -0,0 +1,40 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
TMPDIR="$(mktemp -d)"
|
||||
export TMPDIR
|
||||
trap 'rm -rf "${TMPDIR}"' EXIT
|
||||
|
||||
DARWIN_AMD64_LLVM_PREFIX=.sysroot/darwin/amd64/usr/local/opt/llvm@18
|
||||
DARWIN_ARM64_LLVM_PREFIX=.sysroot/darwin/arm64/opt/homebrew/opt/llvm@18
|
||||
mkdir -p "${DARWIN_AMD64_LLVM_PREFIX}" "${DARWIN_ARM64_LLVM_PREFIX}"
|
||||
|
||||
BREW_LLVM_FORMULA_JSON="$(mktemp)"
|
||||
curl -fsSL https://formulae.brew.sh/api/formula/llvm.json > "${BREW_LLVM_FORMULA_JSON}"
|
||||
BREW_LLVM_AMD64_BOTTLE_URL=$(jq -r '.bottle.stable.files.sonoma.url' "${BREW_LLVM_FORMULA_JSON}")
|
||||
BREW_LLVM_ARM64_BOTTLE_URL=$(jq -r '.bottle.stable.files.arm64_sonoma.url' "${BREW_LLVM_FORMULA_JSON}")
|
||||
curl -fsSL -H "Authorization: Bearer QQ==" "${BREW_LLVM_AMD64_BOTTLE_URL}" | tar -xzf - --strip-components=2 -C "${DARWIN_AMD64_LLVM_PREFIX}"
|
||||
curl -fsSL -H "Authorization: Bearer QQ==" "${BREW_LLVM_ARM64_BOTTLE_URL}" | tar -xzf - --strip-components=2 -C "${DARWIN_ARM64_LLVM_PREFIX}"
|
||||
|
||||
patch_homebrew_lib_dir() {
|
||||
local LIB_DIR="$1"
|
||||
local HOMEBREW_PREFIX="$2"
|
||||
for DYLIB_FILE in "${LIB_DIR}"/*.dylib; do
|
||||
if [[ -f "${DYLIB_FILE}" ]]; then
|
||||
ID=$(otool -D "${DYLIB_FILE}" | grep '@@HOMEBREW_PREFIX@@' | awk '{print $1}')
|
||||
if [[ -n "${ID}" ]]; then
|
||||
NEW_ID=${ID/'@@HOMEBREW_PREFIX@@'/${HOMEBREW_PREFIX}}
|
||||
install_name_tool -id "${NEW_ID}" "${DYLIB_FILE}"
|
||||
fi
|
||||
|
||||
DEPS=$(otool -L "${DYLIB_FILE}" | grep '@@HOMEBREW_PREFIX@@' | awk '{print $1}')
|
||||
for DEP in ${DEPS}; do
|
||||
NEW_DEP=${DEP/'@@HOMEBREW_PREFIX@@'/${HOMEBREW_PREFIX}}
|
||||
install_name_tool -change "${DEP}" "${NEW_DEP}" "${DYLIB_FILE}"
|
||||
done
|
||||
fi
|
||||
done
|
||||
}
|
||||
patch_homebrew_lib_dir "${DARWIN_AMD64_LLVM_PREFIX}/lib" /usr/lib
|
||||
patch_homebrew_lib_dir "${DARWIN_ARM64_LLVM_PREFIX}/lib" /opt/homebrew
|
||||
143
.github/workflows/populate_linux_sysroot.sh
vendored
Executable file
143
.github/workflows/populate_linux_sysroot.sh
vendored
Executable file
@@ -0,0 +1,143 @@
|
||||
#!/bin/bash
|
||||
|
||||
set -e
|
||||
|
||||
TMPDIR="$(mktemp -d)"
|
||||
export TMPDIR
|
||||
trap 'rm -rf "${TMPDIR}"' EXIT
|
||||
|
||||
LINUX_AMD64_PREFIX=.sysroot/linux/amd64
|
||||
LINUX_ARM64_PREFIX=.sysroot/linux/arm64
|
||||
mkdir -p "${LINUX_AMD64_PREFIX}" "${LINUX_ARM64_PREFIX}"
|
||||
|
||||
POPULATE_LINUX_SYSROOT_SCRIPT="$(mktemp)"
|
||||
cat > "${POPULATE_LINUX_SYSROOT_SCRIPT}" << EOF
|
||||
#!/bin/bash
|
||||
|
||||
export DEBIAN_FRONTEND=noninteractive
|
||||
|
||||
apt-get update
|
||||
apt-get install -y lsb-release gnupg2 wget rsync
|
||||
|
||||
echo "deb http://apt.llvm.org/\$(lsb_release -cs)/ llvm-toolchain-\$(lsb_release -cs)-18 main" | tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | apt-key add -
|
||||
apt-get update
|
||||
apt-get install -y llvm-18-dev
|
||||
|
||||
error() {
|
||||
echo -e "\$1" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
exclude_list=()
|
||||
include_list=()
|
||||
|
||||
exclude_list+=(--exclude "/bin")
|
||||
exclude_list+=(--exclude "/boot")
|
||||
exclude_list+=(--exclude "/boot*")
|
||||
exclude_list+=(--exclude "/dev")
|
||||
exclude_list+=(--exclude "/etc")
|
||||
exclude_list+=(--exclude "/home")
|
||||
exclude_list+=(--exclude "/lib/dhcpd")
|
||||
exclude_list+=(--exclude "/lib/firmware")
|
||||
exclude_list+=(--exclude "/lib/hdparm")
|
||||
exclude_list+=(--exclude "/lib/ifupdown")
|
||||
exclude_list+=(--exclude "/lib/modules")
|
||||
exclude_list+=(--exclude "/lib/modprobe.d")
|
||||
exclude_list+=(--exclude "/lib/modules-load.d")
|
||||
exclude_list+=(--exclude "/lib/resolvconf")
|
||||
exclude_list+=(--exclude "/lib/startpar")
|
||||
exclude_list+=(--exclude "/lib/systemd")
|
||||
exclude_list+=(--exclude "/lib/terminfo")
|
||||
exclude_list+=(--exclude "/lib/udev")
|
||||
exclude_list+=(--exclude "/lib/xtables")
|
||||
exclude_list+=(--exclude "/lib/ssl/private")
|
||||
exclude_list+=(--exclude "/lost+found")
|
||||
exclude_list+=(--exclude "/media")
|
||||
exclude_list+=(--exclude "/mnt")
|
||||
exclude_list+=(--exclude "/proc")
|
||||
exclude_list+=(--exclude "/root")
|
||||
exclude_list+=(--exclude "/run")
|
||||
exclude_list+=(--exclude "/sbin")
|
||||
exclude_list+=(--exclude "/srv")
|
||||
exclude_list+=(--exclude "/sys")
|
||||
exclude_list+=(--exclude "/tmp")
|
||||
exclude_list+=(--exclude "/usr/bin")
|
||||
exclude_list+=(--exclude "/usr/games")
|
||||
exclude_list+=(--exclude "/usr/sbin")
|
||||
exclude_list+=(--exclude "/usr/share")
|
||||
exclude_list+=(--exclude "/usr/src")
|
||||
exclude_list+=(--exclude "/usr/local/bin")
|
||||
exclude_list+=(--exclude "/usr/local/etc")
|
||||
exclude_list+=(--exclude "/usr/local/games")
|
||||
exclude_list+=(--exclude "/usr/local/man")
|
||||
exclude_list+=(--exclude "/usr/local/sbin")
|
||||
exclude_list+=(--exclude "/usr/local/share")
|
||||
exclude_list+=(--exclude "/usr/local/src")
|
||||
exclude_list+=(--exclude "/usr/lib/ssl/private")
|
||||
exclude_list+=(--exclude "/var")
|
||||
exclude_list+=(--exclude "/snap")
|
||||
exclude_list+=(--exclude "*python*")
|
||||
|
||||
include_list+=(--include "*.a")
|
||||
include_list+=(--include "*.so")
|
||||
include_list+=(--include "*.so.*")
|
||||
include_list+=(--include "*.h")
|
||||
include_list+=(--include "*.hh")
|
||||
include_list+=(--include "*.hpp")
|
||||
include_list+=(--include "*.hxx")
|
||||
include_list+=(--include "*.pc")
|
||||
include_list+=(--include "*.def")
|
||||
include_list+=(--include "*.inc")
|
||||
include_list+=(--include "/lib")
|
||||
include_list+=(--include "/lib32")
|
||||
include_list+=(--include "/lib64")
|
||||
include_list+=(--include "/libx32")
|
||||
include_list+=(--include "*/")
|
||||
|
||||
do-sync() {
|
||||
from=\$1
|
||||
to=\$2
|
||||
|
||||
args=()
|
||||
args+=(-a)
|
||||
args+=(-z)
|
||||
args+=(-m)
|
||||
args+=(-d)
|
||||
args+=(-h)
|
||||
args+=(--keep-dirlinks)
|
||||
args+=("--info=progress2")
|
||||
args+=(--delete)
|
||||
args+=(--prune-empty-dirs)
|
||||
args+=(--sparse)
|
||||
args+=(--links)
|
||||
args+=(--copy-unsafe-links)
|
||||
args+=("\${exclude_list[@]}")
|
||||
args+=("\${include_list[@]}")
|
||||
args+=(--exclude "*")
|
||||
args+=("\${from}")
|
||||
args+=("\${to}")
|
||||
|
||||
echo "\${args[@]}"
|
||||
rsync "\${args[@]}"
|
||||
|
||||
exit \$?
|
||||
}
|
||||
|
||||
do-sync / /sysroot/
|
||||
EOF
|
||||
chmod +x "${POPULATE_LINUX_SYSROOT_SCRIPT}"
|
||||
|
||||
populate_linux_sysroot() {
|
||||
local ARCH="$1"
|
||||
local PREFIX="$2"
|
||||
docker run \
|
||||
--rm \
|
||||
--platform "linux/${ARCH}" \
|
||||
-v "$(pwd)/${PREFIX}":/sysroot \
|
||||
-v "${POPULATE_LINUX_SYSROOT_SCRIPT}":/populate_linux_sysroot.sh \
|
||||
debian:bullseye \
|
||||
/populate_linux_sysroot.sh
|
||||
}
|
||||
populate_linux_sysroot amd64 "${LINUX_AMD64_PREFIX}"
|
||||
populate_linux_sysroot arm64 "${LINUX_ARM64_PREFIX}"
|
||||
58
.github/workflows/release-build.yml
vendored
Normal file
58
.github/workflows/release-build.yml
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
name: Release Build
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "*"
|
||||
|
||||
jobs:
|
||||
populate-darwin-sysroot:
|
||||
runs-on: macos-latest
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
- name: Populate Darwin sysroot
|
||||
run: bash .github/workflows/populate_darwin_sysroot.sh
|
||||
- name: Create Darwin sysroot tarball
|
||||
run: tar -czvf .sysroot/darwin.tar.gz -C .sysroot darwin
|
||||
- name: Upload Darwin sysroot tarball
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: darwin-sysroot-tarball
|
||||
path: .sysroot/darwin.tar.gz
|
||||
compression-level: 0
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
needs: populate-darwin-sysroot
|
||||
steps:
|
||||
- name: Check out code
|
||||
uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: 1.20.x
|
||||
- name: Set up QEMU
|
||||
uses: docker/setup-qemu-action@v3
|
||||
- name: Download Darwin sysroot tarball
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: darwin-sysroot-tarball
|
||||
path: .sysroot
|
||||
- name: Populate Darwin sysroot
|
||||
run: tar -xzvf .sysroot/darwin.tar.gz -C .sysroot
|
||||
- name: Populate Linux sysroot
|
||||
run: bash .github/workflows/populate_linux_sysroot.sh
|
||||
- name: Run GoReleaser
|
||||
env:
|
||||
GITHUB_TOKEN: ${{github.token}}
|
||||
run: |
|
||||
docker run \
|
||||
--rm \
|
||||
-e GITHUB_TOKEN=${GITHUB_TOKEN} \
|
||||
-v /var/run/docker.sock:/var/run/docker.sock \
|
||||
-v $(pwd):/go/src/llgo \
|
||||
-w /go/src/llgo \
|
||||
ghcr.io/goreleaser/goreleaser-cross:v1.22 \
|
||||
release --clean --skip nfpm,snapcraft
|
||||
29
.github/workflows/test_demo.sh
vendored
Normal file
29
.github/workflows/test_demo.sh
vendored
Normal file
@@ -0,0 +1,29 @@
|
||||
#!/bin/bash
|
||||
|
||||
# llgo run subdirectories under _demo and _pydemo
|
||||
total=0
|
||||
failed=0
|
||||
failed_cases=""
|
||||
for d in ./_demo/* ./_pydemo/*; do
|
||||
total=$((total+1))
|
||||
if [ -d "$d" ]; then
|
||||
echo "Testing $d"
|
||||
if ! llgo run "$d"; then
|
||||
echo "FAIL"
|
||||
failed=$((failed+1))
|
||||
failed_cases="$failed_cases\n* :x: $d"
|
||||
else
|
||||
echo "PASS"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
echo "=== Done"
|
||||
echo "$((total-failed))/$total tests passed"
|
||||
|
||||
if [ "$failed" -ne 0 ]; then
|
||||
echo ":bangbang: Failed demo cases:" | tee -a result.md
|
||||
echo -e "$failed_cases" | tee -a result.md
|
||||
exit 1
|
||||
else
|
||||
echo ":white_check_mark: All demo tests passed" | tee -a result.md
|
||||
fi
|
||||
38
.github/workflows/test_llgo.sh
vendored
Normal file
38
.github/workflows/test_llgo.sh
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
export LLGOROOT=$PWD
|
||||
|
||||
testcmd=/tmp/test
|
||||
llgo build -o $testcmd ./c/bdwgc/_test
|
||||
cases=$($testcmd)
|
||||
total=$(echo "$cases" | wc -l | tr -d ' ')
|
||||
failed=0
|
||||
failed_cases=""
|
||||
|
||||
for idx in $(seq 1 $((total))); do
|
||||
case=$(echo "$cases" | sed -n "${idx}p")
|
||||
case_name=$(echo "$case" | cut -d',' -f2)
|
||||
echo "=== Test case: $case_name"
|
||||
set +e
|
||||
out=$("$testcmd" "$((idx-1))" 2>&1)
|
||||
exit_code=$?
|
||||
set -e
|
||||
if [ "${exit_code:-0}" -ne 0 ]; then
|
||||
echo "failed: $out"
|
||||
failed=$((failed+1))
|
||||
failed_cases="$failed_cases\n* :x: $case_name"
|
||||
else
|
||||
echo "passed"
|
||||
fi
|
||||
done
|
||||
echo "=== Done"
|
||||
echo "$((total-failed))/$total tests passed"
|
||||
|
||||
if [ "$failed" -ne 0 ]; then
|
||||
echo ":bangbang: Failed llgo cases:" | tee -a result.md
|
||||
echo -e "$failed_cases" | tee -a result.md
|
||||
exit 1
|
||||
else
|
||||
echo ":white_check_mark: All llgo tests passed" | tee -a result.md
|
||||
fi
|
||||
17
.gitignore
vendored
17
.gitignore
vendored
@@ -8,7 +8,20 @@
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
test.db
|
||||
demo.ll
|
||||
llgo_autogen*.ll
|
||||
stories*.bin
|
||||
.DS_Store
|
||||
err.log
|
||||
numpy.txt
|
||||
|
||||
_go/
|
||||
_runtime/
|
||||
_tinygo/
|
||||
_output/
|
||||
build.dir/
|
||||
.vscode/
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
@@ -22,3 +35,7 @@ _tinygo/
|
||||
|
||||
# Go workspace file
|
||||
go.work*
|
||||
|
||||
# GoReleaser
|
||||
.dist/
|
||||
.sysroot/
|
||||
|
||||
3
.gitmodules
vendored
Normal file
3
.gitmodules
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
[submodule "c/llama2/llama2.c"]
|
||||
path = c/llama2/llama2.c
|
||||
url = https://github.com/karpathy/llama2.c.git
|
||||
145
.goreleaser.yaml
Normal file
145
.goreleaser.yaml
Normal file
@@ -0,0 +1,145 @@
|
||||
version: 2
|
||||
|
||||
dist: .dist
|
||||
|
||||
env:
|
||||
- SYSROOT_DARWIN_AMD64={{.Env.PWD}}/.sysroot/darwin/amd64
|
||||
- SYSROOT_DARWIN_ARM64={{.Env.PWD}}/.sysroot/darwin/arm64
|
||||
- SYSROOT_LINUX_AMD64={{.Env.PWD}}/.sysroot/linux/amd64
|
||||
- SYSROOT_LINUX_ARM64={{.Env.PWD}}/.sysroot/linux/arm64
|
||||
- CGO_ENABLED=1
|
||||
- CGO_CXXFLAGS=-std=c++17
|
||||
|
||||
before:
|
||||
hooks:
|
||||
- go mod download
|
||||
|
||||
builds:
|
||||
- id: llgo-darwin-amd64
|
||||
main: ./cmd/llgo
|
||||
flags:
|
||||
- -tags=darwin,amd64,byollvm
|
||||
ldflags:
|
||||
- -X github.com/goplus/llgo/xtool/env.buildVersion=v{{.Version}}
|
||||
- -X github.com/goplus/llgo/xtool/env.buildDate={{.Date}}
|
||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/local/opt/llvm@18/bin/llvm-config
|
||||
env:
|
||||
- CC=o64-clang
|
||||
- CXX=o64-clang++
|
||||
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_AMD64}}/usr/local/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_AMD64}}/usr/local/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-18 -lz -lm
|
||||
targets:
|
||||
- darwin_amd64
|
||||
mod_timestamp: "{{.CommitTimestamp}}"
|
||||
- id: llgo-darwin-arm64
|
||||
main: ./cmd/llgo
|
||||
flags:
|
||||
- -tags=darwin,arm64,byollvm
|
||||
ldflags:
|
||||
- -X github.com/goplus/llgo/xtool/env.buildVersion=v{{.Version}}
|
||||
- -X github.com/goplus/llgo/xtool/env.buildDate={{.Date}}
|
||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/opt/homebrew/opt/llvm@18/bin/llvm-config
|
||||
env:
|
||||
- CC=oa64-clang
|
||||
- CXX=oa64-clang++
|
||||
- CGO_CPPFLAGS=-I{{.Env.SYSROOT_DARWIN_ARM64}}/opt/homebrew/opt/llvm@18/include -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
- CGO_LDFLAGS=-L{{.Env.SYSROOT_DARWIN_ARM64}}/opt/homebrew/opt/llvm@18/lib -Wl,-search_paths_first -Wl,-headerpad_max_install_names -lLLVM-18 -lz -lm
|
||||
targets:
|
||||
- darwin_arm64
|
||||
mod_timestamp: "{{.CommitTimestamp}}"
|
||||
- id: llgo-linux-amd64
|
||||
main: ./cmd/llgo
|
||||
flags:
|
||||
- -tags=linux,amd64,byollvm
|
||||
ldflags:
|
||||
- -X github.com/goplus/llgo/xtool/env.buildVersion=v{{.Version}}
|
||||
- -X github.com/goplus/llgo/xtool/env.buildDate={{.Date}}
|
||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-18/bin/llvm-config
|
||||
env:
|
||||
- CC=x86_64-linux-gnu-gcc
|
||||
- CXX=x86_64-linux-gnu-g++
|
||||
- CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-18 -I{{.Env.SYSROOT_LINUX_AMD64}}/usr/include/llvm-c-18 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_AMD64}} -L{{.Env.SYSROOT_LINUX_AMD64}}/usr/lib/llvm-18/lib -lLLVM-18
|
||||
targets:
|
||||
- linux_amd64
|
||||
mod_timestamp: "{{.CommitTimestamp}}"
|
||||
- id: llgo-linux-arm64
|
||||
main: ./cmd/llgo
|
||||
flags:
|
||||
- -tags=linux,arm64,byollvm
|
||||
ldflags:
|
||||
- -X github.com/goplus/llgo/xtool/env.buildVersion=v{{.Version}}
|
||||
- -X github.com/goplus/llgo/xtool/env.buildDate={{.Date}}
|
||||
- -X github.com/goplus/llgo/xtool/env/llvm.ldLLVMConfigBin=/usr/lib/llvm-18/bin/llvm-config
|
||||
env:
|
||||
- CC=aarch64-linux-gnu-gcc
|
||||
- CXX=aarch64-linux-gnu-g++
|
||||
- CGO_CPPFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-18 -I{{.Env.SYSROOT_LINUX_ARM64}}/usr/include/llvm-c-18 -D_GNU_SOURCE -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS
|
||||
- CGO_LDFLAGS=--sysroot={{.Env.SYSROOT_LINUX_ARM64}} -L{{.Env.SYSROOT_LINUX_ARM64}}/usr/lib/llvm-18/lib -lLLVM-18
|
||||
targets:
|
||||
- linux_arm64
|
||||
mod_timestamp: "{{.CommitTimestamp}}"
|
||||
|
||||
archives:
|
||||
- format: tar.gz
|
||||
name_template: >-
|
||||
{{.ProjectName}}{{.Version}}.{{.Os}}-{{.Arch}}
|
||||
{{- if .Arm}}v{{.Arm}}{{end}}
|
||||
files:
|
||||
- LICENSE
|
||||
- README.md
|
||||
|
||||
checksum:
|
||||
name_template: "{{.ProjectName}}{{.Version}}.checksums.txt"
|
||||
|
||||
nfpms:
|
||||
- package_name: llgo
|
||||
vendor: goplus
|
||||
homepage: https://github.com/goplus/llgo
|
||||
maintainer: Aofei Sheng <aofei@aofeisheng.com>
|
||||
description: |
|
||||
LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a
|
||||
subproject of the Go+ project.
|
||||
|
||||
LLGo aims to expand the boundaries of Go/Go+, providing limitless possibilities such as:
|
||||
|
||||
- Game development
|
||||
- AI and data science
|
||||
- WebAssembly
|
||||
- Embedded development
|
||||
- ...
|
||||
license: Apache-2.0
|
||||
formats:
|
||||
- deb
|
||||
- rpm
|
||||
file_name_template: >-
|
||||
{{.ProjectName}}{{.Version}}.{{.Os}}-{{.Arch}}
|
||||
{{- if .Arm}}v{{.Arm}}{{end}}
|
||||
bindir: /usr/local/bin
|
||||
|
||||
snapcrafts:
|
||||
- name: llgo
|
||||
title: A Go compiler based on LLVM
|
||||
summary: A Go compiler based on LLVM
|
||||
description: |
|
||||
LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a
|
||||
subproject of the Go+ project.
|
||||
|
||||
LLGo aims to expand the boundaries of Go/Go+, providing limitless possibilities such as:
|
||||
|
||||
- Game development
|
||||
- AI and data science
|
||||
- WebAssembly
|
||||
- Embedded development
|
||||
- ...
|
||||
license: Apache-2.0
|
||||
confinement: classic
|
||||
name_template: >-
|
||||
{{.ProjectName}}{{.Version}}.{{.Os}}-{{.Arch}}
|
||||
{{- if .Arm}}v{{.Arm}}{{end}}
|
||||
|
||||
snapshot:
|
||||
name_template: '{{trimprefix .Summary "v"}}'
|
||||
|
||||
release:
|
||||
prerelease: auto
|
||||
354
README.md
354
README.md
@@ -4,7 +4,355 @@ llgo - A Go compiler based on LLVM
|
||||
[](https://github.com/goplus/llgo/actions/workflows/go.yml)
|
||||
[](https://goreportcard.com/report/github.com/goplus/llgo)
|
||||
[](https://github.com/goplus/llgo/releases)
|
||||
[](https://pkg.go.dev/github.com/goplus/llgo)
|
||||
<!--
|
||||
[](https://codecov.io/gh/goplus/llgo)
|
||||
-->
|
||||
[](https://pkg.go.dev/github.com/goplus/llgo)
|
||||
[](https://github.com/goplus/gop)
|
||||
|
||||
LLGo is a Go compiler based on LLVM in order to better integrate Go with the C ecosystem including Python. It's a subproject of [the Go+ project](https://github.com/goplus/gop).
|
||||
|
||||
LLGo aims to expand the boundaries of Go/Go+, providing limitless possibilities such as:
|
||||
|
||||
* Game development
|
||||
* AI and data science
|
||||
* WebAssembly
|
||||
* Embedded development
|
||||
* ...
|
||||
|
||||
How can these be achieved?
|
||||
|
||||
```
|
||||
LLGo := Go + C + Python
|
||||
```
|
||||
|
||||
LLGo is compatible with C and Python through the language's **Application Binary Interface (ABI)**, while LLGo is compatible with Go through its **syntax (source code)**.
|
||||
|
||||
|
||||
## C/C++ standard libary support
|
||||
|
||||
You can import a C/C++ standard library in LLGo!
|
||||
|
||||
* [c](https://pkg.go.dev/github.com/goplus/llgo/c)
|
||||
* [c/os](https://pkg.go.dev/github.com/goplus/llgo/c/os)
|
||||
* [c/syscall](https://pkg.go.dev/github.com/goplus/llgo/c/syscall)
|
||||
* [c/math](https://pkg.go.dev/github.com/goplus/llgo/c/math)
|
||||
* [c/math/cmplx](https://pkg.go.dev/github.com/goplus/llgo/c/math/cmplx)
|
||||
* [c/math/rand](https://pkg.go.dev/github.com/goplus/llgo/c/math/rand)
|
||||
* [c/pthread](https://pkg.go.dev/github.com/goplus/llgo/c/pthread)
|
||||
* [c/pthread/sync](https://pkg.go.dev/github.com/goplus/llgo/c/pthread/sync)
|
||||
* [c/sync/atomic](https://pkg.go.dev/github.com/goplus/llgo/c/sync/atomic)
|
||||
* [c/time](https://pkg.go.dev/github.com/goplus/llgo/c/time)
|
||||
* [c/socket](https://pkg.go.dev/github.com/goplus/llgo/c/socket)
|
||||
* [cpp/std](https://pkg.go.dev/github.com/goplus/llgo/cpp/std)
|
||||
|
||||
Here is a simple example:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/goplus/llgo/c"
|
||||
|
||||
func main() {
|
||||
c.Printf(c.Str("Hello world\n"))
|
||||
}
|
||||
```
|
||||
|
||||
This is a simple example of calling the C `printf` function to print `Hello world`. Here, `c.Str` is not a function for converting a Go string to a C string, but a built-in instruction supported by `llgo` for generating a C string constant.
|
||||
|
||||
The `_demo` directory contains some C standard libary related demos (it start with `_` to prevent the `go` command from compiling it):
|
||||
|
||||
* [hello](_demo/hello/hello.go): call C `printf` to print `Hello world`
|
||||
* [concat](_demo/concat/concat.go): call C `fprintf` with `stderr`
|
||||
* [qsort](_demo/qsort/qsort.go): call C function with a callback (eg. `qsort`)
|
||||
|
||||
To run these demos (If you haven't installed `llgo` yet, please refer to [How to install](#how-to-install)):
|
||||
|
||||
```sh
|
||||
cd <demo-directory> # eg. cd _demo/hello
|
||||
llgo run .
|
||||
```
|
||||
|
||||
|
||||
## How support C/C++ and Python
|
||||
|
||||
LLGo use `go:linkname` to link an extern symbol througth its ABI:
|
||||
|
||||
```go
|
||||
import _ "unsafe" // for go:linkname
|
||||
|
||||
//go:linkname Sqrt C.sqrt
|
||||
func Sqrt(x float64) float64
|
||||
```
|
||||
|
||||
You can directly integrate it into [your own code](_demo/linkname/linkname.go):
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import _ "unsafe" // for go:linkname
|
||||
|
||||
//go:linkname Sqrt C.sqrt
|
||||
func Sqrt(x float64) float64
|
||||
|
||||
func main() {
|
||||
println("sqrt(2) =", Sqrt(2))
|
||||
}
|
||||
```
|
||||
|
||||
Or put it into a package (see [c/math](c/math/math.go)):
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import "github.com/goplus/llgo/c/math"
|
||||
|
||||
func main() {
|
||||
println("sqrt(2) =", math.Sqrt(2))
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
## Python support
|
||||
|
||||
You can import a Python library in LLGo!
|
||||
|
||||
And you can import any Python library into `llgo` through a program called `llpyg` (see [Development tools](#development-tools)). The following libraries have been included in `llgo`:
|
||||
|
||||
* [py](https://pkg.go.dev/github.com/goplus/llgo/py) (abi)
|
||||
* [py/std](https://pkg.go.dev/github.com/goplus/llgo/py/std) (builtins)
|
||||
* [py/sys](https://pkg.go.dev/github.com/goplus/llgo/py/sys)
|
||||
* [py/os](https://pkg.go.dev/github.com/goplus/llgo/py/os)
|
||||
* [py/math](https://pkg.go.dev/github.com/goplus/llgo/py/math)
|
||||
* [py/json](https://pkg.go.dev/github.com/goplus/llgo/py/json)
|
||||
* [py/inspect](https://pkg.go.dev/github.com/goplus/llgo/py/inspect)
|
||||
* [py/statistics](https://pkg.go.dev/github.com/goplus/llgo/py/statistics)
|
||||
* [py/numpy](https://pkg.go.dev/github.com/goplus/llgo/py/numpy)
|
||||
* [py/pandas](https://pkg.go.dev/github.com/goplus/llgo/py/pandas)
|
||||
* [py/torch](https://pkg.go.dev/github.com/goplus/llgo/py/torch)
|
||||
* [py/matplotlib](https://pkg.go.dev/github.com/goplus/llgo/py/matplotlib)
|
||||
|
||||
Note: For third-party libraries (such as pandas and pytorch), you still need to install the library files.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/py"
|
||||
"github.com/goplus/llgo/py/math"
|
||||
"github.com/goplus/llgo/py/std"
|
||||
)
|
||||
|
||||
func main() {
|
||||
x := math.Sqrt(py.Float(2)) // x = sqrt(2)
|
||||
std.Print(py.Str("sqrt(2) ="), x) // print("sqrt(2) =", x)
|
||||
}
|
||||
```
|
||||
|
||||
It is equivalent to the following Python code:
|
||||
|
||||
```py
|
||||
import math
|
||||
|
||||
x = math.sqrt(2)
|
||||
print("sqrt =", x)
|
||||
```
|
||||
|
||||
Here, We call `py.Float(2)` to create a Python number 2, and pass it to Python’s `math.sqrt` to get `x`. Then we call `std.Print` to print the result.
|
||||
|
||||
Let's look at a slightly more complex example. For example, we use `numpy` to calculate:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/py"
|
||||
"github.com/goplus/llgo/py/numpy"
|
||||
"github.com/goplus/llgo/py/std"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := py.List(
|
||||
py.List(1.0, 2.0, 3.0),
|
||||
py.List(4.0, 5.0, 6.0),
|
||||
py.List(7.0, 8.0, 9.0),
|
||||
)
|
||||
b := py.List(
|
||||
py.List(9.0, 8.0, 7.0),
|
||||
py.List(6.0, 5.0, 4.0),
|
||||
py.List(3.0, 2.0, 1.0),
|
||||
)
|
||||
x := numpy.Add(a, b)
|
||||
std.Print(py.Str("a+b ="), x)
|
||||
}
|
||||
```
|
||||
|
||||
Here we define two 3x3 matrices a and b, add them to get x, and then print the result.
|
||||
|
||||
The `_pydemo` directory contains some python related demos:
|
||||
|
||||
* [callpy](_pydemo/callpy/callpy.go): call Python standard library function `math.sqrt`
|
||||
* [pi](_pydemo/pi/pi.go): print python constants `math.pi`
|
||||
* [statistics](_pydemo/statistics/statistics.go): define a python list and call `statistics.mean` to get the mean
|
||||
* [matrix](_pydemo/matrix/matrix.go): a basic `numpy` demo
|
||||
|
||||
To run these demos (If you haven't installed `llgo` yet, please refer to [How to install](#how-to-install)):
|
||||
|
||||
```sh
|
||||
cd <demo-directory> # eg. cd _pydemo/callpy
|
||||
llgo run .
|
||||
```
|
||||
|
||||
|
||||
## Other frequently used libraries
|
||||
|
||||
LLGo can easily import any libraries from the C ecosystem. Currently, this import process is still manual, but in the future, it will be automated similar to Python library imports.
|
||||
|
||||
The currently supported libraries include:
|
||||
|
||||
* [c/bdwgc](https://pkg.go.dev/github.com/goplus/llgo/c/bdwgc)
|
||||
* [c/cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson)
|
||||
* [c/clang](https://pkg.go.dev/github.com/goplus/llgo/c/clang)
|
||||
* [c/llama2](https://pkg.go.dev/github.com/goplus/llgo/c/llama2)
|
||||
* [c/lua](https://pkg.go.dev/github.com/goplus/llgo/c/lua)
|
||||
* [c/neco](https://pkg.go.dev/github.com/goplus/llgo/c/neco)
|
||||
* [c/raylib](https://pkg.go.dev/github.com/goplus/llgo/c/raylib)
|
||||
* [c/sqlite](https://pkg.go.dev/github.com/goplus/llgo/c/sqlite)
|
||||
* [c/zlib](https://pkg.go.dev/github.com/goplus/llgo/c/zlib)
|
||||
* [cpp/inih](https://pkg.go.dev/github.com/goplus/llgo/cpp/inih)
|
||||
|
||||
Here are some examples related to them:
|
||||
|
||||
* [llama2-c](_demo/llama2-c): inference Llama 2 (It's the first llgo AI example)
|
||||
* [mkjson](c/cjson/_demo/mkjson/mkjson.go): create a json object and print it
|
||||
* [sqlitedemo](c/sqlite/_demo/sqlitedemo/demo.go): a basic sqlite demo
|
||||
* [tetris](c/raylib/_demo/tetris/tetris.go): a tetris game based on raylib
|
||||
|
||||
|
||||
## Go syntax support
|
||||
|
||||
All Go syntax (not including `cgo`) is already supported. Here are some examples:
|
||||
|
||||
* [concat](_demo/concat/concat.go): define a variadic function
|
||||
* [genints](_demo/genints/genints.go): various forms of closure usage (including C function, recv.method and anonymous function)
|
||||
* [errors](_cmptest/errors/errors.go): demo to implement error interface
|
||||
* [defer](_cmptest/defer/defer.go): defer demo
|
||||
* [goroutine](_demo/goroutine/goroutine.go): goroutine demo
|
||||
|
||||
|
||||
## Defer
|
||||
|
||||
LLGo `defer` does not support usage in loops. This is not a bug but a feature, because we think that using `defer` in a loop is a very unrecommended practice.
|
||||
|
||||
|
||||
### Garbage Collection (GC)
|
||||
|
||||
By default, LLGo implements `gc` based on [bdwgc](https://www.hboehm.info/gc/) (also known as [libgc](https://www.hboehm.info/gc/)).
|
||||
|
||||
However, you can disable gc by specifying the `nogc` tag. For example:
|
||||
|
||||
```sh
|
||||
llgo run -tags nogc .
|
||||
```
|
||||
|
||||
|
||||
## Go packages support
|
||||
|
||||
Here are the Go packages that can be imported correctly:
|
||||
|
||||
* [unsafe](https://pkg.go.dev/unsafe)
|
||||
* [unicode](https://pkg.go.dev/unicode)
|
||||
* [unicode/utf8](https://pkg.go.dev/unicode/utf8)
|
||||
* [unicode/utf16](https://pkg.go.dev/unicode/utf16)
|
||||
* [math](https://pkg.go.dev/math)
|
||||
* [math/bits](https://pkg.go.dev/math/bits)
|
||||
* [math/cmplx](https://pkg.go.dev/math/cmplx)
|
||||
* [errors](https://pkg.go.dev/errors)
|
||||
* [context](https://pkg.go.dev/context)
|
||||
* [io](https://pkg.go.dev/io)
|
||||
* [io/fs](https://pkg.go.dev/io/fs)
|
||||
* [log](https://pkg.go.dev/log)
|
||||
* [flag](https://pkg.go.dev/flag)
|
||||
* [sort](https://pkg.go.dev/sort)
|
||||
* [strconv](https://pkg.go.dev/strconv)
|
||||
* [strings](https://pkg.go.dev/strings)
|
||||
* [sync/atomic](https://pkg.go.dev/sync/atomic)
|
||||
* [sync](https://pkg.go.dev/sync) (partially)
|
||||
* [syscall](https://pkg.go.dev/syscall) (partially)
|
||||
* [runtime](https://pkg.go.dev/runtime) (partially)
|
||||
* [os](https://pkg.go.dev/os) (partially)
|
||||
* [os/exec](https://pkg.go.dev/os/exec) (partially)
|
||||
* [fmt](https://pkg.go.dev/fmt) (partially)
|
||||
* [reflect](https://pkg.go.dev/reflect) (partially)
|
||||
* [time](https://pkg.go.dev/time) (partially)
|
||||
|
||||
|
||||
## Dependencies
|
||||
|
||||
- [Go 1.20+](https://go.dev) (build only)
|
||||
- [LLVM 18](https://llvm.org)
|
||||
- [LLD 18](https://lld.llvm.org)
|
||||
- [Clang 18](https://clang.llvm.org)
|
||||
- [pkg-config 0.29+](https://www.freedesktop.org/wiki/Software/pkg-config/)
|
||||
- [bdwgc/libgc 8.0+](https://www.hboehm.info/gc/)
|
||||
- [cJSON 1.7+](https://github.com/DaveGamble/cJSON) (optional, for [github.com/goplus/llgo/c/cjson](https://pkg.go.dev/github.com/goplus/llgo/c/cjson))
|
||||
- [SQLite 3](https://www.sqlite.org) (optional, for [github.com/goplus/llgo/c/sqlite](https://pkg.go.dev/github.com/goplus/llgo/c/sqlite))
|
||||
- [Python 3.11+](https://www.python.org) (optional, for [github.com/goplus/llgo/py](https://pkg.go.dev/github.com/goplus/llgo/py))
|
||||
|
||||
## How to install
|
||||
|
||||
Follow these steps to generate the `llgo` command (its usage is the same as the `go` command):
|
||||
|
||||
### on macOS
|
||||
|
||||
```sh
|
||||
brew update # execute if needed
|
||||
brew install llvm@18 pkg-config libgc
|
||||
brew install cjson sqlite python@3.12 # optional
|
||||
export PATH=$(brew --prefix llvm@18)/bin:$PATH # you may want to add this to your shell RC file, e.g. ~/.zshrc
|
||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
||||
```
|
||||
|
||||
### on Linux (Debian/Ubuntu)
|
||||
|
||||
```sh
|
||||
echo "deb http://apt.llvm.org/$(lsb_release -cs)/ llvm-toolchain-$(lsb_release -cs)-18 main" | sudo tee /etc/apt/sources.list.d/llvm.list
|
||||
wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key | sudo apt-key add -
|
||||
sudo apt-get update # execute if needed
|
||||
sudo apt-get install -y llvm-18-dev clang-18 lld-18 pkg-config libgc-dev
|
||||
sudo apt-get install -y libcjson-dev libsqlite3-dev python3.12-dev # optional
|
||||
export PATH=/usr/lib/llvm-18/bin:$PATH # you may want to add this to your shell RC file, e.g. ~/.bashrc
|
||||
go install -v github.com/goplus/llgo/cmd/llgo@latest
|
||||
```
|
||||
|
||||
### on Windows
|
||||
|
||||
TODO
|
||||
|
||||
|
||||
## Development tools
|
||||
|
||||
* [pydump](chore/_xtool/pydump): It's the first program compiled by `llgo` (NOT `go`) in a production environment. It outputs symbol information (functions, variables, and constants) from a Python library in JSON format, preparing for the generation of corresponding packages in `llgo`.
|
||||
* [pysigfetch](https://github.com/goplus/hdq/tree/main/chore/pysigfetch): It generates symbol information by extracting information from Python's documentation site. This tool is not part of the `llgo` project, but we depend on it.
|
||||
* [llpyg](chore/llpyg): It is used to automatically convert Python libraries into Go packages that `llgo` can import. It depends on `pydump` and `pysigfetch` to accomplish the task.
|
||||
* [llgen](chore/llgen): It is used to compile Go packages into LLVM IR files (*.ll).
|
||||
* [ssadump](chore/ssadump): It is a Go SSA builder and interpreter.
|
||||
|
||||
How do I generate these tools?
|
||||
|
||||
```sh
|
||||
git clone https://github.com/goplus/llgo.git
|
||||
cd llgo
|
||||
go install -v ./chore/... # compile all tools except pydump
|
||||
cd chore/_xtool
|
||||
llgo install ./... # compile pydump
|
||||
go install github.com/goplus/hdq/chore/pysigfetch@v0.8.1 # compile pysigfetch
|
||||
```
|
||||
|
||||
## Key modules
|
||||
|
||||
Below are the key modules for understanding the implementation principles of `llgo`:
|
||||
|
||||
* [llgo/ssa](https://pkg.go.dev/github.com/goplus/llgo/ssa): It generates LLVM IR files (LLVM SSA) using the semantics (interfaces) of Go SSA. Although `LLVM SSA` and `Go SSA` are both IR languages, they work at completely different levels. `LLVM SSA` is closer to machine code, which abstracts different instruction sets. While `Go SSA` is closer to a high-level language. We can think of it as the instruction set of the `Go computer`. `llgo/ssa` is not just limited to the `llgo` compiler. If we view it as the high-level expressive power of `LLVM`, you'll find it very useful. Prior to `llgo/ssa`, you had to operate `LLVM` using machine code semantics. But now, with the advanced SSA form (in the semantics of Go SSA), you can conveniently utilize `LLVM`.
|
||||
* [llgo/cl](https://pkg.go.dev/github.com/goplus/llgo/cl): It is the core of the llgo compiler. It converts a Go package into LLVM IR files. It depends on `llgo/ssa`.
|
||||
* [llgo/internal/build](https://pkg.go.dev/github.com/goplus/llgo/internal/build): It strings together the entire compilation process of `llgo`. It depends on `llgo/ssa` and `llgo/cl`.
|
||||
|
||||
21
_cmptest/_chandemo/chan.go
Normal file
21
_cmptest/_chandemo/chan.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
c1 := make(chan string)
|
||||
c2 := make(chan string, 1)
|
||||
go func() {
|
||||
c1 <- "ch1"
|
||||
}()
|
||||
go func() {
|
||||
c2 <- "ch2"
|
||||
}()
|
||||
|
||||
for i := 0; i < 2; i++ {
|
||||
select {
|
||||
case msg1 := <-c1:
|
||||
println(msg1)
|
||||
case msg2 := <-c2:
|
||||
println(msg2)
|
||||
}
|
||||
}
|
||||
}
|
||||
19
_cmptest/_timeout/timer.go
Normal file
19
_cmptest/_timeout/timer.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
var c chan int
|
||||
|
||||
func handle(int) {}
|
||||
|
||||
func main() {
|
||||
select {
|
||||
case m := <-c:
|
||||
handle(m)
|
||||
case <-time.After(10 * time.Second):
|
||||
fmt.Println("timed out")
|
||||
}
|
||||
}
|
||||
11
_cmptest/chan/chan.go
Normal file
11
_cmptest/chan/chan.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
ch := make(chan int, 10)
|
||||
println(len(ch), cap(ch))
|
||||
go func() {
|
||||
ch <- 100
|
||||
}()
|
||||
n, ok := <-ch
|
||||
println(n, ok)
|
||||
}
|
||||
26
_cmptest/chansel/chansel.go
Normal file
26
_cmptest/chansel/chansel.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
func fibonacci(c, quit chan int) {
|
||||
x, y := 0, 1
|
||||
for {
|
||||
select {
|
||||
case c <- x:
|
||||
x, y = y, x+y
|
||||
case <-quit:
|
||||
println("quit")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := make(chan int)
|
||||
quit := make(chan int)
|
||||
go func() {
|
||||
for i := 0; i < 10; i++ {
|
||||
println(<-c)
|
||||
}
|
||||
close(quit)
|
||||
}()
|
||||
fibonacci(c, quit)
|
||||
}
|
||||
39
_cmptest/ctxcancel/ctx.go
Normal file
39
_cmptest/ctxcancel/ctx.go
Normal file
@@ -0,0 +1,39 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// gen generates integers in a separate goroutine and
|
||||
// sends them to the returned channel.
|
||||
// The callers of gen need to cancel the context once
|
||||
// they are done consuming generated integers not to leak
|
||||
// the internal goroutine started by gen.
|
||||
gen := func(ctx context.Context) <-chan int {
|
||||
dst := make(chan int)
|
||||
n := 1
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-ctx.Done():
|
||||
return // returning not to leak the goroutine
|
||||
case dst <- n:
|
||||
n++
|
||||
}
|
||||
}
|
||||
}()
|
||||
return dst
|
||||
}
|
||||
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
defer cancel() // cancel when we are finished consuming integers
|
||||
|
||||
for n := range gen(ctx) {
|
||||
fmt.Println(n)
|
||||
if n == 5 {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
17
_cmptest/defer/defer.go
Normal file
17
_cmptest/defer/defer.go
Normal file
@@ -0,0 +1,17 @@
|
||||
package main
|
||||
|
||||
func f(s string) bool {
|
||||
return len(s) > 2
|
||||
}
|
||||
|
||||
func main() {
|
||||
defer func() {
|
||||
println("hi")
|
||||
}()
|
||||
if s := "hello"; f(s) {
|
||||
defer println(s)
|
||||
} else {
|
||||
defer println("world")
|
||||
}
|
||||
defer println("bye")
|
||||
}
|
||||
21
_cmptest/errors/errors.go
Normal file
21
_cmptest/errors/errors.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
// New returns an error that formats as the given text.
|
||||
// Each call to New returns a distinct error value even if the text is identical.
|
||||
func New(text string) error {
|
||||
return &errorString{text}
|
||||
}
|
||||
|
||||
// errorString is a trivial implementation of error.
|
||||
type errorString struct {
|
||||
s string
|
||||
}
|
||||
|
||||
func (e *errorString) Error() string {
|
||||
return e.s
|
||||
}
|
||||
|
||||
func main() {
|
||||
err := New("an error")
|
||||
println(err.Error())
|
||||
}
|
||||
21
_cmptest/flagdemo/flagdemo.go
Normal file
21
_cmptest/flagdemo/flagdemo.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("args:", os.Args[1:])
|
||||
if len(os.Args) == 1 {
|
||||
os.Args = []string{"flagdemo", "-cpu", "100"}
|
||||
}
|
||||
|
||||
verbose := flag.Bool("v", false, "verbose")
|
||||
cpu := flag.Int("cpu", 1, "cpu number")
|
||||
host := flag.String("host", ":8888", "host")
|
||||
flag.Parse()
|
||||
|
||||
fmt.Println("host:", *host, "cpu:", *cpu, "verbose:", *verbose)
|
||||
}
|
||||
12
_cmptest/fmtdemo/fmt.go
Normal file
12
_cmptest/fmtdemo/fmt.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello, world")
|
||||
fmt.Printf("%f\n", 3.14)
|
||||
fmt.Printf("%v\n", errors.New("error message"))
|
||||
}
|
||||
9
_cmptest/interf/foo/foo.go
Normal file
9
_cmptest/interf/foo/foo.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package foo
|
||||
|
||||
func Bar() any {
|
||||
return struct{ V int }{1}
|
||||
}
|
||||
|
||||
func F() any {
|
||||
return struct{ v int }{1}
|
||||
}
|
||||
35
_cmptest/interf/interf.go
Normal file
35
_cmptest/interf/interf.go
Normal file
@@ -0,0 +1,35 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/_cmptest/interf/foo"
|
||||
)
|
||||
|
||||
func Foo() any {
|
||||
return struct{ v int }{1}
|
||||
}
|
||||
|
||||
func main() {
|
||||
v := Foo()
|
||||
if x, ok := v.(struct{ v int }); ok {
|
||||
println(x.v)
|
||||
} else {
|
||||
println("Foo: not ok")
|
||||
}
|
||||
bar := foo.Bar()
|
||||
if x, ok := bar.(struct{ V int }); ok {
|
||||
println(x.V)
|
||||
} else {
|
||||
println("Bar: not ok")
|
||||
}
|
||||
if x, ok := foo.F().(struct{ v int }); ok {
|
||||
println(x.v)
|
||||
} else {
|
||||
println("F: not ok")
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
1
|
||||
1
|
||||
F: not ok
|
||||
*/
|
||||
14
_cmptest/iodemo/io.go
Normal file
14
_cmptest/iodemo/io.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"io"
|
||||
"os"
|
||||
)
|
||||
|
||||
func f(w io.Writer) {
|
||||
w.Write([]byte("Hello, world\n"))
|
||||
}
|
||||
|
||||
func main() {
|
||||
f(os.Stdout)
|
||||
}
|
||||
18
_cmptest/osdemo/osd.go
Normal file
18
_cmptest/osdemo/osd.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
home, _ := os.UserHomeDir()
|
||||
println("home:", home)
|
||||
|
||||
cfgdir, _ := os.UserConfigDir()
|
||||
println("cfgdir:", cfgdir)
|
||||
|
||||
cache, _ := os.UserCacheDir()
|
||||
println("cachedir:", cache)
|
||||
|
||||
os.Stdout.Write([]byte("Hello, World\n"))
|
||||
}
|
||||
30
_cmptest/osproc/exec.go
Normal file
30
_cmptest/osproc/exec.go
Normal file
@@ -0,0 +1,30 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := "ls"
|
||||
args := []string{ls, "-l"}
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = "dir"
|
||||
args = []string{ls}
|
||||
}
|
||||
lspath, _ := exec.LookPath(ls)
|
||||
if lspath != "" {
|
||||
ls = lspath
|
||||
}
|
||||
proc, err := os.StartProcess(ls, args, &os.ProcAttr{
|
||||
Files: []*os.File{nil, os.Stdout, os.Stderr},
|
||||
})
|
||||
if err != nil {
|
||||
fmt.Println("os.StartProcess error:", err)
|
||||
return
|
||||
}
|
||||
proc.Wait()
|
||||
fmt.Println("proc.Wait done")
|
||||
}
|
||||
13
_cmptest/reflect/reflect.go
Normal file
13
_cmptest/reflect/reflect.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import "reflect"
|
||||
|
||||
func main() {
|
||||
tyIntSlice := reflect.SliceOf(reflect.TypeOf(0))
|
||||
v := reflect.Zero(tyIntSlice)
|
||||
v = reflect.Append(v, reflect.ValueOf(1), reflect.ValueOf(2), reflect.ValueOf(3))
|
||||
for i, n := 0, v.Len(); i < n; i++ {
|
||||
item := v.Index(i)
|
||||
println(item.Int())
|
||||
}
|
||||
}
|
||||
14
_cmptest/rtype/rtype.go
Normal file
14
_cmptest/rtype/rtype.go
Normal file
@@ -0,0 +1,14 @@
|
||||
package main
|
||||
|
||||
import "reflect"
|
||||
|
||||
func main() {
|
||||
tyIntSlice := reflect.SliceOf(reflect.TypeOf(0))
|
||||
println(tyIntSlice.String())
|
||||
|
||||
v := reflect.Zero(tyIntSlice)
|
||||
println(v.Len())
|
||||
|
||||
v = reflect.ValueOf(100)
|
||||
println(v.Int())
|
||||
}
|
||||
23
_cmptest/sortdemo/sort.go
Normal file
23
_cmptest/sortdemo/sort.go
Normal file
@@ -0,0 +1,23 @@
|
||||
package main
|
||||
|
||||
import "sort"
|
||||
|
||||
func main() {
|
||||
vals := []int{32, 58, 25, 92, 45, 78}
|
||||
sort.Ints(vals)
|
||||
for _, v := range vals {
|
||||
println(v)
|
||||
}
|
||||
|
||||
texts := []string{"apple", "banana", "cherry", "date", "elderberry", "fig"}
|
||||
sort.Slice(texts, func(i, j int) bool {
|
||||
leni, lenj := len(texts[i]), len(texts[j])
|
||||
if leni != lenj {
|
||||
return leni < lenj
|
||||
}
|
||||
return texts[i] < texts[j]
|
||||
})
|
||||
for _, v := range texts {
|
||||
println(v)
|
||||
}
|
||||
}
|
||||
12
_cmptest/strconv/strconv.go
Normal file
12
_cmptest/strconv/strconv.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println(strconv.Itoa(-123))
|
||||
fmt.Println(strings.Split("abc,def,123", ","))
|
||||
}
|
||||
11
_cmptest/syscall/syscall.go
Normal file
11
_cmptest/syscall/syscall.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import "syscall"
|
||||
|
||||
func main() {
|
||||
wd, err := syscall.Getwd()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
println("cwd:", wd)
|
||||
}
|
||||
8
_cmptest/timedemo/time.go
Normal file
8
_cmptest/timedemo/time.go
Normal file
@@ -0,0 +1,8 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
t := time.Date(2018, time.January, 1, 2, 3, 4, 5, time.UTC)
|
||||
println(t.String())
|
||||
}
|
||||
24
_demo/catomic/atomic.go
Normal file
24
_demo/catomic/atomic.go
Normal file
@@ -0,0 +1,24 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c/sync/atomic"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var v int64
|
||||
|
||||
atomic.Store(&v, 100)
|
||||
println("store:", atomic.Load(&v))
|
||||
|
||||
ret := atomic.Add(&v, 1)
|
||||
println("ret:", ret, "v:", v)
|
||||
|
||||
ret, _ = atomic.CompareAndExchange(&v, 100, 102)
|
||||
println("ret:", ret, "vs 100, v:", v)
|
||||
|
||||
ret, _ = atomic.CompareAndExchange(&v, 101, 102)
|
||||
println("ret:", ret, "vs 101, v:", v)
|
||||
|
||||
ret = atomic.Sub(&v, 1)
|
||||
println("ret:", ret, "v:", v)
|
||||
}
|
||||
50
_demo/cchan/cchan.go
Normal file
50
_demo/cchan/cchan.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/internal/runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
eltSize = int(unsafe.Sizeof(0))
|
||||
)
|
||||
|
||||
func doChan(cap int) {
|
||||
c := runtime.NewChan(eltSize, cap)
|
||||
go func() {
|
||||
v := 100
|
||||
runtime.ChanSend(c, unsafe.Pointer(&v), eltSize)
|
||||
}()
|
||||
var ret int
|
||||
runtime.ChanRecv(c, unsafe.Pointer(&ret), eltSize)
|
||||
println(ret)
|
||||
}
|
||||
|
||||
func main() {
|
||||
doChan(10)
|
||||
doChan(0)
|
||||
|
||||
c := runtime.NewChan(eltSize, 3)
|
||||
|
||||
v := 1
|
||||
runtime.ChanSend(c, unsafe.Pointer(&v), eltSize)
|
||||
v = 2
|
||||
runtime.ChanSend(c, unsafe.Pointer(&v), eltSize)
|
||||
v = 3
|
||||
runtime.ChanSend(c, unsafe.Pointer(&v), eltSize)
|
||||
runtime.ChanClose(c)
|
||||
|
||||
v = 10
|
||||
|
||||
if runtime.ChanTrySend(c, unsafe.Pointer(&v), eltSize) {
|
||||
println("error: chan send to closed chan")
|
||||
}
|
||||
|
||||
for {
|
||||
if ok := runtime.ChanRecv(c, unsafe.Pointer(&v), eltSize); !ok {
|
||||
break
|
||||
}
|
||||
println(v)
|
||||
}
|
||||
}
|
||||
41
_demo/cchansel/cchansel.go
Normal file
41
_demo/cchansel/cchansel.go
Normal file
@@ -0,0 +1,41 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/internal/runtime"
|
||||
)
|
||||
|
||||
const (
|
||||
eltSize = int(unsafe.Sizeof(0))
|
||||
)
|
||||
|
||||
func fibonacci(c, quit *runtime.Chan) {
|
||||
x, y := 0, 1
|
||||
for {
|
||||
isel, _ := runtime.Select(
|
||||
runtime.ChanOp{C: c, Send: true, Val: unsafe.Pointer(&x), Size: int32(eltSize)},
|
||||
runtime.ChanOp{C: quit},
|
||||
)
|
||||
if isel == 0 {
|
||||
x, y = y, x+y
|
||||
} else {
|
||||
println("quit")
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func main() {
|
||||
c := runtime.NewChan(eltSize, 0)
|
||||
quit := runtime.NewChan(eltSize, 0)
|
||||
go func() {
|
||||
for i := 0; i < 10; i++ {
|
||||
val := 0
|
||||
runtime.ChanRecv(c, unsafe.Pointer(&val), eltSize)
|
||||
println(val)
|
||||
}
|
||||
runtime.ChanClose(quit)
|
||||
}()
|
||||
fibonacci(c, quit)
|
||||
}
|
||||
11
_demo/cexec/exec.go
Normal file
11
_demo/cexec/exec.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := c.Str("ls")
|
||||
os.Execlp(ls, ls, c.Str("-l"), nil)
|
||||
}
|
||||
9
_demo/complex/cmplx.go
Normal file
9
_demo/complex/cmplx.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math/cmplx"
|
||||
)
|
||||
|
||||
func main() {
|
||||
println("abs(3+4i):", cmplx.Abs(3+4i))
|
||||
}
|
||||
21
_demo/concat/concat.go
Normal file
21
_demo/concat/concat.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
func concat(args ...string) (ret string) {
|
||||
for _, v := range args {
|
||||
ret += v
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
func main() {
|
||||
result := concat("Hello", " ", "World")
|
||||
c.Fprintf(c.Stderr, c.Str("Hi, %s\n"), c.AllocaCStr(result))
|
||||
}
|
||||
|
||||
/* Expected output (stderr):
|
||||
Hi, Hello World
|
||||
*/
|
||||
38
_demo/cppintf/cppintf.go
Normal file
38
_demo/cppintf/cppintf.go
Normal file
@@ -0,0 +1,38 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/_demo/cppintf/foo"
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/math"
|
||||
)
|
||||
|
||||
type Bar struct {
|
||||
foo.Callback
|
||||
a c.Int
|
||||
}
|
||||
|
||||
func NewBar(a c.Int) *Bar {
|
||||
return &Bar{
|
||||
Callback: foo.Callback{
|
||||
Vptr: &foo.CallbackVtbl{
|
||||
Val: c.Func((*Bar).getA),
|
||||
Calc: c.Func((*Bar).sqrt),
|
||||
},
|
||||
},
|
||||
a: a,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Bar) getA() c.Int {
|
||||
return p.a
|
||||
}
|
||||
|
||||
func (p *Bar) sqrt(v float64) float64 {
|
||||
return math.Sqrt(v)
|
||||
}
|
||||
|
||||
func main() {
|
||||
bar := NewBar(1)
|
||||
foo.F(&bar.Callback)
|
||||
foo.G(&bar.Callback)
|
||||
}
|
||||
15
_demo/cppintf/foo/bar/bar.cpp
Normal file
15
_demo/cppintf/foo/bar/bar.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
#include <stdio.h>
|
||||
#define interface struct
|
||||
|
||||
interface ICallback {
|
||||
virtual int val() = 0;
|
||||
virtual double calc(double v) = 0;
|
||||
};
|
||||
|
||||
extern "C" void f(ICallback* cb) {
|
||||
printf("val: %d\ncalc(2): %lf\n", cb->val(), cb->calc(2));
|
||||
}
|
||||
|
||||
void g(ICallback* cb) {
|
||||
f(cb);
|
||||
}
|
||||
25
_demo/cppintf/foo/foo.go
Normal file
25
_demo/cppintf/foo/foo.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package foo
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "bar/bar.cpp"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
type Callback struct {
|
||||
Vptr *CallbackVtbl
|
||||
}
|
||||
|
||||
type CallbackVtbl struct {
|
||||
Val unsafe.Pointer
|
||||
Calc unsafe.Pointer
|
||||
}
|
||||
|
||||
//go:linkname F C.f
|
||||
func F(cb *Callback)
|
||||
|
||||
//go:linkname G C._Z1gP9ICallback
|
||||
func G(cb *Callback)
|
||||
50
_demo/cppmintf/cpp_multi_intf.go
Normal file
50
_demo/cppmintf/cpp_multi_intf.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/_demo/cppmintf/foo"
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/math"
|
||||
)
|
||||
|
||||
type Bar struct {
|
||||
foo.Callback
|
||||
a c.Int
|
||||
}
|
||||
|
||||
func NewBar(a c.Int) *Bar {
|
||||
return &Bar{
|
||||
Callback: foo.Callback{
|
||||
ICalc: foo.ICalc{
|
||||
Vptr: &foo.ICalcVtbl{
|
||||
Calc: c.Func((*Bar).sqrt),
|
||||
},
|
||||
},
|
||||
IVal: foo.IVal{
|
||||
Vptr: &foo.IValVtbl{
|
||||
Val: c.Func(bar_IVal_getA),
|
||||
},
|
||||
},
|
||||
},
|
||||
a: a,
|
||||
}
|
||||
}
|
||||
|
||||
func (p *Bar) getA() c.Int {
|
||||
return p.a
|
||||
}
|
||||
|
||||
func bar_IVal_getA(this c.Pointer) c.Int {
|
||||
const delta = -int(unsafe.Offsetof(foo.Callback{}.IVal))
|
||||
return (*Bar)(c.Advance(this, delta)).getA()
|
||||
}
|
||||
|
||||
func (p *Bar) sqrt(v float64) float64 {
|
||||
return math.Sqrt(v)
|
||||
}
|
||||
|
||||
func main() {
|
||||
bar := NewBar(1)
|
||||
foo.F(&bar.Callback)
|
||||
}
|
||||
17
_demo/cppmintf/foo/bar/bar.cpp
Normal file
17
_demo/cppmintf/foo/bar/bar.cpp
Normal file
@@ -0,0 +1,17 @@
|
||||
#include <stdio.h>
|
||||
#define interface struct
|
||||
|
||||
interface ICalc {
|
||||
virtual double calc(double v) = 0;
|
||||
};
|
||||
|
||||
interface IVal {
|
||||
virtual int val() = 0;
|
||||
};
|
||||
|
||||
class Callback : public ICalc, public IVal {
|
||||
};
|
||||
|
||||
extern "C" void f(Callback* cb) {
|
||||
printf("val: %d\ncalc(2): %lf\n", cb->val(), cb->calc(2));
|
||||
}
|
||||
42
_demo/cppmintf/foo/foo.go
Normal file
42
_demo/cppmintf/foo/foo.go
Normal file
@@ -0,0 +1,42 @@
|
||||
package foo
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "bar/bar.cpp"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type ICalc struct {
|
||||
Vptr *ICalcVtbl
|
||||
}
|
||||
|
||||
type ICalcVtbl struct {
|
||||
Calc unsafe.Pointer
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type IVal struct {
|
||||
Vptr *IValVtbl
|
||||
}
|
||||
|
||||
type IValVtbl struct {
|
||||
Val unsafe.Pointer
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type Callback struct {
|
||||
ICalc
|
||||
IVal
|
||||
}
|
||||
|
||||
//go:linkname F C.f
|
||||
func F(cb *Callback)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
12
_demo/ctime/time.go
Normal file
12
_demo/ctime/time.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import "github.com/goplus/llgo/c/time"
|
||||
|
||||
func main() {
|
||||
var tv time.Timespec
|
||||
time.ClockGettime(time.CLOCK_REALTIME, &tv)
|
||||
println("REALTIME sec:", tv.Sec, "nsec:", tv.Nsec)
|
||||
|
||||
time.ClockGettime(time.CLOCK_MONOTONIC, &tv)
|
||||
println("MONOTONIC sec:", tv.Sec, "nsec:", tv.Nsec)
|
||||
}
|
||||
77
_demo/fcntl/fcntl.go
Normal file
77
_demo/fcntl/fcntl.go
Normal file
@@ -0,0 +1,77 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
filename := c.Str("testfile.txt")
|
||||
data := c.Str("Hello, os!")
|
||||
var buffer [20]c.Char
|
||||
|
||||
// Open a file, O_CREAT|O_WRONLY|O_TRUNC means create, write only, or clear the file
|
||||
fd := os.Open(filename, os.O_CREAT|os.O_WRONLY|os.O_TRUNC, 0644)
|
||||
if fd == -1 {
|
||||
c.Printf(c.Str("open error\n"))
|
||||
return
|
||||
}
|
||||
|
||||
// Writing data to a file
|
||||
bytesWritten := os.Write(fd, c.Pointer(data), c.Strlen(data))
|
||||
if bytesWritten == -1 {
|
||||
c.Printf(c.Str("write error\n"))
|
||||
os.Close(fd)
|
||||
return
|
||||
}
|
||||
c.Printf(c.Str("Written %ld bytes to %s\n"), bytesWritten, filename)
|
||||
|
||||
// Get file status flags
|
||||
flags := os.Fcntl(fd, os.F_GETFL)
|
||||
if flags == -1 {
|
||||
c.Printf(c.Str("os error\n"))
|
||||
os.Close(fd)
|
||||
return
|
||||
}
|
||||
c.Printf(c.Str("File flags: %d\n"), flags)
|
||||
|
||||
// Set the file status flag to non-blocking mode
|
||||
if os.Fcntl(fd, os.F_SETFL, flags|os.O_NONBLOCK) == -1 {
|
||||
c.Printf(c.Str("os error\n"))
|
||||
os.Close(fd)
|
||||
return
|
||||
}
|
||||
c.Printf(c.Str("set file status successfully\n"))
|
||||
|
||||
|
||||
|
||||
c.Printf(c.Str("111"))
|
||||
// Close file
|
||||
os.Close(fd)
|
||||
|
||||
// Reopen the file, O_RDONLY means read-only
|
||||
fd = os.Open(filename, os.O_RDONLY)
|
||||
if fd == -1 {
|
||||
c.Printf(c.Str("open error\n"))
|
||||
return
|
||||
}
|
||||
|
||||
// Reading data from a file
|
||||
// &buffer[:][0]
|
||||
// unsafe.SliceData(buffer[:])
|
||||
bytesRead := os.Read(fd, c.Pointer(unsafe.SliceData(buffer[:])), unsafe.Sizeof(buffer)-1)
|
||||
if bytesRead == -1 {
|
||||
c.Printf(c.Str("read error\n"))
|
||||
os.Close(fd)
|
||||
return
|
||||
}
|
||||
|
||||
// Ensure that the buffer is null-terminated
|
||||
buffer[bytesRead] = c.Char(0)
|
||||
c.Printf(c.Str("Read %ld bytes: %s\n"), bytesRead, &buffer[0])
|
||||
|
||||
// Close file
|
||||
os.Close(fd)
|
||||
}
|
||||
63
_demo/genints/genints.go
Normal file
63
_demo/genints/genints.go
Normal file
@@ -0,0 +1,63 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
type generator struct {
|
||||
val c.Int
|
||||
}
|
||||
|
||||
func (g *generator) next() c.Int {
|
||||
g.val++
|
||||
return g.val
|
||||
}
|
||||
|
||||
func genInts(n int, gen func() c.Int) []c.Int {
|
||||
a := make([]c.Int, n)
|
||||
for i := range a {
|
||||
a[i] = gen()
|
||||
}
|
||||
return a
|
||||
}
|
||||
|
||||
func main() {
|
||||
// generate 5 random integers
|
||||
for _, v := range genInts(5, c.Rand) {
|
||||
c.Printf(c.Str("%d\n"), v)
|
||||
}
|
||||
|
||||
// generate 5 integers, each is double of the previous one
|
||||
initVal := c.Int(1)
|
||||
ints := genInts(5, func() c.Int {
|
||||
initVal *= 2
|
||||
return initVal
|
||||
})
|
||||
for _, v := range ints {
|
||||
c.Printf(c.Str("%d\n"), v)
|
||||
}
|
||||
|
||||
// generate 5 integers, each is incremented by 1
|
||||
g := &generator{val: 1}
|
||||
for _, v := range genInts(5, g.next) {
|
||||
c.Printf(c.Str("%d\n"), v)
|
||||
}
|
||||
}
|
||||
|
||||
/* Posible output:
|
||||
16807
|
||||
282475249
|
||||
1622650073
|
||||
984943658
|
||||
1144108930
|
||||
2
|
||||
4
|
||||
8
|
||||
16
|
||||
32
|
||||
2
|
||||
3
|
||||
4
|
||||
5
|
||||
6
|
||||
*/
|
||||
11
_demo/getcwd/getcwd.go
Normal file
11
_demo/getcwd/getcwd.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
)
|
||||
|
||||
func main() {
|
||||
wd := os.Getcwd(c.Alloca(os.PATH_MAX), os.PATH_MAX)
|
||||
c.Printf(c.Str("cwd: %s\n"), wd)
|
||||
}
|
||||
12
_demo/goroutine/goroutine.go
Normal file
12
_demo/goroutine/goroutine.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
func main() {
|
||||
done := false
|
||||
go func() {
|
||||
println("Hello, goroutine")
|
||||
done = true
|
||||
}()
|
||||
for !done {
|
||||
print(".")
|
||||
}
|
||||
}
|
||||
7
_demo/gotime/time.go
Normal file
7
_demo/gotime/time.go
Normal file
@@ -0,0 +1,7 @@
|
||||
package main
|
||||
|
||||
import "time"
|
||||
|
||||
func main() {
|
||||
println(time.Now().String())
|
||||
}
|
||||
13
_demo/hello/hello.go
Normal file
13
_demo/hello/hello.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c.Printf(c.Str("Hello world\n"))
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
Hello world
|
||||
*/
|
||||
10
_demo/linkname/linkname.go
Normal file
10
_demo/linkname/linkname.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import _ "unsafe" // for go:linkname
|
||||
|
||||
//go:linkname Sqrt C.sqrt
|
||||
func Sqrt(x float64) float64
|
||||
|
||||
func main() {
|
||||
println("sqrt(2) =", Sqrt(2))
|
||||
}
|
||||
137
_demo/llama2-c/README.md
Normal file
137
_demo/llama2-c/README.md
Normal file
@@ -0,0 +1,137 @@
|
||||
llama2 - Inference Llama 2 in LLGo
|
||||
=====
|
||||
|
||||
<p align="center">
|
||||
<img src="assets/llama_cute.jpg" width="300" height="300" alt="Cute Llama">
|
||||
</p>
|
||||
|
||||
Have you ever wanted to inference a baby [Llama 2](https://ai.meta.com/llama/) model in Go? No? Well, now you can!
|
||||
|
||||
This is based on [llama2.c](https://github.com/karpathy/llama2.c), we didn't port anything! So it's very different from these Go implementations:
|
||||
* https://github.com/nikolaydubina/llama2.go
|
||||
* https://github.com/tmc/go-llama2
|
||||
|
||||
llgo plays a great role as a bridge, allowing the C ecosystem to be seamlessly connected to Go.
|
||||
|
||||
You might think that you need many billion parameter LLMs to do anything useful, but in fact very small LLMs can have surprisingly strong performance if you make the domain narrow enough (ref: [TinyStories](https://huggingface.co/datasets/roneneldan/TinyStories) paper). This repo is a "fullstack" train + inference solution for Llama 2 LLM, with focus on minimalism and simplicity.
|
||||
|
||||
As the architecture is identical, you can also load and inference Meta's Llama 2 models. However, the current code only inferences models in fp32, so you will most likely not be able to productively load models larger than 7B.
|
||||
|
||||
## feel the magic
|
||||
|
||||
How to run this example? The simplest way is to run it without any arguments:
|
||||
|
||||
```bash
|
||||
llgo run .
|
||||
```
|
||||
|
||||
This means it uses the default model checkpoint file (`stories15M.bin`), and the default prompt (`Once upon a time`).
|
||||
|
||||
You need download the model checkpoint file first. Download this 15M parameter model trained on the [TinyStories](https://huggingface.co/datasets/roneneldan/TinyStories) dataset (~60MB download):
|
||||
|
||||
```bash
|
||||
wget https://huggingface.co/karpathy/tinyllamas/resolve/main/stories15M.bin
|
||||
```
|
||||
|
||||
If you want to specify a prompt (eg. `Long long ago`):
|
||||
|
||||
```bash
|
||||
llgo run . 'Long long ago'
|
||||
```
|
||||
|
||||
We can also try a bit bigger 42M parameter model (ie. `stories42M.bin`):
|
||||
|
||||
```bash
|
||||
wget https://huggingface.co/karpathy/tinyllamas/resolve/main/stories42M.bin
|
||||
llgo run . -m stories42M.bin 'Long long ago'
|
||||
```
|
||||
|
||||
There is also an even better 110M param model available, see [models](#models).
|
||||
|
||||
Quick note on sampling, the recommendation for ~best results is to sample with `-t 1.0 -p 0.9`, i.e. temperature 1.0 (default) but also top-p sampling at 0.9 (default). Intuitively, top-p ensures that tokens with tiny probabilities do not get sampled, so we can't get "unlucky" during sampling, and we are less likely to go "off the rails" afterwards. More generally, to control the diversity of samples use either the temperature (i.e. vary `-t` between 0 and 1 and keep top-p off with `-p 0`) or the top-p value (i.e. vary `-p` between 0 and 1 and keep `-t 1`), but not both. Nice explainers on LLM sampling strategies include [this](https://peterchng.com/blog/2023/05/02/token-selection-strategies-top-k-top-p-and-temperature/), [this](https://docs.cohere.com/docs/controlling-generation-with-top-k-top-p) or [this](https://huggingface.co/blog/how-to-generate).
|
||||
|
||||
|
||||
## Meta's Llama 2 models
|
||||
|
||||
As the neural net architecture is identical, we can also inference the Llama 2 models released by Meta. Sadly there is a bit of friction here due to licensing (I can't directly upload the checkpoints, I think). So Step 1, get the Llama 2 checkpoints by following the [Meta instructions](https://github.com/facebookresearch/llama). Once we have those checkpoints, we have to convert them into the llama2.c format.
|
||||
For this we need to install the python dependencies (`pip install -r requirements.txt`) and then use the `export.py` file, e.g. for 7B model:
|
||||
|
||||
```bash
|
||||
python export.py llama2_7b.bin --meta-llama path/to/llama/model/7B
|
||||
```
|
||||
|
||||
The export will take ~10 minutes or so and generate a 26GB file (the weights of the 7B model in float32) called `llama2_7b.bin` in the current directory. It has been [reported](https://github.com/karpathy/llama2.c/pull/85) that despite efforts. I would not attempt to run anything above 7B right now for two reasons: first, 13B+ currently doesn't work because of integer flow in pointer arithmetic, which is yet to be fixed, and second, even if it were fixed, this repo is doing float32 inference right now, so it would be fairly unusably slow. Once the export is done, we can run it:
|
||||
|
||||
```bash
|
||||
./run llama2_7b.bin
|
||||
```
|
||||
|
||||
This ran at about 4 tokens/s compiled with [OpenMP](#OpenMP) on 96 threads on my CPU Linux box in the cloud. (On my MacBook Air M1, currently it's closer to 30 seconds per token if you just build with `make runfast`.) Example output:
|
||||
|
||||
> The purpose of this document is to highlight the state-of-the-art of CoO generation technologies, both recent developments and those in commercial use. The focus is on the technologies with the highest merit to become the dominating processes of the future and therefore to be technologies of interest to S&T ... R&D. As such, CoO generation technologies developed in Russia, Japan and Europe are described in some depth. The document starts with an introduction to cobalt oxides as complex products and a short view on cobalt as an essential material. The document continues with the discussion of the available CoO generation processes with respect to energy and capital consumption as well as to environmental damage.
|
||||
|
||||
base models... ¯\\_(ツ)_/¯. Since we can inference the base model, it should be possible to also inference the chat model quite easily, and have a conversation with it. And if we can find a way to run 7B more efficiently, we can start adding LoRA to our training script, and going wild with finetunes all within the repo!
|
||||
|
||||
You can also try Meta's Code Llama models even if support for them is incomplete. In particular, some hyperparameters changed (e.g. the constant in RoPE layer), so the inference is not exactly correct and a bit buggy right now. Looking into fixes. Make sure to build the tokenizer for the plain and instruct variants and pass it when doing inference.
|
||||
|
||||
```bash
|
||||
python export.py codellama2_7b.bin --meta-llama /path/to/CodeLlama-7b
|
||||
python tokenizer.py --tokenizer-model=/path/to/CodeLlama-7b/tokenizer.model
|
||||
./run codellama2_7b.bin -z /path/to/CodeLlama-7b/tokenizer.bin
|
||||
```
|
||||
|
||||
Chat with Code Llama Instruct:
|
||||
|
||||
```bash
|
||||
python export.py codellama2_7b_instruct.bin --meta-llama /path/to/CodeLlama-7b-Instruct
|
||||
python tokenizer.py --tokenizer-model=/path/to/CodeLlama-7b-Instruct/tokenizer.model
|
||||
./run codellama2_7b_instruct.bin -m chat -z /path/to/CodeLlama-7b-Instruct/tokenizer.bin
|
||||
```
|
||||
|
||||
|
||||
## huggingface models
|
||||
|
||||
We can load any huggingface models that use the Llama 2 architecture. See the script [export.py](export.py) and the `--hf` flag to export the model .bin file.
|
||||
|
||||
## models
|
||||
|
||||
For the sake of examples of smaller, from-scratch models, I trained a small model series on TinyStories. All of these trained in a few hours on my training setup (4X A100 40GB GPUs). The 110M took around 24 hours. I am hosting them on huggingface hub [tinyllamas](https://huggingface.co/karpathy/tinyllamas), both in the original PyTorch .pt, and also in the llama2.c format .bin:
|
||||
|
||||
| model | dim | n_layers | n_heads | n_kv_heads | max context length | parameters | val loss | download
|
||||
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
|
||||
| 260K | 64 | 5 | 8 | 4 | 512 | 260K | 1.297 | [stories260K](https://huggingface.co/karpathy/tinyllamas/tree/main/stories260K)
|
||||
| OG | 288 | 6 | 6 | 6 | 256 | 15M | 1.072 | [stories15M.bin](https://huggingface.co/karpathy/tinyllamas/resolve/main/stories15M.bin) |
|
||||
| 42M| 512 | 8 | 8 | 8 | 1024 | 42M | 0.847 | [stories42M.bin](https://huggingface.co/karpathy/tinyllamas/resolve/main/stories42M.bin) |
|
||||
| 110M| 768 | 12 | 12 | 12 | 1024 | 110M | 0.760 | [stories110M.bin](https://huggingface.co/karpathy/tinyllamas/resolve/main/stories110M.bin) |
|
||||
|
||||
You'll notice that the 110M model is equivalent to GPT-1 in size. Alternatively, this is also the smallest model in the GPT-2 series (`GPT-2 small`), except the max context length is only 1024 instead of 2048. The only notable changes from GPT-1/2 architecture is that Llama uses RoPE relatively positional embeddings instead of absolute/learned positional embeddings, a bit more fancy SwiGLU non-linearity in the MLP, RMSNorm instead of LayerNorm, bias=False on all Linear layers, and is optionally multiquery.
|
||||
|
||||
|
||||
## training
|
||||
|
||||
Let's see how we can train a baby Llama 2 from scratch using the code in this repo. First let's download and pretokenize some source dataset, e.g. I like [TinyStories](https://huggingface.co/datasets/roneneldan/TinyStories) so this is the only example currently available in this repo. But it should be very easy to add datasets, see the code.
|
||||
|
||||
```bash
|
||||
python tinystories.py download
|
||||
python tinystories.py pretokenize
|
||||
```
|
||||
|
||||
Then train our model:
|
||||
|
||||
```bash
|
||||
python train.py
|
||||
```
|
||||
|
||||
**brief training guide**. See the train.py script for more exotic launches and hyperparameter overrides. Here is a brief guide to how to set the parameters. Look at the table at the very end of the [Chinchilla paper](https://arxiv.org/abs/2203.15556) to get a sense of how the Transformer parameters (dim, n_layers, n_heads) grow or shrink together. Extrapolate/interpolate this pattern to get bigger or smaller transformers. Set the max context length however you wish, depending on the problem: this should be the max number of tokens that matter to predict the next token. E.g. Llama 2 uses 2048. Next, you want the _total_ batch size per update (printed by the script as "tokens per iteration will be:") to be somewhere around 100K tokens for medium-sized applications. For tiny applications it could be lower, for large training (e.g. GPTs/LLamas) it is usually ~0.5M, or even more. You get there by first maxing out the batch_size to whatever your system allows (e.g. mine was 16 in a recent run because after that my GPU runs out of memory), and then you want to increase gradient_accumulation_steps to be as high as necessary to reach the total batch size of ~100K. Finally, you want to tune your learning_rate (LR). You want this to be as high as your training allows. Very small networks can get away with a large LR (e.g. 1e-3 or even higher). Large networks need lower LRs. 3e-4 is a safe choice in most medium-sized applications, but can be too low for small networks, so try to increase it! Finally, max_iters is the length of training. Play with different settings. I mostly only ever tune these parameters and leave most of the others unchanged. Here is an example of how I trained the 110M model, which I don't think is anywhere near optimal, but looked sensible to me: dim 768, n_layers 12, n_heads 12 (so size of each head is 768 / 12 = 64 channels), seq len of 1024, batch size 16 (this is the most that fit my A100 40GB GPU), gradient_accumulation_steps = 8 was needed to get total tokens batch size to be 16 batch size * 1024 tokens in sequence * 8 grad_accum = 131,072 tokens per update. Good. Learning rate 4e-4 (probably a little too low). max_iters 200K (probably a bit too high). Dropout 0.1, as that usually helps a bit at medium size. That was it. I ran using Distributed Data Parallel (DDP) on 4 GPUs on my cloud machine, training took ~day or so.
|
||||
|
||||
Totally understand if you want to skip model training, for simple demo just download one of the pretrained models (see [models](#models) section), e.g.:
|
||||
|
||||
```bash
|
||||
wget https://huggingface.co/karpathy/tinyllamas/resolve/main/stories15M.bin
|
||||
```
|
||||
|
||||
Once we have the model.bin file, we can inference in C. Compile the C code first:
|
||||
|
||||
```bash
|
||||
llgo run . -m stories15M.bin
|
||||
```
|
||||
BIN
_demo/llama2-c/assets/llama_cute.jpg
Normal file
BIN
_demo/llama2-c/assets/llama_cute.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 183 KiB |
50
_demo/llama2-c/run.go
Normal file
50
_demo/llama2-c/run.go
Normal file
@@ -0,0 +1,50 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/llama2"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var prompt *c.Char = c.Str("Once upon a time")
|
||||
var checkpointPath *c.Char = c.Str("stories15M.bin")
|
||||
var tokenizerPath *c.Char = c.Str("tokenizer.bin")
|
||||
var temperature, topp c.Float = 1.0, 0.9
|
||||
var steps c.Int = 256
|
||||
var rngSeed uint64 = uint64(c.Time(nil))
|
||||
|
||||
loop: // parse command line arguments
|
||||
for {
|
||||
switch c.Getopt(c.Argc, c.Argv, c.Str("m:")) {
|
||||
case 'm':
|
||||
checkpointPath = c.Optarg
|
||||
c.Fprintf(c.Stderr, c.Str("==> use model: %s\n"), checkpointPath)
|
||||
case -1:
|
||||
break loop
|
||||
}
|
||||
}
|
||||
if c.Optind < c.Argc {
|
||||
prompt = c.Index(c.Argv, c.Optind)
|
||||
c.Fprintf(c.Stderr, c.Str("==> prompt: %s\n"), prompt)
|
||||
}
|
||||
|
||||
// build the Transformer via the model .bin file
|
||||
var transformer llama2.Transformer
|
||||
llama2.BuildTransformer(&transformer, checkpointPath)
|
||||
|
||||
// build the Tokenizer via the tokenizer .bin file
|
||||
var tokenizer llama2.Tokenizer
|
||||
llama2.BuildTokenizer(&tokenizer, tokenizerPath, transformer.Config.VocabSize)
|
||||
|
||||
// build the Sampler
|
||||
var sampler llama2.Sampler
|
||||
llama2.BuildSampler(&sampler, transformer.Config.VocabSize, temperature, topp, rngSeed)
|
||||
|
||||
// run!
|
||||
llama2.Generate(&transformer, &tokenizer, &sampler, prompt, steps)
|
||||
|
||||
// memory and file handles cleanup
|
||||
llama2.FreeSampler(&sampler)
|
||||
llama2.FreeTokenizer(&tokenizer)
|
||||
llama2.FreeTransformer(&transformer)
|
||||
}
|
||||
BIN
_demo/llama2-c/tokenizer.bin
Normal file
BIN
_demo/llama2-c/tokenizer.bin
Normal file
Binary file not shown.
9
_demo/logdemo/log.go
Normal file
9
_demo/logdemo/log.go
Normal file
@@ -0,0 +1,9 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
log.Println("Hello")
|
||||
}
|
||||
11
_demo/math/math.go
Normal file
11
_demo/math/math.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"math"
|
||||
)
|
||||
|
||||
func main() {
|
||||
println(math.Sqrt(2))
|
||||
println(math.Abs(-1.2))
|
||||
println(math.Ldexp(1.2, 3))
|
||||
}
|
||||
18
_demo/osexec/exec.go
Normal file
18
_demo/osexec/exec.go
Normal file
@@ -0,0 +1,18 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"os"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := "ls"
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = "dir"
|
||||
}
|
||||
cmd := exec.Command(ls)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
cmd.Run()
|
||||
}
|
||||
19
_demo/oslookpath/lookpath.go
Normal file
19
_demo/oslookpath/lookpath.go
Normal file
@@ -0,0 +1,19 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := "ls"
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = "dir"
|
||||
}
|
||||
lspath, _ := exec.LookPath(ls)
|
||||
if lspath != "" {
|
||||
ls = lspath
|
||||
}
|
||||
fmt.Println(ls)
|
||||
}
|
||||
25
_demo/qsort/qsort.go
Normal file
25
_demo/qsort/qsort.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := [...]int{100, 8, 23, 2, 7}
|
||||
c.Qsort(c.Pointer(&a), 5, unsafe.Sizeof(0), func(a, b c.Pointer) c.Int {
|
||||
return c.Int(*(*int)(a) - *(*int)(b))
|
||||
})
|
||||
for _, v := range a {
|
||||
c.Printf(c.Str("%d\n"), v)
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
2
|
||||
7
|
||||
8
|
||||
23
|
||||
100
|
||||
*/
|
||||
15
_demo/rand/rand.go
Normal file
15
_demo/rand/rand.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/math/rand"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var s c.Uint = 6
|
||||
rand.Srand(s)
|
||||
rr := rand.RandR(&s)
|
||||
r := rand.Rand()
|
||||
println("r:", r)
|
||||
println("rr:", rr)
|
||||
}
|
||||
16
_demo/setjmp/setjmp.go
Normal file
16
_demo/setjmp/setjmp.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c/setjmp"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var jb setjmp.SigjmpBuf
|
||||
switch ret := setjmp.Sigsetjmp(&jb, 0); ret {
|
||||
case 0:
|
||||
println("Hello, setjmp!")
|
||||
setjmp.Siglongjmp(&jb, 1)
|
||||
default:
|
||||
println("exception:", ret)
|
||||
}
|
||||
}
|
||||
32
_demo/socket/client/client.go
Normal file
32
_demo/socket/client/client.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
"github.com/goplus/llgo/c/socket"
|
||||
)
|
||||
|
||||
func main() {
|
||||
sockfd := socket.Socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
msg := c.Str("Hello, World!")
|
||||
defer os.Close(sockfd)
|
||||
|
||||
server := socket.GetHostByName(c.Str("localhost"))
|
||||
if server == nil {
|
||||
c.Perror(c.Str("hostname get error"))
|
||||
return
|
||||
}
|
||||
|
||||
servAddr := &socket.SockaddrIn{}
|
||||
servAddr.Family = socket.AF_INET
|
||||
servAddr.Port = socket.Htons(uint16(1234))
|
||||
c.Memcpy(unsafe.Pointer(&servAddr.Addr.Addr), unsafe.Pointer(*server.AddrList), uintptr(server.Length))
|
||||
|
||||
if res := socket.Connect(sockfd, (*socket.SockAddr)(unsafe.Pointer(servAddr)), c.Uint(16)); res < 0 {
|
||||
c.Perror(c.Str("connect error"))
|
||||
return
|
||||
}
|
||||
os.Write(sockfd, unsafe.Pointer(msg), c.Strlen(msg))
|
||||
}
|
||||
43
_demo/socket/server/server.go
Normal file
43
_demo/socket/server/server.go
Normal file
@@ -0,0 +1,43 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/os"
|
||||
"github.com/goplus/llgo/c/socket"
|
||||
)
|
||||
|
||||
func main() {
|
||||
var buffer [256]c.Char
|
||||
|
||||
sockfd := socket.Socket(socket.AF_INET, socket.SOCK_STREAM, 0)
|
||||
defer os.Close(sockfd)
|
||||
|
||||
servAddr := &socket.SockaddrIn{
|
||||
Family: socket.AF_INET,
|
||||
Port: socket.Htons(uint16(1234)),
|
||||
Addr: socket.InAddr{Addr: 0x00000000},
|
||||
Zero: [8]c.Char{0, 0, 0, 0, 0, 0, 0, 0},
|
||||
}
|
||||
if res := socket.Bind(sockfd, servAddr, c.Uint(unsafe.Sizeof(*servAddr))); res < 0 {
|
||||
c.Perror(c.Str("bind error"))
|
||||
return
|
||||
}
|
||||
|
||||
if socket.Listen(sockfd, 5) < 0 {
|
||||
c.Printf(c.Str("listen error"))
|
||||
return
|
||||
}
|
||||
c.Printf(c.Str("Listening on port 1234...\n"))
|
||||
|
||||
cliAddr, clilen := &socket.SockaddrIn{}, c.Uint(unsafe.Sizeof(servAddr))
|
||||
|
||||
newsockfd := socket.Accept(sockfd, cliAddr, &clilen)
|
||||
defer os.Close(newsockfd)
|
||||
c.Printf(c.Str("Connection accepted."))
|
||||
|
||||
os.Read(newsockfd, unsafe.Pointer(unsafe.SliceData(buffer[:])), 256)
|
||||
c.Printf(c.Str("Received: %s"), &buffer[0])
|
||||
|
||||
}
|
||||
26
_demo/sysexec/exec.go
Normal file
26
_demo/sysexec/exec.go
Normal file
@@ -0,0 +1,26 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os/exec"
|
||||
"runtime"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
func main() {
|
||||
ls := "ls"
|
||||
args := []string{ls, "-l"}
|
||||
if runtime.GOOS == "windows" {
|
||||
ls = "dir"
|
||||
args = []string{ls}
|
||||
}
|
||||
lspath, _ := exec.LookPath(ls)
|
||||
if lspath != "" {
|
||||
ls = lspath
|
||||
}
|
||||
err := syscall.Exec(ls, args, nil)
|
||||
if err != nil {
|
||||
fmt.Println("syscall.Exec error:", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
25
_demo/thread/thd.go
Normal file
25
_demo/thread/thd.go
Normal file
@@ -0,0 +1,25 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/pthread"
|
||||
)
|
||||
|
||||
var key pthread.Key
|
||||
|
||||
func main() {
|
||||
key.Create(nil)
|
||||
key.Set(c.Pointer(c.Str("main value\n")))
|
||||
|
||||
var thd pthread.Thread
|
||||
pthread.Create(&thd, nil, func(arg c.Pointer) c.Pointer {
|
||||
key.Set(c.Pointer(c.Str("thread value\n")))
|
||||
c.Printf(c.Str("Hello, thread\nTLS: %s"), key.Get())
|
||||
return c.Pointer(c.Str("Back to main\n"))
|
||||
}, nil)
|
||||
|
||||
var retval c.Pointer
|
||||
pthread.Join(thd, &retval)
|
||||
|
||||
c.Printf(c.Str("%sTLS: %s"), retval, key.Get())
|
||||
}
|
||||
11
_demo/timedur/timedur.go
Normal file
11
_demo/timedur/timedur.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
)
|
||||
|
||||
func main() {
|
||||
t := time.Now().Add(time.Second * 5)
|
||||
fmt.Println(time.Until(t))
|
||||
}
|
||||
12
_pydemo/callpy/callpy.go
Normal file
12
_pydemo/callpy/callpy.go
Normal file
@@ -0,0 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/py"
|
||||
"github.com/goplus/llgo/py/math"
|
||||
"github.com/goplus/llgo/py/std"
|
||||
)
|
||||
|
||||
func main() {
|
||||
x := math.Sqrt(py.Float(2)) // x = sqrt(2)
|
||||
std.Print(py.Str("sqrt(2) ="), x) // print("sqrt(2) =", x)
|
||||
}
|
||||
22
_pydemo/matrix/matrix.go
Normal file
22
_pydemo/matrix/matrix.go
Normal file
@@ -0,0 +1,22 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/py"
|
||||
"github.com/goplus/llgo/py/numpy"
|
||||
"github.com/goplus/llgo/py/std"
|
||||
)
|
||||
|
||||
func main() {
|
||||
a := py.List(
|
||||
py.List(1.0, 2.0, 3.0),
|
||||
py.List(4.0, 5.0, 6.0),
|
||||
py.List(7.0, 8.0, 9.0),
|
||||
)
|
||||
b := py.List(
|
||||
py.List(9.0, 8.0, 7.0),
|
||||
py.List(6.0, 5.0, 4.0),
|
||||
py.List(3.0, 2.0, 1.0),
|
||||
)
|
||||
x := numpy.Add(a, b)
|
||||
std.Print(py.Str("a+b ="), x)
|
||||
}
|
||||
15
_pydemo/max/max.go
Normal file
15
_pydemo/max/max.go
Normal file
@@ -0,0 +1,15 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/py"
|
||||
"github.com/goplus/llgo/py/std"
|
||||
)
|
||||
|
||||
func main() {
|
||||
x := std.Max(py.Float(3.0), py.Float(9.0), py.Float(23.0), py.Float(100.0))
|
||||
std.Print(x)
|
||||
|
||||
list := py.List(3.0, 9.0, 23.0, 100.0)
|
||||
y := std.Max(std.Iter(list))
|
||||
std.Print(y)
|
||||
}
|
||||
10
_pydemo/pi/pi.go
Normal file
10
_pydemo/pi/pi.go
Normal file
@@ -0,0 +1,10 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/py/math"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c.Printf(c.Str("pi = %f\n"), math.Pi.Float64())
|
||||
}
|
||||
11
_pydemo/print/print.go
Normal file
11
_pydemo/print/print.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/py"
|
||||
"github.com/goplus/llgo/py/std"
|
||||
)
|
||||
|
||||
func main() {
|
||||
x := py.Float(3.14)
|
||||
std.Print(x)
|
||||
}
|
||||
13
_pydemo/statistics/statistics.go
Normal file
13
_pydemo/statistics/statistics.go
Normal file
@@ -0,0 +1,13 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/py"
|
||||
"github.com/goplus/llgo/py/statistics"
|
||||
)
|
||||
|
||||
func main() {
|
||||
list := py.List(1.0, 2.0, 3.0, 4.0, 4.0)
|
||||
mean := statistics.Mean(list)
|
||||
c.Printf(c.Str("mean(1, 2, 3, 4, 4) = %f\n"), mean.Float64())
|
||||
}
|
||||
16
_pydemo/tensor/tensor.go
Normal file
16
_pydemo/tensor/tensor.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/py"
|
||||
"github.com/goplus/llgo/py/std"
|
||||
"github.com/goplus/llgo/py/torch"
|
||||
)
|
||||
|
||||
func main() {
|
||||
data := py.List(
|
||||
py.List(1.0, 2.0),
|
||||
py.List(3.0, 4.0),
|
||||
)
|
||||
x := torch.Tensor(data)
|
||||
std.Print(x)
|
||||
}
|
||||
101
c/bdwgc/_test/bdwgc.go
Normal file
101
c/bdwgc/_test/bdwgc.go
Normal file
@@ -0,0 +1,101 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/bdwgc"
|
||||
"github.com/goplus/llgo/c/bdwgc/_test/testing"
|
||||
)
|
||||
|
||||
// ------ Test malloc ------
|
||||
|
||||
func TestMalloc(t *testing.T) {
|
||||
pn := (*int)(bdwgc.Malloc(unsafe.Sizeof(int(0))))
|
||||
*pn = 1 << 30
|
||||
c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn)
|
||||
|
||||
pl := (*int64)(bdwgc.Realloc(c.Pointer(pn), unsafe.Sizeof(int64(0))))
|
||||
*pl = 1 << 60
|
||||
c.Printf(c.Str("value: %lld, %llx, %p, %p\n"), *pl, *pl, pl, &pl)
|
||||
|
||||
bdwgc.Free(c.Pointer(pl))
|
||||
}
|
||||
|
||||
// ------ Test finalizer ------
|
||||
|
||||
const (
|
||||
RETURN_VALUE_FREED = 1 << 31
|
||||
)
|
||||
|
||||
var called uint = 0
|
||||
|
||||
func setReturnValueFreed(pobj c.Pointer, clientData c.Pointer) {
|
||||
called |= RETURN_VALUE_FREED
|
||||
c.Printf(c.Str("called: %x\n"), called)
|
||||
}
|
||||
|
||||
func setLoopValueFreed(pobj c.Pointer, clientData c.Pointer) {
|
||||
pmask := (*uint)(clientData)
|
||||
called |= *pmask
|
||||
c.Printf(c.Str("called: %x\n"), called)
|
||||
}
|
||||
|
||||
func isCalled(mask uint) bool {
|
||||
return called&mask != 0
|
||||
}
|
||||
|
||||
func returnValue() *int {
|
||||
pn := bdwgc.Malloc(unsafe.Sizeof(int(0)))
|
||||
bdwgc.RegisterFinalizer(pn, setReturnValueFreed, nil, nil, nil)
|
||||
return (*int)(pn)
|
||||
}
|
||||
|
||||
func callFunc() {
|
||||
pn := returnValue()
|
||||
*pn = 1 << 30
|
||||
c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn)
|
||||
bdwgc.Gcollect()
|
||||
check(!isCalled(RETURN_VALUE_FREED), c.Str("finalizer should not be called"))
|
||||
}
|
||||
|
||||
func loop() {
|
||||
for i := 0; i < 5; i++ {
|
||||
p := bdwgc.Malloc(unsafe.Sizeof(int(0)))
|
||||
pn := (*int)(p)
|
||||
*pn = i
|
||||
c.Printf(c.Str("value: %d, %x, %p, %p\n"), *pn, *pn, pn, &pn)
|
||||
pflag := (*uint)(c.Malloc(unsafe.Sizeof(uint(0))))
|
||||
*pflag = 1 << i
|
||||
bdwgc.RegisterFinalizer(p, setLoopValueFreed, c.Pointer(pflag), nil, nil)
|
||||
bdwgc.Gcollect()
|
||||
check(!isCalled(1<<i), c.Str("finalizer should not be called"))
|
||||
for j := 0; j < i; j++ {
|
||||
check(isCalled(1<<j), c.Str("finalizers of previous objects should be called"))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clear stack to avoid reference
|
||||
func clearStack() {
|
||||
p := c.Alloca(128)
|
||||
c.Memset(p, 0, 128)
|
||||
}
|
||||
|
||||
func check(b bool, msg *c.Char) {
|
||||
if !b {
|
||||
c.Printf(c.Str("check failed: %s\n"), msg)
|
||||
panic("check failed")
|
||||
}
|
||||
}
|
||||
|
||||
func TestFinalizer(t *testing.T) {
|
||||
bdwgc.Init()
|
||||
|
||||
callFunc()
|
||||
clearStack()
|
||||
bdwgc.Gcollect()
|
||||
check(isCalled(RETURN_VALUE_FREED), c.Str("finalizer should be called"))
|
||||
|
||||
loop()
|
||||
}
|
||||
31
c/bdwgc/_test/main.go
Normal file
31
c/bdwgc/_test/main.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/bdwgc/_test/testing"
|
||||
)
|
||||
|
||||
type TestCase struct {
|
||||
Name string
|
||||
F func(*testing.T)
|
||||
}
|
||||
|
||||
func main() {
|
||||
tests := []TestCase{
|
||||
{"TestMalloc", TestMalloc},
|
||||
{"TestFinalizer", TestFinalizer},
|
||||
}
|
||||
if c.Argc == 1 {
|
||||
for _, test := range tests {
|
||||
c.Printf(c.Str("%s\n"), c.AllocaCStr(test.Name))
|
||||
}
|
||||
return
|
||||
}
|
||||
c.Fprintf(c.Stderr, c.Str("arg: %s\n"), c.Index(c.Argv, 1))
|
||||
idx := int(c.Atoi(c.Index(c.Argv, 1)))
|
||||
if idx < 0 || idx >= len(tests) {
|
||||
c.Printf(c.Str("invalid test index %d"), idx)
|
||||
panic("invalid test index")
|
||||
}
|
||||
tests[idx].F(nil)
|
||||
}
|
||||
4
c/bdwgc/_test/testing/testing.go
Normal file
4
c/bdwgc/_test/testing/testing.go
Normal file
@@ -0,0 +1,4 @@
|
||||
package testing
|
||||
|
||||
type T struct {
|
||||
}
|
||||
103
c/bdwgc/bdwgc.go
Normal file
103
c/bdwgc/bdwgc.go
Normal file
@@ -0,0 +1,103 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package bdwgc
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link: $(pkg-config --libs bdw-gc); -lgc"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Init C.GC_init
|
||||
func Init()
|
||||
|
||||
//go:linkname Malloc C.GC_malloc
|
||||
func Malloc(size uintptr) c.Pointer
|
||||
|
||||
//go:linkname Realloc C.GC_realloc
|
||||
func Realloc(ptr c.Pointer, size uintptr) c.Pointer
|
||||
|
||||
//go:linkname Free C.GC_free
|
||||
func Free(ptr c.Pointer)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname RegisterFinalizer C.GC_register_finalizer
|
||||
func RegisterFinalizer(
|
||||
obj c.Pointer,
|
||||
fn func(c.Pointer, c.Pointer), cd c.Pointer,
|
||||
oldFn *func(c.Pointer, c.Pointer), oldCd *c.Pointer)
|
||||
|
||||
//go:linkname RegisterFinalizerNoOrder C.GC_register_finalizer_no_order
|
||||
func RegisterFinalizerNoOrder(
|
||||
obj c.Pointer,
|
||||
fn func(c.Pointer, c.Pointer), cd c.Pointer,
|
||||
oldFn *func(c.Pointer, c.Pointer), oldCd *c.Pointer)
|
||||
|
||||
//go:linkname RegisterFinalizerIgnoreSelf C.GC_register_finalizer_ignore_self
|
||||
func RegisterFinalizerIgnoreSelf(
|
||||
obj c.Pointer,
|
||||
fn func(c.Pointer, c.Pointer), cd c.Pointer,
|
||||
oldFn *func(c.Pointer, c.Pointer), oldCd *c.Pointer)
|
||||
|
||||
//go:linkname RegisterFinalizerUnreachable C.GC_register_finalizer_unreachable
|
||||
func RegisterFinalizerUnreachable(
|
||||
obj c.Pointer,
|
||||
fn func(c.Pointer, c.Pointer), cd c.Pointer,
|
||||
oldFn *func(c.Pointer, c.Pointer), oldCd *c.Pointer)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Enable C.GC_enable
|
||||
func Enable()
|
||||
|
||||
//go:linkname Disable C.GC_disable
|
||||
func Disable()
|
||||
|
||||
//go:linkname IsDisabled C.GC_is_disabled
|
||||
func IsDisabled() c.Int
|
||||
|
||||
//go:linkname Gcollect C.GC_gcollect
|
||||
func Gcollect()
|
||||
|
||||
//go:linkname GetMemoryUse C.GC_get_memory_use
|
||||
func GetMemoryUse() uintptr
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname EnableIncremental C.GC_enable_incremental
|
||||
func EnableIncremental()
|
||||
|
||||
//go:linkname IsIncrementalMode C.GC_is_incremental_mode
|
||||
func IsIncrementalMode() c.Int
|
||||
|
||||
//go:linkname IncrementalProtectionNeeds C.GC_incremental_protection_needs
|
||||
func IncrementalProtectionNeeds() c.Int
|
||||
|
||||
//go:linkname StartIncrementalCollection C.GC_start_incremental_collection
|
||||
func StartIncrementalCollection()
|
||||
|
||||
//go:linkname CollectALittle C.GC_collect_a_little
|
||||
func CollectALittle()
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
17
c/bitcast/_cast/cast.c
Normal file
17
c/bitcast/_cast/cast.c
Normal file
@@ -0,0 +1,17 @@
|
||||
typedef union {
|
||||
double d;
|
||||
float f;
|
||||
long v;
|
||||
} castUnion;
|
||||
|
||||
double llgoToFloat64(long v) {
|
||||
castUnion k;
|
||||
k.v = v;
|
||||
return k.d;
|
||||
}
|
||||
|
||||
float llgoToFloat32(long v) {
|
||||
castUnion k;
|
||||
k.v = v;
|
||||
return k.f;
|
||||
}
|
||||
30
c/bitcast/bitcast.go
Normal file
30
c/bitcast/bitcast.go
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package bitcast
|
||||
|
||||
import _ "unsafe"
|
||||
|
||||
const (
|
||||
LLGoFiles = "_cast/cast.c"
|
||||
LLGoPackage = "link"
|
||||
)
|
||||
|
||||
//go:linkname ToFloat64 C.llgoToFloat64
|
||||
func ToFloat64(v uintptr) float64
|
||||
|
||||
//go:linkname ToFloat32 C.llgoToFloat32
|
||||
func ToFloat32(v uintptr) float32
|
||||
271
c/c.go
Normal file
271
c/c.go
Normal file
@@ -0,0 +1,271 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package c
|
||||
|
||||
// typedef unsigned int uint;
|
||||
// typedef unsigned long ulong;
|
||||
// typedef unsigned long long ulonglong;
|
||||
// typedef long long longlong;
|
||||
import "C"
|
||||
import "unsafe"
|
||||
|
||||
const (
|
||||
LLGoPackage = "decl"
|
||||
)
|
||||
|
||||
type (
|
||||
Char = int8
|
||||
Float = float32
|
||||
Double = float64
|
||||
Pointer = unsafe.Pointer
|
||||
FilePtr = unsafe.Pointer
|
||||
)
|
||||
|
||||
type (
|
||||
Int C.int
|
||||
Uint C.uint
|
||||
|
||||
Long C.long
|
||||
Ulong C.ulong
|
||||
|
||||
LongLong C.longlong
|
||||
UlongLong C.ulonglong
|
||||
)
|
||||
|
||||
type integer interface {
|
||||
~int | ~uint | ~uintptr | ~int32 | ~uint32 | ~int64 | ~uint64
|
||||
}
|
||||
|
||||
//go:linkname Str llgo.cstr
|
||||
func Str(string) *Char
|
||||
|
||||
//go:linkname Func llgo.funcAddr
|
||||
func Func(any) Pointer
|
||||
|
||||
// llgo:link Advance llgo.advance
|
||||
func Advance[PtrT any, I integer](ptr PtrT, offset I) PtrT { return ptr }
|
||||
|
||||
// llgo:link Index llgo.index
|
||||
func Index[T any, I integer](ptr *T, offset I) T { return *ptr }
|
||||
|
||||
//go:linkname Alloca llgo.alloca
|
||||
func Alloca(size uintptr) Pointer
|
||||
|
||||
//go:linkname AllocaCStr llgo.allocaCStr
|
||||
func AllocaCStr(s string) *Char
|
||||
|
||||
//go:linkname AllocaCStrs llgo.allocaCStrs
|
||||
func AllocaCStrs(strs []string, endWithNil bool) **Char
|
||||
|
||||
// TODO(xsw):
|
||||
// llgo:link AllocaNew llgo.allocaNew
|
||||
func AllocaNew[T any]() *T { return nil }
|
||||
|
||||
//go:linkname Malloc C.malloc
|
||||
func Malloc(size uintptr) Pointer
|
||||
|
||||
//go:linkname Free C.free
|
||||
func Free(ptr Pointer)
|
||||
|
||||
//go:linkname Memcpy C.memcpy
|
||||
func Memcpy(dst, src Pointer, n uintptr) Pointer
|
||||
|
||||
//go:linkname Memmove C.memmove
|
||||
func Memmove(dst, src Pointer, n uintptr) Pointer
|
||||
|
||||
//go:linkname Memset C.memset
|
||||
func Memset(s Pointer, c Int, n uintptr) Pointer
|
||||
|
||||
//go:linkname Memchr C.memchr
|
||||
func Memchr(s Pointer, c Int, n uintptr) Pointer
|
||||
|
||||
//go:linkname Memcmp C.memcmp
|
||||
func Memcmp(s1, s2 Pointer, n uintptr) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Strlen C.strlen
|
||||
func Strlen(s *Char) uintptr
|
||||
|
||||
//go:linkname Strcpy C.strcpy
|
||||
func Strcpy(dst, src *Char) *Char
|
||||
|
||||
//go:linkname Strncpy C.strncpy
|
||||
func Strncpy(dst, src *Char, n uintptr) *Char
|
||||
|
||||
//go:linkname Strcat C.strcat
|
||||
func Strcat(dst, src *Char) *Char
|
||||
|
||||
//go:linkname Strncat C.strncat
|
||||
func Strncat(dst, src *Char, n uintptr) *Char
|
||||
|
||||
//go:linkname Strcmp C.strcmp
|
||||
func Strcmp(s1, s2 *Char) Int
|
||||
|
||||
//go:linkname Strncmp C.strncmp
|
||||
func Strncmp(s1, s2 *Char, n uintptr) Int
|
||||
|
||||
//go:linkname Strchr C.strchr
|
||||
func Strchr(s *Char, c Int) *Char
|
||||
|
||||
//go:linkname Strrchr C.strrchr
|
||||
func Strrchr(s *Char, c Int) *Char
|
||||
|
||||
//go:linkname Strstr C.strstr
|
||||
func Strstr(s1, s2 *Char) *Char
|
||||
|
||||
//go:linkname Strdup C.strdup
|
||||
func Strdup(s *Char) *Char
|
||||
|
||||
//go:linkname Strndup C.strndup
|
||||
func Strndup(s *Char, n uintptr) *Char
|
||||
|
||||
//go:linkname Strtok C.strtok
|
||||
func Strtok(s, delim *Char) *Char
|
||||
|
||||
//go:linkname Strerror C.strerror
|
||||
func Strerror(errnum Int) *Char
|
||||
|
||||
//go:linkname Sprintf C.sprintf
|
||||
func Sprintf(s *Char, format *Char, __llgo_va_list ...any) Int
|
||||
|
||||
//go:linkname Snprintf C.snprintf
|
||||
func Snprintf(s *Char, n uintptr, format *Char, __llgo_va_list ...any) Int
|
||||
|
||||
//go:linkname Vsnprintf C.vsnprintf
|
||||
func Vsnprintf(s *Char, n uintptr, format *Char, ap Pointer) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// GoString converts a C string to a Go string.
|
||||
// TODO(xsw): any => int
|
||||
//
|
||||
//go:linkname GoString llgo.string
|
||||
func GoString(cstr *Char, __llgo_va_list /* n */ ...any) string
|
||||
|
||||
//go:linkname GoStringData llgo.stringData
|
||||
func GoStringData(string) *Char
|
||||
|
||||
//go:linkname GoDeferData llgo.deferData
|
||||
func GoDeferData() Pointer
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname AllocaSigjmpBuf llgo.sigjmpbuf
|
||||
func AllocaSigjmpBuf() Pointer
|
||||
|
||||
//go:linkname Sigsetjmp llgo.sigsetjmp
|
||||
func Sigsetjmp(jb Pointer, savemask Int) Int
|
||||
|
||||
//go:linkname Siglongjmp llgo.siglongjmp
|
||||
func Siglongjmp(jb Pointer, retval Int)
|
||||
|
||||
//go:linkname Unreachable llgo.unreachable
|
||||
func Unreachable()
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Exit C.exit
|
||||
func Exit(Int)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Rand C.rand
|
||||
func Rand() Int
|
||||
|
||||
//go:linkname Qsort C.qsort
|
||||
func Qsort(base Pointer, count, elem uintptr, compar func(a, b Pointer) Int)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Atoi C.atoi
|
||||
func Atoi(s *Char) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Printf C.printf
|
||||
func Printf(format *Char, __llgo_va_list ...any) Int
|
||||
|
||||
//go:linkname Fprintf C.fprintf
|
||||
func Fprintf(fp FilePtr, format *Char, __llgo_va_list ...any) Int
|
||||
|
||||
//go:linkname Fwrite C.fwrite
|
||||
func Fwrite(data Pointer, size, count uintptr, fp FilePtr) uintptr
|
||||
|
||||
//go:linkname Fputc C.fputc
|
||||
func Fputc(c Int, fp FilePtr) Int
|
||||
|
||||
//go:linkname Fputs C.fputs
|
||||
func Fputs(s *Char, fp FilePtr) Int
|
||||
|
||||
//go:linkname Fflush C.fflush
|
||||
func Fflush(fp FilePtr) Int
|
||||
|
||||
//go:linkname Fopen C.fopen
|
||||
func Fopen(c *Char, mod *Char) FilePtr
|
||||
|
||||
//go:linkname Fclose C.fclose
|
||||
func Fclose(fp FilePtr) Int
|
||||
|
||||
//go:linkname Perror C.perror
|
||||
func Perror(s *Char)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Time C.time
|
||||
func Time(*int32) int32
|
||||
|
||||
//go:linkname Usleep C.usleep
|
||||
func Usleep(useconds Uint) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
type Option struct {
|
||||
Name *Char
|
||||
HasArg Int
|
||||
Flag *Int
|
||||
Val Int
|
||||
}
|
||||
|
||||
//go:linkname Argc __llgo_argc
|
||||
var Argc Int
|
||||
|
||||
//go:linkname Argv __llgo_argv
|
||||
var Argv **Char
|
||||
|
||||
//go:linkname Optarg optarg
|
||||
var Optarg *Char
|
||||
|
||||
//go:linkname Optind optind
|
||||
var Optind Int
|
||||
|
||||
//go:linkname Opterr opterr
|
||||
var Opterr Int
|
||||
|
||||
//go:linkname Optopt optopt
|
||||
var Optopt Int
|
||||
|
||||
//go:linkname Getopt C.getopt
|
||||
func Getopt(argc Int, argv **Char, optstring *Char) Int
|
||||
|
||||
//go:linkname GetoptLong C.getopt_long
|
||||
func GetoptLong(argc Int, argv **Char, optstring *Char, longopts *Option, longindex *Int) Int
|
||||
|
||||
//go:linkname GetoptLongOnly C.getopt_long_only
|
||||
func GetoptLongOnly(argc Int, argv **Char, optstring *Char, longopts *Option, longindex *Int) Int
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
31
c/c_default.go
Normal file
31
c/c_default.go
Normal file
@@ -0,0 +1,31 @@
|
||||
//go:build !linux
|
||||
// +build !linux
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package c
|
||||
|
||||
import _ "unsafe"
|
||||
|
||||
//go:linkname Stdin __stdinp
|
||||
var Stdin FilePtr
|
||||
|
||||
//go:linkname Stdout __stdoutp
|
||||
var Stdout FilePtr
|
||||
|
||||
//go:linkname Stderr __stderrp
|
||||
var Stderr FilePtr
|
||||
31
c/c_linux.go
Normal file
31
c/c_linux.go
Normal file
@@ -0,0 +1,31 @@
|
||||
//go:build linux
|
||||
// +build linux
|
||||
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package c
|
||||
|
||||
import _ "unsafe"
|
||||
|
||||
//go:linkname Stdin stdin
|
||||
var Stdin FilePtr
|
||||
|
||||
//go:linkname Stdout stdout
|
||||
var Stdout FilePtr
|
||||
|
||||
//go:linkname Stderr stderr
|
||||
var Stderr FilePtr
|
||||
31
c/cjson/README.md
Normal file
31
c/cjson/README.md
Normal file
@@ -0,0 +1,31 @@
|
||||
LLGo wrapper of DaveGamble/cJSON
|
||||
=====
|
||||
|
||||
## How to install
|
||||
|
||||
### on macOS (Homebrew)
|
||||
|
||||
```sh
|
||||
brew install cjson
|
||||
```
|
||||
|
||||
### on Linux (Debian/Ubuntu)
|
||||
|
||||
```sh
|
||||
apt-get install -y libcjson-dev
|
||||
```
|
||||
|
||||
## Demos
|
||||
|
||||
The `_demo` directory contains our demos (it start with `_` to prevent the `go` command from compiling it):
|
||||
|
||||
* [mkjson](_demo/mkjson/mkjson.go): create a json object and print it
|
||||
|
||||
### How to run demos
|
||||
|
||||
To run the demos in directory `_demo`:
|
||||
|
||||
```sh
|
||||
cd <demo-directory> # eg. cd _demo/mkjson
|
||||
llgo run .
|
||||
```
|
||||
27
c/cjson/_demo/mkjson/mkjson.go
Normal file
27
c/cjson/_demo/mkjson/mkjson.go
Normal file
@@ -0,0 +1,27 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/cjson"
|
||||
)
|
||||
|
||||
func main() {
|
||||
mod := cjson.Object()
|
||||
mod.SetItem(c.Str("name"), cjson.String(c.Str("math")))
|
||||
|
||||
syms := cjson.Array()
|
||||
|
||||
fn := cjson.Object()
|
||||
fn.SetItem(c.Str("name"), cjson.String(c.Str("sqrt")))
|
||||
fn.SetItem(c.Str("sig"), cjson.String(c.Str("(x, /)")))
|
||||
syms.AddItem(fn)
|
||||
|
||||
v := cjson.Object()
|
||||
v.SetItem(c.Str("name"), cjson.String(c.Str("pi")))
|
||||
syms.AddItem(v)
|
||||
|
||||
mod.SetItem(c.Str("items"), syms)
|
||||
|
||||
c.Printf(c.Str("%s\n"), mod.CStr())
|
||||
mod.Delete()
|
||||
}
|
||||
121
c/cjson/cjson.go
Normal file
121
c/cjson/cjson.go
Normal file
@@ -0,0 +1,121 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cjson
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoPackage = "link: $(pkg-config --libs libcjson); -lcjson"
|
||||
)
|
||||
|
||||
// llgo:type C
|
||||
type JSON struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
//go:linkname Null C.cJSON_CreateNull
|
||||
func Null() *JSON
|
||||
|
||||
//go:linkname True C.cJSON_CreateTrue
|
||||
func True() *JSON
|
||||
|
||||
//go:linkname False C.cJSON_CreateFalse
|
||||
func False() *JSON
|
||||
|
||||
//go:linkname Bool C.cJSON_CreateBool
|
||||
func Bool(boolean c.Int) *JSON
|
||||
|
||||
//go:linkname Number C.cJSON_CreateNumber
|
||||
func Number(num float64) *JSON
|
||||
|
||||
//go:linkname String C.cJSON_CreateString
|
||||
func String(str *c.Char) *JSON
|
||||
|
||||
//go:linkname Array C.cJSON_CreateArray
|
||||
func Array() *JSON
|
||||
|
||||
//go:linkname Object C.cJSON_CreateObject
|
||||
func Object() *JSON
|
||||
|
||||
// raw json
|
||||
//
|
||||
//go:linkname Raw C.cJSON_CreateRaw
|
||||
func Raw(raw *c.Char) *JSON
|
||||
|
||||
// Create a string where valuestring references a string so
|
||||
// it will not be freed by Delete
|
||||
//
|
||||
//go:linkname StringRef C.cJSON_CreateStringReference
|
||||
func StringRef(str *c.Char) *JSON
|
||||
|
||||
// Create an object that only references it's elements so
|
||||
// they will not be freed by Delete
|
||||
//
|
||||
//go:linkname ObjectRef C.cJSON_CreateObjectReference
|
||||
func ObjectRef(child *JSON) *JSON
|
||||
|
||||
// Create an array that only references it's elements so
|
||||
// they will not be freed by Delete
|
||||
//
|
||||
//go:linkname ArrayRef C.cJSON_CreateArrayReference
|
||||
func ArrayRef(child *JSON) *JSON
|
||||
|
||||
// Delete a JSON entity and all subentities.
|
||||
//
|
||||
// llgo:link (*JSON).Delete C.cJSON_Delete
|
||||
func (o *JSON) Delete() {}
|
||||
|
||||
// Append item to the specified array.
|
||||
//
|
||||
// llgo:link (*JSON).AddItem C.cJSON_AddItemToArray
|
||||
func (o *JSON) AddItem(item *JSON) c.Int { return 0 }
|
||||
|
||||
// Append item to the specified object.
|
||||
//
|
||||
// llgo:link (*JSON).SetItem C.cJSON_AddItemToObject
|
||||
func (o *JSON) SetItem(key *c.Char, item *JSON) c.Int { return 0 }
|
||||
|
||||
// llgo:link (*JSON).CStr C.cJSON_PrintUnformatted
|
||||
func (o *JSON) CStr() *c.Char { return nil }
|
||||
|
||||
// Same as CStr. Provided for Go+.
|
||||
//
|
||||
// llgo:link (*JSON).Cstr C.cJSON_PrintUnformatted
|
||||
func (o *JSON) Cstr() *c.Char { return nil }
|
||||
|
||||
// Render a JSON entity to text for transfer/storage.
|
||||
//
|
||||
// llgo:link (*JSON).Print C.cJSON_Print
|
||||
func (o *JSON) Print() *c.Char { return nil }
|
||||
|
||||
// Render a JSON entity to text for transfer/storage without any formatting.
|
||||
//
|
||||
// llgo:link (*JSON).PrintUnformatted C.cJSON_PrintUnformatted
|
||||
func (o *JSON) PrintUnformatted() *c.Char { return nil }
|
||||
|
||||
// Render a JSON entity to text using a buffered strategy.
|
||||
//
|
||||
// prebuffer is a guess at the final size. guessing well reduces reallocation.
|
||||
//
|
||||
// fmt=0 gives unformatted, =1 gives formatted.
|
||||
//
|
||||
// llgo:link (*JSON).PrintBuffered C.cJSON_PrintBuffered
|
||||
func (o *JSON) PrintBuffered(prebuffer c.Int, fmt c.Int) *c.Char { return nil }
|
||||
61
c/clang/_demo/castdump/astdump.go
Normal file
61
c/clang/_demo/castdump/astdump.go
Normal file
@@ -0,0 +1,61 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/clang"
|
||||
)
|
||||
|
||||
func visit(cursor, parent clang.Cursor, clientData c.Pointer) clang.ChildVisitResult {
|
||||
depth := *(*c.Uint)(clientData)
|
||||
printAST(cursor, depth+1)
|
||||
return clang.ChildVisit_Continue
|
||||
}
|
||||
|
||||
func printAST(cursor clang.Cursor, depth c.Uint) {
|
||||
cursorKind := cursor.Kind.String()
|
||||
|
||||
cursorSpelling := cursor.String()
|
||||
|
||||
for i := c.Uint(0); i < depth; i++ {
|
||||
c.Fputs(c.Str(" "), c.Stdout)
|
||||
}
|
||||
|
||||
c.Printf(c.Str("%s: %s\n"), cursorKind.CStr(), cursorSpelling.CStr())
|
||||
|
||||
cursorKind.Dispose()
|
||||
cursorSpelling.Dispose()
|
||||
|
||||
clang.VisitChildren(cursor, visit, c.Pointer(&depth))
|
||||
}
|
||||
|
||||
func main() {
|
||||
if c.Argc != 2 {
|
||||
fmt.Fprintln(os.Stderr, "Usage: castdump <headerFile>")
|
||||
return
|
||||
}
|
||||
sourceFile := *c.Advance(c.Argv, 1)
|
||||
|
||||
index := clang.CreateIndex(0, 0)
|
||||
|
||||
unit := index.ParseTranslationUnit(
|
||||
sourceFile,
|
||||
nil, 0,
|
||||
nil, 0,
|
||||
clang.TranslationUnit_None,
|
||||
)
|
||||
|
||||
if unit == nil {
|
||||
println("Unable to parse translation unit. Quitting.")
|
||||
c.Exit(1)
|
||||
}
|
||||
|
||||
cursor := unit.Cursor()
|
||||
|
||||
printAST(cursor, 0)
|
||||
|
||||
unit.Dispose()
|
||||
index.Dispose()
|
||||
}
|
||||
29
c/clang/_wrap/cursor.cpp
Normal file
29
c/clang/_wrap/cursor.cpp
Normal file
@@ -0,0 +1,29 @@
|
||||
#include <stdio.h>
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
typedef enum CXChildVisitResult(* wrap_CXCursorVisitor) (CXCursor *cursor, CXCursor *parent, CXClientData client_data);
|
||||
|
||||
typedef struct {
|
||||
CXClientData data;
|
||||
wrap_CXCursorVisitor visitor;
|
||||
} wrap_data;
|
||||
|
||||
CXChildVisitResult wrap_visitor(CXCursor cursor, CXCursor parent, CXClientData data) {
|
||||
wrap_data *d = (wrap_data*)(data);
|
||||
return d->visitor(&cursor,&parent,d->data);
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
CXString wrap_clang_getCursorSpelling(CXCursor *cur) {
|
||||
return clang_getCursorSpelling(*cur);
|
||||
}
|
||||
|
||||
unsigned wrap_clang_visitChildren(CXCursor *parent,
|
||||
wrap_CXCursorVisitor visitor,
|
||||
CXClientData client_data) {
|
||||
wrap_data data = {client_data,visitor};
|
||||
return clang_visitChildren(*parent,wrap_visitor,CXClientData(&data));
|
||||
}
|
||||
|
||||
} // extern "C"
|
||||
7
c/clang/_wrap/llgo_check.cpp
Normal file
7
c/clang/_wrap/llgo_check.cpp
Normal file
@@ -0,0 +1,7 @@
|
||||
#include <stdio.h>
|
||||
#include <clang-c/Index.h>
|
||||
|
||||
int main() {
|
||||
printf("sizeof(clang.Cursor) = %lu\n", sizeof(CXCursor));
|
||||
return 0;
|
||||
}
|
||||
16
c/clang/_wrap/llgo_check.go
Normal file
16
c/clang/_wrap/llgo_check.go
Normal file
@@ -0,0 +1,16 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/clang"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoCFlags = "-I$(llvm-config --includedir)"
|
||||
)
|
||||
|
||||
func main() {
|
||||
c.Printf(c.Str("sizeof(clang.Cursor) = %lu\n"), unsafe.Sizeof(clang.Cursor{}))
|
||||
}
|
||||
59
c/clang/basic.go
Normal file
59
c/clang/basic.go
Normal file
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package clang
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
/**
|
||||
* A character string.
|
||||
*
|
||||
* The \c CXString type is used to return strings from the interface when
|
||||
* the ownership of that string might differ from one call to the next.
|
||||
* Use \c clang_getCString() to retrieve the string data and, once finished
|
||||
* with the string data, call \c clang_disposeString() to free the string.
|
||||
*/
|
||||
type String struct {
|
||||
Data c.Pointer
|
||||
PrivateFlags c.Uint
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the character data associated with the given string.
|
||||
*/
|
||||
// llgo:link String.CStr C.clang_getCString
|
||||
func (String) CStr() *c.Char { return nil }
|
||||
|
||||
/**
|
||||
* Free the given string.
|
||||
*/
|
||||
// llgo:link String.Dispose C.clang_disposeString
|
||||
func (String) Dispose() {}
|
||||
|
||||
type StringSet struct {
|
||||
Strings *String
|
||||
Count c.Uint
|
||||
}
|
||||
|
||||
/**
|
||||
* Free the given string set.
|
||||
*/
|
||||
// llgo:link (*StringSet).Dispose C.clang_disposeStringSet
|
||||
func (*StringSet) Dispose() {}
|
||||
292
c/clang/clang.go
Normal file
292
c/clang/clang.go
Normal file
@@ -0,0 +1,292 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package clang
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "$(llvm-config --cflags): _wrap/cursor.cpp"
|
||||
LLGoPackage = "link: -L$(llvm-config --libdir) -lclang; -lclang"
|
||||
)
|
||||
|
||||
/**
|
||||
* Opaque pointer representing client data that will be passed through
|
||||
* to various callbacks and visitors.
|
||||
*/
|
||||
type ClientData = c.Pointer
|
||||
|
||||
/**
|
||||
* Provides the contents of a file that has not yet been saved to disk.
|
||||
*
|
||||
* Each CXUnsavedFile instance provides the name of a file on the
|
||||
* system along with the current contents of that file that have not
|
||||
* yet been saved to disk.
|
||||
*/
|
||||
type UnsavedFile struct {
|
||||
/**
|
||||
* The file whose contents have not yet been saved.
|
||||
*
|
||||
* This file must already exist in the file system.
|
||||
*/
|
||||
Filename *c.Char
|
||||
|
||||
/**
|
||||
* A buffer containing the unsaved contents of this file.
|
||||
*/
|
||||
Contents *c.Char
|
||||
|
||||
/**
|
||||
* The length of the unsaved contents of this buffer.
|
||||
*/
|
||||
Length c.Ulong
|
||||
}
|
||||
|
||||
/**
|
||||
* An "index" that consists of a set of translation units that would
|
||||
* typically be linked together into an executable or library.
|
||||
*/
|
||||
type Index struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a shared context for creating translation units.
|
||||
*
|
||||
* It provides two options:
|
||||
*
|
||||
* - excludeDeclarationsFromPCH: When non-zero, allows enumeration of "local"
|
||||
* declarations (when loading any new translation units). A "local" declaration
|
||||
* is one that belongs in the translation unit itself and not in a precompiled
|
||||
* header that was used by the translation unit. If zero, all declarations
|
||||
* will be enumerated.
|
||||
*
|
||||
* Here is an example:
|
||||
*
|
||||
* \code
|
||||
* // excludeDeclsFromPCH = 1, displayDiagnostics=1
|
||||
* Idx = clang_createIndex(1, 1);
|
||||
*
|
||||
* // IndexTest.pch was produced with the following command:
|
||||
* // "clang -x c IndexTest.h -emit-ast -o IndexTest.pch"
|
||||
* TU = clang_createTranslationUnit(Idx, "IndexTest.pch");
|
||||
*
|
||||
* // This will load all the symbols from 'IndexTest.pch'
|
||||
* clang_visitChildren(clang_getTranslationUnitCursor(TU),
|
||||
* TranslationUnitVisitor, 0);
|
||||
* clang_disposeTranslationUnit(TU);
|
||||
*
|
||||
* // This will load all the symbols from 'IndexTest.c', excluding symbols
|
||||
* // from 'IndexTest.pch'.
|
||||
* char *args[] = { "-Xclang", "-include-pch=IndexTest.pch" };
|
||||
* TU = clang_createTranslationUnitFromSourceFile(Idx, "IndexTest.c", 2, args,
|
||||
* 0, 0);
|
||||
* clang_visitChildren(clang_getTranslationUnitCursor(TU),
|
||||
* TranslationUnitVisitor, 0);
|
||||
* clang_disposeTranslationUnit(TU);
|
||||
* \endcode
|
||||
*
|
||||
* This process of creating the 'pch', loading it separately, and using it (via
|
||||
* -include-pch) allows 'excludeDeclsFromPCH' to remove redundant callbacks
|
||||
* (which gives the indexer the same performance benefit as the compiler).
|
||||
*/
|
||||
//go:linkname CreateIndex C.clang_createIndex
|
||||
func CreateIndex(excludeDeclarationsFromPCH, displayDiagnostics c.Int) *Index
|
||||
|
||||
/**
|
||||
* Destroy the given index.
|
||||
*
|
||||
* The index must not be destroyed until all of the translation units created
|
||||
* within that index have been destroyed.
|
||||
*/
|
||||
// llgo:link (*Index).Dispose C.clang_disposeIndex
|
||||
func (*Index) Dispose() {}
|
||||
|
||||
/**
|
||||
* Flags that control the creation of translation units.
|
||||
*
|
||||
* The enumerators in this enumeration type are meant to be bitwise
|
||||
* ORed together to specify which options should be used when
|
||||
* constructing the translation unit.
|
||||
*/
|
||||
const (
|
||||
TranslationUnit_None = 0x0
|
||||
)
|
||||
|
||||
/**
|
||||
* Same as \c clang_parseTranslationUnit2, but returns
|
||||
* the \c CXTranslationUnit instead of an error code. In case of an error this
|
||||
* routine returns a \c NULL \c CXTranslationUnit, without further detailed
|
||||
* error codes.
|
||||
*/
|
||||
// llgo:link (*Index).ParseTranslationUnit C.clang_parseTranslationUnit
|
||||
func (*Index) ParseTranslationUnit(
|
||||
sourceFilename *c.Char, commandLineArgs **c.Char, numCommandLineArgs c.Int,
|
||||
unsavedFiles *UnsavedFile, numUnsavedFiles c.Uint, options c.Uint) *TranslationUnit {
|
||||
return nil
|
||||
}
|
||||
|
||||
/**
|
||||
* A single translation unit, which resides in an index.
|
||||
*/
|
||||
type TranslationUnit struct {
|
||||
Unused [0]byte
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy the specified CXTranslationUnit object.
|
||||
*/
|
||||
// llgo:link (*TranslationUnit).Dispose C.clang_disposeTranslationUnit
|
||||
func (*TranslationUnit) Dispose() {}
|
||||
|
||||
/**
|
||||
* Retrieve the cursor that represents the given translation unit.
|
||||
*
|
||||
* The translation unit cursor can be used to start traversing the
|
||||
* various declarations within the given translation unit.
|
||||
*/
|
||||
// llgo:link (*TranslationUnit).Cursor C.clang_getTranslationUnitCursor
|
||||
func (*TranslationUnit) Cursor() (ret Cursor) {
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes the kind of entity that a cursor refers to.
|
||||
*/
|
||||
type CursorKind c.Int
|
||||
|
||||
/* for debug/testing */
|
||||
// llgo:link CursorKind.String C.clang_getCursorKindSpelling
|
||||
func (CursorKind) String() (ret String) {
|
||||
return
|
||||
}
|
||||
|
||||
/**
|
||||
* A cursor representing some element in the abstract syntax tree for
|
||||
* a translation unit.
|
||||
*
|
||||
* The cursor abstraction unifies the different kinds of entities in a
|
||||
* program--declaration, statements, expressions, references to declarations,
|
||||
* etc.--under a single "cursor" abstraction with a common set of operations.
|
||||
* Common operation for a cursor include: getting the physical location in
|
||||
* a source file where the cursor points, getting the name associated with a
|
||||
* cursor, and retrieving cursors for any child nodes of a particular cursor.
|
||||
*
|
||||
* Cursors can be produced in two specific ways.
|
||||
* clang_getTranslationUnitCursor() produces a cursor for a translation unit,
|
||||
* from which one can use clang_visitChildren() to explore the rest of the
|
||||
* translation unit. clang_getCursor() maps from a physical source location
|
||||
* to the entity that resides at that location, allowing one to map from the
|
||||
* source code into the AST.
|
||||
*/
|
||||
type Cursor struct {
|
||||
Kind CursorKind
|
||||
Xdata c.Int
|
||||
Data [3]c.Pointer
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a name for the entity referenced by this cursor.
|
||||
*/
|
||||
// llgo:link (*Cursor).wrapString C.wrap_clang_getCursorSpelling
|
||||
func (*Cursor) wrapString() (ret String) {
|
||||
return
|
||||
}
|
||||
|
||||
func (c Cursor) String() (ret String) {
|
||||
return c.wrapString()
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes how the traversal of the children of a particular
|
||||
* cursor should proceed after visiting a particular child cursor.
|
||||
*
|
||||
* A value of this enumeration type should be returned by each
|
||||
* \c CXCursorVisitor to indicate how clang_visitChildren() proceed.
|
||||
*/
|
||||
type ChildVisitResult c.Int
|
||||
|
||||
const (
|
||||
/**
|
||||
* Terminates the cursor traversal.
|
||||
*/
|
||||
ChildVisit_Break ChildVisitResult = iota
|
||||
/**
|
||||
* Continues the cursor traversal with the next sibling of
|
||||
* the cursor just visited, without visiting its children.
|
||||
*/
|
||||
ChildVisit_Continue
|
||||
/**
|
||||
* Recursively traverse the children of this cursor, using
|
||||
* the same visitor and client data.
|
||||
*/
|
||||
ChildVisit_Recurse
|
||||
)
|
||||
|
||||
/**
|
||||
* Visit the children of a particular cursor.
|
||||
*
|
||||
* This function visits all the direct children of the given cursor,
|
||||
* invoking the given \p visitor function with the cursors of each
|
||||
* visited child. The traversal may be recursive, if the visitor returns
|
||||
* \c CXChildVisit_Recurse. The traversal may also be ended prematurely, if
|
||||
* the visitor returns \c CXChildVisit_Break.
|
||||
*
|
||||
* \param parent the cursor whose child may be visited. All kinds of
|
||||
* cursors can be visited, including invalid cursors (which, by
|
||||
* definition, have no children).
|
||||
*
|
||||
* \param visitor the visitor function that will be invoked for each
|
||||
* child of \p parent.
|
||||
*
|
||||
* \param client_data pointer data supplied by the client, which will
|
||||
* be passed to the visitor each time it is invoked.
|
||||
*
|
||||
* \returns a non-zero value if the traversal was terminated
|
||||
* prematurely by the visitor returning \c CXChildVisit_Break.
|
||||
*/
|
||||
//go:linkname wrapVisitChildren C.wrap_clang_visitChildren
|
||||
func wrapVisitChildren(
|
||||
cusor *Cursor,
|
||||
fn wrapVisitor,
|
||||
clientData ClientData) c.Uint {
|
||||
return 0
|
||||
}
|
||||
|
||||
//llgo:type C
|
||||
type wrapVisitor func(cursor, parent *Cursor, clientData ClientData) ChildVisitResult
|
||||
|
||||
type wrapData struct {
|
||||
data ClientData
|
||||
fn Visitor
|
||||
}
|
||||
|
||||
func VisitChildren(
|
||||
root Cursor,
|
||||
fn Visitor,
|
||||
clientData ClientData) c.Uint {
|
||||
return wrapVisitChildren(&root, func(cursor, parent *Cursor, data ClientData) ChildVisitResult {
|
||||
p := (*wrapData)(data)
|
||||
return p.fn(*cursor, *parent, p.data)
|
||||
}, unsafe.Pointer(&wrapData{clientData, fn}))
|
||||
}
|
||||
|
||||
//llgo:type C
|
||||
type Visitor func(cursor, parent Cursor, clientData ClientData) ChildVisitResult
|
||||
26
c/llama2/.gitignore
vendored
Normal file
26
c/llama2/.gitignore
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
# If you prefer the allow list template instead of the deny list, see community template:
|
||||
# https://github.com/github/gitignore/blob/main/community/Golang/Go.AllowList.gitignore
|
||||
#
|
||||
# Binaries for programs and plugins
|
||||
*.exe
|
||||
*.exe~
|
||||
*.dll
|
||||
*.so
|
||||
*.dylib
|
||||
|
||||
stories*.bin
|
||||
.DS_Store
|
||||
err.log
|
||||
|
||||
# Test binary, built with `go test -c`
|
||||
*.test
|
||||
|
||||
# Output of the go coverage tool, specifically when used with LiteIDE
|
||||
*.out
|
||||
*.swp
|
||||
|
||||
# Dependency directories (remove the comment below to include it)
|
||||
# vendor/
|
||||
|
||||
# Go workspace file
|
||||
go.work*
|
||||
10
c/llama2/README.md
Normal file
10
c/llama2/README.md
Normal file
@@ -0,0 +1,10 @@
|
||||
LLGo wrapper of karpathy/llama2.c
|
||||
=====
|
||||
|
||||
## How to update source to llgo
|
||||
|
||||
```
|
||||
git submodule init
|
||||
git submodule update
|
||||
cp llama2.c/run.c llama2/run.c
|
||||
```
|
||||
1
c/llama2/llama2.c
Submodule
1
c/llama2/llama2.c
Submodule
Submodule c/llama2/llama2.c added at b3c4b6c3c4
160
c/llama2/llama2.go
Normal file
160
c/llama2/llama2.go
Normal file
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package llama2
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
)
|
||||
|
||||
const (
|
||||
LLGoFiles = "llama2/llama2.c"
|
||||
LLGoPackage = "link: -lm"
|
||||
)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// llgo:type C
|
||||
type TokenIndex struct {
|
||||
Str *c.Char
|
||||
Id c.Int
|
||||
}
|
||||
|
||||
// llgo:type C
|
||||
type Tokenizer struct {
|
||||
Vocab **c.Char
|
||||
VocabScores *c.Float
|
||||
SortedVocab *TokenIndex
|
||||
VocabSize c.Int
|
||||
MaxTokenLength c.Uint
|
||||
BytePieces [512]uint8 // stores all single-byte strings
|
||||
}
|
||||
|
||||
//go:linkname BuildTokenizer C.build_tokenizer
|
||||
func BuildTokenizer(t *Tokenizer, tokenizerPath *c.Char, vocabSize c.Int)
|
||||
|
||||
//go:linkname FreeTokenizer C.free_tokenizer
|
||||
func FreeTokenizer(t *Tokenizer)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// llgo:type C
|
||||
type Config struct {
|
||||
Dim c.Int // transformer dimension
|
||||
HiddenDim c.Int // for ffn layers
|
||||
NLayers c.Int // number of layers
|
||||
NHeads c.Int // number of query heads
|
||||
NKVHeads c.Int // number of key/value heads (can be < query heads because of multiquery)
|
||||
VocabSize c.Int // vocabulary size, usually 256 (byte-level)
|
||||
SeqLen c.Int // max sequence length
|
||||
}
|
||||
|
||||
// llgo:type C
|
||||
type TransformerWeights struct {
|
||||
// token embedding table
|
||||
TokenEmbeddingTable *c.Float // (vocab_size, dim)
|
||||
// weights for rmsnorms
|
||||
RmsAttWeight *c.Float // (layer, dim) rmsnorm weights
|
||||
RmsFfnWeight *c.Float // (layer, dim)
|
||||
// weights for matmuls. note dim == n_heads * head_size
|
||||
Wq *c.Float // (layer, dim, n_heads * head_size)
|
||||
Wk *c.Float // (layer, dim, n_kv_heads * head_size)
|
||||
Wv *c.Float // (layer, dim, n_kv_heads * head_size)
|
||||
Wo *c.Float // (layer, n_heads * head_size, dim)
|
||||
// weights for ffn
|
||||
W1 *c.Float // (layer, hidden_dim, dim)
|
||||
W2 *c.Float // (layer, dim, hidden_dim)
|
||||
W3 *c.Float // (layer, hidden_dim, dim)
|
||||
// final rmsnorm
|
||||
RmsFinalWeight *c.Float // (dim,)
|
||||
// (optional) classifier weights for the logits, on the last layer
|
||||
Wcls *c.Float
|
||||
}
|
||||
|
||||
// llgo:type C
|
||||
type RunState struct {
|
||||
// current wave of activations
|
||||
X *c.Float // activation at current time stamp (dim,)
|
||||
Xb *c.Float // same, but inside a residual branch (dim,)
|
||||
Xb2 *c.Float // an additional buffer just for convenience (dim,)
|
||||
Hb *c.Float // buffer for hidden dimension in the ffn (hidden_dim,)
|
||||
Hb2 *c.Float // buffer for hidden dimension in the ffn (hidden_dim,)
|
||||
Q *c.Float // query (dim,)
|
||||
K *c.Float // key (dim,)
|
||||
V *c.Float // value (dim,)
|
||||
Att *c.Float // buffer for scores/attention values (n_heads, seq_len)
|
||||
Logits *c.Float // output logits
|
||||
// kv cache
|
||||
KeyCache *c.Float // (layer, seq_len, dim)
|
||||
ValueCache *c.Float // (layer, seq_len, dim)
|
||||
}
|
||||
|
||||
// llgo:type C
|
||||
type Transformer struct {
|
||||
Config Config // the hyperparameters of the architecture (the blueprint)
|
||||
Weights TransformerWeights // the weights of the model
|
||||
State RunState // buffers for the "wave" of activations in the forward pass
|
||||
|
||||
// some more state needed to properly clean up the memory mapping (sigh)
|
||||
Fd c.Int // file descriptor for memory mapping
|
||||
Data *c.Float // memory mapped data pointer
|
||||
FileSize uintptr // size of the checkpoint file in bytes
|
||||
}
|
||||
|
||||
//go:linkname BuildTransformer C.build_transformer
|
||||
func BuildTransformer(t *Transformer, checkpointPath *c.Char)
|
||||
|
||||
//go:linkname FreeTransformer C.free_transformer
|
||||
func FreeTransformer(t *Transformer)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
// llgo:type C
|
||||
type ProbIndex struct {
|
||||
Prob c.Float
|
||||
Index c.Int
|
||||
} // struct used when sorting probabilities during top-p sampling
|
||||
|
||||
// llgo:type C
|
||||
type Sampler struct {
|
||||
VocabSize c.Int
|
||||
Probindex *ProbIndex // buffer used in top-p sampling
|
||||
Temperature c.Float
|
||||
Topp c.Float
|
||||
RngState uint64
|
||||
}
|
||||
|
||||
//go:linkname BuildSampler C.build_sampler
|
||||
func BuildSampler(sampler *Sampler, vocabSize c.Int, temperature c.Float, topp c.Float, rngSeed uint64)
|
||||
|
||||
//go:linkname FreeSampler C.free_sampler
|
||||
func FreeSampler(sampler *Sampler)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
|
||||
//go:linkname Generate C.generate
|
||||
func Generate(
|
||||
transformer *Transformer, tokenizer *Tokenizer, sampler *Sampler,
|
||||
prompt *c.Char, steps c.Int)
|
||||
|
||||
//go:linkname Chat C.chat
|
||||
func Chat(
|
||||
transformer *Transformer, tokenizer *Tokenizer, sampler *Sampler,
|
||||
cliUserPrompt *c.Char, cliSystemPrompt *c.Char, steps c.Int)
|
||||
|
||||
// -----------------------------------------------------------------------------
|
||||
2
c/llama2/llama2/llama2.c
Normal file
2
c/llama2/llama2/llama2.c
Normal file
@@ -0,0 +1,2 @@
|
||||
#define TESTING
|
||||
#include "./run.c"
|
||||
973
c/llama2/llama2/run.c
Normal file
973
c/llama2/llama2/run.c
Normal file
@@ -0,0 +1,973 @@
|
||||
/* Inference for Llama-2 Transformer model in pure C */
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
#include <time.h>
|
||||
#include <math.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#if defined _WIN32
|
||||
#include "win.h"
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#endif
|
||||
// ----------------------------------------------------------------------------
|
||||
// Transformer model
|
||||
|
||||
typedef struct {
|
||||
int dim; // transformer dimension
|
||||
int hidden_dim; // for ffn layers
|
||||
int n_layers; // number of layers
|
||||
int n_heads; // number of query heads
|
||||
int n_kv_heads; // number of key/value heads (can be < query heads because of multiquery)
|
||||
int vocab_size; // vocabulary size, usually 256 (byte-level)
|
||||
int seq_len; // max sequence length
|
||||
} Config;
|
||||
|
||||
typedef struct {
|
||||
// token embedding table
|
||||
float* token_embedding_table; // (vocab_size, dim)
|
||||
// weights for rmsnorms
|
||||
float* rms_att_weight; // (layer, dim) rmsnorm weights
|
||||
float* rms_ffn_weight; // (layer, dim)
|
||||
// weights for matmuls. note dim == n_heads * head_size
|
||||
float* wq; // (layer, dim, n_heads * head_size)
|
||||
float* wk; // (layer, dim, n_kv_heads * head_size)
|
||||
float* wv; // (layer, dim, n_kv_heads * head_size)
|
||||
float* wo; // (layer, n_heads * head_size, dim)
|
||||
// weights for ffn
|
||||
float* w1; // (layer, hidden_dim, dim)
|
||||
float* w2; // (layer, dim, hidden_dim)
|
||||
float* w3; // (layer, hidden_dim, dim)
|
||||
// final rmsnorm
|
||||
float* rms_final_weight; // (dim,)
|
||||
// (optional) classifier weights for the logits, on the last layer
|
||||
float* wcls;
|
||||
} TransformerWeights;
|
||||
|
||||
typedef struct {
|
||||
// current wave of activations
|
||||
float *x; // activation at current time stamp (dim,)
|
||||
float *xb; // same, but inside a residual branch (dim,)
|
||||
float *xb2; // an additional buffer just for convenience (dim,)
|
||||
float *hb; // buffer for hidden dimension in the ffn (hidden_dim,)
|
||||
float *hb2; // buffer for hidden dimension in the ffn (hidden_dim,)
|
||||
float *q; // query (dim,)
|
||||
float *k; // key (dim,)
|
||||
float *v; // value (dim,)
|
||||
float *att; // buffer for scores/attention values (n_heads, seq_len)
|
||||
float *logits; // output logits
|
||||
// kv cache
|
||||
float* key_cache; // (layer, seq_len, dim)
|
||||
float* value_cache; // (layer, seq_len, dim)
|
||||
} RunState;
|
||||
|
||||
typedef struct {
|
||||
Config config; // the hyperparameters of the architecture (the blueprint)
|
||||
TransformerWeights weights; // the weights of the model
|
||||
RunState state; // buffers for the "wave" of activations in the forward pass
|
||||
// some more state needed to properly clean up the memory mapping (sigh)
|
||||
int fd; // file descriptor for memory mapping
|
||||
float* data; // memory mapped data pointer
|
||||
ssize_t file_size; // size of the checkpoint file in bytes
|
||||
} Transformer;
|
||||
|
||||
void malloc_run_state(RunState* s, Config* p) {
|
||||
// we calloc instead of malloc to keep valgrind happy
|
||||
int kv_dim = (p->dim * p->n_kv_heads) / p->n_heads;
|
||||
s->x = calloc(p->dim, sizeof(float));
|
||||
s->xb = calloc(p->dim, sizeof(float));
|
||||
s->xb2 = calloc(p->dim, sizeof(float));
|
||||
s->hb = calloc(p->hidden_dim, sizeof(float));
|
||||
s->hb2 = calloc(p->hidden_dim, sizeof(float));
|
||||
s->q = calloc(p->dim, sizeof(float));
|
||||
s->key_cache = calloc(p->n_layers * p->seq_len * kv_dim, sizeof(float));
|
||||
s->value_cache = calloc(p->n_layers * p->seq_len * kv_dim, sizeof(float));
|
||||
s->att = calloc(p->n_heads * p->seq_len, sizeof(float));
|
||||
s->logits = calloc(p->vocab_size, sizeof(float));
|
||||
// ensure all mallocs went fine
|
||||
if (!s->x || !s->xb || !s->xb2 || !s->hb || !s->hb2 || !s->q
|
||||
|| !s->key_cache || !s->value_cache || !s->att || !s->logits) {
|
||||
fprintf(stderr, "malloc failed!\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void free_run_state(RunState* s) {
|
||||
free(s->x);
|
||||
free(s->xb);
|
||||
free(s->xb2);
|
||||
free(s->hb);
|
||||
free(s->hb2);
|
||||
free(s->q);
|
||||
free(s->att);
|
||||
free(s->logits);
|
||||
free(s->key_cache);
|
||||
free(s->value_cache);
|
||||
}
|
||||
|
||||
void memory_map_weights(TransformerWeights *w, Config* p, float* ptr, int shared_weights) {
|
||||
int head_size = p->dim / p->n_heads;
|
||||
// make sure the multiplications below are done in 64bit to fit the parameter counts of 13B+ models
|
||||
unsigned long long n_layers = p->n_layers;
|
||||
w->token_embedding_table = ptr;
|
||||
ptr += p->vocab_size * p->dim;
|
||||
w->rms_att_weight = ptr;
|
||||
ptr += n_layers * p->dim;
|
||||
w->wq = ptr;
|
||||
ptr += n_layers * p->dim * (p->n_heads * head_size);
|
||||
w->wk = ptr;
|
||||
ptr += n_layers * p->dim * (p->n_kv_heads * head_size);
|
||||
w->wv = ptr;
|
||||
ptr += n_layers * p->dim * (p->n_kv_heads * head_size);
|
||||
w->wo = ptr;
|
||||
ptr += n_layers * (p->n_heads * head_size) * p->dim;
|
||||
w->rms_ffn_weight = ptr;
|
||||
ptr += n_layers * p->dim;
|
||||
w->w1 = ptr;
|
||||
ptr += n_layers * p->dim * p->hidden_dim;
|
||||
w->w2 = ptr;
|
||||
ptr += n_layers * p->hidden_dim * p->dim;
|
||||
w->w3 = ptr;
|
||||
ptr += n_layers * p->dim * p->hidden_dim;
|
||||
w->rms_final_weight = ptr;
|
||||
ptr += p->dim;
|
||||
ptr += p->seq_len * head_size / 2; // skip what used to be freq_cis_real (for RoPE)
|
||||
ptr += p->seq_len * head_size / 2; // skip what used to be freq_cis_imag (for RoPE)
|
||||
w->wcls = shared_weights ? w->token_embedding_table : ptr;
|
||||
}
|
||||
|
||||
void read_checkpoint(char* checkpoint, Config* config, TransformerWeights* weights,
|
||||
int* fd, float** data, ssize_t* file_size) {
|
||||
FILE *file = fopen(checkpoint, "rb");
|
||||
if (!file) { fprintf(stderr, "Couldn't open file %s\n", checkpoint); exit(EXIT_FAILURE); }
|
||||
// read in the config header
|
||||
if (fread(config, sizeof(Config), 1, file) != 1) { exit(EXIT_FAILURE); }
|
||||
// negative vocab size is hacky way of signaling unshared weights. bit yikes.
|
||||
int shared_weights = config->vocab_size > 0 ? 1 : 0;
|
||||
config->vocab_size = abs(config->vocab_size);
|
||||
// figure out the file size
|
||||
fseek(file, 0, SEEK_END); // move file pointer to end of file
|
||||
*file_size = ftell(file); // get the file size, in bytes
|
||||
fclose(file);
|
||||
// memory map the Transformer weights into the data pointer
|
||||
*fd = open(checkpoint, O_RDONLY); // open in read only mode
|
||||
if (*fd == -1) { fprintf(stderr, "open failed!\n"); exit(EXIT_FAILURE); }
|
||||
*data = mmap(NULL, *file_size, PROT_READ, MAP_PRIVATE, *fd, 0);
|
||||
if (*data == MAP_FAILED) { fprintf(stderr, "mmap failed!\n"); exit(EXIT_FAILURE); }
|
||||
float* weights_ptr = *data + sizeof(Config)/sizeof(float);
|
||||
memory_map_weights(weights, config, weights_ptr, shared_weights);
|
||||
}
|
||||
|
||||
void build_transformer(Transformer *t, char* checkpoint_path) {
|
||||
// read in the Config and the Weights from the checkpoint
|
||||
read_checkpoint(checkpoint_path, &t->config, &t->weights, &t->fd, &t->data, &t->file_size);
|
||||
// allocate the RunState buffers
|
||||
malloc_run_state(&t->state, &t->config);
|
||||
}
|
||||
|
||||
void free_transformer(Transformer* t) {
|
||||
// close the memory mapping
|
||||
if (t->data != MAP_FAILED) { munmap(t->data, t->file_size); }
|
||||
if (t->fd != -1) { close(t->fd); }
|
||||
// free the RunState buffers
|
||||
free_run_state(&t->state);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// neural net blocks; the dynamics of the Transformer
|
||||
|
||||
void rmsnorm(float* o, float* x, float* weight, int size) {
|
||||
// calculate sum of squares
|
||||
float ss = 0.0f;
|
||||
for (int j = 0; j < size; j++) {
|
||||
ss += x[j] * x[j];
|
||||
}
|
||||
ss /= size;
|
||||
ss += 1e-5f;
|
||||
ss = 1.0f / sqrtf(ss);
|
||||
// normalize and scale
|
||||
for (int j = 0; j < size; j++) {
|
||||
o[j] = weight[j] * (ss * x[j]);
|
||||
}
|
||||
}
|
||||
|
||||
void softmax(float* x, int size) {
|
||||
// find max value (for numerical stability)
|
||||
float max_val = x[0];
|
||||
for (int i = 1; i < size; i++) {
|
||||
if (x[i] > max_val) {
|
||||
max_val = x[i];
|
||||
}
|
||||
}
|
||||
// exp and sum
|
||||
float sum = 0.0f;
|
||||
for (int i = 0; i < size; i++) {
|
||||
x[i] = expf(x[i] - max_val);
|
||||
sum += x[i];
|
||||
}
|
||||
// normalize
|
||||
for (int i = 0; i < size; i++) {
|
||||
x[i] /= sum;
|
||||
}
|
||||
}
|
||||
|
||||
void matmul(float* xout, float* x, float* w, int n, int d) {
|
||||
// W (d,n) @ x (n,) -> xout (d,)
|
||||
// by far the most amount of time is spent inside this little function
|
||||
int i;
|
||||
#pragma omp parallel for private(i)
|
||||
for (i = 0; i < d; i++) {
|
||||
float val = 0.0f;
|
||||
for (int j = 0; j < n; j++) {
|
||||
val += w[i * n + j] * x[j];
|
||||
}
|
||||
xout[i] = val;
|
||||
}
|
||||
}
|
||||
|
||||
float* forward(Transformer* transformer, int token, int pos) {
|
||||
|
||||
// a few convenience variables
|
||||
Config* p = &transformer->config;
|
||||
TransformerWeights* w = &transformer->weights;
|
||||
RunState* s = &transformer->state;
|
||||
float *x = s->x;
|
||||
int dim = p->dim;
|
||||
int kv_dim = (p->dim * p->n_kv_heads) / p->n_heads;
|
||||
int kv_mul = p->n_heads / p->n_kv_heads; // integer multiplier of the kv sharing in multiquery
|
||||
int hidden_dim = p->hidden_dim;
|
||||
int head_size = dim / p->n_heads;
|
||||
|
||||
// copy the token embedding into x
|
||||
float* content_row = w->token_embedding_table + token * dim;
|
||||
memcpy(x, content_row, dim*sizeof(*x));
|
||||
|
||||
// forward all the layers
|
||||
for(unsigned long long l = 0; l < p->n_layers; l++) {
|
||||
|
||||
// attention rmsnorm
|
||||
rmsnorm(s->xb, x, w->rms_att_weight + l*dim, dim);
|
||||
|
||||
// key and value point to the kv cache
|
||||
int loff = l * p->seq_len * kv_dim; // kv cache layer offset for convenience
|
||||
s->k = s->key_cache + loff + pos * kv_dim;
|
||||
s->v = s->value_cache + loff + pos * kv_dim;
|
||||
|
||||
// qkv matmuls for this position
|
||||
matmul(s->q, s->xb, w->wq + l*dim*dim, dim, dim);
|
||||
matmul(s->k, s->xb, w->wk + l*dim*kv_dim, dim, kv_dim);
|
||||
matmul(s->v, s->xb, w->wv + l*dim*kv_dim, dim, kv_dim);
|
||||
|
||||
// RoPE relative positional encoding: complex-valued rotate q and k in each head
|
||||
for (int i = 0; i < dim; i+=2) {
|
||||
int head_dim = i % head_size;
|
||||
float freq = 1.0f / powf(10000.0f, head_dim / (float)head_size);
|
||||
float val = pos * freq;
|
||||
float fcr = cosf(val);
|
||||
float fci = sinf(val);
|
||||
int rotn = i < kv_dim ? 2 : 1; // how many vectors? 2 = q & k, 1 = q only
|
||||
for (int v = 0; v < rotn; v++) {
|
||||
float* vec = v == 0 ? s->q : s->k; // the vector to rotate (query or key)
|
||||
float v0 = vec[i];
|
||||
float v1 = vec[i+1];
|
||||
vec[i] = v0 * fcr - v1 * fci;
|
||||
vec[i+1] = v0 * fci + v1 * fcr;
|
||||
}
|
||||
}
|
||||
|
||||
// multihead attention. iterate over all heads
|
||||
int h;
|
||||
#pragma omp parallel for private(h)
|
||||
for (h = 0; h < p->n_heads; h++) {
|
||||
// get the query vector for this head
|
||||
float* q = s->q + h * head_size;
|
||||
// attention scores for this head
|
||||
float* att = s->att + h * p->seq_len;
|
||||
// iterate over all timesteps, including the current one
|
||||
for (int t = 0; t <= pos; t++) {
|
||||
// get the key vector for this head and at this timestep
|
||||
float* k = s->key_cache + loff + t * kv_dim + (h / kv_mul) * head_size;
|
||||
// calculate the attention score as the dot product of q and k
|
||||
float score = 0.0f;
|
||||
for (int i = 0; i < head_size; i++) {
|
||||
score += q[i] * k[i];
|
||||
}
|
||||
score /= sqrtf(head_size);
|
||||
// save the score to the attention buffer
|
||||
att[t] = score;
|
||||
}
|
||||
|
||||
// softmax the scores to get attention weights, from 0..pos inclusively
|
||||
softmax(att, pos + 1);
|
||||
|
||||
// weighted sum of the values, store back into xb
|
||||
float* xb = s->xb + h * head_size;
|
||||
memset(xb, 0, head_size * sizeof(float));
|
||||
for (int t = 0; t <= pos; t++) {
|
||||
// get the value vector for this head and at this timestep
|
||||
float* v = s->value_cache + loff + t * kv_dim + (h / kv_mul) * head_size;
|
||||
// get the attention weight for this timestep
|
||||
float a = att[t];
|
||||
// accumulate the weighted value into xb
|
||||
for (int i = 0; i < head_size; i++) {
|
||||
xb[i] += a * v[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// final matmul to get the output of the attention
|
||||
matmul(s->xb2, s->xb, w->wo + l*dim*dim, dim, dim);
|
||||
|
||||
// residual connection back into x
|
||||
for (int i = 0; i < dim; i++) {
|
||||
x[i] += s->xb2[i];
|
||||
}
|
||||
|
||||
// ffn rmsnorm
|
||||
rmsnorm(s->xb, x, w->rms_ffn_weight + l*dim, dim);
|
||||
|
||||
// Now for FFN in PyTorch we have: self.w2(F.silu(self.w1(x)) * self.w3(x))
|
||||
// first calculate self.w1(x) and self.w3(x)
|
||||
matmul(s->hb, s->xb, w->w1 + l*dim*hidden_dim, dim, hidden_dim);
|
||||
matmul(s->hb2, s->xb, w->w3 + l*dim*hidden_dim, dim, hidden_dim);
|
||||
|
||||
// SwiGLU non-linearity
|
||||
for (int i = 0; i < hidden_dim; i++) {
|
||||
float val = s->hb[i];
|
||||
// silu(x)=x*σ(x), where σ(x) is the logistic sigmoid
|
||||
val *= (1.0f / (1.0f + expf(-val)));
|
||||
// elementwise multiply with w3(x)
|
||||
val *= s->hb2[i];
|
||||
s->hb[i] = val;
|
||||
}
|
||||
|
||||
// final matmul to get the output of the ffn
|
||||
matmul(s->xb, s->hb, w->w2 + l*dim*hidden_dim, hidden_dim, dim);
|
||||
|
||||
// residual connection
|
||||
for (int i = 0; i < dim; i++) {
|
||||
x[i] += s->xb[i];
|
||||
}
|
||||
}
|
||||
|
||||
// final rmsnorm
|
||||
rmsnorm(x, x, w->rms_final_weight, dim);
|
||||
|
||||
// classifier into logits
|
||||
matmul(s->logits, x, w->wcls, p->dim, p->vocab_size);
|
||||
return s->logits;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// The Byte Pair Encoding (BPE) Tokenizer that translates strings <-> tokens
|
||||
|
||||
typedef struct {
|
||||
char *str;
|
||||
int id;
|
||||
} TokenIndex;
|
||||
|
||||
typedef struct {
|
||||
char** vocab;
|
||||
float* vocab_scores;
|
||||
TokenIndex *sorted_vocab;
|
||||
int vocab_size;
|
||||
unsigned int max_token_length;
|
||||
unsigned char byte_pieces[512]; // stores all single-byte strings
|
||||
} Tokenizer;
|
||||
|
||||
int compare_tokens(const void *a, const void *b) {
|
||||
return strcmp(((TokenIndex*)a)->str, ((TokenIndex*)b)->str);
|
||||
}
|
||||
|
||||
void build_tokenizer(Tokenizer* t, char* tokenizer_path, int vocab_size) {
|
||||
// i should have written the vocab_size into the tokenizer file... sigh
|
||||
t->vocab_size = vocab_size;
|
||||
// malloc space to hold the scores and the strings
|
||||
t->vocab = (char**)malloc(vocab_size * sizeof(char*));
|
||||
t->vocab_scores = (float*)malloc(vocab_size * sizeof(float));
|
||||
t->sorted_vocab = NULL; // initialized lazily
|
||||
for (int i = 0; i < 256; i++) {
|
||||
t->byte_pieces[i * 2] = (unsigned char)i;
|
||||
t->byte_pieces[i * 2 + 1] = '\0';
|
||||
}
|
||||
// read in the file
|
||||
FILE *file = fopen(tokenizer_path, "rb");
|
||||
if (!file) { fprintf(stderr, "couldn't load %s\n", tokenizer_path); exit(EXIT_FAILURE); }
|
||||
if (fread(&t->max_token_length, sizeof(int), 1, file) != 1) { fprintf(stderr, "failed read\n"); exit(EXIT_FAILURE); }
|
||||
int len;
|
||||
for (int i = 0; i < vocab_size; i++) {
|
||||
if (fread(t->vocab_scores + i, sizeof(float), 1, file) != 1) { fprintf(stderr, "failed read\n"); exit(EXIT_FAILURE);}
|
||||
if (fread(&len, sizeof(int), 1, file) != 1) { fprintf(stderr, "failed read\n"); exit(EXIT_FAILURE); }
|
||||
t->vocab[i] = (char *)malloc(len + 1);
|
||||
if (fread(t->vocab[i], len, 1, file) != 1) { fprintf(stderr, "failed read\n"); exit(EXIT_FAILURE); }
|
||||
t->vocab[i][len] = '\0'; // add the string terminating token
|
||||
}
|
||||
fclose(file);
|
||||
}
|
||||
|
||||
void free_tokenizer(Tokenizer* t) {
|
||||
for (int i = 0; i < t->vocab_size; i++) { free(t->vocab[i]); }
|
||||
free(t->vocab);
|
||||
free(t->vocab_scores);
|
||||
free(t->sorted_vocab);
|
||||
}
|
||||
|
||||
char* decode(Tokenizer* t, int prev_token, int token) {
|
||||
char *piece = t->vocab[token];
|
||||
// following BOS (1) token, sentencepiece decoder strips any leading whitespace (see PR #89)
|
||||
if (prev_token == 1 && piece[0] == ' ') { piece++; }
|
||||
// careful, some tokens designate raw bytes, and look like e.g. '<0x01>'
|
||||
// parse this and convert and return the actual byte
|
||||
unsigned char byte_val;
|
||||
if (sscanf(piece, "<0x%02hhX>", &byte_val) == 1) {
|
||||
piece = (char*)t->byte_pieces + byte_val * 2;
|
||||
}
|
||||
return piece;
|
||||
}
|
||||
|
||||
void safe_printf(char *piece) {
|
||||
// piece might be a raw byte token, and we only want to print printable chars or whitespace
|
||||
// because some of the other bytes can be various control codes, backspace, etc.
|
||||
if (piece == NULL) { return; }
|
||||
if (piece[0] == '\0') { return; }
|
||||
if (piece[1] == '\0') {
|
||||
unsigned char byte_val = piece[0];
|
||||
if (!(isprint(byte_val) || isspace(byte_val))) {
|
||||
return; // bad byte, don't print it
|
||||
}
|
||||
}
|
||||
printf("%s", piece);
|
||||
}
|
||||
|
||||
int str_lookup(char *str, TokenIndex *sorted_vocab, int vocab_size) {
|
||||
// efficiently find the perfect match for str in vocab, return its index or -1 if not found
|
||||
TokenIndex tok = { .str = str }; // acts as the key to search for
|
||||
TokenIndex *res = bsearch(&tok, sorted_vocab, vocab_size, sizeof(TokenIndex), compare_tokens);
|
||||
return res != NULL ? res->id : -1;
|
||||
}
|
||||
|
||||
void encode(Tokenizer* t, char *text, int8_t bos, int8_t eos, int *tokens, int *n_tokens) {
|
||||
// encode the string text (input) into an upper-bound preallocated tokens[] array
|
||||
// bos != 0 means prepend the BOS token (=1), eos != 0 means append the EOS token (=2)
|
||||
if (text == NULL) { fprintf(stderr, "cannot encode NULL text\n"); exit(EXIT_FAILURE); }
|
||||
|
||||
if (t->sorted_vocab == NULL) {
|
||||
// lazily malloc and sort the vocabulary
|
||||
t->sorted_vocab = malloc(t->vocab_size * sizeof(TokenIndex));
|
||||
for (int i = 0; i < t->vocab_size; i++) {
|
||||
t->sorted_vocab[i].str = t->vocab[i];
|
||||
t->sorted_vocab[i].id = i;
|
||||
}
|
||||
qsort(t->sorted_vocab, t->vocab_size, sizeof(TokenIndex), compare_tokens);
|
||||
}
|
||||
|
||||
// create a temporary buffer that will store merge candidates of always two consecutive tokens
|
||||
// *2 for concat, +1 for null terminator +2 for UTF8 (in case max_token_length is 1)
|
||||
char* str_buffer = malloc((t->max_token_length*2 +1 +2) * sizeof(char));
|
||||
size_t str_len = 0;
|
||||
|
||||
// start at 0 tokens
|
||||
*n_tokens = 0;
|
||||
|
||||
// add optional BOS (=1) token, if desired
|
||||
if (bos) tokens[(*n_tokens)++] = 1;
|
||||
|
||||
// add_dummy_prefix is true by default
|
||||
// so prepend a dummy prefix token to the input string, but only if text != ""
|
||||
// TODO: pretty sure this isn't correct in the general case but I don't have the
|
||||
// energy to read more of the sentencepiece code to figure out what it's doing
|
||||
if (text[0] != '\0') {
|
||||
int dummy_prefix = str_lookup(" ", t->sorted_vocab, t->vocab_size);
|
||||
tokens[(*n_tokens)++] = dummy_prefix;
|
||||
}
|
||||
|
||||
// Okay UTF-8 time. This will get messy. Here is the reference from Wikipedia:
|
||||
// Code point ↔ UTF-8 conversion
|
||||
// First code point Last code point Byte 1 Byte 2 Byte 3 Byte 4
|
||||
// U+0000 U+007F 0xxxxxxx
|
||||
// U+0080 U+07FF 110xxxxx 10xxxxxx
|
||||
// U+0800 U+FFFF 1110xxxx 10xxxxxx 10xxxxxx
|
||||
// U+10000 U+10FFFF 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
|
||||
|
||||
// process the raw (UTF-8) byte sequence of the input string
|
||||
for (char *c = text; *c != '\0'; c++) {
|
||||
|
||||
// reset buffer if the current byte is ASCII or a leading byte
|
||||
// 0xC0 is 11000000, so (*c & 0xC0) keeps the first 2 bits and zeros the rest
|
||||
// 0x80 is 10000000
|
||||
// in UTF-8, all continuation bytes start with "10" in first two bits
|
||||
// so in English this is: "if this byte is not a continuation byte"
|
||||
if ((*c & 0xC0) != 0x80) {
|
||||
// this byte must be either a leading byte (11...) or an ASCII char (0x...)
|
||||
// => reset our location, as we're starting a new UTF-8 codepoint
|
||||
str_len = 0;
|
||||
}
|
||||
|
||||
// append the current byte to the buffer
|
||||
str_buffer[str_len++] = *c; // ++ is post-increment, incremented after this line
|
||||
str_buffer[str_len] = '\0';
|
||||
|
||||
// while the next character is a continuation byte, continue appending
|
||||
// but if there are too many of them, just stop to avoid overruning str_buffer size.
|
||||
if ((*(c+1) & 0xC0) == 0x80 && str_len < 4) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// ok c+1 is not a continuation byte, so we've read in a full codepoint
|
||||
int id = str_lookup(str_buffer, t->sorted_vocab, t->vocab_size);
|
||||
|
||||
if (id != -1) {
|
||||
// we found this codepoint in vocab, add it as a token
|
||||
tokens[(*n_tokens)++] = id;
|
||||
} else {
|
||||
// byte_fallback encoding: just encode each byte as a token
|
||||
// +3 is here because the first 3 vocab elements are <unk>, <s>, </s>
|
||||
// so the individual bytes only start at index 3
|
||||
for (int i=0; i < str_len; i++) {
|
||||
tokens[(*n_tokens)++] = (unsigned char)str_buffer[i] + 3;
|
||||
}
|
||||
}
|
||||
str_len = 0; // protect against a sequence of stray UTF8 continuation bytes
|
||||
}
|
||||
|
||||
// merge the best consecutive pair each iteration, according the scores in vocab_scores
|
||||
while (1) {
|
||||
float best_score = -1e10;
|
||||
int best_id = -1;
|
||||
int best_idx = -1;
|
||||
|
||||
for (int i=0; i < (*n_tokens-1); i++) {
|
||||
// check if we can merge the pair (tokens[i], tokens[i+1])
|
||||
sprintf(str_buffer, "%s%s", t->vocab[tokens[i]], t->vocab[tokens[i+1]]);
|
||||
int id = str_lookup(str_buffer, t->sorted_vocab, t->vocab_size);
|
||||
if (id != -1 && t->vocab_scores[id] > best_score) {
|
||||
// this merge pair exists in vocab! record its score and position
|
||||
best_score = t->vocab_scores[id];
|
||||
best_id = id;
|
||||
best_idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (best_idx == -1) {
|
||||
break; // we couldn't find any more pairs to merge, so we're done
|
||||
}
|
||||
|
||||
// merge the consecutive pair (best_idx, best_idx+1) into new token best_id
|
||||
tokens[best_idx] = best_id;
|
||||
// delete token at position best_idx+1, shift the entire sequence back 1
|
||||
for (int i = best_idx+1; i < (*n_tokens-1); i++) {
|
||||
tokens[i] = tokens[i+1];
|
||||
}
|
||||
(*n_tokens)--; // token length decreased
|
||||
}
|
||||
|
||||
// add optional EOS (=2) token, if desired
|
||||
if (eos) tokens[(*n_tokens)++] = 2;
|
||||
|
||||
free(str_buffer);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// The Sampler, which takes logits and returns a sampled token
|
||||
// sampling can be done in a few ways: greedy argmax, sampling, top-p sampling
|
||||
|
||||
typedef struct {
|
||||
float prob;
|
||||
int index;
|
||||
} ProbIndex; // struct used when sorting probabilities during top-p sampling
|
||||
|
||||
typedef struct {
|
||||
int vocab_size;
|
||||
ProbIndex* probindex; // buffer used in top-p sampling
|
||||
float temperature;
|
||||
float topp;
|
||||
unsigned long long rng_state;
|
||||
} Sampler;
|
||||
|
||||
int sample_argmax(float* probabilities, int n) {
|
||||
// return the index that has the highest probability
|
||||
int max_i = 0;
|
||||
float max_p = probabilities[0];
|
||||
for (int i = 1; i < n; i++) {
|
||||
if (probabilities[i] > max_p) {
|
||||
max_i = i;
|
||||
max_p = probabilities[i];
|
||||
}
|
||||
}
|
||||
return max_i;
|
||||
}
|
||||
|
||||
int sample_mult(float* probabilities, int n, float coin) {
|
||||
// sample index from probabilities (they must sum to 1!)
|
||||
// coin is a random number in [0, 1), usually from random_f32()
|
||||
float cdf = 0.0f;
|
||||
for (int i = 0; i < n; i++) {
|
||||
cdf += probabilities[i];
|
||||
if (coin < cdf) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return n - 1; // in case of rounding errors
|
||||
}
|
||||
|
||||
int compare(const void* a, const void* b) {
|
||||
ProbIndex* a_ = (ProbIndex*) a;
|
||||
ProbIndex* b_ = (ProbIndex*) b;
|
||||
if (a_->prob > b_->prob) return -1;
|
||||
if (a_->prob < b_->prob) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sample_topp(float* probabilities, int n, float topp, ProbIndex* probindex, float coin) {
|
||||
// top-p sampling (or "nucleus sampling") samples from the smallest set of
|
||||
// tokens that exceed probability topp. This way we never sample tokens that
|
||||
// have very low probabilities and are less likely to go "off the rails".
|
||||
// coin is a random number in [0, 1), usually from random_f32()
|
||||
|
||||
int n0 = 0;
|
||||
// quicksort indices in descending order of probabilities
|
||||
// values smaller than (1 - topp) / (n - 1) cannot be part of the result
|
||||
// so for efficiency we crop these out as candidates before sorting
|
||||
const float cutoff = (1.0f - topp) / (n - 1);
|
||||
for (int i = 0; i < n; i++) {
|
||||
if (probabilities[i] >= cutoff) {
|
||||
probindex[n0].index = i;
|
||||
probindex[n0].prob = probabilities[i];
|
||||
n0++;
|
||||
}
|
||||
}
|
||||
qsort(probindex, n0, sizeof(ProbIndex), compare);
|
||||
|
||||
// truncate the list where cumulative probability exceeds topp
|
||||
float cumulative_prob = 0.0f;
|
||||
int last_idx = n0 - 1; // in case of rounding errors consider all elements
|
||||
for (int i = 0; i < n0; i++) {
|
||||
cumulative_prob += probindex[i].prob;
|
||||
if (cumulative_prob > topp) {
|
||||
last_idx = i;
|
||||
break; // we've exceeded topp by including last_idx
|
||||
}
|
||||
}
|
||||
|
||||
// sample from the truncated list
|
||||
float r = coin * cumulative_prob;
|
||||
float cdf = 0.0f;
|
||||
for (int i = 0; i <= last_idx; i++) {
|
||||
cdf += probindex[i].prob;
|
||||
if (r < cdf) {
|
||||
return probindex[i].index;
|
||||
}
|
||||
}
|
||||
return probindex[last_idx].index; // in case of rounding errors
|
||||
}
|
||||
|
||||
void build_sampler(Sampler* sampler, int vocab_size, float temperature, float topp, unsigned long long rng_seed) {
|
||||
sampler->vocab_size = vocab_size;
|
||||
sampler->temperature = temperature;
|
||||
sampler->topp = topp;
|
||||
sampler->rng_state = rng_seed;
|
||||
// buffer only used with nucleus sampling; may not need but it's ~small
|
||||
sampler->probindex = malloc(sampler->vocab_size * sizeof(ProbIndex));
|
||||
}
|
||||
|
||||
void free_sampler(Sampler* sampler) {
|
||||
free(sampler->probindex);
|
||||
}
|
||||
|
||||
unsigned int random_u32(unsigned long long *state) {
|
||||
// xorshift rng: https://en.wikipedia.org/wiki/Xorshift#xorshift.2A
|
||||
*state ^= *state >> 12;
|
||||
*state ^= *state << 25;
|
||||
*state ^= *state >> 27;
|
||||
return (*state * 0x2545F4914F6CDD1Dull) >> 32;
|
||||
}
|
||||
float random_f32(unsigned long long *state) { // random float32 in [0,1)
|
||||
return (random_u32(state) >> 8) / 16777216.0f;
|
||||
}
|
||||
|
||||
int sample(Sampler* sampler, float* logits) {
|
||||
// sample the token given the logits and some hyperparameters
|
||||
int next;
|
||||
if (sampler->temperature == 0.0f) {
|
||||
// greedy argmax sampling: take the token with the highest probability
|
||||
next = sample_argmax(logits, sampler->vocab_size);
|
||||
} else {
|
||||
// apply the temperature to the logits
|
||||
for (int q=0; q<sampler->vocab_size; q++) { logits[q] /= sampler->temperature; }
|
||||
// apply softmax to the logits to get the probabilities for next token
|
||||
softmax(logits, sampler->vocab_size);
|
||||
// flip a (float) coin (this is our source of entropy for sampling)
|
||||
float coin = random_f32(&sampler->rng_state);
|
||||
// we sample from this distribution to get the next token
|
||||
if (sampler->topp <= 0 || sampler->topp >= 1) {
|
||||
// simply sample from the predicted probability distribution
|
||||
next = sample_mult(logits, sampler->vocab_size, coin);
|
||||
} else {
|
||||
// top-p (nucleus) sampling, clamping the least likely tokens to zero
|
||||
next = sample_topp(logits, sampler->vocab_size, sampler->topp, sampler->probindex, coin);
|
||||
}
|
||||
}
|
||||
return next;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// utilities: time
|
||||
|
||||
long time_in_ms() {
|
||||
// return time in milliseconds, for benchmarking the model speed
|
||||
struct timespec time;
|
||||
clock_gettime(CLOCK_REALTIME, &time);
|
||||
return time.tv_sec * 1000 + time.tv_nsec / 1000000;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// generation loop
|
||||
|
||||
void generate(Transformer *transformer, Tokenizer *tokenizer, Sampler *sampler, char *prompt, int steps) {
|
||||
char *empty_prompt = "";
|
||||
if (prompt == NULL) { prompt = empty_prompt; }
|
||||
|
||||
// encode the (string) prompt into tokens sequence
|
||||
int num_prompt_tokens = 0;
|
||||
int* prompt_tokens = (int*)malloc((strlen(prompt)+3) * sizeof(int)); // +3 for '\0', ?BOS, ?EOS
|
||||
encode(tokenizer, prompt, 1, 0, prompt_tokens, &num_prompt_tokens);
|
||||
if (num_prompt_tokens < 1) {
|
||||
fprintf(stderr, "something is wrong, expected at least 1 prompt token\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
// start the main loop
|
||||
long start = 0; // used to time our code, only initialized after first iteration
|
||||
int next; // will store the next token in the sequence
|
||||
int token = prompt_tokens[0]; // kick off with the first token in the prompt
|
||||
int pos = 0; // position in the sequence
|
||||
while (pos < steps) {
|
||||
|
||||
// forward the transformer to get logits for the next token
|
||||
float* logits = forward(transformer, token, pos);
|
||||
|
||||
// advance the state machine
|
||||
if (pos < num_prompt_tokens - 1) {
|
||||
// if we are still processing the input prompt, force the next prompt token
|
||||
next = prompt_tokens[pos + 1];
|
||||
} else {
|
||||
// otherwise sample the next token from the logits
|
||||
next = sample(sampler, logits);
|
||||
}
|
||||
pos++;
|
||||
|
||||
// data-dependent terminating condition: the BOS (=1) token delimits sequences
|
||||
if (next == 1) { break; }
|
||||
|
||||
// print the token as string, decode it with the Tokenizer object
|
||||
char* piece = decode(tokenizer, token, next);
|
||||
safe_printf(piece); // same as printf("%s", piece), but skips "unsafe" bytes
|
||||
fflush(stdout);
|
||||
token = next;
|
||||
|
||||
// init the timer here because the first iteration can be slower
|
||||
if (start == 0) { start = time_in_ms(); }
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
// report achieved tok/s (pos-1 because the timer starts after first iteration)
|
||||
if (pos > 1) {
|
||||
long end = time_in_ms();
|
||||
fprintf(stderr, "achieved tok/s: %f\n", (pos-1) / (double)(end-start)*1000);
|
||||
}
|
||||
|
||||
free(prompt_tokens);
|
||||
}
|
||||
|
||||
void read_stdin(const char* guide, char* buffer, size_t bufsize) {
|
||||
// read a line from stdin, up to but not including \n
|
||||
printf("%s", guide);
|
||||
if (fgets(buffer, bufsize, stdin) != NULL) {
|
||||
size_t len = strlen(buffer);
|
||||
if (len > 0 && buffer[len - 1] == '\n') {
|
||||
buffer[len - 1] = '\0'; // strip newline
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// chat loop
|
||||
// I manually inspected the tokens for a few chat conversations compared to
|
||||
// python reference and that seemed ok, but this was not thoroughly tested and
|
||||
// is not safely implemented, it's more a proof of concept atm.
|
||||
|
||||
void chat(Transformer *transformer, Tokenizer *tokenizer, Sampler *sampler,
|
||||
char *cli_user_prompt, char *cli_system_prompt, int steps) {
|
||||
|
||||
// buffers for reading the system prompt and user prompt from stdin
|
||||
// you'll notice they are soomewhat haphazardly and unsafely set atm
|
||||
char system_prompt[512];
|
||||
char user_prompt[512];
|
||||
char rendered_prompt[1152];
|
||||
int num_prompt_tokens = 0;
|
||||
int* prompt_tokens = (int*)malloc(1152 * sizeof(int));
|
||||
int user_idx;
|
||||
|
||||
// start the main loop
|
||||
int8_t user_turn = 1; // user starts
|
||||
int next; // will store the next token in the sequence
|
||||
int token; // stores the current token to feed into the transformer
|
||||
int prev_token;
|
||||
int pos = 0; // position in the sequence
|
||||
while (pos < steps) {
|
||||
|
||||
// when it is the user's turn to contribute tokens to the dialog...
|
||||
if (user_turn) {
|
||||
// get the (optional) system prompt at position 0
|
||||
if (pos == 0) {
|
||||
// at position 0, the user can also contribute a system prompt
|
||||
if (cli_system_prompt == NULL) {
|
||||
// system prompt was not passed in, attempt to get it from stdin
|
||||
read_stdin("Enter system prompt (optional): ", system_prompt, sizeof(system_prompt));
|
||||
} else {
|
||||
// system prompt was passed in, use it
|
||||
strcpy(system_prompt, cli_system_prompt);
|
||||
}
|
||||
}
|
||||
// get the user prompt
|
||||
if (pos == 0 && cli_user_prompt != NULL) {
|
||||
// user prompt for position 0 was passed in, use it
|
||||
strcpy(user_prompt, cli_user_prompt);
|
||||
} else {
|
||||
// otherwise get user prompt from stdin
|
||||
read_stdin("User: ", user_prompt, sizeof(user_prompt));
|
||||
}
|
||||
// render user/system prompts into the Llama 2 Chat schema
|
||||
if (pos == 0 && system_prompt[0] != '\0') {
|
||||
char system_template[] = "[INST] <<SYS>>\n%s\n<</SYS>>\n\n%s [/INST]";
|
||||
sprintf(rendered_prompt, system_template, system_prompt, user_prompt);
|
||||
} else {
|
||||
char user_template[] = "[INST] %s [/INST]";
|
||||
sprintf(rendered_prompt, user_template, user_prompt);
|
||||
}
|
||||
// encode the rendered prompt into tokens
|
||||
encode(tokenizer, rendered_prompt, 1, 0, prompt_tokens, &num_prompt_tokens);
|
||||
user_idx = 0; // reset the user index
|
||||
user_turn = 0;
|
||||
printf("Assistant: ");
|
||||
}
|
||||
|
||||
// determine the token to pass into the transformer next
|
||||
if (user_idx < num_prompt_tokens) {
|
||||
// if we are still processing the input prompt, force the next prompt token
|
||||
token = prompt_tokens[user_idx++];
|
||||
} else {
|
||||
// otherwise use the next token sampled from previous turn
|
||||
token = next;
|
||||
}
|
||||
// EOS (=2) token ends the Assistant turn
|
||||
if (token == 2) { user_turn = 1; }
|
||||
|
||||
// forward the transformer to get logits for the next token
|
||||
float* logits = forward(transformer, token, pos);
|
||||
next = sample(sampler, logits);
|
||||
pos++;
|
||||
|
||||
if (user_idx >= num_prompt_tokens && next != 2) {
|
||||
// the Assistant is responding, so print its output
|
||||
char* piece = decode(tokenizer, token, next);
|
||||
safe_printf(piece); // same as printf("%s", piece), but skips "unsafe" bytes
|
||||
fflush(stdout);
|
||||
}
|
||||
if (next == 2) { printf("\n"); }
|
||||
}
|
||||
printf("\n");
|
||||
free(prompt_tokens);
|
||||
}
|
||||
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// CLI, include only if not testing
|
||||
#ifndef TESTING
|
||||
|
||||
void error_usage() {
|
||||
fprintf(stderr, "Usage: run <checkpoint> [options]\n");
|
||||
fprintf(stderr, "Example: run model.bin -n 256 -i \"Once upon a time\"\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr, " -t <float> temperature in [0,inf], default 1.0\n");
|
||||
fprintf(stderr, " -p <float> p value in top-p (nucleus) sampling in [0,1] default 0.9\n");
|
||||
fprintf(stderr, " -s <int> random seed, default time(NULL)\n");
|
||||
fprintf(stderr, " -n <int> number of steps to run for, default 256. 0 = max_seq_len\n");
|
||||
fprintf(stderr, " -i <string> input prompt\n");
|
||||
fprintf(stderr, " -z <string> optional path to custom tokenizer\n");
|
||||
fprintf(stderr, " -m <string> mode: generate|chat, default: generate\n");
|
||||
fprintf(stderr, " -y <string> (optional) system prompt in chat mode\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
|
||||
// default parameters
|
||||
char *checkpoint_path = NULL; // e.g. out/model.bin
|
||||
char *tokenizer_path = "tokenizer.bin";
|
||||
float temperature = 1.0f; // 0.0 = greedy deterministic. 1.0 = original. don't set higher
|
||||
float topp = 0.9f; // top-p in nucleus sampling. 1.0 = off. 0.9 works well, but slower
|
||||
int steps = 256; // number of steps to run for
|
||||
char *prompt = NULL; // prompt string
|
||||
unsigned long long rng_seed = 0; // seed rng with time by default
|
||||
char *mode = "generate"; // generate|chat
|
||||
char *system_prompt = NULL; // the (optional) system prompt to use in chat mode
|
||||
|
||||
// poor man's C argparse so we can override the defaults above from the command line
|
||||
if (argc >= 2) { checkpoint_path = argv[1]; } else { error_usage(); }
|
||||
for (int i = 2; i < argc; i+=2) {
|
||||
// do some basic validation
|
||||
if (i + 1 >= argc) { error_usage(); } // must have arg after flag
|
||||
if (argv[i][0] != '-') { error_usage(); } // must start with dash
|
||||
if (strlen(argv[i]) != 2) { error_usage(); } // must be -x (one dash, one letter)
|
||||
// read in the args
|
||||
if (argv[i][1] == 't') { temperature = atof(argv[i + 1]); }
|
||||
else if (argv[i][1] == 'p') { topp = atof(argv[i + 1]); }
|
||||
else if (argv[i][1] == 's') { rng_seed = atoi(argv[i + 1]); }
|
||||
else if (argv[i][1] == 'n') { steps = atoi(argv[i + 1]); }
|
||||
else if (argv[i][1] == 'i') { prompt = argv[i + 1]; }
|
||||
else if (argv[i][1] == 'z') { tokenizer_path = argv[i + 1]; }
|
||||
else if (argv[i][1] == 'm') { mode = argv[i + 1]; }
|
||||
else if (argv[i][1] == 'y') { system_prompt = argv[i + 1]; }
|
||||
else { error_usage(); }
|
||||
}
|
||||
|
||||
// parameter validation/overrides
|
||||
if (rng_seed <= 0) rng_seed = (unsigned int)time(NULL);
|
||||
if (temperature < 0.0) temperature = 0.0;
|
||||
if (topp < 0.0 || 1.0 < topp) topp = 0.9;
|
||||
if (steps < 0) steps = 0;
|
||||
|
||||
// build the Transformer via the model .bin file
|
||||
Transformer transformer;
|
||||
build_transformer(&transformer, checkpoint_path);
|
||||
if (steps == 0 || steps > transformer.config.seq_len) steps = transformer.config.seq_len; // override to ~max length
|
||||
|
||||
// build the Tokenizer via the tokenizer .bin file
|
||||
Tokenizer tokenizer;
|
||||
build_tokenizer(&tokenizer, tokenizer_path, transformer.config.vocab_size);
|
||||
|
||||
// build the Sampler
|
||||
Sampler sampler;
|
||||
build_sampler(&sampler, transformer.config.vocab_size, temperature, topp, rng_seed);
|
||||
|
||||
// run!
|
||||
if (strcmp(mode, "generate") == 0) {
|
||||
generate(&transformer, &tokenizer, &sampler, prompt, steps);
|
||||
} else if (strcmp(mode, "chat") == 0) {
|
||||
chat(&transformer, &tokenizer, &sampler, prompt, system_prompt, steps);
|
||||
} else {
|
||||
fprintf(stderr, "unknown mode: %s\n", mode);
|
||||
error_usage();
|
||||
}
|
||||
|
||||
// memory and file handles cleanup
|
||||
free_sampler(&sampler);
|
||||
free_tokenizer(&tokenizer);
|
||||
free_transformer(&transformer);
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
60
c/lua/_demo/coroutine/coroutine.go
Normal file
60
c/lua/_demo/coroutine/coroutine.go
Normal file
@@ -0,0 +1,60 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func coroutineFunc(L *lua.State) {
|
||||
L.Loadstring(c.Str(`
|
||||
function coro_func()
|
||||
for i = 1, 5 do
|
||||
coroutine.yield(i)
|
||||
end
|
||||
end
|
||||
`))
|
||||
L.Pcall(0, 0, 0)
|
||||
L.Getglobal(c.Str("coro_func"))
|
||||
}
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
|
||||
coroutineFunc(L) // Load and get the coroutine function
|
||||
|
||||
co := L.Newthread() // Create a new coroutine/thread
|
||||
L.Pushvalue(-2) // Move the function to the top of the stack
|
||||
L.Xmove(co, 1) // Move the function to the new coroutine
|
||||
|
||||
var nres c.Int
|
||||
var status c.Int
|
||||
|
||||
c.Printf(c.Str("Resuming coroutine...\n"))
|
||||
// Resume coroutine and handle yields
|
||||
for {
|
||||
status = co.Resume(nil, 0, &nres)
|
||||
c.Printf(c.Str("Resuming coroutine %d...\n"), status)
|
||||
if status == lua.YIELD {
|
||||
yieldValue := co.Tointeger(-1)
|
||||
c.Printf(c.Str("Yield value: %d\n"), yieldValue)
|
||||
co.Pop(1) // Clean up the stack
|
||||
|
||||
// Check if the coroutine is yieldable
|
||||
if co.Isyieldable() != 0 {
|
||||
c.Printf(c.Str("Coroutine is yieldable.\n"))
|
||||
} else {
|
||||
c.Printf(c.Str("Coroutine is not yieldable.\n"))
|
||||
}
|
||||
|
||||
} else {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Check the final status of the coroutine
|
||||
finalStatus := co.Status()
|
||||
c.Printf(c.Str("Final status of coroutine: %d\n"), finalStatus)
|
||||
}
|
||||
21
c/lua/_demo/error/error.go
Normal file
21
c/lua/_demo/error/error.go
Normal file
@@ -0,0 +1,21 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
L.Openlibs()
|
||||
if res := L.Loadstring(c.Str("function doubleNumber(x) ! return x * 2 end")); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
error: [string "function doubleNumber(x) ! return x * 2 end"]:1: unexpected symbol near '!'
|
||||
*/
|
||||
32
c/lua/_demo/funccall-concat/funccall.go
Normal file
32
c/lua/_demo/funccall-concat/funccall.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
_ "unsafe"
|
||||
|
||||
"github.com/goplus/llgo/c"
|
||||
"github.com/goplus/llgo/c/lua"
|
||||
)
|
||||
|
||||
func main() {
|
||||
L := lua.Newstate()
|
||||
defer L.Close()
|
||||
|
||||
L.Openlibs()
|
||||
if res := L.Dostring(c.Str("function combineParams(num, str) return 'Result: ' .. str .. ' ' .. num end")); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
L.Getglobal(c.Str("combineParams"))
|
||||
L.Pushnumber(3.14159)
|
||||
L.Pushstring(c.Str("Hello, World!"))
|
||||
if res := L.Pcall(2, 1, 0); res != lua.OK {
|
||||
c.Printf(c.Str("error: %s\n"), L.Tostring(-1))
|
||||
}
|
||||
if res := L.Isstring(-1); res != 0 {
|
||||
result := L.Tostring(-1)
|
||||
c.Printf(result)
|
||||
}
|
||||
}
|
||||
|
||||
/* Expected output:
|
||||
Result: Hello, World! 3.14159
|
||||
*/
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user