Delete old code #55

Merged
davidgmbb merged 12 commits from delete-old-code into main 2025-06-27 21:00:53 +00:00
209 changed files with 3168 additions and 70526 deletions

View File

@ -1,17 +1,15 @@
name: CI
on:
pull_request:
push:
tags:
- "**"
branches:
- main
schedule:
- cron: "0 0 * * *"
env:
BB_CI: 1
BUILD_DEBUG: 1
jobs:
ci:
@ -19,7 +17,7 @@ jobs:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
BIRTH_CMAKE_BUILD_TYPE: [ Debug, Release ]
BIRTH_CMAKE_BUILD_TYPE: [ Debug, Release-assertions, Release ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
@ -32,11 +30,7 @@ jobs:
CLANGXX_PATH: clang++-19
run: |
set -eux
./generate.sh
./build.sh
./build/bb test
mkdir -p $HOME/bloat-buster-artifacts/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/$CMAKE_BUILD_TYPE
mv ./self-hosted-bb-cache $HOME/bloat-buster-artifacts/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/$CMAKE_BUILD_TYPE/cache
ci/reproduce.sh
release:
needs: ci
strategy:
@ -52,8 +46,7 @@ jobs:
BB_CI: 1
run: |
set -eux
mkdir -p $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)
cp $HOME/bloat-buster-artifacts/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/Release/cache/debug_none_di/compiler/aggressively_optimize_for_speed_nodi/compiler $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)
ci/install.sh
- name: Release (locally)
if: ${{ (github.ref == 'refs/heads/main') }}
shell: bash
@ -61,8 +54,7 @@ jobs:
BB_CI: 1
run: |
set -eux
cp $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/compiler $HOME/bloat-buster-artifacts/releases/main/
ci/release.sh
- name: Release (web)
uses: akkuman/gitea-release-action@v1
if: ${{ (github.ref == 'refs/heads/main') }}
@ -70,4 +62,6 @@ jobs:
NODE_OPTIONS: '--experimental-fetch' # if nodejs < 18
with:
files: |-
/home/act_runner/bloat-buster-artifacts/releases/main/compiler
/home/act_runner/bloat-buster-artifacts/releases/main/compiler_generic_debug
/home/act_runner/bloat-buster-artifacts/releases/main/compiler_generic
/home/act_runner/bloat-buster-artifacts/releases/main/compiler_native

30
.gitea/workflows/pr.yml Normal file
View File

@ -0,0 +1,30 @@
name: CI
on:
pull_request:
env:
BB_CI: 1
jobs:
ci:
strategy:
fail-fast: false
matrix:
os: [ ubuntu-latest ]
BIRTH_CMAKE_BUILD_TYPE: [ Release-assertions, Release ]
runs-on: ${{ matrix.os }}
steps:
- uses: actions/checkout@v4
- name: Build and test (Packaged LLVM)
shell: bash
env:
BB_CI: 1
CMAKE_BUILD_TYPE: ${{matrix.BIRTH_CMAKE_BUILD_TYPE}}
CLANG_PATH: clang-19
CLANGXX_PATH: clang++-19
run: |
set -eux
./generate.sh
./build.sh
./build/bb test

View File

@ -21,7 +21,6 @@ add_executable(bb
)
add_library(c_abi tests/c_abi.c)
add_library(llvm_bindings src/llvm.cpp)
include_directories(src)
add_compile_definitions(
@ -29,25 +28,25 @@ add_compile_definitions(
$<$<NOT:$<CONFIG:Debug>>:BB_DEBUG=0>
)
find_library(llvm_bindings NAMES libllvm_bindings.dylib libllvm_bindings.lib libllvm_bindings.a libllvm_bindingsELF.dll.a libllvm_bindingsELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_COMMON NAMES liblldCommon.dylib lldCommon.lib lldCommon.a liblldCommon.dll.a liblldCommon.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_ELF NAMES liblldELF.dylib lldELF.lib lldELF.a liblldELF.dll.a liblldELF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
# find_library(LLD_COFF NAMES liblldCOFF.dylib lldCOFF.lib lldCOFF.a liblldCOFF.dll.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
# find_library(LLD_MACHO NAMES liblldMachO.dylib lldMachO.lib lldMachO.a liblldMachO.dll.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
# find_library(LLD_MINGW NAMES liblldMinGW.dylib lldMinGW.lib lldMinGW.a liblldMinGW.dll.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
# find_library(LLD_WASM NAMES liblldWasm.dylib lldWasm.lib lldWasm.a liblldWasm.dll.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_COFF NAMES liblldCOFF.dylib lldCOFF.lib lldCOFF.a liblldCOFF.dll.a liblldCOFF.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MACHO NAMES liblldMachO.dylib lldMachO.lib lldMachO.a liblldMachO.dll.a liblldMachO.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_MINGW NAMES liblldMinGW.dylib lldMinGW.lib lldMinGW.a liblldMinGW.dll.a liblldMinGW.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
find_library(LLD_WASM NAMES liblldWasm.dylib lldWasm.lib lldWasm.a liblldWasm.dll.a liblldWasm.a PATHS ${LLVM_LIBRARY_DIRS} NO_DEFAULT_PATH)
target_link_libraries(llvm_bindings PUBLIC
target_link_libraries(bb PUBLIC
${LLVM_AVAILABLE_LIBS}
${LLD_COMMON}
# ${LLD_COFF}
${LLD_COFF}
${LLD_ELF}
# ${LLD_MACHO}
# ${LLD_MINGW}
# ${LLD_WASM}
${LLD_MACHO}
${LLD_MINGW}
${LLD_WASM}
${llvm_bindings}
)
target_link_libraries(bb PUBLIC llvm_bindings)
add_compile_options(-Wall -Wextra -pedantic -Wpedantic -Werror -Wno-c99-extensions -Wno-unused-function -Wno-missing-designated-field-initializers -fno-signed-char -fwrapv -fno-strict-aliasing)
add_compile_definitions(CMAKE_PREFIX_PATH="${CMAKE_PREFIX_PATH}")
add_compile_definitions(BB_CI=${BB_CI})

View File

@ -1,214 +0,0 @@
#pragma once
#include <std/base.h>
#include <std/os.h>
typedef enum CpuArchitecture : u8
{
CPU_ARCH_X86_64,
CPU_ARCH_AARCH64,
} CpuArchitecture;
fn String cpu_to_string(CpuArchitecture cpu)
{
switch (cpu)
{
case CPU_ARCH_X86_64:
return strlit("x86_64");
case CPU_ARCH_AARCH64:
return strlit("aarch64");
}
}
typedef enum OperatingSystem : u8
{
OPERATING_SYSTEM_LINUX,
OPERATING_SYSTEM_MAC,
OPERATING_SYSTEM_WINDOWS,
} OperatingSystem;
fn String operating_system_to_string(OperatingSystem os)
{
switch (os)
{
case OPERATING_SYSTEM_LINUX:
return strlit("linux");
case OPERATING_SYSTEM_MAC:
return strlit("macos");
case OPERATING_SYSTEM_WINDOWS:
return strlit("windows");
}
}
STRUCT(Target)
{
CpuArchitecture cpu;
OperatingSystem os;
};
typedef enum CompilerBackend : u8
{
COMPILER_BACKEND_BB,
COMPILER_BACKEND_LLVM,
COMPILER_BACKEND_COUNT,
} CompilerBackend;
fn String compiler_backend_to_one_char_string(CompilerBackend backend)
{
switch (backend)
{
case COMPILER_BACKEND_BB:
return strlit("b");
case COMPILER_BACKEND_LLVM:
return strlit("l");
case COMPILER_BACKEND_COUNT:
unreachable();
}
}
fn String compiler_backend_to_string(CompilerBackend backend)
{
switch (backend)
{
case COMPILER_BACKEND_BB:
return strlit("bb");
case COMPILER_BACKEND_LLVM:
return strlit("llvm");
case COMPILER_BACKEND_COUNT:
unreachable();
}
}
typedef enum BinaryFileType : u8
{
BINARY_FILE_OBJECT,
BINARY_FILE_STATIC_LIBRARY,
BINARY_FILE_DYNAMIC_LIBRARY,
BINARY_FILE_EXECUTABLE,
} BinaryFileType;
STRUCT(BinaryPathOptions)
{
String build_directory;
String name;
Target target;
CompilerBackend backend;
BinaryFileType binary_file_type;
};
fn String binary_path_from_options(Arena* arena, BinaryPathOptions options)
{
String object_extension;
switch (options.target.os)
{
case OPERATING_SYSTEM_WINDOWS:
object_extension = strlit(".obj");
break;
default:
object_extension = strlit(".o");
break;
}
String executable_extension;
switch (options.target.os)
{
case OPERATING_SYSTEM_WINDOWS:
executable_extension = strlit(".exe");
break;
default:
executable_extension = strlit("");
break;
}
String extension;
switch (options.binary_file_type)
{
case BINARY_FILE_OBJECT:
extension = object_extension;
break;
case BINARY_FILE_STATIC_LIBRARY:
unreachable();
break;
case BINARY_FILE_DYNAMIC_LIBRARY:
unreachable();
break;
case BINARY_FILE_EXECUTABLE:
extension = executable_extension;
break;
}
auto backend_string = compiler_backend_to_string(options.backend);
auto cpu_string = cpu_to_string(options.target.cpu);
auto os_string = operating_system_to_string(options.target.os);
String parts[] = {
options.build_directory,
strlit("/"),
options.name,
// strlit("_"),
// cpu_string,
// strlit("_"),
// os_string,
// strlit("_"),
// backend_string,
extension,
};
auto result = arena_join_string(arena, (Slice(String)) array_to_slice(parts));
return result;
}
fn CompilerBackend one_char_string_to_compiler_backend(String string)
{
CompilerBackend result = COMPILER_BACKEND_COUNT;
for (u32 i = 0; i < COMPILER_BACKEND_COUNT; i += 1)
{
auto candidate = (CompilerBackend)i;
if (s_equal(compiler_backend_to_one_char_string(candidate), string))
{
result = candidate;
break;
}
}
return result;
}
STRUCT(CodegenOptions)
{
String test_name;
Target target;
CompilerBackend backend;
u8 generate_debug_information;
};
fn Target native_target_get()
{
Target target = {
#ifdef __x86_64__
.cpu = CPU_ARCH_X86_64,
#else
.cpu = CPU_ARCH_AARCH64,
#endif
#if _WIN32
.os = OPERATING_SYSTEM_WINDOWS,
#elif defined(__APPLE__)
.os = OPERATING_SYSTEM_MAC,
#elif defined(__linux__)
.os = OPERATING_SYSTEM_LINUX,
#else
#error "Unknown platform"
#endif
};
return target;
}
STRUCT(LinkerArguments)
{
Target target;
String out_path;
Slice(String) objects;
Slice(String) libraries;
u8 link_libc:1;
u8 link_libcpp:1;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,276 +0,0 @@
#if BB_CI == 0
#include <bloat-buster/bb_core.h>
#include <std/virtual_buffer.h>
#include <std/window.h>
#include <std/render.h>
#include <std/image_loader.h>
#include <std/font_provider.h>
#include <std/ui_core.h>
#include <std/ui_builder.h>
#define default_font_height (24)
auto proportional_font_height = default_font_height;
auto monospace_font_height = default_font_height;
fn TextureIndex white_texture_create(Arena* arena, Renderer* renderer)
{
u32 white_texture_width = 1024;
u32 white_texture_height = white_texture_width;
auto* white_texture_buffer = arena_allocate(arena, u32, white_texture_width * white_texture_height);
memset(white_texture_buffer, 0xff, white_texture_width * white_texture_height * sizeof(u32));
auto white_texture = renderer_texture_create(renderer, (TextureMemory) {
.pointer = white_texture_buffer,
.width = white_texture_width,
.height = white_texture_height,
.depth = 1,
.format = TEXTURE_FORMAT_R8G8B8A8_SRGB,
});
return white_texture;
}
STRUCT(BBPanel)
{
BBPanel* first;
BBPanel* last;
BBPanel* next;
BBPanel* previous;
BBPanel* parent;
f32 parent_percentage;
Axis2 split_axis;
};
STRUCT(BBWindow)
{
OSWindow os;
RenderWindow* render;
BBWindow* previous;
BBWindow* next;
BBPanel* root_panel;
UI_State* ui;
};
STRUCT(BBGUIState)
{
Arena* arena;
Timestamp last_frame_timestamp;
BBWindow* first_window;
BBWindow* last_window;
Renderer* renderer;
// TODO: should this not be thread local?
OSEventQueue event_queue;
};
global_variable BBGUIState state;
fn void ui_top_bar()
{
ui_push(pref_height, ui_em(1, 1));
{
ui_push(child_layout_axis, AXIS2_X);
auto* top_bar = ui_widget_make((UI_WidgetFlags) {
}, strlit("top_bar"));
ui_push(parent, top_bar);
{
ui_button(strlit("Button 1"));
ui_button(strlit("Button 2"));
ui_button(strlit("Button 3"));
}
ui_pop(parent);
ui_pop(child_layout_axis);
}
ui_pop(pref_height);
}
STRUCT(UI_Node)
{
String name;
String type;
String value;
String namespace;
String function;
};
fn void ui_node(UI_Node node)
{
auto* node_widget = ui_widget_make_format((UI_WidgetFlags) {
.draw_background = 1,
.draw_text = 1,
}, "{s} : {s} = {s}##{s}{s}", node.name, node.type, node.value, node.function, node.namespace);
}
fn void app_update()
{
auto frame_end = os_timestamp();
os_poll_events(&state.event_queue);
auto frame_ms = os_resolve_timestamps(state.last_frame_timestamp, frame_end, TIME_UNIT_MILLISECONDS);
state.last_frame_timestamp = frame_end;
Renderer* renderer = state.renderer;
BBWindow* window = state.first_window;
while (likely(window))
{
auto* previous = window->previous;
auto* next = window->next;
auto* render_window = window->render;
renderer_window_frame_begin(renderer, render_window);
ui_state_select(window->ui);
if (likely(ui_build_begin(window->os, frame_ms, &state.event_queue)))
{
ui_push(font_size, default_font_height);
ui_top_bar();
ui_push(child_layout_axis, AXIS2_X);
auto* workspace_widget = ui_widget_make_format((UI_WidgetFlags) {}, "workspace{u64}", window->os);
ui_push(parent, workspace_widget);
{
// Node visualizer
ui_push(child_layout_axis, AXIS2_Y);
auto* node_visualizer_widget = ui_widget_make_format((UI_WidgetFlags) {
.draw_background = 1,
}, "node_visualizer{u64}", window->os);
ui_push(parent, node_visualizer_widget);
{
ui_node((UI_Node) {
.name = strlit("a"),
.type = strlit("s32"),
.value = strlit("1"),
.namespace = strlit("foo"),
.function = strlit("main"),
});
ui_node((UI_Node) {
.name = strlit("b"),
.type = strlit("s32"),
.value = strlit("2"),
.namespace = strlit("foo"),
.function = strlit("main"),
});
}
ui_pop(parent);
ui_pop(child_layout_axis);
// Side-panel stub
ui_button(strlit("Options"));
}
ui_pop(parent);
ui_pop(child_layout_axis);
ui_build_end();
ui_draw();
ui_pop(font_size);
renderer_window_frame_end(renderer, render_window);
}
else
{
if (previous)
{
previous->next = next;
}
if (next)
{
next->previous = previous;
}
if (state.first_window == window)
{
state.first_window = next;
}
if (state.last_window == window)
{
state.last_window = previous;
}
}
window = next;
}
}
fn void window_refresh_callback(OSWindow window, void* context)
{
unused(window);
unused(context);
app_update();
}
void run_app()
{
state.arena = arena_init(MB(512), MB(2), MB(2));
os_windowing_init((OSWindowingInitializationOptions) {
#ifdef __linux__
.should_use_x11 = 1,
#else
.should_use_x11 = 0,
#endif
});
state.renderer = renderer_initialize(state.arena);
state.first_window = state.last_window = arena_allocate(state.arena, BBWindow, 1);
state.first_window->os = os_window_create((OSWindowCreate) {
.name = strlit("Bloat Buster"),
.size = {
.width = 1600,
.height= 900,
},
.refresh_callback = &window_refresh_callback,
});
if (!state.first_window->os)
{
failed_execution();
}
state.first_window->render = renderer_window_initialize(state.renderer, state.first_window->os);
state.first_window->ui = ui_state_allocate(state.renderer, state.first_window->render);
state.first_window->root_panel = arena_allocate(state.arena, BBPanel, 1);
state.first_window->root_panel->parent_percentage = 1.0f;
state.first_window->root_panel->split_axis = AXIS2_X;
auto font_path =
#ifdef _WIN32
strlit("C:/Users/David/Downloads/Fira_Sans/FiraSans-Regular.ttf");
#elif defined(__linux__)
strlit("/usr/share/fonts/TTF/FiraSans-Regular.ttf");
#elif defined(__APPLE__)
strlit("/Users/david/Library/Fonts/FiraSans-Regular.ttf");
#else
strlit("WRONG_PATH");
#endif
window_rect_texture_update_begin(state.first_window->render);
auto white_texture = white_texture_create(state.arena, state.renderer);
auto monospace_font = font_texture_atlas_create(state.arena, state.renderer, (TextureAtlasCreate) {
.font_path = font_path,
.text_height = monospace_font_height,
});
auto proportional_font = monospace_font;
window_queue_rect_texture_update(state.first_window->render, RECT_TEXTURE_SLOT_WHITE, white_texture);
renderer_queue_font_update(state.renderer, state.first_window->render, RENDER_FONT_TYPE_MONOSPACE, monospace_font);
renderer_queue_font_update(state.renderer, state.first_window->render, RENDER_FONT_TYPE_PROPORTIONAL, proportional_font);
window_rect_texture_update_end(state.renderer, state.first_window->render);
state.last_frame_timestamp = os_timestamp();
while (state.first_window)
{
app_update();
}
// TODO: deinitialization
}
#endif

View File

@ -1,7 +0,0 @@
#if BB_CI == 0
#include <std/base.h>
#include <std/os.h>
EXPORT void run_app();
#endif

View File

@ -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]

View File

@ -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

View File

@ -1,55 +0,0 @@
#include <bloat-buster/lld_api.h>
#include <llvm/ADT/ArrayRef.h>
#include <llvm/Support/raw_ostream.h>
#include <lld/Common/Driver.h>
#include <std/os.h>
#define lld_api_function_signature(name) bool name(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS, llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput)
#define lld_link_decl(link_name) \
namespace link_name \
{\
lld_api_function_signature(link);\
}
typedef lld_api_function_signature(LinkerFunction);
namespace lld
{
lld_link_decl(coff);
lld_link_decl(elf);
lld_link_decl(mingw);
lld_link_decl(macho);
lld_link_decl(wasm);
}
fn u8 lld_api_generic(LLDArguments args, LinkerFunction linker_function)
{
auto arguments = llvm::ArrayRef(args.argument_pointer, args.argument_count);
std::string stdout_string;
llvm::raw_string_ostream stdout_stream(stdout_string);
std::string stderr_string;
llvm::raw_string_ostream stderr_stream(stderr_string);
u8 result = linker_function(arguments, stdout_stream, stderr_stream, args.exit_early, args.disable_output);
// assert(result == (stdout_string.length() == 0));
// assert(result == (stderr_string.length() == 0));
print_string(String{(u8*)stdout_string.data(), stdout_string.length()});
print_string(String{(u8*)stderr_string.data(), stderr_string.length()});
return result;
}
#define lld_api_function_impl(link_name) \
lld_api_function_decl(link_name)\
{\
return lld_api_generic(args, lld::link_name::link);\
}
lld_api_function_impl(coff)
lld_api_function_impl(elf)
lld_api_function_impl(mingw)
lld_api_function_impl(macho)
lld_api_function_impl(wasm)

View File

@ -1,17 +0,0 @@
#include <std/base.h>
STRUCT(LLDArguments)
{
const char** argument_pointer;
u32 argument_count;
u8 exit_early;
u8 disable_output;
};
#define lld_api_function_decl(link_name) u8 lld_ ## link_name ## _link(LLDArguments args)
EXPORT lld_api_function_decl(coff);
EXPORT lld_api_function_decl(elf);
EXPORT lld_api_function_decl(mingw);
EXPORT lld_api_function_decl(macho);
EXPORT lld_api_function_decl(coff);

View File

@ -1,244 +0,0 @@
#include <bloat-buster/lld_driver.h>
#include <std/virtual_buffer.h>
#include <std/string.h>
fn String linux_crt_find_path()
{
auto flags = (OSFileOpenFlags) {
.read = 1,
};
auto permissions = (OSFilePermissions) {
.readable = 1,
.writable = 1,
};
if (os_file_descriptor_is_valid(os_file_open(strlit("/usr/lib/crti.o"), flags, permissions)))
{
return strlit("/usr/lib");
}
if (os_file_descriptor_is_valid(os_file_open(strlit("/usr/lib/x86_64-linux-gnu/crti.o"), flags, permissions)))
{
return strlit("/usr/lib/x86_64-linux-gnu");
}
if (os_file_descriptor_is_valid(os_file_open(strlit("/usr/lib/aarch64-linux-gnu/crti.o"), flags, permissions)))
{
return strlit("/usr/lib/aarch64-linux-gnu");
}
todo();
}
fn String windows_msvc_find_path()
{
auto flags = (OSFileOpenFlags) {
.read = 1,
.directory = 1,
};
auto permissions = (OSFilePermissions) {
.readable = 1,
};
String possibilities[] = {
strlit("C:/Program Files/Microsoft Visual Studio/2022/Enterprise"),
strlit("C:/Program Files/Microsoft Visual Studio/2022/Community"),
};
for (u64 i = 0; i < array_length(possibilities); i += 1)
{
auto possibility = possibilities[i];
auto fd = os_file_open(possibility, flags, permissions);
if (os_file_descriptor_is_valid(fd))
{
return possibility;
}
}
failed_execution();
}
fn void linux_add_crt_item(Arena* arena, VirtualBufferP(char)* args, String crt_path, String item)
{
String parts[] = {
crt_path,
strlit("/"),
item,
};
*vb_add(args, 1) = string_to_c(arena_join_string(arena, (Slice(String))array_to_slice(parts)));
}
SliceP(char) lld_driver(Arena* arena, LinkerArguments arguments)
{
VirtualBufferP(char) args = {};
char* driver;
switch (arguments.target.os)
{
case OPERATING_SYSTEM_LINUX:
driver = "ld.lld";
break;
case OPERATING_SYSTEM_MAC:
driver = "ld64.lld";
break;
case OPERATING_SYSTEM_WINDOWS:
driver = "lld-link";
break;
}
*vb_add(&args, 1) = driver;
if (arguments.target.os != OPERATING_SYSTEM_WINDOWS)
{
*vb_add(&args, 1) = "--error-limit=0";
}
switch (arguments.target.os)
{
case OPERATING_SYSTEM_WINDOWS:
{
String parts[] = {
strlit("-out:"),
arguments.out_path,
};
auto arg = arena_join_string(arena, (Slice(String))array_to_slice(parts));
*vb_add(&args, 1) = string_to_c(arg);
} break;
default:
{
*vb_add(&args, 1) = "-o";
*vb_add(&args, 1) = string_to_c(arguments.out_path);
} break;
}
if (arguments.target.os != OPERATING_SYSTEM_WINDOWS)
{
for (u64 i = 0; i < arguments.objects.length; i += 1)
{
*vb_add(&args, 1) = string_to_c(arguments.objects.pointer[i]);
}
}
switch (arguments.target.os)
{
case OPERATING_SYSTEM_LINUX:
{
if (arguments.link_libcpp && !arguments.link_libc)
{
failed_execution();
}
if (arguments.link_libc)
{
auto crt_path = linux_crt_find_path();
*vb_add(&args, 1) = "-dynamic-linker";
String dynamic_linker_filename;
switch (arguments.target.cpu)
{
case CPU_ARCH_X86_64:
dynamic_linker_filename = strlit("ld-linux-x86-64.so.2");
break;
case CPU_ARCH_AARCH64:
dynamic_linker_filename = strlit("ld-linux-aarch64.so.1");
break;
}
linux_add_crt_item(arena, &args, crt_path, dynamic_linker_filename);
linux_add_crt_item(arena, &args, crt_path, strlit("crt1.o"));
*vb_add(&args, 1) = "-L";
*vb_add(&args, 1) = string_to_c(crt_path);
*vb_add(&args, 1) = "--as-needed";
*vb_add(&args, 1) = "-lm";
*vb_add(&args, 1) = "-lpthread";
*vb_add(&args, 1) = "-lc";
*vb_add(&args, 1) = "-ldl";
*vb_add(&args, 1) = "-lrt";
*vb_add(&args, 1) = "-lutil";
linux_add_crt_item(arena, &args, crt_path, strlit("crtn.o"));
if (arguments.link_libcpp)
{
// TODO: implement better path finding
linux_add_crt_item(arena, &args, crt_path, strlit("libstdc++.so.6"));
}
}
for (u64 i = 0; i < arguments.libraries.length; i += 1)
{
auto library = arguments.libraries.pointer[i];
String library_pieces[] = {
strlit("-l"),
library,
};
auto library_argument = arena_join_string(arena, (Slice(String))array_to_slice(library_pieces));
*vb_add(&args, 1) = string_to_c(library_argument);
}
} break;
case OPERATING_SYSTEM_MAC:
{
*vb_add(&args, 1) = "-dynamic";
*vb_add(&args, 1) = "-platform_version";
*vb_add(&args, 1) = "macos";
*vb_add(&args, 1) = "15.0.0";
*vb_add(&args, 1) = "15.0.0";
*vb_add(&args, 1) = "-arch";
*vb_add(&args, 1) = "arm64";
*vb_add(&args, 1) = "-syslibroot";
*vb_add(&args, 1) = "/Library/Developer/CommandLineTools/SDKs/MacOSX.sdk";
if (string_ends_with(arguments.out_path, strlit(".dylib")))
{
*vb_add(&args, 1) = "-e";
*vb_add(&args, 1) = "_main";
}
*vb_add(&args, 1) = "-lSystem";
if (arguments.link_libcpp)
{
*vb_add(&args, 1) = "-lc++";
}
} break;
case OPERATING_SYSTEM_WINDOWS:
{
if (arguments.link_libcpp && !arguments.link_libc)
{
failed_execution();
}
auto msvc_path = windows_msvc_find_path();
if (arguments.link_libc)
{
*vb_add(&args, 1) = "-defaultlib:libcmt";
{
// String parts[] = {
// strlit("-libpath:"),
// msvc_path,
// strlit("/"),
// strlit("VC/Tools/MSVC/14.41.34120/lib/x64"),
// };
// auto arg = arena_join_string(arena, (Slice(String)) array_to_slice(parts));
}
if (arguments.link_libcpp)
{
todo();
}
for (u64 i = 0; i < arguments.objects.length; i += 1)
{
*vb_add(&args, 1) = string_to_c(arguments.objects.pointer[i]);
}
}
// clang -v main.c
// "C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.41.34120\\bin\\Hostx64\\x64\\link.exe" -out:a.exe -defaultlib:libcmt -defaultlib:oldnames "-libpath:C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.41.34120\\lib\\x64" "-libpath:C:\\Program Files\\Microsoft Visual Studio\\2022\\Community\\VC\\Tools\\MSVC\\14.41.34120\\atlmfc\\lib\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.22621.0\\ucrt\\x64" "-libpath:C:\\Program Files (x86)\\Windows Kits\\10\\Lib\\10.0.22621.0\\um\\x64" "-libpath:C:\\Users\\David\\scoop\\apps\\llvm\\19.1.3\\lib\\clang\\19\\lib\\windows" -nologo "C:\\Users\\David\\AppData\\Local\\Temp\\main-706820.o"
} break;
}
return (SliceP(char)){ .pointer = args.pointer, .length = args.length };
}

View File

@ -1,4 +0,0 @@
#include <bloat-buster/base.h>
#include <std/os.h>
EXPORT SliceP(char) lld_driver(Arena* arena, LinkerArguments arguments);

View File

@ -1,166 +0,0 @@
#define unreachable() __builtin_unreachable()
#include <llvm-c/Core.h>
#include <std/os.h>
#include <bloat-buster/base.h>
#include <llvm/IR/IRBuilder.h>
#include <llvm/IR/LegacyPassManager.h>
#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/IR/Verifier.h>
#include <llvm/MC/TargetRegistry.h>
#include <llvm/Support/TargetSelect.h>
#include <llvm/Target/TargetMachine.h>
#include <llvm/Target/TargetOptions.h>
#include <llvm-c/TargetMachine.h>
#define string_ref(lit) StringRef(lit, strlit_len(lit))
namespace llvm
{
#define llvm_initialize_macro(target) \
LLVMInitialize ## target ## Target();\
LLVMInitialize ## target ## TargetInfo();\
LLVMInitialize ## target ## TargetMC();\
LLVMInitialize ## target ## AsmParser();\
LLVMInitialize ## target ## AsmPrinter()
fn void target_initialize(CpuArchitecture architecture)
{
// These are meant to be called globally, so if this code is ever threaded, we need to call this code only once
switch (architecture)
{
case CPU_ARCH_X86_64:
{
llvm_initialize_macro(X86);
} break;
case CPU_ARCH_AARCH64:
{
llvm_initialize_macro(AArch64);
} break;
}
}
EXPORT void llvm_codegen(CodegenOptions options, String object_path)
{
target_initialize(options.target.cpu);
auto context = LLVMContext();
auto module = Module(string_ref("first"), context);
std::string error_message;
// TODO: debug builder
// TODO: attributes
{
u32 return_bit_count = 32;
auto* return_type = IntegerType::get(context, return_bit_count);
ArrayRef<Type*> parameter_types = {};
u8 is_var_args = 0;
auto* function_type = FunctionType::get(return_type, parameter_types, is_var_args);
auto function_name = string_ref("main");
auto linkage = GlobalValue::LinkageTypes::ExternalLinkage;
u32 address_space = 0;
auto* function = Function::Create(function_type, linkage, address_space, function_name, &module);
auto builder = IRBuilder<>(context);
auto entry_block_name = string_ref("entry");
auto* basic_block = BasicBlock::Create(context, entry_block_name, function, 0);
builder.SetInsertPoint(basic_block);
u64 return_value_int = 0;
u8 is_signed = 0;
auto* return_value = ConstantInt::get(context, APInt(return_bit_count, return_value_int, is_signed));
builder.CreateRet(return_value);
{
raw_string_ostream message_stream(error_message);
if (verifyModule(module, &message_stream))
{
// Failure
auto& error_std_string = message_stream.str();
auto error_string = String{ .pointer = (u8*)error_std_string.data(), .length = error_std_string.length() };
print("Verification for module failed:\n{s}\n", error_string);
failed_execution();
}
}
}
// TODO: make a more correct logic
std::string target_triple_str;
switch (options.target.cpu)
{
case CPU_ARCH_X86_64:
target_triple_str += string_ref("x86_64-");
break;
case CPU_ARCH_AARCH64:
target_triple_str += string_ref("aarch64-");
break;
}
switch (options.target.os)
{
case OPERATING_SYSTEM_LINUX:
target_triple_str += string_ref("unknown-linux-gnu");
break;
case OPERATING_SYSTEM_MAC:
target_triple_str += string_ref("apple-macosx-none");
break;
case OPERATING_SYSTEM_WINDOWS:
target_triple_str += string_ref("pc-windows-msvc");
break;
}
auto target_triple = StringRef(target_triple_str);
const Target* target = TargetRegistry::lookupTarget(target_triple, error_message);
if (!target)
{
String string = { .pointer = (u8*)error_message.data(), .length = error_message.length() };
print("Could not find target: {s}\n", string);
failed_execution();
}
module.setTargetTriple(target_triple);
// TODO:
auto cpu_model = string_ref("");
auto cpu_features = string_ref("");
TargetOptions target_options;
std::optional<Reloc::Model> relocation_model = std::nullopt;
std::optional<CodeModel::Model> code_model = std::nullopt;
auto codegen_optimization_level = CodeGenOptLevel::None;
u8 jit = 0;
auto* target_machine = target->createTargetMachine(target_triple, cpu_model, cpu_features, target_options, relocation_model, code_model, codegen_optimization_level, jit);
auto data_layout = target_machine->createDataLayout();
module.setDataLayout(data_layout);
// TODO: optimizations
SmallString<0> object_string;
raw_svector_ostream object_stream(object_string);
auto file_type = CodeGenFileType::ObjectFile;
legacy::PassManager pass;
assert(target_machine->isCompatibleDataLayout(module.getDataLayout()));
raw_pwrite_stream* dwo_stream = 0;
if (target_machine->addPassesToEmitFile(pass, object_stream, dwo_stream, file_type)) {
failed_execution();
}
pass.run(module);
assert(object_path.pointer);
assert(object_path.length);
file_write(FileWriteOptions{
.path = object_path,
.content = { .pointer = (u8*)object_string.str().data(), .length = object_string.str().size() },
.executable = 1,
});
}
}

View File

@ -1,5 +0,0 @@
#pragma once
#include <bloat-buster/base.h>
EXPORT void llvm_codegen(CodegenOptions options, String object_path);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,2 +0,0 @@
#include <std/base.h>
extern u8 pdb_image[143360];

View File

@ -1,463 +0,0 @@
#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);
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)
u128 result = { .low = n };
return result;
#else
return n;
#endif
}
fn u64 u64_from_u128(u128 n)
{
#if defined (__TINYC__) || defined(_MSC_VER)
return n.low;
#else
return (u64)n;
#endif
}
fn u128 u128_shift_right(u128 value, u16 n)
{
#if defined (__TINYC__) || defined(_MSC_VER)
u128 result = {};
if (n < 128)
{
if (n >= 64)
{
// If n >= 64, only the high part contributes to the low part
result.low = value.high >> (n - 64);
result.high = 0;
}
else
{
// Standard case: n < 64
result.low = (value.low >> n) | (value.high << (64 - n));
result.high = value.high >> n;
}
}
return result;
#else
return value >> n;
#endif
}
fn u128 u128_shift_left(u128 value, u16 n)
{
#if defined(__TINYC__) || defined(_MSC_VER)
u128 result = {};
if (n < 128)
{
if (n >= 64)
{
// If n >= 64, only the low part contributes to the high part
result.high = value.low << (n - 64);
result.low = 0;
}
else
{
// Standard case: n < 64
result.high = (value.high << n) | (value.low >> (64 - n));
result.low = value.low << n;
}
}
return result;
#else
return value << n;
#endif
}
fn u128 u128_u64_or(u128 a, u64 b)
{
#if defined(__TINYC__) || defined(_MSC_VER)
a.low |= b;
return a;
#else
return a | b;
#endif
}
fn u128 u128_u64_add(u128 a, u64 b)
{
#if defined(__TINYC__) || defined(_MSC_VER)
u128 result;
// Add the lower 64 bits and check for overflow
result.low = a.low + b;
u64 carry = (result.low < a.low) ? 1 : 0;
// Add the carry to the upper 64 bits
result.high = a.high + carry;
return result;
#else
return a + b;
#endif
}
// Multiply two u128 values
fn u128 u128_u64_mul(u128 a, u64 b)
{
#if defined(__TINYC__) || defined(_MSC_VER)
u128 result = {};
// Compute low and high parts of the product
u64 low_low = (a.low & 0xFFFFFFFF) * (b & 0xFFFFFFFF);
u64 low_high = (a.low >> 32) * (b & 0xFFFFFFFF);
u64 high_low = (a.low & 0xFFFFFFFF) * (b >> 32);
u64 high_high = (a.low >> 32) * (b >> 32);
// Combine partial products for the lower 64 bits
u64 carry = (low_low >> 32) + (low_high & 0xFFFFFFFF) + (high_low & 0xFFFFFFFF);
result.low = (low_low & 0xFFFFFFFF) | (carry << 32);
// Add carry from lower to the high product
result.high = a.high * b + (low_high >> 32) + (high_low >> 32) + (carry >> 32) + high_high;
return result;
#else
return a * b;
#endif
}
fn u64 u128_shift_right_by_64(u128 n)
{
#if defined(__TINYC__) || defined(_MSC_VER)
return n.high;
#else
return n >> 64;
#endif
}
// Lehmer's generator
// https://lemire.me/blog/2019/03/19/the-fastest-conventional-random-number-generator-that-can-pass-big-crush/
global_variable u128 rn_state;
fn u64 generate_random_number()
{
rn_state = u128_u64_mul(rn_state, 0xda942042e4dd58b5);
return u128_shift_right_by_64(rn_state);
}
fn u64 next_power_of_two(u64 n)
{
n -= 1;
n |= n >> 1;
n |= n >> 2;
n |= n >> 4;
n |= n >> 8;
n |= n >> 16;
n |= n >> 32;
n += 1;
return n;
}
fn u64 absolute_int(s64 n)
{
return n < 0 ? cast_to(u64, -n) : cast_to(u64, n);
}
fn u64 parse_decimal(String string)
{
u64 value = 0;
for (u64 i = 0; i < string.length; i += 1)
{
u8 ch = s_get(string, i);
assert(((ch >= '0') & (ch <= '9')));
value = (value * 10) + (ch - '0');
}
return value;
}
fn u8 get_next_ch_safe(String string, u64 index)
{
u64 next_index = index + 1;
u64 is_in_range = next_index < string.length;
u64 safe_index = safe_flag(next_index, is_in_range);
u8 unsafe_result = string.pointer[safe_index];
u64 safe_result = safe_flag(unsafe_result, is_in_range);
assert(safe_result < 256);
return (u8)safe_result;
}
fn u32 is_space(u8 ch, u8 next_ch)
{
u32 is_comment = (ch == '/') & (next_ch == '/');
u32 is_whitespace = ch == ' ';
u32 is_vertical_tab = ch == 0x0b;
u32 is_horizontal_tab = ch == '\t';
u32 is_line_feed = ch == '\n';
u32 is_carry_return = ch == '\r';
u32 result = (((is_vertical_tab | is_horizontal_tab) | (is_line_feed | is_carry_return)) | (is_comment | is_whitespace));
return result;
}
fn u64 is_lower(u8 ch)
{
return (ch >= 'a') & (ch <= 'z');
}
fn u64 is_upper(u8 ch)
{
return (ch >= 'A') & (ch <= 'Z');
}
fn u64 is_alphabetic(u8 ch)
{
return is_lower(ch) | is_upper(ch);
}
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();
}
}
fn u64 is_identifier_start(u8 ch)
{
u64 alphabetic = is_alphabetic(ch);
u64 is_underscore = ch == '_';
return alphabetic | is_underscore;
}
fn u64 is_identifier_ch(u8 ch)
{
u64 identifier_start = is_identifier_start(ch);
u64 decimal = is_decimal_digit(ch);
return identifier_start | decimal;
}
fn Hash64 hash_byte(Hash64 source, u8 ch)
{
source ^= ch;
source *= fnv_prime;
return source;
}
fn Hash64 hash_bytes(String bytes)
{
u64 result = fnv_offset;
for (u64 i = 0; i < bytes.length; i += 1)
{
result = hash_byte(result, bytes.pointer[i]);
}
return result;
}
fn Hash32 hash64_to_hash32(Hash64 hash64)
{
Hash32 low = hash64 & 0xffff;
Hash32 high = (hash64 >> 32) & 0xffff;
Hash32 result = (high << 16) | low;
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)
{
u64 mask = alignment - 1;
u64 result = (value + mask) & ~mask;
return result;
}
fn u64 align_backward_u64(u64 value, u64 alignment)
{
u64 result = value & ~(alignment - 1);
return result;
}
fn u8 is_power_of_two_u64(u64 value)
{
return (value & (value - 1)) == 0;
}
fn u8 first_bit_set_u32(u32 value)
{
#if _MSC_VER
DWORD result_dword;
u8 result_u8 = _BitScanForward(&result_dword, value);
unused(result_u8);
let_cast(u8, result, result_dword);
#else
let(result, (u8)__builtin_ffs((s32)value));
#endif
result -= result != 0;
return result;
}
fn u64 first_bit_set_u64(u64 value)
{
#if _MSC_VER
DWORD result_dword;
u8 result_u8 = _BitScanForward64(&result_dword, value);
unused(result_u8);
let_cast(u8, result, result_dword);
#else
let(result, (u8) __builtin_ffs((s64)value));
#endif
result -= result != 0;
return result;
}
fn Hash32 hash32_fib_end(Hash32 hash)
{
let(result, TRUNCATE(Hash32, ((hash + 1) * 11400714819323198485ull) >> 32));
return result;
}
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;
}

