Compare commits

..

No commits in common. "main" and "large-assets" have entirely different histories.

129 changed files with 1002130 additions and 40311 deletions

@ -1,30 +0,0 @@
name: CI
on:
pull_request:
push:
tags:
- "**"
branches:
- main
- zig
schedule:
- cron: "0 0 * * *"
env:
BB_CI: 1
jobs:
ci:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
BIRTH_ZIG_BUILD_TYPE: [ Debug, ReleaseSafe, ReleaseFast, ReleaseSmall ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Build and test (Packaged LLVM)
run: |
~/zig-linux-x86_64-0.14.0/zig build test -Doptimize=${{matrix.BIRTH_ZIG_BUILD_TYPE}} -Dsystem_llvm=false
ldd zig-out/bin/bloat-buster

76
.github/workflows/ci.yml vendored Normal file

@ -0,0 +1,76 @@
name: CI
on:
pull_request:
push:
tags:
- "**"
branches:
- main
schedule:
- cron: "0 0 * * *"
env:
BB_CI: 1
jobs:
generate-config:
runs-on: ubuntu-24.04
permissions: write-all
outputs:
BIRTH_GITHUB_TARGETS: ${{ steps.generate-config.outputs.BIRTH_GITHUB_TARGETS }}
BIRTH_BUILD_TYPES: ${{ steps.generate-config.outputs.BIRTH_BUILD_TYPES }}
BIRTH_CMAKE_BUILD_TYPES: ${{ steps.generate-config.outputs.BIRTH_CMAKE_BUILD_TYPES }}
BIRTH_COMPILERS: ${{ steps.generate-config.outputs.BIRTH_COMPILERS }}
BIRTH_LINUX_IMAGE: ${{ steps.generate-config.outputs.BIRTH_LINUX_IMAGE }}
BIRTH_MACOS_IMAGE: ${{ steps.generate-config.outputs.BIRTH_MACOS_IMAGE }}
BIRTH_WINDOWS_IMAGE: ${{ steps.generate-config.outputs.BIRTH_WINDOWS_IMAGE }}
RELEASE_TAG_NAME: ${{ steps.generate-tag.outputs.RELEASE_TAG_NAME }} # Define job output here
steps:
- name: Check out repository
uses: actions/checkout@v4
- name: Generate config
id: generate-config
uses: birth-software/github-config@v4
- name: Create tag
if: github.ref == 'refs/heads/main'
shell: bash
id: generate-tag
env:
GH_TOKEN: ${{ github.token }}
run: |
set -eux
git config --global user.name "github-actions"
git config --global user.email "github-actions@github.com"
TAG="dev"
gh release delete $TAG --yes || true
git tag -d $TAG || true
git push origin --delete $TAG || true
git fetch --tags
git tag -l
git tag $TAG
git push origin $TAG
echo "RELEASE_TAG_NAME=$TAG" >> $GITHUB_OUTPUT
ci:
needs: generate-config
permissions: write-all
strategy:
fail-fast: true
matrix:
os: [ x86_64-linux-znver4 ]
BIRTH_BUILD_TYPE: ${{ fromJSON(needs.generate-config.outputs.BIRTH_BUILD_TYPES) }}
runs-on: ${{ matrix.os }}
env:
BIRTH_LINUX_IMAGE: ${{ needs.generate-config.outputs.BIRTH_LINUX_IMAGE }}
BIRTH_MACOS_IMAGE: ${{ needs.generate-config.outputs.BIRTH_MACOS_IMAGE }}
BIRTH_WINDOWS_IMAGE: ${{ needs.generate-config.outputs.BIRTH_WINDOWS_IMAGE }}
RELEASE_TAG_NAME: ${{ needs.generate-config.outputs.RELEASE_TAG_NAME }}
steps:
- uses: actions/checkout@v4
- name: Build
env:
CC: clang
BB_BUILD_TYPE: ${{matrix.BIRTH_BUILD_TYPE}}
run: ./build.sh
- name: Run
run: ./cache/bb

5
.gitignore vendored

@ -8,8 +8,3 @@ project
imgui.ini
/cache/
.DS_Store
/*.perf
/.gdb_history
/.zig-cache/
/zig-out/
/bb-cache/

File diff suppressed because it is too large Load Diff

@ -1,281 +0,0 @@
adc: class base_arithmetic(/2, 15, 11, 13)
adcx: class unsigned_add_flag(66)
add: class base_arithmetic(/0, 05, 01, 03)
adox: class unsigned_add_flag(f3)
and: class base_arithmetic(/4, 25, 21, 23)
bsf:
r16, rm16 [rm: rex.r 0f bc /r]
r32, rm32 [rm: 0f bc /r]
r64, rm64 [rm: rex.w 0f bc /r]
bsr:
r16, rm16 [rm: rex.r 0f bd /r]
r32, rm32 [rm: 0f bd /r]
r64, rm64 [rm: rex.w 0f bd /r]
bswap:
r32 [o: 0f c8+r]
r64 [o: rex.w 0f c8+r]
bt: class bittest(/4, a3)
btc: class bittest(/7, bb)
btr: class bittest(/6, b3)
bts: class bittest(/5, ab)
call:
rel [d: e8 rel32]
rm64 [m: ff /2]
cbw: [zo: rex.r 98]
cwde: [zo: 98]
cwqe: [zo: rex.w 98]
clc: [zo: f8]
cld: [zo: fd]
clflush: m8 [m: 0f ae /7]
clflushopt: m8 [m: 66 0f ae /7]
cli: [zo: fa]
clts: [zo: 0f 06]
cmc: [zo: f5]
cmovcc: class cmov
cmp: class base_arithmetic(/7, 3d, 39, 3b)
cmpsb: [zo: a6]
cmpsw: [zo: a7]
cmpsd: [zo: a7]
cmpsq: [zo: a7]
cmpxchg:
rm8, r8 [mr: 0f b0]
rm16, r16 [mr: 0f b1]
rm32, r32 [mr: 0f b1]
rm64, r64 [mr: 0f b1]
cmpxchg8b: m64 [m: 0f c7 /1]
cmpxchg16b: m64 [m: rex.w 0f c7 /1]
cpuid: [zo: 0f a2]
crc32:
r32, rm8 [rm: f2 0f 38 f0]
r32, rm16 [rm: 66 f2 0f 38 f1]
r32, rm32 [rm: f2 0f 38 f1]
r64, rm8 [rm: f2 rex.w 0f 38 f0]
r64, rm64 [rm: f2 rex.w 0f 38 f1]
dec:
rm8 [m: fe /1]
rm16 [m: fe /1]
rm32 [m: fe /1]
rm64 [m: fe /1]
div:
rm8 [m: f6 /6]
rm16 [m: f7 /6]
rm32 [m: f7 /6]
rm64 [m: f7 /6]
hlt: [zo: f4]
idiv:
rm8 [m: f6 /7]
rm16 [m: f7 /7]
rm32 [m: f7 /7]
rm64 [m: f7 /7]
imul:
rm8 [m: f6 /5]
rm16 [m: f7 /5]
rm32 [m: f7 /5]
rm64 [m: f7 /5]
r16, rm16 [rm: 0f af]
r32, rm32 [rm: 0f af]
r64, rm64 [rm: 0f af]
r16, rm16, imm [rmi: 6b ib]
r32, rm32, imm [rmi: 6b ib]
r64, rm64, imm [rmi: 6b ib]
r16, rm16, imm16 [rmi: 69 iw]
r32, rm32, imm32 [rmi: 69 id]
r64, rm64, imm32 [rmi: 69 id]
in:
al, imm8 [-i: e4 ib]
ax, imm8 [-i: e5 ib]
eax, imm8 [-i: e5 ib]
al, dx [--: ec]
ax, dx [--: ed]
eax, dx [--: ed]
inc:
rm8 [m: fe /0]
rm16 [m: fe /0]
rm32 [m: fe /0]
rm64 [m: fe /0]
insb: [zo: 6c]
insw: [zo: 6d]
insd: [zo: 6d]
int: imm [i: cd ib]
int3: [zo: cc]
invd: [zo: 0f 08]
invlpg: m8 [m: 0f 01 /7]
iret: [zo: 66 cf]
iretd: [zo: cf]
iretq: [zo: rex.w cf]
jmp:
rel [d: eb rel8]
rel [d: e9 rel32]
rm64 [m: ff /4]
jcc: class jcc
jrcxz: rel [d: e3 rel8]
lahf: [zo: 9f]
lea:
r16, m16 [rm: 8d /r]
r32, m32 [rm: 8d /r]
r64, m64 [rm: 8d /r]
lodsb: [zo: ac]
lodsw: [zo: ad]
lodsd: [zo: ad]
lodsq: [zo: ad]
loop: rel [d: e2 rel8]
loope: rel [d: e1 rel8]
loopne: rel [d: e0 rel8]
monitor: [zo: 0f 01 c8]
mov:
rm8, r8 [mr: 88 /r]
rm16, r16 [mr: 89 /r]
rm32, r32 [mr: 89 /r]
rm64, r64 [mr: 89 /r]
r8, rm8 [rm: 8a /r]
r16, rm16 [rm: 8b /r]
r32, rm32 [rm: 8b /r]
r64, rm64 [rm: 8b /r]
r8, imm [ri: b0+r ib]
r16, imm [ri: b8+r iw]
r32, imm [ri: b8+r id]
r64, imm [ri: b8+r iq]
r8, imm [ri: c6 /0 ib]
r16, imm [ri: c7 /0 iw]
r32, imm [ri: c7 /0 id]
r64, imm [ri: c7 /0 id]
movsb: [zo: a4]
movsw: [zo: a5]
movsd: [zo: a5]
movsq: [zo: a5]
movsx:
r16, rm8 [rm: 0f be /r]
r32, rm8 [rm: 0f be /r]
r64, rm8 [rm: 0f be /r]
r32, rm16 [rm: 0f bf /r]
r64, rm16 [rm: 0f bf /r]
movsxd: r64, rm32 [rm: rex.w 63 /r]
movzx:
r16, rm8 [rm: 0f b6 /r]
r32, rm8 [rm: 0f b6 /r]
r64, rm8 [rm: 0f b6 /r]
r32, rm16 [rm: 0f b7 /r]
r64, rm16 [rm: 0f b7 /r]
mul:
rm8 [m: f6 /4]
rm16 [m: f7 /4]
rm32 [m: f7 /4]
rm64 [m: f7 /4]
mwait: [zo: 0f 01 c9]
neg:
rm8 [m: f6 /3]
rm16 [m: f7 /3]
rm32 [m: f7 /3]
rm64 [m: f7 /3]
nop:
[zo: 90]
rm16 [m: 0f 1f /0]
rm32 [m: 0f 1f /0]
not:
rm8 [m: f6 /2]
rm16 [m: f7 /2]
rm32 [m: f7 /2]
rm64 [m: f7 /2]
or: class base_arithmetic(/1, 0d, 09, 0b)
out:
imm, al [i-: e6 ib]
imm, ax [i-: e7 ib]
imm, ax [i-: e7 ib]
pause: [zo: f3 90]
pop:
rm16 [m: 8f /0]
rm64 [m: 8f /0]
r16 [o: 58+r]
r64 [o: 58+r]
popcnt:
r16, rm16 [rm: f3 0f b8 /r]
r32, rm32 [rm: f3 0f b8 /r]
r64, rm64 [rm: f3 0f b8 /r]
popf: [zo: 66 9d]
popfq: [zo: 9d]
prefetcht0: m8 [m: 0f 18 /1]
prefetcht1: m8 [m: 0f 18 /2]
prefetcht2: m8 [m: 0f 18 /3]
prefetchnta: m8 [m: 0f 18 /0]
push:
rm16 [m: ff /6]
rm64 [m: ff /6]
r16 [o: 50+r]
r64 [o: 50+r]
imm [i: 6a ib]
imm [i: 68 iw]
imm [i: 68 id]
pushf: [zo: 66 9c]
pushfq: [zo: 9c]
rol: class rotate(/0)
ror: class rotate(/1)
rcl: class rotate(/2)
rcr: class rotate(/3)
rdmsr: [zo: 0f 32]
rdpmc: [zo: 0f 33]
rdtsc: [zo: 0f 31]
rdtscp: [zo: 0f 01 f9]
ret:
[zo: c3]
imm [i: c2 iw]
retf:
[zo: cb]
imm [i: ca iw]
rsm: [zo: 0f aa]
sal: class shift(/4)
sar: class shift(/7)
shl: class shift(/4)
shr: class shift(/5)
scasb: [zo: ae]
scasw: [zo: af]
scasd: [zo: af]
scasq: [zo: af]
setcc: class setcc
stc: [zo: f9]
std: [zo: fd]
sti: [zo: fb]
stosb: [zo: aa]
stosw: [zo: ab]
stosd: [zo: ab]
stosq: [zo: ab]
sub: class base_arithmetic(/5, 2d, 29, 2b)
syscall: [zo: 0f 05]
sysenter: [zo: 0f 34]
sysexit: [zo: 0f 35]
sysret: [zo: 0f 07]
test:
al, imm8 [-i: a8 ib]
ax, imm16 [-i: a9 iw]
eax, imm32 [-i: a9 id]
rax, imm32 [-i: a9 id]
rm8, imm8 [mi: f6 /0 ib]
rm16, imm8 [mi: f7 /0 ib]
rm32, imm8 [mi: f7 /0 ib]
rm64, imm8 [mi: f7 /0 ib]
rm8, r8 [mr: 84 /r]
rm16, r16 [mr: 85 /r]
rm32, r32 [mr: 85 /r]
rm64, r64 [mr: 85 /r]
ud0: r32, rm32 [rm: 0f ff /r]
ud1: r32, rm32 [rm: 0f ff /r]
ud2: [zo: 0f 0b]
xadd:
rm8, r8 [mr: 0f c0 /r]
rm16, r16 [mr: 0f c1 /r]
rm32, r32 [mr: 0f c1 /r]
rm64, r64 [mr: 0f c1 /r]
xchg:
ax, r16 [-o: 90+r]
r16, ax [o-: 90+r]
eax, r32 [-o: 90+r]
r32, eax [o-: 90+r]
rax, r64 [-o: 90+r]
r64, rax [o-: 90+r]
rm8, r8 [mr: 86 /r]
r8, rm8 [rm: 86 /r]
rm16, r16 [mr: 87 /r]
r16, rm16 [rm: 87 /r]
rm32, r32 [mr: 87 /r]
r32, rm32 [rm: 87 /r]
rm64, r64 [mr: 87 /r]
r64, rm64 [rm: 87 /r]

@ -1,226 +0,0 @@
adc
adcx
add
adox
and
bsf
bsr
bswap
bt
btc
btr
bts
call
cbw
cwde
cdqe
cwd
cdq
cqo
clc
cld
clflush
clflushopt
cli
clts
cmc
cmova
cmovae
cmovb
cmovbe
cmovc
cmove
cmovg
cmovge
cmovl
cmovle
cmovna
cmovnae
cmovnb
cmovnbe
cmovnc
cmovne
cmovng
cmovnge
cmovnl
cmovnle
cmovno
cmovnp
cmovns
cmovnz
cmovo
cmovp
cmovpe
cmovpo
cmovs
cmovz
cmp
cmpsb
cmpsw
cmpsd
cmpsq
cmpxchg
cmpxchg8b
cmpxchg16b
cpuid
crc32
dec
div
hlt
idiv
imul
in
inc
insb
insw
insd
int
int3
invd
invlpg
iret
iretd
iretq
jmp
ja
jae
jb
jbe
jc
je
jg
jge
jl
jle
jna
jnae
jnb
jnbe
jnc
jne
jng
jnge
jnl
jnle
jno
jnp
jns
jnz
jo
jp
jpe
jpo
js
jz
jrcxz
lahf
lea
lodsb
lodsw
lodsd
lodsq
loop
loope
loopne
monitor
mov
movsb
movsw
movsd
movsq
movsx
movsxd
movzx
mul
mwait
neg
nop
not
or
out
outsb
outsw
outsd
pause
pop
popcnt
popf
popfq
prefetcht0
prefetcht1
prefetcht2
prefetchnta
push
pushf
pushfq
rcl
rcr
rol
ror
rdmsr
rdpmc
rdtsc
rdtscp
ret
retf
rsm
sal
sar
shl
shr
sbb
scasb
scasw
scasd
scasq
seta
setae
setb
setbe
setc
sete
setg
setge
setl
setle
setna
setnae
setnb
setnbe
setnc
setne
setng
setnge
setnl
setnle
setno
setnp
setns
setnz
seto
setp
setpe
setpo
sets
setz
stc
std
sti
stosb
stosw
stosd
stosq
sub
syscall
sysenter
sysexit
sysret
test
ud0
ud1
ud2
wbinvd
wrmsr
xadd
xchg
xor

@ -1,63 +1,24 @@
#pragma once
#if _MSC_VER
extern u32 _lzcnt_u32(u32);
extern u32 _tzcnt_u32(u32);
extern u64 _lzcnt_u64(u64);
extern u64 _tzcnt_u64(u64);
#endif
fn u8 leading_zeroes_u32(u32 value)
{
#if _MSC_VER
return (u8)_lzcnt_u32(value);
#else
return __builtin_clz(value);
#endif
}
fn u8 leading_zeroes_u64(u64 value)
{
#if _MSC_VER
return (u8)_lzcnt_u64(value);
#else
return __builtin_clzll(value);
#endif
}
fn u8 log2_alignment(u64 alignment)
{
assert(alignment != 0);
assert((alignment & (alignment - 1)) == 0);
u8 left = (sizeof(alignment) * 8) - 1;
u8 right = leading_zeroes_u64(alignment);
u64 left = (sizeof(alignment) * 8) - 1;
#if _MSC_VER
let_cast(u64, right, _lzcnt_u64(alignment));
#else
let_cast(u64, right, __builtin_clzll(alignment));
#endif
let_cast(u8, result, left - right);
return result;
}
fn u8 log2_u64(u64 v)
{
assert(v != 0);
return (sizeof(u64) * 8 - 1) - leading_zeroes_u64(v);
}
fn u8 log2_u32(u32 v)
{
assert(v != 0);
return (sizeof(u32) * 8 - 1) - leading_zeroes_u32(v);
}
fn u8 hex_digit_count(u64 v)
{
u8 result = 1;
if (v)
{
result = log2_u64(v) / log2_u64(16) + 1;
}
return result;
}
fn u128 u128_from_u64(u64 n)
{
#if defined(__TINYC__) || defined(_MSC_VER)
@ -202,7 +163,7 @@ fn u64 generate_random_number()
return u128_shift_right_by_64(rn_state);
}
fn u64 next_power_of_two(u64 n)
fn u64 round_up_to_next_power_of_2(u64 n)
{
n -= 1;
n |= n >> 1;
@ -276,49 +237,9 @@ fn u64 is_decimal_digit(u8 ch)
return (ch >= '0') & (ch <= '9');
}
fn u64 is_alphanumeric(u8 ch)
{
return is_alphabetic(ch) | is_decimal_digit(ch);
}
fn u64 is_hex_digit_alpha_lower(u8 ch)
{
return (ch >= 'a') & (ch <= 'f');
}
fn u64 is_hex_digit_alpha_upper(u8 ch)
{
return (ch >= 'A') & (ch <= 'F');
}
fn u64 is_hex_digit_alpha(u8 ch)
{
return is_hex_digit_alpha_lower(ch) | is_hex_digit_alpha_upper(ch);
}
fn u64 is_hex_digit(u8 ch)
{
return is_decimal_digit(ch) | is_hex_digit_alpha(ch);
}
fn u8 hex_ch_to_int(u8 ch)
{
if ((ch >= '0') & (ch <= '9'))
{
return ch - '0';
}
else if ((ch >= 'a') & (ch <= 'f'))
{
return ch - 'a' + 10;
}
else if ((ch >= 'A') & (ch <= 'F'))
{
return ch - 'A' + 10;
}
else
{
unreachable();
}
return (is_decimal_digit(ch) | (((ch == 'a') | (ch == 'A')) | ((ch == 'b') | (ch == 'B')))) | ((((ch == 'c') | (ch == 'C')) | ((ch == 'd') | (ch == 'D'))) | (((ch == 'e') | (ch == 'E')) | ((ch == 'f') | (ch == 'F'))));
}
fn u64 is_identifier_start(u8 ch)
@ -361,38 +282,25 @@ fn Hash32 hash64_to_hash32(Hash64 hash64)
return result;
}
fn u64 align_forward_u32(u32 value, u32 alignment)
{
u32 mask = alignment - 1;
u32 result = (value + mask) & ~mask;
return result;
}
fn u32 align_backward_u32(u32 value, u32 alignment)
{
u32 result = value & ~(alignment - 1);
return result;
}
fn u64 align_forward_u64(u64 value, u64 alignment)
fn u64 align_forward(u64 value, u64 alignment)
{
u64 mask = alignment - 1;
u64 result = (value + mask) & ~mask;
return result;
}
fn u64 align_backward_u64(u64 value, u64 alignment)
fn u64 align_backward(u64 value, u64 alignment)
{
u64 result = value & ~(alignment - 1);
return result;
}
fn u8 is_power_of_two_u64(u64 value)
fn u8 is_power_of_two(u64 value)
{
return (value & (value - 1)) == 0;
}
fn u8 first_bit_set_u32(u32 value)
fn u8 first_bit_set_32(u32 value)
{
#if _MSC_VER
DWORD result_dword;
@ -406,7 +314,7 @@ fn u8 first_bit_set_u32(u32 value)
return result;
}
fn u64 first_bit_set_u64(u64 value)
fn u64 first_bit_set_64(u64 value)
{
#if _MSC_VER
DWORD result_dword;
@ -431,33 +339,3 @@ fn Hash32 hash64_fib_end(Hash64 hash)
let(result, TRUNCATE(Hash32, ((hash + 1) * 11400714819323198485ull) >> 32));
return result;
}
fn u64 parse_hexadecimal(String string, u8* error)
{
u8* it = &string.pointer[string.length - 1];
u8 is_error = 0;
u64 result = 0;
while (it >= string.pointer)
{
u8 ch = *it;
u8 is_error_it = !is_hex_digit(ch);
is_error |= is_error_it;
if (is_error_it)
{
break;
}
u8 sub = is_decimal_digit(ch) ? '0' : (is_hex_digit_alpha_lower(ch) ? 'a' : 'A');
u8 hex_value = ch - sub + 10 * is_hex_digit_alpha(ch);
assert((hex_value & 0xf) == hex_value);
result = (result << 4) | hex_value;
it -= 1;
}
*error = is_error;
return result;
}

@ -1,10 +1,5 @@
#pragma once
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define USE_MEMCPY 1
#if _WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
@ -15,6 +10,16 @@
#define BB_DEBUG 1
#endif
#define BB_INCLUDE_INTRINSIC 0
#if BB_DEBUG == 0
#undef BB_INCLUDE_INTRINSIC
#define BB_INCLUDE_INTRINSIC 1
#endif
#if BB_INCLUDE_INTRINSIC
#if defined(__x86_64__)
#include <immintrin.h>
#endif
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
@ -135,7 +140,6 @@ declare_slice(s32);
declare_slice(s64);
declare_slice_p(char);
declare_slice_p(u8);
declare_slice_p(void);
typedef Slice(u8) String;
@ -190,7 +194,7 @@ declare_slice(String);
#define unlikely(x) expect(x, 0)
#define breakpoint() __builtin_debugtrap()
#define failed_execution() panic("Failed execution at {cstr}:{u32}\n", __FILE__, __LINE__)
#define todo() os_is_being_debugged() ? trap() : panic("TODO at {cstr}:{u32}\n", __FILE__, __LINE__); fix_unreachable()
#define todo() panic("TODO at {cstr}:{u32}\n", __FILE__, __LINE__); fix_unreachable()
fn void print(const char* format, ...);
BB_NORETURN BB_COLD fn void os_exit(u32 exit_code);
@ -212,8 +216,7 @@ fn BB_NORETURN BB_COLD void trap_ext()
#define trap() (trap_ext(), __builtin_unreachable())
#endif
fn u8 os_is_being_debugged();
#define panic(format, ...) (!os_is_being_debugged() ? print(format, __VA_ARGS__), os_exit(1) : os_exit(1))
#define panic(format, ...) (print(format, __VA_ARGS__), os_exit(1))
#define let_pointer_cast(PointerChildType, var_name, value) PointerChildType* var_name = (PointerChildType*)(value)
#if defined(__TINYC__) || defined(_MSC_VER)
@ -320,12 +323,12 @@ global_variable const u8 bracket_close = ']';
#define s_get_slice(T, s, start, end) (Slice(T)){ .pointer = ((s).pointer) + (start), .length = (end) - (start) }
#define s_equal(a, b) ((a).length == (b).length && memcmp((a).pointer, (b).pointer, sizeof(*((a).pointer)) * (a).length) == 0)
fn u64 align_forward_u64(u64 value, u64 alignment);
fn u64 align_backward_u64(u64 value, u64 alignment);
fn u8 log2_alignment_u64(u64 alignment);
fn u8 is_power_of_two_u64(u64 value);
fn u8 first_bit_set_u32(u32 value);
fn u64 first_bit_set_u64(u64 value);
fn u64 align_forward(u64 value, u64 alignment);
fn u64 align_backward(u64 value, u64 alignment);
fn u8 log2_alignment(u64 alignment);
fn u8 is_power_of_two(u64 value);
fn u8 first_bit_set_32(u32 value);
fn u64 first_bit_set_64(u64 value);
fn u32 format_decimal(String buffer, u64 decimal);
fn u32 format_hexadecimal(String buffer, u64 hexadecimal);
@ -337,7 +340,6 @@ fn u8 get_next_ch_safe(String string, u64 index);
fn u64 is_identifier_start(u8 ch);
fn u64 is_identifier_ch(u8 ch);
fn u64 is_alphabetic(u8 ch);
fn u64 is_alphanumeric(u8 ch);
fn u64 parse_decimal(String string);

@ -1075,72 +1075,6 @@ typedef enum IntegerFormat
INTEGER_FORMAT_BINARY,
} IntegerFormat;
STRUCT(IntegerFormatOptions)
{
IntegerFormat format;
u32 width;
};
fn IntegerFormatOptions integer_format_options(u8** it)
{
IntegerFormatOptions options = {
.format = INTEGER_FORMAT_DECIMAL,
};
if (**it == ':')
{
*it += 1;
while (**it != brace_close)
{
switch (**it)
{
case 'x':
options.format = INTEGER_FORMAT_HEXADECIMAL;
*it += 1;
break;
case 'd':
options.format = INTEGER_FORMAT_DECIMAL;
*it += 1;
break;
case 'o':
options.format = INTEGER_FORMAT_OCTAL;
*it += 1;
break;
case 'b':
options.format = INTEGER_FORMAT_BINARY;
*it += 1;
break;
case 'w':
{
*it += 1;
if (**it != '=')
{
todo();
}
*it += 1;
let(start, *it);
while (is_decimal_digit(**it))
{
*it += 1;
}
let(end, *it);
assign_cast(options.width, parse_decimal(slice_from_pointer_range(u8, start, end)));
} break;
default:
unreachable();
}
*it += **it == ',';
}
}
return options;
}
fn String format_string_va(String buffer, const char* format, va_list args)
{
u8* it = (u8*)format;
@ -1247,7 +1181,31 @@ fn String format_string_va(String buffer, const char* format, va_list args)
u8* bit_count_end = it;
u64 bit_count = parse_decimal(slice_from_pointer_range(u8, (u8*)bit_count_start, (u8*)bit_count_end));
IntegerFormatOptions options = integer_format_options(&it);
IntegerFormat integer_format = INTEGER_FORMAT_DECIMAL;
if (*it == ':')
{
it += 1;
switch (*it)
{
case 'x':
integer_format = INTEGER_FORMAT_HEXADECIMAL;
break;
case 'd':
integer_format = INTEGER_FORMAT_DECIMAL;
break;
case 'o':
integer_format = INTEGER_FORMAT_OCTAL;
break;
case 'b':
integer_format = INTEGER_FORMAT_BINARY;
break;
default:
unreachable();
}
it += 1;
}
s64 original_value;
switch (bit_count)
@ -1266,21 +1224,11 @@ fn String format_string_va(String buffer, const char* format, va_list args)
String buffer_slice = s_get_slice(u8, buffer, buffer_i, buffer.length);
switch (options.format)
switch (integer_format)
{
case INTEGER_FORMAT_HEXADECIMAL:
{
u32 expected_characters = hex_digit_count(original_value);
if (expected_characters < options.width)
{
u32 extra_characters = options.width - expected_characters;
memset(buffer.pointer, '0', extra_characters);
buffer_i += extra_characters;
}
let(written_characters, format_hexadecimal(buffer_slice, original_value));
assert(expected_characters == written_characters);
buffer_i += written_characters;
} break;
case INTEGER_FORMAT_DECIMAL:
@ -1333,7 +1281,39 @@ fn String format_string_va(String buffer, const char* format, va_list args)
u8* bit_count_end = it;
u64 bit_count = parse_decimal(slice_from_pointer_range(u8, (u8*)bit_count_start, (u8*)bit_count_end));
IntegerFormatOptions options = integer_format_options(&it);
typedef enum IntegerFormat
{
INTEGER_FORMAT_HEXADECIMAL,
INTEGER_FORMAT_DECIMAL,
INTEGER_FORMAT_OCTAL,
INTEGER_FORMAT_BINARY,
} IntegerFormat;
IntegerFormat integer_format = INTEGER_FORMAT_DECIMAL;
if (*it == ':')
{
it += 1;
switch (*it)
{
case 'x':
integer_format = INTEGER_FORMAT_HEXADECIMAL;
break;
case 'd':
integer_format = INTEGER_FORMAT_DECIMAL;
break;
case 'o':
integer_format = INTEGER_FORMAT_OCTAL;
break;
case 'b':
integer_format = INTEGER_FORMAT_BINARY;
break;
default:
unreachable();
}
it += 1;
}
u64 original_value;
switch (bit_count)
@ -1350,41 +1330,26 @@ fn String format_string_va(String buffer, const char* format, va_list args)
unreachable();
}
let(buffer_slice, s_get_slice(u8, buffer, buffer_i, buffer.length));
switch (options.format)
switch (integer_format)
{
case INTEGER_FORMAT_HEXADECIMAL:
{
u32 expected_characters = hex_digit_count(original_value);
if (expected_characters < options.width)
{
u32 extra_characters = options.width - expected_characters;
memset(buffer.pointer + buffer_i, '0', extra_characters);
buffer_i += extra_characters;
}
let(buffer_slice, s_get_slice(u8, buffer, buffer_i, buffer.length));
let(written_characters, format_hexadecimal(buffer_slice, original_value));
assert(expected_characters == written_characters);
buffer_i += written_characters;
} break;
case INTEGER_FORMAT_DECIMAL:
{
let(buffer_slice, s_get_slice(u8, buffer, buffer_i, buffer.length));
let(written_characters, format_decimal(buffer_slice, original_value));
buffer_i += written_characters;
} break;
case INTEGER_FORMAT_OCTAL:
{
let(buffer_slice, s_get_slice(u8, buffer, buffer_i, buffer.length));
unused(buffer_slice);
todo();
} break;
case INTEGER_FORMAT_BINARY:
{
let(buffer_slice, s_get_slice(u8, buffer, buffer_i, buffer.length));
unused(buffer_slice);
todo();
} break;
}
@ -1416,27 +1381,3 @@ fn String format_string(String buffer, const char* format, ...)
va_end(args);
return result;
}
fn void formatter_append(StringFormatter* formatter, const char* format, ...)
{
va_list args;
va_start(args, format);
String buffer = s_get_slice(u8, formatter->buffer, formatter->index, formatter->buffer.length);
let(result, format_string_va(buffer, format, args));
va_end(args);
formatter->index += result.length;
}
fn void formatter_append_string(StringFormatter* formatter, String string)
{
assert(string.length + formatter->index <= formatter->buffer.length);
memcpy(formatter->buffer.pointer + formatter->index, string.pointer, string.length);
formatter->index += string.length;
}
fn void formatter_append_character(StringFormatter* formatter, u8 ch)
{
assert(formatter->index < formatter->buffer.length);
formatter->buffer.pointer[formatter->index] = ch;
formatter->index += 1;
}

@ -1,13 +1,6 @@
#pragma once
STRUCT(StringFormatter)
{
String buffer;
u64 index;
};
#include <std/base.h>
fn void formatter_append(StringFormatter* formatter, const char* format, ...);
fn void formatter_append_string(StringFormatter* formatter, String string);
fn void formatter_append_character(StringFormatter* formatter, u8 ch);
fn String format_string(String buffer, const char* format, ...);
fn String format_string_va(String buffer, const char* format, va_list args);

@ -2,11 +2,9 @@
#include <std/string.h>
#include <std/format.h>
#include <std/virtual_buffer.h>
#include <std/string.c>
#include <std/format.c>
#include <std/virtual_buffer.c>
#if _WIN32
global_variable u64 cpu_frequency;
@ -776,15 +774,6 @@ fn u64 os_timer_get()
#endif
}
FileDescriptor os_file_descriptor_invalid()
{
#if _WIN32
return INVALID_HANDLE_VALUE;
#else
return -1;
#endif
}
fn u8 os_file_descriptor_is_valid(FileDescriptor fd)
{
#if _WIN32
@ -863,8 +852,6 @@ fn void os_file_write(FileDescriptor fd, String content)
assert(result != 0);
#else
let(result, syscall_write(fd, content.pointer, content.length));
let(my_errno, strerror(errno));
unused(my_errno);
assert(cast_to(u64, result) == content.length);
#endif
}
@ -950,9 +937,6 @@ fn u8* os_reserve(u64 base, u64 size, OSReserveProtectionFlags protection, OSRes
#else
int protection_flags = (protection.read * PROT_READ) | (protection.write * PROT_WRITE) | (protection.execute * PROT_EXEC);
int map_flags = (map.anon * MAP_ANONYMOUS) | (map.priv * MAP_PRIVATE) | (map.noreserve * MAP_NORESERVE);
#ifdef __linux__
map_flags |= (map.populate * MAP_POPULATE);
#endif
u8* result = (u8*)posix_mmap((void*)base, size, protection_flags, map_flags, -1, 0);
assert(result != MAP_FAILED);
return result;
@ -979,36 +963,8 @@ fn void os_directory_make(String path)
#endif
}
fn u8 os_is_being_debugged()
{
u8 result = 0;
#if _WIN32
result = IsDebuggerPresent() != 0;
#else
#ifdef __APPLE__
let(request, PT_TRACE_ME);
#else
let(request, PTRACE_TRACEME);
#endif
if (ptrace(request, 0, 0, 0) == -1)
{
let(error, errno);
if (error == EPERM)
{
result = 1;
}
}
#endif
return result;
}
BB_NORETURN BB_COLD fn void os_exit(u32 exit_code)
{
if (exit_code != 0 && os_is_being_debugged())
{
trap();
}
exit(exit_code);
}
@ -1060,12 +1016,12 @@ fn Arena* arena_initialize_default(u64 initial_size)
fn u8* arena_allocate_bytes(Arena* arena, u64 size, u64 alignment)
{
u64 aligned_offset = align_forward_u64(arena->position, alignment);
u64 aligned_offset = align_forward(arena->position, alignment);
u64 aligned_size_after = aligned_offset + size;
if (aligned_size_after > arena->os_position)
{
u64 committed_size = align_forward_u64(aligned_size_after, arena->granularity);
u64 committed_size = align_forward(aligned_size_after, arena->granularity);
u64 size_to_commit = committed_size - arena->os_position;
void* commit_pointer = (u8*)arena + arena->os_position;
os_commit(commit_pointer, size_to_commit);
@ -1101,18 +1057,6 @@ fn String arena_join_string(Arena* arena, Slice(String) pieces)
return (String) { .pointer = pointer, .length = size };
}
fn String arena_duplicate_string(Arena* arena, String string)
{
u8* result = arena_allocate(arena, u8, string.length + 1);
memcpy(result, string.pointer, string.length);
result[string.length] = 0;
return (String) {
.pointer = result,
.length = string.length,
};
}
fn void arena_reset(Arena* arena)
{
arena->position = minimum_position;
@ -1161,6 +1105,7 @@ fn String file_read(Arena* arena, String path)
fn void file_write(FileWriteOptions options)
{
print("Writing file \"{s}\"...\n", options.path);
let(fd, os_file_open(options.path, (OSFileOpenFlags) {
.write = 1,
.truncate = 1,
@ -1177,18 +1122,11 @@ fn void file_write(FileWriteOptions options)
os_file_close(fd);
}
fn RunCommandResult run_command(Arena* arena, CStringSlice arguments, char* envp[], RunCommandOptions run_options)
fn void run_command(Arena* arena, CStringSlice arguments, char* envp[], RunCommandOptions run_options)
{
unused(arena);
assert(arguments.length > 0);
assert(arguments.pointer[arguments.length - 1] == 0);
RunCommandResult result = {};
Timestamp start_timestamp = {};
Timestamp end_timestamp = {};
f64 ms = 0.0;
u64 measure_time = run_options.debug;
if (run_options.debug)
{
print("Running command:\n");
@ -1201,6 +1139,8 @@ fn RunCommandResult run_command(Arena* arena, CStringSlice arguments, char* envp
}
#if _WIN32
let(start_timestamp, os_timestamp());
u32 length = 0;
for (u32 i = 0; i < arguments.length; i += 1)
{
@ -1227,6 +1167,7 @@ fn RunCommandResult run_command(Arena* arena, CStringSlice arguments, char* envp
}
}
bytes[byte_i - 1] = 0;
let(end_timestamp, os_timestamp());
PROCESS_INFORMATION process_information = {};
STARTUPINFOA startup_info = {};
@ -1234,22 +1175,14 @@ fn RunCommandResult run_command(Arena* arena, CStringSlice arguments, char* envp
startup_info.dwFlags |= STARTF_USESTDHANDLES;
startup_info.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
startup_info.hStdError = GetStdHandle(STD_ERROR_HANDLE);
let(handle_inheritance, 1);
if (measure_time)
{
start_timestamp = os_timestamp();
}
let(start, os_timestamp());
if (CreateProcessA(0, bytes, 0, 0, handle_inheritance, 0, 0, 0, &startup_info, &process_information))
{
WaitForSingleObject(process_information.hProcess, INFINITE);
if (measure_time)
{
end_timestamp = os_timestamp();
ms = os_resolve_timestamps(start_timestamp, end_timestamp, TIME_UNIT_MILLISECONDS);
}
let(end, os_timestamp());
let(ms, os_resolve_timestamps(start, end, TIME_UNIT_MILLISECONDS));
if (run_options.debug)
{
@ -1294,179 +1227,74 @@ fn RunCommandResult run_command(Arena* arena, CStringSlice arguments, char* envp
print("CreateProcessA call failed: {cstr}\n", lpMsgBuf);
todo();
}
unused(start_timestamp);
unused(end_timestamp);
unused(envp);
#else
int null_fd;
if (run_options.use_null_file_descriptor)
{
null_fd = run_options.null_file_descriptor;
assert(os_file_descriptor_is_valid(null_fd));
}
else if (run_options.stdout_stream.policy == CHILD_PROCESS_STREAM_IGNORE || run_options.stderr_stream.policy == CHILD_PROCESS_STREAM_IGNORE)
{
null_fd = open("/dev/null", O_WRONLY);
assert(os_file_descriptor_is_valid(null_fd));
}
int stdout_pipe[2];
int stderr_pipe[2];
if (run_options.stdout_stream.policy == CHILD_PROCESS_STREAM_PIPE && pipe(stdout_pipe) == -1)
{
todo();
}
if (run_options.stderr_stream.policy == CHILD_PROCESS_STREAM_PIPE && pipe(stderr_pipe) == -1)
{
todo();
}
unused(arena);
pid_t pid = syscall_fork();
if (pid == -1)
{
todo();
}
if (measure_time)
{
start_timestamp = os_timestamp();
}
let(start_timestamp, os_timestamp());
if (pid == 0)
{
switch (run_options.stdout_stream.policy)
{
case CHILD_PROCESS_STREAM_PIPE:
{
close(stdout_pipe[0]);
dup2(stdout_pipe[1], STDOUT_FILENO);
close(stdout_pipe[1]);
} break;
case CHILD_PROCESS_STREAM_IGNORE:
{
dup2(null_fd, STDOUT_FILENO);
close(null_fd);
} break;
case CHILD_PROCESS_STREAM_INHERIT:
{
} break;
}
switch (run_options.stderr_stream.policy)
{
case CHILD_PROCESS_STREAM_PIPE:
{
close(stderr_pipe[0]);
dup2(stderr_pipe[1], STDERR_FILENO);
close(stderr_pipe[1]);
} break;
case CHILD_PROCESS_STREAM_IGNORE:
{
dup2(null_fd, STDERR_FILENO);
close(null_fd);
} break;
case CHILD_PROCESS_STREAM_INHERIT:
{
} break;
}
// close(pipes[0]);
// fcntl(pipes[1], F_SETFD, FD_CLOEXEC);
let(result, syscall_execve(arguments.pointer[0], arguments.pointer, envp));
unused(result);
#if LINK_LIBC
panic("Execve failed! Error: {cstr}\n", strerror(errno));
#else
todo();
#endif
}
else
{
if (run_options.stdout_stream.policy == CHILD_PROCESS_STREAM_PIPE)
{
close(stdout_pipe[1]);
}
if (run_options.stderr_stream.policy == CHILD_PROCESS_STREAM_PIPE)
{
close(stderr_pipe[1]);
}
if (run_options.stdout_stream.policy == CHILD_PROCESS_STREAM_PIPE)
{
assert(run_options.stdout_stream.capacity);
ssize_t byte_count = read(stdout_pipe[0], run_options.stdout_stream.buffer, run_options.stdout_stream.capacity);
assert(byte_count >= 0);
*run_options.stdout_stream.length = byte_count;
close(stdout_pipe[0]);
}
if (run_options.stderr_stream.policy == CHILD_PROCESS_STREAM_PIPE)
{
assert(run_options.stderr_stream.capacity);
ssize_t byte_count = read(stderr_pipe[0], run_options.stderr_stream.buffer, run_options.stderr_stream.capacity);
assert(byte_count >= 0);
*run_options.stderr_stream.length = byte_count;
close(stderr_pipe[0]);
}
int status = 0;
int options = 0;
pid_t waitpid_result = syscall_waitpid(pid, &status, options);
if (measure_time)
{
end_timestamp = os_timestamp();
}
if (waitpid_result == pid)
pid_t result = syscall_waitpid(pid, &status, options);
let(end_timestamp, os_timestamp());
int success = 0;
if (result == pid)
{
if (run_options.debug)
{
print("{cstr} ", arguments.pointer[0]);
if (WIFEXITED(status))
{
let(exit_code, WEXITSTATUS(status));
print("exited with code {u32}\n", exit_code);
}
else if (WIFSIGNALED(status))
{
let(signal_code, WTERMSIG(status));
print("was signaled: {u32}\n", signal_code);
}
else if (WIFSTOPPED(status))
{
let(stopped_code, WSTOPSIG(status));
print("was stopped: {u32}\n", stopped_code);
}
else
{
print("terminated unexpectedly with status {u32}\n", status);
}
}
if (WIFEXITED(status))
{
let(exit_code, WEXITSTATUS(status));
result.termination_code = exit_code;
result.termination_kind = PROCESS_TERMINATION_EXIT;
if (run_options.debug)
{
print("exited with code {u32}\n", exit_code);
}
}
else if (WIFSIGNALED(status))
{
let(signal_code, WTERMSIG(status));
result.termination_code = signal_code;
result.termination_kind = PROCESS_TERMINATION_SIGNAL;
if (run_options.debug)
{
print("was signaled: {u32}\n", signal_code);
}
}
else if (WIFSTOPPED(status))
{
let(stop_code, WSTOPSIG(status));
result.termination_code = stop_code;
result.termination_kind = PROCESS_TERMINATION_STOP;
if (run_options.debug)
{
print("was stopped: {u32}\n", stop_code);
}
}
else
{
result.termination_kind = PROCESS_TERMINATION_UNKNOWN;
if (run_options.debug)
{
print("terminated unexpectedly with status {u32}\n", status);
}
success = exit_code == 0;
}
}
else if (waitpid_result == -1)
else if (result == -1)
{
let(waitpid_error, errno);
print("Error waiting for process termination: {u32}\n", waitpid_error);
@ -1477,25 +1305,42 @@ fn RunCommandResult run_command(Arena* arena, CStringSlice arguments, char* envp
todo();
}
let(success, result.termination_kind == PROCESS_TERMINATION_EXIT && result.termination_code == 0);
if (run_options.debug && !success)
if (!success)
{
print("{cstr} failed to run successfully!\n", arguments.pointer[0]);
print("Program failed to run successfully!\n");
failed_execution();
}
if (run_options.debug)
{
ms = os_resolve_timestamps(start_timestamp, end_timestamp, TIME_UNIT_MILLISECONDS);
let(ms, os_resolve_timestamps(start_timestamp, end_timestamp, TIME_UNIT_MILLISECONDS));
u32 ticks = 0;
#if LINK_LIBC == 0
ticks = cpu_frequency != 0;
#endif
print("Command run {cstr} in {f64} {cstr}\n", success ? "successfully" : "with errors", ms, ticks ? "ticks" : "ms");
print("Command run successfully in {f64} {cstr}\n", ms, ticks ? "ticks" : "ms");
}
}
#endif
}
if (!run_options.use_null_file_descriptor && os_file_descriptor_is_valid(null_fd))
fn u8 os_is_being_debugged()
{
u8 result = 0;
#if _WIN32
result = IsDebuggerPresent() != 0;
#else
#ifdef __APPLE__
let(request, PT_TRACE_ME);
#else
let(request, PTRACE_TRACEME);
#endif
if (ptrace(request, 0, 0, 0) == -1)
{
let(error, errno);
if (error == EPERM)
{
close(null_fd);
result = 1;
}
}
#endif
@ -1617,85 +1462,3 @@ fn u8 os_library_is_valid(OSLibrary library)
{
return library.handle != 0;
}
fn String file_find_in_path(Arena* arena, String file, String path_env, String extension)
{
String result = {};
assert(path_env.pointer);
String path_it = path_env;
u8 buffer[4096];
#if _WIN32
u8 env_path_separator = ';';
u8 path_separator = '\\';
#else
u8 env_path_separator = ':';
u8 path_separator = '/';
#endif
while (path_it.length)
{
let(index, string_first_ch(path_it, env_path_separator));
index = unlikely(index == STRING_NO_MATCH) ? path_it.length : index;
let(path_chunk, s_get_slice(u8, path_it, 0, index));
u64 i = 0;
memcpy(&buffer[i], path_chunk.pointer, path_chunk.length);
i += path_chunk.length;
buffer[i] = path_separator;
i += 1;
memcpy(&buffer[i], file.pointer, file.length);
i += file.length;
if (extension.length)
{
memcpy(&buffer[i], extension.pointer, extension.length);
i += extension.length;
}
buffer[i] = 0;
i += 1;
let(total_length, i - 1);
OSFileOpenFlags flags = {
.read = 1,
};
OSFilePermissions permissions = {
.readable = 1,
.writable = 1,
};
String path = { .pointer = buffer, .length = total_length };
FileDescriptor fd = os_file_open(path, flags, permissions);
if (os_file_descriptor_is_valid(fd))
{
os_file_close(fd);
result.pointer = arena_allocate(arena, u8, total_length + 1);
memcpy(result.pointer, buffer, total_length + 1);
result.length = total_length;
break;
}
String new_path = s_get_slice(u8, path_it, index + (index != path_it.length), path_it.length);
assert(new_path.length < path_env.length);
path_it = new_path;
}
return result;
}
fn String executable_find_in_path(Arena* arena, String executable, String path_env)
{
String extension = {};
#if _WIN32
extension = strlit(".exe");
#endif
return file_find_in_path(arena, executable, path_env, extension);
}

@ -27,43 +27,9 @@ typedef enum TimeUnit
TIME_UNIT_SECONDS,
} TimeUnit;
ENUM(ProcessTerminationKind, u8,
PROCESS_TERMINATION_UNKNOWN,
PROCESS_TERMINATION_EXIT,
PROCESS_TERMINATION_SIGNAL,
PROCESS_TERMINATION_STOP,
);
STRUCT(RunCommandResult)
{
u32 termination_code;
ProcessTerminationKind termination_kind;
u8 reserved[3];
};
typedef enum ChildProcessStreamPolicy
{
CHILD_PROCESS_STREAM_INHERIT,
CHILD_PROCESS_STREAM_PIPE,
CHILD_PROCESS_STREAM_IGNORE,
} ChildProcessStreamPolicy;
STRUCT(ChildProcessStream)
{
u8* buffer;
u32* length;
u32 capacity;
ChildProcessStreamPolicy policy;
};
STRUCT(RunCommandOptions)
{
ChildProcessStream stdout_stream;
ChildProcessStream stderr_stream;
FileDescriptor null_file_descriptor;
u64 use_null_file_descriptor:1;
u64 debug:1;
u64 reserved:62;
};
STRUCT(Timestamp)
@ -100,7 +66,6 @@ STRUCT(OSReserveMapFlags)
{
u32 priv:1;
u32 anon:1;
u32 populate:1;
u32 noreserve:1;
u32 reserved:29;
};
@ -134,7 +99,7 @@ global_variable u64 default_size = GB(4);
fn void vprint(const char* format, va_list args);
fn void print(const char* format, ...);
fn RunCommandResult run_command(Arena* arena, CStringSlice arguments, char* envp[], RunCommandOptions options);
fn void run_command(Arena* arena, CStringSlice arguments, char* envp[], RunCommandOptions options);
fn String file_read(Arena* arena, String path);
fn void file_write(FileWriteOptions options);

@ -31,7 +31,7 @@ fn u8 rendering_backend_is_valid(RenderingBackend rendering_backend)
{
#ifdef __linux__
valid = rendering_backend == RENDERING_BACKEND_VULKAN;
#elif defined(__APPLE__)
#elif __APPLE__
valid = rendering_backend == RENDERING_BACKEND_METAL || rendering_backend == RENDERING_BACKEND_VULKAN;
#elif _WIN32
valid = rendering_backend == RENDERING_BACKEND_DIRECTX12 || rendering_backend == RENDERING_BACKEND_VULKAN;

@ -1,4 +1,5 @@
#pragma once
#include <std/virtual_buffer.h>
#include <std/os.h>
fn void vb_generic_ensure_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count)
{
@ -12,8 +13,8 @@ fn void vb_generic_ensure_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 ite
vb->pointer = os_reserve(0, item_size * UINT32_MAX, (OSReserveProtectionFlags) {}, (OSReserveMapFlags) { .priv = 1, .anon = 1, .noreserve = 1 });
}
let_cast(u32, old_page_capacity, align_forward_u64(old_capacity * item_size, minimum_granularity));
let_cast(u32, new_page_capacity, align_forward_u64(wanted_capacity * item_size, minimum_granularity));
let_cast(u32, old_page_capacity, align_forward(old_capacity * item_size, minimum_granularity));
let_cast(u32, new_page_capacity, align_forward(wanted_capacity * item_size, minimum_granularity));
let(commit_size, new_page_capacity - old_page_capacity);
void* commit_pointer = vb->pointer + old_page_capacity;
@ -48,13 +49,11 @@ fn u8* vb_append_bytes(VirtualBuffer(u8*) vb, Slice(u8) bytes)
return pointer;
}
fn u32 vb_copy_string(VirtualBuffer(u8)* buffer, String string)
fn void vb_copy_string(VirtualBuffer(u8)* buffer, String string)
{
let(offset, buffer->length);
let_cast(u32, length, string.length);
let(pointer, vb_add(buffer, length));
memcpy(pointer, string.pointer, length);
return offset;
}
fn u64 vb_copy_string_zero_terminated(VirtualBuffer(u8)* buffer, String string)
@ -66,23 +65,3 @@ fn u64 vb_copy_string_zero_terminated(VirtualBuffer(u8)* buffer, String string)
return string.length;
}
fn void vb_copy_byte_repeatedly(VirtualBuffer(u8)* buffer, u8 byte, u32 times)
{
u8* ptr = vb_generic_add(buffer, 1, times);
memset(ptr, byte, times);
}
fn u64 vb_format(VirtualBuffer(u8)* vb, const char* format, ...)
{
u8 buffer[4096];
va_list args;
va_start(args, format);
let(result, format_string_va((String)array_to_slice(buffer), format, args));
va_end(args);
assert(result.length <= array_length(buffer));
vb_copy_string(vb, result);
return result.length;
}

@ -49,6 +49,5 @@ fn void vb_generic_ensure_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 ite
fn u8* vb_generic_add_assume_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count);
fn u8* vb_generic_add(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count);
fn u8* vb_append_bytes(VirtualBuffer(u8*) vb, Slice(u8) bytes);
fn u32 vb_copy_string(VirtualBuffer(u8)* buffer, String string);
fn void vb_copy_string(VirtualBuffer(u8)* buffer, String string);
fn u64 vb_copy_string_zero_terminated(VirtualBuffer(u8)* buffer, String string);
fn u64 vb_format(VirtualBuffer(u8)* vb, const char* format, ...);

@ -312,6 +312,7 @@ fn void buffer_copy_to_host(VulkanBuffer buffer, Slice(HostBufferCopy) regions)
let(region, regions.pointer[i]);
let(destination, buffer_pointer + region.destination_offset);
assert(destination + region.source.length <= (u8*)buffer.address + buffer.size);
#define USE_MEMCPY 1
#if USE_MEMCPY
memcpy(destination, region.source.pointer, region.source.length);
#else

@ -22,10 +22,10 @@ mkdir %BUILD_DIR% > NUL 2>&1
set BUILD_OUT=cache\build.exe
set BB_ERROR_ON_WARNINGS=%BB_CI%
REM if "%BB_CI%" == "0" (
REM %VK_SDK_PATH%\Bin\glslangValidator.exe -V bootstrap\std\shaders\rect.vert -o cache\rect.vert.spv --quiet || exit /b 1
REM %VK_SDK_PATH%\Bin\glslangValidator.exe -V bootstrap\std\shaders\rect.frag -o cache\rect.frag.spv --quiet || exit /b 1
REM )
if "%BB_CI%" == "0" (
%VK_SDK_PATH%\Bin\glslangValidator.exe -V bootstrap\std\shaders\rect.vert -o cache\rect.vert.spv --quiet || exit /b 1
%VK_SDK_PATH%\Bin\glslangValidator.exe -V bootstrap\std\shaders\rect.frag -o cache\rect.frag.spv --quiet || exit /b 1
)
cl /Zi /Y- /Gm- /std:clatest /diagnostics:caret -FC /nologo build.c /Fd%BUILD_DIR%\ /Fo%BUILD_DIR%\ /Fe%BUILD_OUT% -Ibootstrap -DBB_TIMETRACE=0 -DBB_BUILD_TYPE=\"%BB_BUILD_TYPE%\" -DBB_CI=%BB_CI% -DBB_ERROR_ON_WARNINGS=%BB_ERROR_ON_WARNINGS% -DBB_ERROR_LIMIT=%BB_ERROR_LIMIT% /link /INCREMENTAL:NO || exit /b 1

2077
build.c

File diff suppressed because it is too large Load Diff

@ -1,8 +1,6 @@
#!/usr/bin/env bash
set -eu
MY_CWD=$PWD
if [[ -z "${BB_CI-}" ]]; then
BB_CI=0
fi
@ -19,19 +17,10 @@ if [[ -z "${BB_ERROR_LIMIT-}" ]]; then
BB_ERROR_LIMIT=$((1 - BB_CI))
fi
BB_COMPILE_SHADERS=0
BUILD_DIR=cache
LARGE_ASSET_BASE_URL=https://github.com/birth-software/bloat-buster/releases/download/large-assets
mkdir -p $BUILD_DIR
if [[ ! -f "$BUILD_DIR/large_assembly.s" ]]; then
cd $BUILD_DIR
wget $LARGE_ASSET_BASE_URL/large_assembly.s -o large_assembly.s
cd $MY_CWD
fi
if [[ "${BB_COMPILE_SHADERS}" == "1" ]]; then
if [[ "${BB_CI}" == "0" ]]; then
glslangValidator -V bootstrap/std/shaders/rect.vert -o $BUILD_DIR/rect.vert.spv --quiet
glslangValidator -V bootstrap/std/shaders/rect.frag -o $BUILD_DIR/rect.frag.spv --quiet
fi

363
build.zig

@ -1,363 +0,0 @@
const std = @import("std");
const builtin = @import("builtin");
fn run_process_and_capture_stdout(b: *std.Build, argv: []const []const u8) ![]const u8 {
const result = std.process.Child.run(.{
.allocator = b.allocator,
.argv = argv,
}) catch |err| return err;
switch (result.term) {
.Exited => |exit_code| {
if (exit_code != 0) {
return error.SpawnError;
}
},
else => return error.SpawnError,
}
return result.stdout;
}
fn file_find_in_path(allocator: std.mem.Allocator, file_name: []const u8, path_env: []const u8, extension: []const u8) ?[]const u8 {
const path_env_separator = switch (builtin.os.tag) {
.windows => ';',
else => ':',
};
const path_separator = switch (builtin.os.tag) {
.windows => '\\',
else => '/',
};
var env_it = std.mem.splitScalar(u8, path_env, path_env_separator);
const result: ?[]const u8 = while (env_it.next()) |dir_path| {
const full_path = std.mem.concatWithSentinel(allocator, u8, &.{ dir_path, &[1]u8{path_separator}, file_name, extension }, 0) catch unreachable;
const file = std.fs.cwd().openFile(full_path, .{}) catch continue;
file.close();
break full_path;
} else null;
return result;
}
fn executable_find_in_path(allocator: std.mem.Allocator, file_name: []const u8, path_env: []const u8) ?[]const u8 {
const extension = switch (builtin.os.tag) {
.windows => ".exe",
else => "",
};
return file_find_in_path(allocator, file_name, path_env, extension);
}
const CmakeBuildType = enum {
Debug,
RelWithDebInfo,
MinSizeRel,
Release,
fn from_zig_build_type(o: std.builtin.OptimizeMode) CmakeBuildType {
return switch (o) {
.Debug => .Debug,
.ReleaseSafe => .RelWithDebInfo,
.ReleaseSmall => .MinSizeRel,
.ReleaseFast => .Release,
};
}
};
var system_llvm: bool = undefined;
var target: std.Build.ResolvedTarget = undefined;
var optimize: std.builtin.OptimizeMode = undefined;
var env: std.process.EnvMap = undefined;
const BuildMode = enum {
debug_none,
debug_fast,
debug_size,
soft_optimize,
optimize_for_speed,
optimize_for_size,
aggressively_optimize_for_speed,
aggressively_optimize_for_size,
};
pub fn build(b: *std.Build) !void {
env = try std.process.getEnvMap(b.allocator);
target = b.standardTargetOptions(.{});
optimize = b.standardOptimizeOption(.{});
system_llvm = b.option(bool, "system_llvm", "Link against system LLVM libraries") orelse false;
const c_abi = b.addObject(.{
.name = "c_abi",
.link_libc = true,
.root_module = b.createModule(.{
.target = target,
.optimize = optimize,
.link_libc = true,
.sanitize_c = false,
}),
.optimize = optimize,
});
c_abi.addCSourceFiles(.{
.files = &.{"tests/c_abi.c"},
.flags = &.{"-g"},
});
const path = env.get("PATH") orelse unreachable;
const stack_trace_library = b.addObject(.{
.name = "stack_trace",
.root_module = b.createModule(.{
.target = target,
.optimize = .ReleaseFast,
.root_source_file = b.path("src/stack_trace.zig"),
.link_libc = true,
}),
});
const exe_mod = b.createModule(.{
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
.link_libc = true,
.sanitize_c = false,
});
const configuration = b.addOptions();
configuration.addOptionPath("c_abi_object_path", c_abi.getEmittedBin());
exe_mod.addOptions("configuration", configuration);
const exe = b.addExecutable(.{
.name = "bloat-buster",
.root_module = exe_mod,
.link_libc = true,
});
exe.addObject(stack_trace_library);
var llvm_libs = std.ArrayList([]const u8).init(b.allocator);
var flags = std.ArrayList([]const u8).init(b.allocator);
const llvm_config_path = if (b.option([]const u8, "llvm_prefix", "LLVM prefix")) |llvm_prefix| blk: {
const full_path = try std.mem.concat(b.allocator, u8, &.{ llvm_prefix, "/bin/llvm-config" });
const f = std.fs.cwd().openFile(full_path, .{}) catch return error.llvm_not_found;
f.close();
break :blk full_path;
} else if (system_llvm) executable_find_in_path(b.allocator, "llvm-config", path) orelse return error.llvm_not_found else blk: {
const home_env = switch (@import("builtin").os.tag) {
.windows => "USERPROFILE",
else => "HOME",
};
const home_path = env.get(home_env) orelse unreachable;
const is_ci = std.mem.eql(u8, (env.get("BB_CI") orelse "0"), "1");
const download_dir = try std.mem.concat(b.allocator, u8, &.{ home_path, "/Downloads" });
std.fs.makeDirAbsolute(download_dir) catch {};
const cmake_build_type = if (is_ci) CmakeBuildType.from_zig_build_type(optimize) else CmakeBuildType.Release;
const version_string = "20.1.2";
const llvm_base = try std.mem.concat(b.allocator, u8, &.{ "llvm_", version_string, "_", @tagName(target.result.cpu.arch), "-", @tagName(target.result.os.tag), "-", @tagName(cmake_build_type) });
const base = try std.mem.concat(b.allocator, u8, &.{ download_dir, "/", llvm_base });
const full_path = try std.mem.concat(b.allocator, u8, &.{ base, "/bin/llvm-config" });
const f = std.fs.cwd().openFile(full_path, .{}) catch {
const url = try std.mem.concat(b.allocator, u8, &.{ "https://github.com/birth-software/llvm/releases/download/v", version_string, "/", llvm_base, ".7z" });
var result = try std.process.Child.run(.{
.allocator = b.allocator,
.argv = &.{ "wget", "-P", download_dir, url },
.max_output_bytes = std.math.maxInt(usize),
});
var success = false;
switch (result.term) {
.Exited => |exit_code| {
success = exit_code == 0;
},
else => {},
}
if (!success) {
std.debug.print("{s}\n{s}\n", .{ result.stdout, result.stderr });
}
if (success) {
const file_7z = try std.mem.concat(b.allocator, u8, &.{ base, ".7z" });
result = try std.process.Child.run(.{
.allocator = b.allocator,
.argv = &.{ "7z", "x", try std.mem.concat(b.allocator, u8, &.{ "-o", download_dir }), file_7z },
.max_output_bytes = std.math.maxInt(usize),
});
success = false;
switch (result.term) {
.Exited => |exit_code| {
success = exit_code == 0;
},
else => {},
}
if (!success) {
std.debug.print("{s}\n{s}\n", .{ result.stdout, result.stderr });
}
break :blk full_path;
}
return error.llvm_not_found;
};
f.close();
break :blk full_path;
};
const llvm_components_result = try run_process_and_capture_stdout(b, &.{ llvm_config_path, "--components" });
var it = std.mem.splitScalar(u8, llvm_components_result, ' ');
{
var args = std.ArrayList([]const u8).init(b.allocator);
try args.append(llvm_config_path);
try args.append("--libs");
while (it.next()) |component| {
try args.append(std.mem.trimRight(u8, component, "\n"));
}
const llvm_libs_result = try run_process_and_capture_stdout(b, args.items);
it = std.mem.splitScalar(u8, llvm_libs_result, ' ');
}
while (it.next()) |lib| {
const llvm_lib = std.mem.trimLeft(u8, std.mem.trimRight(u8, lib, "\n"), "-l");
try llvm_libs.append(llvm_lib);
}
const llvm_cxx_flags_result = try run_process_and_capture_stdout(b, &.{ llvm_config_path, "--cxxflags" });
it = std.mem.splitScalar(u8, llvm_cxx_flags_result, ' ');
while (it.next()) |flag| {
const llvm_cxx_flag = std.mem.trimRight(u8, flag, "\n");
try flags.append(llvm_cxx_flag);
}
const llvm_lib_dir = std.mem.trimRight(u8, try run_process_and_capture_stdout(b, &.{ llvm_config_path, "--libdir" }), "\n");
if (optimize != .ReleaseSmall) {
try flags.append("-g");
}
try flags.append("-fno-rtti");
exe.addLibraryPath(.{ .cwd_relative = llvm_lib_dir });
const a = std.fs.cwd().openDir("/usr/lib/x86_64-linux-gnu/", .{});
if (a) |_| {
var dir = a catch unreachable;
dir.close();
exe.addLibraryPath(.{ .cwd_relative = "/usr/lib/x86_64-linux-gnu/" });
} else |err| {
err catch {};
}
exe.addCSourceFiles(.{
.files = &.{"src/llvm.cpp"},
.flags = flags.items,
});
var dir = try std.fs.cwd().openDir("/usr/include/c++", .{
.iterate = true,
});
var iterator = dir.iterate();
const gcc_version = while (try iterator.next()) |entry| {
if (entry.kind == .directory) {
break entry.name;
}
} else return error.include_cpp_dir_not_found;
dir.close();
const general_cpp_include_dir = try std.mem.concat(b.allocator, u8, &.{ "/usr/include/c++/", gcc_version });
exe.addIncludePath(.{ .cwd_relative = general_cpp_include_dir });
{
const arch_cpp_include_dir = try std.mem.concat(b.allocator, u8, &.{ general_cpp_include_dir, "/x86_64-pc-linux-gnu" });
const d2 = std.fs.cwd().openDir(arch_cpp_include_dir, .{});
if (d2) |_| {
var d = d2 catch unreachable;
d.close();
exe.addIncludePath(.{ .cwd_relative = arch_cpp_include_dir });
} else |err| err catch {};
}
{
const arch_cpp_include_dir = try std.mem.concat(b.allocator, u8, &.{ "/usr/include/x86_64-linux-gnu/c++/", gcc_version });
const d2 = std.fs.cwd().openDir(arch_cpp_include_dir, .{});
if (d2) |_| {
var d = d2 catch unreachable;
d.close();
exe.addIncludePath(.{ .cwd_relative = arch_cpp_include_dir });
} else |err| err catch {};
}
var found_libcpp = false;
if (std.fs.cwd().openFile("/usr/lib/libstdc++.so.6", .{})) |file| {
file.close();
found_libcpp = true;
exe.addObjectFile(.{ .cwd_relative = "/usr/lib/libstdc++.so.6" });
} else |err| {
err catch {};
}
if (std.fs.cwd().openFile("/usr/lib/x86_64-linux-gnu/libstdc++.so.6", .{})) |file| {
file.close();
found_libcpp = true;
exe.addObjectFile(.{ .cwd_relative = "/usr/lib/x86_64-linux-gnu/libstdc++.so.6" });
} else |err| {
err catch {};
}
if (!found_libcpp) {
return error.libcpp_not_found;
}
const needed_libraries: []const []const u8 = &.{ "unwind", "z", "zstd" };
for (needed_libraries) |lib| {
exe.linkSystemLibrary(lib);
}
for (llvm_libs.items) |lib| {
exe.linkSystemLibrary(lib);
}
const lld_libs: []const []const u8 = &.{ "lldCommon", "lldCOFF", "lldELF", "lldMachO", "lldMinGW", "lldWasm" };
for (lld_libs) |lib| {
exe.linkSystemLibrary(lib);
}
b.installArtifact(exe);
for ([_]bool{ false, true }) |is_test| {
const run_step_name = switch (is_test) {
true => "test",
false => "run",
};
const debug_step_name = switch (is_test) {
true => "debug_test",
false => "debug",
};
const command = b.addRunArtifact(exe);
command.step.dependOn(b.getInstallStep());
if (is_test) {
command.addArg("test");
}
if (b.args) |args| {
command.addArgs(args);
}
const run_step = b.step(run_step_name, "");
run_step.dependOn(&command.step);
const debug_command = std.Build.Step.Run.create(b, b.fmt("{s} {s}", .{ debug_step_name, exe.name }));
debug_command.addArg("gdb");
debug_command.addArg("-ex");
debug_command.addArg("r");
debug_command.addArg("--args");
debug_command.addArtifactArg(exe);
if (is_test) {
debug_command.addArg("test");
}
if (b.args) |args| {
debug_command.addArgs(args);
}
const debug_step = b.step(debug_step_name, "");
debug_step.dependOn(&debug_command.step);
}
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -1,261 +0,0 @@
[extern] memcmp = fn [cc(c)] (a: &u8, b: &u8, byte_count: u64) s32;
string_no_match = #integer_max(u64);
c_string_length = fn (c_string: &u8) u64
{
>it = c_string;
while (it.&)
{
it = it + 1;
}
return #int_from_pointer(it) - #int_from_pointer(c_string);
}
c_string_to_slice = fn (c_string: &u8) []u8
{
>length = c_string_length(c_string);
return c_string[0..length];
}
string_equal = fn(a: []u8, b: []u8) u1
{
>result: #ReturnType() = 0;
if (a.length == b.length)
{
result = memcmp(a.pointer, b.pointer, a.length) == 0;
}
return result;
}
string_last_character = fn(string: []u8, character: u8) u64
{
>i = string.length;
while (i > 0)
{
i -= 1;
if (string[i] == character)
{
return i;
}
}
return string_no_match;
}
OS_Linux_PROT = bits u32
{
read: u1,
write: u1,
execute: u1,
sem: u1,
_: u28,
}
OS_Linux_MAP_Type = enum u4
{
shared = 0x1,
private = 0x2,
shared_validate = 0x3,
}
OS_Linux_MAP = bits u32
{
type: OS_Linux_MAP_Type,
fixed: u1,
anonymous: u1,
bit_32: u1,
_: u1,
grows_down: u1,
_: u2,
deny_write: u1,
executable: u1,
locked: u1,
no_reserve: u1,
populate: u1,
non_block: u1,
stack: u1,
huge_tlb: u1,
sync: u1,
fixed_noreplace: u1,
_: u5,
uninitialized: u1,
_: u5,
}
[extern] mmap = fn [cc(c)] (address: u64, size: u64, protection: OS_Linux_PROT, map: OS_Linux_MAP, file_descriptor: s32, offset: s64) &u8;
[extern] mprotect = fn [cc(c)] (address: u64, size: u64, protection: OS_Linux_PROT) s32;
OS_ProtectionFlags = bits
{
read: u1,
write: u1,
execute: u1,
}
OS_MapFlags = bits
{
private: u1,
anonymous: u1,
no_reserve: u1,
populate: u1,
}
os_linux_protection_flags = fn(map_flags: OS_ProtectionFlags) OS_Linux_PROT
{
return {
.read = map_flags.read,
.write = map_flags.write,
.execute = map_flags.execute,
zero,
};
}
os_linux_map_flags = fn(map_flags: OS_MapFlags) OS_Linux_MAP
{
return {
.type = #select(map_flags.private, .private, .shared),
.anonymous = map_flags.anonymous,
.no_reserve = map_flags.no_reserve,
.populate = map_flags.populate,
zero,
};
}
os_reserve = fn (base: u64, size: u64, protection: OS_ProtectionFlags, map: OS_MapFlags) &u8
{
>protection_flags = os_linux_protection_flags(protection);
>map_flags = os_linux_map_flags(map);
>address = mmap(base, size, protection_flags, map_flags, -1, 0);
if (#int_from_pointer(address) == #integer_max(u64))
{
unreachable;
}
return address;
}
os_commit = fn (address: u64, size: u64, protection: OS_ProtectionFlags) void
{
>protection_flags = os_linux_protection_flags(protection);
>result = mprotect(address, size, protection_flags);
if (result != 0)
{
unreachable;
}
}
Arena = struct
{
reserved_size: u64,
position: u64,
os_position: u64,
granularity: u64,
reserved: [32]u8,
}
minimum_position: u64 = #byte_size(Arena);
ArenaInitialization = struct
{
reserved_size: u64,
granularity: u64,
initial_size: u64,
}
arena_initialize = fn (initialization: ArenaInitialization) &Arena
{
>protection_flags: OS_ProtectionFlags = {
.read = 1,
.write = 1,
zero,
};
>map_flags: OS_MapFlags = {
.private = 1,
.anonymous = 1,
.no_reserve = 1,
.populate = 0,
};
>arena: &Arena = #pointer_cast(os_reserve(0, initialization.reserved_size, protection_flags, map_flags));
os_commit(#int_from_pointer(arena), initialization.initial_size, {
.read = 1,
.write = 1,
zero,
});
arena.& = {
.reserved_size = initialization.reserved_size,
.position = minimum_position,
.os_position = initialization.initial_size,
.granularity = initialization.granularity,
zero,
};
return arena;
}
arena_initialize_default = fn (initial_size: u64) &Arena
{
return arena_initialize({
.reserved_size = 4 * 1024 * 1024 * 1024,
.granularity = 4 * 1024,
.initial_size = initial_size,
});
}
GlobalState = struct
{
arena: &Arena,
}
global_state: GlobalState = undefined;
global_state_initialize = fn () void
{
global_state = {
.arena = arena_initialize_default(2 * 1024 * 1024),
};
}
[export] main = fn [cc(c)] (argument_count: u32, argv: &&u8) s32
{
if (argument_count != 2)
{
return 1;
}
>relative_file_path_pointer = argv[1];
if (!relative_file_path_pointer)
{
return 1;
}
>relative_file_path = c_string_to_slice(relative_file_path_pointer);
if (relative_file_path.length < 5)
{
return 1;
}
>extension_start = string_last_character(relative_file_path, '.');
if (extension_start == string_no_match)
{
return 1;
}
if (!string_equal(relative_file_path[extension_start..], ".bbb"))
{
return 1;
}
global_state_initialize();
return 0;
}

File diff suppressed because it is too large Load Diff

@ -1,457 +0,0 @@
const lib = @import("lib.zig");
const Arena = lib.Arena;
const assert = lib.assert;
const std = @import("std");
const configuration = @import("configuration");
const converter = @import("converter.zig");
const BuildMode = converter.BuildMode;
fn invoke(name: []const u8) !void {
if (!lib.GlobalState.initialized) {
lib.GlobalState.initialize();
}
comptime assert(lib.is_test);
const allocator = std.testing.allocator;
const arena = lib.global.arena;
const arena_position = arena.position;
defer arena.restore(arena_position);
const c_abi_object_path = arena.duplicate_string(configuration.c_abi_object_path);
const file_path = arena.join_string(&.{ "tests/", name, ".bbb" });
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
const build_mode = @field(BuildMode, f.name);
inline for ([2]bool{ true, false }) |has_debug_info| {
// Bootstrap
{
var tmp_dir = std.testing.tmpDir(.{});
defer tmp_dir.cleanup();
const base_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
const executable_path = base_path;
const directory_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
const object_path = arena.join_string(&.{ base_path, ".o" });
try unit_test(arena, allocator, .{
.object_paths = if (lib.string.equal(name, "c_abi")) &.{ object_path, c_abi_object_path } else &.{object_path},
.executable_path = executable_path,
.file_path = file_path,
.name = name,
.directory_path = directory_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.self_hosted_path = null,
.run = true,
});
}
// Self-hosted
{
var tmp_dir = std.testing.tmpDir(.{});
defer tmp_dir.cleanup();
const base_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path, "/", name });
const executable_path = base_path;
const directory_path = arena.join_string(&.{ ".zig-cache/tmp/", &tmp_dir.sub_path });
const object_path = arena.join_string(&.{ base_path, ".o" });
try unit_test(arena, allocator, .{
.object_paths = if (lib.string.equal(name, "c_abi")) &.{ object_path, c_abi_object_path } else &.{object_path},
.executable_path = executable_path,
.file_path = file_path,
.name = name,
.directory_path = directory_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.self_hosted_path = arena.join_string(&.{ "bb-cache/", compiler_basename(arena, build_mode, has_debug_info) }),
.run = true,
});
}
}
}
}
fn compiler_basename(arena: *Arena, build_mode: BuildMode, has_debug_info: bool) [:0]const u8 {
return arena.join_string(&.{ "compiler_", @tagName(build_mode), if (has_debug_info) "_di" else "_nodi" });
}
var compiler_compiled = false;
fn compile_the_compiler() !void {
if (!compiler_compiled) {
defer compiler_compiled = true;
if (!lib.GlobalState.initialized) {
lib.GlobalState.initialize();
}
comptime assert(lib.is_test);
const allocator = std.testing.allocator;
const arena = lib.global.arena;
const arena_position = arena.position;
defer arena.restore(arena_position);
inline for (@typeInfo(BuildMode).@"enum".fields) |f| {
const build_mode = @field(BuildMode, f.name);
inline for ([2]bool{ false, true }) |has_debug_info| {
var tmp_dir = std.testing.tmpDir(.{});
defer tmp_dir.cleanup();
const base_path = arena.join_string(&.{ "bb-cache/", compiler_basename(arena, build_mode, has_debug_info) });
const executable_path = base_path;
const directory_path = "bb-cache";
const object_path = arena.join_string(&.{ base_path, ".o" });
try unit_test(arena, allocator, .{
.object_paths = &.{object_path},
.executable_path = executable_path,
.file_path = arena.join_string(&.{"src/compiler.bbb"}),
.name = "compiler",
.directory_path = directory_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.self_hosted_path = null,
.run = false,
});
}
}
}
}
const InvokeWrapper = struct {
executable_path: [:0]const u8,
object_paths: []const [:0]const u8,
file_path: [:0]const u8,
name: []const u8,
build_mode: BuildMode,
has_debug_info: bool,
directory_path: [:0]const u8,
self_hosted_path: ?[]const u8,
run: bool,
};
fn unit_test(arena: *Arena, allocator: std.mem.Allocator, options: InvokeWrapper) anyerror!void {
const position = arena.position;
defer arena.restore(position);
const file_content = lib.file.read(arena, options.file_path);
if (options.self_hosted_path) |self_hosted_path| {
try compile_the_compiler();
const argv = [_][]const u8{
self_hosted_path,
options.file_path,
};
const run_result = try std.process.Child.run(.{
.allocator = allocator,
.argv = &argv,
});
const success = switch (run_result.term) {
.Exited => |exit_code| exit_code == 0,
else => false,
};
if (!success) {
std.debug.print("{s}\n{}\n{}\n", .{ argv, run_result, options });
return error.compiler_failed_to_run_successfully;
}
} else {
converter.convert(arena, .{
.path = options.file_path,
.content = file_content,
.objects = options.object_paths,
.executable = options.executable_path,
.build_mode = options.build_mode,
.name = options.name,
.has_debug_info = options.has_debug_info,
.target = converter.Target.get_native(),
});
if (options.run) {
const argv = [_][]const u8{options.executable_path};
const run_result = std.process.Child.run(.{
.allocator = allocator,
.argv = &argv,
}) catch |err| {
std.debug.print("error: {}\n", .{err});
const r = try std.process.Child.run(.{
.allocator = allocator,
.argv = &.{ "/usr/bin/ls", "-lasR", options.directory_path },
.max_output_bytes = std.math.maxInt(usize),
});
defer allocator.free(r.stdout);
defer allocator.free(r.stderr);
std.debug.print("ls {s} {s}\n", .{ options.directory_path, r.stdout });
return err;
};
const success = switch (run_result.term) {
.Exited => |exit_code| exit_code == 0,
else => false,
};
if (!success) {
std.debug.print("{s} {}\n{}\n", .{ argv, run_result, options });
return error.executable_failed_to_run_successfully;
}
}
}
}
fn invsrc(src: std.builtin.SourceLocation) !void {
try invoke(src.fn_name[std.mem.lastIndexOfScalar(u8, src.fn_name, '.').? + 1 ..]);
}
test "minimal" {
try invsrc(@src());
}
test "constant_add" {
try invsrc(@src());
}
test "constant_sub" {
try invsrc(@src());
}
test "constant_mul" {
try invsrc(@src());
}
test "constant_div" {
try invsrc(@src());
}
test "constant_rem" {
try invsrc(@src());
}
test "constant_shift_left" {
try invsrc(@src());
}
test "constant_shift_right" {
try invsrc(@src());
}
test "constant_and" {
try invsrc(@src());
}
test "constant_or" {
try invsrc(@src());
}
test "constant_xor" {
try invsrc(@src());
}
test "minimal_stack" {
try invsrc(@src());
}
test "stack_add" {
try invsrc(@src());
}
test "stack_sub" {
try invsrc(@src());
}
test "global" {
try invsrc(@src());
}
test "simple_branch" {
try invsrc(@src());
}
test "basic_call" {
try invsrc(@src());
}
test "struct" {
try invsrc(@src());
}
test "extend" {
try invsrc(@src());
}
test "bits" {
try invsrc(@src());
}
test "basic_array" {
try invsrc(@src());
}
test "extern" {
try invsrc(@src());
}
test "pointer" {
try invsrc(@src());
}
test "if_no_else" {
try invsrc(@src());
}
test "comments" {
try invsrc(@src());
}
test "local_type_inference" {
try invsrc(@src());
}
test "if_no_else_void" {
try invsrc(@src());
}
test "c_abi0" {
try invsrc(@src());
}
test "c_abi1" {
try invsrc(@src());
}
test "return_u64_u64" {
try invsrc(@src());
}
test "struct_u64_u64" {
try invsrc(@src());
}
test "ret_c_bool" {
try invsrc(@src());
}
test "c_split_struct_ints" {
try invsrc(@src());
}
test "c_ret_struct_array" {
try invsrc(@src());
}
test "function_pointer" {
try invsrc(@src());
}
test "c_struct_with_array" {
try invsrc(@src());
}
test "indirect" {
try invsrc(@src());
}
test "indirect_struct" {
try invsrc(@src());
}
test "u1_return" {
try invsrc(@src());
}
test "small_struct_ints" {
try invsrc(@src());
}
test "c_med_struct_ints" {
try invsrc(@src());
}
test "c_abi" {
try invsrc(@src());
}
test "basic_varargs" {
try invsrc(@src());
}
test "struct_varargs" {
try invsrc(@src());
}
test "indirect_varargs" {
try invsrc(@src());
}
test "varargs" {
try invsrc(@src());
}
test "byte_size" {
try invsrc(@src());
}
test "bits_no_backing_type" {
try invsrc(@src());
}
test "basic_enum" {
try invsrc(@src());
}
test "return_type_builtin" {
try invsrc(@src());
}
test "bits_zero" {
try invsrc(@src());
}
test "struct_zero" {
try invsrc(@src());
}
test "select" {
try invsrc(@src());
}
test "bits_return_u1" {
try invsrc(@src());
}
test "integer_max" {
try invsrc(@src());
}
test "unreachable" {
try invsrc(@src());
}
test "pointer_cast" {
try invsrc(@src());
}
test "struct_assignment" {
try invsrc(@src());
}
test "global_struct" {
try invsrc(@src());
}
test "basic_slice" {
try invsrc(@src());
}
test "basic_string" {
try invsrc(@src());
}
test "argv" {
try invsrc(@src());
}
test "basic_while" {
try invsrc(@src());
}
test "c_string_to_slice" {
try invsrc(@src());
}
test "assignment_operators" {
try invsrc(@src());
}

File diff suppressed because it is too large Load Diff

@ -1,44 +0,0 @@
const lib = @import("lib.zig");
test "value_from_flag" {
const std = @import("std");
const expect = std.testing.expect;
const value_from_flag = lib.value_from_flag;
try expect(value_from_flag(1, 1) == 1);
try expect(value_from_flag(2, true) == 2);
try expect(value_from_flag(3, false) == 0);
try expect(value_from_flag(3, true) == 3);
try expect(value_from_flag(3, 1) == 3);
try expect(value_from_flag(0xffff, 1) == 0xffff);
try expect(value_from_flag(0xffff, 0) == 0);
try expect(value_from_flag(0xffff, true) == 0xffff);
try expect(value_from_flag(0xffff, false) == 0);
try expect(value_from_flag(0xffffffff, 1) == 0xffffffff);
try expect(value_from_flag(0xffffffff, 0) == 0);
try expect(value_from_flag(0xffffffff, true) == 0xffffffff);
try expect(value_from_flag(0xffffffff, false) == 0);
try expect(value_from_flag(0xffffffffffffffff, 1) == 0xffffffffffffffff);
try expect(value_from_flag(0xffffffffffffffff, 0) == 0);
try expect(value_from_flag(0xffffffffffffffff, true) == 0xffffffffffffffff);
try expect(value_from_flag(0xffffffffffffffff, false) == 0);
const a: u32 = 1235;
const b_true: bool = true;
const b_false: bool = false;
const u_true: u1 = 1;
const u_false: u1 = 0;
try expect(value_from_flag(a, b_true) == a);
try expect(value_from_flag(a, b_false) == 0);
try expect(value_from_flag(a, u_true) == a);
try expect(value_from_flag(a, u_false) == 0);
const b: u64 = 0xffffffffffffffff;
try expect(value_from_flag(b, b_true) == b);
try expect(value_from_flag(b, b_false) == 0);
try expect(value_from_flag(b, u_true) == b);
try expect(value_from_flag(b, u_false) == 0);
}

File diff suppressed because it is too large Load Diff

@ -1,288 +0,0 @@
const llvm = @import("LLVM.zig");
const lld = llvm.lld;
const Bool = c_int;
pub extern fn llvm_context_create_module(context: *llvm.Context, name: llvm.String) *llvm.Module;
pub extern fn LLVMContextCreate() *llvm.Context;
pub extern fn LLVMCreateBuilderInContext(context: *llvm.Context) *llvm.Builder;
pub extern fn LLVMGetOperand(value: *llvm.Value, index: c_uint) *llvm.Value;
pub extern fn LLVMSetAlignment(value: *llvm.Value, alignment: c_uint) void;
pub extern fn llvm_instruction_is_call_base(instruction: *llvm.Instruction) bool;
// Module
pub extern fn llvm_module_create_global_variable(module: *llvm.Module, global_type: *llvm.Type, is_constant: bool, linkage: llvm.LinkageType, initial_value: *llvm.Constant, name: llvm.String, before: ?*llvm.GlobalVariable, thread_local_mode: llvm.ThreadLocalMode, address_space: c_uint, externally_initialized: bool) *llvm.GlobalVariable;
pub extern fn LLVMSetUnnamedAddress(global: *llvm.GlobalVariable, unnamed_address: llvm.GlobalVariable.UnnamedAddress) void;
pub extern fn llvm_module_create_function(module: *llvm.Module, function_type: *llvm.Type.Function, linkage_type: llvm.LinkageType, address_space: c_uint, name: llvm.String) *llvm.Function;
pub extern fn llvm_context_create_basic_block(context: *llvm.Context, name: llvm.String, parent: ?*llvm.Function) *llvm.BasicBlock;
pub extern fn LLVMGetNextBasicBlock(basic_block: *llvm.BasicBlock) ?*llvm.BasicBlock;
pub extern fn LLVMDeleteBasicBlock(basic_block: *llvm.BasicBlock) void;
pub extern fn LLVMGetLastBasicBlock(function: *llvm.Function) *llvm.BasicBlock;
pub extern fn LLVMGetBasicBlockParent(basic_block: *llvm.BasicBlock) ?*llvm.BasicBlock;
pub extern fn LLVMAppendExistingBasicBlock(function: *llvm.Function, basic_block: *llvm.BasicBlock) void;
pub extern fn LLVMInsertExistingBasicBlockAfterInsertBlock(builder: *llvm.Builder, basic_block: *llvm.BasicBlock) void;
pub extern fn LLVMSetValueName2(value: *llvm.Value, name_pointer: [*]const u8, name_length: usize) void;
pub extern fn llvm_value_use_empty(value: *llvm.Value) bool;
pub extern fn llvm_value_has_one_use(value: *llvm.Value) bool;
pub extern fn llvm_value_to_branch(value: ?*llvm.Value) ?*llvm.Instruction.Branch;
pub extern fn LLVMReplaceAllUsesWith(old: *llvm.Value, new: *llvm.Value) void;
pub extern fn LLVMGetSuccessor(branch: *llvm.Instruction.Branch, index: c_uint) *llvm.BasicBlock;
pub extern fn LLVMIsConditional(branch: *llvm.Instruction.Branch) bool;
pub extern fn LLVMGetInstructionParent(instruction: *llvm.Instruction) *llvm.BasicBlock;
pub extern fn llvm_basic_block_is_empty(basic_block: *llvm.BasicBlock) bool;
pub extern fn llvm_basic_block_user_begin(basic_block: *llvm.BasicBlock) ?*llvm.Value;
pub extern fn llvm_basic_block_delete(basic_block: *llvm.BasicBlock) void;
pub extern fn LLVMGetBasicBlockTerminator(basic_block: *llvm.BasicBlock) ?*llvm.Value;
pub extern fn LLVMSetFunctionCallConv(function: *llvm.Function, calling_convention: llvm.CallingConvention) void;
pub extern fn LLVMGetFunctionCallConv(function: *llvm.Function) llvm.CallingConvention;
pub extern fn LLVMSetInstructionCallConv(instruction: *llvm.Instruction.CallBase, calling_convention: llvm.CallingConvention) void;
pub extern fn LLVMGetParams(function: *llvm.Function, argument_buffer: [*]*llvm.Argument) void;
pub extern fn llvm_function_to_string(function: *llvm.Function) llvm.String;
pub extern fn llvm_function_verify(function: *llvm.Function, error_message: *llvm.String) bool;
pub extern fn llvm_module_verify(module: *llvm.Module, error_message: *llvm.String) bool;
pub extern fn llvm_module_to_string(module: *llvm.Module) llvm.String;
// Builder API
pub extern fn LLVMPositionBuilderAtEnd(builder: *llvm.Builder, basic_block: *llvm.BasicBlock) void;
pub extern fn LLVMClearInsertionPosition(builder: *llvm.Builder) void;
pub extern fn LLVMGetInsertBlock(builder: *llvm.Builder) ?*llvm.BasicBlock;
pub extern fn llvm_find_return_value_dominating_store(builder: *llvm.Builder, return_alloca: *llvm.Value, element_type: *llvm.Type) ?*llvm.Instruction.Store;
pub extern fn LLVMDeleteInstruction(instruction: *llvm.Instruction) void;
pub extern fn LLVMInstructionEraseFromParent(instruction: *llvm.Instruction) void;
pub extern fn LLVMBuildRet(builder: *llvm.Builder, value: ?*llvm.Value) void;
pub extern fn LLVMBuildAdd(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildSub(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildMul(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildSDiv(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildUDiv(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildSRem(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildURem(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildShl(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildAShr(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildLShr(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildAnd(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildOr(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildXor(builder: *llvm.Builder, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildICmp(builder: *llvm.Builder, predicate: llvm.IntPredicate, left: *llvm.Value, right: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildBr(builder: *llvm.Builder, block: *llvm.BasicBlock) *llvm.Value;
pub extern fn LLVMBuildCondBr(builder: *llvm.Builder, condition: *llvm.Value, taken: *llvm.BasicBlock, not_taken: *llvm.BasicBlock) *llvm.Value;
pub extern fn LLVMBuildNeg(builder: *llvm.Builder, value: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildNot(builder: *llvm.Builder, value: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn llvm_builder_create_alloca(builder: *llvm.Builder, ty: *llvm.Type, address_space: c_uint, name: llvm.String) *llvm.Value;
pub extern fn LLVMBuildStore(builder: *llvm.Builder, value: *llvm.Value, pointer: *llvm.Value) *llvm.Value;
pub extern fn LLVMBuildLoad2(builder: *llvm.Builder, ty: *llvm.Type, pointer: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildCall2(builder: *llvm.Builder, ty: *llvm.Type.Function, pointer: *llvm.Value, argument_pointer: [*]const *llvm.Value, argument_count: c_uint, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildStructGEP2(builder: *llvm.Builder, struct_type: *llvm.Type.Struct, pointer: *llvm.Value, index: c_uint, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildGEP2(builder: *llvm.Builder, ty: *llvm.Type, aggregate: *llvm.Value, index_pointer: [*]const *llvm.Value, index_count: c_uint, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildInBoundsGEP2(builder: *llvm.Builder, ty: *llvm.Type, aggregate: *llvm.Value, index_pointer: [*]const *llvm.Value, index_count: c_uint, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildInsertValue(builder: *llvm.Builder, aggregate: *llvm.Value, element: *llvm.Value, index: c_uint, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildExtractValue(builder: *llvm.Builder, aggregate: *llvm.Value, index: c_uint, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildUnreachable(builder: *llvm.Builder) *llvm.Value;
pub extern fn LLVMBuildMemCpy(builder: *llvm.Builder, destination: *llvm.Value, destination_alignment: c_uint, source: *llvm.Value, source_alignment: c_uint, size: *llvm.Value) *llvm.Value;
pub extern fn LLVMBuildMemSet(builder: *llvm.Builder, pointer: *llvm.Value, value: *llvm.Value, value_count: *llvm.Value, alignment: c_uint) *llvm.Value;
pub extern fn LLVMBuildPhi(builder: *llvm.Builder, ty: *llvm.Type, name: [*:0]const u8) *llvm.Instruction.Phi;
pub extern fn LLVMAddIncoming(phi: *llvm.Instruction.Phi, incoming_value_pointer: [*]const *llvm.Value, incoming_basic_block_pointer: [*]const *llvm.BasicBlock, incoming_count: c_uint) void;
pub extern fn LLVMBuildSelect(builder: *llvm.Builder, condition: *llvm.Value, true_value: *llvm.Value, false_value: *llvm.Value, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildVAArg(builder: *llvm.Builder, va_list: *llvm.Value, arg_type: *llvm.Type, name: [*:0]const u8) *llvm.Value;
// Casts
pub extern fn LLVMBuildZExt(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildSExt(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildIntToPtr(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildPtrToInt(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildPointerCast(builder: *llvm.Builder, value: *llvm.Value, ty: *llvm.Type, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMBuildTrunc(builder: *llvm.Builder, value: *llvm.Value, destination_type: *llvm.Type, name: [*:0]const u8) *llvm.Value;
pub extern fn LLVMSetCurrentDebugLocation2(builder: *llvm.Builder, location: ?*llvm.DI.Location) void;
pub extern fn LLVMTypeOf(value: *llvm.Value) *llvm.Type;
pub extern fn LLVMSizeOf(ty: *llvm.Type) *llvm.Constant;
pub extern fn LLVMAlignOf(ty: *llvm.Type) *llvm.Constant;
pub extern fn LLVMGlobalGetValueType(value: *llvm.GlobalValue) *llvm.Type;
pub extern fn LLVMGetInitializer(global_variable: *llvm.GlobalVariable) *llvm.Constant;
pub extern fn LLVMSetInitializer(global_variable: *llvm.GlobalVariable, initializer: *llvm.Constant) void;
pub extern fn LLVMDeleteGlobal(global_variable: *llvm.GlobalVariable) void;
pub extern fn llvm_global_variable_delete(global_variable: *llvm.GlobalVariable) void;
pub extern fn llvm_value_is_instruction(value: *llvm.Value) bool;
// Intrinsics
pub extern fn LLVMLookupIntrinsicID(name_pointer: [*]const u8, name_length: usize) llvm.Intrinsic.Id;
pub extern fn LLVMGetIntrinsicDeclaration(module: *llvm.Module, intrinsic_id: llvm.Intrinsic.Id, parameter_type_pointer: [*]const *llvm.Type, parameter_type_count: usize) *llvm.Value;
pub extern fn LLVMIntrinsicGetType(context: *llvm.Context, intrinsic_id: llvm.Intrinsic.Id, parameter_type_pointer: [*]const *llvm.Type, parameter_type_count: usize) *llvm.Type.Function;
// Attributes
pub extern fn llvm_attribute_list_build(context: *llvm.Context, options: *const llvm.Attribute.List.Options, call_site: bool) *llvm.Attribute.List;
pub extern fn llvm_function_set_attributes(function: *llvm.Function, attribute_list: *llvm.Attribute.List) void;
pub extern fn llvm_call_base_set_attributes(function: *llvm.Instruction.CallBase, attribute_list: *llvm.Attribute.List) void;
// pub extern fn LLVMGetEnumAttributeKindForName(name_pointer: [*]const u8, name_length: usize) llvm.Attribute.Kind;
//
// pub extern fn LLVMCreateEnumAttribute(context: *llvm.Context, kind: llvm.Attribute.Kind, value: u64) *llvm.Attribute;
// pub extern fn LLVMCreateTypeAttribute(context: *llvm.Context, kind: llvm.Attribute.Kind, ty: *llvm.Type) *llvm.Attribute;
// pub extern fn LLVMCreateConstantRangeAttribute(context: *llvm.Context, kind: llvm.Attribute.Kind, bit_count: c_uint, lower_words: [*]const u64, upper_words: [*]const u64) *llvm.Attribute;
// pub extern fn LLVMCreateStringAttribute(context: *llvm.Context, key_pointer: [*]const u8, key_length: c_uint, value_pointer: [*]const u8, value_length: usize) *llvm.Attribute;
//
// pub extern fn LLVMAddAttributeAtIndex(function: *llvm.Function, attribute_index: llvm.Attribute.Index, attribute: *llvm.Attribute) void;
// pub extern fn LLVMAddCallSiteAttribute(call: *llvm.Instruction.Call, attribute_index: llvm.Attribute.Index, attribute: *llvm.Attribute) void;
// TYPES
// Types: integers
pub extern fn LLVMVoidTypeInContext(context: *llvm.Context) *llvm.Type;
pub extern fn LLVMInt1TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
pub extern fn LLVMInt8TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
pub extern fn LLVMInt16TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
pub extern fn LLVMInt32TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
pub extern fn LLVMInt64TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
pub extern fn LLVMInt128TypeInContext(context: *llvm.Context) *llvm.Type.Integer;
pub extern fn LLVMIntTypeInContext(context: *llvm.Context, bit_count: c_uint) *llvm.Type.Integer;
// Types: floating point
pub extern fn LLVMHalfTypeInContext(context: *llvm.Context) *llvm.Type;
pub extern fn LLVMBFloatTypeInContext(context: *llvm.Context) *llvm.Type;
pub extern fn LLVMFloatTypeInContext(context: *llvm.Context) *llvm.Type;
pub extern fn LLVMDoubleTypeInContext(context: *llvm.Context) *llvm.Type;
pub extern fn LLVMFP128TypeInContext(context: *llvm.Context) *llvm.Type;
// Types: functions
pub extern fn LLVMFunctionType(return_type: *llvm.Type, parameter_type_pointer: [*]const *llvm.Type, parameter_type_count: c_uint, is_var_arg: Bool) *llvm.Type.Function;
pub extern fn LLVMIsFunctionVarArg(function_type: *llvm.Type.Function) Bool;
pub extern fn LLVMGetReturnType(function_type: *llvm.Type.Function) *llvm.Type;
pub extern fn LLVMSetSubprogram(function: *llvm.Function, subprogram: *llvm.DI.Subprogram) void;
pub extern fn LLVMGetSubprogram(function: *llvm.Function) ?*llvm.DI.Subprogram;
pub extern fn LLVMCountParamTypes(function_type: *llvm.Type.Function) c_uint;
pub extern fn LLVMGetParamTypes(function_type: *llvm.Type.Function, types: [*]*llvm.Type) void;
// Types: struct
pub extern fn LLVMStructSetBody(struct_type: *llvm.Type.Struct, element_type_pointer: [*]const *llvm.Type, element_type_count: c_uint, is_packed: Bool) void;
pub extern fn llvm_context_create_forward_declared_struct_type(context: *llvm.Context, name: llvm.String) *llvm.Type.Struct;
pub extern fn llvm_context_create_struct_type(context: *llvm.Context, element_types_pointer: [*]const *llvm.Type, element_type_count: usize, name: llvm.String, is_packed: bool) *llvm.Type.Struct;
pub extern fn llvm_context_get_struct_type(context: *llvm.Context, element_types_pointer: [*]const *llvm.Type, element_type_count: usize, is_packed: bool) *llvm.Type.Struct;
// Types: arrays
pub extern fn LLVMArrayType2(element_type: *llvm.Type, element_count: u64) *llvm.Type.Array;
// Types: pointers
pub extern fn LLVMPointerTypeInContext(context: *llvm.Context, address_space: c_uint) *llvm.Type.Pointer;
// Types: vectors
pub extern fn LLVMVectorType(element_type: *llvm.Type, element_count: c_uint) *llvm.Type.FixedVector;
pub extern fn LLVMScalableVectorType(element_type: *llvm.Type, element_count: c_uint) *llvm.Type.ScalableVector;
pub extern fn LLVMGetTypeKind(ty: *llvm.Type) llvm.Type.Kind;
pub extern fn llvm_integer_type_get_bit_count(integer_type: *llvm.Type.Integer) c_uint;
// VALUES
pub extern fn LLVMGetPoison(type: *llvm.Type) *llvm.Value;
pub extern fn LLVMConstNeg(constant: *llvm.Constant) *llvm.Constant;
pub extern fn LLVMConstNull(type: *llvm.Type) *llvm.Constant;
pub extern fn LLVMConstInt(type: *llvm.Type.Integer, value: c_ulonglong, sign_extend: Bool) *llvm.Constant.Integer;
pub extern fn LLVMConstIntGetZExtValue(constant: *llvm.Constant) u64;
pub extern fn LLVMConstIntGetSExtValue(constant: *llvm.Constant) i64;
pub extern fn LLVMConstArray2(element_type: *llvm.Type, value_pointer: [*]const *llvm.Constant, value_length: u64) *llvm.Constant;
pub extern fn LLVMConstStructInContext(context: *llvm.Context, constant_value_pointer: [*]const *llvm.Constant, constant_value_count: c_uint, is_packed: c_uint) *llvm.Constant;
pub extern fn LLVMConstNamedStruct(struct_type: *llvm.Type.Struct, constant_value_pointer: [*]const *llvm.Constant, constant_value_count: c_uint) *llvm.Constant;
pub extern fn LLVMConstStringInContext2(context: *llvm.Context, string_pointer: [*]const u8, string_length: usize, dont_null_terminate: Bool) *llvm.Constant;
pub extern fn LLVMGetValueKind(value: *llvm.Value) llvm.Value.Kind;
pub extern fn LLVMIsConstant(value: *llvm.Value) Bool;
// Debug info API
pub extern fn LLVMCreateDIBuilder(module: *llvm.Module) *llvm.DI.Builder;
pub extern fn LLVMDIBuilderFinalize(builder: *llvm.DI.Builder) void;
pub extern fn LLVMDIBuilderCreateFile(builder: *llvm.DI.Builder, file_name: llvm.String, directory_name: llvm.String) *llvm.DI.File;
pub extern fn LLVMDIBuilderCreateCompileUnit(builder: *llvm.DI.Builder, language: llvm.Dwarf.SourceLanguage, file: *llvm.DI.File, producer_name: llvm.String, optimized: Bool, flags: llvm.String, runtime_version: c_uint, split_name: llvm.String, dwarf_emission_kind: llvm.Dwarf.EmissionKind, debug_with_offset_id: c_uint, split_debug_inlining: Bool, debug_info_for_profiling: Bool, sysroot: llvm.String, sdk: llvm.String) *llvm.DI.CompileUnit;
pub extern fn LLVMDIBuilderCreateSubroutineType(builder: *llvm.DI.Builder, file: *llvm.DI.File, parameter_type_pointer: [*]const *llvm.DI.Type, parameter_type_count: c_uint, flags: llvm.DI.Flags) *llvm.DI.Type.Subroutine;
pub extern fn LLVMDIBuilderCreateFunction(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name: llvm.String, linkage_name: llvm.String, file: *llvm.DI.File, line_number: c_uint, type: *llvm.DI.Type.Subroutine, local_to_unit: Bool, is_definition: Bool, scope_line: c_uint, flags: llvm.DI.Flags, is_optimized: Bool) *llvm.DI.Subprogram;
pub extern fn LLVMDIBuilderFinalizeSubprogram(builder: *llvm.DI.Builder, subprogram: *llvm.DI.Subprogram) void;
pub extern fn LLVMDIBuilderCreateExpression(builder: *llvm.DI.Builder, address: ?[*]const u64, length: u64) *llvm.DI.Expression;
pub extern fn LLVMDIBuilderCreateDebugLocation(context: *llvm.Context, line: c_uint, column: c_uint, scope: *llvm.DI.Scope, inlined_at: ?*llvm.DI.Metadata) *llvm.DI.Location;
pub extern fn LLVMDIBuilderCreateBasicType(builder: *llvm.DI.Builder, name_pointer: [*]const u8, name_length: usize, bit_count: u64, dwarf_type: llvm.Dwarf.Type, flags: llvm.DI.Flags) *llvm.DI.Type;
pub extern fn LLVMDIBuilderCreateAutoVariable(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, type: *llvm.DI.Type, always_preserve: Bool, flags: llvm.DI.Flags, align_in_bits: u32) *llvm.DI.LocalVariable;
pub extern fn LLVMDIBuilderInsertDeclareRecordAtEnd(builder: *llvm.DI.Builder, storage: *llvm.Value, local_variable: *llvm.DI.LocalVariable, expression: *llvm.DI.Expression, debug_location: *llvm.DI.Location, basic_block: *llvm.BasicBlock) *llvm.DI.Record;
pub extern fn LLVMDIBuilderCreateParameterVariable(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, argument_number: c_uint, file: *llvm.DI.File, line: c_uint, type: *llvm.DI.Type, always_preserve: Bool, flags: llvm.DI.Flags) *llvm.DI.LocalVariable;
pub extern fn LLVMDIBuilderCreateGlobalVariableExpression(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, linkage_name_pointer: [*]const u8, linkage_name_length: usize, file: *llvm.DI.File, line: c_uint, global_type: *llvm.DI.Type, local_to_unit: Bool, expression: *llvm.DI.Expression, declaration: ?*llvm.DI.Metadata, align_in_bits: u32) *llvm.DI.GlobalVariableExpression;
pub extern fn llvm_global_variable_add_debug_info(global_variable: *llvm.GlobalVariable, debug_global_variable: *llvm.DI.GlobalVariableExpression) void;
pub extern fn LLVMDIBuilderCreateLexicalBlock(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, file: *llvm.DI.File, line: c_uint, column: c_uint) *llvm.DI.LexicalBlock;
pub extern fn LLVMDIBuilderCreateReplaceableCompositeType(builder: *llvm.DI.Builder, tag: c_uint, name_pointer: [*]const u8, name_length: usize, scope: *llvm.DI.Scope, file: *llvm.DI.File, line: c_uint, runtime_language: c_uint, bit_size: u64, align_in_bits: u32, flags: llvm.DI.Flags, unique_identifier_pointer: ?[*]const u8, unique_identifier_length: usize) *llvm.DI.Type.Composite;
pub extern fn LLVMDIBuilderCreateArrayType(builder: *llvm.DI.Builder, element_count: u64, align_in_bits: u32, element_type: *llvm.DI.Type, subscript_pointer: ?[*]const *llvm.DI.Metadata, subscript_count: c_uint) *llvm.DI.Type.Composite;
pub extern fn LLVMDIBuilderCreateStructType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, flags: llvm.DI.Flags, derived_from: ?*llvm.DI.Type, member_pointer: [*]const *llvm.DI.Type.Derived, member_length: c_uint, runtime_language: c_uint, vtable_holder: ?*llvm.DI.Metadata, unique_id_pointer: ?[*]const u8, unique_id_length: usize) *llvm.DI.Type.Composite;
pub extern fn LLVMDIBuilderCreateMemberType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, bit_offset: u64, flags: llvm.DI.Flags, member_type: *llvm.DI.Type) *llvm.DI.Type.Derived;
pub extern fn LLVMDIBuilderCreateBitFieldMemberType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, bit_offset: u64, bit_storage_offset: u64, flags: llvm.DI.Flags, member_type: *llvm.DI.Type) *llvm.DI.Type.Derived;
pub extern fn LLVMDIBuilderCreatePointerType(builder: *llvm.DI.Builder, element_type: *llvm.DI.Type, bit_size: u64, align_in_bits: u32, address_space: c_uint, name_pointer: [*]const u8, name_length: usize) *llvm.DI.Type.Derived;
pub extern fn LLVMDIBuilderCreateEnumerator(builder: *llvm.DI.Builder, name_pointer: [*]const u8, name_length: usize, value: i64, is_unsigned: Bool) *llvm.DI.Enumerator;
pub extern fn LLVMDIBuilderCreateEnumerationType(builder: *llvm.DI.Builder, scope: *llvm.DI.Scope, name_pointer: [*]const u8, name_length: usize, file: *llvm.DI.File, line: c_uint, bit_size: u64, align_in_bits: u32, enumerator_pointer: [*]const *llvm.DI.Enumerator, enumerator_count: c_uint, backing_type: *llvm.DI.Type) *llvm.DI.Type.Composite;
pub extern fn LLVMMetadataReplaceAllUsesWith(forward: *llvm.DI.Type.Composite, complete: *llvm.DI.Type.Composite) void;
// Target
pub extern fn llvm_default_target_triple() llvm.String;
pub extern fn llvm_host_cpu_name() llvm.String;
pub extern fn llvm_host_cpu_features() llvm.String;
pub extern fn llvm_create_target_machine(create: *const llvm.Target.Machine.Create, error_message: *llvm.String) ?*llvm.Target.Machine;
pub extern fn llvm_module_set_target(module: *llvm.Module, target_machine: *llvm.Target.Machine) void;
pub extern fn llvm_module_run_optimization_pipeline(module: *llvm.Module, target_machine: *llvm.Target.Machine, options: llvm.OptimizationPipelineOptions) void;
pub extern fn llvm_module_run_code_generation_pipeline(module: *llvm.Module, target_machine: *llvm.Target.Machine, options: llvm.CodeGenerationPipelineOptions) llvm.CodeGenerationPipelineResult;
pub fn get_initializer(comptime llvm_arch: llvm.Architecture) type {
const arch_name = @tagName(llvm_arch);
return struct {
pub const initialize_target_info = @extern(*const fn () callconv(.C) void, .{
.name = "LLVMInitialize" ++ arch_name ++ "TargetInfo",
});
pub const initialize_target = @extern(*const fn () callconv(.C) void, .{
.name = "LLVMInitialize" ++ arch_name ++ "Target",
});
pub const initialize_target_mc = @extern(*const fn () callconv(.C) void, .{
.name = "LLVMInitialize" ++ arch_name ++ "TargetMC",
});
pub const initialize_asm_printer = @extern(*const fn () callconv(.C) void, .{
.name = "LLVMInitialize" ++ arch_name ++ "AsmPrinter",
});
pub const initialize_asm_parser = @extern(*const fn () callconv(.C) void, .{
.name = "LLVMInitialize" ++ arch_name ++ "AsmParser",
});
pub const initialize_disassembler = @extern(*const fn () callconv(.C) void, .{
.name = "LLVMInitialize" ++ arch_name ++ "Disassembler",
});
pub fn initialize(options: llvm.TargetInitializerOptions) void {
initialize_target_info();
initialize_target();
initialize_target_mc();
if (options.asm_printer) {
initialize_asm_printer();
}
if (options.asm_parser) {
initialize_asm_parser();
}
if (options.disassembler) {
initialize_disassembler();
}
}
};
}
// LLD
pub extern fn lld_elf_link(argument_pointer: [*:null]const ?[*:0]const u8, argument_length: u64, exit_early: bool, disable_output: bool) lld.Result;

4
src/main.nat Normal file

@ -0,0 +1,4 @@
fn main() s32
{
return 0;
}

@ -1,244 +0,0 @@
const lib = @import("lib.zig");
const configuration = @import("configuration");
const os = lib.os;
const llvm = @import("LLVM.zig");
const Arena = lib.Arena;
const compiler = @import("bootstrap.zig");
const BuildMode = compiler.BuildMode;
test {
_ = lib;
_ = llvm;
_ = compiler;
}
fn fail() noreturn {
lib.libc.exit(1);
}
const Command = enum {
@"test",
compile,
};
const Compile = struct {
relative_file_path: [:0]const u8,
build_mode: BuildMode,
has_debug_info: bool,
silent: bool,
};
fn compile_file(arena: *Arena, compile: Compile) compiler.Options {
const checkpoint = arena.position;
defer arena.restore(checkpoint);
const relative_file_path = compile.relative_file_path;
if (relative_file_path.len < 5) {
fail();
}
const extension_start = lib.string.last_character(relative_file_path, '.') orelse fail();
if (!lib.string.equal(relative_file_path[extension_start..], ".bbb")) {
fail();
}
const separator_index = lib.string.last_character(relative_file_path, '/') orelse 0;
const base_start = separator_index + @intFromBool(separator_index != 0 or relative_file_path[separator_index] == '/');
const base_name = relative_file_path[base_start..extension_start];
const is_compiler = lib.string.equal(relative_file_path, "src/compiler.bbb");
const output_path_dir = arena.join_string(&.{
base_cache_dir,
if (is_compiler) "/compiler/" else "/",
@tagName(compile.build_mode),
"_",
if (compile.has_debug_info) "di" else "nodi",
});
os.make_directory(base_cache_dir);
if (is_compiler) {
os.make_directory(base_cache_dir ++ "/compiler");
}
os.make_directory(output_path_dir);
const output_path_base = arena.join_string(&.{
output_path_dir,
"/",
base_name,
});
const output_object_path = arena.join_string(&.{ output_path_base, ".o" });
const output_executable_path = output_path_base;
const file_content = lib.file.read(arena, relative_file_path);
const file_path = os.absolute_path(arena, relative_file_path);
const c_abi_object_path = arena.duplicate_string(configuration.c_abi_object_path);
const convert_options = compiler.Options{
.executable = output_executable_path,
.objects = if (lib.string.equal(base_name, "c_abi")) &.{ output_object_path, c_abi_object_path } else &.{output_object_path},
.name = base_name,
.build_mode = compile.build_mode,
.content = file_content,
.path = file_path,
.has_debug_info = compile.has_debug_info,
.target = compiler.Target.get_native(),
.silent = compile.silent,
};
compiler.compile(arena, convert_options);
return convert_options;
}
const base_cache_dir = "bb-cache";
pub const panic = lib.panic_struct;
pub const std_options = lib.std_options;
pub const main = lib.main;
pub fn entry_point(arguments: []const [*:0]const u8, environment: [*:null]const ?[*:0]const u8) void {
lib.GlobalState.initialize();
const arena = lib.global.arena;
if (arguments.len < 2) {
lib.print_string("error: Not enough arguments\n");
fail();
}
const command = lib.string.to_enum(Command, lib.cstring.to_slice(arguments[1])) orelse fail();
switch (command) {
.compile => {
const relative_file_path = lib.cstring.to_slice(arguments[2]);
_ = compile_file(arena, .{
.relative_file_path = relative_file_path,
.build_mode = .debug_none,
.has_debug_info = true,
.silent = false,
});
},
.@"test" => {
if (arguments.len != 2) {
fail();
}
const stop_at_failure = true;
var build_modes: [@typeInfo(BuildMode).@"enum".fields.len]BuildMode = undefined;
inline for (@typeInfo(BuildMode).@"enum".fields, 0..) |field, field_index| {
const build_mode = @field(BuildMode, field.name);
build_modes[field_index] = build_mode;
}
for (names) |name| {
for (build_modes) |build_mode| {
for ([2]bool{ true, false }) |has_debug_info| {
const position = arena.position;
defer arena.restore(position);
const relative_file_path = arena.join_string(&.{ "tests/", name, ".bbb" });
const compile_result = compile_file(arena, .{
.relative_file_path = relative_file_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.silent = true,
});
const result = lib.os.run_child_process(arena, &.{compile_result.executable}, environment, .{
.stdout = .inherit,
.stderr = .inherit,
.null_file_descriptor = null,
});
if (!result.is_successful()) {
lib.print_string("Failed to run test ");
lib.print_string(name);
lib.print_string(" with build mode ");
lib.print_string(@tagName(build_mode));
if (stop_at_failure) {
lib.libc.exit(1);
}
}
}
}
}
},
}
}
const names = &[_][]const u8{
"minimal",
"comments",
"constant_add",
"constant_and",
"constant_div",
"constant_mul",
"constant_rem",
"constant_or",
"constant_sub",
"constant_xor",
"constant_shift_left",
"constant_shift_right",
"minimal_stack",
"minimal_stack_arithmetic",
"minimal_stack_arithmetic2",
"minimal_stack_arithmetic3",
"extend",
"stack_negation",
"stack_add",
"stack_sub",
"integer_max",
"integer_hex",
"basic_pointer",
"basic_call",
"pointer",
"pointer_cast",
"u1_return",
"local_type_inference",
"global",
"function_pointer",
"extern",
"byte_size",
"basic_branch",
"basic_array",
"basic_enum",
"argv",
"assignment_operators",
"basic_enum",
"basic_slice",
"basic_string",
"basic_varargs",
"basic_while",
"not_pointer",
"bits",
"bits_no_backing_type",
"bits_return_u1",
"bits_zero",
"comparison",
"global_struct",
"if_no_else",
"if_no_else_void",
"indirect",
"indirect_struct",
"indirect_varargs",
"ret_c_bool",
"return_type_builtin",
"return_u64_u64",
"select",
"slice",
"small_struct_ints",
"struct_assignment",
"struct",
"struct_u64_u64",
"struct_varargs",
"struct_zero",
"unreachable",
"varargs",
"c_abi0",
"c_abi1",
"c_med_struct_ints",
"c_ret_struct_array",
};

@ -1,20 +0,0 @@
const std = @import("std");
export fn enable_signal_handlers() void {
std.debug.attachSegfaultHandler();
}
export fn dump_stack_trace(return_address: usize) void {
const stderr = std.io.getStdErr().writer();
if (@import("builtin").strip_debug_info) {
stderr.print("Unable to dump stack trace: debug info stripped\n", .{}) catch return;
return;
}
const debug_info = std.debug.getSelfDebugInfo() catch |err| {
stderr.print("Unable to dump stack trace: Unable to open debug info: {s}\n", .{@errorName(err)}) catch return;
return;
};
std.debug.writeCurrentStackTrace(stderr, debug_info, std.io.tty.detectConfig(std.io.getStdErr()), return_address) catch |err| {
stderr.print("Unable to dump stack trace: {s}\n", .{@errorName(err)}) catch return;
return;
};
}

4
tests/add_sub.nat Normal file

@ -0,0 +1,4 @@
fn main() s32
{
return 1 - 1 + 1 - 1;
}

4
tests/and.nat Normal file

@ -0,0 +1,4 @@
fn main() s32
{
return 1 & 0;
}

@ -1,13 +0,0 @@
[export] main = fn [cc(c)] (argument_count: u32, argument_pointer: &&u8) s32
{
if (argument_count != 1)
{
return 1;
}
>arg = argument_pointer[0];
if (arg != argument_pointer[0])
{
return 1;
}
return 0;
}

@ -1,35 +0,0 @@
unsigned = fn(n: s32) s32
{
>result: u32 = #extend(n);
result >>= 1;
result <<= 1;
result ^= 1;
result |= 1;
result &= 1;
result += 1;
result -= 1;
result /= 1;
result %= 1;
result *= 0;
return #extend(result);
}
[export] main = fn [cc(c)] () s32
{
>result: s32 = 0;
>pointer = &result;
pointer -= 1;
pointer += 1;
result >>= 1;
result <<= 1;
result ^= 1;
result |= 1;
result &= 1;
result += 1;
result -= 1;
result /= 1;
result %= 1;
result *= 0;
return unsigned(result);
}

@ -1,5 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>array: [_]s32 = [3, 2, 1, 0];
return array[3];
}

@ -1,12 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>result: s32 = 1;
if (result != 1)
{
return 1;
}
else
{
return 0;
}
}

@ -1,9 +0,0 @@
foo = fn() s32
{
return 0;
}
[export] main = fn[cc(c)] () s32
{
return foo();
}

@ -1,18 +0,0 @@
E = enum
{
zero = 0,
one = 1,
two = 2,
three = 3,
}
[export] main = fn [cc(c)] () s32
{
>a: E = .three;
>b: E = .two;
>c: E = .one;
>a_int: s32 = #extend(#int_from_enum(a));
>b_int: s32 = #extend(#int_from_enum(b));
>c_int: s32 = #extend(#int_from_enum(c));
return a_int - (b_int + c_int);
}

@ -1,6 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = 0;
>pointer = &a;
return pointer.&;
}

@ -1,22 +0,0 @@
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
slice_receiver = fn (slice: []u8) void
{
require(slice.length == 3);
require(slice[0] == 0);
require(slice[1] == 1);
require(slice[2] == 2);
}
[export] main = fn [cc(c)] () s32
{
>a: [_]u8 = [0, 1, 2];
slice_receiver(&a);
return 0;
}

@ -1,16 +0,0 @@
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
[export] main = fn [cc(c)] () s32
{
>string = "abc";
require(string[0] == 'a');
require(string[1] == 'b');
require(string[2] == 'c');
return 0;
}

@ -1,29 +0,0 @@
va_arg_fn = fn [cc(c)] (first_arg: u32, ...) void
{
if (first_arg != 123456789)
{
#trap();
}
>va = #va_start();
>a = #va_arg(&va, u32);
if (a != 987654321)
{
#trap();
}
>first_arg_b = #va_arg(&va, u32);
if (first_arg_b != 123456789)
{
#trap();
}
}
[export] main = fn [cc(c)] () s32
{
>first_arg: u32 = 123456789;
>a: u32 = 987654321;
va_arg_fn(first_arg, a, first_arg);
return 0;
}

@ -1,38 +0,0 @@
c_string_length = fn (c_string: &u8) u64
{
>it = c_string;
while (it.&)
{
it = it + 1;
}
return #int_from_pointer(it) - #int_from_pointer(c_string);
}
[export] main = fn (argument_count: u32, argument_pointer: &&u8) s32
{
if (argument_count == 0)
{
return 1;
}
>first_arg = argument_pointer[0];
if (!first_arg)
{
return 1;
}
>arg_length = c_string_length(first_arg);
if (arg_length == 0)
{
return 1;
}
if (first_arg[arg_length] != 0)
{
return 1;
}
return 0;
}

@ -1,18 +0,0 @@
BitField = bits u8
{
a: u2,
b: u2,
c: u2,
d: u2,
};
[export] main = fn [cc(c)] () s32
{
>b: BitField = {
.a = 3,
.b = 2,
.c = 2,
.d = 3,
};
return #extend((b.a - b.d) + (b.b - b.c));
}

@ -1,13 +0,0 @@
A = bits {
a: u1,
b: u1,
}
[export] main = fn [cc(c)] () s32
{
>a: A = {
.a = 1,
.b = 1,
};
return #extend(a.a - a.b);
}

@ -1,17 +0,0 @@
S = bits u32
{
a: u1,
b: u1,
c: u1,
}
foo = fn () u1
{
>a: S = { .a = 1, .b = 1, .c = 0 };
return a.c;
}
[export] main = fn [cc(c)] () s32
{
return #extend(foo() == 1);
}

@ -1,35 +0,0 @@
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
S = bits
{
a: u1,
b: u1,
c: u1,
}
[export] main = fn () s32
{
>a: S = zero;
require(a.a == 0);
require(a.b == 0);
require(a.c == 0);
>b: S = {
.a = 1,
.b = 1,
zero,
};
require(b.a == 1);
require(b.b == 1);
require(b.c == 0);
return 0;
}

166
tests/break_continue.nat Normal file

@ -0,0 +1,166 @@
fn fn0(arg: s32) s32
{
>a = arg;
while (a < 10)
{
a = a + 1;
if (a == 5)
{
break;
}
if (a == 6)
{
break;
}
}
return a;
}
fn fn1(arg: s32) s32
{
>a: s32 = 1;
>i = arg;
while (i < 10)
{
i = i + 1;
if (i == 5)
{
continue;
}
if (i == 7)
{
continue;
}
a = a + 1;
}
return a;
}
fn fn2(arg: s32) s32
{
>i = arg;
while (i < 10)
{
i = i + 1;
if (i == 5)
{
continue;
}
if (i == 6)
{
break;
}
}
return i;
}
fn fn3(arg: s32) s32
{
>i = arg;
while (i < 10)
{
i = i + 1;
if (i == 6)
{
break;
}
}
return i;
}
fn fn4(arg: s32) s32
{
>i = arg;
while (i < 10)
{
i = i + 1;
if (i == 5)
{
continue;
}
if (i == 6)
{
continue;
}
}
return i;
}
fn fn5(arg: s32) s32
{
>i = arg;
while (i < 10)
{
i = i + 1;
if (i == 5)
{
continue;
}
}
return i;
}
fn fn6(arg: s32) s32
{
>i = arg;
while (i < 10)
{
>a = i + 2;
if (a > 4)
{
break;
}
}
return i;
}
fn fn7(arg: s32) s32
{
>i = arg;
while (i < 10)
{
break;
}
return i;
}
fn fn8(arg: s32) s32
{
>a: s32 = 1;
while (1)
{
a = a + 1;
if (a < 10)
{
continue;
}
break;
}
return a;
}
fn[cc(.c)] main[export]() s32
{
return fn0(0) +
fn1(1) +
fn2(2) +
fn3(3) +
fn4(4) +
fn5(5) +
fn6(6) +
fn7(7) +
fn8(8);
}

@ -1,6 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = #byte_size(s32);
>b: s32 = #byte_size(s32);
return a - b;
}

@ -1,539 +0,0 @@
Struct_u64_u64 = struct
{
a: u64,
b: u64,
}
BigStruct = struct
{
a: u64,
b: u64,
c: u64,
d: u64,
e: u8,
}
SmallPackedStruct = bits u8
{
a: u2,
b: u2,
c: u2,
d: u2,
}
SmallStructInts = struct
{
a: u8,
b: u8,
c: u8,
d: u8,
}
SplitStructInt = struct
{
a: u64,
b: u8,
c: u32,
}
MedStructInts = struct
{
x: s32,
y: s32,
z: s32,
}
Rect = struct
{
left: u32,
right: u32,
top: u32,
bottom: u32,
}
StructWithArray = struct
{
a: s32,
padding: [4]u8,
b: s64,
}
ByRef = struct
{
val: s32,
arr: [15]s32,
}
ByValOrigin = struct
{
x: u64,
y: u64,
z: u64,
}
ByValSize = struct
{
width: u64,
height: u64,
depth: u64,
}
ByVal = struct
{
origin: ByValOrigin,
size: ByValSize,
}
[extern] run_c_tests = fn [cc(c)] () void;
[extern] c_u8 = fn [cc(c)] (x: u8) void;
[extern] c_u16 = fn [cc(c)] (x: u16) void;
[extern] c_u32 = fn [cc(c)] (x: u32) void;
[extern] c_u64 = fn [cc(c)] (x: u64) void;
[extern] c_s8 = fn [cc(c)] (x: s8) void;
[extern] c_s16 = fn [cc(c)] (x: s16) void;
[extern] c_s32 = fn [cc(c)] (x: s32) void;
[extern] c_s64 = fn [cc(c)] (x: s64) void;
[extern] c_bool = fn [cc(c)] (x: u8) void;
[extern] c_five_integers = fn [cc(c)] (a: s32, b: s32, c: s32, d: s32, e: s32) void;
[extern] c_ret_struct_u64_u64 = fn [cc(c)] () Struct_u64_u64;
[extern] c_struct_u64_u64_0 = fn [cc(c)] (a: Struct_u64_u64) void;
[extern] c_struct_u64_u64_1 = fn [cc(c)] (a: u64, b: Struct_u64_u64) void;
[extern] c_struct_u64_u64_2 = fn [cc(c)] (a: u64, b: u64, c: Struct_u64_u64) void;
[extern] c_struct_u64_u64_3 = fn [cc(c)] (a: u64, b: u64, c: u64, d: Struct_u64_u64) void;
[extern] c_struct_u64_u64_4 = fn [cc(c)] (a: u64, b: u64, c: u64, d: u64, e: Struct_u64_u64) void;
[extern] c_struct_u64_u64_5 = fn [cc(c)] (a: u64, b: u64, c: u64, d: u64, e: u64, f: Struct_u64_u64) void;
[extern] c_struct_u64_u64_6 = fn [cc(c)] (a: u64, b: u64, c: u64, d: u64, e: u64, f: u64, g: Struct_u64_u64) void;
[extern] c_struct_u64_u64_7 = fn [cc(c)] (a: u64, b: u64, c: u64, d: u64, e: u64, f: u64, g: u64, h: Struct_u64_u64) void;
[extern] c_struct_u64_u64_8 = fn [cc(c)] (a: u64, b: u64, c: u64, d: u64, e: u64, f: u64, g: u64, h: u64, i: Struct_u64_u64) void;
[extern] c_big_struct = fn [cc(c)] (x: BigStruct) void;
[extern] c_small_struct_ints = fn [cc(c)] (x: SmallStructInts) void;
[extern] c_ret_small_struct_ints = fn [cc(c)] () SmallStructInts;
[extern] c_med_struct_ints = fn [cc(c)] (x: MedStructInts) void;
[extern] c_ret_med_struct_ints = fn [cc(c)] () MedStructInts;
[extern] c_small_packed_struct = fn [cc(c)] (x: SmallPackedStruct) void;
[extern] c_ret_small_packed_struct = fn [cc(c)] () SmallPackedStruct;
[extern] c_split_struct_ints = fn [cc(c)] (x: SplitStructInt) void;
[extern] c_big_struct_both = fn [cc(c)] (x: BigStruct) BigStruct;
[extern] c_multiple_struct_ints = fn [cc(c)] (a: Rect, b: Rect) void;
[extern] c_ret_bool = fn [cc(c)] () u8;
[extern] c_ret_u8 = fn [cc(c)] () u8;
[extern] c_ret_u16 = fn [cc(c)] () u16;
[extern] c_ret_u32 = fn [cc(c)] () u32;
[extern] c_ret_u64 = fn [cc(c)] () u64;
[extern] c_ret_s8 = fn [cc(c)] () s8;
[extern] c_ret_s16 = fn [cc(c)] () s16;
[extern] c_ret_s32 = fn [cc(c)] () s32;
[extern] c_ret_s64 = fn [cc(c)] () s64;
[extern] c_struct_with_array = fn [cc(c)] (x: StructWithArray) void;
[extern] c_ret_struct_with_array = fn [cc(c)] () StructWithArray;
[extern] c_modify_by_ref_param = fn [cc(c)] (x: ByRef) ByRef;
[extern] c_func_ptr_byval = fn [cc(c)] (a: u64, b: u64, c: ByVal, d: u64, e: u64, f: u64) void;
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
[export] main = fn [cc(c)] () s32
{
run_c_tests();
c_u8(0xff);
c_u16(0xfffe);
c_u32(0xfffffffd);
c_u64(0xfffffffffffffffc);
//if (has_i128) {
// c_struct_u128({ .value = 0xfffffffffffffffc, });
//}
c_s8(-1);
c_s16(-2);
c_s32(-3);
c_s64(-4);
//if (has_i128) {
// c_struct_i128({ .value = -6, });
//}
c_bool(1);
c_five_integers(12, 34, 56, 78, 90);
>s = c_ret_struct_u64_u64();
require(s.a == 21);
require(s.b == 22);
c_struct_u64_u64_0({ .a = 23, .b = 24, });
c_struct_u64_u64_1(0, { .a = 25, .b = 26, });
c_struct_u64_u64_2(0, 1, { .a = 27, .b = 28, });
c_struct_u64_u64_3(0, 1, 2, { .a = 29, .b = 30, });
c_struct_u64_u64_4(0, 1, 2, 3, { .a = 31, .b = 32, });
c_struct_u64_u64_5(0, 1, 2, 3, 4, { .a = 33, .b = 34, });
c_struct_u64_u64_6(0, 1, 2, 3, 4, 5, { .a = 35, .b = 36, });
c_struct_u64_u64_7(0, 1, 2, 3, 4, 5, 6, { .a = 37, .b = 38, });
c_struct_u64_u64_8(0, 1, 2, 3, 4, 5, 6, 7, { .a = 39, .b = 40, });
>big_struct: BigStruct = {
.a = 1,
.b = 2,
.c = 3,
.d = 4,
.e = 5,
};
c_big_struct(big_struct);
>small: SmallStructInts = {
.a = 1,
.b = 2,
.c = 3,
.d = 4,
};
c_small_struct_ints(small);
>small2 = c_ret_small_struct_ints();
require(small2.a == 1);
require(small2.b == 2);
require(small2.c == 3);
require(small2.d == 4);
>med: MedStructInts = {
.x = 1,
.y = 2,
.z = 3,
};
c_med_struct_ints(med);
>med2 = c_ret_med_struct_ints();
require(med2.x == 1);
require(med2.y == 2);
require(med2.z == 3);
>p: SmallPackedStruct = { .a = 0, .b = 1, .c = 2, .d = 3, };
c_small_packed_struct(p);
>p2 = c_ret_small_packed_struct();
require(p2.a == 0);
require(p2.b == 1);
require(p2.c == 2);
require(p2.d == 3);
>split: SplitStructInt = {
.a = 1234,
.b = 100,
.c = 1337,
};
c_split_struct_ints(split);
> big: BigStruct = {
.a = 1,
.b = 2,
.c = 3,
.d = 4,
.e = 5,
};
>big2 = c_big_struct_both(big);
require(big2.a == 10);
require(big2.b == 11);
require(big2.c == 12);
require(big2.d == 13);
require(big2.e == 14);
>r1: Rect = {
.left = 1,
.right = 21,
.top = 16,
.bottom = 4,
};
>r2: Rect = {
.left = 178,
.right = 189,
.top = 21,
.bottom = 15,
};
c_multiple_struct_ints(r1, r2);
require(c_ret_bool() == 1);
require(c_ret_u8() == 0xff);
require(c_ret_u16() == 0xffff);
require(c_ret_u32() == 0xffffffff);
require(c_ret_u64() == 0xffffffffffffffff);
require(c_ret_s8() == -1);
require(c_ret_s16() == -1);
require(c_ret_s32() == -1);
require(c_ret_s64() == -1);
c_struct_with_array({ .a = 1, .padding = [0, 0, 0, 0], .b = 2, });
>x = c_ret_struct_with_array();
require(x.a == 4);
require(x.b == 155);
>res = c_modify_by_ref_param({ .val = 1, .arr = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ] });
require(res.val == 42);
>function_pointer = &c_func_ptr_byval;
function_pointer(1, 2, { .origin = { .x = 9, .y = 10, .z = 11, }, .size = { .width = 12, .height = 13, .depth = 14, }, }, 3, 4, 5);
return 0;
}
[export] bb_u8 = fn [cc(c)] (x: u8) void
{
require(x == 0xff);
}
[export] bb_u16 = fn [cc(c)] (x: u16) void
{
require(x == 0xfffe);
}
[export] bb_u32 = fn [cc(c)] (x: u32) void
{
require(x == 0xfffffffd);
}
[export] bb_u64 = fn [cc(c)] (x: u64) void
{
require(x == 0xfffffffffffffffc);
}
[export] bb_s8 = fn [cc(c)] (x: s8) void
{
require(x == -1);
}
[export] bb_s16 = fn [cc(c)] (x: s16) void
{
require(x == -2);
}
[export] bb_s32 = fn [cc(c)] (x: s32) void
{
require(x == -3);
}
[export] bb_s64 = fn [cc(c)] (x: s64) void
{
require(x == -4);
}
[export] bb_ptr = fn [cc(c)] (x: &u8) void
{
require(#cast_to(u64, x) == 0xdeadbeef);
}
[export] bb_five_integers = fn [cc(c)] (a: s32, b: s32, c: s32, d: s32, e: s32) void
{
require(a == 12);
require(b == 34);
require(c == 56);
require(d == 78);
require(e == 90);
}
[export] bb_bool = fn [cc(c)] (x: u8) void
{
require(#truncate(x));
}
[export] bb_ret_struct_u64_u64 = fn [cc(c)] () Struct_u64_u64
{
return { .a = 1, .b = 2, };
}
[export] bb_struct_u64_u64_0 = fn [cc(c)] (s: Struct_u64_u64) void
{
require(s.a == 3);
require(s.b == 4);
}
[export] bb_struct_u64_u64_1 = fn [cc(c)] (_: u64, s: Struct_u64_u64) void
{
require(s.a == 5);
require(s.b == 6);
}
[export] bb_struct_u64_u64_2 = fn [cc(c)] (_: u64, _: u64, s: Struct_u64_u64) void
{
require(s.a == 7);
require(s.b == 8);
}
[export] bb_struct_u64_u64_3 = fn [cc(c)] (_: u64, _: u64, _: u64, s: Struct_u64_u64) void
{
require(s.a == 9);
require(s.b == 10);
}
[export] bb_struct_u64_u64_4 = fn [cc(c)] (_: u64, _: u64, _: u64, _: u64, s: Struct_u64_u64) void
{
require(s.a == 11);
require(s.b == 12);
}
[export] bb_struct_u64_u64_5 = fn [cc(c)] (_: u64, _: u64, _: u64, _: u64, _: u64, s: Struct_u64_u64) void
{
require(s.a == 13);
require(s.b == 14);
}
[export] bb_struct_u64_u64_6 = fn [cc(c)] (_: u64, _: u64, _: u64, _: u64, _: u64, _: u64, s: Struct_u64_u64) void
{
require(s.a == 15);
require(s.b == 16);
}
[export] bb_struct_u64_u64_7 = fn [cc(c)] (_: u64, _: u64, _: u64, _: u64, _: u64, _: u64, _: u64, s: Struct_u64_u64) void
{
require(s.a == 17);
require(s.b == 18);
}
[export] bb_struct_u64_u64_8 = fn [cc(c)] (_: u64, _: u64, _: u64, _: u64, _: u64, _: u64, _: u64, _: u64, s: Struct_u64_u64) void
{
require(s.a == 19);
require(s.b == 20);
}
[export] bb_big_struct = fn [cc(c)] (x: BigStruct) void
{
require(x.a == 1);
require(x.b == 2);
require(x.c == 3);
require(x.d == 4);
require(x.e == 5);
}
[export] bb_small_packed_struct = fn [cc(c)] (x: SmallPackedStruct) void
{
require(x.a == 0);
require(x.b == 1);
require(x.c == 2);
require(x.d == 3);
}
[export] bb_split_struct_ints = fn [cc(c)] (x: SplitStructInt) void
{
require(x.a == 1234);
require(x.b == 100);
require(x.c == 1337);
}
[export] bb_big_struct_both = fn [cc(c)] (x: BigStruct) BigStruct
{
require(x.a == 30);
require(x.b == 31);
require(x.c == 32);
require(x.d == 33);
require(x.e == 34);
>s: BigStruct = {
.a = 20,
.b = 21,
.c = 22,
.d = 23,
.e = 24,
};
return s;
}
[export] bb_ret_bool = fn [cc(c)] () u8
{
return 1;
}
[export] bb_ret_u8 = fn [cc(c)] () u8
{
return 0xff;
}
[export] bb_ret_u16 = fn [cc(c)] () u16
{
return 0xffff;
}
[export] bb_ret_u32 = fn [cc(c)] () u32
{
return 0xffffffff;
}
[export] bb_ret_u64 = fn [cc(c)] () u64
{
return 0xffffffffffffffff;
}
[export] bb_ret_s8 = fn [cc(c)] () s8
{
return -1;
}
[export] bb_ret_s16 = fn [cc(c)] () s16
{
return -1;
}
[export] bb_ret_s32 = fn [cc(c)] () s32
{
return -1;
}
[export] bb_ret_s64 = fn [cc(c)] () s64
{
return -1;
}
[export] bb_ret_small_struct_ints = fn [cc(c)] () SmallStructInts
{
return {
.a = 1,
.b = 2,
.c = 3,
.d = 4,
};
}
[export] bb_ret_med_struct_ints = fn [cc(c)] () MedStructInts
{
return {
.x = 1,
.y = 2,
.z = 3,
};
}
[export] bb_multiple_struct_ints = fn [cc(c)] (x: Rect, y: Rect) void
{
require(x.left == 1);
require(x.right == 21);
require(x.top == 16);
require(x.bottom == 4);
require(y.left == 178);
require(y.right == 189);
require(y.top == 21);
require(y.bottom == 15);
}
[export] bb_small_struct_ints = fn [cc(c)] (x: SmallStructInts) void
{
require(x.a == 1);
require(x.b == 2);
require(x.c == 3);
require(x.d == 4);
}
[export] bb_med_struct_ints = fn [cc(c)] (s: MedStructInts) void
{
require(s.x == 1);
require(s.y == 2);
require(s.z == 3);
}

File diff suppressed because it is too large Load Diff

@ -1,20 +0,0 @@
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
c_u8 = fn [cc(c)] (x: u8) void
{
require(x == 0xff);
}
[export] main = fn [cc(c)] () s32
{
>v: u8 = 0xff;
c_u8(v);
return 0;
}

@ -1,18 +0,0 @@
require = fn(ok: u1) void
{
if (!ok)
{
#trap();
}
}
c_u16 = fn [cc(c)] (v: u16) void
{
require(v == 0xfffe);
}
[export] main = fn [cc(c)] () s32
{
c_u16(0xfffe);
return 0;
}

@ -1,51 +0,0 @@
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
MedStructInts = struct
{
x: s32,
y: s32,
z: s32,
}
bb_ret_med_struct_ints = fn [cc(c)] () MedStructInts
{
return {
.x = 1,
.y = 2,
.z = 3,
};
}
c_med_struct_ints = fn [cc(c)] (s: MedStructInts) void
{
require(s.x == 1);
require(s.y == 2);
require(s.z == 3);
>s2 = bb_ret_med_struct_ints();
require(s2.x == 1);
require(s2.y == 2);
require(s2.z == 3);
}
[export] main = fn [cc(c)] () s32
{
>med: MedStructInts = {
.x = 1,
.y = 2,
.z = 3,
};
c_med_struct_ints(med);
>med2 = bb_ret_med_struct_ints();
require(med2.x == 1);
require(med2.y == 2);
require(med2.z == 3);
return 0;
}

@ -1,27 +0,0 @@
StructWithArray = struct
{
a: u32,
padding: [4]u8,
c: u64,
};
c_ret_struct_with_array = fn [cc(c)] () StructWithArray
{
return { .a = 4, .padding = [ 0, 0, 0, 0 ], .c = 155 };
}
require = fn(ok: u1) void
{
if (!ok)
{
#trap();
}
}
[export] main = fn [cc(c)] () s32
{
>s = c_ret_struct_with_array();
require(s.a == 4);
require(s.c == 155);
return 0;
}

@ -1,36 +0,0 @@
SplitStructInt = struct
{
a: u64,
b: u8,
c: u32,
}
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
bb_split_struct_ints = fn [cc(c)] (x: SplitStructInt) void
{
require(x.a == 1234);
require(x.b == 100);
require(x.c == 1337);
}
[export] main = fn [cc(c)] () s32
{
>split: SplitStructInt = {
.a = 1234,
.b = 100,
.c = 1337,
};
bb_split_struct_ints(split);
>a: s32 = #truncate(split.a);
>b: s32 = #extend(split.b);
>c: s32 = #extend(split.c);
return a + b + 3 - c;
}

@ -1,33 +0,0 @@
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
c_string_length = fn (c_string: &u8) u64
{
>it = c_string;
while (it.&)
{
it = it + 1;
}
return #int_from_pointer(it) - #int_from_pointer(c_string);
}
c_string_slice_build = fn (c_string: &u8, length: u64) []u8
{
return c_string[0..length];
}
[export] main = fn [cc(c)] (argument_count: u32, argument_pointer: &&u8) s32
{
>length = c_string_length(argument_pointer[0]);
>string = c_string_slice_build(argument_pointer[0], length);
require(string.pointer == argument_pointer[0]);
require(string.length == length);
return 0;
}

@ -1,26 +0,0 @@
require = fn(ok: u1) void
{
if (!ok)
{
#trap();
}
}
StructWithArray = struct
{
a: u32,
padding: [4]u8,
b: u64,
}
c_struct_with_array = fn [cc(c)] (x: StructWithArray) void
{
require(x.a == 1);
require(x.b == 2);
}
[export] main = fn [cc(c)] () s32
{
c_struct_with_array({ .a = 1, .padding = [0, 0, 0, 0], .b = 2 });
return 0;
}

@ -1,7 +0,0 @@
[export] main = fn [cc(c)] () s32 // This is a comment
// This is a comment
{ // This is a comment
// This is a comment
return 0; // This is a comment
}// This is a comment
// This is a comment

@ -1,14 +0,0 @@
trivial_comparison = fn (a: u32, b: u32) u1
{
return a + 1 == b + 1;
}
[export] main = fn [cc(c)] (argument_count: u32) s32
{
>result = trivial_comparison(argument_count, argument_count);
if (!result)
{
#trap();
}
return 0;
}

4
tests/comparison.nat Normal file

@ -0,0 +1,4 @@
fn main (argc: s32) s32
{
return argc != 1;
}

@ -1,4 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return -1 + 1;
}

@ -1,4 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 1 & 2;
}

@ -1,4 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 0 / 5;
}

@ -1,4 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 1 * 0;
}

@ -1,4 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 0 | 0;
}

4
tests/constant_prop.nat Normal file

@ -0,0 +1,4 @@
fn[cc(.c)] main [export] () s32
{
return 2 + 4 - 1 - 5;
}

@ -1,4 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 5 % 5;
}

@ -1,4 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 0 << 1;
}

@ -1,4 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 0 >> 1;
}

@ -1,5 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 1 - 1;
}

@ -1,4 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 0 ^ 0;
}

4
tests/div.nat Normal file

@ -0,0 +1,4 @@
fn main() s32
{
return 0 / 1;
}

@ -1,5 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>result: s8 = 0;
return #extend(result);
}

@ -1,5 +0,0 @@
[extern] exit = fn [cc(c)] (exit_code: s32) noreturn;
[export] main = fn [cc(c)] () s32
{
exit(0);
}

4
tests/first.nat Normal file

@ -0,0 +1,4 @@
fn main () s32
{
return 0;
}

@ -0,0 +1,10 @@
fn foo(arg: s32) s32
{
return arg;
}
fn[cc(.c)] main [export] () s32
{
>arg: s32 = 6;
return foo(arg) - arg;
}

@ -1,10 +0,0 @@
foo = fn [cc(c)] () s32
{
return 123;
}
[export] main = fn [cc(c)] () s32
{
>fn_ptr = &foo;
return fn_ptr() - 123;
}

@ -1,5 +0,0 @@
result: s32 = 0;
[export] main = fn [cc(c)] () s32 {
return result;
}

@ -1,28 +0,0 @@
S = struct
{
a: u32,
b: u32,
c: u32,
}
s: S = {
.a = 1,
.b = 2,
.c = 3,
};
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
[export] main = fn () s32
{
require(s.a == 1);
require(s.b == 2);
require(s.c == 3);
return 0;
}

131
tests/if.nat Normal file

@ -0,0 +1,131 @@
fn if0(arg: s32) s32
{
>a: s32 = 1;
if (arg == 1)
{
a = arg + 2;
}
else
{
a = arg - 3;
}
return a;
}
fn if1(arg: s32) s32
{
>c: s32 = 3;
>b: s32 = 2;
if (arg == 1)
{
b = 3;
c = 4;
}
return c;
}
fn if2(arg: s32) s32
{
if (arg == 1)
{
return 3;
}
else
{
return 4;
}
}
fn if3(arg: s32) s32
{
>a: s32 = arg + 1;
>b: s32 = 0;
if (arg == 1)
{
b = a;
}
else
{
b = a + 1;
}
return a + b;
}
fn if4(arg: s32) s32
{
>a: s32 = arg + 1;
>b: s32 = arg + 2;
if (arg == 1)
{
b = b + a;
}
else
{
a = b + 1;
}
return a + b;
}
fn if5(arg: s32) s32
{
>a: s32 = 1;
if (arg == 1)
{
if (arg == 2)
{
a = 2;
}
else
{
a = 3;
}
}
else if (arg == 3)
{
a = 4;
}
else
{
a = 5;
}
return a;
}
fn if6(arg: s32) s32
{
>a: s32 = 0;
>b: s32 = 0;
if (arg)
{
a = 1;
}
if (arg == 0)
{
b = 2;
}
return arg + a + b;
}
fn if7(arg: s32) s32
{
>a: s32 = arg == 2;
if (arg == 1)
{
a = arg == 3;
}
return a;
}
fn[cc(.c)] main[export] () s32
{
return if0(3) + if1(1) - 4 + if2(1) - 3 + if3(1) - 4 + if4(0) - 5 + if5(4) - 5 + if6(0) - 2 + if7(0);
}

@ -1,9 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = 5;
if (a == 2)
{
return 1;
}
return 0;
}

@ -1,14 +0,0 @@
require = fn [cc(c)] (ok: u1) void
{
if (!ok)
{
#trap();
}
}
[export] main = fn [cc(c)] () s32
{
>result: s32 = 0;
require(result == 0);
return result;
}

@ -1,45 +0,0 @@
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
S = struct
{
a: u32,
b: u32,
c: u32,
d: u32,
e: u32,
f: u32,
}
ret = fn [cc(c)] () S
{
return { .a = 56, .b = 57, .c = 58, .d = 59, .e = 60, .f = 61 };
}
arg = fn [cc(c)] (s: S) void
{
require(s.a == 56);
require(s.b == 57);
require(s.c == 58);
require(s.d == 59);
require(s.e == 60);
require(s.f == 61);
}
[export] main = fn [cc(c)] () s32
{
>s = ret();
require(s.a == 56);
require(s.b == 57);
require(s.c == 58);
require(s.d == 59);
require(s.e == 60);
require(s.f == 61);
arg(s);
return 0;
}

@ -1,46 +0,0 @@
Struct_u64_u64 = struct
{
a: u64,
b: u64,
}
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
c_struct_u64_u64_5 = fn [cc(c)] (a: u64, b: u64, c: u64, d: u64, e: u64, s: Struct_u64_u64) void
{
require(s.a == 33);
require(s.b == 34);
}
c_struct_u64_u64_6 = fn [cc(c)] (a: u64, b: u64, c: u64, d: u64, e: u64, f: u64, s: Struct_u64_u64) void
{
require(s.a == 35);
require(s.b == 36);
}
c_struct_u64_u64_7 = fn [cc(c)] (a: u64, b: u64, c: u64, d: u64, e: u64, f: u64, g: u64, s: Struct_u64_u64) void
{
require(s.a == 37);
require(s.b == 38);
}
c_struct_u64_u64_8 = fn [cc(c)] (a: u64, b: u64, c: u64, d: u64, e: u64, f: u64, g: u64, h: u64, s: Struct_u64_u64) void
{
require(s.a == 39);
require(s.b == 40);
}
[export] main = fn [cc(c)] () s32
{
c_struct_u64_u64_5(0, 0, 0, 0, 0, { .a = 33, .b = 34, });
c_struct_u64_u64_6(0, 0, 0, 0, 0, 0, { .a = 35, .b = 36, });
c_struct_u64_u64_7(0, 0, 0, 0, 0, 0, 0, { .a = 37, .b = 38, });
c_struct_u64_u64_8(0, 0, 0, 0, 0, 0, 0, 0, { .a = 39, .b = 40, });
return 0;
}

@ -1,62 +0,0 @@
S = struct
{
a: u64,
b: u64,
c: u64,
d: u64,
e: u64
f: u64,
g: u64,
h: u64,
i: u64,
j: u64
}
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
va_arg_fn = fn [cc(c)] (first_arg: u32, ...) void
{
if (first_arg != 123456789)
{
#trap();
}
>va = #va_start();
>s = #va_arg(&va, S);
require(s.a == 9);
require(s.b == 8);
require(s.c == 7);
require(s.d == 6);
require(s.e == 5);
require(s.f == 4);
require(s.g == 3);
require(s.h == 2);
require(s.i == 1);
require(s.j == 0);
}
[export] main = fn [cc(c)] () s32
{
>first_arg: u32 = 123456789;
>s : S = {
.a = 9,
.b = 8,
.c = 7,
.d = 6,
.e = 5,
.f = 4,
.g = 3,
.h = 2,
.i = 1,
.j = 0,
};
va_arg_fn(first_arg, s);
return 0;
}

@ -1,5 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>result: s32 = 0x0;
return result;
}

@ -1,5 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>a = #integer_max(u64);
return #truncate(a + 1);
}

@ -1,10 +0,0 @@
foo = fn() s32
{
return 0;
}
[export] main = fn [cc(c)] () s32
{
>a: s32 = 0;
>result = foo() + a;
return result;
}

File diff suppressed because it is too large Load Diff

@ -1,5 +0,0 @@
[export] main = fn [cc(c)] () s32
{
return 0;
}

@ -1,5 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>result: s32 = 0;
return result;
}

@ -1,5 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = 1;
return a - 1;
}

@ -1,6 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = 1;
>b = a - 1;
return b;
}

@ -1,6 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = 1;
>b = 1 - a;
return b;
}

4
tests/mul.nat Normal file

@ -0,0 +1,4 @@
fn main() s32
{
return 1 * 0;
}

@ -1,7 +0,0 @@
[export] main = fn [cc(c)] () s32
{
>a: s32 = 0;
>ptr = &a;
>b = !ptr;
return #extend(b);
}

4
tests/or.nat Normal file

@ -0,0 +1,4 @@
fn main() s32
{
return 0 | 0;
}

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