Compare commits

...

321 Commits

Author SHA1 Message Date
gingerBill fcc920ed39 Fix typo 2023-02-02 00:24:36 +00:00
gingerBill 4e70256109 Fix when within foreign block (again) 2023-02-02 00:22:54 +00:00
gingerBill 2e4d6d2577 Fix when within foreign blocks at the file scope 2023-02-01 23:41:13 +00:00
gingerBill 51ae21a029 Separate check_stmt code into separate procedures 2023-02-01 23:40:42 +00:00
gingerBill f59846377d Improve ternary logic for untyped nil stuff 2023-01-30 15:29:59 +00:00
gingerBill 8e8eb9e5cd Improve ternary if expression type inference rues
Allow for expression like this

    `x: union{f32} = f32(123) if cond else nil`
2023-01-30 12:54:11 +00:00
gingerBill 88b578ca11 Add for C++ for loop uses 2023-01-30 12:53:36 +00:00
gingerBill 4cb16db4e9 Remove @(require_results) from one procedure 2023-01-30 12:51:56 +00:00
gingerBill 338d483682 Merge branch 'master' of https://github.com/odin-lang/Odin 2023-01-30 11:58:39 +00:00
gingerBill 0ce59a9e2b Use C++ for rather than for_array macro 2023-01-29 11:28:36 +00:00
gingerBill 8d43cc840a Add @(require_results) to package reflect 2023-01-29 11:28:05 +00:00
gingerBill 9ae1bfb69d Merge pull request #2317 from ftphikari/master
vendor/d3d11: fixed function definition
2023-01-28 23:45:23 +00:00
hikari 6ec7284467 vendor/d3d11: fixed function definition 2023-01-29 01:38:28 +02:00
gingerBill 0ccc570ef2 Merge pull request #2316 from Hyp-X/master
Fix decimal_to_float_bits for floats >= 1
2023-01-28 23:31:57 +00:00
Hyp-X a3bb7d3028 Fix decimal_to_float_bits for floats >= 1 2023-01-28 14:40:44 +01:00
gingerBill c45ca1bfcc Correct arena_temp_end usage when no allocation ever happens for that arena 2023-01-28 12:09:24 +00:00
gingerBill 94edf89b20 Use a separate arena for heap_allocator 2023-01-28 11:53:05 +00:00
gingerBill 8d6ce0b693 Add mutex to virtual.Arena; add virtual.arena_temp_ignore 2023-01-28 11:51:58 +00:00
gingerBill ccf4b48865 Add extra checks for multiple assignments when emitting stores 2023-01-27 11:47:00 +00:00
gingerBill 96eae94103 Merge branch 'master' of https://github.com/odin-lang/Odin 2023-01-27 11:12:17 +00:00
gingerBill db8b2e69dd Fix slice.reverse 2023-01-27 11:12:10 +00:00
Jeroen van Rijn 82821580c7 Merge pull request #2315 from SentientCoffee/pr/os_read_file_location
Add caller location info to `os.read_entire_file()`
2023-01-27 12:00:56 +01:00
Daniel d23d7cf0f2 Add caller location info to os.read_entire_file()
This helps people using the mem.Tracking_Allocator to more easily
pinpoint where they leaked memory in their own code, rather than
having the leaks be reported as if they were in the core library
itself.
2023-01-27 02:42:16 -05:00
gingerBill 450a602230 Fix json.marshal for map[string]string 2023-01-24 12:05:43 +00:00
gingerBill 36764779cf Add extra add_type_info_type calls 2023-01-23 14:09:55 +00:00
gingerBill 97595c4b50 Use a LUT for shift_left 2023-01-23 14:00:02 +00:00
gingerBill ea9fe397e5 Fix typo in decimal_to_float_bits 2023-01-23 12:46:03 +00:00
gingerBill c482432966 Disable arena guards 2023-01-23 12:29:59 +00:00
gingerBill 55176e52fc Use heap_allocator() with -debug; Reinstate the arena guards 2023-01-23 11:38:18 +00:00
gingerBill 4eb08bb096 Change current requirements for valgrind targets 2023-01-23 10:20:04 +00:00
gingerBill 881ef69063 Use ~{} syntax 2023-01-23 10:14:21 +00:00
gingerBill 761a19689d Escape $ in asm 2023-01-23 10:09:22 +00:00
gingerBill f438153b81 Change to use ODIN_VALGRIND_SUPPORT 2023-01-23 09:29:39 +00:00
gingerBill 117c0cceb1 Add helgrind markers to package sync 2023-01-23 09:24:21 +00:00
gingerBill c949e404c3 Fix bug when . is passed to remove_extension_from_path 2023-01-20 13:01:00 +00:00
gingerBill 3d2a6c5895 Fix #2282 caused by a typo 2023-01-20 11:37:40 +00:00
gingerBill 8f4ffbe1da Fix #2299 by handling very large value cases correctly 2023-01-20 11:23:15 +00:00
gingerBill 8f3b6738ff Merge pull request #2273 from ap29600/core_slice_rotate_fix
Fix `core:slice.rotate_left`
2023-01-19 11:13:40 +00:00
gingerBill d50c6d72db Merge pull request #2310 from Lperlind/staging/ns-application-delegate-fix
Fix a few bindings in NSApplicationDelegate
2023-01-19 11:03:21 +00:00
gingerBill 15c5e92d63 Merge pull request #2309 from Lperlind/staging/ns-window-delegate
Fully implement NSWindowDelegate
2023-01-19 11:03:02 +00:00
gingerBill 041c7c8284 Remove tools directory 2023-01-19 10:33:46 +00:00
Lucas Perlind f040ef41cb Fix a few bindings in NSApplicationDelegate 2023-01-19 21:18:30 +11:00
Lucas Perlind 91ab184175 Fully implement NSWindowDelegate 2023-01-19 19:12:14 +11:00
gingerBill 48a64a2c88 Minor fix to string_compare 2023-01-18 16:48:11 +00:00
gingerBill 7f3795a231 Improve odin doc string printing (Fixes #2246) 2023-01-18 16:17:02 +00:00
gingerBill eb1d00ced6 Fix #2264 2023-01-18 16:05:30 +00:00
gingerBill f41c91d36b Fix #2274 2023-01-18 15:41:49 +00:00
gingerBill 6909e0d774 Minor changes to Semaphore to make it trivially copyable 2023-01-18 15:41:39 +00:00
gingerBill d52921edd4 Merge pull request #2308 from Lperlind/staging/ns-application-delegate
(almost) Fully implement NSApplicationDelegate
2023-01-18 12:21:39 +00:00
gingerBill dcca40033e Merge pull request #2307 from Sanian-Creations/update_vendor-sdl2
Removed multiple "SDL_" prefixes that were missed
2023-01-18 12:21:31 +00:00
Lucas Perlind fed65742df (almost) Fully implement NSApplicationDelegate 2023-01-17 18:53:17 +11:00
Sanian b918acd871 Removed some more SDL_'s in sdl_render.odin 2023-01-16 23:45:03 +01:00
Sanian a046c41c7c Removed another missed SDL_ in sdl_mouse.odin
`sdl2.SDL_MouseWheelDirection` is now `sdl2.MouseWheelDirection`
2023-01-16 23:41:11 +01:00
Sanian 2513403014 Removed an SDL_ prefix that was missed 2023-01-16 22:46:46 +01:00
gingerBill 4a8564aff7 Update threading.cpp to have helgrind annotations 2023-01-16 19:23:13 +00:00
gingerBill edb23db2ae Fix potential race condition when determining the package name 2023-01-16 18:31:40 +00:00
gingerBill 0b01cfd853 Fix minor possible race condition 2023-01-16 18:18:08 +00:00
gingerBill 0d059aa797 Replace BlockingMutex with RwMutex 2023-01-16 18:08:28 +00:00
gingerBill 65c0255e7e Replace RecursiveMutex with a BlockingMutex 2023-01-16 18:05:58 +00:00
gingerBill b289a27c4e Move the mutex up a little 2023-01-16 17:04:37 +00:00
gingerBill d085283f20 Fix cnd_timedwait 2023-01-16 15:32:23 +00:00
gingerBill b6ca10cd5e Fix memory leak in os.get_current_directory on failure on *nix systems 2023-01-16 15:29:45 +00:00
gingerBill 7416f72565 Make static value atomic too 2023-01-16 15:12:34 +00:00
gingerBill b51be71a6f Remove initialization on static atomic 2023-01-16 15:11:24 +00:00
gingerBill e488cf4601 Enforce atomic on hasher id 2023-01-16 15:09:29 +00:00
gingerBill 5d397804f7 Fix #2286 by printing an error correctly 2023-01-16 13:22:37 +00:00
gingerBill a5a7226885 Remove auto_cast 2023-01-16 12:09:09 +00:00
gingerBill 2dca39b557 Remove auto_cast procedure field flag
Fixes #2285
2023-01-16 12:06:03 +00:00
gingerBill b55fa268bf Fix #2267 by making it an error 2023-01-16 12:03:46 +00:00
gingerBill c819c350d6 Add error message for atomic intrinsics to prevent arbitrary types 2023-01-16 11:58:14 +00:00
gingerBill d55248ab0f Fix #2301 2023-01-16 11:45:15 +00:00
gingerBill 68b2d4b9e2 Fix #2305 2023-01-16 11:41:58 +00:00
gingerBill 54f02f59db Fix compiler error on clang 2023-01-16 11:03:24 +00:00
gingerBill 64047cbf05 Fix #2304 2023-01-16 11:02:42 +00:00
gingerBill b0619980b2 Add /NOIMPLIB /NOEXP on MSVC linker by default when building an executable 2023-01-14 13:42:29 +00:00
gingerBill 9aa9429135 Update debugf usage 2023-01-14 13:42:04 +00:00
gingerBill 518f30e523 Bring PtrMap inline with StringMap 2023-01-14 13:23:17 +00:00
gingerBill 868aa4c14a Minor changes to StringMap allocation 2023-01-14 12:58:45 +00:00
gingerBill 1ab90de493 Minimize StringMap structure usage 2023-01-14 12:33:42 +00:00
gingerBill 1064bcd060 Clean up use of StringMap 2023-01-13 12:13:26 +00:00
gingerBill 1e21125527 Split out object generation more 2023-01-12 21:49:53 +00:00
gingerBill 4a8c37dd52 Prepare for arbitrary separate modules 2023-01-12 21:45:02 +00:00
gingerBill 3b22c6620c Begin to generalize modules away from AstPackage * in -use-separate-modules 2023-01-12 17:13:25 +00:00
gingerBill 402a165b60 Correct missing procedures in other build modules which cause a linkage problem 2023-01-12 16:59:16 +00:00
gingerBill 34f9170189 Fix race condition with polymorphic record generation 2023-01-12 16:06:09 +00:00
gingerBill 38136e15fc add_deps_from_child_to_parent always 2023-01-12 15:44:55 +00:00
gingerBill e97bf2ef35 Minimize contention on the deps for decls 2023-01-12 15:38:23 +00:00
gingerBill d6c54148d9 Minor clean up 2023-01-12 15:23:59 +00:00
gingerBill cbe3791b42 Replace all queues with MPSCQueue where possible 2023-01-12 13:11:17 +00:00
gingerBill b470ceb470 Correct mpsc_dequeue 2023-01-12 12:59:09 +00:00
gingerBill c15db05199 Implement MPSCQueue 2023-01-12 12:41:53 +00:00
gingerBill 9428f792ed Comment out allocator guards for the time being 2023-01-12 01:09:36 +00:00
gingerBill 520ff731de Add ArenaTemp to the compiler 2023-01-12 00:47:20 +00:00
gingerBill e9cfe698ba Make the heap_allocator just be the permanent_allocator
This improves the speed of the compiler with very little memory increase (which surprised me, Ginger Bill)
2023-01-12 00:20:25 +00:00
gingerBill 5fa66ac6a8 Fix random race condition for poly records 2023-01-12 00:18:58 +00:00
gingerBill 320062157f Merge pull request #2288 from odin-lang/compiler-improvements-2023-01
Multithreading Compiler Improvements 2023-01
2023-01-11 22:14:53 +00:00
gingerBill d7d6608142 Remove unneeded CI stage 2023-01-11 22:08:25 +00:00
gingerBill 7f2ef2ac67 Move check for type info above 2023-01-11 21:52:04 +00:00
gingerBill 7124d541a1 General optimizations 2023-01-11 18:10:27 +00:00
gingerBill 3c7e45a46f Remove possible race condition in type_size_of/type_align_of 2023-01-11 17:45:18 +00:00
gingerBill 6ec014e980 Make -threaded-checker the default not (opt out with -no-threaded-checker) 2023-01-11 17:27:06 +00:00
gingerBill 9b47a5eddb Fix macro issue 2023-01-11 00:49:04 +00:00
gingerBill 3e8c63ad31 Add Odin check -threaded-checker test for windows 2023-01-10 20:46:00 +00:00
gingerBill 15469758de Merge branch 'master' into compiler-improvements-2023-01 2023-01-10 16:25:38 +00:00
gingerBill 86511d44e4 Merge pull request #2300 from MarenFayre/float-format
Clean up float_fmt logic
2023-01-10 15:46:54 +00:00
MarenFayre fd4633eb25 Clean up float_fmt logic 2023-01-10 15:03:53 +01:00
gingerBill b0756f9e29 Merge pull request #2297 from MarenFayre/d-parsing
Fix off by one error in %d parsing
2023-01-10 12:24:13 +00:00
gingerBill c3ff1e9591 Merge pull request #2298 from MarenFayre/left-pad
Fix left padding format specifier and float formatting
2023-01-10 12:24:07 +00:00
gingerBill dd3fac7523 Merge pull request #2292 from colrdavidson/get_core_count
add get core count
2023-01-10 11:42:02 +00:00
MarenFayre 13029d06b2 Removed unneeded semicolon. 2023-01-09 10:39:46 +01:00
MarenFayre 68173f4bc7 Remove unused formatting flag 2023-01-08 20:24:08 +01:00
MarenFayre c979c2fafa Fix left padding format specifier and float formatting 2023-01-08 20:00:42 +01:00
MarenFayre 658435f1b9 Fix off by one error in %d parsing 2023-01-08 19:59:48 +01:00
Colin Davidson 3935957979 remove unused c import 2023-01-06 13:53:32 -08:00
Colin Davidson a36640bcfc more windows fixes 2023-01-06 13:51:25 -08:00
Colin Davidson 171d5b4012 more windows kerfuffle 2023-01-06 13:45:21 -08:00
Colin Davidson 1cc893f21c Merge branch 'master' into get_core_count 2023-01-06 13:34:16 -08:00
Colin Davidson 6ff2db47b4 shuffle to private/public wrapper 2023-01-06 13:33:47 -08:00
gingerBill a11b6a9e5f Merge pull request #2265 from JooperGH/more_dwmapi_bindings
More dwmapi bindings
2023-01-06 12:18:10 +00:00
gingerBill 978568684c Merge pull request #2295 from matias-eduardo/patch-1
Add GetKeyboardState to user32
2023-01-06 12:16:51 +00:00
gingerBill e8e7d3ea31 Merge pull request #2293 from colrdavidson/fix_futexes
fix futex error handling
2023-01-06 12:09:44 +00:00
matias c03cc21908 Add GetKeyboardState to user32 2023-01-06 07:04:38 -04:00
gingerBill 8ef406324b Multi thread more of the backend where possible 2023-01-05 17:26:51 +00:00
gingerBill 23d0c52bf4 Refactor llvm backend code into separate procedures to make it simpler to profile 2023-01-05 16:42:02 +00:00
gingerBill 5eee8077dd enum-ifiy function pass managers for lbModule 2023-01-05 15:56:45 +00:00
gingerBill 029cb6581b Unify function pass managers for auxiliary procedures (e.g. startup type info, runtime, objc names) 2023-01-05 12:54:53 +00:00
gingerBill 025e87d974 Multithread LLVM procedure generation 2023-01-05 12:39:57 +00:00
gingerBill 213a0499a1 Begin multithreading the llvm backend when -use-separate-modules is enabled 2023-01-05 12:29:16 +00:00
gingerBill 1517f1d779 Add uncomment add_type_info_type calls for type assertions 2023-01-05 11:54:21 +00:00
Colin Davidson 50a2493fd3 add get thread count to openbsd 2023-01-05 01:48:00 -08:00
Colin Davidson b455ccd261 fix more things? 2023-01-05 01:37:50 -08:00
Colin Davidson a58650728e fix futex error handling 2023-01-05 01:27:37 -08:00
Colin Davidson b22ddb1453 fix windows structs 2023-01-05 01:25:18 -08:00
Colin Davidson cb7dd12222 name raw union 2023-01-05 01:18:44 -08:00
Colin Davidson 0484bdbb7e fix darwin/freebsd 2023-01-05 01:14:51 -08:00
Colin Davidson 8f39c45e9b use raw_union? 2023-01-05 01:11:46 -08:00
Colin Davidson 944396128b add get core count 2023-01-05 01:06:55 -08:00
gingerBill bbb2164e38 Inline map gets; cast explicitly on TOMBSTONE checking 2023-01-05 01:25:37 +00:00
gingerBill be23d83fc8 Remove unnecessary check is align_formula* et al 2023-01-05 00:47:09 +00:00
gingerBill 291ea33939 Initialize TypePath constructor like to keep the Futex constructor happy 2023-01-04 22:34:59 +00:00
gingerBill 9455918eec Fix min dep type info problem caused by const ref of map_set 2023-01-04 22:20:18 +00:00
gingerBill 8a99b8af3e Narrow mutex usage 2023-01-04 15:55:10 +00:00
gingerBill 12e42d92d3 Localize GenProcsData to the entity itself 2023-01-04 15:35:24 +00:00
gingerBill faa735d0c7 Localize gen_types mutexes 2023-01-04 15:15:12 +00:00
gingerBill d4e18109da Move walking of dependencies for procedures to just before calculating the min dep set 2023-01-04 13:52:38 +00:00
gingerBill d06a0e7093 Improve the PtrSet to be as simple and small as possible 2023-01-04 13:30:27 +00:00
gingerBill b3a55b8b6f Remove unused procedures 2023-01-03 18:42:13 +00:00
gingerBill ec69101101 Convert minimum_dependency_type_info_set to use a PtrMap 2023-01-03 18:39:37 +00:00
gingerBill 17fa8cb6ef Add extra mutex to TypePth just in case 2023-01-03 18:21:42 +00:00
gingerBill 855ebceadc Minimize add_type_info_type usage 2023-01-03 17:26:05 +00:00
gingerBill 2720e98127 Add +ignore along with +build ignore 2023-01-03 17:25:51 +00:00
gingerBill bb80c1b059 Add type_and_value_mutex to DeclInfo 2023-01-03 17:07:53 +00:00
gingerBill 85e390deba Minimize calling of Ast::thread_safe_file() when cloning 2023-01-03 15:57:09 +00:00
gingerBill dc317c8cd8 Make BlockingMutex 2023-01-03 15:50:31 +00:00
gingerBill 774fea1e63 Use RwMutex for gen_procs 2023-01-03 15:47:25 +00:00
gingerBill 485c606672 Clarify RwLocks for add_dependenies_from_unpacking 2023-01-03 15:37:35 +00:00
gingerBill 3dee3205b2 Use RwMutex for DeclInfo `deps 2023-01-03 15:34:52 +00:00
gingerBill c7a704d345 Use RwMutex for the Scope 2023-01-03 15:26:47 +00:00
gingerBill 0fb3032b73 General improves to alloc_ast_node and other unnecessary checks 2023-01-03 14:45:09 +00:00
gingerBill 69934c3b0b More for_array(i, y) to for (x : y) translations 2023-01-03 13:04:09 +00:00
gingerBill 7380b7e61b Add more uses of C++ style for loops over for_array macro 2023-01-03 12:37:41 +00:00
gingerBill 747a11a954 Allow all set entry types to be implicitly cast to their key/value type to allow for easier iteration 2023-01-03 12:18:35 +00:00
gingerBill 252be0fb41 Make all maps use heap allocator implicitly 2023-01-03 11:59:52 +00:00
gingerBill 600f2b7284 Use heap_allocator for all hash set types 2023-01-03 11:53:59 +00:00
gingerBill 670274ad8f More explicit uses of mutexes 2023-01-02 23:56:37 +00:00
gingerBill e10fe91eba Narrow global gen_procs_mutex further 2023-01-02 23:50:48 +00:00
gingerBill fd62ee14cd Code moving around 2023-01-02 23:31:38 +00:00
gingerBill 8ece92f1f6 Minimize the parapoly mutex usage a bit 2023-01-02 23:21:16 +00:00
gingerBill 69b075782b Use a package local mutex for add_type_and_value 2023-01-02 22:40:28 +00:00
gingerBill 6bd3a9d422 Be very explicit where the gen_procs_mutex can be unlock 2023-01-02 22:23:49 +00:00
gingerBill bc9ee8e1a4 Remove loops within futex signals on Linux 2023-01-02 22:13:49 +00:00
gingerBill d36c3c2590 Re enable type_and_value_mutex 2023-01-02 22:06:05 +00:00
gingerBill 52b319dbfd Fix darwin's futex implementation in the compiler 2023-01-02 21:53:41 +00:00
gingerBill 318d92f9a8 Comment out type_and_value_mutex usage 2023-01-02 21:37:21 +00:00
gingerBill 7ffffeeccc Comment out many mutex guards in type_(size|align)_of_internal 2023-01-02 21:35:40 +00:00
gingerBill f16d8e77b3 Narrow fullpath_mutex usage 2023-01-02 20:55:49 +00:00
gingerBill 5b335bb88c Narrow g_type_mutex usage 2023-01-02 20:48:24 +00:00
gingerBill df2767311f Use mutex_try_lock in check_proc_info 2023-01-02 20:42:22 +00:00
gingerBill 09c26e6be0 Narrow type info mutex usage 2023-01-02 20:38:37 +00:00
gingerBill d2ec2d1606 Remove another use of a global mutex 2023-01-02 19:46:55 +00:00
gingerBill 0d87b2e8db Use local mutexes rather than a global one for the dependency insertion 2023-01-02 19:39:35 +00:00
gingerBill 1568971732 Fix pool running 2023-01-02 18:04:16 +00:00
gingerBill 0e040be941 Add define for darwin 2023-01-02 17:49:16 +00:00
gingerBill 9737b65d9c Explicitly call store for futex 2023-01-02 17:18:59 +00:00
gingerBill ad52003077 Remove some unneeded checks 2023-01-02 17:15:29 +00:00
gingerBill c386509112 Minor clean up of thread pool code 2023-01-02 17:06:29 +00:00
gingerBill c293f5b7eb Remove unneeded mutex 2023-01-02 16:56:05 +00:00
gingerBill fa562ec5d6 Remove unneeded local_entity_map 2023-01-02 15:40:25 +00:00
gingerBill 529383f5b1 Correct a race condition when checking the procedure body 2023-01-02 15:30:04 +00:00
gingerBill f01cff7ff0 Multithread checker 2023-01-02 12:31:00 +00:00
gingerBill 015fe924b8 Remove use of queues for procedure checking. 2023-01-02 12:28:38 +00:00
gingerBill a5ce8a8c0b Multi thread check_export_entities 2023-01-02 01:31:14 +00:00
gingerBill bfdcf900ef Remove global_ prefix from global_thread_pool_* procedures 2023-01-02 00:56:06 +00:00
gingerBill 54f89dd84b Multithread check_collect_entities_all using new thread pool 2023-01-02 00:53:11 +00:00
gingerBill da479c7628 Minor style change 2023-01-02 00:35:12 +00:00
gingerBill 3c90a05957 Replace condition+mutex with futex 2023-01-02 00:26:17 +00:00
gingerBill d16ddf7926 Use C++ style for loop over for_array macro in parser.cpp where posible 2023-01-01 16:32:51 +00:00
gingerBill 5c519f0e8d Remove the synchronization primitive init/destroy calls 2023-01-01 16:19:21 +00:00
gingerBill 74e6d9144e Get around the std::atomic issue 2023-01-01 16:15:35 +00:00
gingerBill 20d451396d Begin work on futex-ifying the threading primitives 2023-01-01 15:06:57 +00:00
gingerBill 60d0390ef8 Unify compiler Futex interface 2023-01-01 14:48:31 +00:00
gingerBill 782f1b4718 Merge pull request #2278 from wjlroe/stb-darwin-universal-libraries
Universal stb libraries for macOS (Intel & Apple Silicon)
2023-01-01 14:10:35 +00:00
gingerBill 85f0a1067c Merge pull request #2280 from DragosPopse/master
Fixed empty output_path.name when building a folder with no subfolders
2023-01-01 14:09:51 +00:00
gingerBill c08ff891ad Merge pull request #2287 from odin-lang/compiler-improvements-2022-12
Compiler improvements 2022 12
2023-01-01 13:29:20 +00:00
gingerBill 168cec1e9d Merge pull request #2283 from colrdavidson/threadpool-swap
move to work-stealing threadpool
2023-01-01 13:28:36 +00:00
gingerBill 28fb35f2f7 Merge pull request #2263 from odin-lang/compiler-improvements-2022-12
Compiler Improvements for 2022-12
2023-01-01 13:26:43 +00:00
gingerBill c1384afe2f Merge branch 'master' into compiler-improvements-2022-12 2023-01-01 13:10:49 +00:00
gingerBill 547c7bce1b Merge pull request #2284 from thePHTest/master
fixup are_types_identical for comparing procs and checking if parameter names differ
2022-12-30 11:19:31 +00:00
Phil 0bb93d40d3 fixup are_types_identical for comparing procs and checking if parameter names differ 2022-12-29 16:10:13 -08:00
Colin Davidson 27ba1d596c rework openbsd futexes a little 2022-12-29 12:00:16 -08:00
Colin Davidson 98e5523f2f cover openbsd too 2022-12-29 11:46:43 -08:00
Colin Davidson 223b66f422 oops if->elif 2022-12-29 11:06:35 -08:00
Colin Davidson 04a4dbcdaf add freebsd support 2022-12-29 11:05:31 -08:00
Colin Davidson ef9e31cb31 fix ulock/uwait imports 2022-12-28 22:08:39 -08:00
Colin Davidson e019673a18 fix build 2022-12-28 21:52:41 -08:00
Colin Davidson 5f27f2dd7f move to work-stealing threadpool 2022-12-28 21:44:17 -08:00
Dragos Popescu cfccf73cdd Merge branch 'odin-lang:master' into master 2022-12-26 19:22:47 +02:00
Dragos 465d003b1e Patched empty output_path.name when building a folder 2022-12-26 19:21:24 +02:00
Mikkel Hjortshøj 1d6f7680a1 Update stale.yml
Update stale action to *not* delete issues/PRs anymore and only mark them as stale, also update the version
2022-12-24 15:44:32 +01:00
Jeroen van Rijn 5d0f9c428a Merge pull request #2279 from ftphikari/master
Replaced opaque bit-shifts with readable constants for memory units
2022-12-24 07:32:29 +01:00
hikari d904ae5191 Replaced opaque bit-shifts with readable constants for memory units 2022-12-24 08:27:15 +02:00
William Roe 8a822bdd9a Update stb macOS libraries to be universal
This updates all the darwin stb libraries to be built as universal
libraries - meaning they contain both Intel and Apple Silicon versions.
This should make these more generally compatible.

Also, add stb_vorbis.a in the same way. Not sure why it was missing
before.
2022-12-23 23:15:14 +00:00
William Roe d1a3842e39 Add Darwin-target for building vendor/stb macos universal libs
This Darwin-specific target builds each stb library with macOS-specific
options so that the results are universal static libraries that should
work on Intel (x86_64) and Apple Silicon (arm64) machines. They also
should work on macOS 10.12 and above (which should match what Odin
compiles for).

The default Makefile target will build the darwin rule if its invoked on
a macOS machine, otherwise it'll invoke the more general unix target.
2022-12-23 23:15:14 +00:00
gingerBill 00823ca88c Remove a few TODOs 2022-12-22 13:03:34 +00:00
gingerBill ffa14c3aad Remove need the MPMC in single threaded case 2022-12-22 12:58:23 +00:00
gingerBill 41b32f0da4 Clean up mutex usage in the parser 2022-12-22 12:45:23 +00:00
gingerBill c53b2198a8 Add minor comment 2022-12-22 12:02:14 +00:00
gingerBill 9b278db993 Revert "Change tav to be a pointer internally"
This reverts commit e98f1a28e6.
2022-12-22 12:01:41 +00:00
gingerBill e98f1a28e6 Change tav to be a pointer internally 2022-12-22 11:53:13 +00:00
gingerBill c8f05b7c0c Merge pull request #2269 from Skytrias/luapattern
Add lua pattern matching to core:text with tests
2022-12-22 11:08:10 +00:00
gingerBill b00c4a6a8f Merge pull request #2272 from sir-w7/fix/darwin_mem_leak
Fixed memory leak in dir_darwin.odin.
2022-12-22 10:58:59 +00:00
gingerBill 84e1fb2cee Merge pull request #2275 from Platin21/fix/dir-opening-macOS
Fix/dir opening mac os
2022-12-22 10:49:41 +00:00
Platin21 b983ac548c Moves check up and sets flag to rdonly if dir is opened.. 2022-12-22 01:36:04 +01:00
Platin21 fb562ea708 Adds error casting from last error if open fails 2022-12-22 01:26:06 +01:00
Platin21 cdeeeafc3f Fixed issues with dir opening on macOS 2022-12-22 01:22:31 +01:00
gingerBill b9a2426e57 Merge branch 'master' into compiler-improvements-2022-12 2022-12-21 23:59:31 +00:00
gingerBill 81037b3091 Change the order of the args and ret for Arm64 ABI 2022-12-21 23:56:34 +00:00
Jooper fc3c76f946 Fixed CI error 2022-12-21 22:18:13 +00:00
Andrea Piseri 3fa971a510 Add the inner for loop back in the logic
This could be easier to predict in cases where one of `left` and `right`
is significantly greater than the other, and as such the same branch is
taken multiple times in a row
2022-12-21 22:10:02 +01:00
skytrias 63a0395a79 refactor SPECIALS_TABLE 2022-12-21 22:08:03 +01:00
Andrea Piseri 191223bb3c Fix non-generic cast in core:slice.rotate_left 2022-12-21 21:58:01 +01:00
gingerBill 6f0bad816e Merge pull request #2248 from tstibor/fix_test_out
Enable -out:<filepath> for build and runs with the attribute @(test)
2022-12-21 20:38:54 +00:00
skytrias 94af3c2887 package name changed 2022-12-21 21:38:21 +01:00
skytrias e5d0417a6c folder name changed 2022-12-21 21:36:50 +01:00
gingerBill c02bda2427 Merge pull request #2256 from Lperlind/staging/small_array_utilities
Add more utility procedures to small array
2022-12-21 20:28:40 +00:00
Andrea Piseri 385d2a143c Fix core:slice.rotate_left
This commit includes two fixes:
- a temporary cast to make the function compile
- a fix to a logic error that caused the function to hang or return
  incorrect results
2022-12-21 21:09:22 +01:00
sir-w7 67c1b364c4 Fixed memory leak in dir_darwin.odin. 2022-12-21 07:25:13 -08:00
Lucas Perlind f029b4beb1 Add more utility procedures to small array 2022-12-21 13:00:33 +11:00
gingerBill 3040361fac Correct type_ptr_set_update and type_ptr_set_exists 2022-12-20 14:59:00 +00:00
gingerBill 44caa96d50 Set the file's filename and directory in init_ast_file 2022-12-20 14:56:44 +00:00
skytrias 1bea0f3772 fix styling issues and use switches in cases its necessary, add comments to helpers 2022-12-20 15:48:10 +01:00
gingerBill eb0775ad53 Move mutex use around in thread pool 2022-12-20 14:45:01 +00:00
gingerBill 8fc9566a83 Use *_set_update where possible 2022-12-20 14:19:55 +00:00
gingerBill 134c7db4d2 Combine join and destroy for threads 2022-12-20 14:08:24 +00:00
gingerBill a0e3a99dd1 Remove need for semaphore in Thread 2022-12-20 14:07:14 +00:00
gingerBill 0edda2bea7 Clarify ThreadPool interface; Move import_mutex guarding to just the string set 2022-12-20 12:46:33 +00:00
skytrias ff7f139fd7 add iter_index and update tests to use easier matcher setup 2022-12-20 12:59:32 +01:00
JooperGH 86a606e716 App bar bindings 2022-12-19 16:31:32 +00:00
JooperGH 1e97588e7b One last binding 2022-12-19 15:29:07 +00:00
JooperGH 3ccc0b5aa6 HRGB and Rect functions 2022-12-19 15:22:05 +00:00
JooperGH 5464a605b1 CreateSolidBrush and FillRect 2022-12-19 13:21:16 +00:00
JooperGH 5519749aa4 Added uxtheme bindings 2022-12-19 11:54:15 +00:00
JooperGH 4a70265bfb Merge branch 'master' of https://github.com/odin-lang/Odin into more_dwmapi_bindings 2022-12-19 11:46:35 +00:00
JooperGH de0d860880 Added more DWMAPI bindings 2022-12-19 11:43:16 +00:00
gingerBill a13e2f4578 Fix minor race condition 2022-12-19 00:29:40 +00:00
gingerBill 01b508f182 Use usize for bounds checking in Array and Slice (compiler) 2022-12-18 23:26:44 +00:00
gingerBill 2a8fa8612d Use fetch_add rather than += 2022-12-18 23:24:34 +00:00
gingerBill e27046098b Add missing gb_internal 2022-12-18 22:58:34 +00:00
gingerBill ca8b148fdc Add gb_internal to path procedures 2022-12-18 22:52:18 +00:00
gingerBill c1f5be24e2 Remove dead code in the compiler 2022-12-18 22:49:10 +00:00
gingerBill 6cdec65ca1 gb_internal LLVM backend 2022-12-18 22:32:05 +00:00
skytrias 967afd8bbb try helper procedures / structs 2022-12-18 23:11:23 +01:00
skytrias 0ae1812f90 small fixes and oob checks, stop infinite loops on empty matches 2022-12-18 23:11:23 +01:00
skytrias eb5523d5d3 case insensitive helper call 2022-12-18 23:11:23 +01:00
skytrias 3f4bbbec29 add proper unicode walking 2022-12-18 23:11:23 +01:00
skytrias 70bd220f34 balanced string, frontier pattern, gsub_with and their tests added 2022-12-18 23:11:23 +01:00
skytrias bd3596f012 create lua strlib text package and tests 2022-12-18 23:11:23 +01:00
gingerBill 66ce990e0b gb_internal to docs and other auxiliary files 2022-12-18 21:51:04 +00:00
gingerBill 690666537c Add gb_internal to checker 2022-12-18 21:46:27 +00:00
gingerBill 056ba1ed13 Even more gb_internal everywhere 2022-12-18 21:24:45 +00:00
gingerBill 93a1f2bf61 Merge remote-tracking branch 'remotes/Odin-GitHub/master' into compiler-improvements-2022-12 2022-12-18 21:17:19 +00:00
gingerBill ac5f5a33e9 gb_internal a lot 2022-12-18 21:17:07 +00:00
gingerBill 0829ac30f7 Merge pull request #2249 from tstibor/fix_odinfmt
Update odinfmt with new filepath.Walk_Proc signature
2022-12-15 10:11:42 +00:00
Thomas Stibor 9d50a04905 Update odinfmt with new filepath.Walk_Proc signature
Commit f9f4551e8d introduced
the additional parameter: `user_data: rawptr` to `filepath.Walk_Proc` callback.
This commit updates odinfmt to meet this new additional parameter.
2022-12-15 09:23:43 +01:00
Thomas Stibor 1ca7da6914 Enable -out:<filepath> for build and runs with the attribute @(test)
According to the odin help command
$ odin help test
...
-out:<filepath>
	Set the file name of the outputted executable
	Example: -out:foo.exe

building and running tests the executable output filepath shall be
specified. However, the -out parameter is disabled, resulting in error message:

Unknown flag for 'odin test': 'out'
'out' is supported with the following commands:
	run, build

Omitting the -out parameter results in default filepath '01.bin' (on Linux).
However, it is desirable for user specifying the output filepath, e.g. by
using this Makefile snippet:

TARGET=main
FLAGS=-warnings-as-errors -verbose-errors

all: run

run:
        @odin run . $(FLAGS) -out:$(TARGET)

test:
        @odin test . $(FLAGS) -out:$(TARGET)

clean:
        @rm -f $(TARGET)

In addition a typo is fixed.
2022-12-14 14:26:32 +01:00
gingerBill 56e050fbc9 Merge pull request #2245 from Said6289/small-typo-in-linalg-any
Fix typo in linalg.any
2022-12-13 11:37:59 +00:00
Said Al Attrach 70e48e39a4 Fix typo in linalg.any 2022-12-13 12:18:58 +01:00
gingerBill 2b0c04f27e Merge pull request #2244 from ftphikari/master
sys/windows: add GetMonitorInfoW
2022-12-13 11:18:35 +00:00
hikari 1ddbe16d28 sys/windows: add GetMonitorInfoW 2022-12-13 10:25:18 +02:00
Jeroen van Rijn 09c1128d9e Merge pull request #2242 from Tetralux/fix-shrink-array
[runtime] Fix typo in shrink_dynamic_array()
2022-12-11 20:14:21 +01:00
Tetralux 588c52a854 [runtime] Fix typo in shrink_dynamic_array() 2022-12-11 09:10:17 +00:00
Jeroen van Rijn 86ec3bcb44 Merge pull request #2238 from awwdev/reflect-procs-aliasing-runtime
Aliasing some procs to avoid code repetition
2022-12-09 19:36:59 +01:00
Jeroen van Rijn 9fc606de48 Merge pull request #2239 from awwdev/patch-3
Fix typo err: runtime.Allocator to Allocator_Error
2022-12-09 19:33:02 +01:00
André (counter) 7fbee88061 Fix typo err: runtime.Allocator to Allocator_Error 2022-12-09 19:20:03 +01:00
André (counter) b3be2cdf9d Aliasing some procs to avoid code repetition
Aliasing some procedures within package reflect so they reference procedures from package runtime.
This avoids redundancy and potential deviation.
Not 100% sure about the ODIN_DISALLOW_RTTI part but I think it should be congruent as well.
2022-12-09 18:14:47 +01:00
gingerBill ff6b76986a Use C++11 loops for some arrays 2022-12-09 12:32:54 +00:00
gingerBill 5c3624eb86 Fix map looping 2022-12-09 12:18:49 +00:00
gingerBill 144e357fd2 Add extra check 2022-12-09 11:37:15 +00:00
gingerBill be22f0d1e1 Fix variable shadow in compiler 2022-12-09 11:32:52 +00:00
gingerBill 34a048f7da Replace compiler for loops for the hash-table types to simplify code usage 2022-12-09 11:29:28 +00:00
gingerBill ffe953b43d Make os.get_last_error contextless 2022-12-08 16:04:03 +00:00
gingerBill b8eacfc7b6 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-12-08 15:58:44 +00:00
gingerBill f8452bf1fc Add different variants for once_do 2022-12-08 15:58:39 +00:00
gingerBill 20943a81c1 Make sync calls contextless where possible 2022-12-08 15:55:53 +00:00
gingerBill 1c4e75e83f Merge pull request #2234 from ftphikari/master
sys/windows: add DescribePixelFormat
2022-12-08 14:59:48 +00:00
gingerBill 9cb9964c2d Remove old code 2022-12-08 00:52:11 +00:00
gingerBill 1f8f94276e Initialize the multiple return value map in lb_create_dummy_procedure 2022-12-07 16:44:26 +00:00
hikari 0d7c89e84a sys/windows: add DescribePixelFormat 2022-12-07 14:33:12 +02:00
gingerBill a5bdb4a8e8 Merge pull request #2208 from odin-lang/multiple-return-abi-experiment
Multiple Return ABI Changes and Improvements
2022-12-07 11:42:23 +00:00
gingerBill d88b052d2d Naïve optimization of named _split_ multiple return valued when defer is never used
This is a naïve optimization but it helps a lot in the general case where callee temporary stack variables
are not allocated to represent the named return values by using that specific memory.

In the future, try to check if a specific named return value is ever used a `defer` within a procedure or not,
or is ever passed to a nested procedure call (e.g. possibly escapes).
2022-11-25 23:57:55 +00:00
gingerBill 615eccb6d1 Correct return ptr semantics for split returns 2022-11-24 14:26:45 +00:00
gingerBill d3c65b6ba5 Make split multiple return logic only work for the native Odin calling conventions 2022-11-24 13:16:02 +00:00
gingerBill 90415e4a6e Add split multiple return to different ABIs 2022-11-24 12:14:19 +00:00
gingerBill 7352c312e0 Fix type for split returns code 2022-11-24 11:20:28 +00:00
gingerBill 0befadde1d Basic copy elision support for multiple return values 2022-11-24 01:27:39 +00:00
gingerBill aef8b25a8e Listen to past Bill's wisdom 2022-11-23 23:54:12 +00:00
gingerBill ae81117f70 Merge branch 'master' into multiple-return-abi-experiment 2022-11-23 23:43:00 +00:00
gingerBill b7b9a016d3 Merge branch 'master' into multiple-return-abi-experiment 2022-11-23 22:48:56 +00:00
gingerBill 708a1b0cd3 Clean up return logic for split multiple return ABI experiment 2022-11-23 16:42:26 +00:00
gingerBill 7ab591667a Basic support for new ABI experiment on Win64 2022-11-23 16:25:09 +00:00
gingerBill 0a0db23b17 Remove copy elision code 2022-11-22 15:49:27 +00:00
137 changed files with 11605 additions and 8901 deletions
+2 -2
View File
@@ -13,7 +13,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Close Stale Issues
uses: actions/stale@v4.1.0
uses: actions/stale@v7.0.0
with:
# stale-issue-message: |
# Hello!
@@ -36,7 +36,7 @@ jobs:
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
days-before-stale: 120
days-before-close: 30
days-before-close: -1
exempt-draft-pr: true
ascending: true
operations-per-run: 1000
+3 -1
View File
@@ -62,12 +62,14 @@ if %release_mode% EQU 0 ( rem Debug
set compiler_warnings= ^
-W4 -WX ^
-wd4100 -wd4101 -wd4127 -wd4146 ^
-wd4505 ^
-wd4456 -wd4457
set compiler_includes= ^
/Isrc\
set libs= ^
kernel32.lib ^
Synchronization.lib ^
bin\llvm\windows\LLVM-C.lib
set linker_flags= -incremental:no -opt:ref -subsystem:console
@@ -94,4 +96,4 @@ if %release_mode% EQU 0 odin run examples/demo
del *.obj > NUL 2> NUL
:end_of_build
:end_of_build
+1 -1
View File
@@ -50,7 +50,7 @@ config_darwin() {
panic "Requirement: llvm-config must be base version smaller than 15"
fi
LDFLAGS="$LDFLAGS -liconv -ldl"
LDFLAGS="$LDFLAGS -liconv -ldl -framework System"
CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS -lLLVM-C"
}
+1 -1
View File
@@ -108,7 +108,7 @@ when ODIN_OS == .Linux {
cnd_destroy :: proc(cond: ^cnd_t) ---
cnd_init :: proc(cond: ^cnd_t) -> int ---
cnd_signal :: proc(cond: ^cnd_t) -> int ---
cnd_timedwait :: proc(cond: ^cnd_t, ts: ^timespec) -> int ---
cnd_timedwait :: proc(cond: ^cnd_t, mtx: ^mtx_t, ts: ^timespec) -> int ---
cnd_wait :: proc(cond: ^cnd_t, mtx: ^mtx_t) -> int ---
// 7.26.4 Mutex functions
+46 -1
View File
@@ -1,6 +1,8 @@
package container_small_array
import "core:builtin"
import "core:runtime"
_ :: runtime
Small_Array :: struct($N: int, $T: typeid) where N >= 0 {
data: [N]T,
@@ -32,6 +34,20 @@ get_ptr :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int) -> ^T {
return &a.data[index]
}
get_safe :: proc(a: $A/Small_Array($N, $T), index: int) -> (T, bool) #no_bounds_check {
if index < 0 || index >= a.len {
return {}, false
}
return a.data[index], true
}
get_ptr_safe :: proc(a: ^$A/Small_Array($N, $T), index: int) -> (^T, bool) #no_bounds_check {
if index < 0 || index >= a.len {
return {}, false
}
return &a.data[index], true
}
set :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, item: T) {
a.data[index] = item
}
@@ -93,7 +109,7 @@ pop_front_safe :: proc "contextless" (a: ^$A/Small_Array($N, $T)) -> (item: T, o
copy(s[:], s[1:])
a.len -= 1
ok = true
}
}
return
}
@@ -102,6 +118,23 @@ consume :: proc "odin" (a: ^$A/Small_Array($N, $T), count: int, loc := #caller_l
a.len -= count
}
ordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check {
runtime.bounds_check_error_loc(loc, index, a.len)
if index+1 < a.len {
copy(a.data[index:], a.data[index+1:])
}
a.len -= 1
}
unordered_remove :: proc "contextless" (a: ^$A/Small_Array($N, $T), index: int, loc := #caller_location) #no_bounds_check {
runtime.bounds_check_error_loc(loc, index, a.len)
n := a.len-1
if index != n {
a.data[index] = a.data[n]
}
a.len -= 1
}
clear :: proc "contextless" (a: ^$A/Small_Array($N, $T)) {
resize(a, 0)
}
@@ -111,6 +144,18 @@ push_back_elems :: proc "contextless" (a: ^$A/Small_Array($N, $T), items: ..T) {
a.len += n
}
inject_at :: proc "contextless" (a: ^$A/Small_Array($N, $T), item: T, index: int) -> bool #no_bounds_check {
if a.len < cap(a^) && index >= 0 && index <= len(a^) {
a.len += 1
for i := a.len - 1; i >= index + 1; i -= 1 {
a.data[i] = a.data[i - 1]
}
a.data[index] = item
return true
}
return false
}
append_elem :: push_back
append_elems :: push_back_elems
push :: proc{push_back, push_back_elems}
+4
View File
@@ -262,10 +262,14 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
}
map_cap := uintptr(runtime.map_cap(m^))
ks, vs, hs, _, _ := runtime.map_kvh_data_dynamic(m^, info.map_info)
i := 0
for bucket_index in 0..<map_cap {
if !runtime.map_hash_is_valid(hs[bucket_index]) {
continue
}
opt_write_iteration(w, opt, i) or_return
i += 1
key := rawptr(runtime.map_cell_index_dynamic(ks, info.map_info.ks, bucket_index))
value := rawptr(runtime.map_cell_index_dynamic(vs, info.map_info.vs, bucket_index))
+23 -74
View File
@@ -547,7 +547,7 @@ _parse_int :: proc(s: string, offset: int) -> (result: int, new_offset: int, ok:
is_digit :: #force_inline proc(r: byte) -> bool { return '0' <= r && r <= '9' }
new_offset = offset
for new_offset <= len(s) {
for new_offset < len(s) {
c := s[new_offset]
if !is_digit(c) {
break
@@ -678,7 +678,7 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
}
} else if fi.zero && fi.width_set {
prec = fi.width
if neg || fi.plus || fi.space {
if neg || fi.plus {
// There needs to be space for the "sign"
prec -= 1
}
@@ -697,7 +697,6 @@ _fmt_int :: proc(fi: ^Info, u: u64, base: int, is_signed: bool, bit_size: int, d
flags: strconv.Int_Flags
if fi.hash && !fi.zero { flags |= {.Prefix} }
if fi.plus { flags |= {.Plus} }
if fi.space { flags |= {.Space} }
s := strconv.append_bits(buf[start:], u, base, is_signed, bit_size, digits, flags)
if fi.hash && fi.zero && fi.indent == 0 {
@@ -744,7 +743,7 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
}
} else if fi.zero && fi.width_set {
prec = fi.width
if neg || fi.plus || fi.space {
if neg || fi.plus {
// There needs to be space for the "sign"
prec -= 1
}
@@ -763,7 +762,6 @@ _fmt_int_128 :: proc(fi: ^Info, u: u128, base: int, is_signed: bool, bit_size: i
flags: strconv.Int_Flags
if fi.hash && !fi.zero { flags |= {.Prefix} }
if fi.plus { flags |= {.Plus} }
if fi.space { flags |= {.Space} }
s := strconv.append_bits_128(buf[start:], u, base, is_signed, bit_size, digits, flags)
if fi.hash && fi.zero && fi.indent == 0 {
@@ -867,79 +865,30 @@ _pad :: proc(fi: ^Info, s: string) {
}
}
_fmt_float_as :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune, float_fmt: byte) {
prec := fi.prec if fi.prec_set else 3
buf: [386]byte
// Can return "NaN", "+Inf", "-Inf", "+<value>", "-<value>".
str := strconv.append_float(buf[:], v, float_fmt, prec, bit_size)
if !fi.plus {
// Strip sign from "+<value>" but not "+Inf".
if str[0] == '+' && str[1] != 'I' {
str = str[1:]
}
}
_pad(fi, str)
}
fmt_float :: proc(fi: ^Info, v: f64, bit_size: int, verb: rune) {
switch verb {
case 'f', 'F', 'g', 'G', 'v':
prec: int = 3
if fi.prec_set {
prec = fi.prec
}
buf: [386]byte
str := strconv.append_float(buf[1:], v, 'f', prec, bit_size)
b := buf[:len(str)+1]
if b[1] == '+' || b[1] == '-' {
b = b[1:]
} else {
b[0] = '+'
}
if fi.space && !fi.plus && b[0] == '+' {
b[0] = ' '
}
if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') {
io.write_string(fi.writer, string(b), &fi.n)
return
}
if fi.plus || b[0] != '+' {
if fi.zero && fi.width_set && fi.width > len(b) {
io.write_byte(fi.writer, b[0], &fi.n)
fmt_write_padding(fi, fi.width - len(b))
io.write_string(fi.writer, string(b[1:]), &fi.n)
} else {
_pad(fi, string(b))
}
} else {
_pad(fi, string(b[1:]))
}
_fmt_float_as(fi, v, bit_size, verb, 'f')
case 'e', 'E':
prec: int = 3
if fi.prec_set {
prec = fi.prec
}
buf: [386]byte
str := strconv.append_float(buf[1:], v, 'e', prec, bit_size)
b := buf[:len(str)+1]
if b[1] == '+' || b[1] == '-' {
b = b[1:]
} else {
b[0] = '+'
}
if fi.space && !fi.plus && b[0] == '+' {
b[0] = ' '
}
if len(b) > 1 && (b[1] == 'N' || b[1] == 'I') {
io.write_string(fi.writer, string(b), &fi.n)
return
}
if fi.plus || str[0] != '+' {
if fi.zero && fi.width_set && fi.width > len(b) {
io.write_byte(fi.writer, b[0], &fi.n)
fmt_write_padding(fi, fi.width - len(b))
io.write_string(fi.writer, string(b[1:]), &fi.n)
} else {
_pad(fi, string(b))
}
} else {
_pad(fi, string(b[1:]))
}
// BUG(): "%.3e" returns "3.000e+00"
_fmt_float_as(fi, v, bit_size, verb, 'e')
case 'h', 'H':
prev_fi := fi^
+1 -1
View File
@@ -118,7 +118,7 @@ XXH_mul_64_to_128_fold_64 :: #force_inline proc(lhs, rhs: xxh_u64) -> (res: xxh_
}
@(optimization_mode="speed")
XXH_xorshift_64 :: #force_inline proc(v: xxh_u64, auto_cast shift: uint) -> (res: xxh_u64) {
XXH_xorshift_64 :: #force_inline proc(v: xxh_u64, #any_int shift: uint) -> (res: xxh_u64) {
return v ~ (v >> shift)
}
+1 -1
View File
@@ -531,7 +531,7 @@ not_equal :: proc{not_equal_single, not_equal_array}
any :: proc(x: $A/[$N]bool) -> (out: bool) {
for e in x {
if x {
if e {
return true
}
}
+1 -1
View File
@@ -153,7 +153,7 @@ scratch_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
s := (^Scratch_Allocator)(allocator_data)
if s.data == nil {
DEFAULT_BACKING_SIZE :: 1<<22
DEFAULT_BACKING_SIZE :: 4 * Megabyte
if !(context.allocator.procedure != scratch_allocator_proc &&
context.allocator.data != allocator_data) {
panic("cyclic initialization of the scratch allocator with itself")
+5 -5
View File
@@ -3,11 +3,11 @@ package mem
import "core:runtime"
import "core:intrinsics"
Byte :: 1
Kilobyte :: 1024 * Byte
Megabyte :: 1024 * Kilobyte
Gigabyte :: 1024 * Megabyte
Terabyte :: 1024 * Gigabyte
Byte :: runtime.Byte
Kilobyte :: runtime.Kilobyte
Megabyte :: runtime.Megabyte
Gigabyte :: runtime.Gigabyte
Terabyte :: runtime.Terabyte
set :: proc "contextless" (data: rawptr, value: byte, len: int) -> rawptr {
return runtime.memset(data, i32(value), len)
-13
View File
@@ -23,16 +23,3 @@ make_any :: proc "contextless" (data: rawptr, id: typeid) -> any {
}
raw_data :: builtin.raw_data
Poly_Raw_Map_Entry :: struct($Key, $Value: typeid) {
hash: uintptr,
next: int,
key: Key,
value: Value,
}
Poly_Raw_Map :: struct($Key, $Value: typeid) {
hashes: []int,
entries: [dynamic]Poly_Raw_Map_Entry(Key, Value),
}
+42 -19
View File
@@ -1,6 +1,7 @@
package mem_virtual
import "core:mem"
import "core:sync"
Arena_Kind :: enum uint {
Growing = 0, // Chained memory blocks (singly linked list).
@@ -15,15 +16,16 @@ Arena :: struct {
total_reserved: uint,
minimum_block_size: uint,
temp_count: uint,
mutex: sync.Mutex,
}
// 1 MiB should be enough to start with
DEFAULT_ARENA_STATIC_COMMIT_SIZE :: 1<<20
DEFAULT_ARENA_STATIC_COMMIT_SIZE :: mem.Megabyte
DEFAULT_ARENA_GROWING_MINIMUM_BLOCK_SIZE :: DEFAULT_ARENA_STATIC_COMMIT_SIZE
// 1 GiB on 64-bit systems, 128 MiB on 32-bit systems by default
DEFAULT_ARENA_STATIC_RESERVE_SIZE :: 1<<30 when size_of(uintptr) == 8 else 1<<27
DEFAULT_ARENA_STATIC_RESERVE_SIZE :: mem.Gigabyte when size_of(uintptr) == 8 else 128 * mem.Megabyte
@@ -78,6 +80,8 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
return nil, nil
}
sync.mutex_guard(&arena.mutex)
switch arena.kind {
case .Growing:
if arena.curr_block == nil || (safe_add(arena.curr_block.used, size) or_else 0) > arena.curr_block.reserved {
@@ -116,6 +120,8 @@ arena_alloc :: proc(arena: ^Arena, size: uint, alignment: uint, loc := #caller_l
}
arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location) -> bool {
sync.mutex_guard(&arena.mutex)
if arena.curr_block != nil {
assert(arena.kind != .Growing, "expected a non .Growing arena", loc)
@@ -135,6 +141,7 @@ arena_static_reset_to :: proc(arena: ^Arena, pos: uint, loc := #caller_location)
}
arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_location) {
sync.mutex_guard(&arena.mutex)
if free_block := arena.curr_block; free_block != nil {
assert(arena.kind == .Growing, "expected a .Growing arena", loc)
arena.curr_block = free_block.prev
@@ -145,6 +152,7 @@ arena_growing_free_last_memory_block :: proc(arena: ^Arena, loc := #caller_locat
arena_free_all :: proc(arena: ^Arena) {
switch arena.kind {
case .Growing:
sync.mutex_guard(&arena.mutex)
for arena.curr_block != nil {
arena_growing_free_last_memory_block(arena)
}
@@ -287,6 +295,8 @@ Arena_Temp :: struct {
@(require_results)
arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena_Temp) {
assert(arena != nil, "nil arena", loc)
sync.mutex_guard(&arena.mutex)
temp.arena = arena
temp.block = arena.curr_block
if arena.curr_block != nil {
@@ -299,28 +309,41 @@ arena_temp_begin :: proc(arena: ^Arena, loc := #caller_location) -> (temp: Arena
arena_temp_end :: proc(temp: Arena_Temp, loc := #caller_location) {
assert(temp.arena != nil, "nil arena", loc)
arena := temp.arena
sync.mutex_guard(&arena.mutex)
memory_block_found := false
for block := arena.curr_block; block != nil; block = block.prev {
if block == temp.block {
memory_block_found = true
break
if temp.block != nil {
memory_block_found := false
for block := arena.curr_block; block != nil; block = block.prev {
if block == temp.block {
memory_block_found = true
break
}
}
if !memory_block_found {
assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc)
}
for arena.curr_block != temp.block {
arena_growing_free_last_memory_block(arena)
}
if block := arena.curr_block; block != nil {
assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
amount_to_zero := min(block.used-temp.used, block.reserved-block.used)
mem.zero_slice(block.base[temp.used:][:amount_to_zero])
block.used = temp.used
}
}
if !memory_block_found {
assert(arena.curr_block == temp.block, "memory block stored within Arena_Temp not owned by Arena", loc)
}
for arena.curr_block != temp.block {
arena_growing_free_last_memory_block(arena)
}
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
arena.temp_count -= 1
}
if block := arena.curr_block; block != nil {
assert(block.used >= temp.used, "out of order use of arena_temp_end", loc)
amount_to_zero := min(block.used-temp.used, block.reserved-block.used)
mem.zero_slice(block.base[temp.used:][:amount_to_zero])
block.used = temp.used
}
// Ignore the use of a `arena_temp_begin` entirely
arena_temp_ignore :: proc(temp: Arena_Temp, loc := #caller_location) {
assert(temp.arena != nil, "nil arena", loc)
arena := temp.arena
sync.mutex_guard(&arena.mutex)
assert(arena.temp_count > 0, "double-use of arena_temp_end", loc)
arena.temp_count -= 1
+5 -1
View File
@@ -7,6 +7,7 @@ DEFAULT_PAGE_SIZE := uint(4096)
Allocator_Error :: mem.Allocator_Error
@(require_results)
reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
return _reserve(size)
}
@@ -15,6 +16,7 @@ commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
return _commit(data, size)
}
@(require_results)
reserve_and_commit :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
data = reserve(size) or_return
commit(raw_data(data), size) or_return
@@ -57,6 +59,7 @@ Memory_Block_Flag :: enum u32 {
Memory_Block_Flags :: distinct bit_set[Memory_Block_Flag; u32]
@(require_results)
memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags) -> (block: ^Memory_Block, err: Allocator_Error) {
align_formula :: proc "contextless" (size, align: uint) -> uint {
result := size + align-1
@@ -100,6 +103,7 @@ memory_block_alloc :: proc(committed, reserved: uint, flags: Memory_Block_Flags)
return &pmblock.block, nil
}
@(require_results)
alloc_from_memory_block :: proc(block: ^Memory_Block, min_size, alignment: uint) -> (data: []byte, err: Allocator_Error) {
calc_alignment_offset :: proc "contextless" (block: ^Memory_Block, alignment: uintptr) -> uint {
alignment_offset := uint(0)
@@ -160,7 +164,7 @@ memory_block_dealloc :: proc(block_to_free: ^Memory_Block) {
@(private)
@(private, require_results)
safe_add :: #force_inline proc "contextless" (x, y: uint) -> (uint, bool) {
z, did_overflow := intrinsics.overflow_add(x, y)
return z, !did_overflow
+2 -1
View File
@@ -14,11 +14,12 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
dirpath: string
dirpath, err = absolute_path_from_handle(fd)
if err != ERROR_NONE {
return
}
defer delete(dirpath)
n := n
size := n
if n <= 0 {
+9 -5
View File
@@ -93,7 +93,7 @@ file_size_from_path :: proc(path: string) -> i64 {
return length
}
read_entire_file_from_filename :: proc(name: string, allocator := context.allocator) -> (data: []byte, success: bool) {
read_entire_file_from_filename :: proc(name: string, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) {
context.allocator = allocator
fd, err := open(name, O_RDONLY, 0)
@@ -102,10 +102,10 @@ read_entire_file_from_filename :: proc(name: string, allocator := context.alloca
}
defer close(fd)
return read_entire_file_from_handle(fd, allocator)
return read_entire_file_from_handle(fd, allocator, loc)
}
read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator) -> (data: []byte, success: bool) {
read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator, loc := #caller_location) -> (data: []byte, success: bool) {
context.allocator = allocator
length: i64
@@ -118,7 +118,7 @@ read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator)
return nil, true
}
data = make([]byte, int(length), allocator)
data = make([]byte, int(length), allocator, loc)
if data == nil {
return nil, false
}
@@ -216,7 +216,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
}
new_memory = aligned_alloc(new_size, new_alignment, p) or_return
// NOTE: heap_resize does not zero the new memory, so we do it
if new_size > old_size {
new_region := mem.raw_data(new_memory[old_size:])
@@ -261,3 +261,7 @@ heap_allocator :: proc() -> mem.Allocator {
data = nil,
}
}
processor_core_count :: proc() -> int {
return _processor_core_count()
}
+32 -6
View File
@@ -314,6 +314,7 @@ foreign libc {
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
}
@@ -333,7 +334,7 @@ foreign dl {
@(link_name="dlerror") _unix_dlerror :: proc() -> cstring ---
}
get_last_error :: proc() -> int {
get_last_error :: proc "contextless" () -> int {
return __error()^
}
@@ -342,21 +343,33 @@ get_last_error_string :: proc() -> string {
}
open :: proc(path: string, flags: int = O_RDWR, mode: int = 0) -> (Handle, Errno) {
isDir := is_dir_path(path)
flags := flags
if isDir {
/*
@INFO(Platin): To make it impossible to use the wrong flag for dir's
as you can't write to a dir only read which makes it fail to open
*/
flags = O_RDONLY
}
cstr := strings.clone_to_cstring(path, context.temp_allocator)
handle := _unix_open(cstr, i32(flags), u16(mode))
if handle == -1 {
return INVALID_HANDLE, 1
return INVALID_HANDLE, cast(Errno)get_last_error()
}
when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 {
if mode != 0 {
/*
@INFO(Platin): this is only done because O_CREATE for some reason fails to apply mode
should not happen if the handle is a directory
*/
if mode != 0 && !isDir {
err := fchmod(handle, cast(u16)mode)
if err != 0 {
_unix_close(handle)
return INVALID_HANDLE, 1
return INVALID_HANDLE, cast(Errno)err
}
}
}
return handle, 0
}
@@ -688,6 +701,7 @@ get_current_directory :: proc() -> string {
return string(cwd)
}
if Errno(get_last_error()) != ERANGE {
delete(buf)
return ""
}
resize(&buf, len(buf)+page_size)
@@ -759,6 +773,18 @@ get_page_size :: proc() -> int {
return page_size
}
@(private)
_processor_core_count :: proc() -> int {
count : int = 0
count_size := size_of(count)
if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 {
if count > 0 {
return count
}
}
return 1
}
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
+16 -1
View File
@@ -287,6 +287,7 @@ foreign libc {
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
@(link_name="sysctlbyname") _sysctlbyname :: proc(path: cstring, oldp: rawptr, oldlenp: rawptr, newp: rawptr, newlen: int) -> c.int ---
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
}
@@ -303,7 +304,7 @@ is_path_separator :: proc(r: rune) -> bool {
return r == '/'
}
get_last_error :: proc() -> int {
get_last_error :: proc "contextless" () -> int {
return __errno_location()^
}
@@ -650,6 +651,7 @@ get_current_directory :: proc() -> string {
return string(cwd)
}
if Errno(get_last_error()) != ERANGE {
delete(buf)
return ""
}
resize(&buf, len(buf)+page_size)
@@ -702,6 +704,19 @@ get_page_size :: proc() -> int {
return page_size
}
@(private)
_processor_core_count :: proc() -> int {
count : int = 0
count_size := size_of(count)
if _sysctlbyname("hw.logicalcpu", &count, &count_size, nil, 0) == 0 {
if count > 0 {
return count
}
}
return 1
}
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
+7 -1
View File
@@ -404,6 +404,7 @@ foreign libc {
@(link_name="__errno_location") __errno_location :: proc() -> ^int ---
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
@(link_name="get_nprocs") _unix_get_nprocs :: proc() -> c.int ---
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
@@ -441,7 +442,7 @@ _get_errno :: proc(res: int) -> Errno {
}
// get errno from libc
get_last_error :: proc() -> int {
get_last_error :: proc "contextless" () -> int {
return __errno_location()^
}
@@ -822,6 +823,7 @@ get_current_directory :: proc() -> string {
return strings.string_from_nul_terminated_ptr(&buf[0], len(buf))
}
if _get_errno(res) != ERANGE {
delete(buf)
return ""
}
resize(&buf, len(buf)+page_size)
@@ -878,6 +880,10 @@ get_page_size :: proc() -> int {
return page_size
}
@(private)
_processor_core_count :: proc() -> int {
return int(_unix_get_nprocs())
}
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
+10 -2
View File
@@ -269,6 +269,7 @@ foreign libc {
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
@(link_name="sysconf") _sysconf :: proc(name: c.int) -> c.long ---
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
@@ -294,7 +295,7 @@ is_path_separator :: proc(r: rune) -> bool {
return r == '/'
}
get_last_error :: proc() -> int {
get_last_error :: proc "contextless" () -> int {
return __errno()^
}
@@ -648,6 +649,7 @@ get_current_directory :: proc() -> string {
return string(cwd)
}
if Errno(get_last_error()) != ERANGE {
delete(buf)
return ""
}
resize(&buf, len(buf) + MAX_PATH)
@@ -704,6 +706,12 @@ get_page_size :: proc() -> int {
return page_size
}
_SC_NPROCESSORS_ONLN :: 503
@(private)
_processor_core_count :: proc() -> int {
return int(_sysconf(_SC_NPROCESSORS_ONLN))
}
_alloc_command_line_arguments :: proc() -> []string {
res := make([]string, len(runtime.args__))
@@ -711,4 +719,4 @@ _alloc_command_line_arguments :: proc() -> []string {
res[i] = string(arg)
}
return res
}
}
+4 -1
View File
@@ -89,7 +89,10 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
current_thread_id :: proc "contextless" () -> int {
return 0
}
@(private)
_processor_core_count :: proc() -> int {
return 1
}
file_size :: proc(fd: Handle) -> (i64, Errno) {
stat, err := wasi.fd_filestat_get(wasi.fd_t(fd))
+23 -1
View File
@@ -3,6 +3,7 @@ package os
import win32 "core:sys/windows"
import "core:runtime"
import "core:intrinsics"
Handle :: distinct uintptr
File_Time :: distinct u64
@@ -126,7 +127,28 @@ get_page_size :: proc() -> int {
return page_size
}
@(private)
_processor_core_count :: proc() -> int {
length : win32.DWORD = 0
result := win32.GetLogicalProcessorInformation(nil, &length)
thread_count := 0
if !result && win32.GetLastError() == 122 && length > 0 {
processors := make([]win32.SYSTEM_LOGICAL_PROCESSOR_INFORMATION, length, context.temp_allocator)
result = win32.GetLogicalProcessorInformation(&processors[0], &length)
if result {
for processor in processors {
if processor.Relationship == .RelationProcessorCore {
thread := intrinsics.count_ones(processor.ProcessorMask)
thread_count += int(thread)
}
}
}
}
return thread_count
}
exit :: proc "contextless" (code: int) -> ! {
runtime._cleanup_runtime_contextless()
@@ -214,4 +236,4 @@ is_windows_10 :: proc() -> bool {
is_windows_11 :: proc() -> bool {
osvi := get_windows_version_w()
return (osvi.dwMajorVersion == 10 && osvi.dwMinorVersion == 0 && osvi.dwBuildNumber >= WINDOWS_11_BUILD_CUTOFF)
}
}
+2
View File
@@ -2,6 +2,7 @@ package reflect
import "core:runtime"
@(require_results)
iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
if val == nil || it == nil {
return
@@ -41,6 +42,7 @@ iterate_array :: proc(val: any, it: ^int) -> (elem: any, index: int, ok: bool) {
return
}
@(require_results)
iterate_map :: proc(val: any, it: ^int) -> (key, value: any, ok: bool) {
if val == nil || it == nil {
return
+61 -39
View File
@@ -74,6 +74,7 @@ Type_Kind :: enum {
}
@(require_results)
type_kind :: proc(T: typeid) -> Type_Kind {
ti := type_info_of(T)
if ti != nil {
@@ -113,57 +114,31 @@ type_kind :: proc(T: typeid) -> Type_Kind {
}
// TODO(bill): Better name
@(require_results)
underlying_type_kind :: proc(T: typeid) -> Type_Kind {
return type_kind(runtime.typeid_base(T))
}
// TODO(bill): Better name
@(require_results)
backing_type_kind :: proc(T: typeid) -> Type_Kind {
return type_kind(runtime.typeid_core(T))
}
type_info_base :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil { return nil }
base := info
loop: for {
#partial switch i in base.variant {
case Type_Info_Named: base = i.base
case: break loop
}
}
return base
}
type_info_core :: proc(info: ^Type_Info) -> ^Type_Info {
if info == nil { return nil }
base := info
loop: for {
#partial switch i in base.variant {
case Type_Info_Named: base = i.base
case Type_Info_Enum: base = i.base
case: break loop
}
}
return base
}
type_info_base :: runtime.type_info_base
type_info_core :: runtime.type_info_core
type_info_base_without_enum :: type_info_core
typeid_base :: proc(id: typeid) -> typeid {
ti := type_info_of(id)
ti = type_info_base(ti)
return ti.id
when !ODIN_DISALLOW_RTTI {
typeid_base :: runtime.typeid_base
typeid_core :: runtime.typeid_core
typeid_base_without_enum :: typeid_core
}
typeid_core :: proc(id: typeid) -> typeid {
ti := type_info_base_without_enum(type_info_of(id))
return ti.id
}
typeid_base_without_enum :: typeid_core
@(require_results)
any_base :: proc(v: any) -> any {
v := v
if v != nil {
@@ -171,6 +146,7 @@ any_base :: proc(v: any) -> any {
}
return v
}
@(require_results)
any_core :: proc(v: any) -> any {
v := v
if v != nil {
@@ -179,6 +155,7 @@ any_core :: proc(v: any) -> any {
return v
}
@(require_results)
typeid_elem :: proc(id: typeid) -> typeid {
ti := type_info_of(id)
if ti == nil { return nil }
@@ -208,6 +185,7 @@ typeid_elem :: proc(id: typeid) -> typeid {
}
@(require_results)
size_of_typeid :: proc(T: typeid) -> int {
if ti := type_info_of(T); ti != nil {
return ti.size
@@ -215,6 +193,7 @@ size_of_typeid :: proc(T: typeid) -> int {
return 0
}
@(require_results)
align_of_typeid :: proc(T: typeid) -> int {
if ti := type_info_of(T); ti != nil {
return ti.align
@@ -222,6 +201,7 @@ align_of_typeid :: proc(T: typeid) -> int {
return 1
}
@(require_results)
as_bytes :: proc(v: any) -> []byte {
if v != nil {
sz := size_of_typeid(v.id)
@@ -230,10 +210,12 @@ as_bytes :: proc(v: any) -> []byte {
return nil
}
@(require_results)
any_data :: #force_inline proc(v: any) -> (data: rawptr, id: typeid) {
return v.data, v.id
}
@(require_results)
is_nil :: proc(v: any) -> bool {
if v == nil {
return true
@@ -250,6 +232,7 @@ is_nil :: proc(v: any) -> bool {
return true
}
@(require_results)
length :: proc(val: any) -> int {
if val == nil { return 0 }
@@ -285,6 +268,7 @@ length :: proc(val: any) -> int {
return 0
}
@(require_results)
capacity :: proc(val: any) -> int {
if val == nil { return 0 }
@@ -311,6 +295,7 @@ capacity :: proc(val: any) -> int {
}
@(require_results)
index :: proc(val: any, i: int, loc := #caller_location) -> any {
if val == nil { return nil }
@@ -370,6 +355,7 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
return nil
}
@(require_results)
deref :: proc(val: any) -> any {
if val != nil {
ti := type_info_base(type_info_of(val.id))
@@ -399,6 +385,7 @@ Struct_Field :: struct {
is_using: bool,
}
@(require_results)
struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
ti := runtime.type_info_base(type_info_of(T))
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
@@ -413,6 +400,7 @@ struct_field_at :: proc(T: typeid, i: int) -> (field: Struct_Field) {
return
}
@(require_results)
struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
ti := runtime.type_info_base(type_info_of(T))
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
@@ -430,6 +418,7 @@ struct_field_by_name :: proc(T: typeid, name: string) -> (field: Struct_Field) {
return
}
@(require_results)
struct_field_value_by_name :: proc(a: any, field: string, allow_using := false) -> any {
if a == nil { return nil }
@@ -461,6 +450,7 @@ struct_field_value_by_name :: proc(a: any, field: string, allow_using := false)
@(require_results)
struct_field_names :: proc(T: typeid) -> []string {
ti := runtime.type_info_base(type_info_of(T))
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
@@ -469,6 +459,7 @@ struct_field_names :: proc(T: typeid) -> []string {
return nil
}
@(require_results)
struct_field_types :: proc(T: typeid) -> []^Type_Info {
ti := runtime.type_info_base(type_info_of(T))
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
@@ -478,6 +469,7 @@ struct_field_types :: proc(T: typeid) -> []^Type_Info {
}
@(require_results)
struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
ti := runtime.type_info_base(type_info_of(T))
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
@@ -486,6 +478,7 @@ struct_field_tags :: proc(T: typeid) -> []Struct_Tag {
return nil
}
@(require_results)
struct_field_offsets :: proc(T: typeid) -> []uintptr {
ti := runtime.type_info_base(type_info_of(T))
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
@@ -494,6 +487,7 @@ struct_field_offsets :: proc(T: typeid) -> []uintptr {
return nil
}
@(require_results)
struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
ti := runtime.type_info_base(type_info_of(T))
if s, ok := ti.variant.(runtime.Type_Info_Struct); ok {
@@ -510,11 +504,13 @@ struct_fields_zipped :: proc(T: typeid) -> (fields: #soa[]Struct_Field) {
@(require_results)
struct_tag_get :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag) {
value, _ = struct_tag_lookup(tag, key)
return
}
@(require_results)
struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, ok: bool) {
for t := tag; t != ""; /**/ {
i := 0
@@ -573,6 +569,7 @@ struct_tag_lookup :: proc(tag: Struct_Tag, key: string) -> (value: Struct_Tag, o
}
@(require_results)
enum_string :: proc(a: any) -> string {
if a == nil { return "" }
ti := runtime.type_info_base(type_info_of(a.id))
@@ -591,6 +588,7 @@ enum_string :: proc(a: any) -> string {
}
// Given a enum type and a value name, get the enum value.
@(require_results)
enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, ok: bool) {
ti := type_info_base(type_info_of(Enum_Type))
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
@@ -607,6 +605,7 @@ enum_from_name :: proc($Enum_Type: typeid, name: string) -> (value: Enum_Type, o
return
}
@(require_results)
enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info_Enum_Value, ok: bool) {
ti := runtime.type_info_base(type_info_of(Enum_Type))
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
@@ -623,6 +622,7 @@ enum_from_name_any :: proc(Enum_Type: typeid, name: string) -> (value: Type_Info
}
@(require_results)
enum_field_names :: proc(Enum_Type: typeid) -> []string {
ti := runtime.type_info_base(type_info_of(Enum_Type))
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
@@ -630,6 +630,7 @@ enum_field_names :: proc(Enum_Type: typeid) -> []string {
}
return nil
}
@(require_results)
enum_field_values :: proc(Enum_Type: typeid) -> []Type_Info_Enum_Value {
ti := runtime.type_info_base(type_info_of(Enum_Type))
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
@@ -643,6 +644,7 @@ Enum_Field :: struct {
value: Type_Info_Enum_Value,
}
@(require_results)
enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
ti := runtime.type_info_base(type_info_of(Enum_Type))
if eti, eti_ok := ti.variant.(runtime.Type_Info_Enum); eti_ok {
@@ -653,15 +655,18 @@ enum_fields_zipped :: proc(Enum_Type: typeid) -> (fields: #soa[]Enum_Field) {
@(require_results)
union_variant_type_info :: proc(a: any) -> ^Type_Info {
id := union_variant_typeid(a)
return type_info_of(id)
}
@(require_results)
type_info_union_is_pure_maybe :: proc(info: runtime.Type_Info_Union) -> bool {
return len(info.variants) == 1 && is_pointer(info.variants[0])
}
@(require_results)
union_variant_typeid :: proc(a: any) -> typeid {
if a == nil { return nil }
@@ -690,9 +695,10 @@ union_variant_typeid :: proc(a: any) -> typeid {
case: unimplemented()
}
if a.data != nil && tag != 0 {
i := tag if info.no_nil else tag-1
return info.variants[i].id
if info.no_nil {
return info.variants[tag].id
} else if tag != 0 {
return info.variants[tag-1].id
}
return nil
@@ -700,6 +706,7 @@ union_variant_typeid :: proc(a: any) -> typeid {
panic("expected a union to reflect.union_variant_typeid")
}
@(require_results)
get_union_variant_raw_tag :: proc(a: any) -> i64 {
if a == nil { return -1 }
@@ -730,6 +737,7 @@ get_union_variant_raw_tag :: proc(a: any) -> i64 {
panic("expected a union to reflect.get_union_variant_raw_tag")
}
@(require_results)
get_union_variant :: proc(a: any) -> any {
if a == nil {
return nil
@@ -741,6 +749,7 @@ get_union_variant :: proc(a: any) -> any {
return any{a.data, id}
}
@(require_results)
get_union_as_ptr_variants :: proc(val: ^$T) -> (res: intrinsics.type_convert_variants_to_pointers(T)) where intrinsics.type_is_union(T) {
ptr := rawptr(val)
tag := get_union_variant_raw_tag(val^)
@@ -881,6 +890,7 @@ set_union_value :: proc(dst: any, value: any) -> bool {
@(require_results)
as_bool :: proc(a: any) -> (value: bool, valid: bool) {
if a == nil { return }
a := a
@@ -903,6 +913,7 @@ as_bool :: proc(a: any) -> (value: bool, valid: bool) {
return
}
@(require_results)
as_int :: proc(a: any) -> (value: int, valid: bool) {
v: i64
v, valid = as_i64(a)
@@ -910,6 +921,7 @@ as_int :: proc(a: any) -> (value: int, valid: bool) {
return
}
@(require_results)
as_uint :: proc(a: any) -> (value: uint, valid: bool) {
v: u64
v, valid = as_u64(a)
@@ -917,6 +929,7 @@ as_uint :: proc(a: any) -> (value: uint, valid: bool) {
return
}
@(require_results)
as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
if a == nil { return }
a := a
@@ -1024,6 +1037,7 @@ as_i64 :: proc(a: any) -> (value: i64, valid: bool) {
return
}
@(require_results)
as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
if a == nil { return }
a := a
@@ -1133,6 +1147,7 @@ as_u64 :: proc(a: any) -> (value: u64, valid: bool) {
}
@(require_results)
as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
if a == nil { return }
a := a
@@ -1239,6 +1254,7 @@ as_f64 :: proc(a: any) -> (value: f64, valid: bool) {
}
@(require_results)
as_string :: proc(a: any) -> (value: string, valid: bool) {
if a == nil { return }
a := a
@@ -1258,6 +1274,7 @@ as_string :: proc(a: any) -> (value: string, valid: bool) {
return
}
@(require_results)
relative_pointer_to_absolute :: proc(a: any) -> rawptr {
if a == nil { return nil }
a := a
@@ -1272,6 +1289,7 @@ relative_pointer_to_absolute :: proc(a: any) -> rawptr {
}
@(require_results)
relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid) -> rawptr {
_handle :: proc(ptr: ^$T) -> rawptr where intrinsics.type_is_integer(T) {
if ptr^ == 0 {
@@ -1314,6 +1332,7 @@ relative_pointer_to_absolute_raw :: proc(data: rawptr, base_integer_id: typeid)
@(require_results)
as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
if a == nil { return }
a := a
@@ -1341,6 +1360,7 @@ as_pointer :: proc(a: any) -> (value: rawptr, valid: bool) {
}
@(require_results)
as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
if a == nil { return }
a := a
@@ -1377,9 +1397,11 @@ ne :: not_equal
DEFAULT_EQUAL_MAX_RECURSION_LEVEL :: 32
@(require_results)
not_equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
return !equal(a, b, including_indirect_array_recursion, recursion_level)
}
@(require_results)
equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_level := 0) -> bool {
if a == nil && b == nil {
return true
+33 -3
View File
@@ -3,17 +3,16 @@ package reflect
import "core:io"
import "core:strings"
@(require_results)
are_types_identical :: proc(a, b: ^Type_Info) -> bool {
if a == b {
return true
}
if (a == nil && b != nil) ||
(a != nil && b == nil) {
if a == nil || b == nil {
return false
}
switch {
case a.size != b.size, a.align != b.align:
return false
@@ -180,6 +179,7 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
return false
}
@(require_results)
is_signed :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
#partial switch i in type_info_base(info).variant {
@@ -188,6 +188,7 @@ is_signed :: proc(info: ^Type_Info) -> bool {
}
return false
}
@(require_results)
is_unsigned :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
#partial switch i in type_info_base(info).variant {
@@ -197,6 +198,7 @@ is_unsigned :: proc(info: ^Type_Info) -> bool {
return false
}
@(require_results)
is_byte :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
#partial switch i in type_info_base(info).variant {
@@ -206,66 +208,79 @@ is_byte :: proc(info: ^Type_Info) -> bool {
}
@(require_results)
is_integer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Integer)
return ok
}
@(require_results)
is_rune :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Rune)
return ok
}
@(require_results)
is_float :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Float)
return ok
}
@(require_results)
is_complex :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Complex)
return ok
}
@(require_results)
is_quaternion :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Quaternion)
return ok
}
@(require_results)
is_any :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Any)
return ok
}
@(require_results)
is_string :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_String)
return ok
}
@(require_results)
is_cstring :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
v, ok := type_info_base(info).variant.(Type_Info_String)
return ok && v.is_cstring
}
@(require_results)
is_boolean :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Boolean)
return ok
}
@(require_results)
is_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Pointer)
return ok
}
@(require_results)
is_multi_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer)
return ok
}
@(require_results)
is_soa_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer)
return ok
}
@(require_results)
is_pointer_internally :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
#partial switch v in info.variant {
@@ -277,76 +292,91 @@ is_pointer_internally :: proc(info: ^Type_Info) -> bool {
}
return false
}
@(require_results)
is_procedure :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Procedure)
return ok
}
@(require_results)
is_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Array)
return ok
}
@(require_results)
is_enumerated_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Enumerated_Array)
return ok
}
@(require_results)
is_dynamic_array :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Dynamic_Array)
return ok
}
@(require_results)
is_dynamic_map :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Map)
return ok
}
@(require_results)
is_bit_set :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Bit_Set)
return ok
}
@(require_results)
is_slice :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Slice)
return ok
}
@(require_results)
is_tuple :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Tuple)
return ok
}
@(require_results)
is_struct :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
s, ok := type_info_base(info).variant.(Type_Info_Struct)
return ok && !s.is_raw_union
}
@(require_results)
is_raw_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
s, ok := type_info_base(info).variant.(Type_Info_Struct)
return ok && s.is_raw_union
}
@(require_results)
is_union :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Union)
return ok
}
@(require_results)
is_enum :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Enum)
return ok
}
@(require_results)
is_simd_vector :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Simd_Vector)
return ok
}
@(require_results)
is_relative_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Relative_Pointer)
return ok
}
@(require_results)
is_relative_slice :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Relative_Slice)
+6
View File
@@ -329,6 +329,12 @@ Allocator :: struct {
data: rawptr,
}
Byte :: 1
Kilobyte :: 1024 * Byte
Megabyte :: 1024 * Kilobyte
Gigabyte :: 1024 * Megabyte
Terabyte :: 1024 * Gigabyte
// Logging stuff
Logger_Level :: enum uint {
+1 -1
View File
@@ -615,7 +615,7 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
old_size := a.cap * size_of(E)
new_size := new_cap * size_of(E)
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc)
new_data, err := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc)
if err != nil {
return
}
+2 -2
View File
@@ -150,14 +150,14 @@ make_soa_dynamic_array :: proc($T: typeid/#soa[dynamic]$E, allocator := context.
}
@builtin
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, auto_cast length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
make_soa_dynamic_array_len :: proc($T: typeid/#soa[dynamic]$E, #any_int length: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
context.allocator = allocator
resize_soa(&array, length, loc)
return
}
@builtin
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, auto_cast length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
make_soa_dynamic_array_len_cap :: proc($T: typeid/#soa[dynamic]$E, #any_int length, capacity: int, allocator := context.allocator, loc := #caller_location) -> (array: T) {
context.allocator = allocator
if reserve_soa(&array, capacity, loc) {
resize_soa(&array, length, loc)
@@ -1,6 +1,6 @@
package runtime
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 1<<22)
DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE: int : #config(DEFAULT_TEMP_ALLOCATOR_BACKING_SIZE, 4 * Megabyte)
when ODIN_OS == .Freestanding || ODIN_OS == .JS || ODIN_DEFAULT_TO_NIL_ALLOCATOR {
@@ -197,4 +197,4 @@ default_temp_allocator :: proc(allocator: ^Default_Temp_Allocator) -> Allocator
procedure = default_temp_allocator_proc,
data = allocator,
}
}
}
+67
View File
@@ -2,6 +2,73 @@ package runtime
_INTEGER_DIGITS :: "0123456789abcdefghijklmnopqrstuvwxyz"
when !ODIN_DISALLOW_RTTI {
print_any_single :: proc(arg: any) {
x := arg
if loc, ok := x.(Source_Code_Location); ok {
print_caller_location(loc)
return
}
x.id = typeid_base(x.id)
switch v in x {
case typeid: print_typeid(v)
case ^Type_Info: print_type(v)
case string: print_string(v)
case cstring: print_string(string(v))
case []byte: print_string(string(v))
case rune: print_rune(v)
case u8: print_u64(u64(v))
case u16: print_u64(u64(v))
case u16le: print_u64(u64(v))
case u16be: print_u64(u64(v))
case u32: print_u64(u64(v))
case u32le: print_u64(u64(v))
case u32be: print_u64(u64(v))
case u64: print_u64(u64(v))
case u64le: print_u64(u64(v))
case u64be: print_u64(u64(v))
case i8: print_i64(i64(v))
case i16: print_i64(i64(v))
case i16le: print_i64(i64(v))
case i16be: print_i64(i64(v))
case i32: print_i64(i64(v))
case i32le: print_i64(i64(v))
case i32be: print_i64(i64(v))
case i64: print_i64(i64(v))
case i64le: print_i64(i64(v))
case i64be: print_i64(i64(v))
case int: print_int(v)
case uint: print_uint(v)
case uintptr: print_uintptr(v)
case:
ti := type_info_of(x.id)
#partial switch v in ti.variant {
case Type_Info_Pointer:
print_uintptr((^uintptr)(x.data)^)
return
}
print_string("<invalid-value>")
}
}
println_any :: proc(args: ..any) {
loop: for arg, i in args {
if i != 0 {
print_string(" ")
}
print_any_single(arg)
}
print_string("\n")
}
}
encode_rune :: proc "contextless" (c: rune) -> ([4]u8, int) {
r := c
+1 -1
View File
@@ -37,7 +37,7 @@ Map_Entry_Info :: struct($Key, $Value: typeid) {
}
map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry(K, V), err: runtime.Allocator) {
map_entries :: proc(m: $M/map[$K]$V, allocator := context.allocator) -> (entries: []Map_Entry(K, V), err: runtime.Allocator_Error) {
entries = make(type_of(entries), len(m), allocator) or_return
i := 0
for key, value in m {
+17 -15
View File
@@ -73,24 +73,26 @@ ptr_rotate :: proc(left: int, mid: ^$T, right: int) {
left, mid, right := left, mid, right
// TODO(bill): Optimization with a buffer for smaller ranges
if left >= right {
for {
ptr_swap_non_overlapping(ptr_sub(mid, right), mid, right)
mid = ptr_sub(mid, right)
for left > 0 && right > 0 {
if left >= right {
for {
ptr_swap_non_overlapping(ptr_sub(mid, right), mid, right * size_of(T))
mid = ptr_sub(mid, right)
left -= right
if left < right {
break
left -= right
if left < right {
break
}
}
}
} else {
for {
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left)
mid = ptr_add(mid, left)
} else {
for {
ptr_swap_non_overlapping(ptr_sub(mid, left), mid, left * size_of(T))
mid = ptr_add(mid, left)
right -= left
if right < left {
break
right -= left
if right < left {
break
}
}
}
}
+6 -5
View File
@@ -77,8 +77,7 @@ swap_between :: proc(a, b: $T/[]$E) {
reverse :: proc(array: $T/[]$E) {
n := len(array)/2
for i in 0..<n {
a, b := i, len(array)-i-1
array[a], array[b] = array[b], array[a]
swap(array, i, len(array)-i-1)
}
}
@@ -218,8 +217,10 @@ rotate_left :: proc(array: $T/[]$E, mid: int) {
n := len(array)
m := mid %% n
k := n - m
p := raw_data(array)
ptr_rotate(mid, ptr_add(p, mid), k)
// FIXME: (ap29600) this cast is a temporary fix for the compiler not matching
// [^T] with $P/^$T
p := cast(^E)raw_data(array)
ptr_rotate(m, ptr_add(p, m), k)
}
rotate_right :: proc(array: $T/[]$E, k: int) {
rotate_left(array, -k)
@@ -515,4 +516,4 @@ dot_product :: proc(a, b: $S/[]$T) -> (r: T, ok: bool)
enumerated_array :: proc(ptr: ^$T) -> []intrinsics.type_elem_type(T)
where intrinsics.type_is_enumerated_array(T) {
return ([^]intrinsics.type_elem_type(T))(ptr)[:len(T)]
}
}
+121 -21
View File
@@ -214,25 +214,128 @@ shift_right :: proc(a: ^Decimal, k: uint) {
trim(a)
}
shift_left :: proc(a: ^Decimal, k: uint) {
// NOTE(bill): used to determine buffer size required for the decimal from the binary shift
// 'k' means `1<<k` == `2^k` which equates to roundup(k*log10(2)) digits required
log10_2 :: 0.301029995663981195213738894724493026768189881462108541310
capacity := int(f64(k)*log10_2 + 1)
import "core:runtime"
println :: proc(args: ..any) {
for arg, i in args {
if i != 0 {
runtime.print_string(" ")
}
switch v in arg {
case string: runtime.print_string(v)
case rune: runtime.print_rune(v)
case int: runtime.print_int(v)
case uint: runtime.print_uint(v)
case u8: runtime.print_u64(u64(v))
case u16: runtime.print_u64(u64(v))
case u32: runtime.print_u64(u64(v))
case u64: runtime.print_u64(v)
case i8: runtime.print_i64(i64(v))
case i16: runtime.print_i64(i64(v))
case i32: runtime.print_i64(i64(v))
case i64: runtime.print_i64(v)
case uintptr: runtime.print_uintptr(v)
case bool: runtime.print_string("true" if v else "false")
}
}
runtime.print_string("\n")
}
r := a.count // read index
w := a.count+capacity // write index
@(private="file")
_shift_left_offsets := [?]struct{delta: int, cutoff: string}{
{ 0, ""},
{ 1, "5"},
{ 1, "25"},
{ 1, "125"},
{ 2, "625"},
{ 2, "3125"},
{ 2, "15625"},
{ 3, "78125"},
{ 3, "390625"},
{ 3, "1953125"},
{ 4, "9765625"},
{ 4, "48828125"},
{ 4, "244140625"},
{ 4, "1220703125"},
{ 5, "6103515625"},
{ 5, "30517578125"},
{ 5, "152587890625"},
{ 6, "762939453125"},
{ 6, "3814697265625"},
{ 6, "19073486328125"},
{ 7, "95367431640625"},
{ 7, "476837158203125"},
{ 7, "2384185791015625"},
{ 7, "11920928955078125"},
{ 8, "59604644775390625"},
{ 8, "298023223876953125"},
{ 8, "1490116119384765625"},
{ 9, "7450580596923828125"},
{ 9, "37252902984619140625"},
{ 9, "186264514923095703125"},
{10, "931322574615478515625"},
{10, "4656612873077392578125"},
{10, "23283064365386962890625"},
{10, "116415321826934814453125"},
{11, "582076609134674072265625"},
{11, "2910383045673370361328125"},
{11, "14551915228366851806640625"},
{12, "72759576141834259033203125"},
{12, "363797880709171295166015625"},
{12, "1818989403545856475830078125"},
{13, "9094947017729282379150390625"},
{13, "45474735088646411895751953125"},
{13, "227373675443232059478759765625"},
{13, "1136868377216160297393798828125"},
{14, "5684341886080801486968994140625"},
{14, "28421709430404007434844970703125"},
{14, "142108547152020037174224853515625"},
{15, "710542735760100185871124267578125"},
{15, "3552713678800500929355621337890625"},
{15, "17763568394002504646778106689453125"},
{16, "88817841970012523233890533447265625"},
{16, "444089209850062616169452667236328125"},
{16, "2220446049250313080847263336181640625"},
{16, "11102230246251565404236316680908203125"},
{17, "55511151231257827021181583404541015625"},
{17, "277555756156289135105907917022705078125"},
{17, "1387778780781445675529539585113525390625"},
{18, "6938893903907228377647697925567626953125"},
{18, "34694469519536141888238489627838134765625"},
{18, "173472347597680709441192448139190673828125"},
{19, "867361737988403547205962240695953369140625"},
}
d := len(a.digits)
shift_left :: proc(a: ^Decimal, k: uint) #no_bounds_check {
prefix_less :: #force_inline proc "contextless" (b: []byte, s: string) -> bool #no_bounds_check {
for i in 0..<len(s) {
if i >= len(b) {
return true
}
if b[i] != s[i] {
return b[i] < s[i]
}
}
return false
}
assert(k < 61)
delta := _shift_left_offsets[k].delta
if prefix_less(a.digits[:a.count], _shift_left_offsets[k].cutoff) {
delta -= 1
}
read_index := a.count
write_index := a.count+delta
n: uint
for r -= 1; r >= 0; r -= 1 {
n += (uint(a.digits[r]) - '0') << k
for read_index -= 1; read_index >= 0; read_index -= 1 {
n += (uint(a.digits[read_index]) - '0') << k
quo := n/10
rem := n - 10*quo
w -= 1
if w < d {
a.digits[w] = byte('0' + rem)
write_index -= 1
if write_index < len(a.digits) {
a.digits[write_index] = byte('0' + rem)
} else if rem != 0 {
a.trunc = true
}
@@ -242,21 +345,18 @@ shift_left :: proc(a: ^Decimal, k: uint) {
for n > 0 {
quo := n/10
rem := n - 10*quo
w -= 1
if w < d {
a.digits[w] = byte('0' + rem)
write_index -= 1
if write_index < len(a.digits) {
a.digits[write_index] = byte('0' + rem)
} else if rem != 0 {
a.trunc = true
}
n = quo
}
// NOTE(bill): Remove unused buffer size
assert(w >= 0)
capacity -= w
a.decimal_point += delta
a.count = min(a.count+capacity, d)
a.decimal_point += capacity
a.count = clamp(a.count, 0, len(a.digits))
trim(a)
}
+5 -5
View File
@@ -287,13 +287,13 @@ round_shortest :: proc(d: ^decimal.Decimal, mant: u64, exp: int, flt: ^Float_Inf
@(private)
decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64, overflow: bool) {
end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (b: u64) {
bits := mant & (u64(1)<<info.mantbits - 1)
end :: proc "contextless" (d: ^decimal.Decimal, mant: u64, exp: int, info: ^Float_Info) -> (bits: u64) {
bits = mant & (u64(1)<<info.mantbits - 1)
bits |= u64((exp-info.bias) & (1<<info.expbits - 1)) << info.mantbits
if d.neg {
bits |= 1<< info.mantbits << info.expbits
}
return bits
return
}
set_overflow :: proc "contextless" (mant: ^u64, exp: ^int, info: ^Float_Info) -> bool {
mant^ = 0
@@ -303,7 +303,7 @@ decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64
mant: u64
exp: int
if d.decimal_point == 0 {
if d.count == 0 {
mant = 0
exp = info.bias
b = end(d, mant, exp, info)
@@ -326,7 +326,7 @@ decimal_to_float_bits :: proc(d: ^decimal.Decimal, info: ^Float_Info) -> (b: u64
exp = 0
for d.decimal_point > 0 {
n := 27 if d.decimal_point >= len(power_table) else power_table[d.decimal_point]
decimal.shift(d, n)
decimal.shift(d, -n)
exp += n
}
for d.decimal_point < 0 || d.decimal_point == 0 && d.digits[0] < '5' {
-5
View File
@@ -3,7 +3,6 @@ package strconv
Int_Flag :: enum {
Prefix,
Plus,
Space,
}
Int_Flags :: bit_set[Int_Flag]
@@ -73,8 +72,6 @@ append_bits :: proc(buf: []byte, x: u64, base: int, is_signed: bool, bit_size: i
i-=1; a[i] = '-'
case .Plus in flags:
i-=1; a[i] = '+'
case .Space in flags:
i-=1; a[i] = ' '
}
out := a[i:]
@@ -157,8 +154,6 @@ append_bits_128 :: proc(buf: []byte, x: u128, base: int, is_signed: bool, bit_si
i-=1; a[i] = '-'
case .Plus in flags:
i-=1; a[i] = '+'
case .Space in flags:
i-=1; a[i] = ' '
}
out := a[i:]
+1 -2
View File
@@ -819,7 +819,7 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
}
if mantissa>>_f64_info.mantbits != 0 {
return
break trunc_block
}
f := f64(mantissa)
if neg {
@@ -841,7 +841,6 @@ parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
return f / pow10[-exp], true
}
}
d: decimal.Decimal
decimal.set(&d, str[:nr])
b, overflow := decimal_to_float_bits(&d, &_f64_info)
+95 -30
View File
@@ -1,6 +1,8 @@
package sync
import "core:time"
import vg "core:sys/valgrind"
_ :: vg
// A Wait_Group waits for a collection of threads to finish
//
@@ -11,7 +13,7 @@ Wait_Group :: struct {
cond: Cond,
}
wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
wait_group_add :: proc "contextless" (wg: ^Wait_Group, delta: int) {
if delta == 0 {
return
}
@@ -20,32 +22,32 @@ wait_group_add :: proc(wg: ^Wait_Group, delta: int) {
atomic_add(&wg.counter, delta)
if wg.counter < 0 {
panic("sync.Wait_Group negative counter")
_panic("sync.Wait_Group negative counter")
}
if wg.counter == 0 {
cond_broadcast(&wg.cond)
if wg.counter != 0 {
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
}
}
}
wait_group_done :: proc(wg: ^Wait_Group) {
wait_group_done :: proc "contextless" (wg: ^Wait_Group) {
wait_group_add(wg, -1)
}
wait_group_wait :: proc(wg: ^Wait_Group) {
wait_group_wait :: proc "contextless" (wg: ^Wait_Group) {
guard(&wg.mutex)
if wg.counter != 0 {
cond_wait(&wg.cond, &wg.mutex)
if wg.counter != 0 {
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
}
}
}
wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -> bool {
wait_group_wait_with_timeout :: proc "contextless" (wg: ^Wait_Group, duration: time.Duration) -> bool {
if duration <= 0 {
return false
}
@@ -56,7 +58,7 @@ wait_group_wait_with_timeout :: proc(wg: ^Wait_Group, duration: time.Duration) -
return false
}
if wg.counter != 0 {
panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
_panic("sync.Wait_Group misuse: sync.wait_group_add called concurrently with sync.wait_group_wait")
}
}
return true
@@ -76,7 +78,7 @@ Example:
barrier := &sync.Barrier{}
main :: proc() {
main :: proc "contextless" () {
fmt.println("Start")
THREAD_COUNT :: 4
@@ -107,7 +109,10 @@ Barrier :: struct {
thread_count: int,
}
barrier_init :: proc(b: ^Barrier, thread_count: int) {
barrier_init :: proc "contextless" (b: ^Barrier, thread_count: int) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_barrier_resize_pre(b, uint(thread_count))
}
b.index = 0
b.generation_id = 0
b.thread_count = thread_count
@@ -115,7 +120,10 @@ barrier_init :: proc(b: ^Barrier, thread_count: int) {
// Block the current thread until all threads have rendezvoused
// Barrier can be reused after all threads rendezvoused once, and can be used continuously
barrier_wait :: proc(b: ^Barrier) -> (is_leader: bool) {
barrier_wait :: proc "contextless" (b: ^Barrier) -> (is_leader: bool) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_barrier_wait_pre(b)
}
guard(&b.mutex)
local_gen := b.generation_id
b.index += 1
@@ -141,7 +149,7 @@ Auto_Reset_Event :: struct {
sema: Sema,
}
auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) {
auto_reset_event_signal :: proc "contextless" (e: ^Auto_Reset_Event) {
old_status := atomic_load_explicit(&e.status, .Relaxed)
for {
new_status := old_status + 1 if old_status < 1 else 1
@@ -155,7 +163,7 @@ auto_reset_event_signal :: proc(e: ^Auto_Reset_Event) {
}
}
auto_reset_event_wait :: proc(e: ^Auto_Reset_Event) {
auto_reset_event_wait :: proc "contextless" (e: ^Auto_Reset_Event) {
old_status := atomic_sub_explicit(&e.status, 1, .Acquire)
if old_status < 1 {
sema_wait(&e.sema)
@@ -169,18 +177,18 @@ Ticket_Mutex :: struct {
serving: uint,
}
ticket_mutex_lock :: #force_inline proc(m: ^Ticket_Mutex) {
ticket_mutex_lock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
ticket := atomic_add_explicit(&m.ticket, 1, .Relaxed)
for ticket != atomic_load_explicit(&m.serving, .Acquire) {
cpu_relax()
}
}
ticket_mutex_unlock :: #force_inline proc(m: ^Ticket_Mutex) {
ticket_mutex_unlock :: #force_inline proc "contextless" (m: ^Ticket_Mutex) {
atomic_add_explicit(&m.serving, 1, .Relaxed)
}
@(deferred_in=ticket_mutex_unlock)
ticket_mutex_guard :: proc(m: ^Ticket_Mutex) -> bool {
ticket_mutex_guard :: proc "contextless" (m: ^Ticket_Mutex) -> bool {
ticket_mutex_lock(m)
return true
}
@@ -191,25 +199,25 @@ Benaphore :: struct {
sema: Sema,
}
benaphore_lock :: proc(b: ^Benaphore) {
benaphore_lock :: proc "contextless" (b: ^Benaphore) {
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
sema_wait(&b.sema)
}
}
benaphore_try_lock :: proc(b: ^Benaphore) -> bool {
benaphore_try_lock :: proc "contextless" (b: ^Benaphore) -> bool {
v, _ := atomic_compare_exchange_strong_explicit(&b.counter, 0, 1, .Acquire, .Acquire)
return v == 0
}
benaphore_unlock :: proc(b: ^Benaphore) {
benaphore_unlock :: proc "contextless" (b: ^Benaphore) {
if atomic_sub_explicit(&b.counter, 1, .Release) > 0 {
sema_post(&b.sema)
}
}
@(deferred_in=benaphore_unlock)
benaphore_guard :: proc(m: ^Benaphore) -> bool {
benaphore_guard :: proc "contextless" (m: ^Benaphore) -> bool {
benaphore_lock(m)
return true
}
@@ -221,7 +229,7 @@ Recursive_Benaphore :: struct {
sema: Sema,
}
recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
recursive_benaphore_lock :: proc "contextless" (b: ^Recursive_Benaphore) {
tid := current_thread_id()
if atomic_add_explicit(&b.counter, 1, .Acquire) > 1 {
if tid != b.owner {
@@ -233,7 +241,7 @@ recursive_benaphore_lock :: proc(b: ^Recursive_Benaphore) {
b.recursion += 1
}
recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
recursive_benaphore_try_lock :: proc "contextless" (b: ^Recursive_Benaphore) -> bool {
tid := current_thread_id()
if b.owner == tid {
atomic_add_explicit(&b.counter, 1, .Acquire)
@@ -248,9 +256,9 @@ recursive_benaphore_try_lock :: proc(b: ^Recursive_Benaphore) -> bool {
return true
}
recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
recursive_benaphore_unlock :: proc "contextless" (b: ^Recursive_Benaphore) {
tid := current_thread_id()
assert(tid == b.owner)
_assert(tid == b.owner, "tid != b.owner")
b.recursion -= 1
recursion := b.recursion
if recursion == 0 {
@@ -265,7 +273,7 @@ recursive_benaphore_unlock :: proc(b: ^Recursive_Benaphore) {
}
@(deferred_in=recursive_benaphore_unlock)
recursive_benaphore_guard :: proc(m: ^Recursive_Benaphore) -> bool {
recursive_benaphore_guard :: proc "contextless" (m: ^Recursive_Benaphore) -> bool {
recursive_benaphore_lock(m)
return true
}
@@ -282,7 +290,15 @@ Once :: struct {
}
// once_do calls the procedure fn if and only if once_do is being called for the first for this instance of Once.
once_do :: proc(o: ^Once, fn: proc()) {
once_do :: proc{
once_do_without_data,
once_do_without_data_contextless,
once_do_with_data,
once_do_with_data_contextless,
}
// once_do_without_data calls the procedure fn if and only if once_do_without_data is being called for the first for this instance of Once.
once_do_without_data :: proc(o: ^Once, fn: proc()) {
@(cold)
do_slow :: proc(o: ^Once, fn: proc()) {
guard(&o.m)
@@ -292,12 +308,61 @@ once_do :: proc(o: ^Once, fn: proc()) {
}
}
if atomic_load_explicit(&o.done, .Acquire) == false {
do_slow(o, fn)
}
}
// once_do_without_data calls the procedure fn if and only if once_do_without_data is being called for the first for this instance of Once.
once_do_without_data_contextless :: proc(o: ^Once, fn: proc "contextless" ()) {
@(cold)
do_slow :: proc(o: ^Once, fn: proc "contextless" ()) {
guard(&o.m)
if !o.done {
fn()
atomic_store_explicit(&o.done, true, .Release)
}
}
if atomic_load_explicit(&o.done, .Acquire) == false {
do_slow(o, fn)
}
}
// once_do_with_data calls the procedure fn if and only if once_do_with_data is being called for the first for this instance of Once.
once_do_with_data :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) {
@(cold)
do_slow :: proc(o: ^Once, fn: proc(data: rawptr), data: rawptr) {
guard(&o.m)
if !o.done {
fn(data)
atomic_store_explicit(&o.done, true, .Release)
}
}
if atomic_load_explicit(&o.done, .Acquire) == false {
do_slow(o, fn, data)
}
}
// once_do_with_data_contextless calls the procedure fn if and only if once_do_with_data_contextless is being called for the first for this instance of Once.
once_do_with_data_contextless :: proc "contextless" (o: ^Once, fn: proc "contextless" (data: rawptr), data: rawptr) {
@(cold)
do_slow :: proc "contextless" (o: ^Once, fn: proc "contextless" (data: rawptr), data: rawptr) {
guard(&o.m)
if !o.done {
fn(data)
atomic_store_explicit(&o.done, true, .Release)
}
}
if atomic_load_explicit(&o.done, .Acquire) == false {
do_slow(o, fn, data)
}
}
// A Parker is an associated token which is initially not present:
@@ -314,7 +379,7 @@ Parker :: struct {
// Blocks the current thread until the token is made available.
//
// Assumes this is only called by the thread that owns the Parker.
park :: proc(p: ^Parker) {
park :: proc "contextless" (p: ^Parker) {
EMPTY :: 0
NOTIFIED :: 1
PARKED :: max(u32)
@@ -333,7 +398,7 @@ park :: proc(p: ^Parker) {
// for a limited duration.
//
// Assumes this is only called by the thread that owns the Parker
park_with_timeout :: proc(p: ^Parker, duration: time.Duration) {
park_with_timeout :: proc "contextless" (p: ^Parker, duration: time.Duration) {
EMPTY :: 0
NOTIFIED :: 1
PARKED :: max(u32)
@@ -345,7 +410,7 @@ park_with_timeout :: proc(p: ^Parker, duration: time.Duration) {
}
// Automatically makes thee token available if it was not already.
unpark :: proc(p: ^Parker) {
unpark :: proc "contextless" (p: ^Parker) {
EMPTY :: 0
NOTIFIED :: 1
PARKED :: max(Futex)
+7 -7
View File
@@ -24,11 +24,11 @@ EINTR :: -4
EFAULT :: -14
ETIMEDOUT :: -60
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
return _futex_wait_with_timeout(f, expected, 0)
}
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
timeout_ns := u32(duration) * 1000
s := __ulock_wait(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, u64(expected), timeout_ns)
@@ -41,13 +41,13 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
case ETIMEDOUT:
return false
case:
panic("futex_wait failure")
_panic("futex_wait failure")
}
return true
}
_futex_signal :: proc(f: ^Futex) {
_futex_signal :: proc "contextless" (f: ^Futex) {
loop: for {
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO, f, 0)
if s >= 0 {
@@ -59,12 +59,12 @@ _futex_signal :: proc(f: ^Futex) {
case ENOENT:
return
case:
panic("futex_wake_single failure")
_panic("futex_wake_single failure")
}
}
}
_futex_broadcast :: proc(f: ^Futex) {
_futex_broadcast :: proc "contextless" (f: ^Futex) {
loop: for {
s := __ulock_wake(UL_COMPARE_AND_WAIT | ULF_NO_ERRNO | ULF_WAKE_ALL, f, 0)
if s >= 0 {
@@ -76,7 +76,7 @@ _futex_broadcast :: proc(f: ^Futex) {
case ENOENT:
return
case:
panic("futex_wake_all failure")
_panic("futex_wake_all failure")
}
}
}
+8 -8
View File
@@ -17,7 +17,7 @@ foreign libc {
__error :: proc "c" () -> ^c.int ---
}
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
timeout := [2]i64{14400, 0} // 4 hours
for {
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
@@ -30,12 +30,12 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
continue
}
panic("_futex_wait failure")
_panic("_futex_wait failure")
}
unreachable()
}
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
if duration <= 0 {
return false
}
@@ -51,21 +51,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
return false
}
panic("_futex_wait_with_timeout failure")
_panic("_futex_wait_with_timeout failure")
}
_futex_signal :: proc(f: ^Futex) {
_futex_signal :: proc "contextless" (f: ^Futex) {
res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil)
if res == -1 {
panic("_futex_signal failure")
_panic("_futex_signal failure")
}
}
_futex_broadcast :: proc(f: ^Futex) {
_futex_broadcast :: proc "contextless" (f: ^Futex) {
res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil)
if res == -1 {
panic("_futex_broadcast failure")
_panic("_futex_broadcast failure")
}
}
+10 -10
View File
@@ -21,20 +21,20 @@ EFAULT :: -14
EINVAL :: -22
ETIMEDOUT :: -110
get_errno :: proc(r: int) -> int {
get_errno :: proc "contextless" (r: int) -> int {
if -4096 < r && r < 0 {
return r
}
return 0
}
internal_futex :: proc(f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int {
internal_futex :: proc "contextless" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> int {
code := int(intrinsics.syscall(unix.SYS_futex, uintptr(f), uintptr(op), uintptr(val), uintptr(timeout), 0, 0))
return get_errno(code)
}
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
err := internal_futex(f, FUTEX_WAIT_PRIVATE | FUTEX_WAIT, expected, nil)
switch err {
case ESUCCESS, EINTR, EAGAIN, EINVAL:
@@ -44,12 +44,12 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
case EFAULT:
fallthrough
case:
panic("futex_wait failure")
_panic("futex_wait failure")
}
return true
}
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
if duration <= 0 {
return false
}
@@ -71,27 +71,27 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
case EFAULT:
fallthrough
case:
panic("futex_wait_with_timeout failure")
_panic("futex_wait_with_timeout failure")
}
return true
}
_futex_signal :: proc(f: ^Futex) {
_futex_signal :: proc "contextless" (f: ^Futex) {
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, 1, nil)
switch err {
case ESUCCESS, EINVAL, EFAULT:
// okay
case:
panic("futex_wake_single failure")
_panic("futex_wake_single failure")
}
}
_futex_broadcast :: proc(f: ^Futex) {
_futex_broadcast :: proc "contextless" (f: ^Futex) {
err := internal_futex(f, FUTEX_WAKE_PRIVATE | FUTEX_WAKE, u32(max(i32)), nil)
switch err {
case ESUCCESS, EINVAL, EFAULT:
// okay
case:
panic("_futex_wake_all failure")
_panic("_futex_wake_all failure")
}
}
+8 -8
View File
@@ -21,7 +21,7 @@ foreign libc {
_unix_futex :: proc "c" (f: ^Futex, op: c.int, val: u32, timeout: rawptr) -> c.int ---
}
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
res := _unix_futex(f, FUTEX_WAIT_PRIVATE, expected, nil)
if res != -1 {
@@ -32,10 +32,10 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
return false
}
panic("futex_wait failure")
_panic("futex_wait failure")
}
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
if duration <= 0 {
return false
}
@@ -58,21 +58,21 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
return false
}
panic("futex_wait_with_timeout failure")
_panic("futex_wait_with_timeout failure")
}
_futex_signal :: proc(f: ^Futex) {
_futex_signal :: proc "contextless" (f: ^Futex) {
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, 1, nil)
if res == -1 {
panic("futex_wake_single failure")
_panic("futex_wake_single failure")
}
}
_futex_broadcast :: proc(f: ^Futex) {
_futex_broadcast :: proc "contextless" (f: ^Futex) {
res := _unix_futex(f, FUTEX_WAKE_PRIVATE, u32(max(i32)), nil)
if res == -1 {
panic("_futex_wake_all failure")
_panic("_futex_wake_all failure")
}
}
+4 -4
View File
@@ -5,18 +5,18 @@ package sync
import "core:intrinsics"
import "core:time"
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
_futex_wait :: proc "contextless" (f: ^Futex, expected: u32) -> bool {
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, -1)
return s != 0
}
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
s := intrinsics.wasm_memory_atomic_wait32((^u32)(f), expected, i64(duration))
return s != 0
}
_futex_signal :: proc(f: ^Futex) {
_futex_signal :: proc "contextless" (f: ^Futex) {
loop: for {
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), 1)
if s >= 1 {
@@ -25,7 +25,7 @@ _futex_signal :: proc(f: ^Futex) {
}
}
_futex_broadcast :: proc(f: ^Futex) {
_futex_broadcast :: proc "contextless" (f: ^Futex) {
loop: for {
s := intrinsics.wasm_memory_atomic_notify32((^u32)(f), ~u32(0))
if s >= 0 {
+4 -4
View File
@@ -39,22 +39,22 @@ CustomWaitOnAddress :: proc "stdcall" (Address: rawptr, CompareAddress: rawptr,
}
_futex_wait :: proc(f: ^Futex, expect: u32) -> bool {
_futex_wait :: proc "contextless" (f: ^Futex, expect: u32) -> bool {
expect := expect
return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
}
_futex_wait_with_timeout :: proc(f: ^Futex, expect: u32, duration: time.Duration) -> bool {
_futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expect: u32, duration: time.Duration) -> bool {
expect := expect
// NOTE(bill): for some bizarre reason, this has be a negative number
timeout := -i64(duration / 100)
return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
}
_futex_signal :: proc(f: ^Futex) {
_futex_signal :: proc "contextless" (f: ^Futex) {
WakeByAddressSingle(f)
}
_futex_broadcast :: proc(f: ^Futex) {
_futex_broadcast :: proc "contextless" (f: ^Futex) {
WakeByAddressAll(f)
}
+44 -28
View File
@@ -1,5 +1,6 @@
package sync
import "core:runtime"
import "core:time"
current_thread_id :: proc "contextless" () -> int {
@@ -15,17 +16,17 @@ Mutex :: struct {
}
// mutex_lock locks m
mutex_lock :: proc(m: ^Mutex) {
mutex_lock :: proc "contextless" (m: ^Mutex) {
_mutex_lock(m)
}
// mutex_unlock unlocks m
mutex_unlock :: proc(m: ^Mutex) {
mutex_unlock :: proc "contextless" (m: ^Mutex) {
_mutex_unlock(m)
}
// mutex_try_lock tries to lock m, will return true on success, and false on failure
mutex_try_lock :: proc(m: ^Mutex) -> bool {
mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
return _mutex_try_lock(m)
}
@@ -36,7 +37,7 @@ Example:
}
*/
@(deferred_in=mutex_unlock)
mutex_guard :: proc(m: ^Mutex) -> bool {
mutex_guard :: proc "contextless" (m: ^Mutex) -> bool {
mutex_lock(m)
return true
}
@@ -52,32 +53,32 @@ RW_Mutex :: struct {
// rw_mutex_lock locks rw for writing (with a single writer)
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
rw_mutex_lock :: proc(rw: ^RW_Mutex) {
rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
_rw_mutex_lock(rw)
}
// rw_mutex_unlock unlocks rw for writing (with a single writer)
rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
_rw_mutex_unlock(rw)
}
// rw_mutex_try_lock tries to lock rw for writing (with a single writer)
rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return _rw_mutex_try_lock(rw)
}
// rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
_rw_mutex_shared_lock(rw)
}
// rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
_rw_mutex_shared_unlock(rw)
}
// rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return _rw_mutex_try_shared_lock(rw)
}
/*
@@ -87,7 +88,7 @@ Example:
}
*/
@(deferred_in=rw_mutex_unlock)
rw_mutex_guard :: proc(m: ^RW_Mutex) -> bool {
rw_mutex_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {
rw_mutex_lock(m)
return true
}
@@ -99,7 +100,7 @@ Example:
}
*/
@(deferred_in=rw_mutex_shared_unlock)
rw_mutex_shared_guard :: proc(m: ^RW_Mutex) -> bool {
rw_mutex_shared_guard :: proc "contextless" (m: ^RW_Mutex) -> bool {
rw_mutex_shared_lock(m)
return true
}
@@ -114,15 +115,15 @@ Recursive_Mutex :: struct {
impl: _Recursive_Mutex,
}
recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {
_recursive_mutex_lock(m)
}
recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) {
_recursive_mutex_unlock(m)
}
recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
return _recursive_mutex_try_lock(m)
}
@@ -133,7 +134,7 @@ Example:
}
*/
@(deferred_in=recursive_mutex_unlock)
recursive_mutex_guard :: proc(m: ^Recursive_Mutex) -> bool {
recursive_mutex_guard :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
recursive_mutex_lock(m)
return true
}
@@ -147,22 +148,22 @@ Cond :: struct {
impl: _Cond,
}
cond_wait :: proc(c: ^Cond, m: ^Mutex) {
cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
_cond_wait(c, m)
}
cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
if duration <= 0 {
return false
}
return _cond_wait_with_timeout(c, m, duration)
}
cond_signal :: proc(c: ^Cond) {
cond_signal :: proc "contextless" (c: ^Cond) {
_cond_signal(c)
}
cond_broadcast :: proc(c: ^Cond) {
cond_broadcast :: proc "contextless" (c: ^Cond) {
_cond_broadcast(c)
}
@@ -175,15 +176,15 @@ Sema :: struct {
impl: _Sema,
}
sema_post :: proc(s: ^Sema, count := 1) {
sema_post :: proc "contextless" (s: ^Sema, count := 1) {
_sema_post(s, count)
}
sema_wait :: proc(s: ^Sema) {
sema_wait :: proc "contextless" (s: ^Sema) {
_sema_wait(s)
}
sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {
return _sema_wait_with_timeout(s, duration)
}
@@ -194,16 +195,16 @@ sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
// An Futex must not be copied after first use
Futex :: distinct u32
futex_wait :: proc(f: ^Futex, expected: u32) {
futex_wait :: proc "contextless" (f: ^Futex, expected: u32) {
if u32(atomic_load_explicit(f, .Acquire)) != expected {
return
}
assert(_futex_wait(f, expected), "futex_wait failure")
_assert(_futex_wait(f, expected), "futex_wait failure")
}
// returns true if the wait happened within the duration, false if it exceeded the time duration
futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
futex_wait_with_timeout :: proc "contextless" (f: ^Futex, expected: u32, duration: time.Duration) -> bool {
if u32(atomic_load_explicit(f, .Acquire)) != expected {
return true
}
@@ -214,10 +215,25 @@ futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duratio
return _futex_wait_with_timeout(f, expected, duration)
}
futex_signal :: proc(f: ^Futex) {
futex_signal :: proc "contextless" (f: ^Futex) {
_futex_signal(f)
}
futex_broadcast :: proc(f: ^Futex) {
futex_broadcast :: proc "contextless" (f: ^Futex) {
_futex_broadcast(f)
}
@(private)
_assert :: proc "contextless" (cond: bool, msg: string) {
if !cond {
_panic(msg)
}
}
@(private)
_panic :: proc "contextless" (msg: string) -> ! {
runtime.print_string(msg)
runtime.print_byte('\n')
runtime.trap()
}
+26 -26
View File
@@ -18,9 +18,9 @@ Atomic_Mutex :: struct {
}
// atomic_mutex_lock locks m
atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
atomic_mutex_lock :: proc "contextless" (m: ^Atomic_Mutex) {
@(cold)
lock_slow :: proc(m: ^Atomic_Mutex, curr_state: Atomic_Mutex_State) {
lock_slow :: proc "contextless" (m: ^Atomic_Mutex, curr_state: Atomic_Mutex_State) {
new_state := curr_state // Make a copy of it
spin_lock: for spin in 0..<i32(100) {
@@ -58,9 +58,9 @@ atomic_mutex_lock :: proc(m: ^Atomic_Mutex) {
}
// atomic_mutex_unlock unlocks m
atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) {
atomic_mutex_unlock :: proc "contextless" (m: ^Atomic_Mutex) {
@(cold)
unlock_slow :: proc(m: ^Atomic_Mutex) {
unlock_slow :: proc "contextless" (m: ^Atomic_Mutex) {
futex_signal((^Futex)(&m.state))
}
@@ -76,7 +76,7 @@ atomic_mutex_unlock :: proc(m: ^Atomic_Mutex) {
}
// atomic_mutex_try_lock tries to lock m, will return true on success, and false on failure
atomic_mutex_try_lock :: proc(m: ^Atomic_Mutex) -> bool {
atomic_mutex_try_lock :: proc "contextless" (m: ^Atomic_Mutex) -> bool {
_, ok := atomic_compare_exchange_strong_explicit(&m.state, .Unlocked, .Locked, .Acquire, .Consume)
return ok
}
@@ -88,7 +88,7 @@ Example:
}
*/
@(deferred_in=atomic_mutex_unlock)
atomic_mutex_guard :: proc(m: ^Atomic_Mutex) -> bool {
atomic_mutex_guard :: proc "contextless" (m: ^Atomic_Mutex) -> bool {
atomic_mutex_lock(m)
return true
}
@@ -117,7 +117,7 @@ Atomic_RW_Mutex :: struct {
// atomic_rw_mutex_lock locks rw for writing (with a single writer)
// If the mutex is already locked for reading or writing, the mutex blocks until the mutex is available.
atomic_rw_mutex_lock :: proc(rw: ^Atomic_RW_Mutex) {
atomic_rw_mutex_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
_ = atomic_add(&rw.state, Atomic_RW_Mutex_State_Writer)
atomic_mutex_lock(&rw.mutex)
@@ -128,13 +128,13 @@ atomic_rw_mutex_lock :: proc(rw: ^Atomic_RW_Mutex) {
}
// atomic_rw_mutex_unlock unlocks rw for writing (with a single writer)
atomic_rw_mutex_unlock :: proc(rw: ^Atomic_RW_Mutex) {
atomic_rw_mutex_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
_ = atomic_and(&rw.state, ~Atomic_RW_Mutex_State_Is_Writing)
atomic_mutex_unlock(&rw.mutex)
}
// atomic_rw_mutex_try_lock tries to lock rw for writing (with a single writer)
atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
atomic_rw_mutex_try_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
if atomic_mutex_try_lock(&rw.mutex) {
state := atomic_load(&rw.state)
if state & Atomic_RW_Mutex_State_Reader_Mask == 0 {
@@ -148,7 +148,7 @@ atomic_rw_mutex_try_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
}
// atomic_rw_mutex_shared_lock locks rw for reading (with arbitrary number of readers)
atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex) {
atomic_rw_mutex_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
state := atomic_load(&rw.state)
for state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
ok: bool
@@ -164,7 +164,7 @@ atomic_rw_mutex_shared_lock :: proc(rw: ^Atomic_RW_Mutex) {
}
// atomic_rw_mutex_shared_unlock unlocks rw for reading (with arbitrary number of readers)
atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex) {
atomic_rw_mutex_shared_unlock :: proc "contextless" (rw: ^Atomic_RW_Mutex) {
state := atomic_sub(&rw.state, Atomic_RW_Mutex_State_Reader)
if (state & Atomic_RW_Mutex_State_Reader_Mask == Atomic_RW_Mutex_State_Reader) &&
@@ -174,7 +174,7 @@ atomic_rw_mutex_shared_unlock :: proc(rw: ^Atomic_RW_Mutex) {
}
// atomic_rw_mutex_try_shared_lock tries to lock rw for reading (with arbitrary number of readers)
atomic_rw_mutex_try_shared_lock :: proc(rw: ^Atomic_RW_Mutex) -> bool {
atomic_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^Atomic_RW_Mutex) -> bool {
state := atomic_load(&rw.state)
if state & (Atomic_RW_Mutex_State_Is_Writing|Atomic_RW_Mutex_State_Writer_Mask) == 0 {
_, ok := atomic_compare_exchange_strong(&rw.state, state, state + Atomic_RW_Mutex_State_Reader)
@@ -198,7 +198,7 @@ Example:
}
*/
@(deferred_in=atomic_rw_mutex_unlock)
atomic_rw_mutex_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
atomic_rw_mutex_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {
atomic_rw_mutex_lock(m)
return true
}
@@ -210,7 +210,7 @@ Example:
}
*/
@(deferred_in=atomic_rw_mutex_shared_unlock)
atomic_rw_mutex_shared_guard :: proc(m: ^Atomic_RW_Mutex) -> bool {
atomic_rw_mutex_shared_guard :: proc "contextless" (m: ^Atomic_RW_Mutex) -> bool {
atomic_rw_mutex_shared_lock(m)
return true
}
@@ -228,7 +228,7 @@ Atomic_Recursive_Mutex :: struct {
mutex: Mutex,
}
atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) {
atomic_recursive_mutex_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
tid := current_thread_id()
if tid != m.owner {
mutex_lock(&m.mutex)
@@ -238,9 +238,9 @@ atomic_recursive_mutex_lock :: proc(m: ^Atomic_Recursive_Mutex) {
m.recursion += 1
}
atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex) {
atomic_recursive_mutex_unlock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) {
tid := current_thread_id()
assert(tid == m.owner)
_assert(tid == m.owner, "tid != m.owner")
m.recursion -= 1
recursion := m.recursion
if recursion == 0 {
@@ -253,7 +253,7 @@ atomic_recursive_mutex_unlock :: proc(m: ^Atomic_Recursive_Mutex) {
}
atomic_recursive_mutex_try_lock :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
atomic_recursive_mutex_try_lock :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {
tid := current_thread_id()
if m.owner == tid {
return mutex_try_lock(&m.mutex)
@@ -274,7 +274,7 @@ Example:
}
*/
@(deferred_in=atomic_recursive_mutex_unlock)
atomic_recursive_mutex_guard :: proc(m: ^Atomic_Recursive_Mutex) -> bool {
atomic_recursive_mutex_guard :: proc "contextless" (m: ^Atomic_Recursive_Mutex) -> bool {
atomic_recursive_mutex_lock(m)
return true
}
@@ -289,7 +289,7 @@ Atomic_Cond :: struct {
state: Futex,
}
atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) {
atomic_cond_wait :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex) {
state := u32(atomic_load_explicit(&c.state, .Relaxed))
unlock(m)
futex_wait(&c.state, state)
@@ -297,7 +297,7 @@ atomic_cond_wait :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex) {
}
atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) {
atomic_cond_wait_with_timeout :: proc "contextless" (c: ^Atomic_Cond, m: ^Atomic_Mutex, duration: time.Duration) -> (ok: bool) {
state := u32(atomic_load_explicit(&c.state, .Relaxed))
unlock(m)
ok = futex_wait_with_timeout(&c.state, state, duration)
@@ -306,12 +306,12 @@ atomic_cond_wait_with_timeout :: proc(c: ^Atomic_Cond, m: ^Atomic_Mutex, duratio
}
atomic_cond_signal :: proc(c: ^Atomic_Cond) {
atomic_cond_signal :: proc "contextless" (c: ^Atomic_Cond) {
atomic_add_explicit(&c.state, 1, .Release)
futex_signal(&c.state)
}
atomic_cond_broadcast :: proc(c: ^Atomic_Cond) {
atomic_cond_broadcast :: proc "contextless" (c: ^Atomic_Cond) {
atomic_add_explicit(&c.state, 1, .Release)
futex_broadcast(&c.state)
}
@@ -324,7 +324,7 @@ Atomic_Sema :: struct {
count: Futex,
}
atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) {
atomic_sema_post :: proc "contextless" (s: ^Atomic_Sema, count := 1) {
atomic_add_explicit(&s.count, Futex(count), .Release)
if count == 1 {
futex_signal(&s.count)
@@ -333,7 +333,7 @@ atomic_sema_post :: proc(s: ^Atomic_Sema, count := 1) {
}
}
atomic_sema_wait :: proc(s: ^Atomic_Sema) {
atomic_sema_wait :: proc "contextless" (s: ^Atomic_Sema) {
for {
original_count := atomic_load_explicit(&s.count, .Relaxed)
for original_count == 0 {
@@ -346,7 +346,7 @@ atomic_sema_wait :: proc(s: ^Atomic_Sema) {
}
}
atomic_sema_wait_with_timeout :: proc(s: ^Atomic_Sema, duration: time.Duration) -> bool {
atomic_sema_wait_with_timeout :: proc "contextless" (s: ^Atomic_Sema, duration: time.Duration) -> bool {
if duration <= 0 {
return false
}
+78 -19
View File
@@ -2,20 +2,31 @@
package sync
import "core:time"
import vg "core:sys/valgrind"
_ :: vg
_Sema :: struct {
atomic: Atomic_Sema,
}
_sema_post :: proc(s: ^Sema, count := 1) {
_sema_post :: proc "contextless" (s: ^Sema, count := 1) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_sem_post_pre(s)
}
atomic_sema_post(&s.impl.atomic, count)
}
_sema_wait :: proc(s: ^Sema) {
_sema_wait :: proc "contextless" (s: ^Sema) {
atomic_sema_wait(&s.impl.atomic)
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_sem_wait_post(s)
}
}
_sema_wait_with_timeout :: proc(s: ^Sema, duration: time.Duration) -> bool {
_sema_wait_with_timeout :: proc "contextless" (s: ^Sema, duration: time.Duration) -> bool {
when ODIN_VALGRIND_SUPPORT {
defer vg.helgrind_sem_wait_post(s)
}
return atomic_sema_wait_with_timeout(&s.impl.atomic, duration)
}
@@ -25,7 +36,12 @@ _Recursive_Mutex :: struct {
recursion: i32,
}
_recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
_recursive_mutex_lock :: proc "contextless" (m: ^Recursive_Mutex) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_mutex_lock_pre(m, false)
defer vg.helgrind_mutex_lock_post(m)
}
tid := Futex(current_thread_id())
for {
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
@@ -40,7 +56,12 @@ _recursive_mutex_lock :: proc(m: ^Recursive_Mutex) {
}
}
_recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
_recursive_mutex_unlock :: proc "contextless" (m: ^Recursive_Mutex) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_mutex_unlock_pre(m)
defer vg.helgrind_mutex_unlock_post(m)
}
m.impl.recursion -= 1
if m.impl.recursion != 0 {
return
@@ -52,7 +73,7 @@ _recursive_mutex_unlock :: proc(m: ^Recursive_Mutex) {
}
_recursive_mutex_try_lock :: proc(m: ^Recursive_Mutex) -> bool {
_recursive_mutex_try_lock :: proc "contextless" (m: ^Recursive_Mutex) -> bool {
tid := Futex(current_thread_id())
prev_owner := atomic_compare_exchange_strong_explicit(&m.impl.owner, 0, tid, .Acquire, .Acquire)
switch prev_owner {
@@ -70,15 +91,27 @@ when ODIN_OS != .Windows {
mutex: Atomic_Mutex,
}
_mutex_lock :: proc(m: ^Mutex) {
_mutex_lock :: proc "contextless" (m: ^Mutex) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_mutex_lock_pre(m, false)
defer vg.helgrind_mutex_lock_post(m)
}
atomic_mutex_lock(&m.impl.mutex)
}
_mutex_unlock :: proc(m: ^Mutex) {
_mutex_unlock :: proc "contextless" (m: ^Mutex) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_mutex_unlock_pre(m)
defer vg.helgrind_mutex_unlock_post(m)
}
atomic_mutex_unlock(&m.impl.mutex)
}
_mutex_try_lock :: proc(m: ^Mutex) -> bool {
_mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_mutex_lock_pre(m, true)
defer vg.helgrind_mutex_lock_post(m)
}
return atomic_mutex_try_lock(&m.impl.mutex)
}
@@ -86,19 +119,33 @@ when ODIN_OS != .Windows {
cond: Atomic_Cond,
}
_cond_wait :: proc(c: ^Cond, m: ^Mutex) {
_cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
when ODIN_VALGRIND_SUPPORT {
_ = vg.helgrind_cond_wait_pre(c, m)
defer _ = vg.helgrind_cond_wait_post(c, m)
}
atomic_cond_wait(&c.impl.cond, &m.impl.mutex)
}
_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
_cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
when ODIN_VALGRIND_SUPPORT {
_ = vg.helgrind_cond_wait_pre(c, m)
defer _ = vg.helgrind_cond_wait_post(c, m)
}
return atomic_cond_wait_with_timeout(&c.impl.cond, &m.impl.mutex, duration)
}
_cond_signal :: proc(c: ^Cond) {
_cond_signal :: proc "contextless" (c: ^Cond) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_cond_signal_pre(c)
}
atomic_cond_signal(&c.impl.cond)
}
_cond_broadcast :: proc(c: ^Cond) {
_cond_broadcast :: proc "contextless" (c: ^Cond) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_cond_broadcast_pre(c)
}
atomic_cond_broadcast(&c.impl.cond)
}
@@ -107,27 +154,39 @@ when ODIN_OS != .Windows {
mutex: Atomic_RW_Mutex,
}
_rw_mutex_lock :: proc(rw: ^RW_Mutex) {
_rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_rwlock_lock_pre(rw, true)
}
atomic_rw_mutex_lock(&rw.impl.mutex)
}
_rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
_rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
atomic_rw_mutex_unlock(&rw.impl.mutex)
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_rwlock_unlock_post(rw, true)
}
}
_rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
_rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return atomic_rw_mutex_try_lock(&rw.impl.mutex)
}
_rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
_rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_rwlock_lock_pre(rw, false)
}
atomic_rw_mutex_shared_lock(&rw.impl.mutex)
}
_rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
_rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
atomic_rw_mutex_shared_unlock(&rw.impl.mutex)
when ODIN_VALGRIND_SUPPORT {
vg.helgrind_rwlock_unlock_post(rw, false)
}
}
_rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return atomic_rw_mutex_try_shared_lock(&rw.impl.mutex)
}
}
+13 -13
View File
@@ -13,15 +13,15 @@ _Mutex :: struct {
srwlock: win32.SRWLOCK,
}
_mutex_lock :: proc(m: ^Mutex) {
_mutex_lock :: proc "contextless" (m: ^Mutex) {
win32.AcquireSRWLockExclusive(&m.impl.srwlock)
}
_mutex_unlock :: proc(m: ^Mutex) {
_mutex_unlock :: proc "contextless" (m: ^Mutex) {
win32.ReleaseSRWLockExclusive(&m.impl.srwlock)
}
_mutex_try_lock :: proc(m: ^Mutex) -> bool {
_mutex_try_lock :: proc "contextless" (m: ^Mutex) -> bool {
return bool(win32.TryAcquireSRWLockExclusive(&m.impl.srwlock))
}
@@ -29,27 +29,27 @@ _RW_Mutex :: struct {
srwlock: win32.SRWLOCK,
}
_rw_mutex_lock :: proc(rw: ^RW_Mutex) {
_rw_mutex_lock :: proc "contextless" (rw: ^RW_Mutex) {
win32.AcquireSRWLockExclusive(&rw.impl.srwlock)
}
_rw_mutex_unlock :: proc(rw: ^RW_Mutex) {
_rw_mutex_unlock :: proc "contextless" (rw: ^RW_Mutex) {
win32.ReleaseSRWLockExclusive(&rw.impl.srwlock)
}
_rw_mutex_try_lock :: proc(rw: ^RW_Mutex) -> bool {
_rw_mutex_try_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return bool(win32.TryAcquireSRWLockExclusive(&rw.impl.srwlock))
}
_rw_mutex_shared_lock :: proc(rw: ^RW_Mutex) {
_rw_mutex_shared_lock :: proc "contextless" (rw: ^RW_Mutex) {
win32.AcquireSRWLockShared(&rw.impl.srwlock)
}
_rw_mutex_shared_unlock :: proc(rw: ^RW_Mutex) {
_rw_mutex_shared_unlock :: proc "contextless" (rw: ^RW_Mutex) {
win32.ReleaseSRWLockShared(&rw.impl.srwlock)
}
_rw_mutex_try_shared_lock :: proc(rw: ^RW_Mutex) -> bool {
_rw_mutex_try_shared_lock :: proc "contextless" (rw: ^RW_Mutex) -> bool {
return bool(win32.TryAcquireSRWLockShared(&rw.impl.srwlock))
}
@@ -58,22 +58,22 @@ _Cond :: struct {
cond: win32.CONDITION_VARIABLE,
}
_cond_wait :: proc(c: ^Cond, m: ^Mutex) {
_cond_wait :: proc "contextless" (c: ^Cond, m: ^Mutex) {
_ = win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, win32.INFINITE, 0)
}
_cond_wait_with_timeout :: proc(c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
_cond_wait_with_timeout :: proc "contextless" (c: ^Cond, m: ^Mutex, duration: time.Duration) -> bool {
duration := u32(duration / time.Millisecond)
ok := win32.SleepConditionVariableSRW(&c.impl.cond, &m.impl.srwlock, duration, 0)
return bool(ok)
}
_cond_signal :: proc(c: ^Cond) {
_cond_signal :: proc "contextless" (c: ^Cond) {
win32.WakeConditionVariable(&c.impl.cond)
}
_cond_broadcast :: proc(c: ^Cond) {
_cond_broadcast :: proc "contextless" (c: ^Cond) {
win32.WakeAllConditionVariable(&c.impl.cond)
}
+38
View File
@@ -3,7 +3,45 @@ package sys_windows
foreign import dwmapi "system:Dwmapi.lib"
DWMWINDOWATTRIBUTE :: enum {
DWMWA_NCRENDERING_ENABLED,
DWMWA_NCRENDERING_POLICY,
DWMWA_TRANSITIONS_FORCEDISABLED,
DWMWA_ALLOW_NCPAINT,
DWMWA_CAPTION_BUTTON_BOUNDS,
DWMWA_NONCLIENT_RTL_LAYOUT,
DWMWA_FORCE_ICONIC_REPRESENTATION,
DWMWA_FLIP3D_POLICY,
DWMWA_EXTENDED_FRAME_BOUNDS,
DWMWA_HAS_ICONIC_BITMAP,
DWMWA_DISALLOW_PEEK,
DWMWA_EXCLUDED_FROM_PEEK,
DWMWA_CLOAK,
DWMWA_CLOAKED,
DWMWA_FREEZE_REPRESENTATION,
DWMWA_PASSIVE_UPDATE_MODE,
DWMWA_USE_HOSTBACKDROPBRUSH,
DWMWA_USE_IMMERSIVE_DARK_MODE = 20,
DWMWA_WINDOW_CORNER_PREFERENCE = 33,
DWMWA_BORDER_COLOR,
DWMWA_CAPTION_COLOR,
DWMWA_TEXT_COLOR,
DWMWA_VISIBLE_FRAME_BORDER_THICKNESS,
DWMWA_SYSTEMBACKDROP_TYPE,
DWMWA_LAST,
}
DWMNCRENDERINGPOLICY :: enum {
DWMNCRP_USEWINDOWSTYLE,
DWMNCRP_DISABLED,
DWMNCRP_ENABLED,
DWMNCRP_LAST,
}
@(default_calling_convention="stdcall")
foreign dwmapi {
DwmFlush :: proc() -> HRESULT ---
DwmIsCompositionEnabled :: proc(pfEnabled: ^BOOL) -> HRESULT ---
DwmExtendFrameIntoClientArea :: proc(hWnd: HWND, pMarInset: PMARGINS) -> HRESULT ---
DwmSetWindowAttribute :: proc(hWnd: HWND, dwAttribute: DWORD, pvAttribute: LPCVOID, cbAttribute: DWORD) -> HRESULT ---
}
+3
View File
@@ -62,6 +62,7 @@ foreign gdi32 {
SetPixelFormat :: proc(hdc: HDC, format: c_int, ppfd: ^PIXELFORMATDESCRIPTOR) -> BOOL ---
ChoosePixelFormat :: proc(hdc: HDC, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int ---
DescribePixelFormat :: proc(hdc: HDC, iPixelFormat: c_int, nBytes: UINT, ppfd: ^PIXELFORMATDESCRIPTOR) -> c_int ---
SwapBuffers :: proc(HDC) -> BOOL ---
SetDCBrushColor :: proc(hdc: HDC, color: COLORREF) -> COLORREF ---
@@ -78,6 +79,8 @@ foreign gdi32 {
TextOutW :: proc(hdc: HDC, x, y: c_int, lpString: LPCWSTR, c: c_int) -> BOOL ---
GetTextExtentPoint32W :: proc(hdc: HDC, lpString: LPCWSTR, c: c_int, psizl: LPSIZE) -> BOOL ---
GetTextMetricsW :: proc(hdc: HDC, lptm: LPTEXTMETRICW) -> BOOL ---
CreateSolidBrush :: proc(color: COLORREF) -> HBRUSH ---
}
RGB :: #force_inline proc "contextless" (r, g, b: u8) -> COLORREF {
+48
View File
@@ -370,6 +370,8 @@ foreign kernel32 {
lpTotalNumberOfBytes: PULARGE_INTEGER,
lpTotalNumberOfFreeBytes: PULARGE_INTEGER,
) -> BOOL ---
GetLogicalProcessorInformation :: proc(buffer: ^SYSTEM_LOGICAL_PROCESSOR_INFORMATION, returnedLength: PDWORD) -> BOOL ---
}
@@ -999,3 +1001,49 @@ foreign kernel32 {
ConvertThreadToFiber :: proc(lpParameter: LPVOID) -> LPVOID ---
SwitchToFiber :: proc(lpFiber: LPVOID) ---
}
LOGICAL_PROCESSOR_RELATIONSHIP :: enum c_int {
RelationProcessorCore,
RelationNumaNode,
RelationCache,
RelationProcessorPackage,
RelationGroup,
RelationProcessorDie,
RelationNumaNodeEx,
RelationProcessorModule,
RelationAll = 0xffff,
}
PROCESSOR_CACHE_TYPE :: enum c_int {
CacheUnified,
CacheInstruction,
CacheData,
CacheTrace,
}
CACHE_DESCRIPTOR :: struct {
Level: BYTE,
Associativity: BYTE,
LineSize: WORD,
Size: DWORD,
Type: PROCESSOR_CACHE_TYPE,
}
ProcessorCore :: struct {
Flags: BYTE,
}
NumaNode :: struct {
NodeNumber: DWORD,
}
DUMMYUNIONNAME_u :: struct #raw_union {
Core: ProcessorCore,
Node: NumaNode,
Cache: CACHE_DESCRIPTOR,
Reserved: [2]ULONGLONG,
}
SYSTEM_LOGICAL_PROCESSOR_INFORMATION :: struct {
ProcessorMask: ULONG_PTR,
Relationship: LOGICAL_PROCESSOR_RELATIONSHIP,
DummyUnion: DUMMYUNIONNAME_u,
}
+33
View File
@@ -22,4 +22,37 @@ foreign shell32 {
) -> c_int ---
SHFileOperationW :: proc(lpFileOp: LPSHFILEOPSTRUCTW) -> c_int ---
SHGetFolderPathW :: proc(hwnd: HWND, csidl: c_int, hToken: HANDLE, dwFlags: DWORD, pszPath: LPWSTR) -> HRESULT ---
SHAppBarMessage :: proc(dwMessage: DWORD, pData: PAPPBARDATA) -> UINT_PTR ---
}
APPBARDATA :: struct {
cbSize: DWORD,
hWnd: HWND,
uCallbackMessage: UINT,
uEdge: UINT,
rc: RECT,
lParam: LPARAM,
}
PAPPBARDATA :: ^APPBARDATA
ABM_NEW :: 0x00000000
ABM_REMOVE :: 0x00000001
ABM_QUERYPOS :: 0x00000002
ABM_SETPOS :: 0x00000003
ABM_GETSTATE :: 0x00000004
ABM_GETTASKBARPOS :: 0x00000005
ABM_ACTIVATE :: 0x00000006
ABM_GETAUTOHIDEBAR :: 0x00000007
ABM_SETAUTOHIDEBAR :: 0x00000008
ABM_WINDOWPOSCHANGED :: 0x0000009
ABM_SETSTATE :: 0x0000000a
ABN_STATECHANGE :: 0x0000000
ABN_POSCHANGED :: 0x0000001
ABN_FULLSCREENAPP :: 0x0000002
ABN_WINDOWARRANGE :: 0x0000003
ABS_AUTOHIDE :: 0x0000001
ABS_ALWAYSONTOP :: 0x0000002
ABE_LEFT :: 0
ABE_TOP :: 1
ABE_RIGHT :: 2
ABE_BOTTOM :: 3
+20
View File
@@ -38,6 +38,7 @@ HHOOK :: distinct HANDLE
HKEY :: distinct HANDLE
HDESK :: distinct HANDLE
HFONT :: distinct HANDLE
HRGN :: distinct HANDLE
BOOL :: distinct b32
BYTE :: distinct u8
BOOLEAN :: distinct b8
@@ -1554,6 +1555,25 @@ WA_INACTIVE :: 0
WA_ACTIVE :: 1
WA_CLICKACTIVE :: 2
// Struct pointed to by WM_GETMINMAXINFO lParam
MINMAXINFO :: struct {
ptReserved: POINT,
ptMaxSize: POINT,
ptMaxPosition: POINT,
ptMinTrackSize: POINT,
ptMaxTrackSize: POINT,
}
PMINMAXINFO :: ^MINMAXINFO
LPMINMAXINFO :: PMINMAXINFO
MONITORINFO :: struct {
cbSize: DWORD,
rcMonitor: RECT,
rcWork: RECT,
dwFlags: DWORD,
}
LPMONITORINFO :: ^MONITORINFO
// SetWindowsHook() codes
WH_MIN :: -1
WH_MSGFILTER :: -1
+38
View File
@@ -100,6 +100,7 @@ foreign user32 {
AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL ---
SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL ---
GetMonitorInfoW :: proc(hMonitor: HMONITOR, lpmi: LPMONITORINFO) -> BOOL ---
GetWindowDC :: proc(hWnd: HWND) -> HDC ---
GetDC :: proc(hWnd: HWND) -> HDC ---
@@ -122,6 +123,8 @@ foreign user32 {
GetKeyState :: proc(nVirtKey: c_int) -> SHORT ---
GetAsyncKeyState :: proc(vKey: c_int) -> SHORT ---
GetKeyboardState :: proc(lpKeyState: PBYTE) -> BOOL ---
MapVirtualKeyW :: proc(uCode: UINT, uMapType: UINT) -> UINT ---
@@ -202,6 +205,17 @@ foreign user32 {
GetRawInputDeviceList :: proc(pRawInputDeviceList: PRAWINPUTDEVICELIST, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
GetRegisteredRawInputDevices :: proc(pRawInputDevices: PRAWINPUTDEVICE, puiNumDevices: PUINT, cbSize: UINT) -> UINT ---
RegisterRawInputDevices :: proc(pRawInputDevices: PCRAWINPUTDEVICE, uiNumDevices: UINT, cbSize: UINT) -> BOOL ---
SetLayeredWindowAttributes :: proc(hWnd: HWND, crKey: COLORREF, bAlpha: BYTE, dwFlags: DWORD) -> BOOL ---
FillRect :: proc(hDC: HDC, lprc: ^RECT, hbr: HBRUSH) -> int ---
EqualRect :: proc(lprc1: ^RECT, lprc2: ^RECT) -> BOOL ---
GetWindowInfo :: proc(hwnd: HWND, pwi: PWINDOWINFO) -> BOOL ---
GetWindowPlacement :: proc(hWnd: HWND, lpwndpl: ^WINDOWPLACEMENT) -> BOOL ---
SetWindowRgn :: proc(hWnd: HWND, hRgn: HRGN, bRedraw: BOOL) -> int ---
CreateRectRgnIndirect :: proc(lprect: ^RECT) -> HRGN ---
GetSystemMetricsForDpi :: proc(nIndex: int, dpi: UINT) -> int ---
}
CreateWindowW :: #force_inline proc "stdcall" (
@@ -432,3 +446,27 @@ RI_MOUSE_BUTTON_5_DOWN :: 0x0100
RI_MOUSE_BUTTON_5_UP :: 0x0200
RI_MOUSE_WHEEL :: 0x0400
RI_MOUSE_HWHEEL :: 0x0800
WINDOWPLACEMENT :: struct {
length: UINT,
flags: UINT,
showCmd: UINT,
ptMinPosition: POINT,
ptMaxPosition: POINT,
rcNormalPosition: RECT,
rcDevice: RECT,
}
WINDOWINFO :: struct {
cbSize: DWORD,
rcWindow: RECT,
rcClient: RECT,
dwStyle: DWORD,
dwExStyle: DWORD,
dwWindowStatus: DWORD,
cxWindowBorders: UINT,
cyWindowBorders: UINT,
atomWindowType: ATOM,
wCreatorVersion: WORD,
}
PWINDOWINFO :: ^WINDOWINFO
+12
View File
@@ -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 ---
}
+959
View File
@@ -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
View File
@@ -10,45 +10,45 @@ struct Array {
T &operator[](isize index) {
#if !defined(NO_ARRAY_BOUNDS_CHECK)
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
GB_ASSERT_MSG(cast(usize)index < cast(usize)count, "Index %td is out of bounds ranges 0..<%td", index, count);
#endif
return data[index];
}
T const &operator[](isize index) const {
#if !defined(NO_ARRAY_BOUNDS_CHECK)
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
GB_ASSERT_MSG(cast(usize)index < cast(usize)count, "Index %td is out of bounds ranges 0..<%td", index, count);
#endif
return data[index];
}
};
template <typename T> void array_init (Array<T> *array, gbAllocator const &a);
template <typename T> void array_init (Array<T> *array, gbAllocator const &a, isize count);
template <typename T> void array_init (Array<T> *array, gbAllocator const &a, isize count, isize capacity);
template <typename T> Array<T> array_make (gbAllocator const &a);
template <typename T> Array<T> array_make (gbAllocator const &a, isize count);
template <typename T> Array<T> array_make (gbAllocator const &a, isize count, isize capacity);
template <typename T> Array<T> array_make_from_ptr (T *data, isize count, isize capacity);
template <typename T> void array_free (Array<T> *array);
template <typename T> void array_add (Array<T> *array, T const &t);
template <typename T> T * array_add_and_get (Array<T> *array);
template <typename T> void array_add_elems (Array<T> *array, T const *elems, isize elem_count);
template <typename T> T array_pop (Array<T> *array);
template <typename T> void array_clear (Array<T> *array);
template <typename T> void array_reserve (Array<T> *array, isize capacity);
template <typename T> void array_resize (Array<T> *array, isize count);
template <typename T> void array_set_capacity (Array<T> *array, isize capacity);
template <typename T> Array<T> array_slice (Array<T> const &array, isize lo, isize hi);
template <typename T> Array<T> array_clone (gbAllocator const &a, Array<T> const &array);
template <typename T> gb_internal void array_init (Array<T> *array, gbAllocator const &a);
template <typename T> gb_internal void array_init (Array<T> *array, gbAllocator const &a, isize count);
template <typename T> gb_internal void array_init (Array<T> *array, gbAllocator const &a, isize count, isize capacity);
template <typename T> gb_internal Array<T> array_make (gbAllocator const &a);
template <typename T> gb_internal Array<T> array_make (gbAllocator const &a, isize count);
template <typename T> gb_internal Array<T> array_make (gbAllocator const &a, isize count, isize capacity);
template <typename T> gb_internal Array<T> array_make_from_ptr (T *data, isize count, isize capacity);
template <typename T> gb_internal void array_free (Array<T> *array);
template <typename T> gb_internal void array_add (Array<T> *array, T const &t);
template <typename T> gb_internal T * array_add_and_get (Array<T> *array);
template <typename T> gb_internal void array_add_elems (Array<T> *array, T const *elems, isize elem_count);
template <typename T> gb_internal T array_pop (Array<T> *array);
template <typename T> gb_internal void array_clear (Array<T> *array);
template <typename T> gb_internal void array_reserve (Array<T> *array, isize capacity);
template <typename T> gb_internal void array_resize (Array<T> *array, isize count);
template <typename T> gb_internal void array_set_capacity (Array<T> *array, isize capacity);
template <typename T> gb_internal Array<T> array_slice (Array<T> const &array, isize lo, isize hi);
template <typename T> gb_internal Array<T> array_clone (gbAllocator const &a, Array<T> const &array);
template <typename T> void array_ordered_remove (Array<T> *array, isize index);
template <typename T> void array_unordered_remove(Array<T> *array, isize index);
template <typename T> gb_internal void array_ordered_remove (Array<T> *array, isize index);
template <typename T> gb_internal void array_unordered_remove(Array<T> *array, isize index);
template <typename T> void array_copy(Array<T> *array, Array<T> const &data, isize offset);
template <typename T> void array_copy(Array<T> *array, Array<T> const &data, isize offset, isize count);
template <typename T> gb_internal void array_copy(Array<T> *array, Array<T> const &data, isize offset);
template <typename T> gb_internal void array_copy(Array<T> *array, Array<T> const &data, isize offset, isize count);
template <typename T> T *array_end_ptr(Array<T> *array);
template <typename T> gb_internal T *array_end_ptr(Array<T> *array);
template <typename T>
@@ -56,27 +56,27 @@ struct Slice {
T *data;
isize count;
T &operator[](isize index) {
gb_inline T &operator[](isize index) {
#if !defined(NO_ARRAY_BOUNDS_CHECK)
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
GB_ASSERT_MSG(cast(usize)index < cast(usize)count, "Index %td is out of bounds ranges 0..<%td", index, count);
#endif
return data[index];
}
T const &operator[](isize index) const {
gb_inline T const &operator[](isize index) const {
#if !defined(NO_ARRAY_BOUNDS_CHECK)
GB_ASSERT_MSG(0 <= index && index < count, "Index %td is out of bounds ranges 0..<%td", index, count);
GB_ASSERT_MSG(cast(usize)index < cast(usize)count, "Index %td is out of bounds ranges 0..<%td", index, count);
#endif
return data[index];
}
};
template <typename T> Slice<T> slice_from_array(Array<T> const &a);
template <typename T> gb_internal Slice<T> slice_from_array(Array<T> const &a);
template <typename T>
Slice<T> slice_make(gbAllocator const &allocator, isize count) {
gb_internal Slice<T> slice_make(gbAllocator const &allocator, isize count) {
GB_ASSERT(count >= 0);
Slice<T> s = {};
s.data = gb_alloc_array(allocator, T, count);
@@ -86,7 +86,7 @@ Slice<T> slice_make(gbAllocator const &allocator, isize count) {
}
template <typename T>
void slice_init(Slice<T> *s, gbAllocator const &allocator, isize count) {
gb_internal void slice_init(Slice<T> *s, gbAllocator const &allocator, isize count) {
GB_ASSERT(count >= 0);
s->data = gb_alloc_array(allocator, T, count);
if (count > 0) {
@@ -96,23 +96,23 @@ void slice_init(Slice<T> *s, gbAllocator const &allocator, isize count) {
}
template <typename T>
void slice_free(Slice<T> *s, gbAllocator const &allocator) {
gb_internal void slice_free(Slice<T> *s, gbAllocator const &allocator) {
gb_free(allocator, s->data);
}
template <typename T>
void slice_resize(Slice<T> *s, gbAllocator const &allocator, isize new_count) {
gb_internal void slice_resize(Slice<T> *s, gbAllocator const &allocator, isize new_count) {
resize_array_raw(&s->data, allocator, s->count, new_count);
s->count = new_count;
}
template <typename T>
Slice<T> slice_from_array(Array<T> const &a) {
gb_internal Slice<T> slice_from_array(Array<T> const &a) {
return {a.data, a.count};
}
template <typename T>
Slice<T> slice_array(Array<T> const &array, isize lo, isize hi) {
gb_internal Slice<T> slice_array(Array<T> const &array, isize lo, isize hi) {
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
Slice<T> out = {};
isize len = hi-lo;
@@ -125,30 +125,30 @@ Slice<T> slice_array(Array<T> const &array, isize lo, isize hi) {
template <typename T>
Slice<T> slice_clone(gbAllocator const &allocator, Slice<T> const &a) {
gb_internal Slice<T> slice_clone(gbAllocator const &allocator, Slice<T> const &a) {
T *data = cast(T *)gb_alloc_copy_align(allocator, a.data, a.count*gb_size_of(T), gb_align_of(T));
return {data, a.count};
}
template <typename T>
Slice<T> slice_clone_from_array(gbAllocator const &allocator, Array<T> const &a) {
gb_internal Slice<T> slice_clone_from_array(gbAllocator const &allocator, Array<T> const &a) {
auto c = array_clone(allocator, a);
return {c.data, c.count};
}
template <typename T>
void slice_copy(Slice<T> *slice, Slice<T> const &data) {
gb_internal void slice_copy(Slice<T> *slice, Slice<T> const &data) {
isize n = gb_min(slice->count, data.count);
gb_memmove(slice->data, data.data, gb_size_of(T)*n);
}
template <typename T>
void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset) {
gb_internal void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset) {
isize n = gb_clamp(slice->count-offset, 0, data.count);
gb_memmove(slice->data+offset, data.data, gb_size_of(T)*n);
}
template <typename T>
void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset, isize count) {
gb_internal void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset, isize count) {
isize n = gb_clamp(slice->count-offset, 0, gb_min(data.count, count));
gb_memmove(slice->data+offset, data.data, gb_size_of(T)*n);
}
@@ -156,7 +156,7 @@ void slice_copy(Slice<T> *slice, Slice<T> const &data, isize offset, isize count
template <typename T>
gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi) {
gb_internal gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi) {
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
Slice<T> out = {};
isize len = hi-lo;
@@ -169,7 +169,7 @@ gb_inline Slice<T> slice(Slice<T> const &array, isize lo, isize hi) {
template <typename T>
void slice_ordered_remove(Slice<T> *array, isize index) {
gb_internal void slice_ordered_remove(Slice<T> *array, isize index) {
GB_ASSERT(0 <= index && index < array->count);
isize bytes = gb_size_of(T) * (array->count-(index+1));
@@ -178,7 +178,7 @@ void slice_ordered_remove(Slice<T> *array, isize index) {
}
template <typename T>
void slice_unordered_remove(Slice<T> *array, isize index) {
gb_internal void slice_unordered_remove(Slice<T> *array, isize index) {
GB_ASSERT(0 <= index && index < array->count);
isize n = array->count-1;
@@ -190,18 +190,18 @@ void slice_unordered_remove(Slice<T> *array, isize index) {
template <typename T>
void array_copy(Array<T> *array, Array<T> const &data, isize offset) {
gb_internal void array_copy(Array<T> *array, Array<T> const &data, isize offset) {
gb_memmove(array->data+offset, data.data, gb_size_of(T)*data.count);
}
template <typename T>
void array_copy(Array<T> *array, Array<T> const &data, isize offset, isize count) {
gb_internal void array_copy(Array<T> *array, Array<T> const &data, isize offset, isize count) {
gb_memmove(array->data+offset, data.data, gb_size_of(T)*gb_min(data.count, count));
}
template <typename T>
T *array_end_ptr(Array<T> *array) {
gb_internal T *array_end_ptr(Array<T> *array) {
if (array->count > 0) {
return &array->data[array->count-1];
}
@@ -210,18 +210,18 @@ T *array_end_ptr(Array<T> *array) {
template <typename T>
gb_inline void array_init(Array<T> *array, gbAllocator const &a) {
gb_internal gb_inline void array_init(Array<T> *array, gbAllocator const &a) {
isize cap = ARRAY_GROW_FORMULA(0);
array_init(array, a, 0, cap);
}
template <typename T>
gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count) {
gb_internal gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count) {
array_init(array, a, count, count);
}
template <typename T>
gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count, isize capacity) {
gb_internal gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count, isize capacity) {
array->allocator = a;
array->data = nullptr;
if (capacity > 0) {
@@ -234,7 +234,7 @@ gb_inline void array_init(Array<T> *array, gbAllocator const &a, isize count, is
template <typename T>
gb_inline Array<T> array_make_from_ptr(T *data, isize count, isize capacity) {
gb_internal gb_inline Array<T> array_make_from_ptr(T *data, isize count, isize capacity) {
Array<T> a = {0};
a.data = data;
a.count = count;
@@ -244,7 +244,7 @@ gb_inline Array<T> array_make_from_ptr(T *data, isize count, isize capacity) {
template <typename T>
gb_inline Array<T> array_make(gbAllocator const &a) {
gb_internal gb_inline Array<T> array_make(gbAllocator const &a) {
isize capacity = ARRAY_GROW_FORMULA(0);
Array<T> array = {};
array.allocator = a;
@@ -254,7 +254,7 @@ gb_inline Array<T> array_make(gbAllocator const &a) {
return array;
}
template <typename T>
gb_inline Array<T> array_make(gbAllocator const &a, isize count) {
gb_internal gb_inline Array<T> array_make(gbAllocator const &a, isize count) {
Array<T> array = {};
array.allocator = a;
array.data = gb_alloc_array(a, T, count);
@@ -263,7 +263,7 @@ gb_inline Array<T> array_make(gbAllocator const &a, isize count) {
return array;
}
template <typename T>
gb_inline Array<T> array_make(gbAllocator const &a, isize count, isize capacity) {
gb_internal gb_inline Array<T> array_make(gbAllocator const &a, isize count, isize capacity) {
Array<T> array = {};
array.allocator = a;
array.data = gb_alloc_array(a, T, capacity);
@@ -275,7 +275,7 @@ gb_inline Array<T> array_make(gbAllocator const &a, isize count, isize capacity)
template <typename T>
gb_inline void array_free(Array<T> *array) {
gb_internal gb_inline void array_free(Array<T> *array) {
if (array->allocator.proc != nullptr) {
gb_free(array->allocator, array->data);
}
@@ -284,7 +284,7 @@ gb_inline void array_free(Array<T> *array) {
}
template <typename T>
void array__grow(Array<T> *array, isize min_capacity) {
gb_internal void array__grow(Array<T> *array, isize min_capacity) {
isize new_capacity = ARRAY_GROW_FORMULA(array->capacity);
if (new_capacity < min_capacity) {
new_capacity = min_capacity;
@@ -293,7 +293,7 @@ void array__grow(Array<T> *array, isize min_capacity) {
}
template <typename T>
void array_add(Array<T> *array, T const &t) {
gb_internal void array_add(Array<T> *array, T const &t) {
if (array->capacity < array->count+1) {
array__grow(array, 0);
}
@@ -302,7 +302,7 @@ void array_add(Array<T> *array, T const &t) {
}
template <typename T>
T *array_add_and_get(Array<T> *array) {
gb_internal T *array_add_and_get(Array<T> *array) {
if (array->count < array->capacity) {
return &array->data[array->count++];
}
@@ -314,7 +314,7 @@ T *array_add_and_get(Array<T> *array) {
template <typename T>
void array_add_elems(Array<T> *array, T const *elems, isize elem_count) {
gb_internal void array_add_elems(Array<T> *array, T const *elems, isize elem_count) {
GB_ASSERT(elem_count >= 0);
if (array->capacity < array->count+elem_count) {
array__grow(array, array->count+elem_count);
@@ -325,26 +325,26 @@ void array_add_elems(Array<T> *array, T const *elems, isize elem_count) {
template <typename T>
gb_inline T array_pop(Array<T> *array) {
gb_internal gb_inline T array_pop(Array<T> *array) {
GB_ASSERT(array->count > 0);
array->count--;
return array->data[array->count];
}
template <typename T>
void array_clear(Array<T> *array) {
gb_internal void array_clear(Array<T> *array) {
array->count = 0;
}
template <typename T>
void array_reserve(Array<T> *array, isize capacity) {
gb_internal void array_reserve(Array<T> *array, isize capacity) {
if (array->capacity < capacity) {
array_set_capacity(array, capacity);
}
}
template <typename T>
void array_resize(Array<T> *array, isize count) {
gb_internal void array_resize(Array<T> *array, isize count) {
if (array->capacity < count) {
array__grow(array, count);
}
@@ -352,7 +352,7 @@ void array_resize(Array<T> *array, isize count) {
}
template <typename T>
void array_set_capacity(Array<T> *array, isize capacity) {
gb_internal void array_set_capacity(Array<T> *array, isize capacity) {
if (capacity == array->capacity) {
return;
}
@@ -381,7 +381,7 @@ void array_set_capacity(Array<T> *array, isize capacity) {
template <typename T>
gb_inline Array<T> array_slice(Array<T> const &array, isize lo, isize hi) {
gb_internal gb_inline Array<T> array_slice(Array<T> const &array, isize lo, isize hi) {
GB_ASSERT(0 <= lo && lo <= hi && hi <= array.count);
Array<T> out = {};
isize len = hi-lo;
@@ -394,7 +394,7 @@ gb_inline Array<T> array_slice(Array<T> const &array, isize lo, isize hi) {
}
template <typename T>
Array<T> array_clone(gbAllocator const &allocator, Array<T> const &array) {
gb_internal Array<T> array_clone(gbAllocator const &allocator, Array<T> const &array) {
auto clone = array_make<T>(allocator, array.count, array.count);
array_copy(&clone, array, 0);
return clone;
@@ -402,7 +402,7 @@ Array<T> array_clone(gbAllocator const &allocator, Array<T> const &array) {
template <typename T>
void array_ordered_remove(Array<T> *array, isize index) {
gb_internal void array_ordered_remove(Array<T> *array, isize index) {
GB_ASSERT(0 <= index && index < array->count);
isize bytes = gb_size_of(T) * (array->count-(index+1));
@@ -411,7 +411,7 @@ void array_ordered_remove(Array<T> *array, isize index) {
}
template <typename T>
void array_unordered_remove(Array<T> *array, isize index) {
gb_internal void array_unordered_remove(Array<T> *array, isize index) {
GB_ASSERT(0 <= index && index < array->count);
isize n = array->count-1;
@@ -424,35 +424,35 @@ void array_unordered_remove(Array<T> *array, isize index) {
template <typename T>
T *begin(Array<T> &array) {
gb_internal T *begin(Array<T> &array) {
return array.data;
}
template <typename T>
T const *begin(Array<T> const &array) {
gb_internal T const *begin(Array<T> const &array) {
return array.data;
}
template <typename T>
T *end(Array<T> &array) {
gb_internal T *end(Array<T> &array) {
return array.data + array.count;
}
template <typename T>
T const *end(Array<T> const &array) {
gb_internal T const *end(Array<T> const &array) {
return array.data + array.count;
}
template <typename T>
T *begin(Slice<T> &array) {
gb_internal T *begin(Slice<T> &array) {
return array.data;
}
template <typename T>
T const *begin(Slice<T> const &array) {
gb_internal T const *begin(Slice<T> const &array) {
return array.data;
}
template <typename T>
T *end(Slice<T> &array) {
gb_internal T *end(Slice<T> &array) {
return array.data + array.count;
}
template <typename T>
T const *end(Slice<T> const &array) {
gb_internal T const *end(Slice<T> const &array) {
return array.data + array.count;
}
+131 -107
View File
@@ -37,86 +37,86 @@ void MP_FREE(void *mem, size_t size) {
typedef mp_int BigInt;
void big_int_from_u64(BigInt *dst, u64 x);
void big_int_from_i64(BigInt *dst, i64 x);
void big_int_init (BigInt *dst, BigInt const *src);
void big_int_from_string(BigInt *dst, String const &s, bool *success);
gb_internal void big_int_from_u64(BigInt *dst, u64 x);
gb_internal void big_int_from_i64(BigInt *dst, i64 x);
gb_internal void big_int_init (BigInt *dst, BigInt const *src);
gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success);
void big_int_dealloc(BigInt *dst) {
gb_internal void big_int_dealloc(BigInt *dst) {
mp_clear(dst);
}
BigInt big_int_make(BigInt const *b, bool abs=false);
BigInt big_int_make_abs(BigInt const *b);
BigInt big_int_make_u64(u64 x);
BigInt big_int_make_i64(i64 x);
gb_internal BigInt big_int_make(BigInt const *b, bool abs=false);
gb_internal BigInt big_int_make_abs(BigInt const *b);
gb_internal BigInt big_int_make_u64(u64 x);
gb_internal BigInt big_int_make_i64(i64 x);
u64 big_int_to_u64 (BigInt const *x);
i64 big_int_to_i64 (BigInt const *x);
f64 big_int_to_f64 (BigInt const *x);
String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base = 10);
gb_internal u64 big_int_to_u64 (BigInt const *x);
gb_internal i64 big_int_to_i64 (BigInt const *x);
gb_internal f64 big_int_to_f64 (BigInt const *x);
gb_internal String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base = 10);
void big_int_add (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_sub (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_shl (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_shr (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_mul (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y);
gb_internal void big_int_add (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_sub (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_shl (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_shr (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_mul (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y);
void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q, BigInt *r);
void big_int_quo (BigInt *z, BigInt const *x, BigInt const *y);
void big_int_rem (BigInt *z, BigInt const *x, BigInt const *y);
gb_internal void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q, BigInt *r);
gb_internal void big_int_quo (BigInt *z, BigInt const *x, BigInt const *y);
gb_internal void big_int_rem (BigInt *z, BigInt const *x, BigInt const *y);
void big_int_and (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_xor (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_or (BigInt *dst, BigInt const *x, BigInt const *y);
void big_int_not (BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed);
gb_internal void big_int_and (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_xor (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_or (BigInt *dst, BigInt const *x, BigInt const *y);
gb_internal void big_int_not (BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed);
void big_int_add_eq(BigInt *dst, BigInt const *x);
void big_int_sub_eq(BigInt *dst, BigInt const *x);
void big_int_shl_eq(BigInt *dst, BigInt const *x);
void big_int_shr_eq(BigInt *dst, BigInt const *x);
void big_int_mul_eq(BigInt *dst, BigInt const *x);
gb_internal void big_int_add_eq(BigInt *dst, BigInt const *x);
gb_internal void big_int_sub_eq(BigInt *dst, BigInt const *x);
gb_internal void big_int_shl_eq(BigInt *dst, BigInt const *x);
gb_internal void big_int_shr_eq(BigInt *dst, BigInt const *x);
gb_internal void big_int_mul_eq(BigInt *dst, BigInt const *x);
void big_int_quo_eq(BigInt *dst, BigInt const *x);
void big_int_rem_eq(BigInt *dst, BigInt const *x);
gb_internal void big_int_quo_eq(BigInt *dst, BigInt const *x);
gb_internal void big_int_rem_eq(BigInt *dst, BigInt const *x);
bool big_int_is_neg(BigInt const *x);
void big_int_neg(BigInt *dst, BigInt const *x);
gb_internal bool big_int_is_neg(BigInt const *x);
gb_internal void big_int_neg(BigInt *dst, BigInt const *x);
void big_int_add_eq(BigInt *dst, BigInt const *x) {
gb_internal void big_int_add_eq(BigInt *dst, BigInt const *x) {
BigInt res = {};
big_int_init(&res, dst);
big_int_add(dst, &res, x);
}
void big_int_sub_eq(BigInt *dst, BigInt const *x) {
gb_internal void big_int_sub_eq(BigInt *dst, BigInt const *x) {
BigInt res = {};
big_int_init(&res, dst);
big_int_sub(dst, &res, x);
}
void big_int_shl_eq(BigInt *dst, BigInt const *x) {
gb_internal void big_int_shl_eq(BigInt *dst, BigInt const *x) {
BigInt res = {};
big_int_init(&res, dst);
big_int_shl(dst, &res, x);
}
void big_int_shr_eq(BigInt *dst, BigInt const *x) {
gb_internal void big_int_shr_eq(BigInt *dst, BigInt const *x) {
BigInt res = {};
big_int_init(&res, dst);
big_int_shr(dst, &res, x);
}
void big_int_mul_eq(BigInt *dst, BigInt const *x) {
gb_internal void big_int_mul_eq(BigInt *dst, BigInt const *x) {
BigInt res = {};
big_int_init(&res, dst);
big_int_mul(dst, &res, x);
}
void big_int_quo_eq(BigInt *dst, BigInt const *x) {
gb_internal void big_int_quo_eq(BigInt *dst, BigInt const *x) {
BigInt res = {};
big_int_init(&res, dst);
big_int_quo(dst, &res, x);
}
void big_int_rem_eq(BigInt *dst, BigInt const *x) {
gb_internal void big_int_rem_eq(BigInt *dst, BigInt const *x) {
BigInt res = {};
big_int_init(&res, dst);
big_int_rem(dst, &res, x);
@@ -124,7 +124,7 @@ void big_int_rem_eq(BigInt *dst, BigInt const *x) {
i64 big_int_sign(BigInt const *x) {
gb_internal i64 big_int_sign(BigInt const *x) {
if (mp_iszero(x)) {
return 0;
}
@@ -132,44 +132,44 @@ i64 big_int_sign(BigInt const *x) {
}
void big_int_from_u64(BigInt *dst, u64 x) {
gb_internal void big_int_from_u64(BigInt *dst, u64 x) {
mp_init_u64(dst, x);
}
void big_int_from_i64(BigInt *dst, i64 x) {
gb_internal void big_int_from_i64(BigInt *dst, i64 x) {
mp_init_i64(dst, x);
}
void big_int_init(BigInt *dst, BigInt const *src) {
gb_internal void big_int_init(BigInt *dst, BigInt const *src) {
if (dst == src) {
return;
}
mp_init_copy(dst, src);
}
BigInt big_int_make(BigInt const *b, bool abs) {
gb_internal BigInt big_int_make(BigInt const *b, bool abs) {
BigInt i = {};
big_int_init(&i, b);
if (abs) mp_abs(&i, &i);
return i;
}
BigInt big_int_make_abs(BigInt const *b) {
gb_internal BigInt big_int_make_abs(BigInt const *b) {
return big_int_make(b, true);
}
BigInt big_int_make_u64(u64 x) {
gb_internal BigInt big_int_make_u64(u64 x) {
BigInt i = {};
big_int_from_u64(&i, x);
return i;
}
BigInt big_int_make_i64(i64 x) {
gb_internal BigInt big_int_make_i64(i64 x) {
BigInt i = {};
big_int_from_i64(&i, x);
return i;
}
void big_int_from_string(BigInt *dst, String const &s, bool *success) {
gb_internal void big_int_from_string(BigInt *dst, String const &s, bool *success) {
*success = true;
bool is_negative = false;
@@ -262,66 +262,66 @@ void big_int_from_string(BigInt *dst, String const &s, bool *success) {
u64 big_int_to_u64(BigInt const *x) {
gb_internal u64 big_int_to_u64(BigInt const *x) {
GB_ASSERT(x->sign == 0);
return mp_get_u64(x);
}
i64 big_int_to_i64(BigInt const *x) {
gb_internal i64 big_int_to_i64(BigInt const *x) {
return mp_get_i64(x);
}
f64 big_int_to_f64(BigInt const *x) {
gb_internal f64 big_int_to_f64(BigInt const *x) {
return mp_get_double(x);
}
void big_int_neg(BigInt *dst, BigInt const *x) {
gb_internal void big_int_neg(BigInt *dst, BigInt const *x) {
mp_neg(x, dst);
}
int big_int_cmp(BigInt const *x, BigInt const *y) {
gb_internal int big_int_cmp(BigInt const *x, BigInt const *y) {
return mp_cmp(x, y);
}
int big_int_cmp_zero(BigInt const *x) {
gb_internal int big_int_cmp_zero(BigInt const *x) {
if (mp_iszero(x)) {
return 0;
}
return x->sign ? -1 : +1;
}
bool big_int_is_zero(BigInt const *x) {
gb_internal bool big_int_is_zero(BigInt const *x) {
return mp_iszero(x);
}
void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
gb_internal void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
mp_add(x, y, dst);
}
void big_int_sub(BigInt *dst, BigInt const *x, BigInt const *y) {
gb_internal void big_int_sub(BigInt *dst, BigInt const *x, BigInt const *y) {
mp_sub(x, y, dst);
}
void big_int_shl(BigInt *dst, BigInt const *x, BigInt const *y) {
gb_internal void big_int_shl(BigInt *dst, BigInt const *x, BigInt const *y) {
u32 yy = mp_get_u32(y);
mp_mul_2d(x, yy, dst);
}
void big_int_shr(BigInt *dst, BigInt const *x, BigInt const *y) {
gb_internal void big_int_shr(BigInt *dst, BigInt const *x, BigInt const *y) {
u32 yy = mp_get_u32(y);
BigInt d = {};
mp_div_2d(x, yy, dst, &d);
big_int_dealloc(&d);
}
void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) {
gb_internal void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) {
BigInt d = {};
big_int_from_u64(&d, y);
mp_mul(x, &d, dst);
@@ -329,12 +329,12 @@ void big_int_mul_u64(BigInt *dst, BigInt const *x, u64 y) {
}
void big_int_mul(BigInt *dst, BigInt const *x, BigInt const *y) {
gb_internal void big_int_mul(BigInt *dst, BigInt const *x, BigInt const *y) {
mp_mul(x, y, dst);
}
u64 leading_zeros_u64(u64 x) {
gb_internal u64 leading_zeros_u64(u64 x) {
#if defined(GB_COMPILER_MSVC)
#if defined(GB_ARCH_64_BIT)
return __lzcnt64(x);
@@ -367,23 +367,23 @@ u64 leading_zeros_u64(u64 x) {
//
// q = x/y with the result truncated to zero
// r = x - y*q
void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q_, BigInt *r_) {
gb_internal void big_int_quo_rem(BigInt const *x, BigInt const *y, BigInt *q_, BigInt *r_) {
mp_div(x, y, q_, r_);
}
void big_int_quo(BigInt *z, BigInt const *x, BigInt const *y) {
gb_internal void big_int_quo(BigInt *z, BigInt const *x, BigInt const *y) {
BigInt r = {};
big_int_quo_rem(x, y, z, &r);
big_int_dealloc(&r);
}
void big_int_rem(BigInt *z, BigInt const *x, BigInt const *y) {
gb_internal void big_int_rem(BigInt *z, BigInt const *x, BigInt const *y) {
BigInt q = {};
big_int_quo_rem(x, y, &q, z);
big_int_dealloc(&q);
}
void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y) {
gb_internal void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y) {
BigInt y0 = {};
big_int_init(&y0, y);
@@ -400,11 +400,11 @@ void big_int_euclidean_mod(BigInt *z, BigInt const *x, BigInt const *y) {
void big_int_and(BigInt *dst, BigInt const *x, BigInt const *y) {
gb_internal void big_int_and(BigInt *dst, BigInt const *x, BigInt const *y) {
mp_and(x, y, dst);
}
void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y) {
gb_internal void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y) {
if (mp_iszero(x)) {
big_int_init(dst, y);
return;
@@ -467,22 +467,23 @@ void big_int_and_not(BigInt *dst, BigInt const *x, BigInt const *y) {
return;
}
void big_int_xor(BigInt *dst, BigInt const *x, BigInt const *y) {
gb_internal void big_int_xor(BigInt *dst, BigInt const *x, BigInt const *y) {
mp_xor(x, y, dst);
}
void big_int_or(BigInt *dst, BigInt const *x, BigInt const *y) {
gb_internal void big_int_or(BigInt *dst, BigInt const *x, BigInt const *y) {
mp_or(x, y, dst);
}
void debug_print_big_int(BigInt const *x) {
gb_internal void debug_print_big_int(BigInt const *x) {
TEMPORARY_ALLOCATOR_GUARD();
String s = big_int_to_string(temporary_allocator(), x, 10);
gb_printf_err("[DEBUG] %.*s\n", LIT(s));
}
void big_int_not(BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed) {
gb_internal void big_int_not(BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed) {
GB_ASSERT(bit_count >= 0);
if (bit_count == 0) {
big_int_from_u64(dst, 0);
@@ -530,7 +531,7 @@ void big_int_not(BigInt *dst, BigInt const *x, i32 bit_count, bool is_signed) {
big_int_dealloc(&v);
}
bool big_int_is_neg(BigInt const *x) {
gb_internal bool big_int_is_neg(BigInt const *x) {
if (x == nullptr) {
return false;
}
@@ -538,7 +539,7 @@ bool big_int_is_neg(BigInt const *x) {
}
char digit_to_char(u8 digit) {
gb_internal char digit_to_char(u8 digit) {
GB_ASSERT(digit < 16);
if (digit <= 9) {
return digit + '0';
@@ -548,7 +549,7 @@ char digit_to_char(u8 digit) {
return '0';
}
String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
gb_internal String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
GB_ASSERT(base <= 16);
if (mp_iszero(x)) {
@@ -560,40 +561,63 @@ String big_int_to_string(gbAllocator allocator, BigInt const *x, u64 base) {
Array<char> buf = {};
array_init(&buf, allocator, 0, 32);
BigInt v = {};
mp_init_copy(&v, x);
if (x->used >= 498) { // 2^498 ~ 10^150
mp_int val = {};
mp_abs(x, &val);
int exp = 0;
mp_err err = mp_log_n(&val, 10, &exp);
GB_ASSERT(err == MP_OKAY);
GB_ASSERT(exp >= 100);
if (v.sign) {
array_add(&buf, '-');
mp_abs(&v, &v);
}
mp_int thousand_below = {};
mp_int thousand_above = {};
mp_init_i32(&thousand_below, 10);
isize first_word_idx = buf.count;
mp_expt_n(&thousand_below, exp-3, &thousand_below);
mp_div(&val, &thousand_below, &thousand_above, nullptr);
BigInt r = {};
BigInt b = {};
big_int_from_u64(&b, base);
double mant = 1.0e-3 * mp_get_double(&thousand_above);
u8 digit = 0;
while (big_int_cmp(&v, &b) >= 0) {
big_int_quo_rem(&v, &b, &v, &r);
char val_buf[256] = {};
isize n = gb_snprintf(val_buf, gb_size_of(val_buf)-1, "~ %s%.fe%u", (x->sign ? "-" : ""), mant, exp);
array_add_elems(&buf, val_buf, n-1);
} else {
BigInt v = {};
mp_init_copy(&v, x);
if (v.sign) {
array_add(&buf, '-');
mp_abs(&v, &v);
}
isize first_word_idx = buf.count;
BigInt r = {};
BigInt b = {};
big_int_from_u64(&b, base);
u8 digit = 0;
while (big_int_cmp(&v, &b) >= 0) {
big_int_quo_rem(&v, &b, &v, &r);
digit = cast(u8)big_int_to_u64(&r);
array_add(&buf, digit_to_char(digit));
}
big_int_rem(&r, &v, &b);
digit = cast(u8)big_int_to_u64(&r);
array_add(&buf, digit_to_char(digit));
big_int_dealloc(&r);
big_int_dealloc(&b);
for (isize i = first_word_idx; i < buf.count/2; i++) {
isize j = buf.count + first_word_idx - i - 1;
char tmp = buf[i];
buf[i] = buf[j];
buf[j] = tmp;
}
}
big_int_rem(&r, &v, &b);
digit = cast(u8)big_int_to_u64(&r);
array_add(&buf, digit_to_char(digit));
big_int_dealloc(&r);
big_int_dealloc(&b);
for (isize i = first_word_idx; i < buf.count/2; i++) {
isize j = buf.count + first_word_idx - i - 1;
char tmp = buf[i];
buf[i] = buf[j];
buf[j] = tmp;
}
return make_string(cast(u8 *)buf.data, buf.count);
}
+6 -6
View File
@@ -30,7 +30,7 @@
NOTE(Jeroen): This prints the Windows product edition only, to be called from `print_platform_details`.
*/
#if defined(GB_SYSTEM_WINDOWS)
void report_windows_product_type(DWORD ProductType) {
gb_internal void report_windows_product_type(DWORD ProductType) {
switch (ProductType) {
case PRODUCT_ULTIMATE:
gb_printf("Ultimate");
@@ -154,7 +154,7 @@ void report_windows_product_type(DWORD ProductType) {
}
#endif
void odin_cpuid(int leaf, int result[]) {
gb_internal void odin_cpuid(int leaf, int result[]) {
#if defined(GB_CPU_ARM)
return;
@@ -169,7 +169,7 @@ void odin_cpuid(int leaf, int result[]) {
#endif
}
void report_cpu_info() {
gb_internal void report_cpu_info() {
gb_printf("\tCPU: ");
#if defined(GB_CPU_X86)
@@ -220,7 +220,7 @@ void report_cpu_info() {
/*
Report the amount of installed RAM.
*/
void report_ram_info() {
gb_internal void report_ram_info() {
gb_printf("\tRAM: ");
#if defined(GB_SYSTEM_WINDOWS)
@@ -271,7 +271,7 @@ void report_ram_info() {
#endif
}
void report_os_info() {
gb_internal void report_os_info() {
gb_printf("\tOS: ");
#if defined(GB_SYSTEM_WINDOWS)
@@ -966,7 +966,7 @@ void report_os_info() {
}
// NOTE(Jeroen): `odin report` prints some system information for easier bug reporting.
void print_bug_report_help() {
gb_internal void print_bug_report_help() {
gb_printf("Where to find more information and get into contact when you encounter a bug:\n\n");
gb_printf("\tWebsite: https://odin-lang.org\n");
gb_printf("\tGitHub: https://github.com/odin-lang/Odin/issues\n");
+99 -68
View File
@@ -57,7 +57,7 @@ enum TargetABIKind : u16 {
};
String target_os_names[TargetOs_COUNT] = {
gb_global String target_os_names[TargetOs_COUNT] = {
str_lit(""),
str_lit("windows"),
str_lit("darwin"),
@@ -72,7 +72,7 @@ String target_os_names[TargetOs_COUNT] = {
str_lit("freestanding"),
};
String target_arch_names[TargetArch_COUNT] = {
gb_global String target_arch_names[TargetArch_COUNT] = {
str_lit(""),
str_lit("amd64"),
str_lit("i386"),
@@ -82,19 +82,19 @@ String target_arch_names[TargetArch_COUNT] = {
str_lit("wasm64"),
};
String target_endian_names[TargetEndian_COUNT] = {
gb_global String target_endian_names[TargetEndian_COUNT] = {
str_lit(""),
str_lit("little"),
str_lit("big"),
};
String target_abi_names[TargetABI_COUNT] = {
gb_global String target_abi_names[TargetABI_COUNT] = {
str_lit(""),
str_lit("win64"),
str_lit("sysv"),
};
TargetEndianKind target_endians[TargetArch_COUNT] = {
gb_global TargetEndianKind target_endians[TargetArch_COUNT] = {
TargetEndian_Invalid,
TargetEndian_Little,
TargetEndian_Little,
@@ -107,7 +107,7 @@ TargetEndianKind target_endians[TargetArch_COUNT] = {
#define ODIN_VERSION_RAW "dev-unknown-unknown"
#endif
String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW);
gb_global String const ODIN_VERSION = str_lit(ODIN_VERSION_RAW);
@@ -149,7 +149,6 @@ enum CommandKind : u32 {
Command_run = 1<<0,
Command_build = 1<<1,
Command_check = 1<<3,
Command_query = 1<<4,
Command_doc = 1<<5,
Command_version = 1<<6,
Command_test = 1<<7,
@@ -157,16 +156,15 @@ enum CommandKind : u32 {
Command_strip_semicolon = 1<<8,
Command_bug_report = 1<<9,
Command__does_check = Command_run|Command_build|Command_check|Command_query|Command_doc|Command_test|Command_strip_semicolon,
Command__does_check = Command_run|Command_build|Command_check|Command_doc|Command_test|Command_strip_semicolon,
Command__does_build = Command_run|Command_build|Command_test,
Command_all = ~(u32)0,
};
char const *odin_command_strings[32] = {
gb_global char const *odin_command_strings[32] = {
"run",
"build",
"check",
"query",
"doc",
"version",
"test",
@@ -293,13 +291,14 @@ struct BuildContext {
bool show_error_line;
bool ignore_lazy;
bool ignore_llvm_build;
bool use_subsystem_windows;
bool ignore_microsoft_magic;
bool linker_map_file;
bool use_separate_modules;
bool threaded_checker;
bool no_threaded_checker;
bool show_debug_messages;
@@ -316,8 +315,6 @@ struct BuildContext {
u32 cmd_doc_flags;
Array<String> extra_packages;
QueryDataSetSettings query_data_set_settings;
StringSet test_names;
gbAffinity affinity;
@@ -333,10 +330,15 @@ struct BuildContext {
gb_global BuildContext build_context = {0};
bool global_warnings_as_errors(void) {
gb_internal bool IS_ODIN_DEBUG(void) {
return build_context.ODIN_DEBUG;
}
gb_internal bool global_warnings_as_errors(void) {
return build_context.warnings_as_errors;
}
bool global_ignore_warnings(void) {
gb_internal bool global_ignore_warnings(void) {
return build_context.ignore_warnings;
}
@@ -398,7 +400,7 @@ gb_global TargetMetrics target_darwin_arm64 = {
TargetArch_arm64,
8, 8, 16,
str_lit("arm64-apple-macosx11.0.0"),
str_lit("e-m:o-i64:64-i128:128-n32:64-S128"), // TODO(bill): Is this correct?
str_lit("e-m:o-i64:64-i128:128-n32:64-S128"),
};
gb_global TargetMetrics target_freebsd_i386 = {
@@ -502,9 +504,9 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
};
NamedTargetMetrics *selected_target_metrics;
gb_global NamedTargetMetrics *selected_target_metrics;
TargetOsKind get_target_os_from_string(String str) {
gb_internal TargetOsKind get_target_os_from_string(String str) {
for (isize i = 0; i < TargetOs_COUNT; i++) {
if (str_eq_ignore_case(target_os_names[i], str)) {
return cast(TargetOsKind)i;
@@ -513,7 +515,7 @@ TargetOsKind get_target_os_from_string(String str) {
return TargetOs_Invalid;
}
TargetArchKind get_target_arch_from_string(String str) {
gb_internal TargetArchKind get_target_arch_from_string(String str) {
for (isize i = 0; i < TargetArch_COUNT; i++) {
if (str_eq_ignore_case(target_arch_names[i], str)) {
return cast(TargetArchKind)i;
@@ -523,7 +525,7 @@ TargetArchKind get_target_arch_from_string(String str) {
}
bool is_excluded_target_filename(String name) {
gb_internal bool is_excluded_target_filename(String name) {
String original_name = name;
name = remove_extension_from_path(name);
@@ -588,23 +590,22 @@ struct LibraryCollections {
gb_global Array<LibraryCollections> library_collections = {0};
void add_library_collection(String name, String path) {
// TODO(bill): Check the path is valid and a directory
gb_internal void add_library_collection(String name, String path) {
LibraryCollections lc = {name, string_trim_whitespace(path)};
array_add(&library_collections, lc);
}
bool find_library_collection_path(String name, String *path) {
for_array(i, library_collections) {
if (library_collections[i].name == name) {
if (path) *path = library_collections[i].path;
gb_internal bool find_library_collection_path(String name, String *path) {
for (auto const &lc : library_collections) {
if (lc.name == name) {
if (path) *path = lc.path;
return true;
}
}
return false;
}
bool is_arch_wasm(void) {
gb_internal bool is_arch_wasm(void) {
switch (build_context.metrics.arch) {
case TargetArch_wasm32:
case TargetArch_wasm64:
@@ -613,7 +614,7 @@ bool is_arch_wasm(void) {
return false;
}
bool is_arch_x86(void) {
gb_internal bool is_arch_x86(void) {
switch (build_context.metrics.arch) {
case TargetArch_i386:
case TargetArch_amd64:
@@ -622,7 +623,7 @@ bool is_arch_x86(void) {
return false;
}
bool allow_check_foreign_filepath(void) {
gb_internal bool allow_check_foreign_filepath(void) {
switch (build_context.metrics.arch) {
case TargetArch_wasm32:
case TargetArch_wasm64:
@@ -638,13 +639,14 @@ bool allow_check_foreign_filepath(void) {
// is_abs_path
// has_subdir
String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
gb_global String const WIN32_SEPARATOR_STRING = {cast(u8 *)"\\", 1};
gb_global String const NIX_SEPARATOR_STRING = {cast(u8 *)"/", 1};
String const WASM_MODULE_NAME_SEPARATOR = str_lit("..");
gb_global String const WASM_MODULE_NAME_SEPARATOR = str_lit("..");
String internal_odin_root_dir(void);
String odin_root_dir(void) {
gb_internal String internal_odin_root_dir(void);
gb_internal String odin_root_dir(void) {
if (global_module_path_set) {
return global_module_path;
}
@@ -670,7 +672,7 @@ String odin_root_dir(void) {
#if defined(GB_SYSTEM_WINDOWS)
String internal_odin_root_dir(void) {
gb_internal String internal_odin_root_dir(void) {
String path = global_module_path;
isize len, i;
wchar_t *text;
@@ -723,9 +725,9 @@ String internal_odin_root_dir(void) {
#include <mach-o/dyld.h>
String path_to_fullpath(gbAllocator a, String s);
gb_internal String path_to_fullpath(gbAllocator a, String s);
String internal_odin_root_dir(void) {
gb_internal String internal_odin_root_dir(void) {
String path = global_module_path;
isize len, i;
u8 *text;
@@ -777,9 +779,9 @@ String internal_odin_root_dir(void) {
// NOTE: Linux / Unix is unfinished and not tested very well.
#include <sys/stat.h>
String path_to_fullpath(gbAllocator a, String s);
gb_internal String path_to_fullpath(gbAllocator a, String s);
String internal_odin_root_dir(void) {
gb_internal String internal_odin_root_dir(void) {
String path = global_module_path;
isize len, i;
u8 *text;
@@ -938,18 +940,22 @@ String internal_odin_root_dir(void) {
gb_global BlockingMutex fullpath_mutex;
#if defined(GB_SYSTEM_WINDOWS)
String path_to_fullpath(gbAllocator a, String s) {
gb_internal String path_to_fullpath(gbAllocator a, String s) {
String result = {};
mutex_lock(&fullpath_mutex);
defer (mutex_unlock(&fullpath_mutex));
String16 string16 = string_to_string16(heap_allocator(), s);
defer (gb_free(heap_allocator(), string16.text));
DWORD len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
DWORD len;
mutex_lock(&fullpath_mutex);
len = GetFullPathNameW(&string16[0], 0, nullptr, nullptr);
if (len != 0) {
wchar_t *text = gb_alloc_array(permanent_allocator(), wchar_t, len+1);
GetFullPathNameW(&string16[0], len, text, nullptr);
mutex_unlock(&fullpath_mutex);
text[len] = 0;
result = string16_to_string(a, make_string16(text, len));
result = string_trim_whitespace(result);
@@ -960,12 +966,14 @@ String path_to_fullpath(gbAllocator a, String s) {
result.text[i] = '/';
}
}
} else {
mutex_unlock(&fullpath_mutex);
}
return result;
}
#elif defined(GB_SYSTEM_OSX) || defined(GB_SYSTEM_UNIX)
String path_to_fullpath(gbAllocator a, String s) {
gb_internal String path_to_fullpath(gbAllocator a, String s) {
char *p;
mutex_lock(&fullpath_mutex);
p = realpath(cast(char *)s.text, 0);
@@ -978,7 +986,7 @@ String path_to_fullpath(gbAllocator a, String s) {
#endif
String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
gb_internal String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
u8 *str = gb_alloc_array(heap_allocator(), u8, base_dir.len+1+path.len+1);
defer (gb_free(heap_allocator(), str));
@@ -1004,7 +1012,7 @@ String get_fullpath_relative(gbAllocator a, String base_dir, String path) {
}
String get_fullpath_core(gbAllocator a, String path) {
gb_internal String get_fullpath_core(gbAllocator a, String path) {
String module_dir = odin_root_dir();
String core = str_lit("core/");
@@ -1024,11 +1032,11 @@ String get_fullpath_core(gbAllocator a, String path) {
return path_to_fullpath(a, res);
}
bool show_error_line(void) {
gb_internal bool show_error_line(void) {
return build_context.show_error_line;
}
bool has_asm_extension(String const &path) {
gb_internal bool has_asm_extension(String const &path) {
String ext = path_extension(path);
if (ext == ".asm") {
return true;
@@ -1041,7 +1049,7 @@ bool has_asm_extension(String const &path) {
}
// temporary
char *token_pos_to_string(TokenPos const &pos) {
gb_internal char *token_pos_to_string(TokenPos const &pos) {
gbString s = gb_string_make_reserve(temporary_allocator(), 128);
String file = get_file_path_string(pos.file_id);
switch (build_context.ODIN_ERROR_POS_STYLE) {
@@ -1056,7 +1064,7 @@ char *token_pos_to_string(TokenPos const &pos) {
return s;
}
void init_build_context(TargetMetrics *cross_target) {
gb_internal void init_build_context(TargetMetrics *cross_target) {
BuildContext *bc = &build_context;
gb_affinity_init(&bc->affinity);
@@ -1245,7 +1253,14 @@ void init_build_context(TargetMetrics *cross_target) {
bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
bc->ODIN_VALGRIND_SUPPORT = is_arch_x86() && build_context.metrics.os != TargetOs_windows;
bc->ODIN_VALGRIND_SUPPORT = false;
if (build_context.metrics.os != TargetOs_windows) {
switch (bc->metrics.arch) {
case TargetArch_amd64:
bc->ODIN_VALGRIND_SUPPORT = true;
break;
}
}
#undef LINK_FLAG_X64
#undef LINK_FLAG_386
@@ -1258,7 +1273,7 @@ void init_build_context(TargetMetrics *cross_target) {
#endif
Array<String> split_by_comma(String const &list) {
gb_internal Array<String> split_by_comma(String const &list) {
isize n = 1;
for (isize i = 0; i < list.len; i++) {
if (list.text[i] == ',') {
@@ -1280,20 +1295,19 @@ Array<String> split_by_comma(String const &list) {
return res;
}
bool check_target_feature_is_valid(TokenPos pos, String const &feature) {
gb_internal bool check_target_feature_is_valid(TokenPos pos, String const &feature) {
// TODO(bill): check_target_feature_is_valid
return true;
}
bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_list) {
gb_internal bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_list) {
BuildContext *bc = &build_context;
mutex_lock(&bc->target_features_mutex);
defer (mutex_unlock(&bc->target_features_mutex));
auto items = split_by_comma(target_feature_list);
array_free(&items);
for_array(i, items) {
String const &item = items.data[i];
for (String const &item : items) {
if (!check_target_feature_is_valid(pos, item)) {
error(pos, "Target feature '%.*s' is not valid", LIT(item));
return false;
@@ -1307,14 +1321,13 @@ bool check_target_feature_is_enabled(TokenPos pos, String const &target_feature_
return true;
}
void enable_target_feature(TokenPos pos, String const &target_feature_list) {
gb_internal void enable_target_feature(TokenPos pos, String const &target_feature_list) {
BuildContext *bc = &build_context;
mutex_lock(&bc->target_features_mutex);
defer (mutex_unlock(&bc->target_features_mutex));
auto items = split_by_comma(target_feature_list);
for_array(i, items) {
String const &item = items.data[i];
for (String const &item : items) {
if (!check_target_feature_is_valid(pos, item)) {
error(pos, "Target feature '%.*s' is not valid", LIT(item));
continue;
@@ -1326,25 +1339,26 @@ void enable_target_feature(TokenPos pos, String const &target_feature_list) {
}
char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes) {
gb_internal char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quotes) {
isize len = 0;
for_array(i, build_context.target_features_set.entries) {
isize i = 0;
for (String const &feature : build_context.target_features_set) {
if (i != 0) {
len += 1;
}
String feature = build_context.target_features_set.entries[i].value;
len += feature.len;
if (with_quotes) len += 2;
i += 1;
}
char *features = gb_alloc_array(allocator, char, len+1);
len = 0;
for_array(i, build_context.target_features_set.entries) {
i = 0;
for (String const &feature : build_context.target_features_set) {
if (i != 0) {
features[len++] = ',';
}
if (with_quotes) features[len++] = '"';
String feature = build_context.target_features_set.entries[i].value;
gb_memmove(features + len, feature.text, feature.len);
len += feature.len;
if (with_quotes) features[len++] = '"';
@@ -1356,15 +1370,14 @@ char const *target_features_set_to_cstring(gbAllocator allocator, bool with_quot
// NOTE(Jeroen): Set/create the output and other paths and report an error as appropriate.
// We've previously called `parse_build_flags`, so `out_filepath` should be set.
bool init_build_paths(String init_filename) {
gb_internal bool init_build_paths(String init_filename) {
gbAllocator ha = heap_allocator();
BuildContext *bc = &build_context;
// NOTE(Jeroen): We're pre-allocating BuildPathCOUNT slots so that certain paths are always at the same enumerated index.
array_init(&bc->build_paths, permanent_allocator(), BuildPathCOUNT);
string_set_init(&bc->target_features_set, heap_allocator(), 1024);
mutex_init(&bc->target_features_mutex);
string_set_init(&bc->target_features_set, 1024);
// [BuildPathMainPackage] Turn given init path into a `Path`, which includes normalizing it into a full path.
bc->build_paths[BuildPath_Main_Package] = path_from_string(ha, init_filename);
@@ -1408,7 +1421,6 @@ bool init_build_paths(String init_filename) {
if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) {
// NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.
Find_Result find_result = find_visual_studio_and_windows_sdk();
defer (mc_free_all());
if (find_result.windows_sdk_version == 0) {
gb_printf_err("Windows SDK not found.\n");
@@ -1533,6 +1545,25 @@ bool init_build_paths(String init_filename) {
output_name = remove_extension_from_path(output_name);
output_name = copy_string(ha, string_trim_whitespace(output_name));
output_path = path_from_string(ha, output_name);
// Note(Dragos): This is a fix for empty filenames
// Turn the trailing folder into the file name
if (output_path.name.len == 0) {
isize len = output_path.basename.len;
while (len > 1 && output_path.basename[len - 1] != '/') {
len -= 1;
}
// We reached the slash
String old_basename = output_path.basename;
output_path.basename.len = len - 1; // Remove the slash
output_path.name = substring(old_basename, len, old_basename.len);
output_path.basename = copy_string(ha, output_path.basename);
output_path.name = copy_string(ha, output_path.name);
// The old basename is wrong. Delete it
gb_free(ha, old_basename.text);
}
// Replace extension.
if (output_path.ext.len > 0) {
+67 -43
View File
@@ -1,6 +1,6 @@
typedef bool (BuiltinTypeIsProc)(Type *t);
BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - BuiltinProc__type_simple_boolean_begin] = {
gb_global BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end - BuiltinProc__type_simple_boolean_begin] = {
nullptr, // BuiltinProc__type_simple_boolean_begin
is_type_boolean,
@@ -51,7 +51,7 @@ BuiltinTypeIsProc *builtin_type_is_procs[BuiltinProc__type_simple_boolean_end -
};
void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type) {
gb_internal void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name, Type *right_type) {
if (right_type == nullptr) {
return;
}
@@ -62,7 +62,7 @@ void check_or_else_right_type(CheckerContext *c, Ast *expr, String const &name,
}
}
void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
gb_internal void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
Type *left_type = nullptr;
Type *right_type = nullptr;
if (x->type->kind == Type_Tuple) {
@@ -88,8 +88,7 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name
}
void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
// TODO(bill): better error message
gb_internal void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint) {
gbString t = type_to_string(x.type);
error(x.expr, "'%.*s' does not return a value, value is of type %s", LIT(name), t);
if (is_type_union(type_deref(x.type))) {
@@ -97,8 +96,7 @@ void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Op
gbString th = nullptr;
if (type_hint != nullptr) {
GB_ASSERT(bsrc->kind == Type_Union);
for_array(i, bsrc->Union.variants) {
Type *vt = bsrc->Union.variants[i];
for (Type *vt : bsrc->Union.variants) {
if (are_types_identical(vt, type_hint)) {
th = type_to_string(type_hint);
break;
@@ -118,7 +116,7 @@ void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Op
}
void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
gb_internal void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_) {
Type *left_type = nullptr;
Type *right_type = nullptr;
if (x->type->kind == Type_Tuple) {
@@ -144,7 +142,7 @@ void check_or_return_split_types(CheckerContext *c, Operand *x, String const &na
}
bool does_require_msgSend_stret(Type *return_type) {
gb_internal bool does_require_msgSend_stret(Type *return_type) {
if (return_type == nullptr) {
return false;
}
@@ -165,7 +163,7 @@ bool does_require_msgSend_stret(Type *return_type) {
return false;
}
ObjcMsgKind get_objc_proc_kind(Type *return_type) {
gb_internal ObjcMsgKind get_objc_proc_kind(Type *return_type) {
if (return_type == nullptr) {
return ObjcMsg_normal;
}
@@ -189,7 +187,7 @@ ObjcMsgKind get_objc_proc_kind(Type *return_type) {
return ObjcMsg_normal;
}
void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<Type *> param_types) {
gb_internal void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<Type *> param_types) {
ObjcMsgKind kind = get_objc_proc_kind(return_type);
Scope *scope = create_scope(c->info, nullptr);
@@ -199,8 +197,7 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<T
{
auto variables = array_make<Entity *>(permanent_allocator(), 0, param_types.count);
for_array(i, param_types) {
Type *type = param_types[i];
for (Type *type : param_types) {
Entity *param = alloc_entity_param(scope, blank_token, type, false, true);
array_add(&variables, param);
}
@@ -230,7 +227,7 @@ void add_objc_proc_type(CheckerContext *c, Ast *call, Type *return_type, Slice<T
try_to_add_package_dependency(c, "runtime", "objc_msgSend_stret");
}
bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) {
gb_internal bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr, String *name_) {
Operand op = {};
check_expr(c, &op, expr);
if (op.mode == Addressing_Constant && op.value.kind == ExactValue_String) {
@@ -245,7 +242,7 @@ bool is_constant_string(CheckerContext *c, String const &builtin_name, Ast *expr
return false;
}
bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
gb_internal bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
String const &builtin_name = builtin_procs[id].name;
if (build_context.metrics.os != TargetOs_darwin) {
@@ -387,7 +384,7 @@ bool check_builtin_objc_procedure(CheckerContext *c, Operand *operand, Ast *call
}
}
bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String const &builtin_name, OdinAtomicMemoryOrder *memory_order_, char const *extra_message = nullptr) {
gb_internal bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String const &builtin_name, OdinAtomicMemoryOrder *memory_order_, char const *extra_message = nullptr) {
Operand x = {};
check_expr_with_type_hint(c, &x, expr, t_atomic_memory_order);
if (x.mode == Addressing_Invalid) {
@@ -417,7 +414,7 @@ bool check_atomic_memory_order_argument(CheckerContext *c, Ast *expr, String con
}
bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
gb_internal bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
ast_node(ce, CallExpr, call);
String const &builtin_name = builtin_procs[id].name;
@@ -1081,7 +1078,7 @@ bool check_builtin_simd_operation(CheckerContext *c, Operand *operand, Ast *call
return false;
}
bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) {
gb_internal bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &original_string, bool err_on_not_found, LoadFileCache **cache_) {
ast_node(ce, CallExpr, call);
ast_node(bd, BasicDirective, ce->proc);
String builtin_name = bd->name.string;
@@ -1111,7 +1108,7 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi
new_cache->path = path;
new_cache->data = data;
new_cache->file_error = file_error;
string_map_init(&new_cache->hashes, heap_allocator(), 32);
string_map_init(&new_cache->hashes, 32);
string_map_set(&c->info->load_file_cache, path, new_cache);
if (cache_) *cache_ = new_cache;
} else {
@@ -1121,8 +1118,8 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi
}
});
char *c_str = alloc_cstring(heap_allocator(), path);
defer (gb_free(heap_allocator(), c_str));
TEMPORARY_ALLOCATOR_GUARD();
char *c_str = alloc_cstring(temporary_allocator(), path);
gbFile f = {};
if (cache == nullptr) {
@@ -1170,7 +1167,7 @@ bool cache_load_file_directive(CheckerContext *c, Ast *call, String const &origi
}
bool is_valid_type_for_load(Type *type) {
gb_internal bool is_valid_type_for_load(Type *type) {
if (type == t_invalid) {
return false;
} else if (is_type_string(type)) {
@@ -1191,7 +1188,16 @@ bool is_valid_type_for_load(Type *type) {
return false;
}
LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) {
gb_internal bool check_atomic_ptr_argument(Operand *operand, String const &builtin_name, Type *elem) {
if (!is_type_valid_atomic_type(elem)) {
error(operand->expr, "Only an integer, floating-point, boolean, or pointer can be used as an atomic for '%.*s'", LIT(builtin_name));
return false;
}
return true;
}
gb_internal LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found) {
ast_node(ce, CallExpr, call);
ast_node(bd, BasicDirective, ce->proc);
String name = bd->name.string;
@@ -1256,7 +1262,7 @@ LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, As
}
bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) {
gb_internal bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint) {
ast_node(ce, CallExpr, call);
ast_node(bd, BasicDirective, ce->proc);
String name = bd->name.string;
@@ -1581,7 +1587,7 @@ bool check_builtin_procedure_directive(CheckerContext *c, Operand *operand, Ast
return true;
}
bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32 id, Type *type_hint) {
ast_node(ce, CallExpr, call);
if (ce->inlining != ProcInlining_none) {
error(call, "Inlining operators are not allowed on built-in procedures");
@@ -1690,7 +1696,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
case BuiltinProc___entry_point:
operand->mode = Addressing_NoValue;
operand->type = nullptr;
mpmc_enqueue(&c->info->intrinsics_entry_point_usage, call);
mpsc_enqueue(&c->info->intrinsics_entry_point_usage, call);
break;
case BuiltinProc_DIRECTIVE:
@@ -2559,7 +2565,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
if (is_type_struct(type)) {
isize variable_count = type->Struct.fields.count;
slice_init(&tuple->Tuple.variables, a, variable_count);
// TODO(bill): Should I copy each of the entities or is this good enough?
// NOTE(bill): don't copy the entities, this should be good enough
gb_memmove_array(tuple->Tuple.variables.data, type->Struct.fields.data, variable_count);
} else if (is_type_array(type)) {
isize variable_count = cast(isize)type->Array.count;
@@ -3066,14 +3072,14 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
case BuiltinProc_soa_zip: {
TEMPORARY_ALLOCATOR_GUARD();
auto types = array_make<Type *>(temporary_allocator(), 0, ce->args.count);
auto names = array_make<String>(temporary_allocator(), 0, ce->args.count);
bool first_is_field_value = (ce->args[0]->kind == Ast_FieldValue);
bool fail = false;
for_array(i, ce->args) {
Ast *arg = ce->args[i];
for (Ast *arg : ce->args) {
bool mix = false;
if (first_is_field_value) {
mix = arg->kind != Ast_FieldValue;
@@ -3087,11 +3093,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
}
StringSet name_set = {};
string_set_init(&name_set, heap_allocator(), 2*ce->args.count);
string_set_init(&name_set, 2*ce->args.count);
for_array(i, ce->args) {
for (Ast *arg : ce->args) {
String name = {};
Ast *arg = ce->args[i];
if (arg->kind == Ast_FieldValue) {
Ast *ename = arg->FieldValue.field;
if (!fail && ename->kind != Ast_Ident) {
@@ -3126,13 +3131,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
if (string_set_exists(&name_set, name)) {
if (string_set_update(&name_set, name)) {
error(op.expr, "Field argument name '%.*s' already exists", LIT(name));
} else {
array_add(&types, arg_type->Slice.elem);
array_add(&names, name);
string_set_add(&name_set, name);
}
}
@@ -3455,9 +3458,8 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
error(ce->args[0], "Expected a constant string for '%.*s'", LIT(builtin_name));
} else if (operand->value.kind == ExactValue_String) {
String pkg_name = operand->value.value_string;
// TODO(bill): probably should have this be a `StringMap` eventually
for_array(i, c->info->packages.entries) {
AstPackage *pkg = c->info->packages.entries[i].value;
for (auto const &entry : c->info->packages) {
AstPackage *pkg = entry.value;
if (pkg->name == pkg_name) {
value = true;
break;
@@ -3769,9 +3771,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
mp_err err = mp_pack(rop, max_count, &written, MP_LSB_FIRST, size, endian, nails, &x.value.value_integer);
GB_ASSERT(err == MP_OKAY);
if (id == BuiltinProc_reverse_bits) {
// TODO(bill): Should this even be allowed at compile time?
} else {
if (id != BuiltinProc_reverse_bits) {
u64 v = 0;
switch (id) {
case BuiltinProc_count_ones:
@@ -4255,6 +4255,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
return false;
}
if (id == BuiltinProc_atomic_store && !check_atomic_ptr_argument(operand, builtin_name, elem)) {
return false;
}
Operand x = {};
check_expr_with_type_hint(c, &x, ce->args[1], elem);
check_assignment(c, &x, elem, builtin_name);
@@ -4271,6 +4274,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
return false;
}
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
return false;
}
Operand x = {};
check_expr_with_type_hint(c, &x, ce->args[1], elem);
check_assignment(c, &x, elem, builtin_name);
@@ -4303,6 +4309,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
return false;
}
if (id == BuiltinProc_atomic_load && !check_atomic_ptr_argument(operand, builtin_name, elem)) {
return false;
}
operand->type = elem;
operand->mode = Addressing_Value;
break;
@@ -4315,6 +4325,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
return false;
}
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
return false;
}
OdinAtomicMemoryOrder memory_order = {};
if (!check_atomic_memory_order_argument(c, ce->args[1], builtin_name, &memory_order)) {
@@ -4346,6 +4359,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
return false;
}
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
return false;
}
Operand x = {};
check_expr_with_type_hint(c, &x, ce->args[1], elem);
check_assignment(c, &x, elem, builtin_name);
@@ -4383,6 +4399,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
return false;
}
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
return false;
}
Operand x = {};
check_expr_with_type_hint(c, &x, ce->args[1], elem);
check_assignment(c, &x, elem, builtin_name);
@@ -4421,6 +4440,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
return false;
}
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
return false;
}
Operand x = {};
Operand y = {};
check_expr_with_type_hint(c, &x, ce->args[1], elem);
@@ -4448,6 +4470,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
error(operand->expr, "Expected a pointer for '%.*s'", LIT(builtin_name));
return false;
}
if (!check_atomic_ptr_argument(operand, builtin_name, elem)) {
return false;
}
Operand x = {};
Operand y = {};
check_expr_with_type_hint(c, &x, ce->args[1], elem);
@@ -4993,8 +5018,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
bool is_variant = false;
for_array(i, u->Union.variants) {
Type *vt = u->Union.variants[i];
for (Type *vt : u->Union.variants) {
if (are_types_identical(v, vt)) {
is_variant = true;
break;
+93 -88
View File
@@ -1,7 +1,7 @@
void check_stmt (CheckerContext *ctx, Ast *node, u32 flags);
gb_internal void check_stmt(CheckerContext *ctx, Ast *node, u32 flags);
// NOTE(bill): 'content_name' is for debugging and error messages
Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, String context_name) {
gb_internal Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, String context_name) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
@@ -10,7 +10,6 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
gbString expr_str = expr_to_string(operand->expr);
// TODO(bill): is this a good enough error message?
// TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error(operand->expr,
"Cannot assign built-in procedure '%s' in %.*s",
expr_str,
@@ -46,7 +45,7 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
if (operand->mode == Addressing_Type) {
if (e->type != nullptr && is_type_typeid(e->type)) {
add_type_info_type(ctx, operand->type);
add_type_and_value(ctx->info, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
add_type_and_value(ctx, operand->expr, Addressing_Value, e->type, exact_value_typeid(operand->type));
return e->type;
} else {
gbString t = type_to_string(operand->type);
@@ -110,7 +109,7 @@ Type *check_init_variable(CheckerContext *ctx, Entity *e, Operand *operand, Stri
return e->type;
}
void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Slice<Ast *> const &inits, String context_name) {
gb_internal void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Slice<Ast *> const &inits, String context_name) {
if ((lhs == nullptr || lhs_count == 0) && inits.count == 0) {
return;
}
@@ -118,17 +117,11 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Sl
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
// an extra allocation
TEMPORARY_ALLOCATOR_GUARD();
auto operands = array_make<Operand>(temporary_allocator(), 0, 2*lhs_count);
check_unpack_arguments(ctx, lhs, lhs_count, &operands, inits, true, false);
isize rhs_count = operands.count;
for_array(i, operands) {
if (operands[i].mode == Addressing_Invalid) {
// TODO(bill): Should I ignore invalid parameters?
// rhs_count--;
}
}
isize max = gb_min(lhs_count, rhs_count);
for (isize i = 0; i < max; i++) {
Entity *e = lhs[i];
@@ -144,7 +137,7 @@ void check_init_variables(CheckerContext *ctx, Entity **lhs, isize lhs_count, Sl
}
}
void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
gb_internal void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
if (operand->mode == Addressing_Invalid ||
operand->type == t_invalid ||
e->type == t_invalid) {
@@ -184,7 +177,7 @@ void check_init_constant(CheckerContext *ctx, Entity *e, Operand *operand) {
}
bool is_type_distinct(Ast *node) {
gb_internal bool is_type_distinct(Ast *node) {
for (;;) {
if (node == nullptr) {
return false;
@@ -217,7 +210,7 @@ bool is_type_distinct(Ast *node) {
return false;
}
Ast *remove_type_alias_clutter(Ast *node) {
gb_internal Ast *remove_type_alias_clutter(Ast *node) {
for (;;) {
if (node == nullptr) {
return nullptr;
@@ -232,17 +225,7 @@ Ast *remove_type_alias_clutter(Ast *node) {
}
}
isize total_attribute_count(DeclInfo *decl) {
isize attribute_count = 0;
for_array(i, decl->attributes) {
Ast *attr = decl->attributes[i];
if (attr->kind != Ast_Attribute) continue;
attribute_count += attr->Attribute.elems.count;
}
return attribute_count;
}
Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named_type) {
gb_internal Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named_type) {
// NOTE(bill, 2022-02-05): Stupid edge case for `distinct` declarations
//
// X :: enum {A, B, C}
@@ -288,7 +271,7 @@ Type *clone_enum_type(CheckerContext *ctx, Type *original_enum_type, Type *named
return et;
}
void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
gb_internal void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def) {
GB_ASSERT(e->type == nullptr);
DeclInfo *decl = decl_info_of_entity(e);
@@ -372,8 +355,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
Type *t = base_type(e->type);
if (t->kind == Type_Enum) {
for_array(i, t->Enum.fields) {
Entity *f = t->Enum.fields[i];
for (Entity *f : t->Enum.fields) {
if (f->kind != Entity_Constant) {
continue;
}
@@ -390,7 +372,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
}
void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
gb_internal void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
// NOTE(bill): The original_entity's scope may not be same scope that it was inserted into
// e.g. file entity inserted into its package scope
String original_name = original_entity->token.string;
@@ -400,8 +382,8 @@ void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
if (found_scope == nullptr) {
return;
}
mutex_lock(&found_scope->mutex);
defer (mutex_unlock(&found_scope->mutex));
rw_mutex_lock(&found_scope->mutex);
defer (rw_mutex_unlock(&found_scope->mutex));
// IMPORTANT NOTE(bill, 2021-04-10): Overriding behaviour was flawed in that the
// original entity was still used check checked, but the checking was only
@@ -433,7 +415,7 @@ void override_entity_in_scope(Entity *original_entity, Entity *new_entity) {
void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) {
gb_internal void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init, Type *named_type) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Constant);
init = unparen_expr(init);
@@ -609,12 +591,12 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
typedef bool TypeCheckSig(Type *t);
bool sig_compare(TypeCheckSig *a, Type *x, Type *y) {
gb_internal bool sig_compare(TypeCheckSig *a, Type *x, Type *y) {
x = core_type(x);
y = core_type(y);
return (a(x) && a(y));
}
bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) {
gb_internal bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) {
x = core_type(x);
y = core_type(y);
if (a == b) {
@@ -623,7 +605,7 @@ bool sig_compare(TypeCheckSig *a, TypeCheckSig *b, Type *x, Type *y) {
return ((a(x) && b(y)) || (b(x) && a(y)));
}
bool signature_parameter_similar_enough(Type *x, Type *y) {
gb_internal bool signature_parameter_similar_enough(Type *x, Type *y) {
if (sig_compare(is_type_pointer, x, y)) {
return true;
}
@@ -674,7 +656,7 @@ bool signature_parameter_similar_enough(Type *x, Type *y) {
}
bool are_signatures_similar_enough(Type *a_, Type *b_) {
gb_internal bool are_signatures_similar_enough(Type *a_, Type *b_) {
GB_ASSERT(a_->kind == Type_Proc);
GB_ASSERT(b_->kind == Type_Proc);
TypeProc *a = &a_->Proc;
@@ -704,7 +686,7 @@ bool are_signatures_similar_enough(Type *a_, Type *b_) {
return true;
}
Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
gb_internal Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
Ast *ident = nullptr;
Entity **foreign_library = nullptr;
@@ -747,7 +729,7 @@ Entity *init_entity_foreign_library(CheckerContext *ctx, Entity *e) {
return nullptr;
}
String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix) {
gb_internal String handle_link_name(CheckerContext *ctx, Token token, String link_name, String link_prefix) {
if (link_prefix.len > 0) {
if (link_name.len > 0) {
error(token, "'link_name' and 'link_prefix' cannot be used together");
@@ -764,7 +746,7 @@ String handle_link_name(CheckerContext *ctx, Token token, String link_name, Stri
return link_name;
}
void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
gb_internal void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
GB_ASSERT(e->type == nullptr);
if (d->proc_lit->kind != Ast_ProcLit) {
// TOOD(bill): Better error message
@@ -1004,7 +986,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
GB_ASSERT(pl->body->kind == Ast_BlockStmt);
if (!pt->is_polymorphic) {
check_procedure_later(ctx, ctx->file, e->token, d, proc_type, pl->body, pl->tags);
check_procedure_later(ctx->checker, ctx->file, e->token, d, proc_type, pl->body, pl->tags);
}
} else if (!is_foreign) {
if (e->Procedure.is_export) {
@@ -1028,7 +1010,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
if (ac.deferred_procedure.entity != nullptr) {
e->Procedure.deferred_procedure = ac.deferred_procedure;
mpmc_enqueue(&ctx->checker->procs_with_deferred_to_check, e);
mpsc_enqueue(&ctx->checker->procs_with_deferred_to_check, e);
}
if (is_foreign) {
@@ -1121,7 +1103,7 @@ void check_proc_decl(CheckerContext *ctx, Entity *e, DeclInfo *d) {
}
}
void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) {
gb_internal void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr, Ast *init_expr) {
GB_ASSERT(e->type == nullptr);
GB_ASSERT(e->kind == Entity_Variable);
@@ -1142,7 +1124,7 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
if (ac.require_declaration) {
e->flags |= EntityFlag_Require;
mpmc_enqueue(&ctx->info->required_global_variable_queue, e);
mpsc_enqueue(&ctx->info->required_global_variable_queue, e);
}
@@ -1239,7 +1221,7 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed");
}
void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) {
gb_internal void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) {
GB_ASSERT(pg_entity->kind == Entity_ProcGroup);
auto *pge = &pg_entity->ProcGroup;
String proc_group_name = pg_entity->token.string;
@@ -1253,10 +1235,9 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d)
pg_entity->type = t_invalid;
PtrSet<Entity *> entity_set = {};
ptr_set_init(&entity_set, heap_allocator(), 2*pg->args.count);
ptr_set_init(&entity_set, 2*pg->args.count);
for_array(i, pg->args) {
Ast *arg = pg->args[i];
for (Ast *arg : pg->args) {
Entity *e = nullptr;
Operand o = {};
if (arg->kind == Ast_Ident) {
@@ -1289,7 +1270,7 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d)
ptr_set_destroy(&entity_set);
for_array(j, pge->entities) {
for (isize j = 0; j < pge->entities.count; j++) {
Entity *p = pge->entities[j];
if (p->type == t_invalid) {
// NOTE(bill): This invalid overload has already been handled
@@ -1367,7 +1348,7 @@ void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d)
}
void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_type) {
gb_internal void check_entity_decl(CheckerContext *ctx, Entity *e, DeclInfo *d, Type *named_type) {
if (e->state == EntityState_Resolved) {
return;
}
@@ -1431,15 +1412,46 @@ end:;
}
gb_internal void add_deps_from_child_to_parent(DeclInfo *decl) {
if (decl && decl->parent) {
Scope *ps = decl->parent->scope;
if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
return;
} else {
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
// But only at the procedure level
rw_mutex_shared_lock(&decl->deps_mutex);
rw_mutex_lock(&decl->parent->deps_mutex);
for (Entity *e : decl->deps) {
ptr_set_add(&decl->parent->deps, e);
}
rw_mutex_unlock(&decl->parent->deps_mutex);
rw_mutex_shared_unlock(&decl->deps_mutex);
rw_mutex_shared_lock(&decl->type_info_deps_mutex);
rw_mutex_lock(&decl->parent->type_info_deps_mutex);
for (Type *t : decl->type_info_deps) {
ptr_set_add(&decl->parent->type_info_deps, t);
}
rw_mutex_unlock(&decl->parent->type_info_deps_mutex);
rw_mutex_shared_unlock(&decl->type_info_deps_mutex);
}
}
}
struct ProcUsingVar {
Entity *e;
Entity *uvar;
};
void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
gb_internal bool check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *type, Ast *body) {
if (body == nullptr) {
return;
return false;
}
GB_ASSERT(body->kind == Ast_BlockStmt);
@@ -1480,8 +1492,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
{
if (type->Proc.param_count > 0) {
TypeTuple *params = &type->Proc.params->Tuple;
for_array(i, params->variables) {
Entity *e = params->variables[i];
for (Entity *e : params->variables) {
if (e->kind != Entity_Variable) {
continue;
}
@@ -1489,7 +1500,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
continue;
}
if (is_blank_ident(e->token)) {
error(e->token, "'using' a procedure parameter requires a non blank identifier");
error(e->token, "'using' a procedure parameter requires a non blank identifier");
break;
}
@@ -1499,8 +1510,9 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
if (t->kind == Type_Struct) {
Scope *scope = t->Struct.scope;
GB_ASSERT(scope != nullptr);
MUTEX_GUARD_BLOCK(scope->mutex) for_array(i, scope->elements.entries) {
Entity *f = scope->elements.entries[i].value;
rw_mutex_lock(&scope->mutex);
for (auto const &entry : scope->elements) {
Entity *f = entry.value;
if (f->kind == Entity_Variable) {
Entity *uvar = alloc_entity_using_variable(e, f->token, f->type, nullptr);
if (is_value) uvar->flags |= EntityFlag_Value;
@@ -1509,6 +1521,7 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
array_add(&using_entities, puv);
}
}
rw_mutex_unlock(&scope->mutex);
} else {
error(e->token, "'using' can only be applied to variables of type struct");
break;
@@ -1517,41 +1530,50 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
}
}
MUTEX_GUARD_BLOCK(ctx->scope->mutex) for_array(i, using_entities) {
Entity *e = using_entities[i].e;
Entity *uvar = using_entities[i].uvar;
Entity *prev = scope_insert(ctx->scope, uvar, false);
rw_mutex_lock(&ctx->scope->mutex);
for (auto const &entry : using_entities) {
Entity *e = entry.e;
Entity *uvar = entry.uvar;
Entity *prev = scope_insert_no_mutex(ctx->scope, uvar);
if (prev != nullptr) {
error(e->token, "Namespace collision while 'using' procedure argument '%.*s' of: %.*s", LIT(e->token.string), LIT(prev->token.string));
error_line("%.*s != %.*s\n", LIT(uvar->token.string), LIT(prev->token.string));
break;
}
}
rw_mutex_unlock(&ctx->scope->mutex);
bool where_clause_ok = evaluate_where_clauses(ctx, nullptr, decl->scope, &decl->proc_lit->ProcLit.where_clauses, !decl->where_clauses_evaluated);
if (!where_clause_ok) {
// NOTE(bill, 2019-08-31): Don't check the body as the where clauses failed
return;
return false;
}
check_open_scope(ctx, body);
{
for_array(i, using_entities) {
Entity *uvar = using_entities[i].uvar;
for (auto const &entry : using_entities) {
Entity *uvar = entry.uvar;
Entity *prev = scope_insert(ctx->scope, uvar);
gb_unused(prev);
// NOTE(bill): Don't err here
}
GB_ASSERT(decl->proc_checked_state != ProcCheckedState_Checked);
if (decl->defer_use_checked) {
GB_ASSERT(is_type_polymorphic(type, true));
error(token, "Defer Use Checked: %.*s", LIT(decl->entity->token.string));
GB_ASSERT(decl->defer_use_checked == false);
}
check_stmt_list(ctx, bs->stmts, Stmt_CheckScopeDecls);
for_array(i, bs->stmts) {
Ast *stmt = bs->stmts[i];
decl->defer_use_checked = true;
for (Ast *stmt : bs->stmts) {
if (stmt->kind == Ast_ValueDecl) {
ast_node(vd, ValueDecl, stmt);
for_array(j, vd->names) {
Ast *name = vd->names[j];
for (Ast *name : vd->names) {
if (!is_blank_ident(name)) {
if (name->kind == Ast_Ident) {
GB_ASSERT(name->Ident.entity != nullptr);
@@ -1580,30 +1602,13 @@ void check_proc_body(CheckerContext *ctx_, Token token, DeclInfo *decl, Type *ty
}
}
}
}
check_close_scope(ctx);
check_scope_usage(ctx->checker, ctx->scope);
if (decl->parent != nullptr) {
Scope *ps = decl->parent->scope;
if (ps->flags & (ScopeFlag_File & ScopeFlag_Pkg & ScopeFlag_Global)) {
return;
} else {
mutex_lock(&ctx->info->deps_mutex);
add_deps_from_child_to_parent(decl);
// NOTE(bill): Add the dependencies from the procedure literal (lambda)
// But only at the procedure level
for_array(i, decl->deps.entries) {
Entity *e = decl->deps.entries[i].ptr;
ptr_set_add(&decl->parent->deps, e);
}
for_array(i, decl->type_info_deps.entries) {
Type *t = decl->type_info_deps.entries[i].ptr;
ptr_set_add(&decl->parent->type_info_deps, t);
}
mutex_unlock(&ctx->info->deps_mutex);
}
}
return true;
}
+412 -410
View File
File diff suppressed because it is too large Load Diff
+875 -863
View File
File diff suppressed because it is too large Load Diff
+144 -132
View File
@@ -1,6 +1,6 @@
ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location);
gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location);
void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) {
gb_internal void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field, Type *t, String name, i32 idx) {
t = base_type(t);
GB_ASSERT(t->kind == Type_Array);
Entity *e = scope_lookup_current(ctx->scope, name);
@@ -27,7 +27,7 @@ void populate_using_array_index(CheckerContext *ctx, Ast *node, AstField *field,
}
}
void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) {
gb_internal void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field, Type *t) {
if (t == nullptr) {
return;
}
@@ -81,7 +81,7 @@ void populate_using_entity_scope(CheckerContext *ctx, Ast *node, AstField *field
}
}
bool does_field_type_allow_using(Type *t) {
gb_internal bool does_field_type_allow_using(Type *t) {
t = base_type(t);
if (is_type_struct(t)) {
return true;
@@ -91,8 +91,8 @@ bool does_field_type_allow_using(Type *t) {
return false;
}
void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields, String **tags, Slice<Ast *> const &params,
isize init_field_capacity, Type *struct_type, String context) {
gb_internal void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields, String **tags, Slice<Ast *> const &params,
isize init_field_capacity, Type *struct_type, String context) {
auto fields_array = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
auto tags_array = array_make<String>(heap_allocator(), 0, init_field_capacity);
@@ -219,7 +219,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Slice<Entity *> *fields
}
bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
gb_internal bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
GB_ASSERT(align_ != nullptr);
Operand o = {};
check_expr(ctx, &o, node);
@@ -256,71 +256,88 @@ bool check_custom_align(CheckerContext *ctx, Ast *node, i64 *align_) {
}
Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> const &ordered_operands, bool *failure) {
mutex_lock(&ctx->info->gen_types_mutex);
defer (mutex_unlock(&ctx->info->gen_types_mutex));
gb_internal Entity *find_polymorphic_record_entity(CheckerContext *ctx, Type *original_type, isize param_count, Array<Operand> const &ordered_operands, bool *failure) {
rw_mutex_shared_lock(&ctx->info->gen_types_mutex); // @@global
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
if (found_gen_types != nullptr) {
// GB_ASSERT_MSG(ordered_operands.count >= param_count, "%td >= %td", ordered_operands.count, param_count);
if (found_gen_types == nullptr) {
rw_mutex_shared_unlock(&ctx->info->gen_types_mutex); // @@global
return nullptr;
}
for_array(i, *found_gen_types) {
Entity *e = (*found_gen_types)[i];
Type *t = base_type(e->type);
TypeTuple *tuple = get_record_polymorphic_params(t);
GB_ASSERT(param_count == tuple->variables.count);
rw_mutex_shared_lock(&found_gen_types->mutex); // @@local
defer (rw_mutex_shared_unlock(&found_gen_types->mutex)); // @@local
bool skip = false;
rw_mutex_shared_unlock(&ctx->info->gen_types_mutex); // @@global
for (isize j = 0; j < param_count; j++) {
Entity *p = tuple->variables[j];
Operand o = {};
if (j < ordered_operands.count) {
o = ordered_operands[j];
}
if (o.expr == nullptr) {
continue;
}
Entity *oe = entity_of_node(o.expr);
if (p == oe) {
// NOTE(bill): This is the same type, make sure that it will be be same thing and use that
// Saves on a lot of checking too below
continue;
}
if (p->kind == Entity_TypeName) {
if (is_type_polymorphic(o.type)) {
// NOTE(bill): Do not add polymorphic version to the gen_types
skip = true;
break;
}
if (!are_types_identical(o.type, p->type)) {
skip = true;
break;
}
} else if (p->kind == Entity_Constant) {
if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) {
skip = true;
break;
}
if (!are_types_identical(o.type, p->type)) {
skip = true;
break;
}
} else {
GB_PANIC("Unknown entity kind");
}
for (Entity *e : found_gen_types->types) {
Type *t = base_type(e->type);
TypeTuple *tuple = nullptr;
switch (t->kind) {
case Type_Struct:
if (t->Struct.polymorphic_params) {
tuple = &t->Struct.polymorphic_params->Tuple;
}
if (!skip) {
return e;
break;
case Type_Union:
if (t->Union.polymorphic_params) {
tuple = &t->Union.polymorphic_params->Tuple;
}
break;
}
GB_ASSERT_MSG(tuple != nullptr, "%s :: %s", type_to_string(e->type), type_to_string(t));
GB_ASSERT(param_count == tuple->variables.count);
bool skip = false;
for (isize j = 0; j < param_count; j++) {
Entity *p = tuple->variables[j];
Operand o = {};
if (j < ordered_operands.count) {
o = ordered_operands[j];
}
if (o.expr == nullptr) {
continue;
}
Entity *oe = entity_of_node(o.expr);
if (p == oe) {
// NOTE(bill): This is the same type, make sure that it will be be same thing and use that
// Saves on a lot of checking too below
continue;
}
if (p->kind == Entity_TypeName) {
if (is_type_polymorphic(o.type)) {
// NOTE(bill): Do not add polymorphic version to the gen_types
skip = true;
break;
}
if (!are_types_identical(o.type, p->type)) {
skip = true;
break;
}
} else if (p->kind == Entity_Constant) {
if (!compare_exact_values(Token_CmpEq, o.value, p->Constant.value)) {
skip = true;
break;
}
if (!are_types_identical(o.type, p->type)) {
skip = true;
break;
}
} else {
GB_PANIC("Unknown entity kind");
}
}
if (!skip) {
return e;
}
}
return nullptr;
}
void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_type, Type *original_type) {
gb_internal void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_type, Type *original_type) {
GB_ASSERT(is_type_named(named_type));
gbAllocator a = heap_allocator();
Scope *s = ctx->scope->parent;
@@ -346,22 +363,24 @@ void add_polymorphic_record_entity(CheckerContext *ctx, Ast *node, Type *named_t
// TODO(bill): Is this even correct? Or should the metadata be copied?
e->TypeName.objc_metadata = original_type->Named.type_name->TypeName.objc_metadata;
mutex_lock(&ctx->info->gen_types_mutex);
rw_mutex_lock(&ctx->info->gen_types_mutex);
auto *found_gen_types = map_get(&ctx->info->gen_types, original_type);
if (found_gen_types) {
array_add(found_gen_types, e);
rw_mutex_lock(&found_gen_types->mutex);
array_add(&found_gen_types->types, e);
rw_mutex_unlock(&found_gen_types->mutex);
} else {
auto array = array_make<Entity *>(heap_allocator());
array_add(&array, e);
map_set(&ctx->info->gen_types, original_type, array);
GenTypesData gen_types = {};
gen_types.types = array_make<Entity *>(heap_allocator());
array_add(&gen_types.types, e);
map_set(&ctx->info->gen_types, original_type, gen_types);
}
mutex_unlock(&ctx->info->gen_types_mutex);
rw_mutex_unlock(&ctx->info->gen_types_mutex);
}
Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params,
bool *is_polymorphic_,
Ast *node, Array<Operand> *poly_operands,
Type *named_type, Type *original_type_for_poly) {
gb_internal Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_params,
bool *is_polymorphic_,
Ast *node, Array<Operand> *poly_operands) {
Type *polymorphic_params_type = nullptr;
bool can_check_fields = true;
GB_ASSERT(is_polymorphic_ != nullptr);
@@ -528,11 +547,6 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
}
}
if (original_type_for_poly != nullptr) {
GB_ASSERT(named_type != nullptr);
add_polymorphic_record_entity(ctx, node, named_type, original_type_for_poly);
}
if (!*is_polymorphic_) {
*is_polymorphic_ = polymorphic_params != nullptr && poly_operands == nullptr;
}
@@ -540,7 +554,7 @@ Type *check_record_polymorphic_params(CheckerContext *ctx, Ast *polymorphic_para
return polymorphic_params_type;
}
bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_type, Array<Operand> *poly_operands, bool *is_polymorphic_) {
gb_internal bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_type, Array<Operand> *poly_operands, bool *is_polymorphic_) {
if (poly_operands == nullptr) {
return false;
}
@@ -569,7 +583,7 @@ bool check_record_poly_operand_specialization(CheckerContext *ctx, Type *record_
}
void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
GB_ASSERT(is_type_struct(struct_type));
ast_node(st, StructType, node);
@@ -600,10 +614,13 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
struct_type->Struct.polymorphic_params = check_record_polymorphic_params(
ctx, st->polymorphic_params,
&struct_type->Struct.is_polymorphic,
node, poly_operands,
named_type, original_type_for_poly
);;
node, poly_operands
);
struct_type->Struct.is_poly_specialized = check_record_poly_operand_specialization(ctx, struct_type, poly_operands, &struct_type->Struct.is_polymorphic);
if (original_type_for_poly) {
GB_ASSERT(named_type != nullptr);
add_polymorphic_record_entity(ctx, node, named_type, original_type_for_poly);
}
if (!struct_type->Struct.is_polymorphic) {
if (st->where_clauses.count > 0 && st->polymorphic_params == nullptr) {
@@ -626,7 +643,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
}
}
}
void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
gb_internal void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Operand> *poly_operands, Type *named_type, Type *original_type_for_poly) {
GB_ASSERT(is_type_union(union_type));
ast_node(ut, UnionType, node);
@@ -635,10 +652,13 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
union_type->Union.polymorphic_params = check_record_polymorphic_params(
ctx, ut->polymorphic_params,
&union_type->Union.is_polymorphic,
node, poly_operands,
named_type, original_type_for_poly
node, poly_operands
);
union_type->Union.is_poly_specialized = check_record_poly_operand_specialization(ctx, union_type, poly_operands, &union_type->Union.is_polymorphic);
if (original_type_for_poly) {
GB_ASSERT(named_type != nullptr);
add_polymorphic_record_entity(ctx, node, named_type, original_type_for_poly);
}
if (!union_type->Union.is_polymorphic) {
if (ut->where_clauses.count > 0 && ut->polymorphic_params == nullptr) {
@@ -709,7 +729,7 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
}
}
void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast *node) {
gb_internal void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast *node) {
ast_node(et, EnumType, node);
GB_ASSERT(is_type_enum(enum_type));
@@ -851,7 +871,7 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
enum_type->Enum.max_value_index = max_value_index;
}
bool is_type_valid_bit_set_range(Type *t) {
gb_internal bool is_type_valid_bit_set_range(Type *t) {
if (is_type_integer(t)) {
return true;
}
@@ -861,7 +881,7 @@ bool is_type_valid_bit_set_range(Type *t) {
return false;
}
void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *node) {
gb_internal void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *node) {
ast_node(bs, BitSetType, node);
GB_ASSERT(type->kind == Type_BitSet);
type->BitSet.node = node;
@@ -1102,7 +1122,7 @@ void check_bit_set_type(CheckerContext *c, Type *type, Type *named_type, Ast *no
}
bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) {
gb_internal bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Type *type, bool compound, bool modify_type) {
if (type == nullptr ||
type == t_invalid) {
return true;
@@ -1229,7 +1249,7 @@ bool check_type_specialization_to(CheckerContext *ctx, Type *specialization, Typ
}
Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand const &operand) {
gb_internal Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Operand const &operand) {
bool modify_type = !ctx->no_polymorphic_errors;
bool show_error = modify_type && !ctx->hide_polymorphic_errors;
if (!is_operand_value(operand)) {
@@ -1256,7 +1276,7 @@ Type *determine_type_from_polymorphic(CheckerContext *ctx, Type *poly_type, Oper
return t_invalid;
}
bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) {
gb_internal bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) {
if (expr == nullptr) {
return false;
}
@@ -1275,7 +1295,7 @@ bool is_expr_from_a_parameter(CheckerContext *ctx, Ast *expr) {
}
ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) {
gb_internal ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type **out_type_, Ast *expr, bool allow_caller_location) {
ParameterValue param_value = {};
param_value.original_ast_expr = expr;
if (expr == nullptr) {
@@ -1370,7 +1390,7 @@ ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type *
}
Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
gb_internal Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is_variadic_, isize *variadic_index_, bool *success_, isize *specialization_count_, Array<Operand> *operands) {
if (_params == nullptr) {
return nullptr;
}
@@ -1599,10 +1619,6 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
}
}
if (p->flags&FieldFlag_auto_cast) {
error(name, "'auto_cast' can only be applied to variable fields");
p->flags &= ~FieldFlag_auto_cast;
}
if (p->flags&FieldFlag_const) {
error(name, "'#const' can only be applied to variable fields");
p->flags &= ~FieldFlag_const;
@@ -1639,6 +1655,12 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
} else if (!ctx->no_polymorphic_errors) {
// NOTE(bill): The type should be determined now and thus, no need to determine the type any more
is_type_polymorphic_type = false;
Entity *proc_entity = entity_from_expr(op.expr);
if ((proc_entity != nullptr) && (op.value.kind == ExactValue_Procedure)) {
if (is_type_polymorphic(proc_entity->type, false)) {
error(op.expr, "Cannot determine complete type of partial polymorphic procedure");
}
}
}
}
if (is_poly_name) {
@@ -1661,11 +1683,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
}
if (type != t_invalid && !check_is_assignable_to(ctx, &op, type)) {
bool ok = true;
if (p->flags&FieldFlag_auto_cast) {
if (!check_is_castable_to(ctx, &op, type)) {
ok = false;
}
} else if (p->flags&FieldFlag_any_int) {
if (p->flags&FieldFlag_any_int) {
if ((!is_type_integer(op.type) && !is_type_enum(op.type)) || (!is_type_integer(type) && !is_type_enum(type))) {
ok = false;
} else if (!check_is_castable_to(ctx, &op, type)) {
@@ -1711,10 +1729,6 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
error(name, "'#no_alias' can only be applied to non constant values");
p->flags &= ~FieldFlag_no_alias; // Remove the flag
}
if (p->flags&FieldFlag_auto_cast) {
error(name, "'auto_cast' can only be applied to variable fields");
p->flags &= ~FieldFlag_auto_cast;
}
if (p->flags&FieldFlag_any_int) {
error(name, "'#any_int' can only be applied to variable fields");
p->flags &= ~FieldFlag_any_int;
@@ -1745,9 +1759,6 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
if (p->flags&FieldFlag_no_alias) {
param->flags |= EntityFlag_NoAlias;
}
if (p->flags&FieldFlag_auto_cast) {
param->flags |= EntityFlag_AutoCast;
}
if (p->flags&FieldFlag_any_int) {
if (!is_type_integer(param->type) && !is_type_enum(param->type)) {
gbString str = type_to_string(param->type);
@@ -1791,8 +1802,8 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
isize specialization_count = 0;
if (scope != nullptr) {
for_array(i, scope->elements.entries) {
Entity *e = scope->elements.entries[i].value;
for (auto const &entry : scope->elements) {
Entity *e = entry.value;
if (e->kind == Entity_TypeName) {
Type *t = e->type;
if (t->kind == Type_Generic &&
@@ -1814,7 +1825,7 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
return tuple;
}
Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
gb_internal Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
if (_results == nullptr) {
return nullptr;
}
@@ -1928,7 +1939,7 @@ Type *check_get_results(CheckerContext *ctx, Scope *scope, Ast *_results) {
// NOTE(bill): 'operands' is for generating non generic procedure type
bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, Array<Operand> *operands) {
gb_internal bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node, Array<Operand> *operands) {
ast_node(pt, ProcType, proc_type_node);
if (ctx->polymorphic_scope == nullptr && ctx->allow_polymorphic_types) {
@@ -2084,7 +2095,7 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
}
i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
gb_internal i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
if (e == nullptr) {
return 0;
}
@@ -2169,7 +2180,7 @@ i64 check_array_count(CheckerContext *ctx, Operand *o, Ast *e) {
return 0;
}
Type *make_optional_ok_type(Type *value, bool typed) {
gb_internal Type *make_optional_ok_type(Type *value, bool typed) {
gbAllocator a = permanent_allocator();
Type *t = alloc_type_tuple();
slice_init(&t->Tuple.variables, a, 2);
@@ -2181,23 +2192,23 @@ Type *make_optional_ok_type(Type *value, bool typed) {
// IMPORTANT NOTE(bill): This must match the definition in dynamic_map_internal.odin
enum : i64 {
MAP_CACHE_LINE_LOG2 = 6,
MAP_CACHE_LINE_SIZE = 1 << MAP_CACHE_LINE_LOG2
MAP_CELL_CACHE_LINE_LOG2 = 6,
MAP_CELL_CACHE_LINE_SIZE = 1 << MAP_CELL_CACHE_LINE_LOG2,
};
GB_STATIC_ASSERT(MAP_CACHE_LINE_SIZE >= 64);
void map_cell_size_and_len(Type *type, i64 *size_, i64 *len_) {
GB_STATIC_ASSERT(MAP_CELL_CACHE_LINE_SIZE >= 64);
gb_internal void map_cell_size_and_len(Type *type, i64 *size_, i64 *len_) {
i64 elem_sz = type_size_of(type);
i64 len = 1;
if (0 < elem_sz && elem_sz < MAP_CACHE_LINE_SIZE) {
len = MAP_CACHE_LINE_SIZE / elem_sz;
if (0 < elem_sz && elem_sz < MAP_CELL_CACHE_LINE_SIZE) {
len = MAP_CELL_CACHE_LINE_SIZE / elem_sz;
}
i64 size = align_formula(elem_sz * len, MAP_CACHE_LINE_SIZE);
i64 size = align_formula(elem_sz * len, MAP_CELL_CACHE_LINE_SIZE);
if (size_) *size_ = size;
if (len_) *len_ = len;
}
void init_map_internal_types(Type *type) {
gb_internal void init_map_internal_types(Type *type) {
GB_ASSERT(type->kind == Type_Map);
GB_ASSERT(t_allocator != nullptr);
if (type->Map.lookup_result_type != nullptr) return;
@@ -2210,7 +2221,7 @@ void init_map_internal_types(Type *type) {
type->Map.lookup_result_type = make_optional_ok_type(value);
}
void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
gb_internal void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
key = core_type(key);
if (is_type_cstring(key)) {
@@ -2249,7 +2260,7 @@ void add_map_key_type_dependencies(CheckerContext *ctx, Type *key) {
}
}
void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
gb_internal void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
GB_ASSERT(type->kind == Type_Map);
ast_node(mt, MapType, node);
@@ -2282,7 +2293,7 @@ void check_map_type(CheckerContext *ctx, Type *type, Ast *node) {
// error(node, "'map' types are not yet implemented");
}
void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) {
gb_internal void check_matrix_type(CheckerContext *ctx, Type **type, Ast *node) {
ast_node(mt, MatrixType, node);
Operand row = {};
@@ -2346,7 +2357,7 @@ type_assign:;
Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type, StructSoaKind soa_kind) {
gb_internal Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type, StructSoaKind soa_kind) {
Type *bt_elem = base_type(elem);
bool is_polymorphic = is_type_polymorphic(elem);
@@ -2398,7 +2409,8 @@ Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *el
}
soa_struct->Struct.soa_count = cast(i32)count;
scope = create_scope(ctx->info, ctx->scope, 8);
scope = create_scope(ctx->info, ctx->scope);
string_map_init(&scope->elements, 8);
soa_struct->Struct.scope = scope;
String params_xyzw[4] = {
@@ -2501,20 +2513,20 @@ Type *make_soa_struct_internal(CheckerContext *ctx, Ast *array_typ_expr, Ast *el
}
Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type) {
gb_internal Type *make_soa_struct_fixed(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem, i64 count, Type *generic_type) {
return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, count, generic_type, StructSoa_Fixed);
}
Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) {
gb_internal Type *make_soa_struct_slice(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) {
return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, -1, nullptr, StructSoa_Slice);
}
Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) {
gb_internal Type *make_soa_struct_dynamic_array(CheckerContext *ctx, Ast *array_typ_expr, Ast *elem_expr, Type *elem) {
return make_soa_struct_internal(ctx, array_typ_expr, elem_expr, elem, -1, nullptr, StructSoa_Dynamic);
}
bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) {
gb_internal bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_type) {
GB_ASSERT_NOT_NULL(type);
if (e == nullptr) {
*type = t_invalid;
@@ -2997,7 +3009,7 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
return false;
}
Type *check_type(CheckerContext *ctx, Ast *e) {
gb_internal Type *check_type(CheckerContext *ctx, Ast *e) {
CheckerContext c = *ctx;
c.type_path = new_checker_type_path();
defer (destroy_checker_type_path(c.type_path));
@@ -3005,7 +3017,7 @@ Type *check_type(CheckerContext *ctx, Ast *e) {
return check_type_expr(&c, e, nullptr);
}
Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) {
gb_internal Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) {
Type *type = nullptr;
bool ok = check_type_internal(ctx, e, &type, named_type);
@@ -3045,7 +3057,7 @@ Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) {
#endif
if (is_type_typed(type)) {
add_type_and_value(ctx->info, e, Addressing_Type, type, empty_exact_value);
add_type_and_value(ctx, e, Addressing_Type, type, empty_exact_value);
} else {
gbString name = type_to_string(type);
error(e, "Invalid type definition of %s", name);
+781 -789
View File
File diff suppressed because it is too large Load Diff
+104 -87
View File
@@ -20,7 +20,7 @@ struct ExprInfo {
ExactValue value;
};
gb_inline ExprInfo *make_expr_info(AddressingMode mode, Type *type, ExactValue const &value, bool is_lhs) {
gb_internal gb_inline ExprInfo *make_expr_info(AddressingMode mode, Type *type, ExactValue const &value, bool is_lhs) {
ExprInfo *ei = gb_alloc_item(permanent_allocator(), ExprInfo);
ei->mode = mode;
ei->type = type;
@@ -130,7 +130,7 @@ struct AttributeContext {
String enable_target_feature; // will be enabled for the procedure only
};
AttributeContext make_attribute_context(String link_prefix) {
gb_internal gb_inline AttributeContext make_attribute_context(String link_prefix) {
AttributeContext ac = {};
ac.link_prefix = link_prefix;
return ac;
@@ -139,12 +139,31 @@ AttributeContext make_attribute_context(String link_prefix) {
#define DECL_ATTRIBUTE_PROC(_name) bool _name(CheckerContext *c, Ast *elem, String name, Ast *value, AttributeContext *ac)
typedef DECL_ATTRIBUTE_PROC(DeclAttributeProc);
void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, DeclAttributeProc *proc, AttributeContext *ac);
gb_internal void check_decl_attributes(CheckerContext *c, Array<Ast *> const &attributes, DeclAttributeProc *proc, AttributeContext *ac);
enum ProcCheckedState : u8 {
ProcCheckedState_Unchecked,
ProcCheckedState_InProgress,
ProcCheckedState_Checked,
ProcCheckedState_COUNT
};
char const *ProcCheckedState_strings[ProcCheckedState_COUNT] {
"Unchecked",
"In Progress",
"Checked",
};
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
struct DeclInfo {
DeclInfo * parent; // NOTE(bill): only used for procedure literals at the moment
BlockingMutex next_mutex;
DeclInfo * next_child;
DeclInfo * next_sibling;
Scope * scope;
Entity *entity;
@@ -157,13 +176,22 @@ struct DeclInfo {
Type * gen_proc_type; // Precalculated
bool is_using;
bool where_clauses_evaluated;
bool proc_checked;
std::atomic<ProcCheckedState> proc_checked_state;
BlockingMutex proc_checked_mutex;
isize defer_used;
bool defer_use_checked;
CommentGroup *comment;
CommentGroup *docs;
PtrSet<Entity *> deps;
RwMutex deps_mutex;
PtrSet<Entity *> deps;
RwMutex type_info_deps_mutex;
PtrSet<Type *> type_info_deps;
BlockingMutex type_and_value_mutex;
Array<BlockLabel> labels;
};
@@ -195,7 +223,7 @@ enum ScopeFlag : i32 {
ScopeFlag_ContextDefined = 1<<16,
};
enum { DEFAULT_SCOPE_CAPACITY = 29 };
enum { DEFAULT_SCOPE_CAPACITY = 32 };
struct Scope {
Ast * node;
@@ -203,7 +231,7 @@ struct Scope {
std::atomic<Scope *> next;
std::atomic<Scope *> head_child;
BlockingMutex mutex;
RwMutex mutex;
StringMap<Entity *> elements;
PtrSet<Scope *> imported;
@@ -275,7 +303,6 @@ struct UntypedExprInfo {
};
typedef PtrMap<Ast *, ExprInfo *> UntypedExprInfoMap;
typedef MPMCQueue<ProcInfo *> ProcBodyQueue;
enum ObjcMsgKind : u32 {
ObjcMsg_normal,
@@ -294,6 +321,16 @@ struct LoadFileCache {
StringMap<u64> hashes;
};
struct GenProcsData {
Array<Entity *> procs;
RwMutex mutex;
};
struct GenTypesData {
Array<Entity *> types;
RwMutex mutex;
};
// CheckerInfo stores all the symbol information for a type-checked program
struct CheckerInfo {
Checker *checker;
@@ -308,7 +345,7 @@ struct CheckerInfo {
Scope * init_scope;
Entity * entry_point;
PtrSet<Entity *> minimum_dependency_set;
PtrSet<isize> minimum_dependency_type_info_set;
PtrMap</*type info index*/isize, /*min dep index*/isize> minimum_dependency_type_info_set;
@@ -321,30 +358,17 @@ struct CheckerInfo {
// Below are accessed within procedures
// NOTE(bill): If the semantic checker (check_proc_body) is to ever to be multithreaded,
// these variables will be of contention
Semaphore collect_semaphore;
RwMutex global_untyped_mutex;
UntypedExprInfoMap global_untyped; // NOTE(bill): This needs to be a map and not on the Ast
// as it needs to be iterated across afterwards
BlockingMutex global_untyped_mutex;
BlockingMutex builtin_mutex;
// NOT recursive & only used at the end of `check_proc_body`
// and in `add_dependency`.
// This is a possible source of contention but probably not
// too much of a problem in practice
BlockingMutex deps_mutex;
BlockingMutex type_and_value_mutex;
RecursiveMutex lazy_mutex; // Mutex required for lazy type checking of specific files
RecursiveMutex gen_procs_mutex;
RecursiveMutex gen_types_mutex;
PtrMap<Ast *, Array<Entity *> > gen_procs; // Key: Ast * | Identifier -> Entity
PtrMap<Type *, Array<Entity *> > gen_types;
RwMutex gen_types_mutex;
PtrMap<Type *, GenTypesData > gen_types;
BlockingMutex type_info_mutex; // NOT recursive
Array<Type *> type_info_types;
@@ -353,37 +377,39 @@ struct CheckerInfo {
BlockingMutex foreign_mutex; // NOT recursive
StringMap<Entity *> foreigns;
// only used by 'odin query'
bool allow_identifier_uses;
BlockingMutex identifier_uses_mutex;
Array<Ast *> identifier_uses;
// NOTE(bill): These are actually MPSC queues
// TODO(bill): Convert them to be MPSC queues
MPMCQueue<Entity *> definition_queue;
MPMCQueue<Entity *> entity_queue;
MPMCQueue<Entity *> required_global_variable_queue;
MPMCQueue<Entity *> required_foreign_imports_through_force_queue;
MPSCQueue<Entity *> definition_queue;
MPSCQueue<Entity *> entity_queue;
MPSCQueue<Entity *> required_global_variable_queue;
MPSCQueue<Entity *> required_foreign_imports_through_force_queue;
MPMCQueue<Ast *> intrinsics_entry_point_usage;
MPSCQueue<Ast *> intrinsics_entry_point_usage;
BlockingMutex objc_types_mutex;
PtrMap<Ast *, ObjcMsgData> objc_msgSend_types;
BlockingMutex load_file_mutex;
StringMap<LoadFileCache *> load_file_cache;
BlockingMutex all_procedures_mutex;
Array<ProcInfo *> all_procedures;
};
struct CheckerContext {
// Order matters here
BlockingMutex mutex;
Checker * checker;
CheckerInfo * info;
AstPackage * pkg;
AstFile * file;
Scope * scope;
DeclInfo * decl;
// Order doesn't matter after this
u32 state_flags;
bool in_defer; // TODO(bill): Actually handle correctly
bool in_defer;
Type * type_hint;
String proc_name;
@@ -394,9 +420,7 @@ struct CheckerContext {
ForeignContext foreign_context;
CheckerTypePath *type_path;
isize type_level; // TODO(bill): Actually handle correctly
CheckerPolyPath *poly_path;
isize poly_level; // TODO(bill): Actually handle correctly
isize type_level;
UntypedExprInfoMap *untyped;
@@ -413,8 +437,6 @@ struct CheckerContext {
Scope * polymorphic_scope;
Ast *assignment_lhs_hint;
ProcBodyQueue *procs_to_check_queue;
};
@@ -424,13 +446,14 @@ struct Checker {
CheckerContext builtin_ctx;
MPMCQueue<Entity *> procs_with_deferred_to_check;
MPSCQueue<Entity *> procs_with_deferred_to_check;
Array<ProcInfo *> procs_to_check;
ProcBodyQueue procs_to_check_queue;
Semaphore procs_to_check_semaphore;
BlockingMutex nested_proc_lits_mutex;
Array<DeclInfo *> nested_proc_lits;
// TODO(bill): Technically MPSC queue
MPMCQueue<UntypedExprInfo> global_untyped_queue;
MPSCQueue<UntypedExprInfo> global_untyped_queue;
};
@@ -441,59 +464,53 @@ gb_global AstPackage *config_pkg = nullptr;
// CheckerInfo API
TypeAndValue type_and_value_of_expr (Ast *expr);
Type * type_of_expr (Ast *expr);
Entity * implicit_entity_of_node(Ast *clause);
DeclInfo * decl_info_of_ident (Ast *ident);
DeclInfo * decl_info_of_entity (Entity * e);
AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
gb_internal TypeAndValue type_and_value_of_expr (Ast *expr);
gb_internal Type * type_of_expr (Ast *expr);
gb_internal Entity * implicit_entity_of_node(Ast *clause);
gb_internal DeclInfo * decl_info_of_ident (Ast *ident);
gb_internal DeclInfo * decl_info_of_entity (Entity * e);
gb_internal AstFile * ast_file_of_filename (CheckerInfo *i, String filename);
// IMPORTANT: Only to use once checking is done
isize type_info_index (CheckerInfo *i, Type *type, bool error_on_failure);
gb_internal isize type_info_index (CheckerInfo *i, Type *type, bool error_on_failure);
// Will return nullptr if not found
Entity *entity_of_node(Ast *expr);
gb_internal Entity *entity_of_node(Ast *expr);
Entity *scope_lookup_current(Scope *s, String const &name);
Entity *scope_lookup (Scope *s, String const &name);
void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_);
Entity *scope_insert (Scope *s, Entity *entity, bool use_mutex=true);
gb_internal Entity *scope_lookup_current(Scope *s, String const &name);
gb_internal Entity *scope_lookup (Scope *s, String const &name);
gb_internal void scope_lookup_parent (Scope *s, String const &name, Scope **scope_, Entity **entity_);
gb_internal Entity *scope_insert (Scope *s, Entity *entity);
void add_type_and_value (CheckerInfo *i, Ast *expression, AddressingMode mode, Type *type, ExactValue value);
ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr);
void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue value);
void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity);
void add_implicit_entity (CheckerContext *c, Ast *node, Entity *e);
void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, DeclInfo *d, bool is_exported=true);
void add_type_info_type (CheckerContext *c, Type *t);
gb_internal void add_type_and_value (CheckerContext *c, Ast *expression, AddressingMode mode, Type *type, ExactValue value);
gb_internal ExprInfo *check_get_expr_info (CheckerContext *c, Ast *expr);
gb_internal void add_untyped (CheckerContext *c, Ast *expression, AddressingMode mode, Type *basic_type, ExactValue value);
gb_internal void add_entity_use (CheckerContext *c, Ast *identifier, Entity *entity);
gb_internal void add_implicit_entity (CheckerContext *c, Ast *node, Entity *e);
gb_internal void add_entity_and_decl_info(CheckerContext *c, Ast *identifier, Entity *e, DeclInfo *d, bool is_exported=true);
gb_internal void add_type_info_type (CheckerContext *c, Type *t);
void check_add_import_decl(CheckerContext *c, Ast *decl);
void check_add_foreign_import_decl(CheckerContext *c, Ast *decl);
gb_internal void check_add_import_decl(CheckerContext *c, Ast *decl);
gb_internal void check_add_foreign_import_decl(CheckerContext *c, Ast *decl);
void check_entity_decl(CheckerContext *c, Entity *e, DeclInfo *d, Type *named_type);
void check_const_decl(CheckerContext *c, Entity *e, Ast *type_expr, Ast *init_expr, Type *named_type);
void check_type_decl(CheckerContext *c, Entity *e, Ast *type_expr, Type *def);
gb_internal void check_entity_decl(CheckerContext *c, Entity *e, DeclInfo *d, Type *named_type);
gb_internal void check_const_decl(CheckerContext *c, Entity *e, Ast *type_expr, Ast *init_expr, Type *named_type);
gb_internal void check_type_decl(CheckerContext *c, Entity *e, Ast *type_expr, Type *def);
bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global = false);
void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes);
void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
gb_internal bool check_arity_match(CheckerContext *c, AstValueDecl *vd, bool is_global = false);
gb_internal void check_collect_entities(CheckerContext *c, Slice<Ast *> const &nodes);
gb_internal void check_collect_entities_from_when_stmt(CheckerContext *c, AstWhenStmt *ws);
gb_internal void check_delayed_file_import_entity(CheckerContext *c, Ast *decl);
CheckerTypePath *new_checker_type_path();
void destroy_checker_type_path(CheckerTypePath *tp);
gb_internal CheckerTypePath *new_checker_type_path();
gb_internal void destroy_checker_type_path(CheckerTypePath *tp);
void check_type_path_push(CheckerContext *c, Entity *e);
Entity *check_type_path_pop (CheckerContext *c);
gb_internal void check_type_path_push(CheckerContext *c, Entity *e);
gb_internal Entity *check_type_path_pop (CheckerContext *c);
CheckerPolyPath *new_checker_poly_path();
void destroy_checker_poly_path(CheckerPolyPath *);
gb_internal void init_core_context(Checker *c);
gb_internal void init_mem_allocator(Checker *c);
void check_poly_path_push(CheckerContext *c, Type *t);
Type *check_poly_path_pop (CheckerContext *c);
void init_core_context(Checker *c);
void init_mem_allocator(Checker *c);
void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped);
gb_internal void add_untyped_expressions(CheckerInfo *cinfo, UntypedExprInfoMap *untyped);
+73 -49
View File
@@ -29,36 +29,51 @@
#include <string.h>
#include <atomic> // Because I wanted the C++11 memory order semantics, of which gb.h does not offer (because it was a C89 library)
gbAllocator heap_allocator(void);
gb_internal gbAllocator heap_allocator(void);
#define for_array(index_, array_) for (isize index_ = 0; index_ < (array_).count; index_++)
#define for_array_off(index_, off_, array_) for (isize index_ = off_; index_ < (array_).count; index_++)
#define for_array(index_, array_) for_array_off(index_, 0, array_)
i32 next_pow2(i32 n);
i64 next_pow2(i64 n);
isize next_pow2_isize(isize n);
void debugf(char const *fmt, ...);
gb_internal i32 next_pow2(i32 n);
gb_internal i64 next_pow2(i64 n);
gb_internal isize next_pow2_isize(isize n);
gb_internal void debugf(char const *fmt, ...);
#if defined(GB_SYSTEM_WINDOWS) && defined(GB_ARCH_32_BIT)
#error Odin on Windows requires a 64-bit build-system. The 'Developer Command Prompt' for VS still defaults to 32-bit shell. The 64-bit shell can be found under the name 'x64 Native Tools Command Prompt' for VS. For more information, please see https://odin-lang.org/docs/install/#for-windows
#endif
#include "threading.cpp"
template <typename T>
struct TypeIsPointer {
enum {value = false};
};
template <typename T>
struct TypeIsPointer<T *> {
enum {value = true};
};
#include "unicode.cpp"
#include "array.cpp"
#include "queue.cpp"
#include "threading.cpp"
#include "common_memory.cpp"
#include "queue.cpp"
#include "string.cpp"
#include "range_cache.cpp"
#if defined(GB_SYSTEM_WINDOWS)
#pragma warning(push)
#pragma warning(disable: 4505)
#endif
bool is_power_of_two(i64 x) {
gb_internal gb_inline bool is_power_of_two(i64 x) {
if (x <= 0) {
return false;
}
return !(x & (x-1));
}
int isize_cmp(isize x, isize y) {
gb_internal int isize_cmp(isize x, isize y) {
if (x < y) {
return -1;
} else if (x > y) {
@@ -66,7 +81,7 @@ int isize_cmp(isize x, isize y) {
}
return 0;
}
int u64_cmp(u64 x, u64 y) {
gb_internal int u64_cmp(u64 x, u64 y) {
if (x < y) {
return -1;
} else if (x > y) {
@@ -74,7 +89,7 @@ int u64_cmp(u64 x, u64 y) {
}
return 0;
}
int i64_cmp(i64 x, i64 y) {
gb_internal int i64_cmp(i64 x, i64 y) {
if (x < y) {
return -1;
} else if (x > y) {
@@ -82,7 +97,7 @@ int i64_cmp(i64 x, i64 y) {
}
return 0;
}
int i32_cmp(i32 x, i32 y) {
gb_internal int i32_cmp(i32 x, i32 y) {
if (x < y) {
return -1;
} else if (x > y) {
@@ -91,7 +106,7 @@ int i32_cmp(i32 x, i32 y) {
return 0;
}
u32 fnv32a(void const *data, isize len) {
gb_internal u32 fnv32a(void const *data, isize len) {
u8 const *bytes = cast(u8 const *)data;
u32 h = 0x811c9dc5;
@@ -112,7 +127,7 @@ u32 fnv32a(void const *data, isize len) {
return h;
}
u64 fnv64a(void const *data, isize len) {
gb_internal u64 fnv64a(void const *data, isize len) {
u8 const *bytes = cast(u8 const *)data;
u64 h = 0xcbf29ce484222325ull;
@@ -133,7 +148,7 @@ u64 fnv64a(void const *data, isize len) {
return h;
}
u64 u64_digit_value(Rune r) {
gb_internal u64 u64_digit_value(Rune r) {
switch (r) {
case '0': return 0;
case '1': return 1;
@@ -162,7 +177,7 @@ u64 u64_digit_value(Rune r) {
}
u64 u64_from_string(String string) {
gb_internal u64 u64_from_string(String string) {
u64 base = 10;
bool has_prefix = false;
if (string.len > 2 && string[0] == '0') {
@@ -205,7 +220,7 @@ gb_global char const global_num_to_char_table[] =
"abcdefghijklmnopqrstuvwxyz"
"@$";
String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
gb_internal String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
char buf[32] = {0};
isize i = gb_size_of(buf);
@@ -220,7 +235,7 @@ String u64_to_string(u64 v, char *out_buf, isize out_buf_len) {
gb_memmove(out_buf, &buf[i], len);
return make_string(cast(u8 *)out_buf, len);
}
String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
gb_internal String i64_to_string(i64 a, char *out_buf, isize out_buf_len) {
char buf[32] = {0};
isize i = gb_size_of(buf);
bool negative = false;
@@ -282,17 +297,17 @@ gb_global u64 const unsigned_integer_maxs[] = {
};
bool add_overflow_u64(u64 x, u64 y, u64 *result) {
gb_internal bool add_overflow_u64(u64 x, u64 y, u64 *result) {
*result = x + y;
return *result < x || *result < y;
}
bool sub_overflow_u64(u64 x, u64 y, u64 *result) {
gb_internal bool sub_overflow_u64(u64 x, u64 y, u64 *result) {
*result = x - y;
return *result > x;
}
void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
gb_internal void mul_overflow_u64(u64 x, u64 y, u64 *lo, u64 *hi) {
#if defined(GB_COMPILER_MSVC) && defined(GB_ARCH_64_BIT)
*lo = _umul128(x, y, hi);
#else
@@ -342,7 +357,7 @@ struct StringIntern {
PtrMap<uintptr, StringIntern *> string_intern_map = {}; // Key: u64
gb_global Arena string_intern_arena = {};
char const *string_intern(char const *text, isize len) {
gb_internal char const *string_intern(char const *text, isize len) {
u64 hash = gb_fnv64a(text, len);
uintptr key = cast(uintptr)(hash ? hash : 1);
StringIntern **found = map_get(&string_intern_map, key);
@@ -363,18 +378,18 @@ char const *string_intern(char const *text, isize len) {
return new_intern->str;
}
char const *string_intern(String const &string) {
gb_internal char const *string_intern(String const &string) {
return string_intern(cast(char const *)string.text, string.len);
}
void init_string_interner(void) {
map_init(&string_intern_map, heap_allocator());
gb_internal void init_string_interner(void) {
map_init(&string_intern_map);
}
i32 next_pow2(i32 n) {
gb_internal i32 next_pow2(i32 n) {
if (n <= 0) {
return 0;
}
@@ -387,7 +402,7 @@ i32 next_pow2(i32 n) {
n++;
return n;
}
i64 next_pow2(i64 n) {
gb_internal i64 next_pow2(i64 n) {
if (n <= 0) {
return 0;
}
@@ -401,7 +416,7 @@ i64 next_pow2(i64 n) {
n++;
return n;
}
isize next_pow2_isize(isize n) {
gb_internal isize next_pow2_isize(isize n) {
if (n <= 0) {
return 0;
}
@@ -417,7 +432,7 @@ isize next_pow2_isize(isize n) {
n++;
return n;
}
u32 next_pow2_u32(u32 n) {
gb_internal u32 next_pow2_u32(u32 n) {
if (n == 0) {
return 0;
}
@@ -432,7 +447,7 @@ u32 next_pow2_u32(u32 n) {
}
i32 bit_set_count(u32 x) {
gb_internal i32 bit_set_count(u32 x) {
x -= ((x >> 1) & 0x55555555);
x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
x = (((x >> 4) + x) & 0x0f0f0f0f);
@@ -442,13 +457,13 @@ i32 bit_set_count(u32 x) {
return cast(i32)(x & 0x0000003f);
}
i64 bit_set_count(u64 x) {
gb_internal i64 bit_set_count(u64 x) {
u32 a = *(cast(u32 *)&x);
u32 b = *(cast(u32 *)&x + 1);
return bit_set_count(a) + bit_set_count(b);
}
u32 floor_log2(u32 x) {
gb_internal u32 floor_log2(u32 x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
@@ -457,7 +472,7 @@ u32 floor_log2(u32 x) {
return cast(u32)(bit_set_count(x) - 1);
}
u64 floor_log2(u64 x) {
gb_internal u64 floor_log2(u64 x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
@@ -468,7 +483,7 @@ u64 floor_log2(u64 x) {
}
u32 ceil_log2(u32 x) {
gb_internal u32 ceil_log2(u32 x) {
i32 y = cast(i32)(x & (x-1));
y |= -y;
y >>= 32-1;
@@ -480,7 +495,7 @@ u32 ceil_log2(u32 x) {
return cast(u32)(bit_set_count(x) - 1 - y);
}
u64 ceil_log2(u64 x) {
gb_internal u64 ceil_log2(u64 x) {
i64 y = cast(i64)(x & (x-1));
y |= -y;
y >>= 64-1;
@@ -493,7 +508,7 @@ u64 ceil_log2(u64 x) {
return cast(u64)(bit_set_count(x) - 1 - y);
}
u32 prev_pow2(u32 n) {
gb_internal u32 prev_pow2(u32 n) {
if (n == 0) {
return 0;
}
@@ -504,7 +519,7 @@ u32 prev_pow2(u32 n) {
n |= n >> 16;
return n - (n >> 1);
}
i32 prev_pow2(i32 n) {
gb_internal i32 prev_pow2(i32 n) {
if (n <= 0) {
return 0;
}
@@ -515,7 +530,7 @@ i32 prev_pow2(i32 n) {
n |= n >> 16;
return n - (n >> 1);
}
i64 prev_pow2(i64 n) {
gb_internal i64 prev_pow2(i64 n) {
if (n <= 0) {
return 0;
}
@@ -528,7 +543,7 @@ i64 prev_pow2(i64 n) {
return n - (n >> 1);
}
u16 f32_to_f16(f32 value) {
gb_internal u16 f32_to_f16(f32 value) {
union { u32 i; f32 f; } v;
i32 i, s, e, m;
@@ -579,7 +594,7 @@ u16 f32_to_f16(f32 value) {
}
}
f32 f16_to_f32(u16 value) {
gb_internal f32 f16_to_f32(u16 value) {
typedef union { u32 u; f32 f; } fp32;
fp32 v;
@@ -595,7 +610,7 @@ f32 f16_to_f32(u16 value) {
return v.f;
}
f64 gb_sqrt(f64 x) {
gb_internal gb_inline f64 gb_sqrt(f64 x) {
return sqrt(x);
}
@@ -623,7 +638,7 @@ f64 gb_sqrt(f64 x) {
#if defined(GB_SYSTEM_WINDOWS)
wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
gb_internal wchar_t **command_line_to_wargv(wchar_t *cmd_line, int *_argc) {
u32 i, j;
u32 len = cast(u32)string16_len(cmd_line);
@@ -706,11 +721,13 @@ enum LoadedFileError {
LoadedFile_COUNT,
};
LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_file, bool copy_file_contents) {
gb_internal LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_file, bool copy_file_contents) {
LoadedFileError err = LoadedFile_None;
if (!copy_file_contents) {
#if defined(GB_SYSTEM_WINDOWS)
TEMPORARY_ALLOCATOR_GUARD();
isize w_len = 0;
wchar_t *w_str = gb__alloc_utf8_to_ucs2(temporary_allocator(), fullpath, &w_len);
if (w_str == nullptr) {
@@ -811,7 +828,9 @@ LoadedFileError load_file_32(char const *fullpath, LoadedFile *memory_mapped_fil
#define USE_DAMERAU_LEVENSHTEIN 1
isize levenstein_distance_case_insensitive(String const &a, String const &b) {
gb_internal isize levenstein_distance_case_insensitive(String const &a, String const &b) {
TEMPORARY_ALLOCATOR_GUARD();
isize w = b.len+1;
isize h = a.len+1;
isize *matrix = gb_alloc_array(temporary_allocator(), isize, w*h);
@@ -870,16 +889,16 @@ struct DidYouMeanAnswers {
enum {MAX_SMALLEST_DID_YOU_MEAN_DISTANCE = 3-USE_DAMERAU_LEVENSHTEIN};
DidYouMeanAnswers did_you_mean_make(gbAllocator allocator, isize cap, String const &key) {
gb_internal DidYouMeanAnswers did_you_mean_make(gbAllocator allocator, isize cap, String const &key) {
DidYouMeanAnswers d = {};
array_init(&d.distances, allocator, 0, cap);
d.key = key;
return d;
}
void did_you_mean_destroy(DidYouMeanAnswers *d) {
gb_internal void did_you_mean_destroy(DidYouMeanAnswers *d) {
array_free(&d->distances);
}
void did_you_mean_append(DidYouMeanAnswers *d, String const &target) {
gb_internal void did_you_mean_append(DidYouMeanAnswers *d, String const &target) {
if (target.len == 0 || target == "_") {
return;
}
@@ -888,7 +907,7 @@ void did_you_mean_append(DidYouMeanAnswers *d, String const &target) {
dat.distance = levenstein_distance_case_insensitive(d->key, target);
array_add(&d->distances, dat);
}
Slice<DistanceAndTarget> did_you_mean_results(DidYouMeanAnswers *d) {
gb_internal Slice<DistanceAndTarget> did_you_mean_results(DidYouMeanAnswers *d) {
gb_sort_array(d->distances.data, d->distances.count, gb_isize_cmp(gb_offset_of(DistanceAndTarget, distance)));
isize count = 0;
for (isize i = 0; i < d->distances.count; i++) {
@@ -900,3 +919,8 @@ Slice<DistanceAndTarget> did_you_mean_results(DidYouMeanAnswers *d) {
}
return slice_array(d->distances, 0, count);
}
#if defined(GB_SYSTEM_WINDOWS)
#pragma warning(pop)
#endif
+149 -76
View File
@@ -1,5 +1,5 @@
gb_inline void zero_size(void *ptr, isize len) {
gb_internal gb_inline void zero_size(void *ptr, isize len) {
memset(ptr, 0, len);
}
@@ -7,43 +7,31 @@ gb_inline void zero_size(void *ptr, isize len) {
template <typename U, typename V>
gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
gb_internal gb_inline U bit_cast(V &v) { return reinterpret_cast<U &>(v); }
template <typename U, typename V>
gb_inline U const &bit_cast(V const &v) { return reinterpret_cast<U const &>(v); }
gb_internal gb_inline U const &bit_cast(V const &v) { return reinterpret_cast<U const &>(v); }
gb_inline i64 align_formula(i64 size, i64 align) {
if (align > 0) {
i64 result = size + align-1;
return result - result%align;
}
return size;
gb_internal gb_inline i64 align_formula(i64 size, i64 align) {
i64 result = size + align-1;
return result - (i64)((u64)result%(u64)align);
}
gb_inline isize align_formula_isize(isize size, isize align) {
if (align > 0) {
isize result = size + align-1;
return result - result%align;
}
return size;
gb_internal gb_inline isize align_formula_isize(isize size, isize align) {
isize result = size + align-1;
return result - (isize)((usize)result%(usize)align);
}
gb_inline void *align_formula_ptr(void *ptr, isize align) {
if (align > 0) {
uintptr result = (cast(uintptr)ptr) + align-1;
return (void *)(result - result%align);
}
return ptr;
gb_internal gb_inline void *align_formula_ptr(void *ptr, isize align) {
uintptr result = (cast(uintptr)ptr) + align-1;
return (void *)(result - result%align);
}
gb_global BlockingMutex global_memory_block_mutex;
gb_global BlockingMutex global_memory_allocator_mutex;
void platform_virtual_memory_init(void);
gb_internal void platform_virtual_memory_init(void);
void virtual_memory_init(void) {
mutex_init(&global_memory_block_mutex);
mutex_init(&global_memory_allocator_mutex);
gb_internal void virtual_memory_init(void) {
platform_virtual_memory_init();
}
@@ -57,22 +45,23 @@ struct MemoryBlock {
};
struct Arena {
MemoryBlock *curr_block;
isize minimum_block_size;
bool ignore_mutex;
MemoryBlock * curr_block;
isize minimum_block_size;
BlockingMutex mutex;
isize temp_count;
};
enum { DEFAULT_MINIMUM_BLOCK_SIZE = 8ll*1024ll*1024ll };
gb_global isize DEFAULT_PAGE_SIZE = 4096;
MemoryBlock *virtual_memory_alloc(isize size);
void virtual_memory_dealloc(MemoryBlock *block);
void *arena_alloc(Arena *arena, isize min_size, isize alignment);
void arena_free_all(Arena *arena);
gb_internal MemoryBlock *virtual_memory_alloc(isize size);
gb_internal void virtual_memory_dealloc(MemoryBlock *block);
gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment);
gb_internal void arena_free_all(Arena *arena);
isize arena_align_forward_offset(Arena *arena, isize alignment) {
gb_internal isize arena_align_forward_offset(Arena *arena, isize alignment) {
isize alignment_offset = 0;
isize ptr = cast(isize)(arena->curr_block->base + arena->curr_block->used);
isize mask = alignment-1;
@@ -82,13 +71,10 @@ isize arena_align_forward_offset(Arena *arena, isize alignment) {
return alignment_offset;
}
void *arena_alloc(Arena *arena, isize min_size, isize alignment) {
gb_internal void *arena_alloc(Arena *arena, isize min_size, isize alignment) {
GB_ASSERT(gb_is_power_of_two(alignment));
BlockingMutex *mutex = &global_memory_allocator_mutex;
if (!arena->ignore_mutex) {
mutex_lock(mutex);
}
mutex_lock(&arena->mutex);
isize size = 0;
if (arena->curr_block != nullptr) {
@@ -115,15 +101,13 @@ void *arena_alloc(Arena *arena, isize min_size, isize alignment) {
curr_block->used += size;
GB_ASSERT(curr_block->used <= curr_block->size);
if (!arena->ignore_mutex) {
mutex_unlock(mutex);
}
mutex_unlock(&arena->mutex);
// NOTE(bill): memory will be zeroed by default due to virtual memory
return ptr;
}
void arena_free_all(Arena *arena) {
gb_internal void arena_free_all(Arena *arena) {
while (arena->curr_block != nullptr) {
MemoryBlock *free_block = arena->curr_block;
arena->curr_block = free_block->prev;
@@ -142,12 +126,12 @@ struct PlatformMemoryBlock {
gb_global std::atomic<isize> global_platform_memory_total_usage;
gb_global PlatformMemoryBlock global_platform_memory_block_sentinel;
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size);
void platform_virtual_memory_free(PlatformMemoryBlock *block);
void platform_virtual_memory_protect(void *memory, isize size);
gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size);
gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block);
gb_internal void platform_virtual_memory_protect(void *memory, isize size);
#if defined(GB_SYSTEM_WINDOWS)
void platform_virtual_memory_init(void) {
gb_internal void platform_virtual_memory_init(void) {
global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel;
global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel;
@@ -157,7 +141,7 @@ void platform_virtual_memory_protect(void *memory, isize size);
GB_ASSERT(gb_is_power_of_two(DEFAULT_PAGE_SIZE));
}
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)VirtualAlloc(0, total_size, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if (pmblock == nullptr) {
gb_printf_err("Out of Virtual memory, oh no...\n");
@@ -165,20 +149,20 @@ void platform_virtual_memory_protect(void *memory, isize size);
gb_printf_err("Total Usage: %lld bytes\n", cast(long long)global_platform_memory_total_usage);
GB_ASSERT_MSG(pmblock != nullptr, "Out of Virtual Memory, oh no...");
}
global_platform_memory_total_usage += total_size;
global_platform_memory_total_usage.fetch_add(total_size);
return pmblock;
}
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
global_platform_memory_total_usage -= block->total_size;
gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block) {
global_platform_memory_total_usage.fetch_sub(block->total_size);
GB_ASSERT(VirtualFree(block, 0, MEM_RELEASE));
}
void platform_virtual_memory_protect(void *memory, isize size) {
gb_internal void platform_virtual_memory_protect(void *memory, isize size) {
DWORD old_protect = 0;
BOOL is_protected = VirtualProtect(memory, size, PAGE_NOACCESS, &old_protect);
GB_ASSERT(is_protected);
}
#else
void platform_virtual_memory_init(void) {
gb_internal void platform_virtual_memory_init(void) {
global_platform_memory_block_sentinel.prev = &global_platform_memory_block_sentinel;
global_platform_memory_block_sentinel.next = &global_platform_memory_block_sentinel;
@@ -186,7 +170,7 @@ void platform_virtual_memory_protect(void *memory, isize size);
GB_ASSERT(gb_is_power_of_two(DEFAULT_PAGE_SIZE));
}
PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
gb_internal PlatformMemoryBlock *platform_virtual_memory_alloc(isize total_size) {
PlatformMemoryBlock *pmblock = (PlatformMemoryBlock *)mmap(nullptr, total_size, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (pmblock == nullptr) {
gb_printf_err("Out of Virtual memory, oh no...\n");
@@ -197,18 +181,18 @@ void platform_virtual_memory_protect(void *memory, isize size);
global_platform_memory_total_usage += total_size;
return pmblock;
}
void platform_virtual_memory_free(PlatformMemoryBlock *block) {
gb_internal void platform_virtual_memory_free(PlatformMemoryBlock *block) {
isize size = block->total_size;
global_platform_memory_total_usage -= size;
munmap(block, size);
}
void platform_virtual_memory_protect(void *memory, isize size) {
gb_internal void platform_virtual_memory_protect(void *memory, isize size) {
int err = mprotect(memory, size, PROT_NONE);
GB_ASSERT(err == 0);
}
#endif
MemoryBlock *virtual_memory_alloc(isize size) {
gb_internal MemoryBlock *virtual_memory_alloc(isize size) {
isize const page_size = DEFAULT_PAGE_SIZE;
isize total_size = size + gb_size_of(PlatformMemoryBlock);
@@ -250,7 +234,7 @@ MemoryBlock *virtual_memory_alloc(isize size) {
return &pmblock->block;
}
void virtual_memory_dealloc(MemoryBlock *block_to_free) {
gb_internal void virtual_memory_dealloc(MemoryBlock *block_to_free) {
PlatformMemoryBlock *block = cast(PlatformMemoryBlock *)block_to_free;
if (block != nullptr) {
mutex_lock(&global_memory_block_mutex);
@@ -262,12 +246,87 @@ void virtual_memory_dealloc(MemoryBlock *block_to_free) {
}
}
struct ArenaTemp {
Arena * arena;
MemoryBlock *block;
isize used;
};
ArenaTemp arena_temp_begin(Arena *arena) {
GB_ASSERT(arena);
MUTEX_GUARD(&arena->mutex);
ArenaTemp temp = {};
temp.arena = arena;
temp.block = arena->curr_block;
if (arena->curr_block != nullptr) {
temp.used = arena->curr_block->used;
}
arena->temp_count += 1;
return temp;
}
void arena_temp_end(ArenaTemp const &temp) {
GB_ASSERT(temp.arena);
Arena *arena = temp.arena;
MUTEX_GUARD(&arena->mutex);
if (temp.block) {
bool memory_block_found = false;
for (MemoryBlock *block = arena->curr_block; block != nullptr; block = block->prev) {
if (block == temp.block) {
memory_block_found = true;
break;
}
}
GB_ASSERT_MSG(memory_block_found, "memory block stored within ArenaTemp not owned by Arena");
while (arena->curr_block != temp.block) {
MemoryBlock *free_block = arena->curr_block;
if (free_block != nullptr) {
arena->curr_block = free_block->prev;
virtual_memory_dealloc(free_block);
}
}
MemoryBlock *block = arena->curr_block;
if (block) {
GB_ASSERT_MSG(block->used >= temp.used, "out of order use of arena_temp_end");
isize amount_to_zero = gb_min(block->used - temp.used, block->size - block->used);
gb_zero_size(block->base + temp.used, amount_to_zero);
block->used = temp.used;
}
}
GB_ASSERT_MSG(arena->temp_count > 0, "double-use of arena_temp_end");
arena->temp_count -= 1;
}
void arena_temp_ignore(ArenaTemp const &temp) {
GB_ASSERT(temp.arena);
Arena *arena = temp.arena;
MUTEX_GUARD(&arena->mutex);
GB_ASSERT_MSG(arena->temp_count > 0, "double-use of arena_temp_end");
arena->temp_count -= 1;
}
GB_ALLOCATOR_PROC(arena_allocator_proc);
struct ArenaTempGuard {
ArenaTempGuard(Arena *arena) {
this->temp = arena_temp_begin(arena);
}
~ArenaTempGuard() {
arena_temp_end(this->temp);
}
ArenaTemp temp;
};
gbAllocator arena_allocator(Arena *arena) {
gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc);
gb_internal gbAllocator arena_allocator(Arena *arena) {
gbAllocator a;
a.proc = arena_allocator_proc;
a.data = arena;
@@ -275,7 +334,7 @@ gbAllocator arena_allocator(Arena *arena) {
}
GB_ALLOCATOR_PROC(arena_allocator_proc) {
gb_internal GB_ALLOCATOR_PROC(arena_allocator_proc) {
void *ptr = nullptr;
Arena *arena = cast(Arena *)allocator_data;
GB_ASSERT_NOT_NULL(arena);
@@ -306,31 +365,44 @@ GB_ALLOCATOR_PROC(arena_allocator_proc) {
}
gb_global gb_thread_local Arena permanent_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE, true};
gbAllocator permanent_allocator() {
gb_global gb_thread_local Arena permanent_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE};
gb_internal gbAllocator permanent_allocator() {
return arena_allocator(&permanent_arena);
}
gbAllocator temporary_allocator() {
return permanent_allocator();
gb_global gb_thread_local Arena temporary_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE};
gb_internal gbAllocator temporary_allocator() {
return arena_allocator(&temporary_arena);
}
#define TEMP_ARENA_GUARD(arena) ArenaTempGuard GB_DEFER_3(_arena_guard_){arena}
// #define TEMPORARY_ALLOCATOR_GUARD()
#define TEMPORARY_ALLOCATOR_GUARD() TEMP_ARENA_GUARD(&temporary_arena)
#define PERMANENT_ALLOCATOR_GUARD()
gb_internal bool IS_ODIN_DEBUG(void);
GB_ALLOCATOR_PROC(heap_allocator_proc);
gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc);
gbAllocator heap_allocator(void) {
gbAllocator a;
a.proc = heap_allocator_proc;
a.data = nullptr;
return a;
gb_global gb_thread_local Arena heap_arena = {nullptr, DEFAULT_MINIMUM_BLOCK_SIZE};
gb_internal gbAllocator heap_allocator(void) {
if (IS_ODIN_DEBUG()) {
gbAllocator a;
a.proc = heap_allocator_proc;
a.data = nullptr;
return a;
}
return arena_allocator(&heap_arena);
}
GB_ALLOCATOR_PROC(heap_allocator_proc) {
gb_internal GB_ALLOCATOR_PROC(heap_allocator_proc) {
void *ptr = nullptr;
gb_unused(allocator_data);
gb_unused(old_size);
@@ -460,21 +532,22 @@ GB_ALLOCATOR_PROC(heap_allocator_proc) {
template <typename T>
void resize_array_raw(T **array, gbAllocator const &a, isize old_count, isize new_count) {
gb_internal isize resize_array_raw(T **array, gbAllocator const &a, isize old_count, isize new_count, isize custom_alignment=1) {
GB_ASSERT(new_count >= 0);
if (new_count == 0) {
gb_free(a, *array);
*array = nullptr;
return;
return 0;
}
if (new_count < old_count) {
return;
return old_count;
}
isize old_size = old_count * gb_size_of(T);
isize new_size = new_count * gb_size_of(T);
isize alignment = gb_align_of(T);
isize alignment = gb_max(gb_align_of(T), custom_alignment);
auto new_data = cast(T *)gb_resize_align(a, *array, old_size, new_size, alignment);
GB_ASSERT(new_data != nullptr);
*array = new_data;
return new_count;
}
+25 -39
View File
@@ -28,7 +28,7 @@ gb_global char const *print_entity_names[Entity_Count] = {
};
GB_COMPARE_PROC(cmp_entities_for_printing) {
gb_internal GB_COMPARE_PROC(cmp_entities_for_printing) {
GB_ASSERT(a != nullptr);
GB_ASSERT(b != nullptr);
Entity *x = *cast(Entity **)a;
@@ -49,14 +49,13 @@ GB_COMPARE_PROC(cmp_entities_for_printing) {
int ox = print_entity_kind_ordering[x->kind];
int oy = print_entity_kind_ordering[y->kind];
res = ox - oy;
if (res != 0) {
return res;
if (res == 0) {
res = string_compare(x->token.string, y->token.string);
}
res = string_compare(x->token.string, y->token.string);
return res;
}
GB_COMPARE_PROC(cmp_ast_package_by_name) {
gb_internal GB_COMPARE_PROC(cmp_ast_package_by_name) {
GB_ASSERT(a != nullptr);
GB_ASSERT(b != nullptr);
AstPackage *x = *cast(AstPackage **)a;
@@ -67,7 +66,7 @@ GB_COMPARE_PROC(cmp_ast_package_by_name) {
#include "docs_format.cpp"
#include "docs_writer.cpp"
void print_doc_line(i32 indent, String const &data) {
gb_internal void print_doc_line(i32 indent, String const &data) {
while (indent --> 0) {
gb_printf("\t");
}
@@ -75,7 +74,7 @@ void print_doc_line(i32 indent, String const &data) {
gb_printf("\n");
}
void print_doc_line(i32 indent, char const *fmt, ...) {
gb_internal void print_doc_line(i32 indent, char const *fmt, ...) {
while (indent --> 0) {
gb_printf("\t");
}
@@ -85,16 +84,7 @@ void print_doc_line(i32 indent, char const *fmt, ...) {
va_end(va);
gb_printf("\n");
}
void print_doc_line_no_newline(i32 indent, char const *fmt, ...) {
while (indent --> 0) {
gb_printf("\t");
}
va_list va;
va_start(va, fmt);
gb_printf_va(fmt, va);
va_end(va);
}
void print_doc_line_no_newline(i32 indent, String const &data) {
gb_internal void print_doc_line_no_newline(i32 indent, String const &data) {
while (indent --> 0) {
gb_printf("\t");
}
@@ -102,7 +92,7 @@ void print_doc_line_no_newline(i32 indent, String const &data) {
}
bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
gb_internal bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
if (g == nullptr) {
return false;
}
@@ -191,7 +181,7 @@ bool print_doc_comment_group_string(i32 indent, CommentGroup *g) {
void print_doc_expr(Ast *expr) {
gb_internal void print_doc_expr(Ast *expr) {
gbString s = nullptr;
if (build_context.cmd_doc_flags & CmdDocFlag_Short) {
s = expr_to_string_shorthand(expr);
@@ -202,8 +192,7 @@ void print_doc_expr(Ast *expr) {
gb_string_free(s);
}
void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
gb_internal void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
if (pkg == nullptr) {
return;
}
@@ -220,10 +209,10 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
}
if (pkg->scope != nullptr) {
auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.entries.count);
auto entities = array_make<Entity *>(heap_allocator(), 0, pkg->scope->elements.count);
defer (array_free(&entities));
for_array(i, pkg->scope->elements.entries) {
Entity *e = pkg->scope->elements.entries[i].value;
for (auto const &entry : pkg->scope->elements) {
Entity *e = entry.value;
switch (e->kind) {
case Entity_Invalid:
case Entity_Builtin:
@@ -240,6 +229,12 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
// Fine
break;
}
if (e->pkg != pkg) {
continue;
}
if (!is_entity_exported(e)) {
continue;
}
array_add(&entities, e);
}
gb_sort_array(entities.data, entities.count, cmp_entities_for_printing);
@@ -247,16 +242,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
bool show_docs = (build_context.cmd_doc_flags & CmdDocFlag_Short) == 0;
EntityKind curr_entity_kind = Entity_Invalid;
for_array(i, entities) {
Entity *e = entities[i];
if (e->pkg != pkg) {
continue;
}
if (!is_entity_exported(e)) {
continue;
}
for (Entity *e : entities) {
if (curr_entity_kind != e->kind) {
if (curr_entity_kind != Entity_Invalid) {
print_doc_line(0, "");
@@ -297,7 +283,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
print_doc_expr(init_expr);
}
gb_printf(";\n");
gb_printf("\n");
if (show_docs) {
print_doc_comment_group_string(3, docs);
@@ -320,7 +306,7 @@ void print_doc_package(CheckerInfo *info, AstPackage *pkg) {
}
void generate_documentation(Checker *c) {
gb_internal void generate_documentation(Checker *c) {
CheckerInfo *info = &c->info;
if (build_context.cmd_doc_flags & CmdDocFlag_DocFormat) {
@@ -358,9 +344,9 @@ void generate_documentation(Checker *c) {
odin_doc_write(info, output_file_path);
} else {
auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.entries.count);
for_array(i, info->packages.entries) {
AstPackage *pkg = info->packages.entries[i].value;
auto pkgs = array_make<AstPackage *>(permanent_allocator(), 0, info->packages.count);
for (auto const &entry : info->packages) {
AstPackage *pkg = entry.value;
if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
array_add(&pkgs, pkg);
} else {
+2 -2
View File
@@ -27,14 +27,14 @@ struct OdinDocHeaderBase {
};
template <typename T>
Slice<T> from_array(OdinDocHeaderBase *base, OdinDocArray<T> const &a) {
gb_internal Slice<T> from_array(OdinDocHeaderBase *base, OdinDocArray<T> const &a) {
Slice<T> s = {};
s.data = cast(T *)(cast(uintptr)base + cast(uintptr)a.offset);
s.count = cast(isize)a.length;
return s;
}
String from_string(OdinDocHeaderBase *base, OdinDocString const &s) {
gb_internal String from_string(OdinDocHeaderBase *base, OdinDocString const &s) {
String str = {};
str.text = cast(u8 *)(cast(uintptr)base + cast(uintptr)s.offset);
str.len = cast(isize)s.length;
+58 -62
View File
@@ -11,7 +11,7 @@ enum OdinDocWriterState {
OdinDocWriterState_Writing,
};
char const* OdinDocWriterState_strings[] {
gb_global char const* OdinDocWriterState_strings[] {
"preparing",
"writing ",
};
@@ -40,26 +40,25 @@ struct OdinDocWriter {
OdinDocWriterItemTracker<u8> blob;
};
OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e);
OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type);
gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e);
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type);
template <typename T>
void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker<T> *t, isize size) {
gb_internal void odin_doc_writer_item_tracker_init(OdinDocWriterItemTracker<T> *t, isize size) {
t->len = size;
t->cap = size;
}
void odin_doc_writer_prepare(OdinDocWriter *w) {
gb_internal void odin_doc_writer_prepare(OdinDocWriter *w) {
w->state = OdinDocWriterState_Preparing;
gbAllocator a = heap_allocator();
string_map_init(&w->string_cache, a);
string_map_init(&w->string_cache);
map_init(&w->file_cache, a);
map_init(&w->pkg_cache, a);
map_init(&w->entity_cache, a);
map_init(&w->type_cache, a);
map_init(&w->file_cache);
map_init(&w->pkg_cache);
map_init(&w->entity_cache);
map_init(&w->type_cache);
odin_doc_writer_item_tracker_init(&w->files, 1);
odin_doc_writer_item_tracker_init(&w->pkgs, 1);
@@ -70,7 +69,7 @@ void odin_doc_writer_prepare(OdinDocWriter *w) {
}
void odin_doc_writer_destroy(OdinDocWriter *w) {
gb_internal void odin_doc_writer_destroy(OdinDocWriter *w) {
gb_free(heap_allocator(), w->data);
string_map_destroy(&w->string_cache);
@@ -83,7 +82,7 @@ void odin_doc_writer_destroy(OdinDocWriter *w) {
template <typename T>
void odin_doc_writer_tracker_size(isize *offset, OdinDocWriterItemTracker<T> *t, isize alignment=1) {
gb_internal void odin_doc_writer_tracker_size(isize *offset, OdinDocWriterItemTracker<T> *t, isize alignment=1) {
isize size = t->cap*gb_size_of(T);
isize align = gb_max(gb_align_of(T), alignment);
*offset = align_formula_isize(*offset, align);
@@ -91,7 +90,7 @@ void odin_doc_writer_tracker_size(isize *offset, OdinDocWriterItemTracker<T> *t,
*offset += size;
}
isize odin_doc_writer_calc_total_size(OdinDocWriter *w) {
gb_internal isize odin_doc_writer_calc_total_size(OdinDocWriter *w) {
isize total_size = gb_size_of(OdinDocHeader);
odin_doc_writer_tracker_size(&total_size, &w->files);
odin_doc_writer_tracker_size(&total_size, &w->pkgs);
@@ -102,7 +101,7 @@ isize odin_doc_writer_calc_total_size(OdinDocWriter *w) {
return total_size;
}
void odin_doc_writer_start_writing(OdinDocWriter *w) {
gb_internal void odin_doc_writer_start_writing(OdinDocWriter *w) {
w->state = OdinDocWriterState_Writing;
string_map_clear(&w->string_cache);
@@ -118,7 +117,7 @@ void odin_doc_writer_start_writing(OdinDocWriter *w) {
w->header = cast(OdinDocHeader *)w->data;
}
u32 hash_data_after_header(OdinDocHeaderBase *base, void *data, isize data_len) {
gb_internal u32 hash_data_after_header(OdinDocHeaderBase *base, void *data, isize data_len) {
u8 *start = cast(u8 *)data;
u8 *end = start + base->total_size;
start += base->header_size;
@@ -132,13 +131,13 @@ u32 hash_data_after_header(OdinDocHeaderBase *base, void *data, isize data_len)
template <typename T>
void odin_doc_writer_assign_tracker(OdinDocArray<T> *array, OdinDocWriterItemTracker<T> const &t) {
gb_internal void odin_doc_writer_assign_tracker(OdinDocArray<T> *array, OdinDocWriterItemTracker<T> const &t) {
array->offset = cast(u32)t.offset;
array->length = cast(u32)t.len;
}
void odin_doc_writer_end_writing(OdinDocWriter *w) {
gb_internal void odin_doc_writer_end_writing(OdinDocWriter *w) {
OdinDocHeader *h = w->header;
gb_memmove(h->base.magic, OdinDocHeader_MagicString, gb_strlen(OdinDocHeader_MagicString));
@@ -156,7 +155,7 @@ void odin_doc_writer_end_writing(OdinDocWriter *w) {
}
template <typename T>
u32 odin_doc_write_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, T const *item, T **dst=nullptr) {
gb_internal u32 odin_doc_write_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, T const *item, T **dst=nullptr) {
if (w->state == OdinDocWriterState_Preparing) {
t->cap += 1;
if (dst) *dst = nullptr;
@@ -175,7 +174,7 @@ u32 odin_doc_write_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, T cons
}
template <typename T>
T *odin_doc_get_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, u32 index) {
gb_internal T *odin_doc_get_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, u32 index) {
if (w->state != OdinDocWriterState_Writing) {
return nullptr;
}
@@ -184,7 +183,7 @@ T *odin_doc_get_item(OdinDocWriter *w, OdinDocWriterItemTracker<T> *t, u32 index
return cast(T *)data;
}
OdinDocString odin_doc_write_string_without_cache(OdinDocWriter *w, String const &str) {
gb_internal OdinDocString odin_doc_write_string_without_cache(OdinDocWriter *w, String const &str) {
OdinDocString res = {};
if (w->state == OdinDocWriterState_Preparing) {
@@ -204,7 +203,7 @@ OdinDocString odin_doc_write_string_without_cache(OdinDocWriter *w, String const
return res;
}
OdinDocString odin_doc_write_string(OdinDocWriter *w, String const &str) {
gb_internal OdinDocString odin_doc_write_string(OdinDocWriter *w, String const &str) {
OdinDocString *c = string_map_get(&w->string_cache, str);
if (c != nullptr) {
if (w->state == OdinDocWriterState_Writing) {
@@ -223,7 +222,7 @@ OdinDocString odin_doc_write_string(OdinDocWriter *w, String const &str) {
template <typename T>
OdinDocArray<T> odin_write_slice(OdinDocWriter *w, T *data, isize len) {
gb_internal OdinDocArray<T> odin_write_slice(OdinDocWriter *w, T *data, isize len) {
GB_ASSERT(gb_align_of(T) <= 4);
if (len <= 0) {
return {0, 0};
@@ -249,12 +248,12 @@ OdinDocArray<T> odin_write_slice(OdinDocWriter *w, T *data, isize len) {
template <typename T>
OdinDocArray<T> odin_write_item_as_slice(OdinDocWriter *w, T data) {
gb_internal OdinDocArray<T> odin_write_item_as_slice(OdinDocWriter *w, T data) {
return odin_write_slice(w, &data, 1);
}
OdinDocPosition odin_doc_token_pos_cast(OdinDocWriter *w, TokenPos const &pos) {
gb_internal OdinDocPosition odin_doc_token_pos_cast(OdinDocWriter *w, TokenPos const &pos) {
OdinDocFileIndex file_index = 0;
if (pos.file_id != 0) {
AstFile *file = global_files[pos.file_id];
@@ -273,7 +272,7 @@ OdinDocPosition odin_doc_token_pos_cast(OdinDocWriter *w, TokenPos const &pos) {
return doc_pos;
}
bool odin_doc_append_comment_group_string(Array<u8> *buf, CommentGroup *g) {
gb_internal bool odin_doc_append_comment_group_string(Array<u8> *buf, CommentGroup *g) {
if (g == nullptr) {
return false;
}
@@ -361,7 +360,7 @@ bool odin_doc_append_comment_group_string(Array<u8> *buf, CommentGroup *g) {
return false;
}
OdinDocString odin_doc_pkg_doc_string(OdinDocWriter *w, AstPackage *pkg) {
gb_internal OdinDocString odin_doc_pkg_doc_string(OdinDocWriter *w, AstPackage *pkg) {
if (pkg == nullptr) {
return {};
}
@@ -378,7 +377,7 @@ OdinDocString odin_doc_pkg_doc_string(OdinDocWriter *w, AstPackage *pkg) {
return odin_doc_write_string_without_cache(w, make_string(buf.data, buf.count));
}
OdinDocString odin_doc_comment_group_string(OdinDocWriter *w, CommentGroup *g) {
gb_internal OdinDocString odin_doc_comment_group_string(OdinDocWriter *w, CommentGroup *g) {
if (g == nullptr) {
return {};
}
@@ -389,7 +388,7 @@ OdinDocString odin_doc_comment_group_string(OdinDocWriter *w, CommentGroup *g) {
return odin_doc_write_string_without_cache(w, make_string(buf.data, buf.count));
}
OdinDocString odin_doc_expr_string(OdinDocWriter *w, Ast *expr) {
gb_internal OdinDocString odin_doc_expr_string(OdinDocWriter *w, Ast *expr) {
if (expr == nullptr) {
return {};
}
@@ -402,7 +401,7 @@ OdinDocString odin_doc_expr_string(OdinDocWriter *w, Ast *expr) {
return odin_doc_write_string(w, make_string(cast(u8 *)s, gb_string_length(s)));
}
OdinDocArray<OdinDocAttribute> odin_doc_attributes(OdinDocWriter *w, Array<Ast *> const &attributes) {
gb_internal OdinDocArray<OdinDocAttribute> odin_doc_attributes(OdinDocWriter *w, Array<Ast *> const &attributes) {
isize count = 0;
for_array(i, attributes) {
Ast *attr = attributes[i];
@@ -448,7 +447,7 @@ OdinDocArray<OdinDocAttribute> odin_doc_attributes(OdinDocWriter *w, Array<Ast *
return odin_write_slice(w, attribs.data, attribs.count);
}
OdinDocArray<OdinDocString> odin_doc_where_clauses(OdinDocWriter *w, Slice<Ast *> const &where_clauses) {
gb_internal OdinDocArray<OdinDocString> odin_doc_where_clauses(OdinDocWriter *w, Slice<Ast *> const &where_clauses) {
if (where_clauses.count == 0) {
return {};
}
@@ -462,17 +461,17 @@ OdinDocArray<OdinDocString> odin_doc_where_clauses(OdinDocWriter *w, Slice<Ast *
return odin_write_slice(w, clauses.data, clauses.count);
}
OdinDocArray<OdinDocTypeIndex> odin_doc_type_as_slice(OdinDocWriter *w, Type *type) {
gb_internal OdinDocArray<OdinDocTypeIndex> odin_doc_type_as_slice(OdinDocWriter *w, Type *type) {
OdinDocTypeIndex index = odin_doc_type(w, type);
return odin_write_item_as_slice(w, index);
}
OdinDocArray<OdinDocEntityIndex> odin_doc_add_entity_as_slice(OdinDocWriter *w, Entity *e) {
gb_internal OdinDocArray<OdinDocEntityIndex> odin_doc_add_entity_as_slice(OdinDocWriter *w, Entity *e) {
OdinDocEntityIndex index = odin_doc_add_entity(w, e);
return odin_write_item_as_slice(w, index);
}
OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
if (type == nullptr) {
return 0;
}
@@ -480,11 +479,11 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
if (found) {
return *found;
}
for_array(i, w->type_cache.entries) {
for (auto const &entry : w->type_cache) {
// NOTE(bill): THIS IS SLOW
Type *other = w->type_cache.entries[i].key;
Type *other = entry.key;
if (are_types_identical_unique_tuples(type, other)) {
OdinDocTypeIndex index = w->type_cache.entries[i].value;
OdinDocTypeIndex index = entry.value;
map_set(&w->type_cache, type, index);
return index;
}
@@ -750,7 +749,7 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
}
return type_index;
}
OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
gb_internal OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
if (e == nullptr) {
return 0;
}
@@ -860,7 +859,6 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
if (e->flags & EntityFlag_Param) {
if (e->flags & EntityFlag_Using) { flags |= OdinDocEntityFlag_Param_Using; }
if (e->flags & EntityFlag_ConstInput) { flags |= OdinDocEntityFlag_Param_Const; }
if (e->flags & EntityFlag_AutoCast) { flags |= OdinDocEntityFlag_Param_AutoCast; }
if (e->flags & EntityFlag_Ellipsis) { flags |= OdinDocEntityFlag_Param_Ellipsis; }
if (e->flags & EntityFlag_NoAlias) { flags |= OdinDocEntityFlag_Param_NoAlias; }
if (e->flags & EntityFlag_AnyInt) { flags |= OdinDocEntityFlag_Param_AnyInt; }
@@ -911,26 +909,24 @@ OdinDocEntityIndex odin_doc_add_entity(OdinDocWriter *w, Entity *e) {
return doc_entity_index;
}
void odin_doc_update_entities(OdinDocWriter *w) {
gb_internal void odin_doc_update_entities(OdinDocWriter *w) {
{
// NOTE(bill): Double pass, just in case entities are created on odin_doc_type
auto entities = array_make<Entity *>(heap_allocator(), w->entity_cache.entries.count);
auto entities = array_make<Entity *>(heap_allocator(), 0, w->entity_cache.count);
defer (array_free(&entities));
for_array(i, w->entity_cache.entries) {
Entity *e = w->entity_cache.entries[i].key;
entities[i] = e;
for (auto const &entry : w->entity_cache) {
array_add(&entities, entry.key);
}
for_array(i, entities) {
Entity *e = entities[i];
for (Entity *e : entities) {
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
gb_unused(type_index);
}
}
for_array(i, w->entity_cache.entries) {
Entity *e = w->entity_cache.entries[i].key;
OdinDocEntityIndex entity_index = w->entity_cache.entries[i].value;
for (auto const &entry : w->entity_cache) {
Entity *e = entry.key;
OdinDocEntityIndex entity_index = entry.value;
OdinDocTypeIndex type_index = odin_doc_type(w, e->type);
OdinDocEntityIndex foreign_library = 0;
@@ -948,8 +944,8 @@ void odin_doc_update_entities(OdinDocWriter *w) {
auto pges = array_make<OdinDocEntityIndex>(heap_allocator(), 0, e->ProcGroup.entities.count);
defer (array_free(&pges));
for_array(j, e->ProcGroup.entities) {
OdinDocEntityIndex index = odin_doc_add_entity(w, e->ProcGroup.entities[j]);
for (Entity *entity : e->ProcGroup.entities) {
OdinDocEntityIndex index = odin_doc_add_entity(w, entity);
array_add(&pges, index);
}
grouped_entities = odin_write_slice(w, pges.data, pges.count);
@@ -968,7 +964,7 @@ void odin_doc_update_entities(OdinDocWriter *w) {
OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPackage *pkg) {
gb_internal OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPackage *pkg) {
if (pkg->scope == nullptr) {
return {};
}
@@ -976,12 +972,12 @@ OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPa
return {};
}
auto entries = array_make<OdinDocScopeEntry>(heap_allocator(), 0, w->entity_cache.entries.count);
auto entries = array_make<OdinDocScopeEntry>(heap_allocator(), 0, w->entity_cache.count);
defer (array_free(&entries));
for_array(i, pkg->scope->elements.entries) {
String name = pkg->scope->elements.entries[i].key.string;
Entity *e = pkg->scope->elements.entries[i].value;
for (auto const &element : pkg->scope->elements) {
String name = element.key;
Entity *e = element.value;
switch (e->kind) {
case Entity_Invalid:
case Entity_Nil:
@@ -1018,11 +1014,11 @@ OdinDocArray<OdinDocScopeEntry> odin_doc_add_pkg_entries(OdinDocWriter *w, AstPa
}
void odin_doc_write_docs(OdinDocWriter *w) {
auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.entries.count);
gb_internal void odin_doc_write_docs(OdinDocWriter *w) {
auto pkgs = array_make<AstPackage *>(heap_allocator(), 0, w->info->packages.count);
defer (array_free(&pkgs));
for_array(i, w->info->packages.entries) {
AstPackage *pkg = w->info->packages.entries[i].value;
for (auto const &entry : w->info->packages) {
AstPackage *pkg = entry.value;
if (build_context.cmd_doc_flags & CmdDocFlag_AllPackages) {
array_add(&pkgs, pkg);
} else {
@@ -1093,7 +1089,7 @@ void odin_doc_write_docs(OdinDocWriter *w) {
}
void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) {
gb_internal void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) {
gbFile f = {};
gbFileError err = gb_file_open_mode(&f, gbFileMode_Write, filename);
if (err != gbFileError_None) {
@@ -1108,7 +1104,7 @@ void odin_doc_write_to_file(OdinDocWriter *w, char const *filename) {
}
}
void odin_doc_write(CheckerInfo *info, char const *filename) {
gb_internal void odin_doc_write(CheckerInfo *info, char const *filename) {
OdinDocWriter w_ = {};
OdinDocWriter *w = &w_;
defer (odin_doc_writer_destroy(w));
+30 -36
View File
@@ -26,7 +26,7 @@ enum EntityKind {
Entity_Count,
};
String const entity_strings[] = {
gb_global String const entity_strings[] = {
#define ENTITY_KIND(k) {cast(u8 *)#k, gb_size_of(#k)-1},
ENTITY_KINDS
#undef ENTITY_KIND
@@ -61,7 +61,7 @@ enum EntityFlag : u64 {
EntityFlag_ProcBodyChecked = 1ull<<21,
EntityFlag_CVarArg = 1ull<<22,
EntityFlag_AutoCast = 1ull<<23,
EntityFlag_AnyInt = 1ull<<24,
EntityFlag_Disabled = 1ull<<25,
@@ -116,7 +116,7 @@ struct ParameterValue {
};
};
bool has_parameter_value(ParameterValue const &param_value) {
gb_internal gb_inline bool has_parameter_value(ParameterValue const &param_value) {
if (param_value.kind != ParameterValue_Invalid) {
return true;
}
@@ -130,7 +130,7 @@ enum EntityConstantFlags : u32 {
EntityConstantFlag_ImplicitEnumValue = 1<<0,
};
enum ProcedureOptimizationMode : u32 {
enum ProcedureOptimizationMode : u8 {
ProcedureOptimizationMode_Default,
ProcedureOptimizationMode_None,
ProcedureOptimizationMode_Minimal,
@@ -151,10 +151,9 @@ struct TypeNameObjCMetadata {
Array<TypeNameObjCMetadataEntry> value_entries;
};
TypeNameObjCMetadata *create_type_name_obj_c_metadata() {
gb_internal TypeNameObjCMetadata *create_type_name_obj_c_metadata() {
TypeNameObjCMetadata *md = gb_alloc_item(permanent_allocator(), TypeNameObjCMetadata);
md->mutex = gb_alloc_item(permanent_allocator(), BlockingMutex);
mutex_init(md->mutex);
array_init(&md->type_entries, heap_allocator());
array_init(&md->value_entries, heap_allocator());
return md;
@@ -234,6 +233,9 @@ struct Entity {
String link_name;
String link_prefix;
DeferredProcedure deferred_procedure;
struct GenProcsData *gen_procs;
BlockingMutex gen_procs_mutex;
ProcedureOptimizationMode optimization_mode;
bool is_foreign : 1;
bool is_export : 1;
@@ -266,7 +268,7 @@ struct Entity {
};
};
bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) {
gb_internal bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) {
switch (kind) {
case Entity_Builtin:
return allow_builtin;
@@ -278,7 +280,7 @@ bool is_entity_kind_exported(EntityKind kind, bool allow_builtin = false) {
return true;
}
bool is_entity_exported(Entity *e, bool allow_builtin = false) {
gb_internal bool is_entity_exported(Entity *e, bool allow_builtin = false) {
// TODO(bill): Determine the actual exportation rules for imports of entities
GB_ASSERT(e != nullptr);
if (!is_entity_kind_exported(e->kind, allow_builtin)) {
@@ -300,7 +302,7 @@ bool is_entity_exported(Entity *e, bool allow_builtin = false) {
return true;
}
bool entity_has_deferred_procedure(Entity *e) {
gb_internal bool entity_has_deferred_procedure(Entity *e) {
GB_ASSERT(e != nullptr);
if (e->kind == Entity_Procedure) {
return e->Procedure.deferred_procedure.entity != nullptr;
@@ -311,7 +313,7 @@ bool entity_has_deferred_procedure(Entity *e) {
gb_global std::atomic<u64> global_entity_id;
Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
gb_internal Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
gbAllocator a = permanent_allocator();
Entity *entity = gb_alloc_item(a, Entity);
entity->kind = kind;
@@ -323,13 +325,13 @@ Entity *alloc_entity(EntityKind kind, Scope *scope, Token token, Type *type) {
return entity;
}
Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
gb_internal Entity *alloc_entity_variable(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
Entity *entity = alloc_entity(Entity_Variable, scope, token, type);
entity->state = state;
return entity;
}
Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) {
gb_internal Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast *using_expr) {
GB_ASSERT(parent != nullptr);
token.pos = parent->token.pos;
Entity *entity = alloc_entity(Entity_Variable, parent->scope, token, type);
@@ -343,19 +345,19 @@ Entity *alloc_entity_using_variable(Entity *parent, Token token, Type *type, Ast
}
Entity *alloc_entity_constant(Scope *scope, Token token, Type *type, ExactValue value) {
gb_internal Entity *alloc_entity_constant(Scope *scope, Token token, Type *type, ExactValue value) {
Entity *entity = alloc_entity(Entity_Constant, scope, token, type);
entity->Constant.value = value;
return entity;
}
Entity *alloc_entity_type_name(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
gb_internal Entity *alloc_entity_type_name(Scope *scope, Token token, Type *type, EntityState state = EntityState_Unresolved) {
Entity *entity = alloc_entity(Entity_TypeName, scope, token, type);
entity->state = state;
return entity;
}
Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
gb_internal Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using, bool is_value) {
Entity *entity = alloc_entity_variable(scope, token, type);
entity->flags |= EntityFlag_Used;
entity->flags |= EntityFlag_Param;
@@ -366,7 +368,7 @@ Entity *alloc_entity_param(Scope *scope, Token token, Type *type, bool is_using,
}
Entity *alloc_entity_const_param(Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
gb_internal Entity *alloc_entity_const_param(Scope *scope, Token token, Type *type, ExactValue value, bool poly_const) {
Entity *entity = alloc_entity_constant(scope, token, type, value);
entity->flags |= EntityFlag_Used;
if (poly_const) entity->flags |= EntityFlag_PolyConst;
@@ -375,7 +377,7 @@ Entity *alloc_entity_const_param(Scope *scope, Token token, Type *type, ExactVal
}
Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using, i32 field_index, EntityState state = EntityState_Unresolved) {
gb_internal Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using, i32 field_index, EntityState state = EntityState_Unresolved) {
Entity *entity = alloc_entity_variable(scope, token, type);
entity->Variable.field_index = field_index;
if (is_using) entity->flags |= EntityFlag_Using;
@@ -384,7 +386,7 @@ Entity *alloc_entity_field(Scope *scope, Token token, Type *type, bool is_using,
return entity;
}
Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field_index) {
gb_internal Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field_index) {
Entity *entity = alloc_entity_variable(scope, token, type);
entity->Variable.field_index = field_index;
entity->flags |= EntityFlag_Field;
@@ -393,26 +395,18 @@ Entity *alloc_entity_array_elem(Scope *scope, Token token, Type *type, i32 field
return entity;
}
Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags) {
gb_internal Entity *alloc_entity_procedure(Scope *scope, Token token, Type *signature_type, u64 tags) {
Entity *entity = alloc_entity(Entity_Procedure, scope, token, signature_type);
entity->Procedure.tags = tags;
return entity;
}
Entity *alloc_entity_proc_group(Scope *scope, Token token, Type *type) {
gb_internal Entity *alloc_entity_proc_group(Scope *scope, Token token, Type *type) {
Entity *entity = alloc_entity(Entity_ProcGroup, scope, token, type);
return entity;
}
Entity *alloc_entity_builtin(Scope *scope, Token token, Type *type, i32 id) {
Entity *entity = alloc_entity(Entity_Builtin, scope, token, type);
entity->Builtin.id = id;
entity->state = EntityState_Resolved;
return entity;
}
Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
gb_internal Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
String path, String name, Scope *import_scope) {
Entity *entity = alloc_entity(Entity_ImportName, scope, token, type);
entity->ImportName.path = path;
@@ -422,7 +416,7 @@ Entity *alloc_entity_import_name(Scope *scope, Token token, Type *type,
return entity;
}
Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type,
gb_internal Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type,
Slice<String> paths, String name) {
Entity *entity = alloc_entity(Entity_LibraryName, scope, token, type);
entity->LibraryName.paths = paths;
@@ -435,12 +429,12 @@ Entity *alloc_entity_library_name(Scope *scope, Token token, Type *type,
Entity *alloc_entity_nil(String name, Type *type) {
gb_internal Entity *alloc_entity_nil(String name, Type *type) {
Entity *entity = alloc_entity(Entity_Nil, nullptr, make_token_ident(name), type);
return entity;
}
Entity *alloc_entity_label(Scope *scope, Token token, Type *type, Ast *node, Ast *parent) {
gb_internal Entity *alloc_entity_label(Scope *scope, Token token, Type *type, Ast *node, Ast *parent) {
Entity *entity = alloc_entity(Entity_Label, scope, token, type);
entity->Label.node = node;
entity->Label.parent = parent;
@@ -448,15 +442,15 @@ Entity *alloc_entity_label(Scope *scope, Token token, Type *type, Ast *node, Ast
return entity;
}
Entity *alloc_entity_dummy_variable(Scope *scope, Token token) {
gb_internal Entity *alloc_entity_dummy_variable(Scope *scope, Token token) {
token.string = str_lit("_");
return alloc_entity_variable(scope, token, nullptr);
}
Entity *entity_from_expr(Ast *expr);
gb_internal Entity *entity_from_expr(Ast *expr);
Entity *strip_entity_wrapping(Entity *e) {
gb_internal Entity *strip_entity_wrapping(Entity *e) {
if (e == nullptr) {
return nullptr;
}
@@ -469,7 +463,7 @@ Entity *strip_entity_wrapping(Entity *e) {
return e;
}
Entity *strip_entity_wrapping(Ast *expr) {
gb_internal Entity *strip_entity_wrapping(Ast *expr) {
Entity *e = entity_from_expr(expr);
return strip_entity_wrapping(e);
}
+31 -35
View File
@@ -17,15 +17,11 @@ gb_global ErrorCollector global_error_collector;
#define MAX_ERROR_COLLECTOR_COUNT (36)
bool any_errors(void) {
gb_internal bool any_errors(void) {
return global_error_collector.count.load() != 0;
}
void init_global_error_collector(void) {
mutex_init(&global_error_collector.mutex);
mutex_init(&global_error_collector.block_mutex);
mutex_init(&global_error_collector.error_out_mutex);
mutex_init(&global_error_collector.string_mutex);
gb_internal void init_global_error_collector(void) {
array_init(&global_error_collector.errors, heap_allocator());
array_init(&global_error_collector.error_buffer, heap_allocator());
array_init(&global_file_path_strings, heap_allocator(), 1, 4096);
@@ -35,9 +31,9 @@ void init_global_error_collector(void) {
// temporary
// defined in build_settings.cpp
char *token_pos_to_string(TokenPos const &pos);
gb_internal char *token_pos_to_string(TokenPos const &pos);
bool set_file_path_string(i32 index, String const &path) {
gb_internal bool set_file_path_string(i32 index, String const &path) {
bool ok = false;
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.string_mutex);
@@ -55,7 +51,7 @@ bool set_file_path_string(i32 index, String const &path) {
return ok;
}
bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
gb_internal bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
bool ok = false;
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.string_mutex);
@@ -73,7 +69,7 @@ bool thread_safe_set_ast_file_from_id(i32 index, AstFile *file) {
return ok;
}
String get_file_path_string(i32 index) {
gb_internal String get_file_path_string(i32 index) {
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.string_mutex);
@@ -86,7 +82,7 @@ String get_file_path_string(i32 index) {
return path;
}
AstFile *thread_safe_get_ast_file_from_id(i32 index) {
gb_internal AstFile *thread_safe_get_ast_file_from_id(i32 index) {
GB_ASSERT(index >= 0);
mutex_lock(&global_error_collector.string_mutex);
@@ -101,12 +97,12 @@ AstFile *thread_safe_get_ast_file_from_id(i32 index) {
void begin_error_block(void) {
gb_internal void begin_error_block(void) {
mutex_lock(&global_error_collector.block_mutex);
global_error_collector.in_block.store(true);
}
void end_error_block(void) {
gb_internal void end_error_block(void) {
if (global_error_collector.error_buffer.count > 0) {
isize n = global_error_collector.error_buffer.count;
u8 *text = gb_alloc_array(permanent_allocator(), u8, n+1);
@@ -127,7 +123,7 @@ void end_error_block(void) {
#define ERROR_OUT_PROC(name) void name(char const *fmt, va_list va)
typedef ERROR_OUT_PROC(ErrorOutProc);
ERROR_OUT_PROC(default_error_out_va) {
gb_internal ERROR_OUT_PROC(default_error_out_va) {
gbFile *f = gb_file_get_standard(gbFileStandard_Error);
char buf[4096] = {};
@@ -154,15 +150,15 @@ ERROR_OUT_PROC(default_error_out_va) {
}
ErrorOutProc *error_out_va = default_error_out_va;
gb_global ErrorOutProc *error_out_va = default_error_out_va;
// NOTE: defined in build_settings.cpp
bool global_warnings_as_errors(void);
bool global_ignore_warnings(void);
bool show_error_line(void);
gbString get_file_line_as_string(TokenPos const &pos, i32 *offset);
gb_internal bool global_warnings_as_errors(void);
gb_internal bool global_ignore_warnings(void);
gb_internal bool show_error_line(void);
gb_internal gbString get_file_line_as_string(TokenPos const &pos, i32 *offset);
void error_out(char const *fmt, ...) {
gb_internal void error_out(char const *fmt, ...) {
va_list va;
va_start(va, fmt);
error_out_va(fmt, va);
@@ -170,7 +166,7 @@ void error_out(char const *fmt, ...) {
}
bool show_error_on_line(TokenPos const &pos, TokenPos end) {
gb_internal bool show_error_on_line(TokenPos const &pos, TokenPos end) {
if (!show_error_line()) {
return false;
}
@@ -237,7 +233,7 @@ bool show_error_on_line(TokenPos const &pos, TokenPos end) {
return false;
}
void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
global_error_collector.count.fetch_add(1);
mutex_lock(&global_error_collector.mutex);
@@ -257,7 +253,7 @@ void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
}
}
void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
if (global_warnings_as_errors()) {
error_va(pos, end, fmt, va);
return;
@@ -280,11 +276,11 @@ void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va)
}
void error_line_va(char const *fmt, va_list va) {
gb_internal void error_line_va(char const *fmt, va_list va) {
error_out_va(fmt, va);
}
void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
mutex_lock(&global_error_collector.mutex);
global_error_collector.count++;
// NOTE(bill): Duplicate error, skip it
@@ -303,7 +299,7 @@ void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
}
void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
mutex_lock(&global_error_collector.mutex);
global_error_collector.count++;
// NOTE(bill): Duplicate error, skip it
@@ -323,7 +319,7 @@ void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list
}
}
void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
gb_internal void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
if (global_warnings_as_errors()) {
syntax_error_va(pos, end, fmt, va);
return;
@@ -347,21 +343,21 @@ void syntax_warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_li
void warning(Token const &token, char const *fmt, ...) {
gb_internal void warning(Token const &token, char const *fmt, ...) {
va_list va;
va_start(va, fmt);
warning_va(token.pos, {}, fmt, va);
va_end(va);
}
void error(Token const &token, char const *fmt, ...) {
gb_internal void error(Token const &token, char const *fmt, ...) {
va_list va;
va_start(va, fmt);
error_va(token.pos, {}, fmt, va);
va_end(va);
}
void error(TokenPos pos, char const *fmt, ...) {
gb_internal void error(TokenPos pos, char const *fmt, ...) {
va_list va;
va_start(va, fmt);
Token token = {};
@@ -370,7 +366,7 @@ void error(TokenPos pos, char const *fmt, ...) {
va_end(va);
}
void error_line(char const *fmt, ...) {
gb_internal void error_line(char const *fmt, ...) {
va_list va;
va_start(va, fmt);
error_line_va(fmt, va);
@@ -378,21 +374,21 @@ void error_line(char const *fmt, ...) {
}
void syntax_error(Token const &token, char const *fmt, ...) {
gb_internal void syntax_error(Token const &token, char const *fmt, ...) {
va_list va;
va_start(va, fmt);
syntax_error_va(token.pos, {}, fmt, va);
va_end(va);
}
void syntax_error(TokenPos pos, char const *fmt, ...) {
gb_internal void syntax_error(TokenPos pos, char const *fmt, ...) {
va_list va;
va_start(va, fmt);
syntax_error_va(pos, {}, fmt, va);
va_end(va);
}
void syntax_warning(Token const &token, char const *fmt, ...) {
gb_internal void syntax_warning(Token const &token, char const *fmt, ...) {
va_list va;
va_start(va, fmt);
syntax_warning_va(token.pos, {}, fmt, va);
@@ -400,7 +396,7 @@ void syntax_warning(Token const &token, char const *fmt, ...) {
}
void compiler_error(char const *fmt, ...) {
gb_internal void compiler_error(char const *fmt, ...) {
va_list va;
va_start(va, fmt);
+82 -92
View File
@@ -6,7 +6,7 @@ struct Ast;
struct HashKey;
struct Type;
struct Entity;
bool are_types_identical(Type *x, Type *y);
gb_internal bool are_types_identical(Type *x, Type *y);
struct Complex128 {
f64 real, imag;
@@ -15,16 +15,6 @@ struct Quaternion256 {
f64 imag, jmag, kmag, real;
};
Quaternion256 quaternion256_inverse(Quaternion256 x) {
f64 invmag2 = 1.0 / (x.real*x.real + x.imag*x.imag + x.jmag*x.jmag + x.kmag*x.kmag);
x.real = +x.real * invmag2;
x.imag = -x.imag * invmag2;
x.jmag = -x.jmag * invmag2;
x.kmag = -x.kmag * invmag2;
return x;
}
enum ExactValueKind {
ExactValue_Invalid = 0,
@@ -60,7 +50,7 @@ struct ExactValue {
gb_global ExactValue const empty_exact_value = {};
uintptr hash_exact_value(ExactValue v) {
gb_internal uintptr hash_exact_value(ExactValue v) {
mutex_lock(&hash_exact_value_mutex);
defer (mutex_unlock(&hash_exact_value_mutex));
@@ -70,7 +60,7 @@ uintptr hash_exact_value(ExactValue v) {
case ExactValue_Bool:
return gb_fnv32a(&v.value_bool, gb_size_of(v.value_bool));
case ExactValue_String:
return ptr_map_hash_key(string_intern(v.value_string));
return gb_fnv32a(v.value_string.text, v.value_string.len);
case ExactValue_Integer:
{
u32 key = gb_fnv32a(v.value_integer.dp, gb_size_of(*v.value_integer.dp) * v.value_integer.used);
@@ -97,44 +87,44 @@ uintptr hash_exact_value(ExactValue v) {
}
ExactValue exact_value_compound(Ast *node) {
gb_internal ExactValue exact_value_compound(Ast *node) {
ExactValue result = {ExactValue_Compound};
result.value_compound = node;
return result;
}
ExactValue exact_value_bool(bool b) {
gb_internal ExactValue exact_value_bool(bool b) {
ExactValue result = {ExactValue_Bool};
result.value_bool = (b != 0);
return result;
}
ExactValue exact_value_string(String string) {
gb_internal ExactValue exact_value_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
ExactValue result = {ExactValue_String};
result.value_string = string;
return result;
}
ExactValue exact_value_i64(i64 i) {
gb_internal ExactValue exact_value_i64(i64 i) {
ExactValue result = {ExactValue_Integer};
big_int_from_i64(&result.value_integer, i);
return result;
}
ExactValue exact_value_u64(u64 i) {
gb_internal ExactValue exact_value_u64(u64 i) {
ExactValue result = {ExactValue_Integer};
big_int_from_u64(&result.value_integer, i);
return result;
}
ExactValue exact_value_float(f64 f) {
gb_internal ExactValue exact_value_float(f64 f) {
ExactValue result = {ExactValue_Float};
result.value_float = f;
return result;
}
ExactValue exact_value_complex(f64 real, f64 imag) {
gb_internal ExactValue exact_value_complex(f64 real, f64 imag) {
ExactValue result = {ExactValue_Complex};
result.value_complex = gb_alloc_item(permanent_allocator(), Complex128);
result.value_complex->real = real;
@@ -142,7 +132,7 @@ ExactValue exact_value_complex(f64 real, f64 imag) {
return result;
}
ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
gb_internal ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
ExactValue result = {ExactValue_Quaternion};
result.value_quaternion = gb_alloc_item(permanent_allocator(), Quaternion256);
result.value_quaternion->real = real;
@@ -152,27 +142,27 @@ ExactValue exact_value_quaternion(f64 real, f64 imag, f64 jmag, f64 kmag) {
return result;
}
ExactValue exact_value_pointer(i64 ptr) {
gb_internal ExactValue exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
return result;
}
ExactValue exact_value_procedure(Ast *node) {
gb_internal ExactValue exact_value_procedure(Ast *node) {
ExactValue result = {ExactValue_Procedure};
result.value_procedure = node;
return result;
}
ExactValue exact_value_typeid(Type *type) {
gb_internal ExactValue exact_value_typeid(Type *type) {
ExactValue result = {ExactValue_Typeid};
result.value_typeid = type;
return result;
}
ExactValue exact_value_integer_from_string(String const &string) {
gb_internal ExactValue exact_value_integer_from_string(String const &string) {
ExactValue result = {ExactValue_Integer};
bool success;
big_int_from_string(&result.value_integer, string, &success);
@@ -184,7 +174,7 @@ ExactValue exact_value_integer_from_string(String const &string) {
f64 float_from_string(String string) {
gb_internal f64 float_from_string(String string) {
isize i = 0;
u8 *str = string.text;
isize len = string.len;
@@ -262,7 +252,7 @@ f64 float_from_string(String string) {
return sign * (frac ? (value / scale) : (value * scale));
}
ExactValue exact_value_float_from_string(String string) {
gb_internal ExactValue exact_value_float_from_string(String string) {
if (string.len > 2 && string[0] == '0' && string[1] == 'h') {
isize digit_count = 0;
@@ -298,7 +288,7 @@ ExactValue exact_value_float_from_string(String string) {
}
ExactValue exact_value_from_basic_literal(TokenKind kind, String const &string) {
gb_internal ExactValue exact_value_from_basic_literal(TokenKind kind, String const &string) {
switch (kind) {
case Token_String: return exact_value_string(string);
case Token_Integer: return exact_value_integer_from_string(string);
@@ -330,7 +320,7 @@ ExactValue exact_value_from_basic_literal(TokenKind kind, String const &string)
return result;
}
ExactValue exact_value_to_integer(ExactValue v) {
gb_internal ExactValue exact_value_to_integer(ExactValue v) {
switch (v.kind) {
case ExactValue_Bool: {
i64 i = 0;
@@ -357,7 +347,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
return r;
}
ExactValue exact_value_to_float(ExactValue v) {
gb_internal ExactValue exact_value_to_float(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_float(big_int_to_f64(&v.value_integer));
@@ -368,7 +358,7 @@ ExactValue exact_value_to_float(ExactValue v) {
return r;
}
ExactValue exact_value_to_complex(ExactValue v) {
gb_internal ExactValue exact_value_to_complex(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_complex(big_int_to_f64(&v.value_integer), 0);
@@ -383,7 +373,7 @@ ExactValue exact_value_to_complex(ExactValue v) {
v.value_complex = gb_alloc_item(permanent_allocator(), Complex128);
return r;
}
ExactValue exact_value_to_quaternion(ExactValue v) {
gb_internal ExactValue exact_value_to_quaternion(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(big_int_to_f64(&v.value_integer), 0, 0, 0);
@@ -399,7 +389,7 @@ ExactValue exact_value_to_quaternion(ExactValue v) {
return r;
}
ExactValue exact_value_real(ExactValue v) {
gb_internal ExactValue exact_value_real(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
@@ -413,7 +403,7 @@ ExactValue exact_value_real(ExactValue v) {
return r;
}
ExactValue exact_value_imag(ExactValue v) {
gb_internal ExactValue exact_value_imag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
@@ -427,7 +417,7 @@ ExactValue exact_value_imag(ExactValue v) {
return r;
}
ExactValue exact_value_jmag(ExactValue v) {
gb_internal ExactValue exact_value_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
@@ -440,7 +430,7 @@ ExactValue exact_value_jmag(ExactValue v) {
return r;
}
ExactValue exact_value_kmag(ExactValue v) {
gb_internal ExactValue exact_value_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
case ExactValue_Float:
@@ -453,60 +443,60 @@ ExactValue exact_value_kmag(ExactValue v) {
return r;
}
ExactValue exact_value_make_imag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_complex(0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_complex(0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
// gb_internal ExactValue exact_value_make_imag(ExactValue v) {
// switch (v.kind) {
// case ExactValue_Integer:
// return exact_value_complex(0, exact_value_to_float(v).value_float);
// case ExactValue_Float:
// return exact_value_complex(0, v.value_float);
// default:
// GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
// }
// ExactValue r = {ExactValue_Invalid};
// return r;
// }
ExactValue exact_value_make_jmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
case ExactValue_Float:
return exact_value_quaternion(0, 0, v.value_float, 0);
default:
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
// gb_internal ExactValue exact_value_make_jmag(ExactValue v) {
// switch (v.kind) {
// case ExactValue_Integer:
// return exact_value_quaternion(0, 0, exact_value_to_float(v).value_float, 0);
// case ExactValue_Float:
// return exact_value_quaternion(0, 0, v.value_float, 0);
// default:
// GB_PANIC("Expected an integer or float type for 'exact_value_make_jmag'");
// }
// ExactValue r = {ExactValue_Invalid};
// return r;
// }
ExactValue exact_value_make_kmag(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
case ExactValue_Float:
return exact_value_quaternion(0, 0, 0, v.value_float);
default:
GB_PANIC("Expected an integer or float type for 'exact_value_make_imag'");
}
ExactValue r = {ExactValue_Invalid};
return r;
}
// gb_internal ExactValue exact_value_make_kmag(ExactValue v) {
// switch (v.kind) {
// case ExactValue_Integer:
// return exact_value_quaternion(0, 0, 0, exact_value_to_float(v).value_float);
// case ExactValue_Float:
// return exact_value_quaternion(0, 0, 0, v.value_float);
// default:
// GB_PANIC("Expected an integer or float type for 'exact_value_make_kmag'");
// }
// ExactValue r = {ExactValue_Invalid};
// return r;
// }
i64 exact_value_to_i64(ExactValue v) {
gb_internal i64 exact_value_to_i64(ExactValue v) {
v = exact_value_to_integer(v);
if (v.kind == ExactValue_Integer) {
return big_int_to_i64(&v.value_integer);
}
return 0;
}
u64 exact_value_to_u64(ExactValue v) {
gb_internal u64 exact_value_to_u64(ExactValue v) {
v = exact_value_to_integer(v);
if (v.kind == ExactValue_Integer) {
return big_int_to_u64(&v.value_integer);
}
return 0;
}
f64 exact_value_to_f64(ExactValue v) {
gb_internal f64 exact_value_to_f64(ExactValue v) {
v = exact_value_to_float(v);
if (v.kind == ExactValue_Float) {
return v.value_float;
@@ -519,7 +509,7 @@ f64 exact_value_to_f64(ExactValue v) {
ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, bool is_unsigned) {
gb_internal ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision, bool is_unsigned) {
switch (op) {
case Token_Add: {
switch (v.kind) {
@@ -596,7 +586,7 @@ failure:
}
// NOTE(bill): Make sure things are evaluated in correct order
i32 exact_value_order(ExactValue const &v) {
gb_internal i32 exact_value_order(ExactValue const &v) {
switch (v.kind) {
case ExactValue_Invalid:
case ExactValue_Compound:
@@ -623,7 +613,7 @@ i32 exact_value_order(ExactValue const &v) {
}
}
void match_exact_values(ExactValue *x, ExactValue *y) {
gb_internal void match_exact_values(ExactValue *x, ExactValue *y) {
if (exact_value_order(*y) < exact_value_order(*x)) {
match_exact_values(y, x);
return;
@@ -687,7 +677,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
}
// TODO(bill): Allow for pointer arithmetic? Or are pointer slices good enough?
ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) {
gb_internal ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y) {
match_exact_values(&x, &y);
switch (x.kind) {
@@ -846,32 +836,32 @@ error:; // NOTE(bill): MSVC accepts this??? apparently you cannot declare variab
return empty_exact_value;
}
gb_inline ExactValue exact_value_add(ExactValue const &x, ExactValue const &y) {
gb_internal gb_inline ExactValue exact_value_add(ExactValue const &x, ExactValue const &y) {
return exact_binary_operator_value(Token_Add, x, y);
}
gb_inline ExactValue exact_value_sub(ExactValue const &x, ExactValue const &y) {
gb_internal gb_inline ExactValue exact_value_sub(ExactValue const &x, ExactValue const &y) {
return exact_binary_operator_value(Token_Sub, x, y);
}
gb_inline ExactValue exact_value_mul(ExactValue const &x, ExactValue const &y) {
gb_internal gb_inline ExactValue exact_value_mul(ExactValue const &x, ExactValue const &y) {
return exact_binary_operator_value(Token_Mul, x, y);
}
gb_inline ExactValue exact_value_quo(ExactValue const &x, ExactValue const &y) {
gb_internal gb_inline ExactValue exact_value_quo(ExactValue const &x, ExactValue const &y) {
return exact_binary_operator_value(Token_Quo, x, y);
}
gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactValue const &y) {
gb_internal gb_inline ExactValue exact_value_shift(TokenKind op, ExactValue const &x, ExactValue const &y) {
return exact_binary_operator_value(op, x, y);
}
gb_inline ExactValue exact_value_increment_one(ExactValue const &x) {
gb_internal gb_inline ExactValue exact_value_increment_one(ExactValue const &x) {
return exact_binary_operator_value(Token_Add, x, exact_value_i64(1));
}
i32 cmp_f64(f64 a, f64 b) {
gb_internal gb_inline i32 cmp_f64(f64 a, f64 b) {
return (a > b) - (a < b);
}
bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
gb_internal bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
match_exact_values(&x, &y);
switch (x.kind) {
@@ -969,12 +959,12 @@ bool compare_exact_values(TokenKind op, ExactValue x, ExactValue y) {
return false;
}
Entity *strip_entity_wrapping(Ast *expr);
Entity *strip_entity_wrapping(Entity *e);
gb_internal Entity *strip_entity_wrapping(Ast *expr);
gb_internal Entity *strip_entity_wrapping(Entity *e);
gbString write_expr_to_string(gbString str, Ast *node, bool shorthand);
gb_internal gbString write_expr_to_string(gbString str, Ast *node, bool shorthand);
gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
gb_internal gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize string_limit=36) {
switch (v.kind) {
case ExactValue_Invalid:
return str;
@@ -1017,6 +1007,6 @@ gbString write_exact_value_to_string(gbString str, ExactValue const &v, isize st
return str;
};
gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) {
gb_internal gbString exact_value_to_string(ExactValue const &v, isize string_limit=36) {
return write_exact_value_to_string(gb_string_make(heap_allocator(), ""), v, string_limit);
}
-2
View File
@@ -465,8 +465,6 @@ typedef i32 b32; // NOTE(bill): Prefer this!!!
#if !defined(gb_thread_local)
#if defined(_MSC_VER) && _MSC_VER >= 1300
#define gb_thread_local __declspec(thread)
#elif defined(__GNUC__)
#define gb_thread_local __thread
#else
#define gb_thread_local thread_local
#endif
+220 -107
View File
@@ -1,3 +1,5 @@
#define ALLOW_SPLIT_MULTI_RETURNS true
enum lbArgKind {
lbArg_Direct,
lbArg_Indirect,
@@ -16,21 +18,21 @@ struct lbArgType {
};
i64 lb_sizeof(LLVMTypeRef type);
i64 lb_alignof(LLVMTypeRef type);
gb_internal i64 lb_sizeof(LLVMTypeRef type);
gb_internal i64 lb_alignof(LLVMTypeRef type);
lbArgType lb_arg_type_direct(LLVMTypeRef type, LLVMTypeRef cast_type, LLVMTypeRef pad_type, LLVMAttributeRef attr) {
gb_internal lbArgType lb_arg_type_direct(LLVMTypeRef type, LLVMTypeRef cast_type, LLVMTypeRef pad_type, LLVMAttributeRef attr) {
return lbArgType{lbArg_Direct, type, cast_type, pad_type, attr, nullptr, 0, false};
}
lbArgType lb_arg_type_direct(LLVMTypeRef type) {
gb_internal lbArgType lb_arg_type_direct(LLVMTypeRef type) {
return lb_arg_type_direct(type, nullptr, nullptr, nullptr);
}
lbArgType lb_arg_type_indirect(LLVMTypeRef type, LLVMAttributeRef attr) {
gb_internal lbArgType lb_arg_type_indirect(LLVMTypeRef type, LLVMAttributeRef attr) {
return lbArgType{lbArg_Indirect, type, nullptr, nullptr, attr, nullptr, 0, false};
}
lbArgType lb_arg_type_indirect_byval(LLVMContextRef c, LLVMTypeRef type) {
gb_internal lbArgType lb_arg_type_indirect_byval(LLVMContextRef c, LLVMTypeRef type) {
i64 alignment = lb_alignof(type);
alignment = gb_max(alignment, 8);
@@ -39,7 +41,7 @@ lbArgType lb_arg_type_indirect_byval(LLVMContextRef c, LLVMTypeRef type) {
return lbArgType{lbArg_Indirect, type, nullptr, nullptr, byval_attr, align_attr, alignment, true};
}
lbArgType lb_arg_type_ignore(LLVMTypeRef type) {
gb_internal lbArgType lb_arg_type_ignore(LLVMTypeRef type) {
return lbArgType{lbArg_Ignore, type, nullptr, nullptr, nullptr, nullptr, 0, false};
}
@@ -48,21 +50,29 @@ struct lbFunctionType {
ProcCallingConvention calling_convention;
Array<lbArgType> args;
lbArgType ret;
LLVMTypeRef multiple_return_original_type; // nullptr if not used
isize original_arg_count;
};
i64 llvm_align_formula(i64 off, i64 a) {
gb_internal gbAllocator lb_function_type_args_allocator(void) {
return heap_allocator();
}
gb_internal gb_inline i64 llvm_align_formula(i64 off, i64 a) {
return (off + a - 1) / a * a;
}
bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
gb_internal bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
if (type == nullptr) {
return false;
}
return LLVMGetTypeKind(type) == kind;
}
LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
gb_internal LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
unsigned arg_count = cast(unsigned)ft->args.count;
unsigned offset = 0;
@@ -100,7 +110,9 @@ LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
}
args[arg_index++] = arg_type;
} else if (arg->kind == lbArg_Indirect) {
GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
if (ft->multiple_return_original_type == nullptr || i < ft->original_arg_count) {
GB_ASSERT(!lb_is_type_kind(arg->type, LLVMPointerTypeKind));
}
args[arg_index++] = LLVMPointerType(arg->type, 0);
} else if (arg->kind == lbArg_Ignore) {
// ignore
@@ -118,7 +130,7 @@ LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
// }
void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) {
gb_internal void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) {
if (ft == nullptr) {
return;
}
@@ -147,6 +159,13 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa
LLVMAddAttributeAtIndex(fn, arg_index+1, arg->align_attribute);
}
if (ft->multiple_return_original_type) {
if (ft->original_arg_count <= i) {
LLVMAddAttributeAtIndex(fn, arg_index+1, noalias_attr);
LLVMAddAttributeAtIndex(fn, arg_index+1, nonnull_attr);
}
}
arg_index++;
}
@@ -182,7 +201,7 @@ void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCa
}
i64 lb_sizeof(LLVMTypeRef type) {
gb_internal i64 lb_sizeof(LLVMTypeRef type) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
switch (kind) {
case LLVMVoidTypeKind:
@@ -248,7 +267,7 @@ i64 lb_sizeof(LLVMTypeRef type) {
return 0;
}
i64 lb_alignof(LLVMTypeRef type) {
gb_internal i64 lb_alignof(LLVMTypeRef type) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
switch (kind) {
case LLVMVoidTypeKind:
@@ -307,25 +326,63 @@ i64 lb_alignof(LLVMTypeRef type) {
}
#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, ProcCallingConvention calling_convention)
#define LB_ABI_INFO(name) lbFunctionType *name(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple, ProcCallingConvention calling_convention)
typedef LB_ABI_INFO(lbAbiInfoType);
#define LB_ABI_COMPUTE_RETURN_TYPE(name) lbArgType name(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined, bool return_is_tuple)
typedef LB_ABI_COMPUTE_RETURN_TYPE(lbAbiComputeReturnType);
gb_internal lbArgType lb_abi_modify_return_is_tuple(lbFunctionType *ft, LLVMContextRef c, LLVMTypeRef return_type, lbAbiComputeReturnType *compute_return_type) {
GB_ASSERT(return_type != nullptr);
GB_ASSERT(compute_return_type != nullptr);
lbArgType return_arg = {};
if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
unsigned field_count = LLVMCountStructElementTypes(return_type);
if (field_count > 1) {
ft->original_arg_count = ft->args.count;
ft->multiple_return_original_type = return_type;
for (unsigned i = 0; i < field_count-1; i++) {
LLVMTypeRef field_type = LLVMStructGetTypeAtIndex(return_type, i);
LLVMTypeRef field_pointer_type = LLVMPointerType(field_type, 0);
lbArgType ret_partial = lb_arg_type_direct(field_pointer_type);
array_add(&ft->args, ret_partial);
}
// override the return type for the last field
LLVMTypeRef new_return_type = LLVMStructGetTypeAtIndex(return_type, field_count-1);
return_arg = compute_return_type(ft, c, new_return_type, true, false);
}
}
return return_arg;
}
#define LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO() do { \
if (return_is_tuple) { \
lbArgType new_return_type = lb_abi_modify_return_is_tuple(ft, c, return_type, compute_return_type); \
if (new_return_type.type != nullptr) { \
return new_return_type; \
} \
} \
} while (0)
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
namespace lbAbi386 {
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
LB_ABI_INFO(abi_info) {
gb_internal LB_ABI_INFO(abi_info) {
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
ft->ctx = c;
ft->args = compute_arg_types(c, arg_types, arg_count);
ft->ret = compute_return_type(c, return_type, return_is_defined);
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
ft->calling_convention = calling_convention;
return ft;
}
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
if (!is_return && lb_sizeof(type) > 8) {
return lb_arg_type_indirect(type, nullptr);
}
@@ -352,8 +409,8 @@ namespace lbAbi386 {
return lb_arg_type_direct(type, nullptr, nullptr, attr);
}
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
for (unsigned i = 0; i < arg_count; i++) {
LLVMTypeRef t = arg_types[i];
@@ -372,7 +429,7 @@ namespace lbAbi386 {
return args;
}
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
if (!return_is_defined) {
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
@@ -383,6 +440,9 @@ namespace lbAbi386 {
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
}
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
return lb_arg_type_indirect(return_type, attr);
}
@@ -391,20 +451,20 @@ namespace lbAbi386 {
};
namespace lbAbiAmd64Win64 {
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
LB_ABI_INFO(abi_info) {
gb_internal LB_ABI_INFO(abi_info) {
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
ft->ctx = c;
ft->args = compute_arg_types(c, arg_types, arg_count);
ft->ret = lbAbi386::compute_return_type(c, return_type, return_is_defined);
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
ft->calling_convention = calling_convention;
return ft;
}
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
for (unsigned i = 0; i < arg_count; i++) {
LLVMTypeRef t = arg_types[i];
@@ -428,6 +488,26 @@ namespace lbAbiAmd64Win64 {
}
return args;
}
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
if (!return_is_defined) {
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
i64 sz = lb_sizeof(return_type);
switch (sz) {
case 1: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 8), nullptr, nullptr);
case 2: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 16), nullptr, nullptr);
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
}
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
return lb_arg_type_indirect(return_type, attr);
}
return lbAbi386::non_struct(c, return_type, true);
}
};
// NOTE(bill): I hate `namespace` in C++ but this is just because I don't want to prefix everything
@@ -450,7 +530,7 @@ namespace lbAbiAmd64SysV {
RegClass_Memory,
};
bool is_sse(RegClass reg_class) {
gb_internal bool is_sse(RegClass reg_class) {
switch (reg_class) {
case RegClass_SSEFs:
case RegClass_SSEFv:
@@ -466,7 +546,7 @@ namespace lbAbiAmd64SysV {
return false;
}
void all_mem(Array<RegClass> *cs) {
gb_internal void all_mem(Array<RegClass> *cs) {
for_array(i, *cs) {
(*cs)[i] = RegClass_Memory;
}
@@ -478,19 +558,19 @@ namespace lbAbiAmd64SysV {
Amd64TypeAttribute_StructRect,
};
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off);
void fixup(LLVMTypeRef t, Array<RegClass> *cls);
lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention);
Array<RegClass> classify(LLVMTypeRef t);
LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes);
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off);
gb_internal void fixup(LLVMTypeRef t, Array<RegClass> *cls);
gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention);
gb_internal Array<RegClass> classify(LLVMTypeRef t);
gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes);
LB_ABI_INFO(abi_info) {
gb_internal LB_ABI_INFO(abi_info) {
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
ft->ctx = c;
ft->calling_convention = calling_convention;
ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
ft->args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
for (unsigned i = 0; i < arg_count; i++) {
ft->args[i] = amd64_type(c, arg_types[i], Amd64TypeAttribute_ByVal, calling_convention);
}
@@ -504,7 +584,7 @@ namespace lbAbiAmd64SysV {
return ft;
}
bool is_mem_cls(Array<RegClass> const &cls, Amd64TypeAttributeKind attribute_kind) {
gb_internal bool is_mem_cls(Array<RegClass> const &cls, Amd64TypeAttributeKind attribute_kind) {
if (attribute_kind == Amd64TypeAttribute_ByVal) {
if (cls.count == 0) {
return false;
@@ -520,7 +600,7 @@ namespace lbAbiAmd64SysV {
return false;
}
bool is_register(LLVMTypeRef type) {
gb_internal bool is_register(LLVMTypeRef type) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
i64 sz = lb_sizeof(type);
if (sz == 0) {
@@ -537,7 +617,7 @@ namespace lbAbiAmd64SysV {
return false;
}
bool is_llvm_type_slice_like(LLVMTypeRef type) {
gb_internal bool is_llvm_type_slice_like(LLVMTypeRef type) {
if (!lb_is_type_kind(type, LLVMStructTypeKind)) {
return false;
}
@@ -553,7 +633,7 @@ namespace lbAbiAmd64SysV {
}
lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention) {
gb_internal lbArgType amd64_type(LLVMContextRef c, LLVMTypeRef type, Amd64TypeAttributeKind attribute_kind, ProcCallingConvention calling_convention) {
if (is_register(type)) {
LLVMAttributeRef attribute = nullptr;
if (type == LLVMInt1TypeInContext(c)) {
@@ -588,7 +668,7 @@ namespace lbAbiAmd64SysV {
}
}
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
LLVMAttributeRef attr = nullptr;
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
if (type == i1) {
@@ -597,7 +677,7 @@ namespace lbAbiAmd64SysV {
return lb_arg_type_direct(type, nullptr, nullptr, attr);
}
Array<RegClass> classify(LLVMTypeRef t) {
gb_internal Array<RegClass> classify(LLVMTypeRef t) {
i64 sz = lb_sizeof(t);
i64 words = (sz + 7)/8;
auto reg_classes = array_make<RegClass>(heap_allocator(), cast(isize)words);
@@ -610,7 +690,7 @@ namespace lbAbiAmd64SysV {
return reg_classes;
}
void unify(Array<RegClass> *cls, i64 i, RegClass const newv) {
gb_internal void unify(Array<RegClass> *cls, i64 i, RegClass const newv) {
RegClass const oldv = (*cls)[cast(isize)i];
if (oldv == newv) {
return;
@@ -646,7 +726,7 @@ namespace lbAbiAmd64SysV {
(*cls)[cast(isize)i] = to_write;
}
void fixup(LLVMTypeRef t, Array<RegClass> *cls) {
gb_internal void fixup(LLVMTypeRef t, Array<RegClass> *cls) {
i64 i = 0;
i64 e = cls->count;
if (e > 2 && (lb_is_type_kind(t, LLVMStructTypeKind) ||
@@ -693,7 +773,7 @@ namespace lbAbiAmd64SysV {
}
}
unsigned llvec_len(Array<RegClass> const &reg_classes, isize offset) {
gb_internal unsigned llvec_len(Array<RegClass> const &reg_classes, isize offset) {
unsigned len = 1;
for (isize i = offset; i < reg_classes.count; i++) {
if (reg_classes[i] != RegClass_SSEUp) {
@@ -705,7 +785,7 @@ namespace lbAbiAmd64SysV {
}
LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes) {
gb_internal LLVMTypeRef llreg(LLVMContextRef c, Array<RegClass> const &reg_classes) {
auto types = array_make<LLVMTypeRef>(heap_allocator(), 0, reg_classes.count);
for (isize i = 0; i < reg_classes.count; /**/) {
RegClass reg_class = reg_classes[i];
@@ -774,7 +854,7 @@ namespace lbAbiAmd64SysV {
return LLVMStructTypeInContext(c, types.data, cast(unsigned)types.count, false);
}
void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) {
gb_internal void classify_with(LLVMTypeRef t, Array<RegClass> *cls, i64 ix, i64 off) {
i64 t_align = lb_alignof(t);
i64 t_size = lb_sizeof(t);
@@ -875,7 +955,7 @@ namespace lbAbiAmd64SysV {
}
}
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
if (!return_is_defined) {
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind)) {
@@ -886,6 +966,9 @@ namespace lbAbiAmd64SysV {
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
}
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
return lb_arg_type_indirect(return_type, attr);
} else if (build_context.metrics.os == TargetOs_windows && lb_is_type_kind(return_type, LLVMIntegerTypeKind) && lb_sizeof(return_type) == 16) {
@@ -897,20 +980,20 @@ namespace lbAbiAmd64SysV {
namespace lbAbiArm64 {
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
gb_internal bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_);
LB_ABI_INFO(abi_info) {
gb_internal LB_ABI_INFO(abi_info) {
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
ft->ctx = c;
ft->ret = compute_return_type(c, return_type, return_is_defined);
ft -> args = compute_arg_types(c, arg_types, arg_count);
ft->args = compute_arg_types(c, arg_types, arg_count);
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
ft->calling_convention = calling_convention;
return ft;
}
bool is_register(LLVMTypeRef type) {
gb_internal bool is_register(LLVMTypeRef type) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
switch (kind) {
case LLVMIntegerTypeKind:
@@ -923,7 +1006,7 @@ namespace lbAbiArm64 {
return false;
}
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type) {
LLVMAttributeRef attr = nullptr;
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
if (type == i1) {
@@ -932,7 +1015,7 @@ namespace lbAbiArm64 {
return lb_arg_type_direct(type, nullptr, nullptr, attr);
}
bool is_homogenous_array(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
gb_internal bool is_homogenous_array(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind));
unsigned len = LLVMGetArrayLength(type);
if (len == 0) {
@@ -949,7 +1032,7 @@ namespace lbAbiArm64 {
}
return false;
}
bool is_homogenous_struct(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
gb_internal bool is_homogenous_struct(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
GB_ASSERT(lb_is_type_kind(type, LLVMStructTypeKind));
unsigned elem_count = LLVMCountStructElementTypes(type);
if (elem_count == 0) {
@@ -992,7 +1075,7 @@ namespace lbAbiArm64 {
}
bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
gb_internal bool is_homogenous_aggregate(LLVMContextRef c, LLVMTypeRef type, LLVMTypeRef *base_type_, unsigned *member_count_) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
switch (kind) {
case LLVMFloatTypeKind:
@@ -1008,31 +1091,33 @@ namespace lbAbiArm64 {
return false;
}
unsigned is_homogenous_aggregate_small_enough(LLVMTypeRef base_type, unsigned member_count) {
gb_internal unsigned is_homogenous_aggregate_small_enough(LLVMTypeRef base_type, unsigned member_count) {
return (member_count <= 4);
}
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef type, bool return_is_defined) {
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
LLVMTypeRef homo_base_type = nullptr;
unsigned homo_member_count = 0;
if (!return_is_defined) {
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
} else if (is_register(type)) {
return non_struct(c, type);
} else if (is_homogenous_aggregate(c, type, &homo_base_type, &homo_member_count)) {
} else if (is_register(return_type)) {
return non_struct(c, return_type);
} else if (is_homogenous_aggregate(c, return_type, &homo_base_type, &homo_member_count)) {
if (is_homogenous_aggregate_small_enough(homo_base_type, homo_member_count)) {
return lb_arg_type_direct(type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
return lb_arg_type_direct(return_type, LLVMArrayType(homo_base_type, homo_member_count), nullptr, nullptr);
} else {
//TODO(Platin): do i need to create stuff that can handle the diffrent return type?
// else this needs a fix in llvm_backend_proc as we would need to cast it to the correct array type
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
//LLVMTypeRef array_type = LLVMArrayType(homo_base_type, homo_member_count);
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
return lb_arg_type_indirect(type, attr);
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
return lb_arg_type_indirect(return_type, attr);
}
} else {
i64 size = lb_sizeof(type);
i64 size = lb_sizeof(return_type);
if (size <= 16) {
LLVMTypeRef cast_type = nullptr;
if (size <= 1) {
@@ -1047,16 +1132,18 @@ namespace lbAbiArm64 {
unsigned count = cast(unsigned)((size+7)/8);
cast_type = LLVMArrayType(LLVMInt64TypeInContext(c), count);
}
return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
return lb_arg_type_direct(return_type, cast_type, nullptr, nullptr);
} else {
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", type);
return lb_arg_type_indirect(type, attr);
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
return lb_arg_type_indirect(return_type, attr);
}
}
}
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
for (unsigned i = 0; i < arg_count; i++) {
LLVMTypeRef type = arg_types[i];
@@ -1101,21 +1188,21 @@ namespace lbAbiWasm {
The approach taken optimizes for passing things in multiple
registers/arguments if possible rather than by pointer.
*/
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count);
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type);
enum {MAX_DIRECT_STRUCT_SIZE = 32};
LB_ABI_INFO(abi_info) {
gb_internal LB_ABI_INFO(abi_info) {
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
ft->ctx = c;
ft->args = compute_arg_types(c, arg_types, arg_count);
ft->ret = compute_return_type(c, return_type, return_is_defined);
ft->ret = compute_return_type(ft, c, return_type, return_is_defined, return_is_tuple);
ft->calling_convention = calling_convention;
return ft;
}
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
if (!is_return && type == LLVMIntTypeInContext(c, 128)) {
LLVMTypeRef cast_type = LLVMVectorType(LLVMInt64TypeInContext(c), 2);
return lb_arg_type_direct(type, cast_type, nullptr, nullptr);
@@ -1133,7 +1220,7 @@ namespace lbAbiWasm {
return lb_arg_type_direct(type, nullptr, nullptr, attr);
}
bool is_basic_register_type(LLVMTypeRef type) {
gb_internal bool is_basic_register_type(LLVMTypeRef type) {
switch (LLVMGetTypeKind(type)) {
case LLVMHalfTypeKind:
case LLVMFloatTypeKind:
@@ -1146,7 +1233,7 @@ namespace lbAbiWasm {
return false;
}
bool type_can_be_direct(LLVMTypeRef type) {
gb_internal bool type_can_be_direct(LLVMTypeRef type) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
i64 sz = lb_sizeof(type);
if (sz == 0) {
@@ -1172,7 +1259,7 @@ namespace lbAbiWasm {
return false;
}
lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
gb_internal lbArgType is_struct(LLVMContextRef c, LLVMTypeRef type) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
GB_ASSERT(kind == LLVMArrayTypeKind || kind == LLVMStructTypeKind);
@@ -1187,8 +1274,8 @@ namespace lbAbiWasm {
}
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count) {
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
for (unsigned i = 0; i < arg_count; i++) {
LLVMTypeRef t = arg_types[i];
@@ -1202,7 +1289,7 @@ namespace lbAbiWasm {
return args;
}
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
gb_internal LB_ABI_COMPUTE_RETURN_TYPE(compute_return_type) {
if (!return_is_defined) {
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
} else if (lb_is_type_kind(return_type, LLVMStructTypeKind) || lb_is_type_kind(return_type, LLVMArrayTypeKind)) {
@@ -1217,6 +1304,9 @@ namespace lbAbiWasm {
case 4: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 32), nullptr, nullptr);
case 8: return lb_arg_type_direct(return_type, LLVMIntTypeInContext(c, 64), nullptr, nullptr);
}
LB_ABI_MODIFY_RETURN_IF_TUPLE_MACRO();
LLVMAttributeRef attr = lb_create_enum_attribute_with_type(c, "sret", return_type);
return lb_arg_type_indirect(return_type, attr);
}
@@ -1225,10 +1315,10 @@ namespace lbAbiWasm {
}
namespace lbAbiArm32 {
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention);
gb_internal lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined);
LB_ABI_INFO(abi_info) {
gb_internal LB_ABI_INFO(abi_info) {
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
ft->ctx = c;
ft->args = compute_arg_types(c, arg_types, arg_count, calling_convention);
@@ -1237,7 +1327,7 @@ namespace lbAbiArm32 {
return ft;
}
bool is_register(LLVMTypeRef type, bool is_return) {
gb_internal bool is_register(LLVMTypeRef type, bool is_return) {
LLVMTypeKind kind = LLVMGetTypeKind(type);
switch (kind) {
case LLVMHalfTypeKind:
@@ -1256,7 +1346,7 @@ namespace lbAbiArm32 {
return false;
}
lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
gb_internal lbArgType non_struct(LLVMContextRef c, LLVMTypeRef type, bool is_return) {
LLVMAttributeRef attr = nullptr;
LLVMTypeRef i1 = LLVMInt1TypeInContext(c);
if (type == i1) {
@@ -1265,8 +1355,8 @@ namespace lbAbiArm32 {
return lb_arg_type_direct(type, nullptr, nullptr, attr);
}
Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
auto args = array_make<lbArgType>(heap_allocator(), arg_count);
gb_internal Array<lbArgType> compute_arg_types(LLVMContextRef c, LLVMTypeRef *arg_types, unsigned arg_count, ProcCallingConvention calling_convention) {
auto args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
for (unsigned i = 0; i < arg_count; i++) {
LLVMTypeRef t = arg_types[i];
@@ -1290,7 +1380,7 @@ namespace lbAbiArm32 {
return args;
}
lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
gb_internal lbArgType compute_return_type(LLVMContextRef c, LLVMTypeRef return_type, bool return_is_defined) {
if (!return_is_defined) {
return lb_arg_type_direct(LLVMVoidTypeInContext(c));
} else if (!is_register(return_type, true)) {
@@ -1307,14 +1397,14 @@ namespace lbAbiArm32 {
};
LB_ABI_INFO(lb_get_abi_info) {
gb_internal LB_ABI_INFO(lb_get_abi_info_internal) {
switch (calling_convention) {
case ProcCC_None:
case ProcCC_InlineAsm:
{
lbFunctionType *ft = gb_alloc_item(permanent_allocator(), lbFunctionType);
ft->ctx = c;
ft->args = array_make<lbArgType>(heap_allocator(), arg_count);
ft->args = array_make<lbArgType>(lb_function_type_args_allocator(), arg_count);
for (unsigned i = 0; i < arg_count; i++) {
ft->args[i] = lb_arg_type_direct(arg_types[i]);
}
@@ -1328,32 +1418,55 @@ LB_ABI_INFO(lb_get_abi_info) {
}
case ProcCC_Win64:
GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
case ProcCC_SysV:
GB_ASSERT(build_context.metrics.arch == TargetArch_amd64);
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
}
switch (build_context.metrics.arch) {
case TargetArch_amd64:
if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) {
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
if (build_context.metrics.os == TargetOs_windows) {
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
} else if (build_context.metrics.abi == TargetABI_Win64) {
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
} else if (build_context.metrics.abi == TargetABI_SysV) {
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
} else {
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
}
case TargetArch_i386:
return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
return lbAbi386::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
case TargetArch_arm32:
return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
return lbAbiArm32::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
case TargetArch_arm64:
return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
return lbAbiArm64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
case TargetArch_wasm32:
case TargetArch_wasm64:
return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
return lbAbiWasm::abi_info(c, arg_types, arg_count, return_type, return_is_defined, return_is_tuple, calling_convention);
}
GB_PANIC("Unsupported ABI");
return {};
}
gb_internal LB_ABI_INFO(lb_get_abi_info) {
lbFunctionType *ft = lb_get_abi_info_internal(
c,
arg_types, arg_count,
return_type, return_is_defined,
ALLOW_SPLIT_MULTI_RETURNS && return_is_tuple && is_calling_convention_odin(calling_convention),
calling_convention);
// NOTE(bill): this is handled here rather than when developing the type in `lb_type_internal_for_procedures_raw`
// This is to make it consistent when and how it is handled
if (calling_convention == ProcCC_Odin) {
// append the `context` pointer
lbArgType context_param = lb_arg_type_direct(LLVMPointerType(LLVMInt8TypeInContext(c), 0));
array_add(&ft->args, context_param);
}
return ft;
}
+674 -566
View File
File diff suppressed because it is too large Load Diff
+169 -150
View File
@@ -117,20 +117,34 @@ struct lbIncompleteDebugType {
typedef Slice<i32> lbStructFieldRemapping;
enum lbFunctionPassManagerKind {
lbFunctionPassManager_default,
lbFunctionPassManager_default_without_memcpy,
lbFunctionPassManager_minimal,
lbFunctionPassManager_size,
lbFunctionPassManager_speed,
lbFunctionPassManager_COUNT
};
struct lbModule {
LLVMModuleRef mod;
LLVMContextRef ctx;
struct lbGenerator *gen;
LLVMTargetMachineRef target_machine;
CheckerInfo *info;
AstPackage *pkg; // associated
AstPackage *pkg; // possibly associated
AstFile *file; // possibly associated
PtrMap<Type *, LLVMTypeRef> types;
PtrMap<Type *, LLVMTypeRef> func_raw_types;
PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *
i32 internal_type_level;
RwMutex values_mutex;
PtrMap<Entity *, lbValue> values;
PtrMap<Entity *, lbAddr> soa_values;
StringMap<lbValue> members;
@@ -150,11 +164,14 @@ struct lbModule {
u32 nested_type_name_guid;
Array<lbProcedure *> procedures_to_generate;
Array<Entity *> global_procedures_and_types_to_create;
lbProcedure *curr_procedure;
LLVMDIBuilderRef debug_builder;
LLVMMetadataRef debug_compile_unit;
RecursiveMutex debug_values_mutex;
PtrMap<void *, LLVMMetadataRef> debug_values;
Array<lbIncompleteDebugType> debug_incomplete_types;
@@ -164,6 +181,8 @@ struct lbModule {
PtrMap<Type *, lbAddr> map_cell_info_map; // address of runtime.Map_Info
PtrMap<Type *, lbAddr> map_info_map; // address of runtime.Map_Cell_Info
LLVMPassManagerRef function_pass_managers[lbFunctionPassManager_COUNT];
};
struct lbGenerator {
@@ -173,10 +192,11 @@ struct lbGenerator {
Array<String> output_temp_paths;
String output_base;
String output_name;
PtrMap<AstPackage *, lbModule *> modules;
PtrMap<void *, lbModule *> modules; // key is `AstPackage *` (`void *` is used for future use)
PtrMap<LLVMContextRef, lbModule *> modules_through_ctx;
lbModule default_module;
BlockingMutex anonymous_proc_lits_mutex;
PtrMap<Ast *, lbProcedure *> anonymous_proc_lits;
BlockingMutex foreign_mutex;
@@ -185,6 +205,10 @@ struct lbGenerator {
std::atomic<u32> global_array_index;
std::atomic<u32> global_generated_index;
lbProcedure *startup_type_info;
lbProcedure *startup_runtime;
lbProcedure *objc_names;
};
@@ -254,17 +278,15 @@ struct lbTargetList {
};
struct lbTupleFix {
Slice<lbValue> values;
};
enum lbProcedureFlag : u32 {
lbProcedureFlag_WithoutMemcpyPass = 1<<0,
lbProcedureFlag_DebugAllocaCopy = 1<<1,
};
struct lbCopyElisionHint {
lbValue ptr;
Ast * ast;
bool used;
};
struct lbProcedure {
u32 flags;
u16 state_flags;
@@ -302,6 +324,7 @@ struct lbProcedure {
lbBlock * curr_block;
lbTargetList * target_list;
PtrMap<Entity *, lbValue> direct_parameters;
bool in_multi_assignment;
Ast *curr_stmt;
@@ -310,10 +333,9 @@ struct lbProcedure {
LLVMMetadataRef debug_info;
lbCopyElisionHint copy_elision_hint;
PtrMap<Ast *, lbValue> selector_values;
PtrMap<Ast *, lbAddr> selector_addr;
PtrMap<LLVMValueRef, lbTupleFix> tuple_fix_map;
};
@@ -324,200 +346,197 @@ struct lbProcedure {
#define LLVMBuildPtrDiff2(Builder__, Ty__, LHS__, RHS__, Name__) LLVMBuildPtrDiff(Builder__, LHS__, RHS__, Name__)
#endif
bool lb_init_generator(lbGenerator *gen, Checker *c);
gb_internal bool lb_init_generator(lbGenerator *gen, Checker *c);
String lb_mangle_name(lbModule *m, Entity *e);
String lb_get_entity_name(lbModule *m, Entity *e, String name = {});
gb_internal String lb_mangle_name(lbModule *m, Entity *e);
gb_internal String lb_get_entity_name(lbModule *m, Entity *e, String name = {});
LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0);
LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type);
void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value);
void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name);
lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false);
void lb_end_procedure(lbProcedure *p);
gb_internal LLVMAttributeRef lb_create_enum_attribute(LLVMContextRef ctx, char const *name, u64 value=0);
gb_internal LLVMAttributeRef lb_create_enum_attribute_with_type(LLVMContextRef ctx, char const *name, LLVMTypeRef type);
gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name, u64 value);
gb_internal void lb_add_proc_attribute_at_index(lbProcedure *p, isize index, char const *name);
gb_internal lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_body=false);
gb_internal void lb_end_procedure(lbProcedure *p);
LLVMTypeRef lb_type(lbModule *m, Type *type);
LLVMTypeRef llvm_get_element_type(LLVMTypeRef type);
gb_internal LLVMTypeRef lb_type(lbModule *m, Type *type);
gb_internal LLVMTypeRef llvm_get_element_type(LLVMTypeRef type);
lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false);
gb_internal lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false);
lbValue lb_const_nil(lbModule *m, Type *type);
lbValue lb_const_undef(lbModule *m, Type *type);
lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local=true);
lbValue lb_const_bool(lbModule *m, Type *type, bool value);
lbValue lb_const_int(lbModule *m, Type *type, u64 value);
gb_internal lbValue lb_const_nil(lbModule *m, Type *type);
gb_internal lbValue lb_const_undef(lbModule *m, Type *type);
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local=true);
gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value);
gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value);
lbAddr lb_addr(lbValue addr);
Type *lb_addr_type(lbAddr const &addr);
LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val);
void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value);
lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr);
lbValue lb_emit_load(lbProcedure *p, lbValue v);
void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value);
gb_internal lbAddr lb_addr(lbValue addr);
gb_internal Type *lb_addr_type(lbAddr const &addr);
gb_internal LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val);
gb_internal void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value);
gb_internal lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr);
gb_internal lbValue lb_emit_load(lbProcedure *p, lbValue v);
gb_internal void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value);
void lb_build_stmt(lbProcedure *p, Ast *stmt);
lbValue lb_build_expr(lbProcedure *p, Ast *expr);
lbAddr lb_build_addr(lbProcedure *p, Ast *expr);
void lb_build_stmt_list(lbProcedure *p, Array<Ast *> const &stmts);
gb_internal void lb_build_stmt(lbProcedure *p, Ast *stmt);
gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr);
gb_internal lbAddr lb_build_addr(lbProcedure *p, Ast *expr);
gb_internal void lb_build_stmt_list(lbProcedure *p, Array<Ast *> const &stmts);
lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index);
lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index);
lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index);
lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index);
lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index);
lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index);
lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index);
lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel);
lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel);
gb_internal lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index);
gb_internal lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index);
gb_internal lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index);
gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index);
gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index);
gb_internal lbValue lb_emit_tuple_ev(lbProcedure *p, lbValue value, i32 index);
gb_internal lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index);
gb_internal lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index);
gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel);
gb_internal lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel);
lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column);
lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column);
lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column);
gb_internal lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column);
gb_internal lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column);
gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column);
lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type);
lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type);
void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block);
lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right);
lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none, bool use_return_ptr_hint = false);
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x);
gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type);
gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type);
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block);
gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t);
gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right);
gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining = ProcInlining_none);
gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x);
void lb_emit_jump(lbProcedure *p, lbBlock *target_block);
void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *false_block);
void lb_start_block(lbProcedure *p, lbBlock *b);
gb_internal void lb_emit_jump(lbProcedure *p, lbBlock *target_block);
gb_internal void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *false_block);
gb_internal void lb_start_block(lbProcedure *p, lbBlock *b);
lbValue lb_build_call_expr(lbProcedure *p, Ast *expr);
gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr);
lbAddr lb_find_or_generate_context_ptr(lbProcedure *p);
lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx);
lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p);
gb_internal lbAddr lb_find_or_generate_context_ptr(lbProcedure *p);
gb_internal lbContextData *lb_push_context_onto_stack(lbProcedure *p, lbAddr ctx);
gb_internal lbContextData *lb_push_context_onto_stack_from_implicit_parameter(lbProcedure *p);
lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}, Entity **entity_=nullptr);
lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_init=true, i32 param_index=0, bool force_no_init=false);
gb_internal lbAddr lb_add_global_generated(lbModule *m, Type *type, lbValue value={}, Entity **entity_=nullptr);
gb_internal lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e=nullptr, bool zero_init=true, bool force_no_init=false);
void lb_add_foreign_library_path(lbModule *m, Entity *e);
gb_internal void lb_add_foreign_library_path(lbModule *m, Entity *e);
lbValue lb_typeid(lbModule *m, Type *type);
gb_internal lbValue lb_typeid(lbModule *m, Type *type);
lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value);
lbValue lb_address_from_load(lbProcedure *p, lbValue value);
void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt);
lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init);
gb_internal lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value);
gb_internal lbValue lb_address_from_load(lbProcedure *p, lbValue value);
gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt);
gb_internal lbAddr lb_add_local_generated(lbProcedure *p, Type *type, bool zero_init);
lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args);
gb_internal lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args);
lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index);
lbValue lb_string_elem(lbProcedure *p, lbValue string);
lbValue lb_string_len(lbProcedure *p, lbValue string);
lbValue lb_cstring_len(lbProcedure *p, lbValue value);
lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr);
lbValue lb_slice_elem(lbProcedure *p, lbValue slice);
lbValue lb_slice_len(lbProcedure *p, lbValue slice);
lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da);
lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da);
lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da);
lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da);
lbValue lb_map_len(lbProcedure *p, lbValue value);
lbValue lb_map_cap(lbProcedure *p, lbValue value);
lbValue lb_soa_struct_len(lbProcedure *p, lbValue value);
void lb_emit_increment(lbProcedure *p, lbValue addr);
lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y);
gb_internal lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index);
gb_internal lbValue lb_string_elem(lbProcedure *p, lbValue string);
gb_internal lbValue lb_string_len(lbProcedure *p, lbValue string);
gb_internal lbValue lb_cstring_len(lbProcedure *p, lbValue value);
gb_internal lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr);
gb_internal lbValue lb_slice_elem(lbProcedure *p, lbValue slice);
gb_internal lbValue lb_slice_len(lbProcedure *p, lbValue slice);
gb_internal lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da);
gb_internal lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da);
gb_internal lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da);
gb_internal lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da);
gb_internal lbValue lb_map_len(lbProcedure *p, lbValue value);
gb_internal lbValue lb_map_cap(lbProcedure *p, lbValue value);
gb_internal lbValue lb_soa_struct_len(lbProcedure *p, lbValue value);
gb_internal void lb_emit_increment(lbProcedure *p, lbValue addr);
gb_internal lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y);
lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t);
gb_internal lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t);
void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len);
gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len);
lbValue lb_type_info(lbModule *m, Type *type);
gb_internal lbValue lb_type_info(lbModule *m, Type *type);
lbValue lb_find_or_add_entity_string(lbModule *m, String const &str);
lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent = nullptr);
gb_internal lbValue lb_find_or_add_entity_string(lbModule *m, String const &str);
gb_internal lbValue lb_generate_anonymous_proc_lit(lbModule *m, String const &prefix_name, Ast *expr, lbProcedure *parent = nullptr);
bool lb_is_const(lbValue value);
bool lb_is_const_or_global(lbValue value);
bool lb_is_const_nil(lbValue value);
String lb_get_const_string(lbModule *m, lbValue value);
gb_internal bool lb_is_const(lbValue value);
gb_internal bool lb_is_const_or_global(lbValue value);
gb_internal bool lb_is_const_nil(lbValue value);
gb_internal String lb_get_const_string(lbModule *m, lbValue value);
lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type);
lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type);
gb_internal lbValue lb_generate_local_array(lbProcedure *p, Type *elem_type, i64 count, bool zero_init=true);
gb_internal lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String prefix, i64 id);
gb_internal lbValue lb_gen_map_key_hash(lbProcedure *p, lbValue key, Type *key_type, lbValue *key_ptr_);
gb_internal lbValue lb_gen_map_cell_info_ptr(lbModule *m, Type *type);
gb_internal lbValue lb_gen_map_info_ptr(lbModule *m, Type *map_type);
lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key);
void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ptr, Type *map_type, lbValue const &map_key, lbValue const &map_value, Ast *node);
lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos);
gb_internal lbValue lb_internal_dynamic_map_get_ptr(lbProcedure *p, lbValue const &map_ptr, lbValue const &key);
gb_internal void lb_internal_dynamic_map_set(lbProcedure *p, lbValue const &map_ptr, Type *map_type, lbValue const &map_key, lbValue const &map_value, Ast *node);
gb_internal lbValue lb_dynamic_map_reserve(lbProcedure *p, lbValue const &map_ptr, isize const capacity, TokenPos const &pos);
lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
lbValue lb_find_value_from_entity(lbModule *m, Entity *e);
gb_internal lbValue lb_find_procedure_value_from_entity(lbModule *m, Entity *e);
gb_internal lbValue lb_find_value_from_entity(lbModule *m, Entity *e);
void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value);
lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value);
lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos);
gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value);
gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value);
gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos);
lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TokenPos const &pos);
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TokenPos const &pos);
lbValue lb_equal_proc_for_type(lbModule *m, Type *type);
lbValue lb_hasher_proc_for_type(lbModule *m, Type *type);
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
gb_internal lbValue lb_equal_proc_for_type(lbModule *m, Type *type);
gb_internal lbValue lb_hasher_proc_for_type(lbModule *m, Type *type);
gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t);
LLVMMetadataRef lb_debug_type(lbModule *m, Type *type);
gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type);
lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type);
lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type);
lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type);
lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type);
lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type);
gb_internal lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type);
gb_internal lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type);
gb_internal lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type);
gb_internal lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type);
gb_internal lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type);
lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x);
gb_internal lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x);
void lb_mem_zero_addr(lbProcedure *p, LLVMValueRef ptr, Type *type);
gb_internal void lb_mem_zero_addr(lbProcedure *p, LLVMValueRef ptr, Type *type);
void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e);
lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type);
lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block);
gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e);
gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type);
gb_internal lbValue lb_build_cond(lbProcedure *p, Ast *cond, lbBlock *true_block, lbBlock *false_block);
LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_);
LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name);
gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_);
gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_);
gb_internal void lb_set_entity_from_other_modules_linkage_correctly(lbModule *other_module, Entity *e, String const &name);
lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t);
bool lb_is_expr_untyped_const(Ast *expr);
gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t);
gb_internal bool lb_is_expr_untyped_const(Ast *expr);
LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const *name = "");
gb_internal LLVMValueRef llvm_alloca(lbProcedure *p, LLVMTypeRef llvm_type, isize alignment, char const *name = "");
void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment);
gb_internal void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment);
void lb_emit_init_context(lbProcedure *p, lbAddr addr);
lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, Ast *ast);
void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint);
lbValue lb_consume_copy_elision_hint(lbProcedure *p);
gb_internal void lb_emit_init_context(lbProcedure *p, lbAddr addr);
lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t);
LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align);
gb_internal lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t);
gb_internal LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align);
LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask);
gb_internal LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask);
LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count);
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
gb_internal LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count);
gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
i64 lb_max_zero_init_size(void) {
gb_internal gb_inline i64 lb_max_zero_init_size(void) {
return cast(i64)(4*build_context.word_size);
}
LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);
LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
gb_internal LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);
gb_internal LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
@@ -637,7 +656,7 @@ enum : LLVMAttributeIndex {
};
char const *llvm_linkage_strings[] = {
gb_global char const *llvm_linkage_strings[] = {
"external linkage",
"available externally linkage",
"link once any linkage",
+30 -30
View File
@@ -1,4 +1,4 @@
bool lb_is_const(lbValue value) {
gb_internal bool lb_is_const(lbValue value) {
LLVMValueRef v = value.value;
if (is_type_untyped_nil(value.type) || is_type_untyped_undef(value.type)) {
// TODO(bill): Is this correct behaviour?
@@ -10,7 +10,7 @@ bool lb_is_const(lbValue value) {
return false;
}
bool lb_is_const_or_global(lbValue value) {
gb_internal bool lb_is_const_or_global(lbValue value) {
if (lb_is_const(value)) {
return true;
}
@@ -29,7 +29,7 @@ bool lb_is_const_or_global(lbValue value) {
}
bool lb_is_elem_const(Ast *elem, Type *elem_type) {
gb_internal bool lb_is_elem_const(Ast *elem, Type *elem_type) {
if (!elem_type_can_be_constant(elem_type)) {
return false;
}
@@ -42,7 +42,7 @@ bool lb_is_elem_const(Ast *elem, Type *elem_type) {
}
bool lb_is_const_nil(lbValue value) {
gb_internal bool lb_is_const_nil(lbValue value) {
LLVMValueRef v = value.value;
if (LLVMIsConstant(v)) {
if (LLVMIsAConstantAggregateZero(v)) {
@@ -55,7 +55,7 @@ bool lb_is_const_nil(lbValue value) {
}
bool lb_is_expr_constant_zero(Ast *expr) {
gb_internal bool lb_is_expr_constant_zero(Ast *expr) {
GB_ASSERT(expr != nullptr);
auto v = exact_value_to_integer(expr->tav.value);
if (v.kind == ExactValue_Integer) {
@@ -64,7 +64,7 @@ bool lb_is_expr_constant_zero(Ast *expr) {
return false;
}
String lb_get_const_string(lbModule *m, lbValue value) {
gb_internal String lb_get_const_string(lbModule *m, lbValue value) {
GB_ASSERT(lb_is_const(value));
GB_ASSERT(LLVMIsConstant(value.value));
@@ -92,7 +92,7 @@ String lb_get_const_string(lbModule *m, lbValue value) {
}
LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
gb_internal LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
LLVMTypeRef src = LLVMTypeOf(val);
if (src == dst) {
return val;
@@ -116,7 +116,7 @@ LLVMValueRef llvm_const_cast(LLVMValueRef val, LLVMTypeRef dst) {
}
lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
gb_internal lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
GB_ASSERT(is_type_internally_pointer_like(value.type));
GB_ASSERT(is_type_internally_pointer_like(t));
GB_ASSERT(lb_is_const(value));
@@ -127,7 +127,7 @@ lbValue lb_const_ptr_cast(lbModule *m, lbValue value, Type *t) {
return res;
}
LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_) {
gb_internal LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values, isize value_count_) {
LLVMTypeRef struct_type = lb_type(m, t);
GB_ASSERT(LLVMGetTypeKind(struct_type) == LLVMStructTypeKind);
@@ -157,7 +157,7 @@ LLVMValueRef llvm_const_named_struct(lbModule *m, Type *t, LLVMValueRef *values,
return llvm_const_named_struct_internal(struct_type, values_with_padding, values_with_padding_count);
}
LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
gb_internal LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *values, isize value_count_) {
unsigned value_count = cast(unsigned)value_count_;
unsigned elem_count = LLVMCountStructElementTypes(t);
GB_ASSERT_MSG(value_count == elem_count, "%s %u %u", LLVMPrintTypeToString(t), value_count, elem_count);
@@ -168,7 +168,7 @@ LLVMValueRef llvm_const_named_struct_internal(LLVMTypeRef t, LLVMValueRef *value
return LLVMConstNamedStruct(t, values, value_count);
}
LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
gb_internal LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize value_count_) {
unsigned value_count = cast(unsigned)value_count_;
for (unsigned i = 0; i < value_count; i++) {
values[i] = llvm_const_cast(values[i], elem_type);
@@ -176,7 +176,7 @@ LLVMValueRef llvm_const_array(LLVMTypeRef elem_type, LLVMValueRef *values, isize
return LLVMConstArray(elem_type, values, value_count);
}
LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) {
gb_internal LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) {
GB_ASSERT(is_type_pointer(data.type) || is_type_multi_pointer(data.type));
GB_ASSERT(are_types_identical(len.type, t_int));
LLVMValueRef vals[2] = {
@@ -187,38 +187,38 @@ LLVMValueRef llvm_const_slice(lbModule *m, lbValue data, lbValue len) {
}
lbValue lb_const_nil(lbModule *m, Type *type) {
gb_internal lbValue lb_const_nil(lbModule *m, Type *type) {
LLVMValueRef v = LLVMConstNull(lb_type(m, type));
return lbValue{v, type};
}
lbValue lb_const_undef(lbModule *m, Type *type) {
gb_internal lbValue lb_const_undef(lbModule *m, Type *type) {
LLVMValueRef v = LLVMGetUndef(lb_type(m, type));
return lbValue{v, type};
}
lbValue lb_const_int(lbModule *m, Type *type, u64 value) {
gb_internal lbValue lb_const_int(lbModule *m, Type *type, u64 value) {
lbValue res = {};
res.value = LLVMConstInt(lb_type(m, type), cast(unsigned long long)value, !is_type_unsigned(type));
res.type = type;
return res;
}
lbValue lb_const_string(lbModule *m, String const &value) {
gb_internal lbValue lb_const_string(lbModule *m, String const &value) {
return lb_const_value(m, t_string, exact_value_string(value));
}
lbValue lb_const_bool(lbModule *m, Type *type, bool value) {
gb_internal lbValue lb_const_bool(lbModule *m, Type *type, bool value) {
lbValue res = {};
res.value = LLVMConstInt(lb_type(m, type), value, false);
res.type = type;
return res;
}
LLVMValueRef lb_const_f16(lbModule *m, f32 f, Type *type=t_f16) {
gb_internal LLVMValueRef lb_const_f16(lbModule *m, f32 f, Type *type=t_f16) {
GB_ASSERT(type_size_of(type) == 2);
u16 u = f32_to_f16(f);
@@ -229,7 +229,7 @@ LLVMValueRef lb_const_f16(lbModule *m, f32 f, Type *type=t_f16) {
return LLVMConstBitCast(i, lb_type(m, type));
}
LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) {
gb_internal LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) {
GB_ASSERT(type_size_of(type) == 4);
u32 u = bit_cast<u32>(f);
if (is_type_different_to_arch_endianness(type)) {
@@ -241,7 +241,7 @@ LLVMValueRef lb_const_f32(lbModule *m, f32 f, Type *type=t_f32) {
bool lb_is_expr_untyped_const(Ast *expr) {
gb_internal bool lb_is_expr_untyped_const(Ast *expr) {
auto const &tv = type_and_value_of_expr(expr);
if (is_type_untyped(tv.type)) {
return tv.value.kind != ExactValue_Invalid;
@@ -250,13 +250,13 @@ bool lb_is_expr_untyped_const(Ast *expr) {
}
lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t) {
gb_internal lbValue lb_expr_untyped_const_to_typed(lbModule *m, Ast *expr, Type *t) {
GB_ASSERT(is_type_typed(t));
auto const &tv = type_and_value_of_expr(expr);
return lb_const_value(m, t, tv.value);
}
lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos) {
gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedure, TokenPos const &pos) {
lbModule *m = p->module;
LLVMValueRef fields[4] = {};
@@ -271,7 +271,7 @@ lbValue lb_emit_source_code_location_const(lbProcedure *p, String const &procedu
return res;
}
lbValue lb_emit_source_code_location_const(lbProcedure *p, Ast *node) {
gb_internal lbValue lb_emit_source_code_location_const(lbProcedure *p, Ast *node) {
String proc_name = {};
if (p->entity) {
proc_name = p->entity->token.string;
@@ -284,7 +284,7 @@ lbValue lb_emit_source_code_location_const(lbProcedure *p, Ast *node) {
}
lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const &procedure, TokenPos const &pos) {
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const &procedure, TokenPos const &pos) {
lbValue loc = lb_emit_source_code_location_const(p, procedure, pos);
lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
lb_make_global_private_const(addr);
@@ -292,24 +292,24 @@ lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, String const
}
lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, Ast *node) {
gb_internal lbValue lb_emit_source_code_location_as_global_ptr(lbProcedure *p, Ast *node) {
lbValue loc = lb_emit_source_code_location_const(p, node);
lbAddr addr = lb_add_global_generated(p->module, loc.type, loc, nullptr);
lb_make_global_private_const(addr);
return addr.addr;
}
lbValue lb_emit_source_code_location_as_global(lbProcedure *p, String const &procedure, TokenPos const &pos) {
gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, String const &procedure, TokenPos const &pos) {
return lb_emit_load(p, lb_emit_source_code_location_as_global_ptr(p, procedure, pos));
}
lbValue lb_emit_source_code_location_as_global(lbProcedure *p, Ast *node) {
gb_internal lbValue lb_emit_source_code_location_as_global(lbProcedure *p, Ast *node) {
return lb_emit_load(p, lb_emit_source_code_location_as_global_ptr(p, node));
}
LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, bool allow_local) {
gb_internal LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_type, isize count, LLVMValueRef *values, bool allow_local) {
bool is_local = allow_local && m->curr_procedure != nullptr;
bool is_const = true;
if (is_local) {
@@ -341,7 +341,7 @@ LLVMValueRef lb_build_constant_array_values(lbModule *m, Type *type, Type *elem_
return llvm_const_array(lb_type(m, elem_type), values, cast(unsigned int)count);
}
LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) {
gb_internal LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *a) {
if (big_int_is_zero(a)) {
return LLVMConstNull(lb_type(m, original_type));
}
@@ -387,7 +387,7 @@ LLVMValueRef lb_big_int_to_llvm(lbModule *m, Type *original_type, BigInt const *
}
lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) {
gb_internal lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_local) {
LLVMContextRef ctx = m->ctx;
type = default_type(type);
+33 -34
View File
@@ -1,27 +1,25 @@
LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) {
gb_internal LLVMMetadataRef lb_get_llvm_metadata(lbModule *m, void *key) {
if (key == nullptr) {
return nullptr;
}
mutex_lock(&m->debug_values_mutex);
auto found = map_get(&m->debug_values, key);
mutex_unlock(&m->debug_values_mutex);
if (found) {
return *found;
}
return nullptr;
}
void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef value) {
gb_internal void lb_set_llvm_metadata(lbModule *m, void *key, LLVMMetadataRef value) {
if (key != nullptr) {
mutex_lock(&m->debug_values_mutex);
map_set(&m->debug_values, key, value);
mutex_unlock(&m->debug_values_mutex);
}
}
LLVMMetadataRef lb_get_llvm_file_metadata_from_node(lbModule *m, Ast *node) {
if (node == nullptr) {
return nullptr;
}
return lb_get_llvm_metadata(m, node->file());
}
LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) {
gb_internal LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) {
GB_ASSERT_MSG(p->debug_info != nullptr, "missing debug information for %.*s", LIT(p->name));
for (isize i = p->scope_stack.count-1; i >= 0; i--) {
@@ -34,21 +32,21 @@ LLVMMetadataRef lb_get_current_debug_scope(lbProcedure *p) {
return p->debug_info;
}
LLVMMetadataRef lb_debug_location_from_token_pos(lbProcedure *p, TokenPos pos) {
gb_internal LLVMMetadataRef lb_debug_location_from_token_pos(lbProcedure *p, TokenPos pos) {
LLVMMetadataRef scope = lb_get_current_debug_scope(p);
GB_ASSERT_MSG(scope != nullptr, "%.*s", LIT(p->name));
return LLVMDIBuilderCreateDebugLocation(p->module->ctx, cast(unsigned)pos.line, cast(unsigned)pos.column, scope, nullptr);
}
LLVMMetadataRef lb_debug_location_from_ast(lbProcedure *p, Ast *node) {
gb_internal LLVMMetadataRef lb_debug_location_from_ast(lbProcedure *p, Ast *node) {
GB_ASSERT(node != nullptr);
return lb_debug_location_from_token_pos(p, ast_token(node).pos);
}
LLVMMetadataRef lb_debug_end_location_from_ast(lbProcedure *p, Ast *node) {
gb_internal LLVMMetadataRef lb_debug_end_location_from_ast(lbProcedure *p, Ast *node) {
GB_ASSERT(node != nullptr);
return lb_debug_location_from_token_pos(p, ast_end_token(node).pos);
}
LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
gb_internal LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
i64 size = type_size_of(type); // Check size
gb_unused(size);
@@ -93,7 +91,7 @@ LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
return LLVMDIBuilderCreateSubroutineType(m->debug_builder, file, parameters, parameter_count, flags);
}
LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *type, u64 offset_in_bits) {
gb_internal LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *type, u64 offset_in_bits) {
unsigned field_line = 1;
LLVMDIFlags field_flags = LLVMDIFlagZero;
@@ -107,7 +105,7 @@ LLVMMetadataRef lb_debug_struct_field(lbModule *m, String const &name, Type *typ
field_flags, lb_debug_type(m, type)
);
}
LLVMMetadataRef lb_debug_basic_struct(lbModule *m, String const &name, u64 size_in_bits, u32 align_in_bits, LLVMMetadataRef *elements, unsigned element_count) {
gb_internal LLVMMetadataRef lb_debug_basic_struct(lbModule *m, String const &name, u64 size_in_bits, u32 align_in_bits, LLVMMetadataRef *elements, unsigned element_count) {
AstPackage *pkg = m->info->runtime_package;
GB_ASSERT(pkg->files.count != 0);
LLVMMetadataRef file = lb_get_llvm_metadata(m, pkg->files[0]);
@@ -117,7 +115,7 @@ LLVMMetadataRef lb_debug_basic_struct(lbModule *m, String const &name, u64 size_
}
LLVMMetadataRef lb_debug_type_basic_type(lbModule *m, String const &name, u64 size_in_bits, LLVMDWARFTypeEncoding encoding, LLVMDIFlags flags = LLVMDIFlagZero) {
gb_internal LLVMMetadataRef lb_debug_type_basic_type(lbModule *m, String const &name, u64 size_in_bits, LLVMDWARFTypeEncoding encoding, LLVMDIFlags flags = LLVMDIFlagZero) {
LLVMMetadataRef basic_type = LLVMDIBuilderCreateBasicType(m->debug_builder, cast(char const *)name.text, name.len, size_in_bits, encoding, flags);
#if 1
LLVMMetadataRef final_decl = LLVMDIBuilderCreateTypedef(m->debug_builder, basic_type, cast(char const *)name.text, name.len, nullptr, 0, nullptr, cast(u32)size_in_bits);
@@ -127,7 +125,7 @@ LLVMMetadataRef lb_debug_type_basic_type(lbModule *m, String const &name, u64 si
#endif
}
LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
gb_internal LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
i64 size = type_size_of(type); // Check size
gb_unused(size);
@@ -474,7 +472,7 @@ LLVMMetadataRef lb_debug_type_internal(lbModule *m, Type *type) {
return nullptr;
}
LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope) {
gb_internal LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope) {
LLVMMetadataRef found = nullptr;
for (;;) {
if (scope == nullptr) {
@@ -496,13 +494,15 @@ LLVMMetadataRef lb_get_base_scope_metadata(lbModule *m, Scope *scope) {
}
}
LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
gb_internal LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
GB_ASSERT(type != nullptr);
LLVMMetadataRef found = lb_get_llvm_metadata(m, type);
if (found != nullptr) {
return found;
}
MUTEX_GUARD(&m->debug_values_mutex);
if (type->kind == Type_Named) {
LLVMMetadataRef file = nullptr;
unsigned line = 0;
@@ -615,11 +615,13 @@ LLVMMetadataRef lb_debug_type(lbModule *m, Type *type) {
return dt;
}
void lb_debug_complete_types(lbModule *m) {
gb_internal void lb_debug_complete_types(lbModule *m) {
/* unsigned const word_size = cast(unsigned)build_context.word_size; */
unsigned const word_bits = cast(unsigned)(8*build_context.word_size);
for_array(debug_incomplete_type_index, m->debug_incomplete_types) {
TEMPORARY_ALLOCATOR_GUARD();
auto const &idt = m->debug_incomplete_types[debug_incomplete_type_index];
GB_ASSERT(idt.type != nullptr);
GB_ASSERT(idt.metadata != nullptr);
@@ -962,7 +964,7 @@ void lb_debug_complete_types(lbModule *m) {
void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token) {
gb_internal void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token) {
if (p->debug_info == nullptr) {
return;
}
@@ -1024,7 +1026,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
LLVMDIBuilderInsertDeclareAtEnd(m->debug_builder, storage, var_info, llvm_expr, llvm_debug_loc, block);
}
void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block, lbArgKind arg_kind) {
gb_internal void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, Token const &token, unsigned arg_number, lbBlock *block, lbArgKind arg_kind) {
if (p->debug_info == nullptr) {
return;
}
@@ -1097,7 +1099,7 @@ void lb_add_debug_param_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
}
void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) {
gb_internal void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) {
if (!p->debug_info || !p->body) {
return;
}
@@ -1125,17 +1127,17 @@ void lb_add_debug_context_variable(lbProcedure *p, lbAddr const &ctx) {
}
String debug_info_mangle_constant_name(Entity *e, bool *did_allocate_) {
gb_internal String debug_info_mangle_constant_name(Entity *e, gbAllocator const &allocator, bool *did_allocate_) {
String name = e->token.string;
if (e->pkg && e->pkg->name.len > 0) {
// NOTE(bill): C++ NONSENSE FOR DEBUG SHITE!
name = concatenate3_strings(heap_allocator(), e->pkg->name, str_lit("::"), name);
name = concatenate3_strings(allocator, e->pkg->name, str_lit("::"), name);
if (did_allocate_) *did_allocate_ = true;
}
return name;
}
void add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMetadataRef dtype, LLVMMetadataRef expr) {
gb_internal void add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMetadataRef dtype, LLVMMetadataRef expr) {
LLVMMetadataRef scope = nullptr;
LLVMMetadataRef file = nullptr;
unsigned line = 0;
@@ -1151,14 +1153,11 @@ void add_debug_info_global_variable_expr(lbModule *m, String const &name, LLVMMe
expr, decl, 8/*AlignInBits*/);
}
void add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLVMMetadataRef dtype, i64 v) {
gb_internal void add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLVMMetadataRef dtype, i64 v) {
LLVMMetadataRef expr = LLVMDIBuilderCreateConstantValueExpression(m->debug_builder, v);
bool did_allocate = false;
String name = debug_info_mangle_constant_name(e, &did_allocate);
defer (if (did_allocate) {
gb_free(heap_allocator(), name.text);
});
TEMPORARY_ALLOCATOR_GUARD();
String name = debug_info_mangle_constant_name(e, temporary_allocator(), nullptr);
add_debug_info_global_variable_expr(m, name, dtype, expr);
if ((e->pkg && e->pkg->kind == Package_Init) ||
@@ -1167,7 +1166,7 @@ void add_debug_info_for_global_constant_internal_i64(lbModule *m, Entity *e, LLV
}
}
void add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e) {
gb_internal void add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e) {
if (e == nullptr || e->kind != Entity_Constant) {
return;
}
@@ -1176,7 +1175,7 @@ void add_debug_info_for_global_constant_from_entity(lbGenerator *gen, Entity *e)
}
lbModule *m = &gen->default_module;
if (USE_SEPARATE_MODULES) {
m = lb_pkg_module(gen, e->pkg);
m = lb_module_of_entity(gen, e);
}
if (is_type_integer(e->type)) {
+62 -60
View File
@@ -1,6 +1,6 @@
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise);
lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
gb_internal lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast *right, Type *type) {
lbModule *m = p->module;
lbBlock *rhs = lb_create_block(p, "logical.cmp.rhs");
@@ -61,8 +61,7 @@ lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast
GB_ASSERT(incoming_values.count > 0);
LLVMTypeRef phi_type = nullptr;
for_array(i, incoming_values) {
LLVMValueRef incoming_value = incoming_values[i];
for (LLVMValueRef incoming_value : incoming_values) {
if (!LLVMIsConstant(incoming_value)) {
phi_type = LLVMTypeOf(incoming_value);
break;
@@ -113,7 +112,7 @@ lbValue lb_emit_logical_binary_expr(lbProcedure *p, TokenKind op, Ast *left, Ast
}
lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) {
gb_internal lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type) {
switch (op) {
case Token_Add:
return x;
@@ -134,7 +133,7 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
Type *elem_type = base_array_type(type);
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
lbAddr res_addr = lb_add_local(p, type, nullptr, false, 0, true);
lbAddr res_addr = lb_add_local(p, type, nullptr, false, true);
lbValue res = lb_addr_get_ptr(p, res_addr);
bool inline_array_arith = lb_can_try_to_inline_array_arith(type);
@@ -283,7 +282,7 @@ lbValue lb_emit_unary_arith(lbProcedure *p, TokenKind op, lbValue x, Type *type)
return res;
}
bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, lbValue *res_) {
gb_internal bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, lbValue *res_) {
GB_ASSERT(is_type_array_like(type));
Type *elem_type = base_array_type(type);
@@ -418,7 +417,7 @@ bool lb_try_direct_vector_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbVal
}
lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
gb_internal lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
GB_ASSERT(is_type_array_like(lhs.type) || is_type_array_like(rhs.type));
lhs = lb_emit_conv(p, lhs, type);
@@ -490,7 +489,7 @@ lbValue lb_emit_arith_array(lbProcedure *p, TokenKind op, lbValue lhs, lbValue r
}
}
bool lb_is_matrix_simdable(Type *t) {
gb_internal bool lb_is_matrix_simdable(Type *t) {
Type *mt = base_type(t);
GB_ASSERT(mt->kind == Type_Matrix);
@@ -510,6 +509,11 @@ bool lb_is_matrix_simdable(Type *t) {
case TargetArch_arm64:
break;
}
if (type_align_of(t) < 16) {
// it's not aligned well enough to use the vector instructions
return false;
}
if (elem->kind == Type_Basic) {
switch (elem->Basic.kind) {
@@ -534,7 +538,7 @@ bool lb_is_matrix_simdable(Type *t) {
}
LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
gb_internal LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
Type *mt = base_type(matrix.type);
GB_ASSERT(mt->kind == Type_Matrix);
LLVMTypeRef elem_type = lb_type(p->module, mt->Matrix.elem);
@@ -554,7 +558,7 @@ LLVMValueRef lb_matrix_to_vector(lbProcedure *p, lbValue matrix) {
#endif
}
LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) {
gb_internal LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) {
mt = base_type(mt);
GB_ASSERT(mt->kind == Type_Matrix);
@@ -574,7 +578,7 @@ LLVMValueRef lb_matrix_trimmed_vector_mask(lbProcedure *p, Type *mt) {
return mask;
}
LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) {
gb_internal LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) {
LLVMValueRef vector = lb_matrix_to_vector(p, m);
Type *mt = base_type(m.type);
@@ -592,7 +596,7 @@ LLVMValueRef lb_matrix_to_trimmed_vector(lbProcedure *p, lbValue m) {
}
lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
gb_internal lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
if (is_type_array(m.type)) {
i32 rank = type_math_rank(m.type);
if (rank == 2) {
@@ -669,7 +673,7 @@ lbValue lb_emit_matrix_tranpose(lbProcedure *p, lbValue m, Type *type) {
return lb_addr_load(p, res);
}
lbValue lb_matrix_cast_vector_to_type(lbProcedure *p, LLVMValueRef vector, Type *type) {
gb_internal lbValue lb_matrix_cast_vector_to_type(lbProcedure *p, LLVMValueRef vector, Type *type) {
lbAddr res = lb_add_local_generated(p, type, true);
LLVMValueRef res_ptr = res.addr.value;
unsigned alignment = cast(unsigned)gb_max(type_align_of(type), lb_alignof(LLVMTypeOf(vector)));
@@ -681,7 +685,7 @@ lbValue lb_matrix_cast_vector_to_type(lbProcedure *p, LLVMValueRef vector, Type
return lb_addr_load(p, res);
}
lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type) {
gb_internal lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type) {
if (is_type_array(m.type)) {
// no-op
m.type = type;
@@ -710,7 +714,7 @@ lbValue lb_emit_matrix_flatten(lbProcedure *p, lbValue m, Type *type) {
}
lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type) {
gb_internal lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type) {
Type *mt = base_type(type);
Type *at = base_type(a.type);
Type *bt = base_type(b.type);
@@ -741,7 +745,7 @@ lbValue lb_emit_outer_product(lbProcedure *p, lbValue a, lbValue b, Type *type)
}
lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
gb_internal lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
Type *xt = base_type(lhs.type);
@@ -828,7 +832,7 @@ lbValue lb_emit_matrix_mul(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type)
}
}
lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
gb_internal lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
Type *mt = base_type(lhs.type);
@@ -897,7 +901,7 @@ lbValue lb_emit_matrix_mul_vector(lbProcedure *p, lbValue lhs, lbValue rhs, Type
return lb_addr_load(p, res);
}
lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
gb_internal lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type *type) {
// TODO(bill): Handle edge case for f16 types on x86(-64) platforms
Type *mt = base_type(rhs.type);
@@ -984,7 +988,7 @@ lbValue lb_emit_vector_mul_matrix(lbProcedure *p, lbValue lhs, lbValue rhs, Type
lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise) {
gb_internal lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type, bool component_wise) {
GB_ASSERT(is_type_matrix(lhs.type) || is_type_matrix(rhs.type));
if (op == Token_Mul && !component_wise) {
@@ -1056,7 +1060,7 @@ lbValue lb_emit_arith_matrix(lbProcedure *p, TokenKind op, lbValue lhs, lbValue
lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
gb_internal lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Type *type) {
if (is_type_array_like(lhs.type) || is_type_array_like(rhs.type)) {
return lb_emit_arith_array(p, op, lhs, rhs, type);
} else if (is_type_matrix(lhs.type) || is_type_matrix(rhs.type)) {
@@ -1164,6 +1168,9 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty
}
}
lhs = lb_emit_conv(p, lhs, type);
rhs = lb_emit_conv(p, rhs, type);
if (is_type_integer(type) && is_type_different_to_arch_endianness(type)) {
switch (op) {
case Token_AndNot:
@@ -1192,10 +1199,7 @@ lbValue lb_emit_arith(lbProcedure *p, TokenKind op, lbValue lhs, lbValue rhs, Ty
return lb_emit_byte_swap(p, res, type);
}
handle_op:
lhs = lb_emit_conv(p, lhs, type);
rhs = lb_emit_conv(p, rhs, type);
handle_op:;
lbValue res = {};
res.type = type;
@@ -1325,7 +1329,7 @@ handle_op:
return {};
}
lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
ast_node(be, BinaryExpr, expr);
TypeAndValue tv = type_and_value_of_expr(expr);
@@ -1472,7 +1476,7 @@ lbValue lb_build_binary_expr(lbProcedure *p, Ast *expr) {
return {};
}
lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
gb_internal lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
lbModule *m = p->module;
t = reduce_tuple_to_single_type(t);
@@ -1554,13 +1558,13 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
if (is_type_boolean(src) && dst == t_llvm_bool) {
lbValue res = {};
res.value = LLVMBuildTrunc(p->builder, value.value, lb_type(m, dst), "");
res.type = dst;
res.type = t;
return res;
}
if (src == t_llvm_bool && is_type_boolean(dst)) {
lbValue res = {};
res.value = LLVMBuildZExt(p->builder, value.value, lb_type(m, dst), "");
res.type = dst;
res.type = t;
return res;
}
@@ -1921,8 +1925,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
}
if (is_type_union(dst)) {
for_array(i, dst->Union.variants) {
Type *vt = dst->Union.variants[i];
for (Type *vt : dst->Union.variants) {
if (are_types_identical(vt, src_type)) {
lbAddr parent = lb_add_local_generated(p, t, true);
lb_emit_store_union_variant(p, parent.addr, value, vt);
@@ -2159,7 +2162,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
// bit_set <-> integer
if (is_type_integer(src) && is_type_bit_set(dst)) {
lbValue res = lb_emit_conv(p, value, bit_set_to_int(dst));
res.type = dst;
res.type = t;
return res;
}
if (is_type_bit_set(src) && is_type_integer(dst)) {
@@ -2202,7 +2205,7 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
return {};
}
lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right, Type *type) {
gb_internal lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right, Type *type) {
GB_ASSERT((is_type_struct(type) || is_type_union(type)) && is_type_comparable(type));
lbValue left_ptr = lb_address_from_load_or_generate_local(p, left);
lbValue right_ptr = lb_address_from_load_or_generate_local(p, right);
@@ -2230,7 +2233,7 @@ lbValue lb_compare_records(lbProcedure *p, TokenKind op_kind, lbValue left, lbVa
lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) {
gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue right) {
Type *a = core_type(left.type);
Type *b = core_type(right.type);
@@ -2642,7 +2645,7 @@ lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left, lbValue ri
lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
gb_internal lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
lbValue res = {};
res.type = t_llvm_bool;
Type *t = x.type;
@@ -2803,7 +2806,7 @@ lbValue lb_emit_comp_against_nil(lbProcedure *p, TokenKind op_kind, lbValue x) {
return {};
}
lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbValue const &index) {
gb_internal lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbValue const &index) {
lbAddr v = lb_add_local_generated(p, type, false);
lbValue ptr = lb_emit_struct_ep(p, v.addr, 0);
lbValue idx = lb_emit_struct_ep(p, v.addr, 1);
@@ -2813,7 +2816,7 @@ lbValue lb_make_soa_pointer(lbProcedure *p, Type *type, lbValue const &addr, lbV
return lb_addr_load(p, v);
}
lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
ast_node(ue, UnaryExpr, expr);
auto tv = type_and_value_of_expr(expr);
@@ -3023,8 +3026,8 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
return lb_build_addr_ptr(p, ue->expr);
}
lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr);
lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr);
gb_internal lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
u16 prev_state_flags = p->state_flags;
defer (p->state_flags = prev_state_flags);
@@ -3080,7 +3083,7 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr) {
return res;
}
lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
lbModule *m = p->module;
expr = unparen_expr(expr);
@@ -3099,6 +3102,9 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
// NOTE(bill): Short on constant values
return lb_const_value(p->module, type, tv.value);
} else if (tv.mode == Addressing_Type) {
// NOTE(bill, 2023-01-16): is this correct? I hope so at least
return lb_typeid(m, tv.type);
}
switch (expr->kind) {
@@ -3355,10 +3361,10 @@ lbValue lb_build_expr_internal(lbProcedure *p, Ast *expr) {
return {};
}
lbAddr lb_get_soa_variable_addr(lbProcedure *p, Entity *e) {
gb_internal lbAddr lb_get_soa_variable_addr(lbProcedure *p, Entity *e) {
return map_must_get(&p->module->soa_values, e);
}
lbValue lb_get_using_variable(lbProcedure *p, Entity *e) {
gb_internal lbValue lb_get_using_variable(lbProcedure *p, Entity *e) {
GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Using);
String name = e->token.string;
Entity *parent = e->using_parent;
@@ -3393,7 +3399,7 @@ lbValue lb_get_using_variable(lbProcedure *p, Entity *e) {
lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) {
gb_internal lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) {
GB_ASSERT(e != nullptr);
if (e->kind == Entity_Constant) {
Type *t = default_type(type_of_expr(expr));
@@ -3427,7 +3433,7 @@ lbAddr lb_build_addr_from_entity(lbProcedure *p, Entity *e, Ast *expr) {
return lb_addr(v);
}
lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
gb_internal lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
isize index_count = ce->args.count-1;
lbAddr addr = lb_build_addr(p, ce->args[0]);
if (index_count == 0) {
@@ -3463,8 +3469,8 @@ lbAddr lb_build_array_swizzle_addr(lbProcedure *p, AstCallExpr *ce, TypeAndValue
}
lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr);
lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr);
gb_internal lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
expr = unparen_expr(expr);
// IMPORTANT NOTE(bill):
@@ -3489,7 +3495,7 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
return addr;
}
void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice<Ast *> const &elems, Array<lbCompoundLitElemTempData> *temp_data, Type *compound_type) {
gb_internal void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice<Ast *> const &elems, Array<lbCompoundLitElemTempData> *temp_data, Type *compound_type) {
Type *bt = base_type(compound_type);
Type *et = nullptr;
switch (bt->kind) {
@@ -3595,9 +3601,8 @@ void lb_build_addr_compound_lit_populate(lbProcedure *p, Slice<Ast *> const &ele
}
}
}
void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array<lbCompoundLitElemTempData> const &temp_data) {
for_array(i, temp_data) {
auto td = temp_data[i];
gb_internal void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array<lbCompoundLitElemTempData> const &temp_data) {
for (auto const &td : temp_data) {
if (td.value.value != nullptr) {
if (td.elem_length > 0) {
auto loop_data = lb_loop_start(p, cast(isize)td.elem_length, t_i32);
@@ -3614,7 +3619,7 @@ void lb_build_addr_compound_lit_assign_array(lbProcedure *p, Array<lbCompoundLit
}
}
lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
gb_internal lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
ast_node(ie, IndexExpr, expr);
Type *t = base_type(type_of_expr(ie->expr));
@@ -3833,7 +3838,7 @@ lbAddr lb_build_addr_index_expr(lbProcedure *p, Ast *expr) {
}
lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
gb_internal lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
ast_node(se, SliceExpr, expr);
lbValue low = lb_const_int(p->module, t_int, 0);
@@ -4031,7 +4036,7 @@ lbAddr lb_build_addr_slice_expr(lbProcedure *p, Ast *expr) {
}
lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
gb_internal lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
ast_node(cl, CompoundLit, expr);
Type *type = type_of_expr(expr);
@@ -4129,8 +4134,7 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
lbValue err = lb_dynamic_map_reserve(p, v.addr, 2*cl->elems.count, pos);
gb_unused(err);
for_array(field_index, cl->elems) {
Ast *elem = cl->elems[field_index];
for (Ast *elem : cl->elems) {
ast_node(fv, FieldValue, elem);
lbValue key = lb_build_expr(p, fv->field);
@@ -4304,8 +4308,7 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
lb_addr_store(p, v, lb_const_value(p->module, type, exact_value_compound(expr)));
lbValue lower = lb_const_value(p->module, t_int, exact_value_i64(bt->BitSet.lower));
for_array(i, cl->elems) {
Ast *elem = cl->elems[i];
for (Ast *elem : cl->elems) {
GB_ASSERT(elem->kind != Ast_FieldValue);
if (lb_is_elem_const(elem, et)) {
@@ -4359,8 +4362,7 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
// TODO(bill): reduce the need for individual `insertelement` if a `shufflevector`
// might be a better option
for_array(i, temp_data) {
auto td = temp_data[i];
for (auto const &td : temp_data) {
if (td.value.value != nullptr) {
if (td.elem_length > 0) {
for (i64 k = 0; k < td.elem_length; k++) {
@@ -4383,7 +4385,7 @@ lbAddr lb_build_addr_compound_lit(lbProcedure *p, Ast *expr) {
}
lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
gb_internal lbAddr lb_build_addr_internal(lbProcedure *p, Ast *expr) {
switch (expr->kind) {
case_ast_node(i, Implicit, expr);
lbAddr v = {};
File diff suppressed because it is too large Load Diff
+28 -25
View File
@@ -32,21 +32,21 @@
**************************************************************************/
void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level);
void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimization_level);
void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPassManagerRef mpm, i32 optimization_level);
void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level);
gb_internal void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level);
gb_internal void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimization_level);
gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPassManagerRef mpm, i32 optimization_level);
gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level);
LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data) {
lbModule *m = cast(lbModule *)user_data;
if (m == nullptr) {
return false;
}
if (value == nullptr) {
return false;
}
return LLVMIsAAllocaInst(value) != nullptr;
}
// gb_internal LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data) {
// lbModule *m = cast(lbModule *)user_data;
// if (m == nullptr) {
// return false;
// }
// if (value == nullptr) {
// return false;
// }
// return LLVMIsAAllocaInst(value) != nullptr;
// }
#if LLVM_VERSION_MAJOR < 12
@@ -55,7 +55,7 @@ LLVMBool lb_must_preserve_predicate_callback(LLVMValueRef value, void *user_data
#define LLVM_ADD_CONSTANT_VALUE_PASS(fpm)
#endif
void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) {
gb_internal void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimization_level) {
if (false && optimization_level == 0 && build_context.ODIN_DEBUG) {
LLVMAddMergedLoadStoreMotionPass(fpm);
} else {
@@ -68,7 +68,7 @@ void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimiz
}
}
void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level) {
gb_internal void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool ignore_memcpy_pass, i32 optimization_level) {
// NOTE(bill): Treat -opt:3 as if it was -opt:2
// TODO(bill): Determine which opt definitions should exist in the first place
optimization_level = gb_clamp(optimization_level, 0, 2);
@@ -102,7 +102,7 @@ void lb_populate_function_pass_manager(lbModule *m, LLVMPassManagerRef fpm, bool
#endif
}
void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level) {
gb_internal void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef fpm, i32 optimization_level) {
// NOTE(bill): Treat -opt:3 as if it was -opt:2
// TODO(bill): Determine which opt definitions should exist in the first place
optimization_level = gb_clamp(optimization_level, 0, 2);
@@ -141,7 +141,7 @@ void lb_populate_function_pass_manager_specific(lbModule *m, LLVMPassManagerRef
#endif
}
void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimization_level) {
gb_internal void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimization_level) {
LLVMAddCFGSimplificationPass(mpm);
LLVMAddJumpThreadingPass(mpm);
@@ -177,7 +177,7 @@ void lb_add_function_simplifcation_passes(LLVMPassManagerRef mpm, i32 optimizati
}
void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPassManagerRef mpm, i32 optimization_level) {
gb_internal void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPassManagerRef mpm, i32 optimization_level) {
// NOTE(bill): Treat -opt:3 as if it was -opt:2
// TODO(bill): Determine which opt definitions should exist in the first place
@@ -266,7 +266,7 @@ void lb_populate_module_pass_manager(LLVMTargetMachineRef target_machine, LLVMPa
optimization of Odin programs
**************************************************************************/
void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
gb_internal void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
isize removal_count = 0;
isize pass_count = 0;
isize const max_pass_count = 10;
@@ -358,7 +358,10 @@ void lb_run_remove_dead_instruction_pass(lbProcedure *p) {
}
void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
gb_internal void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
if (p == nullptr) {
return;
}
LLVMRunFunctionPassManager(fpm, p->value);
// NOTE(bill): LLVMAddDCEPass doesn't seem to be exported in the official DLL's for LLVM
// which means we cannot rely upon it
@@ -367,7 +370,7 @@ void lb_run_function_pass_manager(LLVMPassManagerRef fpm, lbProcedure *p) {
lb_run_remove_dead_instruction_pass(p);
}
void llvm_delete_function(LLVMValueRef func) {
gb_internal void llvm_delete_function(LLVMValueRef func) {
// for (LLVMBasicBlockRef block = LLVMGetFirstBasicBlock(func); block != nullptr; /**/) {
// LLVMBasicBlockRef curr_block = block;
// block = LLVMGetNextBasicBlock(block);
@@ -382,7 +385,7 @@ void llvm_delete_function(LLVMValueRef func) {
LLVMDeleteFunction(func);
}
void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) {
gb_internal void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) {
LLVMValueRef global = LLVMGetNamedGlobal(m->mod, "llvm.compiler.used");
LLVMValueRef *constants;
@@ -419,7 +422,7 @@ void lb_append_to_compiler_used(lbModule *m, LLVMValueRef func) {
LLVMSetInitializer(global, initializer);
}
void lb_run_remove_unused_function_pass(lbModule *m) {
gb_internal void lb_run_remove_unused_function_pass(lbModule *m) {
isize removal_count = 0;
isize pass_count = 0;
isize const max_pass_count = 10;
@@ -470,7 +473,7 @@ void lb_run_remove_unused_function_pass(lbModule *m) {
}
void lb_run_remove_unused_globals_pass(lbModule *m) {
gb_internal void lb_run_remove_unused_globals_pass(lbModule *m) {
isize removal_count = 0;
isize pass_count = 0;
isize const max_pass_count = 10;
+253 -127
View File
@@ -1,6 +1,4 @@
LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count)
{
gb_internal LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count) {
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, type_count);
@@ -8,7 +6,7 @@ LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* a
return LLVMBuildCall2(p->builder, call_type, ip, args, arg_count, "");
}
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
gb_internal void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
dst = lb_emit_conv(p, dst, t_rawptr);
src = lb_emit_conv(p, src, t_rawptr);
len = lb_emit_conv(p, len, t_int);
@@ -37,7 +35,7 @@ void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue l
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
gb_internal void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
dst = lb_emit_conv(p, dst, t_rawptr);
src = lb_emit_conv(p, src, t_rawptr);
len = lb_emit_conv(p, len, t_int);
@@ -66,17 +64,19 @@ void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbVal
}
lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) {
gb_internal lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body) {
GB_ASSERT(entity != nullptr);
GB_ASSERT(entity->kind == Entity_Procedure);
if (!entity->Procedure.is_foreign) {
GB_ASSERT_MSG(entity->flags & EntityFlag_ProcBodyChecked, "%.*s :: %s", LIT(entity->token.string), type_to_string(entity->type));
if ((entity->flags & EntityFlag_ProcBodyChecked) == 0) {
GB_PANIC("%.*s :: %s (was parapoly: %d %d)", LIT(entity->token.string), type_to_string(entity->type), is_type_polymorphic(entity->type, true), is_type_polymorphic(entity->type, false));
}
}
String link_name = {};
if (ignore_body) {
lbModule *other_module = lb_pkg_module(m->gen, entity->pkg);
lbModule *other_module = lb_module_of_entity(m->gen, entity);
link_name = lb_get_entity_name(other_module, entity);
} else {
link_name = lb_get_entity_name(m, entity);
@@ -121,8 +121,9 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
p->branch_blocks.allocator = a;
p->context_stack.allocator = a;
p->scope_stack.allocator = a;
map_init(&p->selector_values, a, 0);
map_init(&p->selector_addr, a, 0);
map_init(&p->selector_values, 0);
map_init(&p->selector_addr, 0);
map_init(&p->tuple_fix_map, 0);
if (p->is_foreign) {
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
@@ -191,11 +192,6 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
lb_add_attribute_to_proc(m, p->value, "cold");
}
lbValue proc_value = {p->value, p->type};
lb_add_entity(m, entity, proc_value);
lb_add_member(m, p->name, proc_value);
lb_add_procedure_value(m, p);
if (p->is_export) {
LLVMSetLinkage(p->value, LLVMDLLExportLinkage);
LLVMSetDLLStorageClass(p->value, LLVMDLLExportStorageClass);
@@ -203,7 +199,9 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
lb_set_wasm_export_attributes(p->value, p->name);
} else if (!p->is_foreign) {
if (!USE_SEPARATE_MODULES) {
if (USE_SEPARATE_MODULES) {
LLVMSetLinkage(p->value, LLVMExternalLinkage);
} else {
LLVMSetLinkage(p->value, LLVMInternalLinkage);
// NOTE(bill): if a procedure is defined in package runtime and uses a custom link name,
@@ -317,10 +315,15 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
}
}
lbValue proc_value = {p->value, p->type};
lb_add_entity(m, entity, proc_value);
lb_add_member(m, p->name, proc_value);
lb_add_procedure_value(m, p);
return p;
}
lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) {
gb_internal lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type) {
{
lbValue *found = string_map_get(&m->members, link_name);
GB_ASSERT_MSG(found == nullptr, "failed to create dummy procedure for: %.*s", LIT(link_name));
@@ -346,6 +349,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
p->blocks.allocator = a;
p->branch_blocks.allocator = a;
p->context_stack.allocator = a;
map_init(&p->tuple_fix_map, 0);
char *c_link_name = alloc_cstring(permanent_allocator(), p->name);
@@ -383,50 +387,50 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
}
lbValue lb_value_param(lbProcedure *p, Entity *e, Type *abi_type, i32 index, lbParamPasskind *kind_) {
lbParamPasskind kind = lbParamPass_Value;
// gb_internal lbValue lb_value_param(lbProcedure *p, Entity *e, Type *abi_type, i32 index, lbParamPasskind *kind_) {
// lbParamPasskind kind = lbParamPass_Value;
if (e != nullptr && !are_types_identical(abi_type, e->type)) {
if (is_type_pointer(abi_type)) {
GB_ASSERT(e->kind == Entity_Variable);
Type *av = core_type(type_deref(abi_type));
if (are_types_identical(av, core_type(e->type))) {
kind = lbParamPass_Pointer;
if (e->flags&EntityFlag_Value) {
kind = lbParamPass_ConstRef;
}
} else {
kind = lbParamPass_BitCast;
}
} else if (is_type_integer(abi_type)) {
kind = lbParamPass_Integer;
} else if (abi_type == t_llvm_bool) {
kind = lbParamPass_Value;
} else if (is_type_boolean(abi_type)) {
kind = lbParamPass_Integer;
} else if (is_type_simd_vector(abi_type)) {
kind = lbParamPass_BitCast;
} else if (is_type_float(abi_type)) {
kind = lbParamPass_BitCast;
} else if (is_type_tuple(abi_type)) {
kind = lbParamPass_Tuple;
} else if (is_type_proc(abi_type)) {
kind = lbParamPass_Value;
} else {
GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type));
}
}
// if (e != nullptr && !are_types_identical(abi_type, e->type)) {
// if (is_type_pointer(abi_type)) {
// GB_ASSERT(e->kind == Entity_Variable);
// Type *av = core_type(type_deref(abi_type));
// if (are_types_identical(av, core_type(e->type))) {
// kind = lbParamPass_Pointer;
// if (e->flags&EntityFlag_Value) {
// kind = lbParamPass_ConstRef;
// }
// } else {
// kind = lbParamPass_BitCast;
// }
// } else if (is_type_integer(abi_type)) {
// kind = lbParamPass_Integer;
// } else if (abi_type == t_llvm_bool) {
// kind = lbParamPass_Value;
// } else if (is_type_boolean(abi_type)) {
// kind = lbParamPass_Integer;
// } else if (is_type_simd_vector(abi_type)) {
// kind = lbParamPass_BitCast;
// } else if (is_type_float(abi_type)) {
// kind = lbParamPass_BitCast;
// } else if (is_type_tuple(abi_type)) {
// kind = lbParamPass_Tuple;
// } else if (is_type_proc(abi_type)) {
// kind = lbParamPass_Value;
// } else {
// GB_PANIC("Invalid abi type pass kind %s", type_to_string(abi_type));
// }
// }
if (kind_) *kind_ = kind;
lbValue res = {};
res.value = LLVMGetParam(p->value, cast(unsigned)index);
res.type = abi_type;
return res;
}
// if (kind_) *kind_ = kind;
// lbValue res = {};
// res.value = LLVMGetParam(p->value, cast(unsigned)index);
// res.type = abi_type;
// return res;
// }
void lb_start_block(lbProcedure *p, lbBlock *b) {
gb_internal void lb_start_block(lbProcedure *p, lbBlock *b) {
GB_ASSERT(b != nullptr);
if (!b->appended) {
b->appended = true;
@@ -436,7 +440,7 @@ void lb_start_block(lbProcedure *p, lbBlock *b) {
p->curr_block = b;
}
void lb_set_debug_position_to_procedure_begin(lbProcedure *p) {
gb_internal void lb_set_debug_position_to_procedure_begin(lbProcedure *p) {
if (p->debug_info == nullptr) {
return;
}
@@ -453,7 +457,7 @@ void lb_set_debug_position_to_procedure_begin(lbProcedure *p) {
}
}
void lb_set_debug_position_to_procedure_end(lbProcedure *p) {
gb_internal void lb_set_debug_position_to_procedure_end(lbProcedure *p) {
if (p->debug_info == nullptr) {
return;
}
@@ -470,7 +474,7 @@ void lb_set_debug_position_to_procedure_end(lbProcedure *p) {
}
}
void lb_begin_procedure_body(lbProcedure *p) {
gb_internal void lb_begin_procedure_body(lbProcedure *p) {
DeclInfo *decl = decl_info_of_entity(p->entity);
if (decl != nullptr) {
for_array(i, decl->labels) {
@@ -486,7 +490,7 @@ void lb_begin_procedure_body(lbProcedure *p) {
p->entry_block = lb_create_block(p, "entry", true);
lb_start_block(p, p->entry_block);
map_init(&p->direct_parameters, heap_allocator());
map_init(&p->direct_parameters);
GB_ASSERT(p->type != nullptr);
@@ -501,8 +505,23 @@ void lb_begin_procedure_body(lbProcedure *p) {
// NOTE(bill): this must be parameter 0
String name = str_lit("agg.result");
if (ft->multiple_return_original_type &&
p->type->Proc.has_named_results) {
auto const &variables = p->type->Proc.results->Tuple.variables;
Entity *e = variables[variables.count-1];
if (!is_blank_ident(e->token)) {
name = e->token.string;
}
}
Type *ptr_type = alloc_type_pointer(reduce_tuple_to_single_type(p->type->Proc.results));
Type *return_ptr_type = reduce_tuple_to_single_type(p->type->Proc.results);
bool split_returns = ft->multiple_return_original_type != nullptr;
if (split_returns) {
GB_ASSERT(is_type_tuple(return_ptr_type));
auto const &variables = return_ptr_type->Tuple.variables;
return_ptr_type = variables[variables.count-1]->type;
}
Type *ptr_type = alloc_type_pointer(return_ptr_type);
Entity *e = alloc_entity_param(nullptr, make_token_ident(name), ptr_type, false, false);
e->flags |= EntityFlag_NoAlias;
@@ -580,14 +599,70 @@ void lb_begin_procedure_body(lbProcedure *p) {
if (e->token.string != "") {
GB_ASSERT(!is_blank_ident(e->token));
// NOTE(bill): Don't even bother trying to optimize this with the return ptr value
// This will violate the defer rules if you do:
// foo :: proc() -> (x, y: T) {
// defer x = ... // defer is executed after the `defer`
// return // the values returned should be zeroed
// }
// NOTE(bill): REALLY, don't even bother.
lbAddr res = lb_add_local(p, e->type, e);
lbAddr res = {};
if (p->entity && p->entity->decl_info &&
p->entity->decl_info->defer_use_checked &&
p->entity->decl_info->defer_used == 0) {
// NOTE(bill): this is a bodge to get around the issue of the problem BELOW
// We check to see if we ever use a defer statement ever within a procedure and if it
// if it never happens, see if you can possibly do take the return value pointer
//
// NOTE(bill): this could be buggy in that I have missed a case where `defer` was used
//
// TODO(bill): This could be optimized to check to see where a `defer` only uses
// the variable in question
bool has_return_ptr = p->return_ptr.addr.value != nullptr;
lbValue ptr = {};
if (ft->multiple_return_original_type != nullptr) {
isize the_offset = -1;
if (i+1 < results->variables.count) {
the_offset = cast(isize)param_offset + ft->original_arg_count + i;
} else if (has_return_ptr) {
GB_ASSERT(i+1 == results->variables.count);
the_offset = 0;
}
if (the_offset >= 0) {
lbValue ptr = {};
ptr.value = LLVMGetParam(p->value, cast(unsigned)the_offset);
ptr.type = alloc_type_pointer(e->type);
}
} else if (has_return_ptr) {
lbValue ptr = p->return_ptr.addr;
if (results->variables.count > 1) {
ptr = lb_emit_tuple_ep(p, ptr, cast(i32)i);
}
GB_ASSERT(is_type_pointer(ptr.type));
GB_ASSERT(are_types_identical(type_deref(ptr.type), e->type));
}
if (ptr.value != nullptr) {
lb_add_entity(p->module, e, ptr);
lb_add_debug_local_variable(p, ptr.value, e->type, e->token);
// NOTE(bill): no need to zero on the callee side as it is zeroed on the caller side
res = lb_addr(ptr);
}
}
if (res.addr.type == nullptr) {
// NOTE(bill): Don't even bother trying to optimize this with the return ptr value
// This will violate the defer rules if you do:
// foo :: proc() -> (x, y: T) {
// defer x = ... // defer is executed after the `defer`
// return // the values returned should be zeroed
// }
// NOTE(bill): REALLY, don't even bother.
//
// IMPORTANT NOTE(bill): REALLY, don't even bother!!!!!!
res = lb_add_local(p, e->type, e);
}
if (e->Variable.param_value.kind != ParameterValue_Invalid) {
lbValue c = lb_handle_param_value(p, e->type, e->Variable.param_value, e->token.pos);
lb_addr_store(p, res, c);
@@ -614,7 +689,7 @@ void lb_begin_procedure_body(lbProcedure *p) {
lb_start_block(p, p->entry_block);
}
void lb_end_procedure_body(lbProcedure *p) {
gb_internal void lb_end_procedure_body(lbProcedure *p) {
lb_set_debug_position_to_procedure_begin(p);
LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block);
@@ -648,11 +723,11 @@ void lb_end_procedure_body(lbProcedure *p) {
p->curr_block = nullptr;
p->state_flags = 0;
}
void lb_end_procedure(lbProcedure *p) {
gb_internal void lb_end_procedure(lbProcedure *p) {
LLVMDisposeBuilder(p->builder);
}
void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) {
gb_internal void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) {
GB_ASSERT(pd->body != nullptr);
lbModule *m = p->module;
auto *min_dep_set = &m->info->minimum_dependency_set;
@@ -694,21 +769,14 @@ void lb_build_nested_proc(lbProcedure *p, AstProcLit *pd, Entity *e) {
Array<lbValue> lb_value_to_array(lbProcedure *p, lbValue value) {
gb_internal Array<lbValue> lb_value_to_array(lbProcedure *p, lbValue value) {
Array<lbValue> array = {};
Type *t = base_type(value.type);
if (t == nullptr) {
// Do nothing
} else if (is_type_tuple(t)) {
GB_ASSERT(t->kind == Type_Tuple);
auto *rt = &t->Tuple;
if (rt->variables.count > 0) {
array = array_make<lbValue>(permanent_allocator(), rt->variables.count);
for_array(i, rt->variables) {
lbValue elem = lb_emit_struct_ev(p, value, cast(i32)i);
array[i] = elem;
}
}
array = array_make<lbValue>(permanent_allocator(), 0, t->Tuple.variables.count);
lb_append_tuple_values(p, &array, value);
} else {
array = array_make<lbValue>(permanent_allocator(), 1);
array[0] = value;
@@ -718,7 +786,7 @@ Array<lbValue> lb_value_to_array(lbProcedure *p, lbValue value) {
lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array<lbValue> const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining) {
gb_internal lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr, Array<lbValue> const &processed_args, Type *abi_rt, lbAddr context_ptr, ProcInlining inlining) {
GB_ASSERT(p->module->ctx == LLVMGetTypeContext(LLVMTypeOf(value.value)));
unsigned arg_count = cast(unsigned)processed_args.count;
@@ -734,6 +802,7 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
if (return_ptr.value != nullptr) {
args[arg_index++] = return_ptr.value;
}
for_array(i, processed_args) {
lbValue arg = processed_args[i];
if (is_type_proc(arg.type)) {
@@ -741,16 +810,23 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
}
args[arg_index++] = arg.value;
}
if (context_ptr.addr.value != nullptr) {
LLVMValueRef cp = context_ptr.addr.value;
cp = LLVMBuildPointerCast(p->builder, cp, lb_type(p->module, t_rawptr), "");
args[arg_index++] = cp;
}
GB_ASSERT(arg_index == arg_count);
LLVMBasicBlockRef curr_block = LLVMGetInsertBlock(p->builder);
GB_ASSERT(curr_block != p->decl_block->block);
{
LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type);
Type *proc_type = base_type(value.type);
GB_ASSERT(proc_type->kind == Type_Proc);
LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, proc_type);
LLVMTypeRef ftp = LLVMPointerType(fnp, 0);
LLVMValueRef fn = value.value;
if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) {
@@ -775,10 +851,11 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
// LLVMTypeKind arg_kind = LLVMGetTypeKind(arg_type);
GB_ASSERT_MSG(
arg_type == param_type,
"Parameter types do not match: %s != %s, argument: %s",
"Parameter types do not match: %s != %s, argument: %s\n\t%s",
LLVMPrintTypeToString(arg_type),
LLVMPrintTypeToString(param_type),
LLVMPrintValueToString(args[i])
LLVMPrintValueToString(args[i]),
LLVMPrintTypeToString(fnp)
);
}
}
@@ -818,20 +895,20 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
}
lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) {
gb_internal lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name) {
AstPackage *pkg = m->info->runtime_package;
Entity *e = scope_lookup_current(pkg->scope, name);
return lb_find_procedure_value_from_entity(m, e);
}
lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args) {
gb_internal lbValue lb_emit_runtime_call(lbProcedure *p, char const *c_name, Array<lbValue> const &args) {
String name = make_string_c(c_name);
lbValue proc = lb_lookup_runtime_procedure(p->module, name);
return lb_emit_call(p, proc, args);
}
lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) {
gb_internal lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) {
lbValue res = {};
Type *t = val.type;
if (is_type_complex(t)) {
@@ -882,7 +959,7 @@ lbValue lb_emit_conjugate(lbProcedure *p, lbValue val, Type *type) {
return lb_emit_load(p, res);
}
lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining, bool use_copy_elision_hint) {
gb_internal lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args, ProcInlining inlining) {
lbModule *m = p->module;
Type *pt = base_type(value.type);
@@ -915,8 +992,9 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
bool is_odin_cc = is_calling_convention_odin(pt->Proc.calling_convention);
lbFunctionType *ft = lb_get_function_type(m, p, pt);
lbFunctionType *ft = lb_get_function_type(m, pt);
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
bool split_returns = ft->multiple_return_original_type != nullptr;
unsigned param_index = 0;
for (isize i = 0; i < param_count; i++) {
@@ -979,18 +1057,19 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
}
Type *rt = reduce_tuple_to_single_type(results);
Type *original_rt = rt;
if (split_returns) {
GB_ASSERT(rt->kind == Type_Tuple);
for (isize j = 0; j < rt->Tuple.variables.count-1; j++) {
Type *partial_return_type = rt->Tuple.variables[j]->type;
lbValue partial_return_ptr = lb_add_local(p, partial_return_type, nullptr, true, false).addr;
array_add(&processed_args, partial_return_ptr);
}
rt = reduce_tuple_to_single_type(rt->Tuple.variables[rt->Tuple.variables.count-1]->type);
}
if (return_by_pointer) {
lbValue return_ptr = {};
if (use_copy_elision_hint && p->copy_elision_hint.ptr.value != nullptr) {
if (are_types_identical(type_deref(p->copy_elision_hint.ptr.type), rt)) {
return_ptr = lb_consume_copy_elision_hint(p);
}
}
if (return_ptr.value == nullptr) {
lbAddr r = lb_add_local_generated(p, rt, true);
return_ptr = r.addr;
}
GB_ASSERT(is_type_pointer(return_ptr.type));
lbValue return_ptr = lb_add_local_generated(p, rt, true).addr;
lb_emit_call_internal(p, value, return_ptr, processed_args, nullptr, context_ptr, inlining);
result = lb_emit_load(p, return_ptr);
} else if (rt != nullptr) {
@@ -1010,6 +1089,47 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
lb_emit_call_internal(p, value, {}, processed_args, nullptr, context_ptr, inlining);
}
if (original_rt != rt) {
GB_ASSERT(split_returns);
GB_ASSERT(is_type_tuple(original_rt));
// IMPORTANT NOTE(bill, 2022-11-24)
// result_ptr is a dummy value which is only used to reference a tuple
// value for the "tuple-fix"
//
// The reason for the fake stack allocation is to have a unique pointer
// for the value to be used as a key within the procedure itself
lbValue result_ptr = lb_add_local_generated(p, original_rt, false).addr;
isize ret_count = original_rt->Tuple.variables.count;
auto tuple_fix_values = slice_make<lbValue>(permanent_allocator(), ret_count);
auto tuple_geps = slice_make<lbValue>(permanent_allocator(), ret_count);
isize offset = ft->original_arg_count;
for (isize j = 0; j < ret_count-1; j++) {
lbValue ret_arg_ptr = processed_args[offset + j];
lbValue ret_arg = lb_emit_load(p, ret_arg_ptr);
tuple_fix_values[j] = ret_arg;
}
tuple_fix_values[ret_count-1] = result;
#if 0
for (isize j = 0; j < ret_count; j++) {
tuple_geps[j] = lb_emit_struct_ep(p, result_ptr, cast(i32)j);
}
for (isize j = 0; j < ret_count; j++) {
lb_emit_store(p, tuple_geps[j], tuple_fix_values[j]);
}
#endif
result = lb_emit_load(p, result_ptr);
lbTupleFix tf = {tuple_fix_values};
map_set(&p->tuple_fix_map, result_ptr.value, tf);
map_set(&p->tuple_fix_map, result.value, tf);
}
}
Entity **found = map_get(&p->module->procedure_values, value.value);
@@ -1049,15 +1169,7 @@ lbValue lb_emit_call(lbProcedure *p, lbValue value, Array<lbValue> const &args,
return result;
}
LLVMValueRef llvm_splat_float(i64 count, LLVMTypeRef type, f64 value) {
LLVMValueRef v = LLVMConstReal(type, value);
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
for (i64 i = 0; i < count; i++) {
values[i] = v;
}
return LLVMConstVector(values, cast(unsigned)count);
}
LLVMValueRef llvm_splat_int(i64 count, LLVMTypeRef type, i64 value, bool is_signed=false) {
gb_internal LLVMValueRef llvm_splat_int(i64 count, LLVMTypeRef type, i64 value, bool is_signed=false) {
LLVMValueRef v = LLVMConstInt(type, value, is_signed);
LLVMValueRef *values = gb_alloc_array(temporary_allocator(), LLVMValueRef, count);
for (i64 i = 0; i < count; i++) {
@@ -1067,7 +1179,7 @@ LLVMValueRef llvm_splat_int(i64 count, LLVMTypeRef type, i64 value, bool is_sign
}
lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId builtin_id) {
gb_internal lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId builtin_id) {
ast_node(ce, CallExpr, expr);
lbModule *m = p->module;
@@ -1483,7 +1595,7 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
}
lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId id) {
gb_internal lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv, BuiltinProcId id) {
ast_node(ce, CallExpr, expr);
if (BuiltinProc__simd_begin < id && id < BuiltinProc__simd_end) {
@@ -2300,7 +2412,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
);
LLVMSetWeak(value, weak);
if (tv.type->kind == Type_Tuple) {
if (is_type_tuple(tv.type)) {
Type *fix_typed = alloc_type_tuple();
slice_init(&fix_typed->Tuple.variables, permanent_allocator(), 2);
fix_typed->Tuple.variables[0] = tv.type->Tuple.variables[0];
@@ -2834,8 +2946,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
LLVMValueRef the_asm = llvm_get_inline_asm(
func_type,
str_lit("rolq $3, %rdi; rolq $13, %rdi\n rolq $61, %rdi; rolq $51, %rdi\n xchgq %rbx, %rbx"),
str_lit("={rdx},{rdx},{rax},cc,memory"),
str_lit("rolq $$3, %rdi; rolq $$13, %rdi\n rolq $$61, %rdi; rolq $$51, %rdi\n xchgq %rbx, %rbx"),
str_lit("={rdx},{rdx},{rax},~{cc},~{memory}"),
true
);
@@ -2863,7 +2975,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
}
lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TokenPos const &pos) {
gb_internal lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterValue const &param_value, TokenPos const &pos) {
switch (param_value.kind) {
case ParameterValue_Constant:
if (is_type_constant_type(parameter_type)) {
@@ -2898,9 +3010,9 @@ lbValue lb_handle_param_value(lbProcedure *p, Type *parameter_type, ParameterVal
}
lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr);
gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr);
lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
expr = unparen_expr(expr);
ast_node(ce, CallExpr, expr);
@@ -2913,7 +3025,7 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
}
return res;
}
lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
lbModule *m = p->module;
TypeAndValue tv = type_and_value_of_expr(expr);
@@ -3015,6 +3127,8 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
GB_ASSERT(e->kind == Entity_Variable);
if (args[i].value == nullptr) {
args[i] = lb_handle_param_value(p, e->type, e->Variable.param_value, ast_token(expr).pos);
} else if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) {
args[i] = lb_typeid(p->module, args[i].type);
} else {
args[i] = lb_emit_conv(p, args[i], e->type);
}
@@ -3032,7 +3146,7 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
}
}
return lb_emit_call(p, value, args, ce->inlining, p->copy_elision_hint.ast == expr);
return lb_emit_call(p, value, args, ce->inlining);
}
isize arg_index = 0;
@@ -3044,7 +3158,7 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
GB_ASSERT_MSG(tav.mode != Addressing_Invalid, "%s %s %d", expr_to_string(arg), expr_to_string(expr), tav.mode);
GB_ASSERT_MSG(tav.mode != Addressing_ProcGroup, "%s", expr_to_string(arg));
Type *at = tav.type;
if (at->kind == Type_Tuple) {
if (is_type_tuple(at)) {
arg_count += at->Tuple.variables.count;
} else {
arg_count++;
@@ -3084,9 +3198,16 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
lbValue a = lb_build_expr(p, arg);
Type *at = a.type;
if (at->kind == Type_Tuple) {
for_array(i, at->Tuple.variables) {
lbValue v = lb_emit_struct_ev(p, a, cast(i32)i);
args[arg_index++] = v;
lbTupleFix *tf = map_get(&p->tuple_fix_map, a.value);
if (tf) {
for_array(j, tf->values) {
args[arg_index++] = tf->values[j];
}
} else {
for_array(j, at->Tuple.variables) {
lbValue v = lb_emit_struct_ev(p, a, cast(i32)j);
args[arg_index++] = v;
}
}
} else {
args[arg_index++] = a;
@@ -3157,7 +3278,12 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
continue;
}
GB_ASSERT_MSG(args[i].value != nullptr, "%.*s", LIT(e->token.string));
args[i] = lb_emit_conv(p, args[i], e->type);
if (is_type_typeid(e->type) && !is_type_typeid(args[i].type)) {
GB_ASSERT(LLVMIsNull(args[i].value));
args[i] = lb_typeid(p->module, args[i].type);
} else {
args[i] = lb_emit_conv(p, args[i], e->type);
}
}
}
}
@@ -3213,6 +3339,6 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
}
auto call_args = array_slice(args, 0, final_count);
return lb_emit_call(p, value, call_args, ce->inlining, p->copy_elision_hint.ast == expr);
return lb_emit_call(p, value, call_args, ce->inlining);
}
+180 -185
View File
@@ -1,32 +1,4 @@
lbCopyElisionHint lb_set_copy_elision_hint(lbProcedure *p, lbAddr const &addr, Ast *ast) {
lbCopyElisionHint prev = p->copy_elision_hint;
p->copy_elision_hint.used = false;
p->copy_elision_hint.ptr = {};
p->copy_elision_hint.ast = nullptr;
#if 0
if (addr.kind == lbAddr_Default && addr.addr.value != nullptr) {
p->copy_elision_hint.ptr = lb_addr_get_ptr(p, addr);
p->copy_elision_hint.ast = unparen_expr(ast);
}
#endif
return prev;
}
void lb_reset_copy_elision_hint(lbProcedure *p, lbCopyElisionHint prev_hint) {
p->copy_elision_hint = prev_hint;
}
lbValue lb_consume_copy_elision_hint(lbProcedure *p) {
lbValue return_ptr = p->copy_elision_hint.ptr;
p->copy_elision_hint.used = true;
p->copy_elision_hint.ptr = {};
p->copy_elision_hint.ast = nullptr;
return return_ptr;
}
void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
gb_internal void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
if (vd == nullptr || vd->is_mutable) {
return;
}
@@ -35,8 +7,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
static i32 global_guid = 0;
for_array(i, vd->names) {
Ast *ident = vd->names[i];
for (Ast *ident : vd->names) {
GB_ASSERT(ident->kind == Ast_Ident);
Entity *e = entity_of_node(ident);
GB_ASSERT(e != nullptr);
@@ -61,7 +32,7 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
continue;
}
lb_set_nested_type_name_ir_mangled_name(e, p);
lb_set_nested_type_name_ir_mangled_name(e, p, p->module);
}
for_array(i, vd->names) {
@@ -79,21 +50,20 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
continue; // It's an alias
}
CheckerInfo *info = p->module->info;
DeclInfo *decl = decl_info_of_entity(e);
ast_node(pl, ProcLit, decl->proc_lit);
if (pl->body != nullptr) {
auto *found = map_get(&info->gen_procs, ident);
if (found) {
auto procs = *found;
for_array(i, procs) {
Entity *e = procs[i];
GenProcsData *gpd = e->Procedure.gen_procs;
if (gpd) {
rw_mutex_shared_lock(&gpd->mutex);
for (Entity *e : gpd->procs) {
if (!ptr_set_exists(min_dep_set, e)) {
continue;
}
DeclInfo *d = decl_info_of_entity(e);
lb_build_nested_proc(p, &d->proc_lit->ProcLit, e);
}
rw_mutex_shared_unlock(&gpd->mutex);
} else {
lb_build_nested_proc(p, pl, e);
}
@@ -133,9 +103,8 @@ void lb_build_constant_value_decl(lbProcedure *p, AstValueDecl *vd) {
}
void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) {
for_array(i, stmts) {
Ast *stmt = stmts[i];
gb_internal void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) {
for (Ast *stmt : stmts) {
switch (stmt->kind) {
case_ast_node(vd, ValueDecl, stmt);
lb_build_constant_value_decl(p, vd);
@@ -146,21 +115,20 @@ void lb_build_stmt_list(lbProcedure *p, Slice<Ast *> const &stmts) {
case_end;
}
}
for_array(i, stmts) {
lb_build_stmt(p, stmts[i]);
for (Ast *stmt : stmts) {
lb_build_stmt(p, stmt);
}
}
lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) {
gb_internal lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) {
GB_ASSERT(ident->kind == Ast_Ident);
Entity *e = entity_of_node(ident);
GB_ASSERT(e->kind == Entity_Label);
for_array(i, p->branch_blocks) {
lbBranchBlocks *b = &p->branch_blocks[i];
if (b->label == e->Label.node) {
return *b;
for (lbBranchBlocks const &b : p->branch_blocks) {
if (b.label == e->Label.node) {
return b;
}
}
@@ -170,7 +138,7 @@ lbBranchBlocks lb_lookup_branch_blocks(lbProcedure *p, Ast *ident) {
}
lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) {
gb_internal lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, lbBlock *continue_, lbBlock *fallthrough_) {
lbTargetList *tl = gb_alloc_item(permanent_allocator(), lbTargetList);
tl->prev = p->target_list;
tl->break_ = break_;
@@ -181,13 +149,12 @@ lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, l
if (label != nullptr) { // Set label blocks
GB_ASSERT(label->kind == Ast_Label);
for_array(i, p->branch_blocks) {
lbBranchBlocks *b = &p->branch_blocks[i];
GB_ASSERT(b->label != nullptr && label != nullptr);
GB_ASSERT(b->label->kind == Ast_Label);
if (b->label == label) {
b->break_ = break_;
b->continue_ = continue_;
for (lbBranchBlocks &b : p->branch_blocks) {
GB_ASSERT(b.label != nullptr && label != nullptr);
GB_ASSERT(b.label->kind == Ast_Label);
if (b.label == label) {
b.break_ = break_;
b.continue_ = continue_;
return tl;
}
}
@@ -198,11 +165,11 @@ lbTargetList *lb_push_target_list(lbProcedure *p, Ast *label, lbBlock *break_, l
return tl;
}
void lb_pop_target_list(lbProcedure *p) {
gb_internal void lb_pop_target_list(lbProcedure *p) {
p->target_list = p->target_list->prev;
}
void lb_open_scope(lbProcedure *p, Scope *s) {
gb_internal void lb_open_scope(lbProcedure *p, Scope *s) {
lbModule *m = p->module;
if (m->debug_builder) {
LLVMMetadataRef curr_metadata = lb_get_llvm_metadata(m, s);
@@ -239,7 +206,7 @@ void lb_open_scope(lbProcedure *p, Scope *s) {
}
void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) {
gb_internal void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool pop_stack=true) {
lb_emit_defer_stmts(p, kind, block);
GB_ASSERT(p->scope_index > 0);
@@ -258,7 +225,7 @@ void lb_close_scope(lbProcedure *p, lbDeferExitKind kind, lbBlock *block, bool p
array_pop(&p->scope_stack);
}
void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
gb_internal void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
TypeAndValue tv = type_and_value_of_expr(ws->cond);
GB_ASSERT(is_type_boolean(tv.type));
GB_ASSERT(tv.value.kind == ExactValue_Bool);
@@ -281,8 +248,8 @@ void lb_build_when_stmt(lbProcedure *p, AstWhenStmt *ws) {
void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
gb_internal void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValue count_ptr,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
lbModule *m = p->module;
lbValue count = {};
@@ -370,7 +337,7 @@ void lb_build_range_indexed(lbProcedure *p, lbValue expr, Type *val_type, lbValu
if (done_) *done_ = done;
}
lbValue lb_map_cell_index_static(lbProcedure *p, Type *type, lbValue cells_ptr, lbValue index) {
gb_internal lbValue lb_map_cell_index_static(lbProcedure *p, Type *type, lbValue cells_ptr, lbValue index) {
i64 size, len;
i64 elem_sz = type_size_of(type);
map_cell_size_and_len(type, &size, &len);
@@ -406,17 +373,7 @@ lbValue lb_map_cell_index_static(lbProcedure *p, Type *type, lbValue cells_ptr,
return lb_emit_ptr_offset(p, elems_ptr, data_index);
}
void lb_map_kvh_data_static(lbProcedure *p, lbValue map_value, lbValue *ks_, lbValue *vs_, lbValue *hs_) {
lbValue capacity = lb_map_cap(p, map_value);
lbValue ks = lb_map_data_uintptr(p, map_value);
lbValue vs = {};
lbValue hs = {};
if (ks_) *ks_ = ks;
if (vs_) *vs_ = vs;
if (hs_) *hs_ = hs;
}
lbValue lb_map_hash_is_valid(lbProcedure *p, lbValue hash) {
gb_internal lbValue lb_map_hash_is_valid(lbProcedure *p, lbValue hash) {
// N :: size_of(uintptr)*8 - 1
// (hash != 0) & (hash>>N == 0)
@@ -432,8 +389,8 @@ lbValue lb_map_hash_is_valid(lbProcedure *p, lbValue hash) {
return lb_emit_arith(p, Token_And, not_deleted, not_empty, t_uintptr);
}
void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type,
lbValue *val_, lbValue *key_, lbBlock **loop_, lbBlock **done_) {
gb_internal void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type,
lbValue *val_, lbValue *key_, lbBlock **loop_, lbBlock **done_) {
lbModule *m = p->module;
Type *type = base_type(type_deref(expr.type));
@@ -494,8 +451,8 @@ void lb_build_range_map(lbProcedure *p, lbValue expr, Type *val_type,
void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
gb_internal void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
lbModule *m = p->module;
lbValue count = lb_const_int(m, t_int, 0);
Type *expr_type = base_type(expr.type);
@@ -554,8 +511,8 @@ void lb_build_range_string(lbProcedure *p, lbValue expr, Type *val_type,
}
void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
AstRangeStmt *rs, Scope *scope) {
gb_internal void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
AstRangeStmt *rs, Scope *scope) {
bool ADD_EXTRA_WRAPPING_CHECK = true;
lbModule *m = p->module;
@@ -658,7 +615,7 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
lb_start_block(p, done);
}
void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
gb_internal void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValue *val_, lbValue *idx_, lbBlock **loop_, lbBlock **done_) {
lbModule *m = p->module;
Type *t = enum_type;
@@ -711,8 +668,8 @@ void lb_build_range_enum(lbProcedure *p, Type *enum_type, Type *val_type, lbValu
if (done_) *done_ = done;
}
void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type,
lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) {
gb_internal void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1_type,
lbValue *val0_, lbValue *val1_, lbBlock **loop_, lbBlock **done_) {
lbBlock *loop = lb_create_block(p, "for.tuple.loop");
lb_emit_jump(p, loop);
lb_start_block(p, loop);
@@ -726,18 +683,18 @@ void lb_build_range_tuple(lbProcedure *p, Ast *expr, Type *val0_type, Type *val1
i32 tuple_count = cast(i32)tuple->Tuple.variables.count;
i32 cond_index = tuple_count-1;
lbValue cond = lb_emit_struct_ev(p, tuple_value, cond_index);
lbValue cond = lb_emit_tuple_ev(p, tuple_value, cond_index);
lb_emit_if(p, cond, body, done);
lb_start_block(p, body);
if (val0_) *val0_ = lb_emit_struct_ev(p, tuple_value, 0);
if (val1_) *val1_ = lb_emit_struct_ev(p, tuple_value, 1);
if (val0_) *val0_ = lb_emit_tuple_ev(p, tuple_value, 0);
if (val1_) *val1_ = lb_emit_tuple_ev(p, tuple_value, 1);
if (loop_) *loop_ = loop;
if (done_) *done_ = done;
}
void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
gb_internal void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
Ast *expr = unparen_expr(rs->expr);
TypeAndValue tav = type_and_value_of_expr(expr);
@@ -806,7 +763,7 @@ void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *sco
}
void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
gb_internal void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
Ast *expr = unparen_expr(rs->expr);
if (is_ast_range(expr)) {
@@ -951,7 +908,7 @@ void lb_build_range_stmt(lbProcedure *p, AstRangeStmt *rs, Scope *scope) {
lb_start_block(p, done);
}
void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *scope) {
gb_internal void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *scope) {
lbModule *m = p->module;
lb_open_scope(p, scope); // Open scope here
@@ -1117,7 +1074,7 @@ void lb_build_unroll_range_stmt(lbProcedure *p, AstUnrollRangeStmt *rs, Scope *s
lb_close_scope(p, lbDeferExit_Default, nullptr);
}
bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) {
gb_internal bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_found_) {
if (ss->tag == nullptr) {
return false;
}
@@ -1133,8 +1090,7 @@ bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_f
}
ast_node(body, BlockStmt, ss->body);
for_array(i, body->stmts) {
Ast *clause = body->stmts[i];
for (Ast *clause : body->stmts) {
ast_node(cc, CaseClause, clause);
if (cc->list.count == 0) {
@@ -1142,8 +1098,8 @@ bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_f
continue;
}
for_array(j, cc->list) {
Ast *expr = unparen_expr(cc->list[j]);
for (Ast *expr : cc->list) {
expr = unparen_expr(expr);
if (is_ast_range(expr)) {
return false;
}
@@ -1166,7 +1122,7 @@ bool lb_switch_stmt_can_be_trivial_jump_table(AstSwitchStmt *ss, bool *default_f
}
void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
gb_internal void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
lb_open_scope(p, scope);
if (ss->init != nullptr) {
@@ -1204,8 +1160,7 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
LLVMValueRef switch_instr = nullptr;
if (is_trivial) {
isize num_cases = 0;
for_array(i, body->stmts) {
Ast *clause = body->stmts[i];
for (Ast *clause : body->stmts) {
ast_node(cc, CaseClause, clause);
num_cases += cc->list.count;
}
@@ -1242,8 +1197,8 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
}
lbBlock *next_cond = nullptr;
for_array(j, cc->list) {
Ast *expr = unparen_expr(cc->list[j]);
for (Ast *expr : cc->list) {
expr = unparen_expr(expr);
if (switch_instr != nullptr) {
lbValue on_val = {};
@@ -1328,7 +1283,7 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
lb_close_scope(p, lbDeferExit_Default, done);
}
void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) {
gb_internal void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) {
Entity *e = implicit_entity_of_node(clause);
GB_ASSERT(e != nullptr);
if (e->flags & EntityFlag_Value) {
@@ -1343,7 +1298,7 @@ void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) {
}
}
lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value) {
gb_internal lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value) {
Entity *e = entity_of_node(stmt_val);
if (e == nullptr) {
return {};
@@ -1363,7 +1318,7 @@ lbAddr lb_store_range_stmt_val(lbProcedure *p, Ast *stmt_val, lbValue value) {
return addr;
}
void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) {
gb_internal void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, lbBlock *done) {
ast_node(cc, CaseClause, clause);
lb_push_target_list(p, label, done, nullptr, nullptr);
@@ -1374,7 +1329,7 @@ void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, l
lb_emit_jump(p, done);
}
void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
gb_internal void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
lbModule *m = p->module;
lb_open_scope(p, ss->scope);
@@ -1422,8 +1377,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
lbBlock *default_block = nullptr;
isize num_cases = 0;
for_array(i, body->stmts) {
Ast *clause = body->stmts[i];
for (Ast *clause : body->stmts) {
ast_node(cc, CaseClause, clause);
num_cases += cc->list.count;
if (cc->list.count == 0) {
@@ -1443,8 +1397,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
switch_instr = LLVMBuildSwitch(p->builder, tag.value, else_block->block, cast(unsigned)num_cases);
}
for_array(i, body->stmts) {
Ast *clause = body->stmts[i];
for (Ast *clause : body->stmts) {
ast_node(cc, CaseClause, clause);
lb_open_scope(p, cc->scope);
if (cc->list.count == 0) {
@@ -1458,9 +1411,8 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
if (p->debug_info != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, clause));
}
Type *case_type = nullptr;
for_array(type_index, cc->list) {
case_type = type_of_expr(cc->list[type_index]);
for (Ast *type_expr : cc->list) {
Type *case_type = type_of_expr(type_expr);
lbValue on_val = {};
if (switch_kind == TypeSwitch_Union) {
Type *ut = base_type(type_deref(parent.type));
@@ -1508,7 +1460,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
}
void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
gb_internal void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
for_array(i, vd->names) {
lbValue value = {};
if (vd->values.count > 0) {
@@ -1571,35 +1523,48 @@ void lb_build_static_variables(lbProcedure *p, AstValueDecl *vd) {
lb_add_member(p->module, mangled_name, global_val);
}
}
gb_internal void lb_append_tuple_values(lbProcedure *p, Array<lbValue> *dst_values, lbValue src_value) {
Type *t = src_value.type;
if (t->kind == Type_Tuple) {
lbTupleFix *tf = map_get(&p->tuple_fix_map, src_value.value);
if (tf) {
for (lbValue const &value : tf->values) {
array_add(dst_values, value);
}
} else {
for_array(i, t->Tuple.variables) {
lbValue v = lb_emit_tuple_ev(p, src_value, cast(i32)i);
array_add(dst_values, v);
}
}
} else {
array_add(dst_values, src_value);
}
}
void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> const &values) {
gb_internal void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> const &values) {
if (values.count == 0) {
return;
}
auto inits = array_make<lbValue>(permanent_allocator(), 0, lvals.count);
for_array(i, values) {
Ast *rhs = values[i];
if (is_type_tuple(type_of_expr(rhs))) {
lbValue init = lb_build_expr(p, rhs);
Type *t = init.type;
GB_ASSERT(t->kind == Type_Tuple);
for_array(i, t->Tuple.variables) {
lbValue v = lb_emit_struct_ev(p, init, cast(i32)i);
array_add(&inits, v);
}
} else {
auto prev_hint = lb_set_copy_elision_hint(p, lvals[inits.count], rhs);
lbValue init = lb_build_expr(p, rhs);
if (p->copy_elision_hint.used) {
lvals[inits.count] = {}; // zero lval
}
lb_reset_copy_elision_hint(p, prev_hint);
array_add(&inits, init);
for (Ast *rhs : values) {
lbValue init = lb_build_expr(p, rhs);
lb_append_tuple_values(p, &inits, init);
}
bool prev_in_assignment = p->in_multi_assignment;
isize lval_count = 0;
for (lbAddr const &lval : lvals) {
if (lval.addr.value != nullptr) {
// check if it is not a blank identifier
lval_count += 1;
}
}
p->in_multi_assignment = lval_count > 1;
GB_ASSERT(lvals.count == inits.count);
for_array(i, inits) {
@@ -1607,11 +1572,18 @@ void lb_build_assignment(lbProcedure *p, Array<lbAddr> &lvals, Slice<Ast *> cons
lbValue init = inits[i];
lb_addr_store(p, lval, init);
}
p->in_multi_assignment = prev_in_assignment;
}
void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) {
lbFunctionType *ft = lb_get_function_type(p->module, p, p->type);
gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res) {
lbFunctionType *ft = lb_get_function_type(p->module, p->type);
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
bool split_returns = ft->multiple_return_original_type != nullptr;
if (split_returns) {
GB_ASSERT(res.value == nullptr || !is_type_tuple(res.type));
}
if (return_by_pointer) {
if (res.value != nullptr) {
@@ -1641,7 +1613,7 @@ void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res) {
LLVMBuildRet(p->builder, ret_val);
}
}
void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
lb_ensure_abi_function_type(p->module, p);
lbValue res = {};
@@ -1650,7 +1622,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
isize return_count = p->type->Proc.result_count;
isize res_count = return_results.count;
lbFunctionType *ft = lb_get_function_type(p->module, p, p->type);
lbFunctionType *ft = lb_get_function_type(p->module, p->type);
bool return_by_pointer = ft->ret.kind == lbArg_Indirect;
if (return_count == 0) {
@@ -1683,15 +1655,7 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
if (res_count != 0) {
for (isize res_index = 0; res_index < res_count; res_index++) {
lbValue res = lb_build_expr(p, return_results[res_index]);
Type *t = res.type;
if (t->kind == Type_Tuple) {
for_array(i, t->Tuple.variables) {
lbValue v = lb_emit_struct_ev(p, res, cast(i32)i);
array_add(&results, v);
}
} else {
array_add(&results, res);
}
lb_append_tuple_values(p, &results, res);
}
} else {
for (isize res_index = 0; res_index < return_count; res_index++) {
@@ -1727,40 +1691,73 @@ void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results) {
}
}
Type *ret_type = p->type->Proc.results;
bool split_returns = ft->multiple_return_original_type != nullptr;
if (split_returns) {
auto result_values = slice_make<lbValue>(temporary_allocator(), results.count);
auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count-1);
for_array(i, results) {
result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type);
}
isize param_offset = return_by_pointer ? 1 : 0;
param_offset += ft->original_arg_count;
for_array(i, result_eps) {
lbValue result_ep = {};
result_ep.value = LLVMGetParam(p->value, cast(unsigned)(param_offset+i));
result_ep.type = alloc_type_pointer(tuple->variables[i]->type);
result_eps[i] = result_ep;
}
for_array(i, result_eps) {
lb_emit_store(p, result_eps[i], result_values[i]);
}
if (return_by_pointer) {
GB_ASSERT(result_values.count-1 == result_eps.count);
lb_addr_store(p, p->return_ptr, result_values[result_values.count-1]);
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
LLVMBuildRetVoid(p->builder);
return;
} else {
return lb_build_return_stmt_internal(p, result_values[result_values.count-1]);
}
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
if (return_by_pointer) {
res = p->return_ptr.addr;
} else {
res = lb_add_local_generated(p, ret_type, false).addr;
}
Type *ret_type = p->type->Proc.results;
auto result_values = slice_make<lbValue>(temporary_allocator(), results.count);
auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count);
// NOTE(bill): Doesn't need to be zero because it will be initialized in the loops
if (return_by_pointer) {
res = p->return_ptr.addr;
} else {
res = lb_add_local_generated(p, ret_type, false).addr;
}
for_array(i, results) {
result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type);
}
for_array(i, results) {
result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i);
}
for_array(i, result_values) {
lb_emit_store(p, result_eps[i], result_values[i]);
}
auto result_values = slice_make<lbValue>(temporary_allocator(), results.count);
auto result_eps = slice_make<lbValue>(temporary_allocator(), results.count);
if (return_by_pointer) {
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
LLVMBuildRetVoid(p->builder);
return;
}
for_array(i, results) {
result_values[i] = lb_emit_conv(p, results[i], tuple->variables[i]->type);
}
for_array(i, results) {
result_eps[i] = lb_emit_struct_ep(p, res, cast(i32)i);
}
for_array(i, result_eps) {
lb_emit_store(p, result_eps[i], result_values[i]);
}
res = lb_emit_load(p, res);
if (return_by_pointer) {
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
LLVMBuildRetVoid(p->builder);
return;
}
res = lb_emit_load(p, res);
}
}
lb_build_return_stmt_internal(p, res);
}
void lb_build_if_stmt(lbProcedure *p, Ast *node) {
gb_internal void lb_build_if_stmt(lbProcedure *p, Ast *node) {
ast_node(is, IfStmt, node);
lb_open_scope(p, is->scope); // Scope #1
defer (lb_close_scope(p, lbDeferExit_Default, nullptr));
@@ -1847,7 +1844,7 @@ void lb_build_if_stmt(lbProcedure *p, Ast *node) {
lb_start_block(p, done);
}
void lb_build_for_stmt(lbProcedure *p, Ast *node) {
gb_internal void lb_build_for_stmt(lbProcedure *p, Ast *node) {
ast_node(fs, ForStmt, node);
lb_open_scope(p, fs->scope); // Open Scope here
@@ -1907,7 +1904,7 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
lb_close_scope(p, lbDeferExit_Default, nullptr);
}
void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
gb_internal void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
GB_ASSERT(op != Token_Eq);
Type *lhs_type = lb_addr_type(lhs);
@@ -1976,8 +1973,7 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs,
auto indices_handled = slice_make<bool>(temporary_allocator(), bt->Array.count);
auto indices = slice_make<i32>(temporary_allocator(), bt->Array.count);
i32 index_count = 0;
for_array(i, lhs.swizzle_large.indices) {
i32 index = lhs.swizzle_large.indices[i];
for (i32 index : lhs.swizzle_large.indices) {
if (indices_handled[index]) {
continue;
}
@@ -2050,12 +2046,11 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs,
lb_loop_end(p, loop_data);
}
}
void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
gb_internal void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
if (as->op.kind == Token_Eq) {
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, as->lhs.count);
for_array(i, as->lhs) {
Ast *lhs = as->lhs[i];
for (Ast *lhs : as->lhs) {
lbAddr lval = {};
if (!is_blank_ident(lhs)) {
lval = lb_build_addr(p, lhs);
@@ -2065,6 +2060,7 @@ void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
lb_build_assignment(p, lvals, as->rhs);
return;
}
GB_ASSERT(as->lhs.count == 1);
GB_ASSERT(as->rhs.count == 1);
// NOTE(bill): Only 1 += 1 is allowed, no tuples
@@ -2108,7 +2104,7 @@ void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
}
void lb_build_stmt(lbProcedure *p, Ast *node) {
gb_internal void lb_build_stmt(lbProcedure *p, Ast *node) {
Ast *prev_stmt = p->curr_stmt;
defer (p->curr_stmt = prev_stmt);
p->curr_stmt = node;
@@ -2190,12 +2186,12 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
bool is_static = false;
if (vd->names.count > 0) {
for_array(i, vd->names) {
Ast *name = vd->names[i];
for (Ast *name : vd->names) {
if (!is_blank_ident(name)) {
GB_ASSERT(name->kind == Ast_Ident);
Entity *e = entity_of_node(name);
TokenPos pos = ast_token(name).pos;
GB_ASSERT_MSG(e != nullptr, "%s", token_pos_to_string(pos));
GB_ASSERT_MSG(e != nullptr, "\n%s missing entity for %.*s", token_pos_to_string(pos), LIT(name->Ident.token.string));
if (e->flags & EntityFlag_Static) {
// NOTE(bill): If one of the entities is static, they all are
is_static = true;
@@ -2212,8 +2208,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
auto lvals = array_make<lbAddr>(permanent_allocator(), 0, vd->names.count);
for_array(i, vd->names) {
Ast *name = vd->names[i];
for (Ast *name : vd->names) {
lbAddr lval = {};
if (!is_blank_ident(name)) {
Entity *e = entity_of_node(name);
@@ -2303,7 +2298,7 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) {
gb_internal void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) {
if (p->curr_block == nullptr) {
return;
}
@@ -2332,7 +2327,7 @@ void lb_build_defer_stmt(lbProcedure *p, lbDefer const &d) {
}
}
void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
gb_internal void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
isize count = p->defer_stmts.count;
isize i = count;
while (i --> 0) {
@@ -2340,7 +2335,7 @@ void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
if (kind == lbDeferExit_Default) {
if (p->scope_index == d.scope_index &&
d.scope_index > 0) { // TODO(bill): Which is correct: > 0 or > 1?
d.scope_index > 0) {
lb_build_defer_stmt(p, d);
array_pop(&p->defer_stmts);
continue;
@@ -2359,7 +2354,7 @@ void lb_emit_defer_stmts(lbProcedure *p, lbDeferExitKind kind, lbBlock *block) {
}
}
void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
gb_internal void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
Type *pt = base_type(p->type);
GB_ASSERT(pt->kind == Type_Proc);
if (pt->Proc.calling_convention == ProcCC_Odin) {
@@ -2374,7 +2369,7 @@ void lb_add_defer_node(lbProcedure *p, isize scope_index, Ast *stmt) {
d->stmt = stmt;
}
void lb_add_defer_proc(lbProcedure *p, isize scope_index, lbValue deferred, Array<lbValue> const &result_as_args) {
gb_internal void lb_add_defer_proc(lbProcedure *p, isize scope_index, lbValue deferred, Array<lbValue> const &result_as_args) {
Type *pt = base_type(p->type);
GB_ASSERT(pt->kind == Type_Proc);
if (pt->Proc.calling_convention == ProcCC_Odin) {
+15 -14
View File
@@ -1,10 +1,11 @@
isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
gb_internal isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=true) {
auto *set = &info->minimum_dependency_type_info_set;
isize index = type_info_index(info, type, err_on_not_found);
if (index >= 0) {
isize i = ptr_entry_index(set, index);
if (i >= 0) {
return i+1;
auto *found = map_get(set, index);
if (found) {
GB_ASSERT(*found >= 0);
return *found + 1;
}
}
if (err_on_not_found) {
@@ -13,7 +14,7 @@ isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=tr
return -1;
}
lbValue lb_typeid(lbModule *m, Type *type) {
gb_internal lbValue lb_typeid(lbModule *m, Type *type) {
GB_ASSERT(!build_context.disallow_rtti);
type = default_type(type);
@@ -90,7 +91,7 @@ lbValue lb_typeid(lbModule *m, Type *type) {
return res;
}
lbValue lb_type_info(lbModule *m, Type *type) {
gb_internal lbValue lb_type_info(lbModule *m, Type *type) {
GB_ASSERT(!build_context.disallow_rtti);
type = default_type(type);
@@ -102,36 +103,36 @@ lbValue lb_type_info(lbModule *m, Type *type) {
return lb_emit_array_epi(m, data, index);
}
LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) {
gb_internal LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) {
return lb_type_internal_for_procedures_raw(m, type);
}
lbValue lb_type_info_member_types_offset(lbProcedure *p, isize count) {
gb_internal lbValue lb_type_info_member_types_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_types.addr, lb_global_type_info_member_types_index);
lb_global_type_info_member_types_index += cast(i32)count;
return offset;
}
lbValue lb_type_info_member_names_offset(lbProcedure *p, isize count) {
gb_internal lbValue lb_type_info_member_names_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_names.addr, lb_global_type_info_member_names_index);
lb_global_type_info_member_names_index += cast(i32)count;
return offset;
}
lbValue lb_type_info_member_offsets_offset(lbProcedure *p, isize count) {
gb_internal lbValue lb_type_info_member_offsets_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_offsets.addr, lb_global_type_info_member_offsets_index);
lb_global_type_info_member_offsets_index += cast(i32)count;
return offset;
}
lbValue lb_type_info_member_usings_offset(lbProcedure *p, isize count) {
gb_internal lbValue lb_type_info_member_usings_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_usings.addr, lb_global_type_info_member_usings_index);
lb_global_type_info_member_usings_index += cast(i32)count;
return offset;
}
lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
gb_internal lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
GB_ASSERT(p->module == &p->module->gen->default_module);
lbValue offset = lb_emit_array_epi(p, lb_global_type_info_member_tags.addr, lb_global_type_info_member_tags_index);
lb_global_type_info_member_tags_index += cast(i32)count;
@@ -139,7 +140,7 @@ lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
}
void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
gb_internal void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
if (build_context.disallow_rtti) {
return;
}
@@ -185,7 +186,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
if (entry_index <= 0) {
continue;
}
if (entries_handled[entry_index]) {
continue;
}
+182 -142
View File
@@ -1,6 +1,6 @@
lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name);
gb_internal lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name);
bool lb_is_type_aggregate(Type *t) {
gb_internal bool lb_is_type_aggregate(Type *t) {
t = base_type(t);
switch (t->kind) {
case Type_Basic:
@@ -39,7 +39,7 @@ bool lb_is_type_aggregate(Type *t) {
return false;
}
void lb_emit_unreachable(lbProcedure *p) {
gb_internal void lb_emit_unreachable(lbProcedure *p) {
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
if (instr == nullptr || !lb_is_instr_terminating(instr)) {
lb_call_intrinsic(p, "llvm.trap", nullptr, 0, nullptr, 0);
@@ -47,7 +47,7 @@ void lb_emit_unreachable(lbProcedure *p) {
}
}
lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
gb_internal lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
Type *src = core_type(value.type);
GB_ASSERT(is_type_integer(src) || is_type_float(src));
if (is_type_different_to_arch_endianness(src)) {
@@ -57,7 +57,7 @@ lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
return value;
}
LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) {
gb_internal LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) {
bool is_inlinable = false;
i64 const_len = 0;
@@ -103,7 +103,7 @@ LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValu
}
void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment) {
gb_internal void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment) {
LLVMTypeRef llvm_type = lb_type(p->module, type);
LLVMTypeKind kind = LLVMGetTypeKind(llvm_type);
@@ -123,7 +123,7 @@ void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alig
}
}
lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y) {
gb_internal lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y) {
cond = lb_emit_conv(p, cond, t_llvm_bool);
lbValue res = {};
res.value = LLVMBuildSelect(p->builder, cond.value, x.value, y.value, "");
@@ -131,19 +131,19 @@ lbValue lb_emit_select(lbProcedure *p, lbValue cond, lbValue x, lbValue y) {
return res;
}
lbValue lb_emit_min(lbProcedure *p, Type *t, lbValue x, lbValue y) {
gb_internal lbValue lb_emit_min(lbProcedure *p, Type *t, lbValue x, lbValue y) {
x = lb_emit_conv(p, x, t);
y = lb_emit_conv(p, y, t);
return lb_emit_select(p, lb_emit_comp(p, Token_Lt, x, y), x, y);
}
lbValue lb_emit_max(lbProcedure *p, Type *t, lbValue x, lbValue y) {
gb_internal lbValue lb_emit_max(lbProcedure *p, Type *t, lbValue x, lbValue y) {
x = lb_emit_conv(p, x, t);
y = lb_emit_conv(p, y, t);
return lb_emit_select(p, lb_emit_comp(p, Token_Gt, x, y), x, y);
}
lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue max) {
gb_internal lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue max) {
lbValue z = {};
z = lb_emit_max(p, t, x, min);
z = lb_emit_min(p, t, z, max);
@@ -152,7 +152,7 @@ lbValue lb_emit_clamp(lbProcedure *p, Type *t, lbValue x, lbValue min, lbValue m
lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) {
gb_internal lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) {
if (false && lb_is_const(str_elem) && lb_is_const(str_len)) {
LLVMValueRef values[2] = {
str_elem.value,
@@ -171,7 +171,7 @@ lbValue lb_emit_string(lbProcedure *p, lbValue str_elem, lbValue str_len) {
}
lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
gb_internal lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
Type *src_type = value.type;
if (are_types_identical(t, src_type)) {
return value;
@@ -259,7 +259,7 @@ lbValue lb_emit_transmute(lbProcedure *p, lbValue value, Type *t) {
return res;
}
lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 alignment) {
gb_internal lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 alignment) {
i64 type_alignment = type_align_of(new_type);
if (alignment < type_alignment) {
alignment = type_alignment;
@@ -274,7 +274,7 @@ lbValue lb_copy_value_to_ptr(lbProcedure *p, lbValue val, Type *new_type, i64 al
}
lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
gb_internal lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
GB_ASSERT(ce->args.count > 0);
auto slices = slice_make<lbValue>(temporary_allocator(), ce->args.count);
@@ -305,7 +305,7 @@ lbValue lb_soa_zip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
return lb_addr_load(p, res);
}
lbValue lb_soa_unzip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
gb_internal lbValue lb_soa_unzip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
GB_ASSERT(ce->args.count == 1);
lbValue arg = lb_build_expr(p, ce->args[0]);
@@ -331,7 +331,7 @@ lbValue lb_soa_unzip(lbProcedure *p, AstCallExpr *ce, TypeAndValue const &tv) {
return lb_addr_load(p, res);
}
void lb_emit_try_lhs_rhs(lbProcedure *p, Ast *arg, TypeAndValue const &tv, lbValue *lhs_, lbValue *rhs_) {
gb_internal void lb_emit_try_lhs_rhs(lbProcedure *p, Ast *arg, TypeAndValue const &tv, lbValue *lhs_, lbValue *rhs_) {
lbValue lhs = {};
lbValue rhs = {};
@@ -339,16 +339,16 @@ void lb_emit_try_lhs_rhs(lbProcedure *p, Ast *arg, TypeAndValue const &tv, lbVal
if (is_type_tuple(value.type)) {
i32 n = cast(i32)(value.type->Tuple.variables.count-1);
if (value.type->Tuple.variables.count == 2) {
lhs = lb_emit_struct_ev(p, value, 0);
lhs = lb_emit_tuple_ev(p, value, 0);
} else {
lbAddr lhs_addr = lb_add_local_generated(p, tv.type, false);
lbValue lhs_ptr = lb_addr_get_ptr(p, lhs_addr);
for (i32 i = 0; i < n; i++) {
lb_emit_store(p, lb_emit_struct_ep(p, lhs_ptr, i), lb_emit_struct_ev(p, value, i));
lb_emit_store(p, lb_emit_struct_ep(p, lhs_ptr, i), lb_emit_tuple_ev(p, value, i));
}
lhs = lb_addr_load(p, lhs_addr);
}
rhs = lb_emit_struct_ev(p, value, n);
rhs = lb_emit_tuple_ev(p, value, n);
} else {
rhs = value;
}
@@ -360,7 +360,7 @@ void lb_emit_try_lhs_rhs(lbProcedure *p, Ast *arg, TypeAndValue const &tv, lbVal
}
lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) {
gb_internal lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) {
lbValue has_value = {};
if (is_type_boolean(rhs.type)) {
has_value = rhs;
@@ -373,7 +373,7 @@ lbValue lb_emit_try_has_value(lbProcedure *p, lbValue rhs) {
}
lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) {
gb_internal lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue const &tv) {
if (arg->state_flags & StateFlag_DirectiveWasFalse) {
return lb_build_expr(p, else_expr);
}
@@ -435,10 +435,10 @@ lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue c
}
}
void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
void lb_build_return_stmt_internal(lbProcedure *p, lbValue const &res);
gb_internal void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
gb_internal void lb_build_return_stmt_internal(lbProcedure *p, lbValue res);
lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
gb_internal lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
lbValue lhs = {};
lbValue rhs = {};
lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs);
@@ -479,7 +479,7 @@ lbValue lb_emit_or_return(lbProcedure *p, Ast *arg, TypeAndValue const &tv) {
}
void lb_emit_increment(lbProcedure *p, lbValue addr) {
gb_internal void lb_emit_increment(lbProcedure *p, lbValue addr) {
GB_ASSERT(is_type_pointer(addr.type));
Type *type = type_deref(addr.type);
lbValue v_one = lb_const_value(p->module, type, exact_value_i64(1));
@@ -487,7 +487,7 @@ void lb_emit_increment(lbProcedure *p, lbValue addr) {
}
lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
gb_internal lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
GB_ASSERT(type_size_of(value.type) == type_size_of(end_type));
if (type_size_of(value.type) < 2) {
@@ -526,7 +526,7 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
gb_internal lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
x = lb_emit_conv(p, x, type);
char const *name = "llvm.ctpop";
@@ -539,7 +539,7 @@ lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
return res;
}
lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type) {
gb_internal lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type) {
Type *elem = base_array_type(type);
i64 sz = 8*type_size_of(elem);
lbValue size = lb_const_int(p->module, elem, cast(u64)sz);
@@ -550,7 +550,7 @@ lbValue lb_emit_count_zeros(lbProcedure *p, lbValue x, Type *type) {
lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
gb_internal lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
x = lb_emit_conv(p, x, type);
char const *name = "llvm.cttz";
@@ -566,7 +566,7 @@ lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
return res;
}
lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) {
gb_internal lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) {
x = lb_emit_conv(p, x, type);
char const *name = "llvm.ctlz";
@@ -584,7 +584,7 @@ lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) {
lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {
gb_internal lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {
x = lb_emit_conv(p, x, type);
char const *name = "llvm.bitreverse";
@@ -599,15 +599,7 @@ lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {
}
lbValue lb_emit_bit_set_card(lbProcedure *p, lbValue x) {
GB_ASSERT(is_type_bit_set(x.type));
Type *underlying = bit_set_to_int(x.type);
lbValue card = lb_emit_count_ones(p, x, underlying);
return lb_emit_conv(p, card, t_int);
}
lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
gb_internal lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
GB_ASSERT(is_type_tuple(type));
lbModule *m = p->module;
@@ -654,7 +646,7 @@ lbValue lb_emit_union_cast_only_ok_check(lbProcedure *p, lbValue value, Type *ty
return lb_addr_load(p, v);
}
lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
gb_internal lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
lbModule *m = p->module;
Type *src_type = value.type;
@@ -753,7 +745,7 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p
return lb_addr_load(p, v);
}
lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
gb_internal lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
lbModule *m = p->module;
Type *src_type = value.type;
@@ -826,13 +818,13 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos
}
return v;
}
lbValue lb_emit_any_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
gb_internal lbValue lb_emit_any_cast(lbProcedure *p, lbValue value, Type *type, TokenPos pos) {
return lb_addr_load(p, lb_emit_any_cast_addr(p, value, type, pos));
}
lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) {
gb_internal lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) {
if (p->context_stack.count > 0) {
return p->context_stack[p->context_stack.count-1].ctx;
}
@@ -850,7 +842,7 @@ lbAddr lb_find_or_generate_context_ptr(lbProcedure *p) {
return c;
}
lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) {
gb_internal lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) {
if (LLVMIsALoadInst(value.value)) {
lbValue res = {};
res.value = LLVMGetOperand(value.value, 0);
@@ -864,7 +856,7 @@ lbValue lb_address_from_load_or_generate_local(lbProcedure *p, lbValue value) {
lb_addr_store(p, res, value);
return res.addr;
}
lbValue lb_address_from_load(lbProcedure *p, lbValue value) {
gb_internal lbValue lb_address_from_load(lbProcedure *p, lbValue value) {
if (LLVMIsALoadInst(value.value)) {
lbValue res = {};
res.value = LLVMGetOperand(value.value, 0);
@@ -877,7 +869,7 @@ lbValue lb_address_from_load(lbProcedure *p, lbValue value) {
}
lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) {
gb_internal lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) {
t = base_type(t);
LLVMTypeRef struct_type = lb_type(m, t);
auto *field_remapping = map_get(&m->struct_field_remapping, cast(void *)struct_type);
@@ -888,7 +880,7 @@ lbStructFieldRemapping lb_get_struct_remapping(lbModule *m, Type *t) {
return *field_remapping;
}
i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
gb_internal i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
if (t->kind == Type_Struct) {
auto field_remapping = lb_get_struct_remapping(m, t);
index = field_remapping[index];
@@ -896,7 +888,7 @@ i32 lb_convert_struct_index(lbModule *m, Type *t, i32 index) {
return index;
}
LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align) {
gb_internal LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align) {
// NOTE(bill): limit to `[N x u64]` to prevent ABI issues
padding_align = gb_clamp(padding_align, 1, 8);
if (padding % padding_align == 0) {
@@ -921,7 +913,7 @@ LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align)
}
char const *llvm_type_kinds[] = {
gb_global char const *llvm_type_kinds[] = {
"LLVMVoidTypeKind",
"LLVMHalfTypeKind",
"LLVMFloatTypeKind",
@@ -943,7 +935,55 @@ char const *llvm_type_kinds[] = {
"LLVMBFloatTypeKind",
};
lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
gb_internal lbValue lb_emit_struct_ep_internal(lbProcedure *p, lbValue s, i32 index, Type *result_type) {
Type *t = base_type(type_deref(s.type));
i32 original_index = index;
index = lb_convert_struct_index(p->module, t, index);
if (lb_is_const(s)) {
// NOTE(bill): this cannot be replaced with lb_emit_epi
lbModule *m = p->module;
lbValue res = {};
LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)};
res.value = LLVMConstGEP2(lb_type(m, type_deref(s.type)), s.value, indices, gb_count_of(indices));
res.type = alloc_type_pointer(result_type);
return res;
} else {
lbValue res = {};
LLVMTypeRef st = lb_type(p->module, type_deref(s.type));
// gb_printf_err("%s\n", type_to_string(s.type));
// gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value)));
// gb_printf_err("%d\n", index);
GB_ASSERT_MSG(LLVMGetTypeKind(st) == LLVMStructTypeKind, "%s", llvm_type_kinds[LLVMGetTypeKind(st)]);
unsigned count = LLVMCountStructElementTypes(st);
GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index);
res.value = LLVMBuildStructGEP2(p->builder, st, s.value, cast(unsigned)index, "");
res.type = alloc_type_pointer(result_type);
return res;
}
}
gb_internal lbValue lb_emit_tuple_ep(lbProcedure *p, lbValue ptr, i32 index) {
Type *t = type_deref(ptr.type);
GB_ASSERT(is_type_tuple(t));
Type *result_type = t->Tuple.variables[index]->type;
lbValue res = {};
lbTupleFix *tf = map_get(&p->tuple_fix_map, ptr.value);
if (tf) {
res = tf->values[index];
GB_ASSERT(are_types_identical(res.type, result_type));
res = lb_address_from_load_or_generate_local(p, res);
} else {
res = lb_emit_struct_ep_internal(p, ptr, index, result_type);
}
return res;
}
gb_internal lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
GB_ASSERT(is_type_pointer(s.type));
Type *t = base_type(type_deref(s.type));
Type *result_type = nullptr;
@@ -958,8 +998,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
GB_ASSERT(index == -1);
return lb_emit_union_tag_ptr(p, s);
} else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variables.count > 0);
result_type = t->Tuple.variables[index]->type;
return lb_emit_tuple_ep(p, s, index);
} else if (is_type_complex(t)) {
Type *ft = base_complex_elem_type(t);
switch (index) {
@@ -1024,34 +1063,45 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
GB_ASSERT_MSG(result_type != nullptr, "%s %d", type_to_string(t), index);
i32 original_index = index;
index = lb_convert_struct_index(p->module, t, index);
if (lb_is_const(s)) {
// NOTE(bill): this cannot be replaced with lb_emit_epi
lbModule *m = p->module;
lbValue res = {};
LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)};
res.value = LLVMConstGEP2(lb_type(m, type_deref(s.type)), s.value, indices, gb_count_of(indices));
res.type = alloc_type_pointer(result_type);
return res;
} else {
lbValue res = {};
LLVMTypeRef st = lb_type(p->module, type_deref(s.type));
// gb_printf_err("%s\n", type_to_string(s.type));
// gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value)));
// gb_printf_err("%d\n", index);
GB_ASSERT_MSG(LLVMGetTypeKind(st) == LLVMStructTypeKind, "%s", llvm_type_kinds[LLVMGetTypeKind(st)]);
unsigned count = LLVMCountStructElementTypes(st);
GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index);
res.value = LLVMBuildStructGEP2(p->builder, st, s.value, cast(unsigned)index, "");
res.type = alloc_type_pointer(result_type);
return res;
}
return lb_emit_struct_ep_internal(p, s, index, result_type);
}
lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
gb_internal lbValue lb_emit_tuple_ev(lbProcedure *p, lbValue value, i32 index) {
Type *t = value.type;
GB_ASSERT(is_type_tuple(t));
Type *result_type = t->Tuple.variables[index]->type;
lbValue res = {};
lbTupleFix *tf = map_get(&p->tuple_fix_map, value.value);
if (tf) {
res = tf->values[index];
GB_ASSERT(are_types_identical(res.type, result_type));
} else {
if (t->Tuple.variables.count == 1) {
GB_ASSERT(index == 0);
// value.type = result_type;
return value;
}
if (LLVMIsALoadInst(value.value)) {
lbValue res = {};
res.value = LLVMGetOperand(value.value, 0);
res.type = alloc_type_pointer(value.type);
lbValue ptr = lb_emit_struct_ep(p, res, index);
return lb_emit_load(p, ptr);
}
res.value = LLVMBuildExtractValue(p->builder, value.value, cast(unsigned)index, "");
res.type = result_type;
}
return res;
}
gb_internal lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
Type *t = base_type(s.type);
if (is_type_tuple(t)) {
return lb_emit_tuple_ev(p, s, index);
}
if (LLVMIsALoadInst(s.value)) {
lbValue res = {};
res.value = LLVMGetOperand(s.value, 0);
@@ -1060,7 +1110,6 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
return lb_emit_load(p, ptr);
}
Type *t = base_type(s.type);
Type *result_type = nullptr;
switch (t->kind) {
@@ -1113,12 +1162,7 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
GB_PANIC("lb_emit_union_tag_value");
case Type_Tuple:
GB_ASSERT(t->Tuple.variables.count > 0);
result_type = t->Tuple.variables[index]->type;
if (t->Tuple.variables.count == 1) {
return s;
}
break;
return lb_emit_tuple_ev(p, s, index);
case Type_Slice:
switch (index) {
case 0: result_type = alloc_type_pointer(t->Slice.elem); break;
@@ -1171,7 +1215,7 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
return res;
}
lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
gb_internal lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
GB_ASSERT(sel.index.count > 0);
Type *type = type_deref(e.type);
@@ -1259,14 +1303,14 @@ lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
}
lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel) {
gb_internal lbValue lb_emit_deep_field_ev(lbProcedure *p, lbValue e, Selection sel) {
lbValue ptr = lb_address_from_load_or_generate_local(p, e);
lbValue res = lb_emit_deep_field_gep(p, ptr, sel);
return lb_emit_load(p, res);
}
lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) {
gb_internal lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) {
Type *t = s.type;
GB_ASSERT_MSG(is_type_pointer(t), "%s", type_to_string(t));
Type *st = base_type(type_deref(t));
@@ -1289,7 +1333,7 @@ lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) {
return res;
}
lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) {
gb_internal lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) {
Type *t = s.type;
GB_ASSERT(is_type_pointer(t));
Type *st = base_type(type_deref(t));
@@ -1297,7 +1341,7 @@ lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) {
GB_ASSERT(0 <= index);
return lb_emit_epi(p, s, index);
}
lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) {
gb_internal lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) {
Type *t = s.type;
GB_ASSERT(is_type_pointer(t));
Type *st = base_type(type_deref(t));
@@ -1306,7 +1350,7 @@ lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) {
return lb_emit_epi(m, s, index);
}
lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
gb_internal lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
index = lb_emit_conv(p, index, t_int);
LLVMValueRef indices[1] = {index.value};
lbValue res = {};
@@ -1321,7 +1365,7 @@ lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
return res;
}
lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) {
gb_internal lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) {
Type *t = s.type;
GB_ASSERT(is_type_pointer(t));
Type *mt = base_type(type_deref(t));
@@ -1339,7 +1383,7 @@ lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) {
return lb_emit_epi(p, s, offset);
}
lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) {
gb_internal lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) {
Type *t = s.type;
GB_ASSERT(is_type_pointer(t));
Type *mt = base_type(type_deref(t));
@@ -1371,7 +1415,7 @@ lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column
}
lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column) {
gb_internal lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column) {
Type *st = base_type(s.type);
GB_ASSERT_MSG(is_type_matrix(st), "%s", type_to_string(st));
@@ -1381,14 +1425,14 @@ lbValue lb_emit_matrix_ev(lbProcedure *p, lbValue s, isize row, isize column) {
}
void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len) {
gb_internal void lb_fill_slice(lbProcedure *p, lbAddr const &slice, lbValue base_elem, lbValue len) {
Type *t = lb_addr_type(slice);
GB_ASSERT(is_type_slice(t));
lbValue ptr = lb_addr_get_ptr(p, slice);
lb_emit_store(p, lb_emit_struct_ep(p, ptr, 0), base_elem);
lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len);
}
void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbValue len) {
gb_internal void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbValue len) {
Type *t = lb_addr_type(string);
GB_ASSERT(is_type_string(t));
lbValue ptr = lb_addr_get_ptr(p, string);
@@ -1396,18 +1440,18 @@ void lb_fill_string(lbProcedure *p, lbAddr const &string, lbValue base_elem, lbV
lb_emit_store(p, lb_emit_struct_ep(p, ptr, 1), len);
}
lbValue lb_string_elem(lbProcedure *p, lbValue string) {
gb_internal lbValue lb_string_elem(lbProcedure *p, lbValue string) {
Type *t = base_type(string.type);
GB_ASSERT(t->kind == Type_Basic && t->Basic.kind == Basic_string);
return lb_emit_struct_ev(p, string, 0);
}
lbValue lb_string_len(lbProcedure *p, lbValue string) {
gb_internal lbValue lb_string_len(lbProcedure *p, lbValue string) {
Type *t = base_type(string.type);
GB_ASSERT_MSG(t->kind == Type_Basic && t->Basic.kind == Basic_string, "%s", type_to_string(t));
return lb_emit_struct_ev(p, string, 1);
}
lbValue lb_cstring_len(lbProcedure *p, lbValue value) {
gb_internal lbValue lb_cstring_len(lbProcedure *p, lbValue value) {
GB_ASSERT(is_type_cstring(value.type));
auto args = array_make<lbValue>(permanent_allocator(), 1);
args[0] = lb_emit_conv(p, value, t_cstring);
@@ -1415,43 +1459,39 @@ lbValue lb_cstring_len(lbProcedure *p, lbValue value) {
}
lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr) {
gb_internal lbValue lb_array_elem(lbProcedure *p, lbValue array_ptr) {
Type *t = type_deref(array_ptr.type);
GB_ASSERT(is_type_array(t));
return lb_emit_struct_ep(p, array_ptr, 0);
}
lbValue lb_slice_elem(lbProcedure *p, lbValue slice) {
gb_internal lbValue lb_slice_elem(lbProcedure *p, lbValue slice) {
GB_ASSERT(is_type_slice(slice.type));
return lb_emit_struct_ev(p, slice, 0);
}
lbValue lb_slice_len(lbProcedure *p, lbValue slice) {
gb_internal lbValue lb_slice_len(lbProcedure *p, lbValue slice) {
GB_ASSERT(is_type_slice(slice.type) || is_type_relative_slice(slice.type));
return lb_emit_struct_ev(p, slice, 1);
}
lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) {
gb_internal lbValue lb_dynamic_array_elem(lbProcedure *p, lbValue da) {
GB_ASSERT(is_type_dynamic_array(da.type));
return lb_emit_struct_ev(p, da, 0);
}
lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da) {
gb_internal lbValue lb_dynamic_array_len(lbProcedure *p, lbValue da) {
GB_ASSERT(is_type_dynamic_array(da.type));
return lb_emit_struct_ev(p, da, 1);
}
lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da) {
gb_internal lbValue lb_dynamic_array_cap(lbProcedure *p, lbValue da) {
GB_ASSERT(is_type_dynamic_array(da.type));
return lb_emit_struct_ev(p, da, 2);
}
lbValue lb_dynamic_array_allocator(lbProcedure *p, lbValue da) {
GB_ASSERT(is_type_dynamic_array(da.type));
return lb_emit_struct_ev(p, da, 3);
}
lbValue lb_map_len(lbProcedure *p, lbValue value) {
gb_internal lbValue lb_map_len(lbProcedure *p, lbValue value) {
GB_ASSERT_MSG(is_type_map(value.type) || are_types_identical(value.type, t_raw_map), "%s", type_to_string(value.type));
lbValue len = lb_emit_struct_ev(p, value, 1);
return lb_emit_conv(p, len, t_int);
}
lbValue lb_map_len_ptr(lbProcedure *p, lbValue map_ptr) {
gb_internal lbValue lb_map_len_ptr(lbProcedure *p, lbValue map_ptr) {
Type *type = map_ptr.type;
GB_ASSERT(is_type_pointer(type));
type = type_deref(type);
@@ -1459,7 +1499,7 @@ lbValue lb_map_len_ptr(lbProcedure *p, lbValue map_ptr) {
return lb_emit_struct_ep(p, map_ptr, 1);
}
lbValue lb_map_cap(lbProcedure *p, lbValue value) {
gb_internal lbValue lb_map_cap(lbProcedure *p, lbValue value) {
GB_ASSERT_MSG(is_type_map(value.type) || are_types_identical(value.type, t_raw_map), "%s", type_to_string(value.type));
lbValue zero = lb_const_int(p->module, t_uintptr, 0);
lbValue one = lb_const_int(p->module, t_uintptr, 1);
@@ -1473,7 +1513,7 @@ lbValue lb_map_cap(lbProcedure *p, lbValue value) {
return lb_emit_conv(p, lb_emit_select(p, cmp, zero, cap), t_int);
}
lbValue lb_map_data_uintptr(lbProcedure *p, lbValue value) {
gb_internal lbValue lb_map_data_uintptr(lbProcedure *p, lbValue value) {
GB_ASSERT(is_type_map(value.type) || are_types_identical(value.type, t_raw_map));
lbValue data = lb_emit_struct_ev(p, value, 0);
u64 mask_value = 0;
@@ -1487,7 +1527,7 @@ lbValue lb_map_data_uintptr(lbProcedure *p, lbValue value) {
}
lbValue lb_soa_struct_len(lbProcedure *p, lbValue value) {
gb_internal lbValue lb_soa_struct_len(lbProcedure *p, lbValue value) {
Type *t = base_type(value.type);
bool is_ptr = false;
if (is_type_pointer(t)) {
@@ -1520,7 +1560,7 @@ lbValue lb_soa_struct_len(lbProcedure *p, lbValue value) {
return lb_emit_struct_ev(p, value, cast(i32)n);
}
lbValue lb_soa_struct_cap(lbProcedure *p, lbValue value) {
gb_internal lbValue lb_soa_struct_cap(lbProcedure *p, lbValue value) {
Type *t = base_type(value.type);
bool is_ptr = false;
@@ -1552,7 +1592,7 @@ lbValue lb_soa_struct_cap(lbProcedure *p, lbValue value) {
return lb_emit_struct_ev(p, value, cast(i32)n);
}
lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t) {
gb_internal lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t) {
lbModule *m = p->module;
a = lb_emit_conv(p, a, t);
@@ -1595,7 +1635,7 @@ lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t
}
}
LLVMValueRef llvm_mask_iota(lbModule *m, unsigned start, unsigned count) {
gb_internal LLVMValueRef llvm_mask_iota(lbModule *m, unsigned start, unsigned count) {
auto iota = slice_make<LLVMValueRef>(temporary_allocator(), count);
for (unsigned i = 0; i < count; i++) {
iota[i] = lb_const_int(m, t_u32, start+i).value;
@@ -1603,7 +1643,7 @@ LLVMValueRef llvm_mask_iota(lbModule *m, unsigned start, unsigned count) {
return LLVMConstVector(iota.data, count);
}
LLVMValueRef llvm_mask_zero(lbModule *m, unsigned count) {
gb_internal LLVMValueRef llvm_mask_zero(lbModule *m, unsigned count) {
return LLVMConstNull(LLVMVectorType(lb_type(m, t_u32), count));
}
@@ -1611,16 +1651,16 @@ LLVMValueRef llvm_mask_zero(lbModule *m, unsigned count) {
// #define LLVM_VECTOR_DUMMY_VALUE(type) LLVMConstNull((type))
LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask) {
gb_internal LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask) {
return LLVMBuildShuffleVector(p->builder, vector, LLVM_VECTOR_DUMMY_VALUE(LLVMTypeOf(vector)), mask, "");
}
LLVMValueRef llvm_basic_const_shuffle(LLVMValueRef vector, LLVMValueRef mask) {
gb_internal LLVMValueRef llvm_basic_const_shuffle(LLVMValueRef vector, LLVMValueRef mask) {
return LLVMConstShuffleVector(vector, LLVM_VECTOR_DUMMY_VALUE(LLVMTypeOf(vector)), mask);
}
LLVMValueRef llvm_vector_broadcast(lbProcedure *p, LLVMValueRef value, unsigned count) {
gb_internal LLVMValueRef llvm_vector_broadcast(lbProcedure *p, LLVMValueRef value, unsigned count) {
GB_ASSERT(count > 0);
if (LLVMIsConstant(value)) {
LLVMValueRef single = LLVMConstVector(&value, 1);
@@ -1640,7 +1680,7 @@ LLVMValueRef llvm_vector_broadcast(lbProcedure *p, LLVMValueRef value, unsigned
return llvm_basic_shuffle(p, single, mask);
}
LLVMValueRef llvm_vector_shuffle_reduction(lbProcedure *p, LLVMValueRef value, LLVMOpcode op_code) {
gb_internal LLVMValueRef llvm_vector_shuffle_reduction(lbProcedure *p, LLVMValueRef value, LLVMOpcode op_code) {
LLVMTypeRef original_vector_type = LLVMTypeOf(value);
GB_ASSERT(LLVMGetTypeKind(original_vector_type) == LLVMVectorTypeKind);
@@ -1667,7 +1707,7 @@ LLVMValueRef llvm_vector_shuffle_reduction(lbProcedure *p, LLVMValueRef value, L
return LLVMBuildExtractElement(p->builder, value, v_zero32, "");
}
LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef value) {
gb_internal LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef value) {
LLVMTypeRef vector_type = LLVMTypeOf(value);
unsigned len = LLVMGetVectorSize(vector_type);
if (len == 1) {
@@ -1682,7 +1722,7 @@ LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef val
return LLVMBuildShuffleVector(p->builder, value, LLVMConstNull(vector_type), mask, "");
}
LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
gb_internal LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
LLVMTypeRef type = LLVMTypeOf(value);
GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind);
LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
@@ -1758,7 +1798,7 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
#endif
}
LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
gb_internal LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
@@ -1769,7 +1809,7 @@ LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
return LLVMBuildFAdd(p->builder, a, b, "");
}
LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
gb_internal LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
@@ -1781,11 +1821,11 @@ LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
}
LLVMValueRef llvm_vector_dot(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
gb_internal LLVMValueRef llvm_vector_dot(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
return llvm_vector_reduce_add(p, llvm_vector_mul(p, a, b));
}
LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, LLVMValueRef c) {
gb_internal LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, LLVMValueRef c) {
LLVMTypeRef t = LLVMTypeOf(a);
GB_ASSERT(t == LLVMTypeOf(b));
@@ -1819,7 +1859,7 @@ LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b,
}
}
LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, String const &clobbers, bool has_side_effects=true, bool is_align_stack=false, LLVMInlineAsmDialect dialect=LLVMInlineAsmDialectATT) {
gb_internal LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, String const &clobbers, bool has_side_effects=true, bool is_align_stack=false, LLVMInlineAsmDialect dialect=LLVMInlineAsmDialectATT) {
return LLVMGetInlineAsm(func_type,
cast(char *)str.text, cast(size_t)str.len,
cast(char *)clobbers.text, cast(size_t)clobbers.len,
@@ -1832,7 +1872,7 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin
}
void lb_set_wasm_import_attributes(LLVMValueRef value, Entity *entity, String import_name) {
gb_internal void lb_set_wasm_import_attributes(LLVMValueRef value, Entity *entity, String import_name) {
if (!is_arch_wasm()) {
return;
}
@@ -1854,7 +1894,7 @@ void lb_set_wasm_import_attributes(LLVMValueRef value, Entity *entity, String im
}
void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) {
gb_internal void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) {
if (!is_arch_wasm()) {
return;
}
@@ -1866,7 +1906,7 @@ void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) {
lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
gb_internal lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
lbAddr *found = string_map_get(&p->module->objc_selectors, name);
if (found) {
return *found;
@@ -1886,7 +1926,7 @@ lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &na
}
}
lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
ast_node(ce, CallExpr, expr);
auto tav = ce->args[0]->tav;
@@ -1895,7 +1935,7 @@ lbValue lb_handle_objc_find_selector(lbProcedure *p, Ast *expr) {
return lb_addr_load(p, lb_handle_objc_find_or_register_selector(p, name));
}
lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) {
ast_node(ce, CallExpr, expr);
lbModule *m = p->module;
@@ -1912,7 +1952,7 @@ lbValue lb_handle_objc_register_selector(lbProcedure *p, Ast *expr) {
return lb_addr_load(p, dst);
}
lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) {
gb_internal lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name) {
lbAddr *found = string_map_get(&p->module->objc_classes, name);
if (found) {
return *found;
@@ -1932,7 +1972,7 @@ lbAddr lb_handle_objc_find_or_register_class(lbProcedure *p, String const &name)
}
}
lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
ast_node(ce, CallExpr, expr);
auto tav = ce->args[0]->tav;
@@ -1941,7 +1981,7 @@ lbValue lb_handle_objc_find_class(lbProcedure *p, Ast *expr) {
return lb_addr_load(p, lb_handle_objc_find_or_register_class(p, name));
}
lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) {
ast_node(ce, CallExpr, expr);
lbModule *m = p->module;
@@ -1961,7 +2001,7 @@ lbValue lb_handle_objc_register_class(lbProcedure *p, Ast *expr) {
}
lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
TypeAndValue const &tav = type_and_value_of_expr(expr);
if (tav.mode == Addressing_Type) {
Type *type = tav.type;
@@ -1992,7 +2032,7 @@ lbValue lb_handle_objc_id(lbProcedure *p, Ast *expr) {
return lb_build_expr(p, expr);
}
lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) {
gb_internal lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) {
ast_node(ce, CallExpr, expr);
lbModule *m = p->module;
@@ -2035,7 +2075,7 @@ lbValue lb_handle_objc_send(lbProcedure *p, Ast *expr) {
LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) {
gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) {
GB_ASSERT(value.kind == ExactValue_Integer);
i64 v = exact_value_to_i64(value);
switch (v) {
@@ -2051,7 +2091,7 @@ LLVMAtomicOrdering llvm_atomic_ordering_from_odin(ExactValue const &value) {
}
LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) {
gb_internal LLVMAtomicOrdering llvm_atomic_ordering_from_odin(Ast *expr) {
ExactValue value = type_and_value_of_expr(expr).value;
return llvm_atomic_ordering_from_odin(value);
}
+124 -204
View File
@@ -3,31 +3,41 @@
#include "common.cpp"
#include "timings.cpp"
#include "tokenizer.cpp"
#if defined(GB_SYSTEM_WINDOWS)
#pragma warning(push)
#pragma warning(disable: 4505)
#endif
#include "big_int.cpp"
#if defined(GB_SYSTEM_WINDOWS)
#pragma warning(pop)
#endif
#include "exact_value.cpp"
#include "build_settings.cpp"
gb_global ThreadPool global_thread_pool;
void init_global_thread_pool(void) {
gb_internal void init_global_thread_pool(void) {
isize thread_count = gb_max(build_context.thread_count, 1);
isize worker_count = thread_count-1; // NOTE(bill): The main thread will also be used for work
thread_pool_init(&global_thread_pool, permanent_allocator(), worker_count, "ThreadPoolWorker");
isize worker_count = thread_count; // +1
thread_pool_init(&global_thread_pool, worker_count, "ThreadPoolWorker");
}
bool global_thread_pool_add_task(WorkerTaskProc *proc, void *data) {
gb_internal bool thread_pool_add_task(WorkerTaskProc *proc, void *data) {
return thread_pool_add_task(&global_thread_pool, proc, data);
}
void global_thread_pool_wait(void) {
gb_internal void thread_pool_wait(void) {
thread_pool_wait(&global_thread_pool);
}
void debugf(char const *fmt, ...) {
gb_global BlockingMutex debugf_mutex;
gb_internal void debugf(char const *fmt, ...) {
if (build_context.show_debug_messages) {
mutex_lock(&debugf_mutex);
gb_printf_err("[DEBUG] ");
va_list va;
va_start(va, fmt);
(void)gb_printf_err_va(fmt, va);
va_end(va);
mutex_unlock(&debugf_mutex);
}
}
@@ -58,11 +68,10 @@ gb_global Timings global_timings = {0};
#endif
#endif
#include "query_data.cpp"
#include "bug_report.cpp"
// NOTE(bill): 'name' is used in debugging and profiling modes
i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
gb_internal i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
isize const cmd_cap = 64<<20; // 64 MiB should be more than enough
char *cmd_line = gb_alloc_array(gb_heap_allocator(), char, cmd_cap);
isize cmd_len = 0;
@@ -124,7 +133,7 @@ i32 system_exec_command_line_app(char const *name, char const *fmt, ...) {
}
i32 linker_stage(lbGenerator *gen) {
gb_internal i32 linker_stage(lbGenerator *gen) {
i32 result = 0;
Timings *timings = &global_timings;
@@ -207,15 +216,14 @@ i32 linker_stage(lbGenerator *gen) {
StringSet libs = {};
string_set_init(&libs, heap_allocator(), 64);
string_set_init(&libs, 64);
defer (string_set_destroy(&libs));
StringSet asm_files = {};
string_set_init(&asm_files, heap_allocator(), 64);
string_set_init(&asm_files, 64);
defer (string_set_destroy(&asm_files));
for_array(j, gen->foreign_libraries) {
Entity *e = gen->foreign_libraries[j];
for (Entity *e : gen->foreign_libraries) {
GB_ASSERT(e->kind == Entity_LibraryName);
for_array(i, e->LibraryName.paths) {
String lib = string_trim_whitespace(e->LibraryName.paths[i]);
@@ -278,8 +286,7 @@ i32 linker_stage(lbGenerator *gen) {
gbString object_files = gb_string_make(heap_allocator(), "");
defer (gb_string_free(object_files));
for_array(i, gen->output_object_paths) {
String object_path = gen->output_object_paths[i];
for (String const &object_path : gen->output_object_paths) {
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
}
@@ -313,12 +320,18 @@ i32 linker_stage(lbGenerator *gen) {
}
}
switch (build_context.build_mode) {
case BuildMode_Executable:
link_settings = gb_string_append_fmt(link_settings, " /NOIMPLIB /NOEXP");
break;
}
result = system_exec_command_line_app("msvc-link",
"\"%.*slink.exe\" %s %.*s -OUT:\"%.*s\" %s "
"/nologo /incremental:no /opt:ref /subsystem:%s "
" %.*s "
" %.*s "
" %s "
"%.*s "
"%.*s "
"%s "
"",
LIT(vs_exe_path), object_files, LIT(res_path), LIT(output_filename),
link_settings,
@@ -334,9 +347,9 @@ i32 linker_stage(lbGenerator *gen) {
result = system_exec_command_line_app("msvc-lld-link",
"\"%.*s\\bin\\lld-link\" %s -OUT:\"%.*s\" %s "
"/nologo /incremental:no /opt:ref /subsystem:%s "
" %.*s "
" %.*s "
" %s "
"%.*s "
"%.*s "
"%s "
"",
LIT(build_context.ODIN_ROOT), object_files, LIT(output_filename),
link_settings,
@@ -366,14 +379,13 @@ i32 linker_stage(lbGenerator *gen) {
defer (gb_string_free(lib_str));
StringSet libs = {};
string_set_init(&libs, heap_allocator(), 64);
string_set_init(&libs, 64);
defer (string_set_destroy(&libs));
for_array(j, gen->foreign_libraries) {
Entity *e = gen->foreign_libraries[j];
for (Entity *e : gen->foreign_libraries) {
GB_ASSERT(e->kind == Entity_LibraryName);
for_array(i, e->LibraryName.paths) {
String lib = string_trim_whitespace(e->LibraryName.paths[i]);
for (String lib : e->LibraryName.paths) {
lib = string_trim_whitespace(lib);
if (lib.len == 0) {
continue;
}
@@ -425,8 +437,7 @@ i32 linker_stage(lbGenerator *gen) {
gbString object_files = gb_string_make(heap_allocator(), "");
defer (gb_string_free(object_files));
for_array(i, gen->output_object_paths) {
String object_path = gen->output_object_paths[i];
for (String object_path : gen->output_object_paths) {
object_files = gb_string_append_fmt(object_files, "\"%.*s\" ", LIT(object_path));
}
@@ -524,7 +535,7 @@ i32 linker_stage(lbGenerator *gen) {
return result;
}
Array<String> setup_args(int argc, char const **argv) {
gb_internal Array<String> setup_args(int argc, char const **argv) {
gbAllocator a = heap_allocator();
#if defined(GB_SYSTEM_WINDOWS)
@@ -553,7 +564,7 @@ Array<String> setup_args(int argc, char const **argv) {
#endif
}
void print_usage_line(i32 indent, char const *fmt, ...) {
gb_internal void print_usage_line(i32 indent, char const *fmt, ...) {
while (indent --> 0) {
gb_printf_err("\t");
}
@@ -564,7 +575,7 @@ void print_usage_line(i32 indent, char const *fmt, ...) {
gb_printf_err("\n");
}
void usage(String argv0) {
gb_internal void usage(String argv0) {
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(argv0));
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s command [arguments]", LIT(argv0));
@@ -573,7 +584,6 @@ void usage(String argv0) {
print_usage_line(1, " one must contain the program's entry point, all must be in the same package.");
print_usage_line(1, "run same as 'build', but also then runs the newly compiled executable.");
print_usage_line(1, "check parse, and type check a directory of .odin files");
print_usage_line(1, "query parse, type check, and output a .json file containing information about the program");
print_usage_line(1, "strip-semicolon parse, type check, and remove unneeded semicolons from the entire program");
print_usage_line(1, "test build and runs procedures with the attribute @(test) in the initial package");
print_usage_line(1, "doc generate documentation on a directory of .odin files");
@@ -613,7 +623,6 @@ enum BuildFlagKind {
BuildFlag_NoEntryPoint,
BuildFlag_UseLLD,
BuildFlag_UseSeparateModules,
BuildFlag_ThreadedChecker,
BuildFlag_NoThreadedChecker,
BuildFlag_ShowDebugMessages,
BuildFlag_Vet,
@@ -655,6 +664,7 @@ enum BuildFlagKind {
// internal use only
BuildFlag_InternalIgnoreLazy,
BuildFlag_InternalIgnoreLLVMBuild,
#if defined(GB_SYSTEM_WINDOWS)
BuildFlag_IgnoreVsSearch,
@@ -687,12 +697,12 @@ struct BuildFlag {
};
void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_mulitple=false) {
gb_internal void add_flag(Array<BuildFlag> *build_flags, BuildFlagKind kind, String name, BuildFlagParamKind param_kind, u32 command_support, bool allow_mulitple=false) {
BuildFlag flag = {kind, name, param_kind, command_support, allow_mulitple};
array_add(build_flags, flag);
}
ExactValue build_param_to_exact_value(String name, String param) {
gb_internal ExactValue build_param_to_exact_value(String name, String param) {
ExactValue value = {};
/*
@@ -747,7 +757,7 @@ ExactValue build_param_to_exact_value(String name, String param) {
}
// Writes a did-you-mean message for formerly deprecated flags.
void did_you_mean_flag(String flag) {
gb_internal void did_you_mean_flag(String flag) {
gbAllocator a = heap_allocator();
String name = copy_string(a, flag);
defer (gb_free(a, name.text));
@@ -760,11 +770,11 @@ void did_you_mean_flag(String flag) {
gb_printf_err("Unknown flag: '%.*s'\n", LIT(flag));
}
bool parse_build_flags(Array<String> args) {
gb_internal bool parse_build_flags(Array<String> args) {
auto build_flags = array_make<BuildFlag>(heap_allocator(), 0, BuildFlag_COUNT);
add_flag(&build_flags, BuildFlag_Help, str_lit("help"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_SingleFile, str_lit("file"), BuildFlagParam_None, Command__does_build | Command__does_check);
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build &~ Command_test);
add_flag(&build_flags, BuildFlag_OutFile, str_lit("out"), BuildFlagParam_String, Command__does_build | Command_test);
add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("o"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_OptimizationMode, str_lit("O"), BuildFlagParam_String, Command__does_build);
add_flag(&build_flags, BuildFlag_ShowTimings, str_lit("show-timings"), BuildFlagParam_None, Command__does_check);
@@ -788,7 +798,6 @@ bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_NoEntryPoint, str_lit("no-entry-point"), BuildFlagParam_None, Command__does_check &~ Command_test);
add_flag(&build_flags, BuildFlag_UseLLD, str_lit("lld"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_UseSeparateModules, str_lit("use-separate-modules"), BuildFlagParam_None, Command__does_build);
add_flag(&build_flags, BuildFlag_ThreadedChecker, str_lit("threaded-checker"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_NoThreadedChecker, str_lit("no-threaded-checker"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_ShowDebugMessages, str_lit("show-debug-messages"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_Vet, str_lit("vet"), BuildFlagParam_None, Command__does_check);
@@ -817,12 +826,6 @@ bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_UseStaticMapCalls, str_lit("use-static-map-calls"), BuildFlagParam_None, Command__does_check);
add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query);
add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query);
add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query);
add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc);
add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc);
add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc);
@@ -833,6 +836,7 @@ bool parse_build_flags(Array<String> args) {
add_flag(&build_flags, BuildFlag_ErrorPosStyle, str_lit("error-pos-style"), BuildFlagParam_String, Command_all);
add_flag(&build_flags, BuildFlag_InternalIgnoreLazy, str_lit("internal-ignore-lazy"), BuildFlagParam_None, Command_all);
add_flag(&build_flags, BuildFlag_InternalIgnoreLLVMBuild, str_lit("internal-ignore-llvm-build"),BuildFlagParam_None, Command_all);
#if defined(GB_SYSTEM_WINDOWS)
add_flag(&build_flags, BuildFlag_IgnoreVsSearch, str_lit("ignore-vs-search"), BuildFlagParam_None, Command__does_build);
@@ -848,8 +852,7 @@ bool parse_build_flags(Array<String> args) {
bool set_flags[BuildFlag_COUNT] = {};
bool bad_flags = false;
for_array(i, flag_args) {
String flag = flag_args[i];
for (String flag : flag_args) {
if (flag[0] != '-') {
gb_printf_err("Invalid flag: %.*s\n", LIT(flag));
continue;
@@ -878,8 +881,7 @@ bool parse_build_flags(Array<String> args) {
bool found = false;
BuildFlag found_bf = {};
for_array(build_flag_index, build_flags) {
BuildFlag bf = build_flags[build_flag_index];
for (BuildFlag const &bf : build_flags) {
if (bf.name == name) {
found = true;
found_bf = bf;
@@ -1311,20 +1313,8 @@ bool parse_build_flags(Array<String> args) {
case BuildFlag_UseSeparateModules:
build_context.use_separate_modules = true;
break;
case BuildFlag_ThreadedChecker: {
#if defined(DEFAULT_TO_THREADED_CHECKER)
gb_printf_err("-threaded-checker is the default on this platform\n");
bad_flags = true;
#endif
build_context.threaded_checker = true;
break;
}
case BuildFlag_NoThreadedChecker: {
#if !defined(DEFAULT_TO_THREADED_CHECKER)
gb_printf_err("-no-threaded-checker is the default on this platform\n");
bad_flags = true;
#endif
build_context.threaded_checker = false;
build_context.no_threaded_checker = true;
break;
}
case BuildFlag_ShowDebugMessages:
@@ -1445,39 +1435,6 @@ bool parse_build_flags(Array<String> args) {
build_context.strict_style_init_only = true;
break;
}
case BuildFlag_Compact: {
if (!build_context.query_data_set_settings.ok) {
gb_printf_err("Invalid use of -compact flag, only allowed with 'odin query'\n");
bad_flags = true;
} else {
build_context.query_data_set_settings.compact = true;
}
break;
}
case BuildFlag_GlobalDefinitions: {
if (!build_context.query_data_set_settings.ok) {
gb_printf_err("Invalid use of -global-definitions flag, only allowed with 'odin query'\n");
bad_flags = true;
} else if (build_context.query_data_set_settings.kind != QueryDataSet_Invalid) {
gb_printf_err("Invalid use of -global-definitions flag, a previous flag for 'odin query' was set\n");
bad_flags = true;
} else {
build_context.query_data_set_settings.kind = QueryDataSet_GlobalDefinitions;
}
break;
}
case BuildFlag_GoToDefinitions: {
if (!build_context.query_data_set_settings.ok) {
gb_printf_err("Invalid use of -go-to-definitions flag, only allowed with 'odin query'\n");
bad_flags = true;
} else if (build_context.query_data_set_settings.kind != QueryDataSet_Invalid) {
gb_printf_err("Invalid use of -global-definitions flag, a previous flag for 'odin query' was set\n");
bad_flags = true;
} else {
build_context.query_data_set_settings.kind = QueryDataSet_GoToDefinitions;
}
break;
}
case BuildFlag_Short:
build_context.cmd_doc_flags |= CmdDocFlag_Short;
break;
@@ -1525,6 +1482,9 @@ bool parse_build_flags(Array<String> args) {
case BuildFlag_InternalIgnoreLazy:
build_context.ignore_lazy = true;
break;
case BuildFlag_InternalIgnoreLLVMBuild:
build_context.ignore_llvm_build = true;
break;
#if defined(GB_SYSTEM_WINDOWS)
case BuildFlag_IgnoreVsSearch: {
GB_ASSERT(value.kind == ExactValue_Invalid);
@@ -1638,20 +1598,10 @@ bool parse_build_flags(Array<String> args) {
gb_printf_err("`-export-timings:<format>` requires `-show-timings` or `-show-more-timings` to be present\n");
bad_flags = true;
}
if (build_context.query_data_set_settings.ok) {
if (build_context.query_data_set_settings.kind == QueryDataSet_Invalid) {
gb_printf_err("'odin query' requires a flag determining the kind of query data set to be returned\n");
gb_printf_err("\t-global-definitions : outputs a JSON file of global definitions\n");
gb_printf_err("\t-go-to-definitions : outputs a OGTD binary file of go to definitions for identifiers within an Odin project\n");
bad_flags = true;
}
}
return !bad_flags;
}
void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = false) {
gb_internal void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = false) {
GB_ASSERT((!(build_context.export_timings_format == TimingsExportUnspecified) && build_context.export_timings_file.len > 0));
/*
@@ -1690,10 +1640,9 @@ void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = fal
isize files = 0;
isize packages = p->packages.count;
isize total_file_size = 0;
for_array(i, p->packages) {
files += p->packages[i]->files.count;
for_array(j, p->packages[i]->files) {
AstFile *file = p->packages[i]->files[j];
for (AstPackage *pkg : p->packages) {
files += pkg->files.count;
for (AstFile *file : pkg->files) {
total_file_size += file->tokenizer.end - file->tokenizer.start;
}
}
@@ -1717,8 +1666,7 @@ void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = fal
gb_fprintf(&f, "\t\t{\"name\": \"%.*s\", \"millis\": %.3f},\n",
LIT(t->total.label), total_time);
for_array(i, t->sections) {
TimeStamp ts = t->sections[i];
for (TimeStamp const &ts : t->sections) {
f64 section_time = time_stamp(ts, t->freq, unit);
gb_fprintf(&f, "\t\t{\"name\": \"%.*s\", \"millis\": %.3f},\n",
LIT(ts.label), section_time);
@@ -1739,8 +1687,7 @@ void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = fal
*/
gb_fprintf(&f, "\"%.*s\", %d\n", LIT(t->total.label), int(total_time));
for_array(i, t->sections) {
TimeStamp ts = t->sections[i];
for (TimeStamp const &ts : t->sections) {
f64 section_time = time_stamp(ts, t->freq, unit);
gb_fprintf(&f, "\"%.*s\", %d\n", LIT(ts.label), int(section_time));
}
@@ -1749,7 +1696,7 @@ void timings_export_all(Timings *t, Checker *c, bool timings_are_finalized = fal
gb_printf("Done.\n");
}
void show_timings(Checker *c, Timings *t) {
gb_internal void show_timings(Checker *c, Timings *t) {
Parser *p = c->parser;
isize lines = p->total_line_count;
isize tokens = p->total_token_count;
@@ -1758,10 +1705,9 @@ void show_timings(Checker *c, Timings *t) {
isize total_file_size = 0;
f64 total_tokenizing_time = 0;
f64 total_parsing_time = 0;
for_array(i, p->packages) {
files += p->packages[i]->files.count;
for_array(j, p->packages[i]->files) {
AstFile *file = p->packages[i]->files[j];
for (AstPackage *pkg : p->packages) {
files += pkg->files.count;
for (AstFile *file : pkg->files) {
total_tokenizing_time += file->time_to_tokenize;
total_parsing_time += file->time_to_parse;
total_file_size += file->tokenizer.end - file->tokenizer.start;
@@ -1770,6 +1716,16 @@ void show_timings(Checker *c, Timings *t) {
timings_print_all(t);
if (build_context.show_more_timings) {
#if defined(GB_SYSTEM_WINDOWS)
PROCESS_MEMORY_COUNTERS p = {sizeof(p)};
if (GetProcessMemoryInfo(GetCurrentProcess(), &p, sizeof(p))) {
gb_printf("\n");
gb_printf("Peak Memory Size: %.3f MiB\n", (cast(f64)p.PeakWorkingSetSize) / cast(f64)(1024ull * 1024ull));
}
#endif
}
if (!(build_context.export_timings_format == TimingsExportUnspecified)) {
timings_export_all(t, c, true);
}
@@ -1812,8 +1768,7 @@ void show_timings(Checker *c, Timings *t) {
}
{
TimeStamp ts = {};
for_array(i, t->sections) {
TimeStamp s = t->sections[i];
for (TimeStamp const &s : t->sections) {
if (s.label == "parse files") {
ts = s;
break;
@@ -1836,8 +1791,7 @@ void show_timings(Checker *c, Timings *t) {
{
TimeStamp ts = {};
TimeStamp ts_end = {};
for_array(i, t->sections) {
TimeStamp s = t->sections[i];
for (TimeStamp const &s : t->sections) {
if (s.label == "type check") {
ts = s;
}
@@ -1878,13 +1832,12 @@ void show_timings(Checker *c, Timings *t) {
}
}
void remove_temp_files(lbGenerator *gen) {
gb_internal void remove_temp_files(lbGenerator *gen) {
if (build_context.keep_temp_files) return;
TIME_SECTION("remove keep temp files");
for_array(i, gen->output_temp_paths) {
String path = gen->output_temp_paths[i];
for (String const &path : gen->output_temp_paths) {
gb_file_remove(cast(char const *)path.text);
}
@@ -1892,8 +1845,7 @@ void remove_temp_files(lbGenerator *gen) {
switch (build_context.build_mode) {
case BuildMode_Executable:
case BuildMode_DynamicLibrary:
for_array(i, gen->output_object_paths) {
String path = gen->output_object_paths[i];
for (String const &path : gen->output_object_paths) {
gb_file_remove(cast(char const *)path.text);
}
break;
@@ -1902,7 +1854,7 @@ void remove_temp_files(lbGenerator *gen) {
}
void print_show_help(String const arg0, String const &command) {
gb_internal void print_show_help(String const arg0, String const &command) {
print_usage_line(0, "%.*s is a tool for managing Odin source code", LIT(arg0));
print_usage_line(0, "Usage:");
print_usage_line(1, "%.*s %.*s [arguments]", LIT(arg0), LIT(command));
@@ -1930,9 +1882,7 @@ void print_show_help(String const arg0, String const &command) {
print_usage_line(3, "odin check <dir> # Type check package in <dir>");
print_usage_line(3, "odin check filename.odin -file # Type check single-file package, must contain entry point.");
} else if (command == "test") {
print_usage_line(1, "test Build ands runs procedures with the attribute @(test) in the initial package");
} else if (command == "query") {
print_usage_line(1, "query [experimental] Parse, type check, and output a .json file containing information about the program");
print_usage_line(1, "test Build and runs procedures with the attribute @(test) in the initial package");
} else if (command == "doc") {
print_usage_line(1, "doc generate documentation from a directory of .odin files");
print_usage_line(2, "Examples:");
@@ -2248,12 +2198,11 @@ void print_show_help(String const arg0, String const &command) {
}
}
void print_show_unused(Checker *c) {
gb_internal void print_show_unused(Checker *c) {
CheckerInfo *info = &c->info;
auto unused = array_make<Entity *>(permanent_allocator(), 0, info->entities.count);
for_array(i, info->entities) {
Entity *e = info->entities[i];
for (Entity *e : info->entities) {
if (e == nullptr) {
continue;
}
@@ -2300,8 +2249,7 @@ void print_show_unused(Checker *c) {
AstPackage *curr_pkg = nullptr;
EntityKind curr_entity_kind = Entity_Invalid;
for_array(i, unused) {
Entity *e = unused[i];
for (Entity *e : unused) {
if (curr_pkg != e->pkg) {
curr_pkg = e->pkg;
curr_entity_kind = Entity_Invalid;
@@ -2322,7 +2270,7 @@ void print_show_unused(Checker *c) {
print_usage_line(0, "");
}
bool check_env(void) {
gb_internal bool check_env(void) {
gbAllocator a = heap_allocator();
char const *odin_root = gb_get_env("ODIN_ROOT", a);
defer (gb_free(a, cast(void *)odin_root));
@@ -2348,25 +2296,24 @@ struct StripSemicolonFile {
i64 written;
};
gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *written_) {
gb_internal gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *written_) {
i64 written = 0;
gbFileError err = gbFileError_None;
u8 const *file_data = file->tokenizer.start;
i32 prev_offset = 0;
i32 const end_offset = cast(i32)(file->tokenizer.end - file->tokenizer.start);
for_array(i, file->tokens) {
Token *token = &file->tokens[i];
if (token->flags & (TokenFlag_Remove|TokenFlag_Replace)) {
i32 offset = token->pos.offset;
for (Token const &token : file->tokens) {
if (token.flags & (TokenFlag_Remove|TokenFlag_Replace)) {
i32 offset = token.pos.offset;
i32 to_write = offset-prev_offset;
if (!gb_file_write(f, file_data+prev_offset, to_write)) {
return gbFileError_Invalid;
}
written += to_write;
prev_offset = token_pos_end(*token).offset;
prev_offset = token_pos_end(token).offset;
}
if (token->flags & TokenFlag_Replace) {
if (token->kind == Token_Ellipsis) {
if (token.flags & TokenFlag_Replace) {
if (token.kind == Token_Ellipsis) {
if (!gb_file_write(f, "..=", 3)) {
return gbFileError_Invalid;
}
@@ -2388,24 +2335,19 @@ gbFileError write_file_with_stripped_tokens(gbFile *f, AstFile *file, i64 *writt
return err;
}
int strip_semicolons(Parser *parser) {
gb_internal int strip_semicolons(Parser *parser) {
isize file_count = 0;
for_array(i, parser->packages) {
AstPackage *pkg = parser->packages[i];
for (AstPackage *pkg : parser->packages) {
file_count += pkg->files.count;
}
auto generated_files = array_make<StripSemicolonFile>(permanent_allocator(), 0, file_count);
for_array(i, parser->packages) {
AstPackage *pkg = parser->packages[i];
for_array(j, pkg->files) {
AstFile *file = pkg->files[j];
for (AstPackage *pkg : parser->packages) {
for (AstFile *file : pkg->files) {
bool nothing_to_change = true;
for_array(i, file->tokens) {
Token *token = &file->tokens[i];
if (token->flags) {
for (Token const &token : file->tokens) {
if (token.flags) {
nothing_to_change = false;
break;
}
@@ -2433,9 +2375,8 @@ int strip_semicolons(Parser *parser) {
isize generated_count = 0;
bool failed = false;
for_array(i, generated_files) {
auto *file = &generated_files[i];
char const *filename = cast(char const *)file->new_fullpath.text;
for (StripSemicolonFile &file : generated_files) {
char const *filename = cast(char const *)file.new_fullpath.text;
gbFileError err = gbFileError_None;
defer (if (err != gbFileError_None) {
failed = true;
@@ -2453,11 +2394,11 @@ int strip_semicolons(Parser *parser) {
defer (err = gb_file_truncate(&f, written));
debugf("Write file with stripped tokens: %s\n", filename);
err = write_file_with_stripped_tokens(&f, file->file, &written);
err = write_file_with_stripped_tokens(&f, file.file, &written);
if (err) {
break;
}
file->written = written;
file.written = written;
}
if (failed) {
@@ -2472,12 +2413,10 @@ int strip_semicolons(Parser *parser) {
isize overwritten_files = 0;
for_array(i, generated_files) {
auto *file = &generated_files[i];
char const *old_fullpath = cast(char const *)file->old_fullpath.text;
char const *old_fullpath_backup = cast(char const *)file->old_fullpath_backup.text;
char const *new_fullpath = cast(char const *)file->new_fullpath.text;
for (StripSemicolonFile const &file : generated_files) {
char const *old_fullpath = cast(char const *)file.old_fullpath.text;
char const *old_fullpath_backup = cast(char const *)file.old_fullpath_backup.text;
char const *new_fullpath = cast(char const *)file.new_fullpath.text;
debugf("Copy '%s' to '%s'\n", old_fullpath, old_fullpath_backup);
if (!gb_file_copy(old_fullpath, old_fullpath_backup, false)) {
@@ -2537,22 +2476,16 @@ int main(int arg_count, char const **arg_ptr) {
usage(make_string_c(arg_ptr[0]));
return 1;
}
virtual_memory_init();
timings_init(&global_timings, str_lit("Total Time"), 2048);
defer (timings_destroy(&global_timings));
MAIN_TIME_SECTION("initialization");
virtual_memory_init();
mutex_init(&fullpath_mutex);
mutex_init(&hash_exact_value_mutex);
mutex_init(&global_type_name_objc_metadata_mutex);
init_string_buffer_memory();
init_string_interner();
init_global_error_collector();
init_keyword_hash_table();
init_type_mutex();
if (!check_env()) {
return 1;
@@ -2563,9 +2496,9 @@ int main(int arg_count, char const **arg_ptr) {
add_library_collection(str_lit("core"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("core")));
add_library_collection(str_lit("vendor"), get_fullpath_relative(heap_allocator(), odin_root_dir(), str_lit("vendor")));
map_init(&build_context.defined_values, heap_allocator());
map_init(&build_context.defined_values);
build_context.extra_packages.allocator = heap_allocator();
string_set_init(&build_context.test_names, heap_allocator());
string_set_init(&build_context.test_names);
Array<String> args = setup_args(arg_count, arg_ptr);
@@ -2627,15 +2560,6 @@ int main(int arg_count, char const **arg_ptr) {
build_context.command_kind = Command_strip_semicolon;
build_context.no_output_files = true;
init_filename = args[2];
} else if (command == "query") {
if (args.count < 3) {
usage(args[0]);
return 1;
}
build_context.command_kind = Command_query;
build_context.no_output_files = true;
build_context.query_data_set_settings.ok = true;
init_filename = args[2];
} else if (command == "doc") {
if (args.count < 3) {
usage(args[0]);
@@ -2824,12 +2748,8 @@ int main(int arg_count, char const **arg_ptr) {
print_show_unused(checker);
}
if (build_context.query_data_set_settings.ok) {
generate_and_print_query_data(checker, &global_timings);
} else {
if (build_context.show_timings) {
show_timings(checker, &global_timings);
}
if (build_context.show_timings) {
show_timings(checker, &global_timings);
}
if (global_error_collector.count != 0) {
@@ -2844,19 +2764,19 @@ int main(int arg_count, char const **arg_ptr) {
if (!lb_init_generator(gen, checker)) {
return 1;
}
lb_generate_code(gen);
switch (build_context.build_mode) {
case BuildMode_Executable:
case BuildMode_DynamicLibrary:
i32 result = linker_stage(gen);
if (result) {
if (build_context.show_timings) {
show_timings(checker, &global_timings);
if (lb_generate_code(gen)) {
switch (build_context.build_mode) {
case BuildMode_Executable:
case BuildMode_DynamicLibrary:
i32 result = linker_stage(gen);
if (result) {
if (build_context.show_timings) {
show_timings(checker, &global_timings);
}
return result;
}
return result;
break;
}
break;
}
remove_temp_files(gen);
+20 -24
View File
@@ -45,7 +45,7 @@
//
// Here is the API you need to know about:
//
gb_global gbAllocator mc_allocator = heap_allocator();
gb_global gbAllocator mc_allocator = permanent_allocator();
struct Find_Result {
int windows_sdk_version; // Zero if no Windows SDK found.
@@ -58,50 +58,46 @@ struct Find_Result {
String vs_library_path;
};
String mc_wstring_to_string(wchar_t const *str) {
gb_internal String mc_wstring_to_string(wchar_t const *str) {
return string16_to_string(mc_allocator, make_string16_c(str));
}
String16 mc_string_to_wstring(String str) {
gb_internal String16 mc_string_to_wstring(String str) {
return string_to_string16(mc_allocator, str);
}
String mc_concat(String a, String b) {
gb_internal String mc_concat(String a, String b) {
return concatenate_strings(mc_allocator, a, b);
}
String mc_concat(String a, String b, String c) {
gb_internal String mc_concat(String a, String b, String c) {
return concatenate3_strings(mc_allocator, a, b, c);
}
String mc_concat(String a, String b, String c, String d) {
gb_internal String mc_concat(String a, String b, String c, String d) {
return concatenate4_strings(mc_allocator, a, b, c, d);
}
String mc_get_env(String key) {
gb_internal String mc_get_env(String key) {
char const * value = gb_get_env((char const *)key.text, mc_allocator);
return make_string_c(value);
}
void mc_free(String str) {
gb_internal void mc_free(String str) {
if (str.len) gb_free(mc_allocator, str.text);
}
void mc_free(String16 str) {
gb_internal void mc_free(String16 str) {
if (str.len) gb_free(mc_allocator, str.text);
}
void mc_free_all() {
gb_free_all(mc_allocator);
}
typedef struct _MC_Find_Data {
DWORD file_attributes;
String filename;
} MC_Find_Data;
HANDLE mc_find_first(String wildcard, MC_Find_Data *find_data) {
gb_internal HANDLE mc_find_first(String wildcard, MC_Find_Data *find_data) {
WIN32_FIND_DATAW _find_data;
String16 wildcard_wide = mc_string_to_wstring(wildcard);
@@ -115,7 +111,7 @@ HANDLE mc_find_first(String wildcard, MC_Find_Data *find_data) {
return handle;
}
bool mc_find_next(HANDLE handle, MC_Find_Data *find_data) {
gb_internal bool mc_find_next(HANDLE handle, MC_Find_Data *find_data) {
WIN32_FIND_DATAW _find_data;
bool success = !!FindNextFileW(handle, &_find_data);
@@ -124,7 +120,7 @@ bool mc_find_next(HANDLE handle, MC_Find_Data *find_data) {
return success;
}
void mc_find_close(HANDLE handle) {
gb_internal void mc_find_close(HANDLE handle) {
FindClose(handle);
}
@@ -216,7 +212,7 @@ struct Version_Data {
};
typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data *data);
bool mc_visit_files(String dir_name, Version_Data *data, MC_Visit_Proc proc) {
gb_internal bool mc_visit_files(String dir_name, Version_Data *data, MC_Visit_Proc proc) {
// Visit everything in one folder (non-recursively). If it's a directory
// that doesn't start with ".", call the visit proc on it. The visit proc
@@ -246,7 +242,7 @@ bool mc_visit_files(String dir_name, Version_Data *data, MC_Visit_Proc proc) {
return true;
}
String find_windows_kit_root(HKEY key, String const version) {
gb_internal String find_windows_kit_root(HKEY key, String const version) {
// Given a key to an already opened registry entry,
// get the value stored under the 'version' subkey.
// If that's not the right terminology, hey, I never do registry stuff.
@@ -275,7 +271,7 @@ String find_windows_kit_root(HKEY key, String const version) {
return value;
}
void win10_best(String short_name, String full_name, Version_Data *data) {
gb_internal void win10_best(String short_name, String full_name, Version_Data *data) {
// Find the Windows 10 subdirectory with the highest version number.
int i0, i1, i2, i3;
@@ -307,7 +303,7 @@ void win10_best(String short_name, String full_name, Version_Data *data) {
}
}
void find_windows_kit_paths(Find_Result *result) {
gb_internal void find_windows_kit_paths(Find_Result *result) {
bool sdk_found = false;
HKEY main_key;
@@ -355,7 +351,7 @@ void find_windows_kit_paths(Find_Result *result) {
}
}
bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *result) {
gb_internal bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *result) {
// The name of this procedure is kind of cryptic. Its purpose is
// to fight through Microsoft craziness. The things that the fine
// Visual Studio team want you to do, JUST TO FIND A SINGLE FOLDER
@@ -519,7 +515,7 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *res
// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both
// official and portable installations (like mmozeiko's portable msvc script).
void find_windows_kit_paths_from_env_vars(Find_Result *result) {
gb_internal void find_windows_kit_paths_from_env_vars(Find_Result *result) {
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
return;
}
@@ -669,7 +665,7 @@ void find_windows_kit_paths_from_env_vars(Find_Result *result) {
// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both
// official and portable installations (like mmozeiko's portable msvc script). This will only use
// the first paths it finds, and won't overwrite any values that `result` already has.
void find_visual_studio_paths_from_env_vars(Find_Result *result) {
gb_internal void find_visual_studio_paths_from_env_vars(Find_Result *result) {
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
return;
}
@@ -756,7 +752,7 @@ void find_visual_studio_paths_from_env_vars(Find_Result *result) {
}
}
Find_Result find_visual_studio_and_windows_sdk() {
gb_internal Find_Result find_visual_studio_and_windows_sdk() {
Find_Result r = {};
find_windows_kit_paths(&r);
find_visual_studio_by_fighting_through_microsoft_craziness(&r);
+449 -492
View File
File diff suppressed because it is too large Load Diff
+59 -51
View File
@@ -62,15 +62,6 @@ enum PackageKind {
Package_Init,
};
struct ImportedPackage {
PackageKind kind;
String path;
String rel_path;
TokenPos pos; // import
isize index;
};
struct ImportedFile {
AstPackage *pkg;
FileInfo fi;
@@ -99,7 +90,11 @@ struct AstFile {
Scope * scope;
Ast * pkg_decl;
String fullpath;
String filename;
String directory;
Tokenizer tokenizer;
Array<Token> tokens;
isize curr_token_index;
@@ -109,6 +104,7 @@ struct AstFile {
Token package_token;
String package_name;
// >= 0: In Expression
// < 0: In Control Clause
// NOTE(bill): Used to prevent type literals in control clauses
@@ -136,9 +132,8 @@ struct AstFile {
CommentGroup *docs; // current docs
Array<CommentGroup *> comments; // All the comments!
// TODO(bill): make this a basic queue as it does not require
// any multiple thread capabilities
MPMCQueue<Ast *> delayed_decls_queues[AstDelayQueue_COUNT];
// This is effectively a queue but does not require any multi-threading capabilities
Array<Ast *> delayed_decls_queues[AstDelayQueue_COUNT];
#define PARSER_MAX_FIX_COUNT 6
isize fix_count;
@@ -177,6 +172,12 @@ struct AstPackage {
bool is_single_file;
isize order;
BlockingMutex files_mutex;
BlockingMutex foreign_files_mutex;
BlockingMutex type_and_value_mutex;
BlockingMutex name_mutex;
// NOTE(bill): This must be a MPMCQueue
MPMCQueue<AstPackageExportedEntity> exported_entity_queue;
// NOTE(bill): Created/set in checker
@@ -186,20 +187,33 @@ struct AstPackage {
};
struct ParseFileErrorNode {
ParseFileErrorNode *next, *prev;
ParseFileError err;
};
struct Parser {
String init_fullpath;
StringSet imported_files; // fullpath
Array<AstPackage *> packages;
Array<ImportedPackage> package_imports;
isize file_to_process_count;
isize total_token_count;
isize total_line_count;
BlockingMutex wait_mutex;
BlockingMutex import_mutex;
BlockingMutex file_add_mutex;
BlockingMutex file_decl_mutex;
BlockingMutex packages_mutex;
MPMCQueue<ParseFileError> file_error_queue;
String init_fullpath;
StringSet imported_files; // fullpath
BlockingMutex imported_files_mutex;
Array<AstPackage *> packages;
BlockingMutex packages_mutex;
std::atomic<isize> file_to_process_count;
std::atomic<isize> total_token_count;
std::atomic<isize> total_line_count;
// TODO(bill): What should this mutex be per?
// * Parser
// * Package
// * File
BlockingMutex file_decl_mutex;
BlockingMutex file_error_mutex;
ParseFileErrorNode * file_error_head;
ParseFileErrorNode * file_error_tail;
};
struct ParserWorkerData {
@@ -258,7 +272,7 @@ enum ProcCallingConvention : i32 {
ProcCC_ForeignBlockDefault = -1,
};
char const *proc_calling_convention_strings[ProcCC_MAX] = {
gb_global char const *proc_calling_convention_strings[ProcCC_MAX] = {
"",
"odin",
"contextless",
@@ -272,7 +286,7 @@ char const *proc_calling_convention_strings[ProcCC_MAX] = {
"sysv",
};
ProcCallingConvention default_calling_convention(void) {
gb_internal ProcCallingConvention default_calling_convention(void) {
return ProcCC_Odin;
}
@@ -299,7 +313,7 @@ enum FieldFlag : u32 {
FieldFlag_using = 1<<1,
FieldFlag_no_alias = 1<<2,
FieldFlag_c_vararg = 1<<3,
FieldFlag_auto_cast = 1<<4,
FieldFlag_const = 1<<5,
FieldFlag_any_int = 1<<6,
FieldFlag_subtype = 1<<7,
@@ -314,7 +328,7 @@ enum FieldFlag : u32 {
FieldFlag_Invalid = 1u<<31,
// Parameter List Restrictions
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr,
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_const|FieldFlag_any_int|FieldFlag_by_ptr,
FieldFlag_Struct = FieldFlag_using|FieldFlag_subtype|FieldFlag_Tags,
};
@@ -332,7 +346,7 @@ enum InlineAsmDialectKind : u8 {
InlineAsmDialect_COUNT,
};
char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
gb_global char const *inline_asm_dialect_strings[InlineAsmDialect_COUNT] = {
"",
"att",
"intel",
@@ -457,11 +471,6 @@ AST_KIND(_StmtBegin, "", bool) \
AST_KIND(BadStmt, "bad statement", struct { Token begin, end; }) \
AST_KIND(EmptyStmt, "empty statement", struct { Token token; }) \
AST_KIND(ExprStmt, "expression statement", struct { Ast *expr; } ) \
AST_KIND(TagStmt, "tag statement", struct { \
Token token; \
Token name; \
Ast * stmt; \
}) \
AST_KIND(AssignStmt, "assign statement", struct { \
Token op; \
Slice<Ast *> lhs, rhs; \
@@ -729,7 +738,7 @@ enum AstKind : u16 {
Ast_COUNT,
};
String const ast_strings[] = {
gb_global String const ast_strings[] = {
{cast(u8 *)"invalid node", gb_size_of("invalid node")},
#define AST_KIND(_kind_name_, name, ...) {cast(u8 *)name, gb_size_of(name)-1},
AST_KINDS
@@ -742,7 +751,7 @@ String const ast_strings[] = {
#undef AST_KIND
isize const ast_variant_sizes[] = {
gb_global isize const ast_variant_sizes[] = {
0,
#define AST_KIND(_kind_name_, name, ...) gb_size_of(GB_JOIN2(Ast, _kind_name_)),
AST_KINDS
@@ -754,7 +763,7 @@ struct AstCommonStuff {
u8 state_flags;
u8 viral_state_flags;
i32 file_id;
TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size
TypeAndValue tav; // NOTE(bill): Making this a pointer is slower
};
struct Ast {
@@ -762,7 +771,7 @@ struct Ast {
u8 state_flags;
u8 viral_state_flags;
i32 file_id;
TypeAndValue tav; // TODO(bill): Make this a pointer to minimize 'Ast' size
TypeAndValue tav; // NOTE(bill): Making this a pointer is slower
// IMPORTANT NOTE(bill): This must be at the end since the AST is allocated to be size of the variant
union {
@@ -793,33 +802,32 @@ struct Ast {
#endif
gb_inline bool is_ast_expr(Ast *node) {
gb_internal gb_inline bool is_ast_expr(Ast *node) {
return gb_is_between(node->kind, Ast__ExprBegin+1, Ast__ExprEnd-1);
}
gb_inline bool is_ast_stmt(Ast *node) {
gb_internal gb_inline bool is_ast_stmt(Ast *node) {
return gb_is_between(node->kind, Ast__StmtBegin+1, Ast__StmtEnd-1);
}
gb_inline bool is_ast_complex_stmt(Ast *node) {
gb_internal gb_inline bool is_ast_complex_stmt(Ast *node) {
return gb_is_between(node->kind, Ast__ComplexStmtBegin+1, Ast__ComplexStmtEnd-1);
}
gb_inline bool is_ast_decl(Ast *node) {
gb_internal gb_inline bool is_ast_decl(Ast *node) {
return gb_is_between(node->kind, Ast__DeclBegin+1, Ast__DeclEnd-1);
}
gb_inline bool is_ast_type(Ast *node) {
gb_internal gb_inline bool is_ast_type(Ast *node) {
return gb_is_between(node->kind, Ast__TypeBegin+1, Ast__TypeEnd-1);
}
gb_inline bool is_ast_when_stmt(Ast *node) {
gb_internal gb_inline bool is_ast_when_stmt(Ast *node) {
return node->kind == Ast_WhenStmt;
}
gb_global gb_thread_local Arena global_thread_local_ast_arena = {};
gbAllocator ast_allocator(AstFile *f) {
Arena *arena = &global_thread_local_ast_arena;
return arena_allocator(arena);
gb_internal gb_inline gbAllocator ast_allocator(AstFile *f) {
return arena_allocator(&global_thread_local_ast_arena);
}
Ast *alloc_ast_node(AstFile *f, AstKind kind);
gb_internal Ast *alloc_ast_node(AstFile *f, AstKind kind);
gbString expr_to_string(Ast *expression);
bool allow_field_separator(AstFile *f);
gb_internal gbString expr_to_string(Ast *expression);
gb_internal bool allow_field_separator(AstFile *f);
+2 -4
View File
@@ -1,4 +1,4 @@
Token ast_token(Ast *node) {
gb_internal Token ast_token(Ast *node) {
switch (node->kind) {
case Ast_Ident: return node->Ident.token;
case Ast_Implicit: return node->Implicit;
@@ -53,7 +53,6 @@ Token ast_token(Ast *node) {
case Ast_BadStmt: return node->BadStmt.begin;
case Ast_EmptyStmt: return node->EmptyStmt.token;
case Ast_ExprStmt: return ast_token(node->ExprStmt.expr);
case Ast_TagStmt: return node->TagStmt.token;
case Ast_AssignStmt: return node->AssignStmt.op;
case Ast_BlockStmt: return node->BlockStmt.open;
case Ast_IfStmt: return node->IfStmt.token;
@@ -197,7 +196,6 @@ Token ast_end_token(Ast *node) {
case Ast_BadStmt: return node->BadStmt.end;
case Ast_EmptyStmt: return node->EmptyStmt.token;
case Ast_ExprStmt: return ast_end_token(node->ExprStmt.expr);
case Ast_TagStmt: return ast_end_token(node->TagStmt.stmt);
case Ast_AssignStmt:
if (node->AssignStmt.rhs.count > 0) {
return ast_end_token(node->AssignStmt.rhs[node->AssignStmt.rhs.count-1]);
@@ -360,6 +358,6 @@ Token ast_end_token(Ast *node) {
return empty_token;
}
TokenPos ast_end_pos(Ast *node) {
gb_internal TokenPos ast_end_pos(Ast *node) {
return token_pos_end(ast_end_token(node));
}
+26 -22
View File
@@ -1,7 +1,10 @@
/*
Path handling utilities.
*/
String remove_extension_from_path(String const &s) {
gb_internal String remove_extension_from_path(String const &s) {
if (s.len != 0 && s.text[s.len-1] == '.') {
return s;
}
for (isize i = s.len-1; i >= 0; i--) {
if (s[i] == '.') {
return substring(s, 0, i);
@@ -10,7 +13,7 @@ String remove_extension_from_path(String const &s) {
return s;
}
String remove_directory_from_path(String const &s) {
gb_internal String remove_directory_from_path(String const &s) {
isize len = 0;
for (isize i = s.len-1; i >= 0; i--) {
if (s[i] == '/' ||
@@ -22,9 +25,9 @@ String remove_directory_from_path(String const &s) {
return substring(s, s.len-len, s.len);
}
bool path_is_directory(String path);
gb_internal bool path_is_directory(String path);
String directory_from_path(String const &s) {
gb_internal String directory_from_path(String const &s) {
if (path_is_directory(s)) {
return s;
}
@@ -43,7 +46,7 @@ String directory_from_path(String const &s) {
}
#if defined(GB_SYSTEM_WINDOWS)
bool path_is_directory(String path) {
gb_internal bool path_is_directory(String path) {
gbAllocator a = heap_allocator();
String16 wstr = string_to_string16(a, path);
defer (gb_free(a, wstr.text));
@@ -55,7 +58,7 @@ String directory_from_path(String const &s) {
}
#else
bool path_is_directory(String path) {
gb_internal bool path_is_directory(String path) {
gbAllocator a = heap_allocator();
char *copy = cast(char *)copy_string(a, path).text;
defer (gb_free(a, copy));
@@ -69,7 +72,7 @@ String directory_from_path(String const &s) {
#endif
String path_to_full_path(gbAllocator a, String path) {
gb_internal String path_to_full_path(gbAllocator a, String path) {
gbAllocator ha = heap_allocator();
char *path_c = gb_alloc_str_len(ha, cast(char *)path.text, path.len);
defer (gb_free(ha, path_c));
@@ -93,7 +96,7 @@ struct Path {
};
// NOTE(Jeroen): Naively turns a Path into a string.
String path_to_string(gbAllocator a, Path path) {
gb_internal String path_to_string(gbAllocator a, Path path) {
if (path.basename.len + path.name.len + path.ext.len == 0) {
return make_string(nullptr, 0);
}
@@ -107,7 +110,9 @@ String path_to_string(gbAllocator a, Path path) {
isize i = 0;
gb_memmove(str+i, path.basename.text, path.basename.len); i += path.basename.len;
gb_memmove(str+i, "/", 1); i += 1;
gb_memmove(str+i, path.name.text, path.name.len); i += path.name.len;
if (path.ext.len > 0) {
gb_memmove(str+i, ".", 1); i += 1;
@@ -121,7 +126,7 @@ String path_to_string(gbAllocator a, Path path) {
}
// NOTE(Jeroen): Naively turns a Path into a string, then normalizes it using `path_to_full_path`.
String path_to_full_path(gbAllocator a, Path path) {
gb_internal String path_to_full_path(gbAllocator a, Path path) {
String temp = path_to_string(heap_allocator(), path);
defer (gb_free(heap_allocator(), temp.text));
@@ -130,7 +135,7 @@ String path_to_full_path(gbAllocator a, Path path) {
// NOTE(Jeroen): Takes a path like "odin" or "W:\Odin", turns it into a full path,
// and then breaks it into its components to make a Path.
Path path_from_string(gbAllocator a, String const &path) {
gb_internal Path path_from_string(gbAllocator a, String const &path) {
Path res = {};
if (path.len == 0) return res;
@@ -150,6 +155,7 @@ Path path_from_string(gbAllocator a, String const &path) {
return res;
}
// Note(Dragos): Is the copy_string required if it's a substring?
isize name_start = (res.basename.len > 0) ? res.basename.len + 1 : res.basename.len;
res.name = substring(fullpath, name_start, fullpath.len);
res.name = remove_extension_from_path(res.name);
@@ -161,7 +167,7 @@ Path path_from_string(gbAllocator a, String const &path) {
}
// NOTE(Jeroen): Takes a path String and returns the last path element.
String last_path_element(String const &path) {
gb_internal String last_path_element(String const &path) {
isize count = 0;
u8 * start = (u8 *)(&path.text[path.len - 1]);
for (isize length = path.len; length > 0 && path.text[length - 1] != '/'; length--) {
@@ -177,7 +183,7 @@ String last_path_element(String const &path) {
return STR_LIT("");
}
bool path_is_directory(Path path) {
gb_internal bool path_is_directory(Path path) {
String path_string = path_to_full_path(heap_allocator(), path);
defer (gb_free(heap_allocator(), path_string.text));
@@ -204,7 +210,7 @@ enum ReadDirectoryError {
ReadDirectory_COUNT,
};
i64 get_file_size(String path) {
gb_internal i64 get_file_size(String path) {
char *c_str = alloc_cstring(heap_allocator(), path);
defer (gb_free(heap_allocator(), c_str));
@@ -219,10 +225,9 @@ i64 get_file_size(String path) {
#if defined(GB_SYSTEM_WINDOWS)
ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
GB_ASSERT(fi != nullptr);
gbAllocator a = heap_allocator();
while (path.len > 0) {
Rune end = path[path.len-1];
@@ -239,9 +244,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
return ReadDirectory_InvalidPath;
}
{
char *c_str = alloc_cstring(a, path);
defer (gb_free(a, c_str));
char *c_str = alloc_cstring(temporary_allocator(), path);
gbFile f = {};
gbFileError file_err = gb_file_open(&f, c_str);
defer (gb_file_close(&f));
@@ -258,6 +261,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
}
gbAllocator a = heap_allocator();
char *new_path = gb_alloc_array(a, char, path.len+3);
defer (gb_free(a, new_path));
@@ -280,8 +284,8 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
do {
wchar_t *filename_w = file_data.cFileName;
i64 size = cast(i64)file_data.nFileSizeLow;
size |= (cast(i64)file_data.nFileSizeHigh) << 32;
u64 size = cast(u64)file_data.nFileSizeLow;
size |= (cast(u64)file_data.nFileSizeHigh) << 32;
String name = string16_to_string(a, make_string16_c(filename_w));
if (name == "." || name == "..") {
gb_free(a, name.text);
@@ -299,7 +303,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
FileInfo info = {};
info.name = name;
info.fullpath = path_to_full_path(a, filepath);
info.size = size;
info.size = cast(i64)size;
info.is_dir = (file_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0;
array_add(fi, info);
} while (FindNextFileW(find_file, &file_data));
@@ -314,7 +318,7 @@ ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
#include <dirent.h>
ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
gb_internal ReadDirectoryError read_directory(String path, Array<FileInfo> *fi) {
GB_ASSERT(fi != nullptr);
gbAllocator a = heap_allocator();
+7 -7
View File
@@ -7,7 +7,7 @@ struct PriorityQueue {
};
template <typename T>
bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
gb_internal bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
// O(n log n)
isize i = i0;
isize j, j1, j2;
@@ -29,7 +29,7 @@ bool priority_queue_shift_down(PriorityQueue<T> *pq, isize i0, isize n) {
}
template <typename T>
void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
gb_internal void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
while (0 <= j && j < pq->queue.count) {
isize i = (j-1)/2;
if (i == j || pq->cmp(&pq->queue[0], j, i) >= 0) {
@@ -43,20 +43,20 @@ void priority_queue_shift_up(PriorityQueue<T> *pq, isize j) {
// NOTE(bill): When an element at index `i0` has changed its value, this will fix the
// the heap ordering. This using a basic "heapsort" with shift up and a shift down parts.
template <typename T>
void priority_queue_fix(PriorityQueue<T> *pq, isize i) {
gb_internal void priority_queue_fix(PriorityQueue<T> *pq, isize i) {
if (!priority_queue_shift_down(pq, i, pq->queue.count)) {
priority_queue_shift_up(pq, i);
}
}
template <typename T>
void priority_queue_push(PriorityQueue<T> *pq, T const &value) {
gb_internal void priority_queue_push(PriorityQueue<T> *pq, T const &value) {
array_add(&pq->queue, value);
priority_queue_shift_up(pq, pq->queue.count-1);
}
template <typename T>
T priority_queue_pop(PriorityQueue<T> *pq) {
gb_internal T priority_queue_pop(PriorityQueue<T> *pq) {
GB_ASSERT(pq->queue.count > 0);
isize n = pq->queue.count - 1;
@@ -67,7 +67,7 @@ T priority_queue_pop(PriorityQueue<T> *pq) {
template <typename T>
T priority_queue_remove(PriorityQueue<T> *pq, isize i) {
gb_internal T priority_queue_remove(PriorityQueue<T> *pq, isize i) {
GB_ASSERT(0 <= i && i < pq->queue.count);
isize n = pq->queue.count - 1;
if (n != i) {
@@ -80,7 +80,7 @@ T priority_queue_remove(PriorityQueue<T> *pq, isize i) {
template <typename T>
PriorityQueue<T> priority_queue_create(Array<T> queue,
gb_internal PriorityQueue<T> priority_queue_create(Array<T> queue,
int (* cmp) (T *q, isize i, isize j),
void (* swap)(T *q, isize i, isize j)) {
PriorityQueue<T> pq = {};
+224 -103
View File
@@ -2,6 +2,13 @@
typedef u32 MapIndex;
enum {
MAP_CACHE_LINE_SIZE_POW = 6,
MAP_CACHE_LINE_SIZE = 1<<MAP_CACHE_LINE_SIZE_POW,
MAP_CACHE_LINE_MASK = MAP_CACHE_LINE_SIZE-1,
};
struct MapFindResult {
MapIndex hash_index;
MapIndex entry_prev;
@@ -21,12 +28,16 @@ struct PtrMapEntry {
template <typename K, typename V>
struct PtrMap {
Slice<MapIndex> hashes;
Array<PtrMapEntry<K, V> > entries;
MapIndex * hashes;
usize hashes_count;
PtrMapEntry<K, V> *entries;
u32 count;
u32 entries_capacity;
};
u32 ptr_map_hash_key(uintptr key) {
gb_internal gb_inline u32 ptr_map_hash_key(uintptr key) {
u32 res;
#if defined(GB_ARCH_64_BIT)
key = (~key) + (key << 21);
key = key ^ (key >> 24);
@@ -34,80 +45,96 @@ u32 ptr_map_hash_key(uintptr key) {
key = key ^ (key >> 14);
key = (key + (key << 2)) + (key << 4);
key = key ^ (key << 28);
return cast(u32)key;
res = cast(u32)key;
#elif defined(GB_ARCH_32_BIT)
u32 state = ((u32)key) * 747796405u + 2891336453u;
u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
res = (word >> 22u) ^ word;
#endif
return res;
}
u32 ptr_map_hash_key(void const *key) {
gb_internal gb_inline u32 ptr_map_hash_key(void const *key) {
return ptr_map_hash_key((uintptr)key);
}
template <typename K, typename V> void map_init (PtrMap<K, V> *h, gbAllocator a, isize capacity = 16);
template <typename K, typename V> void map_destroy (PtrMap<K, V> *h);
template <typename K, typename V> V * map_get (PtrMap<K, V> *h, K key);
template <typename K, typename V> void map_set (PtrMap<K, V> *h, K key, V const &value);
template <typename K, typename V> void map_remove (PtrMap<K, V> *h, K key);
template <typename K, typename V> void map_clear (PtrMap<K, V> *h);
template <typename K, typename V> void map_grow (PtrMap<K, V> *h);
template <typename K, typename V> void map_rehash (PtrMap<K, V> *h, isize new_count);
template <typename K, typename V> void map_reserve (PtrMap<K, V> *h, isize cap);
template <typename K, typename V> gb_internal void map_init (PtrMap<K, V> *h, isize capacity = 16);
template <typename K, typename V> gb_internal void map_destroy (PtrMap<K, V> *h);
template <typename K, typename V> gb_internal V * map_get (PtrMap<K, V> *h, K key);
template <typename K, typename V> gb_internal void map_set (PtrMap<K, V> *h, K key, V const &value);
template <typename K, typename V> gb_internal bool map_set_if_not_previously_exists(PtrMap<K, V> *h, K key, V const &value); // returns true if it previously existed
template <typename K, typename V> gb_internal void map_remove (PtrMap<K, V> *h, K key);
template <typename K, typename V> gb_internal void map_clear (PtrMap<K, V> *h);
template <typename K, typename V> gb_internal void map_grow (PtrMap<K, V> *h);
template <typename K, typename V> gb_internal void map_rehash (PtrMap<K, V> *h, isize new_count);
template <typename K, typename V> gb_internal void map_reserve (PtrMap<K, V> *h, isize cap);
#if PTR_MAP_ENABLE_MULTI_MAP
// Mutlivalued map procedure
template <typename K, typename V> PtrMapEntry<K, V> * multi_map_find_first(PtrMap<K, V> *h, K key);
template <typename K, typename V> PtrMapEntry<K, V> * multi_map_find_next (PtrMap<K, V> *h, PtrMapEntry<K, V> *e);
template <typename K, typename V> gb_internal PtrMapEntry<K, V> * multi_map_find_first(PtrMap<K, V> *h, K key);
template <typename K, typename V> gb_internal PtrMapEntry<K, V> * multi_map_find_next (PtrMap<K, V> *h, PtrMapEntry<K, V> *e);
template <typename K, typename V> isize multi_map_count (PtrMap<K, V> *h, K key);
template <typename K, typename V> void multi_map_get_all (PtrMap<K, V> *h, K key, V *items);
template <typename K, typename V> void multi_map_insert (PtrMap<K, V> *h, K key, V const &value);
template <typename K, typename V> void multi_map_remove (PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e);
template <typename K, typename V> void multi_map_remove_all(PtrMap<K, V> *h, K key);
template <typename K, typename V> gb_internal isize multi_map_count (PtrMap<K, V> *h, K key);
template <typename K, typename V> gb_internal void multi_map_get_all (PtrMap<K, V> *h, K key, V *items);
template <typename K, typename V> gb_internal void multi_map_insert (PtrMap<K, V> *h, K key, V const &value);
template <typename K, typename V> gb_internal void multi_map_remove (PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e);
template <typename K, typename V> gb_internal void multi_map_remove_all(PtrMap<K, V> *h, K key);
#endif
template <typename K, typename V>
gb_inline void map_init(PtrMap<K, V> *h, gbAllocator a, isize capacity) {
capacity = next_pow2_isize(capacity);
slice_init(&h->hashes, a, capacity);
array_init(&h->entries, a, 0, capacity);
for (isize i = 0; i < capacity; i++) {
h->hashes.data[i] = MAP_SENTINEL;
}
gb_internal gbAllocator map_allocator(void) {
return heap_allocator();
}
template <typename K, typename V>
gb_inline void map_destroy(PtrMap<K, V> *h) {
slice_free(&h->hashes, h->entries.allocator);
array_free(&h->entries);
gb_internal gb_inline void map_init(PtrMap<K, V> *h, isize capacity) {
capacity = next_pow2_isize(capacity);
map_reserve(h, capacity);
}
template <typename K, typename V>
gb_internal gb_inline void map_destroy(PtrMap<K, V> *h) {
gbAllocator a = map_allocator();
gb_free(a, h->hashes);
gb_free(a, h->entries);
}
template <typename K, typename V>
gb_internal void map__resize_hashes(PtrMap<K, V> *h, usize count) {
h->hashes_count = cast(u32)resize_array_raw(&h->hashes, map_allocator(), h->hashes_count, count, MAP_CACHE_LINE_SIZE);
}
template <typename K, typename V>
gb_internal void map__reserve_entries(PtrMap<K, V> *h, usize capacity) {
h->entries_capacity = cast(u32)resize_array_raw(&h->entries, map_allocator(), h->entries_capacity, capacity, MAP_CACHE_LINE_SIZE);
}
template <typename K, typename V>
gb_internal MapIndex map__add_entry(PtrMap<K, V> *h, K key) {
PtrMapEntry<K, V> e = {};
e.key = key;
e.next = MAP_SENTINEL;
array_add(&h->entries, e);
return cast(MapIndex)(h->entries.count-1);
map__reserve_entries(h, h->count+1);
h->entries[h->count++] = e;
return cast(MapIndex)(h->count-1);
}
template <typename K, typename V>
gb_internal MapFindResult map__find(PtrMap<K, V> *h, K key) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (h->hashes.count == 0) {
if (h->hashes_count == 0) {
return fr;
}
u32 hash = ptr_map_hash_key(key);
fr.hash_index = cast(MapIndex)(hash & (h->hashes.count-1));
fr.entry_index = h->hashes.data[fr.hash_index];
fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
fr.entry_index = h->hashes[fr.hash_index];
while (fr.entry_index != MAP_SENTINEL) {
if (h->entries.data[fr.entry_index].key == key) {
auto *entry = &h->entries[fr.entry_index];
if (entry->key == key) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.data[fr.entry_index].next;
fr.entry_index = entry->next;
}
return fr;
}
@@ -115,41 +142,41 @@ gb_internal MapFindResult map__find(PtrMap<K, V> *h, K key) {
template <typename K, typename V>
gb_internal MapFindResult map__find_from_entry(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (h->hashes.count == 0) {
if (h->hashes_count == 0) {
return fr;
}
u32 hash = ptr_map_hash_key(e->key);
fr.hash_index = cast(MapIndex)(hash & (h->hashes.count-1));
fr.entry_index = h->hashes.data[fr.hash_index];
fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
fr.entry_index = h->hashes[fr.hash_index];
while (fr.entry_index != MAP_SENTINEL) {
if (&h->entries.data[fr.entry_index] == e) {
if (&h->entries[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = h->entries.data[fr.entry_index].next;
fr.entry_index = h->entries[fr.entry_index].next;
}
return fr;
}
template <typename K, typename V>
gb_internal b32 map__full(PtrMap<K, V> *h) {
return 0.75f * h->hashes.count <= h->entries.count;
return 0.75f * h->hashes_count <= h->count;
}
template <typename K, typename V>
gb_inline void map_grow(PtrMap<K, V> *h) {
isize new_count = gb_max(h->hashes.count<<1, 16);
gb_internal gb_inline void map_grow(PtrMap<K, V> *h) {
isize new_count = gb_max(h->hashes_count<<1, 16);
map_rehash(h, new_count);
}
template <typename K, typename V>
void map_reset_entries(PtrMap<K, V> *h) {
for (isize i = 0; i < h->hashes.count; i++) {
h->hashes.data[i] = MAP_SENTINEL;
gb_internal void map_reset_entries(PtrMap<K, V> *h) {
for (usize i = 0; i < h->hashes_count; i++) {
h->hashes[i] = MAP_SENTINEL;
}
for (isize i = 0; i < h->entries.count; i++) {
for (usize i = 0; i < h->count; i++) {
MapFindResult fr;
PtrMapEntry<K, V> *e = &h->entries.data[i];
PtrMapEntry<K, V> *e = &h->entries[i];
e->next = MAP_SENTINEL;
fr = map__find_from_entry(h, e);
if (fr.entry_prev == MAP_SENTINEL) {
@@ -161,42 +188,88 @@ void map_reset_entries(PtrMap<K, V> *h) {
}
template <typename K, typename V>
void map_reserve(PtrMap<K, V> *h, isize cap) {
array_reserve(&h->entries, cap);
if (h->entries.count*2 < h->hashes.count) {
gb_internal void map_reserve(PtrMap<K, V> *h, isize cap) {
if (h->count*2 < h->hashes_count) {
return;
}
slice_resize(&h->hashes, h->entries.allocator, cap*2);
map__reserve_entries(h, cap);
map__resize_hashes(h, cap*2);
map_reset_entries(h);
}
template <typename K, typename V>
void map_rehash(PtrMap<K, V> *h, isize new_count) {
gb_internal void map_rehash(PtrMap<K, V> *h, isize new_count) {
map_reserve(h, new_count);
}
template <typename K, typename V>
V *map_get(PtrMap<K, V> *h, K key) {
MapIndex index = map__find(h, key).entry_index;
if (index != MAP_SENTINEL) {
return &h->entries.data[index].value;
gb_internal V *map_get(PtrMap<K, V> *h, K key) {
MapIndex hash_index = MAP_SENTINEL;
MapIndex entry_prev = MAP_SENTINEL;
MapIndex entry_index = MAP_SENTINEL;
if (h->hashes_count != 0) {
u32 hash = ptr_map_hash_key(key);
hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
entry_index = h->hashes[hash_index];
while (entry_index != MAP_SENTINEL) {
auto *entry = &h->entries[entry_index];
if (entry->key == key) {
return &entry->value;
}
entry_prev = entry_index;
entry_index = entry->next;
}
}
return nullptr;
}
template <typename K, typename V>
gb_internal V *map_try_get(PtrMap<K, V> *h, K key, MapFindResult *fr_) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (h->hashes_count != 0) {
u32 hash = ptr_map_hash_key(key);
fr.hash_index = cast(MapIndex)(hash & (h->hashes_count-1));
fr.entry_index = h->hashes[fr.hash_index];
while (fr.entry_index != MAP_SENTINEL) {
auto *entry = &h->entries[fr.entry_index];
if (entry->key == key) {
return &entry->value;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = entry->next;
}
}
if (h->hashes_count == 0 || map__full(h)) {
map_grow(h);
}
if (fr_) *fr_ = fr;
return nullptr;
}
template <typename K, typename V>
V &map_must_get(PtrMap<K, V> *h, K key) {
MapIndex index = map__find(h, key).entry_index;
GB_ASSERT(index != MAP_SENTINEL);
return h->entries.data[index].value;
gb_internal void map_set_internal_from_try_get(PtrMap<K, V> *h, K key, V const &value, MapFindResult const &fr) {
MapIndex index = map__add_entry(h, key);
if (fr.entry_prev != MAP_SENTINEL) {
h->entries[fr.entry_prev].next = index;
} else {
h->hashes[fr.hash_index] = index;
}
h->entries[index].value = value;
}
template <typename K, typename V>
void map_set(PtrMap<K, V> *h, K key, V const &value) {
gb_internal V &map_must_get(PtrMap<K, V> *h, K key) {
V *ptr = map_get(h, key);
GB_ASSERT(ptr != nullptr);
return *ptr;
}
template <typename K, typename V>
gb_internal void map_set(PtrMap<K, V> *h, K key, V const &value) {
MapIndex index;
MapFindResult fr;
if (h->hashes.count == 0) {
if (h->hashes_count == 0) {
map_grow(h);
}
fr = map__find(h, key);
@@ -205,44 +278,71 @@ void map_set(PtrMap<K, V> *h, K key, V const &value) {
} else {
index = map__add_entry(h, key);
if (fr.entry_prev != MAP_SENTINEL) {
h->entries.data[fr.entry_prev].next = index;
h->entries[fr.entry_prev].next = index;
} else {
h->hashes.data[fr.hash_index] = index;
h->hashes[fr.hash_index] = index;
}
}
h->entries.data[index].value = value;
h->entries[index].value = value;
if (map__full(h)) {
map_grow(h);
}
}
// returns true if it previously existed
template <typename K, typename V>
gb_internal bool map_set_if_not_previously_exists(PtrMap<K, V> *h, K key, V const &value) {
MapIndex index;
MapFindResult fr;
if (h->hashes_count == 0) {
map_grow(h);
}
fr = map__find(h, key);
if (fr.entry_index != MAP_SENTINEL) {
return true;
} else {
index = map__add_entry(h, key);
if (fr.entry_prev != MAP_SENTINEL) {
h->entries[fr.entry_prev].next = index;
} else {
h->hashes[fr.hash_index] = index;
}
}
h->entries[index].value = value;
if (map__full(h)) {
map_grow(h);
}
return false;
}
template <typename K, typename V>
void map__erase(PtrMap<K, V> *h, MapFindResult const &fr) {
gb_internal void map__erase(PtrMap<K, V> *h, MapFindResult const &fr) {
MapFindResult last;
if (fr.entry_prev == MAP_SENTINEL) {
h->hashes.data[fr.hash_index] = h->entries.data[fr.entry_index].next;
h->hashes[fr.hash_index] = h->entries[fr.entry_index].next;
} else {
h->entries.data[fr.entry_prev].next = h->entries.data[fr.entry_index].next;
h->entries[fr.entry_prev].next = h->entries[fr.entry_index].next;
}
if (fr.entry_index == h->entries.count-1) {
array_pop(&h->entries);
if (fr.entry_index == h->count-1) {
h->count--;
return;
}
h->entries.data[fr.entry_index] = h->entries.data[h->entries.count-1];
array_pop(&h->entries);
h->entries[fr.entry_index] = h->entries[h->count-1];
h->count--;
last = map__find(h, h->entries.data[fr.entry_index].key);
last = map__find(h, h->entries[fr.entry_index].key);
if (last.entry_prev != MAP_SENTINEL) {
h->entries.data[last.entry_prev].next = fr.entry_index;
h->entries[last.entry_prev].next = fr.entry_index;
} else {
h->hashes.data[last.hash_index] = fr.entry_index;
h->hashes[last.hash_index] = fr.entry_index;
}
}
template <typename K, typename V>
void map_remove(PtrMap<K, V> *h, K key) {
gb_internal void map_remove(PtrMap<K, V> *h, K key) {
MapFindResult fr = map__find(h, key);
if (fr.entry_index != MAP_SENTINEL) {
map__erase(h, fr);
@@ -250,38 +350,38 @@ void map_remove(PtrMap<K, V> *h, K key) {
}
template <typename K, typename V>
gb_inline void map_clear(PtrMap<K, V> *h) {
array_clear(&h->entries);
for (isize i = 0; i < h->hashes.count; i++) {
h->hashes.data[i] = MAP_SENTINEL;
gb_internal gb_inline void map_clear(PtrMap<K, V> *h) {
h->count = 0;
for (usize i = 0; i < h->hashes_count; i++) {
h->hashes[i] = MAP_SENTINEL;
}
}
#if PTR_MAP_ENABLE_MULTI_MAP
template <typename K, typename V>
PtrMapEntry<K, V> *multi_map_find_first(PtrMap<K, V> *h, K key) {
gb_internal PtrMapEntry<K, V> *multi_map_find_first(PtrMap<K, V> *h, K key) {
MapIndex i = map__find(h, key).entry_index;
if (i == MAP_SENTINEL) {
return nullptr;
}
return &h->entries.data[i];
return &h->entries[i];
}
template <typename K, typename V>
PtrMapEntry<K, V> *multi_map_find_next(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
gb_internal PtrMapEntry<K, V> *multi_map_find_next(PtrMap<K, V> *h, PtrMapEntry<K, V> *e) {
MapIndex i = e->next;
while (i != MAP_SENTINEL) {
if (h->entries.data[i].key == e->key) {
return &h->entries.data[i];
if (h->entries[i].key == e->key) {
return &h->entries[i];
}
i = h->entries.data[i].next;
i = h->entries[i].next;
}
return nullptr;
}
template <typename K, typename V>
isize multi_map_count(PtrMap<K, V> *h, K key) {
gb_internal isize multi_map_count(PtrMap<K, V> *h, K key) {
isize count = 0;
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
while (e != nullptr) {
@@ -292,8 +392,8 @@ isize multi_map_count(PtrMap<K, V> *h, K key) {
}
template <typename K, typename V>
void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
isize i = 0;
gb_internal void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
usize i = 0;
PtrMapEntry<K, V> *e = multi_map_find_first(h, key);
while (e != nullptr) {
items[i++] = e->value;
@@ -302,22 +402,22 @@ void multi_map_get_all(PtrMap<K, V> *h, K key, V *items) {
}
template <typename K, typename V>
void multi_map_insert(PtrMap<K, V> *h, K key, V const &value) {
gb_internal void multi_map_insert(PtrMap<K, V> *h, K key, V const &value) {
MapFindResult fr;
MapIndex i;
if (h->hashes.count == 0) {
if (h->hashes_count == 0) {
map_grow(h);
}
// Make
fr = map__find(h, key);
i = map__add_entry(h, key);
if (fr.entry_prev == MAP_SENTINEL) {
h->hashes.data[fr.hash_index] = i;
h->hashes[fr.hash_index] = i;
} else {
h->entries.data[fr.entry_prev].next = i;
h->entries[fr.entry_prev].next = i;
}
h->entries.data[i].next = fr.entry_index;
h->entries.data[i].value = value;
h->entries[i].next = fr.entry_index;
h->entries[i].value = value;
// Grow if needed
if (map__full(h)) {
map_grow(h);
@@ -325,7 +425,7 @@ void multi_map_insert(PtrMap<K, V> *h, K key, V const &value) {
}
template <typename K, typename V>
void multi_map_remove(PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e) {
gb_internal void multi_map_remove(PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e) {
MapFindResult fr = map__find_from_entry(h, e);
if (fr.entry_index != MAP_SENTINEL) {
map__erase(h, fr);
@@ -333,9 +433,30 @@ void multi_map_remove(PtrMap<K, V> *h, K key, PtrMapEntry<K, V> *e) {
}
template <typename K, typename V>
void multi_map_remove_all(PtrMap<K, V> *h, K key) {
gb_internal void multi_map_remove_all(PtrMap<K, V> *h, K key) {
while (map_get(h, key) != nullptr) {
map_remove(h, key);
}
}
#endif
template <typename K, typename V>
gb_internal PtrMapEntry<K, V> *begin(PtrMap<K, V> &m) {
return m.entries;
}
template <typename K, typename V>
gb_internal PtrMapEntry<K, V> const *begin(PtrMap<K, V> const &m) {
return m.entries;
}
template <typename K, typename V>
gb_internal PtrMapEntry<K, V> *end(PtrMap<K, V> &m) {
return m.entries + m.count;
}
template <typename K, typename V>
gb_internal PtrMapEntry<K, V> const *end(PtrMap<K, V> const &m) {
return m.entries + m.count;
}
+162 -193
View File
@@ -1,235 +1,204 @@
template <typename T>
struct PtrSetEntry {
T ptr;
MapIndex next;
};
template <typename T>
struct PtrSet {
Slice<MapIndex> hashes;
Array<PtrSetEntry<T>> entries;
static_assert(TypeIsPointer<T>::value, "PtrSet::T must be a pointer");
static constexpr uintptr TOMBSTONE = ~(uintptr)(0ull);
T * keys;
usize count;
usize capacity;
};
template <typename T> void ptr_set_init (PtrSet<T> *s, gbAllocator a, isize capacity = 16);
template <typename T> void ptr_set_destroy(PtrSet<T> *s);
template <typename T> T ptr_set_add (PtrSet<T> *s, T ptr);
template <typename T> bool ptr_set_update (PtrSet<T> *s, T ptr); // returns true if it previously existed
template <typename T> bool ptr_set_exists (PtrSet<T> *s, T ptr);
template <typename T> void ptr_set_remove (PtrSet<T> *s, T ptr);
template <typename T> void ptr_set_clear (PtrSet<T> *s);
template <typename T> void ptr_set_grow (PtrSet<T> *s);
template <typename T> void ptr_set_rehash (PtrSet<T> *s, isize new_count);
template <typename T> void ptr_set_reserve(PtrSet<T> *h, isize cap);
template <typename T> gb_internal void ptr_set_init (PtrSet<T> *s, isize capacity = 16);
template <typename T> gb_internal void ptr_set_destroy(PtrSet<T> *s);
template <typename T> gb_internal T ptr_set_add (PtrSet<T> *s, T ptr);
template <typename T> gb_internal bool ptr_set_update (PtrSet<T> *s, T ptr); // returns true if it previously existed
template <typename T> gb_internal bool ptr_set_exists (PtrSet<T> *s, T ptr);
template <typename T> gb_internal void ptr_set_remove (PtrSet<T> *s, T ptr);
template <typename T> gb_internal void ptr_set_clear (PtrSet<T> *s);
gb_internal gbAllocator ptr_set_allocator(void) {
return heap_allocator();
}
template <typename T>
void ptr_set_init(PtrSet<T> *s, gbAllocator a, isize capacity) {
gb_internal void ptr_set_init(PtrSet<T> *s, isize capacity) {
GB_ASSERT(s->keys == nullptr);
if (capacity != 0) {
capacity = next_pow2_isize(gb_max(16, capacity));
s->keys = gb_alloc_array(ptr_set_allocator(), T, capacity);
// This memory will be zeroed, no need to explicitly zero it
}
slice_init(&s->hashes, a, capacity);
array_init(&s->entries, a, 0, capacity);
for (isize i = 0; i < capacity; i++) {
s->hashes.data[i] = MAP_SENTINEL;
}
s->count = 0;
s->capacity = capacity;
}
template <typename T>
void ptr_set_destroy(PtrSet<T> *s) {
slice_free(&s->hashes, s->entries.allocator);
array_free(&s->entries);
gb_internal void ptr_set_destroy(PtrSet<T> *s) {
gb_free(ptr_set_allocator(), s->keys);
s->keys = nullptr;
s->count = 0;
s->capacity = 0;
}
template <typename T>
gb_internal MapIndex ptr_set__add_entry(PtrSet<T> *s, T ptr) {
PtrSetEntry<T> e = {};
e.ptr = ptr;
e.next = MAP_SENTINEL;
array_add(&s->entries, e);
return cast(MapIndex)(s->entries.count-1);
}
template <typename T>
gb_internal MapFindResult ptr_set__find(PtrSet<T> *s, T ptr) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (s->hashes.count != 0) {
gb_internal isize ptr_set__find(PtrSet<T> *s, T ptr) {
GB_ASSERT(ptr != nullptr);
if (s->count != 0) {
#if 0
for (usize i = 0; i < s->capacity; i++) {
if (s->keys[i] == ptr) {
return i;
}
}
#else
u32 hash = ptr_map_hash_key(ptr);
fr.hash_index = cast(MapIndex)(hash & (s->hashes.count-1));
fr.entry_index = s->hashes.data[fr.hash_index];
while (fr.entry_index != MAP_SENTINEL) {
if (s->entries.data[fr.entry_index].ptr == ptr) {
return fr;
usize mask = s->capacity-1;
usize hash_index = cast(usize)hash & mask;
for (usize i = 0; i < s->capacity; i++) {
T key = s->keys[hash_index];
if (key == ptr) {
return hash_index;
} else if (key == nullptr) {
return -1;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries.data[fr.entry_index].next;
hash_index = (hash_index+1)&mask;
}
}
return fr;
}
template <typename T>
gb_internal MapFindResult ptr_set__find_from_entry(PtrSet<T> *s, PtrSetEntry<T> *e) {
MapFindResult fr = {MAP_SENTINEL, MAP_SENTINEL, MAP_SENTINEL};
if (s->hashes.count != 0) {
u32 hash = ptr_map_hash_key(e->ptr);
fr.hash_index = cast(MapIndex)(hash & (s->hashes.count-1));
fr.entry_index = s->hashes.data[fr.hash_index];
while (fr.entry_index != MAP_SENTINEL) {
if (&s->entries.data[fr.entry_index] == e) {
return fr;
}
fr.entry_prev = fr.entry_index;
fr.entry_index = s->entries.data[fr.entry_index].next;
}
}
return fr;
}
template <typename T>
gb_internal bool ptr_set__full(PtrSet<T> *s) {
return 0.75f * s->hashes.count <= s->entries.count;
}
template <typename T>
gb_inline void ptr_set_grow(PtrSet<T> *s) {
isize new_count = gb_max(s->hashes.count<<1, 16);
ptr_set_rehash(s, new_count);
}
template <typename T>
void ptr_set_reset_entries(PtrSet<T> *s) {
for (isize i = 0; i < s->hashes.count; i++) {
s->hashes.data[i] = MAP_SENTINEL;
}
for (isize i = 0; i < s->entries.count; i++) {
MapFindResult fr;
PtrSetEntry<T> *e = &s->entries.data[i];
e->next = MAP_SENTINEL;
fr = ptr_set__find_from_entry(s, e);
if (fr.entry_prev == MAP_SENTINEL) {
s->hashes[fr.hash_index] = cast(MapIndex)i;
} else {
s->entries[fr.entry_prev].next = cast(MapIndex)i;
}
}
}
template <typename T>
void ptr_set_reserve(PtrSet<T> *s, isize cap) {
array_reserve(&s->entries, cap);
if (s->entries.count*2 < s->hashes.count) {
return;
}
slice_resize(&s->hashes, s->entries.allocator, cap*2);
ptr_set_reset_entries(s);
}
template <typename T>
void ptr_set_rehash(PtrSet<T> *s, isize new_count) {
ptr_set_reserve(s, new_count);
}
template <typename T>
gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
isize index = ptr_set__find(s, ptr).entry_index;
return index != MAP_SENTINEL;
}
template <typename T>
gb_inline isize ptr_entry_index(PtrSet<T> *s, T ptr) {
isize index = ptr_set__find(s, ptr).entry_index;
if (index != MAP_SENTINEL) {
return index;
#endif
}
return -1;
}
// Returns true if it already exists
template <typename T>
T ptr_set_add(PtrSet<T> *s, T ptr) {
MapIndex index;
MapFindResult fr;
if (s->hashes.count == 0) {
gb_internal bool ptr_set__full(PtrSet<T> *s) {
return 0.75f * s->capacity <= s->count;
}
template <typename T>
gb_internal gb_inline void ptr_set_grow(PtrSet<T> *old_set) {
if (old_set->capacity == 0) {
ptr_set_init(old_set);
return;
}
PtrSet<T> new_set = {};
ptr_set_init(&new_set, gb_max(old_set->capacity<<1, 16));
for (T ptr : *old_set) {
bool was_new = ptr_set_update(&new_set, ptr);
GB_ASSERT(!was_new);
}
GB_ASSERT(old_set->count == new_set.count);
ptr_set_destroy(old_set);
*old_set = new_set;
}
template <typename T>
gb_internal gb_inline bool ptr_set_exists(PtrSet<T> *s, T ptr) {
return ptr_set__find(s, ptr) >= 0;
}
template <typename T>
gb_internal bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it previously existsed
if (ptr_set_exists(s, ptr)) {
return true;
}
if (s->keys == nullptr) {
ptr_set_init(s);
} else if (ptr_set__full(s)) {
ptr_set_grow(s);
}
fr = ptr_set__find(s, ptr);
if (fr.entry_index == MAP_SENTINEL) {
index = ptr_set__add_entry(s, ptr);
if (fr.entry_prev != MAP_SENTINEL) {
s->entries.data[fr.entry_prev].next = index;
} else {
s->hashes.data[fr.hash_index] = index;
GB_ASSERT(s->count < s->capacity);
GB_ASSERT(s->capacity >= 0);
usize mask = s->capacity-1;
u32 hash = ptr_map_hash_key(ptr);
usize hash_index = (cast(usize)hash) & mask;
GB_ASSERT(hash_index < s->capacity);
for (usize i = 0; i < s->capacity; i++) {
T *key = &s->keys[hash_index];
GB_ASSERT(*key != ptr);
if (*key == (T)PtrSet<T>::TOMBSTONE || *key == nullptr) {
*key = ptr;
s->count++;
return false;
}
hash_index = (hash_index+1)&mask;
}
if (ptr_set__full(s)) {
ptr_set_grow(s);
}
GB_PANIC("ptr set out of memory");
return false;
}
template <typename T>
gb_internal T ptr_set_add(PtrSet<T> *s, T ptr) {
ptr_set_update(s, ptr);
return ptr;
}
template <typename T>
bool ptr_set_update(PtrSet<T> *s, T ptr) { // returns true if it previously existsed
bool exists = false;
MapIndex index;
MapFindResult fr;
if (s->hashes.count == 0) {
ptr_set_grow(s);
gb_internal void ptr_set_remove(PtrSet<T> *s, T ptr) {
isize index = ptr_set__find(s, ptr);
if (index >= 0) {
GB_ASSERT(s->count > 0);
s->keys[index] = (T)PtrSet<T>::TOMBSTONE;
s->count--;
}
fr = ptr_set__find(s, ptr);
if (fr.entry_index != MAP_SENTINEL) {
exists = true;
} else {
index = ptr_set__add_entry(s, ptr);
if (fr.entry_prev != MAP_SENTINEL) {
s->entries.data[fr.entry_prev].next = index;
} else {
s->hashes.data[fr.hash_index] = index;
}
template <typename T>
gb_internal gb_inline void ptr_set_clear(PtrSet<T> *s) {
s->count = 0;
gb_zero_size(s->keys, s->capacity*gb_size_of(T));
}
template <typename T>
struct PtrSetIterator {
PtrSet<T> *set;
usize index;
PtrSetIterator<T> &operator++() noexcept {
for (;;) {
++index;
if (set->capacity == index) {
return *this;
}
T key = set->keys[index];
if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
return *this;
}
}
}
if (ptr_set__full(s)) {
ptr_set_grow(s);
}
return exists;
}
bool operator==(PtrSetIterator<T> const &other) const noexcept {
return this->set == other.set && this->index == other.index;
}
operator T *() const {
return &set->keys[index];
}
};
template <typename T>
void ptr_set__erase(PtrSet<T> *s, MapFindResult fr) {
MapFindResult last;
if (fr.entry_prev == MAP_SENTINEL) {
s->hashes.data[fr.hash_index] = s->entries.data[fr.entry_index].next;
} else {
s->entries.data[fr.entry_prev].next = s->entries.data[fr.entry_index].next;
}
if (cast(isize)fr.entry_index == s->entries.count-1) {
array_pop(&s->entries);
return;
}
s->entries.data[fr.entry_index] = s->entries.data[s->entries.count-1];
last = ptr_set__find(s, s->entries.data[fr.entry_index].ptr);
if (last.entry_prev != MAP_SENTINEL) {
s->entries.data[last.entry_prev].next = fr.entry_index;
} else {
s->hashes.data[last.hash_index] = fr.entry_index;
gb_internal PtrSetIterator<T> begin(PtrSet<T> &set) noexcept {
usize index = 0;
while (index < set.capacity) {
T key = set.keys[index];
if (key != nullptr && key != (T)PtrSet<T>::TOMBSTONE) {
break;
}
index++;
}
return PtrSetIterator<T>{&set, index};
}
template <typename T>
void ptr_set_remove(PtrSet<T> *s, T ptr) {
MapFindResult fr = ptr_set__find(s, ptr);
if (fr.entry_index != MAP_SENTINEL) {
ptr_set__erase(s, fr);
}
}
template <typename T>
gb_inline void ptr_set_clear(PtrSet<T> *s) {
array_clear(&s->entries);
for (isize i = 0; i < s->hashes.count; i++) {
s->hashes.data[i] = MAP_SENTINEL;
}
}
gb_internal PtrSetIterator<T> end(PtrSet<T> &set) noexcept {
return PtrSetIterator<T>{&set, set.capacity};
}
-1030
View File
File diff suppressed because it is too large Load Diff
+99 -14
View File
@@ -1,3 +1,86 @@
template <typename T>
struct MPSCNode {
std::atomic<MPSCNode<T> *> next;
T value;
};
//
// Multiple Producer Single Consumer Lockless Queue
// URL: https://www.1024cores.net
//
template <typename T>
struct MPSCQueue {
MPSCNode<T> sentinel;
std::atomic<MPSCNode<T> *> head;
std::atomic<MPSCNode<T> *> tail;
std::atomic<isize> count;
};
template <typename T> gb_internal void mpsc_init (MPSCQueue<T> *q);
template <typename T> gb_internal void mpsc_destroy(MPSCQueue<T> *q);
template <typename T> gb_internal isize mpsc_enqueue(MPSCQueue<T> *q, T const &value);
template <typename T> gb_internal bool mpsc_dequeue(MPSCQueue<T> *q, T *value_);
template <typename T>
gb_internal void mpsc_init(MPSCQueue<T> *q, gbAllocator const &allocator) {
q->sentinel.next.store(nullptr, std::memory_order_relaxed);
q->head.store(&q->sentinel, std::memory_order_relaxed);
q->tail.store(&q->sentinel, std::memory_order_relaxed);
q->count.store(0, std::memory_order_relaxed);
}
template <typename T>
gb_internal void mpsc_destroy(MPSCQueue<T> *q) {
GB_ASSERT(q->count.load() == 0);
}
template <typename T>
gb_internal MPSCNode<T> *mpsc_alloc_node(MPSCQueue<T> *q, T const &value) {
auto new_node = gb_alloc_item(heap_allocator(), MPSCNode<T>);
new_node->value = value;
return new_node;
}
template <typename T>
gb_internal void mpsc_free_node(MPSCQueue<T> *q, MPSCNode<T> *node) {
// TODO(bill): determine a good way to handle the freed nodes rather than letting them leak
}
template <typename T>
gb_internal isize mpsc_enqueue(MPSCQueue<T> *q, MPSCNode<T> *node) {
node->next.store(nullptr, std::memory_order_relaxed);
auto prev = q->head.exchange(node, std::memory_order_acq_rel);
prev->next.store(node, std::memory_order_release);
isize count = 1 + q->count.fetch_add(1, std::memory_order_relaxed);
return count;
}
template <typename T>
gb_internal isize mpsc_enqueue(MPSCQueue<T> *q, T const &value) {
auto node = mpsc_alloc_node(q, value);
return mpsc_enqueue(q, node);
}
template <typename T>
gb_internal bool mpsc_dequeue(MPSCQueue<T> *q, T *value_) {
auto tail = q->tail.load(std::memory_order_relaxed);
auto next = tail->next.load(std::memory_order_relaxed);
if (next) {
q->tail.store(next, std::memory_order_relaxed);
if (value_) *value_ = next->value;
q->count.fetch_sub(1, std::memory_order_relaxed);
mpsc_free_node(q, tail);
return true;
}
GB_ASSERT(q->count.load(std::memory_order_acquire) == 0);
return false;
}
////////////////////////////
#define MPMC_CACHE_LINE_SIZE 64
typedef std::atomic<i32> MPMCQueueAtomicIdx;
@@ -9,7 +92,6 @@ struct MPMCQueue {
T * nodes;
MPMCQueueAtomicIdx *indices;
gbAllocator allocator;
BlockingMutex mutex;
MPMCQueueAtomicIdx count;
i32 mask; // capacity-1, because capacity must be a power of 2
@@ -22,8 +104,11 @@ struct MPMCQueue {
};
gb_internal gbAllocator mpmc_allocator(void) {
return heap_allocator();
}
void mpmc_internal_init_indices(MPMCQueueAtomicIdx *indices, i32 offset, i32 size) {
gb_internal void mpmc_internal_init_indices(MPMCQueueAtomicIdx *indices, i32 offset, i32 size) {
GB_ASSERT(offset % 8 == 0);
GB_ASSERT(size % 8 == 0);
@@ -43,7 +128,7 @@ void mpmc_internal_init_indices(MPMCQueueAtomicIdx *indices, i32 offset, i32 siz
template <typename T>
void mpmc_init(MPMCQueue<T> *q, gbAllocator a, isize size_i) {
gb_internal void mpmc_init(MPMCQueue<T> *q, isize size_i) {
if (size_i < 8) {
size_i = 8;
}
@@ -52,9 +137,8 @@ void mpmc_init(MPMCQueue<T> *q, gbAllocator a, isize size_i) {
size = next_pow2(size);
GB_ASSERT(gb_is_power_of_two(size));
mutex_init(&q->mutex);
q->mask = size-1;
q->allocator = a;
gbAllocator a = mpmc_allocator();
q->nodes = gb_alloc_array(a, T, size);
q->indices = gb_alloc_array(a, MPMCQueueAtomicIdx, size);
@@ -64,25 +148,26 @@ void mpmc_init(MPMCQueue<T> *q, gbAllocator a, isize size_i) {
template <typename T>
void mpmc_destroy(MPMCQueue<T> *q) {
mutex_destroy(&q->mutex);
gb_free(q->allocator, q->nodes);
gb_free(q->allocator, q->indices);
gb_internal void mpmc_destroy(MPMCQueue<T> *q) {
gbAllocator a = mpmc_allocator();
gb_free(a, q->nodes);
gb_free(a, q->indices);
}
template <typename T>
bool mpmc_internal_grow(MPMCQueue<T> *q) {
gb_internal bool mpmc_internal_grow(MPMCQueue<T> *q) {
gbAllocator a = mpmc_allocator();
mutex_lock(&q->mutex);
i32 old_size = q->mask+1;
i32 new_size = old_size*2;
resize_array_raw(&q->nodes, q->allocator, old_size, new_size);
resize_array_raw(&q->nodes, a, old_size, new_size);
if (q->nodes == nullptr) {
GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size);
mutex_unlock(&q->mutex);
return false;
}
resize_array_raw(&q->indices, q->allocator, old_size, new_size);
resize_array_raw(&q->indices, a, old_size, new_size);
if (q->indices == nullptr) {
GB_PANIC("Unable to resize enqueue: %td -> %td", old_size, new_size);
mutex_unlock(&q->mutex);
@@ -95,7 +180,7 @@ bool mpmc_internal_grow(MPMCQueue<T> *q) {
}
template <typename T>
i32 mpmc_enqueue(MPMCQueue<T> *q, T const &data) {
gb_internal i32 mpmc_enqueue(MPMCQueue<T> *q, T const &data) {
GB_ASSERT(q->mask != 0);
i32 head_idx = q->head_idx.load(std::memory_order_relaxed);
@@ -125,7 +210,7 @@ i32 mpmc_enqueue(MPMCQueue<T> *q, T const &data) {
}
template <typename T>
bool mpmc_dequeue(MPMCQueue<T> *q, T *data_) {
gb_internal bool mpmc_dequeue(MPMCQueue<T> *q, T *data_) {
if (q->mask == 0) {
return false;
}
+13 -13
View File
@@ -10,17 +10,17 @@ struct RangeCache {
};
RangeCache range_cache_make(gbAllocator a) {
gb_internal RangeCache range_cache_make(gbAllocator a) {
RangeCache cache = {};
array_init(&cache.ranges, a);
return cache;
}
void range_cache_destroy(RangeCache *c) {
gb_internal void range_cache_destroy(RangeCache *c) {
array_free(&c->ranges);
}
bool range_cache_add_index(RangeCache *c, i64 index) {
gb_internal bool range_cache_add_index(RangeCache *c, i64 index) {
for_array(i, c->ranges) {
RangeValue v = c->ranges[i];
if (v.lo <= index && index <= v.hi) {
@@ -33,7 +33,7 @@ bool range_cache_add_index(RangeCache *c, i64 index) {
}
bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) {
gb_internal bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) {
GB_ASSERT(lo <= hi);
for_array(i, c->ranges) {
RangeValue v = c->ranges[i];
@@ -59,12 +59,12 @@ bool range_cache_add_range(RangeCache *c, i64 lo, i64 hi) {
}
bool range_cache_index_exists(RangeCache *c, i64 index) {
for_array(i, c->ranges) {
RangeValue v = c->ranges[i];
if (v.lo <= index && index <= v.hi) {
return true;
}
}
return false;
}
// gb_internal bool range_cache_index_exists(RangeCache *c, i64 index) {
// for_array(i, c->ranges) {
// RangeValue v = c->ranges[i];
// if (v.lo <= index && index <= v.hi) {
// return true;
// }
// }
// return false;
// }

Some files were not shown because too many files have changed in this diff Show More