View File

@ -1,373 +0,0 @@
#pragma once
#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define USE_MEMCPY 1
#if _WIN32
#define _CRT_SECURE_NO_WARNINGS
#endif
#define LINK_LIBC 1
#ifndef BB_DEBUG
#define BB_DEBUG 1
#endif
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
#ifndef BB_SAFETY
#define BB_SAFETY BB_DEBUG
#endif
#define STRUCT_FORWARD_DECL(S) typedef struct S S
#define STRUCT(S) STRUCT_FORWARD_DECL(S); struct S
#define UNION_FORWARD_DECL(U) typedef union U U
#define UNION(U) UNION_FORWARD_DECL(U); union U
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#define CLAMP(a, x, b) (((a)>(x))?(a):((b)<(x))?(b):(x))
#ifdef __TINYC__
#define declare_vector_type #error
#else
#ifdef __clang__
#define declare_vector_type(T, count, name) typedef T name __attribute__((ext_vector_type(count)))
#else
#define declare_vector_type(T, count, name) typedef T name __attribute__((vector_size(count)))
#endif
#endif
#define array_length(arr) sizeof(arr) / sizeof((arr)[0])
#define KB(n) ((n) * 1024)
#define MB(n) ((n) * 1024 * 1024)
#define GB(n) ((u64)(n) * 1024 * 1024 * 1024)
#define TB(n) ((u64)(n) * 1024 * 1024 * 1024 * 1024)
#define unused(x) (void)(x)
#if _MSC_VER
#define BB_NORETURN __declspec(noreturn)
#define BB_COLD __declspec(noinline)
#elif defined(__TINYC__)
#define BB_NORETURN __attribute__((noreturn))
#define BB_COLD __attribute__((cold))
#else
#define BB_NORETURN [[noreturn]]
#define BB_COLD [[gnu::cold]]
#endif
#define TRUNCATE(Destination, source) (Destination)(source)
#if _MSC_VER
#define ENUM_START(EnumName, T) typedef T EnumName; typedef enum EnumName ## Flags
#define ENUM_END(EnumName) EnumName ## Flags
#else
#define ENUM_START(EnumName, T) typedef enum EnumName : T
#define ENUM_END(EnumName) EnumName
#endif
#define ENUM(EnumName, T, ...) \
ENUM_START(EnumName, T)\
{\
__VA_ARGS__\
} ENUM_END(EnumName)
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
#if defined (__TINYC__) || defined(_MSC_VER)
UNION(u128)
{
struct
{
u64 low;
u64 high;
};
u64 v[2];
};
#else
typedef __uint128_t u128;
#endif
typedef unsigned int uint;
typedef int8_t s8;
typedef int16_t s16;
typedef int32_t s32;
typedef int64_t s64;
#if !defined(__TINYC__) && !defined(_MSC_VER)
typedef __int128_t s128;
#endif
typedef size_t usize;
#if !defined(__TINYC__) && !defined(_MSC_VER)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpedantic"
typedef _Float16 f16;
#pragma GCC diagnostic pop
#endif
typedef float f32;
typedef double f64;
typedef u32 Hash32;
typedef u64 Hash64;
#define Slice(T) Slice_ ## T
#define SliceP(T) SliceP_ ## T
#define declare_slice_ex(T, StructName) STRUCT(StructName) \
{\
T* pointer;\
u64 length;\
}
#define declare_slice(T) declare_slice_ex(T, Slice(T))
#define declare_slice_p(T) declare_slice_ex(T*, SliceP(T))
declare_slice(u8);
declare_slice(u16);
declare_slice(u32);
declare_slice(u64);
declare_slice(s8);
declare_slice(s16);
declare_slice(s32);
declare_slice(s64);
declare_slice_p(char);
declare_slice_p(u8);
declare_slice_p(void);
typedef Slice(u8) String;
declare_slice(String);
#if BB_DEBUG
#define assert(x) (unlikely(!(x)) ? panic("Assert failed: \"" # x "\" at {cstr}:{u32}\n", __FILE__, __LINE__) : unused(0))
#else
#define assert(x) unused(likely(x))
#endif
#ifndef __cplusplus
#if _MSC_VER
#define unreachable_raw() __assume(0)
#else
#define unreachable_raw() __builtin_unreachable()
#endif
// Undefine unreachable if needed to provide a more safe-guard implementation
#ifdef unreachable
#undef unreachable
#endif
#if BB_DEBUG
#define unreachable() panic("Unreachable triggered\n", __FILE__, __LINE__)
#else
#define unreachable() unreachable_raw()
#endif
#define fix_unreachable() unreachable_raw()
#ifndef static_assert
#define static_assert(x) _Static_assert((x), "Static assert failed!")
#endif
#define alignof(x) _Alignof(x)
#else
#define restrict __restrict
#endif
#ifndef BB_INFINITY
#define BB_INFINITY __builtin_inff()
#endif
#ifndef BB_NAN
#define BB_NAN __builtin_nanf("")
#endif
#define fn static
#define method __attribute__((visibility("internal")))
#define global_variable static
#define forceinline __attribute__((always_inline))
#if _MSC_VER
#define expect(x, b) (!!(x))
#else
#define expect(x, b) __builtin_expect(!!(x), b)
#endif
#define likely(x) expect(x, 1)
#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()
fn void print(const char* format, ...);
BB_NORETURN BB_COLD fn void os_exit(u32 exit_code);
#if _MSC_VER
#define trap() __fastfail(1)
#elif __has_builtin(__builtin_trap)
#define trap() __builtin_trap()
#else
extern BB_NORETURN BB_COLD void abort(void);
fn BB_NORETURN BB_COLD void trap_ext()
{
#ifdef __x86_64__
asm volatile("ud2");
#else
abort();
#endif
}
#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 let_pointer_cast(PointerChildType, var_name, value) PointerChildType* var_name = (PointerChildType*)(value)
#if defined(__TINYC__) || defined(_MSC_VER)
#define let(name, value) typeof(value) name = (value)
#else
#define let(name, value) __auto_type name = (value)
#endif
#define let_cast(T, name, value) T name = cast_to(T, value)
#define assign_cast(to, from) to = cast_to(typeof(to), from)
#define let_va_arg(T, name, args) T name = va_arg(args, T)
#define transmute(D, source) *(D*)&source
#if BB_SAFETY
#define cast_to(T, value) (assert((typeof(value)) (T) (value) == (value) && ((value) > 0) == ((T) (value) > 0)), (T) (value))
#else
#define cast_to(T, value) (T)(value)
#endif
typedef enum Corner
{
CORNER_00,
CORNER_01,
CORNER_10,
CORNER_11,
CORNER_COUNT,
} Corner;
typedef enum Axis2
{
AXIS2_X,
AXIS2_Y,
AXIS2_COUNT,
} Axis2;
// #ifdef __cplusplus
// #define EXPORT extern "C"
// #else
// #define EXPORT
// #endif
#if defined(__cplusplus) && defined(__linux__)
#define NO_EXCEPT __THROW
#else
#define NO_EXCEPT
#endif
#define NamedEnumMemberEnum(e, enum_member) e ## _ ## enum_member
#define NamedEnumMemberString(e, enum_member) strlit(#enum_member)
typedef SliceP(char) CStringSlice;
#ifdef _WIN32
typedef void* FileDescriptor;
#else
typedef int FileDescriptor;
#endif
#define FOR_N(it, start, end) \
for (u32 it = (start), end__ = (end); it < end__; ++it)
#define FOR_REV_N(it, start, end) \
for (u32 it = (end), start__ = (start); (it--) > start__;)
#define FOR_BIT(it, start, bits) \
for (typeof(bits) _bits_ = (bits), it = (start); _bits_; _bits_ >>= 1, ++it) if (_bits_ & 1)
#define FOREACH_SET(it, set) \
FOR_N(_i, 0, ((set)->arr.capacity + 63) / 64) FOR_BIT(it, _i*64, (set)->arr.pointer[_i])
#define size_until_end(T, field_name) (sizeof(T) - offsetof(T, field_name))
#define SWAP(a, b) \
do {\
static_assert(typeof(a) == typeof(b));\
let(temp, a);\
a = b;\
b = temp;\
} while (0)
#define slice_from_pointer_range(T, start, end) (Slice(T)) { .pointer = start, .length = (u64)(end - start), }
#define strlit_len(s) (sizeof(s) - 1)
#define strlit(s) (String){ .pointer = (u8*)(s), .length = strlit_len(s), }
#define ch_to_str(ch) (String){ .pointer = &ch, .length = 1 }
#define array_to_slice(arr) { .pointer = (arr), .length = array_length(arr) }
#define array_to_bytes(arr) { .pointer = (u8*)(arr), .length = sizeof(arr) }
#define pointer_to_bytes(p) (String) { .pointer = (u8*)(p), .length = sizeof(*p) }
#define scalar_to_bytes(s) pointer_to_bytes(&(s))
#define string_to_c(s) ((char*)((s).pointer))
#define cstr(s) ((String) { .pointer = (u8*)(s), .length = strlen((char*)s), } )
#define case_to_name(prefix, e) case prefix ## e: return strlit(#e)
global_variable const u8 brace_open = '{';
global_variable const u8 brace_close = '}';
global_variable const u8 parenthesis_open = '(';
global_variable const u8 parenthesis_close = ')';
global_variable const u8 bracket_open = '[';
global_variable const u8 bracket_close = ']';
#define s_get(s, i) (s).pointer[i]
#define s_get_pointer(s, i) &((s).pointer[i])
#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 u32 format_decimal(String buffer, u64 decimal);
fn u32 format_hexadecimal(String buffer, u64 hexadecimal);
fn u64 format_float(String buffer, f64 value_double);
fn u64 is_decimal_digit(u8 ch);
fn u32 is_space(u8 ch, u8 next_ch);
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);
global_variable const Hash64 fnv_offset = 14695981039346656037ull;
global_variable const u64 fnv_prime = 1099511628211ull;
fn Hash32 hash32_fib_end(Hash32 hash);
fn Hash32 hash64_fib_end(Hash64 hash);
fn Hash64 hash_byte(Hash64 source, u8 ch);
fn Hash64 hash_bytes(String bytes);
fn Hash32 hash64_to_hash32(Hash64 hash64);
fn u64 round_up_to_next_power_of_2(u64 n);
STRUCT(TextureIndex)
{
u32 value;
};
fn u64 safe_flag(u64 value, u64 flag)
{
u64 result = value & ((u64)0 - flag);
return result;
}
#define member_from_offset(pointer, type, memory_offset) (*(type*)((u8*)pointer + memory_offset))
#if _MSC_VER
#define offset_of(T, member) offsetof(T, member)
#else
#define offset_of(T, member) __builtin_offsetof(T, member)
#endif

