Merge branch 'master' into pretty-json-2

This commit is contained in:
gingerBill
2022-08-11 16:14:27 +01:00
committed by GitHub
134 changed files with 3800 additions and 3085 deletions
+1 -1
View File
@@ -1,5 +1,5 @@
name: CI name: CI
on: [push, pull_request] on: [push, pull_request, workflow_dispatch]
jobs: jobs:
build_linux: build_linux:
+43
View File
@@ -0,0 +1,43 @@
name: "Close Stale Issues & PRs"
on:
workflow_dispatch:
schedule:
- cron: "0 21 * * *"
permissions:
issues: write
pull-requests: write
jobs:
stale:
runs-on: ubuntu-latest
steps:
- name: Close Stale Issues
uses: actions/stale@v4.1.0
with:
# stale-issue-message: |
# Hello!
#
# I am marking this issue as stale as it has not received any engagement from the community or maintainers 120 days. That does not imply that the issue has no merit! If you feel strongly about this issue
# - open a PR referencing and resolving the issue;
# - leave a comment on it and discuss ideas how you could contribute towards resolving it;
# - leave a comment and describe in detail why this issue is critical for your use case;
# - open a new issue with updated details and a plan on resolving the issue.
#
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
#
# stale-pr-message: |
# Hello!
#
# I am marking this PR as stale as it has not received any engagement from the community or maintainers 120 days. That does not imply that the issue has no merit! If you feel strongly about this issue
# - leave a comment on it and discuss ideas how you could contribute towards resolving it;
# - leave a comment and describe in detail why this issue is critical for your use case;
#
# The motivation for this automation is to help prioritize issues in the backlog and not ignore, reject, or belittle anyone..
days-before-stale: 120
days-before-close: 30
exempt-draft-pr: true
ascending: true
operations-per-run: 1000
exempt-issue-labels: "ignore"
+1 -1
View File
@@ -58,7 +58,7 @@ set libs= ^
set linker_flags= -incremental:no -opt:ref -subsystem:console set linker_flags= -incremental:no -opt:ref -subsystem:console
if %release_mode% EQU 0 ( rem Debug if %release_mode% EQU 0 ( rem Debug
set linker_flags=%linker_flags% -debug set linker_flags=%linker_flags% -debug /NATVIS:src\odin_compiler.natvis
) else ( rem Release ) else ( rem Release
set linker_flags=%linker_flags% -debug set linker_flags=%linker_flags% -debug
) )
+35 -23
View File
@@ -1,12 +1,20 @@
#!/bin/bash #!/usr/bin/env bash
set -eu set -eu
GIT_SHA=$(git rev-parse --short HEAD) : ${CXX=clang++}
: ${CPPFLAGS=}
: ${CXXFLAGS=}
: ${LDFLAGS=}
: ${ODIN_VERSION=dev-$(date +"%Y-%m")}
CPPFLAGS="$CPPFLAGS -DODIN_VERSION_RAW=\"$ODIN_VERSION\""
CXXFLAGS="$CXXFLAGS -std=c++14"
LDFLAGS="$LDFLAGS -pthread -lm -lstdc++"
GIT_SHA=$(git rev-parse --short HEAD || :)
if [ "$GIT_SHA" ]; then CPPFLAGS="$CPPFLAGS -DGIT_SHA=\"$GIT_SHA\""; fi
DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value" DISABLED_WARNINGS="-Wno-switch -Wno-macro-redefined -Wno-unused-value"
LDFLAGS="-pthread -lm -lstdc++"
CFLAGS="-std=c++14 -DGIT_SHA=\"$GIT_SHA\""
CFLAGS="$CFLAGS -DODIN_VERSION_RAW=\"dev-$(date +"%Y-%m")\""
CC=clang
OS=$(uname) OS=$(uname)
panic() { panic() {
@@ -18,13 +26,13 @@ version() { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }';
config_darwin() { config_darwin() {
ARCH=$(uname -m) ARCH=$(uname -m)
LLVM_CONFIG=llvm-config : ${LLVM_CONFIG=llvm-config}
# allow for arm only llvm's with version 13 # allow for arm only llvm's with version 13
if [ ARCH == arm64 ]; then if [ ARCH == arm64 ]; then
MIN_LLVM_VERSION=("13.0.0") MIN_LLVM_VERSION=("13.0.0")
else else
# allow for x86 / amd64 all llvm versions begining from 11 # allow for x86 / amd64 all llvm versions beginning from 11
MIN_LLVM_VERSION=("11.1.0") MIN_LLVM_VERSION=("11.1.0")
fi fi
@@ -37,34 +45,38 @@ config_darwin() {
fi fi
LDFLAGS="$LDFLAGS -liconv -ldl" LDFLAGS="$LDFLAGS -liconv -ldl"
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS -lLLVM-C" LDFLAGS="$LDFLAGS -lLLVM-C"
} }
config_freebsd() { config_freebsd() {
LLVM_CONFIG=/usr/local/bin/llvm-config11 : ${LLVM_CONFIG=/usr/local/bin/llvm-config11}
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
} }
config_openbsd() { config_openbsd() {
LLVM_CONFIG=/usr/local/bin/llvm-config : ${LLVM_CONFIG=/usr/local/bin/llvm-config}
LDFLAGS="$LDFLAGS -liconv" LDFLAGS="$LDFLAGS -liconv"
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
} }
config_linux() { config_linux() {
if which llvm-config > /dev/null 2>&1; then : ${LLVM_CONFIG=}
LLVM_CONFIG=llvm-config
elif which llvm-config-11 > /dev/null 2>&1; then if [ ! "$LLVM_CONFIG" ]; then
LLVM_CONFIG=llvm-config-11 if which llvm-config > /dev/null 2>&1; then
elif which llvm-config-11-64 > /dev/null 2>&1; then LLVM_CONFIG=llvm-config
LLVM_CONFIG=llvm-config-11-64 elif which llvm-config-11 > /dev/null 2>&1; then
else LLVM_CONFIG=llvm-config-11
panic "Unable to find LLVM-config" elif which llvm-config-11-64 > /dev/null 2>&1; then
LLVM_CONFIG=llvm-config-11-64
else
panic "Unable to find LLVM-config"
fi
fi fi
MIN_LLVM_VERSION=("11.0.0") MIN_LLVM_VERSION=("11.0.0")
@@ -74,7 +86,7 @@ config_linux() {
fi fi
LDFLAGS="$LDFLAGS -ldl" LDFLAGS="$LDFLAGS -ldl"
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)" CXXFLAGS="$CXXFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)" LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
} }
@@ -97,7 +109,7 @@ build_odin() {
esac esac
set -x set -x
$CC src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CFLAGS $EXTRAFLAGS $LDFLAGS -o odin $CXX src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CPPFLAGS $CXXFLAGS $EXTRAFLAGS $LDFLAGS -o odin
set +x set +x
} }
+1 -1
View File
@@ -66,7 +66,7 @@ scanner_destroy :: proc(s: ^Scanner) {
} }
// Returns the first non-EOF error that was encounted by the scanner // Returns the first non-EOF error that was encountered by the scanner
scanner_error :: proc(s: ^Scanner) -> Scanner_Error { scanner_error :: proc(s: ^Scanner) -> Scanner_Error {
switch s._err { switch s._err {
case .EOF, nil: case .EOF, nil:
+8
View File
@@ -161,6 +161,10 @@ buffer_write :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
return copy(b.buf[m:], p), nil return copy(b.buf[m:], p), nil
} }
buffer_write_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
return buffer_write(b, ([^]byte)(ptr)[:size])
}
buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) { buffer_write_string :: proc(b: ^Buffer, s: string) -> (n: int, err: io.Error) {
b.last_read = .Invalid b.last_read = .Invalid
m, ok := _buffer_try_grow(b, len(s)) m, ok := _buffer_try_grow(b, len(s))
@@ -229,6 +233,10 @@ buffer_read :: proc(b: ^Buffer, p: []byte) -> (n: int, err: io.Error) {
return return
} }
buffer_read_ptr :: proc(b: ^Buffer, ptr: rawptr, size: int) -> (n: int, err: io.Error) {
return buffer_read(b, ([^]byte)(ptr)[:size])
}
buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) { buffer_read_at :: proc(b: ^Buffer, p: []byte, offset: int) -> (n: int, err: io.Error) {
b.last_read = .Invalid b.last_read = .Invalid
+1 -1
View File
@@ -519,7 +519,7 @@ join_adjacent_string_literals :: proc(cpp: ^Preprocessor, initial_tok: ^Token) {
quote_string :: proc(s: string) -> []byte { quote_string :: proc(s: string) -> []byte {
b := strings.make_builder(0, len(s)+2) b := strings.builder_make(0, len(s)+2)
io.write_quoted_string(strings.to_writer(&b), s, '"') io.write_quoted_string(strings.to_writer(&b), s, '"')
return b.buf[:] return b.buf[:]
} }
+1 -1
View File
@@ -331,7 +331,7 @@ fmin :: proc{libc_fmin, libc_fminf}
fma :: proc{libc_fma, libc_fmaf} fma :: proc{libc_fma, libc_fmaf}
// But retain the 'f' suffix-variant functions as well so they can be used, // But retain the 'f' suffix-variant functions as well so they can be used,
// a trick is used here where we use explicit procedrual overloading of one // a trick is used here where we use explicit procedural overloading of one
// procedure. This is done because the foreign block is marked @(private) and // procedure. This is done because the foreign block is marked @(private) and
// aliasing functions does not remove privateness from the entity. // aliasing functions does not remove privateness from the entity.
acosf :: proc{libc_acosf} acosf :: proc{libc_acosf}
+1 -1
View File
@@ -196,7 +196,7 @@ foreign libc {
getc :: proc(stream: ^FILE) -> int --- getc :: proc(stream: ^FILE) -> int ---
getchar :: proc() -> int --- getchar :: proc() -> int ---
putc :: proc(c: int, stream: ^FILE) -> int --- putc :: proc(c: int, stream: ^FILE) -> int ---
putchar :: proc() -> int --- putchar :: proc(c: int) -> int ---
puts :: proc(s: cstring) -> int --- puts :: proc(s: cstring) -> int ---
ungetc :: proc(c: int, stream: ^FILE) -> int --- ungetc :: proc(c: int, stream: ^FILE) -> int ---
fread :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t --- fread :: proc(ptr: rawptr, size: size_t, nmemb: size_t, stream: ^FILE) -> size_t ---
+1 -1
View File
@@ -81,7 +81,7 @@ The crypto package is not thread-safe at the moment. This may change in the futu
### Disclaimer ### Disclaimer
The algorithms were ported out of curiosity and due to interest in the field. The algorithms were ported out of curiosity and due to interest in the field.
We have not had any of the code verified by a third party or tested/fuzzed by any automatic means. We have not had any of the code verified by a third party or tested/fuzzed by any automatic means.
Whereever we were able to find official test vectors, those were used to verify the implementation. Wherever we were able to find official test vectors, those were used to verify the implementation.
We do not recommend using them in a production environment, without any additional testing and/or verification. We do not recommend using them in a production environment, without any additional testing and/or verification.
### ToDo ### ToDo
+1 -1
View File
@@ -30,6 +30,6 @@ equivalence.
For the most part, alterations to the base fiat-crypto generated code was For the most part, alterations to the base fiat-crypto generated code was
kept to a minimum, to aid auditability. This results in a somewhat kept to a minimum, to aid auditability. This results in a somewhat
ideosyncratic style, and in some cases minor performance penalties. idiosyncratic style, and in some cases minor performance penalties.
[1]: https://github.com/mit-plv/fiat-crypto [1]: https://github.com/mit-plv/fiat-crypto
+1 -1
View File
@@ -233,7 +233,7 @@ init :: proc(ctx: ^Context, key: []byte, c_rounds, d_rounds: int) {
} }
update :: proc(ctx: ^Context, data: []byte) { update :: proc(ctx: ^Context, data: []byte) {
assert(ctx.is_initialized, "crypto/siphash: Context is not initalized") assert(ctx.is_initialized, "crypto/siphash: Context is not initialized")
ctx.last_block = len(data) / 8 * 8 ctx.last_block = len(data) / 8 * 8
ctx.buf = data ctx.buf = data
i := 0 i := 0
+4 -4
View File
@@ -25,8 +25,8 @@ import "core:strings"
MAX_RUNE_CODEPOINT :: int(unicode.MAX_RUNE) MAX_RUNE_CODEPOINT :: int(unicode.MAX_RUNE)
write_rune :: strings.write_rune_builder write_rune :: strings.write_rune
write_string :: strings.write_string_builder write_string :: strings.write_string
Error :: enum u8 { Error :: enum u8 {
None = 0, None = 0,
@@ -94,8 +94,8 @@ decode_xml :: proc(input: string, options := XML_Decode_Options{}, allocator :=
l := len(input) l := len(input)
if l == 0 { return "", .None } if l == 0 { return "", .None }
builder := strings.make_builder() builder := strings.builder_make()
defer strings.destroy_builder(&builder) defer strings.builder_destroy(&builder)
t := Tokenizer{src=input} t := Tokenizer{src=input}
in_data := false in_data := false
@@ -8,7 +8,7 @@ import "core:time"
doc_print :: proc(doc: ^xml.Document) { doc_print :: proc(doc: ^xml.Document) {
buf: strings.Builder buf: strings.Builder
defer strings.destroy_builder(&buf) defer strings.builder_destroy(&buf)
w := strings.to_writer(&buf) w := strings.to_writer(&buf)
xml.print(w, doc) xml.print(w, doc)
+1 -1
View File
@@ -107,7 +107,7 @@ Node :: struct {
/* Conventions */ /* Conventions */
/* ------------ /* ------------
Much of HxA's use is based on convention. HxA lets users store arbitrary data in its structure that can be parsed but whose semantic meaning does not need to be understood. Much of HxA's use is based on convention. HxA lets users store arbitrary data in its structure that can be parsed but whose semantic meaning does not need to be understood.
A few conventions are hard, and some are soft. Hard convention that a user HAS to follow in order to produce a valid file. Hard conventions simplify parsing becaus the parser can make some assumptions. Soft convenbtions are basicly recomendations of how to store common data. A few conventions are hard, and some are soft. Hard convention that a user HAS to follow in order to produce a valid file. Hard conventions simplify parsing becaus the parser can make some assumptions. Soft convenbtions are basically recomendations of how to store common data.
If you use HxA for something not covered by the conventions but need a convention for your use case. Please let us know so that we can add it! If you use HxA for something not covered by the conventions but need a convention for your use case. Please let us know so that we can add it!
*/ */
+4 -1
View File
@@ -44,7 +44,7 @@ Marshal_Options :: struct {
mjson_skipped_first_braces_end: bool, mjson_skipped_first_braces_end: bool,
} }
marshal :: proc(v: any, opt: Marshal_Options = {}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) { marshal :: proc(v: any, opt := Marshal_Options{}, allocator := context.allocator) -> (data: []byte, err: Marshal_Error) {
b := strings.builder_make(allocator) b := strings.builder_make(allocator)
defer if err != nil { defer if err != nil {
strings.builder_destroy(&b) strings.builder_destroy(&b)
@@ -192,6 +192,9 @@ marshal_to_writer :: proc(w: io.Writer, v: any, opt: ^Marshal_Options) -> (err:
case runtime.Type_Info_Multi_Pointer: case runtime.Type_Info_Multi_Pointer:
return .Unsupported_Type return .Unsupported_Type
case runtime.Type_Info_Soa_Pointer:
return .Unsupported_Type
case runtime.Type_Info_Procedure: case runtime.Type_Info_Procedure:
return .Unsupported_Type return .Unsupported_Type
+2 -2
View File
@@ -325,7 +325,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token} UNSUPPORTED_TYPE := Unsupported_Type_Error{v.id, p.curr_token}
if end_token == .Close_Brace { if end_token == .Close_Brace {
assert(expect_token(p, .Open_Brace) == nil) unmarshal_expect_token(p, .Open_Brace)
} }
v := v v := v
@@ -473,7 +473,7 @@ unmarshal_object :: proc(p: ^Parser, v: any, end_token: Token_Kind) -> (err: Unm
} }
if end_token == .Close_Brace { if end_token == .Close_Brace {
assert(expect_token(p, .Close_Brace) == nil) unmarshal_expect_token(p, .Close_Brace)
} }
return return
} }
+1 -1
View File
@@ -84,7 +84,7 @@ example :: proc() {
doc_hash :: proc(doc: ^xml.Document, print := false) -> (crc32: u32) { doc_hash :: proc(doc: ^xml.Document, print := false) -> (crc32: u32) {
buf: strings.Builder buf: strings.Builder
defer strings.destroy_builder(&buf) defer strings.builder_destroy(&buf)
w := strings.to_writer(&buf) w := strings.to_writer(&buf)
xml.print(w, doc) xml.print(w, doc)
+21 -8
View File
@@ -77,7 +77,7 @@ register_user_formatter :: proc(id: typeid, formatter: User_Formatter) -> Regist
// They must be freed accordingly // They must be freed accordingly
aprint :: proc(args: ..any, sep := " ") -> string { aprint :: proc(args: ..any, sep := " ") -> string {
str: strings.Builder str: strings.Builder
strings.init_builder(&str) strings.builder_init(&str)
sbprint(buf=&str, args=args, sep=sep) sbprint(buf=&str, args=args, sep=sep)
return strings.to_string(str) return strings.to_string(str)
} }
@@ -85,7 +85,7 @@ aprint :: proc(args: ..any, sep := " ") -> string {
// They must be freed accordingly // They must be freed accordingly
aprintln :: proc(args: ..any, sep := " ") -> string { aprintln :: proc(args: ..any, sep := " ") -> string {
str: strings.Builder str: strings.Builder
strings.init_builder(&str) strings.builder_init(&str)
sbprintln(buf=&str, args=args, sep=sep) sbprintln(buf=&str, args=args, sep=sep)
return strings.to_string(str) return strings.to_string(str)
} }
@@ -93,7 +93,7 @@ aprintln :: proc(args: ..any, sep := " ") -> string {
// They must be freed accordingly // They must be freed accordingly
aprintf :: proc(fmt: string, args: ..any) -> string { aprintf :: proc(fmt: string, args: ..any) -> string {
str: strings.Builder str: strings.Builder
strings.init_builder(&str) strings.builder_init(&str)
sbprintf(&str, fmt, ..args) sbprintf(&str, fmt, ..args)
return strings.to_string(str) return strings.to_string(str)
} }
@@ -102,21 +102,21 @@ aprintf :: proc(fmt: string, args: ..any) -> string {
// tprint procedure return a string that was allocated with the current context's temporary allocator // tprint procedure return a string that was allocated with the current context's temporary allocator
tprint :: proc(args: ..any, sep := " ") -> string { tprint :: proc(args: ..any, sep := " ") -> string {
str: strings.Builder str: strings.Builder
strings.init_builder(&str, context.temp_allocator) strings.builder_init(&str, context.temp_allocator)
sbprint(buf=&str, args=args, sep=sep) sbprint(buf=&str, args=args, sep=sep)
return strings.to_string(str) return strings.to_string(str)
} }
// tprintln procedure return a string that was allocated with the current context's temporary allocator // tprintln procedure return a string that was allocated with the current context's temporary allocator
tprintln :: proc(args: ..any, sep := " ") -> string { tprintln :: proc(args: ..any, sep := " ") -> string {
str: strings.Builder str: strings.Builder
strings.init_builder(&str, context.temp_allocator) strings.builder_init(&str, context.temp_allocator)
sbprintln(buf=&str, args=args, sep=sep) sbprintln(buf=&str, args=args, sep=sep)
return strings.to_string(str) return strings.to_string(str)
} }
// tprintf procedure return a string that was allocated with the current context's temporary allocator // tprintf procedure return a string that was allocated with the current context's temporary allocator
tprintf :: proc(fmt: string, args: ..any) -> string { tprintf :: proc(fmt: string, args: ..any) -> string {
str: strings.Builder str: strings.Builder
strings.init_builder(&str, context.temp_allocator) strings.builder_init(&str, context.temp_allocator)
sbprintf(&str, fmt, ..args) sbprintf(&str, fmt, ..args)
return strings.to_string(str) return strings.to_string(str)
} }
@@ -776,7 +776,7 @@ fmt_rune :: proc(fi: ^Info, r: rune, verb: rune) {
case 'c', 'r', 'v': case 'c', 'r', 'v':
io.write_rune(fi.writer, r, &fi.n) io.write_rune(fi.writer, r, &fi.n)
case 'q': case 'q':
fi.n += strings.write_quoted_rune(fi.writer, r) fi.n += io.write_quoted_rune(fi.writer, r)
case: case:
fmt_int(fi, u64(r), false, 32, verb) fmt_int(fi, u64(r), false, 32, verb)
} }
@@ -1014,7 +1014,7 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
u := u64(uintptr(p)) u := u64(uintptr(p))
switch verb { switch verb {
case 'p', 'v': case 'p', 'v':
if !fi.hash || verb == 'v' { if !fi.hash && verb == 'v' {
io.write_string(fi.writer, "0x", &fi.n) io.write_string(fi.writer, "0x", &fi.n)
} }
_fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER) _fmt_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER)
@@ -1031,6 +1031,15 @@ fmt_pointer :: proc(fi: ^Info, p: rawptr, verb: rune) {
} }
} }
fmt_soa_pointer :: proc(fi: ^Info, p: runtime.Raw_Soa_Pointer, verb: rune) {
io.write_string(fi.writer, "#soa{data=0x", &fi.n)
_fmt_int(fi, u64(uintptr(p.data)), 16, false, 8*size_of(rawptr), __DIGITS_UPPER)
io.write_string(fi.writer, ", index=", &fi.n)
_fmt_int(fi, u64(p.index), 10, false, 8*size_of(rawptr), __DIGITS_UPPER)
io.write_string(fi.writer, "}", &fi.n)
}
enum_value_to_string :: proc(val: any) -> (string, bool) { enum_value_to_string :: proc(val: any) -> (string, bool) {
v := val v := val
v.id = runtime.typeid_base(v.id) v.id = runtime.typeid_base(v.id)
@@ -1867,6 +1876,10 @@ fmt_value :: proc(fi: ^Info, v: any, verb: rune) {
fmt_pointer(fi, ptr, verb) fmt_pointer(fi, ptr, verb)
} }
case runtime.Type_Info_Soa_Pointer:
ptr := (^runtime.Raw_Soa_Pointer)(v.data)^
fmt_soa_pointer(fi, ptr, verb)
case runtime.Type_Info_Multi_Pointer: case runtime.Type_Info_Multi_Pointer:
ptr := (^rawptr)(v.data)^ ptr := (^rawptr)(v.data)^
if ptr == nil { if ptr == nil {
+2 -2
View File
@@ -1,8 +1,8 @@
package hash package hash
@(optimization_mode="speed") @(optimization_mode="speed")
crc64_ecma_182 :: proc(data: []byte, seed := u32(0)) -> u64 #no_bounds_check { crc64_ecma_182 :: proc(data: []byte, seed := u64(0)) -> (result: u64) #no_bounds_check {
result := u64(seed) result = seed
#no_bounds_check for b in data { #no_bounds_check for b in data {
result = result<<8 ~ _crc64_table_ecma_182[((result>>56) ~ u64(b)) & 0xff] result = result<<8 ~ _crc64_table_ecma_182[((result>>56) ~ u64(b)) & 0xff]
} }
+101 -95
View File
@@ -172,108 +172,114 @@ murmur32 :: proc(data: []byte, seed := u32(0)) -> u32 {
return h1 return h1
} }
// See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L96
@(optimization_mode="speed") @(optimization_mode="speed")
murmur64 :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 { murmur64a :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
when size_of(int) == 8 { m :: 0xc6a4a7935bd1e995
m :: 0xc6a4a7935bd1e995 r :: 47
r :: 47
h: u64 = seed ~ (u64(len(data)) * m) h: u64 = seed ~ (u64(len(data)) * m)
data64 := mem.slice_ptr(cast(^u64)raw_data(data), len(data)/size_of(u64)) data64 := mem.slice_data_cast([]u64, data)
for _, i in data64 { for _, i in data64 {
k := data64[i] k := data64[i]
k *= m k *= m
k ~= k>>r k ~= k>>r
k *= m k *= m
h ~= k h ~= k
h *= m
}
switch len(data)&7 {
case 7: h ~= u64(data[6]) << 48; fallthrough
case 6: h ~= u64(data[5]) << 40; fallthrough
case 5: h ~= u64(data[4]) << 32; fallthrough
case 4: h ~= u64(data[3]) << 24; fallthrough
case 3: h ~= u64(data[2]) << 16; fallthrough
case 2: h ~= u64(data[1]) << 8; fallthrough
case 1:
h ~= u64(data[0])
h *= m
}
h ~= h>>r
h *= m h *= m
h ~= h>>r
return h
} else {
m :: 0x5bd1e995
r :: 24
h1 := u32(seed) ~ u32(len(data))
h2 := u32(seed) >> 32
data32 := mem.slice_ptr(cast(^u32)raw_data(data), len(data)/size_of(u32))
len := len(data)
i := 0
for len >= 8 {
k1, k2: u32
k1 = data32[i]; i += 1
k1 *= m
k1 ~= k1>>r
k1 *= m
h1 *= m
h1 ~= k1
len -= 4
k2 = data32[i]; i += 1
k2 *= m
k2 ~= k2>>r
k2 *= m
h2 *= m
h2 ~= k2
len -= 4
}
if len >= 4 {
k1: u32
k1 = data32[i]; i += 1
k1 *= m
k1 ~= k1>>r
k1 *= m
h1 *= m
h1 ~= k1
len -= 4
}
// TODO(bill): Fix this
#no_bounds_check data8 := mem.slice_to_bytes(data32[i:])[:3]
switch len {
case 3:
h2 ~= u32(data8[2]) << 16
fallthrough
case 2:
h2 ~= u32(data8[1]) << 8
fallthrough
case 1:
h2 ~= u32(data8[0])
h2 *= m
}
h1 ~= h2>>18
h1 *= m
h2 ~= h1>>22
h2 *= m
h1 ~= h2>>17
h1 *= m
h2 ~= h1>>19
h2 *= m
return u64(h1)<<32 | u64(h2)
} }
offset := len(data64) * size_of(u64)
switch len(data)&7 {
case 7: h ~= u64(data[offset + 6]) << 48; fallthrough
case 6: h ~= u64(data[offset + 5]) << 40; fallthrough
case 5: h ~= u64(data[offset + 4]) << 32; fallthrough
case 4: h ~= u64(data[offset + 3]) << 24; fallthrough
case 3: h ~= u64(data[offset + 2]) << 16; fallthrough
case 2: h ~= u64(data[offset + 1]) << 8; fallthrough
case 1:
h ~= u64(data[offset + 0])
h *= m
}
h ~= h>>r
h *= m
h ~= h>>r
return h
}
// See https://github.com/aappleby/smhasher/blob/master/src/MurmurHash2.cpp#L140
@(optimization_mode="speed")
murmur64b :: proc(data: []byte, seed := u64(0x9747b28c)) -> u64 {
m :: 0x5bd1e995
r :: 24
h1 := u32(seed) ~ u32(len(data))
h2 := u32(seed) >> 32
data32 := mem.slice_ptr(cast(^u32)raw_data(data), len(data)/size_of(u32))
len := len(data)
i := 0
for len >= 8 {
k1, k2: u32
k1 = data32[i]; i += 1
k1 *= m
k1 ~= k1>>r
k1 *= m
h1 *= m
h1 ~= k1
len -= 4
k2 = data32[i]; i += 1
k2 *= m
k2 ~= k2>>r
k2 *= m
h2 *= m
h2 ~= k2
len -= 4
}
if len >= 4 {
k1: u32
k1 = data32[i]; i += 1
k1 *= m
k1 ~= k1>>r
k1 *= m
h1 *= m
h1 ~= k1
len -= 4
}
// TODO(bill): Fix this
#no_bounds_check data8 := mem.slice_to_bytes(data32[i:])[:3]
switch len {
case 3:
h2 ~= u32(data8[2]) << 16
fallthrough
case 2:
h2 ~= u32(data8[1]) << 8
fallthrough
case 1:
h2 ~= u32(data8[0])
h2 *= m
}
h1 ~= h2>>18
h1 *= m
h2 ~= h1>>22
h2 *= m
h1 ~= h2>>17
h1 *= m
h2 ~= h1>>19
h2 *= m
return u64(h1)<<32 | u64(h2)
} }
@(optimization_mode="speed") @(optimization_mode="speed")
+5 -5
View File
@@ -469,7 +469,7 @@ return_single_channel :: proc(img: ^Image, channel: Channel) -> (res: ^Image, ok
} }
// Does the image have 1 or 2 channels, a valid bit depth (8 or 16), // Does the image have 1 or 2 channels, a valid bit depth (8 or 16),
// Is the pointer valid, are the dimenions valid? // Is the pointer valid, are the dimensions valid?
is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) { is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) {
// Were we actually given a valid image? // Were we actually given a valid image?
if img == nil { if img == nil {
@@ -489,7 +489,7 @@ is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) {
// This returns 0 if any of the inputs is zero. // This returns 0 if any of the inputs is zero.
bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth) bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth)
// If the dimenions are invalid or the buffer size doesn't match the image characteristics, bail. // If the dimensions are invalid or the buffer size doesn't match the image characteristics, bail.
if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS { if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS {
return false return false
} }
@@ -498,7 +498,7 @@ is_valid_grayscale_image :: proc(img: ^Image) -> (ok: bool) {
} }
// Does the image have 3 or 4 channels, a valid bit depth (8 or 16), // Does the image have 3 or 4 channels, a valid bit depth (8 or 16),
// Is the pointer valid, are the dimenions valid? // Is the pointer valid, are the dimensions valid?
is_valid_color_image :: proc(img: ^Image) -> (ok: bool) { is_valid_color_image :: proc(img: ^Image) -> (ok: bool) {
// Were we actually given a valid image? // Were we actually given a valid image?
if img == nil { if img == nil {
@@ -518,7 +518,7 @@ is_valid_color_image :: proc(img: ^Image) -> (ok: bool) {
// This returns 0 if any of the inputs is zero. // This returns 0 if any of the inputs is zero.
bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth) bytes_expected := compute_buffer_size(img.width, img.height, img.channels, img.depth)
// If the dimenions are invalid or the buffer size doesn't match the image characteristics, bail. // If the dimensions are invalid or the buffer size doesn't match the image characteristics, bail.
if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS { if bytes_expected == 0 || bytes_expected != len(img.pixels.buf) || img.width * img.height > MAX_DIMENSIONS {
return false return false
} }
@@ -527,7 +527,7 @@ is_valid_color_image :: proc(img: ^Image) -> (ok: bool) {
} }
// Does the image have 1..4 channels, a valid bit depth (8 or 16), // Does the image have 1..4 channels, a valid bit depth (8 or 16),
// Is the pointer valid, are the dimenions valid? // Is the pointer valid, are the dimensions valid?
is_valid_image :: proc(img: ^Image) -> (ok: bool) { is_valid_image :: proc(img: ^Image) -> (ok: bool) {
// Were we actually given a valid image? // Were we actually given a valid image?
if img == nil { if img == nil {
+2 -2
View File
@@ -130,7 +130,7 @@ save_to_buffer :: proc(img: ^Image, custom_info: Info = {}, allocator := context
// we will write to a string builder // we will write to a string builder
data: strings.Builder data: strings.Builder
strings.init_builder(&data) strings.builder_init(&data)
// all PNM headers start with the format // all PNM headers start with the format
fmt.sbprintf(&data, "%s\n", header.format) fmt.sbprintf(&data, "%s\n", header.format)
@@ -409,7 +409,7 @@ _parse_header_pam :: proc(data: []byte, allocator := context.allocator) -> (head
// string buffer for the tupltype // string buffer for the tupltype
tupltype: strings.Builder tupltype: strings.Builder
strings.init_builder(&tupltype, context.temp_allocator); defer strings.destroy_builder(&tupltype) strings.builder_init(&tupltype, context.temp_allocator); defer strings.builder_destroy(&tupltype)
fmt.sbprint(&tupltype, "") fmt.sbprint(&tupltype, "")
// PAM uses actual lines, so we can iterate easily // PAM uses actual lines, so we can iterate easily
+1 -1
View File
@@ -219,7 +219,7 @@ write_image_as_ppm :: proc(filename: string, image: ^image.Image) -> (success: b
defer close(fd) defer close(fd)
write_string(fd, write_string(fd,
fmt.tprintf("P6\n%v %v\n%v\n", width, height, (1 << uint(depth) - 1)), fmt.tprintf("P6\n%v %v\n%v\n", width, height, uint(1 << uint(depth) - 1)),
) )
if channels == 3 { if channels == 3 {
+3 -3
View File
@@ -1002,7 +1002,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
o16 = o16[out_image_channels:] o16 = o16[out_image_channels:]
} }
case: case:
unreachable("We should never seen # channels other than 1-4 inclusive.") panic("We should never seen # channels other than 1-4 inclusive.")
} }
img.pixels = t img.pixels = t
@@ -1195,7 +1195,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
o = o[out_image_channels:] o = o[out_image_channels:]
} }
case: case:
unreachable("We should never seen # channels other than 1-4 inclusive.") panic("We should never seen # channels other than 1-4 inclusive.")
} }
img.pixels = t img.pixels = t
@@ -1206,7 +1206,7 @@ load_from_context :: proc(ctx: ^$C, options := Options{}, allocator := context.a
This may change if we ever don't expand 1, 2 and 4 bit images. But, those raw This may change if we ever don't expand 1, 2 and 4 bit images. But, those raw
returns will likely bypass this processing pipeline. returns will likely bypass this processing pipeline.
*/ */
unreachable("We should never see bit depths other than 8, 16 and 'Paletted' here.") panic("We should never see bit depths other than 8, 16 and 'Paletted' here.")
} }
return img, nil return img, nil
+24
View File
@@ -247,6 +247,30 @@ write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written
return return
} }
// writer append a quoted rune into the byte buffer, return the written size
write_quoted_rune :: proc(w: Writer, r: rune) -> (n: int) {
_write_byte :: #force_inline proc(w: Writer, c: byte) -> int {
err := write_byte(w, c)
return 1 if err == nil else 0
}
quote := byte('\'')
n += _write_byte(w, quote)
buf, width := utf8.encode_rune(r)
if width == 1 && r == utf8.RUNE_ERROR {
n += _write_byte(w, '\\')
n += _write_byte(w, 'x')
n += _write_byte(w, DIGITS_LOWER[buf[0]>>4])
n += _write_byte(w, DIGITS_LOWER[buf[0]&0xf])
} else {
i, _ := write_escaped_rune(w, r, quote)
n += i
}
n += _write_byte(w, quote)
return
}
Tee_Reader :: struct { Tee_Reader :: struct {
+1 -1
View File
@@ -56,7 +56,7 @@ create_console_logger :: proc(lowest := Level.Debug, opt := Default_Console_Logg
return Logger{file_console_logger_proc, data, lowest, opt} return Logger{file_console_logger_proc, data, lowest, opt}
} }
destroy_console_logger :: proc(log: ^Logger) { destroy_console_logger :: proc(log: Logger) {
free(log.data) free(log.data)
} }
+5 -6
View File
@@ -6,7 +6,6 @@ import "core:fmt"
// NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle. // NOTE(bill, 2019-12-31): These are defined in `package runtime` as they are used in the `context`. This is to prevent an import definition cycle.
Level :: runtime.Logger_Level
/* /*
Logger_Level :: enum { Logger_Level :: enum {
Debug = 0, Debug = 0,
@@ -16,8 +15,8 @@ Logger_Level :: enum {
Fatal = 40, Fatal = 40,
} }
*/ */
Level :: runtime.Logger_Level
Option :: runtime.Logger_Option
/* /*
Option :: enum { Option :: enum {
Level, Level,
@@ -30,11 +29,12 @@ Option :: enum {
Terminal_Color Terminal_Color
} }
*/ */
Option :: runtime.Logger_Option
Options :: runtime.Logger_Options
/* /*
Options :: bit_set[Option]; Options :: bit_set[Option];
*/ */
Options :: runtime.Logger_Options
Full_Timestamp_Opts :: Options{ Full_Timestamp_Opts :: Options{
.Date, .Date,
@@ -52,12 +52,11 @@ Location_File_Opts :: Options{
} }
Logger_Proc :: runtime.Logger_Proc
/* /*
Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location); Logger_Proc :: #type proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location);
*/ */
Logger_Proc :: runtime.Logger_Proc
Logger :: runtime.Logger
/* /*
Logger :: struct { Logger :: struct {
procedure: Logger_Proc, procedure: Logger_Proc,
@@ -66,6 +65,7 @@ Logger :: struct {
options: Logger_Options, options: Logger_Options,
} }
*/ */
Logger :: runtime.Logger
nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) { nil_logger_proc :: proc(data: rawptr, level: Level, text: string, options: Options, location := #caller_location) {
// Do nothing // Do nothing
@@ -75,7 +75,6 @@ nil_logger :: proc() -> Logger {
return Logger{nil_logger_proc, nil, Level.Debug, nil} return Logger{nil_logger_proc, nil, Level.Debug, nil}
} }
// TODO(bill): Should these be redesigned so that they are do not rely upon `package fmt`?
debugf :: proc(fmt_str: string, args: ..any, location := #caller_location) { debugf :: proc(fmt_str: string, args: ..any, location := #caller_location) {
logf(level=.Debug, fmt_str=fmt_str, args=args, location=location) logf(level=.Debug, fmt_str=fmt_str, args=args, location=location)
} }
+107
View File
@@ -0,0 +1,107 @@
package log
import "core:runtime"
Log_Allocator :: struct {
allocator: runtime.Allocator,
level: Level,
prefix: string,
locked: bool,
}
log_allocator_init :: proc(la: ^Log_Allocator, level: Level, allocator := context.allocator, prefix := "") {
la.allocator = allocator
la.level = level
la.prefix = prefix
la.locked = false
}
log_allocator :: proc(la: ^Log_Allocator) -> runtime.Allocator {
return runtime.Allocator{
procedure = log_allocator_proc,
data = la,
}
}
log_allocator_proc :: proc(allocator_data: rawptr, mode: runtime.Allocator_Mode,
size, alignment: int,
old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, runtime.Allocator_Error) {
la := (^Log_Allocator)(allocator_data)
padding := " " if la.prefix != "" else ""
if !la.locked {
la.locked = true
defer la.locked = false
switch mode {
case .Alloc:
logf(
level=la.level,
fmt_str = "%s%s>>> ALLOCATOR(mode=.Alloc, size=%d, alignment=%d)",
args = {la.prefix, padding, size, alignment},
location = location,
)
case .Free:
if old_size != 0 {
logf(
level=la.level,
fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p, size=%d)",
args = {la.prefix, padding, old_memory, old_size},
location = location,
)
} else {
logf(
level=la.level,
fmt_str = "%s%s<<< ALLOCATOR(mode=.Free, ptr=%p)",
args = {la.prefix, padding, old_memory},
location = location,
)
}
case .Free_All:
logf(
level=la.level,
fmt_str = "%s%s<<< ALLOCATOR(mode=.Free_All)",
args = {la.prefix, padding},
location = location,
)
case .Resize:
logf(
level=la.level,
fmt_str = "%s%s>>> ALLOCATOR(mode=.Resize, ptr=%p, old_size=%d, size=%d, alignment=%d)",
args = {la.prefix, padding, old_memory, old_size, size, alignment},
location = location,
)
case .Query_Features:
logf(
level=la.level,
fmt_str = "%s%ALLOCATOR(mode=.Query_Features)",
args = {la.prefix, padding},
location = location,
)
case .Query_Info:
logf(
level=la.level,
fmt_str = "%s%ALLOCATOR(mode=.Query_Info)",
args = {la.prefix, padding},
location = location,
)
}
}
data, err := la.allocator.procedure(la.allocator.data, mode, size, alignment, old_memory, old_size, location)
if !la.locked {
la.locked = true
defer la.locked = false
if err != nil {
logf(
level=la.level,
fmt_str = "%s%ALLOCATOR ERROR=%v",
args = {la.prefix, padding, error},
location = location,
)
}
}
return data, err
}
+1 -1
View File
@@ -449,7 +449,7 @@ internal_int_is_prime :: proc(a: ^Int, miller_rabin_trials := int(-1), miller_ra
in the loop is non-zero, although very low. in the loop is non-zero, although very low.
-- NOTE(Jeroen): This is not yet true in Odin, but I have some ideas. -- NOTE(Jeroen): This is not yet true in Odin, but I have some ideas.
If the BPSW test and/or the addtional Frobenious test have been If the BPSW test and/or the additional Frobenious test have been
performed instead of just the Miller-Rabin test with the bases 2 and 3, performed instead of just the Miller-Rabin test with the bases 2 and 3,
a single extra test should suffice, so such a very unlikely event will not do much harm. a single extra test should suffice, so such a very unlikely event will not do much harm.
+23 -11
View File
@@ -325,9 +325,9 @@ ease :: proc "contextless" (type: Ease, p: $T) -> T
// in case type was invalid // in case type was invalid
return 0 return 0
} }
Flux_Map :: struct($T: typeid) { Flux_Map :: struct($T: typeid) {
values: map[^T]Flux_Tween(T), values: map[^T]Flux_Tween(T),
keys_to_be_deleted: [dynamic]^T,
} }
Flux_Tween :: struct($T: typeid) { Flux_Tween :: struct($T: typeid) {
@@ -353,15 +353,17 @@ Flux_Tween :: struct($T: typeid) {
} }
// init flux map to a float type and a wanted cap // init flux map to a float type and a wanted cap
flux_init :: proc($T: typeid, cap := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) { flux_init :: proc($T: typeid, value_capacity := 8) -> Flux_Map(T) where intrinsics.type_is_float(T) {
return { return {
make(map[^T]Flux_Tween(T), cap), values = make(map[^T]Flux_Tween(T), value_capacity),
keys_to_be_deleted = make([dynamic]^T, 0, value_capacity)
} }
} }
// delete map content // delete map content
flux_destroy :: proc(flux: Flux_Map($T)) where intrinsics.type_is_float(T) { flux_destroy :: proc(flux: Flux_Map($T)) where intrinsics.type_is_float(T) {
delete(flux.values) delete(flux.values)
delete(flux.keys_to_be_deleted)
} }
// clear map content, stops all animations // clear map content, stops all animations
@@ -374,8 +376,8 @@ flux_clear :: proc(flux: ^Flux_Map($T)) where intrinsics.type_is_float(T) {
// return value can be used to set callbacks // return value can be used to set callbacks
flux_to :: proc( flux_to :: proc(
flux: ^Flux_Map($T), flux: ^Flux_Map($T),
value: ^f32, value: ^T,
goal: f32, goal: T,
type: Ease = .Quadratic_Out, type: Ease = .Quadratic_Out,
duration: time.Duration = time.Second, duration: time.Duration = time.Second,
delay: f64 = 0, delay: f64 = 0,
@@ -413,6 +415,8 @@ flux_tween_init :: proc(tween: ^Flux_Tween($T), duration: time.Duration) where i
// calls callbacks in all stages, when they're filled // calls callbacks in all stages, when they're filled
// deletes tween from the map after completion // deletes tween from the map after completion
flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float(T) { flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float(T) {
clear(&flux.keys_to_be_deleted)
for key, tween in &flux.values { for key, tween in &flux.values {
delay_remainder := f64(0) delay_remainder := f64(0)
@@ -451,7 +455,8 @@ flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float
} }
if tween.progress >= 1 { if tween.progress >= 1 {
delete_key(&flux.values, key) // append keys to array that will be deleted after the loop
append(&flux.keys_to_be_deleted, key)
if tween.on_complete != nil { if tween.on_complete != nil {
tween.on_complete(flux, tween.data) tween.on_complete(flux, tween.data)
@@ -459,17 +464,24 @@ flux_update :: proc(flux: ^Flux_Map($T), dt: f64) where intrinsics.type_is_float
} }
} }
} }
// loop through keys that should be deleted from the map
if len(flux.keys_to_be_deleted) != 0 {
for key in flux.keys_to_be_deleted {
delete_key(&flux.values, key)
}
}
} }
// stop a specific key inside the map // stop a specific key inside the map
// returns true when it successfully removed the key // returns true when it successfully removed the key
flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) { flux_stop :: proc(flux: ^Flux_Map($T), key: ^T) -> bool where intrinsics.type_is_float(T) {
if key in flux.values { if key in flux.values {
delete_key(&flux.values, key) delete_key(&flux.values, key)
return true return true
} }
return false return false
} }
// returns the amount of time left for the tween animation, if the key exists in the map // returns the amount of time left for the tween animation, if the key exists in the map
+3 -3
View File
@@ -476,21 +476,21 @@ quaternion_angle_axis :: proc{
angle_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 { angle_from_quaternion_f16 :: proc(q: Quaternionf16) -> f16 {
if abs(q.w) > math.SQRT_THREE*0.5 { if abs(q.w) > math.SQRT_THREE*0.5 {
return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2 return math.asin(math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)) * 2
} }
return math.acos(q.w) * 2 return math.acos(q.w) * 2
} }
angle_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 { angle_from_quaternion_f32 :: proc(q: Quaternionf32) -> f32 {
if abs(q.w) > math.SQRT_THREE*0.5 { if abs(q.w) > math.SQRT_THREE*0.5 {
return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2 return math.asin(math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)) * 2
} }
return math.acos(q.w) * 2 return math.acos(q.w) * 2
} }
angle_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 { angle_from_quaternion_f64 :: proc(q: Quaternionf64) -> f64 {
if abs(q.w) > math.SQRT_THREE*0.5 { if abs(q.w) > math.SQRT_THREE*0.5 {
return math.asin(q.x*q.x + q.y*q.y + q.z*q.z) * 2 return math.asin(math.sqrt(q.x*q.x + q.y*q.y + q.z*q.z)) * 2
} }
return math.acos(q.w) * 2 return math.acos(q.w) * 2
+18 -11
View File
@@ -185,16 +185,23 @@ log :: proc{
log_f64, log_f64le, log_f64be, log_f64, log_f64le, log_f64be,
} }
log2_f16 :: logb_f16 log2_f16 :: proc "contextless" (x: f16) -> f16 { return log(f16(x), f16(2.0)) }
log2_f16le :: logb_f16le log2_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log_f16(f16(x), f16(2.0))) }
log2_f16be :: logb_f16be log2_f16be :: proc "contextless" (x: f16be) -> f16be { return f16be(log_f16(f16(x), f16(2.0))) }
log2_f32 :: logb_f32
log2_f32le :: logb_f32le log2_f32 :: proc "contextless" (x: f32) -> f32 { return log(f32(x), f32(2.0)) }
log2_f32be :: logb_f32be log2_f32le :: proc "contextless" (x: f32le) -> f32le { return f32le(log_f32(f32(x), f32(2.0))) }
log2_f64 :: logb_f64 log2_f32be :: proc "contextless" (x: f32be) -> f32be { return f32be(log_f32(f32(x), f32(2.0))) }
log2_f64le :: logb_f64le
log2_f64be :: logb_f64be log2_f64 :: proc "contextless" (x: f64) -> f64 { return log(f64(x), f64(2.0)) }
log2 :: logb log2_f64le :: proc "contextless" (x: f64le) -> f64le { return f64le(log_f64(f64(x), f64(2.0))) }
log2_f64be :: proc "contextless" (x: f64be) -> f64be { return f64be(log_f64(f64(x), f64(2.0))) }
log2 :: proc{
log2_f16, log2_f16le, log2_f16be,
log2_f32, log2_f32le, log2_f32be,
log2_f64, log2_f64le, log2_f64be,
}
log10_f16 :: proc "contextless" (x: f16) -> f16 { return ln(x)/LN10 } log10_f16 :: proc "contextless" (x: f16) -> f16 { return ln(x)/LN10 }
log10_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log10_f16(f16(x))) } log10_f16le :: proc "contextless" (x: f16le) -> f16le { return f16le(log10_f16(f16(x))) }
@@ -1357,7 +1364,7 @@ atan :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
} }
asin :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { asin :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
return atan2(x, 1 + sqrt(1 - x*x)) return atan2(x, sqrt(1 - x*x))
} }
acos :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) { acos :: proc "contextless" (x: $T) -> T where intrinsics.type_is_float(T) {
+9 -85
View File
@@ -61,114 +61,38 @@ DEFAULT_PAGE_SIZE ::
4 * 1024 4 * 1024
alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { alloc :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
if size == 0 { data, _ := runtime.mem_alloc(size, alignment, allocator, loc)
return nil
}
if allocator.procedure == nil {
return nil
}
data, err := allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, loc)
_ = err
return raw_data(data) return raw_data(data)
} }
alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { alloc_bytes :: proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if size == 0 { return runtime.mem_alloc(size, alignment, allocator, loc)
return nil, nil
}
if allocator.procedure == nil {
return nil, nil
}
return allocator.procedure(allocator.data, Allocator_Mode.Alloc, size, alignment, nil, 0, loc)
} }
free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { free :: proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if ptr == nil { return runtime.mem_free(ptr, allocator, loc)
return nil
}
if allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, 0, loc)
return err
} }
free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { free_bytes :: proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if bytes == nil { return runtime.mem_free_bytes(bytes, allocator, loc)
return nil
}
if allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, raw_data(bytes), len(bytes), loc)
return err
} }
free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error { free_all :: proc(allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if allocator.procedure != nil { return runtime.mem_free_all(allocator, loc)
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free_All, 0, 0, nil, 0, loc)
return err
}
return nil
} }
resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr { resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> rawptr {
if allocator.procedure == nil { data, _ := runtime.mem_resize(ptr, old_size, new_size, alignment, allocator, loc)
return nil
}
if new_size == 0 {
if ptr != nil {
allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
}
return nil
} else if ptr == nil {
_, err := allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
_ = err
return nil
}
data, err := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, loc)
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
if err != nil {
return nil
}
runtime.copy(data, byte_slice(ptr, old_size))
_, err = allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
return raw_data(data)
}
return raw_data(data) return raw_data(data)
} }
resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) { resize_bytes :: proc(old_data: []byte, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if allocator.procedure == nil { return runtime.mem_resize(raw_data(old_data), len(old_data), new_size, alignment, allocator, loc)
return nil, nil
}
ptr := raw_data(old_data)
old_size := len(old_data)
if new_size == 0 {
if ptr != nil {
_, err := allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
return nil, err
}
return nil, nil
} else if ptr == nil {
return allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
}
data, err := allocator.procedure(allocator.data, Allocator_Mode.Resize, new_size, alignment, ptr, old_size, loc)
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, Allocator_Mode.Alloc, new_size, alignment, nil, 0, loc)
if err != nil {
return data, err
}
runtime.copy(data, old_data)
_, err = allocator.procedure(allocator.data, Allocator_Mode.Free, 0, 0, ptr, old_size, loc)
}
return data, err
} }
query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) { query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: Allocator_Mode_Set) {
if allocator.procedure != nil { if allocator.procedure != nil {
allocator.procedure(allocator.data, Allocator_Mode.Query_Features, 0, 0, &set, 0, loc) allocator.procedure(allocator.data, .Query_Features, 0, 0, &set, 0, loc)
return set return set
} }
return nil return nil
@@ -177,7 +101,7 @@ query_features :: proc(allocator: Allocator, loc := #caller_location) -> (set: A
query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) { query_info :: proc(pointer: rawptr, allocator: Allocator, loc := #caller_location) -> (props: Allocator_Query_Info) {
props.pointer = pointer props.pointer = pointer
if allocator.procedure != nil { if allocator.procedure != nil {
allocator.procedure(allocator.data, Allocator_Mode.Query_Info, 0, 0, &props, 0, loc) allocator.procedure(allocator.data, .Query_Info, 0, 0, &props, 0, loc)
} }
return return
} }
+29 -6
View File
@@ -31,6 +31,14 @@ Arena_Temp_Memory :: struct {
} }
arena_init :: proc(a: ^Arena, data: []byte) {
a.data = data
a.offset = 0
a.peak_used = 0
a.temp_count = 0
}
@(deprecated="prefer 'mem.arena_init'")
init_arena :: proc(a: ^Arena, data: []byte) { init_arena :: proc(a: ^Arena, data: []byte) {
a.data = data a.data = data
a.offset = 0 a.offset = 0
@@ -293,6 +301,14 @@ Stack :: struct {
peak_used: int, peak_used: int,
} }
stack_init :: proc(s: ^Stack, data: []byte) {
s.data = data
s.prev_offset = 0
s.curr_offset = 0
s.peak_used = 0
}
@(deprecated="prefer 'mem.stack_init'")
init_stack :: proc(s: ^Stack, data: []byte) { init_stack :: proc(s: ^Stack, data: []byte) {
s.data = data s.data = data
s.prev_offset = 0 s.prev_offset = 0
@@ -445,27 +461,34 @@ Small_Stack_Allocation_Header :: struct {
// Small_Stack is a stack-like allocator which uses the smallest possible header but at the cost of non-strict memory freeing order // Small_Stack is a stack-like allocator which uses the smallest possible header but at the cost of non-strict memory freeing order
Small_Stack :: struct { Small_Stack :: struct {
data: []byte, data: []byte,
offset: int, offset: int,
peak_used: int, peak_used: int,
} }
small_stack_init :: proc(s: ^Small_Stack, data: []byte) {
s.data = data
s.offset = 0
s.peak_used = 0
}
@(deprecated="prefer 'small_stack_init'")
init_small_stack :: proc(s: ^Small_Stack, data: []byte) { init_small_stack :: proc(s: ^Small_Stack, data: []byte) {
s.data = data s.data = data
s.offset = 0 s.offset = 0
s.peak_used = 0 s.peak_used = 0
} }
small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator { small_stack_allocator :: proc(stack: ^Small_Stack) -> Allocator {
return Allocator{ return Allocator{
procedure = small_stack_allocator_proc, procedure = small_stack_allocator_proc,
data = stack, data = stack,
} }
} }
small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode, small_stack_allocator_proc :: proc(allocator_data: rawptr, mode: Allocator_Mode,
size, alignment: int, size, alignment: int,
old_memory: rawptr, old_size: int, ocation := #caller_location) -> ([]byte, Allocator_Error) { old_memory: rawptr, old_size: int, location := #caller_location) -> ([]byte, Allocator_Error) {
s := cast(^Small_Stack)allocator_data s := cast(^Small_Stack)allocator_data
if s.data == nil { if s.data == nil {
+1
View File
@@ -8,6 +8,7 @@ Raw_Cstring :: runtime.Raw_Cstring
Raw_Slice :: runtime.Raw_Slice Raw_Slice :: runtime.Raw_Slice
Raw_Dynamic_Array :: runtime.Raw_Dynamic_Array Raw_Dynamic_Array :: runtime.Raw_Dynamic_Array
Raw_Map :: runtime.Raw_Map Raw_Map :: runtime.Raw_Map
Raw_Soa_Pointer :: runtime.Raw_Soa_Pointer
Raw_Complex64 :: struct {real, imag: f32} Raw_Complex64 :: struct {real, imag: f32}
Raw_Complex128 :: struct {real, imag: f64} Raw_Complex128 :: struct {real, imag: f64}
+5
View File
@@ -1,5 +1,10 @@
package mem_virtual package mem_virtual
arena_init :: proc{
static_arena_init,
growing_arena_init,
}
arena_temp_begin :: proc{ arena_temp_begin :: proc{
static_arena_temp_begin, static_arena_temp_begin,
growing_arena_temp_begin, growing_arena_temp_begin,
+8 -1
View File
@@ -13,6 +13,13 @@ Growing_Arena :: struct {
DEFAULT_MINIMUM_BLOCK_SIZE :: 1<<20 // 1 MiB should be enough DEFAULT_MINIMUM_BLOCK_SIZE :: 1<<20 // 1 MiB should be enough
growing_arena_init :: proc(arena: ^Static_Arena, reserved: uint = DEFAULT_MINIMUM_BLOCK_SIZE) -> (err: Allocator_Error) {
arena.block = memory_block_alloc(0, reserved, {}) or_return
arena.total_used = 0
arena.total_reserved = arena.block.reserved
return
}
growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: Allocator_Error) { growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int) -> (data: []byte, err: Allocator_Error) {
align_forward_offset :: proc "contextless" (arena: ^Growing_Arena, alignment: int) -> uint #no_bounds_check { align_forward_offset :: proc "contextless" (arena: ^Growing_Arena, alignment: int) -> uint #no_bounds_check {
alignment_offset := uint(0) alignment_offset := uint(0)
@@ -37,7 +44,7 @@ growing_arena_alloc :: proc(arena: ^Growing_Arena, min_size: int, alignment: int
block_size := max(size, arena.minimum_block_size) block_size := max(size, arena.minimum_block_size)
new_block := memory_block_alloc(block_size, block_size, {}) or_return new_block := memory_block_alloc(size, block_size, {}) or_return
new_block.prev = arena.curr_block new_block.prev = arena.curr_block
arena.curr_block = new_block arena.curr_block = new_block
arena.total_reserved += new_block.reserved arena.total_reserved += new_block.reserved
+148
View File
@@ -0,0 +1,148 @@
//+build darwin
//+private
package mem_virtual
foreign import libc "System.framework"
import "core:c"
PROT_NONE :: 0x0 /* [MC2] no permissions */
PROT_READ :: 0x1 /* [MC2] pages can be read */
PROT_WRITE :: 0x2 /* [MC2] pages can be written */
PROT_EXEC :: 0x4 /* [MC2] pages can be executed */
// Sharing options
MAP_SHARED :: 0x1 /* [MF|SHM] share changes */
MAP_PRIVATE :: 0x2 /* [MF|SHM] changes are private */
// Other flags
MAP_FIXED :: 0x0010 /* [MF|SHM] interpret addr exactly */
MAP_RENAME :: 0x0020 /* Sun: rename private pages to file */
MAP_NORESERVE :: 0x0040 /* Sun: don't reserve needed swap area */
MAP_RESERVED0080 :: 0x0080 /* previously unimplemented MAP_INHERIT */
MAP_NOEXTEND :: 0x0100 /* for MAP_FILE, don't change file size */
MAP_HASSEMAPHORE :: 0x0200 /* region may contain semaphores */
MAP_NOCACHE :: 0x0400 /* don't cache pages for this mapping */
MAP_JIT :: 0x0800 /* Allocate a region that will be used for JIT purposes */
// Mapping type
MAP_FILE :: 0x0000 /* map from file (default) */
MAP_ANONYMOUS :: 0x1000 /* allocated from memory, swap space */
/*
* The MAP_RESILIENT_* flags can be used when the caller wants to map some
* possibly unreliable memory and be able to access it safely, possibly
* getting the wrong contents rather than raising any exception.
* For safety reasons, such mappings have to be read-only (PROT_READ access
* only).
*
* MAP_RESILIENT_CODESIGN:
* accessing this mapping will not generate code-signing violations,
* even if the contents are tainted.
* MAP_RESILIENT_MEDIA:
* accessing this mapping will not generate an exception if the contents
* are not available (unreachable removable or remote media, access beyond
* end-of-file, ...). Missing contents will be replaced with zeroes.
*/
MAP_RESILIENT_CODESIGN :: 0x2000 /* no code-signing failures */
MAP_RESILIENT_MEDIA :: 0x4000 /* no backing-store failures */
MAP_32BIT :: 0x8000 /* Return virtual addresses <4G only */
// Flags used to support translated processes.
MAP_TRANSLATED_ALLOW_EXECUTE :: 0x20000 /* allow execute in translated processes */
MAP_UNIX03 :: 0x40000 /* UNIX03 compliance */
// Process memory locking
MCL_CURRENT :: 0x0001 /* [ML] Lock only current memory */
MCL_FUTURE :: 0x0002 /* [ML] Lock all future memory as well */
MADV_NORMAL :: 0 /* [MC1] no further special treatment */
MADV_RANDOM :: 1 /* [MC1] expect random page refs */
MADV_SEQUENTIAL :: 2 /* [MC1] expect sequential page refs */
MADV_WILLNEED :: 3 /* [MC1] will need these pages */
MADV_DONTNEED :: 4 /* [MC1] dont need these pages */
MADV_FREE :: 5 /* pages unneeded, discard contents */
MADV_ZERO_WIRED_PAGES :: 6 /* zero the wired pages that have not been unwired before the entry is deleted */
MADV_FREE_REUSABLE :: 7 /* pages can be reused (by anyone) */
MADV_FREE_REUSE :: 8 /* caller wants to reuse those pages */
MADV_CAN_REUSE :: 9
MADV_PAGEOUT :: 10 /* page out now (internal only) */
// msync() flags
MS_ASYNC :: 0x0001 /* [MF|SIO] return immediately */
MS_INVALIDATE :: 0x0002 /* [MF|SIO] invalidate all cached data */
MS_SYNC :: 0x0010 /* [MF|SIO] msync synchronously */
MS_KILLPAGES :: 0x0004 /* invalidate pages, leave mapped */
MS_DEACTIVATE :: 0x0008 /* deactivate pages, leave mapped */
// Return bits from mincore
MINCORE_INCORE :: 0x1 /* Page is incore */
MINCORE_REFERENCED :: 0x2 /* Page has been referenced by us */
MINCORE_MODIFIED :: 0x4 /* Page has been modified by us */
MINCORE_REFERENCED_OTHER :: 0x8 /* Page has been referenced */
MINCORE_MODIFIED_OTHER :: 0x10 /* Page has been modified */
MINCORE_PAGED_OUT :: 0x20 /* Page has been paged out */
MINCORE_COPIED :: 0x40 /* Page has been copied */
MINCORE_ANONYMOUS :: 0x80 /* Page belongs to an anonymous object */
// Allocation failure result
MAP_FAILED : rawptr = rawptr(~uintptr(0))
foreign libc {
@(link_name="mlockall") _mlockall :: proc(flags: c.int) -> c.int ---
@(link_name="munlockall") _munlockall :: proc() -> c.int ---
@(link_name="mlock") _mlock :: proc(addr: rawptr, len: c.size_t) -> c.int ---
@(link_name="mmap") _mmap :: proc(addr: rawptr, len: c.size_t, prot: c.int, flags: c.int, fd: c.int, offset: int) -> rawptr ---
@(link_name="mprotect") _mprotect :: proc(addr: rawptr, len: c.size_t, prot: c.int) -> c.int ---
@(link_name="msync") _msync :: proc(addr: rawptr, len: c.size_t) -> c.int ---
@(link_name="munlock") _munlock :: proc(addr: rawptr, len: c.size_t) -> c.int ---
@(link_name="munmap") _munmap :: proc(addr: rawptr, len: c.size_t) -> c.int ---
@(link_name="shm_open") _shm_open :: proc(name: cstring, oflag: c.int, #c_vararg args: ..any) -> c.int ---
@(link_name="shm_unlink") _shm_unlink :: proc(name: cstring) -> c.int ---
@(link_name="posix_madvise") _posix_madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
@(link_name="madvise") _madvise :: proc(addr: rawptr, len: c.size_t, advice: c.int) -> c.int ---
@(link_name="mincore") _mincore :: proc(addr: rawptr, len: c.size_t, vec: cstring) -> c.int ---
@(link_name="minherit") _minherit :: proc(addr: rawptr, len: c.size_t, inherit: c.int) -> c.int ---
}
_reserve :: proc "contextless" (size: uint) -> (data: []byte, err: Allocator_Error) {
result := _mmap(nil, size, PROT_NONE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0)
if result == MAP_FAILED {
return nil, .Out_Of_Memory
}
return ([^]byte)(uintptr(result))[:size], nil
}
_commit :: proc "contextless" (data: rawptr, size: uint) -> Allocator_Error {
result := _mprotect(data, size, PROT_READ|PROT_WRITE)
if result != 0 {
return .Out_Of_Memory
}
return nil
}
_decommit :: proc "contextless" (data: rawptr, size: uint) {
_mprotect(data, size, PROT_NONE)
_madvise(data, size, MADV_FREE)
}
_release :: proc "contextless" (data: rawptr, size: uint) {
_munmap(data, size)
}
_protect :: proc "contextless" (data: rawptr, size: uint, flags: Protect_Flags) -> bool {
pflags: c.int
pflags = PROT_NONE
if .Read in flags { pflags |= PROT_READ }
if .Write in flags { pflags |= PROT_WRITE }
if .Execute in flags { pflags |= PROT_EXEC }
err := _mprotect(data, size, pflags)
return err != 0
}
_platform_memory_init :: proc() {
DEFAULT_PAGE_SIZE = 4096
// is power of two
assert(DEFAULT_PAGE_SIZE != 0 && (DEFAULT_PAGE_SIZE & (DEFAULT_PAGE_SIZE-1)) == 0)
}
+37 -1
View File
@@ -552,13 +552,20 @@ unparen_expr :: proc(expr: ^Expr) -> (val: ^Expr) {
return return
} }
Field_Flags :: distinct bit_set[Field_Flag]
Field_Flag :: enum { Field_Flag :: enum {
Invalid,
Unknown,
Ellipsis, Ellipsis,
Using, Using,
No_Alias, No_Alias,
C_Vararg, C_Vararg,
Auto_Cast, Auto_Cast,
Any_Int, Any_Int,
Subtype,
By_Ptr,
Results, Results,
Tags, Tags,
@@ -566,11 +573,38 @@ Field_Flag :: enum {
Typeid_Token, Typeid_Token,
} }
Field_Flags :: distinct bit_set[Field_Flag] field_flag_strings := [Field_Flag]string{
.Invalid = "",
.Unknown = "",
.Ellipsis = "..",
.Using = "using",
.No_Alias = "#no_alias",
.C_Vararg = "#c_vararg",
.Auto_Cast = "auto_cast",
.Any_Int = "#any_int",
.Subtype = "#subtype",
.By_Ptr = "#by_ptr",
.Results = "results",
.Tags = "field tag",
.Default_Parameters = "default parameters",
.Typeid_Token = "typeid",
}
field_hash_flag_strings := []struct{key: string, flag: Field_Flag}{
{"no_alias", .No_Alias},
{"c_vararg", .C_Vararg},
{"any_int", .Any_Int},
{"subtype", .Subtype},
{"by_ptr", .By_Ptr},
}
Field_Flags_Struct :: Field_Flags{ Field_Flags_Struct :: Field_Flags{
.Using, .Using,
.Tags, .Tags,
.Subtype,
} }
Field_Flags_Record_Poly_Params :: Field_Flags{ Field_Flags_Record_Poly_Params :: Field_Flags{
.Typeid_Token, .Typeid_Token,
@@ -583,6 +617,7 @@ Field_Flags_Signature :: Field_Flags{
.C_Vararg, .C_Vararg,
.Auto_Cast, .Auto_Cast,
.Any_Int, .Any_Int,
.By_Ptr,
.Default_Parameters, .Default_Parameters,
} }
@@ -665,6 +700,7 @@ Proc_Type :: struct {
Pointer_Type :: struct { Pointer_Type :: struct {
using node: Expr, using node: Expr,
tag: ^Expr,
pointer: tokenizer.Pos, pointer: tokenizer.Pos,
elem: ^Expr, elem: ^Expr,
} }
+1
View File
@@ -286,6 +286,7 @@ clone_node :: proc(node: ^Node) -> ^Node {
r.results = auto_cast clone(r.results) r.results = auto_cast clone(r.results)
case ^Pointer_Type: case ^Pointer_Type:
r.elem = clone(r.elem) r.elem = clone(r.elem)
r.tag = clone(r.tag)
case ^Multi_Pointer_Type: case ^Multi_Pointer_Type:
r.elem = clone(r.elem) r.elem = clone(r.elem)
case ^Array_Type: case ^Array_Type:
+2
View File
@@ -186,6 +186,7 @@ Type_Kind :: enum u32le {
Relative_Slice = 21, Relative_Slice = 21,
Multi_Pointer = 22, Multi_Pointer = 22,
Matrix = 23, Matrix = 23,
Soa_Pointer = 24,
} }
Type_Elems_Cap :: 4 Type_Elems_Cap :: 4
@@ -245,6 +246,7 @@ Type :: struct {
// .Relative_Slice - 2 types: 0=slice type, 1=base integer // .Relative_Slice - 2 types: 0=slice type, 1=base integer
// .Multi_Pointer - 1 type: 0=element // .Multi_Pointer - 1 type: 0=element
// .Matrix - 1 type: 0=element // .Matrix - 1 type: 0=element
// .Soa_Pointer - 1 type: 0=element
types: Array(Type_Index), types: Array(Type_Index),
// Used by: // Used by:
+39 -72
View File
@@ -1611,20 +1611,6 @@ new_ast_field :: proc(names: []^ast.Expr, type: ^ast.Expr, default_value: ^ast.E
return field return field
} }
Field_Prefix :: enum {
Invalid,
Unknown,
Using,
No_Alias,
C_Vararg,
Auto_Cast,
Any_Int,
}
Field_Prefixes :: distinct bit_set[Field_Prefix]
Expr_And_Flags :: struct { Expr_And_Flags :: struct {
expr: ^ast.Expr, expr: ^ast.Expr,
flags: ast.Field_Flags, flags: ast.Field_Flags,
@@ -1666,7 +1652,7 @@ convert_to_ident_list :: proc(p: ^Parser, list: []Expr_And_Flags, ignore_flags,
return idents[:] return idents[:]
} }
is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix { is_token_field_prefix :: proc(p: ^Parser) -> ast.Field_Flag {
#partial switch p.curr_tok.kind { #partial switch p.curr_tok.kind {
case .EOF: case .EOF:
return .Invalid return .Invalid
@@ -1677,17 +1663,15 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
advance_token(p) advance_token(p)
return .Auto_Cast return .Auto_Cast
case .Hash: case .Hash:
tok: tokenizer.Token
advance_token(p) advance_token(p)
defer advance_token(p) tok = p.curr_tok
#partial switch p.curr_tok.kind { advance_token(p)
case .Ident: if tok.kind == .Ident {
switch p.curr_tok.text { for kf in ast.field_hash_flag_strings {
case "no_alias": if kf.key == tok.text {
return .No_Alias return kf.flag
case "c_vararg": }
return .C_Vararg
case "any_int":
return .Any_Int
} }
} }
return .Unknown return .Unknown
@@ -1695,8 +1679,8 @@ is_token_field_prefix :: proc(p: ^Parser) -> Field_Prefix {
return .Invalid return .Invalid
} }
parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags { parse_field_prefixes :: proc(p: ^Parser) -> (flags: ast.Field_Flags) {
counts: [len(Field_Prefix)]int counts: [len(ast.Field_Flag)]int
for { for {
kind := is_token_field_prefix(p) kind := is_token_field_prefix(p)
@@ -1712,31 +1696,17 @@ parse_field_prefixes :: proc(p: ^Parser) -> ast.Field_Flags {
counts[kind] += 1 counts[kind] += 1
} }
flags: ast.Field_Flags for kind in ast.Field_Flag {
for kind in Field_Prefix {
count := counts[kind] count := counts[kind]
switch kind { if kind == .Invalid || kind == .Unknown {
case .Invalid, .Unknown: // Ignore // Ignore
case .Using: } else {
if count > 1 { error(p, p.curr_tok.pos, "multiple 'using' in this field list") } if count > 1 { error(p, p.curr_tok.pos, "multiple '%s' in this field list", ast.field_flag_strings[kind]) }
if count > 0 { flags += {.Using} } if count > 0 { flags += {kind} }
case .No_Alias:
if count > 1 { error(p, p.curr_tok.pos, "multiple '#no_alias' in this field list") }
if count > 0 { flags += {.No_Alias} }
case .C_Vararg:
if count > 1 { error(p, p.curr_tok.pos, "multiple '#c_vararg' in this field list") }
if count > 0 { flags += {.C_Vararg} }
case .Auto_Cast:
if count > 1 { error(p, p.curr_tok.pos, "multiple 'auto_cast' in this field list") }
if count > 0 { flags += {.Auto_Cast} }
case .Any_Int:
if count > 1 { error(p, p.curr_tok.pos, "multiple '#any_int' in this field list") }
if count > 0 { flags += {.Any_Int} }
} }
} }
return flags return
} }
check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, set_flags: ast.Field_Flags) -> (flags: ast.Field_Flags) { check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, set_flags: ast.Field_Flags) -> (flags: ast.Field_Flags) {
@@ -1748,19 +1718,13 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
for flag in ast.Field_Flag { for flag in ast.Field_Flag {
if flag not_in allowed_flags && flag in flags { if flag not_in allowed_flags && flag in flags {
switch flag { #partial switch flag {
case .Using: case .Unknown, .Invalid:
error(p, p.curr_tok.pos, "'using' is not allowed within this field list") // ignore
case .No_Alias:
error(p, p.curr_tok.pos, "'#no_alias' is not allowed within this field list")
case .C_Vararg:
error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list")
case .Auto_Cast:
error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list")
case .Any_Int:
error(p, p.curr_tok.pos, "'#any_int' is not allowed within this field list")
case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token: case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
panic("Impossible prefixes") panic("Impossible prefixes")
case:
error(p, p.curr_tok.pos, "'%s' is not allowed within this field list", ast.field_flag_strings[flag])
} }
flags -= {flag} flags -= {flag}
} }
@@ -2271,7 +2235,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
return parse_call_expr(p, bd) return parse_call_expr(p, bd)
case "soa", "simd": case "soa":
bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name)) bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
bd.tok = tok bd.tok = tok
bd.name = name.text bd.name = name.text
@@ -2280,6 +2244,20 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
#partial switch t in type.derived_expr { #partial switch t in type.derived_expr {
case ^ast.Array_Type: t.tag = bd case ^ast.Array_Type: t.tag = bd
case ^ast.Dynamic_Array_Type: t.tag = bd case ^ast.Dynamic_Array_Type: t.tag = bd
case ^ast.Pointer_Type: t.tag = bd
case:
error(p, original_type.pos, "expected an array or pointer type after #%s", name.text)
}
return original_type
case "simd":
bd := ast.new(ast.Basic_Directive, tok.pos, end_pos(name))
bd.tok = tok
bd.name = name.text
original_type := parse_type(p)
type := ast.unparen_expr(original_type)
#partial switch t in type.derived_expr {
case ^ast.Array_Type: t.tag = bd
case: case:
error(p, original_type.pos, "expected an array type after #%s", name.text) error(p, original_type.pos, "expected an array type after #%s", name.text)
} }
@@ -2631,7 +2609,6 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
tok := expect_token(p, .Union) tok := expect_token(p, .Union)
poly_params: ^ast.Field_List poly_params: ^ast.Field_List
align: ^ast.Expr align: ^ast.Expr
is_maybe: bool
is_no_nil: bool is_no_nil: bool
is_shared_nil: bool is_shared_nil: bool
@@ -2656,10 +2633,7 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
} }
align = parse_expr(p, true) align = parse_expr(p, true)
case "maybe": case "maybe":
if is_maybe { error(p, tag.pos, "#%s functionality has now been merged with standard 'union' functionality", tag.text)
error(p, tag.pos, "duplicate union tag '#%s'", tag.text)
}
is_maybe = true
case "no_nil": case "no_nil":
if is_no_nil { if is_no_nil {
error(p, tag.pos, "duplicate union tag '#%s'", tag.text) error(p, tag.pos, "duplicate union tag '#%s'", tag.text)
@@ -2676,19 +2650,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
} }
p.expr_level = prev_level p.expr_level = prev_level
if is_no_nil && is_maybe {
error(p, p.curr_tok.pos, "#maybe and #no_nil cannot be applied together")
}
if is_no_nil && is_shared_nil { if is_no_nil && is_shared_nil {
error(p, p.curr_tok.pos, "#shared_nil and #no_nil cannot be applied together") error(p, p.curr_tok.pos, "#shared_nil and #no_nil cannot be applied together")
} }
if is_shared_nil && is_maybe {
error(p, p.curr_tok.pos, "#maybe and #shared_nil cannot be applied together")
}
union_kind := ast.Union_Type_Kind.Normal union_kind := ast.Union_Type_Kind.Normal
switch { switch {
case is_maybe: union_kind = .maybe
case is_no_nil: union_kind = .no_nil case is_no_nil: union_kind = .no_nil
case is_shared_nil: union_kind = .shared_nil case is_shared_nil: union_kind = .shared_nil
} }
+1 -1
View File
@@ -151,7 +151,7 @@ print :: proc(p: ^Printer, file: ^ast.File) -> string {
fix_lines(p) fix_lines(p)
builder := strings.make_builder(0, 5 * mem.Megabyte, p.allocator) builder := strings.builder_make(0, 5 * mem.Megabyte, p.allocator)
last_line := 0 last_line := 0
+3 -3
View File
@@ -71,7 +71,7 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int {
return 0 return 0
} else { } else {
builder := strings.make_builder(context.temp_allocator) builder := strings.builder_make(context.temp_allocator)
c_len := len(comment.text) c_len := len(comment.text)
trim_space := true trim_space := true
@@ -90,12 +90,12 @@ push_comment :: proc(p: ^Printer, comment: tokenizer.Token) -> int {
continue continue
case c == '\r' && comment.text[min(c_len - 1, i + 1)] == '\n': case c == '\r' && comment.text[min(c_len - 1, i + 1)] == '\n':
append(&multilines, strings.to_string(builder)) append(&multilines, strings.to_string(builder))
builder = strings.make_builder(context.temp_allocator) builder = strings.builder_make(context.temp_allocator)
trim_space = true trim_space = true
i += 1 i += 1
case c == '\n': case c == '\n':
append(&multilines, strings.to_string(builder)) append(&multilines, strings.to_string(builder))
builder = strings.make_builder(context.temp_allocator) builder = strings.builder_make(context.temp_allocator)
trim_space = true trim_space = true
case c == '/' && comment.text[min(c_len - 1, i + 1)] == '*': case c == '/' && comment.text[min(c_len - 1, i + 1)] == '*':
strings.write_string(&builder, "/*") strings.write_string(&builder, "/*")
+5 -3
View File
@@ -1,6 +1,5 @@
package os package os
import "core:strings"
import "core:mem" import "core:mem"
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) { read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
@@ -51,10 +50,13 @@ read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []F
continue continue
} }
fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator) fullpath := make([]byte, len(dirpath)+1+len(filename))
copy(fullpath, dirpath)
copy(fullpath[len(dirpath):], "/")
copy(fullpath[len(dirpath)+1:], filename)
defer delete(fullpath, context.temp_allocator) defer delete(fullpath, context.temp_allocator)
fi_, err = stat(fullpath, allocator) fi_, err = stat(string(fullpath), allocator)
if err != ERROR_NONE { if err != ERROR_NONE {
for fi__ in dfi { for fi__ in dfi {
file_info_delete(fi__, allocator) file_info_delete(fi__, allocator)
+16 -16
View File
@@ -11,24 +11,24 @@ lookup_env :: proc(key: string, allocator := context.allocator) -> (value: strin
return return
} }
wkey := win32.utf8_to_wstring(key) wkey := win32.utf8_to_wstring(key)
b := make([dynamic]u16, 100, context.temp_allocator) n := win32.GetEnvironmentVariableW(wkey, nil, 0)
for { if n == 0 {
n := win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b))) err := win32.GetLastError()
if n == 0 { if err == u32(ERROR_ENVVAR_NOT_FOUND) {
err := win32.GetLastError() return "", false
if err == u32(ERROR_ENVVAR_NOT_FOUND) {
return "", false
}
} }
if n <= u32(len(b)) {
value, _ = win32.utf16_to_utf8(b[:n], allocator)
found = true
return
}
resize(&b, len(b)*2)
} }
b := make([dynamic]u16, n, context.temp_allocator)
n = win32.GetEnvironmentVariableW(wkey, raw_data(b), u32(len(b)))
if n == 0 {
err := win32.GetLastError()
if err == u32(ERROR_ENVVAR_NOT_FOUND) {
return "", false
}
}
value, _ = win32.utf16_to_utf8(b[:n], allocator)
found = true
return
} }
+10 -10
View File
@@ -6,19 +6,19 @@ import "core:runtime"
user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS { #partial switch ODIN_OS {
case .Windows: case .Windows:
dir = get_env("LocalAppData") dir = get_env("LocalAppData", allocator)
if dir != "" { if dir != "" {
dir = strings.clone_safe(dir, allocator) or_return dir = strings.clone_safe(dir, allocator) or_return
} }
case .Darwin: case .Darwin:
dir = get_env("HOME") dir = get_env("HOME", allocator)
if dir != "" { if dir != "" {
dir = strings.concatenate_safe({dir, "/Library/Caches"}, allocator) or_return dir = strings.concatenate_safe({dir, "/Library/Caches"}, allocator) or_return
} }
case: // All other UNIX systems case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME") dir = get_env("XDG_CACHE_HOME", allocator)
if dir == "" { if dir == "" {
dir = get_env("HOME") dir = get_env("HOME", allocator)
if dir == "" { if dir == "" {
return return
} }
@@ -34,19 +34,19 @@ user_cache_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error
user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) { user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
#partial switch ODIN_OS { #partial switch ODIN_OS {
case .Windows: case .Windows:
dir = get_env("AppData") dir = get_env("AppData", allocator)
if dir != "" { if dir != "" {
dir = strings.clone_safe(dir, allocator) or_return dir = strings.clone_safe(dir, allocator) or_return
} }
case .Darwin: case .Darwin:
dir = get_env("HOME") dir = get_env("HOME", allocator)
if dir != "" { if dir != "" {
dir = strings.concatenate_safe({dir, "/Library/Application Support"}, allocator) or_return dir = strings.concatenate_safe({dir, "/Library/Application Support"}, allocator) or_return
} }
case: // All other UNIX systems case: // All other UNIX systems
dir = get_env("XDG_CACHE_HOME") dir = get_env("XDG_CACHE_HOME", allocator)
if dir == "" { if dir == "" {
dir = get_env("HOME") dir = get_env("HOME", allocator)
if dir == "" { if dir == "" {
return return
} }
@@ -59,13 +59,13 @@ user_config_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Erro
return return
} }
user_home_dir :: proc() -> (dir: string, err: Error) { user_home_dir :: proc(allocator: runtime.Allocator) -> (dir: string, err: Error) {
env := "HOME" env := "HOME"
#partial switch ODIN_OS { #partial switch ODIN_OS {
case .Windows: case .Windows:
env = "USERPROFILE" env = "USERPROFILE"
} }
if v := get_env(env); v != "" { if v := get_env(env, allocator); v != "" {
return v, nil return v, nil
} }
return "", .Invalid_Path return "", .Invalid_Path
+8 -8
View File
@@ -241,13 +241,13 @@ S_ISGID :: 0o2000 // Set group id on execution
S_ISVTX :: 0o1000 // Directory restrcted delete S_ISVTX :: 0o1000 // Directory restrcted delete
S_ISLNK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFLNK S_ISLNK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFLNK }
S_ISREG :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFREG S_ISREG :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFREG }
S_ISDIR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFDIR S_ISDIR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFDIR }
S_ISCHR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFCHR S_ISCHR :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFCHR }
S_ISBLK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFBLK S_ISBLK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFBLK }
S_ISFIFO :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFIFO S_ISFIFO :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFIFO }
S_ISSOCK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFSOCK S_ISSOCK :: #force_inline proc(m: mode_t) -> bool { return (m & S_IFMT) == S_IFSOCK }
F_OK :: 0 // Test for file existance F_OK :: 0 // Test for file existance
X_OK :: 1 // Test for execute permission X_OK :: 1 // Test for execute permission
@@ -257,7 +257,7 @@ R_OK :: 4 // Test for read permission
foreign libc { foreign libc {
@(link_name="__error") __errno_location :: proc() -> ^int --- @(link_name="__error") __errno_location :: proc() -> ^int ---
@(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle --- @(link_name="open") _unix_open :: proc(path: cstring, flags: c.int, mode: c.int) -> Handle ---
@(link_name="close") _unix_close :: proc(fd: Handle) -> c.int --- @(link_name="close") _unix_close :: proc(fd: Handle) -> c.int ---
@(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- @(link_name="read") _unix_read :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
@(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t --- @(link_name="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
+1 -1
View File
@@ -271,7 +271,7 @@ _glob :: proc(dir, pattern: string, matches: ^[dynamic]string, allocator := cont
} }
d, derr := os.open(dir) d, derr := os.open(dir, os.O_RDONLY)
if derr != 0 { if derr != 0 {
return return
} }
+1 -1
View File
@@ -146,7 +146,7 @@ clean :: proc(path: string, allocator := context.allocator) -> string {
} }
// join joins numerous path elements into a single path // join joins numerous path elements into a single path
join :: proc(elems: ..string, allocator := context.allocator) -> string { join :: proc(elems: []string, allocator := context.allocator) -> string {
context.allocator = allocator context.allocator = allocator
for elem, i in elems { for elem, i in elems {
if elem != "" { if elem != "" {
+5
View File
@@ -34,6 +34,7 @@ Type_Info_Simd_Vector :: runtime.Type_Info_Simd_Vector
Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer Type_Info_Relative_Pointer :: runtime.Type_Info_Relative_Pointer
Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice Type_Info_Relative_Slice :: runtime.Type_Info_Relative_Slice
Type_Info_Matrix :: runtime.Type_Info_Matrix Type_Info_Matrix :: runtime.Type_Info_Matrix
Type_Info_Soa_Pointer :: runtime.Type_Info_Soa_Pointer
Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value Type_Info_Enum_Value :: runtime.Type_Info_Enum_Value
@@ -68,6 +69,7 @@ Type_Kind :: enum {
Relative_Pointer, Relative_Pointer,
Relative_Slice, Relative_Slice,
Matrix, Matrix,
Soa_Pointer,
} }
@@ -102,6 +104,7 @@ type_kind :: proc(T: typeid) -> Type_Kind {
case Type_Info_Relative_Pointer: return .Relative_Pointer case Type_Info_Relative_Pointer: return .Relative_Pointer
case Type_Info_Relative_Slice: return .Relative_Slice case Type_Info_Relative_Slice: return .Relative_Slice
case Type_Info_Matrix: return .Matrix case Type_Info_Matrix: return .Matrix
case Type_Info_Soa_Pointer: return .Soa_Pointer
} }
} }
@@ -194,6 +197,7 @@ typeid_elem :: proc(id: typeid) -> typeid {
} }
case Type_Info_Pointer: return v.elem.id case Type_Info_Pointer: return v.elem.id
case Type_Info_Multi_Pointer: return v.elem.id case Type_Info_Multi_Pointer: return v.elem.id
case Type_Info_Soa_Pointer: return v.elem.id
case Type_Info_Array: return v.elem.id case Type_Info_Array: return v.elem.id
case Type_Info_Enumerated_Array: return v.elem.id case Type_Info_Enumerated_Array: return v.elem.id
case Type_Info_Slice: return v.elem.id case Type_Info_Slice: return v.elem.id
@@ -1419,6 +1423,7 @@ equal :: proc(a, b: any, including_indirect_array_recursion := false, recursion_
Type_Info_Enum, Type_Info_Enum,
Type_Info_Simd_Vector, Type_Info_Simd_Vector,
Type_Info_Relative_Pointer, Type_Info_Relative_Pointer,
Type_Info_Soa_Pointer,
Type_Info_Matrix: Type_Info_Matrix:
return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0 return mem.compare_byte_ptrs((^byte)(a.data), (^byte)(b.data), t.size) == 0
+15 -2
View File
@@ -68,6 +68,11 @@ are_types_identical :: proc(a, b: ^Type_Info) -> bool {
y := b.variant.(Type_Info_Multi_Pointer) or_return y := b.variant.(Type_Info_Multi_Pointer) or_return
return are_types_identical(x.elem, y.elem) return are_types_identical(x.elem, y.elem)
case Type_Info_Soa_Pointer:
y := b.variant.(Type_Info_Soa_Pointer) or_return
return are_types_identical(x.elem, y.elem)
case Type_Info_Procedure: case Type_Info_Procedure:
y := b.variant.(Type_Info_Procedure) or_return y := b.variant.(Type_Info_Procedure) or_return
switch { switch {
@@ -256,6 +261,11 @@ is_multi_pointer :: proc(info: ^Type_Info) -> bool {
_, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer) _, ok := type_info_base(info).variant.(Type_Info_Multi_Pointer)
return ok return ok
} }
is_soa_pointer :: proc(info: ^Type_Info) -> bool {
if info == nil { return false }
_, ok := type_info_base(info).variant.(Type_Info_Soa_Pointer)
return ok
}
is_pointer_internally :: proc(info: ^Type_Info) -> bool { is_pointer_internally :: proc(info: ^Type_Info) -> bool {
if info == nil { return false } if info == nil { return false }
#partial switch v in info.variant { #partial switch v in info.variant {
@@ -437,6 +447,9 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
case Type_Info_Multi_Pointer: case Type_Info_Multi_Pointer:
io.write_string(w, "[^]", &n) or_return io.write_string(w, "[^]", &n) or_return
write_type(w, info.elem, &n) or_return write_type(w, info.elem, &n) or_return
case Type_Info_Soa_Pointer:
io.write_string(w, "#soa ^", &n) or_return
write_type(w, info.elem, &n) or_return
case Type_Info_Procedure: case Type_Info_Procedure:
io.write_string(w, "proc", &n) or_return io.write_string(w, "proc", &n) or_return
if info.params == nil { if info.params == nil {
@@ -573,11 +586,11 @@ write_type_writer :: proc(w: io.Writer, ti: ^Type_Info, n_written: ^int = nil) -
write_type(w, info.elem, &n) or_return write_type(w, info.elem, &n) or_return
case is_rune(info.elem): case is_rune(info.elem):
io.write_encoded_rune(w, rune(info.lower), true, &n) or_return io.write_encoded_rune(w, rune(info.lower), true, &n) or_return
io.write_string(w, "..", &n) or_return io.write_string(w, "..=", &n) or_return
io.write_encoded_rune(w, rune(info.upper), true, &n) or_return io.write_encoded_rune(w, rune(info.upper), true, &n) or_return
case: case:
io.write_i64(w, info.lower, 10, &n) or_return io.write_i64(w, info.lower, 10, &n) or_return
io.write_string(w, "..", &n) or_return io.write_string(w, "..=", &n) or_return
io.write_i64(w, info.upper, 10, &n) or_return io.write_i64(w, info.upper, 10, &n) or_return
} }
if info.underlying != nil { if info.underlying != nil {
+10
View File
@@ -176,6 +176,9 @@ Type_Info_Matrix :: struct {
column_count: int, column_count: int,
// Total element count = column_count * elem_stride // Total element count = column_count * elem_stride
} }
Type_Info_Soa_Pointer :: struct {
elem: ^Type_Info,
}
Type_Info_Flag :: enum u8 { Type_Info_Flag :: enum u8 {
Comparable = 0, Comparable = 0,
@@ -217,6 +220,7 @@ Type_Info :: struct {
Type_Info_Relative_Pointer, Type_Info_Relative_Pointer,
Type_Info_Relative_Slice, Type_Info_Relative_Slice,
Type_Info_Matrix, Type_Info_Matrix,
Type_Info_Soa_Pointer,
}, },
} }
@@ -403,6 +407,12 @@ Raw_Cstring :: struct {
data: [^]byte, data: [^]byte,
} }
Raw_Soa_Pointer :: struct {
data: rawptr,
index: int,
}
/* /*
// Defined internally by the compiler // Defined internally by the compiler
+90 -47
View File
@@ -143,7 +143,7 @@ free_all :: proc{mem_free_all}
@builtin @builtin
delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { delete_string :: proc(str: string, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free(raw_data(str), allocator, loc) return mem_free_with_size(raw_data(str), len(str), allocator, loc)
} }
@builtin @builtin
delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
@@ -151,17 +151,24 @@ delete_cstring :: proc(str: cstring, allocator := context.allocator, loc := #cal
} }
@builtin @builtin
delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error { delete_dynamic_array :: proc(array: $T/[dynamic]$E, loc := #caller_location) -> Allocator_Error {
return mem_free(raw_data(array), array.allocator, loc) return mem_free_with_size(raw_data(array), cap(array)*size_of(E), array.allocator, loc)
} }
@builtin @builtin
delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { delete_slice :: proc(array: $T/[]$E, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
return mem_free(raw_data(array), allocator, loc) return mem_free_with_size(raw_data(array), len(array)*size_of(E), allocator, loc)
} }
@builtin @builtin
delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error { delete_map :: proc(m: $T/map[$K]$V, loc := #caller_location) -> Allocator_Error {
Entry :: struct {
hash: uintptr,
next: int,
key: K,
value: V,
}
raw := transmute(Raw_Map)m raw := transmute(Raw_Map)m
err := delete_slice(raw.hashes, raw.entries.allocator, loc) err := delete_slice(raw.hashes, raw.entries.allocator, loc)
err1 := mem_free(raw.entries.data, raw.entries.allocator, loc) err1 := mem_free_with_size(raw.entries.data, raw.entries.cap*size_of(Entry), raw.entries.allocator, loc)
if err == nil { if err == nil {
err = err1 err = err1
} }
@@ -339,19 +346,22 @@ append_elem :: proc(array: ^$T/[dynamic]$E, arg: E, loc := #caller_location) {
if array == nil { if array == nil {
return return
} }
when size_of(E) == 0 {
if cap(array) < len(array)+1 {
cap := 2 * cap(array) + max(8, 1)
_ = 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(condition=data != nil, loc=loc)
data[a.len] = arg
}
a.len += 1 a.len += 1
} else {
if cap(array) < len(array)+1 {
cap := 2 * cap(array) + max(8, 1)
_ = 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(condition=data != nil, loc=loc)
data[a.len] = arg
}
a.len += 1
}
} }
} }
@@ -366,20 +376,23 @@ append_elems :: proc(array: ^$T/[dynamic]$E, args: ..E, loc := #caller_location)
return return
} }
when size_of(E) == 0 {
if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len)
_ = 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(condition=data != nil, loc=loc)
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len)
}
a.len += arg_len a.len += arg_len
} else {
if cap(array) < len(array)+arg_len {
cap := 2 * cap(array) + max(8, arg_len)
_ = 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(condition=data != nil, loc=loc)
intrinsics.mem_copy(&data[a.len], raw_data(args), size_of(E) * arg_len)
}
a.len += arg_len
}
} }
} }
@@ -413,7 +426,7 @@ append_nothing :: proc(array: ^$T/[dynamic]$E, loc := #caller_location) {
@builtin @builtin
insert_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check { inject_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if array == nil { if array == nil {
return return
} }
@@ -432,7 +445,7 @@ insert_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #calle
} }
@builtin @builtin
insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check { inject_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if array == nil { if array == nil {
return return
} }
@@ -456,7 +469,7 @@ insert_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #c
} }
@builtin @builtin
insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check { inject_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if array == nil { if array == nil {
return return
} }
@@ -477,7 +490,51 @@ insert_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string
return return
} }
@builtin insert_at :: proc{insert_at_elem, insert_at_elems, insert_at_elem_string} @builtin inject_at :: proc{inject_at_elem, inject_at_elems, inject_at_elem_string}
@builtin
assign_at_elem :: proc(array: ^$T/[dynamic]$E, index: int, arg: E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if index < len(array) {
array[index] = arg
ok = true
} else if resize(array, index+1, loc) {
array[index] = arg
ok = true
}
return
}
@builtin
assign_at_elems :: proc(array: ^$T/[dynamic]$E, index: int, args: ..E, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if index+len(args) < len(array) {
copy(array[index:], args)
ok = true
} else if resize(array, index+1+len(args), loc) {
copy(array[index:], args)
ok = true
}
return
}
@builtin
assign_at_elem_string :: proc(array: ^$T/[dynamic]$E/u8, index: int, arg: string, loc := #caller_location) -> (ok: bool) #no_bounds_check {
if len(args) == 0 {
ok = true
} else if index+len(args) < len(array) {
copy(array[index:], args)
ok = true
} else if resize(array, index+1+len(args), loc) {
copy(array[index:], args)
ok = true
}
return
}
@builtin assign_at :: proc{assign_at_elem, assign_at_elems, assign_at_elem_string}
@@ -735,17 +792,3 @@ unimplemented :: proc(message := "", loc := #caller_location) -> ! {
} }
p("not yet implemented", message, loc) p("not yet implemented", message, loc)
} }
@builtin
@(disabled=ODIN_DISABLE_ASSERT)
unreachable :: proc(message := "", loc := #caller_location) -> ! {
p := context.assertion_failure_proc
if p == nil {
p = default_assertion_failure_proc
}
if message != "" {
p("internal error", message, loc)
} else {
p("internal error", "entered unreachable code", loc)
}
}
+7 -3
View File
@@ -29,11 +29,15 @@ __dynamic_array_reserve :: proc(array_: rawptr, elem_size, elem_align: int, cap:
new_size := cap * elem_size new_size := cap * elem_size
allocator := array.allocator allocator := array.allocator
new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc) new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc)
if err != nil { if err != nil {
return false return false
} }
if new_data != nil || elem_size == 0 { if elem_size == 0 {
array.data = raw_data(new_data)
array.cap = cap
return true
} else if new_data != nil {
array.data = raw_data(new_data) array.data = raw_data(new_data)
array.cap = min(cap, len(new_data)/elem_size) array.cap = min(cap, len(new_data)/elem_size)
return true return true
@@ -59,7 +63,7 @@ __dynamic_array_shrink :: proc(array_: rawptr, elem_size, elem_align: int, new_c
new_size := new_cap * elem_size new_size := new_cap * elem_size
allocator := array.allocator allocator := array.allocator
new_data, err := allocator.procedure(allocator.data, .Resize, new_size, elem_align, array.data, old_size, loc) new_data, err := mem_resize(array.data, old_size, new_size, elem_align, allocator, loc)
if err != nil { if err != nil {
return return
} }
+8 -5
View File
@@ -194,12 +194,15 @@ __slice_resize :: proc(array_: ^$T/[]$E, new_count: int, allocator: Allocator, l
new_size := new_count*size_of(T) new_size := new_count*size_of(T)
new_data, err := mem_resize(array.data, old_size, new_size, align_of(T), allocator, loc) new_data, err := mem_resize(array.data, old_size, new_size, align_of(T), allocator, loc)
if new_data == nil || err != nil { if err != nil {
return false return false
} }
array.data = new_data if new_data != nil || size_of(E) == 0 {
array.len = new_count array.data = raw_data(new_data)
return true array.len = new_count
return true
}
return false
} }
__dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) { __dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_location) {
@@ -207,7 +210,7 @@ __dynamic_map_reset_entries :: proc(using header: Map_Header, loc := #caller_loc
m.hashes[i] = -1 m.hashes[i] = -1
} }
for i in 0 ..< m.entries.len { for i in 0..<m.entries.len {
entry_header := __dynamic_map_get_entry(header, i) entry_header := __dynamic_map_get_entry(header, i)
entry_hash := __get_map_hash_from_entry(header, entry_header) entry_hash := __get_map_hash_from_entry(header, entry_header)
entry_header.next = -1 entry_header.next = -1
+61 -37
View File
@@ -103,7 +103,7 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
if data == nil { if data == nil {
return nil return nil
} }
if len < 0 { if len <= 0 {
return data return data
} }
intrinsics.mem_zero(data, len) intrinsics.mem_zero(data, len)
@@ -111,22 +111,18 @@ mem_zero :: proc "contextless" (data: rawptr, len: int) -> rawptr {
} }
mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { mem_copy :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil { if src != nil && dst != src && len > 0 {
return dst // NOTE(bill): This _must_ be implemented like C's memmove
intrinsics.mem_copy(dst, src, len)
} }
// NOTE(bill): This _must_ be implemented like C's memmove
intrinsics.mem_copy(dst, src, len)
return dst return dst
} }
mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr { mem_copy_non_overlapping :: proc "contextless" (dst, src: rawptr, len: int) -> rawptr {
if src == nil { if src != nil && dst != src && len > 0 {
return dst // NOTE(bill): This _must_ be implemented like C's memcpy
intrinsics.mem_copy_non_overlapping(dst, src, len)
} }
// NOTE(bill): This _must_ be implemented like C's memcpy
intrinsics.mem_copy_non_overlapping(dst, src, len)
return dst return dst
} }
@@ -142,28 +138,38 @@ mem_alloc_bytes :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNM
return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc) return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
} }
mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (rawptr, Allocator_Error) { mem_alloc :: #force_inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
if size == 0 { if size == 0 || allocator.procedure == nil {
return nil, nil return nil, nil
} }
if allocator.procedure == nil { return allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
return nil, nil
}
data, err := allocator.procedure(allocator.data, .Alloc, size, alignment, nil, 0, loc)
return raw_data(data), err
} }
mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error { mem_free :: #force_inline proc(ptr: rawptr, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if ptr == nil { if ptr == nil || allocator.procedure == nil {
return .None return nil
}
if allocator.procedure == nil {
return .None
} }
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc) _, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc)
return err return err
} }
mem_free_with_size :: #force_inline proc(ptr: rawptr, byte_count: int, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if ptr == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, byte_count, loc)
return err
}
mem_free_bytes :: #force_inline proc(bytes: []byte, allocator := context.allocator, loc := #caller_location) -> Allocator_Error {
if bytes == nil || allocator.procedure == nil {
return nil
}
_, err := allocator.procedure(allocator.data, .Free, 0, 0, raw_data(bytes), len(bytes), loc)
return err
}
mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) { mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #caller_location) -> (err: Allocator_Error) {
if allocator.procedure != nil { if allocator.procedure != nil {
_, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc) _, err = allocator.procedure(allocator.data, .Free_All, 0, 0, nil, 0, loc)
@@ -171,21 +177,34 @@ mem_free_all :: #force_inline proc(allocator := context.allocator, loc := #calle
return return
} }
mem_resize :: #force_inline proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> (new_ptr: rawptr, err: Allocator_Error) { mem_resize :: proc(ptr: rawptr, old_size, new_size: int, alignment: int = DEFAULT_ALIGNMENT, allocator := context.allocator, loc := #caller_location) -> ([]byte, Allocator_Error) {
new_data: []byte if allocator.procedure == nil {
switch { return nil, nil
case allocator.procedure == nil:
return
case new_size == 0:
new_data, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, 0, loc)
case ptr == nil:
new_data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
case:
new_data, err = allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
} }
new_ptr = raw_data(new_data) if new_size == 0 {
return if ptr != nil {
_, err := allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
return nil, err
}
return nil, nil
} else if ptr == nil {
return allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
} else if old_size == new_size && uintptr(ptr) % uintptr(alignment) == 0 {
return ([^]byte)(ptr)[:old_size], nil
}
data, err := allocator.procedure(allocator.data, .Resize, new_size, alignment, ptr, old_size, loc)
if err == .Mode_Not_Implemented {
data, err = allocator.procedure(allocator.data, .Alloc, new_size, alignment, nil, 0, loc)
if err != nil {
return data, err
}
copy(data, ([^]byte)(ptr)[:old_size])
_, err = allocator.procedure(allocator.data, .Free, 0, 0, ptr, old_size, loc)
}
return data, err
} }
memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool { memory_equal :: proc "contextless" (x, y: rawptr, n: int) -> bool {
switch { switch {
case n == 0: return true case n == 0: return true
@@ -341,7 +360,12 @@ string_eq :: proc "contextless" (lhs, rhs: string) -> bool {
string_cmp :: proc "contextless" (a, b: string) -> int { string_cmp :: proc "contextless" (a, b: string) -> int {
x := transmute(Raw_String)a x := transmute(Raw_String)a
y := transmute(Raw_String)b y := transmute(Raw_String)b
return memory_compare(x.data, y.data, min(x.len, y.len))
ret := memory_compare(x.data, y.data, min(x.len, y.len))
if ret == 0 && x.len != y.len {
return -1 if x.len < y.len else +1
}
return ret
} }
string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b) } string_ne :: #force_inline proc "contextless" (a, b: string) -> bool { return !string_eq(a, b) }
+3
View File
@@ -228,6 +228,9 @@ print_type :: proc "contextless" (ti: ^Type_Info) {
case Type_Info_Multi_Pointer: case Type_Info_Multi_Pointer:
print_string("[^]") print_string("[^]")
print_type(info.elem) print_type(info.elem)
case Type_Info_Soa_Pointer:
print_string("#soa ^")
print_type(info.elem)
case Type_Info_Procedure: case Type_Info_Procedure:
print_string("proc") print_string("proc")
if info.params == nil { if info.params == nil {
+6 -1
View File
@@ -684,5 +684,10 @@ compare_f64s :: proc(a, b: f64) -> int {
compare_strings :: proc(a, b: string) -> int { compare_strings :: proc(a, b: string) -> int {
x := transmute(mem.Raw_String)a x := transmute(mem.Raw_String)a
y := transmute(mem.Raw_String)b y := transmute(mem.Raw_String)b
return mem.compare_byte_ptrs(x.data, y.data, min(x.len, y.len))
ret := mem.compare_byte_ptrs(x.data, y.data, min(x.len, y.len))
if ret == 0 && x.len != y.len {
return -1 if x.len < y.len else +1
}
return ret
} }
+43 -105
View File
@@ -17,50 +17,53 @@ Builder :: struct {
} }
// return a builder, default length 0 / cap 16 are done through make // return a builder, default length 0 / cap 16 are done through make
make_builder_none :: proc(allocator := context.allocator) -> Builder { builder_make_none :: proc(allocator := context.allocator) -> Builder {
return Builder{buf=make([dynamic]byte, allocator)} return Builder{buf=make([dynamic]byte, allocator)}
} }
// return a builder, with a set length `len` and cap 16 byte buffer // return a builder, with a set length `len` and cap 16 byte buffer
make_builder_len :: proc(len: int, allocator := context.allocator) -> Builder { builder_make_len :: proc(len: int, allocator := context.allocator) -> Builder {
return Builder{buf=make([dynamic]byte, len, allocator)} return Builder{buf=make([dynamic]byte, len, allocator)}
} }
// return a builder, with a set length `len` byte buffer and a custom `cap` // return a builder, with a set length `len` byte buffer and a custom `cap`
make_builder_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder { builder_make_len_cap :: proc(len, cap: int, allocator := context.allocator) -> Builder {
return Builder{buf=make([dynamic]byte, len, cap, allocator)} return Builder{buf=make([dynamic]byte, len, cap, allocator)}
} }
// overload simple `make_builder_*` with or without len / cap parameters // overload simple `builder_make_*` with or without len / cap parameters
make_builder :: proc{ builder_make :: proc{
make_builder_none, builder_make_none,
make_builder_len, builder_make_len,
make_builder_len_cap, builder_make_len_cap,
} }
// initialize a builder, default length 0 / cap 16 are done through make // initialize a builder, default length 0 / cap 16 are done through make
// replaces the existing `buf` // replaces the existing `buf`
init_builder_none :: proc(b: ^Builder, allocator := context.allocator) { builder_init_none :: proc(b: ^Builder, allocator := context.allocator) -> ^Builder {
b.buf = make([dynamic]byte, allocator) b.buf = make([dynamic]byte, allocator)
return b
} }
// initialize a builder, with a set length `len` and cap 16 byte buffer // initialize a builder, with a set length `len` and cap 16 byte buffer
// replaces the existing `buf` // replaces the existing `buf`
init_builder_len :: proc(b: ^Builder, len: int, allocator := context.allocator) { builder_init_len :: proc(b: ^Builder, len: int, allocator := context.allocator) -> ^Builder {
b.buf = make([dynamic]byte, len, allocator) b.buf = make([dynamic]byte, len, allocator)
return b
} }
// initialize a builder, with a set length `len` byte buffer and a custom `cap` // initialize a builder, with a set length `len` byte buffer and a custom `cap`
// replaces the existing `buf` // replaces the existing `buf`
init_builder_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) { builder_init_len_cap :: proc(b: ^Builder, len, cap: int, allocator := context.allocator) -> ^Builder {
b.buf = make([dynamic]byte, len, cap, allocator) b.buf = make([dynamic]byte, len, cap, allocator)
return b
} }
// overload simple `init_builder_*` with or without len / ap parameters // overload simple `builder_init_*` with or without len / ap parameters
init_builder :: proc{ builder_init :: proc{
init_builder_none, builder_init_none,
init_builder_len, builder_init_len,
init_builder_len_cap, builder_init_len_cap,
} }
@(private) @(private)
@@ -103,18 +106,18 @@ to_writer :: proc(b: ^Builder) -> io.Writer {
} }
// delete and clear the builder byte buffer content // delete and clear the builder byte buffer content
destroy_builder :: proc(b: ^Builder) { builder_destroy :: proc(b: ^Builder) {
delete(b.buf) delete(b.buf)
clear(&b.buf) clear(&b.buf)
} }
// reserve the builfer byte buffer to a specific cap, when it's higher than before // reserve the builfer byte buffer to a specific cap, when it's higher than before
grow_builder :: proc(b: ^Builder, cap: int) { builder_grow :: proc(b: ^Builder, cap: int) {
reserve(&b.buf, cap) reserve(&b.buf, cap)
} }
// clear the builder byte buffer content // clear the builder byte buffer content
reset_builder :: proc(b: ^Builder) { builder_reset :: proc(b: ^Builder) {
clear(&b.buf) clear(&b.buf)
} }
@@ -165,7 +168,7 @@ builder_space :: proc(b: Builder) -> int {
/* /*
appends a byte to the builder, returns the append diff appends a byte to the builder, returns the append diff
builder := strings.make_builder() builder := strings.builder_make()
strings.write_byte(&builder, 'a') // 1 strings.write_byte(&builder, 'a') // 1
strings.write_byte(&builder, 'b') // 1 strings.write_byte(&builder, 'b') // 1
strings.write_byte(&builder, 'c') // 1 strings.write_byte(&builder, 'c') // 1
@@ -181,7 +184,7 @@ write_byte :: proc(b: ^Builder, x: byte) -> (n: int) {
/* /*
appends a slice of bytes to the builder, returns the append diff appends a slice of bytes to the builder, returns the append diff
builder := strings.make_builder() builder := strings.builder_make()
bytes := [?]byte { 'a', 'b', 'c' } bytes := [?]byte { 'a', 'b', 'c' }
strings.write_bytes(&builder, bytes[:]) // 3 strings.write_bytes(&builder, bytes[:]) // 3
fmt.println(strings.to_string(builder)) // -> abc fmt.println(strings.to_string(builder)) // -> abc
@@ -196,77 +199,46 @@ write_bytes :: proc(b: ^Builder, x: []byte) -> (n: int) {
/* /*
appends a single rune into the builder, returns written rune size and an `io.Error` appends a single rune into the builder, returns written rune size and an `io.Error`
builder := strings.make_builder() builder := strings.builder_make()
strings.write_rune_builder(&builder, 'ä') // 2 None strings.write_rune(&builder, 'ä') // 2 None
strings.write_rune_builder(&builder, 'b') // 1 None strings.write_rune(&builder, 'b') // 1 None
strings.write_rune_builder(&builder, 'c') // 1 None strings.write_rune(&builder, 'c') // 1 None
fmt.println(strings.to_string(builder)) // -> äbc fmt.println(strings.to_string(builder)) // -> äbc
*/ */
write_rune_builder :: proc(b: ^Builder, r: rune) -> (int, io.Error) { write_rune :: proc(b: ^Builder, r: rune) -> (int, io.Error) {
return io.write_rune(to_writer(b), r) return io.write_rune(to_writer(b), r)
} }
/* /*
appends a quoted rune into the builder, returns written size appends a quoted rune into the builder, returns written size
builder := strings.make_builder() builder := strings.builder_make()
strings.write_string(&builder, "abc") // 3 strings.write_string(&builder, "abc") // 3
strings.write_quoted_rune_builder(&builder, 'ä') // 4 strings.write_quoted_rune(&builder, 'ä') // 4
strings.write_string(&builder, "abc") // 3 strings.write_string(&builder, "abc") // 3
fmt.println(strings.to_string(builder)) // -> abc'ä'abc fmt.println(strings.to_string(builder)) // -> abc'ä'abc
*/ */
write_quoted_rune_builder :: proc(b: ^Builder, r: rune) -> (n: int) { write_quoted_rune :: proc(b: ^Builder, r: rune) -> (n: int) {
return write_quoted_rune(to_writer(b), r) return io.write_quoted_rune(to_writer(b), r)
} }
@(private)
_write_byte :: proc(w: io.Writer, c: byte) -> int {
err := io.write_byte(w, c)
return 1 if err == nil else 0
}
// writer append a quoted rune into the byte buffer, return the written size
write_quoted_rune :: proc(w: io.Writer, r: rune) -> (n: int) {
quote := byte('\'')
n += _write_byte(w, quote)
buf, width := utf8.encode_rune(r)
if width == 1 && r == utf8.RUNE_ERROR {
n += _write_byte(w, '\\')
n += _write_byte(w, 'x')
n += _write_byte(w, DIGITS_LOWER[buf[0]>>4])
n += _write_byte(w, DIGITS_LOWER[buf[0]&0xf])
} else {
i, _ := io.write_escaped_rune(w, r, quote)
n += i
}
n += _write_byte(w, quote)
return
}
// overload for `write_string_*` variants
write_string :: proc{
write_string_builder,
write_string_writer,
}
/* /*
appends a string to the builder, return the written byte size appends a string to the builder, return the written byte size
builder := strings.make_builder() builder := strings.builder_make()
strings.write_string(&builder, "a") // 1 strings.write_string(&builder, "a") // 1
strings.write_string(&builder, "bc") // 2 strings.write_string(&builder, "bc") // 2
strings.write_string(&builder, "xyz") // 3 strings.write_string(&builder, "xyz") // 3
fmt.println(strings.to_string(builder)) // -> abcxyz fmt.println(strings.to_string(builder)) // -> abcxyz
*/ */
write_string_builder :: proc(b: ^Builder, s: string) -> (n: int) { write_string :: proc(b: ^Builder, s: string) -> (n: int) {
return write_string_writer(to_writer(b), s) n0 := len(b.buf)
append(&b.buf, s)
n1 := len(b.buf)
return n1-n0
} }
// appends a string to the writer
write_string_writer :: proc(w: io.Writer, s: string) -> (n: int) {
n, _ = io.write(w, transmute([]byte)s)
return
}
// pops and returns the last byte in the builder // pops and returns the last byte in the builder
// returns 0 when the builder is empty // returns 0 when the builder is empty
@@ -297,70 +269,36 @@ pop_rune :: proc(b: ^Builder) -> (r: rune, width: int) {
@(private) @(private)
DIGITS_LOWER := "0123456789abcdefx" DIGITS_LOWER := "0123456789abcdefx"
// overload for `write_quoted_string_*` variants
write_quoted_string :: proc{
write_quoted_string_builder,
write_quoted_string_writer,
}
/* /*
append a quoted string into the builder, return the written byte size append a quoted string into the builder, return the written byte size
builder := strings.make_builder() builder := strings.builder_make()
strings.write_quoted_string(&builder, "a") // 3 strings.write_quoted_string(&builder, "a") // 3
strings.write_quoted_string(&builder, "bc", '\'') // 4 strings.write_quoted_string(&builder, "bc", '\'') // 4
strings.write_quoted_string(&builder, "xyz") // 5 strings.write_quoted_string(&builder, "xyz") // 5
fmt.println(strings.to_string(builder)) // -> "a"'bc'xyz" fmt.println(strings.to_string(builder)) // -> "a"'bc'xyz"
*/ */
write_quoted_string_builder :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) { write_quoted_string :: proc(b: ^Builder, str: string, quote: byte = '"') -> (n: int) {
n, _ = io.write_quoted_string(to_writer(b), str, quote) n, _ = io.write_quoted_string(to_writer(b), str, quote)
return return
} }
@(deprecated="prefer io.write_quoted_string")
write_quoted_string_writer :: proc(w: io.Writer, str: string, quote: byte = '"') -> (n: int) {
n, _ = io.write_quoted_string(w, str, quote)
return
}
// overload for `write_encoded_rune_*`
write_encoded_rune :: proc{
write_encoded_rune_builder,
write_encoded_rune_writer,
}
// appends a rune to the builder, optional `write_quote` boolean tag, returns the written rune size // appends a rune to the builder, optional `write_quote` boolean tag, returns the written rune size
write_encoded_rune_builder :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) { write_encoded_rune :: proc(b: ^Builder, r: rune, write_quote := true) -> (n: int) {
n, _ = io.write_encoded_rune(to_writer(b), r, write_quote) n, _ = io.write_encoded_rune(to_writer(b), r, write_quote)
return return
} }
@(deprecated="prefer io.write_encoded_rune")
write_encoded_rune_writer :: proc(w: io.Writer, r: rune, write_quote := true) -> (n: int) {
n, _ = io.write_encoded_rune(w, r, write_quote)
return
}
// overload for `write_escaped_rune_*`
write_escaped_rune :: proc{
write_escaped_rune_builder,
write_escaped_rune_writer,
}
// appends a rune to the builder, fully written out in case of escaped runes e.g. '\a' will be written as such // appends a rune to the builder, fully written out in case of escaped runes e.g. '\a' will be written as such
// when `r` and `quote` match and `quote` is `\\` - they will be written as two slashes // when `r` and `quote` match and `quote` is `\\` - they will be written as two slashes
// `html_safe` flag in case the runes '<', '>', '&' should be encoded as digits e.g. `\u0026` // `html_safe` flag in case the runes '<', '>', '&' should be encoded as digits e.g. `\u0026`
write_escaped_rune_builder :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) { write_escaped_rune :: proc(b: ^Builder, r: rune, quote: byte, html_safe := false) -> (n: int) {
n, _ = io.write_escaped_rune(to_writer(b), r, quote, html_safe) n, _ = io.write_escaped_rune(to_writer(b), r, quote, html_safe)
return return
} }
@(deprecated="prefer io.write_escaped_rune")
write_escaped_rune_writer :: proc(w: io.Writer, r: rune, quote: byte, html_safe := false) -> (n: int) {
n, _ = io.write_escaped_rune(w, r, quote, html_safe)
return
}
// writes a u64 value `i` in `base` = 10 into the builder, returns the written amount of characters // writes a u64 value `i` in `base` = 10 into the builder, returns the written amount of characters
write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) { write_u64 :: proc(b: ^Builder, i: u64, base: int = 10) -> (n: int) {
buf: [32]byte buf: [32]byte
+10 -10
View File
@@ -10,7 +10,7 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
} }
b: Builder b: Builder
init_builder(&b, 0, 0, allocator) builder_init(&b, 0, 0, allocator)
s := s s := s
for c, i in s { for c, i in s {
@@ -20,7 +20,7 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
_, w := utf8.decode_rune_in_string(s[i:]) _, w := utf8.decode_rune_in_string(s[i:])
if w == 1 { if w == 1 {
grow_builder(&b, len(s) + len(replacement)) builder_grow(&b, len(s) + len(replacement))
write_string(&b, s[:i]) write_string(&b, s[:i])
s = s[i:] s = s[i:]
break break
@@ -67,9 +67,9 @@ to_valid_utf8 :: proc(s, replacement: string, allocator := context.allocator) ->
*/ */
to_lower :: proc(s: string, allocator := context.allocator) -> string { to_lower :: proc(s: string, allocator := context.allocator) -> string {
b: Builder b: Builder
init_builder(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator)
for r in s { for r in s {
write_rune_builder(&b, unicode.to_lower(r)) write_rune(&b, unicode.to_lower(r))
} }
return to_string(b) return to_string(b)
} }
@@ -83,9 +83,9 @@ to_lower :: proc(s: string, allocator := context.allocator) -> string {
*/ */
to_upper :: proc(s: string, allocator := context.allocator) -> string { to_upper :: proc(s: string, allocator := context.allocator) -> string {
b: Builder b: Builder
init_builder(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator)
for r in s { for r in s {
write_rune_builder(&b, unicode.to_upper(r)) write_rune(&b, unicode.to_upper(r))
} }
return to_string(b) return to_string(b)
} }
@@ -147,7 +147,7 @@ to_camel_case :: proc(s: string, allocator := context.allocator) -> string {
s := s s := s
s = trim_space(s) s = trim_space(s)
b: Builder b: Builder
init_builder(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator)
w := to_writer(&b) w := to_writer(&b)
string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) { string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
@@ -172,7 +172,7 @@ to_pascal_case :: proc(s: string, allocator := context.allocator) -> string {
s := s s := s
s = trim_space(s) s = trim_space(s)
b: Builder b: Builder
init_builder(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator)
w := to_writer(&b) w := to_writer(&b)
string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) { string_case_iterator(w, s, proc(w: io.Writer, prev, curr, next: rune) {
@@ -203,7 +203,7 @@ to_delimiter_case :: proc(s: string, delimiter: rune, all_upper_case: bool, allo
s := s s := s
s = trim_space(s) s = trim_space(s)
b: Builder b: Builder
init_builder(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator)
w := to_writer(&b) w := to_writer(&b)
adjust_case := unicode.to_upper if all_upper_case else unicode.to_lower adjust_case := unicode.to_upper if all_upper_case else unicode.to_lower
@@ -272,7 +272,7 @@ to_ada_case :: proc(s: string, allocator := context.allocator) -> string {
s := s s := s
s = trim_space(s) s = trim_space(s)
b: Builder b: Builder
init_builder(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator)
w := to_writer(&b) w := to_writer(&b)
prev, curr: rune prev, curr: rune
+11 -11
View File
@@ -31,31 +31,31 @@ intern_destroy :: proc(m: ^Intern) {
// returns the `text` string from the intern map - gets set if it didnt exist yet // returns the `text` string from the intern map - gets set if it didnt exist yet
// the returned string lives as long as the map entry lives // the returned string lives as long as the map entry lives
intern_get :: proc(m: ^Intern, text: string) -> string { intern_get :: proc(m: ^Intern, text: string) -> (str: string, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) entry := _intern_get_entry(m, text) or_return
#no_bounds_check return string(entry.str[:entry.len]) #no_bounds_check return string(entry.str[:entry.len]), nil
} }
// returns the `text` cstring from the intern map - gets set if it didnt exist yet // returns the `text` cstring from the intern map - gets set if it didnt exist yet
// the returned cstring lives as long as the map entry lives // the returned cstring lives as long as the map entry lives
intern_get_cstring :: proc(m: ^Intern, text: string) -> cstring { intern_get_cstring :: proc(m: ^Intern, text: string) -> (str: cstring, err: runtime.Allocator_Error) {
entry := _intern_get_entry(m, text) entry := _intern_get_entry(m, text) or_return
return cstring(&entry.str[0]) return cstring(&entry.str[0]), nil
} }
// looks up wether the `text` string exists in the map, returns the entry // looks up wether the `text` string exists in the map, returns the entry
// sets & allocates the entry if it wasnt set yet // sets & allocates the entry if it wasnt set yet
_intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_check { _intern_get_entry :: proc(m: ^Intern, text: string) -> (new_entry: ^Intern_Entry, err: runtime.Allocator_Error) #no_bounds_check {
if prev, ok := m.entries[text]; ok { if prev, ok := m.entries[text]; ok {
return prev return prev, nil
} }
if m.allocator.procedure == nil { if m.allocator.procedure == nil {
m.allocator = context.allocator m.allocator = context.allocator
} }
entry_size := int(offset_of(Intern_Entry, str)) + len(text) + 1 entry_size := int(offset_of(Intern_Entry, str)) + len(text) + 1
ptr, _ := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator) bytes := runtime.mem_alloc(entry_size, align_of(Intern_Entry), m.allocator) or_return
new_entry := (^Intern_Entry)(ptr) new_entry = (^Intern_Entry)(raw_data(bytes))
new_entry.len = len(text) new_entry.len = len(text)
copy(new_entry.str[:new_entry.len], text) copy(new_entry.str[:new_entry.len], text)
@@ -63,5 +63,5 @@ _intern_get_entry :: proc(m: ^Intern, text: string) -> ^Intern_Entry #no_bounds_
key := string(new_entry.str[:new_entry.len]) key := string(new_entry.str[:new_entry.len])
m.entries[key] = new_entry m.entries[key] = new_entry
return new_entry return new_entry, nil
} }
+8 -8
View File
@@ -1553,7 +1553,7 @@ split_multi_iterate :: proc(using sm: ^Split_Multi) -> (res: string, ok: bool) #
scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string { scrub :: proc(s: string, replacement: string, allocator := context.allocator) -> string {
str := s str := s
b: Builder b: Builder
init_builder(&b, 0, len(s), allocator) builder_init(&b, 0, len(s), allocator)
has_error := false has_error := false
cursor := 0 cursor := 0
@@ -1622,7 +1622,7 @@ expand_tabs :: proc(s: string, tab_size: int, allocator := context.allocator) ->
} }
b: Builder b: Builder
init_builder(&b, allocator) builder_init(&b, allocator)
writer := to_writer(&b) writer := to_writer(&b)
str := s str := s
column: int column: int
@@ -1690,8 +1690,8 @@ centre_justify :: proc(str: string, length: int, pad: string, allocator := conte
pad_len := rune_count(pad) pad_len := rune_count(pad)
b: Builder b: Builder
init_builder(&b, allocator) builder_init(&b, allocator)
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad)) builder_grow(&b, len(str) + (remains/pad_len + 1)*len(pad))
w := to_writer(&b) w := to_writer(&b)
@@ -1713,8 +1713,8 @@ left_justify :: proc(str: string, length: int, pad: string, allocator := context
pad_len := rune_count(pad) pad_len := rune_count(pad)
b: Builder b: Builder
init_builder(&b, allocator) builder_init(&b, allocator)
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad)) builder_grow(&b, len(str) + (remains/pad_len + 1)*len(pad))
w := to_writer(&b) w := to_writer(&b)
@@ -1735,8 +1735,8 @@ right_justify :: proc(str: string, length: int, pad: string, allocator := contex
pad_len := rune_count(pad) pad_len := rune_count(pad)
b: Builder b: Builder
init_builder(&b, allocator) builder_init(&b, allocator)
grow_builder(&b, len(str) + (remains/pad_len + 1)*len(pad)) builder_grow(&b, len(str) + (remains/pad_len + 1)*len(pad))
w := to_writer(&b) w := to_writer(&b)
+8 -12
View File
@@ -3,24 +3,22 @@
package sync package sync
import "core:c" import "core:c"
import "core:os"
import "core:time" import "core:time"
UMTX_OP_WAIT :: 2 UMTX_OP_WAIT :: 2
UMTX_OP_WAKE :: 3 UMTX_OP_WAKE :: 3
ETIMEDOUT :: 60
foreign import libc "system:c" foreign import libc "system:c"
foreign libc { foreign libc {
_umtx_op :: proc "c" (obj: rawptr, op: c.int, val: c.ulong, uaddr: rawptr, uaddr2: rawptr) -> c.int --- _umtx_op :: proc "c" (obj: rawptr, op: c.int, val: c.ulong, uaddr: rawptr, uaddr2: rawptr) -> c.int ---
__error :: proc "c" () -> ^c.int ---
} }
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool { _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
timeout := os.Unix_File_Time{ timeout := [2]i64{14400, 0} // 4 hours
seconds = 5,
nanoseconds = 0,
}
for { for {
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout) res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
@@ -28,7 +26,7 @@ _futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
return true return true
} }
if os.Errno(os.get_last_error()) == os.ETIMEDOUT { if __error()^ == ETIMEDOUT {
continue continue
} }
@@ -42,16 +40,14 @@ _futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Durati
return false return false
} }
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &os.Unix_File_Time{ timeout := [2]i64{i64(duration/1e9), i64(duration%1e9)}
seconds = (os.time_t)(duration/1e9),
nanoseconds = (c.long)(duration%1e9),
})
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
if res != -1 { if res != -1 {
return true return true
} }
if os.Errno(os.get_last_error()) == os.ETIMEDOUT { if __error()^ == ETIMEDOUT {
return false return false
} }
+8 -2
View File
@@ -2,8 +2,14 @@
//+private //+private
package sync package sync
import "core:os" import "core:c"
foreign import dl "system:dl"
foreign dl {
pthread_getthreadid_np :: proc "c" () -> c.int ---
}
_current_thread_id :: proc "contextless" () -> int { _current_thread_id :: proc "contextless" () -> int {
return os.current_thread_id() return int(pthread_getthreadid_np())
} }
+171 -259
View File
@@ -1148,6 +1148,156 @@ foreign wasi {
*/ */
how: sdflags_t, how: sdflags_t,
) -> errno_t --- ) -> errno_t ---
/**
* Return a description of the given preopened file descriptor.
*/
fd_prestat_dir_name :: proc(
fd: fd_t,
/**
* A buffer into which to write the preopened directory name.
*/
path: string,
) -> errno_t ---
/**
* Create a directory.
* Note: This is similar to `mkdirat` in POSIX.
*/
path_create_directory :: proc(
fd: fd_t,
/**
* The path at which to create the directory.
*/
path: string,
) -> errno_t ---
/**
* Adjust the timestamps of a file or directory.
* Note: This is similar to `utimensat` in POSIX.
*/
path_filestat_set_times :: proc(
fd: fd_t,
/**
* Flags determining the method of how the path is resolved.
*/
flags: lookupflags_t,
/**
* The path of the file or directory to operate on.
*/
path: string,
/**
* The desired values of the data access timestamp.
*/
atim: timestamp_t,
/**
* The desired values of the data modification timestamp.
*/
mtim: timestamp_t,
/**
* A bitmask indicating which timestamps to adjust.
*/
fst_flags: fstflags_t,
) -> errno_t ---
/**
* Remove a directory.
* Return `errno::notempty` if the directory is not empty.
* Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
*/
path_remove_directory :: proc(
fd: fd_t,
/**
* The path to a directory to remove.
*/
path: string,
) -> errno_t ---
/**
* Create a hard link.
* Note: This is similar to `linkat` in POSIX.
*/
path_link :: proc(
old_fd: fd_t,
/**
* Flags determining the method of how the path is resolved.
*/
old_flags: lookupflags_t,
/**
* The source path from which to link.
*/
old_path: string,
/**
* The working directory at which the resolution of the new path starts.
*/
new_fd: fd_t,
/**
* The destination path at which to create the hard link.
*/
new_path: string,
) -> errno_t ---
/**
* Rename a file or directory.
* Note: This is similar to `renameat` in POSIX.
*/
path_rename :: proc(
fd: fd_t,
/**
* The source path of the file or directory to rename.
*/
old_path: string,
/**
* The working directory at which the resolution of the new path starts.
*/
new_fd: fd_t,
/**
* The destination path to which to rename the file or directory.
*/
new_path: string,
) -> errno_t ---
/**
* Create a symbolic link.
* Note: This is similar to `symlinkat` in POSIX.
*/
path_symlink :: proc(
/**
* The contents of the symbolic link.
*/
old_path: string,
fd: fd_t,
/**
* The destination path at which to create the symbolic link.
*/
new_path: string,
) -> errno_t ---
/**
* Unlink a file.
* Return `errno::isdir` if the path refers to a directory.
* Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
*/
path_unlink_file :: proc(
fd: fd_t,
/**
* The path to a file to unlink.
*/
path: string,
) -> errno_t ---
/**
* Write high-quality random data into a buffer.
* This function blocks when the implementation is unable to immediately
* provide sufficient high-quality random data.
* This function may execute slowly, so when large mounts of random data are
* required, it's advisable to use this function to seed a pseudo-random
* number generator, rather than to provide the random data directly.
*/
random_get :: proc(
/**
* The buffer to fill with random data.
*/
buf: []u8,
) -> errno_t ---
} }
/** /**
@@ -1250,7 +1400,7 @@ fd_pread :: proc "c" (
*/ */
offset: filesize_t, offset: filesize_t,
) -> (n: size_t, err: errno_t) { ) -> (n: size_t, err: errno_t) {
err = wasi_fd_pread(fd, raw_data(iovs), len(iovs), offset, &n) err = wasi_fd_pread(fd, iovs, offset, &n)
return return
} }
/** /**
@@ -1281,7 +1431,7 @@ fd_pwrite :: proc "c" (
*/ */
offset: filesize_t, offset: filesize_t,
) -> (n: size_t, err: errno_t) { ) -> (n: size_t, err: errno_t) {
err = wasi_fd_pwrite(fd, raw_data(iovs), len(iovs), offset, &n) err = wasi_fd_pwrite(fd, iovs, offset, &n)
return return
} }
/** /**
@@ -1297,7 +1447,7 @@ fd_read :: proc "c" (
*/ */
iovs: []iovec_t, iovs: []iovec_t,
) -> (n: size_t, err: errno_t) { ) -> (n: size_t, err: errno_t) {
err = wasi_fd_read(fd, raw_data(iovs), len(iovs), &n) err = wasi_fd_read(fd, iovs, &n)
return return
} }
/** /**
@@ -1324,7 +1474,7 @@ fd_readdir :: proc "c" (
*/ */
cookie: dircookie_t, cookie: dircookie_t,
) -> (n: size_t, err: errno_t) { ) -> (n: size_t, err: errno_t) {
err = wasi_fd_readdir(fd, raw_data(buf), len(buf), cookie, &n) err = wasi_fd_readdir(fd, buf, cookie, &n)
return return
} }
/** /**
@@ -1370,7 +1520,7 @@ fd_write :: proc "c" (
*/ */
iovs: []ciovec_t, iovs: []ciovec_t,
) -> (n: size_t, err: errno_t) { ) -> (n: size_t, err: errno_t) {
err = wasi_fd_write(fd, raw_data(iovs), len(iovs), &n) err = wasi_fd_write(fd, iovs, &n)
return return
} }
/** /**
@@ -1390,7 +1540,7 @@ path_filestat_get :: proc "c" (
*/ */
path: string, path: string,
) -> (offset: filestat_t, err: errno_t) { ) -> (offset: filestat_t, err: errno_t) {
err = wasi_path_filestat_get(fd, flags, raw_data(path), len(path), &offset) err = wasi_path_filestat_get(fd, flags, path, &offset)
return return
} }
/** /**
@@ -1432,7 +1582,7 @@ path_open :: proc "c" (
fs_rights_inheriting: rights_t, fs_rights_inheriting: rights_t,
fdflags: fdflags_t, fdflags: fdflags_t,
) -> (file: fd_t, err: errno_t) { ) -> (file: fd_t, err: errno_t) {
err = wasi_path_open(fd, dirflags, raw_data(path), len(path), oflags, fs_rights_base, fs_rights_inheriting, fdflags, &file) err = wasi_path_open(fd, dirflags, path, oflags, fs_rights_base, fs_rights_inheriting, fdflags, &file)
return return
} }
/** /**
@@ -1452,7 +1602,7 @@ path_readlink :: proc "c" (
*/ */
buf: []u8, buf: []u8,
) -> (n: size_t, err: errno_t) { ) -> (n: size_t, err: errno_t) {
err = wasi_path_readlink(fd, raw_data(path), len(path), raw_data(buf), len(buf), &n) err = wasi_path_readlink(fd, path, buf, &n)
return return
} }
/** /**
@@ -1495,7 +1645,7 @@ sock_recv :: proc "c" (
*/ */
ri_flags: riflags_t, ri_flags: riflags_t,
) -> (n: size_t, flags: roflags_t, err: errno_t) { ) -> (n: size_t, flags: roflags_t, err: errno_t) {
err = wasi_sock_recv(fd, raw_data(ri_data), len(ri_data), ri_flags, &n, &flags) err = wasi_sock_recv(fd, ri_data, ri_flags, &n, &flags)
return return
} }
/** /**
@@ -1516,172 +1666,11 @@ sock_send :: proc "c" (
*/ */
si_flags: siflags_t, si_flags: siflags_t,
) -> (n: size_t, err: errno_t) { ) -> (n: size_t, err: errno_t) {
err = wasi_sock_send(fd, raw_data(si_data), len(si_data), si_flags, &n) err = wasi_sock_send(fd, si_data, si_flags, &n)
return return
} }
/**
* Return a description of the given preopened file descriptor.
*/
fd_prestat_dir_name :: proc(
fd: fd_t,
/**
* A buffer into which to write the preopened directory name.
*/
path: string,
) -> errno_t {
return wasm_fd_prestat_dir_name(fd, raw_data(path), len(path))
}
/**
* Create a directory.
* Note: This is similar to `mkdirat` in POSIX.
*/
path_create_directory :: proc(
fd: fd_t,
/**
* The path at which to create the directory.
*/
path: string,
) -> errno_t {
return wasm_path_create_directory(fd, raw_data(path), len(path))
}
/**
* Adjust the timestamps of a file or directory.
* Note: This is similar to `utimensat` in POSIX.
*/
path_filestat_set_times :: proc(
fd: fd_t,
/**
* Flags determining the method of how the path is resolved.
*/
flags: lookupflags_t,
/**
* The path of the file or directory to operate on.
*/
path: string,
/**
* The desired values of the data access timestamp.
*/
atim: timestamp_t,
/**
* The desired values of the data modification timestamp.
*/
mtim: timestamp_t,
/**
* A bitmask indicating which timestamps to adjust.
*/
fst_flags: fstflags_t,
) -> errno_t {
return wasm_path_filestat_set_times(fd, flags, raw_data(path), len(path), atim, mtim, fst_flags)
}
/**
* Remove a directory.
* Return `errno::notempty` if the directory is not empty.
* Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX.
*/
path_remove_directory :: proc(
fd: fd_t,
/**
* The path to a directory to remove.
*/
path: string,
) -> errno_t {
return wasm_path_remove_directory(fd, raw_data(path), len(path))
}
/**
* Create a hard link.
* Note: This is similar to `linkat` in POSIX.
*/
path_link :: proc(
old_fd: fd_t,
/**
* Flags determining the method of how the path is resolved.
*/
old_flags: lookupflags_t,
/**
* The source path from which to link.
*/
old_path: string,
/**
* The working directory at which the resolution of the new path starts.
*/
new_fd: fd_t,
/**
* The destination path at which to create the hard link.
*/
new_path: string,
) -> errno_t {
return wasm_path_link(old_fd, old_flags, raw_data(old_path), len(old_path), new_fd, raw_data(new_path), len(new_path))
}
/**
* Rename a file or directory.
* Note: This is similar to `renameat` in POSIX.
*/
path_rename :: proc(
fd: fd_t,
/**
* The source path of the file or directory to rename.
*/
old_path: string,
/**
* The working directory at which the resolution of the new path starts.
*/
new_fd: fd_t,
/**
* The destination path to which to rename the file or directory.
*/
new_path: string,
) -> errno_t {
return wasm_path_rename(fd, raw_data(old_path), len(old_path), new_fd, raw_data(new_path), len(new_path))
}
/**
* Create a symbolic link.
* Note: This is similar to `symlinkat` in POSIX.
*/
path_symlink :: proc(
/**
* The contents of the symbolic link.
*/
old_path: string,
fd: fd_t,
/**
* The destination path at which to create the symbolic link.
*/
new_path: string,
) -> errno_t {
return wasm_path_symlink(raw_data(old_path), len(old_path), fd, raw_data(new_path), len(new_path))
}
/**
* Unlink a file.
* Return `errno::isdir` if the path refers to a directory.
* Note: This is similar to `unlinkat(fd, path, 0)` in POSIX.
*/
path_unlink_file :: proc(
fd: fd_t,
/**
* The path to a file to unlink.
*/
path: string,
) -> errno_t {
return wasm_path_unlink_file(fd, raw_data(path), len(path))
}
/**
* Write high-quality random data into a buffer.
* This function blocks when the implementation is unable to immediately
* provide sufficient high-quality random data.
* This function may execute slowly, so when large mounts of random data are
* required, it's advisable to use this function to seed a pseudo-random
* number generator, rather than to provide the random data directly.
*/
random_get :: proc(
/**
* The buffer to fill with random data.
*/
buf: []u8,
) -> errno_t {
return wasm_random_get(raw_data(buf), len(buf))
}
@@ -1722,8 +1711,7 @@ foreign wasi {
@(link_name="fd_pread") @(link_name="fd_pread")
wasi_fd_pread :: proc( wasi_fd_pread :: proc(
fd: fd_t, fd: fd_t,
iovs: [^]iovec_t, iovs: []iovec_t,
iovs_len: size_t,
offset: filesize_t, offset: filesize_t,
retptr0: ^size_t, retptr0: ^size_t,
) -> errno_t --- ) -> errno_t ---
@@ -1735,23 +1723,20 @@ foreign wasi {
@(link_name="fd_pwrite") @(link_name="fd_pwrite")
wasi_fd_pwrite :: proc( wasi_fd_pwrite :: proc(
fd: fd_t, fd: fd_t,
iovs: [^]ciovec_t, iovs: []ciovec_t,
iovs_len: size_t,
offset: filesize_t, offset: filesize_t,
retptr0: ^size_t, retptr0: ^size_t,
) -> errno_t --- ) -> errno_t ---
@(link_name="fd_read") @(link_name="fd_read")
wasi_fd_read :: proc( wasi_fd_read :: proc(
fd: fd_t, fd: fd_t,
iovs: [^]iovec_t, iovs: []iovec_t,
iovs_len: size_t,
retptr0: ^size_t, retptr0: ^size_t,
) -> errno_t --- ) -> errno_t ---
@(link_name="fd_readdir") @(link_name="fd_readdir")
wasi_fd_readdir :: proc( wasi_fd_readdir :: proc(
fd: fd_t, fd: fd_t,
buf: [^]u8, buf: []u8,
buf_len: size_t,
cookie: dircookie_t, cookie: dircookie_t,
retptr0: ^size_t, retptr0: ^size_t,
) -> errno_t --- ) -> errno_t ---
@@ -1770,8 +1755,7 @@ foreign wasi {
@(link_name="fd_write") @(link_name="fd_write")
wasi_fd_write :: proc( wasi_fd_write :: proc(
fd: fd_t, fd: fd_t,
iovs: [^]ciovec_t, iovs: []ciovec_t,
iovs_len: size_t,
retptr0: ^size_t, retptr0: ^size_t,
) -> errno_t --- ) -> errno_t ---
@(link_name="path_filestat_get") @(link_name="path_filestat_get")
@@ -1781,16 +1765,14 @@ foreign wasi {
/** /**
* The path of the file or directory to inspect. * The path of the file or directory to inspect.
*/ */
path: [^]u8, path: string,
path_len: size_t,
retptr0: ^filestat_t, retptr0: ^filestat_t,
) -> errno_t --- ) -> errno_t ---
@(link_name="path_open") @(link_name="path_open")
wasi_path_open :: proc( wasi_path_open :: proc(
fd: fd_t, fd: fd_t,
dirflags: lookupflags_t, dirflags: lookupflags_t,
path: [^]u8, path: string,
path_len: size_t,
oflags: oflags_t, oflags: oflags_t,
fs_rights_base: rights_t, fs_rights_base: rights_t,
fs_rights_inheriting: rights_t, fs_rights_inheriting: rights_t,
@@ -1800,10 +1782,8 @@ foreign wasi {
@(link_name="path_readlink") @(link_name="path_readlink")
wasi_path_readlink :: proc( wasi_path_readlink :: proc(
fd: fd_t, fd: fd_t,
path: [^]u8, path: string,
path_len: size_t, buf: []u8,
buf: [^]u8,
buf_len: size_t,
retptr0: ^size_t, retptr0: ^size_t,
) -> errno_t --- ) -> errno_t ---
@(link_name="poll_oneoff") @(link_name="poll_oneoff")
@@ -1816,8 +1796,7 @@ foreign wasi {
@(link_name="sock_recv") @(link_name="sock_recv")
wasi_sock_recv :: proc( wasi_sock_recv :: proc(
fd: fd_t, fd: fd_t,
ri_data: [^]iovec_t, ri_data: []iovec_t,
ri_data_len: size_t,
ri_flags: riflags_t, ri_flags: riflags_t,
retptr0: ^size_t, retptr0: ^size_t,
retptr1: ^roflags_t, retptr1: ^roflags_t,
@@ -1825,75 +1804,8 @@ foreign wasi {
@(link_name="sock_send") @(link_name="sock_send")
wasi_sock_send :: proc( wasi_sock_send :: proc(
fd: fd_t, fd: fd_t,
si_data: [^]ciovec_t, si_data: []ciovec_t,
si_data_len: size_t,
si_flags: siflags_t, si_flags: siflags_t,
retptr0: ^size_t, retptr0: ^size_t,
) -> errno_t --- ) -> errno_t ---
@(link_name="fd_prestat_dir_name")
wasm_fd_prestat_dir_name :: proc(
fd: fd_t,
path: [^]u8,
path_len: size_t,
) -> errno_t ---
@(link_name="path_create_directory")
wasm_path_create_directory :: proc(
fd: fd_t,
path: [^]u8,
path_len: size_t,
) -> errno_t ---
@(link_name="path_filestat_set_times")
wasm_path_filestat_set_times :: proc(
fd: fd_t,
flags: lookupflags_t,
path: [^]u8,
path_len: size_t,
atim: timestamp_t,
mtim: timestamp_t,
fst_flags: fstflags_t,
) -> errno_t ---
@(link_name="path_remove_directory")
wasm_path_remove_directory :: proc(
fd: fd_t,
path: [^]u8,
path_len: size_t,
) -> errno_t ---
@(link_name="path_link")
wasm_path_link :: proc(
old_fd: fd_t,
old_flags: lookupflags_t,
old_path: [^]u8,
old_path_len: size_t,
new_fd: fd_t,
new_path: [^]u8,
new_path_len: size_t,
) -> errno_t ---
@(link_name="path_rename")
wasm_path_rename :: proc(
fd: fd_t,
old_path: [^]u8,
old_path_len: size_t,
new_fd: fd_t,
new_path: [^]u8,
new_path_len: size_t,
) -> errno_t ---
@(link_name="path_symlink")
wasm_path_symlink :: proc(
old_path: [^]u8,
old_path_len: size_t,
fd: fd_t,
new_path: [^]u8,
new_path_len: size_t,
) -> errno_t ---
@(link_name="path_unlink_file")
wasm_path_unlink_file :: proc(
fd: fd_t,
path: [^]u8,
path_len: size_t,
) -> errno_t ---
@(link_name="random_get")
wasm_random_get :: proc(
buf: [^]u8,
buf_len: size_t,
) -> errno_t ---
} }
+1
View File
@@ -18,6 +18,7 @@ foreign user32 {
RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM --- RegisterClassW :: proc(lpWndClass: ^WNDCLASSW) -> ATOM ---
RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM --- RegisterClassExW :: proc(^WNDCLASSEXW) -> ATOM ---
UnregisterClassW :: proc(lpClassName: LPCWSTR, hInstance: HINSTANCE) -> BOOL ---
CreateWindowExW :: proc( CreateWindowExW :: proc(
dwExStyle: DWORD, dwExStyle: DWORD,
+4
View File
@@ -22,6 +22,10 @@ GET_Y_LPARAM :: #force_inline proc "contextless" (lp: LPARAM) -> c_int {
return cast(c_int)cast(c_short)HIWORD(cast(DWORD)lp) return cast(c_int)cast(c_short)HIWORD(cast(DWORD)lp)
} }
MAKE_WORD :: #force_inline proc "contextless" (x, y: WORD) -> WORD {
return x << 8 | y
}
utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 { utf8_to_utf16 :: proc(s: string, allocator := context.temp_allocator) -> []u16 {
if len(s) < 1 { if len(s) < 1 {
return nil return nil
+1 -1
View File
@@ -45,4 +45,4 @@ ERROR_NOT_SAME_OBJECT : DWORD : 1656
E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001 E_NOTIMPL :: HRESULT(-0x7fff_bfff) // 0x8000_4001
SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool do return result >= 0 SUCCEEDED :: #force_inline proc(#any_int result: int) -> bool { return result >= 0 }
+2 -2
View File
@@ -99,14 +99,14 @@ parse_mo_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTIONS, plur
} }
for k in keys { for k in keys {
interned_key := strings.intern_get(&translation.intern, string(k)) interned_key, _ := strings.intern_get(&translation.intern, string(k))
interned_vals := make([]string, len(keys)) interned_vals := make([]string, len(keys))
last_val: string last_val: string
i := 0 i := 0
for v in vals { for v in vals {
interned_vals[i] = strings.intern_get(&translation.intern, string(v)) interned_vals[i], _ = strings.intern_get(&translation.intern, string(v))
last_val = interned_vals[i] last_val = interned_vals[i]
i += 1 i += 1
} }
+5 -5
View File
@@ -59,9 +59,9 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
return translation, .TS_File_Expected_Context_Name, return translation, .TS_File_Expected_Context_Name,
} }
section_name := strings.intern_get(&translation.intern, "") section_name, _ := strings.intern_get(&translation.intern, "")
if !options.merge_sections { if !options.merge_sections {
section_name = strings.intern_get(&translation.intern, ts.elements[section_name_id].value) section_name, _ = strings.intern_get(&translation.intern, ts.elements[section_name_id].value)
} }
if section_name not_in translation.k_v { if section_name not_in translation.k_v {
@@ -92,8 +92,8 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
return translation, .TS_File_Expected_Translation return translation, .TS_File_Expected_Translation
} }
source := strings.intern_get(&translation.intern, ts.elements[source_id].value) source, _ := strings.intern_get(&translation.intern, ts.elements[source_id].value)
xlat := strings.intern_get(&translation.intern, ts.elements[translation_id].value) xlat, _ := strings.intern_get(&translation.intern, ts.elements[translation_id].value)
if source in section { if source in section {
return translation, .Duplicate_Key return translation, .Duplicate_Key
@@ -124,7 +124,7 @@ parse_qt_linguist_from_bytes :: proc(data: []byte, options := DEFAULT_PARSE_OPTI
if !numerus_found { if !numerus_found {
break break
} }
numerus := strings.intern_get(&translation.intern, ts.elements[numerus_id].value) numerus, _ := strings.intern_get(&translation.intern, ts.elements[numerus_id].value)
section[source][num_plurals] = numerus section[source][num_plurals] = numerus
num_plurals += 1 num_plurals += 1
@@ -45,7 +45,7 @@ generate_encoding_entity_table :: proc() {
printf("\"%v\" loaded and parsed.\n", filename) printf("\"%v\" loaded and parsed.\n", filename)
generated_buf: strings.Builder generated_buf: strings.Builder
defer strings.destroy_builder(&generated_buf) defer strings.builder_destroy(&generated_buf)
w := strings.to_writer(&generated_buf) w := strings.to_writer(&generated_buf)
charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist") charlist, charlist_ok := xml.find_child_by_ident(doc.root, "charlist")
+6 -4
View File
@@ -204,7 +204,7 @@ enum BuildPath : u8 {
BuildPath_Main_Package, // Input Path to the package directory (or file) we're building. BuildPath_Main_Package, // Input Path to the package directory (or file) we're building.
BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`. BuildPath_RC, // Input Path for .rc file, can be set with `-resource:`.
BuildPath_RES, // Output Path for .res file, generated from previous. BuildPath_RES, // Output Path for .res file, generated from previous.
BuildPath_Win_SDK_Root, // windows_sdk_root BuildPath_Win_SDK_Bin_Path, // windows_sdk_bin_path
BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path BuildPath_Win_SDK_UM_Lib, // windows_sdk_um_library_path
BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path BuildPath_Win_SDK_UCRT_Lib, // windows_sdk_ucrt_library_path
BuildPath_VS_EXE, // vs_exe_path BuildPath_VS_EXE, // vs_exe_path
@@ -1322,6 +1322,7 @@ bool init_build_paths(String init_filename) {
} }
#if defined(GB_SYSTEM_WINDOWS) #if defined(GB_SYSTEM_WINDOWS)
if (bc->metrics.os == TargetOs_windows) {
if (bc->resource_filepath.len > 0) { if (bc->resource_filepath.len > 0) {
bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath); bc->build_paths[BuildPath_RC] = path_from_string(ha, bc->resource_filepath);
bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath); bc->build_paths[BuildPath_RES] = path_from_string(ha, bc->resource_filepath);
@@ -1335,7 +1336,7 @@ bool init_build_paths(String init_filename) {
if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) { if ((bc->command_kind & Command__does_build) && (!bc->ignore_microsoft_magic)) {
// NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest. // NOTE(ic): It would be nice to extend this so that we could specify the Visual Studio version that we want instead of defaulting to the latest.
Find_Result_Utf8 find_result = find_visual_studio_and_windows_sdk_utf8(); Find_Result find_result = find_visual_studio_and_windows_sdk();
defer (mc_free_all()); defer (mc_free_all());
if (find_result.windows_sdk_version == 0) { if (find_result.windows_sdk_version == 0) {
@@ -1356,8 +1357,8 @@ bool init_build_paths(String init_filename) {
if (find_result.windows_sdk_um_library_path.len > 0) { if (find_result.windows_sdk_um_library_path.len > 0) {
GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0); GB_ASSERT(find_result.windows_sdk_ucrt_library_path.len > 0);
if (find_result.windows_sdk_root.len > 0) { if (find_result.windows_sdk_bin_path.len > 0) {
bc->build_paths[BuildPath_Win_SDK_Root] = path_from_string(ha, find_result.windows_sdk_root); bc->build_paths[BuildPath_Win_SDK_Bin_Path] = path_from_string(ha, find_result.windows_sdk_bin_path);
} }
if (find_result.windows_sdk_um_library_path.len > 0) { if (find_result.windows_sdk_um_library_path.len > 0) {
@@ -1377,6 +1378,7 @@ bool init_build_paths(String init_filename) {
} }
} }
} }
}
#endif #endif
// All the build targets and OSes. // All the build targets and OSes.
+1
View File
@@ -3569,6 +3569,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
operand->mode = Addressing_NoValue; operand->mode = Addressing_NoValue;
break; break;
case BuiltinProc_unreachable:
case BuiltinProc_trap: case BuiltinProc_trap:
case BuiltinProc_debug_trap: case BuiltinProc_debug_trap:
operand->mode = Addressing_NoValue; operand->mode = Addressing_NoValue;
+1 -1
View File
@@ -320,7 +320,7 @@ void check_type_decl(CheckerContext *ctx, Entity *e, Ast *init_expr, Type *def)
} else if (is_type_any(e->type)) { } else if (is_type_any(e->type)) {
error(init_expr, "'distinct' cannot be applied to 'any'"); error(init_expr, "'distinct' cannot be applied to 'any'");
is_distinct = false; is_distinct = false;
} else if (is_type_simd_vector(e->type)) { } else if (is_type_simd_vector(e->type) || is_type_soa_pointer(e->type)) {
gbString str = type_to_string(e->type); gbString str = type_to_string(e->type);
error(init_expr, "'distinct' cannot be applied to '%s'", str); error(init_expr, "'distinct' cannot be applied to '%s'", str);
gb_string_free(str); gb_string_free(str);
+87 -29
View File
@@ -119,6 +119,7 @@ void check_or_else_split_types(CheckerContext *c, Operand *x, String const &name
void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint); void check_or_else_expr_no_value_error(CheckerContext *c, String const &name, Operand const &x, Type *type_hint);
void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_); void check_or_return_split_types(CheckerContext *c, Operand *x, String const &name, Type **left_type_, Type **right_type_);
bool is_diverging_expr(Ast *expr);
void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") { void check_did_you_mean_print(DidYouMeanAnswers *d, char const *prefix = "") {
auto results = did_you_mean_results(d); auto results = did_you_mean_results(d);
@@ -2051,7 +2052,7 @@ bool check_is_not_addressable(CheckerContext *c, Operand *o) {
return false; return false;
} }
return o->mode != Addressing_Variable; return o->mode != Addressing_Variable && o->mode != Addressing_SoaVariable;
} }
void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) { void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
@@ -2068,9 +2069,6 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str); error(op, "Cannot take the pointer address of '%s' which is a procedure parameter", str);
} else { } else {
switch (o->mode) { switch (o->mode) {
case Addressing_SoaVariable:
error(op, "Cannot take the pointer address of '%s' as it is an indirect index of an SOA struct", str);
break;
case Addressing_Constant: case Addressing_Constant:
error(op, "Cannot take the pointer address of '%s' which is a constant", str); error(op, "Cannot take the pointer address of '%s' which is a constant", str);
break; break;
@@ -2098,7 +2096,19 @@ void check_unary_expr(CheckerContext *c, Operand *o, Token op, Ast *node) {
return; return;
} }
o->type = alloc_type_pointer(o->type); if (o->mode == Addressing_SoaVariable) {
ast_node(ue, UnaryExpr, node);
if (ast_node_expect(ue->expr, Ast_IndexExpr)) {
ast_node(ie, IndexExpr, ue->expr);
Type *soa_type = type_of_expr(ie->expr);
GB_ASSERT(is_type_soa_struct(soa_type));
o->type = alloc_type_soa_pointer(soa_type);
} else {
o->type = alloc_type_pointer(o->type);
}
} else {
o->type = alloc_type_pointer(o->type);
}
switch (o->mode) { switch (o->mode) {
case Addressing_OptionalOk: case Addressing_OptionalOk:
@@ -2495,8 +2505,17 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
x->expr->tav.is_lhs = true; x->expr->tav.is_lhs = true;
} }
x->mode = Addressing_Value; x->mode = Addressing_Value;
if (type_hint && is_type_integer(type_hint)) { if (type_hint) {
x->type = type_hint; if (is_type_integer(type_hint)) {
x->type = type_hint;
} else {
gbString x_str = expr_to_string(x->expr);
gbString to_type = type_to_string(type_hint);
error(node, "Conversion of shifted operand '%s' to '%s' is not allowed", x_str, to_type);
gb_string_free(x_str);
gb_string_free(to_type);
x->mode = Addressing_Invalid;
}
} }
// x->value = x_val; // x->value = x_val;
return; return;
@@ -2512,7 +2531,7 @@ void check_shift(CheckerContext *c, Operand *x, Operand *y, Ast *node, Type *typ
// TODO(bill): Should we support shifts for fixed arrays and #simd vectors? // TODO(bill): Should we support shifts for fixed arrays and #simd vectors?
if (!is_type_integer(x->type)) { if (!is_type_integer(x->type)) {
gbString err_str = expr_to_string(y->expr); gbString err_str = expr_to_string(x->expr);
error(node, "Shift operand '%s' must be an integer", err_str); error(node, "Shift operand '%s' must be an integer", err_str);
gb_string_free(err_str); gb_string_free(err_str);
x->mode = Addressing_Invalid; x->mode = Addressing_Invalid;
@@ -2959,7 +2978,14 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand
goto matrix_error; goto matrix_error;
} }
x->mode = Addressing_Value; x->mode = Addressing_Value;
x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count); if (are_types_identical(xt, yt)) {
if (!is_type_named(x->type) && is_type_named(y->type)) {
// prefer the named type
x->type = y->type;
}
} else {
x->type = alloc_type_matrix(xt->Matrix.elem, xt->Matrix.row_count, yt->Matrix.column_count);
}
goto matrix_success; goto matrix_success;
} else if (yt->kind == Type_Array) { } else if (yt->kind == Type_Array) {
if (!are_types_identical(xt->Matrix.elem, yt->Array.elem)) { if (!are_types_identical(xt->Matrix.elem, yt->Array.elem)) {
@@ -3021,7 +3047,6 @@ void check_binary_matrix(CheckerContext *c, Token const &op, Operand *x, Operand
matrix_success: matrix_success:
x->type = check_matrix_type_hint(x->type, type_hint); x->type = check_matrix_type_hint(x->type, type_hint);
return; return;
@@ -7393,8 +7418,25 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
return Expr_Expr; return Expr_Expr;
} }
check_multi_expr_with_type_hint(c, &y, default_value, x.type); bool y_is_diverging = false;
error_operand_no_value(&y); check_expr_base(c, &y, default_value, x.type);
switch (y.mode) {
case Addressing_NoValue:
if (is_diverging_expr(y.expr)) {
// Allow
y.mode = Addressing_Value;
y_is_diverging = true;
} else {
error_operand_no_value(&y);
y.mode = Addressing_Invalid;
}
break;
case Addressing_Type:
error_operand_not_expression(&y);
y.mode = Addressing_Invalid;
break;
}
if (y.mode == Addressing_Invalid) { if (y.mode == Addressing_Invalid) {
o->mode = Addressing_Value; o->mode = Addressing_Value;
o->type = t_invalid; o->type = t_invalid;
@@ -7408,7 +7450,9 @@ ExprKind check_or_else_expr(CheckerContext *c, Operand *o, Ast *node, Type *type
add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value); add_type_and_value(&c->checker->info, arg, x.mode, x.type, x.value);
if (left_type != nullptr) { if (left_type != nullptr) {
check_assignment(c, &y, left_type, name); if (!y_is_diverging) {
check_assignment(c, &y, left_type, name);
}
} else { } else {
check_or_else_expr_no_value_error(c, name, x, type_hint); check_or_else_expr_no_value_error(c, name, x, type_hint);
} }
@@ -8404,23 +8448,30 @@ ExprKind check_compound_literal(CheckerContext *c, Operand *o, Ast *node, Type *
if (is_type_bit_set(type)) { if (is_type_bit_set(type)) {
// NOTE(bill): Encode as an integer // NOTE(bill): Encode as an integer
i64 lower = base_type(type)->BitSet.lower; Type *bt = base_type(type);
BigInt bits = {};
BigInt one = {};
big_int_from_u64(&one, 1);
u64 bits = 0; for_array(i, cl->elems) {
for_array(index, cl->elems) { Ast *e = cl->elems[i];
Ast *elem = cl->elems[index]; GB_ASSERT(e->kind != Ast_FieldValue);
GB_ASSERT(elem->kind != Ast_FieldValue);
TypeAndValue tav = elem->tav; TypeAndValue tav = e->tav;
ExactValue i = exact_value_to_integer(tav.value); if (tav.mode != Addressing_Constant) {
if (i.kind != ExactValue_Integer) {
continue; continue;
} }
i64 val = big_int_to_i64(&i.value_integer); GB_ASSERT(tav.value.kind == ExactValue_Integer);
val -= lower; i64 v = big_int_to_i64(&tav.value.value_integer);
u64 bit = u64(1ll<<val); i64 lower = bt->BitSet.lower;
bits |= bit; u64 index = cast(u64)(v-lower);
BigInt bit = {};
big_int_from_u64(&bit, index);
big_int_shl(&bit, &one, &bit);
big_int_or(&bits, &bits, &bit);
} }
o->value = exact_value_u64(bits); o->value.kind = ExactValue_Integer;
o->value.value_integer = bits;
} else if (is_type_constant_type(type) && cl->elems.count == 0) { } else if (is_type_constant_type(type) && cl->elems.count == 0) {
ExactValue value = exact_value_compound(node); ExactValue value = exact_value_compound(node);
Type *bt = core_type(type); Type *bt = core_type(type);
@@ -8643,6 +8694,8 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type
Ast *first_arg = x.expr->SelectorExpr.expr; Ast *first_arg = x.expr->SelectorExpr.expr;
GB_ASSERT(first_arg != nullptr); GB_ASSERT(first_arg != nullptr);
first_arg->state_flags |= StateFlag_SelectorCallExpr;
Type *pt = base_type(x.type); Type *pt = base_type(x.type);
GB_ASSERT(pt->kind == Type_Proc); GB_ASSERT(pt->kind == Type_Proc);
Type *first_type = nullptr; Type *first_type = nullptr;
@@ -8668,6 +8721,7 @@ ExprKind check_selector_call_expr(CheckerContext *c, Operand *o, Ast *node, Type
y.mode = first_arg->tav.mode; y.mode = first_arg->tav.mode;
y.type = first_arg->tav.type; y.type = first_arg->tav.type;
y.value = first_arg->tav.value; y.value = first_arg->tav.value;
if (check_is_assignable_to(c, &y, first_type)) { if (check_is_assignable_to(c, &y, first_type)) {
// Do nothing, it's valid // Do nothing, it's valid
} else { } else {
@@ -9286,7 +9340,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
check_unary_expr(c, o, ue->op, node); check_unary_expr(c, o, ue->op, node);
} }
o->expr = node; o->expr = node;
return kind; return Expr_Expr;
case_end; case_end;
@@ -9342,6 +9396,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) { if (t->kind == Type_Pointer && !is_type_empty_union(t->Pointer.elem)) {
o->mode = Addressing_Variable; o->mode = Addressing_Variable;
o->type = t->Pointer.elem; o->type = t->Pointer.elem;
} else if (t->kind == Type_SoaPointer) {
o->mode = Addressing_SoaVariable;
o->type = type_deref(t);
} else if (t->kind == Type_RelativePointer) { } else if (t->kind == Type_RelativePointer) {
if (o->mode != Addressing_Variable) { if (o->mode != Addressing_Variable) {
gbString str = expr_to_string(o->expr); gbString str = expr_to_string(o->expr);
@@ -10034,9 +10091,10 @@ gbString write_expr_to_string(gbString str, Ast *node, bool shorthand) {
str = write_expr_to_string(str, ce->proc, shorthand); str = write_expr_to_string(str, ce->proc, shorthand);
str = gb_string_appendc(str, "("); str = gb_string_appendc(str, "(");
for_array(i, ce->args) { isize idx0 = cast(isize)ce->was_selector;
for (isize i = idx0; i < ce->args.count; i++) {
Ast *arg = ce->args[i]; Ast *arg = ce->args[i];
if (i > 0) { if (i > idx0) {
str = gb_string_appendc(str, ", "); str = gb_string_appendc(str, ", ");
} }
str = write_expr_to_string(str, arg, shorthand); str = write_expr_to_string(str, arg, shorthand);
+8 -5
View File
@@ -1,8 +1,5 @@
bool is_diverging_stmt(Ast *stmt) { bool is_diverging_expr(Ast *expr) {
if (stmt->kind != Ast_ExprStmt) { expr = unparen_expr(expr);
return false;
}
Ast *expr = unparen_expr(stmt->ExprStmt.expr);
if (expr->kind != Ast_CallExpr) { if (expr->kind != Ast_CallExpr) {
return false; return false;
} }
@@ -26,6 +23,12 @@ bool is_diverging_stmt(Ast *stmt) {
t = base_type(t); t = base_type(t);
return t != nullptr && t->kind == Type_Proc && t->Proc.diverging; return t != nullptr && t->kind == Type_Proc && t->Proc.diverging;
} }
bool is_diverging_stmt(Ast *stmt) {
if (stmt->kind != Ast_ExprStmt) {
return false;
}
return is_diverging_expr(stmt->ExprStmt.expr);
}
bool contains_deferred_call(Ast *node) { bool contains_deferred_call(Ast *node) {
if (node->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) { if (node->viral_state_flags & ViralStateFlag_ContainsDeferredProcedure) {
+67 -11
View File
@@ -695,11 +695,6 @@ void check_union_type(CheckerContext *ctx, Type *union_type, Ast *node, Array<Op
error(ut->align, "A union with #no_nil must have at least 2 variants"); error(ut->align, "A union with #no_nil must have at least 2 variants");
} }
break; break;
case UnionType_maybe:
if (variants.count != 1) {
error(ut->align, "A union with #maybe must have at 1 variant, got %lld", cast(long long)variants.count);
}
break;
} }
if (ut->align != nullptr) { if (ut->align != nullptr) {
@@ -1345,7 +1340,9 @@ ParameterValue handle_parameter_value(CheckerContext *ctx, Type *in_type, Type *
param_value.kind = ParameterValue_Constant; param_value.kind = ParameterValue_Constant;
param_value.value = o.value; param_value.value = o.value;
} else { } else {
error(expr, "Default parameter must be a constant, %d", o.mode); gbString s = expr_to_string(o.expr);
error(expr, "Default parameter must be a constant, got %s", s);
gb_string_free(s);
} }
} }
} else { } else {
@@ -1614,6 +1611,10 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
error(name, "'#any_int' can only be applied to variable fields"); error(name, "'#any_int' can only be applied to variable fields");
p->flags &= ~FieldFlag_any_int; p->flags &= ~FieldFlag_any_int;
} }
if (p->flags&FieldFlag_by_ptr) {
error(name, "'#by_ptr' can only be applied to variable fields");
p->flags &= ~FieldFlag_by_ptr;
}
param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved); param = alloc_entity_type_name(scope, name->Ident.token, type, EntityState_Resolved);
param->TypeName.is_type_alias = true; param->TypeName.is_type_alias = true;
@@ -1690,10 +1691,17 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
if (p->flags&FieldFlag_no_alias) { if (p->flags&FieldFlag_no_alias) {
if (!is_type_pointer(type)) { if (!is_type_pointer(type)) {
error(name, "'#no_alias' can only be applied to fields of pointer type"); error(name, "'#no_alias' can only be applied pointer typed parameters");
p->flags &= ~FieldFlag_no_alias; // Remove the flag p->flags &= ~FieldFlag_no_alias; // Remove the flag
} }
} }
if (p->flags&FieldFlag_by_ptr) {
if (is_type_internally_pointer_like(type)) {
error(name, "'#by_ptr' can only be applied to non-pointer-like parameters");
p->flags &= ~FieldFlag_by_ptr; // Remove the flag
}
}
if (is_poly_name) { if (is_poly_name) {
if (p->flags&FieldFlag_no_alias) { if (p->flags&FieldFlag_no_alias) {
error(name, "'#no_alias' can only be applied to non constant values"); error(name, "'#no_alias' can only be applied to non constant values");
@@ -1711,6 +1719,10 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
error(name, "'#const' can only be applied to variable fields"); error(name, "'#const' can only be applied to variable fields");
p->flags &= ~FieldFlag_const; p->flags &= ~FieldFlag_const;
} }
if (p->flags&FieldFlag_by_ptr) {
error(name, "'#by_ptr' can only be applied to variable fields");
p->flags &= ~FieldFlag_by_ptr;
}
if (!is_type_constant_type(type) && !is_type_polymorphic(type)) { if (!is_type_constant_type(type) && !is_type_polymorphic(type)) {
gbString str = type_to_string(type); gbString str = type_to_string(type);
@@ -1743,6 +1755,9 @@ Type *check_get_params(CheckerContext *ctx, Scope *scope, Ast *_params, bool *is
if (p->flags&FieldFlag_const) { if (p->flags&FieldFlag_const) {
param->flags |= EntityFlag_ConstInput; param->flags |= EntityFlag_ConstInput;
} }
if (p->flags&FieldFlag_by_ptr) {
param->flags |= EntityFlag_ByPtr;
}
param->state = EntityState_Resolved; // NOTE(bill): This should have be resolved whilst determining it param->state = EntityState_Resolved; // NOTE(bill): This should have be resolved whilst determining it
add_entity(ctx, scope, name, param); add_entity(ctx, scope, name, param);
@@ -2678,14 +2693,55 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
case_ast_node(ue, UnaryExpr, e); case_ast_node(ue, UnaryExpr, e);
switch (ue->op.kind) { switch (ue->op.kind) {
case Token_Pointer: case Token_Pointer:
*type = alloc_type_pointer(check_type(ctx, ue->expr)); {
set_base_type(named_type, *type); Type *elem = check_type(ctx, ue->expr);
return true; *type = alloc_type_pointer(elem);
set_base_type(named_type, *type);
return true;
}
} }
case_end; case_end;
case_ast_node(pt, PointerType, e); case_ast_node(pt, PointerType, e);
*type = alloc_type_pointer(check_type(ctx, pt->type)); CheckerContext c = *ctx;
c.type_path = new_checker_type_path();
defer (destroy_checker_type_path(c.type_path));
Type *elem = t_invalid;
Operand o = {};
check_expr_or_type(&c, &o, pt->type);
if (o.mode != Addressing_Invalid && o.mode != Addressing_Type) {
// NOTE(bill): call check_type_expr again to get a consistent error message
begin_error_block();
elem = check_type_expr(&c, pt->type, nullptr);
if (o.mode == Addressing_Variable) {
gbString s = expr_to_string(pt->type);
error_line("\tSuggestion: ^ is used for pointer types, did you mean '&%s'?\n", s);
gb_string_free(s);
}
end_error_block();
} else {
elem = o.type;
}
if (pt->tag != nullptr) {
GB_ASSERT(pt->tag->kind == Ast_BasicDirective);
String name = pt->tag->BasicDirective.name.string;
if (name == "soa") {
// TODO(bill): generic #soa pointers
if (is_type_soa_struct(elem)) {
*type = alloc_type_soa_pointer(elem);
} else {
error(pt->tag, "#soa pointers require an #soa record type as the element");
*type = alloc_type_pointer(elem);
}
} else {
error(pt->tag, "Invalid tag applied to pointer, got #%.*s", LIT(name));
*type = alloc_type_pointer(elem);
}
} else {
*type = alloc_type_pointer(elem);
}
set_base_type(named_type, *type); set_base_type(named_type, *type);
return true; return true;
case_end; case_end;
+11
View File
@@ -1947,6 +1947,11 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
add_type_info_type_internal(c, bt->Matrix.elem); add_type_info_type_internal(c, bt->Matrix.elem);
break; break;
case Type_SoaPointer:
add_type_info_type_internal(c, bt->SoaPointer.elem);
break;
default: default:
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind); GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
break; break;
@@ -2164,6 +2169,10 @@ void add_min_dep_type_info(Checker *c, Type *t) {
add_min_dep_type_info(c, bt->Matrix.elem); add_min_dep_type_info(c, bt->Matrix.elem);
break; break;
case Type_SoaPointer:
add_min_dep_type_info(c, bt->SoaPointer.elem);
break;
default: default:
GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind])); GB_PANIC("Unhandled type: %*.s", LIT(type_strings[bt->kind]));
break; break;
@@ -2756,6 +2765,7 @@ void init_core_type_info(Checker *c) {
t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer")); t_type_info_relative_pointer = find_core_type(c, str_lit("Type_Info_Relative_Pointer"));
t_type_info_relative_slice = find_core_type(c, str_lit("Type_Info_Relative_Slice")); t_type_info_relative_slice = find_core_type(c, str_lit("Type_Info_Relative_Slice"));
t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix")); t_type_info_matrix = find_core_type(c, str_lit("Type_Info_Matrix"));
t_type_info_soa_pointer = find_core_type(c, str_lit("Type_Info_Soa_Pointer"));
t_type_info_named_ptr = alloc_type_pointer(t_type_info_named); t_type_info_named_ptr = alloc_type_pointer(t_type_info_named);
t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer); t_type_info_integer_ptr = alloc_type_pointer(t_type_info_integer);
@@ -2784,6 +2794,7 @@ void init_core_type_info(Checker *c) {
t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer); t_type_info_relative_pointer_ptr = alloc_type_pointer(t_type_info_relative_pointer);
t_type_info_relative_slice_ptr = alloc_type_pointer(t_type_info_relative_slice); t_type_info_relative_slice_ptr = alloc_type_pointer(t_type_info_relative_slice);
t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix); t_type_info_matrix_ptr = alloc_type_pointer(t_type_info_matrix);
t_type_info_soa_pointer_ptr = alloc_type_pointer(t_type_info_soa_pointer);
} }
void init_mem_allocator(Checker *c) { void init_mem_allocator(Checker *c) {
+6 -2
View File
@@ -40,6 +40,8 @@ enum BuiltinProcId {
BuiltinProc_hadamard_product, BuiltinProc_hadamard_product,
BuiltinProc_matrix_flatten, BuiltinProc_matrix_flatten,
BuiltinProc_unreachable,
BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures BuiltinProc_DIRECTIVE, // NOTE(bill): This is used for specialized hash-prefixed procedures
// "Intrinsics" // "Intrinsics"
@@ -330,6 +332,8 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("hadamard_product"), 2, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("matrix_flatten"), 1, false, Expr_Expr, BuiltinProcPkg_builtin}, {STR_LIT("matrix_flatten"), 1, false, Expr_Expr, BuiltinProcPkg_builtin},
{STR_LIT("unreachable"), 0, false, Expr_Expr, BuiltinProcPkg_builtin, /*diverging*/true},
{STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE {STR_LIT(""), 0, true, Expr_Expr, BuiltinProcPkg_builtin}, // DIRECTIVE
@@ -341,7 +345,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("alloca"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("alloca"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("cpu_relax"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics}, {STR_LIT("cpu_relax"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics},
{STR_LIT("trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/true}, {STR_LIT("trap"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics, /*diverging*/true},
{STR_LIT("debug_trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/false}, {STR_LIT("debug_trap"), 0, false, Expr_Stmt, BuiltinProcPkg_intrinsics, /*diverging*/false},
{STR_LIT("read_cycle_counter"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("read_cycle_counter"), 0, false, Expr_Expr, BuiltinProcPkg_intrinsics},
@@ -434,7 +438,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_COUNT] = {
{STR_LIT("simd_neg"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_neg"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_abs"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_abs"), 1, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_min"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_min"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
{STR_LIT("simd_max"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics}, {STR_LIT("simd_max"), 2, false, Expr_Expr, BuiltinProcPkg_intrinsics},
+1 -1
View File
@@ -83,6 +83,7 @@ enum OdinDocTypeKind : u32 {
OdinDocType_RelativeSlice = 21, OdinDocType_RelativeSlice = 21,
OdinDocType_MultiPointer = 22, OdinDocType_MultiPointer = 22,
OdinDocType_Matrix = 23, OdinDocType_Matrix = 23,
OdinDocType_SoaPointer = 24,
}; };
enum OdinDocTypeFlag_Basic : u32 { enum OdinDocTypeFlag_Basic : u32 {
@@ -98,7 +99,6 @@ enum OdinDocTypeFlag_Struct : u32 {
enum OdinDocTypeFlag_Union : u32 { enum OdinDocTypeFlag_Union : u32 {
OdinDocTypeFlag_Union_polymorphic = 1<<0, OdinDocTypeFlag_Union_polymorphic = 1<<0,
OdinDocTypeFlag_Union_no_nil = 1<<1, OdinDocTypeFlag_Union_no_nil = 1<<1,
OdinDocTypeFlag_Union_maybe = 1<<2,
OdinDocTypeFlag_Union_shared_nil = 1<<3, OdinDocTypeFlag_Union_shared_nil = 1<<3,
}; };
+4
View File
@@ -532,6 +532,10 @@ OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type) {
doc_type.kind = OdinDocType_MultiPointer; doc_type.kind = OdinDocType_MultiPointer;
doc_type.types = odin_doc_type_as_slice(w, type->MultiPointer.elem); doc_type.types = odin_doc_type_as_slice(w, type->MultiPointer.elem);
break; break;
case Type_SoaPointer:
doc_type.kind = OdinDocType_SoaPointer;
doc_type.types = odin_doc_type_as_slice(w, type->SoaPointer.elem);
break;
case Type_Array: case Type_Array:
doc_type.kind = OdinDocType_Array; doc_type.kind = OdinDocType_Array;
doc_type.elem_count_len = 1; doc_type.elem_count_len = 1;
+1
View File
@@ -83,6 +83,7 @@ enum EntityFlag : u64 {
EntityFlag_CustomLinkage_LinkOnce = 1ull<<44, EntityFlag_CustomLinkage_LinkOnce = 1ull<<44,
EntityFlag_Require = 1ull<<50, EntityFlag_Require = 1ull<<50,
EntityFlag_ByPtr = 1ull<<51, // enforce parameter is passed by pointer
EntityFlag_Overridden = 1ull<<63, EntityFlag_Overridden = 1ull<<63,
}; };
+4
View File
@@ -90,6 +90,10 @@ extern "C" {
#error This operating system is not supported #error This operating system is not supported
#endif #endif
#if defined(GB_SYSTEM_OPENBSD)
#include <sys/wait.h>
#endif
#if defined(_MSC_VER) #if defined(_MSC_VER)
#define GB_COMPILER_MSVC 1 #define GB_COMPILER_MSVC 1
#elif defined(__GNUC__) #elif defined(__GNUC__)
+30 -17
View File
@@ -62,7 +62,7 @@ bool lb_is_type_kind(LLVMTypeRef type, LLVMTypeKind kind) {
return LLVMGetTypeKind(type) == kind; return LLVMGetTypeKind(type) == kind;
} }
LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) { LLVMTypeRef lb_function_type_to_llvm_raw(lbFunctionType *ft, bool is_var_arg) {
unsigned arg_count = cast(unsigned)ft->args.count; unsigned arg_count = cast(unsigned)ft->args.count;
unsigned offset = 0; unsigned offset = 0;
@@ -108,10 +108,16 @@ LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
} }
unsigned total_arg_count = arg_index; unsigned total_arg_count = arg_index;
LLVMTypeRef func_type = LLVMFunctionType(ret, args, total_arg_count, is_var_arg); LLVMTypeRef func_type = LLVMFunctionType(ret, args, total_arg_count, is_var_arg);
return LLVMPointerType(func_type, 0); return func_type;
} }
// LLVMTypeRef lb_function_type_to_llvm_ptr(lbFunctionType *ft, bool is_var_arg) {
// LLVMTypeRef func_type = lb_function_type_to_llvm_raw(ft, is_var_arg);
// return LLVMPointerType(func_type, 0);
// }
void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) { void lb_add_function_type_attributes(LLVMValueRef fn, lbFunctionType *ft, ProcCallingConvention calling_convention) {
if (ft == nullptr) { if (ft == nullptr) {
return; return;
@@ -217,7 +223,7 @@ i64 lb_sizeof(LLVMTypeRef type) {
break; break;
case LLVMArrayTypeKind: case LLVMArrayTypeKind:
{ {
LLVMTypeRef elem = LLVMGetElementType(type); LLVMTypeRef elem = OdinLLVMGetArrayElementType(type);
i64 elem_size = lb_sizeof(elem); i64 elem_size = lb_sizeof(elem);
i64 count = LLVMGetArrayLength(type); i64 count = LLVMGetArrayLength(type);
i64 size = count * elem_size; i64 size = count * elem_size;
@@ -229,11 +235,11 @@ i64 lb_sizeof(LLVMTypeRef type) {
return 8; return 8;
case LLVMVectorTypeKind: case LLVMVectorTypeKind:
{ {
LLVMTypeRef elem = LLVMGetElementType(type); LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
i64 elem_size = lb_sizeof(elem); i64 elem_size = lb_sizeof(elem);
i64 count = LLVMGetVectorSize(type); i64 count = LLVMGetVectorSize(type);
i64 size = count * elem_size; i64 size = count * elem_size;
return gb_clamp(next_pow2(size), 1, build_context.max_align); return next_pow2(size);
} }
} }
@@ -277,14 +283,14 @@ i64 lb_alignof(LLVMTypeRef type) {
} }
break; break;
case LLVMArrayTypeKind: case LLVMArrayTypeKind:
return lb_alignof(LLVMGetElementType(type)); return lb_alignof(OdinLLVMGetArrayElementType(type));
case LLVMX86_MMXTypeKind: case LLVMX86_MMXTypeKind:
return 8; return 8;
case LLVMVectorTypeKind: case LLVMVectorTypeKind:
{ {
// TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation // TODO(bill): This appears to be correct but LLVM isn't necessarily "great" with regards to documentation
LLVMTypeRef elem = LLVMGetElementType(type); LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
i64 elem_size = lb_sizeof(elem); i64 elem_size = lb_sizeof(elem);
i64 count = LLVMGetVectorSize(type); i64 count = LLVMGetVectorSize(type);
i64 size = count * elem_size; i64 size = count * elem_size;
@@ -787,7 +793,7 @@ namespace lbAbiAmd64SysV {
case LLVMArrayTypeKind: case LLVMArrayTypeKind:
{ {
i64 len = LLVMGetArrayLength(t); i64 len = LLVMGetArrayLength(t);
LLVMTypeRef elem = LLVMGetElementType(t); LLVMTypeRef elem = OdinLLVMGetArrayElementType(t);
i64 elem_sz = lb_sizeof(elem); i64 elem_sz = lb_sizeof(elem);
for (i64 i = 0; i < len; i++) { for (i64 i = 0; i < len; i++) {
classify_with(elem, cls, ix, off + i*elem_sz); classify_with(elem, cls, ix, off + i*elem_sz);
@@ -797,20 +803,27 @@ namespace lbAbiAmd64SysV {
case LLVMVectorTypeKind: case LLVMVectorTypeKind:
{ {
i64 len = LLVMGetVectorSize(t); i64 len = LLVMGetVectorSize(t);
LLVMTypeRef elem = LLVMGetElementType(t); LLVMTypeRef elem = OdinLLVMGetVectorElementType(t);
i64 elem_sz = lb_sizeof(elem); i64 elem_sz = lb_sizeof(elem);
LLVMTypeKind elem_kind = LLVMGetTypeKind(elem); LLVMTypeKind elem_kind = LLVMGetTypeKind(elem);
RegClass reg = RegClass_NoClass; RegClass reg = RegClass_NoClass;
unsigned elem_width = LLVMGetIntTypeWidth(elem);
switch (elem_kind) { switch (elem_kind) {
case LLVMIntegerTypeKind: case LLVMIntegerTypeKind:
case LLVMHalfTypeKind: case LLVMHalfTypeKind:
switch (LLVMGetIntTypeWidth(elem)) { switch (elem_width) {
case 8: reg = RegClass_SSEInt8; case 8: reg = RegClass_SSEInt8; break;
case 16: reg = RegClass_SSEInt16; case 16: reg = RegClass_SSEInt16; break;
case 32: reg = RegClass_SSEInt32; case 32: reg = RegClass_SSEInt32; break;
case 64: reg = RegClass_SSEInt64; case 64: reg = RegClass_SSEInt64; break;
default: default:
GB_PANIC("Unhandled integer width for vector type"); if (elem_width > 64) {
for (i64 i = 0; i < len; i++) {
classify_with(elem, cls, ix, off + i*elem_sz);
}
break;
}
GB_PANIC("Unhandled integer width for vector type %u", elem_width);
} }
break; break;
case LLVMFloatTypeKind: case LLVMFloatTypeKind:
@@ -900,7 +913,7 @@ namespace lbAbiArm64 {
if (len == 0) { if (len == 0) {
return false; return false;
} }
LLVMTypeRef elem = LLVMGetElementType(type); LLVMTypeRef elem = OdinLLVMGetArrayElementType(type);
LLVMTypeRef base_type = nullptr; LLVMTypeRef base_type = nullptr;
unsigned member_count = 0; unsigned member_count = 0;
if (is_homogenous_aggregate(c, elem, &base_type, &member_count)) { if (is_homogenous_aggregate(c, elem, &base_type, &member_count)) {
@@ -1116,7 +1129,7 @@ namespace lbAbiWasm {
} }
if (sz <= MAX_DIRECT_STRUCT_SIZE) { if (sz <= MAX_DIRECT_STRUCT_SIZE) {
if (kind == LLVMArrayTypeKind) { if (kind == LLVMArrayTypeKind) {
if (is_basic_register_type(LLVMGetElementType(type))) { if (is_basic_register_type(OdinLLVMGetArrayElementType(type))) {
return true; return true;
} }
} else if (kind == LLVMStructTypeKind) { } else if (kind == LLVMStructTypeKind) {
+5 -6
View File
@@ -739,11 +739,11 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
lb_begin_procedure_body(p); lb_begin_procedure_body(p);
if (startup_type_info) { if (startup_type_info) {
LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, ""); LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, startup_type_info->type), startup_type_info->value, nullptr, 0, "");
} }
if (objc_names) { if (objc_names) {
LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, ""); LLVMBuildCall2(p->builder, lb_type_internal_for_procedures_raw(main_module, objc_names->type), objc_names->value, nullptr, 0, "");
} }
for_array(i, global_variables) { for_array(i, global_variables) {
@@ -762,7 +762,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
if (init_expr != nullptr) { if (init_expr != nullptr) {
lbValue init = lb_build_expr(p, init_expr); lbValue init = lb_build_expr(p, init_expr);
if (init.value == nullptr) { if (init.value == nullptr) {
LLVMTypeRef global_type = LLVMGetElementType(LLVMTypeOf(var->var.value)); LLVMTypeRef global_type = llvm_addr_type(p->module, var->var);
if (is_type_untyped_undef(init.type)) { if (is_type_untyped_undef(init.type)) {
// LLVMSetInitializer(var->var.value, LLVMGetUndef(global_type)); // LLVMSetInitializer(var->var.value, LLVMGetUndef(global_type));
LLVMSetInitializer(var->var.value, LLVMConstNull(global_type)); LLVMSetInitializer(var->var.value, LLVMConstNull(global_type));
@@ -805,8 +805,7 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr)); lb_emit_store(p, data, lb_emit_conv(p, gp, t_rawptr));
lb_emit_store(p, ti, lb_type_info(main_module, var_type)); lb_emit_store(p, ti, lb_type_info(main_module, var_type));
} else { } else {
LLVMTypeRef pvt = LLVMTypeOf(var->var.value); LLVMTypeRef vt = llvm_addr_type(p->module, var->var);
LLVMTypeRef vt = LLVMGetElementType(pvt);
lbValue src0 = lb_emit_conv(p, var->init, t); lbValue src0 = lb_emit_conv(p, var->init, t);
LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt); LLVMValueRef src = OdinLLVMBuildTransmute(p, src0.value, vt);
LLVMValueRef dst = var->var.value; LLVMValueRef dst = var->var.value;
@@ -933,7 +932,7 @@ lbProcedure *lb_create_main_procedure(lbModule *m, lbProcedure *startup_runtime)
GB_ASSERT(LLVMIsConstant(vals[1])); GB_ASSERT(LLVMIsConstant(vals[1]));
GB_ASSERT(LLVMIsConstant(vals[2])); GB_ASSERT(LLVMIsConstant(vals[2]));
LLVMValueRef dst = LLVMConstInBoundsGEP(all_tests_array.value, indices, gb_count_of(indices)); LLVMValueRef dst = LLVMConstInBoundsGEP2(llvm_addr_type(m, all_tests_array), all_tests_array.value, indices, gb_count_of(indices));
LLVMValueRef src = llvm_const_named_struct(m, t_Internal_Test, vals, gb_count_of(vals)); LLVMValueRef src = llvm_const_named_struct(m, t_Internal_Test, vals, gb_count_of(vals));
LLVMBuildStore(p->builder, src, dst); LLVMBuildStore(p->builder, src, dst);
+35 -5
View File
@@ -42,6 +42,18 @@
#define ODIN_LLVM_MINIMUM_VERSION_12 0 #define ODIN_LLVM_MINIMUM_VERSION_12 0
#endif #endif
#if LLVM_VERSION_MAJOR > 13 || (LLVM_VERSION_MAJOR == 13 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0)
#define ODIN_LLVM_MINIMUM_VERSION_13 1
#else
#define ODIN_LLVM_MINIMUM_VERSION_13 0
#endif
#if LLVM_VERSION_MAJOR > 14 || (LLVM_VERSION_MAJOR == 14 && LLVM_VERSION_MINOR >= 0 && LLVM_VERSION_PATCH > 0)
#define ODIN_LLVM_MINIMUM_VERSION_14 1
#else
#define ODIN_LLVM_MINIMUM_VERSION_14 0
#endif
struct lbProcedure; struct lbProcedure;
struct lbValue { struct lbValue {
@@ -115,6 +127,7 @@ struct lbModule {
AstPackage *pkg; // associated AstPackage *pkg; // associated
PtrMap<Type *, LLVMTypeRef> types; PtrMap<Type *, LLVMTypeRef> types;
PtrMap<Type *, LLVMTypeRef> func_raw_types;
PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type * PtrMap<void *, lbStructFieldRemapping> struct_field_remapping; // Key: LLVMTypeRef or Type *
i32 internal_type_level; i32 internal_type_level;
@@ -292,11 +305,18 @@ struct lbProcedure {
LLVMMetadataRef debug_info; LLVMMetadataRef debug_info;
lbCopyElisionHint copy_elision_hint; lbCopyElisionHint copy_elision_hint;
PtrMap<Ast *, lbValue> selector_values;
PtrMap<Ast *, lbAddr> selector_addr;
}; };
#if !ODIN_LLVM_MINIMUM_VERSION_14
#define LLVMConstGEP2(Ty__, ConstantVal__, ConstantIndices__, NumIndices__) LLVMConstGEP(ConstantVal__, ConstantIndices__, NumIndices__)
#define LLVMConstInBoundsGEP2(Ty__, ConstantVal__, ConstantIndices__, NumIndices__) LLVMConstInBoundsGEP(ConstantVal__, ConstantIndices__, NumIndices__)
#define LLVMBuildPtrDiff2(Builder__, Ty__, LHS__, RHS__, Name__) LLVMBuildPtrDiff(Builder__, LHS__, RHS__, Name__)
#endif
bool lb_init_generator(lbGenerator *gen, Checker *c); bool lb_init_generator(lbGenerator *gen, Checker *c);
@@ -311,7 +331,8 @@ lbProcedure *lb_create_procedure(lbModule *module, Entity *entity, bool ignore_b
void lb_end_procedure(lbProcedure *p); void lb_end_procedure(lbProcedure *p);
LLVMTypeRef lb_type(lbModule *m, Type *type); LLVMTypeRef lb_type(lbModule *m, Type *type);
LLVMTypeRef llvm_get_element_type(LLVMTypeRef type);
lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false); lbBlock *lb_create_block(lbProcedure *p, char const *name, bool append=false);
@@ -324,7 +345,7 @@ lbValue lb_const_int(lbModule *m, Type *type, u64 value);
lbAddr lb_addr(lbValue addr); lbAddr lb_addr(lbValue addr);
Type *lb_addr_type(lbAddr const &addr); Type *lb_addr_type(lbAddr const &addr);
LLVMTypeRef lb_addr_lb_type(lbAddr const &addr); LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val);
void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value); void lb_addr_store(lbProcedure *p, lbAddr addr, lbValue value);
lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr); lbValue lb_addr_load(lbProcedure *p, lbAddr const &addr);
lbValue lb_emit_load(lbProcedure *p, lbValue v); lbValue lb_emit_load(lbProcedure *p, lbValue v);
@@ -336,8 +357,9 @@ lbValue lb_build_expr(lbProcedure *p, Ast *expr);
lbAddr lb_build_addr(lbProcedure *p, Ast *expr); lbAddr lb_build_addr(lbProcedure *p, Ast *expr);
void lb_build_stmt_list(lbProcedure *p, Array<Ast *> const &stmts); void lb_build_stmt_list(lbProcedure *p, Array<Ast *> const &stmts);
lbValue lb_build_gep(lbProcedure *p, lbValue const &value, i32 index) ; lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index);
lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index);
lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index);
lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index); lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index);
lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index); lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index);
lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index); lbValue lb_emit_array_epi(lbProcedure *p, lbValue value, isize index);
@@ -477,9 +499,17 @@ LLVMTypeRef lb_type_padding_filler(lbModule *m, i64 padding, i64 padding_align);
LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask); LLVMValueRef llvm_basic_shuffle(lbProcedure *p, LLVMValueRef vector, LLVMValueRef mask);
LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count);
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false); void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile=false);
LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile);
i64 lb_max_zero_init_size(void) {
return cast(i64)(4*build_context.word_size);
}
LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type);
LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type);
#define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime" #define LB_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
#define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info" #define LB_STARTUP_TYPE_INFO_PROC_NAME "__$startup_type_info"
+16 -16
View File
@@ -10,11 +10,12 @@ bool lb_is_const(lbValue value) {
return false; return false;
} }
bool lb_is_const_or_global(lbValue value) { bool lb_is_const_or_global(lbValue value) {
if (lb_is_const(value)) { if (lb_is_const(value)) {
return true; return true;
} }
// TODO remove use of LLVMGetElementType
#if 0
if (LLVMGetValueKind(value.value) == LLVMGlobalVariableValueKind) { if (LLVMGetValueKind(value.value) == LLVMGlobalVariableValueKind) {
LLVMTypeRef t = LLVMGetElementType(LLVMTypeOf(value.value)); LLVMTypeRef t = LLVMGetElementType(LLVMTypeOf(value.value));
if (!lb_is_type_kind(t, LLVMPointerTypeKind)) { if (!lb_is_type_kind(t, LLVMPointerTypeKind)) {
@@ -23,6 +24,7 @@ bool lb_is_const_or_global(lbValue value) {
LLVMTypeRef elem = LLVMGetElementType(t); LLVMTypeRef elem = LLVMGetElementType(t);
return lb_is_type_kind(elem, LLVMFunctionTypeKind); return lb_is_type_kind(elem, LLVMFunctionTypeKind);
} }
#endif
return false; return false;
} }
@@ -418,7 +420,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
{ {
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef ptr = LLVMBuildInBoundsGEP(p->builder, array_data, indices, 2, ""); LLVMValueRef ptr = LLVMBuildInBoundsGEP2(p->builder, llvm_type, array_data, indices, 2, "");
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
lbAddr slice = lb_add_local_generated(p, type, false); lbAddr slice = lb_add_local_generated(p, type, false);
lb_fill_slice(p, slice, {ptr, alloc_type_pointer(elem)}, {len, t_int}); lb_fill_slice(p, slice, {ptr, alloc_type_pointer(elem)}, {len, t_int});
@@ -445,7 +447,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
{ {
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef ptr = LLVMConstInBoundsGEP(array_data, indices, 2); LLVMValueRef ptr = LLVMConstInBoundsGEP2(lb_type(m, t), array_data, indices, 2);
LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true); LLVMValueRef len = LLVMConstInt(lb_type(m, t_int), count, true);
LLVMValueRef values[2] = {ptr, len}; LLVMValueRef values[2] = {ptr, len};
@@ -1007,7 +1009,7 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
for (isize i = 0; i < value_count; i++) { for (isize i = 0; i < value_count; i++) {
LLVMValueRef val = old_values[i]; LLVMValueRef val = old_values[i];
if (!LLVMIsConstant(val)) { if (!LLVMIsConstant(val)) {
LLVMValueRef dst = LLVMBuildStructGEP(p->builder, v.addr.value, cast(unsigned)i, ""); LLVMValueRef dst = LLVMBuildStructGEP2(p->builder, llvm_addr_type(p->module, v.addr), v.addr.value, cast(unsigned)i, "");
LLVMBuildStore(p->builder, val, dst); LLVMBuildStore(p->builder, val, dst);
} }
} }
@@ -1025,7 +1027,10 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
return lb_const_nil(m, original_type); return lb_const_nil(m, original_type);
} }
u64 bits = 0; BigInt bits = {};
BigInt one = {};
big_int_from_u64(&one, 1);
for_array(i, cl->elems) { for_array(i, cl->elems) {
Ast *e = cl->elems[i]; Ast *e = cl->elems[i];
GB_ASSERT(e->kind != Ast_FieldValue); GB_ASSERT(e->kind != Ast_FieldValue);
@@ -1037,18 +1042,13 @@ lbValue lb_const_value(lbModule *m, Type *type, ExactValue value, bool allow_loc
GB_ASSERT(tav.value.kind == ExactValue_Integer); GB_ASSERT(tav.value.kind == ExactValue_Integer);
i64 v = big_int_to_i64(&tav.value.value_integer); i64 v = big_int_to_i64(&tav.value.value_integer);
i64 lower = type->BitSet.lower; i64 lower = type->BitSet.lower;
bits |= 1ull<<cast(u64)(v-lower); u64 index = cast(u64)(v-lower);
BigInt bit = {};
big_int_from_u64(&bit, index);
big_int_shl(&bit, &one, &bit);
big_int_or(&bits, &bits, &bit);
} }
if (is_type_different_to_arch_endianness(type)) { res.value = lb_big_int_to_llvm(m, original_type, &bits);
i64 size = type_size_of(type);
switch (size) {
case 2: bits = cast(u64)gb_endian_swap16(cast(u16)bits); break;
case 4: bits = cast(u64)gb_endian_swap32(cast(u32)bits); break;
case 8: bits = cast(u64)gb_endian_swap64(cast(u64)bits); break;
}
}
res.value = LLVMConstInt(lb_type(m, original_type), bits, false);
return res; return res;
} else if (is_type_matrix(type)) { } else if (is_type_matrix(type)) {
ast_node(cl, CompoundLit, value.value_compound); ast_node(cl, CompoundLit, value.value_compound);
+5 -1
View File
@@ -43,6 +43,10 @@ LLVMMetadataRef lb_debug_location_from_ast(lbProcedure *p, Ast *node) {
GB_ASSERT(node != nullptr); GB_ASSERT(node != nullptr);
return lb_debug_location_from_token_pos(p, ast_token(node).pos); return lb_debug_location_from_token_pos(p, ast_token(node).pos);
} }
LLVMMetadataRef lb_debug_end_location_from_ast(lbProcedure *p, Ast *node) {
GB_ASSERT(node != nullptr);
return lb_debug_location_from_token_pos(p, ast_end_token(node).pos);
}
LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) { LLVMMetadataRef lb_debug_type_internal_proc(lbModule *m, Type *type) {
i64 size = type_size_of(type); // Check size i64 size = type_size_of(type); // Check size
@@ -969,7 +973,7 @@ void lb_add_debug_local_variable(lbProcedure *p, LLVMValueRef ptr, Type *type, T
); );
LLVMValueRef storage = ptr; LLVMValueRef storage = ptr;
LLVMBasicBlockRef block = p->decl_block->block; LLVMBasicBlockRef block = p->curr_block->block;
LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos); LLVMMetadataRef llvm_debug_loc = lb_debug_location_from_token_pos(p, token.pos);
LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0); LLVMMetadataRef llvm_expr = LLVMDIBuilderCreateExpression(m->debug_builder, nullptr, 0);
lb_set_llvm_metadata(m, ptr, llvm_expr); lb_set_llvm_metadata(m, ptr, llvm_expr);
+1127 -1291
View File
File diff suppressed because it is too large Load Diff
+268 -121
View File
@@ -56,6 +56,7 @@ void lb_init_module(lbModule *m, Checker *c) {
gbAllocator a = heap_allocator(); gbAllocator a = heap_allocator();
map_init(&m->types, a); map_init(&m->types, a);
map_init(&m->func_raw_types, a);
map_init(&m->struct_field_remapping, a); map_init(&m->struct_field_remapping, a);
map_init(&m->values, a); map_init(&m->values, a);
map_init(&m->soa_values, a); map_init(&m->soa_values, a);
@@ -174,7 +175,8 @@ struct lbLoopData {
struct lbCompoundLitElemTempData { struct lbCompoundLitElemTempData {
Ast * expr; Ast * expr;
lbValue value; lbValue value;
i32 elem_index; i64 elem_index;
i64 elem_length;
lbValue gep; lbValue gep;
}; };
@@ -211,6 +213,45 @@ void lb_loop_end(lbProcedure *p, lbLoopData const &data) {
} }
// This emits a GEP at 0, index
lbValue lb_emit_epi(lbProcedure *p, lbValue const &value, isize index) {
GB_ASSERT(is_type_pointer(value.type));
Type *type = type_deref(value.type);
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(p->module, t_int), 0, false),
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned long long)index, false),
};
LLVMTypeRef llvm_type = lb_type(p->module, type);
lbValue res = {};
Type *ptr = base_array_type(type);
res.type = alloc_type_pointer(ptr);
if (LLVMIsConstant(value.value)) {
res.value = LLVMConstGEP2(llvm_type, value.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP2(p->builder, llvm_type, value.value, indices, gb_count_of(indices), "");
}
return res;
}
// This emits a GEP at 0, index
lbValue lb_emit_epi(lbModule *m, lbValue const &value, isize index) {
GB_ASSERT(is_type_pointer(value.type));
GB_ASSERT(LLVMIsConstant(value.value));
Type *type = type_deref(value.type);
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(m, t_int), 0, false),
LLVMConstInt(lb_type(m, t_int), cast(unsigned long long)index, false),
};
lbValue res = {};
Type *ptr = base_array_type(type);
res.type = alloc_type_pointer(ptr);
res.value = LLVMConstGEP2(lb_type(m, type), value.value, indices, gb_count_of(indices));
return res;
}
LLVMValueRef llvm_zero(lbModule *m) { LLVMValueRef llvm_zero(lbModule *m) {
return LLVMConstInt(lb_type(m, t_int), 0, false); return LLVMConstInt(lb_type(m, t_int), 0, false);
} }
@@ -341,9 +382,6 @@ Type *lb_addr_type(lbAddr const &addr) {
} }
return type_deref(addr.addr.type); return type_deref(addr.addr.type);
} }
LLVMTypeRef lb_addr_lb_type(lbAddr const &addr) {
return LLVMGetElementType(LLVMTypeOf(addr.addr.value));
}
lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) { lbValue lb_addr_get_ptr(lbProcedure *p, lbAddr const &addr) {
if (addr.addr.value == nullptr) { if (addr.addr.value == nullptr) {
@@ -530,6 +568,13 @@ void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValu
} }
} }
unsigned lb_try_get_alignment(LLVMValueRef addr_ptr, unsigned default_alignment) {
if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) {
return LLVMGetAlignment(addr_ptr);
}
return default_alignment;
}
bool lb_try_update_alignment(LLVMValueRef addr_ptr, unsigned alignment) { bool lb_try_update_alignment(LLVMValueRef addr_ptr, unsigned alignment) {
if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) { if (LLVMIsAGlobalValue(addr_ptr) || LLVMIsAAllocaInst(addr_ptr) || LLVMIsALoadInst(addr_ptr)) {
if (LLVMGetAlignment(addr_ptr) < alignment) { if (LLVMGetAlignment(addr_ptr) < alignment) {
@@ -852,6 +897,20 @@ bool lb_is_type_proc_recursive(Type *t) {
void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) { void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
GB_ASSERT(value.value != nullptr); GB_ASSERT(value.value != nullptr);
Type *a = type_deref(ptr.type); Type *a = type_deref(ptr.type);
if (LLVMIsNull(value.value)) {
LLVMTypeRef src_t = llvm_addr_type(p->module, ptr);
if (is_type_proc(a)) {
LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr);
LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0);
LLVMBuildStore(p->builder, LLVMConstNull(rawptr_type), LLVMBuildBitCast(p->builder, ptr.value, rawptr_ptr_type, ""));
} else if (lb_sizeof(src_t) <= lb_max_zero_init_size()) {
LLVMBuildStore(p->builder, LLVMConstNull(src_t), ptr.value);
} else {
lb_mem_zero_ptr(p, ptr.value, a, 1);
}
return;
}
if (is_type_boolean(a)) { if (is_type_boolean(a)) {
// NOTE(bill): There are multiple sized booleans, thus force a conversion (if necessarily) // NOTE(bill): There are multiple sized booleans, thus force a conversion (if necessarily)
value = lb_emit_conv(p, value, a); value = lb_emit_conv(p, value, a);
@@ -861,13 +920,48 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
GB_ASSERT_MSG(are_types_identical(ca, core_type(value.type)), "%s != %s", type_to_string(a), type_to_string(value.type)); GB_ASSERT_MSG(are_types_identical(ca, core_type(value.type)), "%s != %s", type_to_string(a), type_to_string(value.type));
} }
enum {MAX_STORE_SIZE = 64};
if (lb_sizeof(LLVMTypeOf(value.value)) > MAX_STORE_SIZE) {
if (LLVMIsALoadInst(value.value)) {
LLVMValueRef dst_ptr = ptr.value;
LLVMValueRef src_ptr_original = LLVMGetOperand(value.value, 0);
LLVMValueRef src_ptr = LLVMBuildPointerCast(p->builder, src_ptr_original, LLVMTypeOf(dst_ptr), "");
LLVMBuildMemMove(p->builder,
dst_ptr, lb_try_get_alignment(dst_ptr, 1),
src_ptr, lb_try_get_alignment(src_ptr_original, 1),
LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
return;
} else if (LLVMIsConstant(value.value)) {
lbAddr addr = lb_add_global_generated(p->module, value.type, value, nullptr);
LLVMValueRef global_data = addr.addr.value;
// make it truly private data
LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetGlobalConstant(global_data, true);
LLVMValueRef dst_ptr = ptr.value;
LLVMValueRef src_ptr = global_data;
src_ptr = LLVMBuildPointerCast(p->builder, src_ptr, LLVMTypeOf(dst_ptr), "");
LLVMBuildMemMove(p->builder,
dst_ptr, lb_try_get_alignment(dst_ptr, 1),
src_ptr, lb_try_get_alignment(global_data, 1),
LLVMConstInt(LLVMInt64TypeInContext(p->module->ctx), lb_sizeof(LLVMTypeOf(value.value)), false));
return;
}
}
if (lb_is_type_proc_recursive(a)) { if (lb_is_type_proc_recursive(a)) {
// NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be // NOTE(bill, 2020-11-11): Because of certain LLVM rules, a procedure value may be
// stored as regular pointer with no procedure information // stored as regular pointer with no procedure information
LLVMTypeRef src_t = LLVMGetElementType(LLVMTypeOf(ptr.value)); LLVMTypeRef rawptr_type = lb_type(p->module, t_rawptr);
LLVMValueRef v = LLVMBuildPointerCast(p->builder, value.value, src_t, ""); LLVMTypeRef rawptr_ptr_type = LLVMPointerType(rawptr_type, 0);
LLVMBuildStore(p->builder, v, ptr.value); LLVMBuildStore(p->builder,
LLVMBuildPointerCast(p->builder, value.value, rawptr_type, ""),
LLVMBuildPointerCast(p->builder, ptr.value, rawptr_ptr_type, ""));
} else { } else {
Type *ca = core_type(a); Type *ca = core_type(a);
if (ca->kind == Type_Basic || ca->kind == Type_Proc) { if (ca->kind == Type_Basic || ca->kind == Type_Proc) {
@@ -880,8 +974,8 @@ void lb_emit_store(lbProcedure *p, lbValue ptr, lbValue value) {
} }
} }
LLVMTypeRef llvm_addr_type(lbValue addr_val) { LLVMTypeRef llvm_addr_type(lbModule *module, lbValue addr_val) {
return LLVMGetElementType(LLVMTypeOf(addr_val.value)); return lb_type(module, type_deref(addr_val.type));
} }
lbValue lb_emit_load(lbProcedure *p, lbValue value) { lbValue lb_emit_load(lbProcedure *p, lbValue value) {
@@ -890,12 +984,18 @@ lbValue lb_emit_load(lbProcedure *p, lbValue value) {
Type *vt = base_type(value.type); Type *vt = base_type(value.type);
GB_ASSERT(vt->kind == Type_MultiPointer); GB_ASSERT(vt->kind == Type_MultiPointer);
Type *t = vt->MultiPointer.elem; Type *t = vt->MultiPointer.elem;
LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, "");
return lbValue{v, t}; return lbValue{v, t};
} else if (is_type_soa_pointer(value.type)) {
lbValue ptr = lb_emit_struct_ev(p, value, 0);
lbValue idx = lb_emit_struct_ev(p, value, 1);
lbAddr addr = lb_addr_soa_variable(ptr, idx, nullptr);
return lb_addr_load(p, addr);
} }
GB_ASSERT(is_type_pointer(value.type)); GB_ASSERT(is_type_pointer(value.type));
Type *t = type_deref(value.type); Type *t = type_deref(value.type);
LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); LLVMValueRef v = LLVMBuildLoad2(p->builder, lb_type(p->module, t), value.value, "");
return lbValue{v, t}; return lbValue{v, t};
} }
@@ -1160,12 +1260,12 @@ lbValue lb_emit_union_tag_ptr(lbProcedure *p, lbValue u) {
Type *tag_type = union_tag_type(ut); Type *tag_type = union_tag_type(ut);
LLVMTypeRef uvt = LLVMGetElementType(LLVMTypeOf(u.value)); LLVMTypeRef uvt = llvm_addr_type(p->module, u);
unsigned element_count = LLVMCountStructElementTypes(uvt); unsigned element_count = LLVMCountStructElementTypes(uvt);
GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt)); GB_ASSERT_MSG(element_count >= 2, "element_count=%u (%s) != (%s)", element_count, type_to_string(ut), LLVMPrintTypeToString(uvt));
lbValue tag_ptr = {}; lbValue tag_ptr = {};
tag_ptr.value = LLVMBuildStructGEP(p->builder, u.value, 1, ""); tag_ptr.value = LLVMBuildStructGEP2(p->builder, uvt, u.value, 1, "");
tag_ptr.type = alloc_type_pointer(tag_type); tag_ptr.type = alloc_type_pointer(tag_type);
return tag_ptr; return tag_ptr;
} }
@@ -1389,6 +1489,116 @@ String lb_get_entity_name(lbModule *m, Entity *e, String default_name) {
} }
LLVMTypeRef lb_type_internal_for_procedures_raw(lbModule *m, Type *type) {
Type *original_type = type;
type = base_type(original_type);
GB_ASSERT(type->kind == Type_Proc);
LLVMTypeRef *found = map_get(&m->func_raw_types, type);
if (found) {
return *found;
}
unsigned param_count = 0;
if (type->Proc.calling_convention == ProcCC_Odin) {
param_count += 1;
}
if (type->Proc.param_count != 0) {
GB_ASSERT(type->Proc.params->kind == Type_Tuple);
for_array(i, type->Proc.params->Tuple.variables) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (e->flags & EntityFlag_CVarArg) {
continue;
}
param_count += 1;
}
}
m->internal_type_level += 1;
defer (m->internal_type_level -= 1);
LLVMTypeRef ret = nullptr;
LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
if (type->Proc.result_count != 0) {
Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
ret = lb_type(m, single_ret);
if (ret != nullptr) {
if (is_type_boolean(single_ret) &&
is_calling_convention_none(type->Proc.calling_convention) &&
type_size_of(single_ret) <= 1) {
ret = LLVMInt1TypeInContext(m->ctx);
}
}
}
unsigned param_index = 0;
if (type->Proc.param_count != 0) {
GB_ASSERT(type->Proc.params->kind == Type_Tuple);
for_array(i, type->Proc.params->Tuple.variables) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (e->flags & EntityFlag_CVarArg) {
continue;
}
Type *e_type = reduce_tuple_to_single_type(e->type);
LLVMTypeRef param_type = nullptr;
if (e->flags & EntityFlag_ByPtr) {
param_type = lb_type(m, alloc_type_pointer(e_type));
} else if (is_type_boolean(e_type) &&
type_size_of(e_type) <= 1) {
param_type = LLVMInt1TypeInContext(m->ctx);
} else {
if (is_type_proc(e_type)) {
param_type = lb_type(m, t_rawptr);
} else {
param_type = lb_type(m, e_type);
}
}
params[param_index++] = param_type;
}
}
if (param_index < param_count) {
params[param_index++] = lb_type(m, t_rawptr);
}
GB_ASSERT(param_index == param_count);
lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention);
{
for_array(j, ft->args) {
auto arg = ft->args[j];
GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx,
"\n\t%s %td/%td"
"\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMPrintTypeToString(arg.type),
j, ft->args.count,
LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext());
}
GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx,
"\n\t%s"
"\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMPrintTypeToString(ft->ret.type),
LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
}
map_set(&m->function_type_map, type, ft);
LLVMTypeRef new_abi_fn_type = lb_function_type_to_llvm_raw(ft, type->Proc.c_vararg);
GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx,
"\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext());
map_set(&m->func_raw_types, type, new_abi_fn_type);
return new_abi_fn_type;
}
LLVMTypeRef lb_type_internal(lbModule *m, Type *type) { LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
LLVMContextRef ctx = m->ctx; LLVMContextRef ctx = m->ctx;
i64 size = type_size_of(type); // Check size i64 size = type_size_of(type); // Check size
@@ -1892,102 +2102,8 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough? if (m->internal_type_level > 1) { // TODO HACK(bill): is this really enough?
return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0); return LLVMPointerType(LLVMIntTypeInContext(m->ctx, 8), 0);
} else { } else {
unsigned param_count = 0; LLVMTypeRef proc_raw_type = lb_type_internal_for_procedures_raw(m, type);
if (type->Proc.calling_convention == ProcCC_Odin) { return LLVMPointerType(proc_raw_type, 0);
param_count += 1;
}
if (type->Proc.param_count != 0) {
GB_ASSERT(type->Proc.params->kind == Type_Tuple);
for_array(i, type->Proc.params->Tuple.variables) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (e->flags & EntityFlag_CVarArg) {
continue;
}
param_count += 1;
}
}
m->internal_type_level += 1;
defer (m->internal_type_level -= 1);
LLVMTypeRef ret = nullptr;
LLVMTypeRef *params = gb_alloc_array(permanent_allocator(), LLVMTypeRef, param_count);
if (type->Proc.result_count != 0) {
Type *single_ret = reduce_tuple_to_single_type(type->Proc.results);
ret = lb_type(m, single_ret);
if (ret != nullptr) {
if (is_type_boolean(single_ret) &&
is_calling_convention_none(type->Proc.calling_convention) &&
type_size_of(single_ret) <= 1) {
ret = LLVMInt1TypeInContext(m->ctx);
}
}
}
unsigned param_index = 0;
if (type->Proc.param_count != 0) {
GB_ASSERT(type->Proc.params->kind == Type_Tuple);
for_array(i, type->Proc.params->Tuple.variables) {
Entity *e = type->Proc.params->Tuple.variables[i];
if (e->kind != Entity_Variable) {
continue;
}
if (e->flags & EntityFlag_CVarArg) {
continue;
}
Type *e_type = reduce_tuple_to_single_type(e->type);
LLVMTypeRef param_type = nullptr;
if (is_type_boolean(e_type) &&
type_size_of(e_type) <= 1) {
param_type = LLVMInt1TypeInContext(m->ctx);
} else {
if (is_type_proc(e_type)) {
param_type = lb_type(m, t_rawptr);
} else {
param_type = lb_type(m, e_type);
}
}
params[param_index++] = param_type;
}
}
if (param_index < param_count) {
params[param_index++] = lb_type(m, t_rawptr);
}
GB_ASSERT(param_index == param_count);
lbFunctionType *ft = lb_get_abi_info(m->ctx, params, param_count, ret, ret != nullptr, type->Proc.calling_convention);
{
for_array(j, ft->args) {
auto arg = ft->args[j];
GB_ASSERT_MSG(LLVMGetTypeContext(arg.type) == ft->ctx,
"\n\t%s %td/%td"
"\n\tArgTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMPrintTypeToString(arg.type),
j, ft->args.count,
LLVMGetTypeContext(arg.type), ft->ctx, LLVMGetGlobalContext());
}
GB_ASSERT_MSG(LLVMGetTypeContext(ft->ret.type) == ft->ctx,
"\n\t%s"
"\n\tRetTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMPrintTypeToString(ft->ret.type),
LLVMGetTypeContext(ft->ret.type), ft->ctx, LLVMGetGlobalContext());
}
map_set(&m->function_type_map, type, ft);
LLVMTypeRef new_abi_fn_ptr_type = lb_function_type_to_llvm_ptr(ft, type->Proc.c_vararg);
LLVMTypeRef new_abi_fn_type = LLVMGetElementType(new_abi_fn_ptr_type);
GB_ASSERT_MSG(LLVMGetTypeContext(new_abi_fn_type) == m->ctx,
"\n\tFuncTypeCtx: %p\n\tCurrentCtx: %p\n\tGlobalCtx: %p",
LLVMGetTypeContext(new_abi_fn_type), m->ctx, LLVMGetGlobalContext());
return new_abi_fn_ptr_type;
} }
break; break;
@@ -2030,6 +2146,15 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
m->internal_type_level += 1; m->internal_type_level += 1;
return t; return t;
} }
case Type_SoaPointer:
{
unsigned field_count = 2;
LLVMTypeRef *fields = gb_alloc_array(permanent_allocator(), LLVMTypeRef, field_count);
fields[0] = LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
fields[1] = LLVMIntTypeInContext(ctx, 8*cast(unsigned)build_context.word_size);
return LLVMStructTypeInContext(ctx, fields, field_count, false);
}
} }
@@ -2234,6 +2359,17 @@ void lb_emit_if(lbProcedure *p, lbValue cond, lbBlock *true_block, lbBlock *fals
} }
gb_inline LLVMTypeRef OdinLLVMGetInternalElementType(LLVMTypeRef type) {
return LLVMGetElementType(type);
}
LLVMTypeRef OdinLLVMGetArrayElementType(LLVMTypeRef type) {
GB_ASSERT(lb_is_type_kind(type, LLVMArrayTypeKind));
return OdinLLVMGetInternalElementType(type);
}
LLVMTypeRef OdinLLVMGetVectorElementType(LLVMTypeRef type) {
GB_ASSERT(lb_is_type_kind(type, LLVMVectorTypeKind));
return OdinLLVMGetInternalElementType(type);
}
LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) { LLVMValueRef OdinLLVMBuildTransmute(lbProcedure *p, LLVMValueRef val, LLVMTypeRef dst_type) {
@@ -2304,7 +2440,7 @@ general_end:;
if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) { if (LLVMIsALoadInst(val) && (src_size >= dst_size && src_align >= dst_align)) {
LLVMValueRef val_ptr = LLVMGetOperand(val, 0); LLVMValueRef val_ptr = LLVMGetOperand(val, 0);
val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), ""); val_ptr = LLVMBuildPointerCast(p->builder, val_ptr, LLVMPointerType(dst_type, 0), "");
LLVMValueRef loaded_val = LLVMBuildLoad(p->builder, val_ptr, ""); LLVMValueRef loaded_val = LLVMBuildLoad2(p->builder, dst_type, val_ptr, "");
// LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align)); // LLVMSetAlignment(loaded_val, gb_min(src_align, dst_align));
@@ -2320,7 +2456,7 @@ general_end:;
LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), ""); LLVMValueRef nptr = LLVMBuildPointerCast(p->builder, ptr, LLVMPointerType(src_type, 0), "");
LLVMBuildStore(p->builder, val, nptr); LLVMBuildStore(p->builder, val, nptr);
return LLVMBuildLoad(p->builder, ptr, ""); return LLVMBuildLoad2(p->builder, dst_type, ptr, "");
} }
} }
@@ -2346,11 +2482,15 @@ LLVMValueRef lb_find_or_add_entity_string_ptr(lbModule *m, String const &str) {
isize len = gb_snprintf(name, max_len, "csbs$%x", id); isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1; len -= 1;
LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); LLVMTypeRef type = LLVMTypeOf(data);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, data); LLVMSetInitializer(global_data, data);
LLVMSetLinkage(global_data, LLVMPrivateLinkage); LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(global_data, 1);
LLVMSetGlobalConstant(global_data, true);
LLVMValueRef ptr = LLVMConstInBoundsGEP(global_data, indices, 2); LLVMValueRef ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
string_map_set(&m->const_strings, key, ptr); string_map_set(&m->const_strings, key, ptr);
return ptr; return ptr;
} }
@@ -2388,13 +2528,17 @@ lbValue lb_find_or_add_entity_string_byte_slice(lbModule *m, String const &str)
isize len = gb_snprintf(name, max_len, "csbs$%x", id); isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1; len -= 1;
} }
LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(data), name); LLVMTypeRef type = LLVMTypeOf(data);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, data); LLVMSetInitializer(global_data, data);
LLVMSetLinkage(global_data, LLVMPrivateLinkage); LLVMSetLinkage(global_data, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(global_data, LLVMGlobalUnnamedAddr);
LLVMSetAlignment(global_data, 1);
LLVMSetGlobalConstant(global_data, true);
LLVMValueRef ptr = nullptr; LLVMValueRef ptr = nullptr;
if (str.len != 0) { if (str.len != 0) {
ptr = LLVMConstInBoundsGEP(global_data, indices, 2); ptr = LLVMConstInBoundsGEP2(type, global_data, indices, 2);
} else { } else {
ptr = LLVMConstNull(lb_type(m, t_u8_ptr)); ptr = LLVMConstNull(lb_type(m, t_u8_ptr));
} }
@@ -2627,6 +2771,7 @@ lbValue lb_generate_global_array(lbModule *m, Type *elem_type, i64 count, String
g.type = alloc_type_pointer(t); g.type = alloc_type_pointer(t);
LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t))); LLVMSetInitializer(g.value, LLVMConstNull(lb_type(m, t)));
LLVMSetLinkage(g.value, LLVMPrivateLinkage); LLVMSetLinkage(g.value, LLVMPrivateLinkage);
LLVMSetUnnamedAddress(g.value, LLVMGlobalUnnamedAddr);
string_map_set(&m->members, s, g); string_map_set(&m->members, s, g);
return g; return g;
} }
@@ -2709,20 +2854,18 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p
if (!zero_init && !force_no_init) { if (!zero_init && !force_no_init) {
// If there is any padding of any kind, just zero init regardless of zero_init parameter // If there is any padding of any kind, just zero init regardless of zero_init parameter
LLVMTypeKind kind = LLVMGetTypeKind(llvm_type); LLVMTypeKind kind = LLVMGetTypeKind(llvm_type);
if (kind == LLVMArrayTypeKind) {
kind = LLVMGetTypeKind(lb_type(p->module, core_array_type(type)));
}
if (kind == LLVMStructTypeKind) { if (kind == LLVMStructTypeKind) {
i64 sz = type_size_of(type); i64 sz = type_size_of(type);
if (type_size_of_struct_pretend_is_packed(type) != sz) { if (type_size_of_struct_pretend_is_packed(type) != sz) {
zero_init = true; zero_init = true;
} }
} else if (kind == LLVMArrayTypeKind) {
zero_init = true;
} }
} }
if (zero_init) {
lb_mem_zero_ptr(p, ptr, type, alignment);
}
lbValue val = {}; lbValue val = {};
val.value = ptr; val.value = ptr;
val.type = alloc_type_pointer(type); val.type = alloc_type_pointer(type);
@@ -2732,6 +2875,10 @@ lbAddr lb_add_local(lbProcedure *p, Type *type, Entity *e, bool zero_init, i32 p
lb_add_debug_local_variable(p, ptr, type, e->token); lb_add_debug_local_variable(p, ptr, type, e->token);
} }
if (zero_init) {
lb_mem_zero_ptr(p, ptr, type, alignment);
}
return lb_addr(val); return lb_addr(val);
} }
+3 -1
View File
@@ -62,7 +62,9 @@ void lb_basic_populate_function_pass_manager(LLVMPassManagerRef fpm, i32 optimiz
LLVMAddPromoteMemoryToRegisterPass(fpm); LLVMAddPromoteMemoryToRegisterPass(fpm);
LLVMAddMergedLoadStoreMotionPass(fpm); LLVMAddMergedLoadStoreMotionPass(fpm);
LLVM_ADD_CONSTANT_VALUE_PASS(fpm); LLVM_ADD_CONSTANT_VALUE_PASS(fpm);
LLVMAddEarlyCSEPass(fpm); if (!build_context.ODIN_DEBUG) {
LLVMAddEarlyCSEPass(fpm);
}
} }
} }
+119 -150
View File
@@ -1,3 +1,13 @@
LLVMValueRef lb_call_intrinsic(lbProcedure *p, const char *name, LLVMValueRef* args, unsigned arg_count, LLVMTypeRef* types, unsigned type_count)
{
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, type_count);
LLVMTypeRef call_type = LLVMIntrinsicGetType(p->module->ctx, id, types, type_count);
return LLVMBuildCall2(p->builder, call_type, ip, args, arg_count, "");
}
void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) { void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
dst = lb_emit_conv(p, dst, t_rawptr); dst = lb_emit_conv(p, dst, t_rawptr);
src = lb_emit_conv(p, src, t_rawptr); src = lb_emit_conv(p, src, t_rawptr);
@@ -10,23 +20,23 @@ void lb_mem_copy_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue l
name = "llvm.memmove.inline"; name = "llvm.memmove.inline";
} }
} }
LLVMTypeRef types[3] = { LLVMTypeRef types[3] = {
lb_type(p->module, t_rawptr), lb_type(p->module, t_rawptr),
lb_type(p->module, t_rawptr), lb_type(p->module, t_rawptr),
lb_type(p->module, t_int) lb_type(p->module, t_int)
}; };
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); LLVMValueRef args[4] = {
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2])); dst.value,
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types)); src.value,
len.value,
LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile)
};
LLVMValueRef args[4] = {}; lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
args[0] = dst.value;
args[1] = src.value;
args[2] = len.value;
args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile);
LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
} }
void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) { void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbValue len, bool is_volatile) {
dst = lb_emit_conv(p, dst, t_rawptr); dst = lb_emit_conv(p, dst, t_rawptr);
src = lb_emit_conv(p, src, t_rawptr); src = lb_emit_conv(p, src, t_rawptr);
@@ -45,16 +55,14 @@ void lb_mem_copy_non_overlapping(lbProcedure *p, lbValue dst, lbValue src, lbVal
lb_type(p->module, t_rawptr), lb_type(p->module, t_rawptr),
lb_type(p->module, t_int) lb_type(p->module, t_int)
}; };
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]), LLVMPrintTypeToString(types[2]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[4] = {}; LLVMValueRef args[4] = {
args[0] = dst.value; dst.value,
args[1] = src.value; src.value,
args[2] = len.value; len.value,
args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile); LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), 0, is_volatile) };
LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
} }
@@ -113,14 +121,15 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
p->branch_blocks.allocator = a; p->branch_blocks.allocator = a;
p->context_stack.allocator = a; p->context_stack.allocator = a;
p->scope_stack.allocator = a; p->scope_stack.allocator = a;
map_init(&p->selector_values, a, 0);
map_init(&p->selector_addr, a, 0);
if (p->is_foreign) { if (p->is_foreign) {
lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library); lb_add_foreign_library_path(p->module, entity->Procedure.foreign_library);
} }
char *c_link_name = alloc_cstring(permanent_allocator(), p->name); char *c_link_name = alloc_cstring(permanent_allocator(), p->name);
LLVMTypeRef func_ptr_type = lb_type(m, p->type); LLVMTypeRef func_type = lb_get_procedure_raw_type(m, p->type);
LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type);
p->value = LLVMAddFunction(m->mod, c_link_name, func_type); p->value = LLVMAddFunction(m->mod, c_link_name, func_type);
@@ -344,8 +353,7 @@ lbProcedure *lb_create_dummy_procedure(lbModule *m, String link_name, Type *type
char *c_link_name = alloc_cstring(permanent_allocator(), p->name); char *c_link_name = alloc_cstring(permanent_allocator(), p->name);
LLVMTypeRef func_ptr_type = lb_type(m, p->type); LLVMTypeRef func_type = lb_get_procedure_raw_type(m, p->type);
LLVMTypeRef func_type = LLVMGetElementType(func_ptr_type);
p->value = LLVMAddFunction(m->mod, c_link_name, func_type); p->value = LLVMAddFunction(m->mod, c_link_name, func_type);
@@ -433,6 +441,40 @@ void lb_start_block(lbProcedure *p, lbBlock *b) {
p->curr_block = b; p->curr_block = b;
} }
void lb_set_debug_position_to_procedure_begin(lbProcedure *p) {
if (p->debug_info == nullptr) {
return;
}
TokenPos pos = {};
if (p->body != nullptr) {
pos = ast_token(p->body).pos;
} else if (p->type_expr != nullptr) {
pos = ast_token(p->type_expr).pos;
} else if (p->entity != nullptr) {
pos = p->entity->token.pos;
}
if (pos.file_id != 0) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos));
}
}
void lb_set_debug_position_to_procedure_end(lbProcedure *p) {
if (p->debug_info == nullptr) {
return;
}
TokenPos pos = {};
if (p->body != nullptr) {
pos = ast_end_token(p->body).pos;
} else if (p->type_expr != nullptr) {
pos = ast_end_token(p->type_expr).pos;
} else if (p->entity != nullptr) {
pos = p->entity->token.pos;
}
if (pos.file_id != 0) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos));
}
}
void lb_begin_procedure_body(lbProcedure *p) { void lb_begin_procedure_body(lbProcedure *p) {
DeclInfo *decl = decl_info_of_entity(p->entity); DeclInfo *decl = decl_info_of_entity(p->entity);
if (decl != nullptr) { if (decl != nullptr) {
@@ -564,29 +606,21 @@ void lb_begin_procedure_body(lbProcedure *p) {
lb_push_context_onto_stack_from_implicit_parameter(p); lb_push_context_onto_stack_from_implicit_parameter(p);
} }
lb_start_block(p, p->entry_block); lb_set_debug_position_to_procedure_begin(p);
if (p->debug_info != nullptr) { if (p->debug_info != nullptr) {
TokenPos pos = {};
if (p->body != nullptr) {
pos = ast_token(p->body).pos;
} else if (p->type_expr != nullptr) {
pos = ast_token(p->type_expr).pos;
} else if (p->entity != nullptr) {
pos = p->entity->token.pos;
}
if (pos.file_id != 0) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_token_pos(p, pos));
}
if (p->context_stack.count != 0) { if (p->context_stack.count != 0) {
p->curr_block = p->decl_block;
lb_add_debug_context_variable(p, lb_find_or_generate_context_ptr(p)); lb_add_debug_context_variable(p, lb_find_or_generate_context_ptr(p));
} }
} }
lb_start_block(p, p->entry_block);
} }
void lb_end_procedure_body(lbProcedure *p) { void lb_end_procedure_body(lbProcedure *p) {
lb_set_debug_position_to_procedure_begin(p);
LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block); LLVMPositionBuilderAtEnd(p->builder, p->decl_block->block);
LLVMBuildBr(p->builder, p->entry_block->block); LLVMBuildBr(p->builder, p->entry_block->block);
LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block); LLVMPositionBuilderAtEnd(p->builder, p->curr_block->block);
@@ -598,6 +632,7 @@ void lb_end_procedure_body(lbProcedure *p) {
instr = LLVMGetLastInstruction(p->curr_block->block); instr = LLVMGetLastInstruction(p->curr_block->block);
if (!lb_is_instr_terminating(instr)) { if (!lb_is_instr_terminating(instr)) {
lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr); lb_emit_defer_stmts(p, lbDeferExit_Return, nullptr);
lb_set_debug_position_to_procedure_end(p);
LLVMBuildRetVoid(p->builder); LLVMBuildRetVoid(p->builder);
} }
} }
@@ -716,12 +751,12 @@ lbValue lb_emit_call_internal(lbProcedure *p, lbValue value, lbValue return_ptr,
GB_ASSERT(curr_block != p->decl_block->block); GB_ASSERT(curr_block != p->decl_block->block);
{ {
LLVMTypeRef ftp = lb_type(p->module, value.type); LLVMTypeRef fnp = lb_type_internal_for_procedures_raw(p->module, value.type);
LLVMTypeRef ftp = LLVMPointerType(fnp, 0);
LLVMValueRef fn = value.value; LLVMValueRef fn = value.value;
if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) { if (!lb_is_type_kind(LLVMTypeOf(value.value), LLVMFunctionTypeKind)) {
fn = LLVMBuildPointerCast(p->builder, fn, ftp, ""); fn = LLVMBuildPointerCast(p->builder, fn, ftp, "");
} }
LLVMTypeRef fnp = LLVMGetElementType(LLVMTypeOf(fn));
GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp)); GB_ASSERT_MSG(lb_is_type_kind(fnp, LLVMFunctionTypeKind), "%s", LLVMPrintTypeToString(fnp));
{ {
@@ -1235,13 +1270,8 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
} }
args[args_count++] = arg0.value; args[args_count++] = arg0.value;
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)}; LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); res.value = lb_call_intrinsic(p, name, args, cast(unsigned)args_count, types, gb_count_of(types));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
res.value = LLVMBuildCall(p->builder, ip, args, cast(unsigned)args_count, "");
return res; return res;
} }
case BuiltinProc_simd_reduce_min: case BuiltinProc_simd_reduce_min:
@@ -1274,15 +1304,11 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
case BuiltinProc_simd_reduce_or: name = "llvm.vector.reduce.or"; break; case BuiltinProc_simd_reduce_or: name = "llvm.vector.reduce.or"; break;
case BuiltinProc_simd_reduce_xor: name = "llvm.vector.reduce.xor"; break; case BuiltinProc_simd_reduce_xor: name = "llvm.vector.reduce.xor"; break;
} }
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {}; LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) };
args[0] = arg0.value; LLVMValueRef args[1] = { arg0.value };
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res; return res;
} }
@@ -1331,15 +1357,10 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
case BuiltinProc_simd_nearest: name = "llvm.nearbyint"; break; case BuiltinProc_simd_nearest: name = "llvm.nearbyint"; break;
} }
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)}; LLVMTypeRef types[1] = { lb_type(p->module, arg0.type) };
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); LLVMValueRef args[1] = { arg0.value };
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {}; res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
args[0] = arg0.value;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
return res; return res;
} }
@@ -1403,15 +1424,10 @@ lbValue lb_build_builtin_simd_proc(lbProcedure *p, Ast *expr, TypeAndValue const
} }
LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)}; LLVMTypeRef types[1] = {lb_type(p->module, arg0.type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {}; LLVMValueRef args[2] = { arg0.value, arg1.value };
args[0] = arg0.value;
args[1] = arg1.value;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res; return res;
} }
@@ -1822,6 +1838,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
return lb_emit_matrix_flatten(p, m, tv.type); return lb_emit_matrix_flatten(p, m, tv.type);
} }
case BuiltinProc_unreachable:
lb_emit_unreachable(p);
return {};
// "Intrinsics" // "Intrinsics"
case BuiltinProc_alloca: case BuiltinProc_alloca:
@@ -1869,11 +1890,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_trap: name = "llvm.trap"; break; case BuiltinProc_trap: name = "llvm.trap"; break;
} }
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); lb_call_intrinsic(p, name, nullptr, 0, nullptr, 0);
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
LLVMBuildCall(p->builder, ip, nullptr, 0, "");
if (id == BuiltinProc_trap) { if (id == BuiltinProc_trap) {
LLVMBuildUnreachable(p->builder); LLVMBuildUnreachable(p->builder);
} }
@@ -1893,11 +1910,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
res.value = LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, ""); res.value = LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, "");
} else { } else {
char const *name = "llvm.readcyclecounter"; char const *name = "llvm.readcyclecounter";
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); res.value = lb_call_intrinsic(p, name, nullptr, 0, nullptr, 0);
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, "");
} }
return res; return res;
} }
@@ -1952,16 +1965,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
} }
} }
LLVMTypeRef types[1] = {lb_type(p->module, type)}; LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {}; LLVMValueRef args[2] = { x.value, y.value };
args[0] = x.value;
args[1] = y.value;
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
if (is_type_tuple(main_type)) { if (is_type_tuple(main_type)) {
Type *res_type = nullptr; Type *res_type = nullptr;
@@ -1988,15 +1996,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.sqrt"; char const *name = "llvm.sqrt";
LLVMTypeRef types[1] = {lb_type(p->module, type)}; LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {}; LLVMValueRef args[1] = { x.value };
args[0] = x.value;
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type; res.type = type;
return res; return res;
} }
@@ -2011,17 +2015,11 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.fma"; char const *name = "llvm.fma";
LLVMTypeRef types[1] = {lb_type(p->module, type)}; LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[3] = {}; LLVMValueRef args[3] = { x.value, y.value, z.value };
args[0] = x.value;
args[1] = y.value;
args[2] = z.value;
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type; res.type = type;
return res; return res;
} }
@@ -2080,7 +2078,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue res = {}; lbValue res = {};
res.type = tv.type; res.type = tv.type;
res.value = LLVMBuildGEP(p->builder, ptr.value, indices, gb_count_of(indices), ""); res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, type_deref(tv.type)), ptr.value, indices, gb_count_of(indices), "");
return res; return res;
} }
case BuiltinProc_ptr_sub: case BuiltinProc_ptr_sub:
@@ -2089,7 +2087,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue ptr1 = lb_build_expr(p, ce->args[1]); lbValue ptr1 = lb_build_expr(p, ce->args[1]);
LLVMTypeRef type_int = lb_type(p->module, t_int); LLVMTypeRef type_int = lb_type(p->module, t_int);
LLVMValueRef diff = LLVMBuildPtrDiff(p->builder, ptr0.value, ptr1.value, ""); LLVMValueRef diff = LLVMBuildPtrDiff2(p->builder, lb_type(p->module, ptr0.type), ptr0.value, ptr1.value, "");
diff = LLVMBuildIntCast2(p->builder, diff, type_int, /*signed*/true, ""); diff = LLVMBuildIntCast2(p->builder, diff, type_int, /*signed*/true, "");
lbValue res = {}; lbValue res = {};
@@ -2140,7 +2138,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_atomic_load_explicit: { case BuiltinProc_atomic_load_explicit: {
lbValue dst = lb_build_expr(p, ce->args[0]); lbValue dst = lb_build_expr(p, ce->args[0]);
LLVMValueRef instr = LLVMBuildLoad(p->builder, dst.value, ""); LLVMValueRef instr = LLVMBuildLoad2(p->builder, lb_type(p->module, type_deref(dst.type)), dst.value, "");
switch (id) { switch (id) {
case BuiltinProc_non_temporal_load: case BuiltinProc_non_temporal_load:
{ {
@@ -2314,18 +2312,14 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
GB_ASSERT(name != nullptr); GB_ASSERT(name != nullptr);
LLVMTypeRef types[1] = {lb_type(p->module, platform_type)}; LLVMTypeRef types[1] = {lb_type(p->module, platform_type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
lbValue res = {}; lbValue res = {};
LLVMValueRef args[3] = {}; LLVMValueRef args[3] = {
args[0] = x.value; x.value,
args[1] = y.value; y.value,
args[2] = scale.value; scale.value };
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = platform_type; res.type = platform_type;
return lb_emit_conv(p, res, tv.type); return lb_emit_conv(p, res, tv.type);
} }
@@ -2339,17 +2333,10 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.expect"; char const *name = "llvm.expect";
LLVMTypeRef types[1] = {lb_type(p->module, t)}; LLVMTypeRef types[1] = {lb_type(p->module, t)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
lbValue res = {}; lbValue res = {};
LLVMValueRef args[2] = { x.value, y.value };
LLVMValueRef args[2] = {}; res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
args[0] = x.value;
args[1] = y.value;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
res.type = t; res.type = t;
return lb_emit_conv(p, res, t); return lb_emit_conv(p, res, t);
} }
@@ -2385,9 +2372,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
char const *name = "llvm.prefetch"; char const *name = "llvm.prefetch";
LLVMTypeRef types[1] = {lb_type(p->module, t_rawptr)}; LLVMTypeRef types[1] = {lb_type(p->module, t_rawptr)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMTypeRef llvm_i32 = lb_type(p->module, t_i32); LLVMTypeRef llvm_i32 = lb_type(p->module, t_i32);
LLVMValueRef args[4] = {}; LLVMValueRef args[4] = {};
@@ -2397,7 +2381,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
args[3] = LLVMConstInt(llvm_i32, cache, false); args[3] = LLVMConstInt(llvm_i32, cache, false);
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = nullptr; res.type = nullptr;
return res; return res;
} }
@@ -2643,7 +2627,8 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
isize len = gb_snprintf(name, max_len, "csbs$%x", id); isize len = gb_snprintf(name, max_len, "csbs$%x", id);
len -= 1; len -= 1;
} }
LLVMValueRef global_data = LLVMAddGlobal(m->mod, LLVMTypeOf(array), name); LLVMTypeRef type = LLVMTypeOf(array);
LLVMValueRef global_data = LLVMAddGlobal(m->mod, type, name);
LLVMSetInitializer(global_data, array); LLVMSetInitializer(global_data, array);
LLVMSetLinkage(global_data, LLVMInternalLinkage); LLVMSetLinkage(global_data, LLVMInternalLinkage);
@@ -2655,7 +2640,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
}; };
lbValue res = {}; lbValue res = {};
res.type = tv.type; res.type = tv.type;
res.value = LLVMBuildInBoundsGEP(p->builder, global_data, indices, gb_count_of(indices), ""); res.value = LLVMBuildInBoundsGEP2(p->builder, type, global_data, indices, gb_count_of(indices), "");
return res; return res;
} }
@@ -2666,9 +2651,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = { LLVMTypeRef types[1] = {
lb_type(p->module, t_uintptr), lb_type(p->module, t_uintptr),
}; };
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {}; LLVMValueRef args[2] = {};
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value; args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value;
@@ -2676,7 +2658,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue res = {}; lbValue res = {};
res.type = tv.type; res.type = tv.type;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res; return res;
} }
case BuiltinProc_wasm_memory_size: case BuiltinProc_wasm_memory_size:
@@ -2685,16 +2667,13 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = { LLVMTypeRef types[1] = {
lb_type(p->module, t_uintptr), lb_type(p->module, t_uintptr),
}; };
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {}; LLVMValueRef args[1] = {};
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value; args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_uintptr).value;
lbValue res = {}; lbValue res = {};
res.type = tv.type; res.type = tv.type;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res; return res;
} }
@@ -2704,9 +2683,6 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = { LLVMTypeRef types[1] = {
lb_type(p->module, t_u32), lb_type(p->module, t_u32),
}; };
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); // types, gb_count_of(types));
Type *t_u32_ptr = alloc_type_pointer(t_u32); Type *t_u32_ptr = alloc_type_pointer(t_u32);
@@ -2717,7 +2693,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
lbValue res = {}; lbValue res = {};
res.type = tv.type; res.type = tv.type;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res; return res;
} }
@@ -2727,19 +2703,16 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
LLVMTypeRef types[1] = { LLVMTypeRef types[1] = {
lb_type(p->module, t_u32), lb_type(p->module, t_u32),
}; };
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0); // types, gb_count_of(types));
Type *t_u32_ptr = alloc_type_pointer(t_u32); Type *t_u32_ptr = alloc_type_pointer(t_u32);
LLVMValueRef args[2] = {}; LLVMValueRef args[2] = {
args[0] = lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value; lb_emit_conv(p, lb_build_expr(p, ce->args[0]), t_u32_ptr).value,
args[1] = lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value; lb_emit_conv(p, lb_build_expr(p, ce->args[1]), t_u32).value };
lbValue res = {}; lbValue res = {};
res.type = tv.type; res.type = tv.type;
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
return res; return res;
} }
@@ -2748,7 +2721,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
{ {
Type *param_types[2] = {t_u32, t_u32}; Type *param_types[2] = {t_u32, t_u32};
Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), tv.type, false, ProcCC_None); Type *type = alloc_type_proc_from_types(param_types, gb_count_of(param_types), tv.type, false, ProcCC_None);
LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type)); LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
LLVMValueRef the_asm = llvm_get_inline_asm( LLVMValueRef the_asm = llvm_get_inline_asm(
func_type, func_type,
str_lit("cpuid"), str_lit("cpuid"),
@@ -2768,7 +2741,7 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
case BuiltinProc_x86_xgetbv: case BuiltinProc_x86_xgetbv:
{ {
Type *type = alloc_type_proc_from_types(&t_u32, 1, tv.type, false, ProcCC_None); Type *type = alloc_type_proc_from_types(&t_u32, 1, tv.type, false, ProcCC_None);
LLVMTypeRef func_type = LLVMGetElementType(lb_type(p->module, type)); LLVMTypeRef func_type = lb_get_procedure_raw_type(p->module, type);
LLVMValueRef the_asm = llvm_get_inline_asm( LLVMValueRef the_asm = llvm_get_inline_asm(
func_type, func_type,
str_lit("xgetbv"), str_lit("xgetbv"),
@@ -2832,10 +2805,6 @@ lbValue lb_build_call_expr(lbProcedure *p, Ast *expr) {
expr = unparen_expr(expr); expr = unparen_expr(expr);
ast_node(ce, CallExpr, expr); ast_node(ce, CallExpr, expr);
if (ce->sce_temp_data) {
return *(lbValue *)ce->sce_temp_data;
}
lbValue res = lb_build_call_expr_internal(p, expr); lbValue res = lb_build_call_expr_internal(p, expr);
if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures if (ce->optional_ok_one) { // TODO(bill): Minor hack for #optional_ok procedures
+20 -10
View File
@@ -1210,8 +1210,8 @@ void lb_build_switch_stmt(lbProcedure *p, AstSwitchStmt *ss, Scope *scope) {
} }
lb_emit_jump(p, done); lb_emit_jump(p, done);
lb_close_scope(p, lbDeferExit_Default, done);
lb_start_block(p, done); lb_start_block(p, done);
lb_close_scope(p, lbDeferExit_Default, done);
} }
void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) { void lb_store_type_case_implicit(lbProcedure *p, Ast *clause, lbValue value) {
@@ -1253,7 +1253,6 @@ void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, l
ast_node(cc, CaseClause, clause); ast_node(cc, CaseClause, clause);
lb_push_target_list(p, label, done, nullptr, nullptr); lb_push_target_list(p, label, done, nullptr, nullptr);
lb_open_scope(p, body->scope);
lb_build_stmt_list(p, cc->stmts); lb_build_stmt_list(p, cc->stmts);
lb_close_scope(p, lbDeferExit_Default, body); lb_close_scope(p, lbDeferExit_Default, body);
lb_pop_target_list(p); lb_pop_target_list(p);
@@ -1263,6 +1262,7 @@ void lb_type_case_body(lbProcedure *p, Ast *label, Ast *clause, lbBlock *body, l
void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) { void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
lbModule *m = p->module; lbModule *m = p->module;
lb_open_scope(p, ss->scope);
ast_node(as, AssignStmt, ss->tag); ast_node(as, AssignStmt, ss->tag);
GB_ASSERT(as->lhs.count == 1); GB_ASSERT(as->lhs.count == 1);
@@ -1321,6 +1321,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
for_array(i, body->stmts) { for_array(i, body->stmts) {
Ast *clause = body->stmts[i]; Ast *clause = body->stmts[i];
ast_node(cc, CaseClause, clause); ast_node(cc, CaseClause, clause);
lb_open_scope(p, cc->scope);
if (cc->list.count == 0) { if (cc->list.count == 0) {
lb_start_block(p, default_block); lb_start_block(p, default_block);
lb_store_type_case_implicit(p, clause, parent_value); lb_store_type_case_implicit(p, clause, parent_value);
@@ -1329,6 +1330,9 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
} }
lbBlock *body = lb_create_block(p, "typeswitch.body"); lbBlock *body = lb_create_block(p, "typeswitch.body");
if (p->debug_info != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, clause));
}
Type *case_type = nullptr; Type *case_type = nullptr;
for_array(type_index, cc->list) { for_array(type_index, cc->list) {
case_type = type_of_expr(cc->list[type_index]); case_type = type_of_expr(cc->list[type_index]);
@@ -1375,6 +1379,7 @@ void lb_build_type_switch_stmt(lbProcedure *p, AstTypeSwitchStmt *ss) {
lb_emit_jump(p, done); lb_emit_jump(p, done);
lb_start_block(p, done); lb_start_block(p, done);
lb_close_scope(p, lbDeferExit_Default, done);
} }
@@ -1721,6 +1726,9 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
ast_node(fs, ForStmt, node); ast_node(fs, ForStmt, node);
lb_open_scope(p, fs->scope); // Open Scope here lb_open_scope(p, fs->scope); // Open Scope here
if (p->debug_info != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node));
}
if (fs->init != nullptr) { if (fs->init != nullptr) {
#if 1 #if 1
@@ -1741,11 +1749,14 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
post = lb_create_block(p, "for.post"); post = lb_create_block(p, "for.post");
} }
lb_emit_jump(p, loop); lb_emit_jump(p, loop);
lb_start_block(p, loop); lb_start_block(p, loop);
if (loop != body) { if (loop != body) {
// right now the condition (all expressions) will not set it's debug location, so we will do it here
if (p->debug_info != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, fs->cond));
}
lb_build_cond(p, fs->cond, body, done); lb_build_cond(p, fs->cond, body, done);
lb_start_block(p, body); lb_start_block(p, body);
} }
@@ -1753,10 +1764,12 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
lb_push_target_list(p, fs->label, done, post, nullptr); lb_push_target_list(p, fs->label, done, post, nullptr);
lb_build_stmt(p, fs->body); lb_build_stmt(p, fs->body);
lb_close_scope(p, lbDeferExit_Default, nullptr);
lb_pop_target_list(p); lb_pop_target_list(p);
if (p->debug_info != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_end_location_from_ast(p, fs->body));
}
lb_emit_jump(p, post); lb_emit_jump(p, post);
if (fs->post != nullptr) { if (fs->post != nullptr) {
@@ -1766,6 +1779,7 @@ void lb_build_for_stmt(lbProcedure *p, Ast *node) {
} }
lb_start_block(p, done); lb_start_block(p, done);
lb_close_scope(p, lbDeferExit_Default, nullptr);
} }
void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) { void lb_build_assign_stmt_array(lbProcedure *p, TokenKind op, lbAddr const &lhs, lbValue const &value) {
@@ -1971,14 +1985,9 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
} }
} }
LLVMMetadataRef prev_debug_location = nullptr;
if (p->debug_info != nullptr) { if (p->debug_info != nullptr) {
prev_debug_location = LLVMGetCurrentDebugLocation2(p->builder);
LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node)); LLVMSetCurrentDebugLocation2(p->builder, lb_debug_location_from_ast(p, node));
} }
defer (if (prev_debug_location != nullptr) {
LLVMSetCurrentDebugLocation2(p->builder, prev_debug_location);
});
u16 prev_state_flags = p->state_flags; u16 prev_state_flags = p->state_flags;
defer (p->state_flags = prev_state_flags); defer (p->state_flags = prev_state_flags);
@@ -2073,7 +2082,8 @@ void lb_build_stmt(lbProcedure *p, Ast *node) {
lbAddr lval = {}; lbAddr lval = {};
if (!is_blank_ident(name)) { if (!is_blank_ident(name)) {
Entity *e = entity_of_node(name); Entity *e = entity_of_node(name);
bool zero_init = true; // Always do it // bool zero_init = true; // Always do it
bool zero_init = vd->values.count == 0;
lval = lb_add_local(p, e->type, e, zero_init); lval = lb_add_local(p, e->type, e, zero_init);
} }
array_add(&lvals, lval); array_add(&lvals, lval);
+44 -51
View File
@@ -57,6 +57,7 @@ lbValue lb_typeid(lbModule *m, Type *type) {
case Type_SimdVector: kind = Typeid_Simd_Vector; break; case Type_SimdVector: kind = Typeid_Simd_Vector; break;
case Type_RelativePointer: kind = Typeid_Relative_Pointer; break; case Type_RelativePointer: kind = Typeid_Relative_Pointer; break;
case Type_RelativeSlice: kind = Typeid_Relative_Slice; break; case Type_RelativeSlice: kind = Typeid_Relative_Slice; break;
case Type_SoaPointer: kind = Typeid_SoaPointer; break;
} }
if (is_type_cstring(type)) { if (is_type_cstring(type)) {
@@ -97,34 +98,12 @@ lbValue lb_type_info(lbModule *m, Type *type) {
isize index = lb_type_info_index(m->info, type); isize index = lb_type_info_index(m->info, type);
GB_ASSERT(index >= 0); GB_ASSERT(index >= 0);
LLVMTypeRef it = lb_type(m, t_int); lbValue data = lb_global_type_info_data_ptr(m);
LLVMValueRef indices[2] = { return lb_emit_array_epi(m, data, index);
LLVMConstInt(it, 0, false),
LLVMConstInt(it, index, true),
};
lbValue value = {};
value.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices));
value.type = t_type_info_ptr;
return value;
} }
lbValue lb_get_type_info_ptr(lbModule *m, Type *type) { LLVMTypeRef lb_get_procedure_raw_type(lbModule *m, Type *type) {
GB_ASSERT(!build_context.disallow_rtti); return lb_type_internal_for_procedures_raw(m, type);
i32 index = cast(i32)lb_type_info_index(m->info, type);
GB_ASSERT(index >= 0);
// gb_printf_err("%d %s\n", index, type_to_string(type));
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(m, t_int), 0, false),
LLVMConstInt(lb_type(m, t_int), index, false),
};
lbValue res = {};
res.type = t_type_info_ptr;
res.value = LLVMConstGEP(lb_global_type_info_data_ptr(m).value, indices, cast(unsigned)gb_count_of(indices));
return res;
} }
@@ -178,10 +157,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)}; LLVMValueRef indices[2] = {llvm_zero(m), llvm_zero(m)};
LLVMValueRef values[2] = { LLVMValueRef values[2] = {
LLVMConstInBoundsGEP(lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)), LLVMConstInBoundsGEP2(lb_type(m, lb_global_type_info_data_entity->type), lb_global_type_info_data_ptr(m).value, indices, gb_count_of(indices)),
LLVMConstInt(lb_type(m, t_int), type->Array.count, true), LLVMConstInt(lb_type(m, t_int), type->Array.count, true),
}; };
LLVMValueRef slice = llvm_const_named_struct_internal(llvm_addr_type(global_type_table), values, gb_count_of(values)); LLVMValueRef slice = llvm_const_named_struct_internal(lb_type(m, type_deref(global_type_table.type)), values, gb_count_of(values));
LLVMSetInitializer(global_type_table.value, slice); LLVMSetInitializer(global_type_table.value, slice);
} }
@@ -260,7 +239,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef vals[4] = { LLVMValueRef vals[4] = {
lb_const_string(p->module, t->Named.type_name->token.string).value, lb_const_string(p->module, t->Named.type_name->token.string).value,
lb_get_type_info_ptr(m, t->Named.base).value, lb_type_info(m, t->Named.base).value,
pkg_name, pkg_name,
loc.value loc.value
}; };
@@ -419,7 +398,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
case Type_Pointer: { case Type_Pointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr); tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_pointer_ptr);
lbValue gep = lb_get_type_info_ptr(m, t->Pointer.elem); lbValue gep = lb_type_info(m, t->Pointer.elem);
LLVMValueRef vals[1] = { LLVMValueRef vals[1] = {
gep.value, gep.value,
@@ -433,7 +412,21 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
} }
case Type_MultiPointer: { case Type_MultiPointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_multi_pointer_ptr); tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_multi_pointer_ptr);
lbValue gep = lb_get_type_info_ptr(m, t->MultiPointer.elem); lbValue gep = lb_type_info(m, t->MultiPointer.elem);
LLVMValueRef vals[1] = {
gep.value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(m, res.type, vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_SoaPointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_soa_pointer_ptr);
lbValue gep = lb_type_info(m, t->SoaPointer.elem);
LLVMValueRef vals[1] = { LLVMValueRef vals[1] = {
gep.value, gep.value,
@@ -450,7 +443,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
i64 ez = type_size_of(t->Array.elem); i64 ez = type_size_of(t->Array.elem);
LLVMValueRef vals[3] = { LLVMValueRef vals[3] = {
lb_get_type_info_ptr(m, t->Array.elem).value, lb_type_info(m, t->Array.elem).value,
lb_const_int(m, t_int, ez).value, lb_const_int(m, t_int, ez).value,
lb_const_int(m, t_int, t->Array.count).value, lb_const_int(m, t_int, t->Array.count).value,
}; };
@@ -465,8 +458,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr); tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_enumerated_array_ptr);
LLVMValueRef vals[7] = { LLVMValueRef vals[7] = {
lb_get_type_info_ptr(m, t->EnumeratedArray.elem).value, lb_type_info(m, t->EnumeratedArray.elem).value,
lb_get_type_info_ptr(m, t->EnumeratedArray.index).value, lb_type_info(m, t->EnumeratedArray.index).value,
lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value, lb_const_int(m, t_int, type_size_of(t->EnumeratedArray.elem)).value,
lb_const_int(m, t_int, t->EnumeratedArray.count).value, lb_const_int(m, t_int, t->EnumeratedArray.count).value,
@@ -497,7 +490,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr); tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_dynamic_array_ptr);
LLVMValueRef vals[2] = { LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->DynamicArray.elem).value, lb_type_info(m, t->DynamicArray.elem).value,
lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value, lb_const_int(m, t_int, type_size_of(t->DynamicArray.elem)).value,
}; };
@@ -511,7 +504,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr); tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_slice_ptr);
LLVMValueRef vals[2] = { LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->Slice.elem).value, lb_type_info(m, t->Slice.elem).value,
lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value, lb_const_int(m, t_int, type_size_of(t->Slice.elem)).value,
}; };
@@ -527,10 +520,10 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr)); LLVMValueRef params = LLVMConstNull(lb_type(m, t_type_info_ptr));
LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr)); LLVMValueRef results = LLVMConstNull(lb_type(m, t_type_info_ptr));
if (t->Proc.params != nullptr) { if (t->Proc.params != nullptr) {
params = lb_get_type_info_ptr(m, t->Proc.params).value; params = lb_type_info(m, t->Proc.params).value;
} }
if (t->Proc.results != nullptr) { if (t->Proc.results != nullptr) {
results = lb_get_type_info_ptr(m, t->Proc.results).value; results = lb_type_info(m, t->Proc.results).value;
} }
LLVMValueRef vals[4] = { LLVMValueRef vals[4] = {
@@ -649,7 +642,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
// NOTE(bill): Zeroth is nil so ignore it // NOTE(bill): Zeroth is nil so ignore it
for (isize variant_index = 0; variant_index < variant_count; variant_index++) { for (isize variant_index = 0; variant_index < variant_count; variant_index++) {
Type *vt = t->Union.variants[variant_index]; Type *vt = t->Union.variants[variant_index];
lbValue tip = lb_get_type_info_ptr(m, vt); lbValue tip = lb_type_info(m, vt);
lbValue index = lb_const_int(m, t_int, variant_index); lbValue index = lb_const_int(m, t_int, variant_index);
lbValue type_info = lb_emit_ptr_offset(p, memory_types, index); lbValue type_info = lb_emit_ptr_offset(p, memory_types, index);
@@ -737,7 +730,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
for (isize source_index = 0; source_index < count; source_index++) { for (isize source_index = 0; source_index < count; source_index++) {
// TODO(bill): Order fields in source order not layout order // TODO(bill): Order fields in source order not layout order
Entity *f = t->Struct.fields[source_index]; Entity *f = t->Struct.fields[source_index];
lbValue tip = lb_get_type_info_ptr(m, f->type); lbValue tip = lb_type_info(m, f->type);
i64 foffset = 0; i64 foffset = 0;
if (!t->Struct.is_raw_union) { if (!t->Struct.is_raw_union) {
GB_ASSERT(t->Struct.offsets != nullptr); GB_ASSERT(t->Struct.offsets != nullptr);
@@ -794,11 +787,11 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr); tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_map_ptr);
init_map_internal_types(t); init_map_internal_types(t);
lbValue gst = lb_get_type_info_ptr(m, t->Map.generated_struct_type); lbValue gst = lb_type_info(m, t->Map.generated_struct_type);
LLVMValueRef vals[5] = { LLVMValueRef vals[5] = {
lb_get_type_info_ptr(m, t->Map.key).value, lb_type_info(m, t->Map.key).value,
lb_get_type_info_ptr(m, t->Map.value).value, lb_type_info(m, t->Map.value).value,
gst.value, gst.value,
lb_get_equal_proc_for_type(m, t->Map.key).value, lb_get_equal_proc_for_type(m, t->Map.key).value,
lb_get_hasher_proc_for_type(m, t->Map.key).value lb_get_hasher_proc_for_type(m, t->Map.key).value
@@ -819,13 +812,13 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef vals[4] = { LLVMValueRef vals[4] = {
lb_get_type_info_ptr(m, t->BitSet.elem).value, lb_type_info(m, t->BitSet.elem).value,
LLVMConstNull(lb_type(m, t_type_info_ptr)), LLVMConstNull(lb_type(m, t_type_info_ptr)),
lb_const_int(m, t_i64, t->BitSet.lower).value, lb_const_int(m, t_i64, t->BitSet.lower).value,
lb_const_int(m, t_i64, t->BitSet.upper).value, lb_const_int(m, t_i64, t->BitSet.upper).value,
}; };
if (t->BitSet.underlying != nullptr) { if (t->BitSet.underlying != nullptr) {
vals[1] =lb_get_type_info_ptr(m, t->BitSet.underlying).value; vals[1] =lb_type_info(m, t->BitSet.underlying).value;
} }
lbValue res = {}; lbValue res = {};
@@ -841,7 +834,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
LLVMValueRef vals[3] = {}; LLVMValueRef vals[3] = {};
vals[0] = lb_get_type_info_ptr(m, t->SimdVector.elem).value; vals[0] = lb_type_info(m, t->SimdVector.elem).value;
vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value; vals[1] = lb_const_int(m, t_int, type_size_of(t->SimdVector.elem)).value;
vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value; vals[2] = lb_const_int(m, t_int, t->SimdVector.count).value;
@@ -856,8 +849,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
{ {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr); tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_pointer_ptr);
LLVMValueRef vals[2] = { LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->RelativePointer.pointer_type).value, lb_type_info(m, t->RelativePointer.pointer_type).value,
lb_get_type_info_ptr(m, t->RelativePointer.base_integer).value, lb_type_info(m, t->RelativePointer.base_integer).value,
}; };
lbValue res = {}; lbValue res = {};
@@ -870,8 +863,8 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
{ {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr); tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_relative_slice_ptr);
LLVMValueRef vals[2] = { LLVMValueRef vals[2] = {
lb_get_type_info_ptr(m, t->RelativeSlice.slice_type).value, lb_type_info(m, t->RelativeSlice.slice_type).value,
lb_get_type_info_ptr(m, t->RelativeSlice.base_integer).value, lb_type_info(m, t->RelativeSlice.base_integer).value,
}; };
lbValue res = {}; lbValue res = {};
@@ -886,7 +879,7 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
i64 ez = type_size_of(t->Matrix.elem); i64 ez = type_size_of(t->Matrix.elem);
LLVMValueRef vals[5] = { LLVMValueRef vals[5] = {
lb_get_type_info_ptr(m, t->Matrix.elem).value, lb_type_info(m, t->Matrix.elem).value,
lb_const_int(m, t_int, ez).value, lb_const_int(m, t_int, ez).value,
lb_const_int(m, t_int, matrix_type_stride_in_elems(t)).value, lb_const_int(m, t_int, matrix_type_stride_in_elems(t)).value,
lb_const_int(m, t_int, t->Matrix.row_count).value, lb_const_int(m, t_int, t->Matrix.row_count).value,
+165 -183
View File
@@ -1,3 +1,5 @@
lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name);
bool lb_is_type_aggregate(Type *t) { bool lb_is_type_aggregate(Type *t) {
t = base_type(t); t = base_type(t);
switch (t->kind) { switch (t->kind) {
@@ -37,6 +39,12 @@ bool lb_is_type_aggregate(Type *t) {
return false; return false;
} }
void lb_emit_unreachable(lbProcedure *p) {
LLVMValueRef instr = LLVMGetLastInstruction(p->curr_block->block);
if (instr == nullptr || !lb_is_instr_terminating(instr)) {
LLVMBuildUnreachable(p->builder);
}
}
lbValue lb_correct_endianness(lbProcedure *p, lbValue value) { lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
Type *src = core_type(value.type); Type *src = core_type(value.type);
@@ -48,18 +56,19 @@ lbValue lb_correct_endianness(lbProcedure *p, lbValue value) {
return value; return value;
} }
void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) { LLVMValueRef lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len, unsigned alignment, bool is_volatile) {
bool is_inlinable = false; bool is_inlinable = false;
i64 const_len = 0; i64 const_len = 0;
if (LLVMIsConstant(len)) { if (LLVMIsConstant(len)) {
const_len = cast(i64)LLVMConstIntGetSExtValue(len); const_len = cast(i64)LLVMConstIntGetSExtValue(len);
// TODO(bill): Determine when it is better to do the `*.inline` versions // TODO(bill): Determine when it is better to do the `*.inline` versions
if (const_len <= 4*build_context.word_size) { if (const_len <= lb_max_zero_init_size()) {
is_inlinable = true; is_inlinable = true;
} }
} }
char const *name = "llvm.memset"; char const *name = "llvm.memset";
if (is_inlinable) { if (is_inlinable) {
name = "llvm.memset.inline"; name = "llvm.memset.inline";
@@ -69,17 +78,28 @@ void lb_mem_zero_ptr_internal(lbProcedure *p, LLVMValueRef ptr, LLVMValueRef len
lb_type(p->module, t_rawptr), lb_type(p->module, t_rawptr),
lb_type(p->module, t_int) lb_type(p->module, t_int)
}; };
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); if (true || is_inlinable) {
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s.%s", name, LLVMPrintTypeToString(types[0]), LLVMPrintTypeToString(types[1]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[4] = {}; LLVMValueRef args[4] = {};
args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], ""); args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
args[1] = LLVMConstInt(LLVMInt8TypeInContext(p->module->ctx), 0, false); args[1] = LLVMConstInt(LLVMInt8TypeInContext(p->module->ctx), 0, false);
args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, ""); args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), is_volatile, false); args[3] = LLVMConstInt(LLVMInt1TypeInContext(p->module->ctx), is_volatile, false);
return lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
} else {
lbValue pr = lb_lookup_runtime_procedure(p->module, str_lit("memset"));
LLVMValueRef args[3] = {};
args[0] = LLVMBuildPointerCast(p->builder, ptr, types[0], "");
args[1] = LLVMConstInt(LLVMInt32TypeInContext(p->module->ctx), 0, false);
args[2] = LLVMBuildIntCast2(p->builder, len, types[1], /*signed*/false, "");
// We always get the function pointer type rather than the function and there is apparently no way around that?
LLVMTypeRef type = lb_type_internal_for_procedures_raw(p->module, pr.type);
return LLVMBuildCall2(p->builder, type, pr.value, args, gb_count_of(args), "");
}
LLVMBuildCall(p->builder, ip, args, gb_count_of(args), "");
} }
void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment) { void lb_mem_zero_ptr(lbProcedure *p, LLVMValueRef ptr, Type *type, unsigned alignment) {
@@ -335,40 +355,57 @@ lbValue lb_emit_or_else(lbProcedure *p, Ast *arg, Ast *else_expr, TypeAndValue c
lbValue rhs = {}; lbValue rhs = {};
lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs); lb_emit_try_lhs_rhs(p, arg, tv, &lhs, &rhs);
LLVMValueRef incoming_values[2] = {};
LLVMBasicBlockRef incoming_blocks[2] = {};
GB_ASSERT(else_expr != nullptr); GB_ASSERT(else_expr != nullptr);
lbBlock *then = lb_create_block(p, "or_else.then");
lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later
lbBlock *else_ = lb_create_block(p, "or_else.else");
lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
lb_start_block(p, then);
Type *type = default_type(tv.type); Type *type = default_type(tv.type);
incoming_values[0] = lb_emit_conv(p, lhs, type).value; if (is_diverging_expr(else_expr)) {
lbBlock *then = lb_create_block(p, "or_else.then");
lbBlock *else_ = lb_create_block(p, "or_else.else");
lb_emit_jump(p, done); lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
lb_start_block(p, else_); // NOTE(bill): else block needs to be straight afterwards to make sure that the actual value is used
// from the then block
lb_start_block(p, else_);
incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value; lb_build_expr(p, else_expr);
lb_emit_unreachable(p); // add just in case
lb_emit_jump(p, done); lb_start_block(p, then);
lb_start_block(p, done); return lb_emit_conv(p, lhs, type);
} else {
LLVMValueRef incoming_values[2] = {};
LLVMBasicBlockRef incoming_blocks[2] = {};
lbValue res = {}; lbBlock *then = lb_create_block(p, "or_else.then");
res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), ""); lbBlock *done = lb_create_block(p, "or_else.done"); // NOTE(bill): Append later
res.type = type; lbBlock *else_ = lb_create_block(p, "or_else.else");
GB_ASSERT(p->curr_block->preds.count >= 2); lb_emit_if(p, lb_emit_try_has_value(p, rhs), then, else_);
incoming_blocks[0] = p->curr_block->preds[0]->block; lb_start_block(p, then);
incoming_blocks[1] = p->curr_block->preds[1]->block;
LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2); incoming_values[0] = lb_emit_conv(p, lhs, type).value;
return res; lb_emit_jump(p, done);
lb_start_block(p, else_);
incoming_values[1] = lb_emit_conv(p, lb_build_expr(p, else_expr), type).value;
lb_emit_jump(p, done);
lb_start_block(p, done);
lbValue res = {};
res.value = LLVMBuildPhi(p->builder, lb_type(p->module, type), "");
res.type = type;
GB_ASSERT(p->curr_block->preds.count >= 2);
incoming_blocks[0] = p->curr_block->preds[0]->block;
incoming_blocks[1] = p->curr_block->preds[1]->block;
LLVMAddIncoming(res.value, incoming_values, incoming_blocks, 2);
return res;
}
} }
void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results); void lb_build_return_stmt(lbProcedure *p, Slice<Ast *> const &return_results);
@@ -445,15 +482,11 @@ lbValue lb_emit_byte_swap(lbProcedure *p, lbValue value, Type *end_type) {
char const *name = "llvm.bswap"; char const *name = "llvm.bswap";
LLVMTypeRef types[1] = {lb_type(p->module, value.type)}; LLVMTypeRef types[1] = {lb_type(p->module, value.type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {}; LLVMValueRef args[1] = { value.value };
args[0] = value.value;
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = value.type; res.type = value.type;
if (is_type_float(original_type)) { if (is_type_float(original_type)) {
@@ -471,15 +504,10 @@ lbValue lb_emit_count_ones(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.ctpop"; char const *name = "llvm.ctpop";
LLVMTypeRef types[1] = {lb_type(p->module, type)}; LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); LLVMValueRef args[1] = { x.value };
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {};
args[0] = x.value;
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type; res.type = type;
return res; return res;
} }
@@ -500,16 +528,13 @@ lbValue lb_emit_count_trailing_zeros(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.cttz"; char const *name = "llvm.cttz";
LLVMTypeRef types[1] = {lb_type(p->module, type)}; LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {}; LLVMValueRef args[2] = {
args[0] = x.value; x.value,
args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)); LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)) };
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type; res.type = type;
return res; return res;
} }
@@ -519,16 +544,13 @@ lbValue lb_emit_count_leading_zeros(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.ctlz"; char const *name = "llvm.ctlz";
LLVMTypeRef types[1] = {lb_type(p->module, type)}; LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[2] = {}; LLVMValueRef args[2] = {
args[0] = x.value; x.value,
args[1] = LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)); LLVMConstNull(LLVMInt1TypeInContext(p->module->ctx)) };
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type; res.type = type;
return res; return res;
} }
@@ -540,15 +562,11 @@ lbValue lb_emit_reverse_bits(lbProcedure *p, lbValue x, Type *type) {
char const *name = "llvm.bitreverse"; char const *name = "llvm.bitreverse";
LLVMTypeRef types[1] = {lb_type(p->module, type)}; LLVMTypeRef types[1] = {lb_type(p->module, type)};
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
GB_ASSERT_MSG(id != 0, "Unable to find %s.%s", name, LLVMPrintTypeToString(types[0]));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef args[1] = {}; LLVMValueRef args[1] = { x.value };
args[0] = x.value;
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildCall(p->builder, ip, args, gb_count_of(args), ""); res.value = lb_call_intrinsic(p, name, args, gb_count_of(args), types, gb_count_of(types));
res.type = type; res.type = type;
return res; return res;
} }
@@ -969,6 +987,11 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
case 0: result_type = t->RelativeSlice.base_integer; break; case 0: result_type = t->RelativeSlice.base_integer; break;
case 1: result_type = t->RelativeSlice.base_integer; break; case 1: result_type = t->RelativeSlice.base_integer; break;
} }
} else if (is_type_soa_pointer(t)) {
switch (index) {
case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break;
case 1: result_type = t_int; break;
}
} else { } else {
GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index); GB_PANIC("TODO(bill): struct_gep type: %s, %d", type_to_string(s.type), index);
} }
@@ -979,15 +1002,16 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
index = lb_convert_struct_index(p->module, t, index); index = lb_convert_struct_index(p->module, t, index);
if (lb_is_const(s)) { if (lb_is_const(s)) {
// NOTE(bill): this cannot be replaced with lb_emit_epi
lbModule *m = p->module; lbModule *m = p->module;
lbValue res = {}; lbValue res = {};
LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)}; LLVMValueRef indices[2] = {llvm_zero(m), LLVMConstInt(lb_type(m, t_i32), index, false)};
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); res.value = LLVMConstGEP2(lb_type(m, type_deref(s.type)), s.value, indices, gb_count_of(indices));
res.type = alloc_type_pointer(result_type); res.type = alloc_type_pointer(result_type);
return res; return res;
} else { } else {
lbValue res = {}; lbValue res = {};
LLVMTypeRef st = LLVMGetElementType(LLVMTypeOf(s.value)); LLVMTypeRef st = lb_type(p->module, type_deref(s.type));
// gb_printf_err("%s\n", type_to_string(s.type)); // gb_printf_err("%s\n", type_to_string(s.type));
// gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value))); // gb_printf_err("%s\n", LLVMPrintTypeToString(LLVMTypeOf(s.value)));
// gb_printf_err("%d\n", index); // gb_printf_err("%d\n", index);
@@ -995,7 +1019,7 @@ lbValue lb_emit_struct_ep(lbProcedure *p, lbValue s, i32 index) {
unsigned count = LLVMCountStructElementTypes(st); unsigned count = LLVMCountStructElementTypes(st);
GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index); GB_ASSERT_MSG(count >= cast(unsigned)index, "%u %d %d", count, index, original_index);
res.value = LLVMBuildStructGEP(p->builder, s.value, cast(unsigned)index, ""); res.value = LLVMBuildStructGEP2(p->builder, st, s.value, cast(unsigned)index, "");
res.type = alloc_type_pointer(result_type); res.type = alloc_type_pointer(result_type);
return res; return res;
} }
@@ -1099,6 +1123,13 @@ lbValue lb_emit_struct_ev(lbProcedure *p, lbValue s, i32 index) {
result_type = t->Array.elem; result_type = t->Array.elem;
break; break;
case Type_SoaPointer:
switch (index) {
case 0: result_type = alloc_type_pointer(t->SoaPointer.elem); break;
case 1: result_type = t_int; break;
}
break;
default: default:
GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s.type), index); GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s.type), index);
break; break;
@@ -1126,7 +1157,28 @@ lbValue lb_emit_deep_field_gep(lbProcedure *p, lbValue e, Selection sel) {
} }
type = core_type(type); type = core_type(type);
if (is_type_quaternion(type)) { if (type->kind == Type_SoaPointer) {
lbValue addr = lb_emit_struct_ep(p, e, 0);
lbValue index = lb_emit_struct_ep(p, e, 1);
addr = lb_emit_load(p, addr);
index = lb_emit_load(p, index);
i32 first_index = sel.index[0];
Selection sub_sel = sel;
sub_sel.index.data += 1;
sub_sel.index.count -= 1;
lbValue arr = lb_emit_struct_ep(p, addr, first_index);
Type *t = base_type(type_deref(addr.type));
GB_ASSERT(is_type_soa_struct(t));
if (t->Struct.soa_kind == StructSoa_Fixed) {
e = lb_emit_array_ep(p, arr, index);
} else {
e = lb_emit_ptr_offset(p, lb_emit_load(p, arr), index);
}
} else if (is_type_quaternion(type)) {
e = lb_emit_struct_ep(p, e, index); e = lb_emit_struct_ep(p, e, index);
} else if (is_type_raw_union(type)) { } else if (is_type_raw_union(type)) {
type = get_struct_field_type(type, index); type = get_struct_field_type(type, index);
@@ -1201,7 +1253,12 @@ lbValue lb_emit_array_ep(lbProcedure *p, lbValue s, lbValue index) {
Type *ptr = base_array_type(st); Type *ptr = base_array_type(st);
lbValue res = {}; lbValue res = {};
res.value = LLVMBuildGEP(p->builder, s.value, indices, 2, "");
if (LLVMIsConstant(s.value) && LLVMIsConstant(index.value)) {
res.value = LLVMConstGEP2(lb_type(p->module, st), s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP2(p->builder, lb_type(p->module, st), s.value, indices, gb_count_of(indices), "");
}
res.type = alloc_type_pointer(ptr); res.type = alloc_type_pointer(ptr);
return res; return res;
} }
@@ -1211,24 +1268,16 @@ lbValue lb_emit_array_epi(lbProcedure *p, lbValue s, isize index) {
GB_ASSERT(is_type_pointer(t)); GB_ASSERT(is_type_pointer(t));
Type *st = base_type(type_deref(t)); Type *st = base_type(type_deref(t));
GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st)); GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st));
GB_ASSERT(0 <= index); GB_ASSERT(0 <= index);
Type *ptr = base_array_type(st); return lb_emit_epi(p, s, index);
}
lbValue lb_emit_array_epi(lbModule *m, lbValue s, isize index) {
LLVMValueRef indices[2] = { Type *t = s.type;
LLVMConstInt(lb_type(p->module, t_int), 0, false), GB_ASSERT(is_type_pointer(t));
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)index, false), Type *st = base_type(type_deref(t));
}; GB_ASSERT_MSG(is_type_array(st) || is_type_enumerated_array(st) || is_type_matrix(st), "%s", type_to_string(st));
GB_ASSERT(0 <= index);
lbValue res = {}; return lb_emit_epi(m, s, index);
if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
}
res.type = alloc_type_pointer(ptr);
return res;
} }
lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) { lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
@@ -1236,11 +1285,12 @@ lbValue lb_emit_ptr_offset(lbProcedure *p, lbValue ptr, lbValue index) {
LLVMValueRef indices[1] = {index.value}; LLVMValueRef indices[1] = {index.value};
lbValue res = {}; lbValue res = {};
res.type = ptr.type; res.type = ptr.type;
LLVMTypeRef type = lb_type(p->module, type_deref(ptr.type));
if (lb_is_const(ptr) && lb_is_const(index)) { if (lb_is_const(ptr) && lb_is_const(index)) {
res.value = LLVMConstGEP(ptr.value, indices, 1); res.value = LLVMConstGEP2(type, ptr.value, indices, 1);
} else { } else {
res.value = LLVMBuildGEP(p->builder, ptr.value, indices, 1, ""); res.value = LLVMBuildGEP2(p->builder, type, ptr.value, indices, 1, "");
} }
return res; return res;
} }
@@ -1249,63 +1299,18 @@ lbValue lb_emit_matrix_epi(lbProcedure *p, lbValue s, isize row, isize column) {
Type *t = s.type; Type *t = s.type;
GB_ASSERT(is_type_pointer(t)); GB_ASSERT(is_type_pointer(t));
Type *mt = base_type(type_deref(t)); Type *mt = base_type(type_deref(t));
Type *ptr = base_array_type(mt);
if (column == 0) { if (column == 0) {
GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt)); GB_ASSERT_MSG(is_type_matrix(mt) || is_type_array_like(mt), "%s", type_to_string(mt));
return lb_emit_epi(p, s, row);
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(p->module, t_int), 0, false),
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)row, false),
};
lbValue res = {};
if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
}
Type *ptr = base_array_type(mt);
res.type = alloc_type_pointer(ptr);
return res;
} else if (row == 0 && is_type_array_like(mt)) { } else if (row == 0 && is_type_array_like(mt)) {
LLVMValueRef indices[2] = { return lb_emit_epi(p, s, column);
LLVMConstInt(lb_type(p->module, t_int), 0, false),
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)column, false),
};
lbValue res = {};
if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
}
Type *ptr = base_array_type(mt);
res.type = alloc_type_pointer(ptr);
return res;
} }
GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt)); GB_ASSERT_MSG(is_type_matrix(mt), "%s", type_to_string(mt));
isize offset = matrix_indices_to_offset(mt, row, column); isize offset = matrix_indices_to_offset(mt, row, column);
return lb_emit_epi(p, s, offset);
LLVMValueRef indices[2] = {
LLVMConstInt(lb_type(p->module, t_int), 0, false),
LLVMConstInt(lb_type(p->module, t_int), cast(unsigned)offset, false),
};
lbValue res = {};
if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices));
} else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), "");
}
res.type = alloc_type_pointer(ptr);
return res;
} }
lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) { lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column) {
@@ -1328,11 +1333,12 @@ lbValue lb_emit_matrix_ep(lbProcedure *p, lbValue s, lbValue row, lbValue column
index, index,
}; };
LLVMTypeRef type = lb_type(p->module, mt);
lbValue res = {}; lbValue res = {};
if (lb_is_const(s)) { if (lb_is_const(s)) {
res.value = LLVMConstGEP(s.value, indices, gb_count_of(indices)); res.value = LLVMConstGEP2(type, s.value, indices, gb_count_of(indices));
} else { } else {
res.value = LLVMBuildGEP(p->builder, s.value, indices, gb_count_of(indices), ""); res.value = LLVMBuildGEP2(p->builder, type, s.value, indices, gb_count_of(indices), "");
} }
res.type = alloc_type_pointer(ptr); res.type = alloc_type_pointer(ptr);
return res; return res;
@@ -1536,18 +1542,12 @@ lbValue lb_emit_mul_add(lbProcedure *p, lbValue a, lbValue b, lbValue c, Type *t
if (is_possible) { if (is_possible) {
char const *name = "llvm.fma"; char const *name = "llvm.fma";
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); LLVMTypeRef types[1] = { lb_type(m, t) };
GB_ASSERT_MSG(id != 0, "Unable to find %s", name); LLVMValueRef values[3] = {
a.value,
LLVMTypeRef types[1] = {}; b.value,
types[0] = lb_type(m, t); c.value };
LLVMValueRef call = lb_call_intrinsic(p, name, values, gb_count_of(values), types, gb_count_of(types));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, types, gb_count_of(types));
LLVMValueRef values[3] = {};
values[0] = a.value;
values[1] = b.value;
values[2] = c.value;
LLVMValueRef call = LLVMBuildCall(p->builder, ip, values, gb_count_of(values), "");
return {call, t}; return {call, t};
} else { } else {
lbValue x = lb_emit_arith(p, Token_Mul, a, b, t); lbValue x = lb_emit_arith(p, Token_Mul, a, b, t);
@@ -1646,7 +1646,7 @@ LLVMValueRef llvm_vector_expand_to_power_of_two(lbProcedure *p, LLVMValueRef val
LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) { LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
LLVMTypeRef type = LLVMTypeOf(value); LLVMTypeRef type = LLVMTypeOf(value);
GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind); GB_ASSERT(LLVMGetTypeKind(type) == LLVMVectorTypeKind);
LLVMTypeRef elem = LLVMGetElementType(type); LLVMTypeRef elem = OdinLLVMGetVectorElementType(type);
unsigned len = LLVMGetVectorSize(type); unsigned len = LLVMGetVectorSize(type);
if (len == 0) { if (len == 0) {
return LLVMConstNull(type); return LLVMConstNull(type);
@@ -1676,15 +1676,9 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
if (id != 0 && false) { if (id != 0 && false) {
LLVMTypeRef types[1] = {}; LLVMTypeRef types[1] = { type };
types[0] = type; LLVMValueRef values[2] = { LLVMConstNull(elem), value };
return lb_call_intrinsic(p, name, values + value_offset, value_count, types, gb_count_of(types));
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, types, gb_count_of(types));
LLVMValueRef values[2] = {};
values[0] = LLVMConstNull(elem);
values[1] = value;
LLVMValueRef call = LLVMBuildCall(p->builder, ip, values+value_offset, value_count, "");
return call;
} }
// Manual reduce // Manual reduce
@@ -1728,7 +1722,7 @@ LLVMValueRef llvm_vector_reduce_add(lbProcedure *p, LLVMValueRef value) {
LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) { LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b)); GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a)); LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) { if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) {
return LLVMBuildAdd(p->builder, a, b, ""); return LLVMBuildAdd(p->builder, a, b, "");
@@ -1739,7 +1733,7 @@ LLVMValueRef llvm_vector_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) { LLVMValueRef llvm_vector_mul(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b)); GB_ASSERT(LLVMTypeOf(a) == LLVMTypeOf(b));
LLVMTypeRef elem = LLVMGetElementType(LLVMTypeOf(a)); LLVMTypeRef elem = OdinLLVMGetVectorElementType(LLVMTypeOf(a));
if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) { if (LLVMGetTypeKind(elem) == LLVMIntegerTypeKind) {
return LLVMBuildMul(p->builder, a, b, ""); return LLVMBuildMul(p->builder, a, b, "");
@@ -1753,14 +1747,13 @@ LLVMValueRef llvm_vector_dot(lbProcedure *p, LLVMValueRef a, LLVMValueRef b) {
} }
LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, LLVMValueRef c) { LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b, LLVMValueRef c) {
lbModule *m = p->module;
LLVMTypeRef t = LLVMTypeOf(a); LLVMTypeRef t = LLVMTypeOf(a);
GB_ASSERT(t == LLVMTypeOf(b)); GB_ASSERT(t == LLVMTypeOf(b));
GB_ASSERT(t == LLVMTypeOf(c)); GB_ASSERT(t == LLVMTypeOf(c));
GB_ASSERT(LLVMGetTypeKind(t) == LLVMVectorTypeKind); GB_ASSERT(LLVMGetTypeKind(t) == LLVMVectorTypeKind);
LLVMTypeRef elem = LLVMGetElementType(t); LLVMTypeRef elem = OdinLLVMGetVectorElementType(t);
bool is_possible = false; bool is_possible = false;
@@ -1776,18 +1769,9 @@ LLVMValueRef llvm_vector_mul_add(lbProcedure *p, LLVMValueRef a, LLVMValueRef b,
if (is_possible) { if (is_possible) {
char const *name = "llvm.fmuladd"; char const *name = "llvm.fmuladd";
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name)); LLVMTypeRef types[1] = { t };
GB_ASSERT_MSG(id != 0, "Unable to find %s", name); LLVMValueRef values[3] = { a, b, c};
LLVMValueRef call = lb_call_intrinsic(p, name, values, gb_count_of(values), types, gb_count_of(types));
LLVMTypeRef types[1] = {};
types[0] = t;
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(m->mod, id, types, gb_count_of(types));
LLVMValueRef values[3] = {};
values[0] = a;
values[1] = b;
values[2] = c;
LLVMValueRef call = LLVMBuildCall(p->builder, ip, values, gb_count_of(values), "");
return call; return call;
} else { } else {
LLVMValueRef x = llvm_vector_mul(p, a, b); LLVMValueRef x = llvm_vector_mul(p, a, b);
@@ -1802,7 +1786,7 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin
cast(char *)clobbers.text, cast(size_t)clobbers.len, cast(char *)clobbers.text, cast(size_t)clobbers.len,
has_side_effects, is_align_stack, has_side_effects, is_align_stack,
dialect dialect
#if LLVM_VERSION_MAJOR >= 13 #if LLVM_VERSION_MAJOR >= 13
, /*CanThrow*/false , /*CanThrow*/false
#endif #endif
); );
@@ -1842,8 +1826,6 @@ void lb_set_wasm_export_attributes(LLVMValueRef value, String export_name) {
} }
lbValue lb_lookup_runtime_procedure(lbModule *m, String const &name);
lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) { lbAddr lb_handle_objc_find_or_register_selector(lbProcedure *p, String const &name) {
lbAddr *found = string_map_get(&p->module->objc_selectors, name); lbAddr *found = string_map_get(&p->module->objc_selectors, name);
+15 -4
View File
@@ -283,6 +283,9 @@ i32 linker_stage(lbGenerator *gen) {
String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]); String vs_exe_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_VS_EXE]);
defer (gb_free(heap_allocator(), vs_exe_path.text)); defer (gb_free(heap_allocator(), vs_exe_path.text));
String windows_sdk_bin_path = path_to_string(heap_allocator(), build_context.build_paths[BuildPath_Win_SDK_Bin_Path]);
defer (gb_free(heap_allocator(), windows_sdk_bin_path.text));
char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE"; char const *subsystem_str = build_context.use_subsystem_windows ? "WINDOWS" : "CONSOLE";
if (!build_context.use_lld) { // msvc if (!build_context.use_lld) { // msvc
if (build_context.has_resource) { if (build_context.has_resource) {
@@ -292,7 +295,8 @@ i32 linker_stage(lbGenerator *gen) {
defer (gb_free(heap_allocator(), res_path.text)); defer (gb_free(heap_allocator(), res_path.text));
result = system_exec_command_line_app("msvc-link", result = system_exec_command_line_app("msvc-link",
"\"rc.exe\" /nologo /fo \"%.*s\" \"%.*s\"", "\"%.*src.exe\" /nologo /fo \"%.*s\" \"%.*s\"",
LIT(windows_sdk_bin_path),
LIT(res_path), LIT(res_path),
LIT(rc_path) LIT(rc_path)
); );
@@ -463,8 +467,15 @@ i32 linker_stage(lbGenerator *gen) {
// correctly this way since all the other dependencies provided implicitly // correctly this way since all the other dependencies provided implicitly
// by the compiler frontend are still needed and most of the command // by the compiler frontend are still needed and most of the command
// line arguments prepared previously are incompatible with ld. // line arguments prepared previously are incompatible with ld.
link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' "); if (build_context.metrics.os == TargetOs_darwin) {
link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' "); link_settings = gb_string_appendc(link_settings, "-Wl,-init,'__odin_entry_point' ");
// NOTE(weshardee): __odin_exit_point should also be added, but -fini
// does not exist on MacOS
} else {
link_settings = gb_string_appendc(link_settings, "-Wl,-init,'_odin_entry_point' ");
link_settings = gb_string_appendc(link_settings, "-Wl,-fini,'_odin_exit_point' ");
}
} else if (build_context.metrics.os != TargetOs_openbsd) { } else if (build_context.metrics.os != TargetOs_openbsd) {
// OpenBSD defaults to PIE executable. do not pass -no-pie for it. // OpenBSD defaults to PIE executable. do not pass -no-pie for it.
link_settings = gb_string_appendc(link_settings, "-no-pie "); link_settings = gb_string_appendc(link_settings, "-no-pie ");
@@ -1551,7 +1562,7 @@ bool parse_build_flags(Array<String> args) {
bad_flags = true; bad_flags = true;
break; break;
} }
build_context.resource_filepath = substring(path, 0, string_extension_position(path)); build_context.resource_filepath = path;
build_context.has_resource = true; build_context.has_resource = true;
} else { } else {
gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path)); gb_printf_err("Invalid -resource path, got %.*s\n", LIT(path));
+181 -172
View File
@@ -50,18 +50,7 @@ gb_global gbAllocator mc_allocator = heap_allocator();
struct Find_Result { struct Find_Result {
int windows_sdk_version; // Zero if no Windows SDK found. int windows_sdk_version; // Zero if no Windows SDK found.
wchar_t const *windows_sdk_root; String windows_sdk_bin_path;
wchar_t const *windows_sdk_um_library_path;
wchar_t const *windows_sdk_ucrt_library_path;
wchar_t const *vs_exe_path;
wchar_t const *vs_library_path;
};
struct Find_Result_Utf8 {
int windows_sdk_version; // Zero if no Windows SDK found.
String windows_sdk_root;
String windows_sdk_um_library_path; String windows_sdk_um_library_path;
String windows_sdk_ucrt_library_path; String windows_sdk_ucrt_library_path;
@@ -69,8 +58,6 @@ struct Find_Result_Utf8 {
String vs_library_path; String vs_library_path;
}; };
Find_Result_Utf8 find_visual_studio_and_windows_sdk_utf8();
String mc_wstring_to_string(wchar_t const *str) { String mc_wstring_to_string(wchar_t const *str) {
return string16_to_string(mc_allocator, make_string16_c(str)); return string16_to_string(mc_allocator, make_string16_c(str));
} }
@@ -87,6 +74,10 @@ String mc_concat(String a, String b, String c) {
return concatenate3_strings(mc_allocator, a, b, c); return concatenate3_strings(mc_allocator, a, b, c);
} }
String mc_concat(String a, String b, String c, String d) {
return concatenate4_strings(mc_allocator, a, b, c, d);
}
String mc_get_env(String key) { String mc_get_env(String key) {
char const * value = gb_get_env((char const *)key.text, mc_allocator); char const * value = gb_get_env((char const *)key.text, mc_allocator);
return make_string_c(value); return make_string_c(value);
@@ -219,19 +210,19 @@ struct DECLSPEC_UUID("42843719-DB4C-46C2-8E7C-64F1816EFD5B") DECLSPEC_NOVTABLE I
// The beginning of the actual code that does things. // The beginning of the actual code that does things.
struct Version_Data_Utf8 { struct Version_Data {
i32 best_version[4]; // For Windows 8 versions, only two of these numbers are used. i32 best_version[4];
String best_name; String best_name;
}; };
typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data_Utf8 *data); typedef void (*MC_Visit_Proc)(String short_name, String full_name, Version_Data *data);
bool mc_visit_files(String dir_name, Version_Data_Utf8 *data, MC_Visit_Proc proc) { bool mc_visit_files(String dir_name, Version_Data *data, MC_Visit_Proc proc) {
// Visit everything in one folder (non-recursively). If it's a directory // Visit everything in one folder (non-recursively). If it's a directory
// that doesn't start with ".", call the visit proc on it. The visit proc // that doesn't start with ".", call the visit proc on it. The visit proc
// will see if the filename conforms to the expected versioning pattern. // will see if the filename conforms to the expected versioning pattern.
String wildcard_name = mc_concat(dir_name, str_lit("\\*")); String wildcard_name = mc_concat(dir_name, str_lit("*"));
defer (mc_free(wildcard_name)); defer (mc_free(wildcard_name));
MC_Find_Data find_data; MC_Find_Data find_data;
@@ -242,7 +233,7 @@ bool mc_visit_files(String dir_name, Version_Data_Utf8 *data, MC_Visit_Proc proc
bool success = true; bool success = true;
while (success) { while (success) {
if ((find_data.file_attributes & FILE_ATTRIBUTE_DIRECTORY) && (find_data.filename[0] != '.')) { if ((find_data.file_attributes & FILE_ATTRIBUTE_DIRECTORY) && (find_data.filename[0] != '.')) {
String full_name = mc_concat(dir_name, str_lit("\\"), find_data.filename); String full_name = mc_concat(dir_name, find_data.filename);
defer (mc_free(full_name)); defer (mc_free(full_name));
proc(find_data.filename, full_name, data); proc(find_data.filename, full_name, data);
@@ -284,7 +275,7 @@ String find_windows_kit_root(HKEY key, String const version) {
return value; return value;
} }
void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) { void win10_best(String short_name, String full_name, Version_Data *data) {
// Find the Windows 10 subdirectory with the highest version number. // Find the Windows 10 subdirectory with the highest version number.
int i0, i1, i2, i3; int i0, i1, i2, i3;
@@ -304,11 +295,11 @@ void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) {
// we have to copy_string and free here because visit_files free's the full_name string // we have to copy_string and free here because visit_files free's the full_name string
// after we execute this function, so Win*_Data would contain an invalid pointer. // after we execute this function, so Win*_Data would contain an invalid pointer.
if (data->best_name.len > 0) mc_free(data->best_name); if (data->best_name.len) mc_free(data->best_name);
data->best_name = copy_string(mc_allocator, full_name); data->best_name = copy_string(mc_allocator, full_name);
if (data->best_name.len > 0) { if (data->best_name.len) {
data->best_version[0] = i0; data->best_version[0] = i0;
data->best_version[1] = i1; data->best_version[1] = i1;
data->best_version[2] = i2; data->best_version[2] = i2;
@@ -316,34 +307,8 @@ void win10_best(String short_name, String full_name, Version_Data_Utf8 *data) {
} }
} }
void win8_best(String short_name, String full_name, Version_Data_Utf8 *data) { void find_windows_kit_paths(Find_Result *result) {
// Find the Windows 8 subdirectory with the highest version number. bool sdk_found = false;
int i0, i1;
auto success = sscanf_s((const char *const)short_name.text, "winv%d.%d", &i0, &i1);
if (success < 2) return;
if (i0 < data->best_version[0]) return;
else if (i0 == data->best_version[0]) {
if (i1 < data->best_version[1]) return;
}
// we have to copy_string and free here because visit_files free's the full_name string
// after we execute this function, so Win*_Data would contain an invalid pointer.
if (data->best_name.len > 0) mc_free(data->best_name);
data->best_name = copy_string(mc_allocator, full_name);
if (data->best_name.len > 0) {
data->best_version[0] = i0;
data->best_version[1] = i1;
}
}
void find_windows_kit_root(Find_Result_Utf8 *result) {
// Information about the Windows 10 and Windows 8 development kits
// is stored in the same place in the registry. We open a key
// to that place, first checking preferntially for a Windows 10 kit,
// then, if that's not found, a Windows 8 kit.
HKEY main_key; HKEY main_key;
@@ -355,44 +320,42 @@ void find_windows_kit_root(Find_Result_Utf8 *result) {
// Look for a Windows 10 entry. // Look for a Windows 10 entry.
String windows10_root = find_windows_kit_root(main_key, str_lit("KitsRoot10")); String windows10_root = find_windows_kit_root(main_key, str_lit("KitsRoot10"));
if (windows10_root.len > 0) { if (windows10_root.len) {
defer (mc_free(windows10_root)); defer (mc_free(windows10_root));
String windows10_lib = mc_concat(windows10_root, str_lit("Lib")); String windows10_lib = mc_concat(windows10_root, str_lit("Lib\\"));
Version_Data data_lib = {0};
mc_visit_files(windows10_lib, &data_lib, win10_best);
defer (mc_free(windows10_lib)); defer (mc_free(windows10_lib));
defer (mc_free(data_lib.best_name));
Version_Data_Utf8 data = {0}; String windows10_bin = mc_concat(windows10_root, str_lit("bin\\"));
mc_visit_files(windows10_lib, &data, win10_best); Version_Data data_bin = {0};
if (data.best_name.len > 0) { mc_visit_files(windows10_bin, &data_bin, win10_best);
result->windows_sdk_version = 10; defer (mc_free(windows10_bin));
result->windows_sdk_root = mc_concat(data.best_name, str_lit("\\")); defer (mc_free(data_bin.best_name));
return;
if (data_lib.best_name.len && data_bin.best_name.len) {
if (build_context.metrics.arch == TargetArch_amd64) {
result->windows_sdk_um_library_path = mc_concat(data_lib.best_name, str_lit("\\um\\x64\\"));
result->windows_sdk_ucrt_library_path = mc_concat(data_lib.best_name, str_lit("\\ucrt\\x64\\"));
result->windows_sdk_bin_path = mc_concat(data_bin.best_name, str_lit("\\x64\\"));
sdk_found = true;
} else if (build_context.metrics.arch == TargetArch_i386) {
result->windows_sdk_um_library_path = mc_concat(data_lib.best_name, str_lit("\\um\\x86\\"));
result->windows_sdk_ucrt_library_path = mc_concat(data_lib.best_name, str_lit("\\ucrt\\x86\\"));
result->windows_sdk_bin_path = mc_concat(data_bin.best_name, str_lit("\\x86\\"));
sdk_found = true;
}
} }
mc_free(data.best_name);
} }
// Look for a Windows 8 entry. if (sdk_found) {
String windows8_root = find_windows_kit_root(main_key, str_lit("KitsRoot81")); result->windows_sdk_version = 10;
if (windows8_root.len > 0) {
defer (mc_free(windows8_root));
String windows8_lib = mc_concat(windows8_root, str_lit("Lib"));
defer (mc_free(windows8_lib));
Version_Data_Utf8 data = {0};
mc_visit_files(windows8_lib, &data, win8_best);
if (data.best_name.len > 0) {
result->windows_sdk_version = 8;
result->windows_sdk_root = mc_concat(data.best_name, str_lit("\\"));
return;
}
mc_free(data.best_name);
} }
// If we get here, we failed to find anything.
} }
bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result_Utf8 *result) { bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result *result) {
// The name of this procedure is kind of cryptic. Its purpose is // The name of this procedure is kind of cryptic. Its purpose is
// to fight through Microsoft craziness. The things that the fine // to fight through Microsoft craziness. The things that the fine
// Visual Studio team want you to do, JUST TO FIND A SINGLE FOLDER // Visual Studio team want you to do, JUST TO FIND A SINGLE FOLDER
@@ -555,54 +518,97 @@ bool find_visual_studio_by_fighting_through_microsoft_craziness(Find_Result_Utf8
} }
// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both // NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both
// official and portable installations (like mmozeiko's portable msvc script). This will only use // official and portable installations (like mmozeiko's portable msvc script).
// the first paths it finds, and won't overwrite any values that `result` already has. void find_windows_kit_paths_from_env_vars(Find_Result *result) {
bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) { if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
return false; return;
} }
// We can find windows sdk using the following combination of env vars: // We can find windows sdk lib dir using the following combination of env vars:
// (UniversalCRTSdkDir or WindowsSdkDir) and (WindowsSDKLibVersion or WindowsSDKVersion) // (WindowsSdkDir or UniversalCRTSdkDir) and (WindowsSDKVersion or WindowsSDKLibVersion)
bool sdk_found = false; bool sdk_lib_found = false;
// We can find windows sdk bin dir using the following combination of env vars:
// (WindowsSdkVerBinPath) or ((WindowsSdkBinPath or WindowsSdkDir or UniversalCRTSdkDir) and (WindowsSDKVersion || WindowsSDKLibVersion))
bool sdk_bin_found = false;
// These appear to be suitable env vars used by Visual Studio // These appear to be suitable env vars used by Visual Studio
String win_sdk_ver_env = mc_get_env(str_lit("WindowsSDKVersion")); String win_sdk_ver_env = mc_get_env(str_lit("WindowsSDKVersion"));
String win_sdk_lib_env = mc_get_env(str_lit("WindowsSDKLibVersion")); String win_sdk_lib_ver_env = mc_get_env(str_lit("WindowsSDKLibVersion"));
String win_sdk_dir_env = mc_get_env(str_lit("WindowsSdkDir")); String win_sdk_dir_env = mc_get_env(str_lit("WindowsSdkDir"));
String crt_sdk_dir_env = mc_get_env(str_lit("UniversalCRTSdkDir")); String crt_sdk_dir_env = mc_get_env(str_lit("UniversalCRTSdkDir"));
String win_sdk_bin_path_env = mc_get_env(str_lit("WindowsSdkBinPath"));
String win_sdk_ver_bin_path_env = mc_get_env(str_lit("WindowsSdkVerBinPath"));
defer ({ defer ({
mc_free(win_sdk_ver_env); mc_free(win_sdk_ver_env);
mc_free(win_sdk_lib_env); mc_free(win_sdk_lib_ver_env);
mc_free(win_sdk_dir_env); mc_free(win_sdk_dir_env);
mc_free(crt_sdk_dir_env); mc_free(crt_sdk_dir_env);
mc_free(win_sdk_bin_path_env);
mc_free(win_sdk_ver_bin_path_env);
}); });
if (win_sdk_ver_bin_path_env.len || ((win_sdk_bin_path_env.len || win_sdk_dir_env.len || crt_sdk_dir_env.len) && (win_sdk_ver_env.len || win_sdk_lib_ver_env.len))) {
String bin;
defer (mc_free(bin));
if (win_sdk_ver_bin_path_env.len) {
String dir = win_sdk_ver_bin_path_env;
// Add trailing '\' in case it was missing
bin = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
} else {
String dir = win_sdk_bin_path_env.len ? win_sdk_bin_path_env : win_sdk_dir_env.len ? win_sdk_dir_env : crt_sdk_dir_env;
String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_ver_env;
// Add trailing '\' in case it was missing
dir = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
ver = mc_concat(ver, ver[ver.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
defer (mc_free(dir));
defer (mc_free(ver));
// Append "bin" for win_sdk_dir_env and crt_sdk_dir_env
String dir_bin = mc_concat(dir, win_sdk_bin_path_env.len ? str_lit("") : str_lit("bin\\"));
defer (mc_free(dir_bin));
bin = mc_concat(dir_bin, ver);
}
if (build_context.metrics.arch == TargetArch_amd64) {
result->windows_sdk_bin_path = mc_concat(bin, str_lit("x64\\"));
sdk_bin_found = true;
} else if (build_context.metrics.arch == TargetArch_i386) {
result->windows_sdk_bin_path = mc_concat(bin, str_lit("x86\\"));
sdk_bin_found = true;
}
}
// NOTE(WalterPlinge): If any combination is found, let's just assume they are correct // NOTE(WalterPlinge): If any combination is found, let's just assume they are correct
if ((win_sdk_ver_env.len || win_sdk_lib_env.len) && (win_sdk_dir_env.len || crt_sdk_dir_env.len)) { if ((win_sdk_ver_env.len || win_sdk_lib_ver_env.len) && (win_sdk_dir_env.len || crt_sdk_dir_env.len)) {
//? Maybe we need to handle missing '\' at end of strings, so far it doesn't seem an issue
String dir = win_sdk_dir_env.len ? win_sdk_dir_env : crt_sdk_dir_env; String dir = win_sdk_dir_env.len ? win_sdk_dir_env : crt_sdk_dir_env;
String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_env; String ver = win_sdk_ver_env.len ? win_sdk_ver_env : win_sdk_lib_ver_env;
// These have trailing '\' as we are just composing the path // Add trailing '\' in case it was missing
String um_dir = build_context.metrics.arch == TargetArch_amd64 dir = mc_concat(dir, dir[dir.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
? str_lit("um\\x64\\") ver = mc_concat(ver, ver[ver.len - 1] != '\\' ? str_lit("\\") : str_lit(""));
: str_lit("um\\x86\\"); defer (mc_free(dir));
String ucrt_dir = build_context.metrics.arch == TargetArch_amd64 defer (mc_free(ver));
? str_lit("ucrt\\x64\\")
: str_lit("ucrt\\x86\\");
result->windows_sdk_root = mc_concat(dir, str_lit("Lib\\"), ver); if (build_context.metrics.arch == TargetArch_amd64) {
result->windows_sdk_um_library_path = mc_concat(result->windows_sdk_root, um_dir); result->windows_sdk_um_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("um\\x64\\"));
result->windows_sdk_ucrt_library_path = mc_concat(result->windows_sdk_root, ucrt_dir); result->windows_sdk_ucrt_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("ucrt\\x64\\"));
sdk_lib_found = true;
sdk_found = true; } else if (build_context.metrics.arch == TargetArch_i386) {
result->windows_sdk_um_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("um\\x86\\"));
result->windows_sdk_ucrt_library_path = mc_concat(dir, str_lit("Lib\\"), ver, str_lit("ucrt\\x86\\"));
sdk_lib_found = true;
}
} }
// If we haven't found it yet, we can loop through LIB for specific folders // If we haven't found it yet, we can loop through LIB for specific folders
//? This may not be robust enough using `um\x64` and `ucrt\x64` //? This may not be robust enough using `um\x64` and `ucrt\x64`
if (!sdk_found) { if (!sdk_lib_found) {
String lib = mc_get_env(str_lit("LIB")); String lib = mc_get_env(str_lit("LIB"));
defer (mc_free(lib)); defer (mc_free(lib));
@@ -624,72 +630,67 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
continue; continue;
} }
hi = c; hi = c;
String dir = substring(lib, lo, hi);
defer (lo = hi + 1); defer (lo = hi + 1);
// Skip when there are two ;; in a row
if (lo == hi) {
continue;
}
String dir = substring(lib, lo, hi);
// Remove the last slash so we can match with the strings above // Remove the last slash so we can match with the strings above
String end = dir[dir.len - 1] == '\\' String end = dir[dir.len - 1] == '\\'
? substring(dir, 0, dir.len - 1) ? substring(dir, 0, dir.len - 1)
: substring(dir, 0, dir.len); : substring(dir, 0, dir.len);
// Find one and we can make the other
if (string_ends_with(end, um_dir)) { if (string_ends_with(end, um_dir)) {
result->windows_sdk_um_library_path = mc_concat(end, str_lit("\\")); result->windows_sdk_um_library_path = mc_concat(end, str_lit("\\"));
break;
} else if (string_ends_with(end, ucrt_dir)) { } else if (string_ends_with(end, ucrt_dir)) {
result->windows_sdk_ucrt_library_path = mc_concat(end, str_lit("\\")); result->windows_sdk_ucrt_library_path = mc_concat(end, str_lit("\\"));
}
if (result->windows_sdk_um_library_path.len && result->windows_sdk_ucrt_library_path.len) {
sdk_lib_found = true;
break; break;
} }
} }
// Get the root from the one we found, and make the other
// NOTE(WalterPlinge): we need to copy the string so that we don't risk a double free
if (result->windows_sdk_um_library_path.len > 0) {
String root = substring(result->windows_sdk_um_library_path, 0, result->windows_sdk_um_library_path.len - 1 - um_dir.len);
result->windows_sdk_root = copy_string(mc_allocator, root);
result->windows_sdk_ucrt_library_path = mc_concat(result->windows_sdk_root, ucrt_dir, str_lit("\\"));
} else if (result->windows_sdk_ucrt_library_path.len > 0) {
String root = substring(result->windows_sdk_ucrt_library_path, 0, result->windows_sdk_ucrt_library_path.len - 1 - ucrt_dir.len);
result->windows_sdk_root = copy_string(mc_allocator, root);
result->windows_sdk_um_library_path = mc_concat(result->windows_sdk_root, um_dir, str_lit("\\"));
}
if (result->windows_sdk_root.len > 0) {
sdk_found = true;
}
} }
} }
// NOTE(WalterPlinge): So far this function assumes it will only be called if MSVC was // NOTE(WalterPlinge): So far this function assumes it will only be called if MSVC was
// installed using mmozeiko's portable msvc script, which uses the windows 10 sdk. // installed using mmozeiko's portable msvc script, which uses the windows 10 sdk.
// This may need to be changed later if it ends up causing problems. // This may need to be changed later if it ends up causing problems.
if (sdk_found && result->windows_sdk_version == 0) { if (sdk_bin_found && sdk_lib_found) {
result->windows_sdk_version = 10; result->windows_sdk_version = 10;
} }
}
// NOTE(WalterPlinge): Environment variables can help to find Visual C++ and WinSDK paths for both
// official and portable installations (like mmozeiko's portable msvc script). This will only use
// the first paths it finds, and won't overwrite any values that `result` already has.
void find_visual_studio_paths_from_env_vars(Find_Result *result) {
if (build_context.metrics.arch != TargetArch_amd64 && build_context.metrics.arch != TargetArch_i386) {
return;
}
bool vs_found = false; bool vs_found = false;
if (result->vs_exe_path.len > 0 && result->vs_library_path.len > 0) {
vs_found = true;
}
// We can find visual studio using VCToolsInstallDir // We can find visual studio using VCToolsInstallDir
if (!vs_found) { String vctid = mc_get_env(str_lit("VCToolsInstallDir"));
String vctid = mc_get_env(str_lit("VCToolsInstallDir")); defer (mc_free(vctid));
defer (mc_free(vctid));
if (vctid.len) { if (vctid.len) {
String exe = build_context.metrics.arch == TargetArch_amd64 String exe = build_context.metrics.arch == TargetArch_amd64
? str_lit("bin\\Hostx64\\x64\\") ? str_lit("bin\\Hostx64\\x64\\")
: str_lit("bin\\Hostx86\\x86\\"); : str_lit("bin\\Hostx86\\x86\\");
String lib = build_context.metrics.arch == TargetArch_amd64 String lib = build_context.metrics.arch == TargetArch_amd64
? str_lit("lib\\x64\\") ? str_lit("lib\\x64\\")
: str_lit("lib\\x86\\"); : str_lit("lib\\x86\\");
result->vs_exe_path = mc_concat(vctid, exe); result->vs_exe_path = mc_concat(vctid, exe);
result->vs_library_path = mc_concat(vctid, lib); result->vs_library_path = mc_concat(vctid, lib);
vs_found = true; vs_found = true;
}
} }
// If we haven't found it yet, we can loop through Path for specific folders // If we haven't found it yet, we can loop through Path for specific folders
@@ -701,21 +702,32 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
String exe = build_context.metrics.arch == TargetArch_amd64 String exe = build_context.metrics.arch == TargetArch_amd64
? str_lit("bin\\Hostx64\\x64") ? str_lit("bin\\Hostx64\\x64")
: str_lit("bin\\Hostx86\\x86"); : str_lit("bin\\Hostx86\\x86");
// The environment variable may have an uppercase X even though the folder is lowercase
String exe2 = build_context.metrics.arch == TargetArch_amd64
? str_lit("bin\\HostX64\\x64")
: str_lit("bin\\HostX86\\x86");
String lib = build_context.metrics.arch == TargetArch_amd64 String lib = build_context.metrics.arch == TargetArch_amd64
? str_lit("lib\\x64") ? str_lit("lib\\x64")
: str_lit("lib\\x86"); : str_lit("lib\\x86");
isize lo = {0}; isize lo = {0};
isize hi = {0}; isize hi = {0};
for (isize c = 0; c < path.len; c += 1) { for (isize c = 0; c <= path.len; c += 1) {
if (path[c] != ';') { if (c != path.len && path[c] != ';') {
continue; continue;
} }
hi = c; hi = c;
String dir = substring(path, lo, hi);
defer (lo = hi + 1); defer (lo = hi + 1);
// Skip when there are two ;; in a row
if (lo == hi) {
continue;
}
String dir = substring(path, lo, hi);
// Remove the last slash so we can match with the strings above
String end = dir[dir.len - 1] == '\\' String end = dir[dir.len - 1] == '\\'
? substring(dir, 0, dir.len - 1) ? substring(dir, 0, dir.len - 1)
: substring(dir, 0, dir.len); : substring(dir, 0, dir.len);
@@ -726,7 +738,10 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
defer (mc_free(cl)); defer (mc_free(cl));
defer (mc_free(link)); defer (mc_free(link));
if (!string_ends_with(end, exe) || !gb_file_exists((char *)cl.text) || !gb_file_exists((char *)link.text)) { if (!string_ends_with(end, exe) && !string_ends_with(end, exe2)) {
continue;
}
if (!gb_file_exists((char *)cl.text) || !gb_file_exists((char *)link.text)) {
continue; continue;
} }
@@ -735,42 +750,36 @@ bool find_msvc_install_from_env_vars(Find_Result_Utf8 *result) {
result->vs_library_path = mc_concat(root, lib, str_lit("\\")); result->vs_library_path = mc_concat(root, lib, str_lit("\\"));
vs_found = true; vs_found = true;
break;
} }
} }
} }
return sdk_found && vs_found;
} }
Find_Result_Utf8 find_visual_studio_and_windows_sdk_utf8() { Find_Result find_visual_studio_and_windows_sdk() {
Find_Result_Utf8 r = {}; Find_Result r = {};
find_windows_kit_root(&r); find_windows_kit_paths(&r);
if (r.windows_sdk_root.len > 0) {
if (build_context.metrics.arch == TargetArch_amd64) {
r.windows_sdk_um_library_path = mc_concat(r.windows_sdk_root, str_lit("um\\x64\\"));
r.windows_sdk_ucrt_library_path = mc_concat(r.windows_sdk_root, str_lit("ucrt\\x64\\"));
} else if (build_context.metrics.arch == TargetArch_i386) {
r.windows_sdk_um_library_path = mc_concat(r.windows_sdk_root, str_lit("um\\x86\\"));
r.windows_sdk_ucrt_library_path = mc_concat(r.windows_sdk_root, str_lit("ucrt\\x86\\"));
}
}
find_visual_studio_by_fighting_through_microsoft_craziness(&r); find_visual_studio_by_fighting_through_microsoft_craziness(&r);
bool all_found = bool sdk_found =
r.windows_sdk_root.len > 0 && r.windows_sdk_bin_path.len &&
r.windows_sdk_um_library_path.len > 0 && r.windows_sdk_um_library_path.len &&
r.windows_sdk_ucrt_library_path.len > 0 && r.windows_sdk_ucrt_library_path.len ;
r.vs_exe_path.len > 0 &&
r.vs_library_path.len > 0;
if (!all_found) { bool vs_found =
find_msvc_install_from_env_vars(&r); r.vs_exe_path.len &&
r.vs_library_path.len ;
if (!sdk_found) {
find_windows_kit_paths_from_env_vars(&r);
}
if (!vs_found) {
find_visual_studio_paths_from_env_vars(&r);
} }
#if 0 #if 0
printf("windows_sdk_root: %.*s\n", LIT(r.windows_sdk_root)); printf("windows_sdk_bin_path: %.*s\n", LIT(r.windows_sdk_bin_path));
printf("windows_sdk_um_library_path: %.*s\n", LIT(r.windows_sdk_um_library_path)); printf("windows_sdk_um_library_path: %.*s\n", LIT(r.windows_sdk_um_library_path));
printf("windows_sdk_ucrt_library_path: %.*s\n", LIT(r.windows_sdk_ucrt_library_path)); printf("windows_sdk_ucrt_library_path: %.*s\n", LIT(r.windows_sdk_ucrt_library_path));
printf("vs_exe_path: %.*s\n", LIT(r.vs_exe_path)); printf("vs_exe_path: %.*s\n", LIT(r.vs_exe_path));
+28
View File
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<AutoVisualizer xmlns="http://schemas.microsoft.com/vstudio/debugger/natvis/2010">
<Type Name="String">
<DisplayString>{text,[len]s8}</DisplayString>
<StringView>text,[len]s8</StringView>
</Type>
<Type Name="Array&lt;*&gt;">
<DisplayString>{{ size={count} capacity={capacity} }}</DisplayString>
<Expand>
<ArrayItems>
<Size>count</Size>
<ValuePointer>data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="Slice&lt;*&gt;">
<DisplayString>{{ size={count} }}</DisplayString>
<Expand>
<ArrayItems>
<Size>count</Size>
<ValuePointer>data</ValuePointer>
</ArrayItems>
</Expand>
</Type>
<Type Name="lbProcedure">
<DisplayString>Procedure {name}</DisplayString>
</Type>
</AutoVisualizer>

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