mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-12 22:31:25 -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
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Close Stale Issues
|
- name: Close Stale Issues
|
||||||
uses: actions/stale@v4.1.0
|
uses: actions/stale@v7.0.0
|
||||||
with:
|
with:
|
||||||
# stale-issue-message: |
|
# stale-issue-message: |
|
||||||
# Hello!
|
# 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..
|
# 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-stale: 120
|
||||||
days-before-close: 30
|
days-before-close: -1
|
||||||
exempt-draft-pr: true
|
exempt-draft-pr: true
|
||||||
ascending: true
|
ascending: true
|
||||||
operations-per-run: 1000
|
operations-per-run: 1000
|
||||||
|
|||||||
@@ -62,12 +62,14 @@ if %release_mode% EQU 0 ( rem Debug
|
|||||||
set compiler_warnings= ^
|
set compiler_warnings= ^
|
||||||
-W4 -WX ^
|
-W4 -WX ^
|
||||||
-wd4100 -wd4101 -wd4127 -wd4146 ^
|
-wd4100 -wd4101 -wd4127 -wd4146 ^
|
||||||
|
-wd4505 ^
|
||||||
-wd4456 -wd4457
|
-wd4456 -wd4457
|
||||||
|
|
||||||
set compiler_includes= ^
|
set compiler_includes= ^
|
||||||
/Isrc\
|
/Isrc\
|
||||||
set libs= ^
|
set libs= ^
|
||||||
kernel32.lib ^
|
kernel32.lib ^
|
||||||
|
Synchronization.lib ^
|
||||||
bin\llvm\windows\LLVM-C.lib
|
bin\llvm\windows\LLVM-C.lib
|
||||||
|
|
||||||
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
set linker_flags= -incremental:no -opt:ref -subsystem:console
|
||||||
|
|||||||
+1
-1
@@ -50,7 +50,7 @@ config_darwin() {
|
|||||||
panic "Requirement: llvm-config must be base version smaller than 15"
|
panic "Requirement: llvm-config must be base version smaller than 15"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
LDFLAGS="$LDFLAGS -liconv -ldl"
|
LDFLAGS="$LDFLAGS -liconv -ldl -framework System"
|
||||||
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||||
LDFLAGS="$LDFLAGS -lLLVM-C"
|
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ when ODIN_OS == .Linux {
|
|||||||
cnd_destroy :: proc(cond: ^cnd_t) ---
|
cnd_destroy :: proc(cond: ^cnd_t) ---
|
||||||
cnd_init :: proc(cond: ^cnd_t) -> int ---
|
cnd_init :: proc(cond: ^cnd_t) -> int ---
|
||||||
cnd_signal :: 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 ---
|
cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
|
||||||
|
|
||||||
// 7.26.4 Mutex functions
|
// 7.26.4 Mutex functions
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
package container_small_array
|
package container_small_array
|
||||||
|
|
||||||
import "core:builtin"
|
import "core:builtin"
|
||||||
|
import "core:runtime"
|
||||||
|
_ :: runtime
|
||||||
|
|
||||||
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
|
||||||
data: [N]T,
|
data: [N]T,
|
||||||
@@ -32,6 +34,20 @@ get_ptr :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int) -> ^T {
|
|||||||
return &a.data[index]
|
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) {
|
set :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, item: T) {
|
||||||
a.data[index] = item
|
a.data[index] = item
|
||||||
}
|
}
|
||||||
@@ -102,6 +118,23 @@ consume :: proc "odin" (a: ^$A/Small_Array($N, $T), count: int, loc := #caller_l
|
|||||||
a.len -= count
|
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)) {
|
clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) {
|
||||||
resize(a, 0)
|
resize(a, 0)
|
||||||
}
|
}
|
||||||
@@ -111,6 +144,18 @@ push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) {
|
|||||||
a.len += n
|
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_elem :: push_back
|
||||||
append_elems :: push_back_elems
|
append_elems :: push_back_elems
|
||||||
push :: proc{push_back, 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^))
|
map_cap := uintptr(runtime.map_cap(m^))
|
||||||
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
|
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
|
||||||
|
|
||||||
|
i := 0
|
||||||
for bucket_index in 0..<map_cap {
|
for bucket_index in 0..<map_cap {
|
||||||
if !runtime.map_hash_is_valid(hs[bucket_index]) {
|
if !runtime.map_hash_is_valid(hs[bucket_index]) {
|
||||||
continue
|
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))
|
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))
|
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' }
|
is_digit :: #force_inline proc(r: byte) -> bool { return '0' <= r && r <= '9' }
|
||||||
|
|
||||||
new_offset = offset
|
new_offset = offset
|
||||||
for new_offset <= len(s) {
|
for new_offset < len(s) {
|
||||||
c := s[new_offset]
|
c := s[new_offset]
|
||||||
if !is_digit(c) {
|
if !is_digit(c) {
|
||||||
break
|
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 {
|
} else if fi.zero && fi.width_set {
|
||||||
prec = fi.width
|
prec = fi.width
|
||||||
if neg || fi.plus || fi.space {
|
if neg || fi.plus {
|
||||||
// There needs to be space for the "sign"
|
// There needs to be space for the "sign"
|
||||||
prec -= 1
|
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
|
flags: strconv.Int_Flags
|
||||||
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
||||||
if fi.plus { flags |= {.Plus} }
|
if fi.plus { flags |= {.Plus} }
|
||||||
if fi.space { flags |= {.Space} }
|
|
||||||
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||||
|
|
||||||
if fi.hash && fi.zero && fi.indent == 0 {
|
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 {
|
} else if fi.zero && fi.width_set {
|
||||||
prec = fi.width
|
prec = fi.width
|
||||||
if neg || fi.plus || fi.space {
|
if neg || fi.plus {
|
||||||
// There needs to be space for the "sign"
|
// There needs to be space for the "sign"
|
||||||
prec -= 1
|
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
|
flags: strconv.Int_Flags
|
||||||
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
if fi.hash && !fi.zero { flags |= {.Prefix} }
|
||||||
if fi.plus { flags |= {.Plus} }
|
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)
|
s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags)
|
||||||
|
|
||||||
if fi.hash && fi.zero && fi.indent == 0 {
|
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) {
|
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
|
||||||
switch verb {
|
switch verb {
|
||||||
case 'f', 'F', 'g', 'G', 'v':
|
case 'f', 'F', 'g', 'G', 'v':
|
||||||
prec: int = 3
|
_fmt_float_as(fi, v, bit_size, verb, 'f')
|
||||||
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:]))
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'e', 'E':
|
case 'e', 'E':
|
||||||
prec: int = 3
|
// BUG(): "%.3e" returns "3.000e+00"
|
||||||
if fi.prec_set {
|
_fmt_float_as(fi, v, bit_size, verb, 'e')
|
||||||
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:]))
|
|
||||||
}
|
|
||||||
|
|
||||||
case 'h', 'H':
|
case 'h', 'H':
|
||||||
prev_fi := fi^
|
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")
|
@(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)
|
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) {
|
any :: proc(x: $A/[$N]bool) -> (out: bool) {
|
||||||
for e in x {
|
for e in x {
|
||||||
if x {
|
if e {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -153,7 +153,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
|
|||||||
s := (^Scratch_Allocator)(allocator_data)
|
s := (^Scratch_Allocator)(allocator_data)
|
||||||
|
|
||||||
if s.data == nil {
|
if s.data == nil {
|
||||||
DEFAULT_BACKING_SIZE :: 1<<22
|
DEFAULT_BACKING_SIZE :: 4 * Megabyte
|
||||||
if !(context.allocator.procedure != scratch_allocator_proc &&
|
if !(context.allocator.procedure != scratch_allocator_proc &&
|
||||||
context.allocator.data != allocator_data) {
|
context.allocator.data != allocator_data) {
|
||||||
panic("cyclic initialization of the scratch allocator with itself")
|
panic("cyclic initialization of the scratch allocator with itself")
|
||||||
|
|||||||
+5
-5
@@ -3,11 +3,11 @@ package mem
|
|||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
|
|
||||||
Byte :: 1
|
Byte :: runtime.Byte
|
||||||
Kilobyte :: 1024 * Byte
|
Kilobyte :: runtime.Kilobyte
|
||||||
Megabyte :: 1024 * Kilobyte
|
Megabyte :: runtime.Megabyte
|
||||||
Gigabyte :: 1024 * Megabyte
|
Gigabyte :: runtime.Gigabyte
|
||||||
Terabyte :: 1024 * Gigabyte
|
Terabyte :: runtime.Terabyte
|
||||||
|
|
||||||
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
|
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
|
||||||
return runtime.memset(data, i32(value), len)
|
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
|
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),
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package mem_virtual
|
package mem_virtual
|
||||||
|
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
|
import "core:sync"
|
||||||
|
|
||||||
Arena_Kind :: enum uint {
|
Arena_Kind :: enum uint {
|
||||||
Growing = 0, // Chained memory blocks (singly linked list).
|
Growing = 0, // Chained memory blocks (singly linked list).
|
||||||
@@ -15,15 +16,16 @@ Arena :: struct {
|
|||||||
total_reserved: uint,
|
total_reserved: uint,
|
||||||
minimum_block_size: uint,
|
minimum_block_size: uint,
|
||||||
temp_count: uint,
|
temp_count: uint,
|
||||||
|
mutex: sync.Mutex,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// 1 MiB should be enough to start with
|
// 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
|
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
|
// 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
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
|
||||||
switch arena.kind {
|
switch arena.kind {
|
||||||
case .Growing:
|
case .Growing:
|
||||||
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
|
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 {
|
arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
|
||||||
if arena.curr_block != nil {
|
if arena.curr_block != nil {
|
||||||
assert(arena.kind != .Growing, "expected a non .Growing arena", loc)
|
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) {
|
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 {
|
if free_block := arena.curr_block; free_block != nil {
|
||||||
assert(arena.kind == .Growing, "expected a .Growing arena", loc)
|
assert(arena.kind == .Growing, "expected a .Growing arena", loc)
|
||||||
arena.curr_block = free_block.prev
|
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) {
|
arena_free_all :: proc(arena: ^Arena) {
|
||||||
switch arena.kind {
|
switch arena.kind {
|
||||||
case .Growing:
|
case .Growing:
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
for arena.curr_block != nil {
|
for arena.curr_block != nil {
|
||||||
arena_growing_free_last_memory_block(arena)
|
arena_growing_free_last_memory_block(arena)
|
||||||
}
|
}
|
||||||
@@ -287,6 +295,8 @@ Arena_Temp :: struct {
|
|||||||
@(require_results)
|
@(require_results)
|
||||||
arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
|
arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
|
||||||
assert(arena != nil, "nil arena", loc)
|
assert(arena != nil, "nil arena", loc)
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
|
||||||
temp.arena = arena
|
temp.arena = arena
|
||||||
temp.block = arena.curr_block
|
temp.block = arena.curr_block
|
||||||
if arena.curr_block != nil {
|
if arena.curr_block != nil {
|
||||||
@@ -299,7 +309,9 @@ arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena
|
|||||||
arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
||||||
assert(temp.arena != nil, "nil arena", loc)
|
assert(temp.arena != nil, "nil arena", loc)
|
||||||
arena := temp.arena
|
arena := temp.arena
|
||||||
|
sync.mutex_guard(&arena.mutex)
|
||||||
|
|
||||||
|
if temp.block != nil {
|
||||||
memory_block_found := false
|
memory_block_found := false
|
||||||
for block := arena.curr_block; block != nil; block = block.prev {
|
for block := arena.curr_block; block != nil; block = block.prev {
|
||||||
if block == temp.block {
|
if block == temp.block {
|
||||||
@@ -321,6 +333,17 @@ arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
|
|||||||
mem.zero_slice(block.base[temp.used:][:amount_to_zero])
|
mem.zero_slice(block.base[temp.used:][:amount_to_zero])
|
||||||
block.used = temp.used
|
block.used = temp.used
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
|
||||||
|
arena.temp_count -= 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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)
|
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
|
||||||
arena.temp_count -= 1
|
arena.temp_count -= 1
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ DEFAULT_PAGE_SIZE := uint(4096)
|
|||||||
|
|
||||||
Allocator_Error :: mem.Allocator_Error
|
Allocator_Error :: mem.Allocator_Error
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
return _reserve(size)
|
return _reserve(size)
|
||||||
}
|
}
|
||||||
@@ -15,6 +16,7 @@ commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
|
|||||||
return _commit(data, size)
|
return _commit(data, size)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
|
||||||
data = reserve(size) or_return
|
data = reserve(size) or_return
|
||||||
commit(raw_data(data), 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]
|
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) {
|
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 {
|
align_formula :: proc "contextless" (size, align: uint) -> uint {
|
||||||
result := size + align-1
|
result := size + align-1
|
||||||
@@ -100,6 +103,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
|
|||||||
return &pmblock.block, nil
|
return &pmblock.block, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) {
|
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 {
|
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
|
||||||
alignment_offset := uint(0)
|
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) {
|
safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
|
||||||
z, did_overflow := intrinsics.overflow_add(x, y)
|
z, did_overflow := intrinsics.overflow_add(x, y)
|
||||||
return z, !did_overflow
|
return z, !did_overflow
|
||||||
|
|||||||
@@ -14,11 +14,12 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
|
|||||||
|
|
||||||
dirpath: string
|
dirpath: string
|
||||||
dirpath, err = absolute_path_from_handle(fd)
|
dirpath, err = absolute_path_from_handle(fd)
|
||||||
|
|
||||||
if err != ERROR_NONE {
|
if err != ERROR_NONE {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defer delete(dirpath)
|
||||||
|
|
||||||
n := n
|
n := n
|
||||||
size := n
|
size := n
|
||||||
if n <= 0 {
|
if n <= 0 {
|
||||||
|
|||||||
+8
-4
@@ -93,7 +93,7 @@ file_size_from_path :: proc(path: string) -> i64 {
|
|||||||
return length
|
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
|
context.allocator = allocator
|
||||||
|
|
||||||
fd, err := open(name, O_RDONLY, 0)
|
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)
|
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
|
context.allocator = allocator
|
||||||
|
|
||||||
length: i64
|
length: i64
|
||||||
@@ -118,7 +118,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator)
|
|||||||
return nil, true
|
return nil, true
|
||||||
}
|
}
|
||||||
|
|
||||||
data = make([]byte, int(length), allocator)
|
data = make([]byte, int(length), allocator, loc)
|
||||||
if data == nil {
|
if data == nil {
|
||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
@@ -261,3 +261,7 @@ heap_allocator :: proc() -> mem.Allocator {
|
|||||||
data = nil,
|
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="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||||
|
|
||||||
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
@(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) -> ! ---
|
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||||
}
|
}
|
||||||
@@ -333,7 +334,7 @@ foreign dl {
|
|||||||
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
|
||||||
}
|
}
|
||||||
|
|
||||||
get_last_error :: proc() -> int {
|
get_last_error :: proc "contextless" () -> int {
|
||||||
return __error()^
|
return __error()^
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -342,19 +343,31 @@ get_last_error_string :: proc() -> string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) {
|
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)
|
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||||
handle := _unix_open(cstr, i32(flags), u16(mode))
|
handle := _unix_open(cstr, i32(flags), u16(mode))
|
||||||
if handle == -1 {
|
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)
|
err := fchmod(handle, cast(u16)mode)
|
||||||
if err != 0 {
|
if err != 0 {
|
||||||
_unix_close(handle)
|
_unix_close(handle)
|
||||||
return INVALID_HANDLE, 1
|
return INVALID_HANDLE, cast(Errno)err
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -688,6 +701,7 @@ get_current_directory :: proc() -> string {
|
|||||||
return string(cwd)
|
return string(cwd)
|
||||||
}
|
}
|
||||||
if Errno(get_last_error()) != ERANGE {
|
if Errno(get_last_error()) != ERANGE {
|
||||||
|
delete(buf)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
resize(&buf, len(buf)+page_size)
|
resize(&buf, len(buf)+page_size)
|
||||||
@@ -759,6 +773,18 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
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 {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
res := make([]string, len(runtime.args__))
|
res := make([]string, len(runtime.args__))
|
||||||
|
|||||||
+16
-1
@@ -287,6 +287,7 @@ foreign libc {
|
|||||||
|
|
||||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
@(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) -> ! ---
|
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||||
}
|
}
|
||||||
@@ -303,7 +304,7 @@ is_path_separator :: proc(r: rune) -> bool {
|
|||||||
return r == '/'
|
return r == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
get_last_error :: proc() -> int {
|
get_last_error :: proc "contextless" () -> int {
|
||||||
return __errno_location()^
|
return __errno_location()^
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -650,6 +651,7 @@ get_current_directory :: proc() -> string {
|
|||||||
return string(cwd)
|
return string(cwd)
|
||||||
}
|
}
|
||||||
if Errno(get_last_error()) != ERANGE {
|
if Errno(get_last_error()) != ERANGE {
|
||||||
|
delete(buf)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
resize(&buf, len(buf)+page_size)
|
resize(&buf, len(buf)+page_size)
|
||||||
@@ -702,6 +704,19 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
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 {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
res := make([]string, len(runtime.args__))
|
res := make([]string, len(runtime.args__))
|
||||||
|
|||||||
@@ -404,6 +404,7 @@ foreign libc {
|
|||||||
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---
|
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---
|
||||||
|
|
||||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.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="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||||
@@ -441,7 +442,7 @@ _get_errno :: proc(res: int) -> Errno {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// get errno from libc
|
// get errno from libc
|
||||||
get_last_error :: proc() -> int {
|
get_last_error :: proc "contextless" () -> int {
|
||||||
return __errno_location()^
|
return __errno_location()^
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -822,6 +823,7 @@ get_current_directory :: proc() -> string {
|
|||||||
return strings.string_from_nul_terminated_ptr(&buf[0], len(buf))
|
return strings.string_from_nul_terminated_ptr(&buf[0], len(buf))
|
||||||
}
|
}
|
||||||
if _get_errno(res) != ERANGE {
|
if _get_errno(res) != ERANGE {
|
||||||
|
delete(buf)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
resize(&buf, len(buf)+page_size)
|
resize(&buf, len(buf)+page_size)
|
||||||
@@ -878,6 +880,10 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
return page_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(private)
|
||||||
|
_processor_core_count :: proc() -> int {
|
||||||
|
return int(_unix_get_nprocs())
|
||||||
|
}
|
||||||
|
|
||||||
_alloc_command_line_arguments :: proc() -> []string {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
res := make([]string, len(runtime.args__))
|
res := make([]string, len(runtime.args__))
|
||||||
|
|||||||
@@ -269,6 +269,7 @@ foreign libc {
|
|||||||
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
||||||
|
|
||||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> 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="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||||
@@ -294,7 +295,7 @@ is_path_separator :: proc(r: rune) -> bool {
|
|||||||
return r == '/'
|
return r == '/'
|
||||||
}
|
}
|
||||||
|
|
||||||
get_last_error :: proc() -> int {
|
get_last_error :: proc "contextless" () -> int {
|
||||||
return __errno()^
|
return __errno()^
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -648,6 +649,7 @@ get_current_directory :: proc() -> string {
|
|||||||
return string(cwd)
|
return string(cwd)
|
||||||
}
|
}
|
||||||
if Errno(get_last_error()) != ERANGE {
|
if Errno(get_last_error()) != ERANGE {
|
||||||
|
delete(buf)
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
resize(&buf, len(buf) + MAX_PATH)
|
resize(&buf, len(buf) + MAX_PATH)
|
||||||
@@ -704,6 +706,12 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
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 {
|
_alloc_command_line_arguments :: proc() -> []string {
|
||||||
res := make([]string, len(runtime.args__))
|
res := make([]string, len(runtime.args__))
|
||||||
|
|||||||
@@ -89,7 +89,10 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
|
|||||||
current_thread_id :: proc "contextless" () -> int {
|
current_thread_id :: proc "contextless" () -> int {
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
@(private)
|
||||||
|
_processor_core_count :: proc() -> int {
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||||
stat, err := wasi.fd_filestat_get(wasi.fd_t(fd))
|
stat, err := wasi.fd_filestat_get(wasi.fd_t(fd))
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package os
|
|||||||
|
|
||||||
import win32 "core:sys/windows"
|
import win32 "core:sys/windows"
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
import "core:intrinsics"
|
||||||
|
|
||||||
Handle :: distinct uintptr
|
Handle :: distinct uintptr
|
||||||
File_Time :: distinct u64
|
File_Time :: distinct u64
|
||||||
@@ -126,7 +127,28 @@ get_page_size :: proc() -> int {
|
|||||||
return page_size
|
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) -> ! {
|
exit :: proc "contextless" (code: int) -> ! {
|
||||||
runtime._cleanup_runtime_contextless()
|
runtime._cleanup_runtime_contextless()
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package reflect
|
|||||||
|
|
||||||
import "core:runtime"
|
import "core:runtime"
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
|
iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
|
||||||
if val == nil || it == nil {
|
if val == nil || it == nil {
|
||||||
return
|
return
|
||||||
@@ -41,6 +42,7 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
iterate_map :: proc(val: any, it: ^int) -> (key, value: any, ok: bool) {
|
iterate_map :: proc(val: any, it: ^int) -> (key, value: any, ok: bool) {
|
||||||
if val == nil || it == nil {
|
if val == nil || it == nil {
|
||||||
return
|
return
|
||||||
|
|||||||
+61
-39
@@ -74,6 +74,7 @@ Type_Kind :: enum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
type_kind :: proc(T: typeid) -> Type_Kind {
|
type_kind :: proc(T: typeid) -> Type_Kind {
|
||||||
ti := type_info_of(T)
|
ti := type_info_of(T)
|
||||||
if ti != nil {
|
if ti != nil {
|
||||||
@@ -113,57 +114,31 @@ type_kind :: proc(T: typeid) -> Type_Kind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bill): Better name
|
// TODO(bill): Better name
|
||||||
|
@(require_results)
|
||||||
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
|
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||||
return type_kind(runtime.typeid_base(T))
|
return type_kind(runtime.typeid_base(T))
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(bill): Better name
|
// TODO(bill): Better name
|
||||||
|
@(require_results)
|
||||||
backing_type_kind :: proc(T: typeid) -> Type_Kind {
|
backing_type_kind :: proc(T: typeid) -> Type_Kind {
|
||||||
return type_kind(runtime.typeid_core(T))
|
return type_kind(runtime.typeid_core(T))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
|
type_info_base :: runtime.type_info_base
|
||||||
if info == nil { return nil }
|
type_info_core :: runtime.type_info_core
|
||||||
|
|
||||||
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_without_enum :: type_info_core
|
type_info_base_without_enum :: type_info_core
|
||||||
|
|
||||||
|
|
||||||
typeid_base :: proc(id: typeid) -> typeid {
|
when !ODIN_DISALLOW_RTTI {
|
||||||
ti := type_info_of(id)
|
typeid_base :: runtime.typeid_base
|
||||||
ti = type_info_base(ti)
|
typeid_core :: runtime.typeid_core
|
||||||
return ti.id
|
|
||||||
}
|
|
||||||
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
|
typeid_base_without_enum :: typeid_core
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
any_base :: proc(v: any) -> any {
|
any_base :: proc(v: any) -> any {
|
||||||
v := v
|
v := v
|
||||||
if v != nil {
|
if v != nil {
|
||||||
@@ -171,6 +146,7 @@ any_base :: proc(v: any) -> any {
|
|||||||
}
|
}
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
any_core :: proc(v: any) -> any {
|
any_core :: proc(v: any) -> any {
|
||||||
v := v
|
v := v
|
||||||
if v != nil {
|
if v != nil {
|
||||||
@@ -179,6 +155,7 @@ any_core :: proc(v: any) -> any {
|
|||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
typeid_elem :: proc(id: typeid) -> typeid {
|
typeid_elem :: proc(id: typeid) -> typeid {
|
||||||
ti := type_info_of(id)
|
ti := type_info_of(id)
|
||||||
if ti == nil { return nil }
|
if ti == nil { return nil }
|
||||||
@@ -208,6 +185,7 @@ typeid_elem :: proc(id: typeid) -> typeid {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
size_of_typeid :: proc(T: typeid) -> int {
|
size_of_typeid :: proc(T: typeid) -> int {
|
||||||
if ti := type_info_of(T); ti != nil {
|
if ti := type_info_of(T); ti != nil {
|
||||||
return ti.size
|
return ti.size
|
||||||
@@ -215,6 +193,7 @@ size_of_typeid :: proc(T: typeid) -> int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
align_of_typeid :: proc(T: typeid) -> int {
|
align_of_typeid :: proc(T: typeid) -> int {
|
||||||
if ti := type_info_of(T); ti != nil {
|
if ti := type_info_of(T); ti != nil {
|
||||||
return ti.align
|
return ti.align
|
||||||
@@ -222,6 +201,7 @@ align_of_typeid :: proc(T: typeid) -> int {
|
|||||||
return 1
|
return 1
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_bytes :: proc(v: any) -> []byte {
|
as_bytes :: proc(v: any) -> []byte {
|
||||||
if v != nil {
|
if v != nil {
|
||||||
sz := size_of_typeid(v.id)
|
sz := size_of_typeid(v.id)
|
||||||
@@ -230,10 +210,12 @@ as_bytes :: proc(v: any) -> []byte {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
any_data :: #force_inline proc(v: any) -> (data: rawptr, id: typeid) {
|
any_data :: #force_inline proc(v: any) -> (data: rawptr, id: typeid) {
|
||||||
return v.data, v.id
|
return v.data, v.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
is_nil :: proc(v: any) -> bool {
|
is_nil :: proc(v: any) -> bool {
|
||||||
if v == nil {
|
if v == nil {
|
||||||
return true
|
return true
|
||||||
@@ -250,6 +232,7 @@ is_nil :: proc(v: any) -> bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
length :: proc(val: any) -> int {
|
length :: proc(val: any) -> int {
|
||||||
if val == nil { return 0 }
|
if val == nil { return 0 }
|
||||||
|
|
||||||
@@ -285,6 +268,7 @@ length :: proc(val: any) -> int {
|
|||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
capacity :: proc(val: any) -> int {
|
capacity :: proc(val: any) -> int {
|
||||||
if val == nil { return 0 }
|
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 {
|
index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
||||||
if val == nil { return nil }
|
if val == nil { return nil }
|
||||||
|
|
||||||
@@ -370,6 +355,7 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
deref :: proc(val: any) -> any {
|
deref :: proc(val: any) -> any {
|
||||||
if val != nil {
|
if val != nil {
|
||||||
ti := type_info_base(type_info_of(val.id))
|
ti := type_info_base(type_info_of(val.id))
|
||||||
@@ -399,6 +385,7 @@ Struct_Field :: struct {
|
|||||||
is_using: bool,
|
is_using: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
|
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) -> any {
|
struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) -> any {
|
||||||
if a == nil { return nil }
|
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 {
|
struct_field_names :: proc(T: typeid) -> []string {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -469,6 +459,7 @@ struct_field_names :: proc(T: typeid) -> []string {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_types :: proc(T: typeid) -> []^Type_Info {
|
struct_field_types :: proc(T: typeid) -> []^Type_Info {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
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 {
|
struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -486,6 +478,7 @@ struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
||||||
@@ -494,6 +487,7 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
|
struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
|
||||||
ti := runtime.type_info_base(type_info_of(T))
|
ti := runtime.type_info_base(type_info_of(T))
|
||||||
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
|
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) {
|
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) {
|
||||||
value, _ = struct_tag_lookup(tag, key)
|
value, _ = struct_tag_lookup(tag, key)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, ok: bool) {
|
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, ok: bool) {
|
||||||
for t := tag; t != ""; /**/ {
|
for t := tag; t != ""; /**/ {
|
||||||
i := 0
|
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 {
|
enum_string :: proc(a: any) -> string {
|
||||||
if a == nil { return "" }
|
if a == nil { return "" }
|
||||||
ti := runtime.type_info_base(type_info_of(a.id))
|
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.
|
// 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) {
|
enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, ok: bool) {
|
||||||
ti := type_info_base(type_info_of(Enum_Type))
|
ti := type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
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
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info_Enum_Value, ok: bool) {
|
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))
|
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
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 {
|
enum_field_names :: proc(Enum_Type: typeid) -> []string {
|
||||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
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
|
return nil
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
enum_field_values :: proc(Enum_Type: typeid) -> []Type_Info_Enum_Value {
|
enum_field_values :: proc(Enum_Type: typeid) -> []Type_Info_Enum_Value {
|
||||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
||||||
@@ -643,6 +644,7 @@ Enum_Field :: struct {
|
|||||||
value: Type_Info_Enum_Value,
|
value: Type_Info_Enum_Value,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
|
enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
|
||||||
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
ti := runtime.type_info_base(type_info_of(Enum_Type))
|
||||||
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
|
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 {
|
union_variant_type_info :: proc(a: any) -> ^Type_Info {
|
||||||
id := union_variant_typeid(a)
|
id := union_variant_typeid(a)
|
||||||
return type_info_of(id)
|
return type_info_of(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
type_info_union_is_pure_maybe :: proc(info: runtime.Type_Info_Union) -> bool {
|
type_info_union_is_pure_maybe :: proc(info: runtime.Type_Info_Union) -> bool {
|
||||||
return len(info.variants) == 1 && is_pointer(info.variants[0])
|
return len(info.variants) == 1 && is_pointer(info.variants[0])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
union_variant_typeid :: proc(a: any) -> typeid {
|
union_variant_typeid :: proc(a: any) -> typeid {
|
||||||
if a == nil { return nil }
|
if a == nil { return nil }
|
||||||
|
|
||||||
@@ -690,9 +695,10 @@ union_variant_typeid :: proc(a: any) -> typeid {
|
|||||||
case: unimplemented()
|
case: unimplemented()
|
||||||
}
|
}
|
||||||
|
|
||||||
if a.data != nil && tag != 0 {
|
if info.no_nil {
|
||||||
i := tag if info.no_nil else tag-1
|
return info.variants[tag].id
|
||||||
return info.variants[i].id
|
} else if tag != 0 {
|
||||||
|
return info.variants[tag-1].id
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
@@ -700,6 +706,7 @@ union_variant_typeid :: proc(a: any) -> typeid {
|
|||||||
panic("expected a union to reflect.union_variant_typeid")
|
panic("expected a union to reflect.union_variant_typeid")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
get_union_variant_raw_tag :: proc(a: any) -> i64 {
|
||||||
if a == nil { return -1 }
|
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")
|
panic("expected a union to reflect.get_union_variant_raw_tag")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
get_union_variant :: proc(a: any) -> any {
|
get_union_variant :: proc(a: any) -> any {
|
||||||
if a == nil {
|
if a == nil {
|
||||||
return nil
|
return nil
|
||||||
@@ -741,6 +749,7 @@ get_union_variant :: proc(a: any) -> any {
|
|||||||
return any{a.data, id}
|
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) {
|
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)
|
ptr := rawptr(val)
|
||||||
tag := get_union_variant_raw_tag(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) {
|
as_bool :: proc(a: any) -> (value: bool, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -903,6 +913,7 @@ as_bool :: proc(a: any) -> (value: bool, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_int :: proc(a: any) -> (value: int, valid: bool) {
|
as_int :: proc(a: any) -> (value: int, valid: bool) {
|
||||||
v: i64
|
v: i64
|
||||||
v, valid = as_i64(a)
|
v, valid = as_i64(a)
|
||||||
@@ -910,6 +921,7 @@ as_int :: proc(a: any) -> (value: int, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_uint :: proc(a: any) -> (value: uint, valid: bool) {
|
as_uint :: proc(a: any) -> (value: uint, valid: bool) {
|
||||||
v: u64
|
v: u64
|
||||||
v, valid = as_u64(a)
|
v, valid = as_u64(a)
|
||||||
@@ -917,6 +929,7 @@ as_uint :: proc(a: any) -> (value: uint, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
|
as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -1024,6 +1037,7 @@ as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
|
as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
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) {
|
as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
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) {
|
as_string :: proc(a: any) -> (value: string, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -1258,6 +1274,7 @@ as_string :: proc(a: any) -> (value: string, valid: bool) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
relative_pointer_to_absolute :: proc(a: any) -> rawptr {
|
||||||
if a == nil { return nil }
|
if a == nil { return nil }
|
||||||
a := a
|
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 {
|
relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
|
||||||
_handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
|
_handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
|
||||||
if ptr^ == 0 {
|
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) {
|
as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
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) {
|
as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
|
||||||
if a == nil { return }
|
if a == nil { return }
|
||||||
a := a
|
a := a
|
||||||
@@ -1377,9 +1397,11 @@ ne :: not_equal
|
|||||||
|
|
||||||
DEFAULT_EQUAL_MAX_RECURSION_LEVEL :: 32
|
DEFAULT_EQUAL_MAX_RECURSION_LEVEL :: 32
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
not_equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
|
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)
|
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 {
|
equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
|
||||||
if a == nil && b == nil {
|
if a == nil && b == nil {
|
||||||
return true
|
return true
|
||||||
|
|||||||
+33
-3
@@ -3,17 +3,16 @@ package reflect
|
|||||||
import "core:io"
|
import "core:io"
|
||||||
import "core:strings"
|
import "core:strings"
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
||||||
if a == b {
|
if a == b {
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
if (a == nil && b != nil) ||
|
if a == nil || b == nil {
|
||||||
(a != nil && b == nil) {
|
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
switch {
|
switch {
|
||||||
case a.size != b.size, a.align != b.align:
|
case a.size != b.size, a.align != b.align:
|
||||||
return false
|
return false
|
||||||
@@ -180,6 +179,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
is_signed :: proc(info: ^Type_Info) -> bool {
|
is_signed :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
#partial switch i in type_info_base(info).variant {
|
#partial switch i in type_info_base(info).variant {
|
||||||
@@ -188,6 +188,7 @@ is_signed :: proc(info: ^Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_unsigned :: proc(info: ^Type_Info) -> bool {
|
is_unsigned :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
#partial switch i in type_info_base(info).variant {
|
#partial switch i in type_info_base(info).variant {
|
||||||
@@ -197,6 +198,7 @@ is_unsigned :: proc(info: ^Type_Info) -> bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@(require_results)
|
||||||
is_byte :: proc(info: ^Type_Info) -> bool {
|
is_byte :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
#partial switch i in type_info_base(info).variant {
|
#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 {
|
is_integer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Integer)
|
_, ok := type_info_base(info).variant.(Type_Info_Integer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_rune :: proc(info: ^Type_Info) -> bool {
|
is_rune :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Rune)
|
_, ok := type_info_base(info).variant.(Type_Info_Rune)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_float :: proc(info: ^Type_Info) -> bool {
|
is_float :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Float)
|
_, ok := type_info_base(info).variant.(Type_Info_Float)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_complex :: proc(info: ^Type_Info) -> bool {
|
is_complex :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Complex)
|
_, ok := type_info_base(info).variant.(Type_Info_Complex)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_quaternion :: proc(info: ^Type_Info) -> bool {
|
is_quaternion :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Quaternion)
|
_, ok := type_info_base(info).variant.(Type_Info_Quaternion)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_any :: proc(info: ^Type_Info) -> bool {
|
is_any :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Any)
|
_, ok := type_info_base(info).variant.(Type_Info_Any)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_string :: proc(info: ^Type_Info) -> bool {
|
is_string :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_String)
|
_, ok := type_info_base(info).variant.(Type_Info_String)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_cstring :: proc(info: ^Type_Info) -> bool {
|
is_cstring :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
v, ok := type_info_base(info).variant.(Type_Info_String)
|
v, ok := type_info_base(info).variant.(Type_Info_String)
|
||||||
return ok && v.is_cstring
|
return ok && v.is_cstring
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_boolean :: proc(info: ^Type_Info) -> bool {
|
is_boolean :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Boolean)
|
_, ok := type_info_base(info).variant.(Type_Info_Boolean)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_pointer :: proc(info: ^Type_Info) -> bool {
|
is_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Pointer)
|
_, ok := type_info_base(info).variant.(Type_Info_Pointer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_multi_pointer :: proc(info: ^Type_Info) -> bool {
|
is_multi_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer)
|
_, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_soa_pointer :: proc(info: ^Type_Info) -> bool {
|
is_soa_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer)
|
_, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_pointer_internally :: proc(info: ^Type_Info) -> bool {
|
is_pointer_internally :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
#partial switch v in info.variant {
|
#partial switch v in info.variant {
|
||||||
@@ -277,76 +292,91 @@ is_pointer_internally :: proc(info: ^Type_Info) -> bool {
|
|||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_procedure :: proc(info: ^Type_Info) -> bool {
|
is_procedure :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Procedure)
|
_, ok := type_info_base(info).variant.(Type_Info_Procedure)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_array :: proc(info: ^Type_Info) -> bool {
|
is_array :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Array)
|
_, ok := type_info_base(info).variant.(Type_Info_Array)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_enumerated_array :: proc(info: ^Type_Info) -> bool {
|
is_enumerated_array :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Enumerated_Array)
|
_, ok := type_info_base(info).variant.(Type_Info_Enumerated_Array)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array)
|
_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Map)
|
_, ok := type_info_base(info).variant.(Type_Info_Map)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_bit_set :: proc(info: ^Type_Info) -> bool {
|
is_bit_set :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Bit_Set)
|
_, ok := type_info_base(info).variant.(Type_Info_Bit_Set)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_slice :: proc(info: ^Type_Info) -> bool {
|
is_slice :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Slice)
|
_, ok := type_info_base(info).variant.(Type_Info_Slice)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_tuple :: proc(info: ^Type_Info) -> bool {
|
is_tuple :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Tuple)
|
_, ok := type_info_base(info).variant.(Type_Info_Tuple)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_struct :: proc(info: ^Type_Info) -> bool {
|
is_struct :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
||||||
return ok && !s.is_raw_union
|
return ok && !s.is_raw_union
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
is_raw_union :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
s, ok := type_info_base(info).variant.(Type_Info_Struct)
|
||||||
return ok && s.is_raw_union
|
return ok && s.is_raw_union
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_union :: proc(info: ^Type_Info) -> bool {
|
is_union :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Union)
|
_, ok := type_info_base(info).variant.(Type_Info_Union)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_enum :: proc(info: ^Type_Info) -> bool {
|
is_enum :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Enum)
|
_, ok := type_info_base(info).variant.(Type_Info_Enum)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_simd_vector :: proc(info: ^Type_Info) -> bool {
|
is_simd_vector :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
|
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_relative_pointer :: proc(info: ^Type_Info) -> bool {
|
is_relative_pointer :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Pointer)
|
_, ok := type_info_base(info).variant.(Type_Info_Relative_Pointer)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
|
@(require_results)
|
||||||
is_relative_slice :: proc(info: ^Type_Info) -> bool {
|
is_relative_slice :: proc(info: ^Type_Info) -> bool {
|
||||||
if info == nil { return false }
|
if info == nil { return false }
|
||||||
_, ok := type_info_base(info).variant.(Type_Info_Relative_Slice)
|
_, ok := type_info_base(info).variant.(Type_Info_Relative_Slice)
|
||||||
|
|||||||
@@ -329,6 +329,12 @@ Allocator :: struct {
|
|||||||
data: rawptr,
|
data: rawptr,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Byte :: 1
|
||||||
|
Kilobyte :: 1024 * Byte
|
||||||
|
Megabyte :: 1024 * Kilobyte
|
||||||
|
Gigabyte :: 1024 * Megabyte
|
||||||
|
Terabyte :: 1024 * Gigabyte
|
||||||
|
|
||||||
// Logging stuff
|
// Logging stuff
|
||||||
|
|
||||||
Logger_Level :: enum uint {
|
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)
|
old_size := a.cap * size_of(E)
|
||||||
new_size := new_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 {
|
if err != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,14 +150,14 @@ make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.
|
|||||||
}
|
}
|
||||||
|
|
||||||
@builtin
|
@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
|
context.allocator = allocator
|
||||||
resize_soa(&array, length, loc)
|
resize_soa(&array, length, loc)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@builtin
|
@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
|
context.allocator = allocator
|
||||||
if reserve_soa(&array, capacity, loc) {
|
if reserve_soa(&array, capacity, loc) {
|
||||||
resize_soa(&array, length, loc)
|
resize_soa(&array, length, loc)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
package runtime
|
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 {
|
when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
|
||||||
|
|||||||
@@ -2,6 +2,73 @@ package runtime
|
|||||||
|
|
||||||
_INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz"
|
_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) {
|
encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
|
||||||
r := c
|
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
|
entries = make(type_of(entries), len(m), allocator) or_return
|
||||||
i := 0
|
i := 0
|
||||||
for key, value in m {
|
for key, value in m {
|
||||||
|
|||||||
+4
-2
@@ -73,9 +73,10 @@ ptr_rotate :: proc(left: int, mid: ^$T, right: int) {
|
|||||||
left, mid, right := left, mid, right
|
left, mid, right := left, mid, right
|
||||||
|
|
||||||
// TODO(bill): Optimization with a buffer for smaller ranges
|
// TODO(bill): Optimization with a buffer for smaller ranges
|
||||||
|
for left > 0 && right > 0 {
|
||||||
if left >= right {
|
if left >= right {
|
||||||
for {
|
for {
|
||||||
ptr_swap_non_overlapping(ptr_sub(mid, right), mid, right)
|
ptr_swap_non_overlapping(ptr_sub(mid, right), mid, right * size_of(T))
|
||||||
mid = ptr_sub(mid, right)
|
mid = ptr_sub(mid, right)
|
||||||
|
|
||||||
left -= right
|
left -= right
|
||||||
@@ -85,7 +86,7 @@ ptr_rotate :: proc(left: int, mid: ^$T, right: int) {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for {
|
for {
|
||||||
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
|
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left * size_of(T))
|
||||||
mid = ptr_add(mid, left)
|
mid = ptr_add(mid, left)
|
||||||
|
|
||||||
right -= left
|
right -= left
|
||||||
@@ -96,3 +97,4 @@ ptr_rotate :: proc(left: int, mid: ^$T, right: int) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -77,8 +77,7 @@ swap_between :: proc(a, b: $T/[]$E) {
|
|||||||
reverse :: proc(array: $T/[]$E) {
|
reverse :: proc(array: $T/[]$E) {
|
||||||
n := len(array)/2
|
n := len(array)/2
|
||||||
for i in 0..<n {
|
for i in 0..<n {
|
||||||
a, b := i, len(array)-i-1
|
swap(array, i, len(array)-i-1)
|
||||||
array[a], array[b] = array[b], array[a]
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -218,8 +217,10 @@ rotate_left :: proc(array: $T/[]$E, mid: int) {
|
|||||||
n := len(array)
|
n := len(array)
|
||||||
m := mid %% n
|
m := mid %% n
|
||||||
k := n - m
|
k := n - m
|
||||||
p := raw_data(array)
|
// FIXME: (ap29600) this cast is a temporary fix for the compiler not matching
|
||||||
ptr_rotate(mid, ptr_add(p, mid), k)
|
// [^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_right :: proc(array: $T/[]$E, k: int) {
|
||||||
rotate_left(array, -k)
|
rotate_left(array, -k)
|
||||||
|
|||||||
@@ -214,25 +214,128 @@ shift_right :: proc(a: ^Decimal, k: uint) {
|
|||||||
trim(a)
|
trim(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
shift_left :: proc(a: ^Decimal, k: uint) {
|
import "core:runtime"
|
||||||
// NOTE(bill): used to determine buffer size required for the decimal from the binary shift
|
println :: proc(args: ..any) {
|
||||||
// 'k' means `1<<k` == `2^k` which equates to roundup(k*log10(2)) digits required
|
for arg, i in args {
|
||||||
log10_2 :: 0.301029995663981195213738894724493026768189881462108541310
|
if i != 0 {
|
||||||
capacity := int(f64(k)*log10_2 + 1)
|
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
|
@(private="file")
|
||||||
w := a.count+capacity // write index
|
_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
|
n: uint
|
||||||
for r -= 1; r >= 0; r -= 1 {
|
for read_index -= 1; read_index >= 0; read_index -= 1 {
|
||||||
n += (uint(a.digits[r]) - '0') << k
|
n += (uint(a.digits[read_index]) - '0') << k
|
||||||
quo := n/10
|
quo := n/10
|
||||||
rem := n - 10*quo
|
rem := n - 10*quo
|
||||||
w -= 1
|
write_index -= 1
|
||||||
if w < d {
|
if write_index < len(a.digits) {
|
||||||
a.digits[w] = byte('0' + rem)
|
a.digits[write_index] = byte('0' + rem)
|
||||||
} else if rem != 0 {
|
} else if rem != 0 {
|
||||||
a.trunc = true
|
a.trunc = true
|
||||||
}
|
}
|
||||||
@@ -242,21 +345,18 @@ shift_left :: proc(a: ^Decimal, k: uint) {
|
|||||||
for n > 0 {
|
for n > 0 {
|
||||||
quo := n/10
|
quo := n/10
|
||||||
rem := n - 10*quo
|
rem := n - 10*quo
|
||||||
w -= 1
|
write_index -= 1
|
||||||
if w < d {
|
if write_index < len(a.digits) {
|
||||||
a.digits[w] = byte('0' + rem)
|
a.digits[write_index] = byte('0' + rem)
|
||||||
} else if rem != 0 {
|
} else if rem != 0 {
|
||||||
a.trunc = true
|
a.trunc = true
|
||||||
}
|
}
|
||||||
n = quo
|
n = quo
|
||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): Remove unused buffer size
|
a.decimal_point += delta
|
||||||
assert(w >= 0)
|
|
||||||
capacity -= w
|
|
||||||
|
|
||||||
a.count = min(a.count+capacity, d)
|
a.count = clamp(a.count, 0, len(a.digits))
|
||||||
a.decimal_point += capacity
|
|
||||||
trim(a)
|
trim(a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -287,13 +287,13 @@ round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Inf
|
|||||||
|
|
||||||
@(private)
|
@(private)
|
||||||
decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64, overflow: bool) {
|
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) {
|
end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (bits: u64) {
|
||||||
bits := mant & (u64(1)<<info.mantbits - 1)
|
bits = mant & (u64(1)<<info.mantbits - 1)
|
||||||
bits |= u64((exp-info.bias) & (1<<info.expbits - 1)) << info.mantbits
|
bits |= u64((exp-info.bias) & (1<<info.expbits - 1)) << info.mantbits
|
||||||
if d.neg {
|
if d.neg {
|
||||||
bits |= 1<< info.mantbits << info.expbits
|
bits |= 1<< info.mantbits << info.expbits
|
||||||
}
|
}
|
||||||
return bits
|
return
|
||||||
}
|
}
|
||||||
set_overflow :: proc "contextless" (mant: ^u64, exp: ^int, info: ^Float_Info) -> bool {
|
set_overflow :: proc "contextless" (mant: ^u64, exp: ^int, info: ^Float_Info) -> bool {
|
||||||
mant^ = 0
|
mant^ = 0
|
||||||
@@ -303,7 +303,7 @@ decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64
|
|||||||
|
|
||||||
mant: u64
|
mant: u64
|
||||||
exp: int
|
exp: int
|
||||||
if d.decimal_point == 0 {
|
if d.count == 0 {
|
||||||
mant = 0
|
mant = 0
|
||||||
exp = info.bias
|
exp = info.bias
|
||||||
b = end(d, mant, exp, info)
|
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
|
exp = 0
|
||||||
for d.decimal_point > 0 {
|
for d.decimal_point > 0 {
|
||||||
n := 27 if d.decimal_point >= len(power_table) else power_table[d.decimal_point]
|
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
|
exp += n
|
||||||
}
|
}
|
||||||
for d.decimal_point < 0 || d.decimal_point == 0 && d.digits[0] < '5' {
|
for d.decimal_point < 0 || d.decimal_point == 0 && d.digits[0] < '5' {
|
||||||
|
|||||||
@@ -3,7 +3,6 @@ package strconv
|
|||||||
Int_Flag :: enum {
|
Int_Flag :: enum {
|
||||||
Prefix,
|
Prefix,
|
||||||
Plus,
|
Plus,
|
||||||
Space,
|
|
||||||
}
|
}
|
||||||
Int_Flags :: bit_set[Int_Flag]
|
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] = '-'
|
i-=1; a[i] = '-'
|
||||||
case .Plus in flags:
|
case .Plus in flags:
|
||||||
i-=1; a[i] = '+'
|
i-=1; a[i] = '+'
|
||||||
case .Space in flags:
|
|
||||||
i-=1; a[i] = ' '
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out := 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] = '-'
|
i-=1; a[i] = '-'
|
||||||
case .Plus in flags:
|
case .Plus in flags:
|
||||||
i-=1; a[i] = '+'
|
i-=1; a[i] = '+'
|
||||||
case .Space in flags:
|
|
||||||
i-=1; a[i] = ' '
|
|
||||||
}
|
}
|
||||||
|
|
||||||
out := 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 {
|
if mantissa>>_f64_info.mantbits != 0 {
|
||||||
return
|
break trunc_block
|
||||||
}
|
}
|
||||||
f := f64(mantissa)
|
f := f64(mantissa)
|
||||||
if neg {
|
if neg {
|
||||||
@@ -841,7 +841,6 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
|
|||||||
return f / pow10[-exp], true
|
return f / pow10[-exp], true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
d: decimal.Decimal
|
d: decimal.Decimal
|
||||||
decimal.set(&d, str[:nr])
|
decimal.set(&d, str[:nr])
|
||||||
b, overflow := decimal_to_float_bits(&d, &_f64_info)
|
b, overflow := decimal_to_float_bits(&d, &_f64_info)
|
||||||
|
|||||||
+94
-29
@@ -1,6 +1,8 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import vg "core:sys/valgrind"
|
||||||
|
_ :: vg
|
||||||
|
|
||||||
// A Wait_Group waits for a collection of threads to finish
|
// A Wait_Group waits for a collection of threads to finish
|
||||||
//
|
//
|
||||||
@@ -11,7 +13,7 @@ Wait_Group :: struct {
|
|||||||
cond: Cond,
|
cond: Cond,
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
|
wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) {
|
||||||
if delta == 0 {
|
if delta == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@@ -20,32 +22,32 @@ wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
|
|||||||
|
|
||||||
atomic_add(&wg.counter, delta)
|
atomic_add(&wg.counter, delta)
|
||||||
if wg.counter < 0 {
|
if wg.counter < 0 {
|
||||||
panic("sync.Wait_Group negative counter")
|
_panic("sync.Wait_Group negative counter")
|
||||||
}
|
}
|
||||||
if wg.counter == 0 {
|
if wg.counter == 0 {
|
||||||
cond_broadcast(&wg.cond)
|
cond_broadcast(&wg.cond)
|
||||||
if wg.counter != 0 {
|
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_add(wg, -1)
|
||||||
}
|
}
|
||||||
|
|
||||||
wait_group_wait :: proc(wg: ^Wait_Group) {
|
wait_group_wait :: proc "contextless" (wg: ^Wait_Group) {
|
||||||
guard(&wg.mutex)
|
guard(&wg.mutex)
|
||||||
|
|
||||||
if wg.counter != 0 {
|
if wg.counter != 0 {
|
||||||
cond_wait(&wg.cond, &wg.mutex)
|
cond_wait(&wg.cond, &wg.mutex)
|
||||||
if wg.counter != 0 {
|
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 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -56,7 +58,7 @@ wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
if wg.counter != 0 {
|
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
|
return true
|
||||||
@@ -76,7 +78,7 @@ Example:
|
|||||||
|
|
||||||
barrier := &sync.Barrier{}
|
barrier := &sync.Barrier{}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc "contextless" () {
|
||||||
fmt.println("Start")
|
fmt.println("Start")
|
||||||
|
|
||||||
THREAD_COUNT :: 4
|
THREAD_COUNT :: 4
|
||||||
@@ -107,7 +109,10 @@ Barrier :: struct {
|
|||||||
thread_count: int,
|
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.index = 0
|
||||||
b.generation_id = 0
|
b.generation_id = 0
|
||||||
b.thread_count = thread_count
|
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
|
// Block the current thread until all threads have rendezvoused
|
||||||
// Barrier can be reused after all threads rendezvoused once, and can be used continuously
|
// 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)
|
guard(&b.mutex)
|
||||||
local_gen := b.generation_id
|
local_gen := b.generation_id
|
||||||
b.index += 1
|
b.index += 1
|
||||||
@@ -141,7 +149,7 @@ Auto_Reset_Event :: struct {
|
|||||||
sema: Sema,
|
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)
|
old_status := atomic_load_explicit(&e.status, .Relaxed)
|
||||||
for {
|
for {
|
||||||
new_status := old_status + 1 if old_status < 1 else 1
|
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)
|
old_status := atomic_sub_explicit(&e.status, 1, .Acquire)
|
||||||
if old_status < 1 {
|
if old_status < 1 {
|
||||||
sema_wait(&e.sema)
|
sema_wait(&e.sema)
|
||||||
@@ -169,18 +177,18 @@ Ticket_Mutex :: struct {
|
|||||||
serving: uint,
|
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)
|
ticket := atomic_add_explicit(&m.ticket, 1, .Relaxed)
|
||||||
for ticket != atomic_load_explicit(&m.serving, .Acquire) {
|
for ticket != atomic_load_explicit(&m.serving, .Acquire) {
|
||||||
cpu_relax()
|
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)
|
atomic_add_explicit(&m.serving, 1, .Relaxed)
|
||||||
}
|
}
|
||||||
@(deferred_in=ticket_mutex_unlock)
|
@(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)
|
ticket_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -191,25 +199,25 @@ Benaphore :: struct {
|
|||||||
sema: Sema,
|
sema: Sema,
|
||||||
}
|
}
|
||||||
|
|
||||||
benaphore_lock :: proc(b: ^Benaphore) {
|
benaphore_lock :: proc "contextless" (b: ^Benaphore) {
|
||||||
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
||||||
sema_wait(&b.sema)
|
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)
|
v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire)
|
||||||
return v == 0
|
return v == 0
|
||||||
}
|
}
|
||||||
|
|
||||||
benaphore_unlock :: proc(b: ^Benaphore) {
|
benaphore_unlock :: proc "contextless" (b: ^Benaphore) {
|
||||||
if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
|
if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
|
||||||
sema_post(&b.sema)
|
sema_post(&b.sema)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@(deferred_in=benaphore_unlock)
|
@(deferred_in=benaphore_unlock)
|
||||||
benaphore_guard :: proc(m: ^Benaphore) -> bool {
|
benaphore_guard :: proc "contextless" (m: ^Benaphore) -> bool {
|
||||||
benaphore_lock(m)
|
benaphore_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -221,7 +229,7 @@ Recursive_Benaphore :: struct {
|
|||||||
sema: Sema,
|
sema: Sema,
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
|
recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) {
|
||||||
tid := current_thread_id()
|
tid := current_thread_id()
|
||||||
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
|
||||||
if tid != b.owner {
|
if tid != b.owner {
|
||||||
@@ -233,7 +241,7 @@ recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
|
|||||||
b.recursion += 1
|
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()
|
tid := current_thread_id()
|
||||||
if b.owner == tid {
|
if b.owner == tid {
|
||||||
atomic_add_explicit(&b.counter, 1, .Acquire)
|
atomic_add_explicit(&b.counter, 1, .Acquire)
|
||||||
@@ -248,9 +256,9 @@ recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
|
|||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
|
recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) {
|
||||||
tid := current_thread_id()
|
tid := current_thread_id()
|
||||||
assert(tid == b.owner)
|
_assert(tid == b.owner, "tid != b.owner")
|
||||||
b.recursion -= 1
|
b.recursion -= 1
|
||||||
recursion := b.recursion
|
recursion := b.recursion
|
||||||
if recursion == 0 {
|
if recursion == 0 {
|
||||||
@@ -265,7 +273,7 @@ recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@(deferred_in=recursive_benaphore_unlock)
|
@(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)
|
recursive_benaphore_lock(m)
|
||||||
return true
|
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 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)
|
@(cold)
|
||||||
do_slow :: proc(o: ^Once, fn: proc()) {
|
do_slow :: proc(o: ^Once, fn: proc()) {
|
||||||
guard(&o.m)
|
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 {
|
if atomic_load_explicit(&o.done, .Acquire) == false {
|
||||||
do_slow(o, fn)
|
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:
|
// 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.
|
// Blocks the current thread until the token is made available.
|
||||||
//
|
//
|
||||||
// Assumes this is only called by the thread that owns the Parker.
|
// Assumes this is only called by the thread that owns the Parker.
|
||||||
park :: proc(p: ^Parker) {
|
park :: proc "contextless" (p: ^Parker) {
|
||||||
EMPTY :: 0
|
EMPTY :: 0
|
||||||
NOTIFIED :: 1
|
NOTIFIED :: 1
|
||||||
PARKED :: max(u32)
|
PARKED :: max(u32)
|
||||||
@@ -333,7 +398,7 @@ park :: proc(p: ^Parker) {
|
|||||||
// for a limited duration.
|
// for a limited duration.
|
||||||
//
|
//
|
||||||
// Assumes this is only called by the thread that owns the Parker
|
// 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
|
EMPTY :: 0
|
||||||
NOTIFIED :: 1
|
NOTIFIED :: 1
|
||||||
PARKED :: max(u32)
|
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.
|
// Automatically makes thee token available if it was not already.
|
||||||
unpark :: proc(p: ^Parker) {
|
unpark :: proc "contextless" (p: ^Parker) {
|
||||||
EMPTY :: 0
|
EMPTY :: 0
|
||||||
NOTIFIED :: 1
|
NOTIFIED :: 1
|
||||||
PARKED :: max(Futex)
|
PARKED :: max(Futex)
|
||||||
|
|||||||
@@ -24,11 +24,11 @@ EINTR :: -4
|
|||||||
EFAULT :: -14
|
EFAULT :: -14
|
||||||
ETIMEDOUT :: -60
|
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)
|
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
|
timeout_ns := u32(duration) * 1000
|
||||||
|
|
||||||
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
|
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:
|
case ETIMEDOUT:
|
||||||
return false
|
return false
|
||||||
case:
|
case:
|
||||||
panic("futex_wait failure")
|
_panic("futex_wait failure")
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
loop: for {
|
loop: for {
|
||||||
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
|
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
|
||||||
if s >= 0 {
|
if s >= 0 {
|
||||||
@@ -59,12 +59,12 @@ _futex_signal :: proc(f: ^Futex) {
|
|||||||
case ENOENT:
|
case ENOENT:
|
||||||
return
|
return
|
||||||
case:
|
case:
|
||||||
panic("futex_wake_single failure")
|
_panic("futex_wake_single failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_broadcast :: proc(f: ^Futex) {
|
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
loop: for {
|
loop: for {
|
||||||
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
|
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
|
||||||
if s >= 0 {
|
if s >= 0 {
|
||||||
@@ -76,7 +76,7 @@ _futex_broadcast :: proc(f: ^Futex) {
|
|||||||
case ENOENT:
|
case ENOENT:
|
||||||
return
|
return
|
||||||
case:
|
case:
|
||||||
panic("futex_wake_all failure")
|
_panic("futex_wake_all failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ foreign libc {
|
|||||||
__error :: proc "c" () -> ^c.int ---
|
__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
|
timeout := [2]i64{14400, 0} // 4 hours
|
||||||
for {
|
for {
|
||||||
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
|
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
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
panic("_futex_wait failure")
|
_panic("_futex_wait failure")
|
||||||
}
|
}
|
||||||
unreachable()
|
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 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -51,21 +51,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
|||||||
return false
|
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)
|
res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil)
|
||||||
|
|
||||||
if res == -1 {
|
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)
|
res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil)
|
||||||
|
|
||||||
if res == -1 {
|
if res == -1 {
|
||||||
panic("_futex_broadcast failure")
|
_panic("_futex_broadcast failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-10
@@ -21,20 +21,20 @@ EFAULT :: -14
|
|||||||
EINVAL :: -22
|
EINVAL :: -22
|
||||||
ETIMEDOUT :: -110
|
ETIMEDOUT :: -110
|
||||||
|
|
||||||
get_errno :: proc(r: int) -> int {
|
get_errno :: proc "contextless" (r: int) -> int {
|
||||||
if -4096 < r && r < 0 {
|
if -4096 < r && r < 0 {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
return 0
|
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))
|
code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0))
|
||||||
return get_errno(code)
|
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)
|
err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil)
|
||||||
switch err {
|
switch err {
|
||||||
case ESUCCESS, EINTR, EAGAIN, EINVAL:
|
case ESUCCESS, EINTR, EAGAIN, EINVAL:
|
||||||
@@ -44,12 +44,12 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
|||||||
case EFAULT:
|
case EFAULT:
|
||||||
fallthrough
|
fallthrough
|
||||||
case:
|
case:
|
||||||
panic("futex_wait failure")
|
_panic("futex_wait failure")
|
||||||
}
|
}
|
||||||
return true
|
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 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -71,27 +71,27 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
|||||||
case EFAULT:
|
case EFAULT:
|
||||||
fallthrough
|
fallthrough
|
||||||
case:
|
case:
|
||||||
panic("futex_wait_with_timeout failure")
|
_panic("futex_wait_with_timeout failure")
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil)
|
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil)
|
||||||
switch err {
|
switch err {
|
||||||
case ESUCCESS, EINVAL, EFAULT:
|
case ESUCCESS, EINVAL, EFAULT:
|
||||||
// okay
|
// okay
|
||||||
case:
|
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)
|
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil)
|
||||||
switch err {
|
switch err {
|
||||||
case ESUCCESS, EINVAL, EFAULT:
|
case ESUCCESS, EINVAL, EFAULT:
|
||||||
// okay
|
// okay
|
||||||
case:
|
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 ---
|
_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)
|
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil)
|
||||||
|
|
||||||
if res != -1 {
|
if res != -1 {
|
||||||
@@ -32,10 +32,10 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
|||||||
return false
|
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 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
@@ -58,21 +58,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
|
|||||||
return false
|
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)
|
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
|
||||||
|
|
||||||
if res == -1 {
|
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)
|
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
|
||||||
|
|
||||||
if res == -1 {
|
if res == -1 {
|
||||||
panic("_futex_wake_all failure")
|
_panic("_futex_wake_all failure")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,18 +5,18 @@ package sync
|
|||||||
import "core:intrinsics"
|
import "core:intrinsics"
|
||||||
import "core:time"
|
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)
|
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
|
||||||
return s != 0
|
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))
|
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
|
||||||
return s != 0
|
return s != 0
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
loop: for {
|
loop: for {
|
||||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
|
||||||
if s >= 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 {
|
loop: for {
|
||||||
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
|
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
|
||||||
if s >= 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
|
expect := expect
|
||||||
return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
|
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
|
expect := expect
|
||||||
// NOTE(bill): for some bizarre reason, this has be a negative number
|
// NOTE(bill): for some bizarre reason, this has be a negative number
|
||||||
timeout := -i64(duration / 100)
|
timeout := -i64(duration / 100)
|
||||||
return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
|
return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_signal :: proc(f: ^Futex) {
|
_futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
WakeByAddressSingle(f)
|
WakeByAddressSingle(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
_futex_broadcast :: proc(f: ^Futex) {
|
_futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
WakeByAddressAll(f)
|
WakeByAddressAll(f)
|
||||||
}
|
}
|
||||||
+44
-28
@@ -1,5 +1,6 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
|
import "core:runtime"
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
|
||||||
current_thread_id :: proc "contextless" () -> int {
|
current_thread_id :: proc "contextless" () -> int {
|
||||||
@@ -15,17 +16,17 @@ Mutex :: struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// mutex_lock locks m
|
// mutex_lock locks m
|
||||||
mutex_lock :: proc(m: ^Mutex) {
|
mutex_lock :: proc "contextless" (m: ^Mutex) {
|
||||||
_mutex_lock(m)
|
_mutex_lock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// mutex_unlock unlocks m
|
// mutex_unlock unlocks m
|
||||||
mutex_unlock :: proc(m: ^Mutex) {
|
mutex_unlock :: proc "contextless" (m: ^Mutex) {
|
||||||
_mutex_unlock(m)
|
_mutex_unlock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// mutex_try_lock tries to lock m, will return true on success, and false on failure
|
// 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)
|
return _mutex_try_lock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -36,7 +37,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=mutex_unlock)
|
@(deferred_in=mutex_unlock)
|
||||||
mutex_guard :: proc(m: ^Mutex) -> bool {
|
mutex_guard :: proc "contextless" (m: ^Mutex) -> bool {
|
||||||
mutex_lock(m)
|
mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -52,32 +53,32 @@ RW_Mutex :: struct {
|
|||||||
|
|
||||||
// rw_mutex_lock locks rw for writing (with a single writer)
|
// 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.
|
// 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_lock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_unlock unlocks rw for writing (with a single writer)
|
// 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_unlock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_try_lock tries to lock rw for writing (with a single writer)
|
// 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)
|
return _rw_mutex_try_lock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
|
// 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_lock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
|
// 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_shared_unlock(rw)
|
||||||
}
|
}
|
||||||
|
|
||||||
// rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
|
// 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)
|
return _rw_mutex_try_shared_lock(rw)
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@@ -87,7 +88,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=rw_mutex_unlock)
|
@(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)
|
rw_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -99,7 +100,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=rw_mutex_shared_unlock)
|
@(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)
|
rw_mutex_shared_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -114,15 +115,15 @@ Recursive_Mutex :: struct {
|
|||||||
impl: _Recursive_Mutex,
|
impl: _Recursive_Mutex,
|
||||||
}
|
}
|
||||||
|
|
||||||
recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
|
recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {
|
||||||
_recursive_mutex_lock(m)
|
_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_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)
|
return _recursive_mutex_try_lock(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -133,7 +134,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=recursive_mutex_unlock)
|
@(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)
|
recursive_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -147,22 +148,22 @@ Cond :: struct {
|
|||||||
impl: _Cond,
|
impl: _Cond,
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_wait :: proc(c: ^Cond, m: ^Mutex) {
|
cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
|
||||||
_cond_wait(c, m)
|
_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 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
return _cond_wait_with_timeout(c, m, duration)
|
return _cond_wait_with_timeout(c, m, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_signal :: proc(c: ^Cond) {
|
cond_signal :: proc "contextless" (c: ^Cond) {
|
||||||
_cond_signal(c)
|
_cond_signal(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
cond_broadcast :: proc(c: ^Cond) {
|
cond_broadcast :: proc "contextless" (c: ^Cond) {
|
||||||
_cond_broadcast(c)
|
_cond_broadcast(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,15 +176,15 @@ Sema :: struct {
|
|||||||
impl: _Sema,
|
impl: _Sema,
|
||||||
}
|
}
|
||||||
|
|
||||||
sema_post :: proc(s: ^Sema, count := 1) {
|
sema_post :: proc "contextless" (s: ^Sema, count := 1) {
|
||||||
_sema_post(s, count)
|
_sema_post(s, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
sema_wait :: proc(s: ^Sema) {
|
sema_wait :: proc "contextless" (s: ^Sema) {
|
||||||
_sema_wait(s)
|
_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)
|
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
|
// An Futex must not be copied after first use
|
||||||
Futex :: distinct u32
|
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 {
|
if u32(atomic_load_explicit(f, .Acquire)) != expected {
|
||||||
return
|
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
|
// 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 {
|
if u32(atomic_load_explicit(f, .Acquire)) != expected {
|
||||||
return true
|
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)
|
return _futex_wait_with_timeout(f, expected, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
futex_signal :: proc(f: ^Futex) {
|
futex_signal :: proc "contextless" (f: ^Futex) {
|
||||||
_futex_signal(f)
|
_futex_signal(f)
|
||||||
}
|
}
|
||||||
|
|
||||||
futex_broadcast :: proc(f: ^Futex) {
|
futex_broadcast :: proc "contextless" (f: ^Futex) {
|
||||||
_futex_broadcast(f)
|
_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 locks m
|
||||||
atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
|
atomic_mutex_lock :: proc "contextless" (m: ^Atomic_Mutex) {
|
||||||
@(cold)
|
@(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
|
new_state := curr_state // Make a copy of it
|
||||||
|
|
||||||
spin_lock: for spin in 0..<i32(100) {
|
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 unlocks m
|
||||||
atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) {
|
atomic_mutex_unlock :: proc "contextless" (m: ^Atomic_Mutex) {
|
||||||
@(cold)
|
@(cold)
|
||||||
unlock_slow :: proc(m: ^Atomic_Mutex) {
|
unlock_slow :: proc "contextless" (m: ^Atomic_Mutex) {
|
||||||
futex_signal((^Futex)(&m.state))
|
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 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)
|
_, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .Acquire, .Consume)
|
||||||
return ok
|
return ok
|
||||||
}
|
}
|
||||||
@@ -88,7 +88,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=atomic_mutex_unlock)
|
@(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)
|
atomic_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -117,7 +117,7 @@ Atomic_RW_Mutex :: struct {
|
|||||||
|
|
||||||
// atomic_rw_mutex_lock locks rw for writing (with a single writer)
|
// 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.
|
// 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_add(&rw.state, Atomic_RW_Mutex_State_Writer)
|
||||||
atomic_mutex_lock(&rw.mutex)
|
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 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_and(&rw.state, ~Atomic_RW_Mutex_State_Is_Writing)
|
||||||
atomic_mutex_unlock(&rw.mutex)
|
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 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) {
|
if atomic_mutex_try_lock(&rw.mutex) {
|
||||||
state := atomic_load(&rw.state)
|
state := atomic_load(&rw.state)
|
||||||
if state & Atomic_RW_Mutex_State_Reader_Mask == 0 {
|
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 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)
|
state := atomic_load(&rw.state)
|
||||||
for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
||||||
ok: bool
|
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 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)
|
state := atomic_sub(&rw.state, Atomic_RW_Mutex_State_Reader)
|
||||||
|
|
||||||
if (state & Atomic_RW_Mutex_State_Reader_Mask == 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 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)
|
state := atomic_load(&rw.state)
|
||||||
if state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
|
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)
|
_, 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)
|
@(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)
|
atomic_rw_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -210,7 +210,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=atomic_rw_mutex_shared_unlock)
|
@(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)
|
atomic_rw_mutex_shared_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -228,7 +228,7 @@ Atomic_Recursive_Mutex :: struct {
|
|||||||
mutex: Mutex,
|
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()
|
tid := current_thread_id()
|
||||||
if tid != m.owner {
|
if tid != m.owner {
|
||||||
mutex_lock(&m.mutex)
|
mutex_lock(&m.mutex)
|
||||||
@@ -238,9 +238,9 @@ atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) {
|
|||||||
m.recursion += 1
|
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()
|
tid := current_thread_id()
|
||||||
assert(tid == m.owner)
|
_assert(tid == m.owner, "tid != m.owner")
|
||||||
m.recursion -= 1
|
m.recursion -= 1
|
||||||
recursion := m.recursion
|
recursion := m.recursion
|
||||||
if recursion == 0 {
|
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()
|
tid := current_thread_id()
|
||||||
if m.owner == tid {
|
if m.owner == tid {
|
||||||
return mutex_try_lock(&m.mutex)
|
return mutex_try_lock(&m.mutex)
|
||||||
@@ -274,7 +274,7 @@ Example:
|
|||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
@(deferred_in=atomic_recursive_mutex_unlock)
|
@(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)
|
atomic_recursive_mutex_lock(m)
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
@@ -289,7 +289,7 @@ Atomic_Cond :: struct {
|
|||||||
state: Futex,
|
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))
|
state := u32(atomic_load_explicit(&c.state, .Relaxed))
|
||||||
unlock(m)
|
unlock(m)
|
||||||
futex_wait(&c.state, state)
|
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))
|
state := u32(atomic_load_explicit(&c.state, .Relaxed))
|
||||||
unlock(m)
|
unlock(m)
|
||||||
ok = futex_wait_with_timeout(&c.state, state, duration)
|
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)
|
atomic_add_explicit(&c.state, 1, .Release)
|
||||||
futex_signal(&c.state)
|
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)
|
atomic_add_explicit(&c.state, 1, .Release)
|
||||||
futex_broadcast(&c.state)
|
futex_broadcast(&c.state)
|
||||||
}
|
}
|
||||||
@@ -324,7 +324,7 @@ Atomic_Sema :: struct {
|
|||||||
count: Futex,
|
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)
|
atomic_add_explicit(&s.count, Futex(count), .Release)
|
||||||
if count == 1 {
|
if count == 1 {
|
||||||
futex_signal(&s.count)
|
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 {
|
for {
|
||||||
original_count := atomic_load_explicit(&s.count, .Relaxed)
|
original_count := atomic_load_explicit(&s.count, .Relaxed)
|
||||||
for original_count == 0 {
|
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 {
|
if duration <= 0 {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,20 +2,31 @@
|
|||||||
package sync
|
package sync
|
||||||
|
|
||||||
import "core:time"
|
import "core:time"
|
||||||
|
import vg "core:sys/valgrind"
|
||||||
|
_ :: vg
|
||||||
|
|
||||||
_Sema :: struct {
|
_Sema :: struct {
|
||||||
atomic: Atomic_Sema,
|
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)
|
atomic_sema_post(&s.impl.atomic, count)
|
||||||
}
|
}
|
||||||
|
|
||||||
_sema_wait :: proc(s: ^Sema) {
|
_sema_wait :: proc "contextless" (s: ^Sema) {
|
||||||
atomic_sema_wait(&s.impl.atomic)
|
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)
|
return atomic_sema_wait_with_timeout(&s.impl.atomic, duration)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -25,7 +36,12 @@ _Recursive_Mutex :: struct {
|
|||||||
recursion: i32,
|
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())
|
tid := Futex(current_thread_id())
|
||||||
for {
|
for {
|
||||||
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
|
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
|
m.impl.recursion -= 1
|
||||||
if m.impl.recursion != 0 {
|
if m.impl.recursion != 0 {
|
||||||
return
|
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())
|
tid := Futex(current_thread_id())
|
||||||
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
|
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
|
||||||
switch prev_owner {
|
switch prev_owner {
|
||||||
@@ -70,15 +91,27 @@ when ODIN_OS != .Windows {
|
|||||||
mutex: Atomic_Mutex,
|
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)
|
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)
|
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)
|
return atomic_mutex_try_lock(&m.impl.mutex)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -86,19 +119,33 @@ when ODIN_OS != .Windows {
|
|||||||
cond: Atomic_Cond,
|
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)
|
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)
|
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)
|
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)
|
atomic_cond_broadcast(&c.impl.cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -107,27 +154,39 @@ when ODIN_OS != .Windows {
|
|||||||
mutex: Atomic_RW_Mutex,
|
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)
|
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)
|
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)
|
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)
|
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)
|
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)
|
return atomic_rw_mutex_try_shared_lock(&rw.impl.mutex)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -13,15 +13,15 @@ _Mutex :: struct {
|
|||||||
srwlock: win32.SRWLOCK,
|
srwlock: win32.SRWLOCK,
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_lock :: proc(m: ^Mutex) {
|
_mutex_lock :: proc "contextless" (m: ^Mutex) {
|
||||||
win32.AcquireSRWLockExclusive(&m.impl.srwlock)
|
win32.AcquireSRWLockExclusive(&m.impl.srwlock)
|
||||||
}
|
}
|
||||||
|
|
||||||
_mutex_unlock :: proc(m: ^Mutex) {
|
_mutex_unlock :: proc "contextless" (m: ^Mutex) {
|
||||||
win32.ReleaseSRWLockExclusive(&m.impl.srwlock)
|
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))
|
return bool(win32.TryAcquireSRWLockExclusive(&m.impl.srwlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -29,27 +29,27 @@ _RW_Mutex :: struct {
|
|||||||
srwlock: win32.SRWLOCK,
|
srwlock: win32.SRWLOCK,
|
||||||
}
|
}
|
||||||
|
|
||||||
_rw_mutex_lock :: proc(rw: ^RW_Mutex) {
|
_rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
|
||||||
win32.AcquireSRWLockExclusive(&rw.impl.srwlock)
|
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)
|
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))
|
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)
|
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)
|
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))
|
return bool(win32.TryAcquireSRWLockShared(&rw.impl.srwlock))
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,22 +58,22 @@ _Cond :: struct {
|
|||||||
cond: win32.CONDITION_VARIABLE,
|
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)
|
_ = 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)
|
duration := u32(duration / time.Millisecond)
|
||||||
ok := win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, duration, 0)
|
ok := win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, duration, 0)
|
||||||
return bool(ok)
|
return bool(ok)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
_cond_signal :: proc(c: ^Cond) {
|
_cond_signal :: proc "contextless" (c: ^Cond) {
|
||||||
win32.WakeConditionVariable(&c.impl.cond)
|
win32.WakeConditionVariable(&c.impl.cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
_cond_broadcast :: proc(c: ^Cond) {
|
_cond_broadcast :: proc "contextless" (c: ^Cond) {
|
||||||
win32.WakeAllConditionVariable(&c.impl.cond)
|
win32.WakeAllConditionVariable(&c.impl.cond)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,45 @@ package sys_windows
|
|||||||
|
|
||||||
foreign import dwmapi "system:Dwmapi.lib"
|
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")
|
@(default_calling_convention="stdcall")
|
||||||
foreign dwmapi {
|
foreign dwmapi {
|
||||||
DwmFlush :: proc() -> HRESULT ---
|
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 ---
|
SetPixelFormat :: proc(hdc: HDC, format: c_int, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL ---
|
||||||
ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int ---
|
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 ---
|
SwapBuffers :: proc(HDC) -> BOOL ---
|
||||||
|
|
||||||
SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF ---
|
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 ---
|
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 ---
|
GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: c_int, psizl: LPSIZE) -> BOOL ---
|
||||||
GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL ---
|
GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL ---
|
||||||
|
|
||||||
|
CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH ---
|
||||||
}
|
}
|
||||||
|
|
||||||
RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF {
|
RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF {
|
||||||
|
|||||||
@@ -370,6 +370,8 @@ foreign kernel32 {
|
|||||||
lpTotalNumberOfBytes: PULARGE_INTEGER,
|
lpTotalNumberOfBytes: PULARGE_INTEGER,
|
||||||
lpTotalNumberOfFreeBytes: PULARGE_INTEGER,
|
lpTotalNumberOfFreeBytes: PULARGE_INTEGER,
|
||||||
) -> BOOL ---
|
) -> BOOL ---
|
||||||
|
|
||||||
|
GetLogicalProcessorInformation :: proc(buffer: ^SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returnedLength: PDWORD) -> BOOL ---
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -999,3 +1001,49 @@ foreign kernel32 {
|
|||||||
ConvertThreadToFiber :: proc(lpParameter: LPVOID) -> LPVOID ---
|
ConvertThreadToFiber :: proc(lpParameter: LPVOID) -> LPVOID ---
|
||||||
SwitchToFiber :: proc(lpFiber: 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 ---
|
) -> c_int ---
|
||||||
SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int ---
|
SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int ---
|
||||||
SHGetFolderPathW :: proc(hwnd: HWND, csidl: c_int, hToken: HANDLE, dwFlags: DWORD, pszPath: LPWSTR) -> HRESULT ---
|
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
|
HKEY :: distinct HANDLE
|
||||||
HDESK :: distinct HANDLE
|
HDESK :: distinct HANDLE
|
||||||
HFONT :: distinct HANDLE
|
HFONT :: distinct HANDLE
|
||||||
|
HRGN :: distinct HANDLE
|
||||||
BOOL :: distinct b32
|
BOOL :: distinct b32
|
||||||
BYTE :: distinct u8
|
BYTE :: distinct u8
|
||||||
BOOLEAN :: distinct b8
|
BOOLEAN :: distinct b8
|
||||||
@@ -1554,6 +1555,25 @@ WA_INACTIVE :: 0
|
|||||||
WA_ACTIVE :: 1
|
WA_ACTIVE :: 1
|
||||||
WA_CLICKACTIVE :: 2
|
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
|
// SetWindowsHook() codes
|
||||||
WH_MIN :: -1
|
WH_MIN :: -1
|
||||||
WH_MSGFILTER :: -1
|
WH_MSGFILTER :: -1
|
||||||
|
|||||||
@@ -100,6 +100,7 @@ foreign user32 {
|
|||||||
AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL ---
|
AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL ---
|
||||||
|
|
||||||
SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL ---
|
SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL ---
|
||||||
|
GetMonitorInfoW :: proc(hMonitor: HMONITOR, lpmi: LPMONITORINFO) -> BOOL ---
|
||||||
|
|
||||||
GetWindowDC :: proc(hWnd: HWND) -> HDC ---
|
GetWindowDC :: proc(hWnd: HWND) -> HDC ---
|
||||||
GetDC :: proc(hWnd: HWND) -> HDC ---
|
GetDC :: proc(hWnd: HWND) -> HDC ---
|
||||||
@@ -123,6 +124,8 @@ foreign user32 {
|
|||||||
GetKeyState :: proc(nVirtKey: c_int) -> SHORT ---
|
GetKeyState :: proc(nVirtKey: c_int) -> SHORT ---
|
||||||
GetAsyncKeyState :: proc(vKey: c_int) -> SHORT ---
|
GetAsyncKeyState :: proc(vKey: c_int) -> SHORT ---
|
||||||
|
|
||||||
|
GetKeyboardState :: proc(lpKeyState: PBYTE) -> BOOL ---
|
||||||
|
|
||||||
MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT ---
|
MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT ---
|
||||||
|
|
||||||
SetWindowsHookExW :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK ---
|
SetWindowsHookExW :: proc(idHook: c_int, lpfn: HOOKPROC, hmod: HINSTANCE, dwThreadId: DWORD) -> HHOOK ---
|
||||||
@@ -202,6 +205,17 @@ foreign user32 {
|
|||||||
GetRawInputDeviceList :: proc(pRawInputDeviceList: PRAWINPUTDEVICELIST, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
GetRawInputDeviceList :: proc(pRawInputDeviceList: PRAWINPUTDEVICELIST, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
||||||
GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
|
||||||
RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL ---
|
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" (
|
CreateWindowW :: #force_inline proc "stdcall" (
|
||||||
@@ -432,3 +446,27 @@ RI_MOUSE_BUTTON_5_DOWN :: 0x0100
|
|||||||
RI_MOUSE_BUTTON_5_UP :: 0x0200
|
RI_MOUSE_BUTTON_5_UP :: 0x0200
|
||||||
RI_MOUSE_WHEEL :: 0x0400
|
RI_MOUSE_WHEEL :: 0x0400
|
||||||
RI_MOUSE_HWHEEL :: 0x0800
|
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) {
|
T &operator[](isize index) {
|
||||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
#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
|
#endif
|
||||||
return data[index];
|
return data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
T const &operator[](isize index) const {
|
T const &operator[](isize index) const {
|
||||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
#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
|
#endif
|
||||||
return data[index];
|
return data[index];
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename T> void array_init (Array<T> *array, gbAllocator const &a);
|
template <typename T> gb_internal 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> gb_internal 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> gb_internal 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> gb_internal Array<T> array_make (gbAllocator const &a);
|
||||||
template <typename T> Array<T> array_make (gbAllocator const &a, isize count);
|
template <typename T> gb_internal 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> gb_internal 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> gb_internal Array<T> array_make_from_ptr (T *data, isize count, isize capacity);
|
||||||
template <typename T> void array_free (Array<T> *array);
|
template <typename T> gb_internal void array_free (Array<T> *array);
|
||||||
template <typename T> void array_add (Array<T> *array, T const &t);
|
template <typename T> gb_internal void array_add (Array<T> *array, T const &t);
|
||||||
template <typename T> T * array_add_and_get (Array<T> *array);
|
template <typename T> gb_internal 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> gb_internal 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> gb_internal T array_pop (Array<T> *array);
|
||||||
template <typename T> void array_clear (Array<T> *array);
|
template <typename T> gb_internal void array_clear (Array<T> *array);
|
||||||
template <typename T> void array_reserve (Array<T> *array, isize capacity);
|
template <typename T> gb_internal void array_reserve (Array<T> *array, isize capacity);
|
||||||
template <typename T> void array_resize (Array<T> *array, isize count);
|
template <typename T> gb_internal void array_resize (Array<T> *array, isize count);
|
||||||
template <typename T> void array_set_capacity (Array<T> *array, isize capacity);
|
template <typename T> gb_internal 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> gb_internal 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 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> gb_internal 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_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> gb_internal 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, 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>
|
template <typename T>
|
||||||
@@ -56,27 +56,27 @@ struct Slice {
|
|||||||
T *data;
|
T *data;
|
||||||
isize count;
|
isize count;
|
||||||
|
|
||||||
T &operator[](isize index) {
|
gb_inline T &operator[](isize index) {
|
||||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
#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
|
#endif
|
||||||
return data[index];
|
return data[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
T const &operator[](isize index) const {
|
gb_inline T const &operator[](isize index) const {
|
||||||
#if !defined(NO_ARRAY_BOUNDS_CHECK)
|
#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
|
#endif
|
||||||
return data[index];
|
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>
|
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);
|
GB_ASSERT(count >= 0);
|
||||||
Slice<T> s = {};
|
Slice<T> s = {};
|
||||||
s.data = gb_alloc_array(allocator, T, count);
|
s.data = gb_alloc_array(allocator, T, count);
|
||||||
@@ -86,7 +86,7 @@ Slice<T> slice_make(gbAllocator const &allocator, isize count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(count >= 0);
|
||||||
s->data = gb_alloc_array(allocator, T, count);
|
s->data = gb_alloc_array(allocator, T, count);
|
||||||
if (count > 0) {
|
if (count > 0) {
|
||||||
@@ -96,23 +96,23 @@ void slice_init(Slice<T> *s, gbAllocator const &allocator, isize count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
gb_free(allocator, s->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
resize_array_raw(&s->data, allocator, s->count, new_count);
|
||||||
s->count = new_count;
|
s->count = new_count;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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};
|
return {a.data, a.count};
|
||||||
}
|
}
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
|
||||||
Slice<T> out = {};
|
Slice<T> out = {};
|
||||||
isize len = hi-lo;
|
isize len = hi-lo;
|
||||||
@@ -125,30 +125,30 @@ Slice<T> slice_array(Array<T> const &array, isize lo, isize hi) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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));
|
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};
|
return {data, a.count};
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
auto c = array_clone(allocator, a);
|
||||||
return {c.data, c.count};
|
return {c.data, c.count};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
isize n = gb_min(slice->count, data.count);
|
||||||
gb_memmove(slice->data, data.data, gb_size_of(T)*n);
|
gb_memmove(slice->data, data.data, gb_size_of(T)*n);
|
||||||
}
|
}
|
||||||
template <typename T>
|
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);
|
isize n = gb_clamp(slice->count-offset, 0, data.count);
|
||||||
gb_memmove(slice->data+offset, data.data, gb_size_of(T)*n);
|
gb_memmove(slice->data+offset, data.data, gb_size_of(T)*n);
|
||||||
}
|
}
|
||||||
template <typename T>
|
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));
|
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);
|
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>
|
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);
|
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
|
||||||
Slice<T> out = {};
|
Slice<T> out = {};
|
||||||
isize len = hi-lo;
|
isize len = hi-lo;
|
||||||
@@ -169,7 +169,7 @@ gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(0 <= index && index < array->count);
|
||||||
|
|
||||||
isize bytes = gb_size_of(T) * (array->count-(index+1));
|
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>
|
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);
|
GB_ASSERT(0 <= index && index < array->count);
|
||||||
|
|
||||||
isize n = array->count-1;
|
isize n = array->count-1;
|
||||||
@@ -190,18 +190,18 @@ void slice_unordered_remove(Slice<T> *array, isize index) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
gb_memmove(array->data+offset, data.data, gb_size_of(T)*data.count);
|
||||||
}
|
}
|
||||||
template <typename T>
|
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));
|
gb_memmove(array->data+offset, data.data, gb_size_of(T)*gb_min(data.count, count));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *array_end_ptr(Array<T> *array) {
|
gb_internal T *array_end_ptr(Array<T> *array) {
|
||||||
if (array->count > 0) {
|
if (array->count > 0) {
|
||||||
return &array->data[array->count-1];
|
return &array->data[array->count-1];
|
||||||
}
|
}
|
||||||
@@ -210,18 +210,18 @@ T *array_end_ptr(Array<T> *array) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
isize cap = ARRAY_GROW_FORMULA(0);
|
||||||
array_init(array, a, 0, cap);
|
array_init(array, a, 0, cap);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
array_init(array, a, count, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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->allocator = a;
|
||||||
array->data = nullptr;
|
array->data = nullptr;
|
||||||
if (capacity > 0) {
|
if (capacity > 0) {
|
||||||
@@ -234,7 +234,7 @@ gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count, is
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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};
|
Array<T> a = {0};
|
||||||
a.data = data;
|
a.data = data;
|
||||||
a.count = count;
|
a.count = count;
|
||||||
@@ -244,7 +244,7 @@ gb_inline Array<T> array_make_from_ptr(T *data, isize count, isize capacity) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
isize capacity = ARRAY_GROW_FORMULA(0);
|
||||||
Array<T> array = {};
|
Array<T> array = {};
|
||||||
array.allocator = a;
|
array.allocator = a;
|
||||||
@@ -254,7 +254,7 @@ gb_inline Array<T> array_make(gbAllocator const &a) {
|
|||||||
return array;
|
return array;
|
||||||
}
|
}
|
||||||
template <typename T>
|
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<T> array = {};
|
||||||
array.allocator = a;
|
array.allocator = a;
|
||||||
array.data = gb_alloc_array(a, T, count);
|
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;
|
return array;
|
||||||
}
|
}
|
||||||
template <typename T>
|
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<T> array = {};
|
||||||
array.allocator = a;
|
array.allocator = a;
|
||||||
array.data = gb_alloc_array(a, T, capacity);
|
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>
|
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) {
|
if (array->allocator.proc != nullptr) {
|
||||||
gb_free(array->allocator, array->data);
|
gb_free(array->allocator, array->data);
|
||||||
}
|
}
|
||||||
@@ -284,7 +284,7 @@ gb_inline void array_free(Array<T> *array) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
isize new_capacity = ARRAY_GROW_FORMULA(array->capacity);
|
||||||
if (new_capacity < min_capacity) {
|
if (new_capacity < min_capacity) {
|
||||||
new_capacity = min_capacity;
|
new_capacity = min_capacity;
|
||||||
@@ -293,7 +293,7 @@ void array__grow(Array<T> *array, isize min_capacity) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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) {
|
if (array->capacity < array->count+1) {
|
||||||
array__grow(array, 0);
|
array__grow(array, 0);
|
||||||
}
|
}
|
||||||
@@ -302,7 +302,7 @@ void array_add(Array<T> *array, T const &t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename 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) {
|
if (array->count < array->capacity) {
|
||||||
return &array->data[array->count++];
|
return &array->data[array->count++];
|
||||||
}
|
}
|
||||||
@@ -314,7 +314,7 @@ T *array_add_and_get(Array<T> *array) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(elem_count >= 0);
|
||||||
if (array->capacity < array->count+elem_count) {
|
if (array->capacity < array->count+elem_count) {
|
||||||
array__grow(array, 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>
|
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);
|
GB_ASSERT(array->count > 0);
|
||||||
array->count--;
|
array->count--;
|
||||||
return array->data[array->count];
|
return array->data[array->count];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void array_clear(Array<T> *array) {
|
gb_internal void array_clear(Array<T> *array) {
|
||||||
array->count = 0;
|
array->count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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) {
|
if (array->capacity < capacity) {
|
||||||
array_set_capacity(array, capacity);
|
array_set_capacity(array, capacity);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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) {
|
if (array->capacity < count) {
|
||||||
array__grow(array, count);
|
array__grow(array, count);
|
||||||
}
|
}
|
||||||
@@ -352,7 +352,7 @@ void array_resize(Array<T> *array, isize count) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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) {
|
if (capacity == array->capacity) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -381,7 +381,7 @@ void array_set_capacity(Array<T> *array, isize capacity) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
|
||||||
Array<T> out = {};
|
Array<T> out = {};
|
||||||
isize len = hi-lo;
|
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>
|
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);
|
auto clone = array_make<T>(allocator, array.count, array.count);
|
||||||
array_copy(&clone, array, 0);
|
array_copy(&clone, array, 0);
|
||||||
return clone;
|
return clone;
|
||||||
@@ -402,7 +402,7 @@ Array<T> array_clone(gbAllocator const &allocator, Array<T> const &array) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(0 <= index && index < array->count);
|
||||||
|
|
||||||
isize bytes = gb_size_of(T) * (array->count-(index+1));
|
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>
|
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);
|
GB_ASSERT(0 <= index && index < array->count);
|
||||||
|
|
||||||
isize n = array->count-1;
|
isize n = array->count-1;
|
||||||
@@ -424,35 +424,35 @@ void array_unordered_remove(Array<T> *array, isize index) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *begin(Array<T> &array) {
|
gb_internal T *begin(Array<T> &array) {
|
||||||
return array.data;
|
return array.data;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T const *begin(Array<T> const &array) {
|
gb_internal T const *begin(Array<T> const &array) {
|
||||||
return array.data;
|
return array.data;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *end(Array<T> &array) {
|
gb_internal T *end(Array<T> &array) {
|
||||||
return array.data + array.count;
|
return array.data + array.count;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T const *end(Array<T> const &array) {
|
gb_internal T const *end(Array<T> const &array) {
|
||||||
return array.data + array.count;
|
return array.data + array.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *begin(Slice<T> &array) {
|
gb_internal T *begin(Slice<T> &array) {
|
||||||
return array.data;
|
return array.data;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T const *begin(Slice<T> const &array) {
|
gb_internal T const *begin(Slice<T> const &array) {
|
||||||
return array.data;
|
return array.data;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T *end(Slice<T> &array) {
|
gb_internal T *end(Slice<T> &array) {
|
||||||
return array.data + array.count;
|
return array.data + array.count;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T const *end(Slice<T> const &array) {
|
gb_internal T const *end(Slice<T> const &array) {
|
||||||
return array.data + array.count;
|
return array.data + array.count;
|
||||||
}
|
}
|
||||||
|
|||||||
+103
-79
@@ -37,86 +37,86 @@ void MP_FREE(void *mem, size_t size) {
|
|||||||
|
|
||||||
typedef mp_int BigInt;
|
typedef mp_int BigInt;
|
||||||
|
|
||||||
void big_int_from_u64(BigInt *dst, u64 x);
|
gb_internal void big_int_from_u64(BigInt *dst, u64 x);
|
||||||
void big_int_from_i64(BigInt *dst, i64 x);
|
gb_internal void big_int_from_i64(BigInt *dst, i64 x);
|
||||||
void big_int_init (BigInt *dst, BigInt const *src);
|
gb_internal 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_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);
|
mp_clear(dst);
|
||||||
}
|
}
|
||||||
|
|
||||||
BigInt big_int_make(BigInt const *b, bool abs=false);
|
gb_internal BigInt big_int_make(BigInt const *b, bool abs=false);
|
||||||
BigInt big_int_make_abs(BigInt const *b);
|
gb_internal BigInt big_int_make_abs(BigInt const *b);
|
||||||
BigInt big_int_make_u64(u64 x);
|
gb_internal BigInt big_int_make_u64(u64 x);
|
||||||
BigInt big_int_make_i64(i64 x);
|
gb_internal BigInt big_int_make_i64(i64 x);
|
||||||
|
|
||||||
u64 big_int_to_u64 (BigInt const *x);
|
gb_internal u64 big_int_to_u64 (BigInt const *x);
|
||||||
i64 big_int_to_i64 (BigInt const *x);
|
gb_internal i64 big_int_to_i64 (BigInt const *x);
|
||||||
f64 big_int_to_f64 (BigInt const *x);
|
gb_internal f64 big_int_to_f64 (BigInt const *x);
|
||||||
String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base = 10);
|
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);
|
gb_internal void big_int_add (BigInt *dst, BigInt const *x, BigInt const *y);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
|
|
||||||
void big_int_add_eq(BigInt *dst, BigInt const *x);
|
gb_internal void big_int_add_eq(BigInt *dst, BigInt const *x);
|
||||||
void big_int_sub_eq(BigInt *dst, BigInt const *x);
|
gb_internal void big_int_sub_eq(BigInt *dst, BigInt const *x);
|
||||||
void big_int_shl_eq(BigInt *dst, BigInt const *x);
|
gb_internal void big_int_shl_eq(BigInt *dst, BigInt const *x);
|
||||||
void big_int_shr_eq(BigInt *dst, BigInt const *x);
|
gb_internal 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_mul_eq(BigInt *dst, BigInt const *x);
|
||||||
|
|
||||||
void big_int_quo_eq(BigInt *dst, BigInt const *x);
|
gb_internal 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_rem_eq(BigInt *dst, BigInt const *x);
|
||||||
|
|
||||||
bool big_int_is_neg(BigInt const *x);
|
gb_internal bool big_int_is_neg(BigInt const *x);
|
||||||
void big_int_neg(BigInt *dst, 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 = {};
|
BigInt res = {};
|
||||||
big_int_init(&res, dst);
|
big_int_init(&res, dst);
|
||||||
big_int_add(dst, &res, x);
|
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 = {};
|
BigInt res = {};
|
||||||
big_int_init(&res, dst);
|
big_int_init(&res, dst);
|
||||||
big_int_sub(dst, &res, x);
|
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 = {};
|
BigInt res = {};
|
||||||
big_int_init(&res, dst);
|
big_int_init(&res, dst);
|
||||||
big_int_shl(dst, &res, x);
|
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 = {};
|
BigInt res = {};
|
||||||
big_int_init(&res, dst);
|
big_int_init(&res, dst);
|
||||||
big_int_shr(dst, &res, x);
|
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 = {};
|
BigInt res = {};
|
||||||
big_int_init(&res, dst);
|
big_int_init(&res, dst);
|
||||||
big_int_mul(dst, &res, x);
|
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 = {};
|
BigInt res = {};
|
||||||
big_int_init(&res, dst);
|
big_int_init(&res, dst);
|
||||||
big_int_quo(dst, &res, x);
|
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 = {};
|
BigInt res = {};
|
||||||
big_int_init(&res, dst);
|
big_int_init(&res, dst);
|
||||||
big_int_rem(dst, &res, x);
|
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)) {
|
if (mp_iszero(x)) {
|
||||||
return 0;
|
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);
|
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);
|
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) {
|
if (dst == src) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mp_init_copy(dst, src);
|
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 = {};
|
BigInt i = {};
|
||||||
big_int_init(&i, b);
|
big_int_init(&i, b);
|
||||||
if (abs) mp_abs(&i, &i);
|
if (abs) mp_abs(&i, &i);
|
||||||
return 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);
|
return big_int_make(b, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BigInt big_int_make_u64(u64 x) {
|
gb_internal BigInt big_int_make_u64(u64 x) {
|
||||||
BigInt i = {};
|
BigInt i = {};
|
||||||
big_int_from_u64(&i, x);
|
big_int_from_u64(&i, x);
|
||||||
return i;
|
return i;
|
||||||
}
|
}
|
||||||
BigInt big_int_make_i64(i64 x) {
|
gb_internal BigInt big_int_make_i64(i64 x) {
|
||||||
BigInt i = {};
|
BigInt i = {};
|
||||||
big_int_from_i64(&i, x);
|
big_int_from_i64(&i, x);
|
||||||
return i;
|
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;
|
*success = true;
|
||||||
|
|
||||||
bool is_negative = false;
|
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);
|
GB_ASSERT(x->sign == 0);
|
||||||
return mp_get_u64(x);
|
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);
|
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);
|
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);
|
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);
|
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)) {
|
if (mp_iszero(x)) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
return x->sign ? -1 : +1;
|
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);
|
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);
|
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);
|
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);
|
u32 yy = mp_get_u32(y);
|
||||||
mp_mul_2d(x, yy, dst);
|
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);
|
u32 yy = mp_get_u32(y);
|
||||||
BigInt d = {};
|
BigInt d = {};
|
||||||
mp_div_2d(x, yy, dst, &d);
|
mp_div_2d(x, yy, dst, &d);
|
||||||
big_int_dealloc(&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 = {};
|
BigInt d = {};
|
||||||
big_int_from_u64(&d, y);
|
big_int_from_u64(&d, y);
|
||||||
mp_mul(x, &d, dst);
|
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);
|
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_COMPILER_MSVC)
|
||||||
#if defined(GB_ARCH_64_BIT)
|
#if defined(GB_ARCH_64_BIT)
|
||||||
return __lzcnt64(x);
|
return __lzcnt64(x);
|
||||||
@@ -367,23 +367,23 @@ u64 leading_zeros_u64(u64 x) {
|
|||||||
//
|
//
|
||||||
// q = x/y with the result truncated to zero
|
// q = x/y with the result truncated to zero
|
||||||
// r = x - y*q
|
// 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_);
|
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 = {};
|
BigInt r = {};
|
||||||
big_int_quo_rem(x, y, z, &r);
|
big_int_quo_rem(x, y, z, &r);
|
||||||
big_int_dealloc(&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 = {};
|
BigInt q = {};
|
||||||
big_int_quo_rem(x, y, &q, z);
|
big_int_quo_rem(x, y, &q, z);
|
||||||
big_int_dealloc(&q);
|
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 = {};
|
BigInt y0 = {};
|
||||||
big_int_init(&y0, y);
|
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);
|
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)) {
|
if (mp_iszero(x)) {
|
||||||
big_int_init(dst, y);
|
big_int_init(dst, y);
|
||||||
return;
|
return;
|
||||||
@@ -467,22 +467,23 @@ void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y) {
|
|||||||
return;
|
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);
|
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);
|
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);
|
String s = big_int_to_string(temporary_allocator(), x, 10);
|
||||||
gb_printf_err("[DEBUG] %.*s\n", LIT(s));
|
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);
|
GB_ASSERT(bit_count >= 0);
|
||||||
if (bit_count == 0) {
|
if (bit_count == 0) {
|
||||||
big_int_from_u64(dst, 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);
|
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) {
|
if (x == nullptr) {
|
||||||
return false;
|
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);
|
GB_ASSERT(digit < 16);
|
||||||
if (digit <= 9) {
|
if (digit <= 9) {
|
||||||
return digit + '0';
|
return digit + '0';
|
||||||
@@ -548,7 +549,7 @@ char digit_to_char(u8 digit) {
|
|||||||
return '0';
|
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);
|
GB_ASSERT(base <= 16);
|
||||||
|
|
||||||
if (mp_iszero(x)) {
|
if (mp_iszero(x)) {
|
||||||
@@ -560,6 +561,28 @@ String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
|
|||||||
Array<char> buf = {};
|
Array<char> buf = {};
|
||||||
array_init(&buf, allocator, 0, 32);
|
array_init(&buf, allocator, 0, 32);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
mp_int thousand_below = {};
|
||||||
|
mp_int thousand_above = {};
|
||||||
|
mp_init_i32(&thousand_below, 10);
|
||||||
|
|
||||||
|
mp_expt_n(&thousand_below, exp-3, &thousand_below);
|
||||||
|
mp_div(&val, &thousand_below, &thousand_above, nullptr);
|
||||||
|
|
||||||
|
double mant = 1.0e-3 * mp_get_double(&thousand_above);
|
||||||
|
|
||||||
|
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 = {};
|
BigInt v = {};
|
||||||
mp_init_copy(&v, x);
|
mp_init_copy(&v, x);
|
||||||
|
|
||||||
@@ -595,5 +618,6 @@ String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
|
|||||||
buf[j] = tmp;
|
buf[j] = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
return make_string(cast(u8 *)buf.data, buf.count);
|
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`.
|
NOTE(Jeroen): This prints the Windows product edition only, to be called from `print_platform_details`.
|
||||||
*/
|
*/
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
void report_windows_product_type(DWORD ProductType) {
|
gb_internal void report_windows_product_type(DWORD ProductType) {
|
||||||
switch (ProductType) {
|
switch (ProductType) {
|
||||||
case PRODUCT_ULTIMATE:
|
case PRODUCT_ULTIMATE:
|
||||||
gb_printf("Ultimate");
|
gb_printf("Ultimate");
|
||||||
@@ -154,7 +154,7 @@ void report_windows_product_type(DWORD ProductType) {
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void odin_cpuid(int leaf, int result[]) {
|
gb_internal void odin_cpuid(int leaf, int result[]) {
|
||||||
#if defined(GB_CPU_ARM)
|
#if defined(GB_CPU_ARM)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@@ -169,7 +169,7 @@ void odin_cpuid(int leaf, int result[]) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_cpu_info() {
|
gb_internal void report_cpu_info() {
|
||||||
gb_printf("\tCPU: ");
|
gb_printf("\tCPU: ");
|
||||||
|
|
||||||
#if defined(GB_CPU_X86)
|
#if defined(GB_CPU_X86)
|
||||||
@@ -220,7 +220,7 @@ void report_cpu_info() {
|
|||||||
/*
|
/*
|
||||||
Report the amount of installed RAM.
|
Report the amount of installed RAM.
|
||||||
*/
|
*/
|
||||||
void report_ram_info() {
|
gb_internal void report_ram_info() {
|
||||||
gb_printf("\tRAM: ");
|
gb_printf("\tRAM: ");
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
@@ -271,7 +271,7 @@ void report_ram_info() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void report_os_info() {
|
gb_internal void report_os_info() {
|
||||||
gb_printf("\tOS: ");
|
gb_printf("\tOS: ");
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#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.
|
// 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("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("\tWebsite: https://odin-lang.org\n");
|
||||||
gb_printf("\tGitHub: https://github.com/odin-lang/Odin/issues\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(""),
|
||||||
str_lit("windows"),
|
str_lit("windows"),
|
||||||
str_lit("darwin"),
|
str_lit("darwin"),
|
||||||
@@ -72,7 +72,7 @@ String target_os_names[TargetOs_COUNT] = {
|
|||||||
str_lit("freestanding"),
|
str_lit("freestanding"),
|
||||||
};
|
};
|
||||||
|
|
||||||
String target_arch_names[TargetArch_COUNT] = {
|
gb_global String target_arch_names[TargetArch_COUNT] = {
|
||||||
str_lit(""),
|
str_lit(""),
|
||||||
str_lit("amd64"),
|
str_lit("amd64"),
|
||||||
str_lit("i386"),
|
str_lit("i386"),
|
||||||
@@ -82,19 +82,19 @@ String target_arch_names[TargetArch_COUNT] = {
|
|||||||
str_lit("wasm64"),
|
str_lit("wasm64"),
|
||||||
};
|
};
|
||||||
|
|
||||||
String target_endian_names[TargetEndian_COUNT] = {
|
gb_global String target_endian_names[TargetEndian_COUNT] = {
|
||||||
str_lit(""),
|
str_lit(""),
|
||||||
str_lit("little"),
|
str_lit("little"),
|
||||||
str_lit("big"),
|
str_lit("big"),
|
||||||
};
|
};
|
||||||
|
|
||||||
String target_abi_names[TargetABI_COUNT] = {
|
gb_global String target_abi_names[TargetABI_COUNT] = {
|
||||||
str_lit(""),
|
str_lit(""),
|
||||||
str_lit("win64"),
|
str_lit("win64"),
|
||||||
str_lit("sysv"),
|
str_lit("sysv"),
|
||||||
};
|
};
|
||||||
|
|
||||||
TargetEndianKind target_endians[TargetArch_COUNT] = {
|
gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
|
||||||
TargetEndian_Invalid,
|
TargetEndian_Invalid,
|
||||||
TargetEndian_Little,
|
TargetEndian_Little,
|
||||||
TargetEndian_Little,
|
TargetEndian_Little,
|
||||||
@@ -107,7 +107,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = {
|
|||||||
#define ODIN_VERSION_RAW "dev-unknown-unknown"
|
#define ODIN_VERSION_RAW "dev-unknown-unknown"
|
||||||
#endif
|
#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_run = 1<<0,
|
||||||
Command_build = 1<<1,
|
Command_build = 1<<1,
|
||||||
Command_check = 1<<3,
|
Command_check = 1<<3,
|
||||||
Command_query = 1<<4,
|
|
||||||
Command_doc = 1<<5,
|
Command_doc = 1<<5,
|
||||||
Command_version = 1<<6,
|
Command_version = 1<<6,
|
||||||
Command_test = 1<<7,
|
Command_test = 1<<7,
|
||||||
@@ -157,16 +156,15 @@ enum CommandKind : u32 {
|
|||||||
Command_strip_semicolon = 1<<8,
|
Command_strip_semicolon = 1<<8,
|
||||||
Command_bug_report = 1<<9,
|
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__does_build = Command_run|Command_build|Command_test,
|
||||||
Command_all = ~(u32)0,
|
Command_all = ~(u32)0,
|
||||||
};
|
};
|
||||||
|
|
||||||
char const *odin_command_strings[32] = {
|
gb_global char const *odin_command_strings[32] = {
|
||||||
"run",
|
"run",
|
||||||
"build",
|
"build",
|
||||||
"check",
|
"check",
|
||||||
"query",
|
|
||||||
"doc",
|
"doc",
|
||||||
"version",
|
"version",
|
||||||
"test",
|
"test",
|
||||||
@@ -293,13 +291,14 @@ struct BuildContext {
|
|||||||
bool show_error_line;
|
bool show_error_line;
|
||||||
|
|
||||||
bool ignore_lazy;
|
bool ignore_lazy;
|
||||||
|
bool ignore_llvm_build;
|
||||||
|
|
||||||
bool use_subsystem_windows;
|
bool use_subsystem_windows;
|
||||||
bool ignore_microsoft_magic;
|
bool ignore_microsoft_magic;
|
||||||
bool linker_map_file;
|
bool linker_map_file;
|
||||||
|
|
||||||
bool use_separate_modules;
|
bool use_separate_modules;
|
||||||
bool threaded_checker;
|
bool no_threaded_checker;
|
||||||
|
|
||||||
bool show_debug_messages;
|
bool show_debug_messages;
|
||||||
|
|
||||||
@@ -316,8 +315,6 @@ struct BuildContext {
|
|||||||
u32 cmd_doc_flags;
|
u32 cmd_doc_flags;
|
||||||
Array<String> extra_packages;
|
Array<String> extra_packages;
|
||||||
|
|
||||||
QueryDataSetSettings query_data_set_settings;
|
|
||||||
|
|
||||||
StringSet test_names;
|
StringSet test_names;
|
||||||
|
|
||||||
gbAffinity affinity;
|
gbAffinity affinity;
|
||||||
@@ -333,10 +330,15 @@ struct BuildContext {
|
|||||||
|
|
||||||
gb_global BuildContext build_context = {0};
|
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;
|
return build_context.warnings_as_errors;
|
||||||
}
|
}
|
||||||
bool global_ignore_warnings(void) {
|
gb_internal bool global_ignore_warnings(void) {
|
||||||
return build_context.ignore_warnings;
|
return build_context.ignore_warnings;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -398,7 +400,7 @@ gb_global TargetMetrics target_darwin_arm64 = {
|
|||||||
TargetArch_arm64,
|
TargetArch_arm64,
|
||||||
8, 8, 16,
|
8, 8, 16,
|
||||||
str_lit("arm64-apple-macosx11.0.0"),
|
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 = {
|
gb_global TargetMetrics target_freebsd_i386 = {
|
||||||
@@ -502,9 +504,9 @@ gb_global NamedTargetMetrics named_targets[] = {
|
|||||||
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
|
{ 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++) {
|
for (isize i = 0; i < TargetOs_COUNT; i++) {
|
||||||
if (str_eq_ignore_case(target_os_names[i], str)) {
|
if (str_eq_ignore_case(target_os_names[i], str)) {
|
||||||
return cast(TargetOsKind)i;
|
return cast(TargetOsKind)i;
|
||||||
@@ -513,7 +515,7 @@ TargetOsKind get_target_os_from_string(String str) {
|
|||||||
return TargetOs_Invalid;
|
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++) {
|
for (isize i = 0; i < TargetArch_COUNT; i++) {
|
||||||
if (str_eq_ignore_case(target_arch_names[i], str)) {
|
if (str_eq_ignore_case(target_arch_names[i], str)) {
|
||||||
return cast(TargetArchKind)i;
|
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;
|
String original_name = name;
|
||||||
name = remove_extension_from_path(name);
|
name = remove_extension_from_path(name);
|
||||||
|
|
||||||
@@ -588,23 +590,22 @@ struct LibraryCollections {
|
|||||||
|
|
||||||
gb_global Array<LibraryCollections> library_collections = {0};
|
gb_global Array<LibraryCollections> library_collections = {0};
|
||||||
|
|
||||||
void add_library_collection(String name, String path) {
|
gb_internal void add_library_collection(String name, String path) {
|
||||||
// TODO(bill): Check the path is valid and a directory
|
|
||||||
LibraryCollections lc = {name, string_trim_whitespace(path)};
|
LibraryCollections lc = {name, string_trim_whitespace(path)};
|
||||||
array_add(&library_collections, lc);
|
array_add(&library_collections, lc);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool find_library_collection_path(String name, String *path) {
|
gb_internal bool find_library_collection_path(String name, String *path) {
|
||||||
for_array(i, library_collections) {
|
for (auto const &lc : library_collections) {
|
||||||
if (library_collections[i].name == name) {
|
if (lc.name == name) {
|
||||||
if (path) *path = library_collections[i].path;
|
if (path) *path = lc.path;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_arch_wasm(void) {
|
gb_internal bool is_arch_wasm(void) {
|
||||||
switch (build_context.metrics.arch) {
|
switch (build_context.metrics.arch) {
|
||||||
case TargetArch_wasm32:
|
case TargetArch_wasm32:
|
||||||
case TargetArch_wasm64:
|
case TargetArch_wasm64:
|
||||||
@@ -613,7 +614,7 @@ bool is_arch_wasm(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_arch_x86(void) {
|
gb_internal bool is_arch_x86(void) {
|
||||||
switch (build_context.metrics.arch) {
|
switch (build_context.metrics.arch) {
|
||||||
case TargetArch_i386:
|
case TargetArch_i386:
|
||||||
case TargetArch_amd64:
|
case TargetArch_amd64:
|
||||||
@@ -622,7 +623,7 @@ bool is_arch_x86(void) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool allow_check_foreign_filepath(void) {
|
gb_internal bool allow_check_foreign_filepath(void) {
|
||||||
switch (build_context.metrics.arch) {
|
switch (build_context.metrics.arch) {
|
||||||
case TargetArch_wasm32:
|
case TargetArch_wasm32:
|
||||||
case TargetArch_wasm64:
|
case TargetArch_wasm64:
|
||||||
@@ -638,13 +639,14 @@ bool allow_check_foreign_filepath(void) {
|
|||||||
// is_abs_path
|
// is_abs_path
|
||||||
// has_subdir
|
// has_subdir
|
||||||
|
|
||||||
String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
|
gb_global String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
|
||||||
String const NIX_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);
|
gb_internal String internal_odin_root_dir(void);
|
||||||
String odin_root_dir(void) {
|
|
||||||
|
gb_internal String odin_root_dir(void) {
|
||||||
if (global_module_path_set) {
|
if (global_module_path_set) {
|
||||||
return global_module_path;
|
return global_module_path;
|
||||||
}
|
}
|
||||||
@@ -670,7 +672,7 @@ String odin_root_dir(void) {
|
|||||||
|
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
String internal_odin_root_dir(void) {
|
gb_internal String internal_odin_root_dir(void) {
|
||||||
String path = global_module_path;
|
String path = global_module_path;
|
||||||
isize len, i;
|
isize len, i;
|
||||||
wchar_t *text;
|
wchar_t *text;
|
||||||
@@ -723,9 +725,9 @@ String internal_odin_root_dir(void) {
|
|||||||
|
|
||||||
#include <mach-o/dyld.h>
|
#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;
|
String path = global_module_path;
|
||||||
isize len, i;
|
isize len, i;
|
||||||
u8 *text;
|
u8 *text;
|
||||||
@@ -777,9 +779,9 @@ String internal_odin_root_dir(void) {
|
|||||||
// NOTE: Linux / Unix is unfinished and not tested very well.
|
// NOTE: Linux / Unix is unfinished and not tested very well.
|
||||||
#include <sys/stat.h>
|
#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;
|
String path = global_module_path;
|
||||||
isize len, i;
|
isize len, i;
|
||||||
u8 *text;
|
u8 *text;
|
||||||
@@ -938,18 +940,22 @@ String internal_odin_root_dir(void) {
|
|||||||
gb_global BlockingMutex fullpath_mutex;
|
gb_global BlockingMutex fullpath_mutex;
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#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 = {};
|
String result = {};
|
||||||
mutex_lock(&fullpath_mutex);
|
|
||||||
defer (mutex_unlock(&fullpath_mutex));
|
|
||||||
|
|
||||||
String16 string16 = string_to_string16(heap_allocator(), s);
|
String16 string16 = string_to_string16(heap_allocator(), s);
|
||||||
defer (gb_free(heap_allocator(), string16.text));
|
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) {
|
if (len != 0) {
|
||||||
wchar_t *text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
|
wchar_t *text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
|
||||||
GetFullPathNameW(&string16[0], len, text, nullptr);
|
GetFullPathNameW(&string16[0], len, text, nullptr);
|
||||||
|
mutex_unlock(&fullpath_mutex);
|
||||||
|
|
||||||
text[len] = 0;
|
text[len] = 0;
|
||||||
result = string16_to_string(a, make_string16(text, len));
|
result = string16_to_string(a, make_string16(text, len));
|
||||||
result = string_trim_whitespace(result);
|
result = string_trim_whitespace(result);
|
||||||
@@ -960,12 +966,14 @@ String path_to_fullpath(gbAllocator a, String s) {
|
|||||||
result.text[i] = '/';
|
result.text[i] = '/';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
mutex_unlock(&fullpath_mutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
|
#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;
|
char *p;
|
||||||
mutex_lock(&fullpath_mutex);
|
mutex_lock(&fullpath_mutex);
|
||||||
p = realpath(cast(char *)s.text, 0);
|
p = realpath(cast(char *)s.text, 0);
|
||||||
@@ -978,7 +986,7 @@ String path_to_fullpath(gbAllocator a, String s) {
|
|||||||
#endif
|
#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);
|
u8 *str = gb_alloc_array(heap_allocator(), u8, base_dir.len+1+path.len+1);
|
||||||
defer (gb_free(heap_allocator(), str));
|
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 module_dir = odin_root_dir();
|
||||||
|
|
||||||
String core = str_lit("core/");
|
String core = str_lit("core/");
|
||||||
@@ -1024,11 +1032,11 @@ String get_fullpath_core(gbAllocator a, String path) {
|
|||||||
return path_to_fullpath(a, res);
|
return path_to_fullpath(a, res);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool show_error_line(void) {
|
gb_internal bool show_error_line(void) {
|
||||||
return build_context.show_error_line;
|
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);
|
String ext = path_extension(path);
|
||||||
if (ext == ".asm") {
|
if (ext == ".asm") {
|
||||||
return true;
|
return true;
|
||||||
@@ -1041,7 +1049,7 @@ bool has_asm_extension(String const &path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// temporary
|
// 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);
|
gbString s = gb_string_make_reserve(temporary_allocator(), 128);
|
||||||
String file = get_file_path_string(pos.file_id);
|
String file = get_file_path_string(pos.file_id);
|
||||||
switch (build_context.ODIN_ERROR_POS_STYLE) {
|
switch (build_context.ODIN_ERROR_POS_STYLE) {
|
||||||
@@ -1056,7 +1064,7 @@ char *token_pos_to_string(TokenPos const &pos) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_build_context(TargetMetrics *cross_target) {
|
gb_internal void init_build_context(TargetMetrics *cross_target) {
|
||||||
BuildContext *bc = &build_context;
|
BuildContext *bc = &build_context;
|
||||||
|
|
||||||
gb_affinity_init(&bc->affinity);
|
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->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_X64
|
||||||
#undef LINK_FLAG_386
|
#undef LINK_FLAG_386
|
||||||
@@ -1258,7 +1273,7 @@ void init_build_context(TargetMetrics *cross_target) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
Array<String> split_by_comma(String const &list) {
|
gb_internal Array<String> split_by_comma(String const &list) {
|
||||||
isize n = 1;
|
isize n = 1;
|
||||||
for (isize i = 0; i < list.len; i++) {
|
for (isize i = 0; i < list.len; i++) {
|
||||||
if (list.text[i] == ',') {
|
if (list.text[i] == ',') {
|
||||||
@@ -1280,20 +1295,19 @@ Array<String> split_by_comma(String const &list) {
|
|||||||
return res;
|
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
|
// TODO(bill): check_target_feature_is_valid
|
||||||
return true;
|
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;
|
BuildContext *bc = &build_context;
|
||||||
mutex_lock(&bc->target_features_mutex);
|
mutex_lock(&bc->target_features_mutex);
|
||||||
defer (mutex_unlock(&bc->target_features_mutex));
|
defer (mutex_unlock(&bc->target_features_mutex));
|
||||||
|
|
||||||
auto items = split_by_comma(target_feature_list);
|
auto items = split_by_comma(target_feature_list);
|
||||||
array_free(&items);
|
array_free(&items);
|
||||||
for_array(i, items) {
|
for (String const &item : items) {
|
||||||
String const &item = items.data[i];
|
|
||||||
if (!check_target_feature_is_valid(pos, item)) {
|
if (!check_target_feature_is_valid(pos, item)) {
|
||||||
error(pos, "Target feature '%.*s' is not valid", LIT(item));
|
error(pos, "Target feature '%.*s' is not valid", LIT(item));
|
||||||
return false;
|
return false;
|
||||||
@@ -1307,14 +1321,13 @@ bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_
|
|||||||
return true;
|
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;
|
BuildContext *bc = &build_context;
|
||||||
mutex_lock(&bc->target_features_mutex);
|
mutex_lock(&bc->target_features_mutex);
|
||||||
defer (mutex_unlock(&bc->target_features_mutex));
|
defer (mutex_unlock(&bc->target_features_mutex));
|
||||||
|
|
||||||
auto items = split_by_comma(target_feature_list);
|
auto items = split_by_comma(target_feature_list);
|
||||||
for_array(i, items) {
|
for (String const &item : items) {
|
||||||
String const &item = items.data[i];
|
|
||||||
if (!check_target_feature_is_valid(pos, item)) {
|
if (!check_target_feature_is_valid(pos, item)) {
|
||||||
error(pos, "Target feature '%.*s' is not valid", LIT(item));
|
error(pos, "Target feature '%.*s' is not valid", LIT(item));
|
||||||
continue;
|
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;
|
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) {
|
if (i != 0) {
|
||||||
len += 1;
|
len += 1;
|
||||||
}
|
}
|
||||||
String feature = build_context.target_features_set.entries[i].value;
|
|
||||||
len += feature.len;
|
len += feature.len;
|
||||||
if (with_quotes) len += 2;
|
if (with_quotes) len += 2;
|
||||||
|
i += 1;
|
||||||
}
|
}
|
||||||
char *features = gb_alloc_array(allocator, char, len+1);
|
char *features = gb_alloc_array(allocator, char, len+1);
|
||||||
len = 0;
|
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) {
|
if (i != 0) {
|
||||||
features[len++] = ',';
|
features[len++] = ',';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (with_quotes) 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);
|
gb_memmove(features + len, feature.text, feature.len);
|
||||||
len += feature.len;
|
len += feature.len;
|
||||||
if (with_quotes) features[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.
|
// 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.
|
// 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();
|
gbAllocator ha = heap_allocator();
|
||||||
BuildContext *bc = &build_context;
|
BuildContext *bc = &build_context;
|
||||||
|
|
||||||
// NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index.
|
// 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);
|
array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT);
|
||||||
|
|
||||||
string_set_init(&bc->target_features_set, heap_allocator(), 1024);
|
string_set_init(&bc->target_features_set, 1024);
|
||||||
mutex_init(&bc->target_features_mutex);
|
|
||||||
|
|
||||||
// [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path.
|
// [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);
|
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)) {
|
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.
|
// 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();
|
Find_Result find_result = find_visual_studio_and_windows_sdk();
|
||||||
defer (mc_free_all());
|
|
||||||
|
|
||||||
if (find_result.windows_sdk_version == 0) {
|
if (find_result.windows_sdk_version == 0) {
|
||||||
gb_printf_err("Windows SDK not found.\n");
|
gb_printf_err("Windows SDK not found.\n");
|
||||||
@@ -1534,6 +1546,25 @@ bool init_build_paths(String init_filename) {
|
|||||||
output_name = copy_string(ha, string_trim_whitespace(output_name));
|
output_name = copy_string(ha, string_trim_whitespace(output_name));
|
||||||
output_path = path_from_string(ha, 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.
|
// Replace extension.
|
||||||
if (output_path.ext.len > 0) {
|
if (output_path.ext.len > 0) {
|
||||||
gb_free(ha, output_path.ext.text);
|
gb_free(ha, output_path.ext.text);
|
||||||
|
|||||||
+67
-43
@@ -1,6 +1,6 @@
|
|||||||
typedef bool (BuiltinTypeIsProc)(Type *t);
|
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
|
nullptr, // BuiltinProc__type_simple_boolean_begin
|
||||||
|
|
||||||
is_type_boolean,
|
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) {
|
if (right_type == nullptr) {
|
||||||
return;
|
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 *left_type = nullptr;
|
||||||
Type *right_type = nullptr;
|
Type *right_type = nullptr;
|
||||||
if (x->type->kind == Type_Tuple) {
|
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) {
|
gb_internal void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
|
||||||
// TODO(bill): better error message
|
|
||||||
gbString t = type_to_string(x.type);
|
gbString t = type_to_string(x.type);
|
||||||
error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t);
|
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))) {
|
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;
|
gbString th = nullptr;
|
||||||
if (type_hint != nullptr) {
|
if (type_hint != nullptr) {
|
||||||
GB_ASSERT(bsrc->kind == Type_Union);
|
GB_ASSERT(bsrc->kind == Type_Union);
|
||||||
for_array(i, bsrc->Union.variants) {
|
for (Type *vt : bsrc->Union.variants) {
|
||||||
Type *vt = bsrc->Union.variants[i];
|
|
||||||
if (are_types_identical(vt, type_hint)) {
|
if (are_types_identical(vt, type_hint)) {
|
||||||
th = type_to_string(type_hint);
|
th = type_to_string(type_hint);
|
||||||
break;
|
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 *left_type = nullptr;
|
||||||
Type *right_type = nullptr;
|
Type *right_type = nullptr;
|
||||||
if (x->type->kind == Type_Tuple) {
|
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) {
|
if (return_type == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -165,7 +163,7 @@ bool does_require_msgSend_stret(Type *return_type) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
ObjcMsgKind get_objc_proc_kind(Type *return_type) {
|
gb_internal ObjcMsgKind get_objc_proc_kind(Type *return_type) {
|
||||||
if (return_type == nullptr) {
|
if (return_type == nullptr) {
|
||||||
return ObjcMsg_normal;
|
return ObjcMsg_normal;
|
||||||
}
|
}
|
||||||
@@ -189,7 +187,7 @@ ObjcMsgKind get_objc_proc_kind(Type *return_type) {
|
|||||||
return ObjcMsg_normal;
|
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);
|
ObjcMsgKind kind = get_objc_proc_kind(return_type);
|
||||||
|
|
||||||
Scope *scope = create_scope(c->info, nullptr);
|
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);
|
auto variables = array_make<Entity *>(permanent_allocator(), 0, param_types.count);
|
||||||
|
|
||||||
for_array(i, param_types) {
|
for (Type *type : param_types) {
|
||||||
Type *type = param_types[i];
|
|
||||||
Entity *param = alloc_entity_param(scope, blank_token, type, false, true);
|
Entity *param = alloc_entity_param(scope, blank_token, type, false, true);
|
||||||
array_add(&variables, param);
|
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");
|
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 = {};
|
Operand op = {};
|
||||||
check_expr(c, &op, expr);
|
check_expr(c, &op, expr);
|
||||||
if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
|
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;
|
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;
|
String const &builtin_name = builtin_procs[id].name;
|
||||||
|
|
||||||
if (build_context.metrics.os != TargetOs_darwin) {
|
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 = {};
|
Operand x = {};
|
||||||
check_expr_with_type_hint(c, &x, expr, t_atomic_memory_order);
|
check_expr_with_type_hint(c, &x, expr, t_atomic_memory_order);
|
||||||
if (x.mode == Addressing_Invalid) {
|
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);
|
ast_node(ce, CallExpr, call);
|
||||||
|
|
||||||
String const &builtin_name = builtin_procs[id].name;
|
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;
|
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(ce, CallExpr, call);
|
||||||
ast_node(bd, BasicDirective, ce->proc);
|
ast_node(bd, BasicDirective, ce->proc);
|
||||||
String builtin_name = bd->name.string;
|
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->path = path;
|
||||||
new_cache->data = data;
|
new_cache->data = data;
|
||||||
new_cache->file_error = file_error;
|
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);
|
string_map_set(&c->info->load_file_cache, path, new_cache);
|
||||||
if (cache_) *cache_ = new_cache;
|
if (cache_) *cache_ = new_cache;
|
||||||
} else {
|
} 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);
|
TEMPORARY_ALLOCATOR_GUARD();
|
||||||
defer (gb_free(heap_allocator(), c_str));
|
char *c_str = alloc_cstring(temporary_allocator(), path);
|
||||||
|
|
||||||
gbFile f = {};
|
gbFile f = {};
|
||||||
if (cache == nullptr) {
|
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) {
|
if (type == t_invalid) {
|
||||||
return false;
|
return false;
|
||||||
} else if (is_type_string(type)) {
|
} else if (is_type_string(type)) {
|
||||||
@@ -1191,7 +1188,16 @@ bool is_valid_type_for_load(Type *type) {
|
|||||||
return false;
|
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(ce, CallExpr, call);
|
||||||
ast_node(bd, BasicDirective, ce->proc);
|
ast_node(bd, BasicDirective, ce->proc);
|
||||||
String name = bd->name.string;
|
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(ce, CallExpr, call);
|
||||||
ast_node(bd, BasicDirective, ce->proc);
|
ast_node(bd, BasicDirective, ce->proc);
|
||||||
String name = bd->name.string;
|
String name = bd->name.string;
|
||||||
@@ -1581,7 +1587,7 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast
|
|||||||
return true;
|
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);
|
ast_node(ce, CallExpr, call);
|
||||||
if (ce->inlining != ProcInlining_none) {
|
if (ce->inlining != ProcInlining_none) {
|
||||||
error(call, "Inlining operators are not allowed on built-in procedures");
|
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:
|
case BuiltinProc___entry_point:
|
||||||
operand->mode = Addressing_NoValue;
|
operand->mode = Addressing_NoValue;
|
||||||
operand->type = nullptr;
|
operand->type = nullptr;
|
||||||
mpmc_enqueue(&c->info->intrinsics_entry_point_usage, call);
|
mpsc_enqueue(&c->info->intrinsics_entry_point_usage, call);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BuiltinProc_DIRECTIVE:
|
case BuiltinProc_DIRECTIVE:
|
||||||
@@ -2559,7 +2565,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
if (is_type_struct(type)) {
|
if (is_type_struct(type)) {
|
||||||
isize variable_count = type->Struct.fields.count;
|
isize variable_count = type->Struct.fields.count;
|
||||||
slice_init(&tuple->Tuple.variables, a, variable_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);
|
gb_memmove_array(tuple->Tuple.variables.data, type->Struct.fields.data, variable_count);
|
||||||
} else if (is_type_array(type)) {
|
} else if (is_type_array(type)) {
|
||||||
isize variable_count = cast(isize)type->Array.count;
|
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: {
|
case BuiltinProc_soa_zip: {
|
||||||
|
TEMPORARY_ALLOCATOR_GUARD();
|
||||||
auto types = array_make<Type *>(temporary_allocator(), 0, ce->args.count);
|
auto types = array_make<Type *>(temporary_allocator(), 0, ce->args.count);
|
||||||
auto names = array_make<String>(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 first_is_field_value = (ce->args[0]->kind == Ast_FieldValue);
|
||||||
|
|
||||||
bool fail = false;
|
bool fail = false;
|
||||||
for_array(i, ce->args) {
|
for (Ast *arg : ce->args) {
|
||||||
Ast *arg = ce->args[i];
|
|
||||||
bool mix = false;
|
bool mix = false;
|
||||||
if (first_is_field_value) {
|
if (first_is_field_value) {
|
||||||
mix = arg->kind != Ast_FieldValue;
|
mix = arg->kind != Ast_FieldValue;
|
||||||
@@ -3087,11 +3093,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
StringSet name_set = {};
|
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 = {};
|
String name = {};
|
||||||
Ast *arg = ce->args[i];
|
|
||||||
if (arg->kind == Ast_FieldValue) {
|
if (arg->kind == Ast_FieldValue) {
|
||||||
Ast *ename = arg->FieldValue.field;
|
Ast *ename = arg->FieldValue.field;
|
||||||
if (!fail && ename->kind != Ast_Ident) {
|
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));
|
error(op.expr, "Field argument name '%.*s' already exists", LIT(name));
|
||||||
} else {
|
} else {
|
||||||
array_add(&types, arg_type->Slice.elem);
|
array_add(&types, arg_type->Slice.elem);
|
||||||
array_add(&names, name);
|
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));
|
error(ce->args[0], "Expected a constant string for '%.*s'", LIT(builtin_name));
|
||||||
} else if (operand->value.kind == ExactValue_String) {
|
} else if (operand->value.kind == ExactValue_String) {
|
||||||
String pkg_name = operand->value.value_string;
|
String pkg_name = operand->value.value_string;
|
||||||
// TODO(bill): probably should have this be a `StringMap` eventually
|
for (auto const &entry : c->info->packages) {
|
||||||
for_array(i, c->info->packages.entries) {
|
AstPackage *pkg = entry.value;
|
||||||
AstPackage *pkg = c->info->packages.entries[i].value;
|
|
||||||
if (pkg->name == pkg_name) {
|
if (pkg->name == pkg_name) {
|
||||||
value = true;
|
value = true;
|
||||||
break;
|
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);
|
mp_err err = mp_pack(rop, max_count, &written, MP_LSB_FIRST, size, endian, nails, &x.value.value_integer);
|
||||||
GB_ASSERT(err == MP_OKAY);
|
GB_ASSERT(err == MP_OKAY);
|
||||||
|
|
||||||
if (id == BuiltinProc_reverse_bits) {
|
if (id != BuiltinProc_reverse_bits) {
|
||||||
// TODO(bill): Should this even be allowed at compile time?
|
|
||||||
} else {
|
|
||||||
u64 v = 0;
|
u64 v = 0;
|
||||||
switch (id) {
|
switch (id) {
|
||||||
case BuiltinProc_count_ones:
|
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));
|
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (id == BuiltinProc_atomic_store && !check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Operand x = {};
|
Operand x = {};
|
||||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||||
check_assignment(c, &x, elem, builtin_name);
|
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));
|
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Operand x = {};
|
Operand x = {};
|
||||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||||
check_assignment(c, &x, elem, builtin_name);
|
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));
|
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (id == BuiltinProc_atomic_load && !check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
operand->type = elem;
|
operand->type = elem;
|
||||||
operand->mode = Addressing_Value;
|
operand->mode = Addressing_Value;
|
||||||
break;
|
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));
|
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
OdinAtomicMemoryOrder memory_order = {};
|
OdinAtomicMemoryOrder memory_order = {};
|
||||||
if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name, &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));
|
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Operand x = {};
|
Operand x = {};
|
||||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||||
check_assignment(c, &x, elem, builtin_name);
|
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));
|
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Operand x = {};
|
Operand x = {};
|
||||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
||||||
check_assignment(c, &x, elem, builtin_name);
|
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));
|
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Operand x = {};
|
Operand x = {};
|
||||||
Operand y = {};
|
Operand y = {};
|
||||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
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));
|
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
Operand x = {};
|
Operand x = {};
|
||||||
Operand y = {};
|
Operand y = {};
|
||||||
check_expr_with_type_hint(c, &x, ce->args[1], elem);
|
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;
|
bool is_variant = false;
|
||||||
|
|
||||||
for_array(i, u->Union.variants) {
|
for (Type *vt : u->Union.variants) {
|
||||||
Type *vt = u->Union.variants[i];
|
|
||||||
if (are_types_identical(v, vt)) {
|
if (are_types_identical(v, vt)) {
|
||||||
is_variant = true;
|
is_variant = true;
|
||||||
break;
|
break;
|
||||||
|
|||||||
+92
-87
@@ -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
|
// 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 ||
|
if (operand->mode == Addressing_Invalid ||
|
||||||
operand->type == t_invalid ||
|
operand->type == t_invalid ||
|
||||||
e->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);
|
gbString expr_str = expr_to_string(operand->expr);
|
||||||
|
|
||||||
// TODO(bill): is this a good enough error message?
|
// 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,
|
error(operand->expr,
|
||||||
"Cannot assign built-in procedure '%s' in %.*s",
|
"Cannot assign built-in procedure '%s' in %.*s",
|
||||||
expr_str,
|
expr_str,
|
||||||
@@ -46,7 +45,7 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
|
|||||||
if (operand->mode == Addressing_Type) {
|
if (operand->mode == Addressing_Type) {
|
||||||
if (e->type != nullptr && is_type_typeid(e->type)) {
|
if (e->type != nullptr && is_type_typeid(e->type)) {
|
||||||
add_type_info_type(ctx, operand->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;
|
return e->type;
|
||||||
} else {
|
} else {
|
||||||
gbString t = type_to_string(operand->type);
|
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;
|
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) {
|
if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
|
||||||
return;
|
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
|
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
|
||||||
// an extra allocation
|
// an extra allocation
|
||||||
|
TEMPORARY_ALLOCATOR_GUARD();
|
||||||
auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
|
auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
|
||||||
check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false);
|
check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false);
|
||||||
|
|
||||||
isize rhs_count = operands.count;
|
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);
|
isize max = gb_min(lhs_count, rhs_count);
|
||||||
for (isize i = 0; i < max; i++) {
|
for (isize i = 0; i < max; i++) {
|
||||||
Entity *e = lhs[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 ||
|
if (operand->mode == Addressing_Invalid ||
|
||||||
operand->type == t_invalid ||
|
operand->type == t_invalid ||
|
||||||
e->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 (;;) {
|
for (;;) {
|
||||||
if (node == nullptr) {
|
if (node == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
@@ -217,7 +210,7 @@ bool is_type_distinct(Ast *node) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast *remove_type_alias_clutter(Ast *node) {
|
gb_internal Ast *remove_type_alias_clutter(Ast *node) {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (node == nullptr) {
|
if (node == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
@@ -232,17 +225,7 @@ Ast *remove_type_alias_clutter(Ast *node) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
isize total_attribute_count(DeclInfo *decl) {
|
gb_internal Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named_type) {
|
||||||
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) {
|
|
||||||
// NOTE(bill, 2022-02-05): Stupid edge case for `distinct` declarations
|
// NOTE(bill, 2022-02-05): Stupid edge case for `distinct` declarations
|
||||||
//
|
//
|
||||||
// X :: enum {A, B, C}
|
// X :: enum {A, B, C}
|
||||||
@@ -288,7 +271,7 @@ Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named
|
|||||||
return et;
|
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);
|
GB_ASSERT(e->type == nullptr);
|
||||||
|
|
||||||
DeclInfo *decl = decl_info_of_entity(e);
|
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);
|
Type *t = base_type(e->type);
|
||||||
if (t->kind == Type_Enum) {
|
if (t->kind == Type_Enum) {
|
||||||
for_array(i, t->Enum.fields) {
|
for (Entity *f : t->Enum.fields) {
|
||||||
Entity *f = t->Enum.fields[i];
|
|
||||||
if (f->kind != Entity_Constant) {
|
if (f->kind != Entity_Constant) {
|
||||||
continue;
|
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
|
// 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
|
// e.g. file entity inserted into its package scope
|
||||||
String original_name = original_entity->token.string;
|
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) {
|
if (found_scope == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mutex_lock(&found_scope->mutex);
|
rw_mutex_lock(&found_scope->mutex);
|
||||||
defer (mutex_unlock(&found_scope->mutex));
|
defer (rw_mutex_unlock(&found_scope->mutex));
|
||||||
|
|
||||||
// IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the
|
// 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
|
// 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->type == nullptr);
|
||||||
GB_ASSERT(e->kind == Entity_Constant);
|
GB_ASSERT(e->kind == Entity_Constant);
|
||||||
init = unparen_expr(init);
|
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);
|
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);
|
x = core_type(x);
|
||||||
y = core_type(y);
|
y = core_type(y);
|
||||||
return (a(x) && a(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);
|
x = core_type(x);
|
||||||
y = core_type(y);
|
y = core_type(y);
|
||||||
if (a == b) {
|
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)));
|
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)) {
|
if (sig_compare(is_type_pointer, x, y)) {
|
||||||
return true;
|
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(a_->kind == Type_Proc);
|
||||||
GB_ASSERT(b_->kind == Type_Proc);
|
GB_ASSERT(b_->kind == Type_Proc);
|
||||||
TypeProc *a = &a_->Proc;
|
TypeProc *a = &a_->Proc;
|
||||||
@@ -704,7 +686,7 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
|
|||||||
return true;
|
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;
|
Ast *ident = nullptr;
|
||||||
Entity **foreign_library = nullptr;
|
Entity **foreign_library = nullptr;
|
||||||
|
|
||||||
@@ -747,7 +729,7 @@ Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
|
|||||||
return nullptr;
|
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_prefix.len > 0) {
|
||||||
if (link_name.len > 0) {
|
if (link_name.len > 0) {
|
||||||
error(token, "'link_name' and 'link_prefix' cannot be used together");
|
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;
|
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);
|
GB_ASSERT(e->type == nullptr);
|
||||||
if (d->proc_lit->kind != Ast_ProcLit) {
|
if (d->proc_lit->kind != Ast_ProcLit) {
|
||||||
// TOOD(bill): Better error message
|
// 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);
|
GB_ASSERT(pl->body->kind == Ast_BlockStmt);
|
||||||
if (!pt->is_polymorphic) {
|
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) {
|
} else if (!is_foreign) {
|
||||||
if (e->Procedure.is_export) {
|
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) {
|
if (ac.deferred_procedure.entity != nullptr) {
|
||||||
e->Procedure.deferred_procedure = ac.deferred_procedure;
|
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) {
|
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->type == nullptr);
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
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) {
|
if (ac.require_declaration) {
|
||||||
e->flags |= EntityFlag_Require;
|
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");
|
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);
|
GB_ASSERT(pg_entity->kind == Entity_ProcGroup);
|
||||||
auto *pge = &pg_entity->ProcGroup;
|
auto *pge = &pg_entity->ProcGroup;
|
||||||
String proc_group_name = pg_entity->token.string;
|
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;
|
pg_entity->type = t_invalid;
|
||||||
|
|
||||||
PtrSet<Entity *> entity_set = {};
|
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) {
|
for (Ast *arg : pg->args) {
|
||||||
Ast *arg = pg->args[i];
|
|
||||||
Entity *e = nullptr;
|
Entity *e = nullptr;
|
||||||
Operand o = {};
|
Operand o = {};
|
||||||
if (arg->kind == Ast_Ident) {
|
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);
|
ptr_set_destroy(&entity_set);
|
||||||
|
|
||||||
for_array(j, pge->entities) {
|
for (isize j = 0; j < pge->entities.count; j++) {
|
||||||
Entity *p = pge->entities[j];
|
Entity *p = pge->entities[j];
|
||||||
if (p->type == t_invalid) {
|
if (p->type == t_invalid) {
|
||||||
// NOTE(bill): This invalid overload has already been handled
|
// 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) {
|
if (e->state == EntityState_Resolved) {
|
||||||
return;
|
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 {
|
struct ProcUsingVar {
|
||||||
Entity *e;
|
Entity *e;
|
||||||
Entity *uvar;
|
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) {
|
if (body == nullptr) {
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
GB_ASSERT(body->kind == Ast_BlockStmt);
|
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) {
|
if (type->Proc.param_count > 0) {
|
||||||
TypeTuple *params = &type->Proc.params->Tuple;
|
TypeTuple *params = &type->Proc.params->Tuple;
|
||||||
for_array(i, params->variables) {
|
for (Entity *e : params->variables) {
|
||||||
Entity *e = params->variables[i];
|
|
||||||
if (e->kind != Entity_Variable) {
|
if (e->kind != Entity_Variable) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -1499,8 +1510,9 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
|
|||||||
if (t->kind == Type_Struct) {
|
if (t->kind == Type_Struct) {
|
||||||
Scope *scope = t->Struct.scope;
|
Scope *scope = t->Struct.scope;
|
||||||
GB_ASSERT(scope != nullptr);
|
GB_ASSERT(scope != nullptr);
|
||||||
MUTEX_GUARD_BLOCK(scope->mutex) for_array(i, scope->elements.entries) {
|
rw_mutex_lock(&scope->mutex);
|
||||||
Entity *f = scope->elements.entries[i].value;
|
for (auto const &entry : scope->elements) {
|
||||||
|
Entity *f = entry.value;
|
||||||
if (f->kind == Entity_Variable) {
|
if (f->kind == Entity_Variable) {
|
||||||
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
|
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
|
||||||
if (is_value) uvar->flags |= EntityFlag_Value;
|
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);
|
array_add(&using_entities, puv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
rw_mutex_unlock(&scope->mutex);
|
||||||
} else {
|
} else {
|
||||||
error(e->token, "'using' can only be applied to variables of type struct");
|
error(e->token, "'using' can only be applied to variables of type struct");
|
||||||
break;
|
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) {
|
rw_mutex_lock(&ctx->scope->mutex);
|
||||||
Entity *e = using_entities[i].e;
|
for (auto const &entry : using_entities) {
|
||||||
Entity *uvar = using_entities[i].uvar;
|
Entity *e = entry.e;
|
||||||
Entity *prev = scope_insert(ctx->scope, uvar, false);
|
Entity *uvar = entry.uvar;
|
||||||
|
Entity *prev = scope_insert_no_mutex(ctx->scope, uvar);
|
||||||
if (prev != nullptr) {
|
if (prev != nullptr) {
|
||||||
error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
|
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));
|
error_line("%.*s != %.*s\n", LIT(uvar->token.string), LIT(prev->token.string));
|
||||||
break;
|
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);
|
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) {
|
if (!where_clause_ok) {
|
||||||
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
|
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
|
||||||
return;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
check_open_scope(ctx, body);
|
check_open_scope(ctx, body);
|
||||||
{
|
{
|
||||||
for_array(i, using_entities) {
|
for (auto const &entry : using_entities) {
|
||||||
Entity *uvar = using_entities[i].uvar;
|
Entity *uvar = entry.uvar;
|
||||||
Entity *prev = scope_insert(ctx->scope, uvar);
|
Entity *prev = scope_insert(ctx->scope, uvar);
|
||||||
gb_unused(prev);
|
gb_unused(prev);
|
||||||
// NOTE(bill): Don't err here
|
// 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);
|
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
|
||||||
|
|
||||||
for_array(i, bs->stmts) {
|
decl->defer_use_checked = true;
|
||||||
Ast *stmt = bs->stmts[i];
|
|
||||||
|
for (Ast *stmt : bs->stmts) {
|
||||||
if (stmt->kind == Ast_ValueDecl) {
|
if (stmt->kind == Ast_ValueDecl) {
|
||||||
ast_node(vd, ValueDecl, stmt);
|
ast_node(vd, ValueDecl, stmt);
|
||||||
for_array(j, vd->names) {
|
for (Ast *name : vd->names) {
|
||||||
Ast *name = vd->names[j];
|
|
||||||
if (!is_blank_ident(name)) {
|
if (!is_blank_ident(name)) {
|
||||||
if (name->kind == Ast_Ident) {
|
if (name->kind == Ast_Ident) {
|
||||||
GB_ASSERT(name->Ident.entity != nullptr);
|
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_close_scope(ctx);
|
||||||
|
|
||||||
check_scope_usage(ctx->checker, ctx->scope);
|
check_scope_usage(ctx->checker, ctx->scope);
|
||||||
|
|
||||||
if (decl->parent != nullptr) {
|
add_deps_from_child_to_parent(decl);
|
||||||
Scope *ps = decl->parent->scope;
|
|
||||||
if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
|
|
||||||
return;
|
|
||||||
} else {
|
|
||||||
mutex_lock(&ctx->info->deps_mutex);
|
|
||||||
|
|
||||||
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
|
return true;
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
+403
-401
File diff suppressed because it is too large
Load Diff
+579
-567
File diff suppressed because it is too large
Load Diff
+100
-88
@@ -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);
|
t = base_type(t);
|
||||||
GB_ASSERT(t->kind == Type_Array);
|
GB_ASSERT(t->kind == Type_Array);
|
||||||
Entity *e = scope_lookup_current(ctx->scope, name);
|
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) {
|
if (t == nullptr) {
|
||||||
return;
|
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);
|
t = base_type(t);
|
||||||
if (is_type_struct(t)) {
|
if (is_type_struct(t)) {
|
||||||
return true;
|
return true;
|
||||||
@@ -91,7 +91,7 @@ bool does_field_type_allow_using(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields, String **tags, Slice<Ast *> const ¶ms,
|
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) {
|
isize init_field_capacity, Type *struct_type, String context) {
|
||||||
auto fields_array = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
|
auto fields_array = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
|
||||||
auto tags_array = array_make<String>(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);
|
GB_ASSERT(align_ != nullptr);
|
||||||
Operand o = {};
|
Operand o = {};
|
||||||
check_expr(ctx, &o, node);
|
check_expr(ctx, &o, node);
|
||||||
@@ -256,18 +256,36 @@ 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) {
|
gb_internal 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);
|
rw_mutex_shared_lock(&ctx->info->gen_types_mutex); // @@global
|
||||||
defer (mutex_unlock(&ctx->info->gen_types_mutex));
|
|
||||||
|
|
||||||
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
|
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
|
||||||
if (found_gen_types != nullptr) {
|
if (found_gen_types == nullptr) {
|
||||||
// GB_ASSERT_MSG(ordered_operands.count >= param_count, "%td >= %td", ordered_operands.count, param_count);
|
rw_mutex_shared_unlock(&ctx->info->gen_types_mutex); // @@global
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
for_array(i, *found_gen_types) {
|
rw_mutex_shared_lock(&found_gen_types->mutex); // @@local
|
||||||
Entity *e = (*found_gen_types)[i];
|
defer (rw_mutex_shared_unlock(&found_gen_types->mutex)); // @@local
|
||||||
|
|
||||||
|
rw_mutex_shared_unlock(&ctx->info->gen_types_mutex); // @@global
|
||||||
|
|
||||||
|
for (Entity *e : found_gen_types->types) {
|
||||||
Type *t = base_type(e->type);
|
Type *t = base_type(e->type);
|
||||||
TypeTuple *tuple = get_record_polymorphic_params(t);
|
TypeTuple *tuple = nullptr;
|
||||||
|
switch (t->kind) {
|
||||||
|
case Type_Struct:
|
||||||
|
if (t->Struct.polymorphic_params) {
|
||||||
|
tuple = &t->Struct.polymorphic_params->Tuple;
|
||||||
|
}
|
||||||
|
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);
|
GB_ASSERT(param_count == tuple->variables.count);
|
||||||
|
|
||||||
bool skip = false;
|
bool skip = false;
|
||||||
@@ -315,12 +333,11 @@ Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type,
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
return nullptr;
|
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));
|
GB_ASSERT(is_type_named(named_type));
|
||||||
gbAllocator a = heap_allocator();
|
gbAllocator a = heap_allocator();
|
||||||
Scope *s = ctx->scope->parent;
|
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?
|
// TODO(bill): Is this even correct? Or should the metadata be copied?
|
||||||
e->TypeName.objc_metadata = original_type->Named.type_name->TypeName.objc_metadata;
|
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);
|
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
|
||||||
if (found_gen_types) {
|
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 {
|
} else {
|
||||||
auto array = array_make<Entity *>(heap_allocator());
|
GenTypesData gen_types = {};
|
||||||
array_add(&array, e);
|
gen_types.types = array_make<Entity *>(heap_allocator());
|
||||||
map_set(&ctx->info->gen_types, original_type, array);
|
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,
|
gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params,
|
||||||
bool *is_polymorphic_,
|
bool *is_polymorphic_,
|
||||||
Ast *node, Array<Operand> *poly_operands,
|
Ast *node, Array<Operand> *poly_operands) {
|
||||||
Type *named_type, Type *original_type_for_poly) {
|
|
||||||
Type *polymorphic_params_type = nullptr;
|
Type *polymorphic_params_type = nullptr;
|
||||||
bool can_check_fields = true;
|
bool can_check_fields = true;
|
||||||
GB_ASSERT(is_polymorphic_ != nullptr);
|
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_) {
|
if (!*is_polymorphic_) {
|
||||||
*is_polymorphic_ = polymorphic_params != nullptr && poly_operands == nullptr;
|
*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;
|
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) {
|
if (poly_operands == nullptr) {
|
||||||
return false;
|
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));
|
GB_ASSERT(is_type_struct(struct_type));
|
||||||
ast_node(st, StructType, node);
|
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(
|
struct_type->Struct.polymorphic_params = check_record_polymorphic_params(
|
||||||
ctx, st->polymorphic_params,
|
ctx, st->polymorphic_params,
|
||||||
&struct_type->Struct.is_polymorphic,
|
&struct_type->Struct.is_polymorphic,
|
||||||
node, poly_operands,
|
node, poly_operands
|
||||||
named_type, original_type_for_poly
|
);
|
||||||
);;
|
|
||||||
struct_type->Struct.is_poly_specialized = check_record_poly_operand_specialization(ctx, struct_type, poly_operands, &struct_type->Struct.is_polymorphic);
|
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 (!struct_type->Struct.is_polymorphic) {
|
||||||
if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
|
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));
|
GB_ASSERT(is_type_union(union_type));
|
||||||
ast_node(ut, UnionType, node);
|
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(
|
union_type->Union.polymorphic_params = check_record_polymorphic_params(
|
||||||
ctx, ut->polymorphic_params,
|
ctx, ut->polymorphic_params,
|
||||||
&union_type->Union.is_polymorphic,
|
&union_type->Union.is_polymorphic,
|
||||||
node, poly_operands,
|
node, poly_operands
|
||||||
named_type, original_type_for_poly
|
|
||||||
);
|
);
|
||||||
union_type->Union.is_poly_specialized = check_record_poly_operand_specialization(ctx, union_type, poly_operands, &union_type->Union.is_polymorphic);
|
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 (!union_type->Union.is_polymorphic) {
|
||||||
if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
|
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);
|
ast_node(et, EnumType, node);
|
||||||
GB_ASSERT(is_type_enum(enum_type));
|
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;
|
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)) {
|
if (is_type_integer(t)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -861,7 +881,7 @@ bool is_type_valid_bit_set_range(Type *t) {
|
|||||||
return false;
|
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);
|
ast_node(bs, BitSetType, node);
|
||||||
GB_ASSERT(type->kind == Type_BitSet);
|
GB_ASSERT(type->kind == Type_BitSet);
|
||||||
type->BitSet.node = node;
|
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 ||
|
if (type == nullptr ||
|
||||||
type == t_invalid) {
|
type == t_invalid) {
|
||||||
return true;
|
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 modify_type = !ctx->no_polymorphic_errors;
|
||||||
bool show_error = modify_type && !ctx->hide_polymorphic_errors;
|
bool show_error = modify_type && !ctx->hide_polymorphic_errors;
|
||||||
if (!is_operand_value(operand)) {
|
if (!is_operand_value(operand)) {
|
||||||
@@ -1256,7 +1276,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper
|
|||||||
return t_invalid;
|
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) {
|
if (expr == nullptr) {
|
||||||
return false;
|
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 = {};
|
ParameterValue param_value = {};
|
||||||
param_value.original_ast_expr = expr;
|
param_value.original_ast_expr = expr;
|
||||||
if (expr == nullptr) {
|
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) {
|
if (_params == nullptr) {
|
||||||
return 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) {
|
if (p->flags&FieldFlag_const) {
|
||||||
error(name, "'#const' can only be applied to variable fields");
|
error(name, "'#const' can only be applied to variable fields");
|
||||||
p->flags &= ~FieldFlag_const;
|
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) {
|
} else if (!ctx->no_polymorphic_errors) {
|
||||||
// NOTE(bill): The type should be determined now and thus, no need to determine the type any more
|
// NOTE(bill): The type should be determined now and thus, no need to determine the type any more
|
||||||
is_type_polymorphic_type = false;
|
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) {
|
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)) {
|
if (type != t_invalid && !check_is_assignable_to(ctx, &op, type)) {
|
||||||
bool ok = true;
|
bool ok = true;
|
||||||
if (p->flags&FieldFlag_auto_cast) {
|
if (p->flags&FieldFlag_any_int) {
|
||||||
if (!check_is_castable_to(ctx, &op, type)) {
|
|
||||||
ok = false;
|
|
||||||
}
|
|
||||||
} else 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))) {
|
if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) {
|
||||||
ok = false;
|
ok = false;
|
||||||
} else if (!check_is_castable_to(ctx, &op, type)) {
|
} 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");
|
error(name, "'#no_alias' can only be applied to non constant values");
|
||||||
p->flags &= ~FieldFlag_no_alias; // Remove the flag
|
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) {
|
if (p->flags&FieldFlag_any_int) {
|
||||||
error(name, "'#any_int' can only be applied to variable fields");
|
error(name, "'#any_int' can only be applied to variable fields");
|
||||||
p->flags &= ~FieldFlag_any_int;
|
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) {
|
if (p->flags&FieldFlag_no_alias) {
|
||||||
param->flags |= EntityFlag_NoAlias;
|
param->flags |= EntityFlag_NoAlias;
|
||||||
}
|
}
|
||||||
if (p->flags&FieldFlag_auto_cast) {
|
|
||||||
param->flags |= EntityFlag_AutoCast;
|
|
||||||
}
|
|
||||||
if (p->flags&FieldFlag_any_int) {
|
if (p->flags&FieldFlag_any_int) {
|
||||||
if (!is_type_integer(param->type) && !is_type_enum(param->type)) {
|
if (!is_type_integer(param->type) && !is_type_enum(param->type)) {
|
||||||
gbString str = type_to_string(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;
|
isize specialization_count = 0;
|
||||||
if (scope != nullptr) {
|
if (scope != nullptr) {
|
||||||
for_array(i, scope->elements.entries) {
|
for (auto const &entry : scope->elements) {
|
||||||
Entity *e = scope->elements.entries[i].value;
|
Entity *e = entry.value;
|
||||||
if (e->kind == Entity_TypeName) {
|
if (e->kind == Entity_TypeName) {
|
||||||
Type *t = e->type;
|
Type *t = e->type;
|
||||||
if (t->kind == Type_Generic &&
|
if (t->kind == Type_Generic &&
|
||||||
@@ -1814,7 +1825,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
|
|||||||
return tuple;
|
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) {
|
if (_results == nullptr) {
|
||||||
return 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
|
// 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);
|
ast_node(pt, ProcType, proc_type_node);
|
||||||
|
|
||||||
if (ctx->polymorphic_scope == nullptr && ctx->allow_polymorphic_types) {
|
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) {
|
if (e == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -2169,7 +2180,7 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
|
|||||||
return 0;
|
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();
|
gbAllocator a = permanent_allocator();
|
||||||
Type *t = alloc_type_tuple();
|
Type *t = alloc_type_tuple();
|
||||||
slice_init(&t->Tuple.variables, a, 2);
|
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
|
// IMPORTANT NOTE(bill): This must match the definition in dynamic_map_internal.odin
|
||||||
enum : i64 {
|
enum : i64 {
|
||||||
MAP_CACHE_LINE_LOG2 = 6,
|
MAP_CELL_CACHE_LINE_LOG2 = 6,
|
||||||
MAP_CACHE_LINE_SIZE = 1 << MAP_CACHE_LINE_LOG2
|
MAP_CELL_CACHE_LINE_SIZE = 1 << MAP_CELL_CACHE_LINE_LOG2,
|
||||||
};
|
};
|
||||||
GB_STATIC_ASSERT(MAP_CACHE_LINE_SIZE >= 64);
|
GB_STATIC_ASSERT(MAP_CELL_CACHE_LINE_SIZE >= 64);
|
||||||
void map_cell_size_and_len(Type *type, i64 *size_, i64 *len_) {
|
gb_internal void map_cell_size_and_len(Type *type, i64 *size_, i64 *len_) {
|
||||||
i64 elem_sz = type_size_of(type);
|
i64 elem_sz = type_size_of(type);
|
||||||
|
|
||||||
i64 len = 1;
|
i64 len = 1;
|
||||||
if (0 < elem_sz && elem_sz < MAP_CACHE_LINE_SIZE) {
|
if (0 < elem_sz && elem_sz < MAP_CELL_CACHE_LINE_SIZE) {
|
||||||
len = MAP_CACHE_LINE_SIZE / elem_sz;
|
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 (size_) *size_ = size;
|
||||||
if (len_) *len_ = len;
|
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(type->kind == Type_Map);
|
||||||
GB_ASSERT(t_allocator != nullptr);
|
GB_ASSERT(t_allocator != nullptr);
|
||||||
if (type->Map.lookup_result_type != nullptr) return;
|
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);
|
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);
|
key = core_type(key);
|
||||||
|
|
||||||
if (is_type_cstring(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);
|
GB_ASSERT(type->kind == Type_Map);
|
||||||
ast_node(mt, MapType, node);
|
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");
|
// 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);
|
ast_node(mt, MatrixType, node);
|
||||||
|
|
||||||
Operand row = {};
|
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);
|
Type *bt_elem = base_type(elem);
|
||||||
|
|
||||||
bool is_polymorphic = is_type_polymorphic(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;
|
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;
|
soa_struct->Struct.scope = scope;
|
||||||
|
|
||||||
String params_xyzw[4] = {
|
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);
|
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);
|
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);
|
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);
|
GB_ASSERT_NOT_NULL(type);
|
||||||
if (e == nullptr) {
|
if (e == nullptr) {
|
||||||
*type = t_invalid;
|
*type = t_invalid;
|
||||||
@@ -2997,7 +3009,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *check_type(CheckerContext *ctx, Ast *e) {
|
gb_internal Type *check_type(CheckerContext *ctx, Ast *e) {
|
||||||
CheckerContext c = *ctx;
|
CheckerContext c = *ctx;
|
||||||
c.type_path = new_checker_type_path();
|
c.type_path = new_checker_type_path();
|
||||||
defer (destroy_checker_type_path(c.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);
|
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;
|
Type *type = nullptr;
|
||||||
bool ok = check_type_internal(ctx, e, &type, named_type);
|
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
|
#endif
|
||||||
|
|
||||||
if (is_type_typed(type)) {
|
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 {
|
} else {
|
||||||
gbString name = type_to_string(type);
|
gbString name = type_to_string(type);
|
||||||
error(e, "Invalid type definition of %s", name);
|
error(e, "Invalid type definition of %s", name);
|
||||||
|
|||||||
+765
-773
File diff suppressed because it is too large
Load Diff
+103
-86
@@ -20,7 +20,7 @@ struct ExprInfo {
|
|||||||
ExactValue value;
|
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);
|
ExprInfo *ei = gb_alloc_item(permanent_allocator(), ExprInfo);
|
||||||
ei->mode = mode;
|
ei->mode = mode;
|
||||||
ei->type = type;
|
ei->type = type;
|
||||||
@@ -130,7 +130,7 @@ struct AttributeContext {
|
|||||||
String enable_target_feature; // will be enabled for the procedure only
|
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 = {};
|
AttributeContext ac = {};
|
||||||
ac.link_prefix = link_prefix;
|
ac.link_prefix = link_prefix;
|
||||||
return ac;
|
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)
|
#define DECL_ATTRIBUTE_PROC(_name) bool _name(CheckerContext *c, Ast *elem, String name, Ast *value, AttributeContext *ac)
|
||||||
typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
|
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
|
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
|
||||||
struct DeclInfo {
|
struct DeclInfo {
|
||||||
DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment
|
DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment
|
||||||
|
|
||||||
|
BlockingMutex next_mutex;
|
||||||
|
DeclInfo * next_child;
|
||||||
|
DeclInfo * next_sibling;
|
||||||
|
|
||||||
Scope * scope;
|
Scope * scope;
|
||||||
|
|
||||||
Entity *entity;
|
Entity *entity;
|
||||||
@@ -157,13 +176,22 @@ struct DeclInfo {
|
|||||||
Type * gen_proc_type; // Precalculated
|
Type * gen_proc_type; // Precalculated
|
||||||
bool is_using;
|
bool is_using;
|
||||||
bool where_clauses_evaluated;
|
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 *comment;
|
||||||
CommentGroup *docs;
|
CommentGroup *docs;
|
||||||
|
|
||||||
|
RwMutex deps_mutex;
|
||||||
PtrSet<Entity *> deps;
|
PtrSet<Entity *> deps;
|
||||||
|
|
||||||
|
RwMutex type_info_deps_mutex;
|
||||||
PtrSet<Type *> type_info_deps;
|
PtrSet<Type *> type_info_deps;
|
||||||
|
|
||||||
|
BlockingMutex type_and_value_mutex;
|
||||||
|
|
||||||
Array<BlockLabel> labels;
|
Array<BlockLabel> labels;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -195,7 +223,7 @@ enum ScopeFlag : i32 {
|
|||||||
ScopeFlag_ContextDefined = 1<<16,
|
ScopeFlag_ContextDefined = 1<<16,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { DEFAULT_SCOPE_CAPACITY = 29 };
|
enum { DEFAULT_SCOPE_CAPACITY = 32 };
|
||||||
|
|
||||||
struct Scope {
|
struct Scope {
|
||||||
Ast * node;
|
Ast * node;
|
||||||
@@ -203,7 +231,7 @@ struct Scope {
|
|||||||
std::atomic<Scope *> next;
|
std::atomic<Scope *> next;
|
||||||
std::atomic<Scope *> head_child;
|
std::atomic<Scope *> head_child;
|
||||||
|
|
||||||
BlockingMutex mutex;
|
RwMutex mutex;
|
||||||
StringMap<Entity *> elements;
|
StringMap<Entity *> elements;
|
||||||
PtrSet<Scope *> imported;
|
PtrSet<Scope *> imported;
|
||||||
|
|
||||||
@@ -275,7 +303,6 @@ struct UntypedExprInfo {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef PtrMap<Ast *, ExprInfo *> UntypedExprInfoMap;
|
typedef PtrMap<Ast *, ExprInfo *> UntypedExprInfoMap;
|
||||||
typedef MPMCQueue<ProcInfo *> ProcBodyQueue;
|
|
||||||
|
|
||||||
enum ObjcMsgKind : u32 {
|
enum ObjcMsgKind : u32 {
|
||||||
ObjcMsg_normal,
|
ObjcMsg_normal,
|
||||||
@@ -294,6 +321,16 @@ struct LoadFileCache {
|
|||||||
StringMap<u64> hashes;
|
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
|
// CheckerInfo stores all the symbol information for a type-checked program
|
||||||
struct CheckerInfo {
|
struct CheckerInfo {
|
||||||
Checker *checker;
|
Checker *checker;
|
||||||
@@ -308,7 +345,7 @@ struct CheckerInfo {
|
|||||||
Scope * init_scope;
|
Scope * init_scope;
|
||||||
Entity * entry_point;
|
Entity * entry_point;
|
||||||
PtrSet<Entity *> minimum_dependency_set;
|
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
|
// Below are accessed within procedures
|
||||||
// NOTE(bill): If the semantic checker (check_proc_body) is to ever to be multithreaded,
|
RwMutex global_untyped_mutex;
|
||||||
// these variables will be of contention
|
|
||||||
|
|
||||||
Semaphore collect_semaphore;
|
|
||||||
|
|
||||||
UntypedExprInfoMap global_untyped; // NOTE(bill): This needs to be a map and not on the Ast
|
UntypedExprInfoMap global_untyped; // NOTE(bill): This needs to be a map and not on the Ast
|
||||||
// as it needs to be iterated across afterwards
|
// as it needs to be iterated across afterwards
|
||||||
BlockingMutex global_untyped_mutex;
|
|
||||||
BlockingMutex builtin_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;
|
BlockingMutex type_and_value_mutex;
|
||||||
|
|
||||||
RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files
|
RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files
|
||||||
|
|
||||||
RecursiveMutex gen_procs_mutex;
|
RwMutex gen_types_mutex;
|
||||||
RecursiveMutex gen_types_mutex;
|
PtrMap<Type *, GenTypesData > gen_types;
|
||||||
PtrMap<Ast *, Array<Entity *> > gen_procs; // Key: Ast * | Identifier -> Entity
|
|
||||||
PtrMap<Type *, Array<Entity *> > gen_types;
|
|
||||||
|
|
||||||
BlockingMutex type_info_mutex; // NOT recursive
|
BlockingMutex type_info_mutex; // NOT recursive
|
||||||
Array<Type *> type_info_types;
|
Array<Type *> type_info_types;
|
||||||
@@ -353,37 +377,39 @@ struct CheckerInfo {
|
|||||||
BlockingMutex foreign_mutex; // NOT recursive
|
BlockingMutex foreign_mutex; // NOT recursive
|
||||||
StringMap<Entity *> foreigns;
|
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
|
// NOTE(bill): These are actually MPSC queues
|
||||||
// TODO(bill): Convert them to be MPSC queues
|
// TODO(bill): Convert them to be MPSC queues
|
||||||
MPMCQueue<Entity *> definition_queue;
|
MPSCQueue<Entity *> definition_queue;
|
||||||
MPMCQueue<Entity *> entity_queue;
|
MPSCQueue<Entity *> entity_queue;
|
||||||
MPMCQueue<Entity *> required_global_variable_queue;
|
MPSCQueue<Entity *> required_global_variable_queue;
|
||||||
MPMCQueue<Entity *> required_foreign_imports_through_force_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;
|
BlockingMutex objc_types_mutex;
|
||||||
PtrMap<Ast *, ObjcMsgData> objc_msgSend_types;
|
PtrMap<Ast *, ObjcMsgData> objc_msgSend_types;
|
||||||
|
|
||||||
BlockingMutex load_file_mutex;
|
BlockingMutex load_file_mutex;
|
||||||
StringMap<LoadFileCache *> load_file_cache;
|
StringMap<LoadFileCache *> load_file_cache;
|
||||||
|
|
||||||
|
BlockingMutex all_procedures_mutex;
|
||||||
|
Array<ProcInfo *> all_procedures;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct CheckerContext {
|
struct CheckerContext {
|
||||||
|
// Order matters here
|
||||||
|
BlockingMutex mutex;
|
||||||
Checker * checker;
|
Checker * checker;
|
||||||
CheckerInfo * info;
|
CheckerInfo * info;
|
||||||
|
|
||||||
AstPackage * pkg;
|
AstPackage * pkg;
|
||||||
AstFile * file;
|
AstFile * file;
|
||||||
Scope * scope;
|
Scope * scope;
|
||||||
DeclInfo * decl;
|
DeclInfo * decl;
|
||||||
|
|
||||||
|
// Order doesn't matter after this
|
||||||
u32 state_flags;
|
u32 state_flags;
|
||||||
bool in_defer; // TODO(bill): Actually handle correctly
|
bool in_defer;
|
||||||
Type * type_hint;
|
Type * type_hint;
|
||||||
|
|
||||||
String proc_name;
|
String proc_name;
|
||||||
@@ -394,9 +420,7 @@ struct CheckerContext {
|
|||||||
ForeignContext foreign_context;
|
ForeignContext foreign_context;
|
||||||
|
|
||||||
CheckerTypePath *type_path;
|
CheckerTypePath *type_path;
|
||||||
isize type_level; // TODO(bill): Actually handle correctly
|
isize type_level;
|
||||||
CheckerPolyPath *poly_path;
|
|
||||||
isize poly_level; // TODO(bill): Actually handle correctly
|
|
||||||
|
|
||||||
UntypedExprInfoMap *untyped;
|
UntypedExprInfoMap *untyped;
|
||||||
|
|
||||||
@@ -413,8 +437,6 @@ struct CheckerContext {
|
|||||||
Scope * polymorphic_scope;
|
Scope * polymorphic_scope;
|
||||||
|
|
||||||
Ast *assignment_lhs_hint;
|
Ast *assignment_lhs_hint;
|
||||||
|
|
||||||
ProcBodyQueue *procs_to_check_queue;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -424,13 +446,14 @@ struct Checker {
|
|||||||
|
|
||||||
CheckerContext builtin_ctx;
|
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;
|
BlockingMutex nested_proc_lits_mutex;
|
||||||
Semaphore procs_to_check_semaphore;
|
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
|
// CheckerInfo API
|
||||||
TypeAndValue type_and_value_of_expr (Ast *expr);
|
gb_internal TypeAndValue type_and_value_of_expr (Ast *expr);
|
||||||
Type * type_of_expr (Ast *expr);
|
gb_internal Type * type_of_expr (Ast *expr);
|
||||||
Entity * implicit_entity_of_node(Ast *clause);
|
gb_internal Entity * implicit_entity_of_node(Ast *clause);
|
||||||
DeclInfo * decl_info_of_ident (Ast *ident);
|
gb_internal DeclInfo * decl_info_of_ident (Ast *ident);
|
||||||
DeclInfo * decl_info_of_entity (Entity * e);
|
gb_internal DeclInfo * decl_info_of_entity (Entity * e);
|
||||||
AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
|
gb_internal AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
|
||||||
// IMPORTANT: Only to use once checking is done
|
// 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
|
// 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);
|
gb_internal Entity *scope_lookup_current(Scope *s, String const &name);
|
||||||
Entity *scope_lookup (Scope *s, String const &name);
|
gb_internal Entity *scope_lookup (Scope *s, String const &name);
|
||||||
void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_);
|
gb_internal 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_insert (Scope *s, Entity *entity);
|
||||||
|
|
||||||
|
|
||||||
void add_type_and_value (CheckerInfo *i, Ast *expression, AddressingMode mode, Type *type, ExactValue value);
|
gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue value);
|
||||||
ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr);
|
gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr);
|
||||||
void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue value);
|
gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue value);
|
||||||
void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity);
|
gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity);
|
||||||
void add_implicit_entity (CheckerContext *c, Ast *node, Entity *e);
|
gb_internal 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);
|
gb_internal 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_info_type (CheckerContext *c, Type *t);
|
||||||
|
|
||||||
void check_add_import_decl(CheckerContext *c, Ast *decl);
|
gb_internal void check_add_import_decl(CheckerContext *c, Ast *decl);
|
||||||
void check_add_foreign_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);
|
gb_internal 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);
|
gb_internal 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_type_decl(CheckerContext *c, Entity *e, Ast *type_expr, Type *def);
|
||||||
|
|
||||||
bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global = false);
|
gb_internal bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global = false);
|
||||||
void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes);
|
gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes);
|
||||||
void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
|
gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
|
||||||
void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
|
gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
|
||||||
|
|
||||||
CheckerTypePath *new_checker_type_path();
|
gb_internal CheckerTypePath *new_checker_type_path();
|
||||||
void destroy_checker_type_path(CheckerTypePath *tp);
|
gb_internal void destroy_checker_type_path(CheckerTypePath *tp);
|
||||||
|
|
||||||
void check_type_path_push(CheckerContext *c, Entity *e);
|
gb_internal void check_type_path_push(CheckerContext *c, Entity *e);
|
||||||
Entity *check_type_path_pop (CheckerContext *c);
|
gb_internal Entity *check_type_path_pop (CheckerContext *c);
|
||||||
|
|
||||||
CheckerPolyPath *new_checker_poly_path();
|
gb_internal void init_core_context(Checker *c);
|
||||||
void destroy_checker_poly_path(CheckerPolyPath *);
|
gb_internal void init_mem_allocator(Checker *c);
|
||||||
|
|
||||||
void check_poly_path_push(CheckerContext *c, Type *t);
|
gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped);
|
||||||
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);
|
|
||||||
|
|||||||
+73
-49
@@ -29,36 +29,51 @@
|
|||||||
#include <string.h>
|
#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)
|
#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);
|
gb_internal i32 next_pow2(i32 n);
|
||||||
i64 next_pow2(i64 n);
|
gb_internal i64 next_pow2(i64 n);
|
||||||
isize next_pow2_isize(isize n);
|
gb_internal isize next_pow2_isize(isize n);
|
||||||
void debugf(char const *fmt, ...);
|
gb_internal void debugf(char const *fmt, ...);
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS) && defined(GB_ARCH_32_BIT)
|
#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
|
#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
|
#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 "unicode.cpp"
|
||||||
#include "array.cpp"
|
#include "array.cpp"
|
||||||
#include "queue.cpp"
|
#include "threading.cpp"
|
||||||
#include "common_memory.cpp"
|
#include "common_memory.cpp"
|
||||||
|
#include "queue.cpp"
|
||||||
#include "string.cpp"
|
#include "string.cpp"
|
||||||
#include "range_cache.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) {
|
if (x <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return !(x & (x-1));
|
return !(x & (x-1));
|
||||||
}
|
}
|
||||||
|
|
||||||
int isize_cmp(isize x, isize y) {
|
gb_internal int isize_cmp(isize x, isize y) {
|
||||||
if (x < y) {
|
if (x < y) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (x > y) {
|
} else if (x > y) {
|
||||||
@@ -66,7 +81,7 @@ int isize_cmp(isize x, isize y) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int u64_cmp(u64 x, u64 y) {
|
gb_internal int u64_cmp(u64 x, u64 y) {
|
||||||
if (x < y) {
|
if (x < y) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (x > y) {
|
} else if (x > y) {
|
||||||
@@ -74,7 +89,7 @@ int u64_cmp(u64 x, u64 y) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int i64_cmp(i64 x, i64 y) {
|
gb_internal int i64_cmp(i64 x, i64 y) {
|
||||||
if (x < y) {
|
if (x < y) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (x > y) {
|
} else if (x > y) {
|
||||||
@@ -82,7 +97,7 @@ int i64_cmp(i64 x, i64 y) {
|
|||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
int i32_cmp(i32 x, i32 y) {
|
gb_internal int i32_cmp(i32 x, i32 y) {
|
||||||
if (x < y) {
|
if (x < y) {
|
||||||
return -1;
|
return -1;
|
||||||
} else if (x > y) {
|
} else if (x > y) {
|
||||||
@@ -91,7 +106,7 @@ int i32_cmp(i32 x, i32 y) {
|
|||||||
return 0;
|
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;
|
u8 const *bytes = cast(u8 const *)data;
|
||||||
u32 h = 0x811c9dc5;
|
u32 h = 0x811c9dc5;
|
||||||
|
|
||||||
@@ -112,7 +127,7 @@ u32 fnv32a(void const *data, isize len) {
|
|||||||
return h;
|
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;
|
u8 const *bytes = cast(u8 const *)data;
|
||||||
u64 h = 0xcbf29ce484222325ull;
|
u64 h = 0xcbf29ce484222325ull;
|
||||||
|
|
||||||
@@ -133,7 +148,7 @@ u64 fnv64a(void const *data, isize len) {
|
|||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 u64_digit_value(Rune r) {
|
gb_internal u64 u64_digit_value(Rune r) {
|
||||||
switch (r) {
|
switch (r) {
|
||||||
case '0': return 0;
|
case '0': return 0;
|
||||||
case '1': return 1;
|
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;
|
u64 base = 10;
|
||||||
bool has_prefix = false;
|
bool has_prefix = false;
|
||||||
if (string.len > 2 && string[0] == '0') {
|
if (string.len > 2 && string[0] == '0') {
|
||||||
@@ -205,7 +220,7 @@ gb_global char const global_num_to_char_table[] =
|
|||||||
"abcdefghijklmnopqrstuvwxyz"
|
"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};
|
char buf[32] = {0};
|
||||||
isize i = gb_size_of(buf);
|
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);
|
gb_memmove(out_buf, &buf[i], len);
|
||||||
return make_string(cast(u8 *)out_buf, 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};
|
char buf[32] = {0};
|
||||||
isize i = gb_size_of(buf);
|
isize i = gb_size_of(buf);
|
||||||
bool negative = false;
|
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;
|
*result = x + y;
|
||||||
return *result < x || *result < 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;
|
*result = x - y;
|
||||||
return *result > x;
|
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)
|
#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT)
|
||||||
*lo = _umul128(x, y, hi);
|
*lo = _umul128(x, y, hi);
|
||||||
#else
|
#else
|
||||||
@@ -342,7 +357,7 @@ struct StringIntern {
|
|||||||
PtrMap<uintptr, StringIntern *> string_intern_map = {}; // Key: u64
|
PtrMap<uintptr, StringIntern *> string_intern_map = {}; // Key: u64
|
||||||
gb_global Arena string_intern_arena = {};
|
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);
|
u64 hash = gb_fnv64a(text, len);
|
||||||
uintptr key = cast(uintptr)(hash ? hash : 1);
|
uintptr key = cast(uintptr)(hash ? hash : 1);
|
||||||
StringIntern **found = map_get(&string_intern_map, key);
|
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;
|
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);
|
return string_intern(cast(char const *)string.text, string.len);
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_string_interner(void) {
|
gb_internal void init_string_interner(void) {
|
||||||
map_init(&string_intern_map, heap_allocator());
|
map_init(&string_intern_map);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
i32 next_pow2(i32 n) {
|
gb_internal i32 next_pow2(i32 n) {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -387,7 +402,7 @@ i32 next_pow2(i32 n) {
|
|||||||
n++;
|
n++;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
i64 next_pow2(i64 n) {
|
gb_internal i64 next_pow2(i64 n) {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -401,7 +416,7 @@ i64 next_pow2(i64 n) {
|
|||||||
n++;
|
n++;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
isize next_pow2_isize(isize n) {
|
gb_internal isize next_pow2_isize(isize n) {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -417,7 +432,7 @@ isize next_pow2_isize(isize n) {
|
|||||||
n++;
|
n++;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
u32 next_pow2_u32(u32 n) {
|
gb_internal u32 next_pow2_u32(u32 n) {
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
return 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 >> 1) & 0x55555555);
|
||||||
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
|
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
|
||||||
x = (((x >> 4) + x) & 0x0f0f0f0f);
|
x = (((x >> 4) + x) & 0x0f0f0f0f);
|
||||||
@@ -442,13 +457,13 @@ i32 bit_set_count(u32 x) {
|
|||||||
return cast(i32)(x & 0x0000003f);
|
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 a = *(cast(u32 *)&x);
|
||||||
u32 b = *(cast(u32 *)&x + 1);
|
u32 b = *(cast(u32 *)&x + 1);
|
||||||
return bit_set_count(a) + bit_set_count(b);
|
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 >> 1;
|
||||||
x |= x >> 2;
|
x |= x >> 2;
|
||||||
x |= x >> 4;
|
x |= x >> 4;
|
||||||
@@ -457,7 +472,7 @@ u32 floor_log2(u32 x) {
|
|||||||
return cast(u32)(bit_set_count(x) - 1);
|
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 >> 1;
|
||||||
x |= x >> 2;
|
x |= x >> 2;
|
||||||
x |= x >> 4;
|
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));
|
i32 y = cast(i32)(x & (x-1));
|
||||||
y |= -y;
|
y |= -y;
|
||||||
y >>= 32-1;
|
y >>= 32-1;
|
||||||
@@ -480,7 +495,7 @@ u32 ceil_log2(u32 x) {
|
|||||||
return cast(u32)(bit_set_count(x) - 1 - y);
|
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));
|
i64 y = cast(i64)(x & (x-1));
|
||||||
y |= -y;
|
y |= -y;
|
||||||
y >>= 64-1;
|
y >>= 64-1;
|
||||||
@@ -493,7 +508,7 @@ u64 ceil_log2(u64 x) {
|
|||||||
return cast(u64)(bit_set_count(x) - 1 - y);
|
return cast(u64)(bit_set_count(x) - 1 - y);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 prev_pow2(u32 n) {
|
gb_internal u32 prev_pow2(u32 n) {
|
||||||
if (n == 0) {
|
if (n == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -504,7 +519,7 @@ u32 prev_pow2(u32 n) {
|
|||||||
n |= n >> 16;
|
n |= n >> 16;
|
||||||
return n - (n >> 1);
|
return n - (n >> 1);
|
||||||
}
|
}
|
||||||
i32 prev_pow2(i32 n) {
|
gb_internal i32 prev_pow2(i32 n) {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -515,7 +530,7 @@ i32 prev_pow2(i32 n) {
|
|||||||
n |= n >> 16;
|
n |= n >> 16;
|
||||||
return n - (n >> 1);
|
return n - (n >> 1);
|
||||||
}
|
}
|
||||||
i64 prev_pow2(i64 n) {
|
gb_internal i64 prev_pow2(i64 n) {
|
||||||
if (n <= 0) {
|
if (n <= 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -528,7 +543,7 @@ i64 prev_pow2(i64 n) {
|
|||||||
return n - (n >> 1);
|
return n - (n >> 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 f32_to_f16(f32 value) {
|
gb_internal u16 f32_to_f16(f32 value) {
|
||||||
union { u32 i; f32 f; } v;
|
union { u32 i; f32 f; } v;
|
||||||
i32 i, s, e, m;
|
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;
|
typedef union { u32 u; f32 f; } fp32;
|
||||||
fp32 v;
|
fp32 v;
|
||||||
|
|
||||||
@@ -595,7 +610,7 @@ f32 f16_to_f32(u16 value) {
|
|||||||
return v.f;
|
return v.f;
|
||||||
}
|
}
|
||||||
|
|
||||||
f64 gb_sqrt(f64 x) {
|
gb_internal gb_inline f64 gb_sqrt(f64 x) {
|
||||||
return sqrt(x);
|
return sqrt(x);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -623,7 +638,7 @@ f64 gb_sqrt(f64 x) {
|
|||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#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 i, j;
|
||||||
|
|
||||||
u32 len = cast(u32)string16_len(cmd_line);
|
u32 len = cast(u32)string16_len(cmd_line);
|
||||||
@@ -706,11 +721,13 @@ enum LoadedFileError {
|
|||||||
LoadedFile_COUNT,
|
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;
|
LoadedFileError err = LoadedFile_None;
|
||||||
|
|
||||||
if (!copy_file_contents) {
|
if (!copy_file_contents) {
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
TEMPORARY_ALLOCATOR_GUARD();
|
||||||
|
|
||||||
isize w_len = 0;
|
isize w_len = 0;
|
||||||
wchar_t *w_str = gb__alloc_utf8_to_ucs2(temporary_allocator(), fullpath, &w_len);
|
wchar_t *w_str = gb__alloc_utf8_to_ucs2(temporary_allocator(), fullpath, &w_len);
|
||||||
if (w_str == nullptr) {
|
if (w_str == nullptr) {
|
||||||
@@ -811,7 +828,9 @@ LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_fil
|
|||||||
|
|
||||||
#define USE_DAMERAU_LEVENSHTEIN 1
|
#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 w = b.len+1;
|
||||||
isize h = a.len+1;
|
isize h = a.len+1;
|
||||||
isize *matrix = gb_alloc_array(temporary_allocator(), isize, w*h);
|
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};
|
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 = {};
|
DidYouMeanAnswers d = {};
|
||||||
array_init(&d.distances, allocator, 0, cap);
|
array_init(&d.distances, allocator, 0, cap);
|
||||||
d.key = key;
|
d.key = key;
|
||||||
return d;
|
return d;
|
||||||
}
|
}
|
||||||
void did_you_mean_destroy(DidYouMeanAnswers *d) {
|
gb_internal void did_you_mean_destroy(DidYouMeanAnswers *d) {
|
||||||
array_free(&d->distances);
|
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 == "_") {
|
if (target.len == 0 || target == "_") {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -888,7 +907,7 @@ void did_you_mean_append(DidYouMeanAnswers *d, String const &target) {
|
|||||||
dat.distance = levenstein_distance_case_insensitive(d->key, target);
|
dat.distance = levenstein_distance_case_insensitive(d->key, target);
|
||||||
array_add(&d->distances, dat);
|
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)));
|
gb_sort_array(d->distances.data, d->distances.count, gb_isize_cmp(gb_offset_of(DistanceAndTarget, distance)));
|
||||||
isize count = 0;
|
isize count = 0;
|
||||||
for (isize i = 0; i < d->distances.count; i++) {
|
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);
|
return slice_array(d->distances, 0, count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
|
|||||||
+139
-66
@@ -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);
|
memset(ptr, 0, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -7,43 +7,31 @@ gb_inline void zero_size(void *ptr, isize len) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename U, typename V>
|
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>
|
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) {
|
gb_internal gb_inline i64 align_formula(i64 size, i64 align) {
|
||||||
if (align > 0) {
|
|
||||||
i64 result = size + align-1;
|
i64 result = size + align-1;
|
||||||
return result - result%align;
|
return result - (i64)((u64)result%(u64)align);
|
||||||
}
|
}
|
||||||
return size;
|
gb_internal gb_inline isize align_formula_isize(isize size, isize align) {
|
||||||
}
|
|
||||||
gb_inline isize align_formula_isize(isize size, isize align) {
|
|
||||||
if (align > 0) {
|
|
||||||
isize result = size + align-1;
|
isize result = size + align-1;
|
||||||
return result - result%align;
|
return result - (isize)((usize)result%(usize)align);
|
||||||
}
|
}
|
||||||
return size;
|
gb_internal gb_inline void *align_formula_ptr(void *ptr, isize align) {
|
||||||
}
|
|
||||||
gb_inline void *align_formula_ptr(void *ptr, isize align) {
|
|
||||||
if (align > 0) {
|
|
||||||
uintptr result = (cast(uintptr)ptr) + align-1;
|
uintptr result = (cast(uintptr)ptr) + align-1;
|
||||||
return (void *)(result - result%align);
|
return (void *)(result - result%align);
|
||||||
}
|
}
|
||||||
return ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
gb_global BlockingMutex global_memory_block_mutex;
|
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) {
|
gb_internal void virtual_memory_init(void) {
|
||||||
mutex_init(&global_memory_block_mutex);
|
|
||||||
mutex_init(&global_memory_allocator_mutex);
|
|
||||||
platform_virtual_memory_init();
|
platform_virtual_memory_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -59,20 +47,21 @@ struct MemoryBlock {
|
|||||||
struct Arena {
|
struct Arena {
|
||||||
MemoryBlock * curr_block;
|
MemoryBlock * curr_block;
|
||||||
isize minimum_block_size;
|
isize minimum_block_size;
|
||||||
bool ignore_mutex;
|
BlockingMutex mutex;
|
||||||
|
isize temp_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum { DEFAULT_MINIMUM_BLOCK_SIZE = 8ll*1024ll*1024ll };
|
enum { DEFAULT_MINIMUM_BLOCK_SIZE = 8ll*1024ll*1024ll };
|
||||||
|
|
||||||
gb_global isize DEFAULT_PAGE_SIZE = 4096;
|
gb_global isize DEFAULT_PAGE_SIZE = 4096;
|
||||||
|
|
||||||
MemoryBlock *virtual_memory_alloc(isize size);
|
gb_internal MemoryBlock *virtual_memory_alloc(isize size);
|
||||||
void virtual_memory_dealloc(MemoryBlock *block);
|
gb_internal void virtual_memory_dealloc(MemoryBlock *block);
|
||||||
void *arena_alloc(Arena *arena, isize min_size, isize alignment);
|
gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment);
|
||||||
void arena_free_all(Arena *arena);
|
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 alignment_offset = 0;
|
||||||
isize ptr = cast(isize)(arena->curr_block->base + arena->curr_block->used);
|
isize ptr = cast(isize)(arena->curr_block->base + arena->curr_block->used);
|
||||||
isize mask = alignment-1;
|
isize mask = alignment-1;
|
||||||
@@ -82,13 +71,10 @@ isize arena_align_forward_offset(Arena *arena, isize alignment) {
|
|||||||
return alignment_offset;
|
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));
|
GB_ASSERT(gb_is_power_of_two(alignment));
|
||||||
|
|
||||||
BlockingMutex *mutex = &global_memory_allocator_mutex;
|
mutex_lock(&arena->mutex);
|
||||||
if (!arena->ignore_mutex) {
|
|
||||||
mutex_lock(mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
isize size = 0;
|
isize size = 0;
|
||||||
if (arena->curr_block != nullptr) {
|
if (arena->curr_block != nullptr) {
|
||||||
@@ -115,15 +101,13 @@ void *arena_alloc(Arena *arena, isize min_size, isize alignment) {
|
|||||||
curr_block->used += size;
|
curr_block->used += size;
|
||||||
GB_ASSERT(curr_block->used <= curr_block->size);
|
GB_ASSERT(curr_block->used <= curr_block->size);
|
||||||
|
|
||||||
if (!arena->ignore_mutex) {
|
mutex_unlock(&arena->mutex);
|
||||||
mutex_unlock(mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// NOTE(bill): memory will be zeroed by default due to virtual memory
|
// NOTE(bill): memory will be zeroed by default due to virtual memory
|
||||||
return ptr;
|
return ptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void arena_free_all(Arena *arena) {
|
gb_internal void arena_free_all(Arena *arena) {
|
||||||
while (arena->curr_block != nullptr) {
|
while (arena->curr_block != nullptr) {
|
||||||
MemoryBlock *free_block = arena->curr_block;
|
MemoryBlock *free_block = arena->curr_block;
|
||||||
arena->curr_block = free_block->prev;
|
arena->curr_block = free_block->prev;
|
||||||
@@ -142,12 +126,12 @@ struct PlatformMemoryBlock {
|
|||||||
gb_global std::atomic<isize> global_platform_memory_total_usage;
|
gb_global std::atomic<isize> global_platform_memory_total_usage;
|
||||||
gb_global PlatformMemoryBlock global_platform_memory_block_sentinel;
|
gb_global PlatformMemoryBlock global_platform_memory_block_sentinel;
|
||||||
|
|
||||||
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size);
|
gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size);
|
||||||
void platform_virtual_memory_free(PlatformMemoryBlock *block);
|
gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block);
|
||||||
void platform_virtual_memory_protect(void *memory, isize size);
|
gb_internal void platform_virtual_memory_protect(void *memory, isize size);
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#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.prev = &global_platform_memory_block_sentinel;
|
||||||
global_platform_memory_block_sentinel.next = &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));
|
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);
|
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)VirtualAlloc(0, total_size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
|
||||||
if (pmblock == nullptr) {
|
if (pmblock == nullptr) {
|
||||||
gb_printf_err("Out of Virtual memory, oh no...\n");
|
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_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...");
|
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;
|
return pmblock;
|
||||||
}
|
}
|
||||||
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
||||||
global_platform_memory_total_usage -= block->total_size;
|
global_platform_memory_total_usage.fetch_sub(block->total_size);
|
||||||
GB_ASSERT(VirtualFree(block, 0, MEM_RELEASE));
|
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;
|
DWORD old_protect = 0;
|
||||||
BOOL is_protected = VirtualProtect(memory, size, PAGE_NOACCESS, &old_protect);
|
BOOL is_protected = VirtualProtect(memory, size, PAGE_NOACCESS, &old_protect);
|
||||||
GB_ASSERT(is_protected);
|
GB_ASSERT(is_protected);
|
||||||
}
|
}
|
||||||
#else
|
#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.prev = &global_platform_memory_block_sentinel;
|
||||||
global_platform_memory_block_sentinel.next = &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));
|
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);
|
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)mmap(nullptr, total_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
|
||||||
if (pmblock == nullptr) {
|
if (pmblock == nullptr) {
|
||||||
gb_printf_err("Out of Virtual memory, oh no...\n");
|
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;
|
global_platform_memory_total_usage += total_size;
|
||||||
return pmblock;
|
return pmblock;
|
||||||
}
|
}
|
||||||
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block) {
|
||||||
isize size = block->total_size;
|
isize size = block->total_size;
|
||||||
global_platform_memory_total_usage -= size;
|
global_platform_memory_total_usage -= size;
|
||||||
munmap(block, 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);
|
int err = mprotect(memory, size, PROT_NONE);
|
||||||
GB_ASSERT(err == 0);
|
GB_ASSERT(err == 0);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
MemoryBlock *virtual_memory_alloc(isize size) {
|
gb_internal MemoryBlock *virtual_memory_alloc(isize size) {
|
||||||
isize const page_size = DEFAULT_PAGE_SIZE;
|
isize const page_size = DEFAULT_PAGE_SIZE;
|
||||||
|
|
||||||
isize total_size = size + gb_size_of(PlatformMemoryBlock);
|
isize total_size = size + gb_size_of(PlatformMemoryBlock);
|
||||||
@@ -250,7 +234,7 @@ MemoryBlock *virtual_memory_alloc(isize size) {
|
|||||||
return &pmblock->block;
|
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;
|
PlatformMemoryBlock *block = cast(PlatformMemoryBlock *)block_to_free;
|
||||||
if (block != nullptr) {
|
if (block != nullptr) {
|
||||||
mutex_lock(&global_memory_block_mutex);
|
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;
|
gbAllocator a;
|
||||||
a.proc = arena_allocator_proc;
|
a.proc = arena_allocator_proc;
|
||||||
a.data = arena;
|
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;
|
void *ptr = nullptr;
|
||||||
Arena *arena = cast(Arena *)allocator_data;
|
Arena *arena = cast(Arena *)allocator_data;
|
||||||
GB_ASSERT_NOT_NULL(arena);
|
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};
|
gb_global gb_thread_local Arena permanent_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE};
|
||||||
gbAllocator permanent_allocator() {
|
gb_internal gbAllocator permanent_allocator() {
|
||||||
return arena_allocator(&permanent_arena);
|
return arena_allocator(&permanent_arena);
|
||||||
}
|
}
|
||||||
|
|
||||||
gbAllocator temporary_allocator() {
|
gb_global gb_thread_local Arena temporary_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE};
|
||||||
return permanent_allocator();
|
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) {
|
|
||||||
|
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;
|
gbAllocator a;
|
||||||
a.proc = heap_allocator_proc;
|
a.proc = heap_allocator_proc;
|
||||||
a.data = nullptr;
|
a.data = nullptr;
|
||||||
return a;
|
return a;
|
||||||
}
|
}
|
||||||
|
return arena_allocator(&heap_arena);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
||||||
void *ptr = nullptr;
|
void *ptr = nullptr;
|
||||||
gb_unused(allocator_data);
|
gb_unused(allocator_data);
|
||||||
gb_unused(old_size);
|
gb_unused(old_size);
|
||||||
@@ -460,21 +532,22 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(new_count >= 0);
|
||||||
if (new_count == 0) {
|
if (new_count == 0) {
|
||||||
gb_free(a, *array);
|
gb_free(a, *array);
|
||||||
*array = nullptr;
|
*array = nullptr;
|
||||||
return;
|
return 0;
|
||||||
}
|
}
|
||||||
if (new_count < old_count) {
|
if (new_count < old_count) {
|
||||||
return;
|
return old_count;
|
||||||
}
|
}
|
||||||
isize old_size = old_count * gb_size_of(T);
|
isize old_size = old_count * gb_size_of(T);
|
||||||
isize new_size = new_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);
|
auto new_data = cast(T *)gb_resize_align(a, *array, old_size, new_size, alignment);
|
||||||
GB_ASSERT(new_data != nullptr);
|
GB_ASSERT(new_data != nullptr);
|
||||||
*array = new_data;
|
*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(a != nullptr);
|
||||||
GB_ASSERT(b != nullptr);
|
GB_ASSERT(b != nullptr);
|
||||||
Entity *x = *cast(Entity **)a;
|
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 ox = print_entity_kind_ordering[x->kind];
|
||||||
int oy = print_entity_kind_ordering[y->kind];
|
int oy = print_entity_kind_ordering[y->kind];
|
||||||
res = ox - oy;
|
res = ox - oy;
|
||||||
if (res != 0) {
|
if (res == 0) {
|
||||||
return res;
|
|
||||||
}
|
|
||||||
res = string_compare(x->token.string, y->token.string);
|
res = string_compare(x->token.string, y->token.string);
|
||||||
|
}
|
||||||
return res;
|
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(a != nullptr);
|
||||||
GB_ASSERT(b != nullptr);
|
GB_ASSERT(b != nullptr);
|
||||||
AstPackage *x = *cast(AstPackage **)a;
|
AstPackage *x = *cast(AstPackage **)a;
|
||||||
@@ -67,7 +66,7 @@ GB_COMPARE_PROC(cmp_ast_package_by_name) {
|
|||||||
#include "docs_format.cpp"
|
#include "docs_format.cpp"
|
||||||
#include "docs_writer.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) {
|
while (indent --> 0) {
|
||||||
gb_printf("\t");
|
gb_printf("\t");
|
||||||
}
|
}
|
||||||
@@ -75,7 +74,7 @@ void print_doc_line(i32 indent, String const &data) {
|
|||||||
gb_printf("\n");
|
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) {
|
while (indent --> 0) {
|
||||||
gb_printf("\t");
|
gb_printf("\t");
|
||||||
}
|
}
|
||||||
@@ -85,16 +84,7 @@ void print_doc_line(i32 indent, char const *fmt, ...) {
|
|||||||
va_end(va);
|
va_end(va);
|
||||||
gb_printf("\n");
|
gb_printf("\n");
|
||||||
}
|
}
|
||||||
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
|
gb_internal void print_doc_line_no_newline(i32 indent, String const &data) {
|
||||||
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) {
|
|
||||||
while (indent --> 0) {
|
while (indent --> 0) {
|
||||||
gb_printf("\t");
|
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) {
|
if (g == nullptr) {
|
||||||
return false;
|
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;
|
gbString s = nullptr;
|
||||||
if (build_context.cmd_doc_flags & CmdDocFlag_Short) {
|
if (build_context.cmd_doc_flags & CmdDocFlag_Short) {
|
||||||
s = expr_to_string_shorthand(expr);
|
s = expr_to_string_shorthand(expr);
|
||||||
@@ -202,8 +192,7 @@ void print_doc_expr(Ast *expr) {
|
|||||||
gb_string_free(s);
|
gb_string_free(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
||||||
void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
|
||||||
if (pkg == nullptr) {
|
if (pkg == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -220,10 +209,10 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (pkg->scope != nullptr) {
|
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));
|
defer (array_free(&entities));
|
||||||
for_array(i, pkg->scope->elements.entries) {
|
for (auto const &entry : pkg->scope->elements) {
|
||||||
Entity *e = pkg->scope->elements.entries[i].value;
|
Entity *e = entry.value;
|
||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case Entity_Invalid:
|
case Entity_Invalid:
|
||||||
case Entity_Builtin:
|
case Entity_Builtin:
|
||||||
@@ -240,6 +229,12 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
|||||||
// Fine
|
// Fine
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (e->pkg != pkg) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!is_entity_exported(e)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
array_add(&entities, e);
|
array_add(&entities, e);
|
||||||
}
|
}
|
||||||
gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);
|
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;
|
bool show_docs = (build_context.cmd_doc_flags & CmdDocFlag_Short) == 0;
|
||||||
|
|
||||||
EntityKind curr_entity_kind = Entity_Invalid;
|
EntityKind curr_entity_kind = Entity_Invalid;
|
||||||
for_array(i, entities) {
|
for (Entity *e : entities) {
|
||||||
Entity *e = entities[i];
|
|
||||||
if (e->pkg != pkg) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
if (!is_entity_exported(e)) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (curr_entity_kind != e->kind) {
|
if (curr_entity_kind != e->kind) {
|
||||||
if (curr_entity_kind != Entity_Invalid) {
|
if (curr_entity_kind != Entity_Invalid) {
|
||||||
print_doc_line(0, "");
|
print_doc_line(0, "");
|
||||||
@@ -297,7 +283,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
|
|||||||
print_doc_expr(init_expr);
|
print_doc_expr(init_expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_printf(";\n");
|
gb_printf("\n");
|
||||||
|
|
||||||
if (show_docs) {
|
if (show_docs) {
|
||||||
print_doc_comment_group_string(3, 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;
|
CheckerInfo *info = &c->info;
|
||||||
|
|
||||||
if (build_context.cmd_doc_flags & CmdDocFlag_DocFormat) {
|
if (build_context.cmd_doc_flags & CmdDocFlag_DocFormat) {
|
||||||
@@ -358,9 +344,9 @@ void generate_documentation(Checker *c) {
|
|||||||
|
|
||||||
odin_doc_write(info, output_file_path);
|
odin_doc_write(info, output_file_path);
|
||||||
} else {
|
} else {
|
||||||
auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
|
auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.count);
|
||||||
for_array(i, info->packages.entries) {
|
for (auto const &entry : info->packages) {
|
||||||
AstPackage *pkg = info->packages.entries[i].value;
|
AstPackage *pkg = entry.value;
|
||||||
if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
|
if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
|
||||||
array_add(&pkgs, pkg);
|
array_add(&pkgs, pkg);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+2
-2
@@ -27,14 +27,14 @@ struct OdinDocHeaderBase {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
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 = {};
|
Slice<T> s = {};
|
||||||
s.data = cast(T *)(cast(uintptr)base + cast(uintptr)a.offset);
|
s.data = cast(T *)(cast(uintptr)base + cast(uintptr)a.offset);
|
||||||
s.count = cast(isize)a.length;
|
s.count = cast(isize)a.length;
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
String from_string(OdinDocHeaderBase *base, OdinDocString const &s) {
|
gb_internal String from_string(OdinDocHeaderBase *base, OdinDocString const &s) {
|
||||||
String str = {};
|
String str = {};
|
||||||
str.text = cast(u8 *)(cast(uintptr)base + cast(uintptr)s.offset);
|
str.text = cast(u8 *)(cast(uintptr)base + cast(uintptr)s.offset);
|
||||||
str.len = cast(isize)s.length;
|
str.len = cast(isize)s.length;
|
||||||
|
|||||||
+58
-62
@@ -11,7 +11,7 @@ enum OdinDocWriterState {
|
|||||||
OdinDocWriterState_Writing,
|
OdinDocWriterState_Writing,
|
||||||
};
|
};
|
||||||
|
|
||||||
char const* OdinDocWriterState_strings[] {
|
gb_global char const* OdinDocWriterState_strings[] {
|
||||||
"preparing",
|
"preparing",
|
||||||
"writing ",
|
"writing ",
|
||||||
};
|
};
|
||||||
@@ -40,26 +40,25 @@ struct OdinDocWriter {
|
|||||||
OdinDocWriterItemTracker<u8> blob;
|
OdinDocWriterItemTracker<u8> blob;
|
||||||
};
|
};
|
||||||
|
|
||||||
OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e);
|
gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e);
|
||||||
OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type);
|
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type);
|
||||||
|
|
||||||
template <typename T>
|
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->len = size;
|
||||||
t->cap = size;
|
t->cap = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void odin_doc_writer_prepare(OdinDocWriter *w) {
|
gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
|
||||||
w->state = OdinDocWriterState_Preparing;
|
w->state = OdinDocWriterState_Preparing;
|
||||||
|
|
||||||
gbAllocator a = heap_allocator();
|
string_map_init(&w->string_cache);
|
||||||
string_map_init(&w->string_cache, a);
|
|
||||||
|
|
||||||
map_init(&w->file_cache, a);
|
map_init(&w->file_cache);
|
||||||
map_init(&w->pkg_cache, a);
|
map_init(&w->pkg_cache);
|
||||||
map_init(&w->entity_cache, a);
|
map_init(&w->entity_cache);
|
||||||
map_init(&w->type_cache, a);
|
map_init(&w->type_cache);
|
||||||
|
|
||||||
odin_doc_writer_item_tracker_init(&w->files, 1);
|
odin_doc_writer_item_tracker_init(&w->files, 1);
|
||||||
odin_doc_writer_item_tracker_init(&w->pkgs, 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);
|
gb_free(heap_allocator(), w->data);
|
||||||
|
|
||||||
string_map_destroy(&w->string_cache);
|
string_map_destroy(&w->string_cache);
|
||||||
@@ -83,7 +82,7 @@ void odin_doc_writer_destroy(OdinDocWriter *w) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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 size = t->cap*gb_size_of(T);
|
||||||
isize align = gb_max(gb_align_of(T), alignment);
|
isize align = gb_max(gb_align_of(T), alignment);
|
||||||
*offset = align_formula_isize(*offset, align);
|
*offset = align_formula_isize(*offset, align);
|
||||||
@@ -91,7 +90,7 @@ void odin_doc_writer_tracker_size(isize *offset, OdinDocWriterItemTracker<T> *t,
|
|||||||
*offset += size;
|
*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);
|
isize total_size = gb_size_of(OdinDocHeader);
|
||||||
odin_doc_writer_tracker_size(&total_size, &w->files);
|
odin_doc_writer_tracker_size(&total_size, &w->files);
|
||||||
odin_doc_writer_tracker_size(&total_size, &w->pkgs);
|
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;
|
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;
|
w->state = OdinDocWriterState_Writing;
|
||||||
|
|
||||||
string_map_clear(&w->string_cache);
|
string_map_clear(&w->string_cache);
|
||||||
@@ -118,7 +117,7 @@ void odin_doc_writer_start_writing(OdinDocWriter *w) {
|
|||||||
w->header = cast(OdinDocHeader *)w->data;
|
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 *start = cast(u8 *)data;
|
||||||
u8 *end = start + base->total_size;
|
u8 *end = start + base->total_size;
|
||||||
start += base->header_size;
|
start += base->header_size;
|
||||||
@@ -132,13 +131,13 @@ u32 hash_data_after_header(OdinDocHeaderBase *base, void *data, isize data_len)
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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->offset = cast(u32)t.offset;
|
||||||
array->length = cast(u32)t.len;
|
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;
|
OdinDocHeader *h = w->header;
|
||||||
|
|
||||||
gb_memmove(h->base.magic, OdinDocHeader_MagicString, gb_strlen(OdinDocHeader_MagicString));
|
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>
|
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) {
|
if (w->state == OdinDocWriterState_Preparing) {
|
||||||
t->cap += 1;
|
t->cap += 1;
|
||||||
if (dst) *dst = nullptr;
|
if (dst) *dst = nullptr;
|
||||||
@@ -175,7 +174,7 @@ u32 odin_doc_write_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, T cons
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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) {
|
if (w->state != OdinDocWriterState_Writing) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -184,7 +183,7 @@ T *odin_doc_get_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, u32 index
|
|||||||
return cast(T *)data;
|
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 = {};
|
OdinDocString res = {};
|
||||||
|
|
||||||
if (w->state == OdinDocWriterState_Preparing) {
|
if (w->state == OdinDocWriterState_Preparing) {
|
||||||
@@ -204,7 +203,7 @@ OdinDocString odin_doc_write_string_without_cache(OdinDocWriter *w, String const
|
|||||||
return res;
|
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);
|
OdinDocString *c = string_map_get(&w->string_cache, str);
|
||||||
if (c != nullptr) {
|
if (c != nullptr) {
|
||||||
if (w->state == OdinDocWriterState_Writing) {
|
if (w->state == OdinDocWriterState_Writing) {
|
||||||
@@ -223,7 +222,7 @@ OdinDocString odin_doc_write_string(OdinDocWriter *w, String const &str) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(gb_align_of(T) <= 4);
|
||||||
if (len <= 0) {
|
if (len <= 0) {
|
||||||
return {0, 0};
|
return {0, 0};
|
||||||
@@ -249,12 +248,12 @@ OdinDocArray<T> odin_write_slice(OdinDocWriter *w, T *data, isize len) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
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;
|
OdinDocFileIndex file_index = 0;
|
||||||
if (pos.file_id != 0) {
|
if (pos.file_id != 0) {
|
||||||
AstFile *file = global_files[pos.file_id];
|
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;
|
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) {
|
if (g == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -361,7 +360,7 @@ bool odin_doc_append_comment_group_string(Array<u8> *buf, CommentGroup *g) {
|
|||||||
return false;
|
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) {
|
if (pkg == nullptr) {
|
||||||
return {};
|
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));
|
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) {
|
if (g == nullptr) {
|
||||||
return {};
|
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));
|
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) {
|
if (expr == nullptr) {
|
||||||
return {};
|
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)));
|
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;
|
isize count = 0;
|
||||||
for_array(i, attributes) {
|
for_array(i, attributes) {
|
||||||
Ast *attr = attributes[i];
|
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);
|
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) {
|
if (where_clauses.count == 0) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -462,17 +461,17 @@ OdinDocArray<OdinDocString> odin_doc_where_clauses(OdinDocWriter *w, Slice<Ast *
|
|||||||
return odin_write_slice(w, clauses.data, clauses.count);
|
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);
|
OdinDocTypeIndex index = odin_doc_type(w, type);
|
||||||
return odin_write_item_as_slice(w, index);
|
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);
|
OdinDocEntityIndex index = odin_doc_add_entity(w, e);
|
||||||
return odin_write_item_as_slice(w, index);
|
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) {
|
if (type == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -480,11 +479,11 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
|||||||
if (found) {
|
if (found) {
|
||||||
return *found;
|
return *found;
|
||||||
}
|
}
|
||||||
for_array(i, w->type_cache.entries) {
|
for (auto const &entry : w->type_cache) {
|
||||||
// NOTE(bill): THIS IS SLOW
|
// 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)) {
|
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);
|
map_set(&w->type_cache, type, index);
|
||||||
return index;
|
return index;
|
||||||
}
|
}
|
||||||
@@ -750,7 +749,7 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
|
|||||||
}
|
}
|
||||||
return type_index;
|
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) {
|
if (e == nullptr) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -860,7 +859,6 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
|
|||||||
if (e->flags & EntityFlag_Param) {
|
if (e->flags & EntityFlag_Param) {
|
||||||
if (e->flags & EntityFlag_Using) { flags |= OdinDocEntityFlag_Param_Using; }
|
if (e->flags & EntityFlag_Using) { flags |= OdinDocEntityFlag_Param_Using; }
|
||||||
if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const; }
|
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_Ellipsis) { flags |= OdinDocEntityFlag_Param_Ellipsis; }
|
||||||
if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; }
|
if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; }
|
||||||
if (e->flags & EntityFlag_AnyInt) { flags |= OdinDocEntityFlag_Param_AnyInt; }
|
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;
|
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
|
// 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));
|
defer (array_free(&entities));
|
||||||
|
|
||||||
for_array(i, w->entity_cache.entries) {
|
for (auto const &entry : w->entity_cache) {
|
||||||
Entity *e = w->entity_cache.entries[i].key;
|
array_add(&entities, entry.key);
|
||||||
entities[i] = e;
|
|
||||||
}
|
}
|
||||||
for_array(i, entities) {
|
for (Entity *e : entities) {
|
||||||
Entity *e = entities[i];
|
|
||||||
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
|
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
|
||||||
gb_unused(type_index);
|
gb_unused(type_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for_array(i, w->entity_cache.entries) {
|
for (auto const &entry : w->entity_cache) {
|
||||||
Entity *e = w->entity_cache.entries[i].key;
|
Entity *e = entry.key;
|
||||||
OdinDocEntityIndex entity_index = w->entity_cache.entries[i].value;
|
OdinDocEntityIndex entity_index = entry.value;
|
||||||
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
|
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
|
||||||
|
|
||||||
OdinDocEntityIndex foreign_library = 0;
|
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);
|
auto pges = array_make<OdinDocEntityIndex>(heap_allocator(), 0, e->ProcGroup.entities.count);
|
||||||
defer (array_free(&pges));
|
defer (array_free(&pges));
|
||||||
|
|
||||||
for_array(j, e->ProcGroup.entities) {
|
for (Entity *entity : e->ProcGroup.entities) {
|
||||||
OdinDocEntityIndex index = odin_doc_add_entity(w, e->ProcGroup.entities[j]);
|
OdinDocEntityIndex index = odin_doc_add_entity(w, entity);
|
||||||
array_add(&pges, index);
|
array_add(&pges, index);
|
||||||
}
|
}
|
||||||
grouped_entities = odin_write_slice(w, pges.data, pges.count);
|
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) {
|
if (pkg->scope == nullptr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
@@ -976,12 +972,12 @@ OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPa
|
|||||||
return {};
|
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));
|
defer (array_free(&entries));
|
||||||
|
|
||||||
for_array(i, pkg->scope->elements.entries) {
|
for (auto const &element : pkg->scope->elements) {
|
||||||
String name = pkg->scope->elements.entries[i].key.string;
|
String name = element.key;
|
||||||
Entity *e = pkg->scope->elements.entries[i].value;
|
Entity *e = element.value;
|
||||||
switch (e->kind) {
|
switch (e->kind) {
|
||||||
case Entity_Invalid:
|
case Entity_Invalid:
|
||||||
case Entity_Nil:
|
case Entity_Nil:
|
||||||
@@ -1018,11 +1014,11 @@ OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPa
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void odin_doc_write_docs(OdinDocWriter *w) {
|
gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
|
||||||
auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.entries.count);
|
auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.count);
|
||||||
defer (array_free(&pkgs));
|
defer (array_free(&pkgs));
|
||||||
for_array(i, w->info->packages.entries) {
|
for (auto const &entry : w->info->packages) {
|
||||||
AstPackage *pkg = w->info->packages.entries[i].value;
|
AstPackage *pkg = entry.value;
|
||||||
if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
|
if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
|
||||||
array_add(&pkgs, pkg);
|
array_add(&pkgs, pkg);
|
||||||
} else {
|
} 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 = {};
|
gbFile f = {};
|
||||||
gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, filename);
|
gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, filename);
|
||||||
if (err != gbFileError_None) {
|
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_ = {};
|
||||||
OdinDocWriter *w = &w_;
|
OdinDocWriter *w = &w_;
|
||||||
defer (odin_doc_writer_destroy(w));
|
defer (odin_doc_writer_destroy(w));
|
||||||
|
|||||||
+30
-36
@@ -26,7 +26,7 @@ enum EntityKind {
|
|||||||
Entity_Count,
|
Entity_Count,
|
||||||
};
|
};
|
||||||
|
|
||||||
String const entity_strings[] = {
|
gb_global String const entity_strings[] = {
|
||||||
#define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1},
|
#define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1},
|
||||||
ENTITY_KINDS
|
ENTITY_KINDS
|
||||||
#undef ENTITY_KIND
|
#undef ENTITY_KIND
|
||||||
@@ -61,7 +61,7 @@ enum EntityFlag : u64 {
|
|||||||
EntityFlag_ProcBodyChecked = 1ull<<21,
|
EntityFlag_ProcBodyChecked = 1ull<<21,
|
||||||
|
|
||||||
EntityFlag_CVarArg = 1ull<<22,
|
EntityFlag_CVarArg = 1ull<<22,
|
||||||
EntityFlag_AutoCast = 1ull<<23,
|
|
||||||
EntityFlag_AnyInt = 1ull<<24,
|
EntityFlag_AnyInt = 1ull<<24,
|
||||||
|
|
||||||
EntityFlag_Disabled = 1ull<<25,
|
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) {
|
if (param_value.kind != ParameterValue_Invalid) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -130,7 +130,7 @@ enum EntityConstantFlags : u32 {
|
|||||||
EntityConstantFlag_ImplicitEnumValue = 1<<0,
|
EntityConstantFlag_ImplicitEnumValue = 1<<0,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum ProcedureOptimizationMode : u32 {
|
enum ProcedureOptimizationMode : u8 {
|
||||||
ProcedureOptimizationMode_Default,
|
ProcedureOptimizationMode_Default,
|
||||||
ProcedureOptimizationMode_None,
|
ProcedureOptimizationMode_None,
|
||||||
ProcedureOptimizationMode_Minimal,
|
ProcedureOptimizationMode_Minimal,
|
||||||
@@ -151,10 +151,9 @@ struct TypeNameObjCMetadata {
|
|||||||
Array<TypeNameObjCMetadataEntry> value_entries;
|
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);
|
TypeNameObjCMetadata *md = gb_alloc_item(permanent_allocator(), TypeNameObjCMetadata);
|
||||||
md->mutex = gb_alloc_item(permanent_allocator(), BlockingMutex);
|
md->mutex = gb_alloc_item(permanent_allocator(), BlockingMutex);
|
||||||
mutex_init(md->mutex);
|
|
||||||
array_init(&md->type_entries, heap_allocator());
|
array_init(&md->type_entries, heap_allocator());
|
||||||
array_init(&md->value_entries, heap_allocator());
|
array_init(&md->value_entries, heap_allocator());
|
||||||
return md;
|
return md;
|
||||||
@@ -234,6 +233,9 @@ struct Entity {
|
|||||||
String link_name;
|
String link_name;
|
||||||
String link_prefix;
|
String link_prefix;
|
||||||
DeferredProcedure deferred_procedure;
|
DeferredProcedure deferred_procedure;
|
||||||
|
|
||||||
|
struct GenProcsData *gen_procs;
|
||||||
|
BlockingMutex gen_procs_mutex;
|
||||||
ProcedureOptimizationMode optimization_mode;
|
ProcedureOptimizationMode optimization_mode;
|
||||||
bool is_foreign : 1;
|
bool is_foreign : 1;
|
||||||
bool is_export : 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) {
|
switch (kind) {
|
||||||
case Entity_Builtin:
|
case Entity_Builtin:
|
||||||
return allow_builtin;
|
return allow_builtin;
|
||||||
@@ -278,7 +280,7 @@ bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) {
|
|||||||
return true;
|
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
|
// TODO(bill): Determine the actual exportation rules for imports of entities
|
||||||
GB_ASSERT(e != nullptr);
|
GB_ASSERT(e != nullptr);
|
||||||
if (!is_entity_kind_exported(e->kind, allow_builtin)) {
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool entity_has_deferred_procedure(Entity *e) {
|
gb_internal bool entity_has_deferred_procedure(Entity *e) {
|
||||||
GB_ASSERT(e != nullptr);
|
GB_ASSERT(e != nullptr);
|
||||||
if (e->kind == Entity_Procedure) {
|
if (e->kind == Entity_Procedure) {
|
||||||
return e->Procedure.deferred_procedure.entity != nullptr;
|
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;
|
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();
|
gbAllocator a = permanent_allocator();
|
||||||
Entity *entity = gb_alloc_item(a, Entity);
|
Entity *entity = gb_alloc_item(a, Entity);
|
||||||
entity->kind = kind;
|
entity->kind = kind;
|
||||||
@@ -323,13 +325,13 @@ Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
|
|||||||
return entity;
|
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 *entity = alloc_entity(Entity_Variable, scope, token, type);
|
||||||
entity->state = state;
|
entity->state = state;
|
||||||
return entity;
|
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);
|
GB_ASSERT(parent != nullptr);
|
||||||
token.pos = parent->token.pos;
|
token.pos = parent->token.pos;
|
||||||
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
|
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 *entity = alloc_entity(Entity_Constant, scope, token, type);
|
||||||
entity->Constant.value = value;
|
entity->Constant.value = value;
|
||||||
return entity;
|
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 *entity = alloc_entity(Entity_TypeName, scope, token, type);
|
||||||
entity->state = state;
|
entity->state = state;
|
||||||
return entity;
|
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 *entity = alloc_entity_variable(scope, token, type);
|
||||||
entity->flags |= EntityFlag_Used;
|
entity->flags |= EntityFlag_Used;
|
||||||
entity->flags |= EntityFlag_Param;
|
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 *entity = alloc_entity_constant(scope, token, type, value);
|
||||||
entity->flags |= EntityFlag_Used;
|
entity->flags |= EntityFlag_Used;
|
||||||
if (poly_const) entity->flags |= EntityFlag_PolyConst;
|
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 *entity = alloc_entity_variable(scope, token, type);
|
||||||
entity->Variable.field_index = field_index;
|
entity->Variable.field_index = field_index;
|
||||||
if (is_using) entity->flags |= EntityFlag_Using;
|
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;
|
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 *entity = alloc_entity_variable(scope, token, type);
|
||||||
entity->Variable.field_index = field_index;
|
entity->Variable.field_index = field_index;
|
||||||
entity->flags |= EntityFlag_Field;
|
entity->flags |= EntityFlag_Field;
|
||||||
@@ -393,26 +395,18 @@ Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field
|
|||||||
return entity;
|
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 *entity = alloc_entity(Entity_Procedure, scope, token, signature_type);
|
||||||
entity->Procedure.tags = tags;
|
entity->Procedure.tags = tags;
|
||||||
return entity;
|
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);
|
Entity *entity = alloc_entity(Entity_ProcGroup, scope, token, type);
|
||||||
return entity;
|
return entity;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gb_internal Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
|
||||||
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,
|
|
||||||
String path, String name, Scope *import_scope) {
|
String path, String name, Scope *import_scope) {
|
||||||
Entity *entity = alloc_entity(Entity_ImportName, scope, token, type);
|
Entity *entity = alloc_entity(Entity_ImportName, scope, token, type);
|
||||||
entity->ImportName.path = path;
|
entity->ImportName.path = path;
|
||||||
@@ -422,7 +416,7 @@ Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
|
|||||||
return entity;
|
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) {
|
Slice<String> paths, String name) {
|
||||||
Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type);
|
Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type);
|
||||||
entity->LibraryName.paths = paths;
|
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);
|
Entity *entity = alloc_entity(Entity_Nil, nullptr, make_token_ident(name), type);
|
||||||
return entity;
|
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 *entity = alloc_entity(Entity_Label, scope, token, type);
|
||||||
entity->Label.node = node;
|
entity->Label.node = node;
|
||||||
entity->Label.parent = parent;
|
entity->Label.parent = parent;
|
||||||
@@ -448,15 +442,15 @@ Entity *alloc_entity_label(Scope *scope, Token token, Type *type, Ast *node, Ast
|
|||||||
return entity;
|
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("_");
|
token.string = str_lit("_");
|
||||||
return alloc_entity_variable(scope, token, nullptr);
|
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) {
|
if (e == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
@@ -469,7 +463,7 @@ Entity *strip_entity_wrapping(Entity *e) {
|
|||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *strip_entity_wrapping(Ast *expr) {
|
gb_internal Entity *strip_entity_wrapping(Ast *expr) {
|
||||||
Entity *e = entity_from_expr(expr);
|
Entity *e = entity_from_expr(expr);
|
||||||
return strip_entity_wrapping(e);
|
return strip_entity_wrapping(e);
|
||||||
}
|
}
|
||||||
|
|||||||
+31
-35
@@ -17,15 +17,11 @@ gb_global ErrorCollector global_error_collector;
|
|||||||
#define MAX_ERROR_COLLECTOR_COUNT (36)
|
#define MAX_ERROR_COLLECTOR_COUNT (36)
|
||||||
|
|
||||||
|
|
||||||
bool any_errors(void) {
|
gb_internal bool any_errors(void) {
|
||||||
return global_error_collector.count.load() != 0;
|
return global_error_collector.count.load() != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void init_global_error_collector(void) {
|
gb_internal 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);
|
|
||||||
array_init(&global_error_collector.errors, heap_allocator());
|
array_init(&global_error_collector.errors, heap_allocator());
|
||||||
array_init(&global_error_collector.error_buffer, heap_allocator());
|
array_init(&global_error_collector.error_buffer, heap_allocator());
|
||||||
array_init(&global_file_path_strings, heap_allocator(), 1, 4096);
|
array_init(&global_file_path_strings, heap_allocator(), 1, 4096);
|
||||||
@@ -35,9 +31,9 @@ void init_global_error_collector(void) {
|
|||||||
|
|
||||||
// temporary
|
// temporary
|
||||||
// defined in build_settings.cpp
|
// 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;
|
bool ok = false;
|
||||||
GB_ASSERT(index >= 0);
|
GB_ASSERT(index >= 0);
|
||||||
mutex_lock(&global_error_collector.string_mutex);
|
mutex_lock(&global_error_collector.string_mutex);
|
||||||
@@ -55,7 +51,7 @@ bool set_file_path_string(i32 index, String const &path) {
|
|||||||
return ok;
|
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;
|
bool ok = false;
|
||||||
GB_ASSERT(index >= 0);
|
GB_ASSERT(index >= 0);
|
||||||
mutex_lock(&global_error_collector.string_mutex);
|
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;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
String get_file_path_string(i32 index) {
|
gb_internal String get_file_path_string(i32 index) {
|
||||||
GB_ASSERT(index >= 0);
|
GB_ASSERT(index >= 0);
|
||||||
mutex_lock(&global_error_collector.string_mutex);
|
mutex_lock(&global_error_collector.string_mutex);
|
||||||
|
|
||||||
@@ -86,7 +82,7 @@ String get_file_path_string(i32 index) {
|
|||||||
return path;
|
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);
|
GB_ASSERT(index >= 0);
|
||||||
mutex_lock(&global_error_collector.string_mutex);
|
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);
|
mutex_lock(&global_error_collector.block_mutex);
|
||||||
global_error_collector.in_block.store(true);
|
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) {
|
if (global_error_collector.error_buffer.count > 0) {
|
||||||
isize n = global_error_collector.error_buffer.count;
|
isize n = global_error_collector.error_buffer.count;
|
||||||
u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1);
|
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)
|
#define ERROR_OUT_PROC(name) void name(char const *fmt, va_list va)
|
||||||
typedef ERROR_OUT_PROC(ErrorOutProc);
|
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);
|
gbFile *f = gb_file_get_standard(gbFileStandard_Error);
|
||||||
|
|
||||||
char buf[4096] = {};
|
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
|
// NOTE: defined in build_settings.cpp
|
||||||
bool global_warnings_as_errors(void);
|
gb_internal bool global_warnings_as_errors(void);
|
||||||
bool global_ignore_warnings(void);
|
gb_internal bool global_ignore_warnings(void);
|
||||||
bool show_error_line(void);
|
gb_internal bool show_error_line(void);
|
||||||
gbString get_file_line_as_string(TokenPos const &pos, i32 *offset);
|
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_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
error_out_va(fmt, va);
|
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()) {
|
if (!show_error_line()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -237,7 +233,7 @@ bool show_error_on_line(TokenPos const &pos, TokenPos end) {
|
|||||||
return false;
|
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);
|
global_error_collector.count.fetch_add(1);
|
||||||
|
|
||||||
mutex_lock(&global_error_collector.mutex);
|
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()) {
|
if (global_warnings_as_errors()) {
|
||||||
error_va(pos, end, fmt, va);
|
error_va(pos, end, fmt, va);
|
||||||
return;
|
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);
|
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);
|
mutex_lock(&global_error_collector.mutex);
|
||||||
global_error_collector.count++;
|
global_error_collector.count++;
|
||||||
// NOTE(bill): Duplicate error, skip it
|
// 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);
|
mutex_lock(&global_error_collector.mutex);
|
||||||
global_error_collector.count++;
|
global_error_collector.count++;
|
||||||
// NOTE(bill): Duplicate error, skip it
|
// 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()) {
|
if (global_warnings_as_errors()) {
|
||||||
syntax_error_va(pos, end, fmt, va);
|
syntax_error_va(pos, end, fmt, va);
|
||||||
return;
|
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_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
warning_va(token.pos, {}, fmt, va);
|
warning_va(token.pos, {}, fmt, va);
|
||||||
va_end(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_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
error_va(token.pos, {}, fmt, va);
|
error_va(token.pos, {}, fmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
void error(TokenPos pos, char const *fmt, ...) {
|
gb_internal void error(TokenPos pos, char const *fmt, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
Token token = {};
|
Token token = {};
|
||||||
@@ -370,7 +366,7 @@ void error(TokenPos pos, char const *fmt, ...) {
|
|||||||
va_end(va);
|
va_end(va);
|
||||||
}
|
}
|
||||||
|
|
||||||
void error_line(char const *fmt, ...) {
|
gb_internal void error_line(char const *fmt, ...) {
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
error_line_va(fmt, va);
|
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_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
syntax_error_va(token.pos, {}, fmt, va);
|
syntax_error_va(token.pos, {}, fmt, va);
|
||||||
va_end(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_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
syntax_error_va(pos, {}, fmt, va);
|
syntax_error_va(pos, {}, fmt, va);
|
||||||
va_end(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_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
syntax_warning_va(token.pos, {}, fmt, va);
|
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_list va;
|
||||||
|
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
|
|||||||
+82
-92
@@ -6,7 +6,7 @@ struct Ast;
|
|||||||
struct HashKey;
|
struct HashKey;
|
||||||
struct Type;
|
struct Type;
|
||||||
struct Entity;
|
struct Entity;
|
||||||
bool are_types_identical(Type *x, Type *y);
|
gb_internal bool are_types_identical(Type *x, Type *y);
|
||||||
|
|
||||||
struct Complex128 {
|
struct Complex128 {
|
||||||
f64 real, imag;
|
f64 real, imag;
|
||||||
@@ -15,16 +15,6 @@ struct Quaternion256 {
|
|||||||
f64 imag, jmag, kmag, real;
|
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 {
|
enum ExactValueKind {
|
||||||
ExactValue_Invalid = 0,
|
ExactValue_Invalid = 0,
|
||||||
|
|
||||||
@@ -60,7 +50,7 @@ struct ExactValue {
|
|||||||
|
|
||||||
gb_global ExactValue const empty_exact_value = {};
|
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);
|
mutex_lock(&hash_exact_value_mutex);
|
||||||
defer (mutex_unlock(&hash_exact_value_mutex));
|
defer (mutex_unlock(&hash_exact_value_mutex));
|
||||||
|
|
||||||
@@ -70,7 +60,7 @@ uintptr hash_exact_value(ExactValue v) {
|
|||||||
case ExactValue_Bool:
|
case ExactValue_Bool:
|
||||||
return gb_fnv32a(&v.value_bool, gb_size_of(v.value_bool));
|
return gb_fnv32a(&v.value_bool, gb_size_of(v.value_bool));
|
||||||
case ExactValue_String:
|
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:
|
case ExactValue_Integer:
|
||||||
{
|
{
|
||||||
u32 key = gb_fnv32a(v.value_integer.dp, gb_size_of(*v.value_integer.dp) * v.value_integer.used);
|
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};
|
ExactValue result = {ExactValue_Compound};
|
||||||
result.value_compound = node;
|
result.value_compound = node;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_bool(bool b) {
|
gb_internal ExactValue exact_value_bool(bool b) {
|
||||||
ExactValue result = {ExactValue_Bool};
|
ExactValue result = {ExactValue_Bool};
|
||||||
result.value_bool = (b != 0);
|
result.value_bool = (b != 0);
|
||||||
return result;
|
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
|
// TODO(bill): Allow for numbers with underscores in them
|
||||||
ExactValue result = {ExactValue_String};
|
ExactValue result = {ExactValue_String};
|
||||||
result.value_string = string;
|
result.value_string = string;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_i64(i64 i) {
|
gb_internal ExactValue exact_value_i64(i64 i) {
|
||||||
ExactValue result = {ExactValue_Integer};
|
ExactValue result = {ExactValue_Integer};
|
||||||
big_int_from_i64(&result.value_integer, i);
|
big_int_from_i64(&result.value_integer, i);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_u64(u64 i) {
|
gb_internal ExactValue exact_value_u64(u64 i) {
|
||||||
ExactValue result = {ExactValue_Integer};
|
ExactValue result = {ExactValue_Integer};
|
||||||
big_int_from_u64(&result.value_integer, i);
|
big_int_from_u64(&result.value_integer, i);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_float(f64 f) {
|
gb_internal ExactValue exact_value_float(f64 f) {
|
||||||
ExactValue result = {ExactValue_Float};
|
ExactValue result = {ExactValue_Float};
|
||||||
result.value_float = f;
|
result.value_float = f;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_complex(f64 real, f64 imag) {
|
gb_internal ExactValue exact_value_complex(f64 real, f64 imag) {
|
||||||
ExactValue result = {ExactValue_Complex};
|
ExactValue result = {ExactValue_Complex};
|
||||||
result.value_complex = gb_alloc_item(permanent_allocator(), Complex128);
|
result.value_complex = gb_alloc_item(permanent_allocator(), Complex128);
|
||||||
result.value_complex->real = real;
|
result.value_complex->real = real;
|
||||||
@@ -142,7 +132,7 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
|
|||||||
return result;
|
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};
|
ExactValue result = {ExactValue_Quaternion};
|
||||||
result.value_quaternion = gb_alloc_item(permanent_allocator(), Quaternion256);
|
result.value_quaternion = gb_alloc_item(permanent_allocator(), Quaternion256);
|
||||||
result.value_quaternion->real = real;
|
result.value_quaternion->real = real;
|
||||||
@@ -152,27 +142,27 @@ ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_pointer(i64 ptr) {
|
gb_internal ExactValue exact_value_pointer(i64 ptr) {
|
||||||
ExactValue result = {ExactValue_Pointer};
|
ExactValue result = {ExactValue_Pointer};
|
||||||
result.value_pointer = ptr;
|
result.value_pointer = ptr;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_procedure(Ast *node) {
|
gb_internal ExactValue exact_value_procedure(Ast *node) {
|
||||||
ExactValue result = {ExactValue_Procedure};
|
ExactValue result = {ExactValue_Procedure};
|
||||||
result.value_procedure = node;
|
result.value_procedure = node;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
ExactValue exact_value_typeid(Type *type) {
|
gb_internal ExactValue exact_value_typeid(Type *type) {
|
||||||
ExactValue result = {ExactValue_Typeid};
|
ExactValue result = {ExactValue_Typeid};
|
||||||
result.value_typeid = type;
|
result.value_typeid = type;
|
||||||
return result;
|
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};
|
ExactValue result = {ExactValue_Integer};
|
||||||
bool success;
|
bool success;
|
||||||
big_int_from_string(&result.value_integer, string, &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;
|
isize i = 0;
|
||||||
u8 *str = string.text;
|
u8 *str = string.text;
|
||||||
isize len = string.len;
|
isize len = string.len;
|
||||||
@@ -262,7 +252,7 @@ f64 float_from_string(String string) {
|
|||||||
return sign * (frac ? (value / scale) : (value * scale));
|
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') {
|
if (string.len > 2 && string[0] == '0' && string[1] == 'h') {
|
||||||
|
|
||||||
isize digit_count = 0;
|
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) {
|
switch (kind) {
|
||||||
case Token_String: return exact_value_string(string);
|
case Token_String: return exact_value_string(string);
|
||||||
case Token_Integer: return exact_value_integer_from_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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_to_integer(ExactValue v) {
|
gb_internal ExactValue exact_value_to_integer(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Bool: {
|
case ExactValue_Bool: {
|
||||||
i64 i = 0;
|
i64 i = 0;
|
||||||
@@ -357,7 +347,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_to_float(ExactValue v) {
|
gb_internal ExactValue exact_value_to_float(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
return exact_value_float(big_int_to_f64(&v.value_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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_to_complex(ExactValue v) {
|
gb_internal ExactValue exact_value_to_complex(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
return exact_value_complex(big_int_to_f64(&v.value_integer), 0);
|
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);
|
v.value_complex = gb_alloc_item(permanent_allocator(), Complex128);
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
ExactValue exact_value_to_quaternion(ExactValue v) {
|
gb_internal ExactValue exact_value_to_quaternion(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0);
|
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;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_real(ExactValue v) {
|
gb_internal ExactValue exact_value_real(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
@@ -413,7 +403,7 @@ ExactValue exact_value_real(ExactValue v) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_imag(ExactValue v) {
|
gb_internal ExactValue exact_value_imag(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
@@ -427,7 +417,7 @@ ExactValue exact_value_imag(ExactValue v) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_jmag(ExactValue v) {
|
gb_internal ExactValue exact_value_jmag(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
@@ -440,7 +430,7 @@ ExactValue exact_value_jmag(ExactValue v) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_kmag(ExactValue v) {
|
gb_internal ExactValue exact_value_kmag(ExactValue v) {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
case ExactValue_Integer:
|
||||||
case ExactValue_Float:
|
case ExactValue_Float:
|
||||||
@@ -453,60 +443,60 @@ ExactValue exact_value_kmag(ExactValue v) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
ExactValue exact_value_make_imag(ExactValue v) {
|
// gb_internal ExactValue exact_value_make_imag(ExactValue v) {
|
||||||
switch (v.kind) {
|
// switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
// case ExactValue_Integer:
|
||||||
return exact_value_complex(0, exact_value_to_float(v).value_float);
|
// return exact_value_complex(0, exact_value_to_float(v).value_float);
|
||||||
case ExactValue_Float:
|
// case ExactValue_Float:
|
||||||
return exact_value_complex(0, v.value_float);
|
// return exact_value_complex(0, v.value_float);
|
||||||
default:
|
// default:
|
||||||
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
// GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
||||||
}
|
// }
|
||||||
ExactValue r = {ExactValue_Invalid};
|
// ExactValue r = {ExactValue_Invalid};
|
||||||
return r;
|
// return r;
|
||||||
}
|
// }
|
||||||
|
|
||||||
ExactValue exact_value_make_jmag(ExactValue v) {
|
// gb_internal ExactValue exact_value_make_jmag(ExactValue v) {
|
||||||
switch (v.kind) {
|
// switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
// case ExactValue_Integer:
|
||||||
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
|
// return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
|
||||||
case ExactValue_Float:
|
// case ExactValue_Float:
|
||||||
return exact_value_quaternion(0, 0, v.value_float, 0);
|
// return exact_value_quaternion(0, 0, v.value_float, 0);
|
||||||
default:
|
// default:
|
||||||
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
// GB_PANIC("Expected an integer or float type for 'exact_value_make_jmag'");
|
||||||
}
|
// }
|
||||||
ExactValue r = {ExactValue_Invalid};
|
// ExactValue r = {ExactValue_Invalid};
|
||||||
return r;
|
// return r;
|
||||||
}
|
// }
|
||||||
|
|
||||||
ExactValue exact_value_make_kmag(ExactValue v) {
|
// gb_internal ExactValue exact_value_make_kmag(ExactValue v) {
|
||||||
switch (v.kind) {
|
// switch (v.kind) {
|
||||||
case ExactValue_Integer:
|
// case ExactValue_Integer:
|
||||||
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
|
// return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
|
||||||
case ExactValue_Float:
|
// case ExactValue_Float:
|
||||||
return exact_value_quaternion(0, 0, 0, v.value_float);
|
// return exact_value_quaternion(0, 0, 0, v.value_float);
|
||||||
default:
|
// default:
|
||||||
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
|
// GB_PANIC("Expected an integer or float type for 'exact_value_make_kmag'");
|
||||||
}
|
// }
|
||||||
ExactValue r = {ExactValue_Invalid};
|
// ExactValue r = {ExactValue_Invalid};
|
||||||
return r;
|
// return r;
|
||||||
}
|
// }
|
||||||
|
|
||||||
i64 exact_value_to_i64(ExactValue v) {
|
gb_internal i64 exact_value_to_i64(ExactValue v) {
|
||||||
v = exact_value_to_integer(v);
|
v = exact_value_to_integer(v);
|
||||||
if (v.kind == ExactValue_Integer) {
|
if (v.kind == ExactValue_Integer) {
|
||||||
return big_int_to_i64(&v.value_integer);
|
return big_int_to_i64(&v.value_integer);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
u64 exact_value_to_u64(ExactValue v) {
|
gb_internal u64 exact_value_to_u64(ExactValue v) {
|
||||||
v = exact_value_to_integer(v);
|
v = exact_value_to_integer(v);
|
||||||
if (v.kind == ExactValue_Integer) {
|
if (v.kind == ExactValue_Integer) {
|
||||||
return big_int_to_u64(&v.value_integer);
|
return big_int_to_u64(&v.value_integer);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
f64 exact_value_to_f64(ExactValue v) {
|
gb_internal f64 exact_value_to_f64(ExactValue v) {
|
||||||
v = exact_value_to_float(v);
|
v = exact_value_to_float(v);
|
||||||
if (v.kind == ExactValue_Float) {
|
if (v.kind == ExactValue_Float) {
|
||||||
return v.value_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) {
|
switch (op) {
|
||||||
case Token_Add: {
|
case Token_Add: {
|
||||||
switch (v.kind) {
|
switch (v.kind) {
|
||||||
@@ -596,7 +586,7 @@ failure:
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NOTE(bill): Make sure things are evaluated in correct order
|
// 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) {
|
switch (v.kind) {
|
||||||
case ExactValue_Invalid:
|
case ExactValue_Invalid:
|
||||||
case ExactValue_Compound:
|
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)) {
|
if (exact_value_order(*y) < exact_value_order(*x)) {
|
||||||
match_exact_values(y, x);
|
match_exact_values(y, x);
|
||||||
return;
|
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?
|
// 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);
|
match_exact_values(&x, &y);
|
||||||
|
|
||||||
switch (x.kind) {
|
switch (x.kind) {
|
||||||
@@ -846,32 +836,32 @@ error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variab
|
|||||||
return empty_exact_value;
|
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);
|
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);
|
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);
|
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);
|
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);
|
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));
|
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);
|
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);
|
match_exact_values(&x, &y);
|
||||||
|
|
||||||
switch (x.kind) {
|
switch (x.kind) {
|
||||||
@@ -969,12 +959,12 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
Entity *strip_entity_wrapping(Ast *expr);
|
gb_internal Entity *strip_entity_wrapping(Ast *expr);
|
||||||
Entity *strip_entity_wrapping(Entity *e);
|
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) {
|
switch (v.kind) {
|
||||||
case ExactValue_Invalid:
|
case ExactValue_Invalid:
|
||||||
return str;
|
return str;
|
||||||
@@ -1017,6 +1007,6 @@ gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize st
|
|||||||
return str;
|
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);
|
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(gb_thread_local)
|
||||||
#if defined(_MSC_VER) && _MSC_VER >= 1300
|
#if defined(_MSC_VER) && _MSC_VER >= 1300
|
||||||
#define gb_thread_local __declspec(thread)
|
#define gb_thread_local __declspec(thread)
|
||||||
#elif defined(__GNUC__)
|
|
||||||
#define gb_thread_local __thread
|
|
||||||
#else
|
#else
|
||||||
#define gb_thread_local thread_local
|
#define gb_thread_local thread_local
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+218
-105
@@ -1,3 +1,5 @@
|
|||||||
|
#define ALLOW_SPLIT_MULTI_RETURNS true
|
||||||
|
|
||||||
enum lbArgKind {
|
enum lbArgKind {
|
||||||
lbArg_Direct,
|
lbArg_Direct,
|
||||||
lbArg_Indirect,
|
lbArg_Indirect,
|
||||||
@@ -16,21 +18,21 @@ struct lbArgType {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
i64 lb_sizeof(LLVMTypeRef type);
|
gb_internal i64 lb_sizeof(LLVMTypeRef type);
|
||||||
i64 lb_alignof(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};
|
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);
|
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};
|
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);
|
i64 alignment = lb_alignof(type);
|
||||||
alignment = gb_max(alignment, 8);
|
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};
|
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};
|
return lbArgType{lbArg_Ignore, type, nullptr, nullptr, nullptr, nullptr, 0, false};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -48,21 +50,29 @@ struct lbFunctionType {
|
|||||||
ProcCallingConvention calling_convention;
|
ProcCallingConvention calling_convention;
|
||||||
Array<lbArgType> args;
|
Array<lbArgType> args;
|
||||||
lbArgType ret;
|
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;
|
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) {
|
if (type == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return LLVMGetTypeKind(type) == kind;
|
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 arg_count = cast(unsigned)ft->args.count;
|
||||||
unsigned offset = 0;
|
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;
|
args[arg_index++] = arg_type;
|
||||||
} else if (arg->kind == lbArg_Indirect) {
|
} else if (arg->kind == lbArg_Indirect) {
|
||||||
|
if (ft->multiple_return_original_type == nullptr || i < ft->original_arg_count) {
|
||||||
GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
|
GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
|
||||||
|
}
|
||||||
args[arg_index++] = LLVMPointerType(arg->type, 0);
|
args[arg_index++] = LLVMPointerType(arg->type, 0);
|
||||||
} else if (arg->kind == lbArg_Ignore) {
|
} else if (arg->kind == lbArg_Ignore) {
|
||||||
// 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) {
|
if (ft == nullptr) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -147,6 +159,13 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa
|
|||||||
LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute);
|
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++;
|
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);
|
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case LLVMVoidTypeKind:
|
case LLVMVoidTypeKind:
|
||||||
@@ -248,7 +267,7 @@ i64 lb_sizeof(LLVMTypeRef type) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
i64 lb_alignof(LLVMTypeRef type) {
|
gb_internal i64 lb_alignof(LLVMTypeRef type) {
|
||||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case LLVMVoidTypeKind:
|
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);
|
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
|
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
|
||||||
namespace lbAbi386 {
|
namespace lbAbi386 {
|
||||||
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);
|
||||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
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);
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||||
ft->ctx = c;
|
ft->ctx = c;
|
||||||
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(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;
|
ft->calling_convention = calling_convention;
|
||||||
return ft;
|
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) {
|
if (!is_return && lb_sizeof(type) > 8) {
|
||||||
return lb_arg_type_indirect(type, nullptr);
|
return lb_arg_type_indirect(type, nullptr);
|
||||||
}
|
}
|
||||||
@@ -352,8 +409,8 @@ namespace lbAbi386 {
|
|||||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||||
|
|
||||||
for (unsigned i = 0; i < arg_count; i++) {
|
for (unsigned i = 0; i < arg_count; i++) {
|
||||||
LLVMTypeRef t = arg_types[i];
|
LLVMTypeRef t = arg_types[i];
|
||||||
@@ -372,7 +429,7 @@ namespace lbAbi386 {
|
|||||||
return args;
|
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) {
|
if (!return_is_defined) {
|
||||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
} 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 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);
|
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);
|
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||||
return lb_arg_type_indirect(return_type, attr);
|
return lb_arg_type_indirect(return_type, attr);
|
||||||
}
|
}
|
||||||
@@ -391,20 +451,20 @@ namespace lbAbi386 {
|
|||||||
};
|
};
|
||||||
|
|
||||||
namespace lbAbiAmd64Win64 {
|
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);
|
||||||
|
|
||||||
|
gb_internal LB_ABI_INFO(abi_info) {
|
||||||
LB_ABI_INFO(abi_info) {
|
|
||||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||||
ft->ctx = c;
|
ft->ctx = c;
|
||||||
ft->args = compute_arg_types(c, arg_types, arg_count);
|
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;
|
ft->calling_convention = calling_convention;
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||||
|
|
||||||
for (unsigned i = 0; i < arg_count; i++) {
|
for (unsigned i = 0; i < arg_count; i++) {
|
||||||
LLVMTypeRef t = arg_types[i];
|
LLVMTypeRef t = arg_types[i];
|
||||||
@@ -428,6 +488,26 @@ namespace lbAbiAmd64Win64 {
|
|||||||
}
|
}
|
||||||
return args;
|
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
|
// 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,
|
RegClass_Memory,
|
||||||
};
|
};
|
||||||
|
|
||||||
bool is_sse(RegClass reg_class) {
|
gb_internal bool is_sse(RegClass reg_class) {
|
||||||
switch (reg_class) {
|
switch (reg_class) {
|
||||||
case RegClass_SSEFs:
|
case RegClass_SSEFs:
|
||||||
case RegClass_SSEFv:
|
case RegClass_SSEFv:
|
||||||
@@ -466,7 +546,7 @@ namespace lbAbiAmd64SysV {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void all_mem(Array<RegClass> *cs) {
|
gb_internal void all_mem(Array<RegClass> *cs) {
|
||||||
for_array(i, *cs) {
|
for_array(i, *cs) {
|
||||||
(*cs)[i] = RegClass_Memory;
|
(*cs)[i] = RegClass_Memory;
|
||||||
}
|
}
|
||||||
@@ -478,19 +558,19 @@ namespace lbAbiAmd64SysV {
|
|||||||
Amd64TypeAttribute_StructRect,
|
Amd64TypeAttribute_StructRect,
|
||||||
};
|
};
|
||||||
|
|
||||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||||
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);
|
||||||
void fixup(LLVMTypeRef t, Array<RegClass> *cls);
|
gb_internal void fixup(LLVMTypeRef t, Array<RegClass> *cls);
|
||||||
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);
|
||||||
Array<RegClass> classify(LLVMTypeRef t);
|
gb_internal Array<RegClass> classify(LLVMTypeRef t);
|
||||||
LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const ®_classes);
|
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);
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||||
ft->ctx = c;
|
ft->ctx = c;
|
||||||
ft->calling_convention = calling_convention;
|
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++) {
|
for (unsigned i = 0; i < arg_count; i++) {
|
||||||
ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention);
|
ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention);
|
||||||
}
|
}
|
||||||
@@ -504,7 +584,7 @@ namespace lbAbiAmd64SysV {
|
|||||||
return ft;
|
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 (attribute_kind == Amd64TypeAttribute_ByVal) {
|
||||||
if (cls.count == 0) {
|
if (cls.count == 0) {
|
||||||
return false;
|
return false;
|
||||||
@@ -520,7 +600,7 @@ namespace lbAbiAmd64SysV {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_register(LLVMTypeRef type) {
|
gb_internal bool is_register(LLVMTypeRef type) {
|
||||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||||
i64 sz = lb_sizeof(type);
|
i64 sz = lb_sizeof(type);
|
||||||
if (sz == 0) {
|
if (sz == 0) {
|
||||||
@@ -537,7 +617,7 @@ namespace lbAbiAmd64SysV {
|
|||||||
return false;
|
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)) {
|
if (!lb_is_type_kind(type, LLVMStructTypeKind)) {
|
||||||
return false;
|
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)) {
|
if (is_register(type)) {
|
||||||
LLVMAttributeRef attribute = nullptr;
|
LLVMAttributeRef attribute = nullptr;
|
||||||
if (type == LLVMInt1TypeInContext(c)) {
|
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;
|
LLVMAttributeRef attr = nullptr;
|
||||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
||||||
if (type == i1) {
|
if (type == i1) {
|
||||||
@@ -597,7 +677,7 @@ namespace lbAbiAmd64SysV {
|
|||||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
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 sz = lb_sizeof(t);
|
||||||
i64 words = (sz + 7)/8;
|
i64 words = (sz + 7)/8;
|
||||||
auto reg_classes = array_make<RegClass>(heap_allocator(), cast(isize)words);
|
auto reg_classes = array_make<RegClass>(heap_allocator(), cast(isize)words);
|
||||||
@@ -610,7 +690,7 @@ namespace lbAbiAmd64SysV {
|
|||||||
return reg_classes;
|
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];
|
RegClass const oldv = (*cls)[cast(isize)i];
|
||||||
if (oldv == newv) {
|
if (oldv == newv) {
|
||||||
return;
|
return;
|
||||||
@@ -646,7 +726,7 @@ namespace lbAbiAmd64SysV {
|
|||||||
(*cls)[cast(isize)i] = to_write;
|
(*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 i = 0;
|
||||||
i64 e = cls->count;
|
i64 e = cls->count;
|
||||||
if (e > 2 && (lb_is_type_kind(t, LLVMStructTypeKind) ||
|
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;
|
unsigned len = 1;
|
||||||
for (isize i = offset; i < reg_classes.count; i++) {
|
for (isize i = offset; i < reg_classes.count; i++) {
|
||||||
if (reg_classes[i] != RegClass_SSEUp) {
|
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);
|
auto types = array_make<LLVMTypeRef>(heap_allocator(), 0, reg_classes.count);
|
||||||
for (isize i = 0; i < reg_classes.count; /**/) {
|
for (isize i = 0; i < reg_classes.count; /**/) {
|
||||||
RegClass reg_class = reg_classes[i];
|
RegClass reg_class = reg_classes[i];
|
||||||
@@ -774,7 +854,7 @@ namespace lbAbiAmd64SysV {
|
|||||||
return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false);
|
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_align = lb_alignof(t);
|
||||||
i64 t_size = lb_sizeof(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) {
|
if (!return_is_defined) {
|
||||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
|
} 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 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);
|
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);
|
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||||
return lb_arg_type_indirect(return_type, attr);
|
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) {
|
} 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 {
|
namespace lbAbiArm64 {
|
||||||
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);
|
||||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||||
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_);
|
||||||
|
|
||||||
LB_ABI_INFO(abi_info) {
|
gb_internal LB_ABI_INFO(abi_info) {
|
||||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||||
ft->ctx = c;
|
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;
|
ft->calling_convention = calling_convention;
|
||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_register(LLVMTypeRef type) {
|
gb_internal bool is_register(LLVMTypeRef type) {
|
||||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case LLVMIntegerTypeKind:
|
case LLVMIntegerTypeKind:
|
||||||
@@ -923,7 +1006,7 @@ namespace lbAbiArm64 {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
|
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||||
LLVMAttributeRef attr = nullptr;
|
LLVMAttributeRef attr = nullptr;
|
||||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
||||||
if (type == i1) {
|
if (type == i1) {
|
||||||
@@ -932,7 +1015,7 @@ namespace lbAbiArm64 {
|
|||||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
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));
|
GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind));
|
||||||
unsigned len = LLVMGetArrayLength(type);
|
unsigned len = LLVMGetArrayLength(type);
|
||||||
if (len == 0) {
|
if (len == 0) {
|
||||||
@@ -949,7 +1032,7 @@ namespace lbAbiArm64 {
|
|||||||
}
|
}
|
||||||
return false;
|
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));
|
GB_ASSERT(lb_is_type_kind(type, LLVMStructTypeKind));
|
||||||
unsigned elem_count = LLVMCountStructElementTypes(type);
|
unsigned elem_count = LLVMCountStructElementTypes(type);
|
||||||
if (elem_count == 0) {
|
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);
|
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case LLVMFloatTypeKind:
|
case LLVMFloatTypeKind:
|
||||||
@@ -1008,31 +1091,33 @@ namespace lbAbiArm64 {
|
|||||||
return false;
|
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);
|
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;
|
LLVMTypeRef homo_base_type = nullptr;
|
||||||
unsigned homo_member_count = 0;
|
unsigned homo_member_count = 0;
|
||||||
|
|
||||||
if (!return_is_defined) {
|
if (!return_is_defined) {
|
||||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||||
} else if (is_register(type)) {
|
} else if (is_register(return_type)) {
|
||||||
return non_struct(c, type);
|
return non_struct(c, return_type);
|
||||||
} else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
|
} 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)) {
|
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 {
|
} else {
|
||||||
//TODO(Platin): do i need to create stuff that can handle the diffrent return type?
|
//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
|
// 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);
|
//LLVMTypeRef array_type = LLVMArrayType(homo_base_type, homo_member_count);
|
||||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
|
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||||
return lb_arg_type_indirect(type, attr);
|
return lb_arg_type_indirect(return_type, attr);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
i64 size = lb_sizeof(type);
|
i64 size = lb_sizeof(return_type);
|
||||||
if (size <= 16) {
|
if (size <= 16) {
|
||||||
LLVMTypeRef cast_type = nullptr;
|
LLVMTypeRef cast_type = nullptr;
|
||||||
if (size <= 1) {
|
if (size <= 1) {
|
||||||
@@ -1047,16 +1132,18 @@ namespace lbAbiArm64 {
|
|||||||
unsigned count = cast(unsigned)((size+7)/8);
|
unsigned count = cast(unsigned)((size+7)/8);
|
||||||
cast_type = LLVMArrayType(LLVMInt64TypeInContext(c), count);
|
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 {
|
} else {
|
||||||
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
|
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
|
||||||
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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) {
|
||||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||||
|
|
||||||
for (unsigned i = 0; i < arg_count; i++) {
|
for (unsigned i = 0; i < arg_count; i++) {
|
||||||
LLVMTypeRef type = arg_types[i];
|
LLVMTypeRef type = arg_types[i];
|
||||||
@@ -1101,21 +1188,21 @@ namespace lbAbiWasm {
|
|||||||
The approach taken optimizes for passing things in multiple
|
The approach taken optimizes for passing things in multiple
|
||||||
registers/arguments if possible rather than by pointer.
|
registers/arguments if possible rather than by pointer.
|
||||||
*/
|
*/
|
||||||
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);
|
||||||
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
|
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
|
||||||
|
|
||||||
enum {MAX_DIRECT_STRUCT_SIZE = 32};
|
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);
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||||
ft->ctx = c;
|
ft->ctx = c;
|
||||||
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(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;
|
ft->calling_convention = calling_convention;
|
||||||
return ft;
|
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)) {
|
if (!is_return && type == LLVMIntTypeInContext(c, 128)) {
|
||||||
LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
|
LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
|
||||||
return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
|
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);
|
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)) {
|
switch (LLVMGetTypeKind(type)) {
|
||||||
case LLVMHalfTypeKind:
|
case LLVMHalfTypeKind:
|
||||||
case LLVMFloatTypeKind:
|
case LLVMFloatTypeKind:
|
||||||
@@ -1146,7 +1233,7 @@ namespace lbAbiWasm {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool type_can_be_direct(LLVMTypeRef type) {
|
gb_internal bool type_can_be_direct(LLVMTypeRef type) {
|
||||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||||
i64 sz = lb_sizeof(type);
|
i64 sz = lb_sizeof(type);
|
||||||
if (sz == 0) {
|
if (sz == 0) {
|
||||||
@@ -1172,7 +1259,7 @@ namespace lbAbiWasm {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
|
gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
|
||||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||||
GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
|
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) {
|
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
|
||||||
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
|
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||||
|
|
||||||
for (unsigned i = 0; i < arg_count; i++) {
|
for (unsigned i = 0; i < arg_count; i++) {
|
||||||
LLVMTypeRef t = arg_types[i];
|
LLVMTypeRef t = arg_types[i];
|
||||||
@@ -1202,7 +1289,7 @@ namespace lbAbiWasm {
|
|||||||
return args;
|
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) {
|
if (!return_is_defined) {
|
||||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||||
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
|
} 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 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);
|
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);
|
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
|
||||||
return lb_arg_type_indirect(return_type, attr);
|
return lb_arg_type_indirect(return_type, attr);
|
||||||
}
|
}
|
||||||
@@ -1225,10 +1315,10 @@ namespace lbAbiWasm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
namespace lbAbiArm32 {
|
namespace lbAbiArm32 {
|
||||||
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
|
gb_internal 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 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);
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||||
ft->ctx = c;
|
ft->ctx = c;
|
||||||
ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention);
|
ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention);
|
||||||
@@ -1237,7 +1327,7 @@ namespace lbAbiArm32 {
|
|||||||
return ft;
|
return ft;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_register(LLVMTypeRef type, bool is_return) {
|
gb_internal bool is_register(LLVMTypeRef type, bool is_return) {
|
||||||
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
LLVMTypeKind kind = LLVMGetTypeKind(type);
|
||||||
switch (kind) {
|
switch (kind) {
|
||||||
case LLVMHalfTypeKind:
|
case LLVMHalfTypeKind:
|
||||||
@@ -1256,7 +1346,7 @@ namespace lbAbiArm32 {
|
|||||||
return false;
|
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;
|
LLVMAttributeRef attr = nullptr;
|
||||||
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
|
||||||
if (type == i1) {
|
if (type == i1) {
|
||||||
@@ -1265,8 +1355,8 @@ namespace lbAbiArm32 {
|
|||||||
return lb_arg_type_direct(type, nullptr, nullptr, attr);
|
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) {
|
gb_internal 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);
|
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
|
||||||
|
|
||||||
for (unsigned i = 0; i < arg_count; i++) {
|
for (unsigned i = 0; i < arg_count; i++) {
|
||||||
LLVMTypeRef t = arg_types[i];
|
LLVMTypeRef t = arg_types[i];
|
||||||
@@ -1290,7 +1380,7 @@ namespace lbAbiArm32 {
|
|||||||
return args;
|
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) {
|
if (!return_is_defined) {
|
||||||
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
|
||||||
} else if (!is_register(return_type, true)) {
|
} 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) {
|
switch (calling_convention) {
|
||||||
case ProcCC_None:
|
case ProcCC_None:
|
||||||
case ProcCC_InlineAsm:
|
case ProcCC_InlineAsm:
|
||||||
{
|
{
|
||||||
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
|
||||||
ft->ctx = c;
|
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++) {
|
for (unsigned i = 0; i < arg_count; i++) {
|
||||||
ft->args[i] = lb_arg_type_direct(arg_types[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:
|
case ProcCC_Win64:
|
||||||
GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
|
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:
|
case ProcCC_SysV:
|
||||||
GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
|
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) {
|
switch (build_context.metrics.arch) {
|
||||||
case TargetArch_amd64:
|
case TargetArch_amd64:
|
||||||
if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) {
|
if (build_context.metrics.os == TargetOs_windows) {
|
||||||
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);
|
||||||
|
} 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) {
|
} 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 {
|
} 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:
|
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:
|
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:
|
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_wasm32:
|
||||||
case TargetArch_wasm64:
|
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");
|
GB_PANIC("Unsupported ABI");
|
||||||
return {};
|
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;
|
||||||
|
}
|
||||||
|
|||||||
+666
-558
File diff suppressed because it is too large
Load Diff
+169
-150
@@ -117,20 +117,34 @@ struct lbIncompleteDebugType {
|
|||||||
|
|
||||||
typedef Slice<i32> lbStructFieldRemapping;
|
typedef Slice<i32> lbStructFieldRemapping;
|
||||||
|
|
||||||
|
enum lbFunctionPassManagerKind {
|
||||||
|
lbFunctionPassManager_default,
|
||||||
|
lbFunctionPassManager_default_without_memcpy,
|
||||||
|
lbFunctionPassManager_minimal,
|
||||||
|
lbFunctionPassManager_size,
|
||||||
|
lbFunctionPassManager_speed,
|
||||||
|
|
||||||
|
lbFunctionPassManager_COUNT
|
||||||
|
};
|
||||||
|
|
||||||
struct lbModule {
|
struct lbModule {
|
||||||
LLVMModuleRef mod;
|
LLVMModuleRef mod;
|
||||||
LLVMContextRef ctx;
|
LLVMContextRef ctx;
|
||||||
|
|
||||||
struct lbGenerator *gen;
|
struct lbGenerator *gen;
|
||||||
|
LLVMTargetMachineRef target_machine;
|
||||||
|
|
||||||
CheckerInfo *info;
|
CheckerInfo *info;
|
||||||
AstPackage *pkg; // associated
|
AstPackage *pkg; // possibly associated
|
||||||
|
AstFile *file; // possibly associated
|
||||||
|
|
||||||
PtrMap<Type *, LLVMTypeRef> types;
|
PtrMap<Type *, LLVMTypeRef> types;
|
||||||
PtrMap<Type *, LLVMTypeRef> func_raw_types;
|
PtrMap<Type *, LLVMTypeRef> func_raw_types;
|
||||||
PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *
|
PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *
|
||||||
i32 internal_type_level;
|
i32 internal_type_level;
|
||||||
|
|
||||||
|
RwMutex values_mutex;
|
||||||
|
|
||||||
PtrMap<Entity *, lbValue> values;
|
PtrMap<Entity *, lbValue> values;
|
||||||
PtrMap<Entity *, lbAddr> soa_values;
|
PtrMap<Entity *, lbAddr> soa_values;
|
||||||
StringMap<lbValue> members;
|
StringMap<lbValue> members;
|
||||||
@@ -150,11 +164,14 @@ struct lbModule {
|
|||||||
u32 nested_type_name_guid;
|
u32 nested_type_name_guid;
|
||||||
|
|
||||||
Array<lbProcedure *> procedures_to_generate;
|
Array<lbProcedure *> procedures_to_generate;
|
||||||
|
Array<Entity *> global_procedures_and_types_to_create;
|
||||||
|
|
||||||
lbProcedure *curr_procedure;
|
lbProcedure *curr_procedure;
|
||||||
|
|
||||||
LLVMDIBuilderRef debug_builder;
|
LLVMDIBuilderRef debug_builder;
|
||||||
LLVMMetadataRef debug_compile_unit;
|
LLVMMetadataRef debug_compile_unit;
|
||||||
|
|
||||||
|
RecursiveMutex debug_values_mutex;
|
||||||
PtrMap<void *, LLVMMetadataRef> debug_values;
|
PtrMap<void *, LLVMMetadataRef> debug_values;
|
||||||
|
|
||||||
Array<lbIncompleteDebugType> debug_incomplete_types;
|
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_cell_info_map; // address of runtime.Map_Info
|
||||||
PtrMap<Type *, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
|
PtrMap<Type *, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
|
||||||
|
|
||||||
|
LLVMPassManagerRef function_pass_managers[lbFunctionPassManager_COUNT];
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lbGenerator {
|
struct lbGenerator {
|
||||||
@@ -173,10 +192,11 @@ struct lbGenerator {
|
|||||||
Array<String> output_temp_paths;
|
Array<String> output_temp_paths;
|
||||||
String output_base;
|
String output_base;
|
||||||
String output_name;
|
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;
|
PtrMap<LLVMContextRef, lbModule *> modules_through_ctx;
|
||||||
lbModule default_module;
|
lbModule default_module;
|
||||||
|
|
||||||
|
BlockingMutex anonymous_proc_lits_mutex;
|
||||||
PtrMap<Ast *, lbProcedure *> anonymous_proc_lits;
|
PtrMap<Ast *, lbProcedure *> anonymous_proc_lits;
|
||||||
|
|
||||||
BlockingMutex foreign_mutex;
|
BlockingMutex foreign_mutex;
|
||||||
@@ -185,6 +205,10 @@ struct lbGenerator {
|
|||||||
|
|
||||||
std::atomic<u32> global_array_index;
|
std::atomic<u32> global_array_index;
|
||||||
std::atomic<u32> global_generated_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 {
|
enum lbProcedureFlag : u32 {
|
||||||
lbProcedureFlag_WithoutMemcpyPass = 1<<0,
|
lbProcedureFlag_WithoutMemcpyPass = 1<<0,
|
||||||
lbProcedureFlag_DebugAllocaCopy = 1<<1,
|
lbProcedureFlag_DebugAllocaCopy = 1<<1,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct lbCopyElisionHint {
|
|
||||||
lbValue ptr;
|
|
||||||
Ast * ast;
|
|
||||||
bool used;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct lbProcedure {
|
struct lbProcedure {
|
||||||
u32 flags;
|
u32 flags;
|
||||||
u16 state_flags;
|
u16 state_flags;
|
||||||
@@ -302,6 +324,7 @@ struct lbProcedure {
|
|||||||
lbBlock * curr_block;
|
lbBlock * curr_block;
|
||||||
lbTargetList * target_list;
|
lbTargetList * target_list;
|
||||||
PtrMap<Entity *, lbValue> direct_parameters;
|
PtrMap<Entity *, lbValue> direct_parameters;
|
||||||
|
bool in_multi_assignment;
|
||||||
|
|
||||||
Ast *curr_stmt;
|
Ast *curr_stmt;
|
||||||
|
|
||||||
@@ -310,10 +333,9 @@ struct lbProcedure {
|
|||||||
|
|
||||||
LLVMMetadataRef debug_info;
|
LLVMMetadataRef debug_info;
|
||||||
|
|
||||||
lbCopyElisionHint copy_elision_hint;
|
|
||||||
|
|
||||||
PtrMap<Ast *, lbValue> selector_values;
|
PtrMap<Ast *, lbValue> selector_values;
|
||||||
PtrMap<Ast *, lbAddr> selector_addr;
|
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__)
|
#define LLVMBuildPtrDiff2(Builder__, Ty__, LHS__, RHS__, Name__) LLVMBuildPtrDiff(Builder__, LHS__, RHS__, Name__)
|
||||||
#endif
|
#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);
|
gb_internal String lb_mangle_name(lbModule *m, Entity *e);
|
||||||
String lb_get_entity_name(lbModule *m, Entity *e, String name = {});
|
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);
|
gb_internal 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);
|
gb_internal 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);
|
gb_internal 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);
|
gb_internal 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);
|
gb_internal lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false);
|
||||||
void lb_end_procedure(lbProcedure *p);
|
gb_internal void lb_end_procedure(lbProcedure *p);
|
||||||
|
|
||||||
|
|
||||||
LLVMTypeRef lb_type(lbModule *m, Type *type);
|
gb_internal LLVMTypeRef lb_type(lbModule *m, Type *type);
|
||||||
LLVMTypeRef llvm_get_element_type(LLVMTypeRef 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);
|
gb_internal lbValue lb_const_nil(lbModule *m, Type *type);
|
||||||
lbValue lb_const_undef(lbModule *m, Type *type);
|
gb_internal lbValue lb_const_undef(lbModule *m, Type *type);
|
||||||
lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local=true);
|
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local=true);
|
||||||
lbValue lb_const_bool(lbModule *m, Type *type, bool value);
|
gb_internal 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_int(lbModule *m, Type *type, u64 value);
|
||||||
|
|
||||||
|
|
||||||
lbAddr lb_addr(lbValue addr);
|
gb_internal lbAddr lb_addr(lbValue addr);
|
||||||
Type *lb_addr_type(lbAddr const &addr);
|
gb_internal Type *lb_addr_type(lbAddr const &addr);
|
||||||
LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val);
|
gb_internal LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val);
|
||||||
void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value);
|
gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value);
|
||||||
lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr);
|
gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr);
|
||||||
lbValue lb_emit_load(lbProcedure *p, lbValue v);
|
gb_internal lbValue lb_emit_load(lbProcedure *p, lbValue v);
|
||||||
void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value);
|
gb_internal void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value);
|
||||||
|
|
||||||
|
|
||||||
void lb_build_stmt(lbProcedure *p, Ast *stmt);
|
gb_internal void lb_build_stmt(lbProcedure *p, Ast *stmt);
|
||||||
lbValue lb_build_expr(lbProcedure *p, Ast *expr);
|
gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr);
|
||||||
lbAddr lb_build_addr(lbProcedure *p, Ast *expr);
|
gb_internal 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_list(lbProcedure *p, Array<Ast *> const &stmts);
|
||||||
|
|
||||||
lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index);
|
gb_internal lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index);
|
||||||
lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index);
|
gb_internal lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize 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);
|
||||||
lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index);
|
gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index);
|
||||||
lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index);
|
gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index);
|
||||||
lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index);
|
gb_internal lbValue lb_emit_tuple_ev(lbProcedure *p, lbValue value, i32 index);
|
||||||
lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index);
|
gb_internal lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index);
|
||||||
lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel);
|
gb_internal lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index);
|
||||||
lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel);
|
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);
|
gb_internal 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);
|
gb_internal 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_ev(lbProcedure *p, lbValue s, isize row, isize column);
|
||||||
|
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block);
|
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block);
|
||||||
lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
|
gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
|
||||||
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);
|
||||||
lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false);
|
gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none);
|
||||||
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
|
gb_internal 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_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x);
|
||||||
|
|
||||||
void lb_emit_jump(lbProcedure *p, lbBlock *target_block);
|
gb_internal void lb_emit_jump(lbProcedure *p, lbBlock *target_block);
|
||||||
void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *false_block);
|
gb_internal 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_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);
|
gb_internal lbAddr lb_find_or_generate_context_ptr(lbProcedure *p);
|
||||||
lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx);
|
gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx);
|
||||||
lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p);
|
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);
|
gb_internal 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_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);
|
gb_internal lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value);
|
||||||
lbValue lb_address_from_load(lbProcedure *p, lbValue value);
|
gb_internal lbValue lb_address_from_load(lbProcedure *p, lbValue value);
|
||||||
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);
|
||||||
lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init);
|
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);
|
gb_internal lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index);
|
||||||
lbValue lb_string_elem(lbProcedure *p, lbValue string);
|
gb_internal lbValue lb_string_elem(lbProcedure *p, lbValue string);
|
||||||
lbValue lb_string_len(lbProcedure *p, lbValue string);
|
gb_internal lbValue lb_string_len(lbProcedure *p, lbValue string);
|
||||||
lbValue lb_cstring_len(lbProcedure *p, lbValue value);
|
gb_internal 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);
|
||||||
lbValue lb_slice_elem(lbProcedure *p, lbValue slice);
|
gb_internal lbValue lb_slice_elem(lbProcedure *p, lbValue slice);
|
||||||
lbValue lb_slice_len(lbProcedure *p, lbValue slice);
|
gb_internal lbValue lb_slice_len(lbProcedure *p, lbValue slice);
|
||||||
lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da);
|
gb_internal lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da);
|
||||||
lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da);
|
gb_internal lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da);
|
||||||
lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da);
|
gb_internal lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da);
|
||||||
lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da);
|
gb_internal lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da);
|
||||||
lbValue lb_map_len(lbProcedure *p, lbValue value);
|
gb_internal lbValue lb_map_len(lbProcedure *p, lbValue value);
|
||||||
lbValue lb_map_cap(lbProcedure *p, lbValue value);
|
gb_internal lbValue lb_map_cap(lbProcedure *p, lbValue value);
|
||||||
lbValue lb_soa_struct_len(lbProcedure *p, lbValue value);
|
gb_internal lbValue lb_soa_struct_len(lbProcedure *p, lbValue value);
|
||||||
void lb_emit_increment(lbProcedure *p, lbValue addr);
|
gb_internal 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_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);
|
gb_internal 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_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent = nullptr);
|
||||||
|
|
||||||
bool lb_is_const(lbValue value);
|
gb_internal bool lb_is_const(lbValue value);
|
||||||
bool lb_is_const_or_global(lbValue value);
|
gb_internal bool lb_is_const_or_global(lbValue value);
|
||||||
bool lb_is_const_nil(lbValue value);
|
gb_internal bool lb_is_const_nil(lbValue value);
|
||||||
String lb_get_const_string(lbModule *m, 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);
|
gb_internal 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);
|
gb_internal 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_);
|
gb_internal 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);
|
gb_internal 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_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);
|
gb_internal 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);
|
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);
|
||||||
lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos);
|
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);
|
gb_internal 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_value_from_entity(lbModule *m, Entity *e);
|
||||||
|
|
||||||
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);
|
||||||
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);
|
||||||
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);
|
||||||
|
|
||||||
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);
|
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type);
|
||||||
lbValue lb_hasher_proc_for_type(lbModule *m, Type *type);
|
gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type);
|
||||||
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
|
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);
|
gb_internal lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type);
|
||||||
lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type);
|
gb_internal 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);
|
||||||
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);
|
||||||
lbValue lb_emit_reverse_bits(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);
|
gb_internal 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);
|
gb_internal 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 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_);
|
gb_internal 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_);
|
gb_internal 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 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);
|
gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t);
|
||||||
bool lb_is_expr_untyped_const(Ast *expr);
|
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);
|
gb_internal 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);
|
|
||||||
|
|
||||||
|
|
||||||
lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t);
|
gb_internal lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t);
|
||||||
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);
|
||||||
|
|
||||||
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);
|
gb_internal 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);
|
gb_internal 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);
|
gb_internal 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_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);
|
return cast(i64)(4*build_context.word_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);
|
gb_internal LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);
|
||||||
LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
|
gb_internal LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
|
||||||
|
|
||||||
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
|
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
|
||||||
#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
|
#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",
|
"external linkage",
|
||||||
"available externally linkage",
|
"available externally linkage",
|
||||||
"link once any 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;
|
LLVMValueRef v = value.value;
|
||||||
if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) {
|
if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) {
|
||||||
// TODO(bill): Is this correct behaviour?
|
// TODO(bill): Is this correct behaviour?
|
||||||
@@ -10,7 +10,7 @@ bool lb_is_const(lbValue value) {
|
|||||||
return false;
|
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)) {
|
if (lb_is_const(value)) {
|
||||||
return true;
|
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)) {
|
if (!elem_type_can_be_constant(elem_type)) {
|
||||||
return false;
|
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;
|
LLVMValueRef v = value.value;
|
||||||
if (LLVMIsConstant(v)) {
|
if (LLVMIsConstant(v)) {
|
||||||
if (LLVMIsAConstantAggregateZero(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);
|
GB_ASSERT(expr != nullptr);
|
||||||
auto v = exact_value_to_integer(expr->tav.value);
|
auto v = exact_value_to_integer(expr->tav.value);
|
||||||
if (v.kind == ExactValue_Integer) {
|
if (v.kind == ExactValue_Integer) {
|
||||||
@@ -64,7 +64,7 @@ bool lb_is_expr_constant_zero(Ast *expr) {
|
|||||||
return false;
|
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(lb_is_const(value));
|
||||||
GB_ASSERT(LLVMIsConstant(value.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);
|
LLVMTypeRef src = LLVMTypeOf(val);
|
||||||
if (src == dst) {
|
if (src == dst) {
|
||||||
return val;
|
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(value.type));
|
||||||
GB_ASSERT(is_type_internally_pointer_like(t));
|
GB_ASSERT(is_type_internally_pointer_like(t));
|
||||||
GB_ASSERT(lb_is_const(value));
|
GB_ASSERT(lb_is_const(value));
|
||||||
@@ -127,7 +127,7 @@ lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
|
|||||||
return res;
|
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);
|
LLVMTypeRef struct_type = lb_type(m, t);
|
||||||
GB_ASSERT(LLVMGetTypeKind(struct_type) == LLVMStructTypeKind);
|
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);
|
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 value_count = cast(unsigned)value_count_;
|
||||||
unsigned elem_count = LLVMCountStructElementTypes(t);
|
unsigned elem_count = LLVMCountStructElementTypes(t);
|
||||||
GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count);
|
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);
|
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_;
|
unsigned value_count = cast(unsigned)value_count_;
|
||||||
for (unsigned i = 0; i < value_count; i++) {
|
for (unsigned i = 0; i < value_count; i++) {
|
||||||
values[i] = llvm_const_cast(values[i], elem_type);
|
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);
|
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(is_type_pointer(data.type) || is_type_multi_pointer(data.type));
|
||||||
GB_ASSERT(are_types_identical(len.type, t_int));
|
GB_ASSERT(are_types_identical(len.type, t_int));
|
||||||
LLVMValueRef vals[2] = {
|
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));
|
LLVMValueRef v = LLVMConstNull(lb_type(m, type));
|
||||||
return lbValue{v, 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));
|
LLVMValueRef v = LLVMGetUndef(lb_type(m, type));
|
||||||
return lbValue{v, 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 = {};
|
lbValue res = {};
|
||||||
res.value = LLVMConstInt(lb_type(m, type), cast(unsigned long long)value, !is_type_unsigned(type));
|
res.value = LLVMConstInt(lb_type(m, type), cast(unsigned long long)value, !is_type_unsigned(type));
|
||||||
res.type = type;
|
res.type = type;
|
||||||
return res;
|
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));
|
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 = {};
|
lbValue res = {};
|
||||||
res.value = LLVMConstInt(lb_type(m, type), value, false);
|
res.value = LLVMConstInt(lb_type(m, type), value, false);
|
||||||
res.type = type;
|
res.type = type;
|
||||||
return res;
|
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);
|
GB_ASSERT(type_size_of(type) == 2);
|
||||||
|
|
||||||
u16 u = f32_to_f16(f);
|
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));
|
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);
|
GB_ASSERT(type_size_of(type) == 4);
|
||||||
u32 u = bit_cast<u32>(f);
|
u32 u = bit_cast<u32>(f);
|
||||||
if (is_type_different_to_arch_endianness(type)) {
|
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);
|
auto const &tv = type_and_value_of_expr(expr);
|
||||||
if (is_type_untyped(tv.type)) {
|
if (is_type_untyped(tv.type)) {
|
||||||
return tv.value.kind != ExactValue_Invalid;
|
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));
|
GB_ASSERT(is_type_typed(t));
|
||||||
auto const &tv = type_and_value_of_expr(expr);
|
auto const &tv = type_and_value_of_expr(expr);
|
||||||
return lb_const_value(m, t, tv.value);
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
LLVMValueRef fields[4] = {};
|
LLVMValueRef fields[4] = {};
|
||||||
@@ -271,7 +271,7 @@ lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedu
|
|||||||
return res;
|
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 = {};
|
String proc_name = {};
|
||||||
if (p->entity) {
|
if (p->entity) {
|
||||||
proc_name = p->entity->token.string;
|
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);
|
lbValue loc = lb_emit_source_code_location_const(p, procedure, pos);
|
||||||
lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
|
lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
|
||||||
lb_make_global_private_const(addr);
|
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);
|
lbValue loc = lb_emit_source_code_location_const(p, node);
|
||||||
lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
|
lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
|
||||||
lb_make_global_private_const(addr);
|
lb_make_global_private_const(addr);
|
||||||
return addr.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));
|
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));
|
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_local = allow_local && m->curr_procedure != nullptr;
|
||||||
bool is_const = true;
|
bool is_const = true;
|
||||||
if (is_local) {
|
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);
|
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)) {
|
if (big_int_is_zero(a)) {
|
||||||
return LLVMConstNull(lb_type(m, original_type));
|
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;
|
LLVMContextRef ctx = m->ctx;
|
||||||
|
|
||||||
type = default_type(type);
|
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) {
|
if (key == nullptr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
mutex_lock(&m->debug_values_mutex);
|
||||||
auto found = map_get(&m->debug_values, key);
|
auto found = map_get(&m->debug_values, key);
|
||||||
|
mutex_unlock(&m->debug_values_mutex);
|
||||||
if (found) {
|
if (found) {
|
||||||
return *found;
|
return *found;
|
||||||
}
|
}
|
||||||
return nullptr;
|
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) {
|
if (key != nullptr) {
|
||||||
|
mutex_lock(&m->debug_values_mutex);
|
||||||
map_set(&m->debug_values, key, value);
|
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));
|
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--) {
|
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;
|
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);
|
LLVMMetadataRef scope = lb_get_current_debug_scope(p);
|
||||||
GB_ASSERT_MSG(scope != nullptr, "%.*s", LIT(p->name));
|
GB_ASSERT_MSG(scope != nullptr, "%.*s", LIT(p->name));
|
||||||
return LLVMDIBuilderCreateDebugLocation(p->module->ctx, cast(unsigned)pos.line, cast(unsigned)pos.column, scope, nullptr);
|
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);
|
GB_ASSERT(node != nullptr);
|
||||||
return lb_debug_location_from_token_pos(p, ast_token(node).pos);
|
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);
|
GB_ASSERT(node != nullptr);
|
||||||
return lb_debug_location_from_token_pos(p, ast_end_token(node).pos);
|
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
|
i64 size = type_size_of(type); // Check size
|
||||||
gb_unused(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);
|
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;
|
unsigned field_line = 1;
|
||||||
LLVMDIFlags field_flags = LLVMDIFlagZero;
|
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)
|
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;
|
AstPackage *pkg = m->info->runtime_package;
|
||||||
GB_ASSERT(pkg->files.count != 0);
|
GB_ASSERT(pkg->files.count != 0);
|
||||||
LLVMMetadataRef file = lb_get_llvm_metadata(m, pkg->files[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);
|
LLVMMetadataRef basic_type = LLVMDIBuilderCreateBasicType(m->debug_builder, cast(char const *)name.text, name.len, size_in_bits, encoding, flags);
|
||||||
#if 1
|
#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);
|
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
|
#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
|
i64 size = type_size_of(type); // Check size
|
||||||
gb_unused(size);
|
gb_unused(size);
|
||||||
|
|
||||||
@@ -474,7 +472,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
|
|||||||
return nullptr;
|
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;
|
LLVMMetadataRef found = nullptr;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
if (scope == nullptr) {
|
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);
|
GB_ASSERT(type != nullptr);
|
||||||
LLVMMetadataRef found = lb_get_llvm_metadata(m, type);
|
LLVMMetadataRef found = lb_get_llvm_metadata(m, type);
|
||||||
if (found != nullptr) {
|
if (found != nullptr) {
|
||||||
return found;
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
MUTEX_GUARD(&m->debug_values_mutex);
|
||||||
|
|
||||||
if (type->kind == Type_Named) {
|
if (type->kind == Type_Named) {
|
||||||
LLVMMetadataRef file = nullptr;
|
LLVMMetadataRef file = nullptr;
|
||||||
unsigned line = 0;
|
unsigned line = 0;
|
||||||
@@ -615,11 +615,13 @@ LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
|
|||||||
return dt;
|
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_size = cast(unsigned)build_context.word_size; */
|
||||||
unsigned const word_bits = cast(unsigned)(8*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) {
|
for_array(debug_incomplete_type_index, m->debug_incomplete_types) {
|
||||||
|
TEMPORARY_ALLOCATOR_GUARD();
|
||||||
|
|
||||||
auto const &idt = m->debug_incomplete_types[debug_incomplete_type_index];
|
auto const &idt = m->debug_incomplete_types[debug_incomplete_type_index];
|
||||||
GB_ASSERT(idt.type != nullptr);
|
GB_ASSERT(idt.type != nullptr);
|
||||||
GB_ASSERT(idt.metadata != 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) {
|
if (p->debug_info == nullptr) {
|
||||||
return;
|
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);
|
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) {
|
if (p->debug_info == nullptr) {
|
||||||
return;
|
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) {
|
if (!p->debug_info || !p->body) {
|
||||||
return;
|
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;
|
String name = e->token.string;
|
||||||
if (e->pkg && e->pkg->name.len > 0) {
|
if (e->pkg && e->pkg->name.len > 0) {
|
||||||
// NOTE(bill): C++ NONSENSE FOR DEBUG SHITE!
|
// 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;
|
if (did_allocate_) *did_allocate_ = true;
|
||||||
}
|
}
|
||||||
return name;
|
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 scope = nullptr;
|
||||||
LLVMMetadataRef file = nullptr;
|
LLVMMetadataRef file = nullptr;
|
||||||
unsigned line = 0;
|
unsigned line = 0;
|
||||||
@@ -1151,14 +1153,11 @@ void add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMe
|
|||||||
expr, decl, 8/*AlignInBits*/);
|
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);
|
LLVMMetadataRef expr = LLVMDIBuilderCreateConstantValueExpression(m->debug_builder, v);
|
||||||
|
|
||||||
bool did_allocate = false;
|
TEMPORARY_ALLOCATOR_GUARD();
|
||||||
String name = debug_info_mangle_constant_name(e, &did_allocate);
|
String name = debug_info_mangle_constant_name(e, temporary_allocator(), nullptr);
|
||||||
defer (if (did_allocate) {
|
|
||||||
gb_free(heap_allocator(), name.text);
|
|
||||||
});
|
|
||||||
|
|
||||||
add_debug_info_global_variable_expr(m, name, dtype, expr);
|
add_debug_info_global_variable_expr(m, name, dtype, expr);
|
||||||
if ((e->pkg && e->pkg->kind == Package_Init) ||
|
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) {
|
if (e == nullptr || e->kind != Entity_Constant) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -1176,7 +1175,7 @@ void add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e)
|
|||||||
}
|
}
|
||||||
lbModule *m = &gen->default_module;
|
lbModule *m = &gen->default_module;
|
||||||
if (USE_SEPARATE_MODULES) {
|
if (USE_SEPARATE_MODULES) {
|
||||||
m = lb_pkg_module(gen, e->pkg);
|
m = lb_module_of_entity(gen, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (is_type_integer(e->type)) {
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs");
|
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);
|
GB_ASSERT(incoming_values.count > 0);
|
||||||
|
|
||||||
LLVMTypeRef phi_type = nullptr;
|
LLVMTypeRef phi_type = nullptr;
|
||||||
for_array(i, incoming_values) {
|
for (LLVMValueRef incoming_value : incoming_values) {
|
||||||
LLVMValueRef incoming_value = incoming_values[i];
|
|
||||||
if (!LLVMIsConstant(incoming_value)) {
|
if (!LLVMIsConstant(incoming_value)) {
|
||||||
phi_type = LLVMTypeOf(incoming_value);
|
phi_type = LLVMTypeOf(incoming_value);
|
||||||
break;
|
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) {
|
switch (op) {
|
||||||
case Token_Add:
|
case Token_Add:
|
||||||
return x;
|
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);
|
Type *elem_type = base_array_type(type);
|
||||||
|
|
||||||
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
|
// 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);
|
lbValue res = lb_addr_get_ptr(p, res_addr);
|
||||||
|
|
||||||
bool inline_array_arith = lb_can_try_to_inline_array_arith(type);
|
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;
|
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));
|
GB_ASSERT(is_type_array_like(type));
|
||||||
Type *elem_type = base_array_type(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));
|
GB_ASSERT(is_type_array_like(lhs.type) || is_type_array_like(rhs.type));
|
||||||
|
|
||||||
lhs = lb_emit_conv(p, lhs, 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);
|
Type *mt = base_type(t);
|
||||||
GB_ASSERT(mt->kind == Type_Matrix);
|
GB_ASSERT(mt->kind == Type_Matrix);
|
||||||
|
|
||||||
@@ -511,6 +510,11 @@ bool lb_is_matrix_simdable(Type *t) {
|
|||||||
break;
|
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) {
|
if (elem->kind == Type_Basic) {
|
||||||
switch (elem->Basic.kind) {
|
switch (elem->Basic.kind) {
|
||||||
case Basic_f16:
|
case Basic_f16:
|
||||||
@@ -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);
|
Type *mt = base_type(matrix.type);
|
||||||
GB_ASSERT(mt->kind == Type_Matrix);
|
GB_ASSERT(mt->kind == Type_Matrix);
|
||||||
LLVMTypeRef elem_type = lb_type(p->module, mt->Matrix.elem);
|
LLVMTypeRef elem_type = lb_type(p->module, mt->Matrix.elem);
|
||||||
@@ -554,7 +558,7 @@ LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
|
|||||||
#endif
|
#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);
|
mt = base_type(mt);
|
||||||
GB_ASSERT(mt->kind == Type_Matrix);
|
GB_ASSERT(mt->kind == Type_Matrix);
|
||||||
|
|
||||||
@@ -574,7 +578,7 @@ LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) {
|
|||||||
return mask;
|
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);
|
LLVMValueRef vector = lb_matrix_to_vector(p, m);
|
||||||
|
|
||||||
Type *mt = base_type(m.type);
|
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)) {
|
if (is_type_array(m.type)) {
|
||||||
i32 rank = type_math_rank(m.type);
|
i32 rank = type_math_rank(m.type);
|
||||||
if (rank == 2) {
|
if (rank == 2) {
|
||||||
@@ -669,7 +673,7 @@ lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
|
|||||||
return lb_addr_load(p, res);
|
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);
|
lbAddr res = lb_add_local_generated(p, type, true);
|
||||||
LLVMValueRef res_ptr = res.addr.value;
|
LLVMValueRef res_ptr = res.addr.value;
|
||||||
unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(LLVMTypeOf(vector)));
|
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);
|
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)) {
|
if (is_type_array(m.type)) {
|
||||||
// no-op
|
// no-op
|
||||||
m.type = type;
|
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 *mt = base_type(type);
|
||||||
Type *at = base_type(a.type);
|
Type *at = base_type(a.type);
|
||||||
Type *bt = base_type(b.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
|
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
|
||||||
|
|
||||||
Type *xt = base_type(lhs.type);
|
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
|
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
|
||||||
|
|
||||||
Type *mt = base_type(lhs.type);
|
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);
|
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
|
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
|
||||||
|
|
||||||
Type *mt = base_type(rhs.type);
|
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));
|
GB_ASSERT(is_type_matrix(lhs.type) || is_type_matrix(rhs.type));
|
||||||
|
|
||||||
if (op == Token_Mul && !component_wise) {
|
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)) {
|
if (is_type_array_like(lhs.type) || is_type_array_like(rhs.type)) {
|
||||||
return lb_emit_arith_array(p, op, lhs, rhs, type);
|
return lb_emit_arith_array(p, op, lhs, rhs, type);
|
||||||
} else if (is_type_matrix(lhs.type) || is_type_matrix(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)) {
|
if (is_type_integer(type) && is_type_different_to_arch_endianness(type)) {
|
||||||
switch (op) {
|
switch (op) {
|
||||||
case Token_AndNot:
|
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);
|
return lb_emit_byte_swap(p, res, type);
|
||||||
}
|
}
|
||||||
|
|
||||||
handle_op:
|
handle_op:;
|
||||||
lhs = lb_emit_conv(p, lhs, type);
|
|
||||||
rhs = lb_emit_conv(p, rhs, type);
|
|
||||||
|
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
res.type = type;
|
res.type = type;
|
||||||
|
|
||||||
@@ -1325,7 +1329,7 @@ handle_op:
|
|||||||
return {};
|
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);
|
ast_node(be, BinaryExpr, expr);
|
||||||
|
|
||||||
TypeAndValue tv = type_and_value_of_expr(expr);
|
TypeAndValue tv = type_and_value_of_expr(expr);
|
||||||
@@ -1472,7 +1476,7 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
|
|||||||
return {};
|
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;
|
lbModule *m = p->module;
|
||||||
t = reduce_tuple_to_single_type(t);
|
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) {
|
if (is_type_boolean(src) && dst == t_llvm_bool) {
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), "");
|
res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), "");
|
||||||
res.type = dst;
|
res.type = t;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (src == t_llvm_bool && is_type_boolean(dst)) {
|
if (src == t_llvm_bool && is_type_boolean(dst)) {
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
res.value = LLVMBuildZExt(p->builder, value.value, lb_type(m, dst), "");
|
res.value = LLVMBuildZExt(p->builder, value.value, lb_type(m, dst), "");
|
||||||
res.type = dst;
|
res.type = t;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1921,8 +1925,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (is_type_union(dst)) {
|
if (is_type_union(dst)) {
|
||||||
for_array(i, dst->Union.variants) {
|
for (Type *vt : dst->Union.variants) {
|
||||||
Type *vt = dst->Union.variants[i];
|
|
||||||
if (are_types_identical(vt, src_type)) {
|
if (are_types_identical(vt, src_type)) {
|
||||||
lbAddr parent = lb_add_local_generated(p, t, true);
|
lbAddr parent = lb_add_local_generated(p, t, true);
|
||||||
lb_emit_store_union_variant(p, parent.addr, value, vt);
|
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
|
// bit_set <-> integer
|
||||||
if (is_type_integer(src) && is_type_bit_set(dst)) {
|
if (is_type_integer(src) && is_type_bit_set(dst)) {
|
||||||
lbValue res = lb_emit_conv(p, value, bit_set_to_int(dst));
|
lbValue res = lb_emit_conv(p, value, bit_set_to_int(dst));
|
||||||
res.type = dst;
|
res.type = t;
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
if (is_type_bit_set(src) && is_type_integer(dst)) {
|
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 {};
|
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));
|
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 left_ptr = lb_address_from_load_or_generate_local(p, left);
|
||||||
lbValue right_ptr = lb_address_from_load_or_generate_local(p, right);
|
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 *a = core_type(left.type);
|
||||||
Type *b = core_type(right.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 = {};
|
lbValue res = {};
|
||||||
res.type = t_llvm_bool;
|
res.type = t_llvm_bool;
|
||||||
Type *t = x.type;
|
Type *t = x.type;
|
||||||
@@ -2803,7 +2806,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
|
|||||||
return {};
|
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);
|
lbAddr v = lb_add_local_generated(p, type, false);
|
||||||
lbValue ptr = lb_emit_struct_ep(p, v.addr, 0);
|
lbValue ptr = lb_emit_struct_ep(p, v.addr, 0);
|
||||||
lbValue idx = lb_emit_struct_ep(p, v.addr, 1);
|
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);
|
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);
|
ast_node(ue, UnaryExpr, expr);
|
||||||
auto tv = type_and_value_of_expr(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);
|
return lb_build_addr_ptr(p, ue->expr);
|
||||||
}
|
}
|
||||||
|
|
||||||
lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr);
|
gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr);
|
||||||
lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
||||||
u16 prev_state_flags = p->state_flags;
|
u16 prev_state_flags = p->state_flags;
|
||||||
defer (p->state_flags = prev_state_flags);
|
defer (p->state_flags = prev_state_flags);
|
||||||
|
|
||||||
@@ -3080,7 +3083,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
|
|||||||
return res;
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
expr = unparen_expr(expr);
|
expr = unparen_expr(expr);
|
||||||
@@ -3099,6 +3102,9 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
|||||||
|
|
||||||
// NOTE(bill): Short on constant values
|
// NOTE(bill): Short on constant values
|
||||||
return lb_const_value(p->module, type, tv.value);
|
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) {
|
switch (expr->kind) {
|
||||||
@@ -3355,10 +3361,10 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
|
|||||||
return {};
|
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);
|
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);
|
GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using);
|
||||||
String name = e->token.string;
|
String name = e->token.string;
|
||||||
Entity *parent = e->using_parent;
|
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);
|
GB_ASSERT(e != nullptr);
|
||||||
if (e->kind == Entity_Constant) {
|
if (e->kind == Entity_Constant) {
|
||||||
Type *t = default_type(type_of_expr(expr));
|
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);
|
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;
|
isize index_count = ce->args.count-1;
|
||||||
lbAddr addr = lb_build_addr(p, ce->args[0]);
|
lbAddr addr = lb_build_addr(p, ce->args[0]);
|
||||||
if (index_count == 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);
|
gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr);
|
||||||
lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
gb_internal lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
||||||
expr = unparen_expr(expr);
|
expr = unparen_expr(expr);
|
||||||
|
|
||||||
// IMPORTANT NOTE(bill):
|
// IMPORTANT NOTE(bill):
|
||||||
@@ -3489,7 +3495,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
|
|||||||
return addr;
|
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 *bt = base_type(compound_type);
|
||||||
Type *et = nullptr;
|
Type *et = nullptr;
|
||||||
switch (bt->kind) {
|
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) {
|
gb_internal void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array<lbCompoundLitElemTempData> const &temp_data) {
|
||||||
for_array(i, temp_data) {
|
for (auto const &td : temp_data) {
|
||||||
auto td = temp_data[i];
|
|
||||||
if (td.value.value != nullptr) {
|
if (td.value.value != nullptr) {
|
||||||
if (td.elem_length > 0) {
|
if (td.elem_length > 0) {
|
||||||
auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32);
|
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);
|
ast_node(ie, IndexExpr, expr);
|
||||||
|
|
||||||
Type *t = base_type(type_of_expr(ie->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);
|
ast_node(se, SliceExpr, expr);
|
||||||
|
|
||||||
lbValue low = lb_const_int(p->module, t_int, 0);
|
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);
|
ast_node(cl, CompoundLit, expr);
|
||||||
|
|
||||||
Type *type = type_of_expr(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);
|
lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
|
||||||
gb_unused(err);
|
gb_unused(err);
|
||||||
|
|
||||||
for_array(field_index, cl->elems) {
|
for (Ast *elem : cl->elems) {
|
||||||
Ast *elem = cl->elems[field_index];
|
|
||||||
ast_node(fv, FieldValue, elem);
|
ast_node(fv, FieldValue, elem);
|
||||||
|
|
||||||
lbValue key = lb_build_expr(p, fv->field);
|
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)));
|
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));
|
lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower));
|
||||||
for_array(i, cl->elems) {
|
for (Ast *elem : cl->elems) {
|
||||||
Ast *elem = cl->elems[i];
|
|
||||||
GB_ASSERT(elem->kind != Ast_FieldValue);
|
GB_ASSERT(elem->kind != Ast_FieldValue);
|
||||||
|
|
||||||
if (lb_is_elem_const(elem, et)) {
|
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`
|
// TODO(bill): reduce the need for individual `insertelement` if a `shufflevector`
|
||||||
// might be a better option
|
// might be a better option
|
||||||
for_array(i, temp_data) {
|
for (auto const &td : temp_data) {
|
||||||
auto td = temp_data[i];
|
|
||||||
if (td.value.value != nullptr) {
|
if (td.value.value != nullptr) {
|
||||||
if (td.elem_length > 0) {
|
if (td.elem_length > 0) {
|
||||||
for (i64 k = 0; k < td.elem_length; k++) {
|
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) {
|
switch (expr->kind) {
|
||||||
case_ast_node(i, Implicit, expr);
|
case_ast_node(i, Implicit, expr);
|
||||||
lbAddr v = {};
|
lbAddr v = {};
|
||||||
|
|||||||
+190
-216
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);
|
gb_internal 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);
|
gb_internal 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);
|
gb_internal 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_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level);
|
||||||
|
|
||||||
LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data) {
|
// gb_internal LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data) {
|
||||||
lbModule *m = cast(lbModule *)user_data;
|
// lbModule *m = cast(lbModule *)user_data;
|
||||||
if (m == nullptr) {
|
// if (m == nullptr) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
if (value == nullptr) {
|
// if (value == nullptr) {
|
||||||
return false;
|
// return false;
|
||||||
}
|
// }
|
||||||
return LLVMIsAAllocaInst(value) != nullptr;
|
// return LLVMIsAAllocaInst(value) != nullptr;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
#if LLVM_VERSION_MAJOR < 12
|
#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)
|
#define LLVM_ADD_CONSTANT_VALUE_PASS(fpm)
|
||||||
#endif
|
#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) {
|
if (false && optimization_level == 0 && build_context.ODIN_DEBUG) {
|
||||||
LLVMAddMergedLoadStoreMotionPass(fpm);
|
LLVMAddMergedLoadStoreMotionPass(fpm);
|
||||||
} else {
|
} 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
|
// NOTE(bill): Treat -opt:3 as if it was -opt:2
|
||||||
// TODO(bill): Determine which opt definitions should exist in the first place
|
// TODO(bill): Determine which opt definitions should exist in the first place
|
||||||
optimization_level = gb_clamp(optimization_level, 0, 2);
|
optimization_level = gb_clamp(optimization_level, 0, 2);
|
||||||
@@ -102,7 +102,7 @@ void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool
|
|||||||
#endif
|
#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
|
// NOTE(bill): Treat -opt:3 as if it was -opt:2
|
||||||
// TODO(bill): Determine which opt definitions should exist in the first place
|
// TODO(bill): Determine which opt definitions should exist in the first place
|
||||||
optimization_level = gb_clamp(optimization_level, 0, 2);
|
optimization_level = gb_clamp(optimization_level, 0, 2);
|
||||||
@@ -141,7 +141,7 @@ void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef
|
|||||||
#endif
|
#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);
|
LLVMAddCFGSimplificationPass(mpm);
|
||||||
|
|
||||||
LLVMAddJumpThreadingPass(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
|
// NOTE(bill): Treat -opt:3 as if it was -opt:2
|
||||||
// TODO(bill): Determine which opt definitions should exist in the first place
|
// 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
|
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 removal_count = 0;
|
||||||
isize pass_count = 0;
|
isize pass_count = 0;
|
||||||
isize const max_pass_count = 10;
|
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);
|
LLVMRunFunctionPassManager(fpm, p->value);
|
||||||
// NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM
|
// NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM
|
||||||
// which means we cannot rely upon it
|
// 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);
|
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; /**/) {
|
// for (LLVMBasicBlockRef block = LLVMGetFirstBasicBlock(func); block != nullptr; /**/) {
|
||||||
// LLVMBasicBlockRef curr_block = block;
|
// LLVMBasicBlockRef curr_block = block;
|
||||||
// block = LLVMGetNextBasicBlock(block);
|
// block = LLVMGetNextBasicBlock(block);
|
||||||
@@ -382,7 +385,7 @@ void llvm_delete_function(LLVMValueRef func) {
|
|||||||
LLVMDeleteFunction(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 global = LLVMGetNamedGlobal(m->mod, "llvm.compiler.used");
|
||||||
|
|
||||||
LLVMValueRef *constants;
|
LLVMValueRef *constants;
|
||||||
@@ -419,7 +422,7 @@ void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) {
|
|||||||
LLVMSetInitializer(global, initializer);
|
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 removal_count = 0;
|
||||||
isize pass_count = 0;
|
isize pass_count = 0;
|
||||||
isize const max_pass_count = 10;
|
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 removal_count = 0;
|
||||||
isize pass_count = 0;
|
isize pass_count = 0;
|
||||||
isize const max_pass_count = 10;
|
isize const max_pass_count = 10;
|
||||||
|
|||||||
+244
-118
@@ -1,6 +1,4 @@
|
|||||||
|
gb_internal LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) {
|
||||||
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));
|
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
|
||||||
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
|
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
|
||||||
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, type_count);
|
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, "");
|
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);
|
dst = lb_emit_conv(p, dst, t_rawptr);
|
||||||
src = lb_emit_conv(p, src, t_rawptr);
|
src = lb_emit_conv(p, src, t_rawptr);
|
||||||
len = lb_emit_conv(p, len, t_int);
|
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);
|
dst = lb_emit_conv(p, dst, t_rawptr);
|
||||||
src = lb_emit_conv(p, src, t_rawptr);
|
src = lb_emit_conv(p, src, t_rawptr);
|
||||||
len = lb_emit_conv(p, len, t_int);
|
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 != nullptr);
|
||||||
GB_ASSERT(entity->kind == Entity_Procedure);
|
GB_ASSERT(entity->kind == Entity_Procedure);
|
||||||
if (!entity->Procedure.is_foreign) {
|
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 = {};
|
String link_name = {};
|
||||||
|
|
||||||
if (ignore_body) {
|
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);
|
link_name = lb_get_entity_name(other_module, entity);
|
||||||
} else {
|
} else {
|
||||||
link_name = lb_get_entity_name(m, entity);
|
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->branch_blocks.allocator = a;
|
||||||
p->context_stack.allocator = a;
|
p->context_stack.allocator = a;
|
||||||
p->scope_stack.allocator = a;
|
p->scope_stack.allocator = a;
|
||||||
map_init(&p->selector_values, a, 0);
|
map_init(&p->selector_values, 0);
|
||||||
map_init(&p->selector_addr, a, 0);
|
map_init(&p->selector_addr, 0);
|
||||||
|
map_init(&p->tuple_fix_map, 0);
|
||||||
|
|
||||||
if (p->is_foreign) {
|
if (p->is_foreign) {
|
||||||
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
|
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");
|
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) {
|
if (p->is_export) {
|
||||||
LLVMSetLinkage(p->value, LLVMDLLExportLinkage);
|
LLVMSetLinkage(p->value, LLVMDLLExportLinkage);
|
||||||
LLVMSetDLLStorageClass(p->value, LLVMDLLExportStorageClass);
|
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);
|
lb_set_wasm_export_attributes(p->value, p->name);
|
||||||
} else if (!p->is_foreign) {
|
} else if (!p->is_foreign) {
|
||||||
if (!USE_SEPARATE_MODULES) {
|
if (USE_SEPARATE_MODULES) {
|
||||||
|
LLVMSetLinkage(p->value, LLVMExternalLinkage);
|
||||||
|
} else {
|
||||||
LLVMSetLinkage(p->value, LLVMInternalLinkage);
|
LLVMSetLinkage(p->value, LLVMInternalLinkage);
|
||||||
|
|
||||||
// NOTE(bill): if a procedure is defined in package runtime and uses a custom link name,
|
// 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;
|
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);
|
lbValue *found = string_map_get(&m->members, link_name);
|
||||||
GB_ASSERT_MSG(found == nullptr, "failed to create dummy procedure for: %.*s", LIT(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->blocks.allocator = a;
|
||||||
p->branch_blocks.allocator = a;
|
p->branch_blocks.allocator = a;
|
||||||
p->context_stack.allocator = a;
|
p->context_stack.allocator = a;
|
||||||
|
map_init(&p->tuple_fix_map, 0);
|
||||||
|
|
||||||
|
|
||||||
char *c_link_name = alloc_cstring(permanent_allocator(), p->name);
|
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_) {
|
// gb_internal lbValue lb_value_param(lbProcedure *p, Entity *e, Type *abi_type, i32 index, lbParamPasskind *kind_) {
|
||||||
lbParamPasskind kind = lbParamPass_Value;
|
// lbParamPasskind kind = lbParamPass_Value;
|
||||||
|
|
||||||
if (e != nullptr && !are_types_identical(abi_type, e->type)) {
|
// if (e != nullptr && !are_types_identical(abi_type, e->type)) {
|
||||||
if (is_type_pointer(abi_type)) {
|
// if (is_type_pointer(abi_type)) {
|
||||||
GB_ASSERT(e->kind == Entity_Variable);
|
// GB_ASSERT(e->kind == Entity_Variable);
|
||||||
Type *av = core_type(type_deref(abi_type));
|
// Type *av = core_type(type_deref(abi_type));
|
||||||
if (are_types_identical(av, core_type(e->type))) {
|
// if (are_types_identical(av, core_type(e->type))) {
|
||||||
kind = lbParamPass_Pointer;
|
// kind = lbParamPass_Pointer;
|
||||||
if (e->flags&EntityFlag_Value) {
|
// if (e->flags&EntityFlag_Value) {
|
||||||
kind = lbParamPass_ConstRef;
|
// kind = lbParamPass_ConstRef;
|
||||||
}
|
// }
|
||||||
} else {
|
// } else {
|
||||||
kind = lbParamPass_BitCast;
|
// kind = lbParamPass_BitCast;
|
||||||
}
|
// }
|
||||||
} else if (is_type_integer(abi_type)) {
|
// } else if (is_type_integer(abi_type)) {
|
||||||
kind = lbParamPass_Integer;
|
// kind = lbParamPass_Integer;
|
||||||
} else if (abi_type == t_llvm_bool) {
|
// } else if (abi_type == t_llvm_bool) {
|
||||||
kind = lbParamPass_Value;
|
// kind = lbParamPass_Value;
|
||||||
} else if (is_type_boolean(abi_type)) {
|
// } else if (is_type_boolean(abi_type)) {
|
||||||
kind = lbParamPass_Integer;
|
// kind = lbParamPass_Integer;
|
||||||
} else if (is_type_simd_vector(abi_type)) {
|
// } else if (is_type_simd_vector(abi_type)) {
|
||||||
kind = lbParamPass_BitCast;
|
// kind = lbParamPass_BitCast;
|
||||||
} else if (is_type_float(abi_type)) {
|
// } else if (is_type_float(abi_type)) {
|
||||||
kind = lbParamPass_BitCast;
|
// kind = lbParamPass_BitCast;
|
||||||
} else if (is_type_tuple(abi_type)) {
|
// } else if (is_type_tuple(abi_type)) {
|
||||||
kind = lbParamPass_Tuple;
|
// kind = lbParamPass_Tuple;
|
||||||
} else if (is_type_proc(abi_type)) {
|
// } else if (is_type_proc(abi_type)) {
|
||||||
kind = lbParamPass_Value;
|
// kind = lbParamPass_Value;
|
||||||
} else {
|
// } else {
|
||||||
GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type));
|
// GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type));
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (kind_) *kind_ = kind;
|
// if (kind_) *kind_ = kind;
|
||||||
lbValue res = {};
|
// lbValue res = {};
|
||||||
res.value = LLVMGetParam(p->value, cast(unsigned)index);
|
// res.value = LLVMGetParam(p->value, cast(unsigned)index);
|
||||||
res.type = abi_type;
|
// res.type = abi_type;
|
||||||
return res;
|
// return res;
|
||||||
}
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void lb_start_block(lbProcedure *p, lbBlock *b) {
|
gb_internal void lb_start_block(lbProcedure *p, lbBlock *b) {
|
||||||
GB_ASSERT(b != nullptr);
|
GB_ASSERT(b != nullptr);
|
||||||
if (!b->appended) {
|
if (!b->appended) {
|
||||||
b->appended = true;
|
b->appended = true;
|
||||||
@@ -436,7 +440,7 @@ void lb_start_block(lbProcedure *p, lbBlock *b) {
|
|||||||
p->curr_block = 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) {
|
if (p->debug_info == nullptr) {
|
||||||
return;
|
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) {
|
if (p->debug_info == nullptr) {
|
||||||
return;
|
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);
|
DeclInfo *decl = decl_info_of_entity(p->entity);
|
||||||
if (decl != nullptr) {
|
if (decl != nullptr) {
|
||||||
for_array(i, decl->labels) {
|
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);
|
p->entry_block = lb_create_block(p, "entry", true);
|
||||||
lb_start_block(p, p->entry_block);
|
lb_start_block(p, p->entry_block);
|
||||||
|
|
||||||
map_init(&p->direct_parameters, heap_allocator());
|
map_init(&p->direct_parameters);
|
||||||
|
|
||||||
GB_ASSERT(p->type != nullptr);
|
GB_ASSERT(p->type != nullptr);
|
||||||
|
|
||||||
@@ -501,8 +505,23 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
|||||||
// NOTE(bill): this must be parameter 0
|
// NOTE(bill): this must be parameter 0
|
||||||
|
|
||||||
String name = str_lit("agg.result");
|
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);
|
Entity *e = alloc_entity_param(nullptr, make_token_ident(name), ptr_type, false, false);
|
||||||
e->flags |= EntityFlag_NoAlias;
|
e->flags |= EntityFlag_NoAlias;
|
||||||
|
|
||||||
@@ -580,6 +599,58 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
|||||||
if (e->token.string != "") {
|
if (e->token.string != "") {
|
||||||
GB_ASSERT(!is_blank_ident(e->token));
|
GB_ASSERT(!is_blank_ident(e->token));
|
||||||
|
|
||||||
|
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
|
// NOTE(bill): Don't even bother trying to optimize this with the return ptr value
|
||||||
// This will violate the defer rules if you do:
|
// This will violate the defer rules if you do:
|
||||||
// foo :: proc() -> (x, y: T) {
|
// foo :: proc() -> (x, y: T) {
|
||||||
@@ -587,7 +658,11 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
|||||||
// return // the values returned should be zeroed
|
// return // the values returned should be zeroed
|
||||||
// }
|
// }
|
||||||
// NOTE(bill): REALLY, don't even bother.
|
// NOTE(bill): REALLY, don't even bother.
|
||||||
lbAddr res = lb_add_local(p, e->type, e);
|
//
|
||||||
|
// IMPORTANT NOTE(bill): REALLY, don't even bother!!!!!!
|
||||||
|
res = lb_add_local(p, e->type, e);
|
||||||
|
}
|
||||||
|
|
||||||
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
|
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
|
||||||
lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
|
lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
|
||||||
lb_addr_store(p, res, c);
|
lb_addr_store(p, res, c);
|
||||||
@@ -614,7 +689,7 @@ void lb_begin_procedure_body(lbProcedure *p) {
|
|||||||
lb_start_block(p, p->entry_block);
|
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);
|
lb_set_debug_position_to_procedure_begin(p);
|
||||||
|
|
||||||
LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block);
|
LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block);
|
||||||
@@ -648,11 +723,11 @@ void lb_end_procedure_body(lbProcedure *p) {
|
|||||||
p->curr_block = nullptr;
|
p->curr_block = nullptr;
|
||||||
p->state_flags = 0;
|
p->state_flags = 0;
|
||||||
}
|
}
|
||||||
void lb_end_procedure(lbProcedure *p) {
|
gb_internal void lb_end_procedure(lbProcedure *p) {
|
||||||
LLVMDisposeBuilder(p->builder);
|
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);
|
GB_ASSERT(pd->body != nullptr);
|
||||||
lbModule *m = p->module;
|
lbModule *m = p->module;
|
||||||
auto *min_dep_set = &m->info->minimum_dependency_set;
|
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 = {};
|
Array<lbValue> array = {};
|
||||||
Type *t = base_type(value.type);
|
Type *t = base_type(value.type);
|
||||||
if (t == nullptr) {
|
if (t == nullptr) {
|
||||||
// Do nothing
|
// Do nothing
|
||||||
} else if (is_type_tuple(t)) {
|
} else if (is_type_tuple(t)) {
|
||||||
GB_ASSERT(t->kind == Type_Tuple);
|
array = array_make<lbValue>(permanent_allocator(), 0, t->Tuple.variables.count);
|
||||||
auto *rt = &t->Tuple;
|
lb_append_tuple_values(p, &array, value);
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
array = array_make<lbValue>(permanent_allocator(), 1);
|
array = array_make<lbValue>(permanent_allocator(), 1);
|
||||||
array[0] = value;
|
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)));
|
GB_ASSERT(p->module->ctx == LLVMGetTypeContext(LLVMTypeOf(value.value)));
|
||||||
|
|
||||||
unsigned arg_count = cast(unsigned)processed_args.count;
|
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) {
|
if (return_ptr.value != nullptr) {
|
||||||
args[arg_index++] = return_ptr.value;
|
args[arg_index++] = return_ptr.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
for_array(i, processed_args) {
|
for_array(i, processed_args) {
|
||||||
lbValue arg = processed_args[i];
|
lbValue arg = processed_args[i];
|
||||||
if (is_type_proc(arg.type)) {
|
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;
|
args[arg_index++] = arg.value;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context_ptr.addr.value != nullptr) {
|
if (context_ptr.addr.value != nullptr) {
|
||||||
LLVMValueRef cp = context_ptr.addr.value;
|
LLVMValueRef cp = context_ptr.addr.value;
|
||||||
cp = LLVMBuildPointerCast(p->builder, cp, lb_type(p->module, t_rawptr), "");
|
cp = LLVMBuildPointerCast(p->builder, cp, lb_type(p->module, t_rawptr), "");
|
||||||
args[arg_index++] = cp;
|
args[arg_index++] = cp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GB_ASSERT(arg_index == arg_count);
|
||||||
|
|
||||||
LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder);
|
LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder);
|
||||||
GB_ASSERT(curr_block != p->decl_block->block);
|
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);
|
LLVMTypeRef ftp = LLVMPointerType(fnp, 0);
|
||||||
LLVMValueRef fn = value.value;
|
LLVMValueRef fn = value.value;
|
||||||
if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) {
|
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);
|
// LLVMTypeKind arg_kind = LLVMGetTypeKind(arg_type);
|
||||||
GB_ASSERT_MSG(
|
GB_ASSERT_MSG(
|
||||||
arg_type == param_type,
|
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(arg_type),
|
||||||
LLVMPrintTypeToString(param_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;
|
AstPackage *pkg = m->info->runtime_package;
|
||||||
Entity *e = scope_lookup_current(pkg->scope, name);
|
Entity *e = scope_lookup_current(pkg->scope, name);
|
||||||
return lb_find_procedure_value_from_entity(m, e);
|
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);
|
String name = make_string_c(c_name);
|
||||||
lbValue proc = lb_lookup_runtime_procedure(p->module, name);
|
lbValue proc = lb_lookup_runtime_procedure(p->module, name);
|
||||||
return lb_emit_call(p, proc, args);
|
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 = {};
|
lbValue res = {};
|
||||||
Type *t = val.type;
|
Type *t = val.type;
|
||||||
if (is_type_complex(t)) {
|
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);
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
Type *pt = base_type(value.type);
|
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);
|
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 return_by_pointer = ft->ret.kind == lbArg_Indirect;
|
||||||
|
bool split_returns = ft->multiple_return_original_type != nullptr;
|
||||||
|
|
||||||
unsigned param_index = 0;
|
unsigned param_index = 0;
|
||||||
for (isize i = 0; i < param_count; i++) {
|
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 *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) {
|
if (return_by_pointer) {
|
||||||
lbValue return_ptr = {};
|
lbValue return_ptr = lb_add_local_generated(p, rt, true).addr;
|
||||||
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));
|
|
||||||
lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining);
|
lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining);
|
||||||
result = lb_emit_load(p, return_ptr);
|
result = lb_emit_load(p, return_ptr);
|
||||||
} else if (rt != nullptr) {
|
} 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);
|
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);
|
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;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
LLVMValueRef llvm_splat_float(i64 count, LLVMTypeRef type, f64 value) {
|
gb_internal LLVMValueRef llvm_splat_int(i64 count, LLVMTypeRef type, i64 value, bool is_signed=false) {
|
||||||
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) {
|
|
||||||
LLVMValueRef v = LLVMConstInt(type, value, is_signed);
|
LLVMValueRef v = LLVMConstInt(type, value, is_signed);
|
||||||
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
|
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
|
||||||
for (i64 i = 0; i < count; i++) {
|
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);
|
ast_node(ce, CallExpr, expr);
|
||||||
|
|
||||||
lbModule *m = p->module;
|
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);
|
ast_node(ce, CallExpr, expr);
|
||||||
|
|
||||||
if (BuiltinProc__simd_begin < id && id < BuiltinProc__simd_end) {
|
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);
|
LLVMSetWeak(value, weak);
|
||||||
|
|
||||||
if (tv.type->kind == Type_Tuple) {
|
if (is_type_tuple(tv.type)) {
|
||||||
Type *fix_typed = alloc_type_tuple();
|
Type *fix_typed = alloc_type_tuple();
|
||||||
slice_init(&fix_typed->Tuple.variables, permanent_allocator(), 2);
|
slice_init(&fix_typed->Tuple.variables, permanent_allocator(), 2);
|
||||||
fix_typed->Tuple.variables[0] = tv.type->Tuple.variables[0];
|
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);
|
LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
|
||||||
LLVMValueRef the_asm = llvm_get_inline_asm(
|
LLVMValueRef the_asm = llvm_get_inline_asm(
|
||||||
func_type,
|
func_type,
|
||||||
str_lit("rolq $3, %rdi; rolq $13, %rdi\n rolq $61, %rdi; rolq $51, %rdi\n xchgq %rbx, %rbx"),
|
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("={rdx},{rdx},{rax},~{cc},~{memory}"),
|
||||||
true
|
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) {
|
switch (param_value.kind) {
|
||||||
case ParameterValue_Constant:
|
case ParameterValue_Constant:
|
||||||
if (is_type_constant_type(parameter_type)) {
|
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);
|
expr = unparen_expr(expr);
|
||||||
ast_node(ce, CallExpr, expr);
|
ast_node(ce, CallExpr, expr);
|
||||||
|
|
||||||
@@ -2913,7 +3025,7 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
|
|||||||
}
|
}
|
||||||
return res;
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
TypeAndValue tv = type_and_value_of_expr(expr);
|
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);
|
GB_ASSERT(e->kind == Entity_Variable);
|
||||||
if (args[i].value == nullptr) {
|
if (args[i].value == nullptr) {
|
||||||
args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos);
|
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 {
|
} else {
|
||||||
args[i] = lb_emit_conv(p, args[i], e->type);
|
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;
|
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_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));
|
GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg));
|
||||||
Type *at = tav.type;
|
Type *at = tav.type;
|
||||||
if (at->kind == Type_Tuple) {
|
if (is_type_tuple(at)) {
|
||||||
arg_count += at->Tuple.variables.count;
|
arg_count += at->Tuple.variables.count;
|
||||||
} else {
|
} else {
|
||||||
arg_count++;
|
arg_count++;
|
||||||
@@ -3084,10 +3198,17 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
|||||||
lbValue a = lb_build_expr(p, arg);
|
lbValue a = lb_build_expr(p, arg);
|
||||||
Type *at = a.type;
|
Type *at = a.type;
|
||||||
if (at->kind == Type_Tuple) {
|
if (at->kind == Type_Tuple) {
|
||||||
for_array(i, at->Tuple.variables) {
|
lbTupleFix *tf = map_get(&p->tuple_fix_map, a.value);
|
||||||
lbValue v = lb_emit_struct_ev(p, a, cast(i32)i);
|
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;
|
args[arg_index++] = v;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
args[arg_index++] = a;
|
args[arg_index++] = a;
|
||||||
}
|
}
|
||||||
@@ -3157,10 +3278,15 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
GB_ASSERT_MSG(args[i].value != nullptr, "%.*s", LIT(e->token.string));
|
GB_ASSERT_MSG(args[i].value != nullptr, "%.*s", LIT(e->token.string));
|
||||||
|
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);
|
args[i] = lb_emit_conv(p, args[i], e->type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (variadic && !vari_expand && !is_c_vararg) {
|
if (variadic && !vari_expand && !is_c_vararg) {
|
||||||
// variadic call argument generation
|
// variadic call argument generation
|
||||||
@@ -3213,6 +3339,6 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
auto call_args = array_slice(args, 0, final_count);
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+151
-156
@@ -1,32 +1,4 @@
|
|||||||
lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, Ast *ast) {
|
gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
||||||
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) {
|
|
||||||
if (vd == nullptr || vd->is_mutable) {
|
if (vd == nullptr || vd->is_mutable) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -35,8 +7,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
|||||||
|
|
||||||
static i32 global_guid = 0;
|
static i32 global_guid = 0;
|
||||||
|
|
||||||
for_array(i, vd->names) {
|
for (Ast *ident : vd->names) {
|
||||||
Ast *ident = vd->names[i];
|
|
||||||
GB_ASSERT(ident->kind == Ast_Ident);
|
GB_ASSERT(ident->kind == Ast_Ident);
|
||||||
Entity *e = entity_of_node(ident);
|
Entity *e = entity_of_node(ident);
|
||||||
GB_ASSERT(e != nullptr);
|
GB_ASSERT(e != nullptr);
|
||||||
@@ -61,7 +32,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
|||||||
continue;
|
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) {
|
for_array(i, vd->names) {
|
||||||
@@ -79,21 +50,20 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
|
|||||||
continue; // It's an alias
|
continue; // It's an alias
|
||||||
}
|
}
|
||||||
|
|
||||||
CheckerInfo *info = p->module->info;
|
|
||||||
DeclInfo *decl = decl_info_of_entity(e);
|
DeclInfo *decl = decl_info_of_entity(e);
|
||||||
ast_node(pl, ProcLit, decl->proc_lit);
|
ast_node(pl, ProcLit, decl->proc_lit);
|
||||||
if (pl->body != nullptr) {
|
if (pl->body != nullptr) {
|
||||||
auto *found = map_get(&info->gen_procs, ident);
|
GenProcsData *gpd = e->Procedure.gen_procs;
|
||||||
if (found) {
|
if (gpd) {
|
||||||
auto procs = *found;
|
rw_mutex_shared_lock(&gpd->mutex);
|
||||||
for_array(i, procs) {
|
for (Entity *e : gpd->procs) {
|
||||||
Entity *e = procs[i];
|
|
||||||
if (!ptr_set_exists(min_dep_set, e)) {
|
if (!ptr_set_exists(min_dep_set, e)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
DeclInfo *d = decl_info_of_entity(e);
|
DeclInfo *d = decl_info_of_entity(e);
|
||||||
lb_build_nested_proc(p, &d->proc_lit->ProcLit, e);
|
lb_build_nested_proc(p, &d->proc_lit->ProcLit, e);
|
||||||
}
|
}
|
||||||
|
rw_mutex_shared_unlock(&gpd->mutex);
|
||||||
} else {
|
} else {
|
||||||
lb_build_nested_proc(p, pl, e);
|
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) {
|
gb_internal void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) {
|
||||||
for_array(i, stmts) {
|
for (Ast *stmt : stmts) {
|
||||||
Ast *stmt = stmts[i];
|
|
||||||
switch (stmt->kind) {
|
switch (stmt->kind) {
|
||||||
case_ast_node(vd, ValueDecl, stmt);
|
case_ast_node(vd, ValueDecl, stmt);
|
||||||
lb_build_constant_value_decl(p, vd);
|
lb_build_constant_value_decl(p, vd);
|
||||||
@@ -146,21 +115,20 @@ void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) {
|
|||||||
case_end;
|
case_end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for_array(i, stmts) {
|
for (Ast *stmt : stmts) {
|
||||||
lb_build_stmt(p, stmts[i]);
|
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);
|
GB_ASSERT(ident->kind == Ast_Ident);
|
||||||
Entity *e = entity_of_node(ident);
|
Entity *e = entity_of_node(ident);
|
||||||
GB_ASSERT(e->kind == Entity_Label);
|
GB_ASSERT(e->kind == Entity_Label);
|
||||||
for_array(i, p->branch_blocks) {
|
for (lbBranchBlocks const &b : p->branch_blocks) {
|
||||||
lbBranchBlocks *b = &p->branch_blocks[i];
|
if (b.label == e->Label.node) {
|
||||||
if (b->label == e->Label.node) {
|
return b;
|
||||||
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);
|
lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList);
|
||||||
tl->prev = p->target_list;
|
tl->prev = p->target_list;
|
||||||
tl->break_ = break_;
|
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
|
if (label != nullptr) { // Set label blocks
|
||||||
GB_ASSERT(label->kind == Ast_Label);
|
GB_ASSERT(label->kind == Ast_Label);
|
||||||
|
|
||||||
for_array(i, p->branch_blocks) {
|
for (lbBranchBlocks &b : p->branch_blocks) {
|
||||||
lbBranchBlocks *b = &p->branch_blocks[i];
|
GB_ASSERT(b.label != nullptr && label != nullptr);
|
||||||
GB_ASSERT(b->label != nullptr && label != nullptr);
|
GB_ASSERT(b.label->kind == Ast_Label);
|
||||||
GB_ASSERT(b->label->kind == Ast_Label);
|
if (b.label == label) {
|
||||||
if (b->label == label) {
|
b.break_ = break_;
|
||||||
b->break_ = break_;
|
b.continue_ = continue_;
|
||||||
b->continue_ = continue_;
|
|
||||||
return tl;
|
return tl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -198,11 +165,11 @@ lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, l
|
|||||||
return tl;
|
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;
|
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;
|
lbModule *m = p->module;
|
||||||
if (m->debug_builder) {
|
if (m->debug_builder) {
|
||||||
LLVMMetadataRef curr_metadata = lb_get_llvm_metadata(m, s);
|
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);
|
lb_emit_defer_stmts(p, kind, block);
|
||||||
GB_ASSERT(p->scope_index > 0);
|
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);
|
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);
|
TypeAndValue tv = type_and_value_of_expr(ws->cond);
|
||||||
GB_ASSERT(is_type_boolean(tv.type));
|
GB_ASSERT(is_type_boolean(tv.type));
|
||||||
GB_ASSERT(tv.value.kind == ExactValue_Bool);
|
GB_ASSERT(tv.value.kind == ExactValue_Bool);
|
||||||
@@ -281,7 +248,7 @@ void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
|
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_) {
|
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||||
lbModule *m = p->module;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
@@ -370,7 +337,7 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu
|
|||||||
if (done_) *done_ = done;
|
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 size, len;
|
||||||
i64 elem_sz = type_size_of(type);
|
i64 elem_sz = type_size_of(type);
|
||||||
map_cell_size_and_len(type, &size, &len);
|
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);
|
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_) {
|
gb_internal lbValue lb_map_hash_is_valid(lbProcedure *p, lbValue hash) {
|
||||||
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) {
|
|
||||||
// N :: size_of(uintptr)*8 - 1
|
// N :: size_of(uintptr)*8 - 1
|
||||||
// (hash != 0) & (hash>>N == 0)
|
// (hash != 0) & (hash>>N == 0)
|
||||||
|
|
||||||
@@ -432,7 +389,7 @@ lbValue lb_map_hash_is_valid(lbProcedure *p, lbValue hash) {
|
|||||||
return lb_emit_arith(p, Token_And, not_deleted, not_empty, t_uintptr);
|
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,
|
gb_internal void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type,
|
||||||
lbValue *val_, lbValue *key_, lbBlock **loop_, lbBlock **done_) {
|
lbValue *val_, lbValue *key_, lbBlock **loop_, lbBlock **done_) {
|
||||||
lbModule *m = p->module;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
@@ -494,7 +451,7 @@ void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type,
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
|
gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
|
||||||
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
|
||||||
lbModule *m = p->module;
|
lbModule *m = p->module;
|
||||||
lbValue count = lb_const_int(m, t_int, 0);
|
lbValue count = lb_const_int(m, t_int, 0);
|
||||||
@@ -554,7 +511,7 @@ void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
|
gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
|
||||||
AstRangeStmt *rs, Scope *scope) {
|
AstRangeStmt *rs, Scope *scope) {
|
||||||
bool ADD_EXTRA_WRAPPING_CHECK = true;
|
bool ADD_EXTRA_WRAPPING_CHECK = true;
|
||||||
|
|
||||||
@@ -658,7 +615,7 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
|
|||||||
lb_start_block(p, done);
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
Type *t = enum_type;
|
Type *t = enum_type;
|
||||||
@@ -711,7 +668,7 @@ void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValu
|
|||||||
if (done_) *done_ = done;
|
if (done_) *done_ = done;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type,
|
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_) {
|
lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) {
|
||||||
lbBlock *loop = lb_create_block(p, "for.tuple.loop");
|
lbBlock *loop = lb_create_block(p, "for.tuple.loop");
|
||||||
lb_emit_jump(p, loop);
|
lb_emit_jump(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 tuple_count = cast(i32)tuple->Tuple.variables.count;
|
||||||
i32 cond_index = tuple_count-1;
|
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_emit_if(p, cond, body, done);
|
||||||
lb_start_block(p, body);
|
lb_start_block(p, body);
|
||||||
|
|
||||||
|
|
||||||
if (val0_) *val0_ = lb_emit_struct_ev(p, tuple_value, 0);
|
if (val0_) *val0_ = lb_emit_tuple_ev(p, tuple_value, 0);
|
||||||
if (val1_) *val1_ = lb_emit_struct_ev(p, tuple_value, 1);
|
if (val1_) *val1_ = lb_emit_tuple_ev(p, tuple_value, 1);
|
||||||
if (loop_) *loop_ = loop;
|
if (loop_) *loop_ = loop;
|
||||||
if (done_) *done_ = done;
|
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);
|
Ast *expr = unparen_expr(rs->expr);
|
||||||
TypeAndValue tav = type_and_value_of_expr(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);
|
Ast *expr = unparen_expr(rs->expr);
|
||||||
|
|
||||||
if (is_ast_range(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);
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
lb_open_scope(p, scope); // Open scope here
|
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);
|
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) {
|
if (ss->tag == nullptr) {
|
||||||
return false;
|
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);
|
ast_node(body, BlockStmt, ss->body);
|
||||||
for_array(i, body->stmts) {
|
for (Ast *clause : body->stmts) {
|
||||||
Ast *clause = body->stmts[i];
|
|
||||||
ast_node(cc, CaseClause, clause);
|
ast_node(cc, CaseClause, clause);
|
||||||
|
|
||||||
if (cc->list.count == 0) {
|
if (cc->list.count == 0) {
|
||||||
@@ -1142,8 +1098,8 @@ bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_f
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for_array(j, cc->list) {
|
for (Ast *expr : cc->list) {
|
||||||
Ast *expr = unparen_expr(cc->list[j]);
|
expr = unparen_expr(expr);
|
||||||
if (is_ast_range(expr)) {
|
if (is_ast_range(expr)) {
|
||||||
return false;
|
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);
|
lb_open_scope(p, scope);
|
||||||
|
|
||||||
if (ss->init != nullptr) {
|
if (ss->init != nullptr) {
|
||||||
@@ -1204,8 +1160,7 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
|
|||||||
LLVMValueRef switch_instr = nullptr;
|
LLVMValueRef switch_instr = nullptr;
|
||||||
if (is_trivial) {
|
if (is_trivial) {
|
||||||
isize num_cases = 0;
|
isize num_cases = 0;
|
||||||
for_array(i, body->stmts) {
|
for (Ast *clause : body->stmts) {
|
||||||
Ast *clause = body->stmts[i];
|
|
||||||
ast_node(cc, CaseClause, clause);
|
ast_node(cc, CaseClause, clause);
|
||||||
num_cases += cc->list.count;
|
num_cases += cc->list.count;
|
||||||
}
|
}
|
||||||
@@ -1242,8 +1197,8 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
lbBlock *next_cond = nullptr;
|
lbBlock *next_cond = nullptr;
|
||||||
for_array(j, cc->list) {
|
for (Ast *expr : cc->list) {
|
||||||
Ast *expr = unparen_expr(cc->list[j]);
|
expr = unparen_expr(expr);
|
||||||
|
|
||||||
if (switch_instr != nullptr) {
|
if (switch_instr != nullptr) {
|
||||||
lbValue on_val = {};
|
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);
|
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);
|
Entity *e = implicit_entity_of_node(clause);
|
||||||
GB_ASSERT(e != nullptr);
|
GB_ASSERT(e != nullptr);
|
||||||
if (e->flags & EntityFlag_Value) {
|
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);
|
Entity *e = entity_of_node(stmt_val);
|
||||||
if (e == nullptr) {
|
if (e == nullptr) {
|
||||||
return {};
|
return {};
|
||||||
@@ -1363,7 +1318,7 @@ lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value) {
|
|||||||
return addr;
|
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);
|
ast_node(cc, CaseClause, clause);
|
||||||
|
|
||||||
lb_push_target_list(p, label, done, nullptr, nullptr);
|
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);
|
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;
|
lbModule *m = p->module;
|
||||||
lb_open_scope(p, ss->scope);
|
lb_open_scope(p, ss->scope);
|
||||||
|
|
||||||
@@ -1422,8 +1377,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
|||||||
lbBlock *default_block = nullptr;
|
lbBlock *default_block = nullptr;
|
||||||
isize num_cases = 0;
|
isize num_cases = 0;
|
||||||
|
|
||||||
for_array(i, body->stmts) {
|
for (Ast *clause : body->stmts) {
|
||||||
Ast *clause = body->stmts[i];
|
|
||||||
ast_node(cc, CaseClause, clause);
|
ast_node(cc, CaseClause, clause);
|
||||||
num_cases += cc->list.count;
|
num_cases += cc->list.count;
|
||||||
if (cc->list.count == 0) {
|
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);
|
switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
|
||||||
}
|
}
|
||||||
|
|
||||||
for_array(i, body->stmts) {
|
for (Ast *clause : body->stmts) {
|
||||||
Ast *clause = body->stmts[i];
|
|
||||||
ast_node(cc, CaseClause, clause);
|
ast_node(cc, CaseClause, clause);
|
||||||
lb_open_scope(p, cc->scope);
|
lb_open_scope(p, cc->scope);
|
||||||
if (cc->list.count == 0) {
|
if (cc->list.count == 0) {
|
||||||
@@ -1458,9 +1411,8 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
|
|||||||
if (p->debug_info != nullptr) {
|
if (p->debug_info != nullptr) {
|
||||||
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, clause));
|
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, clause));
|
||||||
}
|
}
|
||||||
Type *case_type = nullptr;
|
for (Ast *type_expr : cc->list) {
|
||||||
for_array(type_index, cc->list) {
|
Type *case_type = type_of_expr(type_expr);
|
||||||
case_type = type_of_expr(cc->list[type_index]);
|
|
||||||
lbValue on_val = {};
|
lbValue on_val = {};
|
||||||
if (switch_kind == TypeSwitch_Union) {
|
if (switch_kind == TypeSwitch_Union) {
|
||||||
Type *ut = base_type(type_deref(parent.type));
|
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) {
|
for_array(i, vd->names) {
|
||||||
lbValue value = {};
|
lbValue value = {};
|
||||||
if (vd->values.count > 0) {
|
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);
|
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) {
|
if (values.count == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
|
auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
|
||||||
|
|
||||||
for_array(i, values) {
|
for (Ast *rhs : values) {
|
||||||
Ast *rhs = values[i];
|
|
||||||
if (is_type_tuple(type_of_expr(rhs))) {
|
|
||||||
lbValue init = lb_build_expr(p, rhs);
|
lbValue init = lb_build_expr(p, rhs);
|
||||||
Type *t = init.type;
|
lb_append_tuple_values(p, &inits, init);
|
||||||
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);
|
bool prev_in_assignment = p->in_multi_assignment;
|
||||||
lbValue init = lb_build_expr(p, rhs);
|
|
||||||
if (p->copy_elision_hint.used) {
|
isize lval_count = 0;
|
||||||
lvals[inits.count] = {}; // zero lval
|
for (lbAddr const &lval : lvals) {
|
||||||
}
|
if (lval.addr.value != nullptr) {
|
||||||
lb_reset_copy_elision_hint(p, prev_hint);
|
// check if it is not a blank identifier
|
||||||
array_add(&inits, init);
|
lval_count += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
p->in_multi_assignment = lval_count > 1;
|
||||||
|
|
||||||
GB_ASSERT(lvals.count == inits.count);
|
GB_ASSERT(lvals.count == inits.count);
|
||||||
for_array(i, inits) {
|
for_array(i, inits) {
|
||||||
@@ -1607,11 +1572,18 @@ void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> cons
|
|||||||
lbValue init = inits[i];
|
lbValue init = inits[i];
|
||||||
lb_addr_store(p, lval, init);
|
lb_addr_store(p, lval, init);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
p->in_multi_assignment = prev_in_assignment;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) {
|
gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
|
||||||
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;
|
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 (return_by_pointer) {
|
||||||
if (res.value != nullptr) {
|
if (res.value != nullptr) {
|
||||||
@@ -1641,7 +1613,7 @@ void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) {
|
|||||||
LLVMBuildRet(p->builder, ret_val);
|
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);
|
lb_ensure_abi_function_type(p->module, p);
|
||||||
|
|
||||||
lbValue res = {};
|
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 return_count = p->type->Proc.result_count;
|
||||||
isize res_count = return_results.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;
|
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
|
||||||
|
|
||||||
if (return_count == 0) {
|
if (return_count == 0) {
|
||||||
@@ -1683,15 +1655,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
|
|||||||
if (res_count != 0) {
|
if (res_count != 0) {
|
||||||
for (isize res_index = 0; res_index < res_count; res_index++) {
|
for (isize res_index = 0; res_index < res_count; res_index++) {
|
||||||
lbValue res = lb_build_expr(p, return_results[res_index]);
|
lbValue res = lb_build_expr(p, return_results[res_index]);
|
||||||
Type *t = res.type;
|
lb_append_tuple_values(p, &results, res);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (isize res_index = 0; res_index < return_count; res_index++) {
|
for (isize res_index = 0; res_index < return_count; res_index++) {
|
||||||
@@ -1727,6 +1691,38 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
Type *ret_type = p->type->Proc.results;
|
Type *ret_type = p->type->Proc.results;
|
||||||
|
|
||||||
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
|
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
|
||||||
@@ -1745,7 +1741,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
|
|||||||
for_array(i, results) {
|
for_array(i, results) {
|
||||||
result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i);
|
result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i);
|
||||||
}
|
}
|
||||||
for_array(i, result_values) {
|
for_array(i, result_eps) {
|
||||||
lb_emit_store(p, result_eps[i], result_values[i]);
|
lb_emit_store(p, result_eps[i], result_values[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1757,10 +1753,11 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
|
|||||||
|
|
||||||
res = lb_emit_load(p, res);
|
res = lb_emit_load(p, res);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
lb_build_return_stmt_internal(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);
|
ast_node(is, IfStmt, node);
|
||||||
lb_open_scope(p, is->scope); // Scope #1
|
lb_open_scope(p, is->scope); // Scope #1
|
||||||
defer (lb_close_scope(p, lbDeferExit_Default, nullptr));
|
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);
|
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);
|
ast_node(fs, ForStmt, node);
|
||||||
|
|
||||||
lb_open_scope(p, fs->scope); // Open Scope here
|
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);
|
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);
|
GB_ASSERT(op != Token_Eq);
|
||||||
|
|
||||||
Type *lhs_type = lb_addr_type(lhs);
|
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_handled = slice_make<bool>(temporary_allocator(), bt->Array.count);
|
||||||
auto indices = slice_make<i32>(temporary_allocator(), bt->Array.count);
|
auto indices = slice_make<i32>(temporary_allocator(), bt->Array.count);
|
||||||
i32 index_count = 0;
|
i32 index_count = 0;
|
||||||
for_array(i, lhs.swizzle_large.indices) {
|
for (i32 index : lhs.swizzle_large.indices) {
|
||||||
i32 index = lhs.swizzle_large.indices[i];
|
|
||||||
if (indices_handled[index]) {
|
if (indices_handled[index]) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2050,12 +2046,11 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs,
|
|||||||
lb_loop_end(p, loop_data);
|
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) {
|
if (as->op.kind == Token_Eq) {
|
||||||
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, as->lhs.count);
|
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, as->lhs.count);
|
||||||
|
|
||||||
for_array(i, as->lhs) {
|
for (Ast *lhs : as->lhs) {
|
||||||
Ast *lhs = as->lhs[i];
|
|
||||||
lbAddr lval = {};
|
lbAddr lval = {};
|
||||||
if (!is_blank_ident(lhs)) {
|
if (!is_blank_ident(lhs)) {
|
||||||
lval = lb_build_addr(p, 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);
|
lb_build_assignment(p, lvals, as->rhs);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
GB_ASSERT(as->lhs.count == 1);
|
GB_ASSERT(as->lhs.count == 1);
|
||||||
GB_ASSERT(as->rhs.count == 1);
|
GB_ASSERT(as->rhs.count == 1);
|
||||||
// NOTE(bill): Only 1 += 1 is allowed, no tuples
|
// 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;
|
Ast *prev_stmt = p->curr_stmt;
|
||||||
defer (p->curr_stmt = prev_stmt);
|
defer (p->curr_stmt = prev_stmt);
|
||||||
p->curr_stmt = node;
|
p->curr_stmt = node;
|
||||||
@@ -2190,12 +2186,12 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
|
|||||||
|
|
||||||
bool is_static = false;
|
bool is_static = false;
|
||||||
if (vd->names.count > 0) {
|
if (vd->names.count > 0) {
|
||||||
for_array(i, vd->names) {
|
for (Ast *name : vd->names) {
|
||||||
Ast *name = vd->names[i];
|
|
||||||
if (!is_blank_ident(name)) {
|
if (!is_blank_ident(name)) {
|
||||||
|
GB_ASSERT(name->kind == Ast_Ident);
|
||||||
Entity *e = entity_of_node(name);
|
Entity *e = entity_of_node(name);
|
||||||
TokenPos pos = ast_token(name).pos;
|
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) {
|
if (e->flags & EntityFlag_Static) {
|
||||||
// NOTE(bill): If one of the entities is static, they all are
|
// NOTE(bill): If one of the entities is static, they all are
|
||||||
is_static = true;
|
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);
|
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count);
|
||||||
|
|
||||||
for_array(i, vd->names) {
|
for (Ast *name : vd->names) {
|
||||||
Ast *name = vd->names[i];
|
|
||||||
lbAddr lval = {};
|
lbAddr lval = {};
|
||||||
if (!is_blank_ident(name)) {
|
if (!is_blank_ident(name)) {
|
||||||
Entity *e = entity_of_node(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) {
|
if (p->curr_block == nullptr) {
|
||||||
return;
|
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 count = p->defer_stmts.count;
|
||||||
isize i = count;
|
isize i = count;
|
||||||
while (i --> 0) {
|
while (i --> 0) {
|
||||||
@@ -2340,7 +2335,7 @@ void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
|
|||||||
|
|
||||||
if (kind == lbDeferExit_Default) {
|
if (kind == lbDeferExit_Default) {
|
||||||
if (p->scope_index == d.scope_index &&
|
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);
|
lb_build_defer_stmt(p, d);
|
||||||
array_pop(&p->defer_stmts);
|
array_pop(&p->defer_stmts);
|
||||||
continue;
|
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);
|
Type *pt = base_type(p->type);
|
||||||
GB_ASSERT(pt->kind == Type_Proc);
|
GB_ASSERT(pt->kind == Type_Proc);
|
||||||
if (pt->Proc.calling_convention == ProcCC_Odin) {
|
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;
|
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);
|
Type *pt = base_type(p->type);
|
||||||
GB_ASSERT(pt->kind == Type_Proc);
|
GB_ASSERT(pt->kind == Type_Proc);
|
||||||
if (pt->Proc.calling_convention == ProcCC_Odin) {
|
if (pt->Proc.calling_convention == ProcCC_Odin) {
|
||||||
|
|||||||
+14
-13
@@ -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;
|
auto *set = &info->minimum_dependency_type_info_set;
|
||||||
isize index = type_info_index(info, type, err_on_not_found);
|
isize index = type_info_index(info, type, err_on_not_found);
|
||||||
if (index >= 0) {
|
if (index >= 0) {
|
||||||
isize i = ptr_entry_index(set, index);
|
auto *found = map_get(set, index);
|
||||||
if (i >= 0) {
|
if (found) {
|
||||||
return i+1;
|
GB_ASSERT(*found >= 0);
|
||||||
|
return *found + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (err_on_not_found) {
|
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;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
lbValue lb_typeid(lbModule *m, Type *type) {
|
gb_internal lbValue lb_typeid(lbModule *m, Type *type) {
|
||||||
GB_ASSERT(!build_context.disallow_rtti);
|
GB_ASSERT(!build_context.disallow_rtti);
|
||||||
|
|
||||||
type = default_type(type);
|
type = default_type(type);
|
||||||
@@ -90,7 +91,7 @@ lbValue lb_typeid(lbModule *m, Type *type) {
|
|||||||
return res;
|
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);
|
GB_ASSERT(!build_context.disallow_rtti);
|
||||||
|
|
||||||
type = default_type(type);
|
type = default_type(type);
|
||||||
@@ -102,36 +103,36 @@ lbValue lb_type_info(lbModule *m, Type *type) {
|
|||||||
return lb_emit_array_epi(m, data, index);
|
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);
|
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);
|
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);
|
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;
|
lb_global_type_info_member_types_index += cast(i32)count;
|
||||||
return offset;
|
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);
|
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);
|
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;
|
lb_global_type_info_member_names_index += cast(i32)count;
|
||||||
return offset;
|
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);
|
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);
|
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;
|
lb_global_type_info_member_offsets_index += cast(i32)count;
|
||||||
return offset;
|
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);
|
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);
|
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;
|
lb_global_type_info_member_usings_index += cast(i32)count;
|
||||||
return offset;
|
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);
|
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);
|
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;
|
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) {
|
if (build_context.disallow_rtti) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
+175
-135
@@ -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);
|
t = base_type(t);
|
||||||
switch (t->kind) {
|
switch (t->kind) {
|
||||||
case Type_Basic:
|
case Type_Basic:
|
||||||
@@ -39,7 +39,7 @@ bool lb_is_type_aggregate(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void lb_emit_unreachable(lbProcedure *p) {
|
gb_internal void lb_emit_unreachable(lbProcedure *p) {
|
||||||
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
|
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
|
||||||
if (instr == nullptr || !lb_is_instr_terminating(instr)) {
|
if (instr == nullptr || !lb_is_instr_terminating(instr)) {
|
||||||
lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
|
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);
|
Type *src = core_type(value.type);
|
||||||
GB_ASSERT(is_type_integer(src) || is_type_float(src));
|
GB_ASSERT(is_type_integer(src) || is_type_float(src));
|
||||||
if (is_type_different_to_arch_endianness(src)) {
|
if (is_type_different_to_arch_endianness(src)) {
|
||||||
@@ -57,7 +57,7 @@ lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
|
|||||||
return 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;
|
bool is_inlinable = false;
|
||||||
|
|
||||||
i64 const_len = 0;
|
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);
|
LLVMTypeRef llvm_type = lb_type(p->module, type);
|
||||||
|
|
||||||
LLVMTypeKind kind = LLVMGetTypeKind(llvm_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);
|
cond = lb_emit_conv(p, cond, t_llvm_bool);
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
res.value = LLVMBuildSelect(p->builder, cond.value, x.value, y.value, "");
|
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;
|
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);
|
x = lb_emit_conv(p, x, t);
|
||||||
y = lb_emit_conv(p, y, t);
|
y = lb_emit_conv(p, y, t);
|
||||||
return lb_emit_select(p, lb_emit_comp(p, Token_Lt, x, y), x, y);
|
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);
|
x = lb_emit_conv(p, x, t);
|
||||||
y = lb_emit_conv(p, y, t);
|
y = lb_emit_conv(p, y, t);
|
||||||
return lb_emit_select(p, lb_emit_comp(p, Token_Gt, x, y), x, y);
|
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 = {};
|
lbValue z = {};
|
||||||
z = lb_emit_max(p, t, x, min);
|
z = lb_emit_max(p, t, x, min);
|
||||||
z = lb_emit_min(p, t, z, max);
|
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)) {
|
if (false && lb_is_const(str_elem) && lb_is_const(str_len)) {
|
||||||
LLVMValueRef values[2] = {
|
LLVMValueRef values[2] = {
|
||||||
str_elem.value,
|
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;
|
Type *src_type = value.type;
|
||||||
if (are_types_identical(t, src_type)) {
|
if (are_types_identical(t, src_type)) {
|
||||||
return value;
|
return value;
|
||||||
@@ -259,7 +259,7 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
|
|||||||
return res;
|
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);
|
i64 type_alignment = type_align_of(new_type);
|
||||||
if (alignment < type_alignment) {
|
if (alignment < type_alignment) {
|
||||||
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);
|
GB_ASSERT(ce->args.count > 0);
|
||||||
|
|
||||||
auto slices = slice_make<lbValue>(temporary_allocator(), ce->args.count);
|
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);
|
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);
|
GB_ASSERT(ce->args.count == 1);
|
||||||
|
|
||||||
lbValue arg = lb_build_expr(p, ce->args[0]);
|
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);
|
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 lhs = {};
|
||||||
lbValue rhs = {};
|
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)) {
|
if (is_type_tuple(value.type)) {
|
||||||
i32 n = cast(i32)(value.type->Tuple.variables.count-1);
|
i32 n = cast(i32)(value.type->Tuple.variables.count-1);
|
||||||
if (value.type->Tuple.variables.count == 2) {
|
if (value.type->Tuple.variables.count == 2) {
|
||||||
lhs = lb_emit_struct_ev(p, value, 0);
|
lhs = lb_emit_tuple_ev(p, value, 0);
|
||||||
} else {
|
} else {
|
||||||
lbAddr lhs_addr = lb_add_local_generated(p, tv.type, false);
|
lbAddr lhs_addr = lb_add_local_generated(p, tv.type, false);
|
||||||
lbValue lhs_ptr = lb_addr_get_ptr(p, lhs_addr);
|
lbValue lhs_ptr = lb_addr_get_ptr(p, lhs_addr);
|
||||||
for (i32 i = 0; i < n; i++) {
|
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);
|
lhs = lb_addr_load(p, lhs_addr);
|
||||||
}
|
}
|
||||||
rhs = lb_emit_struct_ev(p, value, n);
|
rhs = lb_emit_tuple_ev(p, value, n);
|
||||||
} else {
|
} else {
|
||||||
rhs = value;
|
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 = {};
|
lbValue has_value = {};
|
||||||
if (is_type_boolean(rhs.type)) {
|
if (is_type_boolean(rhs.type)) {
|
||||||
has_value = rhs;
|
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) {
|
if (arg->state_flags & StateFlag_DirectiveWasFalse) {
|
||||||
return lb_build_expr(p, else_expr);
|
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);
|
gb_internal 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_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 lhs = {};
|
||||||
lbValue rhs = {};
|
lbValue rhs = {};
|
||||||
lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &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));
|
GB_ASSERT(is_type_pointer(addr.type));
|
||||||
Type *type = type_deref(addr.type);
|
Type *type = type_deref(addr.type);
|
||||||
lbValue v_one = lb_const_value(p->module, type, exact_value_i64(1));
|
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));
|
GB_ASSERT(type_size_of(value.type) == type_size_of(end_type));
|
||||||
|
|
||||||
if (type_size_of(value.type) < 2) {
|
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);
|
x = lb_emit_conv(p, x, type);
|
||||||
|
|
||||||
char const *name = "llvm.ctpop";
|
char const *name = "llvm.ctpop";
|
||||||
@@ -539,7 +539,7 @@ lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
|
|||||||
return res;
|
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);
|
Type *elem = base_array_type(type);
|
||||||
i64 sz = 8*type_size_of(elem);
|
i64 sz = 8*type_size_of(elem);
|
||||||
lbValue size = lb_const_int(p->module, elem, cast(u64)sz);
|
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);
|
x = lb_emit_conv(p, x, type);
|
||||||
|
|
||||||
char const *name = "llvm.cttz";
|
char const *name = "llvm.cttz";
|
||||||
@@ -566,7 +566,7 @@ lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
|
|||||||
return res;
|
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);
|
x = lb_emit_conv(p, x, type);
|
||||||
|
|
||||||
char const *name = "llvm.ctlz";
|
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);
|
x = lb_emit_conv(p, x, type);
|
||||||
|
|
||||||
char const *name = "llvm.bitreverse";
|
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_internal lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
|
||||||
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_ASSERT(is_type_tuple(type));
|
GB_ASSERT(is_type_tuple(type));
|
||||||
lbModule *m = p->module;
|
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);
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
Type *src_type = value.type;
|
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);
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
Type *src_type = value.type;
|
Type *src_type = value.type;
|
||||||
@@ -826,13 +818,13 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos
|
|||||||
}
|
}
|
||||||
return v;
|
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));
|
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) {
|
if (p->context_stack.count > 0) {
|
||||||
return p->context_stack[p->context_stack.count-1].ctx;
|
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;
|
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)) {
|
if (LLVMIsALoadInst(value.value)) {
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
res.value = LLVMGetOperand(value.value, 0);
|
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);
|
lb_addr_store(p, res, value);
|
||||||
return res.addr;
|
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)) {
|
if (LLVMIsALoadInst(value.value)) {
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
res.value = LLVMGetOperand(value.value, 0);
|
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);
|
t = base_type(t);
|
||||||
LLVMTypeRef struct_type = lb_type(m, t);
|
LLVMTypeRef struct_type = lb_type(m, t);
|
||||||
auto *field_remapping = map_get(&m->struct_field_remapping, cast(void *)struct_type);
|
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;
|
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) {
|
if (t->kind == Type_Struct) {
|
||||||
auto field_remapping = lb_get_struct_remapping(m, t);
|
auto field_remapping = lb_get_struct_remapping(m, t);
|
||||||
index = field_remapping[index];
|
index = field_remapping[index];
|
||||||
@@ -896,7 +888,7 @@ i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
|
|||||||
return 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
|
// NOTE(bill): limit to `[N x u64]` to prevent ABI issues
|
||||||
padding_align = gb_clamp(padding_align, 1, 8);
|
padding_align = gb_clamp(padding_align, 1, 8);
|
||||||
if (padding % padding_align == 0) {
|
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",
|
"LLVMVoidTypeKind",
|
||||||
"LLVMHalfTypeKind",
|
"LLVMHalfTypeKind",
|
||||||
"LLVMFloatTypeKind",
|
"LLVMFloatTypeKind",
|
||||||
@@ -943,7 +935,55 @@ char const *llvm_type_kinds[] = {
|
|||||||
"LLVMBFloatTypeKind",
|
"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));
|
GB_ASSERT(is_type_pointer(s.type));
|
||||||
Type *t = base_type(type_deref(s.type));
|
Type *t = base_type(type_deref(s.type));
|
||||||
Type *result_type = nullptr;
|
Type *result_type = nullptr;
|
||||||
@@ -958,8 +998,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
|
|||||||
GB_ASSERT(index == -1);
|
GB_ASSERT(index == -1);
|
||||||
return lb_emit_union_tag_ptr(p, s);
|
return lb_emit_union_tag_ptr(p, s);
|
||||||
} else if (is_type_tuple(t)) {
|
} else if (is_type_tuple(t)) {
|
||||||
GB_ASSERT(t->Tuple.variables.count > 0);
|
return lb_emit_tuple_ep(p, s, index);
|
||||||
result_type = t->Tuple.variables[index]->type;
|
|
||||||
} else if (is_type_complex(t)) {
|
} else if (is_type_complex(t)) {
|
||||||
Type *ft = base_complex_elem_type(t);
|
Type *ft = base_complex_elem_type(t);
|
||||||
switch (index) {
|
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);
|
GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index);
|
||||||
|
|
||||||
i32 original_index = index;
|
return lb_emit_struct_ep_internal(p, s, index, result_type);
|
||||||
index = lb_convert_struct_index(p->module, t, 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;
|
||||||
|
|
||||||
if (lb_is_const(s)) {
|
|
||||||
// NOTE(bill): this cannot be replaced with lb_emit_epi
|
|
||||||
lbModule *m = p->module;
|
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)};
|
lbTupleFix *tf = map_get(&p->tuple_fix_map, value.value);
|
||||||
res.value = LLVMConstGEP2(lb_type(m, type_deref(s.type)), s.value, indices, gb_count_of(indices));
|
if (tf) {
|
||||||
res.type = alloc_type_pointer(result_type);
|
res = tf->values[index];
|
||||||
return res;
|
GB_ASSERT(are_types_identical(res.type, result_type));
|
||||||
} else {
|
} else {
|
||||||
|
if (t->Tuple.variables.count == 1) {
|
||||||
|
GB_ASSERT(index == 0);
|
||||||
|
// value.type = result_type;
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
if (LLVMIsALoadInst(value.value)) {
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
LLVMTypeRef st = lb_type(p->module, type_deref(s.type));
|
res.value = LLVMGetOperand(value.value, 0);
|
||||||
// gb_printf_err("%s\n", type_to_string(s.type));
|
res.type = alloc_type_pointer(value.type);
|
||||||
// gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value)));
|
lbValue ptr = lb_emit_struct_ep(p, res, index);
|
||||||
// gb_printf_err("%d\n", index);
|
return lb_emit_load(p, ptr);
|
||||||
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.value = LLVMBuildExtractValue(p->builder, value.value, cast(unsigned)index, "");
|
||||||
res.type = alloc_type_pointer(result_type);
|
res.type = result_type;
|
||||||
|
}
|
||||||
return res;
|
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);
|
||||||
}
|
}
|
||||||
|
|
||||||
lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
|
|
||||||
if (LLVMIsALoadInst(s.value)) {
|
if (LLVMIsALoadInst(s.value)) {
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
res.value = LLVMGetOperand(s.value, 0);
|
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);
|
return lb_emit_load(p, ptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
Type *t = base_type(s.type);
|
|
||||||
Type *result_type = nullptr;
|
Type *result_type = nullptr;
|
||||||
|
|
||||||
switch (t->kind) {
|
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");
|
GB_PANIC("lb_emit_union_tag_value");
|
||||||
|
|
||||||
case Type_Tuple:
|
case Type_Tuple:
|
||||||
GB_ASSERT(t->Tuple.variables.count > 0);
|
return lb_emit_tuple_ev(p, s, index);
|
||||||
result_type = t->Tuple.variables[index]->type;
|
|
||||||
if (t->Tuple.variables.count == 1) {
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case Type_Slice:
|
case Type_Slice:
|
||||||
switch (index) {
|
switch (index) {
|
||||||
case 0: result_type = alloc_type_pointer(t->Slice.elem); break;
|
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;
|
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);
|
GB_ASSERT(sel.index.count > 0);
|
||||||
Type *type = type_deref(e.type);
|
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 ptr = lb_address_from_load_or_generate_local(p, e);
|
||||||
lbValue res = lb_emit_deep_field_gep(p, ptr, sel);
|
lbValue res = lb_emit_deep_field_gep(p, ptr, sel);
|
||||||
return lb_emit_load(p, res);
|
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;
|
Type *t = s.type;
|
||||||
GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t));
|
GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t));
|
||||||
Type *st = base_type(type_deref(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;
|
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;
|
Type *t = s.type;
|
||||||
GB_ASSERT(is_type_pointer(t));
|
GB_ASSERT(is_type_pointer(t));
|
||||||
Type *st = base_type(type_deref(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);
|
GB_ASSERT(0 <= index);
|
||||||
return lb_emit_epi(p, s, 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;
|
Type *t = s.type;
|
||||||
GB_ASSERT(is_type_pointer(t));
|
GB_ASSERT(is_type_pointer(t));
|
||||||
Type *st = base_type(type_deref(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);
|
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);
|
index = lb_emit_conv(p, index, t_int);
|
||||||
LLVMValueRef indices[1] = {index.value};
|
LLVMValueRef indices[1] = {index.value};
|
||||||
lbValue res = {};
|
lbValue res = {};
|
||||||
@@ -1321,7 +1365,7 @@ lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
|
|||||||
return res;
|
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;
|
Type *t = s.type;
|
||||||
GB_ASSERT(is_type_pointer(t));
|
GB_ASSERT(is_type_pointer(t));
|
||||||
Type *mt = base_type(type_deref(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);
|
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;
|
Type *t = s.type;
|
||||||
GB_ASSERT(is_type_pointer(t));
|
GB_ASSERT(is_type_pointer(t));
|
||||||
Type *mt = base_type(type_deref(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);
|
Type *st = base_type(s.type);
|
||||||
GB_ASSERT_MSG(is_type_matrix(st), "%s", type_to_string(st));
|
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);
|
Type *t = lb_addr_type(slice);
|
||||||
GB_ASSERT(is_type_slice(t));
|
GB_ASSERT(is_type_slice(t));
|
||||||
lbValue ptr = lb_addr_get_ptr(p, slice);
|
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, 0), base_elem);
|
||||||
lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len);
|
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);
|
Type *t = lb_addr_type(string);
|
||||||
GB_ASSERT(is_type_string(t));
|
GB_ASSERT(is_type_string(t));
|
||||||
lbValue ptr = lb_addr_get_ptr(p, string);
|
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);
|
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);
|
Type *t = base_type(string.type);
|
||||||
GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string);
|
GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string);
|
||||||
return lb_emit_struct_ev(p, string, 0);
|
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);
|
Type *t = base_type(string.type);
|
||||||
GB_ASSERT_MSG(t->kind == Type_Basic && t->Basic.kind == Basic_string, "%s", type_to_string(t));
|
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);
|
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));
|
GB_ASSERT(is_type_cstring(value.type));
|
||||||
auto args = array_make<lbValue>(permanent_allocator(), 1);
|
auto args = array_make<lbValue>(permanent_allocator(), 1);
|
||||||
args[0] = lb_emit_conv(p, value, t_cstring);
|
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);
|
Type *t = type_deref(array_ptr.type);
|
||||||
GB_ASSERT(is_type_array(t));
|
GB_ASSERT(is_type_array(t));
|
||||||
return lb_emit_struct_ep(p, array_ptr, 0);
|
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));
|
GB_ASSERT(is_type_slice(slice.type));
|
||||||
return lb_emit_struct_ev(p, slice, 0);
|
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));
|
GB_ASSERT(is_type_slice(slice.type) || is_type_relative_slice(slice.type));
|
||||||
return lb_emit_struct_ev(p, slice, 1);
|
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));
|
GB_ASSERT(is_type_dynamic_array(da.type));
|
||||||
return lb_emit_struct_ev(p, da, 0);
|
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));
|
GB_ASSERT(is_type_dynamic_array(da.type));
|
||||||
return lb_emit_struct_ev(p, da, 1);
|
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));
|
GB_ASSERT(is_type_dynamic_array(da.type));
|
||||||
return lb_emit_struct_ev(p, da, 2);
|
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));
|
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);
|
lbValue len = lb_emit_struct_ev(p, value, 1);
|
||||||
return lb_emit_conv(p, len, t_int);
|
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;
|
Type *type = map_ptr.type;
|
||||||
GB_ASSERT(is_type_pointer(type));
|
GB_ASSERT(is_type_pointer(type));
|
||||||
type = type_deref(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);
|
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));
|
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 zero = lb_const_int(p->module, t_uintptr, 0);
|
||||||
lbValue one = lb_const_int(p->module, t_uintptr, 1);
|
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);
|
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));
|
GB_ASSERT(is_type_map(value.type) || are_types_identical(value.type, t_raw_map));
|
||||||
lbValue data = lb_emit_struct_ev(p, value, 0);
|
lbValue data = lb_emit_struct_ev(p, value, 0);
|
||||||
u64 mask_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);
|
Type *t = base_type(value.type);
|
||||||
bool is_ptr = false;
|
bool is_ptr = false;
|
||||||
if (is_type_pointer(t)) {
|
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);
|
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);
|
Type *t = base_type(value.type);
|
||||||
|
|
||||||
bool is_ptr = false;
|
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);
|
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;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
a = lb_emit_conv(p, a, t);
|
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);
|
auto iota = slice_make<LLVMValueRef>(temporary_allocator(), count);
|
||||||
for (unsigned i = 0; i < count; i++) {
|
for (unsigned i = 0; i < count; i++) {
|
||||||
iota[i] = lb_const_int(m, t_u32, start+i).value;
|
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);
|
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));
|
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))
|
// #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, "");
|
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);
|
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);
|
GB_ASSERT(count > 0);
|
||||||
if (LLVMIsConstant(value)) {
|
if (LLVMIsConstant(value)) {
|
||||||
LLVMValueRef single = LLVMConstVector(&value, 1);
|
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);
|
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);
|
LLVMTypeRef original_vector_type = LLVMTypeOf(value);
|
||||||
|
|
||||||
GB_ASSERT(LLVMGetTypeKind(original_vector_type) == LLVMVectorTypeKind);
|
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, "");
|
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);
|
LLVMTypeRef vector_type = LLVMTypeOf(value);
|
||||||
unsigned len = LLVMGetVectorSize(vector_type);
|
unsigned len = LLVMGetVectorSize(vector_type);
|
||||||
if (len == 1) {
|
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, "");
|
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);
|
LLVMTypeRef type = LLVMTypeOf(value);
|
||||||
GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind);
|
GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind);
|
||||||
LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
|
LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
|
||||||
@@ -1758,7 +1798,7 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
|
|||||||
#endif
|
#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));
|
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
|
||||||
|
|
||||||
LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
|
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, "");
|
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));
|
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
|
||||||
|
|
||||||
LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
|
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));
|
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);
|
LLVMTypeRef t = LLVMTypeOf(a);
|
||||||
GB_ASSERT(t == LLVMTypeOf(b));
|
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,
|
return LLVMGetInlineAsm(func_type,
|
||||||
cast(char *)str.text, cast(size_t)str.len,
|
cast(char *)str.text, cast(size_t)str.len,
|
||||||
cast(char *)clobbers.text, cast(size_t)clobbers.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()) {
|
if (!is_arch_wasm()) {
|
||||||
return;
|
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()) {
|
if (!is_arch_wasm()) {
|
||||||
return;
|
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);
|
lbAddr *found = string_map_get(&p->module->objc_selectors, name);
|
||||||
if (found) {
|
if (found) {
|
||||||
return *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);
|
ast_node(ce, CallExpr, expr);
|
||||||
|
|
||||||
auto tav = ce->args[0]->tav;
|
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));
|
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);
|
ast_node(ce, CallExpr, expr);
|
||||||
lbModule *m = p->module;
|
lbModule *m = p->module;
|
||||||
|
|
||||||
@@ -1912,7 +1952,7 @@ lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) {
|
|||||||
return lb_addr_load(p, dst);
|
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);
|
lbAddr *found = string_map_get(&p->module->objc_classes, name);
|
||||||
if (found) {
|
if (found) {
|
||||||
return *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);
|
ast_node(ce, CallExpr, expr);
|
||||||
|
|
||||||
auto tav = ce->args[0]->tav;
|
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));
|
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);
|
ast_node(ce, CallExpr, expr);
|
||||||
lbModule *m = p->module;
|
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);
|
TypeAndValue const &tav = type_and_value_of_expr(expr);
|
||||||
if (tav.mode == Addressing_Type) {
|
if (tav.mode == Addressing_Type) {
|
||||||
Type *type = tav.type;
|
Type *type = tav.type;
|
||||||
@@ -1992,7 +2032,7 @@ lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
|
|||||||
return lb_build_expr(p, 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);
|
ast_node(ce, CallExpr, expr);
|
||||||
|
|
||||||
lbModule *m = p->module;
|
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);
|
GB_ASSERT(value.kind == ExactValue_Integer);
|
||||||
i64 v = exact_value_to_i64(value);
|
i64 v = exact_value_to_i64(value);
|
||||||
switch (v) {
|
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;
|
ExactValue value = type_and_value_of_expr(expr).value;
|
||||||
return llvm_atomic_ordering_from_odin(value);
|
return llvm_atomic_ordering_from_odin(value);
|
||||||
}
|
}
|
||||||
|
|||||||
+107
-187
@@ -3,31 +3,41 @@
|
|||||||
#include "common.cpp"
|
#include "common.cpp"
|
||||||
#include "timings.cpp"
|
#include "timings.cpp"
|
||||||
#include "tokenizer.cpp"
|
#include "tokenizer.cpp"
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
#pragma warning(push)
|
||||||
|
#pragma warning(disable: 4505)
|
||||||
|
#endif
|
||||||
#include "big_int.cpp"
|
#include "big_int.cpp"
|
||||||
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
|
#pragma warning(pop)
|
||||||
|
#endif
|
||||||
#include "exact_value.cpp"
|
#include "exact_value.cpp"
|
||||||
#include "build_settings.cpp"
|
#include "build_settings.cpp"
|
||||||
|
|
||||||
gb_global ThreadPool global_thread_pool;
|
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 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
|
isize worker_count = thread_count; // +1
|
||||||
thread_pool_init(&global_thread_pool, permanent_allocator(), worker_count, "ThreadPoolWorker");
|
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);
|
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);
|
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) {
|
if (build_context.show_debug_messages) {
|
||||||
|
mutex_lock(&debugf_mutex);
|
||||||
gb_printf_err("[DEBUG] ");
|
gb_printf_err("[DEBUG] ");
|
||||||
va_list va;
|
va_list va;
|
||||||
va_start(va, fmt);
|
va_start(va, fmt);
|
||||||
(void)gb_printf_err_va(fmt, va);
|
(void)gb_printf_err_va(fmt, va);
|
||||||
va_end(va);
|
va_end(va);
|
||||||
|
mutex_unlock(&debugf_mutex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,11 +68,10 @@ gb_global Timings global_timings = {0};
|
|||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "query_data.cpp"
|
|
||||||
#include "bug_report.cpp"
|
#include "bug_report.cpp"
|
||||||
|
|
||||||
// NOTE(bill): 'name' is used in debugging and profiling modes
|
// 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
|
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);
|
char *cmd_line = gb_alloc_array(gb_heap_allocator(), char, cmd_cap);
|
||||||
isize cmd_len = 0;
|
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;
|
i32 result = 0;
|
||||||
Timings *timings = &global_timings;
|
Timings *timings = &global_timings;
|
||||||
|
|
||||||
@@ -207,15 +216,14 @@ i32 linker_stage(lbGenerator *gen) {
|
|||||||
|
|
||||||
|
|
||||||
StringSet libs = {};
|
StringSet libs = {};
|
||||||
string_set_init(&libs, heap_allocator(), 64);
|
string_set_init(&libs, 64);
|
||||||
defer (string_set_destroy(&libs));
|
defer (string_set_destroy(&libs));
|
||||||
|
|
||||||
StringSet asm_files = {};
|
StringSet asm_files = {};
|
||||||
string_set_init(&asm_files, heap_allocator(), 64);
|
string_set_init(&asm_files, 64);
|
||||||
defer (string_set_destroy(&asm_files));
|
defer (string_set_destroy(&asm_files));
|
||||||
|
|
||||||
for_array(j, gen->foreign_libraries) {
|
for (Entity *e : gen->foreign_libraries) {
|
||||||
Entity *e = gen->foreign_libraries[j];
|
|
||||||
GB_ASSERT(e->kind == Entity_LibraryName);
|
GB_ASSERT(e->kind == Entity_LibraryName);
|
||||||
for_array(i, e->LibraryName.paths) {
|
for_array(i, e->LibraryName.paths) {
|
||||||
String lib = string_trim_whitespace(e->LibraryName.paths[i]);
|
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(), "");
|
gbString object_files = gb_string_make(heap_allocator(), "");
|
||||||
defer (gb_string_free(object_files));
|
defer (gb_string_free(object_files));
|
||||||
for_array(i, gen->output_object_paths) {
|
for (String const &object_path : gen->output_object_paths) {
|
||||||
String object_path = gen->output_object_paths[i];
|
|
||||||
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
|
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -313,6 +320,12 @@ 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",
|
result = system_exec_command_line_app("msvc-link",
|
||||||
"\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s "
|
"\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s "
|
||||||
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
"/nologo /incremental:no /opt:ref /subsystem:%s "
|
||||||
@@ -366,14 +379,13 @@ i32 linker_stage(lbGenerator *gen) {
|
|||||||
defer (gb_string_free(lib_str));
|
defer (gb_string_free(lib_str));
|
||||||
|
|
||||||
StringSet libs = {};
|
StringSet libs = {};
|
||||||
string_set_init(&libs, heap_allocator(), 64);
|
string_set_init(&libs, 64);
|
||||||
defer (string_set_destroy(&libs));
|
defer (string_set_destroy(&libs));
|
||||||
|
|
||||||
for_array(j, gen->foreign_libraries) {
|
for (Entity *e : gen->foreign_libraries) {
|
||||||
Entity *e = gen->foreign_libraries[j];
|
|
||||||
GB_ASSERT(e->kind == Entity_LibraryName);
|
GB_ASSERT(e->kind == Entity_LibraryName);
|
||||||
for_array(i, e->LibraryName.paths) {
|
for (String lib : e->LibraryName.paths) {
|
||||||
String lib = string_trim_whitespace(e->LibraryName.paths[i]);
|
lib = string_trim_whitespace(lib);
|
||||||
if (lib.len == 0) {
|
if (lib.len == 0) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -425,8 +437,7 @@ i32 linker_stage(lbGenerator *gen) {
|
|||||||
|
|
||||||
gbString object_files = gb_string_make(heap_allocator(), "");
|
gbString object_files = gb_string_make(heap_allocator(), "");
|
||||||
defer (gb_string_free(object_files));
|
defer (gb_string_free(object_files));
|
||||||
for_array(i, gen->output_object_paths) {
|
for (String object_path : gen->output_object_paths) {
|
||||||
String object_path = gen->output_object_paths[i];
|
|
||||||
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
|
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -524,7 +535,7 @@ i32 linker_stage(lbGenerator *gen) {
|
|||||||
return result;
|
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();
|
gbAllocator a = heap_allocator();
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
@@ -553,7 +564,7 @@ Array<String> setup_args(int argc, char const **argv) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void print_usage_line(i32 indent, char const *fmt, ...) {
|
gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
|
||||||
while (indent --> 0) {
|
while (indent --> 0) {
|
||||||
gb_printf_err("\t");
|
gb_printf_err("\t");
|
||||||
}
|
}
|
||||||
@@ -564,7 +575,7 @@ void print_usage_line(i32 indent, char const *fmt, ...) {
|
|||||||
gb_printf_err("\n");
|
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, "%.*s is a tool for managing Odin source code", LIT(argv0));
|
||||||
print_usage_line(0, "Usage:");
|
print_usage_line(0, "Usage:");
|
||||||
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
|
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, " 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, "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, "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, "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, "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");
|
print_usage_line(1, "doc generate documentation on a directory of .odin files");
|
||||||
@@ -613,7 +623,6 @@ enum BuildFlagKind {
|
|||||||
BuildFlag_NoEntryPoint,
|
BuildFlag_NoEntryPoint,
|
||||||
BuildFlag_UseLLD,
|
BuildFlag_UseLLD,
|
||||||
BuildFlag_UseSeparateModules,
|
BuildFlag_UseSeparateModules,
|
||||||
BuildFlag_ThreadedChecker,
|
|
||||||
BuildFlag_NoThreadedChecker,
|
BuildFlag_NoThreadedChecker,
|
||||||
BuildFlag_ShowDebugMessages,
|
BuildFlag_ShowDebugMessages,
|
||||||
BuildFlag_Vet,
|
BuildFlag_Vet,
|
||||||
@@ -655,6 +664,7 @@ enum BuildFlagKind {
|
|||||||
|
|
||||||
// internal use only
|
// internal use only
|
||||||
BuildFlag_InternalIgnoreLazy,
|
BuildFlag_InternalIgnoreLazy,
|
||||||
|
BuildFlag_InternalIgnoreLLVMBuild,
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
BuildFlag_IgnoreVsSearch,
|
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};
|
BuildFlag flag = {kind, name, param_kind, command_support, allow_mulitple};
|
||||||
array_add(build_flags, flag);
|
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 = {};
|
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.
|
// 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();
|
gbAllocator a = heap_allocator();
|
||||||
String name = copy_string(a, flag);
|
String name = copy_string(a, flag);
|
||||||
defer (gb_free(a, name.text));
|
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));
|
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);
|
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_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_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_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);
|
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_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_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_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_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_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all);
|
||||||
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check);
|
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_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_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_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc);
|
||||||
add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), 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_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_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)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build);
|
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 set_flags[BuildFlag_COUNT] = {};
|
||||||
|
|
||||||
bool bad_flags = false;
|
bool bad_flags = false;
|
||||||
for_array(i, flag_args) {
|
for (String flag : flag_args) {
|
||||||
String flag = flag_args[i];
|
|
||||||
if (flag[0] != '-') {
|
if (flag[0] != '-') {
|
||||||
gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
|
gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
|
||||||
continue;
|
continue;
|
||||||
@@ -878,8 +881,7 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
bool found = false;
|
bool found = false;
|
||||||
|
|
||||||
BuildFlag found_bf = {};
|
BuildFlag found_bf = {};
|
||||||
for_array(build_flag_index, build_flags) {
|
for (BuildFlag const &bf : build_flags) {
|
||||||
BuildFlag bf = build_flags[build_flag_index];
|
|
||||||
if (bf.name == name) {
|
if (bf.name == name) {
|
||||||
found = true;
|
found = true;
|
||||||
found_bf = bf;
|
found_bf = bf;
|
||||||
@@ -1311,20 +1313,8 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
case BuildFlag_UseSeparateModules:
|
case BuildFlag_UseSeparateModules:
|
||||||
build_context.use_separate_modules = true;
|
build_context.use_separate_modules = true;
|
||||||
break;
|
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: {
|
case BuildFlag_NoThreadedChecker: {
|
||||||
#if !defined(DEFAULT_TO_THREADED_CHECKER)
|
build_context.no_threaded_checker = true;
|
||||||
gb_printf_err("-no-threaded-checker is the default on this platform\n");
|
|
||||||
bad_flags = true;
|
|
||||||
#endif
|
|
||||||
build_context.threaded_checker = false;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case BuildFlag_ShowDebugMessages:
|
case BuildFlag_ShowDebugMessages:
|
||||||
@@ -1445,39 +1435,6 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
build_context.strict_style_init_only = true;
|
build_context.strict_style_init_only = true;
|
||||||
break;
|
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:
|
case BuildFlag_Short:
|
||||||
build_context.cmd_doc_flags |= CmdDocFlag_Short;
|
build_context.cmd_doc_flags |= CmdDocFlag_Short;
|
||||||
break;
|
break;
|
||||||
@@ -1525,6 +1482,9 @@ bool parse_build_flags(Array<String> args) {
|
|||||||
case BuildFlag_InternalIgnoreLazy:
|
case BuildFlag_InternalIgnoreLazy:
|
||||||
build_context.ignore_lazy = true;
|
build_context.ignore_lazy = true;
|
||||||
break;
|
break;
|
||||||
|
case BuildFlag_InternalIgnoreLLVMBuild:
|
||||||
|
build_context.ignore_llvm_build = true;
|
||||||
|
break;
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
case BuildFlag_IgnoreVsSearch: {
|
case BuildFlag_IgnoreVsSearch: {
|
||||||
GB_ASSERT(value.kind == ExactValue_Invalid);
|
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");
|
gb_printf_err("`-export-timings:<format>` requires `-show-timings` or `-show-more-timings` to be present\n");
|
||||||
bad_flags = true;
|
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;
|
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));
|
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 files = 0;
|
||||||
isize packages = p->packages.count;
|
isize packages = p->packages.count;
|
||||||
isize total_file_size = 0;
|
isize total_file_size = 0;
|
||||||
for_array(i, p->packages) {
|
for (AstPackage *pkg : p->packages) {
|
||||||
files += p->packages[i]->files.count;
|
files += pkg->files.count;
|
||||||
for_array(j, p->packages[i]->files) {
|
for (AstFile *file : pkg->files) {
|
||||||
AstFile *file = p->packages[i]->files[j];
|
|
||||||
total_file_size += file->tokenizer.end - file->tokenizer.start;
|
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",
|
gb_fprintf(&f, "\t\t{\"name\": \"%.*s\", \"millis\": %.3f},\n",
|
||||||
LIT(t->total.label), total_time);
|
LIT(t->total.label), total_time);
|
||||||
|
|
||||||
for_array(i, t->sections) {
|
for (TimeStamp const &ts : t->sections) {
|
||||||
TimeStamp ts = t->sections[i];
|
|
||||||
f64 section_time = time_stamp(ts, t->freq, unit);
|
f64 section_time = time_stamp(ts, t->freq, unit);
|
||||||
gb_fprintf(&f, "\t\t{\"name\": \"%.*s\", \"millis\": %.3f},\n",
|
gb_fprintf(&f, "\t\t{\"name\": \"%.*s\", \"millis\": %.3f},\n",
|
||||||
LIT(ts.label), section_time);
|
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));
|
gb_fprintf(&f, "\"%.*s\", %d\n", LIT(t->total.label), int(total_time));
|
||||||
|
|
||||||
for_array(i, t->sections) {
|
for (TimeStamp const &ts : t->sections) {
|
||||||
TimeStamp ts = t->sections[i];
|
|
||||||
f64 section_time = time_stamp(ts, t->freq, unit);
|
f64 section_time = time_stamp(ts, t->freq, unit);
|
||||||
gb_fprintf(&f, "\"%.*s\", %d\n", LIT(ts.label), int(section_time));
|
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");
|
gb_printf("Done.\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void show_timings(Checker *c, Timings *t) {
|
gb_internal void show_timings(Checker *c, Timings *t) {
|
||||||
Parser *p = c->parser;
|
Parser *p = c->parser;
|
||||||
isize lines = p->total_line_count;
|
isize lines = p->total_line_count;
|
||||||
isize tokens = p->total_token_count;
|
isize tokens = p->total_token_count;
|
||||||
@@ -1758,10 +1705,9 @@ void show_timings(Checker *c, Timings *t) {
|
|||||||
isize total_file_size = 0;
|
isize total_file_size = 0;
|
||||||
f64 total_tokenizing_time = 0;
|
f64 total_tokenizing_time = 0;
|
||||||
f64 total_parsing_time = 0;
|
f64 total_parsing_time = 0;
|
||||||
for_array(i, p->packages) {
|
for (AstPackage *pkg : p->packages) {
|
||||||
files += p->packages[i]->files.count;
|
files += pkg->files.count;
|
||||||
for_array(j, p->packages[i]->files) {
|
for (AstFile *file : pkg->files) {
|
||||||
AstFile *file = p->packages[i]->files[j];
|
|
||||||
total_tokenizing_time += file->time_to_tokenize;
|
total_tokenizing_time += file->time_to_tokenize;
|
||||||
total_parsing_time += file->time_to_parse;
|
total_parsing_time += file->time_to_parse;
|
||||||
total_file_size += file->tokenizer.end - file->tokenizer.start;
|
total_file_size += file->tokenizer.end - file->tokenizer.start;
|
||||||
@@ -1770,6 +1716,16 @@ void show_timings(Checker *c, Timings *t) {
|
|||||||
|
|
||||||
timings_print_all(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)) {
|
if (!(build_context.export_timings_format == TimingsExportUnspecified)) {
|
||||||
timings_export_all(t, c, true);
|
timings_export_all(t, c, true);
|
||||||
}
|
}
|
||||||
@@ -1812,8 +1768,7 @@ void show_timings(Checker *c, Timings *t) {
|
|||||||
}
|
}
|
||||||
{
|
{
|
||||||
TimeStamp ts = {};
|
TimeStamp ts = {};
|
||||||
for_array(i, t->sections) {
|
for (TimeStamp const &s : t->sections) {
|
||||||
TimeStamp s = t->sections[i];
|
|
||||||
if (s.label == "parse files") {
|
if (s.label == "parse files") {
|
||||||
ts = s;
|
ts = s;
|
||||||
break;
|
break;
|
||||||
@@ -1836,8 +1791,7 @@ void show_timings(Checker *c, Timings *t) {
|
|||||||
{
|
{
|
||||||
TimeStamp ts = {};
|
TimeStamp ts = {};
|
||||||
TimeStamp ts_end = {};
|
TimeStamp ts_end = {};
|
||||||
for_array(i, t->sections) {
|
for (TimeStamp const &s : t->sections) {
|
||||||
TimeStamp s = t->sections[i];
|
|
||||||
if (s.label == "type check") {
|
if (s.label == "type check") {
|
||||||
ts = s;
|
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;
|
if (build_context.keep_temp_files) return;
|
||||||
|
|
||||||
TIME_SECTION("remove keep temp files");
|
TIME_SECTION("remove keep temp files");
|
||||||
|
|
||||||
for_array(i, gen->output_temp_paths) {
|
for (String const &path : gen->output_temp_paths) {
|
||||||
String path = gen->output_temp_paths[i];
|
|
||||||
gb_file_remove(cast(char const *)path.text);
|
gb_file_remove(cast(char const *)path.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1892,8 +1845,7 @@ void remove_temp_files(lbGenerator *gen) {
|
|||||||
switch (build_context.build_mode) {
|
switch (build_context.build_mode) {
|
||||||
case BuildMode_Executable:
|
case BuildMode_Executable:
|
||||||
case BuildMode_DynamicLibrary:
|
case BuildMode_DynamicLibrary:
|
||||||
for_array(i, gen->output_object_paths) {
|
for (String const &path : gen->output_object_paths) {
|
||||||
String path = gen->output_object_paths[i];
|
|
||||||
gb_file_remove(cast(char const *)path.text);
|
gb_file_remove(cast(char const *)path.text);
|
||||||
}
|
}
|
||||||
break;
|
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, "%.*s is a tool for managing Odin source code", LIT(arg0));
|
||||||
print_usage_line(0, "Usage:");
|
print_usage_line(0, "Usage:");
|
||||||
print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
|
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 <dir> # Type check package in <dir>");
|
||||||
print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point.");
|
print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point.");
|
||||||
} else if (command == "test") {
|
} else if (command == "test") {
|
||||||
print_usage_line(1, "test Build ands runs procedures with the attribute @(test) in the initial package");
|
print_usage_line(1, "test Build and 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");
|
|
||||||
} else if (command == "doc") {
|
} else if (command == "doc") {
|
||||||
print_usage_line(1, "doc generate documentation from a directory of .odin files");
|
print_usage_line(1, "doc generate documentation from a directory of .odin files");
|
||||||
print_usage_line(2, "Examples:");
|
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;
|
CheckerInfo *info = &c->info;
|
||||||
|
|
||||||
auto unused = array_make<Entity *>(permanent_allocator(), 0, info->entities.count);
|
auto unused = array_make<Entity *>(permanent_allocator(), 0, info->entities.count);
|
||||||
for_array(i, info->entities) {
|
for (Entity *e : info->entities) {
|
||||||
Entity *e = info->entities[i];
|
|
||||||
if (e == nullptr) {
|
if (e == nullptr) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@@ -2300,8 +2249,7 @@ void print_show_unused(Checker *c) {
|
|||||||
|
|
||||||
AstPackage *curr_pkg = nullptr;
|
AstPackage *curr_pkg = nullptr;
|
||||||
EntityKind curr_entity_kind = Entity_Invalid;
|
EntityKind curr_entity_kind = Entity_Invalid;
|
||||||
for_array(i, unused) {
|
for (Entity *e : unused) {
|
||||||
Entity *e = unused[i];
|
|
||||||
if (curr_pkg != e->pkg) {
|
if (curr_pkg != e->pkg) {
|
||||||
curr_pkg = e->pkg;
|
curr_pkg = e->pkg;
|
||||||
curr_entity_kind = Entity_Invalid;
|
curr_entity_kind = Entity_Invalid;
|
||||||
@@ -2322,7 +2270,7 @@ void print_show_unused(Checker *c) {
|
|||||||
print_usage_line(0, "");
|
print_usage_line(0, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_env(void) {
|
gb_internal bool check_env(void) {
|
||||||
gbAllocator a = heap_allocator();
|
gbAllocator a = heap_allocator();
|
||||||
char const *odin_root = gb_get_env("ODIN_ROOT", a);
|
char const *odin_root = gb_get_env("ODIN_ROOT", a);
|
||||||
defer (gb_free(a, cast(void *)odin_root));
|
defer (gb_free(a, cast(void *)odin_root));
|
||||||
@@ -2348,25 +2296,24 @@ struct StripSemicolonFile {
|
|||||||
i64 written;
|
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;
|
i64 written = 0;
|
||||||
gbFileError err = gbFileError_None;
|
gbFileError err = gbFileError_None;
|
||||||
u8 const *file_data = file->tokenizer.start;
|
u8 const *file_data = file->tokenizer.start;
|
||||||
i32 prev_offset = 0;
|
i32 prev_offset = 0;
|
||||||
i32 const end_offset = cast(i32)(file->tokenizer.end - file->tokenizer.start);
|
i32 const end_offset = cast(i32)(file->tokenizer.end - file->tokenizer.start);
|
||||||
for_array(i, file->tokens) {
|
for (Token const &token : file->tokens) {
|
||||||
Token *token = &file->tokens[i];
|
if (token.flags & (TokenFlag_Remove|TokenFlag_Replace)) {
|
||||||
if (token->flags & (TokenFlag_Remove|TokenFlag_Replace)) {
|
i32 offset = token.pos.offset;
|
||||||
i32 offset = token->pos.offset;
|
|
||||||
i32 to_write = offset-prev_offset;
|
i32 to_write = offset-prev_offset;
|
||||||
if (!gb_file_write(f, file_data+prev_offset, to_write)) {
|
if (!gb_file_write(f, file_data+prev_offset, to_write)) {
|
||||||
return gbFileError_Invalid;
|
return gbFileError_Invalid;
|
||||||
}
|
}
|
||||||
written += to_write;
|
written += to_write;
|
||||||
prev_offset = token_pos_end(*token).offset;
|
prev_offset = token_pos_end(token).offset;
|
||||||
}
|
}
|
||||||
if (token->flags & TokenFlag_Replace) {
|
if (token.flags & TokenFlag_Replace) {
|
||||||
if (token->kind == Token_Ellipsis) {
|
if (token.kind == Token_Ellipsis) {
|
||||||
if (!gb_file_write(f, "..=", 3)) {
|
if (!gb_file_write(f, "..=", 3)) {
|
||||||
return gbFileError_Invalid;
|
return gbFileError_Invalid;
|
||||||
}
|
}
|
||||||
@@ -2388,24 +2335,19 @@ gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *writt
|
|||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
int strip_semicolons(Parser *parser) {
|
gb_internal int strip_semicolons(Parser *parser) {
|
||||||
isize file_count = 0;
|
isize file_count = 0;
|
||||||
for_array(i, parser->packages) {
|
for (AstPackage *pkg : parser->packages) {
|
||||||
AstPackage *pkg = parser->packages[i];
|
|
||||||
file_count += pkg->files.count;
|
file_count += pkg->files.count;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto generated_files = array_make<StripSemicolonFile>(permanent_allocator(), 0, file_count);
|
auto generated_files = array_make<StripSemicolonFile>(permanent_allocator(), 0, file_count);
|
||||||
|
|
||||||
for_array(i, parser->packages) {
|
for (AstPackage *pkg : parser->packages) {
|
||||||
AstPackage *pkg = parser->packages[i];
|
for (AstFile *file : pkg->files) {
|
||||||
for_array(j, pkg->files) {
|
|
||||||
AstFile *file = pkg->files[j];
|
|
||||||
|
|
||||||
bool nothing_to_change = true;
|
bool nothing_to_change = true;
|
||||||
for_array(i, file->tokens) {
|
for (Token const &token : file->tokens) {
|
||||||
Token *token = &file->tokens[i];
|
if (token.flags) {
|
||||||
if (token->flags) {
|
|
||||||
nothing_to_change = false;
|
nothing_to_change = false;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -2433,9 +2375,8 @@ int strip_semicolons(Parser *parser) {
|
|||||||
isize generated_count = 0;
|
isize generated_count = 0;
|
||||||
bool failed = false;
|
bool failed = false;
|
||||||
|
|
||||||
for_array(i, generated_files) {
|
for (StripSemicolonFile &file : generated_files) {
|
||||||
auto *file = &generated_files[i];
|
char const *filename = cast(char const *)file.new_fullpath.text;
|
||||||
char const *filename = cast(char const *)file->new_fullpath.text;
|
|
||||||
gbFileError err = gbFileError_None;
|
gbFileError err = gbFileError_None;
|
||||||
defer (if (err != gbFileError_None) {
|
defer (if (err != gbFileError_None) {
|
||||||
failed = true;
|
failed = true;
|
||||||
@@ -2453,11 +2394,11 @@ int strip_semicolons(Parser *parser) {
|
|||||||
defer (err = gb_file_truncate(&f, written));
|
defer (err = gb_file_truncate(&f, written));
|
||||||
|
|
||||||
debugf("Write file with stripped tokens: %s\n", filename);
|
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) {
|
if (err) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
file->written = written;
|
file.written = written;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (failed) {
|
if (failed) {
|
||||||
@@ -2472,12 +2413,10 @@ int strip_semicolons(Parser *parser) {
|
|||||||
|
|
||||||
isize overwritten_files = 0;
|
isize overwritten_files = 0;
|
||||||
|
|
||||||
for_array(i, generated_files) {
|
for (StripSemicolonFile const &file : 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 *old_fullpath = cast(char const *)file->old_fullpath.text;
|
char const *new_fullpath = cast(char const *)file.new_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);
|
debugf("Copy '%s' to '%s'\n", old_fullpath, old_fullpath_backup);
|
||||||
if (!gb_file_copy(old_fullpath, old_fullpath_backup, false)) {
|
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]));
|
usage(make_string_c(arg_ptr[0]));
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
virtual_memory_init();
|
||||||
|
|
||||||
timings_init(&global_timings, str_lit("Total Time"), 2048);
|
timings_init(&global_timings, str_lit("Total Time"), 2048);
|
||||||
defer (timings_destroy(&global_timings));
|
defer (timings_destroy(&global_timings));
|
||||||
|
|
||||||
MAIN_TIME_SECTION("initialization");
|
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_string_interner();
|
||||||
init_global_error_collector();
|
init_global_error_collector();
|
||||||
init_keyword_hash_table();
|
init_keyword_hash_table();
|
||||||
init_type_mutex();
|
|
||||||
|
|
||||||
if (!check_env()) {
|
if (!check_env()) {
|
||||||
return 1;
|
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("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")));
|
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();
|
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);
|
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.command_kind = Command_strip_semicolon;
|
||||||
build_context.no_output_files = true;
|
build_context.no_output_files = true;
|
||||||
init_filename = args[2];
|
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") {
|
} else if (command == "doc") {
|
||||||
if (args.count < 3) {
|
if (args.count < 3) {
|
||||||
usage(args[0]);
|
usage(args[0]);
|
||||||
@@ -2824,13 +2748,9 @@ int main(int arg_count, char const **arg_ptr) {
|
|||||||
print_show_unused(checker);
|
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) {
|
if (build_context.show_timings) {
|
||||||
show_timings(checker, &global_timings);
|
show_timings(checker, &global_timings);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (global_error_collector.count != 0) {
|
if (global_error_collector.count != 0) {
|
||||||
return 1;
|
return 1;
|
||||||
@@ -2844,8 +2764,7 @@ int main(int arg_count, char const **arg_ptr) {
|
|||||||
if (!lb_init_generator(gen, checker)) {
|
if (!lb_init_generator(gen, checker)) {
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
lb_generate_code(gen);
|
if (lb_generate_code(gen)) {
|
||||||
|
|
||||||
switch (build_context.build_mode) {
|
switch (build_context.build_mode) {
|
||||||
case BuildMode_Executable:
|
case BuildMode_Executable:
|
||||||
case BuildMode_DynamicLibrary:
|
case BuildMode_DynamicLibrary:
|
||||||
@@ -2858,6 +2777,7 @@ int main(int arg_count, char const **arg_ptr) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
remove_temp_files(gen);
|
remove_temp_files(gen);
|
||||||
|
|
||||||
|
|||||||
+20
-24
@@ -45,7 +45,7 @@
|
|||||||
//
|
//
|
||||||
// Here is the API you need to know about:
|
// 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 {
|
struct Find_Result {
|
||||||
int windows_sdk_version; // Zero if no Windows SDK found.
|
int windows_sdk_version; // Zero if no Windows SDK found.
|
||||||
@@ -58,50 +58,46 @@ struct Find_Result {
|
|||||||
String vs_library_path;
|
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));
|
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);
|
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);
|
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);
|
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);
|
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);
|
char const * value = gb_get_env((char const *)key.text, mc_allocator);
|
||||||
return make_string_c(value);
|
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);
|
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);
|
if (str.len) gb_free(mc_allocator, str.text);
|
||||||
}
|
}
|
||||||
|
|
||||||
void mc_free_all() {
|
|
||||||
gb_free_all(mc_allocator);
|
|
||||||
}
|
|
||||||
|
|
||||||
typedef struct _MC_Find_Data {
|
typedef struct _MC_Find_Data {
|
||||||
DWORD file_attributes;
|
DWORD file_attributes;
|
||||||
String filename;
|
String filename;
|
||||||
} MC_Find_Data;
|
} 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;
|
WIN32_FIND_DATAW _find_data;
|
||||||
|
|
||||||
String16 wildcard_wide = mc_string_to_wstring(wildcard);
|
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;
|
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;
|
WIN32_FIND_DATAW _find_data;
|
||||||
bool success = !!FindNextFileW(handle, &_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;
|
return success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void mc_find_close(HANDLE handle) {
|
gb_internal void mc_find_close(HANDLE handle) {
|
||||||
FindClose(handle);
|
FindClose(handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -216,7 +212,7 @@ struct Version_Data {
|
|||||||
};
|
};
|
||||||
|
|
||||||
typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data *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
|
// 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
|
// 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;
|
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,
|
// Given a key to an already opened registry entry,
|
||||||
// get the value stored under the 'version' subkey.
|
// get the value stored under the 'version' subkey.
|
||||||
// If that's not the right terminology, hey, I never do registry stuff.
|
// 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;
|
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.
|
// Find the Windows 10 subdirectory with the highest version number.
|
||||||
|
|
||||||
int i0, i1, i2, i3;
|
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;
|
bool sdk_found = false;
|
||||||
|
|
||||||
HKEY main_key;
|
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
|
// The name of this procedure is kind of cryptic. Its purpose is
|
||||||
// to fight through Microsoft craziness. The things that the fine
|
// to fight through Microsoft craziness. The things that the fine
|
||||||
// Visual Studio team want you to do, JUST TO FIND A SINGLE FOLDER
|
// 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
|
// 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).
|
// 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) {
|
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
|
||||||
return;
|
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
|
// 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
|
// 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.
|
// 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) {
|
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
|
||||||
return;
|
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_Result r = {};
|
||||||
find_windows_kit_paths(&r);
|
find_windows_kit_paths(&r);
|
||||||
find_visual_studio_by_fighting_through_microsoft_craziness(&r);
|
find_visual_studio_by_fighting_through_microsoft_craziness(&r);
|
||||||
|
|||||||
+443
-486
File diff suppressed because it is too large
Load Diff
+55
-47
@@ -62,15 +62,6 @@ enum PackageKind {
|
|||||||
Package_Init,
|
Package_Init,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct ImportedPackage {
|
|
||||||
PackageKind kind;
|
|
||||||
String path;
|
|
||||||
String rel_path;
|
|
||||||
TokenPos pos; // import
|
|
||||||
isize index;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
struct ImportedFile {
|
struct ImportedFile {
|
||||||
AstPackage *pkg;
|
AstPackage *pkg;
|
||||||
FileInfo fi;
|
FileInfo fi;
|
||||||
@@ -99,7 +90,11 @@ struct AstFile {
|
|||||||
Scope * scope;
|
Scope * scope;
|
||||||
|
|
||||||
Ast * pkg_decl;
|
Ast * pkg_decl;
|
||||||
|
|
||||||
String fullpath;
|
String fullpath;
|
||||||
|
String filename;
|
||||||
|
String directory;
|
||||||
|
|
||||||
Tokenizer tokenizer;
|
Tokenizer tokenizer;
|
||||||
Array<Token> tokens;
|
Array<Token> tokens;
|
||||||
isize curr_token_index;
|
isize curr_token_index;
|
||||||
@@ -109,6 +104,7 @@ struct AstFile {
|
|||||||
Token package_token;
|
Token package_token;
|
||||||
String package_name;
|
String package_name;
|
||||||
|
|
||||||
|
|
||||||
// >= 0: In Expression
|
// >= 0: In Expression
|
||||||
// < 0: In Control Clause
|
// < 0: In Control Clause
|
||||||
// NOTE(bill): Used to prevent type literals in control clauses
|
// NOTE(bill): Used to prevent type literals in control clauses
|
||||||
@@ -136,9 +132,8 @@ struct AstFile {
|
|||||||
CommentGroup *docs; // current docs
|
CommentGroup *docs; // current docs
|
||||||
Array<CommentGroup *> comments; // All the comments!
|
Array<CommentGroup *> comments; // All the comments!
|
||||||
|
|
||||||
// TODO(bill): make this a basic queue as it does not require
|
// This is effectively a queue but does not require any multi-threading capabilities
|
||||||
// any multiple thread capabilities
|
Array<Ast *> delayed_decls_queues[AstDelayQueue_COUNT];
|
||||||
MPMCQueue<Ast *> delayed_decls_queues[AstDelayQueue_COUNT];
|
|
||||||
|
|
||||||
#define PARSER_MAX_FIX_COUNT 6
|
#define PARSER_MAX_FIX_COUNT 6
|
||||||
isize fix_count;
|
isize fix_count;
|
||||||
@@ -177,6 +172,12 @@ struct AstPackage {
|
|||||||
bool is_single_file;
|
bool is_single_file;
|
||||||
isize order;
|
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;
|
MPMCQueue<AstPackageExportedEntity> exported_entity_queue;
|
||||||
|
|
||||||
// NOTE(bill): Created/set in checker
|
// NOTE(bill): Created/set in checker
|
||||||
@@ -186,20 +187,33 @@ struct AstPackage {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
struct ParseFileErrorNode {
|
||||||
|
ParseFileErrorNode *next, *prev;
|
||||||
|
ParseFileError err;
|
||||||
|
};
|
||||||
|
|
||||||
struct Parser {
|
struct Parser {
|
||||||
String init_fullpath;
|
String init_fullpath;
|
||||||
|
|
||||||
StringSet imported_files; // fullpath
|
StringSet imported_files; // fullpath
|
||||||
|
BlockingMutex imported_files_mutex;
|
||||||
|
|
||||||
Array<AstPackage *> packages;
|
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;
|
BlockingMutex packages_mutex;
|
||||||
MPMCQueue<ParseFileError> file_error_queue;
|
|
||||||
|
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 {
|
struct ParserWorkerData {
|
||||||
@@ -258,7 +272,7 @@ enum ProcCallingConvention : i32 {
|
|||||||
ProcCC_ForeignBlockDefault = -1,
|
ProcCC_ForeignBlockDefault = -1,
|
||||||
};
|
};
|
||||||
|
|
||||||
char const *proc_calling_convention_strings[ProcCC_MAX] = {
|
gb_global char const *proc_calling_convention_strings[ProcCC_MAX] = {
|
||||||
"",
|
"",
|
||||||
"odin",
|
"odin",
|
||||||
"contextless",
|
"contextless",
|
||||||
@@ -272,7 +286,7 @@ char const *proc_calling_convention_strings[ProcCC_MAX] = {
|
|||||||
"sysv",
|
"sysv",
|
||||||
};
|
};
|
||||||
|
|
||||||
ProcCallingConvention default_calling_convention(void) {
|
gb_internal ProcCallingConvention default_calling_convention(void) {
|
||||||
return ProcCC_Odin;
|
return ProcCC_Odin;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -299,7 +313,7 @@ enum FieldFlag : u32 {
|
|||||||
FieldFlag_using = 1<<1,
|
FieldFlag_using = 1<<1,
|
||||||
FieldFlag_no_alias = 1<<2,
|
FieldFlag_no_alias = 1<<2,
|
||||||
FieldFlag_c_vararg = 1<<3,
|
FieldFlag_c_vararg = 1<<3,
|
||||||
FieldFlag_auto_cast = 1<<4,
|
|
||||||
FieldFlag_const = 1<<5,
|
FieldFlag_const = 1<<5,
|
||||||
FieldFlag_any_int = 1<<6,
|
FieldFlag_any_int = 1<<6,
|
||||||
FieldFlag_subtype = 1<<7,
|
FieldFlag_subtype = 1<<7,
|
||||||
@@ -314,7 +328,7 @@ enum FieldFlag : u32 {
|
|||||||
FieldFlag_Invalid = 1u<<31,
|
FieldFlag_Invalid = 1u<<31,
|
||||||
|
|
||||||
// Parameter List Restrictions
|
// 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,
|
FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -332,7 +346,7 @@ enum InlineAsmDialectKind : u8 {
|
|||||||
InlineAsmDialect_COUNT,
|
InlineAsmDialect_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
|
gb_global char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
|
||||||
"",
|
"",
|
||||||
"att",
|
"att",
|
||||||
"intel",
|
"intel",
|
||||||
@@ -457,11 +471,6 @@ AST_KIND(_StmtBegin, "", bool) \
|
|||||||
AST_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
|
AST_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
|
||||||
AST_KIND(EmptyStmt, "empty statement", struct { Token token; }) \
|
AST_KIND(EmptyStmt, "empty statement", struct { Token token; }) \
|
||||||
AST_KIND(ExprStmt, "expression statement", struct { Ast *expr; } ) \
|
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 { \
|
AST_KIND(AssignStmt, "assign statement", struct { \
|
||||||
Token op; \
|
Token op; \
|
||||||
Slice<Ast *> lhs, rhs; \
|
Slice<Ast *> lhs, rhs; \
|
||||||
@@ -729,7 +738,7 @@ enum AstKind : u16 {
|
|||||||
Ast_COUNT,
|
Ast_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
String const ast_strings[] = {
|
gb_global String const ast_strings[] = {
|
||||||
{cast(u8 *)"invalid node", gb_size_of("invalid node")},
|
{cast(u8 *)"invalid node", gb_size_of("invalid node")},
|
||||||
#define AST_KIND(_kind_name_, name, ...) {cast(u8 *)name, gb_size_of(name)-1},
|
#define AST_KIND(_kind_name_, name, ...) {cast(u8 *)name, gb_size_of(name)-1},
|
||||||
AST_KINDS
|
AST_KINDS
|
||||||
@@ -742,7 +751,7 @@ String const ast_strings[] = {
|
|||||||
#undef AST_KIND
|
#undef AST_KIND
|
||||||
|
|
||||||
|
|
||||||
isize const ast_variant_sizes[] = {
|
gb_global isize const ast_variant_sizes[] = {
|
||||||
0,
|
0,
|
||||||
#define AST_KIND(_kind_name_, name, ...) gb_size_of(GB_JOIN2(Ast, _kind_name_)),
|
#define AST_KIND(_kind_name_, name, ...) gb_size_of(GB_JOIN2(Ast, _kind_name_)),
|
||||||
AST_KINDS
|
AST_KINDS
|
||||||
@@ -754,7 +763,7 @@ struct AstCommonStuff {
|
|||||||
u8 state_flags;
|
u8 state_flags;
|
||||||
u8 viral_state_flags;
|
u8 viral_state_flags;
|
||||||
i32 file_id;
|
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 {
|
struct Ast {
|
||||||
@@ -762,7 +771,7 @@ struct Ast {
|
|||||||
u8 state_flags;
|
u8 state_flags;
|
||||||
u8 viral_state_flags;
|
u8 viral_state_flags;
|
||||||
i32 file_id;
|
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
|
// IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant
|
||||||
union {
|
union {
|
||||||
@@ -793,33 +802,32 @@ struct Ast {
|
|||||||
#endif
|
#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);
|
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);
|
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);
|
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);
|
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);
|
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;
|
return node->kind == Ast_WhenStmt;
|
||||||
}
|
}
|
||||||
|
|
||||||
gb_global gb_thread_local Arena global_thread_local_ast_arena = {};
|
gb_global gb_thread_local Arena global_thread_local_ast_arena = {};
|
||||||
|
|
||||||
gbAllocator ast_allocator(AstFile *f) {
|
gb_internal gb_inline gbAllocator ast_allocator(AstFile *f) {
|
||||||
Arena *arena = &global_thread_local_ast_arena;
|
return arena_allocator(&global_thread_local_ast_arena);
|
||||||
return arena_allocator(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);
|
gb_internal gbString expr_to_string(Ast *expression);
|
||||||
bool allow_field_separator(AstFile *f);
|
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) {
|
switch (node->kind) {
|
||||||
case Ast_Ident: return node->Ident.token;
|
case Ast_Ident: return node->Ident.token;
|
||||||
case Ast_Implicit: return node->Implicit;
|
case Ast_Implicit: return node->Implicit;
|
||||||
@@ -53,7 +53,6 @@ Token ast_token(Ast *node) {
|
|||||||
case Ast_BadStmt: return node->BadStmt.begin;
|
case Ast_BadStmt: return node->BadStmt.begin;
|
||||||
case Ast_EmptyStmt: return node->EmptyStmt.token;
|
case Ast_EmptyStmt: return node->EmptyStmt.token;
|
||||||
case Ast_ExprStmt: return ast_token(node->ExprStmt.expr);
|
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_AssignStmt: return node->AssignStmt.op;
|
||||||
case Ast_BlockStmt: return node->BlockStmt.open;
|
case Ast_BlockStmt: return node->BlockStmt.open;
|
||||||
case Ast_IfStmt: return node->IfStmt.token;
|
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_BadStmt: return node->BadStmt.end;
|
||||||
case Ast_EmptyStmt: return node->EmptyStmt.token;
|
case Ast_EmptyStmt: return node->EmptyStmt.token;
|
||||||
case Ast_ExprStmt: return ast_end_token(node->ExprStmt.expr);
|
case Ast_ExprStmt: return ast_end_token(node->ExprStmt.expr);
|
||||||
case Ast_TagStmt: return ast_end_token(node->TagStmt.stmt);
|
|
||||||
case Ast_AssignStmt:
|
case Ast_AssignStmt:
|
||||||
if (node->AssignStmt.rhs.count > 0) {
|
if (node->AssignStmt.rhs.count > 0) {
|
||||||
return ast_end_token(node->AssignStmt.rhs[node->AssignStmt.rhs.count-1]);
|
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;
|
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));
|
return token_pos_end(ast_end_token(node));
|
||||||
}
|
}
|
||||||
|
|||||||
+26
-22
@@ -1,7 +1,10 @@
|
|||||||
/*
|
/*
|
||||||
Path handling utilities.
|
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--) {
|
for (isize i = s.len-1; i >= 0; i--) {
|
||||||
if (s[i] == '.') {
|
if (s[i] == '.') {
|
||||||
return substring(s, 0, i);
|
return substring(s, 0, i);
|
||||||
@@ -10,7 +13,7 @@ String remove_extension_from_path(String const &s) {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
String remove_directory_from_path(String const &s) {
|
gb_internal String remove_directory_from_path(String const &s) {
|
||||||
isize len = 0;
|
isize len = 0;
|
||||||
for (isize i = s.len-1; i >= 0; i--) {
|
for (isize i = s.len-1; i >= 0; i--) {
|
||||||
if (s[i] == '/' ||
|
if (s[i] == '/' ||
|
||||||
@@ -22,9 +25,9 @@ String remove_directory_from_path(String const &s) {
|
|||||||
return substring(s, s.len-len, s.len);
|
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)) {
|
if (path_is_directory(s)) {
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
@@ -43,7 +46,7 @@ String directory_from_path(String const &s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#if defined(GB_SYSTEM_WINDOWS)
|
||||||
bool path_is_directory(String path) {
|
gb_internal bool path_is_directory(String path) {
|
||||||
gbAllocator a = heap_allocator();
|
gbAllocator a = heap_allocator();
|
||||||
String16 wstr = string_to_string16(a, path);
|
String16 wstr = string_to_string16(a, path);
|
||||||
defer (gb_free(a, wstr.text));
|
defer (gb_free(a, wstr.text));
|
||||||
@@ -55,7 +58,7 @@ String directory_from_path(String const &s) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#else
|
#else
|
||||||
bool path_is_directory(String path) {
|
gb_internal bool path_is_directory(String path) {
|
||||||
gbAllocator a = heap_allocator();
|
gbAllocator a = heap_allocator();
|
||||||
char *copy = cast(char *)copy_string(a, path).text;
|
char *copy = cast(char *)copy_string(a, path).text;
|
||||||
defer (gb_free(a, copy));
|
defer (gb_free(a, copy));
|
||||||
@@ -69,7 +72,7 @@ String directory_from_path(String const &s) {
|
|||||||
#endif
|
#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();
|
gbAllocator ha = heap_allocator();
|
||||||
char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len);
|
char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len);
|
||||||
defer (gb_free(ha, path_c));
|
defer (gb_free(ha, path_c));
|
||||||
@@ -93,7 +96,7 @@ struct Path {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// NOTE(Jeroen): Naively turns a Path into a string.
|
// 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) {
|
if (path.basename.len + path.name.len + path.ext.len == 0) {
|
||||||
return make_string(nullptr, 0);
|
return make_string(nullptr, 0);
|
||||||
}
|
}
|
||||||
@@ -107,7 +110,9 @@ String path_to_string(gbAllocator a, Path path) {
|
|||||||
|
|
||||||
isize i = 0;
|
isize i = 0;
|
||||||
gb_memmove(str+i, path.basename.text, path.basename.len); i += path.basename.len;
|
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, "/", 1); i += 1;
|
||||||
|
|
||||||
gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len;
|
gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len;
|
||||||
if (path.ext.len > 0) {
|
if (path.ext.len > 0) {
|
||||||
gb_memmove(str+i, ".", 1); i += 1;
|
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`.
|
// 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);
|
String temp = path_to_string(heap_allocator(), path);
|
||||||
defer (gb_free(heap_allocator(), temp.text));
|
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,
|
// 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.
|
// 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 = {};
|
Path res = {};
|
||||||
|
|
||||||
if (path.len == 0) return res;
|
if (path.len == 0) return res;
|
||||||
@@ -150,6 +155,7 @@ Path path_from_string(gbAllocator a, String const &path) {
|
|||||||
return res;
|
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;
|
isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len;
|
||||||
res.name = substring(fullpath, name_start, fullpath.len);
|
res.name = substring(fullpath, name_start, fullpath.len);
|
||||||
res.name = remove_extension_from_path(res.name);
|
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.
|
// 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;
|
isize count = 0;
|
||||||
u8 * start = (u8 *)(&path.text[path.len - 1]);
|
u8 * start = (u8 *)(&path.text[path.len - 1]);
|
||||||
for (isize length = path.len; length > 0 && path.text[length - 1] != '/'; length--) {
|
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("");
|
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);
|
String path_string = path_to_full_path(heap_allocator(), path);
|
||||||
defer (gb_free(heap_allocator(), path_string.text));
|
defer (gb_free(heap_allocator(), path_string.text));
|
||||||
|
|
||||||
@@ -204,7 +210,7 @@ enum ReadDirectoryError {
|
|||||||
ReadDirectory_COUNT,
|
ReadDirectory_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
i64 get_file_size(String path) {
|
gb_internal i64 get_file_size(String path) {
|
||||||
char *c_str = alloc_cstring(heap_allocator(), path);
|
char *c_str = alloc_cstring(heap_allocator(), path);
|
||||||
defer (gb_free(heap_allocator(), c_str));
|
defer (gb_free(heap_allocator(), c_str));
|
||||||
|
|
||||||
@@ -219,10 +225,9 @@ i64 get_file_size(String path) {
|
|||||||
|
|
||||||
|
|
||||||
#if defined(GB_SYSTEM_WINDOWS)
|
#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);
|
GB_ASSERT(fi != nullptr);
|
||||||
|
|
||||||
gbAllocator a = heap_allocator();
|
|
||||||
|
|
||||||
while (path.len > 0) {
|
while (path.len > 0) {
|
||||||
Rune end = path[path.len-1];
|
Rune end = path[path.len-1];
|
||||||
@@ -239,9 +244,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
|||||||
return ReadDirectory_InvalidPath;
|
return ReadDirectory_InvalidPath;
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
char *c_str = alloc_cstring(a, path);
|
char *c_str = alloc_cstring(temporary_allocator(), path);
|
||||||
defer (gb_free(a, c_str));
|
|
||||||
|
|
||||||
gbFile f = {};
|
gbFile f = {};
|
||||||
gbFileError file_err = gb_file_open(&f, c_str);
|
gbFileError file_err = gb_file_open(&f, c_str);
|
||||||
defer (gb_file_close(&f));
|
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);
|
char *new_path = gb_alloc_array(a, char, path.len+3);
|
||||||
defer (gb_free(a, new_path));
|
defer (gb_free(a, new_path));
|
||||||
|
|
||||||
@@ -280,8 +284,8 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
|||||||
|
|
||||||
do {
|
do {
|
||||||
wchar_t *filename_w = file_data.cFileName;
|
wchar_t *filename_w = file_data.cFileName;
|
||||||
i64 size = cast(i64)file_data.nFileSizeLow;
|
u64 size = cast(u64)file_data.nFileSizeLow;
|
||||||
size |= (cast(i64)file_data.nFileSizeHigh) << 32;
|
size |= (cast(u64)file_data.nFileSizeHigh) << 32;
|
||||||
String name = string16_to_string(a, make_string16_c(filename_w));
|
String name = string16_to_string(a, make_string16_c(filename_w));
|
||||||
if (name == "." || name == "..") {
|
if (name == "." || name == "..") {
|
||||||
gb_free(a, name.text);
|
gb_free(a, name.text);
|
||||||
@@ -299,7 +303,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
|||||||
FileInfo info = {};
|
FileInfo info = {};
|
||||||
info.name = name;
|
info.name = name;
|
||||||
info.fullpath = path_to_full_path(a, filepath);
|
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;
|
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
|
||||||
array_add(fi, info);
|
array_add(fi, info);
|
||||||
} while (FindNextFileW(find_file, &file_data));
|
} while (FindNextFileW(find_file, &file_data));
|
||||||
@@ -314,7 +318,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
|
|||||||
|
|
||||||
#include <dirent.h>
|
#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);
|
GB_ASSERT(fi != nullptr);
|
||||||
|
|
||||||
gbAllocator a = heap_allocator();
|
gbAllocator a = heap_allocator();
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ struct PriorityQueue {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template <typename T>
|
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)
|
// O(n log n)
|
||||||
isize i = i0;
|
isize i = i0;
|
||||||
isize j, j1, j2;
|
isize j, j1, j2;
|
||||||
@@ -29,7 +29,7 @@ bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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) {
|
while (0 <= j && j < pq->queue.count) {
|
||||||
isize i = (j-1)/2;
|
isize i = (j-1)/2;
|
||||||
if (i == j || pq->cmp(&pq->queue[0], j, i) >= 0) {
|
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
|
// 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.
|
// the heap ordering. This using a basic "heapsort" with shift up and a shift down parts.
|
||||||
template <typename T>
|
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)) {
|
if (!priority_queue_shift_down(pq, i, pq->queue.count)) {
|
||||||
priority_queue_shift_up(pq, i);
|
priority_queue_shift_up(pq, i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
array_add(&pq->queue, value);
|
||||||
priority_queue_shift_up(pq, pq->queue.count-1);
|
priority_queue_shift_up(pq, pq->queue.count-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(pq->queue.count > 0);
|
||||||
|
|
||||||
isize n = pq->queue.count - 1;
|
isize n = pq->queue.count - 1;
|
||||||
@@ -67,7 +67,7 @@ T priority_queue_pop(PriorityQueue<T> *pq) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(0 <= i && i < pq->queue.count);
|
||||||
isize n = pq->queue.count - 1;
|
isize n = pq->queue.count - 1;
|
||||||
if (n != i) {
|
if (n != i) {
|
||||||
@@ -80,7 +80,7 @@ T priority_queue_remove(PriorityQueue<T> *pq, isize i) {
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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),
|
int (* cmp) (T *q, isize i, isize j),
|
||||||
void (* swap)(T *q, isize i, isize j)) {
|
void (* swap)(T *q, isize i, isize j)) {
|
||||||
PriorityQueue<T> pq = {};
|
PriorityQueue<T> pq = {};
|
||||||
|
|||||||
+224
-103
@@ -2,6 +2,13 @@
|
|||||||
|
|
||||||
typedef u32 MapIndex;
|
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 {
|
struct MapFindResult {
|
||||||
MapIndex hash_index;
|
MapIndex hash_index;
|
||||||
MapIndex entry_prev;
|
MapIndex entry_prev;
|
||||||
@@ -21,12 +28,16 @@ struct PtrMapEntry {
|
|||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
struct PtrMap {
|
struct PtrMap {
|
||||||
Slice<MapIndex> hashes;
|
MapIndex * hashes;
|
||||||
Array<PtrMapEntry<K, V> > entries;
|
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)
|
#if defined(GB_ARCH_64_BIT)
|
||||||
key = (~key) + (key << 21);
|
key = (~key) + (key << 21);
|
||||||
key = key ^ (key >> 24);
|
key = key ^ (key >> 24);
|
||||||
@@ -34,80 +45,96 @@ u32 ptr_map_hash_key(uintptr key) {
|
|||||||
key = key ^ (key >> 14);
|
key = key ^ (key >> 14);
|
||||||
key = (key + (key << 2)) + (key << 4);
|
key = (key + (key << 2)) + (key << 4);
|
||||||
key = key ^ (key << 28);
|
key = key ^ (key << 28);
|
||||||
return cast(u32)key;
|
res = cast(u32)key;
|
||||||
#elif defined(GB_ARCH_32_BIT)
|
#elif defined(GB_ARCH_32_BIT)
|
||||||
u32 state = ((u32)key) * 747796405u + 2891336453u;
|
u32 state = ((u32)key) * 747796405u + 2891336453u;
|
||||||
u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
|
||||||
return (word >> 22u) ^ word;
|
res = (word >> 22u) ^ word;
|
||||||
#endif
|
#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);
|
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> gb_internal void map_init (PtrMap<K, V> *h, isize capacity = 16);
|
||||||
template <typename K, typename V> void map_destroy (PtrMap<K, V> *h);
|
template <typename K, typename V> gb_internal 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> gb_internal 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> gb_internal 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> 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> void map_clear (PtrMap<K, V> *h);
|
template <typename K, typename V> gb_internal void map_remove (PtrMap<K, V> *h, K key);
|
||||||
template <typename K, typename V> void map_grow (PtrMap<K, V> *h);
|
template <typename K, typename V> gb_internal void map_clear (PtrMap<K, V> *h);
|
||||||
template <typename K, typename V> void map_rehash (PtrMap<K, V> *h, isize new_count);
|
template <typename K, typename V> gb_internal void map_grow (PtrMap<K, V> *h);
|
||||||
template <typename K, typename V> void map_reserve (PtrMap<K, V> *h, isize cap);
|
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
|
#if PTR_MAP_ENABLE_MULTI_MAP
|
||||||
// Mutlivalued map procedure
|
// 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> gb_internal 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_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> gb_internal 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> gb_internal 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> gb_internal 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> gb_internal 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 void multi_map_remove_all(PtrMap<K, V> *h, K key);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
template <typename K, typename V>
|
gb_internal gbAllocator map_allocator(void) {
|
||||||
gb_inline void map_init(PtrMap<K, V> *h, gbAllocator a, isize capacity) {
|
return heap_allocator();
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
gb_inline void map_destroy(PtrMap<K, V> *h) {
|
gb_internal gb_inline void map_init(PtrMap<K, V> *h, isize capacity) {
|
||||||
slice_free(&h->hashes, h->entries.allocator);
|
capacity = next_pow2_isize(capacity);
|
||||||
array_free(&h->entries);
|
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>
|
template <typename K, typename V>
|
||||||
gb_internal MapIndex map__add_entry(PtrMap<K, V> *h, K key) {
|
gb_internal MapIndex map__add_entry(PtrMap<K, V> *h, K key) {
|
||||||
PtrMapEntry<K, V> e = {};
|
PtrMapEntry<K, V> e = {};
|
||||||
e.key = key;
|
e.key = key;
|
||||||
e.next = MAP_SENTINEL;
|
e.next = MAP_SENTINEL;
|
||||||
array_add(&h->entries, e);
|
map__reserve_entries(h, h->count+1);
|
||||||
return cast(MapIndex)(h->entries.count-1);
|
h->entries[h->count++] = e;
|
||||||
|
return cast(MapIndex)(h->count-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
gb_internal MapFindResult map__find(PtrMap<K, V> *h, K key) {
|
gb_internal MapFindResult map__find(PtrMap<K, V> *h, K key) {
|
||||||
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
|
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
|
||||||
if (h->hashes.count == 0) {
|
if (h->hashes_count == 0) {
|
||||||
return fr;
|
return fr;
|
||||||
}
|
}
|
||||||
u32 hash = ptr_map_hash_key(key);
|
u32 hash = ptr_map_hash_key(key);
|
||||||
fr.hash_index = cast(MapIndex)(hash & (h->hashes.count-1));
|
fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
|
||||||
fr.entry_index = h->hashes.data[fr.hash_index];
|
fr.entry_index = h->hashes[fr.hash_index];
|
||||||
while (fr.entry_index != MAP_SENTINEL) {
|
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;
|
return fr;
|
||||||
}
|
}
|
||||||
fr.entry_prev = fr.entry_index;
|
fr.entry_prev = fr.entry_index;
|
||||||
fr.entry_index = h->entries.data[fr.entry_index].next;
|
fr.entry_index = entry->next;
|
||||||
}
|
}
|
||||||
return fr;
|
return fr;
|
||||||
}
|
}
|
||||||
@@ -115,41 +142,41 @@ gb_internal MapFindResult map__find(PtrMap<K, V> *h, K key) {
|
|||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
gb_internal MapFindResult map__find_from_entry(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
|
gb_internal MapFindResult map__find_from_entry(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
|
||||||
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
|
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
|
||||||
if (h->hashes.count == 0) {
|
if (h->hashes_count == 0) {
|
||||||
return fr;
|
return fr;
|
||||||
}
|
}
|
||||||
u32 hash = ptr_map_hash_key(e->key);
|
u32 hash = ptr_map_hash_key(e->key);
|
||||||
fr.hash_index = cast(MapIndex)(hash & (h->hashes.count-1));
|
fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
|
||||||
fr.entry_index = h->hashes.data[fr.hash_index];
|
fr.entry_index = h->hashes[fr.hash_index];
|
||||||
while (fr.entry_index != MAP_SENTINEL) {
|
while (fr.entry_index != MAP_SENTINEL) {
|
||||||
if (&h->entries.data[fr.entry_index] == e) {
|
if (&h->entries[fr.entry_index] == e) {
|
||||||
return fr;
|
return fr;
|
||||||
}
|
}
|
||||||
fr.entry_prev = fr.entry_index;
|
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;
|
return fr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
gb_internal b32 map__full(PtrMap<K, V> *h) {
|
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>
|
template <typename K, typename V>
|
||||||
gb_inline void map_grow(PtrMap<K, V> *h) {
|
gb_internal gb_inline void map_grow(PtrMap<K, V> *h) {
|
||||||
isize new_count = gb_max(h->hashes.count<<1, 16);
|
isize new_count = gb_max(h->hashes_count<<1, 16);
|
||||||
map_rehash(h, new_count);
|
map_rehash(h, new_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
void map_reset_entries(PtrMap<K, V> *h) {
|
gb_internal void map_reset_entries(PtrMap<K, V> *h) {
|
||||||
for (isize i = 0; i < h->hashes.count; i++) {
|
for (usize i = 0; i < h->hashes_count; i++) {
|
||||||
h->hashes.data[i] = MAP_SENTINEL;
|
h->hashes[i] = MAP_SENTINEL;
|
||||||
}
|
}
|
||||||
for (isize i = 0; i < h->entries.count; i++) {
|
for (usize i = 0; i < h->count; i++) {
|
||||||
MapFindResult fr;
|
MapFindResult fr;
|
||||||
PtrMapEntry<K, V> *e = &h->entries.data[i];
|
PtrMapEntry<K, V> *e = &h->entries[i];
|
||||||
e->next = MAP_SENTINEL;
|
e->next = MAP_SENTINEL;
|
||||||
fr = map__find_from_entry(h, e);
|
fr = map__find_from_entry(h, e);
|
||||||
if (fr.entry_prev == MAP_SENTINEL) {
|
if (fr.entry_prev == MAP_SENTINEL) {
|
||||||
@@ -161,42 +188,88 @@ void map_reset_entries(PtrMap<K, V> *h) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
void map_reserve(PtrMap<K, V> *h, isize cap) {
|
gb_internal void map_reserve(PtrMap<K, V> *h, isize cap) {
|
||||||
array_reserve(&h->entries, cap);
|
if (h->count*2 < h->hashes_count) {
|
||||||
if (h->entries.count*2 < h->hashes.count) {
|
|
||||||
return;
|
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);
|
map_reset_entries(h);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename K, typename V>
|
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);
|
map_reserve(h, new_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
V *map_get(PtrMap<K, V> *h, K key) {
|
gb_internal V *map_get(PtrMap<K, V> *h, K key) {
|
||||||
MapIndex index = map__find(h, key).entry_index;
|
MapIndex hash_index = MAP_SENTINEL;
|
||||||
if (index != MAP_SENTINEL) {
|
MapIndex entry_prev = MAP_SENTINEL;
|
||||||
return &h->entries.data[index].value;
|
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;
|
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>
|
template <typename K, typename V>
|
||||||
V &map_must_get(PtrMap<K, V> *h, K key) {
|
gb_internal void map_set_internal_from_try_get(PtrMap<K, V> *h, K key, V const &value, MapFindResult const &fr) {
|
||||||
MapIndex index = map__find(h, key).entry_index;
|
MapIndex index = map__add_entry(h, key);
|
||||||
GB_ASSERT(index != MAP_SENTINEL);
|
if (fr.entry_prev != MAP_SENTINEL) {
|
||||||
return h->entries.data[index].value;
|
h->entries[fr.entry_prev].next = index;
|
||||||
|
} else {
|
||||||
|
h->hashes[fr.hash_index] = index;
|
||||||
|
}
|
||||||
|
h->entries[index].value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
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;
|
MapIndex index;
|
||||||
MapFindResult fr;
|
MapFindResult fr;
|
||||||
if (h->hashes.count == 0) {
|
if (h->hashes_count == 0) {
|
||||||
map_grow(h);
|
map_grow(h);
|
||||||
}
|
}
|
||||||
fr = map__find(h, key);
|
fr = map__find(h, key);
|
||||||
@@ -205,44 +278,71 @@ void map_set(PtrMap<K, V> *h, K key, V const &value) {
|
|||||||
} else {
|
} else {
|
||||||
index = map__add_entry(h, key);
|
index = map__add_entry(h, key);
|
||||||
if (fr.entry_prev != MAP_SENTINEL) {
|
if (fr.entry_prev != MAP_SENTINEL) {
|
||||||
h->entries.data[fr.entry_prev].next = index;
|
h->entries[fr.entry_prev].next = index;
|
||||||
} else {
|
} 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)) {
|
if (map__full(h)) {
|
||||||
map_grow(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>
|
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;
|
MapFindResult last;
|
||||||
if (fr.entry_prev == MAP_SENTINEL) {
|
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 {
|
} 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) {
|
if (fr.entry_index == h->count-1) {
|
||||||
array_pop(&h->entries);
|
h->count--;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
h->entries.data[fr.entry_index] = h->entries.data[h->entries.count-1];
|
h->entries[fr.entry_index] = h->entries[h->count-1];
|
||||||
array_pop(&h->entries);
|
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) {
|
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 {
|
} else {
|
||||||
h->hashes.data[last.hash_index] = fr.entry_index;
|
h->hashes[last.hash_index] = fr.entry_index;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
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);
|
MapFindResult fr = map__find(h, key);
|
||||||
if (fr.entry_index != MAP_SENTINEL) {
|
if (fr.entry_index != MAP_SENTINEL) {
|
||||||
map__erase(h, fr);
|
map__erase(h, fr);
|
||||||
@@ -250,38 +350,38 @@ void map_remove(PtrMap<K, V> *h, K key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
gb_inline void map_clear(PtrMap<K, V> *h) {
|
gb_internal gb_inline void map_clear(PtrMap<K, V> *h) {
|
||||||
array_clear(&h->entries);
|
h->count = 0;
|
||||||
for (isize i = 0; i < h->hashes.count; i++) {
|
for (usize i = 0; i < h->hashes_count; i++) {
|
||||||
h->hashes.data[i] = MAP_SENTINEL;
|
h->hashes[i] = MAP_SENTINEL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#if PTR_MAP_ENABLE_MULTI_MAP
|
#if PTR_MAP_ENABLE_MULTI_MAP
|
||||||
template <typename K, typename V>
|
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;
|
MapIndex i = map__find(h, key).entry_index;
|
||||||
if (i == MAP_SENTINEL) {
|
if (i == MAP_SENTINEL) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
return &h->entries.data[i];
|
return &h->entries[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
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;
|
MapIndex i = e->next;
|
||||||
while (i != MAP_SENTINEL) {
|
while (i != MAP_SENTINEL) {
|
||||||
if (h->entries.data[i].key == e->key) {
|
if (h->entries[i].key == e->key) {
|
||||||
return &h->entries.data[i];
|
return &h->entries[i];
|
||||||
}
|
}
|
||||||
i = h->entries.data[i].next;
|
i = h->entries[i].next;
|
||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
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;
|
isize count = 0;
|
||||||
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
|
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
|
||||||
while (e != nullptr) {
|
while (e != nullptr) {
|
||||||
@@ -292,8 +392,8 @@ isize multi_map_count(PtrMap<K, V> *h, K key) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename K, typename V>
|
template <typename K, typename V>
|
||||||
void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
|
gb_internal void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
|
||||||
isize i = 0;
|
usize i = 0;
|
||||||
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
|
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
|
||||||
while (e != nullptr) {
|
while (e != nullptr) {
|
||||||
items[i++] = e->value;
|
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>
|
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;
|
MapFindResult fr;
|
||||||
MapIndex i;
|
MapIndex i;
|
||||||
if (h->hashes.count == 0) {
|
if (h->hashes_count == 0) {
|
||||||
map_grow(h);
|
map_grow(h);
|
||||||
}
|
}
|
||||||
// Make
|
// Make
|
||||||
fr = map__find(h, key);
|
fr = map__find(h, key);
|
||||||
i = map__add_entry(h, key);
|
i = map__add_entry(h, key);
|
||||||
if (fr.entry_prev == MAP_SENTINEL) {
|
if (fr.entry_prev == MAP_SENTINEL) {
|
||||||
h->hashes.data[fr.hash_index] = i;
|
h->hashes[fr.hash_index] = i;
|
||||||
} else {
|
} 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[i].next = fr.entry_index;
|
||||||
h->entries.data[i].value = value;
|
h->entries[i].value = value;
|
||||||
// Grow if needed
|
// Grow if needed
|
||||||
if (map__full(h)) {
|
if (map__full(h)) {
|
||||||
map_grow(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>
|
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);
|
MapFindResult fr = map__find_from_entry(h, e);
|
||||||
if (fr.entry_index != MAP_SENTINEL) {
|
if (fr.entry_index != MAP_SENTINEL) {
|
||||||
map__erase(h, fr);
|
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>
|
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) {
|
while (map_get(h, key) != nullptr) {
|
||||||
map_remove(h, key);
|
map_remove(h, key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#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;
|
||||||
|
}
|
||||||
|
|||||||
+160
-191
@@ -1,235 +1,204 @@
|
|||||||
template <typename T>
|
|
||||||
struct PtrSetEntry {
|
|
||||||
T ptr;
|
|
||||||
MapIndex next;
|
|
||||||
};
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
struct PtrSet {
|
struct PtrSet {
|
||||||
Slice<MapIndex> hashes;
|
static_assert(TypeIsPointer<T>::value, "PtrSet::T must be a pointer");
|
||||||
Array<PtrSetEntry<T>> entries;
|
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> gb_internal void ptr_set_init (PtrSet<T> *s, isize capacity = 16);
|
||||||
template <typename T> void ptr_set_destroy(PtrSet<T> *s);
|
template <typename T> gb_internal void ptr_set_destroy(PtrSet<T> *s);
|
||||||
template <typename T> T ptr_set_add (PtrSet<T> *s, T ptr);
|
template <typename T> gb_internal 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> gb_internal 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> gb_internal bool ptr_set_exists (PtrSet<T> *s, T ptr);
|
||||||
template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
|
template <typename T> gb_internal void ptr_set_remove (PtrSet<T> *s, T ptr);
|
||||||
template <typename T> void ptr_set_clear (PtrSet<T> *s);
|
template <typename T> gb_internal 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);
|
|
||||||
|
|
||||||
|
gb_internal gbAllocator ptr_set_allocator(void) {
|
||||||
|
return heap_allocator();
|
||||||
|
}
|
||||||
|
|
||||||
template <typename T>
|
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) {
|
if (capacity != 0) {
|
||||||
capacity = next_pow2_isize(gb_max(16, capacity));
|
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
|
||||||
}
|
}
|
||||||
|
s->count = 0;
|
||||||
slice_init(&s->hashes, a, capacity);
|
s->capacity = capacity;
|
||||||
array_init(&s->entries, a, 0, capacity);
|
|
||||||
for (isize i = 0; i < capacity; i++) {
|
|
||||||
s->hashes.data[i] = MAP_SENTINEL;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ptr_set_destroy(PtrSet<T> *s) {
|
gb_internal void ptr_set_destroy(PtrSet<T> *s) {
|
||||||
slice_free(&s->hashes, s->entries.allocator);
|
gb_free(ptr_set_allocator(), s->keys);
|
||||||
array_free(&s->entries);
|
s->keys = nullptr;
|
||||||
|
s->count = 0;
|
||||||
|
s->capacity = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
gb_internal MapIndex ptr_set__add_entry(PtrSet<T> *s, T ptr) {
|
gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
|
||||||
PtrSetEntry<T> e = {};
|
GB_ASSERT(ptr != nullptr);
|
||||||
e.ptr = ptr;
|
if (s->count != 0) {
|
||||||
e.next = MAP_SENTINEL;
|
#if 0
|
||||||
array_add(&s->entries, e);
|
for (usize i = 0; i < s->capacity; i++) {
|
||||||
return cast(MapIndex)(s->entries.count-1);
|
if (s->keys[i] == ptr) {
|
||||||
|
return i;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
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) {
|
|
||||||
u32 hash = ptr_map_hash_key(ptr);
|
u32 hash = ptr_map_hash_key(ptr);
|
||||||
fr.hash_index = cast(MapIndex)(hash & (s->hashes.count-1));
|
usize mask = s->capacity-1;
|
||||||
fr.entry_index = s->hashes.data[fr.hash_index];
|
usize hash_index = cast(usize)hash & mask;
|
||||||
while (fr.entry_index != MAP_SENTINEL) {
|
for (usize i = 0; i < s->capacity; i++) {
|
||||||
if (s->entries.data[fr.entry_index].ptr == ptr) {
|
T key = s->keys[hash_index];
|
||||||
return fr;
|
if (key == ptr) {
|
||||||
|
return hash_index;
|
||||||
|
} else if (key == nullptr) {
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
fr.entry_prev = fr.entry_index;
|
hash_index = (hash_index+1)&mask;
|
||||||
fr.entry_index = s->entries.data[fr.entry_index].next;
|
|
||||||
}
|
}
|
||||||
}
|
#endif
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns true if it already exists
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T ptr_set_add(PtrSet<T> *s, T ptr) {
|
gb_internal bool ptr_set__full(PtrSet<T> *s) {
|
||||||
MapIndex index;
|
return 0.75f * s->capacity <= s->count;
|
||||||
MapFindResult fr;
|
}
|
||||||
if (s->hashes.count == 0) {
|
|
||||||
|
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);
|
ptr_set_grow(s);
|
||||||
}
|
}
|
||||||
fr = ptr_set__find(s, ptr);
|
GB_ASSERT(s->count < s->capacity);
|
||||||
if (fr.entry_index == MAP_SENTINEL) {
|
GB_ASSERT(s->capacity >= 0);
|
||||||
index = ptr_set__add_entry(s, ptr);
|
|
||||||
if (fr.entry_prev != MAP_SENTINEL) {
|
usize mask = s->capacity-1;
|
||||||
s->entries.data[fr.entry_prev].next = index;
|
u32 hash = ptr_map_hash_key(ptr);
|
||||||
} else {
|
usize hash_index = (cast(usize)hash) & mask;
|
||||||
s->hashes.data[fr.hash_index] = index;
|
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;
|
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);
|
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (ptr_set__full(s)) {
|
|
||||||
ptr_set_grow(s);
|
|
||||||
}
|
|
||||||
return exists;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ptr_set__erase(PtrSet<T> *s, MapFindResult fr) {
|
gb_internal void ptr_set_remove(PtrSet<T> *s, T ptr) {
|
||||||
MapFindResult last;
|
isize index = ptr_set__find(s, ptr);
|
||||||
if (fr.entry_prev == MAP_SENTINEL) {
|
if (index >= 0) {
|
||||||
s->hashes.data[fr.hash_index] = s->entries.data[fr.entry_index].next;
|
GB_ASSERT(s->count > 0);
|
||||||
} else {
|
s->keys[index] = (T)PtrSet<T>::TOMBSTONE;
|
||||||
s->entries.data[fr.entry_prev].next = s->entries.data[fr.entry_index].next;
|
s->count--;
|
||||||
}
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void ptr_set_remove(PtrSet<T> *s, T ptr) {
|
gb_internal gb_inline void ptr_set_clear(PtrSet<T> *s) {
|
||||||
MapFindResult fr = ptr_set__find(s, ptr);
|
s->count = 0;
|
||||||
if (fr.entry_index != MAP_SENTINEL) {
|
gb_zero_size(s->keys, s->capacity*gb_size_of(T));
|
||||||
ptr_set__erase(s, fr);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
gb_inline void ptr_set_clear(PtrSet<T> *s) {
|
struct PtrSetIterator {
|
||||||
array_clear(&s->entries);
|
PtrSet<T> *set;
|
||||||
for (isize i = 0; i < s->hashes.count; i++) {
|
usize index;
|
||||||
s->hashes.data[i] = MAP_SENTINEL;
|
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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>
|
||||||
|
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>
|
||||||
|
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
|
#define MPMC_CACHE_LINE_SIZE 64
|
||||||
|
|
||||||
typedef std::atomic<i32> MPMCQueueAtomicIdx;
|
typedef std::atomic<i32> MPMCQueueAtomicIdx;
|
||||||
@@ -9,7 +92,6 @@ struct MPMCQueue {
|
|||||||
|
|
||||||
T * nodes;
|
T * nodes;
|
||||||
MPMCQueueAtomicIdx *indices;
|
MPMCQueueAtomicIdx *indices;
|
||||||
gbAllocator allocator;
|
|
||||||
BlockingMutex mutex;
|
BlockingMutex mutex;
|
||||||
MPMCQueueAtomicIdx count;
|
MPMCQueueAtomicIdx count;
|
||||||
i32 mask; // capacity-1, because capacity must be a power of 2
|
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(offset % 8 == 0);
|
||||||
GB_ASSERT(size % 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>
|
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) {
|
if (size_i < 8) {
|
||||||
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);
|
size = next_pow2(size);
|
||||||
GB_ASSERT(gb_is_power_of_two(size));
|
GB_ASSERT(gb_is_power_of_two(size));
|
||||||
|
|
||||||
mutex_init(&q->mutex);
|
|
||||||
q->mask = size-1;
|
q->mask = size-1;
|
||||||
q->allocator = a;
|
gbAllocator a = mpmc_allocator();
|
||||||
q->nodes = gb_alloc_array(a, T, size);
|
q->nodes = gb_alloc_array(a, T, size);
|
||||||
q->indices = gb_alloc_array(a, MPMCQueueAtomicIdx, 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>
|
template <typename T>
|
||||||
void mpmc_destroy(MPMCQueue<T> *q) {
|
gb_internal void mpmc_destroy(MPMCQueue<T> *q) {
|
||||||
mutex_destroy(&q->mutex);
|
gbAllocator a = mpmc_allocator();
|
||||||
gb_free(q->allocator, q->nodes);
|
gb_free(a, q->nodes);
|
||||||
gb_free(q->allocator, q->indices);
|
gb_free(a, q->indices);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
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);
|
mutex_lock(&q->mutex);
|
||||||
i32 old_size = q->mask+1;
|
i32 old_size = q->mask+1;
|
||||||
i32 new_size = old_size*2;
|
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) {
|
if (q->nodes == nullptr) {
|
||||||
GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size);
|
GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size);
|
||||||
mutex_unlock(&q->mutex);
|
mutex_unlock(&q->mutex);
|
||||||
return false;
|
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) {
|
if (q->indices == nullptr) {
|
||||||
GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size);
|
GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size);
|
||||||
mutex_unlock(&q->mutex);
|
mutex_unlock(&q->mutex);
|
||||||
@@ -95,7 +180,7 @@ bool mpmc_internal_grow(MPMCQueue<T> *q) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
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);
|
GB_ASSERT(q->mask != 0);
|
||||||
|
|
||||||
i32 head_idx = q->head_idx.load(std::memory_order_relaxed);
|
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>
|
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) {
|
if (q->mask == 0) {
|
||||||
return false;
|
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 = {};
|
RangeCache cache = {};
|
||||||
array_init(&cache.ranges, a);
|
array_init(&cache.ranges, a);
|
||||||
return cache;
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
void range_cache_destroy(RangeCache *c) {
|
gb_internal void range_cache_destroy(RangeCache *c) {
|
||||||
array_free(&c->ranges);
|
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) {
|
for_array(i, c->ranges) {
|
||||||
RangeValue v = c->ranges[i];
|
RangeValue v = c->ranges[i];
|
||||||
if (v.lo <= index && index <= v.hi) {
|
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);
|
GB_ASSERT(lo <= hi);
|
||||||
for_array(i, c->ranges) {
|
for_array(i, c->ranges) {
|
||||||
RangeValue v = c->ranges[i];
|
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) {
|
// gb_internal bool range_cache_index_exists(RangeCache *c, i64 index) {
|
||||||
for_array(i, c->ranges) {
|
// for_array(i, c->ranges) {
|
||||||
RangeValue v = c->ranges[i];
|
// RangeValue v = c->ranges[i];
|
||||||
if (v.lo <= index && index <= v.hi) {
|
// if (v.lo <= index && index <= v.hi) {
|
||||||
return true;
|
// return true;
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
return false;
|
// 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