mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-05 11:11:37 -07:00
Compare commits
321 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| fcc920ed39 | |||
| 4e70256109 | |||
| 2e4d6d2577 | |||
| 51ae21a029 | |||
| f59846377d | |||
| 8e8eb9e5cd | |||
| 88b578ca11 | |||
| 4cb16db4e9 | |||
| 338d483682 | |||
| 0ce59a9e2b | |||
| 8d43cc840a | |||
| 9ae1bfb69d | |||
| 6ec7284467 | |||
| 0ccc570ef2 | |||
| a3bb7d3028 | |||
| c45ca1bfcc | |||
| 94edf89b20 | |||
| 8d6ce0b693 | |||
| ccf4b48865 | |||
| 96eae94103 | |||
| db8b2e69dd | |||
| 82821580c7 | |||
| d23d7cf0f2 | |||
| 450a602230 | |||
| 36764779cf | |||
| 97595c4b50 | |||
| ea9fe397e5 | |||
| c482432966 | |||
| 55176e52fc | |||
| 4eb08bb096 | |||
| 881ef69063 | |||
| 761a19689d | |||
| f438153b81 | |||
| 117c0cceb1 | |||
| c949e404c3 | |||
| 3d2a6c5895 | |||
| 8f4ffbe1da | |||
| 8f3b6738ff | |||
| d50c6d72db | |||
| 15c5e92d63 | |||
| 041c7c8284 | |||
| f040ef41cb | |||
| 91ab184175 | |||
| 48a64a2c88 | |||
| 7f3795a231 | |||
| eb1d00ced6 | |||
| f41c91d36b | |||
| 6909e0d774 | |||
| d52921edd4 | |||
| dcca40033e | |||
| fed65742df | |||
| b918acd871 | |||
| a046c41c7c | |||
| 2513403014 | |||
| 4a8564aff7 | |||
| edb23db2ae | |||
| 0b01cfd853 | |||
| 0d059aa797 | |||
| 65c0255e7e | |||
| b289a27c4e | |||
| d085283f20 | |||
| b6ca10cd5e | |||
| 7416f72565 | |||
| b51be71a6f | |||
| e488cf4601 | |||
| 5d397804f7 | |||
| a5a7226885 | |||
| 2dca39b557 | |||
| b55fa268bf | |||
| c819c350d6 | |||
| d55248ab0f | |||
| 68b2d4b9e2 | |||
| 54f02f59db | |||
| 64047cbf05 | |||
| b0619980b2 | |||
| 9aa9429135 | |||
| 518f30e523 | |||
| 868aa4c14a | |||
| 1ab90de493 | |||
| 1064bcd060 | |||
| 1e21125527 | |||
| 4a8c37dd52 | |||
| 3b22c6620c | |||
| 402a165b60 | |||
| 34f9170189 | |||
| 38136e15fc | |||
| e97bf2ef35 | |||
| d6c54148d9 | |||
| cbe3791b42 | |||
| b470ceb470 | |||
| c15db05199 | |||
| 9428f792ed | |||
| 520ff731de | |||
| e9cfe698ba | |||
| 5fa66ac6a8 | |||
| 320062157f | |||
| d7d6608142 | |||
| 7f2ef2ac67 | |||
| 7124d541a1 | |||
| 3c7e45a46f | |||
| 6ec014e980 | |||
| 9b47a5eddb | |||
| 3e8c63ad31 | |||
| 15469758de | |||
| 86511d44e4 | |||
| fd4633eb25 | |||
| b0756f9e29 | |||
| c3ff1e9591 | |||
| dd3fac7523 | |||
| 13029d06b2 | |||
| 68173f4bc7 | |||
| c979c2fafa | |||
| 658435f1b9 | |||
| 3935957979 | |||
| a36640bcfc | |||
| 171d5b4012 | |||
| 1cc893f21c | |||
| 6ff2db47b4 | |||
| a11b6a9e5f | |||
| 978568684c | |||
| e8e7d3ea31 | |||
| c03cc21908 | |||
| 8ef406324b | |||
| 23d0c52bf4 | |||
| 5eee8077dd | |||
| 029cb6581b | |||
| 025e87d974 | |||
| 213a0499a1 | |||
| 1517f1d779 | |||
| 50a2493fd3 | |||
| b455ccd261 | |||
| a58650728e | |||
| b22ddb1453 | |||
| cb7dd12222 | |||
| 0484bdbb7e | |||
| 8f39c45e9b | |||
| 944396128b | |||
| bbb2164e38 | |||
| be23d83fc8 | |||
| 291ea33939 | |||
| 9455918eec | |||
| 8a99b8af3e | |||
| 12e42d92d3 | |||
| faa735d0c7 | |||
| d4e18109da | |||
| d06a0e7093 | |||
| b3a55b8b6f | |||
| ec69101101 | |||
| 17fa8cb6ef | |||
| 855ebceadc | |||
| 2720e98127 | |||
| bb80c1b059 | |||
| 85e390deba | |||
| dc317c8cd8 | |||
| 774fea1e63 | |||
| 485c606672 | |||
| 3dee3205b2 | |||
| c7a704d345 | |||
| 0fb3032b73 | |||
| 69934c3b0b | |||
| 7380b7e61b | |||
| 747a11a954 | |||
| 252be0fb41 | |||
| 600f2b7284 | |||
| 670274ad8f | |||
| e10fe91eba | |||
| fd62ee14cd | |||
| 8ece92f1f6 | |||
| 69b075782b | |||
| 6bd3a9d422 | |||
| bc9ee8e1a4 | |||
| d36c3c2590 | |||
| 52b319dbfd | |||
| 318d92f9a8 | |||
| 7ffffeeccc | |||
| f16d8e77b3 | |||
| 5b335bb88c | |||
| df2767311f | |||
| 09c26e6be0 | |||
| d2ec2d1606 | |||
| 0d87b2e8db | |||
| 1568971732 | |||
| 0e040be941 | |||
| 9737b65d9c | |||
| ad52003077 | |||
| c386509112 | |||
| c293f5b7eb | |||
| fa562ec5d6 | |||
| 529383f5b1 | |||
| f01cff7ff0 | |||
| 015fe924b8 | |||
| a5ce8a8c0b | |||
| bfdcf900ef | |||
| 54f89dd84b | |||
| da479c7628 | |||
| 3c90a05957 | |||
| d16ddf7926 | |||
| 5c519f0e8d | |||
| 74e6d9144e | |||
| 20d451396d | |||
| 60d0390ef8 | |||
| 782f1b4718 | |||
| 85f0a1067c | |||
| c08ff891ad | |||
| 168cec1e9d | |||
| 28fb35f2f7 | |||
| c1384afe2f | |||
| 547c7bce1b | |||
| 0bb93d40d3 | |||
| 27ba1d596c | |||
| 98e5523f2f | |||
| 223b66f422 | |||
| 04a4dbcdaf | |||
| ef9e31cb31 | |||
| e019673a18 | |||
| 5f27f2dd7f | |||
| cfccf73cdd | |||
| 465d003b1e | |||
| 1d6f7680a1 | |||
| 5d0f9c428a | |||
| d904ae5191 | |||
| 8a822bdd9a | |||
| d1a3842e39 | |||
| 00823ca88c | |||
| ffa14c3aad | |||
| 41b32f0da4 | |||
| c53b2198a8 | |||
| 9b278db993 | |||
| e98f1a28e6 | |||
| c8f05b7c0c | |||
| b00c4a6a8f | |||
| 84e1fb2cee | |||
| b983ac548c | |||
| fb562ea708 | |||
| cdeeeafc3f | |||
| b9a2426e57 | |||
| 81037b3091 | |||
| fc3c76f946 | |||
| 3fa971a510 | |||
| 63a0395a79 | |||
| 191223bb3c | |||
| 6f0bad816e | |||
| 94af3c2887 | |||
| e5d0417a6c | |||
| c02bda2427 | |||
| 385d2a143c | |||
| 67c1b364c4 | |||
| f029b4beb1 | |||
| 3040361fac | |||
| 44caa96d50 | |||
| 1bea0f3772 | |||
| eb0775ad53 | |||
| 8fc9566a83 | |||
| 134c7db4d2 | |||
| a0e3a99dd1 | |||
| 0edda2bea7 | |||
| ff7f139fd7 | |||
| 86a606e716 | |||
| 1e97588e7b | |||
| 3ccc0b5aa6 | |||
| 5464a605b1 | |||
| 5519749aa4 | |||
| 4a70265bfb | |||
| de0d860880 | |||
| a13e2f4578 | |||
| 01b508f182 | |||
| 2a8fa8612d | |||
| e27046098b | |||
| ca8b148fdc | |||
| c1f5be24e2 | |||
| 6cdec65ca1 | |||
| 967afd8bbb | |||
| 0ae1812f90 | |||
| eb5523d5d3 | |||
| 3f4bbbec29 | |||
| 70bd220f34 | |||
| bd3596f012 | |||
| 66ce990e0b | |||
| 690666537c | |||
| 056ba1ed13 | |||
| 93a1f2bf61 | |||
| ac5f5a33e9 | |||
| 0829ac30f7 | |||
| 9d50a04905 | |||
| 1ca7da6914 | |||
| 56e050fbc9 | |||
| 70e48e39a4 | |||
| 2b0c04f27e | |||
| 1ddbe16d28 | |||
| 09c1128d9e | |||
| 588c52a854 | |||
| 86ec3bcb44 | |||
| 9fc606de48 | |||
| 7fbee88061 | |||
| b3be2cdf9d | |||
| ff6b76986a | |||
| 5c3624eb86 | |||
| 144e357fd2 | |||
| be22f0d1e1 | |||
| 34a048f7da | |||
| ffe953b43d | |||
| b8eacfc7b6 | |||
| f8452bf1fc | |||
| 20943a81c1 | |||
| 1c4e75e83f | |||
| 9cb9964c2d | |||
| 1f8f94276e | |||
| 0d7c89e84a | |||
| a5bdb4a8e8 | |||
| d88b052d2d | |||
| 615eccb6d1 | |||
| d3c65b6ba5 | |||
| 90415e4a6e | |||
| 7352c312e0 | |||
| 0befadde1d | |||
| aef8b25a8e | |||
| ae81117f70 | |||
| b7b9a016d3 | |||
| 708a1b0cd3 | |||
| 7ab591667a | |||
| 0a0db23b17 |
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Close Stale Issues
|
||||
uses: actions/stale@v4.1.0
|
||||
uses: actions/stale@v7.0.0
|
||||
with:
|
||||
# stale-issue-message: |
|
||||
# Hello!
|
||||
@@ -36,7 +36,7 @@ jobs:
|
||||
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
|
||||
|
||||
days-before-stale: 120
|
||||
days-before-close: 30
|
||||
days-before-close: -1
|
||||
exempt-draft-pr: true
|
||||
ascending: true
|
||||
operations-per-run: 1000
|
||||
|
||||
@@ -62,12 +62,14 @@ if %release_mode% EQU 0 ( rem Debug
|
||||
set compiler_warnings= ^
|
||||
-W4 -WX ^
|
||||
-wd4100 -wd4101 -wd4127 -wd4146 ^
|
||||
-wd4505 ^
|
||||
-wd4456 -wd4457
|
||||
|
||||
set compiler_includes= ^
|
||||
/Isrc\
|
||||
set libs= ^
|
||||
kernel32.lib ^
|
||||
Synchronization.lib ^
|
||||
bin\llvm\windows\LLVM-C.lib
|
||||
|
||||
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||
@@ -94,4 +96,4 @@ if %release_mode% EQU 0 odin run examples/demo
|
||||
|
||||
del *.obj > NUL 2> NUL
|
||||
|
||||
:end_of_build
|
||||
:end_of_build
|
||||
|
||||
+1
-1
@@ -50,7 +50,7 @@ config_darwin() {
|
||||
panic "Requirement: llvm-config must be base version smaller than 15"
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -liconv -ldl"
|
||||
LDFLAGS="$LDFLAGS -liconv -ldl -framework System"
|
||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||
}
|
||||
|
||||
@@ -108,7 +108,7 @@ when ODIN_OS == .Linux {
|
||||
cnd_destroy :: proc(cond: ^cnd_t) ---
|
||||
cnd_init :: proc(cond: ^cnd_t) -> int ---
|
||||
cnd_signal :: proc(cond: ^cnd_t) -> int ---
|
||||
cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---
|
||||
cnd_timedwait :: proc(cond: ^cnd_t, mtx: ^mtx_t, ts: ^timespec) -> int ---
|
||||
cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
|
||||
|
||||
// 7.26.4 Mutex functions
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
package container_small_array
|
||||
|
||||
import "core:builtin"
|
||||
import "core:runtime"
|
||||
_ :: runtime
|
||||
|
||||
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
||||
data: [N]T,
|
||||
@@ -32,6 +34,20 @@ get_ptr :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int) -> ^T {
|
||||
return &a.data[index]
|
||||
}
|
||||
|
||||
get_safe :: proc(a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check {
|
||||
if index < 0 || index >= a.len {
|
||||
return {}, false
|
||||
}
|
||||
return a.data[index], true
|
||||
}
|
||||
|
||||
get_ptr_safe :: proc(a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check {
|
||||
if index < 0 || index >= a.len {
|
||||
return {}, false
|
||||
}
|
||||
return &a.data[index], true
|
||||
}
|
||||
|
||||
set :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, item: T) {
|
||||
a.data[index] = item
|
||||
}
|
||||
@@ -93,7 +109,7 @@ pop_front_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> (item: T, o
|
||||
copy(s[:], s[1:])
|
||||
a.len -= 1
|
||||
ok = true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -102,6 +118,23 @@ consume :: proc "odin" (a: ^$A/Small_Array($N, $T), count: int, loc := #caller_l
|
||||
a.len -= count
|
||||
}
|
||||
|
||||
ordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check {
|
||||
runtime.bounds_check_error_loc(loc, index, a.len)
|
||||
if index+1 < a.len {
|
||||
copy(a.data[index:], a.data[index+1:])
|
||||
}
|
||||
a.len -= 1
|
||||
}
|
||||
|
||||
unordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check {
|
||||
runtime.bounds_check_error_loc(loc, index, a.len)
|
||||
n := a.len-1
|
||||
if index != n {
|
||||
a.data[index] = a.data[n]
|
||||
}
|
||||
a.len -= 1
|
||||
}
|
||||
|
||||
clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) {
|
||||
resize(a, 0)
|
||||
}
|
||||
@@ -111,6 +144,18 @@ push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) {
|
||||
a.len += n
|
||||
}
|
||||
|
||||
inject_at :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T, index: int) -> bool #no_bounds_check {
|
||||
if a.len < cap(a^) && index >= 0 && index <= len(a^) {
|
||||
a.len += 1
|
||||
for i := a.len - 1; i >= index + 1; i -= 1 {
|
||||
a.data[i] = a.data[i - 1]
|
||||
}
|
||||
a.data[index] = item
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
append_elem :: push_back
|
||||
append_elems :: push_back_elems
|
||||
push :: proc{push_back, push_back_elems}
|
||||
|
||||
@@ -262,10 +262,14 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
|
||||
}
|
||||
map_cap := uintptr(runtime.map_cap(m^))
|
||||
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
|
||||
|
||||
i := 0
|
||||
for bucket_index in 0..<map_cap {
|
||||
if !runtime.map_hash_is_valid(hs[bucket_index]) {
|
||||
continue
|
||||
}
|
||||
opt_write_iteration(w, opt, i) or_return
|
||||
i += 1
|
||||
|
||||
key := rawptr(runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index))
|
||||
value := rawptr(runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index))
|
||||
|
||||
+23
-74
@@ -547,7 +547,7 @@ _parse_int :: proc(s: string, offset: int) -> (result: int, new_offset: int, ok:
|
||||
is_digit :: #force_inline proc(r: byte) -> bool { return '0' <= r && r <= '9' }
|
||||
|
||||
new_offset = offset
|
||||
for new_offset <= len(s) {
|
||||
for new_offset < len(s) {
|
||||
c := s[new_offset]
|
||||
if !is_digit(c) {
|
||||
break
|
||||
@@ -678,7 +678,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
|
||||
}
|
||||
} else if fi.zero && fi.width_set {
|
||||
prec = fi.width
|
||||
if neg || fi.plus || fi.space {
|
||||
if neg || fi.plus {
|
||||
// There needs to be space for the "sign"
|
||||
prec -= 1
|
||||
}
|
||||
@@ -697,7 +697,6 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
|
||||
flags: strconv.Int_Flags
|
||||
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
||||
if fi.plus { flags |= {.Plus} }
|
||||
if fi.space { flags |= {.Space} }
|
||||
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||
|
||||
if fi.hash && fi.zero && fi.indent == 0 {
|
||||
@@ -744,7 +743,7 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
|
||||
}
|
||||
} else if fi.zero && fi.width_set {
|
||||
prec = fi.width
|
||||
if neg || fi.plus || fi.space {
|
||||
if neg || fi.plus {
|
||||
// There needs to be space for the "sign"
|
||||
prec -= 1
|
||||
}
|
||||
@@ -763,7 +762,6 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
|
||||
flags: strconv.Int_Flags
|
||||
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
||||
if fi.plus { flags |= {.Plus} }
|
||||
if fi.space { flags |= {.Space} }
|
||||
s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||
|
||||
if fi.hash && fi.zero && fi.indent == 0 {
|
||||
@@ -867,79 +865,30 @@ _pad :: proc(fi: ^Info, s: string) {
|
||||
}
|
||||
}
|
||||
|
||||
_fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: byte) {
|
||||
prec := fi.prec if fi.prec_set else 3
|
||||
buf: [386]byte
|
||||
|
||||
// Can return "NaN", "+Inf", "-Inf", "+<value>", "-<value>".
|
||||
str := strconv.append_float(buf[:], v, float_fmt, prec, bit_size)
|
||||
|
||||
if !fi.plus {
|
||||
// Strip sign from "+<value>" but not "+Inf".
|
||||
if str[0] == '+' && str[1] != 'I' {
|
||||
str = str[1:]
|
||||
}
|
||||
}
|
||||
|
||||
_pad(fi, str)
|
||||
}
|
||||
|
||||
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||
switch verb {
|
||||
case 'f', 'F', 'g', 'G', 'v':
|
||||
prec: int = 3
|
||||
if fi.prec_set {
|
||||
prec = fi.prec
|
||||
}
|
||||
buf: [386]byte
|
||||
|
||||
str := strconv.append_float(buf[1:], v, 'f', prec, bit_size)
|
||||
b := buf[:len(str)+1]
|
||||
if b[1] == '+' || b[1] == '-' {
|
||||
b = b[1:]
|
||||
} else {
|
||||
b[0] = '+'
|
||||
}
|
||||
|
||||
if fi.space && !fi.plus && b[0] == '+' {
|
||||
b[0] = ' '
|
||||
}
|
||||
|
||||
if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') {
|
||||
io.write_string(fi.writer, string(b), &fi.n)
|
||||
return
|
||||
}
|
||||
|
||||
if fi.plus || b[0] != '+' {
|
||||
if fi.zero && fi.width_set && fi.width > len(b) {
|
||||
io.write_byte(fi.writer, b[0], &fi.n)
|
||||
fmt_write_padding(fi, fi.width - len(b))
|
||||
io.write_string(fi.writer, string(b[1:]), &fi.n)
|
||||
} else {
|
||||
_pad(fi, string(b))
|
||||
}
|
||||
} else {
|
||||
_pad(fi, string(b[1:]))
|
||||
}
|
||||
|
||||
_fmt_float_as(fi, v, bit_size, verb, 'f')
|
||||
case 'e', 'E':
|
||||
prec: int = 3
|
||||
if fi.prec_set {
|
||||
prec = fi.prec
|
||||
}
|
||||
buf: [386]byte
|
||||
|
||||
str := strconv.append_float(buf[1:], v, 'e', prec, bit_size)
|
||||
b := buf[:len(str)+1]
|
||||
if b[1] == '+' || b[1] == '-' {
|
||||
b = b[1:]
|
||||
} else {
|
||||
b[0] = '+'
|
||||
}
|
||||
|
||||
if fi.space && !fi.plus && b[0] == '+' {
|
||||
b[0] = ' '
|
||||
}
|
||||
|
||||
if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') {
|
||||
io.write_string(fi.writer, string(b), &fi.n)
|
||||
return
|
||||
}
|
||||
|
||||
if fi.plus || str[0] != '+' {
|
||||
if fi.zero && fi.width_set && fi.width > len(b) {
|
||||
io.write_byte(fi.writer, b[0], &fi.n)
|
||||
fmt_write_padding(fi, fi.width - len(b))
|
||||
io.write_string(fi.writer, string(b[1:]), &fi.n)
|
||||
} else {
|
||||
_pad(fi, string(b))
|
||||
}
|
||||
} else {
|
||||
_pad(fi, string(b[1:]))
|
||||
}
|
||||
// BUG(): "%.3e" returns "3.000e+00"
|
||||
_fmt_float_as(fi, v, bit_size, verb, 'e')
|
||||
|
||||
case 'h', 'H':
|
||||
prev_fi := fi^
|
||||
|
||||
@@ -118,7 +118,7 @@ XXH_mul_64_to_128_fold_64 :: #force_inline proc(lhs, rhs: xxh_u64) -> (res: xxh_
|
||||
}
|
||||
|
||||
@(optimization_mode="speed")
|
||||
XXH_xorshift_64 :: #force_inline proc(v: xxh_u64, auto_cast shift: uint) -> (res: xxh_u64) {
|
||||
XXH_xorshift_64 :: #force_inline proc(v: xxh_u64, #any_int shift: uint) -> (res: xxh_u64) {
|
||||
return v ~ (v >> shift)
|
||||
}
|
||||
|
||||
|
||||
@@ -531,7 +531,7 @@ not_equal :: proc{not_equal_single, not_equal_array}
|
||||
|
||||
any :: proc(x: $A/[$N]bool) -> (out: bool) {
|
||||
for e in x {
|
||||
if x {
|
||||
if e {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,7 +153,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
||||
s := (^Scratch_Allocator)(allocator_data)
|
||||
|
||||
if s.data == nil {
|
||||
DEFAULT_BACKING_SIZE :: 1<<22
|
||||
DEFAULT_BACKING_SIZE :: 4 * Megabyte
|
||||
if !(context.allocator.procedure != scratch_allocator_proc &&
|
||||
context.allocator.data != allocator_data) {
|
||||
panic("cyclic initialization of the scratch allocator with itself")
|
||||
|
||||
+5
-5
@@ -3,11 +3,11 @@ package mem
|
||||
import "core:runtime"
|
||||
import "core:intrinsics"
|
||||
|
||||
Byte :: 1
|
||||
Kilobyte :: 1024 * Byte
|
||||
Megabyte :: 1024 * Kilobyte
|
||||
Gigabyte :: 1024 * Megabyte
|
||||
Terabyte :: 1024 * Gigabyte
|
||||
Byte :: runtime.Byte
|
||||
Kilobyte :: runtime.Kilobyte
|
||||
Megabyte :: runtime.Megabyte
|
||||
Gigabyte :: runtime.Gigabyte
|
||||
Terabyte :: runtime.Terabyte
|
||||
|
||||
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
|
||||
return runtime.memset(data, i32(value), len)
|
||||
|
||||
@@ -23,16 +23,3 @@ make_any :: proc "contextless" (data: rawptr, id: typeid) -> any {
|
||||
}
|
||||
|
||||
raw_data :: builtin.raw_data
|
||||
|
||||
|
||||
Poly_Raw_Map_Entry :: struct($Key, $Value: typeid) {
|
||||
hash: uintptr,
|
||||
next: int,
|
||||
key: Key,
|
||||
value: Value,
|
||||
}
|
||||
|
||||
Poly_Raw_Map :: struct($Key, $Value: typeid) {
|
||||
hashes: []int,
|
||||
entries: [dynamic]Poly_Raw_Map_Entry(Key, Value),
|
||||
}
|
||||
+42
-19
@@ -1,6 +1,7 @@
|
||||
package mem_virtual
|
||||
|
||||
import "core:mem"
|
||||
import "core:sync"
|
||||
|
||||
Arena_Kind :: enum uint {
|
||||
Growing = 0, // Chained memory blocks (singly linked list).
|
||||
@@ -15,15 +16,16 @@ Arena :: struct {
|
||||
total_reserved: uint,
|
||||
minimum_block_size: uint,
|
||||
temp_count: uint,
|
||||
mutex: sync.Mutex,
|
||||
}
|
||||
|
||||
|
||||
// 1 MiB should be enough to start with
|
||||
DEFAULT_ARENA_STATIC_COMMIT_SIZE :: 1<<20
|
||||
DEFAULT_ARENA_STATIC_COMMIT_SIZE :: mem.Megabyte
|
||||
DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: DEFAULT_ARENA_STATIC_COMMIT_SIZE
|
||||
|
||||
// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default
|
||||
DEFAULT_ARENA_STATIC_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27
|
||||
DEFAULT_ARENA_STATIC_RESERVE_SIZE :: mem.Gigabyte when size_of(uintptr) == 8 else 128 * mem.Megabyte
|
||||
|
||||
|
||||
|
||||
@@ -78,6 +80,8 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
|
||||
switch arena.kind {
|
||||
case .Growing:
|
||||
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
|
||||
@@ -116,6 +120,8 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
|
||||
}
|
||||
|
||||
arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
|
||||
if arena.curr_block != nil {
|
||||
assert(arena.kind != .Growing, "expected a non .Growing arena", loc)
|
||||
|
||||
@@ -135,6 +141,7 @@ arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location)
|
||||
}
|
||||
|
||||
arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
if free_block := arena.curr_block; free_block != nil {
|
||||
assert(arena.kind == .Growing, "expected a .Growing arena", loc)
|
||||
arena.curr_block = free_block.prev
|
||||
@@ -145,6 +152,7 @@ arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_locat
|
||||
arena_free_all :: proc(arena: ^Arena) {
|
||||
switch arena.kind {
|
||||
case .Growing:
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
for arena.curr_block != nil {
|
||||
arena_growing_free_last_memory_block(arena)
|
||||
}
|
||||
@@ -287,6 +295,8 @@ Arena_Temp :: struct {
|
||||
@(require_results)
|
||||
arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
|
||||
assert(arena != nil, "nil arena", loc)
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
|
||||
temp.arena = arena
|
||||
temp.block = arena.curr_block
|
||||
if arena.curr_block != nil {
|
||||
@@ -299,28 +309,41 @@ arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena
|
||||
arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
assert(temp.arena != nil, "nil arena", loc)
|
||||
arena := temp.arena
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
|
||||
memory_block_found := false
|
||||
for block := arena.curr_block; block != nil; block = block.prev {
|
||||
if block == temp.block {
|
||||
memory_block_found = true
|
||||
break
|
||||
if temp.block != nil {
|
||||
memory_block_found := false
|
||||
for block := arena.curr_block; block != nil; block = block.prev {
|
||||
if block == temp.block {
|
||||
memory_block_found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !memory_block_found {
|
||||
assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc)
|
||||
}
|
||||
|
||||
for arena.curr_block != temp.block {
|
||||
arena_growing_free_last_memory_block(arena)
|
||||
}
|
||||
|
||||
if block := arena.curr_block; block != nil {
|
||||
assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
|
||||
amount_to_zero := min(block.used-temp.used, block.reserved-block.used)
|
||||
mem.zero_slice(block.base[temp.used:][:amount_to_zero])
|
||||
block.used = temp.used
|
||||
}
|
||||
}
|
||||
if !memory_block_found {
|
||||
assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc)
|
||||
}
|
||||
|
||||
for arena.curr_block != temp.block {
|
||||
arena_growing_free_last_memory_block(arena)
|
||||
}
|
||||
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
|
||||
arena.temp_count -= 1
|
||||
}
|
||||
|
||||
if block := arena.curr_block; block != nil {
|
||||
assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
|
||||
amount_to_zero := min(block.used-temp.used, block.reserved-block.used)
|
||||
mem.zero_slice(block.base[temp.used:][:amount_to_zero])
|
||||
block.used = temp.used
|
||||
}
|
||||
// Ignore the use of a `arena_temp_begin` entirely
|
||||
arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||
assert(temp.arena != nil, "nil arena", loc)
|
||||
arena := temp.arena
|
||||
sync.mutex_guard(&arena.mutex)
|
||||
|
||||
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
|
||||
arena.temp_count -= 1
|
||||
|
||||
@@ -7,6 +7,7 @@ DEFAULT_PAGE_SIZE := uint(4096)
|
||||
|
||||
Allocator_Error :: mem.Allocator_Error
|
||||
|
||||
@(require_results)
|
||||
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
return _reserve(size)
|
||||
}
|
||||
@@ -15,6 +16,7 @@ commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
||||
return _commit(data, size)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
data = reserve(size) or_return
|
||||
commit(raw_data(data), size) or_return
|
||||
@@ -57,6 +59,7 @@ Memory_Block_Flag :: enum u32 {
|
||||
Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32]
|
||||
|
||||
|
||||
@(require_results)
|
||||
memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) {
|
||||
align_formula :: proc "contextless" (size, align: uint) -> uint {
|
||||
result := size + align-1
|
||||
@@ -100,6 +103,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
||||
return &pmblock.block, nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) {
|
||||
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||
alignment_offset := uint(0)
|
||||
@@ -160,7 +164,7 @@ memory_block_dealloc :: proc(block_to_free: ^Memory_Block) {
|
||||
|
||||
|
||||
|
||||
@(private)
|
||||
@(private, require_results)
|
||||
safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
|
||||
z, did_overflow := intrinsics.overflow_add(x, y)
|
||||
return z, !did_overflow
|
||||
|
||||
@@ -14,11 +14,12 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
||||
|
||||
dirpath: string
|
||||
dirpath, err = absolute_path_from_handle(fd)
|
||||
|
||||
if err != ERROR_NONE {
|
||||
return
|
||||
}
|
||||
|
||||
defer delete(dirpath)
|
||||
|
||||
n := n
|
||||
size := n
|
||||
if n <= 0 {
|
||||
|
||||
+9
-5
@@ -93,7 +93,7 @@ file_size_from_path :: proc(path: string) -> i64 {
|
||||
return length
|
||||
}
|
||||
|
||||
read_entire_file_from_filename :: proc(name: string, allocator := context.allocator) -> (data: []byte, success: bool) {
|
||||
read_entire_file_from_filename :: proc(name: string, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) {
|
||||
context.allocator = allocator
|
||||
|
||||
fd, err := open(name, O_RDONLY, 0)
|
||||
@@ -102,10 +102,10 @@ read_entire_file_from_filename :: proc(name: string, allocator := context.alloca
|
||||
}
|
||||
defer close(fd)
|
||||
|
||||
return read_entire_file_from_handle(fd, allocator)
|
||||
return read_entire_file_from_handle(fd, allocator, loc)
|
||||
}
|
||||
|
||||
read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator) -> (data: []byte, success: bool) {
|
||||
read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) {
|
||||
context.allocator = allocator
|
||||
|
||||
length: i64
|
||||
@@ -118,7 +118,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator)
|
||||
return nil, true
|
||||
}
|
||||
|
||||
data = make([]byte, int(length), allocator)
|
||||
data = make([]byte, int(length), allocator, loc)
|
||||
if data == nil {
|
||||
return nil, false
|
||||
}
|
||||
@@ -216,7 +216,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
|
||||
}
|
||||
|
||||
new_memory = aligned_alloc(new_size, new_alignment, p) or_return
|
||||
|
||||
|
||||
// NOTE: heap_resize does not zero the new memory, so we do it
|
||||
if new_size > old_size {
|
||||
new_region := mem.raw_data(new_memory[old_size:])
|
||||
@@ -261,3 +261,7 @@ heap_allocator :: proc() -> mem.Allocator {
|
||||
data = nil,
|
||||
}
|
||||
}
|
||||
|
||||
processor_core_count :: proc() -> int {
|
||||
return _processor_core_count()
|
||||
}
|
||||
|
||||
+32
-6
@@ -314,6 +314,7 @@ foreign libc {
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
|
||||
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
||||
@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
}
|
||||
@@ -333,7 +334,7 @@ foreign dl {
|
||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
||||
}
|
||||
|
||||
get_last_error :: proc() -> int {
|
||||
get_last_error :: proc "contextless" () -> int {
|
||||
return __error()^
|
||||
}
|
||||
|
||||
@@ -342,21 +343,33 @@ get_last_error_string :: proc() -> string {
|
||||
}
|
||||
|
||||
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) {
|
||||
isDir := is_dir_path(path)
|
||||
flags := flags
|
||||
if isDir {
|
||||
/*
|
||||
@INFO(Platin): To make it impossible to use the wrong flag for dir's
|
||||
as you can't write to a dir only read which makes it fail to open
|
||||
*/
|
||||
flags = O_RDONLY
|
||||
}
|
||||
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
handle := _unix_open(cstr, i32(flags), u16(mode))
|
||||
if handle == -1 {
|
||||
return INVALID_HANDLE, 1
|
||||
return INVALID_HANDLE, cast(Errno)get_last_error()
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 {
|
||||
if mode != 0 {
|
||||
/*
|
||||
@INFO(Platin): this is only done because O_CREATE for some reason fails to apply mode
|
||||
should not happen if the handle is a directory
|
||||
*/
|
||||
if mode != 0 && !isDir {
|
||||
err := fchmod(handle, cast(u16)mode)
|
||||
if err != 0 {
|
||||
_unix_close(handle)
|
||||
return INVALID_HANDLE, 1
|
||||
return INVALID_HANDLE, cast(Errno)err
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return handle, 0
|
||||
}
|
||||
@@ -688,6 +701,7 @@ get_current_directory :: proc() -> string {
|
||||
return string(cwd)
|
||||
}
|
||||
if Errno(get_last_error()) != ERANGE {
|
||||
delete(buf)
|
||||
return ""
|
||||
}
|
||||
resize(&buf, len(buf)+page_size)
|
||||
@@ -759,6 +773,18 @@ get_page_size :: proc() -> int {
|
||||
return page_size
|
||||
}
|
||||
|
||||
@(private)
|
||||
_processor_core_count :: proc() -> int {
|
||||
count : int = 0
|
||||
count_size := size_of(count)
|
||||
if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 {
|
||||
if count > 0 {
|
||||
return count
|
||||
}
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
res := make([]string, len(runtime.args__))
|
||||
|
||||
+16
-1
@@ -287,6 +287,7 @@ foreign libc {
|
||||
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
}
|
||||
@@ -303,7 +304,7 @@ is_path_separator :: proc(r: rune) -> bool {
|
||||
return r == '/'
|
||||
}
|
||||
|
||||
get_last_error :: proc() -> int {
|
||||
get_last_error :: proc "contextless" () -> int {
|
||||
return __errno_location()^
|
||||
}
|
||||
|
||||
@@ -650,6 +651,7 @@ get_current_directory :: proc() -> string {
|
||||
return string(cwd)
|
||||
}
|
||||
if Errno(get_last_error()) != ERANGE {
|
||||
delete(buf)
|
||||
return ""
|
||||
}
|
||||
resize(&buf, len(buf)+page_size)
|
||||
@@ -702,6 +704,19 @@ get_page_size :: proc() -> int {
|
||||
return page_size
|
||||
}
|
||||
|
||||
@(private)
|
||||
_processor_core_count :: proc() -> int {
|
||||
count : int = 0
|
||||
count_size := size_of(count)
|
||||
if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 {
|
||||
if count > 0 {
|
||||
return count
|
||||
}
|
||||
}
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
res := make([]string, len(runtime.args__))
|
||||
|
||||
@@ -404,6 +404,7 @@ foreign libc {
|
||||
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---
|
||||
|
||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||
@(link_name="get_nprocs") _unix_get_nprocs :: proc() -> c.int ---
|
||||
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||
@@ -441,7 +442,7 @@ _get_errno :: proc(res: int) -> Errno {
|
||||
}
|
||||
|
||||
// get errno from libc
|
||||
get_last_error :: proc() -> int {
|
||||
get_last_error :: proc "contextless" () -> int {
|
||||
return __errno_location()^
|
||||
}
|
||||
|
||||
@@ -822,6 +823,7 @@ get_current_directory :: proc() -> string {
|
||||
return strings.string_from_nul_terminated_ptr(&buf[0], len(buf))
|
||||
}
|
||||
if _get_errno(res) != ERANGE {
|
||||
delete(buf)
|
||||
return ""
|
||||
}
|
||||
resize(&buf, len(buf)+page_size)
|
||||
@@ -878,6 +880,10 @@ get_page_size :: proc() -> int {
|
||||
return page_size
|
||||
}
|
||||
|
||||
@(private)
|
||||
_processor_core_count :: proc() -> int {
|
||||
return int(_unix_get_nprocs())
|
||||
}
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
res := make([]string, len(runtime.args__))
|
||||
|
||||
+10
-2
@@ -269,6 +269,7 @@ foreign libc {
|
||||
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
||||
|
||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||
@(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long ---
|
||||
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||
@@ -294,7 +295,7 @@ is_path_separator :: proc(r: rune) -> bool {
|
||||
return r == '/'
|
||||
}
|
||||
|
||||
get_last_error :: proc() -> int {
|
||||
get_last_error :: proc "contextless" () -> int {
|
||||
return __errno()^
|
||||
}
|
||||
|
||||
@@ -648,6 +649,7 @@ get_current_directory :: proc() -> string {
|
||||
return string(cwd)
|
||||
}
|
||||
if Errno(get_last_error()) != ERANGE {
|
||||
delete(buf)
|
||||
return ""
|
||||
}
|
||||
resize(&buf, len(buf) + MAX_PATH)
|
||||
@@ -704,6 +706,12 @@ get_page_size :: proc() -> int {
|
||||
return page_size
|
||||
}
|
||||
|
||||
_SC_NPROCESSORS_ONLN :: 503
|
||||
|
||||
@(private)
|
||||
_processor_core_count :: proc() -> int {
|
||||
return int(_sysconf(_SC_NPROCESSORS_ONLN))
|
||||
}
|
||||
|
||||
_alloc_command_line_arguments :: proc() -> []string {
|
||||
res := make([]string, len(runtime.args__))
|
||||
@@ -711,4 +719,4 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
res[i] = string(arg)
|
||||
}
|
||||
return res
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +89,10 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
return 0
|
||||
}
|
||||
|
||||
@(private)
|
||||
_processor_core_count :: proc() -> int {
|
||||
return 1
|
||||
}
|
||||
|
||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
stat, err := wasi.fd_filestat_get(wasi.fd_t(fd))
|
||||
|
||||
+23
-1
@@ -3,6 +3,7 @@ package os
|
||||
|
||||
import win32 "core:sys/windows"
|
||||
import "core:runtime"
|
||||
import "core:intrinsics"
|
||||
|
||||
Handle :: distinct uintptr
|
||||
File_Time :: distinct u64
|
||||
@@ -126,7 +127,28 @@ get_page_size :: proc() -> int {
|
||||
return page_size
|
||||
}
|
||||
|
||||
@(private)
|
||||
_processor_core_count :: proc() -> int {
|
||||
length : win32.DWORD = 0
|
||||
result := win32.GetLogicalProcessorInformation(nil, &length)
|
||||
|
||||
thread_count := 0
|
||||
if !result && win32.GetLastError() == 122 && length > 0 {
|
||||
processors := make([]win32.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, length, context.temp_allocator)
|
||||
|
||||
result = win32.GetLogicalProcessorInformation(&processors[0], &length)
|
||||
if result {
|
||||
for processor in processors {
|
||||
if processor.Relationship == .RelationProcessorCore {
|
||||
thread := intrinsics.count_ones(processor.ProcessorMask)
|
||||
thread_count += int(thread)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return thread_count
|
||||
}
|
||||
|
||||
exit :: proc "contextless" (code: int) -> ! {
|
||||
runtime._cleanup_runtime_contextless()
|
||||
@@ -214,4 +236,4 @@ is_windows_10 :: proc() -> bool {
|
||||
is_windows_11 :: proc() -> bool {
|
||||
osvi := get_windows_version_w()
|
||||
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package reflect
|
||||
|
||||
import "core:runtime"
|
||||
|
||||
@(require_results)
|
||||
iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
|
||||
if val == nil || it == nil {
|
||||
return
|
||||
@@ -41,6 +42,7 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
iterate_map :: proc(val: any, it: ^int) -> (key, value: any, ok: bool) {
|
||||
if val == nil || it == nil {
|
||||
return
|
||||
|
||||
+61
-39
@@ -74,6 +74,7 @@ Type_Kind :: enum {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
ti := type_info_of(T)
|
||||
if ti != nil {
|
||||
@@ -113,57 +114,31 @@ type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
}
|
||||
|
||||
// TODO(bill): Better name
|
||||
@(require_results)
|
||||
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
return type_kind(runtime.typeid_base(T))
|
||||
}
|
||||
|
||||
// TODO(bill): Better name
|
||||
@(require_results)
|
||||
backing_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||
return type_kind(runtime.typeid_core(T))
|
||||
}
|
||||
|
||||
|
||||
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||
if info == nil { return nil }
|
||||
|
||||
base := info
|
||||
loop: for {
|
||||
#partial switch i in base.variant {
|
||||
case Type_Info_Named: base = i.base
|
||||
case: break loop
|
||||
}
|
||||
}
|
||||
return base
|
||||
}
|
||||
|
||||
|
||||
type_info_core :: proc(info: ^Type_Info) -> ^Type_Info {
|
||||
if info == nil { return nil }
|
||||
|
||||
base := info
|
||||
loop: for {
|
||||
#partial switch i in base.variant {
|
||||
case Type_Info_Named: base = i.base
|
||||
case Type_Info_Enum: base = i.base
|
||||
case: break loop
|
||||
}
|
||||
}
|
||||
return base
|
||||
}
|
||||
type_info_base :: runtime.type_info_base
|
||||
type_info_core :: runtime.type_info_core
|
||||
type_info_base_without_enum :: type_info_core
|
||||
|
||||
|
||||
typeid_base :: proc(id: typeid) -> typeid {
|
||||
ti := type_info_of(id)
|
||||
ti = type_info_base(ti)
|
||||
return ti.id
|
||||
when !ODIN_DISALLOW_RTTI {
|
||||
typeid_base :: runtime.typeid_base
|
||||
typeid_core :: runtime.typeid_core
|
||||
typeid_base_without_enum :: typeid_core
|
||||
}
|
||||
typeid_core :: proc(id: typeid) -> typeid {
|
||||
ti := type_info_base_without_enum(type_info_of(id))
|
||||
return ti.id
|
||||
}
|
||||
typeid_base_without_enum :: typeid_core
|
||||
|
||||
|
||||
@(require_results)
|
||||
any_base :: proc(v: any) -> any {
|
||||
v := v
|
||||
if v != nil {
|
||||
@@ -171,6 +146,7 @@ any_base :: proc(v: any) -> any {
|
||||
}
|
||||
return v
|
||||
}
|
||||
@(require_results)
|
||||
any_core :: proc(v: any) -> any {
|
||||
v := v
|
||||
if v != nil {
|
||||
@@ -179,6 +155,7 @@ any_core :: proc(v: any) -> any {
|
||||
return v
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
typeid_elem :: proc(id: typeid) -> typeid {
|
||||
ti := type_info_of(id)
|
||||
if ti == nil { return nil }
|
||||
@@ -208,6 +185,7 @@ typeid_elem :: proc(id: typeid) -> typeid {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
size_of_typeid :: proc(T: typeid) -> int {
|
||||
if ti := type_info_of(T); ti != nil {
|
||||
return ti.size
|
||||
@@ -215,6 +193,7 @@ size_of_typeid :: proc(T: typeid) -> int {
|
||||
return 0
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
align_of_typeid :: proc(T: typeid) -> int {
|
||||
if ti := type_info_of(T); ti != nil {
|
||||
return ti.align
|
||||
@@ -222,6 +201,7 @@ align_of_typeid :: proc(T: typeid) -> int {
|
||||
return 1
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
as_bytes :: proc(v: any) -> []byte {
|
||||
if v != nil {
|
||||
sz := size_of_typeid(v.id)
|
||||
@@ -230,10 +210,12 @@ as_bytes :: proc(v: any) -> []byte {
|
||||
return nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
any_data :: #force_inline proc(v: any) -> (data: rawptr, id: typeid) {
|
||||
return v.data, v.id
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_nil :: proc(v: any) -> bool {
|
||||
if v == nil {
|
||||
return true
|
||||
@@ -250,6 +232,7 @@ is_nil :: proc(v: any) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
length :: proc(val: any) -> int {
|
||||
if val == nil { return 0 }
|
||||
|
||||
@@ -285,6 +268,7 @@ length :: proc(val: any) -> int {
|
||||
return 0
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
capacity :: proc(val: any) -> int {
|
||||
if val == nil { return 0 }
|
||||
|
||||
@@ -311,6 +295,7 @@ capacity :: proc(val: any) -> int {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
||||
if val == nil { return nil }
|
||||
|
||||
@@ -370,6 +355,7 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
||||
return nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
deref :: proc(val: any) -> any {
|
||||
if val != nil {
|
||||
ti := type_info_base(type_info_of(val.id))
|
||||
@@ -399,6 +385,7 @@ Struct_Field :: struct {
|
||||
is_using: bool,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
|
||||
ti := runtime.type_info_base(type_info_of(T))
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
@@ -413,6 +400,7 @@ struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
||||
ti := runtime.type_info_base(type_info_of(T))
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
@@ -430,6 +418,7 @@ struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) -> any {
|
||||
if a == nil { return nil }
|
||||
|
||||
@@ -461,6 +450,7 @@ struct_field_value_by_name :: proc(a: any, field: string, allow_using := false)
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
struct_field_names :: proc(T: typeid) -> []string {
|
||||
ti := runtime.type_info_base(type_info_of(T))
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
@@ -469,6 +459,7 @@ struct_field_names :: proc(T: typeid) -> []string {
|
||||
return nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
struct_field_types :: proc(T: typeid) -> []^Type_Info {
|
||||
ti := runtime.type_info_base(type_info_of(T))
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
@@ -478,6 +469,7 @@ struct_field_types :: proc(T: typeid) -> []^Type_Info {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
|
||||
ti := runtime.type_info_base(type_info_of(T))
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
@@ -486,6 +478,7 @@ struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
|
||||
return nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
||||
ti := runtime.type_info_base(type_info_of(T))
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
@@ -494,6 +487,7 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
||||
return nil
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
|
||||
ti := runtime.type_info_base(type_info_of(T))
|
||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||
@@ -510,11 +504,13 @@ struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) {
|
||||
value, _ = struct_tag_lookup(tag, key)
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, ok: bool) {
|
||||
for t := tag; t != ""; /**/ {
|
||||
i := 0
|
||||
@@ -573,6 +569,7 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, o
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
enum_string :: proc(a: any) -> string {
|
||||
if a == nil { return "" }
|
||||
ti := runtime.type_info_base(type_info_of(a.id))
|
||||
@@ -591,6 +588,7 @@ enum_string :: proc(a: any) -> string {
|
||||
}
|
||||
|
||||
// Given a enum type and a value name, get the enum value.
|
||||
@(require_results)
|
||||
enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, ok: bool) {
|
||||
ti := type_info_base(type_info_of(Enum_Type))
|
||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||
@@ -607,6 +605,7 @@ enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, o
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info_Enum_Value, ok: bool) {
|
||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||
@@ -623,6 +622,7 @@ enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
enum_field_names :: proc(Enum_Type: typeid) -> []string {
|
||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||
@@ -630,6 +630,7 @@ enum_field_names :: proc(Enum_Type: typeid) -> []string {
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@(require_results)
|
||||
enum_field_values :: proc(Enum_Type: typeid) -> []Type_Info_Enum_Value {
|
||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||
@@ -643,6 +644,7 @@ Enum_Field :: struct {
|
||||
value: Type_Info_Enum_Value,
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
|
||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||
@@ -653,15 +655,18 @@ enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
union_variant_type_info :: proc(a: any) -> ^Type_Info {
|
||||
id := union_variant_typeid(a)
|
||||
return type_info_of(id)
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
type_info_union_is_pure_maybe :: proc(info: runtime.Type_Info_Union) -> bool {
|
||||
return len(info.variants) == 1 && is_pointer(info.variants[0])
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
union_variant_typeid :: proc(a: any) -> typeid {
|
||||
if a == nil { return nil }
|
||||
|
||||
@@ -690,9 +695,10 @@ union_variant_typeid :: proc(a: any) -> typeid {
|
||||
case: unimplemented()
|
||||
}
|
||||
|
||||
if a.data != nil && tag != 0 {
|
||||
i := tag if info.no_nil else tag-1
|
||||
return info.variants[i].id
|
||||
if info.no_nil {
|
||||
return info.variants[tag].id
|
||||
} else if tag != 0 {
|
||||
return info.variants[tag-1].id
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -700,6 +706,7 @@ union_variant_typeid :: proc(a: any) -> typeid {
|
||||
panic("expected a union to reflect.union_variant_typeid")
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
||||
if a == nil { return -1 }
|
||||
|
||||
@@ -730,6 +737,7 @@ get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
||||
panic("expected a union to reflect.get_union_variant_raw_tag")
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
get_union_variant :: proc(a: any) -> any {
|
||||
if a == nil {
|
||||
return nil
|
||||
@@ -741,6 +749,7 @@ get_union_variant :: proc(a: any) -> any {
|
||||
return any{a.data, id}
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
get_union_as_ptr_variants :: proc(val: ^$T) -> (res: intrinsics.type_convert_variants_to_pointers(T)) where intrinsics.type_is_union(T) {
|
||||
ptr := rawptr(val)
|
||||
tag := get_union_variant_raw_tag(val^)
|
||||
@@ -881,6 +890,7 @@ set_union_value :: proc(dst: any, value: any) -> bool {
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
as_bool :: proc(a: any) -> (value: bool, valid: bool) {
|
||||
if a == nil { return }
|
||||
a := a
|
||||
@@ -903,6 +913,7 @@ as_bool :: proc(a: any) -> (value: bool, valid: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
as_int :: proc(a: any) -> (value: int, valid: bool) {
|
||||
v: i64
|
||||
v, valid = as_i64(a)
|
||||
@@ -910,6 +921,7 @@ as_int :: proc(a: any) -> (value: int, valid: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
as_uint :: proc(a: any) -> (value: uint, valid: bool) {
|
||||
v: u64
|
||||
v, valid = as_u64(a)
|
||||
@@ -917,6 +929,7 @@ as_uint :: proc(a: any) -> (value: uint, valid: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
|
||||
if a == nil { return }
|
||||
a := a
|
||||
@@ -1024,6 +1037,7 @@ as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
|
||||
if a == nil { return }
|
||||
a := a
|
||||
@@ -1133,6 +1147,7 @@ as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
|
||||
if a == nil { return }
|
||||
a := a
|
||||
@@ -1239,6 +1254,7 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
as_string :: proc(a: any) -> (value: string, valid: bool) {
|
||||
if a == nil { return }
|
||||
a := a
|
||||
@@ -1258,6 +1274,7 @@ as_string :: proc(a: any) -> (value: string, valid: bool) {
|
||||
return
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
||||
if a == nil { return nil }
|
||||
a := a
|
||||
@@ -1272,6 +1289,7 @@ relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
|
||||
_handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
|
||||
if ptr^ == 0 {
|
||||
@@ -1314,6 +1332,7 @@ relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid)
|
||||
|
||||
|
||||
|
||||
@(require_results)
|
||||
as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||
if a == nil { return }
|
||||
a := a
|
||||
@@ -1341,6 +1360,7 @@ as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||
if a == nil { return }
|
||||
a := a
|
||||
@@ -1377,9 +1397,11 @@ ne :: not_equal
|
||||
|
||||
DEFAULT_EQUAL_MAX_RECURSION_LEVEL :: 32
|
||||
|
||||
@(require_results)
|
||||
not_equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
|
||||
return !equal(a, b, including_indirect_array_recursion, recursion_level)
|
||||
}
|
||||
@(require_results)
|
||||
equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
|
||||
if a == nil && b == nil {
|
||||
return true
|
||||
|
||||
+33
-3
@@ -3,17 +3,16 @@ package reflect
|
||||
import "core:io"
|
||||
import "core:strings"
|
||||
|
||||
@(require_results)
|
||||
are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
if a == b {
|
||||
return true
|
||||
}
|
||||
|
||||
if (a == nil && b != nil) ||
|
||||
(a != nil && b == nil) {
|
||||
if a == nil || b == nil {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
switch {
|
||||
case a.size != b.size, a.align != b.align:
|
||||
return false
|
||||
@@ -180,6 +179,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_signed :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
#partial switch i in type_info_base(info).variant {
|
||||
@@ -188,6 +188,7 @@ is_signed :: proc(info: ^Type_Info) -> bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
@(require_results)
|
||||
is_unsigned :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
#partial switch i in type_info_base(info).variant {
|
||||
@@ -197,6 +198,7 @@ is_unsigned :: proc(info: ^Type_Info) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
@(require_results)
|
||||
is_byte :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
#partial switch i in type_info_base(info).variant {
|
||||
@@ -206,66 +208,79 @@ is_byte :: proc(info: ^Type_Info) -> bool {
|
||||
}
|
||||
|
||||
|
||||
@(require_results)
|
||||
is_integer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Integer)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_rune :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Rune)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_float :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Float)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_complex :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Complex)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_quaternion :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Quaternion)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_any :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Any)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_string :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_String)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_cstring :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
v, ok := type_info_base(info).variant.(Type_Info_String)
|
||||
return ok && v.is_cstring
|
||||
}
|
||||
@(require_results)
|
||||
is_boolean :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Boolean)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Pointer)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_multi_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_soa_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_pointer_internally :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
#partial switch v in info.variant {
|
||||
@@ -277,76 +292,91 @@ is_pointer_internally :: proc(info: ^Type_Info) -> bool {
|
||||
}
|
||||
return false
|
||||
}
|
||||
@(require_results)
|
||||
is_procedure :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Procedure)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Array)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_enumerated_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Enumerated_Array)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Map)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_bit_set :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Bit_Set)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_slice :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Slice)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_tuple :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Tuple)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_struct :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
||||
return ok && !s.is_raw_union
|
||||
}
|
||||
@(require_results)
|
||||
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
||||
return ok && s.is_raw_union
|
||||
}
|
||||
@(require_results)
|
||||
is_union :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Union)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_enum :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Enum)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_simd_vector :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_relative_pointer :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Pointer)
|
||||
return ok
|
||||
}
|
||||
@(require_results)
|
||||
is_relative_slice :: proc(info: ^Type_Info) -> bool {
|
||||
if info == nil { return false }
|
||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Slice)
|
||||
|
||||
@@ -329,6 +329,12 @@ Allocator :: struct {
|
||||
data: rawptr,
|
||||
}
|
||||
|
||||
Byte :: 1
|
||||
Kilobyte :: 1024 * Byte
|
||||
Megabyte :: 1024 * Kilobyte
|
||||
Gigabyte :: 1024 * Megabyte
|
||||
Terabyte :: 1024 * Gigabyte
|
||||
|
||||
// Logging stuff
|
||||
|
||||
Logger_Level :: enum uint {
|
||||
|
||||
@@ -615,7 +615,7 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
|
||||
old_size := a.cap * size_of(E)
|
||||
new_size := new_cap * size_of(E)
|
||||
|
||||
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
|
||||
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -150,14 +150,14 @@ make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, auto_cast length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
context.allocator = allocator
|
||||
resize_soa(&array, length, loc)
|
||||
return
|
||||
}
|
||||
|
||||
@builtin
|
||||
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, auto_cast length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
|
||||
context.allocator = allocator
|
||||
if reserve_soa(&array, capacity, loc) {
|
||||
resize_soa(&array, length, loc)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package runtime
|
||||
|
||||
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22)
|
||||
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 4 * Megabyte)
|
||||
|
||||
|
||||
when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
||||
@@ -197,4 +197,4 @@ default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator
|
||||
procedure = default_temp_allocator_proc,
|
||||
data = allocator,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2,6 +2,73 @@ package runtime
|
||||
|
||||
_INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz"
|
||||
|
||||
when !ODIN_DISALLOW_RTTI {
|
||||
print_any_single :: proc(arg: any) {
|
||||
x := arg
|
||||
if loc, ok := x.(Source_Code_Location); ok {
|
||||
print_caller_location(loc)
|
||||
return
|
||||
}
|
||||
x.id = typeid_base(x.id)
|
||||
switch v in x {
|
||||
case typeid: print_typeid(v)
|
||||
case ^Type_Info: print_type(v)
|
||||
|
||||
case string: print_string(v)
|
||||
case cstring: print_string(string(v))
|
||||
case []byte: print_string(string(v))
|
||||
|
||||
case rune: print_rune(v)
|
||||
|
||||
case u8: print_u64(u64(v))
|
||||
case u16: print_u64(u64(v))
|
||||
case u16le: print_u64(u64(v))
|
||||
case u16be: print_u64(u64(v))
|
||||
case u32: print_u64(u64(v))
|
||||
case u32le: print_u64(u64(v))
|
||||
case u32be: print_u64(u64(v))
|
||||
case u64: print_u64(u64(v))
|
||||
case u64le: print_u64(u64(v))
|
||||
case u64be: print_u64(u64(v))
|
||||
|
||||
case i8: print_i64(i64(v))
|
||||
case i16: print_i64(i64(v))
|
||||
case i16le: print_i64(i64(v))
|
||||
case i16be: print_i64(i64(v))
|
||||
case i32: print_i64(i64(v))
|
||||
case i32le: print_i64(i64(v))
|
||||
case i32be: print_i64(i64(v))
|
||||
case i64: print_i64(i64(v))
|
||||
case i64le: print_i64(i64(v))
|
||||
case i64be: print_i64(i64(v))
|
||||
|
||||
case int: print_int(v)
|
||||
case uint: print_uint(v)
|
||||
case uintptr: print_uintptr(v)
|
||||
|
||||
case:
|
||||
ti := type_info_of(x.id)
|
||||
#partial switch v in ti.variant {
|
||||
case Type_Info_Pointer:
|
||||
print_uintptr((^uintptr)(x.data)^)
|
||||
return
|
||||
}
|
||||
|
||||
print_string("<invalid-value>")
|
||||
}
|
||||
}
|
||||
println_any :: proc(args: ..any) {
|
||||
loop: for arg, i in args {
|
||||
if i != 0 {
|
||||
print_string(" ")
|
||||
}
|
||||
print_any_single(arg)
|
||||
}
|
||||
print_string("\n")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
|
||||
r := c
|
||||
|
||||
|
||||
+1
-1
@@ -37,7 +37,7 @@ Map_Entry_Info :: struct($Key, $Value: typeid) {
|
||||
}
|
||||
|
||||
|
||||
map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry(K, V), err: runtime.Allocator) {
|
||||
map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry(K, V), err: runtime.Allocator_Error) {
|
||||
entries = make(type_of(entries), len(m), allocator) or_return
|
||||
i := 0
|
||||
for key, value in m {
|
||||
|
||||
+17
-15
@@ -73,24 +73,26 @@ ptr_rotate :: proc(left: int, mid: ^$T, right: int) {
|
||||
left, mid, right := left, mid, right
|
||||
|
||||
// TODO(bill): Optimization with a buffer for smaller ranges
|
||||
if left >= right {
|
||||
for {
|
||||
ptr_swap_non_overlapping(ptr_sub(mid, right), mid, right)
|
||||
mid = ptr_sub(mid, right)
|
||||
for left > 0 && right > 0 {
|
||||
if left >= right {
|
||||
for {
|
||||
ptr_swap_non_overlapping(ptr_sub(mid, right), mid, right * size_of(T))
|
||||
mid = ptr_sub(mid, right)
|
||||
|
||||
left -= right
|
||||
if left < right {
|
||||
break
|
||||
left -= right
|
||||
if left < right {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for {
|
||||
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
|
||||
mid = ptr_add(mid, left)
|
||||
} else {
|
||||
for {
|
||||
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left * size_of(T))
|
||||
mid = ptr_add(mid, left)
|
||||
|
||||
right -= left
|
||||
if right < left {
|
||||
break
|
||||
right -= left
|
||||
if right < left {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,8 +77,7 @@ swap_between :: proc(a, b: $T/[]$E) {
|
||||
reverse :: proc(array: $T/[]$E) {
|
||||
n := len(array)/2
|
||||
for i in 0..<n {
|
||||
a, b := i, len(array)-i-1
|
||||
array[a], array[b] = array[b], array[a]
|
||||
swap(array, i, len(array)-i-1)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,8 +217,10 @@ rotate_left :: proc(array: $T/[]$E, mid: int) {
|
||||
n := len(array)
|
||||
m := mid %% n
|
||||
k := n - m
|
||||
p := raw_data(array)
|
||||
ptr_rotate(mid, ptr_add(p, mid), k)
|
||||
// FIXME: (ap29600) this cast is a temporary fix for the compiler not matching
|
||||
// [^T] with $P/^$T
|
||||
p := cast(^E)raw_data(array)
|
||||
ptr_rotate(m, ptr_add(p, m), k)
|
||||
}
|
||||
rotate_right :: proc(array: $T/[]$E, k: int) {
|
||||
rotate_left(array, -k)
|
||||
@@ -515,4 +516,4 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
|
||||
enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T)
|
||||
where intrinsics.type_is_enumerated_array(T) {
|
||||
return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,25 +214,128 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
||||
trim(a)
|
||||
}
|
||||
|
||||
shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
// NOTE(bill): used to determine buffer size required for the decimal from the binary shift
|
||||
// 'k' means `1<<k` == `2^k` which equates to roundup(k*log10(2)) digits required
|
||||
log10_2 :: 0.301029995663981195213738894724493026768189881462108541310
|
||||
capacity := int(f64(k)*log10_2 + 1)
|
||||
import "core:runtime"
|
||||
println :: proc(args: ..any) {
|
||||
for arg, i in args {
|
||||
if i != 0 {
|
||||
runtime.print_string(" ")
|
||||
}
|
||||
switch v in arg {
|
||||
case string: runtime.print_string(v)
|
||||
case rune: runtime.print_rune(v)
|
||||
case int: runtime.print_int(v)
|
||||
case uint: runtime.print_uint(v)
|
||||
case u8: runtime.print_u64(u64(v))
|
||||
case u16: runtime.print_u64(u64(v))
|
||||
case u32: runtime.print_u64(u64(v))
|
||||
case u64: runtime.print_u64(v)
|
||||
case i8: runtime.print_i64(i64(v))
|
||||
case i16: runtime.print_i64(i64(v))
|
||||
case i32: runtime.print_i64(i64(v))
|
||||
case i64: runtime.print_i64(v)
|
||||
case uintptr: runtime.print_uintptr(v)
|
||||
case bool: runtime.print_string("true" if v else "false")
|
||||
}
|
||||
}
|
||||
runtime.print_string("\n")
|
||||
}
|
||||
|
||||
r := a.count // read index
|
||||
w := a.count+capacity // write index
|
||||
@(private="file")
|
||||
_shift_left_offsets := [?]struct{delta: int, cutoff: string}{
|
||||
{ 0, ""},
|
||||
{ 1, "5"},
|
||||
{ 1, "25"},
|
||||
{ 1, "125"},
|
||||
{ 2, "625"},
|
||||
{ 2, "3125"},
|
||||
{ 2, "15625"},
|
||||
{ 3, "78125"},
|
||||
{ 3, "390625"},
|
||||
{ 3, "1953125"},
|
||||
{ 4, "9765625"},
|
||||
{ 4, "48828125"},
|
||||
{ 4, "244140625"},
|
||||
{ 4, "1220703125"},
|
||||
{ 5, "6103515625"},
|
||||
{ 5, "30517578125"},
|
||||
{ 5, "152587890625"},
|
||||
{ 6, "762939453125"},
|
||||
{ 6, "3814697265625"},
|
||||
{ 6, "19073486328125"},
|
||||
{ 7, "95367431640625"},
|
||||
{ 7, "476837158203125"},
|
||||
{ 7, "2384185791015625"},
|
||||
{ 7, "11920928955078125"},
|
||||
{ 8, "59604644775390625"},
|
||||
{ 8, "298023223876953125"},
|
||||
{ 8, "1490116119384765625"},
|
||||
{ 9, "7450580596923828125"},
|
||||
{ 9, "37252902984619140625"},
|
||||
{ 9, "186264514923095703125"},
|
||||
{10, "931322574615478515625"},
|
||||
{10, "4656612873077392578125"},
|
||||
{10, "23283064365386962890625"},
|
||||
{10, "116415321826934814453125"},
|
||||
{11, "582076609134674072265625"},
|
||||
{11, "2910383045673370361328125"},
|
||||
{11, "14551915228366851806640625"},
|
||||
{12, "72759576141834259033203125"},
|
||||
{12, "363797880709171295166015625"},
|
||||
{12, "1818989403545856475830078125"},
|
||||
{13, "9094947017729282379150390625"},
|
||||
{13, "45474735088646411895751953125"},
|
||||
{13, "227373675443232059478759765625"},
|
||||
{13, "1136868377216160297393798828125"},
|
||||
{14, "5684341886080801486968994140625"},
|
||||
{14, "28421709430404007434844970703125"},
|
||||
{14, "142108547152020037174224853515625"},
|
||||
{15, "710542735760100185871124267578125"},
|
||||
{15, "3552713678800500929355621337890625"},
|
||||
{15, "17763568394002504646778106689453125"},
|
||||
{16, "88817841970012523233890533447265625"},
|
||||
{16, "444089209850062616169452667236328125"},
|
||||
{16, "2220446049250313080847263336181640625"},
|
||||
{16, "11102230246251565404236316680908203125"},
|
||||
{17, "55511151231257827021181583404541015625"},
|
||||
{17, "277555756156289135105907917022705078125"},
|
||||
{17, "1387778780781445675529539585113525390625"},
|
||||
{18, "6938893903907228377647697925567626953125"},
|
||||
{18, "34694469519536141888238489627838134765625"},
|
||||
{18, "173472347597680709441192448139190673828125"},
|
||||
{19, "867361737988403547205962240695953369140625"},
|
||||
}
|
||||
|
||||
d := len(a.digits)
|
||||
shift_left :: proc(a: ^Decimal, k: uint) #no_bounds_check {
|
||||
prefix_less :: #force_inline proc "contextless" (b: []byte, s: string) -> bool #no_bounds_check {
|
||||
for i in 0..<len(s) {
|
||||
if i >= len(b) {
|
||||
return true
|
||||
}
|
||||
if b[i] != s[i] {
|
||||
return b[i] < s[i]
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
assert(k < 61)
|
||||
|
||||
delta := _shift_left_offsets[k].delta
|
||||
if prefix_less(a.digits[:a.count], _shift_left_offsets[k].cutoff) {
|
||||
delta -= 1
|
||||
}
|
||||
|
||||
read_index := a.count
|
||||
write_index := a.count+delta
|
||||
|
||||
n: uint
|
||||
for r -= 1; r >= 0; r -= 1 {
|
||||
n += (uint(a.digits[r]) - '0') << k
|
||||
for read_index -= 1; read_index >= 0; read_index -= 1 {
|
||||
n += (uint(a.digits[read_index]) - '0') << k
|
||||
quo := n/10
|
||||
rem := n - 10*quo
|
||||
w -= 1
|
||||
if w < d {
|
||||
a.digits[w] = byte('0' + rem)
|
||||
write_index -= 1
|
||||
if write_index < len(a.digits) {
|
||||
a.digits[write_index] = byte('0' + rem)
|
||||
} else if rem != 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
@@ -242,21 +345,18 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
||||
for n > 0 {
|
||||
quo := n/10
|
||||
rem := n - 10*quo
|
||||
w -= 1
|
||||
if w < d {
|
||||
a.digits[w] = byte('0' + rem)
|
||||
write_index -= 1
|
||||
if write_index < len(a.digits) {
|
||||
a.digits[write_index] = byte('0' + rem)
|
||||
} else if rem != 0 {
|
||||
a.trunc = true
|
||||
}
|
||||
n = quo
|
||||
}
|
||||
|
||||
// NOTE(bill): Remove unused buffer size
|
||||
assert(w >= 0)
|
||||
capacity -= w
|
||||
a.decimal_point += delta
|
||||
|
||||
a.count = min(a.count+capacity, d)
|
||||
a.decimal_point += capacity
|
||||
a.count = clamp(a.count, 0, len(a.digits))
|
||||
trim(a)
|
||||
}
|
||||
|
||||
|
||||
@@ -287,13 +287,13 @@ round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Inf
|
||||
|
||||
@(private)
|
||||
decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64, overflow: bool) {
|
||||
end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (b: u64) {
|
||||
bits := mant & (u64(1)<<info.mantbits - 1)
|
||||
end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (bits: u64) {
|
||||
bits = mant & (u64(1)<<info.mantbits - 1)
|
||||
bits |= u64((exp-info.bias) & (1<<info.expbits - 1)) << info.mantbits
|
||||
if d.neg {
|
||||
bits |= 1<< info.mantbits << info.expbits
|
||||
}
|
||||
return bits
|
||||
return
|
||||
}
|
||||
set_overflow :: proc "contextless" (mant: ^u64, exp: ^int, info: ^Float_Info) -> bool {
|
||||
mant^ = 0
|
||||
@@ -303,7 +303,7 @@ decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64
|
||||
|
||||
mant: u64
|
||||
exp: int
|
||||
if d.decimal_point == 0 {
|
||||
if d.count == 0 {
|
||||
mant = 0
|
||||
exp = info.bias
|
||||
b = end(d, mant, exp, info)
|
||||
@@ -326,7 +326,7 @@ decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64
|
||||
exp = 0
|
||||
for d.decimal_point > 0 {
|
||||
n := 27 if d.decimal_point >= len(power_table) else power_table[d.decimal_point]
|
||||
decimal.shift(d, n)
|
||||
decimal.shift(d, -n)
|
||||
exp += n
|
||||
}
|
||||
for d.decimal_point < 0 || d.decimal_point == 0 && d.digits[0] < '5' {
|
||||
|
||||
@@ -3,7 +3,6 @@ package strconv
|
||||
Int_Flag :: enum {
|
||||
Prefix,
|
||||
Plus,
|
||||
Space,
|
||||
}
|
||||
Int_Flags :: bit_set[Int_Flag]
|
||||
|
||||
@@ -73,8 +72,6 @@ append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: i
|
||||
i-=1; a[i] = '-'
|
||||
case .Plus in flags:
|
||||
i-=1; a[i] = '+'
|
||||
case .Space in flags:
|
||||
i-=1; a[i] = ' '
|
||||
}
|
||||
|
||||
out := a[i:]
|
||||
@@ -157,8 +154,6 @@ append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_si
|
||||
i-=1; a[i] = '-'
|
||||
case .Plus in flags:
|
||||
i-=1; a[i] = '+'
|
||||
case .Space in flags:
|
||||
i-=1; a[i] = ' '
|
||||
}
|
||||
|
||||
out := a[i:]
|
||||
|
||||
@@ -819,7 +819,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
|
||||
}
|
||||
|
||||
if mantissa>>_f64_info.mantbits != 0 {
|
||||
return
|
||||
break trunc_block
|
||||
}
|
||||
f := f64(mantissa)
|
||||
if neg {
|
||||
@@ -841,7 +841,6 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
|
||||
return f / pow10[-exp], true
|
||||
}
|
||||
}
|
||||
|
||||
d: decimal.Decimal
|
||||
decimal.set(&d, str[:nr])
|
||||
b, overflow := decimal_to_float_bits(&d, &_f64_info)
|
||||
|
||||
+95
-30
@@ -1,6 +1,8 @@
|
||||
package sync
|
||||
|
||||
import "core:time"
|
||||
import vg "core:sys/valgrind"
|
||||
_ :: vg
|
||||
|
||||
// A Wait_Group waits for a collection of threads to finish
|
||||
//
|
||||
@@ -11,7 +13,7 @@ Wait_Group :: struct {
|
||||
cond: Cond,
|
||||
}
|
||||
|
||||
wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
|
||||
wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) {
|
||||
if delta == 0 {
|
||||
return
|
||||
}
|
||||
@@ -20,32 +22,32 @@ wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
|
||||
|
||||
atomic_add(&wg.counter, delta)
|
||||
if wg.counter < 0 {
|
||||
panic("sync.Wait_Group negative counter")
|
||||
_panic("sync.Wait_Group negative counter")
|
||||
}
|
||||
if wg.counter == 0 {
|
||||
cond_broadcast(&wg.cond)
|
||||
if wg.counter != 0 {
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wait_group_done :: proc(wg: ^Wait_Group) {
|
||||
wait_group_done :: proc "contextless" (wg: ^Wait_Group) {
|
||||
wait_group_add(wg, -1)
|
||||
}
|
||||
|
||||
wait_group_wait :: proc(wg: ^Wait_Group) {
|
||||
wait_group_wait :: proc "contextless" (wg: ^Wait_Group) {
|
||||
guard(&wg.mutex)
|
||||
|
||||
if wg.counter != 0 {
|
||||
cond_wait(&wg.cond, &wg.mutex)
|
||||
if wg.counter != 0 {
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -> bool {
|
||||
wait_group_wait_with_timeout :: proc "contextless" (wg: ^Wait_Group, duration: time.Duration) -> bool {
|
||||
if duration <= 0 {
|
||||
return false
|
||||
}
|
||||
@@ -56,7 +58,7 @@ wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -
|
||||
return false
|
||||
}
|
||||
if wg.counter != 0 {
|
||||
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
|
||||
}
|
||||
}
|
||||
return true
|
||||
@@ -76,7 +78,7 @@ Example:
|
||||
|
||||
barrier := &sync.Barrier{}
|
||||
|
||||
main :: proc() {
|
||||
main :: proc "contextless" () {
|
||||
fmt.println("Start")
|
||||
|
||||
THREAD_COUNT :: 4
|
||||
@@ -107,7 +109,10 @@ Barrier :: struct {
|
||||
thread_count: int,
|
||||
}
|
||||
|
||||
barrier_init :: proc(b: ^Barrier, thread_count: int) {
|
||||
barrier_init :: proc "contextless" (b: ^Barrier, thread_count: int) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_barrier_resize_pre(b, uint(thread_count))
|
||||
}
|
||||
b.index = 0
|
||||
b.generation_id = 0
|
||||
b.thread_count = thread_count
|
||||
@@ -115,7 +120,10 @@ barrier_init :: proc(b: ^Barrier, thread_count: int) {
|
||||
|
||||
// Block the current thread until all threads have rendezvoused
|
||||
// Barrier can be reused after all threads rendezvoused once, and can be used continuously
|
||||
barrier_wait :: proc(b: ^Barrier) -> (is_leader: bool) {
|
||||
barrier_wait :: proc "contextless" (b: ^Barrier) -> (is_leader: bool) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_barrier_wait_pre(b)
|
||||
}
|
||||
guard(&b.mutex)
|
||||
local_gen := b.generation_id
|
||||
b.index += 1
|
||||
@@ -141,7 +149,7 @@ Auto_Reset_Event :: struct {
|
||||
sema: Sema,
|
||||
}
|
||||
|
||||
auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) {
|
||||
auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) {
|
||||
old_status := atomic_load_explicit(&e.status, .Relaxed)
|
||||
for {
|
||||
new_status := old_status + 1 if old_status < 1 else 1
|
||||
@@ -155,7 +163,7 @@ auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) {
|
||||
}
|
||||
}
|
||||
|
||||
auto_reset_event_wait :: proc(e: ^Auto_Reset_Event) {
|
||||
auto_reset_event_wait :: proc "contextless" (e: ^Auto_Reset_Event) {
|
||||
old_status := atomic_sub_explicit(&e.status, 1, .Acquire)
|
||||
if old_status < 1 {
|
||||
sema_wait(&e.sema)
|
||||
@@ -169,18 +177,18 @@ Ticket_Mutex :: struct {
|
||||
serving: uint,
|
||||
}
|
||||
|
||||
ticket_mutex_lock :: #force_inline proc(m: ^Ticket_Mutex) {
|
||||
ticket_mutex_lock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
|
||||
ticket := atomic_add_explicit(&m.ticket, 1, .Relaxed)
|
||||
for ticket != atomic_load_explicit(&m.serving, .Acquire) {
|
||||
cpu_relax()
|
||||
}
|
||||
}
|
||||
|
||||
ticket_mutex_unlock :: #force_inline proc(m: ^Ticket_Mutex) {
|
||||
ticket_mutex_unlock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
|
||||
atomic_add_explicit(&m.serving, 1, .Relaxed)
|
||||
}
|
||||
@(deferred_in=ticket_mutex_unlock)
|
||||
ticket_mutex_guard :: proc(m: ^Ticket_Mutex) -> bool {
|
||||
ticket_mutex_guard :: proc "contextless" (m: ^Ticket_Mutex) -> bool {
|
||||
ticket_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -191,25 +199,25 @@ Benaphore :: struct {
|
||||
sema: Sema,
|
||||
}
|
||||
|
||||
benaphore_lock :: proc(b: ^Benaphore) {
|
||||
benaphore_lock :: proc "contextless" (b: ^Benaphore) {
|
||||
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
||||
sema_wait(&b.sema)
|
||||
}
|
||||
}
|
||||
|
||||
benaphore_try_lock :: proc(b: ^Benaphore) -> bool {
|
||||
benaphore_try_lock :: proc "contextless" (b: ^Benaphore) -> bool {
|
||||
v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire)
|
||||
return v == 0
|
||||
}
|
||||
|
||||
benaphore_unlock :: proc(b: ^Benaphore) {
|
||||
benaphore_unlock :: proc "contextless" (b: ^Benaphore) {
|
||||
if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
|
||||
sema_post(&b.sema)
|
||||
}
|
||||
}
|
||||
|
||||
@(deferred_in=benaphore_unlock)
|
||||
benaphore_guard :: proc(m: ^Benaphore) -> bool {
|
||||
benaphore_guard :: proc "contextless" (m: ^Benaphore) -> bool {
|
||||
benaphore_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -221,7 +229,7 @@ Recursive_Benaphore :: struct {
|
||||
sema: Sema,
|
||||
}
|
||||
|
||||
recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
|
||||
recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) {
|
||||
tid := current_thread_id()
|
||||
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
||||
if tid != b.owner {
|
||||
@@ -233,7 +241,7 @@ recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
|
||||
b.recursion += 1
|
||||
}
|
||||
|
||||
recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
|
||||
recursive_benaphore_try_lock :: proc "contextless" (b: ^Recursive_Benaphore) -> bool {
|
||||
tid := current_thread_id()
|
||||
if b.owner == tid {
|
||||
atomic_add_explicit(&b.counter, 1, .Acquire)
|
||||
@@ -248,9 +256,9 @@ recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
|
||||
return true
|
||||
}
|
||||
|
||||
recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
|
||||
recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) {
|
||||
tid := current_thread_id()
|
||||
assert(tid == b.owner)
|
||||
_assert(tid == b.owner, "tid != b.owner")
|
||||
b.recursion -= 1
|
||||
recursion := b.recursion
|
||||
if recursion == 0 {
|
||||
@@ -265,7 +273,7 @@ recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
|
||||
}
|
||||
|
||||
@(deferred_in=recursive_benaphore_unlock)
|
||||
recursive_benaphore_guard :: proc(m: ^Recursive_Benaphore) -> bool {
|
||||
recursive_benaphore_guard :: proc "contextless" (m: ^Recursive_Benaphore) -> bool {
|
||||
recursive_benaphore_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -282,7 +290,15 @@ Once :: struct {
|
||||
}
|
||||
|
||||
// once_do calls the procedure fn if and only if once_do is being called for the first for this instance of Once.
|
||||
once_do :: proc(o: ^Once, fn: proc()) {
|
||||
once_do :: proc{
|
||||
once_do_without_data,
|
||||
once_do_without_data_contextless,
|
||||
once_do_with_data,
|
||||
once_do_with_data_contextless,
|
||||
}
|
||||
|
||||
// once_do_without_data calls the procedure fn if and only if once_do_without_data is being called for the first for this instance of Once.
|
||||
once_do_without_data :: proc(o: ^Once, fn: proc()) {
|
||||
@(cold)
|
||||
do_slow :: proc(o: ^Once, fn: proc()) {
|
||||
guard(&o.m)
|
||||
@@ -292,12 +308,61 @@ once_do :: proc(o: ^Once, fn: proc()) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if atomic_load_explicit(&o.done, .Acquire) == false {
|
||||
do_slow(o, fn)
|
||||
}
|
||||
}
|
||||
|
||||
// once_do_without_data calls the procedure fn if and only if once_do_without_data is being called for the first for this instance of Once.
|
||||
once_do_without_data_contextless :: proc(o: ^Once, fn: proc "contextless" ()) {
|
||||
@(cold)
|
||||
do_slow :: proc(o: ^Once, fn: proc "contextless" ()) {
|
||||
guard(&o.m)
|
||||
if !o.done {
|
||||
fn()
|
||||
atomic_store_explicit(&o.done, true, .Release)
|
||||
}
|
||||
}
|
||||
|
||||
if atomic_load_explicit(&o.done, .Acquire) == false {
|
||||
do_slow(o, fn)
|
||||
}
|
||||
}
|
||||
|
||||
// once_do_with_data calls the procedure fn if and only if once_do_with_data is being called for the first for this instance of Once.
|
||||
once_do_with_data :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) {
|
||||
@(cold)
|
||||
do_slow :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) {
|
||||
guard(&o.m)
|
||||
if !o.done {
|
||||
fn(data)
|
||||
atomic_store_explicit(&o.done, true, .Release)
|
||||
}
|
||||
}
|
||||
|
||||
if atomic_load_explicit(&o.done, .Acquire) == false {
|
||||
do_slow(o, fn, data)
|
||||
}
|
||||
}
|
||||
|
||||
// once_do_with_data_contextless calls the procedure fn if and only if once_do_with_data_contextless is being called for the first for this instance of Once.
|
||||
once_do_with_data_contextless :: proc "contextless" (o: ^Once, fn: proc "contextless" (data: rawptr), data: rawptr) {
|
||||
@(cold)
|
||||
do_slow :: proc "contextless" (o: ^Once, fn: proc "contextless" (data: rawptr), data: rawptr) {
|
||||
guard(&o.m)
|
||||
if !o.done {
|
||||
fn(data)
|
||||
atomic_store_explicit(&o.done, true, .Release)
|
||||
}
|
||||
}
|
||||
|
||||
if atomic_load_explicit(&o.done, .Acquire) == false {
|
||||
do_slow(o, fn, data)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// A Parker is an associated token which is initially not present:
|
||||
@@ -314,7 +379,7 @@ Parker :: struct {
|
||||
// Blocks the current thread until the token is made available.
|
||||
//
|
||||
// Assumes this is only called by the thread that owns the Parker.
|
||||
park :: proc(p: ^Parker) {
|
||||
park :: proc "contextless" (p: ^Parker) {
|
||||
EMPTY :: 0
|
||||
NOTIFIED :: 1
|
||||
PARKED :: max(u32)
|
||||
@@ -333,7 +398,7 @@ park :: proc(p: ^Parker) {
|
||||
// for a limited duration.
|
||||
//
|
||||
// Assumes this is only called by the thread that owns the Parker
|
||||
park_with_timeout :: proc(p: ^Parker, duration: time.Duration) {
|
||||
park_with_timeout :: proc "contextless" (p: ^Parker, duration: time.Duration) {
|
||||
EMPTY :: 0
|
||||
NOTIFIED :: 1
|
||||
PARKED :: max(u32)
|
||||
@@ -345,7 +410,7 @@ park_with_timeout :: proc(p: ^Parker, duration: time.Duration) {
|
||||
}
|
||||
|
||||
// Automatically makes thee token available if it was not already.
|
||||
unpark :: proc(p: ^Parker) {
|
||||
unpark :: proc "contextless" (p: ^Parker) {
|
||||
EMPTY :: 0
|
||||
NOTIFIED :: 1
|
||||
PARKED :: max(Futex)
|
||||
|
||||
@@ -24,11 +24,11 @@ EINTR :: -4
|
||||
EFAULT :: -14
|
||||
ETIMEDOUT :: -60
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
return _futex_wait_with_timeout(f, expected, 0)
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
timeout_ns := u32(duration) * 1000
|
||||
|
||||
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
|
||||
@@ -41,13 +41,13 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
||||
case ETIMEDOUT:
|
||||
return false
|
||||
case:
|
||||
panic("futex_wait failure")
|
||||
_panic("futex_wait failure")
|
||||
}
|
||||
return true
|
||||
|
||||
}
|
||||
|
||||
_futex_signal :: proc(f: ^Futex) {
|
||||
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
loop: for {
|
||||
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
|
||||
if s >= 0 {
|
||||
@@ -59,12 +59,12 @@ _futex_signal :: proc(f: ^Futex) {
|
||||
case ENOENT:
|
||||
return
|
||||
case:
|
||||
panic("futex_wake_single failure")
|
||||
_panic("futex_wake_single failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_futex_broadcast :: proc(f: ^Futex) {
|
||||
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
loop: for {
|
||||
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
|
||||
if s >= 0 {
|
||||
@@ -76,7 +76,7 @@ _futex_broadcast :: proc(f: ^Futex) {
|
||||
case ENOENT:
|
||||
return
|
||||
case:
|
||||
panic("futex_wake_all failure")
|
||||
_panic("futex_wake_all failure")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ foreign libc {
|
||||
__error :: proc "c" () -> ^c.int ---
|
||||
}
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
timeout := [2]i64{14400, 0} // 4 hours
|
||||
for {
|
||||
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
|
||||
@@ -30,12 +30,12 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
continue
|
||||
}
|
||||
|
||||
panic("_futex_wait failure")
|
||||
_panic("_futex_wait failure")
|
||||
}
|
||||
unreachable()
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
if duration <= 0 {
|
||||
return false
|
||||
}
|
||||
@@ -51,21 +51,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
||||
return false
|
||||
}
|
||||
|
||||
panic("_futex_wait_with_timeout failure")
|
||||
_panic("_futex_wait_with_timeout failure")
|
||||
}
|
||||
|
||||
_futex_signal :: proc(f: ^Futex) {
|
||||
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil)
|
||||
|
||||
if res == -1 {
|
||||
panic("_futex_signal failure")
|
||||
_panic("_futex_signal failure")
|
||||
}
|
||||
}
|
||||
|
||||
_futex_broadcast :: proc(f: ^Futex) {
|
||||
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil)
|
||||
|
||||
if res == -1 {
|
||||
panic("_futex_broadcast failure")
|
||||
_panic("_futex_broadcast failure")
|
||||
}
|
||||
}
|
||||
|
||||
+10
-10
@@ -21,20 +21,20 @@ EFAULT :: -14
|
||||
EINVAL :: -22
|
||||
ETIMEDOUT :: -110
|
||||
|
||||
get_errno :: proc(r: int) -> int {
|
||||
get_errno :: proc "contextless" (r: int) -> int {
|
||||
if -4096 < r && r < 0 {
|
||||
return r
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
internal_futex :: proc(f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int {
|
||||
internal_futex :: proc "contextless" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int {
|
||||
code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0))
|
||||
return get_errno(code)
|
||||
}
|
||||
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil)
|
||||
switch err {
|
||||
case ESUCCESS, EINTR, EAGAIN, EINVAL:
|
||||
@@ -44,12 +44,12 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
case EFAULT:
|
||||
fallthrough
|
||||
case:
|
||||
panic("futex_wait failure")
|
||||
_panic("futex_wait failure")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
if duration <= 0 {
|
||||
return false
|
||||
}
|
||||
@@ -71,27 +71,27 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
||||
case EFAULT:
|
||||
fallthrough
|
||||
case:
|
||||
panic("futex_wait_with_timeout failure")
|
||||
_panic("futex_wait_with_timeout failure")
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
|
||||
_futex_signal :: proc(f: ^Futex) {
|
||||
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil)
|
||||
switch err {
|
||||
case ESUCCESS, EINVAL, EFAULT:
|
||||
// okay
|
||||
case:
|
||||
panic("futex_wake_single failure")
|
||||
_panic("futex_wake_single failure")
|
||||
}
|
||||
}
|
||||
_futex_broadcast :: proc(f: ^Futex) {
|
||||
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil)
|
||||
switch err {
|
||||
case ESUCCESS, EINVAL, EFAULT:
|
||||
// okay
|
||||
case:
|
||||
panic("_futex_wake_all failure")
|
||||
_panic("_futex_wake_all failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ foreign libc {
|
||||
_unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
|
||||
}
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil)
|
||||
|
||||
if res != -1 {
|
||||
@@ -32,10 +32,10 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
return false
|
||||
}
|
||||
|
||||
panic("futex_wait failure")
|
||||
_panic("futex_wait failure")
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
if duration <= 0 {
|
||||
return false
|
||||
}
|
||||
@@ -58,21 +58,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
||||
return false
|
||||
}
|
||||
|
||||
panic("futex_wait_with_timeout failure")
|
||||
_panic("futex_wait_with_timeout failure")
|
||||
}
|
||||
|
||||
_futex_signal :: proc(f: ^Futex) {
|
||||
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
|
||||
|
||||
if res == -1 {
|
||||
panic("futex_wake_single failure")
|
||||
_panic("futex_wake_single failure")
|
||||
}
|
||||
}
|
||||
|
||||
_futex_broadcast :: proc(f: ^Futex) {
|
||||
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
|
||||
|
||||
if res == -1 {
|
||||
panic("_futex_wake_all failure")
|
||||
_panic("_futex_wake_all failure")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,18 +5,18 @@ package sync
|
||||
import "core:intrinsics"
|
||||
import "core:time"
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
|
||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
||||
return s != 0
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
|
||||
return s != 0
|
||||
|
||||
}
|
||||
|
||||
_futex_signal :: proc(f: ^Futex) {
|
||||
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
loop: for {
|
||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
||||
if s >= 1 {
|
||||
@@ -25,7 +25,7 @@ _futex_signal :: proc(f: ^Futex) {
|
||||
}
|
||||
}
|
||||
|
||||
_futex_broadcast :: proc(f: ^Futex) {
|
||||
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
loop: for {
|
||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
|
||||
if s >= 0 {
|
||||
|
||||
@@ -39,22 +39,22 @@ CustomWaitOnAddress :: proc "stdcall" (Address: rawptr, CompareAddress: rawptr,
|
||||
}
|
||||
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expect: u32) -> bool {
|
||||
_futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> bool {
|
||||
expect := expect
|
||||
return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expect: u32, duration: time.Duration) -> bool {
|
||||
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> bool {
|
||||
expect := expect
|
||||
// NOTE(bill): for some bizarre reason, this has be a negative number
|
||||
timeout := -i64(duration / 100)
|
||||
return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
|
||||
}
|
||||
|
||||
_futex_signal :: proc(f: ^Futex) {
|
||||
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
WakeByAddressSingle(f)
|
||||
}
|
||||
|
||||
_futex_broadcast :: proc(f: ^Futex) {
|
||||
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
WakeByAddressAll(f)
|
||||
}
|
||||
+44
-28
@@ -1,5 +1,6 @@
|
||||
package sync
|
||||
|
||||
import "core:runtime"
|
||||
import "core:time"
|
||||
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
@@ -15,17 +16,17 @@ Mutex :: struct {
|
||||
}
|
||||
|
||||
// mutex_lock locks m
|
||||
mutex_lock :: proc(m: ^Mutex) {
|
||||
mutex_lock :: proc "contextless" (m: ^Mutex) {
|
||||
_mutex_lock(m)
|
||||
}
|
||||
|
||||
// mutex_unlock unlocks m
|
||||
mutex_unlock :: proc(m: ^Mutex) {
|
||||
mutex_unlock :: proc "contextless" (m: ^Mutex) {
|
||||
_mutex_unlock(m)
|
||||
}
|
||||
|
||||
// mutex_try_lock tries to lock m, will return true on success, and false on failure
|
||||
mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
|
||||
return _mutex_try_lock(m)
|
||||
}
|
||||
|
||||
@@ -36,7 +37,7 @@ Example:
|
||||
}
|
||||
*/
|
||||
@(deferred_in=mutex_unlock)
|
||||
mutex_guard :: proc(m: ^Mutex) -> bool {
|
||||
mutex_guard :: proc "contextless" (m: ^Mutex) -> bool {
|
||||
mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -52,32 +53,32 @@ RW_Mutex :: struct {
|
||||
|
||||
// rw_mutex_lock locks rw for writing (with a single writer)
|
||||
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
|
||||
rw_mutex_lock :: proc(rw: ^RW_Mutex) {
|
||||
rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
_rw_mutex_lock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_unlock unlocks rw for writing (with a single writer)
|
||||
rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
|
||||
rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
_rw_mutex_unlock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_try_lock tries to lock rw for writing (with a single writer)
|
||||
rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||
return _rw_mutex_try_lock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
||||
rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
|
||||
rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
_rw_mutex_shared_lock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
|
||||
rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
|
||||
rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
_rw_mutex_shared_unlock(rw)
|
||||
}
|
||||
|
||||
// rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
||||
rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||
return _rw_mutex_try_shared_lock(rw)
|
||||
}
|
||||
/*
|
||||
@@ -87,7 +88,7 @@ Example:
|
||||
}
|
||||
*/
|
||||
@(deferred_in=rw_mutex_unlock)
|
||||
rw_mutex_guard :: proc(m: ^RW_Mutex) -> bool {
|
||||
rw_mutex_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {
|
||||
rw_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -99,7 +100,7 @@ Example:
|
||||
}
|
||||
*/
|
||||
@(deferred_in=rw_mutex_shared_unlock)
|
||||
rw_mutex_shared_guard :: proc(m: ^RW_Mutex) -> bool {
|
||||
rw_mutex_shared_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {
|
||||
rw_mutex_shared_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -114,15 +115,15 @@ Recursive_Mutex :: struct {
|
||||
impl: _Recursive_Mutex,
|
||||
}
|
||||
|
||||
recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||
recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {
|
||||
_recursive_mutex_lock(m)
|
||||
}
|
||||
|
||||
recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
||||
recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) {
|
||||
_recursive_mutex_unlock(m)
|
||||
}
|
||||
|
||||
recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
||||
recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
|
||||
return _recursive_mutex_try_lock(m)
|
||||
}
|
||||
|
||||
@@ -133,7 +134,7 @@ Example:
|
||||
}
|
||||
*/
|
||||
@(deferred_in=recursive_mutex_unlock)
|
||||
recursive_mutex_guard :: proc(m: ^Recursive_Mutex) -> bool {
|
||||
recursive_mutex_guard :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
|
||||
recursive_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -147,22 +148,22 @@ Cond :: struct {
|
||||
impl: _Cond,
|
||||
}
|
||||
|
||||
cond_wait :: proc(c: ^Cond, m: ^Mutex) {
|
||||
cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
|
||||
_cond_wait(c, m)
|
||||
}
|
||||
|
||||
cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
||||
cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
||||
if duration <= 0 {
|
||||
return false
|
||||
}
|
||||
return _cond_wait_with_timeout(c, m, duration)
|
||||
}
|
||||
|
||||
cond_signal :: proc(c: ^Cond) {
|
||||
cond_signal :: proc "contextless" (c: ^Cond) {
|
||||
_cond_signal(c)
|
||||
}
|
||||
|
||||
cond_broadcast :: proc(c: ^Cond) {
|
||||
cond_broadcast :: proc "contextless" (c: ^Cond) {
|
||||
_cond_broadcast(c)
|
||||
}
|
||||
|
||||
@@ -175,15 +176,15 @@ Sema :: struct {
|
||||
impl: _Sema,
|
||||
}
|
||||
|
||||
sema_post :: proc(s: ^Sema, count := 1) {
|
||||
sema_post :: proc "contextless" (s: ^Sema, count := 1) {
|
||||
_sema_post(s, count)
|
||||
}
|
||||
|
||||
sema_wait :: proc(s: ^Sema) {
|
||||
sema_wait :: proc "contextless" (s: ^Sema) {
|
||||
_sema_wait(s)
|
||||
}
|
||||
|
||||
sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
|
||||
sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {
|
||||
return _sema_wait_with_timeout(s, duration)
|
||||
}
|
||||
|
||||
@@ -194,16 +195,16 @@ sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
|
||||
// An Futex must not be copied after first use
|
||||
Futex :: distinct u32
|
||||
|
||||
futex_wait :: proc(f: ^Futex, expected: u32) {
|
||||
futex_wait :: proc "contextless" (f: ^Futex, expected: u32) {
|
||||
if u32(atomic_load_explicit(f, .Acquire)) != expected {
|
||||
return
|
||||
}
|
||||
|
||||
assert(_futex_wait(f, expected), "futex_wait failure")
|
||||
_assert(_futex_wait(f, expected), "futex_wait failure")
|
||||
}
|
||||
|
||||
// returns true if the wait happened within the duration, false if it exceeded the time duration
|
||||
futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
if u32(atomic_load_explicit(f, .Acquire)) != expected {
|
||||
return true
|
||||
}
|
||||
@@ -214,10 +215,25 @@ futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duratio
|
||||
return _futex_wait_with_timeout(f, expected, duration)
|
||||
}
|
||||
|
||||
futex_signal :: proc(f: ^Futex) {
|
||||
futex_signal :: proc "contextless" (f: ^Futex) {
|
||||
_futex_signal(f)
|
||||
}
|
||||
|
||||
futex_broadcast :: proc(f: ^Futex) {
|
||||
futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||
_futex_broadcast(f)
|
||||
}
|
||||
|
||||
|
||||
@(private)
|
||||
_assert :: proc "contextless" (cond: bool, msg: string) {
|
||||
if !cond {
|
||||
_panic(msg)
|
||||
}
|
||||
}
|
||||
|
||||
@(private)
|
||||
_panic :: proc "contextless" (msg: string) -> ! {
|
||||
runtime.print_string(msg)
|
||||
runtime.print_byte('\n')
|
||||
runtime.trap()
|
||||
}
|
||||
@@ -18,9 +18,9 @@ Atomic_Mutex :: struct {
|
||||
}
|
||||
|
||||
// atomic_mutex_lock locks m
|
||||
atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
|
||||
atomic_mutex_lock :: proc "contextless" (m: ^Atomic_Mutex) {
|
||||
@(cold)
|
||||
lock_slow :: proc(m: ^Atomic_Mutex, curr_state: Atomic_Mutex_State) {
|
||||
lock_slow :: proc "contextless" (m: ^Atomic_Mutex, curr_state: Atomic_Mutex_State) {
|
||||
new_state := curr_state // Make a copy of it
|
||||
|
||||
spin_lock: for spin in 0..<i32(100) {
|
||||
@@ -58,9 +58,9 @@ atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
|
||||
}
|
||||
|
||||
// atomic_mutex_unlock unlocks m
|
||||
atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) {
|
||||
atomic_mutex_unlock :: proc "contextless" (m: ^Atomic_Mutex) {
|
||||
@(cold)
|
||||
unlock_slow :: proc(m: ^Atomic_Mutex) {
|
||||
unlock_slow :: proc "contextless" (m: ^Atomic_Mutex) {
|
||||
futex_signal((^Futex)(&m.state))
|
||||
}
|
||||
|
||||
@@ -76,7 +76,7 @@ atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) {
|
||||
}
|
||||
|
||||
// atomic_mutex_try_lock tries to lock m, will return true on success, and false on failure
|
||||
atomic_mutex_try_lock :: proc(m: ^Atomic_Mutex) -> bool {
|
||||
atomic_mutex_try_lock :: proc "contextless" (m: ^Atomic_Mutex) -> bool {
|
||||
_, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .Acquire, .Consume)
|
||||
return ok
|
||||
}
|
||||
@@ -88,7 +88,7 @@ Example:
|
||||
}
|
||||
*/
|
||||
@(deferred_in=atomic_mutex_unlock)
|
||||
atomic_mutex_guard :: proc(m: ^Atomic_Mutex) -> bool {
|
||||
atomic_mutex_guard :: proc "contextless" (m: ^Atomic_Mutex) -> bool {
|
||||
atomic_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -117,7 +117,7 @@ Atomic_RW_Mutex :: struct {
|
||||
|
||||
// atomic_rw_mutex_lock locks rw for writing (with a single writer)
|
||||
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
|
||||
atomic_rw_mutex_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
atomic_rw_mutex_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Writer)
|
||||
atomic_mutex_lock(&rw.mutex)
|
||||
|
||||
@@ -128,13 +128,13 @@ atomic_rw_mutex_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_unlock unlocks rw for writing (with a single writer)
|
||||
atomic_rw_mutex_unlock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
atomic_rw_mutex_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||
_ = atomic_and(&rw.state, ~Atomic_RW_Mutex_State_Is_Writing)
|
||||
atomic_mutex_unlock(&rw.mutex)
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_try_lock tries to lock rw for writing (with a single writer)
|
||||
atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_try_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
|
||||
if atomic_mutex_try_lock(&rw.mutex) {
|
||||
state := atomic_load(&rw.state)
|
||||
if state & Atomic_RW_Mutex_State_Reader_Mask == 0 {
|
||||
@@ -148,7 +148,7 @@ atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
||||
atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
atomic_rw_mutex_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||
state := atomic_load(&rw.state)
|
||||
for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
||||
ok: bool
|
||||
@@ -164,7 +164,7 @@ atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
|
||||
atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
atomic_rw_mutex_shared_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
|
||||
state := atomic_sub(&rw.state, Atomic_RW_Mutex_State_Reader)
|
||||
|
||||
if (state & Atomic_RW_Mutex_State_Reader_Mask == Atomic_RW_Mutex_State_Reader) &&
|
||||
@@ -174,7 +174,7 @@ atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex) {
|
||||
}
|
||||
|
||||
// atomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
||||
atomic_rw_mutex_try_shared_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
|
||||
state := atomic_load(&rw.state)
|
||||
if state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
||||
_, ok := atomic_compare_exchange_strong(&rw.state, state, state + Atomic_RW_Mutex_State_Reader)
|
||||
@@ -198,7 +198,7 @@ Example:
|
||||
}
|
||||
*/
|
||||
@(deferred_in=atomic_rw_mutex_unlock)
|
||||
atomic_rw_mutex_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -210,7 +210,7 @@ Example:
|
||||
}
|
||||
*/
|
||||
@(deferred_in=atomic_rw_mutex_shared_unlock)
|
||||
atomic_rw_mutex_shared_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_shared_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {
|
||||
atomic_rw_mutex_shared_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -228,7 +228,7 @@ Atomic_Recursive_Mutex :: struct {
|
||||
mutex: Mutex,
|
||||
}
|
||||
|
||||
atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) {
|
||||
atomic_recursive_mutex_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
|
||||
tid := current_thread_id()
|
||||
if tid != m.owner {
|
||||
mutex_lock(&m.mutex)
|
||||
@@ -238,9 +238,9 @@ atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) {
|
||||
m.recursion += 1
|
||||
}
|
||||
|
||||
atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex) {
|
||||
atomic_recursive_mutex_unlock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
|
||||
tid := current_thread_id()
|
||||
assert(tid == m.owner)
|
||||
_assert(tid == m.owner, "tid != m.owner")
|
||||
m.recursion -= 1
|
||||
recursion := m.recursion
|
||||
if recursion == 0 {
|
||||
@@ -253,7 +253,7 @@ atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex) {
|
||||
|
||||
}
|
||||
|
||||
atomic_recursive_mutex_try_lock :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
|
||||
atomic_recursive_mutex_try_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {
|
||||
tid := current_thread_id()
|
||||
if m.owner == tid {
|
||||
return mutex_try_lock(&m.mutex)
|
||||
@@ -274,7 +274,7 @@ Example:
|
||||
}
|
||||
*/
|
||||
@(deferred_in=atomic_recursive_mutex_unlock)
|
||||
atomic_recursive_mutex_guard :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
|
||||
atomic_recursive_mutex_guard :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {
|
||||
atomic_recursive_mutex_lock(m)
|
||||
return true
|
||||
}
|
||||
@@ -289,7 +289,7 @@ Atomic_Cond :: struct {
|
||||
state: Futex,
|
||||
}
|
||||
|
||||
atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) {
|
||||
atomic_cond_wait :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex) {
|
||||
state := u32(atomic_load_explicit(&c.state, .Relaxed))
|
||||
unlock(m)
|
||||
futex_wait(&c.state, state)
|
||||
@@ -297,7 +297,7 @@ atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) {
|
||||
|
||||
}
|
||||
|
||||
atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) {
|
||||
atomic_cond_wait_with_timeout :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) {
|
||||
state := u32(atomic_load_explicit(&c.state, .Relaxed))
|
||||
unlock(m)
|
||||
ok = futex_wait_with_timeout(&c.state, state, duration)
|
||||
@@ -306,12 +306,12 @@ atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duratio
|
||||
}
|
||||
|
||||
|
||||
atomic_cond_signal :: proc(c: ^Atomic_Cond) {
|
||||
atomic_cond_signal :: proc "contextless" (c: ^Atomic_Cond) {
|
||||
atomic_add_explicit(&c.state, 1, .Release)
|
||||
futex_signal(&c.state)
|
||||
}
|
||||
|
||||
atomic_cond_broadcast :: proc(c: ^Atomic_Cond) {
|
||||
atomic_cond_broadcast :: proc "contextless" (c: ^Atomic_Cond) {
|
||||
atomic_add_explicit(&c.state, 1, .Release)
|
||||
futex_broadcast(&c.state)
|
||||
}
|
||||
@@ -324,7 +324,7 @@ Atomic_Sema :: struct {
|
||||
count: Futex,
|
||||
}
|
||||
|
||||
atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) {
|
||||
atomic_sema_post :: proc "contextless" (s: ^Atomic_Sema, count := 1) {
|
||||
atomic_add_explicit(&s.count, Futex(count), .Release)
|
||||
if count == 1 {
|
||||
futex_signal(&s.count)
|
||||
@@ -333,7 +333,7 @@ atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) {
|
||||
}
|
||||
}
|
||||
|
||||
atomic_sema_wait :: proc(s: ^Atomic_Sema) {
|
||||
atomic_sema_wait :: proc "contextless" (s: ^Atomic_Sema) {
|
||||
for {
|
||||
original_count := atomic_load_explicit(&s.count, .Relaxed)
|
||||
for original_count == 0 {
|
||||
@@ -346,7 +346,7 @@ atomic_sema_wait :: proc(s: ^Atomic_Sema) {
|
||||
}
|
||||
}
|
||||
|
||||
atomic_sema_wait_with_timeout :: proc(s: ^Atomic_Sema, duration: time.Duration) -> bool {
|
||||
atomic_sema_wait_with_timeout :: proc "contextless" (s: ^Atomic_Sema, duration: time.Duration) -> bool {
|
||||
if duration <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -2,20 +2,31 @@
|
||||
package sync
|
||||
|
||||
import "core:time"
|
||||
import vg "core:sys/valgrind"
|
||||
_ :: vg
|
||||
|
||||
_Sema :: struct {
|
||||
atomic: Atomic_Sema,
|
||||
}
|
||||
|
||||
_sema_post :: proc(s: ^Sema, count := 1) {
|
||||
_sema_post :: proc "contextless" (s: ^Sema, count := 1) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_sem_post_pre(s)
|
||||
}
|
||||
atomic_sema_post(&s.impl.atomic, count)
|
||||
}
|
||||
|
||||
_sema_wait :: proc(s: ^Sema) {
|
||||
_sema_wait :: proc "contextless" (s: ^Sema) {
|
||||
atomic_sema_wait(&s.impl.atomic)
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_sem_wait_post(s)
|
||||
}
|
||||
}
|
||||
|
||||
_sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
|
||||
_sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
defer vg.helgrind_sem_wait_post(s)
|
||||
}
|
||||
return atomic_sema_wait_with_timeout(&s.impl.atomic, duration)
|
||||
}
|
||||
|
||||
@@ -25,7 +36,12 @@ _Recursive_Mutex :: struct {
|
||||
recursion: i32,
|
||||
}
|
||||
|
||||
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||
_recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_mutex_lock_pre(m, false)
|
||||
defer vg.helgrind_mutex_lock_post(m)
|
||||
}
|
||||
|
||||
tid := Futex(current_thread_id())
|
||||
for {
|
||||
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
|
||||
@@ -40,7 +56,12 @@ _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
||||
}
|
||||
}
|
||||
|
||||
_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
||||
_recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_mutex_unlock_pre(m)
|
||||
defer vg.helgrind_mutex_unlock_post(m)
|
||||
}
|
||||
|
||||
m.impl.recursion -= 1
|
||||
if m.impl.recursion != 0 {
|
||||
return
|
||||
@@ -52,7 +73,7 @@ _recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
|
||||
|
||||
}
|
||||
|
||||
_recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
|
||||
_recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
|
||||
tid := Futex(current_thread_id())
|
||||
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
|
||||
switch prev_owner {
|
||||
@@ -70,15 +91,27 @@ when ODIN_OS != .Windows {
|
||||
mutex: Atomic_Mutex,
|
||||
}
|
||||
|
||||
_mutex_lock :: proc(m: ^Mutex) {
|
||||
_mutex_lock :: proc "contextless" (m: ^Mutex) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_mutex_lock_pre(m, false)
|
||||
defer vg.helgrind_mutex_lock_post(m)
|
||||
}
|
||||
atomic_mutex_lock(&m.impl.mutex)
|
||||
}
|
||||
|
||||
_mutex_unlock :: proc(m: ^Mutex) {
|
||||
_mutex_unlock :: proc "contextless" (m: ^Mutex) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_mutex_unlock_pre(m)
|
||||
defer vg.helgrind_mutex_unlock_post(m)
|
||||
}
|
||||
atomic_mutex_unlock(&m.impl.mutex)
|
||||
}
|
||||
|
||||
_mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
_mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_mutex_lock_pre(m, true)
|
||||
defer vg.helgrind_mutex_lock_post(m)
|
||||
}
|
||||
return atomic_mutex_try_lock(&m.impl.mutex)
|
||||
}
|
||||
|
||||
@@ -86,19 +119,33 @@ when ODIN_OS != .Windows {
|
||||
cond: Atomic_Cond,
|
||||
}
|
||||
|
||||
_cond_wait :: proc(c: ^Cond, m: ^Mutex) {
|
||||
_cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
_ = vg.helgrind_cond_wait_pre(c, m)
|
||||
defer _ = vg.helgrind_cond_wait_post(c, m)
|
||||
}
|
||||
atomic_cond_wait(&c.impl.cond, &m.impl.mutex)
|
||||
}
|
||||
|
||||
_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
||||
_cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
_ = vg.helgrind_cond_wait_pre(c, m)
|
||||
defer _ = vg.helgrind_cond_wait_post(c, m)
|
||||
}
|
||||
return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration)
|
||||
}
|
||||
|
||||
_cond_signal :: proc(c: ^Cond) {
|
||||
_cond_signal :: proc "contextless" (c: ^Cond) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_cond_signal_pre(c)
|
||||
}
|
||||
atomic_cond_signal(&c.impl.cond)
|
||||
}
|
||||
|
||||
_cond_broadcast :: proc(c: ^Cond) {
|
||||
_cond_broadcast :: proc "contextless" (c: ^Cond) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_cond_broadcast_pre(c)
|
||||
}
|
||||
atomic_cond_broadcast(&c.impl.cond)
|
||||
}
|
||||
|
||||
@@ -107,27 +154,39 @@ when ODIN_OS != .Windows {
|
||||
mutex: Atomic_RW_Mutex,
|
||||
}
|
||||
|
||||
_rw_mutex_lock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_rwlock_lock_pre(rw, true)
|
||||
}
|
||||
atomic_rw_mutex_lock(&rw.impl.mutex)
|
||||
}
|
||||
|
||||
_rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
atomic_rw_mutex_unlock(&rw.impl.mutex)
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_rwlock_unlock_post(rw, true)
|
||||
}
|
||||
}
|
||||
|
||||
_rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
_rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||
return atomic_rw_mutex_try_lock(&rw.impl.mutex)
|
||||
}
|
||||
|
||||
_rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_rwlock_lock_pre(rw, false)
|
||||
}
|
||||
atomic_rw_mutex_shared_lock(&rw.impl.mutex)
|
||||
}
|
||||
|
||||
_rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
atomic_rw_mutex_shared_unlock(&rw.impl.mutex)
|
||||
when ODIN_VALGRIND_SUPPORT {
|
||||
vg.helgrind_rwlock_unlock_post(rw, false)
|
||||
}
|
||||
}
|
||||
|
||||
_rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||
return atomic_rw_mutex_try_shared_lock(&rw.impl.mutex)
|
||||
}
|
||||
}
|
||||
@@ -13,15 +13,15 @@ _Mutex :: struct {
|
||||
srwlock: win32.SRWLOCK,
|
||||
}
|
||||
|
||||
_mutex_lock :: proc(m: ^Mutex) {
|
||||
_mutex_lock :: proc "contextless" (m: ^Mutex) {
|
||||
win32.AcquireSRWLockExclusive(&m.impl.srwlock)
|
||||
}
|
||||
|
||||
_mutex_unlock :: proc(m: ^Mutex) {
|
||||
_mutex_unlock :: proc "contextless" (m: ^Mutex) {
|
||||
win32.ReleaseSRWLockExclusive(&m.impl.srwlock)
|
||||
}
|
||||
|
||||
_mutex_try_lock :: proc(m: ^Mutex) -> bool {
|
||||
_mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&m.impl.srwlock))
|
||||
}
|
||||
|
||||
@@ -29,27 +29,27 @@ _RW_Mutex :: struct {
|
||||
srwlock: win32.SRWLOCK,
|
||||
}
|
||||
|
||||
_rw_mutex_lock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
win32.AcquireSRWLockExclusive(&rw.impl.srwlock)
|
||||
}
|
||||
|
||||
_rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
win32.ReleaseSRWLockExclusive(&rw.impl.srwlock)
|
||||
}
|
||||
|
||||
_rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
_rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||
return bool(win32.TryAcquireSRWLockExclusive(&rw.impl.srwlock))
|
||||
}
|
||||
|
||||
_rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
win32.AcquireSRWLockShared(&rw.impl.srwlock)
|
||||
}
|
||||
|
||||
_rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
|
||||
_rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||
win32.ReleaseSRWLockShared(&rw.impl.srwlock)
|
||||
}
|
||||
|
||||
_rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
|
||||
_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
|
||||
return bool(win32.TryAcquireSRWLockShared(&rw.impl.srwlock))
|
||||
}
|
||||
|
||||
@@ -58,22 +58,22 @@ _Cond :: struct {
|
||||
cond: win32.CONDITION_VARIABLE,
|
||||
}
|
||||
|
||||
_cond_wait :: proc(c: ^Cond, m: ^Mutex) {
|
||||
_cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
|
||||
_ = win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, win32.INFINITE, 0)
|
||||
}
|
||||
|
||||
_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
||||
_cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
|
||||
duration := u32(duration / time.Millisecond)
|
||||
ok := win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, duration, 0)
|
||||
return bool(ok)
|
||||
}
|
||||
|
||||
|
||||
_cond_signal :: proc(c: ^Cond) {
|
||||
_cond_signal :: proc "contextless" (c: ^Cond) {
|
||||
win32.WakeConditionVariable(&c.impl.cond)
|
||||
}
|
||||
|
||||
_cond_broadcast :: proc(c: ^Cond) {
|
||||
_cond_broadcast :: proc "contextless" (c: ^Cond) {
|
||||
win32.WakeAllConditionVariable(&c.impl.cond)
|
||||
}
|
||||
|
||||
|
||||
@@ -3,7 +3,45 @@ package sys_windows
|
||||
|
||||
foreign import dwmapi "system:Dwmapi.lib"
|
||||
|
||||
DWMWINDOWATTRIBUTE :: enum {
|
||||
DWMWA_NCRENDERING_ENABLED,
|
||||
DWMWA_NCRENDERING_POLICY,
|
||||
DWMWA_TRANSITIONS_FORCEDISABLED,
|
||||
DWMWA_ALLOW_NCPAINT,
|
||||
DWMWA_CAPTION_BUTTON_BOUNDS,
|
||||
DWMWA_NONCLIENT_RTL_LAYOUT,
|
||||
DWMWA_FORCE_ICONIC_REPRESENTATION,
|
||||
DWMWA_FLIP3D_POLICY,
|
||||
DWMWA_EXTENDED_FRAME_BOUNDS,
|
||||
DWMWA_HAS_ICONIC_BITMAP,
|
||||
DWMWA_DISALLOW_PEEK,
|
||||
DWMWA_EXCLUDED_FROM_PEEK,
|
||||
DWMWA_CLOAK,
|
||||
DWMWA_CLOAKED,
|
||||
DWMWA_FREEZE_REPRESENTATION,
|
||||
DWMWA_PASSIVE_UPDATE_MODE,
|
||||
DWMWA_USE_HOSTBACKDROPBRUSH,
|
||||
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
|
||||
DWMWA_WINDOW_CORNER_PREFERENCE = 33,
|
||||
DWMWA_BORDER_COLOR,
|
||||
DWMWA_CAPTION_COLOR,
|
||||
DWMWA_TEXT_COLOR,
|
||||
DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
|
||||
DWMWA_SYSTEMBACKDROP_TYPE,
|
||||
DWMWA_LAST,
|
||||
}
|
||||
|
||||
DWMNCRENDERINGPOLICY :: enum {
|
||||
DWMNCRP_USEWINDOWSTYLE,
|
||||
DWMNCRP_DISABLED,
|
||||
DWMNCRP_ENABLED,
|
||||
DWMNCRP_LAST,
|
||||
}
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign dwmapi {
|
||||
DwmFlush :: proc() -> HRESULT ---
|
||||
DwmIsCompositionEnabled :: proc(pfEnabled: ^BOOL) -> HRESULT ---
|
||||
DwmExtendFrameIntoClientArea :: proc(hWnd: HWND, pMarInset: PMARGINS) -> HRESULT ---
|
||||
DwmSetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: LPCVOID, cbAttribute: DWORD) -> HRESULT ---
|
||||
}
|
||||
|
||||
@@ -62,6 +62,7 @@ foreign gdi32 {
|
||||
|
||||
SetPixelFormat :: proc(hdc: HDC, format: c_int, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL ---
|
||||
ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int ---
|
||||
DescribePixelFormat :: proc(hdc: HDC, iPixelFormat: c_int, nBytes: UINT, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int ---
|
||||
SwapBuffers :: proc(HDC) -> BOOL ---
|
||||
|
||||
SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF ---
|
||||
@@ -78,6 +79,8 @@ foreign gdi32 {
|
||||
TextOutW :: proc(hdc: HDC, x, y: c_int, lpString: LPCWSTR, c: c_int) -> BOOL ---
|
||||
GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: c_int, psizl: LPSIZE) -> BOOL ---
|
||||
GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL ---
|
||||
|
||||
CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH ---
|
||||
}
|
||||
|
||||
RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF {
|
||||
|
||||
@@ -370,6 +370,8 @@ foreign kernel32 {
|
||||
lpTotalNumberOfBytes: PULARGE_INTEGER,
|
||||
lpTotalNumberOfFreeBytes: PULARGE_INTEGER,
|
||||
) -> BOOL ---
|
||||
|
||||
GetLogicalProcessorInformation :: proc(buffer: ^SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returnedLength: PDWORD) -> BOOL ---
|
||||
}
|
||||
|
||||
|
||||
@@ -999,3 +1001,49 @@ foreign kernel32 {
|
||||
ConvertThreadToFiber :: proc(lpParameter: LPVOID) -> LPVOID ---
|
||||
SwitchToFiber :: proc(lpFiber: LPVOID) ---
|
||||
}
|
||||
|
||||
LOGICAL_PROCESSOR_RELATIONSHIP :: enum c_int {
|
||||
RelationProcessorCore,
|
||||
RelationNumaNode,
|
||||
RelationCache,
|
||||
RelationProcessorPackage,
|
||||
RelationGroup,
|
||||
RelationProcessorDie,
|
||||
RelationNumaNodeEx,
|
||||
RelationProcessorModule,
|
||||
RelationAll = 0xffff,
|
||||
}
|
||||
|
||||
PROCESSOR_CACHE_TYPE :: enum c_int {
|
||||
CacheUnified,
|
||||
CacheInstruction,
|
||||
CacheData,
|
||||
CacheTrace,
|
||||
}
|
||||
|
||||
CACHE_DESCRIPTOR :: struct {
|
||||
Level: BYTE,
|
||||
Associativity: BYTE,
|
||||
LineSize: WORD,
|
||||
Size: DWORD,
|
||||
Type: PROCESSOR_CACHE_TYPE,
|
||||
}
|
||||
|
||||
ProcessorCore :: struct {
|
||||
Flags: BYTE,
|
||||
}
|
||||
NumaNode :: struct {
|
||||
NodeNumber: DWORD,
|
||||
}
|
||||
DUMMYUNIONNAME_u :: struct #raw_union {
|
||||
Core: ProcessorCore,
|
||||
Node: NumaNode,
|
||||
Cache: CACHE_DESCRIPTOR,
|
||||
Reserved: [2]ULONGLONG,
|
||||
}
|
||||
|
||||
SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct {
|
||||
ProcessorMask: ULONG_PTR,
|
||||
Relationship: LOGICAL_PROCESSOR_RELATIONSHIP,
|
||||
DummyUnion: DUMMYUNIONNAME_u,
|
||||
}
|
||||
|
||||
@@ -22,4 +22,37 @@ foreign shell32 {
|
||||
) -> c_int ---
|
||||
SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int ---
|
||||
SHGetFolderPathW :: proc(hwnd: HWND, csidl: c_int, hToken: HANDLE, dwFlags: DWORD, pszPath: LPWSTR) -> HRESULT ---
|
||||
SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR ---
|
||||
}
|
||||
|
||||
APPBARDATA :: struct {
|
||||
cbSize: DWORD,
|
||||
hWnd: HWND,
|
||||
uCallbackMessage: UINT,
|
||||
uEdge: UINT,
|
||||
rc: RECT,
|
||||
lParam: LPARAM,
|
||||
}
|
||||
PAPPBARDATA :: ^APPBARDATA
|
||||
|
||||
ABM_NEW :: 0x00000000
|
||||
ABM_REMOVE :: 0x00000001
|
||||
ABM_QUERYPOS :: 0x00000002
|
||||
ABM_SETPOS :: 0x00000003
|
||||
ABM_GETSTATE :: 0x00000004
|
||||
ABM_GETTASKBARPOS :: 0x00000005
|
||||
ABM_ACTIVATE :: 0x00000006
|
||||
ABM_GETAUTOHIDEBAR :: 0x00000007
|
||||
ABM_SETAUTOHIDEBAR :: 0x00000008
|
||||
ABM_WINDOWPOSCHANGED :: 0x0000009
|
||||
ABM_SETSTATE :: 0x0000000a
|
||||
ABN_STATECHANGE :: 0x0000000
|
||||
ABN_POSCHANGED :: 0x0000001
|
||||
ABN_FULLSCREENAPP :: 0x0000002
|
||||
ABN_WINDOWARRANGE :: 0x0000003
|
||||
ABS_AUTOHIDE :: 0x0000001
|
||||
ABS_ALWAYSONTOP :: 0x0000002
|
||||
ABE_LEFT :: 0
|
||||
ABE_TOP :: 1
|
||||
ABE_RIGHT :: 2
|
||||
ABE_BOTTOM :: 3
|
||||
|
||||
@@ -38,6 +38,7 @@ HHOOK :: distinct HANDLE
|
||||
HKEY :: distinct HANDLE
|
||||
HDESK :: distinct HANDLE
|
||||
HFONT :: distinct HANDLE
|
||||
HRGN :: distinct HANDLE
|
||||
BOOL :: distinct b32
|
||||
BYTE :: distinct u8
|
||||
BOOLEAN :: distinct b8
|
||||
@@ -1554,6 +1555,25 @@ WA_INACTIVE :: 0
|
||||
WA_ACTIVE :: 1
|
||||
WA_CLICKACTIVE :: 2
|
||||
|
||||
// Struct pointed to by WM_GETMINMAXINFO lParam
|
||||
MINMAXINFO :: struct {
|
||||
ptReserved: POINT,
|
||||
ptMaxSize: POINT,
|
||||
ptMaxPosition: POINT,
|
||||
ptMinTrackSize: POINT,
|
||||
ptMaxTrackSize: POINT,
|
||||
}
|
||||
PMINMAXINFO :: ^MINMAXINFO
|
||||
LPMINMAXINFO :: PMINMAXINFO
|
||||
|
||||
MONITORINFO :: struct {
|
||||
cbSize: DWORD,
|
||||
rcMonitor: RECT,
|
||||
rcWork: RECT,
|
||||
dwFlags: DWORD,
|
||||
}
|
||||
LPMONITORINFO :: ^MONITORINFO
|
||||
|
||||
// SetWindowsHook() codes
|
||||
WH_MIN :: -1
|
||||
WH_MSGFILTER :: -1
|
||||
|
||||
@@ -100,6 +100,7 @@ foreign user32 {
|
||||
AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL ---
|
||||
|
||||
SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL ---
|
||||
GetMonitorInfoW :: proc(hMonitor: HMONITOR, lpmi: LPMONITORINFO) -> BOOL ---
|
||||
|
||||
GetWindowDC :: proc(hWnd: HWND) -> HDC ---
|
||||
GetDC :: proc(hWnd: HWND) -> HDC ---
|
||||
@@ -122,6 +123,8 @@ foreign user32 {
|
||||
|
||||
GetKeyState :: proc(nVirtKey: c_int) -> SHORT ---
|
||||
GetAsyncKeyState :: proc(vKey: c_int) -> SHORT ---
|
||||
|
||||
GetKeyboardState :: proc(lpKeyState: PBYTE) -> BOOL ---
|
||||
|
||||
MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT ---
|
||||
|
||||
@@ -202,6 +205,17 @@ foreign user32 {
|
||||
GetRawInputDeviceList :: proc(pRawInputDeviceList: PRAWINPUTDEVICELIST, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
||||
GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
||||
RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL ---
|
||||
|
||||
SetLayeredWindowAttributes :: proc(hWnd: HWND, crKey: COLORREF, bAlpha: BYTE, dwFlags: DWORD) -> BOOL ---
|
||||
|
||||
FillRect :: proc(hDC: HDC, lprc: ^RECT, hbr: HBRUSH) -> int ---
|
||||
EqualRect :: proc(lprc1: ^RECT, lprc2: ^RECT) -> BOOL ---
|
||||
|
||||
GetWindowInfo :: proc(hwnd: HWND, pwi: PWINDOWINFO) -> BOOL ---
|
||||
GetWindowPlacement :: proc(hWnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL ---
|
||||
SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int ---
|
||||
CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN ---
|
||||
GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int ---
|
||||
}
|
||||
|
||||
CreateWindowW :: #force_inline proc "stdcall" (
|
||||
@@ -432,3 +446,27 @@ RI_MOUSE_BUTTON_5_DOWN :: 0x0100
|
||||
RI_MOUSE_BUTTON_5_UP :: 0x0200
|
||||
RI_MOUSE_WHEEL :: 0x0400
|
||||
RI_MOUSE_HWHEEL :: 0x0800
|
||||
|
||||
WINDOWPLACEMENT :: struct {
|
||||
length: UINT,
|
||||
flags: UINT,
|
||||
showCmd: UINT,
|
||||
ptMinPosition: POINT,
|
||||
ptMaxPosition: POINT,
|
||||
rcNormalPosition: RECT,
|
||||
rcDevice: RECT,
|
||||
}
|
||||
|
||||
WINDOWINFO :: struct {
|
||||
cbSize: DWORD,
|
||||
rcWindow: RECT,
|
||||
rcClient: RECT,
|
||||
dwStyle: DWORD,
|
||||
dwExStyle: DWORD,
|
||||
dwWindowStatus: DWORD,
|
||||
cxWindowBorders: UINT,
|
||||
cyWindowBorders: UINT,
|
||||
atomWindowType: ATOM,
|
||||
wCreatorVersion: WORD,
|
||||
}
|
||||
PWINDOWINFO :: ^WINDOWINFO
|
||||
@@ -0,0 +1,12 @@
|
||||
// +build windows
|
||||
package sys_windows
|
||||
|
||||
foreign import uxtheme "system:UxTheme.lib"
|
||||
|
||||
MARGINS :: distinct [4]int
|
||||
PMARGINS :: ^MARGINS
|
||||
|
||||
@(default_calling_convention="stdcall")
|
||||
foreign uxtheme {
|
||||
IsThemeActive :: proc() -> BOOL ---
|
||||
}
|
||||
@@ -0,0 +1,959 @@
|
||||
package text_match
|
||||
|
||||
import "core:runtime"
|
||||
import "core:unicode"
|
||||
import "core:unicode/utf8"
|
||||
import "core:strings"
|
||||
|
||||
MAX_CAPTURES :: 32
|
||||
|
||||
Capture :: struct {
|
||||
init: int,
|
||||
len: int,
|
||||
}
|
||||
|
||||
Match :: struct {
|
||||
byte_start, byte_end: int,
|
||||
}
|
||||
|
||||
Error :: enum {
|
||||
OK,
|
||||
OOB,
|
||||
Invalid_Capture_Index,
|
||||
Invalid_Pattern_Capture,
|
||||
Unfinished_Capture,
|
||||
Malformed_Pattern,
|
||||
Rune_Error,
|
||||
Match_Invalid,
|
||||
}
|
||||
|
||||
L_ESC :: '%'
|
||||
CAP_POSITION :: -2
|
||||
CAP_UNFINISHED :: -1
|
||||
INVALID :: -1
|
||||
|
||||
Match_State :: struct {
|
||||
src: string,
|
||||
pattern: string,
|
||||
level: int,
|
||||
capture: [MAX_CAPTURES]Capture,
|
||||
}
|
||||
|
||||
match_class :: proc(c: rune, cl: rune) -> (res: bool) {
|
||||
switch unicode.to_lower(cl) {
|
||||
case 'a': res = is_alpha(c)
|
||||
case 'c': res = is_cntrl(c)
|
||||
case 'd': res = is_digit(c)
|
||||
case 'g': res = is_graph(c)
|
||||
case 'l': res = is_lower(c)
|
||||
case 'p': res = is_punct(c)
|
||||
case 's': res = is_space(c)
|
||||
case 'u': res = is_upper(c)
|
||||
case 'w': res = is_alnum(c)
|
||||
case 'x': res = is_xdigit(c)
|
||||
case: return cl == c
|
||||
}
|
||||
|
||||
return is_lower(cl) ? res : !res
|
||||
}
|
||||
|
||||
is_alpha :: unicode.is_alpha
|
||||
is_digit :: unicode.is_digit
|
||||
is_lower :: unicode.is_lower
|
||||
is_upper :: unicode.is_upper
|
||||
is_punct :: unicode.is_punct
|
||||
is_space :: unicode.is_space
|
||||
is_cntrl :: unicode.is_control
|
||||
|
||||
is_alnum :: proc(c: rune) -> bool {
|
||||
return unicode.is_alpha(c) || unicode.is_digit(c)
|
||||
}
|
||||
|
||||
is_graph :: proc(c: rune) -> bool {
|
||||
return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || unicode.is_digit(c)
|
||||
}
|
||||
|
||||
is_xdigit :: proc(c: rune) -> bool {
|
||||
return (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') || unicode.is_digit(c)
|
||||
}
|
||||
|
||||
// find the first utf8 charater and its size, return an error if the character is an error
|
||||
utf8_peek :: proc(bytes: string) -> (c: rune, size: int, err: Error) {
|
||||
c, size = utf8.decode_rune_in_string(bytes)
|
||||
|
||||
if c == utf8.RUNE_ERROR {
|
||||
err = .Rune_Error
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// find the first utf8 charater and its size and advance the index
|
||||
// return an error if the character is an error
|
||||
utf8_advance :: proc(bytes: string, index: ^int) -> (c: rune, err: Error) {
|
||||
size: int
|
||||
c, size = utf8.decode_rune_in_string(bytes[index^:])
|
||||
|
||||
if c == utf8.RUNE_ERROR {
|
||||
err = .Rune_Error
|
||||
}
|
||||
|
||||
index^ += size
|
||||
return
|
||||
}
|
||||
|
||||
// continuation byte?
|
||||
is_cont :: proc(b: byte) -> bool {
|
||||
return b & 0xc0 == 0x80
|
||||
}
|
||||
|
||||
utf8_prev :: proc(bytes: string, a, b: int) -> int {
|
||||
b := b
|
||||
|
||||
for a < b && is_cont(bytes[b - 1]) {
|
||||
b -= 1
|
||||
}
|
||||
|
||||
return a < b ? b - 1 : a
|
||||
}
|
||||
|
||||
utf8_next :: proc(bytes: string, a: int) -> int {
|
||||
a := a
|
||||
b := len(bytes)
|
||||
|
||||
for a < b - 1 && is_cont(bytes[a + 1]) {
|
||||
a += 1
|
||||
}
|
||||
|
||||
return a < b ? a + 1 : b
|
||||
}
|
||||
|
||||
check_capture :: proc(ms: ^Match_State, l: rune) -> (int, Error) {
|
||||
l := int(l - '1')
|
||||
|
||||
if l < 0 || l >= ms.level || ms.capture[l].len == CAP_UNFINISHED {
|
||||
return 0, .Invalid_Capture_Index
|
||||
}
|
||||
|
||||
return l, .OK
|
||||
}
|
||||
|
||||
capture_to_close :: proc(ms: ^Match_State) -> (int, Error) {
|
||||
level := ms.level - 1
|
||||
|
||||
for level >= 0 {
|
||||
if ms.capture[level].len == CAP_UNFINISHED {
|
||||
return level, .OK
|
||||
}
|
||||
|
||||
level -= 1
|
||||
}
|
||||
|
||||
return 0, .Invalid_Pattern_Capture
|
||||
}
|
||||
|
||||
class_end :: proc(ms: ^Match_State, p: int) -> (step: int, err: Error) {
|
||||
step = p
|
||||
ch := utf8_advance(ms.pattern, &step) or_return
|
||||
|
||||
switch ch {
|
||||
case L_ESC:
|
||||
if step == len(ms.pattern) {
|
||||
err = .Malformed_Pattern
|
||||
return
|
||||
}
|
||||
|
||||
utf8_advance(ms.pattern, &step) or_return
|
||||
|
||||
case '[':
|
||||
// fine with step by 1
|
||||
if step + 1 < len(ms.pattern) && ms.pattern[step] == '^' {
|
||||
step += 1
|
||||
}
|
||||
|
||||
// run till end is reached
|
||||
for {
|
||||
if step == len(ms.pattern) {
|
||||
err = .Malformed_Pattern
|
||||
return
|
||||
}
|
||||
|
||||
if ms.pattern[step] == ']' {
|
||||
break
|
||||
}
|
||||
|
||||
// dont care about utf8 here
|
||||
step += 1
|
||||
|
||||
if step < len(ms.pattern) && ms.pattern[step] == L_ESC {
|
||||
// skip escapes like '%'
|
||||
step += 1
|
||||
}
|
||||
}
|
||||
|
||||
// advance last time
|
||||
step += 1
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
match_bracket_class :: proc(ms: ^Match_State, c: rune, p, ec: int) -> (sig: bool, err: Error) {
|
||||
sig = true
|
||||
p := p
|
||||
|
||||
if ms.pattern[p + 1] == '^' {
|
||||
p += 1
|
||||
sig = false
|
||||
}
|
||||
|
||||
// while inside of class range
|
||||
for p < ec {
|
||||
char := utf8_advance(ms.pattern, &p) or_return
|
||||
|
||||
// e.g. %a
|
||||
if char == L_ESC {
|
||||
next := utf8_advance(ms.pattern, &p) or_return
|
||||
|
||||
if match_class(c, next) {
|
||||
return
|
||||
}
|
||||
} else {
|
||||
next, next_size := utf8_peek(ms.pattern[p:]) or_return
|
||||
|
||||
// TODO test case for [a-???] where ??? is missing
|
||||
if next == '-' && p + next_size < len(ms.pattern) {
|
||||
// advance 2 codepoints
|
||||
p += next_size
|
||||
last := utf8_advance(ms.pattern, &p) or_return
|
||||
|
||||
if char <= c && c <= last {
|
||||
return
|
||||
}
|
||||
} else if char == c {
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sig = !sig
|
||||
return
|
||||
}
|
||||
|
||||
single_match :: proc(ms: ^Match_State, s, p, ep: int) -> (matched: bool, schar_size: int, err: Error) {
|
||||
if s >= len(ms.src) {
|
||||
return
|
||||
}
|
||||
|
||||
pchar, psize := utf8_peek(ms.pattern[p:]) or_return
|
||||
schar, ssize := utf8_peek(ms.src[s:]) or_return
|
||||
schar_size = ssize
|
||||
|
||||
switch pchar {
|
||||
case '.': matched = true
|
||||
case L_ESC:
|
||||
pchar_next, _ := utf8_peek(ms.pattern[p + psize:]) or_return
|
||||
matched = match_class(schar, pchar_next)
|
||||
case '[': matched = match_bracket_class(ms, schar, p, ep - 1) or_return
|
||||
case: matched = schar == pchar
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
match_balance :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) {
|
||||
if p >= len(ms.pattern) - 1 {
|
||||
return INVALID, .Invalid_Pattern_Capture
|
||||
}
|
||||
|
||||
schar, ssize := utf8_peek(ms.src[s:]) or_return
|
||||
pchar, psize := utf8_peek(ms.pattern[p:]) or_return
|
||||
|
||||
// skip until the src and pattern match
|
||||
if schar != pchar {
|
||||
return INVALID, .OK
|
||||
}
|
||||
|
||||
s_begin := s
|
||||
cont := 1
|
||||
s := s + ssize
|
||||
begin := pchar
|
||||
end, _ := utf8_peek(ms.pattern[p + psize:]) or_return
|
||||
|
||||
for s < len(ms.src) {
|
||||
ch := utf8_advance(ms.src, &s) or_return
|
||||
|
||||
switch ch{
|
||||
case end:
|
||||
cont -= 1
|
||||
|
||||
if cont == 0 {
|
||||
return s, .OK
|
||||
}
|
||||
|
||||
case begin:
|
||||
cont += 1
|
||||
}
|
||||
}
|
||||
|
||||
return INVALID, .OK
|
||||
}
|
||||
|
||||
max_expand :: proc(ms: ^Match_State, s, p, ep: int) -> (res: int, err: Error) {
|
||||
m := s
|
||||
|
||||
// count up matches
|
||||
for {
|
||||
matched, size := single_match(ms, m, p, ep) or_return
|
||||
|
||||
if !matched {
|
||||
break
|
||||
}
|
||||
|
||||
m += size
|
||||
}
|
||||
|
||||
for s <= m {
|
||||
result := match(ms, m, ep + 1) or_return
|
||||
|
||||
if result != INVALID {
|
||||
return result, .OK
|
||||
}
|
||||
|
||||
if s == m {
|
||||
break
|
||||
}
|
||||
|
||||
m = utf8_prev(ms.src, s, m)
|
||||
}
|
||||
|
||||
return INVALID, .OK
|
||||
}
|
||||
|
||||
min_expand :: proc(ms: ^Match_State, s, p, ep: int) -> (res: int, err: Error) {
|
||||
s := s
|
||||
|
||||
for {
|
||||
result := match(ms, s, ep + 1) or_return
|
||||
|
||||
if result != INVALID {
|
||||
return result, .OK
|
||||
} else {
|
||||
// TODO receive next step maybe?
|
||||
matched, rune_size := single_match(ms, s, p, ep) or_return
|
||||
|
||||
if matched {
|
||||
s += rune_size
|
||||
} else {
|
||||
return INVALID, .OK
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
start_capture :: proc(ms: ^Match_State, s, p, what: int) -> (res: int, err: Error) {
|
||||
level := ms.level
|
||||
|
||||
ms.capture[level].init = s
|
||||
ms.capture[level].len = what
|
||||
ms.level += 1
|
||||
|
||||
res = match(ms, s, p) or_return
|
||||
if res == INVALID {
|
||||
ms.level -= 1
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
end_capture :: proc(ms: ^Match_State, s, p: int) -> (res: int, err: Error) {
|
||||
l := capture_to_close(ms) or_return
|
||||
|
||||
// TODO double check, could do string as int index
|
||||
ms.capture[l].len = s - ms.capture[l].init
|
||||
|
||||
res = match(ms, s, p) or_return
|
||||
if res == INVALID {
|
||||
ms.capture[l].len = CAP_UNFINISHED
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
match_capture :: proc(ms: ^Match_State, s: int, char: rune) -> (res: int, err: Error) {
|
||||
index := check_capture(ms, char) or_return
|
||||
length := ms.capture[index].len
|
||||
|
||||
if len(ms.src) - s >= length {
|
||||
return s + length, .OK
|
||||
}
|
||||
|
||||
return INVALID, .OK
|
||||
}
|
||||
|
||||
match :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) {
|
||||
s := s
|
||||
p := p
|
||||
|
||||
if p == len(ms.pattern) {
|
||||
return s, .OK
|
||||
}
|
||||
|
||||
// NOTE we can walk by ascii steps if we know the characters are ascii
|
||||
char, _ := utf8_peek(ms.pattern[p:]) or_return
|
||||
switch char {
|
||||
case '(':
|
||||
if p + 1 < len(ms.pattern) && ms.pattern[p + 1] == ')' {
|
||||
s = start_capture(ms, s, p + 2, CAP_POSITION) or_return
|
||||
} else {
|
||||
s = start_capture(ms, s, p + 1, CAP_UNFINISHED) or_return
|
||||
}
|
||||
|
||||
case ')':
|
||||
s = end_capture(ms, s, p + 1) or_return
|
||||
|
||||
case '$':
|
||||
if p + 1 != len(ms.pattern) {
|
||||
return match_default(ms, s, p)
|
||||
}
|
||||
|
||||
if len(ms.src) != s {
|
||||
s = INVALID
|
||||
}
|
||||
|
||||
case L_ESC:
|
||||
// stop short patterns like "%" only
|
||||
if p + 1 >= len(ms.pattern) {
|
||||
err = .OOB
|
||||
return
|
||||
}
|
||||
|
||||
switch ms.pattern[p + 1] {
|
||||
// balanced string
|
||||
case 'b':
|
||||
s = match_balance(ms, s, p + 2) or_return
|
||||
|
||||
if s != INVALID {
|
||||
// eg after %b()
|
||||
return match(ms, s, p + 4)
|
||||
}
|
||||
|
||||
// frontier
|
||||
case 'f':
|
||||
p += 2
|
||||
|
||||
if ms.pattern[p] != '[' {
|
||||
return INVALID, .Invalid_Pattern_Capture
|
||||
}
|
||||
|
||||
ep := class_end(ms, p) or_return
|
||||
previous, current: rune
|
||||
|
||||
// get previous
|
||||
if s != 0 {
|
||||
temp := utf8_prev(ms.src, 0, s)
|
||||
previous, _ = utf8_peek(ms.src[temp:]) or_return
|
||||
}
|
||||
|
||||
// get current
|
||||
if s != len(ms.src) {
|
||||
current, _ = utf8_peek(ms.src[s:]) or_return
|
||||
}
|
||||
|
||||
m1 := match_bracket_class(ms, previous, p, ep - 1) or_return
|
||||
m2 := match_bracket_class(ms, current, p, ep - 1) or_return
|
||||
|
||||
if !m1 && m2 {
|
||||
return match(ms, s, ep)
|
||||
}
|
||||
|
||||
s = INVALID
|
||||
|
||||
// capture group
|
||||
case '0'..<'9':
|
||||
s = match_capture(ms, s, rune(ms.pattern[p + 1])) or_return
|
||||
|
||||
if s != INVALID {
|
||||
return match(ms, s, p + 2)
|
||||
}
|
||||
|
||||
case: return match_default(ms, s, p)
|
||||
}
|
||||
|
||||
case:
|
||||
return match_default(ms, s, p)
|
||||
}
|
||||
|
||||
return s, .OK
|
||||
}
|
||||
|
||||
match_default :: proc(ms: ^Match_State, s, p: int) -> (unused: int, err: Error) {
|
||||
s := s
|
||||
ep := class_end(ms, p) or_return
|
||||
single_matched, ssize := single_match(ms, s, p, ep) or_return
|
||||
|
||||
if !single_matched {
|
||||
epc := ep < len(ms.pattern) ? ms.pattern[ep] : 0
|
||||
|
||||
switch epc {
|
||||
case '*', '?', '-': return match(ms, s, ep + 1)
|
||||
case: s = INVALID
|
||||
}
|
||||
} else {
|
||||
epc := ep < len(ms.pattern) ? ms.pattern[ep] : 0
|
||||
|
||||
switch epc {
|
||||
case '?':
|
||||
result := match(ms, s + ssize, ep + 1) or_return
|
||||
|
||||
if result != INVALID {
|
||||
s = result
|
||||
} else {
|
||||
return match(ms, s, ep + 1)
|
||||
}
|
||||
|
||||
case '+': s = max_expand(ms, s + ssize, p, ep) or_return
|
||||
case '*': s = max_expand(ms, s, p, ep) or_return
|
||||
case '-': s = min_expand(ms, s, p, ep) or_return
|
||||
case: return match(ms, s + ssize, ep)
|
||||
}
|
||||
}
|
||||
|
||||
return s, .OK
|
||||
}
|
||||
|
||||
push_onecapture :: proc(ms: ^Match_State, i: int, s: int, e: int, matches: []Match) -> (err: Error) {
|
||||
if i >= ms.level {
|
||||
if i == 0 {
|
||||
matches[0] = { 0, e - s }
|
||||
} else {
|
||||
err = .Invalid_Capture_Index
|
||||
}
|
||||
} else {
|
||||
init := ms.capture[i].init
|
||||
length := ms.capture[i].len
|
||||
|
||||
switch length {
|
||||
case CAP_UNFINISHED: err = .Unfinished_Capture
|
||||
case CAP_POSITION: matches[i] = { init, init + 1 }
|
||||
case: matches[i] = { init, init + length }
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
push_captures :: proc(
|
||||
ms: ^Match_State,
|
||||
s: int,
|
||||
e: int,
|
||||
matches: []Match,
|
||||
) -> (nlevels: int, err: Error) {
|
||||
nlevels = 1 if ms.level == 0 && s != -1 else ms.level
|
||||
|
||||
for i in 0..<nlevels {
|
||||
push_onecapture(ms, i, s, e, matches) or_return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// SPECIALS := "^$*+?.([%-"
|
||||
// all special characters inside a small ascii array
|
||||
SPECIALS_TABLE := [256]bool {
|
||||
'^' = true,
|
||||
'$' = true,
|
||||
'*' = true,
|
||||
'+' = true,
|
||||
'?' = true,
|
||||
'.' = true,
|
||||
'(' = true,
|
||||
'[' = true,
|
||||
'%' = true,
|
||||
'-' = true,
|
||||
}
|
||||
|
||||
// helper call to quick search for special characters
|
||||
index_special :: proc(text: string) -> int {
|
||||
for i in 0..<len(text) {
|
||||
if SPECIALS_TABLE[text[i]] {
|
||||
return i
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
lmem_find :: proc(s1, s2: string) -> int {
|
||||
l1 := len(s1)
|
||||
l2 := len(s2)
|
||||
|
||||
if l2 == 0 {
|
||||
return 0
|
||||
} else if l2 > l1 {
|
||||
return -1
|
||||
} else {
|
||||
init := strings.index_byte(s1, s2[0])
|
||||
end := init + l2
|
||||
|
||||
for end <= l1 && init != -1 {
|
||||
init += 1
|
||||
|
||||
if s1[init - 1:end] == s2 {
|
||||
return init - 1
|
||||
} else {
|
||||
next := strings.index_byte(s1[init:], s2[0])
|
||||
|
||||
if next == -1 {
|
||||
return -1
|
||||
} else {
|
||||
init = init + next
|
||||
end = init + l2
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return -1
|
||||
}
|
||||
|
||||
// find a pattern with in a haystack with an offset
|
||||
// allow_memfind will speed up simple searches
|
||||
find_aux :: proc(
|
||||
haystack: string,
|
||||
pattern: string,
|
||||
offset: int,
|
||||
allow_memfind: bool,
|
||||
matches: ^[MAX_CAPTURES]Match,
|
||||
) -> (captures: int, err: Error) {
|
||||
s := offset
|
||||
p := 0
|
||||
|
||||
specials_idx := index_special(pattern)
|
||||
if allow_memfind && specials_idx == -1 {
|
||||
if index := lmem_find(haystack[s:], pattern); index != -1 {
|
||||
matches[0] = { index + s, index + s + len(pattern) }
|
||||
captures = 1
|
||||
return
|
||||
} else {
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
pattern := pattern
|
||||
anchor: bool
|
||||
if len(pattern) > 0 && pattern[0] == '^' {
|
||||
anchor = true
|
||||
pattern = pattern[1:]
|
||||
}
|
||||
|
||||
ms := Match_State {
|
||||
src = haystack,
|
||||
pattern = pattern,
|
||||
}
|
||||
|
||||
for {
|
||||
res := match(&ms, s, p) or_return
|
||||
|
||||
if res != INVALID {
|
||||
// disallow non advancing match
|
||||
if s == res {
|
||||
err = .Match_Invalid
|
||||
}
|
||||
|
||||
// NOTE(Skytrias): first result is reserved for a full match
|
||||
matches[0] = { s, res }
|
||||
|
||||
// rest are the actual captures
|
||||
captures = push_captures(&ms, -1, -1, matches[1:]) or_return
|
||||
captures += 1
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
s += 1
|
||||
|
||||
if !(s < len(ms.src) && !anchor) {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// iterative matching which returns the 0th/1st match
|
||||
// rest has to be used from captures
|
||||
gmatch :: proc(
|
||||
haystack: ^string,
|
||||
pattern: string,
|
||||
captures: ^[MAX_CAPTURES]Match,
|
||||
) -> (res: string, ok: bool) {
|
||||
if len(haystack) > 0 {
|
||||
length, err := find_aux(haystack^, pattern, 0, false, captures)
|
||||
|
||||
if length != 0 && err == .OK {
|
||||
ok = true
|
||||
first := length > 1 ? 1 : 0
|
||||
cap := captures[first]
|
||||
res = haystack[cap.byte_start:cap.byte_end]
|
||||
haystack^ = haystack[cap.byte_end:]
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// gsub with builder, replace patterns found with the replace content
|
||||
gsub_builder :: proc(
|
||||
builder: ^strings.Builder,
|
||||
haystack: string,
|
||||
pattern: string,
|
||||
replace: string,
|
||||
) -> string {
|
||||
// find matches
|
||||
captures: [MAX_CAPTURES]Match
|
||||
haystack := haystack
|
||||
|
||||
for {
|
||||
length, err := find_aux(haystack, pattern, 0, false, &captures)
|
||||
|
||||
// done
|
||||
if length == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
if err != .OK {
|
||||
return {}
|
||||
}
|
||||
|
||||
cap := captures[0]
|
||||
|
||||
// write front till capture
|
||||
strings.write_string(builder, haystack[:cap.byte_start])
|
||||
|
||||
// write replacements
|
||||
strings.write_string(builder, replace)
|
||||
|
||||
// advance string till end
|
||||
haystack = haystack[cap.byte_end:]
|
||||
}
|
||||
|
||||
strings.write_string(builder, haystack[:])
|
||||
return strings.to_string(builder^)
|
||||
}
|
||||
|
||||
// uses temp builder to build initial string - then allocates the result
|
||||
gsub_allocator :: proc(
|
||||
haystack: string,
|
||||
pattern: string,
|
||||
replace: string,
|
||||
allocator := context.allocator,
|
||||
) -> string {
|
||||
builder := strings.builder_make(0, 256, context.temp_allocator)
|
||||
return gsub_builder(&builder, haystack, pattern, replace)
|
||||
}
|
||||
|
||||
Gsub_Proc :: proc(
|
||||
// optional passed data
|
||||
data: rawptr,
|
||||
// word match found
|
||||
word: string,
|
||||
// current haystack for found captures
|
||||
haystack: string,
|
||||
// found captures - empty for no captures
|
||||
captures: []Match,
|
||||
)
|
||||
|
||||
// call a procedure on every match in the haystack
|
||||
gsub_with :: proc(
|
||||
haystack: string,
|
||||
pattern: string,
|
||||
data: rawptr,
|
||||
call: Gsub_Proc,
|
||||
) {
|
||||
// find matches
|
||||
captures: [MAX_CAPTURES]Match
|
||||
haystack := haystack
|
||||
|
||||
for {
|
||||
length, err := find_aux(haystack, pattern, 0, false, &captures)
|
||||
|
||||
// done
|
||||
if length == 0 || err != .OK {
|
||||
break
|
||||
}
|
||||
|
||||
cap := captures[0]
|
||||
|
||||
word := haystack[cap.byte_start:cap.byte_end]
|
||||
call(data, word, haystack, captures[1:length])
|
||||
|
||||
// advance string till end
|
||||
haystack = haystack[cap.byte_end:]
|
||||
}
|
||||
}
|
||||
|
||||
gsub :: proc { gsub_builder, gsub_allocator }
|
||||
|
||||
// iterative find with zeroth capture only
|
||||
gfind :: proc(
|
||||
haystack: ^string,
|
||||
pattern: string,
|
||||
captures: ^[MAX_CAPTURES]Match,
|
||||
) -> (res: string, ok: bool) {
|
||||
if len(haystack) > 0 {
|
||||
length, err := find_aux(haystack^, pattern, 0, true, captures)
|
||||
|
||||
if length != 0 && err == .OK {
|
||||
ok = true
|
||||
cap := captures[0]
|
||||
res = haystack[cap.byte_start:cap.byte_end]
|
||||
haystack^ = haystack[cap.byte_end:]
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// rebuilds a pattern into a case insensitive pattern
|
||||
pattern_case_insensitive_builder :: proc(
|
||||
builder: ^strings.Builder,
|
||||
pattern: string,
|
||||
) -> (res: string) {
|
||||
p := pattern
|
||||
last_percent: bool
|
||||
|
||||
for len(p) > 0 {
|
||||
char, size := utf8.decode_rune_in_string(p)
|
||||
|
||||
if unicode.is_alpha(char) && !last_percent {
|
||||
// write character class in manually
|
||||
strings.write_byte(builder, '[')
|
||||
strings.write_rune(builder, unicode.to_lower(char))
|
||||
strings.write_rune(builder, unicode.to_upper(char))
|
||||
strings.write_byte(builder, ']')
|
||||
} else {
|
||||
strings.write_rune(builder, char)
|
||||
}
|
||||
|
||||
last_percent = char == L_ESC
|
||||
p = p[size:]
|
||||
}
|
||||
|
||||
return strings.to_string(builder^)
|
||||
}
|
||||
|
||||
pattern_case_insensitive_allocator :: proc(
|
||||
pattern: string,
|
||||
cap: int = 256,
|
||||
allocator := context.allocator,
|
||||
) -> (res: string) {
|
||||
builder := strings.builder_make(0, cap, context.temp_allocator)
|
||||
return pattern_case_insensitive_builder(&builder, pattern)
|
||||
}
|
||||
|
||||
pattern_case_insensitive :: proc { pattern_case_insensitive_builder, pattern_case_insensitive_allocator }
|
||||
|
||||
// Matcher helper struct that stores optional data you might want to use or not
|
||||
// as lua is far more dynamic this helps dealing with too much data
|
||||
// this also allows use of find/match/gmatch at through one struct
|
||||
Matcher :: struct {
|
||||
haystack: string,
|
||||
pattern: string,
|
||||
captures: [MAX_CAPTURES]Match,
|
||||
captures_length: int,
|
||||
offset: int,
|
||||
err: Error,
|
||||
|
||||
// changing content for iterators
|
||||
iter: string,
|
||||
iter_index: int,
|
||||
}
|
||||
|
||||
// init using haystack & pattern and an optional byte offset
|
||||
matcher_init :: proc(haystack, pattern: string, offset: int = 0) -> (res: Matcher) {
|
||||
res.haystack = haystack
|
||||
res.pattern = pattern
|
||||
res.offset = offset
|
||||
res.iter = haystack
|
||||
return
|
||||
}
|
||||
|
||||
// find the first match and return the byte start / end position in the string, true on success
|
||||
matcher_find :: proc(matcher: ^Matcher) -> (start, end: int, ok: bool) #no_bounds_check {
|
||||
matcher.captures_length, matcher.err = find_aux(
|
||||
matcher.haystack,
|
||||
matcher.pattern,
|
||||
matcher.offset,
|
||||
true,
|
||||
&matcher.captures,
|
||||
)
|
||||
ok = matcher.captures_length > 0 && matcher.err == .OK
|
||||
match := matcher.captures[0]
|
||||
start = match.byte_start
|
||||
end = match.byte_end
|
||||
return
|
||||
}
|
||||
|
||||
// find the first match and return the matched word, true on success
|
||||
matcher_match :: proc(matcher: ^Matcher) -> (word: string, ok: bool) #no_bounds_check {
|
||||
matcher.captures_length, matcher.err = find_aux(
|
||||
matcher.haystack,
|
||||
matcher.pattern,
|
||||
matcher.offset,
|
||||
false,
|
||||
&matcher.captures,
|
||||
)
|
||||
ok = matcher.captures_length > 0 && matcher.err == .OK
|
||||
match := matcher.captures[0]
|
||||
word = matcher.haystack[match.byte_start:match.byte_end]
|
||||
return
|
||||
}
|
||||
|
||||
// get the capture at the "correct" spot, as spot 0 is reserved for the first match
|
||||
matcher_capture :: proc(matcher: ^Matcher, index: int, loc := #caller_location) -> string #no_bounds_check {
|
||||
runtime.bounds_check_error_loc(loc, index + 1, MAX_CAPTURES - 1)
|
||||
cap := matcher.captures[index + 1]
|
||||
return matcher.haystack[cap.byte_start:cap.byte_end]
|
||||
}
|
||||
|
||||
// get the raw match out of the captures, skipping spot 0
|
||||
matcher_capture_raw :: proc(matcher: ^Matcher, index: int, loc := #caller_location) -> Match #no_bounds_check {
|
||||
runtime.bounds_check_error_loc(loc, index + 1, MAX_CAPTURES - 1)
|
||||
return matcher.captures[index + 1]
|
||||
}
|
||||
|
||||
// alias
|
||||
matcher_gmatch :: matcher_match_iter
|
||||
|
||||
// iteratively match the haystack till it cant find any matches
|
||||
matcher_match_iter :: proc(matcher: ^Matcher) -> (res: string, index: int, ok: bool) {
|
||||
if len(matcher.iter) > 0 {
|
||||
matcher.captures_length, matcher.err = find_aux(
|
||||
matcher.iter,
|
||||
matcher.pattern,
|
||||
matcher.offset,
|
||||
false,
|
||||
&matcher.captures,
|
||||
)
|
||||
|
||||
if matcher.captures_length != 0 && matcher.err == .OK {
|
||||
ok = true
|
||||
first := matcher.captures_length > 1 ? 1 : 0
|
||||
match := matcher.captures[first]
|
||||
|
||||
// output
|
||||
res = matcher.iter[match.byte_start:match.byte_end]
|
||||
index = matcher.iter_index
|
||||
|
||||
// advance
|
||||
matcher.iter_index += 1
|
||||
matcher.iter = matcher.iter[match.byte_end:]
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
// get a slice of all valid captures above the first match
|
||||
matcher_captures_slice :: proc(matcher: ^Matcher) -> []Match {
|
||||
return matcher.captures[1:matcher.captures_length]
|
||||
}
|
||||
+76
-76
@@ -10,45 +10,45 @@ struct Array {
|
||||
|
||||
T &operator[](isize index) {
|
||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
GB_ASSERT_MSG(cast(usize)index < cast(usize)count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
|
||||
T const &operator[](isize index) const {
|
||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
GB_ASSERT_MSG(cast(usize)index < cast(usize)count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> void array_init (Array<T> *array, gbAllocator const &a);
|
||||
template <typename T> void array_init (Array<T> *array, gbAllocator const &a, isize count);
|
||||
template <typename T> void array_init (Array<T> *array, gbAllocator const &a, isize count, isize capacity);
|
||||
template <typename T> Array<T> array_make (gbAllocator const &a);
|
||||
template <typename T> Array<T> array_make (gbAllocator const &a, isize count);
|
||||
template <typename T> Array<T> array_make (gbAllocator const &a, isize count, isize capacity);
|
||||
template <typename T> Array<T> array_make_from_ptr (T *data, isize count, isize capacity);
|
||||
template <typename T> void array_free (Array<T> *array);
|
||||
template <typename T> void array_add (Array<T> *array, T const &t);
|
||||
template <typename T> T * array_add_and_get (Array<T> *array);
|
||||
template <typename T> void array_add_elems (Array<T> *array, T const *elems, isize elem_count);
|
||||
template <typename T> T array_pop (Array<T> *array);
|
||||
template <typename T> void array_clear (Array<T> *array);
|
||||
template <typename T> void array_reserve (Array<T> *array, isize capacity);
|
||||
template <typename T> void array_resize (Array<T> *array, isize count);
|
||||
template <typename T> void array_set_capacity (Array<T> *array, isize capacity);
|
||||
template <typename T> Array<T> array_slice (Array<T> const &array, isize lo, isize hi);
|
||||
template <typename T> Array<T> array_clone (gbAllocator const &a, Array<T> const &array);
|
||||
template <typename T> gb_internal void array_init (Array<T> *array, gbAllocator const &a);
|
||||
template <typename T> gb_internal void array_init (Array<T> *array, gbAllocator const &a, isize count);
|
||||
template <typename T> gb_internal void array_init (Array<T> *array, gbAllocator const &a, isize count, isize capacity);
|
||||
template <typename T> gb_internal Array<T> array_make (gbAllocator const &a);
|
||||
template <typename T> gb_internal Array<T> array_make (gbAllocator const &a, isize count);
|
||||
template <typename T> gb_internal Array<T> array_make (gbAllocator const &a, isize count, isize capacity);
|
||||
template <typename T> gb_internal Array<T> array_make_from_ptr (T *data, isize count, isize capacity);
|
||||
template <typename T> gb_internal void array_free (Array<T> *array);
|
||||
template <typename T> gb_internal void array_add (Array<T> *array, T const &t);
|
||||
template <typename T> gb_internal T * array_add_and_get (Array<T> *array);
|
||||
template <typename T> gb_internal void array_add_elems (Array<T> *array, T const *elems, isize elem_count);
|
||||
template <typename T> gb_internal T array_pop (Array<T> *array);
|
||||
template <typename T> gb_internal void array_clear (Array<T> *array);
|
||||
template <typename T> gb_internal void array_reserve (Array<T> *array, isize capacity);
|
||||
template <typename T> gb_internal void array_resize (Array<T> *array, isize count);
|
||||
template <typename T> gb_internal void array_set_capacity (Array<T> *array, isize capacity);
|
||||
template <typename T> gb_internal Array<T> array_slice (Array<T> const &array, isize lo, isize hi);
|
||||
template <typename T> gb_internal Array<T> array_clone (gbAllocator const &a, Array<T> const &array);
|
||||
|
||||
template <typename T> void array_ordered_remove (Array<T> *array, isize index);
|
||||
template <typename T> void array_unordered_remove(Array<T> *array, isize index);
|
||||
template <typename T> gb_internal void array_ordered_remove (Array<T> *array, isize index);
|
||||
template <typename T> gb_internal void array_unordered_remove(Array<T> *array, isize index);
|
||||
|
||||
template <typename T> void array_copy(Array<T> *array, Array<T> const &data, isize offset);
|
||||
template <typename T> void array_copy(Array<T> *array, Array<T> const &data, isize offset, isize count);
|
||||
template <typename T> gb_internal void array_copy(Array<T> *array, Array<T> const &data, isize offset);
|
||||
template <typename T> gb_internal void array_copy(Array<T> *array, Array<T> const &data, isize offset, isize count);
|
||||
|
||||
template <typename T> T *array_end_ptr(Array<T> *array);
|
||||
template <typename T> gb_internal T *array_end_ptr(Array<T> *array);
|
||||
|
||||
|
||||
template <typename T>
|
||||
@@ -56,27 +56,27 @@ struct Slice {
|
||||
T *data;
|
||||
isize count;
|
||||
|
||||
T &operator[](isize index) {
|
||||
gb_inline T &operator[](isize index) {
|
||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
GB_ASSERT_MSG(cast(usize)index < cast(usize)count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
|
||||
T const &operator[](isize index) const {
|
||||
gb_inline T const &operator[](isize index) const {
|
||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
||||
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
GB_ASSERT_MSG(cast(usize)index < cast(usize)count, "Index %td is out of bounds ranges 0..<%td", index, count);
|
||||
#endif
|
||||
return data[index];
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T> Slice<T> slice_from_array(Array<T> const &a);
|
||||
template <typename T> gb_internal Slice<T> slice_from_array(Array<T> const &a);
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
Slice<T> slice_make(gbAllocator const &allocator, isize count) {
|
||||
gb_internal Slice<T> slice_make(gbAllocator const &allocator, isize count) {
|
||||
GB_ASSERT(count >= 0);
|
||||
Slice<T> s = {};
|
||||
s.data = gb_alloc_array(allocator, T, count);
|
||||
@@ -86,7 +86,7 @@ Slice<T> slice_make(gbAllocator const &allocator, isize count) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void slice_init(Slice<T> *s, gbAllocator const &allocator, isize count) {
|
||||
gb_internal void slice_init(Slice<T> *s, gbAllocator const &allocator, isize count) {
|
||||
GB_ASSERT(count >= 0);
|
||||
s->data = gb_alloc_array(allocator, T, count);
|
||||
if (count > 0) {
|
||||
@@ -96,23 +96,23 @@ void slice_init(Slice<T> *s, gbAllocator const &allocator, isize count) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void slice_free(Slice<T> *s, gbAllocator const &allocator) {
|
||||
gb_internal void slice_free(Slice<T> *s, gbAllocator const &allocator) {
|
||||
gb_free(allocator, s->data);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void slice_resize(Slice<T> *s, gbAllocator const &allocator, isize new_count) {
|
||||
gb_internal void slice_resize(Slice<T> *s, gbAllocator const &allocator, isize new_count) {
|
||||
resize_array_raw(&s->data, allocator, s->count, new_count);
|
||||
s->count = new_count;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
Slice<T> slice_from_array(Array<T> const &a) {
|
||||
gb_internal Slice<T> slice_from_array(Array<T> const &a) {
|
||||
return {a.data, a.count};
|
||||
}
|
||||
template <typename T>
|
||||
Slice<T> slice_array(Array<T> const &array, isize lo, isize hi) {
|
||||
gb_internal Slice<T> slice_array(Array<T> const &array, isize lo, isize hi) {
|
||||
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
|
||||
Slice<T> out = {};
|
||||
isize len = hi-lo;
|
||||
@@ -125,30 +125,30 @@ Slice<T> slice_array(Array<T> const &array, isize lo, isize hi) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
Slice<T> slice_clone(gbAllocator const &allocator, Slice<T> const &a) {
|
||||
gb_internal Slice<T> slice_clone(gbAllocator const &allocator, Slice<T> const &a) {
|
||||
T *data = cast(T *)gb_alloc_copy_align(allocator, a.data, a.count*gb_size_of(T), gb_align_of(T));
|
||||
return {data, a.count};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Slice<T> slice_clone_from_array(gbAllocator const &allocator, Array<T> const &a) {
|
||||
gb_internal Slice<T> slice_clone_from_array(gbAllocator const &allocator, Array<T> const &a) {
|
||||
auto c = array_clone(allocator, a);
|
||||
return {c.data, c.count};
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void slice_copy(Slice<T> *slice, Slice<T> const &data) {
|
||||
gb_internal void slice_copy(Slice<T> *slice, Slice<T> const &data) {
|
||||
isize n = gb_min(slice->count, data.count);
|
||||
gb_memmove(slice->data, data.data, gb_size_of(T)*n);
|
||||
}
|
||||
template <typename T>
|
||||
void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset) {
|
||||
gb_internal void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset) {
|
||||
isize n = gb_clamp(slice->count-offset, 0, data.count);
|
||||
gb_memmove(slice->data+offset, data.data, gb_size_of(T)*n);
|
||||
}
|
||||
template <typename T>
|
||||
void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset, isize count) {
|
||||
gb_internal void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset, isize count) {
|
||||
isize n = gb_clamp(slice->count-offset, 0, gb_min(data.count, count));
|
||||
gb_memmove(slice->data+offset, data.data, gb_size_of(T)*n);
|
||||
}
|
||||
@@ -156,7 +156,7 @@ void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset, isize count
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi) {
|
||||
gb_internal gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi) {
|
||||
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
|
||||
Slice<T> out = {};
|
||||
isize len = hi-lo;
|
||||
@@ -169,7 +169,7 @@ gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void slice_ordered_remove(Slice<T> *array, isize index) {
|
||||
gb_internal void slice_ordered_remove(Slice<T> *array, isize index) {
|
||||
GB_ASSERT(0 <= index && index < array->count);
|
||||
|
||||
isize bytes = gb_size_of(T) * (array->count-(index+1));
|
||||
@@ -178,7 +178,7 @@ void slice_ordered_remove(Slice<T> *array, isize index) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void slice_unordered_remove(Slice<T> *array, isize index) {
|
||||
gb_internal void slice_unordered_remove(Slice<T> *array, isize index) {
|
||||
GB_ASSERT(0 <= index && index < array->count);
|
||||
|
||||
isize n = array->count-1;
|
||||
@@ -190,18 +190,18 @@ void slice_unordered_remove(Slice<T> *array, isize index) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void array_copy(Array<T> *array, Array<T> const &data, isize offset) {
|
||||
gb_internal void array_copy(Array<T> *array, Array<T> const &data, isize offset) {
|
||||
gb_memmove(array->data+offset, data.data, gb_size_of(T)*data.count);
|
||||
}
|
||||
template <typename T>
|
||||
void array_copy(Array<T> *array, Array<T> const &data, isize offset, isize count) {
|
||||
gb_internal void array_copy(Array<T> *array, Array<T> const &data, isize offset, isize count) {
|
||||
gb_memmove(array->data+offset, data.data, gb_size_of(T)*gb_min(data.count, count));
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <typename T>
|
||||
T *array_end_ptr(Array<T> *array) {
|
||||
gb_internal T *array_end_ptr(Array<T> *array) {
|
||||
if (array->count > 0) {
|
||||
return &array->data[array->count-1];
|
||||
}
|
||||
@@ -210,18 +210,18 @@ T *array_end_ptr(Array<T> *array) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline void array_init(Array<T> *array, gbAllocator const &a) {
|
||||
gb_internal gb_inline void array_init(Array<T> *array, gbAllocator const &a) {
|
||||
isize cap = ARRAY_GROW_FORMULA(0);
|
||||
array_init(array, a, 0, cap);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count) {
|
||||
gb_internal gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count) {
|
||||
array_init(array, a, count, count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count, isize capacity) {
|
||||
gb_internal gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count, isize capacity) {
|
||||
array->allocator = a;
|
||||
array->data = nullptr;
|
||||
if (capacity > 0) {
|
||||
@@ -234,7 +234,7 @@ gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count, is
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline Array<T> array_make_from_ptr(T *data, isize count, isize capacity) {
|
||||
gb_internal gb_inline Array<T> array_make_from_ptr(T *data, isize count, isize capacity) {
|
||||
Array<T> a = {0};
|
||||
a.data = data;
|
||||
a.count = count;
|
||||
@@ -244,7 +244,7 @@ gb_inline Array<T> array_make_from_ptr(T *data, isize count, isize capacity) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline Array<T> array_make(gbAllocator const &a) {
|
||||
gb_internal gb_inline Array<T> array_make(gbAllocator const &a) {
|
||||
isize capacity = ARRAY_GROW_FORMULA(0);
|
||||
Array<T> array = {};
|
||||
array.allocator = a;
|
||||
@@ -254,7 +254,7 @@ gb_inline Array<T> array_make(gbAllocator const &a) {
|
||||
return array;
|
||||
}
|
||||
template <typename T>
|
||||
gb_inline Array<T> array_make(gbAllocator const &a, isize count) {
|
||||
gb_internal gb_inline Array<T> array_make(gbAllocator const &a, isize count) {
|
||||
Array<T> array = {};
|
||||
array.allocator = a;
|
||||
array.data = gb_alloc_array(a, T, count);
|
||||
@@ -263,7 +263,7 @@ gb_inline Array<T> array_make(gbAllocator const &a, isize count) {
|
||||
return array;
|
||||
}
|
||||
template <typename T>
|
||||
gb_inline Array<T> array_make(gbAllocator const &a, isize count, isize capacity) {
|
||||
gb_internal gb_inline Array<T> array_make(gbAllocator const &a, isize count, isize capacity) {
|
||||
Array<T> array = {};
|
||||
array.allocator = a;
|
||||
array.data = gb_alloc_array(a, T, capacity);
|
||||
@@ -275,7 +275,7 @@ gb_inline Array<T> array_make(gbAllocator const &a, isize count, isize capacity)
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline void array_free(Array<T> *array) {
|
||||
gb_internal gb_inline void array_free(Array<T> *array) {
|
||||
if (array->allocator.proc != nullptr) {
|
||||
gb_free(array->allocator, array->data);
|
||||
}
|
||||
@@ -284,7 +284,7 @@ gb_inline void array_free(Array<T> *array) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void array__grow(Array<T> *array, isize min_capacity) {
|
||||
gb_internal void array__grow(Array<T> *array, isize min_capacity) {
|
||||
isize new_capacity = ARRAY_GROW_FORMULA(array->capacity);
|
||||
if (new_capacity < min_capacity) {
|
||||
new_capacity = min_capacity;
|
||||
@@ -293,7 +293,7 @@ void array__grow(Array<T> *array, isize min_capacity) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void array_add(Array<T> *array, T const &t) {
|
||||
gb_internal void array_add(Array<T> *array, T const &t) {
|
||||
if (array->capacity < array->count+1) {
|
||||
array__grow(array, 0);
|
||||
}
|
||||
@@ -302,7 +302,7 @@ void array_add(Array<T> *array, T const &t) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *array_add_and_get(Array<T> *array) {
|
||||
gb_internal T *array_add_and_get(Array<T> *array) {
|
||||
if (array->count < array->capacity) {
|
||||
return &array->data[array->count++];
|
||||
}
|
||||
@@ -314,7 +314,7 @@ T *array_add_and_get(Array<T> *array) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void array_add_elems(Array<T> *array, T const *elems, isize elem_count) {
|
||||
gb_internal void array_add_elems(Array<T> *array, T const *elems, isize elem_count) {
|
||||
GB_ASSERT(elem_count >= 0);
|
||||
if (array->capacity < array->count+elem_count) {
|
||||
array__grow(array, array->count+elem_count);
|
||||
@@ -325,26 +325,26 @@ void array_add_elems(Array<T> *array, T const *elems, isize elem_count) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline T array_pop(Array<T> *array) {
|
||||
gb_internal gb_inline T array_pop(Array<T> *array) {
|
||||
GB_ASSERT(array->count > 0);
|
||||
array->count--;
|
||||
return array->data[array->count];
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void array_clear(Array<T> *array) {
|
||||
gb_internal void array_clear(Array<T> *array) {
|
||||
array->count = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void array_reserve(Array<T> *array, isize capacity) {
|
||||
gb_internal void array_reserve(Array<T> *array, isize capacity) {
|
||||
if (array->capacity < capacity) {
|
||||
array_set_capacity(array, capacity);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void array_resize(Array<T> *array, isize count) {
|
||||
gb_internal void array_resize(Array<T> *array, isize count) {
|
||||
if (array->capacity < count) {
|
||||
array__grow(array, count);
|
||||
}
|
||||
@@ -352,7 +352,7 @@ void array_resize(Array<T> *array, isize count) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void array_set_capacity(Array<T> *array, isize capacity) {
|
||||
gb_internal void array_set_capacity(Array<T> *array, isize capacity) {
|
||||
if (capacity == array->capacity) {
|
||||
return;
|
||||
}
|
||||
@@ -381,7 +381,7 @@ void array_set_capacity(Array<T> *array, isize capacity) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_inline Array<T> array_slice(Array<T> const &array, isize lo, isize hi) {
|
||||
gb_internal gb_inline Array<T> array_slice(Array<T> const &array, isize lo, isize hi) {
|
||||
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
|
||||
Array<T> out = {};
|
||||
isize len = hi-lo;
|
||||
@@ -394,7 +394,7 @@ gb_inline Array<T> array_slice(Array<T> const &array, isize lo, isize hi) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
Array<T> array_clone(gbAllocator const &allocator, Array<T> const &array) {
|
||||
gb_internal Array<T> array_clone(gbAllocator const &allocator, Array<T> const &array) {
|
||||
auto clone = array_make<T>(allocator, array.count, array.count);
|
||||
array_copy(&clone, array, 0);
|
||||
return clone;
|
||||
@@ -402,7 +402,7 @@ Array<T> array_clone(gbAllocator const &allocator, Array<T> const &array) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void array_ordered_remove(Array<T> *array, isize index) {
|
||||
gb_internal void array_ordered_remove(Array<T> *array, isize index) {
|
||||
GB_ASSERT(0 <= index && index < array->count);
|
||||
|
||||
isize bytes = gb_size_of(T) * (array->count-(index+1));
|
||||
@@ -411,7 +411,7 @@ void array_ordered_remove(Array<T> *array, isize index) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void array_unordered_remove(Array<T> *array, isize index) {
|
||||
gb_internal void array_unordered_remove(Array<T> *array, isize index) {
|
||||
GB_ASSERT(0 <= index && index < array->count);
|
||||
|
||||
isize n = array->count-1;
|
||||
@@ -424,35 +424,35 @@ void array_unordered_remove(Array<T> *array, isize index) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
T *begin(Array<T> &array) {
|
||||
gb_internal T *begin(Array<T> &array) {
|
||||
return array.data;
|
||||
}
|
||||
template <typename T>
|
||||
T const *begin(Array<T> const &array) {
|
||||
gb_internal T const *begin(Array<T> const &array) {
|
||||
return array.data;
|
||||
}
|
||||
template <typename T>
|
||||
T *end(Array<T> &array) {
|
||||
gb_internal T *end(Array<T> &array) {
|
||||
return array.data + array.count;
|
||||
}
|
||||
template <typename T>
|
||||
T const *end(Array<T> const &array) {
|
||||
gb_internal T const *end(Array<T> const &array) {
|
||||
return array.data + array.count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *begin(Slice<T> &array) {
|
||||
gb_internal T *begin(Slice<T> &array) {
|
||||
return array.data;
|
||||
}
|
||||
template <typename T>
|
||||
T const *begin(Slice<T> const &array) {
|
||||
gb_internal T const *begin(Slice<T> const &array) {
|
||||
return array.data;
|
||||
}
|
||||
template <typename T>
|
||||
T *end(Slice<T> &array) {
|
||||
gb_internal T *end(Slice<T> &array) {
|
||||
return array.data + array.count;
|
||||
}
|
||||
template <typename T>
|
||||
T const *end(Slice<T> const &array) {
|
||||
gb_internal T const *end(Slice<T> const &array) {
|
||||
return array.data + array.count;
|
||||
}
|
||||
|
||||
+131
-107
@@ -37,86 +37,86 @@ void MP_FREE(void *mem, size_t size) {
|
||||
|
||||
typedef mp_int BigInt;
|
||||
|
||||
void big_int_from_u64(BigInt *dst, u64 x);
|
||||
void big_int_from_i64(BigInt *dst, i64 x);
|
||||
void big_int_init (BigInt *dst, BigInt const *src);
|
||||
void big_int_from_string(BigInt *dst, String const &s, bool *success);
|
||||
gb_internal void big_int_from_u64(BigInt *dst, u64 x);
|
||||
gb_internal void big_int_from_i64(BigInt *dst, i64 x);
|
||||
gb_internal void big_int_init (BigInt *dst, BigInt const *src);
|
||||
gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success);
|
||||
|
||||
void big_int_dealloc(BigInt *dst) {
|
||||
gb_internal void big_int_dealloc(BigInt *dst) {
|
||||
mp_clear(dst);
|
||||
}
|
||||
|
||||
BigInt big_int_make(BigInt const *b, bool abs=false);
|
||||
BigInt big_int_make_abs(BigInt const *b);
|
||||
BigInt big_int_make_u64(u64 x);
|
||||
BigInt big_int_make_i64(i64 x);
|
||||
gb_internal BigInt big_int_make(BigInt const *b, bool abs=false);
|
||||
gb_internal BigInt big_int_make_abs(BigInt const *b);
|
||||
gb_internal BigInt big_int_make_u64(u64 x);
|
||||
gb_internal BigInt big_int_make_i64(i64 x);
|
||||
|
||||
u64 big_int_to_u64 (BigInt const *x);
|
||||
i64 big_int_to_i64 (BigInt const *x);
|
||||
f64 big_int_to_f64 (BigInt const *x);
|
||||
String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base = 10);
|
||||
gb_internal u64 big_int_to_u64 (BigInt const *x);
|
||||
gb_internal i64 big_int_to_i64 (BigInt const *x);
|
||||
gb_internal f64 big_int_to_f64 (BigInt const *x);
|
||||
gb_internal String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base = 10);
|
||||
|
||||
void big_int_add (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
void big_int_sub (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
void big_int_shl (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
void big_int_shr (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
void big_int_mul (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y);
|
||||
gb_internal void big_int_add (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_sub (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_shl (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_shr (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_mul (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y);
|
||||
|
||||
void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q, BigInt *r);
|
||||
void big_int_quo (BigInt *z, BigInt const *x, BigInt const *y);
|
||||
void big_int_rem (BigInt *z, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q, BigInt *r);
|
||||
gb_internal void big_int_quo (BigInt *z, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_rem (BigInt *z, BigInt const *x, BigInt const *y);
|
||||
|
||||
void big_int_and (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
void big_int_xor (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
void big_int_or (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
void big_int_not (BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed);
|
||||
gb_internal void big_int_and (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_xor (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_or (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||
gb_internal void big_int_not (BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed);
|
||||
|
||||
|
||||
void big_int_add_eq(BigInt *dst, BigInt const *x);
|
||||
void big_int_sub_eq(BigInt *dst, BigInt const *x);
|
||||
void big_int_shl_eq(BigInt *dst, BigInt const *x);
|
||||
void big_int_shr_eq(BigInt *dst, BigInt const *x);
|
||||
void big_int_mul_eq(BigInt *dst, BigInt const *x);
|
||||
gb_internal void big_int_add_eq(BigInt *dst, BigInt const *x);
|
||||
gb_internal void big_int_sub_eq(BigInt *dst, BigInt const *x);
|
||||
gb_internal void big_int_shl_eq(BigInt *dst, BigInt const *x);
|
||||
gb_internal void big_int_shr_eq(BigInt *dst, BigInt const *x);
|
||||
gb_internal void big_int_mul_eq(BigInt *dst, BigInt const *x);
|
||||
|
||||
void big_int_quo_eq(BigInt *dst, BigInt const *x);
|
||||
void big_int_rem_eq(BigInt *dst, BigInt const *x);
|
||||
gb_internal void big_int_quo_eq(BigInt *dst, BigInt const *x);
|
||||
gb_internal void big_int_rem_eq(BigInt *dst, BigInt const *x);
|
||||
|
||||
bool big_int_is_neg(BigInt const *x);
|
||||
void big_int_neg(BigInt *dst, BigInt const *x);
|
||||
gb_internal bool big_int_is_neg(BigInt const *x);
|
||||
gb_internal void big_int_neg(BigInt *dst, BigInt const *x);
|
||||
|
||||
void big_int_add_eq(BigInt *dst, BigInt const *x) {
|
||||
gb_internal void big_int_add_eq(BigInt *dst, BigInt const *x) {
|
||||
BigInt res = {};
|
||||
big_int_init(&res, dst);
|
||||
big_int_add(dst, &res, x);
|
||||
}
|
||||
void big_int_sub_eq(BigInt *dst, BigInt const *x) {
|
||||
gb_internal void big_int_sub_eq(BigInt *dst, BigInt const *x) {
|
||||
BigInt res = {};
|
||||
big_int_init(&res, dst);
|
||||
big_int_sub(dst, &res, x);
|
||||
}
|
||||
void big_int_shl_eq(BigInt *dst, BigInt const *x) {
|
||||
gb_internal void big_int_shl_eq(BigInt *dst, BigInt const *x) {
|
||||
BigInt res = {};
|
||||
big_int_init(&res, dst);
|
||||
big_int_shl(dst, &res, x);
|
||||
}
|
||||
void big_int_shr_eq(BigInt *dst, BigInt const *x) {
|
||||
gb_internal void big_int_shr_eq(BigInt *dst, BigInt const *x) {
|
||||
BigInt res = {};
|
||||
big_int_init(&res, dst);
|
||||
big_int_shr(dst, &res, x);
|
||||
}
|
||||
void big_int_mul_eq(BigInt *dst, BigInt const *x) {
|
||||
gb_internal void big_int_mul_eq(BigInt *dst, BigInt const *x) {
|
||||
BigInt res = {};
|
||||
big_int_init(&res, dst);
|
||||
big_int_mul(dst, &res, x);
|
||||
}
|
||||
void big_int_quo_eq(BigInt *dst, BigInt const *x) {
|
||||
gb_internal void big_int_quo_eq(BigInt *dst, BigInt const *x) {
|
||||
BigInt res = {};
|
||||
big_int_init(&res, dst);
|
||||
big_int_quo(dst, &res, x);
|
||||
}
|
||||
void big_int_rem_eq(BigInt *dst, BigInt const *x) {
|
||||
gb_internal void big_int_rem_eq(BigInt *dst, BigInt const *x) {
|
||||
BigInt res = {};
|
||||
big_int_init(&res, dst);
|
||||
big_int_rem(dst, &res, x);
|
||||
@@ -124,7 +124,7 @@ void big_int_rem_eq(BigInt *dst, BigInt const *x) {
|
||||
|
||||
|
||||
|
||||
i64 big_int_sign(BigInt const *x) {
|
||||
gb_internal i64 big_int_sign(BigInt const *x) {
|
||||
if (mp_iszero(x)) {
|
||||
return 0;
|
||||
}
|
||||
@@ -132,44 +132,44 @@ i64 big_int_sign(BigInt const *x) {
|
||||
}
|
||||
|
||||
|
||||
void big_int_from_u64(BigInt *dst, u64 x) {
|
||||
gb_internal void big_int_from_u64(BigInt *dst, u64 x) {
|
||||
mp_init_u64(dst, x);
|
||||
}
|
||||
void big_int_from_i64(BigInt *dst, i64 x) {
|
||||
gb_internal void big_int_from_i64(BigInt *dst, i64 x) {
|
||||
mp_init_i64(dst, x);
|
||||
|
||||
}
|
||||
void big_int_init(BigInt *dst, BigInt const *src) {
|
||||
gb_internal void big_int_init(BigInt *dst, BigInt const *src) {
|
||||
if (dst == src) {
|
||||
return;
|
||||
}
|
||||
mp_init_copy(dst, src);
|
||||
}
|
||||
|
||||
BigInt big_int_make(BigInt const *b, bool abs) {
|
||||
gb_internal BigInt big_int_make(BigInt const *b, bool abs) {
|
||||
BigInt i = {};
|
||||
big_int_init(&i, b);
|
||||
if (abs) mp_abs(&i, &i);
|
||||
return i;
|
||||
}
|
||||
BigInt big_int_make_abs(BigInt const *b) {
|
||||
gb_internal BigInt big_int_make_abs(BigInt const *b) {
|
||||
return big_int_make(b, true);
|
||||
}
|
||||
|
||||
|
||||
BigInt big_int_make_u64(u64 x) {
|
||||
gb_internal BigInt big_int_make_u64(u64 x) {
|
||||
BigInt i = {};
|
||||
big_int_from_u64(&i, x);
|
||||
return i;
|
||||
}
|
||||
BigInt big_int_make_i64(i64 x) {
|
||||
gb_internal BigInt big_int_make_i64(i64 x) {
|
||||
BigInt i = {};
|
||||
big_int_from_i64(&i, x);
|
||||
return i;
|
||||
}
|
||||
|
||||
|
||||
void big_int_from_string(BigInt *dst, String const &s, bool *success) {
|
||||
gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success) {
|
||||
*success = true;
|
||||
|
||||
bool is_negative = false;
|
||||
@@ -262,66 +262,66 @@ void big_int_from_string(BigInt *dst, String const &s, bool *success) {
|
||||
|
||||
|
||||
|
||||
u64 big_int_to_u64(BigInt const *x) {
|
||||
gb_internal u64 big_int_to_u64(BigInt const *x) {
|
||||
GB_ASSERT(x->sign == 0);
|
||||
return mp_get_u64(x);
|
||||
}
|
||||
|
||||
i64 big_int_to_i64(BigInt const *x) {
|
||||
gb_internal i64 big_int_to_i64(BigInt const *x) {
|
||||
return mp_get_i64(x);
|
||||
}
|
||||
|
||||
f64 big_int_to_f64(BigInt const *x) {
|
||||
gb_internal f64 big_int_to_f64(BigInt const *x) {
|
||||
return mp_get_double(x);
|
||||
}
|
||||
|
||||
|
||||
void big_int_neg(BigInt *dst, BigInt const *x) {
|
||||
gb_internal void big_int_neg(BigInt *dst, BigInt const *x) {
|
||||
mp_neg(x, dst);
|
||||
}
|
||||
|
||||
|
||||
int big_int_cmp(BigInt const *x, BigInt const *y) {
|
||||
gb_internal int big_int_cmp(BigInt const *x, BigInt const *y) {
|
||||
return mp_cmp(x, y);
|
||||
}
|
||||
|
||||
int big_int_cmp_zero(BigInt const *x) {
|
||||
gb_internal int big_int_cmp_zero(BigInt const *x) {
|
||||
if (mp_iszero(x)) {
|
||||
return 0;
|
||||
}
|
||||
return x->sign ? -1 : +1;
|
||||
}
|
||||
|
||||
bool big_int_is_zero(BigInt const *x) {
|
||||
gb_internal bool big_int_is_zero(BigInt const *x) {
|
||||
return mp_iszero(x);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
mp_add(x, y, dst);
|
||||
}
|
||||
|
||||
|
||||
void big_int_sub(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_sub(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
mp_sub(x, y, dst);
|
||||
}
|
||||
|
||||
|
||||
void big_int_shl(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_shl(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
u32 yy = mp_get_u32(y);
|
||||
mp_mul_2d(x, yy, dst);
|
||||
}
|
||||
|
||||
void big_int_shr(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_shr(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
u32 yy = mp_get_u32(y);
|
||||
BigInt d = {};
|
||||
mp_div_2d(x, yy, dst, &d);
|
||||
big_int_dealloc(&d);
|
||||
}
|
||||
|
||||
void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) {
|
||||
gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) {
|
||||
BigInt d = {};
|
||||
big_int_from_u64(&d, y);
|
||||
mp_mul(x, &d, dst);
|
||||
@@ -329,12 +329,12 @@ void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) {
|
||||
}
|
||||
|
||||
|
||||
void big_int_mul(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_mul(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
mp_mul(x, y, dst);
|
||||
}
|
||||
|
||||
|
||||
u64 leading_zeros_u64(u64 x) {
|
||||
gb_internal u64 leading_zeros_u64(u64 x) {
|
||||
#if defined(GB_COMPILER_MSVC)
|
||||
#if defined(GB_ARCH_64_BIT)
|
||||
return __lzcnt64(x);
|
||||
@@ -367,23 +367,23 @@ u64 leading_zeros_u64(u64 x) {
|
||||
//
|
||||
// q = x/y with the result truncated to zero
|
||||
// r = x - y*q
|
||||
void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q_, BigInt *r_) {
|
||||
gb_internal void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q_, BigInt *r_) {
|
||||
mp_div(x, y, q_, r_);
|
||||
}
|
||||
|
||||
void big_int_quo(BigInt *z, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_quo(BigInt *z, BigInt const *x, BigInt const *y) {
|
||||
BigInt r = {};
|
||||
big_int_quo_rem(x, y, z, &r);
|
||||
big_int_dealloc(&r);
|
||||
}
|
||||
|
||||
void big_int_rem(BigInt *z, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_rem(BigInt *z, BigInt const *x, BigInt const *y) {
|
||||
BigInt q = {};
|
||||
big_int_quo_rem(x, y, &q, z);
|
||||
big_int_dealloc(&q);
|
||||
}
|
||||
|
||||
void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y) {
|
||||
BigInt y0 = {};
|
||||
big_int_init(&y0, y);
|
||||
|
||||
@@ -400,11 +400,11 @@ void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y) {
|
||||
|
||||
|
||||
|
||||
void big_int_and(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_and(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
mp_and(x, y, dst);
|
||||
}
|
||||
|
||||
void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
if (mp_iszero(x)) {
|
||||
big_int_init(dst, y);
|
||||
return;
|
||||
@@ -467,22 +467,23 @@ void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
return;
|
||||
}
|
||||
|
||||
void big_int_xor(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_xor(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
mp_xor(x, y, dst);
|
||||
}
|
||||
|
||||
|
||||
void big_int_or(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
gb_internal void big_int_or(BigInt *dst, BigInt const *x, BigInt const *y) {
|
||||
mp_or(x, y, dst);
|
||||
}
|
||||
|
||||
void debug_print_big_int(BigInt const *x) {
|
||||
gb_internal void debug_print_big_int(BigInt const *x) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
String s = big_int_to_string(temporary_allocator(), x, 10);
|
||||
gb_printf_err("[DEBUG] %.*s\n", LIT(s));
|
||||
}
|
||||
|
||||
|
||||
void big_int_not(BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed) {
|
||||
gb_internal void big_int_not(BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed) {
|
||||
GB_ASSERT(bit_count >= 0);
|
||||
if (bit_count == 0) {
|
||||
big_int_from_u64(dst, 0);
|
||||
@@ -530,7 +531,7 @@ void big_int_not(BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed) {
|
||||
big_int_dealloc(&v);
|
||||
}
|
||||
|
||||
bool big_int_is_neg(BigInt const *x) {
|
||||
gb_internal bool big_int_is_neg(BigInt const *x) {
|
||||
if (x == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -538,7 +539,7 @@ bool big_int_is_neg(BigInt const *x) {
|
||||
}
|
||||
|
||||
|
||||
char digit_to_char(u8 digit) {
|
||||
gb_internal char digit_to_char(u8 digit) {
|
||||
GB_ASSERT(digit < 16);
|
||||
if (digit <= 9) {
|
||||
return digit + '0';
|
||||
@@ -548,7 +549,7 @@ char digit_to_char(u8 digit) {
|
||||
return '0';
|
||||
}
|
||||
|
||||
String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
|
||||
gb_internal String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
|
||||
GB_ASSERT(base <= 16);
|
||||
|
||||
if (mp_iszero(x)) {
|
||||
@@ -560,40 +561,63 @@ String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
|
||||
Array<char> buf = {};
|
||||
array_init(&buf, allocator, 0, 32);
|
||||
|
||||
BigInt v = {};
|
||||
mp_init_copy(&v, x);
|
||||
if (x->used >= 498) { // 2^498 ~ 10^150
|
||||
mp_int val = {};
|
||||
mp_abs(x, &val);
|
||||
int exp = 0;
|
||||
mp_err err = mp_log_n(&val, 10, &exp);
|
||||
GB_ASSERT(err == MP_OKAY);
|
||||
GB_ASSERT(exp >= 100);
|
||||
|
||||
if (v.sign) {
|
||||
array_add(&buf, '-');
|
||||
mp_abs(&v, &v);
|
||||
}
|
||||
mp_int thousand_below = {};
|
||||
mp_int thousand_above = {};
|
||||
mp_init_i32(&thousand_below, 10);
|
||||
|
||||
isize first_word_idx = buf.count;
|
||||
mp_expt_n(&thousand_below, exp-3, &thousand_below);
|
||||
mp_div(&val, &thousand_below, &thousand_above, nullptr);
|
||||
|
||||
BigInt r = {};
|
||||
BigInt b = {};
|
||||
big_int_from_u64(&b, base);
|
||||
double mant = 1.0e-3 * mp_get_double(&thousand_above);
|
||||
|
||||
u8 digit = 0;
|
||||
while (big_int_cmp(&v, &b) >= 0) {
|
||||
big_int_quo_rem(&v, &b, &v, &r);
|
||||
char val_buf[256] = {};
|
||||
isize n = gb_snprintf(val_buf, gb_size_of(val_buf)-1, "~ %s%.fe%u", (x->sign ? "-" : ""), mant, exp);
|
||||
|
||||
array_add_elems(&buf, val_buf, n-1);
|
||||
} else {
|
||||
BigInt v = {};
|
||||
mp_init_copy(&v, x);
|
||||
|
||||
if (v.sign) {
|
||||
array_add(&buf, '-');
|
||||
mp_abs(&v, &v);
|
||||
}
|
||||
|
||||
isize first_word_idx = buf.count;
|
||||
|
||||
BigInt r = {};
|
||||
BigInt b = {};
|
||||
big_int_from_u64(&b, base);
|
||||
|
||||
u8 digit = 0;
|
||||
while (big_int_cmp(&v, &b) >= 0) {
|
||||
big_int_quo_rem(&v, &b, &v, &r);
|
||||
digit = cast(u8)big_int_to_u64(&r);
|
||||
array_add(&buf, digit_to_char(digit));
|
||||
}
|
||||
|
||||
big_int_rem(&r, &v, &b);
|
||||
digit = cast(u8)big_int_to_u64(&r);
|
||||
array_add(&buf, digit_to_char(digit));
|
||||
|
||||
big_int_dealloc(&r);
|
||||
big_int_dealloc(&b);
|
||||
|
||||
for (isize i = first_word_idx; i < buf.count/2; i++) {
|
||||
isize j = buf.count + first_word_idx - i - 1;
|
||||
char tmp = buf[i];
|
||||
buf[i] = buf[j];
|
||||
buf[j] = tmp;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
big_int_rem(&r, &v, &b);
|
||||
digit = cast(u8)big_int_to_u64(&r);
|
||||
array_add(&buf, digit_to_char(digit));
|
||||
|
||||
big_int_dealloc(&r);
|
||||
big_int_dealloc(&b);
|
||||
|
||||
for (isize i = first_word_idx; i < buf.count/2; i++) {
|
||||
isize j = buf.count + first_word_idx - i - 1;
|
||||
char tmp = buf[i];
|
||||
buf[i] = buf[j];
|
||||
buf[j] = tmp;
|
||||
}
|
||||
|
||||
return make_string(cast(u8 *)buf.data, buf.count);
|
||||
}
|
||||
|
||||
+6
-6
@@ -30,7 +30,7 @@
|
||||
NOTE(Jeroen): This prints the Windows product edition only, to be called from `print_platform_details`.
|
||||
*/
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
void report_windows_product_type(DWORD ProductType) {
|
||||
gb_internal void report_windows_product_type(DWORD ProductType) {
|
||||
switch (ProductType) {
|
||||
case PRODUCT_ULTIMATE:
|
||||
gb_printf("Ultimate");
|
||||
@@ -154,7 +154,7 @@ void report_windows_product_type(DWORD ProductType) {
|
||||
}
|
||||
#endif
|
||||
|
||||
void odin_cpuid(int leaf, int result[]) {
|
||||
gb_internal void odin_cpuid(int leaf, int result[]) {
|
||||
#if defined(GB_CPU_ARM)
|
||||
return;
|
||||
|
||||
@@ -169,7 +169,7 @@ void odin_cpuid(int leaf, int result[]) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void report_cpu_info() {
|
||||
gb_internal void report_cpu_info() {
|
||||
gb_printf("\tCPU: ");
|
||||
|
||||
#if defined(GB_CPU_X86)
|
||||
@@ -220,7 +220,7 @@ void report_cpu_info() {
|
||||
/*
|
||||
Report the amount of installed RAM.
|
||||
*/
|
||||
void report_ram_info() {
|
||||
gb_internal void report_ram_info() {
|
||||
gb_printf("\tRAM: ");
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
@@ -271,7 +271,7 @@ void report_ram_info() {
|
||||
#endif
|
||||
}
|
||||
|
||||
void report_os_info() {
|
||||
gb_internal void report_os_info() {
|
||||
gb_printf("\tOS: ");
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
@@ -966,7 +966,7 @@ void report_os_info() {
|
||||
}
|
||||
|
||||
// NOTE(Jeroen): `odin report` prints some system information for easier bug reporting.
|
||||
void print_bug_report_help() {
|
||||
gb_internal void print_bug_report_help() {
|
||||
gb_printf("Where to find more information and get into contact when you encounter a bug:\n\n");
|
||||
gb_printf("\tWebsite: https://odin-lang.org\n");
|
||||
gb_printf("\tGitHub: https://github.com/odin-lang/Odin/issues\n");
|
||||
|
||||
+99
-68
@@ -57,7 +57,7 @@ enum TargetABIKind : u16 {
|
||||
};
|
||||
|
||||
|
||||
String target_os_names[TargetOs_COUNT] = {
|
||||
gb_global String target_os_names[TargetOs_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("windows"),
|
||||
str_lit("darwin"),
|
||||
@@ -72,7 +72,7 @@ String target_os_names[TargetOs_COUNT] = {
|
||||
str_lit("freestanding"),
|
||||
};
|
||||
|
||||
String target_arch_names[TargetArch_COUNT] = {
|
||||
gb_global String target_arch_names[TargetArch_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("amd64"),
|
||||
str_lit("i386"),
|
||||
@@ -82,19 +82,19 @@ String target_arch_names[TargetArch_COUNT] = {
|
||||
str_lit("wasm64"),
|
||||
};
|
||||
|
||||
String target_endian_names[TargetEndian_COUNT] = {
|
||||
gb_global String target_endian_names[TargetEndian_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("little"),
|
||||
str_lit("big"),
|
||||
};
|
||||
|
||||
String target_abi_names[TargetABI_COUNT] = {
|
||||
gb_global String target_abi_names[TargetABI_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("win64"),
|
||||
str_lit("sysv"),
|
||||
};
|
||||
|
||||
TargetEndianKind target_endians[TargetArch_COUNT] = {
|
||||
gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
|
||||
TargetEndian_Invalid,
|
||||
TargetEndian_Little,
|
||||
TargetEndian_Little,
|
||||
@@ -107,7 +107,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = {
|
||||
#define ODIN_VERSION_RAW "dev-unknown-unknown"
|
||||
#endif
|
||||
|
||||
String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW);
|
||||
gb_global String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW);
|
||||
|
||||
|
||||
|
||||
@@ -149,7 +149,6 @@ enum CommandKind : u32 {
|
||||
Command_run = 1<<0,
|
||||
Command_build = 1<<1,
|
||||
Command_check = 1<<3,
|
||||
Command_query = 1<<4,
|
||||
Command_doc = 1<<5,
|
||||
Command_version = 1<<6,
|
||||
Command_test = 1<<7,
|
||||
@@ -157,16 +156,15 @@ enum CommandKind : u32 {
|
||||
Command_strip_semicolon = 1<<8,
|
||||
Command_bug_report = 1<<9,
|
||||
|
||||
Command__does_check = Command_run|Command_build|Command_check|Command_query|Command_doc|Command_test|Command_strip_semicolon,
|
||||
Command__does_check = Command_run|Command_build|Command_check|Command_doc|Command_test|Command_strip_semicolon,
|
||||
Command__does_build = Command_run|Command_build|Command_test,
|
||||
Command_all = ~(u32)0,
|
||||
};
|
||||
|
||||
char const *odin_command_strings[32] = {
|
||||
gb_global char const *odin_command_strings[32] = {
|
||||
"run",
|
||||
"build",
|
||||
"check",
|
||||
"query",
|
||||
"doc",
|
||||
"version",
|
||||
"test",
|
||||
@@ -293,13 +291,14 @@ struct BuildContext {
|
||||
bool show_error_line;
|
||||
|
||||
bool ignore_lazy;
|
||||
bool ignore_llvm_build;
|
||||
|
||||
bool use_subsystem_windows;
|
||||
bool ignore_microsoft_magic;
|
||||
bool linker_map_file;
|
||||
|
||||
bool use_separate_modules;
|
||||
bool threaded_checker;
|
||||
bool no_threaded_checker;
|
||||
|
||||
bool show_debug_messages;
|
||||
|
||||
@@ -316,8 +315,6 @@ struct BuildContext {
|
||||
u32 cmd_doc_flags;
|
||||
Array<String> extra_packages;
|
||||
|
||||
QueryDataSetSettings query_data_set_settings;
|
||||
|
||||
StringSet test_names;
|
||||
|
||||
gbAffinity affinity;
|
||||
@@ -333,10 +330,15 @@ struct BuildContext {
|
||||
|
||||
gb_global BuildContext build_context = {0};
|
||||
|
||||
bool global_warnings_as_errors(void) {
|
||||
gb_internal bool IS_ODIN_DEBUG(void) {
|
||||
return build_context.ODIN_DEBUG;
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool global_warnings_as_errors(void) {
|
||||
return build_context.warnings_as_errors;
|
||||
}
|
||||
bool global_ignore_warnings(void) {
|
||||
gb_internal bool global_ignore_warnings(void) {
|
||||
return build_context.ignore_warnings;
|
||||
}
|
||||
|
||||
@@ -398,7 +400,7 @@ gb_global TargetMetrics target_darwin_arm64 = {
|
||||
TargetArch_arm64,
|
||||
8, 8, 16,
|
||||
str_lit("arm64-apple-macosx11.0.0"),
|
||||
str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct?
|
||||
str_lit("e-m:o-i64:64-i128:128-n32:64-S128"),
|
||||
};
|
||||
|
||||
gb_global TargetMetrics target_freebsd_i386 = {
|
||||
@@ -502,9 +504,9 @@ gb_global NamedTargetMetrics named_targets[] = {
|
||||
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
|
||||
};
|
||||
|
||||
NamedTargetMetrics *selected_target_metrics;
|
||||
gb_global NamedTargetMetrics *selected_target_metrics;
|
||||
|
||||
TargetOsKind get_target_os_from_string(String str) {
|
||||
gb_internal TargetOsKind get_target_os_from_string(String str) {
|
||||
for (isize i = 0; i < TargetOs_COUNT; i++) {
|
||||
if (str_eq_ignore_case(target_os_names[i], str)) {
|
||||
return cast(TargetOsKind)i;
|
||||
@@ -513,7 +515,7 @@ TargetOsKind get_target_os_from_string(String str) {
|
||||
return TargetOs_Invalid;
|
||||
}
|
||||
|
||||
TargetArchKind get_target_arch_from_string(String str) {
|
||||
gb_internal TargetArchKind get_target_arch_from_string(String str) {
|
||||
for (isize i = 0; i < TargetArch_COUNT; i++) {
|
||||
if (str_eq_ignore_case(target_arch_names[i], str)) {
|
||||
return cast(TargetArchKind)i;
|
||||
@@ -523,7 +525,7 @@ TargetArchKind get_target_arch_from_string(String str) {
|
||||
}
|
||||
|
||||
|
||||
bool is_excluded_target_filename(String name) {
|
||||
gb_internal bool is_excluded_target_filename(String name) {
|
||||
String original_name = name;
|
||||
name = remove_extension_from_path(name);
|
||||
|
||||
@@ -588,23 +590,22 @@ struct LibraryCollections {
|
||||
|
||||
gb_global Array<LibraryCollections> library_collections = {0};
|
||||
|
||||
void add_library_collection(String name, String path) {
|
||||
// TODO(bill): Check the path is valid and a directory
|
||||
gb_internal void add_library_collection(String name, String path) {
|
||||
LibraryCollections lc = {name, string_trim_whitespace(path)};
|
||||
array_add(&library_collections, lc);
|
||||
}
|
||||
|
||||
bool find_library_collection_path(String name, String *path) {
|
||||
for_array(i, library_collections) {
|
||||
if (library_collections[i].name == name) {
|
||||
if (path) *path = library_collections[i].path;
|
||||
gb_internal bool find_library_collection_path(String name, String *path) {
|
||||
for (auto const &lc : library_collections) {
|
||||
if (lc.name == name) {
|
||||
if (path) *path = lc.path;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_arch_wasm(void) {
|
||||
gb_internal bool is_arch_wasm(void) {
|
||||
switch (build_context.metrics.arch) {
|
||||
case TargetArch_wasm32:
|
||||
case TargetArch_wasm64:
|
||||
@@ -613,7 +614,7 @@ bool is_arch_wasm(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_arch_x86(void) {
|
||||
gb_internal bool is_arch_x86(void) {
|
||||
switch (build_context.metrics.arch) {
|
||||
case TargetArch_i386:
|
||||
case TargetArch_amd64:
|
||||
@@ -622,7 +623,7 @@ bool is_arch_x86(void) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool allow_check_foreign_filepath(void) {
|
||||
gb_internal bool allow_check_foreign_filepath(void) {
|
||||
switch (build_context.metrics.arch) {
|
||||
case TargetArch_wasm32:
|
||||
case TargetArch_wasm64:
|
||||
@@ -638,13 +639,14 @@ bool allow_check_foreign_filepath(void) {
|
||||
// is_abs_path
|
||||
// has_subdir
|
||||
|
||||
String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
|
||||
String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
|
||||
gb_global String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
|
||||
gb_global String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
|
||||
|
||||
String const WASM_MODULE_NAME_SEPARATOR = str_lit("..");
|
||||
gb_global String const WASM_MODULE_NAME_SEPARATOR = str_lit("..");
|
||||
|
||||
String internal_odin_root_dir(void);
|
||||
String odin_root_dir(void) {
|
||||
gb_internal String internal_odin_root_dir(void);
|
||||
|
||||
gb_internal String odin_root_dir(void) {
|
||||
if (global_module_path_set) {
|
||||
return global_module_path;
|
||||
}
|
||||
@@ -670,7 +672,7 @@ String odin_root_dir(void) {
|
||||
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
String internal_odin_root_dir(void) {
|
||||
gb_internal String internal_odin_root_dir(void) {
|
||||
String path = global_module_path;
|
||||
isize len, i;
|
||||
wchar_t *text;
|
||||
@@ -723,9 +725,9 @@ String internal_odin_root_dir(void) {
|
||||
|
||||
#include <mach-o/dyld.h>
|
||||
|
||||
String path_to_fullpath(gbAllocator a, String s);
|
||||
gb_internal String path_to_fullpath(gbAllocator a, String s);
|
||||
|
||||
String internal_odin_root_dir(void) {
|
||||
gb_internal String internal_odin_root_dir(void) {
|
||||
String path = global_module_path;
|
||||
isize len, i;
|
||||
u8 *text;
|
||||
@@ -777,9 +779,9 @@ String internal_odin_root_dir(void) {
|
||||
// NOTE: Linux / Unix is unfinished and not tested very well.
|
||||
#include <sys/stat.h>
|
||||
|
||||
String path_to_fullpath(gbAllocator a, String s);
|
||||
gb_internal String path_to_fullpath(gbAllocator a, String s);
|
||||
|
||||
String internal_odin_root_dir(void) {
|
||||
gb_internal String internal_odin_root_dir(void) {
|
||||
String path = global_module_path;
|
||||
isize len, i;
|
||||
u8 *text;
|
||||
@@ -938,18 +940,22 @@ String internal_odin_root_dir(void) {
|
||||
gb_global BlockingMutex fullpath_mutex;
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
String path_to_fullpath(gbAllocator a, String s) {
|
||||
gb_internal String path_to_fullpath(gbAllocator a, String s) {
|
||||
String result = {};
|
||||
mutex_lock(&fullpath_mutex);
|
||||
defer (mutex_unlock(&fullpath_mutex));
|
||||
|
||||
String16 string16 = string_to_string16(heap_allocator(), s);
|
||||
defer (gb_free(heap_allocator(), string16.text));
|
||||
|
||||
DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
|
||||
DWORD len;
|
||||
|
||||
mutex_lock(&fullpath_mutex);
|
||||
|
||||
len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
|
||||
if (len != 0) {
|
||||
wchar_t *text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
|
||||
GetFullPathNameW(&string16[0], len, text, nullptr);
|
||||
mutex_unlock(&fullpath_mutex);
|
||||
|
||||
text[len] = 0;
|
||||
result = string16_to_string(a, make_string16(text, len));
|
||||
result = string_trim_whitespace(result);
|
||||
@@ -960,12 +966,14 @@ String path_to_fullpath(gbAllocator a, String s) {
|
||||
result.text[i] = '/';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mutex_unlock(&fullpath_mutex);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
||||
String path_to_fullpath(gbAllocator a, String s) {
|
||||
gb_internal String path_to_fullpath(gbAllocator a, String s) {
|
||||
char *p;
|
||||
mutex_lock(&fullpath_mutex);
|
||||
p = realpath(cast(char *)s.text, 0);
|
||||
@@ -978,7 +986,7 @@ String path_to_fullpath(gbAllocator a, String s) {
|
||||
#endif
|
||||
|
||||
|
||||
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||
gb_internal String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||
u8 *str = gb_alloc_array(heap_allocator(), u8, base_dir.len+1+path.len+1);
|
||||
defer (gb_free(heap_allocator(), str));
|
||||
|
||||
@@ -1004,7 +1012,7 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
|
||||
}
|
||||
|
||||
|
||||
String get_fullpath_core(gbAllocator a, String path) {
|
||||
gb_internal String get_fullpath_core(gbAllocator a, String path) {
|
||||
String module_dir = odin_root_dir();
|
||||
|
||||
String core = str_lit("core/");
|
||||
@@ -1024,11 +1032,11 @@ String get_fullpath_core(gbAllocator a, String path) {
|
||||
return path_to_fullpath(a, res);
|
||||
}
|
||||
|
||||
bool show_error_line(void) {
|
||||
gb_internal bool show_error_line(void) {
|
||||
return build_context.show_error_line;
|
||||
}
|
||||
|
||||
bool has_asm_extension(String const &path) {
|
||||
gb_internal bool has_asm_extension(String const &path) {
|
||||
String ext = path_extension(path);
|
||||
if (ext == ".asm") {
|
||||
return true;
|
||||
@@ -1041,7 +1049,7 @@ bool has_asm_extension(String const &path) {
|
||||
}
|
||||
|
||||
// temporary
|
||||
char *token_pos_to_string(TokenPos const &pos) {
|
||||
gb_internal char *token_pos_to_string(TokenPos const &pos) {
|
||||
gbString s = gb_string_make_reserve(temporary_allocator(), 128);
|
||||
String file = get_file_path_string(pos.file_id);
|
||||
switch (build_context.ODIN_ERROR_POS_STYLE) {
|
||||
@@ -1056,7 +1064,7 @@ char *token_pos_to_string(TokenPos const &pos) {
|
||||
return s;
|
||||
}
|
||||
|
||||
void init_build_context(TargetMetrics *cross_target) {
|
||||
gb_internal void init_build_context(TargetMetrics *cross_target) {
|
||||
BuildContext *bc = &build_context;
|
||||
|
||||
gb_affinity_init(&bc->affinity);
|
||||
@@ -1245,7 +1253,14 @@ void init_build_context(TargetMetrics *cross_target) {
|
||||
|
||||
bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
|
||||
|
||||
bc->ODIN_VALGRIND_SUPPORT = is_arch_x86() && build_context.metrics.os != TargetOs_windows;
|
||||
bc->ODIN_VALGRIND_SUPPORT = false;
|
||||
if (build_context.metrics.os != TargetOs_windows) {
|
||||
switch (bc->metrics.arch) {
|
||||
case TargetArch_amd64:
|
||||
bc->ODIN_VALGRIND_SUPPORT = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#undef LINK_FLAG_X64
|
||||
#undef LINK_FLAG_386
|
||||
@@ -1258,7 +1273,7 @@ void init_build_context(TargetMetrics *cross_target) {
|
||||
#endif
|
||||
|
||||
|
||||
Array<String> split_by_comma(String const &list) {
|
||||
gb_internal Array<String> split_by_comma(String const &list) {
|
||||
isize n = 1;
|
||||
for (isize i = 0; i < list.len; i++) {
|
||||
if (list.text[i] == ',') {
|
||||
@@ -1280,20 +1295,19 @@ Array<String> split_by_comma(String const &list) {
|
||||
return res;
|
||||
}
|
||||
|
||||
bool check_target_feature_is_valid(TokenPos pos, String const &feature) {
|
||||
gb_internal bool check_target_feature_is_valid(TokenPos pos, String const &feature) {
|
||||
// TODO(bill): check_target_feature_is_valid
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_list) {
|
||||
gb_internal bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_list) {
|
||||
BuildContext *bc = &build_context;
|
||||
mutex_lock(&bc->target_features_mutex);
|
||||
defer (mutex_unlock(&bc->target_features_mutex));
|
||||
|
||||
auto items = split_by_comma(target_feature_list);
|
||||
array_free(&items);
|
||||
for_array(i, items) {
|
||||
String const &item = items.data[i];
|
||||
for (String const &item : items) {
|
||||
if (!check_target_feature_is_valid(pos, item)) {
|
||||
error(pos, "Target feature '%.*s' is not valid", LIT(item));
|
||||
return false;
|
||||
@@ -1307,14 +1321,13 @@ bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_
|
||||
return true;
|
||||
}
|
||||
|
||||
void enable_target_feature(TokenPos pos, String const &target_feature_list) {
|
||||
gb_internal void enable_target_feature(TokenPos pos, String const &target_feature_list) {
|
||||
BuildContext *bc = &build_context;
|
||||
mutex_lock(&bc->target_features_mutex);
|
||||
defer (mutex_unlock(&bc->target_features_mutex));
|
||||
|
||||
auto items = split_by_comma(target_feature_list);
|
||||
for_array(i, items) {
|
||||
String const &item = items.data[i];
|
||||
for (String const &item : items) {
|
||||
if (!check_target_feature_is_valid(pos, item)) {
|
||||
error(pos, "Target feature '%.*s' is not valid", LIT(item));
|
||||
continue;
|
||||
@@ -1326,25 +1339,26 @@ void enable_target_feature(TokenPos pos, String const &target_feature_list) {
|
||||
}
|
||||
|
||||
|
||||
char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes) {
|
||||
gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes) {
|
||||
isize len = 0;
|
||||
for_array(i, build_context.target_features_set.entries) {
|
||||
isize i = 0;
|
||||
for (String const &feature : build_context.target_features_set) {
|
||||
if (i != 0) {
|
||||
len += 1;
|
||||
}
|
||||
String feature = build_context.target_features_set.entries[i].value;
|
||||
len += feature.len;
|
||||
if (with_quotes) len += 2;
|
||||
i += 1;
|
||||
}
|
||||
char *features = gb_alloc_array(allocator, char, len+1);
|
||||
len = 0;
|
||||
for_array(i, build_context.target_features_set.entries) {
|
||||
i = 0;
|
||||
for (String const &feature : build_context.target_features_set) {
|
||||
if (i != 0) {
|
||||
features[len++] = ',';
|
||||
}
|
||||
|
||||
if (with_quotes) features[len++] = '"';
|
||||
String feature = build_context.target_features_set.entries[i].value;
|
||||
gb_memmove(features + len, feature.text, feature.len);
|
||||
len += feature.len;
|
||||
if (with_quotes) features[len++] = '"';
|
||||
@@ -1356,15 +1370,14 @@ char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quot
|
||||
|
||||
// NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate.
|
||||
// We've previously called `parse_build_flags`, so `out_filepath` should be set.
|
||||
bool init_build_paths(String init_filename) {
|
||||
gb_internal bool init_build_paths(String init_filename) {
|
||||
gbAllocator ha = heap_allocator();
|
||||
BuildContext *bc = &build_context;
|
||||
|
||||
// NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index.
|
||||
array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT);
|
||||
|
||||
string_set_init(&bc->target_features_set, heap_allocator(), 1024);
|
||||
mutex_init(&bc->target_features_mutex);
|
||||
string_set_init(&bc->target_features_set, 1024);
|
||||
|
||||
// [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path.
|
||||
bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename);
|
||||
@@ -1408,7 +1421,6 @@ bool init_build_paths(String init_filename) {
|
||||
if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) {
|
||||
// NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.
|
||||
Find_Result find_result = find_visual_studio_and_windows_sdk();
|
||||
defer (mc_free_all());
|
||||
|
||||
if (find_result.windows_sdk_version == 0) {
|
||||
gb_printf_err("Windows SDK not found.\n");
|
||||
@@ -1533,6 +1545,25 @@ bool init_build_paths(String init_filename) {
|
||||
output_name = remove_extension_from_path(output_name);
|
||||
output_name = copy_string(ha, string_trim_whitespace(output_name));
|
||||
output_path = path_from_string(ha, output_name);
|
||||
|
||||
// Note(Dragos): This is a fix for empty filenames
|
||||
// Turn the trailing folder into the file name
|
||||
if (output_path.name.len == 0) {
|
||||
isize len = output_path.basename.len;
|
||||
while (len > 1 && output_path.basename[len - 1] != '/') {
|
||||
len -= 1;
|
||||
}
|
||||
// We reached the slash
|
||||
String old_basename = output_path.basename;
|
||||
output_path.basename.len = len - 1; // Remove the slash
|
||||
output_path.name = substring(old_basename, len, old_basename.len);
|
||||
output_path.basename = copy_string(ha, output_path.basename);
|
||||
output_path.name = copy_string(ha, output_path.name);
|
||||
// The old basename is wrong. Delete it
|
||||
gb_free(ha, old_basename.text);
|
||||
|
||||
|
||||
}
|
||||
|
||||
// Replace extension.
|
||||
if (output_path.ext.len > 0) {
|
||||
|
||||
+67
-43
@@ -1,6 +1,6 @@
|
||||
typedef bool (BuiltinTypeIsProc)(Type *t);
|
||||
|
||||
BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - BuiltinProc__type_simple_boolean_begin] = {
|
||||
gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - BuiltinProc__type_simple_boolean_begin] = {
|
||||
nullptr, // BuiltinProc__type_simple_boolean_begin
|
||||
|
||||
is_type_boolean,
|
||||
@@ -51,7 +51,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end -
|
||||
};
|
||||
|
||||
|
||||
void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type) {
|
||||
gb_internal void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type) {
|
||||
if (right_type == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -62,7 +62,7 @@ void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name,
|
||||
}
|
||||
}
|
||||
|
||||
void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
|
||||
gb_internal void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
|
||||
Type *left_type = nullptr;
|
||||
Type *right_type = nullptr;
|
||||
if (x->type->kind == Type_Tuple) {
|
||||
@@ -88,8 +88,7 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name
|
||||
}
|
||||
|
||||
|
||||
void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
|
||||
// TODO(bill): better error message
|
||||
gb_internal void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
|
||||
gbString t = type_to_string(x.type);
|
||||
error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t);
|
||||
if (is_type_union(type_deref(x.type))) {
|
||||
@@ -97,8 +96,7 @@ void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Op
|
||||
gbString th = nullptr;
|
||||
if (type_hint != nullptr) {
|
||||
GB_ASSERT(bsrc->kind == Type_Union);
|
||||
for_array(i, bsrc->Union.variants) {
|
||||
Type *vt = bsrc->Union.variants[i];
|
||||
for (Type *vt : bsrc->Union.variants) {
|
||||
if (are_types_identical(vt, type_hint)) {
|
||||
th = type_to_string(type_hint);
|
||||
break;
|
||||
@@ -118,7 +116,7 @@ void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Op
|
||||
}
|
||||
|
||||
|
||||
void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
|
||||
gb_internal void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
|
||||
Type *left_type = nullptr;
|
||||
Type *right_type = nullptr;
|
||||
if (x->type->kind == Type_Tuple) {
|
||||
@@ -144,7 +142,7 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na
|
||||
}
|
||||
|
||||
|
||||
bool does_require_msgSend_stret(Type *return_type) {
|
||||
gb_internal bool does_require_msgSend_stret(Type *return_type) {
|
||||
if (return_type == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -165,7 +163,7 @@ bool does_require_msgSend_stret(Type *return_type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
ObjcMsgKind get_objc_proc_kind(Type *return_type) {
|
||||
gb_internal ObjcMsgKind get_objc_proc_kind(Type *return_type) {
|
||||
if (return_type == nullptr) {
|
||||
return ObjcMsg_normal;
|
||||
}
|
||||
@@ -189,7 +187,7 @@ ObjcMsgKind get_objc_proc_kind(Type *return_type) {
|
||||
return ObjcMsg_normal;
|
||||
}
|
||||
|
||||
void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<Type *> param_types) {
|
||||
gb_internal void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<Type *> param_types) {
|
||||
ObjcMsgKind kind = get_objc_proc_kind(return_type);
|
||||
|
||||
Scope *scope = create_scope(c->info, nullptr);
|
||||
@@ -199,8 +197,7 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<T
|
||||
{
|
||||
auto variables = array_make<Entity *>(permanent_allocator(), 0, param_types.count);
|
||||
|
||||
for_array(i, param_types) {
|
||||
Type *type = param_types[i];
|
||||
for (Type *type : param_types) {
|
||||
Entity *param = alloc_entity_param(scope, blank_token, type, false, true);
|
||||
array_add(&variables, param);
|
||||
}
|
||||
@@ -230,7 +227,7 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<T
|
||||
try_to_add_package_dependency(c, "runtime", "objc_msgSend_stret");
|
||||
}
|
||||
|
||||
bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) {
|
||||
gb_internal bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) {
|
||||
Operand op = {};
|
||||
check_expr(c, &op, expr);
|
||||
if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
|
||||
@@ -245,7 +242,7 @@ bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
||||
gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
||||
String const &builtin_name = builtin_procs[id].name;
|
||||
|
||||
if (build_context.metrics.os != TargetOs_darwin) {
|
||||
@@ -387,7 +384,7 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
|
||||
}
|
||||
}
|
||||
|
||||
bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String const &builtin_name, OdinAtomicMemoryOrder *memory_order_, char const *extra_message = nullptr) {
|
||||
gb_internal bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String const &builtin_name, OdinAtomicMemoryOrder *memory_order_, char const *extra_message = nullptr) {
|
||||
Operand x = {};
|
||||
check_expr_with_type_hint(c, &x, expr, t_atomic_memory_order);
|
||||
if (x.mode == Addressing_Invalid) {
|
||||
@@ -417,7 +414,7 @@ bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String con
|
||||
}
|
||||
|
||||
|
||||
bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
||||
gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
|
||||
String const &builtin_name = builtin_procs[id].name;
|
||||
@@ -1081,7 +1078,7 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call
|
||||
return false;
|
||||
}
|
||||
|
||||
bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) {
|
||||
gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String builtin_name = bd->name.string;
|
||||
@@ -1111,7 +1108,7 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi
|
||||
new_cache->path = path;
|
||||
new_cache->data = data;
|
||||
new_cache->file_error = file_error;
|
||||
string_map_init(&new_cache->hashes, heap_allocator(), 32);
|
||||
string_map_init(&new_cache->hashes, 32);
|
||||
string_map_set(&c->info->load_file_cache, path, new_cache);
|
||||
if (cache_) *cache_ = new_cache;
|
||||
} else {
|
||||
@@ -1121,8 +1118,8 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi
|
||||
}
|
||||
});
|
||||
|
||||
char *c_str = alloc_cstring(heap_allocator(), path);
|
||||
defer (gb_free(heap_allocator(), c_str));
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
char *c_str = alloc_cstring(temporary_allocator(), path);
|
||||
|
||||
gbFile f = {};
|
||||
if (cache == nullptr) {
|
||||
@@ -1170,7 +1167,7 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi
|
||||
}
|
||||
|
||||
|
||||
bool is_valid_type_for_load(Type *type) {
|
||||
gb_internal bool is_valid_type_for_load(Type *type) {
|
||||
if (type == t_invalid) {
|
||||
return false;
|
||||
} else if (is_type_string(type)) {
|
||||
@@ -1191,7 +1188,16 @@ bool is_valid_type_for_load(Type *type) {
|
||||
return false;
|
||||
}
|
||||
|
||||
LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) {
|
||||
gb_internal bool check_atomic_ptr_argument(Operand *operand, String const &builtin_name, Type *elem) {
|
||||
if (!is_type_valid_atomic_type(elem)) {
|
||||
error(operand->expr, "Only an integer, floating-point, boolean, or pointer can be used as an atomic for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String name = bd->name.string;
|
||||
@@ -1256,7 +1262,7 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As
|
||||
}
|
||||
|
||||
|
||||
bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) {
|
||||
gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
ast_node(bd, BasicDirective, ce->proc);
|
||||
String name = bd->name.string;
|
||||
@@ -1581,7 +1587,7 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast
|
||||
return true;
|
||||
}
|
||||
|
||||
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
||||
gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
|
||||
ast_node(ce, CallExpr, call);
|
||||
if (ce->inlining != ProcInlining_none) {
|
||||
error(call, "Inlining operators are not allowed on built-in procedures");
|
||||
@@ -1690,7 +1696,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
case BuiltinProc___entry_point:
|
||||
operand->mode = Addressing_NoValue;
|
||||
operand->type = nullptr;
|
||||
mpmc_enqueue(&c->info->intrinsics_entry_point_usage, call);
|
||||
mpsc_enqueue(&c->info->intrinsics_entry_point_usage, call);
|
||||
break;
|
||||
|
||||
case BuiltinProc_DIRECTIVE:
|
||||
@@ -2559,7 +2565,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
if (is_type_struct(type)) {
|
||||
isize variable_count = type->Struct.fields.count;
|
||||
slice_init(&tuple->Tuple.variables, a, variable_count);
|
||||
// TODO(bill): Should I copy each of the entities or is this good enough?
|
||||
// NOTE(bill): don't copy the entities, this should be good enough
|
||||
gb_memmove_array(tuple->Tuple.variables.data, type->Struct.fields.data, variable_count);
|
||||
} else if (is_type_array(type)) {
|
||||
isize variable_count = cast(isize)type->Array.count;
|
||||
@@ -3066,14 +3072,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
}
|
||||
|
||||
case BuiltinProc_soa_zip: {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
auto types = array_make<Type *>(temporary_allocator(), 0, ce->args.count);
|
||||
auto names = array_make<String>(temporary_allocator(), 0, ce->args.count);
|
||||
|
||||
bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue);
|
||||
|
||||
bool fail = false;
|
||||
for_array(i, ce->args) {
|
||||
Ast *arg = ce->args[i];
|
||||
for (Ast *arg : ce->args) {
|
||||
bool mix = false;
|
||||
if (first_is_field_value) {
|
||||
mix = arg->kind != Ast_FieldValue;
|
||||
@@ -3087,11 +3093,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
}
|
||||
}
|
||||
StringSet name_set = {};
|
||||
string_set_init(&name_set, heap_allocator(), 2*ce->args.count);
|
||||
string_set_init(&name_set, 2*ce->args.count);
|
||||
|
||||
for_array(i, ce->args) {
|
||||
for (Ast *arg : ce->args) {
|
||||
String name = {};
|
||||
Ast *arg = ce->args[i];
|
||||
if (arg->kind == Ast_FieldValue) {
|
||||
Ast *ename = arg->FieldValue.field;
|
||||
if (!fail && ename->kind != Ast_Ident) {
|
||||
@@ -3126,13 +3131,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
}
|
||||
|
||||
|
||||
if (string_set_exists(&name_set, name)) {
|
||||
if (string_set_update(&name_set, name)) {
|
||||
error(op.expr, "Field argument name '%.*s' already exists", LIT(name));
|
||||
} else {
|
||||
array_add(&types, arg_type->Slice.elem);
|
||||
array_add(&names, name);
|
||||
|
||||
string_set_add(&name_set, name);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3455,9 +3458,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
error(ce->args[0], "Expected a constant string for '%.*s'", LIT(builtin_name));
|
||||
} else if (operand->value.kind == ExactValue_String) {
|
||||
String pkg_name = operand->value.value_string;
|
||||
// TODO(bill): probably should have this be a `StringMap` eventually
|
||||
for_array(i, c->info->packages.entries) {
|
||||
AstPackage *pkg = c->info->packages.entries[i].value;
|
||||
for (auto const &entry : c->info->packages) {
|
||||
AstPackage *pkg = entry.value;
|
||||
if (pkg->name == pkg_name) {
|
||||
value = true;
|
||||
break;
|
||||
@@ -3769,9 +3771,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
mp_err err = mp_pack(rop, max_count, &written, MP_LSB_FIRST, size, endian, nails, &x.value.value_integer);
|
||||
GB_ASSERT(err == MP_OKAY);
|
||||
|
||||
if (id == BuiltinProc_reverse_bits) {
|
||||
// TODO(bill): Should this even be allowed at compile time?
|
||||
} else {
|
||||
if (id != BuiltinProc_reverse_bits) {
|
||||
u64 v = 0;
|
||||
switch (id) {
|
||||
case BuiltinProc_count_ones:
|
||||
@@ -4255,6 +4255,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (id == BuiltinProc_atomic_store && !check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||
return false;
|
||||
}
|
||||
Operand x = {};
|
||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||
check_assignment(c, &x, elem, builtin_name);
|
||||
@@ -4271,6 +4274,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||
return false;
|
||||
}
|
||||
Operand x = {};
|
||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||
check_assignment(c, &x, elem, builtin_name);
|
||||
@@ -4303,6 +4309,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (id == BuiltinProc_atomic_load && !check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
operand->type = elem;
|
||||
operand->mode = Addressing_Value;
|
||||
break;
|
||||
@@ -4315,6 +4325,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OdinAtomicMemoryOrder memory_order = {};
|
||||
if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name, &memory_order)) {
|
||||
@@ -4346,6 +4359,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||
return false;
|
||||
}
|
||||
Operand x = {};
|
||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||
check_assignment(c, &x, elem, builtin_name);
|
||||
@@ -4383,6 +4399,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||
return false;
|
||||
}
|
||||
Operand x = {};
|
||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||
check_assignment(c, &x, elem, builtin_name);
|
||||
@@ -4421,6 +4440,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||
return false;
|
||||
}
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||
@@ -4448,6 +4470,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||
return false;
|
||||
}
|
||||
Operand x = {};
|
||||
Operand y = {};
|
||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||
@@ -4993,8 +5018,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
|
||||
bool is_variant = false;
|
||||
|
||||
for_array(i, u->Union.variants) {
|
||||
Type *vt = u->Union.variants[i];
|
||||
for (Type *vt : u->Union.variants) {
|
||||
if (are_types_identical(v, vt)) {
|
||||
is_variant = true;
|
||||
break;
|
||||
|
||||
+93
-88
@@ -1,7 +1,7 @@
|
||||
void check_stmt (CheckerContext *ctx, Ast *node, u32 flags);
|
||||
gb_internal void check_stmt(CheckerContext *ctx, Ast *node, u32 flags);
|
||||
|
||||
// NOTE(bill): 'content_name' is for debugging and error messages
|
||||
Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, String context_name) {
|
||||
gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, String context_name) {
|
||||
if (operand->mode == Addressing_Invalid ||
|
||||
operand->type == t_invalid ||
|
||||
e->type == t_invalid) {
|
||||
@@ -10,7 +10,6 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
|
||||
gbString expr_str = expr_to_string(operand->expr);
|
||||
|
||||
// TODO(bill): is this a good enough error message?
|
||||
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
|
||||
error(operand->expr,
|
||||
"Cannot assign built-in procedure '%s' in %.*s",
|
||||
expr_str,
|
||||
@@ -46,7 +45,7 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
|
||||
if (operand->mode == Addressing_Type) {
|
||||
if (e->type != nullptr && is_type_typeid(e->type)) {
|
||||
add_type_info_type(ctx, operand->type);
|
||||
add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
|
||||
add_type_and_value(ctx, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
|
||||
return e->type;
|
||||
} else {
|
||||
gbString t = type_to_string(operand->type);
|
||||
@@ -110,7 +109,7 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
|
||||
return e->type;
|
||||
}
|
||||
|
||||
void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Slice<Ast *> const &inits, String context_name) {
|
||||
gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Slice<Ast *> const &inits, String context_name) {
|
||||
if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
|
||||
return;
|
||||
}
|
||||
@@ -118,17 +117,11 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Sl
|
||||
|
||||
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||
// an extra allocation
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
|
||||
check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false);
|
||||
|
||||
isize rhs_count = operands.count;
|
||||
for_array(i, operands) {
|
||||
if (operands[i].mode == Addressing_Invalid) {
|
||||
// TODO(bill): Should I ignore invalid parameters?
|
||||
// rhs_count--;
|
||||
}
|
||||
}
|
||||
|
||||
isize max = gb_min(lhs_count, rhs_count);
|
||||
for (isize i = 0; i < max; i++) {
|
||||
Entity *e = lhs[i];
|
||||
@@ -144,7 +137,7 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Sl
|
||||
}
|
||||
}
|
||||
|
||||
void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
|
||||
gb_internal void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
|
||||
if (operand->mode == Addressing_Invalid ||
|
||||
operand->type == t_invalid ||
|
||||
e->type == t_invalid) {
|
||||
@@ -184,7 +177,7 @@ void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
|
||||
}
|
||||
|
||||
|
||||
bool is_type_distinct(Ast *node) {
|
||||
gb_internal bool is_type_distinct(Ast *node) {
|
||||
for (;;) {
|
||||
if (node == nullptr) {
|
||||
return false;
|
||||
@@ -217,7 +210,7 @@ bool is_type_distinct(Ast *node) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Ast *remove_type_alias_clutter(Ast *node) {
|
||||
gb_internal Ast *remove_type_alias_clutter(Ast *node) {
|
||||
for (;;) {
|
||||
if (node == nullptr) {
|
||||
return nullptr;
|
||||
@@ -232,17 +225,7 @@ Ast *remove_type_alias_clutter(Ast *node) {
|
||||
}
|
||||
}
|
||||
|
||||
isize total_attribute_count(DeclInfo *decl) {
|
||||
isize attribute_count = 0;
|
||||
for_array(i, decl->attributes) {
|
||||
Ast *attr = decl->attributes[i];
|
||||
if (attr->kind != Ast_Attribute) continue;
|
||||
attribute_count += attr->Attribute.elems.count;
|
||||
}
|
||||
return attribute_count;
|
||||
}
|
||||
|
||||
Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named_type) {
|
||||
gb_internal Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named_type) {
|
||||
// NOTE(bill, 2022-02-05): Stupid edge case for `distinct` declarations
|
||||
//
|
||||
// X :: enum {A, B, C}
|
||||
@@ -288,7 +271,7 @@ Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named
|
||||
return et;
|
||||
}
|
||||
|
||||
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
|
||||
gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
@@ -372,8 +355,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
|
||||
|
||||
Type *t = base_type(e->type);
|
||||
if (t->kind == Type_Enum) {
|
||||
for_array(i, t->Enum.fields) {
|
||||
Entity *f = t->Enum.fields[i];
|
||||
for (Entity *f : t->Enum.fields) {
|
||||
if (f->kind != Entity_Constant) {
|
||||
continue;
|
||||
}
|
||||
@@ -390,7 +372,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
|
||||
}
|
||||
|
||||
|
||||
void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
|
||||
gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
|
||||
// NOTE(bill): The original_entity's scope may not be same scope that it was inserted into
|
||||
// e.g. file entity inserted into its package scope
|
||||
String original_name = original_entity->token.string;
|
||||
@@ -400,8 +382,8 @@ void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
|
||||
if (found_scope == nullptr) {
|
||||
return;
|
||||
}
|
||||
mutex_lock(&found_scope->mutex);
|
||||
defer (mutex_unlock(&found_scope->mutex));
|
||||
rw_mutex_lock(&found_scope->mutex);
|
||||
defer (rw_mutex_unlock(&found_scope->mutex));
|
||||
|
||||
// IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the
|
||||
// original entity was still used check checked, but the checking was only
|
||||
@@ -433,7 +415,7 @@ void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
|
||||
|
||||
|
||||
|
||||
void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) {
|
||||
gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
GB_ASSERT(e->kind == Entity_Constant);
|
||||
init = unparen_expr(init);
|
||||
@@ -609,12 +591,12 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
|
||||
|
||||
|
||||
typedef bool TypeCheckSig(Type *t);
|
||||
bool sig_compare(TypeCheckSig *a, Type *x, Type *y) {
|
||||
gb_internal bool sig_compare(TypeCheckSig *a, Type *x, Type *y) {
|
||||
x = core_type(x);
|
||||
y = core_type(y);
|
||||
return (a(x) && a(y));
|
||||
}
|
||||
bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) {
|
||||
gb_internal bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) {
|
||||
x = core_type(x);
|
||||
y = core_type(y);
|
||||
if (a == b) {
|
||||
@@ -623,7 +605,7 @@ bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) {
|
||||
return ((a(x) && b(y)) || (b(x) && a(y)));
|
||||
}
|
||||
|
||||
bool signature_parameter_similar_enough(Type *x, Type *y) {
|
||||
gb_internal bool signature_parameter_similar_enough(Type *x, Type *y) {
|
||||
if (sig_compare(is_type_pointer, x, y)) {
|
||||
return true;
|
||||
}
|
||||
@@ -674,7 +656,7 @@ bool signature_parameter_similar_enough(Type *x, Type *y) {
|
||||
}
|
||||
|
||||
|
||||
bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
gb_internal bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
GB_ASSERT(a_->kind == Type_Proc);
|
||||
GB_ASSERT(b_->kind == Type_Proc);
|
||||
TypeProc *a = &a_->Proc;
|
||||
@@ -704,7 +686,7 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
||||
return true;
|
||||
}
|
||||
|
||||
Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
|
||||
gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
|
||||
Ast *ident = nullptr;
|
||||
Entity **foreign_library = nullptr;
|
||||
|
||||
@@ -747,7 +729,7 @@ Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix) {
|
||||
gb_internal String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix) {
|
||||
if (link_prefix.len > 0) {
|
||||
if (link_name.len > 0) {
|
||||
error(token, "'link_name' and 'link_prefix' cannot be used together");
|
||||
@@ -764,7 +746,7 @@ String handle_link_name(CheckerContext *ctx, Token token, String link_name, Stri
|
||||
return link_name;
|
||||
}
|
||||
|
||||
void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
if (d->proc_lit->kind != Ast_ProcLit) {
|
||||
// TOOD(bill): Better error message
|
||||
@@ -1004,7 +986,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
|
||||
GB_ASSERT(pl->body->kind == Ast_BlockStmt);
|
||||
if (!pt->is_polymorphic) {
|
||||
check_procedure_later(ctx, ctx->file, e->token, d, proc_type, pl->body, pl->tags);
|
||||
check_procedure_later(ctx->checker, ctx->file, e->token, d, proc_type, pl->body, pl->tags);
|
||||
}
|
||||
} else if (!is_foreign) {
|
||||
if (e->Procedure.is_export) {
|
||||
@@ -1028,7 +1010,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
|
||||
if (ac.deferred_procedure.entity != nullptr) {
|
||||
e->Procedure.deferred_procedure = ac.deferred_procedure;
|
||||
mpmc_enqueue(&ctx->checker->procs_with_deferred_to_check, e);
|
||||
mpsc_enqueue(&ctx->checker->procs_with_deferred_to_check, e);
|
||||
}
|
||||
|
||||
if (is_foreign) {
|
||||
@@ -1121,7 +1103,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
|
||||
}
|
||||
}
|
||||
|
||||
void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) {
|
||||
gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) {
|
||||
GB_ASSERT(e->type == nullptr);
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
|
||||
@@ -1142,7 +1124,7 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
|
||||
|
||||
if (ac.require_declaration) {
|
||||
e->flags |= EntityFlag_Require;
|
||||
mpmc_enqueue(&ctx->info->required_global_variable_queue, e);
|
||||
mpsc_enqueue(&ctx->info->required_global_variable_queue, e);
|
||||
}
|
||||
|
||||
|
||||
@@ -1239,7 +1221,7 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
|
||||
check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed");
|
||||
}
|
||||
|
||||
void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) {
|
||||
gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) {
|
||||
GB_ASSERT(pg_entity->kind == Entity_ProcGroup);
|
||||
auto *pge = &pg_entity->ProcGroup;
|
||||
String proc_group_name = pg_entity->token.string;
|
||||
@@ -1253,10 +1235,9 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d)
|
||||
pg_entity->type = t_invalid;
|
||||
|
||||
PtrSet<Entity *> entity_set = {};
|
||||
ptr_set_init(&entity_set, heap_allocator(), 2*pg->args.count);
|
||||
ptr_set_init(&entity_set, 2*pg->args.count);
|
||||
|
||||
for_array(i, pg->args) {
|
||||
Ast *arg = pg->args[i];
|
||||
for (Ast *arg : pg->args) {
|
||||
Entity *e = nullptr;
|
||||
Operand o = {};
|
||||
if (arg->kind == Ast_Ident) {
|
||||
@@ -1289,7 +1270,7 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d)
|
||||
|
||||
ptr_set_destroy(&entity_set);
|
||||
|
||||
for_array(j, pge->entities) {
|
||||
for (isize j = 0; j < pge->entities.count; j++) {
|
||||
Entity *p = pge->entities[j];
|
||||
if (p->type == t_invalid) {
|
||||
// NOTE(bill): This invalid overload has already been handled
|
||||
@@ -1367,7 +1348,7 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d)
|
||||
|
||||
}
|
||||
|
||||
void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
gb_internal void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_type) {
|
||||
if (e->state == EntityState_Resolved) {
|
||||
return;
|
||||
}
|
||||
@@ -1431,15 +1412,46 @@ end:;
|
||||
}
|
||||
|
||||
|
||||
gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) {
|
||||
if (decl && decl->parent) {
|
||||
Scope *ps = decl->parent->scope;
|
||||
if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
|
||||
return;
|
||||
} else {
|
||||
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
||||
// But only at the procedure level
|
||||
rw_mutex_shared_lock(&decl->deps_mutex);
|
||||
rw_mutex_lock(&decl->parent->deps_mutex);
|
||||
|
||||
for (Entity *e : decl->deps) {
|
||||
ptr_set_add(&decl->parent->deps, e);
|
||||
}
|
||||
|
||||
rw_mutex_unlock(&decl->parent->deps_mutex);
|
||||
rw_mutex_shared_unlock(&decl->deps_mutex);
|
||||
|
||||
rw_mutex_shared_lock(&decl->type_info_deps_mutex);
|
||||
rw_mutex_lock(&decl->parent->type_info_deps_mutex);
|
||||
|
||||
for (Type *t : decl->type_info_deps) {
|
||||
ptr_set_add(&decl->parent->type_info_deps, t);
|
||||
}
|
||||
|
||||
rw_mutex_unlock(&decl->parent->type_info_deps_mutex);
|
||||
rw_mutex_shared_unlock(&decl->type_info_deps_mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ProcUsingVar {
|
||||
Entity *e;
|
||||
Entity *uvar;
|
||||
};
|
||||
|
||||
|
||||
void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
|
||||
gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
|
||||
if (body == nullptr) {
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
GB_ASSERT(body->kind == Ast_BlockStmt);
|
||||
|
||||
@@ -1480,8 +1492,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
{
|
||||
if (type->Proc.param_count > 0) {
|
||||
TypeTuple *params = &type->Proc.params->Tuple;
|
||||
for_array(i, params->variables) {
|
||||
Entity *e = params->variables[i];
|
||||
for (Entity *e : params->variables) {
|
||||
if (e->kind != Entity_Variable) {
|
||||
continue;
|
||||
}
|
||||
@@ -1489,7 +1500,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
continue;
|
||||
}
|
||||
if (is_blank_ident(e->token)) {
|
||||
error(e->token, "'using' a procedure parameter requires a non blank identifier");
|
||||
error(e->token, "'using' a procedure parameter requires a non blank identifier");
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1499,8 +1510,9 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
if (t->kind == Type_Struct) {
|
||||
Scope *scope = t->Struct.scope;
|
||||
GB_ASSERT(scope != nullptr);
|
||||
MUTEX_GUARD_BLOCK(scope->mutex) for_array(i, scope->elements.entries) {
|
||||
Entity *f = scope->elements.entries[i].value;
|
||||
rw_mutex_lock(&scope->mutex);
|
||||
for (auto const &entry : scope->elements) {
|
||||
Entity *f = entry.value;
|
||||
if (f->kind == Entity_Variable) {
|
||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
|
||||
if (is_value) uvar->flags |= EntityFlag_Value;
|
||||
@@ -1509,6 +1521,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
array_add(&using_entities, puv);
|
||||
}
|
||||
}
|
||||
rw_mutex_unlock(&scope->mutex);
|
||||
} else {
|
||||
error(e->token, "'using' can only be applied to variables of type struct");
|
||||
break;
|
||||
@@ -1517,41 +1530,50 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
}
|
||||
}
|
||||
|
||||
MUTEX_GUARD_BLOCK(ctx->scope->mutex) for_array(i, using_entities) {
|
||||
Entity *e = using_entities[i].e;
|
||||
Entity *uvar = using_entities[i].uvar;
|
||||
Entity *prev = scope_insert(ctx->scope, uvar, false);
|
||||
rw_mutex_lock(&ctx->scope->mutex);
|
||||
for (auto const &entry : using_entities) {
|
||||
Entity *e = entry.e;
|
||||
Entity *uvar = entry.uvar;
|
||||
Entity *prev = scope_insert_no_mutex(ctx->scope, uvar);
|
||||
if (prev != nullptr) {
|
||||
error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
|
||||
error_line("%.*s != %.*s\n", LIT(uvar->token.string), LIT(prev->token.string));
|
||||
break;
|
||||
}
|
||||
}
|
||||
rw_mutex_unlock(&ctx->scope->mutex);
|
||||
|
||||
|
||||
bool where_clause_ok = evaluate_where_clauses(ctx, nullptr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, !decl->where_clauses_evaluated);
|
||||
if (!where_clause_ok) {
|
||||
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
check_open_scope(ctx, body);
|
||||
{
|
||||
for_array(i, using_entities) {
|
||||
Entity *uvar = using_entities[i].uvar;
|
||||
for (auto const &entry : using_entities) {
|
||||
Entity *uvar = entry.uvar;
|
||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||
gb_unused(prev);
|
||||
// NOTE(bill): Don't err here
|
||||
}
|
||||
|
||||
GB_ASSERT(decl->proc_checked_state != ProcCheckedState_Checked);
|
||||
if (decl->defer_use_checked) {
|
||||
GB_ASSERT(is_type_polymorphic(type, true));
|
||||
error(token, "Defer Use Checked: %.*s", LIT(decl->entity->token.string));
|
||||
GB_ASSERT(decl->defer_use_checked == false);
|
||||
}
|
||||
|
||||
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
|
||||
|
||||
for_array(i, bs->stmts) {
|
||||
Ast *stmt = bs->stmts[i];
|
||||
decl->defer_use_checked = true;
|
||||
|
||||
for (Ast *stmt : bs->stmts) {
|
||||
if (stmt->kind == Ast_ValueDecl) {
|
||||
ast_node(vd, ValueDecl, stmt);
|
||||
for_array(j, vd->names) {
|
||||
Ast *name = vd->names[j];
|
||||
for (Ast *name : vd->names) {
|
||||
if (!is_blank_ident(name)) {
|
||||
if (name->kind == Ast_Ident) {
|
||||
GB_ASSERT(name->Ident.entity != nullptr);
|
||||
@@ -1580,30 +1602,13 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
check_close_scope(ctx);
|
||||
|
||||
check_scope_usage(ctx->checker, ctx->scope);
|
||||
|
||||
if (decl->parent != nullptr) {
|
||||
Scope *ps = decl->parent->scope;
|
||||
if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
|
||||
return;
|
||||
} else {
|
||||
mutex_lock(&ctx->info->deps_mutex);
|
||||
add_deps_from_child_to_parent(decl);
|
||||
|
||||
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
||||
// But only at the procedure level
|
||||
for_array(i, decl->deps.entries) {
|
||||
Entity *e = decl->deps.entries[i].ptr;
|
||||
ptr_set_add(&decl->parent->deps, e);
|
||||
}
|
||||
for_array(i, decl->type_info_deps.entries) {
|
||||
Type *t = decl->type_info_deps.entries[i].ptr;
|
||||
ptr_set_add(&decl->parent->type_info_deps, t);
|
||||
}
|
||||
|
||||
mutex_unlock(&ctx->info->deps_mutex);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
+412
-410
File diff suppressed because it is too large
Load Diff
+875
-863
File diff suppressed because it is too large
Load Diff
+144
-132
@@ -1,6 +1,6 @@
|
||||
ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location);
|
||||
gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location);
|
||||
|
||||
void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) {
|
||||
gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) {
|
||||
t = base_type(t);
|
||||
GB_ASSERT(t->kind == Type_Array);
|
||||
Entity *e = scope_lookup_current(ctx->scope, name);
|
||||
@@ -27,7 +27,7 @@ void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field,
|
||||
}
|
||||
}
|
||||
|
||||
void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) {
|
||||
gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) {
|
||||
if (t == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -81,7 +81,7 @@ void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field
|
||||
}
|
||||
}
|
||||
|
||||
bool does_field_type_allow_using(Type *t) {
|
||||
gb_internal bool does_field_type_allow_using(Type *t) {
|
||||
t = base_type(t);
|
||||
if (is_type_struct(t)) {
|
||||
return true;
|
||||
@@ -91,8 +91,8 @@ bool does_field_type_allow_using(Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields, String **tags, Slice<Ast *> const ¶ms,
|
||||
isize init_field_capacity, Type *struct_type, String context) {
|
||||
gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields, String **tags, Slice<Ast *> const ¶ms,
|
||||
isize init_field_capacity, Type *struct_type, String context) {
|
||||
auto fields_array = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
|
||||
auto tags_array = array_make<String>(heap_allocator(), 0, init_field_capacity);
|
||||
|
||||
@@ -219,7 +219,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
|
||||
}
|
||||
|
||||
|
||||
bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
|
||||
gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
|
||||
GB_ASSERT(align_ != nullptr);
|
||||
Operand o = {};
|
||||
check_expr(ctx, &o, node);
|
||||
@@ -256,71 +256,88 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
|
||||
}
|
||||
|
||||
|
||||
Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> const &ordered_operands, bool *failure) {
|
||||
mutex_lock(&ctx->info->gen_types_mutex);
|
||||
defer (mutex_unlock(&ctx->info->gen_types_mutex));
|
||||
gb_internal Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> const &ordered_operands, bool *failure) {
|
||||
rw_mutex_shared_lock(&ctx->info->gen_types_mutex); // @@global
|
||||
|
||||
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
|
||||
if (found_gen_types != nullptr) {
|
||||
// GB_ASSERT_MSG(ordered_operands.count >= param_count, "%td >= %td", ordered_operands.count, param_count);
|
||||
if (found_gen_types == nullptr) {
|
||||
rw_mutex_shared_unlock(&ctx->info->gen_types_mutex); // @@global
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
for_array(i, *found_gen_types) {
|
||||
Entity *e = (*found_gen_types)[i];
|
||||
Type *t = base_type(e->type);
|
||||
TypeTuple *tuple = get_record_polymorphic_params(t);
|
||||
GB_ASSERT(param_count == tuple->variables.count);
|
||||
rw_mutex_shared_lock(&found_gen_types->mutex); // @@local
|
||||
defer (rw_mutex_shared_unlock(&found_gen_types->mutex)); // @@local
|
||||
|
||||
bool skip = false;
|
||||
rw_mutex_shared_unlock(&ctx->info->gen_types_mutex); // @@global
|
||||
|
||||
for (isize j = 0; j < param_count; j++) {
|
||||
Entity *p = tuple->variables[j];
|
||||
Operand o = {};
|
||||
if (j < ordered_operands.count) {
|
||||
o = ordered_operands[j];
|
||||
}
|
||||
if (o.expr == nullptr) {
|
||||
continue;
|
||||
}
|
||||
Entity *oe = entity_of_node(o.expr);
|
||||
if (p == oe) {
|
||||
// NOTE(bill): This is the same type, make sure that it will be be same thing and use that
|
||||
// Saves on a lot of checking too below
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p->kind == Entity_TypeName) {
|
||||
if (is_type_polymorphic(o.type)) {
|
||||
// NOTE(bill): Do not add polymorphic version to the gen_types
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
if (!are_types_identical(o.type, p->type)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
} else if (p->kind == Entity_Constant) {
|
||||
if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
if (!are_types_identical(o.type, p->type)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
GB_PANIC("Unknown entity kind");
|
||||
}
|
||||
for (Entity *e : found_gen_types->types) {
|
||||
Type *t = base_type(e->type);
|
||||
TypeTuple *tuple = nullptr;
|
||||
switch (t->kind) {
|
||||
case Type_Struct:
|
||||
if (t->Struct.polymorphic_params) {
|
||||
tuple = &t->Struct.polymorphic_params->Tuple;
|
||||
}
|
||||
if (!skip) {
|
||||
return e;
|
||||
break;
|
||||
case Type_Union:
|
||||
if (t->Union.polymorphic_params) {
|
||||
tuple = &t->Union.polymorphic_params->Tuple;
|
||||
}
|
||||
break;
|
||||
}
|
||||
GB_ASSERT_MSG(tuple != nullptr, "%s :: %s", type_to_string(e->type), type_to_string(t));
|
||||
GB_ASSERT(param_count == tuple->variables.count);
|
||||
|
||||
bool skip = false;
|
||||
|
||||
for (isize j = 0; j < param_count; j++) {
|
||||
Entity *p = tuple->variables[j];
|
||||
Operand o = {};
|
||||
if (j < ordered_operands.count) {
|
||||
o = ordered_operands[j];
|
||||
}
|
||||
if (o.expr == nullptr) {
|
||||
continue;
|
||||
}
|
||||
Entity *oe = entity_of_node(o.expr);
|
||||
if (p == oe) {
|
||||
// NOTE(bill): This is the same type, make sure that it will be be same thing and use that
|
||||
// Saves on a lot of checking too below
|
||||
continue;
|
||||
}
|
||||
|
||||
if (p->kind == Entity_TypeName) {
|
||||
if (is_type_polymorphic(o.type)) {
|
||||
// NOTE(bill): Do not add polymorphic version to the gen_types
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
if (!are_types_identical(o.type, p->type)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
} else if (p->kind == Entity_Constant) {
|
||||
if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
if (!are_types_identical(o.type, p->type)) {
|
||||
skip = true;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
GB_PANIC("Unknown entity kind");
|
||||
}
|
||||
}
|
||||
if (!skip) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_type, Type *original_type) {
|
||||
gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_type, Type *original_type) {
|
||||
GB_ASSERT(is_type_named(named_type));
|
||||
gbAllocator a = heap_allocator();
|
||||
Scope *s = ctx->scope->parent;
|
||||
@@ -346,22 +363,24 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t
|
||||
// TODO(bill): Is this even correct? Or should the metadata be copied?
|
||||
e->TypeName.objc_metadata = original_type->Named.type_name->TypeName.objc_metadata;
|
||||
|
||||
mutex_lock(&ctx->info->gen_types_mutex);
|
||||
rw_mutex_lock(&ctx->info->gen_types_mutex);
|
||||
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
|
||||
if (found_gen_types) {
|
||||
array_add(found_gen_types, e);
|
||||
rw_mutex_lock(&found_gen_types->mutex);
|
||||
array_add(&found_gen_types->types, e);
|
||||
rw_mutex_unlock(&found_gen_types->mutex);
|
||||
} else {
|
||||
auto array = array_make<Entity *>(heap_allocator());
|
||||
array_add(&array, e);
|
||||
map_set(&ctx->info->gen_types, original_type, array);
|
||||
GenTypesData gen_types = {};
|
||||
gen_types.types = array_make<Entity *>(heap_allocator());
|
||||
array_add(&gen_types.types, e);
|
||||
map_set(&ctx->info->gen_types, original_type, gen_types);
|
||||
}
|
||||
mutex_unlock(&ctx->info->gen_types_mutex);
|
||||
rw_mutex_unlock(&ctx->info->gen_types_mutex);
|
||||
}
|
||||
|
||||
Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params,
|
||||
bool *is_polymorphic_,
|
||||
Ast *node, Array<Operand> *poly_operands,
|
||||
Type *named_type, Type *original_type_for_poly) {
|
||||
gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params,
|
||||
bool *is_polymorphic_,
|
||||
Ast *node, Array<Operand> *poly_operands) {
|
||||
Type *polymorphic_params_type = nullptr;
|
||||
bool can_check_fields = true;
|
||||
GB_ASSERT(is_polymorphic_ != nullptr);
|
||||
@@ -528,11 +547,6 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
|
||||
}
|
||||
}
|
||||
|
||||
if (original_type_for_poly != nullptr) {
|
||||
GB_ASSERT(named_type != nullptr);
|
||||
add_polymorphic_record_entity(ctx, node, named_type, original_type_for_poly);
|
||||
}
|
||||
|
||||
if (!*is_polymorphic_) {
|
||||
*is_polymorphic_ = polymorphic_params != nullptr && poly_operands == nullptr;
|
||||
}
|
||||
@@ -540,7 +554,7 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
|
||||
return polymorphic_params_type;
|
||||
}
|
||||
|
||||
bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_type, Array<Operand> *poly_operands, bool *is_polymorphic_) {
|
||||
gb_internal bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_type, Array<Operand> *poly_operands, bool *is_polymorphic_) {
|
||||
if (poly_operands == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -569,7 +583,7 @@ bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_
|
||||
}
|
||||
|
||||
|
||||
void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
|
||||
gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
|
||||
GB_ASSERT(is_type_struct(struct_type));
|
||||
ast_node(st, StructType, node);
|
||||
|
||||
@@ -600,10 +614,13 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
struct_type->Struct.polymorphic_params = check_record_polymorphic_params(
|
||||
ctx, st->polymorphic_params,
|
||||
&struct_type->Struct.is_polymorphic,
|
||||
node, poly_operands,
|
||||
named_type, original_type_for_poly
|
||||
);;
|
||||
node, poly_operands
|
||||
);
|
||||
struct_type->Struct.is_poly_specialized = check_record_poly_operand_specialization(ctx, struct_type, poly_operands, &struct_type->Struct.is_polymorphic);
|
||||
if (original_type_for_poly) {
|
||||
GB_ASSERT(named_type != nullptr);
|
||||
add_polymorphic_record_entity(ctx, node, named_type, original_type_for_poly);
|
||||
}
|
||||
|
||||
if (!struct_type->Struct.is_polymorphic) {
|
||||
if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
|
||||
@@ -626,7 +643,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
||||
}
|
||||
}
|
||||
}
|
||||
void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
|
||||
gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
|
||||
GB_ASSERT(is_type_union(union_type));
|
||||
ast_node(ut, UnionType, node);
|
||||
|
||||
@@ -635,10 +652,13 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
union_type->Union.polymorphic_params = check_record_polymorphic_params(
|
||||
ctx, ut->polymorphic_params,
|
||||
&union_type->Union.is_polymorphic,
|
||||
node, poly_operands,
|
||||
named_type, original_type_for_poly
|
||||
node, poly_operands
|
||||
);
|
||||
union_type->Union.is_poly_specialized = check_record_poly_operand_specialization(ctx, union_type, poly_operands, &union_type->Union.is_polymorphic);
|
||||
if (original_type_for_poly) {
|
||||
GB_ASSERT(named_type != nullptr);
|
||||
add_polymorphic_record_entity(ctx, node, named_type, original_type_for_poly);
|
||||
}
|
||||
|
||||
if (!union_type->Union.is_polymorphic) {
|
||||
if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
|
||||
@@ -709,7 +729,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
|
||||
}
|
||||
}
|
||||
|
||||
void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast *node) {
|
||||
gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast *node) {
|
||||
ast_node(et, EnumType, node);
|
||||
GB_ASSERT(is_type_enum(enum_type));
|
||||
|
||||
@@ -851,7 +871,7 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
|
||||
enum_type->Enum.max_value_index = max_value_index;
|
||||
}
|
||||
|
||||
bool is_type_valid_bit_set_range(Type *t) {
|
||||
gb_internal bool is_type_valid_bit_set_range(Type *t) {
|
||||
if (is_type_integer(t)) {
|
||||
return true;
|
||||
}
|
||||
@@ -861,7 +881,7 @@ bool is_type_valid_bit_set_range(Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *node) {
|
||||
gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *node) {
|
||||
ast_node(bs, BitSetType, node);
|
||||
GB_ASSERT(type->kind == Type_BitSet);
|
||||
type->BitSet.node = node;
|
||||
@@ -1102,7 +1122,7 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no
|
||||
}
|
||||
|
||||
|
||||
bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) {
|
||||
gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) {
|
||||
if (type == nullptr ||
|
||||
type == t_invalid) {
|
||||
return true;
|
||||
@@ -1229,7 +1249,7 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ
|
||||
}
|
||||
|
||||
|
||||
Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand const &operand) {
|
||||
gb_internal Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand const &operand) {
|
||||
bool modify_type = !ctx->no_polymorphic_errors;
|
||||
bool show_error = modify_type && !ctx->hide_polymorphic_errors;
|
||||
if (!is_operand_value(operand)) {
|
||||
@@ -1256,7 +1276,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper
|
||||
return t_invalid;
|
||||
}
|
||||
|
||||
bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) {
|
||||
gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) {
|
||||
if (expr == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -1275,7 +1295,7 @@ bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) {
|
||||
}
|
||||
|
||||
|
||||
ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) {
|
||||
gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) {
|
||||
ParameterValue param_value = {};
|
||||
param_value.original_ast_expr = expr;
|
||||
if (expr == nullptr) {
|
||||
@@ -1370,7 +1390,7 @@ ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type *
|
||||
}
|
||||
|
||||
|
||||
Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
|
||||
gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
|
||||
if (_params == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1599,10 +1619,6 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
}
|
||||
}
|
||||
|
||||
if (p->flags&FieldFlag_auto_cast) {
|
||||
error(name, "'auto_cast' can only be applied to variable fields");
|
||||
p->flags &= ~FieldFlag_auto_cast;
|
||||
}
|
||||
if (p->flags&FieldFlag_const) {
|
||||
error(name, "'#const' can only be applied to variable fields");
|
||||
p->flags &= ~FieldFlag_const;
|
||||
@@ -1639,6 +1655,12 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
} else if (!ctx->no_polymorphic_errors) {
|
||||
// NOTE(bill): The type should be determined now and thus, no need to determine the type any more
|
||||
is_type_polymorphic_type = false;
|
||||
Entity *proc_entity = entity_from_expr(op.expr);
|
||||
if ((proc_entity != nullptr) && (op.value.kind == ExactValue_Procedure)) {
|
||||
if (is_type_polymorphic(proc_entity->type, false)) {
|
||||
error(op.expr, "Cannot determine complete type of partial polymorphic procedure");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (is_poly_name) {
|
||||
@@ -1661,11 +1683,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
}
|
||||
if (type != t_invalid && !check_is_assignable_to(ctx, &op, type)) {
|
||||
bool ok = true;
|
||||
if (p->flags&FieldFlag_auto_cast) {
|
||||
if (!check_is_castable_to(ctx, &op, type)) {
|
||||
ok = false;
|
||||
}
|
||||
} else if (p->flags&FieldFlag_any_int) {
|
||||
if (p->flags&FieldFlag_any_int) {
|
||||
if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) {
|
||||
ok = false;
|
||||
} else if (!check_is_castable_to(ctx, &op, type)) {
|
||||
@@ -1711,10 +1729,6 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
error(name, "'#no_alias' can only be applied to non constant values");
|
||||
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
||||
}
|
||||
if (p->flags&FieldFlag_auto_cast) {
|
||||
error(name, "'auto_cast' can only be applied to variable fields");
|
||||
p->flags &= ~FieldFlag_auto_cast;
|
||||
}
|
||||
if (p->flags&FieldFlag_any_int) {
|
||||
error(name, "'#any_int' can only be applied to variable fields");
|
||||
p->flags &= ~FieldFlag_any_int;
|
||||
@@ -1745,9 +1759,6 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
if (p->flags&FieldFlag_no_alias) {
|
||||
param->flags |= EntityFlag_NoAlias;
|
||||
}
|
||||
if (p->flags&FieldFlag_auto_cast) {
|
||||
param->flags |= EntityFlag_AutoCast;
|
||||
}
|
||||
if (p->flags&FieldFlag_any_int) {
|
||||
if (!is_type_integer(param->type) && !is_type_enum(param->type)) {
|
||||
gbString str = type_to_string(param->type);
|
||||
@@ -1791,8 +1802,8 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
|
||||
isize specialization_count = 0;
|
||||
if (scope != nullptr) {
|
||||
for_array(i, scope->elements.entries) {
|
||||
Entity *e = scope->elements.entries[i].value;
|
||||
for (auto const &entry : scope->elements) {
|
||||
Entity *e = entry.value;
|
||||
if (e->kind == Entity_TypeName) {
|
||||
Type *t = e->type;
|
||||
if (t->kind == Type_Generic &&
|
||||
@@ -1814,7 +1825,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
||||
return tuple;
|
||||
}
|
||||
|
||||
Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
|
||||
gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
|
||||
if (_results == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -1928,7 +1939,7 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
|
||||
|
||||
|
||||
// NOTE(bill): 'operands' is for generating non generic procedure type
|
||||
bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, Array<Operand> *operands) {
|
||||
gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, Array<Operand> *operands) {
|
||||
ast_node(pt, ProcType, proc_type_node);
|
||||
|
||||
if (ctx->polymorphic_scope == nullptr && ctx->allow_polymorphic_types) {
|
||||
@@ -2084,7 +2095,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
||||
}
|
||||
|
||||
|
||||
i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
|
||||
gb_internal i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
|
||||
if (e == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
@@ -2169,7 +2180,7 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
Type *make_optional_ok_type(Type *value, bool typed) {
|
||||
gb_internal Type *make_optional_ok_type(Type *value, bool typed) {
|
||||
gbAllocator a = permanent_allocator();
|
||||
Type *t = alloc_type_tuple();
|
||||
slice_init(&t->Tuple.variables, a, 2);
|
||||
@@ -2181,23 +2192,23 @@ Type *make_optional_ok_type(Type *value, bool typed) {
|
||||
|
||||
// IMPORTANT NOTE(bill): This must match the definition in dynamic_map_internal.odin
|
||||
enum : i64 {
|
||||
MAP_CACHE_LINE_LOG2 = 6,
|
||||
MAP_CACHE_LINE_SIZE = 1 << MAP_CACHE_LINE_LOG2
|
||||
MAP_CELL_CACHE_LINE_LOG2 = 6,
|
||||
MAP_CELL_CACHE_LINE_SIZE = 1 << MAP_CELL_CACHE_LINE_LOG2,
|
||||
};
|
||||
GB_STATIC_ASSERT(MAP_CACHE_LINE_SIZE >= 64);
|
||||
void map_cell_size_and_len(Type *type, i64 *size_, i64 *len_) {
|
||||
GB_STATIC_ASSERT(MAP_CELL_CACHE_LINE_SIZE >= 64);
|
||||
gb_internal void map_cell_size_and_len(Type *type, i64 *size_, i64 *len_) {
|
||||
i64 elem_sz = type_size_of(type);
|
||||
|
||||
i64 len = 1;
|
||||
if (0 < elem_sz && elem_sz < MAP_CACHE_LINE_SIZE) {
|
||||
len = MAP_CACHE_LINE_SIZE / elem_sz;
|
||||
if (0 < elem_sz && elem_sz < MAP_CELL_CACHE_LINE_SIZE) {
|
||||
len = MAP_CELL_CACHE_LINE_SIZE / elem_sz;
|
||||
}
|
||||
i64 size = align_formula(elem_sz * len, MAP_CACHE_LINE_SIZE);
|
||||
i64 size = align_formula(elem_sz * len, MAP_CELL_CACHE_LINE_SIZE);
|
||||
if (size_) *size_ = size;
|
||||
if (len_) *len_ = len;
|
||||
}
|
||||
|
||||
void init_map_internal_types(Type *type) {
|
||||
gb_internal void init_map_internal_types(Type *type) {
|
||||
GB_ASSERT(type->kind == Type_Map);
|
||||
GB_ASSERT(t_allocator != nullptr);
|
||||
if (type->Map.lookup_result_type != nullptr) return;
|
||||
@@ -2210,7 +2221,7 @@ void init_map_internal_types(Type *type) {
|
||||
type->Map.lookup_result_type = make_optional_ok_type(value);
|
||||
}
|
||||
|
||||
void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
|
||||
gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
|
||||
key = core_type(key);
|
||||
|
||||
if (is_type_cstring(key)) {
|
||||
@@ -2249,7 +2260,7 @@ void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
|
||||
}
|
||||
}
|
||||
|
||||
void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
|
||||
gb_internal void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
|
||||
GB_ASSERT(type->kind == Type_Map);
|
||||
ast_node(mt, MapType, node);
|
||||
|
||||
@@ -2282,7 +2293,7 @@ void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
|
||||
// error(node, "'map' types are not yet implemented");
|
||||
}
|
||||
|
||||
void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) {
|
||||
gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) {
|
||||
ast_node(mt, MatrixType, node);
|
||||
|
||||
Operand row = {};
|
||||
@@ -2346,7 +2357,7 @@ type_assign:;
|
||||
|
||||
|
||||
|
||||
Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type, StructSoaKind soa_kind) {
|
||||
gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type, StructSoaKind soa_kind) {
|
||||
Type *bt_elem = base_type(elem);
|
||||
|
||||
bool is_polymorphic = is_type_polymorphic(elem);
|
||||
@@ -2398,7 +2409,8 @@ Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *el
|
||||
}
|
||||
soa_struct->Struct.soa_count = cast(i32)count;
|
||||
|
||||
scope = create_scope(ctx->info, ctx->scope, 8);
|
||||
scope = create_scope(ctx->info, ctx->scope);
|
||||
string_map_init(&scope->elements, 8);
|
||||
soa_struct->Struct.scope = scope;
|
||||
|
||||
String params_xyzw[4] = {
|
||||
@@ -2501,20 +2513,20 @@ Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *el
|
||||
}
|
||||
|
||||
|
||||
Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type) {
|
||||
gb_internal Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type) {
|
||||
return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, count, generic_type, StructSoa_Fixed);
|
||||
}
|
||||
|
||||
Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) {
|
||||
gb_internal Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) {
|
||||
return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, -1, nullptr, StructSoa_Slice);
|
||||
}
|
||||
|
||||
|
||||
Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) {
|
||||
gb_internal Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) {
|
||||
return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, -1, nullptr, StructSoa_Dynamic);
|
||||
}
|
||||
|
||||
bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) {
|
||||
gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) {
|
||||
GB_ASSERT_NOT_NULL(type);
|
||||
if (e == nullptr) {
|
||||
*type = t_invalid;
|
||||
@@ -2997,7 +3009,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
||||
return false;
|
||||
}
|
||||
|
||||
Type *check_type(CheckerContext *ctx, Ast *e) {
|
||||
gb_internal Type *check_type(CheckerContext *ctx, Ast *e) {
|
||||
CheckerContext c = *ctx;
|
||||
c.type_path = new_checker_type_path();
|
||||
defer (destroy_checker_type_path(c.type_path));
|
||||
@@ -3005,7 +3017,7 @@ Type *check_type(CheckerContext *ctx, Ast *e) {
|
||||
return check_type_expr(&c, e, nullptr);
|
||||
}
|
||||
|
||||
Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) {
|
||||
gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) {
|
||||
Type *type = nullptr;
|
||||
bool ok = check_type_internal(ctx, e, &type, named_type);
|
||||
|
||||
@@ -3045,7 +3057,7 @@ Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) {
|
||||
#endif
|
||||
|
||||
if (is_type_typed(type)) {
|
||||
add_type_and_value(ctx->info, e, Addressing_Type, type, empty_exact_value);
|
||||
add_type_and_value(ctx, e, Addressing_Type, type, empty_exact_value);
|
||||
} else {
|
||||
gbString name = type_to_string(type);
|
||||
error(e, "Invalid type definition of %s", name);
|
||||
|
||||
+781
-789
File diff suppressed because it is too large
Load Diff
+104
-87
@@ -20,7 +20,7 @@ struct ExprInfo {
|
||||
ExactValue value;
|
||||
};
|
||||
|
||||
gb_inline ExprInfo *make_expr_info(AddressingMode mode, Type *type, ExactValue const &value, bool is_lhs) {
|
||||
gb_internal gb_inline ExprInfo *make_expr_info(AddressingMode mode, Type *type, ExactValue const &value, bool is_lhs) {
|
||||
ExprInfo *ei = gb_alloc_item(permanent_allocator(), ExprInfo);
|
||||
ei->mode = mode;
|
||||
ei->type = type;
|
||||
@@ -130,7 +130,7 @@ struct AttributeContext {
|
||||
String enable_target_feature; // will be enabled for the procedure only
|
||||
};
|
||||
|
||||
AttributeContext make_attribute_context(String link_prefix) {
|
||||
gb_internal gb_inline AttributeContext make_attribute_context(String link_prefix) {
|
||||
AttributeContext ac = {};
|
||||
ac.link_prefix = link_prefix;
|
||||
return ac;
|
||||
@@ -139,12 +139,31 @@ AttributeContext make_attribute_context(String link_prefix) {
|
||||
#define DECL_ATTRIBUTE_PROC(_name) bool _name(CheckerContext *c, Ast *elem, String name, Ast *value, AttributeContext *ac)
|
||||
typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
|
||||
|
||||
void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, DeclAttributeProc *proc, AttributeContext *ac);
|
||||
gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, DeclAttributeProc *proc, AttributeContext *ac);
|
||||
|
||||
|
||||
enum ProcCheckedState : u8 {
|
||||
ProcCheckedState_Unchecked,
|
||||
ProcCheckedState_InProgress,
|
||||
ProcCheckedState_Checked,
|
||||
|
||||
ProcCheckedState_COUNT
|
||||
};
|
||||
|
||||
char const *ProcCheckedState_strings[ProcCheckedState_COUNT] {
|
||||
"Unchecked",
|
||||
"In Progress",
|
||||
"Checked",
|
||||
};
|
||||
|
||||
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
|
||||
struct DeclInfo {
|
||||
DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment
|
||||
|
||||
BlockingMutex next_mutex;
|
||||
DeclInfo * next_child;
|
||||
DeclInfo * next_sibling;
|
||||
|
||||
Scope * scope;
|
||||
|
||||
Entity *entity;
|
||||
@@ -157,13 +176,22 @@ struct DeclInfo {
|
||||
Type * gen_proc_type; // Precalculated
|
||||
bool is_using;
|
||||
bool where_clauses_evaluated;
|
||||
bool proc_checked;
|
||||
std::atomic<ProcCheckedState> proc_checked_state;
|
||||
BlockingMutex proc_checked_mutex;
|
||||
isize defer_used;
|
||||
bool defer_use_checked;
|
||||
|
||||
CommentGroup *comment;
|
||||
CommentGroup *docs;
|
||||
|
||||
PtrSet<Entity *> deps;
|
||||
RwMutex deps_mutex;
|
||||
PtrSet<Entity *> deps;
|
||||
|
||||
RwMutex type_info_deps_mutex;
|
||||
PtrSet<Type *> type_info_deps;
|
||||
|
||||
BlockingMutex type_and_value_mutex;
|
||||
|
||||
Array<BlockLabel> labels;
|
||||
};
|
||||
|
||||
@@ -195,7 +223,7 @@ enum ScopeFlag : i32 {
|
||||
ScopeFlag_ContextDefined = 1<<16,
|
||||
};
|
||||
|
||||
enum { DEFAULT_SCOPE_CAPACITY = 29 };
|
||||
enum { DEFAULT_SCOPE_CAPACITY = 32 };
|
||||
|
||||
struct Scope {
|
||||
Ast * node;
|
||||
@@ -203,7 +231,7 @@ struct Scope {
|
||||
std::atomic<Scope *> next;
|
||||
std::atomic<Scope *> head_child;
|
||||
|
||||
BlockingMutex mutex;
|
||||
RwMutex mutex;
|
||||
StringMap<Entity *> elements;
|
||||
PtrSet<Scope *> imported;
|
||||
|
||||
@@ -275,7 +303,6 @@ struct UntypedExprInfo {
|
||||
};
|
||||
|
||||
typedef PtrMap<Ast *, ExprInfo *> UntypedExprInfoMap;
|
||||
typedef MPMCQueue<ProcInfo *> ProcBodyQueue;
|
||||
|
||||
enum ObjcMsgKind : u32 {
|
||||
ObjcMsg_normal,
|
||||
@@ -294,6 +321,16 @@ struct LoadFileCache {
|
||||
StringMap<u64> hashes;
|
||||
};
|
||||
|
||||
struct GenProcsData {
|
||||
Array<Entity *> procs;
|
||||
RwMutex mutex;
|
||||
};
|
||||
|
||||
struct GenTypesData {
|
||||
Array<Entity *> types;
|
||||
RwMutex mutex;
|
||||
};
|
||||
|
||||
// CheckerInfo stores all the symbol information for a type-checked program
|
||||
struct CheckerInfo {
|
||||
Checker *checker;
|
||||
@@ -308,7 +345,7 @@ struct CheckerInfo {
|
||||
Scope * init_scope;
|
||||
Entity * entry_point;
|
||||
PtrSet<Entity *> minimum_dependency_set;
|
||||
PtrSet<isize> minimum_dependency_type_info_set;
|
||||
PtrMap</*type info index*/isize, /*min dep index*/isize> minimum_dependency_type_info_set;
|
||||
|
||||
|
||||
|
||||
@@ -321,30 +358,17 @@ struct CheckerInfo {
|
||||
|
||||
|
||||
// Below are accessed within procedures
|
||||
// NOTE(bill): If the semantic checker (check_proc_body) is to ever to be multithreaded,
|
||||
// these variables will be of contention
|
||||
|
||||
Semaphore collect_semaphore;
|
||||
|
||||
RwMutex global_untyped_mutex;
|
||||
UntypedExprInfoMap global_untyped; // NOTE(bill): This needs to be a map and not on the Ast
|
||||
// as it needs to be iterated across afterwards
|
||||
BlockingMutex global_untyped_mutex;
|
||||
BlockingMutex builtin_mutex;
|
||||
|
||||
// NOT recursive & only used at the end of `check_proc_body`
|
||||
// and in `add_dependency`.
|
||||
// This is a possible source of contention but probably not
|
||||
// too much of a problem in practice
|
||||
BlockingMutex deps_mutex;
|
||||
|
||||
BlockingMutex type_and_value_mutex;
|
||||
|
||||
RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files
|
||||
|
||||
RecursiveMutex gen_procs_mutex;
|
||||
RecursiveMutex gen_types_mutex;
|
||||
PtrMap<Ast *, Array<Entity *> > gen_procs; // Key: Ast * | Identifier -> Entity
|
||||
PtrMap<Type *, Array<Entity *> > gen_types;
|
||||
RwMutex gen_types_mutex;
|
||||
PtrMap<Type *, GenTypesData > gen_types;
|
||||
|
||||
BlockingMutex type_info_mutex; // NOT recursive
|
||||
Array<Type *> type_info_types;
|
||||
@@ -353,37 +377,39 @@ struct CheckerInfo {
|
||||
BlockingMutex foreign_mutex; // NOT recursive
|
||||
StringMap<Entity *> foreigns;
|
||||
|
||||
// only used by 'odin query'
|
||||
bool allow_identifier_uses;
|
||||
BlockingMutex identifier_uses_mutex;
|
||||
Array<Ast *> identifier_uses;
|
||||
|
||||
// NOTE(bill): These are actually MPSC queues
|
||||
// TODO(bill): Convert them to be MPSC queues
|
||||
MPMCQueue<Entity *> definition_queue;
|
||||
MPMCQueue<Entity *> entity_queue;
|
||||
MPMCQueue<Entity *> required_global_variable_queue;
|
||||
MPMCQueue<Entity *> required_foreign_imports_through_force_queue;
|
||||
MPSCQueue<Entity *> definition_queue;
|
||||
MPSCQueue<Entity *> entity_queue;
|
||||
MPSCQueue<Entity *> required_global_variable_queue;
|
||||
MPSCQueue<Entity *> required_foreign_imports_through_force_queue;
|
||||
|
||||
MPMCQueue<Ast *> intrinsics_entry_point_usage;
|
||||
MPSCQueue<Ast *> intrinsics_entry_point_usage;
|
||||
|
||||
BlockingMutex objc_types_mutex;
|
||||
PtrMap<Ast *, ObjcMsgData> objc_msgSend_types;
|
||||
|
||||
BlockingMutex load_file_mutex;
|
||||
StringMap<LoadFileCache *> load_file_cache;
|
||||
|
||||
BlockingMutex all_procedures_mutex;
|
||||
Array<ProcInfo *> all_procedures;
|
||||
};
|
||||
|
||||
struct CheckerContext {
|
||||
// Order matters here
|
||||
BlockingMutex mutex;
|
||||
Checker * checker;
|
||||
CheckerInfo * info;
|
||||
|
||||
AstPackage * pkg;
|
||||
AstFile * file;
|
||||
Scope * scope;
|
||||
DeclInfo * decl;
|
||||
|
||||
// Order doesn't matter after this
|
||||
u32 state_flags;
|
||||
bool in_defer; // TODO(bill): Actually handle correctly
|
||||
bool in_defer;
|
||||
Type * type_hint;
|
||||
|
||||
String proc_name;
|
||||
@@ -394,9 +420,7 @@ struct CheckerContext {
|
||||
ForeignContext foreign_context;
|
||||
|
||||
CheckerTypePath *type_path;
|
||||
isize type_level; // TODO(bill): Actually handle correctly
|
||||
CheckerPolyPath *poly_path;
|
||||
isize poly_level; // TODO(bill): Actually handle correctly
|
||||
isize type_level;
|
||||
|
||||
UntypedExprInfoMap *untyped;
|
||||
|
||||
@@ -413,8 +437,6 @@ struct CheckerContext {
|
||||
Scope * polymorphic_scope;
|
||||
|
||||
Ast *assignment_lhs_hint;
|
||||
|
||||
ProcBodyQueue *procs_to_check_queue;
|
||||
};
|
||||
|
||||
|
||||
@@ -424,13 +446,14 @@ struct Checker {
|
||||
|
||||
CheckerContext builtin_ctx;
|
||||
|
||||
MPMCQueue<Entity *> procs_with_deferred_to_check;
|
||||
MPSCQueue<Entity *> procs_with_deferred_to_check;
|
||||
Array<ProcInfo *> procs_to_check;
|
||||
|
||||
ProcBodyQueue procs_to_check_queue;
|
||||
Semaphore procs_to_check_semaphore;
|
||||
BlockingMutex nested_proc_lits_mutex;
|
||||
Array<DeclInfo *> nested_proc_lits;
|
||||
|
||||
// TODO(bill): Technically MPSC queue
|
||||
MPMCQueue<UntypedExprInfo> global_untyped_queue;
|
||||
|
||||
MPSCQueue<UntypedExprInfo> global_untyped_queue;
|
||||
};
|
||||
|
||||
|
||||
@@ -441,59 +464,53 @@ gb_global AstPackage *config_pkg = nullptr;
|
||||
|
||||
|
||||
// CheckerInfo API
|
||||
TypeAndValue type_and_value_of_expr (Ast *expr);
|
||||
Type * type_of_expr (Ast *expr);
|
||||
Entity * implicit_entity_of_node(Ast *clause);
|
||||
DeclInfo * decl_info_of_ident (Ast *ident);
|
||||
DeclInfo * decl_info_of_entity (Entity * e);
|
||||
AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
|
||||
gb_internal TypeAndValue type_and_value_of_expr (Ast *expr);
|
||||
gb_internal Type * type_of_expr (Ast *expr);
|
||||
gb_internal Entity * implicit_entity_of_node(Ast *clause);
|
||||
gb_internal DeclInfo * decl_info_of_ident (Ast *ident);
|
||||
gb_internal DeclInfo * decl_info_of_entity (Entity * e);
|
||||
gb_internal AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
|
||||
// IMPORTANT: Only to use once checking is done
|
||||
isize type_info_index (CheckerInfo *i, Type *type, bool error_on_failure);
|
||||
gb_internal isize type_info_index (CheckerInfo *i, Type *type, bool error_on_failure);
|
||||
|
||||
// Will return nullptr if not found
|
||||
Entity *entity_of_node(Ast *expr);
|
||||
gb_internal Entity *entity_of_node(Ast *expr);
|
||||
|
||||
|
||||
Entity *scope_lookup_current(Scope *s, String const &name);
|
||||
Entity *scope_lookup (Scope *s, String const &name);
|
||||
void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_);
|
||||
Entity *scope_insert (Scope *s, Entity *entity, bool use_mutex=true);
|
||||
gb_internal Entity *scope_lookup_current(Scope *s, String const &name);
|
||||
gb_internal Entity *scope_lookup (Scope *s, String const &name);
|
||||
gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_);
|
||||
gb_internal Entity *scope_insert (Scope *s, Entity *entity);
|
||||
|
||||
|
||||
void add_type_and_value (CheckerInfo *i, Ast *expression, AddressingMode mode, Type *type, ExactValue value);
|
||||
ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr);
|
||||
void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue value);
|
||||
void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity);
|
||||
void add_implicit_entity (CheckerContext *c, Ast *node, Entity *e);
|
||||
void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, DeclInfo *d, bool is_exported=true);
|
||||
void add_type_info_type (CheckerContext *c, Type *t);
|
||||
gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue value);
|
||||
gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr);
|
||||
gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue value);
|
||||
gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity);
|
||||
gb_internal void add_implicit_entity (CheckerContext *c, Ast *node, Entity *e);
|
||||
gb_internal void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, DeclInfo *d, bool is_exported=true);
|
||||
gb_internal void add_type_info_type (CheckerContext *c, Type *t);
|
||||
|
||||
void check_add_import_decl(CheckerContext *c, Ast *decl);
|
||||
void check_add_foreign_import_decl(CheckerContext *c, Ast *decl);
|
||||
gb_internal void check_add_import_decl(CheckerContext *c, Ast *decl);
|
||||
gb_internal void check_add_foreign_import_decl(CheckerContext *c, Ast *decl);
|
||||
|
||||
|
||||
void check_entity_decl(CheckerContext *c, Entity *e, DeclInfo *d, Type *named_type);
|
||||
void check_const_decl(CheckerContext *c, Entity *e, Ast *type_expr, Ast *init_expr, Type *named_type);
|
||||
void check_type_decl(CheckerContext *c, Entity *e, Ast *type_expr, Type *def);
|
||||
gb_internal void check_entity_decl(CheckerContext *c, Entity *e, DeclInfo *d, Type *named_type);
|
||||
gb_internal void check_const_decl(CheckerContext *c, Entity *e, Ast *type_expr, Ast *init_expr, Type *named_type);
|
||||
gb_internal void check_type_decl(CheckerContext *c, Entity *e, Ast *type_expr, Type *def);
|
||||
|
||||
bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global = false);
|
||||
void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes);
|
||||
void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
|
||||
void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
|
||||
gb_internal bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global = false);
|
||||
gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes);
|
||||
gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
|
||||
gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
|
||||
|
||||
CheckerTypePath *new_checker_type_path();
|
||||
void destroy_checker_type_path(CheckerTypePath *tp);
|
||||
gb_internal CheckerTypePath *new_checker_type_path();
|
||||
gb_internal void destroy_checker_type_path(CheckerTypePath *tp);
|
||||
|
||||
void check_type_path_push(CheckerContext *c, Entity *e);
|
||||
Entity *check_type_path_pop (CheckerContext *c);
|
||||
gb_internal void check_type_path_push(CheckerContext *c, Entity *e);
|
||||
gb_internal Entity *check_type_path_pop (CheckerContext *c);
|
||||
|
||||
CheckerPolyPath *new_checker_poly_path();
|
||||
void destroy_checker_poly_path(CheckerPolyPath *);
|
||||
gb_internal void init_core_context(Checker *c);
|
||||
gb_internal void init_mem_allocator(Checker *c);
|
||||
|
||||
void check_poly_path_push(CheckerContext *c, Type *t);
|
||||
Type *check_poly_path_pop (CheckerContext *c);
|
||||
|
||||
void init_core_context(Checker *c);
|
||||
void init_mem_allocator(Checker *c);
|
||||
|
||||
void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped);
|
||||
gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped);
|
||||
|
||||
+73
-49
@@ -29,36 +29,51 @@
|
||||
#include <string.h>
|
||||
#include <atomic> // Because I wanted the C++11 memory order semantics, of which gb.h does not offer (because it was a C89 library)
|
||||
|
||||
gbAllocator heap_allocator(void);
|
||||
gb_internal gbAllocator heap_allocator(void);
|
||||
|
||||
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
|
||||
#define for_array_off(index_, off_, array_) for (isize index_ = off_; index_ < (array_).count; index_++)
|
||||
#define for_array(index_, array_) for_array_off(index_, 0, array_)
|
||||
|
||||
i32 next_pow2(i32 n);
|
||||
i64 next_pow2(i64 n);
|
||||
isize next_pow2_isize(isize n);
|
||||
void debugf(char const *fmt, ...);
|
||||
gb_internal i32 next_pow2(i32 n);
|
||||
gb_internal i64 next_pow2(i64 n);
|
||||
gb_internal isize next_pow2_isize(isize n);
|
||||
gb_internal void debugf(char const *fmt, ...);
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS) && defined(GB_ARCH_32_BIT)
|
||||
#error Odin on Windows requires a 64-bit build-system. The 'Developer Command Prompt' for VS still defaults to 32-bit shell. The 64-bit shell can be found under the name 'x64 Native Tools Command Prompt' for VS. For more information, please see https://odin-lang.org/docs/install/#for-windows
|
||||
#endif
|
||||
|
||||
#include "threading.cpp"
|
||||
template <typename T>
|
||||
struct TypeIsPointer {
|
||||
enum {value = false};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct TypeIsPointer<T *> {
|
||||
enum {value = true};
|
||||
};
|
||||
|
||||
#include "unicode.cpp"
|
||||
#include "array.cpp"
|
||||
#include "queue.cpp"
|
||||
#include "threading.cpp"
|
||||
#include "common_memory.cpp"
|
||||
#include "queue.cpp"
|
||||
#include "string.cpp"
|
||||
#include "range_cache.cpp"
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4505)
|
||||
#endif
|
||||
|
||||
bool is_power_of_two(i64 x) {
|
||||
gb_internal gb_inline bool is_power_of_two(i64 x) {
|
||||
if (x <= 0) {
|
||||
return false;
|
||||
}
|
||||
return !(x & (x-1));
|
||||
}
|
||||
|
||||
int isize_cmp(isize x, isize y) {
|
||||
gb_internal int isize_cmp(isize x, isize y) {
|
||||
if (x < y) {
|
||||
return -1;
|
||||
} else if (x > y) {
|
||||
@@ -66,7 +81,7 @@ int isize_cmp(isize x, isize y) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int u64_cmp(u64 x, u64 y) {
|
||||
gb_internal int u64_cmp(u64 x, u64 y) {
|
||||
if (x < y) {
|
||||
return -1;
|
||||
} else if (x > y) {
|
||||
@@ -74,7 +89,7 @@ int u64_cmp(u64 x, u64 y) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int i64_cmp(i64 x, i64 y) {
|
||||
gb_internal int i64_cmp(i64 x, i64 y) {
|
||||
if (x < y) {
|
||||
return -1;
|
||||
} else if (x > y) {
|
||||
@@ -82,7 +97,7 @@ int i64_cmp(i64 x, i64 y) {
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int i32_cmp(i32 x, i32 y) {
|
||||
gb_internal int i32_cmp(i32 x, i32 y) {
|
||||
if (x < y) {
|
||||
return -1;
|
||||
} else if (x > y) {
|
||||
@@ -91,7 +106,7 @@ int i32_cmp(i32 x, i32 y) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
u32 fnv32a(void const *data, isize len) {
|
||||
gb_internal u32 fnv32a(void const *data, isize len) {
|
||||
u8 const *bytes = cast(u8 const *)data;
|
||||
u32 h = 0x811c9dc5;
|
||||
|
||||
@@ -112,7 +127,7 @@ u32 fnv32a(void const *data, isize len) {
|
||||
return h;
|
||||
}
|
||||
|
||||
u64 fnv64a(void const *data, isize len) {
|
||||
gb_internal u64 fnv64a(void const *data, isize len) {
|
||||
u8 const *bytes = cast(u8 const *)data;
|
||||
u64 h = 0xcbf29ce484222325ull;
|
||||
|
||||
@@ -133,7 +148,7 @@ u64 fnv64a(void const *data, isize len) {
|
||||
return h;
|
||||
}
|
||||
|
||||
u64 u64_digit_value(Rune r) {
|
||||
gb_internal u64 u64_digit_value(Rune r) {
|
||||
switch (r) {
|
||||
case '0': return 0;
|
||||
case '1': return 1;
|
||||
@@ -162,7 +177,7 @@ u64 u64_digit_value(Rune r) {
|
||||
}
|
||||
|
||||
|
||||
u64 u64_from_string(String string) {
|
||||
gb_internal u64 u64_from_string(String string) {
|
||||
u64 base = 10;
|
||||
bool has_prefix = false;
|
||||
if (string.len > 2 && string[0] == '0') {
|
||||
@@ -205,7 +220,7 @@ gb_global char const global_num_to_char_table[] =
|
||||
"abcdefghijklmnopqrstuvwxyz"
|
||||
"@$";
|
||||
|
||||
String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
|
||||
gb_internal String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
|
||||
char buf[32] = {0};
|
||||
isize i = gb_size_of(buf);
|
||||
|
||||
@@ -220,7 +235,7 @@ String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
|
||||
gb_memmove(out_buf, &buf[i], len);
|
||||
return make_string(cast(u8 *)out_buf, len);
|
||||
}
|
||||
String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
|
||||
gb_internal String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
|
||||
char buf[32] = {0};
|
||||
isize i = gb_size_of(buf);
|
||||
bool negative = false;
|
||||
@@ -282,17 +297,17 @@ gb_global u64 const unsigned_integer_maxs[] = {
|
||||
};
|
||||
|
||||
|
||||
bool add_overflow_u64(u64 x, u64 y, u64 *result) {
|
||||
gb_internal bool add_overflow_u64(u64 x, u64 y, u64 *result) {
|
||||
*result = x + y;
|
||||
return *result < x || *result < y;
|
||||
}
|
||||
|
||||
bool sub_overflow_u64(u64 x, u64 y, u64 *result) {
|
||||
gb_internal bool sub_overflow_u64(u64 x, u64 y, u64 *result) {
|
||||
*result = x - y;
|
||||
return *result > x;
|
||||
}
|
||||
|
||||
void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
|
||||
gb_internal void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
|
||||
#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT)
|
||||
*lo = _umul128(x, y, hi);
|
||||
#else
|
||||
@@ -342,7 +357,7 @@ struct StringIntern {
|
||||
PtrMap<uintptr, StringIntern *> string_intern_map = {}; // Key: u64
|
||||
gb_global Arena string_intern_arena = {};
|
||||
|
||||
char const *string_intern(char const *text, isize len) {
|
||||
gb_internal char const *string_intern(char const *text, isize len) {
|
||||
u64 hash = gb_fnv64a(text, len);
|
||||
uintptr key = cast(uintptr)(hash ? hash : 1);
|
||||
StringIntern **found = map_get(&string_intern_map, key);
|
||||
@@ -363,18 +378,18 @@ char const *string_intern(char const *text, isize len) {
|
||||
return new_intern->str;
|
||||
}
|
||||
|
||||
char const *string_intern(String const &string) {
|
||||
gb_internal char const *string_intern(String const &string) {
|
||||
return string_intern(cast(char const *)string.text, string.len);
|
||||
}
|
||||
|
||||
void init_string_interner(void) {
|
||||
map_init(&string_intern_map, heap_allocator());
|
||||
gb_internal void init_string_interner(void) {
|
||||
map_init(&string_intern_map);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
i32 next_pow2(i32 n) {
|
||||
gb_internal i32 next_pow2(i32 n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -387,7 +402,7 @@ i32 next_pow2(i32 n) {
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
i64 next_pow2(i64 n) {
|
||||
gb_internal i64 next_pow2(i64 n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -401,7 +416,7 @@ i64 next_pow2(i64 n) {
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
isize next_pow2_isize(isize n) {
|
||||
gb_internal isize next_pow2_isize(isize n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -417,7 +432,7 @@ isize next_pow2_isize(isize n) {
|
||||
n++;
|
||||
return n;
|
||||
}
|
||||
u32 next_pow2_u32(u32 n) {
|
||||
gb_internal u32 next_pow2_u32(u32 n) {
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -432,7 +447,7 @@ u32 next_pow2_u32(u32 n) {
|
||||
}
|
||||
|
||||
|
||||
i32 bit_set_count(u32 x) {
|
||||
gb_internal i32 bit_set_count(u32 x) {
|
||||
x -= ((x >> 1) & 0x55555555);
|
||||
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
|
||||
x = (((x >> 4) + x) & 0x0f0f0f0f);
|
||||
@@ -442,13 +457,13 @@ i32 bit_set_count(u32 x) {
|
||||
return cast(i32)(x & 0x0000003f);
|
||||
}
|
||||
|
||||
i64 bit_set_count(u64 x) {
|
||||
gb_internal i64 bit_set_count(u64 x) {
|
||||
u32 a = *(cast(u32 *)&x);
|
||||
u32 b = *(cast(u32 *)&x + 1);
|
||||
return bit_set_count(a) + bit_set_count(b);
|
||||
}
|
||||
|
||||
u32 floor_log2(u32 x) {
|
||||
gb_internal u32 floor_log2(u32 x) {
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
@@ -457,7 +472,7 @@ u32 floor_log2(u32 x) {
|
||||
return cast(u32)(bit_set_count(x) - 1);
|
||||
}
|
||||
|
||||
u64 floor_log2(u64 x) {
|
||||
gb_internal u64 floor_log2(u64 x) {
|
||||
x |= x >> 1;
|
||||
x |= x >> 2;
|
||||
x |= x >> 4;
|
||||
@@ -468,7 +483,7 @@ u64 floor_log2(u64 x) {
|
||||
}
|
||||
|
||||
|
||||
u32 ceil_log2(u32 x) {
|
||||
gb_internal u32 ceil_log2(u32 x) {
|
||||
i32 y = cast(i32)(x & (x-1));
|
||||
y |= -y;
|
||||
y >>= 32-1;
|
||||
@@ -480,7 +495,7 @@ u32 ceil_log2(u32 x) {
|
||||
return cast(u32)(bit_set_count(x) - 1 - y);
|
||||
}
|
||||
|
||||
u64 ceil_log2(u64 x) {
|
||||
gb_internal u64 ceil_log2(u64 x) {
|
||||
i64 y = cast(i64)(x & (x-1));
|
||||
y |= -y;
|
||||
y >>= 64-1;
|
||||
@@ -493,7 +508,7 @@ u64 ceil_log2(u64 x) {
|
||||
return cast(u64)(bit_set_count(x) - 1 - y);
|
||||
}
|
||||
|
||||
u32 prev_pow2(u32 n) {
|
||||
gb_internal u32 prev_pow2(u32 n) {
|
||||
if (n == 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -504,7 +519,7 @@ u32 prev_pow2(u32 n) {
|
||||
n |= n >> 16;
|
||||
return n - (n >> 1);
|
||||
}
|
||||
i32 prev_pow2(i32 n) {
|
||||
gb_internal i32 prev_pow2(i32 n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -515,7 +530,7 @@ i32 prev_pow2(i32 n) {
|
||||
n |= n >> 16;
|
||||
return n - (n >> 1);
|
||||
}
|
||||
i64 prev_pow2(i64 n) {
|
||||
gb_internal i64 prev_pow2(i64 n) {
|
||||
if (n <= 0) {
|
||||
return 0;
|
||||
}
|
||||
@@ -528,7 +543,7 @@ i64 prev_pow2(i64 n) {
|
||||
return n - (n >> 1);
|
||||
}
|
||||
|
||||
u16 f32_to_f16(f32 value) {
|
||||
gb_internal u16 f32_to_f16(f32 value) {
|
||||
union { u32 i; f32 f; } v;
|
||||
i32 i, s, e, m;
|
||||
|
||||
@@ -579,7 +594,7 @@ u16 f32_to_f16(f32 value) {
|
||||
}
|
||||
}
|
||||
|
||||
f32 f16_to_f32(u16 value) {
|
||||
gb_internal f32 f16_to_f32(u16 value) {
|
||||
typedef union { u32 u; f32 f; } fp32;
|
||||
fp32 v;
|
||||
|
||||
@@ -595,7 +610,7 @@ f32 f16_to_f32(u16 value) {
|
||||
return v.f;
|
||||
}
|
||||
|
||||
f64 gb_sqrt(f64 x) {
|
||||
gb_internal gb_inline f64 gb_sqrt(f64 x) {
|
||||
return sqrt(x);
|
||||
}
|
||||
|
||||
@@ -623,7 +638,7 @@ f64 gb_sqrt(f64 x) {
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
|
||||
wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
|
||||
u32 i, j;
|
||||
|
||||
u32 len = cast(u32)string16_len(cmd_line);
|
||||
@@ -706,11 +721,13 @@ enum LoadedFileError {
|
||||
LoadedFile_COUNT,
|
||||
};
|
||||
|
||||
LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_file, bool copy_file_contents) {
|
||||
gb_internal LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_file, bool copy_file_contents) {
|
||||
LoadedFileError err = LoadedFile_None;
|
||||
|
||||
if (!copy_file_contents) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
isize w_len = 0;
|
||||
wchar_t *w_str = gb__alloc_utf8_to_ucs2(temporary_allocator(), fullpath, &w_len);
|
||||
if (w_str == nullptr) {
|
||||
@@ -811,7 +828,9 @@ LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_fil
|
||||
|
||||
#define USE_DAMERAU_LEVENSHTEIN 1
|
||||
|
||||
isize levenstein_distance_case_insensitive(String const &a, String const &b) {
|
||||
gb_internal isize levenstein_distance_case_insensitive(String const &a, String const &b) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
isize w = b.len+1;
|
||||
isize h = a.len+1;
|
||||
isize *matrix = gb_alloc_array(temporary_allocator(), isize, w*h);
|
||||
@@ -870,16 +889,16 @@ struct DidYouMeanAnswers {
|
||||
|
||||
enum {MAX_SMALLEST_DID_YOU_MEAN_DISTANCE = 3-USE_DAMERAU_LEVENSHTEIN};
|
||||
|
||||
DidYouMeanAnswers did_you_mean_make(gbAllocator allocator, isize cap, String const &key) {
|
||||
gb_internal DidYouMeanAnswers did_you_mean_make(gbAllocator allocator, isize cap, String const &key) {
|
||||
DidYouMeanAnswers d = {};
|
||||
array_init(&d.distances, allocator, 0, cap);
|
||||
d.key = key;
|
||||
return d;
|
||||
}
|
||||
void did_you_mean_destroy(DidYouMeanAnswers *d) {
|
||||
gb_internal void did_you_mean_destroy(DidYouMeanAnswers *d) {
|
||||
array_free(&d->distances);
|
||||
}
|
||||
void did_you_mean_append(DidYouMeanAnswers *d, String const &target) {
|
||||
gb_internal void did_you_mean_append(DidYouMeanAnswers *d, String const &target) {
|
||||
if (target.len == 0 || target == "_") {
|
||||
return;
|
||||
}
|
||||
@@ -888,7 +907,7 @@ void did_you_mean_append(DidYouMeanAnswers *d, String const &target) {
|
||||
dat.distance = levenstein_distance_case_insensitive(d->key, target);
|
||||
array_add(&d->distances, dat);
|
||||
}
|
||||
Slice<DistanceAndTarget> did_you_mean_results(DidYouMeanAnswers *d) {
|
||||
gb_internal Slice<DistanceAndTarget> did_you_mean_results(DidYouMeanAnswers *d) {
|
||||
gb_sort_array(d->distances.data, d->distances.count, gb_isize_cmp(gb_offset_of(DistanceAndTarget, distance)));
|
||||
isize count = 0;
|
||||
for (isize i = 0; i < d->distances.count; i++) {
|
||||
@@ -900,3 +919,8 @@ Slice<DistanceAndTarget> did_you_mean_results(DidYouMeanAnswers *d) {
|
||||
}
|
||||
return slice_array(d->distances, 0, count);
|
||||
}
|
||||
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
|
||||
+149
-76
@@ -1,5 +1,5 @@
|
||||
|
||||
gb_inline void zero_size(void *ptr, isize len) {
|
||||
gb_internal gb_inline void zero_size(void *ptr, isize len) {
|
||||
memset(ptr, 0, len);
|
||||
}
|
||||
|
||||
@@ -7,43 +7,31 @@ gb_inline void zero_size(void *ptr, isize len) {
|
||||
|
||||
|
||||
template <typename U, typename V>
|
||||
gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
|
||||
gb_internal gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
|
||||
|
||||
template <typename U, typename V>
|
||||
gb_inline U const &bit_cast(V const &v) { return reinterpret_cast<U const &>(v); }
|
||||
gb_internal gb_inline U const &bit_cast(V const &v) { return reinterpret_cast<U const &>(v); }
|
||||
|
||||
|
||||
gb_inline i64 align_formula(i64 size, i64 align) {
|
||||
if (align > 0) {
|
||||
i64 result = size + align-1;
|
||||
return result - result%align;
|
||||
}
|
||||
return size;
|
||||
gb_internal gb_inline i64 align_formula(i64 size, i64 align) {
|
||||
i64 result = size + align-1;
|
||||
return result - (i64)((u64)result%(u64)align);
|
||||
}
|
||||
gb_inline isize align_formula_isize(isize size, isize align) {
|
||||
if (align > 0) {
|
||||
isize result = size + align-1;
|
||||
return result - result%align;
|
||||
}
|
||||
return size;
|
||||
gb_internal gb_inline isize align_formula_isize(isize size, isize align) {
|
||||
isize result = size + align-1;
|
||||
return result - (isize)((usize)result%(usize)align);
|
||||
}
|
||||
gb_inline void *align_formula_ptr(void *ptr, isize align) {
|
||||
if (align > 0) {
|
||||
uintptr result = (cast(uintptr)ptr) + align-1;
|
||||
return (void *)(result - result%align);
|
||||
}
|
||||
return ptr;
|
||||
gb_internal gb_inline void *align_formula_ptr(void *ptr, isize align) {
|
||||
uintptr result = (cast(uintptr)ptr) + align-1;
|
||||
return (void *)(result - result%align);
|
||||
}
|
||||
|
||||
|
||||
gb_global BlockingMutex global_memory_block_mutex;
|
||||
gb_global BlockingMutex global_memory_allocator_mutex;
|
||||
|
||||
void platform_virtual_memory_init(void);
|
||||
gb_internal void platform_virtual_memory_init(void);
|
||||
|
||||
void virtual_memory_init(void) {
|
||||
mutex_init(&global_memory_block_mutex);
|
||||
mutex_init(&global_memory_allocator_mutex);
|
||||
gb_internal void virtual_memory_init(void) {
|
||||
platform_virtual_memory_init();
|
||||
}
|
||||
|
||||
@@ -57,22 +45,23 @@ struct MemoryBlock {
|
||||
};
|
||||
|
||||
struct Arena {
|
||||
MemoryBlock *curr_block;
|
||||
isize minimum_block_size;
|
||||
bool ignore_mutex;
|
||||
MemoryBlock * curr_block;
|
||||
isize minimum_block_size;
|
||||
BlockingMutex mutex;
|
||||
isize temp_count;
|
||||
};
|
||||
|
||||
enum { DEFAULT_MINIMUM_BLOCK_SIZE = 8ll*1024ll*1024ll };
|
||||
|
||||
gb_global isize DEFAULT_PAGE_SIZE = 4096;
|
||||
|
||||
MemoryBlock *virtual_memory_alloc(isize size);
|
||||
void virtual_memory_dealloc(MemoryBlock *block);
|
||||
void *arena_alloc(Arena *arena, isize min_size, isize alignment);
|
||||
void arena_free_all(Arena *arena);
|
||||
gb_internal MemoryBlock *virtual_memory_alloc(isize size);
|
||||
gb_internal void virtual_memory_dealloc(MemoryBlock *block);
|
||||
gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment);
|
||||
gb_internal void arena_free_all(Arena *arena);
|
||||
|
||||
|
||||
isize arena_align_forward_offset(Arena *arena, isize alignment) {
|
||||
gb_internal isize arena_align_forward_offset(Arena *arena, isize alignment) {
|
||||
isize alignment_offset = 0;
|
||||
isize ptr = cast(isize)(arena->curr_block->base + arena->curr_block->used);
|
||||
isize mask = alignment-1;
|
||||
@@ -82,13 +71,10 @@ isize arena_align_forward_offset(Arena *arena, isize alignment) {
|
||||
return alignment_offset;
|
||||
}
|
||||
|
||||
void *arena_alloc(Arena *arena, isize min_size, isize alignment) {
|
||||
gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) {
|
||||
GB_ASSERT(gb_is_power_of_two(alignment));
|
||||
|
||||
BlockingMutex *mutex = &global_memory_allocator_mutex;
|
||||
if (!arena->ignore_mutex) {
|
||||
mutex_lock(mutex);
|
||||
}
|
||||
mutex_lock(&arena->mutex);
|
||||
|
||||
isize size = 0;
|
||||
if (arena->curr_block != nullptr) {
|
||||
@@ -115,15 +101,13 @@ void *arena_alloc(Arena *arena, isize min_size, isize alignment) {
|
||||
curr_block->used += size;
|
||||
GB_ASSERT(curr_block->used <= curr_block->size);
|
||||
|
||||
if (!arena->ignore_mutex) {
|
||||
mutex_unlock(mutex);
|
||||
}
|
||||
mutex_unlock(&arena->mutex);
|
||||
|
||||
// NOTE(bill): memory will be zeroed by default due to virtual memory
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void arena_free_all(Arena *arena) {
|
||||
gb_internal void arena_free_all(Arena *arena) {
|
||||
while (arena->curr_block != nullptr) {
|
||||
MemoryBlock *free_block = arena->curr_block;
|
||||
arena->curr_block = free_block->prev;
|
||||
@@ -142,12 +126,12 @@ struct PlatformMemoryBlock {
|
||||
gb_global std::atomic<isize> global_platform_memory_total_usage;
|
||||
gb_global PlatformMemoryBlock global_platform_memory_block_sentinel;
|
||||
|
||||
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size);
|
||||
void platform_virtual_memory_free(PlatformMemoryBlock *block);
|
||||
void platform_virtual_memory_protect(void *memory, isize size);
|
||||
gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size);
|
||||
gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block);
|
||||
gb_internal void platform_virtual_memory_protect(void *memory, isize size);
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
void platform_virtual_memory_init(void) {
|
||||
gb_internal void platform_virtual_memory_init(void) {
|
||||
global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel;
|
||||
global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel;
|
||||
|
||||
@@ -157,7 +141,7 @@ void platform_virtual_memory_protect(void *memory, isize size);
|
||||
GB_ASSERT(gb_is_power_of_two(DEFAULT_PAGE_SIZE));
|
||||
}
|
||||
|
||||
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
|
||||
gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
|
||||
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)VirtualAlloc(0, total_size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||
if (pmblock == nullptr) {
|
||||
gb_printf_err("Out of Virtual memory, oh no...\n");
|
||||
@@ -165,20 +149,20 @@ void platform_virtual_memory_protect(void *memory, isize size);
|
||||
gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage);
|
||||
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
|
||||
}
|
||||
global_platform_memory_total_usage += total_size;
|
||||
global_platform_memory_total_usage.fetch_add(total_size);
|
||||
return pmblock;
|
||||
}
|
||||
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
||||
global_platform_memory_total_usage -= block->total_size;
|
||||
gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
||||
global_platform_memory_total_usage.fetch_sub(block->total_size);
|
||||
GB_ASSERT(VirtualFree(block, 0, MEM_RELEASE));
|
||||
}
|
||||
void platform_virtual_memory_protect(void *memory, isize size) {
|
||||
gb_internal void platform_virtual_memory_protect(void *memory, isize size) {
|
||||
DWORD old_protect = 0;
|
||||
BOOL is_protected = VirtualProtect(memory, size, PAGE_NOACCESS, &old_protect);
|
||||
GB_ASSERT(is_protected);
|
||||
}
|
||||
#else
|
||||
void platform_virtual_memory_init(void) {
|
||||
gb_internal void platform_virtual_memory_init(void) {
|
||||
global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel;
|
||||
global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel;
|
||||
|
||||
@@ -186,7 +170,7 @@ void platform_virtual_memory_protect(void *memory, isize size);
|
||||
GB_ASSERT(gb_is_power_of_two(DEFAULT_PAGE_SIZE));
|
||||
}
|
||||
|
||||
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
|
||||
gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
|
||||
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)mmap(nullptr, total_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||
if (pmblock == nullptr) {
|
||||
gb_printf_err("Out of Virtual memory, oh no...\n");
|
||||
@@ -197,18 +181,18 @@ void platform_virtual_memory_protect(void *memory, isize size);
|
||||
global_platform_memory_total_usage += total_size;
|
||||
return pmblock;
|
||||
}
|
||||
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
||||
gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
||||
isize size = block->total_size;
|
||||
global_platform_memory_total_usage -= size;
|
||||
munmap(block, size);
|
||||
}
|
||||
void platform_virtual_memory_protect(void *memory, isize size) {
|
||||
gb_internal void platform_virtual_memory_protect(void *memory, isize size) {
|
||||
int err = mprotect(memory, size, PROT_NONE);
|
||||
GB_ASSERT(err == 0);
|
||||
}
|
||||
#endif
|
||||
|
||||
MemoryBlock *virtual_memory_alloc(isize size) {
|
||||
gb_internal MemoryBlock *virtual_memory_alloc(isize size) {
|
||||
isize const page_size = DEFAULT_PAGE_SIZE;
|
||||
|
||||
isize total_size = size + gb_size_of(PlatformMemoryBlock);
|
||||
@@ -250,7 +234,7 @@ MemoryBlock *virtual_memory_alloc(isize size) {
|
||||
return &pmblock->block;
|
||||
}
|
||||
|
||||
void virtual_memory_dealloc(MemoryBlock *block_to_free) {
|
||||
gb_internal void virtual_memory_dealloc(MemoryBlock *block_to_free) {
|
||||
PlatformMemoryBlock *block = cast(PlatformMemoryBlock *)block_to_free;
|
||||
if (block != nullptr) {
|
||||
mutex_lock(&global_memory_block_mutex);
|
||||
@@ -262,12 +246,87 @@ void virtual_memory_dealloc(MemoryBlock *block_to_free) {
|
||||
}
|
||||
}
|
||||
|
||||
struct ArenaTemp {
|
||||
Arena * arena;
|
||||
MemoryBlock *block;
|
||||
isize used;
|
||||
};
|
||||
|
||||
ArenaTemp arena_temp_begin(Arena *arena) {
|
||||
GB_ASSERT(arena);
|
||||
MUTEX_GUARD(&arena->mutex);
|
||||
|
||||
ArenaTemp temp = {};
|
||||
temp.arena = arena;
|
||||
temp.block = arena->curr_block;
|
||||
if (arena->curr_block != nullptr) {
|
||||
temp.used = arena->curr_block->used;
|
||||
}
|
||||
arena->temp_count += 1;
|
||||
return temp;
|
||||
}
|
||||
|
||||
void arena_temp_end(ArenaTemp const &temp) {
|
||||
GB_ASSERT(temp.arena);
|
||||
Arena *arena = temp.arena;
|
||||
MUTEX_GUARD(&arena->mutex);
|
||||
|
||||
if (temp.block) {
|
||||
bool memory_block_found = false;
|
||||
for (MemoryBlock *block = arena->curr_block; block != nullptr; block = block->prev) {
|
||||
if (block == temp.block) {
|
||||
memory_block_found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
GB_ASSERT_MSG(memory_block_found, "memory block stored within ArenaTemp not owned by Arena");
|
||||
|
||||
while (arena->curr_block != temp.block) {
|
||||
MemoryBlock *free_block = arena->curr_block;
|
||||
if (free_block != nullptr) {
|
||||
arena->curr_block = free_block->prev;
|
||||
virtual_memory_dealloc(free_block);
|
||||
}
|
||||
}
|
||||
|
||||
MemoryBlock *block = arena->curr_block;
|
||||
if (block) {
|
||||
GB_ASSERT_MSG(block->used >= temp.used, "out of order use of arena_temp_end");
|
||||
isize amount_to_zero = gb_min(block->used - temp.used, block->size - block->used);
|
||||
gb_zero_size(block->base + temp.used, amount_to_zero);
|
||||
block->used = temp.used;
|
||||
}
|
||||
}
|
||||
|
||||
GB_ASSERT_MSG(arena->temp_count > 0, "double-use of arena_temp_end");
|
||||
arena->temp_count -= 1;
|
||||
}
|
||||
|
||||
void arena_temp_ignore(ArenaTemp const &temp) {
|
||||
GB_ASSERT(temp.arena);
|
||||
Arena *arena = temp.arena;
|
||||
MUTEX_GUARD(&arena->mutex);
|
||||
|
||||
GB_ASSERT_MSG(arena->temp_count > 0, "double-use of arena_temp_end");
|
||||
arena->temp_count -= 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
GB_ALLOCATOR_PROC(arena_allocator_proc);
|
||||
struct ArenaTempGuard {
|
||||
ArenaTempGuard(Arena *arena) {
|
||||
this->temp = arena_temp_begin(arena);
|
||||
}
|
||||
~ArenaTempGuard() {
|
||||
arena_temp_end(this->temp);
|
||||
}
|
||||
ArenaTemp temp;
|
||||
};
|
||||
|
||||
gbAllocator arena_allocator(Arena *arena) {
|
||||
|
||||
gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc);
|
||||
|
||||
gb_internal gbAllocator arena_allocator(Arena *arena) {
|
||||
gbAllocator a;
|
||||
a.proc = arena_allocator_proc;
|
||||
a.data = arena;
|
||||
@@ -275,7 +334,7 @@ gbAllocator arena_allocator(Arena *arena) {
|
||||
}
|
||||
|
||||
|
||||
GB_ALLOCATOR_PROC(arena_allocator_proc) {
|
||||
gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc) {
|
||||
void *ptr = nullptr;
|
||||
Arena *arena = cast(Arena *)allocator_data;
|
||||
GB_ASSERT_NOT_NULL(arena);
|
||||
@@ -306,31 +365,44 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) {
|
||||
}
|
||||
|
||||
|
||||
gb_global gb_thread_local Arena permanent_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE, true};
|
||||
gbAllocator permanent_allocator() {
|
||||
gb_global gb_thread_local Arena permanent_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE};
|
||||
gb_internal gbAllocator permanent_allocator() {
|
||||
return arena_allocator(&permanent_arena);
|
||||
}
|
||||
|
||||
gbAllocator temporary_allocator() {
|
||||
return permanent_allocator();
|
||||
gb_global gb_thread_local Arena temporary_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE};
|
||||
gb_internal gbAllocator temporary_allocator() {
|
||||
return arena_allocator(&temporary_arena);
|
||||
}
|
||||
|
||||
|
||||
#define TEMP_ARENA_GUARD(arena) ArenaTempGuard GB_DEFER_3(_arena_guard_){arena}
|
||||
|
||||
|
||||
// #define TEMPORARY_ALLOCATOR_GUARD()
|
||||
#define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(&temporary_arena)
|
||||
#define PERMANENT_ALLOCATOR_GUARD()
|
||||
|
||||
|
||||
|
||||
gb_internal bool IS_ODIN_DEBUG(void);
|
||||
|
||||
GB_ALLOCATOR_PROC(heap_allocator_proc);
|
||||
gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc);
|
||||
|
||||
gbAllocator heap_allocator(void) {
|
||||
gbAllocator a;
|
||||
a.proc = heap_allocator_proc;
|
||||
a.data = nullptr;
|
||||
return a;
|
||||
|
||||
gb_global gb_thread_local Arena heap_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE};
|
||||
gb_internal gbAllocator heap_allocator(void) {
|
||||
if (IS_ODIN_DEBUG()) {
|
||||
gbAllocator a;
|
||||
a.proc = heap_allocator_proc;
|
||||
a.data = nullptr;
|
||||
return a;
|
||||
}
|
||||
return arena_allocator(&heap_arena);
|
||||
}
|
||||
|
||||
|
||||
GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||
gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||
void *ptr = nullptr;
|
||||
gb_unused(allocator_data);
|
||||
gb_unused(old_size);
|
||||
@@ -460,21 +532,22 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void resize_array_raw(T **array, gbAllocator const &a, isize old_count, isize new_count) {
|
||||
gb_internal isize resize_array_raw(T **array, gbAllocator const &a, isize old_count, isize new_count, isize custom_alignment=1) {
|
||||
GB_ASSERT(new_count >= 0);
|
||||
if (new_count == 0) {
|
||||
gb_free(a, *array);
|
||||
*array = nullptr;
|
||||
return;
|
||||
return 0;
|
||||
}
|
||||
if (new_count < old_count) {
|
||||
return;
|
||||
return old_count;
|
||||
}
|
||||
isize old_size = old_count * gb_size_of(T);
|
||||
isize new_size = new_count * gb_size_of(T);
|
||||
isize alignment = gb_align_of(T);
|
||||
isize alignment = gb_max(gb_align_of(T), custom_alignment);
|
||||
auto new_data = cast(T *)gb_resize_align(a, *array, old_size, new_size, alignment);
|
||||
GB_ASSERT(new_data != nullptr);
|
||||
*array = new_data;
|
||||
return new_count;
|
||||
}
|
||||
|
||||
|
||||
+25
-39
@@ -28,7 +28,7 @@ gb_global char const *print_entity_names[Entity_Count] = {
|
||||
};
|
||||
|
||||
|
||||
GB_COMPARE_PROC(cmp_entities_for_printing) {
|
||||
gb_internal GB_COMPARE_PROC(cmp_entities_for_printing) {
|
||||
GB_ASSERT(a != nullptr);
|
||||
GB_ASSERT(b != nullptr);
|
||||
Entity *x = *cast(Entity **)a;
|
||||
@@ -49,14 +49,13 @@ GB_COMPARE_PROC(cmp_entities_for_printing) {
|
||||
int ox = print_entity_kind_ordering[x->kind];
|
||||
int oy = print_entity_kind_ordering[y->kind];
|
||||
res = ox - oy;
|
||||
if (res != 0) {
|
||||
return res;
|
||||
if (res == 0) {
|
||||
res = string_compare(x->token.string, y->token.string);
|
||||
}
|
||||
res = string_compare(x->token.string, y->token.string);
|
||||
return res;
|
||||
}
|
||||
|
||||
GB_COMPARE_PROC(cmp_ast_package_by_name) {
|
||||
gb_internal GB_COMPARE_PROC(cmp_ast_package_by_name) {
|
||||
GB_ASSERT(a != nullptr);
|
||||
GB_ASSERT(b != nullptr);
|
||||
AstPackage *x = *cast(AstPackage **)a;
|
||||
@@ -67,7 +66,7 @@ GB_COMPARE_PROC(cmp_ast_package_by_name) {
|
||||
#include "docs_format.cpp"
|
||||
#include "docs_writer.cpp"
|
||||
|
||||
void print_doc_line(i32 indent, String const &data) {
|
||||
gb_internal void print_doc_line(i32 indent, String const &data) {
|
||||
while (indent --> 0) {
|
||||
gb_printf("\t");
|
||||
}
|
||||
@@ -75,7 +74,7 @@ void print_doc_line(i32 indent, String const &data) {
|
||||
gb_printf("\n");
|
||||
}
|
||||
|
||||
void print_doc_line(i32 indent, char const *fmt, ...) {
|
||||
gb_internal void print_doc_line(i32 indent, char const *fmt, ...) {
|
||||
while (indent --> 0) {
|
||||
gb_printf("\t");
|
||||
}
|
||||
@@ -85,16 +84,7 @@ void print_doc_line(i32 indent, char const *fmt, ...) {
|
||||
va_end(va);
|
||||
gb_printf("\n");
|
||||
}
|
||||
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
|
||||
while (indent --> 0) {
|
||||
gb_printf("\t");
|
||||
}
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
gb_printf_va(fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
void print_doc_line_no_newline(i32 indent, String const &data) {
|
||||
gb_internal void print_doc_line_no_newline(i32 indent, String const &data) {
|
||||
while (indent --> 0) {
|
||||
gb_printf("\t");
|
||||
}
|
||||
@@ -102,7 +92,7 @@ void print_doc_line_no_newline(i32 indent, String const &data) {
|
||||
}
|
||||
|
||||
|
||||
bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
|
||||
gb_internal bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
|
||||
if (g == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -191,7 +181,7 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
|
||||
|
||||
|
||||
|
||||
void print_doc_expr(Ast *expr) {
|
||||
gb_internal void print_doc_expr(Ast *expr) {
|
||||
gbString s = nullptr;
|
||||
if (build_context.cmd_doc_flags & CmdDocFlag_Short) {
|
||||
s = expr_to_string_shorthand(expr);
|
||||
@@ -202,8 +192,7 @@ void print_doc_expr(Ast *expr) {
|
||||
gb_string_free(s);
|
||||
}
|
||||
|
||||
|
||||
void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||
gb_internal void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||
if (pkg == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -220,10 +209,10 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||
}
|
||||
|
||||
if (pkg->scope != nullptr) {
|
||||
auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
|
||||
auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.count);
|
||||
defer (array_free(&entities));
|
||||
for_array(i, pkg->scope->elements.entries) {
|
||||
Entity *e = pkg->scope->elements.entries[i].value;
|
||||
for (auto const &entry : pkg->scope->elements) {
|
||||
Entity *e = entry.value;
|
||||
switch (e->kind) {
|
||||
case Entity_Invalid:
|
||||
case Entity_Builtin:
|
||||
@@ -240,6 +229,12 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||
// Fine
|
||||
break;
|
||||
}
|
||||
if (e->pkg != pkg) {
|
||||
continue;
|
||||
}
|
||||
if (!is_entity_exported(e)) {
|
||||
continue;
|
||||
}
|
||||
array_add(&entities, e);
|
||||
}
|
||||
gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);
|
||||
@@ -247,16 +242,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||
bool show_docs = (build_context.cmd_doc_flags & CmdDocFlag_Short) == 0;
|
||||
|
||||
EntityKind curr_entity_kind = Entity_Invalid;
|
||||
for_array(i, entities) {
|
||||
Entity *e = entities[i];
|
||||
if (e->pkg != pkg) {
|
||||
continue;
|
||||
}
|
||||
if (!is_entity_exported(e)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
for (Entity *e : entities) {
|
||||
if (curr_entity_kind != e->kind) {
|
||||
if (curr_entity_kind != Entity_Invalid) {
|
||||
print_doc_line(0, "");
|
||||
@@ -297,7 +283,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||
print_doc_expr(init_expr);
|
||||
}
|
||||
|
||||
gb_printf(";\n");
|
||||
gb_printf("\n");
|
||||
|
||||
if (show_docs) {
|
||||
print_doc_comment_group_string(3, docs);
|
||||
@@ -320,7 +306,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||
|
||||
}
|
||||
|
||||
void generate_documentation(Checker *c) {
|
||||
gb_internal void generate_documentation(Checker *c) {
|
||||
CheckerInfo *info = &c->info;
|
||||
|
||||
if (build_context.cmd_doc_flags & CmdDocFlag_DocFormat) {
|
||||
@@ -358,9 +344,9 @@ void generate_documentation(Checker *c) {
|
||||
|
||||
odin_doc_write(info, output_file_path);
|
||||
} else {
|
||||
auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
|
||||
for_array(i, info->packages.entries) {
|
||||
AstPackage *pkg = info->packages.entries[i].value;
|
||||
auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.count);
|
||||
for (auto const &entry : info->packages) {
|
||||
AstPackage *pkg = entry.value;
|
||||
if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
|
||||
array_add(&pkgs, pkg);
|
||||
} else {
|
||||
|
||||
+2
-2
@@ -27,14 +27,14 @@ struct OdinDocHeaderBase {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
Slice<T> from_array(OdinDocHeaderBase *base, OdinDocArray<T> const &a) {
|
||||
gb_internal Slice<T> from_array(OdinDocHeaderBase *base, OdinDocArray<T> const &a) {
|
||||
Slice<T> s = {};
|
||||
s.data = cast(T *)(cast(uintptr)base + cast(uintptr)a.offset);
|
||||
s.count = cast(isize)a.length;
|
||||
return s;
|
||||
}
|
||||
|
||||
String from_string(OdinDocHeaderBase *base, OdinDocString const &s) {
|
||||
gb_internal String from_string(OdinDocHeaderBase *base, OdinDocString const &s) {
|
||||
String str = {};
|
||||
str.text = cast(u8 *)(cast(uintptr)base + cast(uintptr)s.offset);
|
||||
str.len = cast(isize)s.length;
|
||||
|
||||
+58
-62
@@ -11,7 +11,7 @@ enum OdinDocWriterState {
|
||||
OdinDocWriterState_Writing,
|
||||
};
|
||||
|
||||
char const* OdinDocWriterState_strings[] {
|
||||
gb_global char const* OdinDocWriterState_strings[] {
|
||||
"preparing",
|
||||
"writing ",
|
||||
};
|
||||
@@ -40,26 +40,25 @@ struct OdinDocWriter {
|
||||
OdinDocWriterItemTracker<u8> blob;
|
||||
};
|
||||
|
||||
OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e);
|
||||
OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type);
|
||||
gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e);
|
||||
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type);
|
||||
|
||||
template <typename T>
|
||||
void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker<T> *t, isize size) {
|
||||
gb_internal void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker<T> *t, isize size) {
|
||||
t->len = size;
|
||||
t->cap = size;
|
||||
}
|
||||
|
||||
|
||||
void odin_doc_writer_prepare(OdinDocWriter *w) {
|
||||
gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
|
||||
w->state = OdinDocWriterState_Preparing;
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
string_map_init(&w->string_cache, a);
|
||||
string_map_init(&w->string_cache);
|
||||
|
||||
map_init(&w->file_cache, a);
|
||||
map_init(&w->pkg_cache, a);
|
||||
map_init(&w->entity_cache, a);
|
||||
map_init(&w->type_cache, a);
|
||||
map_init(&w->file_cache);
|
||||
map_init(&w->pkg_cache);
|
||||
map_init(&w->entity_cache);
|
||||
map_init(&w->type_cache);
|
||||
|
||||
odin_doc_writer_item_tracker_init(&w->files, 1);
|
||||
odin_doc_writer_item_tracker_init(&w->pkgs, 1);
|
||||
@@ -70,7 +69,7 @@ void odin_doc_writer_prepare(OdinDocWriter *w) {
|
||||
}
|
||||
|
||||
|
||||
void odin_doc_writer_destroy(OdinDocWriter *w) {
|
||||
gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
|
||||
gb_free(heap_allocator(), w->data);
|
||||
|
||||
string_map_destroy(&w->string_cache);
|
||||
@@ -83,7 +82,7 @@ void odin_doc_writer_destroy(OdinDocWriter *w) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void odin_doc_writer_tracker_size(isize *offset, OdinDocWriterItemTracker<T> *t, isize alignment=1) {
|
||||
gb_internal void odin_doc_writer_tracker_size(isize *offset, OdinDocWriterItemTracker<T> *t, isize alignment=1) {
|
||||
isize size = t->cap*gb_size_of(T);
|
||||
isize align = gb_max(gb_align_of(T), alignment);
|
||||
*offset = align_formula_isize(*offset, align);
|
||||
@@ -91,7 +90,7 @@ void odin_doc_writer_tracker_size(isize *offset, OdinDocWriterItemTracker<T> *t,
|
||||
*offset += size;
|
||||
}
|
||||
|
||||
isize odin_doc_writer_calc_total_size(OdinDocWriter *w) {
|
||||
gb_internal isize odin_doc_writer_calc_total_size(OdinDocWriter *w) {
|
||||
isize total_size = gb_size_of(OdinDocHeader);
|
||||
odin_doc_writer_tracker_size(&total_size, &w->files);
|
||||
odin_doc_writer_tracker_size(&total_size, &w->pkgs);
|
||||
@@ -102,7 +101,7 @@ isize odin_doc_writer_calc_total_size(OdinDocWriter *w) {
|
||||
return total_size;
|
||||
}
|
||||
|
||||
void odin_doc_writer_start_writing(OdinDocWriter *w) {
|
||||
gb_internal void odin_doc_writer_start_writing(OdinDocWriter *w) {
|
||||
w->state = OdinDocWriterState_Writing;
|
||||
|
||||
string_map_clear(&w->string_cache);
|
||||
@@ -118,7 +117,7 @@ void odin_doc_writer_start_writing(OdinDocWriter *w) {
|
||||
w->header = cast(OdinDocHeader *)w->data;
|
||||
}
|
||||
|
||||
u32 hash_data_after_header(OdinDocHeaderBase *base, void *data, isize data_len) {
|
||||
gb_internal u32 hash_data_after_header(OdinDocHeaderBase *base, void *data, isize data_len) {
|
||||
u8 *start = cast(u8 *)data;
|
||||
u8 *end = start + base->total_size;
|
||||
start += base->header_size;
|
||||
@@ -132,13 +131,13 @@ u32 hash_data_after_header(OdinDocHeaderBase *base, void *data, isize data_len)
|
||||
|
||||
|
||||
template <typename T>
|
||||
void odin_doc_writer_assign_tracker(OdinDocArray<T> *array, OdinDocWriterItemTracker<T> const &t) {
|
||||
gb_internal void odin_doc_writer_assign_tracker(OdinDocArray<T> *array, OdinDocWriterItemTracker<T> const &t) {
|
||||
array->offset = cast(u32)t.offset;
|
||||
array->length = cast(u32)t.len;
|
||||
}
|
||||
|
||||
|
||||
void odin_doc_writer_end_writing(OdinDocWriter *w) {
|
||||
gb_internal void odin_doc_writer_end_writing(OdinDocWriter *w) {
|
||||
OdinDocHeader *h = w->header;
|
||||
|
||||
gb_memmove(h->base.magic, OdinDocHeader_MagicString, gb_strlen(OdinDocHeader_MagicString));
|
||||
@@ -156,7 +155,7 @@ void odin_doc_writer_end_writing(OdinDocWriter *w) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
u32 odin_doc_write_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, T const *item, T **dst=nullptr) {
|
||||
gb_internal u32 odin_doc_write_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, T const *item, T **dst=nullptr) {
|
||||
if (w->state == OdinDocWriterState_Preparing) {
|
||||
t->cap += 1;
|
||||
if (dst) *dst = nullptr;
|
||||
@@ -175,7 +174,7 @@ u32 odin_doc_write_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, T cons
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T *odin_doc_get_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, u32 index) {
|
||||
gb_internal T *odin_doc_get_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, u32 index) {
|
||||
if (w->state != OdinDocWriterState_Writing) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -184,7 +183,7 @@ T *odin_doc_get_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, u32 index
|
||||
return cast(T *)data;
|
||||
}
|
||||
|
||||
OdinDocString odin_doc_write_string_without_cache(OdinDocWriter *w, String const &str) {
|
||||
gb_internal OdinDocString odin_doc_write_string_without_cache(OdinDocWriter *w, String const &str) {
|
||||
OdinDocString res = {};
|
||||
|
||||
if (w->state == OdinDocWriterState_Preparing) {
|
||||
@@ -204,7 +203,7 @@ OdinDocString odin_doc_write_string_without_cache(OdinDocWriter *w, String const
|
||||
return res;
|
||||
}
|
||||
|
||||
OdinDocString odin_doc_write_string(OdinDocWriter *w, String const &str) {
|
||||
gb_internal OdinDocString odin_doc_write_string(OdinDocWriter *w, String const &str) {
|
||||
OdinDocString *c = string_map_get(&w->string_cache, str);
|
||||
if (c != nullptr) {
|
||||
if (w->state == OdinDocWriterState_Writing) {
|
||||
@@ -223,7 +222,7 @@ OdinDocString odin_doc_write_string(OdinDocWriter *w, String const &str) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
OdinDocArray<T> odin_write_slice(OdinDocWriter *w, T *data, isize len) {
|
||||
gb_internal OdinDocArray<T> odin_write_slice(OdinDocWriter *w, T *data, isize len) {
|
||||
GB_ASSERT(gb_align_of(T) <= 4);
|
||||
if (len <= 0) {
|
||||
return {0, 0};
|
||||
@@ -249,12 +248,12 @@ OdinDocArray<T> odin_write_slice(OdinDocWriter *w, T *data, isize len) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
OdinDocArray<T> odin_write_item_as_slice(OdinDocWriter *w, T data) {
|
||||
gb_internal OdinDocArray<T> odin_write_item_as_slice(OdinDocWriter *w, T data) {
|
||||
return odin_write_slice(w, &data, 1);
|
||||
}
|
||||
|
||||
|
||||
OdinDocPosition odin_doc_token_pos_cast(OdinDocWriter *w, TokenPos const &pos) {
|
||||
gb_internal OdinDocPosition odin_doc_token_pos_cast(OdinDocWriter *w, TokenPos const &pos) {
|
||||
OdinDocFileIndex file_index = 0;
|
||||
if (pos.file_id != 0) {
|
||||
AstFile *file = global_files[pos.file_id];
|
||||
@@ -273,7 +272,7 @@ OdinDocPosition odin_doc_token_pos_cast(OdinDocWriter *w, TokenPos const &pos) {
|
||||
return doc_pos;
|
||||
}
|
||||
|
||||
bool odin_doc_append_comment_group_string(Array<u8> *buf, CommentGroup *g) {
|
||||
gb_internal bool odin_doc_append_comment_group_string(Array<u8> *buf, CommentGroup *g) {
|
||||
if (g == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -361,7 +360,7 @@ bool odin_doc_append_comment_group_string(Array<u8> *buf, CommentGroup *g) {
|
||||
return false;
|
||||
}
|
||||
|
||||
OdinDocString odin_doc_pkg_doc_string(OdinDocWriter *w, AstPackage *pkg) {
|
||||
gb_internal OdinDocString odin_doc_pkg_doc_string(OdinDocWriter *w, AstPackage *pkg) {
|
||||
if (pkg == nullptr) {
|
||||
return {};
|
||||
}
|
||||
@@ -378,7 +377,7 @@ OdinDocString odin_doc_pkg_doc_string(OdinDocWriter *w, AstPackage *pkg) {
|
||||
return odin_doc_write_string_without_cache(w, make_string(buf.data, buf.count));
|
||||
}
|
||||
|
||||
OdinDocString odin_doc_comment_group_string(OdinDocWriter *w, CommentGroup *g) {
|
||||
gb_internal OdinDocString odin_doc_comment_group_string(OdinDocWriter *w, CommentGroup *g) {
|
||||
if (g == nullptr) {
|
||||
return {};
|
||||
}
|
||||
@@ -389,7 +388,7 @@ OdinDocString odin_doc_comment_group_string(OdinDocWriter *w, CommentGroup *g) {
|
||||
return odin_doc_write_string_without_cache(w, make_string(buf.data, buf.count));
|
||||
}
|
||||
|
||||
OdinDocString odin_doc_expr_string(OdinDocWriter *w, Ast *expr) {
|
||||
gb_internal OdinDocString odin_doc_expr_string(OdinDocWriter *w, Ast *expr) {
|
||||
if (expr == nullptr) {
|
||||
return {};
|
||||
}
|
||||
@@ -402,7 +401,7 @@ OdinDocString odin_doc_expr_string(OdinDocWriter *w, Ast *expr) {
|
||||
return odin_doc_write_string(w, make_string(cast(u8 *)s, gb_string_length(s)));
|
||||
}
|
||||
|
||||
OdinDocArray<OdinDocAttribute> odin_doc_attributes(OdinDocWriter *w, Array<Ast *> const &attributes) {
|
||||
gb_internal OdinDocArray<OdinDocAttribute> odin_doc_attributes(OdinDocWriter *w, Array<Ast *> const &attributes) {
|
||||
isize count = 0;
|
||||
for_array(i, attributes) {
|
||||
Ast *attr = attributes[i];
|
||||
@@ -448,7 +447,7 @@ OdinDocArray<OdinDocAttribute> odin_doc_attributes(OdinDocWriter *w, Array<Ast *
|
||||
return odin_write_slice(w, attribs.data, attribs.count);
|
||||
}
|
||||
|
||||
OdinDocArray<OdinDocString> odin_doc_where_clauses(OdinDocWriter *w, Slice<Ast *> const &where_clauses) {
|
||||
gb_internal OdinDocArray<OdinDocString> odin_doc_where_clauses(OdinDocWriter *w, Slice<Ast *> const &where_clauses) {
|
||||
if (where_clauses.count == 0) {
|
||||
return {};
|
||||
}
|
||||
@@ -462,17 +461,17 @@ OdinDocArray<OdinDocString> odin_doc_where_clauses(OdinDocWriter *w, Slice<Ast *
|
||||
return odin_write_slice(w, clauses.data, clauses.count);
|
||||
}
|
||||
|
||||
OdinDocArray<OdinDocTypeIndex> odin_doc_type_as_slice(OdinDocWriter *w, Type *type) {
|
||||
gb_internal OdinDocArray<OdinDocTypeIndex> odin_doc_type_as_slice(OdinDocWriter *w, Type *type) {
|
||||
OdinDocTypeIndex index = odin_doc_type(w, type);
|
||||
return odin_write_item_as_slice(w, index);
|
||||
}
|
||||
|
||||
OdinDocArray<OdinDocEntityIndex> odin_doc_add_entity_as_slice(OdinDocWriter *w, Entity *e) {
|
||||
gb_internal OdinDocArray<OdinDocEntityIndex> odin_doc_add_entity_as_slice(OdinDocWriter *w, Entity *e) {
|
||||
OdinDocEntityIndex index = odin_doc_add_entity(w, e);
|
||||
return odin_write_item_as_slice(w, index);
|
||||
}
|
||||
|
||||
OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
if (type == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
@@ -480,11 +479,11 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
for_array(i, w->type_cache.entries) {
|
||||
for (auto const &entry : w->type_cache) {
|
||||
// NOTE(bill): THIS IS SLOW
|
||||
Type *other = w->type_cache.entries[i].key;
|
||||
Type *other = entry.key;
|
||||
if (are_types_identical_unique_tuples(type, other)) {
|
||||
OdinDocTypeIndex index = w->type_cache.entries[i].value;
|
||||
OdinDocTypeIndex index = entry.value;
|
||||
map_set(&w->type_cache, type, index);
|
||||
return index;
|
||||
}
|
||||
@@ -750,7 +749,7 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
||||
}
|
||||
return type_index;
|
||||
}
|
||||
OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
|
||||
gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
|
||||
if (e == nullptr) {
|
||||
return 0;
|
||||
}
|
||||
@@ -860,7 +859,6 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
|
||||
if (e->flags & EntityFlag_Param) {
|
||||
if (e->flags & EntityFlag_Using) { flags |= OdinDocEntityFlag_Param_Using; }
|
||||
if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const; }
|
||||
if (e->flags & EntityFlag_AutoCast) { flags |= OdinDocEntityFlag_Param_AutoCast; }
|
||||
if (e->flags & EntityFlag_Ellipsis) { flags |= OdinDocEntityFlag_Param_Ellipsis; }
|
||||
if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; }
|
||||
if (e->flags & EntityFlag_AnyInt) { flags |= OdinDocEntityFlag_Param_AnyInt; }
|
||||
@@ -911,26 +909,24 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
|
||||
return doc_entity_index;
|
||||
}
|
||||
|
||||
void odin_doc_update_entities(OdinDocWriter *w) {
|
||||
gb_internal void odin_doc_update_entities(OdinDocWriter *w) {
|
||||
{
|
||||
// NOTE(bill): Double pass, just in case entities are created on odin_doc_type
|
||||
auto entities = array_make<Entity *>(heap_allocator(), w->entity_cache.entries.count);
|
||||
auto entities = array_make<Entity *>(heap_allocator(), 0, w->entity_cache.count);
|
||||
defer (array_free(&entities));
|
||||
|
||||
for_array(i, w->entity_cache.entries) {
|
||||
Entity *e = w->entity_cache.entries[i].key;
|
||||
entities[i] = e;
|
||||
for (auto const &entry : w->entity_cache) {
|
||||
array_add(&entities, entry.key);
|
||||
}
|
||||
for_array(i, entities) {
|
||||
Entity *e = entities[i];
|
||||
for (Entity *e : entities) {
|
||||
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
|
||||
gb_unused(type_index);
|
||||
}
|
||||
}
|
||||
|
||||
for_array(i, w->entity_cache.entries) {
|
||||
Entity *e = w->entity_cache.entries[i].key;
|
||||
OdinDocEntityIndex entity_index = w->entity_cache.entries[i].value;
|
||||
for (auto const &entry : w->entity_cache) {
|
||||
Entity *e = entry.key;
|
||||
OdinDocEntityIndex entity_index = entry.value;
|
||||
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
|
||||
|
||||
OdinDocEntityIndex foreign_library = 0;
|
||||
@@ -948,8 +944,8 @@ void odin_doc_update_entities(OdinDocWriter *w) {
|
||||
auto pges = array_make<OdinDocEntityIndex>(heap_allocator(), 0, e->ProcGroup.entities.count);
|
||||
defer (array_free(&pges));
|
||||
|
||||
for_array(j, e->ProcGroup.entities) {
|
||||
OdinDocEntityIndex index = odin_doc_add_entity(w, e->ProcGroup.entities[j]);
|
||||
for (Entity *entity : e->ProcGroup.entities) {
|
||||
OdinDocEntityIndex index = odin_doc_add_entity(w, entity);
|
||||
array_add(&pges, index);
|
||||
}
|
||||
grouped_entities = odin_write_slice(w, pges.data, pges.count);
|
||||
@@ -968,7 +964,7 @@ void odin_doc_update_entities(OdinDocWriter *w) {
|
||||
|
||||
|
||||
|
||||
OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPackage *pkg) {
|
||||
gb_internal OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPackage *pkg) {
|
||||
if (pkg->scope == nullptr) {
|
||||
return {};
|
||||
}
|
||||
@@ -976,12 +972,12 @@ OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPa
|
||||
return {};
|
||||
}
|
||||
|
||||
auto entries = array_make<OdinDocScopeEntry>(heap_allocator(), 0, w->entity_cache.entries.count);
|
||||
auto entries = array_make<OdinDocScopeEntry>(heap_allocator(), 0, w->entity_cache.count);
|
||||
defer (array_free(&entries));
|
||||
|
||||
for_array(i, pkg->scope->elements.entries) {
|
||||
String name = pkg->scope->elements.entries[i].key.string;
|
||||
Entity *e = pkg->scope->elements.entries[i].value;
|
||||
for (auto const &element : pkg->scope->elements) {
|
||||
String name = element.key;
|
||||
Entity *e = element.value;
|
||||
switch (e->kind) {
|
||||
case Entity_Invalid:
|
||||
case Entity_Nil:
|
||||
@@ -1018,11 +1014,11 @@ OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPa
|
||||
}
|
||||
|
||||
|
||||
void odin_doc_write_docs(OdinDocWriter *w) {
|
||||
auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.entries.count);
|
||||
gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
|
||||
auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.count);
|
||||
defer (array_free(&pkgs));
|
||||
for_array(i, w->info->packages.entries) {
|
||||
AstPackage *pkg = w->info->packages.entries[i].value;
|
||||
for (auto const &entry : w->info->packages) {
|
||||
AstPackage *pkg = entry.value;
|
||||
if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
|
||||
array_add(&pkgs, pkg);
|
||||
} else {
|
||||
@@ -1093,7 +1089,7 @@ void odin_doc_write_docs(OdinDocWriter *w) {
|
||||
}
|
||||
|
||||
|
||||
void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) {
|
||||
gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) {
|
||||
gbFile f = {};
|
||||
gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, filename);
|
||||
if (err != gbFileError_None) {
|
||||
@@ -1108,7 +1104,7 @@ void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) {
|
||||
}
|
||||
}
|
||||
|
||||
void odin_doc_write(CheckerInfo *info, char const *filename) {
|
||||
gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
|
||||
OdinDocWriter w_ = {};
|
||||
OdinDocWriter *w = &w_;
|
||||
defer (odin_doc_writer_destroy(w));
|
||||
|
||||
+30
-36
@@ -26,7 +26,7 @@ enum EntityKind {
|
||||
Entity_Count,
|
||||
};
|
||||
|
||||
String const entity_strings[] = {
|
||||
gb_global String const entity_strings[] = {
|
||||
#define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1},
|
||||
ENTITY_KINDS
|
||||
#undef ENTITY_KIND
|
||||
@@ -61,7 +61,7 @@ enum EntityFlag : u64 {
|
||||
EntityFlag_ProcBodyChecked = 1ull<<21,
|
||||
|
||||
EntityFlag_CVarArg = 1ull<<22,
|
||||
EntityFlag_AutoCast = 1ull<<23,
|
||||
|
||||
EntityFlag_AnyInt = 1ull<<24,
|
||||
|
||||
EntityFlag_Disabled = 1ull<<25,
|
||||
@@ -116,7 +116,7 @@ struct ParameterValue {
|
||||
};
|
||||
};
|
||||
|
||||
bool has_parameter_value(ParameterValue const ¶m_value) {
|
||||
gb_internal gb_inline bool has_parameter_value(ParameterValue const ¶m_value) {
|
||||
if (param_value.kind != ParameterValue_Invalid) {
|
||||
return true;
|
||||
}
|
||||
@@ -130,7 +130,7 @@ enum EntityConstantFlags : u32 {
|
||||
EntityConstantFlag_ImplicitEnumValue = 1<<0,
|
||||
};
|
||||
|
||||
enum ProcedureOptimizationMode : u32 {
|
||||
enum ProcedureOptimizationMode : u8 {
|
||||
ProcedureOptimizationMode_Default,
|
||||
ProcedureOptimizationMode_None,
|
||||
ProcedureOptimizationMode_Minimal,
|
||||
@@ -151,10 +151,9 @@ struct TypeNameObjCMetadata {
|
||||
Array<TypeNameObjCMetadataEntry> value_entries;
|
||||
};
|
||||
|
||||
TypeNameObjCMetadata *create_type_name_obj_c_metadata() {
|
||||
gb_internal TypeNameObjCMetadata *create_type_name_obj_c_metadata() {
|
||||
TypeNameObjCMetadata *md = gb_alloc_item(permanent_allocator(), TypeNameObjCMetadata);
|
||||
md->mutex = gb_alloc_item(permanent_allocator(), BlockingMutex);
|
||||
mutex_init(md->mutex);
|
||||
array_init(&md->type_entries, heap_allocator());
|
||||
array_init(&md->value_entries, heap_allocator());
|
||||
return md;
|
||||
@@ -234,6 +233,9 @@ struct Entity {
|
||||
String link_name;
|
||||
String link_prefix;
|
||||
DeferredProcedure deferred_procedure;
|
||||
|
||||
struct GenProcsData *gen_procs;
|
||||
BlockingMutex gen_procs_mutex;
|
||||
ProcedureOptimizationMode optimization_mode;
|
||||
bool is_foreign : 1;
|
||||
bool is_export : 1;
|
||||
@@ -266,7 +268,7 @@ struct Entity {
|
||||
};
|
||||
};
|
||||
|
||||
bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) {
|
||||
gb_internal bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) {
|
||||
switch (kind) {
|
||||
case Entity_Builtin:
|
||||
return allow_builtin;
|
||||
@@ -278,7 +280,7 @@ bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is_entity_exported(Entity *e, bool allow_builtin = false) {
|
||||
gb_internal bool is_entity_exported(Entity *e, bool allow_builtin = false) {
|
||||
// TODO(bill): Determine the actual exportation rules for imports of entities
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (!is_entity_kind_exported(e->kind, allow_builtin)) {
|
||||
@@ -300,7 +302,7 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool entity_has_deferred_procedure(Entity *e) {
|
||||
gb_internal bool entity_has_deferred_procedure(Entity *e) {
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (e->kind == Entity_Procedure) {
|
||||
return e->Procedure.deferred_procedure.entity != nullptr;
|
||||
@@ -311,7 +313,7 @@ bool entity_has_deferred_procedure(Entity *e) {
|
||||
|
||||
gb_global std::atomic<u64> global_entity_id;
|
||||
|
||||
Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||
gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||
gbAllocator a = permanent_allocator();
|
||||
Entity *entity = gb_alloc_item(a, Entity);
|
||||
entity->kind = kind;
|
||||
@@ -323,13 +325,13 @@ Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
|
||||
gb_internal Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
|
||||
Entity *entity = alloc_entity(Entity_Variable, scope, token, type);
|
||||
entity->state = state;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) {
|
||||
gb_internal Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) {
|
||||
GB_ASSERT(parent != nullptr);
|
||||
token.pos = parent->token.pos;
|
||||
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
|
||||
@@ -343,19 +345,19 @@ Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast
|
||||
}
|
||||
|
||||
|
||||
Entity *alloc_entity_constant(Scope *scope, Token token, Type *type, ExactValue value) {
|
||||
gb_internal Entity *alloc_entity_constant(Scope *scope, Token token, Type *type, ExactValue value) {
|
||||
Entity *entity = alloc_entity(Entity_Constant, scope, token, type);
|
||||
entity->Constant.value = value;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_type_name(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
|
||||
gb_internal Entity *alloc_entity_type_name(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
|
||||
Entity *entity = alloc_entity(Entity_TypeName, scope, token, type);
|
||||
entity->state = state;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
|
||||
gb_internal Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
|
||||
Entity *entity = alloc_entity_variable(scope, token, type);
|
||||
entity->flags |= EntityFlag_Used;
|
||||
entity->flags |= EntityFlag_Param;
|
||||
@@ -366,7 +368,7 @@ Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using,
|
||||
}
|
||||
|
||||
|
||||
Entity *alloc_entity_const_param(Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
|
||||
gb_internal Entity *alloc_entity_const_param(Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
|
||||
Entity *entity = alloc_entity_constant(scope, token, type, value);
|
||||
entity->flags |= EntityFlag_Used;
|
||||
if (poly_const) entity->flags |= EntityFlag_PolyConst;
|
||||
@@ -375,7 +377,7 @@ Entity *alloc_entity_const_param(Scope *scope, Token token, Type *type, ExactVal
|
||||
}
|
||||
|
||||
|
||||
Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using, i32 field_index, EntityState state = EntityState_Unresolved) {
|
||||
gb_internal Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using, i32 field_index, EntityState state = EntityState_Unresolved) {
|
||||
Entity *entity = alloc_entity_variable(scope, token, type);
|
||||
entity->Variable.field_index = field_index;
|
||||
if (is_using) entity->flags |= EntityFlag_Using;
|
||||
@@ -384,7 +386,7 @@ Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using,
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field_index) {
|
||||
gb_internal Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field_index) {
|
||||
Entity *entity = alloc_entity_variable(scope, token, type);
|
||||
entity->Variable.field_index = field_index;
|
||||
entity->flags |= EntityFlag_Field;
|
||||
@@ -393,26 +395,18 @@ Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags) {
|
||||
gb_internal Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags) {
|
||||
Entity *entity = alloc_entity(Entity_Procedure, scope, token, signature_type);
|
||||
entity->Procedure.tags = tags;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_proc_group(Scope *scope, Token token, Type *type) {
|
||||
gb_internal Entity *alloc_entity_proc_group(Scope *scope, Token token, Type *type) {
|
||||
Entity *entity = alloc_entity(Entity_ProcGroup, scope, token, type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
|
||||
Entity *alloc_entity_builtin(Scope *scope, Token token, Type *type, i32 id) {
|
||||
Entity *entity = alloc_entity(Entity_Builtin, scope, token, type);
|
||||
entity->Builtin.id = id;
|
||||
entity->state = EntityState_Resolved;
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
|
||||
gb_internal Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
|
||||
String path, String name, Scope *import_scope) {
|
||||
Entity *entity = alloc_entity(Entity_ImportName, scope, token, type);
|
||||
entity->ImportName.path = path;
|
||||
@@ -422,7 +416,7 @@ Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type,
|
||||
gb_internal Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type,
|
||||
Slice<String> paths, String name) {
|
||||
Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type);
|
||||
entity->LibraryName.paths = paths;
|
||||
@@ -435,12 +429,12 @@ Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type,
|
||||
|
||||
|
||||
|
||||
Entity *alloc_entity_nil(String name, Type *type) {
|
||||
gb_internal Entity *alloc_entity_nil(String name, Type *type) {
|
||||
Entity *entity = alloc_entity(Entity_Nil, nullptr, make_token_ident(name), type);
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_label(Scope *scope, Token token, Type *type, Ast *node, Ast *parent) {
|
||||
gb_internal Entity *alloc_entity_label(Scope *scope, Token token, Type *type, Ast *node, Ast *parent) {
|
||||
Entity *entity = alloc_entity(Entity_Label, scope, token, type);
|
||||
entity->Label.node = node;
|
||||
entity->Label.parent = parent;
|
||||
@@ -448,15 +442,15 @@ Entity *alloc_entity_label(Scope *scope, Token token, Type *type, Ast *node, Ast
|
||||
return entity;
|
||||
}
|
||||
|
||||
Entity *alloc_entity_dummy_variable(Scope *scope, Token token) {
|
||||
gb_internal Entity *alloc_entity_dummy_variable(Scope *scope, Token token) {
|
||||
token.string = str_lit("_");
|
||||
return alloc_entity_variable(scope, token, nullptr);
|
||||
}
|
||||
|
||||
|
||||
Entity *entity_from_expr(Ast *expr);
|
||||
gb_internal Entity *entity_from_expr(Ast *expr);
|
||||
|
||||
Entity *strip_entity_wrapping(Entity *e) {
|
||||
gb_internal Entity *strip_entity_wrapping(Entity *e) {
|
||||
if (e == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
@@ -469,7 +463,7 @@ Entity *strip_entity_wrapping(Entity *e) {
|
||||
return e;
|
||||
}
|
||||
|
||||
Entity *strip_entity_wrapping(Ast *expr) {
|
||||
gb_internal Entity *strip_entity_wrapping(Ast *expr) {
|
||||
Entity *e = entity_from_expr(expr);
|
||||
return strip_entity_wrapping(e);
|
||||
}
|
||||
|
||||
+31
-35
@@ -17,15 +17,11 @@ gb_global ErrorCollector global_error_collector;
|
||||
#define MAX_ERROR_COLLECTOR_COUNT (36)
|
||||
|
||||
|
||||
bool any_errors(void) {
|
||||
gb_internal bool any_errors(void) {
|
||||
return global_error_collector.count.load() != 0;
|
||||
}
|
||||
|
||||
void init_global_error_collector(void) {
|
||||
mutex_init(&global_error_collector.mutex);
|
||||
mutex_init(&global_error_collector.block_mutex);
|
||||
mutex_init(&global_error_collector.error_out_mutex);
|
||||
mutex_init(&global_error_collector.string_mutex);
|
||||
gb_internal void init_global_error_collector(void) {
|
||||
array_init(&global_error_collector.errors, heap_allocator());
|
||||
array_init(&global_error_collector.error_buffer, heap_allocator());
|
||||
array_init(&global_file_path_strings, heap_allocator(), 1, 4096);
|
||||
@@ -35,9 +31,9 @@ void init_global_error_collector(void) {
|
||||
|
||||
// temporary
|
||||
// defined in build_settings.cpp
|
||||
char *token_pos_to_string(TokenPos const &pos);
|
||||
gb_internal char *token_pos_to_string(TokenPos const &pos);
|
||||
|
||||
bool set_file_path_string(i32 index, String const &path) {
|
||||
gb_internal bool set_file_path_string(i32 index, String const &path) {
|
||||
bool ok = false;
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.string_mutex);
|
||||
@@ -55,7 +51,7 @@ bool set_file_path_string(i32 index, String const &path) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
|
||||
gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
|
||||
bool ok = false;
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.string_mutex);
|
||||
@@ -73,7 +69,7 @@ bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
|
||||
return ok;
|
||||
}
|
||||
|
||||
String get_file_path_string(i32 index) {
|
||||
gb_internal String get_file_path_string(i32 index) {
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.string_mutex);
|
||||
|
||||
@@ -86,7 +82,7 @@ String get_file_path_string(i32 index) {
|
||||
return path;
|
||||
}
|
||||
|
||||
AstFile *thread_safe_get_ast_file_from_id(i32 index) {
|
||||
gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
|
||||
GB_ASSERT(index >= 0);
|
||||
mutex_lock(&global_error_collector.string_mutex);
|
||||
|
||||
@@ -101,12 +97,12 @@ AstFile *thread_safe_get_ast_file_from_id(i32 index) {
|
||||
|
||||
|
||||
|
||||
void begin_error_block(void) {
|
||||
gb_internal void begin_error_block(void) {
|
||||
mutex_lock(&global_error_collector.block_mutex);
|
||||
global_error_collector.in_block.store(true);
|
||||
}
|
||||
|
||||
void end_error_block(void) {
|
||||
gb_internal void end_error_block(void) {
|
||||
if (global_error_collector.error_buffer.count > 0) {
|
||||
isize n = global_error_collector.error_buffer.count;
|
||||
u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1);
|
||||
@@ -127,7 +123,7 @@ void end_error_block(void) {
|
||||
#define ERROR_OUT_PROC(name) void name(char const *fmt, va_list va)
|
||||
typedef ERROR_OUT_PROC(ErrorOutProc);
|
||||
|
||||
ERROR_OUT_PROC(default_error_out_va) {
|
||||
gb_internal ERROR_OUT_PROC(default_error_out_va) {
|
||||
gbFile *f = gb_file_get_standard(gbFileStandard_Error);
|
||||
|
||||
char buf[4096] = {};
|
||||
@@ -154,15 +150,15 @@ ERROR_OUT_PROC(default_error_out_va) {
|
||||
}
|
||||
|
||||
|
||||
ErrorOutProc *error_out_va = default_error_out_va;
|
||||
gb_global ErrorOutProc *error_out_va = default_error_out_va;
|
||||
|
||||
// NOTE: defined in build_settings.cpp
|
||||
bool global_warnings_as_errors(void);
|
||||
bool global_ignore_warnings(void);
|
||||
bool show_error_line(void);
|
||||
gbString get_file_line_as_string(TokenPos const &pos, i32 *offset);
|
||||
gb_internal bool global_warnings_as_errors(void);
|
||||
gb_internal bool global_ignore_warnings(void);
|
||||
gb_internal bool show_error_line(void);
|
||||
gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset);
|
||||
|
||||
void error_out(char const *fmt, ...) {
|
||||
gb_internal void error_out(char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
error_out_va(fmt, va);
|
||||
@@ -170,7 +166,7 @@ void error_out(char const *fmt, ...) {
|
||||
}
|
||||
|
||||
|
||||
bool show_error_on_line(TokenPos const &pos, TokenPos end) {
|
||||
gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
|
||||
if (!show_error_line()) {
|
||||
return false;
|
||||
}
|
||||
@@ -237,7 +233,7 @@ bool show_error_on_line(TokenPos const &pos, TokenPos end) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
global_error_collector.count.fetch_add(1);
|
||||
|
||||
mutex_lock(&global_error_collector.mutex);
|
||||
@@ -257,7 +253,7 @@ void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
}
|
||||
}
|
||||
|
||||
void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
if (global_warnings_as_errors()) {
|
||||
error_va(pos, end, fmt, va);
|
||||
return;
|
||||
@@ -280,11 +276,11 @@ void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va)
|
||||
}
|
||||
|
||||
|
||||
void error_line_va(char const *fmt, va_list va) {
|
||||
gb_internal void error_line_va(char const *fmt, va_list va) {
|
||||
error_out_va(fmt, va);
|
||||
}
|
||||
|
||||
void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
mutex_lock(&global_error_collector.mutex);
|
||||
global_error_collector.count++;
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
@@ -303,7 +299,7 @@ void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
}
|
||||
|
||||
|
||||
void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
mutex_lock(&global_error_collector.mutex);
|
||||
global_error_collector.count++;
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
@@ -323,7 +319,7 @@ void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list
|
||||
}
|
||||
}
|
||||
|
||||
void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
if (global_warnings_as_errors()) {
|
||||
syntax_error_va(pos, end, fmt, va);
|
||||
return;
|
||||
@@ -347,21 +343,21 @@ void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_li
|
||||
|
||||
|
||||
|
||||
void warning(Token const &token, char const *fmt, ...) {
|
||||
gb_internal void warning(Token const &token, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
warning_va(token.pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void error(Token const &token, char const *fmt, ...) {
|
||||
gb_internal void error(Token const &token, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
error_va(token.pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void error(TokenPos pos, char const *fmt, ...) {
|
||||
gb_internal void error(TokenPos pos, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
Token token = {};
|
||||
@@ -370,7 +366,7 @@ void error(TokenPos pos, char const *fmt, ...) {
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void error_line(char const *fmt, ...) {
|
||||
gb_internal void error_line(char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
error_line_va(fmt, va);
|
||||
@@ -378,21 +374,21 @@ void error_line(char const *fmt, ...) {
|
||||
}
|
||||
|
||||
|
||||
void syntax_error(Token const &token, char const *fmt, ...) {
|
||||
gb_internal void syntax_error(Token const &token, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
syntax_error_va(token.pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void syntax_error(TokenPos pos, char const *fmt, ...) {
|
||||
gb_internal void syntax_error(TokenPos pos, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
syntax_error_va(pos, {}, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
|
||||
void syntax_warning(Token const &token, char const *fmt, ...) {
|
||||
gb_internal void syntax_warning(Token const &token, char const *fmt, ...) {
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
syntax_warning_va(token.pos, {}, fmt, va);
|
||||
@@ -400,7 +396,7 @@ void syntax_warning(Token const &token, char const *fmt, ...) {
|
||||
}
|
||||
|
||||
|
||||
void compiler_error(char const *fmt, ...) {
|
||||
gb_internal void compiler_error(char const *fmt, ...) {
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
|
||||
+82
-92
@@ -6,7 +6,7 @@ struct Ast;
|
||||
struct HashKey;
|
||||
struct Type;
|
||||
struct Entity;
|
||||
bool are_types_identical(Type *x, Type *y);
|
||||
gb_internal bool are_types_identical(Type *x, Type *y);
|
||||
|
||||
struct Complex128 {
|
||||
f64 real, imag;
|
||||
@@ -15,16 +15,6 @@ struct Quaternion256 {
|
||||
f64 imag, jmag, kmag, real;
|
||||
};
|
||||
|
||||
Quaternion256 quaternion256_inverse(Quaternion256 x) {
|
||||
f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag);
|
||||
x.real = +x.real * invmag2;
|
||||
x.imag = -x.imag * invmag2;
|
||||
x.jmag = -x.jmag * invmag2;
|
||||
x.kmag = -x.kmag * invmag2;
|
||||
return x;
|
||||
}
|
||||
|
||||
|
||||
enum ExactValueKind {
|
||||
ExactValue_Invalid = 0,
|
||||
|
||||
@@ -60,7 +50,7 @@ struct ExactValue {
|
||||
|
||||
gb_global ExactValue const empty_exact_value = {};
|
||||
|
||||
uintptr hash_exact_value(ExactValue v) {
|
||||
gb_internal uintptr hash_exact_value(ExactValue v) {
|
||||
mutex_lock(&hash_exact_value_mutex);
|
||||
defer (mutex_unlock(&hash_exact_value_mutex));
|
||||
|
||||
@@ -70,7 +60,7 @@ uintptr hash_exact_value(ExactValue v) {
|
||||
case ExactValue_Bool:
|
||||
return gb_fnv32a(&v.value_bool, gb_size_of(v.value_bool));
|
||||
case ExactValue_String:
|
||||
return ptr_map_hash_key(string_intern(v.value_string));
|
||||
return gb_fnv32a(v.value_string.text, v.value_string.len);
|
||||
case ExactValue_Integer:
|
||||
{
|
||||
u32 key = gb_fnv32a(v.value_integer.dp, gb_size_of(*v.value_integer.dp) * v.value_integer.used);
|
||||
@@ -97,44 +87,44 @@ uintptr hash_exact_value(ExactValue v) {
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_compound(Ast *node) {
|
||||
gb_internal ExactValue exact_value_compound(Ast *node) {
|
||||
ExactValue result = {ExactValue_Compound};
|
||||
result.value_compound = node;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_bool(bool b) {
|
||||
gb_internal ExactValue exact_value_bool(bool b) {
|
||||
ExactValue result = {ExactValue_Bool};
|
||||
result.value_bool = (b != 0);
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_string(String string) {
|
||||
gb_internal ExactValue exact_value_string(String string) {
|
||||
// TODO(bill): Allow for numbers with underscores in them
|
||||
ExactValue result = {ExactValue_String};
|
||||
result.value_string = string;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_i64(i64 i) {
|
||||
gb_internal ExactValue exact_value_i64(i64 i) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
big_int_from_i64(&result.value_integer, i);
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_u64(u64 i) {
|
||||
gb_internal ExactValue exact_value_u64(u64 i) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
big_int_from_u64(&result.value_integer, i);
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_float(f64 f) {
|
||||
gb_internal ExactValue exact_value_float(f64 f) {
|
||||
ExactValue result = {ExactValue_Float};
|
||||
result.value_float = f;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_complex(f64 real, f64 imag) {
|
||||
gb_internal ExactValue exact_value_complex(f64 real, f64 imag) {
|
||||
ExactValue result = {ExactValue_Complex};
|
||||
result.value_complex = gb_alloc_item(permanent_allocator(), Complex128);
|
||||
result.value_complex->real = real;
|
||||
@@ -142,7 +132,7 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
|
||||
gb_internal ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
|
||||
ExactValue result = {ExactValue_Quaternion};
|
||||
result.value_quaternion = gb_alloc_item(permanent_allocator(), Quaternion256);
|
||||
result.value_quaternion->real = real;
|
||||
@@ -152,27 +142,27 @@ ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_pointer(i64 ptr) {
|
||||
gb_internal ExactValue exact_value_pointer(i64 ptr) {
|
||||
ExactValue result = {ExactValue_Pointer};
|
||||
result.value_pointer = ptr;
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_procedure(Ast *node) {
|
||||
gb_internal ExactValue exact_value_procedure(Ast *node) {
|
||||
ExactValue result = {ExactValue_Procedure};
|
||||
result.value_procedure = node;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_typeid(Type *type) {
|
||||
gb_internal ExactValue exact_value_typeid(Type *type) {
|
||||
ExactValue result = {ExactValue_Typeid};
|
||||
result.value_typeid = type;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_integer_from_string(String const &string) {
|
||||
gb_internal ExactValue exact_value_integer_from_string(String const &string) {
|
||||
ExactValue result = {ExactValue_Integer};
|
||||
bool success;
|
||||
big_int_from_string(&result.value_integer, string, &success);
|
||||
@@ -184,7 +174,7 @@ ExactValue exact_value_integer_from_string(String const &string) {
|
||||
|
||||
|
||||
|
||||
f64 float_from_string(String string) {
|
||||
gb_internal f64 float_from_string(String string) {
|
||||
isize i = 0;
|
||||
u8 *str = string.text;
|
||||
isize len = string.len;
|
||||
@@ -262,7 +252,7 @@ f64 float_from_string(String string) {
|
||||
return sign * (frac ? (value / scale) : (value * scale));
|
||||
}
|
||||
|
||||
ExactValue exact_value_float_from_string(String string) {
|
||||
gb_internal ExactValue exact_value_float_from_string(String string) {
|
||||
if (string.len > 2 && string[0] == '0' && string[1] == 'h') {
|
||||
|
||||
isize digit_count = 0;
|
||||
@@ -298,7 +288,7 @@ ExactValue exact_value_float_from_string(String string) {
|
||||
}
|
||||
|
||||
|
||||
ExactValue exact_value_from_basic_literal(TokenKind kind, String const &string) {
|
||||
gb_internal ExactValue exact_value_from_basic_literal(TokenKind kind, String const &string) {
|
||||
switch (kind) {
|
||||
case Token_String: return exact_value_string(string);
|
||||
case Token_Integer: return exact_value_integer_from_string(string);
|
||||
@@ -330,7 +320,7 @@ ExactValue exact_value_from_basic_literal(TokenKind kind, String const &string)
|
||||
return result;
|
||||
}
|
||||
|
||||
ExactValue exact_value_to_integer(ExactValue v) {
|
||||
gb_internal ExactValue exact_value_to_integer(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Bool: {
|
||||
i64 i = 0;
|
||||
@@ -357,7 +347,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_to_float(ExactValue v) {
|
||||
gb_internal ExactValue exact_value_to_float(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_float(big_int_to_f64(&v.value_integer));
|
||||
@@ -368,7 +358,7 @@ ExactValue exact_value_to_float(ExactValue v) {
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_to_complex(ExactValue v) {
|
||||
gb_internal ExactValue exact_value_to_complex(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_complex(big_int_to_f64(&v.value_integer), 0);
|
||||
@@ -383,7 +373,7 @@ ExactValue exact_value_to_complex(ExactValue v) {
|
||||
v.value_complex = gb_alloc_item(permanent_allocator(), Complex128);
|
||||
return r;
|
||||
}
|
||||
ExactValue exact_value_to_quaternion(ExactValue v) {
|
||||
gb_internal ExactValue exact_value_to_quaternion(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0);
|
||||
@@ -399,7 +389,7 @@ ExactValue exact_value_to_quaternion(ExactValue v) {
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_real(ExactValue v) {
|
||||
gb_internal ExactValue exact_value_real(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
case ExactValue_Float:
|
||||
@@ -413,7 +403,7 @@ ExactValue exact_value_real(ExactValue v) {
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_imag(ExactValue v) {
|
||||
gb_internal ExactValue exact_value_imag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
case ExactValue_Float:
|
||||
@@ -427,7 +417,7 @@ ExactValue exact_value_imag(ExactValue v) {
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_jmag(ExactValue v) {
|
||||
gb_internal ExactValue exact_value_jmag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
case ExactValue_Float:
|
||||
@@ -440,7 +430,7 @@ ExactValue exact_value_jmag(ExactValue v) {
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_kmag(ExactValue v) {
|
||||
gb_internal ExactValue exact_value_kmag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
case ExactValue_Float:
|
||||
@@ -453,60 +443,60 @@ ExactValue exact_value_kmag(ExactValue v) {
|
||||
return r;
|
||||
}
|
||||
|
||||
ExactValue exact_value_make_imag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_complex(0, exact_value_to_float(v).value_float);
|
||||
case ExactValue_Float:
|
||||
return exact_value_complex(0, v.value_float);
|
||||
default:
|
||||
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
}
|
||||
// gb_internal ExactValue exact_value_make_imag(ExactValue v) {
|
||||
// switch (v.kind) {
|
||||
// case ExactValue_Integer:
|
||||
// return exact_value_complex(0, exact_value_to_float(v).value_float);
|
||||
// case ExactValue_Float:
|
||||
// return exact_value_complex(0, v.value_float);
|
||||
// default:
|
||||
// GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
||||
// }
|
||||
// ExactValue r = {ExactValue_Invalid};
|
||||
// return r;
|
||||
// }
|
||||
|
||||
ExactValue exact_value_make_jmag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
|
||||
case ExactValue_Float:
|
||||
return exact_value_quaternion(0, 0, v.value_float, 0);
|
||||
default:
|
||||
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
}
|
||||
// gb_internal ExactValue exact_value_make_jmag(ExactValue v) {
|
||||
// switch (v.kind) {
|
||||
// case ExactValue_Integer:
|
||||
// return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
|
||||
// case ExactValue_Float:
|
||||
// return exact_value_quaternion(0, 0, v.value_float, 0);
|
||||
// default:
|
||||
// GB_PANIC("Expected an integer or float type for 'exact_value_make_jmag'");
|
||||
// }
|
||||
// ExactValue r = {ExactValue_Invalid};
|
||||
// return r;
|
||||
// }
|
||||
|
||||
ExactValue exact_value_make_kmag(ExactValue v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Integer:
|
||||
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
|
||||
case ExactValue_Float:
|
||||
return exact_value_quaternion(0, 0, 0, v.value_float);
|
||||
default:
|
||||
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
||||
}
|
||||
ExactValue r = {ExactValue_Invalid};
|
||||
return r;
|
||||
}
|
||||
// gb_internal ExactValue exact_value_make_kmag(ExactValue v) {
|
||||
// switch (v.kind) {
|
||||
// case ExactValue_Integer:
|
||||
// return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
|
||||
// case ExactValue_Float:
|
||||
// return exact_value_quaternion(0, 0, 0, v.value_float);
|
||||
// default:
|
||||
// GB_PANIC("Expected an integer or float type for 'exact_value_make_kmag'");
|
||||
// }
|
||||
// ExactValue r = {ExactValue_Invalid};
|
||||
// return r;
|
||||
// }
|
||||
|
||||
i64 exact_value_to_i64(ExactValue v) {
|
||||
gb_internal i64 exact_value_to_i64(ExactValue v) {
|
||||
v = exact_value_to_integer(v);
|
||||
if (v.kind == ExactValue_Integer) {
|
||||
return big_int_to_i64(&v.value_integer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
u64 exact_value_to_u64(ExactValue v) {
|
||||
gb_internal u64 exact_value_to_u64(ExactValue v) {
|
||||
v = exact_value_to_integer(v);
|
||||
if (v.kind == ExactValue_Integer) {
|
||||
return big_int_to_u64(&v.value_integer);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
f64 exact_value_to_f64(ExactValue v) {
|
||||
gb_internal f64 exact_value_to_f64(ExactValue v) {
|
||||
v = exact_value_to_float(v);
|
||||
if (v.kind == ExactValue_Float) {
|
||||
return v.value_float;
|
||||
@@ -519,7 +509,7 @@ f64 exact_value_to_f64(ExactValue v) {
|
||||
|
||||
|
||||
|
||||
ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, bool is_unsigned) {
|
||||
gb_internal ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, bool is_unsigned) {
|
||||
switch (op) {
|
||||
case Token_Add: {
|
||||
switch (v.kind) {
|
||||
@@ -596,7 +586,7 @@ failure:
|
||||
}
|
||||
|
||||
// NOTE(bill): Make sure things are evaluated in correct order
|
||||
i32 exact_value_order(ExactValue const &v) {
|
||||
gb_internal i32 exact_value_order(ExactValue const &v) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Invalid:
|
||||
case ExactValue_Compound:
|
||||
@@ -623,7 +613,7 @@ i32 exact_value_order(ExactValue const &v) {
|
||||
}
|
||||
}
|
||||
|
||||
void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
gb_internal void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
if (exact_value_order(*y) < exact_value_order(*x)) {
|
||||
match_exact_values(y, x);
|
||||
return;
|
||||
@@ -687,7 +677,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
|
||||
}
|
||||
|
||||
// TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough?
|
||||
ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) {
|
||||
gb_internal ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) {
|
||||
match_exact_values(&x, &y);
|
||||
|
||||
switch (x.kind) {
|
||||
@@ -846,32 +836,32 @@ error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variab
|
||||
return empty_exact_value;
|
||||
}
|
||||
|
||||
gb_inline ExactValue exact_value_add(ExactValue const &x, ExactValue const &y) {
|
||||
gb_internal gb_inline ExactValue exact_value_add(ExactValue const &x, ExactValue const &y) {
|
||||
return exact_binary_operator_value(Token_Add, x, y);
|
||||
}
|
||||
gb_inline ExactValue exact_value_sub(ExactValue const &x, ExactValue const &y) {
|
||||
gb_internal gb_inline ExactValue exact_value_sub(ExactValue const &x, ExactValue const &y) {
|
||||
return exact_binary_operator_value(Token_Sub, x, y);
|
||||
}
|
||||
gb_inline ExactValue exact_value_mul(ExactValue const &x, ExactValue const &y) {
|
||||
gb_internal gb_inline ExactValue exact_value_mul(ExactValue const &x, ExactValue const &y) {
|
||||
return exact_binary_operator_value(Token_Mul, x, y);
|
||||
}
|
||||
gb_inline ExactValue exact_value_quo(ExactValue const &x, ExactValue const &y) {
|
||||
gb_internal gb_inline ExactValue exact_value_quo(ExactValue const &x, ExactValue const &y) {
|
||||
return exact_binary_operator_value(Token_Quo, x, y);
|
||||
}
|
||||
gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactValue const &y) {
|
||||
gb_internal gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactValue const &y) {
|
||||
return exact_binary_operator_value(op, x, y);
|
||||
}
|
||||
|
||||
gb_inline ExactValue exact_value_increment_one(ExactValue const &x) {
|
||||
gb_internal gb_inline ExactValue exact_value_increment_one(ExactValue const &x) {
|
||||
return exact_binary_operator_value(Token_Add, x, exact_value_i64(1));
|
||||
}
|
||||
|
||||
|
||||
i32 cmp_f64(f64 a, f64 b) {
|
||||
gb_internal gb_inline i32 cmp_f64(f64 a, f64 b) {
|
||||
return (a > b) - (a < b);
|
||||
}
|
||||
|
||||
bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
match_exact_values(&x, &y);
|
||||
|
||||
switch (x.kind) {
|
||||
@@ -969,12 +959,12 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Entity *strip_entity_wrapping(Ast *expr);
|
||||
Entity *strip_entity_wrapping(Entity *e);
|
||||
gb_internal Entity *strip_entity_wrapping(Ast *expr);
|
||||
gb_internal Entity *strip_entity_wrapping(Entity *e);
|
||||
|
||||
gbString write_expr_to_string(gbString str, Ast *node, bool shorthand);
|
||||
gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthand);
|
||||
|
||||
gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
|
||||
gb_internal gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
|
||||
switch (v.kind) {
|
||||
case ExactValue_Invalid:
|
||||
return str;
|
||||
@@ -1017,6 +1007,6 @@ gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize st
|
||||
return str;
|
||||
};
|
||||
|
||||
gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) {
|
||||
gb_internal gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) {
|
||||
return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit);
|
||||
}
|
||||
|
||||
@@ -465,8 +465,6 @@ typedef i32 b32; // NOTE(bill): Prefer this!!!
|
||||
#if !defined(gb_thread_local)
|
||||
#if defined(_MSC_VER) && _MSC_VER >= 1300
|
||||
#define gb_thread_local __declspec(thread)
|
||||
#elif defined(__GNUC__)
|
||||
#define gb_thread_local __thread
|
||||
#else
|
||||
#define gb_thread_local thread_local
|
||||
#endif
|
||||
|
||||
+220
-107
@@ -1,3 +1,5 @@
|
||||
#define ALLOW_SPLIT_MULTI_RETURNS true
|
||||
|
||||
enum lbArgKind {
|
||||
lbArg_Direct,
|
||||
lbArg_Indirect,
|
||||
@@ -16,21 +18,21 @@ struct lbArgType {
|
||||
};
|
||||
|
||||
|
||||
i64 lb_sizeof(LLVMTypeRef type);
|
||||
i64 lb_alignof(LLVMTypeRef type);
|
||||
gb_internal i64 lb_sizeof(LLVMTypeRef type);
|
||||
gb_internal i64 lb_alignof(LLVMTypeRef type);
|
||||
|
||||
lbArgType lb_arg_type_direct(LLVMTypeRef type, LLVMTypeRef cast_type, LLVMTypeRef pad_type, LLVMAttributeRef attr) {
|
||||
gb_internal lbArgType lb_arg_type_direct(LLVMTypeRef type, LLVMTypeRef cast_type, LLVMTypeRef pad_type, LLVMAttributeRef attr) {
|
||||
return lbArgType{lbArg_Direct, type, cast_type, pad_type, attr, nullptr, 0, false};
|
||||
}
|
||||
lbArgType lb_arg_type_direct(LLVMTypeRef type) {
|
||||
gb_internal lbArgType lb_arg_type_direct(LLVMTypeRef type) {
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, nullptr);
|
||||
}
|
||||
|
||||
lbArgType lb_arg_type_indirect(LLVMTypeRef type, LLVMAttributeRef attr) {
|
||||
gb_internal lbArgType lb_arg_type_indirect(LLVMTypeRef type, LLVMAttributeRef attr) {
|
||||
return lbArgType{lbArg_Indirect, type, nullptr, nullptr, attr, nullptr, 0, false};
|
||||
}
|
||||
|
||||
lbArgType lb_arg_type_indirect_byval(LLVMContextRef c, LLVMTypeRef type) {
|
||||
gb_internal lbArgType lb_arg_type_indirect_byval(LLVMContextRef c, LLVMTypeRef type) {
|
||||
i64 alignment = lb_alignof(type);
|
||||
alignment = gb_max(alignment, 8);
|
||||
|
||||
@@ -39,7 +41,7 @@ lbArgType lb_arg_type_indirect_byval(LLVMContextRef c, LLVMTypeRef type) {
|
||||
return lbArgType{lbArg_Indirect, type, nullptr, nullptr, byval_attr, align_attr, alignment, true};
|
||||
}
|
||||
|
||||
lbArgType lb_arg_type_ignore(LLVMTypeRef type) {
|
||||
gb_internal lbArgType lb_arg_type_ignore(LLVMTypeRef type) {
|
||||
return lbArgType{lbArg_Ignore, type, nullptr, nullptr, nullptr, nullptr, 0, false};
|
||||
}
|
||||
|
||||
@@ -48,21 +50,29 @@ struct lbFunctionType {
|
||||
ProcCallingConvention calling_convention;
|
||||
Array<lbArgType> args;
|
||||
lbArgType ret;
|
||||
|
||||
LLVMTypeRef multiple_return_original_type; // nullptr if not used
|
||||
isize original_arg_count;
|
||||
};
|
||||
|
||||
i64 llvm_align_formula(i64 off, i64 a) {
|
||||
gb_internal gbAllocator lb_function_type_args_allocator(void) {
|
||||
return heap_allocator();
|
||||
}
|
||||
|
||||
|
||||
gb_internal gb_inline i64 llvm_align_formula(i64 off, i64 a) {
|
||||
return (off + a - 1) / a * a;
|
||||
}
|
||||
|
||||
|
||||
bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
|
||||
gb_internal bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
|
||||
if (type == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return LLVMGetTypeKind(type) == kind;
|
||||
}
|
||||
|
||||
LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
|
||||
gb_internal LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
|
||||
unsigned arg_count = cast(unsigned)ft->args.count;
|
||||
unsigned offset = 0;
|
||||
|
||||
@@ -100,7 +110,9 @@ LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
|
||||
}
|
||||
args[arg_index++] = arg_type;
|
||||
} else if (arg->kind == lbArg_Indirect) {
|
||||
GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
|
||||
if (ft->multiple_return_original_type == nullptr || i < ft->original_arg_count) {
|
||||
GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
|
||||
}
|
||||
args[arg_index++] = LLVMPointerType(arg->type, 0);
|
||||
} else if (arg->kind == lbArg_Ignore) {
|
||||
// ignore
|
||||
@@ -118,7 +130,7 @@ LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
|
||||
// }
|
||||
|
||||
|
||||
void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) {
|
||||
gb_internal void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) {
|
||||
if (ft == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -147,6 +159,13 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa
|
||||
LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute);
|
||||
}
|
||||
|
||||
if (ft->multiple_return_original_type) {
|
||||
if (ft->original_arg_count <= i) {
|
||||
LLVMAddAttributeAtIndex(fn, arg_index+1, noalias_attr);
|
||||
LLVMAddAttributeAtIndex(fn, arg_index+1, nonnull_attr);
|
||||
}
|
||||
}
|
||||
|
||||
arg_index++;
|
||||
}
|
||||
|
||||
@@ -182,7 +201,7 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa
|
||||
}
|
||||
|
||||
|
||||
i64 lb_sizeof(LLVMTypeRef type) {
|
||||
gb_internal i64 lb_sizeof(LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
case LLVMVoidTypeKind:
|
||||
@@ -248,7 +267,7 @@ i64 lb_sizeof(LLVMTypeRef type) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
i64 lb_alignof(LLVMTypeRef type) {
|
||||
gb_internal i64 lb_alignof(LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
case LLVMVoidTypeKind:
|
||||
@@ -307,25 +326,63 @@ i64 lb_alignof(LLVMTypeRef type) {
|
||||
}
|
||||
|
||||
|
||||
#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, ProcCallingConvention calling_convention)
|
||||
#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, ProcCallingConvention calling_convention)
|
||||
typedef LB_ABI_INFO(lbAbiInfoType);
|
||||
|
||||
#define LB_ABI_COMPUTE_RETURN_TYPE(name) lbArgType name(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple)
|
||||
typedef LB_ABI_COMPUTE_RETURN_TYPE(lbAbiComputeReturnType);
|
||||
|
||||
|
||||
gb_internal lbArgType lb_abi_modify_return_is_tuple(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, lbAbiComputeReturnType *compute_return_type) {
|
||||
GB_ASSERT(return_type != nullptr);
|
||||
GB_ASSERT(compute_return_type != nullptr);
|
||||
|
||||
lbArgType return_arg = {};
|
||||
if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
|
||||
unsigned field_count = LLVMCountStructElementTypes(return_type);
|
||||
if (field_count > 1) {
|
||||
ft->original_arg_count = ft->args.count;
|
||||
ft->multiple_return_original_type = return_type;
|
||||
|
||||
for (unsigned i = 0; i < field_count-1; i++) {
|
||||
LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(return_type, i);
|
||||
LLVMTypeRef field_pointer_type = LLVMPointerType(field_type, 0);
|
||||
lbArgType ret_partial = lb_arg_type_direct(field_pointer_type);
|
||||
array_add(&ft->args, ret_partial);
|
||||
}
|
||||
|
||||
// override the return type for the last field
|
||||
LLVMTypeRef new_return_type = LLVMStructGetTypeAtIndex(return_type, field_count-1);
|
||||
return_arg = compute_return_type(ft, c, new_return_type, true, false);
|
||||
}
|
||||
}
|
||||
return return_arg;
|
||||
}
|
||||
|
||||
#define LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO() do { \
|
||||
if (return_is_tuple) { \
|
||||
lbArgType new_return_type = lb_abi_modify_return_is_tuple(ft, c, return_type, compute_return_type); \
|
||||
if (new_return_type.type != nullptr) { \
|
||||
return new_return_type; \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
|
||||
namespace lbAbi386 {
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||
|
||||
LB_ABI_INFO(abi_info) {
|
||||
gb_internal LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count);
|
||||
ft->ret = compute_return_type(c, return_type, return_is_defined);
|
||||
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
||||
ft->calling_convention = calling_convention;
|
||||
return ft;
|
||||
}
|
||||
|
||||
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
|
||||
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
|
||||
if (!is_return && lb_sizeof(type) > 8) {
|
||||
return lb_arg_type_indirect(type, nullptr);
|
||||
}
|
||||
@@ -352,8 +409,8 @@ namespace lbAbi386 {
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
||||
}
|
||||
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
LLVMTypeRef t = arg_types[i];
|
||||
@@ -372,7 +429,7 @@ namespace lbAbi386 {
|
||||
return args;
|
||||
}
|
||||
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
||||
@@ -383,6 +440,9 @@ namespace lbAbi386 {
|
||||
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
||||
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
||||
}
|
||||
|
||||
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
||||
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||
return lb_arg_type_indirect(return_type, attr);
|
||||
}
|
||||
@@ -391,20 +451,20 @@ namespace lbAbi386 {
|
||||
};
|
||||
|
||||
namespace lbAbiAmd64Win64 {
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||
|
||||
|
||||
LB_ABI_INFO(abi_info) {
|
||||
gb_internal LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count);
|
||||
ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined);
|
||||
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
||||
ft->calling_convention = calling_convention;
|
||||
return ft;
|
||||
}
|
||||
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
LLVMTypeRef t = arg_types[i];
|
||||
@@ -428,6 +488,26 @@ namespace lbAbiAmd64Win64 {
|
||||
}
|
||||
return args;
|
||||
}
|
||||
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
||||
i64 sz = lb_sizeof(return_type);
|
||||
switch (sz) {
|
||||
case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr);
|
||||
case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr);
|
||||
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
||||
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
||||
}
|
||||
|
||||
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
||||
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||
return lb_arg_type_indirect(return_type, attr);
|
||||
}
|
||||
return lbAbi386::non_struct(c, return_type, true);
|
||||
}
|
||||
};
|
||||
|
||||
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
|
||||
@@ -450,7 +530,7 @@ namespace lbAbiAmd64SysV {
|
||||
RegClass_Memory,
|
||||
};
|
||||
|
||||
bool is_sse(RegClass reg_class) {
|
||||
gb_internal bool is_sse(RegClass reg_class) {
|
||||
switch (reg_class) {
|
||||
case RegClass_SSEFs:
|
||||
case RegClass_SSEFv:
|
||||
@@ -466,7 +546,7 @@ namespace lbAbiAmd64SysV {
|
||||
return false;
|
||||
}
|
||||
|
||||
void all_mem(Array<RegClass> *cs) {
|
||||
gb_internal void all_mem(Array<RegClass> *cs) {
|
||||
for_array(i, *cs) {
|
||||
(*cs)[i] = RegClass_Memory;
|
||||
}
|
||||
@@ -478,19 +558,19 @@ namespace lbAbiAmd64SysV {
|
||||
Amd64TypeAttribute_StructRect,
|
||||
};
|
||||
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
||||
void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off);
|
||||
void fixup(LLVMTypeRef t, Array<RegClass> *cls);
|
||||
lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention);
|
||||
Array<RegClass> classify(LLVMTypeRef t);
|
||||
LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes);
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||
gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off);
|
||||
gb_internal void fixup(LLVMTypeRef t, Array<RegClass> *cls);
|
||||
gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention);
|
||||
gb_internal Array<RegClass> classify(LLVMTypeRef t);
|
||||
gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes);
|
||||
|
||||
LB_ABI_INFO(abi_info) {
|
||||
gb_internal LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->calling_convention = calling_convention;
|
||||
|
||||
ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
ft->args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention);
|
||||
}
|
||||
@@ -504,7 +584,7 @@ namespace lbAbiAmd64SysV {
|
||||
return ft;
|
||||
}
|
||||
|
||||
bool is_mem_cls(Array<RegClass> const &cls, Amd64TypeAttributeKind attribute_kind) {
|
||||
gb_internal bool is_mem_cls(Array<RegClass> const &cls, Amd64TypeAttributeKind attribute_kind) {
|
||||
if (attribute_kind == Amd64TypeAttribute_ByVal) {
|
||||
if (cls.count == 0) {
|
||||
return false;
|
||||
@@ -520,7 +600,7 @@ namespace lbAbiAmd64SysV {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_register(LLVMTypeRef type) {
|
||||
gb_internal bool is_register(LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
i64 sz = lb_sizeof(type);
|
||||
if (sz == 0) {
|
||||
@@ -537,7 +617,7 @@ namespace lbAbiAmd64SysV {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool is_llvm_type_slice_like(LLVMTypeRef type) {
|
||||
gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) {
|
||||
if (!lb_is_type_kind(type, LLVMStructTypeKind)) {
|
||||
return false;
|
||||
}
|
||||
@@ -553,7 +633,7 @@ namespace lbAbiAmd64SysV {
|
||||
|
||||
}
|
||||
|
||||
lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention) {
|
||||
gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention) {
|
||||
if (is_register(type)) {
|
||||
LLVMAttributeRef attribute = nullptr;
|
||||
if (type == LLVMInt1TypeInContext(c)) {
|
||||
@@ -588,7 +668,7 @@ namespace lbAbiAmd64SysV {
|
||||
}
|
||||
}
|
||||
|
||||
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||
LLVMAttributeRef attr = nullptr;
|
||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
||||
if (type == i1) {
|
||||
@@ -597,7 +677,7 @@ namespace lbAbiAmd64SysV {
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
||||
}
|
||||
|
||||
Array<RegClass> classify(LLVMTypeRef t) {
|
||||
gb_internal Array<RegClass> classify(LLVMTypeRef t) {
|
||||
i64 sz = lb_sizeof(t);
|
||||
i64 words = (sz + 7)/8;
|
||||
auto reg_classes = array_make<RegClass>(heap_allocator(), cast(isize)words);
|
||||
@@ -610,7 +690,7 @@ namespace lbAbiAmd64SysV {
|
||||
return reg_classes;
|
||||
}
|
||||
|
||||
void unify(Array<RegClass> *cls, i64 i, RegClass const newv) {
|
||||
gb_internal void unify(Array<RegClass> *cls, i64 i, RegClass const newv) {
|
||||
RegClass const oldv = (*cls)[cast(isize)i];
|
||||
if (oldv == newv) {
|
||||
return;
|
||||
@@ -646,7 +726,7 @@ namespace lbAbiAmd64SysV {
|
||||
(*cls)[cast(isize)i] = to_write;
|
||||
}
|
||||
|
||||
void fixup(LLVMTypeRef t, Array<RegClass> *cls) {
|
||||
gb_internal void fixup(LLVMTypeRef t, Array<RegClass> *cls) {
|
||||
i64 i = 0;
|
||||
i64 e = cls->count;
|
||||
if (e > 2 && (lb_is_type_kind(t, LLVMStructTypeKind) ||
|
||||
@@ -693,7 +773,7 @@ namespace lbAbiAmd64SysV {
|
||||
}
|
||||
}
|
||||
|
||||
unsigned llvec_len(Array<RegClass> const ®_classes, isize offset) {
|
||||
gb_internal unsigned llvec_len(Array<RegClass> const ®_classes, isize offset) {
|
||||
unsigned len = 1;
|
||||
for (isize i = offset; i < reg_classes.count; i++) {
|
||||
if (reg_classes[i] != RegClass_SSEUp) {
|
||||
@@ -705,7 +785,7 @@ namespace lbAbiAmd64SysV {
|
||||
}
|
||||
|
||||
|
||||
LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes) {
|
||||
gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes) {
|
||||
auto types = array_make<LLVMTypeRef>(heap_allocator(), 0, reg_classes.count);
|
||||
for (isize i = 0; i < reg_classes.count; /**/) {
|
||||
RegClass reg_class = reg_classes[i];
|
||||
@@ -774,7 +854,7 @@ namespace lbAbiAmd64SysV {
|
||||
return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false);
|
||||
}
|
||||
|
||||
void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) {
|
||||
gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) {
|
||||
i64 t_align = lb_alignof(t);
|
||||
i64 t_size = lb_sizeof(t);
|
||||
|
||||
@@ -875,7 +955,7 @@ namespace lbAbiAmd64SysV {
|
||||
}
|
||||
}
|
||||
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
|
||||
@@ -886,6 +966,9 @@ namespace lbAbiAmd64SysV {
|
||||
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
||||
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
||||
}
|
||||
|
||||
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
||||
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||
return lb_arg_type_indirect(return_type, attr);
|
||||
} else if (build_context.metrics.os == TargetOs_windows && lb_is_type_kind(return_type, LLVMIntegerTypeKind) && lb_sizeof(return_type) == 16) {
|
||||
@@ -897,20 +980,20 @@ namespace lbAbiAmd64SysV {
|
||||
|
||||
|
||||
namespace lbAbiArm64 {
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
||||
bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||
gb_internal bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_);
|
||||
|
||||
LB_ABI_INFO(abi_info) {
|
||||
gb_internal LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->ret = compute_return_type(c, return_type, return_is_defined);
|
||||
ft -> args = compute_arg_types(c, arg_types, arg_count);
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count);
|
||||
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
||||
ft->calling_convention = calling_convention;
|
||||
return ft;
|
||||
}
|
||||
|
||||
bool is_register(LLVMTypeRef type) {
|
||||
gb_internal bool is_register(LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
case LLVMIntegerTypeKind:
|
||||
@@ -923,7 +1006,7 @@ namespace lbAbiArm64 {
|
||||
return false;
|
||||
}
|
||||
|
||||
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||
LLVMAttributeRef attr = nullptr;
|
||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
||||
if (type == i1) {
|
||||
@@ -932,7 +1015,7 @@ namespace lbAbiArm64 {
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
||||
}
|
||||
|
||||
bool is_homogenous_array(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
|
||||
gb_internal bool is_homogenous_array(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
|
||||
GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind));
|
||||
unsigned len = LLVMGetArrayLength(type);
|
||||
if (len == 0) {
|
||||
@@ -949,7 +1032,7 @@ namespace lbAbiArm64 {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
bool is_homogenous_struct(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
|
||||
gb_internal bool is_homogenous_struct(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
|
||||
GB_ASSERT(lb_is_type_kind(type, LLVMStructTypeKind));
|
||||
unsigned elem_count = LLVMCountStructElementTypes(type);
|
||||
if (elem_count == 0) {
|
||||
@@ -992,7 +1075,7 @@ namespace lbAbiArm64 {
|
||||
}
|
||||
|
||||
|
||||
bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
|
||||
gb_internal bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
case LLVMFloatTypeKind:
|
||||
@@ -1008,31 +1091,33 @@ namespace lbAbiArm64 {
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned is_homogenous_aggregate_small_enough(LLVMTypeRef base_type, unsigned member_count) {
|
||||
gb_internal unsigned is_homogenous_aggregate_small_enough(LLVMTypeRef base_type, unsigned member_count) {
|
||||
return (member_count <= 4);
|
||||
}
|
||||
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef type, bool return_is_defined) {
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
||||
LLVMTypeRef homo_base_type = nullptr;
|
||||
unsigned homo_member_count = 0;
|
||||
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
} else if (is_register(type)) {
|
||||
return non_struct(c, type);
|
||||
} else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
|
||||
} else if (is_register(return_type)) {
|
||||
return non_struct(c, return_type);
|
||||
} else if (is_homogenous_aggregate(c, return_type, &homo_base_type, &homo_member_count)) {
|
||||
if (is_homogenous_aggregate_small_enough(homo_base_type, homo_member_count)) {
|
||||
return lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
|
||||
return lb_arg_type_direct(return_type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
|
||||
} else {
|
||||
//TODO(Platin): do i need to create stuff that can handle the diffrent return type?
|
||||
// else this needs a fix in llvm_backend_proc as we would need to cast it to the correct array type
|
||||
|
||||
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
||||
|
||||
//LLVMTypeRef array_type = LLVMArrayType(homo_base_type, homo_member_count);
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
|
||||
return lb_arg_type_indirect(type, attr);
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||
return lb_arg_type_indirect(return_type, attr);
|
||||
}
|
||||
} else {
|
||||
i64 size = lb_sizeof(type);
|
||||
i64 size = lb_sizeof(return_type);
|
||||
if (size <= 16) {
|
||||
LLVMTypeRef cast_type = nullptr;
|
||||
if (size <= 1) {
|
||||
@@ -1047,16 +1132,18 @@ namespace lbAbiArm64 {
|
||||
unsigned count = cast(unsigned)((size+7)/8);
|
||||
cast_type = LLVMArrayType(LLVMInt64TypeInContext(c), count);
|
||||
}
|
||||
return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
|
||||
return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr);
|
||||
} else {
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
|
||||
return lb_arg_type_indirect(type, attr);
|
||||
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
||||
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||
return lb_arg_type_indirect(return_type, attr);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
LLVMTypeRef type = arg_types[i];
|
||||
@@ -1101,21 +1188,21 @@ namespace lbAbiWasm {
|
||||
The approach taken optimizes for passing things in multiple
|
||||
registers/arguments if possible rather than by pointer.
|
||||
*/
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||
|
||||
enum {MAX_DIRECT_STRUCT_SIZE = 32};
|
||||
|
||||
LB_ABI_INFO(abi_info) {
|
||||
gb_internal LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count);
|
||||
ft->ret = compute_return_type(c, return_type, return_is_defined);
|
||||
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
|
||||
ft->calling_convention = calling_convention;
|
||||
return ft;
|
||||
}
|
||||
|
||||
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
|
||||
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
|
||||
if (!is_return && type == LLVMIntTypeInContext(c, 128)) {
|
||||
LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
|
||||
return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
|
||||
@@ -1133,7 +1220,7 @@ namespace lbAbiWasm {
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
||||
}
|
||||
|
||||
bool is_basic_register_type(LLVMTypeRef type) {
|
||||
gb_internal bool is_basic_register_type(LLVMTypeRef type) {
|
||||
switch (LLVMGetTypeKind(type)) {
|
||||
case LLVMHalfTypeKind:
|
||||
case LLVMFloatTypeKind:
|
||||
@@ -1146,7 +1233,7 @@ namespace lbAbiWasm {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool type_can_be_direct(LLVMTypeRef type) {
|
||||
gb_internal bool type_can_be_direct(LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
i64 sz = lb_sizeof(type);
|
||||
if (sz == 0) {
|
||||
@@ -1172,7 +1259,7 @@ namespace lbAbiWasm {
|
||||
return false;
|
||||
}
|
||||
|
||||
lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||
gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
|
||||
|
||||
@@ -1187,8 +1274,8 @@ namespace lbAbiWasm {
|
||||
}
|
||||
|
||||
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
LLVMTypeRef t = arg_types[i];
|
||||
@@ -1202,7 +1289,7 @@ namespace lbAbiWasm {
|
||||
return args;
|
||||
}
|
||||
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
||||
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
||||
@@ -1217,6 +1304,9 @@ namespace lbAbiWasm {
|
||||
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
|
||||
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
|
||||
}
|
||||
|
||||
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
||||
|
||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||
return lb_arg_type_indirect(return_type, attr);
|
||||
}
|
||||
@@ -1225,10 +1315,10 @@ namespace lbAbiWasm {
|
||||
}
|
||||
|
||||
namespace lbAbiArm32 {
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
|
||||
gb_internal lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
||||
|
||||
LB_ABI_INFO(abi_info) {
|
||||
gb_internal LB_ABI_INFO(abi_info) {
|
||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention);
|
||||
@@ -1237,7 +1327,7 @@ namespace lbAbiArm32 {
|
||||
return ft;
|
||||
}
|
||||
|
||||
bool is_register(LLVMTypeRef type, bool is_return) {
|
||||
gb_internal bool is_register(LLVMTypeRef type, bool is_return) {
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||
switch (kind) {
|
||||
case LLVMHalfTypeKind:
|
||||
@@ -1256,7 +1346,7 @@ namespace lbAbiArm32 {
|
||||
return false;
|
||||
}
|
||||
|
||||
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
|
||||
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
|
||||
LLVMAttributeRef attr = nullptr;
|
||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
||||
if (type == i1) {
|
||||
@@ -1265,8 +1355,8 @@ namespace lbAbiArm32 {
|
||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
||||
}
|
||||
|
||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
|
||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
|
||||
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
LLVMTypeRef t = arg_types[i];
|
||||
@@ -1290,7 +1380,7 @@ namespace lbAbiArm32 {
|
||||
return args;
|
||||
}
|
||||
|
||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
||||
gb_internal lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
|
||||
if (!return_is_defined) {
|
||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||
} else if (!is_register(return_type, true)) {
|
||||
@@ -1307,14 +1397,14 @@ namespace lbAbiArm32 {
|
||||
};
|
||||
|
||||
|
||||
LB_ABI_INFO(lb_get_abi_info) {
|
||||
gb_internal LB_ABI_INFO(lb_get_abi_info_internal) {
|
||||
switch (calling_convention) {
|
||||
case ProcCC_None:
|
||||
case ProcCC_InlineAsm:
|
||||
{
|
||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||
ft->ctx = c;
|
||||
ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
|
||||
ft->args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||
for (unsigned i = 0; i < arg_count; i++) {
|
||||
ft->args[i] = lb_arg_type_direct(arg_types[i]);
|
||||
}
|
||||
@@ -1328,32 +1418,55 @@ LB_ABI_INFO(lb_get_abi_info) {
|
||||
}
|
||||
case ProcCC_Win64:
|
||||
GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
|
||||
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
case ProcCC_SysV:
|
||||
GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
|
||||
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
}
|
||||
|
||||
switch (build_context.metrics.arch) {
|
||||
case TargetArch_amd64:
|
||||
if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) {
|
||||
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
if (build_context.metrics.os == TargetOs_windows) {
|
||||
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
} else if (build_context.metrics.abi == TargetABI_Win64) {
|
||||
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
} else if (build_context.metrics.abi == TargetABI_SysV) {
|
||||
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
} else {
|
||||
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
}
|
||||
case TargetArch_i386:
|
||||
return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
case TargetArch_arm32:
|
||||
return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
case TargetArch_arm64:
|
||||
return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
case TargetArch_wasm32:
|
||||
case TargetArch_wasm64:
|
||||
return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
|
||||
}
|
||||
|
||||
GB_PANIC("Unsupported ABI");
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
gb_internal LB_ABI_INFO(lb_get_abi_info) {
|
||||
lbFunctionType *ft = lb_get_abi_info_internal(
|
||||
c,
|
||||
arg_types, arg_count,
|
||||
return_type, return_is_defined,
|
||||
ALLOW_SPLIT_MULTI_RETURNS && return_is_tuple && is_calling_convention_odin(calling_convention),
|
||||
calling_convention);
|
||||
|
||||
|
||||
// NOTE(bill): this is handled here rather than when developing the type in `lb_type_internal_for_procedures_raw`
|
||||
// This is to make it consistent when and how it is handled
|
||||
if (calling_convention == ProcCC_Odin) {
|
||||
// append the `context` pointer
|
||||
lbArgType context_param = lb_arg_type_direct(LLVMPointerType(LLVMInt8TypeInContext(c), 0));
|
||||
array_add(&ft->args, context_param);
|
||||
}
|
||||
|
||||
return ft;
|
||||
}
|
||||
|
||||
+674
-566
File diff suppressed because it is too large
Load Diff
+169
-150
@@ -117,20 +117,34 @@ struct lbIncompleteDebugType {
|
||||
|
||||
typedef Slice<i32> lbStructFieldRemapping;
|
||||
|
||||
enum lbFunctionPassManagerKind {
|
||||
lbFunctionPassManager_default,
|
||||
lbFunctionPassManager_default_without_memcpy,
|
||||
lbFunctionPassManager_minimal,
|
||||
lbFunctionPassManager_size,
|
||||
lbFunctionPassManager_speed,
|
||||
|
||||
lbFunctionPassManager_COUNT
|
||||
};
|
||||
|
||||
struct lbModule {
|
||||
LLVMModuleRef mod;
|
||||
LLVMContextRef ctx;
|
||||
|
||||
struct lbGenerator *gen;
|
||||
LLVMTargetMachineRef target_machine;
|
||||
|
||||
CheckerInfo *info;
|
||||
AstPackage *pkg; // associated
|
||||
AstPackage *pkg; // possibly associated
|
||||
AstFile *file; // possibly associated
|
||||
|
||||
PtrMap<Type *, LLVMTypeRef> types;
|
||||
PtrMap<Type *, LLVMTypeRef> func_raw_types;
|
||||
PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *
|
||||
i32 internal_type_level;
|
||||
|
||||
RwMutex values_mutex;
|
||||
|
||||
PtrMap<Entity *, lbValue> values;
|
||||
PtrMap<Entity *, lbAddr> soa_values;
|
||||
StringMap<lbValue> members;
|
||||
@@ -150,11 +164,14 @@ struct lbModule {
|
||||
u32 nested_type_name_guid;
|
||||
|
||||
Array<lbProcedure *> procedures_to_generate;
|
||||
Array<Entity *> global_procedures_and_types_to_create;
|
||||
|
||||
lbProcedure *curr_procedure;
|
||||
|
||||
LLVMDIBuilderRef debug_builder;
|
||||
LLVMMetadataRef debug_compile_unit;
|
||||
|
||||
RecursiveMutex debug_values_mutex;
|
||||
PtrMap<void *, LLVMMetadataRef> debug_values;
|
||||
|
||||
Array<lbIncompleteDebugType> debug_incomplete_types;
|
||||
@@ -164,6 +181,8 @@ struct lbModule {
|
||||
|
||||
PtrMap<Type *, lbAddr> map_cell_info_map; // address of runtime.Map_Info
|
||||
PtrMap<Type *, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
|
||||
|
||||
LLVMPassManagerRef function_pass_managers[lbFunctionPassManager_COUNT];
|
||||
};
|
||||
|
||||
struct lbGenerator {
|
||||
@@ -173,10 +192,11 @@ struct lbGenerator {
|
||||
Array<String> output_temp_paths;
|
||||
String output_base;
|
||||
String output_name;
|
||||
PtrMap<AstPackage *, lbModule *> modules;
|
||||
PtrMap<void *, lbModule *> modules; // key is `AstPackage *` (`void *` is used for future use)
|
||||
PtrMap<LLVMContextRef, lbModule *> modules_through_ctx;
|
||||
lbModule default_module;
|
||||
|
||||
BlockingMutex anonymous_proc_lits_mutex;
|
||||
PtrMap<Ast *, lbProcedure *> anonymous_proc_lits;
|
||||
|
||||
BlockingMutex foreign_mutex;
|
||||
@@ -185,6 +205,10 @@ struct lbGenerator {
|
||||
|
||||
std::atomic<u32> global_array_index;
|
||||
std::atomic<u32> global_generated_index;
|
||||
|
||||
lbProcedure *startup_type_info;
|
||||
lbProcedure *startup_runtime;
|
||||
lbProcedure *objc_names;
|
||||
};
|
||||
|
||||
|
||||
@@ -254,17 +278,15 @@ struct lbTargetList {
|
||||
};
|
||||
|
||||
|
||||
struct lbTupleFix {
|
||||
Slice<lbValue> values;
|
||||
};
|
||||
|
||||
enum lbProcedureFlag : u32 {
|
||||
lbProcedureFlag_WithoutMemcpyPass = 1<<0,
|
||||
lbProcedureFlag_DebugAllocaCopy = 1<<1,
|
||||
};
|
||||
|
||||
struct lbCopyElisionHint {
|
||||
lbValue ptr;
|
||||
Ast * ast;
|
||||
bool used;
|
||||
};
|
||||
|
||||
struct lbProcedure {
|
||||
u32 flags;
|
||||
u16 state_flags;
|
||||
@@ -302,6 +324,7 @@ struct lbProcedure {
|
||||
lbBlock * curr_block;
|
||||
lbTargetList * target_list;
|
||||
PtrMap<Entity *, lbValue> direct_parameters;
|
||||
bool in_multi_assignment;
|
||||
|
||||
Ast *curr_stmt;
|
||||
|
||||
@@ -310,10 +333,9 @@ struct lbProcedure {
|
||||
|
||||
LLVMMetadataRef debug_info;
|
||||
|
||||
lbCopyElisionHint copy_elision_hint;
|
||||
|
||||
PtrMap<Ast *, lbValue> selector_values;
|
||||
PtrMap<Ast *, lbAddr> selector_addr;
|
||||
PtrMap<LLVMValueRef, lbTupleFix> tuple_fix_map;
|
||||
};
|
||||
|
||||
|
||||
@@ -324,200 +346,197 @@ struct lbProcedure {
|
||||
#define LLVMBuildPtrDiff2(Builder__, Ty__, LHS__, RHS__, Name__) LLVMBuildPtrDiff(Builder__, LHS__, RHS__, Name__)
|
||||
#endif
|
||||
|
||||
bool lb_init_generator(lbGenerator *gen, Checker *c);
|
||||
gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c);
|
||||
|
||||
String lb_mangle_name(lbModule *m, Entity *e);
|
||||
String lb_get_entity_name(lbModule *m, Entity *e, String name = {});
|
||||
gb_internal String lb_mangle_name(lbModule *m, Entity *e);
|
||||
gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String name = {});
|
||||
|
||||
LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0);
|
||||
LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type);
|
||||
void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value);
|
||||
void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name);
|
||||
lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false);
|
||||
void lb_end_procedure(lbProcedure *p);
|
||||
gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0);
|
||||
gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type);
|
||||
gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value);
|
||||
gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name);
|
||||
gb_internal lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false);
|
||||
gb_internal void lb_end_procedure(lbProcedure *p);
|
||||
|
||||
|
||||
LLVMTypeRef lb_type(lbModule *m, Type *type);
|
||||
LLVMTypeRef llvm_get_element_type(LLVMTypeRef type);
|
||||
gb_internal LLVMTypeRef lb_type(lbModule *m, Type *type);
|
||||
gb_internal LLVMTypeRef llvm_get_element_type(LLVMTypeRef type);
|
||||
|
||||
lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false);
|
||||
gb_internal lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false);
|
||||
|
||||
lbValue lb_const_nil(lbModule *m, Type *type);
|
||||
lbValue lb_const_undef(lbModule *m, Type *type);
|
||||
lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local=true);
|
||||
lbValue lb_const_bool(lbModule *m, Type *type, bool value);
|
||||
lbValue lb_const_int(lbModule *m, Type *type, u64 value);
|
||||
gb_internal lbValue lb_const_nil(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_const_undef(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local=true);
|
||||
gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value);
|
||||
gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value);
|
||||
|
||||
|
||||
lbAddr lb_addr(lbValue addr);
|
||||
Type *lb_addr_type(lbAddr const &addr);
|
||||
LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val);
|
||||
void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value);
|
||||
lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr);
|
||||
lbValue lb_emit_load(lbProcedure *p, lbValue v);
|
||||
void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value);
|
||||
gb_internal lbAddr lb_addr(lbValue addr);
|
||||
gb_internal Type *lb_addr_type(lbAddr const &addr);
|
||||
gb_internal LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val);
|
||||
gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value);
|
||||
gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr);
|
||||
gb_internal lbValue lb_emit_load(lbProcedure *p, lbValue v);
|
||||
gb_internal void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value);
|
||||
|
||||
|
||||
void lb_build_stmt(lbProcedure *p, Ast *stmt);
|
||||
lbValue lb_build_expr(lbProcedure *p, Ast *expr);
|
||||
lbAddr lb_build_addr(lbProcedure *p, Ast *expr);
|
||||
void lb_build_stmt_list(lbProcedure *p, Array<Ast *> const &stmts);
|
||||
gb_internal void lb_build_stmt(lbProcedure *p, Ast *stmt);
|
||||
gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr);
|
||||
gb_internal lbAddr lb_build_addr(lbProcedure *p, Ast *expr);
|
||||
gb_internal void lb_build_stmt_list(lbProcedure *p, Array<Ast *> const &stmts);
|
||||
|
||||
lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index);
|
||||
lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index);
|
||||
lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index);
|
||||
lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index);
|
||||
lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index);
|
||||
lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index);
|
||||
lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index);
|
||||
lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel);
|
||||
lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel);
|
||||
gb_internal lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index);
|
||||
gb_internal lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index);
|
||||
gb_internal lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index);
|
||||
gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index);
|
||||
gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index);
|
||||
gb_internal lbValue lb_emit_tuple_ev(lbProcedure *p, lbValue value, i32 index);
|
||||
gb_internal lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index);
|
||||
gb_internal lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index);
|
||||
gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel);
|
||||
gb_internal lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel);
|
||||
|
||||
lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column);
|
||||
lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column);
|
||||
lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column);
|
||||
gb_internal lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column);
|
||||
gb_internal lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column);
|
||||
gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column);
|
||||
|
||||
|
||||
lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type);
|
||||
lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type);
|
||||
void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block);
|
||||
lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
|
||||
lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right);
|
||||
lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false);
|
||||
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
|
||||
lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x);
|
||||
gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type);
|
||||
gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type);
|
||||
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block);
|
||||
gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
|
||||
gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right);
|
||||
gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none);
|
||||
gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
|
||||
gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x);
|
||||
|
||||
void lb_emit_jump(lbProcedure *p, lbBlock *target_block);
|
||||
void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *false_block);
|
||||
void lb_start_block(lbProcedure *p, lbBlock *b);
|
||||
gb_internal void lb_emit_jump(lbProcedure *p, lbBlock *target_block);
|
||||
gb_internal void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *false_block);
|
||||
gb_internal void lb_start_block(lbProcedure *p, lbBlock *b);
|
||||
|
||||
lbValue lb_build_call_expr(lbProcedure *p, Ast *expr);
|
||||
gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr);
|
||||
|
||||
|
||||
lbAddr lb_find_or_generate_context_ptr(lbProcedure *p);
|
||||
lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx);
|
||||
lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p);
|
||||
gb_internal lbAddr lb_find_or_generate_context_ptr(lbProcedure *p);
|
||||
gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx);
|
||||
gb_internal lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p);
|
||||
|
||||
|
||||
lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}, Entity **entity_=nullptr);
|
||||
lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_init=true, i32 param_index=0, bool force_no_init=false);
|
||||
gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}, Entity **entity_=nullptr);
|
||||
gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_init=true, bool force_no_init=false);
|
||||
|
||||
void lb_add_foreign_library_path(lbModule *m, Entity *e);
|
||||
gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e);
|
||||
|
||||
lbValue lb_typeid(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_typeid(lbModule *m, Type *type);
|
||||
|
||||
lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value);
|
||||
lbValue lb_address_from_load(lbProcedure *p, lbValue value);
|
||||
void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt);
|
||||
lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init);
|
||||
gb_internal lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value);
|
||||
gb_internal lbValue lb_address_from_load(lbProcedure *p, lbValue value);
|
||||
gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt);
|
||||
gb_internal lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init);
|
||||
|
||||
lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args);
|
||||
gb_internal lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args);
|
||||
|
||||
|
||||
lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index);
|
||||
lbValue lb_string_elem(lbProcedure *p, lbValue string);
|
||||
lbValue lb_string_len(lbProcedure *p, lbValue string);
|
||||
lbValue lb_cstring_len(lbProcedure *p, lbValue value);
|
||||
lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr);
|
||||
lbValue lb_slice_elem(lbProcedure *p, lbValue slice);
|
||||
lbValue lb_slice_len(lbProcedure *p, lbValue slice);
|
||||
lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da);
|
||||
lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da);
|
||||
lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da);
|
||||
lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da);
|
||||
lbValue lb_map_len(lbProcedure *p, lbValue value);
|
||||
lbValue lb_map_cap(lbProcedure *p, lbValue value);
|
||||
lbValue lb_soa_struct_len(lbProcedure *p, lbValue value);
|
||||
void lb_emit_increment(lbProcedure *p, lbValue addr);
|
||||
lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y);
|
||||
gb_internal lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index);
|
||||
gb_internal lbValue lb_string_elem(lbProcedure *p, lbValue string);
|
||||
gb_internal lbValue lb_string_len(lbProcedure *p, lbValue string);
|
||||
gb_internal lbValue lb_cstring_len(lbProcedure *p, lbValue value);
|
||||
gb_internal lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr);
|
||||
gb_internal lbValue lb_slice_elem(lbProcedure *p, lbValue slice);
|
||||
gb_internal lbValue lb_slice_len(lbProcedure *p, lbValue slice);
|
||||
gb_internal lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da);
|
||||
gb_internal lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da);
|
||||
gb_internal lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da);
|
||||
gb_internal lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da);
|
||||
gb_internal lbValue lb_map_len(lbProcedure *p, lbValue value);
|
||||
gb_internal lbValue lb_map_cap(lbProcedure *p, lbValue value);
|
||||
gb_internal lbValue lb_soa_struct_len(lbProcedure *p, lbValue value);
|
||||
gb_internal void lb_emit_increment(lbProcedure *p, lbValue addr);
|
||||
gb_internal lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y);
|
||||
|
||||
lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t);
|
||||
gb_internal lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t);
|
||||
|
||||
void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len);
|
||||
gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len);
|
||||
|
||||
lbValue lb_type_info(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_type_info(lbModule *m, Type *type);
|
||||
|
||||
lbValue lb_find_or_add_entity_string(lbModule *m, String const &str);
|
||||
lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent = nullptr);
|
||||
gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str);
|
||||
gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent = nullptr);
|
||||
|
||||
bool lb_is_const(lbValue value);
|
||||
bool lb_is_const_or_global(lbValue value);
|
||||
bool lb_is_const_nil(lbValue value);
|
||||
String lb_get_const_string(lbModule *m, lbValue value);
|
||||
gb_internal bool lb_is_const(lbValue value);
|
||||
gb_internal bool lb_is_const_or_global(lbValue value);
|
||||
gb_internal bool lb_is_const_nil(lbValue value);
|
||||
gb_internal String lb_get_const_string(lbModule *m, lbValue value);
|
||||
|
||||
lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
|
||||
lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
|
||||
lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
|
||||
lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type);
|
||||
lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type);
|
||||
gb_internal lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
|
||||
gb_internal lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
|
||||
gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
|
||||
gb_internal lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type);
|
||||
|
||||
lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key);
|
||||
void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ptr, Type *map_type, lbValue const &map_key, lbValue const &map_value, Ast *node);
|
||||
lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos);
|
||||
gb_internal lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key);
|
||||
gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ptr, Type *map_type, lbValue const &map_key, lbValue const &map_value, Ast *node);
|
||||
gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos);
|
||||
|
||||
lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
|
||||
lbValue lb_find_value_from_entity(lbModule *m, Entity *e);
|
||||
gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
|
||||
gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e);
|
||||
|
||||
void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value);
|
||||
lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value);
|
||||
lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos);
|
||||
gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value);
|
||||
gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value);
|
||||
gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos);
|
||||
|
||||
lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos);
|
||||
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos);
|
||||
|
||||
lbValue lb_equal_proc_for_type(lbModule *m, Type *type);
|
||||
lbValue lb_hasher_proc_for_type(lbModule *m, Type *type);
|
||||
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
|
||||
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type);
|
||||
gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
|
||||
|
||||
LLVMMetadataRef lb_debug_type(lbModule *m, Type *type);
|
||||
gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type);
|
||||
|
||||
lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type);
|
||||
lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type);
|
||||
lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type);
|
||||
lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type);
|
||||
lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type);
|
||||
gb_internal lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type);
|
||||
gb_internal lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type);
|
||||
gb_internal lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type);
|
||||
gb_internal lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type);
|
||||
gb_internal lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type);
|
||||
|
||||
lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x);
|
||||
gb_internal lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x);
|
||||
|
||||
void lb_mem_zero_addr(lbProcedure *p, LLVMValueRef ptr, Type *type);
|
||||
gb_internal void lb_mem_zero_addr(lbProcedure *p, LLVMValueRef ptr, Type *type);
|
||||
|
||||
void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e);
|
||||
lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type);
|
||||
lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block);
|
||||
gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e);
|
||||
gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type);
|
||||
gb_internal lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block);
|
||||
|
||||
LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_);
|
||||
LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
|
||||
void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name);
|
||||
gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_);
|
||||
gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
|
||||
gb_internal void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name);
|
||||
|
||||
lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t);
|
||||
bool lb_is_expr_untyped_const(Ast *expr);
|
||||
gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t);
|
||||
gb_internal bool lb_is_expr_untyped_const(Ast *expr);
|
||||
|
||||
LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const *name = "");
|
||||
gb_internal LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const *name = "");
|
||||
|
||||
void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment);
|
||||
gb_internal void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment);
|
||||
|
||||
void lb_emit_init_context(lbProcedure *p, lbAddr addr);
|
||||
|
||||
lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, Ast *ast);
|
||||
void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint);
|
||||
lbValue lb_consume_copy_elision_hint(lbProcedure *p);
|
||||
gb_internal void lb_emit_init_context(lbProcedure *p, lbAddr addr);
|
||||
|
||||
|
||||
lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t);
|
||||
LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align);
|
||||
gb_internal lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t);
|
||||
gb_internal LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align);
|
||||
|
||||
LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask);
|
||||
gb_internal LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask);
|
||||
|
||||
LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count);
|
||||
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
|
||||
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
|
||||
LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
|
||||
gb_internal LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count);
|
||||
gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
|
||||
gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
|
||||
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
|
||||
|
||||
i64 lb_max_zero_init_size(void) {
|
||||
gb_internal gb_inline i64 lb_max_zero_init_size(void) {
|
||||
return cast(i64)(4*build_context.word_size);
|
||||
}
|
||||
|
||||
LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);
|
||||
LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
|
||||
gb_internal LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);
|
||||
gb_internal LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
|
||||
|
||||
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
|
||||
#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
|
||||
@@ -637,7 +656,7 @@ enum : LLVMAttributeIndex {
|
||||
};
|
||||
|
||||
|
||||
char const *llvm_linkage_strings[] = {
|
||||
gb_global char const *llvm_linkage_strings[] = {
|
||||
"external linkage",
|
||||
"available externally linkage",
|
||||
"link once any linkage",
|
||||
|
||||
+30
-30
@@ -1,4 +1,4 @@
|
||||
bool lb_is_const(lbValue value) {
|
||||
gb_internal bool lb_is_const(lbValue value) {
|
||||
LLVMValueRef v = value.value;
|
||||
if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) {
|
||||
// TODO(bill): Is this correct behaviour?
|
||||
@@ -10,7 +10,7 @@ bool lb_is_const(lbValue value) {
|
||||
return false;
|
||||
}
|
||||
|
||||
bool lb_is_const_or_global(lbValue value) {
|
||||
gb_internal bool lb_is_const_or_global(lbValue value) {
|
||||
if (lb_is_const(value)) {
|
||||
return true;
|
||||
}
|
||||
@@ -29,7 +29,7 @@ bool lb_is_const_or_global(lbValue value) {
|
||||
}
|
||||
|
||||
|
||||
bool lb_is_elem_const(Ast *elem, Type *elem_type) {
|
||||
gb_internal bool lb_is_elem_const(Ast *elem, Type *elem_type) {
|
||||
if (!elem_type_can_be_constant(elem_type)) {
|
||||
return false;
|
||||
}
|
||||
@@ -42,7 +42,7 @@ bool lb_is_elem_const(Ast *elem, Type *elem_type) {
|
||||
}
|
||||
|
||||
|
||||
bool lb_is_const_nil(lbValue value) {
|
||||
gb_internal bool lb_is_const_nil(lbValue value) {
|
||||
LLVMValueRef v = value.value;
|
||||
if (LLVMIsConstant(v)) {
|
||||
if (LLVMIsAConstantAggregateZero(v)) {
|
||||
@@ -55,7 +55,7 @@ bool lb_is_const_nil(lbValue value) {
|
||||
}
|
||||
|
||||
|
||||
bool lb_is_expr_constant_zero(Ast *expr) {
|
||||
gb_internal bool lb_is_expr_constant_zero(Ast *expr) {
|
||||
GB_ASSERT(expr != nullptr);
|
||||
auto v = exact_value_to_integer(expr->tav.value);
|
||||
if (v.kind == ExactValue_Integer) {
|
||||
@@ -64,7 +64,7 @@ bool lb_is_expr_constant_zero(Ast *expr) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String lb_get_const_string(lbModule *m, lbValue value) {
|
||||
gb_internal String lb_get_const_string(lbModule *m, lbValue value) {
|
||||
GB_ASSERT(lb_is_const(value));
|
||||
GB_ASSERT(LLVMIsConstant(value.value));
|
||||
|
||||
@@ -92,7 +92,7 @@ String lb_get_const_string(lbModule *m, lbValue value) {
|
||||
}
|
||||
|
||||
|
||||
LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
|
||||
gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
|
||||
LLVMTypeRef src = LLVMTypeOf(val);
|
||||
if (src == dst) {
|
||||
return val;
|
||||
@@ -116,7 +116,7 @@ LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
|
||||
gb_internal lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
|
||||
GB_ASSERT(is_type_internally_pointer_like(value.type));
|
||||
GB_ASSERT(is_type_internally_pointer_like(t));
|
||||
GB_ASSERT(lb_is_const(value));
|
||||
@@ -127,7 +127,7 @@ lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
|
||||
return res;
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_) {
|
||||
gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_) {
|
||||
LLVMTypeRef struct_type = lb_type(m, t);
|
||||
GB_ASSERT(LLVMGetTypeKind(struct_type) == LLVMStructTypeKind);
|
||||
|
||||
@@ -157,7 +157,7 @@ LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values,
|
||||
return llvm_const_named_struct_internal(struct_type, values_with_padding, values_with_padding_count);
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
|
||||
gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
|
||||
unsigned value_count = cast(unsigned)value_count_;
|
||||
unsigned elem_count = LLVMCountStructElementTypes(t);
|
||||
GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count);
|
||||
@@ -168,7 +168,7 @@ LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *value
|
||||
return LLVMConstNamedStruct(t, values, value_count);
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
|
||||
gb_internal LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
|
||||
unsigned value_count = cast(unsigned)value_count_;
|
||||
for (unsigned i = 0; i < value_count; i++) {
|
||||
values[i] = llvm_const_cast(values[i], elem_type);
|
||||
@@ -176,7 +176,7 @@ LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize
|
||||
return LLVMConstArray(elem_type, values, value_count);
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) {
|
||||
gb_internal LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) {
|
||||
GB_ASSERT(is_type_pointer(data.type) || is_type_multi_pointer(data.type));
|
||||
GB_ASSERT(are_types_identical(len.type, t_int));
|
||||
LLVMValueRef vals[2] = {
|
||||
@@ -187,38 +187,38 @@ LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_const_nil(lbModule *m, Type *type) {
|
||||
gb_internal lbValue lb_const_nil(lbModule *m, Type *type) {
|
||||
LLVMValueRef v = LLVMConstNull(lb_type(m, type));
|
||||
return lbValue{v, type};
|
||||
}
|
||||
|
||||
lbValue lb_const_undef(lbModule *m, Type *type) {
|
||||
gb_internal lbValue lb_const_undef(lbModule *m, Type *type) {
|
||||
LLVMValueRef v = LLVMGetUndef(lb_type(m, type));
|
||||
return lbValue{v, type};
|
||||
}
|
||||
|
||||
|
||||
|
||||
lbValue lb_const_int(lbModule *m, Type *type, u64 value) {
|
||||
gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMConstInt(lb_type(m, type), cast(unsigned long long)value, !is_type_unsigned(type));
|
||||
res.type = type;
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_const_string(lbModule *m, String const &value) {
|
||||
gb_internal lbValue lb_const_string(lbModule *m, String const &value) {
|
||||
return lb_const_value(m, t_string, exact_value_string(value));
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_const_bool(lbModule *m, Type *type, bool value) {
|
||||
gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMConstInt(lb_type(m, type), value, false);
|
||||
res.type = type;
|
||||
return res;
|
||||
}
|
||||
|
||||
LLVMValueRef lb_const_f16(lbModule *m, f32 f, Type *type=t_f16) {
|
||||
gb_internal LLVMValueRef lb_const_f16(lbModule *m, f32 f, Type *type=t_f16) {
|
||||
GB_ASSERT(type_size_of(type) == 2);
|
||||
|
||||
u16 u = f32_to_f16(f);
|
||||
@@ -229,7 +229,7 @@ LLVMValueRef lb_const_f16(lbModule *m, f32 f, Type *type=t_f16) {
|
||||
return LLVMConstBitCast(i, lb_type(m, type));
|
||||
}
|
||||
|
||||
LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) {
|
||||
gb_internal LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) {
|
||||
GB_ASSERT(type_size_of(type) == 4);
|
||||
u32 u = bit_cast<u32>(f);
|
||||
if (is_type_different_to_arch_endianness(type)) {
|
||||
@@ -241,7 +241,7 @@ LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) {
|
||||
|
||||
|
||||
|
||||
bool lb_is_expr_untyped_const(Ast *expr) {
|
||||
gb_internal bool lb_is_expr_untyped_const(Ast *expr) {
|
||||
auto const &tv = type_and_value_of_expr(expr);
|
||||
if (is_type_untyped(tv.type)) {
|
||||
return tv.value.kind != ExactValue_Invalid;
|
||||
@@ -250,13 +250,13 @@ bool lb_is_expr_untyped_const(Ast *expr) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t) {
|
||||
gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t) {
|
||||
GB_ASSERT(is_type_typed(t));
|
||||
auto const &tv = type_and_value_of_expr(expr);
|
||||
return lb_const_value(m, t, tv.value);
|
||||
}
|
||||
|
||||
lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos) {
|
||||
gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
LLVMValueRef fields[4] = {};
|
||||
@@ -271,7 +271,7 @@ lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedu
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_emit_source_code_location_const(lbProcedure *p, Ast *node) {
|
||||
gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, Ast *node) {
|
||||
String proc_name = {};
|
||||
if (p->entity) {
|
||||
proc_name = p->entity->token.string;
|
||||
@@ -284,7 +284,7 @@ lbValue lb_emit_source_code_location_const(lbProcedure *p, Ast *node) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const &procedure, TokenPos const &pos) {
|
||||
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const &procedure, TokenPos const &pos) {
|
||||
lbValue loc = lb_emit_source_code_location_const(p, procedure, pos);
|
||||
lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
|
||||
lb_make_global_private_const(addr);
|
||||
@@ -292,24 +292,24 @@ lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, Ast *node) {
|
||||
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, Ast *node) {
|
||||
lbValue loc = lb_emit_source_code_location_const(p, node);
|
||||
lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
|
||||
lb_make_global_private_const(addr);
|
||||
return addr.addr;
|
||||
}
|
||||
|
||||
lbValue lb_emit_source_code_location_as_global(lbProcedure *p, String const &procedure, TokenPos const &pos) {
|
||||
gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, String const &procedure, TokenPos const &pos) {
|
||||
return lb_emit_load(p, lb_emit_source_code_location_as_global_ptr(p, procedure, pos));
|
||||
}
|
||||
|
||||
lbValue lb_emit_source_code_location_as_global(lbProcedure *p, Ast *node) {
|
||||
gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, Ast *node) {
|
||||
return lb_emit_load(p, lb_emit_source_code_location_as_global_ptr(p, node));
|
||||
}
|
||||
|
||||
|
||||
|
||||
LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, bool allow_local) {
|
||||
gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, bool allow_local) {
|
||||
bool is_local = allow_local && m->curr_procedure != nullptr;
|
||||
bool is_const = true;
|
||||
if (is_local) {
|
||||
@@ -341,7 +341,7 @@ LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_
|
||||
return llvm_const_array(lb_type(m, elem_type), values, cast(unsigned int)count);
|
||||
}
|
||||
|
||||
LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) {
|
||||
gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) {
|
||||
if (big_int_is_zero(a)) {
|
||||
return LLVMConstNull(lb_type(m, original_type));
|
||||
}
|
||||
@@ -387,7 +387,7 @@ LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) {
|
||||
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) {
|
||||
LLVMContextRef ctx = m->ctx;
|
||||
|
||||
type = default_type(type);
|
||||
|
||||
+33
-34
@@ -1,27 +1,25 @@
|
||||
LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) {
|
||||
gb_internal LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) {
|
||||
if (key == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
mutex_lock(&m->debug_values_mutex);
|
||||
auto found = map_get(&m->debug_values, key);
|
||||
mutex_unlock(&m->debug_values_mutex);
|
||||
if (found) {
|
||||
return *found;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef value) {
|
||||
gb_internal void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef value) {
|
||||
if (key != nullptr) {
|
||||
mutex_lock(&m->debug_values_mutex);
|
||||
map_set(&m->debug_values, key, value);
|
||||
mutex_unlock(&m->debug_values_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
LLVMMetadataRef lb_get_llvm_file_metadata_from_node(lbModule *m, Ast *node) {
|
||||
if (node == nullptr) {
|
||||
return nullptr;
|
||||
}
|
||||
return lb_get_llvm_metadata(m, node->file());
|
||||
}
|
||||
|
||||
LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) {
|
||||
gb_internal LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) {
|
||||
GB_ASSERT_MSG(p->debug_info != nullptr, "missing debug information for %.*s", LIT(p->name));
|
||||
|
||||
for (isize i = p->scope_stack.count-1; i >= 0; i--) {
|
||||
@@ -34,21 +32,21 @@ LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) {
|
||||
return p->debug_info;
|
||||
}
|
||||
|
||||
LLVMMetadataRef lb_debug_location_from_token_pos(lbProcedure *p, TokenPos pos) {
|
||||
gb_internal LLVMMetadataRef lb_debug_location_from_token_pos(lbProcedure *p, TokenPos pos) {
|
||||
LLVMMetadataRef scope = lb_get_current_debug_scope(p);
|
||||
GB_ASSERT_MSG(scope != nullptr, "%.*s", LIT(p->name));
|
||||
return LLVMDIBuilderCreateDebugLocation(p->module->ctx, cast(unsigned)pos.line, cast(unsigned)pos.column, scope, nullptr);
|
||||
}
|
||||
LLVMMetadataRef lb_debug_location_from_ast(lbProcedure *p, Ast *node) {
|
||||
gb_internal LLVMMetadataRef lb_debug_location_from_ast(lbProcedure *p, Ast *node) {
|
||||
GB_ASSERT(node != nullptr);
|
||||
return lb_debug_location_from_token_pos(p, ast_token(node).pos);
|
||||
}
|
||||
LLVMMetadataRef lb_debug_end_location_from_ast(lbProcedure *p, Ast *node) {
|
||||
gb_internal LLVMMetadataRef lb_debug_end_location_from_ast(lbProcedure *p, Ast *node) {
|
||||
GB_ASSERT(node != nullptr);
|
||||
return lb_debug_location_from_token_pos(p, ast_end_token(node).pos);
|
||||
}
|
||||
|
||||
LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
|
||||
gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
|
||||
i64 size = type_size_of(type); // Check size
|
||||
gb_unused(size);
|
||||
|
||||
@@ -93,7 +91,7 @@ LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
|
||||
return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters, parameter_count, flags);
|
||||
}
|
||||
|
||||
LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *type, u64 offset_in_bits) {
|
||||
gb_internal LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *type, u64 offset_in_bits) {
|
||||
unsigned field_line = 1;
|
||||
LLVMDIFlags field_flags = LLVMDIFlagZero;
|
||||
|
||||
@@ -107,7 +105,7 @@ LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *typ
|
||||
field_flags, lb_debug_type(m, type)
|
||||
);
|
||||
}
|
||||
LLVMMetadataRef lb_debug_basic_struct(lbModule *m, String const &name, u64 size_in_bits, u32 align_in_bits, LLVMMetadataRef *elements, unsigned element_count) {
|
||||
gb_internal LLVMMetadataRef lb_debug_basic_struct(lbModule *m, String const &name, u64 size_in_bits, u32 align_in_bits, LLVMMetadataRef *elements, unsigned element_count) {
|
||||
AstPackage *pkg = m->info->runtime_package;
|
||||
GB_ASSERT(pkg->files.count != 0);
|
||||
LLVMMetadataRef file = lb_get_llvm_metadata(m, pkg->files[0]);
|
||||
@@ -117,7 +115,7 @@ LLVMMetadataRef lb_debug_basic_struct(lbModule *m, String const &name, u64 size_
|
||||
}
|
||||
|
||||
|
||||
LLVMMetadataRef lb_debug_type_basic_type(lbModule *m, String const &name, u64 size_in_bits, LLVMDWARFTypeEncoding encoding, LLVMDIFlags flags = LLVMDIFlagZero) {
|
||||
gb_internal LLVMMetadataRef lb_debug_type_basic_type(lbModule *m, String const &name, u64 size_in_bits, LLVMDWARFTypeEncoding encoding, LLVMDIFlags flags = LLVMDIFlagZero) {
|
||||
LLVMMetadataRef basic_type = LLVMDIBuilderCreateBasicType(m->debug_builder, cast(char const *)name.text, name.len, size_in_bits, encoding, flags);
|
||||
#if 1
|
||||
LLVMMetadataRef final_decl = LLVMDIBuilderCreateTypedef(m->debug_builder, basic_type, cast(char const *)name.text, name.len, nullptr, 0, nullptr, cast(u32)size_in_bits);
|
||||
@@ -127,7 +125,7 @@ LLVMMetadataRef lb_debug_type_basic_type(lbModule *m, String const &name, u64 si
|
||||
#endif
|
||||
}
|
||||
|
||||
LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
i64 size = type_size_of(type); // Check size
|
||||
gb_unused(size);
|
||||
|
||||
@@ -474,7 +472,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope) {
|
||||
gb_internal LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope) {
|
||||
LLVMMetadataRef found = nullptr;
|
||||
for (;;) {
|
||||
if (scope == nullptr) {
|
||||
@@ -496,13 +494,15 @@ LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope) {
|
||||
}
|
||||
}
|
||||
|
||||
LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
|
||||
gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
|
||||
GB_ASSERT(type != nullptr);
|
||||
LLVMMetadataRef found = lb_get_llvm_metadata(m, type);
|
||||
if (found != nullptr) {
|
||||
return found;
|
||||
}
|
||||
|
||||
MUTEX_GUARD(&m->debug_values_mutex);
|
||||
|
||||
if (type->kind == Type_Named) {
|
||||
LLVMMetadataRef file = nullptr;
|
||||
unsigned line = 0;
|
||||
@@ -615,11 +615,13 @@ LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
|
||||
return dt;
|
||||
}
|
||||
|
||||
void lb_debug_complete_types(lbModule *m) {
|
||||
gb_internal void lb_debug_complete_types(lbModule *m) {
|
||||
/* unsigned const word_size = cast(unsigned)build_context.word_size; */
|
||||
unsigned const word_bits = cast(unsigned)(8*build_context.word_size);
|
||||
|
||||
for_array(debug_incomplete_type_index, m->debug_incomplete_types) {
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
|
||||
auto const &idt = m->debug_incomplete_types[debug_incomplete_type_index];
|
||||
GB_ASSERT(idt.type != nullptr);
|
||||
GB_ASSERT(idt.metadata != nullptr);
|
||||
@@ -962,7 +964,7 @@ void lb_debug_complete_types(lbModule *m) {
|
||||
|
||||
|
||||
|
||||
void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token) {
|
||||
gb_internal void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token) {
|
||||
if (p->debug_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -1024,7 +1026,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
|
||||
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
|
||||
}
|
||||
|
||||
void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block, lbArgKind arg_kind) {
|
||||
gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block, lbArgKind arg_kind) {
|
||||
if (p->debug_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -1097,7 +1099,7 @@ void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
|
||||
}
|
||||
|
||||
|
||||
void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) {
|
||||
gb_internal void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) {
|
||||
if (!p->debug_info || !p->body) {
|
||||
return;
|
||||
}
|
||||
@@ -1125,17 +1127,17 @@ void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) {
|
||||
}
|
||||
|
||||
|
||||
String debug_info_mangle_constant_name(Entity *e, bool *did_allocate_) {
|
||||
gb_internal String debug_info_mangle_constant_name(Entity *e, gbAllocator const &allocator, bool *did_allocate_) {
|
||||
String name = e->token.string;
|
||||
if (e->pkg && e->pkg->name.len > 0) {
|
||||
// NOTE(bill): C++ NONSENSE FOR DEBUG SHITE!
|
||||
name = concatenate3_strings(heap_allocator(), e->pkg->name, str_lit("::"), name);
|
||||
name = concatenate3_strings(allocator, e->pkg->name, str_lit("::"), name);
|
||||
if (did_allocate_) *did_allocate_ = true;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
void add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMetadataRef dtype, LLVMMetadataRef expr) {
|
||||
gb_internal void add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMetadataRef dtype, LLVMMetadataRef expr) {
|
||||
LLVMMetadataRef scope = nullptr;
|
||||
LLVMMetadataRef file = nullptr;
|
||||
unsigned line = 0;
|
||||
@@ -1151,14 +1153,11 @@ void add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMe
|
||||
expr, decl, 8/*AlignInBits*/);
|
||||
}
|
||||
|
||||
void add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLVMMetadataRef dtype, i64 v) {
|
||||
gb_internal void add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLVMMetadataRef dtype, i64 v) {
|
||||
LLVMMetadataRef expr = LLVMDIBuilderCreateConstantValueExpression(m->debug_builder, v);
|
||||
|
||||
bool did_allocate = false;
|
||||
String name = debug_info_mangle_constant_name(e, &did_allocate);
|
||||
defer (if (did_allocate) {
|
||||
gb_free(heap_allocator(), name.text);
|
||||
});
|
||||
TEMPORARY_ALLOCATOR_GUARD();
|
||||
String name = debug_info_mangle_constant_name(e, temporary_allocator(), nullptr);
|
||||
|
||||
add_debug_info_global_variable_expr(m, name, dtype, expr);
|
||||
if ((e->pkg && e->pkg->kind == Package_Init) ||
|
||||
@@ -1167,7 +1166,7 @@ void add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLV
|
||||
}
|
||||
}
|
||||
|
||||
void add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e) {
|
||||
gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e) {
|
||||
if (e == nullptr || e->kind != Entity_Constant) {
|
||||
return;
|
||||
}
|
||||
@@ -1176,7 +1175,7 @@ void add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e)
|
||||
}
|
||||
lbModule *m = &gen->default_module;
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
m = lb_pkg_module(gen, e->pkg);
|
||||
m = lb_module_of_entity(gen, e);
|
||||
}
|
||||
|
||||
if (is_type_integer(e->type)) {
|
||||
|
||||
+62
-60
@@ -1,6 +1,6 @@
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
|
||||
gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
|
||||
|
||||
lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
|
||||
gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs");
|
||||
@@ -61,8 +61,7 @@ lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast
|
||||
GB_ASSERT(incoming_values.count > 0);
|
||||
|
||||
LLVMTypeRef phi_type = nullptr;
|
||||
for_array(i, incoming_values) {
|
||||
LLVMValueRef incoming_value = incoming_values[i];
|
||||
for (LLVMValueRef incoming_value : incoming_values) {
|
||||
if (!LLVMIsConstant(incoming_value)) {
|
||||
phi_type = LLVMTypeOf(incoming_value);
|
||||
break;
|
||||
@@ -113,7 +112,7 @@ lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) {
|
||||
gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) {
|
||||
switch (op) {
|
||||
case Token_Add:
|
||||
return x;
|
||||
@@ -134,7 +133,7 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
|
||||
Type *elem_type = base_array_type(type);
|
||||
|
||||
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
|
||||
lbAddr res_addr = lb_add_local(p, type, nullptr, false, 0, true);
|
||||
lbAddr res_addr = lb_add_local(p, type, nullptr, false, true);
|
||||
lbValue res = lb_addr_get_ptr(p, res_addr);
|
||||
|
||||
bool inline_array_arith = lb_can_try_to_inline_array_arith(type);
|
||||
@@ -283,7 +282,7 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
|
||||
return res;
|
||||
}
|
||||
|
||||
bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, lbValue *res_) {
|
||||
gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, lbValue *res_) {
|
||||
GB_ASSERT(is_type_array_like(type));
|
||||
Type *elem_type = base_array_type(type);
|
||||
|
||||
@@ -418,7 +417,7 @@ bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbVal
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
|
||||
gb_internal lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
|
||||
GB_ASSERT(is_type_array_like(lhs.type) || is_type_array_like(rhs.type));
|
||||
|
||||
lhs = lb_emit_conv(p, lhs, type);
|
||||
@@ -490,7 +489,7 @@ lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue r
|
||||
}
|
||||
}
|
||||
|
||||
bool lb_is_matrix_simdable(Type *t) {
|
||||
gb_internal bool lb_is_matrix_simdable(Type *t) {
|
||||
Type *mt = base_type(t);
|
||||
GB_ASSERT(mt->kind == Type_Matrix);
|
||||
|
||||
@@ -510,6 +509,11 @@ bool lb_is_matrix_simdable(Type *t) {
|
||||
case TargetArch_arm64:
|
||||
break;
|
||||
}
|
||||
|
||||
if (type_align_of(t) < 16) {
|
||||
// it's not aligned well enough to use the vector instructions
|
||||
return false;
|
||||
}
|
||||
|
||||
if (elem->kind == Type_Basic) {
|
||||
switch (elem->Basic.kind) {
|
||||
@@ -534,7 +538,7 @@ bool lb_is_matrix_simdable(Type *t) {
|
||||
}
|
||||
|
||||
|
||||
LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
|
||||
gb_internal LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
|
||||
Type *mt = base_type(matrix.type);
|
||||
GB_ASSERT(mt->kind == Type_Matrix);
|
||||
LLVMTypeRef elem_type = lb_type(p->module, mt->Matrix.elem);
|
||||
@@ -554,7 +558,7 @@ LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
|
||||
#endif
|
||||
}
|
||||
|
||||
LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) {
|
||||
gb_internal LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) {
|
||||
mt = base_type(mt);
|
||||
GB_ASSERT(mt->kind == Type_Matrix);
|
||||
|
||||
@@ -574,7 +578,7 @@ LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) {
|
||||
return mask;
|
||||
}
|
||||
|
||||
LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) {
|
||||
gb_internal LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) {
|
||||
LLVMValueRef vector = lb_matrix_to_vector(p, m);
|
||||
|
||||
Type *mt = base_type(m.type);
|
||||
@@ -592,7 +596,7 @@ LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
|
||||
gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
|
||||
if (is_type_array(m.type)) {
|
||||
i32 rank = type_math_rank(m.type);
|
||||
if (rank == 2) {
|
||||
@@ -669,7 +673,7 @@ lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
|
||||
return lb_addr_load(p, res);
|
||||
}
|
||||
|
||||
lbValue lb_matrix_cast_vector_to_type(lbProcedure *p, LLVMValueRef vector, Type *type) {
|
||||
gb_internal lbValue lb_matrix_cast_vector_to_type(lbProcedure *p, LLVMValueRef vector, Type *type) {
|
||||
lbAddr res = lb_add_local_generated(p, type, true);
|
||||
LLVMValueRef res_ptr = res.addr.value;
|
||||
unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(LLVMTypeOf(vector)));
|
||||
@@ -681,7 +685,7 @@ lbValue lb_matrix_cast_vector_to_type(lbProcedure *p, LLVMValueRef vector, Type
|
||||
return lb_addr_load(p, res);
|
||||
}
|
||||
|
||||
lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type) {
|
||||
gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type) {
|
||||
if (is_type_array(m.type)) {
|
||||
// no-op
|
||||
m.type = type;
|
||||
@@ -710,7 +714,7 @@ lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type) {
|
||||
gb_internal lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type) {
|
||||
Type *mt = base_type(type);
|
||||
Type *at = base_type(a.type);
|
||||
Type *bt = base_type(b.type);
|
||||
@@ -741,7 +745,7 @@ lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type)
|
||||
|
||||
}
|
||||
|
||||
lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
|
||||
gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
|
||||
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
|
||||
|
||||
Type *xt = base_type(lhs.type);
|
||||
@@ -828,7 +832,7 @@ lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type)
|
||||
}
|
||||
}
|
||||
|
||||
lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
|
||||
gb_internal lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
|
||||
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
|
||||
|
||||
Type *mt = base_type(lhs.type);
|
||||
@@ -897,7 +901,7 @@ lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type
|
||||
return lb_addr_load(p, res);
|
||||
}
|
||||
|
||||
lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
|
||||
gb_internal lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
|
||||
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
|
||||
|
||||
Type *mt = base_type(rhs.type);
|
||||
@@ -984,7 +988,7 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise) {
|
||||
gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise) {
|
||||
GB_ASSERT(is_type_matrix(lhs.type) || is_type_matrix(rhs.type));
|
||||
|
||||
if (op == Token_Mul && !component_wise) {
|
||||
@@ -1056,7 +1060,7 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
|
||||
gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
|
||||
if (is_type_array_like(lhs.type) || is_type_array_like(rhs.type)) {
|
||||
return lb_emit_arith_array(p, op, lhs, rhs, type);
|
||||
} else if (is_type_matrix(lhs.type) || is_type_matrix(rhs.type)) {
|
||||
@@ -1164,6 +1168,9 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty
|
||||
}
|
||||
}
|
||||
|
||||
lhs = lb_emit_conv(p, lhs, type);
|
||||
rhs = lb_emit_conv(p, rhs, type);
|
||||
|
||||
if (is_type_integer(type) && is_type_different_to_arch_endianness(type)) {
|
||||
switch (op) {
|
||||
case Token_AndNot:
|
||||
@@ -1192,10 +1199,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty
|
||||
return lb_emit_byte_swap(p, res, type);
|
||||
}
|
||||
|
||||
handle_op:
|
||||
lhs = lb_emit_conv(p, lhs, type);
|
||||
rhs = lb_emit_conv(p, rhs, type);
|
||||
|
||||
handle_op:;
|
||||
lbValue res = {};
|
||||
res.type = type;
|
||||
|
||||
@@ -1325,7 +1329,7 @@ handle_op:
|
||||
return {};
|
||||
}
|
||||
|
||||
lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
||||
ast_node(be, BinaryExpr, expr);
|
||||
|
||||
TypeAndValue tv = type_and_value_of_expr(expr);
|
||||
@@ -1472,7 +1476,7 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
lbModule *m = p->module;
|
||||
t = reduce_tuple_to_single_type(t);
|
||||
|
||||
@@ -1554,13 +1558,13 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
if (is_type_boolean(src) && dst == t_llvm_bool) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), "");
|
||||
res.type = dst;
|
||||
res.type = t;
|
||||
return res;
|
||||
}
|
||||
if (src == t_llvm_bool && is_type_boolean(dst)) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMBuildZExt(p->builder, value.value, lb_type(m, dst), "");
|
||||
res.type = dst;
|
||||
res.type = t;
|
||||
return res;
|
||||
}
|
||||
|
||||
@@ -1921,8 +1925,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
}
|
||||
|
||||
if (is_type_union(dst)) {
|
||||
for_array(i, dst->Union.variants) {
|
||||
Type *vt = dst->Union.variants[i];
|
||||
for (Type *vt : dst->Union.variants) {
|
||||
if (are_types_identical(vt, src_type)) {
|
||||
lbAddr parent = lb_add_local_generated(p, t, true);
|
||||
lb_emit_store_union_variant(p, parent.addr, value, vt);
|
||||
@@ -2159,7 +2162,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
// bit_set <-> integer
|
||||
if (is_type_integer(src) && is_type_bit_set(dst)) {
|
||||
lbValue res = lb_emit_conv(p, value, bit_set_to_int(dst));
|
||||
res.type = dst;
|
||||
res.type = t;
|
||||
return res;
|
||||
}
|
||||
if (is_type_bit_set(src) && is_type_integer(dst)) {
|
||||
@@ -2202,7 +2205,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
||||
return {};
|
||||
}
|
||||
|
||||
lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right, Type *type) {
|
||||
gb_internal lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right, Type *type) {
|
||||
GB_ASSERT((is_type_struct(type) || is_type_union(type)) && is_type_comparable(type));
|
||||
lbValue left_ptr = lb_address_from_load_or_generate_local(p, left);
|
||||
lbValue right_ptr = lb_address_from_load_or_generate_local(p, right);
|
||||
@@ -2230,7 +2233,7 @@ lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbVa
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) {
|
||||
gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) {
|
||||
Type *a = core_type(left.type);
|
||||
Type *b = core_type(right.type);
|
||||
|
||||
@@ -2642,7 +2645,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
|
||||
gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
|
||||
lbValue res = {};
|
||||
res.type = t_llvm_bool;
|
||||
Type *t = x.type;
|
||||
@@ -2803,7 +2806,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
|
||||
return {};
|
||||
}
|
||||
|
||||
lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbValue const &index) {
|
||||
gb_internal lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbValue const &index) {
|
||||
lbAddr v = lb_add_local_generated(p, type, false);
|
||||
lbValue ptr = lb_emit_struct_ep(p, v.addr, 0);
|
||||
lbValue idx = lb_emit_struct_ep(p, v.addr, 1);
|
||||
@@ -2813,7 +2816,7 @@ lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbV
|
||||
return lb_addr_load(p, v);
|
||||
}
|
||||
|
||||
lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
|
||||
ast_node(ue, UnaryExpr, expr);
|
||||
auto tv = type_and_value_of_expr(expr);
|
||||
|
||||
@@ -3023,8 +3026,8 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
|
||||
return lb_build_addr_ptr(p, ue->expr);
|
||||
}
|
||||
|
||||
lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr);
|
||||
lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr);
|
||||
gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
u16 prev_state_flags = p->state_flags;
|
||||
defer (p->state_flags = prev_state_flags);
|
||||
|
||||
@@ -3080,7 +3083,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
expr = unparen_expr(expr);
|
||||
@@ -3099,6 +3102,9 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
|
||||
// NOTE(bill): Short on constant values
|
||||
return lb_const_value(p->module, type, tv.value);
|
||||
} else if (tv.mode == Addressing_Type) {
|
||||
// NOTE(bill, 2023-01-16): is this correct? I hope so at least
|
||||
return lb_typeid(m, tv.type);
|
||||
}
|
||||
|
||||
switch (expr->kind) {
|
||||
@@ -3355,10 +3361,10 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
return {};
|
||||
}
|
||||
|
||||
lbAddr lb_get_soa_variable_addr(lbProcedure *p, Entity *e) {
|
||||
gb_internal lbAddr lb_get_soa_variable_addr(lbProcedure *p, Entity *e) {
|
||||
return map_must_get(&p->module->soa_values, e);
|
||||
}
|
||||
lbValue lb_get_using_variable(lbProcedure *p, Entity *e) {
|
||||
gb_internal lbValue lb_get_using_variable(lbProcedure *p, Entity *e) {
|
||||
GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using);
|
||||
String name = e->token.string;
|
||||
Entity *parent = e->using_parent;
|
||||
@@ -3393,7 +3399,7 @@ lbValue lb_get_using_variable(lbProcedure *p, Entity *e) {
|
||||
|
||||
|
||||
|
||||
lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) {
|
||||
gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) {
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (e->kind == Entity_Constant) {
|
||||
Type *t = default_type(type_of_expr(expr));
|
||||
@@ -3427,7 +3433,7 @@ lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) {
|
||||
return lb_addr(v);
|
||||
}
|
||||
|
||||
lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
|
||||
gb_internal lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
|
||||
isize index_count = ce->args.count-1;
|
||||
lbAddr addr = lb_build_addr(p, ce->args[0]);
|
||||
if (index_count == 0) {
|
||||
@@ -3463,8 +3469,8 @@ lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, TypeAndValue
|
||||
}
|
||||
|
||||
|
||||
lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr);
|
||||
lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr);
|
||||
gb_internal lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||
expr = unparen_expr(expr);
|
||||
|
||||
// IMPORTANT NOTE(bill):
|
||||
@@ -3489,7 +3495,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||
return addr;
|
||||
}
|
||||
|
||||
void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice<Ast *> const &elems, Array<lbCompoundLitElemTempData> *temp_data, Type *compound_type) {
|
||||
gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice<Ast *> const &elems, Array<lbCompoundLitElemTempData> *temp_data, Type *compound_type) {
|
||||
Type *bt = base_type(compound_type);
|
||||
Type *et = nullptr;
|
||||
switch (bt->kind) {
|
||||
@@ -3595,9 +3601,8 @@ void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice<Ast *> const &ele
|
||||
}
|
||||
}
|
||||
}
|
||||
void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array<lbCompoundLitElemTempData> const &temp_data) {
|
||||
for_array(i, temp_data) {
|
||||
auto td = temp_data[i];
|
||||
gb_internal void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array<lbCompoundLitElemTempData> const &temp_data) {
|
||||
for (auto const &td : temp_data) {
|
||||
if (td.value.value != nullptr) {
|
||||
if (td.elem_length > 0) {
|
||||
auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32);
|
||||
@@ -3614,7 +3619,7 @@ void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array<lbCompoundLit
|
||||
}
|
||||
}
|
||||
|
||||
lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
|
||||
ast_node(ie, IndexExpr, expr);
|
||||
|
||||
Type *t = base_type(type_of_expr(ie->expr));
|
||||
@@ -3833,7 +3838,7 @@ lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
|
||||
|
||||
lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
|
||||
ast_node(se, SliceExpr, expr);
|
||||
|
||||
lbValue low = lb_const_int(p->module, t_int, 0);
|
||||
@@ -4031,7 +4036,7 @@ lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
|
||||
|
||||
lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
ast_node(cl, CompoundLit, expr);
|
||||
|
||||
Type *type = type_of_expr(expr);
|
||||
@@ -4129,8 +4134,7 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
|
||||
gb_unused(err);
|
||||
|
||||
for_array(field_index, cl->elems) {
|
||||
Ast *elem = cl->elems[field_index];
|
||||
for (Ast *elem : cl->elems) {
|
||||
ast_node(fv, FieldValue, elem);
|
||||
|
||||
lbValue key = lb_build_expr(p, fv->field);
|
||||
@@ -4304,8 +4308,7 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
|
||||
|
||||
lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower));
|
||||
for_array(i, cl->elems) {
|
||||
Ast *elem = cl->elems[i];
|
||||
for (Ast *elem : cl->elems) {
|
||||
GB_ASSERT(elem->kind != Ast_FieldValue);
|
||||
|
||||
if (lb_is_elem_const(elem, et)) {
|
||||
@@ -4359,8 +4362,7 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
|
||||
// TODO(bill): reduce the need for individual `insertelement` if a `shufflevector`
|
||||
// might be a better option
|
||||
for_array(i, temp_data) {
|
||||
auto td = temp_data[i];
|
||||
for (auto const &td : temp_data) {
|
||||
if (td.value.value != nullptr) {
|
||||
if (td.elem_length > 0) {
|
||||
for (i64 k = 0; k < td.elem_length; k++) {
|
||||
@@ -4383,7 +4385,7 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
|
||||
|
||||
lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
|
||||
switch (expr->kind) {
|
||||
case_ast_node(i, Implicit, expr);
|
||||
lbAddr v = {};
|
||||
|
||||
+199
-225
File diff suppressed because it is too large
Load Diff
+28
-25
@@ -32,21 +32,21 @@
|
||||
**************************************************************************/
|
||||
|
||||
|
||||
void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level);
|
||||
void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimization_level);
|
||||
void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPassManagerRef mpm, i32 optimization_level);
|
||||
void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level);
|
||||
gb_internal void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level);
|
||||
gb_internal void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimization_level);
|
||||
gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPassManagerRef mpm, i32 optimization_level);
|
||||
gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level);
|
||||
|
||||
LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data) {
|
||||
lbModule *m = cast(lbModule *)user_data;
|
||||
if (m == nullptr) {
|
||||
return false;
|
||||
}
|
||||
if (value == nullptr) {
|
||||
return false;
|
||||
}
|
||||
return LLVMIsAAllocaInst(value) != nullptr;
|
||||
}
|
||||
// gb_internal LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data) {
|
||||
// lbModule *m = cast(lbModule *)user_data;
|
||||
// if (m == nullptr) {
|
||||
// return false;
|
||||
// }
|
||||
// if (value == nullptr) {
|
||||
// return false;
|
||||
// }
|
||||
// return LLVMIsAAllocaInst(value) != nullptr;
|
||||
// }
|
||||
|
||||
|
||||
#if LLVM_VERSION_MAJOR < 12
|
||||
@@ -55,7 +55,7 @@ LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data
|
||||
#define LLVM_ADD_CONSTANT_VALUE_PASS(fpm)
|
||||
#endif
|
||||
|
||||
void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) {
|
||||
gb_internal void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) {
|
||||
if (false && optimization_level == 0 && build_context.ODIN_DEBUG) {
|
||||
LLVMAddMergedLoadStoreMotionPass(fpm);
|
||||
} else {
|
||||
@@ -68,7 +68,7 @@ void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimiz
|
||||
}
|
||||
}
|
||||
|
||||
void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level) {
|
||||
gb_internal void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level) {
|
||||
// NOTE(bill): Treat -opt:3 as if it was -opt:2
|
||||
// TODO(bill): Determine which opt definitions should exist in the first place
|
||||
optimization_level = gb_clamp(optimization_level, 0, 2);
|
||||
@@ -102,7 +102,7 @@ void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool
|
||||
#endif
|
||||
}
|
||||
|
||||
void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level) {
|
||||
gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level) {
|
||||
// NOTE(bill): Treat -opt:3 as if it was -opt:2
|
||||
// TODO(bill): Determine which opt definitions should exist in the first place
|
||||
optimization_level = gb_clamp(optimization_level, 0, 2);
|
||||
@@ -141,7 +141,7 @@ void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef
|
||||
#endif
|
||||
}
|
||||
|
||||
void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimization_level) {
|
||||
gb_internal void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimization_level) {
|
||||
LLVMAddCFGSimplificationPass(mpm);
|
||||
|
||||
LLVMAddJumpThreadingPass(mpm);
|
||||
@@ -177,7 +177,7 @@ void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimizati
|
||||
}
|
||||
|
||||
|
||||
void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPassManagerRef mpm, i32 optimization_level) {
|
||||
gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPassManagerRef mpm, i32 optimization_level) {
|
||||
|
||||
// NOTE(bill): Treat -opt:3 as if it was -opt:2
|
||||
// TODO(bill): Determine which opt definitions should exist in the first place
|
||||
@@ -266,7 +266,7 @@ void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPa
|
||||
optimization of Odin programs
|
||||
**************************************************************************/
|
||||
|
||||
void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
|
||||
gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
|
||||
isize removal_count = 0;
|
||||
isize pass_count = 0;
|
||||
isize const max_pass_count = 10;
|
||||
@@ -358,7 +358,10 @@ void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
|
||||
}
|
||||
|
||||
|
||||
void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
|
||||
gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
|
||||
if (p == nullptr) {
|
||||
return;
|
||||
}
|
||||
LLVMRunFunctionPassManager(fpm, p->value);
|
||||
// NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM
|
||||
// which means we cannot rely upon it
|
||||
@@ -367,7 +370,7 @@ void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
|
||||
lb_run_remove_dead_instruction_pass(p);
|
||||
}
|
||||
|
||||
void llvm_delete_function(LLVMValueRef func) {
|
||||
gb_internal void llvm_delete_function(LLVMValueRef func) {
|
||||
// for (LLVMBasicBlockRef block = LLVMGetFirstBasicBlock(func); block != nullptr; /**/) {
|
||||
// LLVMBasicBlockRef curr_block = block;
|
||||
// block = LLVMGetNextBasicBlock(block);
|
||||
@@ -382,7 +385,7 @@ void llvm_delete_function(LLVMValueRef func) {
|
||||
LLVMDeleteFunction(func);
|
||||
}
|
||||
|
||||
void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) {
|
||||
gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) {
|
||||
LLVMValueRef global = LLVMGetNamedGlobal(m->mod, "llvm.compiler.used");
|
||||
|
||||
LLVMValueRef *constants;
|
||||
@@ -419,7 +422,7 @@ void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) {
|
||||
LLVMSetInitializer(global, initializer);
|
||||
}
|
||||
|
||||
void lb_run_remove_unused_function_pass(lbModule *m) {
|
||||
gb_internal void lb_run_remove_unused_function_pass(lbModule *m) {
|
||||
isize removal_count = 0;
|
||||
isize pass_count = 0;
|
||||
isize const max_pass_count = 10;
|
||||
@@ -470,7 +473,7 @@ void lb_run_remove_unused_function_pass(lbModule *m) {
|
||||
}
|
||||
|
||||
|
||||
void lb_run_remove_unused_globals_pass(lbModule *m) {
|
||||
gb_internal void lb_run_remove_unused_globals_pass(lbModule *m) {
|
||||
isize removal_count = 0;
|
||||
isize pass_count = 0;
|
||||
isize const max_pass_count = 10;
|
||||
|
||||
+253
-127
@@ -1,6 +1,4 @@
|
||||
|
||||
LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count)
|
||||
{
|
||||
gb_internal LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) {
|
||||
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
|
||||
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
|
||||
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, type_count);
|
||||
@@ -8,7 +6,7 @@ LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* a
|
||||
return LLVMBuildCall2(p->builder, call_type, ip, args, arg_count, "");
|
||||
}
|
||||
|
||||
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
|
||||
gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
|
||||
dst = lb_emit_conv(p, dst, t_rawptr);
|
||||
src = lb_emit_conv(p, src, t_rawptr);
|
||||
len = lb_emit_conv(p, len, t_int);
|
||||
@@ -37,7 +35,7 @@ void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue l
|
||||
|
||||
|
||||
|
||||
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
|
||||
gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
|
||||
dst = lb_emit_conv(p, dst, t_rawptr);
|
||||
src = lb_emit_conv(p, src, t_rawptr);
|
||||
len = lb_emit_conv(p, len, t_int);
|
||||
@@ -66,17 +64,19 @@ void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbVal
|
||||
}
|
||||
|
||||
|
||||
lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) {
|
||||
gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) {
|
||||
GB_ASSERT(entity != nullptr);
|
||||
GB_ASSERT(entity->kind == Entity_Procedure);
|
||||
if (!entity->Procedure.is_foreign) {
|
||||
GB_ASSERT_MSG(entity->flags & EntityFlag_ProcBodyChecked, "%.*s :: %s", LIT(entity->token.string), type_to_string(entity->type));
|
||||
if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) {
|
||||
GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false));
|
||||
}
|
||||
}
|
||||
|
||||
String link_name = {};
|
||||
|
||||
if (ignore_body) {
|
||||
lbModule *other_module = lb_pkg_module(m->gen, entity->pkg);
|
||||
lbModule *other_module = lb_module_of_entity(m->gen, entity);
|
||||
link_name = lb_get_entity_name(other_module, entity);
|
||||
} else {
|
||||
link_name = lb_get_entity_name(m, entity);
|
||||
@@ -121,8 +121,9 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
||||
p->branch_blocks.allocator = a;
|
||||
p->context_stack.allocator = a;
|
||||
p->scope_stack.allocator = a;
|
||||
map_init(&p->selector_values, a, 0);
|
||||
map_init(&p->selector_addr, a, 0);
|
||||
map_init(&p->selector_values, 0);
|
||||
map_init(&p->selector_addr, 0);
|
||||
map_init(&p->tuple_fix_map, 0);
|
||||
|
||||
if (p->is_foreign) {
|
||||
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
||||
@@ -191,11 +192,6 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
||||
lb_add_attribute_to_proc(m, p->value, "cold");
|
||||
}
|
||||
|
||||
lbValue proc_value = {p->value, p->type};
|
||||
lb_add_entity(m, entity, proc_value);
|
||||
lb_add_member(m, p->name, proc_value);
|
||||
lb_add_procedure_value(m, p);
|
||||
|
||||
if (p->is_export) {
|
||||
LLVMSetLinkage(p->value, LLVMDLLExportLinkage);
|
||||
LLVMSetDLLStorageClass(p->value, LLVMDLLExportStorageClass);
|
||||
@@ -203,7 +199,9 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
||||
|
||||
lb_set_wasm_export_attributes(p->value, p->name);
|
||||
} else if (!p->is_foreign) {
|
||||
if (!USE_SEPARATE_MODULES) {
|
||||
if (USE_SEPARATE_MODULES) {
|
||||
LLVMSetLinkage(p->value, LLVMExternalLinkage);
|
||||
} else {
|
||||
LLVMSetLinkage(p->value, LLVMInternalLinkage);
|
||||
|
||||
// NOTE(bill): if a procedure is defined in package runtime and uses a custom link name,
|
||||
@@ -317,10 +315,15 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
||||
}
|
||||
}
|
||||
|
||||
lbValue proc_value = {p->value, p->type};
|
||||
lb_add_entity(m, entity, proc_value);
|
||||
lb_add_member(m, p->name, proc_value);
|
||||
lb_add_procedure_value(m, p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) {
|
||||
gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) {
|
||||
{
|
||||
lbValue *found = string_map_get(&m->members, link_name);
|
||||
GB_ASSERT_MSG(found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name));
|
||||
@@ -346,6 +349,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
|
||||
p->blocks.allocator = a;
|
||||
p->branch_blocks.allocator = a;
|
||||
p->context_stack.allocator = a;
|
||||
map_init(&p->tuple_fix_map, 0);
|
||||
|
||||
|
||||
char *c_link_name = alloc_cstring(permanent_allocator(), p->name);
|
||||
@@ -383,50 +387,50 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_value_param(lbProcedure *p, Entity *e, Type *abi_type, i32 index, lbParamPasskind *kind_) {
|
||||
lbParamPasskind kind = lbParamPass_Value;
|
||||
// gb_internal lbValue lb_value_param(lbProcedure *p, Entity *e, Type *abi_type, i32 index, lbParamPasskind *kind_) {
|
||||
// lbParamPasskind kind = lbParamPass_Value;
|
||||
|
||||
if (e != nullptr && !are_types_identical(abi_type, e->type)) {
|
||||
if (is_type_pointer(abi_type)) {
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
Type *av = core_type(type_deref(abi_type));
|
||||
if (are_types_identical(av, core_type(e->type))) {
|
||||
kind = lbParamPass_Pointer;
|
||||
if (e->flags&EntityFlag_Value) {
|
||||
kind = lbParamPass_ConstRef;
|
||||
}
|
||||
} else {
|
||||
kind = lbParamPass_BitCast;
|
||||
}
|
||||
} else if (is_type_integer(abi_type)) {
|
||||
kind = lbParamPass_Integer;
|
||||
} else if (abi_type == t_llvm_bool) {
|
||||
kind = lbParamPass_Value;
|
||||
} else if (is_type_boolean(abi_type)) {
|
||||
kind = lbParamPass_Integer;
|
||||
} else if (is_type_simd_vector(abi_type)) {
|
||||
kind = lbParamPass_BitCast;
|
||||
} else if (is_type_float(abi_type)) {
|
||||
kind = lbParamPass_BitCast;
|
||||
} else if (is_type_tuple(abi_type)) {
|
||||
kind = lbParamPass_Tuple;
|
||||
} else if (is_type_proc(abi_type)) {
|
||||
kind = lbParamPass_Value;
|
||||
} else {
|
||||
GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type));
|
||||
}
|
||||
}
|
||||
// if (e != nullptr && !are_types_identical(abi_type, e->type)) {
|
||||
// if (is_type_pointer(abi_type)) {
|
||||
// GB_ASSERT(e->kind == Entity_Variable);
|
||||
// Type *av = core_type(type_deref(abi_type));
|
||||
// if (are_types_identical(av, core_type(e->type))) {
|
||||
// kind = lbParamPass_Pointer;
|
||||
// if (e->flags&EntityFlag_Value) {
|
||||
// kind = lbParamPass_ConstRef;
|
||||
// }
|
||||
// } else {
|
||||
// kind = lbParamPass_BitCast;
|
||||
// }
|
||||
// } else if (is_type_integer(abi_type)) {
|
||||
// kind = lbParamPass_Integer;
|
||||
// } else if (abi_type == t_llvm_bool) {
|
||||
// kind = lbParamPass_Value;
|
||||
// } else if (is_type_boolean(abi_type)) {
|
||||
// kind = lbParamPass_Integer;
|
||||
// } else if (is_type_simd_vector(abi_type)) {
|
||||
// kind = lbParamPass_BitCast;
|
||||
// } else if (is_type_float(abi_type)) {
|
||||
// kind = lbParamPass_BitCast;
|
||||
// } else if (is_type_tuple(abi_type)) {
|
||||
// kind = lbParamPass_Tuple;
|
||||
// } else if (is_type_proc(abi_type)) {
|
||||
// kind = lbParamPass_Value;
|
||||
// } else {
|
||||
// GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type));
|
||||
// }
|
||||
// }
|
||||
|
||||
if (kind_) *kind_ = kind;
|
||||
lbValue res = {};
|
||||
res.value = LLVMGetParam(p->value, cast(unsigned)index);
|
||||
res.type = abi_type;
|
||||
return res;
|
||||
}
|
||||
// if (kind_) *kind_ = kind;
|
||||
// lbValue res = {};
|
||||
// res.value = LLVMGetParam(p->value, cast(unsigned)index);
|
||||
// res.type = abi_type;
|
||||
// return res;
|
||||
// }
|
||||
|
||||
|
||||
|
||||
void lb_start_block(lbProcedure *p, lbBlock *b) {
|
||||
gb_internal void lb_start_block(lbProcedure *p, lbBlock *b) {
|
||||
GB_ASSERT(b != nullptr);
|
||||
if (!b->appended) {
|
||||
b->appended = true;
|
||||
@@ -436,7 +440,7 @@ void lb_start_block(lbProcedure *p, lbBlock *b) {
|
||||
p->curr_block = b;
|
||||
}
|
||||
|
||||
void lb_set_debug_position_to_procedure_begin(lbProcedure *p) {
|
||||
gb_internal void lb_set_debug_position_to_procedure_begin(lbProcedure *p) {
|
||||
if (p->debug_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -453,7 +457,7 @@ void lb_set_debug_position_to_procedure_begin(lbProcedure *p) {
|
||||
}
|
||||
}
|
||||
|
||||
void lb_set_debug_position_to_procedure_end(lbProcedure *p) {
|
||||
gb_internal void lb_set_debug_position_to_procedure_end(lbProcedure *p) {
|
||||
if (p->debug_info == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -470,7 +474,7 @@ void lb_set_debug_position_to_procedure_end(lbProcedure *p) {
|
||||
}
|
||||
}
|
||||
|
||||
void lb_begin_procedure_body(lbProcedure *p) {
|
||||
gb_internal void lb_begin_procedure_body(lbProcedure *p) {
|
||||
DeclInfo *decl = decl_info_of_entity(p->entity);
|
||||
if (decl != nullptr) {
|
||||
for_array(i, decl->labels) {
|
||||
@@ -486,7 +490,7 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
||||
p->entry_block = lb_create_block(p, "entry", true);
|
||||
lb_start_block(p, p->entry_block);
|
||||
|
||||
map_init(&p->direct_parameters, heap_allocator());
|
||||
map_init(&p->direct_parameters);
|
||||
|
||||
GB_ASSERT(p->type != nullptr);
|
||||
|
||||
@@ -501,8 +505,23 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
||||
// NOTE(bill): this must be parameter 0
|
||||
|
||||
String name = str_lit("agg.result");
|
||||
if (ft->multiple_return_original_type &&
|
||||
p->type->Proc.has_named_results) {
|
||||
auto const &variables = p->type->Proc.results->Tuple.variables;
|
||||
Entity *e = variables[variables.count-1];
|
||||
if (!is_blank_ident(e->token)) {
|
||||
name = e->token.string;
|
||||
}
|
||||
}
|
||||
|
||||
Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results));
|
||||
Type *return_ptr_type = reduce_tuple_to_single_type(p->type->Proc.results);
|
||||
bool split_returns = ft->multiple_return_original_type != nullptr;
|
||||
if (split_returns) {
|
||||
GB_ASSERT(is_type_tuple(return_ptr_type));
|
||||
auto const &variables = return_ptr_type->Tuple.variables;
|
||||
return_ptr_type = variables[variables.count-1]->type;
|
||||
}
|
||||
Type *ptr_type = alloc_type_pointer(return_ptr_type);
|
||||
Entity *e = alloc_entity_param(nullptr, make_token_ident(name), ptr_type, false, false);
|
||||
e->flags |= EntityFlag_NoAlias;
|
||||
|
||||
@@ -580,14 +599,70 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
||||
if (e->token.string != "") {
|
||||
GB_ASSERT(!is_blank_ident(e->token));
|
||||
|
||||
// NOTE(bill): Don't even bother trying to optimize this with the return ptr value
|
||||
// This will violate the defer rules if you do:
|
||||
// foo :: proc() -> (x, y: T) {
|
||||
// defer x = ... // defer is executed after the `defer`
|
||||
// return // the values returned should be zeroed
|
||||
// }
|
||||
// NOTE(bill): REALLY, don't even bother.
|
||||
lbAddr res = lb_add_local(p, e->type, e);
|
||||
lbAddr res = {};
|
||||
if (p->entity && p->entity->decl_info &&
|
||||
p->entity->decl_info->defer_use_checked &&
|
||||
p->entity->decl_info->defer_used == 0) {
|
||||
|
||||
// NOTE(bill): this is a bodge to get around the issue of the problem BELOW
|
||||
// We check to see if we ever use a defer statement ever within a procedure and if it
|
||||
// if it never happens, see if you can possibly do take the return value pointer
|
||||
//
|
||||
// NOTE(bill): this could be buggy in that I have missed a case where `defer` was used
|
||||
//
|
||||
// TODO(bill): This could be optimized to check to see where a `defer` only uses
|
||||
// the variable in question
|
||||
|
||||
bool has_return_ptr = p->return_ptr.addr.value != nullptr;
|
||||
lbValue ptr = {};
|
||||
|
||||
if (ft->multiple_return_original_type != nullptr) {
|
||||
isize the_offset = -1;
|
||||
if (i+1 < results->variables.count) {
|
||||
the_offset = cast(isize)param_offset + ft->original_arg_count + i;
|
||||
} else if (has_return_ptr) {
|
||||
GB_ASSERT(i+1 == results->variables.count);
|
||||
the_offset = 0;
|
||||
}
|
||||
if (the_offset >= 0) {
|
||||
lbValue ptr = {};
|
||||
ptr.value = LLVMGetParam(p->value, cast(unsigned)the_offset);
|
||||
ptr.type = alloc_type_pointer(e->type);
|
||||
|
||||
|
||||
}
|
||||
} else if (has_return_ptr) {
|
||||
lbValue ptr = p->return_ptr.addr;
|
||||
|
||||
if (results->variables.count > 1) {
|
||||
ptr = lb_emit_tuple_ep(p, ptr, cast(i32)i);
|
||||
}
|
||||
GB_ASSERT(is_type_pointer(ptr.type));
|
||||
GB_ASSERT(are_types_identical(type_deref(ptr.type), e->type));
|
||||
}
|
||||
|
||||
if (ptr.value != nullptr) {
|
||||
lb_add_entity(p->module, e, ptr);
|
||||
lb_add_debug_local_variable(p, ptr.value, e->type, e->token);
|
||||
// NOTE(bill): no need to zero on the callee side as it is zeroed on the caller side
|
||||
|
||||
res = lb_addr(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
if (res.addr.type == nullptr) {
|
||||
// NOTE(bill): Don't even bother trying to optimize this with the return ptr value
|
||||
// This will violate the defer rules if you do:
|
||||
// foo :: proc() -> (x, y: T) {
|
||||
// defer x = ... // defer is executed after the `defer`
|
||||
// return // the values returned should be zeroed
|
||||
// }
|
||||
// NOTE(bill): REALLY, don't even bother.
|
||||
//
|
||||
// IMPORTANT NOTE(bill): REALLY, don't even bother!!!!!!
|
||||
res = lb_add_local(p, e->type, e);
|
||||
}
|
||||
|
||||
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
|
||||
lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
|
||||
lb_addr_store(p, res, c);
|
||||
@@ -614,7 +689,7 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
||||
lb_start_block(p, p->entry_block);
|
||||
}
|
||||
|
||||
void lb_end_procedure_body(lbProcedure *p) {
|
||||
gb_internal void lb_end_procedure_body(lbProcedure *p) {
|
||||
lb_set_debug_position_to_procedure_begin(p);
|
||||
|
||||
LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block);
|
||||
@@ -648,11 +723,11 @@ void lb_end_procedure_body(lbProcedure *p) {
|
||||
p->curr_block = nullptr;
|
||||
p->state_flags = 0;
|
||||
}
|
||||
void lb_end_procedure(lbProcedure *p) {
|
||||
gb_internal void lb_end_procedure(lbProcedure *p) {
|
||||
LLVMDisposeBuilder(p->builder);
|
||||
}
|
||||
|
||||
void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) {
|
||||
gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) {
|
||||
GB_ASSERT(pd->body != nullptr);
|
||||
lbModule *m = p->module;
|
||||
auto *min_dep_set = &m->info->minimum_dependency_set;
|
||||
@@ -694,21 +769,14 @@ void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) {
|
||||
|
||||
|
||||
|
||||
Array<lbValue> lb_value_to_array(lbProcedure *p, lbValue value) {
|
||||
gb_internal Array<lbValue> lb_value_to_array(lbProcedure *p, lbValue value) {
|
||||
Array<lbValue> array = {};
|
||||
Type *t = base_type(value.type);
|
||||
if (t == nullptr) {
|
||||
// Do nothing
|
||||
} else if (is_type_tuple(t)) {
|
||||
GB_ASSERT(t->kind == Type_Tuple);
|
||||
auto *rt = &t->Tuple;
|
||||
if (rt->variables.count > 0) {
|
||||
array = array_make<lbValue>(permanent_allocator(), rt->variables.count);
|
||||
for_array(i, rt->variables) {
|
||||
lbValue elem = lb_emit_struct_ev(p, value, cast(i32)i);
|
||||
array[i] = elem;
|
||||
}
|
||||
}
|
||||
array = array_make<lbValue>(permanent_allocator(), 0, t->Tuple.variables.count);
|
||||
lb_append_tuple_values(p, &array, value);
|
||||
} else {
|
||||
array = array_make<lbValue>(permanent_allocator(), 1);
|
||||
array[0] = value;
|
||||
@@ -718,7 +786,7 @@ Array<lbValue> lb_value_to_array(lbProcedure *p, lbValue value) {
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array<lbValue> const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining) {
|
||||
gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array<lbValue> const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining) {
|
||||
GB_ASSERT(p->module->ctx == LLVMGetTypeContext(LLVMTypeOf(value.value)));
|
||||
|
||||
unsigned arg_count = cast(unsigned)processed_args.count;
|
||||
@@ -734,6 +802,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
|
||||
if (return_ptr.value != nullptr) {
|
||||
args[arg_index++] = return_ptr.value;
|
||||
}
|
||||
|
||||
for_array(i, processed_args) {
|
||||
lbValue arg = processed_args[i];
|
||||
if (is_type_proc(arg.type)) {
|
||||
@@ -741,16 +810,23 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
|
||||
}
|
||||
args[arg_index++] = arg.value;
|
||||
}
|
||||
|
||||
if (context_ptr.addr.value != nullptr) {
|
||||
LLVMValueRef cp = context_ptr.addr.value;
|
||||
cp = LLVMBuildPointerCast(p->builder, cp, lb_type(p->module, t_rawptr), "");
|
||||
args[arg_index++] = cp;
|
||||
}
|
||||
|
||||
GB_ASSERT(arg_index == arg_count);
|
||||
|
||||
LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder);
|
||||
GB_ASSERT(curr_block != p->decl_block->block);
|
||||
|
||||
{
|
||||
LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type);
|
||||
Type *proc_type = base_type(value.type);
|
||||
GB_ASSERT(proc_type->kind == Type_Proc);
|
||||
|
||||
LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, proc_type);
|
||||
LLVMTypeRef ftp = LLVMPointerType(fnp, 0);
|
||||
LLVMValueRef fn = value.value;
|
||||
if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) {
|
||||
@@ -775,10 +851,11 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
|
||||
// LLVMTypeKind arg_kind = LLVMGetTypeKind(arg_type);
|
||||
GB_ASSERT_MSG(
|
||||
arg_type == param_type,
|
||||
"Parameter types do not match: %s != %s, argument: %s",
|
||||
"Parameter types do not match: %s != %s, argument: %s\n\t%s",
|
||||
LLVMPrintTypeToString(arg_type),
|
||||
LLVMPrintTypeToString(param_type),
|
||||
LLVMPrintValueToString(args[i])
|
||||
LLVMPrintValueToString(args[i]),
|
||||
LLVMPrintTypeToString(fnp)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -818,20 +895,20 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) {
|
||||
gb_internal lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) {
|
||||
AstPackage *pkg = m->info->runtime_package;
|
||||
Entity *e = scope_lookup_current(pkg->scope, name);
|
||||
return lb_find_procedure_value_from_entity(m, e);
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args) {
|
||||
gb_internal lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args) {
|
||||
String name = make_string_c(c_name);
|
||||
lbValue proc = lb_lookup_runtime_procedure(p->module, name);
|
||||
return lb_emit_call(p, proc, args);
|
||||
}
|
||||
|
||||
lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) {
|
||||
gb_internal lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) {
|
||||
lbValue res = {};
|
||||
Type *t = val.type;
|
||||
if (is_type_complex(t)) {
|
||||
@@ -882,7 +959,7 @@ lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) {
|
||||
return lb_emit_load(p, res);
|
||||
}
|
||||
|
||||
lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining, bool use_copy_elision_hint) {
|
||||
gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
Type *pt = base_type(value.type);
|
||||
@@ -915,8 +992,9 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
|
||||
|
||||
bool is_odin_cc = is_calling_convention_odin(pt->Proc.calling_convention);
|
||||
|
||||
lbFunctionType *ft = lb_get_function_type(m, p, pt);
|
||||
lbFunctionType *ft = lb_get_function_type(m, pt);
|
||||
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
|
||||
bool split_returns = ft->multiple_return_original_type != nullptr;
|
||||
|
||||
unsigned param_index = 0;
|
||||
for (isize i = 0; i < param_count; i++) {
|
||||
@@ -979,18 +1057,19 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
|
||||
}
|
||||
|
||||
Type *rt = reduce_tuple_to_single_type(results);
|
||||
Type *original_rt = rt;
|
||||
if (split_returns) {
|
||||
GB_ASSERT(rt->kind == Type_Tuple);
|
||||
for (isize j = 0; j < rt->Tuple.variables.count-1; j++) {
|
||||
Type *partial_return_type = rt->Tuple.variables[j]->type;
|
||||
lbValue partial_return_ptr = lb_add_local(p, partial_return_type, nullptr, true, false).addr;
|
||||
array_add(&processed_args, partial_return_ptr);
|
||||
}
|
||||
rt = reduce_tuple_to_single_type(rt->Tuple.variables[rt->Tuple.variables.count-1]->type);
|
||||
}
|
||||
|
||||
if (return_by_pointer) {
|
||||
lbValue return_ptr = {};
|
||||
if (use_copy_elision_hint && p->copy_elision_hint.ptr.value != nullptr) {
|
||||
if (are_types_identical(type_deref(p->copy_elision_hint.ptr.type), rt)) {
|
||||
return_ptr = lb_consume_copy_elision_hint(p);
|
||||
}
|
||||
}
|
||||
if (return_ptr.value == nullptr) {
|
||||
lbAddr r = lb_add_local_generated(p, rt, true);
|
||||
return_ptr = r.addr;
|
||||
}
|
||||
GB_ASSERT(is_type_pointer(return_ptr.type));
|
||||
lbValue return_ptr = lb_add_local_generated(p, rt, true).addr;
|
||||
lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining);
|
||||
result = lb_emit_load(p, return_ptr);
|
||||
} else if (rt != nullptr) {
|
||||
@@ -1010,6 +1089,47 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
|
||||
lb_emit_call_internal(p, value, {}, processed_args, nullptr, context_ptr, inlining);
|
||||
}
|
||||
|
||||
if (original_rt != rt) {
|
||||
GB_ASSERT(split_returns);
|
||||
GB_ASSERT(is_type_tuple(original_rt));
|
||||
|
||||
// IMPORTANT NOTE(bill, 2022-11-24)
|
||||
// result_ptr is a dummy value which is only used to reference a tuple
|
||||
// value for the "tuple-fix"
|
||||
//
|
||||
// The reason for the fake stack allocation is to have a unique pointer
|
||||
// for the value to be used as a key within the procedure itself
|
||||
|
||||
lbValue result_ptr = lb_add_local_generated(p, original_rt, false).addr;
|
||||
isize ret_count = original_rt->Tuple.variables.count;
|
||||
|
||||
auto tuple_fix_values = slice_make<lbValue>(permanent_allocator(), ret_count);
|
||||
auto tuple_geps = slice_make<lbValue>(permanent_allocator(), ret_count);
|
||||
|
||||
isize offset = ft->original_arg_count;
|
||||
for (isize j = 0; j < ret_count-1; j++) {
|
||||
lbValue ret_arg_ptr = processed_args[offset + j];
|
||||
lbValue ret_arg = lb_emit_load(p, ret_arg_ptr);
|
||||
tuple_fix_values[j] = ret_arg;
|
||||
}
|
||||
tuple_fix_values[ret_count-1] = result;
|
||||
|
||||
#if 0
|
||||
for (isize j = 0; j < ret_count; j++) {
|
||||
tuple_geps[j] = lb_emit_struct_ep(p, result_ptr, cast(i32)j);
|
||||
}
|
||||
for (isize j = 0; j < ret_count; j++) {
|
||||
lb_emit_store(p, tuple_geps[j], tuple_fix_values[j]);
|
||||
}
|
||||
#endif
|
||||
|
||||
result = lb_emit_load(p, result_ptr);
|
||||
|
||||
lbTupleFix tf = {tuple_fix_values};
|
||||
map_set(&p->tuple_fix_map, result_ptr.value, tf);
|
||||
map_set(&p->tuple_fix_map, result.value, tf);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Entity **found = map_get(&p->module->procedure_values, value.value);
|
||||
@@ -1049,15 +1169,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
|
||||
return result;
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_splat_float(i64 count, LLVMTypeRef type, f64 value) {
|
||||
LLVMValueRef v = LLVMConstReal(type, value);
|
||||
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
|
||||
for (i64 i = 0; i < count; i++) {
|
||||
values[i] = v;
|
||||
}
|
||||
return LLVMConstVector(values, cast(unsigned)count);
|
||||
}
|
||||
LLVMValueRef llvm_splat_int(i64 count, LLVMTypeRef type, i64 value, bool is_signed=false) {
|
||||
gb_internal LLVMValueRef llvm_splat_int(i64 count, LLVMTypeRef type, i64 value, bool is_signed=false) {
|
||||
LLVMValueRef v = LLVMConstInt(type, value, is_signed);
|
||||
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
|
||||
for (i64 i = 0; i < count; i++) {
|
||||
@@ -1067,7 +1179,7 @@ LLVMValueRef llvm_splat_int(i64 count, LLVMTypeRef type, i64 value, bool is_sign
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId builtin_id) {
|
||||
gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId builtin_id) {
|
||||
ast_node(ce, CallExpr, expr);
|
||||
|
||||
lbModule *m = p->module;
|
||||
@@ -1483,7 +1595,7 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId id) {
|
||||
gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId id) {
|
||||
ast_node(ce, CallExpr, expr);
|
||||
|
||||
if (BuiltinProc__simd_begin < id && id < BuiltinProc__simd_end) {
|
||||
@@ -2300,7 +2412,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
|
||||
);
|
||||
LLVMSetWeak(value, weak);
|
||||
|
||||
if (tv.type->kind == Type_Tuple) {
|
||||
if (is_type_tuple(tv.type)) {
|
||||
Type *fix_typed = alloc_type_tuple();
|
||||
slice_init(&fix_typed->Tuple.variables, permanent_allocator(), 2);
|
||||
fix_typed->Tuple.variables[0] = tv.type->Tuple.variables[0];
|
||||
@@ -2834,8 +2946,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
|
||||
LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
|
||||
LLVMValueRef the_asm = llvm_get_inline_asm(
|
||||
func_type,
|
||||
str_lit("rolq $3, %rdi; rolq $13, %rdi\n rolq $61, %rdi; rolq $51, %rdi\n xchgq %rbx, %rbx"),
|
||||
str_lit("={rdx},{rdx},{rax},cc,memory"),
|
||||
str_lit("rolq $$3, %rdi; rolq $$13, %rdi\n rolq $$61, %rdi; rolq $$51, %rdi\n xchgq %rbx, %rbx"),
|
||||
str_lit("={rdx},{rdx},{rax},~{cc},~{memory}"),
|
||||
true
|
||||
);
|
||||
|
||||
@@ -2863,7 +2975,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos) {
|
||||
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const ¶m_value, TokenPos const &pos) {
|
||||
switch (param_value.kind) {
|
||||
case ParameterValue_Constant:
|
||||
if (is_type_constant_type(parameter_type)) {
|
||||
@@ -2898,9 +3010,9 @@ lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterVal
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr);
|
||||
gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr);
|
||||
|
||||
lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
|
||||
expr = unparen_expr(expr);
|
||||
ast_node(ce, CallExpr, expr);
|
||||
|
||||
@@ -2913,7 +3025,7 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
return res;
|
||||
}
|
||||
lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
TypeAndValue tv = type_and_value_of_expr(expr);
|
||||
@@ -3015,6 +3127,8 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
GB_ASSERT(e->kind == Entity_Variable);
|
||||
if (args[i].value == nullptr) {
|
||||
args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos);
|
||||
} else if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) {
|
||||
args[i] = lb_typeid(p->module, args[i].type);
|
||||
} else {
|
||||
args[i] = lb_emit_conv(p, args[i], e->type);
|
||||
}
|
||||
@@ -3032,7 +3146,7 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
}
|
||||
|
||||
return lb_emit_call(p, value, args, ce->inlining, p->copy_elision_hint.ast == expr);
|
||||
return lb_emit_call(p, value, args, ce->inlining);
|
||||
}
|
||||
|
||||
isize arg_index = 0;
|
||||
@@ -3044,7 +3158,7 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s %d", expr_to_string(arg), expr_to_string(expr), tav.mode);
|
||||
GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg));
|
||||
Type *at = tav.type;
|
||||
if (at->kind == Type_Tuple) {
|
||||
if (is_type_tuple(at)) {
|
||||
arg_count += at->Tuple.variables.count;
|
||||
} else {
|
||||
arg_count++;
|
||||
@@ -3084,9 +3198,16 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
lbValue a = lb_build_expr(p, arg);
|
||||
Type *at = a.type;
|
||||
if (at->kind == Type_Tuple) {
|
||||
for_array(i, at->Tuple.variables) {
|
||||
lbValue v = lb_emit_struct_ev(p, a, cast(i32)i);
|
||||
args[arg_index++] = v;
|
||||
lbTupleFix *tf = map_get(&p->tuple_fix_map, a.value);
|
||||
if (tf) {
|
||||
for_array(j, tf->values) {
|
||||
args[arg_index++] = tf->values[j];
|
||||
}
|
||||
} else {
|
||||
for_array(j, at->Tuple.variables) {
|
||||
lbValue v = lb_emit_struct_ev(p, a, cast(i32)j);
|
||||
args[arg_index++] = v;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
args[arg_index++] = a;
|
||||
@@ -3157,7 +3278,12 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
continue;
|
||||
}
|
||||
GB_ASSERT_MSG(args[i].value != nullptr, "%.*s", LIT(e->token.string));
|
||||
args[i] = lb_emit_conv(p, args[i], e->type);
|
||||
if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) {
|
||||
GB_ASSERT(LLVMIsNull(args[i].value));
|
||||
args[i] = lb_typeid(p->module, args[i].type);
|
||||
} else {
|
||||
args[i] = lb_emit_conv(p, args[i], e->type);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3213,6 +3339,6 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
|
||||
auto call_args = array_slice(args, 0, final_count);
|
||||
return lb_emit_call(p, value, call_args, ce->inlining, p->copy_elision_hint.ast == expr);
|
||||
return lb_emit_call(p, value, call_args, ce->inlining);
|
||||
}
|
||||
|
||||
|
||||
+180
-185
@@ -1,32 +1,4 @@
|
||||
lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, Ast *ast) {
|
||||
lbCopyElisionHint prev = p->copy_elision_hint;
|
||||
p->copy_elision_hint.used = false;
|
||||
p->copy_elision_hint.ptr = {};
|
||||
p->copy_elision_hint.ast = nullptr;
|
||||
#if 0
|
||||
if (addr.kind == lbAddr_Default && addr.addr.value != nullptr) {
|
||||
p->copy_elision_hint.ptr = lb_addr_get_ptr(p, addr);
|
||||
p->copy_elision_hint.ast = unparen_expr(ast);
|
||||
}
|
||||
#endif
|
||||
return prev;
|
||||
}
|
||||
|
||||
void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint) {
|
||||
p->copy_elision_hint = prev_hint;
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_consume_copy_elision_hint(lbProcedure *p) {
|
||||
lbValue return_ptr = p->copy_elision_hint.ptr;
|
||||
p->copy_elision_hint.used = true;
|
||||
p->copy_elision_hint.ptr = {};
|
||||
p->copy_elision_hint.ast = nullptr;
|
||||
return return_ptr;
|
||||
}
|
||||
|
||||
|
||||
void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
||||
gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
||||
if (vd == nullptr || vd->is_mutable) {
|
||||
return;
|
||||
}
|
||||
@@ -35,8 +7,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
||||
|
||||
static i32 global_guid = 0;
|
||||
|
||||
for_array(i, vd->names) {
|
||||
Ast *ident = vd->names[i];
|
||||
for (Ast *ident : vd->names) {
|
||||
GB_ASSERT(ident->kind == Ast_Ident);
|
||||
Entity *e = entity_of_node(ident);
|
||||
GB_ASSERT(e != nullptr);
|
||||
@@ -61,7 +32,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
||||
continue;
|
||||
}
|
||||
|
||||
lb_set_nested_type_name_ir_mangled_name(e, p);
|
||||
lb_set_nested_type_name_ir_mangled_name(e, p, p->module);
|
||||
}
|
||||
|
||||
for_array(i, vd->names) {
|
||||
@@ -79,21 +50,20 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
||||
continue; // It's an alias
|
||||
}
|
||||
|
||||
CheckerInfo *info = p->module->info;
|
||||
DeclInfo *decl = decl_info_of_entity(e);
|
||||
ast_node(pl, ProcLit, decl->proc_lit);
|
||||
if (pl->body != nullptr) {
|
||||
auto *found = map_get(&info->gen_procs, ident);
|
||||
if (found) {
|
||||
auto procs = *found;
|
||||
for_array(i, procs) {
|
||||
Entity *e = procs[i];
|
||||
GenProcsData *gpd = e->Procedure.gen_procs;
|
||||
if (gpd) {
|
||||
rw_mutex_shared_lock(&gpd->mutex);
|
||||
for (Entity *e : gpd->procs) {
|
||||
if (!ptr_set_exists(min_dep_set, e)) {
|
||||
continue;
|
||||
}
|
||||
DeclInfo *d = decl_info_of_entity(e);
|
||||
lb_build_nested_proc(p, &d->proc_lit->ProcLit, e);
|
||||
}
|
||||
rw_mutex_shared_unlock(&gpd->mutex);
|
||||
} else {
|
||||
lb_build_nested_proc(p, pl, e);
|
||||
}
|
||||
@@ -133,9 +103,8 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
||||
}
|
||||
|
||||
|
||||
void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) {
|
||||
for_array(i, stmts) {
|
||||
Ast *stmt = stmts[i];
|
||||
gb_internal void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) {
|
||||
for (Ast *stmt : stmts) {
|
||||
switch (stmt->kind) {
|
||||
case_ast_node(vd, ValueDecl, stmt);
|
||||
lb_build_constant_value_decl(p, vd);
|
||||
@@ -146,21 +115,20 @@ void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) {
|
||||
case_end;
|
||||
}
|
||||
}
|
||||
for_array(i, stmts) {
|
||||
lb_build_stmt(p, stmts[i]);
|
||||
for (Ast *stmt : stmts) {
|
||||
lb_build_stmt(p, stmt);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) {
|
||||
gb_internal lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) {
|
||||
GB_ASSERT(ident->kind == Ast_Ident);
|
||||
Entity *e = entity_of_node(ident);
|
||||
GB_ASSERT(e->kind == Entity_Label);
|
||||
for_array(i, p->branch_blocks) {
|
||||
lbBranchBlocks *b = &p->branch_blocks[i];
|
||||
if (b->label == e->Label.node) {
|
||||
return *b;
|
||||
for (lbBranchBlocks const &b : p->branch_blocks) {
|
||||
if (b.label == e->Label.node) {
|
||||
return b;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -170,7 +138,7 @@ lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) {
|
||||
}
|
||||
|
||||
|
||||
lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) {
|
||||
gb_internal lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) {
|
||||
lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList);
|
||||
tl->prev = p->target_list;
|
||||
tl->break_ = break_;
|
||||
@@ -181,13 +149,12 @@ lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, l
|
||||
if (label != nullptr) { // Set label blocks
|
||||
GB_ASSERT(label->kind == Ast_Label);
|
||||
|
||||
for_array(i, p->branch_blocks) {
|
||||
lbBranchBlocks *b = &p->branch_blocks[i];
|
||||
GB_ASSERT(b->label != nullptr && label != nullptr);
|
||||
GB_ASSERT(b->label->kind == Ast_Label);
|
||||
if (b->label == label) {
|
||||
b->break_ = break_;
|
||||
b->continue_ = continue_;
|
||||
for (lbBranchBlocks &b : p->branch_blocks) {
|
||||
GB_ASSERT(b.label != nullptr && label != nullptr);
|
||||
GB_ASSERT(b.label->kind == Ast_Label);
|
||||
if (b.label == label) {
|
||||
b.break_ = break_;
|
||||
b.continue_ = continue_;
|
||||
return tl;
|
||||
}
|
||||
}
|
||||
@@ -198,11 +165,11 @@ lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, l
|
||||
return tl;
|
||||
}
|
||||
|
||||
void lb_pop_target_list(lbProcedure *p) {
|
||||
gb_internal void lb_pop_target_list(lbProcedure *p) {
|
||||
p->target_list = p->target_list->prev;
|
||||
}
|
||||
|
||||
void lb_open_scope(lbProcedure *p, Scope *s) {
|
||||
gb_internal void lb_open_scope(lbProcedure *p, Scope *s) {
|
||||
lbModule *m = p->module;
|
||||
if (m->debug_builder) {
|
||||
LLVMMetadataRef curr_metadata = lb_get_llvm_metadata(m, s);
|
||||
@@ -239,7 +206,7 @@ void lb_open_scope(lbProcedure *p, Scope *s) {
|
||||
|
||||
}
|
||||
|
||||
void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) {
|
||||
gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) {
|
||||
lb_emit_defer_stmts(p, kind, block);
|
||||
GB_ASSERT(p->scope_index > 0);
|
||||
|
||||
@@ -258,7 +225,7 @@ void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool p
|
||||
array_pop(&p->scope_stack);
|
||||
}
|
||||
|
||||
void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
|
||||
gb_internal void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
|
||||
TypeAndValue tv = type_and_value_of_expr(ws->cond);
|
||||
GB_ASSERT(is_type_boolean(tv.type));
|
||||
GB_ASSERT(tv.value.kind == ExactValue_Bool);
|
||||
@@ -281,8 +248,8 @@ void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
|
||||
|
||||
|
||||
|
||||
void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
|
||||
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||
gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
|
||||
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
lbValue count = {};
|
||||
@@ -370,7 +337,7 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu
|
||||
if (done_) *done_ = done;
|
||||
}
|
||||
|
||||
lbValue lb_map_cell_index_static(lbProcedure *p, Type *type, lbValue cells_ptr, lbValue index) {
|
||||
gb_internal lbValue lb_map_cell_index_static(lbProcedure *p, Type *type, lbValue cells_ptr, lbValue index) {
|
||||
i64 size, len;
|
||||
i64 elem_sz = type_size_of(type);
|
||||
map_cell_size_and_len(type, &size, &len);
|
||||
@@ -406,17 +373,7 @@ lbValue lb_map_cell_index_static(lbProcedure *p, Type *type, lbValue cells_ptr,
|
||||
return lb_emit_ptr_offset(p, elems_ptr, data_index);
|
||||
}
|
||||
|
||||
void lb_map_kvh_data_static(lbProcedure *p, lbValue map_value, lbValue *ks_, lbValue *vs_, lbValue *hs_) {
|
||||
lbValue capacity = lb_map_cap(p, map_value);
|
||||
lbValue ks = lb_map_data_uintptr(p, map_value);
|
||||
lbValue vs = {};
|
||||
lbValue hs = {};
|
||||
if (ks_) *ks_ = ks;
|
||||
if (vs_) *vs_ = vs;
|
||||
if (hs_) *hs_ = hs;
|
||||
}
|
||||
|
||||
lbValue lb_map_hash_is_valid(lbProcedure *p, lbValue hash) {
|
||||
gb_internal lbValue lb_map_hash_is_valid(lbProcedure *p, lbValue hash) {
|
||||
// N :: size_of(uintptr)*8 - 1
|
||||
// (hash != 0) & (hash>>N == 0)
|
||||
|
||||
@@ -432,8 +389,8 @@ lbValue lb_map_hash_is_valid(lbProcedure *p, lbValue hash) {
|
||||
return lb_emit_arith(p, Token_And, not_deleted, not_empty, t_uintptr);
|
||||
}
|
||||
|
||||
void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type,
|
||||
lbValue *val_, lbValue *key_, lbBlock **loop_, lbBlock **done_) {
|
||||
gb_internal void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type,
|
||||
lbValue *val_, lbValue *key_, lbBlock **loop_, lbBlock **done_) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
Type *type = base_type(type_deref(expr.type));
|
||||
@@ -494,8 +451,8 @@ void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type,
|
||||
|
||||
|
||||
|
||||
void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
|
||||
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||
gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
|
||||
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||
lbModule *m = p->module;
|
||||
lbValue count = lb_const_int(m, t_int, 0);
|
||||
Type *expr_type = base_type(expr.type);
|
||||
@@ -554,8 +511,8 @@ void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
|
||||
}
|
||||
|
||||
|
||||
void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
|
||||
AstRangeStmt *rs, Scope *scope) {
|
||||
gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
|
||||
AstRangeStmt *rs, Scope *scope) {
|
||||
bool ADD_EXTRA_WRAPPING_CHECK = true;
|
||||
|
||||
lbModule *m = p->module;
|
||||
@@ -658,7 +615,7 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
|
||||
lb_start_block(p, done);
|
||||
}
|
||||
|
||||
void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||
gb_internal void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
Type *t = enum_type;
|
||||
@@ -711,8 +668,8 @@ void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValu
|
||||
if (done_) *done_ = done;
|
||||
}
|
||||
|
||||
void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type,
|
||||
lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) {
|
||||
gb_internal void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type,
|
||||
lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) {
|
||||
lbBlock *loop = lb_create_block(p, "for.tuple.loop");
|
||||
lb_emit_jump(p, loop);
|
||||
lb_start_block(p, loop);
|
||||
@@ -726,18 +683,18 @@ void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1
|
||||
i32 tuple_count = cast(i32)tuple->Tuple.variables.count;
|
||||
i32 cond_index = tuple_count-1;
|
||||
|
||||
lbValue cond = lb_emit_struct_ev(p, tuple_value, cond_index);
|
||||
lbValue cond = lb_emit_tuple_ev(p, tuple_value, cond_index);
|
||||
lb_emit_if(p, cond, body, done);
|
||||
lb_start_block(p, body);
|
||||
|
||||
|
||||
if (val0_) *val0_ = lb_emit_struct_ev(p, tuple_value, 0);
|
||||
if (val1_) *val1_ = lb_emit_struct_ev(p, tuple_value, 1);
|
||||
if (val0_) *val0_ = lb_emit_tuple_ev(p, tuple_value, 0);
|
||||
if (val1_) *val1_ = lb_emit_tuple_ev(p, tuple_value, 1);
|
||||
if (loop_) *loop_ = loop;
|
||||
if (done_) *done_ = done;
|
||||
}
|
||||
|
||||
void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||
gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||
Ast *expr = unparen_expr(rs->expr);
|
||||
TypeAndValue tav = type_and_value_of_expr(expr);
|
||||
|
||||
@@ -806,7 +763,7 @@ void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *sco
|
||||
|
||||
}
|
||||
|
||||
void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||
gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||
Ast *expr = unparen_expr(rs->expr);
|
||||
|
||||
if (is_ast_range(expr)) {
|
||||
@@ -951,7 +908,7 @@ void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
|
||||
lb_start_block(p, done);
|
||||
}
|
||||
|
||||
void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *scope) {
|
||||
gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *scope) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
lb_open_scope(p, scope); // Open scope here
|
||||
@@ -1117,7 +1074,7 @@ void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *s
|
||||
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
||||
}
|
||||
|
||||
bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) {
|
||||
gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) {
|
||||
if (ss->tag == nullptr) {
|
||||
return false;
|
||||
}
|
||||
@@ -1133,8 +1090,7 @@ bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_f
|
||||
}
|
||||
|
||||
ast_node(body, BlockStmt, ss->body);
|
||||
for_array(i, body->stmts) {
|
||||
Ast *clause = body->stmts[i];
|
||||
for (Ast *clause : body->stmts) {
|
||||
ast_node(cc, CaseClause, clause);
|
||||
|
||||
if (cc->list.count == 0) {
|
||||
@@ -1142,8 +1098,8 @@ bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_f
|
||||
continue;
|
||||
}
|
||||
|
||||
for_array(j, cc->list) {
|
||||
Ast *expr = unparen_expr(cc->list[j]);
|
||||
for (Ast *expr : cc->list) {
|
||||
expr = unparen_expr(expr);
|
||||
if (is_ast_range(expr)) {
|
||||
return false;
|
||||
}
|
||||
@@ -1166,7 +1122,7 @@ bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_f
|
||||
}
|
||||
|
||||
|
||||
void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
|
||||
gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
|
||||
lb_open_scope(p, scope);
|
||||
|
||||
if (ss->init != nullptr) {
|
||||
@@ -1204,8 +1160,7 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
|
||||
LLVMValueRef switch_instr = nullptr;
|
||||
if (is_trivial) {
|
||||
isize num_cases = 0;
|
||||
for_array(i, body->stmts) {
|
||||
Ast *clause = body->stmts[i];
|
||||
for (Ast *clause : body->stmts) {
|
||||
ast_node(cc, CaseClause, clause);
|
||||
num_cases += cc->list.count;
|
||||
}
|
||||
@@ -1242,8 +1197,8 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
|
||||
}
|
||||
|
||||
lbBlock *next_cond = nullptr;
|
||||
for_array(j, cc->list) {
|
||||
Ast *expr = unparen_expr(cc->list[j]);
|
||||
for (Ast *expr : cc->list) {
|
||||
expr = unparen_expr(expr);
|
||||
|
||||
if (switch_instr != nullptr) {
|
||||
lbValue on_val = {};
|
||||
@@ -1328,7 +1283,7 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
|
||||
lb_close_scope(p, lbDeferExit_Default, done);
|
||||
}
|
||||
|
||||
void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) {
|
||||
gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) {
|
||||
Entity *e = implicit_entity_of_node(clause);
|
||||
GB_ASSERT(e != nullptr);
|
||||
if (e->flags & EntityFlag_Value) {
|
||||
@@ -1343,7 +1298,7 @@ void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) {
|
||||
}
|
||||
}
|
||||
|
||||
lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value) {
|
||||
gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value) {
|
||||
Entity *e = entity_of_node(stmt_val);
|
||||
if (e == nullptr) {
|
||||
return {};
|
||||
@@ -1363,7 +1318,7 @@ lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value) {
|
||||
return addr;
|
||||
}
|
||||
|
||||
void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) {
|
||||
gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) {
|
||||
ast_node(cc, CaseClause, clause);
|
||||
|
||||
lb_push_target_list(p, label, done, nullptr, nullptr);
|
||||
@@ -1374,7 +1329,7 @@ void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, l
|
||||
lb_emit_jump(p, done);
|
||||
}
|
||||
|
||||
void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
lbModule *m = p->module;
|
||||
lb_open_scope(p, ss->scope);
|
||||
|
||||
@@ -1422,8 +1377,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
lbBlock *default_block = nullptr;
|
||||
isize num_cases = 0;
|
||||
|
||||
for_array(i, body->stmts) {
|
||||
Ast *clause = body->stmts[i];
|
||||
for (Ast *clause : body->stmts) {
|
||||
ast_node(cc, CaseClause, clause);
|
||||
num_cases += cc->list.count;
|
||||
if (cc->list.count == 0) {
|
||||
@@ -1443,8 +1397,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
|
||||
}
|
||||
|
||||
for_array(i, body->stmts) {
|
||||
Ast *clause = body->stmts[i];
|
||||
for (Ast *clause : body->stmts) {
|
||||
ast_node(cc, CaseClause, clause);
|
||||
lb_open_scope(p, cc->scope);
|
||||
if (cc->list.count == 0) {
|
||||
@@ -1458,9 +1411,8 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
if (p->debug_info != nullptr) {
|
||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, clause));
|
||||
}
|
||||
Type *case_type = nullptr;
|
||||
for_array(type_index, cc->list) {
|
||||
case_type = type_of_expr(cc->list[type_index]);
|
||||
for (Ast *type_expr : cc->list) {
|
||||
Type *case_type = type_of_expr(type_expr);
|
||||
lbValue on_val = {};
|
||||
if (switch_kind == TypeSwitch_Union) {
|
||||
Type *ut = base_type(type_deref(parent.type));
|
||||
@@ -1508,7 +1460,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
||||
}
|
||||
|
||||
|
||||
void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
|
||||
gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
|
||||
for_array(i, vd->names) {
|
||||
lbValue value = {};
|
||||
if (vd->values.count > 0) {
|
||||
@@ -1571,35 +1523,48 @@ void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
|
||||
lb_add_member(p->module, mangled_name, global_val);
|
||||
}
|
||||
}
|
||||
gb_internal void lb_append_tuple_values(lbProcedure *p, Array<lbValue> *dst_values, lbValue src_value) {
|
||||
Type *t = src_value.type;
|
||||
if (t->kind == Type_Tuple) {
|
||||
lbTupleFix *tf = map_get(&p->tuple_fix_map, src_value.value);
|
||||
if (tf) {
|
||||
for (lbValue const &value : tf->values) {
|
||||
array_add(dst_values, value);
|
||||
}
|
||||
} else {
|
||||
for_array(i, t->Tuple.variables) {
|
||||
lbValue v = lb_emit_tuple_ev(p, src_value, cast(i32)i);
|
||||
array_add(dst_values, v);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
array_add(dst_values, src_value);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> const &values) {
|
||||
gb_internal void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> const &values) {
|
||||
if (values.count == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
|
||||
|
||||
for_array(i, values) {
|
||||
Ast *rhs = values[i];
|
||||
if (is_type_tuple(type_of_expr(rhs))) {
|
||||
lbValue init = lb_build_expr(p, rhs);
|
||||
Type *t = init.type;
|
||||
GB_ASSERT(t->kind == Type_Tuple);
|
||||
for_array(i, t->Tuple.variables) {
|
||||
lbValue v = lb_emit_struct_ev(p, init, cast(i32)i);
|
||||
array_add(&inits, v);
|
||||
}
|
||||
} else {
|
||||
auto prev_hint = lb_set_copy_elision_hint(p, lvals[inits.count], rhs);
|
||||
lbValue init = lb_build_expr(p, rhs);
|
||||
if (p->copy_elision_hint.used) {
|
||||
lvals[inits.count] = {}; // zero lval
|
||||
}
|
||||
lb_reset_copy_elision_hint(p, prev_hint);
|
||||
array_add(&inits, init);
|
||||
for (Ast *rhs : values) {
|
||||
lbValue init = lb_build_expr(p, rhs);
|
||||
lb_append_tuple_values(p, &inits, init);
|
||||
}
|
||||
|
||||
bool prev_in_assignment = p->in_multi_assignment;
|
||||
|
||||
isize lval_count = 0;
|
||||
for (lbAddr const &lval : lvals) {
|
||||
if (lval.addr.value != nullptr) {
|
||||
// check if it is not a blank identifier
|
||||
lval_count += 1;
|
||||
}
|
||||
}
|
||||
p->in_multi_assignment = lval_count > 1;
|
||||
|
||||
GB_ASSERT(lvals.count == inits.count);
|
||||
for_array(i, inits) {
|
||||
@@ -1607,11 +1572,18 @@ void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> cons
|
||||
lbValue init = inits[i];
|
||||
lb_addr_store(p, lval, init);
|
||||
}
|
||||
|
||||
p->in_multi_assignment = prev_in_assignment;
|
||||
}
|
||||
|
||||
void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) {
|
||||
lbFunctionType *ft = lb_get_function_type(p->module, p, p->type);
|
||||
gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
|
||||
lbFunctionType *ft = lb_get_function_type(p->module, p->type);
|
||||
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
|
||||
bool split_returns = ft->multiple_return_original_type != nullptr;
|
||||
|
||||
if (split_returns) {
|
||||
GB_ASSERT(res.value == nullptr || !is_type_tuple(res.type));
|
||||
}
|
||||
|
||||
if (return_by_pointer) {
|
||||
if (res.value != nullptr) {
|
||||
@@ -1641,7 +1613,7 @@ void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) {
|
||||
LLVMBuildRet(p->builder, ret_val);
|
||||
}
|
||||
}
|
||||
void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
|
||||
gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
|
||||
lb_ensure_abi_function_type(p->module, p);
|
||||
|
||||
lbValue res = {};
|
||||
@@ -1650,7 +1622,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
|
||||
isize return_count = p->type->Proc.result_count;
|
||||
isize res_count = return_results.count;
|
||||
|
||||
lbFunctionType *ft = lb_get_function_type(p->module, p, p->type);
|
||||
lbFunctionType *ft = lb_get_function_type(p->module, p->type);
|
||||
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
|
||||
|
||||
if (return_count == 0) {
|
||||
@@ -1683,15 +1655,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
|
||||
if (res_count != 0) {
|
||||
for (isize res_index = 0; res_index < res_count; res_index++) {
|
||||
lbValue res = lb_build_expr(p, return_results[res_index]);
|
||||
Type *t = res.type;
|
||||
if (t->kind == Type_Tuple) {
|
||||
for_array(i, t->Tuple.variables) {
|
||||
lbValue v = lb_emit_struct_ev(p, res, cast(i32)i);
|
||||
array_add(&results, v);
|
||||
}
|
||||
} else {
|
||||
array_add(&results, res);
|
||||
}
|
||||
lb_append_tuple_values(p, &results, res);
|
||||
}
|
||||
} else {
|
||||
for (isize res_index = 0; res_index < return_count; res_index++) {
|
||||
@@ -1727,40 +1691,73 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
|
||||
}
|
||||
}
|
||||
|
||||
Type *ret_type = p->type->Proc.results;
|
||||
bool split_returns = ft->multiple_return_original_type != nullptr;
|
||||
if (split_returns) {
|
||||
auto result_values = slice_make<lbValue>(temporary_allocator(), results.count);
|
||||
auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count-1);
|
||||
|
||||
for_array(i, results) {
|
||||
result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type);
|
||||
}
|
||||
|
||||
isize param_offset = return_by_pointer ? 1 : 0;
|
||||
param_offset += ft->original_arg_count;
|
||||
for_array(i, result_eps) {
|
||||
lbValue result_ep = {};
|
||||
result_ep.value = LLVMGetParam(p->value, cast(unsigned)(param_offset+i));
|
||||
result_ep.type = alloc_type_pointer(tuple->variables[i]->type);
|
||||
result_eps[i] = result_ep;
|
||||
}
|
||||
for_array(i, result_eps) {
|
||||
lb_emit_store(p, result_eps[i], result_values[i]);
|
||||
}
|
||||
if (return_by_pointer) {
|
||||
GB_ASSERT(result_values.count-1 == result_eps.count);
|
||||
lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]);
|
||||
|
||||
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
||||
LLVMBuildRetVoid(p->builder);
|
||||
return;
|
||||
} else {
|
||||
return lb_build_return_stmt_internal(p, result_values[result_values.count-1]);
|
||||
}
|
||||
|
||||
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
|
||||
if (return_by_pointer) {
|
||||
res = p->return_ptr.addr;
|
||||
} else {
|
||||
res = lb_add_local_generated(p, ret_type, false).addr;
|
||||
}
|
||||
Type *ret_type = p->type->Proc.results;
|
||||
|
||||
auto result_values = slice_make<lbValue>(temporary_allocator(), results.count);
|
||||
auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count);
|
||||
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
|
||||
if (return_by_pointer) {
|
||||
res = p->return_ptr.addr;
|
||||
} else {
|
||||
res = lb_add_local_generated(p, ret_type, false).addr;
|
||||
}
|
||||
|
||||
for_array(i, results) {
|
||||
result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type);
|
||||
}
|
||||
for_array(i, results) {
|
||||
result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i);
|
||||
}
|
||||
for_array(i, result_values) {
|
||||
lb_emit_store(p, result_eps[i], result_values[i]);
|
||||
}
|
||||
auto result_values = slice_make<lbValue>(temporary_allocator(), results.count);
|
||||
auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count);
|
||||
|
||||
if (return_by_pointer) {
|
||||
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
||||
LLVMBuildRetVoid(p->builder);
|
||||
return;
|
||||
}
|
||||
for_array(i, results) {
|
||||
result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type);
|
||||
}
|
||||
for_array(i, results) {
|
||||
result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i);
|
||||
}
|
||||
for_array(i, result_eps) {
|
||||
lb_emit_store(p, result_eps[i], result_values[i]);
|
||||
}
|
||||
|
||||
res = lb_emit_load(p, res);
|
||||
if (return_by_pointer) {
|
||||
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
|
||||
LLVMBuildRetVoid(p->builder);
|
||||
return;
|
||||
}
|
||||
|
||||
res = lb_emit_load(p, res);
|
||||
}
|
||||
}
|
||||
lb_build_return_stmt_internal(p, res);
|
||||
}
|
||||
|
||||
void lb_build_if_stmt(lbProcedure *p, Ast *node) {
|
||||
gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
|
||||
ast_node(is, IfStmt, node);
|
||||
lb_open_scope(p, is->scope); // Scope #1
|
||||
defer (lb_close_scope(p, lbDeferExit_Default, nullptr));
|
||||
@@ -1847,7 +1844,7 @@ void lb_build_if_stmt(lbProcedure *p, Ast *node) {
|
||||
lb_start_block(p, done);
|
||||
}
|
||||
|
||||
void lb_build_for_stmt(lbProcedure *p, Ast *node) {
|
||||
gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
|
||||
ast_node(fs, ForStmt, node);
|
||||
|
||||
lb_open_scope(p, fs->scope); // Open Scope here
|
||||
@@ -1907,7 +1904,7 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
|
||||
lb_close_scope(p, lbDeferExit_Default, nullptr);
|
||||
}
|
||||
|
||||
void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
|
||||
gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
|
||||
GB_ASSERT(op != Token_Eq);
|
||||
|
||||
Type *lhs_type = lb_addr_type(lhs);
|
||||
@@ -1976,8 +1973,7 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs,
|
||||
auto indices_handled = slice_make<bool>(temporary_allocator(), bt->Array.count);
|
||||
auto indices = slice_make<i32>(temporary_allocator(), bt->Array.count);
|
||||
i32 index_count = 0;
|
||||
for_array(i, lhs.swizzle_large.indices) {
|
||||
i32 index = lhs.swizzle_large.indices[i];
|
||||
for (i32 index : lhs.swizzle_large.indices) {
|
||||
if (indices_handled[index]) {
|
||||
continue;
|
||||
}
|
||||
@@ -2050,12 +2046,11 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs,
|
||||
lb_loop_end(p, loop_data);
|
||||
}
|
||||
}
|
||||
void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
|
||||
gb_internal void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
|
||||
if (as->op.kind == Token_Eq) {
|
||||
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, as->lhs.count);
|
||||
|
||||
for_array(i, as->lhs) {
|
||||
Ast *lhs = as->lhs[i];
|
||||
for (Ast *lhs : as->lhs) {
|
||||
lbAddr lval = {};
|
||||
if (!is_blank_ident(lhs)) {
|
||||
lval = lb_build_addr(p, lhs);
|
||||
@@ -2065,6 +2060,7 @@ void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
|
||||
lb_build_assignment(p, lvals, as->rhs);
|
||||
return;
|
||||
}
|
||||
|
||||
GB_ASSERT(as->lhs.count == 1);
|
||||
GB_ASSERT(as->rhs.count == 1);
|
||||
// NOTE(bill): Only 1 += 1 is allowed, no tuples
|
||||
@@ -2108,7 +2104,7 @@ void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
|
||||
}
|
||||
|
||||
|
||||
void lb_build_stmt(lbProcedure *p, Ast *node) {
|
||||
gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
|
||||
Ast *prev_stmt = p->curr_stmt;
|
||||
defer (p->curr_stmt = prev_stmt);
|
||||
p->curr_stmt = node;
|
||||
@@ -2190,12 +2186,12 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
|
||||
|
||||
bool is_static = false;
|
||||
if (vd->names.count > 0) {
|
||||
for_array(i, vd->names) {
|
||||
Ast *name = vd->names[i];
|
||||
for (Ast *name : vd->names) {
|
||||
if (!is_blank_ident(name)) {
|
||||
GB_ASSERT(name->kind == Ast_Ident);
|
||||
Entity *e = entity_of_node(name);
|
||||
TokenPos pos = ast_token(name).pos;
|
||||
GB_ASSERT_MSG(e != nullptr, "%s", token_pos_to_string(pos));
|
||||
GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string));
|
||||
if (e->flags & EntityFlag_Static) {
|
||||
// NOTE(bill): If one of the entities is static, they all are
|
||||
is_static = true;
|
||||
@@ -2212,8 +2208,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
|
||||
|
||||
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count);
|
||||
|
||||
for_array(i, vd->names) {
|
||||
Ast *name = vd->names[i];
|
||||
for (Ast *name : vd->names) {
|
||||
lbAddr lval = {};
|
||||
if (!is_blank_ident(name)) {
|
||||
Entity *e = entity_of_node(name);
|
||||
@@ -2303,7 +2298,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
|
||||
|
||||
|
||||
|
||||
void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) {
|
||||
gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) {
|
||||
if (p->curr_block == nullptr) {
|
||||
return;
|
||||
}
|
||||
@@ -2332,7 +2327,7 @@ void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) {
|
||||
}
|
||||
}
|
||||
|
||||
void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
|
||||
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
|
||||
isize count = p->defer_stmts.count;
|
||||
isize i = count;
|
||||
while (i --> 0) {
|
||||
@@ -2340,7 +2335,7 @@ void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
|
||||
|
||||
if (kind == lbDeferExit_Default) {
|
||||
if (p->scope_index == d.scope_index &&
|
||||
d.scope_index > 0) { // TODO(bill): Which is correct: > 0 or > 1?
|
||||
d.scope_index > 0) {
|
||||
lb_build_defer_stmt(p, d);
|
||||
array_pop(&p->defer_stmts);
|
||||
continue;
|
||||
@@ -2359,7 +2354,7 @@ void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
|
||||
}
|
||||
}
|
||||
|
||||
void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
|
||||
gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
|
||||
Type *pt = base_type(p->type);
|
||||
GB_ASSERT(pt->kind == Type_Proc);
|
||||
if (pt->Proc.calling_convention == ProcCC_Odin) {
|
||||
@@ -2374,7 +2369,7 @@ void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
|
||||
d->stmt = stmt;
|
||||
}
|
||||
|
||||
void lb_add_defer_proc(lbProcedure *p, isize scope_index, lbValue deferred, Array<lbValue> const &result_as_args) {
|
||||
gb_internal void lb_add_defer_proc(lbProcedure *p, isize scope_index, lbValue deferred, Array<lbValue> const &result_as_args) {
|
||||
Type *pt = base_type(p->type);
|
||||
GB_ASSERT(pt->kind == Type_Proc);
|
||||
if (pt->Proc.calling_convention == ProcCC_Odin) {
|
||||
|
||||
+15
-14
@@ -1,10 +1,11 @@
|
||||
isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
|
||||
gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
|
||||
auto *set = &info->minimum_dependency_type_info_set;
|
||||
isize index = type_info_index(info, type, err_on_not_found);
|
||||
if (index >= 0) {
|
||||
isize i = ptr_entry_index(set, index);
|
||||
if (i >= 0) {
|
||||
return i+1;
|
||||
auto *found = map_get(set, index);
|
||||
if (found) {
|
||||
GB_ASSERT(*found >= 0);
|
||||
return *found + 1;
|
||||
}
|
||||
}
|
||||
if (err_on_not_found) {
|
||||
@@ -13,7 +14,7 @@ isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=tr
|
||||
return -1;
|
||||
}
|
||||
|
||||
lbValue lb_typeid(lbModule *m, Type *type) {
|
||||
gb_internal lbValue lb_typeid(lbModule *m, Type *type) {
|
||||
GB_ASSERT(!build_context.disallow_rtti);
|
||||
|
||||
type = default_type(type);
|
||||
@@ -90,7 +91,7 @@ lbValue lb_typeid(lbModule *m, Type *type) {
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_type_info(lbModule *m, Type *type) {
|
||||
gb_internal lbValue lb_type_info(lbModule *m, Type *type) {
|
||||
GB_ASSERT(!build_context.disallow_rtti);
|
||||
|
||||
type = default_type(type);
|
||||
@@ -102,36 +103,36 @@ lbValue lb_type_info(lbModule *m, Type *type) {
|
||||
return lb_emit_array_epi(m, data, index);
|
||||
}
|
||||
|
||||
LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) {
|
||||
gb_internal LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) {
|
||||
return lb_type_internal_for_procedures_raw(m, type);
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_type_info_member_types_offset(lbProcedure *p, isize count) {
|
||||
gb_internal lbValue lb_type_info_member_types_offset(lbProcedure *p, isize count) {
|
||||
GB_ASSERT(p->module == &p->module->gen->default_module);
|
||||
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_types.addr, lb_global_type_info_member_types_index);
|
||||
lb_global_type_info_member_types_index += cast(i32)count;
|
||||
return offset;
|
||||
}
|
||||
lbValue lb_type_info_member_names_offset(lbProcedure *p, isize count) {
|
||||
gb_internal lbValue lb_type_info_member_names_offset(lbProcedure *p, isize count) {
|
||||
GB_ASSERT(p->module == &p->module->gen->default_module);
|
||||
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_names.addr, lb_global_type_info_member_names_index);
|
||||
lb_global_type_info_member_names_index += cast(i32)count;
|
||||
return offset;
|
||||
}
|
||||
lbValue lb_type_info_member_offsets_offset(lbProcedure *p, isize count) {
|
||||
gb_internal lbValue lb_type_info_member_offsets_offset(lbProcedure *p, isize count) {
|
||||
GB_ASSERT(p->module == &p->module->gen->default_module);
|
||||
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_offsets.addr, lb_global_type_info_member_offsets_index);
|
||||
lb_global_type_info_member_offsets_index += cast(i32)count;
|
||||
return offset;
|
||||
}
|
||||
lbValue lb_type_info_member_usings_offset(lbProcedure *p, isize count) {
|
||||
gb_internal lbValue lb_type_info_member_usings_offset(lbProcedure *p, isize count) {
|
||||
GB_ASSERT(p->module == &p->module->gen->default_module);
|
||||
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_usings.addr, lb_global_type_info_member_usings_index);
|
||||
lb_global_type_info_member_usings_index += cast(i32)count;
|
||||
return offset;
|
||||
}
|
||||
lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
|
||||
gb_internal lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
|
||||
GB_ASSERT(p->module == &p->module->gen->default_module);
|
||||
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_tags.addr, lb_global_type_info_member_tags_index);
|
||||
lb_global_type_info_member_tags_index += cast(i32)count;
|
||||
@@ -139,7 +140,7 @@ lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
|
||||
}
|
||||
|
||||
|
||||
void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
|
||||
gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
|
||||
if (build_context.disallow_rtti) {
|
||||
return;
|
||||
}
|
||||
@@ -185,7 +186,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
|
||||
if (entry_index <= 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (entries_handled[entry_index]) {
|
||||
continue;
|
||||
}
|
||||
|
||||
+182
-142
@@ -1,6 +1,6 @@
|
||||
lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name);
|
||||
gb_internal lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name);
|
||||
|
||||
bool lb_is_type_aggregate(Type *t) {
|
||||
gb_internal bool lb_is_type_aggregate(Type *t) {
|
||||
t = base_type(t);
|
||||
switch (t->kind) {
|
||||
case Type_Basic:
|
||||
@@ -39,7 +39,7 @@ bool lb_is_type_aggregate(Type *t) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void lb_emit_unreachable(lbProcedure *p) {
|
||||
gb_internal void lb_emit_unreachable(lbProcedure *p) {
|
||||
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
|
||||
if (instr == nullptr || !lb_is_instr_terminating(instr)) {
|
||||
lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
|
||||
@@ -47,7 +47,7 @@ void lb_emit_unreachable(lbProcedure *p) {
|
||||
}
|
||||
}
|
||||
|
||||
lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
|
||||
gb_internal lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
|
||||
Type *src = core_type(value.type);
|
||||
GB_ASSERT(is_type_integer(src) || is_type_float(src));
|
||||
if (is_type_different_to_arch_endianness(src)) {
|
||||
@@ -57,7 +57,7 @@ lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
|
||||
return value;
|
||||
}
|
||||
|
||||
LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) {
|
||||
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) {
|
||||
bool is_inlinable = false;
|
||||
|
||||
i64 const_len = 0;
|
||||
@@ -103,7 +103,7 @@ LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValu
|
||||
|
||||
}
|
||||
|
||||
void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment) {
|
||||
gb_internal void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment) {
|
||||
LLVMTypeRef llvm_type = lb_type(p->module, type);
|
||||
|
||||
LLVMTypeKind kind = LLVMGetTypeKind(llvm_type);
|
||||
@@ -123,7 +123,7 @@ void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alig
|
||||
}
|
||||
}
|
||||
|
||||
lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y) {
|
||||
gb_internal lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y) {
|
||||
cond = lb_emit_conv(p, cond, t_llvm_bool);
|
||||
lbValue res = {};
|
||||
res.value = LLVMBuildSelect(p->builder, cond.value, x.value, y.value, "");
|
||||
@@ -131,19 +131,19 @@ lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y) {
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_emit_min(lbProcedure *p, Type *t, lbValue x, lbValue y) {
|
||||
gb_internal lbValue lb_emit_min(lbProcedure *p, Type *t, lbValue x, lbValue y) {
|
||||
x = lb_emit_conv(p, x, t);
|
||||
y = lb_emit_conv(p, y, t);
|
||||
return lb_emit_select(p, lb_emit_comp(p, Token_Lt, x, y), x, y);
|
||||
}
|
||||
lbValue lb_emit_max(lbProcedure *p, Type *t, lbValue x, lbValue y) {
|
||||
gb_internal lbValue lb_emit_max(lbProcedure *p, Type *t, lbValue x, lbValue y) {
|
||||
x = lb_emit_conv(p, x, t);
|
||||
y = lb_emit_conv(p, y, t);
|
||||
return lb_emit_select(p, lb_emit_comp(p, Token_Gt, x, y), x, y);
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue max) {
|
||||
gb_internal lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue max) {
|
||||
lbValue z = {};
|
||||
z = lb_emit_max(p, t, x, min);
|
||||
z = lb_emit_min(p, t, z, max);
|
||||
@@ -152,7 +152,7 @@ lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue m
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) {
|
||||
gb_internal lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) {
|
||||
if (false && lb_is_const(str_elem) && lb_is_const(str_len)) {
|
||||
LLVMValueRef values[2] = {
|
||||
str_elem.value,
|
||||
@@ -171,7 +171,7 @@ lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
|
||||
gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
|
||||
Type *src_type = value.type;
|
||||
if (are_types_identical(t, src_type)) {
|
||||
return value;
|
||||
@@ -259,7 +259,7 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 alignment) {
|
||||
gb_internal lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 alignment) {
|
||||
i64 type_alignment = type_align_of(new_type);
|
||||
if (alignment < type_alignment) {
|
||||
alignment = type_alignment;
|
||||
@@ -274,7 +274,7 @@ lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 al
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
|
||||
gb_internal lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
|
||||
GB_ASSERT(ce->args.count > 0);
|
||||
|
||||
auto slices = slice_make<lbValue>(temporary_allocator(), ce->args.count);
|
||||
@@ -305,7 +305,7 @@ lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
|
||||
return lb_addr_load(p, res);
|
||||
}
|
||||
|
||||
lbValue lb_soa_unzip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
|
||||
gb_internal lbValue lb_soa_unzip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
|
||||
GB_ASSERT(ce->args.count == 1);
|
||||
|
||||
lbValue arg = lb_build_expr(p, ce->args[0]);
|
||||
@@ -331,7 +331,7 @@ lbValue lb_soa_unzip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
|
||||
return lb_addr_load(p, res);
|
||||
}
|
||||
|
||||
void lb_emit_try_lhs_rhs(lbProcedure *p, Ast *arg, TypeAndValue const &tv, lbValue *lhs_, lbValue *rhs_) {
|
||||
gb_internal void lb_emit_try_lhs_rhs(lbProcedure *p, Ast *arg, TypeAndValue const &tv, lbValue *lhs_, lbValue *rhs_) {
|
||||
lbValue lhs = {};
|
||||
lbValue rhs = {};
|
||||
|
||||
@@ -339,16 +339,16 @@ void lb_emit_try_lhs_rhs(lbProcedure *p, Ast *arg, TypeAndValue const &tv, lbVal
|
||||
if (is_type_tuple(value.type)) {
|
||||
i32 n = cast(i32)(value.type->Tuple.variables.count-1);
|
||||
if (value.type->Tuple.variables.count == 2) {
|
||||
lhs = lb_emit_struct_ev(p, value, 0);
|
||||
lhs = lb_emit_tuple_ev(p, value, 0);
|
||||
} else {
|
||||
lbAddr lhs_addr = lb_add_local_generated(p, tv.type, false);
|
||||
lbValue lhs_ptr = lb_addr_get_ptr(p, lhs_addr);
|
||||
for (i32 i = 0; i < n; i++) {
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, lhs_ptr, i), lb_emit_struct_ev(p, value, i));
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, lhs_ptr, i), lb_emit_tuple_ev(p, value, i));
|
||||
}
|
||||
lhs = lb_addr_load(p, lhs_addr);
|
||||
}
|
||||
rhs = lb_emit_struct_ev(p, value, n);
|
||||
rhs = lb_emit_tuple_ev(p, value, n);
|
||||
} else {
|
||||
rhs = value;
|
||||
}
|
||||
@@ -360,7 +360,7 @@ void lb_emit_try_lhs_rhs(lbProcedure *p, Ast *arg, TypeAndValue const &tv, lbVal
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) {
|
||||
gb_internal lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) {
|
||||
lbValue has_value = {};
|
||||
if (is_type_boolean(rhs.type)) {
|
||||
has_value = rhs;
|
||||
@@ -373,7 +373,7 @@ lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) {
|
||||
gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) {
|
||||
if (arg->state_flags & StateFlag_DirectiveWasFalse) {
|
||||
return lb_build_expr(p, else_expr);
|
||||
}
|
||||
@@ -435,10 +435,10 @@ lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue c
|
||||
}
|
||||
}
|
||||
|
||||
void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
|
||||
void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res);
|
||||
gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
|
||||
gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res);
|
||||
|
||||
lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
|
||||
gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
|
||||
lbValue lhs = {};
|
||||
lbValue rhs = {};
|
||||
lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs);
|
||||
@@ -479,7 +479,7 @@ lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
|
||||
}
|
||||
|
||||
|
||||
void lb_emit_increment(lbProcedure *p, lbValue addr) {
|
||||
gb_internal void lb_emit_increment(lbProcedure *p, lbValue addr) {
|
||||
GB_ASSERT(is_type_pointer(addr.type));
|
||||
Type *type = type_deref(addr.type);
|
||||
lbValue v_one = lb_const_value(p->module, type, exact_value_i64(1));
|
||||
@@ -487,7 +487,7 @@ void lb_emit_increment(lbProcedure *p, lbValue addr) {
|
||||
|
||||
}
|
||||
|
||||
lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
|
||||
gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
|
||||
GB_ASSERT(type_size_of(value.type) == type_size_of(end_type));
|
||||
|
||||
if (type_size_of(value.type) < 2) {
|
||||
@@ -526,7 +526,7 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
|
||||
gb_internal lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
|
||||
x = lb_emit_conv(p, x, type);
|
||||
|
||||
char const *name = "llvm.ctpop";
|
||||
@@ -539,7 +539,7 @@ lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type) {
|
||||
gb_internal lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type) {
|
||||
Type *elem = base_array_type(type);
|
||||
i64 sz = 8*type_size_of(elem);
|
||||
lbValue size = lb_const_int(p->module, elem, cast(u64)sz);
|
||||
@@ -550,7 +550,7 @@ lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type) {
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
|
||||
gb_internal lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
|
||||
x = lb_emit_conv(p, x, type);
|
||||
|
||||
char const *name = "llvm.cttz";
|
||||
@@ -566,7 +566,7 @@ lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) {
|
||||
gb_internal lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) {
|
||||
x = lb_emit_conv(p, x, type);
|
||||
|
||||
char const *name = "llvm.ctlz";
|
||||
@@ -584,7 +584,7 @@ lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) {
|
||||
|
||||
|
||||
|
||||
lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {
|
||||
gb_internal lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {
|
||||
x = lb_emit_conv(p, x, type);
|
||||
|
||||
char const *name = "llvm.bitreverse";
|
||||
@@ -599,15 +599,7 @@ lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x) {
|
||||
GB_ASSERT(is_type_bit_set(x.type));
|
||||
Type *underlying = bit_set_to_int(x.type);
|
||||
lbValue card = lb_emit_count_ones(p, x, underlying);
|
||||
return lb_emit_conv(p, card, t_int);
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
|
||||
gb_internal lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
|
||||
GB_ASSERT(is_type_tuple(type));
|
||||
lbModule *m = p->module;
|
||||
|
||||
@@ -654,7 +646,7 @@ lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *ty
|
||||
return lb_addr_load(p, v);
|
||||
}
|
||||
|
||||
lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
|
||||
gb_internal lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
Type *src_type = value.type;
|
||||
@@ -753,7 +745,7 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p
|
||||
return lb_addr_load(p, v);
|
||||
}
|
||||
|
||||
lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
|
||||
gb_internal lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
Type *src_type = value.type;
|
||||
@@ -826,13 +818,13 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos
|
||||
}
|
||||
return v;
|
||||
}
|
||||
lbValue lb_emit_any_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
|
||||
gb_internal lbValue lb_emit_any_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
|
||||
return lb_addr_load(p, lb_emit_any_cast_addr(p, value, type, pos));
|
||||
}
|
||||
|
||||
|
||||
|
||||
lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) {
|
||||
gb_internal lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) {
|
||||
if (p->context_stack.count > 0) {
|
||||
return p->context_stack[p->context_stack.count-1].ctx;
|
||||
}
|
||||
@@ -850,7 +842,7 @@ lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) {
|
||||
return c;
|
||||
}
|
||||
|
||||
lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) {
|
||||
gb_internal lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) {
|
||||
if (LLVMIsALoadInst(value.value)) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMGetOperand(value.value, 0);
|
||||
@@ -864,7 +856,7 @@ lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) {
|
||||
lb_addr_store(p, res, value);
|
||||
return res.addr;
|
||||
}
|
||||
lbValue lb_address_from_load(lbProcedure *p, lbValue value) {
|
||||
gb_internal lbValue lb_address_from_load(lbProcedure *p, lbValue value) {
|
||||
if (LLVMIsALoadInst(value.value)) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMGetOperand(value.value, 0);
|
||||
@@ -877,7 +869,7 @@ lbValue lb_address_from_load(lbProcedure *p, lbValue value) {
|
||||
}
|
||||
|
||||
|
||||
lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) {
|
||||
gb_internal lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) {
|
||||
t = base_type(t);
|
||||
LLVMTypeRef struct_type = lb_type(m, t);
|
||||
auto *field_remapping = map_get(&m->struct_field_remapping, cast(void *)struct_type);
|
||||
@@ -888,7 +880,7 @@ lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) {
|
||||
return *field_remapping;
|
||||
}
|
||||
|
||||
i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
|
||||
gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
|
||||
if (t->kind == Type_Struct) {
|
||||
auto field_remapping = lb_get_struct_remapping(m, t);
|
||||
index = field_remapping[index];
|
||||
@@ -896,7 +888,7 @@ i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
|
||||
return index;
|
||||
}
|
||||
|
||||
LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align) {
|
||||
gb_internal LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align) {
|
||||
// NOTE(bill): limit to `[N x u64]` to prevent ABI issues
|
||||
padding_align = gb_clamp(padding_align, 1, 8);
|
||||
if (padding % padding_align == 0) {
|
||||
@@ -921,7 +913,7 @@ LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align)
|
||||
}
|
||||
|
||||
|
||||
char const *llvm_type_kinds[] = {
|
||||
gb_global char const *llvm_type_kinds[] = {
|
||||
"LLVMVoidTypeKind",
|
||||
"LLVMHalfTypeKind",
|
||||
"LLVMFloatTypeKind",
|
||||
@@ -943,7 +935,55 @@ char const *llvm_type_kinds[] = {
|
||||
"LLVMBFloatTypeKind",
|
||||
};
|
||||
|
||||
lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
|
||||
gb_internal lbValue lb_emit_struct_ep_internal(lbProcedure *p, lbValue s, i32 index, Type *result_type) {
|
||||
Type *t = base_type(type_deref(s.type));
|
||||
|
||||
i32 original_index = index;
|
||||
index = lb_convert_struct_index(p->module, t, index);
|
||||
|
||||
if (lb_is_const(s)) {
|
||||
// NOTE(bill): this cannot be replaced with lb_emit_epi
|
||||
lbModule *m = p->module;
|
||||
lbValue res = {};
|
||||
LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)};
|
||||
res.value = LLVMConstGEP2(lb_type(m, type_deref(s.type)), s.value, indices, gb_count_of(indices));
|
||||
res.type = alloc_type_pointer(result_type);
|
||||
return res;
|
||||
} else {
|
||||
lbValue res = {};
|
||||
LLVMTypeRef st = lb_type(p->module, type_deref(s.type));
|
||||
// gb_printf_err("%s\n", type_to_string(s.type));
|
||||
// gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value)));
|
||||
// gb_printf_err("%d\n", index);
|
||||
GB_ASSERT_MSG(LLVMGetTypeKind(st) == LLVMStructTypeKind, "%s", llvm_type_kinds[LLVMGetTypeKind(st)]);
|
||||
unsigned count = LLVMCountStructElementTypes(st);
|
||||
GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index);
|
||||
|
||||
res.value = LLVMBuildStructGEP2(p->builder, st, s.value, cast(unsigned)index, "");
|
||||
res.type = alloc_type_pointer(result_type);
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_emit_tuple_ep(lbProcedure *p, lbValue ptr, i32 index) {
|
||||
Type *t = type_deref(ptr.type);
|
||||
GB_ASSERT(is_type_tuple(t));
|
||||
Type *result_type = t->Tuple.variables[index]->type;
|
||||
|
||||
lbValue res = {};
|
||||
lbTupleFix *tf = map_get(&p->tuple_fix_map, ptr.value);
|
||||
if (tf) {
|
||||
res = tf->values[index];
|
||||
GB_ASSERT(are_types_identical(res.type, result_type));
|
||||
res = lb_address_from_load_or_generate_local(p, res);
|
||||
} else {
|
||||
res = lb_emit_struct_ep_internal(p, ptr, index, result_type);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
|
||||
GB_ASSERT(is_type_pointer(s.type));
|
||||
Type *t = base_type(type_deref(s.type));
|
||||
Type *result_type = nullptr;
|
||||
@@ -958,8 +998,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
|
||||
GB_ASSERT(index == -1);
|
||||
return lb_emit_union_tag_ptr(p, s);
|
||||
} else if (is_type_tuple(t)) {
|
||||
GB_ASSERT(t->Tuple.variables.count > 0);
|
||||
result_type = t->Tuple.variables[index]->type;
|
||||
return lb_emit_tuple_ep(p, s, index);
|
||||
} else if (is_type_complex(t)) {
|
||||
Type *ft = base_complex_elem_type(t);
|
||||
switch (index) {
|
||||
@@ -1024,34 +1063,45 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
|
||||
|
||||
GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index);
|
||||
|
||||
i32 original_index = index;
|
||||
index = lb_convert_struct_index(p->module, t, index);
|
||||
|
||||
if (lb_is_const(s)) {
|
||||
// NOTE(bill): this cannot be replaced with lb_emit_epi
|
||||
lbModule *m = p->module;
|
||||
lbValue res = {};
|
||||
LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)};
|
||||
res.value = LLVMConstGEP2(lb_type(m, type_deref(s.type)), s.value, indices, gb_count_of(indices));
|
||||
res.type = alloc_type_pointer(result_type);
|
||||
return res;
|
||||
} else {
|
||||
lbValue res = {};
|
||||
LLVMTypeRef st = lb_type(p->module, type_deref(s.type));
|
||||
// gb_printf_err("%s\n", type_to_string(s.type));
|
||||
// gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value)));
|
||||
// gb_printf_err("%d\n", index);
|
||||
GB_ASSERT_MSG(LLVMGetTypeKind(st) == LLVMStructTypeKind, "%s", llvm_type_kinds[LLVMGetTypeKind(st)]);
|
||||
unsigned count = LLVMCountStructElementTypes(st);
|
||||
GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index);
|
||||
|
||||
res.value = LLVMBuildStructGEP2(p->builder, st, s.value, cast(unsigned)index, "");
|
||||
res.type = alloc_type_pointer(result_type);
|
||||
return res;
|
||||
}
|
||||
return lb_emit_struct_ep_internal(p, s, index, result_type);
|
||||
}
|
||||
|
||||
lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
|
||||
gb_internal lbValue lb_emit_tuple_ev(lbProcedure *p, lbValue value, i32 index) {
|
||||
Type *t = value.type;
|
||||
GB_ASSERT(is_type_tuple(t));
|
||||
Type *result_type = t->Tuple.variables[index]->type;
|
||||
|
||||
lbValue res = {};
|
||||
lbTupleFix *tf = map_get(&p->tuple_fix_map, value.value);
|
||||
if (tf) {
|
||||
res = tf->values[index];
|
||||
GB_ASSERT(are_types_identical(res.type, result_type));
|
||||
} else {
|
||||
if (t->Tuple.variables.count == 1) {
|
||||
GB_ASSERT(index == 0);
|
||||
// value.type = result_type;
|
||||
return value;
|
||||
}
|
||||
if (LLVMIsALoadInst(value.value)) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMGetOperand(value.value, 0);
|
||||
res.type = alloc_type_pointer(value.type);
|
||||
lbValue ptr = lb_emit_struct_ep(p, res, index);
|
||||
return lb_emit_load(p, ptr);
|
||||
}
|
||||
|
||||
res.value = LLVMBuildExtractValue(p->builder, value.value, cast(unsigned)index, "");
|
||||
res.type = result_type;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
|
||||
Type *t = base_type(s.type);
|
||||
if (is_type_tuple(t)) {
|
||||
return lb_emit_tuple_ev(p, s, index);
|
||||
}
|
||||
|
||||
if (LLVMIsALoadInst(s.value)) {
|
||||
lbValue res = {};
|
||||
res.value = LLVMGetOperand(s.value, 0);
|
||||
@@ -1060,7 +1110,6 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
|
||||
return lb_emit_load(p, ptr);
|
||||
}
|
||||
|
||||
Type *t = base_type(s.type);
|
||||
Type *result_type = nullptr;
|
||||
|
||||
switch (t->kind) {
|
||||
@@ -1113,12 +1162,7 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
|
||||
GB_PANIC("lb_emit_union_tag_value");
|
||||
|
||||
case Type_Tuple:
|
||||
GB_ASSERT(t->Tuple.variables.count > 0);
|
||||
result_type = t->Tuple.variables[index]->type;
|
||||
if (t->Tuple.variables.count == 1) {
|
||||
return s;
|
||||
}
|
||||
break;
|
||||
return lb_emit_tuple_ev(p, s, index);
|
||||
case Type_Slice:
|
||||
switch (index) {
|
||||
case 0: result_type = alloc_type_pointer(t->Slice.elem); break;
|
||||
@@ -1171,7 +1215,7 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
|
||||
gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
|
||||
GB_ASSERT(sel.index.count > 0);
|
||||
Type *type = type_deref(e.type);
|
||||
|
||||
@@ -1259,14 +1303,14 @@ lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel) {
|
||||
gb_internal lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel) {
|
||||
lbValue ptr = lb_address_from_load_or_generate_local(p, e);
|
||||
lbValue res = lb_emit_deep_field_gep(p, ptr, sel);
|
||||
return lb_emit_load(p, res);
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) {
|
||||
gb_internal lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) {
|
||||
Type *t = s.type;
|
||||
GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t));
|
||||
Type *st = base_type(type_deref(t));
|
||||
@@ -1289,7 +1333,7 @@ lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) {
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) {
|
||||
gb_internal lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) {
|
||||
Type *t = s.type;
|
||||
GB_ASSERT(is_type_pointer(t));
|
||||
Type *st = base_type(type_deref(t));
|
||||
@@ -1297,7 +1341,7 @@ lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) {
|
||||
GB_ASSERT(0 <= index);
|
||||
return lb_emit_epi(p, s, index);
|
||||
}
|
||||
lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) {
|
||||
gb_internal lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) {
|
||||
Type *t = s.type;
|
||||
GB_ASSERT(is_type_pointer(t));
|
||||
Type *st = base_type(type_deref(t));
|
||||
@@ -1306,7 +1350,7 @@ lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) {
|
||||
return lb_emit_epi(m, s, index);
|
||||
}
|
||||
|
||||
lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
|
||||
gb_internal lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
|
||||
index = lb_emit_conv(p, index, t_int);
|
||||
LLVMValueRef indices[1] = {index.value};
|
||||
lbValue res = {};
|
||||
@@ -1321,7 +1365,7 @@ lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
|
||||
return res;
|
||||
}
|
||||
|
||||
lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) {
|
||||
gb_internal lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) {
|
||||
Type *t = s.type;
|
||||
GB_ASSERT(is_type_pointer(t));
|
||||
Type *mt = base_type(type_deref(t));
|
||||
@@ -1339,7 +1383,7 @@ lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) {
|
||||
return lb_emit_epi(p, s, offset);
|
||||
}
|
||||
|
||||
lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) {
|
||||
gb_internal lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) {
|
||||
Type *t = s.type;
|
||||
GB_ASSERT(is_type_pointer(t));
|
||||
Type *mt = base_type(type_deref(t));
|
||||
@@ -1371,7 +1415,7 @@ lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column) {
|
||||
gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column) {
|
||||
Type *st = base_type(s.type);
|
||||
GB_ASSERT_MSG(is_type_matrix(st), "%s", type_to_string(st));
|
||||
|
||||
@@ -1381,14 +1425,14 @@ lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column) {
|
||||
}
|
||||
|
||||
|
||||
void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len) {
|
||||
gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len) {
|
||||
Type *t = lb_addr_type(slice);
|
||||
GB_ASSERT(is_type_slice(t));
|
||||
lbValue ptr = lb_addr_get_ptr(p, slice);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem);
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len);
|
||||
}
|
||||
void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbValue len) {
|
||||
gb_internal void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbValue len) {
|
||||
Type *t = lb_addr_type(string);
|
||||
GB_ASSERT(is_type_string(t));
|
||||
lbValue ptr = lb_addr_get_ptr(p, string);
|
||||
@@ -1396,18 +1440,18 @@ void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbV
|
||||
lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len);
|
||||
}
|
||||
|
||||
lbValue lb_string_elem(lbProcedure *p, lbValue string) {
|
||||
gb_internal lbValue lb_string_elem(lbProcedure *p, lbValue string) {
|
||||
Type *t = base_type(string.type);
|
||||
GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string);
|
||||
return lb_emit_struct_ev(p, string, 0);
|
||||
}
|
||||
lbValue lb_string_len(lbProcedure *p, lbValue string) {
|
||||
gb_internal lbValue lb_string_len(lbProcedure *p, lbValue string) {
|
||||
Type *t = base_type(string.type);
|
||||
GB_ASSERT_MSG(t->kind == Type_Basic && t->Basic.kind == Basic_string, "%s", type_to_string(t));
|
||||
return lb_emit_struct_ev(p, string, 1);
|
||||
}
|
||||
|
||||
lbValue lb_cstring_len(lbProcedure *p, lbValue value) {
|
||||
gb_internal lbValue lb_cstring_len(lbProcedure *p, lbValue value) {
|
||||
GB_ASSERT(is_type_cstring(value.type));
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 1);
|
||||
args[0] = lb_emit_conv(p, value, t_cstring);
|
||||
@@ -1415,43 +1459,39 @@ lbValue lb_cstring_len(lbProcedure *p, lbValue value) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr) {
|
||||
gb_internal lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr) {
|
||||
Type *t = type_deref(array_ptr.type);
|
||||
GB_ASSERT(is_type_array(t));
|
||||
return lb_emit_struct_ep(p, array_ptr, 0);
|
||||
}
|
||||
|
||||
lbValue lb_slice_elem(lbProcedure *p, lbValue slice) {
|
||||
gb_internal lbValue lb_slice_elem(lbProcedure *p, lbValue slice) {
|
||||
GB_ASSERT(is_type_slice(slice.type));
|
||||
return lb_emit_struct_ev(p, slice, 0);
|
||||
}
|
||||
lbValue lb_slice_len(lbProcedure *p, lbValue slice) {
|
||||
gb_internal lbValue lb_slice_len(lbProcedure *p, lbValue slice) {
|
||||
GB_ASSERT(is_type_slice(slice.type) || is_type_relative_slice(slice.type));
|
||||
return lb_emit_struct_ev(p, slice, 1);
|
||||
}
|
||||
lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) {
|
||||
gb_internal lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) {
|
||||
GB_ASSERT(is_type_dynamic_array(da.type));
|
||||
return lb_emit_struct_ev(p, da, 0);
|
||||
}
|
||||
lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da) {
|
||||
gb_internal lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da) {
|
||||
GB_ASSERT(is_type_dynamic_array(da.type));
|
||||
return lb_emit_struct_ev(p, da, 1);
|
||||
}
|
||||
lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da) {
|
||||
gb_internal lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da) {
|
||||
GB_ASSERT(is_type_dynamic_array(da.type));
|
||||
return lb_emit_struct_ev(p, da, 2);
|
||||
}
|
||||
lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da) {
|
||||
GB_ASSERT(is_type_dynamic_array(da.type));
|
||||
return lb_emit_struct_ev(p, da, 3);
|
||||
}
|
||||
|
||||
lbValue lb_map_len(lbProcedure *p, lbValue value) {
|
||||
gb_internal lbValue lb_map_len(lbProcedure *p, lbValue value) {
|
||||
GB_ASSERT_MSG(is_type_map(value.type) || are_types_identical(value.type, t_raw_map), "%s", type_to_string(value.type));
|
||||
lbValue len = lb_emit_struct_ev(p, value, 1);
|
||||
return lb_emit_conv(p, len, t_int);
|
||||
}
|
||||
lbValue lb_map_len_ptr(lbProcedure *p, lbValue map_ptr) {
|
||||
gb_internal lbValue lb_map_len_ptr(lbProcedure *p, lbValue map_ptr) {
|
||||
Type *type = map_ptr.type;
|
||||
GB_ASSERT(is_type_pointer(type));
|
||||
type = type_deref(type);
|
||||
@@ -1459,7 +1499,7 @@ lbValue lb_map_len_ptr(lbProcedure *p, lbValue map_ptr) {
|
||||
return lb_emit_struct_ep(p, map_ptr, 1);
|
||||
}
|
||||
|
||||
lbValue lb_map_cap(lbProcedure *p, lbValue value) {
|
||||
gb_internal lbValue lb_map_cap(lbProcedure *p, lbValue value) {
|
||||
GB_ASSERT_MSG(is_type_map(value.type) || are_types_identical(value.type, t_raw_map), "%s", type_to_string(value.type));
|
||||
lbValue zero = lb_const_int(p->module, t_uintptr, 0);
|
||||
lbValue one = lb_const_int(p->module, t_uintptr, 1);
|
||||
@@ -1473,7 +1513,7 @@ lbValue lb_map_cap(lbProcedure *p, lbValue value) {
|
||||
return lb_emit_conv(p, lb_emit_select(p, cmp, zero, cap), t_int);
|
||||
}
|
||||
|
||||
lbValue lb_map_data_uintptr(lbProcedure *p, lbValue value) {
|
||||
gb_internal lbValue lb_map_data_uintptr(lbProcedure *p, lbValue value) {
|
||||
GB_ASSERT(is_type_map(value.type) || are_types_identical(value.type, t_raw_map));
|
||||
lbValue data = lb_emit_struct_ev(p, value, 0);
|
||||
u64 mask_value = 0;
|
||||
@@ -1487,7 +1527,7 @@ lbValue lb_map_data_uintptr(lbProcedure *p, lbValue value) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_soa_struct_len(lbProcedure *p, lbValue value) {
|
||||
gb_internal lbValue lb_soa_struct_len(lbProcedure *p, lbValue value) {
|
||||
Type *t = base_type(value.type);
|
||||
bool is_ptr = false;
|
||||
if (is_type_pointer(t)) {
|
||||
@@ -1520,7 +1560,7 @@ lbValue lb_soa_struct_len(lbProcedure *p, lbValue value) {
|
||||
return lb_emit_struct_ev(p, value, cast(i32)n);
|
||||
}
|
||||
|
||||
lbValue lb_soa_struct_cap(lbProcedure *p, lbValue value) {
|
||||
gb_internal lbValue lb_soa_struct_cap(lbProcedure *p, lbValue value) {
|
||||
Type *t = base_type(value.type);
|
||||
|
||||
bool is_ptr = false;
|
||||
@@ -1552,7 +1592,7 @@ lbValue lb_soa_struct_cap(lbProcedure *p, lbValue value) {
|
||||
return lb_emit_struct_ev(p, value, cast(i32)n);
|
||||
}
|
||||
|
||||
lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t) {
|
||||
gb_internal lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t) {
|
||||
lbModule *m = p->module;
|
||||
|
||||
a = lb_emit_conv(p, a, t);
|
||||
@@ -1595,7 +1635,7 @@ lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_mask_iota(lbModule *m, unsigned start, unsigned count) {
|
||||
gb_internal LLVMValueRef llvm_mask_iota(lbModule *m, unsigned start, unsigned count) {
|
||||
auto iota = slice_make<LLVMValueRef>(temporary_allocator(), count);
|
||||
for (unsigned i = 0; i < count; i++) {
|
||||
iota[i] = lb_const_int(m, t_u32, start+i).value;
|
||||
@@ -1603,7 +1643,7 @@ LLVMValueRef llvm_mask_iota(lbModule *m, unsigned start, unsigned count) {
|
||||
return LLVMConstVector(iota.data, count);
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_mask_zero(lbModule *m, unsigned count) {
|
||||
gb_internal LLVMValueRef llvm_mask_zero(lbModule *m, unsigned count) {
|
||||
return LLVMConstNull(LLVMVectorType(lb_type(m, t_u32), count));
|
||||
}
|
||||
|
||||
@@ -1611,16 +1651,16 @@ LLVMValueRef llvm_mask_zero(lbModule *m, unsigned count) {
|
||||
// #define LLVM_VECTOR_DUMMY_VALUE(type) LLVMConstNull((type))
|
||||
|
||||
|
||||
LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask) {
|
||||
gb_internal LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask) {
|
||||
return LLVMBuildShuffleVector(p->builder, vector, LLVM_VECTOR_DUMMY_VALUE(LLVMTypeOf(vector)), mask, "");
|
||||
}
|
||||
LLVMValueRef llvm_basic_const_shuffle(LLVMValueRef vector, LLVMValueRef mask) {
|
||||
gb_internal LLVMValueRef llvm_basic_const_shuffle(LLVMValueRef vector, LLVMValueRef mask) {
|
||||
return LLVMConstShuffleVector(vector, LLVM_VECTOR_DUMMY_VALUE(LLVMTypeOf(vector)), mask);
|
||||
}
|
||||
|
||||
|
||||
|
||||
LLVMValueRef llvm_vector_broadcast(lbProcedure *p, LLVMValueRef value, unsigned count) {
|
||||
gb_internal LLVMValueRef llvm_vector_broadcast(lbProcedure *p, LLVMValueRef value, unsigned count) {
|
||||
GB_ASSERT(count > 0);
|
||||
if (LLVMIsConstant(value)) {
|
||||
LLVMValueRef single = LLVMConstVector(&value, 1);
|
||||
@@ -1640,7 +1680,7 @@ LLVMValueRef llvm_vector_broadcast(lbProcedure *p, LLVMValueRef value, unsigned
|
||||
return llvm_basic_shuffle(p, single, mask);
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_vector_shuffle_reduction(lbProcedure *p, LLVMValueRef value, LLVMOpcode op_code) {
|
||||
gb_internal LLVMValueRef llvm_vector_shuffle_reduction(lbProcedure *p, LLVMValueRef value, LLVMOpcode op_code) {
|
||||
LLVMTypeRef original_vector_type = LLVMTypeOf(value);
|
||||
|
||||
GB_ASSERT(LLVMGetTypeKind(original_vector_type) == LLVMVectorTypeKind);
|
||||
@@ -1667,7 +1707,7 @@ LLVMValueRef llvm_vector_shuffle_reduction(lbProcedure *p, LLVMValueRef value, L
|
||||
return LLVMBuildExtractElement(p->builder, value, v_zero32, "");
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef value) {
|
||||
gb_internal LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef value) {
|
||||
LLVMTypeRef vector_type = LLVMTypeOf(value);
|
||||
unsigned len = LLVMGetVectorSize(vector_type);
|
||||
if (len == 1) {
|
||||
@@ -1682,7 +1722,7 @@ LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef val
|
||||
return LLVMBuildShuffleVector(p->builder, value, LLVMConstNull(vector_type), mask, "");
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
|
||||
gb_internal LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
|
||||
LLVMTypeRef type = LLVMTypeOf(value);
|
||||
GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind);
|
||||
LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
|
||||
@@ -1758,7 +1798,7 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
|
||||
#endif
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
|
||||
gb_internal LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
|
||||
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
|
||||
|
||||
LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
|
||||
@@ -1769,7 +1809,7 @@ LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
|
||||
return LLVMBuildFAdd(p->builder, a, b, "");
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
|
||||
gb_internal LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
|
||||
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
|
||||
|
||||
LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
|
||||
@@ -1781,11 +1821,11 @@ LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
|
||||
}
|
||||
|
||||
|
||||
LLVMValueRef llvm_vector_dot(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
|
||||
gb_internal LLVMValueRef llvm_vector_dot(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
|
||||
return llvm_vector_reduce_add(p, llvm_vector_mul(p, a, b));
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, LLVMValueRef c) {
|
||||
gb_internal LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, LLVMValueRef c) {
|
||||
|
||||
LLVMTypeRef t = LLVMTypeOf(a);
|
||||
GB_ASSERT(t == LLVMTypeOf(b));
|
||||
@@ -1819,7 +1859,7 @@ LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b,
|
||||
}
|
||||
}
|
||||
|
||||
LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, String const &clobbers, bool has_side_effects=true, bool is_align_stack=false, LLVMInlineAsmDialect dialect=LLVMInlineAsmDialectATT) {
|
||||
gb_internal LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, String const &clobbers, bool has_side_effects=true, bool is_align_stack=false, LLVMInlineAsmDialect dialect=LLVMInlineAsmDialectATT) {
|
||||
return LLVMGetInlineAsm(func_type,
|
||||
cast(char *)str.text, cast(size_t)str.len,
|
||||
cast(char *)clobbers.text, cast(size_t)clobbers.len,
|
||||
@@ -1832,7 +1872,7 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin
|
||||
}
|
||||
|
||||
|
||||
void lb_set_wasm_import_attributes(LLVMValueRef value, Entity *entity, String import_name) {
|
||||
gb_internal void lb_set_wasm_import_attributes(LLVMValueRef value, Entity *entity, String import_name) {
|
||||
if (!is_arch_wasm()) {
|
||||
return;
|
||||
}
|
||||
@@ -1854,7 +1894,7 @@ void lb_set_wasm_import_attributes(LLVMValueRef value, Entity *entity, String im
|
||||
}
|
||||
|
||||
|
||||
void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) {
|
||||
gb_internal void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) {
|
||||
if (!is_arch_wasm()) {
|
||||
return;
|
||||
}
|
||||
@@ -1866,7 +1906,7 @@ void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) {
|
||||
|
||||
|
||||
|
||||
lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
|
||||
gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
|
||||
lbAddr *found = string_map_get(&p->module->objc_selectors, name);
|
||||
if (found) {
|
||||
return *found;
|
||||
@@ -1886,7 +1926,7 @@ lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &na
|
||||
}
|
||||
}
|
||||
|
||||
lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
|
||||
ast_node(ce, CallExpr, expr);
|
||||
|
||||
auto tav = ce->args[0]->tav;
|
||||
@@ -1895,7 +1935,7 @@ lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
|
||||
return lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, name));
|
||||
}
|
||||
|
||||
lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) {
|
||||
ast_node(ce, CallExpr, expr);
|
||||
lbModule *m = p->module;
|
||||
|
||||
@@ -1912,7 +1952,7 @@ lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) {
|
||||
return lb_addr_load(p, dst);
|
||||
}
|
||||
|
||||
lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) {
|
||||
gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) {
|
||||
lbAddr *found = string_map_get(&p->module->objc_classes, name);
|
||||
if (found) {
|
||||
return *found;
|
||||
@@ -1932,7 +1972,7 @@ lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name)
|
||||
}
|
||||
}
|
||||
|
||||
lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
|
||||
ast_node(ce, CallExpr, expr);
|
||||
|
||||
auto tav = ce->args[0]->tav;
|
||||
@@ -1941,7 +1981,7 @@ lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
|
||||
return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name));
|
||||
}
|
||||
|
||||
lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) {
|
||||
ast_node(ce, CallExpr, expr);
|
||||
lbModule *m = p->module;
|
||||
|
||||
@@ -1961,7 +2001,7 @@ lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
|
||||
|
||||
lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
|
||||
TypeAndValue const &tav = type_and_value_of_expr(expr);
|
||||
if (tav.mode == Addressing_Type) {
|
||||
Type *type = tav.type;
|
||||
@@ -1992,7 +2032,7 @@ lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
|
||||
return lb_build_expr(p, expr);
|
||||
}
|
||||
|
||||
lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) {
|
||||
gb_internal lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) {
|
||||
ast_node(ce, CallExpr, expr);
|
||||
|
||||
lbModule *m = p->module;
|
||||
@@ -2035,7 +2075,7 @@ lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) {
|
||||
|
||||
|
||||
|
||||
LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) {
|
||||
gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) {
|
||||
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||
i64 v = exact_value_to_i64(value);
|
||||
switch (v) {
|
||||
@@ -2051,7 +2091,7 @@ LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) {
|
||||
}
|
||||
|
||||
|
||||
LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) {
|
||||
gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) {
|
||||
ExactValue value = type_and_value_of_expr(expr).value;
|
||||
return llvm_atomic_ordering_from_odin(value);
|
||||
}
|
||||
|
||||
+124
-204
@@ -3,31 +3,41 @@
|
||||
#include "common.cpp"
|
||||
#include "timings.cpp"
|
||||
#include "tokenizer.cpp"
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable: 4505)
|
||||
#endif
|
||||
#include "big_int.cpp"
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
#pragma warning(pop)
|
||||
#endif
|
||||
#include "exact_value.cpp"
|
||||
#include "build_settings.cpp"
|
||||
|
||||
gb_global ThreadPool global_thread_pool;
|
||||
void init_global_thread_pool(void) {
|
||||
gb_internal void init_global_thread_pool(void) {
|
||||
isize thread_count = gb_max(build_context.thread_count, 1);
|
||||
isize worker_count = thread_count-1; // NOTE(bill): The main thread will also be used for work
|
||||
thread_pool_init(&global_thread_pool, permanent_allocator(), worker_count, "ThreadPoolWorker");
|
||||
isize worker_count = thread_count; // +1
|
||||
thread_pool_init(&global_thread_pool, worker_count, "ThreadPoolWorker");
|
||||
}
|
||||
bool global_thread_pool_add_task(WorkerTaskProc *proc, void *data) {
|
||||
gb_internal bool thread_pool_add_task(WorkerTaskProc *proc, void *data) {
|
||||
return thread_pool_add_task(&global_thread_pool, proc, data);
|
||||
}
|
||||
void global_thread_pool_wait(void) {
|
||||
gb_internal void thread_pool_wait(void) {
|
||||
thread_pool_wait(&global_thread_pool);
|
||||
}
|
||||
|
||||
|
||||
void debugf(char const *fmt, ...) {
|
||||
gb_global BlockingMutex debugf_mutex;
|
||||
|
||||
gb_internal void debugf(char const *fmt, ...) {
|
||||
if (build_context.show_debug_messages) {
|
||||
mutex_lock(&debugf_mutex);
|
||||
gb_printf_err("[DEBUG] ");
|
||||
va_list va;
|
||||
va_start(va, fmt);
|
||||
(void)gb_printf_err_va(fmt, va);
|
||||
va_end(va);
|
||||
mutex_unlock(&debugf_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -58,11 +68,10 @@ gb_global Timings global_timings = {0};
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "query_data.cpp"
|
||||
#include "bug_report.cpp"
|
||||
|
||||
// NOTE(bill): 'name' is used in debugging and profiling modes
|
||||
i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
|
||||
gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
|
||||
isize const cmd_cap = 64<<20; // 64 MiB should be more than enough
|
||||
char *cmd_line = gb_alloc_array(gb_heap_allocator(), char, cmd_cap);
|
||||
isize cmd_len = 0;
|
||||
@@ -124,7 +133,7 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
|
||||
}
|
||||
|
||||
|
||||
i32 linker_stage(lbGenerator *gen) {
|
||||
gb_internal i32 linker_stage(lbGenerator *gen) {
|
||||
i32 result = 0;
|
||||
Timings *timings = &global_timings;
|
||||
|
||||
@@ -207,15 +216,14 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
|
||||
|
||||
StringSet libs = {};
|
||||
string_set_init(&libs, heap_allocator(), 64);
|
||||
string_set_init(&libs, 64);
|
||||
defer (string_set_destroy(&libs));
|
||||
|
||||
StringSet asm_files = {};
|
||||
string_set_init(&asm_files, heap_allocator(), 64);
|
||||
string_set_init(&asm_files, 64);
|
||||
defer (string_set_destroy(&asm_files));
|
||||
|
||||
for_array(j, gen->foreign_libraries) {
|
||||
Entity *e = gen->foreign_libraries[j];
|
||||
for (Entity *e : gen->foreign_libraries) {
|
||||
GB_ASSERT(e->kind == Entity_LibraryName);
|
||||
for_array(i, e->LibraryName.paths) {
|
||||
String lib = string_trim_whitespace(e->LibraryName.paths[i]);
|
||||
@@ -278,8 +286,7 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
|
||||
gbString object_files = gb_string_make(heap_allocator(), "");
|
||||
defer (gb_string_free(object_files));
|
||||
for_array(i, gen->output_object_paths) {
|
||||
String object_path = gen->output_object_paths[i];
|
||||
for (String const &object_path : gen->output_object_paths) {
|
||||
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
|
||||
}
|
||||
|
||||
@@ -313,12 +320,18 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
}
|
||||
}
|
||||
|
||||
switch (build_context.build_mode) {
|
||||
case BuildMode_Executable:
|
||||
link_settings = gb_string_append_fmt(link_settings, " /NOIMPLIB /NOEXP");
|
||||
break;
|
||||
}
|
||||
|
||||
result = system_exec_command_line_app("msvc-link",
|
||||
"\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
" %.*s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
"%.*s "
|
||||
"%.*s "
|
||||
"%s "
|
||||
"",
|
||||
LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename),
|
||||
link_settings,
|
||||
@@ -334,9 +347,9 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
result = system_exec_command_line_app("msvc-lld-link",
|
||||
"\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
|
||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||
" %.*s "
|
||||
" %.*s "
|
||||
" %s "
|
||||
"%.*s "
|
||||
"%.*s "
|
||||
"%s "
|
||||
"",
|
||||
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
|
||||
link_settings,
|
||||
@@ -366,14 +379,13 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
defer (gb_string_free(lib_str));
|
||||
|
||||
StringSet libs = {};
|
||||
string_set_init(&libs, heap_allocator(), 64);
|
||||
string_set_init(&libs, 64);
|
||||
defer (string_set_destroy(&libs));
|
||||
|
||||
for_array(j, gen->foreign_libraries) {
|
||||
Entity *e = gen->foreign_libraries[j];
|
||||
for (Entity *e : gen->foreign_libraries) {
|
||||
GB_ASSERT(e->kind == Entity_LibraryName);
|
||||
for_array(i, e->LibraryName.paths) {
|
||||
String lib = string_trim_whitespace(e->LibraryName.paths[i]);
|
||||
for (String lib : e->LibraryName.paths) {
|
||||
lib = string_trim_whitespace(lib);
|
||||
if (lib.len == 0) {
|
||||
continue;
|
||||
}
|
||||
@@ -425,8 +437,7 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
|
||||
gbString object_files = gb_string_make(heap_allocator(), "");
|
||||
defer (gb_string_free(object_files));
|
||||
for_array(i, gen->output_object_paths) {
|
||||
String object_path = gen->output_object_paths[i];
|
||||
for (String object_path : gen->output_object_paths) {
|
||||
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
|
||||
}
|
||||
|
||||
@@ -524,7 +535,7 @@ i32 linker_stage(lbGenerator *gen) {
|
||||
return result;
|
||||
}
|
||||
|
||||
Array<String> setup_args(int argc, char const **argv) {
|
||||
gb_internal Array<String> setup_args(int argc, char const **argv) {
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
@@ -553,7 +564,7 @@ Array<String> setup_args(int argc, char const **argv) {
|
||||
#endif
|
||||
}
|
||||
|
||||
void print_usage_line(i32 indent, char const *fmt, ...) {
|
||||
gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
|
||||
while (indent --> 0) {
|
||||
gb_printf_err("\t");
|
||||
}
|
||||
@@ -564,7 +575,7 @@ void print_usage_line(i32 indent, char const *fmt, ...) {
|
||||
gb_printf_err("\n");
|
||||
}
|
||||
|
||||
void usage(String argv0) {
|
||||
gb_internal void usage(String argv0) {
|
||||
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0));
|
||||
print_usage_line(0, "Usage:");
|
||||
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
|
||||
@@ -573,7 +584,6 @@ void usage(String argv0) {
|
||||
print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
|
||||
print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
|
||||
print_usage_line(1, "check parse, and type check a directory of .odin files");
|
||||
print_usage_line(1, "query parse, type check, and output a .json file containing information about the program");
|
||||
print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program");
|
||||
print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package");
|
||||
print_usage_line(1, "doc generate documentation on a directory of .odin files");
|
||||
@@ -613,7 +623,6 @@ enum BuildFlagKind {
|
||||
BuildFlag_NoEntryPoint,
|
||||
BuildFlag_UseLLD,
|
||||
BuildFlag_UseSeparateModules,
|
||||
BuildFlag_ThreadedChecker,
|
||||
BuildFlag_NoThreadedChecker,
|
||||
BuildFlag_ShowDebugMessages,
|
||||
BuildFlag_Vet,
|
||||
@@ -655,6 +664,7 @@ enum BuildFlagKind {
|
||||
|
||||
// internal use only
|
||||
BuildFlag_InternalIgnoreLazy,
|
||||
BuildFlag_InternalIgnoreLLVMBuild,
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
BuildFlag_IgnoreVsSearch,
|
||||
@@ -687,12 +697,12 @@ struct BuildFlag {
|
||||
};
|
||||
|
||||
|
||||
void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_mulitple=false) {
|
||||
gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_mulitple=false) {
|
||||
BuildFlag flag = {kind, name, param_kind, command_support, allow_mulitple};
|
||||
array_add(build_flags, flag);
|
||||
}
|
||||
|
||||
ExactValue build_param_to_exact_value(String name, String param) {
|
||||
gb_internal ExactValue build_param_to_exact_value(String name, String param) {
|
||||
ExactValue value = {};
|
||||
|
||||
/*
|
||||
@@ -747,7 +757,7 @@ ExactValue build_param_to_exact_value(String name, String param) {
|
||||
}
|
||||
|
||||
// Writes a did-you-mean message for formerly deprecated flags.
|
||||
void did_you_mean_flag(String flag) {
|
||||
gb_internal void did_you_mean_flag(String flag) {
|
||||
gbAllocator a = heap_allocator();
|
||||
String name = copy_string(a, flag);
|
||||
defer (gb_free(a, name.text));
|
||||
@@ -760,11 +770,11 @@ void did_you_mean_flag(String flag) {
|
||||
gb_printf_err("Unknown flag: '%.*s'\n", LIT(flag));
|
||||
}
|
||||
|
||||
bool parse_build_flags(Array<String> args) {
|
||||
gb_internal bool parse_build_flags(Array<String> args) {
|
||||
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
|
||||
add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_SingleFile, str_lit("file"), BuildFlagParam_None, Command__does_build | Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build &~ Command_test);
|
||||
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test);
|
||||
add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("O"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check);
|
||||
@@ -788,7 +798,6 @@ bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test);
|
||||
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_ThreadedChecker, str_lit("threaded-checker"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check);
|
||||
@@ -817,12 +826,6 @@ bool parse_build_flags(Array<String> args) {
|
||||
|
||||
add_flag(&build_flags, BuildFlag_UseStaticMapCalls, str_lit("use-static-map-calls"), BuildFlagParam_None, Command__does_check);
|
||||
|
||||
|
||||
add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query);
|
||||
add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query);
|
||||
add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query);
|
||||
|
||||
|
||||
add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc);
|
||||
add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc);
|
||||
add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc);
|
||||
@@ -833,6 +836,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_ErrorPosStyle, str_lit("error-pos-style"), BuildFlagParam_String, Command_all);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
|
||||
add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all);
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build);
|
||||
@@ -848,8 +852,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
bool set_flags[BuildFlag_COUNT] = {};
|
||||
|
||||
bool bad_flags = false;
|
||||
for_array(i, flag_args) {
|
||||
String flag = flag_args[i];
|
||||
for (String flag : flag_args) {
|
||||
if (flag[0] != '-') {
|
||||
gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
|
||||
continue;
|
||||
@@ -878,8 +881,7 @@ bool parse_build_flags(Array<String> args) {
|
||||
bool found = false;
|
||||
|
||||
BuildFlag found_bf = {};
|
||||
for_array(build_flag_index, build_flags) {
|
||||
BuildFlag bf = build_flags[build_flag_index];
|
||||
for (BuildFlag const &bf : build_flags) {
|
||||
if (bf.name == name) {
|
||||
found = true;
|
||||
found_bf = bf;
|
||||
@@ -1311,20 +1313,8 @@ bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_UseSeparateModules:
|
||||
build_context.use_separate_modules = true;
|
||||
break;
|
||||
case BuildFlag_ThreadedChecker: {
|
||||
#if defined(DEFAULT_TO_THREADED_CHECKER)
|
||||
gb_printf_err("-threaded-checker is the default on this platform\n");
|
||||
bad_flags = true;
|
||||
#endif
|
||||
build_context.threaded_checker = true;
|
||||
break;
|
||||
}
|
||||
case BuildFlag_NoThreadedChecker: {
|
||||
#if !defined(DEFAULT_TO_THREADED_CHECKER)
|
||||
gb_printf_err("-no-threaded-checker is the default on this platform\n");
|
||||
bad_flags = true;
|
||||
#endif
|
||||
build_context.threaded_checker = false;
|
||||
build_context.no_threaded_checker = true;
|
||||
break;
|
||||
}
|
||||
case BuildFlag_ShowDebugMessages:
|
||||
@@ -1445,39 +1435,6 @@ bool parse_build_flags(Array<String> args) {
|
||||
build_context.strict_style_init_only = true;
|
||||
break;
|
||||
}
|
||||
case BuildFlag_Compact: {
|
||||
if (!build_context.query_data_set_settings.ok) {
|
||||
gb_printf_err("Invalid use of -compact flag, only allowed with 'odin query'\n");
|
||||
bad_flags = true;
|
||||
} else {
|
||||
build_context.query_data_set_settings.compact = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BuildFlag_GlobalDefinitions: {
|
||||
if (!build_context.query_data_set_settings.ok) {
|
||||
gb_printf_err("Invalid use of -global-definitions flag, only allowed with 'odin query'\n");
|
||||
bad_flags = true;
|
||||
} else if (build_context.query_data_set_settings.kind != QueryDataSet_Invalid) {
|
||||
gb_printf_err("Invalid use of -global-definitions flag, a previous flag for 'odin query' was set\n");
|
||||
bad_flags = true;
|
||||
} else {
|
||||
build_context.query_data_set_settings.kind = QueryDataSet_GlobalDefinitions;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BuildFlag_GoToDefinitions: {
|
||||
if (!build_context.query_data_set_settings.ok) {
|
||||
gb_printf_err("Invalid use of -go-to-definitions flag, only allowed with 'odin query'\n");
|
||||
bad_flags = true;
|
||||
} else if (build_context.query_data_set_settings.kind != QueryDataSet_Invalid) {
|
||||
gb_printf_err("Invalid use of -global-definitions flag, a previous flag for 'odin query' was set\n");
|
||||
bad_flags = true;
|
||||
} else {
|
||||
build_context.query_data_set_settings.kind = QueryDataSet_GoToDefinitions;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case BuildFlag_Short:
|
||||
build_context.cmd_doc_flags |= CmdDocFlag_Short;
|
||||
break;
|
||||
@@ -1525,6 +1482,9 @@ bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_InternalIgnoreLazy:
|
||||
build_context.ignore_lazy = true;
|
||||
break;
|
||||
case BuildFlag_InternalIgnoreLLVMBuild:
|
||||
build_context.ignore_llvm_build = true;
|
||||
break;
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
case BuildFlag_IgnoreVsSearch: {
|
||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
||||
@@ -1638,20 +1598,10 @@ bool parse_build_flags(Array<String> args) {
|
||||
gb_printf_err("`-export-timings:<format>` requires `-show-timings` or `-show-more-timings` to be present\n");
|
||||
bad_flags = true;
|
||||
}
|
||||
|
||||
if (build_context.query_data_set_settings.ok) {
|
||||
if (build_context.query_data_set_settings.kind == QueryDataSet_Invalid) {
|
||||
gb_printf_err("'odin query' requires a flag determining the kind of query data set to be returned\n");
|
||||
gb_printf_err("\t-global-definitions : outputs a JSON file of global definitions\n");
|
||||
gb_printf_err("\t-go-to-definitions : outputs a OGTD binary file of go to definitions for identifiers within an Odin project\n");
|
||||
bad_flags = true;
|
||||
}
|
||||
}
|
||||
|
||||
return !bad_flags;
|
||||
}
|
||||
|
||||
void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = false) {
|
||||
gb_internal void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = false) {
|
||||
GB_ASSERT((!(build_context.export_timings_format == TimingsExportUnspecified) && build_context.export_timings_file.len > 0));
|
||||
|
||||
/*
|
||||
@@ -1690,10 +1640,9 @@ void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = fal
|
||||
isize files = 0;
|
||||
isize packages = p->packages.count;
|
||||
isize total_file_size = 0;
|
||||
for_array(i, p->packages) {
|
||||
files += p->packages[i]->files.count;
|
||||
for_array(j, p->packages[i]->files) {
|
||||
AstFile *file = p->packages[i]->files[j];
|
||||
for (AstPackage *pkg : p->packages) {
|
||||
files += pkg->files.count;
|
||||
for (AstFile *file : pkg->files) {
|
||||
total_file_size += file->tokenizer.end - file->tokenizer.start;
|
||||
}
|
||||
}
|
||||
@@ -1717,8 +1666,7 @@ void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = fal
|
||||
gb_fprintf(&f, "\t\t{\"name\": \"%.*s\", \"millis\": %.3f},\n",
|
||||
LIT(t->total.label), total_time);
|
||||
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp ts = t->sections[i];
|
||||
for (TimeStamp const &ts : t->sections) {
|
||||
f64 section_time = time_stamp(ts, t->freq, unit);
|
||||
gb_fprintf(&f, "\t\t{\"name\": \"%.*s\", \"millis\": %.3f},\n",
|
||||
LIT(ts.label), section_time);
|
||||
@@ -1739,8 +1687,7 @@ void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = fal
|
||||
*/
|
||||
gb_fprintf(&f, "\"%.*s\", %d\n", LIT(t->total.label), int(total_time));
|
||||
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp ts = t->sections[i];
|
||||
for (TimeStamp const &ts : t->sections) {
|
||||
f64 section_time = time_stamp(ts, t->freq, unit);
|
||||
gb_fprintf(&f, "\"%.*s\", %d\n", LIT(ts.label), int(section_time));
|
||||
}
|
||||
@@ -1749,7 +1696,7 @@ void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = fal
|
||||
gb_printf("Done.\n");
|
||||
}
|
||||
|
||||
void show_timings(Checker *c, Timings *t) {
|
||||
gb_internal void show_timings(Checker *c, Timings *t) {
|
||||
Parser *p = c->parser;
|
||||
isize lines = p->total_line_count;
|
||||
isize tokens = p->total_token_count;
|
||||
@@ -1758,10 +1705,9 @@ void show_timings(Checker *c, Timings *t) {
|
||||
isize total_file_size = 0;
|
||||
f64 total_tokenizing_time = 0;
|
||||
f64 total_parsing_time = 0;
|
||||
for_array(i, p->packages) {
|
||||
files += p->packages[i]->files.count;
|
||||
for_array(j, p->packages[i]->files) {
|
||||
AstFile *file = p->packages[i]->files[j];
|
||||
for (AstPackage *pkg : p->packages) {
|
||||
files += pkg->files.count;
|
||||
for (AstFile *file : pkg->files) {
|
||||
total_tokenizing_time += file->time_to_tokenize;
|
||||
total_parsing_time += file->time_to_parse;
|
||||
total_file_size += file->tokenizer.end - file->tokenizer.start;
|
||||
@@ -1770,6 +1716,16 @@ void show_timings(Checker *c, Timings *t) {
|
||||
|
||||
timings_print_all(t);
|
||||
|
||||
if (build_context.show_more_timings) {
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
PROCESS_MEMORY_COUNTERS p = {sizeof(p)};
|
||||
if (GetProcessMemoryInfo(GetCurrentProcess(), &p, sizeof(p))) {
|
||||
gb_printf("\n");
|
||||
gb_printf("Peak Memory Size: %.3f MiB\n", (cast(f64)p.PeakWorkingSetSize) / cast(f64)(1024ull * 1024ull));
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!(build_context.export_timings_format == TimingsExportUnspecified)) {
|
||||
timings_export_all(t, c, true);
|
||||
}
|
||||
@@ -1812,8 +1768,7 @@ void show_timings(Checker *c, Timings *t) {
|
||||
}
|
||||
{
|
||||
TimeStamp ts = {};
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp s = t->sections[i];
|
||||
for (TimeStamp const &s : t->sections) {
|
||||
if (s.label == "parse files") {
|
||||
ts = s;
|
||||
break;
|
||||
@@ -1836,8 +1791,7 @@ void show_timings(Checker *c, Timings *t) {
|
||||
{
|
||||
TimeStamp ts = {};
|
||||
TimeStamp ts_end = {};
|
||||
for_array(i, t->sections) {
|
||||
TimeStamp s = t->sections[i];
|
||||
for (TimeStamp const &s : t->sections) {
|
||||
if (s.label == "type check") {
|
||||
ts = s;
|
||||
}
|
||||
@@ -1878,13 +1832,12 @@ void show_timings(Checker *c, Timings *t) {
|
||||
}
|
||||
}
|
||||
|
||||
void remove_temp_files(lbGenerator *gen) {
|
||||
gb_internal void remove_temp_files(lbGenerator *gen) {
|
||||
if (build_context.keep_temp_files) return;
|
||||
|
||||
TIME_SECTION("remove keep temp files");
|
||||
|
||||
for_array(i, gen->output_temp_paths) {
|
||||
String path = gen->output_temp_paths[i];
|
||||
for (String const &path : gen->output_temp_paths) {
|
||||
gb_file_remove(cast(char const *)path.text);
|
||||
}
|
||||
|
||||
@@ -1892,8 +1845,7 @@ void remove_temp_files(lbGenerator *gen) {
|
||||
switch (build_context.build_mode) {
|
||||
case BuildMode_Executable:
|
||||
case BuildMode_DynamicLibrary:
|
||||
for_array(i, gen->output_object_paths) {
|
||||
String path = gen->output_object_paths[i];
|
||||
for (String const &path : gen->output_object_paths) {
|
||||
gb_file_remove(cast(char const *)path.text);
|
||||
}
|
||||
break;
|
||||
@@ -1902,7 +1854,7 @@ void remove_temp_files(lbGenerator *gen) {
|
||||
}
|
||||
|
||||
|
||||
void print_show_help(String const arg0, String const &command) {
|
||||
gb_internal void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0));
|
||||
print_usage_line(0, "Usage:");
|
||||
print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
|
||||
@@ -1930,9 +1882,7 @@ void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(3, "odin check <dir> # Type check package in <dir>");
|
||||
print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point.");
|
||||
} else if (command == "test") {
|
||||
print_usage_line(1, "test Build ands runs procedures with the attribute @(test) in the initial package");
|
||||
} else if (command == "query") {
|
||||
print_usage_line(1, "query [experimental] Parse, type check, and output a .json file containing information about the program");
|
||||
print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package");
|
||||
} else if (command == "doc") {
|
||||
print_usage_line(1, "doc generate documentation from a directory of .odin files");
|
||||
print_usage_line(2, "Examples:");
|
||||
@@ -2248,12 +2198,11 @@ void print_show_help(String const arg0, String const &command) {
|
||||
}
|
||||
}
|
||||
|
||||
void print_show_unused(Checker *c) {
|
||||
gb_internal void print_show_unused(Checker *c) {
|
||||
CheckerInfo *info = &c->info;
|
||||
|
||||
auto unused = array_make<Entity *>(permanent_allocator(), 0, info->entities.count);
|
||||
for_array(i, info->entities) {
|
||||
Entity *e = info->entities[i];
|
||||
for (Entity *e : info->entities) {
|
||||
if (e == nullptr) {
|
||||
continue;
|
||||
}
|
||||
@@ -2300,8 +2249,7 @@ void print_show_unused(Checker *c) {
|
||||
|
||||
AstPackage *curr_pkg = nullptr;
|
||||
EntityKind curr_entity_kind = Entity_Invalid;
|
||||
for_array(i, unused) {
|
||||
Entity *e = unused[i];
|
||||
for (Entity *e : unused) {
|
||||
if (curr_pkg != e->pkg) {
|
||||
curr_pkg = e->pkg;
|
||||
curr_entity_kind = Entity_Invalid;
|
||||
@@ -2322,7 +2270,7 @@ void print_show_unused(Checker *c) {
|
||||
print_usage_line(0, "");
|
||||
}
|
||||
|
||||
bool check_env(void) {
|
||||
gb_internal bool check_env(void) {
|
||||
gbAllocator a = heap_allocator();
|
||||
char const *odin_root = gb_get_env("ODIN_ROOT", a);
|
||||
defer (gb_free(a, cast(void *)odin_root));
|
||||
@@ -2348,25 +2296,24 @@ struct StripSemicolonFile {
|
||||
i64 written;
|
||||
};
|
||||
|
||||
gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *written_) {
|
||||
gb_internal gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *written_) {
|
||||
i64 written = 0;
|
||||
gbFileError err = gbFileError_None;
|
||||
u8 const *file_data = file->tokenizer.start;
|
||||
i32 prev_offset = 0;
|
||||
i32 const end_offset = cast(i32)(file->tokenizer.end - file->tokenizer.start);
|
||||
for_array(i, file->tokens) {
|
||||
Token *token = &file->tokens[i];
|
||||
if (token->flags & (TokenFlag_Remove|TokenFlag_Replace)) {
|
||||
i32 offset = token->pos.offset;
|
||||
for (Token const &token : file->tokens) {
|
||||
if (token.flags & (TokenFlag_Remove|TokenFlag_Replace)) {
|
||||
i32 offset = token.pos.offset;
|
||||
i32 to_write = offset-prev_offset;
|
||||
if (!gb_file_write(f, file_data+prev_offset, to_write)) {
|
||||
return gbFileError_Invalid;
|
||||
}
|
||||
written += to_write;
|
||||
prev_offset = token_pos_end(*token).offset;
|
||||
prev_offset = token_pos_end(token).offset;
|
||||
}
|
||||
if (token->flags & TokenFlag_Replace) {
|
||||
if (token->kind == Token_Ellipsis) {
|
||||
if (token.flags & TokenFlag_Replace) {
|
||||
if (token.kind == Token_Ellipsis) {
|
||||
if (!gb_file_write(f, "..=", 3)) {
|
||||
return gbFileError_Invalid;
|
||||
}
|
||||
@@ -2388,24 +2335,19 @@ gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *writt
|
||||
return err;
|
||||
}
|
||||
|
||||
int strip_semicolons(Parser *parser) {
|
||||
gb_internal int strip_semicolons(Parser *parser) {
|
||||
isize file_count = 0;
|
||||
for_array(i, parser->packages) {
|
||||
AstPackage *pkg = parser->packages[i];
|
||||
for (AstPackage *pkg : parser->packages) {
|
||||
file_count += pkg->files.count;
|
||||
}
|
||||
|
||||
auto generated_files = array_make<StripSemicolonFile>(permanent_allocator(), 0, file_count);
|
||||
|
||||
for_array(i, parser->packages) {
|
||||
AstPackage *pkg = parser->packages[i];
|
||||
for_array(j, pkg->files) {
|
||||
AstFile *file = pkg->files[j];
|
||||
|
||||
for (AstPackage *pkg : parser->packages) {
|
||||
for (AstFile *file : pkg->files) {
|
||||
bool nothing_to_change = true;
|
||||
for_array(i, file->tokens) {
|
||||
Token *token = &file->tokens[i];
|
||||
if (token->flags) {
|
||||
for (Token const &token : file->tokens) {
|
||||
if (token.flags) {
|
||||
nothing_to_change = false;
|
||||
break;
|
||||
}
|
||||
@@ -2433,9 +2375,8 @@ int strip_semicolons(Parser *parser) {
|
||||
isize generated_count = 0;
|
||||
bool failed = false;
|
||||
|
||||
for_array(i, generated_files) {
|
||||
auto *file = &generated_files[i];
|
||||
char const *filename = cast(char const *)file->new_fullpath.text;
|
||||
for (StripSemicolonFile &file : generated_files) {
|
||||
char const *filename = cast(char const *)file.new_fullpath.text;
|
||||
gbFileError err = gbFileError_None;
|
||||
defer (if (err != gbFileError_None) {
|
||||
failed = true;
|
||||
@@ -2453,11 +2394,11 @@ int strip_semicolons(Parser *parser) {
|
||||
defer (err = gb_file_truncate(&f, written));
|
||||
|
||||
debugf("Write file with stripped tokens: %s\n", filename);
|
||||
err = write_file_with_stripped_tokens(&f, file->file, &written);
|
||||
err = write_file_with_stripped_tokens(&f, file.file, &written);
|
||||
if (err) {
|
||||
break;
|
||||
}
|
||||
file->written = written;
|
||||
file.written = written;
|
||||
}
|
||||
|
||||
if (failed) {
|
||||
@@ -2472,12 +2413,10 @@ int strip_semicolons(Parser *parser) {
|
||||
|
||||
isize overwritten_files = 0;
|
||||
|
||||
for_array(i, generated_files) {
|
||||
auto *file = &generated_files[i];
|
||||
|
||||
char const *old_fullpath = cast(char const *)file->old_fullpath.text;
|
||||
char const *old_fullpath_backup = cast(char const *)file->old_fullpath_backup.text;
|
||||
char const *new_fullpath = cast(char const *)file->new_fullpath.text;
|
||||
for (StripSemicolonFile const &file : generated_files) {
|
||||
char const *old_fullpath = cast(char const *)file.old_fullpath.text;
|
||||
char const *old_fullpath_backup = cast(char const *)file.old_fullpath_backup.text;
|
||||
char const *new_fullpath = cast(char const *)file.new_fullpath.text;
|
||||
|
||||
debugf("Copy '%s' to '%s'\n", old_fullpath, old_fullpath_backup);
|
||||
if (!gb_file_copy(old_fullpath, old_fullpath_backup, false)) {
|
||||
@@ -2537,22 +2476,16 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
usage(make_string_c(arg_ptr[0]));
|
||||
return 1;
|
||||
}
|
||||
virtual_memory_init();
|
||||
|
||||
timings_init(&global_timings, str_lit("Total Time"), 2048);
|
||||
defer (timings_destroy(&global_timings));
|
||||
|
||||
MAIN_TIME_SECTION("initialization");
|
||||
|
||||
virtual_memory_init();
|
||||
mutex_init(&fullpath_mutex);
|
||||
mutex_init(&hash_exact_value_mutex);
|
||||
mutex_init(&global_type_name_objc_metadata_mutex);
|
||||
|
||||
init_string_buffer_memory();
|
||||
init_string_interner();
|
||||
init_global_error_collector();
|
||||
init_keyword_hash_table();
|
||||
init_type_mutex();
|
||||
|
||||
if (!check_env()) {
|
||||
return 1;
|
||||
@@ -2563,9 +2496,9 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
|
||||
add_library_collection(str_lit("vendor"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("vendor")));
|
||||
|
||||
map_init(&build_context.defined_values, heap_allocator());
|
||||
map_init(&build_context.defined_values);
|
||||
build_context.extra_packages.allocator = heap_allocator();
|
||||
string_set_init(&build_context.test_names, heap_allocator());
|
||||
string_set_init(&build_context.test_names);
|
||||
|
||||
Array<String> args = setup_args(arg_count, arg_ptr);
|
||||
|
||||
@@ -2627,15 +2560,6 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
build_context.command_kind = Command_strip_semicolon;
|
||||
build_context.no_output_files = true;
|
||||
init_filename = args[2];
|
||||
} else if (command == "query") {
|
||||
if (args.count < 3) {
|
||||
usage(args[0]);
|
||||
return 1;
|
||||
}
|
||||
build_context.command_kind = Command_query;
|
||||
build_context.no_output_files = true;
|
||||
build_context.query_data_set_settings.ok = true;
|
||||
init_filename = args[2];
|
||||
} else if (command == "doc") {
|
||||
if (args.count < 3) {
|
||||
usage(args[0]);
|
||||
@@ -2824,12 +2748,8 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
print_show_unused(checker);
|
||||
}
|
||||
|
||||
if (build_context.query_data_set_settings.ok) {
|
||||
generate_and_print_query_data(checker, &global_timings);
|
||||
} else {
|
||||
if (build_context.show_timings) {
|
||||
show_timings(checker, &global_timings);
|
||||
}
|
||||
if (build_context.show_timings) {
|
||||
show_timings(checker, &global_timings);
|
||||
}
|
||||
|
||||
if (global_error_collector.count != 0) {
|
||||
@@ -2844,19 +2764,19 @@ int main(int arg_count, char const **arg_ptr) {
|
||||
if (!lb_init_generator(gen, checker)) {
|
||||
return 1;
|
||||
}
|
||||
lb_generate_code(gen);
|
||||
|
||||
switch (build_context.build_mode) {
|
||||
case BuildMode_Executable:
|
||||
case BuildMode_DynamicLibrary:
|
||||
i32 result = linker_stage(gen);
|
||||
if (result) {
|
||||
if (build_context.show_timings) {
|
||||
show_timings(checker, &global_timings);
|
||||
if (lb_generate_code(gen)) {
|
||||
switch (build_context.build_mode) {
|
||||
case BuildMode_Executable:
|
||||
case BuildMode_DynamicLibrary:
|
||||
i32 result = linker_stage(gen);
|
||||
if (result) {
|
||||
if (build_context.show_timings) {
|
||||
show_timings(checker, &global_timings);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return result;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
remove_temp_files(gen);
|
||||
|
||||
+20
-24
@@ -45,7 +45,7 @@
|
||||
//
|
||||
// Here is the API you need to know about:
|
||||
//
|
||||
gb_global gbAllocator mc_allocator = heap_allocator();
|
||||
gb_global gbAllocator mc_allocator = permanent_allocator();
|
||||
|
||||
struct Find_Result {
|
||||
int windows_sdk_version; // Zero if no Windows SDK found.
|
||||
@@ -58,50 +58,46 @@ struct Find_Result {
|
||||
String vs_library_path;
|
||||
};
|
||||
|
||||
String mc_wstring_to_string(wchar_t const *str) {
|
||||
gb_internal String mc_wstring_to_string(wchar_t const *str) {
|
||||
return string16_to_string(mc_allocator, make_string16_c(str));
|
||||
}
|
||||
|
||||
String16 mc_string_to_wstring(String str) {
|
||||
gb_internal String16 mc_string_to_wstring(String str) {
|
||||
return string_to_string16(mc_allocator, str);
|
||||
}
|
||||
|
||||
String mc_concat(String a, String b) {
|
||||
gb_internal String mc_concat(String a, String b) {
|
||||
return concatenate_strings(mc_allocator, a, b);
|
||||
}
|
||||
|
||||
String mc_concat(String a, String b, String c) {
|
||||
gb_internal String mc_concat(String a, String b, String c) {
|
||||
return concatenate3_strings(mc_allocator, a, b, c);
|
||||
}
|
||||
|
||||
String mc_concat(String a, String b, String c, String d) {
|
||||
gb_internal String mc_concat(String a, String b, String c, String d) {
|
||||
return concatenate4_strings(mc_allocator, a, b, c, d);
|
||||
}
|
||||
|
||||
String mc_get_env(String key) {
|
||||
gb_internal String mc_get_env(String key) {
|
||||
char const * value = gb_get_env((char const *)key.text, mc_allocator);
|
||||
return make_string_c(value);
|
||||
}
|
||||
|
||||
void mc_free(String str) {
|
||||
gb_internal void mc_free(String str) {
|
||||
if (str.len) gb_free(mc_allocator, str.text);
|
||||
}
|
||||
|
||||
void mc_free(String16 str) {
|
||||
gb_internal void mc_free(String16 str) {
|
||||
if (str.len) gb_free(mc_allocator, str.text);
|
||||
}
|
||||
|
||||
void mc_free_all() {
|
||||
gb_free_all(mc_allocator);
|
||||
}
|
||||
|
||||
typedef struct _MC_Find_Data {
|
||||
DWORD file_attributes;
|
||||
String filename;
|
||||
} MC_Find_Data;
|
||||
|
||||
|
||||
HANDLE mc_find_first(String wildcard, MC_Find_Data *find_data) {
|
||||
gb_internal HANDLE mc_find_first(String wildcard, MC_Find_Data *find_data) {
|
||||
WIN32_FIND_DATAW _find_data;
|
||||
|
||||
String16 wildcard_wide = mc_string_to_wstring(wildcard);
|
||||
@@ -115,7 +111,7 @@ HANDLE mc_find_first(String wildcard, MC_Find_Data *find_data) {
|
||||
return handle;
|
||||
}
|
||||
|
||||
bool mc_find_next(HANDLE handle, MC_Find_Data *find_data) {
|
||||
gb_internal bool mc_find_next(HANDLE handle, MC_Find_Data *find_data) {
|
||||
WIN32_FIND_DATAW _find_data;
|
||||
bool success = !!FindNextFileW(handle, &_find_data);
|
||||
|
||||
@@ -124,7 +120,7 @@ bool mc_find_next(HANDLE handle, MC_Find_Data *find_data) {
|
||||
return success;
|
||||
}
|
||||
|
||||
void mc_find_close(HANDLE handle) {
|
||||
gb_internal void mc_find_close(HANDLE handle) {
|
||||
FindClose(handle);
|
||||
}
|
||||
|
||||
@@ -216,7 +212,7 @@ struct Version_Data {
|
||||
};
|
||||
|
||||
typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data *data);
|
||||
bool mc_visit_files(String dir_name, Version_Data *data, MC_Visit_Proc proc) {
|
||||
gb_internal bool mc_visit_files(String dir_name, Version_Data *data, MC_Visit_Proc proc) {
|
||||
|
||||
// Visit everything in one folder (non-recursively). If it's a directory
|
||||
// that doesn't start with ".", call the visit proc on it. The visit proc
|
||||
@@ -246,7 +242,7 @@ bool mc_visit_files(String dir_name, Version_Data *data, MC_Visit_Proc proc) {
|
||||
return true;
|
||||
}
|
||||
|
||||
String find_windows_kit_root(HKEY key, String const version) {
|
||||
gb_internal String find_windows_kit_root(HKEY key, String const version) {
|
||||
// Given a key to an already opened registry entry,
|
||||
// get the value stored under the 'version' subkey.
|
||||
// If that's not the right terminology, hey, I never do registry stuff.
|
||||
@@ -275,7 +271,7 @@ String find_windows_kit_root(HKEY key, String const version) {
|
||||
return value;
|
||||
}
|
||||
|
||||
void win10_best(String short_name, String full_name, Version_Data *data) {
|
||||
gb_internal void win10_best(String short_name, String full_name, Version_Data *data) {
|
||||
// Find the Windows 10 subdirectory with the highest version number.
|
||||
|
||||
int i0, i1, i2, i3;
|
||||
@@ -307,7 +303,7 @@ void win10_best(String short_name, String full_name, Version_Data *data) {
|
||||
}
|
||||
}
|
||||
|
||||
void find_windows_kit_paths(Find_Result *result) {
|
||||
gb_internal void find_windows_kit_paths(Find_Result *result) {
|
||||
bool sdk_found = false;
|
||||
|
||||
HKEY main_key;
|
||||
@@ -355,7 +351,7 @@ void find_windows_kit_paths(Find_Result *result) {
|
||||
}
|
||||
}
|
||||
|
||||
bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *result) {
|
||||
gb_internal bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *result) {
|
||||
// The name of this procedure is kind of cryptic. Its purpose is
|
||||
// to fight through Microsoft craziness. The things that the fine
|
||||
// Visual Studio team want you to do, JUST TO FIND A SINGLE FOLDER
|
||||
@@ -519,7 +515,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res
|
||||
|
||||
// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both
|
||||
// official and portable installations (like mmozeiko's portable msvc script).
|
||||
void find_windows_kit_paths_from_env_vars(Find_Result *result) {
|
||||
gb_internal void find_windows_kit_paths_from_env_vars(Find_Result *result) {
|
||||
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
|
||||
return;
|
||||
}
|
||||
@@ -669,7 +665,7 @@ void find_windows_kit_paths_from_env_vars(Find_Result *result) {
|
||||
// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both
|
||||
// official and portable installations (like mmozeiko's portable msvc script). This will only use
|
||||
// the first paths it finds, and won't overwrite any values that `result` already has.
|
||||
void find_visual_studio_paths_from_env_vars(Find_Result *result) {
|
||||
gb_internal void find_visual_studio_paths_from_env_vars(Find_Result *result) {
|
||||
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
|
||||
return;
|
||||
}
|
||||
@@ -756,7 +752,7 @@ void find_visual_studio_paths_from_env_vars(Find_Result *result) {
|
||||
}
|
||||
}
|
||||
|
||||
Find_Result find_visual_studio_and_windows_sdk() {
|
||||
gb_internal Find_Result find_visual_studio_and_windows_sdk() {
|
||||
Find_Result r = {};
|
||||
find_windows_kit_paths(&r);
|
||||
find_visual_studio_by_fighting_through_microsoft_craziness(&r);
|
||||
|
||||
+449
-492
File diff suppressed because it is too large
Load Diff
+59
-51
@@ -62,15 +62,6 @@ enum PackageKind {
|
||||
Package_Init,
|
||||
};
|
||||
|
||||
struct ImportedPackage {
|
||||
PackageKind kind;
|
||||
String path;
|
||||
String rel_path;
|
||||
TokenPos pos; // import
|
||||
isize index;
|
||||
};
|
||||
|
||||
|
||||
struct ImportedFile {
|
||||
AstPackage *pkg;
|
||||
FileInfo fi;
|
||||
@@ -99,7 +90,11 @@ struct AstFile {
|
||||
Scope * scope;
|
||||
|
||||
Ast * pkg_decl;
|
||||
|
||||
String fullpath;
|
||||
String filename;
|
||||
String directory;
|
||||
|
||||
Tokenizer tokenizer;
|
||||
Array<Token> tokens;
|
||||
isize curr_token_index;
|
||||
@@ -109,6 +104,7 @@ struct AstFile {
|
||||
Token package_token;
|
||||
String package_name;
|
||||
|
||||
|
||||
// >= 0: In Expression
|
||||
// < 0: In Control Clause
|
||||
// NOTE(bill): Used to prevent type literals in control clauses
|
||||
@@ -136,9 +132,8 @@ struct AstFile {
|
||||
CommentGroup *docs; // current docs
|
||||
Array<CommentGroup *> comments; // All the comments!
|
||||
|
||||
// TODO(bill): make this a basic queue as it does not require
|
||||
// any multiple thread capabilities
|
||||
MPMCQueue<Ast *> delayed_decls_queues[AstDelayQueue_COUNT];
|
||||
// This is effectively a queue but does not require any multi-threading capabilities
|
||||
Array<Ast *> delayed_decls_queues[AstDelayQueue_COUNT];
|
||||
|
||||
#define PARSER_MAX_FIX_COUNT 6
|
||||
isize fix_count;
|
||||
@@ -177,6 +172,12 @@ struct AstPackage {
|
||||
bool is_single_file;
|
||||
isize order;
|
||||
|
||||
BlockingMutex files_mutex;
|
||||
BlockingMutex foreign_files_mutex;
|
||||
BlockingMutex type_and_value_mutex;
|
||||
BlockingMutex name_mutex;
|
||||
|
||||
// NOTE(bill): This must be a MPMCQueue
|
||||
MPMCQueue<AstPackageExportedEntity> exported_entity_queue;
|
||||
|
||||
// NOTE(bill): Created/set in checker
|
||||
@@ -186,20 +187,33 @@ struct AstPackage {
|
||||
};
|
||||
|
||||
|
||||
struct ParseFileErrorNode {
|
||||
ParseFileErrorNode *next, *prev;
|
||||
ParseFileError err;
|
||||
};
|
||||
|
||||
struct Parser {
|
||||
String init_fullpath;
|
||||
StringSet imported_files; // fullpath
|
||||
Array<AstPackage *> packages;
|
||||
Array<ImportedPackage> package_imports;
|
||||
isize file_to_process_count;
|
||||
isize total_token_count;
|
||||
isize total_line_count;
|
||||
BlockingMutex wait_mutex;
|
||||
BlockingMutex import_mutex;
|
||||
BlockingMutex file_add_mutex;
|
||||
BlockingMutex file_decl_mutex;
|
||||
BlockingMutex packages_mutex;
|
||||
MPMCQueue<ParseFileError> file_error_queue;
|
||||
String init_fullpath;
|
||||
|
||||
StringSet imported_files; // fullpath
|
||||
BlockingMutex imported_files_mutex;
|
||||
|
||||
Array<AstPackage *> packages;
|
||||
BlockingMutex packages_mutex;
|
||||
|
||||
std::atomic<isize> file_to_process_count;
|
||||
std::atomic<isize> total_token_count;
|
||||
std::atomic<isize> total_line_count;
|
||||
|
||||
// TODO(bill): What should this mutex be per?
|
||||
// * Parser
|
||||
// * Package
|
||||
// * File
|
||||
BlockingMutex file_decl_mutex;
|
||||
|
||||
BlockingMutex file_error_mutex;
|
||||
ParseFileErrorNode * file_error_head;
|
||||
ParseFileErrorNode * file_error_tail;
|
||||
};
|
||||
|
||||
struct ParserWorkerData {
|
||||
@@ -258,7 +272,7 @@ enum ProcCallingConvention : i32 {
|
||||
ProcCC_ForeignBlockDefault = -1,
|
||||
};
|
||||
|
||||
char const *proc_calling_convention_strings[ProcCC_MAX] = {
|
||||
gb_global char const *proc_calling_convention_strings[ProcCC_MAX] = {
|
||||
"",
|
||||
"odin",
|
||||
"contextless",
|
||||
@@ -272,7 +286,7 @@ char const *proc_calling_convention_strings[ProcCC_MAX] = {
|
||||
"sysv",
|
||||
};
|
||||
|
||||
ProcCallingConvention default_calling_convention(void) {
|
||||
gb_internal ProcCallingConvention default_calling_convention(void) {
|
||||
return ProcCC_Odin;
|
||||
}
|
||||
|
||||
@@ -299,7 +313,7 @@ enum FieldFlag : u32 {
|
||||
FieldFlag_using = 1<<1,
|
||||
FieldFlag_no_alias = 1<<2,
|
||||
FieldFlag_c_vararg = 1<<3,
|
||||
FieldFlag_auto_cast = 1<<4,
|
||||
|
||||
FieldFlag_const = 1<<5,
|
||||
FieldFlag_any_int = 1<<6,
|
||||
FieldFlag_subtype = 1<<7,
|
||||
@@ -314,7 +328,7 @@ enum FieldFlag : u32 {
|
||||
FieldFlag_Invalid = 1u<<31,
|
||||
|
||||
// Parameter List Restrictions
|
||||
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr,
|
||||
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr,
|
||||
FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags,
|
||||
};
|
||||
|
||||
@@ -332,7 +346,7 @@ enum InlineAsmDialectKind : u8 {
|
||||
InlineAsmDialect_COUNT,
|
||||
};
|
||||
|
||||
char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
|
||||
gb_global char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
|
||||
"",
|
||||
"att",
|
||||
"intel",
|
||||
@@ -457,11 +471,6 @@ AST_KIND(_StmtBegin, "", bool) \
|
||||
AST_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
|
||||
AST_KIND(EmptyStmt, "empty statement", struct { Token token; }) \
|
||||
AST_KIND(ExprStmt, "expression statement", struct { Ast *expr; } ) \
|
||||
AST_KIND(TagStmt, "tag statement", struct { \
|
||||
Token token; \
|
||||
Token name; \
|
||||
Ast * stmt; \
|
||||
}) \
|
||||
AST_KIND(AssignStmt, "assign statement", struct { \
|
||||
Token op; \
|
||||
Slice<Ast *> lhs, rhs; \
|
||||
@@ -729,7 +738,7 @@ enum AstKind : u16 {
|
||||
Ast_COUNT,
|
||||
};
|
||||
|
||||
String const ast_strings[] = {
|
||||
gb_global String const ast_strings[] = {
|
||||
{cast(u8 *)"invalid node", gb_size_of("invalid node")},
|
||||
#define AST_KIND(_kind_name_, name, ...) {cast(u8 *)name, gb_size_of(name)-1},
|
||||
AST_KINDS
|
||||
@@ -742,7 +751,7 @@ String const ast_strings[] = {
|
||||
#undef AST_KIND
|
||||
|
||||
|
||||
isize const ast_variant_sizes[] = {
|
||||
gb_global isize const ast_variant_sizes[] = {
|
||||
0,
|
||||
#define AST_KIND(_kind_name_, name, ...) gb_size_of(GB_JOIN2(Ast, _kind_name_)),
|
||||
AST_KINDS
|
||||
@@ -754,7 +763,7 @@ struct AstCommonStuff {
|
||||
u8 state_flags;
|
||||
u8 viral_state_flags;
|
||||
i32 file_id;
|
||||
TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size
|
||||
TypeAndValue tav; // NOTE(bill): Making this a pointer is slower
|
||||
};
|
||||
|
||||
struct Ast {
|
||||
@@ -762,7 +771,7 @@ struct Ast {
|
||||
u8 state_flags;
|
||||
u8 viral_state_flags;
|
||||
i32 file_id;
|
||||
TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size
|
||||
TypeAndValue tav; // NOTE(bill): Making this a pointer is slower
|
||||
|
||||
// IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant
|
||||
union {
|
||||
@@ -793,33 +802,32 @@ struct Ast {
|
||||
#endif
|
||||
|
||||
|
||||
gb_inline bool is_ast_expr(Ast *node) {
|
||||
gb_internal gb_inline bool is_ast_expr(Ast *node) {
|
||||
return gb_is_between(node->kind, Ast__ExprBegin+1, Ast__ExprEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_stmt(Ast *node) {
|
||||
gb_internal gb_inline bool is_ast_stmt(Ast *node) {
|
||||
return gb_is_between(node->kind, Ast__StmtBegin+1, Ast__StmtEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_complex_stmt(Ast *node) {
|
||||
gb_internal gb_inline bool is_ast_complex_stmt(Ast *node) {
|
||||
return gb_is_between(node->kind, Ast__ComplexStmtBegin+1, Ast__ComplexStmtEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_decl(Ast *node) {
|
||||
gb_internal gb_inline bool is_ast_decl(Ast *node) {
|
||||
return gb_is_between(node->kind, Ast__DeclBegin+1, Ast__DeclEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_type(Ast *node) {
|
||||
gb_internal gb_inline bool is_ast_type(Ast *node) {
|
||||
return gb_is_between(node->kind, Ast__TypeBegin+1, Ast__TypeEnd-1);
|
||||
}
|
||||
gb_inline bool is_ast_when_stmt(Ast *node) {
|
||||
gb_internal gb_inline bool is_ast_when_stmt(Ast *node) {
|
||||
return node->kind == Ast_WhenStmt;
|
||||
}
|
||||
|
||||
gb_global gb_thread_local Arena global_thread_local_ast_arena = {};
|
||||
|
||||
gbAllocator ast_allocator(AstFile *f) {
|
||||
Arena *arena = &global_thread_local_ast_arena;
|
||||
return arena_allocator(arena);
|
||||
gb_internal gb_inline gbAllocator ast_allocator(AstFile *f) {
|
||||
return arena_allocator(&global_thread_local_ast_arena);
|
||||
}
|
||||
|
||||
Ast *alloc_ast_node(AstFile *f, AstKind kind);
|
||||
gb_internal Ast *alloc_ast_node(AstFile *f, AstKind kind);
|
||||
|
||||
gbString expr_to_string(Ast *expression);
|
||||
bool allow_field_separator(AstFile *f);
|
||||
gb_internal gbString expr_to_string(Ast *expression);
|
||||
gb_internal bool allow_field_separator(AstFile *f);
|
||||
+2
-4
@@ -1,4 +1,4 @@
|
||||
Token ast_token(Ast *node) {
|
||||
gb_internal Token ast_token(Ast *node) {
|
||||
switch (node->kind) {
|
||||
case Ast_Ident: return node->Ident.token;
|
||||
case Ast_Implicit: return node->Implicit;
|
||||
@@ -53,7 +53,6 @@ Token ast_token(Ast *node) {
|
||||
case Ast_BadStmt: return node->BadStmt.begin;
|
||||
case Ast_EmptyStmt: return node->EmptyStmt.token;
|
||||
case Ast_ExprStmt: return ast_token(node->ExprStmt.expr);
|
||||
case Ast_TagStmt: return node->TagStmt.token;
|
||||
case Ast_AssignStmt: return node->AssignStmt.op;
|
||||
case Ast_BlockStmt: return node->BlockStmt.open;
|
||||
case Ast_IfStmt: return node->IfStmt.token;
|
||||
@@ -197,7 +196,6 @@ Token ast_end_token(Ast *node) {
|
||||
case Ast_BadStmt: return node->BadStmt.end;
|
||||
case Ast_EmptyStmt: return node->EmptyStmt.token;
|
||||
case Ast_ExprStmt: return ast_end_token(node->ExprStmt.expr);
|
||||
case Ast_TagStmt: return ast_end_token(node->TagStmt.stmt);
|
||||
case Ast_AssignStmt:
|
||||
if (node->AssignStmt.rhs.count > 0) {
|
||||
return ast_end_token(node->AssignStmt.rhs[node->AssignStmt.rhs.count-1]);
|
||||
@@ -360,6 +358,6 @@ Token ast_end_token(Ast *node) {
|
||||
return empty_token;
|
||||
}
|
||||
|
||||
TokenPos ast_end_pos(Ast *node) {
|
||||
gb_internal TokenPos ast_end_pos(Ast *node) {
|
||||
return token_pos_end(ast_end_token(node));
|
||||
}
|
||||
|
||||
+26
-22
@@ -1,7 +1,10 @@
|
||||
/*
|
||||
Path handling utilities.
|
||||
*/
|
||||
String remove_extension_from_path(String const &s) {
|
||||
gb_internal String remove_extension_from_path(String const &s) {
|
||||
if (s.len != 0 && s.text[s.len-1] == '.') {
|
||||
return s;
|
||||
}
|
||||
for (isize i = s.len-1; i >= 0; i--) {
|
||||
if (s[i] == '.') {
|
||||
return substring(s, 0, i);
|
||||
@@ -10,7 +13,7 @@ String remove_extension_from_path(String const &s) {
|
||||
return s;
|
||||
}
|
||||
|
||||
String remove_directory_from_path(String const &s) {
|
||||
gb_internal String remove_directory_from_path(String const &s) {
|
||||
isize len = 0;
|
||||
for (isize i = s.len-1; i >= 0; i--) {
|
||||
if (s[i] == '/' ||
|
||||
@@ -22,9 +25,9 @@ String remove_directory_from_path(String const &s) {
|
||||
return substring(s, s.len-len, s.len);
|
||||
}
|
||||
|
||||
bool path_is_directory(String path);
|
||||
gb_internal bool path_is_directory(String path);
|
||||
|
||||
String directory_from_path(String const &s) {
|
||||
gb_internal String directory_from_path(String const &s) {
|
||||
if (path_is_directory(s)) {
|
||||
return s;
|
||||
}
|
||||
@@ -43,7 +46,7 @@ String directory_from_path(String const &s) {
|
||||
}
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
bool path_is_directory(String path) {
|
||||
gb_internal bool path_is_directory(String path) {
|
||||
gbAllocator a = heap_allocator();
|
||||
String16 wstr = string_to_string16(a, path);
|
||||
defer (gb_free(a, wstr.text));
|
||||
@@ -55,7 +58,7 @@ String directory_from_path(String const &s) {
|
||||
}
|
||||
|
||||
#else
|
||||
bool path_is_directory(String path) {
|
||||
gb_internal bool path_is_directory(String path) {
|
||||
gbAllocator a = heap_allocator();
|
||||
char *copy = cast(char *)copy_string(a, path).text;
|
||||
defer (gb_free(a, copy));
|
||||
@@ -69,7 +72,7 @@ String directory_from_path(String const &s) {
|
||||
#endif
|
||||
|
||||
|
||||
String path_to_full_path(gbAllocator a, String path) {
|
||||
gb_internal String path_to_full_path(gbAllocator a, String path) {
|
||||
gbAllocator ha = heap_allocator();
|
||||
char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len);
|
||||
defer (gb_free(ha, path_c));
|
||||
@@ -93,7 +96,7 @@ struct Path {
|
||||
};
|
||||
|
||||
// NOTE(Jeroen): Naively turns a Path into a string.
|
||||
String path_to_string(gbAllocator a, Path path) {
|
||||
gb_internal String path_to_string(gbAllocator a, Path path) {
|
||||
if (path.basename.len + path.name.len + path.ext.len == 0) {
|
||||
return make_string(nullptr, 0);
|
||||
}
|
||||
@@ -107,7 +110,9 @@ String path_to_string(gbAllocator a, Path path) {
|
||||
|
||||
isize i = 0;
|
||||
gb_memmove(str+i, path.basename.text, path.basename.len); i += path.basename.len;
|
||||
|
||||
gb_memmove(str+i, "/", 1); i += 1;
|
||||
|
||||
gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len;
|
||||
if (path.ext.len > 0) {
|
||||
gb_memmove(str+i, ".", 1); i += 1;
|
||||
@@ -121,7 +126,7 @@ String path_to_string(gbAllocator a, Path path) {
|
||||
}
|
||||
|
||||
// NOTE(Jeroen): Naively turns a Path into a string, then normalizes it using `path_to_full_path`.
|
||||
String path_to_full_path(gbAllocator a, Path path) {
|
||||
gb_internal String path_to_full_path(gbAllocator a, Path path) {
|
||||
String temp = path_to_string(heap_allocator(), path);
|
||||
defer (gb_free(heap_allocator(), temp.text));
|
||||
|
||||
@@ -130,7 +135,7 @@ String path_to_full_path(gbAllocator a, Path path) {
|
||||
|
||||
// NOTE(Jeroen): Takes a path like "odin" or "W:\Odin", turns it into a full path,
|
||||
// and then breaks it into its components to make a Path.
|
||||
Path path_from_string(gbAllocator a, String const &path) {
|
||||
gb_internal Path path_from_string(gbAllocator a, String const &path) {
|
||||
Path res = {};
|
||||
|
||||
if (path.len == 0) return res;
|
||||
@@ -150,6 +155,7 @@ Path path_from_string(gbAllocator a, String const &path) {
|
||||
return res;
|
||||
}
|
||||
|
||||
// Note(Dragos): Is the copy_string required if it's a substring?
|
||||
isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len;
|
||||
res.name = substring(fullpath, name_start, fullpath.len);
|
||||
res.name = remove_extension_from_path(res.name);
|
||||
@@ -161,7 +167,7 @@ Path path_from_string(gbAllocator a, String const &path) {
|
||||
}
|
||||
|
||||
// NOTE(Jeroen): Takes a path String and returns the last path element.
|
||||
String last_path_element(String const &path) {
|
||||
gb_internal String last_path_element(String const &path) {
|
||||
isize count = 0;
|
||||
u8 * start = (u8 *)(&path.text[path.len - 1]);
|
||||
for (isize length = path.len; length > 0 && path.text[length - 1] != '/'; length--) {
|
||||
@@ -177,7 +183,7 @@ String last_path_element(String const &path) {
|
||||
return STR_LIT("");
|
||||
}
|
||||
|
||||
bool path_is_directory(Path path) {
|
||||
gb_internal bool path_is_directory(Path path) {
|
||||
String path_string = path_to_full_path(heap_allocator(), path);
|
||||
defer (gb_free(heap_allocator(), path_string.text));
|
||||
|
||||
@@ -204,7 +210,7 @@ enum ReadDirectoryError {
|
||||
ReadDirectory_COUNT,
|
||||
};
|
||||
|
||||
i64 get_file_size(String path) {
|
||||
gb_internal i64 get_file_size(String path) {
|
||||
char *c_str = alloc_cstring(heap_allocator(), path);
|
||||
defer (gb_free(heap_allocator(), c_str));
|
||||
|
||||
@@ -219,10 +225,9 @@ i64 get_file_size(String path) {
|
||||
|
||||
|
||||
#if defined(GB_SYSTEM_WINDOWS)
|
||||
ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
GB_ASSERT(fi != nullptr);
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
while (path.len > 0) {
|
||||
Rune end = path[path.len-1];
|
||||
@@ -239,9 +244,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
return ReadDirectory_InvalidPath;
|
||||
}
|
||||
{
|
||||
char *c_str = alloc_cstring(a, path);
|
||||
defer (gb_free(a, c_str));
|
||||
|
||||
char *c_str = alloc_cstring(temporary_allocator(), path);
|
||||
gbFile f = {};
|
||||
gbFileError file_err = gb_file_open(&f, c_str);
|
||||
defer (gb_file_close(&f));
|
||||
@@ -258,6 +261,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
}
|
||||
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
char *new_path = gb_alloc_array(a, char, path.len+3);
|
||||
defer (gb_free(a, new_path));
|
||||
|
||||
@@ -280,8 +284,8 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
|
||||
do {
|
||||
wchar_t *filename_w = file_data.cFileName;
|
||||
i64 size = cast(i64)file_data.nFileSizeLow;
|
||||
size |= (cast(i64)file_data.nFileSizeHigh) << 32;
|
||||
u64 size = cast(u64)file_data.nFileSizeLow;
|
||||
size |= (cast(u64)file_data.nFileSizeHigh) << 32;
|
||||
String name = string16_to_string(a, make_string16_c(filename_w));
|
||||
if (name == "." || name == "..") {
|
||||
gb_free(a, name.text);
|
||||
@@ -299,7 +303,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
FileInfo info = {};
|
||||
info.name = name;
|
||||
info.fullpath = path_to_full_path(a, filepath);
|
||||
info.size = size;
|
||||
info.size = cast(i64)size;
|
||||
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||
array_add(fi, info);
|
||||
} while (FindNextFileW(find_file, &file_data));
|
||||
@@ -314,7 +318,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
|
||||
#include <dirent.h>
|
||||
|
||||
ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
||||
GB_ASSERT(fi != nullptr);
|
||||
|
||||
gbAllocator a = heap_allocator();
|
||||
|
||||
@@ -7,7 +7,7 @@ struct PriorityQueue {
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
|
||||
gb_internal bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
|
||||
// O(n log n)
|
||||
isize i = i0;
|
||||
isize j, j1, j2;
|
||||
@@ -29,7 +29,7 @@ bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
|
||||
gb_internal void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
|
||||
while (0 <= j && j < pq->queue.count) {
|
||||
isize i = (j-1)/2;
|
||||
if (i == j || pq->cmp(&pq->queue[0], j, i) >= 0) {
|
||||
@@ -43,20 +43,20 @@ void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
|
||||
// NOTE(bill): When an element at index `i0` has changed its value, this will fix the
|
||||
// the heap ordering. This using a basic "heapsort" with shift up and a shift down parts.
|
||||
template <typename T>
|
||||
void priority_queue_fix(PriorityQueue<T> *pq, isize i) {
|
||||
gb_internal void priority_queue_fix(PriorityQueue<T> *pq, isize i) {
|
||||
if (!priority_queue_shift_down(pq, i, pq->queue.count)) {
|
||||
priority_queue_shift_up(pq, i);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void priority_queue_push(PriorityQueue<T> *pq, T const &value) {
|
||||
gb_internal void priority_queue_push(PriorityQueue<T> *pq, T const &value) {
|
||||
array_add(&pq->queue, value);
|
||||
priority_queue_shift_up(pq, pq->queue.count-1);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T priority_queue_pop(PriorityQueue<T> *pq) {
|
||||
gb_internal T priority_queue_pop(PriorityQueue<T> *pq) {
|
||||
GB_ASSERT(pq->queue.count > 0);
|
||||
|
||||
isize n = pq->queue.count - 1;
|
||||
@@ -67,7 +67,7 @@ T priority_queue_pop(PriorityQueue<T> *pq) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
T priority_queue_remove(PriorityQueue<T> *pq, isize i) {
|
||||
gb_internal T priority_queue_remove(PriorityQueue<T> *pq, isize i) {
|
||||
GB_ASSERT(0 <= i && i < pq->queue.count);
|
||||
isize n = pq->queue.count - 1;
|
||||
if (n != i) {
|
||||
@@ -80,7 +80,7 @@ T priority_queue_remove(PriorityQueue<T> *pq, isize i) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
PriorityQueue<T> priority_queue_create(Array<T> queue,
|
||||
gb_internal PriorityQueue<T> priority_queue_create(Array<T> queue,
|
||||
int (* cmp) (T *q, isize i, isize j),
|
||||
void (* swap)(T *q, isize i, isize j)) {
|
||||
PriorityQueue<T> pq = {};
|
||||
|
||||
+224
-103
@@ -2,6 +2,13 @@
|
||||
|
||||
typedef u32 MapIndex;
|
||||
|
||||
enum {
|
||||
MAP_CACHE_LINE_SIZE_POW = 6,
|
||||
MAP_CACHE_LINE_SIZE = 1<<MAP_CACHE_LINE_SIZE_POW,
|
||||
MAP_CACHE_LINE_MASK = MAP_CACHE_LINE_SIZE-1,
|
||||
};
|
||||
|
||||
|
||||
struct MapFindResult {
|
||||
MapIndex hash_index;
|
||||
MapIndex entry_prev;
|
||||
@@ -21,12 +28,16 @@ struct PtrMapEntry {
|
||||
|
||||
template <typename K, typename V>
|
||||
struct PtrMap {
|
||||
Slice<MapIndex> hashes;
|
||||
Array<PtrMapEntry<K, V> > entries;
|
||||
MapIndex * hashes;
|
||||
usize hashes_count;
|
||||
PtrMapEntry<K, V> *entries;
|
||||
u32 count;
|
||||
u32 entries_capacity;
|
||||
};
|
||||
|
||||
|
||||
u32 ptr_map_hash_key(uintptr key) {
|
||||
gb_internal gb_inline u32 ptr_map_hash_key(uintptr key) {
|
||||
u32 res;
|
||||
#if defined(GB_ARCH_64_BIT)
|
||||
key = (~key) + (key << 21);
|
||||
key = key ^ (key >> 24);
|
||||
@@ -34,80 +45,96 @@ u32 ptr_map_hash_key(uintptr key) {
|
||||
key = key ^ (key >> 14);
|
||||
key = (key + (key << 2)) + (key << 4);
|
||||
key = key ^ (key << 28);
|
||||
return cast(u32)key;
|
||||
res = cast(u32)key;
|
||||
#elif defined(GB_ARCH_32_BIT)
|
||||
u32 state = ((u32)key) * 747796405u + 2891336453u;
|
||||
u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
||||
return (word >> 22u) ^ word;
|
||||
res = (word >> 22u) ^ word;
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
u32 ptr_map_hash_key(void const *key) {
|
||||
gb_internal gb_inline u32 ptr_map_hash_key(void const *key) {
|
||||
return ptr_map_hash_key((uintptr)key);
|
||||
}
|
||||
|
||||
|
||||
template <typename K, typename V> void map_init (PtrMap<K, V> *h, gbAllocator a, isize capacity = 16);
|
||||
template <typename K, typename V> void map_destroy (PtrMap<K, V> *h);
|
||||
template <typename K, typename V> V * map_get (PtrMap<K, V> *h, K key);
|
||||
template <typename K, typename V> void map_set (PtrMap<K, V> *h, K key, V const &value);
|
||||
template <typename K, typename V> void map_remove (PtrMap<K, V> *h, K key);
|
||||
template <typename K, typename V> void map_clear (PtrMap<K, V> *h);
|
||||
template <typename K, typename V> void map_grow (PtrMap<K, V> *h);
|
||||
template <typename K, typename V> void map_rehash (PtrMap<K, V> *h, isize new_count);
|
||||
template <typename K, typename V> void map_reserve (PtrMap<K, V> *h, isize cap);
|
||||
template <typename K, typename V> gb_internal void map_init (PtrMap<K, V> *h, isize capacity = 16);
|
||||
template <typename K, typename V> gb_internal void map_destroy (PtrMap<K, V> *h);
|
||||
template <typename K, typename V> gb_internal V * map_get (PtrMap<K, V> *h, K key);
|
||||
template <typename K, typename V> gb_internal void map_set (PtrMap<K, V> *h, K key, V const &value);
|
||||
template <typename K, typename V> gb_internal bool map_set_if_not_previously_exists(PtrMap<K, V> *h, K key, V const &value); // returns true if it previously existed
|
||||
template <typename K, typename V> gb_internal void map_remove (PtrMap<K, V> *h, K key);
|
||||
template <typename K, typename V> gb_internal void map_clear (PtrMap<K, V> *h);
|
||||
template <typename K, typename V> gb_internal void map_grow (PtrMap<K, V> *h);
|
||||
template <typename K, typename V> gb_internal void map_rehash (PtrMap<K, V> *h, isize new_count);
|
||||
template <typename K, typename V> gb_internal void map_reserve (PtrMap<K, V> *h, isize cap);
|
||||
|
||||
#if PTR_MAP_ENABLE_MULTI_MAP
|
||||
// Mutlivalued map procedure
|
||||
template <typename K, typename V> PtrMapEntry<K, V> * multi_map_find_first(PtrMap<K, V> *h, K key);
|
||||
template <typename K, typename V> PtrMapEntry<K, V> * multi_map_find_next (PtrMap<K, V> *h, PtrMapEntry<K, V> *e);
|
||||
template <typename K, typename V> gb_internal PtrMapEntry<K, V> * multi_map_find_first(PtrMap<K, V> *h, K key);
|
||||
template <typename K, typename V> gb_internal PtrMapEntry<K, V> * multi_map_find_next (PtrMap<K, V> *h, PtrMapEntry<K, V> *e);
|
||||
|
||||
template <typename K, typename V> isize multi_map_count (PtrMap<K, V> *h, K key);
|
||||
template <typename K, typename V> void multi_map_get_all (PtrMap<K, V> *h, K key, V *items);
|
||||
template <typename K, typename V> void multi_map_insert (PtrMap<K, V> *h, K key, V const &value);
|
||||
template <typename K, typename V> void multi_map_remove (PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e);
|
||||
template <typename K, typename V> void multi_map_remove_all(PtrMap<K, V> *h, K key);
|
||||
template <typename K, typename V> gb_internal isize multi_map_count (PtrMap<K, V> *h, K key);
|
||||
template <typename K, typename V> gb_internal void multi_map_get_all (PtrMap<K, V> *h, K key, V *items);
|
||||
template <typename K, typename V> gb_internal void multi_map_insert (PtrMap<K, V> *h, K key, V const &value);
|
||||
template <typename K, typename V> gb_internal void multi_map_remove (PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e);
|
||||
template <typename K, typename V> gb_internal void multi_map_remove_all(PtrMap<K, V> *h, K key);
|
||||
#endif
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_inline void map_init(PtrMap<K, V> *h, gbAllocator a, isize capacity) {
|
||||
capacity = next_pow2_isize(capacity);
|
||||
slice_init(&h->hashes, a, capacity);
|
||||
array_init(&h->entries, a, 0, capacity);
|
||||
for (isize i = 0; i < capacity; i++) {
|
||||
h->hashes.data[i] = MAP_SENTINEL;
|
||||
}
|
||||
gb_internal gbAllocator map_allocator(void) {
|
||||
return heap_allocator();
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_inline void map_destroy(PtrMap<K, V> *h) {
|
||||
slice_free(&h->hashes, h->entries.allocator);
|
||||
array_free(&h->entries);
|
||||
gb_internal gb_inline void map_init(PtrMap<K, V> *h, isize capacity) {
|
||||
capacity = next_pow2_isize(capacity);
|
||||
map_reserve(h, capacity);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal gb_inline void map_destroy(PtrMap<K, V> *h) {
|
||||
gbAllocator a = map_allocator();
|
||||
gb_free(a, h->hashes);
|
||||
gb_free(a, h->entries);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal void map__resize_hashes(PtrMap<K, V> *h, usize count) {
|
||||
h->hashes_count = cast(u32)resize_array_raw(&h->hashes, map_allocator(), h->hashes_count, count, MAP_CACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal void map__reserve_entries(PtrMap<K, V> *h, usize capacity) {
|
||||
h->entries_capacity = cast(u32)resize_array_raw(&h->entries, map_allocator(), h->entries_capacity, capacity, MAP_CACHE_LINE_SIZE);
|
||||
}
|
||||
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal MapIndex map__add_entry(PtrMap<K, V> *h, K key) {
|
||||
PtrMapEntry<K, V> e = {};
|
||||
e.key = key;
|
||||
e.next = MAP_SENTINEL;
|
||||
array_add(&h->entries, e);
|
||||
return cast(MapIndex)(h->entries.count-1);
|
||||
map__reserve_entries(h, h->count+1);
|
||||
h->entries[h->count++] = e;
|
||||
return cast(MapIndex)(h->count-1);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal MapFindResult map__find(PtrMap<K, V> *h, K key) {
|
||||
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
|
||||
if (h->hashes.count == 0) {
|
||||
if (h->hashes_count == 0) {
|
||||
return fr;
|
||||
}
|
||||
u32 hash = ptr_map_hash_key(key);
|
||||
fr.hash_index = cast(MapIndex)(hash & (h->hashes.count-1));
|
||||
fr.entry_index = h->hashes.data[fr.hash_index];
|
||||
fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
|
||||
fr.entry_index = h->hashes[fr.hash_index];
|
||||
while (fr.entry_index != MAP_SENTINEL) {
|
||||
if (h->entries.data[fr.entry_index].key == key) {
|
||||
auto *entry = &h->entries[fr.entry_index];
|
||||
if (entry->key == key) {
|
||||
return fr;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = h->entries.data[fr.entry_index].next;
|
||||
fr.entry_index = entry->next;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
@@ -115,41 +142,41 @@ gb_internal MapFindResult map__find(PtrMap<K, V> *h, K key) {
|
||||
template <typename K, typename V>
|
||||
gb_internal MapFindResult map__find_from_entry(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
|
||||
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
|
||||
if (h->hashes.count == 0) {
|
||||
if (h->hashes_count == 0) {
|
||||
return fr;
|
||||
}
|
||||
u32 hash = ptr_map_hash_key(e->key);
|
||||
fr.hash_index = cast(MapIndex)(hash & (h->hashes.count-1));
|
||||
fr.entry_index = h->hashes.data[fr.hash_index];
|
||||
fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
|
||||
fr.entry_index = h->hashes[fr.hash_index];
|
||||
while (fr.entry_index != MAP_SENTINEL) {
|
||||
if (&h->entries.data[fr.entry_index] == e) {
|
||||
if (&h->entries[fr.entry_index] == e) {
|
||||
return fr;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = h->entries.data[fr.entry_index].next;
|
||||
fr.entry_index = h->entries[fr.entry_index].next;
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal b32 map__full(PtrMap<K, V> *h) {
|
||||
return 0.75f * h->hashes.count <= h->entries.count;
|
||||
return 0.75f * h->hashes_count <= h->count;
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_inline void map_grow(PtrMap<K, V> *h) {
|
||||
isize new_count = gb_max(h->hashes.count<<1, 16);
|
||||
gb_internal gb_inline void map_grow(PtrMap<K, V> *h) {
|
||||
isize new_count = gb_max(h->hashes_count<<1, 16);
|
||||
map_rehash(h, new_count);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void map_reset_entries(PtrMap<K, V> *h) {
|
||||
for (isize i = 0; i < h->hashes.count; i++) {
|
||||
h->hashes.data[i] = MAP_SENTINEL;
|
||||
gb_internal void map_reset_entries(PtrMap<K, V> *h) {
|
||||
for (usize i = 0; i < h->hashes_count; i++) {
|
||||
h->hashes[i] = MAP_SENTINEL;
|
||||
}
|
||||
for (isize i = 0; i < h->entries.count; i++) {
|
||||
for (usize i = 0; i < h->count; i++) {
|
||||
MapFindResult fr;
|
||||
PtrMapEntry<K, V> *e = &h->entries.data[i];
|
||||
PtrMapEntry<K, V> *e = &h->entries[i];
|
||||
e->next = MAP_SENTINEL;
|
||||
fr = map__find_from_entry(h, e);
|
||||
if (fr.entry_prev == MAP_SENTINEL) {
|
||||
@@ -161,42 +188,88 @@ void map_reset_entries(PtrMap<K, V> *h) {
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void map_reserve(PtrMap<K, V> *h, isize cap) {
|
||||
array_reserve(&h->entries, cap);
|
||||
if (h->entries.count*2 < h->hashes.count) {
|
||||
gb_internal void map_reserve(PtrMap<K, V> *h, isize cap) {
|
||||
if (h->count*2 < h->hashes_count) {
|
||||
return;
|
||||
}
|
||||
slice_resize(&h->hashes, h->entries.allocator, cap*2);
|
||||
map__reserve_entries(h, cap);
|
||||
map__resize_hashes(h, cap*2);
|
||||
map_reset_entries(h);
|
||||
}
|
||||
|
||||
|
||||
template <typename K, typename V>
|
||||
void map_rehash(PtrMap<K, V> *h, isize new_count) {
|
||||
gb_internal void map_rehash(PtrMap<K, V> *h, isize new_count) {
|
||||
map_reserve(h, new_count);
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
V *map_get(PtrMap<K, V> *h, K key) {
|
||||
MapIndex index = map__find(h, key).entry_index;
|
||||
if (index != MAP_SENTINEL) {
|
||||
return &h->entries.data[index].value;
|
||||
gb_internal V *map_get(PtrMap<K, V> *h, K key) {
|
||||
MapIndex hash_index = MAP_SENTINEL;
|
||||
MapIndex entry_prev = MAP_SENTINEL;
|
||||
MapIndex entry_index = MAP_SENTINEL;
|
||||
if (h->hashes_count != 0) {
|
||||
u32 hash = ptr_map_hash_key(key);
|
||||
hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
|
||||
entry_index = h->hashes[hash_index];
|
||||
while (entry_index != MAP_SENTINEL) {
|
||||
auto *entry = &h->entries[entry_index];
|
||||
if (entry->key == key) {
|
||||
return &entry->value;
|
||||
}
|
||||
entry_prev = entry_index;
|
||||
entry_index = entry->next;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
template <typename K, typename V>
|
||||
gb_internal V *map_try_get(PtrMap<K, V> *h, K key, MapFindResult *fr_) {
|
||||
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
|
||||
if (h->hashes_count != 0) {
|
||||
u32 hash = ptr_map_hash_key(key);
|
||||
fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
|
||||
fr.entry_index = h->hashes[fr.hash_index];
|
||||
while (fr.entry_index != MAP_SENTINEL) {
|
||||
auto *entry = &h->entries[fr.entry_index];
|
||||
if (entry->key == key) {
|
||||
return &entry->value;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = entry->next;
|
||||
}
|
||||
}
|
||||
if (h->hashes_count == 0 || map__full(h)) {
|
||||
map_grow(h);
|
||||
}
|
||||
if (fr_) *fr_ = fr;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
template <typename K, typename V>
|
||||
V &map_must_get(PtrMap<K, V> *h, K key) {
|
||||
MapIndex index = map__find(h, key).entry_index;
|
||||
GB_ASSERT(index != MAP_SENTINEL);
|
||||
return h->entries.data[index].value;
|
||||
gb_internal void map_set_internal_from_try_get(PtrMap<K, V> *h, K key, V const &value, MapFindResult const &fr) {
|
||||
MapIndex index = map__add_entry(h, key);
|
||||
if (fr.entry_prev != MAP_SENTINEL) {
|
||||
h->entries[fr.entry_prev].next = index;
|
||||
} else {
|
||||
h->hashes[fr.hash_index] = index;
|
||||
}
|
||||
h->entries[index].value = value;
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void map_set(PtrMap<K, V> *h, K key, V const &value) {
|
||||
gb_internal V &map_must_get(PtrMap<K, V> *h, K key) {
|
||||
V *ptr = map_get(h, key);
|
||||
GB_ASSERT(ptr != nullptr);
|
||||
return *ptr;
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal void map_set(PtrMap<K, V> *h, K key, V const &value) {
|
||||
MapIndex index;
|
||||
MapFindResult fr;
|
||||
if (h->hashes.count == 0) {
|
||||
if (h->hashes_count == 0) {
|
||||
map_grow(h);
|
||||
}
|
||||
fr = map__find(h, key);
|
||||
@@ -205,44 +278,71 @@ void map_set(PtrMap<K, V> *h, K key, V const &value) {
|
||||
} else {
|
||||
index = map__add_entry(h, key);
|
||||
if (fr.entry_prev != MAP_SENTINEL) {
|
||||
h->entries.data[fr.entry_prev].next = index;
|
||||
h->entries[fr.entry_prev].next = index;
|
||||
} else {
|
||||
h->hashes.data[fr.hash_index] = index;
|
||||
h->hashes[fr.hash_index] = index;
|
||||
}
|
||||
}
|
||||
h->entries.data[index].value = value;
|
||||
h->entries[index].value = value;
|
||||
|
||||
if (map__full(h)) {
|
||||
map_grow(h);
|
||||
}
|
||||
}
|
||||
|
||||
// returns true if it previously existed
|
||||
template <typename K, typename V>
|
||||
gb_internal bool map_set_if_not_previously_exists(PtrMap<K, V> *h, K key, V const &value) {
|
||||
MapIndex index;
|
||||
MapFindResult fr;
|
||||
if (h->hashes_count == 0) {
|
||||
map_grow(h);
|
||||
}
|
||||
fr = map__find(h, key);
|
||||
if (fr.entry_index != MAP_SENTINEL) {
|
||||
return true;
|
||||
} else {
|
||||
index = map__add_entry(h, key);
|
||||
if (fr.entry_prev != MAP_SENTINEL) {
|
||||
h->entries[fr.entry_prev].next = index;
|
||||
} else {
|
||||
h->hashes[fr.hash_index] = index;
|
||||
}
|
||||
}
|
||||
h->entries[index].value = value;
|
||||
|
||||
if (map__full(h)) {
|
||||
map_grow(h);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
template <typename K, typename V>
|
||||
void map__erase(PtrMap<K, V> *h, MapFindResult const &fr) {
|
||||
gb_internal void map__erase(PtrMap<K, V> *h, MapFindResult const &fr) {
|
||||
MapFindResult last;
|
||||
if (fr.entry_prev == MAP_SENTINEL) {
|
||||
h->hashes.data[fr.hash_index] = h->entries.data[fr.entry_index].next;
|
||||
h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
|
||||
} else {
|
||||
h->entries.data[fr.entry_prev].next = h->entries.data[fr.entry_index].next;
|
||||
h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next;
|
||||
}
|
||||
if (fr.entry_index == h->entries.count-1) {
|
||||
array_pop(&h->entries);
|
||||
if (fr.entry_index == h->count-1) {
|
||||
h->count--;
|
||||
return;
|
||||
}
|
||||
h->entries.data[fr.entry_index] = h->entries.data[h->entries.count-1];
|
||||
array_pop(&h->entries);
|
||||
h->entries[fr.entry_index] = h->entries[h->count-1];
|
||||
h->count--;
|
||||
|
||||
last = map__find(h, h->entries.data[fr.entry_index].key);
|
||||
last = map__find(h, h->entries[fr.entry_index].key);
|
||||
if (last.entry_prev != MAP_SENTINEL) {
|
||||
h->entries.data[last.entry_prev].next = fr.entry_index;
|
||||
h->entries[last.entry_prev].next = fr.entry_index;
|
||||
} else {
|
||||
h->hashes.data[last.hash_index] = fr.entry_index;
|
||||
h->hashes[last.hash_index] = fr.entry_index;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void map_remove(PtrMap<K, V> *h, K key) {
|
||||
gb_internal void map_remove(PtrMap<K, V> *h, K key) {
|
||||
MapFindResult fr = map__find(h, key);
|
||||
if (fr.entry_index != MAP_SENTINEL) {
|
||||
map__erase(h, fr);
|
||||
@@ -250,38 +350,38 @@ void map_remove(PtrMap<K, V> *h, K key) {
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_inline void map_clear(PtrMap<K, V> *h) {
|
||||
array_clear(&h->entries);
|
||||
for (isize i = 0; i < h->hashes.count; i++) {
|
||||
h->hashes.data[i] = MAP_SENTINEL;
|
||||
gb_internal gb_inline void map_clear(PtrMap<K, V> *h) {
|
||||
h->count = 0;
|
||||
for (usize i = 0; i < h->hashes_count; i++) {
|
||||
h->hashes[i] = MAP_SENTINEL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#if PTR_MAP_ENABLE_MULTI_MAP
|
||||
template <typename K, typename V>
|
||||
PtrMapEntry<K, V> *multi_map_find_first(PtrMap<K, V> *h, K key) {
|
||||
gb_internal PtrMapEntry<K, V> *multi_map_find_first(PtrMap<K, V> *h, K key) {
|
||||
MapIndex i = map__find(h, key).entry_index;
|
||||
if (i == MAP_SENTINEL) {
|
||||
return nullptr;
|
||||
}
|
||||
return &h->entries.data[i];
|
||||
return &h->entries[i];
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
PtrMapEntry<K, V> *multi_map_find_next(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
|
||||
gb_internal PtrMapEntry<K, V> *multi_map_find_next(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
|
||||
MapIndex i = e->next;
|
||||
while (i != MAP_SENTINEL) {
|
||||
if (h->entries.data[i].key == e->key) {
|
||||
return &h->entries.data[i];
|
||||
if (h->entries[i].key == e->key) {
|
||||
return &h->entries[i];
|
||||
}
|
||||
i = h->entries.data[i].next;
|
||||
i = h->entries[i].next;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
isize multi_map_count(PtrMap<K, V> *h, K key) {
|
||||
gb_internal isize multi_map_count(PtrMap<K, V> *h, K key) {
|
||||
isize count = 0;
|
||||
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
|
||||
while (e != nullptr) {
|
||||
@@ -292,8 +392,8 @@ isize multi_map_count(PtrMap<K, V> *h, K key) {
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
|
||||
isize i = 0;
|
||||
gb_internal void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
|
||||
usize i = 0;
|
||||
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
|
||||
while (e != nullptr) {
|
||||
items[i++] = e->value;
|
||||
@@ -302,22 +402,22 @@ void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void multi_map_insert(PtrMap<K, V> *h, K key, V const &value) {
|
||||
gb_internal void multi_map_insert(PtrMap<K, V> *h, K key, V const &value) {
|
||||
MapFindResult fr;
|
||||
MapIndex i;
|
||||
if (h->hashes.count == 0) {
|
||||
if (h->hashes_count == 0) {
|
||||
map_grow(h);
|
||||
}
|
||||
// Make
|
||||
fr = map__find(h, key);
|
||||
i = map__add_entry(h, key);
|
||||
if (fr.entry_prev == MAP_SENTINEL) {
|
||||
h->hashes.data[fr.hash_index] = i;
|
||||
h->hashes[fr.hash_index] = i;
|
||||
} else {
|
||||
h->entries.data[fr.entry_prev].next = i;
|
||||
h->entries[fr.entry_prev].next = i;
|
||||
}
|
||||
h->entries.data[i].next = fr.entry_index;
|
||||
h->entries.data[i].value = value;
|
||||
h->entries[i].next = fr.entry_index;
|
||||
h->entries[i].value = value;
|
||||
// Grow if needed
|
||||
if (map__full(h)) {
|
||||
map_grow(h);
|
||||
@@ -325,7 +425,7 @@ void multi_map_insert(PtrMap<K, V> *h, K key, V const &value) {
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void multi_map_remove(PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e) {
|
||||
gb_internal void multi_map_remove(PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e) {
|
||||
MapFindResult fr = map__find_from_entry(h, e);
|
||||
if (fr.entry_index != MAP_SENTINEL) {
|
||||
map__erase(h, fr);
|
||||
@@ -333,9 +433,30 @@ void multi_map_remove(PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e) {
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
void multi_map_remove_all(PtrMap<K, V> *h, K key) {
|
||||
gb_internal void multi_map_remove_all(PtrMap<K, V> *h, K key) {
|
||||
while (map_get(h, key) != nullptr) {
|
||||
map_remove(h, key);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal PtrMapEntry<K, V> *begin(PtrMap<K, V> &m) {
|
||||
return m.entries;
|
||||
}
|
||||
template <typename K, typename V>
|
||||
gb_internal PtrMapEntry<K, V> const *begin(PtrMap<K, V> const &m) {
|
||||
return m.entries;
|
||||
}
|
||||
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal PtrMapEntry<K, V> *end(PtrMap<K, V> &m) {
|
||||
return m.entries + m.count;
|
||||
}
|
||||
|
||||
template <typename K, typename V>
|
||||
gb_internal PtrMapEntry<K, V> const *end(PtrMap<K, V> const &m) {
|
||||
return m.entries + m.count;
|
||||
}
|
||||
|
||||
+162
-193
@@ -1,235 +1,204 @@
|
||||
template <typename T>
|
||||
struct PtrSetEntry {
|
||||
T ptr;
|
||||
MapIndex next;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct PtrSet {
|
||||
Slice<MapIndex> hashes;
|
||||
Array<PtrSetEntry<T>> entries;
|
||||
static_assert(TypeIsPointer<T>::value, "PtrSet::T must be a pointer");
|
||||
static constexpr uintptr TOMBSTONE = ~(uintptr)(0ull);
|
||||
|
||||
T * keys;
|
||||
usize count;
|
||||
usize capacity;
|
||||
};
|
||||
|
||||
template <typename T> void ptr_set_init (PtrSet<T> *s, gbAllocator a, isize capacity = 16);
|
||||
template <typename T> void ptr_set_destroy(PtrSet<T> *s);
|
||||
template <typename T> T ptr_set_add (PtrSet<T> *s, T ptr);
|
||||
template <typename T> bool ptr_set_update (PtrSet<T> *s, T ptr); // returns true if it previously existed
|
||||
template <typename T> bool ptr_set_exists (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
|
||||
template <typename T> void ptr_set_clear (PtrSet<T> *s);
|
||||
template <typename T> void ptr_set_grow (PtrSet<T> *s);
|
||||
template <typename T> void ptr_set_rehash (PtrSet<T> *s, isize new_count);
|
||||
template <typename T> void ptr_set_reserve(PtrSet<T> *h, isize cap);
|
||||
template <typename T> gb_internal void ptr_set_init (PtrSet<T> *s, isize capacity = 16);
|
||||
template <typename T> gb_internal void ptr_set_destroy(PtrSet<T> *s);
|
||||
template <typename T> gb_internal T ptr_set_add (PtrSet<T> *s, T ptr);
|
||||
template <typename T> gb_internal bool ptr_set_update (PtrSet<T> *s, T ptr); // returns true if it previously existed
|
||||
template <typename T> gb_internal bool ptr_set_exists (PtrSet<T> *s, T ptr);
|
||||
template <typename T> gb_internal void ptr_set_remove (PtrSet<T> *s, T ptr);
|
||||
template <typename T> gb_internal void ptr_set_clear (PtrSet<T> *s);
|
||||
|
||||
gb_internal gbAllocator ptr_set_allocator(void) {
|
||||
return heap_allocator();
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_init(PtrSet<T> *s, gbAllocator a, isize capacity) {
|
||||
gb_internal void ptr_set_init(PtrSet<T> *s, isize capacity) {
|
||||
GB_ASSERT(s->keys == nullptr);
|
||||
if (capacity != 0) {
|
||||
capacity = next_pow2_isize(gb_max(16, capacity));
|
||||
s->keys = gb_alloc_array(ptr_set_allocator(), T, capacity);
|
||||
// This memory will be zeroed, no need to explicitly zero it
|
||||
}
|
||||
|
||||
slice_init(&s->hashes, a, capacity);
|
||||
array_init(&s->entries, a, 0, capacity);
|
||||
for (isize i = 0; i < capacity; i++) {
|
||||
s->hashes.data[i] = MAP_SENTINEL;
|
||||
}
|
||||
s->count = 0;
|
||||
s->capacity = capacity;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_destroy(PtrSet<T> *s) {
|
||||
slice_free(&s->hashes, s->entries.allocator);
|
||||
array_free(&s->entries);
|
||||
gb_internal void ptr_set_destroy(PtrSet<T> *s) {
|
||||
gb_free(ptr_set_allocator(), s->keys);
|
||||
s->keys = nullptr;
|
||||
s->count = 0;
|
||||
s->capacity = 0;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal MapIndex ptr_set__add_entry(PtrSet<T> *s, T ptr) {
|
||||
PtrSetEntry<T> e = {};
|
||||
e.ptr = ptr;
|
||||
e.next = MAP_SENTINEL;
|
||||
array_add(&s->entries, e);
|
||||
return cast(MapIndex)(s->entries.count-1);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_internal MapFindResult ptr_set__find(PtrSet<T> *s, T ptr) {
|
||||
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
|
||||
if (s->hashes.count != 0) {
|
||||
gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
|
||||
GB_ASSERT(ptr != nullptr);
|
||||
if (s->count != 0) {
|
||||
#if 0
|
||||
for (usize i = 0; i < s->capacity; i++) {
|
||||
if (s->keys[i] == ptr) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
#else
|
||||
u32 hash = ptr_map_hash_key(ptr);
|
||||
fr.hash_index = cast(MapIndex)(hash & (s->hashes.count-1));
|
||||
fr.entry_index = s->hashes.data[fr.hash_index];
|
||||
while (fr.entry_index != MAP_SENTINEL) {
|
||||
if (s->entries.data[fr.entry_index].ptr == ptr) {
|
||||
return fr;
|
||||
usize mask = s->capacity-1;
|
||||
usize hash_index = cast(usize)hash & mask;
|
||||
for (usize i = 0; i < s->capacity; i++) {
|
||||
T key = s->keys[hash_index];
|
||||
if (key == ptr) {
|
||||
return hash_index;
|
||||
} else if (key == nullptr) {
|
||||
return -1;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = s->entries.data[fr.entry_index].next;
|
||||
hash_index = (hash_index+1)&mask;
|
||||
}
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal MapFindResult ptr_set__find_from_entry(PtrSet<T> *s, PtrSetEntry<T> *e) {
|
||||
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
|
||||
if (s->hashes.count != 0) {
|
||||
u32 hash = ptr_map_hash_key(e->ptr);
|
||||
fr.hash_index = cast(MapIndex)(hash & (s->hashes.count-1));
|
||||
fr.entry_index = s->hashes.data[fr.hash_index];
|
||||
while (fr.entry_index != MAP_SENTINEL) {
|
||||
if (&s->entries.data[fr.entry_index] == e) {
|
||||
return fr;
|
||||
}
|
||||
fr.entry_prev = fr.entry_index;
|
||||
fr.entry_index = s->entries.data[fr.entry_index].next;
|
||||
}
|
||||
}
|
||||
return fr;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal bool ptr_set__full(PtrSet<T> *s) {
|
||||
return 0.75f * s->hashes.count <= s->entries.count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void ptr_set_grow(PtrSet<T> *s) {
|
||||
isize new_count = gb_max(s->hashes.count<<1, 16);
|
||||
ptr_set_rehash(s, new_count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_reset_entries(PtrSet<T> *s) {
|
||||
for (isize i = 0; i < s->hashes.count; i++) {
|
||||
s->hashes.data[i] = MAP_SENTINEL;
|
||||
}
|
||||
for (isize i = 0; i < s->entries.count; i++) {
|
||||
MapFindResult fr;
|
||||
PtrSetEntry<T> *e = &s->entries.data[i];
|
||||
e->next = MAP_SENTINEL;
|
||||
fr = ptr_set__find_from_entry(s, e);
|
||||
if (fr.entry_prev == MAP_SENTINEL) {
|
||||
s->hashes[fr.hash_index] = cast(MapIndex)i;
|
||||
} else {
|
||||
s->entries[fr.entry_prev].next = cast(MapIndex)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_reserve(PtrSet<T> *s, isize cap) {
|
||||
array_reserve(&s->entries, cap);
|
||||
if (s->entries.count*2 < s->hashes.count) {
|
||||
return;
|
||||
}
|
||||
slice_resize(&s->hashes, s->entries.allocator, cap*2);
|
||||
ptr_set_reset_entries(s);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_rehash(PtrSet<T> *s, isize new_count) {
|
||||
ptr_set_reserve(s, new_count);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
|
||||
isize index = ptr_set__find(s, ptr).entry_index;
|
||||
return index != MAP_SENTINEL;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline isize ptr_entry_index(PtrSet<T> *s, T ptr) {
|
||||
isize index = ptr_set__find(s, ptr).entry_index;
|
||||
if (index != MAP_SENTINEL) {
|
||||
return index;
|
||||
#endif
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Returns true if it already exists
|
||||
template <typename T>
|
||||
T ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
MapIndex index;
|
||||
MapFindResult fr;
|
||||
if (s->hashes.count == 0) {
|
||||
gb_internal bool ptr_set__full(PtrSet<T> *s) {
|
||||
return 0.75f * s->capacity <= s->count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal gb_inline void ptr_set_grow(PtrSet<T> *old_set) {
|
||||
if (old_set->capacity == 0) {
|
||||
ptr_set_init(old_set);
|
||||
return;
|
||||
}
|
||||
|
||||
PtrSet<T> new_set = {};
|
||||
ptr_set_init(&new_set, gb_max(old_set->capacity<<1, 16));
|
||||
|
||||
for (T ptr : *old_set) {
|
||||
bool was_new = ptr_set_update(&new_set, ptr);
|
||||
GB_ASSERT(!was_new);
|
||||
}
|
||||
GB_ASSERT(old_set->count == new_set.count);
|
||||
|
||||
ptr_set_destroy(old_set);
|
||||
|
||||
*old_set = new_set;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_internal gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
|
||||
return ptr_set__find(s, ptr) >= 0;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_internal bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it previously existsed
|
||||
if (ptr_set_exists(s, ptr)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (s->keys == nullptr) {
|
||||
ptr_set_init(s);
|
||||
} else if (ptr_set__full(s)) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
fr = ptr_set__find(s, ptr);
|
||||
if (fr.entry_index == MAP_SENTINEL) {
|
||||
index = ptr_set__add_entry(s, ptr);
|
||||
if (fr.entry_prev != MAP_SENTINEL) {
|
||||
s->entries.data[fr.entry_prev].next = index;
|
||||
} else {
|
||||
s->hashes.data[fr.hash_index] = index;
|
||||
GB_ASSERT(s->count < s->capacity);
|
||||
GB_ASSERT(s->capacity >= 0);
|
||||
|
||||
usize mask = s->capacity-1;
|
||||
u32 hash = ptr_map_hash_key(ptr);
|
||||
usize hash_index = (cast(usize)hash) & mask;
|
||||
GB_ASSERT(hash_index < s->capacity);
|
||||
for (usize i = 0; i < s->capacity; i++) {
|
||||
T *key = &s->keys[hash_index];
|
||||
GB_ASSERT(*key != ptr);
|
||||
if (*key == (T)PtrSet<T>::TOMBSTONE || *key == nullptr) {
|
||||
*key = ptr;
|
||||
s->count++;
|
||||
return false;
|
||||
}
|
||||
hash_index = (hash_index+1)&mask;
|
||||
}
|
||||
if (ptr_set__full(s)) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
|
||||
GB_PANIC("ptr set out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal T ptr_set_add(PtrSet<T> *s, T ptr) {
|
||||
ptr_set_update(s, ptr);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it previously existsed
|
||||
bool exists = false;
|
||||
MapIndex index;
|
||||
MapFindResult fr;
|
||||
if (s->hashes.count == 0) {
|
||||
ptr_set_grow(s);
|
||||
gb_internal void ptr_set_remove(PtrSet<T> *s, T ptr) {
|
||||
isize index = ptr_set__find(s, ptr);
|
||||
if (index >= 0) {
|
||||
GB_ASSERT(s->count > 0);
|
||||
s->keys[index] = (T)PtrSet<T>::TOMBSTONE;
|
||||
s->count--;
|
||||
}
|
||||
fr = ptr_set__find(s, ptr);
|
||||
if (fr.entry_index != MAP_SENTINEL) {
|
||||
exists = true;
|
||||
} else {
|
||||
index = ptr_set__add_entry(s, ptr);
|
||||
if (fr.entry_prev != MAP_SENTINEL) {
|
||||
s->entries.data[fr.entry_prev].next = index;
|
||||
} else {
|
||||
s->hashes.data[fr.hash_index] = index;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal gb_inline void ptr_set_clear(PtrSet<T> *s) {
|
||||
s->count = 0;
|
||||
gb_zero_size(s->keys, s->capacity*gb_size_of(T));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct PtrSetIterator {
|
||||
PtrSet<T> *set;
|
||||
usize index;
|
||||
|
||||
PtrSetIterator<T> &operator++() noexcept {
|
||||
for (;;) {
|
||||
++index;
|
||||
if (set->capacity == index) {
|
||||
return *this;
|
||||
}
|
||||
T key = set->keys[index];
|
||||
if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ptr_set__full(s)) {
|
||||
ptr_set_grow(s);
|
||||
}
|
||||
return exists;
|
||||
}
|
||||
|
||||
bool operator==(PtrSetIterator<T> const &other) const noexcept {
|
||||
return this->set == other.set && this->index == other.index;
|
||||
}
|
||||
|
||||
|
||||
operator T *() const {
|
||||
return &set->keys[index];
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
template <typename T>
|
||||
void ptr_set__erase(PtrSet<T> *s, MapFindResult fr) {
|
||||
MapFindResult last;
|
||||
if (fr.entry_prev == MAP_SENTINEL) {
|
||||
s->hashes.data[fr.hash_index] = s->entries.data[fr.entry_index].next;
|
||||
} else {
|
||||
s->entries.data[fr.entry_prev].next = s->entries.data[fr.entry_index].next;
|
||||
}
|
||||
if (cast(isize)fr.entry_index == s->entries.count-1) {
|
||||
array_pop(&s->entries);
|
||||
return;
|
||||
}
|
||||
s->entries.data[fr.entry_index] = s->entries.data[s->entries.count-1];
|
||||
last = ptr_set__find(s, s->entries.data[fr.entry_index].ptr);
|
||||
if (last.entry_prev != MAP_SENTINEL) {
|
||||
s->entries.data[last.entry_prev].next = fr.entry_index;
|
||||
} else {
|
||||
s->hashes.data[last.hash_index] = fr.entry_index;
|
||||
gb_internal PtrSetIterator<T> begin(PtrSet<T> &set) noexcept {
|
||||
usize index = 0;
|
||||
while (index < set.capacity) {
|
||||
T key = set.keys[index];
|
||||
if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return PtrSetIterator<T>{&set, index};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void ptr_set_remove(PtrSet<T> *s, T ptr) {
|
||||
MapFindResult fr = ptr_set__find(s, ptr);
|
||||
if (fr.entry_index != MAP_SENTINEL) {
|
||||
ptr_set__erase(s, fr);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_inline void ptr_set_clear(PtrSet<T> *s) {
|
||||
array_clear(&s->entries);
|
||||
for (isize i = 0; i < s->hashes.count; i++) {
|
||||
s->hashes.data[i] = MAP_SENTINEL;
|
||||
}
|
||||
}
|
||||
gb_internal PtrSetIterator<T> end(PtrSet<T> &set) noexcept {
|
||||
return PtrSetIterator<T>{&set, set.capacity};
|
||||
}
|
||||
-1030
File diff suppressed because it is too large
Load Diff
+99
-14
@@ -1,3 +1,86 @@
|
||||
template <typename T>
|
||||
struct MPSCNode {
|
||||
std::atomic<MPSCNode<T> *> next;
|
||||
T value;
|
||||
};
|
||||
|
||||
//
|
||||
// Multiple Producer Single Consumer Lockless Queue
|
||||
// URL: https://www.1024cores.net
|
||||
//
|
||||
template <typename T>
|
||||
struct MPSCQueue {
|
||||
MPSCNode<T> sentinel;
|
||||
std::atomic<MPSCNode<T> *> head;
|
||||
std::atomic<MPSCNode<T> *> tail;
|
||||
std::atomic<isize> count;
|
||||
};
|
||||
|
||||
template <typename T> gb_internal void mpsc_init (MPSCQueue<T> *q);
|
||||
template <typename T> gb_internal void mpsc_destroy(MPSCQueue<T> *q);
|
||||
template <typename T> gb_internal isize mpsc_enqueue(MPSCQueue<T> *q, T const &value);
|
||||
template <typename T> gb_internal bool mpsc_dequeue(MPSCQueue<T> *q, T *value_);
|
||||
|
||||
template <typename T>
|
||||
gb_internal void mpsc_init(MPSCQueue<T> *q, gbAllocator const &allocator) {
|
||||
q->sentinel.next.store(nullptr, std::memory_order_relaxed);
|
||||
q->head.store(&q->sentinel, std::memory_order_relaxed);
|
||||
q->tail.store(&q->sentinel, std::memory_order_relaxed);
|
||||
q->count.store(0, std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal void mpsc_destroy(MPSCQueue<T> *q) {
|
||||
GB_ASSERT(q->count.load() == 0);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal MPSCNode<T> *mpsc_alloc_node(MPSCQueue<T> *q, T const &value) {
|
||||
auto new_node = gb_alloc_item(heap_allocator(), MPSCNode<T>);
|
||||
new_node->value = value;
|
||||
return new_node;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal void mpsc_free_node(MPSCQueue<T> *q, MPSCNode<T> *node) {
|
||||
// TODO(bill): determine a good way to handle the freed nodes rather than letting them leak
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal isize mpsc_enqueue(MPSCQueue<T> *q, MPSCNode<T> *node) {
|
||||
node->next.store(nullptr, std::memory_order_relaxed);
|
||||
auto prev = q->head.exchange(node, std::memory_order_acq_rel);
|
||||
prev->next.store(node, std::memory_order_release);
|
||||
isize count = 1 + q->count.fetch_add(1, std::memory_order_relaxed);
|
||||
return count;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
gb_internal isize mpsc_enqueue(MPSCQueue<T> *q, T const &value) {
|
||||
auto node = mpsc_alloc_node(q, value);
|
||||
return mpsc_enqueue(q, node);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
gb_internal bool mpsc_dequeue(MPSCQueue<T> *q, T *value_) {
|
||||
auto tail = q->tail.load(std::memory_order_relaxed);
|
||||
auto next = tail->next.load(std::memory_order_relaxed);
|
||||
if (next) {
|
||||
q->tail.store(next, std::memory_order_relaxed);
|
||||
if (value_) *value_ = next->value;
|
||||
q->count.fetch_sub(1, std::memory_order_relaxed);
|
||||
mpsc_free_node(q, tail);
|
||||
return true;
|
||||
}
|
||||
GB_ASSERT(q->count.load(std::memory_order_acquire) == 0);
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////
|
||||
|
||||
|
||||
|
||||
#define MPMC_CACHE_LINE_SIZE 64
|
||||
|
||||
typedef std::atomic<i32> MPMCQueueAtomicIdx;
|
||||
@@ -9,7 +92,6 @@ struct MPMCQueue {
|
||||
|
||||
T * nodes;
|
||||
MPMCQueueAtomicIdx *indices;
|
||||
gbAllocator allocator;
|
||||
BlockingMutex mutex;
|
||||
MPMCQueueAtomicIdx count;
|
||||
i32 mask; // capacity-1, because capacity must be a power of 2
|
||||
@@ -22,8 +104,11 @@ struct MPMCQueue {
|
||||
};
|
||||
|
||||
|
||||
gb_internal gbAllocator mpmc_allocator(void) {
|
||||
return heap_allocator();
|
||||
}
|
||||
|
||||
void mpmc_internal_init_indices(MPMCQueueAtomicIdx *indices, i32 offset, i32 size) {
|
||||
gb_internal void mpmc_internal_init_indices(MPMCQueueAtomicIdx *indices, i32 offset, i32 size) {
|
||||
GB_ASSERT(offset % 8 == 0);
|
||||
GB_ASSERT(size % 8 == 0);
|
||||
|
||||
@@ -43,7 +128,7 @@ void mpmc_internal_init_indices(MPMCQueueAtomicIdx *indices, i32 offset, i32 siz
|
||||
|
||||
|
||||
template <typename T>
|
||||
void mpmc_init(MPMCQueue<T> *q, gbAllocator a, isize size_i) {
|
||||
gb_internal void mpmc_init(MPMCQueue<T> *q, isize size_i) {
|
||||
if (size_i < 8) {
|
||||
size_i = 8;
|
||||
}
|
||||
@@ -52,9 +137,8 @@ void mpmc_init(MPMCQueue<T> *q, gbAllocator a, isize size_i) {
|
||||
size = next_pow2(size);
|
||||
GB_ASSERT(gb_is_power_of_two(size));
|
||||
|
||||
mutex_init(&q->mutex);
|
||||
q->mask = size-1;
|
||||
q->allocator = a;
|
||||
gbAllocator a = mpmc_allocator();
|
||||
q->nodes = gb_alloc_array(a, T, size);
|
||||
q->indices = gb_alloc_array(a, MPMCQueueAtomicIdx, size);
|
||||
|
||||
@@ -64,25 +148,26 @@ void mpmc_init(MPMCQueue<T> *q, gbAllocator a, isize size_i) {
|
||||
|
||||
|
||||
template <typename T>
|
||||
void mpmc_destroy(MPMCQueue<T> *q) {
|
||||
mutex_destroy(&q->mutex);
|
||||
gb_free(q->allocator, q->nodes);
|
||||
gb_free(q->allocator, q->indices);
|
||||
gb_internal void mpmc_destroy(MPMCQueue<T> *q) {
|
||||
gbAllocator a = mpmc_allocator();
|
||||
gb_free(a, q->nodes);
|
||||
gb_free(a, q->indices);
|
||||
}
|
||||
|
||||
|
||||
template <typename T>
|
||||
bool mpmc_internal_grow(MPMCQueue<T> *q) {
|
||||
gb_internal bool mpmc_internal_grow(MPMCQueue<T> *q) {
|
||||
gbAllocator a = mpmc_allocator();
|
||||
mutex_lock(&q->mutex);
|
||||
i32 old_size = q->mask+1;
|
||||
i32 new_size = old_size*2;
|
||||
resize_array_raw(&q->nodes, q->allocator, old_size, new_size);
|
||||
resize_array_raw(&q->nodes, a, old_size, new_size);
|
||||
if (q->nodes == nullptr) {
|
||||
GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size);
|
||||
mutex_unlock(&q->mutex);
|
||||
return false;
|
||||
}
|
||||
resize_array_raw(&q->indices, q->allocator, old_size, new_size);
|
||||
resize_array_raw(&q->indices, a, old_size, new_size);
|
||||
if (q->indices == nullptr) {
|
||||
GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size);
|
||||
mutex_unlock(&q->mutex);
|
||||
@@ -95,7 +180,7 @@ bool mpmc_internal_grow(MPMCQueue<T> *q) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
i32 mpmc_enqueue(MPMCQueue<T> *q, T const &data) {
|
||||
gb_internal i32 mpmc_enqueue(MPMCQueue<T> *q, T const &data) {
|
||||
GB_ASSERT(q->mask != 0);
|
||||
|
||||
i32 head_idx = q->head_idx.load(std::memory_order_relaxed);
|
||||
@@ -125,7 +210,7 @@ i32 mpmc_enqueue(MPMCQueue<T> *q, T const &data) {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool mpmc_dequeue(MPMCQueue<T> *q, T *data_) {
|
||||
gb_internal bool mpmc_dequeue(MPMCQueue<T> *q, T *data_) {
|
||||
if (q->mask == 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
+13
-13
@@ -10,17 +10,17 @@ struct RangeCache {
|
||||
};
|
||||
|
||||
|
||||
RangeCache range_cache_make(gbAllocator a) {
|
||||
gb_internal RangeCache range_cache_make(gbAllocator a) {
|
||||
RangeCache cache = {};
|
||||
array_init(&cache.ranges, a);
|
||||
return cache;
|
||||
}
|
||||
|
||||
void range_cache_destroy(RangeCache *c) {
|
||||
gb_internal void range_cache_destroy(RangeCache *c) {
|
||||
array_free(&c->ranges);
|
||||
}
|
||||
|
||||
bool range_cache_add_index(RangeCache *c, i64 index) {
|
||||
gb_internal bool range_cache_add_index(RangeCache *c, i64 index) {
|
||||
for_array(i, c->ranges) {
|
||||
RangeValue v = c->ranges[i];
|
||||
if (v.lo <= index && index <= v.hi) {
|
||||
@@ -33,7 +33,7 @@ bool range_cache_add_index(RangeCache *c, i64 index) {
|
||||
}
|
||||
|
||||
|
||||
bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) {
|
||||
gb_internal bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) {
|
||||
GB_ASSERT(lo <= hi);
|
||||
for_array(i, c->ranges) {
|
||||
RangeValue v = c->ranges[i];
|
||||
@@ -59,12 +59,12 @@ bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) {
|
||||
}
|
||||
|
||||
|
||||
bool range_cache_index_exists(RangeCache *c, i64 index) {
|
||||
for_array(i, c->ranges) {
|
||||
RangeValue v = c->ranges[i];
|
||||
if (v.lo <= index && index <= v.hi) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// gb_internal bool range_cache_index_exists(RangeCache *c, i64 index) {
|
||||
// for_array(i, c->ranges) {
|
||||
// RangeValue v = c->ranges[i];
|
||||
// if (v.lo <= index && index <= v.hi) {
|
||||
// return true;
|
||||
// }
|
||||
// }
|
||||
// return false;
|
||||
// }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user