View File

@ -1,65 +0,0 @@
#pragma once
@implementation AppleApplicationDelegate
- (void)applicationDidFinishLaunching:(NSNotification*)aNotification
{
}
@end
@implementation AppleWindow
@end
global_variable WindowConnection window_connection;
fn u8 windowing_initialize()
{
u8 result = 1;
window_connection.application = [NSApplication sharedApplication];
AppleApplicationDelegate* application_delegate = [[AppleApplicationDelegate alloc] init];
NSApp.delegate = application_delegate;
return result;
}
fn WindowingInstance* windowing_instantiate(WindowingInstantiate instantiate)
{
NSRect rect = { { 0, 0 }, { 800, 600 } };
AppleWindow* window = [[AppleWindow alloc] initWithContentRect:rect styleMask:(NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable) backing:NSBackingStoreBuffered defer:NO];
window.title = @"Hello Metal";
[window_connection.application activate];
[window orderFrontRegardless];
return window;
}
fn WindowingSize windowing_get_instance_framebuffer_size(WindowingInstance* instance)
{
WindowingSize size;
@autoreleasepool {
const NSRect contentRect = instance.contentView.frame;
const NSRect fbRect = [instance.contentView convertRectToBacking:contentRect];
size = (WindowingSize) {
.width = fbRect.size.width,
.height = fbRect.size.height,
};
} // autoreleasepool
return size;
}
fn void windowing_poll_events()
{
@autoreleasepool {
while (1)
{
NSEvent* event = [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
if (event == nil)
{
break;
}
[NSApp sendEvent:event];
}
} // autoreleasepool
}

View File

@ -1,18 +0,0 @@
#pragma once
#import <Cocoa/Cocoa.h>
#import <QuartzCore/CAMetalLayer.h>
@interface AppleApplicationDelegate : NSObject<NSApplicationDelegate>
@end
@interface AppleWindow : NSWindow
@end
@interface AppleWindowDelegate : NSObject<NSWindowDelegate>
@end
typedef AppleWindow WindowingInstance;
STRUCT(WindowConnection)
{
NSApplication* application;
};

View File

@ -1 +0,0 @@
#pragma once

View File

@ -1 +0,0 @@
#pragma once

View File

@ -1,35 +0,0 @@
#include <std/entry_point.h>
#include <std/os.h>
#if LINK_LIBC == 0
[[gnu::naked]] BB_NORETURN void _start()
{
__asm__ __volatile__(
"\nxor %ebp, %ebp"
"\npopq %rdi"
"\nmov %rsp, %rsi"
"\nand $~0xf, %rsp"
"\npushq %rsp"
"\npushq $0"
"\ncallq static_entry_point"
"\nud2\n"
);
}
#endif
#if LINK_LIBC == 0
void static_entry_point(int argc, char* argv[])
{
char** envp = (char**)&argv[argc + 1];
#else
int main(int argc, char* argv[], char* envp[])
{
#endif
calibrate_cpu_timer();
entry_point(argc, argv, envp);
#if LINK_LIBC
return 0;
#else
syscall_exit(0);
#endif
}

View File

@ -1,11 +0,0 @@
#include <std/base.h>
void entry_point(int argc, char* argv[], char* envp[]);
#if LINK_LIBC == 0
[[gnu::naked]] BB_NORETURN void _start();
#endif
#if LINK_LIBC == 0
void static_entry_point(int argc, char* argv[]);
#endif

View File

@ -1,167 +0,0 @@
#pragma once
#include <std/font_provider.h>
#define STBTT_STATIC
#define STB_TRUETYPE_IMPLEMENTATION
#define stbtt_uint8 u8
#define stbtt_uint16 u16
#define stbtt_uint32 u32
#define stbtt_int8 s8
#define stbtt_int16 s16
#define stbtt_int32 s32
extern float sqrtf(float x);
extern float roundf(float x);
extern float floorf(float x);
extern double sqrt(double x);
extern double fabs(double x);
extern double floor(double x);
extern double ceil(double x);
extern double fmod(double x, double y);
extern double pow(double x, double y);
extern double acos(double x);
extern double cos(double x);
#define STBTT_ifloor(x) ((int) floor(x))
#define STBTT_iceil(x) ((int) ceil(x))
#define STBTT_sqrt(x) sqrt(x)
#define STBTT_pow(x,y) pow(x,y)
#define STBTT_fmod(x,y) fmod(x,y)
#define STBTT_cos(x) cos(x)
#define STBTT_acos(x) acos(x)
#define STBTT_fabs(x) fabs(x)
#define STBTT_malloc(x,u) ((void)(u),malloc(x))
#define STBTT_free(x,u) ((void)(u),free(x))
#define STBTT_assert(x) assert(x)
#define STBTT_strlen(x) strlen(x)
#define STBTT_memcpy memcpy
#define STBTT_memset memset
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#endif
#include <stb_truetype.h>
#ifdef __clang__
#pragma clang diagnostic pop
#endif
fn TextureAtlas font_texture_atlas_create(Arena* arena, Renderer* renderer, TextureAtlasCreate create)
{
let(font_file, file_read(arena, create.font_path));
stbtt_fontinfo font_info;
if (!stbtt_InitFont(&font_info, font_file.pointer, stbtt_GetFontOffsetForIndex(font_file.pointer, 0)))
{
failed_execution();
}
TextureAtlas result = {};
u32 character_count = 256;
result.characters = arena_allocate(arena, FontCharacter, character_count);
result.kerning_tables = arena_allocate(arena, s32, character_count * character_count);
result.height = (u32)sqrtf((f32)(create.text_height * create.text_height * character_count));
result.width = result.height;
result.pointer = arena_allocate(arena, u32, result.width * result.height);
let(scale_factor, stbtt_ScaleForPixelHeight(&font_info, create.text_height));
int ascent;
int descent;
int line_gap;
stbtt_GetFontVMetrics(&font_info, &ascent, &descent, &line_gap);
result.ascent = (u32)roundf(ascent * scale_factor);
result.descent = (u32)roundf(descent * scale_factor);
result.line_gap = (u32)roundf(line_gap * scale_factor);
u32 x = 0;
u32 y = 0;
u32 max_row_height = 0;
u32 first_character = ' ';
u32 last_character = '~';
for (let(i, first_character); i <= last_character; ++i)
{
u32 width;
u32 height;
int advance;
int left_bearing;
let(ch, (u8)i);
let(character, &result.characters[i]);
stbtt_GetCodepointHMetrics(&font_info, ch, &advance, &left_bearing);
character->advance = (u32)roundf(advance * scale_factor);
character->left_bearing = (u32)roundf(left_bearing * scale_factor);
u8* bitmap = stbtt_GetCodepointBitmap(&font_info, 0.0f, scale_factor, ch, (int*)&width, (int*)&height, &character->x_offset, &character->y_offset);
let(kerning_table, result.kerning_tables + i * character_count);
for (u32 j = first_character; j <= last_character; j += 1)
{
let(kerning_advance, stbtt_GetCodepointKernAdvance(&font_info, i, j));
kerning_table[j] = (s32)roundf(kerning_advance * scale_factor);
}
if (x + width > result.width)
{
y += max_row_height;
max_row_height = height;
x = 0;
}
else
{
max_row_height = MAX(height, max_row_height);
}
character->x = x;
character->y = y;
character->width = width;
character->height = height;
let(source, bitmap);
let(destination, result.pointer);
for (u32 bitmap_y = 0; bitmap_y < height; bitmap_y += 1)
{
for (u32 bitmap_x = 0; bitmap_x < width; bitmap_x += 1)
{
let(source_index, bitmap_y * width + bitmap_x);
let(destination_index, (bitmap_y + y) * result.width + (bitmap_x + x));
let(value, source[source_index]);
destination[destination_index] = ((u32)value << 24) | 0xffffff;
}
}
x += width;
stbtt_FreeBitmap(bitmap, 0);
}
result.texture = renderer_texture_create(renderer, (TextureMemory) {
.pointer = result.pointer,
.width = result.width,
.height = result.height,
.depth = 1,
.format = TEXTURE_FORMAT_R8G8B8A8_SRGB,
});
return result;
}
fn uint2 texture_atlas_compute_string_rect(String string, const TextureAtlas* atlas)
{
let(height, atlas->ascent - atlas->descent);
u32 x_offset = 0;
u32 y_offset = height;
for (u64 i = 0; i < string.length; i += 1)
{
let(ch, string.pointer[i]);
let(character, &atlas->characters[ch]);
let(kerning, (atlas->kerning_tables + ch * 256)[string.pointer[i + 1]]);
x_offset += character->advance + kerning;
}
return (uint2) { x_offset, y_offset };
}

View File

@ -1,35 +0,0 @@
#pragma once
STRUCT(FontCharacter)
{
u32 advance;
u32 left_bearing;
u32 x;
u32 y;
u32 width;
u32 height;
s32 x_offset;
s32 y_offset;
};
STRUCT(TextureAtlas)
{
u32* pointer;
FontCharacter* characters;
s32* kerning_tables;
u32 width;
u32 height;
s32 ascent;
s32 descent;
s32 line_gap;
TextureIndex texture;
};
STRUCT(TextureAtlasCreate)
{
String font_path;
u32 text_height;
};
fn TextureAtlas font_texture_atlas_create(Arena* arena, Renderer* renderer, TextureAtlasCreate create);
fn uint2 texture_atlas_compute_string_rect(String string, const TextureAtlas* atlas);

File diff suppressed because it is too large Load Diff

View File

@ -1,13 +0,0 @@
#pragma once
STRUCT(StringFormatter)
{
String buffer;
u64 index;
};
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);

View File

@ -1,26 +0,0 @@
#include <std/image_loader.h>
#define STB_IMAGE_STATIC
#define STB_IMAGE_IMPLEMENTATION
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#include <stb_image.h>
#pragma clang diagnostic pop
EXPORT TextureMemory texture_load_from_file(Arena* arena, String path)
{
auto file = file_read(arena, path);
int width;
int height;
int channels;
u8* buffer = stbi_load_from_memory(file.pointer, file.length, &width, &height, &channels, STBI_rgb_alpha);
channels += 1;
return (TextureMemory) {
.pointer = buffer,
.width = width,
.height = height,
.format = TEXTURE_FORMAT_R8G8B8A8_SRGB,
.depth = 1,
};
}

View File

@ -1,7 +0,0 @@
#pragma once
#include <std/base.h>
#include <std/os.h>
#include <std/render.h>
EXPORT TextureMemory texture_load_from_file(Arena* arena, String path);

View File

@ -1,178 +0,0 @@
#include <std/md5.h>
STRUCT(MD5Context)
{
u32 buffer[4];
u8 input[64];
u64 size;
};
// Took from: https://github.com/Zunawe/md5-c
#define MD5_A 0x67452301
#define MD5_B 0xefcdab89
#define MD5_C 0x98badcfe
#define MD5_D 0x10325476
#define MD5_F(X, Y, Z) ((X & Y) | (~X & Z))
#define MD5_G(X, Y, Z) ((X & Z) | (Y & ~Z))
#define MD5_H(X, Y, Z) (X ^ Y ^ Z)
#define MD5_I(X, Y, Z) (Y ^ (X | ~Z))
global_variable u32 md5_s[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
global_variable u32 md5_k[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
/*
* Padding used to make the size (in bits) of the input congruent to 448 mod 512
*/
global_variable u8 md5_padding[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
fn MD5Context md5_init()
{
return (MD5Context) {
.buffer = { MD5_A, MD5_B, MD5_C, MD5_D },
};
}
fn u32 rotate_left_u32(u32 x, u32 n)
{
return (x << n) | (x >> (32 - n));
}
fn void md5_step(u32* buffer, u32* input)
{
u32 aa = buffer[0];
u32 bb = buffer[1];
u32 cc = buffer[2];
u32 dd = buffer[3];
for (u32 i = 0; i < 64; i += 1)
{
u32 j;
u32 e;
switch (i / 16)
{
case 0:
{
e = MD5_F(bb, cc, dd);
j = i;
} break;
case 1:
{
e = MD5_G(bb, cc, dd);
j = ((i * 5) + 1) % 16;
} break;
case 2:
{
e = MD5_H(bb, cc, dd);
j = ((i * 3) + 5) % 16;
} break;
default:
{
e = MD5_I(bb, cc, dd);
j = (i * 7) % 16;
} break;
}
u32 old_dd = dd;
dd = cc;
cc = bb;
bb = bb + rotate_left_u32(aa + e + md5_k[i] + input[j], md5_s[i]);
aa = old_dd;
}
buffer[0] += aa;
buffer[1] += bb;
buffer[2] += cc;
buffer[3] += dd;
}
fn void md5_update(MD5Context* context, String input_argument)
{
u32 input_local[16];
auto offset = context->size % 64;
context->size += input_argument.length;
for (u64 i = 0; i < input_argument.length; i += 1)
{
context->input[offset] = input_argument.pointer[i];
offset += 1;
if (offset % 64 == 0)
{
// TODO: convert to little-endian in case we are big-endian?
for (u16 i = 0; i < 16; i += 1)
{
auto existing = *(u32*)&input_argument.pointer[i * 4];
input_local[i] = existing;
}
md5_step(context->buffer, input_local);
offset = 0;
}
}
}
fn MD5Result md5_end(MD5Context* context)
{
u32 input[16];
auto offset = context->size % 64;
auto padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset;
md5_update(context, (String) { .pointer = md5_padding, .length = padding_length });
context->size -= (u64)padding_length;
for (u32 i = 0; i < 14; i += 1)
{
input[i] = *(u32*)&context->input[i * 4];
}
input[14] = (u32)(context->size * 8);
input[15] = (u32)((context->size * 8) >> 32);
md5_step(context->buffer, input);
MD5Result result;
for (u32 i = 0; i < 4; i += 1)
{
result.hash[(i * 4) + 0] = (u8)((context->buffer[i] & 0x000000ff) >> 0);
result.hash[(i * 4) + 1] = (u8)((context->buffer[i] & 0x0000ff00) >> 8);
result.hash[(i * 4) + 2] = (u8)((context->buffer[i] & 0x00ff0000) >> 16);
result.hash[(i * 4) + 3] = (u8)((context->buffer[i] & 0xff000000) >> 24);
}
return result;
}
MD5Result md5_string(String string)
{
auto context = md5_init();
md5_update(&context, string);
auto result = md5_end(&context);
return result;
}

View File

@ -1,8 +0,0 @@
#include <std/base.h>
STRUCT(MD5Result)
{
u8 hash[16];
};
MD5Result md5_string(String string);

View File

@ -1,148 +0,0 @@
#pragma once
global_variable Renderer renderer_memory;
fn NSString* apple_string(String string)
{
NSString* result = [[NSString alloc] initWithBytes:string.pointer length:string.length encoding:NSUTF8StringEncoding];
return result;
}
fn Renderer* rendering_initialize(Arena* arena)
{
Renderer* renderer = &renderer_memory;
@autoreleasepool {
renderer->device = MTLCreateSystemDefaultDevice();
String shader_source = file_read(arena, strlit("bootstrap/std/shaders/rect.metal"));
NSString* apple_shader_source = apple_string(shader_source);
NSError* error = nil;
id<MTLLibrary> library = [renderer->device newLibraryWithSource: apple_shader_source options:nil error:&error];
if (!library)
{
// Inspect the error
NSLog(@"Error Domain: %@", error.domain);
NSLog(@"Error Code: %ld", (long)error.code);
NSLog(@"Localized Description: %@", error.localizedDescription);
NSDictionary *userInfo = error.userInfo;
if (userInfo) {
NSLog(@"Additional Info: %@", userInfo);
}
// Take action based on the error
if ([error.domain isEqualToString:MTLLibraryErrorDomain]) {
NSLog(@"Metal Library Compilation Error. Check the shader source.");
} else {
NSLog(@"Unexpected error occurred.");
}
}
id<MTLFunction> vertex = [library newFunctionWithName:@"vertex_main"];
id<MTLFunction> fragment = [library newFunctionWithName:@"fragment_main"];
MTLRenderPipelineDescriptor* pipeline_descriptor = [[MTLRenderPipelineDescriptor alloc] init];
pipeline_descriptor.vertexFunction = vertex;
pipeline_descriptor.fragmentFunction = fragment;
pipeline_descriptor.colorAttachments[0].pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
id<MTLRenderPipelineState> pipeline_state = [renderer->device newRenderPipelineStateWithDescriptor:pipeline_descriptor error:&error];
if (!pipeline_state)
{
// Inspect the error
NSLog(@"Error Domain: %@", error.domain);
NSLog(@"Error Code: %ld", (long)error.code);
NSLog(@"Localized Description: %@", error.localizedDescription);
NSDictionary *userInfo = error.userInfo;
if (userInfo) {
NSLog(@"Additional Info: %@", userInfo);
}
}
id<MTLCommandQueue> command_queue = [renderer->device newCommandQueue];
}
return renderer;
}
global_variable RenderWindow render_window_memory;
fn RenderWindow* rendering_initialize_window(Renderer* renderer, WindowingInstance* window)
{
RenderWindow* render_window = &render_window_memory;
CAMetalLayer* layer = [CAMetalLayer layer];
render_window->layer = layer;
layer.device = renderer->device;
layer.pixelFormat = MTLPixelFormatBGRA8Unorm_sRGB;
layer.framebufferOnly = true;
layer.frame = window.frame;
window.contentView.layer = layer;
window.opaque = true;
window.backgroundColor = nil;
return render_window;
}
fn void renderer_window_frame_begin(Renderer* renderer, RenderWindow* window)
{
@autoreleasepool {
id<CAMetalDrawable> drawable = [window->layer nextDrawable];
MTLRenderPassDescriptor* render_pass_descriptor = [MTLRenderPassDescriptor renderPassDescriptor];
MTLRenderPassColorAttachmentDescriptor* color_attachment = render_pass_descriptor.colorAttachments[0];
color_attachment.clearColor = MTLClearColorMake(1, 1, 1, 1);
color_attachment.storeAction = MTLStoreActionStore;
color_attachment.texture = drawable.texture;
id<MTLCommandBuffer> command_buffer = [renderer->command_queue commandBuffer];
id<MTLRenderCommandEncoder> render_command_encoder = [command_buffer renderCommandEncoderWithDescriptor:render_pass_descriptor];
[render_command_encoder setRenderPipelineState: renderer->pipeline_state];
[render_command_encoder drawPrimitives:MTLPrimitiveTypeTriangle vertexStart:0 vertexCount:3];
[render_command_encoder endEncoding];
[command_buffer presentDrawable:drawable];
[command_buffer commit];
}
}
fn void renderer_window_frame_end(Renderer* renderer, RenderWindow* window)
{
// todo();
}
fn TextureIndex renderer_texture_create(Renderer* renderer, TextureMemory texture_memory)
{
todo();
}
fn void window_rect_texture_update_begin(RenderWindow* window)
{
todo();
}
fn void renderer_queue_font_update(Renderer* renderer, RenderWindow* window, RenderFontType type, TextureAtlas atlas)
{
todo();
}
fn void window_queue_rect_texture_update(RenderWindow* window, RectTextureSlot slot, TextureIndex texture_index)
{
todo();
}
fn void window_rect_texture_update_end(Renderer* renderer, RenderWindow* window)
{
todo();
}
fn void window_render_rect(RenderWindow* window, RectDraw draw)
{
// todo();
}
fn void window_render_text(Renderer* renderer, RenderWindow* window, String string, float4 color, RenderFontType font_type, u32 x_offset, u32 y_offset)
{
// todo();
}

View File

@ -1,16 +0,0 @@
#pragma once
#import <Metal/Metal.h>
STRUCT(Renderer)
{
id<MTLDevice> device;
id<MTLCommandQueue> command_queue;
id<MTLRenderPipelineState> pipeline_state;
};
STRUCT(RenderWindow)
{
CAMetalLayer* layer;
};

File diff suppressed because it is too large Load Diff

View File

@ -1,195 +0,0 @@
#pragma once
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <errno.h>
#ifdef _WIN32
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
#else
#include <dlfcn.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <sys/time.h>
#include <sys/ptrace.h>
#endif
typedef enum TimeUnit
{
TIME_UNIT_NANOSECONDS,
TIME_UNIT_MICROSECONDS,
TIME_UNIT_MILLISECONDS,
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)
{
u128 value;
};
STRUCT(OSFileOpenFlags)
{
u32 truncate:1;
u32 executable:1;
u32 write:1;
u32 read:1;
u32 create:1;
u32 directory:1;
};
STRUCT(OSFilePermissions)
{
u8 readable:1;
u8 writable:1;
u8 executable:1;
};
STRUCT(OSReserveProtectionFlags)
{
u32 read:1;
u32 write:1;
u32 execute:1;
u32 reserved:29;
};
STRUCT(OSReserveMapFlags)
{
u32 priv:1;
u32 anon:1;
u32 populate:1;
u32 noreserve:1;
u32 reserved:29;
};
STRUCT(Arena)
{
u64 reserved_size;
u64 position;
u64 os_position;
u64 granularity;
u8 reserved[4 * 8];
};
STRUCT(FileWriteOptions)
{
String path;
String content;
u64 executable:1;
};
#ifndef __APPLE__
#define MY_PAGE_SIZE KB(4)
#else
#define MY_PAGE_SIZE KB(16)
#endif
global_variable const u64 page_size = MY_PAGE_SIZE;
global_variable u64 minimum_granularity = MY_PAGE_SIZE;
// global_variable u64 middle_granularity = MB(2);
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 String file_read(Arena* arena, String path);
fn void file_write(FileWriteOptions options);
fn String path_dir(String string);
fn String path_base(String string);
fn String path_no_extension(String string);
fn Arena* arena_initialize(u64 reserved_size, u64 granularity, u64 initial_size);
fn Arena* arena_initialize_default(u64 initial_size);
fn void arena_clear(Arena* arena);
fn String arena_join_string(Arena* arena, Slice(String) pieces);
fn u8* arena_allocate_bytes(Arena* arena, u64 size, u64 alignment);
fn void arena_reset(Arena* arena);
#define arena_allocate(arena, T, count) (T*)(arena_allocate_bytes(arena, sizeof(T) * count, alignof(T)))
#define arena_allocate_slice(arena, T, count) (Slice(T)){ .pointer = arena_allocate(arena, T, count), .length = count }
fn u8* os_reserve(u64 base, u64 size, OSReserveProtectionFlags protection, OSReserveMapFlags map);
fn void os_commit(void* address, u64 size);
fn u8 os_file_descriptor_is_valid(FileDescriptor fd);
fn FileDescriptor os_file_open(String path, OSFileOpenFlags flags, OSFilePermissions permissions);
fn void os_file_close(FileDescriptor fd);
fn u64 os_file_get_size(FileDescriptor fd);
fn void os_file_write(FileDescriptor fd, String content);
fn FileDescriptor os_stdout_get();
fn void os_directory_make(String path);
BB_NORETURN BB_COLD fn void os_exit(u32 exit_code);
fn void calibrate_cpu_timer();
fn void print_string(String string);
fn Timestamp os_timestamp();
fn f64 os_resolve_timestamps(Timestamp start, Timestamp end, TimeUnit time_unit);
fn u8 os_is_being_debugged();
#if _WIN32
typedef void* HANDLE;
fn HANDLE os_windows_get_module_handle();
#endif
#if _WIN32
#define EXECUTABLE_EXTENSION ".exe"
#else
#define EXECUTABLE_EXTENSION ""
#endif
STRUCT(OSLibrary)
{
void* handle;
};
typedef void* OSSymbol;
fn OSLibrary os_library_load(const char* library_name);
fn OSSymbol os_symbol_load(OSLibrary library, const char* symbol_name);

View File

@ -1,60 +0,0 @@
#pragma once
#ifndef BUILD_DIR
#define BUILD_DIR "cache"
#endif
typedef enum RenderingBackend
{
RENDERING_BACKEND_NONE,
RENDERING_BACKEND_METAL,
RENDERING_BACKEND_VULKAN,
RENDERING_BACKEND_DIRECTX12,
RENDERING_BACKEND_COUNT,
} RenderingBackend;
typedef enum WindowingBackend
{
WINDOWING_BACKEND_NONE,
WINDOWING_BACKEND_WIN32,
WINDOWING_BACKEND_X11,
WINDOWING_BACKEND_WAYLAND,
WINDOWING_BACKEND_COCOA,
WINDOWING_BACKEND_COUNT,
} WindowingBackend;
fn u8 rendering_backend_is_valid(RenderingBackend rendering_backend)
{
u8 valid = rendering_backend != RENDERING_BACKEND_COUNT;
if (valid && rendering_backend != RENDERING_BACKEND_NONE)
{
#ifdef __linux__
valid = rendering_backend == RENDERING_BACKEND_VULKAN;
#elif defined(__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;
#endif
}
return valid;
}
fn u8 windowing_backend_is_valid(WindowingBackend windowing_backend)
{
u8 valid = windowing_backend != WINDOWING_BACKEND_COUNT;
if (valid && windowing_backend != WINDOWING_BACKEND_NONE)
{
#ifdef __linux__
valid = windowing_backend == WINDOWING_BACKEND_WAYLAND || windowing_backend == WINDOWING_BACKEND_X11;
#elif _WIN32
valid = windowing_backend == WINDOWING_BACKEND_WIN32;
#elif __APPLE__
valid = windowing_backend == WINDOWING_BACKEND_COCOA;
#endif
}
return valid;
}

View File

@ -1,15 +0,0 @@
#pragma once
#include <std/font_provider.c>
#if BB_RENDERING_BACKEND_VULKAN
#include <std/vulkan_rendering.c>
#endif
#if BB_RENDERING_BACKEND_METAL
#include <std/metal_rendering.c>
#endif
#if BB_RENDERING_BACKEND_DIRECTX12
#include <std/directx12_rendering.c>
#endif

View File

@ -1,334 +0,0 @@
#pragma once
#if BB_RENDERING_BACKEND_VULKAN
#include <std/vulkan_rendering.h>
#endif
#if BB_RENDERING_BACKEND_METAL
#include <std/metal_rendering.h>
#endif
#if BB_RENDERING_BACKEND_DIRECTX12
#include <std/directx12_rendering.h>
#endif
#ifdef __clang__
#define BB_HAS_NATIVE_FLOAT2 1
#define BB_HAS_NATIVE_FLOAT3 1
#define BB_HAS_NATIVE_FLOAT4 1
#define BB_HAS_NATIVE_UINT2 1
#define BB_HAS_NATIVE_UINT3 1
#define BB_HAS_NATIVE_UINT4 1
#else
#define BB_HAS_NATIVE_FLOAT2 0
#define BB_HAS_NATIVE_FLOAT3 0
#define BB_HAS_NATIVE_FLOAT4 0
#define BB_HAS_NATIVE_UINT2 0
#define BB_HAS_NATIVE_UINT3 0
#define BB_HAS_NATIVE_UINT4 0
#endif
#if BB_HAS_NATIVE_FLOAT2
declare_vector_type(float, 2, float2);
#else
UNION(float2)
{
struct
{
float x, y;
};
float v[2];
};
#endif
#if BB_HAS_NATIVE_FLOAT3
declare_vector_type(float, 3, float3);
#else
UNION(float3)
{
struct
{
float x, y, z;
};
float v[3];
};
#endif
#if BB_HAS_NATIVE_FLOAT4
declare_vector_type(float, 4, float4);
#else
UNION(float4)
{
struct
{
float x, y, z, w;
};
float v[4];
};
#endif
#if BB_HAS_NATIVE_UINT2
declare_vector_type(uint, 2, uint2);
#else
UNION(uint2)
{
struct
{
uint x, y;
};
uint v[2];
};
#endif
#if BB_HAS_NATIVE_UINT3
declare_vector_type(uint, 3, uint3);
#else
UNION(uint3)
{
struct
{
uint x, y, z;
};
uint v[3];
};
#endif
#if BB_HAS_NATIVE_UINT4
declare_vector_type(uint, 4, uint4);
#else
UNION(uint4)
{
struct
{
uint x, y, z, w;
};
uint v[4];
};
#endif
typedef float2 vec2;
typedef float3 vec3;
typedef float4 vec4;
#if BB_HAS_NATIVE_FLOAT2
#define VEC2(_x, y) ((vec2){_x, _y})
#else
#define VEC2(_x, _y) ((vec2){ .x = _x, .y = _y})
#endif
#if BB_HAS_NATIVE_FLOAT3
#define VEC3(_x, _y, _z) ((vec3){_x, _y, _z})
#else
#define VEC3(_x, _y, _z) ((vec3){ .x = _x, .y = _y, .z = _z})
#endif
#if BB_HAS_NATIVE_FLOAT4
#define VEC4(_x, _y, _z, _w) ((vec4){_x, _y, _z, _w})
#else
#define VEC4(_x, _y, _z, _w) ((vec4){ .x = _x, .y = _y, .z = _z, .w = _w})
#endif
fn float2 float2_add(float2 a, float2 b)
{
#if BB_HAS_NATIVE_FLOAT2
return a + b;
#else
float2 result;
result.x = a.x + b.x;
result.y = a.y + b.y;
return result;
#endif
}
fn float2 float2_sub(float2 a, float2 b)
{
#if BB_HAS_NATIVE_FLOAT2
return a - b;
#else
float2 result;
result.x = a.x - b.x;
result.y = a.y - b.y;
return result;
#endif
}
UNION(F32Interval2)
{
struct
{
vec2 min;
vec2 max;
};
struct
{
float2 p0;
float2 p1;
};
struct
{
f32 x0;
f32 y0;
f32 x1;
f32 y1;
};
float2 v[2];
};
static_assert(sizeof(F32Interval2) == 4 * sizeof(f32));
typedef struct Renderer Renderer;
typedef struct RenderWindow RenderWindow;
typedef struct Pipeline Pipeline;
STRUCT(RectDraw)
{
F32Interval2 vertex;
F32Interval2 texture;
vec4 colors[4];
u32 texture_index;
};
#include "../std/shaders/rect.inc"
typedef struct RectVertex RectVertex;
decl_vb(RectVertex);
typedef enum BBPipeline
{
BB_PIPELINE_RECT,
BB_PIPELINE_COUNT,
} BBPipeline;
typedef enum RenderFontType
{
RENDER_FONT_TYPE_MONOSPACE,
RENDER_FONT_TYPE_PROPORTIONAL,
RENDER_FONT_TYPE_COUNT,
} RenderFontType;
typedef enum RectTextureSlot
{
RECT_TEXTURE_SLOT_WHITE,
RECT_TEXTURE_SLOT_MONOSPACE_FONT,
RECT_TEXTURE_SLOT_PROPORTIONAL_FONT,
RECT_TEXTURE_SLOT_COUNT
} RectTextureSlot;
typedef enum TextureFormat
{
TEXTURE_FORMAT_R8_UNORM,
TEXTURE_FORMAT_R8G8B8A8_SRGB,
} TextureFormat;
STRUCT(TextureMemory)
{
void* pointer;
u32 width;
u32 height;
u32 depth;
TextureFormat format;
};
ENUM(ShaderStage, u8,
SHADER_STAGE_VERTEX,
SHADER_STAGE_FRAGMENT,
);
STRUCT(PipelineCreate)
{
Slice(u16) shader_source_indices;
u16 layout_index;
};
declare_slice(PipelineCreate);
STRUCT(PushConstantRange)
{
u16 offset;
u16 size;
ShaderStage stage;
};
declare_slice(PushConstantRange);
ENUM(DescriptorType, u8,
DESCRIPTOR_TYPE_IMAGE_PLUS_SAMPLER,
DESCRIPTOR_TYPE_COUNT,
);
STRUCT(DescriptorSetLayoutBinding)
{
u8 binding;
DescriptorType type;
ShaderStage stage;
u8 count;
};
declare_slice(DescriptorSetLayoutBinding);
STRUCT(DescriptorSetLayoutCreate)
{
Slice(DescriptorSetLayoutBinding) bindings;
};
declare_slice(DescriptorSetLayoutCreate);
STRUCT(PipelineLayoutCreate)
{
Slice(PushConstantRange) push_constant_ranges;
Slice(DescriptorSetLayoutCreate) descriptor_set_layouts;
};
declare_slice(PipelineLayoutCreate);
STRUCT(GraphicsPipelinesCreate)
{
Slice(String) shader_binaries;
Slice(PipelineLayoutCreate) layouts;
Slice(PipelineCreate) pipelines;
};
STRUCT(PipelineIndex)
{
u32 value;
};
STRUCT(PipelineLayoutIndex)
{
u32 value;
};
STRUCT(DescriptorSetIndex)
{
u32 value;
};
ENUM(BufferType, u8,
BUFFER_TYPE_VERTEX,
BUFFER_TYPE_INDEX,
BUFFER_TYPE_STAGING,
);
STRUCT(HostBufferCopy)
{
String source;
u64 destination_offset;
};
declare_slice(HostBufferCopy);
STRUCT(LocalBufferCopyRegion)
{
u64 source_offset;
u64 destination_offset;
u64 size;
};
declare_slice(LocalBufferCopyRegion);
#include <std/font_provider.h>
fn Renderer* rendering_initialize(Arena* arena);
fn RenderWindow* rendering_initialize_window(Renderer* renderer, WindowingInstance* window);
fn void renderer_window_frame_begin(Renderer* renderer, RenderWindow* window);
fn void renderer_window_frame_end(Renderer* renderer, RenderWindow* window);
fn TextureIndex renderer_texture_create(Renderer* renderer, TextureMemory texture_memory);
fn void window_rect_texture_update_begin(RenderWindow* window);
fn void renderer_queue_font_update(Renderer* renderer, RenderWindow* window, RenderFontType type, TextureAtlas atlas);
fn void window_queue_rect_texture_update(RenderWindow* window, RectTextureSlot slot, TextureIndex texture_index);
fn void window_rect_texture_update_end(Renderer* renderer, RenderWindow* window);
fn void window_render_rect(RenderWindow* window, RectDraw draw);
fn void window_render_text(Renderer* renderer, RenderWindow* window, String string, float4 color, RenderFontType font_type, u32 x_offset, u32 y_offset);

View File

@ -1,163 +0,0 @@
#include <std/sha1.h>
// https://github.com/jasinb/sha1.git
// STRUCT(Sha1Digest)
// {
// u32 digest[5];
// };
// static uint32_t rotl32(uint32_t x, int b)
// {
// return (x << b) | (x >> (32-b));
// }
//
// switch endianness
// fn u32 sha1_get32(u8* p)
// {
// return (p[0] << 24) | (p[1] << 16) | (p[2] << 8) | p[3];
// }
// fn u32 sha1_f(int t, u32 b, u32 c, u32 d)
// {
// assert(0 <= t && t < 80);
//
// if (t < 20)
// {
// return (b & c) | ((~b) & d);
// }
// else if (t < 40)
// {
// return b ^ c ^ d;
// }
// else if (t < 60)
// {
// return (b & c) | (b & d) | (c & d);
// }
// else
// //if (t < 80)
// {
// return b ^ c ^ d;
// }
// }
// STRUCT(Sha1Context)
// {
// u8 block[64];
// u32 h[5];
// u64 bytes;
// u32 cur;
// };
// fn void sha1_reset(Sha1Context* ctx)
// {
// ctx->h[0] = 0x67452301;
// ctx->h[1] = 0xefcdab89;
// ctx->h[2] = 0x98badcfe;
// ctx->h[3] = 0x10325476;
// ctx->h[4] = 0xc3d2e1f0;
// ctx->bytes = 0;
// ctx->cur = 0;
// }
// fn void sha1_process_block(Sha1Context* ctx)
// {
// global_variable const u32 k[4] =
// {
// 0x5A827999,
// 0x6ED9EBA1,
// 0x8F1BBCDC,
// 0xCA62C1D6
// };
//
// u32 w[16];
// u32 a = ctx->h[0];
// u32 b = ctx->h[1];
// u32 c = ctx->h[2];
// u32 d = ctx->h[3];
// u32 e = ctx->h[4];
// u32 t;
//
// for (t = 0; t < 16; t++)
// w[t] = sha1_get32((u8*)(&((uint32_t*)ctx->block)[t]));
//
// for (t = 0; t < 80; t++)
// {
// auto s = t & 0xf;
// u32 temp;
// if (t >= 16)
// w[s] = rotate_left_u32(w[(s + 13) & 0xf] ^ w[(s + 8) & 0xf] ^ w[(s + 2) & 0xf] ^ w[s], 1);
//
// temp = rotate_left_u32(a, 5) + sha1_f(t, b,c,d) + e + w[s] + k[t/20];
//
// e = d; d = c; c = rotate_left_u32(b, 30); b = a; a = temp;
// }
//
// ctx->h[0] += a;
// ctx->h[1] += b;
// ctx->h[2] += c;
// ctx->h[3] += d;
// ctx->h[4] += e;
// }
// fn void sha1_write(Sha1Context* ctx, String bytes)
// {
// auto length = bytes.length;
// ctx->bytes += length;
//
// const uint8_t* src = bytes.pointer;
// while (length--)
// {
// // TODO: could optimize the first and last few bytes, and then copy
// // 128 bit blocks with SIMD in between
// ctx->block[ctx->cur++] = *src++;
// if (ctx->cur == 64)
// {
// sha1_process_block(ctx);
// ctx->cur = 0;
// }
// }
// }
// fn Sha1Digest sha1_get_digest(Sha1Context* ctx)
// {
// // append separator
// ctx->block[ctx->cur++] = 0x80;
// if (ctx->cur > 56)
// {
// // no space in block for the 64-bit message length, flush
// memset(&ctx->block[ctx->cur], 0, 64 - ctx->cur);
// sha1_process_block(ctx);
// ctx->cur = 0;
// }
//
// memset(&ctx->block[ctx->cur], 0, 56 - ctx->cur);
// uint64_t bits = ctx->bytes * 8;
//
// // TODO a few instructions could be shaven
// ctx->block[56] = (uint8_t)(bits >> 56 & 0xff);
// ctx->block[57] = (uint8_t)(bits >> 48 & 0xff);
// ctx->block[58] = (uint8_t)(bits >> 40 & 0xff);
// ctx->block[59] = (uint8_t)(bits >> 32 & 0xff);
// ctx->block[60] = (uint8_t)(bits >> 24 & 0xff);
// ctx->block[61] = (uint8_t)(bits >> 16 & 0xff);
// ctx->block[62] = (uint8_t)(bits >> 8 & 0xff);
// ctx->block[63] = (uint8_t)(bits >> 0 & 0xff);
// sha1_process_block(ctx);
//
// {
// Sha1Digest ret;
// int i;
// for (i = 0; i < 5; i++)
// ret.digest[i] = sha1_get32((u8*)&ctx->h[i]);
// sha1_reset(ctx);
// return ret;
// }
// }
// fn Sha1Digest sha1_compute(String bytes)
// {
// Sha1Context ctx;
// sha1_reset(&ctx);
// sha1_write(&ctx, bytes);
// return sha1_get_digest(&ctx);
// }

View File

View File

@ -1,43 +0,0 @@
#version 450
#extension GL_EXT_nonuniform_qualifier : require
#extension GL_EXT_debug_printf : require
#extension GL_GOOGLE_include_directive : require
#include "rect.inc"
layout (location = 0) in flat uint texture_index;
layout (location = 1) in RectFragmentShaderInput inputs;
layout (location = 0) out vec4 color;
layout(set = 0, binding = 0) uniform sampler2D textures[];
float rounded_rect_sdf(vec2 position, vec2 center, vec2 half_size, float radius)
{
vec2 r2 = vec2(radius, radius);
// This is 0 when the point is at the border
vec2 d2_no_r2 = abs(center - position) - half_size;
vec2 d2 = d2_no_r2 + r2;
// 0 when outside the rectangle
float negative_euclidean_distance = min(max(d2.x, d2.y), 0.0);
// 0 when inside the rectangle
float positive_euclidean_distance = length(max(d2, 0.0));
float result = negative_euclidean_distance + positive_euclidean_distance - radius;
return result;
}
void main()
{
// WARN: do not cache nonuniformEXT indexing
vec2 texture_size = textureSize(textures[nonuniformEXT(texture_index)], 0);
vec2 uv = vec2(inputs.uv.x / texture_size.x, inputs.uv.y / texture_size.y);
// WARN: do not cache nonuniformEXT indexing
vec4 sampled = texture(textures[nonuniformEXT(texture_index)], uv);
float softness = inputs.softness;
float softness_padding_scalar = max(0, softness * 2 - 1);
vec2 softness_padding = vec2(softness_padding_scalar, softness_padding_scalar);
float distance = rounded_rect_sdf(inputs.position, inputs.center, inputs.half_size - softness_padding, inputs.corner_radius);
float sdf_factor = 1.0 - smoothstep(0, 2 * softness, distance);
color = inputs.color * sampled * sdf_factor;
}

View File

@ -1,22 +0,0 @@
struct RectVertex
{
vec2 p0;
vec2 uv0;
vec2 extent;
float corner_radius;
float softness;
vec4 colors[4];
uint texture_index;
uint reserved[3];
};
struct RectFragmentShaderInput
{
vec4 color;
vec2 uv;
vec2 position;
vec2 center;
vec2 half_size;
float corner_radius;
float softness;
};

View File

@ -1,122 +0,0 @@
#include <metal_stdlib>
using namespace metal;
// Structs to match buffer data
struct RectVertex
{
float2 p0; // Bottom-left corner position
float2 extent; // Rectangle size (width and height)
float2 uv0; // UV coordinates for bottom-left
float corner_radius; // Corner radius
float softness; // Edge softness
float4 colors[4]; // Per-vertex colors
uint texture_index; // Texture index
};
struct RectFragmentShaderInput
{
float4 vertex_position [[position]];
float4 color; // Vertex color
float2 uv; // UV coordinates
float2 position; // Position in world space
float2 center; // Center of the rectangle
float2 half_size; // Half dimensions of the rectangle
float corner_radius; // Corner radius
float softness; // Edge softness
};
// Push constants (Metal uses constant buffers or argument buffers for this)
struct PushConstants
{
device const RectVertex* vertex_buffer;
float width; // Screen width
float height; // Screen height
};
// Vertex shader main function
vertex RectFragmentShaderInput vertex_main(const device PushConstants& push_constants [[buffer(0)]], uint vertex_id [[vertex_id]])
{
// Constants for normalized quad corners
constexpr float2 vertices[] = {
float2(-1.0, -1.0),
float2( 1.0, -1.0),
float2(-1.0, 1.0),
float2( 1.0, 1.0)
};
// Fetch the vertex data from the buffer
const RectVertex v = push_constants.vertex_buffer[vertex_id / 4];
// Rectangle calculations
float2 p0 = v.p0;
float2 p1 = p0 + v.extent;
float2 position_center = (p1 + p0) * 0.5;
float2 half_size = (p1 - p0) * 0.5;
float2 position = vertices[vertex_id % 4] * half_size + position_center;
// Screen-space transformation
float2 ndc_position = float2(2.0 * position.x / push_constants.width - 1.0,
2.0 * position.y / push_constants.height - 1.0);
// Texture UV calculations
float2 uv0 = v.uv0;
float2 uv1 = uv0 + v.extent;
float2 texture_center = (uv1 + uv0) * 0.5;
float2 uv = vertices[vertex_id % 4] * half_size + texture_center;
// Output to fragment shader
RectFragmentShaderInput out_data;
out_data.color = v.colors[vertex_id % 4];
out_data.uv = uv;
out_data.position = position;
out_data.vertex_position = float4(ndc_position.x, ndc_position.y, 0, 1);
out_data.center = position_center;
out_data.half_size = half_size;
out_data.corner_radius = v.corner_radius;
out_data.softness = v.softness;
return out_data;
}
// Uniform buffer for textures
struct FragmentUniforms
{
array<texture2d<float>, 100> textures; // Array of textures
sampler texture_sampler; // Sampler for texture sampling
};
// Calculate the signed distance field (SDF) for a rounded rectangle
float rounded_rect_sdf(float2 position, float2 center, float2 half_size, float radius)
{
float2 r2 = float2(radius, radius);
float2 d2_no_r2 = abs(center - position) - half_size;
float2 d2 = d2_no_r2 + r2;
float negative_euclidean_distance = min(max(d2.x, d2.y), 0.0);
float positive_euclidean_distance = length(max(d2, 0.0));
return negative_euclidean_distance + positive_euclidean_distance - radius;
}
// Fragment shader function
fragment float4 fragment_main(RectFragmentShaderInput inputs [[stage_in]], constant FragmentUniforms &uniforms [[buffer(0)]], uint texture_index)
{
// Texture size
float2 texture_size = float2(uniforms.textures[texture_index].get_width(), uniforms.textures[texture_index].get_height());
float2 uv = float2(inputs.uv.x / texture_size.x, inputs.uv.y / texture_size.y);
// Sample texture
float4 sampled = uniforms.textures[texture_index].sample(uniforms.texture_sampler, uv);
// Compute softness padding
float softness = inputs.softness;
float softness_padding_scalar = max(0.0, softness * 2.0 - 1.0);
float2 softness_padding = float2(softness_padding_scalar, softness_padding_scalar);
// Compute signed distance
float distance = rounded_rect_sdf(inputs.position, inputs.center, inputs.half_size - softness_padding, inputs.corner_radius);
// Compute SDF factor
float sdf_factor = 1.0 - smoothstep(0.0, 2.0 * softness, distance);
// Compute final color
return inputs.color * sampled * sdf_factor;
}

View File

@ -1,61 +0,0 @@
#version 450
#extension GL_EXT_buffer_reference : require
#extension GL_EXT_debug_printf : require
#extension GL_GOOGLE_include_directive : require
#include "rect.inc"
layout (location = 0) out uint texture_index;
layout (location = 1) out RectFragmentShaderInput outputs;
layout(buffer_reference, std430) readonly buffer VertexBuffer{
RectVertex vertices[];
};
layout(push_constant) uniform constants
{
VertexBuffer vertex_buffer;
float width;
float height;
} PushConstants;
const vec2 vertices[] = {
{ -1, -1 },
{ +1, -1 },
{ -1, +1 },
{ +1, +1 },
};
void main()
{
RectVertex v = PushConstants.vertex_buffer.vertices[gl_VertexIndex];
uint vertex_id = gl_VertexIndex % 4;
float width = PushConstants.width;
float height = PushConstants.height;
vec2 extent = v.extent;
vec2 p0 = v.p0;
vec2 p1 = p0 + extent;
vec2 position_center = (p1 + p0) / 2;
vec2 half_size = (p1 - p0) / 2;
vec2 position = vertices[vertex_id] * half_size + position_center;
//debugPrintfEXT("Vertex index: (%u). P0: (%f, %f). P1: (%f, %f). Center: (%f, %f). Half size: (%f, %f). Position: (%f, %f)\n", gl_VertexIndex, p0.x, p0.y, p1.x, p1.y, center.x, center.y, half_size.x, half_size.y, position.x, position.y);
gl_Position = vec4(2 * position.x / width - 1, 2 * position.y / height - 1, 0, 1);
vec2 uv0 = v.uv0;
vec2 uv1 = uv0 + extent;
vec2 texture_center = (uv1 + uv0) / 2;
vec2 uv = vertices[vertex_id] * half_size + texture_center;
texture_index = v.texture_index;
outputs.color = v.colors[vertex_id];
outputs.uv = uv;
outputs.position = position;
outputs.center = position_center;
outputs.half_size = half_size;
outputs.corner_radius = v.corner_radius;
outputs.softness = v.softness;
}

View File

@ -1,136 +0,0 @@
#include <std/string.h>
u64 string_first_ch(String string, u8 ch)
{
u64 result = STRING_NO_MATCH;
for (u64 i = 0; i < string.length; i += 1)
{
if (string.pointer[i] == ch)
{
result = i;
break;
}
}
return result;
}
u64 string_last_ch(String string, u8 ch)
{
u64 result = STRING_NO_MATCH;
u64 i = string.length;
while (i > 0)
{
i -= 1;
if (string.pointer[i] == ch)
{
result = i;
break;
}
}
return result;
}
u8 string_starts_with(String string, String start)
{
u8 result = 0;
if (likely(start.length <= string.length))
{
if (unlikely(start.pointer == string.pointer))
{
result = 1;
}
else
{
u64 i;
for (i = 0; i < start.length; i += 1)
{
let(start_ch, start.pointer[i]);
let(string_ch, string.pointer[i]);
if (unlikely(string_ch != start_ch))
{
break;
}
}
result = i == start.length;
}
}
return result;
}
u8 string_ends_with(String string, String end)
{
u8 result = 0;
if (likely(end.length <= string.length))
{
u64 i;
u64 offset = string.length - end.length;
for (i = 0; i < end.length; i += 1)
{
let(start_ch, end.pointer[i]);
let(string_ch, string.pointer[i + offset]);
if (unlikely(string_ch != start_ch))
{
break;
}
}
result = i == end.length;
}
return result;
}
u64 string_first_occurrence(String string, String substring)
{
u64 result = STRING_NO_MATCH;
if (substring.length < string.length)
{
for (u64 i = 0; i < string.length; i += 1)
{
if ((string.length - i) < substring.length)
{
break;
}
String s = s_get_slice(u8, string, i, i + substring.length);
if (s_equal(s, substring))
{
result = i;
break;
}
}
}
else if (unlikely(substring.length == string.length))
{
if (unlikely(string.pointer == substring.pointer))
{
result = 0;
}
else if (memcmp(string.pointer, substring.pointer, substring.length) == 0)
{
result = 0;
}
}
return result;
}
fn u64 string_last_occurrence(String string, String substring)
{
unused(string);
unused(substring);
todo();
}
fn u8 string_contains(String string, String substring)
{
return string_first_occurrence(string, substring) != STRING_NO_MATCH;
}

View File

@ -1,10 +0,0 @@
#include <std/base.h>
#define STRING_NO_MATCH UINT64_MAX
fn u64 string_first_ch(String string, u8 ch);
fn u64 string_last_ch(String string, u8 ch);
fn u8 string_starts_with(String string, String start);
fn u8 string_ends_with(String string, String end);
fn u64 string_first_occurrence(String string, String substring);
fn u64 string_last_occurrence(String string, String substring);

View File

@ -1,14 +0,0 @@
#pragma once
fn UI_Signal ui_button(String string)
{
let(widget, ui_widget_make((UI_WidgetFlags) {
.draw_text = 1,
.draw_background = 1,
.mouse_clickable = 1,
.keyboard_pressable = 1,
}, string));
UI_Signal signal = ui_signal_from_widget(widget);
return signal;
}

View File

@ -1,6 +0,0 @@
#pragma once
#include <std/base.h>
#include <std/ui_core.h>
fn UI_Signal ui_button(String string);

View File

@ -1,810 +0,0 @@
// This UI is heavily inspired by the ideas of Casey Muratori and Ryan Fleury ideas on GUI programming, to whom I am deeply grateful.
// Here are some links which helped me achieve this build
// https://www.youtube.com/watch?v=Z1qyvQsjK5Y
// https://www.rfleury.com/p/ui-part-1-the-interaction-medium
// https://www.rfleury.com/p/ui-part-2-build-it-every-frame-immediate
// https://www.rfleury.com/p/ui-part-3-the-widget-building-language
// https://www.rfleury.com/p/ui-part-4-the-widget-is-a-lie-node
// https://www.rfleury.com/p/ui-part-5-visual-content
// https://www.rfleury.com/p/ui-part-6-rendering
// https://www.rfleury.com/p/ui-part-7-where-imgui-ends
// https://www.rfleury.com/p/ui-part-8-state-mutation-jank-and
// https://www.rfleury.com/p/ui-part-9-keyboard-and-gamepad-navigation
// https://www.rfleury.com/p/ui-bonus-1-simple-single-line-text
// https://www.rfleury.com/p/codebase-walkthrough-multi-window
#pragma once
global_variable UI_State* ui_state = 0;
fn void ui_autopop(UI_State* state)
{
let(stack_end, (u32*)((u8*)&state->stacks + sizeof(state->stacks)));
let(bitset_pointer, (u64*)&state->stack_autopops);
u64 bitset_index = 0;
for (let(stack_pointer, (u32*)&state->stacks); stack_pointer != stack_end; stack_pointer += sizeof(VirtualBuffer(u8)) / sizeof(u32))
{
let(bitset, *bitset_pointer);
let(shift_value, 1 << bitset_index);
let(autopop, (bitset & shift_value) != 0);
let(mask, ~shift_value);
*bitset_pointer = bitset & mask;
let(length_pointer, stack_pointer + (offsetof(VirtualBuffer(u8), length) / sizeof(u32)));
let(current_length, *length_pointer);
assert(!autopop | current_length);
*length_pointer -= autopop;
u64 increment_bitset_element = (bitset_index > 0) & (bitset_index % 64 == 0);
bitset_pointer += increment_bitset_element;
bitset_index = increment_bitset_element ? 0 : bitset_index + 1;
}
}
fn void ui_state_select(UI_State* state)
{
ui_state = state;
}
fn UI_State* ui_state_get()
{
return ui_state;
}
fn Arena* ui_build_arena()
{
let(arena, ui_state->build_arenas[ui_state->build_count % array_length(ui_state->build_arenas)]);
return arena;
}
fn UI_Key ui_key_null()
{
UI_Key key = {};
return key;
}
fn UI_State* ui_state_allocate(Renderer* renderer, RenderWindow* window)
{
Arena* arena = arena_initialize(GB(8), MB(2), MB(2));
UI_State* state = arena_allocate(arena, UI_State, 1);
state->renderer = renderer;
state->render_window = window;
state->arena = arena;
state->widget_table.length = 4096;
state->widget_table.pointer = arena_allocate(arena, UI_WidgetSlot, state->widget_table.length);
for (u64 i = 0; i < array_length(state->build_arenas); i += 1)
{
state->build_arenas[i] = arena_initialize(GB(8), MB(2), MB(2));
}
state->stack_nulls = (UI_StateStackNulls){
.parent = 0,
.child_layout_axis = AXIS2_COUNT,
.pref_width = {},
.pref_height = {},
};
let(stack_end, (u32*)((u8*)&state->stacks + sizeof(state->stacks)));
for (let(stack_pointer, (u32*)&state->stacks); stack_pointer != stack_end; stack_pointer += sizeof(VirtualBuffer(u8)) / sizeof(u32))
{
let(length_pointer, stack_pointer + (offsetof(VirtualBuffer(u8), length) / sizeof(u32)));
assert(*length_pointer == 0);
}
return state;
}
fn u64 ui_widget_index_from_key(UI_Key key)
{
let(length, ui_state->widget_table.length);
assert(is_power_of_two(length));
return key.value & (length - 1);
}
fn String ui_text_from_key_string(String string)
{
String result = string;
String text_end_delimiter = strlit("##");
let(index, string_first_occurrence(string, text_end_delimiter));
if (index < string.length)
{
result.length = index;
}
return result;
}
fn String ui_hash_from_key_string(String string)
{
String result = string;
String hash_start_delimiter = strlit("###");
let(index, string_first_occurrence(string, hash_start_delimiter));
if (index < string.length)
{
result = s_get_slice(u8, string, index, string.length);
}
return result;
}
fn UI_Key ui_key_from_string(UI_Key seed, String string)
{
UI_Key key = ui_key_null();
if (string.length)
{
key = seed;
for (u64 i = 0; i < string.length; i += 1)
{
key.value = ((key.value << 5) + key.value) + string.pointer[i];
}
}
return key;
}
fn UI_Key ui_key_from_string_format(UI_Key seed, char* format, ...)
{
u8 buffer[256];
va_list args;
va_start(args, format);
let(string, format_string_va((String)array_to_slice(buffer), format, args));
va_end(args);
let(result, ui_key_from_string(seed, string));
return result;
}
fn u8 ui_key_equal(UI_Key a, UI_Key b)
{
return a.value == b.value;
}
fn UI_Widget* ui_widget_from_key(UI_Key key)
{
UI_Widget* result = 0;
if (!ui_key_equal(key, ui_key_null()))
{
let(index, ui_widget_index_from_key(key));
for (UI_Widget* widget = ui_state->widget_table.pointer[index].first; widget; widget = widget->hash_next)
{
if (ui_key_equal(widget->key, key))
{
result = widget;
break;
}
}
}
return result;
}
fn UI_Widget* ui_widget_make_from_key(UI_WidgetFlags flags, UI_Key key)
{
let(widget, ui_widget_from_key(key));
static let(count, 0);
count += 1;
if (widget)
{
if (widget->last_build_touched == ui_state->build_count)
{
key = ui_key_null();
widget = 0;
}
}
u8 first_frame = 0;
if (!widget)
{
let(index, ui_widget_index_from_key(key));
first_frame = 1;
widget = arena_allocate(ui_state->arena, UI_Widget, 1);
let(table_widget_slot, &ui_state->widget_table.pointer[index]);
if (!table_widget_slot->last)
{
table_widget_slot->first = widget;
table_widget_slot->last = widget;
}
else
{
table_widget_slot->last->hash_next = widget;
widget->hash_previous = table_widget_slot->last;
table_widget_slot->last = widget;
}
}
let(parent, ui_top(parent));
if (parent)
{
if (!parent->last)
{
parent->last = widget;
parent->first = widget;
}
else
{
let(previous_last, parent->last);
previous_last->next = widget;
widget->previous = previous_last;
parent->last = widget;
}
parent->child_count += 1;
widget->parent = parent;
}
else
{
ui_state->root = widget;
}
widget->key = key;
for (u64 i = 0; i < array_length(widget->background_colors); i += 1)
{
widget->background_colors[i] = ui_top(background_color);
}
widget->text_color = ui_top(text_color);
widget->flags = flags;
widget->first = 0;
widget->last = 0;
widget->last_build_touched = ui_state->build_count;
widget->pref_size[AXIS2_X] = ui_top(pref_width);
widget->pref_size[AXIS2_Y] = ui_top(pref_height);
widget->child_layout_axis = ui_top(child_layout_axis);
ui_autopop(ui_state);
return widget;
}
fn UI_Widget* ui_widget_make(UI_WidgetFlags flags, String string)
{
// TODO:
let(seed, ui_key_null());
let(hash_string, ui_hash_from_key_string(string));
let(key, ui_key_from_string(seed, hash_string));
let(widget, ui_widget_make_from_key(flags, key));
if (flags.draw_text)
{
widget->text = ui_text_from_key_string(string);
}
return widget;
}
fn UI_Widget* ui_widget_make_format(UI_WidgetFlags flags, const char* format, ...)
{
va_list args;
u8 buffer[4096];
va_start(args, format);
let(string, format_string_va((String)array_to_slice(buffer), format, args));
va_end(args);
let(result, ui_widget_make(flags, string));
return result;
}
fn UI_Signal ui_signal_from_widget(UI_Widget* widget)
{
let(rect, widget->rect);
let(mouse_position, ui_state->mouse_position);
UI_Signal signal = {
.clicked_left =
(widget->flags.mouse_clickable & (ui_state->mouse_button_events[WINDOWING_EVENT_MOUSE_LEFT].action == WINDOWING_EVENT_MOUSE_RELEASE)) &
((mouse_position.x >= rect.x0) & (mouse_position.x <= rect.x1)) &
((mouse_position.y >= rect.y0) & (mouse_position.y <= rect.y1)),
};
return signal;
}
fn void ui_stack_reset(UI_State* state)
{
let(stack_end, (u32*)((u8*)&state->stacks + sizeof(state->stacks)));
for (let(stack_pointer, (u32*)&state->stacks); stack_pointer != stack_end; stack_pointer += sizeof(VirtualBuffer(u8)) / sizeof(u32))
{
let(length_pointer, stack_pointer + (offsetof(VirtualBuffer(u8), length) / sizeof(u32)));
*length_pointer = 0;
}
}
fn UI_Size ui_pixels(u32 width, f32 strictness)
{
return (UI_Size) {
.kind = UI_SIZE_PIXEL_COUNT,
.strictness = strictness,
.value = (f32)width,
};
}
fn UI_Size ui_percentage(f32 percentage, f32 strictness)
{
return (UI_Size) {
.kind = UI_SIZE_PERCENTAGE,
.strictness = strictness,
.value = percentage,
};
}
fn UI_Size ui_em(f32 value, f32 strictness)
{
let(font_size, ui_top(font_size));
assert(font_size);
return (UI_Size) {
.kind = UI_SIZE_PIXEL_COUNT,
.strictness = strictness,
.value = value * font_size,
};
}
fn u8 ui_build_begin(WindowingInstance* window, f64 frame_time, WindowingEventQueue* event_queue)
{
ui_state->build_count += 1;
let(build_arena, ui_build_arena());
arena_reset(build_arena);
ui_state->frame_time = frame_time;
ui_state->window = window;
ui_stack_reset(ui_state);
u8 open = 1;
let(mouse_button_count, 0);
for (u32 generic_event_index = 0; open & (generic_event_index < event_queue->descriptors.length); generic_event_index += 1)
{
let(event_descriptor, event_queue->descriptors.pointer[generic_event_index]);
u32 event_index = event_descriptor.index;
switch (event_descriptor.type)
{
case WINDOWING_EVENT_TYPE_MOUSE_BUTTON:
{
let(button, event_queue->mouse_buttons.pointer[event_index]);
let(previous_button_event, ui_state->mouse_button_events[button.button]);
switch (button.event.action)
{
case WINDOWING_EVENT_MOUSE_RELAX:
unreachable();
case WINDOWING_EVENT_MOUSE_RELEASE:
{
assert(previous_button_event.action == WINDOWING_EVENT_MOUSE_PRESS);
} break;
case WINDOWING_EVENT_MOUSE_PRESS:
{
// TODO: handle properly
assert(previous_button_event.action == WINDOWING_EVENT_MOUSE_RELAX || mouse_button_count);
} break;
case WINDOWING_EVENT_MOUSE_REPEAT:
{
unreachable();
} break;
}
ui_state->mouse_button_events[button.button] = button.event;
mouse_button_count += 1;
} break;
case WINDOWING_EVENT_TYPE_WINDOW_FOCUS:
{
} break;
case WINDOWING_EVENT_TYPE_CURSOR_POSITION:
{
let(mouse_position, event_queue->cursor_positions.pointer[event_index]);
ui_state->mouse_position = (UI_MousePosition) {
.x = mouse_position.x,
.y = mouse_position.y,
};
} break;
case WINDOWING_EVENT_TYPE_CURSOR_ENTER:
{
todo();
} break;
case WINDOWING_EVENT_TYPE_WINDOW_POSITION:
{
// event_queue->window_positions.pointer[event_index];
// todo();
} break;
case WINDOWING_EVENT_TYPE_WINDOW_CLOSE:
{
open = 0;
} break;
}
}
if (open)
{
for (u64 i = 0; i < ui_state->widget_table.length; i += 1)
{
let(widget_table_element, &ui_state->widget_table.pointer[i]);
for (UI_Widget* widget = widget_table_element->first, *next = 0; widget; widget = next)
{
next = widget->hash_next;
if (ui_key_equal(widget->key, ui_key_null()) || widget->last_build_touched + 1 < ui_state->build_count)
{
// Remove from the list
if (widget->hash_previous)
{
widget->hash_previous->hash_next = widget->hash_next;
}
if (widget->hash_next)
{
widget->hash_next->hash_previous = widget->hash_previous;
}
if (widget_table_element->first == widget)
{
widget_table_element->first = widget->hash_next;
}
if (widget_table_element->last == widget)
{
widget_table_element->last = widget->hash_previous;
}
}
}
}
let(framebuffer_size, windowing_get_instance_framebuffer_size(window));
ui_push_next_only(pref_width, ui_pixels(framebuffer_size.width, 1.0f));
ui_push_next_only(pref_height, ui_pixels(framebuffer_size.height, 1.0f));
ui_push_next_only(child_layout_axis, AXIS2_Y);
let(root, ui_widget_make_format((UI_WidgetFlags) {}, "window_root_{u64}", window));
assert(!ui_state->stack_autopops.child_layout_axis);
ui_push(parent, root);
ui_push(font_size, 12);
ui_push(text_color, VEC4(0.9, 0.9, 0.02, 1));
ui_push(background_color, VEC4(0.1, 0.1, 0.1, 1));
ui_push(pref_width, ui_percentage(1.0, 0.0));
ui_push(pref_height, ui_percentage(1.0, 0.0));
// ui_push(pref_height, ui_em(1.8, 0.0));
}
return open;
}
fn void ui_compute_independent_sizes(UI_Widget* widget)
{
for (Axis2 axis = 0; axis < AXIS2_COUNT; axis += 1)
{
let(pref_size, widget->pref_size[axis]);
switch (pref_size.kind)
{
default: break; case UI_SIZE_COUNT: unreachable();
case UI_SIZE_PIXEL_COUNT:
{
#if BB_HAS_NATIVE_FLOAT2
widget->computed_size[axis] = floorf(widget->pref_size[axis].value);
#else
widget->computed_size.v[axis] = floorf(widget->pref_size[axis].value);
#endif
} break;
}
}
for (UI_Widget* child_widget = widget->first; child_widget; child_widget = child_widget->next)
{
ui_compute_independent_sizes(child_widget);
}
}
fn void ui_compute_upward_dependent_sizes(UI_Widget* widget)
{
// TODO: optimize loop out if possible
for (Axis2 axis = 0; axis < AXIS2_COUNT; axis += 1)
{
let(pref_size, widget->pref_size[axis]);
switch (pref_size.kind)
{
default: break; case UI_SIZE_COUNT: unreachable();
case UI_SIZE_PERCENTAGE:
{
for (UI_Widget* ancestor = widget->parent; ancestor; ancestor = ancestor->parent)
{
if (ancestor->pref_size[axis].kind != UI_SIZE_BY_CHILDREN)
{
#if BB_HAS_NATIVE_FLOAT2
widget->computed_size[axis] = floorf(ancestor->computed_size[axis] * widget->pref_size[axis].value);
#else
widget->computed_size.v[axis] = floorf(ancestor->computed_size.v[axis] * widget->pref_size[axis].value);
#endif
break;
}
}
} break;
}
}
for (UI_Widget* child_widget = widget->first; child_widget; child_widget = child_widget->next)
{
ui_compute_upward_dependent_sizes(child_widget);
}
}
fn void ui_compute_downward_dependent_sizes(UI_Widget* widget)
{
for (UI_Widget* child_widget = widget->first; child_widget; child_widget = child_widget->next)
{
ui_compute_downward_dependent_sizes(child_widget);
}
for (Axis2 axis = 0; axis < AXIS2_COUNT; axis += 1)
{
let(pref_size, widget->pref_size[axis]);
switch (pref_size.kind)
{
default: break; case UI_SIZE_COUNT: unreachable();
case UI_SIZE_BY_CHILDREN:
{
todo();
} break;
}
}
}
fn void ui_resolve_conflicts(UI_Widget* widget)
{
for (Axis2 axis = 0; axis < AXIS2_COUNT; axis += 1)
{
#if BB_HAS_NATIVE_FLOAT2
let(available_space, widget->computed_size[axis]);
#else
let(available_space, widget->computed_size.v[axis]);
#endif
f32 taken_space = 0;
f32 total_fixup_budget = 0;
if (!(widget->flags.v & (UI_WIDGET_FLAG_OVERFLOW_X << axis)))
{
for (UI_Widget* child_widget = widget->first; child_widget; child_widget = child_widget->next)
{
if (!(child_widget->flags.v & (UI_WIDGET_FLAG_FLOATING_X << axis)))
{
if (axis == widget->child_layout_axis)
{
#if BB_HAS_NATIVE_FLOAT2
taken_space += child_widget->computed_size[axis];
#else
taken_space += child_widget->computed_size.v[axis];
#endif
}
else
{
#if BB_HAS_NATIVE_FLOAT2
taken_space = MAX(taken_space, child_widget->computed_size[axis]);
#else
taken_space = MAX(taken_space, child_widget->computed_size.v[axis]);
#endif
}
#if BB_HAS_NATIVE_FLOAT2
let(fixup_budget_this_child, child_widget->computed_size[axis] * (1 - child_widget->pref_size[axis].strictness));
#else
let(fixup_budget_this_child, child_widget->computed_size.v[axis] * (1 - child_widget->pref_size[axis].strictness));
#endif
total_fixup_budget += fixup_budget_this_child;
}
}
let(conflict, taken_space - available_space);
if (conflict > 0 && total_fixup_budget > 0)
{
for (UI_Widget* child_widget = widget->first; child_widget; child_widget = child_widget->next)
{
if (!(child_widget->flags.v & (UI_WIDGET_FLAG_FLOATING_X << axis)))
{
#if BB_HAS_NATIVE_FLOAT2
let(fixup_budget_this_child, child_widget->computed_size[axis] * (1 - child_widget->pref_size[axis].strictness));
#else
let(fixup_budget_this_child, child_widget->computed_size.v[axis] * (1 - child_widget->pref_size[axis].strictness));
#endif
f32 fixup_size_this_child = 0;
if (axis == widget->child_layout_axis)
{
fixup_size_this_child = fixup_budget_this_child * (conflict / total_fixup_budget);
}
else
{
#if BB_HAS_NATIVE_FLOAT2
fixup_size_this_child = child_widget->computed_size[axis] - available_space;
#else
fixup_size_this_child = child_widget->computed_size.v[axis] - available_space;
#endif
}
fixup_size_this_child = CLAMP(0, fixup_size_this_child, fixup_budget_this_child);
#if BB_HAS_NATIVE_FLOAT2
child_widget->computed_size[axis] = floorf(child_widget->computed_size[axis] - fixup_size_this_child);
#else
child_widget->computed_size.v[axis] = floorf(child_widget->computed_size.v[axis] - fixup_size_this_child);
#endif
}
}
}
}
if (axis == widget->child_layout_axis)
{
f32 p = 0;
for (UI_Widget* child_widget = widget->first; child_widget; child_widget = child_widget->next)
{
if (!(child_widget->flags.v & (UI_WIDGET_FLAG_FLOATING_X << axis)))
{
#if BB_HAS_NATIVE_FLOAT2
child_widget->computed_relative_position[axis] = p;
p += child_widget->computed_size[axis];
#else
child_widget->computed_relative_position.v[axis] = p;
p += child_widget->computed_size.v[axis];
#endif
}
}
}
else
{
for (UI_Widget* child_widget = widget->first; child_widget; child_widget = child_widget->next)
{
if (!(child_widget->flags.v & (UI_WIDGET_FLAG_FLOATING_X << axis)))
{
#if BB_HAS_NATIVE_FLOAT2
child_widget->computed_relative_position[axis] = 0;
#else
child_widget->computed_relative_position.v[axis] = 0;
#endif
}
}
}
for (UI_Widget* child_widget = widget->first; child_widget; child_widget = child_widget->next)
{
let(last_relative_rect, child_widget->relative_rect);
#if BB_HAS_NATIVE_FLOAT2
child_widget->relative_rect.p0[axis] = child_widget->computed_relative_position[axis];
child_widget->relative_rect.p1[axis] = child_widget->relative_rect.p0[axis] + child_widget->computed_size[axis];
#else
child_widget->relative_rect.p0.v[axis] = child_widget->computed_relative_position.v[axis];
child_widget->relative_rect.p1.v[axis] = child_widget->relative_rect.p0.v[axis] + child_widget->computed_size.v[axis];
#endif
float2 last_corner_01 = { last_relative_rect.x0, last_relative_rect.y1 };
float2 last_corner_10 = { last_relative_rect.x1, last_relative_rect.y0 };
float2 this_corner_01 = { child_widget->relative_rect.x0, child_widget->relative_rect.y1 };
float2 this_corner_10 = { child_widget->relative_rect.x1, child_widget->relative_rect.y0 };
#if BB_HAS_NATIVE_FLOAT2
child_widget->relative_corner_delta[CORNER_00][axis] = child_widget->relative_rect.p0[axis] - last_relative_rect.p0[axis];
child_widget->relative_corner_delta[CORNER_01][axis] = this_corner_01[axis] - last_corner_01[axis];
child_widget->relative_corner_delta[CORNER_10][axis] = this_corner_10[axis] - last_corner_10[axis];
child_widget->relative_corner_delta[CORNER_11][axis] = child_widget->relative_rect.p1[axis] - last_relative_rect.p1[axis];
child_widget->rect.p0[axis] = widget->rect.p0[axis] + child_widget->relative_rect.p0[axis] - widget->view_offset[axis];
child_widget->rect.p1[axis] = child_widget->rect.p0[axis] + child_widget->computed_size[axis];
if (!(child_widget->flags.v & (UI_WIDGET_FLAG_FLOATING_X << axis)))
{
child_widget->rect.p0[axis] = floorf(child_widget->rect.p0[axis]);
child_widget->rect.p1[axis] = floorf(child_widget->rect.p1[axis]);
}
#else
child_widget->relative_corner_delta[CORNER_00].v[axis] = child_widget->relative_rect.p0.v[axis] - last_relative_rect.p0.v[axis];
child_widget->relative_corner_delta[CORNER_01].v[axis] = this_corner_01.v[axis] - last_corner_01.v[axis];
child_widget->relative_corner_delta[CORNER_10].v[axis] = this_corner_10.v[axis] - last_corner_10.v[axis];
child_widget->relative_corner_delta[CORNER_11].v[axis] = child_widget->relative_rect.p1.v[axis] - last_relative_rect.p1.v[axis];
child_widget->rect.p0.v[axis] = widget->rect.p0.v[axis] + child_widget->relative_rect.p0.v[axis] - widget->view_offset.v[axis];
child_widget->rect.p1.v[axis] = child_widget->rect.p0.v[axis] + child_widget->computed_size.v[axis];
if (!(child_widget->flags.v & (UI_WIDGET_FLAG_FLOATING_X << axis)))
{
child_widget->rect.p0.v[axis] = floorf(child_widget->rect.p0.v[axis]);
child_widget->rect.p1.v[axis] = floorf(child_widget->rect.p1.v[axis]);
}
#endif
}
for (UI_Widget* child_widget = widget->first; child_widget; child_widget = child_widget->next)
{
ui_resolve_conflicts(child_widget);
}
}
}
fn void ui_build_end()
{
// Clear release button presses
for (u32 i = 0; i < array_length(ui_state->mouse_button_events); i += 1)
{
let(event, &ui_state->mouse_button_events[i]);
if (event->action == WINDOWING_EVENT_MOUSE_RELEASE)
{
event->action = WINDOWING_EVENT_MOUSE_RELAX;
}
}
ui_pop(parent);
ui_compute_independent_sizes(ui_state->root);
ui_compute_upward_dependent_sizes(ui_state->root);
ui_compute_downward_dependent_sizes(ui_state->root);
ui_resolve_conflicts(ui_state->root);
}
STRUCT(WidgetIterator)
{
UI_Widget* next;
u32 push_count;
u32 pop_count;
};
#define ui_widget_recurse_depth_first_preorder(widget) ui_widget_recurse_depth_first((widget), offset_of(UI_Widget, next), offset_of(UI_Widget, first))
#define ui_widget_recurse_depth_first_postorder(widget) ui_widget_recurse_depth_first((widget), offset_of(UI_Widget, previous), offset_of(UI_Widget, last))
fn WidgetIterator ui_widget_recurse_depth_first(UI_Widget* widget, u64 sibling_offset, u64 child_offset)
{
WidgetIterator it = {};
let(child, member_from_offset(widget, UI_Widget*, child_offset));
if (child)
{
it.next = child;
it.push_count += 1;
}
else
{
for (UI_Widget* w = widget; w; w = w->parent)
{
let(sibling, member_from_offset(w, UI_Widget*, sibling_offset));
if (sibling)
{
it.next = sibling;
break;
}
it.pop_count += 1;
}
}
return it;
}
fn void ui_draw()
{
UI_Widget* root = ui_state->root;
UI_Widget* widget = root;
RenderWindow* window = ui_state->render_window;
Renderer* renderer = ui_state->renderer;
while (widget)
{
if (widget->flags.draw_background)
{
window_render_rect(window, (RectDraw) {
.colors = { widget->background_colors[0], widget->background_colors[1], widget->background_colors[2], widget->background_colors[3] },
.vertex = widget->rect,
});
}
if (widget->flags.draw_text)
{
window_render_text(renderer, window, widget->text, widget->text_color, RENDER_FONT_TYPE_PROPORTIONAL, widget->rect.x0, widget->rect.y0);
}
widget = ui_widget_recurse_depth_first_postorder(widget).next;
}
}

View File

@ -1,223 +0,0 @@
#pragma once
ENUM(UI_SizeKind, u8,
UI_SIZE_PIXEL_COUNT,
UI_SIZE_PERCENTAGE,
UI_SIZE_BY_CHILDREN,
UI_SIZE_COUNT,
);
STRUCT(UI_Size)
{
UI_SizeKind kind;
f32 value;
f32 strictness;
};
static_assert(sizeof(UI_Size) == 12);
decl_vb(UI_Size);
STRUCT(UI_Key)
{
u64 value;
};
STRUCT(UI_MousePosition)
{
f64 x;
f64 y;
};
ENUM(UI_WidgetFlagEnum, u64,
UI_WIDGET_FLAG_DISABLED = 1 << 0,
UI_WIDGET_FLAG_MOUSE_CLICKABLE = 1 << 1,
UI_WIDGET_FLAG_KEYBOARD_PRESSABLE = 1 << 2,
UI_WIDGET_FLAG_DRAW_TEXT = 1 << 3,
UI_WIDGET_FLAG_DRAW_BACKGROUND = 1 << 4,
UI_WIDGET_FLAG_OVERFLOW_X = 1 << 5,
UI_WIDGET_FLAG_OVERFLOW_Y = 1 << 6,
UI_WIDGET_FLAG_FLOATING_X = 1 << 7,
UI_WIDGET_FLAG_FLOATING_Y = 1 << 8,
);
UNION(UI_WidgetFlags)
{
struct
{
u64 disabled:1;
u64 mouse_clickable:1;
u64 keyboard_pressable:1;
u64 draw_text:1;
u64 draw_background:1;
u64 overflow_x:1;
u64 overflow_y:1;
u64 floating_x:1;
u64 floating_y:1;
};
u64 v;
};
static_assert(sizeof(UI_WidgetFlags) == sizeof(u64));
STRUCT(UI_Widget)
{
// Random category I temporarily introduce
String text;
UI_Widget* hash_previous;
UI_Widget* hash_next;
UI_Widget* first;
UI_Widget* last;
UI_Widget* next;
UI_Widget* previous;
UI_Widget* parent;
u64 child_count;
UI_Key key;
// Input parameters
UI_Size pref_size[AXIS2_COUNT];
Axis2 child_layout_axis;
UI_WidgetFlags flags;
// Data known after size determination happens
float2 computed_size;
float2 computed_relative_position;
// Data known after layout computation happens
F32Interval2 relative_rect;
F32Interval2 rect;
float2 relative_corner_delta[CORNER_COUNT];
// Persistent data across frames
u64 last_build_touched;
float2 view_offset;
float4 background_colors[4];
float4 text_color;
};
decl_vbp(UI_Widget);
STRUCT(UI_WidgetSlot)
{
UI_Widget* first;
UI_Widget* last;
};
declare_slice(UI_WidgetSlot);
decl_vb(Axis2);
decl_vb(float4);
STRUCT(UI_StateStackAutoPops)
{
u64 parent:1;
u64 pref_width:1;
u64 pref_height:1;
u64 child_layout_axis:1;
u64 text_color:1;
u64 background_color:1;
u64 font_size:1;
};
static_assert(sizeof(UI_StateStackAutoPops) % sizeof(u64) == 0);
STRUCT(UI_StateStackNulls)
{
UI_Widget* parent;
UI_Size pref_width;
UI_Size pref_height;
Axis2 child_layout_axis;
float4 text_color;
float4 background_color;
f32 font_size;
};
STRUCT(UI_StateStacks)
{
VirtualBufferP(UI_Widget) parent;
VirtualBuffer(UI_Size) pref_width;
VirtualBuffer(UI_Size) pref_height;
VirtualBuffer(Axis2) child_layout_axis;
VirtualBuffer(float4) text_color;
VirtualBuffer(float4) background_color;
VirtualBuffer(f32) font_size;
};
STRUCT(UI_State)
{
Arena* arena;
Arena* build_arenas[2];
Renderer* renderer;
RenderWindow* render_window;
WindowingInstance* window;
u64 build_count;
f64 frame_time;
UI_Widget* root;
UI_MousePosition mouse_position;
Slice(UI_WidgetSlot) widget_table;
UI_Widget* free_widget_list;
u64 free_widget_count;
WindowingEventMouseButtonEvent mouse_button_events[WINDOWING_EVENT_MOUSE_BUTTON_COUNT];
u8 focused:1;
UI_StateStacks stacks;
UI_StateStackNulls stack_nulls;
UI_StateStackAutoPops stack_autopops;
};
enum
{
UI_SignalFlag_ClickedLeft = (1 << 0),
};
typedef u32 UI_SignalFlags;
STRUCT(UI_Signal)
{
UI_Widget* widget;
union
{
UI_SignalFlags flags;
struct
{
u32 clicked_left:1;
u32 reserved:31;
};
};
};
#define ui_stack_autopop_set(field_name, value) ui_state->stack_autopops.field_name = (value)
#define ui_stack_push_impl(field_name, value, auto_pop_value) do \
{\
*vb_add(&ui_state->stacks.field_name, 1) = (value);\
ui_stack_autopop_set(field_name, auto_pop_value);\
} while (0)
#define ui_push(field_name, value) ui_stack_push_impl(field_name, value, 0)
#define ui_push_next_only(field_name, value) ui_stack_push_impl(field_name, value, 1)
#define ui_pop(field_name) (typeof(ui_state->stacks.field_name.pointer)) ui_pop_generic((VirtualBuffer(u8)*)&ui_state->stacks.field_name, sizeof(*ui_state->stacks.field_name.pointer))
#define ui_top(field_name) (ui_state->stacks.field_name.length ? ui_state->stacks.field_name.pointer[ui_state->stacks.field_name.length - 1] : ui_state->stack_nulls.field_name)
fn u8* ui_pop_generic(VirtualBuffer(u8)* stack, u32 element_size)
{
let(length, stack->length);
assert(length > 0);
let(next_length, length - 1);
let(index, next_length);
let(result, &stack->pointer[index * element_size]);
stack->length = next_length;
return result;
}
fn UI_State* ui_state_allocate(Renderer* renderer, RenderWindow* window);
fn void ui_state_select(UI_State* state);
fn u8 ui_build_begin(WindowingInstance* window, f64 frame_time, WindowingEventQueue* event_queue);
fn void ui_build_end();
fn void ui_draw();
fn UI_Signal ui_signal_from_widget(UI_Widget* widget);
fn UI_State* ui_state_get();
fn UI_Widget* ui_widget_make(UI_WidgetFlags flags, String string);
fn UI_Widget* ui_widget_make_format(UI_WidgetFlags flags, const char* format, ...);
fn UI_Size ui_pixels(u32 width, f32 strictness);
fn UI_Size ui_percentage(f32 percentage, f32 strictness);
fn UI_Size ui_em(f32 value, f32 strictness);

View File

@ -1,88 +0,0 @@
#pragma once
fn void vb_generic_ensure_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count)
{
u32 old_capacity = vb->capacity;
u32 wanted_capacity = vb->length + item_count;
if (old_capacity < wanted_capacity)
{
if (old_capacity == 0)
{
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(commit_size, new_page_capacity - old_page_capacity);
void* commit_pointer = vb->pointer + old_page_capacity;
os_commit(commit_pointer, commit_size);
let(new_capacity, new_page_capacity / item_size);
vb->capacity = new_capacity;
}
}
fn u8* vb_generic_add_assume_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count)
{
u32 index = vb->length;
assert(vb->capacity >= index + item_count);
vb->length = index + item_count;
return vb->pointer + (index * item_size);
}
fn u8* vb_generic_add(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count)
{
vb_generic_ensure_capacity(vb, item_size, item_count);
return vb_generic_add_assume_capacity(vb, item_size, item_count);
}
fn u8* vb_append_bytes(VirtualBuffer(u8*) vb, Slice(u8) bytes)
{
let_cast(u32, len, bytes.length);
vb_generic_ensure_capacity(vb, sizeof(u8), len);
let(pointer, vb_generic_add_assume_capacity(vb, sizeof(u8), len));
memcpy(pointer, bytes.pointer, len);
return pointer;
}
fn u32 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)
{
assert(string.pointer[string.length] == 0);
string.length += 1;
vb_copy_string(buffer, 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;
}

View File

@ -1,54 +0,0 @@
#pragma once
#include <std/base.h>
#define VirtualBuffer(T) VirtualBuffer_ ## T
#define VirtualBufferP(T) VirtualBufferPointerTo_ ## T
#define decl_vb_ex(T, StructName) \
struct StructName \
{\
T* pointer;\
u32 length;\
u32 capacity;\
};\
typedef struct StructName StructName
#define decl_vb(T) decl_vb_ex(T, VirtualBuffer(T))
#define decl_vbp(T) decl_vb_ex(T*, VirtualBufferP(T))
decl_vb(u8);
decl_vbp(u8);
decl_vb(u16);
decl_vbp(u16);
decl_vb(u32);
decl_vbp(u32);
decl_vb(s32);
decl_vbp(s32);
decl_vb(s64);
decl_vbp(s64);
decl_vb(String);
decl_vbp(char);
decl_vb(f32);
decl_vb(f64);
#define vb_size_of_element(vb) sizeof(*((vb)->pointer))
#define vb_add(vb, count) (typeof((vb)->pointer)) vb_generic_add((VirtualBuffer(u8)*)(vb), (vb_size_of_element(vb)), (count))
#define vb_add_scalar(vb, S) (S*) vb_generic_add(vb, 1, sizeof(S))
#define vb_copy_scalar(vb, s) *vb_add_scalar(vb, typeof(s)) = s
#define vb_append_struct(vb, T, s) *(vb_add_struct(vb, T)) = s
#define vb_append_one(vb, item) (typeof((vb)->pointer)) vb_generic_append((VirtualBuffer(u8)*)(vb), &(item), (vb_size_of_element(vb)), 1)
#define vb_to_bytes(vb) (Slice(u8)) { .pointer = (u8*)((vb).pointer), .length = (vb_size_of_element(vb)) * (vb).length, }
#define vb_ensure_capacity(vb, count) vb_generic_ensure_capacity((VirtualBuffer(u8)*)(vb), vb_size_of_element(vb), (count))
#define vb_copy_array(vb, arr) memcpy(vb_add(vb, array_length(arr)), arr, sizeof(arr))
#define vb_add_any_array(vb, E, count) (E*)vb_generic_add(vb, vb_size_of_element(vb), sizeof(E) * count)
#define vb_copy_any_array(vb, arr) memcpy(vb_generic_add(vb, vb_size_of_element(vb), sizeof(arr)), (arr), sizeof(arr))
#define vb_copy_any_slice(vb, slice) memcpy(vb_generic_add(vb, vb_size_of_element(vb), sizeof(*((slice).pointer)) * (slice).length), (slice).pointer, sizeof(*((slice).pointer)) * (slice).length)
fn void vb_generic_ensure_capacity(VirtualBuffer(u8)* vb, u32 item_size, u32 item_count);
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 u64 vb_copy_string_zero_terminated(VirtualBuffer(u8)* buffer, String string);
fn u64 vb_format(VirtualBuffer(u8)* vb, const char* format, ...);

File diff suppressed because it is too large Load Diff

View File

@ -1,130 +0,0 @@
#pragma once
#if BB_WINDOWING_BACKEND_X11
#define VK_USE_PLATFORM_XCB_KHR
#endif
#if BB_WINDOWING_BACKEND_COCOA
#define VK_USE_PLATFORM_METAL_EXT
#endif
#if BB_WINDOWING_BACKEND_WIN32
#define VK_USE_PLATFORM_WIN32_KHR
#endif
// Code from Volk
#ifndef VK_NO_PROTOTYPES
#define VK_NO_PROTOTYPES
#endif
#ifndef VULKAN_H_
#if defined(VK_USE_PLATFORM_WIN32_KHR)
#include <vulkan/vk_platform.h>
#include <vulkan/vulkan_core.h>
/* When VK_USE_PLATFORM_WIN32_KHR is defined, instead of including vulkan.h directly, we include individual parts of the SDK
* This is necessary to avoid including <windows.h> which is very heavy - it takes 200ms to parse without WIN32_LEAN_AND_MEAN
* and 100ms to parse with it. vulkan_win32.h only needs a few symbols that are easy to redefine ourselves.
*/
typedef unsigned long DWORD;
typedef const wchar_t* LPCWSTR;
typedef void* HANDLE;
typedef struct HINSTANCE__* HINSTANCE;
typedef struct HWND__* HWND;
typedef struct HMONITOR__* HMONITOR;
typedef struct _SECURITY_ATTRIBUTES SECURITY_ATTRIBUTES;
#include <vulkan/vulkan_win32.h>
#ifdef VK_ENABLE_BETA_EXTENSIONS
#include <vulkan/vulkan_beta.h>
#endif
#else
#include <vulkan/vulkan.h>
#endif
#endif
#define vulkan_function_pointer(n) PFN_ ## n n
#define vulkan_global_function_pointer(n) global_variable vulkan_function_pointer(n)
// INSTANCE FUNCTIONS START
// These functions require no instance
vulkan_global_function_pointer(vkGetInstanceProcAddr);
vulkan_global_function_pointer(vkEnumerateInstanceVersion);
vulkan_global_function_pointer(vkEnumerateInstanceLayerProperties);
vulkan_global_function_pointer(vkCreateInstance);
// These functions require an instance as a parameter
vulkan_global_function_pointer(vkGetDeviceProcAddr);
vulkan_global_function_pointer(vkCreateDebugUtilsMessengerEXT);
vulkan_global_function_pointer(vkEnumeratePhysicalDevices);
vulkan_global_function_pointer(vkGetPhysicalDeviceMemoryProperties);
vulkan_global_function_pointer(vkGetPhysicalDeviceProperties);
vulkan_global_function_pointer(vkGetPhysicalDeviceQueueFamilyProperties);
vulkan_global_function_pointer(vkGetPhysicalDeviceSurfaceCapabilitiesKHR);
vulkan_global_function_pointer(vkGetPhysicalDeviceSurfacePresentModesKHR);
vulkan_global_function_pointer(vkCreateDevice);
#if defined(VK_KHR_xcb_surface)
vulkan_global_function_pointer(vkCreateXcbSurfaceKHR);
#endif
#if defined(VK_KHR_win32_surface)
vulkan_global_function_pointer(vkCreateWin32SurfaceKHR);
#endif
#if defined(VK_EXT_metal_surface)
vulkan_global_function_pointer(vkCreateMetalSurfaceEXT);
#endif
// INSTANCE FUNCTIONS END
vulkan_global_function_pointer(vkCreateSwapchainKHR);
vulkan_global_function_pointer(vkCmdCopyBuffer2);
vulkan_global_function_pointer(vkAllocateMemory);
vulkan_global_function_pointer(vkCreateBuffer);
vulkan_global_function_pointer(vkGetBufferMemoryRequirements);
vulkan_global_function_pointer(vkBindBufferMemory);
vulkan_global_function_pointer(vkMapMemory);
vulkan_global_function_pointer(vkGetBufferDeviceAddress);
vulkan_global_function_pointer(vkResetFences);
vulkan_global_function_pointer(vkResetCommandBuffer);
vulkan_global_function_pointer(vkBeginCommandBuffer);
vulkan_global_function_pointer(vkEndCommandBuffer);
vulkan_global_function_pointer(vkQueueSubmit2);
vulkan_global_function_pointer(vkWaitForFences);
vulkan_global_function_pointer(vkCreateImage);
vulkan_global_function_pointer(vkGetImageMemoryRequirements);
vulkan_global_function_pointer(vkBindImageMemory);
vulkan_global_function_pointer(vkCreateImageView);
vulkan_global_function_pointer(vkCmdPipelineBarrier2);
vulkan_global_function_pointer(vkCmdBlitImage2);
vulkan_global_function_pointer(vkGetDeviceQueue);
vulkan_global_function_pointer(vkCreateCommandPool);
vulkan_global_function_pointer(vkAllocateCommandBuffers);
vulkan_global_function_pointer(vkCreateFence);
vulkan_global_function_pointer(vkCreateSampler);
vulkan_global_function_pointer(vkCreateShaderModule);
vulkan_global_function_pointer(vkCreateDescriptorSetLayout);
vulkan_global_function_pointer(vkCreatePipelineLayout);
vulkan_global_function_pointer(vkCreateGraphicsPipelines);
vulkan_global_function_pointer(vkDestroyImageView);
vulkan_global_function_pointer(vkDestroyImage);
vulkan_global_function_pointer(vkFreeMemory);
vulkan_global_function_pointer(vkDeviceWaitIdle);
vulkan_global_function_pointer(vkDestroySwapchainKHR);
vulkan_global_function_pointer(vkGetSwapchainImagesKHR);
vulkan_global_function_pointer(vkCreateDescriptorPool);
vulkan_global_function_pointer(vkAllocateDescriptorSets);
vulkan_global_function_pointer(vkCreateSemaphore);
vulkan_global_function_pointer(vkAcquireNextImageKHR);
vulkan_global_function_pointer(vkDestroyBuffer);
vulkan_global_function_pointer(vkUnmapMemory);
vulkan_global_function_pointer(vkCmdSetViewport);
vulkan_global_function_pointer(vkCmdSetScissor);
vulkan_global_function_pointer(vkCmdBeginRendering);
vulkan_global_function_pointer(vkCmdBindPipeline);
vulkan_global_function_pointer(vkCmdBindDescriptorSets);
vulkan_global_function_pointer(vkCmdBindIndexBuffer);
vulkan_global_function_pointer(vkCmdPushConstants);
vulkan_global_function_pointer(vkCmdDrawIndexed);
vulkan_global_function_pointer(vkCmdEndRendering);
vulkan_global_function_pointer(vkQueuePresentKHR);
vulkan_global_function_pointer(vkCmdCopyBufferToImage);
vulkan_global_function_pointer(vkUpdateDescriptorSets);

View File

@ -1 +0,0 @@
#pragma once

View File

@ -1 +0,0 @@
#pragma once

View File

@ -1,59 +0,0 @@
#pragma once
#pragma comment(lib, "user32")
fn LRESULT window_callback(HWND window, UINT message, WPARAM w_parameter, LPARAM l_parameter)
{
return DefWindowProcW(window, message, w_parameter, l_parameter);
}
fn u8 windowing_initialize()
{
HINSTANCE instance = GetModuleHandleW(0);
windowing_connection.instance = instance;
WNDCLASSEXW window_class = {
.cbSize = sizeof(window_class),
.lpfnWndProc = window_callback,
.hInstance = instance,
.lpszClassName = L"window",
.hCursor = LoadCursorA(0, IDC_ARROW),
.hIcon = LoadIcon(instance, MAKEINTRESOURCE(1)),
.style = CS_VREDRAW|CS_HREDRAW,
};
RegisterClassExW(&window_class);
windowing_connection.window_class = window_class;
return 1;
}
fn WindowingInstance* windowing_instantiate(WindowingInstantiate instantiate)
{
// TODO:
WindowingInstance* window = &windowing_instances[0];
window->handle = CreateWindowExW(WS_EX_APPWINDOW, L"window", L"Bloat Buster", WS_OVERLAPPEDWINDOW | WS_SIZEBOX, CW_USEDEFAULT, CW_USEDEFAULT, instantiate.size.width, instantiate.size.height, 0, 0, windowing_connection.instance, 0);
ShowWindow(window->handle, SW_SHOW);
return window;
}
fn WindowingSize windowing_get_instance_framebuffer_size(WindowingInstance* instance)
{
RECT area;
GetClientRect(instance->handle, &area);
WindowingSize size = {
.width = area.right,
.height = area.bottom,
};
return size;
}
fn void windowing_poll_events()
{
MSG msg;
HWND handle;
while (PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessageW(&msg);
}
}

View File

@ -1,13 +0,0 @@
#pragma once
STRUCT(WindowingConnection)
{
HINSTANCE instance;
WNDCLASSEXW window_class;
};
STRUCT(WindowingInstance)
{
HWND handle;
};

View File

@ -1,15 +0,0 @@
#if BB_WINDOWING_BACKEND_X11
#include <std/x11_windowing.c>
#endif
#if BB_WINDOWING_BACKEND_WAYLAND
#include <std/wayland_windowing.c>
#endif
#if BB_WINDOWING_BACKEND_COCOA
#include <std/cocoa_windowing.c>
#endif
#if BB_WINDOWING_BACKEND_WIN32
#include <std/win32_windowing.c>
#endif

View File

@ -1,206 +0,0 @@
#pragma once
#if BB_WINDOWING_BACKEND_X11
#include <std/x11_windowing.h>
#endif
#if BB_WINDOWING_BACKEND_WAYLAND
#include <std/wayland_windowing.h>
#endif
#if BB_WINDOWING_BACKEND_COCOA
#include <std/cocoa_windowing.h>
#endif
#if BB_WINDOWING_BACKEND_WIN32
#include <std/win32_windowing.h>
#endif
typedef enum WindowingEventType
{
WINDOWING_EVENT_TYPE_MOUSE_BUTTON,
WINDOWING_EVENT_TYPE_CURSOR_POSITION,
WINDOWING_EVENT_TYPE_CURSOR_ENTER,
WINDOWING_EVENT_TYPE_WINDOW_FOCUS,
WINDOWING_EVENT_TYPE_WINDOW_POSITION,
WINDOWING_EVENT_TYPE_WINDOW_CLOSE,
} WindowingEventType;
STRUCT(WindowingEventDescriptor)
{
u32 index:24;
WindowingEventType type:8;
};
static_assert(sizeof(WindowingEventDescriptor) == 4);
decl_vb(WindowingEventDescriptor);
ENUM_START(WindowingEventMouseButtonKind, u8)
{
WINDOWING_EVENT_MOUSE_BUTTON_1 = 0,
WINDOWING_EVENT_MOUSE_BUTTON_2 = 1,
WINDOWING_EVENT_MOUSE_BUTTON_3 = 2,
WINDOWING_EVENT_MOUSE_BUTTON_4 = 3,
WINDOWING_EVENT_MOUSE_BUTTON_5 = 4,
WINDOWING_EVENT_MOUSE_BUTTON_6 = 5,
WINDOWING_EVENT_MOUSE_BUTTON_7 = 6,
WINDOWING_EVENT_MOUSE_BUTTON_8 = 7,
WINDOWING_EVENT_MOUSE_LEFT = WINDOWING_EVENT_MOUSE_BUTTON_1,
WINDOWING_EVENT_MOUSE_RIGHT = WINDOWING_EVENT_MOUSE_BUTTON_2,
WINDOWING_EVENT_MOUSE_MIDDLE = WINDOWING_EVENT_MOUSE_BUTTON_3,
}
ENUM_END(WindowingEventMouseButtonKind);
#define WINDOWING_EVENT_MOUSE_BUTTON_COUNT (WINDOWING_EVENT_MOUSE_BUTTON_8 + 1)
ENUM_START(WindowingEventMouseButtonAction, u8)
{
WINDOWING_EVENT_MOUSE_RELAX = 0,
WINDOWING_EVENT_MOUSE_RELEASE = 1,
WINDOWING_EVENT_MOUSE_PRESS = 2,
WINDOWING_EVENT_MOUSE_REPEAT = 3,
} ENUM_END(WindowingEventMouseButtonAction);
STRUCT(WindowingEventMouseButtonEvent)
{
WindowingEventMouseButtonAction action:2;
u8 mod_shift:1;
u8 mod_control:1;
u8 mod_alt:1;
u8 mod_super:1;
u8 mod_caps_lock:1;
u8 mod_num_lock:1;
};
STRUCT(WindowingEventMouseButton)
{
WindowingEventMouseButtonKind button:3;
u8 reserved:5;
WindowingEventMouseButtonEvent event;
};
static_assert(sizeof(WindowingEventMouseButton) == sizeof(u16));
decl_vb(WindowingEventMouseButton);
#define WINDOWING_EVENT_BITSET_SIZE (64)
STRUCT(WindowingEventBitset)
{
u64 value;
};
decl_vb(WindowingEventBitset);
STRUCT(WindowingEventCursorPosition)
{
f64 x;
f64 y;
};
decl_vb(WindowingEventCursorPosition);
STRUCT(WindowingEventWindowPosition)
{
u32 x;
u32 y;
};
decl_vb(WindowingEventWindowPosition);
STRUCT(WindowingEventQueue)
{
VirtualBuffer(WindowingEventDescriptor) descriptors;
VirtualBuffer(WindowingEventMouseButton) mouse_buttons;
VirtualBuffer(WindowingEventBitset) window_focuses;
u32 window_focuses_count;
u32 cursor_enter_count;
VirtualBuffer(WindowingEventBitset) cursor_enters;
VirtualBuffer(WindowingEventCursorPosition) cursor_positions;
VirtualBuffer(WindowingEventWindowPosition) window_positions;
};
// typedef void OSFramebufferResize(OSWindow window, void* context, u32 width, u32 height);
// typedef void OSWindowResize(OSWindow window, void* context, u32 width, u32 height);
// typedef void OSWindowRefresh(OSWindow window, void* context);
// typedef void OSWindowPosition(OSWindow window, void* context, u32 x, u32 y);
// typedef void OSWindowClose(OSWindow window, void* context);
// typedef void OSWindowFocus(OSWindow window, void* context, u8 focused);
// typedef void OSWindowIconify(OSWindow window, void* context, u8 iconified);
// typedef void OSWindowMaximize(OSWindow window, void* context, u8 maximized);
// typedef void OSWindowContentScale(OSWindow window, void* context, f32 x, f32 y);
// typedef void OSWindowKey(OSWindow window, void* context, s32 key, s32 scancode, s32 action, s32 mods);
// typedef void OSWindowCharacter(OSWindow window, void* context, u32 codepoint);
// typedef void OSWindowCharacterModifier(OSWindow window, void* context, u32 codepoint, s32 mods);
// typedef void OSWindowMouseButton(OSWindow window, void* context, s32 button, s32 action, s32 mods);
// typedef void OSWindowCursorPosition(OSWindow window, void* context, f64 x, f64 y);
// typedef void OSWindowCursorEnter(OSWindow window, void* context, u8 entered);
// typedef void OSWindowScroll(OSWindow window, void* context, f64 x, f64 y);
// typedef void OSWindowDrop(OSWindow window, void* context, CStringSlice paths);
// STRUCT(OSWindowingCallbacks)
// {
// // OSFramebufferResize* framebuffer_resize;
// // OSWindowResize* window_resize;
// // OSWindowRefresh* window_refresh;
// // OSWindowPosition* window_position;
// // OSWindowClose* window_close;
// // OSWindowFocus* window_focus;
// // OSWindowIconify* window_iconify;
// // OSWindowMaximize* window_maximize;
// // OSWindowContentScale* window_content_scale;
// // OSWindowKey* window_key;
// // OSWindowCharacter* window_character;
// // OSWindowCharacterModifier* window_character_modifier;
// // OSWindowMouseButton* window_mouse_button;
// // OSWindowCursorPosition* window_cursor_position;
// // OSWindowCursorEnter* window_cursor_enter;
// // OSWindowScroll* window_scroll;
// // OSWindowDrop* window_drop;
// };
// STRUCT(OSWindowCreate)
// {
// String name;
// OSWindowSize size;
// void* context;
// // OSWindowResize* resize_callback;
// // OSWindowRefresh* refresh_callback;
// };
STRUCT(WindowingCursorPosition)
{
f64 x;
f64 y;
};
// NEW API START
STRUCT(WindowingOffset)
{
u32 x;
u32 y;
};
STRUCT(WindowingSize)
{
u32 width;
u32 height;
};
STRUCT(WindowingInstantiate)
{
String name;
WindowingOffset offset;
WindowingSize size;
void* context;
};
fn u8 windowing_initialize();
fn WindowingInstance* windowing_instantiate(WindowingInstantiate instantiate);
fn void windowing_poll_events();
fn WindowingSize windowing_get_instance_framebuffer_size(WindowingInstance* window);
// NEW API END
// fn OSWindow os_window_create(OSWindowCreate create);
// fn u8 os_window_should_close(OSWindow window);
// fn OSCursorPosition os_window_cursor_position_get(OSWindow window);
//
// fn u8 os_event_queue_get_window_focus(OSEventQueue* queue, u32 index);
#ifndef __APPLE__
global_variable WindowingConnection windowing_connection;
global_variable WindowingInstance windowing_instances[256];
#endif

View File

@ -1,197 +0,0 @@
#pragma once
global_variable xcb_window_t windowing_instance_handles[256];
typedef enum WindowingEvent : u32
{
WINDOWING_EVENT_CLOSE,
WINDOWING_EVENT_COUNT,
} WindowingEvent;
fn xcb_connection_t* xcb_connection_get()
{
return windowing_connection.handle;
}
fn xcb_window_t xcb_window_from_windowing_instance(WindowingInstance* instance)
{
return instance->handle;
}
fn void x11_intern_atoms(u32 atom_count, String* names, xcb_intern_atom_cookie_t* cookies, xcb_intern_atom_reply_t** replies)
{
xcb_connection_t* connection = windowing_connection.handle;
for (u64 i = 0; i < atom_count; i += 1)
{
String atom_name = names[i];
cookies[i] = xcb_intern_atom(connection, 0, atom_name.length, string_to_c(atom_name));
}
for (u64 i = 0; i < atom_count; i += 1)
{
replies[i] = xcb_intern_atom_reply(connection, cookies[i], 0);
}
}
typedef enum X11Atom
{
X11_ATOM_WM_PROTOCOLS,
X11_ATOM_WM_DELETE_WINDOW,
X11_ATOM_COUNT,
} X11Atom;
global_variable String atom_names[X11_ATOM_COUNT] = {
strlit("WM_PROTOCOLS"),
strlit("WM_DELETE_WINDOW"),
};
global_variable xcb_intern_atom_reply_t* atom_replies[array_length(atom_names)];
global_variable xcb_intern_atom_cookie_t atom_cookies[array_length(atom_names)];
fn u8 windowing_initialize()
{
u8 result = 0;
windowing_connection.handle = xcb_connect(0, 0);
if (windowing_connection.handle)
{
if (!xcb_connection_has_error(windowing_connection.handle))
{
windowing_connection.setup = xcb_get_setup(windowing_connection.handle);
if (windowing_connection.setup)
{
x11_intern_atoms(array_length(atom_names), atom_names, atom_cookies, atom_replies);
if (atom_replies[X11_ATOM_WM_PROTOCOLS])
{
if (atom_replies[X11_ATOM_WM_DELETE_WINDOW])
{
result = 1;
}
}
}
}
}
return result;
}
fn WindowingInstance* windowing_instantiate(WindowingInstantiate create)
{
xcb_connection_t* connection = windowing_connection.handle;
xcb_screen_iterator_t iter = xcb_setup_roots_iterator(windowing_connection.setup);
xcb_screen_t *screen = iter.data;
/* Create a window */
xcb_window_t window_handle = xcb_generate_id(connection);
u32 i;
for (i = 0; i < array_length(windowing_instance_handles); i += 1)
{
xcb_window_t* window_handle_pointer = &windowing_instance_handles[i];
if (!*window_handle_pointer)
{
*window_handle_pointer = window_handle;
break;
}
}
WindowingInstance* window = &windowing_instances[i];
window->handle = window_handle;
u32 value_mask = XCB_CW_BACK_PIXEL | XCB_CW_EVENT_MASK;
u32 value_list[] = {
screen->black_pixel,
XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_KEY_PRESS | XCB_EVENT_MASK_STRUCTURE_NOTIFY
};
xcb_create_window(
connection, /* Connection */
XCB_COPY_FROM_PARENT, /* Depth (same as parent) */
window_handle, /* Window ID */
screen->root, /* Parent window (root) */
create.offset.x, create.offset.y, /* X, Y */
create.size.width, create.size.height,
10, /* Border width */
XCB_WINDOW_CLASS_INPUT_OUTPUT, /* Class */
screen->root_visual, /* Visual */
value_mask, /* Value mask */
value_list /* Value list */
);
xcb_change_property(connection, XCB_PROP_MODE_REPLACE, window_handle, atom_replies[X11_ATOM_WM_PROTOCOLS]->atom, XCB_ATOM_ATOM, 32, 1, &atom_replies[X11_ATOM_WM_DELETE_WINDOW]->atom);
xcb_map_window(connection, window_handle);
/* Flush requests to the X server */
xcb_flush(connection);
return window;
}
fn void windowing_poll_events()
{
xcb_generic_event_t *event;
xcb_connection_t* connection = windowing_connection.handle;
while ((event = xcb_poll_for_event(connection)))
{
switch (event->response_type & ~0x80) {
case XCB_EXPOSE:
break;
case XCB_KEY_PRESS:
break;
case XCB_CLIENT_MESSAGE:
{
let_pointer_cast(xcb_client_message_event_t, client_message_event, event);
if (client_message_event->data.data32[0] == atom_replies[X11_ATOM_WM_DELETE_WINDOW]->atom)
{
xcb_window_t window_handle = client_message_event->window;
u32 i;
u32 window_handle_count = array_length(windowing_instance_handles);
for (i = 0; i < window_handle_count; i += 1)
{
xcb_window_t* window_handle_pointer = &windowing_instance_handles[i];
if (window_handle == *window_handle_pointer)
{
windowing_instances[i].handle = 0;
*window_handle_pointer = 0;
// TODO: For now do this
os_exit(0);
break;
}
}
if (i == window_handle_count)
{
os_exit(1);
}
}
else
{
trap();
}
} break;
case XCB_DESTROY_NOTIFY:
trap();
default:
break;
}
os_free(event);
}
}
fn WindowingSize windowing_get_instance_framebuffer_size(WindowingInstance* instance)
{
WindowingSize result = {};
xcb_connection_t* connection = windowing_connection.handle;
xcb_window_t window = instance->handle;
xcb_get_geometry_cookie_t cookie = xcb_get_geometry(connection, window);
xcb_get_geometry_reply_t* reply = xcb_get_geometry_reply(connection, cookie, 0);
result.width = reply->width;
result.height = reply->height;
os_free(reply);
return result;
}

View File

@ -1,17 +0,0 @@
#pragma once
#include <xcb/xcb.h>
STRUCT(WindowingConnection)
{
xcb_connection_t* handle;
const xcb_setup_t* setup;
};
STRUCT(WindowingInstance)
{
xcb_window_t handle;
};
fn xcb_connection_t* xcb_connection_get();
fn xcb_window_t xcb_window_from_windowing_instance(WindowingInstance* instance);

2656
build.c

File diff suppressed because it is too large Load Diff

7
ci/install.sh Executable file
View File

@ -0,0 +1,7 @@
set -eux
mkdir -p $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)
if [[ -n "${BUILD_DEBUG:-}" ]]; then
cp $HOME/bloat-buster-artifacts/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/Debug/cache/generic/debug_none_di/compiler/aggressively_optimize_for_speed_nodi/compiler $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/compiler_generic_debug
fi
cp $HOME/bloat-buster-artifacts/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/Release/cache/generic/debug_none_di/compiler/aggressively_optimize_for_speed_nodi/compiler $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/compiler_generic
cp $HOME/bloat-buster-artifacts/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/Release/cache/native/debug_none_di/compiler/aggressively_optimize_for_speed_nodi/compiler $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/compiler_native

7
ci/release.sh Executable file
View File

@ -0,0 +1,7 @@
set -eux
mkdir -p $HOME/bloat-buster-artifacts/releases/main/
if [[ -n "${BUILD_DEBUG:-}" ]]; then
cp $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/compiler_generic_debug $HOME/bloat-buster-artifacts/releases/main/
fi
cp $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/compiler_generic $HOME/bloat-buster-artifacts/releases/main/
cp $HOME/bloat-buster-artifacts/releases/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/compiler_native $HOME/bloat-buster-artifacts/releases/main/

10
ci/release_locally.sh Executable file
View File

@ -0,0 +1,10 @@
#!/usr/bin/env bash
set -eux
if [[ -n "${BUILD_DEBUG:-}" ]]; then
export BUILD_DEBUG
CMAKE_BUILD_TYPE=Debug ci/reproduce.sh
fi
CMAKE_BUILD_TYPE=Release ci/reproduce.sh
CMAKE_BUILD_TYPE=Release-assertions ci/reproduce.sh
ci/install.sh
ci/release.sh

8
ci/reproduce.sh Executable file
View File

@ -0,0 +1,8 @@
set -eux
rm -rf bb-cache self-hosted-bb-cache || true
./generate.sh
./build.sh
./build/bb test
mkdir -p $HOME/bloat-buster-artifacts/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/$CMAKE_BUILD_TYPE
mv ./self-hosted-bb-cache $HOME/bloat-buster-artifacts/$(git rev-parse --abbrev-ref HEAD)/$(git rev-parse HEAD)/$CMAKE_BUILD_TYPE/cache

View File

@ -1,3 +0,0 @@
*.o
*.obj
*.exe

View File

@ -1,37 +0,0 @@
This software is available under 2 licenses -- choose whichever you prefer.
------------------------------------------------------------------------------
ALTERNATIVE A - MIT License
Copyright (c) 2017 Sean Barrett
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
------------------------------------------------------------------------------
ALTERNATIVE B - Public Domain (www.unlicense.org)
This is free and unencumbered software released into the public domain.
Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
software, either in source code form or as a compiled binary, for any purpose,
commercial or non-commercial, and by any means.
In jurisdictions that recognize copyright laws, the author or authors of this
software dedicate any and all copyright interest in the software to the public
domain. We make this dedication for the benefit of the public at large and to
the detriment of our heirs and successors. We intend this dedication to be an
overt act of relinquishment in perpetuity of all present and future rights to
this software under copyright law.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +1,13 @@
#!/usr/bin/env bash
set -eu
set -eux
if [[ -z "${BB_CI:-}" ]]; then
BB_CI=0
fi
if [[ -z "${CMAKE_BUILD_TYPE:-}" ]]; then
CMAKE_BUILD_TYPE=Debug
LLVM_CMAKE_BUILD_TYPE=Release
BB_CI=0
else
LLVM_CMAKE_BUILD_TYPE=$CMAKE_BUILD_TYPE
fi
@ -36,12 +39,12 @@ esac
rm -rf $BUILD_DIR
mkdir $BUILD_DIR
cd $BUILD_DIR
LLVM_PREFIX_PATH=$HOME/dev/llvm/install/llvm_20.1.3_$BIRTH_ARCH-$BIRTH_OS-$LLVM_CMAKE_BUILD_TYPE
LLVM_PREFIX_PATH=$HOME/dev/llvm/install/llvm_20.1.7_$BIRTH_ARCH-$BIRTH_OS-$LLVM_CMAKE_BUILD_TYPE
if [[ -z "${CLANG_PATH:-}" ]]; then
CLANG_PATH=clang
CLANGXX_PATH=clang++
fi
cmake .. -G Ninja -DCMAKE_C_COMPILER=$CLANG_PATH -DCMAKE_CXX_COMPILER=$CLANGXX_PATH -DCMAKE_LINKER_TYPE=$LINKER_TYPE -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_PREFIX_PATH=$LLVM_PREFIX_PATH -DCMAKE_COLOR_DIAGNOSTICS=ON -DBB_CI=$BB_CI
cmake .. -G Ninja -DCMAKE_C_COMPILER=$CLANG_PATH -DCMAKE_CXX_COMPILER=$CLANGXX_PATH -DCMAKE_LINKER_TYPE=$LINKER_TYPE -DCMAKE_EXPORT_COMPILE_COMMANDS=ON -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE%%-*} -DCMAKE_PREFIX_PATH=$LLVM_PREFIX_PATH -DCMAKE_COLOR_DIAGNOSTICS=ON -DBB_CI=$BB_CI
cd ..

View File

@ -1,27 +0,0 @@
// This license belongs to https://github.com/MolecularMatters/raw_pdb
BSD 2-Clause License
Copyright 2011-2022, Molecular Matters GmbH <office@molecular-matters.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

View File

@ -1,203 +0,0 @@
// This license belongs to https://github.com/SeaOfNodes/Simple
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -1,23 +0,0 @@
// This license belongs to https://github.com/RealNeGate/Cuik
MIT License
Copyright (c) 2021 Yasser Arguelles Snape
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

File diff suppressed because it is too large Load Diff

View File

@ -163,22 +163,39 @@ fn String compile_file(Arena* arena, Compile options)
auto is_compiler = relative_file_path.equal(string_literal("src/compiler.bbb"));
String output_path_dir_parts[] = {
make_directory(base_cache_dir);
String cpu_dir_parts[] = {
string_literal(base_cache_dir),
is_compiler ? string_literal("/compiler/") : string_literal("/"),
string_literal("/"),
options.host_cpu_model ? string_literal("native") : string_literal("generic"),
};
auto cpu_dir = arena_join_string(arena, array_to_slice(cpu_dir_parts));
make_directory(cstr(cpu_dir));
auto base_dir = cpu_dir;
if (is_compiler)
{
String compiler_dir_parts[] = {
base_dir,
string_literal("/compiler"),
};
base_dir = arena_join_string(arena, array_to_slice(compiler_dir_parts));
make_directory(cstr(base_dir));
}
String output_path_dir_parts[] = {
base_dir,
string_literal("/"),
build_mode_to_string(options.build_mode),
string_literal("_"),
options.has_debug_info ? string_literal("di") : string_literal("nodi"),
};
auto output_path_dir = arena_join_string(arena, array_to_slice(output_path_dir_parts));
make_directory(base_cache_dir);
if (is_compiler)
{
make_directory(base_cache_dir "/compiler");
}
make_directory(cstr(output_path_dir));
String output_path_base_parts[] = {
@ -204,6 +221,16 @@ fn String compile_file(Arena* arena, Compile options)
.value = cmake_prefix_path,
};
if (is_compiler)
{
auto cmake_prefix_path_cstr = os_get_environment_variable("CMAKE_PREFIX_PATH");
if (cmake_prefix_path_cstr)
{
auto cmake_prefix_path_string = c_string_to_slice(cmake_prefix_path_cstr);
cmake_prefix_path_definition.value = cmake_prefix_path_string;
}
}
String objects[] = {
output_object_path,
};
@ -316,13 +343,28 @@ fn String compile_file(Arena* arena, Compile options)
library_buffer[library_count] = string_literal("lldCommon");
library_count += 1;
library_buffer[library_count] = string_literal("lldCOFF");
library_count += 1;
library_buffer[library_count] = string_literal("lldELF");
library_count += 1;
library_buffer[library_count] = string_literal("lldMachO");
library_count += 1;
library_buffer[library_count] = string_literal("lldMinGW");
library_count += 1;
library_buffer[library_count] = string_literal("lldWasm");
library_count += 1;
library_buffer[library_count] = string_literal("llvm_bindings");
library_count += 1;
library_names = { library_buffer, library_count };
library_paths = { &llvm_bindings_library, 1 };
}
else if (base_name.equal(string_literal("c_abi")))
else if (base_name.equal(string_literal("tests")))
{
library_paths = { &c_abi_library, 1 };
}
@ -341,6 +383,7 @@ fn String compile_file(Arena* arena, Compile options)
.target = {
.cpu = CPUArchitecture::x86_64,
.os = OperatingSystem::linux_,
.host_cpu_model = options.host_cpu_model,
},
.build_mode = options.build_mode,
.has_debug_info = options.has_debug_info,
@ -352,129 +395,7 @@ fn String compile_file(Arena* arena, Compile options)
global_variable String names[] =
{
string_literal("minimal"),
string_literal("comments"),
string_literal("constant_add"),
string_literal("constant_and"),
string_literal("constant_div"),
string_literal("constant_mul"),
string_literal("constant_rem"),
string_literal("constant_or"),
string_literal("constant_sub"),
string_literal("constant_xor"),
string_literal("constant_shift_left"),
string_literal("constant_shift_right"),
string_literal("minimal_stack"),
string_literal("minimal_stack_arithmetic"),
string_literal("minimal_stack_arithmetic2"),
string_literal("minimal_stack_arithmetic3"),
string_literal("stack_negation"),
string_literal("stack_add"),
string_literal("stack_sub"),
string_literal("extend"),
string_literal("integer_max"),
string_literal("integer_hex"),
string_literal("basic_pointer"),
string_literal("basic_call"),
string_literal("basic_branch"),
string_literal("basic_array"),
string_literal("basic_enum"),
string_literal("basic_slice"),
string_literal("basic_string"),
string_literal("basic_varargs"),
string_literal("basic_while"),
string_literal("pointer"),
string_literal("pointer_cast"),
string_literal("u1_return"),
string_literal("local_type_inference"),
string_literal("global"),
string_literal("function_pointer"),
string_literal("extern"),
string_literal("byte_size"),
string_literal("argv"),
string_literal("assignment_operators"),
string_literal("not_pointer"),
string_literal("bits"),
string_literal("bits_no_backing_type"),
string_literal("bits_return_u1"),
string_literal("bits_zero"),
string_literal("comparison"),
string_literal("global_struct"),
string_literal("if_no_else"),
string_literal("if_no_else_void"),
string_literal("indirect"),
string_literal("indirect_struct"),
string_literal("indirect_varargs"),
string_literal("ret_c_bool"),
string_literal("return_type_builtin"),
string_literal("return_u64_u64"),
string_literal("select"),
string_literal("slice"),
string_literal("small_struct_ints"),
string_literal("struct_assignment"),
string_literal("struct"),
string_literal("struct_u64_u64"),
string_literal("struct_varargs"),
string_literal("struct_zero"),
string_literal("unreachable"),
string_literal("varargs"),
string_literal("c_abi0"),
string_literal("c_abi1"),
string_literal("c_med_struct_ints"),
string_literal("c_ret_struct_array"),
string_literal("c_split_struct_ints"),
string_literal("c_string_to_slice"),
string_literal("c_struct_with_array"),
string_literal("c_function_pointer"),
string_literal("basic_bool_call"),
string_literal("abi_enum_bool"),
string_literal("return_small_struct"),
string_literal("c_abi"),
string_literal("string_to_enum"),
string_literal("empty_if"),
string_literal("else_if"),
string_literal("else_if_complicated"),
string_literal("basic_shortcircuiting_if"),
string_literal("shortcircuiting_if"),
string_literal("field_access_left_assign"),
string_literal("for_each"),
string_literal("pointer_decay"),
string_literal("enum_name"),
string_literal("slice_of_slices"),
string_literal("type_alias"),
string_literal("integer_formats"),
string_literal("for_each_int"),
string_literal("bool_array"),
string_literal("basic_union"),
string_literal("break_continue"),
string_literal("constant_global_reference"),
string_literal("concat_logical_or"),
string_literal("strict_array_type"),
string_literal("pointer_struct_initialization"),
string_literal("slice_array_literal"),
string_literal("slice_only_start"),
string_literal("basic_macro"),
string_literal("generic_macro"),
string_literal("generic_pointer_macro"),
string_literal("noreturn_macro"),
string_literal("generic_pointer_array"),
string_literal("self_referential_struct"),
string_literal("forward_declared_type"),
string_literal("enum_array"),
string_literal("opaque"),
string_literal("basic_struct_passing"),
string_literal("enum_arbitrary_abi"),
string_literal("enum_debug_info"),
string_literal("return_array"),
string_literal("bool_pair"),
string_literal("min_max"),
string_literal("field_parent_pointer"),
string_literal("leading_trailing_zeroes"),
string_literal("pointer_sub"),
string_literal("tests"),
};
void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
@ -517,6 +438,7 @@ void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
auto build_mode = BuildMode::debug_none;
auto has_debug_info = true;
auto is_host_cpu_model = true;
if (arguments.length >= 4)
{
@ -565,12 +487,30 @@ void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
}
}
if (arguments.length >= 6)
{
auto is_host_cpu_model_string = c_string_to_slice(arguments[5]);
if (is_host_cpu_model_string.equal(string_literal("true")))
{
is_host_cpu_model = true;
}
else if (is_host_cpu_model_string.equal(string_literal("false")))
{
is_host_cpu_model = false;
}
else
{
bb_fail_with_message(string_literal("Wrong value for is_host_cpu_model\n"));
}
}
auto relative_file_path = c_string_to_slice(arguments[2]);
compile_file(arena, {
.relative_file_path = relative_file_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.host_cpu_model = is_host_cpu_model,
.silent = false,
});
} break;
@ -596,11 +536,11 @@ void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
auto relative_file_path = arena_join_string(arena, array_to_slice(relative_file_path_parts));
auto executable_path = compile_file(arena, {
.relative_file_path = relative_file_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.silent = true,
});
.relative_file_path = relative_file_path,
.build_mode = build_mode,
.has_debug_info = has_debug_info,
.silent = true,
});
char* const arguments[] =
{
@ -630,6 +570,7 @@ void entry_point(Slice<char* const> arguments, Slice<char* const> envp)
.relative_file_path = string_literal("src/compiler.bbb"),
.build_mode = compiler_build_mode,
.has_debug_info = compiler_has_debug_info,
.host_cpu_model = true,
.silent = true,
});

