Compare commits

..

1040 Commits

Author SHA1 Message Date
gingerBill 16c5c69a40 Merge pull request #4175 from laytan/riscv-compiler
Support RISC-V for the compiler itself
2024-09-02 00:20:04 +01:00
gingerBill 39b49cb6fb Merge pull request #4176 from Feoramund/fix-context-error-msg
Remove extra format item at end of `context` error message
2024-09-02 00:18:15 +01:00
Feoramund 9871ad5fc8 Remove extra format item at end of context error message 2024-09-01 17:50:50 -04:00
Laytan 28c643d23f riscv compiler support 2024-09-01 21:42:47 +02:00
Jeroen van Rijn dd1f151696 Add math.remap_clamped. 2024-09-01 17:22:58 +02:00
Jeroen van Rijn c1605b5b4f Merge pull request #4173 from karl-zylinski/clamp-remap
Make math.remap clamp the result in range [new_min, new_max]
2024-09-01 16:54:17 +02:00
Karl Zylinski 6e150d1d58 Make math.remap clamp the result in range [new_min, new_max]. 2024-09-01 16:30:48 +02:00
Laytan 722b638e2c "fix" #4169, looks like llvm 14 bug 2024-08-31 19:40:05 +02:00
Jeroen van Rijn c1cb1a3d7e Simplified #assert check 2024-08-31 19:13:37 +02:00
Jeroen van Rijn a4ac50a5b4 Check for #assert condition to be a constant bool
Fixes #4170
2024-08-31 19:06:17 +02:00
gingerBill 6ba1506aa9 Fix possible leaks in os2.user_* calls 2024-08-31 15:12:47 +01:00
gingerBill b4bdb73158 Fix new(sync.Mutex) 2024-08-31 15:06:20 +01:00
gingerBill 476030dd28 Fix #4156 2024-08-31 13:51:35 +01:00
Laytan Laats e0a2e52601 c/libc: fix time link name 2024-08-31 02:49:53 +02:00
Laytan Laats 7f3d8e115f remove comma 2024-08-31 02:45:17 +02:00
Laytan 584e8859bf Merge pull request #4168 from laytan/fix-bad-import-name-errors
fix some issues with the "bad import name" errors
2024-08-31 02:44:16 +02:00
Laytan Laats 8e855155fd fix bad import 2024-08-31 02:38:07 +02:00
Laytan Laats 7624ecf4ba fix some issues with the "bad import name" errors
There was so much wrong here:
- The `if` statement was never entered because even on invalid import
  names `path_to_entity_name` returns "_"
- Two errors were shown where one doesn't make sense, need to choose one
  based on context
- Structure of the messages were different from other error messages
- Suggestion was using the wrong import path
2024-08-31 02:30:32 +02:00
Laytan Laats bfedcd7035 encoding/csv: fix examples 2024-08-30 23:31:31 +02:00
Laytan Laats 6ef49d4f24 core/odin: support #type_assert and #no_type_assert 2024-08-30 23:21:35 +02:00
Jeroen van Rijn 8ad4427a25 Add a few more reflect.bit_field_* helpers. 2024-08-30 22:40:14 +02:00
Jeroen van Rijn db3bcd2cea Add reflect.bit_fields_zipped 2024-08-30 22:04:10 +02:00
Jeroen van Rijn 3072a02d5d Attempt to account for BuildTools installer's lack of \ 2024-08-30 18:54:51 +02:00
gingerBill 773703bc83 Merge pull request #4009 from thetarnav/file-tag-parser
Add a file tag parser to core:odin/parser
2024-08-30 11:58:18 +01:00
gingerBill a4e865f90b Fix #4166 2024-08-30 11:01:06 +01:00
gingerBill 9197a126fc Use XOR directly rather than (~x) & mask 2024-08-30 10:52:11 +01:00
gingerBill 38ea276231 Make ~some_bit_set work on only the possible bits by doing a mask with the full set 2024-08-30 10:48:21 +01:00
gingerBill b020b91df2 Merge pull request #4112 from Feoramund/fix-test-io-issues
Add `core:io` test suite
2024-08-30 09:57:02 +01:00
gingerBill 291048cb3b Merge pull request #4165 from avanspector/master
Add missing lexer checking delay for foreign blocks
2024-08-30 09:56:36 +01:00
avanspector 3135c89a0a Merge branch 'master' of https://github.com/avanspector/Odin 2024-08-30 01:32:21 +02:00
avanspector 47f423c123 Set a flag for delayed checking 2024-08-30 01:32:06 +02:00
avanspector a7a2611efc Merge branch 'odin-lang:master' into master 2024-08-29 23:44:14 +02:00
avanspector 9866c83d61 Add missing checker delaying 2024-08-29 23:43:01 +02:00
Damian Tarnawski 655610ec87 Satisfy vet 2024-08-29 23:06:50 +02:00
Damian Tarnawski a28d574272 Add and test match_build_tags 2024-08-29 23:02:49 +02:00
Damian Tarnawski f93779d425 Parse build_project_name as [][]string 2024-08-29 22:08:01 +02:00
Damian Tarnawski a10f988020 Move some types to runtime, use reflection instead of lut 2024-08-29 21:12:33 +02:00
Damian Tarnawski 39bdf4d710 Add missing require_results attr 2024-08-29 20:52:27 +02:00
Damian Tarnawski 7862460374 Remove useless code 2024-08-29 20:52:27 +02:00
Damian Tarnawski 92821300e4 Add a file tag parser to core:odin/parser 2024-08-29 20:52:27 +02:00
Laytan 94a1a7aed5 Merge pull request #4164 from laytan/virtual-growing-min-block-size-fix
mem/virtual: make sure the given size is used for subsequent blocks
2024-08-29 18:27:54 +02:00
Laytan Laats 5a22d49b72 mem/virtual: make sure the given size is used for subsequent blocks 2024-08-29 14:48:36 +02:00
Laytan 942017b958 Merge pull request #4163 from laytan/sysconf-pagesize
mem/virtual: use `sysconf` for retrieving page size and actually use these init procs
2024-08-29 14:44:54 +02:00
Laytan Laats fd2ad20cd4 mem/virtual: use sysconf for retrieving page size and actually use these init procs 2024-08-29 14:36:32 +02:00
Laytan Laats cca385209b Remove double close 2024-08-28 19:53:20 +02:00
Laytan Laats fe2d256468 Properly close the temporary files in io tests 2024-08-28 19:53:20 +02:00
Laytan Laats 0f2ad95014 Fix EOF detection is os2 window read 2024-08-28 19:53:20 +02:00
Feoramund 7fa2e56cd9 Add io tests for bufio streams 2024-08-28 19:53:20 +02:00
Feoramund 24a53c246f Make sure seek succeeds in io.Limited_Reader test setup 2024-08-28 19:53:20 +02:00
Feoramund b11fa90ed2 Test empty slice usage in io procs 2024-08-28 19:53:20 +02:00
Feoramund f453054aff Return 0, nil in all io cases where an empty slice is provided 2024-08-28 19:53:20 +02:00
Feoramund ef99373c31 Fix pread and pwrite on os2 Windows
The previous code was jumping ahead by the specified offset, instead of
getting the current offset.
2024-08-28 19:53:20 +02:00
Feoramund 1cd5cbb0e4 Test io unexpected pointer movement 2024-08-28 19:53:20 +02:00
Feoramund 56f232e5fc Report invalid whence & offset on os2 Windows 2024-08-28 19:53:20 +02:00
Feoramund de1432b315 Fix Windows infinite recursion with os2._flush 2024-08-28 19:53:20 +02:00
Feoramund e7d6e2d163 Add documentation to os2.close
Make it explicit that using a stream after closing is like a
use-after-free bug.
2024-08-28 19:53:20 +02:00
Feoramund 8b40be50b9 Update core:io tests
- Relax return value requirements on errors. Only the error is checked,
  as there are multiple conflicting return styles throughout the `os`
  API.

  Some return the error along with `0`, `-1`, or another value. This can
  be smoothed out later.

- Test `os2` files now.
- No longer test streams after closing; this is considered similar to a
  use-after-free in `os2`.
2024-08-28 19:53:20 +02:00
Feoramund 6798d15ecb Check int(abs) instead to avoid overflows 2024-08-28 19:53:20 +02:00
Feoramund 6aedb2695a Report Invalid_Whence on some os platforms
- Move `Seek`-related checks into OS-specific files for granularity.

Platforms:
- Darwin
- FreeBSD
- Haiku
- Linux
- NetBSD
- OpenBSD
2024-08-28 19:53:20 +02:00
Feoramund 0243647e15 Add missing flush functionality to os platforms
Platforms:
- FreeBSD
- Haiku
- Linux
- NetBSD
- OpenBSD
2024-08-28 19:53:20 +02:00
Feoramund 3ec4db212b Report Invalid_Whence in os2 Linux seek 2024-08-28 19:53:20 +02:00
Feoramund 7683c1f4bb Report Invalid_Whence in os2 POSIX seek 2024-08-28 19:53:20 +02:00
Feoramund ef2cd9d97f Copy missing errors in os2._get_platform_error from posix to linux 2024-08-28 19:53:20 +02:00
Feoramund 5b9e9fb822 Add test suite for core:io 2024-08-28 19:53:20 +02:00
Feoramund 741ccd7ff5 Zero n on error in _file_stream_proc 2024-08-28 19:53:20 +02:00
Feoramund eb92a2df71 Fix indentation 2024-08-28 19:53:20 +02:00
Feoramund d60f404bb4 Fix OpenBSD implementations of read_at and write_at 2024-08-28 19:53:20 +02:00
Feoramund 6c4806835c Fix indentation 2024-08-28 19:53:20 +02:00
Feoramund e1555e04ad Fix Haiku implementations of read_at and write_at 2024-08-28 19:53:20 +02:00
Feoramund 7061032db6 Fix NetBSD implementations of read_at and write_at
These procedures must not modify the underlying file pointer.
2024-08-28 19:53:20 +02:00
Feoramund 861d892ffe Make Windows pread and pwrite conform to POSIX 2024-08-28 19:53:20 +02:00
Feoramund 5c8c63ae04 Fix FreeBSD implementations of read_at and write_at
These procedures must not modify the underlying file pointer.
2024-08-28 19:53:20 +02:00
Feoramund 1ced76cdd1 Fix broken cases of Seek usage in _file_stream_proc
Handles `EINVAL`, among other fixes.
2024-08-28 19:53:20 +02:00
Feoramund e83b982afe Measure bytes.Buffer size by length instead of capacity 2024-08-28 19:53:20 +02:00
Feoramund 7c6cc81041 Add Seek behavior to bytes.Buffer 2024-08-28 19:53:20 +02:00
Feoramund 521e47ffee Don't invalidate prev_rune if Reader seek failed 2024-08-28 19:53:20 +02:00
Feoramund 8251f4d7d0 Return .EOF in bytes.buffer_read_at instead
This is consistent with the other stream `read` procs
2024-08-28 19:53:20 +02:00
Feoramund da49f7eb4e Make bytes.reader_init return an io.Stream
Makes the API like the other stream `init` procs.
2024-08-28 19:53:20 +02:00
Feoramund d66486c17e Make io.Section_Reader set base too
This should fix seeking from `.Start`, getting the `size`, and
`read_at`.

Also make the API consistent with the other `*_init` procs in
`util.odin` by returning the `io.Reader`.
2024-08-28 19:53:20 +02:00
Feoramund 981a2e1a00 Add missing io.Stream_Mode responses 2024-08-28 19:53:19 +02:00
Laytan eb6e5ee3a1 Merge pull request #4162 from laytan/os2-disable-custom-heap-allocator
os2: disable custom heap allocator
2024-08-28 19:51:22 +02:00
Laytan 5e850e24d6 os2: disable custom heap allocator
See #4161
2024-08-28 19:45:34 +02:00
Jeroen van Rijn 17d10b72d5 Merge pull request #4158 from sqrt-negativeone/master
Win32 clipboard procedures
2024-08-28 19:02:18 +02:00
Fakhri Mouad b08c14b710 fix style, ensure we compile with flags -vet -strict-style -disallow-do 2024-08-28 17:52:58 +01:00
Jeroen van Rijn d3fca60e4d Merge pull request #4160 from Kelimion/vsdd
-vet -strict-style -disallow-do
2024-08-28 18:49:44 +02:00
Jeroen van Rijn d602e2cc74 Remove duplicate vet flag. 2024-08-28 18:43:54 +02:00
Jeroen van Rijn 831e26cb6f Remove unused import. 2024-08-28 18:42:54 +02:00
Jeroen van Rijn 7b276cbc7e -vet -strict-style -disallow-do 2024-08-28 18:36:49 +02:00
Fakhri Mouad 7e4750c303 fix indentation in test file 2024-08-28 17:30:30 +01:00
Fakhri Mouad 967b6d46b2 avoid using do statement in odin codebase 2024-08-28 17:27:27 +01:00
Jeroen van Rijn fcafd83506 Merge pull request #4159 from Kelimion/disallow-do
More -disallow-do in CI.
2024-08-28 18:20:39 +02:00
Jeroen van Rijn 21dab9673d More -disallow-do in CI. 2024-08-28 18:13:53 +02:00
Fakhri Mouad 16503c3b91 Add Win32 procs needed to handle clipboard 2024-08-28 16:36:06 +01:00
Laytan Laats 1e6419b5b7 fix zombie thread leak in thread self cleanup 2024-08-28 16:22:38 +02:00
Laytan Laats ef66f96cf2 fix windows bindings where BOOL is not actually a boolean
Fixes #4157
2024-08-28 15:45:41 +02:00
Laytan Laats 9684ade23e fix -vet-tabs 2024-08-27 19:13:46 +02:00
gingerBill 8694fa5f78 Minor cleanup of CFString.odin 2024-08-27 11:22:28 +01:00
gingerBill fb248056c9 Merge pull request #4146 from Feoramund/fix-i128-transmute-align
Fix inline transmutation of `[16]i8` to `i128`
2024-08-26 22:38:24 +01:00
gingerBill ade4e312fe Merge pull request #4154 from avanspector/master
Delay lexical checking for foreign blocks that are in file scope
2024-08-26 22:38:13 +01:00
gingerBill 12bd07d2df Merge pull request #4150 from laytan/update-wgpu-to-22-1-0
wgpu: update to v22.1.0.1
2024-08-26 22:37:31 +01:00
gingerBill 91f8c626bb Merge pull request #4148 from Feoramund/tls-cleaner
Add API for freeing `thread_local` state
2024-08-26 22:37:08 +01:00
Laytan c1684d6335 Merge pull request #4136 from flysand7/process-info-fix
[os2/process]: Don't free process info fields in partial success scenarios
2024-08-26 23:25:21 +02:00
flysand7 1a4faff9c9 [os2/process]: Fix typo on doc comments 2024-08-27 08:06:11 +11:00
Laytan 6c17642b91 Merge pull request #4155 from Feoramund/fix-test-vet-style
Fix `-vet` and `-strict-style` failures in tests
2024-08-26 23:01:21 +02:00
Laytan ef254ec055 Merge pull request #4153 from Feoramund/fix-4151
Fix #4151
2024-08-26 22:59:48 +02:00
Feoramund 1f04f541cf Fix -vet and -strict-style failures in tests 2024-08-26 16:20:08 -04:00
avanspector dd86a8f013 Merge branch 'odin-lang:master' into master 2024-08-26 21:00:25 +02:00
avanspector 43ec2b9253 checker: delay foreign block checking
if file scope, otherwise as before
2024-08-26 20:59:16 +02:00
Laytan Laats 60cd0da2ed wgpu: cont. fix sdl2glue on Linux 2024-08-26 20:24:26 +02:00
avanspector c21bbae427 Merge branch 'master' of https://github.com/avanspector/Odin 2024-08-26 19:59:20 +02:00
avanspector d7e977069a Update checker.cpp 2024-08-26 19:59:15 +02:00
Jeroen van Rijn ef98aa1fe1 Merge pull request #4152 from edyu/master
Fix error for uuid to require 36 bytes instead 32 (4 bytes for dashes)
2024-08-26 19:35:04 +02:00
Ed Yu 4e2bce0c83 Fix error for uuid to require 36 bytes instead 32 (4 bytes for dashes) 2024-08-26 10:25:10 -07:00
Feoramund d43c6e39f6 Fix #4151
The `core:mem` procs were calling the wrong `runtime` procs for their
number of arguments.
2024-08-26 13:23:04 -04:00
Laytan f56b895c05 wgpu: fix sdl2glue not using GetWindowWMInfo properly
Fixes #4127
2024-08-26 16:08:14 +02:00
Laytan Laats 54a420f3eb wgpu: update to v22.1.0.1 2024-08-26 15:49:12 +02:00
Jeroen van Rijn 3e0f6bda91 Merge pull request #4149 from Feoramund/fix-thread-pool-use-after-free
Fix use-after-free in `thread.Pool`
2024-08-26 13:05:23 +02:00
Feoramund 9fac03b84c Fix use-after-free in thread.Pool 2024-08-26 06:39:05 -04:00
Laytan 0a8f85e879 Merge pull request #4147 from Feoramund/cleanup-test-runtime-arenas
Free the arenas allocated in `test_core_runtime`
2024-08-26 12:09:34 +02:00
Feoramund 49606ec3ea Use thread_local_cleaner API in os2 2024-08-26 06:01:59 -04:00
Feoramund d338642dc4 Add API for freeing thread_local state 2024-08-26 06:01:59 -04:00
Feoramund 95d1c29c2a Free the arenas allocated in test_core_runtime
Found by using `-sanitize:address`.
2024-08-26 05:45:24 -04:00
Feoramund c424c94030 Fix inline transmutation of [16]i8 to i128
Forbids LLVM from generating SSE aligned loads on unaligned data.
2024-08-26 04:48:31 -04:00
gingerBill 8de1e88c4f Merge pull request #4144 from laytan/riscv-error-on-atomics-without-extension
riscv: add an error when atomics are used without the atomics extension
2024-08-25 22:49:42 +01:00
flysand7 3119e0489f [os2/process]: Fix vet errors 2024-08-26 07:23:59 +11:00
flysand7 db94e646e0 [os2/process]: Adjust documentation for process info 2024-08-26 07:21:54 +11:00
flysand7 4737485f09 [os2/process]: Force return on allocation errors and process not existing 2024-08-26 07:19:39 +11:00
Laytan d299d4e1cd riscv: add an error when atomics are used without the atomics extension 2024-08-25 21:17:00 +02:00
Laytan 9aeb0d0fb6 Merge pull request #4142 from laytan/os2-propogate-errors-from-execv
os2: propagate errors from execv
2024-08-25 21:09:54 +02:00
Laytan 0ea6809b49 os2: remove return on file_size error from read_entire_file
file_size can't return .No_Size because it uses io.size and only returns
an io.Error, removing this so it works when file_size fails (linux pipes
for instance)
2024-08-25 18:43:23 +02:00
Laytan Laats a0fe6da10b os2: propogate errors from execv functions to parent 2024-08-25 18:01:33 +02:00
gingerBill 8c952878fb Allow empty strings in link_prefix and link_suffix 2024-08-25 14:03:14 +01:00
gingerBill eda58357b6 Merge pull request #4141 from VladPavliuk/fix-dwmapi-enum
Fix win32 dwmapi DWMWINDOWATTRIBUTE enum.
2024-08-25 12:46:51 +01:00
gingerBill 7b14c267fb Merge pull request #4138 from z64/z64/fix-cmark
Fix binding to cmark_node_get_fence_info
2024-08-25 12:43:07 +01:00
VladPavliuk cc2ed2b302 Fix win32 dwmapi enum. 2024-08-25 14:34:24 +03:00
Zac Nowicki 17cc423a17 Fix binding to cmark_node_get_fence_info
https://github.com/commonmark/cmark/blob/master/src/cmark.h#L334
2024-08-25 01:42:12 -04:00
flysand7 fa84e86766 [os2/process]: Allow for partial success scenarios 2024-08-25 14:22:27 +11:00
flysand7 0d7e6430eb [os2/process]: Don't free process info fields in partial success scenarios 2024-08-25 13:08:24 +11:00
Jeroen van Rijn 4cf1af3f7d Merge pull request #4135 from gelatinstudios/master
fix core:reflect/iterator.odin
2024-08-24 23:23:33 +02:00
Laytan eef4dffa12 Merge pull request #4134 from karl-zylinski/fix-raylib-LoadImageAnim-binding
Fix binding: Make rl.LoadImageAnim take a pointer instead of a multi-pointer.
2024-08-24 22:56:49 +02:00
Karl Zylinski 25e8a6353d Fix comment indentation. 2024-08-24 22:02:17 +02:00
unknown ae5ef0ce9c fix core:reflect/iterator.odin 2024-08-24 16:01:49 -04:00
Karl Zylinski 574a5015d6 Make rl.LoadImageAnim take a pointer instead of a multipointer. The param frames is just for returning an int, it's not for passing a multipointer into the proc. 2024-08-24 22:00:29 +02:00
Jeroen van Rijn 0a825fc44d Improve SRV handling in dns_windows.odin 2024-08-24 18:43:25 +02:00
gingerBill aa659a637a Fix #4132 2024-08-24 15:46:54 +01:00
gingerBill 0e71e93b22 Remove unused import 2024-08-24 14:51:28 +01:00
gingerBill 61b3af5b08 MemFree as a procedure group for both rawptr and cstring 2024-08-24 14:51:05 +01:00
gingerBill 19b95349a6 Use fmt.caprintf directly 2024-08-24 14:47:33 +01:00
gingerBill d0eaf7642d Add intrinsics.type_has_shared_fields 2024-08-24 14:36:18 +01:00
gingerBill eb799393d5 Fix -vet-tabs issues 2024-08-24 13:56:41 +01:00
gingerBill 8ba87e01bd Improve parse_enforce_tabs usage 2024-08-24 13:56:30 +01:00
gingerBill daccd72162 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-08-24 13:36:51 +01:00
gingerBill 8b248673c1 Fix #4105 2024-08-24 13:36:43 +01:00
Jeroen van Rijn faec52623d Merge pull request #4128 from gordonshamway23/mini_fix_in_image
Added missing slice advancing.
2024-08-24 14:23:42 +02:00
gingerBill b6d9a0c32e Manually implement tail-recursion for parse_if_stmt 2024-08-24 13:16:55 +01:00
gingerBill a4cc207022 Add a recursion depth limit for #3987 with a consideration to use a switch statement or refactor the code to not use a large if-else chain 2024-08-24 12:59:17 +01:00
gingerBill 683dde1fa0 Disallow labelled branches in defer - fix #3960 2024-08-24 12:47:29 +01:00
gingerBill ca4d91a8a3 Fix #4079 2024-08-24 12:26:41 +01:00
gingerBill 65543b993f Merge pull request #4130 from fusion32/fix-ambiguous-generic-type-names
fix ambiguous generic type names
2024-08-24 11:50:02 +01:00
gingerBill 00fb60d3d9 #4115 Add Suggestion: 'typeid_of(T)' 2024-08-24 11:48:32 +01:00
gingerBill 68a83abcd6 #4119 Add error when doing {.A | .B} instead of {.A, .B} with a suggestion to do surround it in parentheses to make it clear it is intended 2024-08-24 11:44:59 +01:00
gingerBill 4458ca4585 Fix #4126 2024-08-24 11:40:02 +01:00
fusion32 5ef8a092f6 fix wrong exact value kind comparison 2024-08-23 17:50:27 -03:00
fusion32 c969bee86d fix ambiguous generic type names 2024-08-23 17:18:10 -03:00
gordonshamway23 426367c522 Added missing slice advancing. 2024-08-23 21:28:59 +02:00
Laytan Laats d410281766 os2: do read_entire_file in parts if the file size is 0 2024-08-23 20:25:47 +02:00
Laytan Laats ce53805d94 os2: fix read_entire_file wrong slice end variable 2024-08-23 20:25:19 +02:00
Laytan Laats 963e8544f4 os2: CLOEXEC the fds from pipe for posix implementation 2024-08-23 20:25:05 +02:00
Laytan Laats c2a7c29ce8 os2: fix using uuid as process handle for darwin, once it goes zombie it changes 2024-08-23 20:24:06 +02:00
Laytan b3f22133f3 Merge pull request #4123 from laytan/more-core-orca-support
orca: implement core:time and core:log
2024-08-23 18:47:00 +02:00
Laytan Laats caef37bc18 orca: implement core:time and core:log 2024-08-23 18:25:10 +02:00
gingerBill 574dc5efe6 Merge pull request #4120 from laytan/posix-process
os2: process API for Darwin and most of it for BSDs
2024-08-22 22:51:48 +01:00
Laytan Laats a66520ba57 os2: process API for Darwin and most of it for BSDs 2024-08-22 23:07:24 +02:00
Laytan Laats b9043db434 os2: make platform error more ergonomic by making it an alias 2024-08-22 22:59:13 +02:00
Laytan Laats 58e5078b66 add riscv to simd.IS_EMULATED 2024-08-22 14:17:45 +02:00
gingerBill 70932dc478 Merge pull request #4089 from laytan/riscv64
add support for linux_riscv64 and freestanding_riscv64
2024-08-22 11:20:03 +01:00
Jeroen van Rijn a8bc6f08a9 Merge pull request #4116 from Kelimion/article
Add table-driven (in)definite article to some errors.
2024-08-21 18:51:43 +02:00
Jeroen van Rijn 07aedb0b89 , 2024-08-21 18:42:11 +02:00
Laytan 63cd9a031a fix variadic parameter with default value error check 2024-08-21 15:11:16 +02:00
gingerBill c77e8ca401 Fix tests 2024-08-21 14:06:04 +01:00
gingerBill 58e811eea5 Merge pull request #3962 from Feoramund/regex
Add `core:text/regex`
2024-08-21 13:55:11 +01:00
Laytan c0125f3192 correct the riscv64 stat structs 2024-08-21 14:41:23 +02:00
Jeroen van Rijn 1bcc074223 dash 2024-08-21 14:18:12 +02:00
gingerBill e7b8e61c68 Merge pull request #4106 from yeongjukang/master
core:sys/linux - implement clock_settime, clock_getres and clock_nanosleep
2024-08-21 09:41:14 +01:00
Yeongju Kang bbe4c32e32 changed signature of clock_getres 2024-08-21 08:25:14 +09:00
Laytan 0d39f52b4d Merge pull request #4117 from yay/vet-tabs
A couple of foundation binding. Vet tabs.
2024-08-21 01:16:30 +02:00
Vitalii Kravchenko 14169ae5b4 A couple of foundation binding. Vet tabs. 2024-08-21 00:09:09 +01:00
Jeroen van Rijn 6b4b0cea5d Add table-driven (in)definite article to some errors. 2024-08-20 22:13:31 +02:00
Laytan 85a33a1c9b add constant_log2 to intrinsics file 2024-08-20 19:14:50 +02:00
Laytan 8f2d3dc955 fix i128 division? 2024-08-20 19:01:09 +02:00
Jeroen van Rijn daa0779c01 Rewrite compound_to_time without using i128. 2024-08-20 18:50:05 +02:00
Laytan d7e81e86f5 Merge pull request #4110 from andradei/termios-linux
Add support for Linux on os/sys/posix termios.
2024-08-20 17:23:53 +02:00
Laytan 06fb500dfe make sure net.Network_Error is of size 8 2024-08-20 15:52:07 +02:00
Jeroen van Rijn 5ef58049dc Merge pull request #4114 from it-a-me/master
fix wiki link in the README.md
2024-08-20 14:27:47 +02:00
Laytan Laats 5b22bfa2b7 unify LB_ABI_INFO and LB_ABI_INFO_CTX 2024-08-20 14:07:47 +02:00
Laytan ca6ef95b03 add support for linux_riscv64 and freestanding_riscv64 2024-08-20 14:06:40 +02:00
it-a-me 53500699a9 README.md: Fix wiki link 2024-08-19 23:00:26 -07:00
Jeroen van Rijn 29838da782 Merge pull request #4111 from RoryO/simd-typo
fix simd var typo
2024-08-20 00:52:37 +02:00
Rory OConnell 97795ff3a2 fix simd var typo 2024-08-19 15:50:42 -07:00
Isaac Andrade 6df51b42a8 Fix termios NCCS size on linux. 2024-08-19 15:32:55 -06:00
Isaac Andrade 3228178d87 Add support for Linux on os/sys/posix termios. 2024-08-19 14:56:37 -06:00
Jeroen van Rijn 3fc1f6f1cd Merge pull request #4101 from Yawning/feature/index-byte-tweaks
core/bytes: Tweak `index_byte`/`last_index_byte`
2024-08-19 20:43:37 +02:00
gingerBill 2999c02f65 Fix random typo 2024-08-19 16:33:17 +01:00
gingerBill 9d7ab8d5ca Add strings.contains_space 2024-08-19 16:31:03 +01:00
gingerBill 2a0785037b Fix switch val in ptr 2024-08-19 12:19:45 +01:00
Yawning Angel 9e65e229d0 core/bytes: Tweak index_byte and last_index_byte
- Assume unaligned loads are cheap
- Explicilty use 256-bit or 128-bit SIMD to avoid AVX512
- Limit "vectorized" scanning to 128-bits if SIMD is emulated via SWAR
- Add a few more benchmark cases
2024-08-19 11:40:36 +09:00
Jeroen van Rijn 34a9e20531 Merge pull request #4108 from Feoramund/remove-deprecated-testing-log
Remove deprecated `log` procs from `core:testing`
2024-08-19 04:19:22 +02:00
Feoramund 0fa24ac3c4 Remove deprecated log procs from core:testing 2024-08-18 21:30:32 -04:00
Jeroen van Rijn 17eb0b5ee0 Merge pull request #4107 from Feoramund/add-digit-count
Add `core:math.count_digits_of_base`
2024-08-19 02:36:05 +02:00
Feoramund b49b80bdf9 Add test for count_digits_of_base 2024-08-18 20:14:14 -04:00
Feoramund 2906f2aa7e Add core:math.count_digits_of_base 2024-08-18 20:14:14 -04:00
Yeongju Kang f96991364a implement clock_settime, clock_getres and clock_nanosleep 2024-08-19 08:53:07 +09:00
Laytan 359a212a78 Merge pull request #4104 from laytan/find-llvm-config-through-brew
query brew for llvm-config location if possible
2024-08-19 00:41:06 +02:00
Laytan Laats ea7e8f075d query brew for llvm-config location if possible 2024-08-19 00:02:14 +02:00
gingerBill d99a6ad003 Add suggestion for ~uint(0) if cast(uint)-1 is done 2024-08-18 22:52:57 +01:00
gingerBill 95c3b8a8de Move assert to else branch 2024-08-18 22:45:26 +01:00
Laytan Laats ae41779366 remove redundant & 2024-08-18 21:10:21 +02:00
Laytan bb3f848b4a Merge pull request #4103 from laytan/wait-shared-on-macos-10-15
UL_COMPARE_AND_WAIT_SHARED is macOS 10.15+
2024-08-18 19:38:52 +02:00
gingerBill a51b9c6fb0 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-08-18 18:37:45 +01:00
gingerBill 8e52a52580 Cache the paddding filler type 2024-08-18 18:37:40 +01:00
Laytan Laats b7b3ada3b1 UL_COMPARE_AND_WAIT_SHARED is macOS 10.15+ 2024-08-18 19:31:52 +02:00
Laytan 9a895a318c Merge pull request #4102 from laytan/wasm-lshrti3
Implement lshrti3 on wasm
2024-08-18 17:18:05 +02:00
Laytan Laats b2e64b7ce0 implement lshrti3 on wasm 2024-08-18 17:09:57 +02:00
Yawning Angel 7020e9b66a core/simd: Add IS_EMULTATED so there is one place to look for potatos 2024-08-18 22:52:39 +09:00
gingerBill f49ebae956 Correct lbAddr_SoaVariable logic 2024-08-18 12:37:15 +01:00
gingerBill 0e82a46047 Fix #3999 2024-08-18 12:35:25 +01:00
gingerBill c4e0cbcd87 Fix #4005 2024-08-18 12:21:35 +01:00
gingerBill f82bf6cd42 Fix #4022 2024-08-18 12:13:52 +01:00
gingerBill 60b2979cfd Fix #4024 2024-08-18 12:10:46 +01:00
gingerBill 17740966e5 Fix #4040 2024-08-18 12:06:58 +01:00
gingerBill 5c06fcd346 Fix #4064 2024-08-18 12:00:27 +01:00
gingerBill 22a82e73d6 Fix #3976 2024-08-18 11:45:27 +01:00
Jeroen van Rijn bbb5593f87 Merge pull request #4098 from jolson88/raygui/vertical-text-alignment
(raygui) Restores vertical text alignment broken after 4.0 migration
2024-08-17 22:29:38 +02:00
Jason Olson d00057c803 Add missing trailing comma 2024-08-17 13:23:42 -07:00
Jason Olson acfd9dcd1b Restores vertical text alignment broken after 4.0 migration
A series of changes between raygui 3.6 and 4.0 were that various text box
properties were moved from the text box specific properties up into the
extended default control properties. This change corrects the various
property enums to match the raygui 4.0 API.

One additional aspect of this change was rolling back a previous commit
made to this vendor file that changed the signature of GuiSetStyle and
GuiGetStyle from using a c.int as property value to a more strongly-defined
GuiControlProperty enum. Unfortunately, this breaks the raygui API by
disallowing the use of various control-specific extended properties due to
how the enums are built.
2024-08-17 12:35:50 -07:00
Jeroen van Rijn 9553bc3689 If missing type is newline, print "newline", not \n
Turns:

W:/Odin/bug/bug.odin(3:27) Syntax Error: Expected a type, got '
'
        Storage :: distinct map[]

Into:

W:/Odin/bug/bug.odin(3:27) Syntax Error: Expected a type, got newline
        Storage :: distinct map[]
2024-08-17 17:25:52 +02:00
Jeroen van Rijn ebbb70f11d Error if missing map key type
Fixes #4096
2024-08-17 17:12:27 +02:00
Laytan Laats 142bda2804 posix: start on process API 2024-08-17 15:48:01 +02:00
Jeroen van Rijn 478f529744 Merge pull request #4094 from amad00r/fix-nil-logger
Fix log unnecessary allocations
2024-08-17 01:50:13 +02:00
gingerBill 536a342873 Merge pull request #4092 from laytan/fix-open-bindings
fix `open` bindings
2024-08-17 00:22:46 +01:00
Amadeu Moya 43dc7704a5 Fix log unnecessary allocations 2024-08-17 00:37:01 +02:00
Laytan Laats e8933e43ec add haiku to unsupported time file 2024-08-16 23:18:59 +02:00
Laytan Laats f7d7d65bc0 fix open bindings
`open` specifies the `mode` argument as vararg (presumably to make it
optional). varargs actually have rules about casting, in this case the
rule that any integer arg of size <= 4 has to be casted to `i32` before
passing it.

Not doing that implicit cast makes the permissions wrong or not apply at
all.
2024-08-16 22:54:53 +02:00
Jeroen van Rijn 970dc7a1f2 Merge pull request #4091 from Feoramund/fix-darwin-os-open
Check if file open-mode is `O_CREATE` on Darwin before forcing chmod
2024-08-16 20:31:22 +02:00
Feoramund a07878be71 Check if file open-mode is O_CREATE on Darwin before forcing chmod
Fixes #4087
2024-08-16 14:08:55 -04:00
Jeroen van Rijn 14e207088a Merge pull request #4088 from Kelimion/benchmark
Improve benchmarks.
2024-08-16 17:16:59 +02:00
Jeroen van Rijn 6c46c9e04b Improve benchmarks. 2024-08-16 17:00:16 +02:00
gingerBill 40b8150a23 Minor clean ups 2024-08-16 12:47:23 +01:00
gingerBill 31bb3dc4f0 Merge pull request #3971 from jasonKercher/os2-process-linux
os2 process linux implementation
2024-08-16 12:38:27 +01:00
gingerBill 65ce7687d7 Merge pull request #4004 from Skytrias/orca-odin-bindings
Add autogenerated orca bindings and macros from laytan
2024-08-16 12:37:36 +01:00
Laytan 6fc39c1b5d Merge pull request #4075 from yay/more-foundation-bindings
More Foundation bindings.
2024-08-16 13:08:15 +02:00
jason 07a9c69714 update core:filepath's clean, join and split_list to return optional Allocator_Errors 2024-08-16 01:48:27 -04:00
Vitalii Kravchenko 004036dc59 More Foundation bindings. 2024-08-16 00:00:29 +01:00
Laytan d91fa162d8 Merge pull request #3280 from beaumccartney/shm_syscalls
add shm_open and shm_unlink syscalls for darwin
2024-08-15 17:08:41 +02:00
gingerBill 6e91f6ab31 Merge pull request #4081 from DerTee/master
fix error handling in os2.read_entire_file_from_file()
2024-08-14 22:12:06 +01:00
gingerBill b16d5198a3 Merge pull request #4082 from FourteenBrush/master
Fix 'odin [run|test] --' giving a compiler out of bounds
2024-08-14 22:11:55 +01:00
FourteenBrush 12813e5d48 Fix 'odin [run|test] --' giving a compiler out of bounds 2024-08-14 21:37:40 +02:00
DerTee 6422e49255 fix error handling in os2.read_entire_file_from_file()
even when an error in file_size() happened, os2.ERROR_NONE was returned
2024-08-14 17:30:02 +02:00
Jeroen van Rijn f7234e2ed3 Allow ODIN_TEST_LOG_LEVEL override when -debug. 2024-08-14 16:29:51 +02:00
gingerBill e810c3eace Merge pull request #4012 from laytan/posix
core:sys/posix and core:os/os2 based on it (for darwin, netbsd, freebsd and openbsd)
2024-08-14 15:10:31 +01:00
gingerBill 18b6af1858 Minor clean up of comments 2024-08-14 14:15:20 +01:00
gingerBill 03dd38f203 Minor changes to vendor:ENet 2024-08-14 14:09:36 +01:00
gingerBill eb6f2078cf Add fmt:"v,extensions_count" tags to many struct fields 2024-08-14 14:03:41 +01:00
gingerBill df61096317 Improve doc comments for vendor:ggpo 2024-08-14 13:55:25 +01:00
gingerBill 8abe054665 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-08-14 13:02:28 +01:00
gingerBill 324d9c2284 Fix doc writer bug caused by using an iterator rather than a for loop 2024-08-14 13:02:23 +01:00
Laytan Laats f657b4cc0c time: use assert_contextless in wasi implementation 2024-08-14 13:27:58 +02:00
gingerBill c98c95fcf0 Add require_results and change some of the wrapper to return a slice 2024-08-14 11:29:23 +01:00
gingerBill fd5376ba88 Allow @(require_results) on foreign blocks 2024-08-14 11:28:49 +01:00
gingerBill 78fa675c1a Add assert_contextless, panic_contextless, unimplemented_contextless 2024-08-14 11:18:24 +01:00
gingerBill 4c19f507ff Merge pull request #4074 from odin-lang/vendor/box2d
`vendor:box2d`
2024-08-14 11:15:34 +01:00
gingerBill 651122e9db Fix foreign import paths 2024-08-14 11:01:54 +01:00
gingerBill d1e114742e Add deprecated and require_results attributes to math_functions.odin 2024-08-14 10:55:40 +01:00
Laytan 29a6959a56 Merge pull request #2977 from jakubtomsu/disallow-variadic-param-default
Report error when a variadic procedure parameter has a default value
2024-08-14 11:55:09 +02:00
gingerBill 491def9d5b Fix paths for amd64 targets 2024-08-14 10:50:53 +01:00
gingerBill 427c48221d Clean up foreign import code for library path determination 2024-08-14 10:28:07 +01:00
gingerBill 1c97739ca3 Merge branch 'vendor/box2d' of https://github.com/odin-lang/Odin into vendor/box2d 2024-08-14 10:18:41 +01:00
gingerBill 0b26115805 Improve presentation 2024-08-14 10:18:36 +01:00
gingerBill 1c8672ac6c Merge pull request #4078 from funkkiy/fix-rodata-index
Error if assigning to `rodata` variable with index
2024-08-14 09:41:35 +01:00
jason 0f052dbde7 os2/process_linux: improve error handling, use pidfd where possible, remove usage of fmt 2024-08-14 00:45:25 -04:00
Davi 4bb51249d1 Error if assigning to rodata variable with index 2024-08-13 23:28:34 -03:00
Laytan Laats e29f0a0f40 os2: dup the file descriptor before fdopendir 2024-08-14 01:45:24 +02:00
Laytan Laats f837e35f4b os2: fix bad free for posix file closure 2024-08-14 01:45:24 +02:00
Laytan Laats 61ee2efa35 os2: just use runtime._heap_allocator_proc instead of a copy for posix 2024-08-14 01:45:24 +02:00
Laytan Laats e94c4e1e18 posix: remove the is_temp things that prevented use-after-frees
https://github.com/odin-lang/Odin/commit/d0709a7de21efded4625167dbff4a7dd13d561b4
fixes those another way.
2024-08-14 01:45:24 +02:00
Laytan Laats b07d0b38b1 os2: improve absolute/full path handling for posix 2024-08-14 01:45:23 +02:00
Laytan Laats a73677d21a os2: nice != priority 2024-08-14 01:44:37 +02:00
Laytan Laats 67ea7bb65a posix: address some freebsd feedback 2024-08-14 01:44:37 +02:00
Laytan Laats 175f5b0bb1 os2: don't rely on PATH_MAX in posix read_directory implementation 2024-08-14 01:44:37 +02:00
Laytan Laats 939ba4cf08 os2: fix leak and always close directory 2024-08-14 01:44:37 +02:00
Laytan Laats f00f68ef6f posix/os2: fix test and add back in removed temp guard 2024-08-14 01:44:37 +02:00
Laytan Laats de9abe1f7b os2: skip . and .. in read dir 2024-08-14 01:44:37 +02:00
Laytan Laats bd808f9ec6 os2: fix wiping results with temp allocator guard 2024-08-14 01:44:37 +02:00
Laytan Laats 7474db6a34 os2: fix lstat logic 2024-08-14 01:44:37 +02:00
Laytan Laats 00eb702c4a os2: implement the iterator based read directory 2024-08-14 01:44:37 +02:00
Laytan Laats ea5783c2ac os2: fixes after rebasing 2024-08-14 01:44:37 +02:00
Laytan Laats e05fddc001 posix: fix file type checks in stat 2024-08-14 01:44:37 +02:00
Laytan Laats 406e60f5dd posix: revert change to os that was done for testing 2024-08-14 01:44:37 +02:00
Laytan Laats 5115aee23f posix: actually fix netbsd test 2024-08-14 01:44:37 +02:00
Laytan Laats 72220a855f posix: fix write error check 2024-08-14 01:44:37 +02:00
Laytan Laats 4a61bac100 posix: fix test on netbsd 2024-08-14 01:44:37 +02:00
Laytan Laats 726891588f posix: more tests 2024-08-14 01:44:37 +02:00
Laytan Laats 2a5ceff667 posix: move doc 2024-08-14 01:44:37 +02:00
Laytan Laats 9e2c5acb9d os2: fix bit checks 2024-08-14 01:44:37 +02:00
Laytan Laats 7c9ca60ff0 mem/virtual: support the BSDs 2024-08-14 01:44:37 +02:00
Laytan Laats 379cd6fe66 os2: cleanup 2024-08-14 01:44:37 +02:00
Laytan Laats ffff3c3c88 posix: fix foreign import of dl for free/netbsd 2024-08-14 01:44:37 +02:00
Laytan Laats a4d459f651 os2: initial implementation for Darwin&BSDs, process API is only thing incomplete 2024-08-14 01:44:37 +02:00
Laytan Laats ff0ca0bd53 os2: make config directory on darwin also ~/.config, it is the proper place 2024-08-14 01:44:37 +02:00
Laytan Laats 07b9f7d280 os2: fix read_entire_file bad logic 2024-08-14 01:44:37 +02:00
Laytan Laats 9f80191f60 os2: add default make_directory permissions 2024-08-14 01:44:37 +02:00
Laytan Laats efe68c2e24 posix: add package 2024-08-14 01:44:35 +02:00
Laytan 3847d03248 Merge pull request #3281 from erjohnson/patch-1
Update mem doc example formatting
2024-08-14 00:10:03 +02:00
Laytan Laats bb54a0a972 fix whitespace 2024-08-14 00:08:46 +02:00
Laytan Laats ac68a9d52c update MacOS releases 2024-08-14 00:00:50 +02:00
Laytan Laats d4d46df2fc box2d: add build script and MacOS libraries 2024-08-13 22:15:31 +02:00
gingerBill 660b6ff0f1 Add vendor:box2d to examples/all 2024-08-13 17:08:31 +01:00
gingerBill 9ccaca7f1a Minor style change 2024-08-13 17:01:55 +01:00
gingerBill 926c419ef8 Change .lib to be /MT compatible; Fix comments 2024-08-13 16:58:35 +01:00
gingerBill 22b32ab0fa Use intrinsics.has_target_feature 2024-08-13 16:35:28 +01:00
gingerBill 40361f877e Add libraries for windows 2024-08-13 16:34:31 +01:00
gingerBill f2ba3da895 Create bindings for box2d
Currently missing lib binaries
2024-08-13 16:18:24 +01:00
Laytan 55be3e60a0 Merge pull request #3125 from marcs-feh/master
sys/linux: Add binding to ioctl syscall + standard fd constants.
2024-08-13 15:30:50 +02:00
gingerBill 62911539cd Minor style change 2024-08-13 14:27:25 +01:00
Laytan c7af8af76a Update core/sys/linux/sys.odin 2024-08-13 15:22:35 +02:00
gingerBill e3d5bbe62c Merge pull request #4065 from laytan/fix-max-alignments
fix max alignments
2024-08-13 14:09:45 +01:00
gingerBill 2584c6bcd7 Merge pull request #4069 from zen3ger/1738-aliased-procedure-resolution
Fix alias handling of procedures
2024-08-13 14:07:51 +01:00
gingerBill 66d3082a9a Merge pull request #4056 from laytan/re-enable-runtime-wasm-stuff
re-enable some wasm things in runtime
2024-08-13 14:04:19 +01:00
gingerBill 09a07bd7e0 Merge pull request #4055 from laytan/time-wasi
time: wasi implementation
2024-08-13 14:03:02 +01:00
gingerBill 848f7e117f Merge pull request #4050 from IllusionMan1212/egl-procs
vendor/egl: added a few more egl procedures and constants
2024-08-13 14:01:20 +01:00
gingerBill d93364ce52 Merge pull request #4049 from IllusionMan1212/xrandr-xinput-xfixes
vendor/x11: added a few procedures for xrandr, xinput, and xfixes
2024-08-13 14:00:08 +01:00
gingerBill 4c4f24b5f4 Merge pull request #4041 from zen3ger/1079-parametric-struct-from-other-package
Check if procedure parameter type declares polymorphic args
2024-08-13 13:59:06 +01:00
Jeroen van Rijn 069ad446cd Merge pull request #4070 from Feoramund/test-runner-mem-fail-as-error
Let memory failures be errors in the test runner
2024-08-13 13:50:46 +02:00
Jeroen van Rijn 02b4bb8491 Merge pull request #4072 from laytan/fix-32-bit-math-round
fix type hint propagation for shift
2024-08-13 00:34:19 +02:00
Laytan Laats 2808ecc5b6 remove panic workaround 2024-08-12 23:48:36 +02:00
Laytan Laats a1d518442a fix type hint propogation for shift
Fixes #3856
2024-08-12 23:39:07 +02:00
Jeroen van Rijn 0d916a659e Merge pull request #4053 from Feoramund/fix-gitignore
Fix `.gitignore`
2024-08-12 21:34:26 +02:00
Feoramund 3a32250b80 Add .gitignore for tests directory 2024-08-12 15:16:52 -04:00
Jeroen van Rijn 053e65a1c8 Merge pull request #4071 from andreas-jonsson/andreas-jonsson-patch-2
Use another URL for pkgsrc on CI
2024-08-12 20:58:41 +02:00
Andreas T Jonsson 7af0291c7d Try use another arch URL for pkgsrc 2024-08-12 20:27:20 +02:00
Feoramund 0af025d056 Add explicit copyright info to core:testing 2024-08-12 14:16:22 -04:00
Roland Kovacs 9eb7186cda Fix alias handling of procedures
An incorrect memmove when overriding entities caused multiple ones to point to
the same procedure with incomplete variant data, resulting in later hiting a
compiler assertion.

Introduced delayed type checking for procedure aliases, as it was masked by
the previous error in the override logic.
2024-08-12 19:52:42 +02:00
Laytan d68cc41782 Merge pull request #4068 from laytan/fix-read-dir-closing-given-fd
fix `os.read_dir` closing the given file descriptor
2024-08-12 19:23:48 +02:00
Laytan fb09ec06d3 Merge pull request #4066 from Tetralux/fmt-bitfields-pointers
[fmt] Add bit fields to the pointer printing logic
2024-08-12 19:14:15 +02:00
Laytan Laats a4ac3cc6e8 fix os.read_dir closing the given file descriptor 2024-08-12 18:51:27 +02:00
Tetralux 4f56822204 [fmt] Add bit fields to the pointer printing logic
core:fmt prints pointers to structs as `&StructName{ ... }` but `bit_field`s are currently printed
the same as rawptrs (`0xAABBCCDDEEFF` only).

This commit changes that so they behave the same as structs and unions.
2024-08-12 16:25:22 +00:00
Laytan Laats f22ff21039 fix max alignments 2024-08-12 17:05:51 +02:00
Laytan b71e0c2e36 Merge pull request #4059 from laytan/loop-write-entire-file
loop write_entire_file to write more than MAX_RW
2024-08-12 13:54:46 +02:00
Laytan fd9a008e1e Merge pull request #4058 from laytan/fix-cvararg-bitset
fix c_vararg bit_set
2024-08-12 13:54:28 +02:00
Laytan 450fc3ec77 Merge pull request #4060 from laytan/support-field-tag-bitsets-in-core-odin
core/odin: support field tags on bit_field fields
2024-08-12 13:53:33 +02:00
Laytan 0a118a14ab Merge pull request #4061 from laytan/fix-fmt-maybe-pointer-detection
fix `type_info_union_is_pure_maybe` only working with regular pointers
2024-08-12 13:53:17 +02:00
Feoramund f42a22369e Fix wrong define name in test runner log messages 2024-08-11 23:01:28 -04:00
Feoramund 675add4d90 Optionally treat memory failures as errors in the test runner
Enable with `-define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true`.
2024-08-11 22:59:20 -04:00
Jeroen van Rijn 1761802330 Merge pull request #4062 from laytan/fix-switch-over-internal-pointer-union
fix type switching over internal pointer union
2024-08-12 00:25:47 +02:00
Laytan Laats 99aa0d3a35 fix type switching over internal pointer union
Fixes #3947
2024-08-12 00:02:05 +02:00
Laytan Laats dec97cbddb fix type_info_union_is_pure_maybe only working with regular pointers
Fixes #3996
2024-08-11 21:07:21 +02:00
Laytan Laats f0840ed24e core/odin: support field tags on bit_field fields
Fixes #4044
2024-08-11 20:59:54 +02:00
Laytan b9e68ee3c1 Merge pull request #4054 from Feoramund/zlib-reverse-bits
Use `intrinsics.reverse_bits` in `core:compress/zlib`
2024-08-11 17:42:28 +02:00
Laytan Laats d6336e7252 add orca to examples/all for docs 2024-08-11 17:35:19 +02:00
Laytan Laats c6a0d302b3 loop write_entire_file to write more than MAX_RW
Fixes #4042
2024-08-11 17:27:54 +02:00
Laytan Laats 26fa3aca44 fix copy-paste error in make docs 2024-08-11 17:09:26 +02:00
Laytan Laats e3f375afd8 fix c_vararg bit_set
Fixes #4051
2024-08-11 17:00:49 +02:00
Jeroen van Rijn 8a67221bd4 Merge pull request #4057 from asibahi/patch-1
typo fix
2024-08-11 13:35:10 +02:00
Abdul Rahman Sibahi 67251ad5b8 typo fix 2024-08-11 14:30:48 +03:00
Laytan 938e81e341 sys/orca: add missing using 2024-08-10 23:59:51 +02:00
Laytan Laats f5fe0de0fd add clarity for diverging mismatch error 2024-08-10 23:34:35 +02:00
Laytan Laats 7fd8b9c55b re-enable some wasm things in runtime
No idea why the floattidf procs are bodged to return 0, does somebody
know? I have just enabled the original codepath, if nobody knows I
suggest just enabling it and see if we get complaints, it works on all
wasm stuff I tried.

The linkage being set to "internal" instead of "strong" is actually
causing problems in my projects which is what prompted looking at this
in the first place, some of these functions were actually needed but not
added/used because they had internal linkage. This only happens on
bigger projects (or just when using f16?).

Unfortunately `git blame` gave me this generic commit: https://github.com/odin-lang/Odin/commit/94bad4d7861c78b9e7191ec0c3114861a1536d5c#diff-fb9f42022cb95efa59d16813546b8cb310234428c85edfabf09b1425c9dc46af
2024-08-10 23:10:30 +02:00
Laytan Laats a2cd763dbb time: wasi implementation 2024-08-10 23:01:31 +02:00
Feoramund cf8f6afeff Use intrinsics.reverse_bits in core:compress/zlib 2024-08-10 15:29:44 -04:00
Feoramund afbdc78f85 Fix .gitignore
- Remove all-encompassing `benchmark`
- Add exception for `core:simd/x86`
2024-08-10 15:16:12 -04:00
Laytan Laats 6918d8aaa6 possibly fix init_core_type_info race condition 2024-08-10 21:03:40 +02:00
Jeroen van Rijn e226d37803 Merge pull request #4023 from Feoramund/simd-index
Vectorize `index_byte`
2024-08-10 21:01:41 +02:00
Feoramund 4f816aabb3 Use SIMD_SCAN_WIDTH constant in core:bytes test 2024-08-10 13:54:12 -04:00
Laytan Laats d98f848247 fix debug compiler build message not ending output with a newline 2024-08-10 19:07:30 +02:00
Jeroen van Rijn 1242b6e82f Improve slice.binary_search_by 2024-08-10 18:26:59 +02:00
Jeroen van Rijn 9759d56c81 Merge pull request #4003 from Yawning/feature/crypto-improvements
core:crypto: Various improvements
2024-08-10 17:17:00 +02:00
Laytan d73ad8eb1e Merge pull request #4046 from laytan/cbor-fixes
encoding/cbor: various fixes
2024-08-10 17:02:41 +02:00
jason a52f7c129f stop trying to handle child pipe read errors in process_start 2024-08-10 09:13:07 -04:00
jason e54d6e5a11 Ignore process_open errors in process_start. This enforces a contract
with the user that any process returned without error must eventually be
waited on.
2024-08-10 09:03:34 -04:00
jason f7a73b9555 fix error handling; close read end of the child pipe instead of the write end twice 2024-08-10 08:55:40 -04:00
Feoramund 9d2b4b2f03 Simplify core:bytes test 2024-08-10 08:13:22 -04:00
Feoramund 5d5addd48f Set SIMD_SCAN_WIDTH based on size_of(uintptr) 2024-08-10 07:43:14 -04:00
Feoramund c69fa87d53 Merge core:simd/util into core:bytes 2024-08-10 07:17:03 -04:00
Jeroen van Rijn bf53d2f6db Fix time.precise_clock on 32-bit platforms. 2024-08-10 12:44:40 +02:00
Jeroen van Rijn d267735d99 Fixed time.precise_clock 2024-08-10 12:35:58 +02:00
IllusionMan1212 554b0e5bf7 vendor/x11: added a few procedures for xrandr, xinput, and xfixes 2024-08-10 12:06:52 +02:00
Yawning Angel ba1ad82c2b core/crypto/aead: Initial import 2024-08-10 18:32:37 +09:00
Yawning Angel 38aea1f907 core/crypto/aes,chacha20poly1305: Add require_results to open 2024-08-10 18:32:37 +09:00
Yawning Angel b381791f42 core/crypto/chacha20: Change API terminology to be consistent with AES 2024-08-10 18:32:37 +09:00
Yawning Angel 14ceb0b19d core/crypto/chacha20poly1305: Support AEAD_XChaCha20_Poly1305
IETF-draft flavor (32-bit counter) though this makes no practical
difference.
2024-08-10 18:32:37 +09:00
Yawning Angel 8efc98ce90 core/crypto/chacha20poly1305: Change the interface to match GCM 2024-08-10 18:32:37 +09:00
Yawning Angel 1f3107e693 core/crypto/chacha20: Use 128-bit/256-bit SIMD 2024-08-10 18:32:37 +09:00
Yawning Angel 708f053fe6 core/crypto/aes: Use NIST terminology for the IV 2024-08-10 18:32:37 +09:00
Yawning Angel ac7f44b1b8 core/crypto/aes: Slightly tweak GHASH to look less spooky 2024-08-10 18:32:37 +09:00
Yawning Angel b1d6e4139e core/crypto/aes: Disable bounds checking for the CTR loops 2024-08-10 18:32:37 +09:00
Yawning Angel dfc4df9807 core/crypto/_aes/hw_intel: Use a constant for the PSHUFB indicies 2024-08-10 18:32:37 +09:00
Yawning Angel b9293334ca core/crypto/ed25519: Rename a member for clarity
This better matches the spec.
2024-08-10 18:32:37 +09:00
Yawning Angel b68311d777 core/crypto/hash: Make the _to_buffer routines return the hash slice
Quality of life improvement.
2024-08-10 18:32:37 +09:00
Yawning Angel c0f9655ec4 test/core/crypto: Minor changes to AES related tests
- Test against the non-standard GCM nonce length vectors
- Fix the CTR mode test to match the comment

Correctness was fine without this change.
2024-08-10 18:32:37 +09:00
IllusionMan1212 7875e4a1ab vendor/egl: added a few more egl procedures and constants 2024-08-10 10:21:03 +02:00
Jeroen van Rijn be7a1f671c Revert "Add time.precise_clock_from_time + time.precise_clock_from_duration"
This reverts commit c9ca192f33.
2024-08-10 03:26:09 +02:00
Jeroen van Rijn c9ca192f33 Add time.precise_clock_from_time + time.precise_clock_from_duration 2024-08-10 03:23:08 +02:00
Feoramund e7e7fe766a Add test for misaligned data to core:simd/util suite 2024-08-09 18:54:04 -04:00
Feoramund 0d29cc3375 Use for x in y construct for bytes iteration
This cannot be applied to the `strings` version, as that would cause a
rune-by-rune iteration, not a byte-by-byte one.
2024-08-09 18:54:04 -04:00
Feoramund c8a62ee4ec Make simd_util index procs contextless where applicable 2024-08-09 18:54:04 -04:00
Feoramund 12dd0cb72a Simplify and make simd_util cross-platform
This new algorithm uses a Scalar->Vector->Scalar iteration loop which
requires no masking off of any incomplete data chunks.

Also, the width was reduced to 32 bytes instead of 64, as I found this
to be about as fast as the previous 64-byte x86 version.
2024-08-09 18:54:04 -04:00
Laytan Laats 912f99abc8 encoding/cbor: various fixes
- "null" is the proper way to represent the nil value in the diagnostic
  format
- hex encoding in diagnostic format was wrong
- struct keys weren't sorted the right deterministic way
2024-08-09 21:56:54 +02:00
jason baacc512e3 fix child pipe in process_start 2024-08-09 15:21:11 -04:00
Jeroen van Rijn c5ed7083d2 Disable NetBSD CI 2024-08-09 19:44:51 +02:00
Jeroen van Rijn d69e0bfa00 NetBSD vm fix. 2024-08-09 19:37:26 +02:00
Jeroen van Rijn fa6f343261 Remove unused import. 2024-08-09 19:06:50 +02:00
jason c4d43bbab0 os2 linux process_wait rework; add Sig_Child_Code to sys/linux bits 2024-08-09 09:16:44 -04:00
Jeroen van Rijn cc24d2de3e Merge pull request #3810 from Feoramund/freebsd-core-net
Port `core:net` to FreeBSD
2024-08-09 09:50:05 +02:00
Jeroen van Rijn bc6deab175 echo -> printf for build_odin.sh message 2024-08-09 09:46:45 +02:00
Laytan b5a612202f Merge pull request #4036 from laytan/master
add debug build message and align more with build.bat
2024-08-08 22:21:17 +02:00
Jeroen van Rijn 1e09ff3b2e Merge pull request #4043 from Kelimion/expect_leak_or_bad_free
Allow testing for intentional leaks in test runner
2024-08-08 21:40:17 +02:00
Jeroen van Rijn 933f9f9bd1 Enable test leak = fatal on CI. 2024-08-08 21:31:30 +02:00
Jeroen van Rijn b82cfc5f15 Fix shoco heisenleak 2024-08-08 21:15:59 +02:00
Jeroen van Rijn a05b73c632 Keep -vet happy when mem tracking is disabled. 2024-08-08 21:02:35 +02:00
Jeroen van Rijn 4d27898418 Use test runner's own tracking allocator. 2024-08-08 20:58:25 +02:00
Jeroen van Rijn 80d1e1ba82 Allow testing for intentional leaks in test runner
Adds `expect_leak_or_bad_free :: proc(t: ^T, client_test: proc(t: ^T), verifier: Memory_Verifier_Proc)`.

It sets up its own `Tracking_Allocator`, runs the `client_test`, and then calls the `verifier` procedure.
The verifier can then inspect the contents of the tracking allocator and call `testing.expect*` as sensible for the test in question.

Any allocations are then cleared so that the test runner doesn't itself complain about leaks.

Additionally, `ODIN_TEST_LOG_LEVEL_MEMORY` has been added as a define to set the severity of the test runner's memory tracker. You can use `-define:ODIN_TEST_LOG_LEVEL_MEMORY=error` to make tests fail rather than warn if leaks or bad frees have been found.
2024-08-08 20:41:32 +02:00
Roland Kovacs dda89a69bf Check if procedure parameter type declares polymorphic args
When a procedure parameter's type was declared in an imported package the type
checker correctly resolved to the parametric type, but it did not check if the
expression that refers to that type conforms to a polymorphic type declaration.

This error was not detected if the procedure was unused, since it was marked as
polymorphic, where further type check is done on instantiation.
2024-08-08 19:50:05 +02:00
Jeroen van Rijn f328929939 Merge pull request #4038 from Hyrtwol/core-sys-windows-rawinput-code
Core sys windows rawinput code
2024-08-08 18:23:02 +02:00
Thomas la Cour 3d0519fe6c trim whitespace 2024-08-08 18:05:41 +02:00
Thomas la Cour a4eeb6ed02 rawinput code 2024-08-08 18:03:59 +02:00
Jeroen van Rijn 94c62fb630 Fix typo. 2024-08-08 18:01:09 +02:00
Jeroen van Rijn a7fe9eec73 Merge pull request #4037 from Kelimion/symlink_test
Allow symlink test to work irrespective of git settings.
2024-08-08 17:56:05 +02:00
Jeroen van Rijn d93f3c63d8 Rename package to test_core_os to fit with the rest of test_* 2024-08-08 17:49:08 +02:00
Jeroen van Rijn ada3df303e Allow symlink test to work irrespective of git settings. 2024-08-08 17:46:00 +02:00
Laytan Laats 8b98fff98e add debug build message and align more with build.bat
1. if ran without choosing a build type (just `make` or
   `build_odin.sh`), print out a message about it being a debug build
2. Add `make release-native` alongside `make release_native` to align
   with `build_odin.sh release-native`
3. Only run the demo if it is a debug build (just like `build.bat`)
2024-08-08 15:33:40 +02:00
jason c3ba8fbd09 add child pipe for reporting post-fork errors 2024-08-08 08:56:29 -04:00
Jeroen van Rijn 4b9ca39522 Merge pull request #4035 from karl-zylinski/build-release-hint
Added a hint at end of build.bat about release mode when building in debug mode
2024-08-08 14:48:48 +02:00
Karl Zylinski 26633bbce6 Added a hint at end of build.bat about release mode when building in debug mode. 2024-08-08 14:15:32 +02:00
jason 9625798513 merge commit 2024-08-07 23:27:45 -04:00
Jeroen van Rijn 796feeead9 Remove LLVM copy from nightly. 2024-08-07 22:12:23 +02:00
Jeroen van Rijn 2bf055ec6e Delete empty file after access check. 2024-08-07 19:38:36 +02:00
Laytan Laats c9b69d76b0 text/edit: fix undo_state_push wrong builder check 2024-08-07 17:21:56 +02:00
Jeroen van Rijn 69a15ca5b6 Don't copy LLVM shared object on Linux
We copy the LLVM shared object when building Odin on Linux. Contrary the comment in `build_odin.sh`,
this is unnecessary, and Odin can be compiled and itself compile things just fine without this step.

This is then packaged up at release and leads to #4019 and #4033. The Linux release builds are built
on Ubuntu and not strictly supported on other Linux distributions. Building from source is preferred.
2024-08-07 14:50:45 +02:00
Laytan Laats 6fe938b946 darwin: add setAllowedFileTypes binding for open panels 2024-08-06 21:42:33 +02:00
Laytan Laats e5a478d393 wgpu: fix examples after changing color to an array 2024-08-06 21:42:33 +02:00
Feoramund 793811b219 Add simd_util to examples/all 2024-08-06 15:19:05 -04:00
Feoramund 0418d27bdf Add benchmarks for vectorized index_* procs 2024-08-06 15:19:05 -04:00
Feoramund 28c98c2e7a Add tests for vectorized index_* procs 2024-08-06 15:19:05 -04:00
Feoramund f66fcd9acb Use vectorized index_* procs in core 2024-08-06 15:19:05 -04:00
Feoramund 8deeb40e5d Add vectorized index_byte and last_index_byte 2024-08-06 15:19:01 -04:00
gingerBill 39d557bcb4 Merge pull request #4032 from Feoramund/fix-intrinsic-wording
Fix SIMD intrinsics wording
2024-08-06 20:13:10 +01:00
Feoramund e27a424f4d Swap reduce_any and reduce_all
`llvm.vector.reduce.or` will return true if any lane is true.
`llvm.vector.reduce.and` will return true if all lanes are true.
2024-08-06 14:50:34 -04:00
Feoramund 7a367c9c08 Fix documented names of a few SIMD procedures 2024-08-06 14:49:56 -04:00
Laytan 4423aac3de Merge pull request #4031 from RilleP/bit-field-closing-brace-fix
Fix missing closing brace for Bit_Field in core:odin/parser
2024-08-06 20:49:49 +02:00
gingerBill 94ded29b5f Merge pull request #4030 from Kelimion/struct_field_count
Add `reflect.struct_field_count` that returns the number of fields in a struct type
2024-08-06 18:56:24 +01:00
Rikard Petré 6a6f078186 Fix missing closing brace for Bit_Field in core:odin/parser 2024-08-06 19:48:38 +02:00
gingerBill bed18a17e6 Bodge: Improve aligned_resize logic 2024-08-06 11:22:34 +01:00
Jeroen van Rijn 17ebaffce8 Update comment. 2024-08-05 22:12:22 +02:00
Jeroen van Rijn 4902288a5a Add reflect.struct_field_count that returns the number of fields in a struct type
Example:
```odin
package struct_count_example

import "core:fmt"
import "core:reflect"
import "core:dynlib"

Foo :: struct{
	one: int,
	two: f32,
}

Bar :: struct {
	three: int,
	four:  bool,
	five:  f64,
}

Game_Api :: struct {
	init:      proc(api: ^Game_Api),
	update:    proc(api: ^Game_Api),

	using foo: Foo,
	bar:       Bar,

	// Private stuff
	reload_count: int,
	__handle:     rawptr,
}
API_PRIVATE_COUNT :: 2

game_api: Game_Api

main :: proc() {
	fmt.printfln("Game_Api, .Top:       %v", reflect.struct_field_count(Game_Api))              // 6
	fmt.printfln("Game_Api, .Using:     %v", reflect.struct_field_count(Game_Api, .Using))      // 8
	fmt.printfln("Game_Api, .Recursive: %v", reflect.struct_field_count(Game_Api, .Recursive))  // 11

	symbols_loaded, _  := dynlib.initialize_symbols(&game_api, "game.dll")
	symbols_expected   := reflect.struct_field_count(Game_Api) - API_PRIVATE_COUNT

	if symbols_loaded == -1 {
		fmt.eprintln("Couldn't load game.dll")
		return
	} else if symbols_loaded != symbols_expected {
		fmt.eprintfln("Expected %v symbols, got %v", symbols_expected, symbols_loaded)
		return
	}
}
```
2024-08-05 22:04:16 +02:00
Laytan a1c3c38f04 Merge pull request #4029 from Feoramund/fix-darwin-sigpipe-send
Prevent `SIGPIPE` on Darwin when writing to a closed `core:net` socket
2024-08-05 19:26:16 +02:00
Feoramund 4c0ab09c9a Handle EPIPE in Darwin core:net 2024-08-05 13:15:08 -04:00
Feoramund 6cc7f3b451 Add FreeBSD Accept_Error.Would_Block alias 2024-08-05 13:00:44 -04:00
Feoramund 3512d7c672 Move Darwin MSG_NOSIGNAL to core:os 2024-08-05 12:49:12 -04:00
Feoramund eba0774bf3 Prevent SIGPIPE on Darwin when writing to a closed core:net socket
Mimics behavior found on Linux implementation.
2024-08-05 12:23:09 -04:00
gingerBill 7c3461b0df Merge pull request #4028 from Kelimion/fix-4026
Fix crash if referencing import "aliased" in other file.
2024-08-05 16:57:58 +01:00
Jeroen van Rijn 2cc3795686 Merge pull request #4027 from karl-zylinski/blend-pixel-compile-fix
Fix for blend_pixel.odin in core/image/common.odin not compiling
2024-08-05 17:38:30 +02:00
Karl Zylinski b63657d293 Fix for blend_pixel.odin in core/image/common.odin not compiling 2024-08-05 17:23:58 +02:00
Jeroen van Rijn 6175efde3d Fix crash if referencing import "aliased" in other file.
Fixes #4026
2024-08-05 17:23:50 +02:00
Jeroen van Rijn 030220eb22 Merge pull request #4025 from karl-zylinski/patch-2
core/image/common.odin compile fix
2024-08-05 16:42:09 +02:00
Karl Zylinski 2d32b819dc common.odin compile fix
Fix for "Error: Prefer to separate 'where' clauses with a comma rather than '&&'"
2024-08-05 16:32:34 +02:00
gingerBill f56abf3780 Add intrinsics.masked_expand_load and intrinsics.masked_compress_store 2024-08-05 14:54:09 +01:00
gingerBill 78919f8524 Fix typos 2024-08-05 14:48:55 +01:00
gingerBill 80ea4e0aeb Remove dead code 2024-08-05 14:25:33 +01:00
gingerBill 84ac56f778 Add intrinsics.simd_masked_load and intrinsics.simd_masked_store 2024-08-05 14:08:41 +01:00
gingerBill 7e701d1677 Add intrinsics.simd_gather and `intrinsics.simd_scatter 2024-08-05 13:46:24 +01:00
gingerBill b67ed78afd add_sat -> saturating_add 2024-08-05 13:21:27 +01:00
gingerBill 90fc52c2ee Rename add_sat -> saturating_add 2024-08-05 13:19:01 +01:00
gingerBill 9a01a13914 Add simd_reduce_any and simd_reduce_all 2024-08-05 13:13:19 +01:00
gingerBill eeb92e2644 Allow cast between #simd[N]rawptr <-> #simd[N]uintptr 2024-08-05 13:06:55 +01:00
gingerBill fd06be2243 Allow swizzle to take more arguments than the original array length 2024-08-05 12:33:02 +01:00
gingerBill a06cb8ba46 Add #simd[N]rawptr support 2024-08-05 12:04:36 +01:00
Feoramund d0d4f19097 Remove debug line from test 2024-08-05 03:50:41 -04:00
Feoramund 8f5b838a07 Review manual for loops in core:text/regex 2024-08-05 03:49:29 -04:00
Feoramund ba0581ae79 Give FreeBSD access to core:net in core:flags 2024-08-05 03:05:50 -04:00
Feoramund d9404d928c Add copyright info to core:sys/freebsd 2024-08-05 03:05:50 -04:00
Feoramund fe754af13d Add new contribution notes to core:net 2024-08-05 03:05:49 -04:00
Feoramund 61e770d943 Clean up some FreeBSD core:net code 2024-08-05 03:05:43 -04:00
Feoramund 2b63684ccf Fix integer socket option values for FreeBSD 2024-08-05 02:14:41 -04:00
Feoramund 5ece6980eb Make EINVAL generic in FreeBSD Socket_Option_Error
The documentation for `setsockopt(2)` mentioned accept filters for
`EINVAL`, but I've found that it can arise for any manner of invalid
values for setting socket options.

We'll just have to leave this as a generic error.
2024-08-05 02:14:27 -04:00
Feoramund 42a2297d31 Add core:net tests specifically for FreeBSD 2024-08-05 02:08:48 -04:00
Feoramund 8de48d81ea Use common name for ENOBUFS 2024-08-05 00:30:39 -04:00
Feoramund 32fb1fb61c Add missing ECONNRESET TCP_Send_Error
This was not specifically documented in `send(2)`.
2024-08-05 00:30:39 -04:00
Feoramund 05c50561ae Set NOSIGPIPE on all core:net FreeBSD sockets 2024-08-05 00:30:39 -04:00
Feoramund 46455dd0a6 Add more socket options for FreeBSD core:net 2024-08-05 00:30:24 -04:00
Feoramund 3f9ddfe029 Clarify what umtx is 2024-08-04 22:24:55 -04:00
Feoramund 14858309f0 Add explicit license info to core:text/regex 2024-08-04 19:18:16 -04:00
Feoramund e17fc8272b Document rationale behind RegEx shorthand classes 2024-08-04 19:12:46 -04:00
Feoramund dde42f0ebc Add more documentation for core:text/regex API 2024-08-04 18:56:29 -04:00
Feoramund ca7e46d56f Add explicit test case for Capture pos 2024-08-04 18:56:29 -04:00
Feoramund 743480b1a4 Use regex.destroy for test captures 2024-08-04 18:56:29 -04:00
Feoramund 1ccb0b2558 Remove unused code 2024-08-04 18:56:29 -04:00
Feoramund babdc432e9 Move Flag_To_Letter to core:text/regex/common 2024-08-04 18:56:25 -04:00
Feoramund d3a51e208d Hide Regular_Expression values
We don't directly support printing these.

To prevent future issues being raised about the pattern being missing if
someone tries to print one, hide everything.
2024-08-04 18:40:27 -04:00
Feoramund cd8272557f Test that a RegEx Capture pos corresponds to its groups 2024-08-04 18:33:36 -04:00
gingerBill 7e0fa795e4 Just compare against nil directly if the comparator is known to be nil too 2024-08-04 21:17:58 +01:00
Feoramund 6252712363 Add missing features to regex package documentation 2024-08-04 13:21:13 -04:00
gingerBill 60bc7f53d2 Comment out open_buffered 2024-08-04 17:41:48 +01:00
gingerBill cf3c1a85ec Remove temp parameter 2024-08-04 17:36:28 +01:00
gingerBill 046f72befd Mock out open_buffered 2024-08-04 17:31:39 +01:00
gingerBill f19436fb4d Only swap if there was an arena 2024-08-04 17:17:09 +01:00
gingerBill d0709a7de2 Allow for nested temp_allocator() calls to flip between arenas on TEMP_ALLOCATOR_GUARDs 2024-08-04 17:14:24 +01:00
gingerBill f427f040fd Merge pull request #4020 from odin-lang/bill/os-errno
`os.Error` to replace `os.Errno`
2024-08-04 15:53:18 +01:00
gingerBill c078b2dd1b Add @(require_results) 2024-08-04 15:24:26 +01:00
gingerBill bf948ab8ae Add stubs for flush on platforms that didn't have it 2024-08-04 15:07:24 +01:00
gingerBill acb1ebddf6 Fix err != 0 uses 2024-08-04 15:01:04 +01:00
gingerBill 0bedd3357a Disallow err != 0 with os.Error when -strict-style is enabled 2024-08-04 14:58:12 +01:00
gingerBill 93fabf8628 Replace err != 0 with err != nil where possible 2024-08-04 14:57:25 +01:00
gingerBill fc10b781af Update core/os/os2/process.odin
Co-authored-by: Laytan <laytanlaats@hotmail.com>
2024-08-04 14:47:44 +01:00
gingerBill 6a6b5061db Update core/os/os_darwin.odin
Co-authored-by: Laytan <laytanlaats@hotmail.com>
2024-08-04 14:47:35 +01:00
gingerBill b67817517e Fix replace typo 2024-08-04 14:46:32 +01:00
gingerBill fff1d509d5 Add read_entire_file_or_err and write_entire_file_or_err 2024-08-04 14:41:55 +01:00
gingerBill e8d26c5797 Move errors to where appropriate 2024-08-04 13:41:34 +01:00
gingerBill 3d992e2704 Improve _error_string for Linux 2024-08-04 13:25:35 +01:00
gingerBill 0c5b645dde Correct EOF value 2024-08-04 13:20:33 +01:00
gingerBill cf5ec25873 Add extra cases for flush 2024-08-04 13:18:51 +01:00
gingerBill 7663a2036a Add read_at/write_at to missing platforms 2024-08-04 13:16:37 +01:00
gingerBill c32f345c68 Move error stuff to errors.odin 2024-08-04 12:55:08 +01:00
gingerBill 649b25fba6 Update the demo.odin to use nil instead of os.ERROR_NONE 2024-08-04 12:47:49 +01:00
gingerBill bdbbbf5c95 Fix typo; remove unneeded casts 2024-08-04 12:39:21 +01:00
gingerBill e8b6d15db9 Fix replace typo 2024-08-04 12:31:22 +01:00
gingerBill 5f7fef92fa Update example to use err != nil instead 2024-08-04 12:25:50 +01:00
gingerBill 66b86bc7e0 Correct os errors for darwin 2024-08-04 12:23:18 +01:00
gingerBill 5187bb68bb Hack: Convert 0 to nil 2024-08-04 12:08:52 +01:00
gingerBill 97c499dbb4 Begin mapping os.Error in the rest of the codebase 2024-08-04 11:58:04 +01:00
gingerBill 1d75a612d5 os.Errno -> os.Error 2024-08-04 11:47:23 +01:00
gingerBill 160048eaee Errno -> Error 2024-08-04 11:46:42 +01:00
gingerBill def2e2e271 Try to map to General_Error where possible 2024-08-04 11:44:45 +01:00
gingerBill 28666414bc More clean ups of ERROR_NONE and != nil usage 2024-08-04 11:37:49 +01:00
gingerBill a241168142 Clean up err != nil usage 2024-08-04 11:26:35 +01:00
gingerBill 29b6eebcd5 Clean up error handling 2024-08-04 11:21:09 +01:00
gingerBill 7dae38ce89 Begin mocking out for other errors 2024-08-04 11:12:45 +01:00
gingerBill 1826b0c700 Fix copy-replace errors 2024-08-04 11:10:17 +01:00
gingerBill 9f9abb8fb3 Use union #shared_nil for os.Error 2024-08-04 11:05:30 +01:00
gingerBill e60951a902 Begin converting os.Errno to be a nil-able type as a transition period 2024-08-04 10:51:08 +01:00
gingerBill 71932628cc Add alias 2024-08-04 10:08:48 +01:00
jason c691c7dc68 point stdin, stdout, stderr to /dev/null if unused in os2.process_start 2024-08-04 01:47:10 -04:00
jason 2a7db08c20 Remove returned bool from access and faccessat in sys/linux.
Switch to using AT_EMPTY_PATH to execve with file descriptors.
2024-08-04 00:59:40 -04:00
jason 2b89829b52 minor edits in process_linux.odin 2024-08-03 18:08:00 -04:00
Laytan Laats e77977c8ef fix vet errors in stb truetype 2024-08-03 23:56:19 +02:00
jason 38b96a7981 change child error behavior to trap instead of exit 2024-08-03 17:50:47 -04:00
Laytan Laats 4dd846fa29 fix readir_r link name for netbsd 2024-08-03 15:54:29 +02:00
Laytan Laats 61008232e4 actually fail CI when NetBSD tests fail 2024-08-03 15:43:35 +02:00
Jeroen van Rijn 90e573c54a Add image.premultiply_alpha helper. 2024-08-03 12:58:43 +02:00
Laytan ac483f72eb Merge pull request #4013 from laytan/fix-os-read-dir-with-symlinks
fix os.read_dir with symlinks
2024-08-03 01:08:23 +02:00
Laytan Laats 99d9e8f8b1 fix os.read_dir with symlinks 2024-08-03 00:26:46 +02:00
skytrias 9f5854e24e Update orca bindings and macros to requested changes 2024-08-02 23:46:02 +02:00
Laytan 772dce7e42 Merge pull request #3969 from elvodqa/master
Add `sdl2glue` to `vendor:wgpu` package
2024-08-02 17:18:34 +02:00
Emir e55d09bdfa Update vendor/wgpu/examples/sdl2/main.odin
Co-authored-by: Laytan <laytanlaats@hotmail.com>
2024-08-02 18:04:36 +03:00
Jeroen van Rijn 1a16585b10 Add image.pixels_to_image helper. 2024-08-02 14:54:52 +02:00
Laytan 500c117312 Merge pull request #4008 from Daxode/wasm-quality-of-life
Quality of Life changes to wgpu/js
2024-08-02 13:51:47 +02:00
daniel-andersen 723e6d19be right number whoops! 2024-08-02 13:38:36 +02:00
Jeroen van Rijn 8e8660fdfc Merge pull request #4007 from marcosantos98/fix-wasm
Fix: compilation error when using BufferSubDataSlice in webgl package
2024-08-02 12:31:23 +02:00
marcosantos98 3bfccde6f9 Fix: remove extra usage in webgl.odin:250
Compilation error when using webgl.BufferSubDataSlice.
The `usage` parameter is nowhere to be found.
This is probably a copy-pasta leftover.
2024-08-02 10:50:16 +01:00
daniel-andersen e7041f785a Quality of life changes to wgpu/wasm stuff 2024-08-02 11:04:10 +02:00
gingerBill 83599957b1 Merge pull request #3998 from zen3ger/os2-temp_file_linux
[os2] Add missing temp_file implementation for Linux
2024-08-01 20:07:21 +01:00
skytrias f8e0cda113 Add autogenerated orca bindings and macros from laytan 2024-08-01 19:19:24 +02:00
Jeroen van Rijn 0fa62937d5 Fix NetBSD CI 2024-07-31 20:19:13 +02:00
Jeroen van Rijn f627a38b4f Update rand.reset() example. 2024-07-31 20:00:55 +02:00
Jeroen van Rijn cc8c2f236b Merge pull request #4002 from thetarnav/update-builtin-constants
Update comments for builtin constants
2024-07-31 19:47:01 +02:00
Damian Tarnawski 953ae32607 Update builtin constants 2024-07-31 18:55:04 +02:00
Jeroen van Rijn fdfe6b00e0 Improve output path checking
Fixes #4001
2024-07-31 15:16:09 +02:00
Laytan 8a9901aeab Merge pull request #4000 from lxmcf/master
[vendor:raylib] Remove GuiStyleProp
2024-07-31 12:34:00 +02:00
Alex Macafee 1f2ab84e82 Use GuiControlProperty instead of c.int 2024-07-31 19:08:08 +10:00
Alex Macafee 92831d7ca3 Remove GuiStyleProp 2024-07-31 18:58:43 +10:00
Alex Macafee f33b4ecd3e Update Raygui Style set/get functions 2024-07-31 18:48:16 +10:00
gingerBill 62191f54a0 Merge pull request #3997 from Hyrtwol/reource-fix-windows
fix for using .rc files
2024-07-30 21:26:07 +01:00
gingerBill 04c3723985 Merge pull request #3992 from thetarnav/parser-patch
Correct the Array_Type.len comment and assign tok when making Ellipsis node
2024-07-30 21:25:21 +01:00
gingerBill ac19bb3a8c Merge pull request #3985 from flysand7/docs-sync
[sync]: Document all procedures
2024-07-30 21:24:59 +01:00
Roland Kovacs 1913c08b7b [os2] Add missing temp_file implementation for Linux 2024-07-30 18:11:44 +02:00
Thomas la Cour 744d7f7ef4 fix for using .rc files 2024-07-30 16:53:14 +02:00
jason c7eb2ae6bb use sys/linux dirent instead of manual iteration 2024-07-30 10:19:09 -04:00
jason 792640df1f remove File_Impl_Kind from file_linux 2024-07-30 09:41:49 -04:00
jason 278a63caaa remove pidfd availability caching 2024-07-30 09:28:40 -04:00
jason a03dffcd1a improve error handling; do not report errors from failed execve 2024-07-30 08:45:53 -04:00
flysand7 3aac4b1a3e [sync]: Document all procedures 2024-07-30 19:13:35 +11:00
Damian Tarnawski 478b2d7444 Correct the Array_Type.len comment and assign tok when making Ellipsis node 2024-07-29 22:14:42 +02:00
Laytan 7f17d4eb7f Merge pull request #3991 from laytan/fix-in-map-with-union-variants
fix `specific_union_variant in map_keyed_by_union` not converting to union type
2024-07-29 02:39:47 +02:00
Laytan Laats 4d1d754cae fix specific_union_variant in map_keyed_by_union not converting to union type 2024-07-29 02:32:13 +02:00
Jeroen van Rijn 24e6f16f4a Clamp dot in angle_between to avoid precision errors.
Fixes #3978
2024-07-28 15:00:29 +02:00
Laytan f852aac0e7 Merge pull request #3989 from colrdavidson/spall_doc
Improve Spall Docs slightly to reduce onboarding friction
2024-07-28 12:46:04 +02:00
Colin Davidson 27f75c40ab make example compile 2024-07-28 01:29:33 -07:00
Colin Davidson 1d598f8287 tweak doc a little to reduce onboarding friction for thread-users 2024-07-28 01:23:47 -07:00
Jeroen van Rijn cb31df34c1 Merge pull request #3362 from Hyrtwol/sys-windows-2
core/sys/windows part 2
2024-07-26 14:29:56 +02:00
Thomas la Cour 271ec643ed removed some comments 2024-07-26 11:30:48 +02:00
Thomas la Cour fe587ee79a try to add sys/windows to the normal core tests 2024-07-26 11:04:13 +02:00
Thomas la Cour b149b3d6c6 Merge remote-tracking branch 'upstream/master' into sys-windows-2 2024-07-26 10:45:09 +02:00
Thomas la Cour 03f3ea5a9e removed old test stuff 2024-07-26 10:43:26 +02:00
Thomas la Cour 6e6f2a1f6b removed obsolete fiels on WIN32_FIND_DATAW to match the size from the winsdk headers 2024-07-26 10:14:13 +02:00
Thomas la Cour 58ab6e5f94 missign cursorinfo 2024-07-26 10:07:20 +02:00
Jeroen van Rijn 4e194d5dbd Merge pull request #3980 from Kelimion/format-time
Add `time.to_string*` formatters.
2024-07-25 21:09:51 +02:00
Jeroen van Rijn 00c6b83537 Use constants in example. 2024-07-25 21:02:38 +02:00
Jeroen van Rijn ca7d86084e Improve docs. 2024-07-25 20:58:47 +02:00
Jeroen van Rijn 9088a493d9 Add time.to_string* formatters. 2024-07-25 19:43:42 +02:00
Thomas la Cour fe4754a77c format 2024-07-25 10:27:49 +02:00
Thomas la Cour 9d67d12d22 Merge remote-tracking branch 'upstream/master' into sys-windows-2
# Conflicts:
#	core/sys/windows/shell32.odin
2024-07-25 10:05:41 +02:00
gingerBill 9e82ae10ac Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-24 21:55:55 +01:00
gingerBill 85880f9def Add more NtDll stuff 2024-07-24 21:55:51 +01:00
Jeroen van Rijn 4ff62994bf Add CLSCTX_ALL 2024-07-24 22:54:17 +02:00
Feoramund 90f1f7fbdf Use unaligned_store in regex too 2024-07-24 16:48:49 -04:00
gingerBill 9b624ef9e1 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-24 21:45:40 +01:00
gingerBill f03c2b7783 General clean up of os2.read_directory for Windows 2024-07-24 21:45:35 +01:00
Feoramund ff492e615c Use unaligned_load for regex virtual machine
This should hopefully avoid any issues with loading operands greater
than 8 bits on alignment-sensitive platforms.
2024-07-24 16:27:20 -04:00
Feoramund 042f6de478 Remove printing facilities for Regular_Expression
The `original_pattern` introduced a tenuous dependency to the expression
value as a whole, and after some consideration, I decided that it would
be better for the developer to manage their own pattern strings.

In the event you need to print the text representation of a pattern,
it's usually better that you manage the memory of it as well.
2024-07-24 16:27:20 -04:00
Feoramund c52a8a5f86 Allow configuring of MAX_CAPTURE_GROUPS for n > 10 2024-07-24 16:27:08 -04:00
Feoramund 16b644ad79 Use slice.zero instead 2024-07-24 15:23:20 -04:00
Feoramund e8537a3134 Add test cases for unclosed classes and repetition
Simplified error checking while I was at it, too.
2024-07-24 15:21:41 -04:00
Feoramund e642be8550 Fix handling of unclosed regex classes and repetitions 2024-07-24 15:17:37 -04:00
Jeroen van Rijn 33d6677514 Merge pull request #3951 from Kelimion/lua_test
Add Lua example to `vendor:lua` as well as basic tests.
2024-07-24 17:50:49 +02:00
Jeroen van Rijn 8d6ff51922 Copy lua54.dll during CI test 2024-07-24 17:43:51 +02:00
jason a5fa93e06d remove ctprintf; use fmt.caprintf; fix pipe_linux that I broke. 2024-07-24 10:23:23 -04:00
jasonKercher 215b21811e Merge branch 'master' into os2-process-linux 2024-07-24 10:14:59 -04:00
jason 95a8a4e7f0 typo - inverted logic 2024-07-24 10:12:16 -04:00
jason ecdd3887b2 fix process_info assumptions 2024-07-24 10:09:50 -04:00
gingerBill 2dbccbde54 Improve win32 types 2024-07-24 14:53:48 +01:00
gingerBill 07b1819dc8 Improve os2.read_directory 2024-07-24 14:53:33 +01:00
gingerBill 9d8953538b Add missing attribute 2024-07-24 14:25:42 +01:00
gingerBill d4af7b86a7 Begin cleaning up os2.read_directory 2024-07-24 14:19:30 +01:00
gingerBill 38e983cac6 Remove dead code 2024-07-24 13:47:57 +01:00
gingerBill 2ddaae45f3 Better handling of allocators 2024-07-24 13:47:22 +01:00
jason 16bdc6d240 use more iterators; global "has pidfd open" state is now thread-safe 2024-07-24 08:43:22 -04:00
gingerBill 6d2487a692 Add some more Ntdll calls 2024-07-24 13:38:14 +01:00
gingerBill c407e423d9 Add inode to os2.Stat 2024-07-24 13:37:56 +01:00
gingerBill 0e91c8368c Add allocator parameters to fmt.caprint* 2024-07-24 09:01:41 +01:00
gingerBill f08a53015c Merge pull request #3972 from laytan/testing-json-report
testing: add json reporting
2024-07-24 08:35:37 +01:00
Emir c98bb7da39 Update README.md 2024-07-24 10:33:34 +03:00
Emir ba81a81ca8 Update os_sdl2.odin 2024-07-24 10:29:34 +03:00
Emir 57dc6c2e94 Update os_sdl2.odin 2024-07-24 10:27:22 +03:00
Emir 95412df129 Add newline to glue_darwin.odin 2024-07-24 10:27:00 +03:00
Emir 2a2bedc85c Fix indentation and add full example 2024-07-24 10:22:18 +03:00
Laytan Laats f6488383d7 fix instrumentation features on LLVM versions with typed pointers
Fixes #3970
2024-07-24 02:43:53 +02:00
jason 0455e4b60f remove unused constants; fix comment 2024-07-23 19:48:18 -04:00
Laytan Laats 545fbc54c7 testing: add json reporting 2024-07-24 01:33:22 +02:00
jason 82deaa59ad os2 linux: fix order of operations bug in _open; fix process_info routine 2024-07-23 17:50:30 -04:00
jason 3c7d1f35db os2 process implementation for linux 2024-07-23 16:50:00 -04:00
Emir f9ef951b22 Add sdl2glue/glue_linux.odin 2024-07-23 22:39:50 +03:00
Laytan Laats fc2e31fcd0 fix build comment in os_freestanding 2024-07-23 20:51:00 +02:00
Emir e8e51db9ff Update glue.odin 2024-07-23 20:42:26 +03:00
Emir a429603195 Remove unused variable from example 2024-07-23 20:39:09 +03:00
Emir 42833d0471 Merge branch 'odin-lang:master' into master 2024-07-23 20:38:04 +03:00
Emir f3f08a4b47 Add sdl2glue to vendor:wgpu package + triangle example 2024-07-23 20:37:26 +03:00
gingerBill efa8c92bab Implement init_long_path_support 2024-07-23 17:46:22 +01:00
gingerBill 65fec9134e Use SHFileOperationW for remove_all on Windows 2024-07-23 17:30:42 +01:00
gingerBill a28392852a Mock out os2.remove_all for Windows 2024-07-23 17:05:41 +01:00
gingerBill 8037ace873 Begin work on os2/dir.odin 2024-07-23 16:47:49 +01:00
gingerBill 182454a1c0 Minor clean ups 2024-07-23 16:09:15 +01:00
gingerBill 24f9e2bbeb Begin mocking out the linux stuff on os2 2024-07-23 16:06:14 +01:00
gingerBill 61b9a5dbb2 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-23 15:57:23 +01:00
gingerBill 0403626acf Add utility calls to os2 2024-07-23 15:57:17 +01:00
Laytan 6fc3d32d4b Merge pull request #3967 from thetarnav/remove-space
Remove space in indentation
2024-07-23 13:58:50 +02:00
Damian Tarnawski eb4f850b7f Remove space in indentation 2024-07-23 13:48:03 +02:00
Jeroen van Rijn da80c51195 Merge pull request #3966 from KyleNBurke/sys-windows-add-type
Add `NCCALCSIZE_PARAMS` to `sys/windows`
2024-07-23 07:45:44 +02:00
Kyle Burke 9d99f98194 Remove semicolon 2024-07-23 00:22:19 -05:00
Kyle Burke c32e12c3f5 Add NCCALCSIZE_PARAMS to sys/windows 2024-07-23 00:09:50 -05:00
Laytan c5fb72340a Merge pull request #3963 from andreas-jonsson/andreas-jonsson-patch-1
Use pkgsrc llvm for NetBSD CI
2024-07-23 04:20:54 +02:00
gingerBill b0fe777ede Propagate rodata a bit more in lb_const_value 2024-07-23 03:01:09 +01:00
gingerBill bc5b41938e Fix #3964 2024-07-23 02:40:51 +01:00
gingerBill 527c0b3202 Change lib for lz4 2024-07-23 00:19:42 +01:00
gingerBill 6eb28aeafc Check to see if people are return a slice of a local fixed array from a procedure 2024-07-22 22:52:10 +01:00
gingerBill 12b971746c vendor:compress/lz4
Bindings to lz4 library
2024-07-22 22:42:29 +01:00
gingerBill ef84382f23 Add suggestion for #3961 2024-07-22 20:11:23 +01:00
Feoramund b8f3d0fb53 Add core:text/regex to examples/all 2024-07-22 15:07:13 -04:00
Feoramund be38ba6c5e Add benchmarks for core:text/regex 2024-07-22 15:07:13 -04:00
Feoramund 3e49ceb82a Add tests for core:text/regex 2024-07-22 15:07:13 -04:00
Feoramund 730e10bd6f Support printing Regular_Expression in fmt 2024-07-22 14:25:12 -04:00
Feoramund cb0704d51c Add core:text/regex 2024-07-22 14:25:12 -04:00
Jeroen van Rijn 9cad8179b7 Clarify core:time Unix timestamp 2024-07-22 20:00:25 +02:00
Jeroen van Rijn ccf8b2764d Create README.md 2024-07-22 18:00:57 +02:00
gingerBill 915c5c3a87 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-22 16:29:35 +01:00
gingerBill fcaa47986a Improve error handling for invalid syntax doing [*]T 2024-07-22 16:29:29 +01:00
Jeroen van Rijn 07d2aba310 Simplify exe path check. 2024-07-22 16:36:21 +02:00
Jeroen van Rijn 4889641af4 Merge pull request #3959 from Kelimion/fix-output-is-directory-check
Fix .exe path is directory check.
2024-07-22 16:22:17 +02:00
Jeroen van Rijn 90a4d12b30 Fix .exe path is directory check. 2024-07-22 16:11:33 +02:00
Jeroen van Rijn a39b6de18c Merge pull request #3958 from Kelimion/fix-3473
Fix #3473
2024-07-22 15:41:39 +02:00
Jeroen van Rijn 39657e4d96 Fix #3473
Fix the problem where the initial package's directory name ended in .odin.
2024-07-22 15:15:51 +02:00
Laytan 73a9a97413 Merge pull request #3476 from PucklaJ/syscall-fix
[sys/linux] Fix fork and execve syscalls on arm64
2024-07-22 13:58:17 +02:00
PucklaJ 1873f7215d [sys/linux]: Change execveat flags type to Execveat_Flags 2024-07-22 11:03:25 +02:00
Laytan Laats 4d86012d96 install lua for new lua vendor tests 2024-07-22 01:13:50 +02:00
Laytan Laats a055c03de9 use #directory in lua test 2024-07-22 01:11:01 +02:00
Laytan 68550cf915 Merge pull request #3957 from laytan/fix-any_base-and-any_core
fix `reflect.any_base` and `reflect.any_core` with any's containing nil
2024-07-22 01:09:38 +02:00
Laytan Laats 3e618bed40 fix reflect.any_base and reflect.any_core with any's containing nil 2024-07-22 00:51:38 +02:00
Jeroen van Rijn 51733fce68 Merge pull request #3952 from Ronaldr1985/master
Ensure that values in ini map are unquoted
2024-07-21 14:58:15 +02:00
Jeroen van Rijn a056e9da81 Merge pull request #3954 from flysand7/docs-thread
[thread]: Document all functions in core:thread
2024-07-21 14:10:49 +02:00
flysand7 b84b4c47d7 [thread]: Document all functions in core:thread 2024-07-21 14:34:36 +11:00
Jeroen van Rijn 431227d4c5 Add NULL check in check_range_stmt
Fixes #3953
2024-07-21 02:52:53 +02:00
Ronald 1a6885c2a3 Tidy up code 2024-07-21 00:08:20 +01:00
Ronald c3a57853e2 Ensure that values in ini map are unquoted 2024-07-21 00:00:47 +01:00
Jeroen van Rijn fc5ce30f34 Allow json to unmarshal empty struct. 2024-07-21 00:37:11 +02:00
Jeroen van Rijn 572b400d8e Merge pull request #3950 from Ronaldr1985/master
Add tests for encoding/ini
2024-07-20 18:47:08 +02:00
Jeroen van Rijn f78a792d48 Add Lua example to vendor\lua as well as basic tests. 2024-07-20 18:30:41 +02:00
Ronald e0a8bd04d5 Ensure deletion of maybe is delayed until we're finished with it. 2024-07-20 17:10:34 +01:00
Ronald f560b14d10 Fix typo in name of test 2024-07-20 17:10:19 +01:00
Ronald b584eeaade Add encoding/ini tests 2024-07-20 16:53:54 +01:00
Jeroen van Rijn cdd2c98b8d Merge pull request #3948 from flysand7/docs-time
[time]: Document all functions
2024-07-20 16:06:07 +02:00
Jeroen van Rijn 9d6ed991cb Remove LUA panic for non-big-3 OS 2024-07-20 14:33:34 +02:00
Jeroen van Rijn 2385e1ddd9 Update LUA imports for Darwin. 2024-07-20 14:24:01 +02:00
flysand7 b3ca2d5e0a [time]: Document all functions 2024-07-20 18:48:50 +11:00
Jeroen van Rijn 64614889de Merge pull request #3946 from flysand7/x11-fixes
[vendor/x11]: Fix missing argument in XDefaultDepth, wrong types in CreateSimpleWindow
2024-07-20 04:00:00 +02:00
Jeroen van Rijn d9d044970e Merge pull request #3945 from flysand7/docs-datetime
[time/datetime]: Document package datetime
2024-07-20 03:56:21 +02:00
flysand7 0c78cab336 [time/datetime]: Document package datetime 2024-07-20 12:49:40 +11:00
flysand7 15997d2a90 [vendor/x11]: Fix missing argument in XDefaultDepth, wrong types in CreateSimpleWindow 2024-07-20 12:47:00 +11:00
Jeroen van Rijn 7237f9c9f8 Help text default -o:none -> -o:minimal. 2024-07-19 20:47:26 +02:00
gingerBill ba3d7ba5d3 Add core:encoding/ini to examples/all 2024-07-19 12:03:34 +01:00
gingerBill f226eba342 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-19 12:00:54 +01:00
gingerBill 393ca40c23 Minor clean ups 2024-07-19 12:00:49 +01:00
gingerBill 62f455f47b Merge branch 'master' into syscall-fix 2024-07-19 11:43:56 +01:00
gingerBill 163287d9ce Merge pull request #3938 from Ronaldr1985/master
Fix memory leak in encoding/ini
2024-07-19 11:42:35 +01:00
gingerBill 2f8399fe20 Merge pull request #3940 from flysand7/os2-handle-inheritance
[os2] Make all handles non-inheritable by default
2024-07-19 11:38:03 +01:00
gingerBill 685dbddcb5 Merge pull request #3939 from flysand7/os2-file-type
[os2]: Split file type from mode bits et other small fixes
2024-07-19 11:37:54 +01:00
Laytan Laats 27f9f0ba17 fix OLS #431, #393 2024-07-18 21:06:37 +02:00
Laytan Laats 2b6a926bb6 fix OLS #52 2024-07-18 21:06:37 +02:00
Laytan b3d798cb76 Merge pull request #3941 from laytan/wgpu-wayland-improvements
improve WGPU / GLFW / Wayland story by weak linking and adjusting docs
2024-07-18 20:20:01 +02:00
Laytan 7134015f56 improve WGPU / GLFW / Wayland story by weak linking and adjusting docs 2024-07-18 19:28:15 +02:00
flysand7 7b501b22bb [os2]: Split file type from mode bits 2024-07-18 23:09:27 +11:00
flysand7 75605a47e7 [os2]: Make anonymous pipes always inheritable 2024-07-18 22:57:30 +11:00
flysand7 4dcb75af6d Make all handles non-inheritable by default
The sockets are left as non-inheritable because they
never should be inherited.
2024-07-18 22:50:47 +11:00
Ronald c768d0719a Remove unnecessary change
This was accidentally added, it was a change I made whilst testing.
2024-07-17 21:57:35 +01:00
Ronald f04db7145c Fix memory leak in encoding/ini
A simple change that fixes a memory leak caused by not deleting all the
values in the map
2024-07-17 21:19:14 +01:00
gingerBill 0bb4cc6ce5 Merge pull request #3935 from IllusionMan1212/win32-drag-n-drop
core/sys/windows: added drag and drop procedures
2024-07-16 23:41:52 +01:00
IllusionMan1212 07121f81ff core/sys/windows: added drag and drop procedures 2024-07-17 00:32:25 +02:00
Jeroen van Rijn 5520b45457 Add glfw LICENSE file 2024-07-16 22:59:32 +02:00
Laytan cb16d2ddaf Merge pull request #3934 from laytan/fix-saturating-intrinsics
fix `add_sat` and `sub_sat` intrinsics
2024-07-16 22:30:06 +02:00
Laytan Laats a6d1a2e46c add #optional_ok to docs file for intrinsics 2024-07-16 22:22:06 +02:00
Laytan Laats 47f14dd9ea type is never a tuple here 2024-07-16 22:11:54 +02:00
Laytan Laats 853487e86c fix add_sat and sub_sat intrinsics 2024-07-16 22:07:49 +02:00
gingerBill 0d881e1561 Improve rand.shuffle further by splitting into 64-bit and 32-bit parts 2024-07-16 18:36:31 +01:00
gingerBill ba49950454 Improve rand.shuffle 2024-07-16 18:33:01 +01:00
gingerBill f66133959f Merge pull request #3933 from laytan/fix-some-bugs-with-disable-assert
fix some bugs with -disable-assert
2024-07-16 17:54:21 +01:00
Laytan Laats 28fac62a02 fix some bugs with -disable-assert 2024-07-16 18:44:18 +02:00
gingerBill a3fe5754d9 Make complex32 use higher precision where possible for calculations 2024-07-16 15:31:00 +01:00
gingerBill df56655ab1 Fix formatting inconsistencies 2024-07-16 14:03:02 +01:00
gingerBill 6702f07762 rawptr -> cstring 2024-07-16 14:02:07 +01:00
gingerBill 03e90bf924 Use RTTI to get the error_string for Windows 2024-07-16 12:26:24 +01:00
gingerBill 8d70a264ab Check for specific error directly 2024-07-16 12:21:55 +01:00
gingerBill fe718460c6 Clean up bit_set usage 2024-07-16 12:17:48 +01:00
gingerBill 1afb10109e Remove the need for temporary variables where possible 2024-07-16 12:13:39 +01:00
gingerBill 3a162de18f More clean up for process_windows.odin 2024-07-16 12:08:59 +01:00
gingerBill 321ef82d76 Add @(require_results) where needed 2024-07-16 11:57:22 +01:00
gingerBill 169fc4d3be General clean up of the os2/process_windows.odin code 2024-07-16 11:56:31 +01:00
gingerBill affe8f7144 Merge pull request #3310 from flysand7/core-process
Addition of `core:os2/process` api.
2024-07-16 11:24:24 +01:00
gingerBill 23ca27f40b Add intrinsics add_sat and sub_sat 2024-07-16 00:48:17 +01:00
Laytan Laats 03426175ae add workaround for kernel panics on MacOS 2024-07-15 22:45:16 +02:00
Jeroen van Rijn 0a9c150748 Merge pull request #3929 from laytan/fix-fmt-len-transfer-to-children
fmt: fix optional_len or use_nul_termination being used by both array and elems
2024-07-15 19:36:20 +02:00
Laytan Laats f362e0fa20 add test for leaking struct tag into elems 2024-07-15 19:27:48 +02:00
Laytan Laats d4d910bcfc fmt: fix optional_len or use_nul_termination being used by both array and elems
```odin
My_Struct :: struct {
	names:      [^]string `fmt:"v,name_count"`,
	name_count: int,
}

main :: proc() {
	name := "hello?"
	foo := My_Struct {
		names = &name,
		name_count = 1,
	}
	fmt.println(foo)
}
```

Before: `My_Struct{names = ["h"], name_count = 1}`
After:  `My_Struct{names = ["hello?"], name_count = 1}`
2024-07-15 18:51:18 +02:00
Jeroen van Rijn 3a75a8dd1b Merge pull request #3928 from Yawning/feature/aes-ni
core/crypto: Support AES-NI + PCLMUL
2024-07-15 18:41:21 +02:00
Yawning Angel 33dae2e26c core/crypto/aes: Support the full range of GCM nonce sizes 2024-07-16 01:29:43 +09:00
Yawning Angel 69026852ce core/crypto/aes: Add Intel AES-NI support
This supports AES-NI + PCLMUL, and provides optimized key schedule, ECB,
CTR, and GCM.  Other modes are trivial to add later if required.
2024-07-16 01:29:43 +09:00
Yawning Angel f578994fa6 core/simd/x86: Make the AES-NI intrinsics consistent with Intel 2024-07-16 01:29:43 +09:00
Yawning Angel 1bc21c3481 core/crypto/_aes: Remove redundant sanity checks 2024-07-16 01:29:43 +09:00
Yawning Angel c9c0b9ea7b core/crypto: Fix/add some documentation (NFC) 2024-07-16 01:29:43 +09:00
Yawning Angel 390cd3c30d core/simd/x86: Fix some intrinsics
- _mm_slli_si128 produced totally incorrect output
- _mm_storeu_si128 refered to a LLVM intrinsic that is missing
2024-07-16 01:29:43 +09:00
Yawning Angel 401877184f tests/benchmark/crypto: Benchmark AES256-CTR 2024-07-16 01:29:43 +09:00
Yawning Angel 4815154c31 test/core/crypto: Fix a copy-paste issue in failure spew 2024-07-16 01:29:43 +09:00
Yawning Angel 0d8dadec8a tests/core/crypto: Fix new -vet issues 2024-07-16 01:29:43 +09:00
Yawning Angel ff13ee3281 core/crypto: Enforce aliasing restrictions 2024-07-16 01:29:43 +09:00
Yawning Angel dcaf085bfa core/bytes: Add alias and alias_inexactly 2024-07-16 01:29:43 +09:00
Laytan Laats 55e0f97cc4 help fmt with Type_Info_Struct and Type_Info_Bit_Field changes 2024-07-15 18:29:06 +02:00
gingerBill 65c91b7dde Fix code gen issue with bit_set 2024-07-15 15:16:23 +01:00
gingerBill bd562116b8 Minor change to an internal flag 2024-07-15 15:08:26 +01:00
gingerBill 1e37eaf54d Begin work for bit_set[...; [N]T] (not working) 2024-07-15 14:49:20 +01:00
flysand7 8df61b7209 [os2/process]: Make get_args() private and use heap_allocator 2024-07-15 23:28:03 +11:00
Yawning Angel 1a30d47ee8 repo: Cleanup the .gitignore to match the new test runner 2024-07-15 21:25:07 +09:00
gingerBill 5cefab8229 Fix case: in type switch issue 2024-07-15 13:22:50 +01:00
gingerBill 7d643bcae3 Make linkage weak in certain places 2024-07-15 12:30:32 +01:00
gingerBill 549311fac9 Fix global variables being "missing" with -use-separate-modules 2024-07-15 12:21:42 +01:00
gingerBill c5decd3eae Fix possible race and correct linkage _after_ generation 2024-07-15 11:49:07 +01:00
flysand7 255f00d971 [os2/process]: Implement missing functionality, update docs 2024-07-15 20:24:05 +11:00
gingerBill 664a71454b -use-separate-modules default on Windows only 2024-07-15 02:53:01 +01:00
gingerBill 432388ac7f Generate backing array in the case where there is no DeclInfo for the procedure body 2024-07-15 02:42:28 +01:00
gingerBill cc3cf12ae2 Disable -use-separate-modules by default on darwin until problem is determined 2024-07-15 02:28:27 +01:00
gingerBill d87583bead Minimize mutex lock for #load_directory 2024-07-15 02:22:23 +01:00
gingerBill 1b0e98116d Revert changes to in_single_threaded_checker_stage 2024-07-15 01:47:52 +01:00
gingerBill eb6805ef40 Disable the need for mutexes in single threaded checker stage 2024-07-15 01:44:23 +01:00
gingerBill a45e05bb18 Remove need for BlockingMutex in Arena 2024-07-15 01:36:54 +01:00
gingerBill e4ba786948 Remove use of mutex in single threaded code 2024-07-15 01:29:57 +01:00
gingerBill cae8c1e94f Minimize use of mutex in Arena 2024-07-15 01:15:00 +01:00
gingerBill a8f84c87ae Add the permanent and temporary arenas directly on the Thread 2024-07-15 01:05:29 +01:00
gingerBill c64702ae5a Make -use-separate-modules the default behaviour for -o:none and -o:minimal 2024-07-15 00:43:46 +01:00
gingerBill 3311ea1c76 Keep MSVC happy with secure versions of C calls 2024-07-15 00:38:10 +01:00
gingerBill 018026d844 Use gb_zero_* calls 2024-07-15 00:36:00 +01:00
gingerBill 139c1bcdda Comment out debug code 2024-07-15 00:25:41 +01:00
gingerBill 46817e8f68 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-15 00:01:31 +01:00
gingerBill 196ac7e6d6 Type erase _make_dynamic_array_len_cap 2024-07-15 00:01:26 +01:00
Jeroen van Rijn e3e31b42d0 #force_no_inline build_huffman to avoid bloat 2024-07-15 00:54:08 +02:00
gingerBill f7cb711874 Add #force_no_inline 2024-07-14 23:48:33 +01:00
gingerBill f657055f12 Add slice variable if not exists 2024-07-14 23:36:54 +01:00
gingerBill 26a9416a41 Minor clean ups 2024-07-14 23:33:35 +01:00
gingerBill e768bddaeb Inline _append_elem_string further 2024-07-14 23:22:22 +01:00
gingerBill 83b7dd122a Type erase for append_elems 2024-07-14 23:20:50 +01:00
gingerBill b0fbaf24a0 Type erase append_elem 2024-07-14 23:16:11 +01:00
gingerBill 1c3240b6b5 Add #force_no_inline 2024-07-14 23:09:58 +01:00
gingerBill 7673d478b6 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-14 23:09:17 +01:00
gingerBill 15fb4ded2a type erase resize and reserve internals 2024-07-14 23:09:10 +01:00
Jeroen van Rijn 03cb585845 Merge pull request #3908 from NicknEma/Intrusive-list-docs
Write docs for `core:container/intrusive/list` package
2024-07-14 23:28:53 +02:00
gingerBill 9d84e00502 Clean up unquote code 2024-07-14 22:25:26 +01:00
gingerBill 7703b37a1b Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-14 22:23:52 +01:00
gingerBill 95a695e4cd Fix #3926 2024-07-14 22:23:46 +01:00
gingerBill 02408b713a Merge pull request #3910 from VladPavliuk/json-add-int-key-map-support
Allow to `marshal` and `unmarshal` maps with int keys
2024-07-14 22:00:01 +01:00
gingerBill 251fa477af Fix type 2024-07-14 21:39:33 +01:00
gingerBill 15a0655988 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-14 21:37:41 +01:00
gingerBill 399c3ab067 Reduce the size of runtime.Type_Info 2024-07-14 21:37:35 +01:00
flysand7 b7ccfed9af [os2/process]: Implement process_kill 2024-07-15 07:27:44 +11:00
flysand7 4eca60946c [os2/process]: Refactor process_info procs, add process_info_by_handle 2024-07-15 07:27:44 +11:00
flysand7 8f4755532e [os2/process]: Adjust docs on process_close function 2024-07-15 07:27:44 +11:00
flysand7 63d94301fc [os2/process]: Implement process creation procedures 2024-07-15 07:27:43 +11:00
flysand7 e1eed7610c [os2/process]: Fix leaking memory on errors 2024-07-15 07:27:43 +11:00
flysand7 5d6e0bc793 [os2/process]: Implement retrieving command args in process info 2024-07-15 07:27:43 +11:00
flysand7 c1f5d8f006 [os2/process]: Improve documentation for *process_info() family of function 2024-07-15 07:27:43 +11:00
flysand7 f3d4a734d8 [os2/process]: Fix environment block null-terminator counting 2024-07-15 07:27:43 +11:00
flysand7 6387cd2c24 [os2/process] Added process_info() procedure 2024-07-15 07:27:43 +11:00
flysand7 56d55e4a86 Rebase master 2024-07-15 07:27:43 +11:00
flysand7 6fab055f43 [os2/process]: Add process list function 2024-07-15 07:27:43 +11:00
flysand7 2495f1c39a [os2/process]: Fill in basic functions 2024-07-15 07:27:43 +11:00
Jeroen van Rijn 65dab3a3b1 Merge pull request #3925 from Feoramund/fix-no-return-switch
Fix compiler crash when switching on no value
2024-07-14 21:26:46 +02:00
Feoramund b38237e8f0 Fix compiler crash when switching on no value 2024-07-14 14:59:00 -04:00
NicknEma 63276a85ba Fixed grammar and expanded info
Fixed points made by Jeroen.
2024-07-14 18:18:12 +02:00
VladPavliuk 3f8712edb0 Merge branch 'master' into json-add-int-key-map-support 2024-07-14 18:22:20 +03:00
gingerBill e7d37607ef Fix parameter to none 2024-07-14 16:05:47 +01:00
gingerBill 6feace2351 Add pseudo flag -fast-build 2024-07-14 16:05:07 +01:00
gingerBill a867378418 Default to -o:minimal again 2024-07-14 15:55:26 +01:00
gingerBill 11e2aa2d51 Improve error message 2024-07-14 15:31:40 +01:00
gingerBill 556355ef05 Disallow global use of target specific procedure calls 2024-07-14 15:30:40 +01:00
gingerBill 5de6016e7f Clean up os2.File.impl usage 2024-07-14 15:26:59 +01:00
gingerBill 2d56e3805b Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-14 15:09:38 +01:00
gingerBill 4f73b35da5 Make os2.File a more generic interface 2024-07-14 15:09:33 +01:00
Jeroen van Rijn 76b0562acd Merge pull request #3923 from laytan/fix-off-by-one-in-queue-back
Fix off-by-one in queue `back` and `back_ptr` procs
2024-07-14 16:09:16 +02:00
Laytan Laats d90d7ed002 Fix off-by-one in queue back and back_ptr procs 2024-07-14 16:00:55 +02:00
gingerBill 3d38f14202 Use fstat on os2.File directly 2024-07-14 14:51:22 +01:00
gingerBill d1450e3d88 Fix styling issues 2024-07-14 14:44:22 +01:00
gingerBill eff46c2e5f Merge pull request #3919 from colrdavidson/growing_workpool
move to a growing workstealing queue
2024-07-14 14:39:49 +01:00
gingerBill 8319917898 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-14 14:07:42 +01:00
gingerBill 2e0c5fefde Reuse the slice value too for variadic parameters (LLVM >= 13) 2024-07-14 14:07:36 +01:00
Jeroen van Rijn 88823c4024 Merge pull request #3921 from Ronaldr1985/master
Fix logic bug in core/encoding/ini/ini.odin
2024-07-14 14:48:47 +02:00
gingerBill 6959554040 Calculate size and alignment, and reuse memory for all variadic calls within a procedure body 2024-07-14 13:44:47 +01:00
gingerBill 0a530b5ce8 Add error for #no_capture being reserved for future use 2024-07-14 13:20:12 +01:00
gingerBill 8650180ccc Change Odin calling convention to not do a copy on byval for SysV 2024-07-14 12:59:55 +01:00
gingerBill 5027c7081e Reuse slice variable for variadic parameters 2024-07-14 12:50:33 +01:00
gingerBill 3533094cc2 Restrict #no_capture to pointer-like types only 2024-07-14 12:44:13 +01:00
gingerBill 5ce6676914 Make #no_capture map to nocapture 2024-07-14 12:41:16 +01:00
gingerBill 3dff83f3dc Mock out #no_capture for future use 2024-07-14 12:39:30 +01:00
gingerBill 8642d719f0 Imply #no_capture to all variadic parameters 2024-07-14 12:19:47 +01:00
gingerBill 891cf54b5c Add f16 to #c_vararg promotion rules 2024-07-14 12:03:34 +01:00
gingerBill 3ba19d94cf Add #no_capture to core:odin/ast 2024-07-14 11:58:26 +01:00
gingerBill c7bd954752 Add more uses of #no_capture 2024-07-14 11:56:04 +01:00
Ronald 7e4e3429d7 Fix logic bug in core/encoding/ini/ini.odin
The load_map_from_path had incorrect logic where it would return false
for ok when err was equal to nil and true when there was an error.
2024-07-14 11:48:34 +01:00
gingerBill edc793d7c1 Add #no_capture args: ..T to reuse the backing array stack memory 2024-07-14 11:39:05 +01:00
gingerBill f98a7b84df Merge pull request #3914 from VladPavliuk/json-add-ignore-tag-support
Add support of `ignore` tag for `json.marshal`
2024-07-14 10:38:15 +01:00
gingerBill 0050cb9471 Merge pull request #3918 from flysand7/file-handle-inheritance2
[os2/file]: Fixes related to handle inheritance
2024-07-14 10:36:10 +01:00
Colin Davidson 64feb7599e move to isize 2024-07-14 00:33:40 -07:00
Colin Davidson 4420128dc1 handle steal-fail vs steal-empty 2024-07-14 00:29:58 -07:00
Colin Davidson cdede4928c move to a growing queue 2024-07-13 23:16:22 -07:00
flysand7 b686b072d5 [os2/file]: Fixes related to handle inheritance
All file handles created on Windows used to be made
non-inheritable, by forcing the .Close_On_Exec flag
in _open() function. In addition, there was an
issue with security descriptor being freed before
use, which has been fixed.
2024-07-14 15:06:28 +11:00
VladPavliuk 76fe5d1346 Align ignore syntax of json tags with fmt, cbor 2024-07-14 00:21:05 +03:00
gingerBill 8cebc7cc0c Merge pull request #3915 from tadeohepperle/vendor-wgpu-RenderPassEncoderSetPushConstants-signature
vendor/wgpu: RenderPassEncoderSetPushConstants should take a rawptr instead of cstring
2024-07-13 15:16:21 +01:00
Tadeo hepperle 75076e2d64 RenderPassEncoderSetPushConstants should take a rawptr instead of cstring for the data 2024-07-13 16:01:33 +02:00
VladPavliuk 64ae99f016 Add support of ignore tag for json.marshal 2024-07-13 14:13:59 +03:00
Jeroen van Rijn d845a07519 Merge pull request #3912 from xzores/master
Update stb_truetype.odin
2024-07-13 00:16:34 +02:00
xzores b4683f4399 Update stb_truetype.odin 2024-07-12 23:57:45 +02:00
VladPavliuk 79e2f63182 Small code refactoring in test_core_json 2024-07-13 00:38:58 +03:00
VladPavliuk 39983eaaa4 Remove unused imports in test_core_json 2024-07-13 00:26:54 +03:00
VladPavliuk dbdad0476d Allow to marshal and unmarshal maps with int keys 2024-07-13 00:07:48 +03:00
Thomas la Cour 3627a51daf Merge remote-tracking branch 'upstream/master' into sys-windows-2 2024-07-12 16:06:48 +02:00
gingerBill e715674512 Merge pull request #3907 from flysand7/console-read-fix
[core/os]: Fix read_console edge case bug
2024-07-12 14:58:40 +01:00
gingerBill 9e0c4098be Merge pull request #3905 from flysand7/winapi-process-procs
[sys/windows]: Advapi bindings, process-related functions and thread context
2024-07-12 14:58:27 +01:00
NicknEma d10694901f Simplify and fix doc examples
Remove unnecessary examples;
fix compilation errors in the remaining ones
2024-07-12 15:48:47 +02:00
NicknEma c75a872909 Write doc comments in intrusive_list.odin
Write description, inputs/returns and some examples for each procedure
2024-07-12 15:37:34 +02:00
NicknEma a348a7e84e Create doc.odin
Create a doc file with a brief of the package and an example program (copied from a discord message by laytan)
2024-07-12 15:18:58 +02:00
flysand7 a7d95ab3e1 [core/os]: Fix read_console not stopping the read when newline can't fit in output slice 2024-07-12 20:28:38 +11:00
flysand7 6ae47c6f43 [sys/windows] Add advapi bindings, process-related functions and context-related stuff 2024-07-12 19:21:44 +11:00
Thomas la Cour 3291c59728 post rebase 2024-07-11 21:37:37 +02:00
Thomas la Cour dd75b7a4d9 Merge remote-tracking branch 'upstream/master' into sys-windows-2
# Conflicts:
#	core/sys/windows/kernel32.odin
#	core/sys/windows/types.odin
#	core/sys/windows/user32.odin
#	core/sys/windows/winerror.odin
2024-07-11 21:20:53 +02:00
gingerBill 1770e3a9a9 Fix typo 2024-07-11 17:19:12 +01:00
gingerBill 19753ed8a3 Add rand.Generator and other calls 2024-07-11 17:12:42 +01:00
gingerBill 59d87d1f05 Add gen := context.random_generator parameters to rand calls 2024-07-11 17:01:34 +01:00
gingerBill 6b3453cc64 Fix #3902 2024-07-11 13:08:38 +01:00
gingerBill 5e7634d90c Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-11 13:04:32 +01:00
gingerBill fc7c7cd8ab Merge pull request #3900 from Kelimion/winres
Allow precompiled resources with `-resource:foo.res`
2024-07-11 12:51:25 +01:00
gingerBill e05e99253b Merge pull request #3904 from laytan/make-instrumentation-work-on-wasm
make instrumentation "work" on wasm
2024-07-11 12:50:51 +01:00
Jeroen van Rijn a8ce5bd005 Merge pull request #3903 from laytan/allow-mem-virtual-import-on-more-targets
allow `core:mem/virtual` import on more targets by expanding the `other` implementation
2024-07-11 02:12:53 +02:00
Laytan Laats 65ca03a930 make instrumentation "work" on wasm
Using instrumentation on WASM causes it to complain about the
llvm.returnaddress instrinsic. This PR could be considered a "hack" but
makes this work by just passing `nil` instead of the return address.
2024-07-11 01:57:00 +02:00
Laytan Laats 0dfc660c71 allow core:mem/virtual import on more targets by expanding the other implementation 2024-07-11 01:55:59 +02:00
Jeroen van Rijn c49afb0039 Add hinstdll forward to runtime globals 2024-07-10 19:58:29 +02:00
Jeroen van Rijn b02291b20a Compile demo with -vet -strict-style. 2024-07-10 19:26:35 +02:00
gingerBill f75a45c3fa Add aliases starts_with and ends_with 2024-07-10 16:34:15 +01:00
gingerBill 7e41340510 Unify IUnknown COM interface 2024-07-10 15:20:07 +01:00
Jeroen van Rijn 4148c6d6c7 #if WINDOWS 2024-07-10 15:25:49 +02:00
Jeroen van Rijn cc73e06a46 Allow precompiled resources with -resource:foo.res
And add them to the magic new feature.
2024-07-10 15:09:13 +02:00
gingerBill 733b7c704c Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-10 13:45:27 +01:00
gingerBill c54e3d3c4f Improve warning handling for possible default: typo 2024-07-10 13:45:21 +01:00
Jeroen van Rijn 8dc4eca4d2 Allow using precompiled .res file. 2024-07-10 14:25:18 +02:00
gingerBill 34c6868e78 Merge pull request #3895 from laytan/fix-optimization-mode-attribute
remove misleading @(optimization_mode) values and make "none" inhibit optimizations
2024-07-10 13:22:57 +01:00
gingerBill 38315f83da Merge pull request #3898 from laytan/fix-enable-target-features-for-poly-procs
fix require/enable target feature attribute on poly procs
2024-07-10 13:22:06 +01:00
gingerBill 5aa1f3751b Merge pull request #3899 from laytan/fix-more-attributes-not-applied-to-poly-procs
fix optimization mode, cold, and disabled not being applied to poly procs
2024-07-10 13:21:57 +01:00
gingerBill 36301d0359 Give better syntax error messages for things like #define Example 123 2024-07-10 13:03:38 +01:00
gingerBill c83307f26f Give error message suggestion when doing ^x instead of x^ if x is an r-value 2024-07-10 12:39:42 +01:00
gingerBill 30204837ce Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-10 12:28:23 +01:00
gingerBill f85f6b338a Change .. variadic logic; comment out unneeded error message 2024-07-10 12:28:15 +01:00
Laytan Laats 40625b24e2 fix optimization mode, cold, and disabled not being applied to poly procs 2024-07-09 19:49:12 +02:00
Laytan Laats 1fce5791a1 fix require/enable target feature attribute on poly procs 2024-07-09 19:33:25 +02:00
Jeroen van Rijn d43a2daa17 Merge pull request #3897 from Kelimion/simd-vet
Let simd/x86 pass new transmute/cast vet.
2024-07-09 17:04:45 +02:00
Jeroen van Rijn 7b31acd2d7 Let simd/x86 pass new transmute/cast vet. 2024-07-09 16:50:55 +02:00
gingerBill b83822fd35 #3892 - Use temporary directory for asm file generation 2024-07-09 15:41:05 +01:00
gingerBill ae2f16edea Fix #3894 2024-07-09 15:29:36 +01:00
gingerBill 9782d7b928 Merge pull request #3896 from odin-lang/cached-builds
Internal Cached Builds
2024-07-09 15:27:45 +01:00
gingerBill 5627af582a Add RPROMPT to blacklist 2024-07-09 15:18:15 +01:00
gingerBill d701642293 Check for PROMPT 2024-07-09 15:15:23 +01:00
gingerBill 4c1754b1dc environ is only for Linux 2024-07-09 14:56:12 +01:00
gingerBill 666703f430 Mock out \*nix stuff for cached.cpp 2024-07-09 14:47:22 +01:00
gingerBill 14dc3598b4 Add gb_internal to procedures 2024-07-09 14:33:01 +01:00
gingerBill 330d0e7a2a Add debugf calls 2024-07-09 14:30:38 +01:00
gingerBill 952fb998e6 Check for CURR_DATE_TIME 2024-07-09 14:20:55 +01:00
gingerBill 886ee66e7f Cache files, env, and args 2024-07-09 14:16:56 +01:00
gingerBill 68b70a2183 Check for bounds check error 2024-07-09 13:35:52 +01:00
gingerBill ccdad8b8dd Add odin clear-cache 2024-07-09 13:31:54 +01:00
gingerBill 45bf180847 Add subtarget to cached executable 2024-07-08 23:55:01 +01:00
gingerBill 87ac68fcf2 Add -internal-cached 2024-07-08 23:39:14 +01:00
Jeroen van Rijn 9575d85f1a Merge pull request #3511 from IllusionMan1212/x11-xkb
vendor/x11: some XKB extension procedures and constants
2024-07-08 21:14:26 +02:00
Laytan Laats 2d8d0dd851 fix @(optimization_mode) usage in builtin collections 2024-07-08 21:07:53 +02:00
Laytan Laats 1a20b78633 remove misleading @(optimization_mode) values and make "none" inhibit optimizations 2024-07-08 21:06:57 +02:00
IllusionMan1212 0c27d95679 vendor/x11: some XKB extension procedures and constants 2024-07-08 21:00:19 +02:00
gingerBill a3af94eeae Merge pull request #3893 from laytan/temporary-directory-non-windows
implement `temporary_directory` on non-windows
2024-07-08 18:25:34 +01:00
Laytan Laats 9ff77397c6 implement temporary_directory on non-windows 2024-07-08 18:58:17 +02:00
gingerBill 48aef50164 Add #load cache files to -export-dependencies:json 2024-07-08 17:46:10 +01:00
gingerBill fc9c995dc4 Fix fmt for code compilation bug with any 2024-07-08 16:39:13 +01:00
gingerBill 564d5af8b2 Default to -o:none for all builds 2024-07-08 16:12:22 +01:00
gingerBill 2c9ef6907a Clean up timings messages showing used module count 2024-07-08 15:30:33 +01:00
gingerBill 505dec7b14 Merge branch 'master' of https://github.com/odin-lang/Odin 2024-07-08 15:13:45 +01:00
gingerBill 2a219fa830 Correct -use-separate-module behaviour 2024-07-08 15:13:40 +01:00
gingerBill 498fb00c25 Merge pull request #3890 from laytan/llvm-18-non-windows-releases
ci: make releases use LLVM 18
2024-07-08 14:57:21 +01:00
Jeroen van Rijn ec2234560a Merge pull request #3889 from laytan/darwin-remove-implicit-syscall-usage
darwin: remove syscall usage (without -no-crt) to comply to Apple guidelines
2024-07-08 15:54:24 +02:00
Laytan Laats 5dd89a29e6 ci: make releases use LLVM 18
Since we updated to LLVM 18 on Windows now, we should make the releases
for non-windows use LLVM 18 too, this way all releases use the same version.
2024-07-08 15:49:37 +02:00
gingerBill 8491e2491c Experiment with different uses of -use-separate-modules 2024-07-08 14:48:59 +01:00
Laytan Laats ddad2011e2 darwin: remove syscall usage (without -no-crt) to comply to Apple guidelines 2024-07-08 15:39:23 +02:00
gingerBill 7dd4cccce7 Use a temporary directory for -use-separate-modules
Windows only currently
2024-07-08 14:21:07 +01:00
gingerBill 0f664893dd Add sort for global types and procedures 2024-07-08 13:59:25 +01:00
gingerBill 04e0b3e270 Merge pull request #3887 from odin-lang/windows-llvm-18
Update to LLVM 18.1.8 for Windows
2024-07-08 13:25:22 +01:00
gingerBill 930a147f24 Update to LLVM 18.1.8 2024-07-08 13:08:18 +01:00
gingerBill 86c58167ed Add -print-linker-flags 2024-07-08 10:40:04 +01:00
Jeroen van Rijn 212906ecd2 Merge pull request #3886 from laytan/cbor-enhancements
CBOR enhancements
2024-07-08 02:01:39 +02:00
Laytan Laats 6ab559437a encoding/cbor: add a custom tag to the example 2024-07-08 01:01:11 +02:00
Laytan Laats db3b4ceb4a encoding/cbor: improve perf of marshalling array-like types 2024-07-08 00:37:40 +02:00
Laytan Laats 39e9b65c59 encoding/cbor: fix umarshal of big fixed arrays 2024-07-08 00:35:19 +02:00
Laytan Laats 56856b6307 io: remove dead code in io.write_at_least 2024-07-08 00:33:50 +02:00
Jeroen van Rijn 861ad2037f Merge pull request #3884 from Feoramund/fix-3883
Forbid `$T=` parameter from crashing compiler
2024-07-06 22:08:05 +02:00
Feoramund 77d64a5461 Forbid $T= parameter from crashing compiler
Fixes #3883
2024-07-06 15:32:17 -04:00
gingerBill 88c9512d5f Merge pull request #3828 from laytan/re-raise-signals-from-odin-run
re-raise signals from the `odin run` binary
2024-07-06 18:55:37 +01:00
Jeroen van Rijn b79a098c2e Merge pull request #3882 from Kelimion/clean_up_iterator
Remove nil checks.
2024-07-06 18:45:45 +02:00
Jeroen van Rijn 258f120d52 Remove nil checks.
The caller should really not pass `foo: ^string = nil`. A `for ch, in foo` would also crash,
so let's not introduce new semantics for iteration.

A caller shouldn't pass garbage if they can help it, and a `nil` ^string is not a useful ZII usage here.
2024-07-06 18:34:52 +02:00
gingerBill 80d122f531 Merge pull request #3879 from caquillo07/hm/adding-missing-env-calls-to-core-os-darwin
Add Darwin setenv and unsetenv syscalls
2024-07-06 12:55:29 +01:00
gingerBill efe5e9e349 Merge pull request #3858 from flysand7/wow64-apiset
Add bindings for WOW64 API set
2024-07-06 00:23:47 +01:00
Jeroen van Rijn 25904e8f89 Merge pull request #3878 from Poaetce/setsid-returns-pid
[sys/linux]: change setsid to return Pid
2024-07-06 01:21:22 +02:00
Hector Mejia 2b854c94da added the setenv and unsetenv bindings for darwin, inspired but os_linux.odin 2024-07-05 16:26:03 -04:00
poa 8c98ca3a10 updated return value of setsid to return Pid 2024-07-05 22:53:45 +09:00
Jeroen van Rijn ecffe5a082 Merge pull request #3877 from Kelimion/wstring_fix
Fix utf8_to_wstring given zero bytes.
2024-07-05 13:58:49 +02:00
Jeroen van Rijn 9ecc33570b Improve fix. 2024-07-05 13:51:38 +02:00
Jeroen van Rijn 164a5e587e Fix utf8_to_wstring given zero bytes. 2024-07-05 13:46:07 +02:00
Jeroen van Rijn c8432df248 Merge pull request #3874 from laytan/fix-not-detecting-duplicate-proc-case
Fix not detecting duplicate proc cases
2024-07-05 01:00:14 +02:00
Laytan Laats f66b7021a6 Fix not detecting duplicate proc cases
Fixes #3864
2024-07-05 00:50:52 +02:00
Jeroen van Rijn 22fabba2f6 Fix #3873 2024-07-05 00:48:08 +02:00
gingerBill c77f5b00bc Merge pull request #3872 from laytan/fix-assertion-failure-on-old-llvm
Fix assertion false negative
2024-07-04 23:27:11 +01:00
Laytan Laats 1bd9fe04c4 Fix assertion false positive
Assertion was added in #3855 - https://github.com/odin-lang/Odin/pull/3855/commits/723314909679b89e159cb4cb05d250d12ac64436
to mimic LLVM's own internal assertion for this, turns out their
assertion is more sophisticated than an `==` so lets just remove it.

To be clear their internal assertion is not hit while this one is, which
defeats the purpose of ours.
2024-07-04 23:55:21 +02:00
Jeroen van Rijn 3c2161b196 Merge pull request #3870 from laytan/fix-fontstash-proc-group
vendor/fontstash: fix 'AddFont' proc group for JS target
2024-07-04 17:05:49 +02:00
Jeroen van Rijn 5247d3749c Merge pull request #3871 from Kelimion/dynlib_temp
Remove implicit allocator usage in `core:dynlib`
2024-07-04 17:05:21 +02:00
Jeroen van Rijn 8bee73b08e Remove implicit allocator usage in core:dynlib 2024-07-04 16:53:00 +02:00
Laytan Laats bcdb202639 vendor/fontstash: fix 'AddFont' proc group for JS target 2024-07-04 16:50:58 +02:00
gingerBill 1eb0bc1408 Remove *_test.odin; always compile it for all targets 2024-07-04 14:43:57 +01:00
gingerBill e9a54666e2 Fix typo. 2024-07-04 14:41:10 +01:00
gingerBill 8b7c6a23ba Restrict a bit more 2024-07-04 14:06:02 +01:00
gingerBill bf711b282d Remove when check in check_entity_from_ident_or_selector 2024-07-04 13:58:36 +01:00
gingerBill 87bccc8f3f Remove import name cases 2024-07-04 13:53:52 +01:00
gingerBill 657bc88535 Allow x :: y when cond else proc(...){...} 2024-07-04 13:48:52 +01:00
gingerBill 45b2a6a19e Fix reflect.as_pointer 2024-07-04 13:37:47 +01:00
gingerBill d78ff0be52 Fix lb_store_type_case_implicit 2024-07-04 13:20:36 +01:00
gingerBill 52c219690a Ff @(disabled=true), do not add that entity's dependencies to the set 2024-07-04 13:09:31 +01:00
gingerBill 053f1759d7 Merge pull request #3866 from DerTee/test_mem_dynamic_pool
add test for mem.dynamic_pool and fix alignment bug
2024-07-03 22:17:57 +01:00
gingerBill b65aa9c439 Merge pull request #3867 from karl-zylinski/error-on-typeof-untyped-type
error on type_of(value of untyped type)
2024-07-03 22:09:59 +01:00
Karl Zylinski 782286357b error on type_of(value of untyped type) 2024-07-03 22:21:32 +02:00
DerTee 6b373cf49e fix #3692 memory alignment bug in core:mem.dynamic_pool_alloc_bytes 2024-07-03 22:14:28 +02:00
DerTee a76f9a70d5 add test for allocator mem.Dynamic_Pool
this test currently fails because of bug #3692
2024-07-03 22:13:20 +02:00
Jeroen van Rijn a276722da5 Merge pull request #3865 from Feoramund/fix-sdl-constants
Fix SDL constants
2024-07-03 21:31:53 +02:00
Feoramund bb6cbf6559 Fix SDL constants 2024-07-03 15:22:39 -04:00
Jeroen van Rijn f6892d2236 Fix help text. 2024-07-03 19:30:25 +02:00
gingerBill 075384b2bb Fix #soa assignment bug 2024-07-03 00:33:13 +01:00
gingerBill 7e6acdf800 Merge pull request #3855 from laytan/master
Fix two LLVM assertion failures
2024-07-02 22:16:49 +01:00
gingerBill 8b49549fd3 Merge pull request #3859 from laytan/wasm-stbtt-object-linking-preopens
wasm: support `vendor:stb/truetype` and `vendor:fontstash`
2024-07-02 22:14:54 +01:00
Jeroen van Rijn 0ceae51223 Merge pull request #3862 from laytan/fix-empty-webgpu-link-errors
vendor/wgpu: fix linker errors with empty project
2024-07-02 23:05:34 +02:00
Laytan Laats 761a50e145 vendor/wgpu: fix linker errors with empty project 2024-07-02 22:37:02 +02:00
Laytan Laats 5399093050 make preopens a slice and remove bad current_dir 2024-07-02 20:17:24 +02:00
Laytan Laats 0ef5191540 use slice.ptr_swap instead of alloca 2024-07-02 20:11:44 +02:00
Laytan Laats 10c68a8951 wasm: support vendor:stb/truetype and vendor:fontstash 2024-07-02 16:03:42 +02:00
Laytan Laats 4e18e1b191 wasi: make os.open work with absolute paths 2024-07-02 15:29:24 +02:00
Laytan Laats 6f1cc8071c wasm: add foreign import and linking of wasm object files 2024-07-02 15:28:08 +02:00
flysand7 41282b5211 Add bindings for WOW64 API set 2024-07-02 21:56:04 +11:00
Jeroen van Rijn 0697fd0101 Merge pull request #3857 from flysand7/tlhelp-modentry
[sys/windows]: Fix the type declaration for MODULEENTRY32W
2024-07-02 12:42:18 +02:00
flysand7 62d107bea5 [sys/windows]: Fix the type declaration for MODULEENTRY32W 2024-07-02 21:34:54 +11:00
Andreas T Jonsson b26f4e0766 Use pkgsrc llvm for NetBSD CI 2024-07-02 11:43:01 +02:00
Laytan Laats 7233149096 fix llvm assertion failure when const initializer is not the same type 2024-07-02 01:25:52 +02:00
Laytan Laats c822f0b8c8 fix llvm assertion about metadata on non-instruction 2024-07-02 01:14:50 +02:00
Jeroen van Rijn d912c6e320 Merge pull request #3849 from Feoramund/zero-mantissa
Don't factor trailing zeroes into mantissa division
2024-07-01 20:53:07 +02:00
Jeroen van Rijn f7243eac74 Force cl.exe to parse Odin source as utf-8. 2024-07-01 20:48:00 +02:00
Jeroen van Rijn c2ab2bf25a Add UTF-8 BOM for ucg.c, because reasons. 2024-07-01 20:23:48 +02:00
Feoramund 8cd7fd95a3 Don't factor trailing zeroes into mantissa division
This should fix issues where `N00 / (pow+2)` results in a different number
than `N / pow`.
2024-06-30 22:18:25 -04:00
Feoramund 8b915aae5e Update code for new -vet 2024-06-30 11:18:40 -04:00
Feoramund f0cf1052d0 Fix FreeBSD recvfrom
`fromlen` must be a pointer, not a value.
2024-06-30 10:17:32 -04:00
Laytan Laats fa5be93da2 re-raise signals from the odin run binary 2024-06-28 19:33:34 +02:00
Feoramund ba05c74936 Enable core:net tests for FreeBSD 2024-06-26 10:05:24 -04:00
Feoramund e61d893a74 Port core:net to FreeBSD 2024-06-26 10:05:24 -04:00
Feoramund 10ce76fcc2 Fix FreeBSD futex implementation
- Add missing size of timeout struct to `_umtx_op`.
- Use `WAIT_UINT` not `WAIT`, as the expected value is an unsigned integer.
- Use new native calls instead of libc.
2024-06-26 10:02:07 -04:00
Feoramund c61f5bbfe7 Add core:sys/freebsd 2024-06-26 10:02:06 -04:00
Thomas la Cour acce9acb6d Merge remote-tracking branch 'upstream/master' into sys-windows-2 2024-06-13 18:31:53 +02:00
Thomas la Cour 8403952fd2 win32gen 2024-06-11 18:30:41 +02:00
Thomas la Cour 32dcb3caef windows bindings test 2024-06-11 18:19:29 +02:00
Thomas la Cour 465ac74020 more windows stuff 2024-06-11 18:19:16 +02:00
PucklaJ 37b026cb9b [sys/linux] Directly call syscall in execve on arm64 2024-04-28 12:00:40 +02:00
PucklaJ d1a205e2cf [sys/linux]: Remove clone syscall and call it directly in fork on arm64 2024-04-28 11:56:19 +02:00
PucklaJ 7f301790d0 [sys/linux] Change flags parameter of execveat to bit_set 2024-04-28 11:48:18 +02:00
PucklaJ b0fe6212bb [sys/linux]: Fix return statement 2024-04-27 13:21:04 +02:00
PucklaJ a2ad66cd9d [sys/linux]: Add clone syscall and use it in fork for arm64 2024-04-24 15:32:43 +02:00
PucklaJ 2bf00d9b3f [sys/linux]: Add flags parameter to execveat and fix execve on arm64 2024-04-24 15:15:38 +02:00
Beau McCartney 43e8da2e06 shm_open: comment with notes abt permissions 2024-03-19 09:36:49 -06:00
Beau McCartney 1758bd683e sys_shm_open: fchmod the returned descriptor to get correct perms
this doesn't happen by default
2024-03-16 12:13:00 -06:00
Eric Johnson 4b7f32c287 Update mem doc example formatting 2024-03-15 12:26:01 -07:00
Beau McCartney 24f9e16dfd sys_open() calls _sys_open_mode() to get a permission flags integer
_sys_open_mode() does exactly what sys_open() was originally doing
inline, I simply factored it into a separate function so that other
wrappers could call it (similar to _sys_permission_mode())
2024-03-15 08:32:25 -06:00
Beau McCartney 56a29685b4 darwin: sys_shm_open() helper
wraps syscall_shm_open() in the same way that sys_open() wraps
syscall_open()
2024-03-15 08:27:27 -06:00
Beau McCartney cf949e541f helper function to convert Open_Flags bitset to a u32
- analagous to _sys_permission_mode()
- uses the already-existing conversion logic in sys_open()
2024-03-15 08:26:25 -06:00
Beau McCartney 44167800ad darwin: syscall wrappers for shm_open() and shm_unlink() 2024-03-15 08:26:03 -06:00
marcs feh 9c6574e053 Merge branch 'odin-lang:master' into master 2024-02-11 23:55:39 +00:00
marcs feh fc113315f6 Merge branch 'odin-lang:master' into master 2024-02-02 21:56:40 -03:00
marcs-feh d931bfcf83 resolve conflict 2024-01-26 16:23:16 -03:00
marcs-feh b58627490b Adjust signture + Fix rebase conflict 2024-01-26 12:10:15 -03:00
marcs feh dbaa82b581 Merge branch 'odin-lang:master' into master 2024-01-24 20:10:44 -03:00
marcs-feh 84123cc879 sys/linux: Adjust ioctl signature to fit the actual Linux Kernel implementation 2024-01-24 13:40:50 -03:00
marcs-feh 7b1f58a06a sys/linux: Add binding to ioctl syscall + fd consts
Add binding to ioctl syscall, due to the vast nature of this syscall
adding more device specific request values is possible. Also added the
stdin, stdout and stderr, to constants.odin
2024-01-22 16:09:44 -03:00
jakubtomsu fe268a9dd2 Add nullptr check back 2023-11-25 13:29:28 +01:00
jakubtomsu 3c25d93eae Check for variadic param default val 2023-11-25 13:20:34 +01:00
639 changed files with 64198 additions and 9891 deletions
+73 -33
View File
@@ -6,7 +6,7 @@ jobs:
name: NetBSD Build, Check, and Test
runs-on: ubuntu-latest
env:
PKGSRC_BRANCH: 2024Q1
PKGSRC_BRANCH: 2024Q2
steps:
- uses: actions/checkout@v4
- name: Build, Check, and Test
@@ -18,13 +18,11 @@ jobs:
usesh: true
copyback: false
prepare: |
PKG_PATH="https://cdn.NetBSD.org/pub/pkgsrc/packages/NetBSD/$(uname -p)/$(uname -r | cut -d_ -f1)_${PKGSRC_BRANCH}/All" /usr/sbin/pkg_add pkgin
pkgin -y in gmake git bash python311
pkgin -y in libxml2 perl zstd
/usr/sbin/pkg_add https://github.com/andreas-jonsson/llvm17-netbsd-bin/releases/download/pkgsrc-current/llvm-17.0.6.tgz
/usr/sbin/pkg_add https://github.com/andreas-jonsson/llvm17-netbsd-bin/releases/download/pkgsrc-current/clang-17.0.6.tgz
PKG_PATH="https://cdn.NetBSD.org/pub/pkgsrc/packages/NetBSD/amd64/$(uname -r | cut -d_ -f1)_${PKGSRC_BRANCH}/All" /usr/sbin/pkg_add pkgin
pkgin -y in gmake git bash python311 llvm clang
ln -s /usr/pkg/bin/python3.11 /usr/bin/python3
run: |
set -e -x
git config --global --add safe.directory $(pwd)
gmake release
./odin version
@@ -34,10 +32,9 @@ jobs:
gmake -C vendor/miniaudio/src
./odin check examples/all -vet -strict-style -disallow-do -target:netbsd_amd64
./odin check examples/all -vet -strict-style -disallow-do -target:netbsd_arm64
./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false
./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false
./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
./odin test tests/core/speed.odin -file -all-packages -vet -strict-style -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
(cd tests/issues; ./run.sh)
build_freebsd:
name: FreeBSD Build, Check, and Test
@@ -63,10 +60,9 @@ jobs:
gmake -C vendor/cgltf/src
gmake -C vendor/miniaudio/src
./odin check examples/all -vet -strict-style -disallow-do -target:freebsd_amd64
./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false
./odin test tests/core/speed.odin -file -all-packages -o:speed -define:ODIN_TEST_FANCY=false
./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
./odin test tests/core/speed.odin -file -all-packages -vet -strict-style -disallow-do -o:speed -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
(cd tests/issues; ./run.sh)
ci:
strategy:
@@ -91,13 +87,13 @@ jobs:
- name: Download LLVM (MacOS Intel)
if: matrix.os == 'macos-13'
run: |
brew install llvm@17
brew install llvm@17 lua@5.4
echo "/usr/local/opt/llvm@17/bin" >> $GITHUB_PATH
- name: Download LLVM (MacOS ARM)
if: matrix.os == 'macos-14'
run: |
brew install llvm@17 wasmtime
brew install llvm@17 wasmtime lua@5.4
echo "/opt/homebrew/opt/llvm@17/bin" >> $GITHUB_PATH
- name: Build Odin
@@ -120,15 +116,13 @@ jobs:
- name: Odin check examples/all
run: ./odin check examples/all -strict-style
- name: Normal Core library tests
run: ./odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false
run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Optimized Core library tests
run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -define:ODIN_TEST_FANCY=false
run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Vendor library tests
run: ./odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
run: ./odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Internals tests
run: ./odin test tests/internal -all-packages -define:ODIN_TEST_FANCY=false
- name: Core library benchmarks
run: ./odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: GitHub Issue tests
run: |
cd tests/issues
@@ -182,37 +176,33 @@ jobs:
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin run examples/demo -debug
odin run examples/demo -debug -vet -strict-style -disallow-do
- name: Odin check examples/all
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/all -strict-style
odin check examples/all -vet -strict-style -disallow-do
- name: Core library tests
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin test tests/core/normal.odin -file -all-packages -define:ODIN_TEST_FANCY=false
odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Optimized core library tests
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin test tests/core/speed.odin -o:speed -file -all-packages -define:ODIN_TEST_FANCY=false
- name: Core library benchmarks
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin test tests/benchmark -all-packages -define:ODIN_TEST_FANCY=false
odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Vendor library tests
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin test tests/vendor -all-packages -define:ODIN_TEST_FANCY=false
copy vendor\lua\5.4\windows\*.dll .
odin test tests/vendor -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Odin internals tests
shell: cmd
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin test tests/internal -all-packages -define:ODIN_TEST_FANCY=false
odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true
- name: Odin documentation tests
shell: cmd
run: |
@@ -230,3 +220,53 @@ jobs:
run: |
call "C:\Program Files\Microsoft Visual Studio\2022\Enterprise\VC\Auxiliary\Build\vcvars64.bat
odin check examples/all -strict-style -target:windows_i386
build_linux_riscv64:
runs-on: ubuntu-latest
name: Linux riscv64 (emulated) Build, Check and Test
timeout-minutes: 15
steps:
- uses: actions/checkout@v4
- name: Download LLVM (Linux)
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 18
echo "/usr/lib/llvm-18/bin" >> $GITHUB_PATH
- name: Build Odin
run: ./build_odin.sh release
- name: Odin version
run: ./odin version
- name: Odin report
run: ./odin report
- name: Compile needed Vendor
run: |
make -C vendor/stb/src
make -C vendor/cgltf/src
make -C vendor/miniaudio/src
- name: Odin check
run: ./odin check examples/all -target:linux_riscv64 -vet -strict-style -disallow-do
- name: Install riscv64 toolchain and qemu
run: sudo apt-get install -y qemu-user qemu-user-static gcc-12-riscv64-linux-gnu libc6-riscv64-cross
- name: Odin run
run: ./odin run examples/demo -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
- name: Odin run -debug
run: ./odin run examples/demo -debug -vet -strict-style -disallow-do -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
- name: Normal Core library tests
run: ./odin test tests/core/normal.odin -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
- name: Optimized Core library tests
run: ./odin test tests/core/speed.odin -o:speed -file -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
- name: Internals tests
run: ./odin test tests/internal -all-packages -vet -strict-style -disallow-do -define:ODIN_TEST_FANCY=false -define:ODIN_TEST_FAIL_ON_BAD_MEMORY=true -target:linux_riscv64 -extra-linker-flags:"-fuse-ld=/usr/bin/riscv64-linux-gnu-gcc-12 -static -Wl,-static"
+6 -7
View File
@@ -50,8 +50,8 @@ jobs:
run: |
wget https://apt.llvm.org/llvm.sh
chmod +x llvm.sh
sudo ./llvm.sh 17
echo "/usr/lib/llvm-17/bin" >> $GITHUB_PATH
sudo ./llvm.sh 18
echo "/usr/lib/llvm-18/bin" >> $GITHUB_PATH
- name: build odin
run: make nightly
- name: Odin run
@@ -61,7 +61,6 @@ jobs:
mkdir dist
cp odin dist
cp LICENSE dist
cp libLLVM* dist
cp -r shared dist
cp -r base dist
cp -r core dist
@@ -82,8 +81,8 @@ jobs:
- uses: actions/checkout@v4
- name: Download LLVM and setup PATH
run: |
brew install llvm@17 dylibbundler
echo "/usr/local/opt/llvm@17/bin" >> $GITHUB_PATH
brew install llvm@18 dylibbundler
echo "/usr/local/opt/llvm@18/bin" >> $GITHUB_PATH
- name: build odin
# These -L makes the linker prioritize system libraries over LLVM libraries, this is mainly to
# not link with libunwind bundled with LLVM but link with libunwind on the system.
@@ -116,8 +115,8 @@ jobs:
- uses: actions/checkout@v4
- name: Download LLVM and setup PATH
run: |
brew install llvm@17 dylibbundler
echo "/opt/homebrew/opt/llvm@17/bin" >> $GITHUB_PATH
brew install llvm@18 dylibbundler
echo "/opt/homebrew/opt/llvm@18/bin" >> $GITHUB_PATH
- name: build odin
# These -L makes the linker prioritize system libraries over LLVM libraries, this is mainly to
# not link with libunwind bundled with LLVM but link with libunwind on the system.
+1 -34
View File
@@ -17,45 +17,12 @@
[Rr]eleases/
x64/
x86/
!/core/simd/x86
bld/
[Bb]in/
[Oo]bj/
[Ll]og/
![Cc]ore/[Ll]og/
tests/documentation/verify/
tests/documentation/all.odin-doc
tests/internal/test_map
tests/internal/test_pow
tests/internal/test_rtti
tests/core/test_base64
tests/core/test_cbor
tests/core/test_core_compress
tests/core/test_core_container
tests/core/test_core_filepath
tests/core/test_core_fmt
tests/core/test_core_i18n
tests/core/test_core_image
tests/core/test_core_libc
tests/core/test_core_match
tests/core/test_core_math
tests/core/test_core_net
tests/core/test_core_os_exit
tests/core/test_core_reflect
tests/core/test_core_strings
tests/core/test_core_time
tests/core/test_crypto
tests/core/test_hash
tests/core/test_hex
tests/core/test_hxa
tests/core/test_json
tests/core/test_linalg_glsl_math
tests/core/test_noise
tests/core/test_varint
tests/core/test_xml
tests/core/test_core_slice
tests/core/test_core_thread
tests/core/test_core_runtime
tests/vendor/vendor_botan
# Visual Studio 2015 cache/options directory
.vs/
# Visual Studio Code options directory
BIN
View File
Binary file not shown.
+7 -1
View File
@@ -1,4 +1,4 @@
all: debug
all: default
demo:
./odin run examples/demo/demo.odin -file
@@ -6,12 +6,18 @@ demo:
report:
./odin report
default:
PROGRAM=make ./build_odin.sh # debug
debug:
./build_odin.sh debug
release:
./build_odin.sh release
release-native:
./build_odin.sh release-native
release_native:
./build_odin.sh release-native
+2 -2
View File
@@ -76,9 +76,9 @@ Answers to common questions about Odin.
Documentation for all the official packages part of the [core](https://pkg.odin-lang.org/core/) and [vendor](https://pkg.odin-lang.org/vendor/) library collections.
#### [The Odin Wiki](https://github.com/odin-lang/Odin/wiki)
#### [Odin Documentation](https://odin-lang.org/docs/)
A wiki maintained by the Odin community.
Documentation for the Odin language itself.
#### [Odin Discord](https://discord.gg/sVBPHEv)
+39 -17
View File
@@ -38,9 +38,12 @@ count_leading_zeros :: proc(x: $T) -> T where type_is_integer(T) || type_is_sim
reverse_bits :: proc(x: $T) -> T where type_is_integer(T) || type_is_simd_vector(T) ---
byte_swap :: proc(x: $T) -> T where type_is_integer(T) || type_is_float(T) ---
overflow_add :: proc(lhs, rhs: $T) -> (T, bool) ---
overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) ---
overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) ---
overflow_add :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) #optional_ok ---
overflow_sub :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) #optional_ok ---
overflow_mul :: proc(lhs, rhs: $T) -> (T, bool) where type_is_integer(T) #optional_ok ---
saturating_add :: proc(lhs, rhs: $T) -> T where type_is_integer(T) ---
saturating_sub :: proc(lhs, rhs: $T) -> T where type_is_integer(T) ---
sqrt :: proc(x: $T) -> T where type_is_float(T) || (type_is_simd_vector(T) && type_is_float(type_elem_type(T))) ---
@@ -216,14 +219,21 @@ type_map_cell_info :: proc($T: typeid) -> ^runtime.Map_Cell_Info ---
type_convert_variants_to_pointers :: proc($T: typeid) -> typeid where type_is_union(T) ---
type_merge :: proc($U, $V: typeid) -> typeid where type_is_union(U), type_is_union(V) ---
type_has_shared_fields :: proc($U, $V: typeid) -> bool typeid where type_is_struct(U), type_is_struct(V) ---
constant_utf16_cstring :: proc($literal: string) -> [^]u16 ---
constant_log2 :: proc($v: $T) -> T where type_is_integer(T) ---
// SIMD related
simd_add :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_sub :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_mul :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_div :: proc(a, b: #simd[N]T) -> #simd[N]T where type_is_float(T) ---
simd_saturating_add :: proc(a, b: #simd[N]T) -> #simd[N]T where type_is_integer(T) ---
simd_saturating_sub :: proc(a, b: #simd[N]T) -> #simd[N]T where type_is_integer(T) ---
// Keeps Odin's Behaviour
// (x << y) if y <= mask else 0
simd_shl :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T ---
@@ -234,9 +244,6 @@ simd_shr :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T ---
simd_shl_masked :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T ---
simd_shr_masked :: proc(a: #simd[N]T, b: #simd[N]Unsigned_Integer) -> #simd[N]T ---
simd_add_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_sub_sat :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_bit_and :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_bit_or :: proc(a, b: #simd[N]T) -> #simd[N]T ---
simd_bit_xor :: proc(a, b: #simd[N]T) -> #simd[N]T ---
@@ -265,13 +272,28 @@ simd_lanes_ge :: proc(a, b: #simd[N]T) -> #simd[N]Integer ---
simd_extract :: proc(a: #simd[N]T, idx: uint) -> T ---
simd_replace :: proc(a: #simd[N]T, idx: uint, elem: T) -> #simd[N]T ---
simd_reduce_add_ordered :: proc(a: #simd[N]T) -> T ---
simd_reduce_mul_ordered :: proc(a: #simd[N]T) -> T ---
simd_reduce_min :: proc(a: #simd[N]T) -> T ---
simd_reduce_max :: proc(a: #simd[N]T) -> T ---
simd_reduce_and :: proc(a: #simd[N]T) -> T ---
simd_reduce_or :: proc(a: #simd[N]T) -> T ---
simd_reduce_xor :: proc(a: #simd[N]T) -> T ---
simd_reduce_add_ordered :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)---
simd_reduce_mul_ordered :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)---
simd_reduce_min :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)---
simd_reduce_max :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)---
simd_reduce_and :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)---
simd_reduce_or :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)---
simd_reduce_xor :: proc(a: #simd[N]T) -> T where type_is_integer(T) || type_is_float(T)---
simd_reduce_any :: proc(a: #simd[N]T) -> T where type_is_boolean(T) ---
simd_reduce_all :: proc(a: #simd[N]T) -> T where type_is_boolean(T) ---
simd_gather :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) ---
simd_scatter :: proc(ptr: #simd[N]rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) ---
simd_masked_load :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) ---
simd_masked_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) ---
simd_masked_expand_load :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) -> #simd[N]T where type_is_integer(U) || type_is_boolean(U) ---
simd_masked_compress_store :: proc(ptr: rawptr, val: #simd[N]T, mask: #simd[N]U) where type_is_integer(U) || type_is_boolean(U) ---
simd_shuffle :: proc(a, b: #simd[N]T, indices: ..int) -> #simd[len(indices)]T ---
simd_select :: proc(cond: #simd[N]boolean_or_integer, true, false: #simd[N]T) -> #simd[N]T ---
@@ -285,11 +307,11 @@ simd_nearest :: proc(a: #simd[N]any_float) -> #simd[N]any_float ---
simd_to_bits :: proc(v: #simd[N]T) -> #simd[N]Integer where size_of(T) == size_of(Integer), type_is_unsigned(Integer) ---
// equivalent a swizzle with descending indices, e.g. reserve(a, 3, 2, 1, 0)
simd_reverse :: proc(a: #simd[N]T) -> #simd[N]T ---
// equivalent to a swizzle with descending indices, e.g. reserve(a, 3, 2, 1, 0)
simd_lanes_reverse :: proc(a: #simd[N]T) -> #simd[N]T ---
simd_rotate_left :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T ---
simd_rotate_right :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T ---
simd_lanes_rotate_left :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T ---
simd_lanes_rotate_right :: proc(a: #simd[N]T, $offset: int) -> #simd[N]T ---
// Checks if the current target supports the given target features.
//
+69 -23
View File
@@ -66,7 +66,7 @@ Type_Info_Named :: struct {
name: string,
base: ^Type_Info,
pkg: string,
loc: Source_Code_Location,
loc: ^Source_Code_Location,
}
Type_Info_Integer :: struct {signed: bool, endianness: Platform_Endianness}
Type_Info_Rune :: struct {}
@@ -112,23 +112,32 @@ Type_Info_Parameters :: struct { // Only used for procedures parameters and resu
}
Type_Info_Tuple :: Type_Info_Parameters // Will be removed eventually
Type_Info_Struct :: struct {
types: []^Type_Info,
names: []string,
offsets: []uintptr,
usings: []bool,
tags: []string,
is_packed: bool,
is_raw_union: bool,
is_no_copy: bool,
custom_align: bool,
Type_Info_Struct_Flags :: distinct bit_set[Type_Info_Struct_Flag; u8]
Type_Info_Struct_Flag :: enum u8 {
packed = 0,
raw_union = 1,
no_copy = 2,
align = 3,
}
equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
Type_Info_Struct :: struct {
// Slice these with `field_count`
types: [^]^Type_Info `fmt:"v,field_count"`,
names: [^]string `fmt:"v,field_count"`,
offsets: [^]uintptr `fmt:"v,field_count"`,
usings: [^]bool `fmt:"v,field_count"`,
tags: [^]string `fmt:"v,field_count"`,
field_count: i32,
flags: Type_Info_Struct_Flags,
// These are only set iff this structure is an SOA structure
soa_kind: Type_Info_Struct_Soa_Kind,
soa_len: i32,
soa_base_type: ^Type_Info,
soa_len: int,
equal: Equal_Proc, // set only when the struct has .Comparable set but does not have .Simple_Compare set
}
Type_Info_Union :: struct {
variants: []^Type_Info,
@@ -142,9 +151,9 @@ Type_Info_Union :: struct {
shared_nil: bool,
}
Type_Info_Enum :: struct {
base: ^Type_Info,
names: []string,
values: []Type_Info_Enum_Value,
base: ^Type_Info,
names: []string,
values: []Type_Info_Enum_Value,
}
Type_Info_Map :: struct {
key: ^Type_Info,
@@ -187,11 +196,12 @@ Type_Info_Soa_Pointer :: struct {
}
Type_Info_Bit_Field :: struct {
backing_type: ^Type_Info,
names: []string,
types: []^Type_Info,
bit_sizes: []uintptr,
bit_offsets: []uintptr,
tags: []string,
names: [^]string `fmt:"v,field_count"`,
types: [^]^Type_Info `fmt:"v,field_count"`,
bit_sizes: [^]uintptr `fmt:"v,field_count"`,
bit_offsets: [^]uintptr `fmt:"v,field_count"`,
tags: [^]string `fmt:"v,field_count"`,
field_count: int,
}
Type_Info_Flag :: enum u8 {
@@ -299,6 +309,8 @@ when ODIN_OS == .Windows {
Thread_Detach = 3,
}
dll_forward_reason: DLL_Forward_Reason
dll_instance: rawptr
}
// IMPORTANT NOTE(bill): Must be in this order (as the compiler relies upon it)
@@ -513,11 +525,12 @@ Raw_Quaternion256_Vector_Scalar :: struct {vector: [3]f64, scalar: f64}
Linux,
Essence,
FreeBSD,
Haiku,
OpenBSD,
NetBSD,
Haiku,
WASI,
JS,
Orca,
Freestanding,
}
*/
@@ -533,10 +546,23 @@ Odin_OS_Type :: type_of(ODIN_OS)
arm64,
wasm32,
wasm64p32,
riscv64,
}
*/
Odin_Arch_Type :: type_of(ODIN_ARCH)
Odin_Arch_Types :: bit_set[Odin_Arch_Type]
ALL_ODIN_ARCH_TYPES :: Odin_Arch_Types{
.amd64,
.i386,
.arm32,
.arm64,
.wasm32,
.wasm64p32,
.riscv64,
}
/*
// Defined internally by the compiler
Odin_Build_Mode_Type :: enum int {
@@ -560,6 +586,22 @@ Odin_Build_Mode_Type :: type_of(ODIN_BUILD_MODE)
*/
Odin_Endian_Type :: type_of(ODIN_ENDIAN)
Odin_OS_Types :: bit_set[Odin_OS_Type]
ALL_ODIN_OS_TYPES :: Odin_OS_Types{
.Windows,
.Darwin,
.Linux,
.Essence,
.FreeBSD,
.OpenBSD,
.NetBSD,
.Haiku,
.WASI,
.JS,
.Orca,
.Freestanding,
}
/*
// Defined internally by the compiler
@@ -577,7 +619,7 @@ Odin_Platform_Subtarget_Type :: type_of(ODIN_PLATFORM_SUBTARGET)
Memory = 1,
Thread = 2,
}
Odin_Sanitizer_Flags :: distinct bitset[Odin_Sanitizer_Flag; u32]
Odin_Sanitizer_Flags :: distinct bit_set[Odin_Sanitizer_Flag; u32]
ODIN_SANITIZER_FLAGS // is a constant
*/
@@ -737,6 +779,10 @@ __init_context :: proc "contextless" (c: ^Context) {
}
default_assertion_failure_proc :: proc(prefix, message: string, loc: Source_Code_Location) -> ! {
default_assertion_contextless_failure_proc(prefix, message, loc)
}
default_assertion_contextless_failure_proc :: proc "contextless" (prefix, message: string, loc: Source_Code_Location) -> ! {
when ODIN_OS == .Freestanding {
// Do nothing
} else {
+135 -103
View File
@@ -333,17 +333,24 @@ make_dynamic_array_len :: proc($T: typeid/[dynamic]$E, #any_int len: int, alloca
// Note: Prefer using the procedure group `make`.
@(builtin, require_results)
make_dynamic_array_len_cap :: proc($T: typeid/[dynamic]$E, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (array: T, err: Allocator_Error) #optional_allocator_error {
make_dynamic_array_error_loc(loc, len, cap)
array.allocator = allocator // initialize allocator before just in case it fails to allocate any memory
data := mem_alloc_bytes(size_of(E)*cap, align_of(E), allocator, loc) or_return
s := Raw_Dynamic_Array{raw_data(data), len, cap, allocator}
if data == nil && size_of(E) != 0 {
s.len, s.cap = 0, 0
}
array = transmute(T)s
err = _make_dynamic_array_len_cap((^Raw_Dynamic_Array)(&array), size_of(E), align_of(E), len, cap, allocator, loc)
return
}
// `make_map` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
@(require_results)
_make_dynamic_array_len_cap :: proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, #any_int len: int, #any_int cap: int, allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) {
make_dynamic_array_error_loc(loc, len, cap)
array.allocator = allocator // initialize allocator before just in case it fails to allocate any memory
data := mem_alloc_bytes(size_of_elem*cap, align_of_elem, allocator, loc) or_return
use_zero := data == nil && size_of_elem != 0
array.data = raw_data(data)
array.len = 0 if use_zero else len
array.cap = 0 if use_zero else cap
array.allocator = allocator
return
}
// `make_map` allocates and initializes a map. Like `new`, the first argument is a type, not a value.
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
//
// Note: Prefer using the procedure group `make`.
@@ -355,7 +362,7 @@ make_map :: proc($T: typeid/map[$K]$E, #any_int capacity: int = 1<<MAP_MIN_LOG2_
err = reserve_map(&m, capacity, loc)
return
}
// `make_multi_pointer` allocates and initializes a dynamic array. Like `new`, the first argument is a type, not a value.
// `make_multi_pointer` allocates and initializes a multi-pointer. Like `new`, the first argument is a type, not a value.
// Unlike `new`, `make`'s return value is the same as the type of its argument, not a pointer to it.
//
// This is "similar" to doing `raw_data(make([]E, len, allocator))`.
@@ -440,107 +447,103 @@ delete_key :: proc(m: ^$T/map[$K]$V, key: K) -> (deleted_key: K, deleted_value:
return
}
_append_elem :: #force_inline proc(array: ^$T/[dynamic]$E, arg: E, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
_append_elem :: #force_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, arg_ptr: rawptr, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil {
return 0, nil
return
}
when size_of(E) == 0 {
array := (^Raw_Dynamic_Array)(array)
array.len += 1
return 1, nil
} else {
if cap(array) < len(array)+1 {
// Same behavior as _append_elems but there's only one arg, so we always just add DEFAULT_DYNAMIC_ARRAY_CAPACITY.
cap := 2 * cap(array) + DEFAULT_DYNAMIC_ARRAY_CAPACITY
// do not 'or_return' here as it could be a partial success
if should_zero {
err = reserve(array, cap, loc)
} else {
err = non_zero_reserve(array, cap, loc)
}
}
if cap(array)-len(array) > 0 {
a := (^Raw_Dynamic_Array)(array)
when size_of(E) != 0 {
data := ([^]E)(a.data)
assert(data != nil, loc=loc)
data[a.len] = arg
}
a.len += 1
return 1, err
}
return 0, err
if array.cap < array.len+1 {
// Same behavior as _append_elems but there's only one arg, so we always just add DEFAULT_DYNAMIC_ARRAY_CAPACITY.
cap := 2 * array.cap + DEFAULT_DYNAMIC_ARRAY_CAPACITY
// do not 'or_return' here as it could be a partial success
err = _reserve_dynamic_array(array, size_of_elem, align_of_elem, cap, should_zero, loc)
}
if array.cap-array.len > 0 {
data := ([^]byte)(array.data)
assert(data != nil, loc=loc)
data = data[array.len*size_of_elem:]
intrinsics.mem_copy_non_overlapping(data, arg_ptr, size_of_elem)
array.len += 1
n = 1
}
return
}
@builtin
append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elem(array, arg, true, loc=loc)
when size_of(E) == 0 {
(^Raw_Dynamic_Array)(array).len += 1
return 1, nil
} else {
arg := arg
return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, true, loc=loc)
}
}
@builtin
non_zero_append_elem :: proc(array: ^$T/[dynamic]$E, #no_broadcast arg: E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elem(array, arg, false, loc=loc)
when size_of(E) == 0 {
(^Raw_Dynamic_Array)(array).len += 1
return 1, nil
} else {
arg := arg
return _append_elem((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), &arg, false, loc=loc)
}
}
_append_elems :: #force_inline proc(array: ^$T/[dynamic]$E, should_zero: bool, loc := #caller_location, args: ..E) -> (n: int, err: Allocator_Error) #optional_allocator_error {
_append_elems :: #force_inline proc(array: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, should_zero: bool, loc := #caller_location, args: rawptr, arg_len: int) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil {
return 0, nil
}
arg_len := len(args)
if arg_len <= 0 {
return 0, nil
}
when size_of(E) == 0 {
array := (^Raw_Dynamic_Array)(array)
array.len += arg_len
return arg_len, nil
} else {
if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(DEFAULT_DYNAMIC_ARRAY_CAPACITY, arg_len)
if array.cap < array.len+arg_len {
cap := 2 * array.cap + max(DEFAULT_DYNAMIC_ARRAY_CAPACITY, arg_len)
// do not 'or_return' here as it could be a partial success
if should_zero {
err = reserve(array, cap, loc)
} else {
err = non_zero_reserve(array, cap, loc)
}
}
arg_len = min(cap(array)-len(array), arg_len)
if arg_len > 0 {
a := (^Raw_Dynamic_Array)(array)
when size_of(E) != 0 {
data := ([^]E)(a.data)
assert(data != nil, loc=loc)
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len)
}
a.len += arg_len
}
return arg_len, err
// do not 'or_return' here as it could be a partial success
err = _reserve_dynamic_array(array, size_of_elem, align_of_elem, cap, should_zero, loc)
}
arg_len := arg_len
arg_len = min(array.cap-array.len, arg_len)
if arg_len > 0 {
data := ([^]byte)(array.data)
assert(data != nil, loc=loc)
data = data[array.len*size_of_elem:]
intrinsics.mem_copy(data, args, size_of_elem * arg_len) // must be mem_copy (overlapping)
array.len += arg_len
}
return arg_len, err
}
@builtin
append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elems(array, true, loc, ..args)
when size_of(E) == 0 {
a := (^Raw_Dynamic_Array)(array)
a.len += len(args)
return len(args), nil
} else {
return _append_elems((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), true, loc, raw_data(args), len(args))
}
}
@builtin
non_zero_append_elems :: proc(array: ^$T/[dynamic]$E, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
return _append_elems(array, false, loc, ..args)
when size_of(E) == 0 {
a := (^Raw_Dynamic_Array)(array)
a.len += len(args)
return len(args), nil
} else {
return _append_elems((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), false, loc, raw_data(args), len(args))
}
}
// The append_string built-in procedure appends a string to the end of a [dynamic]u8 like type
_append_elem_string :: proc(array: ^$T/[dynamic]$E/u8, arg: $A/string, should_zero: bool, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
args := transmute([]E)arg
if should_zero {
return append_elems(array, ..args, loc=loc)
} else {
return non_zero_append_elems(array, ..args, loc=loc)
}
return _append_elems((^Raw_Dynamic_Array)(array), 1, 1, should_zero, loc, raw_data(arg), len(arg))
}
@builtin
@@ -679,7 +682,7 @@ assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
@builtin
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, #no_broadcast args: ..E, loc := #caller_location) -> (ok: bool, err: Allocator_Error) #no_bounds_check #optional_allocator_error {
new_size := index + len(args)
if len(args) == 0 {
ok = true
@@ -729,11 +732,10 @@ clear_dynamic_array :: proc "contextless" (array: ^$T/[dynamic]$E) {
// `reserve_dynamic_array` will try to reserve memory of a passed dynamic array or map to the requested element count (setting the `cap`).
//
// Note: Prefer the procedure group `reserve`.
_reserve_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
if array == nil {
_reserve_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, capacity: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
if a == nil {
return nil
}
a := (^Raw_Dynamic_Array)(array)
if capacity <= a.cap {
return nil
@@ -744,15 +746,15 @@ _reserve_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, capacity: i
}
assert(a.allocator.procedure != nil)
old_size := a.cap * size_of(E)
new_size := capacity * size_of(E)
old_size := a.cap * size_of_elem
new_size := capacity * size_of_elem
allocator := a.allocator
new_data: []byte
if should_zero {
new_data = mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
new_data = mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
} else {
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
}
if new_data == nil && new_size > 0 {
return .Out_Of_Memory
@@ -765,26 +767,23 @@ _reserve_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, capacity: i
@builtin
reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
return _reserve_dynamic_array(array, capacity, true, loc)
return _reserve_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), capacity, true, loc)
}
@builtin
non_zero_reserve_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int capacity: int, loc := #caller_location) -> Allocator_Error {
return _reserve_dynamic_array(array, capacity, false, loc)
return _reserve_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), capacity, false, loc)
}
// `resize_dynamic_array` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
//
// Note: Prefer the procedure group `resize`
_resize_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
if array == nil {
_resize_dynamic_array :: #force_inline proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, length: int, should_zero: bool, loc := #caller_location) -> Allocator_Error {
if a == nil {
return nil
}
a := (^Raw_Dynamic_Array)(array)
if length <= a.cap {
if should_zero && a.len < length {
intrinsics.mem_zero(([^]E)(a.data)[a.len:], (length-a.len)*size_of(E))
intrinsics.mem_zero(([^]byte)(a.data)[a.len*size_of_elem:], (length-a.len)*size_of_elem)
}
a.len = max(length, 0)
return nil
@@ -795,15 +794,15 @@ _resize_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, length: int,
}
assert(a.allocator.procedure != nil)
old_size := a.cap * size_of(E)
new_size := length * size_of(E)
old_size := a.cap * size_of_elem
new_size := length * size_of_elem
allocator := a.allocator
new_data : []byte
if should_zero {
new_data = mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
new_data = mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
} else {
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of(E), allocator, loc) or_return
new_data = non_zero_mem_resize(a.data, old_size, new_size, align_of_elem, allocator, loc) or_return
}
if new_data == nil && new_size > 0 {
return .Out_Of_Memory
@@ -815,14 +814,17 @@ _resize_dynamic_array :: #force_inline proc(array: ^$T/[dynamic]$E, length: int,
return nil
}
// `resize_dynamic_array` will try to resize memory of a passed dynamic array or map to the requested element count (setting the `len`, and possibly `cap`).
//
// Note: Prefer the procedure group `resize`
@builtin
resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
return _resize_dynamic_array(array, length, true, loc=loc)
return _resize_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), length, true, loc=loc)
}
@builtin
non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: int, loc := #caller_location) -> Allocator_Error {
return _resize_dynamic_array(array, length, false, loc=loc)
return _resize_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), length, false, loc=loc)
}
/*
@@ -837,10 +839,13 @@ non_zero_resize_dynamic_array :: proc(array: ^$T/[dynamic]$E, #any_int length: i
Note: Prefer the procedure group `shrink`
*/
shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
if array == nil {
return _shrink_dynamic_array((^Raw_Dynamic_Array)(array), size_of(E), align_of(E), new_cap, loc)
}
_shrink_dynamic_array :: proc(a: ^Raw_Dynamic_Array, size_of_elem, align_of_elem: int, new_cap := -1, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
if a == nil {
return
}
a := (^Raw_Dynamic_Array)(array)
new_cap := new_cap if new_cap >= 0 else a.len
@@ -853,10 +858,10 @@ shrink_dynamic_array :: proc(array: ^$T/[dynamic]$E, new_cap := -1, loc := #call
}
assert(a.allocator.procedure != nil)
old_size := a.cap * size_of(E)
new_size := new_cap * size_of(E)
old_size := a.cap * size_of_elem
new_size := new_cap * size_of_elem
new_data := mem_resize(a.data, old_size, new_size, align_of(E), a.allocator, loc) or_return
new_data := mem_resize(a.data, old_size, new_size, align_of_elem, a.allocator, loc) or_return
a.data = raw_data(new_data)
a.len = min(new_cap, a.len)
@@ -943,3 +948,30 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! {
}
p("not yet implemented", message, loc)
}
@builtin
@(disabled=ODIN_DISABLE_ASSERT)
assert_contextless :: proc "contextless" (condition: bool, message := "", loc := #caller_location) {
if !condition {
// NOTE(bill): This is wrapped in a procedure call
// to improve performance to make the CPU not
// execute speculatively, making it about an order of
// magnitude faster
@(cold)
internal :: proc "contextless" (message: string, loc: Source_Code_Location) {
default_assertion_contextless_failure_proc("runtime assertion", message, loc)
}
internal(message, loc)
}
}
@builtin
panic_contextless :: proc "contextless" (message: string, loc := #caller_location) -> ! {
default_assertion_contextless_failure_proc("panic", message, loc)
}
@builtin
unimplemented_contextless :: proc "contextless" (message := "", loc := #caller_location) -> ! {
default_assertion_contextless_failure_proc("not yet implemented", message, loc)
}
+1 -1
View File
@@ -352,7 +352,7 @@ non_zero_append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, #no_broadcast args
}
_append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, zero_memory: bool, #no_broadcast args: ..E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
_append_soa_elems :: proc(array: ^$T/#soa[dynamic]$E, zero_memory: bool, #no_broadcast args: []E, loc := #caller_location) -> (n: int, err: Allocator_Error) #optional_allocator_error {
if array == nil {
return
}
+2 -2
View File
@@ -1,8 +1,8 @@
package runtime
nil_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
size, alignment: int,
old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, Allocator_Error) {
switch mode {
case .Alloc, .Alloc_Non_Zeroed:
return nil, .Out_Of_Memory
@@ -129,7 +129,7 @@ arena_alloc :: proc(arena: ^Arena, size, alignment: uint, loc := #caller_locatio
return
}
// `arena_init` will initialize the arena with a usuable block.
// `arena_init` will initialize the arena with a usable block.
// This procedure is not necessary to use the Arena as the default zero as `arena_alloc` will set things up if necessary
@(require_results)
arena_init :: proc(arena: ^Arena, size: uint, backing_allocator: Allocator, loc := #caller_location) -> Allocator_Error {
+6 -6
View File
@@ -577,7 +577,7 @@ map_grow_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Inf
@(require_results)
map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uintptr, loc := #caller_location) -> Allocator_Error {
map_reserve_dynamic :: #force_no_inline proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, new_capacity: uintptr, loc := #caller_location) -> Allocator_Error {
@(require_results)
ceil_log2 :: #force_inline proc "contextless" (x: uintptr) -> uintptr {
z := intrinsics.count_leading_zeros(x)
@@ -641,7 +641,7 @@ map_reserve_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_
@(require_results)
map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
map_shrink_dynamic :: #force_no_inline proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, loc := #caller_location) -> (did_shrink: bool, err: Allocator_Error) {
if m.allocator.procedure == nil {
m.allocator = context.allocator
}
@@ -688,7 +688,7 @@ map_shrink_dynamic :: proc "odin" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_I
}
@(require_results)
map_free_dynamic :: proc "odin" (m: Raw_Map, info: ^Map_Info, loc := #caller_location) -> Allocator_Error {
map_free_dynamic :: #force_no_inline proc "odin" (m: Raw_Map, info: ^Map_Info, loc := #caller_location) -> Allocator_Error {
ptr := rawptr(map_data(m))
size := int(map_total_allocation_size(uintptr(map_cap(m)), info))
err := mem_free_with_size(ptr, size, m.allocator, loc)
@@ -700,7 +700,7 @@ map_free_dynamic :: proc "odin" (m: Raw_Map, info: ^Map_Info, loc := #caller_loc
}
@(require_results)
map_lookup_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (index: uintptr, ok: bool) {
map_lookup_dynamic :: #force_no_inline proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (index: uintptr, ok: bool) {
if map_len(m) == 0 {
return 0, false
}
@@ -723,7 +723,7 @@ map_lookup_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
}
}
@(require_results)
map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (ok: bool) {
map_exists_dynamic :: #force_no_inline proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (ok: bool) {
if map_len(m) == 0 {
return false
}
@@ -749,7 +749,7 @@ map_exists_dynamic :: proc "contextless" (m: Raw_Map, #no_alias info: ^Map_Info,
@(require_results)
map_erase_dynamic :: #force_inline proc "contextless" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (old_k, old_v: uintptr, ok: bool) {
map_erase_dynamic :: #force_no_inline proc "contextless" (#no_alias m: ^Raw_Map, #no_alias info: ^Map_Info, k: uintptr) -> (old_k, old_v: uintptr, ok: bool) {
index := map_lookup_dynamic(m^, info, k) or_return
ks, vs, hs, _, _ := map_kvh_data_dynamic(m^, info)
hs[index] |= TOMBSTONE_MASK
+3
View File
@@ -34,6 +34,9 @@ when ODIN_BUILD_MODE == .Dynamic {
} else when ODIN_OS == .Darwin && ODIN_ARCH == .arm64 {
@require foreign import entry "entry_unix_no_crt_darwin_arm64.asm"
SYS_exit :: 1
} else when ODIN_ARCH == .riscv64 {
@require foreign import entry "entry_unix_no_crt_riscv64.asm"
SYS_exit :: 93
}
@(link_name="_start_odin", linkage="strong", require)
_start_odin :: proc "c" (argc: i32, argv: [^]cstring) -> ! {
@@ -0,0 +1,10 @@
.text
.globl _start
_start:
ld a0, 0(sp)
addi a1, sp, 8
addi sp, sp, ~15
call _start_odin
ebreak
+2 -1
View File
@@ -10,8 +10,9 @@ when ODIN_BUILD_MODE == .Dynamic {
DllMain :: proc "system" (hinstDLL: rawptr, fdwReason: u32, lpReserved: rawptr) -> b32 {
context = default_context()
// Populate Windows DLL-specific global
// Populate Windows DLL-specific globals
dll_forward_reason = DLL_Forward_Reason(fdwReason)
dll_instance = hinstDLL
switch dll_forward_reason {
case .Process_Attach:
+15 -8
View File
@@ -19,12 +19,15 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
// the pointer we return to the user.
//
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil, zero_memory := true) -> ([]byte, Allocator_Error) {
aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr, old_size: int, zero_memory := true) -> ([]byte, Allocator_Error) {
a := max(alignment, align_of(rawptr))
space := size + a - 1
allocated_mem: rawptr
if old_ptr != nil {
force_copy := old_ptr != nil && a > align_of(rawptr)
if !force_copy && old_ptr != nil {
original_old_ptr := ([^]rawptr)(old_ptr)[-1]
allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
} else {
@@ -36,12 +39,19 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
diff := int(aligned_ptr - ptr)
if (size + diff) > space || allocated_mem == nil {
aligned_free(old_ptr)
aligned_free(allocated_mem)
return nil, .Out_Of_Memory
}
aligned_mem = rawptr(aligned_ptr)
([^]rawptr)(aligned_mem)[-1] = allocated_mem
if force_copy {
mem_copy_non_overlapping(aligned_mem, old_ptr, old_size)
aligned_free(old_ptr)
}
return byte_slice(aligned_mem, size), nil
}
@@ -53,10 +63,10 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int, zero_memory := true) -> (new_memory: []byte, err: Allocator_Error) {
if p == nil {
return nil, nil
return aligned_alloc(new_size, new_alignment, nil, old_size, zero_memory)
}
new_memory = aligned_alloc(new_size, new_alignment, p, zero_memory) or_return
new_memory = aligned_alloc(new_size, new_alignment, p, old_size, zero_memory) or_return
// NOTE: heap_resize does not zero the new memory, so we do it
if zero_memory && new_size > old_size {
@@ -68,7 +78,7 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
switch mode {
case .Alloc, .Alloc_Non_Zeroed:
return aligned_alloc(size, alignment, nil, mode == .Alloc)
return aligned_alloc(size, alignment, nil, 0, mode == .Alloc)
case .Free:
aligned_free(old_memory)
@@ -77,9 +87,6 @@ heap_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
return nil, .Mode_Not_Implemented
case .Resize, .Resize_Non_Zeroed:
if old_memory == nil {
return aligned_alloc(size, alignment, nil, mode == .Resize)
}
return aligned_resize(old_memory, old_size, size, alignment, mode == .Resize)
case .Query_Features:
+24 -15
View File
@@ -8,10 +8,9 @@ IS_WASM :: ODIN_ARCH == .wasm32 || ODIN_ARCH == .wasm64p32
@(private)
RUNTIME_LINKAGE :: "strong" when (
(ODIN_USE_SEPARATE_MODULES ||
ODIN_USE_SEPARATE_MODULES ||
ODIN_BUILD_MODE == .Dynamic ||
!ODIN_NO_CRT) &&
!IS_WASM) else "internal"
!ODIN_NO_CRT) else "internal"
RUNTIME_REQUIRE :: false // !ODIN_TILDE
@(private)
@@ -879,9 +878,6 @@ extendhfsf2 :: proc "c" (value: __float16) -> f32 {
@(link_name="__floattidf", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
floattidf :: proc "c" (a: i128) -> f64 {
when IS_WASM {
return 0
} else {
DBL_MANT_DIG :: 53
if a == 0 {
return 0.0
@@ -921,14 +917,10 @@ when IS_WASM {
fb[0] = u32(a) // mantissa-low
return transmute(f64)fb
}
}
@(link_name="__floattidf_unsigned", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
floattidf_unsigned :: proc "c" (a: u128) -> f64 {
when IS_WASM {
return 0
} else {
DBL_MANT_DIG :: 53
if a == 0 {
return 0.0
@@ -966,7 +958,6 @@ when IS_WASM {
fb[0] = u32(a) // mantissa-low
return transmute(f64)fb
}
}
@@ -1023,14 +1014,32 @@ modti3 :: proc "c" (a, b: i128) -> i128 {
@(link_name="__divmodti4", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
divmodti4 :: proc "c" (a, b: i128, rem: ^i128) -> i128 {
u := udivmod128(u128(a), u128(b), (^u128)(rem))
return i128(u)
s_a := a >> (128 - 1) // -1 if negative or 0
s_b := b >> (128 - 1)
an := (a ~ s_a) - s_a // absolute
bn := (b ~ s_b) - s_b
s_b ~= s_a // quotient sign
u_s_b := u128(s_b)
u_s_a := u128(s_a)
r: u128 = ---
u := i128((udivmodti4(u128(an), u128(bn), &r) ~ u_s_b) - u_s_b) // negate if negative
rem^ = i128((r ~ u_s_a) - u_s_a)
return u
}
@(link_name="__divti3", linkage=RUNTIME_LINKAGE, require=RUNTIME_REQUIRE)
divti3 :: proc "c" (a, b: i128) -> i128 {
u := udivmodti4(u128(a), u128(b), nil)
return i128(u)
s_a := a >> (128 - 1) // -1 if negative or 0
s_b := b >> (128 - 1)
an := (a ~ s_a) - s_a // absolute
bn := (b ~ s_b) - s_b
s_a ~= s_b // quotient sign
u_s_a := u128(s_a)
return i128((udivmodti4(u128(an), u128(bn), nil) ~ u_s_a) - u_s_a) // negate if negative
}
+18 -5
View File
@@ -5,11 +5,24 @@ package runtime
import "base:intrinsics"
_stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
WRITE :: 0x2000004
STDERR :: 2
ret := intrinsics.syscall(WRITE, STDERR, uintptr(raw_data(data)), uintptr(len(data)))
if ret < 0 {
return 0, _OS_Errno(-ret)
when ODIN_NO_CRT {
WRITE :: 0x2000004
ret := intrinsics.syscall(WRITE, STDERR, uintptr(raw_data(data)), uintptr(len(data)))
if ret < 0 {
return 0, _OS_Errno(-ret)
}
return int(ret), 0
} else {
foreign {
write :: proc(handle: i32, buffer: [^]byte, count: uint) -> int ---
__error :: proc() -> ^i32 ---
}
if ret := write(STDERR, raw_data(data), len(data)); ret >= 0 {
return int(ret), 0
}
return 0, _OS_Errno(__error()^)
}
return int(ret), 0
}
+2
View File
@@ -12,6 +12,8 @@ _stderr_write :: proc "contextless" (data: []byte) -> (int, _OS_Errno) {
SYS_write :: uintptr(4)
} else when ODIN_ARCH == .arm32 {
SYS_write :: uintptr(4)
} else when ODIN_ARCH == .riscv64 {
SYS_write :: uintptr(64)
}
stderr :: 2
+7 -6
View File
@@ -262,7 +262,7 @@ print_typeid :: #force_no_inline proc "contextless" (id: typeid) {
}
}
@(optimization_mode="size")
@(optimization_mode="favor_size")
print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
if ti == nil {
print_string("nil")
@@ -401,15 +401,16 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
}
print_string("struct ")
if info.is_packed { print_string("#packed ") }
if info.is_raw_union { print_string("#raw_union ") }
if info.custom_align {
if .packed in info.flags { print_string("#packed ") }
if .raw_union in info.flags { print_string("#raw_union ") }
if .no_copy in info.flags { print_string("#no_copy ") }
if .align in info.flags {
print_string("#align(")
print_u64(u64(ti.align))
print_string(") ")
}
print_byte('{')
for name, i in info.names {
for name, i in info.names[:info.field_count] {
if i > 0 { print_string(", ") }
print_string(name)
print_string(": ")
@@ -469,7 +470,7 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
print_string("bit_field ")
print_type(info.backing_type)
print_string(" {")
for name, i in info.names {
for name, i in info.names[:info.field_count] {
if i > 0 { print_string(", ") }
print_string(name)
print_string(": ")
+21
View File
@@ -52,3 +52,24 @@ udivti3 :: proc "c" (la, ha, lb, hb: u64) -> u128 {
b.lo, b.hi = lb, hb
return udivmodti4(a.all, b.all, nil)
}
@(link_name="__lshrti3", linkage="strong")
__lshrti3 :: proc "c" (la, ha: u64, b: u32) -> i128 {
bits :: size_of(u32)*8
input, result: ti_int
input.lo = la
input.hi = ha
if b & bits != 0 {
result.hi = 0
result.lo = input.hi >> (b - bits)
} else if b == 0 {
return input.all
} else {
result.hi = input.hi >> b
result.lo = (input.hi << (bits - b)) | (input.lo >> b)
}
return result.all
}
+34
View File
@@ -0,0 +1,34 @@
package runtime
Thread_Local_Cleaner :: #type proc "odin" ()
@(private="file")
thread_local_cleaners: [8]Thread_Local_Cleaner
// Add a procedure that will be run at the end of a thread for the purpose of
// deallocating state marked as `thread_local`.
//
// Intended to be called in an `init` procedure of a package with
// dynamically-allocated memory that is stored in `thread_local` variables.
add_thread_local_cleaner :: proc "contextless" (p: Thread_Local_Cleaner) {
for &v in thread_local_cleaners {
if v == nil {
v = p
return
}
}
panic_contextless("There are no more thread-local cleaner slots available.")
}
// Run all of the thread-local cleaner procedures.
//
// Intended to be called by the internals of a threading API at the end of a
// thread's lifetime.
run_thread_local_cleaners :: proc "odin" () {
for p in thread_local_cleaners {
if p == nil {
break
}
p()
}
}
+2 -1
View File
@@ -297,7 +297,8 @@ lock :: proc(a: ^WASM_Allocator) {
return
}
assert(intrinsics.wasm_memory_atomic_wait32((^u32)(&a.mu), u32(new_state), -1) != 0)
ret := intrinsics.wasm_memory_atomic_wait32((^u32)(&a.mu), u32(new_state), -1)
assert(ret != 0)
intrinsics.cpu_relax()
}
}
Binary file not shown.
Binary file not shown.
+7 -1
View File
@@ -48,6 +48,9 @@ if "%2" == "1" (
set odin_version_raw="dev-%curr_year%-%curr_month%"
set compiler_flags= -nologo -Oi -TP -fp:precise -Gm- -MP -FC -EHsc- -GR- -GF
rem Parse source code as utf-8 even on shift-jis and other codepages
rem See https://learn.microsoft.com/en-us/cpp/build/reference/utf-8-set-source-and-executable-character-sets-to-utf-8?view=msvc-170
set compiler_flags= %compiler_flags% /utf-8
set compiler_defines= -DODIN_VERSION_RAW=\"%odin_version_raw%\"
if not exist .git\ goto skip_git_hash
@@ -111,7 +114,10 @@ call build_vendor.bat
if %errorlevel% neq 0 goto end_of_build
rem If the demo doesn't run for you and your CPU is more than a decade old, try -microarch:native
if %release_mode% EQU 0 odin run examples/demo -- Hellope World
if %release_mode% EQU 0 odin run examples/demo -vet -strict-style -- Hellope World
rem Many non-compiler devs seem to run debug build but don't realize.
if %release_mode% EQU 0 echo: & echo Debug compiler built. Note: run "build.bat release" if you want a faster, release mode compiler.
del *.obj > NUL 2> NUL
+15 -2
View File
@@ -23,6 +23,14 @@ error() {
exit 1
}
# Brew advises people not to add llvm to their $PATH, so try and use brew to find it.
if [ -z "$LLVM_CONFIG" ] && [ -n "$(command -v brew)" ]; then
if [ -n "$(command -v $(brew --prefix llvm@18)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@18)/bin/llvm-config"
elif [ -n "$(command -v $(brew --prefix llvm@17)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@17)/bin/llvm-config"
elif [ -n "$(command -v $(brew --prefix llvm@14)/bin/llvm-config)" ]; then LLVM_CONFIG="$(brew --prefix llvm@14)/bin/llvm-config"
fi
fi
if [ -z "$LLVM_CONFIG" ]; then
# darwin, linux, openbsd
if [ -n "$(command -v llvm-config-18)" ]; then LLVM_CONFIG="llvm-config-18"
@@ -95,7 +103,7 @@ Linux)
LDFLAGS="$LDFLAGS -ldl $($LLVM_CONFIG --libs core native --system-libs --libfiles)"
# Copy libLLVM*.so into current directory for linking
# NOTE: This is needed by the Linux release pipeline!
cp $(readlink -f $($LLVM_CONFIG --libfiles)) ./
# cp $(readlink -f $($LLVM_CONFIG --libfiles)) ./
LDFLAGS="$LDFLAGS -Wl,-rpath=\$ORIGIN"
;;
OpenBSD)
@@ -144,12 +152,17 @@ build_odin() {
}
run_demo() {
./odin run examples/demo/demo.odin -file -- Hellope World
if [ $# -eq 0 ] || [ "$1" = "debug" ]; then
./odin run examples/demo -vet -strict-style -- Hellope World
fi
}
if [ $# -eq 0 ]; then
build_odin debug
run_demo
: ${PROGRAM:=$0}
printf "\nDebug compiler built. Note: run \"$PROGRAM release\" or \"$PROGRAM release-native\" if you want a faster, release mode compiler.\n"
elif [ $# -eq 1 ]; then
case $1 in
report)
+33 -3
View File
@@ -144,6 +144,9 @@ buffer_grow :: proc(b: ^Buffer, n: int, loc := #caller_location) {
}
buffer_write_at :: proc(b: ^Buffer, p: []byte, offset: int, loc := #caller_location) -> (n: int, err: io.Error) {
if len(p) == 0 {
return 0, nil
}
b.last_read = .Invalid
if offset < 0 {
err = .Invalid_Offset
@@ -246,10 +249,13 @@ buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.
}
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
if len(p) == 0 {
return 0, nil
}
b.last_read = .Invalid
if uint(offset) >= len(b.buf) {
err = .Invalid_Offset
err = .EOF
return
}
n = copy(p, b.buf[offset:])
@@ -310,6 +316,27 @@ buffer_unread_rune :: proc(b: ^Buffer) -> io.Error {
return nil
}
buffer_seek :: proc(b: ^Buffer, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
abs: i64
switch whence {
case .Start:
abs = offset
case .Current:
abs = i64(b.off) + offset
case .End:
abs = i64(len(b.buf)) + offset
case:
return 0, .Invalid_Whence
}
abs_int := int(abs)
if abs_int < 0 {
return 0, .Invalid_Offset
}
b.last_read = .Invalid
b.off = abs_int
return abs, nil
}
buffer_read_bytes :: proc(b: ^Buffer, delim: byte) -> (line: []byte, err: io.Error) {
i := index_byte(b.buf[b.off:], delim)
@@ -395,14 +422,17 @@ _buffer_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offse
return io._i64_err(buffer_write(b, p))
case .Write_At:
return io._i64_err(buffer_write_at(b, p, int(offset)))
case .Seek:
n, err = buffer_seek(b, offset, whence)
return
case .Size:
n = i64(buffer_capacity(b))
n = i64(buffer_length(b))
return
case .Destroy:
buffer_destroy(b)
return
case .Query:
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Size, .Destroy})
return io.query_utility({.Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Destroy, .Query})
}
return 0, .Empty
}
+311 -6
View File
@@ -1,9 +1,38 @@
package bytes
import "base:intrinsics"
import "core:mem"
import "core:simd"
import "core:unicode"
import "core:unicode/utf8"
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
@(private)
SCANNER_INDICES_256 : simd.u8x32 : {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23,
24, 25, 26, 27, 28, 29, 30, 31,
}
@(private)
SCANNER_SENTINEL_MAX_256: simd.u8x32 : u8(0x00)
@(private)
SCANNER_SENTINEL_MIN_256: simd.u8x32 : u8(0xff)
@(private)
SIMD_REG_SIZE_256 :: 32
}
@(private)
SCANNER_INDICES_128 : simd.u8x16 : {
0, 1, 2, 3, 4, 5, 6, 7,
8, 9, 10, 11, 12, 13, 14, 15,
}
@(private)
SCANNER_SENTINEL_MAX_128: simd.u8x16 : u8(0x00)
@(private)
SCANNER_SENTINEL_MIN_128: simd.u8x16 : u8(0xff)
@(private)
SIMD_REG_SIZE_128 :: 16
clone :: proc(s: []byte, allocator := context.allocator, loc := #caller_location) -> []byte {
c := make([]byte, len(s), allocator, loc)
copy(c, s)
@@ -293,28 +322,279 @@ split_after_iterator :: proc(s: ^[]byte, sep: []byte) -> ([]byte, bool) {
return _split_iterator(s, sep, len(sep))
}
/*
Scan a slice of bytes for a specific byte.
index_byte :: proc(s: []byte, c: byte) -> int {
for i := 0; i < len(s); i += 1 {
This procedure safely handles slices of any length, including empty slices.
Inputs:
- data: A slice of bytes.
- c: The byte to search for.
Returns:
- index: The index of the byte `c`, or -1 if it was not found.
*/
index_byte :: proc(s: []byte, c: byte) -> (index: int) #no_bounds_check {
i, l := 0, len(s)
// Guard against small strings. On modern systems, it is ALWAYS
// worth vectorizing assuming there is a hardware vector unit, and
// the data size is large enough.
if l < SIMD_REG_SIZE_128 {
for /**/; i < l; i += 1 {
if s[i] == c {
return i
}
}
return -1
}
c_vec: simd.u8x16 = c
when !simd.IS_EMULATED {
// Note: While this is something that could also logically take
// advantage of AVX512, the various downclocking and power
// consumption related woes make premature to have a dedicated
// code path.
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
c_vec_256: simd.u8x32 = c
s_vecs: [4]simd.u8x32 = ---
c_vecs: [4]simd.u8x32 = ---
m_vec: [4]u8 = ---
// Scan 128-byte chunks, using 256-bit SIMD.
for nr_blocks := l / (4 * SIMD_REG_SIZE_256); nr_blocks > 0; nr_blocks -= 1 {
#unroll for j in 0..<4 {
s_vecs[j] = intrinsics.unaligned_load(cast(^simd.u8x32)raw_data(s[i+j*SIMD_REG_SIZE_256:]))
c_vecs[j] = simd.lanes_eq(s_vecs[j], c_vec_256)
m_vec[j] = simd.reduce_or(c_vecs[j])
}
if m_vec[0] | m_vec[1] | m_vec[2] | m_vec[3] > 0 {
#unroll for j in 0..<4 {
if m_vec[j] > 0 {
sel := simd.select(c_vecs[j], SCANNER_INDICES_256, SCANNER_SENTINEL_MIN_256)
off := simd.reduce_min(sel)
return i + j * SIMD_REG_SIZE_256 + int(off)
}
}
}
i += 4 * SIMD_REG_SIZE_256
}
// Scan 64-byte chunks, using 256-bit SIMD.
for nr_blocks := (l - i) / (2 * SIMD_REG_SIZE_256); nr_blocks > 0; nr_blocks -= 1 {
#unroll for j in 0..<2 {
s_vecs[j] = intrinsics.unaligned_load(cast(^simd.u8x32)raw_data(s[i+j*SIMD_REG_SIZE_256:]))
c_vecs[j] = simd.lanes_eq(s_vecs[j], c_vec_256)
m_vec[j] = simd.reduce_or(c_vecs[j])
}
if m_vec[0] | m_vec[1] > 0 {
#unroll for j in 0..<2 {
if m_vec[j] > 0 {
sel := simd.select(c_vecs[j], SCANNER_INDICES_256, SCANNER_SENTINEL_MIN_256)
off := simd.reduce_min(sel)
return i + j * SIMD_REG_SIZE_256 + int(off)
}
}
}
i += 2 * SIMD_REG_SIZE_256
}
} else {
s_vecs: [4]simd.u8x16 = ---
c_vecs: [4]simd.u8x16 = ---
m_vecs: [4]u8 = ---
// Scan 64-byte chunks, using 128-bit SIMD.
for nr_blocks := l / (4 * SIMD_REG_SIZE_128); nr_blocks > 0; nr_blocks -= 1 {
#unroll for j in 0..<4 {
s_vecs[j]= intrinsics.unaligned_load(cast(^simd.u8x16)raw_data(s[i+j*SIMD_REG_SIZE_128:]))
c_vecs[j] = simd.lanes_eq(s_vecs[j], c_vec)
m_vecs[j] = simd.reduce_or(c_vecs[j])
}
if m_vecs[0] | m_vecs[1] | m_vecs[2] | m_vecs[3] > 0 {
#unroll for j in 0..<4 {
if m_vecs[j] > 0 {
sel := simd.select(c_vecs[j], SCANNER_INDICES_128, SCANNER_SENTINEL_MIN_128)
off := simd.reduce_min(sel)
return i + j * SIMD_REG_SIZE_128 + int(off)
}
}
}
i += 4 * SIMD_REG_SIZE_128
}
}
}
// Scan the remaining SIMD register sized chunks.
//
// Apparently LLVM does ok with 128-bit SWAR, so this path is also taken
// on potato targets. Scanning more at a time when LLVM is emulating SIMD
// likely does not buy much, as all that does is increase GP register
// pressure.
for nr_blocks := (l - i) / SIMD_REG_SIZE_128; nr_blocks > 0; nr_blocks -= 1 {
s0 := intrinsics.unaligned_load(cast(^simd.u8x16)raw_data(s[i:]))
c0 := simd.lanes_eq(s0, c_vec)
if simd.reduce_or(c0) > 0 {
sel := simd.select(c0, SCANNER_INDICES_128, SCANNER_SENTINEL_MIN_128)
off := simd.reduce_min(sel)
return i + int(off)
}
i += SIMD_REG_SIZE_128
}
// Scan serially for the remainder.
for /**/; i < l; i += 1 {
if s[i] == c {
return i
}
}
return -1
}
// Returns -1 if c is not present
last_index_byte :: proc(s: []byte, c: byte) -> int {
for i := len(s)-1; i >= 0; i -= 1 {
/*
Scan a slice of bytes for a specific byte, starting from the end and working
backwards to the start.
This procedure safely handles slices of any length, including empty slices.
Inputs:
- data: A slice of bytes.
- c: The byte to search for.
Returns:
- index: The index of the byte `c`, or -1 if it was not found.
*/
last_index_byte :: proc(s: []byte, c: byte) -> int #no_bounds_check {
i := len(s)
// Guard against small strings. On modern systems, it is ALWAYS
// worth vectorizing assuming there is a hardware vector unit, and
// the data size is large enough.
if i < SIMD_REG_SIZE_128 {
if i > 0 { // Handle s == nil.
for /**/; i >= 0; i -= 1 {
if s[i] == c {
return i
}
}
}
return -1
}
c_vec: simd.u8x16 = c
when !simd.IS_EMULATED {
// Note: While this is something that could also logically take
// advantage of AVX512, the various downclocking and power
// consumption related woes make premature to have a dedicated
// code path.
when ODIN_ARCH == .amd64 && intrinsics.has_target_feature("avx2") {
c_vec_256: simd.u8x32 = c
s_vecs: [4]simd.u8x32 = ---
c_vecs: [4]simd.u8x32 = ---
m_vec: [4]u8 = ---
// Scan 128-byte chunks, using 256-bit SIMD.
for i >= 4 * SIMD_REG_SIZE_256 {
i -= 4 * SIMD_REG_SIZE_256
#unroll for j in 0..<4 {
s_vecs[j] = intrinsics.unaligned_load(cast(^simd.u8x32)raw_data(s[i+j*SIMD_REG_SIZE_256:]))
c_vecs[j] = simd.lanes_eq(s_vecs[j], c_vec_256)
m_vec[j] = simd.reduce_or(c_vecs[j])
}
if m_vec[0] | m_vec[1] | m_vec[2] | m_vec[3] > 0 {
#unroll for j in 0..<4 {
if m_vec[3-j] > 0 {
sel := simd.select(c_vecs[3-j], SCANNER_INDICES_256, SCANNER_SENTINEL_MAX_256)
off := simd.reduce_max(sel)
return i + (3-j) * SIMD_REG_SIZE_256 + int(off)
}
}
}
}
// Scan 64-byte chunks, using 256-bit SIMD.
for i >= 2 * SIMD_REG_SIZE_256 {
i -= 2 * SIMD_REG_SIZE_256
#unroll for j in 0..<2 {
s_vecs[j] = intrinsics.unaligned_load(cast(^simd.u8x32)raw_data(s[i+j*SIMD_REG_SIZE_256:]))
c_vecs[j] = simd.lanes_eq(s_vecs[j], c_vec_256)
m_vec[j] = simd.reduce_or(c_vecs[j])
}
if m_vec[0] | m_vec[1] > 0 {
#unroll for j in 0..<2 {
if m_vec[1-j] > 0 {
sel := simd.select(c_vecs[1-j], SCANNER_INDICES_256, SCANNER_SENTINEL_MAX_256)
off := simd.reduce_max(sel)
return i + (1-j) * SIMD_REG_SIZE_256 + int(off)
}
}
}
}
} else {
s_vecs: [4]simd.u8x16 = ---
c_vecs: [4]simd.u8x16 = ---
m_vecs: [4]u8 = ---
// Scan 64-byte chunks, using 128-bit SIMD.
for i >= 4 * SIMD_REG_SIZE_128 {
i -= 4 * SIMD_REG_SIZE_128
#unroll for j in 0..<4 {
s_vecs[j] = intrinsics.unaligned_load(cast(^simd.u8x16)raw_data(s[i+j*SIMD_REG_SIZE_128:]))
c_vecs[j] = simd.lanes_eq(s_vecs[j], c_vec)
m_vecs[j] = simd.reduce_or(c_vecs[j])
}
if m_vecs[0] | m_vecs[1] | m_vecs[2] | m_vecs[3] > 0 {
#unroll for j in 0..<4 {
if m_vecs[3-j] > 0 {
sel := simd.select(c_vecs[3-j], SCANNER_INDICES_128, SCANNER_SENTINEL_MAX_128)
off := simd.reduce_max(sel)
return i + (3-j) * SIMD_REG_SIZE_128 + int(off)
}
}
}
}
}
}
// Scan the remaining SIMD register sized chunks.
//
// Apparently LLVM does ok with 128-bit SWAR, so this path is also taken
// on potato targets. Scanning more at a time when LLVM is emulating SIMD
// likely does not buy much, as all that does is increase GP register
// pressure.
for i >= SIMD_REG_SIZE_128 {
i -= SIMD_REG_SIZE_128
s0 := intrinsics.unaligned_load(cast(^simd.u8x16)raw_data(s[i:]))
c0 := simd.lanes_eq(s0, c_vec)
if simd.reduce_or(c0) > 0 {
sel := simd.select(c0, SCANNER_INDICES_128, SCANNER_SENTINEL_MAX_128)
off := simd.reduce_max(sel)
return i + int(off)
}
}
// Scan serially for the remainder.
for i > 0 {
i -= 1
if s[i] == c {
return i
}
}
return -1
}
@private PRIME_RABIN_KARP :: 16777619
index :: proc(s, substr: []byte) -> int {
@@ -1167,3 +1447,28 @@ fields_proc :: proc(s: []byte, f: proc(rune) -> bool, allocator := context.alloc
return subslices[:]
}
// alias returns true iff a and b have a non-zero length, and any part of
// a overlaps with b.
alias :: proc "contextless" (a, b: []byte) -> bool {
a_len, b_len := len(a), len(b)
if a_len == 0 || b_len == 0 {
return false
}
a_start, b_start := uintptr(raw_data(a)), uintptr(raw_data(b))
a_end, b_end := a_start + uintptr(a_len-1), b_start + uintptr(b_len-1)
return a_start <= b_end && b_start <= a_end
}
// alias_inexactly returns true iff a and b have a non-zero length,
// the base pointer of a and b are NOT equal, and any part of a overlaps
// with b (ie: `alias(a, b)` with an exception that returns false for
// `a == b`, `b = a[:len(a)-69]` and similar conditions).
alias_inexactly :: proc "contextless" (a, b: []byte) -> bool {
if raw_data(a) == raw_data(b) {
return false
}
return alias(a, b)
}
+9 -2
View File
@@ -9,10 +9,11 @@ Reader :: struct {
prev_rune: int, // previous reading index of rune or < 0
}
reader_init :: proc(r: ^Reader, s: []byte) {
reader_init :: proc(r: ^Reader, s: []byte) -> io.Stream {
r.s = s
r.i = 0
r.prev_rune = -1
return reader_to_stream(r)
}
reader_to_stream :: proc(r: ^Reader) -> (s: io.Stream) {
@@ -33,6 +34,9 @@ reader_size :: proc(r: ^Reader) -> i64 {
}
reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
if len(p) == 0 {
return 0, nil
}
if r.i >= i64(len(r.s)) {
return 0, .EOF
}
@@ -42,6 +46,9 @@ reader_read :: proc(r: ^Reader, p: []byte) -> (n: int, err: io.Error) {
return
}
reader_read_at :: proc(r: ^Reader, p: []byte, off: i64) -> (n: int, err: io.Error) {
if len(p) == 0 {
return 0, nil
}
if off < 0 {
return 0, .Invalid_Offset
}
@@ -97,7 +104,6 @@ reader_unread_rune :: proc(r: ^Reader) -> io.Error {
return nil
}
reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.Error) {
r.prev_rune = -1
abs: i64
switch whence {
case .Start:
@@ -114,6 +120,7 @@ reader_seek :: proc(r: ^Reader, offset: i64, whence: io.Seek_From) -> (i64, io.E
return 0, .Invalid_Offset
}
r.i = abs
r.prev_rune = -1
return abs, nil
}
reader_write_to :: proc(r: ^Reader, w: io.Writer) -> (n: i64, err: io.Error) {
+2 -2
View File
@@ -47,8 +47,8 @@ foreign libc {
clogf :: proc(z: complex_float) -> complex_float ---
// 7.3.8 Power and absolute-value functions
cabs :: proc(z: complex_double) -> complex_double ---
cabsf :: proc(z: complex_float) -> complex_float ---
cabs :: proc(z: complex_double) -> double ---
cabsf :: proc(z: complex_float) -> float ---
cpow :: proc(x, y: complex_double) -> complex_double ---
cpowf :: proc(x, y: complex_float) -> complex_float ---
csqrt :: proc(z: complex_double) -> complex_double ---
+1 -1
View File
@@ -102,6 +102,6 @@ when ODIN_OS == .Haiku {
// read the value, or to produce an lvalue such that you can assign a different
// error value to errno. To work around this, just expose it as a function like
// it actually is.
errno :: #force_inline proc() -> ^int {
errno :: #force_inline proc "contextless" () -> ^int {
return _get_errno()
}
+12 -7
View File
@@ -32,24 +32,21 @@ when ODIN_OS == .Windows {
// the RDX register will contain zero and correctly set the flag to disable
// stack unwinding.
@(link_name="_setjmp")
setjmp :: proc(env: ^jmp_buf, hack: rawptr = nil) -> int ---
setjmp :: proc(env: ^jmp_buf, hack: rawptr = nil) -> int ---
}
} else {
@(default_calling_convention="c")
foreign libc {
// 7.13.1 Save calling environment
//
// NOTE(dweiler): C11 requires setjmp be a macro, which means it won't
// necessarily export a symbol named setjmp but rather _setjmp in the case
// of musl, glibc, BSD libc, and msvcrt.
@(link_name="_setjmp")
setjmp :: proc(env: ^jmp_buf) -> int ---
@(link_name=LSETJMP)
setjmp :: proc(env: ^jmp_buf) -> int ---
}
}
@(default_calling_convention="c")
foreign libc {
// 7.13.2 Restore calling environment
@(link_name=LLONGJMP)
longjmp :: proc(env: ^jmp_buf, val: int) -> ! ---
}
@@ -64,3 +61,11 @@ foreign libc {
// The choice of 4096 bytes for storage of this type is more than enough on all
// relevant platforms.
jmp_buf :: struct #align(16) { _: [4096]char, }
when ODIN_OS == .NetBSD {
@(private) LSETJMP :: "__setjmp14"
@(private) LLONGJMP :: "__longjmp14"
} else {
@(private) LSETJMP :: "setjmp"
@(private) LLONGJMP :: "longjmp"
}
+36 -9
View File
@@ -17,6 +17,12 @@ when ODIN_OS == .Windows {
FILE :: struct {}
Whence :: enum int {
SET = SEEK_SET,
CUR = SEEK_CUR,
END = SEEK_END,
}
// MSVCRT compatible.
when ODIN_OS == .Windows {
_IOFBF :: 0x0000
@@ -101,6 +107,8 @@ when ODIN_OS == .OpenBSD || ODIN_OS == .NetBSD {
SEEK_CUR :: 1
SEEK_END :: 2
TMP_MAX :: 308915776
foreign libc {
__sF: [3]FILE
}
@@ -128,6 +136,8 @@ when ODIN_OS == .FreeBSD {
SEEK_CUR :: 1
SEEK_END :: 2
TMP_MAX :: 308915776
foreign libc {
@(link_name="__stderrp") stderr: ^FILE
@(link_name="__stdinp") stdin: ^FILE
@@ -195,10 +205,21 @@ when ODIN_OS == .Haiku {
}
}
when ODIN_OS == .NetBSD {
@(private) LRENAME :: "__posix_rename"
@(private) LFGETPOS :: "__fgetpos50"
@(private) LFSETPOS :: "__fsetpos50"
} else {
@(private) LRENAME :: "rename"
@(private) LFGETPOS :: "fgetpos"
@(private) LFSETPOS :: "fsetpos"
}
@(default_calling_convention="c")
foreign libc {
// 7.21.4 Operations on files
remove :: proc(filename: cstring) -> int ---
@(link_name=LRENAME)
rename :: proc(old, new: cstring) -> int ---
tmpfile :: proc() -> ^FILE ---
tmpnam :: proc(s: [^]char) -> [^]char ---
@@ -240,8 +261,10 @@ foreign libc {
fwrite :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
// 7.21.9 File positioning functions
@(link_name=LFGETPOS)
fgetpos :: proc(stream: ^FILE, pos: ^fpos_t) -> int ---
fseek :: proc(stream: ^FILE, offset: long, whence: int) -> int ---
fseek :: proc(stream: ^FILE, offset: long, whence: Whence) -> int ---
@(link_name=LFSETPOS)
fsetpos :: proc(stream: ^FILE, pos: ^fpos_t) -> int ---
ftell :: proc(stream: ^FILE) -> long ---
rewind :: proc(stream: ^FILE) ---
@@ -288,11 +311,11 @@ to_stream :: proc(file: ^FILE) -> io.Stream {
return 0, unknown_or_eof(file)
}
if fseek(file, long(offset), SEEK_SET) != 0 {
if fseek(file, long(offset), .SET) != 0 {
return 0, unknown_or_eof(file)
}
defer fseek(file, long(curr), SEEK_SET)
defer fseek(file, long(curr), .SET)
n = i64(fread(raw_data(p), size_of(byte), len(p), file))
if n == 0 { err = unknown_or_eof(file) }
@@ -307,17 +330,21 @@ to_stream :: proc(file: ^FILE) -> io.Stream {
return 0, unknown_or_eof(file)
}
if fseek(file, long(offset), SEEK_SET) != 0 {
if fseek(file, long(offset), .SET) != 0 {
return 0, unknown_or_eof(file)
}
defer fseek(file, long(curr), SEEK_SET)
defer fseek(file, long(curr), .SET)
n = i64(fwrite(raw_data(p), size_of(byte), len(p), file))
if n == 0 { err = unknown_or_eof(file) }
case .Seek:
if fseek(file, long(offset), int(whence)) != 0 {
#assert(int(Whence.SET) == int(io.Seek_From.Start))
#assert(int(Whence.CUR) == int(io.Seek_From.Current))
#assert(int(Whence.END) == int(io.Seek_From.End))
if fseek(file, long(offset), Whence(whence)) != 0 {
return 0, unknown_or_eof(file)
}
@@ -326,9 +353,9 @@ to_stream :: proc(file: ^FILE) -> io.Stream {
if curr == -1 {
return 0, unknown_or_eof(file)
}
defer fseek(file, curr, SEEK_SET)
defer fseek(file, curr, .SET)
if fseek(file, 0, SEEK_END) != 0 {
if fseek(file, 0, .END) != 0 {
return 0, unknown_or_eof(file)
}
@@ -341,7 +368,7 @@ to_stream :: proc(file: ^FILE) -> io.Stream {
return 0, .Empty
case .Query:
return io.query_utility({ .Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size })
return io.query_utility({ .Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size, .Query })
}
return
}
+17 -4
View File
@@ -40,10 +40,9 @@ when ODIN_OS == .Linux {
}
when ODIN_OS == .Darwin {
when ODIN_OS == .Darwin || ODIN_OS == .FreeBSD || ODIN_OS == .OpenBSD {
RAND_MAX :: 0x7fffffff
// GLIBC and MUSL only
@(private="file")
@(default_calling_convention="c")
foreign libc {
@@ -55,6 +54,20 @@ when ODIN_OS == .Darwin {
}
}
when ODIN_OS == .NetBSD {
RAND_MAX :: 0x7fffffff
@(private="file")
@(default_calling_convention="c")
foreign libc {
__mb_cur_max: size_t
}
MB_CUR_MAX :: #force_inline proc() -> size_t {
return __mb_cur_max
}
}
// C does not declare what these values should be, as an implementation is free
// to use any two distinct values it wants to indicate success or failure.
// However, nobody actually does and everyone appears to have agreed upon these
@@ -99,7 +112,7 @@ foreign libc {
at_quick_exit :: proc(func: proc "c" ()) -> int ---
exit :: proc(status: int) -> ! ---
_Exit :: proc(status: int) -> ! ---
getenv :: proc(name: cstring) -> [^]char ---
getenv :: proc(name: cstring) -> cstring ---
quick_exit :: proc(status: int) -> ! ---
system :: proc(cmd: cstring) -> int ---
@@ -150,4 +163,4 @@ aligned_free :: #force_inline proc "c" (ptr: rawptr) {
} else {
free(ptr)
}
}
}
+1 -1
View File
@@ -40,7 +40,7 @@ foreign libc {
strtok :: proc(s1: [^]char, s2: cstring) -> [^]char ---
// 7.24.6 Miscellaneous functions
strerror :: proc(errnum: int) -> [^]char ---
strerror :: proc(errnum: int) -> cstring ---
strlen :: proc(s: cstring) -> size_t ---
}
memset :: proc "c" (s: rawptr, c: int, n: size_t) -> rawptr {
+29 -3
View File
@@ -50,30 +50,56 @@ when ODIN_OS == .Linux || ODIN_OS == .FreeBSD || ODIN_OS == .Darwin || ODIN_OS =
foreign libc {
// 7.27.2 Time manipulation functions
clock :: proc() -> clock_t ---
@(link_name=LDIFFTIME)
difftime :: proc(time1, time2: time_t) -> double ---
@(link_name=LMKTIME)
mktime :: proc(timeptr: ^tm) -> time_t ---
@(link_name=LTIME)
time :: proc(timer: ^time_t) -> time_t ---
timespec_get :: proc(ts: ^timespec, base: int) -> int ---
// 7.27.3 Time conversion functions
asctime :: proc(timeptr: ^tm) -> [^]char ---
@(link_name=LCTIME)
ctime :: proc(timer: ^time_t) -> [^]char ---
@(link_name=LGMTIME)
gmtime :: proc(timer: ^time_t) -> ^tm ---
@(link_name=LLOCALTIME)
localtime :: proc(timer: ^time_t) -> ^tm ---
strftime :: proc(s: [^]char, maxsize: size_t, format: cstring, timeptr: ^tm) -> size_t ---
}
when ODIN_OS == .NetBSD {
@(private) LDIFFTIME :: "__difftime50"
@(private) LMKTIME :: "__mktime50"
@(private) LTIME :: "__time50"
@(private) LCTIME :: "__ctime50"
@(private) LGMTIME :: "__gmtime50"
@(private) LLOCALTIME :: "__localtime50"
} else {
@(private) LDIFFTIME :: "difftime"
@(private) LMKTIME :: "mktime"
@(private) LTIME :: "time"
@(private) LCTIME :: "ctime"
@(private) LGMTIME :: "gmtime"
@(private) LLOCALTIME :: "localtime"
}
when ODIN_OS == .OpenBSD {
CLOCKS_PER_SEC :: 100
} else {
CLOCKS_PER_SEC :: 1000000
}
TIME_UTC :: 1
TIME_UTC :: 1
time_t :: distinct i64
time_t :: distinct i64
clock_t :: long
when ODIN_OS == .FreeBSD || ODIN_OS == .NetBSD {
clock_t :: distinct int32_t
} else {
clock_t :: distinct long
}
timespec :: struct {
tv_sec: time_t,
+25 -25
View File
@@ -186,7 +186,7 @@ input_size_from_stream :: proc(z: ^Context_Stream_Input) -> (res: i64, err: Erro
input_size :: proc{input_size_from_memory, input_size_from_stream}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int) -> (res: []u8, err: io.Error) {
#no_bounds_check {
if len(z.input_data) >= size {
@@ -203,7 +203,7 @@ read_slice_from_memory :: #force_inline proc(z: ^Context_Memory_Input, size: int
}
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int) -> (res: []u8, err: io.Error) {
// TODO: REMOVE ALL USE OF context.temp_allocator here
// there is literally no need for it
@@ -214,13 +214,13 @@ read_slice_from_stream :: #force_inline proc(z: ^Context_Stream_Input, size: int
read_slice :: proc{read_slice_from_memory, read_slice_from_stream}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_data :: #force_inline proc(z: ^$C, $T: typeid) -> (res: T, err: io.Error) {
b := read_slice(z, size_of(T)) or_return
return (^T)(&b[0])^, nil
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8, err: io.Error) {
#no_bounds_check {
if len(z.input_data) >= 1 {
@@ -232,7 +232,7 @@ read_u8_from_memory :: #force_inline proc(z: ^Context_Memory_Input) -> (res: u8,
return 0, .EOF
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_u8_from_stream :: #force_inline proc(z: ^Context_Stream_Input) -> (res: u8, err: io.Error) {
b := read_slice_from_stream(z, 1) or_return
return b[0], nil
@@ -242,7 +242,7 @@ read_u8 :: proc{read_u8_from_memory, read_u8_from_stream}
// You would typically only use this at the end of Inflate, to drain bits from the code buffer
// preferentially.
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_u8_prefer_code_buffer_lsb :: #force_inline proc(z: ^$C) -> (res: u8, err: io.Error) {
if z.num_bits >= 8 {
res = u8(read_bits_no_refill_lsb(z, 8))
@@ -257,7 +257,7 @@ read_u8_prefer_code_buffer_lsb :: #force_inline proc(z: ^$C) -> (res: u8, err: i
return
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid) -> (res: T, err: io.Error) {
size :: size_of(T)
@@ -275,7 +275,7 @@ peek_data_from_memory :: #force_inline proc(z: ^Context_Memory_Input, $T: typeid
}
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
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)
@@ -293,7 +293,7 @@ peek_data_at_offset_from_memory :: #force_inline proc(z: ^Context_Memory_Input,
}
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid) -> (res: T, err: io.Error) {
size :: size_of(T)
@@ -317,7 +317,7 @@ peek_data_from_stream :: #force_inline proc(z: ^Context_Stream_Input, $T: typeid
return res, .None
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
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)
@@ -352,14 +352,14 @@ peek_data :: proc{peek_data_from_memory, peek_data_from_stream, peek_data_at_off
// Sliding window read back
@(optimization_mode="speed")
@(optimization_mode="favor_size")
peek_back_byte :: #force_inline proc(z: ^$C, offset: i64) -> (res: u8, err: io.Error) {
// Look back into the sliding window.
return z.output.buf[z.bytes_written - offset], .None
}
// Generalized bit reader LSB
@(optimization_mode="speed")
@(optimization_mode="favor_size")
refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width := i8(48)) {
refill := u64(width)
b := u64(0)
@@ -385,7 +385,7 @@ refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width :=
}
// Generalized bit reader LSB
@(optimization_mode="speed")
@(optimization_mode="favor_size")
refill_lsb_from_stream :: proc(z: ^Context_Stream_Input, width := i8(24)) {
refill := u64(width)
@@ -414,13 +414,13 @@ refill_lsb_from_stream :: proc(z: ^Context_Stream_Input, width := i8(24)) {
refill_lsb :: proc{refill_lsb_from_memory, refill_lsb_from_stream}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
consume_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) {
z.code_buffer >>= width
z.num_bits -= u64(width)
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
consume_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) {
z.code_buffer >>= width
z.num_bits -= u64(width)
@@ -428,7 +428,7 @@ consume_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, wid
consume_bits_lsb :: proc{consume_bits_lsb_from_memory, consume_bits_lsb_from_stream}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
if z.num_bits < u64(width) {
refill_lsb(z)
@@ -436,7 +436,7 @@ peek_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width:
return u32(z.code_buffer &~ (~u64(0) << width))
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
if z.num_bits < u64(width) {
refill_lsb(z)
@@ -446,13 +446,13 @@ peek_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width:
peek_bits_lsb :: proc{peek_bits_lsb_from_memory, peek_bits_lsb_from_stream}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
peek_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
assert(z.num_bits >= u64(width))
return u32(z.code_buffer &~ (~u64(0) << width))
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
assert(z.num_bits >= u64(width))
return u32(z.code_buffer &~ (~u64(0) << width))
@@ -460,14 +460,14 @@ peek_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Inp
peek_bits_no_refill_lsb :: proc{peek_bits_no_refill_lsb_from_memory, peek_bits_no_refill_lsb_from_stream}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_bits_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
k := #force_inline peek_bits_lsb(z, width)
#force_inline consume_bits_lsb(z, width)
return k
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
k := peek_bits_lsb(z, width)
consume_bits_lsb(z, width)
@@ -476,14 +476,14 @@ read_bits_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width:
read_bits_lsb :: proc{read_bits_lsb_from_memory, read_bits_lsb_from_stream}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_bits_no_refill_lsb_from_memory :: #force_inline proc(z: ^Context_Memory_Input, width: u8) -> u32 {
k := #force_inline peek_bits_no_refill_lsb(z, width)
#force_inline consume_bits_lsb(z, width)
return k
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
read_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Input, width: u8) -> u32 {
k := peek_bits_no_refill_lsb(z, width)
consume_bits_lsb(z, width)
@@ -493,14 +493,14 @@ read_bits_no_refill_lsb_from_stream :: #force_inline proc(z: ^Context_Stream_Inp
read_bits_no_refill_lsb :: proc{read_bits_no_refill_lsb_from_memory, read_bits_no_refill_lsb_from_stream}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
discard_to_next_byte_lsb_from_memory :: proc(z: ^Context_Memory_Input) {
discard := u8(z.num_bits & 7)
#force_inline consume_bits_lsb(z, discard)
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
discard_to_next_byte_lsb_from_stream :: proc(z: ^Context_Stream_Input) {
discard := u8(z.num_bits & 7)
consume_bits_lsb(z, discard)
+15 -20
View File
@@ -12,6 +12,7 @@ package compress_zlib
import "core:compress"
import "base:intrinsics"
import "core:mem"
import "core:io"
import "core:hash"
@@ -120,23 +121,17 @@ Huffman_Table :: struct {
}
// Implementation starts here
@(optimization_mode="speed")
@(optimization_mode="favor_size")
z_bit_reverse :: #force_inline proc(n: u16, bits: u8) -> (r: u16) {
assert(bits <= 16)
// NOTE: Can optimize with llvm.bitreverse.i64 or some bit twiddling
// by reversing all of the bits and masking out the unneeded ones.
r = n
r = ((r & 0xAAAA) >> 1) | ((r & 0x5555) << 1)
r = ((r & 0xCCCC) >> 2) | ((r & 0x3333) << 2)
r = ((r & 0xF0F0) >> 4) | ((r & 0x0F0F) << 4)
r = ((r & 0xFF00) >> 8) | ((r & 0x00FF) << 8)
r = intrinsics.reverse_bits(n)
r >>= (16 - bits)
return
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) {
/*
That we get here at all means that we didn't pass an expected output size,
@@ -154,7 +149,7 @@ grow_buffer :: proc(buf: ^[dynamic]u8) -> (err: compress.Error) {
TODO: Make these return compress.Error.
*/
@(optimization_mode="speed")
@(optimization_mode="favor_size")
write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_check {
/*
Resize if needed.
@@ -173,7 +168,7 @@ write_byte :: #force_inline proc(z: ^$C, c: u8) -> (err: io.Error) #no_bounds_ch
return .None
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check {
/*
TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it
@@ -201,7 +196,7 @@ repl_byte :: proc(z: ^$C, count: u16, c: u8) -> (err: io.Error) #no_bounds_check
return .None
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
repl_bytes :: proc(z: ^$C, count: u16, distance: u16) -> (err: io.Error) {
/*
TODO(Jeroen): Once we have a magic ring buffer, we can just peek/write into it
@@ -234,8 +229,8 @@ allocate_huffman_table :: proc(allocator := context.allocator) -> (z: ^Huffman_T
return new(Huffman_Table, allocator), nil
}
@(optimization_mode="speed")
build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
@(optimization_mode="favor_size")
build_huffman :: #force_no_inline proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
sizes: [HUFFMAN_MAX_BITS+1]int
next_code: [HUFFMAN_MAX_BITS+1]int
@@ -293,7 +288,7 @@ build_huffman :: proc(z: ^Huffman_Table, code_lengths: []u8) -> (err: Error) {
return nil
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
code := u16(compress.peek_bits_lsb(z,16))
@@ -324,7 +319,7 @@ decode_huffman_slowpath :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Erro
return r, nil
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bounds_check {
if z.num_bits < 16 {
if z.num_bits > 63 {
@@ -344,7 +339,7 @@ decode_huffman :: proc(z: ^$C, t: ^Huffman_Table) -> (r: u16, err: Error) #no_bo
return decode_huffman_slowpath(z, t)
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err: Error) #no_bounds_check {
#no_bounds_check for {
value, e := decode_huffman(z, z_repeat)
@@ -413,7 +408,7 @@ parse_huffman_block :: proc(z: ^$C, z_repeat, z_offset: ^Huffman_Table) -> (err:
}
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := false, expected_output_size := -1, allocator := context.allocator) -> (err: Error) #no_bounds_check {
/*
ctx.output must be a bytes.Buffer for now. We'll add a separate implementation that writes to a stream.
@@ -486,7 +481,7 @@ inflate_from_context :: proc(using ctx: ^compress.Context_Memory_Input, raw := f
// TODO: Check alignment of reserve/resize.
@(optimization_mode="speed")
@(optimization_mode="favor_size")
inflate_raw :: proc(z: ^$C, expected_output_size := -1, allocator := context.allocator) -> (err: Error) #no_bounds_check {
context.allocator = allocator
expected_output_size := expected_output_size
@@ -670,4 +665,4 @@ inflate_from_byte_array_raw :: proc(input: []u8, buf: ^bytes.Buffer, raw := fals
return inflate_raw(&ctx, expected_output_size=expected_output_size)
}
inflate :: proc{inflate_from_context, inflate_from_byte_array}
inflate :: proc{inflate_from_context, inflate_from_byte_array}
+46
View File
@@ -0,0 +1,46 @@
/*
Package list implements an intrusive doubly-linked list.
An intrusive container requires a `Node` to be embedded in your own structure, like this:
My_String :: struct {
node: list.Node,
value: string,
}
Embedding the members of a `list.Node` in your structure with the `using` keyword is also allowed:
My_String :: struct {
using node: list.Node,
value: string,
}
Here is a full example:
package test
import "core:fmt"
import "core:container/intrusive/list"
main :: proc() {
l: list.List
one := My_String{value="Hello"}
two := My_String{value="World"}
list.push_back(&l, &one.node)
list.push_back(&l, &two.node)
iter := list.iterator_head(l, My_String, "node")
for s in list.iterate_next(&iter) {
fmt.println(s.value)
}
}
My_String :: struct {
node: list.Node,
value: string,
}
*/
package container_intrusive_list
@@ -18,11 +18,18 @@ List :: struct {
tail: ^Node,
}
// The list link you must include in your own structure.
Node :: struct {
prev, next: ^Node,
}
/*
Inserts a new element at the front of the list with O(1) time complexity.
**Inputs**
- list: The container list
- node: The node member of the user-defined element structure
*/
push_front :: proc "contextless" (list: ^List, node: ^Node) {
if list.head != nil {
list.head.prev = node
@@ -33,7 +40,13 @@ push_front :: proc "contextless" (list: ^List, node: ^Node) {
node.prev, node.next = nil, nil
}
}
/*
Inserts a new element at the back of the list with O(1) time complexity.
**Inputs**
- list: The container list
- node: The node member of the user-defined element structure
*/
push_back :: proc "contextless" (list: ^List, node: ^Node) {
if list.tail != nil {
list.tail.next = node
@@ -45,6 +58,13 @@ push_back :: proc "contextless" (list: ^List, node: ^Node) {
}
}
/*
Removes an element from a list with O(1) time complexity.
**Inputs**
- list: The container list
- node: The node member of the user-defined element structure to be removed
*/
remove :: proc "contextless" (list: ^List, node: ^Node) {
if node != nil {
if node.next != nil {
@@ -61,7 +81,13 @@ remove :: proc "contextless" (list: ^List, node: ^Node) {
}
}
}
/*
Removes from the given list all elements that satisfy a condition with O(N) time complexity.
**Inputs**
- list: The container list
- to_erase: The condition procedure. It should return `true` if a node should be removed, `false` otherwise
*/
remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
for node := list.head; node != nil; {
next := node.next
@@ -82,7 +108,13 @@ remove_by_proc :: proc(list: ^List, to_erase: proc(^Node) -> bool) {
node = next
}
}
/*
Removes from the given list all elements that satisfy a condition with O(N) time complexity.
**Inputs**
- list: The container list
- to_erase: The _contextless_ condition procedure. It should return `true` if a node should be removed, `false` otherwise
*/
remove_by_proc_contextless :: proc(list: ^List, to_erase: proc "contextless" (^Node) -> bool) {
for node := list.head; node != nil; {
next := node.next
@@ -104,12 +136,26 @@ remove_by_proc_contextless :: proc(list: ^List, to_erase: proc "contextless" (^N
}
}
/*
Checks whether the given list does not contain any element.
**Inputs**
- list: The container list
**Returns** `true` if `list` is empty, `false` otherwise
*/
is_empty :: proc "contextless" (list: ^List) -> bool {
return list.head == nil
}
/*
Removes and returns the element at the front of the list with O(1) time complexity.
**Inputs**
- list: The container list
**Returns** The node member of the user-defined element structure, or `nil` if the list is empty
*/
pop_front :: proc "contextless" (list: ^List) -> ^Node {
link := list.head
if link == nil {
@@ -130,6 +176,14 @@ pop_front :: proc "contextless" (list: ^List) -> ^Node {
return link
}
/*
Removes and returns the element at the back of the list with O(1) time complexity.
**Inputs**
- list: The container list
**Returns** The node member of the user-defined element structure, or `nil` if the list is empty
*/
pop_back :: proc "contextless" (list: ^List) -> ^Node {
link := list.tail
if link == nil {
@@ -151,29 +205,102 @@ pop_back :: proc "contextless" (list: ^List) -> ^Node {
}
Iterator :: struct($T: typeid) {
curr: ^Node,
offset: uintptr,
}
/*
Creates an iterator pointing at the head of the given list. For an example, see `iterate_next`.
**Inputs**
- list: The container list
- T: The type of the list's elements
- field_name: The name of the node field in the `T` structure
**Returns** An iterator pointing at the head of `list`
*/
iterator_head :: proc "contextless" (list: List, $T: typeid, $field_name: string) -> Iterator(T)
where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Node {
return {list.head, offset_of_by_string(T, field_name)}
}
/*
Creates an iterator pointing at the tail of the given list. For an example, see `iterate_prev`.
**Inputs**
- list: The container list
- T: The type of the list's elements
- field_name: The name of the node field in the `T` structure
**Returns** An iterator pointing at the tail of `list`
*/
iterator_tail :: proc "contextless" (list: List, $T: typeid, $field_name: string) -> Iterator(T)
where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Node {
return {list.tail, offset_of_by_string(T, field_name)}
}
/*
Creates an iterator pointing at the specified node of a list.
**Inputs**
- node: a list node
- T: The type of the list's elements
- field_name: The name of the node field in the `T` structure
**Returns** An iterator pointing at `node`
*/
iterator_from_node :: proc "contextless" (node: ^Node, $T: typeid, $field_name: string) -> Iterator(T)
where intrinsics.type_has_field(T, field_name),
intrinsics.type_field_type(T, field_name) == Node {
return {node, offset_of_by_string(T, field_name)}
}
/*
Retrieves the next element in a list and advances the iterator.
**Inputs**
- it: The iterator
**Returns**
- ptr: The next list element
- ok: `true` if the element is valid (the iterator could advance), `false` otherwise
Example:
import "core:fmt"
import "core:container/intrusive/list"
iterate_next_example :: proc() {
l: list.List
one := My_Struct{value=1}
two := My_Struct{value=2}
list.push_back(&l, &one.node)
list.push_back(&l, &two.node)
it := list.iterator_head(l, My_Struct, "node")
for num in list.iterate_next(&it) {
fmt.println(num.value)
}
}
My_Struct :: struct {
node : list.Node,
value: int,
}
Output:
1
2
*/
iterate_next :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
node := it.curr
if node == nil {
@@ -183,7 +310,47 @@ iterate_next :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
return (^T)(uintptr(node) - it.offset), true
}
/*
Retrieves the previous element in a list and recede the iterator.
**Inputs**
- it: The iterator
**Returns**
- ptr: The previous list element
- ok: `true` if the element is valid (the iterator could recede), `false` otherwise
Example:
import "core:fmt"
import "core:container/intrusive/list"
iterate_next_example :: proc() {
l: list.List
one := My_Struct{value=1}
two := My_Struct{value=2}
list.push_back(&l, &one.node)
list.push_back(&l, &two.node)
it := list.iterator_tail(l, My_Struct, "node")
for num in list.iterate_prev(&it) {
fmt.println(num.value)
}
}
My_Struct :: struct {
node : list.Node,
value: int,
}
Output:
2
1
*/
iterate_prev :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
node := it.curr
if node == nil {
@@ -192,4 +359,4 @@ iterate_prev :: proc "contextless" (it: ^Iterator($T)) -> (ptr: ^T, ok: bool) {
it.curr = node.prev
return (^T)(uintptr(node) - it.offset), true
}
}
+2 -2
View File
@@ -95,11 +95,11 @@ front_ptr :: proc(q: ^$Q/Queue($T)) -> ^T {
}
back :: proc(q: ^$Q/Queue($T)) -> T {
idx := (q.offset+uint(q.len))%builtin.len(q.data)
idx := (q.offset+uint(q.len - 1))%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)
idx := (q.offset+uint(q.len - 1))%builtin.len(q.data)
return &q.data[idx]
}
+2 -12
View File
@@ -7,9 +7,8 @@ STRIDE :: 4
// Context is a keyed AES (ECB) instance.
Context :: struct {
_sk_exp: [120]u64,
_num_rounds: int,
_is_initialized: bool,
_sk_exp: [120]u64,
_num_rounds: int,
}
// init initializes a context for AES with the provided key.
@@ -18,13 +17,10 @@ init :: proc(ctx: ^Context, key: []byte) {
ctx._num_rounds = keysched(skey[:], key)
skey_expand(ctx._sk_exp[:], skey[:], ctx._num_rounds)
ctx._is_initialized = true
}
// encrypt_block sets `dst` to `AES-ECB-Encrypt(src)`.
encrypt_block :: proc(ctx: ^Context, dst, src: []byte) {
assert(ctx._is_initialized)
q: [8]u64
load_blockx1(&q, src)
_encrypt(&q, ctx._sk_exp[:], ctx._num_rounds)
@@ -33,8 +29,6 @@ encrypt_block :: proc(ctx: ^Context, dst, src: []byte) {
// encrypt_block sets `dst` to `AES-ECB-Decrypt(src)`.
decrypt_block :: proc(ctx: ^Context, dst, src: []byte) {
assert(ctx._is_initialized)
q: [8]u64
load_blockx1(&q, src)
_decrypt(&q, ctx._sk_exp[:], ctx._num_rounds)
@@ -43,8 +37,6 @@ decrypt_block :: proc(ctx: ^Context, dst, src: []byte) {
// encrypt_blocks sets `dst` to `AES-ECB-Encrypt(src[0], .. src[n])`.
encrypt_blocks :: proc(ctx: ^Context, dst, src: [][]byte) {
assert(ctx._is_initialized)
q: [8]u64 = ---
src, dst := src, dst
@@ -67,8 +59,6 @@ encrypt_blocks :: proc(ctx: ^Context, dst, src: [][]byte) {
// decrypt_blocks sets dst to `AES-ECB-Decrypt(src[0], .. src[n])`.
decrypt_blocks :: proc(ctx: ^Context, dst, src: [][]byte) {
assert(ctx._is_initialized)
q: [8]u64 = ---
src, dst := src, dst
+1 -1
View File
@@ -80,8 +80,8 @@ ghash :: proc "contextless" (dst, key, data: []byte) {
h2 := h0 ~ h1
h2r := h0r ~ h1r
src: []byte
for l > 0 {
src: []byte = ---
if l >= _aes.GHASH_BLOCK_SIZE {
src = buf
buf = buf[_aes.GHASH_BLOCK_SIZE:]
+43
View File
@@ -0,0 +1,43 @@
//+build amd64
package aes_hw_intel
import "core:sys/info"
// is_supported returns true iff hardware accelerated AES
// is supported.
is_supported :: proc "contextless" () -> bool {
features, ok := info.cpu_features.?
if !ok {
return false
}
// Note: Everything with AES-NI and PCLMULQDQ has support for
// the required SSE extxtensions.
req_features :: info.CPU_Features{
.sse2,
.ssse3,
.sse41,
.aes,
.pclmulqdq,
}
return features >= req_features
}
// Context is a keyed AES (ECB) instance.
Context :: struct {
// Note: The ideal thing to do is for the expanded round keys to be
// arrays of `__m128i`, however that implies alignment (or using AVX).
//
// All the people using e-waste processors that don't support an
// insturction set that has been around for over 10 years are why
// we can't have nice things.
_sk_exp_enc: [15][16]byte,
_sk_exp_dec: [15][16]byte,
_num_rounds: int,
}
// init initializes a context for AES with the provided key.
init :: proc(ctx: ^Context, key: []byte) {
keysched(ctx, key)
}
+277
View File
@@ -0,0 +1,277 @@
// Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “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 AUTHORS 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.
//+build amd64
package aes_hw_intel
import "base:intrinsics"
import "core:crypto/_aes"
import "core:simd/x86"
@(private = "file")
GHASH_STRIDE_HW :: 4
@(private = "file")
GHASH_STRIDE_BYTES_HW :: GHASH_STRIDE_HW * _aes.GHASH_BLOCK_SIZE
// GHASH is defined over elements of GF(2^128) with "full little-endian"
// representation: leftmost byte is least significant, and, within each
// byte, leftmost _bit_ is least significant. The natural ordering in
// x86 is "mixed little-endian": bytes are ordered from least to most
// significant, but bits within a byte are in most-to-least significant
// order. Going to full little-endian representation would require
// reversing bits within each byte, which is doable but expensive.
//
// Instead, we go to full big-endian representation, by swapping bytes
// around, which is done with a single _mm_shuffle_epi8() opcode (it
// comes with SSSE3; all CPU that offer pclmulqdq also have SSSE3). We
// can use a full big-endian representation because in a carryless
// multiplication, we have a nice bit reversal property:
//
// rev_128(x) * rev_128(y) = rev_255(x * y)
//
// So by using full big-endian, we still get the right result, except
// that it is right-shifted by 1 bit. The left-shift is relatively
// inexpensive, and it can be mutualised.
//
// Since SSE2 opcodes do not have facilities for shitfting full 128-bit
// values with bit precision, we have to break down values into 64-bit
// chunks. We number chunks from 0 to 3 in left to right order.
@(private = "file")
_BYTESWAP_INDEX: x86.__m128i : { 0x08090a0b0c0d0e0f, 0x0001020304050607 }
@(private = "file", require_results, enable_target_feature = "sse2,ssse3")
byteswap :: #force_inline proc "contextless" (x: x86.__m128i) -> x86.__m128i {
return x86._mm_shuffle_epi8(x, _BYTESWAP_INDEX)
}
// From a 128-bit value kw, compute kx as the XOR of the two 64-bit
// halves of kw (into the right half of kx; left half is unspecified),
// and return kx.
@(private = "file", require_results, enable_target_feature = "sse2")
bk :: #force_inline proc "contextless" (kw: x86.__m128i) -> x86.__m128i {
return x86._mm_xor_si128(kw, x86._mm_shuffle_epi32(kw, 0x0e))
}
// Combine two 64-bit values (k0:k1) into a 128-bit (kw) value and
// the XOR of the two values (kx), and return (kw, kx).
@(private = "file", enable_target_feature = "sse2")
pbk :: #force_inline proc "contextless" (k0, k1: x86.__m128i) -> (x86.__m128i, x86.__m128i) {
kw := x86._mm_unpacklo_epi64(k1, k0)
kx := x86._mm_xor_si128(k0, k1)
return kw, kx
}
// Left-shift by 1 bit a 256-bit value (in four 64-bit words).
@(private = "file", require_results, enable_target_feature = "sse2")
sl_256 :: #force_inline proc "contextless" (x0, x1, x2, x3: x86.__m128i) -> (x86.__m128i, x86.__m128i, x86.__m128i, x86.__m128i) {
x0, x1, x2, x3 := x0, x1, x2, x3
x0 = x86._mm_or_si128(x86._mm_slli_epi64(x0, 1), x86._mm_srli_epi64(x1, 63))
x1 = x86._mm_or_si128(x86._mm_slli_epi64(x1, 1), x86._mm_srli_epi64(x2, 63))
x2 = x86._mm_or_si128(x86._mm_slli_epi64(x2, 1), x86._mm_srli_epi64(x3, 63))
x3 = x86._mm_slli_epi64(x3, 1)
return x0, x1, x2, x3
}
// Perform reduction in GF(2^128).
@(private = "file", require_results, enable_target_feature = "sse2")
reduce_f128 :: #force_inline proc "contextless" (x0, x1, x2, x3: x86.__m128i) -> (x86.__m128i, x86.__m128i) {
x0, x1, x2 := x0, x1, x2
x1 = x86._mm_xor_si128(
x1,
x86._mm_xor_si128(
x86._mm_xor_si128(
x3,
x86._mm_srli_epi64(x3, 1)),
x86._mm_xor_si128(
x86._mm_srli_epi64(x3, 2),
x86._mm_srli_epi64(x3, 7))))
x2 = x86._mm_xor_si128(
x86._mm_xor_si128(
x2,
x86._mm_slli_epi64(x3, 63)),
x86._mm_xor_si128(
x86._mm_slli_epi64(x3, 62),
x86._mm_slli_epi64(x3, 57)))
x0 = x86._mm_xor_si128(
x0,
x86._mm_xor_si128(
x86._mm_xor_si128(
x2,
x86._mm_srli_epi64(x2, 1)),
x86._mm_xor_si128(
x86._mm_srli_epi64(x2, 2),
x86._mm_srli_epi64(x2, 7))))
x1 = x86._mm_xor_si128(
x86._mm_xor_si128(
x1,
x86._mm_slli_epi64(x2, 63)),
x86._mm_xor_si128(
x86._mm_slli_epi64(x2, 62),
x86._mm_slli_epi64(x2, 57)))
return x0, x1
}
// Square value kw in GF(2^128) into (dw,dx).
@(private = "file", require_results, enable_target_feature = "sse2,pclmul")
square_f128 :: #force_inline proc "contextless" (kw: x86.__m128i) -> (x86.__m128i, x86.__m128i) {
z1 := x86._mm_clmulepi64_si128(kw, kw, 0x11)
z3 := x86._mm_clmulepi64_si128(kw, kw, 0x00)
z0 := x86._mm_shuffle_epi32(z1, 0x0E)
z2 := x86._mm_shuffle_epi32(z3, 0x0E)
z0, z1, z2, z3 = sl_256(z0, z1, z2, z3)
z0, z1 = reduce_f128(z0, z1, z2, z3)
return pbk(z0, z1)
}
// ghash calculates the GHASH of data, with the key `key`, and input `dst`
// and `data`, and stores the resulting digest in `dst`.
//
// Note: `dst` is both an input and an output, to support easy implementation
// of GCM.
@(enable_target_feature = "sse2,ssse3,pclmul")
ghash :: proc "contextless" (dst, key, data: []byte) #no_bounds_check {
if len(dst) != _aes.GHASH_BLOCK_SIZE || len(key) != _aes.GHASH_BLOCK_SIZE {
intrinsics.trap()
}
// Note: BearSSL opts to copy the remainder into a zero-filled
// 64-byte buffer. We do something slightly more simple.
// Load key and dst (h and y).
yw := intrinsics.unaligned_load((^x86.__m128i)(raw_data(dst)))
h1w := intrinsics.unaligned_load((^x86.__m128i)(raw_data(key)))
yw = byteswap(yw)
h1w = byteswap(h1w)
h1x := bk(h1w)
// Process 4 blocks at a time
buf := data
l := len(buf)
if l >= GHASH_STRIDE_BYTES_HW {
// Compute h2 = h^2
h2w, h2x := square_f128(h1w)
// Compute h3 = h^3 = h*(h^2)
t1 := x86._mm_clmulepi64_si128(h1w, h2w, 0x11)
t3 := x86._mm_clmulepi64_si128(h1w, h2w, 0x00)
t2 := x86._mm_xor_si128(
x86._mm_clmulepi64_si128(h1x, h2x, 0x00),
x86._mm_xor_si128(t1, t3))
t0 := x86._mm_shuffle_epi32(t1, 0x0E)
t1 = x86._mm_xor_si128(t1, x86._mm_shuffle_epi32(t2, 0x0E))
t2 = x86._mm_xor_si128(t2, x86._mm_shuffle_epi32(t3, 0x0E))
t0, t1, t2, t3 = sl_256(t0, t1, t2, t3)
t0, t1 = reduce_f128(t0, t1, t2, t3)
h3w, h3x := pbk(t0, t1)
// Compute h4 = h^4 = (h^2)^2
h4w, h4x := square_f128(h2w)
for l >= GHASH_STRIDE_BYTES_HW {
aw0 := intrinsics.unaligned_load((^x86.__m128i)(raw_data(buf)))
aw1 := intrinsics.unaligned_load((^x86.__m128i)(raw_data(buf[16:])))
aw2 := intrinsics.unaligned_load((^x86.__m128i)(raw_data(buf[32:])))
aw3 := intrinsics.unaligned_load((^x86.__m128i)(raw_data(buf[48:])))
aw0 = byteswap(aw0)
aw1 = byteswap(aw1)
aw2 = byteswap(aw2)
aw3 = byteswap(aw3)
buf, l = buf[GHASH_STRIDE_BYTES_HW:], l - GHASH_STRIDE_BYTES_HW
aw0 = x86._mm_xor_si128(aw0, yw)
ax1 := bk(aw1)
ax2 := bk(aw2)
ax3 := bk(aw3)
ax0 := bk(aw0)
t1 = x86._mm_xor_si128(
x86._mm_xor_si128(
x86._mm_clmulepi64_si128(aw0, h4w, 0x11),
x86._mm_clmulepi64_si128(aw1, h3w, 0x11)),
x86._mm_xor_si128(
x86._mm_clmulepi64_si128(aw2, h2w, 0x11),
x86._mm_clmulepi64_si128(aw3, h1w, 0x11)))
t3 = x86._mm_xor_si128(
x86._mm_xor_si128(
x86._mm_clmulepi64_si128(aw0, h4w, 0x00),
x86._mm_clmulepi64_si128(aw1, h3w, 0x00)),
x86._mm_xor_si128(
x86._mm_clmulepi64_si128(aw2, h2w, 0x00),
x86._mm_clmulepi64_si128(aw3, h1w, 0x00)))
t2 = x86._mm_xor_si128(
x86._mm_xor_si128(
x86._mm_clmulepi64_si128(ax0, h4x, 0x00),
x86._mm_clmulepi64_si128(ax1, h3x, 0x00)),
x86._mm_xor_si128(
x86._mm_clmulepi64_si128(ax2, h2x, 0x00),
x86._mm_clmulepi64_si128(ax3, h1x, 0x00)))
t2 = x86._mm_xor_si128(t2, x86._mm_xor_si128(t1, t3))
t0 = x86._mm_shuffle_epi32(t1, 0x0E)
t1 = x86._mm_xor_si128(t1, x86._mm_shuffle_epi32(t2, 0x0E))
t2 = x86._mm_xor_si128(t2, x86._mm_shuffle_epi32(t3, 0x0E))
t0, t1, t2, t3 = sl_256(t0, t1, t2, t3)
t0, t1 = reduce_f128(t0, t1, t2, t3)
yw = x86._mm_unpacklo_epi64(t1, t0)
}
}
// Process 1 block at a time
for l > 0 {
src: []byte = ---
if l >= _aes.GHASH_BLOCK_SIZE {
src = buf
buf = buf[_aes.GHASH_BLOCK_SIZE:]
l -= _aes.GHASH_BLOCK_SIZE
} else {
tmp: [_aes.GHASH_BLOCK_SIZE]byte
copy(tmp[:], buf)
src = tmp[:]
l = 0
}
aw := intrinsics.unaligned_load((^x86.__m128i)(raw_data(src)))
aw = byteswap(aw)
aw = x86._mm_xor_si128(aw, yw)
ax := bk(aw)
t1 := x86._mm_clmulepi64_si128(aw, h1w, 0x11)
t3 := x86._mm_clmulepi64_si128(aw, h1w, 0x00)
t2 := x86._mm_clmulepi64_si128(ax, h1x, 0x00)
t2 = x86._mm_xor_si128(t2, x86._mm_xor_si128(t1, t3))
t0 := x86._mm_shuffle_epi32(t1, 0x0E)
t1 = x86._mm_xor_si128(t1, x86._mm_shuffle_epi32(t2, 0x0E))
t2 = x86._mm_xor_si128(t2, x86._mm_shuffle_epi32(t3, 0x0E))
t0, t1, t2, t3 = sl_256(t0, t1, t2, t3)
t0, t1 = reduce_f128(t0, t1, t2, t3)
yw = x86._mm_unpacklo_epi64(t1, t0)
}
// Write back the hash (dst, aka y)
yw = byteswap(yw)
intrinsics.unaligned_store((^x86.__m128i)(raw_data(dst)), yw)
}
@@ -0,0 +1,178 @@
// Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// 1. Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// THIS SOFTWARE IS PROVIDED BY THE AUTHORS “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 AUTHORS 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.
//+build amd64
package aes_hw_intel
import "base:intrinsics"
import "core:crypto/_aes"
import "core:mem"
import "core:simd/x86"
// Intel AES-NI based implementation. Inspiration taken from BearSSL.
//
// Note: This assumes that the SROA optimization pass is enabled to be
// anything resembling performat otherwise, LLVM will not elide a massive
// number of redundant loads/stores it generates for every intrinsic call.
@(private = "file", require_results, enable_target_feature = "sse2")
expand_step128 :: #force_inline proc(k1, k2: x86.__m128i) -> x86.__m128i {
k1, k2 := k1, k2
k2 = x86._mm_shuffle_epi32(k2, 0xff)
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
return x86._mm_xor_si128(k1, k2)
}
@(private = "file", require_results, enable_target_feature = "sse,sse2")
expand_step192a :: #force_inline proc (k1_, k2_: ^x86.__m128i, k3: x86.__m128i) -> (x86.__m128i, x86.__m128i) {
k1, k2, k3 := k1_^, k2_^, k3
k3 = x86._mm_shuffle_epi32(k3, 0x55)
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, k3)
tmp := k2
k2 = x86._mm_xor_si128(k2, x86._mm_slli_si128(k2, 0x04))
k2 = x86._mm_xor_si128(k2, x86._mm_shuffle_epi32(k1, 0xff))
k1_, k2_ := k1_, k2_
k1_^, k2_^ = k1, k2
r1 := transmute(x86.__m128i)(x86._mm_shuffle_ps(transmute(x86.__m128)(tmp), transmute(x86.__m128)(k1), 0x44))
r2 := transmute(x86.__m128i)(x86._mm_shuffle_ps(transmute(x86.__m128)(k1), transmute(x86.__m128)(k2), 0x4e))
return r1, r2
}
@(private = "file", require_results, enable_target_feature = "sse2")
expand_step192b :: #force_inline proc (k1_, k2_: ^x86.__m128i, k3: x86.__m128i) -> x86.__m128i {
k1, k2, k3 := k1_^, k2_^, k3
k3 = x86._mm_shuffle_epi32(k3, 0x55)
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, k3)
k2 = x86._mm_xor_si128(k2, x86._mm_slli_si128(k2, 0x04))
k2 = x86._mm_xor_si128(k2, x86._mm_shuffle_epi32(k1, 0xff))
k1_, k2_ := k1_, k2_
k1_^, k2_^ = k1, k2
return k1
}
@(private = "file", require_results, enable_target_feature = "sse2")
expand_step256b :: #force_inline proc(k1, k2: x86.__m128i) -> x86.__m128i {
k1, k2 := k1, k2
k2 = x86._mm_shuffle_epi32(k2, 0xaa)
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
k1 = x86._mm_xor_si128(k1, x86._mm_slli_si128(k1, 0x04))
return x86._mm_xor_si128(k1, k2)
}
@(private = "file", enable_target_feature = "aes")
derive_dec_keys :: proc(ctx: ^Context, sks: ^[15]x86.__m128i, num_rounds: int) {
intrinsics.unaligned_store((^x86.__m128i)(&ctx._sk_exp_dec[0]), sks[num_rounds])
for i in 1 ..< num_rounds {
tmp := x86._mm_aesimc_si128(sks[i])
intrinsics.unaligned_store((^x86.__m128i)(&ctx._sk_exp_dec[num_rounds - i]), tmp)
}
intrinsics.unaligned_store((^x86.__m128i)(&ctx._sk_exp_dec[num_rounds]), sks[0])
}
@(private, enable_target_feature = "sse,sse2,aes")
keysched :: proc(ctx: ^Context, key: []byte) {
sks: [15]x86.__m128i = ---
// Compute the encryption keys.
num_rounds, key_len := 0, len(key)
switch key_len {
case _aes.KEY_SIZE_128:
sks[0] = intrinsics.unaligned_load((^x86.__m128i)(raw_data(key)))
sks[1] = expand_step128(sks[0], x86._mm_aeskeygenassist_si128(sks[0], 0x01))
sks[2] = expand_step128(sks[1], x86._mm_aeskeygenassist_si128(sks[1], 0x02))
sks[3] = expand_step128(sks[2], x86._mm_aeskeygenassist_si128(sks[2], 0x04))
sks[4] = expand_step128(sks[3], x86._mm_aeskeygenassist_si128(sks[3], 0x08))
sks[5] = expand_step128(sks[4], x86._mm_aeskeygenassist_si128(sks[4], 0x10))
sks[6] = expand_step128(sks[5], x86._mm_aeskeygenassist_si128(sks[5], 0x20))
sks[7] = expand_step128(sks[6], x86._mm_aeskeygenassist_si128(sks[6], 0x40))
sks[8] = expand_step128(sks[7], x86._mm_aeskeygenassist_si128(sks[7], 0x80))
sks[9] = expand_step128(sks[8], x86._mm_aeskeygenassist_si128(sks[8], 0x1b))
sks[10] = expand_step128(sks[9], x86._mm_aeskeygenassist_si128(sks[9], 0x36))
num_rounds = _aes.ROUNDS_128
case _aes.KEY_SIZE_192:
k0 := intrinsics.unaligned_load((^x86.__m128i)(raw_data(key)))
k1 := x86.__m128i{
intrinsics.unaligned_load((^i64)(raw_data(key[16:]))),
0,
}
sks[0] = k0
sks[1], sks[2] = expand_step192a(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x01))
sks[3] = expand_step192b(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x02))
sks[4], sks[5] = expand_step192a(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x04))
sks[6] = expand_step192b(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x08))
sks[7], sks[8] = expand_step192a(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x10))
sks[9] = expand_step192b(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x20))
sks[10], sks[11] = expand_step192a(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x40))
sks[12] = expand_step192b(&k0, &k1, x86._mm_aeskeygenassist_si128(k1, 0x80))
num_rounds = _aes.ROUNDS_192
case _aes.KEY_SIZE_256:
sks[0] = intrinsics.unaligned_load((^x86.__m128i)(raw_data(key)))
sks[1] = intrinsics.unaligned_load((^x86.__m128i)(raw_data(key[16:])))
sks[2] = expand_step128(sks[0], x86._mm_aeskeygenassist_si128(sks[1], 0x01))
sks[3] = expand_step256b(sks[1], x86._mm_aeskeygenassist_si128(sks[2], 0x01))
sks[4] = expand_step128(sks[2], x86._mm_aeskeygenassist_si128(sks[3], 0x02))
sks[5] = expand_step256b(sks[3], x86._mm_aeskeygenassist_si128(sks[4], 0x02))
sks[6] = expand_step128(sks[4], x86._mm_aeskeygenassist_si128(sks[5], 0x04))
sks[7] = expand_step256b(sks[5], x86._mm_aeskeygenassist_si128(sks[6], 0x04))
sks[8] = expand_step128(sks[6], x86._mm_aeskeygenassist_si128(sks[7], 0x08))
sks[9] = expand_step256b(sks[7], x86._mm_aeskeygenassist_si128(sks[8], 0x08))
sks[10] = expand_step128(sks[8], x86._mm_aeskeygenassist_si128(sks[9], 0x10))
sks[11] = expand_step256b(sks[9], x86._mm_aeskeygenassist_si128(sks[10], 0x10))
sks[12] = expand_step128(sks[10], x86._mm_aeskeygenassist_si128(sks[11], 0x20))
sks[13] = expand_step256b(sks[11], x86._mm_aeskeygenassist_si128(sks[12], 0x20))
sks[14] = expand_step128(sks[12], x86._mm_aeskeygenassist_si128(sks[13], 0x40))
num_rounds = _aes.ROUNDS_256
case:
panic("crypto/aes: invalid AES key size")
}
for i in 0 ..= num_rounds {
intrinsics.unaligned_store((^x86.__m128i)(&ctx._sk_exp_enc[i]), sks[i])
}
// Compute the decryption keys. GCM and CTR do not need this, however
// ECB, CBC, OCB3, etc do.
derive_dec_keys(ctx, &sks, num_rounds)
ctx._num_rounds = num_rounds
mem.zero_explicit(&sks, size_of(sks))
}
+123
View File
@@ -0,0 +1,123 @@
package _chacha20
import "base:intrinsics"
import "core:encoding/endian"
import "core:math/bits"
import "core:mem"
// KEY_SIZE is the (X)ChaCha20 key size in bytes.
KEY_SIZE :: 32
// IV_SIZE is the ChaCha20 IV size in bytes.
IV_SIZE :: 12
// XIV_SIZE is the XChaCha20 IV size in bytes.
XIV_SIZE :: 24
// MAX_CTR_IETF is the maximum counter value for the IETF flavor ChaCha20.
MAX_CTR_IETF :: 0xffffffff
// BLOCK_SIZE is the (X)ChaCha20 block size in bytes.
BLOCK_SIZE :: 64
// STATE_SIZE_U32 is the (X)ChaCha20 state size in u32s.
STATE_SIZE_U32 :: 16
// Rounds is the (X)ChaCha20 round count.
ROUNDS :: 20
// SIGMA_0 is sigma[0:4].
SIGMA_0: u32 : 0x61707865
// SIGMA_1 is sigma[4:8].
SIGMA_1: u32 : 0x3320646e
// SIGMA_2 is sigma[8:12].
SIGMA_2: u32 : 0x79622d32
// SIGMA_3 is sigma[12:16].
SIGMA_3: u32 : 0x6b206574
// Context is a ChaCha20 or XChaCha20 instance.
Context :: struct {
_s: [STATE_SIZE_U32]u32,
_buffer: [BLOCK_SIZE]byte,
_off: int,
_is_ietf_flavor: bool,
_is_initialized: bool,
}
// init inititializes a Context for ChaCha20 with the provided key and
// iv.
//
// WARNING: This ONLY handles ChaCha20. XChaCha20 sub-key and IV
// derivation is expected to be handled by the caller, so that the
// HChaCha call can be suitably accelerated.
init :: proc "contextless" (ctx: ^Context, key, iv: []byte, is_xchacha: bool) {
if len(key) != KEY_SIZE || len(iv) != IV_SIZE {
intrinsics.trap()
}
k, n := key, iv
ctx._s[0] = SIGMA_0
ctx._s[1] = SIGMA_1
ctx._s[2] = SIGMA_2
ctx._s[3] = SIGMA_3
ctx._s[4] = endian.unchecked_get_u32le(k[0:4])
ctx._s[5] = endian.unchecked_get_u32le(k[4:8])
ctx._s[6] = endian.unchecked_get_u32le(k[8:12])
ctx._s[7] = endian.unchecked_get_u32le(k[12:16])
ctx._s[8] = endian.unchecked_get_u32le(k[16:20])
ctx._s[9] = endian.unchecked_get_u32le(k[20:24])
ctx._s[10] = endian.unchecked_get_u32le(k[24:28])
ctx._s[11] = endian.unchecked_get_u32le(k[28:32])
ctx._s[12] = 0
ctx._s[13] = endian.unchecked_get_u32le(n[0:4])
ctx._s[14] = endian.unchecked_get_u32le(n[4:8])
ctx._s[15] = endian.unchecked_get_u32le(n[8:12])
ctx._off = BLOCK_SIZE
ctx._is_ietf_flavor = !is_xchacha
ctx._is_initialized = true
}
// seek seeks the (X)ChaCha20 stream counter to the specified block.
seek :: proc(ctx: ^Context, block_nr: u64) {
assert(ctx._is_initialized)
if ctx._is_ietf_flavor {
if block_nr > MAX_CTR_IETF {
panic("crypto/chacha20: attempted to seek past maximum counter")
}
} else {
ctx._s[13] = u32(block_nr >> 32)
}
ctx._s[12] = u32(block_nr)
ctx._off = BLOCK_SIZE
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
mem.zero_explicit(&ctx._s, size_of(ctx._s))
mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer))
ctx._is_initialized = false
}
check_counter_limit :: proc(ctx: ^Context, nr_blocks: int) {
// Enforce the maximum consumed keystream per IV.
//
// While all modern "standard" definitions of ChaCha20 use
// the IETF 32-bit counter, for XChaCha20 most common
// implementations allow for a 64-bit counter.
//
// Honestly, the answer here is "use a MRAE primitive", but
// go with "common" practice in the case of XChaCha20.
ERR_CTR_EXHAUSTED :: "crypto/chacha20: maximum (X)ChaCha20 keystream per IV reached"
if ctx._is_ietf_flavor {
if u64(ctx._s[12]) + u64(nr_blocks) > MAX_CTR_IETF {
panic(ERR_CTR_EXHAUSTED)
}
} else {
ctr := (u64(ctx._s[13]) << 32) | u64(ctx._s[12])
if _, carry := bits.add_u64(ctr, u64(nr_blocks), 0); carry != 0 {
panic(ERR_CTR_EXHAUSTED)
}
}
}
+360
View File
@@ -0,0 +1,360 @@
package chacha20_ref
import "core:crypto/_chacha20"
import "core:encoding/endian"
import "core:math/bits"
stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) {
// Enforce the maximum consumed keystream per IV.
_chacha20.check_counter_limit(ctx, nr_blocks)
dst, src := dst, src
x := &ctx._s
for n := 0; n < nr_blocks; n = n + 1 {
x0, x1, x2, x3 :=
_chacha20.SIGMA_0, _chacha20.SIGMA_1, _chacha20.SIGMA_2, _chacha20.SIGMA_3
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 :=
x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
// Even when forcing inlining manually inlining all of
// these is decently faster.
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ~= x0
x12 = bits.rotate_left32(x12, 16)
x8 += x12
x4 ~= x8
x4 = bits.rotate_left32(x4, 12)
x0 += x4
x12 ~= x0
x12 = bits.rotate_left32(x12, 8)
x8 += x12
x4 ~= x8
x4 = bits.rotate_left32(x4, 7)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ~= x1
x13 = bits.rotate_left32(x13, 16)
x9 += x13
x5 ~= x9
x5 = bits.rotate_left32(x5, 12)
x1 += x5
x13 ~= x1
x13 = bits.rotate_left32(x13, 8)
x9 += x13
x5 ~= x9
x5 = bits.rotate_left32(x5, 7)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ~= x2
x14 = bits.rotate_left32(x14, 16)
x10 += x14
x6 ~= x10
x6 = bits.rotate_left32(x6, 12)
x2 += x6
x14 ~= x2
x14 = bits.rotate_left32(x14, 8)
x10 += x14
x6 ~= x10
x6 = bits.rotate_left32(x6, 7)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ~= x3
x15 = bits.rotate_left32(x15, 16)
x11 += x15
x7 ~= x11
x7 = bits.rotate_left32(x7, 12)
x3 += x7
x15 ~= x3
x15 = bits.rotate_left32(x15, 8)
x11 += x15
x7 ~= x11
x7 = bits.rotate_left32(x7, 7)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ~= x0
x15 = bits.rotate_left32(x15, 16)
x10 += x15
x5 ~= x10
x5 = bits.rotate_left32(x5, 12)
x0 += x5
x15 ~= x0
x15 = bits.rotate_left32(x15, 8)
x10 += x15
x5 ~= x10
x5 = bits.rotate_left32(x5, 7)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ~= x1
x12 = bits.rotate_left32(x12, 16)
x11 += x12
x6 ~= x11
x6 = bits.rotate_left32(x6, 12)
x1 += x6
x12 ~= x1
x12 = bits.rotate_left32(x12, 8)
x11 += x12
x6 ~= x11
x6 = bits.rotate_left32(x6, 7)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ~= x2
x13 = bits.rotate_left32(x13, 16)
x8 += x13
x7 ~= x8
x7 = bits.rotate_left32(x7, 12)
x2 += x7
x13 ~= x2
x13 = bits.rotate_left32(x13, 8)
x8 += x13
x7 ~= x8
x7 = bits.rotate_left32(x7, 7)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ~= x3
x14 = bits.rotate_left32(x14, 16)
x9 += x14
x4 ~= x9
x4 = bits.rotate_left32(x4, 12)
x3 += x4
x14 ~= x3
x14 = bits.rotate_left32(x14, 8)
x9 += x14
x4 ~= x9
x4 = bits.rotate_left32(x4, 7)
}
x0 += _chacha20.SIGMA_0
x1 += _chacha20.SIGMA_1
x2 += _chacha20.SIGMA_2
x3 += _chacha20.SIGMA_3
x4 += x[4]
x5 += x[5]
x6 += x[6]
x7 += x[7]
x8 += x[8]
x9 += x[9]
x10 += x[10]
x11 += x[11]
x12 += x[12]
x13 += x[13]
x14 += x[14]
x15 += x[15]
// - The caller(s) ensure that src/dst are valid.
// - The compiler knows if the target is picky about alignment.
#no_bounds_check {
if src != nil {
endian.unchecked_put_u32le(dst[0:4], endian.unchecked_get_u32le(src[0:4]) ~ x0)
endian.unchecked_put_u32le(dst[4:8], endian.unchecked_get_u32le(src[4:8]) ~ x1)
endian.unchecked_put_u32le(dst[8:12], endian.unchecked_get_u32le(src[8:12]) ~ x2)
endian.unchecked_put_u32le(dst[12:16], endian.unchecked_get_u32le(src[12:16]) ~ x3)
endian.unchecked_put_u32le(dst[16:20], endian.unchecked_get_u32le(src[16:20]) ~ x4)
endian.unchecked_put_u32le(dst[20:24], endian.unchecked_get_u32le(src[20:24]) ~ x5)
endian.unchecked_put_u32le(dst[24:28], endian.unchecked_get_u32le(src[24:28]) ~ x6)
endian.unchecked_put_u32le(dst[28:32], endian.unchecked_get_u32le(src[28:32]) ~ x7)
endian.unchecked_put_u32le(dst[32:36], endian.unchecked_get_u32le(src[32:36]) ~ x8)
endian.unchecked_put_u32le(dst[36:40], endian.unchecked_get_u32le(src[36:40]) ~ x9)
endian.unchecked_put_u32le(
dst[40:44],
endian.unchecked_get_u32le(src[40:44]) ~ x10,
)
endian.unchecked_put_u32le(
dst[44:48],
endian.unchecked_get_u32le(src[44:48]) ~ x11,
)
endian.unchecked_put_u32le(
dst[48:52],
endian.unchecked_get_u32le(src[48:52]) ~ x12,
)
endian.unchecked_put_u32le(
dst[52:56],
endian.unchecked_get_u32le(src[52:56]) ~ x13,
)
endian.unchecked_put_u32le(
dst[56:60],
endian.unchecked_get_u32le(src[56:60]) ~ x14,
)
endian.unchecked_put_u32le(
dst[60:64],
endian.unchecked_get_u32le(src[60:64]) ~ x15,
)
src = src[_chacha20.BLOCK_SIZE:]
} else {
endian.unchecked_put_u32le(dst[0:4], x0)
endian.unchecked_put_u32le(dst[4:8], x1)
endian.unchecked_put_u32le(dst[8:12], x2)
endian.unchecked_put_u32le(dst[12:16], x3)
endian.unchecked_put_u32le(dst[16:20], x4)
endian.unchecked_put_u32le(dst[20:24], x5)
endian.unchecked_put_u32le(dst[24:28], x6)
endian.unchecked_put_u32le(dst[28:32], x7)
endian.unchecked_put_u32le(dst[32:36], x8)
endian.unchecked_put_u32le(dst[36:40], x9)
endian.unchecked_put_u32le(dst[40:44], x10)
endian.unchecked_put_u32le(dst[44:48], x11)
endian.unchecked_put_u32le(dst[48:52], x12)
endian.unchecked_put_u32le(dst[52:56], x13)
endian.unchecked_put_u32le(dst[56:60], x14)
endian.unchecked_put_u32le(dst[60:64], x15)
}
dst = dst[_chacha20.BLOCK_SIZE:]
}
// Increment the counter. Overflow checking is done upon
// entry into the routine, so a 64-bit increment safely
// covers both cases.
new_ctr := ((u64(ctx._s[13]) << 32) | u64(ctx._s[12])) + 1
x[12] = u32(new_ctr)
x[13] = u32(new_ctr >> 32)
}
}
hchacha20 :: proc "contextless" (dst, key, iv: []byte) {
x0, x1, x2, x3 := _chacha20.SIGMA_0, _chacha20.SIGMA_1, _chacha20.SIGMA_2, _chacha20.SIGMA_3
x4 := endian.unchecked_get_u32le(key[0:4])
x5 := endian.unchecked_get_u32le(key[4:8])
x6 := endian.unchecked_get_u32le(key[8:12])
x7 := endian.unchecked_get_u32le(key[12:16])
x8 := endian.unchecked_get_u32le(key[16:20])
x9 := endian.unchecked_get_u32le(key[20:24])
x10 := endian.unchecked_get_u32le(key[24:28])
x11 := endian.unchecked_get_u32le(key[28:32])
x12 := endian.unchecked_get_u32le(iv[0:4])
x13 := endian.unchecked_get_u32le(iv[4:8])
x14 := endian.unchecked_get_u32le(iv[8:12])
x15 := endian.unchecked_get_u32le(iv[12:16])
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ~= x0
x12 = bits.rotate_left32(x12, 16)
x8 += x12
x4 ~= x8
x4 = bits.rotate_left32(x4, 12)
x0 += x4
x12 ~= x0
x12 = bits.rotate_left32(x12, 8)
x8 += x12
x4 ~= x8
x4 = bits.rotate_left32(x4, 7)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ~= x1
x13 = bits.rotate_left32(x13, 16)
x9 += x13
x5 ~= x9
x5 = bits.rotate_left32(x5, 12)
x1 += x5
x13 ~= x1
x13 = bits.rotate_left32(x13, 8)
x9 += x13
x5 ~= x9
x5 = bits.rotate_left32(x5, 7)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ~= x2
x14 = bits.rotate_left32(x14, 16)
x10 += x14
x6 ~= x10
x6 = bits.rotate_left32(x6, 12)
x2 += x6
x14 ~= x2
x14 = bits.rotate_left32(x14, 8)
x10 += x14
x6 ~= x10
x6 = bits.rotate_left32(x6, 7)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ~= x3
x15 = bits.rotate_left32(x15, 16)
x11 += x15
x7 ~= x11
x7 = bits.rotate_left32(x7, 12)
x3 += x7
x15 ~= x3
x15 = bits.rotate_left32(x15, 8)
x11 += x15
x7 ~= x11
x7 = bits.rotate_left32(x7, 7)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ~= x0
x15 = bits.rotate_left32(x15, 16)
x10 += x15
x5 ~= x10
x5 = bits.rotate_left32(x5, 12)
x0 += x5
x15 ~= x0
x15 = bits.rotate_left32(x15, 8)
x10 += x15
x5 ~= x10
x5 = bits.rotate_left32(x5, 7)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ~= x1
x12 = bits.rotate_left32(x12, 16)
x11 += x12
x6 ~= x11
x6 = bits.rotate_left32(x6, 12)
x1 += x6
x12 ~= x1
x12 = bits.rotate_left32(x12, 8)
x11 += x12
x6 ~= x11
x6 = bits.rotate_left32(x6, 7)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ~= x2
x13 = bits.rotate_left32(x13, 16)
x8 += x13
x7 ~= x8
x7 = bits.rotate_left32(x7, 12)
x2 += x7
x13 ~= x2
x13 = bits.rotate_left32(x13, 8)
x8 += x13
x7 ~= x8
x7 = bits.rotate_left32(x7, 7)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ~= x3
x14 = bits.rotate_left32(x14, 16)
x9 += x14
x4 ~= x9
x4 = bits.rotate_left32(x4, 12)
x3 += x4
x14 ~= x3
x14 = bits.rotate_left32(x14, 8)
x9 += x14
x4 ~= x9
x4 = bits.rotate_left32(x4, 7)
}
endian.unchecked_put_u32le(dst[0:4], x0)
endian.unchecked_put_u32le(dst[4:8], x1)
endian.unchecked_put_u32le(dst[8:12], x2)
endian.unchecked_put_u32le(dst[12:16], x3)
endian.unchecked_put_u32le(dst[16:20], x12)
endian.unchecked_put_u32le(dst[20:24], x13)
endian.unchecked_put_u32le(dst[24:28], x14)
endian.unchecked_put_u32le(dst[28:32], x15)
}
@@ -0,0 +1,481 @@
package chacha20_simd128
import "base:intrinsics"
import "core:crypto/_chacha20"
import "core:simd"
@(require) import "core:sys/info"
// Portable 128-bit `core:simd` implementation.
//
// This is loosely based on Ted Krovetz's public domain C intrinsic
// implementation.
//
// This is written to perform adequately on any target that has "enough"
// 128-bit vector registers, the current thought is that 4 blocks at at
// time is reasonable for amd64, though Ted's code is more conservative.
//
// See:
// supercop-20230530/crypto_stream/chacha20/krovetz/vec128
// Ensure the compiler emits SIMD instructions. This is a minimum, and
// setting the microarchitecture at compile time will allow for better
// code gen when applicable (eg: AVX). This is somewhat redundant with
// the default microarchitecture configurations.
when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 {
@(private = "file")
TARGET_SIMD_FEATURES :: "neon"
} else when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 {
// Note: LLVM appears to be smart enough to use PSHUFB despite not
// explicitly using simd.u8x16 shuffles.
@(private = "file")
TARGET_SIMD_FEATURES :: "sse2,ssse3"
} else {
@(private = "file")
TARGET_SIMD_FEATURES :: ""
}
@(private = "file")
_ROT_7L: simd.u32x4 : {7, 7, 7, 7}
@(private = "file")
_ROT_7R: simd.u32x4 : {25, 25, 25, 25}
@(private = "file")
_ROT_12L: simd.u32x4 : {12, 12, 12, 12}
@(private = "file")
_ROT_12R: simd.u32x4 : {20, 20, 20, 20}
@(private = "file")
_ROT_8L: simd.u32x4 : {8, 8, 8, 8}
@(private = "file")
_ROT_8R: simd.u32x4 : {24, 24, 24, 24}
@(private = "file")
_ROT_16: simd.u32x4 : {16, 16, 16, 16}
when ODIN_ENDIAN == .Big {
@(private = "file")
_increment_counter :: #force_inline proc "contextless" (ctx: ^Context) -> simd.u32x4 {
// In the Big Endian case, the low and high portions in the vector
// are flipped, so the 64-bit addition can't be done with a simple
// vector add.
x := &ctx._s
new_ctr := ((u64(ctx._s[13]) << 32) | u64(ctx._s[12])) + 1
x[12] = u32(new_ctr)
x[13] = u32(new_ctr >> 32)
return intrinsics.unaligned_load(transmute(^simd.u32x4)&x[12])
}
// Convert the endian-ness of the components of a u32x4 vector, for
// the purposes of output.
@(private = "file")
_byteswap_u32x4 :: #force_inline proc "contextless" (v: simd.u32x4) -> simd.u32x4 {
return(
transmute(simd.u32x4)simd.shuffle(
transmute(simd.u8x16)v,
transmute(simd.u8x16)v,
3, 2, 1, 0, 7, 6, 5, 4, 11, 10, 9, 8, 15, 14, 13, 12,
)
)
}
} else {
@(private = "file")
_VEC_ONE: simd.u64x2 : {1, 0}
}
@(private = "file")
_dq_round_simd128 :: #force_inline proc "contextless" (
v0, v1, v2, v3: simd.u32x4,
) -> (
simd.u32x4,
simd.u32x4,
simd.u32x4,
simd.u32x4,
) {
v0, v1, v2, v3 := v0, v1, v2, v3
// a += b; d ^= a; d = ROTW16(d);
v0 = simd.add(v0, v1)
v3 = simd.bit_xor(v3, v0)
v3 = simd.bit_xor(simd.shl(v3, _ROT_16), simd.shr(v3, _ROT_16))
// c += d; b ^= c; b = ROTW12(b);
v2 = simd.add(v2, v3)
v1 = simd.bit_xor(v1, v2)
v1 = simd.bit_xor(simd.shl(v1, _ROT_12L), simd.shr(v1, _ROT_12R))
// a += b; d ^= a; d = ROTW8(d);
v0 = simd.add(v0, v1)
v3 = simd.bit_xor(v3, v0)
v3 = simd.bit_xor(simd.shl(v3, _ROT_8L), simd.shr(v3, _ROT_8R))
// c += d; b ^= c; b = ROTW7(b);
v2 = simd.add(v2, v3)
v1 = simd.bit_xor(v1, v2)
v1 = simd.bit_xor(simd.shl(v1, _ROT_7L), simd.shr(v1, _ROT_7R))
// b = ROTV1(b); c = ROTV2(c); d = ROTV3(d);
v1 = simd.shuffle(v1, v1, 1, 2, 3, 0)
v2 = simd.shuffle(v2, v2, 2, 3, 0, 1)
v3 = simd.shuffle(v3, v3, 3, 0, 1, 2)
// a += b; d ^= a; d = ROTW16(d);
v0 = simd.add(v0, v1)
v3 = simd.bit_xor(v3, v0)
v3 = simd.bit_xor(simd.shl(v3, _ROT_16), simd.shr(v3, _ROT_16))
// c += d; b ^= c; b = ROTW12(b);
v2 = simd.add(v2, v3)
v1 = simd.bit_xor(v1, v2)
v1 = simd.bit_xor(simd.shl(v1, _ROT_12L), simd.shr(v1, _ROT_12R))
// a += b; d ^= a; d = ROTW8(d);
v0 = simd.add(v0, v1)
v3 = simd.bit_xor(v3, v0)
v3 = simd.bit_xor(simd.shl(v3, _ROT_8L), simd.shr(v3, _ROT_8R))
// c += d; b ^= c; b = ROTW7(b);
v2 = simd.add(v2, v3)
v1 = simd.bit_xor(v1, v2)
v1 = simd.bit_xor(simd.shl(v1, _ROT_7L), simd.shr(v1, _ROT_7R))
// b = ROTV3(b); c = ROTV2(c); d = ROTV1(d);
v1 = simd.shuffle(v1, v1, 3, 0, 1, 2)
v2 = simd.shuffle(v2, v2, 2, 3, 0, 1)
v3 = simd.shuffle(v3, v3, 1, 2, 3, 0)
return v0, v1, v2, v3
}
@(private = "file")
_add_state_simd128 :: #force_inline proc "contextless" (
v0, v1, v2, v3, s0, s1, s2, s3: simd.u32x4,
) -> (
simd.u32x4,
simd.u32x4,
simd.u32x4,
simd.u32x4,
) {
v0, v1, v2, v3 := v0, v1, v2, v3
v0 = simd.add(v0, s0)
v1 = simd.add(v1, s1)
v2 = simd.add(v2, s2)
v3 = simd.add(v3, s3)
when ODIN_ENDIAN == .Big {
v0 = _byteswap_u32x4(v0)
v1 = _byteswap_u32x4(v1)
v2 = _byteswap_u32x4(v2)
v3 = _byteswap_u32x4(v3)
}
return v0, v1, v2, v3
}
@(private = "file")
_xor_simd128 :: #force_inline proc "contextless" (
src: [^]simd.u32x4,
v0, v1, v2, v3: simd.u32x4,
) -> (
simd.u32x4,
simd.u32x4,
simd.u32x4,
simd.u32x4,
) {
v0, v1, v2, v3 := v0, v1, v2, v3
v0 = simd.bit_xor(v0, intrinsics.unaligned_load((^simd.u32x4)(src[0:])))
v1 = simd.bit_xor(v1, intrinsics.unaligned_load((^simd.u32x4)(src[1:])))
v2 = simd.bit_xor(v2, intrinsics.unaligned_load((^simd.u32x4)(src[2:])))
v3 = simd.bit_xor(v3, intrinsics.unaligned_load((^simd.u32x4)(src[3:])))
return v0, v1, v2, v3
}
@(private = "file")
_store_simd128 :: #force_inline proc "contextless" (
dst: [^]simd.u32x4,
v0, v1, v2, v3: simd.u32x4,
) {
intrinsics.unaligned_store((^simd.u32x4)(dst[0:]), v0)
intrinsics.unaligned_store((^simd.u32x4)(dst[1:]), v1)
intrinsics.unaligned_store((^simd.u32x4)(dst[2:]), v2)
intrinsics.unaligned_store((^simd.u32x4)(dst[3:]), v3)
}
// is_performant returns true iff the target and current host both support
// "enough" 128-bit SIMD to make this implementation performant.
is_performant :: proc "contextless" () -> bool {
when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 || ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 {
when ODIN_ARCH == .arm64 || ODIN_ARCH == .arm32 {
req_features :: info.CPU_Features{.asimd}
} else when ODIN_ARCH == .amd64 || ODIN_ARCH == .i386 {
req_features :: info.CPU_Features{.sse2, .ssse3}
}
features, ok := info.cpu_features.?
if !ok {
return false
}
return features >= req_features
} else when ODIN_ARCH == .wasm64p32 || ODIN_ARCH == .wasm32 {
return intrinsics.has_target_feature("simd128")
} else {
return false
}
}
@(enable_target_feature = TARGET_SIMD_FEATURES)
stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) {
// Enforce the maximum consumed keystream per IV.
_chacha20.check_counter_limit(ctx, nr_blocks)
dst_v := ([^]simd.u32x4)(raw_data(dst))
src_v := ([^]simd.u32x4)(raw_data(src))
x := &ctx._s
n := nr_blocks
// The state vector is an array of uint32s in native byte-order.
x_v := ([^]simd.u32x4)(raw_data(x))
s0 := intrinsics.unaligned_load((^simd.u32x4)(x_v[0:]))
s1 := intrinsics.unaligned_load((^simd.u32x4)(x_v[1:]))
s2 := intrinsics.unaligned_load((^simd.u32x4)(x_v[2:]))
s3 := intrinsics.unaligned_load((^simd.u32x4)(x_v[3:]))
// 8 blocks at a time.
//
// Note: This is only worth it on Aarch64.
when ODIN_ARCH == .arm64 {
for ; n >= 8; n = n - 8 {
v0, v1, v2, v3 := s0, s1, s2, s3
when ODIN_ENDIAN == .Little {
s7 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s3, _VEC_ONE)
} else {
s7 := _increment_counter(ctx)
}
v4, v5, v6, v7 := s0, s1, s2, s7
when ODIN_ENDIAN == .Little {
s11 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s7, _VEC_ONE)
} else {
s11 := _increment_counter(ctx)
}
v8, v9, v10, v11 := s0, s1, s2, s11
when ODIN_ENDIAN == .Little {
s15 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s11, _VEC_ONE)
} else {
s15 := _increment_counter(ctx)
}
v12, v13, v14, v15 := s0, s1, s2, s15
when ODIN_ENDIAN == .Little {
s19 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s15, _VEC_ONE)
} else {
s19 := _increment_counter(ctx)
}
v16, v17, v18, v19 := s0, s1, s2, s19
when ODIN_ENDIAN == .Little {
s23 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s19, _VEC_ONE)
} else {
s23 := _increment_counter(ctx)
}
v20, v21, v22, v23 := s0, s1, s2, s23
when ODIN_ENDIAN == .Little {
s27 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s23, _VEC_ONE)
} else {
s27 := _increment_counter(ctx)
}
v24, v25, v26, v27 := s0, s1, s2, s27
when ODIN_ENDIAN == .Little {
s31 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s27, _VEC_ONE)
} else {
s31 := _increment_counter(ctx)
}
v28, v29, v30, v31 := s0, s1, s2, s31
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
v0, v1, v2, v3 = _dq_round_simd128(v0, v1, v2, v3)
v4, v5, v6, v7 = _dq_round_simd128(v4, v5, v6, v7)
v8, v9, v10, v11 = _dq_round_simd128(v8, v9, v10, v11)
v12, v13, v14, v15 = _dq_round_simd128(v12, v13, v14, v15)
v16, v17, v18, v19 = _dq_round_simd128(v16, v17, v18, v19)
v20, v21, v22, v23 = _dq_round_simd128(v20, v21, v22, v23)
v24, v25, v26, v27 = _dq_round_simd128(v24, v25, v26, v27)
v28, v29, v30, v31 = _dq_round_simd128(v28, v29, v30, v31)
}
v0, v1, v2, v3 = _add_state_simd128(v0, v1, v2, v3, s0, s1, s2, s3)
v4, v5, v6, v7 = _add_state_simd128(v4, v5, v6, v7, s0, s1, s2, s7)
v8, v9, v10, v11 = _add_state_simd128(v8, v9, v10, v11, s0, s1, s2, s11)
v12, v13, v14, v15 = _add_state_simd128(v12, v13, v14, v15, s0, s1, s2, s15)
v16, v17, v18, v19 = _add_state_simd128(v16, v17, v18, v19, s0, s1, s2, s19)
v20, v21, v22, v23 = _add_state_simd128(v20, v21, v22, v23, s0, s1, s2, s23)
v24, v25, v26, v27 = _add_state_simd128(v24, v25, v26, v27, s0, s1, s2, s27)
v28, v29, v30, v31 = _add_state_simd128(v28, v29, v30, v31, s0, s1, s2, s31)
#no_bounds_check {
if src != nil {
v0, v1, v2, v3 = _xor_simd128(src_v, v0, v1, v2, v3)
v4, v5, v6, v7 = _xor_simd128(src_v[4:], v4, v5, v6, v7)
v8, v9, v10, v11 = _xor_simd128(src_v[8:], v8, v9, v10, v11)
v12, v13, v14, v15 = _xor_simd128(src_v[12:], v12, v13, v14, v15)
v16, v17, v18, v19 = _xor_simd128(src_v[16:], v16, v17, v18, v19)
v20, v21, v22, v23 = _xor_simd128(src_v[20:], v20, v21, v22, v23)
v24, v25, v26, v27 = _xor_simd128(src_v[24:], v24, v25, v26, v27)
v28, v29, v30, v31 = _xor_simd128(src_v[28:], v28, v29, v30, v31)
src_v = src_v[32:]
}
_store_simd128(dst_v, v0, v1, v2, v3)
_store_simd128(dst_v[4:], v4, v5, v6, v7)
_store_simd128(dst_v[8:], v8, v9, v10, v11)
_store_simd128(dst_v[12:], v12, v13, v14, v15)
_store_simd128(dst_v[16:], v16, v17, v18, v19)
_store_simd128(dst_v[20:], v20, v21, v22, v23)
_store_simd128(dst_v[24:], v24, v25, v26, v27)
_store_simd128(dst_v[28:], v28, v29, v30, v31)
dst_v = dst_v[32:]
}
when ODIN_ENDIAN == .Little {
// s31 holds the most current counter, so `s3 = s31 + 1`.
s3 = transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s31, _VEC_ONE)
} else {
s3 = _increment_counter(ctx)
}
}
}
// 4 blocks at a time.
//
// Note: The i386 target lacks the required number of registers
// for this to be performant, so it is skipped.
when ODIN_ARCH != .i386 {
for ; n >= 4; n = n - 4 {
v0, v1, v2, v3 := s0, s1, s2, s3
when ODIN_ENDIAN == .Little {
s7 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s3, _VEC_ONE)
} else {
s7 := _increment_counter(ctx)
}
v4, v5, v6, v7 := s0, s1, s2, s7
when ODIN_ENDIAN == .Little {
s11 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s7, _VEC_ONE)
} else {
s11 := _increment_counter(ctx)
}
v8, v9, v10, v11 := s0, s1, s2, s11
when ODIN_ENDIAN == .Little {
s15 := transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s11, _VEC_ONE)
} else {
s15 := _increment_counter(ctx)
}
v12, v13, v14, v15 := s0, s1, s2, s15
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
v0, v1, v2, v3 = _dq_round_simd128(v0, v1, v2, v3)
v4, v5, v6, v7 = _dq_round_simd128(v4, v5, v6, v7)
v8, v9, v10, v11 = _dq_round_simd128(v8, v9, v10, v11)
v12, v13, v14, v15 = _dq_round_simd128(v12, v13, v14, v15)
}
v0, v1, v2, v3 = _add_state_simd128(v0, v1, v2, v3, s0, s1, s2, s3)
v4, v5, v6, v7 = _add_state_simd128(v4, v5, v6, v7, s0, s1, s2, s7)
v8, v9, v10, v11 = _add_state_simd128(v8, v9, v10, v11, s0, s1, s2, s11)
v12, v13, v14, v15 = _add_state_simd128(v12, v13, v14, v15, s0, s1, s2, s15)
#no_bounds_check {
if src != nil {
v0, v1, v2, v3 = _xor_simd128(src_v, v0, v1, v2, v3)
v4, v5, v6, v7 = _xor_simd128(src_v[4:], v4, v5, v6, v7)
v8, v9, v10, v11 = _xor_simd128(src_v[8:], v8, v9, v10, v11)
v12, v13, v14, v15 = _xor_simd128(src_v[12:], v12, v13, v14, v15)
src_v = src_v[16:]
}
_store_simd128(dst_v, v0, v1, v2, v3)
_store_simd128(dst_v[4:], v4, v5, v6, v7)
_store_simd128(dst_v[8:], v8, v9, v10, v11)
_store_simd128(dst_v[12:], v12, v13, v14, v15)
dst_v = dst_v[16:]
}
when ODIN_ENDIAN == .Little {
// s15 holds the most current counter, so `s3 = s15 + 1`.
s3 = transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s15, _VEC_ONE)
} else {
s3 = _increment_counter(ctx)
}
}
}
// 1 block at a time.
for ; n > 0; n = n - 1 {
v0, v1, v2, v3 := s0, s1, s2, s3
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
v0, v1, v2, v3 = _dq_round_simd128(v0, v1, v2, v3)
}
v0, v1, v2, v3 = _add_state_simd128(v0, v1, v2, v3, s0, s1, s2, s3)
#no_bounds_check {
if src != nil {
v0, v1, v2, v3 = _xor_simd128(src_v, v0, v1, v2, v3)
src_v = src_v[4:]
}
_store_simd128(dst_v, v0, v1, v2, v3)
dst_v = dst_v[4:]
}
// Increment the counter. Overflow checking is done upon
// entry into the routine, so a 64-bit increment safely
// covers both cases.
when ODIN_ENDIAN == .Little {
s3 = transmute(simd.u32x4)simd.add(transmute(simd.u64x2)s3, _VEC_ONE)
} else {
s3 = _increment_counter(ctx)
}
}
when ODIN_ENDIAN == .Little {
// Write back the counter to the state.
intrinsics.unaligned_store((^simd.u32x4)(x_v[3:]), s3)
}
}
@(enable_target_feature = TARGET_SIMD_FEATURES)
hchacha20 :: proc "contextless" (dst, key, iv: []byte) {
v0 := simd.u32x4{_chacha20.SIGMA_0, _chacha20.SIGMA_1, _chacha20.SIGMA_2, _chacha20.SIGMA_3}
v1 := intrinsics.unaligned_load((^simd.u32x4)(&key[0]))
v2 := intrinsics.unaligned_load((^simd.u32x4)(&key[16]))
v3 := intrinsics.unaligned_load((^simd.u32x4)(&iv[0]))
when ODIN_ENDIAN == .Big {
v1 = _byteswap_u32x4(v1)
v2 = _byteswap_u32x4(v2)
v3 = _byteswap_u32x4(v3)
}
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
v0, v1, v2, v3 = _dq_round_simd128(v0, v1, v2, v3)
}
when ODIN_ENDIAN == .Big {
v0 = _byteswap_u32x4(v0)
v3 = _byteswap_u32x4(v3)
}
dst_v := ([^]simd.u32x4)(raw_data(dst))
intrinsics.unaligned_store((^simd.u32x4)(dst_v[0:]), v0)
intrinsics.unaligned_store((^simd.u32x4)(dst_v[1:]), v3)
}
@@ -0,0 +1,319 @@
//+build amd64
package chacha20_simd256
import "base:intrinsics"
import "core:crypto/_chacha20"
import chacha_simd128 "core:crypto/_chacha20/simd128"
import "core:simd"
import "core:sys/info"
// This is loosely based on Ted Krovetz's public domain C intrinsic
// implementations. While written using `core:simd`, this is currently
// amd64 specific because we do not have a way to detect ARM SVE.
//
// See:
// supercop-20230530/crypto_stream/chacha20/krovetz/vec128
// supercop-20230530/crypto_stream/chacha20/krovetz/avx2
#assert(ODIN_ENDIAN == .Little)
@(private = "file")
_ROT_7L: simd.u32x8 : {7, 7, 7, 7, 7, 7, 7, 7}
@(private = "file")
_ROT_7R: simd.u32x8 : {25, 25, 25, 25, 25, 25, 25, 25}
@(private = "file")
_ROT_12L: simd.u32x8 : {12, 12, 12, 12, 12, 12, 12, 12}
@(private = "file")
_ROT_12R: simd.u32x8 : {20, 20, 20, 20, 20, 20, 20, 20}
@(private = "file")
_ROT_8L: simd.u32x8 : {8, 8, 8, 8, 8, 8, 8, 8}
@(private = "file")
_ROT_8R: simd.u32x8 : {24, 24, 24, 24, 24, 24, 24, 24}
@(private = "file")
_ROT_16: simd.u32x8 : {16, 16, 16, 16, 16, 16, 16, 16}
@(private = "file")
_VEC_ZERO_ONE: simd.u64x4 : {0, 0, 1, 0}
@(private = "file")
_VEC_TWO: simd.u64x4 : {2, 0, 2, 0}
// is_performant returns true iff the target and current host both support
// "enough" SIMD to make this implementation performant.
is_performant :: proc "contextless" () -> bool {
req_features :: info.CPU_Features{.avx, .avx2}
features, ok := info.cpu_features.?
if !ok {
return false
}
return features >= req_features
}
@(private = "file")
_dq_round_simd256 :: #force_inline proc "contextless" (
v0, v1, v2, v3: simd.u32x8,
) -> (
simd.u32x8,
simd.u32x8,
simd.u32x8,
simd.u32x8,
) {
v0, v1, v2, v3 := v0, v1, v2, v3
// a += b; d ^= a; d = ROTW16(d);
v0 = simd.add(v0, v1)
v3 = simd.bit_xor(v3, v0)
v3 = simd.bit_xor(simd.shl(v3, _ROT_16), simd.shr(v3, _ROT_16))
// c += d; b ^= c; b = ROTW12(b);
v2 = simd.add(v2, v3)
v1 = simd.bit_xor(v1, v2)
v1 = simd.bit_xor(simd.shl(v1, _ROT_12L), simd.shr(v1, _ROT_12R))
// a += b; d ^= a; d = ROTW8(d);
v0 = simd.add(v0, v1)
v3 = simd.bit_xor(v3, v0)
v3 = simd.bit_xor(simd.shl(v3, _ROT_8L), simd.shr(v3, _ROT_8R))
// c += d; b ^= c; b = ROTW7(b);
v2 = simd.add(v2, v3)
v1 = simd.bit_xor(v1, v2)
v1 = simd.bit_xor(simd.shl(v1, _ROT_7L), simd.shr(v1, _ROT_7R))
// b = ROTV1(b); c = ROTV2(c); d = ROTV3(d);
v1 = simd.shuffle(v1, v1, 1, 2, 3, 0, 5, 6, 7, 4)
v2 = simd.shuffle(v2, v2, 2, 3, 0, 1, 6, 7, 4, 5)
v3 = simd.shuffle(v3, v3, 3, 0, 1, 2, 7, 4, 5, 6)
// a += b; d ^= a; d = ROTW16(d);
v0 = simd.add(v0, v1)
v3 = simd.bit_xor(v3, v0)
v3 = simd.bit_xor(simd.shl(v3, _ROT_16), simd.shr(v3, _ROT_16))
// c += d; b ^= c; b = ROTW12(b);
v2 = simd.add(v2, v3)
v1 = simd.bit_xor(v1, v2)
v1 = simd.bit_xor(simd.shl(v1, _ROT_12L), simd.shr(v1, _ROT_12R))
// a += b; d ^= a; d = ROTW8(d);
v0 = simd.add(v0, v1)
v3 = simd.bit_xor(v3, v0)
v3 = simd.bit_xor(simd.shl(v3, _ROT_8L), simd.shr(v3, _ROT_8R))
// c += d; b ^= c; b = ROTW7(b);
v2 = simd.add(v2, v3)
v1 = simd.bit_xor(v1, v2)
v1 = simd.bit_xor(simd.shl(v1, _ROT_7L), simd.shr(v1, _ROT_7R))
// b = ROTV3(b); c = ROTV2(c); d = ROTV1(d);
v1 = simd.shuffle(v1, v1, 3, 0, 1, 2, 7, 4, 5, 6)
v2 = simd.shuffle(v2, v2, 2, 3, 0, 1, 6, 7, 4, 5)
v3 = simd.shuffle(v3, v3, 1, 2, 3, 0, 5, 6, 7, 4)
return v0, v1, v2, v3
}
@(private = "file")
_add_and_permute_state_simd256 :: #force_inline proc "contextless" (
v0, v1, v2, v3, s0, s1, s2, s3: simd.u32x8,
) -> (
simd.u32x8,
simd.u32x8,
simd.u32x8,
simd.u32x8,
) {
t0 := simd.add(v0, s0)
t1 := simd.add(v1, s1)
t2 := simd.add(v2, s2)
t3 := simd.add(v3, s3)
// Big Endian would byteswap here.
// Each of v0 .. v3 has 128-bits of keystream for 2 separate blocks.
// permute the state such that (r0, r1) contains block 0, and (r2, r3)
// contains block 1.
r0 := simd.shuffle(t0, t1, 0, 1, 2, 3, 8, 9, 10, 11)
r2 := simd.shuffle(t0, t1, 4, 5, 6, 7, 12, 13, 14, 15)
r1 := simd.shuffle(t2, t3, 0, 1, 2, 3, 8, 9, 10, 11)
r3 := simd.shuffle(t2, t3, 4, 5, 6, 7, 12, 13, 14, 15)
return r0, r1, r2, r3
}
@(private = "file")
_xor_simd256 :: #force_inline proc "contextless" (
src: [^]simd.u32x8,
v0, v1, v2, v3: simd.u32x8,
) -> (
simd.u32x8,
simd.u32x8,
simd.u32x8,
simd.u32x8,
) {
v0, v1, v2, v3 := v0, v1, v2, v3
v0 = simd.bit_xor(v0, intrinsics.unaligned_load((^simd.u32x8)(src[0:])))
v1 = simd.bit_xor(v1, intrinsics.unaligned_load((^simd.u32x8)(src[1:])))
v2 = simd.bit_xor(v2, intrinsics.unaligned_load((^simd.u32x8)(src[2:])))
v3 = simd.bit_xor(v3, intrinsics.unaligned_load((^simd.u32x8)(src[3:])))
return v0, v1, v2, v3
}
@(private = "file")
_xor_simd256_x1 :: #force_inline proc "contextless" (
src: [^]simd.u32x8,
v0, v1: simd.u32x8,
) -> (
simd.u32x8,
simd.u32x8,
) {
v0, v1 := v0, v1
v0 = simd.bit_xor(v0, intrinsics.unaligned_load((^simd.u32x8)(src[0:])))
v1 = simd.bit_xor(v1, intrinsics.unaligned_load((^simd.u32x8)(src[1:])))
return v0, v1
}
@(private = "file")
_store_simd256 :: #force_inline proc "contextless" (
dst: [^]simd.u32x8,
v0, v1, v2, v3: simd.u32x8,
) {
intrinsics.unaligned_store((^simd.u32x8)(dst[0:]), v0)
intrinsics.unaligned_store((^simd.u32x8)(dst[1:]), v1)
intrinsics.unaligned_store((^simd.u32x8)(dst[2:]), v2)
intrinsics.unaligned_store((^simd.u32x8)(dst[3:]), v3)
}
@(private = "file")
_store_simd256_x1 :: #force_inline proc "contextless" (
dst: [^]simd.u32x8,
v0, v1: simd.u32x8,
) {
intrinsics.unaligned_store((^simd.u32x8)(dst[0:]), v0)
intrinsics.unaligned_store((^simd.u32x8)(dst[1:]), v1)
}
@(enable_target_feature = "sse2,ssse3,avx,avx2")
stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) {
// Enforce the maximum consumed keystream per IV.
_chacha20.check_counter_limit(ctx, nr_blocks)
dst_v := ([^]simd.u32x8)(raw_data(dst))
src_v := ([^]simd.u32x8)(raw_data(src))
x := &ctx._s
n := nr_blocks
// The state vector is an array of uint32s in native byte-order.
// Setup s0 .. s3 such that each register stores 2 copies of the
// state.
x_v := ([^]simd.u32x4)(raw_data(x))
t0 := intrinsics.unaligned_load((^simd.u32x4)(x_v[0:]))
t1 := intrinsics.unaligned_load((^simd.u32x4)(x_v[1:]))
t2 := intrinsics.unaligned_load((^simd.u32x4)(x_v[2:]))
t3 := intrinsics.unaligned_load((^simd.u32x4)(x_v[3:]))
s0 := simd.swizzle(t0, 0, 1, 2, 3, 0, 1, 2, 3)
s1 := simd.swizzle(t1, 0, 1, 2, 3, 0, 1, 2, 3)
s2 := simd.swizzle(t2, 0, 1, 2, 3, 0, 1, 2, 3)
s3 := simd.swizzle(t3, 0, 1, 2, 3, 0, 1, 2, 3)
// Advance the counter in the 2nd copy of the state by one.
s3 = transmute(simd.u32x8)simd.add(transmute(simd.u64x4)s3, _VEC_ZERO_ONE)
// 8 blocks at a time.
for ; n >= 8; n = n - 8 {
v0, v1, v2, v3 := s0, s1, s2, s3
s7 := transmute(simd.u32x8)simd.add(transmute(simd.u64x4)s3, _VEC_TWO)
v4, v5, v6, v7 := s0, s1, s2, s7
s11 := transmute(simd.u32x8)simd.add(transmute(simd.u64x4)s7, _VEC_TWO)
v8, v9, v10, v11 := s0, s1, s2, s11
s15 := transmute(simd.u32x8)simd.add(transmute(simd.u64x4)s11, _VEC_TWO)
v12, v13, v14, v15 := s0, s1, s2, s15
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
v0, v1, v2, v3 = _dq_round_simd256(v0, v1, v2, v3)
v4, v5, v6, v7 = _dq_round_simd256(v4, v5, v6, v7)
v8, v9, v10, v11 = _dq_round_simd256(v8, v9, v10, v11)
v12, v13, v14, v15 = _dq_round_simd256(v12, v13, v14, v15)
}
v0, v1, v2, v3 = _add_and_permute_state_simd256(v0, v1, v2, v3, s0, s1, s2, s3)
v4, v5, v6, v7 = _add_and_permute_state_simd256(v4, v5, v6, v7, s0, s1, s2, s7)
v8, v9, v10, v11 = _add_and_permute_state_simd256(v8, v9, v10, v11, s0, s1, s2, s11)
v12, v13, v14, v15 = _add_and_permute_state_simd256(v12, v13, v14, v15, s0, s1, s2, s15)
#no_bounds_check {
if src != nil {
v0, v1, v2, v3 = _xor_simd256(src_v, v0, v1, v2, v3)
v4, v5, v6, v7 = _xor_simd256(src_v[4:], v4, v5, v6, v7)
v8, v9, v10, v11 = _xor_simd256(src_v[8:], v8, v9, v10, v11)
v12, v13, v14, v15 = _xor_simd256(src_v[12:], v12, v13, v14, v15)
src_v = src_v[16:]
}
_store_simd256(dst_v, v0, v1, v2, v3)
_store_simd256(dst_v[4:], v4, v5, v6, v7)
_store_simd256(dst_v[8:], v8, v9, v10, v11)
_store_simd256(dst_v[12:], v12, v13, v14, v15)
dst_v = dst_v[16:]
}
s3 = transmute(simd.u32x8)simd.add(transmute(simd.u64x4)s15, _VEC_TWO)
}
// 2 (or 1) block at a time.
for ; n > 0; n = n - 2 {
v0, v1, v2, v3 := s0, s1, s2, s3
for i := _chacha20.ROUNDS; i > 0; i = i - 2 {
v0, v1, v2, v3 = _dq_round_simd256(v0, v1, v2, v3)
}
v0, v1, v2, v3 = _add_and_permute_state_simd256(v0, v1, v2, v3, s0, s1, s2, s3)
if n == 1 {
// Note: No need to advance src_v, dst_v, or increment the counter
// since this is guaranteed to be the final block.
#no_bounds_check {
if src != nil {
v0, v1 = _xor_simd256_x1(src_v, v0, v1)
}
_store_simd256_x1(dst_v, v0, v1)
}
break
}
#no_bounds_check {
if src != nil {
v0, v1, v2, v3 = _xor_simd256(src_v, v0, v1, v2, v3)
src_v = src_v[4:]
}
_store_simd256(dst_v, v0, v1, v2, v3)
dst_v = dst_v[4:]
}
s3 = transmute(simd.u32x8)simd.add(transmute(simd.u64x4)s3, _VEC_TWO)
}
// Write back the counter. Doing it this way, saves having to
// pull out the correct counter value from s3.
new_ctr := ((u64(ctx._s[13]) << 32) | u64(ctx._s[12])) + u64(nr_blocks)
ctx._s[12] = u32(new_ctr)
ctx._s[13] = u32(new_ctr >> 32)
}
@(enable_target_feature = "sse2,ssse3,avx")
hchacha20 :: proc "contextless" (dst, key, iv: []byte) {
// We can just enable AVX and call the simd128 code as going
// wider has 0 performance benefit, but VEX encoded instructions
// is nice.
#force_inline chacha_simd128.hchacha20(dst, key, iv)
}
@@ -0,0 +1,17 @@
//+build !amd64
package chacha20_simd256
import "base:intrinsics"
import "core:crypto/_chacha20"
is_performant :: proc "contextless" () -> bool {
return false
}
stream_blocks :: proc(ctx: ^_chacha20.Context, dst, src: []byte, nr_blocks: int) {
panic("crypto/chacha20: simd256 implementation unsupported")
}
hchacha20 :: proc "contextless" (dst, key, iv: []byte) {
intrinsics.trap()
}
+36
View File
@@ -0,0 +1,36 @@
package aead
// seal_oneshot encrypts the plaintext and authenticates the aad and ciphertext,
// with the provided algorithm, key, and iv, stores the output in dst and tag.
//
// dst and plaintext MUST alias exactly or not at all.
seal_oneshot :: proc(algo: Algorithm, dst, tag, key, iv, aad, plaintext: []byte, impl: Implementation = nil) {
ctx: Context
init(&ctx, algo, key, impl)
defer reset(&ctx)
seal_ctx(&ctx, dst, tag, iv, aad, plaintext)
}
// open authenticates the aad and ciphertext, and decrypts the ciphertext,
// with the provided algorithm, key, iv, and tag, and stores the output in dst,
// returning true iff the authentication was successful. If authentication
// fails, the destination buffer will be zeroed.
//
// dst and plaintext MUST alias exactly or not at all.
@(require_results)
open_oneshot :: proc(algo: Algorithm, dst, key, iv, aad, ciphertext, tag: []byte, impl: Implementation = nil) -> bool {
ctx: Context
init(&ctx, algo, key, impl)
defer reset(&ctx)
return open_ctx(&ctx, dst, iv, aad, ciphertext, tag)
}
seal :: proc {
seal_ctx,
seal_oneshot,
}
open :: proc {
open_ctx,
open_oneshot,
}
+58
View File
@@ -0,0 +1,58 @@
/*
package aead provides a generic interface to the supported Authenticated
Encryption with Associated Data algorithms.
Both a one-shot and context based interface are provided, with similar
usage. If multiple messages are to be sealed/opened via the same key,
the context based interface may be more efficient, depending on the
algorithm.
WARNING: Reusing the same key + iv to seal (encrypt) multiple messages
results in catastrophic loss of security for most algorithms.
```odin
package aead_example
import "core:bytes"
import "core:crypto"
import "core:crypto/aead"
main :: proc() {
algo := aead.Algorithm.XCHACHA20POLY1305
// The example added associated data, and plaintext.
aad_str := "Get your ass in gear boys."
pt_str := "They're immanetizing the Eschaton."
aad := transmute([]byte)aad_str
plaintext := transmute([]byte)pt_str
pt_len := len(plaintext)
// Generate a random key for the purposes of illustration.
key := make([]byte, aead.KEY_SIZES[algo])
defer delete(key)
crypto.rand_bytes(key)
// `ciphertext || tag`, is a common way data is transmitted, so
// demonstrate that.
buf := make([]byte, pt_len + aead.TAG_SIZES[algo])
defer delete(buf)
ciphertext, tag := buf[:pt_len], buf[pt_len:]
// Seal the AAD + Plaintext.
iv := make([]byte, aead.IV_SIZES[algo])
defer delete(iv)
crypto.rand_bytes(iv) // Random IVs are safe with XChaCha20-Poly1305.
aead.seal(algo, ciphertext, tag, key, iv, aad, plaintext)
// Open the AAD + Ciphertext.
opened_pt := buf[:pt_len]
if ok := aead.open(algo, opened_pt, key, iv, aad, ciphertext, tag); !ok {
panic("aead example: failed to open")
}
assert(bytes.equal(opened_pt, plaintext))
}
```
*/
package aead
+187
View File
@@ -0,0 +1,187 @@
package aead
import "core:crypto/aes"
import "core:crypto/chacha20"
import "core:crypto/chacha20poly1305"
import "core:reflect"
// Implementation is an AEAD implementation. Most callers will not need
// to use this as the package will automatically select the most performant
// implementation available.
Implementation :: union {
aes.Implementation,
chacha20.Implementation,
}
// MAX_TAG_SIZE is the maximum size tag that can be returned by any of the
// Algorithms supported via this package.
MAX_TAG_SIZE :: 16
// Algorithm is the algorithm identifier associated with a given Context.
Algorithm :: enum {
Invalid,
AES_GCM_128,
AES_GCM_192,
AES_GCM_256,
CHACHA20POLY1305,
XCHACHA20POLY1305,
}
// ALGORITM_NAMES is the Agorithm to algorithm name string.
ALGORITHM_NAMES := [Algorithm]string {
.Invalid = "Invalid",
.AES_GCM_128 = "AES-GCM-128",
.AES_GCM_192 = "AES-GCM-192",
.AES_GCM_256 = "AES-GCM-256",
.CHACHA20POLY1305 = "chacha20poly1305",
.XCHACHA20POLY1305 = "xchacha20poly1305",
}
// TAG_SIZES is the Algorithm to tag size in bytes.
TAG_SIZES := [Algorithm]int {
.Invalid = 0,
.AES_GCM_128 = aes.GCM_TAG_SIZE,
.AES_GCM_192 = aes.GCM_TAG_SIZE,
.AES_GCM_256 = aes.GCM_TAG_SIZE,
.CHACHA20POLY1305 = chacha20poly1305.TAG_SIZE,
.XCHACHA20POLY1305 = chacha20poly1305.TAG_SIZE,
}
// KEY_SIZES is the Algorithm to key size in bytes.
KEY_SIZES := [Algorithm]int {
.Invalid = 0,
.AES_GCM_128 = aes.KEY_SIZE_128,
.AES_GCM_192 = aes.KEY_SIZE_192,
.AES_GCM_256 = aes.KEY_SIZE_256,
.CHACHA20POLY1305 = chacha20poly1305.KEY_SIZE,
.XCHACHA20POLY1305 = chacha20poly1305.KEY_SIZE,
}
// IV_SIZES is the Algorithm to initialization vector size in bytes.
//
// Note: Some algorithms (such as AES-GCM) support variable IV sizes.
IV_SIZES := [Algorithm]int {
.Invalid = 0,
.AES_GCM_128 = aes.GCM_IV_SIZE,
.AES_GCM_192 = aes.GCM_IV_SIZE,
.AES_GCM_256 = aes.GCM_IV_SIZE,
.CHACHA20POLY1305 = chacha20poly1305.IV_SIZE,
.XCHACHA20POLY1305 = chacha20poly1305.XIV_SIZE,
}
// Context is a concrete instantiation of a specific AEAD algorithm.
Context :: struct {
_algo: Algorithm,
_impl: union {
aes.Context_GCM,
chacha20poly1305.Context,
},
}
@(private)
_IMPL_IDS := [Algorithm]typeid {
.Invalid = nil,
.AES_GCM_128 = typeid_of(aes.Context_GCM),
.AES_GCM_192 = typeid_of(aes.Context_GCM),
.AES_GCM_256 = typeid_of(aes.Context_GCM),
.CHACHA20POLY1305 = typeid_of(chacha20poly1305.Context),
.XCHACHA20POLY1305 = typeid_of(chacha20poly1305.Context),
}
// init initializes a Context with a specific AEAD Algorithm.
init :: proc(ctx: ^Context, algorithm: Algorithm, key: []byte, impl: Implementation = nil) {
if ctx._impl != nil {
reset(ctx)
}
if len(key) != KEY_SIZES[algorithm] {
panic("crypto/aead: invalid key size")
}
// Directly specialize the union by setting the type ID (save a copy).
reflect.set_union_variant_typeid(
ctx._impl,
_IMPL_IDS[algorithm],
)
switch algorithm {
case .AES_GCM_128, .AES_GCM_192, .AES_GCM_256:
impl_ := impl != nil ? impl.(aes.Implementation) : aes.DEFAULT_IMPLEMENTATION
aes.init_gcm(&ctx._impl.(aes.Context_GCM), key, impl_)
case .CHACHA20POLY1305:
impl_ := impl != nil ? impl.(chacha20.Implementation) : chacha20.DEFAULT_IMPLEMENTATION
chacha20poly1305.init(&ctx._impl.(chacha20poly1305.Context), key, impl_)
case .XCHACHA20POLY1305:
impl_ := impl != nil ? impl.(chacha20.Implementation) : chacha20.DEFAULT_IMPLEMENTATION
chacha20poly1305.init_xchacha(&ctx._impl.(chacha20poly1305.Context), key, impl_)
case .Invalid:
panic("crypto/aead: uninitialized algorithm")
case:
panic("crypto/aead: invalid algorithm")
}
ctx._algo = algorithm
}
// seal_ctx encrypts the plaintext and authenticates the aad and ciphertext,
// with the provided Context and iv, stores the output in dst and tag.
//
// dst and plaintext MUST alias exactly or not at all.
seal_ctx :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) {
switch &impl in ctx._impl {
case aes.Context_GCM:
aes.seal_gcm(&impl, dst, tag, iv, aad, plaintext)
case chacha20poly1305.Context:
chacha20poly1305.seal(&impl, dst, tag, iv, aad, plaintext)
case:
panic("crypto/aead: uninitialized algorithm")
}
}
// open_ctx authenticates the aad and ciphertext, and decrypts the ciphertext,
// with the provided Context, iv, and tag, and stores the output in dst,
// returning true iff the authentication was successful. If authentication
// fails, the destination buffer will be zeroed.
//
// dst and plaintext MUST alias exactly or not at all.
@(require_results)
open_ctx :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool {
switch &impl in ctx._impl {
case aes.Context_GCM:
return aes.open_gcm(&impl, dst, iv, aad, ciphertext, tag)
case chacha20poly1305.Context:
return chacha20poly1305.open(&impl, dst, iv, aad, ciphertext, tag)
case:
panic("crypto/aead: uninitialized algorithm")
}
}
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
switch &impl in ctx._impl {
case aes.Context_GCM:
aes.reset_gcm(&impl)
case chacha20poly1305.Context:
chacha20poly1305.reset(&impl)
case:
// Calling reset repeatedly is fine.
}
ctx._algo = .Invalid
ctx._impl = nil
}
// algorithm returns the Algorithm used by a Context instance.
algorithm :: proc(ctx: ^Context) -> Algorithm {
return ctx._algo
}
// iv_size returns the IV size of a Context instance in bytes.
iv_size :: proc(ctx: ^Context) -> int {
return IV_SIZES[ctx._algo]
}
// tag_size returns the tag size of a Context instance in bytes.
tag_size :: proc(ctx: ^Context) -> int {
return TAG_SIZES[ctx._algo]
}
-1
View File
@@ -6,7 +6,6 @@ See:
- https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38a.pdf
- https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-38d.pdf
*/
package aes
import "core:crypto/_aes"
+20 -18
View File
@@ -1,5 +1,6 @@
package aes
import "core:bytes"
import "core:crypto/_aes/ct64"
import "core:encoding/endian"
import "core:math/bits"
@@ -19,7 +20,7 @@ Context_CTR :: struct {
}
// init_ctr initializes a Context_CTR with the provided key and IV.
init_ctr :: proc(ctx: ^Context_CTR, key, iv: []byte, impl := Implementation.Hardware) {
init_ctr :: proc(ctx: ^Context_CTR, key, iv: []byte, impl := DEFAULT_IMPLEMENTATION) {
if len(iv) != CTR_IV_SIZE {
panic("crypto/aes: invalid CTR IV size")
}
@@ -37,15 +38,16 @@ init_ctr :: proc(ctx: ^Context_CTR, key, iv: []byte, impl := Implementation.Hard
xor_bytes_ctr :: proc(ctx: ^Context_CTR, dst, src: []byte) {
assert(ctx._is_initialized)
// TODO: Enforcing that dst and src alias exactly or not at all
// is a good idea, though odd aliasing should be extremely uncommon.
src, dst := src, dst
if dst_len := len(dst); dst_len < len(src) {
src = src[:dst_len]
}
for remaining := len(src); remaining > 0; {
if bytes.alias_inexactly(dst, src) {
panic("crypto/aes: dst and src alias inexactly")
}
#no_bounds_check for remaining := len(src); remaining > 0; {
// Process multiple blocks at once
if ctx._off == BLOCK_SIZE {
if nr_blocks := remaining / BLOCK_SIZE; nr_blocks > 0 {
@@ -83,7 +85,7 @@ keystream_bytes_ctr :: proc(ctx: ^Context_CTR, dst: []byte) {
assert(ctx._is_initialized)
dst := dst
for remaining := len(dst); remaining > 0; {
#no_bounds_check for remaining := len(dst); remaining > 0; {
// Process multiple blocks at once
if ctx._off == BLOCK_SIZE {
if nr_blocks := remaining / BLOCK_SIZE; nr_blocks > 0 {
@@ -123,8 +125,8 @@ reset_ctr :: proc "contextless" (ctx: ^Context_CTR) {
ctx._is_initialized = false
}
@(private)
ctr_blocks :: proc(ctx: ^Context_CTR, dst, src: []byte, nr_blocks: int) {
@(private = "file")
ctr_blocks :: proc(ctx: ^Context_CTR, dst, src: []byte, nr_blocks: int) #no_bounds_check {
// Use the optimized hardware implementation if available.
if _, is_hw := ctx._impl.(Context_Impl_Hardware); is_hw {
ctr_blocks_hw(ctx, dst, src, nr_blocks)
@@ -183,17 +185,17 @@ xor_blocks :: #force_inline proc "contextless" (dst, src: []byte, blocks: [][]by
// performance of this implementation matters to where that
// optimization would be worth it, use chacha20poly1305, or a
// CPU that isn't e-waste.
if src != nil {
#no_bounds_check {
for i in 0 ..< len(blocks) {
off := i * BLOCK_SIZE
for j in 0 ..< BLOCK_SIZE {
blocks[i][j] ~= src[off + j]
#no_bounds_check {
if src != nil {
for i in 0 ..< len(blocks) {
off := i * BLOCK_SIZE
for j in 0 ..< BLOCK_SIZE {
blocks[i][j] ~= src[off + j]
}
}
}
}
for i in 0 ..< len(blocks) {
copy(dst[i * BLOCK_SIZE:], blocks[i])
}
}
for i in 0 ..< len(blocks) {
copy(dst[i * BLOCK_SIZE:], blocks[i])
}
}
+151
View File
@@ -0,0 +1,151 @@
//+build amd64
package aes
import "base:intrinsics"
import "core:crypto/_aes"
import "core:math/bits"
import "core:mem"
import "core:simd/x86"
@(private)
CTR_STRIDE_HW :: 4
@(private)
CTR_STRIDE_BYTES_HW :: CTR_STRIDE_HW * BLOCK_SIZE
@(private, enable_target_feature = "sse2,aes")
ctr_blocks_hw :: proc(ctx: ^Context_CTR, dst, src: []byte, nr_blocks: int) #no_bounds_check {
hw_ctx := ctx._impl.(Context_Impl_Hardware)
sks: [15]x86.__m128i = ---
for i in 0 ..= hw_ctx._num_rounds {
sks[i] = intrinsics.unaligned_load((^x86.__m128i)(&hw_ctx._sk_exp_enc[i]))
}
hw_inc_ctr := #force_inline proc "contextless" (hi, lo: u64) -> (x86.__m128i, u64, u64) {
ret := x86.__m128i{
i64(intrinsics.byte_swap(hi)),
i64(intrinsics.byte_swap(lo)),
}
hi, lo := hi, lo
carry: u64
lo, carry = bits.add_u64(lo, 1, 0)
hi, _ = bits.add_u64(hi, 0, carry)
return ret, hi, lo
}
// The latency of AESENC depends on mfg and microarchitecture:
// - 7 -> up to Broadwell
// - 4 -> AMD and Skylake - Cascade Lake
// - 3 -> Ice Lake and newer
//
// This implementation does 4 blocks at once, since performance
// should be "adequate" across most CPUs.
src, dst := src, dst
nr_blocks := nr_blocks
ctr_hi, ctr_lo := ctx._ctr_hi, ctx._ctr_lo
blks: [CTR_STRIDE_HW]x86.__m128i = ---
for nr_blocks >= CTR_STRIDE_HW {
#unroll for i in 0..< CTR_STRIDE_HW {
blks[i], ctr_hi, ctr_lo = hw_inc_ctr(ctr_hi, ctr_lo)
}
#unroll for i in 0 ..< CTR_STRIDE_HW {
blks[i] = x86._mm_xor_si128(blks[i], sks[0])
}
#unroll for i in 1 ..= 9 {
#unroll for j in 0 ..< CTR_STRIDE_HW {
blks[j] = x86._mm_aesenc_si128(blks[j], sks[i])
}
}
switch hw_ctx._num_rounds {
case _aes.ROUNDS_128:
#unroll for i in 0 ..< CTR_STRIDE_HW {
blks[i] = x86._mm_aesenclast_si128(blks[i], sks[10])
}
case _aes.ROUNDS_192:
#unroll for i in 10 ..= 11 {
#unroll for j in 0 ..< CTR_STRIDE_HW {
blks[j] = x86._mm_aesenc_si128(blks[j], sks[i])
}
}
#unroll for i in 0 ..< CTR_STRIDE_HW {
blks[i] = x86._mm_aesenclast_si128(blks[i], sks[12])
}
case _aes.ROUNDS_256:
#unroll for i in 10 ..= 13 {
#unroll for j in 0 ..< CTR_STRIDE_HW {
blks[j] = x86._mm_aesenc_si128(blks[j], sks[i])
}
}
#unroll for i in 0 ..< CTR_STRIDE_HW {
blks[i] = x86._mm_aesenclast_si128(blks[i], sks[14])
}
}
xor_blocks_hw(dst, src, blks[:])
if src != nil {
src = src[CTR_STRIDE_BYTES_HW:]
}
dst = dst[CTR_STRIDE_BYTES_HW:]
nr_blocks -= CTR_STRIDE_HW
}
// Handle the remainder.
for nr_blocks > 0 {
blks[0], ctr_hi, ctr_lo = hw_inc_ctr(ctr_hi, ctr_lo)
blks[0] = x86._mm_xor_si128(blks[0], sks[0])
#unroll for i in 1 ..= 9 {
blks[0] = x86._mm_aesenc_si128(blks[0], sks[i])
}
switch hw_ctx._num_rounds {
case _aes.ROUNDS_128:
blks[0] = x86._mm_aesenclast_si128(blks[0], sks[10])
case _aes.ROUNDS_192:
#unroll for i in 10 ..= 11 {
blks[0] = x86._mm_aesenc_si128(blks[0], sks[i])
}
blks[0] = x86._mm_aesenclast_si128(blks[0], sks[12])
case _aes.ROUNDS_256:
#unroll for i in 10 ..= 13 {
blks[0] = x86._mm_aesenc_si128(blks[0], sks[i])
}
blks[0] = x86._mm_aesenclast_si128(blks[0], sks[14])
}
xor_blocks_hw(dst, src, blks[:1])
if src != nil {
src = src[BLOCK_SIZE:]
}
dst = dst[BLOCK_SIZE:]
nr_blocks -= 1
}
// Write back the counter.
ctx._ctr_hi, ctx._ctr_lo = ctr_hi, ctr_lo
mem.zero_explicit(&blks, size_of(blks))
mem.zero_explicit(&sks, size_of(sks))
}
@(private, enable_target_feature = "sse2")
xor_blocks_hw :: proc(dst, src: []byte, blocks: []x86.__m128i) {
#no_bounds_check {
if src != nil {
for i in 0 ..< len(blocks) {
off := i * BLOCK_SIZE
tmp := intrinsics.unaligned_load((^x86.__m128i)(raw_data(src[off:])))
blocks[i] = x86._mm_xor_si128(blocks[i], tmp)
}
}
for i in 0 ..< len(blocks) {
intrinsics.unaligned_store((^x86.__m128i)(raw_data(dst[i * BLOCK_SIZE:])), blocks[i])
}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ Context_ECB :: struct {
}
// init_ecb initializes a Context_ECB with the provided key.
init_ecb :: proc(ctx: ^Context_ECB, key: []byte, impl := Implementation.Hardware) {
init_ecb :: proc(ctx: ^Context_ECB, key: []byte, impl := DEFAULT_IMPLEMENTATION) {
init_impl(&ctx._impl, key, impl)
ctx._is_initialized = true
}
+58
View File
@@ -0,0 +1,58 @@
//+build amd64
package aes
import "base:intrinsics"
import "core:crypto/_aes"
import "core:simd/x86"
@(private, enable_target_feature = "sse2,aes")
encrypt_block_hw :: proc(ctx: ^Context_Impl_Hardware, dst, src: []byte) {
blk := intrinsics.unaligned_load((^x86.__m128i)(raw_data(src)))
blk = x86._mm_xor_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[0])))
#unroll for i in 1 ..= 9 {
blk = x86._mm_aesenc_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[i])))
}
switch ctx._num_rounds {
case _aes.ROUNDS_128:
blk = x86._mm_aesenclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[10])))
case _aes.ROUNDS_192:
#unroll for i in 10 ..= 11 {
blk = x86._mm_aesenc_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[i])))
}
blk = x86._mm_aesenclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[12])))
case _aes.ROUNDS_256:
#unroll for i in 10 ..= 13 {
blk = x86._mm_aesenc_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[i])))
}
blk = x86._mm_aesenclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[14])))
}
intrinsics.unaligned_store((^x86.__m128i)(raw_data(dst)), blk)
}
@(private, enable_target_feature = "sse2,aes")
decrypt_block_hw :: proc(ctx: ^Context_Impl_Hardware, dst, src: []byte) {
blk := intrinsics.unaligned_load((^x86.__m128i)(raw_data(src)))
blk = x86._mm_xor_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[0])))
#unroll for i in 1 ..= 9 {
blk = x86._mm_aesdec_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[i])))
}
switch ctx._num_rounds {
case _aes.ROUNDS_128:
blk = x86._mm_aesdeclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[10])))
case _aes.ROUNDS_192:
#unroll for i in 10 ..= 11 {
blk = x86._mm_aesdec_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[i])))
}
blk = x86._mm_aesdeclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[12])))
case _aes.ROUNDS_256:
#unroll for i in 10 ..= 13 {
blk = x86._mm_aesdec_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[i])))
}
blk = x86._mm_aesdeclast_si128(blk, intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_dec[14])))
}
intrinsics.unaligned_store((^x86.__m128i)(raw_data(dst)), blk)
}
+60 -43
View File
@@ -1,13 +1,16 @@
package aes
import "core:bytes"
import "core:crypto"
import "core:crypto/_aes"
import "core:crypto/_aes/ct64"
import "core:encoding/endian"
import "core:mem"
// GCM_NONCE_SIZE is the size of the GCM nonce in bytes.
GCM_NONCE_SIZE :: 12
// GCM_IV_SIZE is the default size of the GCM IV in bytes.
GCM_IV_SIZE :: 12
// GCM_IV_SIZE_MAX is the maximum size of the GCM IV in bytes.
GCM_IV_SIZE_MAX :: 0x2000000000000000 // floor((2^64 - 1) / 8) bits
// GCM_TAG_SIZE is the size of a GCM tag in bytes.
GCM_TAG_SIZE :: _aes.GHASH_TAG_SIZE
@@ -23,69 +26,79 @@ Context_GCM :: struct {
}
// init_gcm initializes a Context_GCM with the provided key.
init_gcm :: proc(ctx: ^Context_GCM, key: []byte, impl := Implementation.Hardware) {
init_gcm :: proc(ctx: ^Context_GCM, key: []byte, impl := DEFAULT_IMPLEMENTATION) {
init_impl(&ctx._impl, key, impl)
ctx._is_initialized = true
}
// seal_gcm encrypts the plaintext and authenticates the aad and ciphertext,
// with the provided Context_GCM and nonce, stores the output in dst and tag.
// with the provided Context_GCM and iv, stores the output in dst and tag.
//
// dst and plaintext MUST alias exactly or not at all.
seal_gcm :: proc(ctx: ^Context_GCM, dst, tag, nonce, aad, plaintext: []byte) {
seal_gcm :: proc(ctx: ^Context_GCM, dst, tag, iv, aad, plaintext: []byte) {
assert(ctx._is_initialized)
gcm_validate_common_slice_sizes(tag, nonce, aad, plaintext)
gcm_validate_common_slice_sizes(tag, iv, aad, plaintext)
if len(dst) != len(plaintext) {
panic("crypto/aes: invalid destination ciphertext size")
}
if bytes.alias_inexactly(dst, plaintext) {
panic("crypto/aes: dst and plaintext alias inexactly")
}
if impl, is_hw := ctx._impl.(Context_Impl_Hardware); is_hw {
gcm_seal_hw(&impl, dst, tag, nonce, aad, plaintext)
gcm_seal_hw(&impl, dst, tag, iv, aad, plaintext)
return
}
h: [_aes.GHASH_KEY_SIZE]byte
j0: [_aes.GHASH_BLOCK_SIZE]byte
j0_enc: [_aes.GHASH_BLOCK_SIZE]byte
s: [_aes.GHASH_TAG_SIZE]byte
init_ghash_ct64(ctx, &h, &j0, nonce)
init_ghash_ct64(ctx, &h, &j0, &j0_enc, iv)
// Note: Our GHASH implementation handles appending padding.
ct64.ghash(s[:], h[:], aad)
gctr_ct64(ctx, dst, &s, plaintext, &h, nonce, true)
final_ghash_ct64(&s, &h, &j0, len(aad), len(plaintext))
gctr_ct64(ctx, dst, &s, plaintext, &h, &j0, true)
final_ghash_ct64(&s, &h, &j0_enc, len(aad), len(plaintext))
copy(tag, s[:])
mem.zero_explicit(&h, len(h))
mem.zero_explicit(&j0, len(j0))
mem.zero_explicit(&j0_enc, len(j0_enc))
}
// open_gcm authenticates the aad and ciphertext, and decrypts the ciphertext,
// with the provided Context_GCM, nonce, and tag, and stores the output in dst,
// with the provided Context_GCM, iv, and tag, and stores the output in dst,
// returning true iff the authentication was successful. If authentication
// fails, the destination buffer will be zeroed.
//
// dst and plaintext MUST alias exactly or not at all.
open_gcm :: proc(ctx: ^Context_GCM, dst, nonce, aad, ciphertext, tag: []byte) -> bool {
@(require_results)
open_gcm :: proc(ctx: ^Context_GCM, dst, iv, aad, ciphertext, tag: []byte) -> bool {
assert(ctx._is_initialized)
gcm_validate_common_slice_sizes(tag, nonce, aad, ciphertext)
gcm_validate_common_slice_sizes(tag, iv, aad, ciphertext)
if len(dst) != len(ciphertext) {
panic("crypto/aes: invalid destination plaintext size")
}
if bytes.alias_inexactly(dst, ciphertext) {
panic("crypto/aes: dst and ciphertext alias inexactly")
}
if impl, is_hw := ctx._impl.(Context_Impl_Hardware); is_hw {
return gcm_open_hw(&impl, dst, nonce, aad, ciphertext, tag)
return gcm_open_hw(&impl, dst, iv, aad, ciphertext, tag)
}
h: [_aes.GHASH_KEY_SIZE]byte
j0: [_aes.GHASH_BLOCK_SIZE]byte
j0_enc: [_aes.GHASH_BLOCK_SIZE]byte
s: [_aes.GHASH_TAG_SIZE]byte
init_ghash_ct64(ctx, &h, &j0, nonce)
init_ghash_ct64(ctx, &h, &j0, &j0_enc, iv)
ct64.ghash(s[:], h[:], aad)
gctr_ct64(ctx, dst, &s, ciphertext, &h, nonce, false)
final_ghash_ct64(&s, &h, &j0, len(aad), len(ciphertext))
gctr_ct64(ctx, dst, &s, ciphertext, &h, &j0, false)
final_ghash_ct64(&s, &h, &j0_enc, len(aad), len(ciphertext))
ok := crypto.compare_constant_time(s[:], tag) == 1
if !ok {
@@ -94,32 +107,28 @@ open_gcm :: proc(ctx: ^Context_GCM, dst, nonce, aad, ciphertext, tag: []byte) ->
mem.zero_explicit(&h, len(h))
mem.zero_explicit(&j0, len(j0))
mem.zero_explicit(&j0_enc, len(j0_enc))
mem.zero_explicit(&s, len(s))
return ok
}
// reset_ctr sanitizes the Context_GCM. The Context_GCM must be
// reset_gcm sanitizes the Context_GCM. The Context_GCM must be
// re-initialized to be used again.
reset_gcm :: proc "contextless" (ctx: ^Context_GCM) {
reset_impl(&ctx._impl)
ctx._is_initialized = false
}
@(private)
gcm_validate_common_slice_sizes :: proc(tag, nonce, aad, text: []byte) {
@(private = "file")
gcm_validate_common_slice_sizes :: proc(tag, iv, aad, text: []byte) {
if len(tag) != GCM_TAG_SIZE {
panic("crypto/aes: invalid GCM tag size")
}
// The specification supports nonces in the range [1, 2^64) bits
// however per NIST SP 800-38D 5.2.1.1:
//
// > For IVs, it is recommended that implementations restrict support
// > to the length of 96 bits, to promote interoperability, efficiency,
// > and simplicity of design.
if len(nonce) != GCM_NONCE_SIZE {
panic("crypto/aes: invalid GCM nonce size")
// The specification supports IVs in the range [1, 2^64) bits.
if l := len(iv); l == 0 || u64(l) >= GCM_IV_SIZE_MAX {
panic("crypto/aes: invalid GCM IV size")
}
if aad_len := u64(len(aad)); aad_len > GCM_A_MAX {
@@ -135,19 +144,33 @@ init_ghash_ct64 :: proc(
ctx: ^Context_GCM,
h: ^[_aes.GHASH_KEY_SIZE]byte,
j0: ^[_aes.GHASH_BLOCK_SIZE]byte,
nonce: []byte,
j0_enc: ^[_aes.GHASH_BLOCK_SIZE]byte,
iv: []byte,
) {
impl := &ctx._impl.(ct64.Context)
// 1. Let H = CIPH(k, 0^128)
ct64.encrypt_block(impl, h[:], h[:])
// Define a block, J0, as follows:
if l := len(iv); l == GCM_IV_SIZE {
// if len(IV) = 96, then let J0 = IV || 0^31 || 1
copy(j0[:], iv)
j0[_aes.GHASH_BLOCK_SIZE - 1] = 1
} else {
// If len(IV) != 96, then let s = 128 ceil(len(IV)/128) - len(IV),
// and let J0 = GHASHH(IV || 0^(s+64) || ceil(len(IV))^64).
ct64.ghash(j0[:], h[:], iv)
tmp: [_aes.GHASH_BLOCK_SIZE]byte
endian.unchecked_put_u64be(tmp[8:], u64(l) * 8)
ct64.ghash(j0[:], h[:], tmp[:])
}
// ECB encrypt j0, so that we can just XOR with the tag. In theory
// this could be processed along with the final GCTR block, to
// potentially save a call to AES-ECB, but... just use AES-NI.
copy(j0[:], nonce)
j0[_aes.GHASH_BLOCK_SIZE - 1] = 1
ct64.encrypt_block(impl, j0[:], j0[:])
ct64.encrypt_block(impl, j0_enc[:], j0[:])
}
@(private = "file")
@@ -175,33 +198,27 @@ gctr_ct64 :: proc(
s: ^[_aes.GHASH_BLOCK_SIZE]byte,
src: []byte,
h: ^[_aes.GHASH_KEY_SIZE]byte,
nonce: []byte,
iv: ^[_aes.GHASH_BLOCK_SIZE]byte,
is_seal: bool,
) {
) #no_bounds_check {
ct64_inc_ctr32 := #force_inline proc "contextless" (dst: []byte, ctr: u32) -> u32 {
endian.unchecked_put_u32be(dst[12:], ctr)
return ctr + 1
}
// 2. Define a block J_0 as follows:
// if len(IV) = 96, then let J0 = IV || 0^31 || 1
//
// Note: We only support 96 bit IVs.
// Setup the counter blocks.
tmp, tmp2: [ct64.STRIDE][BLOCK_SIZE]byte = ---, ---
ctrs, blks: [ct64.STRIDE][]byte = ---, ---
ctr: u32 = 2
ctr := endian.unchecked_get_u32be(iv[GCM_IV_SIZE:]) + 1
for i in 0 ..< ct64.STRIDE {
// Setup scratch space for the keystream.
blks[i] = tmp2[i][:]
// Pre-copy the IV to all the counter blocks.
ctrs[i] = tmp[i][:]
copy(ctrs[i], nonce)
copy(ctrs[i], iv[:GCM_IV_SIZE])
}
// We stitch the GCTR and GHASH operations together, so that only
// one pass over the ciphertext is required.
impl := &ctx._impl.(ct64.Context)
src, dst := src, dst
+243
View File
@@ -0,0 +1,243 @@
//+build amd64
package aes
import "base:intrinsics"
import "core:crypto"
import "core:crypto/_aes"
import "core:crypto/_aes/hw_intel"
import "core:encoding/endian"
import "core:mem"
import "core:simd/x86"
@(private)
gcm_seal_hw :: proc(ctx: ^Context_Impl_Hardware, dst, tag, iv, aad, plaintext: []byte) {
h: [_aes.GHASH_KEY_SIZE]byte
j0: [_aes.GHASH_BLOCK_SIZE]byte
j0_enc: [_aes.GHASH_BLOCK_SIZE]byte
s: [_aes.GHASH_TAG_SIZE]byte
init_ghash_hw(ctx, &h, &j0, &j0_enc, iv)
// Note: Our GHASH implementation handles appending padding.
hw_intel.ghash(s[:], h[:], aad)
gctr_hw(ctx, dst, &s, plaintext, &h, &j0, true)
final_ghash_hw(&s, &h, &j0_enc, len(aad), len(plaintext))
copy(tag, s[:])
mem.zero_explicit(&h, len(h))
mem.zero_explicit(&j0, len(j0))
mem.zero_explicit(&j0_enc, len(j0_enc))
}
@(private)
gcm_open_hw :: proc(ctx: ^Context_Impl_Hardware, dst, iv, aad, ciphertext, tag: []byte) -> bool {
h: [_aes.GHASH_KEY_SIZE]byte
j0: [_aes.GHASH_BLOCK_SIZE]byte
j0_enc: [_aes.GHASH_BLOCK_SIZE]byte
s: [_aes.GHASH_TAG_SIZE]byte
init_ghash_hw(ctx, &h, &j0, &j0_enc, iv)
hw_intel.ghash(s[:], h[:], aad)
gctr_hw(ctx, dst, &s, ciphertext, &h, &j0, false)
final_ghash_hw(&s, &h, &j0_enc, len(aad), len(ciphertext))
ok := crypto.compare_constant_time(s[:], tag) == 1
if !ok {
mem.zero_explicit(raw_data(dst), len(dst))
}
mem.zero_explicit(&h, len(h))
mem.zero_explicit(&j0, len(j0))
mem.zero_explicit(&j0_enc, len(j0_enc))
mem.zero_explicit(&s, len(s))
return ok
}
@(private = "file")
init_ghash_hw :: proc(
ctx: ^Context_Impl_Hardware,
h: ^[_aes.GHASH_KEY_SIZE]byte,
j0: ^[_aes.GHASH_BLOCK_SIZE]byte,
j0_enc: ^[_aes.GHASH_BLOCK_SIZE]byte,
iv: []byte,
) {
// 1. Let H = CIPH(k, 0^128)
encrypt_block_hw(ctx, h[:], h[:])
// Define a block, J0, as follows:
if l := len(iv); l == GCM_IV_SIZE {
// if len(IV) = 96, then let J0 = IV || 0^31 || 1
copy(j0[:], iv)
j0[_aes.GHASH_BLOCK_SIZE - 1] = 1
} else {
// If len(IV) != 96, then let s = 128 ceil(len(IV)/128) - len(IV),
// and let J0 = GHASHH(IV || 0^(s+64) || ceil(len(IV))^64).
hw_intel.ghash(j0[:], h[:], iv)
tmp: [_aes.GHASH_BLOCK_SIZE]byte
endian.unchecked_put_u64be(tmp[8:], u64(l) * 8)
hw_intel.ghash(j0[:], h[:], tmp[:])
}
// ECB encrypt j0, so that we can just XOR with the tag.
encrypt_block_hw(ctx, j0_enc[:], j0[:])
}
@(private = "file", enable_target_feature = "sse2")
final_ghash_hw :: proc(
s: ^[_aes.GHASH_BLOCK_SIZE]byte,
h: ^[_aes.GHASH_KEY_SIZE]byte,
j0: ^[_aes.GHASH_BLOCK_SIZE]byte,
a_len: int,
t_len: int,
) {
blk: [_aes.GHASH_BLOCK_SIZE]byte
endian.unchecked_put_u64be(blk[0:], u64(a_len) * 8)
endian.unchecked_put_u64be(blk[8:], u64(t_len) * 8)
hw_intel.ghash(s[:], h[:], blk[:])
j0_vec := intrinsics.unaligned_load((^x86.__m128i)(j0))
s_vec := intrinsics.unaligned_load((^x86.__m128i)(s))
s_vec = x86._mm_xor_si128(s_vec, j0_vec)
intrinsics.unaligned_store((^x86.__m128i)(s), s_vec)
}
@(private = "file", enable_target_feature = "sse2,sse4.1,aes")
gctr_hw :: proc(
ctx: ^Context_Impl_Hardware,
dst: []byte,
s: ^[_aes.GHASH_BLOCK_SIZE]byte,
src: []byte,
h: ^[_aes.GHASH_KEY_SIZE]byte,
iv: ^[_aes.GHASH_BLOCK_SIZE]byte,
is_seal: bool,
) #no_bounds_check {
sks: [15]x86.__m128i = ---
for i in 0 ..= ctx._num_rounds {
sks[i] = intrinsics.unaligned_load((^x86.__m128i)(&ctx._sk_exp_enc[i]))
}
// Setup the counter block
ctr_blk := intrinsics.unaligned_load((^x86.__m128i)(iv))
ctr := endian.unchecked_get_u32be(iv[GCM_IV_SIZE:]) + 1
src, dst := src, dst
// Note: Instead of doing GHASH and CTR separately, it is more
// performant to interleave (stitch) the two operations together.
// This results in an unreadable mess, so we opt for simplicity
// as performance is adequate.
blks: [CTR_STRIDE_HW]x86.__m128i = ---
nr_blocks := len(src) / BLOCK_SIZE
for nr_blocks >= CTR_STRIDE_HW {
if !is_seal {
hw_intel.ghash(s[:], h[:], src[:CTR_STRIDE_BYTES_HW])
}
#unroll for i in 0 ..< CTR_STRIDE_HW {
blks[i], ctr = hw_inc_ctr32(&ctr_blk, ctr)
}
#unroll for i in 0 ..< CTR_STRIDE_HW {
blks[i] = x86._mm_xor_si128(blks[i], sks[0])
}
#unroll for i in 1 ..= 9 {
#unroll for j in 0 ..< CTR_STRIDE_HW {
blks[j] = x86._mm_aesenc_si128(blks[j], sks[i])
}
}
switch ctx._num_rounds {
case _aes.ROUNDS_128:
#unroll for i in 0 ..< CTR_STRIDE_HW {
blks[i] = x86._mm_aesenclast_si128(blks[i], sks[10])
}
case _aes.ROUNDS_192:
#unroll for i in 10 ..= 11 {
#unroll for j in 0 ..< CTR_STRIDE_HW {
blks[j] = x86._mm_aesenc_si128(blks[j], sks[i])
}
}
#unroll for i in 0 ..< CTR_STRIDE_HW {
blks[i] = x86._mm_aesenclast_si128(blks[i], sks[12])
}
case _aes.ROUNDS_256:
#unroll for i in 10 ..= 13 {
#unroll for j in 0 ..< CTR_STRIDE_HW {
blks[j] = x86._mm_aesenc_si128(blks[j], sks[i])
}
}
#unroll for i in 0 ..< CTR_STRIDE_HW {
blks[i] = x86._mm_aesenclast_si128(blks[i], sks[14])
}
}
xor_blocks_hw(dst, src, blks[:])
if is_seal {
hw_intel.ghash(s[:], h[:], dst[:CTR_STRIDE_BYTES_HW])
}
src = src[CTR_STRIDE_BYTES_HW:]
dst = dst[CTR_STRIDE_BYTES_HW:]
nr_blocks -= CTR_STRIDE_HW
}
// Handle the remainder.
for n := len(src); n > 0; {
l := min(n, BLOCK_SIZE)
if !is_seal {
hw_intel.ghash(s[:], h[:], src[:l])
}
blks[0], ctr = hw_inc_ctr32(&ctr_blk, ctr)
blks[0] = x86._mm_xor_si128(blks[0], sks[0])
#unroll for i in 1 ..= 9 {
blks[0] = x86._mm_aesenc_si128(blks[0], sks[i])
}
switch ctx._num_rounds {
case _aes.ROUNDS_128:
blks[0] = x86._mm_aesenclast_si128(blks[0], sks[10])
case _aes.ROUNDS_192:
#unroll for i in 10 ..= 11 {
blks[0] = x86._mm_aesenc_si128(blks[0], sks[i])
}
blks[0] = x86._mm_aesenclast_si128(blks[0], sks[12])
case _aes.ROUNDS_256:
#unroll for i in 10 ..= 13 {
blks[0] = x86._mm_aesenc_si128(blks[0], sks[i])
}
blks[0] = x86._mm_aesenclast_si128(blks[0], sks[14])
}
if l == BLOCK_SIZE {
xor_blocks_hw(dst, src, blks[:1])
} else {
blk: [BLOCK_SIZE]byte
copy(blk[:], src)
xor_blocks_hw(blk[:], blk[:], blks[:1])
copy(dst, blk[:l])
}
if is_seal {
hw_intel.ghash(s[:], h[:], dst[:l])
}
dst = dst[l:]
src = src[l:]
n -= l
}
mem.zero_explicit(&blks, size_of(blks))
mem.zero_explicit(&sks, size_of(sks))
}
// BUG: Sticking this in gctr_hw (like the other implementations) crashes
// the compiler.
//
// src/check_expr.cpp(7892): Assertion Failure: `c->curr_proc_decl->entity`
@(private = "file", enable_target_feature = "sse4.1")
hw_inc_ctr32 :: #force_inline proc "contextless" (src: ^x86.__m128i, ctr: u32) -> (x86.__m128i, u32) {
ret := x86._mm_insert_epi32(src^, i32(intrinsics.byte_swap(ctr)), 3)
return ret, ctr + 1
}
+4
View File
@@ -10,6 +10,10 @@ Context_Impl :: union {
Context_Impl_Hardware,
}
// DEFAULT_IMPLEMENTATION is the implementation that will be used by
// default if possible.
DEFAULT_IMPLEMENTATION :: Implementation.Hardware
// Implementation is an AES implementation. Most callers will not need
// to use this as the package will automatically select the most performant
// implementation available (See `is_hardware_accelerated()`).
+3 -2
View File
@@ -1,3 +1,4 @@
//+build !amd64
package aes
@(private = "file")
@@ -33,11 +34,11 @@ ctr_blocks_hw :: proc(ctx: ^Context_CTR, dst, src: []byte, nr_blocks: int) {
}
@(private)
gcm_seal_hw :: proc(ctx: ^Context_Impl_Hardware, dst, tag, nonce, aad, plaintext: []byte) {
gcm_seal_hw :: proc(ctx: ^Context_Impl_Hardware, dst, tag, iv, aad, plaintext: []byte) {
panic(ERR_HW_NOT_SUPPORTED)
}
@(private)
gcm_open_hw :: proc(ctx: ^Context_Impl_Hardware, dst, nonce, aad, ciphertext, tag: []byte) -> bool {
gcm_open_hw :: proc(ctx: ^Context_Impl_Hardware, dst, iv, aad, ciphertext, tag: []byte) -> bool {
panic(ERR_HW_NOT_SUPPORTED)
}
+18
View File
@@ -0,0 +1,18 @@
//+build amd64
package aes
import "core:crypto/_aes/hw_intel"
// is_hardware_accelerated returns true iff hardware accelerated AES
// is supported.
is_hardware_accelerated :: proc "contextless" () -> bool {
return hw_intel.is_supported()
}
@(private)
Context_Impl_Hardware :: hw_intel.Context
@(private, enable_target_feature = "sse2,aes")
init_impl_hw :: proc(ctx: ^Context_Impl_Hardware, key: []byte) {
hw_intel.init(ctx, key)
}
+56 -467
View File
@@ -7,134 +7,84 @@ See:
*/
package chacha20
import "core:encoding/endian"
import "core:math/bits"
import "core:bytes"
import "core:crypto/_chacha20"
import "core:mem"
// KEY_SIZE is the (X)ChaCha20 key size in bytes.
KEY_SIZE :: 32
// NONCE_SIZE is the ChaCha20 nonce size in bytes.
NONCE_SIZE :: 12
// XNONCE_SIZE is the XChaCha20 nonce size in bytes.
XNONCE_SIZE :: 24
@(private)
_MAX_CTR_IETF :: 0xffffffff
@(private)
_BLOCK_SIZE :: 64
@(private)
_STATE_SIZE_U32 :: 16
@(private)
_ROUNDS :: 20
@(private)
_SIGMA_0: u32 : 0x61707865
@(private)
_SIGMA_1: u32 : 0x3320646e
@(private)
_SIGMA_2: u32 : 0x79622d32
@(private)
_SIGMA_3: u32 : 0x6b206574
KEY_SIZE :: _chacha20.KEY_SIZE
// IV_SIZE is the ChaCha20 IV size in bytes.
IV_SIZE :: _chacha20.IV_SIZE
// XIV_SIZE is the XChaCha20 IV size in bytes.
XIV_SIZE :: _chacha20.XIV_SIZE
// Context is a ChaCha20 or XChaCha20 instance.
Context :: struct {
_s: [_STATE_SIZE_U32]u32,
_buffer: [_BLOCK_SIZE]byte,
_off: int,
_is_ietf_flavor: bool,
_is_initialized: bool,
_state: _chacha20.Context,
_impl: Implementation,
}
// init inititializes a Context for ChaCha20 or XChaCha20 with the provided
// key and nonce.
init :: proc(ctx: ^Context, key, nonce: []byte) {
// key and iv.
init :: proc(ctx: ^Context, key, iv: []byte, impl := DEFAULT_IMPLEMENTATION) {
if len(key) != KEY_SIZE {
panic("crypto/chacha20: invalid ChaCha20 key size")
panic("crypto/chacha20: invalid (X)ChaCha20 key size")
}
if n_len := len(nonce); n_len != NONCE_SIZE && n_len != XNONCE_SIZE {
panic("crypto/chacha20: invalid (X)ChaCha20 nonce size")
if l := len(iv); l != IV_SIZE && l != XIV_SIZE {
panic("crypto/chacha20: invalid (X)ChaCha20 IV size")
}
k, n := key, nonce
k, n := key, iv
// Derive the XChaCha20 subkey and sub-nonce via HChaCha20.
is_xchacha := len(nonce) == XNONCE_SIZE
init_impl(ctx, impl)
is_xchacha := len(iv) == XIV_SIZE
if is_xchacha {
sub_key := ctx._buffer[:KEY_SIZE]
_hchacha20(sub_key, k, n)
sub_iv: [IV_SIZE]byte
sub_key := ctx._state._buffer[:KEY_SIZE]
hchacha20(sub_key, k, n, ctx._impl)
k = sub_key
n = n[16:24]
copy(sub_iv[4:], n[16:])
n = sub_iv[:]
}
ctx._s[0] = _SIGMA_0
ctx._s[1] = _SIGMA_1
ctx._s[2] = _SIGMA_2
ctx._s[3] = _SIGMA_3
ctx._s[4] = endian.unchecked_get_u32le(k[0:4])
ctx._s[5] = endian.unchecked_get_u32le(k[4:8])
ctx._s[6] = endian.unchecked_get_u32le(k[8:12])
ctx._s[7] = endian.unchecked_get_u32le(k[12:16])
ctx._s[8] = endian.unchecked_get_u32le(k[16:20])
ctx._s[9] = endian.unchecked_get_u32le(k[20:24])
ctx._s[10] = endian.unchecked_get_u32le(k[24:28])
ctx._s[11] = endian.unchecked_get_u32le(k[28:32])
ctx._s[12] = 0
if !is_xchacha {
ctx._s[13] = endian.unchecked_get_u32le(n[0:4])
ctx._s[14] = endian.unchecked_get_u32le(n[4:8])
ctx._s[15] = endian.unchecked_get_u32le(n[8:12])
} else {
ctx._s[13] = 0
ctx._s[14] = endian.unchecked_get_u32le(n[0:4])
ctx._s[15] = endian.unchecked_get_u32le(n[4:8])
_chacha20.init(&ctx._state, k, n, is_xchacha)
if is_xchacha {
// The sub-key is stored in the keystream buffer. While
// this will be overwritten in most circumstances, explicitly
// clear it out early.
mem.zero_explicit(&ctx._buffer, KEY_SIZE)
mem.zero_explicit(&ctx._state._buffer, KEY_SIZE)
}
ctx._off = _BLOCK_SIZE
ctx._is_ietf_flavor = !is_xchacha
ctx._is_initialized = true
}
// seek seeks the (X)ChaCha20 stream counter to the specified block.
seek :: proc(ctx: ^Context, block_nr: u64) {
assert(ctx._is_initialized)
if ctx._is_ietf_flavor {
if block_nr > _MAX_CTR_IETF {
panic("crypto/chacha20: attempted to seek past maximum counter")
}
} else {
ctx._s[13] = u32(block_nr >> 32)
}
ctx._s[12] = u32(block_nr)
ctx._off = _BLOCK_SIZE
_chacha20.seek(&ctx._state, block_nr)
}
// xor_bytes XORs each byte in src with bytes taken from the (X)ChaCha20
// keystream, and writes the resulting output to dst. Dst and src MUST
// alias exactly or not at all.
xor_bytes :: proc(ctx: ^Context, dst, src: []byte) {
assert(ctx._is_initialized)
// TODO: Enforcing that dst and src alias exactly or not at all
// is a good idea, though odd aliasing should be extremely uncommon.
assert(ctx._state._is_initialized)
src, dst := src, dst
if dst_len := len(dst); dst_len < len(src) {
src = src[:dst_len]
}
for remaining := len(src); remaining > 0; {
if bytes.alias_inexactly(dst, src) {
panic("crypto/chacha20: dst and src alias inexactly")
}
st := &ctx._state
#no_bounds_check for remaining := len(src); remaining > 0; {
// Process multiple blocks at once
if ctx._off == _BLOCK_SIZE {
if nr_blocks := remaining / _BLOCK_SIZE; nr_blocks > 0 {
direct_bytes := nr_blocks * _BLOCK_SIZE
_do_blocks(ctx, dst, src, nr_blocks)
if st._off == _chacha20.BLOCK_SIZE {
if nr_blocks := remaining / _chacha20.BLOCK_SIZE; nr_blocks > 0 {
direct_bytes := nr_blocks * _chacha20.BLOCK_SIZE
stream_blocks(ctx, dst, src, nr_blocks)
remaining -= direct_bytes
if remaining == 0 {
return
@@ -145,17 +95,17 @@ xor_bytes :: proc(ctx: ^Context, dst, src: []byte) {
// If there is a partial block, generate and buffer 1 block
// worth of keystream.
_do_blocks(ctx, ctx._buffer[:], nil, 1)
ctx._off = 0
stream_blocks(ctx, st._buffer[:], nil, 1)
st._off = 0
}
// Process partial blocks from the buffered keystream.
to_xor := min(_BLOCK_SIZE - ctx._off, remaining)
buffered_keystream := ctx._buffer[ctx._off:]
to_xor := min(_chacha20.BLOCK_SIZE - st._off, remaining)
buffered_keystream := st._buffer[st._off:]
for i := 0; i < to_xor; i = i + 1 {
dst[i] = buffered_keystream[i] ~ src[i]
}
ctx._off += to_xor
st._off += to_xor
dst = dst[to_xor:]
src = src[to_xor:]
remaining -= to_xor
@@ -164,15 +114,15 @@ xor_bytes :: proc(ctx: ^Context, dst, src: []byte) {
// keystream_bytes fills dst with the raw (X)ChaCha20 keystream output.
keystream_bytes :: proc(ctx: ^Context, dst: []byte) {
assert(ctx._is_initialized)
assert(ctx._state._is_initialized)
dst := dst
for remaining := len(dst); remaining > 0; {
dst, st := dst, &ctx._state
#no_bounds_check for remaining := len(dst); remaining > 0; {
// Process multiple blocks at once
if ctx._off == _BLOCK_SIZE {
if nr_blocks := remaining / _BLOCK_SIZE; nr_blocks > 0 {
direct_bytes := nr_blocks * _BLOCK_SIZE
_do_blocks(ctx, dst, nil, nr_blocks)
if st._off == _chacha20.BLOCK_SIZE {
if nr_blocks := remaining / _chacha20.BLOCK_SIZE; nr_blocks > 0 {
direct_bytes := nr_blocks * _chacha20.BLOCK_SIZE
stream_blocks(ctx, dst, nil, nr_blocks)
remaining -= direct_bytes
if remaining == 0 {
return
@@ -182,15 +132,15 @@ keystream_bytes :: proc(ctx: ^Context, dst: []byte) {
// If there is a partial block, generate and buffer 1 block
// worth of keystream.
_do_blocks(ctx, ctx._buffer[:], nil, 1)
ctx._off = 0
stream_blocks(ctx, st._buffer[:], nil, 1)
st._off = 0
}
// Process partial blocks from the buffered keystream.
to_copy := min(_BLOCK_SIZE - ctx._off, remaining)
buffered_keystream := ctx._buffer[ctx._off:]
to_copy := min(_chacha20.BLOCK_SIZE - st._off, remaining)
buffered_keystream := st._buffer[st._off:]
copy(dst[:to_copy], buffered_keystream[:to_copy])
ctx._off += to_copy
st._off += to_copy
dst = dst[to_copy:]
remaining -= to_copy
}
@@ -199,366 +149,5 @@ keystream_bytes :: proc(ctx: ^Context, dst: []byte) {
// reset sanitizes the Context. The Context must be re-initialized to
// be used again.
reset :: proc(ctx: ^Context) {
mem.zero_explicit(&ctx._s, size_of(ctx._s))
mem.zero_explicit(&ctx._buffer, size_of(ctx._buffer))
ctx._is_initialized = false
}
@(private)
_do_blocks :: proc(ctx: ^Context, dst, src: []byte, nr_blocks: int) {
// Enforce the maximum consumed keystream per nonce.
//
// While all modern "standard" definitions of ChaCha20 use
// the IETF 32-bit counter, for XChaCha20 most common
// implementations allow for a 64-bit counter.
//
// Honestly, the answer here is "use a MRAE primitive", but
// go with common practice in the case of XChaCha20.
if ctx._is_ietf_flavor {
if u64(ctx._s[12]) + u64(nr_blocks) > 0xffffffff {
panic("crypto/chacha20: maximum ChaCha20 keystream per nonce reached")
}
} else {
ctr := (u64(ctx._s[13]) << 32) | u64(ctx._s[12])
if _, carry := bits.add_u64(ctr, u64(nr_blocks), 0); carry != 0 {
panic("crypto/chacha20: maximum XChaCha20 keystream per nonce reached")
}
}
dst, src := dst, src
x := &ctx._s
for n := 0; n < nr_blocks; n = n + 1 {
x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3
x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 := x[4], x[5], x[6], x[7], x[8], x[9], x[10], x[11], x[12], x[13], x[14], x[15]
for i := _ROUNDS; i > 0; i = i - 2 {
// Even when forcing inlining manually inlining all of
// these is decently faster.
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ~= x0
x12 = bits.rotate_left32(x12, 16)
x8 += x12
x4 ~= x8
x4 = bits.rotate_left32(x4, 12)
x0 += x4
x12 ~= x0
x12 = bits.rotate_left32(x12, 8)
x8 += x12
x4 ~= x8
x4 = bits.rotate_left32(x4, 7)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ~= x1
x13 = bits.rotate_left32(x13, 16)
x9 += x13
x5 ~= x9
x5 = bits.rotate_left32(x5, 12)
x1 += x5
x13 ~= x1
x13 = bits.rotate_left32(x13, 8)
x9 += x13
x5 ~= x9
x5 = bits.rotate_left32(x5, 7)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ~= x2
x14 = bits.rotate_left32(x14, 16)
x10 += x14
x6 ~= x10
x6 = bits.rotate_left32(x6, 12)
x2 += x6
x14 ~= x2
x14 = bits.rotate_left32(x14, 8)
x10 += x14
x6 ~= x10
x6 = bits.rotate_left32(x6, 7)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ~= x3
x15 = bits.rotate_left32(x15, 16)
x11 += x15
x7 ~= x11
x7 = bits.rotate_left32(x7, 12)
x3 += x7
x15 ~= x3
x15 = bits.rotate_left32(x15, 8)
x11 += x15
x7 ~= x11
x7 = bits.rotate_left32(x7, 7)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ~= x0
x15 = bits.rotate_left32(x15, 16)
x10 += x15
x5 ~= x10
x5 = bits.rotate_left32(x5, 12)
x0 += x5
x15 ~= x0
x15 = bits.rotate_left32(x15, 8)
x10 += x15
x5 ~= x10
x5 = bits.rotate_left32(x5, 7)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ~= x1
x12 = bits.rotate_left32(x12, 16)
x11 += x12
x6 ~= x11
x6 = bits.rotate_left32(x6, 12)
x1 += x6
x12 ~= x1
x12 = bits.rotate_left32(x12, 8)
x11 += x12
x6 ~= x11
x6 = bits.rotate_left32(x6, 7)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ~= x2
x13 = bits.rotate_left32(x13, 16)
x8 += x13
x7 ~= x8
x7 = bits.rotate_left32(x7, 12)
x2 += x7
x13 ~= x2
x13 = bits.rotate_left32(x13, 8)
x8 += x13
x7 ~= x8
x7 = bits.rotate_left32(x7, 7)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ~= x3
x14 = bits.rotate_left32(x14, 16)
x9 += x14
x4 ~= x9
x4 = bits.rotate_left32(x4, 12)
x3 += x4
x14 ~= x3
x14 = bits.rotate_left32(x14, 8)
x9 += x14
x4 ~= x9
x4 = bits.rotate_left32(x4, 7)
}
x0 += _SIGMA_0
x1 += _SIGMA_1
x2 += _SIGMA_2
x3 += _SIGMA_3
x4 += x[4]
x5 += x[5]
x6 += x[6]
x7 += x[7]
x8 += x[8]
x9 += x[9]
x10 += x[10]
x11 += x[11]
x12 += x[12]
x13 += x[13]
x14 += x[14]
x15 += x[15]
// While the "correct" answer to getting more performance out of
// this is "use vector operations", support for that is currently
// a work in progress/to be designed.
//
// In the meantime:
// - The caller(s) ensure that src/dst are valid.
// - The compiler knows if the target is picky about alignment.
#no_bounds_check {
if src != nil {
endian.unchecked_put_u32le(dst[0:4], endian.unchecked_get_u32le(src[0:4]) ~ x0)
endian.unchecked_put_u32le(dst[4:8], endian.unchecked_get_u32le(src[4:8]) ~ x1)
endian.unchecked_put_u32le(dst[8:12], endian.unchecked_get_u32le(src[8:12]) ~ x2)
endian.unchecked_put_u32le(dst[12:16], endian.unchecked_get_u32le(src[12:16]) ~ x3)
endian.unchecked_put_u32le(dst[16:20], endian.unchecked_get_u32le(src[16:20]) ~ x4)
endian.unchecked_put_u32le(dst[20:24], endian.unchecked_get_u32le(src[20:24]) ~ x5)
endian.unchecked_put_u32le(dst[24:28], endian.unchecked_get_u32le(src[24:28]) ~ x6)
endian.unchecked_put_u32le(dst[28:32], endian.unchecked_get_u32le(src[28:32]) ~ x7)
endian.unchecked_put_u32le(dst[32:36], endian.unchecked_get_u32le(src[32:36]) ~ x8)
endian.unchecked_put_u32le(dst[36:40], endian.unchecked_get_u32le(src[36:40]) ~ x9)
endian.unchecked_put_u32le(dst[40:44], endian.unchecked_get_u32le(src[40:44]) ~ x10)
endian.unchecked_put_u32le(dst[44:48], endian.unchecked_get_u32le(src[44:48]) ~ x11)
endian.unchecked_put_u32le(dst[48:52], endian.unchecked_get_u32le(src[48:52]) ~ x12)
endian.unchecked_put_u32le(dst[52:56], endian.unchecked_get_u32le(src[52:56]) ~ x13)
endian.unchecked_put_u32le(dst[56:60], endian.unchecked_get_u32le(src[56:60]) ~ x14)
endian.unchecked_put_u32le(dst[60:64], endian.unchecked_get_u32le(src[60:64]) ~ x15)
src = src[_BLOCK_SIZE:]
} else {
endian.unchecked_put_u32le(dst[0:4], x0)
endian.unchecked_put_u32le(dst[4:8], x1)
endian.unchecked_put_u32le(dst[8:12], x2)
endian.unchecked_put_u32le(dst[12:16], x3)
endian.unchecked_put_u32le(dst[16:20], x4)
endian.unchecked_put_u32le(dst[20:24], x5)
endian.unchecked_put_u32le(dst[24:28], x6)
endian.unchecked_put_u32le(dst[28:32], x7)
endian.unchecked_put_u32le(dst[32:36], x8)
endian.unchecked_put_u32le(dst[36:40], x9)
endian.unchecked_put_u32le(dst[40:44], x10)
endian.unchecked_put_u32le(dst[44:48], x11)
endian.unchecked_put_u32le(dst[48:52], x12)
endian.unchecked_put_u32le(dst[52:56], x13)
endian.unchecked_put_u32le(dst[56:60], x14)
endian.unchecked_put_u32le(dst[60:64], x15)
}
dst = dst[_BLOCK_SIZE:]
}
// Increment the counter. Overflow checking is done upon
// entry into the routine, so a 64-bit increment safely
// covers both cases.
new_ctr := ((u64(ctx._s[13]) << 32) | u64(ctx._s[12])) + 1
x[12] = u32(new_ctr)
x[13] = u32(new_ctr >> 32)
}
}
@(private)
_hchacha20 :: proc "contextless" (dst, key, nonce: []byte) {
x0, x1, x2, x3 := _SIGMA_0, _SIGMA_1, _SIGMA_2, _SIGMA_3
x4 := endian.unchecked_get_u32le(key[0:4])
x5 := endian.unchecked_get_u32le(key[4:8])
x6 := endian.unchecked_get_u32le(key[8:12])
x7 := endian.unchecked_get_u32le(key[12:16])
x8 := endian.unchecked_get_u32le(key[16:20])
x9 := endian.unchecked_get_u32le(key[20:24])
x10 := endian.unchecked_get_u32le(key[24:28])
x11 := endian.unchecked_get_u32le(key[28:32])
x12 := endian.unchecked_get_u32le(nonce[0:4])
x13 := endian.unchecked_get_u32le(nonce[4:8])
x14 := endian.unchecked_get_u32le(nonce[8:12])
x15 := endian.unchecked_get_u32le(nonce[12:16])
for i := _ROUNDS; i > 0; i = i - 2 {
// quarterround(x, 0, 4, 8, 12)
x0 += x4
x12 ~= x0
x12 = bits.rotate_left32(x12, 16)
x8 += x12
x4 ~= x8
x4 = bits.rotate_left32(x4, 12)
x0 += x4
x12 ~= x0
x12 = bits.rotate_left32(x12, 8)
x8 += x12
x4 ~= x8
x4 = bits.rotate_left32(x4, 7)
// quarterround(x, 1, 5, 9, 13)
x1 += x5
x13 ~= x1
x13 = bits.rotate_left32(x13, 16)
x9 += x13
x5 ~= x9
x5 = bits.rotate_left32(x5, 12)
x1 += x5
x13 ~= x1
x13 = bits.rotate_left32(x13, 8)
x9 += x13
x5 ~= x9
x5 = bits.rotate_left32(x5, 7)
// quarterround(x, 2, 6, 10, 14)
x2 += x6
x14 ~= x2
x14 = bits.rotate_left32(x14, 16)
x10 += x14
x6 ~= x10
x6 = bits.rotate_left32(x6, 12)
x2 += x6
x14 ~= x2
x14 = bits.rotate_left32(x14, 8)
x10 += x14
x6 ~= x10
x6 = bits.rotate_left32(x6, 7)
// quarterround(x, 3, 7, 11, 15)
x3 += x7
x15 ~= x3
x15 = bits.rotate_left32(x15, 16)
x11 += x15
x7 ~= x11
x7 = bits.rotate_left32(x7, 12)
x3 += x7
x15 ~= x3
x15 = bits.rotate_left32(x15, 8)
x11 += x15
x7 ~= x11
x7 = bits.rotate_left32(x7, 7)
// quarterround(x, 0, 5, 10, 15)
x0 += x5
x15 ~= x0
x15 = bits.rotate_left32(x15, 16)
x10 += x15
x5 ~= x10
x5 = bits.rotate_left32(x5, 12)
x0 += x5
x15 ~= x0
x15 = bits.rotate_left32(x15, 8)
x10 += x15
x5 ~= x10
x5 = bits.rotate_left32(x5, 7)
// quarterround(x, 1, 6, 11, 12)
x1 += x6
x12 ~= x1
x12 = bits.rotate_left32(x12, 16)
x11 += x12
x6 ~= x11
x6 = bits.rotate_left32(x6, 12)
x1 += x6
x12 ~= x1
x12 = bits.rotate_left32(x12, 8)
x11 += x12
x6 ~= x11
x6 = bits.rotate_left32(x6, 7)
// quarterround(x, 2, 7, 8, 13)
x2 += x7
x13 ~= x2
x13 = bits.rotate_left32(x13, 16)
x8 += x13
x7 ~= x8
x7 = bits.rotate_left32(x7, 12)
x2 += x7
x13 ~= x2
x13 = bits.rotate_left32(x13, 8)
x8 += x13
x7 ~= x8
x7 = bits.rotate_left32(x7, 7)
// quarterround(x, 3, 4, 9, 14)
x3 += x4
x14 ~= x3
x14 = bits.rotate_left32(x14, 16)
x9 += x14
x4 ~= x9
x4 = bits.rotate_left32(x4, 12)
x3 += x4
x14 ~= x3
x14 = bits.rotate_left32(x14, 8)
x9 += x14
x4 ~= x9
x4 = bits.rotate_left32(x4, 7)
}
endian.unchecked_put_u32le(dst[0:4], x0)
endian.unchecked_put_u32le(dst[4:8], x1)
endian.unchecked_put_u32le(dst[8:12], x2)
endian.unchecked_put_u32le(dst[12:16], x3)
endian.unchecked_put_u32le(dst[16:20], x12)
endian.unchecked_put_u32le(dst[20:24], x13)
endian.unchecked_put_u32le(dst[24:28], x14)
endian.unchecked_put_u32le(dst[28:32], x15)
_chacha20.reset(&ctx._state)
}
+56
View File
@@ -0,0 +1,56 @@
package chacha20
import "base:intrinsics"
import "core:crypto/_chacha20/ref"
import "core:crypto/_chacha20/simd128"
import "core:crypto/_chacha20/simd256"
// DEFAULT_IMPLEMENTATION is the implementation that will be used by
// default if possible.
DEFAULT_IMPLEMENTATION :: Implementation.Simd256
// Implementation is a ChaCha20 implementation. Most callers will not need
// to use this as the package will automatically select the most performant
// implementation available.
Implementation :: enum {
Portable,
Simd128,
Simd256,
}
@(private)
init_impl :: proc(ctx: ^Context, impl: Implementation) {
impl := impl
if impl == .Simd256 && !simd256.is_performant() {
impl = .Simd128
}
if impl == .Simd128 && !simd128.is_performant() {
impl = .Portable
}
ctx._impl = impl
}
@(private)
stream_blocks :: proc(ctx: ^Context, dst, src: []byte, nr_blocks: int) {
switch ctx._impl {
case .Simd256:
simd256.stream_blocks(&ctx._state, dst, src, nr_blocks)
case .Simd128:
simd128.stream_blocks(&ctx._state, dst, src, nr_blocks)
case .Portable:
ref.stream_blocks(&ctx._state, dst, src, nr_blocks)
}
}
@(private)
hchacha20 :: proc "contextless" (dst, key, iv: []byte, impl: Implementation) {
switch impl {
case .Simd256:
simd256.hchacha20(dst, key, iv)
case .Simd128:
simd128.hchacha20(dst, key, iv)
case .Portable:
ref.hchacha20(dst, key, iv)
}
}
@@ -1,9 +1,11 @@
/*
package chacha20poly1305 implements the AEAD_CHACHA20_POLY1305 Authenticated
Encryption with Additional Data algorithm.
package chacha20poly1305 implements the AEAD_CHACHA20_POLY1305 and
AEAD_XChaCha20_Poly1305 Authenticated Encryption with Additional Data
algorithms.
See:
- https://www.rfc-editor.org/rfc/rfc8439
- https://datatracker.ietf.org/doc/html/draft-arciszewski-xchacha-03
*/
package chacha20poly1305
@@ -15,8 +17,10 @@ import "core:mem"
// KEY_SIZE is the chacha20poly1305 key size in bytes.
KEY_SIZE :: chacha20.KEY_SIZE
// NONCE_SIZE is the chacha20poly1305 nonce size in bytes.
NONCE_SIZE :: chacha20.NONCE_SIZE
// IV_SIZE is the chacha20poly1305 IV size in bytes.
IV_SIZE :: chacha20.IV_SIZE
// XIV_SIZE is the xchacha20poly1305 IV size in bytes.
XIV_SIZE :: chacha20.XIV_SIZE
// TAG_SIZE is the chacha20poly1305 tag size in bytes.
TAG_SIZE :: poly1305.TAG_SIZE
@@ -24,15 +28,13 @@ TAG_SIZE :: poly1305.TAG_SIZE
_P_MAX :: 64 * 0xffffffff // 64 * (2^32-1)
@(private)
_validate_common_slice_sizes :: proc (tag, key, nonce, aad, text: []byte) {
_validate_common_slice_sizes :: proc (tag, iv, aad, text: []byte, is_xchacha: bool) {
if len(tag) != TAG_SIZE {
panic("crypto/chacha20poly1305: invalid destination tag size")
}
if len(key) != KEY_SIZE {
panic("crypto/chacha20poly1305: invalid key size")
}
if len(nonce) != NONCE_SIZE {
panic("crypto/chacha20poly1305: invalid nonce size")
expected_iv_len := is_xchacha ? XIV_SIZE : IV_SIZE
if len(iv) != expected_iv_len {
panic("crypto/chacha20poly1305: invalid IV size")
}
#assert(size_of(int) == 8 || size_of(int) <= 4)
@@ -59,18 +61,52 @@ _update_mac_pad16 :: #force_inline proc (ctx: ^poly1305.Context, x_len: int) {
}
}
// encrypt encrypts the plaintext and authenticates the aad and ciphertext,
// with the provided key and nonce, stores the output in ciphertext and tag.
encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) {
_validate_common_slice_sizes(tag, key, nonce, aad, plaintext)
// Context is a keyed (X)Chacha20Poly1305 instance.
Context :: struct {
_key: [KEY_SIZE]byte,
_impl: chacha20.Implementation,
_is_xchacha: bool,
_is_initialized: bool,
}
// init initializes a Context with the provided key, for AEAD_CHACHA20_POLY1305.
init :: proc(ctx: ^Context, key: []byte, impl := chacha20.DEFAULT_IMPLEMENTATION) {
if len(key) != KEY_SIZE {
panic("crypto/chacha20poly1305: invalid key size")
}
copy(ctx._key[:], key)
ctx._impl = impl
ctx._is_xchacha = false
ctx._is_initialized = true
}
// init_xchacha initializes a Context with the provided key, for
// AEAD_XChaCha20_Poly1305.
//
// Note: While there are multiple definitions of XChaCha20-Poly1305
// this sticks to the IETF draft and uses a 32-bit counter.
init_xchacha :: proc(ctx: ^Context, key: []byte, impl := chacha20.DEFAULT_IMPLEMENTATION) {
init(ctx, key, impl)
ctx._is_xchacha = true
}
// seal encrypts the plaintext and authenticates the aad and ciphertext,
// with the provided Context and iv, stores the output in dst and tag.
//
// dst and plaintext MUST alias exactly or not at all.
seal :: proc(ctx: ^Context, dst, tag, iv, aad, plaintext: []byte) {
ciphertext := dst
_validate_common_slice_sizes(tag, iv, aad, plaintext, ctx._is_xchacha)
if len(ciphertext) != len(plaintext) {
panic("crypto/chacha20poly1305: invalid destination ciphertext size")
}
stream_ctx: chacha20.Context = ---
chacha20.init(&stream_ctx, key, nonce)
chacha20.init(&stream_ctx, ctx._key[:],iv, ctx._impl)
stream_ctx._state._is_ietf_flavor = true
// otk = poly1305_key_gen(key, nonce)
// otk = poly1305_key_gen(key, iv)
otk: [poly1305.KEY_SIZE]byte = ---
chacha20.keystream_bytes(&stream_ctx, otk[:])
mac_ctx: poly1305.Context = ---
@@ -87,7 +123,7 @@ encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) {
poly1305.update(&mac_ctx, aad)
_update_mac_pad16(&mac_ctx, aad_len)
// ciphertext = chacha20_encrypt(key, 1, nonce, plaintext)
// ciphertext = chacha20_encrypt(key, 1, iv, plaintext)
chacha20.seek(&stream_ctx, 1)
chacha20.xor_bytes(&stream_ctx, ciphertext, plaintext)
chacha20.reset(&stream_ctx) // Don't need the stream context anymore.
@@ -107,13 +143,16 @@ encrypt :: proc (ciphertext, tag, key, nonce, aad, plaintext: []byte) {
poly1305.final(&mac_ctx, tag) // Implicitly sanitizes context.
}
// decrypt authenticates the aad and ciphertext, and decrypts the ciphertext,
// with the provided key, nonce, and tag, and stores the output in plaintext,
// returning true iff the authentication was successful.
// open authenticates the aad and ciphertext, and decrypts the ciphertext,
// with the provided Context, iv, and tag, and stores the output in dst,
// returning true iff the authentication was successful. If authentication
// fails, the destination buffer will be zeroed.
//
// If authentication fails, the destination plaintext buffer will be zeroed.
decrypt :: proc (plaintext, tag, key, nonce, aad, ciphertext: []byte) -> bool {
_validate_common_slice_sizes(tag, key, nonce, aad, ciphertext)
// dst and plaintext MUST alias exactly or not at all.
@(require_results)
open :: proc(ctx: ^Context, dst, iv, aad, ciphertext, tag: []byte) -> bool {
plaintext := dst
_validate_common_slice_sizes(tag, iv, aad, ciphertext, ctx._is_xchacha)
if len(ciphertext) != len(plaintext) {
panic("crypto/chacha20poly1305: invalid destination plaintext size")
}
@@ -123,9 +162,10 @@ decrypt :: proc (plaintext, tag, key, nonce, aad, ciphertext: []byte) -> bool {
// points where needed.
stream_ctx: chacha20.Context = ---
chacha20.init(&stream_ctx, key, nonce)
chacha20.init(&stream_ctx, ctx._key[:], iv, ctx._impl)
stream_ctx._state._is_ietf_flavor = true
// otk = poly1305_key_gen(key, nonce)
// otk = poly1305_key_gen(key, iv)
otk: [poly1305.KEY_SIZE]byte = ---
chacha20.keystream_bytes(&stream_ctx, otk[:])
defer chacha20.reset(&stream_ctx)
@@ -160,9 +200,17 @@ decrypt :: proc (plaintext, tag, key, nonce, aad, ciphertext: []byte) -> bool {
return false
}
// plaintext = chacha20_decrypt(key, 1, nonce, ciphertext)
// plaintext = chacha20_decrypt(key, 1, iv, ciphertext)
chacha20.seek(&stream_ctx, 1)
chacha20.xor_bytes(&stream_ctx, plaintext, ciphertext)
return true
}
// reset sanitizes the Context. The Context must be
// re-initialized to be used again.
reset :: proc "contextless" (ctx: ^Context) {
mem.zero_explicit(&ctx._key, len(ctx._key))
ctx._is_xchacha = false
ctx._is_initialized = false
}
+6 -2
View File
@@ -60,7 +60,11 @@ rand_bytes :: proc (dst: []byte) {
_rand_bytes(dst)
}
// random_generator returns a `runtime.Random_Generator` backed by the
// system entropy source.
//
// Support for the system entropy source can be checked with the
// `HAS_RAND_BYTES` boolean constant.
random_generator :: proc() -> runtime.Random_Generator {
return {
procedure = proc(data: rawptr, mode: runtime.Random_Generator_Mode, p: []byte) {
@@ -79,4 +83,4 @@ random_generator :: proc() -> runtime.Random_Generator {
},
data = nil,
}
}
}
+4 -4
View File
@@ -21,7 +21,7 @@ PUBLIC_KEY_SIZE :: 32
SIGNATURE_SIZE :: 64
@(private)
NONCE_SIZE :: 32
HDIGEST2_SIZE :: 32
// Private_Key is an Ed25519 private key.
Private_Key :: struct {
@@ -33,7 +33,7 @@ Private_Key :: struct {
// See: https://github.com/MystenLabs/ed25519-unsafe-libs
_b: [PRIVATE_KEY_SIZE]byte,
_s: grp.Scalar,
_nonce: [NONCE_SIZE]byte,
_hdigest2: [HDIGEST2_SIZE]byte,
_pub_key: Public_Key,
_is_initialized: bool,
}
@@ -63,7 +63,7 @@ private_key_set_bytes :: proc(priv_key: ^Private_Key, b: []byte) -> bool {
sha2.final(&ctx, h_bytes[:])
copy(priv_key._b[:], b)
copy(priv_key._nonce[:], h_bytes[32:])
copy(priv_key._hdigest2[:], h_bytes[32:])
grp.sc_set_bytes_rfc8032(&priv_key._s, h_bytes[:32])
// Derive the corresponding public key.
@@ -116,7 +116,7 @@ sign :: proc(priv_key: ^Private_Key, msg, sig: []byte) {
ctx: sha2.Context_512 = ---
digest_bytes: [sha2.DIGEST_SIZE_512]byte = ---
sha2.init_512(&ctx)
sha2.update(&ctx, priv_key._nonce[:])
sha2.update(&ctx, priv_key._hdigest2[:])
sha2.update(&ctx, msg)
sha2.final(&ctx, digest_bytes[:])
+11 -5
View File
@@ -28,20 +28,26 @@ hash_bytes :: proc(algorithm: Algorithm, data: []byte, allocator := context.allo
// hash_string_to_buffer will hash the given input and assign the
// computed digest to the third parameter. It requires that the
// destination buffer is at least as big as the digest size.
hash_string_to_buffer :: proc(algorithm: Algorithm, data: string, hash: []byte) {
hash_bytes_to_buffer(algorithm, transmute([]byte)(data), hash)
// destination buffer is at least as big as the digest size. The
// provided destination buffer is returned to match the behavior of
// `hash_string`.
hash_string_to_buffer :: proc(algorithm: Algorithm, data: string, hash: []byte) -> []byte {
return hash_bytes_to_buffer(algorithm, transmute([]byte)(data), hash)
}
// hash_bytes_to_buffer will hash the given input and write the
// computed digest into the third parameter. It requires that the
// destination buffer is at least as big as the digest size.
hash_bytes_to_buffer :: proc(algorithm: Algorithm, data, hash: []byte) {
// destination buffer is at least as big as the digest size. The
// provided destination buffer is returned to match the behavior of
// `hash_bytes`.
hash_bytes_to_buffer :: proc(algorithm: Algorithm, data, hash: []byte) -> []byte {
ctx: Context
init(&ctx, algorithm)
update(&ctx, data)
final(&ctx, hash)
return hash
}
// hash_stream will incrementally fully consume a stream, and return the
+3 -3
View File
@@ -8,9 +8,9 @@ HAS_RAND_BYTES :: true
@(private)
_rand_bytes :: proc(dst: []byte) {
ret := (os.Errno)(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
if ret != os.ERROR_NONE {
switch ret {
ret := os.Platform_Error(win32.BCryptGenRandom(nil, raw_data(dst), u32(len(dst)), win32.BCRYPT_USE_SYSTEM_PREFERRED_RNG))
if ret != nil {
#partial switch ret {
case os.ERROR_INVALID_HANDLE:
// The handle to the first parameter is invalid.
// This should not happen here, since we explicitly pass nil to it
+5 -13
View File
@@ -16,15 +16,12 @@ Library :: distinct rawptr
Loads a dynamic library from the filesystem. The paramater `global_symbols` makes the symbols in the loaded
library available to resolve references in subsequently loaded libraries.
The paramater `global_symbols` is only used for the platforms `linux`, `darwin`, `freebsd` and `openbsd`.
The parameter `global_symbols` is only used for the platforms `linux`, `darwin`, `freebsd` and `openbsd`.
On `windows` this paramater is ignored.
The underlying behaviour is platform specific.
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlopen`.
On `windows` refer to `LoadLibraryW`.
**Implicit Allocators**
`context.temp_allocator`
On `windows` refer to `LoadLibraryW`. Also temporarily needs an allocator to convert a string.
Example:
import "core:dynlib"
@@ -79,10 +76,7 @@ Loads the address of a procedure/variable from a dynamic library.
The underlying behaviour is platform specific.
On `linux`, `darwin`, `freebsd` and `openbsd` refer to `dlsym`.
On `windows` refer to `GetProcAddress`.
**Implicit Allocators**
`context.temp_allocator`
On `windows` refer to `GetProcAddress`. Also temporarily needs an allocator to convert a string.
Example:
import "core:dynlib"
@@ -177,9 +171,7 @@ initialize_symbols :: proc(
return count, count > 0
}
/*
Returns an error message for the last failed procedure call.
*/
// Returns an error message for the last failed procedure call.
last_error :: proc() -> string {
return _last_error()
}
}
+1 -1
View File
@@ -16,4 +16,4 @@ _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found
_last_error :: proc() -> string {
return ""
}
}
+1 -1
View File
@@ -26,4 +26,4 @@ _symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found
_last_error :: proc() -> string {
err := os.dlerror()
return "unknown" if err == "" else err
}
}
+7 -9
View File
@@ -4,14 +4,12 @@ package dynlib
import win32 "core:sys/windows"
import "core:strings"
import "base:runtime"
import "core:reflect"
_load_library :: proc(path: string, global_symbols := false) -> (Library, bool) {
_load_library :: proc(path: string, global_symbols := false, allocator := context.temp_allocator) -> (Library, bool) {
// NOTE(bill): 'global_symbols' is here only for consistency with POSIX which has RTLD_GLOBAL
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
wide_path := win32.utf8_to_wstring(path, context.temp_allocator)
wide_path := win32.utf8_to_wstring(path, allocator)
defer free(wide_path, allocator)
handle := cast(Library)win32.LoadLibraryW(wide_path)
return handle, handle != nil
}
@@ -21,9 +19,9 @@ _unload_library :: proc(library: Library) -> bool {
return bool(ok)
}
_symbol_address :: proc(library: Library, symbol: string) -> (ptr: rawptr, found: bool) {
runtime.DEFAULT_TEMP_ALLOCATOR_TEMP_GUARD()
c_str := strings.clone_to_cstring(symbol, context.temp_allocator)
_symbol_address :: proc(library: Library, symbol: string, allocator := context.temp_allocator) -> (ptr: rawptr, found: bool) {
c_str := strings.clone_to_cstring(symbol, allocator)
defer delete(c_str, allocator)
ptr = win32.GetProcAddress(cast(win32.HMODULE)library, c_str)
found = ptr != nil
return
@@ -33,4 +31,4 @@ _last_error :: proc() -> string {
err := win32.System_Error(win32.GetLastError())
err_msg := reflect.enum_string(err)
return "unknown" if err_msg == "" else err_msg
}
}
+3 -2
View File
@@ -3,6 +3,7 @@ package encoding_cbor
import "base:intrinsics"
import "core:encoding/json"
import "core:encoding/hex"
import "core:io"
import "core:mem"
import "core:strconv"
@@ -399,11 +400,11 @@ to_diagnostic_format_writer :: proc(w: io.Writer, val: Value, padding := 0) -> i
io.write_string(w, str) or_return
case bool: io.write_string(w, "true" if v else "false") or_return
case Nil: io.write_string(w, "nil") or_return
case Nil: io.write_string(w, "null") or_return
case Undefined: io.write_string(w, "undefined") or_return
case ^Bytes:
io.write_string(w, "h'") or_return
for b in v { io.write_int(w, int(b), 16) or_return }
hex.encode_into_writer(w, v^) or_return
io.write_string(w, "'") or_return
case ^Text:
io.write_string(w, `"`) or_return
+33 -5
View File
@@ -77,8 +77,11 @@ You can look at the default tags provided for pointers on how these implementati
Example:
package main
import "base:intrinsics"
import "core:encoding/cbor"
import "core:fmt"
import "core:reflect"
import "core:time"
Possibilities :: union {
@@ -93,9 +96,32 @@ Example:
ignore_this: ^Data `cbor:"-"`, // Ignored by implementation.
renamed: f32 `cbor:"renamed :)"`, // Renamed when encoded.
my_union: Possibilities, // Union support.
my_raw: [8]u32 `cbor_tag:"raw"`, // Custom tag that just writes the value as bytes.
}
main :: proc() {
// Example custom tag implementation that instead of breaking down all parts,
// just writes the value as a big byte blob. This is an advanced feature but very powerful.
RAW_TAG_NR :: 200
cbor.tag_register_number({
marshal = proc(_: ^cbor.Tag_Implementation, e: cbor.Encoder, v: any) -> cbor.Marshal_Error {
cbor._encode_u8(e.writer, RAW_TAG_NR, .Tag) or_return
return cbor.err_conv(cbor._encode_bytes(e, reflect.as_bytes(v)))
},
unmarshal = proc(_: ^cbor.Tag_Implementation, d: cbor.Decoder, _: cbor.Tag_Number, v: any) -> (cbor.Unmarshal_Error) {
hdr := cbor._decode_header(d.reader) or_return
maj, add := cbor._header_split(hdr)
if maj != .Bytes {
return .Bad_Tag_Value
}
bytes := cbor.err_conv(cbor._decode_bytes(d, add, maj)) or_return
intrinsics.mem_copy_non_overlapping(v.data, raw_data(bytes), len(bytes))
return nil
},
}, RAW_TAG_NR, "raw")
now := time.Time{_nsec = 1701117968 * 1e9}
data := Data{
@@ -105,21 +131,22 @@ Example:
ignore_this = &Data{},
renamed = 123123.125,
my_union = 3,
my_raw = {1=1, 2=2, 3=3},
}
// Marshal the struct into binary CBOR.
binary, err := cbor.marshal(data, cbor.ENCODE_FULLY_DETERMINISTIC)
assert(err == nil)
fmt.assertf(err == nil, "marshal error: %v", err)
defer delete(binary)
// Decode the binary data into a `cbor.Value`.
decoded, derr := cbor.decode(string(binary))
assert(derr == nil)
fmt.assertf(derr == nil, "decode error: %v", derr)
defer cbor.destroy(decoded)
// Turn the CBOR into a human readable representation defined as the diagnostic format in [[RFC 8949 Section 8;https://www.rfc-editor.org/rfc/rfc8949.html#name-diagnostic-notation]].
diagnosis, eerr := cbor.to_diagnostic_format(decoded)
assert(eerr == nil)
fmt.assertf(eerr == nil, "to diagnostic error: %v", eerr)
defer delete(diagnosis)
fmt.println(diagnosis)
@@ -127,6 +154,7 @@ Example:
Output:
{
"my_raw": 200(h'00001000200030000000000000000000'),
"my_union": 1010([
"int",
3
+71 -28
View File
@@ -54,7 +54,7 @@ marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.a
defer if err != nil { strings.builder_destroy(&b) }
if err = marshal_into_builder(&b, v, flags, temp_allocator, loc=loc); err != nil {
if err = marshal_into_builder(&b, v, flags, temp_allocator); err != nil {
return
}
@@ -63,20 +63,20 @@ marshal_into_bytes :: proc(v: any, flags := ENCODE_SMALL, allocator := context.a
// Marshals the given value into a CBOR byte stream written to the given builder.
// See docs on the `marshal_into` proc group for more info.
marshal_into_builder :: proc(b: ^strings.Builder, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Marshal_Error {
return marshal_into_writer(strings.to_writer(b), v, flags, temp_allocator, loc=loc)
marshal_into_builder :: proc(b: ^strings.Builder, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error {
return marshal_into_writer(strings.to_writer(b), v, flags, temp_allocator)
}
// Marshals the given value into a CBOR byte stream written to the given writer.
// See docs on the `marshal_into` proc group for more info.
marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator, loc := #caller_location) -> Marshal_Error {
marshal_into_writer :: proc(w: io.Writer, v: any, flags := ENCODE_SMALL, temp_allocator := context.temp_allocator) -> Marshal_Error {
encoder := Encoder{flags, w, temp_allocator}
return marshal_into_encoder(encoder, v, loc=loc)
return marshal_into_encoder(encoder, v)
}
// Marshals the given value into a CBOR byte stream written to the given encoder.
// See docs on the `marshal_into` proc group for more info.
marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (err: Marshal_Error) {
marshal_into_encoder :: proc(e: Encoder, v: any) -> (err: Marshal_Error) {
e := e
if e.temp_allocator.procedure == nil {
@@ -97,11 +97,14 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e
return impl->marshal(e, v)
}
ti := runtime.type_info_base(type_info_of(v.id))
a := any{v.data, ti.id}
ti := runtime.type_info_core(type_info_of(v.id))
return _marshal_into_encoder(e, v, ti)
}
_marshal_into_encoder :: proc(e: Encoder, v: any, ti: ^runtime.Type_Info) -> (err: Marshal_Error) {
a := any{v.data, ti.id}
#partial switch info in ti.variant {
case runtime.Type_Info_Named:
case runtime.Type_Info_Named, runtime.Type_Info_Enum, runtime.Type_Info_Bit_Field:
unreachable()
case runtime.Type_Info_Pointer:
@@ -223,18 +226,38 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e
}
err_conv(_encode_u64(e, u64(info.count), .Array)) or_return
if impl, ok := _tag_implementations_type[info.elem.id]; ok {
for i in 0..<info.count {
data := uintptr(v.data) + uintptr(i*info.elem_size)
impl->marshal(e, any{rawptr(data), info.elem.id}) or_return
}
return
}
elem_ti := runtime.type_info_core(type_info_of(info.elem.id))
for i in 0..<info.count {
data := uintptr(v.data) + uintptr(i*info.elem_size)
marshal_into(e, any{rawptr(data), info.elem.id}) or_return
_marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return
}
return
case runtime.Type_Info_Enumerated_Array:
// index := runtime.type_info_base(info.index).variant.(runtime.Type_Info_Enum)
err_conv(_encode_u64(e, u64(info.count), .Array)) or_return
if impl, ok := _tag_implementations_type[info.elem.id]; ok {
for i in 0..<info.count {
data := uintptr(v.data) + uintptr(i*info.elem_size)
impl->marshal(e, any{rawptr(data), info.elem.id}) or_return
}
return
}
elem_ti := runtime.type_info_core(type_info_of(info.elem.id))
for i in 0..<info.count {
data := uintptr(v.data) + uintptr(i*info.elem_size)
marshal_into(e, any{rawptr(data), info.elem.id}) or_return
_marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return
}
return
@@ -246,9 +269,19 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e
array := (^mem.Raw_Dynamic_Array)(v.data)
err_conv(_encode_u64(e, u64(array.len), .Array)) or_return
if impl, ok := _tag_implementations_type[info.elem.id]; ok {
for i in 0..<array.len {
data := uintptr(array.data) + uintptr(i*info.elem_size)
impl->marshal(e, any{rawptr(data), info.elem.id}) or_return
}
return
}
elem_ti := runtime.type_info_core(type_info_of(info.elem.id))
for i in 0..<array.len {
data := uintptr(array.data) + uintptr(i*info.elem_size)
marshal_into(e, any{rawptr(data), info.elem.id}) or_return
_marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return
}
return
@@ -260,9 +293,19 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e
array := (^mem.Raw_Slice)(v.data)
err_conv(_encode_u64(e, u64(array.len), .Array)) or_return
if impl, ok := _tag_implementations_type[info.elem.id]; ok {
for i in 0..<array.len {
data := uintptr(array.data) + uintptr(i*info.elem_size)
impl->marshal(e, any{rawptr(data), info.elem.id}) or_return
}
return
}
elem_ti := runtime.type_info_core(type_info_of(info.elem.id))
for i in 0..<array.len {
data := uintptr(array.data) + uintptr(i*info.elem_size)
marshal_into(e, any{rawptr(data), info.elem.id}) or_return
_marshal_into_encoder(e, any{rawptr(data), info.elem.id}, elem_ti) or_return
}
return
@@ -308,7 +351,8 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e
builder := strings.builder_from_slice(res[:])
e.writer = strings.to_stream(&builder)
assert(_encode_u64(e, u64(len(str)), .Text) == nil)
err := _encode_u64(e, u64(len(str)), .Text)
assert(err == nil)
res[9] = u8(len(builder.buf))
assert(res[9] < 10)
return
@@ -437,9 +481,7 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e
}
}
marshal_entry :: #force_inline proc(e: Encoder, info: runtime.Type_Info_Struct, v: any, name: string, i: int) -> Marshal_Error {
err_conv(_encode_text(e, name)) or_return
marshal_entry :: #force_inline proc(e: Encoder, info: runtime.Type_Info_Struct, v: any, i: int) -> Marshal_Error {
id := info.types[i].id
data := rawptr(uintptr(v.data) + info.offsets[i])
field_any := any{data, id}
@@ -463,7 +505,7 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e
}
n: u64; {
for _, i in info.names {
for _, i in info.names[:info.field_count] {
if field_name(info, i) != "-" {
n += 1
}
@@ -473,37 +515,41 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e
if .Deterministic_Map_Sorting in e.flags {
Name :: struct {
name: string,
name: []byte,
field: int,
}
entries := make([dynamic]Name, 0, n, e.temp_allocator) or_return
defer delete(entries)
for _, i in info.names {
for _, i in info.names[:info.field_count] {
fname := field_name(info, i)
if fname == "-" {
continue
}
append(&entries, Name{fname, i}) or_return
key_builder := strings.builder_make(e.temp_allocator) or_return
err_conv(_encode_text(Encoder{e.flags, strings.to_stream(&key_builder), e.temp_allocator}, fname)) or_return
append(&entries, Name{key_builder.buf[:], i}) or_return
}
// Sort lexicographic on the bytes of the key.
slice.sort_by_cmp(entries[:], proc(a, b: Name) -> slice.Ordering {
return slice.Ordering(bytes.compare(transmute([]byte)a.name, transmute([]byte)b.name))
return slice.Ordering(bytes.compare(a.name, b.name))
})
for entry in entries {
marshal_entry(e, info, v, entry.name, entry.field) or_return
io.write_full(e.writer, entry.name) or_return
marshal_entry(e, info, v, entry.field) or_return
}
} else {
for _, i in info.names {
for _, i in info.names[:info.field_count] {
fname := field_name(info, i)
if fname == "-" {
continue
}
marshal_entry(e, info, v, fname, i) or_return
err_conv(_encode_text(e, fname)) or_return
marshal_entry(e, info, v, i) or_return
}
}
return
@@ -542,9 +588,6 @@ marshal_into_encoder :: proc(e: Encoder, v: any, loc := #caller_location) -> (e
return marshal_into(e, any{v.data, vti.id})
case runtime.Type_Info_Enum:
return marshal_into(e, any{v.data, info.base.id})
case runtime.Type_Info_Bit_Set:
// Store bit_set as big endian just like the protocol.
do_byte_swap := !reflect.bit_set_is_big_endian(v)
+9 -16
View File
@@ -96,7 +96,8 @@ _unmarshal_value :: proc(d: Decoder, v: any, hdr: Header, allocator := context.a
ti = reflect.type_info_base(variant)
if !reflect.is_pointer_internally(variant) {
tag := any{rawptr(uintptr(v.data) + u.tag_offset), u.tag_type.id}
assert(_assign_int(tag, 1))
assigned := _assign_int(tag, 1)
assert(assigned)
}
}
}
@@ -520,9 +521,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
return
case reflect.Type_Info_Array:
_, scap := err_conv(_decode_len_container(d, add)) or_return
length := min(scap, t.count)
length, _ := err_conv(_decode_len_container(d, add)) or_return
if length > t.count {
return _unsupported(v, hdr)
}
@@ -534,9 +533,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
return
case reflect.Type_Info_Enumerated_Array:
_, scap := err_conv(_decode_len_container(d, add)) or_return
length := min(scap, t.count)
length, _ := err_conv(_decode_len_container(d, add)) or_return
if length > t.count {
return _unsupported(v, hdr)
}
@@ -548,9 +545,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
return
case reflect.Type_Info_Complex:
_, scap := err_conv(_decode_len_container(d, add)) or_return
length := min(scap, 2)
length, _ := err_conv(_decode_len_container(d, add)) or_return
if length > 2 {
return _unsupported(v, hdr)
}
@@ -570,9 +565,7 @@ _unmarshal_array :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header
return
case reflect.Type_Info_Quaternion:
_, scap := err_conv(_decode_len_container(d, add)) or_return
length := min(scap, 4)
length, _ := err_conv(_decode_len_container(d, add)) or_return
if length > 4 {
return _unsupported(v, hdr)
}
@@ -626,14 +619,14 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header,
#partial switch t in ti.variant {
case reflect.Type_Info_Struct:
if t.is_raw_union {
if .raw_union in t.flags {
return _unsupported(v, hdr)
}
length, _ := err_conv(_decode_len_container(d, add)) or_return
unknown := length == -1
fields := reflect.struct_fields_zipped(ti.id)
for idx := 0; idx < len(fields) && (unknown || idx < length); idx += 1 {
// Decode key, keys can only be strings.
key: string
@@ -646,7 +639,7 @@ _unmarshal_map :: proc(d: Decoder, v: any, ti: ^reflect.Type_Info, hdr: Header,
key = keyv
}
defer delete(key, context.temp_allocator)
// Find matching field.
use_field_idx := -1
{
+9 -7
View File
@@ -13,13 +13,14 @@ iterate_csv_from_string :: proc(filename: string) {
r.reuse_record_buffer = true // Without it you have to each of the fields within it
defer csv.reader_destroy(&r)
if csv_data, ok := os.read_entire_file(filename); ok {
csv_data, ok := os.read_entire_file(filename)
if ok {
csv.reader_init_with_string(&r, string(csv_data))
defer delete(csv_data)
} else {
fmt.printfln("Unable to open file: %v", filename)
return
}
defer delete(csv_data)
for r, i, err in csv.iterator_next(&r) {
if err != nil { /* Do something with error */ }
@@ -38,9 +39,9 @@ iterate_csv_from_stream :: proc(filename: string) {
r.reuse_record_buffer = true // Without it you have to each of the fields within it
defer csv.reader_destroy(&r)
handle, errno := os.open(filename)
if errno != os.ERROR_NONE {
fmt.printfln("Error opening file: %v", filename)
handle, err := os.open(filename)
if err != nil {
fmt.eprintfln("Error opening file: %v", filename)
return
}
defer os.close(handle)
@@ -62,13 +63,14 @@ read_csv_from_string :: proc(filename: string) {
r.reuse_record_buffer = true // Without it you have to each of the fields within it
defer csv.reader_destroy(&r)
if csv_data, ok := os.read_entire_file(filename); ok {
csv_data, ok := os.read_entire_file(filename)
if ok {
csv.reader_init_with_string(&r, string(csv_data))
defer delete(csv_data)
} else {
fmt.printfln("Unable to open file: %v", filename)
return
}
defer delete(csv_data)
records, err := csv.read_all(&r)
if err != nil { /* Do something with CSV parse error */ }
+7
View File
@@ -1,5 +1,6 @@
package encoding_hex
import "core:io"
import "core:strings"
encode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> []byte #no_bounds_check {
@@ -14,6 +15,12 @@ encode :: proc(src: []byte, allocator := context.allocator, loc := #caller_locat
return dst
}
encode_into_writer :: proc(dst: io.Writer, src: []byte) -> io.Error {
for v in src {
io.write(dst, {HEXTABLE[v>>4], HEXTABLE[v&0x0f]}) or_return
}
return nil
}
decode :: proc(src: []byte, allocator := context.allocator, loc := #caller_location) -> (dst: []byte, ok: bool) #no_bounds_check {
if len(src) % 2 == 1 {
+12 -9
View File
@@ -82,15 +82,17 @@ Map :: distinct map[string]map[string]string
load_map_from_string :: proc(src: string, allocator: runtime.Allocator, options := DEFAULT_OPTIONS) -> (m: Map, err: runtime.Allocator_Error) {
unquote :: proc(val: string) -> (string, runtime.Allocator_Error) {
v, allocated, ok := strconv.unquote_string(val)
if !ok {
return strings.clone(val)
if len(val) > 0 && (val[0] == '"' || val[0] == '\'') {
v, allocated, ok := strconv.unquote_string(val)
if !ok {
return strings.clone(val)
}
if allocated {
return v, nil
}
return strings.clone(v), nil
}
if allocated {
return v, nil
}
return strings.clone(v)
return strings.clone(val)
}
context.allocator = allocator
@@ -121,7 +123,7 @@ load_map_from_path :: proc(path: string, allocator: runtime.Allocator, options :
data := os.read_entire_file(path, allocator) or_return
defer delete(data, allocator)
m, err = load_map_from_string(string(data), allocator, options)
ok = err != nil
ok = err == nil
defer if !ok {
delete_map(m)
}
@@ -142,6 +144,7 @@ delete_map :: proc(m: Map) {
delete(value, allocator)
}
delete(section)
delete(pairs)
}
delete(m)
}
+51 -34
View File
@@ -100,38 +100,7 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
case runtime.Type_Info_Integer:
buf: [40]byte
u: u128
switch i in a {
case i8: u = u128(i)
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)
case u32: u = u128(i)
case u64: u = u128(i)
case u128: u = u128(i)
case uint: u = u128(i)
case uintptr: u = u128(i)
case i16le: u = u128(i)
case i32le: u = u128(i)
case i64le: u = u128(i)
case u16le: u = u128(i)
case u32le: u = u128(i)
case u64le: u = u128(i)
case u128le: u = u128(i)
case i16be: u = u128(i)
case i32be: u = u128(i)
case i64be: u = u128(i)
case u16be: u = u128(i)
case u32be: u = u128(i)
case u64be: u = u128(i)
case u128be: u = u128(i)
}
u := cast_any_int_to_u128(a)
s: string
@@ -310,7 +279,12 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
case cstring: name = string(s)
}
opt_write_key(w, opt, name) or_return
case runtime.Type_Info_Integer:
buf: [40]byte
u := cast_any_int_to_u128(ka)
name = strconv.append_bits_128(buf[:], u, 10, info.signed, 8*kti.size, "0123456789", nil)
opt_write_key(w, opt, name) or_return
case: return .Unsupported_Type
}
}
@@ -406,10 +380,15 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
ti := runtime.type_info_base(type_info_of(v.id))
info := ti.variant.(runtime.Type_Info_Struct)
first_iteration := true
for name, i in info.names {
for name, i in info.names[:info.field_count] {
omitempty := false
json_name, extra := json_name_from_tag_value(reflect.struct_tag_get(reflect.Struct_Tag(info.tags[i]), "json"))
if json_name == "-" {
continue
}
for flag in strings.split_iterator(&extra, ",") {
switch flag {
case "omitempty":
@@ -657,3 +636,41 @@ opt_write_indentation :: proc(w: io.Writer, opt: ^Marshal_Options) -> (err: io.E
return
}
@(private)
cast_any_int_to_u128 :: proc(any_int_value: any) -> u128 {
u: u128 = 0
switch i in any_int_value {
case i8: u = u128(i)
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)
case u32: u = u128(i)
case u64: u = u128(i)
case u128: u = u128(i)
case uint: u = u128(i)
case uintptr: u = u128(i)
case i16le: u = u128(i)
case i32le: u = u128(i)
case i64le: u = u128(i)
case u16le: u = u128(i)
case u32le: u = u128(i)
case u64le: u = u128(i)
case u128le: u = u128(i)
case i16be: u = u128(i)
case i32be: u = u128(i)
case i64be: u = u128(i)
case u16be: u = u128(i)
case u32be: u = u128(i)
case u64be: u = u128(i)
case u128be: u = u128(i)
}
return u
}
+24 -11
View File
@@ -363,12 +363,11 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
}
v := v
v = reflect.any_base(v)
ti := type_info_of(v.id)
ti := reflect.type_info_base(type_info_of(v.id))
#partial switch t in ti.variant {
case reflect.Type_Info_Struct:
if t.is_raw_union {
if .raw_union in t.flags {
return UNSUPPORTED_TYPE
}
@@ -475,7 +474,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
}
case reflect.Type_Info_Map:
if !reflect.is_string(t.key) {
if !reflect.is_string(t.key) && !reflect.is_integer(t.key) {
return UNSUPPORTED_TYPE
}
raw_map := (^mem.Raw_Map)(v.data)
@@ -492,25 +491,39 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
key, _ := parse_object_key(p, p.allocator)
unmarshal_expect_token(p, .Colon)
mem.zero_slice(elem_backing)
if uerr := unmarshal_value(p, map_backing_value); uerr != nil {
delete(key, p.allocator)
return uerr
}
key_ptr := rawptr(&key)
key_ptr: rawptr
key_cstr: cstring
if reflect.is_cstring(t.key) {
key_cstr = cstring(raw_data(key))
key_ptr = &key_cstr
#partial switch tk in t.key.variant {
case runtime.Type_Info_String:
key_ptr = rawptr(&key)
key_cstr: cstring
if reflect.is_cstring(t.key) {
key_cstr = cstring(raw_data(key))
key_ptr = &key_cstr
}
case runtime.Type_Info_Integer:
i, ok := strconv.parse_i128(key)
if !ok { return UNSUPPORTED_TYPE }
key_ptr = rawptr(&i)
case: return UNSUPPORTED_TYPE
}
set_ptr := runtime.__dynamic_map_set_without_hash(raw_map, t.map_info, key_ptr, map_backing_value.data)
if set_ptr == nil {
delete(key, p.allocator)
}
// there's no need to keep string value on the heap, since it was copied into map
if reflect.is_integer(t.key) {
delete(key, p.allocator)
}
if parse_comma(p) {
break map_loop
+20 -15
View File
@@ -11,7 +11,7 @@ Write a UUID in the 8-4-4-4-12 format.
This procedure performs error checking with every byte written.
If you can guarantee beforehand that your stream has enough space to hold the
UUID (32 bytes), then it is better to use `unsafe_write` instead as that will
UUID (36 bytes), then it is better to use `unsafe_write` instead as that will
be faster.
Inputs:
@@ -22,7 +22,7 @@ Returns:
- error: An `io` error, if one occurred, otherwise `nil`.
*/
write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_check {
write_octet :: proc (w: io.Writer, octet: u8) -> io.Error #no_bounds_check {
write_octet :: proc(w: io.Writer, octet: u8) -> io.Error #no_bounds_check {
high_nibble := octet >> 4
low_nibble := octet & 0xF
@@ -31,15 +31,15 @@ write :: proc(w: io.Writer, id: Identifier) -> (error: io.Error) #no_bounds_chec
return nil
}
for index in 0 ..< 4 { write_octet(w, id[index]) or_return }
for index in 0 ..< 4 {write_octet(w, id[index]) or_return}
io.write_byte(w, '-') or_return
for index in 4 ..< 6 { write_octet(w, id[index]) or_return }
for index in 4 ..< 6 {write_octet(w, id[index]) or_return}
io.write_byte(w, '-') or_return
for index in 6 ..< 8 { write_octet(w, id[index]) or_return }
for index in 6 ..< 8 {write_octet(w, id[index]) or_return}
io.write_byte(w, '-') or_return
for index in 8 ..< 10 { write_octet(w, id[index]) or_return }
for index in 8 ..< 10 {write_octet(w, id[index]) or_return}
io.write_byte(w, '-') or_return
for index in 10 ..< 16 { write_octet(w, id[index]) or_return }
for index in 10 ..< 16 {write_octet(w, id[index]) or_return}
return nil
}
@@ -54,7 +54,7 @@ Inputs:
- id: The identifier to convert.
*/
unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check {
write_octet :: proc (w: io.Writer, octet: u8) #no_bounds_check {
write_octet :: proc(w: io.Writer, octet: u8) #no_bounds_check {
high_nibble := octet >> 4
low_nibble := octet & 0xF
@@ -62,15 +62,15 @@ unsafe_write :: proc(w: io.Writer, id: Identifier) #no_bounds_check {
io.write_byte(w, strconv.digits[low_nibble])
}
for index in 0 ..< 4 { write_octet(w, id[index]) }
for index in 0 ..< 4 {write_octet(w, id[index])}
io.write_byte(w, '-')
for index in 4 ..< 6 { write_octet(w, id[index]) }
for index in 4 ..< 6 {write_octet(w, id[index])}
io.write_byte(w, '-')
for index in 6 ..< 8 { write_octet(w, id[index]) }
for index in 6 ..< 8 {write_octet(w, id[index])}
io.write_byte(w, '-')
for index in 8 ..< 10 { write_octet(w, id[index]) }
for index in 8 ..< 10 {write_octet(w, id[index])}
io.write_byte(w, '-')
for index in 10 ..< 16 { write_octet(w, id[index]) }
for index in 10 ..< 16 {write_octet(w, id[index])}
}
/*
@@ -106,7 +106,7 @@ Convert a UUID to a string in the 8-4-4-4-12 format.
Inputs:
- id: The identifier to convert.
- buffer: A byte buffer to store the result. Must be at least 32 bytes large.
- buffer: A byte buffer to store the result. Must be at least 36 bytes large.
- loc: The caller location for debugging purposes (default: #caller_location)
Returns:
@@ -119,7 +119,11 @@ to_string_buffer :: proc(
) -> (
str: string,
) {
assert(len(buffer) >= EXPECTED_LENGTH, "The buffer provided is not at least 32 bytes large.", loc)
assert(
len(buffer) >= EXPECTED_LENGTH,
"The buffer provided is not at least 36 bytes large.",
loc,
)
builder := strings.builder_from_bytes(buffer)
unsafe_write(strings.to_writer(&builder), id)
return strings.to_string(builder)
@@ -129,3 +133,4 @@ to_string :: proc {
to_string_allocated,
to_string_buffer,
}
+5 -5
View File
@@ -126,7 +126,7 @@ error :: proc(t: ^Tokenizer, offset: int, msg: string, args: ..any) {
t.error_count += 1
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
advance_rune :: proc(t: ^Tokenizer) {
#no_bounds_check {
/*
@@ -170,7 +170,7 @@ peek_byte :: proc(t: ^Tokenizer, offset := 0) -> byte {
return 0
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
skip_whitespace :: proc(t: ^Tokenizer) {
for {
switch t.ch {
@@ -182,7 +182,7 @@ skip_whitespace :: proc(t: ^Tokenizer) {
}
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
is_letter :: proc(r: rune) -> bool {
if r < utf8.RUNE_SELF {
switch r {
@@ -296,7 +296,7 @@ skip_cdata :: proc(t: ^Tokenizer) -> (err: Error) {
return
}
@(optimization_mode="speed")
@(optimization_mode="favor_size")
scan_string :: proc(t: ^Tokenizer, offset: int, close: rune = '<', consume_close := false, multiline := true) -> (value: string, err: Error) {
err = .None
@@ -414,4 +414,4 @@ scan :: proc(t: ^Tokenizer, multiline_string := false) -> Token {
lit = string(t.src[offset : t.offset])
}
return Token{kind, lit, pos}
}
}
+1 -1
View File
@@ -12,7 +12,7 @@ IMPORTING_TIME :: #config(ODIN_CORE_FLAGS_USE_TIME, time.IS_SUPPORTED)
// Override support for parsing `net` types.
// TODO: Update this when the BSDs are supported.
IMPORTING_NET :: #config(ODIN_CORE_FLAGS_USE_NET, ODIN_OS == .Windows || ODIN_OS == .Linux || ODIN_OS == .Darwin)
IMPORTING_NET :: #config(ODIN_CORE_FLAGS_USE_NET, ODIN_OS == .Windows || ODIN_OS == .Linux || ODIN_OS == .Darwin || ODIN_OS == .FreeBSD)
TAG_ARGS :: "args"
SUBTAG_NAME :: "name"
+1 -1
View File
@@ -28,7 +28,7 @@ Parse_Error :: struct {
// Provides more granular information than what just a string could hold.
Open_File_Error :: struct {
filename: string,
errno: os.Errno,
errno: os.Error,
mode: int,
perms: int,
}
+1 -1
View File
@@ -1,4 +1,4 @@
//+build freebsd, netbsd, openbsd
//+build netbsd, openbsd
package flags
import "base:runtime"
+1 -1
View File
@@ -1,4 +1,4 @@
//+build !freebsd !netbsd !openbsd
//+build !netbsd !openbsd
package flags
import "base:runtime"
+5 -5
View File
@@ -12,7 +12,7 @@ import "core:reflect"
// Push a positional argument onto a data struct, checking for specified
// positionals first before adding it to a fallback field.
@(optimization_mode="size")
@(optimization_mode="favor_size")
push_positional :: #force_no_inline proc (model: ^$T, parser: ^Parser, arg: string) -> (error: Error) {
if bit_array.get(&parser.filled_pos, parser.filled_pos.max_index) {
// The max index is set, which means we're out of space.
@@ -74,7 +74,7 @@ register_field :: proc(parser: ^Parser, field: reflect.Struct_Field, index: int)
}
// Set a `-flag` argument, Odin-style.
@(optimization_mode="size")
@(optimization_mode="favor_size")
set_odin_flag :: proc(model: ^$T, parser: ^Parser, name: string) -> (error: Error) {
// We make a special case for help requests.
switch name {
@@ -100,7 +100,7 @@ set_odin_flag :: proc(model: ^$T, parser: ^Parser, name: string) -> (error: Erro
}
// Set a `-flag` argument, UNIX-style.
@(optimization_mode="size")
@(optimization_mode="favor_size")
set_unix_flag :: proc(model: ^$T, parser: ^Parser, name: string) -> (future_args: int, error: Error) {
// We make a special case for help requests.
switch name {
@@ -137,7 +137,7 @@ set_unix_flag :: proc(model: ^$T, parser: ^Parser, name: string) -> (future_args
}
// Set a `-flag:option` argument.
@(optimization_mode="size")
@(optimization_mode="favor_size")
set_option :: proc(model: ^$T, parser: ^Parser, name, option: string) -> (error: Error) {
field, index := get_field_by_name(model, name) or_return
@@ -176,7 +176,7 @@ set_option :: proc(model: ^$T, parser: ^Parser, name, option: string) -> (error:
}
// Set a `-map:key=value` argument.
@(optimization_mode="size")
@(optimization_mode="favor_size")
set_key_value :: proc(model: ^$T, parser: ^Parser, name, key, value: string) -> (error: Error) {
field, index := get_field_by_name(model, name) or_return
+6 -6
View File
@@ -13,7 +13,7 @@ import "core:strings"
@require import "core:time/datetime"
import "core:unicode/utf8"
@(optimization_mode="size")
@(optimization_mode="favor_size")
parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info: ^runtime.Type_Info) -> bool {
bounded_int :: proc(value, min, max: i128) -> (result: i128, ok: bool) {
return value, min <= value && value <= max
@@ -202,7 +202,7 @@ parse_and_set_pointer_by_base_type :: proc(ptr: rawptr, str: string, type_info:
// especially with files.
//
// We want to provide as informative as an error as we can.
@(optimization_mode="size", disabled=NO_CORE_NAMED_TYPES)
@(optimization_mode="favor_size", disabled=NO_CORE_NAMED_TYPES)
parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type: typeid, arg_tag: string, out_error: ^Error) {
// Core types currently supported:
//
@@ -254,8 +254,8 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type:
}
handle, errno := os.open(str, mode, perms)
if errno != 0 {
// NOTE(Feoramund): os.Errno is system-dependent, and there's
if errno != nil {
// NOTE(Feoramund): os.Error is system-dependent, and there's
// currently no good way to translate them all into strings.
//
// The upcoming `os2` package will hopefully solve this.
@@ -320,7 +320,7 @@ parse_and_set_pointer_by_named_type :: proc(ptr: rawptr, str: string, data_type:
}
}
@(optimization_mode="size")
@(optimization_mode="favor_size")
set_unbounded_integer_by_type :: proc(ptr: rawptr, value: $T, data_type: typeid) where intrinsics.type_is_integer(T) {
switch data_type {
case i8: (^i8) (ptr)^ = cast(i8) value
@@ -367,7 +367,7 @@ set_unbounded_integer_by_type :: proc(ptr: rawptr, value: $T, data_type: typeid)
}
}
@(optimization_mode="size")
@(optimization_mode="favor_size")
parse_and_set_pointer_by_type :: proc(ptr: rawptr, str: string, type_info: ^runtime.Type_Info, arg_tag: string) -> (error: Error) {
#partial switch specific_type_info in type_info.variant {
case runtime.Type_Info_Named:
+1 -1
View File
@@ -1,5 +1,5 @@
//+private
//+build !freebsd !netbsd !openbsd
//+build !netbsd !openbsd
package flags
import "core:net"
+2 -2
View File
@@ -11,7 +11,7 @@ package flags
@require import "core:strings"
// This proc is used to assert that `T` meets the expectations of the library.
@(optimization_mode="size", disabled=ODIN_DISABLE_ASSERT)
@(optimization_mode="favor_size", disabled=ODIN_DISABLE_ASSERT)
validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_location) {
positionals_assigned_so_far: bit_array.Bit_Array
defer bit_array.destroy(&positionals_assigned_so_far)
@@ -162,7 +162,7 @@ validate_structure :: proc(model_type: $T, style: Parsing_Style, loc := #caller_
// Validate that all the required arguments are set and that the set arguments
// are up to the program's expectations.
@(optimization_mode="size")
@(optimization_mode="favor_size")
validate_arguments :: proc(model: ^$T, parser: ^Parser) -> Error {
check_fields: for field, index in reflect.struct_fields_zipped(T) {
was_set := bit_array.get(&parser.fields_set, index)
+1 -1
View File
@@ -32,7 +32,7 @@ Inputs:
Returns:
- error: A union of errors; parsing, file open, a help request, or validation.
*/
@(optimization_mode="size")
@(optimization_mode="favor_size")
parse :: proc(
model: ^$T,
args: []string,
+1 -1
View File
@@ -17,7 +17,7 @@ Inputs:
- program: The name of the program, usually the first argument to `os.args`.
- style: The argument parsing style, required to show flags in the proper style.
*/
@(optimization_mode="size")
@(optimization_mode="favor_size")
write_usage :: proc(out: io.Writer, data_type: typeid, program: string = "", style: Parsing_Style = .Odin) {
// All flags get their tags parsed so they can be reasoned about later.
Flag :: struct {
+2 -2
View File
@@ -19,7 +19,7 @@ Inputs:
- allocator: (default: context.allocator)
- loc: The caller location for debugging purposes (default: #caller_location)
*/
@(optimization_mode="size")
@(optimization_mode="favor_size")
parse_or_exit :: proc(
model: ^$T,
program_args: []string,
@@ -63,7 +63,7 @@ Inputs:
- error: The error returned from `parse`.
- style: The argument parsing style, required to show flags in the proper style, when usage is shown.
*/
@(optimization_mode="size")
@(optimization_mode="favor_size")
print_errors :: proc(data_type: typeid, error: Error, program: string, style: Parsing_Style = .Odin) {
stderr := os.stream_from_handle(os.stderr)
stdout := os.stream_from_handle(os.stdout)
+49 -29
View File
@@ -334,6 +334,27 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! {
message := tprintf(fmt, ..args)
p("Panic", message, loc)
}
// Creates a formatted C string
//
// *Allocates Using Context's Allocator*
//
// Inputs:
// - args: A variadic list of arguments to be formatted.
// - sep: An optional separator string (default is a single space).
//
// Returns: A formatted C string.
//
@(require_results)
caprint :: proc(args: ..any, sep := " ", allocator := context.allocator) -> cstring {
str: strings.Builder
strings.builder_init(&str, allocator)
sbprint(&str, ..args, sep=sep)
strings.write_byte(&str, 0)
s := strings.to_string(str)
return cstring(raw_data(s))
}
// Creates a formatted C string
//
// *Allocates Using Context's Allocator*
@@ -346,9 +367,9 @@ panicf :: proc(fmt: string, args: ..any, loc := #caller_location) -> ! {
// Returns: A formatted C string
//
@(require_results)
caprintf :: proc(format: string, args: ..any, newline := false) -> cstring {
caprintf :: proc(format: string, args: ..any, allocator := context.allocator, newline := false) -> cstring {
str: strings.Builder
strings.builder_init(&str)
strings.builder_init(&str, allocator)
sbprintf(&str, format, ..args, newline=newline)
strings.write_byte(&str, 0)
s := strings.to_string(str)
@@ -365,8 +386,8 @@ caprintf :: proc(format: string, args: ..any, newline := false) -> cstring {
// Returns: A formatted C string
//
@(require_results)
caprintfln :: proc(format: string, args: ..any) -> cstring {
return caprintf(format, ..args, newline=true)
caprintfln :: proc(format: string, args: ..any, allocator := context.allocator) -> cstring {
return caprintf(format, ..args, allocator=allocator, newline=true)
}
// Creates a formatted C string
//
@@ -380,12 +401,7 @@ caprintfln :: proc(format: string, args: ..any) -> cstring {
//
@(require_results)
ctprint :: proc(args: ..any, sep := " ") -> cstring {
str: strings.Builder
strings.builder_init(&str, context.temp_allocator)
sbprint(&str, ..args, sep=sep)
strings.write_byte(&str, 0)
s := strings.to_string(str)
return cstring(raw_data(s))
return caprint(args=args, sep=sep, allocator=context.temp_allocator)
}
// Creates a formatted C string
//
@@ -400,12 +416,7 @@ ctprint :: proc(args: ..any, sep := " ") -> cstring {
//
@(require_results)
ctprintf :: proc(format: string, args: ..any, newline := false) -> cstring {
str: strings.Builder
strings.builder_init(&str, context.temp_allocator)
sbprintf(&str, format, ..args, newline=newline)
strings.write_byte(&str, 0)
s := strings.to_string(str)
return cstring(raw_data(s))
return caprintf(format=format, args=args, allocator=context.temp_allocator, newline=newline)
}
// Creates a formatted C string, followed by a newline.
//
@@ -419,7 +430,7 @@ ctprintf :: proc(format: string, args: ..any, newline := false) -> cstring {
//
@(require_results)
ctprintfln :: proc(format: string, args: ..any) -> cstring {
return ctprintf(format, ..args, newline=true)
return caprintf(format=format, args=args, allocator=context.temp_allocator, newline=true)
}
// Formats using the default print settings and writes to the given strings.Builder
//
@@ -951,10 +962,10 @@ fmt_bad_verb :: proc(fi: ^Info, verb: rune) {
io.write_string(fi.writer, "%!", &fi.n)
io.write_rune(fi.writer, verb, &fi.n)
io.write_byte(fi.writer, '(', &fi.n)
if fi.arg.id != nil {
reflect.write_typeid(fi.writer, fi.arg.id, &fi.n)
if arg := fi.arg; arg != nil {
reflect.write_typeid(fi.writer, arg.id, &fi.n)
io.write_byte(fi.writer, '=', &fi.n)
fmt_value(fi, fi.arg, 'v')
fmt_value(fi, arg, 'v')
} else {
io.write_string(fi.writer, "<nil>", &fi.n)
}
@@ -1861,7 +1872,7 @@ handle_tag :: proc(state: ^Info_State, data: rawptr, info: reflect.Type_Info_Str
if optional_len == nil {
return
}
for f, i in info.names {
for f, i in info.names[:info.field_count] {
if f != field_name {
continue
}
@@ -1965,7 +1976,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St
fmt_bad_verb(fi, the_verb)
return
}
if info.is_raw_union {
if .raw_union in info.flags {
if type_name == "" {
io.write_string(fi.writer, "(raw union)", &fi.n)
} else {
@@ -1989,7 +2000,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St
// fi.hash = false;
fi.indent += 1
is_empty := len(info.names) == 0
is_empty := info.field_count == 0
if !is_soa && hash && !is_empty {
io.write_byte(fi.writer, '\n', &fi.n)
@@ -2010,17 +2021,17 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St
base_type_name = v.name
}
actual_field_count := len(info.names)
actual_field_count := info.field_count
n := uintptr(info.soa_len)
if info.soa_kind == .Slice {
actual_field_count = len(info.names)-1 // len
actual_field_count = info.field_count-1 // len
n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^)
} else if info.soa_kind == .Dynamic {
actual_field_count = len(info.names)-3 // len, cap, allocator
actual_field_count = info.field_count-3 // len, cap, allocator
n = uintptr((^int)(uintptr(v.data) + info.offsets[actual_field_count])^)
}
@@ -2099,7 +2110,7 @@ fmt_struct :: proc(fi: ^Info, v: any, the_verb: rune, info: runtime.Type_Info_St
}
} else {
field_count := -1
for name, i in info.names {
for name, i in info.names[:info.field_count] {
optional_len: int = -1
use_nul_termination: bool = false
verb := the_verb if the_verb == 'w' else 'v'
@@ -2605,7 +2616,7 @@ fmt_bit_field :: proc(fi: ^Info, v: any, verb: rune, info: runtime.Type_Info_Bit
field_count := -1
for name, i in info.names {
for name, i in info.names[:info.field_count] {
field_verb := verb
if handle_bit_field_tag(v.data, info, i, &field_verb) {
continue
@@ -2717,7 +2728,8 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
}
case runtime.Type_Info_Struct,
runtime.Type_Info_Union:
runtime.Type_Info_Union,
runtime.Type_Info_Bit_Field:
if ptr == nil {
io.write_string(fi.writer, "<nil>", &fi.n)
return
@@ -2751,9 +2763,11 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
elem := runtime.type_info_base(info.elem)
if elem != nil {
if n, ok := fi.optional_len.?; ok {
fi.optional_len = nil
fmt_array(fi, ptr, n, elem.size, elem, verb)
return
} else if fi.use_nul_termination {
fi.use_nul_termination = false
fmt_array_nul_terminated(fi, ptr, -1, elem.size, elem, verb)
return
}
@@ -2855,8 +2869,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
n := info.count
ptr := v.data
if ol, ok := fi.optional_len.?; ok {
fi.optional_len = nil
n = min(n, ol)
} else if fi.use_nul_termination {
fi.use_nul_termination = false
fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb)
return
}
@@ -2867,8 +2883,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
n := slice.len
ptr := slice.data
if ol, ok := fi.optional_len.?; ok {
fi.optional_len = nil
n = min(n, ol)
} else if fi.use_nul_termination {
fi.use_nul_termination = false
fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb)
return
}
@@ -2879,8 +2897,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
n := array.len
ptr := array.data
if ol, ok := fi.optional_len.?; ok {
fi.optional_len = nil
n = min(n, ol)
} else if fi.use_nul_termination {
fi.use_nul_termination = false
fmt_array_nul_terminated(fi, ptr, n, info.elem_size, info.elem, verb)
return
}

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