mirror of
https://github.com/odin-lang/Odin.git
synced 2026-06-13 05:43:41 +00:00
merge upstream/master
This commit is contained in:
12
.github/workflows/ci.yml
vendored
12
.github/workflows/ci.yml
vendored
@@ -7,9 +7,9 @@ jobs:
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
- name: Download LLVM, botan
|
||||
run: sudo apt-get install llvm-11 clang-11 llvm libbotan-2-dev botan
|
||||
run: sudo apt-get install llvm-11 clang-11 libbotan-2-dev botan
|
||||
- name: build odin
|
||||
run: make release
|
||||
run: ./build_odin.sh release
|
||||
- name: Odin version
|
||||
run: ./odin version
|
||||
timeout-minutes: 1
|
||||
@@ -41,6 +41,9 @@ jobs:
|
||||
- name: Odin check examples/all for Linux i386
|
||||
run: ./odin check examples/all -vet -strict-style -target:linux_i386
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for FreeBSD amd64
|
||||
run: ./odin check examples/all -vet -strict-style -target:freebsd_amd64
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for OpenBSD amd64
|
||||
run: ./odin check examples/all -vet -strict-style -target:openbsd_amd64
|
||||
timeout-minutes: 10
|
||||
@@ -55,7 +58,7 @@ jobs:
|
||||
TMP_PATH=$(xcrun --show-sdk-path)/user/include
|
||||
echo "CPATH=$TMP_PATH" >> $GITHUB_ENV
|
||||
- name: build odin
|
||||
run: make release
|
||||
run: ./build_odin.sh release
|
||||
- name: Odin version
|
||||
run: ./odin version
|
||||
timeout-minutes: 1
|
||||
@@ -87,6 +90,9 @@ jobs:
|
||||
- name: Odin check examples/all for Darwin arm64
|
||||
run: ./odin check examples/all -vet -strict-style -target:darwin_arm64
|
||||
timeout-minutes: 10
|
||||
- name: Odin check examples/all for Linux arm64
|
||||
run: ./odin check examples/all -vet -strict-style -target:linux_arm64
|
||||
timeout-minutes: 10
|
||||
build_windows:
|
||||
runs-on: windows-2019
|
||||
steps:
|
||||
|
||||
12
Makefile
12
Makefile
@@ -30,10 +30,10 @@ ifeq ($(OS), Darwin)
|
||||
ifeq ($(shell $(LLVM_CONFIG) --version | grep -E $(LLVM_VERSION_PATTERN)),)
|
||||
ifeq ($(ARCH), arm64)
|
||||
$(error "Requirement: llvm-config must be base version 13 for arm64")
|
||||
else
|
||||
else
|
||||
$(error "Requirement: llvm-config must be base version greater than 11 for amd64/x86")
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
LDFLAGS:=$(LDFLAGS) -liconv -ldl
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
@@ -62,6 +62,12 @@ ifeq ($(OS), OpenBSD)
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
||||
endif
|
||||
ifeq ($(OS), FreeBSD)
|
||||
LLVM_CONFIG=/usr/local/bin/llvm-config11
|
||||
|
||||
CFLAGS:=$(CFLAGS) $(shell $(LLVM_CONFIG) --cxxflags --ldflags)
|
||||
LDFLAGS:=$(LDFLAGS) $(shell $(LLVM_CONFIG) --libs core native --system-libs)
|
||||
endif
|
||||
|
||||
all: debug demo
|
||||
|
||||
|
||||
140
build_odin.sh
Executable file
140
build_odin.sh
Executable file
@@ -0,0 +1,140 @@
|
||||
#!/bin/bash
|
||||
set -eu
|
||||
|
||||
GIT_SHA=$(git rev-parse --short HEAD)
|
||||
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)
|
||||
|
||||
panic() {
|
||||
printf "%s\n" "$1"
|
||||
exit 1
|
||||
}
|
||||
|
||||
version() { echo "$@" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'; }
|
||||
|
||||
config_darwin() {
|
||||
ARCH=$(uname -m)
|
||||
LLVM_CONFIG=llvm-config
|
||||
|
||||
# allow for arm only llvm's with version 13
|
||||
if [ ARCH == arm64 ]; then
|
||||
MIN_LLVM_VERSION=("13.0.0")
|
||||
else
|
||||
# allow for x86 / amd64 all llvm versions begining from 11
|
||||
MIN_LLVM_VERSION=("11.1.0")
|
||||
fi
|
||||
|
||||
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
|
||||
if [ ARCH == arm64 ]; then
|
||||
panic "Requirement: llvm-config must be base version 13 for arm64"
|
||||
else
|
||||
panic "Requirement: llvm-config must be base version greater than 11 for amd64/x86"
|
||||
fi
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -liconv -ldl"
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS -lLLVM-C"
|
||||
}
|
||||
|
||||
config_openbsd() {
|
||||
LLVM_CONFIG=/usr/local/bin/llvm-config
|
||||
|
||||
LDFLAGS="$LDFLAGS -liconv"
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
config_linux() {
|
||||
if which llvm-config > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config
|
||||
elif which llvm-config-11 > /dev/null 2>&1; then
|
||||
LLVM_CONFIG=llvm-config-11
|
||||
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
|
||||
|
||||
MIN_LLVM_VERSION=("11.0.0")
|
||||
if [ $(version $($LLVM_CONFIG --version)) -lt $(version $MIN_LLVM_VERSION) ]; then
|
||||
echo "Tried to use " $(which $LLVM_CONFIG) "version" $($LLVM_CONFIG --version)
|
||||
panic "Requirement: llvm-config must be base version greater than 11"
|
||||
fi
|
||||
|
||||
LDFLAGS="$LDFLAGS -ldl"
|
||||
CFLAGS="$CFLAGS $($LLVM_CONFIG --cxxflags --ldflags)"
|
||||
LDFLAGS="$LDFLAGS $($LLVM_CONFIG --libs core native --system-libs)"
|
||||
}
|
||||
|
||||
build_odin() {
|
||||
case $1 in
|
||||
debug)
|
||||
EXTRAFLAGS="-g"
|
||||
;;
|
||||
release)
|
||||
EXTRAFLAGS="-O3"
|
||||
;;
|
||||
release-native)
|
||||
EXTRAFLAGS="-O3 -march=native"
|
||||
;;
|
||||
nightly)
|
||||
EXTRAFLAGS="-DNIGHTLY -O3"
|
||||
;;
|
||||
*)
|
||||
panic "Build mode unsupported!"
|
||||
esac
|
||||
|
||||
set -x
|
||||
$CC src/main.cpp src/libtommath.cpp $DISABLED_WARNINGS $CFLAGS $EXTRAFLAGS $LDFLAGS -o odin
|
||||
set +x
|
||||
}
|
||||
|
||||
run_demo() {
|
||||
./odin run examples/demo/demo.odin
|
||||
}
|
||||
|
||||
case $OS in
|
||||
Linux)
|
||||
config_linux
|
||||
;;
|
||||
Darwin)
|
||||
config_darwin
|
||||
;;
|
||||
OpenBSD)
|
||||
config_openbsd
|
||||
;;
|
||||
*)
|
||||
panic "Platform unsupported!"
|
||||
esac
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
build_odin debug
|
||||
run_demo
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if [[ $# -eq 1 ]]; then
|
||||
case $1 in
|
||||
report)
|
||||
if [[ ! -f "./odin" ]]; then
|
||||
build_odin debug
|
||||
fi
|
||||
|
||||
./odin report
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
build_odin $1
|
||||
;;
|
||||
esac
|
||||
|
||||
run_demo
|
||||
exit 0
|
||||
else
|
||||
panic "Too many arguments!"
|
||||
fi
|
||||
@@ -79,7 +79,32 @@ when ODIN_OS == .Linux {
|
||||
}
|
||||
|
||||
when ODIN_OS == .OpenBSD {
|
||||
fpos_t :: i64
|
||||
fpos_t :: distinct i64
|
||||
|
||||
_IOFBF :: 0
|
||||
_IOLBF :: 1
|
||||
_IONBF :: 1
|
||||
|
||||
BUFSIZ :: 1024
|
||||
|
||||
EOF :: int(-1)
|
||||
|
||||
FOPEN_MAX :: 20
|
||||
FILENAME_MAX :: 1024
|
||||
|
||||
SEEK_SET :: 0
|
||||
SEEK_CUR :: 1
|
||||
SEEK_END :: 2
|
||||
|
||||
foreign libc {
|
||||
stderr: ^FILE
|
||||
stdin: ^FILE
|
||||
stdout: ^FILE
|
||||
}
|
||||
}
|
||||
|
||||
when ODIN_OS == .FreeBSD {
|
||||
fpos_t :: distinct i64
|
||||
|
||||
_IOFBF :: 0
|
||||
_IOLBF :: 1
|
||||
|
||||
@@ -13,21 +13,23 @@ when ODIN_OS == .Windows {
|
||||
when ODIN_OS == .Windows {
|
||||
wctrans_t :: distinct wchar_t
|
||||
wctype_t :: distinct ushort
|
||||
}
|
||||
|
||||
when ODIN_OS == .Linux {
|
||||
} else when ODIN_OS == .Linux {
|
||||
wctrans_t :: distinct intptr_t
|
||||
wctype_t :: distinct ulong
|
||||
}
|
||||
|
||||
when ODIN_OS == .Darwin {
|
||||
} else when ODIN_OS == .Darwin {
|
||||
wctrans_t :: distinct int
|
||||
wctype_t :: distinct u32
|
||||
}
|
||||
|
||||
when ODIN_OS == .OpenBSD {
|
||||
} else when ODIN_OS == .OpenBSD {
|
||||
wctrans_t :: distinct rawptr
|
||||
wctype_t :: distinct rawptr
|
||||
|
||||
} else when ODIN_OS == .FreeBSD {
|
||||
wctrans_t :: distinct int
|
||||
wctype_t :: distinct ulong
|
||||
|
||||
}
|
||||
|
||||
@(default_calling_convention="c")
|
||||
|
||||
@@ -151,7 +151,7 @@ murmur32 :: proc(data: []byte, seed := u32(0)) -> u32 {
|
||||
k1 ~= u32(tail[2]) << 16
|
||||
fallthrough
|
||||
case 2:
|
||||
k1 ~= u32(tail[2]) << 8
|
||||
k1 ~= u32(tail[1]) << 8
|
||||
fallthrough
|
||||
case 1:
|
||||
k1 ~= u32(tail[0])
|
||||
|
||||
@@ -396,7 +396,7 @@ trunc_f16 :: proc "contextless" (x: f16) -> f16 {
|
||||
e := (x >> shift) & mask - bias
|
||||
|
||||
if e < shift {
|
||||
x &= ~(1 << (shift-e)) - 1
|
||||
x &~= 1 << (shift-e) - 1
|
||||
}
|
||||
return transmute(f16)x
|
||||
}
|
||||
@@ -428,7 +428,7 @@ trunc_f32 :: proc "contextless" (x: f32) -> f32 {
|
||||
e := (x >> shift) & mask - bias
|
||||
|
||||
if e < shift {
|
||||
x &= ~(1 << (shift-e)) - 1
|
||||
x &~= 1 << (shift-e) - 1
|
||||
}
|
||||
return transmute(f32)x
|
||||
}
|
||||
@@ -460,7 +460,7 @@ trunc_f64 :: proc "contextless" (x: f64) -> f64 {
|
||||
e := (x >> shift) & mask - bias
|
||||
|
||||
if e < shift {
|
||||
x &= ~(1 << (shift-e)) - 1
|
||||
x &~= 1 << (shift-e) - 1
|
||||
}
|
||||
return transmute(f64)x
|
||||
}
|
||||
@@ -473,6 +473,7 @@ trunc_f64 :: proc "contextless" (x: f64) -> f64 {
|
||||
}
|
||||
trunc_f64le :: proc "contextless" (x: f64le) -> f64le { return #force_inline f64le(trunc_f64(f64(x))) }
|
||||
trunc_f64be :: proc "contextless" (x: f64be) -> f64be { return #force_inline f64be(trunc_f64(f64(x))) }
|
||||
// Removes the fractional part of the value, i.e. rounds towards zero.
|
||||
trunc :: proc{
|
||||
trunc_f16, trunc_f16le, trunc_f16be,
|
||||
trunc_f32, trunc_f32le, trunc_f32be,
|
||||
@@ -958,7 +959,7 @@ classify_f16 :: proc "contextless" (x: f16) -> Float_Class {
|
||||
return .Neg_Zero
|
||||
}
|
||||
return .Zero
|
||||
case x*0.5 == x:
|
||||
case x*0.25 == x:
|
||||
if x < 0 {
|
||||
return .Neg_Inf
|
||||
}
|
||||
@@ -1027,6 +1028,8 @@ classify_f64 :: proc "contextless" (x: f64) -> Float_Class {
|
||||
}
|
||||
classify_f64le :: proc "contextless" (x: f64le) -> Float_Class { return #force_inline classify_f64(f64(x)) }
|
||||
classify_f64be :: proc "contextless" (x: f64be) -> Float_Class { return #force_inline classify_f64(f64(x)) }
|
||||
// Returns the `Float_Class` of the value, i.e. whether normal, subnormal, zero, negative zero, NaN, infinity or
|
||||
// negative infinity.
|
||||
classify :: proc{
|
||||
classify_f16, classify_f16le, classify_f16be,
|
||||
classify_f32, classify_f32le, classify_f32be,
|
||||
@@ -1715,4 +1718,22 @@ F32_BIAS :: 0x7f
|
||||
|
||||
F64_MASK :: 0x7ff
|
||||
F64_SHIFT :: 64 - 12
|
||||
F64_BIAS :: 0x3ff
|
||||
F64_BIAS :: 0x3ff
|
||||
|
||||
INF_F16 :f16: 0h7C00
|
||||
NEG_INF_F16 :f16: 0hFC00
|
||||
|
||||
SNAN_F16 :f16: 0h7C01
|
||||
QNAN_F16 :f16: 0h7E01
|
||||
|
||||
INF_F32 :f32: 0h7F80_0000
|
||||
NEG_INF_F32 :f32: 0hFF80_0000
|
||||
|
||||
SNAN_F32 :f32: 0hFF80_0001
|
||||
QNAN_F32 :f32: 0hFFC0_0001
|
||||
|
||||
INF_F64 :f64: 0h7FF0_0000_0000_0000
|
||||
NEG_INF_F64 :f64: 0hFFF0_0000_0000_0000
|
||||
|
||||
SNAN_F64 :f64: 0h7FF0_0000_0000_0001
|
||||
QNAN_F64 :f64: 0h7FF8_0000_0000_0001
|
||||
70
core/os/dir_freebsd.odin
Normal file
70
core/os/dir_freebsd.odin
Normal file
@@ -0,0 +1,70 @@
|
||||
package os
|
||||
|
||||
import "core:strings"
|
||||
import "core:mem"
|
||||
|
||||
read_dir :: proc(fd: Handle, n: int, allocator := context.allocator) -> (fi: []File_Info, err: Errno) {
|
||||
dirp: Dir
|
||||
dirp, err = _fdopendir(fd)
|
||||
if err != ERROR_NONE {
|
||||
return
|
||||
}
|
||||
|
||||
defer _closedir(dirp)
|
||||
|
||||
dirpath: string
|
||||
dirpath, err = absolute_path_from_handle(fd)
|
||||
|
||||
if err != ERROR_NONE {
|
||||
return
|
||||
}
|
||||
|
||||
defer delete(dirpath)
|
||||
|
||||
n := n
|
||||
size := n
|
||||
if n <= 0 {
|
||||
n = -1
|
||||
size = 100
|
||||
}
|
||||
|
||||
dfi := make([dynamic]File_Info, 0, size, allocator)
|
||||
|
||||
for {
|
||||
entry: Dirent
|
||||
end_of_stream: bool
|
||||
entry, err, end_of_stream = _readdir(dirp)
|
||||
if err != ERROR_NONE {
|
||||
for fi_ in dfi {
|
||||
file_info_delete(fi_, allocator)
|
||||
}
|
||||
delete(dfi)
|
||||
return
|
||||
} else if end_of_stream {
|
||||
break
|
||||
}
|
||||
|
||||
fi_: File_Info
|
||||
filename := cast(string)(transmute(cstring)mem.Raw_Cstring{ data = &entry.name[0] })
|
||||
|
||||
if filename == "." || filename == ".." {
|
||||
continue
|
||||
}
|
||||
|
||||
fullpath := strings.join( []string{ dirpath, filename }, "/", context.temp_allocator)
|
||||
defer delete(fullpath, context.temp_allocator)
|
||||
|
||||
fi_, err = stat(fullpath, allocator)
|
||||
if err != ERROR_NONE {
|
||||
for fi__ in dfi {
|
||||
file_info_delete(fi__, allocator)
|
||||
}
|
||||
delete(dfi)
|
||||
return
|
||||
}
|
||||
|
||||
append(&dfi, fi_)
|
||||
}
|
||||
|
||||
return dfi[:], ERROR_NONE
|
||||
}
|
||||
@@ -113,7 +113,7 @@ read_console :: proc(handle: win32.HANDLE, b: []byte) -> (n: int, err: Errno) {
|
||||
if max_read == 0 {
|
||||
break
|
||||
}
|
||||
|
||||
|
||||
single_read_length: u32
|
||||
ok := win32.ReadConsoleW(handle, &buf16[0], max_read, &single_read_length, nil)
|
||||
if !ok {
|
||||
|
||||
@@ -260,13 +260,13 @@ S_ISUID :: 0o4000 // Set user id on execution
|
||||
S_ISGID :: 0o2000 // Set group id on execution
|
||||
S_ISVTX :: 0o1000 // Directory restrcted delete
|
||||
|
||||
S_ISLNK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFLNK }
|
||||
S_ISREG :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFREG }
|
||||
S_ISDIR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFDIR }
|
||||
S_ISCHR :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFCHR }
|
||||
S_ISBLK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFBLK }
|
||||
S_ISFIFO :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFIFO }
|
||||
S_ISSOCK :: #force_inline proc(m: u32) -> bool { return (m & S_IFMT) == S_IFSOCK }
|
||||
S_ISLNK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFLNK }
|
||||
S_ISREG :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFREG }
|
||||
S_ISDIR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFDIR }
|
||||
S_ISCHR :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFCHR }
|
||||
S_ISBLK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFBLK }
|
||||
S_ISFIFO :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFIFO }
|
||||
S_ISSOCK :: #force_inline proc(m: u16) -> bool { return (m & S_IFMT) == S_IFSOCK }
|
||||
|
||||
R_OK :: 4 // Test for read permission
|
||||
W_OK :: 2 // Test for write permission
|
||||
@@ -313,7 +313,7 @@ foreign libc {
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||
@(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u32) -> c.int ---
|
||||
@(link_name="mkdir") _unix_mkdir :: proc(buf: cstring, mode: u16) -> c.int ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
|
||||
@(link_name="strerror") _darwin_string_error :: proc(num : c.int) -> cstring ---
|
||||
@@ -433,7 +433,7 @@ is_file_handle :: proc(fd: Handle) -> bool {
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(cast(u32)s.mode)
|
||||
return S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
@@ -447,7 +447,7 @@ is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(cast(u32)s.mode)
|
||||
return S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
|
||||
@@ -456,7 +456,7 @@ is_dir_handle :: proc(fd: Handle) -> bool {
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(cast(u32)s.mode)
|
||||
return S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
@@ -470,7 +470,7 @@ is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(cast(u32)s.mode)
|
||||
return S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
is_file :: proc {is_file_path, is_file_handle}
|
||||
@@ -670,7 +670,7 @@ set_current_directory :: proc(path: string) -> (err: Errno) {
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
make_directory :: proc(path: string, mode: u32 = 0o775) -> Errno {
|
||||
make_directory :: proc(path: string, mode: u16 = 0o775) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_mkdir(path_cstr, mode)
|
||||
if res == -1 {
|
||||
|
||||
@@ -10,7 +10,6 @@ import "core:c"
|
||||
Handle :: distinct i32
|
||||
File_Time :: distinct u64
|
||||
Errno :: distinct i32
|
||||
Syscall :: distinct i32
|
||||
|
||||
INVALID_HANDLE :: ~Handle(0)
|
||||
|
||||
@@ -142,40 +141,74 @@ RTLD_TRACE :: 0x200
|
||||
RTLD_NODELETE :: 0x01000
|
||||
RTLD_NOLOAD :: 0x02000
|
||||
|
||||
MAX_PATH :: 1024
|
||||
|
||||
args := _alloc_command_line_arguments()
|
||||
|
||||
Unix_File_Time :: struct {
|
||||
seconds: i64,
|
||||
seconds: time_t,
|
||||
nanoseconds: c.long,
|
||||
}
|
||||
|
||||
dev_t :: u64
|
||||
ino_t :: u64
|
||||
nlink_t :: u64
|
||||
off_t :: i64
|
||||
mode_t :: u16
|
||||
pid_t :: u32
|
||||
uid_t :: u32
|
||||
gid_t :: u32
|
||||
blkcnt_t :: i64
|
||||
blksize_t :: i32
|
||||
fflags_t :: u32
|
||||
|
||||
when ODIN_ARCH == .amd64 /* LP64 */ {
|
||||
time_t :: i64
|
||||
} else {
|
||||
time_t :: i32
|
||||
}
|
||||
|
||||
|
||||
OS_Stat :: struct {
|
||||
device_id: u64,
|
||||
serial: u64,
|
||||
nlink: u64,
|
||||
mode: u32,
|
||||
device_id: dev_t,
|
||||
serial: ino_t,
|
||||
nlink: nlink_t,
|
||||
mode: mode_t,
|
||||
_padding0: i16,
|
||||
uid: u32,
|
||||
gid: u32,
|
||||
uid: uid_t,
|
||||
gid: gid_t,
|
||||
_padding1: i32,
|
||||
rdev: u64,
|
||||
rdev: dev_t,
|
||||
|
||||
last_access: Unix_File_Time,
|
||||
modified: Unix_File_Time,
|
||||
status_change: Unix_File_Time,
|
||||
birthtime: Unix_File_Time,
|
||||
|
||||
size: i64,
|
||||
blocks: i64,
|
||||
block_size: i32,
|
||||
size: off_t,
|
||||
blocks: blkcnt_t,
|
||||
block_size: blksize_t,
|
||||
|
||||
flags: u32,
|
||||
flags: fflags_t,
|
||||
gen: u64,
|
||||
lspare: i64,
|
||||
lspare: [10]u64,
|
||||
}
|
||||
|
||||
|
||||
// since FreeBSD v12
|
||||
Dirent :: struct {
|
||||
ino: ino_t,
|
||||
off: off_t,
|
||||
reclen: u16,
|
||||
type: u8,
|
||||
_pad0: u8,
|
||||
namlen: u16,
|
||||
_pad1: u16,
|
||||
name: [256]byte,
|
||||
}
|
||||
|
||||
Dir :: distinct rawptr // DIR*
|
||||
|
||||
// File type
|
||||
S_IFMT :: 0o170000 // Type of file mask
|
||||
S_IFIFO :: 0o010000 // Named pipe (fifo)
|
||||
@@ -211,13 +244,13 @@ S_ISGID :: 0o2000 // Set group id on execution
|
||||
S_ISVTX :: 0o1000 // Directory restrcted delete
|
||||
|
||||
|
||||
S_ISLNK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFLNK
|
||||
S_ISREG :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFREG
|
||||
S_ISDIR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFDIR
|
||||
S_ISCHR :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFCHR
|
||||
S_ISBLK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFBLK
|
||||
S_ISFIFO :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFIFO
|
||||
S_ISSOCK :: #force_inline proc(m: u32) -> bool do return (m & S_IFMT) == S_IFSOCK
|
||||
S_ISLNK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFLNK
|
||||
S_ISREG :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFREG
|
||||
S_ISDIR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFDIR
|
||||
S_ISCHR :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFCHR
|
||||
S_ISBLK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFBLK
|
||||
S_ISFIFO :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFIFO
|
||||
S_ISSOCK :: #force_inline proc(m: mode_t) -> bool do return (m & S_IFMT) == S_IFSOCK
|
||||
|
||||
F_OK :: 0 // Test for file existance
|
||||
X_OK :: 1 // Test for execute permission
|
||||
@@ -225,27 +258,38 @@ W_OK :: 2 // Test for write permission
|
||||
R_OK :: 4 // Test for read permission
|
||||
|
||||
foreign libc {
|
||||
@(link_name="__error") __errno_location :: proc() -> ^int ---
|
||||
@(link_name="syscall") syscall :: proc(number: Syscall, #c_vararg args: ..any) -> 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="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="write") _unix_write :: proc(fd: Handle, buf: rawptr, size: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="lseek64") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---
|
||||
@(link_name="gettid") _unix_gettid :: proc() -> u64 ---
|
||||
@(link_name="lseek") _unix_seek :: proc(fd: Handle, offset: i64, whence: c.int) -> i64 ---
|
||||
@(link_name="getpagesize") _unix_getpagesize :: proc() -> c.int ---
|
||||
@(link_name="stat64") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---
|
||||
@(link_name="stat") _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> c.int ---
|
||||
@(link_name="lstat") _unix_lstat :: proc(path: cstring, sb: ^OS_Stat) -> c.int ---
|
||||
@(link_name="fstat") _unix_fstat :: proc(fd: Handle, stat: ^OS_Stat) -> c.int ---
|
||||
@(link_name="readlink") _unix_readlink :: proc(path: cstring, buf: ^byte, bufsiz: c.size_t) -> c.ssize_t ---
|
||||
@(link_name="access") _unix_access :: proc(path: cstring, mask: c.int) -> c.int ---
|
||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||
@(link_name="rename") _unix_rename :: proc(old, new: cstring) -> c.int ---
|
||||
@(link_name="unlink") _unix_unlink :: proc(path: cstring) -> c.int ---
|
||||
@(link_name="rmdir") _unix_rmdir :: proc(path: cstring) -> c.int ---
|
||||
@(link_name="mkdir") _unix_mkdir :: proc(path: cstring, mode: mode_t) -> c.int ---
|
||||
|
||||
@(link_name="fdopendir") _unix_fdopendir :: proc(fd: Handle) -> Dir ---
|
||||
@(link_name="closedir") _unix_closedir :: proc(dirp: Dir) -> c.int ---
|
||||
@(link_name="rewinddir") _unix_rewinddir :: proc(dirp: Dir) ---
|
||||
@(link_name="readdir_r") _unix_readdir_r :: proc(dirp: Dir, entry: ^Dirent, result: ^^Dirent) -> c.int ---
|
||||
|
||||
@(link_name="malloc") _unix_malloc :: proc(size: c.size_t) -> rawptr ---
|
||||
@(link_name="calloc") _unix_calloc :: proc(num, size: c.size_t) -> rawptr ---
|
||||
@(link_name="free") _unix_free :: proc(ptr: rawptr) ---
|
||||
@(link_name="realloc") _unix_realloc :: proc(ptr: rawptr, size: c.size_t) -> rawptr ---
|
||||
|
||||
@(link_name="getenv") _unix_getenv :: proc(cstring) -> cstring ---
|
||||
@(link_name="getcwd") _unix_getcwd :: proc(buf: cstring, len: c.size_t) -> cstring ---
|
||||
@(link_name="chdir") _unix_chdir :: proc(buf: cstring) -> c.int ---
|
||||
@(link_name="realpath") _unix_realpath :: proc(path: cstring, resolved_path: rawptr) -> rawptr ---
|
||||
|
||||
@(link_name="exit") _unix_exit :: proc(status: c.int) -> ! ---
|
||||
}
|
||||
@@ -318,12 +362,102 @@ file_size :: proc(fd: Handle) -> (i64, Errno) {
|
||||
return s.size, ERROR_NONE
|
||||
}
|
||||
|
||||
stdin: Handle = 0
|
||||
rename :: proc(old_path, new_path: string) -> Errno {
|
||||
old_path_cstr := strings.clone_to_cstring(old_path, context.temp_allocator)
|
||||
new_path_cstr := strings.clone_to_cstring(new_path, context.temp_allocator)
|
||||
res := _unix_rename(old_path_cstr, new_path_cstr)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
remove :: proc(path: string) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_unlink(path_cstr)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
make_directory :: proc(path: string, mode: mode_t = 0o775) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_mkdir(path_cstr, mode)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
remove_directory :: proc(path: string) -> Errno {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
res := _unix_rmdir(path_cstr)
|
||||
if res == -1 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
is_file_handle :: proc(fd: Handle) -> bool {
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
is_file_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
s: OS_Stat
|
||||
err: Errno
|
||||
if follow_links {
|
||||
s, err = _stat(path)
|
||||
} else {
|
||||
s, err = _lstat(path)
|
||||
}
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISREG(s.mode)
|
||||
}
|
||||
|
||||
is_dir_handle :: proc(fd: Handle) -> bool {
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
is_dir_path :: proc(path: string, follow_links: bool = true) -> bool {
|
||||
s: OS_Stat
|
||||
err: Errno
|
||||
if follow_links {
|
||||
s, err = _stat(path)
|
||||
} else {
|
||||
s, err = _lstat(path)
|
||||
}
|
||||
if err != ERROR_NONE {
|
||||
return false
|
||||
}
|
||||
return S_ISDIR(s.mode)
|
||||
}
|
||||
|
||||
is_file :: proc {is_file_path, is_file_handle}
|
||||
is_dir :: proc {is_dir_path, is_dir_handle}
|
||||
|
||||
// NOTE(bill): Uses startup to initialize it
|
||||
|
||||
stdin: Handle = 0
|
||||
stdout: Handle = 1
|
||||
stderr: Handle = 2
|
||||
|
||||
/* TODO(zangent): Implement these!
|
||||
last_write_time :: proc(fd: Handle) -> File_Time {}
|
||||
last_write_time_by_name :: proc(name: string) -> File_Time {}
|
||||
*/
|
||||
last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
|
||||
s, err := fstat(fd)
|
||||
s, err := _fstat(fd)
|
||||
if err != ERROR_NONE {
|
||||
return 0, err
|
||||
}
|
||||
@@ -332,7 +466,7 @@ last_write_time :: proc(fd: Handle) -> (File_Time, Errno) {
|
||||
}
|
||||
|
||||
last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||
s, err := stat(name)
|
||||
s, err := _stat(name)
|
||||
if err != ERROR_NONE {
|
||||
return 0, err
|
||||
}
|
||||
@@ -340,18 +474,33 @@ last_write_time_by_name :: proc(name: string) -> (File_Time, Errno) {
|
||||
return File_Time(modified), ERROR_NONE
|
||||
}
|
||||
|
||||
stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
@private
|
||||
_stat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
s: OS_Stat
|
||||
result := _unix_stat(cstr, &s)
|
||||
s: OS_Stat = ---
|
||||
result := _unix_lstat(cstr, &s)
|
||||
if result == -1 {
|
||||
return s, Errno(get_last_error())
|
||||
}
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
|
||||
fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||
s: OS_Stat
|
||||
@private
|
||||
_lstat :: proc(path: string) -> (OS_Stat, Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
// deliberately uninitialized
|
||||
s: OS_Stat = ---
|
||||
res := _unix_lstat(cstr, &s)
|
||||
if res == -1 {
|
||||
return s, Errno(get_last_error())
|
||||
}
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||
s: OS_Stat = ---
|
||||
result := _unix_fstat(fd, &s)
|
||||
if result == -1 {
|
||||
return s, Errno(get_last_error())
|
||||
@@ -359,6 +508,95 @@ fstat :: proc(fd: Handle) -> (OS_Stat, Errno) {
|
||||
return s, ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_fdopendir :: proc(fd: Handle) -> (Dir, Errno) {
|
||||
dirp := _unix_fdopendir(fd)
|
||||
if dirp == cast(Dir)nil {
|
||||
return nil, Errno(get_last_error())
|
||||
}
|
||||
return dirp, ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_closedir :: proc(dirp: Dir) -> Errno {
|
||||
rc := _unix_closedir(dirp)
|
||||
if rc != 0 {
|
||||
return Errno(get_last_error())
|
||||
}
|
||||
return ERROR_NONE
|
||||
}
|
||||
|
||||
@private
|
||||
_rewinddir :: proc(dirp: Dir) {
|
||||
_unix_rewinddir(dirp)
|
||||
}
|
||||
|
||||
@private
|
||||
_readdir :: proc(dirp: Dir) -> (entry: Dirent, err: Errno, end_of_stream: bool) {
|
||||
result: ^Dirent
|
||||
rc := _unix_readdir_r(dirp, &entry, &result)
|
||||
|
||||
if rc != 0 {
|
||||
err = Errno(get_last_error())
|
||||
return
|
||||
}
|
||||
err = ERROR_NONE
|
||||
|
||||
if result == nil {
|
||||
end_of_stream = true
|
||||
return
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
@private
|
||||
_readlink :: proc(path: string) -> (string, Errno) {
|
||||
path_cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
|
||||
bufsz : uint = MAX_PATH
|
||||
buf := make([]byte, MAX_PATH)
|
||||
for {
|
||||
rc := _unix_readlink(path_cstr, &(buf[0]), bufsz)
|
||||
if rc == -1 {
|
||||
delete(buf)
|
||||
return "", Errno(get_last_error())
|
||||
} else if rc == int(bufsz) {
|
||||
bufsz += MAX_PATH
|
||||
delete(buf)
|
||||
buf = make([]byte, bufsz)
|
||||
} else {
|
||||
return strings.string_from_ptr(&buf[0], rc), ERROR_NONE
|
||||
}
|
||||
}
|
||||
unreachable()
|
||||
}
|
||||
|
||||
// XXX FreeBSD
|
||||
absolute_path_from_handle :: proc(fd: Handle) -> (string, Errno) {
|
||||
return "", Errno(ENOSYS)
|
||||
}
|
||||
|
||||
absolute_path_from_relative :: proc(rel: string) -> (path: string, err: Errno) {
|
||||
rel := rel
|
||||
if rel == "" {
|
||||
rel = "."
|
||||
}
|
||||
|
||||
rel_cstr := strings.clone_to_cstring(rel, context.temp_allocator)
|
||||
|
||||
path_ptr := _unix_realpath(rel_cstr, nil)
|
||||
if path_ptr == nil {
|
||||
return "", Errno(get_last_error())
|
||||
}
|
||||
defer _unix_free(path_ptr)
|
||||
|
||||
path_cstr := transmute(cstring)path_ptr
|
||||
path = strings.clone( string(path_cstr) )
|
||||
|
||||
return path, ERROR_NONE
|
||||
}
|
||||
|
||||
access :: proc(path: string, mask: int) -> (bool, Errno) {
|
||||
cstr := strings.clone_to_cstring(path, context.temp_allocator)
|
||||
result := _unix_access(cstr, c.int(mask))
|
||||
@@ -464,4 +702,3 @@ _alloc_command_line_arguments :: proc() -> []string {
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
@@ -269,7 +269,7 @@ X_OK :: 1 // Test for execute permission
|
||||
W_OK :: 2 // Test for write permission
|
||||
R_OK :: 4 // Test for read permission
|
||||
|
||||
AT_FDCWD :: -100
|
||||
AT_FDCWD :: ~uintptr(99) /* -100 */
|
||||
AT_REMOVEDIR :: uintptr(0x200)
|
||||
AT_SYMLINK_NOFOLLOW :: uintptr(0x100)
|
||||
|
||||
@@ -278,7 +278,11 @@ _unix_personality :: proc(persona: u64) -> int {
|
||||
}
|
||||
|
||||
_unix_fork :: proc() -> Pid {
|
||||
res := int(intrinsics.syscall(unix.SYS_fork))
|
||||
when ODIN_ARCH != .arm64 {
|
||||
res := int(intrinsics.syscall(unix.SYS_fork))
|
||||
} else {
|
||||
res := int(intrinsics.syscall(unix.SYS_clone, unix.SIGCHLD))
|
||||
}
|
||||
return -1 if res < 0 else Pid(res)
|
||||
}
|
||||
|
||||
@@ -286,7 +290,7 @@ _unix_open :: proc(path: cstring, flags: int, mode: int = 0o000) -> Handle {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
res := int(intrinsics.syscall(unix.SYS_open, uintptr(rawptr(path)), uintptr(flags), uintptr(mode)))
|
||||
} else { // NOTE: arm64 does not have open
|
||||
res := int(intrinsics.syscall(unix.SYS_openat, uintptr(AT_FDCWD), uintptr(rawptr(path), uintptr(flags), uintptr(mode))))
|
||||
res := int(intrinsics.syscall(unix.SYS_openat, AT_FDCWD, uintptr(rawptr(path)), uintptr(flags), uintptr(mode)))
|
||||
}
|
||||
return -1 if res < 0 else Handle(res)
|
||||
}
|
||||
@@ -321,7 +325,7 @@ _unix_stat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||
} else when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_stat64, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else { // NOTE: arm64 does not have stat
|
||||
return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), 0))
|
||||
return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), 0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -339,7 +343,7 @@ _unix_lstat :: proc(path: cstring, stat: ^OS_Stat) -> int {
|
||||
} else when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_lstat64, uintptr(rawptr(path)), uintptr(stat)))
|
||||
} else { // NOTE: arm64 does not have any lstat
|
||||
return int(intrinsics.syscall(unix.SYS_fstatat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW))
|
||||
return int(intrinsics.syscall(unix.SYS_fstatat, AT_FDCWD, uintptr(rawptr(path)), uintptr(stat), AT_SYMLINK_NOFOLLOW))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,7 +351,7 @@ _unix_readlink :: proc(path: cstring, buf: rawptr, bufsiz: uint) -> int {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_readlink, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
||||
} else { // NOTE: arm64 does not have readlink
|
||||
return int(intrinsics.syscall(unix.SYS_readlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
||||
return int(intrinsics.syscall(unix.SYS_readlinkat, AT_FDCWD, uintptr(rawptr(path)), uintptr(buf), uintptr(bufsiz)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -355,7 +359,7 @@ _unix_access :: proc(path: cstring, mask: int) -> int {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_access, uintptr(rawptr(path)), uintptr(mask)))
|
||||
} else { // NOTE: arm64 does not have access
|
||||
return int(intrinsics.syscall(unix.SYS_faccessat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mask)))
|
||||
return int(intrinsics.syscall(unix.SYS_faccessat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mask)))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -371,7 +375,7 @@ _unix_rename :: proc(old, new: cstring) -> int {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_rename, uintptr(rawptr(old)), uintptr(rawptr(new))))
|
||||
} else { // NOTE: arm64 does not have rename
|
||||
return int(intrinsics.syscall(unix.SYS_renameat, uintptr(AT_FDCWD), uintptr(rawptr(old)), uintptr(rawptr(new))))
|
||||
return int(intrinsics.syscall(unix.SYS_renameat, AT_FDCWD, uintptr(rawptr(old)), uintptr(rawptr(new))))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,7 +383,7 @@ _unix_unlink :: proc(path: cstring) -> int {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_unlink, uintptr(rawptr(path))))
|
||||
} else { // NOTE: arm64 does not have unlink
|
||||
return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path), 0)))
|
||||
return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), 0))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -387,7 +391,7 @@ _unix_rmdir :: proc(path: cstring) -> int {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_rmdir, uintptr(rawptr(path))))
|
||||
} else { // NOTE: arm64 does not have rmdir
|
||||
return int(intrinsics.syscall(unix.SYS_unlinkat, uintptr(AT_FDCWD), uintptr(rawptr(path)), AT_REMOVEDIR))
|
||||
return int(intrinsics.syscall(unix.SYS_unlinkat, AT_FDCWD, uintptr(rawptr(path)), AT_REMOVEDIR))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -395,7 +399,7 @@ _unix_mkdir :: proc(path: cstring, mode: u32) -> int {
|
||||
when ODIN_ARCH != .arm64 {
|
||||
return int(intrinsics.syscall(unix.SYS_mkdir, uintptr(rawptr(path)), uintptr(mode)))
|
||||
} else { // NOTE: arm64 does not have mkdir
|
||||
return int(intrinsics.syscall(unix.SYS_mkdirat, uintptr(AT_FDCWD), uintptr(rawptr(path)), uintptr(mode)))
|
||||
return int(intrinsics.syscall(unix.SYS_mkdirat, AT_FDCWD, uintptr(rawptr(path)), uintptr(mode)))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -61,7 +61,7 @@ _make_time_from_unix_file_time :: proc(uft: Unix_File_Time) -> time.Time {
|
||||
_fill_file_info_from_stat :: proc(fi: ^File_Info, s: OS_Stat) {
|
||||
fi.size = s.size
|
||||
fi.mode = cast(File_Mode)s.mode
|
||||
fi.is_dir = S_ISDIR(u32(s.mode))
|
||||
fi.is_dir = S_ISDIR(s.mode)
|
||||
|
||||
// NOTE(laleksic, 2021-01-21): Not really creation time, but closest we can get (maybe better to leave it 0?)
|
||||
fi.creation_time = _make_time_from_unix_file_time(s.status_change)
|
||||
|
||||
@@ -451,7 +451,7 @@ Odin_Endian_Type :: type_of(ODIN_ENDIAN)
|
||||
// This is probably only useful for freestanding targets
|
||||
foreign {
|
||||
@(link_name="__$startup_runtime")
|
||||
_startup_runtime :: proc() ---
|
||||
_startup_runtime :: proc "odin" () ---
|
||||
}
|
||||
|
||||
@(link_name="__$cleanup_runtime")
|
||||
@@ -513,16 +513,18 @@ __type_info_of :: proc "contextless" (id: typeid) -> ^Type_Info #no_bounds_check
|
||||
return &type_table[n]
|
||||
}
|
||||
|
||||
typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_of(id)
|
||||
ti = type_info_base(ti)
|
||||
return ti.id
|
||||
when !ODIN_DISALLOW_RTTI {
|
||||
typeid_base :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_of(id)
|
||||
ti = type_info_base(ti)
|
||||
return ti.id
|
||||
}
|
||||
typeid_core :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_core(type_info_of(id))
|
||||
return ti.id
|
||||
}
|
||||
typeid_base_without_enum :: typeid_core
|
||||
}
|
||||
typeid_core :: proc "contextless" (id: typeid) -> typeid {
|
||||
ti := type_info_core(type_info_of(id))
|
||||
return ti.id
|
||||
}
|
||||
typeid_base_without_enum :: typeid_core
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ bounds_check_error :: proc "contextless" (file: string, line, column: i32, index
|
||||
if 0 <= index && index < count {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, index, count: int) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Index ")
|
||||
@@ -81,6 +82,7 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
|
||||
if 0 <= low && low <= high && high <= max {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, low, high, max: int) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid dynamic array indices ")
|
||||
@@ -97,10 +99,11 @@ dynamic_array_expr_error :: proc "contextless" (file: string, line, column: i32,
|
||||
|
||||
|
||||
matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
|
||||
if 0 <= row_index && row_index < row_count &&
|
||||
if 0 <= row_index && row_index < row_count &&
|
||||
0 <= column_index && column_index < column_count {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, row_index, column_index, row_count, column_count: int) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Matrix indices [")
|
||||
@@ -119,71 +122,101 @@ matrix_bounds_check_error :: proc "contextless" (file: string, line, column: i32
|
||||
}
|
||||
|
||||
|
||||
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) {
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion from ")
|
||||
print_typeid(from)
|
||||
print_string(" to ")
|
||||
print_typeid(to)
|
||||
print_byte('\n')
|
||||
type_assertion_trap()
|
||||
}
|
||||
handle_error(file, line, column, from, to)
|
||||
}
|
||||
|
||||
type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
||||
if ok {
|
||||
return
|
||||
when ODIN_DISALLOW_RTTI {
|
||||
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32) {
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion\n")
|
||||
type_assertion_trap()
|
||||
}
|
||||
handle_error(file, line, column)
|
||||
}
|
||||
|
||||
variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid {
|
||||
if id == nil || data == nil {
|
||||
type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32) {
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion\n")
|
||||
type_assertion_trap()
|
||||
}
|
||||
handle_error(file, line, column)
|
||||
}
|
||||
} else {
|
||||
type_assertion_check :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid) {
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid) {
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion from ")
|
||||
print_typeid(from)
|
||||
print_string(" to ")
|
||||
print_typeid(to)
|
||||
print_byte('\n')
|
||||
type_assertion_trap()
|
||||
}
|
||||
handle_error(file, line, column, from, to)
|
||||
}
|
||||
|
||||
type_assertion_check2 :: proc "contextless" (ok: bool, file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
||||
if ok {
|
||||
return
|
||||
}
|
||||
|
||||
variant_type :: proc "contextless" (id: typeid, data: rawptr) -> typeid {
|
||||
if id == nil || data == nil {
|
||||
return id
|
||||
}
|
||||
ti := type_info_base(type_info_of(id))
|
||||
#partial switch v in ti.variant {
|
||||
case Type_Info_Any:
|
||||
return (^any)(data).id
|
||||
case Type_Info_Union:
|
||||
tag_ptr := uintptr(data) + v.tag_offset
|
||||
idx := 0
|
||||
switch v.tag_type.size {
|
||||
case 1: idx = int((^u8)(tag_ptr)^) - 1
|
||||
case 2: idx = int((^u16)(tag_ptr)^) - 1
|
||||
case 4: idx = int((^u32)(tag_ptr)^) - 1
|
||||
case 8: idx = int((^u64)(tag_ptr)^) - 1
|
||||
case 16: idx = int((^u128)(tag_ptr)^) - 1
|
||||
}
|
||||
if idx < 0 {
|
||||
return nil
|
||||
} else if idx < len(v.variants) {
|
||||
return v.variants[idx].id
|
||||
}
|
||||
}
|
||||
return id
|
||||
}
|
||||
ti := type_info_base(type_info_of(id))
|
||||
#partial switch v in ti.variant {
|
||||
case Type_Info_Any:
|
||||
return (^any)(data).id
|
||||
case Type_Info_Union:
|
||||
tag_ptr := uintptr(data) + v.tag_offset
|
||||
idx := 0
|
||||
switch v.tag_type.size {
|
||||
case 1: idx = int((^u8)(tag_ptr)^) - 1
|
||||
case 2: idx = int((^u16)(tag_ptr)^) - 1
|
||||
case 4: idx = int((^u32)(tag_ptr)^) - 1
|
||||
case 8: idx = int((^u64)(tag_ptr)^) - 1
|
||||
case 16: idx = int((^u128)(tag_ptr)^) - 1
|
||||
}
|
||||
if idx < 0 {
|
||||
return nil
|
||||
} else if idx < len(v.variants) {
|
||||
return v.variants[idx].id
|
||||
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
||||
|
||||
actual := variant_type(from, from_data)
|
||||
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion from ")
|
||||
print_typeid(from)
|
||||
print_string(" to ")
|
||||
print_typeid(to)
|
||||
if actual != from {
|
||||
print_string(", actual type: ")
|
||||
print_typeid(actual)
|
||||
}
|
||||
print_byte('\n')
|
||||
type_assertion_trap()
|
||||
}
|
||||
return id
|
||||
handle_error(file, line, column, from, to, from_data)
|
||||
}
|
||||
|
||||
handle_error :: proc "contextless" (file: string, line, column: i32, from, to: typeid, from_data: rawptr) {
|
||||
|
||||
actual := variant_type(from, from_data)
|
||||
|
||||
print_caller_location(Source_Code_Location{file, line, column, ""})
|
||||
print_string(" Invalid type assertion from ")
|
||||
print_typeid(from)
|
||||
print_string(" to ")
|
||||
print_typeid(to)
|
||||
if actual != from {
|
||||
print_string(", actual type: ")
|
||||
print_typeid(actual)
|
||||
}
|
||||
print_byte('\n')
|
||||
type_assertion_trap()
|
||||
}
|
||||
handle_error(file, line, column, from, to, from_data)
|
||||
}
|
||||
|
||||
|
||||
@@ -191,6 +224,7 @@ make_slice_error_loc :: #force_inline proc "contextless" (loc := #caller_locatio
|
||||
if 0 <= len {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len: int) {
|
||||
print_caller_location(loc)
|
||||
print_string(" Invalid slice length for make: ")
|
||||
@@ -205,6 +239,7 @@ make_dynamic_array_error_loc :: #force_inline proc "contextless" (using loc := #
|
||||
if 0 <= len && len <= cap {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, len, cap: int) {
|
||||
print_caller_location(loc)
|
||||
print_string(" Invalid dynamic array parameters for make: ")
|
||||
@@ -221,6 +256,7 @@ make_map_expr_error_loc :: #force_inline proc "contextless" (loc := #caller_loca
|
||||
if 0 <= cap {
|
||||
return
|
||||
}
|
||||
@(cold)
|
||||
handle_error :: proc "contextless" (loc: Source_Code_Location, cap: int) {
|
||||
print_caller_location(loc)
|
||||
print_string(" Invalid map capacity for make: ")
|
||||
|
||||
@@ -160,11 +160,19 @@ print_caller_location :: proc "contextless" (using loc: Source_Code_Location) {
|
||||
}
|
||||
}
|
||||
print_typeid :: proc "contextless" (id: typeid) {
|
||||
if id == nil {
|
||||
print_string("nil")
|
||||
when ODIN_DISALLOW_RTTI {
|
||||
if id == nil {
|
||||
print_string("nil")
|
||||
} else {
|
||||
print_string("<unknown type>")
|
||||
}
|
||||
} else {
|
||||
ti := type_info_of(id)
|
||||
print_type(ti)
|
||||
if id == nil {
|
||||
print_string("nil")
|
||||
} else {
|
||||
ti := type_info_of(id)
|
||||
print_type(ti)
|
||||
}
|
||||
}
|
||||
}
|
||||
print_type :: proc "contextless" (ti: ^Type_Info) {
|
||||
|
||||
75
core/sync/sync2/futex_freebsd.odin
Normal file
75
core/sync/sync2/futex_freebsd.odin
Normal file
@@ -0,0 +1,75 @@
|
||||
//+private
|
||||
//+build freebsd
|
||||
package sync2
|
||||
|
||||
import "core:c"
|
||||
import "core:os"
|
||||
import "core:time"
|
||||
|
||||
UMTX_OP_WAIT :: 2
|
||||
UMTX_OP_WAKE :: 3
|
||||
|
||||
foreign import libc "system:c"
|
||||
|
||||
foreign libc {
|
||||
_umtx_op :: proc "c" (obj: rawptr, op: c.int, val: c.ulong, uaddr: rawptr, uaddr2: rawptr) -> c.int ---
|
||||
}
|
||||
|
||||
_futex_wait :: proc(f: ^Futex, expected: u32) -> bool {
|
||||
timeout := os.Unix_File_Time{
|
||||
seconds = 5,
|
||||
nanoseconds = 0,
|
||||
}
|
||||
|
||||
for {
|
||||
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &timeout)
|
||||
|
||||
if res != -1 {
|
||||
return true
|
||||
}
|
||||
|
||||
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
|
||||
continue
|
||||
}
|
||||
|
||||
panic("_futex_wait failure")
|
||||
}
|
||||
unreachable()
|
||||
}
|
||||
|
||||
_futex_wait_with_timeout :: proc(f: ^Futex, expected: u32, duration: time.Duration) -> bool {
|
||||
if duration <= 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
res := _umtx_op(f, UMTX_OP_WAIT, c.ulong(expected), nil, &os.Unix_File_Time{
|
||||
seconds = (os.time_t)(duration/1e9),
|
||||
nanoseconds = (c.long)(duration%1e9),
|
||||
})
|
||||
|
||||
if res != -1 {
|
||||
return true
|
||||
}
|
||||
|
||||
if os.Errno(os.get_last_error()) == os.ETIMEDOUT {
|
||||
return false
|
||||
}
|
||||
|
||||
panic("_futex_wait_with_timeout failure")
|
||||
}
|
||||
|
||||
_futex_signal :: proc(f: ^Futex) {
|
||||
res := _umtx_op(f, UMTX_OP_WAKE, 1, nil, nil)
|
||||
|
||||
if res == -1 {
|
||||
panic("_futex_signal failure")
|
||||
}
|
||||
}
|
||||
|
||||
_futex_broadcast :: proc(f: ^Futex) {
|
||||
res := _umtx_op(f, UMTX_OP_WAKE, c.ulong(max(i32)), nil, nil)
|
||||
|
||||
if res == -1 {
|
||||
panic("_futex_broadcast failure")
|
||||
}
|
||||
}
|
||||
@@ -11,7 +11,7 @@ current_thread_id :: proc "contextless" () -> int {
|
||||
//
|
||||
// A Mutex must not be copied after first use
|
||||
Mutex :: struct {
|
||||
impl: _Mutex `This is a tag`,
|
||||
impl: _Mutex,
|
||||
}
|
||||
|
||||
// mutex_lock locks m
|
||||
|
||||
9
core/sync/sync2/primitives_freebsd.odin
Normal file
9
core/sync/sync2/primitives_freebsd.odin
Normal file
@@ -0,0 +1,9 @@
|
||||
//+build freebsd
|
||||
//+private
|
||||
package sync2
|
||||
|
||||
import "core:os"
|
||||
|
||||
_current_thread_id :: proc "contextless" () -> int {
|
||||
return os.current_thread_id()
|
||||
}
|
||||
@@ -5,8 +5,8 @@ import "core:intrinsics"
|
||||
|
||||
|
||||
current_thread_id :: proc "contextless" () -> int {
|
||||
SYS_GETTID :: 186;
|
||||
return int(intrinsics.syscall(SYS_GETTID));
|
||||
SYS_GETTID :: 186
|
||||
return int(intrinsics.syscall(SYS_GETTID))
|
||||
}
|
||||
|
||||
|
||||
@@ -19,22 +19,22 @@ Semaphore :: struct #align 16 {
|
||||
}
|
||||
|
||||
semaphore_init :: proc(s: ^Semaphore, initial_count := 0) {
|
||||
assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0);
|
||||
assert(unix.sem_init(&s.handle, 0, u32(initial_count)) == 0)
|
||||
}
|
||||
|
||||
semaphore_destroy :: proc(s: ^Semaphore) {
|
||||
assert(unix.sem_destroy(&s.handle) == 0);
|
||||
s.handle = {};
|
||||
assert(unix.sem_destroy(&s.handle) == 0)
|
||||
s.handle = {}
|
||||
}
|
||||
|
||||
semaphore_post :: proc(s: ^Semaphore, count := 1) {
|
||||
// NOTE: SPEED: If there's one syscall to do this, we should use it instead of the loop.
|
||||
for in 0..<count {
|
||||
assert(unix.sem_post(&s.handle) == 0);
|
||||
assert(unix.sem_post(&s.handle) == 0)
|
||||
}
|
||||
}
|
||||
|
||||
semaphore_wait_for :: proc(s: ^Semaphore) {
|
||||
assert(unix.sem_wait(&s.handle) == 0);
|
||||
assert(unix.sem_wait(&s.handle) == 0)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,76 +1,76 @@
|
||||
//+build freebsd
|
||||
package unix
|
||||
|
||||
import "core:c";
|
||||
import "core:c"
|
||||
|
||||
pthread_t :: distinct u64;
|
||||
// pthread_t :: struct #align 16 { x: u64 };
|
||||
pthread_t :: distinct u64
|
||||
// pthread_t :: struct #align 16 { x: u64 }
|
||||
|
||||
PTHREAD_COND_T_SIZE :: 8;
|
||||
PTHREAD_COND_T_SIZE :: 8
|
||||
|
||||
PTHREAD_MUTEXATTR_T_SIZE :: 8;
|
||||
PTHREAD_CONDATTR_T_SIZE :: 8;
|
||||
PTHREAD_RWLOCKATTR_T_SIZE :: 8;
|
||||
PTHREAD_BARRIERATTR_T_SIZE :: 8;
|
||||
PTHREAD_MUTEXATTR_T_SIZE :: 8
|
||||
PTHREAD_CONDATTR_T_SIZE :: 8
|
||||
PTHREAD_RWLOCKATTR_T_SIZE :: 8
|
||||
PTHREAD_BARRIERATTR_T_SIZE :: 8
|
||||
|
||||
// WARNING: The sizes of these things are different yet again
|
||||
// on non-X86!
|
||||
when size_of(int) == 8 {
|
||||
PTHREAD_ATTR_T_SIZE :: 8;
|
||||
PTHREAD_MUTEX_T_SIZE :: 8;
|
||||
PTHREAD_RWLOCK_T_SIZE :: 8;
|
||||
PTHREAD_BARRIER_T_SIZE :: 8;
|
||||
PTHREAD_ATTR_T_SIZE :: 8
|
||||
PTHREAD_MUTEX_T_SIZE :: 8
|
||||
PTHREAD_RWLOCK_T_SIZE :: 8
|
||||
PTHREAD_BARRIER_T_SIZE :: 8
|
||||
} else when size_of(int) == 4 { // TODO
|
||||
PTHREAD_ATTR_T_SIZE :: 32;
|
||||
PTHREAD_MUTEX_T_SIZE :: 32;
|
||||
PTHREAD_RWLOCK_T_SIZE :: 44;
|
||||
PTHREAD_BARRIER_T_SIZE :: 20;
|
||||
PTHREAD_ATTR_T_SIZE :: 32
|
||||
PTHREAD_MUTEX_T_SIZE :: 32
|
||||
PTHREAD_RWLOCK_T_SIZE :: 44
|
||||
PTHREAD_BARRIER_T_SIZE :: 20
|
||||
}
|
||||
|
||||
pthread_cond_t :: struct #align 16 {
|
||||
_: [PTHREAD_COND_T_SIZE] c.char,
|
||||
};
|
||||
}
|
||||
pthread_mutex_t :: struct #align 16 {
|
||||
_: [PTHREAD_MUTEX_T_SIZE] c.char,
|
||||
};
|
||||
}
|
||||
pthread_rwlock_t :: struct #align 16 {
|
||||
_: [PTHREAD_RWLOCK_T_SIZE] c.char,
|
||||
};
|
||||
}
|
||||
pthread_barrier_t :: struct #align 16 {
|
||||
_: [PTHREAD_BARRIER_T_SIZE] c.char,
|
||||
};
|
||||
}
|
||||
|
||||
pthread_attr_t :: struct #align 16 {
|
||||
_: [PTHREAD_ATTR_T_SIZE] c.char,
|
||||
};
|
||||
}
|
||||
pthread_condattr_t :: struct #align 16 {
|
||||
_: [PTHREAD_CONDATTR_T_SIZE] c.char,
|
||||
};
|
||||
}
|
||||
pthread_mutexattr_t :: struct #align 16 {
|
||||
_: [PTHREAD_MUTEXATTR_T_SIZE] c.char,
|
||||
};
|
||||
}
|
||||
pthread_rwlockattr_t :: struct #align 16 {
|
||||
_: [PTHREAD_RWLOCKATTR_T_SIZE] c.char,
|
||||
};
|
||||
}
|
||||
pthread_barrierattr_t :: struct #align 16 {
|
||||
_: [PTHREAD_BARRIERATTR_T_SIZE] c.char,
|
||||
};
|
||||
}
|
||||
|
||||
PTHREAD_MUTEX_ERRORCHECK :: 1;
|
||||
PTHREAD_MUTEX_RECURSIVE :: 2;
|
||||
PTHREAD_MUTEX_NORMAL :: 3;
|
||||
PTHREAD_MUTEX_ERRORCHECK :: 1
|
||||
PTHREAD_MUTEX_RECURSIVE :: 2
|
||||
PTHREAD_MUTEX_NORMAL :: 3
|
||||
|
||||
|
||||
PTHREAD_CREATE_JOINABLE :: 0;
|
||||
PTHREAD_CREATE_DETACHED :: 1;
|
||||
PTHREAD_INHERIT_SCHED :: 4;
|
||||
PTHREAD_EXPLICIT_SCHED :: 0;
|
||||
PTHREAD_PROCESS_PRIVATE :: 0;
|
||||
PTHREAD_PROCESS_SHARED :: 1;
|
||||
PTHREAD_CREATE_JOINABLE :: 0
|
||||
PTHREAD_CREATE_DETACHED :: 1
|
||||
PTHREAD_INHERIT_SCHED :: 4
|
||||
PTHREAD_EXPLICIT_SCHED :: 0
|
||||
PTHREAD_PROCESS_PRIVATE :: 0
|
||||
PTHREAD_PROCESS_SHARED :: 1
|
||||
|
||||
SCHED_FIFO :: 1;
|
||||
SCHED_OTHER :: 2;
|
||||
SCHED_RR :: 3; // Round robin.
|
||||
SCHED_FIFO :: 1
|
||||
SCHED_OTHER :: 2
|
||||
SCHED_RR :: 3 // Round robin.
|
||||
|
||||
|
||||
sched_param :: struct {
|
||||
@@ -98,17 +98,17 @@ foreign import "system:pthread"
|
||||
foreign pthread {
|
||||
// create named semaphore.
|
||||
// used in process-shared semaphores.
|
||||
sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---;
|
||||
sem_open :: proc(name: cstring, flags: c.int) -> ^sem_t ---
|
||||
|
||||
sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---;
|
||||
sem_destroy :: proc(sem: ^sem_t) -> c.int ---;
|
||||
sem_post :: proc(sem: ^sem_t) -> c.int ---;
|
||||
sem_wait :: proc(sem: ^sem_t) -> c.int ---;
|
||||
sem_trywait :: proc(sem: ^sem_t) -> c.int ---;
|
||||
// sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---;
|
||||
sem_init :: proc(sem: ^sem_t, pshared: c.int, initial_value: c.uint) -> c.int ---
|
||||
sem_destroy :: proc(sem: ^sem_t) -> c.int ---
|
||||
sem_post :: proc(sem: ^sem_t) -> c.int ---
|
||||
sem_wait :: proc(sem: ^sem_t) -> c.int ---
|
||||
sem_trywait :: proc(sem: ^sem_t) -> c.int ---
|
||||
// sem_timedwait :: proc(sem: ^sem_t, timeout: time.TimeSpec) -> c.int ---
|
||||
|
||||
// NOTE: unclear whether pthread_yield is well-supported on Linux systems,
|
||||
// see https://linux.die.net/man/3/pthread_yield
|
||||
pthread_yield :: proc() ---;
|
||||
pthread_yield :: proc() ---
|
||||
}
|
||||
|
||||
|
||||
@@ -675,6 +675,8 @@ when ODIN_ARCH == .amd64 {
|
||||
SYS_landlock_create_ruleset : uintptr : 444
|
||||
SYS_landlock_add_rule : uintptr : 445
|
||||
SYS_landlock_restrict_self : uintptr : 446
|
||||
|
||||
SIGCHLD :: 17
|
||||
} else when ODIN_ARCH == .i386 {
|
||||
SYS_restart_syscall : uintptr : 0
|
||||
SYS_exit : uintptr : 1
|
||||
|
||||
@@ -54,6 +54,7 @@ import base64 "core:encoding/base64"
|
||||
import csv "core:encoding/csv"
|
||||
import hxa "core:encoding/hxa"
|
||||
import json "core:encoding/json"
|
||||
import varint "core:encoding/varint"
|
||||
|
||||
import fmt "core:fmt"
|
||||
import hash "core:hash"
|
||||
@@ -153,6 +154,7 @@ _ :: base64
|
||||
_ :: csv
|
||||
_ :: hxa
|
||||
_ :: json
|
||||
_ :: varint
|
||||
_ :: fmt
|
||||
_ :: hash
|
||||
_ :: image
|
||||
|
||||
@@ -94,6 +94,7 @@ the_basics :: proc() {
|
||||
z: f64 // `z` is typed of type `f64` (64-bit floating point number)
|
||||
z = 1 // `1` is an untyped integer literal which can be implicitly converted to `f64`
|
||||
// No need for any suffixes or decimal places like in other languages
|
||||
// (with the exception of negative zero, which must be given as `-0.0`)
|
||||
// CONSTANTS JUST WORK!!!
|
||||
|
||||
|
||||
@@ -1714,7 +1715,6 @@ deprecated_attribute :: proc() {
|
||||
}
|
||||
|
||||
range_statements_with_multiple_return_values :: proc() {
|
||||
// IMPORTANT NOTE(bill, 2019-11-02): This feature is subject to be changed/removed
|
||||
fmt.println("\n#range statements with multiple return values")
|
||||
My_Iterator :: struct {
|
||||
index: int,
|
||||
@@ -2004,7 +2004,6 @@ relative_data_types :: proc() {
|
||||
|
||||
or_else_operator :: proc() {
|
||||
fmt.println("\n#'or_else'")
|
||||
// IMPORTANT NOTE: 'or_else' is an experimental feature and subject to change/removal
|
||||
{
|
||||
m: map[string]int
|
||||
i: int
|
||||
@@ -2035,8 +2034,6 @@ or_else_operator :: proc() {
|
||||
|
||||
or_return_operator :: proc() {
|
||||
fmt.println("\n#'or_return'")
|
||||
// IMPORTANT NOTE: 'or_return' is an experimental feature and subject to change/removal
|
||||
//
|
||||
// The concept of 'or_return' will work by popping off the end value in a multiple
|
||||
// valued expression and checking whether it was not 'nil' or 'false', and if so,
|
||||
// set the end return value to value if possible. If the procedure only has one
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
// #define DEFAULT_TO_THREADED_CHECKER
|
||||
// #endif
|
||||
|
||||
enum TargetOsKind {
|
||||
enum TargetOsKind : u16 {
|
||||
TargetOs_Invalid,
|
||||
|
||||
TargetOs_windows,
|
||||
@@ -26,7 +26,7 @@ enum TargetOsKind {
|
||||
TargetOs_COUNT,
|
||||
};
|
||||
|
||||
enum TargetArchKind {
|
||||
enum TargetArchKind : u16 {
|
||||
TargetArch_Invalid,
|
||||
|
||||
TargetArch_amd64,
|
||||
@@ -38,7 +38,7 @@ enum TargetArchKind {
|
||||
TargetArch_COUNT,
|
||||
};
|
||||
|
||||
enum TargetEndianKind {
|
||||
enum TargetEndianKind : u8 {
|
||||
TargetEndian_Invalid,
|
||||
|
||||
TargetEndian_Little,
|
||||
@@ -47,6 +47,16 @@ enum TargetEndianKind {
|
||||
TargetEndian_COUNT,
|
||||
};
|
||||
|
||||
enum TargetABIKind : u16 {
|
||||
TargetABI_Default,
|
||||
|
||||
TargetABI_Win64,
|
||||
TargetABI_SysV,
|
||||
|
||||
TargetABI_COUNT,
|
||||
};
|
||||
|
||||
|
||||
String target_os_names[TargetOs_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("windows"),
|
||||
@@ -77,6 +87,12 @@ String target_endian_names[TargetEndian_COUNT] = {
|
||||
str_lit("big"),
|
||||
};
|
||||
|
||||
String target_abi_names[TargetABI_COUNT] = {
|
||||
str_lit(""),
|
||||
str_lit("win64"),
|
||||
str_lit("sysv"),
|
||||
};
|
||||
|
||||
TargetEndianKind target_endians[TargetArch_COUNT] = {
|
||||
TargetEndian_Invalid,
|
||||
TargetEndian_Little,
|
||||
@@ -100,6 +116,7 @@ struct TargetMetrics {
|
||||
isize max_align;
|
||||
String target_triplet;
|
||||
String target_data_layout;
|
||||
TargetABIKind abi;
|
||||
};
|
||||
|
||||
|
||||
@@ -174,6 +191,13 @@ enum ErrorPosStyle {
|
||||
ErrorPosStyle_COUNT
|
||||
};
|
||||
|
||||
enum RelocMode : u8 {
|
||||
RelocMode_Default,
|
||||
RelocMode_Static,
|
||||
RelocMode_PIC,
|
||||
RelocMode_DynamicNoPIC,
|
||||
};
|
||||
|
||||
// This stores the information for the specify architecture of this build
|
||||
struct BuildContext {
|
||||
// Constants
|
||||
@@ -185,6 +209,7 @@ struct BuildContext {
|
||||
bool ODIN_DEBUG; // Odin in debug mode
|
||||
bool ODIN_DISABLE_ASSERT; // Whether the default 'assert' et al is disabled in code or not
|
||||
bool ODIN_DEFAULT_TO_NIL_ALLOCATOR; // Whether the default allocator is a "nil" allocator or not (i.e. it does nothing)
|
||||
bool ODIN_FOREIGN_ERROR_PROCEDURES;
|
||||
|
||||
ErrorPosStyle ODIN_ERROR_POS_STYLE;
|
||||
|
||||
@@ -209,6 +234,7 @@ struct BuildContext {
|
||||
String extra_linker_flags;
|
||||
String extra_assembler_flags;
|
||||
String microarch;
|
||||
String target_features;
|
||||
BuildModeKind build_mode;
|
||||
bool generate_docs;
|
||||
i32 optimization_level;
|
||||
@@ -254,6 +280,12 @@ struct BuildContext {
|
||||
|
||||
bool copy_file_contents;
|
||||
|
||||
bool disallow_rtti;
|
||||
|
||||
RelocMode reloc_mode;
|
||||
bool disable_red_zone;
|
||||
|
||||
|
||||
u32 cmd_doc_flags;
|
||||
Array<String> extra_packages;
|
||||
|
||||
@@ -410,6 +442,16 @@ gb_global TargetMetrics target_wasi_wasm32 = {
|
||||
// str_lit(""),
|
||||
// };
|
||||
|
||||
gb_global TargetMetrics target_freestanding_amd64_sysv = {
|
||||
TargetOs_freestanding,
|
||||
TargetArch_amd64,
|
||||
8,
|
||||
16,
|
||||
str_lit("x86_64-pc-none-gnu"),
|
||||
str_lit("e-m:w-i64:64-f80:128-n8:16:32:64-S128"),
|
||||
TargetABI_SysV,
|
||||
};
|
||||
|
||||
|
||||
|
||||
struct NamedTargetMetrics {
|
||||
@@ -432,7 +474,8 @@ gb_global NamedTargetMetrics named_targets[] = {
|
||||
{ str_lit("freestanding_wasm32"), &target_freestanding_wasm32 },
|
||||
{ str_lit("wasi_wasm32"), &target_wasi_wasm32 },
|
||||
{ str_lit("js_wasm32"), &target_js_wasm32 },
|
||||
// { str_lit("freestanding_wasm64"), &target_freestanding_wasm64 },
|
||||
|
||||
{ str_lit("freestanding_amd64_sysv"), &target_freestanding_amd64_sysv },
|
||||
};
|
||||
|
||||
NamedTargetMetrics *selected_target_metrics;
|
||||
@@ -946,7 +989,6 @@ void init_build_context(TargetMetrics *cross_target) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bc->copy_file_contents = true;
|
||||
|
||||
TargetMetrics *metrics = nullptr;
|
||||
@@ -1005,6 +1047,21 @@ void init_build_context(TargetMetrics *cross_target) {
|
||||
bc->threaded_checker = true;
|
||||
#endif
|
||||
|
||||
if (bc->disable_red_zone) {
|
||||
if (!!is_arch_wasm() && bc->metrics.os == TargetOs_freestanding) {
|
||||
gb_printf_err("-disable-red-zone is not support for this target");
|
||||
gb_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (bc->metrics.os == TargetOs_freestanding) {
|
||||
bc->no_entry_point = true;
|
||||
} else {
|
||||
if (bc->disallow_rtti) {
|
||||
gb_printf_err("-disallow-rtti is only allowed on freestanding targets\n");
|
||||
gb_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
// NOTE(zangent): The linker flags to set the build architecture are different
|
||||
// across OSs. It doesn't make sense to allocate extra data on the heap
|
||||
@@ -1059,14 +1116,14 @@ void init_build_context(TargetMetrics *cross_target) {
|
||||
if (bc->metrics.arch == TargetArch_wasm64) {
|
||||
link_flags = gb_string_appendc(link_flags, "-mwas64 ");
|
||||
}
|
||||
if (bc->metrics.os == TargetOs_freestanding) {
|
||||
if (bc->no_entry_point) {
|
||||
link_flags = gb_string_appendc(link_flags, "--no-entry ");
|
||||
}
|
||||
|
||||
bc->link_flags = make_string_c(link_flags);
|
||||
|
||||
// Disallow on wasm
|
||||
build_context.use_separate_modules = false;
|
||||
bc->use_separate_modules = false;
|
||||
} else {
|
||||
gb_printf_err("Compiler Error: Unsupported architecture\n");
|
||||
gb_exit(1);
|
||||
@@ -1074,6 +1131,8 @@ void init_build_context(TargetMetrics *cross_target) {
|
||||
|
||||
bc->optimization_level = gb_clamp(bc->optimization_level, 0, 3);
|
||||
|
||||
|
||||
|
||||
#undef LINK_FLAG_X64
|
||||
#undef LINK_FLAG_386
|
||||
}
|
||||
|
||||
@@ -1241,6 +1241,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
if (c->scope->flags&ScopeFlag_Global) {
|
||||
compiler_error("'type_info_of' Cannot be declared within the runtime package due to how the internals of the compiler works");
|
||||
}
|
||||
if (build_context.disallow_rtti) {
|
||||
error(call, "'%.*s' has been disallowed", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE(bill): The type information may not be setup yet
|
||||
init_core_type_info(c->checker);
|
||||
@@ -1253,9 +1257,9 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
Type *t = o.type;
|
||||
if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(t)) {
|
||||
if (is_type_polymorphic(t)) {
|
||||
error(ce->args[0], "Invalid argument for 'type_info_of', unspecialized polymorphic type");
|
||||
error(ce->args[0], "Invalid argument for '%.*s', unspecialized polymorphic type", LIT(builtin_name));
|
||||
} else {
|
||||
error(ce->args[0], "Invalid argument for 'type_info_of'");
|
||||
error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -1266,7 +1270,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
if (is_operand_value(o) && is_type_typeid(t)) {
|
||||
add_package_dependency(c, "runtime", "__type_info_of");
|
||||
} else if (o.mode != Addressing_Type) {
|
||||
error(expr, "Expected a type or typeid for 'type_info_of'");
|
||||
error(expr, "Expected a type or typeid for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -1280,6 +1284,10 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
if (c->scope->flags&ScopeFlag_Global) {
|
||||
compiler_error("'typeid_of' Cannot be declared within the runtime package due to how the internals of the compiler works");
|
||||
}
|
||||
if (build_context.disallow_rtti) {
|
||||
error(call, "'%.*s' has been disallowed", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
// NOTE(bill): The type information may not be setup yet
|
||||
init_core_type_info(c->checker);
|
||||
@@ -1291,7 +1299,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
}
|
||||
Type *t = o.type;
|
||||
if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) {
|
||||
error(ce->args[0], "Invalid argument for 'typeid_of'");
|
||||
error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
t = default_type(t);
|
||||
@@ -1299,7 +1307,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
|
||||
add_type_info_type(c, t);
|
||||
|
||||
if (o.mode != Addressing_Type) {
|
||||
error(expr, "Expected a type for 'typeid_of'");
|
||||
error(expr, "Expected a type for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -440,6 +440,12 @@ void check_const_decl(CheckerContext *ctx, Entity *e, Ast *type_expr, Ast *init,
|
||||
|
||||
if (type_expr) {
|
||||
e->type = check_type(ctx, type_expr);
|
||||
if (are_types_identical(e->type, t_typeid)) {
|
||||
e->type = nullptr;
|
||||
e->kind = Entity_TypeName;
|
||||
check_type_decl(ctx, e, init, named_type);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Operand operand = {};
|
||||
@@ -1130,6 +1136,10 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
|
||||
}
|
||||
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
|
||||
|
||||
if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
|
||||
error(e->token, "@(thread_local) is not supported for this target platform");
|
||||
}
|
||||
|
||||
String context_name = str_lit("variable declaration");
|
||||
|
||||
if (type_expr != nullptr) {
|
||||
@@ -1205,6 +1215,8 @@ void check_global_variable_decl(CheckerContext *ctx, Entity *&e, Ast *type_expr,
|
||||
Operand o = {};
|
||||
check_expr_with_type_hint(ctx, &o, init_expr, e->type);
|
||||
check_init_variable(ctx, e, &o, str_lit("variable declaration"));
|
||||
|
||||
check_rtti_type_disallowed(e->token, e->type, "A variable declaration is using a type, %s, which has been disallowed");
|
||||
}
|
||||
|
||||
void check_proc_group_decl(CheckerContext *ctx, Entity *&pg_entity, DeclInfo *d) {
|
||||
|
||||
@@ -9352,6 +9352,8 @@ ExprKind check_expr_base(CheckerContext *c, Operand *o, Ast *node, Type *type_hi
|
||||
if (o->type != nullptr && is_type_untyped(o->type)) {
|
||||
add_untyped(c, node, o->mode, o->type, o->value);
|
||||
}
|
||||
check_rtti_type_disallowed(node, o->type, "An expression is using a type, %s, which has been disallowed");
|
||||
|
||||
add_type_and_value(c->info, node, o->mode, o->type, o->value);
|
||||
return kind;
|
||||
}
|
||||
|
||||
@@ -2152,7 +2152,6 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
e->state = EntityState_Resolved;
|
||||
}
|
||||
ac.link_name = handle_link_name(ctx, e->token, ac.link_name, ac.link_prefix);
|
||||
e->Variable.thread_local_model = ac.thread_local_model;
|
||||
|
||||
if (ac.link_name.len > 0) {
|
||||
e->Variable.link_name = ac.link_name;
|
||||
@@ -2182,6 +2181,10 @@ void check_stmt_internal(CheckerContext *ctx, Ast *node, u32 flags) {
|
||||
}
|
||||
e->Variable.thread_local_model = ac.thread_local_model;
|
||||
}
|
||||
|
||||
if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
|
||||
error(e->token, "@(thread_local) is not supported for this target platform");
|
||||
}
|
||||
|
||||
|
||||
if (ac.is_static && ac.thread_local_model != "") {
|
||||
|
||||
@@ -2031,10 +2031,14 @@ bool check_procedure_type(CheckerContext *ctx, Type *type, Ast *proc_type_node,
|
||||
if (param_count > 0) {
|
||||
Entity *end = params->Tuple.variables[param_count-1];
|
||||
if (end->flags&EntityFlag_CVarArg) {
|
||||
if (cc == ProcCC_StdCall || cc == ProcCC_CDecl) {
|
||||
switch (cc) {
|
||||
default:
|
||||
type->Proc.c_vararg = true;
|
||||
} else {
|
||||
break;
|
||||
case ProcCC_Odin:
|
||||
case ProcCC_Contextless:
|
||||
error(end->token, "Calling convention does not support #c_vararg");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2170,7 +2174,7 @@ void init_map_entry_type(Type *type) {
|
||||
|
||||
/*
|
||||
struct {
|
||||
hash: runtime.Map_Hash,
|
||||
hash: uintptr,
|
||||
next: int,
|
||||
key: Key,
|
||||
value: Value,
|
||||
@@ -3027,5 +3031,7 @@ Type *check_type_expr(CheckerContext *ctx, Ast *e, Type *named_type) {
|
||||
}
|
||||
set_base_type(named_type, type);
|
||||
|
||||
check_rtti_type_disallowed(e, type, "Use of a type, %s, which has been disallowed");
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
101
src/checker.cpp
101
src/checker.cpp
@@ -29,6 +29,23 @@ bool is_operand_undef(Operand o) {
|
||||
return o.mode == Addressing_Value && o.type == t_untyped_undef;
|
||||
}
|
||||
|
||||
bool check_rtti_type_disallowed(Token const &token, Type *type, char const *format) {
|
||||
if (build_context.disallow_rtti && type) {
|
||||
if (is_type_any(type)) {
|
||||
gbString t = type_to_string(type);
|
||||
error(token, format, t);
|
||||
gb_string_free(t);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool check_rtti_type_disallowed(Ast *expr, Type *type, char const *format) {
|
||||
GB_ASSERT(expr != nullptr);
|
||||
return check_rtti_type_disallowed(ast_token(expr), type, format);
|
||||
}
|
||||
|
||||
void scope_reset(Scope *scope) {
|
||||
if (scope == nullptr) return;
|
||||
|
||||
@@ -875,7 +892,8 @@ void init_universal(void) {
|
||||
|
||||
// Types
|
||||
for (isize i = 0; i < gb_count_of(basic_types); i++) {
|
||||
add_global_type_entity(basic_types[i].Basic.name, &basic_types[i]);
|
||||
String const &name = basic_types[i].Basic.name;
|
||||
add_global_type_entity(name, &basic_types[i]);
|
||||
}
|
||||
add_global_type_entity(str_lit("byte"), &basic_types[Basic_u8]);
|
||||
|
||||
@@ -977,6 +995,8 @@ void init_universal(void) {
|
||||
add_global_bool_constant("ODIN_USE_SEPARATE_MODULES", bc->use_separate_modules);
|
||||
add_global_bool_constant("ODIN_TEST", bc->command_kind == Command_test);
|
||||
add_global_bool_constant("ODIN_NO_ENTRY_POINT", bc->no_entry_point);
|
||||
add_global_bool_constant("ODIN_FOREIGN_ERROR_PROCEDURES", bc->ODIN_FOREIGN_ERROR_PROCEDURES);
|
||||
add_global_bool_constant("ODIN_DISALLOW_RTTI", bc->disallow_rtti);
|
||||
|
||||
|
||||
// Builtin Procedures
|
||||
@@ -1669,6 +1689,10 @@ void add_implicit_entity(CheckerContext *c, Ast *clause, Entity *e) {
|
||||
void add_type_info_type(CheckerContext *c, Type *t) {
|
||||
void add_type_info_type_internal(CheckerContext *c, Type *t);
|
||||
|
||||
if (build_context.disallow_rtti) {
|
||||
return;
|
||||
}
|
||||
|
||||
mutex_lock(&c->info->type_info_mutex);
|
||||
add_type_info_type_internal(c, t);
|
||||
mutex_unlock(&c->info->type_info_mutex);
|
||||
@@ -2181,21 +2205,25 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
ptr_set_init(&c->info.minimum_dependency_set, heap_allocator(), min_dep_set_cap);
|
||||
ptr_set_init(&c->info.minimum_dependency_type_info_set, heap_allocator());
|
||||
|
||||
String required_runtime_entities[] = {
|
||||
#define FORCE_ADD_RUNTIME_ENTITIES(condition, ...) do { \
|
||||
if (condition) { \
|
||||
String entities[] = {__VA_ARGS__}; \
|
||||
for (isize i = 0; i < gb_count_of(entities); i++) { \
|
||||
force_add_dependency_entity(c, c->info.runtime_package->scope, entities[i]); \
|
||||
} \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
// required runtime entities
|
||||
FORCE_ADD_RUNTIME_ENTITIES(true,
|
||||
// Odin types
|
||||
str_lit("Type_Info"),
|
||||
str_lit("Source_Code_Location"),
|
||||
str_lit("Context"),
|
||||
str_lit("Allocator"),
|
||||
str_lit("Logger"),
|
||||
|
||||
// Global variables
|
||||
str_lit("args__"),
|
||||
str_lit("type_table"),
|
||||
|
||||
// Odin internal procedures
|
||||
str_lit("__init_context"),
|
||||
str_lit("__type_info_of"),
|
||||
str_lit("cstring_to_string"),
|
||||
str_lit("_cleanup_runtime"),
|
||||
|
||||
@@ -2228,35 +2256,36 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
// WASM Specific
|
||||
str_lit("__ashlti3"),
|
||||
str_lit("__multi3"),
|
||||
};
|
||||
for (isize i = 0; i < gb_count_of(required_runtime_entities); i++) {
|
||||
force_add_dependency_entity(c, c->info.runtime_package->scope, required_runtime_entities[i]);
|
||||
}
|
||||
);
|
||||
|
||||
if (build_context.no_crt) {
|
||||
String required_no_crt_entities[] = {
|
||||
// NOTE(bill): Only if these exist
|
||||
str_lit("_tls_index"),
|
||||
str_lit("_fltused"),
|
||||
};
|
||||
for (isize i = 0; i < gb_count_of(required_no_crt_entities); i++) {
|
||||
force_add_dependency_entity(c, c->info.runtime_package->scope, required_no_crt_entities[i]);
|
||||
}
|
||||
}
|
||||
FORCE_ADD_RUNTIME_ENTITIES(!build_context.disallow_rtti,
|
||||
// Odin types
|
||||
str_lit("Type_Info"),
|
||||
|
||||
if (!build_context.no_bounds_check) {
|
||||
String bounds_check_entities[] = {
|
||||
// Bounds checking related procedures
|
||||
str_lit("bounds_check_error"),
|
||||
str_lit("matrix_bounds_check_error"),
|
||||
str_lit("slice_expr_error_hi"),
|
||||
str_lit("slice_expr_error_lo_hi"),
|
||||
str_lit("multi_pointer_slice_expr_error"),
|
||||
};
|
||||
for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) {
|
||||
force_add_dependency_entity(c, c->info.runtime_package->scope, bounds_check_entities[i]);
|
||||
}
|
||||
}
|
||||
// Global variables
|
||||
str_lit("type_table"),
|
||||
str_lit("__type_info_of"),
|
||||
);
|
||||
|
||||
FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_entry_point,
|
||||
// Global variables
|
||||
str_lit("args__"),
|
||||
);
|
||||
|
||||
FORCE_ADD_RUNTIME_ENTITIES((build_context.no_crt && !is_arch_wasm()),
|
||||
// NOTE(bill): Only if these exist
|
||||
str_lit("_tls_index"),
|
||||
str_lit("_fltused"),
|
||||
);
|
||||
|
||||
FORCE_ADD_RUNTIME_ENTITIES(!build_context.no_bounds_check,
|
||||
// Bounds checking related procedures
|
||||
str_lit("bounds_check_error"),
|
||||
str_lit("matrix_bounds_check_error"),
|
||||
str_lit("slice_expr_error_hi"),
|
||||
str_lit("slice_expr_error_lo_hi"),
|
||||
str_lit("multi_pointer_slice_expr_error"),
|
||||
);
|
||||
|
||||
for_array(i, c->info.definitions) {
|
||||
Entity *e = c->info.definitions[i];
|
||||
@@ -2378,6 +2407,8 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
|
||||
start->flags |= EntityFlag_Used;
|
||||
add_dependency_to_set(c, start);
|
||||
}
|
||||
|
||||
#undef FORCE_ADD_RUNTIME_ENTITIES
|
||||
}
|
||||
|
||||
bool is_entity_a_dependency(Entity *e) {
|
||||
|
||||
@@ -1194,8 +1194,10 @@ LB_ABI_INFO(lb_get_abi_info) {
|
||||
|
||||
switch (build_context.metrics.arch) {
|
||||
case TargetArch_amd64:
|
||||
if (build_context.metrics.os == TargetOs_windows) {
|
||||
if (build_context.metrics.os == TargetOs_windows || build_context.metrics.abi == TargetABI_Win64) {
|
||||
return lbAbiAmd64Win64::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
} else if (build_context.metrics.abi == TargetABI_SysV) {
|
||||
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
} else {
|
||||
return lbAbiAmd64SysV::abi_info(c, arg_types, arg_count, return_type, return_is_defined, calling_convention);
|
||||
}
|
||||
|
||||
@@ -624,6 +624,9 @@ struct lbGlobalVariable {
|
||||
};
|
||||
|
||||
lbProcedure *lb_create_startup_type_info(lbModule *m) {
|
||||
if (build_context.disallow_rtti) {
|
||||
return nullptr;
|
||||
}
|
||||
LLVMPassManagerRef default_function_pass_manager = LLVMCreateFunctionPassManagerForModule(m->mod);
|
||||
lb_populate_function_pass_manager(m, default_function_pass_manager, false, build_context.optimization_level);
|
||||
LLVMFinalizeFunctionPassManager(default_function_pass_manager);
|
||||
@@ -711,7 +714,9 @@ lbProcedure *lb_create_startup_runtime(lbModule *main_module, lbProcedure *start
|
||||
|
||||
lb_begin_procedure_body(p);
|
||||
|
||||
LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
|
||||
if (startup_type_info) {
|
||||
LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, startup_type_info->type)), startup_type_info->value, nullptr, 0, "");
|
||||
}
|
||||
|
||||
if (objc_names) {
|
||||
LLVMBuildCall2(p->builder, LLVMGetElementType(lb_type(main_module, objc_names->type)), objc_names->value, nullptr, 0, "");
|
||||
@@ -996,6 +1001,19 @@ String lb_filepath_obj_for_module(lbModule *m) {
|
||||
case TargetOs_essence:
|
||||
ext = STR_LIT(".o");
|
||||
break;
|
||||
|
||||
case TargetOs_freestanding:
|
||||
switch (build_context.metrics.abi) {
|
||||
default:
|
||||
case TargetABI_Default:
|
||||
case TargetABI_SysV:
|
||||
ext = STR_LIT(".o");
|
||||
break;
|
||||
case TargetABI_Win64:
|
||||
ext = STR_LIT(".obj");
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1248,6 +1266,8 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
LLVMCodeModel code_mode = LLVMCodeModelDefault;
|
||||
if (is_arch_wasm()) {
|
||||
code_mode = LLVMCodeModelJITDefault;
|
||||
} else if (build_context.metrics.os == TargetOs_freestanding) {
|
||||
code_mode = LLVMCodeModelKernel;
|
||||
}
|
||||
|
||||
char const *host_cpu_name = LLVMGetHostCPUName();
|
||||
@@ -1270,10 +1290,18 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
// x86-64-v3: (close to Haswell) AVX, AVX2, BMI1, BMI2, F16C, FMA, LZCNT, MOVBE, XSAVE
|
||||
// x86-64-v4: AVX512F, AVX512BW, AVX512CD, AVX512DQ, AVX512VL
|
||||
if (ODIN_LLVM_MINIMUM_VERSION_12) {
|
||||
llvm_cpu = "x86-64-v2";
|
||||
if (build_context.metrics.os == TargetOs_freestanding) {
|
||||
llvm_cpu = "x86-64";
|
||||
} else {
|
||||
llvm_cpu = "x86-64-v2";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (build_context.target_features.len != 0) {
|
||||
llvm_features = alloc_cstring(permanent_allocator(), build_context.target_features);
|
||||
}
|
||||
|
||||
// GB_ASSERT_MSG(LLVMTargetHasAsmBackend(target));
|
||||
|
||||
LLVMCodeGenOptLevel code_gen_level = LLVMCodeGenLevelNone;
|
||||
@@ -1295,9 +1323,22 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
reloc_mode = LLVMRelocPIC;
|
||||
}
|
||||
|
||||
if (build_context.metrics.os == TargetOs_openbsd) {
|
||||
// Always use PIC for OpenBSD: it defaults to PIE
|
||||
switch (build_context.reloc_mode) {
|
||||
case RelocMode_Default:
|
||||
if (build_context.metrics.os == TargetOs_openbsd) {
|
||||
// Always use PIC for OpenBSD: it defaults to PIE
|
||||
reloc_mode = LLVMRelocPIC;
|
||||
}
|
||||
break;
|
||||
case RelocMode_Static:
|
||||
reloc_mode = LLVMRelocStatic;
|
||||
break;
|
||||
case RelocMode_PIC:
|
||||
reloc_mode = LLVMRelocPIC;
|
||||
break;
|
||||
case RelocMode_DynamicNoPIC:
|
||||
reloc_mode = LLVMRelocDynamicNoPic;
|
||||
break;
|
||||
}
|
||||
|
||||
for_array(i, gen->modules.entries) {
|
||||
@@ -1366,7 +1407,7 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
|
||||
TIME_SECTION("LLVM Global Variables");
|
||||
|
||||
{
|
||||
if (!build_context.disallow_rtti) {
|
||||
lbModule *m = default_module;
|
||||
|
||||
{ // Add type info data
|
||||
@@ -1473,9 +1514,8 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
if ((e->scope->flags&ScopeFlag_Init) && name == "main") {
|
||||
GB_ASSERT(e == info->entry_point);
|
||||
}
|
||||
if (e->Procedure.is_export ||
|
||||
(e->Procedure.link_name.len > 0) ||
|
||||
((e->scope->flags&ScopeFlag_File) && e->Procedure.link_name.len > 0)) {
|
||||
if (build_context.command_kind == Command_test &&
|
||||
(e->Procedure.is_export || e->Procedure.link_name.len > 0)) {
|
||||
String link_name = e->Procedure.link_name;
|
||||
if (e->pkg->kind == Package_Runtime) {
|
||||
if (link_name == "main" ||
|
||||
@@ -1699,6 +1739,11 @@ void lb_generate_code(lbGenerator *gen) {
|
||||
}
|
||||
}
|
||||
|
||||
if (build_context.command_kind == Command_test && !already_has_entry_point) {
|
||||
TIME_SECTION("LLVM main");
|
||||
lb_create_main_procedure(default_module, startup_runtime);
|
||||
}
|
||||
|
||||
for_array(j, gen->modules.entries) {
|
||||
lbModule *m = gen->modules.entries[j].value;
|
||||
for_array(i, m->missing_procedures_to_check) {
|
||||
|
||||
@@ -2824,16 +2824,25 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
|
||||
src_tag = lb_emit_load(p, lb_emit_union_tag_ptr(p, v));
|
||||
dst_tag = lb_const_union_tag(p->module, src_type, dst_type);
|
||||
}
|
||||
|
||||
|
||||
isize arg_count = 6;
|
||||
if (build_context.disallow_rtti) {
|
||||
arg_count = 4;
|
||||
}
|
||||
|
||||
lbValue ok = lb_emit_comp(p, Token_CmpEq, src_tag, dst_tag);
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 6);
|
||||
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
|
||||
args[0] = ok;
|
||||
|
||||
args[1] = lb_find_or_add_entity_string(p->module, get_file_path_string(pos.file_id));
|
||||
args[2] = lb_const_int(p->module, t_i32, pos.line);
|
||||
args[3] = lb_const_int(p->module, t_i32, pos.column);
|
||||
|
||||
args[4] = lb_typeid(p->module, src_type);
|
||||
args[5] = lb_typeid(p->module, dst_type);
|
||||
if (!build_context.disallow_rtti) {
|
||||
args[4] = lb_typeid(p->module, src_type);
|
||||
args[5] = lb_typeid(p->module, dst_type);
|
||||
}
|
||||
lb_emit_runtime_call(p, "type_assertion_check", args);
|
||||
}
|
||||
|
||||
@@ -2846,6 +2855,8 @@ lbValue lb_build_unary_and(lbProcedure *p, Ast *expr) {
|
||||
}
|
||||
lbValue data_ptr = lb_emit_struct_ev(p, v, 0);
|
||||
if ((p->state_flags & StateFlag_no_type_assert) == 0) {
|
||||
GB_ASSERT(!build_context.disallow_rtti);
|
||||
|
||||
lbValue any_id = lb_emit_struct_ev(p, v, 1);
|
||||
|
||||
lbValue id = lb_typeid(p->module, type);
|
||||
|
||||
@@ -135,6 +135,10 @@ lbProcedure *lb_create_procedure(lbModule *m, Entity *entity, bool ignore_body)
|
||||
lb_add_attribute_to_proc(m, p->value, "naked");
|
||||
}
|
||||
|
||||
if (!entity->Procedure.is_foreign && build_context.disable_red_zone) {
|
||||
lb_add_attribute_to_proc(m, p->value, "noredzone");
|
||||
}
|
||||
|
||||
switch (p->inlining) {
|
||||
case ProcInlining_inline:
|
||||
lb_add_attribute_to_proc(m, p->value, "alwaysinline");
|
||||
@@ -1402,14 +1406,23 @@ lbValue lb_build_builtin_proc(lbProcedure *p, Ast *expr, TypeAndValue const &tv,
|
||||
|
||||
case BuiltinProc_read_cycle_counter:
|
||||
{
|
||||
char const *name = "llvm.readcyclecounter";
|
||||
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
|
||||
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
|
||||
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
|
||||
|
||||
lbValue res = {};
|
||||
res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, "");
|
||||
res.type = tv.type;
|
||||
|
||||
if (build_context.metrics.arch == TargetArch_arm64) {
|
||||
LLVMTypeRef func_type = LLVMFunctionType(LLVMInt64TypeInContext(p->module->ctx), nullptr, 0, false);
|
||||
bool has_side_effects = false;
|
||||
LLVMValueRef the_asm = llvm_get_inline_asm(func_type, str_lit("mrs x9, cntvct_el0"), str_lit("=r"), has_side_effects);
|
||||
GB_ASSERT(the_asm != nullptr);
|
||||
res.value = LLVMBuildCall2(p->builder, func_type, the_asm, nullptr, 0, "");
|
||||
} else {
|
||||
char const *name = "llvm.readcyclecounter";
|
||||
unsigned id = LLVMLookupIntrinsicID(name, gb_strlen(name));
|
||||
GB_ASSERT_MSG(id != 0, "Unable to find %s", name);
|
||||
LLVMValueRef ip = LLVMGetIntrinsicDeclaration(p->module->mod, id, nullptr, 0);
|
||||
|
||||
res.value = LLVMBuildCall(p->builder, ip, nullptr, 0, "");
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
@@ -14,6 +14,8 @@ isize lb_type_info_index(CheckerInfo *info, Type *type, bool err_on_not_found=tr
|
||||
}
|
||||
|
||||
lbValue lb_typeid(lbModule *m, Type *type) {
|
||||
GB_ASSERT(!build_context.disallow_rtti);
|
||||
|
||||
type = default_type(type);
|
||||
|
||||
u64 id = cast(u64)lb_type_info_index(m->info, type);
|
||||
@@ -88,6 +90,8 @@ lbValue lb_typeid(lbModule *m, Type *type) {
|
||||
}
|
||||
|
||||
lbValue lb_type_info(lbModule *m, Type *type) {
|
||||
GB_ASSERT(!build_context.disallow_rtti);
|
||||
|
||||
type = default_type(type);
|
||||
|
||||
isize index = lb_type_info_index(m->info, type);
|
||||
@@ -106,6 +110,8 @@ lbValue lb_type_info(lbModule *m, Type *type) {
|
||||
}
|
||||
|
||||
lbValue lb_get_type_info_ptr(lbModule *m, Type *type) {
|
||||
GB_ASSERT(!build_context.disallow_rtti);
|
||||
|
||||
i32 index = cast(i32)lb_type_info_index(m->info, type);
|
||||
GB_ASSERT(index >= 0);
|
||||
// gb_printf_err("%d %s\n", index, type_to_string(type));
|
||||
@@ -155,6 +161,10 @@ lbValue lb_type_info_member_tags_offset(lbProcedure *p, isize count) {
|
||||
|
||||
|
||||
void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info data
|
||||
if (build_context.disallow_rtti) {
|
||||
return;
|
||||
}
|
||||
|
||||
lbModule *m = p->module;
|
||||
CheckerInfo *info = m->info;
|
||||
|
||||
|
||||
@@ -676,17 +676,24 @@ lbValue lb_emit_union_cast(lbProcedure *p, lbValue value, Type *type, TokenPos p
|
||||
// NOTE(bill): Panic on invalid conversion
|
||||
Type *dst_type = tuple->Tuple.variables[0]->type;
|
||||
|
||||
isize arg_count = 7;
|
||||
if (build_context.disallow_rtti) {
|
||||
arg_count = 4;
|
||||
}
|
||||
|
||||
lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 7);
|
||||
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
|
||||
args[0] = ok;
|
||||
|
||||
args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
|
||||
args[2] = lb_const_int(m, t_i32, pos.line);
|
||||
args[3] = lb_const_int(m, t_i32, pos.column);
|
||||
|
||||
args[4] = lb_typeid(m, src_type);
|
||||
args[5] = lb_typeid(m, dst_type);
|
||||
args[6] = lb_emit_conv(p, value_, t_rawptr);
|
||||
if (!build_context.disallow_rtti) {
|
||||
args[4] = lb_typeid(m, src_type);
|
||||
args[5] = lb_typeid(m, dst_type);
|
||||
args[6] = lb_emit_conv(p, value_, t_rawptr);
|
||||
}
|
||||
lb_emit_runtime_call(p, "type_assertion_check2", args);
|
||||
|
||||
return lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 0));
|
||||
@@ -744,16 +751,23 @@ lbAddr lb_emit_any_cast_addr(lbProcedure *p, lbValue value, Type *type, TokenPos
|
||||
if (!is_tuple) {
|
||||
// NOTE(bill): Panic on invalid conversion
|
||||
lbValue ok = lb_emit_load(p, lb_emit_struct_ep(p, v.addr, 1));
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 7);
|
||||
|
||||
isize arg_count = 7;
|
||||
if (build_context.disallow_rtti) {
|
||||
arg_count = 4;
|
||||
}
|
||||
auto args = array_make<lbValue>(permanent_allocator(), arg_count);
|
||||
args[0] = ok;
|
||||
|
||||
args[1] = lb_const_string(m, get_file_path_string(pos.file_id));
|
||||
args[2] = lb_const_int(m, t_i32, pos.line);
|
||||
args[3] = lb_const_int(m, t_i32, pos.column);
|
||||
|
||||
args[4] = any_typeid;
|
||||
args[5] = dst_typeid;
|
||||
args[6] = lb_emit_struct_ev(p, value, 0);;
|
||||
if (!build_context.disallow_rtti) {
|
||||
args[4] = any_typeid;
|
||||
args[5] = dst_typeid;
|
||||
args[6] = lb_emit_struct_ev(p, value, 0);
|
||||
}
|
||||
lb_emit_runtime_call(p, "type_assertion_check2", args);
|
||||
|
||||
return lb_addr(lb_emit_struct_ep(p, v.addr, 0));
|
||||
@@ -1779,7 +1793,7 @@ LLVMValueRef llvm_get_inline_asm(LLVMTypeRef func_type, String const &str, Strin
|
||||
return LLVMGetInlineAsm(func_type,
|
||||
cast(char *)str.text, cast(size_t)str.len,
|
||||
cast(char *)clobbers.text, cast(size_t)clobbers.len,
|
||||
/*HasSideEffects*/true, /*IsAlignStack*/false,
|
||||
has_side_effects, is_align_stack,
|
||||
dialect
|
||||
#if LLVM_VERSION_MAJOR >= 13
|
||||
, /*CanThrow*/false
|
||||
|
||||
72
src/main.cpp
72
src/main.cpp
@@ -632,6 +632,10 @@ enum BuildFlagKind {
|
||||
BuildFlag_ExtraLinkerFlags,
|
||||
BuildFlag_ExtraAssemblerFlags,
|
||||
BuildFlag_Microarch,
|
||||
BuildFlag_TargetFeatures,
|
||||
|
||||
BuildFlag_RelocMode,
|
||||
BuildFlag_DisableRedZone,
|
||||
|
||||
BuildFlag_TestName,
|
||||
|
||||
@@ -640,6 +644,8 @@ enum BuildFlagKind {
|
||||
BuildFlag_InsertSemicolon,
|
||||
BuildFlag_StrictStyle,
|
||||
BuildFlag_StrictStyleInitOnly,
|
||||
BuildFlag_ForeignErrorProcedures,
|
||||
BuildFlag_DisallowRTTI,
|
||||
|
||||
BuildFlag_Compact,
|
||||
BuildFlag_GlobalDefinitions,
|
||||
@@ -784,7 +790,11 @@ bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_IgnoreUnknownAttributes, str_lit("ignore-unknown-attributes"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_ExtraLinkerFlags, str_lit("extra-linker-flags"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_ExtraAssemblerFlags, str_lit("extra-assembler-flags"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_Microarch, str_lit("microarch"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_TargetFeatures, str_lit("target-features"), BuildFlagParam_String, Command__does_build);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_RelocMode, str_lit("reloc-mode"), BuildFlagParam_String, Command__does_build);
|
||||
add_flag(&build_flags, BuildFlag_DisableRedZone, str_lit("disable-red-zone"), BuildFlagParam_None, Command__does_build);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_TestName, str_lit("test-name"), BuildFlagParam_String, Command_test);
|
||||
|
||||
@@ -793,10 +803,16 @@ bool parse_build_flags(Array<String> args) {
|
||||
add_flag(&build_flags, BuildFlag_InsertSemicolon, str_lit("insert-semicolon"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_StrictStyle, str_lit("strict-style"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_StrictStyleInitOnly, str_lit("strict-style-init-only"), BuildFlagParam_None, Command__does_check);
|
||||
add_flag(&build_flags, BuildFlag_ForeignErrorProcedures, str_lit("foreign-error-procedures"), BuildFlagParam_None, Command__does_check);
|
||||
|
||||
add_flag(&build_flags, BuildFlag_DisallowRTTI, str_lit("disallow-rtti"), BuildFlagParam_None, Command__does_check);
|
||||
|
||||
|
||||
add_flag(&build_flags, BuildFlag_Compact, str_lit("compact"), BuildFlagParam_None, Command_query);
|
||||
add_flag(&build_flags, BuildFlag_GlobalDefinitions, str_lit("global-definitions"), BuildFlagParam_None, Command_query);
|
||||
add_flag(&build_flags, BuildFlag_GoToDefinitions, str_lit("go-to-definitions"), BuildFlagParam_None, Command_query);
|
||||
|
||||
|
||||
add_flag(&build_flags, BuildFlag_Short, str_lit("short"), BuildFlagParam_None, Command_doc);
|
||||
add_flag(&build_flags, BuildFlag_AllPackages, str_lit("all-packages"), BuildFlagParam_None, Command_doc);
|
||||
add_flag(&build_flags, BuildFlag_DocFormat, str_lit("doc-format"), BuildFlagParam_None, Command_doc);
|
||||
@@ -1343,6 +1359,37 @@ bool parse_build_flags(Array<String> args) {
|
||||
string_to_lower(&build_context.microarch);
|
||||
break;
|
||||
}
|
||||
case BuildFlag_TargetFeatures: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
build_context.target_features = value.value_string;
|
||||
string_to_lower(&build_context.target_features);
|
||||
break;
|
||||
}
|
||||
case BuildFlag_RelocMode: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
String v = value.value_string;
|
||||
if (v == "default") {
|
||||
build_context.reloc_mode = RelocMode_Default;
|
||||
} else if (v == "static") {
|
||||
build_context.reloc_mode = RelocMode_Static;
|
||||
} else if (v == "pic") {
|
||||
build_context.reloc_mode = RelocMode_PIC;
|
||||
} else if (v == "dynamic-no-pic") {
|
||||
build_context.reloc_mode = RelocMode_DynamicNoPIC;
|
||||
} else {
|
||||
gb_printf_err("-reloc-mode flag expected one of the following\n");
|
||||
gb_printf_err("\tdefault\n");
|
||||
gb_printf_err("\tstatic\n");
|
||||
gb_printf_err("\tpic\n");
|
||||
gb_printf_err("\tdynamic-no-pic\n");
|
||||
bad_flags = true;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case BuildFlag_DisableRedZone:
|
||||
build_context.disable_red_zone = true;
|
||||
break;
|
||||
case BuildFlag_TestName: {
|
||||
GB_ASSERT(value.kind == ExactValue_String);
|
||||
{
|
||||
@@ -1361,9 +1408,15 @@ bool parse_build_flags(Array<String> args) {
|
||||
case BuildFlag_DisallowDo:
|
||||
build_context.disallow_do = true;
|
||||
break;
|
||||
case BuildFlag_DisallowRTTI:
|
||||
build_context.disallow_rtti = true;
|
||||
break;
|
||||
case BuildFlag_DefaultToNilAllocator:
|
||||
build_context.ODIN_DEFAULT_TO_NIL_ALLOCATOR = true;
|
||||
break;
|
||||
case BuildFlag_ForeignErrorProcedures:
|
||||
build_context.ODIN_FOREIGN_ERROR_PROCEDURES = true;
|
||||
break;
|
||||
case BuildFlag_InsertSemicolon: {
|
||||
gb_printf_err("-insert-semicolon flag is not required any more\n");
|
||||
bad_flags = true;
|
||||
@@ -2062,6 +2115,18 @@ void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(3, "-microarch:sandybridge");
|
||||
print_usage_line(3, "-microarch:native");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-reloc-mode:<string>");
|
||||
print_usage_line(2, "Specifies the reloc mode");
|
||||
print_usage_line(2, "Options:");
|
||||
print_usage_line(3, "default");
|
||||
print_usage_line(3, "static");
|
||||
print_usage_line(3, "pic");
|
||||
print_usage_line(3, "dynamic-no-pic");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-disable-red-zone");
|
||||
print_usage_line(2, "Disable red zone on a supported freestanding target");
|
||||
}
|
||||
|
||||
if (check) {
|
||||
@@ -2092,6 +2157,11 @@ void print_show_help(String const arg0, String const &command) {
|
||||
print_usage_line(1, "-verbose-errors");
|
||||
print_usage_line(2, "Prints verbose error messages showing the code on that line and the location in that line");
|
||||
print_usage_line(0, "");
|
||||
|
||||
print_usage_line(1, "-foreign-error-procedures");
|
||||
print_usage_line(2, "States that the error procedues used in the runtime are defined in a separate translation unit");
|
||||
print_usage_line(0, "");
|
||||
|
||||
}
|
||||
|
||||
if (run_or_build) {
|
||||
|
||||
@@ -1577,7 +1577,7 @@ void assign_removal_flag_to_semicolon(AstFile *f) {
|
||||
}
|
||||
}
|
||||
|
||||
void expect_semicolon(AstFile *f, Ast *s) {
|
||||
void expect_semicolon(AstFile *f) {
|
||||
Token prev_token = {};
|
||||
|
||||
if (allow_token(f, Token_Semicolon)) {
|
||||
@@ -1602,17 +1602,17 @@ void expect_semicolon(AstFile *f, Ast *s) {
|
||||
if (f->curr_token.kind == Token_EOF) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (s != nullptr) {
|
||||
return;
|
||||
}
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_EOF:
|
||||
return;
|
||||
}
|
||||
String p = token_to_string(f->curr_token);
|
||||
syntax_error(prev_token, "Expected ';', got %.*s", LIT(p));
|
||||
fix_advance_to_next_stmt(f);
|
||||
|
||||
if (f->curr_token.pos.line == f->prev_token.pos.line) {
|
||||
String p = token_to_string(f->curr_token);
|
||||
prev_token.pos = token_pos_end(prev_token);
|
||||
syntax_error(prev_token, "Expected ';', got %.*s", LIT(p));
|
||||
fix_advance_to_next_stmt(f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3181,7 +3181,7 @@ Ast *parse_foreign_block(AstFile *f, Token token) {
|
||||
Ast *body = ast_block_stmt(f, decls, open, close);
|
||||
|
||||
Ast *decl = ast_foreign_block_decl(f, token, foreign_library, body, docs);
|
||||
expect_semicolon(f, decl);
|
||||
expect_semicolon(f);
|
||||
return decl;
|
||||
}
|
||||
|
||||
@@ -3227,15 +3227,11 @@ Ast *parse_value_decl(AstFile *f, Array<Ast *> names, CommentGroup *docs) {
|
||||
}
|
||||
|
||||
if (f->expr_level >= 0) {
|
||||
Ast *end = nullptr;
|
||||
if (!is_mutable && values.count > 0) {
|
||||
end = values[values.count-1];
|
||||
}
|
||||
if (f->curr_token.kind == Token_CloseBrace &&
|
||||
f->curr_token.pos.line == f->prev_token.pos.line) {
|
||||
|
||||
} else {
|
||||
expect_semicolon(f, end);
|
||||
expect_semicolon(f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4143,11 +4139,7 @@ Ast *parse_return_stmt(AstFile *f) {
|
||||
advance_token(f);
|
||||
}
|
||||
|
||||
Ast *end = nullptr;
|
||||
if (results.count > 0) {
|
||||
end = results[results.count-1];
|
||||
}
|
||||
expect_semicolon(f, end);
|
||||
expect_semicolon(f);
|
||||
return ast_return_stmt(f, token, results);
|
||||
}
|
||||
|
||||
@@ -4398,7 +4390,7 @@ Ast *parse_import_decl(AstFile *f, ImportDeclKind kind) {
|
||||
syntax_error(import_name, "'using import' is not allowed, please use the import name explicitly");
|
||||
}
|
||||
|
||||
expect_semicolon(f, s);
|
||||
expect_semicolon(f);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -4456,7 +4448,7 @@ Ast *parse_foreign_decl(AstFile *f) {
|
||||
} else {
|
||||
s = ast_foreign_import_decl(f, token, filepaths, lib_name, docs, f->line_comment);
|
||||
}
|
||||
expect_semicolon(f, s);
|
||||
expect_semicolon(f);
|
||||
return s;
|
||||
}
|
||||
}
|
||||
@@ -4595,7 +4587,7 @@ Ast *parse_stmt(AstFile *f) {
|
||||
case Token_Not:
|
||||
case Token_And:
|
||||
s = parse_simple_stmt(f, StmtAllowFlag_Label);
|
||||
expect_semicolon(f, s);
|
||||
expect_semicolon(f);
|
||||
return s;
|
||||
|
||||
|
||||
@@ -4623,7 +4615,7 @@ Ast *parse_stmt(AstFile *f) {
|
||||
label = parse_ident(f);
|
||||
}
|
||||
s = ast_branch_stmt(f, token, label);
|
||||
expect_semicolon(f, s);
|
||||
expect_semicolon(f);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -4638,12 +4630,12 @@ Ast *parse_stmt(AstFile *f) {
|
||||
Array<Ast *> list = parse_lhs_expr_list(f);
|
||||
if (list.count == 0) {
|
||||
syntax_error(token, "Illegal use of 'using' statement");
|
||||
expect_semicolon(f, nullptr);
|
||||
expect_semicolon(f);
|
||||
return ast_bad_stmt(f, token, f->curr_token);
|
||||
}
|
||||
|
||||
if (f->curr_token.kind != Token_Colon) {
|
||||
expect_semicolon(f, list[list.count-1]);
|
||||
expect_semicolon(f);
|
||||
return ast_using_stmt(f, token, list);
|
||||
}
|
||||
expect_token_after(f, Token_Colon, "identifier list");
|
||||
@@ -4700,13 +4692,13 @@ Ast *parse_stmt(AstFile *f) {
|
||||
} else if (tag == "assert" || tag == "panic") {
|
||||
Ast *t = ast_basic_directive(f, hash_token, name);
|
||||
Ast *stmt = ast_expr_stmt(f, parse_call_expr(f, t));
|
||||
expect_semicolon(f, stmt);
|
||||
expect_semicolon(f);
|
||||
return stmt;
|
||||
} else if (name.string == "force_inline" ||
|
||||
name.string == "force_no_inline") {
|
||||
Ast *expr = parse_force_inlining_operand(f, name);
|
||||
Ast *stmt = ast_expr_stmt(f, expr);
|
||||
expect_semicolon(f, stmt);
|
||||
expect_semicolon(f);
|
||||
return stmt;
|
||||
} else if (tag == "unroll") {
|
||||
return parse_unrolled_for_loop(f, name);
|
||||
@@ -4728,7 +4720,7 @@ Ast *parse_stmt(AstFile *f) {
|
||||
|
||||
case Token_Semicolon:
|
||||
s = ast_empty_stmt(f, token);
|
||||
expect_semicolon(f, nullptr);
|
||||
expect_semicolon(f);
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -5586,7 +5578,7 @@ bool parse_file(Parser *p, AstFile *f) {
|
||||
}
|
||||
|
||||
Ast *pd = ast_package_decl(f, f->package_token, package_name, docs, f->line_comment);
|
||||
expect_semicolon(f, pd);
|
||||
expect_semicolon(f);
|
||||
f->pkg_decl = pd;
|
||||
|
||||
if (f->error_count == 0) {
|
||||
|
||||
@@ -10,10 +10,6 @@ struct String {
|
||||
u8 * text;
|
||||
isize len;
|
||||
|
||||
// u8 &operator[](isize i) {
|
||||
// GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
|
||||
// return text[i];
|
||||
// }
|
||||
u8 const &operator[](isize i) const {
|
||||
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
|
||||
return text[i];
|
||||
@@ -33,10 +29,6 @@ struct String {
|
||||
struct String16 {
|
||||
wchar_t *text;
|
||||
isize len;
|
||||
wchar_t &operator[](isize i) {
|
||||
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
|
||||
return text[i];
|
||||
}
|
||||
wchar_t const &operator[](isize i) const {
|
||||
GB_ASSERT_MSG(0 <= i && i < len, "[%td]", i);
|
||||
return text[i];
|
||||
|
||||
40
tests/common/common.odin
Normal file
40
tests/common/common.odin
Normal file
@@ -0,0 +1,40 @@
|
||||
// Boilerplate for tests
|
||||
package common
|
||||
|
||||
import "core:testing"
|
||||
import "core:fmt"
|
||||
import "core:os"
|
||||
|
||||
TEST_count := 0
|
||||
TEST_fail := 0
|
||||
|
||||
when ODIN_TEST {
|
||||
expect :: testing.expect
|
||||
log :: testing.log
|
||||
} else {
|
||||
expect :: proc(t: ^testing.T, condition: bool, message: string, loc := #caller_location) {
|
||||
TEST_count += 1
|
||||
if !condition {
|
||||
TEST_fail += 1
|
||||
fmt.printf("[%v] FAIL %v\n", loc, message)
|
||||
return
|
||||
}
|
||||
}
|
||||
log :: proc(t: ^testing.T, v: any, loc := #caller_location) {
|
||||
fmt.printf("[%v] ", loc)
|
||||
fmt.printf("log: %v\n", v)
|
||||
}
|
||||
}
|
||||
|
||||
report :: proc(t: ^testing.T) {
|
||||
if TEST_fail > 0 {
|
||||
if TEST_fail > 1 {
|
||||
fmt.printf("%v/%v tests successful, %v tests failed.\n", TEST_count - TEST_fail, TEST_count, TEST_fail)
|
||||
} else {
|
||||
fmt.printf("%v/%v tests successful, 1 test failed.\n", TEST_count - TEST_fail, TEST_count)
|
||||
}
|
||||
os.exit(1)
|
||||
} else {
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count, TEST_count)
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,12 @@
|
||||
ODIN=../../odin
|
||||
PYTHON=$(shell which python3)
|
||||
|
||||
<<<<<<< HEAD
|
||||
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test os2_test
|
||||
=======
|
||||
all: download_test_assets image_test compress_test strings_test hash_test crypto_test noise_test encoding_test \
|
||||
math_test linalg_glsl_math_test
|
||||
>>>>>>> upstream/master
|
||||
|
||||
download_test_assets:
|
||||
$(PYTHON) download_assets.py
|
||||
@@ -30,3 +35,12 @@ os2_test:
|
||||
encoding_test:
|
||||
$(ODIN) run encoding/json -out=test_json
|
||||
$(ODIN) run encoding/varint -out=test_varint
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
|
||||
math_test:
|
||||
$(ODIN) run math/test_core_math.odin -out=test_core_math -collection:tests=..
|
||||
|
||||
linalg_glsl_math_test:
|
||||
$(ODIN) run math/linalg/glsl/test_linalg_glsl_math.odin -out=test_linalg_glsl_math -collection:tests=..
|
||||
>>>>>>> upstream/master
|
||||
|
||||
85
tests/core/math/linalg/glsl/test_linalg_glsl_math.odin
Normal file
85
tests/core/math/linalg/glsl/test_linalg_glsl_math.odin
Normal file
@@ -0,0 +1,85 @@
|
||||
// Tests "linalg_glsl_math.odin" in "core:math/linalg/glsl".
|
||||
// Must be run with `-collection:tests=` flag, e.g.
|
||||
// ./odin run tests/core/math/linalg/glsl/test_linalg_glsl_math.odin -collection:tests=./tests
|
||||
package test_core_math_linalg_glsl_math
|
||||
|
||||
import glsl "core:math/linalg/glsl"
|
||||
|
||||
import "core:fmt"
|
||||
import "core:math"
|
||||
import "core:testing"
|
||||
import tc "tests:common"
|
||||
|
||||
main :: proc() {
|
||||
|
||||
t := testing.T{}
|
||||
|
||||
test_fract_f32(&t)
|
||||
test_fract_f64(&t)
|
||||
|
||||
tc.report(&t)
|
||||
}
|
||||
|
||||
@test
|
||||
test_fract_f32 :: proc(t: ^testing.T) {
|
||||
|
||||
using math
|
||||
|
||||
r: f32
|
||||
|
||||
Datum :: struct {
|
||||
i: int,
|
||||
v: f32,
|
||||
e: f32,
|
||||
}
|
||||
@static data := []Datum{
|
||||
{ 0, 10.5, 0.5 }, // Issue #1574 fract in linalg/glm is broken
|
||||
{ 1, -10.5, -0.5 },
|
||||
{ 2, F32_MIN, F32_MIN }, // 0x1p-126
|
||||
{ 3, -F32_MIN, -F32_MIN },
|
||||
{ 4, 0.0, 0.0 },
|
||||
{ 5, -0.0, -0.0 },
|
||||
{ 6, 1, 0.0 },
|
||||
{ 7, -1, -0.0 },
|
||||
{ 8, 0h3F80_0001, 0h3400_0000 }, // 0x1.000002p+0, 0x1p-23
|
||||
{ 9, -0h3F80_0001, -0h3400_0000 },
|
||||
}
|
||||
|
||||
for d, i in data {
|
||||
assert(i == d.i)
|
||||
r = glsl.fract(d.v)
|
||||
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%v (%h)) -> %v (%h) != %v", i, #procedure, d.v, d.v, r, r, d.e))
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
test_fract_f64 :: proc(t: ^testing.T) {
|
||||
|
||||
using math
|
||||
|
||||
r: f64
|
||||
|
||||
Datum :: struct {
|
||||
i: int,
|
||||
v: f64,
|
||||
e: f64,
|
||||
}
|
||||
@static data := []Datum{
|
||||
{ 0, 10.5, 0.5 }, // Issue #1574 fract in linalg/glm is broken
|
||||
{ 1, -10.5, -0.5 },
|
||||
{ 2, F64_MIN, F64_MIN }, // 0x1p-1022
|
||||
{ 3, -F64_MIN, -F64_MIN },
|
||||
{ 4, 0.0, 0.0 },
|
||||
{ 5, -0.0, -0.0 },
|
||||
{ 6, 1, 0.0 },
|
||||
{ 7, -1, -0.0 },
|
||||
{ 8, 0h3FF0_0000_0000_0001, 0h3CB0_0000_0000_0000 }, // 0x1.0000000000001p+0, 0x1p-52
|
||||
{ 9, -0h3FF0_0000_0000_0001, -0h3CB0_0000_0000_0000 },
|
||||
}
|
||||
|
||||
for d, i in data {
|
||||
assert(i == d.i)
|
||||
r = glsl.fract(d.v)
|
||||
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%v (%h)) -> %v (%h) != %v", i, #procedure, d.v, d.v, r, r, d.e))
|
||||
}
|
||||
}
|
||||
310
tests/core/math/test_core_math.odin
Normal file
310
tests/core/math/test_core_math.odin
Normal file
@@ -0,0 +1,310 @@
|
||||
// Tests "math.odin" in "core:math".
|
||||
// Must be run with `-collection:tests=` flag, e.g.
|
||||
// ./odin run tests/core/math/test_core_math.odin -collection:tests=./tests
|
||||
package test_core_math
|
||||
|
||||
import "core:fmt"
|
||||
import "core:math"
|
||||
import "core:testing"
|
||||
import tc "tests:common"
|
||||
|
||||
main :: proc() {
|
||||
t := testing.T{}
|
||||
|
||||
test_classify_f16(&t)
|
||||
test_classify_f32(&t)
|
||||
test_classify_f64(&t)
|
||||
|
||||
test_trunc_f16(&t)
|
||||
test_trunc_f32(&t)
|
||||
test_trunc_f64(&t)
|
||||
|
||||
tc.report(&t)
|
||||
}
|
||||
|
||||
@test
|
||||
test_classify_f16 :: proc(t: ^testing.T) {
|
||||
|
||||
using math
|
||||
using Float_Class
|
||||
|
||||
r: Float_Class
|
||||
|
||||
Datum :: struct {
|
||||
i: int,
|
||||
v: f16,
|
||||
e: math.Float_Class,
|
||||
}
|
||||
@static data := []Datum{
|
||||
{ 0, 1.2, Normal },
|
||||
{ 1, 0h0001, Subnormal },
|
||||
{ 2, 0.0, Zero },
|
||||
{ 3, -0.0, Neg_Zero },
|
||||
{ 4, SNAN_F16, NaN },
|
||||
{ 5, QNAN_F16, NaN },
|
||||
{ 6, INF_F16, Inf },
|
||||
{ 7, NEG_INF_F16, Neg_Inf },
|
||||
}
|
||||
|
||||
for d, i in data {
|
||||
assert(i == d.i)
|
||||
r = classify_f16(d.v)
|
||||
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e))
|
||||
}
|
||||
|
||||
/* Check all subnormals (exponent 0, 10-bit significand non-zero) */
|
||||
for i :u16 = 1; i < 0x400; i += 1 {
|
||||
v :f16 = transmute(f16)i
|
||||
r = classify_f16(v)
|
||||
e :Float_Class: Subnormal
|
||||
tc.expect(t, r == e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, v, r, e))
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
test_classify_f32 :: proc(t: ^testing.T) {
|
||||
|
||||
using math
|
||||
using Float_Class
|
||||
|
||||
r: Float_Class
|
||||
|
||||
Datum :: struct {
|
||||
i: int,
|
||||
v: f32,
|
||||
e: math.Float_Class,
|
||||
}
|
||||
@static data := []Datum{
|
||||
{ 0, 1.2, Normal },
|
||||
{ 1, 0h0000_0001, Subnormal },
|
||||
{ 2, 0.0, Zero },
|
||||
{ 3, -0.0, Neg_Zero },
|
||||
{ 4, SNAN_F32, NaN },
|
||||
{ 5, QNAN_F32, NaN },
|
||||
{ 6, INF_F32, Inf },
|
||||
{ 7, NEG_INF_F32, Neg_Inf },
|
||||
}
|
||||
|
||||
for d, i in data {
|
||||
assert(i == d.i)
|
||||
r = classify_f32(d.v)
|
||||
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e))
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
test_classify_f64 :: proc(t: ^testing.T) {
|
||||
|
||||
using math
|
||||
using Float_Class
|
||||
|
||||
r: Float_Class
|
||||
|
||||
Datum :: struct {
|
||||
i: int,
|
||||
v: f64,
|
||||
e: math.Float_Class,
|
||||
}
|
||||
@static data := []Datum{
|
||||
{ 0, 1.2, Normal },
|
||||
{ 1, 0h0000_0000_0000_0001, Subnormal },
|
||||
{ 2, 0.0, Zero },
|
||||
{ 3, -0.0, Neg_Zero },
|
||||
{ 4, SNAN_F64, NaN },
|
||||
{ 5, QNAN_F64, NaN },
|
||||
{ 6, INF_F64, Inf },
|
||||
{ 7, NEG_INF_F64, Neg_Inf },
|
||||
}
|
||||
|
||||
for d, i in data {
|
||||
assert(i == d.i)
|
||||
r = classify_f64(d.v)
|
||||
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %v != %v", i, #procedure, d.v, r, d.e))
|
||||
}
|
||||
}
|
||||
|
||||
@test
|
||||
test_trunc_f16 :: proc(t: ^testing.T) {
|
||||
|
||||
using math
|
||||
|
||||
r, v: f16
|
||||
|
||||
Datum :: struct {
|
||||
i: int,
|
||||
v: f16,
|
||||
e: f16,
|
||||
}
|
||||
@static data := []Datum{
|
||||
{ 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken
|
||||
{ 1, -10.5, -10 },
|
||||
|
||||
{ 2, F16_MAX, F16_MAX },
|
||||
{ 3, -F16_MAX, -F16_MAX },
|
||||
{ 4, F16_MIN, 0.0 },
|
||||
{ 5, -F16_MIN, -0.0 },
|
||||
{ 6, 0.0, 0.0 },
|
||||
{ 7, -0.0, -0.0 },
|
||||
{ 8, 1, 1 },
|
||||
{ 9, -1, -1 },
|
||||
{ 10, INF_F16, INF_F16 },
|
||||
{ 11, NEG_INF_F16, NEG_INF_F16 },
|
||||
|
||||
/* From https://en.wikipedia.org/wiki/Half-precision_floating-point_format */
|
||||
{ 12, 0h3C01, 1 }, // 0x1.004p+0 (smallest > 1)
|
||||
{ 13, -0h3C01, -1 },
|
||||
{ 14, 0h3BFF, 0.0 }, // 0x1.ffcp-1 (largest < 1)
|
||||
{ 15, -0h3BFF, -0.0 },
|
||||
{ 16, 0h0001, 0.0 }, // 0x0.004p-14 (smallest subnormal)
|
||||
{ 17, -0h0001, -0.0 },
|
||||
{ 18, 0h03FF, 0.0 }, // 0x0.ffcp-14 (largest subnormal)
|
||||
{ 19, -0h03FF, -0.0 },
|
||||
|
||||
{ 20, 0hC809, -8 }, // -0x1.024p+3
|
||||
{ 21, 0h4458, 4 }, // 0x1.16p+2
|
||||
}
|
||||
|
||||
for d, i in data {
|
||||
assert(i == d.i)
|
||||
r = trunc_f16(d.v)
|
||||
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e))
|
||||
}
|
||||
|
||||
v = SNAN_F16
|
||||
r = trunc_f16(v)
|
||||
tc.expect(t, is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
|
||||
|
||||
v = QNAN_F16
|
||||
r = trunc_f16(v)
|
||||
tc.expect(t, is_nan_f16(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
|
||||
}
|
||||
|
||||
@test
|
||||
test_trunc_f32 :: proc(t: ^testing.T) {
|
||||
|
||||
using math
|
||||
|
||||
r, v: f32
|
||||
|
||||
Datum :: struct {
|
||||
i: int,
|
||||
v: f32,
|
||||
e: f32,
|
||||
}
|
||||
@static data := []Datum{
|
||||
{ 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken
|
||||
{ 1, -10.5, -10 },
|
||||
|
||||
{ 2, F32_MAX, F32_MAX },
|
||||
{ 3, -F32_MAX, -F32_MAX },
|
||||
{ 4, F32_MIN, 0.0 },
|
||||
{ 5, -F32_MIN, -0.0 },
|
||||
{ 6, 0.0, 0.0 },
|
||||
{ 7, -0.0, -0.0 },
|
||||
{ 8, 1, 1 },
|
||||
{ 9, -1, -1 },
|
||||
{ 10, INF_F32, INF_F32 },
|
||||
{ 11, NEG_INF_F32, NEG_INF_F32 },
|
||||
|
||||
/* From https://en.wikipedia.org/wiki/Single-precision_floating-point_format */
|
||||
{ 12, 0h3F80_0001, 1 }, // 0x1.000002p+0 (smallest > 1)
|
||||
{ 13, -0h3F80_0001, -1 },
|
||||
{ 14, 0h3F7F_FFFF, 0.0 }, // 0x1.fffffep-1 (largest < 1)
|
||||
{ 15, -0h3F7F_FFFF, -0.0 },
|
||||
{ 16, 0h0000_0001, 0.0 }, // 0x0.000002p-126 (smallest subnormal)
|
||||
{ 17, -0h0000_0001, -0.0 },
|
||||
{ 18, 0h007F_FFFF, 0.0 }, // 0x0.fffffep-126 (largest subnormal)
|
||||
{ 19, -0h007F_FFFF, -0.0 },
|
||||
|
||||
/* From libc-test src/math/sanity/truncf.h */
|
||||
{ 20, 0hC101_11D0, -8 }, // -0x1.0223ap+3
|
||||
{ 21, 0h408B_0C34, 4 }, // 0x1.161868p+2
|
||||
{ 22, 0hC106_1A5A, -8 }, // -0x1.0c34b4p+3
|
||||
{ 23, 0hC0D1_0378, -6 }, // -0x1.a206fp+2
|
||||
{ 24, 0h4114_45DE, 9 }, // 0x1.288bbcp+3
|
||||
{ 25, 0h3F29_77E8, 0.0 }, // 0x1.52efdp-1
|
||||
{ 26, 0hBED0_2E64, -0.0 }, // -0x1.a05cc8p-2
|
||||
{ 27, 0h3F0F_CF7D, 0.0 }, // 0x1.1f9efap-1
|
||||
{ 28, 0h3F46_2ED8, 0.0 }, // 0x1.8c5dbp-1
|
||||
{ 29, 0hBF2D_C375, -0.0 }, // -0x1.5b86eap-1
|
||||
}
|
||||
|
||||
for d, i in data {
|
||||
assert(i == d.i)
|
||||
r = trunc_f32(d.v)
|
||||
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e))
|
||||
}
|
||||
|
||||
v = SNAN_F32
|
||||
r = trunc_f32(v)
|
||||
tc.expect(t, is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
|
||||
|
||||
v = QNAN_F32
|
||||
r = trunc_f32(v)
|
||||
tc.expect(t, is_nan_f32(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
|
||||
}
|
||||
|
||||
@test
|
||||
test_trunc_f64 :: proc(t: ^testing.T) {
|
||||
|
||||
using math
|
||||
|
||||
r, v: f64
|
||||
|
||||
Datum :: struct {
|
||||
i: int,
|
||||
v: f64,
|
||||
e: f64,
|
||||
}
|
||||
data := []Datum{
|
||||
{ 0, 10.5, 10 }, // Issue #1574 fract in linalg/glm is broken
|
||||
{ 1, -10.5, -10 },
|
||||
|
||||
{ 2, F64_MAX, F64_MAX },
|
||||
{ 3, -F64_MAX, -F64_MAX },
|
||||
{ 4, F64_MIN, 0.0 },
|
||||
{ 5, -F64_MIN, -0.0 },
|
||||
{ 6, 0.0, 0.0 },
|
||||
{ 7, -0.0, -0.0 },
|
||||
{ 8, 1, 1 },
|
||||
{ 9, -1, -1 },
|
||||
{ 10, INF_F64, INF_F64 },
|
||||
{ 11, NEG_INF_F64, NEG_INF_F64 },
|
||||
|
||||
/* From https://en.wikipedia.org/wiki/Double-precision_floating-point_format */
|
||||
{ 12, 0h3FF0_0000_0000_0001, 1 }, // 0x1.0000000000001p+0 (smallest > 1)
|
||||
{ 13, -0h3FF0_0000_0000_0001, -1 },
|
||||
{ 14, 0h3FEF_FFFF_FFFF_FFFF, 0.0 }, // 0x1.fffffffffffffp-1 (largest < 1)
|
||||
{ 15, -0h3FEF_FFFF_FFFF_FFFF, -0.0 },
|
||||
{ 16, 0h0000_0000_0000_0001, 0.0 }, // 0x0.0000000000001p-1022 (smallest subnormal)
|
||||
{ 17, -0h0000_0000_0000_0001, -0.0 },
|
||||
{ 18, 0h000F_FFFF_FFFF_FFFF, 0.0 }, // 0x0.fffffffffffffp-1022 (largest subnormal)
|
||||
{ 19, -0h000F_FFFF_FFFF_FFFF, -0.0 },
|
||||
|
||||
/* From libc-test src/math/sanity/trunc.h */
|
||||
{ 20, 0hC020_2239_F3C6_A8F1, -8 }, // -0x1.02239f3c6a8f1p+3
|
||||
{ 21, 0h4011_6186_8E18_BC67, 4 }, // 0x1.161868e18bc67p+2
|
||||
{ 22, 0hC020_C34B_3E01_E6E7, -8 }, // -0x1.0c34b3e01e6e7p+3
|
||||
{ 23, 0hC01A_206F_0A19_DCC4, -6 }, // -0x1.a206f0a19dcc4p+2
|
||||
{ 24, 0h4022_88BB_B0D6_A1E6, 9 }, // 0x1.288bbb0d6a1e6p+3
|
||||
{ 25, 0h3FE5_2EFD_0CD8_0497, 0.0 }, // 0x1.52efd0cd80497p-1
|
||||
{ 26, 0hBFDA_05CC_7544_81D1, -0.0 }, // -0x1.a05cc754481d1p-2
|
||||
{ 27, 0h3FE1_F9EF_9347_45CB, 0.0 }, // 0x1.1f9ef934745cbp-1
|
||||
{ 28, 0h3FE8_C5DB_097F_7442, 0.0 }, // 0x1.8c5db097f7442p-1
|
||||
{ 29, 0hBFE5_B86E_A811_8A0E, -0.0 }, // -0x1.5b86ea8118a0ep-1
|
||||
}
|
||||
|
||||
for d, i in data {
|
||||
assert(i == d.i)
|
||||
r = trunc_f64(d.v)
|
||||
tc.expect(t, r == d.e, fmt.tprintf("i:%d %s(%h) -> %h != %h", i, #procedure, d.v, r, d.e))
|
||||
}
|
||||
|
||||
v = SNAN_F64
|
||||
r = trunc_f64(v)
|
||||
tc.expect(t, is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
|
||||
|
||||
v = QNAN_F64
|
||||
r = trunc_f64(v)
|
||||
tc.expect(t, is_nan_f64(r), fmt.tprintf("%s(%f) -> %f != NaN", #procedure, v, r))
|
||||
}
|
||||
3
vendor/directx/d3d12/d3d12_constants.odin
vendored
3
vendor/directx/d3d12/d3d12_constants.odin
vendored
@@ -292,7 +292,8 @@ MAX_DEPTH :: 1.0
|
||||
MAX_LIVE_STATIC_SAMPLERS :: 2032
|
||||
MAX_MAXANISOTROPY :: 16
|
||||
MAX_MULTISAMPLE_SAMPLE_COUNT :: 32
|
||||
MAX_POSITION_VALUE :: 3.402823466e+34D3D12_MAX_ROOT_COST :: 64
|
||||
MAX_POSITION_VALUE :: 3.402823466e+34
|
||||
MAX_ROOT_COST :: 64
|
||||
MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_1 :: 1000000
|
||||
MAX_SHADER_VISIBLE_DESCRIPTOR_HEAP_SIZE_TIER_2 :: 1000000
|
||||
MAX_SHADER_VISIBLE_SAMPLER_HEAP_SIZE :: 2048
|
||||
|
||||
Reference in New Issue
Block a user