View File

@ -247,6 +247,7 @@ struct Target
{
CPUArchitecture cpu;
OperatingSystem os;
bool host_cpu_model;
};
fn Target target_get_native()
@ -270,6 +271,7 @@ struct Compile
String relative_file_path;
BuildMode build_mode;
bool has_debug_info;
bool host_cpu_model;
bool silent;
};

View File

@ -416,15 +416,23 @@ fn void llvm_initialize(Module* module)
module->scope.llvm = di_compile_unit;
}
char* target_triple = {};
char* cpu_model = {};
char* cpu_features = {};
const char* target_triple = {};
const char* cpu_model = {};
const char* cpu_features = {};
if (target_compare(module->target, target_get_native()))
{
target_triple = llvm_global.host_triple;
cpu_model = llvm_global.host_cpu_model;
cpu_features = llvm_global.host_cpu_features;
if (module->target.host_cpu_model)
{
cpu_model = llvm_global.host_cpu_model;
cpu_features = llvm_global.host_cpu_features;
}
else
{
cpu_model = "generic";
cpu_features = "";
}
}
else
{
@ -9168,36 +9176,52 @@ struct ObjectGenerate
bool has_debug_info;
};
fn BBLLVMCodeGenerationPipelineResult generate_object(LLVMModuleRef module, LLVMTargetMachineRef target_machine, ObjectGenerate options)
fn bool generate_object(LLVMModuleRef module, LLVMTargetMachineRef target_machine, ObjectGenerate options)
{
if (options.run_optimization_passes)
{
// BBLLVM
bool prefer_speed = options.optimization_level == BBLLVMOptimizationLevel::O2 || options.optimization_level == BBLLVMOptimizationLevel::O3;
BBLLVMOptimizationPipelineOptions optimization_options = {
.optimization_level = (u64)options.optimization_level,
.debug_info = options.has_debug_info,
.loop_unrolling = prefer_speed,
.loop_interleaving = prefer_speed,
.loop_vectorization = prefer_speed,
.slp_vectorization = prefer_speed,
.merge_functions = prefer_speed,
.call_graph_profile = false,
.unified_lto = false,
.assignment_tracking = options.has_debug_info,
.verify_module = true,
};
llvm_module_run_optimization_pipeline(module, target_machine, optimization_options);
auto pass_builder_options = LLVMCreatePassBuilderOptions();
LLVMPassBuilderOptionsSetVerifyEach(pass_builder_options, 1);
LLVMPassBuilderOptionsSetDebugLogging(pass_builder_options, 0);
LLVMPassBuilderOptionsSetLoopInterleaving(pass_builder_options, prefer_speed);
LLVMPassBuilderOptionsSetLoopVectorization(pass_builder_options, prefer_speed);
LLVMPassBuilderOptionsSetSLPVectorization(pass_builder_options, prefer_speed);
LLVMPassBuilderOptionsSetLoopUnrolling(pass_builder_options, prefer_speed);
LLVMPassBuilderOptionsSetMergeFunctions(pass_builder_options, prefer_speed);
const char* passes;
switch (options.optimization_level)
{
case BBLLVMOptimizationLevel::O0: passes = "default<O0>"; break;
case BBLLVMOptimizationLevel::O1: passes = "default<O1>"; break;
case BBLLVMOptimizationLevel::O2: passes = "default<O2>"; break;
case BBLLVMOptimizationLevel::O3: passes = "default<O3>"; break;
case BBLLVMOptimizationLevel::Os: passes = "default<Os>"; break;
case BBLLVMOptimizationLevel::Oz: passes = "default<Oz>"; break;
}
auto error = LLVMRunPasses(module, passes, target_machine, pass_builder_options);
if (error)
{
report_error();
}
}
BBLLVMCodeGenerationPipelineOptions code_generation_options = {
.output_file_path = options.path,
.file_type = BBLLVMCodeGenerationFileType::object_file,
.optimize_when_possible = options.optimization_level > BBLLVMOptimizationLevel::O0,
.verify_module = true,
};
auto result = llvm_module_run_code_generation_pipeline(module, target_machine, &code_generation_options);
return result;
auto file_name = cstr(options.path);
char* error_message = 0;
auto result = LLVMTargetMachineEmitToFile(target_machine, module, file_name, LLVMObjectFile, &error_message);
if (result)
{
assert(error_message);
trap();
}
else
{
assert(!error_message);
}
return !result;
}
fn void link(Module* module)
@ -10049,10 +10073,7 @@ void emit(Module* module)
.run_optimization_passes = module->build_mode != BuildMode::debug_none,
.has_debug_info = module->has_debug_info,
});
if (object_generation_result != BBLLVMCodeGenerationPipelineResult::success)
{
report_error();
}
assert(object_generation_result);
link(module);
}

