Compare commits

...

195 Commits

Author SHA1 Message Date
gingerBill 74458ab096 Merge pull request #1989 from Kelimion/cmark
Add CMark bindings
2022-09-01 23:02:30 +01:00
Jeroen van Rijn c39b1a31db vendor:cmark -> vendor:commonmark 2022-09-01 23:44:38 +02:00
Jeroen van Rijn 635c7fa153 Merge branch 'master' into cmark 2022-09-01 23:42:15 +02:00
Jeroen van Rijn b7ac0a9e8d Merge pull request #2006 from thePHTest/sort_with_indices
fix sort_by_with_indices for zero and one length slices
2022-09-01 22:21:44 +02:00
Phil 3f3ae4b2b6 fix sort_by_with_indices for zero and one length slices: 2022-09-01 13:14:10 -07:00
Jeroen van Rijn c2423dc07f Merge pull request #2005 from thePHTest/sort_with_indices
have sort_with_indices allocate. Add a couple convenience procs for using the indices result to sort other slices.
2022-09-01 21:42:16 +02:00
Phil 1296630160 cleanup tests 2022-09-01 12:34:08 -07:00
Phil 63eec25044 add sort_by_indices overload and test 2022-09-01 12:32:33 -07:00
Phil 7a9b0731cf add tests for sort_by_indices 2022-09-01 12:13:15 -07:00
Phil d45661c405 cleanup slice sorting with indices changes 2022-09-01 11:51:45 -07:00
Phil 002bec256a have sort_with_indices allocate. Add a couple convenience procs for using the indices result to sort other slices. 2022-09-01 11:46:59 -07:00
Jeroen van Rijn 000861cba8 Merge pull request #2003 from Kelimion/tests
Add tests for `slice.sort_with_indices`
2022-09-01 18:19:47 +02:00
Jeroen van Rijn 36473b2774 Add test for core:slice. 2022-09-01 18:04:48 +02:00
gingerBill 4188f50105 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-09-01 16:33:50 +01:00
gingerBill 3e3b9ae2df Fix #1994 Returning to err: Maybe(Error) raises compiler assert 2022-09-01 16:33:44 +01:00
gingerBill e89f0de232 Merge pull request #1997 from thePHTest/sort_with_indices
add sort_with_indices family of procs
2022-09-01 16:27:00 +01:00
gingerBill 4858e16a11 Merge pull request #1976 from matias-eduardo/patch-2
Add Extended Window Styles (WS_EX)
2022-09-01 16:26:51 +01:00
gingerBill 902a6db0e1 Fix #2000 - allow #soa array iteration by pointer 2022-09-01 16:15:09 +01:00
gingerBill 19ae6122c7 Fix #2002 (allow array *= matrix) 2022-09-01 16:11:03 +01:00
gingerBill b82b91ea08 Fix #1974 by erring on untyped parameters to intrinsics.objc_send 2022-09-01 15:15:51 +01:00
gingerBill 636f0d7063 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-09-01 15:11:58 +01:00
gingerBill ed73441a4c Fix code generation related to Objective-C related x->y() calls 2022-09-01 15:11:53 +01:00
Jeroen van Rijn 4c2be6cd49 Merge pull request #2001 from Lperlind/staging/add-window-bindings
Kernel32: Add more window bindings and improve consistency
2022-09-01 15:57:58 +02:00
Lucas Perlind f3f51bd643 Kernel32: Add more window bindings and improve consistency 2022-09-01 22:57:27 +10:00
Jeroen van Rijn 4c5672119a Merge pull request #1998 from thePHTest/ease_fix
fix ease.odin compile error from missing comma
2022-09-01 00:14:22 +02:00
Phil 8482f943ea fix ease.odin compile error from missing comma 2022-08-31 14:14:06 -07:00
Phil 15aaf7dfa0 add sort_with_indices family of procs 2022-08-31 14:06:21 -07:00
Jeroen van Rijn 768abf83f6 Merge pull request #1993 from SyndaKitty/master
Fix for SDL `GetPreferredLocales`
2022-08-31 14:09:35 +02:00
gingerBill ca76d53452 Fix more typos 2022-08-31 11:07:31 +01:00
gingerBill b0904d6598 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-31 11:02:52 +01:00
gingerBill b0a09f7b9e Fix typo 2022-08-31 11:02:36 +01:00
SyndaKai eb4891bcc8 Fix for SDL GetPreferredLocales 2022-08-31 04:28:46 -04:00
Jeroen van Rijn 803fd8f037 Wrap CMark allocator as Odin allocator
```odin
	// Smaller allocation to larger allocation resize
	{
		// Allocated on CMark's allocator
		foo := make([dynamic]int, 13)

		for i in 0..<13 {
			foo[i] = i
		}
		fmt.println("Before resize:", foo)

		resize(&foo, 42)
		fmt.println("After resize:", foo)

		delete(foo)
	}
```
2022-08-30 16:35:18 +02:00
Jeroen van Rijn 67bdb5b1a3 [cmark] Add static library for Linux
Built on Ubuntu 20.04.3 LTS.

Remove Odin allocator wrapper.
2022-08-30 16:02:40 +02:00
Jeroen van Rijn acc635b535 [cmark] Move wrapped allocator next to get_default_allocator 2022-08-30 14:56:10 +02:00
Jeroen van Rijn 4e8ce87792 [cmark] Allow wrapping context.allocator 2022-08-30 14:53:48 +02:00
Jeroen van Rijn 2c8daa25dc [cmark] Add wrappers. 2022-08-30 13:55:53 +02:00
Jeroen van Rijn 054ee0a8b5 [cmark] Change to static library 2022-08-30 13:32:07 +02:00
Jeroen van Rijn d0cadaf1a6 Add CMark bindings 2022-08-30 00:54:12 +02:00
Jeroen van Rijn 317db2758a Revert "Fix #1985"
This reverts commit 25102d4792.
2022-08-29 14:50:18 +02:00
Jeroen van Rijn 25102d4792 Fix #1985 2022-08-29 14:47:00 +02:00
gingerBill d39f1c461e Merge pull request #1988 from colrdavidson/queue_peek
Add peek_front and peek_back
2022-08-29 12:02:17 +01:00
Colin Davidson 7a6fc3a93b Add bounds check for peeks 2022-08-29 02:03:12 -07:00
Colin Davidson 83c002c197 add peeks 2022-08-29 01:53:40 -07:00
gingerBill fc47b5dee0 Merge pull request #1987 from colrdavidson/more_queue
Add more queue helpers
2022-08-29 09:38:53 +01:00
Colin Davidson 6c2e0b09ba Add more queue helpers 2022-08-29 00:43:35 -07:00
Jeroen van Rijn 3d4698debe [TGA] Add B&W and RLE color-mapped. 2022-08-29 00:29:50 +02:00
Jeroen van Rijn 4a25cfb27c Merge pull request #1984 from Kelimion/tga
TGA improvements
2022-08-28 21:58:20 +02:00
Jeroen van Rijn 294bd6a446 [TGA] Add B5G5R5 15- and 16-bit support. 2022-08-28 21:48:51 +02:00
Jeroen van Rijn d0109db23b [TGA] Add support for Top-Right and Bottom-Right origins. 2022-08-28 19:41:42 +02:00
Jeroen van Rijn ee3ee66aae Merge pull request #1981 from benoitjacquier/master
TGA loader
2022-08-28 18:33:20 +02:00
Jeroen van Rijn f74e281efa Various changes to TGA reader
- Style changes
- Change ptr usage to slice indexing
- Add TGA Footer

Also, add `peek_data` with offset to `compress`.
2022-08-28 18:25:07 +02:00
Jeroen van Rijn c0cd02883f Merge pull request #1982 from Lperlind/staging/raw_windows_input
Add much of Win32's Raw Input API
2022-08-28 12:29:19 +02:00
Lucas Perlind d9adb0fd6b Add much of Win32's Raw Input API 2022-08-28 16:30:55 +10:00
Benoit Jacquier 6363013dd8 style fix 2022-08-27 19:45:14 +02:00
Benoit Jacquier 934131abf8 Add RLE supports for TGA loader 2022-08-27 19:30:34 +02:00
Benoit Jacquier 4e5337412a Merge remote-tracking branch 'origin/master' 2022-08-27 16:22:37 +02:00
Benoit Jacquier 00f2e911a7 Add support for basic TGA loading 2022-08-27 16:07:21 +02:00
gingerBill c82d7d3d87 Merge pull request #1979 from Despacito696969/master
Fixed marshal_to_writer not supporting i128
2022-08-27 00:58:54 +01:00
Despacito696969 ecfea027a0 Fixed marshal_to_writer not supporting i128
Previously json.marshal(i128(696969)) would print 0 as there was no `u = i128(i)` initialization.
2022-08-26 23:49:33 +02:00
gingerBill 96be494730 Fix append_nothing 2022-08-26 22:21:19 +01:00
gingerBill 12c8db927b Remove direct core:mem dependency in core:reflect 2022-08-26 16:46:19 +01:00
gingerBill 027ea587fc Unify mem and runtime logic 2022-08-26 16:45:40 +01:00
gingerBill 026900c7f0 Add optional n parameter to strconv.parse_* procedures to state how many bytes could be read 2022-08-26 16:31:42 +01:00
gingerBill ffa87f55c4 Add a return value to append that states the number of elements that were returned 2022-08-26 16:20:47 +01:00
gingerBill c9eed04b51 Add comment regarding the layout of a map to explain how it is iterated 2022-08-26 16:19:48 +01:00
gingerBill b50b6b9f33 Add reflect.get_union_variant 2022-08-26 16:19:16 +01:00
gingerBill 8fd5bef0bd Fix #1977 2022-08-26 12:14:04 +01:00
gingerBill d6b49994a2 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-26 12:11:34 +01:00
gingerBill 776927709b Check for using variables 2022-08-26 12:11:27 +01:00
matias 96e033b22c Add Extended Window Styles (WS_EX)
Featuring frequently used styles such as: `WS_EX_APPWINDOW`, `WS_EX_NOREDIRECTIONBITMAP`, `WS_EX_ACCEPTFILES`, `WS_EX_TOOLWINDOW`, `WS_EX_TOPMOST`, `WS_EX_NOACTIVATE`, `WS_EX_LAYERED`, and more.
2022-08-25 21:12:45 -04:00
Jeroen van Rijn 3469178dc1 Fix #1973. 2022-08-25 13:31:45 +02:00
gingerBill af1b3b6368 Correct check_expr_is_stack_variable 2022-08-24 16:03:04 +01:00
gingerBill d56789e5a7 Add very basic escape analysis on return values 2022-08-24 15:58:20 +01:00
gingerBill aeacf3a9d8 Correct max alignment handling throughout the llvm backend 2022-08-24 13:07:41 +01:00
gingerBill 4ba486baa2 Add extra max alignment parameter for metrics (specifically for SIMD) 2022-08-24 12:58:16 +01:00
gingerBill f1ffd90294 Fix #1966 2022-08-24 12:52:57 +01:00
gingerBill 777aa8b118 Merge pull request #1955 from jaspergeer/fix-endian-type-conversion
fix #1759 endian float type conversion errors
2022-08-24 12:49:57 +01:00
gingerBill cb9e16f4df Correct syscalls for linux_i386 2022-08-24 12:37:56 +01:00
gingerBill 2908923db9 Fix #1972 2022-08-24 12:18:42 +01:00
Jeroen van Rijn 8c1dfabb6b Fix append for size_of(E) == 0 2022-08-23 16:00:14 +02:00
gingerBill 7fe36de069 Correct Try SRWLock related procedures to return BOOLEAN rather than BOOL 2022-08-22 22:24:51 +01:00
Jeroen van Rijn 27d556735a Merge pull request #1969 from ashemedai/bug-1968-bsd-headers
fix: Expand OpenBSD include for wait.h to all Unix
2022-08-22 13:50:40 +02:00
Jeroen Ruigrok van der Werven b70d211f21 fix: Expand OpenBSD include for wait.h to all Unix
closes: #1968
2022-08-22 11:15:53 +02:00
gingerBill b3e3b6c656 Fix #1965 2022-08-20 11:17:47 +01:00
gingerBill 1734286252 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-19 16:57:44 +01:00
gingerBill c8c076f970 Fix #1963 2022-08-19 16:57:36 +01:00
Jeroen van Rijn e40b3ad338 Remove unused n from PQ; add reflect.is_bit_set 2022-08-18 18:00:25 +02:00
gingerBill afec321db2 Add core:sys/valgrind package for valgrind, memcheck, and callgrind 2022-08-17 16:09:03 +01:00
gingerBill 6e9f9e6f3c Fix typo 2022-08-17 15:57:56 +01:00
gingerBill f504b200a9 Improve unreachable generation by putting a trap before it 2022-08-17 15:54:45 +01:00
gingerBill 82e840a0ca EXPERIMENTAL intrinsics.valgrind_client_request 2022-08-17 13:52:13 +01:00
gingerBill 82765ca96e Fix RtlWaitOnAddress behaviour with SetLastError(RtlNtStatusToDosError(status)) if an error occurred 2022-08-17 13:12:45 +01:00
Jasper Geer 5387ec5f29 Remove erroneous byte swap 2022-08-16 19:22:52 -07:00
gingerBill f2908cbc5a Remove debug crap with inlining 2022-08-16 16:36:13 +01:00
gingerBill 5337b0b471 Revert "Remove debug message"
This reverts commit 22d16c20f8.

Revert "Correct global constant procedure initialization"

This reverts commit 697c839c84.

Revert "Clean up how procedures are typed in LLVM's dumb type system"