View File

@ -225,3 +225,9 @@ Execution os_execute(Arena* arena, Slice<char* const> arguments, Slice<char* con
return execution;
}
extern "C" char* getenv(const char*);
char* os_get_environment_variable(const char* env)
{
return getenv(env);
}

View File

@ -719,3 +719,4 @@ struct Execution
};
Execution os_execute(Arena* arena, Slice<char* const> arguments, Slice<char* const> environment, ExecuteOptions options);
char* os_get_environment_variable(const char* env);

View File

@ -7,6 +7,7 @@
#include <llvm-c/Target.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/TargetMachine.h>
#include <llvm-c/Transforms/PassBuilder.h>
struct LLDResult
{
@ -15,31 +16,6 @@ struct LLDResult
bool success;
};
enum class BBLLVMCodeGenerationPipelineResult : u8
{
success = 0,
failed_to_create_file = 1,
failed_to_add_emit_passes = 2,
};
enum class BBLLVMCodeGenerationFileType : u8
{
assembly_file = 0,
object_file = 1,
null = 2,
};
struct BBLLVMCodeGenerationPipelineOptions
{
String output_dwarf_file_path;
String output_file_path;
BBLLVMCodeGenerationFileType file_type;
bool optimize_when_possible;
bool verify_module;
};
static_assert(sizeof(BBLLVMCodeGenerationPipelineOptions) == 5 * sizeof(u64));
enum class BBLLVMOptimizationLevel : u8
{
O0 = 0,
@ -50,26 +26,6 @@ enum class BBLLVMOptimizationLevel : u8
Oz = 5,
};
#define BB_LLVM_OPTIMIZATION_PIPELINE_OPTIONS_PADDING_BIT_COUNT (51)
struct BBLLVMOptimizationPipelineOptions
{
u64 optimization_level:3;
u64 debug_info:1;
u64 loop_unrolling:1;
u64 loop_interleaving:1;
u64 loop_vectorization:1;
u64 slp_vectorization:1;
u64 merge_functions:1;
u64 call_graph_profile:1;
u64 unified_lto:1;
u64 assignment_tracking:1;
u64 verify_module:1;
u64 reserved:BB_LLVM_OPTIMIZATION_PIPELINE_OPTIONS_PADDING_BIT_COUNT;
};
static_assert(sizeof(BBLLVMOptimizationPipelineOptions) == sizeof(u64));
static_assert(BB_LLVM_OPTIMIZATION_PIPELINE_OPTIONS_PADDING_BIT_COUNT == 51);
enum class DwarfType
{
void_type = 0x0,
@ -123,9 +79,6 @@ extern "C" LLVMValueRef llvm_find_return_value_dominating_store(LLVMBuilderRef b
extern "C" void llvm_subprogram_replace_type(LLVMMetadataRef subprogram, LLVMMetadataRef subroutine_type);
extern "C" void llvm_module_run_optimization_pipeline(LLVMModuleRef module, LLVMTargetMachineRef target_machine, BBLLVMOptimizationPipelineOptions options);
extern "C" BBLLVMCodeGenerationPipelineResult llvm_module_run_code_generation_pipeline(LLVMModuleRef m, LLVMTargetMachineRef tm, const BBLLVMCodeGenerationPipelineOptions* options);
#define lld_api_args() char* const* argument_pointer, u64 argument_count, bool exit_early, bool disable_output
#define lld_api_function_decl(link_name) LLDResult lld_ ## link_name ## _link(lld_api_args())
extern "C" lld_api_function_decl(elf);

View File

@ -999,7 +999,7 @@ fn Type* parse_type(Module* module, Scope* scope)
}
}
}
else if (start_character == '#')
else if (start_character == '@')
{
module->offset += 1;
auto identifier = parse_identifier(module);
@ -1167,7 +1167,7 @@ fn Token tokenize(Module* module)
.id = id,
};
} break;
case '#':
case '@':
{
module->offset += 1;
if (is_identifier_start(module->content[module->offset]))
@ -2631,7 +2631,7 @@ fn Statement* parse_statement(Module* module, Scope* scope)
statement->local = local;
statement->id = StatementId::local;
} break;
case '#':
case '@':
{
statement->expression = parse_value(module, scope, {});
statement->id = StatementId::expression;

View File

@ -1,36 +0,0 @@
Foo = enum {
a,
b,
c,
d,
e,
f,
g,
}
S = struct
{
enum: Foo,
some_boolean: u1,
}
require = fn (ok: u1) void
{
if (!ok)
{
#trap();
}
}
[export] main = fn [cc(c)] () s32
{
>s: S = {
.enum = .f,
.some_boolean = 1,
};
require(s.enum == .f);
require(s.some_boolean);
return 0;
}

View File

@ -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;
}

View File

@ -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);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}

View File

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

View File

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

View File

@ -1,12 +0,0 @@
[export] main = fn [cc(c)] (argument_count: u32) s32
{
>a: s32 = 0;
if (argument_count != 3 and? argument_count != 2)
{
return 0;
}
else
{
return 1;
}
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -1,140 +0,0 @@
CallingConvention = enum
{
c,
}
InlineBehavior = enum
{
default = 0,
always_inline = 1,
no_inline = 2,
inline_hint = 3,
}
FunctionAttributes = struct
{
inline_behavior: InlineBehavior,
naked: u1,
}
Type = struct;
TypeId = enum
{
void,
noreturn,
forward_declaration,
integer,
function,
pointer,
array,
enum,
struct,
bits,
alias,
union,
unresolved,
vector,
floating_point,
enum_array,
opaque,
}
TypeInteger = struct
{
bit_count: u32,
signed: u1,
}
TypePointer = struct
{
element_type: &Type,
next: &Type,
}
AbiRegisterCountSystemV = struct
{
gpr: u32,
sse: u32,
};
AbiRegisterCount = union
{
system_v: AbiRegisterCountSystemV,
};
AbiInformation = struct
{
foo: u32,
}
TypeFunction = struct
{
semantic_return_type: &Type,
semantic_argument_types: []&Type,
calling_convention: CallingConvention,
is_variable_arguments: u1,
abi_argument_types: []&Type,
abi_return_type: &Type,
available_registers: AbiRegisterCount,
argument_abis: []AbiInformation,
return_abi: AbiInformation,
}
TypeContent = union
{
integer: TypeInteger,
function: TypeFunction,
pointer: TypePointer,
}
Type = struct
{
content: TypeContent,
id: TypeId,
name: []u8,
next: &Type,
}
give_me_string = fn () []u8
{
return "foooo";
}
get_type = fn (src: &Type, type: Type) &Type
{
src.& = type;
return src;
}
require = fn (ok: u1) void
{
if (!ok) #trap();
}
[export] main = fn [cc(c)] () s32
{
>buffer: Type = undefined;
>pointer = &buffer;
require(pointer == &buffer);
require(pointer != zero);
>result = get_type(pointer, {
.content = {
.pointer = {
.element_type = pointer,
zero,
},
},
.id = .pointer,
.name = give_me_string(),
zero,
});
require(pointer != zero);
require(pointer == &buffer);
require(buffer.content.pointer.element_type == pointer);
require(buffer.id == .pointer);
return 0;
}

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