This reverts commit de8bd88d2a.
2022-08-16 16:16:36 +01:00
gingerBill e51afc3509 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-16 12:02:22 +01:00
gingerBill 2c004dbcc9 Improve matrix conversion rules 2022-08-16 12:02:14 +01:00
gingerBill e128ed7d26 Merge pull request #1953 from thePHTest/master
Change math/linalg/general.odin vector_length and vector_normalize to only accept vectors of float types rather than any numeric type
2022-08-16 01:17:39 +01:00
Phil 9064ebfe97 Change math/linalg/general.odin vector_length and vector_normalize to only accept vectors of float types rather than any numeric type 2022-08-15 16:45:54 -07:00
gingerBill 4f7bbe0e4a Merge pull request #1927 from IanLilleyT/debug_symbols_for_range_interval
Debug symbols for range-based for loop over number range
2022-08-15 16:56:01 +01:00
gingerBill 208f168564 Correct assignment 2022-08-15 16:31:59 +01:00
gingerBill 737bccbd5e Add math.divmod and math.floor_divmod 2022-08-15 16:31:43 +01:00
Ian Lilley f5431a046d using correct type for val1 2022-08-15 08:08:49 -04:00
gingerBill 5a9422b6bc Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-15 10:27:57 +01:00
gingerBill d30198c99a Merge pull request #1944 from odin-lang/load-improvements
Improvements to `#load`
2022-08-15 10:27:53 +01:00
gingerBill 0c8d59dd20 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-15 10:24:23 +01:00
gingerBill a460d140fe Merge pull request #1889 from thePHTest/master
fix glfw/native.odin foreign lib import
2022-08-15 10:24:19 +01:00
gingerBill 881d18ee88 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-15 10:23:56 +01:00
gingerBill d73a4aa34b Merge pull request #1938 from Skytrias/pretty-json-2
add pretty json output in marshal based on spec + options
2022-08-15 10:23:50 +01:00
gingerBill 5c298c1501 Minor text alignment 2022-08-15 10:22:32 +01:00
gingerBill a83ca2120e Remove unused import 2022-08-14 21:50:41 +01:00
gingerBill 81799f7f78 Fix #1950 2022-08-14 21:50:21 +01:00
Jeroen van Rijn 7973f7e750 Merge pull request #1949 from matias-eduardo/patch-1
Typo: `GetWindowLongW` to `SetWindowLongW`
2022-08-14 13:25:23 +02:00
matias 3dc62a67e0 Typo: "Get" -> "Set" 2022-08-14 07:16:54 -04:00
Jeroen van Rijn 081e36c909 Add additional mouse buttons to Raylib bindings. 2022-08-13 15:34:52 +02:00
Jeroen van Rijn 3a1d364f59 Merge pull request #1929 from fabiansperber/add-windows-definitions
Add windows & wgl definitions
2022-08-12 22:58:18 +02:00
Fabian Sperber e50648279d Add some wgl extensions
- fix upper case for wglSwapIntervalEXT to be the same as the exported name
2022-08-12 21:56:55 +02:00
Fabian Sperber 929af320da Add more windows bindings 2022-08-12 21:56:54 +02:00
gingerBill 8e7c7eeeba Fix lb_emit_ptr_offset 2022-08-12 13:48:10 +01:00
Michael Kutowski b739044e69 Update marshal.odin 2022-08-12 13:59:11 +02:00
Michael Kutowski 9e0107c9fc add new soa type, my bad wasnt on master 2022-08-12 13:50:19 +02:00
Michael Kutowski 107e016508 switch styling and opt.spaces max 2022-08-12 13:42:19 +02:00
gingerBill 22d16c20f8 Remove debug message 2022-08-12 12:29:32 +01:00
gingerBill 697c839c84 Correct global constant procedure initialization 2022-08-12 12:29:11 +01:00
gingerBill de8bd88d2a Clean up how procedures are typed in LLVM's dumb type system 2022-08-12 11:15:12 +01:00
Ian Lilley 595efba747 removed unnecessary ternary 2022-08-11 11:43:19 -04:00
gingerBill c041d15569 Merge pull request #1928 from IanLilleyT/logger_extra_space
Removed extra space from file_console_logger
2022-08-11 16:18:46 +01:00
gingerBill 57b20e634b Merge branch 'master' into pretty-json-2 2022-08-11 16:14:27 +01:00
gingerBill e285796fc1 Merge pull request #1940 from Lperlind/staging/d3d11-idebug
Add ID3D11Debug interface to d3d11 package
2022-08-11 16:13:09 +01:00
gingerBill a19494d3a7 Minor refactoring of lb_build_addr 2022-08-11 16:12:07 +01:00
gingerBill d2a362fd52 Clean up compound literal backend stuff some more 2022-08-11 16:07:55 +01:00
gingerBill 0f3562ef02 Improve compound literal generation for array-like types 2022-08-11 16:01:46 +01:00
gingerBill 03f683f9e7 Improve emit store for large constants 2022-08-11 15:19:27 +01:00
gingerBill cecadce86d Allow for chaining of '#load(path) or_else #load(path)' 2022-08-11 14:42:29 +01:00
gingerBill a7c3906003 #load(path, type)
where `type` can be `string` or `[]T` where `T` is a simple type
2022-08-11 14:30:14 +01:00
gingerBill 70dc0c15fd Improve type hint for #load to allow for string types 2022-08-11 13:43:35 +01:00
gingerBill 9eeed9d5bd Simplify #load_or for the time being 2022-08-11 13:35:24 +01:00
gingerBill a054c2934e Cache #load data and hashes 2022-08-11 13:32:45 +01:00
gingerBill 38102f14c1 Add #load(path) or_else default in favour of #load_or(path, default) 2022-08-11 13:01:54 +01:00
gingerBill 0997df4fcf Move builtin directives to a separate procedure 2022-08-11 12:39:05 +01:00
gingerBill a5a56e061c Fix to png example.odin 2022-08-11 11:10:05 +01:00
gingerBill 8b007ad55a Merge pull request #1943 from jaspergeer/fix-untyped-const-shift
fix #1840 invalid LLVM code gen for arithmetics between f32 and shifted untyped integer
2022-08-11 10:58:58 +01:00
Jasper Yujin Geer 57dd5ec4db Added back missing return statement 2022-08-10 18:25:29 -07:00
Jasper Yujin Geer 5b621d5be1 More accurate error message 2022-08-10 18:07:49 -07:00
Jasper Yujin Geer 7aee762f3a Throw error when untyped shift expressions have non-integral type hints 2022-08-10 17:39:21 -07:00
Jeroen van Rijn 4ee50c5a35 Merge pull request #1941 from jockus/fix-rc-missing-extension
Do not remove .rc extension from resource path to prevent expansion t…
2022-08-10 15:22:09 +02:00
Joakim Hentula 28f440dd9e Do not remove .rc extension from resource path to prevent expansion to full path assuming it's a directory if a folder with the same name exists in the same folder as the resource file 2022-08-10 14:03:04 +01:00
Lucas Perlind 43b78e51a4 Add ID3D11Debug interface to d3d11 package 2022-08-10 22:28:24 +10:00
gingerBill 84f9fb706b General clean up of LLVM*GEP2 code 2022-08-10 11:36:25 +01:00
gingerBill 812823cad8 Wrap all LLVMGetElementType uses 2022-08-09 21:17:32 +01:00
gingerBill 0655260378 Comment out a bit of code in lb_is_const_or_global 2022-08-09 21:13:52 +01:00
gingerBill cfc3723879 Remove other uses of LLVMGetElementType on pointer types 2022-08-09 21:12:31 +01:00
gingerBill 4c3281b3f2 Disallow Early CSE on -debug builds 2022-08-09 18:09:26 +01:00
gingerBill ff94c605e0 Minor change to lb_emit_store for storing nil to procedure variables 2022-08-09 18:08:30 +01:00
gingerBill cb0a59bb2c Eliminate use of LLVMGetElementType for pointers 2022-08-09 15:36:18 +01:00
gingerBill 076700bd22 Merge pull request #1933 from lerno/reduce_reliance_on_ptr_type
Removed use of deprecated functions. Cleaned up most deprecated use o…
2022-08-09 15:18:09 +01:00
Jeroen van Rijn bcccc8338f Merge pull request #1937 from IanLilleyT/rc_fix
Find rc.exe in Windows SDK
2022-08-09 16:03:17 +02:00
Michael Kutowski 425dec8bb8 add uint as hex option 2022-08-08 18:28:28 +02:00
gingerBill 838554460b Add basic "lock" around Log_Allocator to minimize errors with allocation logging loops 2022-08-08 15:25:11 +01:00
gingerBill 659c3c528d Update delete to pass size in bytes to free when possible 2022-08-08 15:16:18 +01:00
gingerBill 60aeab3c38 Update fmt.odin 2022-08-08 15:07:19 +01:00
gingerBill 5e3cf45df3 Add #soa pointer type to aid with refactoring to #soa data types
a: #soa[16]Foo
p := &a[6]
#assert(type_of(p) == #soa^#soa[16]Foo)
p^.x = 123
p.x = 123
2022-08-08 15:07:00 +01:00
gingerBill 4633591918 Remove unnecessary pointer 2022-08-08 14:28:36 +01:00
gingerBill 0e6a8b7c72 Make Growing_Arena reserve memory first and then commit as needed
It just committed all at once to begin with
2022-08-08 12:43:18 +01:00
gingerBill 147848ca20 Clean up naming conventions 2022-08-08 12:30:58 +01:00
gingerBill cde002c579 Fix i18n 2022-08-08 12:27:23 +01:00
gingerBill f23d93ba89 Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-08 12:23:48 +01:00
gingerBill c97a8418dc Clean-up and unification for the allocation procedures 2022-08-08 12:23:19 +01:00
gingerBill 4aca9372a6 Improve resize call 2022-08-08 12:11:30 +01:00
gingerBill 4912ecc3ea Add log.Log_Allocator 2022-08-08 11:57:51 +01:00
Ian Lilley c1c8ceafc2 find windows sdk bin path for rc.exe 2022-08-07 17:52:29 -04:00
Christoffer Lerno 9c0a3b6c60 Removed use of deprecated functions. Cleaned up most deprecated use of LLVMGetElementType. 2022-08-07 19:26:28 +02:00
Jeroen van Rijn 7b539e3025 Merge pull request #1932 from blakeb211/fixed_math_log2
fixed math.log2
2022-08-06 14:55:23 +02:00
blake b2b0043875 fixed math.log2 2022-08-06 06:19:47 -04:00
Michael Kutowski 53e0d182af ...bad paste 2022-08-05 18:56:14 +02:00
Michael Kutowski a6fa41e290 marshal output options with pretty option and other config 2022-08-05 18:53:29 +02:00
Jeroen van Rijn edba99d636 Revert "Use sync.Mutex rather than a spin lock for the threading example"
This reverts commit 8d1f46d837.
2022-08-05 15:03:09 +02:00
gingerBill 35674959f2 Merge pull request #1931 from cuishuang/master
fix some typos
2022-08-05 13:16:48 +01:00
cui fliter dc8b7a0eb8 fix some typos
Signed-off-by: cui fliter <imcusg@gmail.com>
2022-08-05 20:10:20 +08:00
gingerBill 8d1f46d837 Use sync.Mutex rather than a spin lock for the threading example 2022-08-05 12:45:26 +01:00
gingerBill a2117d23b2 Change unreachable with panic 2022-08-05 12:41:25 +01:00
gingerBill a58e4d0359 Allow for foo() or_else unreachable() and other diverging procedures 2022-08-05 12:19:57 +01:00
gingerBill 576914aee1 Make unreachable() a built-in compiler-level procedure 2022-08-05 11:57:33 +01:00
gingerBill 8171f8209a Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-05 11:37:28 +01:00
gingerBill 64ff05303c Merge branch 'master' of https://github.com/odin-lang/Odin 2022-08-05 11:36:20 +01:00
gingerBill 6caab6225d Fix #1930 2022-08-05 11:36:12 +01:00
gingerBill 326411498a Merge pull request #1925 from neNasko1/fix-incorrect-behaviour-of-string-ordering
Fix incorrect behaviour of string ordering
2022-08-03 19:43:55 +01:00
gingerBill d50fcf0020 Merge pull request #1926 from IanLilleyT/env_leak
Memory leak in os2 user_config_dir and user_home_dir
2022-08-03 19:02:05 +01:00
Ian Lilley d354d36a3b removed extra space from file_console_logger 2022-08-03 13:22:12 -04:00
Ian Lilley 483a72ac61 fixed debug symbols for range interval 2022-08-03 12:36:52 -04:00
Ian Lilley dbec4b0d0e fixed memory leak from calling get_env 2022-08-03 11:49:42 -04:00
Atanas Dimitrov 4cb489b9e4 Fix sort.compare_strings for prefixes 2022-08-03 16:22:54 +03:00
Atanas Dimitrov 28ec50d567 Fix string orderings to account for prefix-equal strings 2022-08-03 16:09:36 +03:00
Phil 0cb1a578d0 fix glfw/native.odin foreign lib import 2022-08-01 08:26:26 -07:00
107 changed files with 6360 additions and 2989 deletions
+1 -1
View File
@@ -32,7 +32,7 @@ config_darwin() {
if [ ARCH == arm64 ]; then
MIN_LLVM_VERSION=("13.0.0")
else
# allow for x86 / amd64 all llvm versions begining from 11
# allow for x86 / amd64 all llvm versions beginning from 11
MIN_LLVM_VERSION=("11.1.0")
fi
+1 -1
View File
@@ -66,7 +66,7 @@ scanner_destroy :: proc(s: ^Scanner) {
}
// Returns the first non-EOF error that was encounted by the scanner
// Returns the first non-EOF error that was encountered by the scanner
scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
switch s._err {
case .EOF, nil:
+1 -1
View File
@@ -331,7 +331,7 @@ fmin :: proc{libc_fmin, libc_fminf}
fma :: proc{libc_fma, libc_fmaf}
// But retain the 'f' suffix-variant functions as well so they can be used,
// a trick is used here where we use explicit procedrual overloading of one
// a trick is used here where we use explicit procedural overloading of one
// procedure. This is done because the foreign block is marked @(private) and
// aliasing functions does not remove privateness from the entity.
acosf :: proc{libc_acosf}
+56 -1
View File
@@ -294,6 +294,24 @@ peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid
}
}
@(optimization_mode="speed")
peek_data_at_offset_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) {
size :: size_of(T)
#no_bounds_check {
if len(z.input_data) >= size + offset {
buf := z.input_data[offset:][:size]
return (^T)(&buf[0])^, .None
}
}
if len(z.input_data) == 0 {
return T{}, .EOF
} else {
return T{}, .Short_Buffer
}
}
@(optimization_mode="speed")
peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid) -> (res: T, err: io.Error) {
size :: size_of(T)
@@ -321,7 +339,44 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
return res, .None
}
peek_data :: proc{peek_data_from_memory, peek_data_from_stream}
@(optimization_mode="speed")
peek_data_at_offset_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid, #any_int offset: int) -> (res: T, err: io.Error) {
size :: size_of(T)
// Get current position to return to.
cur_pos, e1 := z.input->impl_seek(0, .Current)
if e1 != .None {
return T{}, e1
}
// Seek to offset.
pos, e2 := z.input->impl_seek(offset, .Start)
if e2 != .None {
return T{}, e2
}
r, e3 := io.to_reader_at(z.input)
if !e3 {
return T{}, .Empty
}
when size <= 128 {
b: [size]u8
} else {
b := make([]u8, size, context.temp_allocator)
}
_, e4 := io.read_at(r, b[:], pos)
if e4 != .None {
return T{}, .Empty
}
// Return read head to original position.
z.input->impl_seek(cur_pos, .Start)
res = (^T)(&b[0])^
return res, .None
}
peek_data :: proc{peek_data_from_memory, peek_data_from_stream, peek_data_at_offset_from_memory, peek_data_at_offset_from_stream}
@@ -85,7 +85,6 @@ _shift_down :: proc(pq: ^$Q/Priority_Queue($T), i0, n: int) -> bool {
_shift_up :: proc(pq: ^$Q/Priority_Queue($T), j: int) {
j := j
queue := pq.queue[:]
n := builtin.len(queue)
for 0 <= j {
i := (j-1)/2
if i == j || !pq.less(queue[j], queue[i]) {
+19
View File
@@ -73,11 +73,18 @@ get :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> T {
front :: proc(q: ^$Q/Queue($T)) -> T {
return q.data[q.offset]
}
front_ptr :: proc(q: ^$Q/Queue($T)) -> ^T {
return &q.data[q.offset]
}
back :: proc(q: ^$Q/Queue($T)) -> T {
idx := (q.offset+uint(q.len))%builtin.len(q.data)
return q.data[idx]
}
back_ptr :: proc(q: ^$Q/Queue($T)) -> ^T {
idx := (q.offset+uint(q.len))%builtin.len(q.data)
return &q.data[idx]
}
set :: proc(q: ^$Q/Queue($T), #any_int i: int, val: T, loc := #caller_location) {
runtime.bounds_check_error_loc(loc, i, builtin.len(q.data))
@@ -92,6 +99,18 @@ get_ptr :: proc(q: ^$Q/Queue($T), #any_int i: int, loc := #caller_location) -> ^
return &q.data[idx]
}
peek_front :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
runtime.bounds_check_error_loc(loc, 0, builtin.len(q.data))
idx := q.offset%builtin.len(q.data)
return &q.data[idx]
}
peek_back :: proc(q: ^$Q/Queue($T), loc := #caller_location) -> ^T {
runtime.bounds_check_error_loc(loc, int(q.len - 1), builtin.len(q.data))
idx := (uint(q.len - 1)+q.offset)%builtin.len(q.data)
return &q.data[idx]
}
// Push an element to the back of the queue
push_back :: proc(q: ^$Q/Queue($T), elem: T) -> bool {
if space(q^) == 0 {
+1 -1
View File
@@ -81,7 +81,7 @@ The crypto package is not thread-safe at the moment. This may change in the futu
### Disclaimer
The algorithms were ported out of curiosity and due to interest in the field.
We have not had any of the code verified by a third party or tested/fuzzed by any automatic means.
Whereever we were able to find official test vectors, those were used to verify the implementation.
Wherever we were able to find official test vectors, those were used to verify the implementation.
We do not recommend using them in a production environment, without any additional testing and/or verification.
### ToDo
+1 -1
View File
@@ -30,6 +30,6 @@ equivalence.
For the most part, alterations to the base fiat-crypto generated code was
kept to a minimum, to aid auditability. This results in a somewhat
ideosyncratic style, and in some cases minor performance penalties.
idiosyncratic style, and in some cases minor performance penalties.
[1]: https://github.com/mit-plv/fiat-crypto
+1 -1
View File
@@ -233,7 +233,7 @@ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) {
}
update :: proc(ctx: ^Context, data: []byte) {
assert(ctx.is_initialized, "crypto/siphash: Context is not initalized")
assert(ctx.is_initialized, "crypto/siphash: Context is not initialized")
ctx.last_block = len(data) / 8 * 8
ctx.buf = data
i := 0
+1 -1
View File
@@ -107,7 +107,7 @@ Node :: struct {
/* Conventions */
/* ------------
Much of HxA's use is based on convention. HxA lets users store arbitrary data in its structure that can be parsed but whose semantic meaning does not need to be understood.
A few conventions are hard, and some are soft. Hard convention that a user HAS to follow in order to produce a valid file. Hard conventions simplify parsing becaus the parser can make some assumptions. Soft convenbtions are basicly recomendations of how to store common data.
A few conventions are hard, and some are soft. Hard convention that a user HAS to follow in order to produce a valid file. Hard conventions simplify parsing becaus the parser can make some assumptions. Soft convenbtions are basically recomendations of how to store common data.
If you use HxA for something not covered by the conventions but need a convention for your use case. Please let us know so that we can add it!
*/
+215 -40
View File
@@ -17,25 +17,54 @@ Marshal_Error :: union #shared_nil {
io.Error,
}
marshal :: proc(v: any, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
// careful with MJSON maps & non quotes usage as keys without whitespace will lead to bad results
Marshal_Options :: struct {
// output based on spec
spec: Specification,
// use line breaks & tab|spaces
pretty: bool,
// spacing
use_spaces: bool,
spaces: int,
// state
indentation: int,
// option to output uint in JSON5 & MJSON
write_uint_as_hex: bool,
// mjson output options
mjson_keys_use_quotes: bool,
mjson_keys_use_equal_sign: bool,
// mjson state
mjson_skipped_first_braces_start: bool,
mjson_skipped_first_braces_end: bool,
}
marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
b := strings.builder_make(allocator)
defer if err != nil {
strings.builder_destroy(&b)
}
marshal_to_builder(&b, v) or_return
opt := opt
marshal_to_builder(&b, v, &opt) or_return
if len(b.buf) != 0 {
data = b.buf[:]
}
return data, nil
}
marshal_to_builder :: proc(b: ^strings.Builder, v: any) -> Marshal_Error {
return marshal_to_writer(strings.to_writer(b), v)
marshal_to_builder :: proc(b: ^strings.Builder, v: any, opt: ^Marshal_Options) -> Marshal_Error {
return marshal_to_writer(strings.to_writer(b), v, opt)
}
marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err: Marshal_Error) {
if v == nil {
io.write_string(w, "null") or_return
return
@@ -56,6 +85,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
case i16: u = u128(i)
case i32: u = u128(i)
case i64: u = u128(i)
case i128: u = u128(i)
case int: u = u128(i)
case u8: u = u128(i)
case u16: u = u128(i)
@@ -82,7 +112,21 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
case u128be: u = u128(i)
}
s := strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
s: string
// allow uints to be printed as hex
if opt.write_uint_as_hex && (opt.spec == .JSON5 || opt.spec == .MJSON) {
switch i in a {
case u8, u16, u32, u64, u128:
s = strconv.append_bits_128(buf[:], u, 16, info.signed, 8*ti.size, "0123456789abcdef", { .Prefix })
case:
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
}
} else {
s = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*ti.size, "0123456789", nil)
}
io.write_string(w, s) or_return
@@ -147,6 +191,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
case runtime.Type_Info_Multi_Pointer:
return .Unsupported_Type
case runtime.Type_Info_Soa_Pointer:
return .Unsupported_Type
case runtime.Type_Info_Procedure:
return .Unsupported_Type
@@ -166,52 +213,48 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
return .Unsupported_Type
case runtime.Type_Info_Array:
io.write_byte(w, '[') or_return
opt_write_start(w, opt, '[') or_return
for i in 0..<info.count {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(v.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
}
io.write_byte(w, ']') or_return
opt_write_end(w, opt, ']') or_return
case runtime.Type_Info_Enumerated_Array:
index := runtime.type_info_base(info.index).variant.(runtime.Type_Info_Enum)
io.write_byte(w, '[') or_return
opt_write_start(w, opt, '[') or_return
for i in 0..<info.count {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(v.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
}
io.write_byte(w, ']') or_return
opt_write_end(w, opt, ']') or_return
case runtime.Type_Info_Dynamic_Array:
io.write_byte(w, '[') or_return
opt_write_start(w, opt, '[') or_return
array := cast(^mem.Raw_Dynamic_Array)v.data
for i in 0..<array.len {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(array.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
}
io.write_byte(w, ']') or_return
opt_write_end(w, opt, ']') or_return
case runtime.Type_Info_Slice:
io.write_byte(w, '[') or_return
opt_write_start(w, opt, '[') or_return
slice := cast(^mem.Raw_Slice)v.data
for i in 0..<slice.len {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(slice.data) + uintptr(i*info.elem_size)
marshal_to_writer(w, any{rawptr(data), info.elem.id}) or_return
marshal_to_writer(w, any{rawptr(data), info.elem.id}, opt) or_return
}
io.write_byte(w, ']') or_return
opt_write_end(w, opt, ']') or_return
case runtime.Type_Info_Map:
m := (^mem.Raw_Map)(v.data)
opt_write_start(w, opt, '{') or_return
io.write_byte(w, '{') or_return
if m != nil {
if info.generated_struct == nil {
return .Unsupported_Type
@@ -223,31 +266,50 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
entry_size := ed.elem_size
for i in 0..<entries.len {
if i > 0 { io.write_string(w, ", ") or_return }
opt_write_iteration(w, opt, i) or_return
data := uintptr(entries.data) + uintptr(i*entry_size)
key := rawptr(data + entry_type.offsets[2])
value := rawptr(data + entry_type.offsets[3])
marshal_to_writer(w, any{key, info.key.id}) or_return
io.write_string(w, ": ") or_return
marshal_to_writer(w, any{value, info.value.id}) or_return
// check for string type
{
v := any{key, info.key.id}
ti := runtime.type_info_base(type_info_of(v.id))
a := any{v.data, ti.id}
name: string
#partial switch info in ti.variant {
case runtime.Type_Info_String:
switch s in a {
case string: name = s
case cstring: name = string(s)
}
opt_write_key(w, opt, name) or_return
case: return .Unsupported_Type
}
}
marshal_to_writer(w, any{value, info.value.id}, opt) or_return
}
}
io.write_byte(w, '}') or_return
opt_write_end(w, opt, '}') or_return
case runtime.Type_Info_Struct:
io.write_byte(w, '{') or_return
opt_write_start(w, opt, '{') or_return
for name, i in info.names {
if i > 0 { io.write_string(w, ", ") or_return }
io.write_quoted_string(w, name) or_return
io.write_string(w, ": ") or_return
opt_write_iteration(w, opt, i) or_return
opt_write_key(w, opt, name) or_return
id := info.types[i].id
data := rawptr(uintptr(v.data) + info.offsets[i])
marshal_to_writer(w, any{data, id}) or_return
marshal_to_writer(w, any{data, id}, opt) or_return
}
io.write_byte(w, '}') or_return
opt_write_end(w, opt, '}') or_return
case runtime.Type_Info_Union:
tag_ptr := uintptr(v.data) + info.tag_offset
@@ -270,11 +332,11 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
io.write_string(w, "null") or_return
} else {
id := info.variants[tag-1].id
return marshal_to_writer(w, any{v.data, id})
return marshal_to_writer(w, any{v.data, id}, opt)
}
case runtime.Type_Info_Enum:
return marshal_to_writer(w, any{v.data, info.base.id})
return marshal_to_writer(w, any{v.data, info.base.id}, opt)
case runtime.Type_Info_Bit_Set:
is_bit_set_different_endian_to_platform :: proc(ti: ^runtime.Type_Info) -> bool {
@@ -330,3 +392,116 @@ marshal_to_writer :: proc(w: io.Writer, v: any) -> (err: Marshal_Error) {
return
}
// write key as quoted string or with optional quotes in mjson
opt_write_key :: proc(w: io.Writer, opt: ^Marshal_Options, name: string) -> (err: io.Error) {
switch opt.spec {
case .JSON, .JSON5:
io.write_quoted_string(w, name) or_return
io.write_string(w, ": ") or_return
case .MJSON:
if opt.mjson_keys_use_quotes {
io.write_quoted_string(w, name) or_return
} else {
io.write_string(w, name) or_return
}
if opt.mjson_keys_use_equal_sign {
io.write_string(w, " = ") or_return
} else {
io.write_string(w, ": ") or_return
}
}
return
}
// insert start byte and increase indentation on pretty
opt_write_start :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) {
// skip mjson starting braces
if opt.spec == .MJSON && !opt.mjson_skipped_first_braces_start {
opt.mjson_skipped_first_braces_start = true
return
}
io.write_byte(w, c) or_return
opt.indentation += 1
if opt.pretty {
io.write_byte(w, '\n') or_return
}
return
}
// insert comma seperation and write indentations
opt_write_iteration :: proc(w: io.Writer, opt: ^Marshal_Options, iteration: int) -> (err: io.Error) {
switch opt.spec {
case .JSON, .JSON5:
if iteration > 0 {
io.write_string(w, ", ") or_return
if opt.pretty {
io.write_byte(w, '\n') or_return
}
}
opt_write_indentation(w, opt) or_return
case .MJSON:
if iteration > 0 {
// on pretty no commas necessary
if opt.pretty {
io.write_byte(w, '\n') or_return
} else {
// comma seperation necessary for non pretty output!
io.write_string(w, ", ") or_return
}
}
opt_write_indentation(w, opt) or_return
}
return
}
// decrease indent, write spacing and insert end byte
opt_write_end :: proc(w: io.Writer, opt: ^Marshal_Options, c: byte) -> (err: io.Error) {
if opt.spec == .MJSON && opt.mjson_skipped_first_braces_start && !opt.mjson_skipped_first_braces_end {
if opt.indentation == 0 {
opt.mjson_skipped_first_braces_end = true
return
}
}
opt.indentation -= 1
if opt.pretty {
io.write_byte(w, '\n') or_return
opt_write_indentation(w, opt) or_return
}
io.write_byte(w, c) or_return
return
}
// writes current indentation level based on options
opt_write_indentation :: proc(w: io.Writer, opt: ^Marshal_Options) -> (err: io.Error) {
if !opt.pretty {
return
}
if opt.use_spaces {
spaces := opt.spaces == 0 ? 4 : opt.spaces
for _ in 0..<opt.indentation * spaces {
io.write_byte(w, ' ') or_return
}
} else {
for _ in 0..<opt.indentation {
io.write_byte(w, '\t') or_return
}
}
return
}
+30 -2
View File
@@ -1031,6 +1031,15 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
}
}
fmt_soa_pointer :: proc(fi: ^Info, p: runtime.Raw_Soa_Pointer, verb: rune) {
io.write_string(fi.writer, "#soa{data=0x", &fi.n)
_fmt_int(fi, u64(uintptr(p.data)), 16, false, 8*size_of(rawptr), __DIGITS_UPPER)
io.write_string(fi.writer, ", index=", &fi.n)
_fmt_int(fi, u64(p.index), 10, false, 8*size_of(rawptr), __DIGITS_UPPER)
io.write_string(fi.writer, "}", &fi.n)
}
enum_value_to_string :: proc(val: any) -> (string, bool) {
v := val
v.id = runtime.typeid_base(v.id)
@@ -1867,6 +1876,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
fmt_pointer(fi, ptr, verb)
}
case runtime.Type_Info_Soa_Pointer:
ptr := (^runtime.Raw_Soa_Pointer)(v.data)^
fmt_soa_pointer(fi, ptr, verb)
case runtime.Type_Info_Multi_Pointer:
ptr := (^rawptr)(v.data)^
if ptr == nil {
@@ -2046,18 +2059,33 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
ed := runtime.type_info_base(gs.types[1]).variant.(runtime.Type_Info_Dynamic_Array)
entry_type := ed.elem.variant.(runtime.Type_Info_Struct)
entry_size := ed.elem_size
/*
NOTE: The layout of a `map` is as follows:
map[Key]Value
## Internal Layout
struct {
hashes: []int,
entries: [dynamic]struct{
hash: uintptr,
next: int,
key: Key,
value: Value,
},
}
*/
for i in 0..<entries.len {
if i > 0 { io.write_string(fi.writer, ", ", &fi.n) }
data := uintptr(entries.data) + uintptr(i*entry_size)
key := data + entry_type.offsets[2]
key := data + entry_type.offsets[2] // key: Key
fmt_arg(&Info{writer = fi.writer}, any{rawptr(key), info.key.id}, 'v')
io.write_string(fi.writer, "=", &fi.n)
value := data + entry_type.offsets[3]
value := data + entry_type.offsets[3] // value: Value
fmt_arg(fi, any{rawptr(value), info.value.id}, 'v')
}
}
+65 -7
View File
@@ -46,7 +46,7 @@ Image :: struct {
height: int,
channels: int,
depth: int, // Channel depth in bits, typically 8 or 16
pixels: bytes.Buffer,
pixels: bytes.Buffer `fmt:"-"`,
/*
Some image loaders/writers can return/take an optional background color.
For convenience, we return them as u16 so we don't need to switch on the type
@@ -61,6 +61,7 @@ Image_Metadata :: union #shared_nil {
^Netpbm_Info,
^PNG_Info,
^QOI_Info,
^TGA_Info,
}
@@ -168,6 +169,7 @@ Error :: union #shared_nil {
General_Image_Error :: enum {
None = 0,
Unsupported_Option,
// File I/O
Unable_To_Read_File,
Unable_To_Write_File,
@@ -376,10 +378,20 @@ QOI_Info :: struct {
header: QOI_Header,
}
TGA_Data_Type :: enum u8 {
No_Image_Data = 0,
Uncompressed_Color_Mapped = 1,
Uncompressed_RGB = 2,
Uncompressed_Black_White = 3,
Compressed_Color_Mapped = 9,
Compressed_RGB = 10,
Compressed_Black_White = 11,
}
TGA_Header :: struct #packed {
id_length: u8,
color_map_type: u8,
data_type_code: u8,
data_type_code: TGA_Data_Type,
color_map_origin: u16le,
color_map_length: u16le,
color_map_depth: u8,
@@ -390,6 +402,52 @@ TGA_Header :: struct #packed {
}
#assert(size_of(TGA_Header) == 18)
New_TGA_Signature :: "TRUEVISION-XFILE.\x00"
TGA_Footer :: struct #packed {
extension_area_offset: u32le,
developer_directory_offset: u32le,
signature: [18]u8 `fmt:"s,0"`, // Should match signature if New TGA.
}
#assert(size_of(TGA_Footer) == 26)
TGA_Extension :: struct #packed {
extension_size: u16le, // Size of this struct. If not 495 bytes it means it's an unsupported version.
author_name: [41]u8 `fmt:"s,0"`, // Author name, ASCII. Zero-terminated
author_comments: [324]u8 `fmt:"s,0"`, // Author comments, formatted as 4 lines of 80 character lines, each zero terminated.
datetime: struct {month, day, year, hour, minute, second: u16le},
job_name: [41]u8 `fmt:"s,0"`, // Author name, ASCII. Zero-terminated
job_time: struct {hour, minute, second: u16le},
software_id: [41]u8 `fmt:"s,0"`, // Software ID name, ASCII. Zero-terminated
software_version: struct #packed {
number: u16le, // Version number * 100
letter: u8 `fmt:"r"`, // " " if not used
},
key_color: [4]u8, // ARGB key color used at time of production
aspect_ratio: [2]u16le, // Numerator / Denominator
gamma: [2]u16le, // Numerator / Denominator, range should be 0.0..10.0
color_correction_offset: u32le, // 0 if no color correction information
postage_stamp_offset: u32le, // 0 if no thumbnail
scanline_offset: u32le, // 0 if no scanline table
attributes: TGA_Alpha_Kind,
}
#assert(size_of(TGA_Extension) == 495)
TGA_Alpha_Kind :: enum u8 {
None,
Undefined_Ignore,
Undefined_Retain,
Useful,
Premultiplied,
}
TGA_Info :: struct {
header: TGA_Header,
image_id: string,
footer: Maybe(TGA_Footer),
extension: Maybe(TGA_Extension),
}
// Function to help with image buffer calculations
compute_buffer_size :: proc(width, height, channels, depth: int, extra_row_bytes := int(0)) -> (size: int) {
size = ((((channels * width * depth) + 7) >> 3) + extra_row_bytes) * height
@@ -469,7 +527,7 @@ return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok
}
// Does the image have 1 or 2 channels, a valid bit depth (8 or 16),
// Is the pointer valid, are the dimenions valid?
// Is the pointer valid, are the dimensions valid?
is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) {
// Were we actually given a valid image?
if img == nil {
@@ -489,7 +547,7 @@ is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) {
// This returns 0 if any of the inputs is zero.
bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth)
// If the dimenions are invalid or the buffer size doesn't match the image characteristics, bail.
// If the dimensions are invalid or the buffer size doesn't match the image characteristics, bail.
if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS {
return false
}
@@ -498,7 +556,7 @@ is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) {
}
// Does the image have 3 or 4 channels, a valid bit depth (8 or 16),
// Is the pointer valid, are the dimenions valid?
// Is the pointer valid, are the dimensions valid?
is_valid_color_image :: proc(img: ^Image) -> (ok: bool) {
// Were we actually given a valid image?
if img == nil {
@@ -518,7 +576,7 @@ is_valid_color_image :: proc(img: ^Image) -> (ok: bool) {
// This returns 0 if any of the inputs is zero.
bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth)
// If the dimenions are invalid or the buffer size doesn't match the image characteristics, bail.
// If the dimensions are invalid or the buffer size doesn't match the image characteristics, bail.
if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS {
return false
}
@@ -527,7 +585,7 @@ is_valid_color_image :: proc(img: ^Image) -> (ok: bool) {
}
// Does the image have 1..4 channels, a valid bit depth (8 or 16),
// Is the pointer valid, are the dimenions valid?
// Is the pointer valid, are the dimensions valid?
is_valid_image :: proc(img: ^Image) -> (ok: bool) {
// Were we actually given a valid image?
if img == nil {
+1 -1
View File
@@ -219,7 +219,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b
defer close(fd)
write_string(fd,
fmt.tprintf("P6\n%v %v\n%v\n", width, height, (1 << uint(depth) - 1)),
fmt.tprintf("P6\n%v %v\n%v\n", width, height, uint(1 << uint(depth) - 1)),
)
if channels == 3 {
+3 -3
View File
@@ -1002,7 +1002,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
o16 = o16[out_image_channels:]
}
case:
unreachable("We should never seen # channels other than 1-4 inclusive.")
panic("We should never seen # channels other than 1-4 inclusive.")
}
img.pixels = t
@@ -1195,7 +1195,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
o = o[out_image_channels:]
}
case:
unreachable("We should never seen # channels other than 1-4 inclusive.")
panic("We should never seen # channels other than 1-4 inclusive.")
}
img.pixels = t
@@ -1206,7 +1206,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
This may change if we ever don't expand 1, 2 and 4 bit images. But, those raw
returns will likely bypass this processing pipeline.
*/
unreachable("We should never see bit depths other than 8, 16 and 'Paletted' here.")
panic("We should never see bit depths other than 8, 16 and 'Paletted' here.")
}
return img, nil
+341 -2
View File
@@ -4,6 +4,7 @@
List of contributors:
Jeroen van Rijn: Initial implementation.
Benoit Jacquier: tga loader
*/
@@ -14,11 +15,16 @@ import "core:mem"
import "core:image"
import "core:bytes"
import "core:os"
import "core:compress"
import "core:strings"
// TODO: alpha_premultiply support
Error :: image.Error
Image :: image.Image
Options :: image.Options
GA_Pixel :: image.GA_Pixel
RGB_Pixel :: image.RGB_Pixel
RGBA_Pixel :: image.RGBA_Pixel
@@ -57,7 +63,7 @@ save_to_memory :: proc(output: ^bytes.Buffer, img: ^Image, options := Options{}
}
header := image.TGA_Header{
data_type_code = 0x02, // Color, uncompressed.
data_type_code = .Uncompressed_RGB,
dimensions = {u16le(img.width), u16le(img.height)},
bits_per_pixel = u8(img.depth * img.channels),
image_descriptor = 1 << 5, // Origin is top left.
@@ -98,4 +104,337 @@ save_to_file :: proc(output: string, img: ^Image, options := Options{}, allocato
return nil if write_ok else .Unable_To_Write_File
}
save :: proc{save_to_memory, save_to_file}
save :: proc{save_to_memory, save_to_file}
load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
context.allocator = allocator
options := options
if .alpha_premultiply in options {
return nil, .Unsupported_Option
}
if .info in options {
options |= {.return_metadata, .do_not_decompress_image}
options -= {.info}
}
if .return_header in options && .return_metadata in options {
options -= {.return_header}
}
// First check for a footer.
filesize := compress.input_size(ctx) or_return
footer: image.TGA_Footer
have_valid_footer := false
extension: image.TGA_Extension
have_valid_extension := false
if filesize >= size_of(image.TGA_Header) + size_of(image.TGA_Footer) {
if f, f_err := compress.peek_data(ctx, image.TGA_Footer, filesize - i64(size_of(image.TGA_Footer))); f_err == .None {
if string(f.signature[:]) == image.New_TGA_Signature {
have_valid_footer = true
footer = f
if i64(footer.extension_area_offset) + i64(size_of(image.TGA_Extension)) < filesize {
if e, e_err := compress.peek_data(ctx, image.TGA_Extension, footer.extension_area_offset); e_err == .None {
if e.extension_size == size_of(image.TGA_Extension) {
have_valid_extension = true
extension = e
}
}
}
}
}
}
header := image.read_data(ctx, image.TGA_Header) or_return
// Header checks
rle_encoding := false
color_mapped := false
black_white := false
src_channels := 0
dest_depth := header.bits_per_pixel
dest_channels := 0
#partial switch header.data_type_code {
// Supported formats: RGB(A), RGB(A) RLE
case .Compressed_RGB:
rle_encoding = true
case .Uncompressed_RGB:
// Intentionally blank
case .Uncompressed_Black_White:
black_white = true
dest_depth = 24
case .Uncompressed_Color_Mapped:
color_mapped = true
case .Compressed_Color_Mapped:
color_mapped = true
rle_encoding = true
case .Compressed_Black_White:
black_white = true
rle_encoding = true
dest_depth = 24
case:
return nil, .Unsupported_Format
}
if color_mapped {
if header.color_map_type != 1 {
return nil, .Unsupported_Format
}
dest_depth = header.color_map_depth
// Expect LUT entry index to be 8 bits
if header.bits_per_pixel != 8 || header.color_map_origin != 0 || header.color_map_length > 256 {
return nil, .Unsupported_Format
}
}
switch dest_depth {
case 15: // B5G5R5
src_channels = 2
dest_channels = 3
if color_mapped {
src_channels = 1
}
case 16: // B5G5R5A1
src_channels = 2
dest_channels = 3 // Alpha bit is dodgy in TGA, so we ignore it.
if color_mapped {
src_channels = 1
}
case 24: // RGB8
src_channels = 1 if (color_mapped || black_white) else 3
dest_channels = 3
case 32: // RGBA8
src_channels = 4 if !color_mapped else 1
dest_channels = 4
case:
return nil, .Unsupported_Format
}
if header.image_descriptor & IMAGE_DESCRIPTOR_INTERLEAVING_MASK != 0 {
return nil, .Unsupported_Format
}
if int(header.dimensions[0]) * int(header.dimensions[1]) > image.MAX_DIMENSIONS {
return nil, .Image_Dimensions_Too_Large
}
if img == nil {
img = new(Image)
}
defer if err != nil {
destroy(img)
}
img.which = .TGA
img.channels = 4 if .alpha_add_if_missing in options else dest_channels
img.channels = 3 if .alpha_drop_if_present in options else img.channels
img.depth = 8
img.width = int(header.dimensions[0])
img.height = int(header.dimensions[1])
// Read Image ID if present
image_id := ""
if _id, e := compress.read_slice(ctx, int(header.id_length)); e != .None {
return img, .Corrupt
} else {
if .return_metadata in options {
id := strings.trim_right_null(string(_id))
image_id = strings.clone(id)
}
}
color_map := make([]RGBA_Pixel, header.color_map_length)
defer delete(color_map)
if color_mapped {
switch header.color_map_depth {
case 16:
for i in 0..<header.color_map_length {
if lut, lut_err := compress.read_data(ctx, GA_Pixel); lut_err != .None {
return img, .Corrupt
} else {
color_map[i].rg = lut
color_map[i].ba = 255
}
}
case 24:
for i in 0..<header.color_map_length {
if lut, lut_err := compress.read_data(ctx, RGB_Pixel); lut_err != .None {
return img, .Corrupt
} else {
color_map[i].rgb = lut
color_map[i].a = 255
}
}
case 32:
for i in 0..<header.color_map_length {
if lut, lut_err := compress.read_data(ctx, RGBA_Pixel); lut_err != .None {
return img, .Corrupt
} else {
color_map[i] = lut
}
}
}
}
if .return_metadata in options {
info := new(image.TGA_Info)
info.header = header
info.image_id = image_id
if have_valid_footer {
info.footer = footer
}
if have_valid_extension {
info.extension = extension
}
img.metadata = info
}
if .do_not_decompress_image in options {
return img, nil
}
if !resize(&img.pixels.buf, dest_channels * img.width * img.height) {
return img, .Unable_To_Allocate_Or_Resize
}
origin_is_top := header.image_descriptor & IMAGE_DESCRIPTOR_TOP_MASK != 0
origin_is_left := header.image_descriptor & IMAGE_DESCRIPTOR_RIGHT_MASK == 0
rle_repetition_count := 0
read_pixel := true
is_packet_rle := false
pixel: RGBA_Pixel
stride := img.width * dest_channels
line := 0 if origin_is_top else img.height - 1
for _ in 0..<img.height {
offset := line * stride + (0 if origin_is_left else (stride - dest_channels))
for _ in 0..<img.width {
// handle RLE decoding
if rle_encoding {
if rle_repetition_count == 0 {
rle_cmd, err := compress.read_u8(ctx)
if err != .None {
return img, .Corrupt
}
is_packet_rle = (rle_cmd >> 7) != 0
rle_repetition_count = 1 + int(rle_cmd & 0x7F)
read_pixel = true
} else if !is_packet_rle {
read_pixel = rle_repetition_count > 0
} else {
read_pixel = false
}
}
// Read pixel
if read_pixel {
src, src_err := compress.read_slice(ctx, src_channels)
if src_err != .None {
return img, .Corrupt
}
switch src_channels {
case 1:
// Color-mapped or Black & White
if black_white {
pixel = {src[0], src[0], src[0], 255}
} else if header.color_map_depth == 24 {
pixel = color_map[src[0]].bgra
} else if header.color_map_depth == 16 {
lut := color_map[src[0]]
v := u16(lut.r) | u16(lut.g) << 8
b := u8( v & 31) << 3
g := u8((v >> 5) & 31) << 3
r := u8((v >> 10) & 31) << 3
pixel = {r, g, b, 255}
}
case 2:
v := u16(src[0]) | u16(src[1]) << 8
b := u8( v & 31) << 3
g := u8((v >> 5) & 31) << 3
r := u8((v >> 10) & 31) << 3
pixel = {r, g, b, 255}
case 3:
pixel = {src[2], src[1], src[0], 255}
case 4:
pixel = {src[2], src[1], src[0], src[3]}
case:
return img, .Corrupt
}
}
// Write pixel
copy(img.pixels.buf[offset:], pixel[:dest_channels])
offset += dest_channels if origin_is_left else -dest_channels
rle_repetition_count -= 1
}
line += 1 if origin_is_top else -1
}
return img, nil
}
load_from_bytes :: proc(data: []byte, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
ctx := &compress.Context_Memory_Input{
input_data = data,
}
img, err = load_from_context(ctx, options, allocator)
return img, err
}
load_from_file :: proc(filename: string, options := Options{}, allocator := context.allocator) -> (img: ^Image, err: Error) {
context.allocator = allocator
data, ok := os.read_entire_file(filename)
defer delete(data)
if ok {
return load_from_bytes(data, options)
} else {
return nil, .Unable_To_Read_File
}
}
load :: proc{load_from_file, load_from_bytes, load_from_context}
destroy :: proc(img: ^Image) {
if img == nil || img.width == 0 || img.height == 0 {
return
}
bytes.buffer_destroy(&img.pixels)
if v, ok := img.metadata.(^image.TGA_Info); ok {
delete(v.image_id)
free(v)
}
// Make destroy idempotent
img.width = 0
img.height = 0
free(img)
}
IMAGE_DESCRIPTOR_INTERLEAVING_MASK :: (1<<6) | (1<<7)
IMAGE_DESCRIPTOR_RIGHT_MASK :: 1<<4
IMAGE_DESCRIPTOR_TOP_MASK :: 1<<5
@(init, private)
_register :: proc() {
image.register(.TGA, load_from_bytes, destroy)
}
+3
View File
@@ -295,6 +295,9 @@ objc_register_selector :: proc($name: string) -> objc_SEL ---
objc_find_class :: proc($name: string) -> objc_Class ---
objc_register_class :: proc($name: string) -> objc_Class ---
valgrind_client_request :: proc(default: uintptr, request: uintptr, a0, a1, a2, a3, a4: uintptr) -> uintptr ---
// Internal compiler use only
__entry_point :: proc() ---
+2 -2
View File
@@ -56,7 +56,7 @@ create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logg
return Logger{file_console_logger_proc, data, lowest, opt}
}
destroy_console_logger :: proc(log: ^Logger) {
destroy_console_logger :: proc(log: Logger) {
free(log.data)
}
@@ -95,7 +95,7 @@ file_console_logger_proc :: proc(logger_data: rawptr, level: Level, text: string
fmt.sbprintf(&buf, "[%s] ", data.ident)
}
//TODO(Hoej): When we have better atomics and such, make this thread-safe
fmt.fprintf(h, "%s %s\n", strings.to_string(buf), text)
fmt.fprintf(h, "%s%s\n", strings.to_string(buf), text)
}
do_level_header :: proc(opts: Options, level: Level, str: ^strings.Builder) {
+5 -6
View File
@@ -6,7 +6,6 @@ import "core:fmt"
// NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle.
Level :: runtime.Logger_Level
/*
Logger_Level :: enum {
Debug = 0,
@@ -16,8 +15,8 @@ Logger_Level :: enum {
Fatal = 40,
}
*/
Level :: runtime.Logger_Level
Option :: runtime.Logger_Option
/*
Option :: enum {
Level,
@@ -30,11 +29,12 @@ Option :: enum {
Terminal_Color
}
*/
Option :: runtime.Logger_Option
Options :: runtime.Logger_Options
/*
Options :: bit_set[Option];
*/
Options :: runtime.Logger_Options
Full_Timestamp_Opts :: Options{
.Date,
@@ -52,12 +52,11 @@ Location_File_Opts :: Options{
}
Logger_Proc :: runtime.Logger_Proc
/*
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
*/
Logger_Proc :: runtime.Logger_Proc
Logger :: runtime.Logger
/*
Logger :: struct {
procedure: Logger_Proc,
@@ -66,6 +65,7 @@ Logger :: struct {
options: Logger_Options,
}
*/
Logger :: runtime.Logger
nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
// Do nothing
@@ -75,7 +75,6 @@ nil_logger :: proc() -> Logger {
return Logger{nil_logger_proc, nil, Level.Debug, nil}
}
// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
debugf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
logf(level=.Debug, fmt_str=fmt_str, args=args, location=location)
}
+107
View File
@@ -0,0 +1,107 @@
package log
import "core:runtime"
Log_Allocator :: struct {
allocator: runtime.Allocator,
level: Level,
prefix: string,
locked: bool,
}
log_allocator_init :: proc(la: ^Log_Allocator, level: Level, allocator := context.allocator, prefix := "") {
la.allocator = allocator
la.level = level
la.prefix = prefix
la.locked = false
}
log_allocator :: proc(la: ^Log_Allocator) -> runtime.Allocator {
return runtime.Allocator{
procedure = log_allocator_proc,
data = la,
}
}
log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) {
la := (^Log_Allocator)(allocator_data)
padding := " " if la.prefix != "" else ""
if !la.locked {
la.locked = true
defer la.locked = false
switch mode {
case .Alloc:
logf(
level=la.level,
fmt_str = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)",
args = {la.prefix, padding, size, alignment},
location = location,
)
case .Free:
if old_size != 0 {
logf(
level=la.level,
fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)",
args = {la.prefix, padding, old_memory, old_size},
location = location,
)
} else {
logf(
level=la.level,
fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)",
args = {la.prefix, padding, old_memory},
location = location,
)
}
case .Free_All:
logf(
level=la.level,
fmt_str = "%s%s<<< ALLOCATOR(mode=.Free_All)",
args = {la.prefix, padding},
location = location,
)
case .Resize:
logf(
level=la.level,
fmt_str = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)",
args = {la.prefix, padding, old_memory, old_size, size, alignment},
location = location,
)
case .Query_Features:
logf(
level=la.level,
fmt_str = "%s%ALLOCATOR(mode=.Query_Features)",
args = {la.prefix, padding},
location = location,
)
case .Query_Info:
logf(
level=la.level,
fmt_str = "%s%ALLOCATOR(mode=.Query_Info)",
args = {la.prefix, padding},
location = location,
)
}
}
data, err := la.allocator.procedure(la.allocator.data, mode, size, alignment, old_memory, old_size, location)
if !la.locked {
la.locked = true
defer la.locked = false
if err != nil {
logf(
level=la.level,
fmt_str = "%s%ALLOCATOR ERROR=%v",
args = {la.prefix, padding, error},
location = location,
)
}
}
return data, err
}
+1 -1
View File
@@ -449,7 +449,7 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra
in the loop is non-zero, although very low.
-- NOTE(Jeroen): This is not yet true in Odin, but I have some ideas.
If the BPSW test and/or the addtional Frobenious test have been
If the BPSW test and/or the additional Frobenious test have been
performed instead of just the Miller-Rabin test with the bases 2 and 3,
a single extra test should suffice, so such a very unlikely event will not do much harm.
+1 -1
View File
@@ -356,7 +356,7 @@ Flux_Tween :: struct($T: typeid) {
flux_init :: proc($T: typeid, value_capacity := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) {
return {
values = make(map[^T]Flux_Tween(T), value_capacity),
keys_to_be_deleted = make([dynamic]^T, 0, value_capacity)
keys_to_be_deleted = make([dynamic]^T, 0, value_capacity),
}
}
+3 -3
View File
@@ -94,7 +94,7 @@ quaternion_cross :: proc(q1, q2: $Q) -> (q3: Q) where IS_QUATERNION(Q) {
vector_cross :: proc{scalar_cross, vector_cross2, vector_cross3}
cross :: proc{scalar_cross, vector_cross2, vector_cross3, quaternion_cross}
vector_normalize :: proc(v: $T/[$N]$E) -> T where IS_NUMERIC(E) {
vector_normalize :: proc(v: $T/[$N]$E) -> T where IS_FLOAT(E) {
return v / length(v)
}
quaternion_normalize :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
@@ -102,7 +102,7 @@ quaternion_normalize :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
}
normalize :: proc{vector_normalize, quaternion_normalize}
vector_normalize0 :: proc(v: $T/[$N]$E) -> T where IS_NUMERIC(E) {
vector_normalize0 :: proc(v: $T/[$N]$E) -> T where IS_FLOAT(E) {
m := length(v)
return 0 if m == 0 else v/m
}
@@ -113,7 +113,7 @@ quaternion_normalize0 :: proc(q: $Q) -> Q where IS_QUATERNION(Q) {
normalize0 :: proc{vector_normalize0, quaternion_normalize0}
vector_length :: proc(v: $T/[$N]$E) -> E where IS_NUMERIC(E) {
vector_length :: proc(v: $T/[$N]$E) -> E where IS_FLOAT(E) {
return math.sqrt(dot(v, v))
}
+36 -10
View File
@@ -185,16 +185,23 @@ log :: proc{
log_f64, log_f64le, log_f64be,
}
log2_f16 :: logb_f16
log2_f16le :: logb_f16le
log2_f16be :: logb_f16be
log2_f32 :: logb_f32
log2_f32le :: logb_f32le
log2_f32be :: logb_f32be
log2_f64 :: logb_f64
log2_f64le :: logb_f64le
log2_f64be :: logb_f64be
log2 :: logb
log2_f16 :: proc "contextless" (x: f16) -> f16 { return log(f16(x), f16(2.0)) }
log2_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log_f16(f16(x), f16(2.0))) }
log2_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log_f16(f16(x), f16(2.0))) }
log2_f32 :: proc "contextless" (x: f32) -> f32 { return log(f32(x), f32(2.0)) }
log2_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log_f32(f32(x), f32(2.0))) }
log2_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log_f32(f32(x), f32(2.0))) }
log2_f64 :: proc "contextless" (x: f64) -> f64 { return log(f64(x), f64(2.0)) }
log2_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log_f64(f64(x), f64(2.0))) }
log2_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log_f64(f64(x), f64(2.0))) }
log2 :: proc{
log2_f16, log2_f16le, log2_f16be,
log2_f32, log2_f32le, log2_f32be,
log2_f64, log2_f64le, log2_f64be,
}
log10_f16 :: proc "contextless" (x: f16) -> f16 { return ln(x)/LN10 }
log10_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log10_f16(f16(x))) }
@@ -607,6 +614,25 @@ floor_mod :: proc "contextless" (x, y: $T) -> T
return r
}
divmod :: #force_inline proc "contextless" (x, y: $T) -> (div, mod: T)
where intrinsics.type_is_integer(T) {
div = x / y
mod = x % y
return
}
floor_divmod :: #force_inline proc "contextless" (x, y: $T) -> (div, mod: T)
where intrinsics.type_is_integer(T) {
div = x / y
mod = x % y
if (div > 0 && y < 0) || (mod < 0 && y > 0) {
div -= 1
mod += y
}
return
}
modf_f16 :: proc "contextless" (x: f16) -> (int: f16, frac: f16) {
shift :: F16_SHIFT
mask :: F16_MASK
+9 -85
View File
@@ -61,114 +61,38 @@ DEFAULT_PAGE_SIZE ::
4 * 1024
alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
if size == 0 {
return nil
}
if allocator.procedure == nil {
return nil
}
data, err := allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, loc)
_ = err
data, _ := runtime.mem_alloc(size, alignment, allocator, loc)
return raw_data(data)
}
alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if size == 0 {
return nil, nil
}
if allocator.procedure == nil {
return nil, nil
}
return allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, loc)
return runtime.mem_alloc(size, alignment, allocator, loc)
}
free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if ptr == nil {
return nil
}
if allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, 0, loc)
return err
return runtime.mem_free(ptr, allocator, loc)
}
free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if bytes == nil {
return nil
}
if allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, raw_data(bytes), len(bytes), loc)
return err
return runtime.mem_free_bytes(bytes, allocator, loc)
}
free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if allocator.procedure != nil {
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free_All, 0, 0, nil, 0, loc)
return err
}
return nil
return runtime.mem_free_all(allocator, loc)
}
resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
if allocator.procedure == nil {
return nil
}
if new_size == 0 {
if ptr != nil {
allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
}
return nil
} else if ptr == nil {
_, err := allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
_ = err
return nil
}
data, err := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, loc)
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
if err != nil {
return nil
}
runtime.copy(data, byte_slice(ptr, old_size))
_, err = allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
return raw_data(data)
}
data, _ := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
return raw_data(data)
}
resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if allocator.procedure == nil {
return nil, nil
}
ptr := raw_data(old_data)
old_size := len(old_data)
if new_size == 0 {
if ptr != nil {
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
return nil, err
}
return nil, nil
} else if ptr == nil {
return allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
}
data, err := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, loc)
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
if err != nil {
return data, err
}
runtime.copy(data, old_data)
_, err = allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
}
return data, err
return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
}
query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
if allocator.procedure != nil {
allocator.procedure(allocator.data, Allocator_Mode.Query_Features, 0, 0, &set, 0, loc)
allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc)
return set
}
return nil
@@ -177,7 +101,7 @@ query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: A
query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) {
props.pointer = pointer
if allocator.procedure != nil {
allocator.procedure(allocator.data, Allocator_Mode.Query_Info, 0, 0, &props, 0, loc)
allocator.procedure(allocator.data, .Query_Info, 0, 0, &props, 0, loc)
}
return
}
+29 -6
View File
@@ -31,6 +31,14 @@ Arena_Temp_Memory :: struct {
}
arena_init :: proc(a: ^Arena, data: []byte) {
a.data = data
a.offset = 0
a.peak_used = 0
a.temp_count = 0
}
@(deprecated="prefer 'mem.arena_init'")
init_arena :: proc(a: ^Arena, data: []byte) {
a.data = data
a.offset = 0
@@ -293,6 +301,14 @@ Stack :: struct {
peak_used: int,
}
stack_init :: proc(s: ^Stack, data: []byte) {
s.data = data
s.prev_offset = 0
s.curr_offset = 0
s.peak_used = 0
}
@(deprecated="prefer 'mem.stack_init'")
init_stack :: proc(s: ^Stack, data: []byte) {
s.data = data
s.prev_offset = 0
@@ -445,27 +461,34 @@ Small_Stack_Allocation_Header :: struct {
// Small_Stack is a stack-like allocator which uses the smallest possible header but at the cost of non-strict memory freeing order
Small_Stack :: struct {
data: []byte,
offset: int,
data: []byte,
offset: int,
peak_used: int,
}
small_stack_init :: proc(s: ^Small_Stack, data: []byte) {
s.data = data
s.offset = 0
s.peak_used = 0
}
@(deprecated="prefer 'small_stack_init'")
init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
s.data = data
s.offset = 0
s.data = data
s.offset = 0
s.peak_used = 0
}
small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
return Allocator{
procedure = small_stack_allocator_proc,
data = stack,
data = stack,
}
}
small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, ocation := #caller_location) -> ([]byte, Allocator_Error) {
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, Allocator_Error) {
s := cast(^Small_Stack)allocator_data
if s.data == nil {
+1 -42
View File
@@ -54,48 +54,7 @@ compare :: proc "contextless" (a, b: []byte) -> int {
}
compare_byte_ptrs :: proc "contextless" (a, b: ^byte, n: int) -> int #no_bounds_check {
switch {
case a == b:
return 0
case a == nil:
return -1
case b == nil:
return -1
case n == 0:
return 0
}
x := slice_ptr(a, n)
y := slice_ptr(b, n)
SU :: size_of(uintptr)
fast := n/SU + 1
offset := (fast-1)*SU
curr_block := 0
if n < SU {
fast = 0
}
la := slice_ptr((^uintptr)(a), fast)
lb := slice_ptr((^uintptr)(b), fast)
for /**/; curr_block < fast; curr_block += 1 {
if la[curr_block] ~ lb[curr_block] != 0 {
for pos := curr_block*SU; pos < n; pos += 1 {
if x[pos] ~ y[pos] != 0 {
return (int(x[pos]) - int(y[pos])) < 0 ? -1 : +1
}
}
}
}
for /**/; offset < n; offset += 1 {
if x[offset] ~ y[offset] != 0 {
return (int(x[offset]) - int(y[offset])) < 0 ? -1 : +1
}
}
return 0
return runtime.memory_compare(a, b, n)
}
check_zero :: proc(data: []byte) -> bool {
+1
View File
@@ -8,6 +8,7 @@ Raw_Cstring :: runtime.Raw_Cstring
Raw_Slice :: runtime.Raw_Slice
Raw_Dynamic_Array :: runtime.Raw_Dynamic_Array
Raw_Map :: runtime.Raw_Map
Raw_Soa_Pointer :: runtime.Raw_Soa_Pointer
Raw_Complex64 :: struct {real, imag: f32}
Raw_Complex128 :: struct {real, imag: f64}
+5
View File
@@ -1,5 +1,10 @@
package mem_virtual
arena_init :: proc{
static_arena_init,
growing_arena_init,
}
arena_temp_begin :: proc{
static_arena_temp_begin,
growing_arena_temp_begin,
+11 -4
View File
@@ -13,6 +13,13 @@ Growing_Arena :: struct {
DEFAULT_MINIMUM_BLOCK_SIZE :: 1<<20 // 1 MiB should be enough
growing_arena_init :: proc(arena: ^Growing_Arena, reserved: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
arena.curr_block = memory_block_alloc(0, reserved, {}) or_return
arena.total_used = 0
arena.total_reserved = arena.curr_block.reserved
return
}
growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
align_forward_offset :: proc "contextless" (arena: ^Growing_Arena, alignment: int) -> uint #no_bounds_check {
alignment_offset := uint(0)
@@ -37,7 +44,7 @@ growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int
block_size := max(size, arena.minimum_block_size)
new_block := memory_block_alloc(block_size, block_size, {}) or_return
new_block := memory_block_alloc(size, block_size, {}) or_return
new_block.prev = arena.curr_block
arena.curr_block = new_block
arena.total_reserved += new_block.reserved
@@ -95,9 +102,9 @@ growing_arena_allocator :: proc(arena: ^Growing_Arena) -> mem.Allocator {
}
growing_arena_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int,
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
size, alignment: int,
old_memory: rawptr, old_size: int,
location := #caller_location) -> (data: []byte, err: Allocator_Error) {
arena := (^Growing_Arena)(allocator_data)
switch mode {
+1 -1
View File
@@ -48,7 +48,7 @@ munmap :: proc "contextless" (addr: rawptr, length: uint) -> c.int {
}
mprotect :: proc "contextless" (addr: rawptr, length: uint, prot: c.int) -> c.int {
res := intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uint(prot))
res := intrinsics.syscall(unix.SYS_mprotect, uintptr(addr), uintptr(length), uintptr(prot))
return c.int(res)
}
+1
View File
@@ -700,6 +700,7 @@ Proc_Type :: struct {
Pointer_Type :: struct {
using node: Expr,
tag: ^Expr,
pointer: tokenizer.Pos,
elem: ^Expr,
}
+1
View File
@@ -286,6 +286,7 @@ clone_node :: proc(node: ^Node) -> ^Node {
r.results = auto_cast clone(r.results)
case ^Pointer_Type:
r.elem = clone(r.elem)
r.tag = clone(r.tag)
case ^Multi_Pointer_Type:
r.elem = clone(r.elem)
case ^Array_Type:
+2
View File
@@ -186,6 +186,7 @@ Type_Kind :: enum u32le {
Relative_Slice = 21,
Multi_Pointer = 22,
Matrix = 23,
Soa_Pointer = 24,
}
Type_Elems_Cap :: 4
@@ -245,6 +246,7 @@ Type :: struct {
// .Relative_Slice - 2 types: 0=slice type, 1=base integer
// .Multi_Pointer - 1 type: 0=element
// .Matrix - 1 type: 0=element
// .Soa_Pointer - 1 type: 0=element
types: Array(Type_Index),
// Used by:
+16 -7
View File
@@ -245,12 +245,7 @@ peek_token :: proc(p: ^Parser, lookahead := 0) -> (tok: tokenizer.Token) {
return
}
skip_possible_newline :: proc(p: ^Parser) -> bool {
if .Optional_Semicolons not_in p.flags {
return false
}
prev := p.curr_tok
if tokenizer.is_newline(prev) {
if tokenizer.is_newline(p.curr_tok) {
advance_token(p)
return true
}
@@ -2235,7 +2230,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
return parse_call_expr(p, bd)
case "soa", "simd":
case "soa":
bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
bd.tok = tok
bd.name = name.text
@@ -2244,6 +2239,20 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
#partial switch t in type.derived_expr {
case ^ast.Array_Type: t.tag = bd
case ^ast.Dynamic_Array_Type: t.tag = bd
case ^ast.Pointer_Type: t.tag = bd
case:
error(p, original_type.pos, "expected an array or pointer type after #%s", name.text)
}
return original_type
case "simd":
bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
bd.tok = tok
bd.name = name.text
original_type := parse_type(p)
type := ast.unparen_expr(original_type)
#partial switch t in type.derived_expr {
case ^ast.Array_Type: t.tag = bd
case:
error(p, original_type.pos, "expected an array type after #%s", name.text)
}
+10 -10
View File
@@ -6,19 +6,19 @@ import "core:runtime"
user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Windows:
dir = get_env("LocalAppData")
dir = get_env("LocalAppData", allocator)
if dir != "" {
dir = strings.clone_safe(dir, allocator) or_return
}
case .Darwin:
dir = get_env("HOME")
dir = get_env("HOME", allocator)
if dir != "" {
dir = strings.concatenate_safe({dir, "/Library/Caches"}, allocator) or_return
}
case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME")
dir = get_env("XDG_CACHE_HOME", allocator)
if dir == "" {
dir = get_env("HOME")
dir = get_env("HOME", allocator)
if dir == "" {
return
}
@@ -34,19 +34,19 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS {
case .Windows:
dir = get_env("AppData")
dir = get_env("AppData", allocator)
if dir != "" {
dir = strings.clone_safe(dir, allocator) or_return
}
case .Darwin:
dir = get_env("HOME")
dir = get_env("HOME", allocator)
if dir != "" {
dir = strings.concatenate_safe({dir, "/Library/Application Support"}, allocator) or_return
}
case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME")
dir = get_env("XDG_CACHE_HOME", allocator)
if dir == "" {
dir = get_env("HOME")
dir = get_env("HOME", allocator)
if dir == "" {
return
}
@@ -59,13 +59,13 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro
return
}
user_home_dir :: proc() -> (dir: string, err: Error) {
user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
env := "HOME"
#partial switch ODIN_OS {
case .Windows:
env = "USERPROFILE"
}
if v := get_env(env); v != "" {
if v := get_env(env, allocator); v != "" {
return v, nil
}
return "", .Invalid_Path
+1 -1
View File
@@ -311,7 +311,7 @@ _unix_seek :: proc(fd: Handle, offset: i64, whence: int) -> i64 {
low := uintptr(offset & 0xFFFFFFFF)
high := uintptr(offset >> 32)
result: i64
res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence)))
res := i64(intrinsics.syscall(unix.SYS__llseek, uintptr(fd), high, low, uintptr(&result), uintptr(whence)))
return -1 if res < 0 else result
}
}
+39 -24
View File
@@ -1,7 +1,6 @@
package reflect
import "core:runtime"
import "core:mem"
import "core:intrinsics"
_ :: intrinsics
@@ -34,6 +33,7 @@ Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer
Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice
Type_Info_Matrix :: runtime.Type_Info_Matrix
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value
@@ -68,6 +68,7 @@ Type_Kind :: enum {
Relative_Pointer,
Relative_Slice,
Matrix,
Soa_Pointer,
}
@@ -102,6 +103,7 @@ type_kind :: proc(T: typeid) -> Type_Kind {
case Type_Info_Relative_Pointer: return .Relative_Pointer
case Type_Info_Relative_Slice: return .Relative_Slice
case Type_Info_Matrix: return .Matrix
case Type_Info_Soa_Pointer: return .Soa_Pointer
}
}
@@ -194,6 +196,7 @@ typeid_elem :: proc(id: typeid) -> typeid {
}
case Type_Info_Pointer: return v.elem.id
case Type_Info_Multi_Pointer: return v.elem.id
case Type_Info_Soa_Pointer: return v.elem.id
case Type_Info_Array: return v.elem.id
case Type_Info_Enumerated_Array: return v.elem.id
case Type_Info_Slice: return v.elem.id
@@ -220,7 +223,7 @@ align_of_typeid :: proc(T: typeid) -> int {
as_bytes :: proc(v: any) -> []byte {
if v != nil {
sz := size_of_typeid(v.id)
return mem.slice_ptr((^byte)(v.data), sz)
return ([^]byte)(v.data)[:sz]
}
return nil
}
@@ -262,19 +265,19 @@ length :: proc(val: any) -> int {
return a.count
case Type_Info_Slice:
return (^mem.Raw_Slice)(val.data).len
return (^runtime.Raw_Slice)(val.data).len
case Type_Info_Dynamic_Array:
return (^mem.Raw_Dynamic_Array)(val.data).len
return (^runtime.Raw_Dynamic_Array)(val.data).len
case Type_Info_Map:
return (^mem.Raw_Map)(val.data).entries.len
return (^runtime.Raw_Map)(val.data).entries.len
case Type_Info_String:
if a.is_cstring {
return len((^cstring)(val.data)^)
} else {
return (^mem.Raw_String)(val.data).len
return (^runtime.Raw_String)(val.data).len
}
}
return 0
@@ -297,10 +300,10 @@ capacity :: proc(val: any) -> int {
return a.count
case Type_Info_Dynamic_Array:
return (^mem.Raw_Dynamic_Array)(val.data).cap
return (^runtime.Raw_Dynamic_Array)(val.data).cap
case Type_Info_Map:
return (^mem.Raw_Map)(val.data).entries.cap
return (^runtime.Raw_Map)(val.data).entries.cap
}
return 0
}
@@ -340,14 +343,14 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
return any{data, a.elem.id}
case Type_Info_Slice:
raw := (^mem.Raw_Slice)(val.data)
raw := (^runtime.Raw_Slice)(val.data)
runtime.bounds_check_error_loc(loc, i, raw.len)
offset := uintptr(a.elem.size * i)
data := rawptr(uintptr(raw.data) + offset)
return any{data, a.elem.id}
case Type_Info_Dynamic_Array:
raw := (^mem.Raw_Dynamic_Array)(val.data)
raw := (^runtime.Raw_Dynamic_Array)(val.data)
runtime.bounds_check_error_loc(loc, i, raw.len)
offset := uintptr(a.elem.size * i)
data := rawptr(uintptr(raw.data) + offset)
@@ -356,7 +359,7 @@ index :: proc(val: any, i: int, loc := #caller_location) -> any {
case Type_Info_String:
if a.is_cstring { return nil }
raw := (^mem.Raw_String)(val.data)
raw := (^runtime.Raw_String)(val.data)
runtime.bounds_check_error_loc(loc, i, raw.len)
offset := uintptr(size_of(u8) * i)
data := rawptr(uintptr(raw.data) + offset)
@@ -725,6 +728,17 @@ get_union_variant_raw_tag :: proc(a: any) -> i64 {
panic("expected a union to reflect.get_union_variant_raw_tag")
}
get_union_variant :: proc(a: any) -> any {
if a == nil {
return nil
}
id := union_variant_typeid(a)
if id == nil {
return nil
}
return any{a.data, id}
}
set_union_variant_raw_tag :: proc(a: any, tag: i64) {
if a == nil { return }
@@ -822,17 +836,17 @@ set_union_value :: proc(dst: any, value: any) -> bool {
ti := runtime.type_info_base(type_info_of(dst.id))
if info, ok := ti.variant.(runtime.Type_Info_Union); ok {
if value.id == nil {
mem.zero(dst.data, ti.size)
intrinsics.mem_zero(dst.data, ti.size)
return true
}
if ti.id == runtime.typeid_base(value.id) {
mem.copy(dst.data, value.data, ti.size)
intrinsics.mem_copy(dst.data, value.data, ti.size)
return true
}
if type_info_union_is_pure_maybe(info) {
if variant := info.variants[0]; variant.id == value.id {
mem.copy(dst.data, value.data, variant.size)
intrinsics.mem_copy(dst.data, value.data, variant.size)
return true
}
return false
@@ -844,7 +858,7 @@ set_union_value :: proc(dst: any, value: any) -> bool {
if !info.no_nil {
tag += 1
}
mem.copy(dst.data, value.data, variant.size)
intrinsics.mem_copy(dst.data, value.data, variant.size)
set_union_variant_raw_tag(dst, tag)
return true
}
@@ -1337,11 +1351,11 @@ as_raw_data :: proc(a: any) -> (value: rawptr, valid: bool) {
case Type_Info_Slice:
valid = true
value = (^mem.Raw_Slice)(a.data).data
value = (^runtime.Raw_Slice)(a.data).data
case Type_Info_Dynamic_Array:
valid = true
value = (^mem.Raw_Dynamic_Array)(a.data).data
value = (^runtime.Raw_Dynamic_Array)(a.data).data
}
return
@@ -1383,7 +1397,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
}
if .Simple_Compare in t.flags {
return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0
return runtime.memory_compare(a.data, b.data, t.size) == 0
}
t = runtime.type_info_core(t)
@@ -1419,8 +1433,9 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
Type_Info_Enum,
Type_Info_Simd_Vector,
Type_Info_Relative_Pointer,
Type_Info_Soa_Pointer,
Type_Info_Matrix:
return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0
return runtime.memory_compare(a.data, b.data, t.size) == 0
case Type_Info_String:
if v.is_cstring {
@@ -1474,8 +1489,8 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
if !including_indirect_array_recursion {
return false
}
array_a := (^mem.Raw_Slice)(a.data)
array_b := (^mem.Raw_Slice)(b.data)
array_a := (^runtime.Raw_Slice)(a.data)
array_b := (^runtime.Raw_Slice)(b.data)
if array_a.len != array_b.len {
return false
}
@@ -1494,8 +1509,8 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
if !including_indirect_array_recursion {
return false
}
array_a := (^mem.Raw_Dynamic_Array)(a.data)
array_b := (^mem.Raw_Dynamic_Array)(b.data)
array_a := (^runtime.Raw_Dynamic_Array)(a.data)
array_b := (^runtime.Raw_Dynamic_Array)(b.data)
if array_a.len != array_b.len {
return false
}
@@ -1503,7 +1518,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
return true
}
if .Simple_Compare in v.elem.flags {
return mem.compare_byte_ptrs((^byte)(array_a.data), (^byte)(array_b.data), array_a.len * v.elem.size) == 0
return runtime.memory_compare((^byte)(array_a.data), (^byte)(array_b.data), array_a.len * v.elem.size) == 0
}
for i in 0..<array_a.len {
+18
View File
@@ -68,6 +68,11 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
y := b.variant.(Type_Info_Multi_Pointer) or_return
return are_types_identical(x.elem, y.elem)
case Type_Info_Soa_Pointer:
y := b.variant.(Type_Info_Soa_Pointer) or_return
return are_types_identical(x.elem, y.elem)
case Type_Info_Procedure:
y := b.variant.(Type_Info_Procedure) or_return
switch {
@@ -256,6 +261,11 @@ is_multi_pointer :: proc(info: ^Type_Info) -> bool {
_, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer)
return ok
}
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
}
is_pointer_internally :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
#partial switch v in info.variant {
@@ -292,6 +302,11 @@ is_dynamic_map :: proc(info: ^Type_Info) -> bool {
_, ok := type_info_base(info).variant.(Type_Info_Map)
return ok
}
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
}
is_slice :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Slice)
@@ -437,6 +452,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
case Type_Info_Multi_Pointer:
io.write_string(w, "[^]", &n) or_return
write_type(w, info.elem, &n) or_return
case Type_Info_Soa_Pointer:
io.write_string(w, "#soa ^", &n) or_return
write_type(w, info.elem, &n) or_return
case Type_Info_Procedure:
io.write_string(w, "proc", &n) or_return
if info.params == nil {
+10
View File
@@ -176,6 +176,9 @@ Type_Info_Matrix :: struct {
column_count: int,
// Total element count = column_count * elem_stride
}
Type_Info_Soa_Pointer :: struct {
elem: ^Type_Info,
}
Type_Info_Flag :: enum u8 {
Comparable = 0,
@@ -217,6 +220,7 @@ Type_Info :: struct {
Type_Info_Relative_Pointer,
Type_Info_Relative_Slice,
Type_Info_Matrix,
Type_Info_Soa_Pointer,
},
}
@@ -403,6 +407,12 @@ Raw_Cstring :: struct {
data: [^]byte,
}
Raw_Soa_Pointer :: struct {
data: rawptr,
index: int,
}
/*
// Defined internally by the compiler
+32 -31
View File
@@ -143,7 +143,7 @@ free_all :: proc{mem_free_all}
@builtin
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free(raw_data(str), allocator, loc)
return mem_free_with_size(raw_data(str), len(str), allocator, loc)
}
@builtin
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
@@ -151,17 +151,24 @@ delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #cal
}
@builtin
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
return mem_free(raw_data(array), array.allocator, loc)
return mem_free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc)
}
@builtin
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free(raw_data(array), allocator, loc)
return mem_free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc)
}
@builtin
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
Entry :: struct {
hash: uintptr,
next: int,
key: K,
value: V,
}
raw := transmute(Raw_Map)m
err := delete_slice(raw.hashes, raw.entries.allocator, loc)
err1 := mem_free(raw.entries.data, raw.entries.allocator, loc)
err1 := mem_free_with_size(raw.entries.data, raw.entries.cap*size_of(Entry), raw.entries.allocator, loc)
if err == nil {
err = err1
}
@@ -335,12 +342,13 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
@builtin
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) -> int {
if array == nil {
return
return 0
}
when size_of(E) == 0 {
a.len += 1
array.len += 1
return 1
} else {
if cap(array) < len(array)+1 {
cap := 2 * cap(array) + max(8, 1)
@@ -354,23 +362,26 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
data[a.len] = arg
}
a.len += 1
return 1
}
return 0
}
}
@builtin
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) {
append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location) -> int {
if array == nil {
return
return 0
}
arg_len := len(args)
if arg_len <= 0 {
return
return 0
}
when size_of(E) == 0 {
a.len += arg_len
array.len += arg_len
return arg_len
} else {
if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len)
@@ -386,23 +397,25 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
}
a.len += arg_len
}
return arg_len
}
}
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
@builtin
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) {
append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, loc := #caller_location) -> int {
args := transmute([]E)arg
append_elems(array=array, args=args, loc=loc)
return append_elems(array=array, args=args, loc=loc)
}
// The append_string built-in procedure appends multiple strings to the end of a [dynamic]u8 like type
@builtin
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) {
append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_location) -> (n: int) {
for arg in args {
append(array = array, args = transmute([]E)(arg), loc = loc)
n += append(array = array, args = transmute([]E)(arg), loc = loc)
}
return
}
// The append built-in procedure appends elements to the end of a dynamic array
@@ -410,11 +423,13 @@ append_string :: proc(array: ^$T/[dynamic]$E/u8, args: ..string, loc := #caller_
@builtin
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) {
append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) -> int {
if array == nil {
return
return 0
}
prev_len := len(array)
resize(array, len(array)+1)
return len(array)-prev_len
}
@@ -785,17 +800,3 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! {
}
p("not yet implemented", message, loc)
}
@builtin
@(disabled=ODIN_DISABLE_ASSERT)
unreachable :: proc(message := "", loc := #caller_location) -> ! {
p := context.assertion_failure_proc
if p == nil {
p = default_assertion_failure_proc
}
if message != "" {
p("internal error", message, loc)
} else {
p("internal error", "entered unreachable code", loc)
}
}
+7 -3
View File
@@ -29,11 +29,15 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
new_size := cap * elem_size
allocator := array.allocator
new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc)
new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc)
if err != nil {
return false
}
if new_data != nil || elem_size == 0 {
if elem_size == 0 {
array.data = raw_data(new_data)
array.cap = cap
return true
} else if new_data != nil {
array.data = raw_data(new_data)
array.cap = min(cap, len(new_data)/elem_size)
return true
@@ -59,7 +63,7 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c
new_size := new_cap * elem_size
allocator := array.allocator
new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc)
new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc)
if err != nil {
return
}
+8 -5
View File
@@ -194,12 +194,15 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l
new_size := new_count*size_of(T)
new_data, err := mem_resize(array.data, old_size, new_size, align_of(T), allocator, loc)
if new_data == nil || err != nil {
if err != nil {
return false
}
array.data = new_data
array.len = new_count
return true
if new_data != nil || size_of(E) == 0 {
array.data = raw_data(new_data)
array.len = new_count
return true
}
return false
}
__dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) {
@@ -207,7 +210,7 @@ __dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_loc
m.hashes[i] = -1
}
for i in 0 ..< m.entries.len {
for i in 0..<m.entries.len {
entry_header := __dynamic_map_get_entry(header, i)
entry_hash := __get_map_hash_from_entry(header, entry_header)
entry_header.next = -1
+61 -37
View File
@@ -103,7 +103,7 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
if data == nil {
return nil
}
if len < 0 {
if len <= 0 {
return data
}
intrinsics.mem_zero(data, len)
@@ -111,22 +111,18 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
}
mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil {
return dst
if src != nil && dst != src && len > 0 {
// NOTE(bill): This _must_ be implemented like C's memmove
intrinsics.mem_copy(dst, src, len)
}
// NOTE(bill): This _must_ be implemented like C's memmove
intrinsics.mem_copy(dst, src, len)
return dst
}
mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil {
return dst
if src != nil && dst != src && len > 0 {
// NOTE(bill): This _must_ be implemented like C's memcpy
intrinsics.mem_copy_non_overlapping(dst, src, len)
}
// NOTE(bill): This _must_ be implemented like C's memcpy
intrinsics.mem_copy_non_overlapping(dst, src, len)
return dst
}
@@ -142,28 +138,38 @@ mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNM
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
}
mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) {
if size == 0 {
mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if size == 0 || allocator.procedure == nil {
return nil, nil
}
if allocator.procedure == nil {
return nil, nil
}
data, err := allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
return raw_data(data), err
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
}
mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if ptr == nil {
return .None
}
if allocator.procedure == nil {
return .None
if ptr == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc)
return err
}
mem_free_with_size :: #force_inline proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if ptr == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, byte_count, loc)
return err
}
mem_free_bytes :: #force_inline proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if bytes == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, raw_data(bytes), len(bytes), loc)
return err
}
mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) {
if allocator.procedure != nil {
_, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc)
@@ -171,21 +177,34 @@ mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #calle
return
}
mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (new_ptr: rawptr, err: Allocator_Error) {
new_data: []byte
switch {
case allocator.procedure == nil:
return
case new_size == 0:
new_data, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc)
case ptr == nil:
new_data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
case:
new_data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if allocator.procedure == nil {
return nil, nil
}
new_ptr = raw_data(new_data)
return
if new_size == 0 {
if ptr != nil {
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
return nil, err
}
return nil, nil
} else if ptr == nil {
return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
} else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 {
return ([^]byte)(ptr)[:old_size], nil
}
data, err := allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
if err != nil {
return data, err
}
copy(data, ([^]byte)(ptr)[:old_size])
_, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
}
return data, err
}
memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
switch {
case n == 0: return true
@@ -341,7 +360,12 @@ string_eq :: proc "contextless" (lhs, rhs: string) -> bool {
string_cmp :: proc "contextless" (a, b: string) -> int {
x := transmute(Raw_String)a
y := transmute(Raw_String)b
return memory_compare(x.data, y.data, min(x.len, y.len))
ret := memory_compare(x.data, y.data, min(x.len, y.len))
if ret == 0 && x.len != y.len {
return -1 if x.len < y.len else +1
}
return ret
}
string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b) }
+3
View File
@@ -228,6 +228,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
case Type_Info_Multi_Pointer:
print_string("[^]")
print_type(info.elem)
case Type_Info_Soa_Pointer:
print_string("#soa ^")
print_type(info.elem)
case Type_Info_Procedure:
print_string("proc")
if info.params == nil {
+19 -9
View File
@@ -6,7 +6,7 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
@(private="file")
@(default_calling_convention="stdcall")
foreign lib {
RtlMoveMemory :: proc(dst, src: rawptr, length: int) ---
RtlMoveMemory :: proc(dst, s: rawptr, length: int) ---
RtlFillMemory :: proc(dst: rawptr, length: int, fill: i32) ---
}
@@ -40,24 +40,34 @@ when ODIN_NO_CRT && ODIN_OS == .Windows {
@(link_name="memmove", linkage="strong", require)
memmove :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
if dst != src {
d, s := ([^]byte)(dst), ([^]byte)(src)
d, s := ([^]byte)(dst), ([^]byte)(src)
if d == s || len == 0 {
return dst
}
if d > s && uintptr(d)-uintptr(s) < uintptr(len) {
for i := len-1; i >= 0; i -= 1 {
d[i] = s[i]
}
return dst
}
return dst
if s > d && uintptr(s)-uintptr(d) < uintptr(len) {
for i := 0; i < len; i += 1 {
d[i] = s[i]
}
return dst
}
return memcpy(dst, src, len)
}
@(link_name="memcpy", linkage="strong", require)
memcpy :: proc "c" (dst, src: rawptr, len: int) -> rawptr {
if dst != src {
d, s := ([^]byte)(dst), ([^]byte)(src)
for i := len-1; i >= 0; i -= 1 {
d, s := ([^]byte)(dst), ([^]byte)(src)
if d != s {
for i := 0; i < len; i += 1 {
d[i] = s[i]
}
}
return dst
return d
}
} else {
+2 -2
View File
@@ -14,14 +14,14 @@ _ :: mem
Turn a pointer and a length into a slice.
*/
from_ptr :: proc "contextless" (ptr: ^$T, count: int) -> []T {
return ([^]T)(ptr)[:count]
return ([^]T)(ptr)[:count]
}
/*
Turn a pointer and a length into a byte slice.
*/
bytes_from_ptr :: proc "contextless" (ptr: rawptr, byte_count: int) -> []byte {
return ([^]byte)(ptr)[:byte_count]
return ([^]byte)(ptr)[:byte_count]
}
/*
+62
View File
@@ -38,6 +38,52 @@ sort :: proc(data: $T/[]$E) where ORD(E) {
}
}
sort_by_indices :: proc{ sort_by_indices_allocate, _sort_by_indices}
sort_by_indices_allocate :: proc(data: $T/[]$E, indices: []int, allocator := context.allocator) -> (sorted: T) {
assert(len(data) == len(indices))
sorted = make([]int, len(data), allocator)
for v, i in indices {
sorted[i] = data[v]
}
return
}
_sort_by_indices :: proc(data, sorted: $T/[]$E, indices: []int) {
assert(len(data) == len(indices))
assert(len(data) == len(sorted))
for v, i in indices {
sorted[i] = data[v]
}
}
sort_by_indices_overwrite :: proc(data: $T/[]$E, indices: []int) {
assert(len(data) == len(indices))
temp := make([]int, len(data), context.allocator)
defer delete(temp)
for v, i in indices {
temp[i] = data[v]
}
swap_with_slice(data, temp)
}
// sort sorts a slice and returns a slice of the original indices
// This sort is not guaranteed to be stable
sort_with_indices :: proc(data: $T/[]$E, allocator := context.allocator) -> (indices: []int) where ORD(E) {
indices = make([]int, len(data), allocator)
when size_of(E) != 0 {
if n := len(data); n > 1 {
for _, idx in indices {
indices[idx] = idx
}
_quick_sort_general_with_indices(data, indices, 0, n, _max_depth(n), struct{}{}, .Ordered)
}
return indices
}
return indices
}
// sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j"
// This sort is not guaranteed to be stable
sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
@@ -48,6 +94,22 @@ sort_by :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool) {
}
}
// sort_by sorts a slice with a given procedure to test whether two values are ordered "i < j"
// This sort is not guaranteed to be stable
sort_by_with_indices :: proc(data: $T/[]$E, less: proc(i, j: E) -> bool, allocator := context.allocator) -> (indices : []int) {
indices = make([]int, len(data), allocator)
when size_of(E) != 0 {
if n := len(data); n > 1 {
for _, idx in indices {
indices[idx] = idx
}
_quick_sort_general_with_indices(data, indices, 0, n, _max_depth(n), less, .Less)
return indices
}
}
return indices
}
sort_by_cmp :: proc(data: $T/[]$E, cmp: proc(i, j: E) -> Ordering) {
when size_of(E) != 0 {
if n := len(data); n > 1 {
+177
View File
@@ -198,3 +198,180 @@ _stable_sort_general :: proc(data: $T/[]$E, call: $P, $KIND: Sort_Kind) where (O
}
}
}
_quick_sort_general_with_indices :: proc(data: $T/[]$E, indices: []int, a, b, max_depth: int, call: $P, $KIND: Sort_Kind) where (ORD(E) && KIND == .Ordered) || (KIND != .Ordered) #no_bounds_check {
less :: #force_inline proc(a, b: E, call: P) -> bool {
when KIND == .Ordered {
return a < b
} else when KIND == .Less {
return call(a, b)
} else when KIND == .Cmp {
return call(a, b) == .Less
} else {
#panic("unhandled Sort_Kind")
}
}
insertion_sort :: proc(data: $T/[]$E, indices: []int, a, b: int, call: P) #no_bounds_check {
for i in a+1..<b {
for j := i; j > a && less(data[j], data[j-1], call); j -= 1 {
swap(data, j, j-1)
swap(indices, j, j-1)
}
}
}
heap_sort :: proc(data: $T/[]$E, indices: []int, a, b: int, call: P) #no_bounds_check {
sift_down :: proc(data: T, indices: []int, lo, hi, first: int, call: P) #no_bounds_check {
root := lo
for {
child := 2*root + 1
if child >= hi {
break
}
if child+1 < hi && less(data[first+child], data[first+child+1], call) {
child += 1
}
if !less(data[first+root], data[first+child], call) {
return
}
swap(data, first+root, first+child)
swap(indices, first+root, first+child)
root = child
}
}
first, lo, hi := a, 0, b-a
for i := (hi-1)/2; i >= 0; i -= 1 {
sift_down(data, indices, i, hi, first, call)
}
for i := hi-1; i >= 0; i -= 1 {
swap(data, first, first+i)
swap(indices, first, first+i)
sift_down(data, indices, lo, i, first, call)
}
}
median3 :: proc(data: T, indices: []int, m1, m0, m2: int, call: P) #no_bounds_check {
if less(data[m1], data[m0], call) {
swap(data, m1, m0)
swap(indices, m1, m0)
}
if less(data[m2], data[m1], call) {
swap(data, m2, m1)
swap(indices, m2, m1)
if less(data[m1], data[m0], call) {
swap(data, m1, m0)
swap(indices, m1, m0)
}
}
}
do_pivot :: proc(data: T, indices: []int, lo, hi: int, call: P) -> (midlo, midhi: int) #no_bounds_check {
m := int(uint(lo+hi)>>1)
if hi-lo > 40 {
s := (hi-lo)/8
median3(data, indices, lo, lo+s, lo+s*2, call)
median3(data, indices, m, m-s, m+s, call)
median3(data, indices, hi-1, hi-1-s, hi-1-s*2, call)
}
median3(data, indices, lo, m, hi-1, call)
pivot := lo
a, c := lo+1, hi-1
for ; a < c && less(data[a], data[pivot], call); a += 1 {
}
b := a
for {
for ; b < c && !less(data[pivot], data[b], call); b += 1 { // data[b] <= pivot
}
for ; b < c && less(data[pivot], data[c-1], call); c -=1 { // data[c-1] > pivot
}
if b >= c {
break
}
swap(data, b, c-1)
swap(indices, b, c-1)
b += 1
c -= 1
}
protect := hi-c < 5
if !protect && hi-c < (hi-lo)/4 {
dups := 0
if !less(data[pivot], data[hi-1], call) {
swap(data, c, hi-1)
swap(indices, c, hi-1)
c += 1
dups += 1
}
if !less(data[b-1], data[pivot], call) {
b -= 1
dups += 1
}
if !less(data[m], data[pivot], call) {
swap(data, m, b-1)
swap(indices, m, b-1)
b -= 1
dups += 1
}
protect = dups > 1
}
if protect {
for {
for ; a < b && !less(data[b-1], data[pivot], call); b -= 1 {
}
for ; a < b && less(data[a], data[pivot], call); a += 1 {
}
if a >= b {
break
}
swap(data, a, b-1)
swap(indices, a, b-1)
a += 1
b -= 1
}
}
swap(data, pivot, b-1)
swap(indices, pivot, b-1)
return b-1, c
}
assert(len(data) == len(indices))
a, b, max_depth := a, b, max_depth
for b-a > 12 { // only use shell sort for lengths <= 12
if max_depth == 0 {
heap_sort(data, indices, a, b, call)
return
}
max_depth -= 1
mlo, mhi := do_pivot(data, indices, a, b, call)
if mlo-a < b-mhi {
_quick_sort_general_with_indices(data, indices, a, mlo, max_depth, call, KIND)
a = mhi
} else {
_quick_sort_general_with_indices(data, indices, mhi, b, max_depth, call, KIND)
b = mlo
}
}
if b-a > 1 {
// Shell short with gap 6
for i in a+6..<b {
if less(data[i], data[i-6], call) {
swap(data, i, i-6)
swap(indices, i, i-6)
}
}
insertion_sort(data, indices, a, b, call)
}
}
+6 -1
View File
@@ -684,5 +684,10 @@ compare_f64s :: proc(a, b: f64) -> int {
compare_strings :: proc(a, b: string) -> int {
x := transmute(mem.Raw_String)a
y := transmute(mem.Raw_String)b
return mem.compare_byte_ptrs(x.data, y.data, min(x.len, y.len))
ret := mem.compare_byte_ptrs(x.data, y.data, min(x.len, y.len))
if ret == 0 && x.len != y.len {
return -1 if x.len < y.len else +1
}
return ret
}
+31 -18
View File
@@ -2,11 +2,13 @@ package strconv
import "core:unicode/utf8"
parse_bool :: proc(s: string) -> (result: bool = false, ok: bool) {
parse_bool :: proc(s: string, n: ^int = nil) -> (result: bool = false, ok: bool) {
switch s {
case "1", "t", "T", "true", "TRUE", "True":
if n != nil { n^ = len(s) }
return true, true
case "0", "f", "F", "false", "FALSE", "False":
if n != nil { n^ = len(s) }
return false, true
}
return
@@ -32,10 +34,13 @@ _digit_value :: proc(r: rune) -> int {
// n, ok := strconv.parse_i64_of_base("-1234eeee", 10);
// assert(n == -1234 && ok);
// ```
parse_i64_of_base :: proc(str: string, base: int) -> (value: i64, ok: bool) {
parse_i64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i64, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -87,8 +92,9 @@ parse_i64_of_base :: proc(str: string, base: int) -> (value: i64, ok: bool) {
// n, ok = strconv.parse_i64_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_i64_maybe_prefixed :: proc(str: string) -> (value: i64, ok: bool) {
parse_i64_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: i64, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -155,9 +161,10 @@ parse_i64 :: proc{parse_i64_maybe_prefixed, parse_i64_of_base}
// n, ok = strconv.parse_u64_of_base("5678eeee", 16);
// assert(n == 0x5678eeee && ok);
// ```
parse_u64_of_base :: proc(str: string, base: int) -> (value: u64, ok: bool) {
parse_u64_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u64, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -198,8 +205,9 @@ parse_u64_of_base :: proc(str: string, base: int) -> (value: u64, ok: bool) {
// n, ok = strconv.parse_u64_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_u64_maybe_prefixed :: proc(str: string) -> (value: u64, ok: bool) {
parse_u64_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: u64, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -259,11 +267,11 @@ parse_u64 :: proc{parse_u64_maybe_prefixed, parse_u64_of_base}
// n, ok = strconv.parse_int("0xffff"); // with prefix and inferred base
// assert(n == 0xffff && ok);
// ```
parse_int :: proc(s: string, base := 0) -> (value: int, ok: bool) {
parse_int :: proc(s: string, base := 0, n: ^int = nil) -> (value: int, ok: bool) {
v: i64 = ---
switch base {
case 0: v, ok = parse_i64_maybe_prefixed(s)
case: v, ok = parse_i64_of_base(s, base)
case 0: v, ok = parse_i64_maybe_prefixed(s, n)
case: v, ok = parse_i64_of_base(s, base, n)
}
value = int(v)
return
@@ -289,11 +297,11 @@ parse_int :: proc(s: string, base := 0) -> (value: int, ok: bool) {
// n, ok = strconv.parse_uint("0xffff"); // with prefix and inferred base
// assert(n == 0xffff && ok);
// ```
parse_uint :: proc(s: string, base := 0) -> (value: uint, ok: bool) {
parse_uint :: proc(s: string, base := 0, n: ^int = nil) -> (value: uint, ok: bool) {
v: u64 = ---
switch base {
case 0: v, ok = parse_u64_maybe_prefixed(s)
case: v, ok = parse_u64_of_base(s, base)
case 0: v, ok = parse_u64_maybe_prefixed(s, n)
case: v, ok = parse_u64_of_base(s, base, n)
}
value = uint(v)
return
@@ -309,10 +317,11 @@ parse_uint :: proc(s: string, base := 0) -> (value: uint, ok: bool) {
// n, ok := strconv.parse_i128_of_base("-1234eeee", 10);
// assert(n == -1234 && ok);
// ```
parse_i128_of_base :: proc(str: string, base: int) -> (value: i128, ok: bool) {
parse_i128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: i128, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -364,8 +373,9 @@ parse_i128_of_base :: proc(str: string, base: int) -> (value: i128, ok: bool) {
// n, ok = strconv.parse_i128_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_i128_maybe_prefixed :: proc(str: string) -> (value: i128, ok: bool) {
parse_i128_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: i128, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -432,9 +442,10 @@ parse_i128 :: proc{parse_i128_maybe_prefixed, parse_i128_of_base}
// n, ok = strconv.parse_u128_of_base("5678eeee", 16);
// assert(n == 0x5678eeee && ok);
// ```
parse_u128_of_base :: proc(str: string, base: int) -> (value: u128, ok: bool) {
parse_u128_of_base :: proc(str: string, base: int, n: ^int = nil) -> (value: u128, ok: bool) {
assert(base <= 16, "base must be 1-16")
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -475,8 +486,9 @@ parse_u128_of_base :: proc(str: string, base: int) -> (value: u128, ok: bool) {
// n, ok = strconv.parse_u128_maybe_prefixed("0xeeee");
// assert(n == 0xeeee && ok);
// ```
parse_u128_maybe_prefixed :: proc(str: string) -> (value: u128, ok: bool) {
parse_u128_maybe_prefixed :: proc(str: string, n: ^int = nil) -> (value: u128, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
@@ -535,9 +547,9 @@ parse_u128 :: proc{parse_u128_maybe_prefixed, parse_u128_of_base}
// n, ok = strconv.parse_f32("12.34");
// assert(n == 12.34 && ok);
// ```
parse_f32 :: proc(s: string) -> (value: f32, ok: bool) {
parse_f32 :: proc(s: string, n: ^int = nil) -> (value: f32, ok: bool) {
v: f64 = ---
v, ok = parse_f64(s)
v, ok = parse_f64(s, n)
return f32(v), ok
}
@@ -553,8 +565,9 @@ parse_f32 :: proc(s: string) -> (value: f32, ok: bool) {
// n, ok = strconv.parse_f32("12.34");
// assert(n == 12.34 && ok);
// ```
parse_f64 :: proc(str: string) -> (value: f64, ok: bool) {
parse_f64 :: proc(str: string, n: ^int = nil) -> (value: f64, ok: bool) {
s := str
defer if n != nil { n^ = len(str)-len(s) }
if s == "" {
return
}
+11 -11
View File
@@ -31,31 +31,31 @@ intern_destroy :: proc(m: ^Intern) {
// returns the `text` string from the intern map - gets set if it didnt exist yet
// the returned string lives as long as the map entry lives
intern_get :: proc(m: ^Intern, text: string) -> string {
entry := _intern_get_entry(m, text)
#no_bounds_check return string(entry.str[:entry.len])
intern_get :: proc(m: ^Intern, text: string) -> (str: string, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) or_return
#no_bounds_check return string(entry.str[:entry.len]), nil
}
// returns the `text` cstring from the intern map - gets set if it didnt exist yet
// the returned cstring lives as long as the map entry lives
intern_get_cstring :: proc(m: ^Intern, text: string) -> cstring {
entry := _intern_get_entry(m, text)
return cstring(&entry.str[0])
intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) or_return
return cstring(&entry.str[0]), nil
}
// looks up wether the `text` string exists in the map, returns the entry
// sets & allocates the entry if it wasnt set yet
_intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_check {
_intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check {
if prev, ok := m.entries[text]; ok {
return prev
return prev, nil
}
if m.allocator.procedure == nil {
m.allocator = context.allocator
}
entry_size := int(offset_of(Intern_Entry, str)) + len(text) + 1
ptr, _ := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator)
new_entry := (^Intern_Entry)(ptr)
bytes := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator) or_return
new_entry = (^Intern_Entry)(raw_data(bytes))
new_entry.len = len(text)
copy(new_entry.str[:new_entry.len], text)
@@ -63,5 +63,5 @@ _intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_
key := string(new_entry.str[:new_entry.len])
m.entries[key] = new_entry
return new_entry
return new_entry, nil
}
+24 -2
View File
@@ -15,18 +15,40 @@ foreign import Ntdll "system:Ntdll.lib"
@(default_calling_convention="stdcall")
foreign Ntdll {
RtlWaitOnAddress :: proc(Address: rawptr, CompareAddress: rawptr, AddressSize: uint, Timeout: ^i64) -> i32 ---
RtlNtStatusToDosError :: proc(status: i32) -> u32 ---
SetLastError :: proc(err: u32) ---
}
/*
NOTE(bill, 2022-08-17)
WaitOnAddress is implemented on top of RtlWaitOnAddress
BUT requires taking the return value of it and if it is non-zero
converting that status to a DOS error and then SetLastError
If this is not done, then things don't work as expected when
and error occurs
GODDAMN MICROSOFT!
*/
CustomWaitOnAddress :: proc "stdcall" (Address: rawptr, CompareAddress: rawptr, AddressSize: uint, Timeout: ^i64) -> bool {
status := RtlWaitOnAddress(Address, CompareAddress, AddressSize, Timeout)
if status != 0 {
SetLastError(RtlNtStatusToDosError(status))
}
return status == 0
}
_futex_wait :: proc(f: ^Futex, expect: u32) -> bool {
expect := expect
return 0 == RtlWaitOnAddress(f, &expect, size_of(expect), nil)
return CustomWaitOnAddress(f, &expect, size_of(expect), nil)
}
_futex_wait_with_timeout :: proc(f: ^Futex, expect: u32, duration: time.Duration) -> bool {
expect := expect
// NOTE(bill): for some bizarre reason, this has be a negative number
timeout := -i64(duration / 100)
return 0 == RtlWaitOnAddress(f, &expect, size_of(expect), &timeout)
return CustomWaitOnAddress(f, &expect, size_of(expect), &timeout)
}
_futex_signal :: proc(f: ^Futex) {
+3 -3
View File
@@ -1568,7 +1568,7 @@ sys_gettid :: proc "contextless" () -> int {
}
sys_getrandom :: proc "contextless" (buf: [^]byte, buflen: int, flags: uint) -> int {
return cast(int)intrinsics.syscall(SYS_getrandom, buf, cast(uintptr)(buflen), cast(uintptr)(flags))
return cast(int)intrinsics.syscall(SYS_getrandom, uintptr(buf), uintptr(buflen), uintptr(flags))
}
sys_open :: proc "contextless" (path: cstring, flags: int, mode: int = 0o000) -> int {
@@ -1622,7 +1622,7 @@ sys_lseek :: proc "contextless" (fd: int, offset: i64, whence: int) -> i64 {
low := uintptr(offset & 0xFFFFFFFF)
high := uintptr(offset >> 32)
result: i64
res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, &result, uintptr(whence)))
res := i64(intrinsics.syscall(SYS__llseek, uintptr(fd), high, low, uintptr(&result), uintptr(whence)))
return res if res < 0 else result
}
}
@@ -1748,7 +1748,7 @@ sys_unlink :: proc "contextless" (path: cstring) -> int {
}
sys_unlinkat :: proc "contextless" (dfd: int, path: cstring, flag: int = 0) -> int {
return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), flag))
return int(intrinsics.syscall(SYS_unlinkat, uintptr(dfd), uintptr(rawptr(path)), uintptr(flag)))
}
sys_rmdir :: proc "contextless" (path: cstring) -> int {
+63
View File
@@ -0,0 +1,63 @@
//+build amd64
package sys_valgrind
import "core:intrinsics"
Callgrind_Client_Request :: enum uintptr {
Dump_Stats = 'C'<<24 | 'T'<<16,
Zero_Stats,
Toggle_Collect,
Dump_Stats_At,
Start_Instrumentation,
Stop_Instrumentation,
}
@(require_results)
callgrind_client_request_expr :: proc "c" (default: uintptr, request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
}
callgrind_client_request_stmt :: proc "c" (request: Callgrind_Client_Request, a0, a1, a2, a3, a4: uintptr) {
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
}
// Dump current state of cost centres, and zero them afterwards.
dump_stats :: proc "c" () {
callgrind_client_request_stmt(.Dump_Stats, 0, 0, 0, 0, 0)
}
// Zero cost centres
zero_stats :: proc "c" () {
callgrind_client_request_stmt(.Zero_Stats, 0, 0, 0, 0, 0)
}
// Toggles collection state.
// The collection state specifies whether the happening of events should be noted or
// if they are to be ignored. Events are noted by increment of counters in a cost centre.
toggle_collect :: proc "c" () {
callgrind_client_request_stmt(.Toggle_Collect, 0, 0, 0, 0, 0)
}
// Dump current state of cost centres, and zero them afterwards.
// The argument is appended to a string stating the reason which triggered
// the dump. This string is written as a description field into the
// profile data dump.
dump_stats_at :: proc "c" (pos_str: rawptr) {
callgrind_client_request_stmt(.Dump_Stats_At, uintptr(pos_str), 0, 0, 0, 0)
}
// Start full callgrind instrumentation if not already switched on.
// When cache simulation is done, it will flush the simulated cache;
// this will lead to an artificial cache warmup phase afterwards with
// cache misses which would not have happened in reality.
start_instrumentation :: proc "c" () {
callgrind_client_request_stmt(.Start_Instrumentation, 0, 0, 0, 0, 0)
}
// Stop full callgrind instrumentation if not already switched off.
// This flushes Valgrinds translation cache, and does no additional instrumentation
// afterwards, which effectivly will run at the same speed as the "none" tool (ie. at minimal slowdown).
// Use this to bypass Callgrind aggregation for uninteresting code parts.
// To start Callgrind in this mode to ignore the setup phase, use the option "--instr-atstart=no".
stop_instrumentation :: proc "c" () {
callgrind_client_request_stmt(.Stop_Instrumentation, 0, 0, 0, 0, 0)
}
+169
View File
@@ -0,0 +1,169 @@
//+build amd64
package sys_valgrind
import "core:intrinsics"
Mem_Check_Client_Request :: enum uintptr {
Make_Mem_No_Access = 'M'<<24 | 'C'<<16,
Make_Mem_Undefined,
Make_Mem_Defined,
Discard,
Check_Mem_Is_Addressable,
Check_Mem_Is_Defined,
Do_Leak_Check,
Count_Leaks,
Get_Vbits,
Set_Vbits,
Create_Block,
Make_Mem_Defined_If_Addressable,
Count_Leak_Blocks,
Enable_Addr_Error_Reporting_In_Range,
Disable_Addr_Error_Reporting_In_Range,
}
@(require_results)
mem_check_client_request_expr :: proc "c" (default: uintptr, request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
}
mem_check_client_request_stmt :: proc "c" (request: Mem_Check_Client_Request, a0, a1, a2, a3, a4: uintptr) {
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
}
// Mark memory at `raw_data(qzz)` as unaddressable for `len(qzz)` bytes.
// Returns true when run on Valgrind and false otherwise.
make_mem_no_access :: proc "c" (qzz: []byte) -> bool {
return 0 != mem_check_client_request_expr(0, .Make_Mem_No_Access, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Mark memory at `raw_data(qzz)` as addressable but undefined for `len(qzz)` bytes.
// Returns true when run on Valgrind and false otherwise.
make_mem_undefined :: proc "c" (qzz: []byte) -> bool {
return 0 != mem_check_client_request_expr(0, .Make_Mem_Undefined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Mark memory at `raw_data(qzz)` as addressable for `len(qzz)` bytes.
// Returns true when run on Valgrind and false otherwise.
make_mem_defined :: proc "c" (qzz: []byte) -> bool {
return 0 != mem_check_client_request_expr(0, .Make_Mem_Defined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Check that memory at `raw_data(qzz)` is addressable for `len(qzz)` bytes.
// If suitable addressibility is not established, Valgrind prints an error
// message and returns the address of the first offending byte.
// Otherwise it returns zero.
check_mem_is_addressable :: proc "c" (qzz: []byte) -> uintptr {
return mem_check_client_request_expr(0, .Check_Mem_Is_Addressable, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Check that memory at `raw_data(qzz)` is addressable and defined for `len(qzz)` bytes.
// If suitable addressibility and definedness are not established,
// Valgrind prints an error message and returns the address of the first
// offending byte. Otherwise it returns zero.
check_mem_is_defined :: proc "c" (qzz: []byte) -> uintptr {
return mem_check_client_request_expr(0, .Check_Mem_Is_Defined, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Similar to `make_mem_defined(qzz)` except that addressability is not altered:
// bytes which are addressable are marked as defined, but those which
// are not addressable are left unchanged.
// Returns true when run on Valgrind and false otherwise.
make_mem_defined_if_addressable :: proc "c" (qzz: []byte) -> bool {
return 0 != mem_check_client_request_expr(0, .Make_Mem_Defined_If_Addressable, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Create a block-description handle.
// The description is an ascii string which is included in any messages
// pertaining to addresses within the specified memory range.
// Has no other effect on the properties of the memory range.
create_block :: proc "c" (qzz: []u8, desc: cstring) -> bool {
return 0 != mem_check_client_request_expr(0, .Create_Block, uintptr(raw_data(qzz)), uintptr(len(qzz)), uintptr(rawptr(desc)), 0, 0)
}
// Discard a block-description-handle. Returns true for an invalid handle, false for a valid handle.
discard :: proc "c" (blk_index: uintptr) -> bool {
return 0 != mem_check_client_request_expr(0, .Discard, 0, blk_index, 0, 0, 0)
}
// Do a full memory leak check (like `--leak-check=full`) mid-execution.
leak_check :: proc "c" () {
mem_check_client_request_stmt(.Do_Leak_Check, 0, 0, 0, 0, 0)
}
// Same as `leak_check()` but only showing the entries for which there was an increase
// in leaked bytes or leaked nr of blocks since the previous leak search.
added_leak_check :: proc "c" () {
mem_check_client_request_stmt(.Do_Leak_Check, 0, 1, 0, 0, 0)
}
// Same as `added_leak_check()` but showing entries with increased or decreased
// leaked bytes/blocks since previous leak search.
changed_leak_check :: proc "c" () {
mem_check_client_request_stmt(.Do_Leak_Check, 0, 2, 0, 0, 0)
}
// Do a summary memory leak check (like `--leak-check=summary`) mid-execution.
quick_leak_check :: proc "c" () {
mem_check_client_request_stmt(.Do_Leak_Check, 1, 0, 0, 0, 0)
}
Count_Result :: struct {
leaked: uint,
dubious: uint,
reachable: uint,
suppressed: uint,
}
count_leaks :: proc "c" () -> (res: Count_Result) {
mem_check_client_request_stmt(
.Count_Leaks,
uintptr(&res.leaked),
uintptr(&res.dubious),
uintptr(&res.reachable),
uintptr(&res.suppressed),
0,
)
return
}
count_leak_blocks :: proc "c" () -> (res: Count_Result) {
mem_check_client_request_stmt(
.Count_Leak_Blocks,
uintptr(&res.leaked),
uintptr(&res.dubious),
uintptr(&res.reachable),
uintptr(&res.suppressed),
0,
)
return
}
// Get the validity data for addresses zza and copy it
// into the provided zzvbits array. Return values:
// 0 - if not running on valgrind
// 1 - success
// 2 - [previously indicated unaligned arrays; these are now allowed]
// 3 - if any parts of zzsrc/zzvbits are not addressable.
// The metadata is not copied in cases 0, 2 or 3 so it should be
// impossible to segfault your system by using this call.
get_vbits :: proc(zza, zzvbits: []byte) -> u8 {
// assert requires a `context` thus these procedures cannot `proc "c"`
assert(len(zzvbits) >= len(zza)/8)
return u8(mem_check_client_request_expr(0, .Get_Vbits, uintptr(raw_data(zza)), uintptr(raw_data(zzvbits)), uintptr(len(zza)), 0, 0))
}
// Set the validity data for addresses zza, copying it
// from the provided zzvbits array. Return values:
// 0 - if not running on valgrind
// 1 - success
// 2 - [previously indicated unaligned arrays; these are now allowed]
// 3 - if any parts of zza/zzvbits are not addressable.
// The metadata is not copied in cases 0, 2 or 3 so it should be
// impossible to segfault your system by using this call.
set_vbits :: proc(zzvbits, zza: []byte) -> u8 {
// assert requires a `context` thus these procedures cannot `proc "c"`
assert(len(zzvbits) >= len(zza)/8)
return u8(mem_check_client_request_expr(0, .Set_Vbits, uintptr(raw_data(zza)), uintptr(raw_data(zzvbits)), uintptr(len(zza)), 0, 0))
}
// (Re-)enable reporting of addressing errors in the specified address range.
enable_addr_error_reporting_in_range :: proc "c" (qzz: []byte) -> uintptr {
return mem_check_client_request_expr(0, .Enable_Addr_Error_Reporting_In_Range, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
// Disable reporting of addressing errors in the specified address range.
disable_addr_error_reporting_in_range :: proc "c" (qzz: []byte) -> uintptr {
return mem_check_client_request_expr(0, .Disable_Addr_Error_Reporting_In_Range, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
+182
View File
@@ -0,0 +1,182 @@
//+build amd64
package sys_valgrind
import "core:intrinsics"
Client_Request :: enum uintptr {
Running_On_Valgrind = 4097,
Discard_Translations = 4098,
Client_Call0 = 4353,
Client_Call1 = 4354,
Client_Call2 = 4355,
Client_Call3 = 4356,
Count_Errors = 4609,
Gdb_Monitor_Command = 4610,
Malloc_Like_Block = 4865,
Resize_Inplace_Block = 4875,
Free_Like_Block = 4866,
Create_Mem_Pool = 4867,
Destroy_Mem_Pool = 4868,
Mem_Pool_Alloc = 4869,
Mem_Pool_Free = 4870,
Mem_Pool_Trim = 4871,
Move_Mem_Pool = 4872,
Mem_Pool_Change = 4873,
Mem_Pool_Exists = 4874,
Printf = 5121,
Printf_Backtrace = 5122,
Printf_Valist_By_Ref = 5123,
Printf_Backtrace_Valist_By_Ref = 5124,
Stack_Register = 5377,
Stack_Deregister = 5378,
Stack_Change = 5379,
Load_Pdb_Debug_Info = 5633,
Map_Ip_To_Src_Loc = 5889,
Change_Err_Disablement = 6145,
Vex_Init_For_Iri = 6401,
Inner_Threads = 6402,
}
@(require_results)
client_request_expr :: proc "c" (default: uintptr, request: Client_Request, a0, a1, a2, a3, a4: uintptr) -> uintptr {
return intrinsics.valgrind_client_request(default, uintptr(request), a0, a1, a2, a3, a4)
}
client_request_stmt :: proc "c" (request: Client_Request, a0, a1, a2, a3, a4: uintptr) {
_ = intrinsics.valgrind_client_request(0, uintptr(request), a0, a1, a2, a3, a4)
}
// Returns the number of Valgrinds this code is running under
// 0 - running natively
// 1 - running under Valgrind
// 2 - running under Valgrind which is running under another Valgrind
running_on_valgrind :: proc "c" () -> uintptr {
return client_request_expr(0, .Running_On_Valgrind, 0, 0, 0, 0, 0)
}
// Discard translation of code in the slice qzz. Useful if you are debugging a JIT-er or some such,
// since it provides a way to make sure valgrind will retranslate the invalidated area.
discard_translations :: proc "c" (qzz: []byte) {
client_request_stmt(.Discard_Translations, uintptr(raw_data(qzz)), uintptr(len(qzz)), 0, 0, 0)
}
non_simd_call0 :: proc "c" (p: proc "c" (uintptr) -> uintptr) -> uintptr {
return client_request_expr(0, .Client_Call0, uintptr(rawptr(p)), 0, 0, 0, 0)
}
non_simd_call1 :: proc "c" (p: proc "c" (uintptr, uintptr) -> uintptr, a0: uintptr) -> uintptr {
return client_request_expr(0, .Client_Call1, uintptr(rawptr(p)), a0, 0, 0, 0)
}
non_simd_call2 :: proc "c" (p: proc "c" (uintptr, uintptr, uintptr) -> uintptr, a0, a1: uintptr) -> uintptr {
return client_request_expr(0, .Client_Call2, uintptr(rawptr(p)), a0, a1, 0, 0)
}
non_simd_call3 :: proc "c" (p: proc "c" (uintptr, uintptr, uintptr, uintptr) -> uintptr, a0, a1, a2: uintptr) -> uintptr {
return client_request_expr(0, .Client_Call3, uintptr(rawptr(p)), a0, a1, a2, 0)
}
// Counts the number of errors that have been recorded by a tool.
count_errrors :: proc "c" () -> uint {
return uint(client_request_expr(0, .Count_Errors, 0, 0, 0, 0, 0))
}
monitor_command :: proc "c" (command: cstring) -> bool {
return 0 != client_request_expr(0, .Gdb_Monitor_Command, uintptr(rawptr(command)), 0, 0, 0, 0)
}
malloc_like_block :: proc "c" (mem: []byte, rz_b: uintptr, is_zeroed: bool) {
client_request_stmt(.Malloc_Like_Block, uintptr(raw_data(mem)), uintptr(len(mem)), rz_b, uintptr(is_zeroed), 0)
}
resize_inplace_block :: proc "c" (old_mem: []byte, new_size: uint, rz_b: uintptr) {
client_request_stmt(.Resize_Inplace_Block, uintptr(raw_data(old_mem)), uintptr(len(old_mem)), uintptr(new_size), rz_b, 0)
}
free_like_block :: proc "c" (addr: rawptr, rz_b: uintptr) {
client_request_stmt(.Free_Like_Block, uintptr(addr), rz_b, 0, 0, 0)
}
Mem_Pool_Flags :: distinct bit_set[Mem_Pool_Flag; uintptr]
Mem_Pool_Flag :: enum uintptr {
Auto_Free = 0,
Meta_Pool = 1,
}
// Create a memory pool.
create_mem_pool :: proc "c" (pool: rawptr, rz_b: uintptr, is_zeroed: bool, flags: Mem_Pool_Flags) {
client_request_stmt(.Create_Mem_Pool, uintptr(pool), rz_b, uintptr(is_zeroed), transmute(uintptr)flags, 0)
}
// Destroy a memory pool.
destroy_mem_pool :: proc "c" (pool: rawptr) {
client_request_stmt(.Destroy_Mem_Pool, uintptr(pool), 0, 0, 0, 0)
}
// Associate a section of memory with a memory pool.
mem_pool_alloc :: proc "c" (pool: rawptr, mem: []byte) {
client_request_stmt(.Mem_Pool_Alloc, uintptr(pool), uintptr(raw_data(mem)), uintptr(len(mem)), 0, 0)
}
// Disassociate a section of memory from a memory pool.
mem_pool_free :: proc "c" (pool: rawptr, addr: rawptr) {
client_request_stmt(.Mem_Pool_Free, uintptr(pool), uintptr(addr), 0, 0, 0)
}
// Disassociate parts of a section of memory outside a particular range.
mem_pool_trim :: proc "c" (pool: rawptr, mem: []byte) {
client_request_stmt(.Mem_Pool_Trim, uintptr(pool), uintptr(raw_data(mem)), uintptr(len(mem)), 0, 0)
}
// Resize and/or move a section of memory associated with a memory pool.
move_mem_pool :: proc "c" (pool_a, pool_b: rawptr) {
client_request_stmt(.Move_Mem_Pool, uintptr(pool_a), uintptr(pool_b), 0, 0, 0)
}
// Resize and/or move a section of memory associated with a memory pool.
mem_pool_change :: proc "c" (pool: rawptr, addr_a: rawptr, mem: []byte) {
client_request_stmt(.Mem_Pool_Change, uintptr(pool), uintptr(addr_a), uintptr(raw_data(mem)), uintptr(len(mem)), 0)
}
// Return true if a memory pool exists
mem_pool_exists :: proc "c" (pool: rawptr) -> bool {
return 0 != client_request_expr(0, .Mem_Pool_Exists, uintptr(pool), 0, 0, 0, 0)
}
// Mark a section of memory as being a stack. Returns a stack id.
stack_register :: proc "c" (stack: []byte) -> (stack_id: uintptr) {
ptr := uintptr(raw_data(stack))
return client_request_expr(0, .Stack_Register, ptr, ptr+uintptr(len(stack)), 0, 0, 0)
}
// Unmark a section of memory associated with a stack id as being a stack.
stack_deregister :: proc "c" (id: uintptr) {
client_request_stmt(.Stack_Deregister, id, 0, 0, 0, 0)
}
// Change the start and end address of the stack id with the `new_stack` slice.
stack_change :: proc "c" (id: uint, new_stack: []byte) {
ptr := uintptr(raw_data(new_stack))
client_request_stmt(.Stack_Change, uintptr(id), ptr, ptr + uintptr(len(new_stack)), 0, 0)
}
// Disable error reporting for the current thread/
// It behaves in a stack-like way, meaning you can safely call this multiple times
// given that `enable_error_reporting()` is called the same number of times to
// re-enable the error reporting.
// The first call of this macro disables reporting.
// Subsequent calls have no effect except to increase the number of `enable_error_reporting()`
// calls needed to re-enable reporting.
// Child threads do not inherit this setting from their parents;
// they are always created with reporting enabled.
disable_error_reporting :: proc "c" () {
client_request_stmt(.Change_Err_Disablement, 1, 0, 0, 0, 0)
}
// Re-enable error reporting
enable_error_reporting :: proc "c" () {
client_request_stmt(.Change_Err_Disablement, ~uintptr(0), 0, 0, 0, 0)
}
inner_threads :: proc "c" (qzz: rawptr) {
client_request_stmt(.Inner_Threads, uintptr(qzz), 0, 0, 0, 0)
}
// Map a code address to a source file name and line number.
// `buf64` must point to a 64-byte buffer in the caller's address space.
// The result will be dumped in there and is guaranteed to be zero terminated.
// If no info is found, the first byte is set to zero.
map_ip_to_src_loc :: proc "c" (addr: rawptr, buf64: ^[64]byte) -> uintptr {
return client_request_expr(0, .Map_Ip_To_Src_Loc, uintptr(addr), uintptr(buf64), 0, 0, 0)
}
+24 -16
View File
@@ -24,6 +24,8 @@ foreign kernel32 {
lpMode: LPDWORD) -> BOOL ---
SetConsoleMode :: proc(hConsoleHandle: HANDLE,
dwMode: DWORD) -> BOOL ---
SetConsoleCursorPosition :: proc(hConsoleHandle: HANDLE,
dwCursorPosition: COORD) -> BOOL ---
GetFileInformationByHandle :: proc(hFile: HANDLE, lpFileInformation: LPBY_HANDLE_FILE_INFORMATION) -> BOOL ---
SetHandleInformation :: proc(hObject: HANDLE,
@@ -94,6 +96,15 @@ foreign kernel32 {
dwCreationFlags: DWORD,
lpThreadId: LPDWORD,
) -> HANDLE ---
CreateRemoteThread :: proc(
hProcess: HANDLE,
lpThreadAttributes: LPSECURITY_ATTRIBUTES,
dwStackSize: SIZE_T,
lpStartAddress: proc "stdcall" (rawptr) -> DWORD,
lpParameter: LPVOID,
dwCreationFlags: DWORD,
lpThreadId: LPDWORD,
) -> HANDLE ---
SwitchToThread :: proc() -> BOOL ---
ResumeThread :: proc(thread: HANDLE) -> DWORD ---
GetThreadPriority :: proc(thread: HANDLE) -> c_int ---
@@ -290,10 +301,10 @@ foreign kernel32 {
InitializeSRWLock :: proc(SRWLock: ^SRWLOCK) ---
AcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) ---
TryAcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) -> BOOL ---
TryAcquireSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) -> BOOLEAN ---
ReleaseSRWLockExclusive :: proc(SRWLock: ^SRWLOCK) ---
AcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) ---
TryAcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) -> BOOL ---
TryAcquireSRWLockShared :: proc(SRWLock: ^SRWLOCK) -> BOOLEAN ---
ReleaseSRWLockShared :: proc(SRWLock: ^SRWLOCK) ---
InitializeConditionVariable :: proc(ConditionVariable: ^CONDITION_VARIABLE) ---
@@ -326,6 +337,15 @@ foreign kernel32 {
SetEndOfFile :: proc(hFile: HANDLE) -> BOOL ---
CreatePipe :: proc(hReadPipe, hWritePipe: ^HANDLE, lpPipeAttributes: LPSECURITY_ATTRIBUTES, nSize: DWORD) -> BOOL ---
ConnectNamedPipe :: proc(hNamedPipe: HANDLE, lpOverlapped: LPOVERLAPPED,) -> BOOL ---
DisconnectNamedPipe :: proc(hNamedPipe: HANDLE,) -> BOOL ---
WaitNamedPipeW :: proc(lpNamedPipeName: LPCWSTR, nTimeOut: DWORD,) -> BOOL ---
SetConsoleCtrlHandler :: proc(HandlerRoutine: PHANDLER_ROUTINE, Add: BOOL) -> BOOL ---
GenerateConsoleCtrlEvent :: proc(dwCtrlEvent: DWORD, dwProcessGroupId: DWORD) -> BOOL ---
FreeConsole :: proc() -> BOOL ---
GetConsoleWindow :: proc() -> HWND ---
}
@@ -780,17 +800,5 @@ foreign kernel32 {
) -> BOOL ---
}
@(default_calling_convention="stdcall")
foreign kernel32 {
@(link_name="SetConsoleCtrlHandler") set_console_ctrl_handler :: proc(handler: Handler_Routine, add: BOOL) -> BOOL ---
}
Handler_Routine :: proc(dwCtrlType: Control_Event) -> BOOL
Control_Event :: enum DWORD {
control_c = 0,
_break = 1,
close = 2,
logoff = 5,
shutdown = 6,
}
HandlerRoutine :: proc "stdcall" (dwCtrlType: DWORD) -> BOOL
PHANDLER_ROUTINE :: HandlerRoutine
+57
View File
@@ -978,6 +978,35 @@ WS_TILEDWINDOW : UINT : WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_THICKF
WS_VISIBLE : UINT : 0x1000_0000
WS_VSCROLL : UINT : 0x0020_0000
WS_EX_ACCEPTFILES : UINT : 0x0000_0010
WS_EX_APPWINDOW : UINT : 0x0004_0000
WS_EX_CLIENTEDGE : UINT : 0x0000_0200
WS_EX_COMPOSITED : UINT : 0x0200_0000
WS_EX_CONTEXTHELP : UINT : 0x0000_0400
WS_EX_CONTROLPARENT : UINT : 0x0001_0000
WS_EX_DLGMODALFRAME : UINT : 0x0000_0001
WS_EX_DRAGDETECT : UINT : 0x0000_0002 // undocumented
WS_EX_LAYERED : UINT : 0x0008_0000
WS_EX_LAYOUTRTL : UINT : 0x0040_0000
WS_EX_LEFT : UINT : 0x0000_0000
WS_EX_LEFTSCROLLBAR : UINT : 0x0000_4000
WS_EX_LTRREADING : UINT : 0x0000_0000
WS_EX_MDICHILD : UINT : 0x0000_0040
WS_EX_NOACTIVATE : UINT : 0x0800_0000
WS_EX_NOINHERITLAYOUT : UINT : 0x0010_0000
WS_EX_NOPARENTNOTIFY : UINT : 0x0000_0004
WS_EX_NOREDIRECTIONBITMAP : UINT : 0x0020_0000
WS_EX_OVERLAPPEDWINDOW : UINT : WS_EX_WINDOWEDGE | WS_EX_CLIENTEDGE
WS_EX_PALETTEWINDOW : UINT : WS_EX_WINDOWEDGE | WS_EX_TOOLWINDOW | WS_EX_TOPMOST
WS_EX_RIGHT : UINT : 0x0000_1000
WS_EX_RIGHTSCROLLBAR : UINT : 0x0000_0000
WS_EX_RTLREADING : UINT : 0x0000_2000
WS_EX_STATICEDGE : UINT : 0x0002_0000
WS_EX_TOOLWINDOW : UINT : 0x0000_0080
WS_EX_TOPMOST : UINT : 0x0000_0008
WS_EX_TRANSPARENT : UINT : 0x0000_0020
WS_EX_WINDOWEDGE : UINT : 0x0000_0100
PBS_SMOOTH :: 0x01
PBS_VERTICAL :: 0x04
@@ -1628,6 +1657,8 @@ CONDITION_VARIABLE_INIT :: CONDITION_VARIABLE{}
SRWLOCK_INIT :: SRWLOCK{}
DETACHED_PROCESS: DWORD : 0x00000008
CREATE_NEW_CONSOLE: DWORD : 0x00000010
CREATE_NO_WINDOW: DWORD : 0x08000000
CREATE_NEW_PROCESS_GROUP: DWORD : 0x00000200
CREATE_UNICODE_ENVIRONMENT: DWORD : 0x00000400
STARTF_USESTDHANDLES: DWORD : 0x00000100
@@ -1689,6 +1720,7 @@ PIPE_WAIT: DWORD : 0x00000000
PIPE_TYPE_BYTE: DWORD : 0x00000000
PIPE_REJECT_REMOTE_CLIENTS: DWORD : 0x00000008
PIPE_READMODE_BYTE: DWORD : 0x00000000
PIPE_ACCEPT_REMOTE_CLIENTS: DWORD : 0x00000000
FD_SETSIZE :: 64
@@ -3265,3 +3297,28 @@ IFileSaveDialogVtbl :: struct {
GetProperties: proc "stdcall" (this: ^IFileSaveDialog, ppStore: ^^IPropertyStore) -> HRESULT,
ApplyProperties: proc "stdcall" (this: ^IFileSaveDialog, psi: ^IShellItem, pStore: ^IPropertyStore, hwnd: HWND, pSink: ^IFileOperationProgressSink) -> HRESULT,
}
ENABLE_ECHO_INPUT : DWORD : 0x0004
ENABLE_INSERT_MODE : DWORD : 0x0020
ENABLE_LINE_INPUT : DWORD : 0x0002
ENABLE_MOUSE_INPUT : DWORD : 0x0010
ENABLE_PROCESSED_INPUT : DWORD : 0x0001
ENABLE_QUICK_EDIT_MODE : DWORD : 0x0040
ENABLE_WINDOW_INPUT : DWORD : 0x0008
ENABLE_VIRTUAL_TERMINAL_INPUT : DWORD : 0x0200
ENABLE_PROCESSED_OUTPUT : DWORD : 0x0001
ENABLE_WRAP_AT_EOL_OUTPUT : DWORD : 0x0002
ENABLE_VIRTUAL_TERMINAL_PROCESSING : DWORD : 0x0004
DISABLE_NEWLINE_AUTO_RETURN : DWORD : 0x0008
ENABLE_LVB_GRID_WORLDWIDE : DWORD : 0x0010
CTRL_C_EVENT : DWORD : 0
CTRL_BREAK_EVENT : DWORD : 1
CTRL_CLOSE_EVENT : DWORD : 2
CTRL_LOGOFF_EVENT : DWORD : 5
CTRL_SHUTDOWN_EVENT : DWORD : 6
COORD :: struct {
X: SHORT,
Y: SHORT,
}
+183 -2
View File
@@ -42,6 +42,7 @@ foreign user32 {
GetTopWindow :: proc(hWnd: HWND) -> HWND ---
SetForegroundWindow :: proc(hWnd: HWND) -> BOOL ---
GetForegroundWindow :: proc() -> HWND ---
UpdateWindow :: proc(hWnd: HWND) -> BOOL ---
SetActiveWindow :: proc(hWnd: HWND) -> HWND ---
GetActiveWindow :: proc() -> HWND ---
@@ -95,6 +96,7 @@ foreign user32 {
GetSystemMetrics :: proc(nIndex: c_int) -> c_int ---
AdjustWindowRect :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL) -> BOOL ---
AdjustWindowRectEx :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD) -> BOOL ---
AdjustWindowRectExForDpi :: proc(lpRect: LPRECT, dwStyle: DWORD, bMenu: BOOL, dwExStyle: DWORD, dpi: UINT) -> BOOL ---
SystemParametersInfoW :: proc(uiAction, uiParam: UINT, pvParam: PVOID, fWinIni: UINT) -> BOOL ---
@@ -137,7 +139,19 @@ foreign user32 {
SetCursor :: proc(hCursor: HCURSOR) -> HCURSOR ---
EnumDisplaySettingsW :: proc(lpszDeviceName: LPCWSTR, iModeNum: DWORD, lpDevMode: ^DEVMODEW) -> BOOL ---
MonitorFromPoint :: proc(pt: POINT, dwFlags: Monitor_From_Flags) -> HMONITOR ---
MonitorFromRect :: proc(lprc: LPRECT, dwFlags: Monitor_From_Flags) -> HMONITOR ---
MonitorFromWindow :: proc(hwnd: HWND, dwFlags: Monitor_From_Flags) -> HMONITOR ---
EnumDisplayMonitors :: proc(hdc: HDC, lprcClip: LPRECT, lpfnEnum: Monitor_Enum_Proc, dwData: LPARAM) -> BOOL ---
SetThreadDpiAwarenessContext :: proc(dpiContext: DPI_AWARENESS_CONTEXT) -> DPI_AWARENESS_CONTEXT ---
GetThreadDpiAwarenessContext :: proc() -> DPI_AWARENESS_CONTEXT ---
GetWindowDpiAwarenessContext :: proc(hwnd: HWND) -> DPI_AWARENESS_CONTEXT ---
GetDpiFromDpiAwarenessContext :: proc(value: DPI_AWARENESS_CONTEXT) -> UINT ---
GetDpiForWindow :: proc(hwnd: HWND) -> UINT ---
SetProcessDpiAwarenessContext :: proc(value: DPI_AWARENESS_CONTEXT) -> BOOL ---
BroadcastSystemMessageW :: proc(
flags: DWORD,
lpInfo: LPDWORD,
@@ -176,6 +190,14 @@ foreign user32 {
SetWindowTextW :: proc(hWnd: HWND, lpString: LPCWSTR) -> BOOL ---
CallWindowProcW :: proc(lpPrevWndFunc: WNDPROC, hWnd: HWND, Msg: UINT, wParam: WPARAM, lParam: LPARAM) -> LRESULT ---
EnableWindow :: proc(hWnd: HWND, bEnable: BOOL) -> BOOL ---
DefRawInputProc :: proc(paRawInput: ^PRAWINPUT, nInput: INT, cbSizeHeader: UINT) -> LRESULT ---
GetRawInputBuffer :: proc(pRawInput: PRAWINPUT, pcbSize: PUINT, cbSizeHeader: UINT) -> UINT ---
GetRawInputData :: proc(hRawInput: HRAWINPUT, uiCommand: UINT, pData: LPVOID, pcbSize: PUINT, cbSizeHeader: UINT) -> UINT ---
GetRawInputDeviceInfoW :: proc(hDevice: HANDLE, uiCommand: UINT, pData: LPVOID, pcbSize: PUINT) -> UINT ---
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 ---
}
CreateWindowW :: #force_inline proc "stdcall" (
@@ -221,7 +243,7 @@ when ODIN_ARCH == .amd64 {
SetClassLongPtrW :: SetClassLongW
GetWindowLongPtrW :: GetWindowLongW
SetWindowLongPtrW :: GetWindowLongW
SetWindowLongPtrW :: SetWindowLongW
}
GET_SC_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> c_int {
@@ -247,3 +269,162 @@ GET_XBUTTON_WPARAM :: #force_inline proc "contextless" (wParam: WPARAM) -> WORD
MAKEINTRESOURCEW :: #force_inline proc "contextless" (#any_int i: int) -> LPWSTR {
return cast(LPWSTR)uintptr(WORD(i))
}
Monitor_From_Flags :: enum DWORD {
MONITOR_DEFAULTTONULL = 0x00000000, // Returns NULL
MONITOR_DEFAULTTOPRIMARY = 0x00000001, // Returns a handle to the primary display monitor
MONITOR_DEFAULTTONEAREST = 0x00000002, // Returns a handle to the display monitor that is nearest to the window
}
Monitor_Enum_Proc :: #type proc "stdcall" (HMONITOR, HDC, LPRECT, LPARAM) -> BOOL
USER_DEFAULT_SCREEN_DPI :: 96
DPI_AWARENESS_CONTEXT :: distinct HANDLE
DPI_AWARENESS_CONTEXT_UNAWARE :: DPI_AWARENESS_CONTEXT(~uintptr(0)) // -1
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE :: DPI_AWARENESS_CONTEXT(~uintptr(1)) // -2
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE :: DPI_AWARENESS_CONTEXT(~uintptr(2)) // -3
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2 :: DPI_AWARENESS_CONTEXT(~uintptr(3)) // -4
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED :: DPI_AWARENESS_CONTEXT(~uintptr(4)) // -5
RAWINPUTHEADER :: struct {
dwType: DWORD,
dwSize: DWORD,
hDevice: HANDLE,
wParam: WPARAM,
}
RAWHID :: struct {
dwSizeHid: DWORD,
dwCount: DWORD,
bRawData: [1]BYTE,
}
RAWMOUSE :: struct {
usFlags: USHORT,
DUMMYUNIONNAME: struct #raw_union {
ulButtons: ULONG,
DUMMYSTRUCTNAME: struct {
usButtonFlags: USHORT,
usButtonData: USHORT,
},
},
ulRawButtons: ULONG,
lLastX: LONG,
lLastY: LONG,
ulExtraInformation: ULONG,
}
RAWKEYBOARD :: struct {
MakeCode: USHORT,
Flags: USHORT,
Rserved: USHORT,
VKey: USHORT,
Message: UINT,
ExtraInformation: ULONG,
}
RAWINPUT :: struct {
header: RAWINPUTHEADER,
data: struct #raw_union {
mouse: RAWMOUSE,
keyboard: RAWKEYBOARD,
hid: RAWHID,
},
}
PRAWINPUT :: ^RAWINPUT
HRAWINPUT :: distinct LPARAM
RAWINPUTDEVICE :: struct {
usUsagePage: USHORT,
usUsage: USHORT,
dwFlags: DWORD,
hwndTarget: HWND,
}
PRAWINPUTDEVICE :: ^RAWINPUTDEVICE
PCRAWINPUTDEVICE :: PRAWINPUTDEVICE
RAWINPUTDEVICELIST :: struct {
hDevice: HANDLE,
dwType: DWORD,
}
PRAWINPUTDEVICELIST :: ^RAWINPUTDEVICELIST
RID_DEVICE_INFO_HID :: struct {
dwVendorId: DWORD,
dwProductId: DWORD,
dwVersionNumber: DWORD,
usUsagePage: USHORT,
usUsage: USHORT,
}
RID_DEVICE_INFO_KEYBOARD :: struct {
dwType: DWORD,
dwSubType: DWORD,
dwKeyboardMode: DWORD,
dwNumberOfFunctionKeys: DWORD,
dwNumberOfIndicators: DWORD,
dwNumberOfKeysTotal: DWORD,
}
RID_DEVICE_INFO_MOUSE :: struct {
dwId: DWORD,
dwNumberOfButtons: DWORD,
dwSampleRate: DWORD,
fHasHorizontalWheel: BOOL,
}
RID_DEVICE_INFO :: struct {
cbSize: DWORD,
dwType: DWORD,
DUMMYUNIONNAME: struct #raw_union {
mouse: RID_DEVICE_INFO_MOUSE,
keyboard: RID_DEVICE_INFO_KEYBOARD,
hid: RID_DEVICE_INFO_HID,
},
}
RIDEV_REMOVE :: 0x00000001
RIDEV_EXCLUDE :: 0x00000010
RIDEV_PAGEONLY :: 0x00000020
RIDEV_NOLEGACY :: 0x00000030
RIDEV_INPUTSINK :: 0x00000100
RIDEV_CAPTUREMOUSE :: 0x00000200
RIDEV_NOHOTKEYS :: 0x00000200
RIDEV_APPKEYS :: 0x00000400
RIDEV_EXINPUTSINK :: 0x00001000
RIDEV_DEVNOTIFY :: 0x00002000
RID_HEADER :: 0x10000005
RID_INPUT :: 0x10000003
RIM_TYPEMOUSE :: 0
RIM_TYPEKEYBOARD :: 1
RIM_TYPEHID :: 2
MOUSE_MOVE_RELATIVE :: 0x00
MOUSE_MOVE_ABSOLUTE :: 0x01
MOUSE_VIRTUAL_DESKTOP :: 0x02
MOUSE_ATTRIUBTTES_CHANGED :: 0x04
MOUSE_MOVE_NOCOALESCE :: 0x08
RI_MOUSE_BUTTON_1_DOWN :: 0x0001
RI_MOUSE_LEFT_BUTTON_DOWNS :: RI_MOUSE_BUTTON_1_DOWN
RI_MOUSE_BUTTON_1_UP :: 0x0002
RI_MOUSE_LEFT_BUTTON_UP :: RI_MOUSE_BUTTON_1_UP
RI_MOUSE_BUTTON_2_DOWN :: 0x0004
RI_MOUSE_RIGHT_BUTTON_DOWN :: RI_MOUSE_BUTTON_2_DOWN
RI_MOUSE_BUTTON_2_UP :: 0x0008
RI_MOUSE_RIGHT_BUTTON_UP :: RI_MOUSE_BUTTON_2_UP
RI_MOUSE_BUTTON_3_DOWN :: 0x0010
RI_MOUSE_MIDDLE_BUTTON_DOWN :: RI_MOUSE_BUTTON_3_DOWN
RI_MOUSE_BUTTON_3_UP :: 0x0020
RI_MOUSE_MIDDLE_BUTTON_UP :: RI_MOUSE_BUTTON_3_UP
RI_MOUSE_BUTTON_4_DOWN :: 0x0040
RI_MOUSE_BUTTON_4_UP :: 0x0080
RI_MOUSE_BUTTON_5_DOWN :: 0x0100
RI_MOUSE_BUTTON_5_UP :: 0x0200
RI_MOUSE_WHEEL :: 0x0400
RI_MOUSE_HWHEEL :: 0x0800
+1 -1
View File
@@ -62,7 +62,7 @@ GetExtensionsStringARBType :: #type proc "c" (HDC) -> cstring
// Procedures
wglCreateContextAttribsARB: CreateContextAttribsARBType
wglChoosePixelFormatARB: ChoosePixelFormatARBType
wglSwapIntervalExt: SwapIntervalEXTType
wglSwapIntervalEXT: SwapIntervalEXTType
wglGetExtensionsStringARB: GetExtensionsStringARBType
+147
View File
@@ -0,0 +1,147 @@
// +build windows
package sys_windows
// WGL_ARB_buffer_region
WGL_FRONT_COLOR_BUFFER_BIT_ARB :: 0x00000001
WGL_BACK_COLOR_BUFFER_BIT_ARB :: 0x00000002
WGL_DEPTH_BUFFER_BIT_ARB :: 0x00000004
WGL_STENCIL_BUFFER_BIT_ARB :: 0x00000008
wglCreateBufferRegionARBType :: #type proc "c" (hDC: HDC, iLayerPlane: c_int, uType: UINT) -> HANDLE
wglDeleteBufferRegionARBType :: #type proc "c" (hRegion: HANDLE)
wglSaveBufferRegionARBType :: #type proc "c" (hRegion: HANDLE, x: c_int, y: c_int, width: c_int, height: c_int) -> BOOL
wglRestoreBufferRegionARBType :: #type proc "c" (hRegion: HANDLE, x: c_int, y: c_int, width: c_int, height: c_int, xSrc: c_int, ySrc: c_int) -> BOOL
// wglCreateBufferRegionARB: wglCreateBufferRegionARBType
// wglDeleteBufferRegionARB: wglDeleteBufferRegionARBType
// wglSaveBufferRegionARB: wglSaveBufferRegionARBType
// wglRestoreBufferRegionARB: wglRestoreBufferRegionARBType
// WGL_ARB_context_flush_control
WGL_CONTEXT_RELEASE_BEHAVIOR_ARB :: 0x2097
WGL_CONTEXT_RELEASE_BEHAVIOR_NONE_ARB :: 0
WGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_ARB :: 0x2098
// WGL_ARB_create_context
WGL_CONTEXT_DEBUG_BIT_ARB :: 0x0001
WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002
WGL_CONTEXT_MAJOR_VERSION_ARB :: 0x2091
WGL_CONTEXT_MINOR_VERSION_ARB :: 0x2092
WGL_CONTEXT_LAYER_PLANE_ARB :: 0x2093
WGL_CONTEXT_FLAGS_ARB :: 0x2094
ERROR_INVALID_VERSION_ARB :: 0x2095
// WGL_ARB_create_context_no_error
WGL_CONTEXT_OPENGL_NO_ERROR_ARB :: 0x31B3
// WGL_ARB_create_context_profile
WGL_CONTEXT_PROFILE_MASK_ARB :: 0x9126
WGL_CONTEXT_CORE_PROFILE_BIT_ARB :: 0x0001
WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB :: 0x0002
ERROR_INVALID_PROFILE_ARB :: 0x2096
// WGL_ARB_create_context_robustness
WGL_CONTEXT_ROBUST_ACCESS_BIT_ARB :: 0x00000004
WGL_LOSE_CONTEXT_ON_RESET_ARB :: 0x8252
WGL_CONTEXT_RESET_NOTIFICATION_STRATEGY_ARB :: 0x8256
WGL_NO_RESET_NOTIFICATION_ARB :: 0x8261
// WGL_ARB_framebuffer_sRGB
WGL_FRAMEBUFFER_SRGB_CAPABLE_ARB :: 0x20A9
// WGL_ARB_make_current_read
ERROR_INVALID_PIXEL_TYPE_ARB :: 0x2043
ERROR_INCOMPATIBLE_DEVICE_CONTEXTS_ARB :: 0x2054
wglMakeContextCurrentARBType :: #type proc "c" (hDrawDC: HDC, hReadDC:HDC, hglrc: HGLRC) -> BOOL
wglGetCurrentReadDCARBType :: #type proc "c" () -> HDC
// wglMakeContextCurrentARB: wglMakeContextCurrentARBType
// wglGetCurrentReadDCARB: wglGetCurrentReadDCARBType
// WGL_ARB_multisample
WGL_SAMPLE_BUFFERS_ARB :: 0x2041
WGL_SAMPLES_ARB :: 0x2042
// WGL_ARB_pbuffer
HPBUFFERARB :: distinct rawptr
WGL_DRAW_TO_PBUFFER_ARB :: 0x202D
WGL_MAX_PBUFFER_PIXELS_ARB :: 0x202E
WGL_MAX_PBUFFER_WIDTH_ARB :: 0x202F
WGL_MAX_PBUFFER_HEIGHT_ARB :: 0x2030
WGL_PBUFFER_LARGEST_ARB :: 0x2033
WGL_PBUFFER_WIDTH_ARB :: 0x2034
WGL_PBUFFER_HEIGHT_ARB :: 0x2035
WGL_PBUFFER_LOST_ARB :: 0x2036
wglCreatePbufferARBType :: #type proc "c" (hDC: HDC, iPixelFormat, iWidth, iHeight: c_int, piAttribList: [^]c_int) -> HPBUFFERARB
wglGetPbufferDCARBType :: #type proc "c" (hPbuffer: HPBUFFERARB) -> HDC
wglReleasePbufferDCARBType :: #type proc "c" (hPbuffer: HPBUFFERARB, hDC: HDC) -> c_int
wglDestroyPbufferARBType :: #type proc "c" (hPbuffer: HPBUFFERARB) -> BOOL
wglQueryPbufferARBType :: #type proc "c" (hPbuffer: HPBUFFERARB, iAttribute: c_int, piValue: ^c_int) -> BOOL
// wglCreatePbufferARB: wglCreatePbufferARBType
// wglGetPbufferDCARB: wglGetPbufferDCARBType
// wglReleasePbufferDCARB: wglReleasePbufferDCARBType
// wglDestroyPbufferARB: wglDestroyPbufferARBType
// wglQueryPbufferARB: wglQueryPbufferARBType
// WGL_ARB_pixel_format
WGL_NUMBER_PIXEL_FORMATS_ARB :: 0x2000
WGL_DRAW_TO_WINDOW_ARB :: 0x2001
WGL_DRAW_TO_BITMAP_ARB :: 0x2002
WGL_ACCELERATION_ARB :: 0x2003
WGL_NEED_PALETTE_ARB :: 0x2004
WGL_NEED_SYSTEM_PALETTE_ARB :: 0x2005
WGL_SWAP_LAYER_BUFFERS_ARB :: 0x2006
WGL_SWAP_METHOD_ARB :: 0x2007
WGL_NUMBER_OVERLAYS_ARB :: 0x2008
WGL_NUMBER_UNDERLAYS_ARB :: 0x2009
WGL_TRANSPARENT_ARB :: 0x200A
WGL_TRANSPARENT_RED_VALUE_ARB :: 0x2037
WGL_TRANSPARENT_GREEN_VALUE_ARB :: 0x2038
WGL_TRANSPARENT_BLUE_VALUE_ARB :: 0x2039
WGL_TRANSPARENT_ALPHA_VALUE_ARB :: 0x203A
WGL_TRANSPARENT_INDEX_VALUE_ARB :: 0x203B
WGL_SHARE_DEPTH_ARB :: 0x200C
WGL_SHARE_STENCIL_ARB :: 0x200D
WGL_SHARE_ACCUM_ARB :: 0x200E
WGL_SUPPORT_GDI_ARB :: 0x200F
WGL_SUPPORT_OPENGL_ARB :: 0x2010
WGL_DOUBLE_BUFFER_ARB :: 0x2011
WGL_STEREO_ARB :: 0x2012
WGL_PIXEL_TYPE_ARB :: 0x2013
WGL_COLOR_BITS_ARB :: 0x2014
WGL_RED_BITS_ARB :: 0x2015
WGL_RED_SHIFT_ARB :: 0x2016
WGL_GREEN_BITS_ARB :: 0x2017
WGL_GREEN_SHIFT_ARB :: 0x2018
WGL_BLUE_BITS_ARB :: 0x2019
WGL_BLUE_SHIFT_ARB :: 0x201A
WGL_ALPHA_BITS_ARB :: 0x201B
WGL_ALPHA_SHIFT_ARB :: 0x201C
WGL_ACCUM_BITS_ARB :: 0x201D
WGL_ACCUM_RED_BITS_ARB :: 0x201E
WGL_ACCUM_GREEN_BITS_ARB :: 0x201F
WGL_ACCUM_BLUE_BITS_ARB :: 0x2020
WGL_ACCUM_ALPHA_BITS_ARB :: 0x2021
WGL_DEPTH_BITS_ARB :: 0x2022
WGL_STENCIL_BITS_ARB :: 0x2023
WGL_AUX_BUFFERS_ARB :: 0x2024
WGL_NO_ACCELERATION_ARB :: 0x2025
WGL_GENERIC_ACCELERATION_ARB :: 0x2026
WGL_FULL_ACCELERATION_ARB :: 0x2027
WGL_SWAP_EXCHANGE_ARB :: 0x2028
WGL_SWAP_COPY_ARB :: 0x2029
WGL_SWAP_UNDEFINED_ARB :: 0x202A
WGL_TYPE_RGBA_ARB :: 0x202B
WGL_TYPE_COLORINDEX_ARB :: 0x202C
wglGetPixelFormatAttribivARBType :: #type proc "c" (hdc: HDC, iPixelFormat, iLayerPlane: c_int, nAttributes: UINT, piAttributes: [^]c_int, piValues: [^]c_int) -> BOOL
wglGetPixelFormatAttribfvARBType :: #type proc "c" (hdc: HDC, iPixelFormat, iLayerPlane: c_int, nAttributes: UINT, piAttributes: [^]c_int, pfValues: [^]f32) -> BOOL
// wglGetPixelFormatAttribivARB: wglGetPixelFormatAttribivARBType
// wglGetPixelFormatAttribfvARB: wglGetPixelFormatAttribfvARBType
// WGL_ARB_pixel_format_float
WGL_TYPE_RGBA_FLOAT_ARB :: 0x21A0
+39
View File
@@ -153,6 +153,7 @@ BM_CLICK :: 0x00f5
BM_GETIMAGE :: 0x00f6
BM_SETIMAGE :: 0x00f7
BM_SETDONTCLICK :: 0x00f8
WM_INPUT_DEVICE_CHANGE :: 0x00fe
WM_INPUT :: 0x00ff
WM_KEYDOWN :: 0x0100
WM_KEYFIRST :: 0x0100
@@ -165,6 +166,7 @@ WM_SYSCHAR :: 0x0106
WM_SYSDEADCHAR :: 0x0107
WM_UNICHAR :: 0x0109
WM_KEYLAST :: 0x0109
UNICODE_NOCHAR :: 0xFFFF
WM_WNT_CONVERTREQUESTEX :: 0x0109
WM_CONVERTREQUEST :: 0x010a
WM_CONVERTRESULT :: 0x010b
@@ -279,6 +281,27 @@ WM_ENTERSIZEMOVE :: 0x0231
WM_EXITSIZEMOVE :: 0x0232
WM_DROPFILES :: 0x0233
WM_MDIREFRESHMENU :: 0x0234
WM_POINTERDEVICECHANGE :: 0x0238
WM_POINTERDEVICEINRANGE :: 0x0239
WM_POINTERDEVICEOUTOFRANGE :: 0x023a
WM_TOUCH :: 0x0240
WM_NCPOINTERUPDATE :: 0x0241
WM_NCPOINTERDOWN :: 0x0242
WM_NCPOINTERUP :: 0x0243
WM_POINTERUPDATE :: 0x0245
WM_POINTERDOWN :: 0x0246
WM_POINTERUP :: 0x0247
WM_POINTERENTER :: 0x0249
WM_POINTERLEAVE :: 0x024a
WM_POINTERACTIVATE :: 0x024b
WM_POINTERCAPTURECHANGED :: 0x024c
WM_TOUCHHITTESTING :: 0x024d
WM_POINTERWHEEL :: 0x024e
WM_POINTERHWHEEL :: 0x024f
DM_POINTERHITTEST :: 0x0250
WM_POINTERROUTEDTO :: 0x0251
WM_POINTERROUTEDAWAY :: 0x0252
WM_POINTERROUTEDRELEASED :: 0x0253
WM_IME_REPORT :: 0x0280
WM_IME_SETCONTEXT :: 0x0281
WM_IME_NOTIFY :: 0x0282
@@ -295,6 +318,13 @@ WM_NCMOUSEHOVER :: 0x02a0
WM_MOUSEHOVER :: 0x02a1
WM_NCMOUSELEAVE :: 0x02a2
WM_MOUSELEAVE :: 0x02a3
WM_WTSSESSION_CHANGE :: 0x02b1
WM_TABLET_FIRST :: 0x02c0
WM_TABLET_LAST :: 0x02df
WM_DPICHANGED :: 0x02e0
WM_DPICHANGED_BEFOREPARENT :: 0x02e2
WM_DPICHANGED_AFTERPARENT :: 0x02e3
WM_GETDPISCALEDSIZE :: 0x02e4
WM_CUT :: 0x0300
WM_COPY :: 0x0301
WM_PASTE :: 0x0302
@@ -317,6 +347,15 @@ WM_HOTKEY :: 0x0312
WM_PRINT :: 0x0317
WM_PRINTCLIENT :: 0x0318
WM_APPCOMMAND :: 0x0319
WM_THEMECHANGED :: 0x031A
WM_CLIPBOARDUPDATE :: 0x031D
WM_DWMCOMPOSITIONCHANGED :: 0x031E
WM_DWMNCRENDERINGCHANGED :: 0x031F
WM_DWMCOLORIZATIONCOLORCHANGED:: 0x0320
WM_DWMWINDOWMAXIMIZEDCHANGE :: 0x0321
WM_DWMSENDICONICTHUMBNAIL :: 0x0323
WM_DWMSENDICONICLIVEPREVIEWBITMAP :: 0x0326
WM_GETTITLEBARINFOEX :: 0x033F
WM_HANDHELDFIRST :: 0x0358
WM_HANDHELDLAST :: 0x035f
WM_AFXFIRST :: 0x0360
+2
View File
@@ -42,6 +42,8 @@ ERROR_TIMEOUT : DWORD : 1460
ERROR_DATATYPE_MISMATCH : DWORD : 1629
ERROR_UNSUPPORTED_TYPE : DWORD : 1630
ERROR_NOT_SAME_OBJECT : DWORD : 1656
ERROR_PIPE_CONNECTED : DWORD : 0x80070217
ERROR_PIPE_BUSY : DWORD : 231
E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001
+2 -2
View File
@@ -99,14 +99,14 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur
}
for k in keys {
interned_key := strings.intern_get(&translation.intern, string(k))
interned_key, _ := strings.intern_get(&translation.intern, string(k))
interned_vals := make([]string, len(keys))
last_val: string
i := 0
for v in vals {
interned_vals[i] = strings.intern_get(&translation.intern, string(v))
interned_vals[i], _ = strings.intern_get(&translation.intern, string(v))
last_val = interned_vals[i]
i += 1
}
+5 -5
View File
@@ -59,9 +59,9 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
return translation, .TS_File_Expected_Context_Name,
}
section_name := strings.intern_get(&translation.intern, "")
section_name, _ := strings.intern_get(&translation.intern, "")
if !options.merge_sections {
section_name = strings.intern_get(&translation.intern, ts.elements[section_name_id].value)
section_name, _ = strings.intern_get(&translation.intern, ts.elements[section_name_id].value)
}
if section_name not_in translation.k_v {
@@ -92,8 +92,8 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
return translation, .TS_File_Expected_Translation
}
source := strings.intern_get(&translation.intern, ts.elements[source_id].value)
xlat := strings.intern_get(&translation.intern, ts.elements[translation_id].value)
source, _ := strings.intern_get(&translation.intern, ts.elements[source_id].value)
xlat, _ := strings.intern_get(&translation.intern, ts.elements[translation_id].value)
if source in section {
return translation, .Duplicate_Key
@@ -124,7 +124,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
if !numerus_found {
break
}
numerus := strings.intern_get(&translation.intern, ts.elements[numerus_id].value)
numerus, _ := strings.intern_get(&translation.intern, ts.elements[numerus_id].value)
section[source][num_plurals] = numerus
num_plurals += 1
+46 -64
View File
@@ -116,6 +116,7 @@ struct TargetMetrics {
TargetArchKind arch;
isize word_size;
isize max_align;
isize max_simd_align;
String target_triplet;
String target_data_layout;
TargetABIKind abi;
@@ -204,7 +205,7 @@ enum BuildPath : u8 {
BuildPath_Main_Package, // Input Path to the package directory (or file) we're building.
BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`.
BuildPath_RES, // Output Path for .res file, generated from previous.
BuildPath_Win_SDK_Root, // windows_sdk_root
BuildPath_Win_SDK_Bin_Path, // windows_sdk_bin_path
BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path
BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path
BuildPath_VS_EXE, // vs_exe_path
@@ -228,14 +229,16 @@ struct BuildContext {
bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
bool ODIN_FOREIGN_ERROR_PROCEDURES;
bool ODIN_VALGRIND_SUPPORT;
ErrorPosStyle ODIN_ERROR_POS_STYLE;
TargetEndianKind endian_kind;
// In bytes
i64 word_size; // Size of a pointer, must be >= 4
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
i64 word_size; // Size of a pointer, must be >= 4
i64 max_align; // max alignment, must be >= 1 (and typically >= word_size)
i64 max_simd_align; // max alignment, must be >= 1 (and typically >= word_size)
CommandKind command_kind;
String command;
@@ -338,15 +341,13 @@ bool global_ignore_warnings(void) {
gb_global TargetMetrics target_windows_i386 = {
TargetOs_windows,
TargetArch_i386,
4,
8,
4, 4, 8,
str_lit("i386-pc-windows-msvc"),
};
gb_global TargetMetrics target_windows_amd64 = {
TargetOs_windows,
TargetArch_amd64,
8,
16,
8, 8, 16,
str_lit("x86_64-pc-windows-msvc"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
@@ -354,24 +355,21 @@ gb_global TargetMetrics target_windows_amd64 = {
gb_global TargetMetrics target_linux_i386 = {
TargetOs_linux,
TargetArch_i386,
4,
8,
4, 4, 8,
str_lit("i386-pc-linux-gnu"),
};
gb_global TargetMetrics target_linux_amd64 = {
TargetOs_linux,
TargetArch_amd64,
8,
16,
8, 8, 16,
str_lit("x86_64-pc-linux-gnu"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
gb_global TargetMetrics target_linux_arm64 = {
TargetOs_linux,
TargetArch_arm64,
8,
16,
8, 8, 16,
str_lit("aarch64-linux-elf"),
str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
};
@@ -379,8 +377,7 @@ gb_global TargetMetrics target_linux_arm64 = {
gb_global TargetMetrics target_linux_arm32 = {
TargetOs_linux,
TargetArch_arm32,
4,
8,
4, 4, 8,
str_lit("arm-linux-gnu"),
str_lit("e-m:o-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"),
};
@@ -388,8 +385,7 @@ gb_global TargetMetrics target_linux_arm32 = {
gb_global TargetMetrics target_darwin_amd64 = {
TargetOs_darwin,
TargetArch_amd64,
8,
16,
8, 8, 16,
str_lit("x86_64-apple-darwin"),
str_lit("e-m:o-i64:64-f80:128-n8:16:32:64-S128"),
};
@@ -397,8 +393,7 @@ gb_global TargetMetrics target_darwin_amd64 = {
gb_global TargetMetrics target_darwin_arm64 = {
TargetOs_darwin,
TargetArch_arm64,
8,
16,
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?
};
@@ -406,16 +401,14 @@ gb_global TargetMetrics target_darwin_arm64 = {
gb_global TargetMetrics target_freebsd_i386 = {
TargetOs_freebsd,
TargetArch_i386,
4,
8,
4, 4, 8,
str_lit("i386-unknown-freebsd-elf"),
};
gb_global TargetMetrics target_freebsd_amd64 = {
TargetOs_freebsd,
TargetArch_amd64,
8,
16,
8, 8, 16,
str_lit("x86_64-unknown-freebsd-elf"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
};
@@ -423,8 +416,7 @@ gb_global TargetMetrics target_freebsd_amd64 = {
gb_global TargetMetrics target_openbsd_amd64 = {
TargetOs_openbsd,
TargetArch_amd64,
8,
16,
8, 8, 16,
str_lit("x86_64-unknown-openbsd-elf"),
str_lit("e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"),
};
@@ -432,62 +424,48 @@ gb_global TargetMetrics target_openbsd_amd64 = {
gb_global TargetMetrics target_essence_amd64 = {
TargetOs_essence,
TargetArch_amd64,
8,
16,
8, 8, 16,
str_lit("x86_64-pc-none-elf"),
};
gb_global TargetMetrics target_freestanding_wasm32 = {
TargetOs_freestanding,
TargetArch_wasm32,
4,
8,
4, 8, 16,
str_lit("wasm32-freestanding-js"),
str_lit(""),
str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
};
gb_global TargetMetrics target_js_wasm32 = {
TargetOs_js,
TargetArch_wasm32,
4,
8,
4, 8, 16,
str_lit("wasm32-js-js"),
str_lit(""),
};
gb_global TargetMetrics target_js_wasm64 = {
TargetOs_js,
TargetArch_wasm64,
8,
16,
str_lit("wasm64-js-js"),
str_lit(""),
str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
};
gb_global TargetMetrics target_wasi_wasm32 = {
TargetOs_wasi,
TargetArch_wasm32,
4,
8,
4, 8, 16,
str_lit("wasm32-wasi-js"),
str_lit(""),
str_lit("e-m:e-p:32:32-i64:64-n32:64-S128"),
};
// gb_global TargetMetrics target_freestanding_wasm64 = {
// TargetOs_freestanding,
// TargetArch_wasm64,
// 8,
// 16,
// str_lit("wasm64-freestanding-js"),
// str_lit(""),
// };
gb_global TargetMetrics target_js_wasm64 = {
TargetOs_js,
TargetArch_wasm64,
8, 8, 16,
str_lit("wasm64-js-js"),
str_lit(""),
};
gb_global TargetMetrics target_freestanding_amd64_sysv = {
TargetOs_freestanding,
TargetArch_amd64,
8,
16,
8, 8, 16,
str_lit("x86_64-pc-none-gnu"),
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
TargetABI_SysV,
@@ -516,7 +494,7 @@ gb_global NamedTargetMetrics named_targets[] = {
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 },
{ str_lit("js_wasm32"), &target_js_wasm32 },
{ str_lit("js_wasm64"), &target_js_wasm64 },
// { str_lit("js_wasm64"), &target_js_wasm64 },
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
};
@@ -1083,14 +1061,16 @@ void init_build_context(TargetMetrics *cross_target) {
GB_ASSERT(metrics->arch != TargetArch_Invalid);
GB_ASSERT(metrics->word_size > 1);
GB_ASSERT(metrics->max_align > 1);
GB_ASSERT(metrics->max_simd_align > 1);
bc->metrics = *metrics;
bc->ODIN_OS = target_os_names[metrics->os];
bc->ODIN_ARCH = target_arch_names[metrics->arch];
bc->endian_kind = target_endians[metrics->arch];
bc->word_size = metrics->word_size;
bc->max_align = metrics->max_align;
bc->ODIN_OS = target_os_names[metrics->os];
bc->ODIN_ARCH = target_arch_names[metrics->arch];
bc->endian_kind = target_endians[metrics->arch];
bc->word_size = metrics->word_size;
bc->max_align = metrics->max_align;
bc->max_simd_align = metrics->max_simd_align;
bc->link_flags = str_lit(" ");
#if defined(DEFAULT_TO_THREADED_CHECKER)
@@ -1190,6 +1170,8 @@ 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;
#undef LINK_FLAG_X64
#undef LINK_FLAG_386
}
@@ -1336,7 +1318,7 @@ 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_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8();
Find_Result find_result = find_visual_studio_and_windows_sdk();
defer (mc_free_all());
if (find_result.windows_sdk_version == 0) {
@@ -1357,8 +1339,8 @@ bool init_build_paths(String init_filename) {
if (find_result.windows_sdk_um_library_path.len > 0) {
GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0);
if (find_result.windows_sdk_root.len > 0) {
bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root);
if (find_result.windows_sdk_bin_path.len > 0) {
bc->build_paths[BuildPath_Win_SDK_Bin_Path] = path_from_string(ha, find_result.windows_sdk_bin_path);
}
if (find_result.windows_sdk_um_library_path.len > 0) {
+546 -453
View File
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -320,7 +320,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
} else if (is_type_any(e->type)) {
error(init_expr, "'distinct' cannot be applied to 'any'");
is_distinct = false;
} else if (is_type_simd_vector(e->type)) {
} else if (is_type_simd_vector(e->type) || is_type_soa_pointer(e->type)) {
gbString str = type_to_string(e->type);
error(init_expr, "'distinct' cannot be applied to '%s'", str);
gb_string_free(str);
+132 -13
View File
@@ -119,6 +119,29 @@ 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);
void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_);
bool is_diverging_expr(Ast *expr);
enum LoadDirectiveResult {
LoadDirective_Success = 0,
LoadDirective_Error = 1,
LoadDirective_NotFound = 2,
};
bool is_load_directive_call(Ast *call) {
call = unparen_expr(call);
if (call->kind != Ast_CallExpr) {
return false;
}
ast_node(ce, CallExpr, call);
if (ce->proc->kind != Ast_BasicDirective) {
return false;
}
ast_node(bd, BasicDirective, ce->proc);
String name = bd->name.string;
return name == "load";
}
LoadDirectiveResult check_load_directive(CheckerContext *c, Operand *operand, Ast *call, Type *type_hint, bool err_on_not_found);
void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") {
auto results = did_you_mean_results(d);
@@ -795,6 +818,10 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
}
if (is_type_matrix(dst)) {
if (are_types_identical(src, dst)) {
return 5;
}
Type *dst_elem = base_array_type(dst);
i64 distance = check_distance_between_types(c, operand, dst_elem);
if (distance >= 0) {
@@ -2051,7 +2078,7 @@ bool check_is_not_addressable(CheckerContext *c, Operand *o) {
return false;
}
return o->mode != Addressing_Variable;
return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable;
}
void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
@@ -2068,9 +2095,6 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str);
} else {
switch (o->mode) {
case Addressing_SoaVariable:
error(op, "Cannot take the pointer address of '%s' as it is an indirect index of an SOA struct", str);
break;
case Addressing_Constant:
error(op, "Cannot take the pointer address of '%s' which is a constant", str);
break;
@@ -2098,7 +2122,19 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
return;
}
o->type = alloc_type_pointer(o->type);
if (o->mode == Addressing_SoaVariable) {
ast_node(ue, UnaryExpr, node);
if (ast_node_expect(ue->expr, Ast_IndexExpr)) {
ast_node(ie, IndexExpr, ue->expr);
Type *soa_type = type_of_expr(ie->expr);
GB_ASSERT(is_type_soa_struct(soa_type));
o->type = alloc_type_soa_pointer(soa_type);
} else {
o->type = alloc_type_pointer(o->type);
}
} else {
o->type = alloc_type_pointer(o->type);
}
switch (o->mode) {
case Addressing_OptionalOk:
@@ -2495,8 +2531,17 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
x->expr->tav.is_lhs = true;
}
x->mode = Addressing_Value;
if (type_hint && is_type_integer(type_hint)) {
x->type = type_hint;
if (type_hint) {
if (is_type_integer(type_hint)) {
x->type = type_hint;
} else {
gbString x_str = expr_to_string(x->expr);
gbString to_type = type_to_string(type_hint);
error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type);
gb_string_free(x_str);
gb_string_free(to_type);
x->mode = Addressing_Invalid;
}
}
// x->value = x_val;
return;
@@ -2512,7 +2557,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
// TODO(bill): Should we support shifts for fixed arrays and #simd vectors?
if (!is_type_integer(x->type)) {
gbString err_str = expr_to_string(y->expr);
gbString err_str = expr_to_string(x->expr);
error(node, "Shift operand '%s' must be an integer", err_str);
gb_string_free(err_str);
x->mode = Addressing_Invalid;
@@ -7388,9 +7433,59 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
String name = oe->token.string;
Ast *arg = oe->x;
Ast *default_value = oe->y;
Operand x = {};
Operand y = {};
// NOTE(bill, 2022-08-11): edge case to handle #load(path) or_else default
if (is_load_directive_call(arg)) {
LoadDirectiveResult res = check_load_directive(c, &x, arg, type_hint, false);
// Allow for chaining of '#load(path) or_else #load(path)'
if (!(is_load_directive_call(default_value) && res == LoadDirective_Success)) {
bool y_is_diverging = false;
check_expr_base(c, &y, default_value, x.type);
switch (y.mode) {
case Addressing_NoValue:
if (is_diverging_expr(y.expr)) {
// Allow
y.mode = Addressing_Value;
y_is_diverging = true;
} else {
error_operand_no_value(&y);
y.mode = Addressing_Invalid;
}
break;
case Addressing_Type:
error_operand_not_expression(&y);
y.mode = Addressing_Invalid;
break;
}
if (y.mode == Addressing_Invalid) {
o->mode = Addressing_Value;
o->type = t_invalid;
o->expr = node;
return Expr_Expr;
}
if (!y_is_diverging) {
check_assignment(c, &y, x.type, name);
if (y.mode != Addressing_Constant) {
error(y.expr, "expected a constant expression on the right-hand side of 'or_else' in conjuction with '#load'");
}
}
}
if (res == LoadDirective_Success) {
*o = x;
} else {
*o = y;
}
o->expr = node;
return Expr_Expr;
}
check_multi_expr_with_type_hint(c, &x, arg, type_hint);
if (x.mode == Addressing_Invalid) {
o->mode = Addressing_Value;
@@ -7398,9 +7493,25 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
o->expr = node;
return Expr_Expr;
}
bool y_is_diverging = false;
check_expr_base(c, &y, default_value, x.type);
switch (y.mode) {
case Addressing_NoValue:
if (is_diverging_expr(y.expr)) {
// Allow
y.mode = Addressing_Value;
y_is_diverging = true;
} else {
error_operand_no_value(&y);
y.mode = Addressing_Invalid;
}
break;
case Addressing_Type:
error_operand_not_expression(&y);
y.mode = Addressing_Invalid;
break;
}
check_multi_expr_with_type_hint(c, &y, default_value, x.type);
error_operand_no_value(&y);
if (y.mode == Addressing_Invalid) {
o->mode = Addressing_Value;
o->type = t_invalid;
@@ -7414,7 +7525,9 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value);
if (left_type != nullptr) {
check_assignment(c, &y, left_type, name);
if (!y_is_diverging) {
check_assignment(c, &y, left_type, name);
}
} else {
check_or_else_expr_no_value_error(c, name, x, type_hint);
}
@@ -8656,7 +8769,10 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type
Ast *first_arg = x.expr->SelectorExpr.expr;
GB_ASSERT(first_arg != nullptr);
first_arg->state_flags |= StateFlag_SelectorCallExpr;
Entity *e = entity_of_node(se->expr);
if (!(e != nullptr && (e->kind == Entity_Procedure || e->kind == Entity_ProcGroup))) {
first_arg->state_flags |= StateFlag_SelectorCallExpr;
}
Type *pt = base_type(x.type);
GB_ASSERT(pt->kind == Type_Proc);
@@ -9358,6 +9474,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) {
o->mode = Addressing_Variable;
o->type = t->Pointer.elem;
} else if (t->kind == Type_SoaPointer) {
o->mode = Addressing_SoaVariable;
o->type = type_deref(t);
} else if (t->kind == Type_RelativePointer) {
if (o->mode != Addressing_Variable) {
gbString str = expr_to_string(o->expr);
+54 -5
View File
@@ -1,8 +1,5 @@
bool is_diverging_stmt(Ast *stmt) {
if (stmt->kind != Ast_ExprStmt) {
return false;
}
Ast *expr = unparen_expr(stmt->ExprStmt.expr);
bool is_diverging_expr(Ast *expr) {
expr = unparen_expr(expr);
if (expr->kind != Ast_CallExpr) {
return false;
}
@@ -26,6 +23,12 @@ bool is_diverging_stmt(Ast *stmt) {
t = base_type(t);
return t != nullptr && t->kind == Type_Proc && t->Proc.diverging;
}
bool is_diverging_stmt(Ast *stmt) {
if (stmt->kind != Ast_ExprStmt) {
return false;
}
return is_diverging_expr(stmt->ExprStmt.expr);
}
bool contains_deferred_call(Ast *node) {
if (node->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) {
@@ -1393,6 +1396,23 @@ bool check_stmt_internal_builtin_proc_id(Ast *expr, BuiltinProcId *id_) {
return id != BuiltinProc_Invalid;
}
bool check_expr_is_stack_variable(Ast *expr) {
expr = unparen_expr(expr);
Entity *e = entity_of_node(expr);
if (e && e->kind == Entity_Variable) {
if (e->flags & (EntityFlag_Static|EntityFlag_Using)) {
// okay
} else if (e->Variable.thread_local_model.len != 0) {
// okay
} else if (e->scope) {
if ((e->scope->flags & (ScopeFlag_Global|ScopeFlag_File|ScopeFlag_Type)) == 0) {
return true;
}
}
}
return false;
}
void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
switch (node->kind) {
@@ -1444,6 +1464,12 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
AstSelectorCallExpr *se = &expr->SelectorCallExpr;
ast_node(ce, CallExpr, se->call);
Type *t = base_type(type_of_expr(ce->proc));
if (t == nullptr) {
gbString expr_str = expr_to_string(ce->proc);
error(node, "'%s' is not a value field nor procedure", expr_str);
gb_string_free(expr_str);
return;
}
if (t->kind == Type_Proc) {
do_require = t->Proc.require_results;
} else if (check_stmt_internal_builtin_proc_id(ce->proc, &builtin_id)) {
@@ -1675,6 +1701,29 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
if (is_type_untyped(o->type)) {
update_untyped_expr_type(ctx, o->expr, e->type, true);
}
// NOTE(bill): This is very basic escape analysis
// This needs to be improved tremendously, and a lot of it done during the
// middle-end (or LLVM side) to improve checks and error messages
Ast *expr = unparen_expr(o->expr);
if (expr->kind == Ast_UnaryExpr && expr->UnaryExpr.op.kind == Token_And) {
Ast *x = unparen_expr(expr->UnaryExpr.expr);
if (x->kind == Ast_CompoundLit) {
error(expr, "Cannot return the address to a stack value from a procedure");
} else if (x->kind == Ast_IndexExpr) {
Ast *array = x->IndexExpr.expr;
if (is_type_array_like(type_of_expr(array)) && check_expr_is_stack_variable(array)) {
gbString t = type_to_string(type_of_expr(array));
error(expr, "Cannot return the address to an element of stack variable from a procedure, of type %s", t);
gb_string_free(t);
}
} else {
if (check_expr_is_stack_variable(x)) {
error(expr, "Cannot return the address to a stack variable from a procedure");
}
}
}
}
}
case_end;
+24 -4
View File
@@ -2693,9 +2693,12 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
case_ast_node(ue, UnaryExpr, e);
switch (ue->op.kind) {
case Token_Pointer:
*type = alloc_type_pointer(check_type(ctx, ue->expr));
set_base_type(named_type, *type);
return true;
{
Type *elem = check_type(ctx, ue->expr);
*type = alloc_type_pointer(elem);
set_base_type(named_type, *type);
return true;
}
}
case_end;
@@ -2721,7 +2724,24 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
elem = o.type;
}
*type = alloc_type_pointer(elem);
if (pt->tag != nullptr) {
GB_ASSERT(pt->tag->kind == Ast_BasicDirective);
String name = pt->tag->BasicDirective.name.string;
if (name == "soa") {
// TODO(bill): generic #soa pointers
if (is_type_soa_struct(elem)) {
*type = alloc_type_soa_pointer(elem);
} else {
error(pt->tag, "#soa pointers require an #soa record type as the element");
*type = alloc_type_pointer(elem);
}
} else {
error(pt->tag, "Invalid tag applied to pointer, got #%.*s", LIT(name));
*type = alloc_type_pointer(elem);
}
} else {
*type = alloc_type_pointer(elem);
}
set_base_type(named_type, *type);
return true;
case_end;
+18
View File
@@ -1037,6 +1037,9 @@ void init_universal(void) {
add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES);
add_global_bool_constant("ODIN_DISALLOW_RTTI", bc->disallow_rtti);
add_global_bool_constant("ODIN_VALGRIND_SUPPORT", bc->ODIN_VALGRIND_SUPPORT);
// Builtin Procedures
for (isize i = 0; i < gb_count_of(builtin_procs); i++) {
@@ -1170,6 +1173,8 @@ void init_checker_info(CheckerInfo *i) {
mutex_init(&i->objc_types_mutex);
map_init(&i->objc_msgSend_types, a);
mutex_init(&i->load_file_mutex);
string_map_init(&i->load_file_cache, a);
}
void destroy_checker_info(CheckerInfo *i) {
@@ -1205,6 +1210,8 @@ void destroy_checker_info(CheckerInfo *i) {
mutex_destroy(&i->objc_types_mutex);
map_destroy(&i->objc_msgSend_types);
mutex_init(&i->load_file_mutex);
string_map_destroy(&i->load_file_cache);
}
CheckerContext make_checker_context(Checker *c) {
@@ -1947,6 +1954,11 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
add_type_info_type_internal(c, bt->Matrix.elem);
break;
case Type_SoaPointer:
add_type_info_type_internal(c, bt->SoaPointer.elem);
break;
default:
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
break;
@@ -2164,6 +2176,10 @@ void add_min_dep_type_info(Checker *c, Type *t) {
add_min_dep_type_info(c, bt->Matrix.elem);
break;
case Type_SoaPointer:
add_min_dep_type_info(c, bt->SoaPointer.elem);
break;
default:
GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind]));
break;
@@ -2756,6 +2772,7 @@ void init_core_type_info(Checker *c) {
t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer"));
t_type_info_relative_slice = find_core_type(c, str_lit("Type_Info_Relative_Slice"));
t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix"));
t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer"));
t_type_info_named_ptr = alloc_type_pointer(t_type_info_named);
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
@@ -2784,6 +2801,7 @@ void init_core_type_info(Checker *c) {
t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer);
t_type_info_relative_slice_ptr = alloc_type_pointer(t_type_info_relative_slice);
t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix);
t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer);
}
void init_mem_allocator(Checker *c) {
+9
View File
@@ -287,6 +287,12 @@ struct ObjcMsgData {
ObjcMsgKind kind;
Type *proc_type;
};
struct LoadFileCache {
String path;
gbFileError file_error;
String data;
StringMap<u64> hashes;
};
// CheckerInfo stores all the symbol information for a type-checked program
struct CheckerInfo {
@@ -363,6 +369,9 @@ struct CheckerInfo {
BlockingMutex objc_types_mutex;
PtrMap<Ast *, ObjcMsgData> objc_msgSend_types;
BlockingMutex load_file_mutex;
StringMap<LoadFileCache *> load_file_cache;
};
struct CheckerContext {
+9 -1
View File
@@ -40,6 +40,8 @@ enum BuiltinProcId {
BuiltinProc_hadamard_product,
BuiltinProc_matrix_flatten,
BuiltinProc_unreachable,
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
// "Intrinsics"
@@ -289,6 +291,8 @@ BuiltinProc__type_end,
BuiltinProc_wasm_memory_atomic_wait32,
BuiltinProc_wasm_memory_atomic_notify32,
BuiltinProc_valgrind_client_request,
BuiltinProc_COUNT,
};
gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
@@ -330,6 +334,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("matrix_flatten"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("unreachable"), 0, false, Expr_Expr, BuiltinProcPkg_builtin, /*diverging*/true},
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
@@ -341,7 +347,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("alloca"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("cpu_relax"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/true},
{STR_LIT("trap"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics, /*diverging*/true},
{STR_LIT("debug_trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/false},
{STR_LIT("read_cycle_counter"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -578,4 +584,6 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("wasm_memory_size"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("wasm_memory_atomic_wait32"), 3, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("wasm_memory_atomic_notify32"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("valgrind_client_request"), 7, false, Expr_Expr, BuiltinProcPkg_intrinsics},
};
+1
View File
@@ -83,6 +83,7 @@ enum OdinDocTypeKind : u32 {
OdinDocType_RelativeSlice = 21,
OdinDocType_MultiPointer = 22,
OdinDocType_Matrix = 23,
OdinDocType_SoaPointer = 24,
};
enum OdinDocTypeFlag_Basic : u32 {
+4
View File
@@ -532,6 +532,10 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
doc_type.kind = OdinDocType_MultiPointer;
doc_type.types = odin_doc_type_as_slice(w, type->MultiPointer.elem);
break;
case Type_SoaPointer:
doc_type.kind = OdinDocType_SoaPointer;
doc_type.types = odin_doc_type_as_slice(w, type->SoaPointer.elem);
break;
case Type_Array:
doc_type.kind = OdinDocType_Array;
doc_type.elem_count_len = 1;
+1 -1
View File
@@ -90,7 +90,7 @@ extern "C" {
#error This operating system is not supported
#endif
#if defined(GB_SYSTEM_OPENBSD)
#if defined(GB_SYSTEM_UNIX)
#include <sys/wait.h>
#endif
+17 -11
View File
@@ -62,7 +62,7 @@ bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
return LLVMGetTypeKind(type) == kind;
}
LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
unsigned arg_count = cast(unsigned)ft->args.count;
unsigned offset = 0;
@@ -108,10 +108,16 @@ LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
}
unsigned total_arg_count = arg_index;
LLVMTypeRef func_type = LLVMFunctionType(ret, args, total_arg_count, is_var_arg);
return LLVMPointerType(func_type, 0);
return func_type;
}
// LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
// LLVMTypeRef func_type = lb_function_type_to_llvm_raw(ft, is_var_arg);
// return LLVMPointerType(func_type, 0);
// }
void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) {
if (ft == nullptr) {
return;
@@ -217,7 +223,7 @@ i64 lb_sizeof(LLVMTypeRef type) {
break;
case LLVMArrayTypeKind:
{
LLVMTypeRef elem = LLVMGetElementType(type);
LLVMTypeRef elem = OdinLLVMGetArrayElementType(type);
i64 elem_size = lb_sizeof(elem);
i64 count = LLVMGetArrayLength(type);
i64 size = count * elem_size;
@@ -229,7 +235,7 @@ i64 lb_sizeof(LLVMTypeRef type) {
return 8;
case LLVMVectorTypeKind:
{
LLVMTypeRef elem = LLVMGetElementType(type);
LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
i64 elem_size = lb_sizeof(elem);
i64 count = LLVMGetVectorSize(type);
i64 size = count * elem_size;
@@ -277,18 +283,18 @@ i64 lb_alignof(LLVMTypeRef type) {
}
break;
case LLVMArrayTypeKind:
return lb_alignof(LLVMGetElementType(type));
return lb_alignof(OdinLLVMGetArrayElementType(type));
case LLVMX86_MMXTypeKind:
return 8;
case LLVMVectorTypeKind:
{
// TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation
LLVMTypeRef elem = LLVMGetElementType(type);
LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
i64 elem_size = lb_sizeof(elem);
i64 count = LLVMGetVectorSize(type);
i64 size = count * elem_size;
return gb_clamp(next_pow2(size), 1, build_context.max_align);
return gb_clamp(next_pow2(size), 1, build_context.max_simd_align);
}
}
@@ -787,7 +793,7 @@ namespace lbAbiAmd64SysV {
case LLVMArrayTypeKind:
{
i64 len = LLVMGetArrayLength(t);
LLVMTypeRef elem = LLVMGetElementType(t);
LLVMTypeRef elem = OdinLLVMGetArrayElementType(t);
i64 elem_sz = lb_sizeof(elem);
for (i64 i = 0; i < len; i++) {
classify_with(elem, cls, ix, off + i*elem_sz);
@@ -797,7 +803,7 @@ namespace lbAbiAmd64SysV {
case LLVMVectorTypeKind:
{
i64 len = LLVMGetVectorSize(t);
LLVMTypeRef elem = LLVMGetElementType(t);
LLVMTypeRef elem = OdinLLVMGetVectorElementType(t);
i64 elem_sz = lb_sizeof(elem);
LLVMTypeKind elem_kind = LLVMGetTypeKind(elem);
RegClass reg = RegClass_NoClass;
@@ -907,7 +913,7 @@ namespace lbAbiArm64 {
if (len == 0) {
return false;
}
LLVMTypeRef elem = LLVMGetElementType(type);
LLVMTypeRef elem = OdinLLVMGetArrayElementType(type);
LLVMTypeRef base_type = nullptr;
unsigned member_count = 0;
if (is_homogenous_aggregate(c, elem, &base_type, &member_count)) {
@@ -1123,7 +1129,7 @@ namespace lbAbiWasm {
}
if (sz <= MAX_DIRECT_STRUCT_SIZE) {
if (kind == LLVMArrayTypeKind) {
if (is_basic_register_type(LLVMGetElementType(type))) {
if (is_basic_register_type(OdinLLVMGetArrayElementType(type))) {
return true;
}
} else if (kind == LLVMStructTypeKind) {
+5 -6
View File
@@ -739,11 +739,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
lb_begin_procedure_body(p);
if (startup_type_info) {
LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, startup_type_info->type), startup_type_info->value, nullptr, 0, "");
}
if (objc_names) {
LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, "");
LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, "");
}
for_array(i, global_variables) {
@@ -762,7 +762,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
if (init_expr != nullptr) {
lbValue init = lb_build_expr(p, init_expr);
if (init.value == nullptr) {
LLVMTypeRef global_type = LLVMGetElementType(LLVMTypeOf(var->var.value));
LLVMTypeRef global_type = llvm_addr_type(p->module, var->var);
if (is_type_untyped_undef(init.type)) {
// LLVMSetInitializer(var->var.value, LLVMGetUndef(global_type));
LLVMSetInitializer(var->var.value, LLVMConstNull(global_type));
@@ -805,8 +805,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
lb_emit_store(p, ti, lb_type_info(main_module, var_type));
} else {
LLVMTypeRef pvt = LLVMTypeOf(var->var.value);
LLVMTypeRef vt = LLVMGetElementType(pvt);
LLVMTypeRef vt = llvm_addr_type(p->module, var->var);
lbValue src0 = lb_emit_conv(p, var->init, t);
LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
LLVMValueRef dst = var->var.value;
@@ -933,7 +932,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
GB_ASSERT(LLVMIsConstant(vals[1]));
GB_ASSERT(LLVMIsConstant(vals[2]));
LLVMValueRef dst = LLVMConstInBoundsGEP(all_tests_array.value, indices, gb_count_of(indices));
LLVMValueRef dst = LLVMConstInBoundsGEP2(llvm_addr_type(m, all_tests_array), all_tests_array.value, indices, gb_count_of(indices));
LLVMValueRef src = llvm_const_named_struct(m, t_Internal_Test, vals, gb_count_of(vals));
LLVMBuildStore(p->builder, src, dst);
+28 -5
View File
@@ -42,6 +42,18 @@
#define ODIN_LLVM_MINIMUM_VERSION_12 0
#endif
#if LLVM_VERSION_MAJOR > 13 || (LLVM_VERSION_MAJOR == 13 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0)
#define ODIN_LLVM_MINIMUM_VERSION_13 1
#else
#define ODIN_LLVM_MINIMUM_VERSION_13 0
#endif
#if LLVM_VERSION_MAJOR > 14 || (LLVM_VERSION_MAJOR == 14 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0)
#define ODIN_LLVM_MINIMUM_VERSION_14 1
#else
#define ODIN_LLVM_MINIMUM_VERSION_14 0
#endif
struct lbProcedure;
struct lbValue {
@@ -115,6 +127,7 @@ struct lbModule {
AstPackage *pkg; // 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;
@@ -299,7 +312,11 @@ struct lbProcedure {
#if !ODIN_LLVM_MINIMUM_VERSION_14
#define LLVMConstGEP2(Ty__, ConstantVal__, ConstantIndices__, NumIndices__) LLVMConstGEP(ConstantVal__, ConstantIndices__, NumIndices__)
#define LLVMConstInBoundsGEP2(Ty__, ConstantVal__, ConstantIndices__, NumIndices__) LLVMConstInBoundsGEP(ConstantVal__, ConstantIndices__, NumIndices__)
#define LLVMBuildPtrDiff2(Builder__, Ty__, LHS__, RHS__, Name__) LLVMBuildPtrDiff(Builder__, LHS__, RHS__, Name__)
#endif
bool lb_init_generator(lbGenerator *gen, Checker *c);
@@ -314,7 +331,8 @@ lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_b
void lb_end_procedure(lbProcedure *p);
LLVMTypeRef lb_type(lbModule *m, Type *type);
LLVMTypeRef lb_type(lbModule *m, Type *type);
LLVMTypeRef llvm_get_element_type(LLVMTypeRef type);
lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false);
@@ -327,7 +345,7 @@ lbValue lb_const_int(lbModule *m, Type *type, u64 value);
lbAddr lb_addr(lbValue addr);
Type *lb_addr_type(lbAddr const &addr);
LLVMTypeRef lb_addr_lb_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);
@@ -339,8 +357,9 @@ 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);
lbValue lb_build_gep(lbProcedure *p, lbValue const &value, i32 index) ;
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);
@@ -480,6 +499,7 @@ LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align);
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);
@@ -488,6 +508,9 @@ i64 lb_max_zero_init_size(void) {
return cast(i64)(4*build_context.word_size);
}
LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);
LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
#define LB_TYPE_INFO_DATA_NAME "__$type_info_data"
+8 -6
View File
@@ -10,11 +10,12 @@ bool lb_is_const(lbValue value) {
return false;
}
bool lb_is_const_or_global(lbValue value) {
if (lb_is_const(value)) {
return true;
}
// TODO remove use of LLVMGetElementType
#if 0
if (LLVMGetValueKind(value.value) == LLVMGlobalVariableValueKind) {
LLVMTypeRef t = LLVMGetElementType(LLVMTypeOf(value.value));
if (!lb_is_type_kind(t, LLVMPointerTypeKind)) {
@@ -23,6 +24,7 @@ bool lb_is_const_or_global(lbValue value) {
LLVMTypeRef elem = LLVMGetElementType(t);
return lb_is_type_kind(elem, LLVMFunctionTypeKind);
}
#endif
return false;
}
@@ -389,8 +391,8 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
if (is_type_slice(type)) {
if (value.kind == ExactValue_String) {
GB_ASSERT(is_type_u8_slice(type));
res.value = lb_find_or_add_entity_string_byte_slice(m, value.value_string).value;
GB_ASSERT(is_type_slice(type));
res.value = lb_find_or_add_entity_string_byte_slice_with_type(m, value.value_string, original_type).value;
return res;
} else {
ast_node(cl, CompoundLit, value.value_compound);
@@ -418,7 +420,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
{
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef ptr = LLVMBuildInBoundsGEP(p->builder, array_data, indices, 2, "");
LLVMValueRef ptr = LLVMBuildInBoundsGEP2(p->builder, llvm_type, array_data, indices, 2, "");
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
lbAddr slice = lb_add_local_generated(p, type, false);
lb_fill_slice(p, slice, {ptr, alloc_type_pointer(elem)}, {len, t_int});
@@ -445,7 +447,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
{
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef ptr = LLVMConstInBoundsGEP(array_data, indices, 2);
LLVMValueRef ptr = LLVMConstInBoundsGEP2(lb_type(m, t), array_data, indices, 2);
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
LLVMValueRef values[2] = {ptr, len};
@@ -1007,7 +1009,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
for (isize i = 0; i < value_count; i++) {
LLVMValueRef val = old_values[i];
if (!LLVMIsConstant(val)) {
LLVMValueRef dst = LLVMBuildStructGEP(p->builder, v.addr.value, cast(unsigned)i, "");
LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, "");
LLVMBuildStore(p->builder, val, dst);
}
}
+1050 -1269
View File
File diff suppressed because it is too large Load Diff
+292 -128
View File
@@ -56,6 +56,7 @@ void lb_init_module(lbModule *m, Checker *c) {
gbAllocator a = heap_allocator();
map_init(&m->types, a);
map_init(&m->func_raw_types, a);
map_init(&m->struct_field_remapping, a);
map_init(&m->values, a);
map_init(&m->soa_values, a);
@@ -174,7 +175,8 @@ struct lbLoopData {
struct lbCompoundLitElemTempData {
Ast * expr;
lbValue value;
i32 elem_index;
i64 elem_index;
i64 elem_length;
lbValue gep;
};
@@ -211,6 +213,45 @@ void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
}
// This emits a GEP at 0, index
lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) {
GB_ASSERT(is_type_pointer(value.type));
Type *type = type_deref(value.type);
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(p->module, t_int), 0, false),
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned long long)index, false),
};
LLVMTypeRef llvm_type = lb_type(p->module, type);
lbValue res = {};
Type *ptr = base_array_type(type);
res.type = alloc_type_pointer(ptr);
if (LLVMIsConstant(value.value)) {
res.value = LLVMConstGEP2(llvm_type, value.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP2(p->builder, llvm_type, value.value, indices, gb_count_of(indices), "");
}
return res;
}
// This emits a GEP at 0, index
lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index) {
GB_ASSERT(is_type_pointer(value.type));
GB_ASSERT(LLVMIsConstant(value.value));
Type *type = type_deref(value.type);
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(m, t_int), 0, false),
LLVMConstInt(lb_type(m, t_int), cast(unsigned long long)index, false),
};
lbValue res = {};
Type *ptr = base_array_type(type);
res.type = alloc_type_pointer(ptr);
res.value = LLVMConstGEP2(lb_type(m, type), value.value, indices, gb_count_of(indices));
return res;
}
LLVMValueRef llvm_zero(lbModule *m) {
return LLVMConstInt(lb_type(m, t_int), 0, false);
}
@@ -341,9 +382,6 @@ Type *lb_addr_type(lbAddr const &addr) {
}
return type_deref(addr.addr.type);
}
LLVMTypeRef lb_addr_lb_type(lbAddr const &addr) {
return LLVMGetElementType(LLVMTypeOf(addr.addr.value));
}
lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
if (addr.addr.value == nullptr) {
@@ -530,6 +568,13 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu
}
}
unsigned lb_try_get_alignment(LLVMValueRef addr_ptr, unsigned default_alignment) {
if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) {
return LLVMGetAlignment(addr_ptr);
}
return default_alignment;
}
bool lb_try_update_alignment(LLVMValueRef addr_ptr, unsigned alignment) {
if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) {
if (LLVMGetAlignment(addr_ptr) < alignment) {
@@ -546,6 +591,9 @@ bool lb_try_update_alignment(lbValue ptr, unsigned alignment) {
return lb_try_update_alignment(ptr.value, alignment);
}
bool lb_can_try_to_inline_array_arith(Type *t) {
return type_size_of(t) <= build_context.max_simd_align;
}
bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) {
Type *array_type = base_type(type_deref(ptr.type));
@@ -554,7 +602,7 @@ bool lb_try_vector_cast(lbModule *m, lbValue ptr, LLVMTypeRef *vector_type_) {
Type *elem_type = base_array_type(array_type);
// TODO(bill): Determine what is the correct limit for doing vector arithmetic
if (type_size_of(array_type) <= build_context.max_align &&
if (lb_can_try_to_inline_array_arith(array_type) &&
is_type_valid_vector_elem(elem_type)) {
// Try to treat it like a vector if possible
bool possible = false;
@@ -854,8 +902,12 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
Type *a = type_deref(ptr.type);
if (LLVMIsNull(value.value)) {
LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value));
if (lb_sizeof(src_t) <= lb_max_zero_init_size()) {
LLVMTypeRef src_t = llvm_addr_type(p->module, ptr);
if (is_type_proc(a)) {
LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr);
LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0);
LLVMBuildStore(p->builder, LLVMConstNull(rawptr_type), LLVMBuildBitCast(p->builder, ptr.value, rawptr_ptr_type, ""));
} else if (lb_sizeof(src_t) <= lb_max_zero_init_size()) {
LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value);
} else {
lb_mem_zero_ptr(p, ptr.value, a, 1);
@@ -873,25 +925,46 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
enum {MAX_STORE_SIZE = 64};
if (LLVMIsALoadInst(value.value) && lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) {
LLVMValueRef dst_ptr = ptr.value;
LLVMValueRef src_ptr = LLVMGetOperand(value.value, 0);
src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
if (lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) {
if (LLVMIsALoadInst(value.value)) {
LLVMValueRef dst_ptr = ptr.value;
LLVMValueRef src_ptr_original = LLVMGetOperand(value.value, 0);
LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, src_ptr_original, LLVMTypeOf(dst_ptr), "");
LLVMBuildMemMove(p->builder,
dst_ptr, 1,
src_ptr, 1,
LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
return;
LLVMBuildMemMove(p->builder,
dst_ptr, lb_try_get_alignment(dst_ptr, 1),
src_ptr, lb_try_get_alignment(src_ptr_original, 1),
LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
return;
} else if (LLVMIsConstant(value.value)) {
lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
LLVMValueRef global_data = addr.addr.value;
// make it truly private data
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(global_data, true);
LLVMValueRef dst_ptr = ptr.value;
LLVMValueRef src_ptr = global_data;
src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
LLVMBuildMemMove(p->builder,
dst_ptr, lb_try_get_alignment(dst_ptr, 1),
src_ptr, lb_try_get_alignment(global_data, 1),
LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
return;
}
}
if (lb_is_type_proc_recursive(a)) {
// NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be
// stored as regular pointer with no procedure information
LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value));
LLVMValueRef v = LLVMBuildPointerCast(p->builder, value.value, src_t, "");
LLVMBuildStore(p->builder, v, ptr.value);
LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr);
LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0);
LLVMBuildStore(p->builder,
LLVMBuildPointerCast(p->builder, value.value, rawptr_type, ""),
LLVMBuildPointerCast(p->builder, ptr.value, rawptr_ptr_type, ""));
} else {
Type *ca = core_type(a);
if (ca->kind == Type_Basic || ca->kind == Type_Proc) {
@@ -904,8 +977,8 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
}
}
LLVMTypeRef llvm_addr_type(lbValue addr_val) {
return LLVMGetElementType(LLVMTypeOf(addr_val.value));
LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val) {
return lb_type(module, type_deref(addr_val.type));
}
lbValue lb_emit_load(lbProcedure *p, lbValue value) {
@@ -914,12 +987,18 @@ lbValue lb_emit_load(lbProcedure *p, lbValue value) {
Type *vt = base_type(value.type);
GB_ASSERT(vt->kind == Type_MultiPointer);
Type *t = vt->MultiPointer.elem;
LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, "");
LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, "");
return lbValue{v, t};
} else if (is_type_soa_pointer(value.type)) {
lbValue ptr = lb_emit_struct_ev(p, value, 0);
lbValue idx = lb_emit_struct_ev(p, value, 1);
lbAddr addr = lb_addr_soa_variable(ptr, idx, nullptr);
return lb_addr_load(p, addr);
}
GB_ASSERT(is_type_pointer(value.type));
Type *t = type_deref(value.type);
LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, "");
LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, "");
return lbValue{v, t};
}
@@ -1184,12 +1263,12 @@ lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) {
Type *tag_type = union_tag_type(ut);
LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value));
LLVMTypeRef uvt = llvm_addr_type(p->module, u);
unsigned element_count = LLVMCountStructElementTypes(uvt);
GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt));
lbValue tag_ptr = {};
tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 1, "");
tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, "");
tag_ptr.type = alloc_type_pointer(tag_type);
return tag_ptr;
}
@@ -1413,6 +1492,116 @@ String lb_get_entity_name(lbModule *m, Entity *e, String default_name) {
}
LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
Type *original_type = type;
type = base_type(original_type);
GB_ASSERT(type->kind == Type_Proc);
LLVMTypeRef *found = map_get(&m->func_raw_types, type);
if (found) {
return *found;
}
unsigned param_count = 0;
if (type->Proc.calling_convention == ProcCC_Odin) {
param_count += 1;
}
if (type->Proc.param_count != 0) {
GB_ASSERT(type->Proc.params->kind == Type_Tuple);
for_array(i, type->Proc.params->Tuple.variables) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (e->flags & EntityFlag_CVarArg) {
continue;
}
param_count += 1;
}
}
m->internal_type_level += 1;
defer (m->internal_type_level -= 1);
LLVMTypeRef ret = nullptr;
LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
if (type->Proc.result_count != 0) {
Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
ret = lb_type(m, single_ret);
if (ret != nullptr) {
if (is_type_boolean(single_ret) &&
is_calling_convention_none(type->Proc.calling_convention) &&
type_size_of(single_ret) <= 1) {
ret = LLVMInt1TypeInContext(m->ctx);
}
}
}
unsigned param_index = 0;
if (type->Proc.param_count != 0) {
GB_ASSERT(type->Proc.params->kind == Type_Tuple);
for_array(i, type->Proc.params->Tuple.variables) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (e->flags & EntityFlag_CVarArg) {
continue;
}
Type *e_type = reduce_tuple_to_single_type(e->type);
LLVMTypeRef param_type = nullptr;
if (e->flags & EntityFlag_ByPtr) {
param_type = lb_type(m, alloc_type_pointer(e_type));
} else if (is_type_boolean(e_type) &&
type_size_of(e_type) <= 1) {
param_type = LLVMInt1TypeInContext(m->ctx);
} else {
if (is_type_proc(e_type)) {
param_type = lb_type(m, t_rawptr);
} else {
param_type = lb_type(m, e_type);
}
}
params[param_index++] = param_type;
}
}
if (param_index < param_count) {
params[param_index++] = lb_type(m, t_rawptr);
}
GB_ASSERT(param_index == param_count);
lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention);
{
for_array(j, ft->args) {
auto arg = ft->args[j];
GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx,
"\n\t%s %td/%td"
"\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMPrintTypeToString(arg.type),
j, ft->args.count,
LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext());
}
GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx,
"\n\t%s"
"\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMPrintTypeToString(ft->ret.type),
LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
}
map_set(&m->function_type_map, type, ft);
LLVMTypeRef new_abi_fn_type = lb_function_type_to_llvm_raw(ft, type->Proc.c_vararg);
GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx,
"\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext());
map_set(&m->func_raw_types, type, new_abi_fn_type);
return new_abi_fn_type;
}
LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
LLVMContextRef ctx = m->ctx;
i64 size = type_size_of(type); // Check size
@@ -1916,103 +2105,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough?
return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0);
} else {
unsigned param_count = 0;
if (type->Proc.calling_convention == ProcCC_Odin) {
param_count += 1;
}
if (type->Proc.param_count != 0) {
GB_ASSERT(type->Proc.params->kind == Type_Tuple);
for_array(i, type->Proc.params->Tuple.variables) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (e->flags & EntityFlag_CVarArg) {
continue;
}
param_count += 1;
}
}
m->internal_type_level += 1;
defer (m->internal_type_level -= 1);
LLVMTypeRef ret = nullptr;
LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
if (type->Proc.result_count != 0) {
Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
ret = lb_type(m, single_ret);
if (ret != nullptr) {
if (is_type_boolean(single_ret) &&
is_calling_convention_none(type->Proc.calling_convention) &&
type_size_of(single_ret) <= 1) {
ret = LLVMInt1TypeInContext(m->ctx);
}
}
}
unsigned param_index = 0;
if (type->Proc.param_count != 0) {
GB_ASSERT(type->Proc.params->kind == Type_Tuple);
for_array(i, type->Proc.params->Tuple.variables) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (e->flags & EntityFlag_CVarArg) {
continue;
}
Type *e_type = reduce_tuple_to_single_type(e->type);
LLVMTypeRef param_type = nullptr;
if (e->flags & EntityFlag_ByPtr) {
param_type = lb_type(m, alloc_type_pointer(e_type));
} else if (is_type_boolean(e_type) &&
type_size_of(e_type) <= 1) {
param_type = LLVMInt1TypeInContext(m->ctx);
} else {
if (is_type_proc(e_type)) {
param_type = lb_type(m, t_rawptr);
} else {
param_type = lb_type(m, e_type);
}
}
params[param_index++] = param_type;
}
}
if (param_index < param_count) {
params[param_index++] = lb_type(m, t_rawptr);
}
GB_ASSERT(param_index == param_count);
lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention);
{
for_array(j, ft->args) {
auto arg = ft->args[j];
GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx,
"\n\t%s %td/%td"
"\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMPrintTypeToString(arg.type),
j, ft->args.count,
LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext());
}
GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx,
"\n\t%s"
"\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMPrintTypeToString(ft->ret.type),
LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
}
map_set(&m->function_type_map, type, ft);
LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg);
LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type);
GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx,
"\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext());
return new_abi_fn_ptr_type;
LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type);
return LLVMPointerType(proc_raw_type, 0);
}
break;
@@ -2055,6 +2149,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
m->internal_type_level += 1;
return t;
}
case Type_SoaPointer:
{
unsigned field_count = 2;
LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count);
fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
fields[1] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size);
return LLVMStructTypeInContext(ctx, fields, field_count, false);
}
}
@@ -2259,6 +2362,17 @@ void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *fals
}
gb_inline LLVMTypeRef OdinLLVMGetInternalElementType(LLVMTypeRef type) {
return LLVMGetElementType(type);
}
LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type) {
GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind));
return OdinLLVMGetInternalElementType(type);
}
LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type) {
GB_ASSERT(lb_is_type_kind(type, LLVMVectorTypeKind));
return OdinLLVMGetInternalElementType(type);
}
LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) {
@@ -2329,7 +2443,7 @@ general_end:;
if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) {
LLVMValueRef val_ptr = LLVMGetOperand(val, 0);
val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), "");
LLVMValueRef loaded_val = LLVMBuildLoad(p->builder, val_ptr, "");
LLVMValueRef loaded_val = LLVMBuildLoad2(p->builder, dst_type, val_ptr, "");
// LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align));
@@ -2345,7 +2459,7 @@ general_end:;
LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), "");
LLVMBuildStore(p->builder, val, nptr);
return LLVMBuildLoad(p->builder, ptr, "");
return LLVMBuildLoad2(p->builder, dst_type, ptr, "");
}
}
@@ -2371,14 +2485,15 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
LLVMTypeRef type = LLVMTypeOf(data);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, data);
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(global_data, 1);
LLVMSetGlobalConstant(global_data, true);
LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2);
LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
string_map_set(&m->const_strings, key, ptr);
return ptr;
}
@@ -2416,7 +2531,8 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
}
LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name);
LLVMTypeRef type = LLVMTypeOf(data);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, data);
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
@@ -2425,7 +2541,7 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
LLVMValueRef ptr = nullptr;
if (str.len != 0) {
ptr = LLVMConstInBoundsGEP(global_data, indices, 2);
ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
} else {
ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
}
@@ -2437,8 +2553,56 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
res.type = t_u8_slice;
return res;
}
lbValue lb_find_or_add_entity_string_byte_slice_with_type(lbModule *m, String const &str, Type *slice_type) {
GB_ASSERT(is_type_slice(slice_type));
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef data = LLVMConstStringInContext(m->ctx,
cast(char const *)str.text,
cast(unsigned)str.len,
false);
char *name = nullptr;
{
isize max_len = 7+8+1;
name = gb_alloc_array(permanent_allocator(), char, max_len);
u32 id = m->gen->global_array_index.fetch_add(1);
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
}
LLVMTypeRef type = LLVMTypeOf(data);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, data);
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(global_data, 1);
LLVMSetGlobalConstant(global_data, true);
i64 data_len = str.len;
LLVMValueRef ptr = nullptr;
if (data_len != 0) {
ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
} else {
ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
}
if (!is_type_u8_slice(slice_type)) {
Type *bt = base_type(slice_type);
Type *elem = bt->Slice.elem;
i64 sz = type_size_of(elem);
GB_ASSERT(sz > 0);
ptr = LLVMConstPointerCast(ptr, lb_type(m, alloc_type_pointer(elem)));
data_len /= sz;
}
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), data_len, true);
LLVMValueRef values[2] = {ptr, len};
lbValue res = {};
res.value = llvm_const_named_struct(m, slice_type, values, 2);
res.type = slice_type;
return res;
}
lbValue lb_find_ident(lbProcedure *p, lbModule *m, Entity *e, Ast *expr) {
+3 -1
View File
@@ -62,7 +62,9 @@ void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimiz
LLVMAddPromoteMemoryToRegisterPass(fpm);
LLVMAddMergedLoadStoreMotionPass(fpm);
LLVM_ADD_CONSTANT_VALUE_PASS(fpm);
LLVMAddEarlyCSEPass(fpm);
if (!build_context.ODIN_DEBUG) {
LLVMAddEarlyCSEPass(fpm);
}
}
}
+150 -170
View File
@@ -1,3 +1,13 @@
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);
LLVMTypeRef call_type = LLVMIntrinsicGetType(p->module->ctx, id, types, type_count);
return LLVMBuildCall2(p->builder, call_type, ip, args, arg_count, "");
}
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
dst = lb_emit_conv(p, dst, t_rawptr);
src = lb_emit_conv(p, src, t_rawptr);
@@ -10,23 +20,23 @@ void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue l
name = "llvm.memmove.inline";
}
}
LLVMTypeRef types[3] = {
lb_type(p->module, t_rawptr),
lb_type(p->module, t_rawptr),
lb_type(p->module, t_int)
};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[4] = {
dst.value,
src.value,
len.value,
LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile)
};
LLVMValueRef args[4] = {};
args[0] = dst.value;
args[1] = src.value;
args[2] = len.value;
args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile);
LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
}
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);
@@ -45,16 +55,14 @@ void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbVal
lb_type(p->module, t_rawptr),
lb_type(p->module, t_int)
};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[4] = {};
args[0] = dst.value;
args[1] = src.value;
args[2] = len.value;
args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile);
LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
LLVMValueRef args[4] = {
dst.value,
src.value,
len.value,
LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile) };
lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
}
@@ -121,8 +129,7 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
}
char *c_link_name = alloc_cstring(permanent_allocator(), p->name);
LLVMTypeRef func_ptr_type = lb_type(m, p->type);
LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type);
LLVMTypeRef func_type = lb_get_procedure_raw_type(m, p->type);
p->value = LLVMAddFunction(m->mod, c_link_name, func_type);
@@ -141,34 +148,30 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
lb_add_attribute_to_proc(m, p->value, "noredzone");
}
if (build_context.optimization_level == 0 && build_context.ODIN_DEBUG) {
lb_add_attribute_to_proc(m, p->value, "noinline");
lb_add_attribute_to_proc(m, p->value, "optnone");
} else {
switch (p->inlining) {
case ProcInlining_inline:
lb_add_attribute_to_proc(m, p->value, "alwaysinline");
break;
case ProcInlining_no_inline:
lb_add_attribute_to_proc(m, p->value, "noinline");
break;
}
switch (entity->Procedure.optimization_mode) {
case ProcedureOptimizationMode_None:
lb_add_attribute_to_proc(m, p->value, "optnone");
break;
case ProcedureOptimizationMode_Minimal:
lb_add_attribute_to_proc(m, p->value, "optnone");
break;
case ProcedureOptimizationMode_Size:
lb_add_attribute_to_proc(m, p->value, "optsize");
break;
case ProcedureOptimizationMode_Speed:
// TODO(bill): handle this correctly
lb_add_attribute_to_proc(m, p->value, "optsize");
break;
}
switch (p->inlining) {
case ProcInlining_inline:
lb_add_attribute_to_proc(m, p->value, "alwaysinline");
break;
case ProcInlining_no_inline:
lb_add_attribute_to_proc(m, p->value, "noinline");
break;
}
switch (entity->Procedure.optimization_mode) {
case ProcedureOptimizationMode_None:
lb_add_attribute_to_proc(m, p->value, "optnone");
break;
case ProcedureOptimizationMode_Minimal:
lb_add_attribute_to_proc(m, p->value, "optnone");
break;
case ProcedureOptimizationMode_Size:
lb_add_attribute_to_proc(m, p->value, "optsize");
break;
case ProcedureOptimizationMode_Speed:
// TODO(bill): handle this correctly
lb_add_attribute_to_proc(m, p->value, "optsize");
break;
}
if (!entity->Procedure.target_feature_disabled &&
@@ -346,8 +349,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
char *c_link_name = alloc_cstring(permanent_allocator(), p->name);
LLVMTypeRef func_ptr_type = lb_type(m, p->type);
LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type);
LLVMTypeRef func_type = lb_get_procedure_raw_type(m, p->type);
p->value = LLVMAddFunction(m->mod, c_link_name, func_type);
@@ -745,12 +747,12 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
GB_ASSERT(curr_block != p->decl_block->block);
{
LLVMTypeRef ftp = lb_type(p->module, value.type);
LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type);
LLVMTypeRef ftp = LLVMPointerType(fnp, 0);
LLVMValueRef fn = value.value;
if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) {
fn = LLVMBuildPointerCast(p->builder, fn, ftp, "");
}
LLVMTypeRef fnp = LLVMGetElementType(LLVMTypeOf(fn));
GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp));
{
@@ -1264,13 +1266,8 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
}
args[args_count++] = arg0.value;
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
res.value = LLVMBuildCall(p->builder, ip, args, cast(unsigned)args_count, "");
res.value = lb_call_intrinsic(p, name, args, cast(unsigned)args_count, types, gb_count_of(types));
return res;
}
case BuiltinProc_simd_reduce_min:
@@ -1303,15 +1300,11 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
case BuiltinProc_simd_reduce_or: name = "llvm.vector.reduce.or"; break;
case BuiltinProc_simd_reduce_xor: name = "llvm.vector.reduce.xor"; break;
}
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {};
args[0] = arg0.value;
LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) };
LLVMValueRef args[1] = { arg0.value };
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -1360,15 +1353,10 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
case BuiltinProc_simd_nearest: name = "llvm.nearbyint"; break;
}
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) };
LLVMValueRef args[1] = { arg0.value };
LLVMValueRef args[1] = {};
args[0] = arg0.value;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -1432,15 +1420,10 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
}
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {};
args[0] = arg0.value;
args[1] = arg1.value;
LLVMValueRef args[2] = { arg0.value, arg1.value };
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -1851,6 +1834,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
return lb_emit_matrix_flatten(p, m, tv.type);
}
case BuiltinProc_unreachable:
lb_emit_unreachable(p);
return {};
// "Intrinsics"
case BuiltinProc_alloca:
@@ -1898,11 +1886,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_trap: name = "llvm.trap"; break;
}
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
LLVMBuildCall(p->builder, ip, nullptr, 0, "");
lb_call_intrinsic(p, name, nullptr, 0, nullptr, 0);
if (id == BuiltinProc_trap) {
LLVMBuildUnreachable(p->builder);
}
@@ -1922,11 +1906,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
res.value = LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, "");
} else {
char const *name = "llvm.readcyclecounter";
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, "");
res.value = lb_call_intrinsic(p, name, nullptr, 0, nullptr, 0);
}
return res;
}
@@ -1981,16 +1961,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
}
}
LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {};
args[0] = x.value;
args[1] = y.value;
LLVMValueRef args[2] = { x.value, y.value };
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
if (is_type_tuple(main_type)) {
Type *res_type = nullptr;
@@ -2017,15 +1992,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.sqrt";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {};
args[0] = x.value;
LLVMValueRef args[1] = { x.value };
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -2040,17 +2011,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.fma";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[3] = {};
args[0] = x.value;
args[1] = y.value;
args[2] = z.value;
LLVMValueRef args[3] = { x.value, y.value, z.value };
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -2102,15 +2067,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue ptr = lb_build_expr(p, ce->args[0]);
lbValue len = lb_build_expr(p, ce->args[1]);
len = lb_emit_conv(p, len, t_int);
LLVMValueRef indices[1] = {
len.value,
};
lbValue res = {};
res.type = tv.type;
res.value = LLVMBuildGEP(p->builder, ptr.value, indices, gb_count_of(indices), "");
return res;
return lb_emit_ptr_offset(p, ptr, len);
}
case BuiltinProc_ptr_sub:
{
@@ -2118,7 +2075,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue ptr1 = lb_build_expr(p, ce->args[1]);
LLVMTypeRef type_int = lb_type(p->module, t_int);
LLVMValueRef diff = LLVMBuildPtrDiff(p->builder, ptr0.value, ptr1.value, "");
LLVMValueRef diff = LLVMBuildPtrDiff2(p->builder, lb_type(p->module, ptr0.type), ptr0.value, ptr1.value, "");
diff = LLVMBuildIntCast2(p->builder, diff, type_int, /*signed*/true, "");
lbValue res = {};
@@ -2169,7 +2126,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_atomic_load_explicit: {
lbValue dst = lb_build_expr(p, ce->args[0]);
LLVMValueRef instr = LLVMBuildLoad(p->builder, dst.value, "");
LLVMValueRef instr = LLVMBuildLoad2(p->builder, lb_type(p->module, type_deref(dst.type)), dst.value, "");
switch (id) {
case BuiltinProc_non_temporal_load:
{
@@ -2343,18 +2300,14 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
GB_ASSERT(name != nullptr);
LLVMTypeRef types[1] = {lb_type(p->module, platform_type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
lbValue res = {};
LLVMValueRef args[3] = {};
args[0] = x.value;
args[1] = y.value;
args[2] = scale.value;
LLVMValueRef args[3] = {
x.value,
y.value,
scale.value };
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = platform_type;
return lb_emit_conv(p, res, tv.type);
}
@@ -2368,17 +2321,10 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.expect";
LLVMTypeRef types[1] = {lb_type(p->module, t)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
lbValue res = {};
LLVMValueRef args[2] = { x.value, y.value };
LLVMValueRef args[2] = {};
args[0] = x.value;
args[1] = y.value;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = t;
return lb_emit_conv(p, res, t);
}
@@ -2414,9 +2360,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.prefetch";
LLVMTypeRef types[1] = {lb_type(p->module, t_rawptr)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMTypeRef llvm_i32 = lb_type(p->module, t_i32);
LLVMValueRef args[4] = {};
@@ -2426,7 +2369,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
args[3] = LLVMConstInt(llvm_i32, cache, false);
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = nullptr;
return res;
}
@@ -2672,7 +2615,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1;
}
LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(array), name);
LLVMTypeRef type = LLVMTypeOf(array);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, array);
LLVMSetLinkage(global_data, LLVMInternalLinkage);
@@ -2684,7 +2628,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
};
lbValue res = {};
res.type = tv.type;
res.value = LLVMBuildInBoundsGEP(p->builder, global_data, indices, gb_count_of(indices), "");
res.value = LLVMBuildInBoundsGEP2(p->builder, type, global_data, indices, gb_count_of(indices), "");
return res;
}
@@ -2695,9 +2639,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = {
lb_type(p->module, t_uintptr),
};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {};
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value;
@@ -2705,7 +2646,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue res = {};
res.type = tv.type;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
case BuiltinProc_wasm_memory_size:
@@ -2714,16 +2655,13 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = {
lb_type(p->module, t_uintptr),
};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {};
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value;
lbValue res = {};
res.type = tv.type;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -2733,9 +2671,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = {
lb_type(p->module, t_u32),
};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); // types, gb_count_of(types));
Type *t_u32_ptr = alloc_type_pointer(t_u32);
@@ -2746,7 +2681,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue res = {};
res.type = tv.type;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -2756,19 +2691,16 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = {
lb_type(p->module, t_u32),
};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); // types, gb_count_of(types));
Type *t_u32_ptr = alloc_type_pointer(t_u32);
LLVMValueRef args[2] = {};
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value;
args[1] = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value;
LLVMValueRef args[2] = {
lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value,
lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value };
lbValue res = {};
res.type = tv.type;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res;
}
@@ -2777,7 +2709,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
{
Type *param_types[2] = {t_u32, t_u32};
Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), tv.type, false, ProcCC_None);
LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type));
LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
LLVMValueRef the_asm = llvm_get_inline_asm(
func_type,
str_lit("cpuid"),
@@ -2797,7 +2729,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_x86_xgetbv:
{
Type *type = alloc_type_proc_from_types(&t_u32, 1, tv.type, false, ProcCC_None);
LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type));
LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
LLVMValueRef the_asm = llvm_get_inline_asm(
func_type,
str_lit("xgetbv"),
@@ -2813,6 +2745,55 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
res.value = LLVMBuildCall2(p->builder, func_type, the_asm, args, gb_count_of(args), "");
return res;
}
case BuiltinProc_valgrind_client_request:
{
lbValue args[7] = {};
for (isize i = 0; i < 7; i++) {
args[i] = lb_emit_conv(p, lb_build_expr(p, ce->args[i]), t_uintptr);
}
if (!build_context.ODIN_VALGRIND_SUPPORT) {
return args[0];
}
lbValue array = lb_generate_local_array(p, t_uintptr, 6, false);
for (isize i = 0; i < 6; i++) {
lbValue gep = lb_emit_array_epi(p, array, i);
lb_emit_store(p, gep, args[i+1]);
}
switch (build_context.metrics.arch) {
case TargetArch_amd64:
{
Type *param_types[2] = {};
param_types[0] = t_uintptr;
param_types[1] = array.type;
Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), t_uintptr, false, ProcCC_None);
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"),
true
);
LLVMValueRef asm_args[2] = {};
asm_args[0] = args[0].value;
asm_args[1] = array.value;
lbValue res = {};
res.type = t_uintptr;
res.value = LLVMBuildCall2(p->builder, func_type, the_asm, asm_args, gb_count_of(asm_args), "");
return res;
}
break;
default:
GB_PANIC("Unsupported architecture: %.*s", LIT(target_arch_names[build_context.metrics.arch]));
break;
}
}
}
GB_PANIC("Unhandled built-in procedure %.*s", LIT(builtin_procs[id].name));
@@ -2886,9 +2867,9 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
return y;
}
Ast *pexpr = unparen_expr(ce->proc);
Ast *proc_expr = unparen_expr(ce->proc);
if (proc_mode == Addressing_Builtin) {
Entity *e = entity_of_node(pexpr);
Entity *e = entity_of_node(proc_expr);
BuiltinProcId id = BuiltinProc_Invalid;
if (e != nullptr) {
id = cast(BuiltinProcId)e->Builtin.id;
@@ -2900,7 +2881,6 @@ lbValue lb_build_call_expr_internal(lbProcedure *p, Ast *expr) {
// NOTE(bill): Regular call
lbValue value = {};
Ast *proc_expr = unparen_expr(ce->proc);
Entity *proc_entity = entity_of_node(proc_expr);
if (proc_entity != nullptr) {
+27 -14
View File
@@ -458,15 +458,6 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
val1_type = type_of_expr(rs->vals[1]);
}
if (val0_type != nullptr) {
Entity *e = entity_of_node(rs->vals[0]);
lb_add_local(p, e->type, e, true);
}
if (val1_type != nullptr) {
Entity *e = entity_of_node(rs->vals[1]);
lb_add_local(p, e->type, e, true);
}
TokenKind op = Token_Lt;
switch (node->op.kind) {
case Token_Ellipsis: op = Token_LtEq; break;
@@ -478,10 +469,22 @@ void lb_build_range_interval(lbProcedure *p, AstBinaryExpr *node,
lbValue lower = lb_build_expr(p, node->left);
lbValue upper = {}; // initialized each time in the loop
lbAddr value = lb_add_local_generated(p, val0_type ? val0_type : lower.type, false);
lbAddr value;
if (val0_type != nullptr) {
Entity *e = entity_of_node(rs->vals[0]);
value = lb_add_local(p, val0_type, e, false);
} else {
value = lb_add_local_generated(p, lower.type, false);
}
lb_addr_store(p, value, lower);
lbAddr index = lb_add_local_generated(p, t_int, false);
lbAddr index;
if (val1_type != nullptr) {
Entity *e = entity_of_node(rs->vals[1]);
index = lb_add_local(p, val1_type, e, false);
} else {
index = lb_add_local_generated(p, t_int, false);
}
lb_addr_store(p, index, lb_const_int(m, t_int, 0));
lbBlock *loop = lb_create_block(p, "for.interval.loop");
@@ -643,7 +646,7 @@ void lb_build_range_stmt_struct_soa(lbProcedure *p, AstRangeStmt *rs, Scope *sco
lbAddr array = lb_build_addr(p, expr);
if (is_type_pointer(type_deref(lb_addr_type(array)))) {
if (is_type_pointer(lb_addr_type(array))) {
array = lb_addr(lb_addr_load(p, array));
}
lbValue count = lb_soa_struct_len(p, lb_addr_load(p, array));
@@ -1793,7 +1796,7 @@ void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs,
lbValue rhs = lb_emit_conv(p, value, lhs_type);
bool inline_array_arith = type_size_of(array_type) <= build_context.max_align;
bool inline_array_arith = lb_can_try_to_inline_array_arith(array_type);
if (lhs.kind == lbAddr_Swizzle) {
@@ -1956,8 +1959,18 @@ void lb_build_assign_stmt(lbProcedure *p, AstAssignStmt *as) {
} else {
lbAddr lhs = lb_build_addr(p, as->lhs[0]);
lbValue value = lb_build_expr(p, as->rhs[0]);
Type *lhs_type = lb_addr_type(lhs);
// NOTE(bill): Allow for the weird edge case of:
// array *= matrix
if (op == Token_Mul && is_type_matrix(value.type) && is_type_array(lhs_type)) {
lbValue old_value = lb_addr_load(p, lhs);
Type *type = old_value.type;
lbValue new_value = lb_emit_vector_mul_matrix(p, old_value, value, type);
lb_addr_store(p, lhs, new_value);
return;
}
if (is_type_array(lhs_type)) {
lb_build_assign_stmt_array(p, op, lhs, value);
return;
+44 -51
View File
@@ -57,6 +57,7 @@ lbValue lb_typeid(lbModule *m, Type *type) {
case Type_SimdVector: kind = Typeid_Simd_Vector; break;
case Type_RelativePointer: kind = Typeid_Relative_Pointer; break;
case Type_RelativeSlice: kind = Typeid_Relative_Slice; break;
case Type_SoaPointer: kind = Typeid_SoaPointer; break;
}
if (is_type_cstring(type)) {
@@ -97,34 +98,12 @@ lbValue lb_type_info(lbModule *m, Type *type) {
isize index = lb_type_info_index(m->info, type);
GB_ASSERT(index >= 0);
LLVMTypeRef it = lb_type(m, t_int);
LLVMValueRef indices[2] = {
LLVMConstInt(it, 0, false),
LLVMConstInt(it, index, true),
};
lbValue value = {};
value.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices));
value.type = t_type_info_ptr;
return value;
lbValue data = lb_global_type_info_data_ptr(m);
return lb_emit_array_epi(m, data, index);
}
lbValue lb_get_type_info_ptr(lbModule *m, Type *type) {
GB_ASSERT(!build_context.disallow_rtti);
i32 index = cast(i32)lb_type_info_index(m->info, type);
GB_ASSERT(index >= 0);
// gb_printf_err("%d %s\n", index, type_to_string(type));
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(m, t_int), 0, false),
LLVMConstInt(lb_type(m, t_int), index, false),
};
lbValue res = {};
res.type = t_type_info_ptr;
res.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, cast(unsigned)gb_count_of(indices));
return res;
LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) {
return lb_type_internal_for_procedures_raw(m, type);
}
@@ -178,10 +157,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef values[2] = {
LLVMConstInBoundsGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)),
LLVMConstInBoundsGEP2(lb_type(m, lb_global_type_info_data_entity->type), lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)),
LLVMConstInt(lb_type(m, t_int), type->Array.count, true),
};
LLVMValueRef slice = llvm_const_named_struct_internal(llvm_addr_type(global_type_table), values, gb_count_of(values));
LLVMValueRef slice = llvm_const_named_struct_internal(lb_type(m, type_deref(global_type_table.type)), values, gb_count_of(values));
LLVMSetInitializer(global_type_table.value, slice);
}
@@ -260,7 +239,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef vals[4] = {
lb_const_string(p->module, t->Named.type_name->token.string).value,
lb_get_type_info_ptr(m, t->Named.base).value,
lb_type_info(m, t->Named.base).value,
pkg_name,
loc.value
};
@@ -419,7 +398,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
case Type_Pointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr);
lbValue gep = lb_get_type_info_ptr(m, t->Pointer.elem);
lbValue gep = lb_type_info(m, t->Pointer.elem);
LLVMValueRef vals[1] = {
gep.value,
@@ -433,7 +412,21 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
}
case Type_MultiPointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_multi_pointer_ptr);
lbValue gep = lb_get_type_info_ptr(m, t->MultiPointer.elem);
lbValue gep = lb_type_info(m, t->MultiPointer.elem);
LLVMValueRef vals[1] = {
gep.value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_SoaPointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_soa_pointer_ptr);
lbValue gep = lb_type_info(m, t->SoaPointer.elem);
LLVMValueRef vals[1] = {
gep.value,
@@ -450,7 +443,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
i64 ez = type_size_of(t->Array.elem);
LLVMValueRef vals[3] = {
lb_get_type_info_ptr(m, t->Array.elem).value,
lb_type_info(m, t->Array.elem).value,
lb_const_int(m, t_int, ez).value,
lb_const_int(m, t_int, t->Array.count).value,
};
@@ -465,8 +458,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr);
LLVMValueRef vals[7] = {
lb_get_type_info_ptr(m, t->EnumeratedArray.elem).value,
lb_get_type_info_ptr(m, t->EnumeratedArray.index).value,
lb_type_info(m, t->EnumeratedArray.elem).value,
lb_type_info(m, t->EnumeratedArray.index).value,
lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value,
lb_const_int(m, t_int, t->EnumeratedArray.count).value,
@@ -497,7 +490,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr);
LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->DynamicArray.elem).value,
lb_type_info(m, t->DynamicArray.elem).value,
lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value,
};
@@ -511,7 +504,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr);
LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->Slice.elem).value,
lb_type_info(m, t->Slice.elem).value,
lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value,
};
@@ -527,10 +520,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr));
LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr));
if (t->Proc.params != nullptr) {
params = lb_get_type_info_ptr(m, t->Proc.params).value;
params = lb_type_info(m, t->Proc.params).value;
}
if (t->Proc.results != nullptr) {
results = lb_get_type_info_ptr(m, t->Proc.results).value;
results = lb_type_info(m, t->Proc.results).value;
}
LLVMValueRef vals[4] = {
@@ -649,7 +642,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
// NOTE(bill): Zeroth is nil so ignore it
for (isize variant_index = 0; variant_index < variant_count; variant_index++) {
Type *vt = t->Union.variants[variant_index];
lbValue tip = lb_get_type_info_ptr(m, vt);
lbValue tip = lb_type_info(m, vt);
lbValue index = lb_const_int(m, t_int, variant_index);
lbValue type_info = lb_emit_ptr_offset(p, memory_types, index);
@@ -737,7 +730,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
for (isize source_index = 0; source_index < count; source_index++) {
// TODO(bill): Order fields in source order not layout order
Entity *f = t->Struct.fields[source_index];
lbValue tip = lb_get_type_info_ptr(m, f->type);
lbValue tip = lb_type_info(m, f->type);
i64 foffset = 0;
if (!t->Struct.is_raw_union) {
GB_ASSERT(t->Struct.offsets != nullptr);
@@ -794,11 +787,11 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr);
init_map_internal_types(t);
lbValue gst = lb_get_type_info_ptr(m, t->Map.generated_struct_type);
lbValue gst = lb_type_info(m, t->Map.generated_struct_type);
LLVMValueRef vals[5] = {
lb_get_type_info_ptr(m, t->Map.key).value,
lb_get_type_info_ptr(m, t->Map.value).value,
lb_type_info(m, t->Map.key).value,
lb_type_info(m, t->Map.value).value,
gst.value,
lb_get_equal_proc_for_type(m, t->Map.key).value,
lb_get_hasher_proc_for_type(m, t->Map.key).value
@@ -819,13 +812,13 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef vals[4] = {
lb_get_type_info_ptr(m, t->BitSet.elem).value,
lb_type_info(m, t->BitSet.elem).value,
LLVMConstNull(lb_type(m, t_type_info_ptr)),
lb_const_int(m, t_i64, t->BitSet.lower).value,
lb_const_int(m, t_i64, t->BitSet.upper).value,
};
if (t->BitSet.underlying != nullptr) {
vals[1] =lb_get_type_info_ptr(m, t->BitSet.underlying).value;
vals[1] =lb_type_info(m, t->BitSet.underlying).value;
}
lbValue res = {};
@@ -841,7 +834,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef vals[3] = {};
vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value;
vals[0] = lb_type_info(m, t->SimdVector.elem).value;
vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value;
vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value;
@@ -856,8 +849,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr);
LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->RelativePointer.pointer_type).value,
lb_get_type_info_ptr(m, t->RelativePointer.base_integer).value,
lb_type_info(m, t->RelativePointer.pointer_type).value,
lb_type_info(m, t->RelativePointer.base_integer).value,
};
lbValue res = {};
@@ -870,8 +863,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
{
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr);
LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->RelativeSlice.slice_type).value,
lb_get_type_info_ptr(m, t->RelativeSlice.base_integer).value,
lb_type_info(m, t->RelativeSlice.slice_type).value,
lb_type_info(m, t->RelativeSlice.base_integer).value,
};
lbValue res = {};
@@ -886,7 +879,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
i64 ez = type_size_of(t->Matrix.elem);
LLVMValueRef vals[5] = {
lb_get_type_info_ptr(m, t->Matrix.elem).value,
lb_type_info(m, t->Matrix.elem).value,
lb_const_int(m, t_int, ez).value,
lb_const_int(m, t_int, matrix_type_stride_in_elems(t)).value,
lb_const_int(m, t_int, t->Matrix.row_count).value,
+150 -176
View File
@@ -39,6 +39,13 @@ bool lb_is_type_aggregate(Type *t) {
return false;
}
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);
LLVMBuildUnreachable(p->builder);
}
}
lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
Type *src = core_type(value.type);
@@ -73,9 +80,6 @@ LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValu
lb_type(p->module, t_int)
};
if (true || is_inlinable) {
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[4] = {};
args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
@@ -83,16 +87,18 @@ LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValu
args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), is_volatile, false);
return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
return lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
} else {
LLVMValueRef ip = lb_lookup_runtime_procedure(p->module, str_lit("memset")).value;
lbValue pr = lb_lookup_runtime_procedure(p->module, str_lit("memset"));
LLVMValueRef args[3] = {};
args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
args[1] = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), 0, false);
args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
return LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
// We always get the function pointer type rather than the function and there is apparently no way around that?
LLVMTypeRef type = lb_type_internal_for_procedures_raw(p->module, pr.type);
return LLVMBuildCall2(p->builder, type, pr.value, args, gb_count_of(args), "");
}
}
@@ -346,44 +352,65 @@ 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) {
if (arg->state_flags & StateFlag_DirectiveWasFalse) {
return lb_build_expr(p, else_expr);
}
lbValue lhs = {};
lbValue rhs = {};
lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs);
LLVMValueRef incoming_values[2] = {};
LLVMBasicBlockRef incoming_blocks[2] = {};
GB_ASSERT(else_expr != nullptr);
lbBlock *then = lb_create_block(p, "or_else.then");
lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later
lbBlock *else_ = lb_create_block(p, "or_else.else");
lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
lb_start_block(p, then);
Type *type = default_type(tv.type);
incoming_values[0] = lb_emit_conv(p, lhs, type).value;
if (is_diverging_expr(else_expr)) {
lbBlock *then = lb_create_block(p, "or_else.then");
lbBlock *else_ = lb_create_block(p, "or_else.else");
lb_emit_jump(p, done);
lb_start_block(p, else_);
lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
// NOTE(bill): else block needs to be straight afterwards to make sure that the actual value is used
// from the then block
lb_start_block(p, else_);
incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value;
lb_build_expr(p, else_expr);
lb_emit_unreachable(p); // add just in case
lb_emit_jump(p, done);
lb_start_block(p, done);
lb_start_block(p, then);
return lb_emit_conv(p, lhs, type);
} else {
LLVMValueRef incoming_values[2] = {};
LLVMBasicBlockRef incoming_blocks[2] = {};
lbValue res = {};
res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), "");
res.type = type;
lbBlock *then = lb_create_block(p, "or_else.then");
lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later
lbBlock *else_ = lb_create_block(p, "or_else.else");
GB_ASSERT(p->curr_block->preds.count >= 2);
incoming_blocks[0] = p->curr_block->preds[0]->block;
incoming_blocks[1] = p->curr_block->preds[1]->block;
lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
lb_start_block(p, then);
LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2);
incoming_values[0] = lb_emit_conv(p, lhs, type).value;
return res;
lb_emit_jump(p, done);
lb_start_block(p, else_);
incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value;
lb_emit_jump(p, done);
lb_start_block(p, done);
lbValue res = {};
res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), "");
res.type = type;
GB_ASSERT(p->curr_block->preds.count >= 2);
incoming_blocks[0] = p->curr_block->preds[0]->block;
incoming_blocks[1] = p->curr_block->preds[1]->block;
LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2);
return res;
}
}
void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
@@ -460,15 +487,11 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
char const *name = "llvm.bswap";
LLVMTypeRef types[1] = {lb_type(p->module, value.type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {};
args[0] = value.value;
LLVMValueRef args[1] = { value.value };
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = value.type;
if (is_type_float(original_type)) {
@@ -486,15 +509,10 @@ lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.ctpop";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {};
args[0] = x.value;
LLVMValueRef args[1] = { x.value };
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -515,16 +533,13 @@ lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.cttz";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {};
args[0] = x.value;
args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx));
LLVMValueRef args[2] = {
x.value,
LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)) };
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -534,16 +549,13 @@ lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.ctlz";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {};
args[0] = x.value;
args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx));
LLVMValueRef args[2] = {
x.value,
LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)) };
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -555,15 +567,11 @@ lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.bitreverse";
LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {};
args[0] = x.value;
LLVMValueRef args[1] = { x.value };
lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type;
return res;
}
@@ -984,6 +992,11 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
case 0: result_type = t->RelativeSlice.base_integer; break;
case 1: result_type = t->RelativeSlice.base_integer; break;
}
} else if (is_type_soa_pointer(t)) {
switch (index) {
case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break;
case 1: result_type = t_int; break;
}
} else {
GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index);
}
@@ -994,15 +1007,16 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 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 = LLVMConstGEP(s.value, indices, gb_count_of(indices));
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 = LLVMGetElementType(LLVMTypeOf(s.value));
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);
@@ -1010,7 +1024,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
unsigned count = LLVMCountStructElementTypes(st);
GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index);
res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, "");
res.value = LLVMBuildStructGEP2(p->builder, st, s.value, cast(unsigned)index, "");
res.type = alloc_type_pointer(result_type);
return res;
}
@@ -1114,6 +1128,13 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
result_type = t->Array.elem;
break;
case Type_SoaPointer:
switch (index) {
case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break;
case 1: result_type = t_int; break;
}
break;
default:
GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s.type), index);
break;
@@ -1141,7 +1162,28 @@ lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
}
type = core_type(type);
if (is_type_quaternion(type)) {
if (type->kind == Type_SoaPointer) {
lbValue addr = lb_emit_struct_ep(p, e, 0);
lbValue index = lb_emit_struct_ep(p, e, 1);
addr = lb_emit_load(p, addr);
index = lb_emit_load(p, index);
i32 first_index = sel.index[0];
Selection sub_sel = sel;
sub_sel.index.data += 1;
sub_sel.index.count -= 1;
lbValue arr = lb_emit_struct_ep(p, addr, first_index);
Type *t = base_type(type_deref(addr.type));
GB_ASSERT(is_type_soa_struct(t));
if (t->Struct.soa_kind == StructSoa_Fixed) {
e = lb_emit_array_ep(p, arr, index);
} else {
e = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index);
}
} else if (is_type_quaternion(type)) {
e = lb_emit_struct_ep(p, e, index);
} else if (is_type_raw_union(type)) {
type = get_struct_field_type(type, index);
@@ -1216,7 +1258,12 @@ lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) {
Type *ptr = base_array_type(st);
lbValue res = {};
res.value = LLVMBuildGEP(p->builder, s.value, indices, 2, "");
if (LLVMIsConstant(s.value) && LLVMIsConstant(index.value)) {
res.value = LLVMConstGEP2(lb_type(p->module, st), s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, st), s.value, indices, gb_count_of(indices), "");
}
res.type = alloc_type_pointer(ptr);
return res;
}
@@ -1226,24 +1273,16 @@ lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) {
GB_ASSERT(is_type_pointer(t));
Type *st = base_type(type_deref(t));
GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st));
GB_ASSERT(0 <= index);
Type *ptr = base_array_type(st);
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(p->module, t_int), 0, false),
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)index, false),
};
lbValue res = {};
if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
}
res.type = alloc_type_pointer(ptr);
return res;
return lb_emit_epi(p, s, index);
}
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));
GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st));
GB_ASSERT(0 <= index);
return lb_emit_epi(m, s, index);
}
lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
@@ -1251,11 +1290,12 @@ lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
LLVMValueRef indices[1] = {index.value};
lbValue res = {};
res.type = ptr.type;
LLVMTypeRef type = lb_type(p->module, type_deref(res.type, true));
if (lb_is_const(ptr) && lb_is_const(index)) {
res.value = LLVMConstGEP(ptr.value, indices, 1);
res.value = LLVMConstGEP2(type, ptr.value, indices, 1);
} else {
res.value = LLVMBuildGEP(p->builder, ptr.value, indices, 1, "");
res.value = LLVMBuildGEP2(p->builder, type, ptr.value, indices, 1, "");
}
return res;
}
@@ -1264,63 +1304,18 @@ 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));
Type *ptr = base_array_type(mt);
if (column == 0) {
GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt));
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(p->module, t_int), 0, false),
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)row, false),
};
lbValue res = {};
if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
}
Type *ptr = base_array_type(mt);
res.type = alloc_type_pointer(ptr);
return res;
return lb_emit_epi(p, s, row);
} else if (row == 0 && is_type_array_like(mt)) {
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(p->module, t_int), 0, false),
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)column, false),
};
lbValue res = {};
if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
}
Type *ptr = base_array_type(mt);
res.type = alloc_type_pointer(ptr);
return res;
return lb_emit_epi(p, s, column);
}
GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt));
isize offset = matrix_indices_to_offset(mt, row, column);
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(p->module, t_int), 0, false),
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)offset, false),
};
lbValue res = {};
if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
}
res.type = alloc_type_pointer(ptr);
return res;
return lb_emit_epi(p, s, offset);
}
lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) {
@@ -1343,11 +1338,12 @@ lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column
index,
};
LLVMTypeRef type = lb_type(p->module, mt);
lbValue res = {};
if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
res.value = LLVMConstGEP2(type, s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
res.value = LLVMBuildGEP2(p->builder, type, s.value, indices, gb_count_of(indices), "");
}
res.type = alloc_type_pointer(ptr);
return res;
@@ -1551,18 +1547,12 @@ lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t
if (is_possible) {
char const *name = "llvm.fma";
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMTypeRef types[1] = {};
types[0] = lb_type(m, t);
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, types, gb_count_of(types));
LLVMValueRef values[3] = {};
values[0] = a.value;
values[1] = b.value;
values[2] = c.value;
LLVMValueRef call = LLVMBuildCall(p->builder, ip, values, gb_count_of(values), "");
LLVMTypeRef types[1] = { lb_type(m, t) };
LLVMValueRef values[3] = {
a.value,
b.value,
c.value };
LLVMValueRef call = lb_call_intrinsic(p, name, values, gb_count_of(values), types, gb_count_of(types));
return {call, t};
} else {
lbValue x = lb_emit_arith(p, Token_Mul, a, b, t);
@@ -1661,7 +1651,7 @@ LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef val
LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
LLVMTypeRef type = LLVMTypeOf(value);
GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind);
LLVMTypeRef elem = LLVMGetElementType(type);
LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
unsigned len = LLVMGetVectorSize(type);
if (len == 0) {
return LLVMConstNull(type);
@@ -1691,15 +1681,9 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
if (id != 0 && false) {
LLVMTypeRef types[1] = {};
types[0] = type;
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef values[2] = {};
values[0] = LLVMConstNull(elem);
values[1] = value;
LLVMValueRef call = LLVMBuildCall(p->builder, ip, values+value_offset, value_count, "");
return call;
LLVMTypeRef types[1] = { type };
LLVMValueRef values[2] = { LLVMConstNull(elem), value };
return lb_call_intrinsic(p, name, values + value_offset, value_count, types, gb_count_of(types));
}
// Manual reduce
@@ -1743,7 +1727,7 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a));
LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) {
return LLVMBuildAdd(p->builder, a, b, "");
@@ -1754,7 +1738,7 @@ LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a));
LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) {
return LLVMBuildMul(p->builder, a, b, "");
@@ -1768,14 +1752,13 @@ LLVMValueRef llvm_vector_dot(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
}
LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, LLVMValueRef c) {
lbModule *m = p->module;
LLVMTypeRef t = LLVMTypeOf(a);
GB_ASSERT(t == LLVMTypeOf(b));
GB_ASSERT(t == LLVMTypeOf(c));
GB_ASSERT(LLVMGetTypeKind(t) == LLVMVectorTypeKind);
LLVMTypeRef elem = LLVMGetElementType(t);
LLVMTypeRef elem = OdinLLVMGetVectorElementType(t);
bool is_possible = false;
@@ -1791,18 +1774,9 @@ LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b,
if (is_possible) {
char const *name = "llvm.fmuladd";
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMTypeRef types[1] = {};
types[0] = t;
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, types, gb_count_of(types));
LLVMValueRef values[3] = {};
values[0] = a;
values[1] = b;
values[2] = c;
LLVMValueRef call = LLVMBuildCall(p->builder, ip, values, gb_count_of(values), "");
LLVMTypeRef types[1] = { t };
LLVMValueRef values[3] = { a, b, c};
LLVMValueRef call = lb_call_intrinsic(p, name, values, gb_count_of(values), types, gb_count_of(types));
return call;
} else {
LLVMValueRef x = llvm_vector_mul(p, a, b);
@@ -1817,7 +1791,7 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin
cast(char *)clobbers.text, cast(size_t)clobbers.len,
has_side_effects, is_align_stack,
dialect
#if LLVM_VERSION_MAJOR >= 13
#if LLVM_VERSION_MAJOR >= 13
, /*CanThrow*/false
#endif
);
+6 -2
View File
@@ -283,6 +283,9 @@ i32 linker_stage(lbGenerator *gen) {
String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]);
defer (gb_free(heap_allocator(), vs_exe_path.text));
String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]);
defer (gb_free(heap_allocator(), windows_sdk_bin_path.text));
char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
if (!build_context.use_lld) { // msvc
if (build_context.has_resource) {
@@ -292,7 +295,8 @@ i32 linker_stage(lbGenerator *gen) {
defer (gb_free(heap_allocator(), res_path.text));
result = system_exec_command_line_app("msvc-link",
"\"rc.exe\" /nologo /fo \"%.*s\" \"%.*s\"",
"\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"",
LIT(windows_sdk_bin_path),
LIT(res_path),
LIT(rc_path)
);
@@ -1558,7 +1562,7 @@ bool parse_build_flags(Array<String> args) {
bad_flags = true;
break;
}
build_context.resource_filepath = substring(path, 0, string_extension_position(path));
build_context.resource_filepath = path;
build_context.has_resource = true;
} else {
gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path));
+181 -172
View File
@@ -50,18 +50,7 @@ gb_global gbAllocator mc_allocator = heap_allocator();
struct Find_Result {
int windows_sdk_version; // Zero if no Windows SDK found.
wchar_t const *windows_sdk_root;
wchar_t const *windows_sdk_um_library_path;
wchar_t const *windows_sdk_ucrt_library_path;
wchar_t const *vs_exe_path;
wchar_t const *vs_library_path;
};
struct Find_Result_Utf8 {
int windows_sdk_version; // Zero if no Windows SDK found.
String windows_sdk_root;
String windows_sdk_bin_path;
String windows_sdk_um_library_path;
String windows_sdk_ucrt_library_path;
@@ -69,8 +58,6 @@ struct Find_Result_Utf8 {
String vs_library_path;
};
Find_Result_Utf8 find_visual_studio_and_windows_sdk_utf8();
String mc_wstring_to_string(wchar_t const *str) {
return string16_to_string(mc_allocator, make_string16_c(str));
}
@@ -87,6 +74,10 @@ 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) {
return concatenate4_strings(mc_allocator, a, b, c, d);
}
String mc_get_env(String key) {
char const * value = gb_get_env((char const *)key.text, mc_allocator);
return make_string_c(value);
@@ -219,19 +210,19 @@ struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE I
// The beginning of the actual code that does things.
struct Version_Data_Utf8 {
i32 best_version[4]; // For Windows 8 versions, only two of these numbers are used.
struct Version_Data {
i32 best_version[4];
String best_name;
};
typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data_Utf8 *data);
bool mc_visit_files(String dir_name, Version_Data_Utf8 *data, MC_Visit_Proc proc) {
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) {
// 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
// will see if the filename conforms to the expected versioning pattern.
String wildcard_name = mc_concat(dir_name, str_lit("\\*"));
String wildcard_name = mc_concat(dir_name, str_lit("*"));
defer (mc_free(wildcard_name));
MC_Find_Data find_data;
@@ -242,7 +233,7 @@ bool mc_visit_files(String dir_name, Version_Data_Utf8 *data, MC_Visit_Proc proc
bool success = true;
while (success) {
if ((find_data.file_attributes & FILE_ATTRIBUTE_DIRECTORY) && (find_data.filename[0] != '.')) {
String full_name = mc_concat(dir_name, str_lit("\\"), find_data.filename);
String full_name = mc_concat(dir_name, find_data.filename);
defer (mc_free(full_name));
proc(find_data.filename, full_name, data);
@@ -284,7 +275,7 @@ String find_windows_kit_root(HKEY key, String const version) {
return value;
}
void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) {
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;
@@ -304,11 +295,11 @@ void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) {
// we have to copy_string and free here because visit_files free's the full_name string
// after we execute this function, so Win*_Data would contain an invalid pointer.
if (data->best_name.len > 0) mc_free(data->best_name);
if (data->best_name.len) mc_free(data->best_name);
data->best_name = copy_string(mc_allocator, full_name);
if (data->best_name.len > 0) {
if (data->best_name.len) {
data->best_version[0] = i0;
data->best_version[1] = i1;
data->best_version[2] = i2;
@@ -316,34 +307,8 @@ void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) {
}
}
void win8_best(String short_name, String full_name, Version_Data_Utf8 *data) {
// Find the Windows 8 subdirectory with the highest version number.
int i0, i1;
auto success = sscanf_s((const char *const)short_name.text, "winv%d.%d", &i0, &i1);
if (success < 2) return;
if (i0 < data->best_version[0]) return;
else if (i0 == data->best_version[0]) {
if (i1 < data->best_version[1]) return;
}
// we have to copy_string and free here because visit_files free's the full_name string
// after we execute this function, so Win*_Data would contain an invalid pointer.
if (data->best_name.len > 0) mc_free(data->best_name);
data->best_name = copy_string(mc_allocator, full_name);
if (data->best_name.len > 0) {
data->best_version[0] = i0;
data->best_version[1] = i1;
}
}
void find_windows_kit_root(Find_Result_Utf8 *result) {
// Information about the Windows 10 and Windows 8 development kits
// is stored in the same place in the registry. We open a key
// to that place, first checking preferntially for a Windows 10 kit,
// then, if that's not found, a Windows 8 kit.
void find_windows_kit_paths(Find_Result *result) {
bool sdk_found = false;
HKEY main_key;
@@ -355,44 +320,42 @@ void find_windows_kit_root(Find_Result_Utf8 *result) {
// Look for a Windows 10 entry.
String windows10_root = find_windows_kit_root(main_key, str_lit("KitsRoot10"));
if (windows10_root.len > 0) {
if (windows10_root.len) {
defer (mc_free(windows10_root));
String windows10_lib = mc_concat(windows10_root, str_lit("Lib"));
String windows10_lib = mc_concat(windows10_root, str_lit("Lib\\"));
Version_Data data_lib = {0};
mc_visit_files(windows10_lib, &data_lib, win10_best);
defer (mc_free(windows10_lib));
defer (mc_free(data_lib.best_name));
Version_Data_Utf8 data = {0};
mc_visit_files(windows10_lib, &data, win10_best);
if (data.best_name.len > 0) {
result->windows_sdk_version = 10;
result->windows_sdk_root = mc_concat(data.best_name, str_lit("\\"));
return;
String windows10_bin = mc_concat(windows10_root, str_lit("bin\\"));
Version_Data data_bin = {0};
mc_visit_files(windows10_bin, &data_bin, win10_best);
defer (mc_free(windows10_bin));
defer (mc_free(data_bin.best_name));
if (data_lib.best_name.len && data_bin.best_name.len) {
if (build_context.metrics.arch == TargetArch_amd64) {
result->windows_sdk_um_library_path = mc_concat(data_lib.best_name, str_lit("\\um\\x64\\"));
result->windows_sdk_ucrt_library_path = mc_concat(data_lib.best_name, str_lit("\\ucrt\\x64\\"));
result->windows_sdk_bin_path = mc_concat(data_bin.best_name, str_lit("\\x64\\"));
sdk_found = true;
} else if (build_context.metrics.arch == TargetArch_i386) {
result->windows_sdk_um_library_path = mc_concat(data_lib.best_name, str_lit("\\um\\x86\\"));
result->windows_sdk_ucrt_library_path = mc_concat(data_lib.best_name, str_lit("\\ucrt\\x86\\"));
result->windows_sdk_bin_path = mc_concat(data_bin.best_name, str_lit("\\x86\\"));
sdk_found = true;
}
}
mc_free(data.best_name);
}
// Look for a Windows 8 entry.
String windows8_root = find_windows_kit_root(main_key, str_lit("KitsRoot81"));
if (windows8_root.len > 0) {
defer (mc_free(windows8_root));
String windows8_lib = mc_concat(windows8_root, str_lit("Lib"));
defer (mc_free(windows8_lib));
Version_Data_Utf8 data = {0};
mc_visit_files(windows8_lib, &data, win8_best);
if (data.best_name.len > 0) {
result->windows_sdk_version = 8;
result->windows_sdk_root = mc_concat(data.best_name, str_lit("\\"));
return;
}
mc_free(data.best_name);
if (sdk_found) {
result->windows_sdk_version = 10;
}
// If we get here, we failed to find anything.
}
bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result_Utf8 *result) {
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
@@ -555,54 +518,97 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result_Utf8
}
// 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.
bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
// official and portable installations (like mmozeiko's portable msvc script).
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 false;
return;
}
// We can find windows sdk using the following combination of env vars:
// (UniversalCRTSdkDir or WindowsSdkDir) and (WindowsSDKLibVersion or WindowsSDKVersion)
bool sdk_found = false;
// We can find windows sdk lib dir using the following combination of env vars:
// (WindowsSdkDir or UniversalCRTSdkDir) and (WindowsSDKVersion or WindowsSDKLibVersion)
bool sdk_lib_found = false;
// We can find windows sdk bin dir using the following combination of env vars:
// (WindowsSdkVerBinPath) or ((WindowsSdkBinPath or WindowsSdkDir or UniversalCRTSdkDir) and (WindowsSDKVersion || WindowsSDKLibVersion))
bool sdk_bin_found = false;
// These appear to be suitable env vars used by Visual Studio
String win_sdk_ver_env = mc_get_env(str_lit("WindowsSDKVersion"));
String win_sdk_lib_env = mc_get_env(str_lit("WindowsSDKLibVersion"));
String win_sdk_lib_ver_env = mc_get_env(str_lit("WindowsSDKLibVersion"));
String win_sdk_dir_env = mc_get_env(str_lit("WindowsSdkDir"));
String crt_sdk_dir_env = mc_get_env(str_lit("UniversalCRTSdkDir"));
String win_sdk_bin_path_env = mc_get_env(str_lit("WindowsSdkBinPath"));
String win_sdk_ver_bin_path_env = mc_get_env(str_lit("WindowsSdkVerBinPath"));
defer ({
mc_free(win_sdk_ver_env);
mc_free(win_sdk_lib_env);
mc_free(win_sdk_lib_ver_env);
mc_free(win_sdk_dir_env);
mc_free(crt_sdk_dir_env);
mc_free(win_sdk_bin_path_env);
mc_free(win_sdk_ver_bin_path_env);
});
if (win_sdk_ver_bin_path_env.len || ((win_sdk_bin_path_env.len || win_sdk_dir_env.len || crt_sdk_dir_env.len) && (win_sdk_ver_env.len || win_sdk_lib_ver_env.len))) {
String bin;
defer (mc_free(bin));
if (win_sdk_ver_bin_path_env.len) {
String dir = win_sdk_ver_bin_path_env;
// Add trailing '\' in case it was missing
bin = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
} else {
String dir = win_sdk_bin_path_env.len ? win_sdk_bin_path_env : win_sdk_dir_env.len ? win_sdk_dir_env : crt_sdk_dir_env;
String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_ver_env;
// Add trailing '\' in case it was missing
dir = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
ver = mc_concat(ver, ver[ver.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
defer (mc_free(dir));
defer (mc_free(ver));
// Append "bin" for win_sdk_dir_env and crt_sdk_dir_env
String dir_bin = mc_concat(dir, win_sdk_bin_path_env.len ? str_lit("") : str_lit("bin\\"));
defer (mc_free(dir_bin));
bin = mc_concat(dir_bin, ver);
}
if (build_context.metrics.arch == TargetArch_amd64) {
result->windows_sdk_bin_path = mc_concat(bin, str_lit("x64\\"));
sdk_bin_found = true;
} else if (build_context.metrics.arch == TargetArch_i386) {
result->windows_sdk_bin_path = mc_concat(bin, str_lit("x86\\"));
sdk_bin_found = true;
}
}
// NOTE(WalterPlinge): If any combination is found, let's just assume they are correct
if ((win_sdk_ver_env.len || win_sdk_lib_env.len) && (win_sdk_dir_env.len || crt_sdk_dir_env.len)) {
//? Maybe we need to handle missing '\' at end of strings, so far it doesn't seem an issue
if ((win_sdk_ver_env.len || win_sdk_lib_ver_env.len) && (win_sdk_dir_env.len || crt_sdk_dir_env.len)) {
String dir = win_sdk_dir_env.len ? win_sdk_dir_env : crt_sdk_dir_env;
String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_env;
String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_ver_env;
// These have trailing '\' as we are just composing the path
String um_dir = build_context.metrics.arch == TargetArch_amd64
? str_lit("um\\x64\\")
: str_lit("um\\x86\\");
String ucrt_dir = build_context.metrics.arch == TargetArch_amd64
? str_lit("ucrt\\x64\\")
: str_lit("ucrt\\x86\\");
// Add trailing '\' in case it was missing
dir = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
ver = mc_concat(ver, ver[ver.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
defer (mc_free(dir));
defer (mc_free(ver));
result->windows_sdk_root = mc_concat(dir, str_lit("Lib\\"), ver);
result->windows_sdk_um_library_path = mc_concat(result->windows_sdk_root, um_dir);
result->windows_sdk_ucrt_library_path = mc_concat(result->windows_sdk_root, ucrt_dir);
sdk_found = true;
if (build_context.metrics.arch == TargetArch_amd64) {
result->windows_sdk_um_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("um\\x64\\"));
result->windows_sdk_ucrt_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("ucrt\\x64\\"));
sdk_lib_found = true;
} else if (build_context.metrics.arch == TargetArch_i386) {
result->windows_sdk_um_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("um\\x86\\"));
result->windows_sdk_ucrt_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("ucrt\\x86\\"));
sdk_lib_found = true;
}
}
// If we haven't found it yet, we can loop through LIB for specific folders
//? This may not be robust enough using `um\x64` and `ucrt\x64`
if (!sdk_found) {
if (!sdk_lib_found) {
String lib = mc_get_env(str_lit("LIB"));
defer (mc_free(lib));
@@ -624,72 +630,67 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
continue;
}
hi = c;
String dir = substring(lib, lo, hi);
defer (lo = hi + 1);
// Skip when there are two ;; in a row
if (lo == hi) {
continue;
}
String dir = substring(lib, lo, hi);
// Remove the last slash so we can match with the strings above
String end = dir[dir.len - 1] == '\\'
? substring(dir, 0, dir.len - 1)
: substring(dir, 0, dir.len);
// Find one and we can make the other
if (string_ends_with(end, um_dir)) {
result->windows_sdk_um_library_path = mc_concat(end, str_lit("\\"));
break;
result->windows_sdk_um_library_path = mc_concat(end, str_lit("\\"));
} else if (string_ends_with(end, ucrt_dir)) {
result->windows_sdk_ucrt_library_path = mc_concat(end, str_lit("\\"));
}
if (result->windows_sdk_um_library_path.len && result->windows_sdk_ucrt_library_path.len) {
sdk_lib_found = true;
break;
}
}
// Get the root from the one we found, and make the other
// NOTE(WalterPlinge): we need to copy the string so that we don't risk a double free
if (result->windows_sdk_um_library_path.len > 0) {
String root = substring(result->windows_sdk_um_library_path, 0, result->windows_sdk_um_library_path.len - 1 - um_dir.len);
result->windows_sdk_root = copy_string(mc_allocator, root);
result->windows_sdk_ucrt_library_path = mc_concat(result->windows_sdk_root, ucrt_dir, str_lit("\\"));
} else if (result->windows_sdk_ucrt_library_path.len > 0) {
String root = substring(result->windows_sdk_ucrt_library_path, 0, result->windows_sdk_ucrt_library_path.len - 1 - ucrt_dir.len);
result->windows_sdk_root = copy_string(mc_allocator, root);
result->windows_sdk_um_library_path = mc_concat(result->windows_sdk_root, um_dir, str_lit("\\"));
}
if (result->windows_sdk_root.len > 0) {
sdk_found = true;
}
}
}
// NOTE(WalterPlinge): So far this function assumes it will only be called if MSVC was
// installed using mmozeiko's portable msvc script, which uses the windows 10 sdk.
// This may need to be changed later if it ends up causing problems.
if (sdk_found && result->windows_sdk_version == 0) {
if (sdk_bin_found && sdk_lib_found) {
result->windows_sdk_version = 10;
}
}
// 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) {
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
return;
}
bool vs_found = false;
if (result->vs_exe_path.len > 0 && result->vs_library_path.len > 0) {
vs_found = true;
}
// We can find visual studio using VCToolsInstallDir
if (!vs_found) {
String vctid = mc_get_env(str_lit("VCToolsInstallDir"));
defer (mc_free(vctid));
String vctid = mc_get_env(str_lit("VCToolsInstallDir"));
defer (mc_free(vctid));
if (vctid.len) {
String exe = build_context.metrics.arch == TargetArch_amd64
? str_lit("bin\\Hostx64\\x64\\")
: str_lit("bin\\Hostx86\\x86\\");
String lib = build_context.metrics.arch == TargetArch_amd64
? str_lit("lib\\x64\\")
: str_lit("lib\\x86\\");
if (vctid.len) {
String exe = build_context.metrics.arch == TargetArch_amd64
? str_lit("bin\\Hostx64\\x64\\")
: str_lit("bin\\Hostx86\\x86\\");
String lib = build_context.metrics.arch == TargetArch_amd64
? str_lit("lib\\x64\\")
: str_lit("lib\\x86\\");
result->vs_exe_path = mc_concat(vctid, exe);
result->vs_library_path = mc_concat(vctid, lib);
vs_found = true;
}
result->vs_exe_path = mc_concat(vctid, exe);
result->vs_library_path = mc_concat(vctid, lib);
vs_found = true;
}
// If we haven't found it yet, we can loop through Path for specific folders
@@ -701,21 +702,32 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
String exe = build_context.metrics.arch == TargetArch_amd64
? str_lit("bin\\Hostx64\\x64")
: str_lit("bin\\Hostx86\\x86");
// The environment variable may have an uppercase X even though the folder is lowercase
String exe2 = build_context.metrics.arch == TargetArch_amd64
? str_lit("bin\\HostX64\\x64")
: str_lit("bin\\HostX86\\x86");
String lib = build_context.metrics.arch == TargetArch_amd64
? str_lit("lib\\x64")
: str_lit("lib\\x86");
isize lo = {0};
isize hi = {0};
for (isize c = 0; c < path.len; c += 1) {
if (path[c] != ';') {
for (isize c = 0; c <= path.len; c += 1) {
if (c != path.len && path[c] != ';') {
continue;
}
hi = c;
String dir = substring(path, lo, hi);
defer (lo = hi + 1);
// Skip when there are two ;; in a row
if (lo == hi) {
continue;
}
String dir = substring(path, lo, hi);
// Remove the last slash so we can match with the strings above
String end = dir[dir.len - 1] == '\\'
? substring(dir, 0, dir.len - 1)
: substring(dir, 0, dir.len);
@@ -726,7 +738,10 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
defer (mc_free(cl));
defer (mc_free(link));
if (!string_ends_with(end, exe) || !gb_file_exists((char *)cl.text) || !gb_file_exists((char *)link.text)) {
if (!string_ends_with(end, exe) && !string_ends_with(end, exe2)) {
continue;
}
if (!gb_file_exists((char *)cl.text) || !gb_file_exists((char *)link.text)) {
continue;
}
@@ -735,42 +750,36 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
result->vs_library_path = mc_concat(root, lib, str_lit("\\"));
vs_found = true;
break;
}
}
}
return sdk_found && vs_found;
}
Find_Result_Utf8 find_visual_studio_and_windows_sdk_utf8() {
Find_Result_Utf8 r = {};
find_windows_kit_root(&r);
if (r.windows_sdk_root.len > 0) {
if (build_context.metrics.arch == TargetArch_amd64) {
r.windows_sdk_um_library_path = mc_concat(r.windows_sdk_root, str_lit("um\\x64\\"));
r.windows_sdk_ucrt_library_path = mc_concat(r.windows_sdk_root, str_lit("ucrt\\x64\\"));
} else if (build_context.metrics.arch == TargetArch_i386) {
r.windows_sdk_um_library_path = mc_concat(r.windows_sdk_root, str_lit("um\\x86\\"));
r.windows_sdk_ucrt_library_path = mc_concat(r.windows_sdk_root, str_lit("ucrt\\x86\\"));
}
}
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);
bool all_found =
r.windows_sdk_root.len > 0 &&
r.windows_sdk_um_library_path.len > 0 &&
r.windows_sdk_ucrt_library_path.len > 0 &&
r.vs_exe_path.len > 0 &&
r.vs_library_path.len > 0;
bool sdk_found =
r.windows_sdk_bin_path.len &&
r.windows_sdk_um_library_path.len &&
r.windows_sdk_ucrt_library_path.len ;
if (!all_found) {
find_msvc_install_from_env_vars(&r);
bool vs_found =
r.vs_exe_path.len &&
r.vs_library_path.len ;
if (!sdk_found) {
find_windows_kit_paths_from_env_vars(&r);
}
if (!vs_found) {
find_visual_studio_paths_from_env_vars(&r);
}
#if 0
printf("windows_sdk_root: %.*s\n", LIT(r.windows_sdk_root));
printf("windows_sdk_bin_path: %.*s\n", LIT(r.windows_sdk_bin_path));
printf("windows_sdk_um_library_path: %.*s\n", LIT(r.windows_sdk_um_library_path));
printf("windows_sdk_ucrt_library_path: %.*s\n", LIT(r.windows_sdk_ucrt_library_path));
printf("vs_exe_path: %.*s\n", LIT(r.vs_exe_path));
+4 -2
View File
@@ -356,6 +356,7 @@ Ast *clone_ast(Ast *node) {
break;
case Ast_PointerType:
n->PointerType.type = clone_ast(n->PointerType.type);
n->PointerType.tag = clone_ast(n->PointerType.tag);
break;
case Ast_MultiPointerType:
n->MultiPointerType.type = clone_ast(n->MultiPointerType.type);
@@ -2167,10 +2168,11 @@ Ast *parse_operand(AstFile *f, bool lhs) {
Ast *original_type = parse_type(f);
Ast *type = unparen_expr(original_type);
switch (type->kind) {
case Ast_ArrayType: type->ArrayType.tag = tag; break;
case Ast_ArrayType: type->ArrayType.tag = tag; break;
case Ast_DynamicArrayType: type->DynamicArrayType.tag = tag; break;
case Ast_PointerType: type->PointerType.tag = tag; break;
default:
syntax_error(type, "Expected an array type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind]));
syntax_error(type, "Expected an array or pointer type after #%.*s, got %.*s", LIT(name.string), LIT(ast_strings[type->kind]));
break;
}
return original_type;
+4 -2
View File
@@ -282,7 +282,8 @@ enum StateFlag : u8 {
StateFlag_type_assert = 1<<2,
StateFlag_no_type_assert = 1<<3,
StateFlag_SelectorCallExpr = 1<<6,
StateFlag_SelectorCallExpr = 1<<5,
StateFlag_DirectiveWasFalse = 1<<6,
StateFlag_BeenHandled = 1<<7,
};
@@ -650,7 +651,8 @@ AST_KIND(_TypeBegin, "", bool) \
}) \
AST_KIND(PointerType, "pointer type", struct { \
Token token; \
Ast *type; \
Ast *type; \
Ast *tag; \
}) \
AST_KIND(RelativeType, "relative type", struct { \
Ast *tag; \
+10
View File
@@ -324,6 +324,16 @@ String concatenate3_strings(gbAllocator a, String const &x, String const &y, Str
data[len] = 0;
return make_string(data, len);
}
String concatenate4_strings(gbAllocator a, String const &x, String const &y, String const &z, String const &w) {
isize len = x.len+y.len+z.len+w.len;
u8 *data = gb_alloc_array(a, u8, len+1);
gb_memmove(data, x.text, x.len);
gb_memmove(data+x.len, y.text, y.len);
gb_memmove(data+x.len+y.len, z.text, z.len);
gb_memmove(data+x.len+y.len+z.len, w.text, w.len);
data[len] = 0;
return make_string(data, len);
}
String string_join_and_quote(gbAllocator a, Array<String> strings) {
if (!strings.count) {
+111 -10
View File
@@ -278,7 +278,8 @@ struct TypeProc {
Type *generic_row_count; \
Type *generic_column_count; \
i64 stride_in_bytes; \
})
}) \
TYPE_KIND(SoaPointer, struct { Type *elem; })
enum TypeKind {
@@ -350,6 +351,7 @@ enum Typeid_Kind : u8 {
Typeid_Relative_Pointer,
Typeid_Relative_Slice,
Typeid_Matrix,
Typeid_SoaPointer,
};
// IMPORTANT NOTE(bill): This must match the same as the in core.odin
@@ -644,6 +646,7 @@ gb_global Type *t_type_info_simd_vector = nullptr;
gb_global Type *t_type_info_relative_pointer = nullptr;
gb_global Type *t_type_info_relative_slice = nullptr;
gb_global Type *t_type_info_matrix = nullptr;
gb_global Type *t_type_info_soa_pointer = nullptr;
gb_global Type *t_type_info_named_ptr = nullptr;
gb_global Type *t_type_info_integer_ptr = nullptr;
@@ -672,6 +675,7 @@ gb_global Type *t_type_info_simd_vector_ptr = nullptr;
gb_global Type *t_type_info_relative_pointer_ptr = nullptr;
gb_global Type *t_type_info_relative_slice_ptr = nullptr;
gb_global Type *t_type_info_matrix_ptr = nullptr;
gb_global Type *t_type_info_soa_pointer_ptr = nullptr;
gb_global Type *t_allocator = nullptr;
gb_global Type *t_allocator_ptr = nullptr;
@@ -735,6 +739,7 @@ Type * bit_set_to_int(Type *t);
bool are_types_identical(Type *x, Type *y);
bool is_type_pointer(Type *t);
bool is_type_soa_pointer(Type *t);
bool is_type_proc(Type *t);
bool is_type_slice(Type *t);
bool is_type_integer(Type *t);
@@ -917,6 +922,13 @@ Type *alloc_type_multi_pointer(Type *elem) {
return t;
}
Type *alloc_type_soa_pointer(Type *elem) {
Type *t = alloc_type(Type_SoaPointer);
t->SoaPointer.elem = elem;
return t;
}
Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) {
if (generic_count != nullptr) {
Type *t = alloc_type(Type_Array);
@@ -1103,17 +1115,28 @@ Type *alloc_type_simd_vector(i64 count, Type *elem, Type *generic_count=nullptr)
////////////////////////////////////////////////////////////////
Type *type_deref(Type *t) {
Type *type_deref(Type *t, bool allow_multi_pointer=false) {
if (t != nullptr) {
Type *bt = base_type(t);
if (bt == nullptr) {
return nullptr;
}
if (bt->kind == Type_Pointer) {
switch (bt->kind) {
case Type_Pointer:
return bt->Pointer.elem;
}
if (bt->kind == Type_RelativePointer) {
case Type_RelativePointer:
return type_deref(bt->RelativePointer.pointer_type);
case Type_SoaPointer:
{
Type *elem = base_type(bt->SoaPointer.elem);
GB_ASSERT(elem->kind == Type_Struct && elem->Struct.soa_kind != StructSoa_None);
return elem->Struct.soa_elem;
}
case Type_MultiPointer:
if (allow_multi_pointer) {
return bt->MultiPointer.elem;
}
break;
}
}
return t;
@@ -1327,6 +1350,10 @@ bool is_type_pointer(Type *t) {
}
return t->kind == Type_Pointer;
}
bool is_type_soa_pointer(Type *t) {
t = base_type(t);
return t->kind == Type_SoaPointer;
}
bool is_type_multi_pointer(Type *t) {
t = base_type(t);
return t->kind == Type_MultiPointer;
@@ -1401,7 +1428,7 @@ i64 matrix_align_of(Type *t, struct TypePath *tp) {
}
GB_ASSERT(min_alignment >= elem_align);
i64 align = gb_min(min_alignment, build_context.max_align);
i64 align = gb_min(min_alignment, build_context.max_simd_align);
return align;
}
@@ -1804,7 +1831,7 @@ bool is_type_dereferenceable(Type *t) {
if (is_type_rawptr(t)) {
return false;
}
return is_type_pointer(t);
return is_type_pointer(t) || is_type_soa_pointer(t);
}
@@ -2079,6 +2106,9 @@ bool is_type_polymorphic(Type *t, bool or_specialized=false) {
case Type_Pointer:
return is_type_polymorphic(t->Pointer.elem, or_specialized);
case Type_SoaPointer:
return is_type_polymorphic(t->SoaPointer.elem, or_specialized);
case Type_EnumeratedArray:
if (is_type_polymorphic(t->EnumeratedArray.index, or_specialized)) {
return true;
@@ -2196,6 +2226,7 @@ bool type_has_nil(Type *t) {
case Type_Slice:
case Type_Proc:
case Type_Pointer:
case Type_SoaPointer:
case Type_MultiPointer:
case Type_DynamicArray:
case Type_Map:
@@ -2262,6 +2293,8 @@ bool is_type_comparable(Type *t) {
return true;
case Type_Pointer:
return true;
case Type_SoaPointer:
return true;
case Type_MultiPointer:
return true;
case Type_Enum:
@@ -2335,6 +2368,7 @@ bool is_type_simple_compare(Type *t) {
case Type_Pointer:
case Type_MultiPointer:
case Type_SoaPointer:
case Type_Proc:
case Type_BitSet:
return true;
@@ -2369,6 +2403,57 @@ bool is_type_simple_compare(Type *t) {
return false;
}
bool is_type_load_safe(Type *type) {
GB_ASSERT(type != nullptr);
type = core_type(core_array_type(type));
switch (type->kind) {
case Type_Basic:
return (type->Basic.flags & (BasicFlag_Boolean|BasicFlag_Numeric|BasicFlag_Rune)) != 0;
case Type_BitSet:
if (type->BitSet.underlying) {
return is_type_load_safe(type->BitSet.underlying);
}
return true;
case Type_RelativePointer:
case Type_RelativeSlice:
return true;
case Type_Pointer:
case Type_MultiPointer:
case Type_Slice:
case Type_DynamicArray:
case Type_Proc:
case Type_SoaPointer:
return false;
case Type_Enum:
case Type_EnumeratedArray:
case Type_Array:
case Type_SimdVector:
case Type_Matrix:
GB_PANIC("should never be hit");
return false;
case Type_Struct:
for_array(i, type->Struct.fields) {
if (!is_type_load_safe(type->Struct.fields[i]->type)) {
return false;
}
}
return type_size_of(type) > 0;
case Type_Union:
for_array(i, type->Union.variants) {
if (!is_type_load_safe(type->Union.variants[i])) {
return false;
}
}
return type_size_of(type) > 0;
}
return false;
}
String lookup_subtype_polymorphic_field(Type *dst, Type *src) {
Type *prev_src = src;
// Type *prev_dst = dst;
@@ -2558,6 +2643,12 @@ bool are_types_identical_internal(Type *x, Type *y, bool check_tuple_names) {
}
break;
case Type_SoaPointer:
if (y->kind == Type_SoaPointer) {
return are_types_identical(x->SoaPointer.elem, y->SoaPointer.elem);
}
break;
case Type_Named:
if (y->kind == Type_Named) {
return x->Named.type_name == y->Named.type_name;
@@ -3465,7 +3556,7 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
case Type_SimdVector: {
// IMPORTANT TODO(bill): Figure out the alignment of vector types
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align*2);
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_simd_align*2);
}
case Type_Matrix:
@@ -3475,12 +3566,14 @@ i64 type_align_of_internal(Type *t, TypePath *path) {
return type_align_of_internal(t->RelativePointer.base_integer, path);
case Type_RelativeSlice:
return type_align_of_internal(t->RelativeSlice.base_integer, path);
case Type_SoaPointer:
return build_context.word_size;
}
// return gb_clamp(next_pow2(type_size_of(t)), 1, build_context.max_align);
// NOTE(bill): Things that are bigger than build_context.word_size, are actually comprised of smaller types
// TODO(bill): Is this correct for 128-bit types (integers)?
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.word_size);
return gb_clamp(next_pow2(type_size_of_internal(t, path)), 1, build_context.max_align);
}
i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_packed, bool is_raw_union) {
@@ -3580,6 +3673,9 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
case Type_MultiPointer:
return build_context.word_size;
case Type_SoaPointer:
return build_context.word_size*2;
case Type_Array: {
i64 count, align, size, alignment;
count = t->Array.count;
@@ -4017,6 +4113,11 @@ gbString write_type_to_string(gbString str, Type *type, bool shorthand=false) {
str = write_type_to_string(str, type->Pointer.elem);
break;
case Type_SoaPointer:
str = gb_string_appendc(str, "#soa ^");
str = write_type_to_string(str, type->SoaPointer.elem);
break;
case Type_MultiPointer:
str = gb_string_appendc(str, "[^]");
str = write_type_to_string(str, type->Pointer.elem);
+6 -1
View File
@@ -69,4 +69,9 @@ echo ---
echo ---
echo Running core:text/i18n tests
echo ---
%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe
%PATH_TO_ODIN% run text\i18n %COMMON% -out:test_core_i18n.exe
echo ---
echo Running core:slice tests
echo ---
%PATH_TO_ODIN% run slice %COMMON% -out:test_core_slice.exe
+182
View File
@@ -0,0 +1,182 @@
package test_core_slice
import "core:slice"
import "core:testing"
import "core:fmt"
import "core:os"
import "core:math/rand"
TEST_count := 0
TEST_fail := 0
when ODIN_TEST {
expect :: testing.expect
log :: testing.log
} else {
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
TEST_count += 1
if !condition {
TEST_fail += 1
fmt.printf("[%v] %v\n", loc, message)
return
}
}
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
fmt.printf("[%v] ", loc)
fmt.printf("log: %v\n", v)
}
}
main :: proc() {
t := testing.T{}
test_sort_with_indices(&t)
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
if TEST_fail > 0 {
os.exit(1)
}
}
@test
test_sort_with_indices :: proc(t: ^testing.T) {
seed := rand.uint64()
fmt.printf("Random seed: %v\n", seed)
// Test sizes are all prime.
test_sizes :: []int{7, 13, 347, 1031, 10111, 100003}
for test_size in test_sizes {
fmt.printf("Sorting %v random u64 values along with index.\n", test_size)
r := rand.create(seed)
vals := make([]u64, test_size)
r_idx := make([]int, test_size) // Reverse index
defer {
delete(vals)
delete(r_idx)
}
// Set up test values
for _, i in vals {
vals[i] = rand.uint64(&r)
}
// Sort
f_idx := slice.sort_with_indices(vals)
defer delete(f_idx)
// Verify sorted test values
rand.init(&r, seed)
for v, i in f_idx {
r_idx[v] = i
}
last: u64
for v, i in vals {
if i > 0 {
val_pass := v >= last
expect(t, val_pass, "Expected values to have been sorted.")
if !val_pass {
break
}
}
idx_pass := vals[r_idx[i]] == rand.uint64(&r)
expect(t, idx_pass, "Expected index to have been sorted.")
if !idx_pass {
break
}
last = v
}
}
}
@test
test_sort_by_indices :: proc(t: ^testing.T) {
seed := rand.uint64()
fmt.printf("Random seed: %v\n", seed)
// Test sizes are all prime.
test_sizes :: []int{7, 13, 347, 1031, 10111, 100003}
for test_size in test_sizes {
fmt.printf("Sorting %v random u64 values along with index.\n", test_size)
r := rand.create(seed)
vals := make([]u64, test_size)
r_idx := make([]int, test_size) // Reverse index
defer {
delete(vals)
delete(r_idx)
}
// Set up test values
for _, i in vals {
vals[i] = rand.uint64(&r)
}
// Sort
f_idx := slice.sort_with_indices(vals)
defer delete(f_idx)
// Verify sorted test values
rand.init(&r, seed)
{
indices := make([]int, test_size)
defer delete(indices)
for _, i in indices {
indices[i] = i
}
sorted_indices := slice.sort_by_indices(indices, f_idx)
defer delete(sorted_indices)
for v, i in sorted_indices {
idx_pass := v == f_idx[i]
expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices")
if !idx_pass {
break
}
}
}
{
indices := make([]int, test_size)
defer delete(indices)
for _, i in indices {
indices[i] = i
}
slice.sort_by_indices_overwrite(indices, f_idx)
for v, i in indices {
idx_pass := v == f_idx[i]
expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices")
if !idx_pass {
break
}
}
}
{
indices := make([]int, test_size)
swap := make([]int, test_size)
defer {
delete(indices)
delete(swap)
}
for _, i in indices {
indices[i] = i
}
slice.sort_by_indices(indices, swap, f_idx)
for v, i in swap {
idx_pass := v == f_idx[i]
expect(t, idx_pass, "Expected the sorted index to be the same as the result from sort_with_indices")
if !idx_pass {
break
}
}
}
}
}
+8 -1
View File
@@ -134,4 +134,11 @@ See also LICENSE in the `GGPO` directory itself.
`botan.lib` is available under Botan's [BSD](https://botan.randombit.net/license.txt) license.
See also LICENSE in the `botan` directory itself.
Includes full bindings as well as wrappers to match the `core:crypto` API.
Includes full bindings as well as wrappers to match the `core:crypto` API.
## CommonMark
[CMark](https://github.com/commonmark/cmark) CommonMark parsing library.
See also LICENSE in the `commonmark` directory itself.
Includes full bindings and Windows `.lib` and `.dll`.
+170
View File
@@ -0,0 +1,170 @@
Copyright (c) 2014, John MacFarlane
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-----
houdini.h, houdini_href_e.c, houdini_html_e.c, houdini_html_u.c
derive from https://github.com/vmg/houdini (with some modifications)
Copyright (C) 2012 Vicent Martí
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-----
buffer.h, buffer.c, chunk.h
are derived from code (C) 2012 Github, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
-----
utf8.c and utf8.c
are derived from utf8proc
(<http://www.public-software-group.org/utf8proc>),
(C) 2009 Public Software Group e. V., Berlin, Germany.
Permission is hereby granted, free of charge, to any person obtaining a
copy of this software and associated documentation files (the "Software"),
to deal in the Software without restriction, including without limitation
the rights to use, copy, modify, merge, publish, distribute, sublicense,
and/or sell copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.
-----
The normalization code in normalize.py was derived from the
markdowntest project, Copyright 2013 Karl Dubost:
The MIT License (MIT)
Copyright (c) 2013 Karl Dubost
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-----
The CommonMark spec (test/spec.txt) is
Copyright (C) 2014-15 John MacFarlane
Released under the Creative Commons CC-BY-SA 4.0 license:
<http://creativecommons.org/licenses/by-sa/4.0/>.
-----
The test software in test/ is
Copyright (c) 2014, John MacFarlane
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+4
View File
@@ -0,0 +1,4 @@
@echo off
pushd W:\Odin-other\Odin-test
call build.bat
popd

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