Browse Source

replace sdl2-sys and llvm-sys with our own bindings

master
Alison Watson 1 year ago
parent
commit
26f753a999
  1. 157
      Cargo.lock
  2. 49
      Cargo.toml
  3. 36
      source/framework/build.rs
  4. 34
      source/framework/ffi.rs
  5. 7
      source/framework/hal.rs
  6. 15
      source/framework/hal/ctx.rs
  7. 24
      source/framework/hal/evt.rs
  8. 183
      source/framework/hal/sdl.rs
  9. 45
      source/framework/hal/win.rs
  10. 1
      source/framework/render/conf.rs
  11. 94
      source/framework/vire/compiler.rs
  12. 85
      source/framework/vire/compiler/function.rs
  13. 176
      source/framework/vire/compiler/llvm.rs
  14. 50
      source/framework/vire/compiler/types.rs
  15. 9
      source/macros/lib.rs

157
Cargo.lock generated

@ -1,19 +1,10 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "aho-corasick"
version = "0.7.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5"
dependencies = [
"memchr",
]
[[package]]
name = "ash"
version = "0.32.0"
version = "0.32.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "77ea56be8250318e64923c7e65b82a35b5c29dfb6dc1c7d1c0b288c4b1bbb084"
checksum = "06063a002a77d2734631db74e8f4ce7148b77fe522e6bca46f2ae7774fd48112"
dependencies = [
"libloading",
]
@ -24,19 +15,25 @@ version = "1.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a"
[[package]]
name = "bitflags"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693"
[[package]]
name = "blonkus"
version = "0.1.0"
dependencies = [
"ash",
"bitflags",
"blonkus_ma",
"glam",
"intaglio",
"llvm-sys",
"memchr",
"sdl2-sys",
"half",
"libc",
"serde",
"shh",
"smallvec",
"smol_str",
"thiserror",
"toml",
@ -52,12 +49,6 @@ dependencies = [
"syn",
]
[[package]]
name = "cc"
version = "1.0.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd"
[[package]]
name = "cfg-if"
version = "0.1.10"
@ -80,22 +71,16 @@ dependencies = [
]
[[package]]
name = "intaglio"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "967a032d0341206335b103da5445b3816370c644af65ca3ca1af9999dca7ea0f"
[[package]]
name = "lazy_static"
version = "1.4.0"
name = "half"
version = "1.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3"
[[package]]
name = "libc"
version = "0.2.91"
version = "0.2.93"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8916b1f6ca17130ec6568feccee27c156ad12037880833a3b842a823236502e7"
checksum = "9385f66bf6105b241aa65a61cb923ef20efc665cb9f9bb50ac2f0c4b7f378d41"
[[package]]
name = "libloading"
@ -113,25 +98,6 @@ version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c7d73b3f436185384286bd8098d17ec07c9a7d2388a6599f824d8502b529702a"
[[package]]
name = "llvm-sys"
version = "110.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "21ede189444b8c78907e5d36da5dabcf153170fcff9c1dba48afc4b33c7e19f0"
dependencies = [
"cc",
"lazy_static",
"libc",
"regex",
"semver",
]
[[package]]
name = "memchr"
version = "2.3.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525"
[[package]]
name = "num-traits"
version = "0.2.14"
@ -142,20 +108,11 @@ dependencies = [
"libm",
]
[[package]]
name = "pest"
version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53"
dependencies = [
"ucd-trie",
]
[[package]]
name = "proc-macro2"
version = "1.0.24"
version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71"
checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec"
dependencies = [
"unicode-xid",
]
@ -169,52 +126,6 @@ dependencies = [
"proc-macro2",
]
[[package]]
name = "regex"
version = "1.4.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "957056ecddbeba1b26965114e191d2e8589ce74db242b6ea25fc4062427a5c19"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax",
]
[[package]]
name = "regex-syntax"
version = "0.6.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "24d5f089152e60f62d28b835fbff2cd2e8dc0baf1ac13343bef92ab7eed84548"
[[package]]
name = "sdl2-sys"
version = "0.34.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "28d81feded049b9c14eceb4a4f6d596a98cebbd59abdba949c5552a015466d33"
dependencies = [
"cfg-if 0.1.10",
"libc",
"version-compare",
]
[[package]]
name = "semver"
version = "0.11.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
dependencies = [
"semver-parser",
]
[[package]]
name = "semver-parser"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0bef5b7f9e0df16536d3961cfb6e84331c065b4066afb39768d0e319411f7"
dependencies = [
"pest",
]
[[package]]
name = "serde"
version = "1.0.125"
@ -245,6 +156,12 @@ dependencies = [
"winapi",
]
[[package]]
name = "smallvec"
version = "1.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fe0f37c9e8f3c5a4a66ad655a93c74daac4ad00c441533bf5c6e7990bb42604e"
[[package]]
name = "smol_str"
version = "0.1.17"
@ -253,9 +170,9 @@ checksum = "6ca0f7ce3a29234210f0f4f0b56f8be2e722488b95cb522077943212da3b32eb"
[[package]]
name = "spirv-std"
version = "0.4.0-alpha.2"
version = "0.4.0-alpha.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1dff3b92a316f3be955de023f86c2a0f91057f7eb69f5991df81eceb85edfd10"
checksum = "895a86b30e3dab8b15ca414bdf1d5d3f132374debb8bf03ca5e89109f674a171"
dependencies = [
"num-traits",
"spirv-std-macros",
@ -263,9 +180,9 @@ dependencies = [
[[package]]
name = "spirv-std-macros"
version = "0.4.0-alpha.2"
version = "0.4.0-alpha.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c8a0b7070980d04781535bff719f9db79745df78ffbf1e45aba5a0e6ed7079dd"
checksum = "5b76d9abb9f30d0da7c54e164efecbfab6c8af3493ae41d43c38ebfbb80b9894"
dependencies = [
"proc-macro2",
"quote",
@ -280,9 +197,9 @@ checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "syn"
version = "1.0.65"
version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3a1d708c221c5a612956ef9f75b37e454e88d1f7b899fbd3a18d4252012d663"
checksum = "48fe99c6bd8b1cc636890bcc071842de909d902c81ac7dab53ba33c421ab8ffb"
dependencies = [
"proc-macro2",
"quote",
@ -328,24 +245,12 @@ dependencies = [
"static_assertions",
]
[[package]]
name = "ucd-trie"
version = "0.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c"
[[package]]
name = "unicode-xid"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564"
[[package]]
name = "version-compare"
version = "0.0.10"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d63556a25bae6ea31b52e640d7c41d1ab27faba4ccb600013837a3d0b3994ca1"
[[package]]
name = "winapi"
version = "0.3.9"

49
Cargo.toml

@ -12,22 +12,49 @@ publish = false
keywords = ["gamedev", "engine"]
categories = ["game-development"]
resolver = "2"
build = "source/framework/build.rs"
[dependencies]
ash = "~0.32"
blonkus_ma = { path = "source/macros" }
glam = "~0.13"
intaglio = "~1.2"
llvm-sys = "~110"
memchr = "~2.3"
sdl2-sys = "~0.34"
serde = { version = "~1.0", features = ["derive"] }
shh = "~1.0"
smol_str = "~0.1"
thiserror = "~1.0"
toml = "~0.5"
# types:
# - bitflags for FFI usage
# - smallvec for potentially small dynamic arrays
# - smol_str for potentially small immutable strings
# - thiserror for implementing error types
bitflags = "~1.2"
smallvec = { version = "~1.6", features = ["const_generics", "union"] }
smol_str = "~0.1"
thiserror = "~1.0"
# i/o:
# - serde for serializing and deserializing our own formats
# - shh for hacking around LLVM crimes
# - toml for config / description files
serde = { version = "~1.0", features = ["derive"] }
shh = "~1.0"
toml = "~0.5"
# math:
# - glam for linear algebra
# - half for half-floats in certain areas
glam = "~0.13"
half = "~1.7"
# hashing:
# - intaglio for symbol tables?
# - rustc-hash for things like mesh names?
# - twox-hash for file deduplication
#intaglio = "~1.2"
#rustc-hash = { version = "~1.1", default-features = false }
twox-hash = { version = "~1.6", default-features = false }
# bindings:
# - ash for the renderer implementation
# - libc for binding SDL2 and LLVM
ash = "~0.32"
libc = "~0.2"
[profile.dev]
opt-level = 1

36
source/framework/build.rs

@ -0,0 +1,36 @@
fn llvm_config(opt: &str) -> String {
std::process::Command::new("llvm-config")
.arg(opt)
.arg("--link-static")
.arg("engine")
.output()
.map(|out| String::from_utf8(out.stdout).unwrap())
.unwrap()
}
fn llvm_config_array(opt: &str) -> Vec<String> {
llvm_config(opt)
.split(' ')
.filter(|lib| !lib.is_empty())
.map(|lib| lib.to_owned())
.collect()
}
fn main() {
let lib_dir = llvm_config("--libdir");
let libs = llvm_config_array("--libs");
let sys_libs = llvm_config_array("--system-libs");
println!("cargo:rustc-link-search=native={}", lib_dir);
for lib in libs.into_iter().chain(sys_libs.into_iter()) {
println!("cargo:rustc-flags={}", lib);
}
#[cfg(any(target_os = "macos", target_os = "freebsd"))]
println!("cargo:rustc-link-lib=c++");
#[cfg(target_os = "linux")]
println!("cargo:rustc-link-lib=stdc++");
}
// EOF

34
source/framework/ffi.rs

@ -1,5 +1,6 @@
use std::{
ffi::{CStr, CString},
os::raw,
ptr::null,
};
@ -11,7 +12,36 @@ macro_rules! c_str {
};
}
pub type Nts = *const std::os::raw::c_char;
#[macro_export]
macro_rules! opaque_struct {
(pub $s:ident) => {
#[repr(C)]
pub struct $s {
_private: [u8; 0],
}
};
($s:ident) => {
#[repr(C)]
struct $s {
_private: [u8; 0],
}
};
}
#[repr(C)]
pub enum Bool {
False = 0,
True,
}
impl Bool {
#[inline]
pub const fn is_true(&self) -> bool {
matches!(self, Self::True)
}
}
pub type Nts = *const raw::c_char;
#[inline]
pub fn cstr_from_slice(s: &[u8]) -> Option<&str> {
@ -33,7 +63,7 @@ pub unsafe fn cstr_from_ptr(s: Nts) -> Option<&'static str> {
#[inline]
pub fn end_of_cstr(s: &[u8]) -> usize {
if let Some(n) = memchr::memchr(0, s) {
if let Some(n) = s.iter().position(|&b| b == b'\0') {
n
} else {
0

7
source/framework/hal.rs

@ -2,7 +2,8 @@ pub mod ctx;
pub mod evt;
pub mod win;
pub(self) use sdl2_sys as sdl;
#[doc(hidden)]
pub mod sdl;
#[derive(Error, Debug)]
pub enum Err {
@ -18,9 +19,7 @@ impl Err {
/// This function will cause undefined behaviour if used from
/// multiple threads.
pub(self) unsafe fn new_sdl() -> Self {
Self::Sdl(
std::ffi::CStr::from_ptr(sdl::SDL_GetError()).to_string_lossy(),
)
Self::Sdl(std::ffi::CStr::from_ptr(sdl::get_error()).to_string_lossy())
}
}

15
source/framework/hal/ctx.rs

@ -4,14 +4,13 @@ pub struct Context;
impl Context {
pub fn new() -> Result<Self, Err> {
let init_flags = sdl::SDL_INIT_VIDEO;
unsafe {
sdl::SDL_SetMainReady();
}
if unsafe { sdl::SDL_Init(init_flags) } == 0 {
Ok(Self)
} else {
Err(unsafe { Err::new_sdl() })
sdl::set_main_ready();
if sdl::init(sdl::InitFlags::VIDEO) == 0 {
Ok(Self)
} else {
Err(Err::new_sdl())
}
}
}
}
@ -19,7 +18,7 @@ impl Context {
impl Drop for Context {
fn drop(&mut self) {
unsafe {
sdl::SDL_Quit();
sdl::quit();
}
}
}

24
source/framework/hal/evt.rs

@ -10,20 +10,26 @@ impl Iterator for EventIterator {
type Item = Event;
fn next(&mut self) -> Option<Self::Item> {
let mut event = unsafe { std::mem::MaybeUninit::uninit().assume_init() };
while unsafe { sdl::SDL_PollEvent(&mut event) } == 1 {
if let Some(evt) = read_in(event) {
return Some(evt);
unsafe {
loop {
let mut event = std::mem::MaybeUninit::uninit();
if sdl::poll_event(event.as_mut_ptr()) != 1 {
break;
}
if let Some(evt) = read_in(event.assume_init()) {
return Some(evt);
}
}
None
}
None
}
}
fn read_in(evt: sdl::SDL_Event) -> Option<Event> {
let typ = unsafe { std::mem::transmute(evt.type_) };
match typ {
| sdl::SDL_EventType::SDL_QUIT => Some(Event::Quit),
fn read_in(evt: sdl::Event) -> Option<Event> {
match unsafe { evt.ty } {
| sdl::EventType::Quit => Some(Event::Quit),
| _ => None,
}
}

183
source/framework/hal/sdl.rs

@ -0,0 +1,183 @@
use bitflags::bitflags;
use crate::ffi::Bool;
use std::os::raw;
pub const WINDOW_POS_UNDEF: raw::c_int = 0x1FFF0000;
bitflags! {
#[repr(transparent)]
pub struct InitFlags: u32 {
const TIMER = 0x01;
const AUDIO = 0x10;
const VIDEO = 0x20;
const JOYSTICK = 0x200;
const HAPTIC = 0x1000;
const GAME_CONTROLLER = 0x2000;
const EVENTS = 0x4000;
const SENSOR = 0x8000;
}
}
bitflags! {
#[repr(transparent)]
pub struct WindowFlags: u32 {
const FULLSCREEN = 0x00000001;
const OPENGL = 0x00000002;
const SHOWN = 0x00000004;
const HIDDEN = 0x00000008;
const BORDERLESS = 0x00000010;
const RESIZABLE = 0x00000020;
const MINIMIZED = 0x00000040;
const MAXIMIZED = 0x00000080;
const INPUT_GRABBED = 0x00000100;
const INPUT_FOCUS = 0x00000200;
const MOUSE_FOCUS = 0x00000400;
const FULLSCREEN_DESKTOP = Self::FULLSCREEN.bits | 0x00001000;
const FOREIGN = 0x00000800;
const ALLOW_HIGH_DPI = 0x00002000;
const MOUSE_CAPTURE = 0x00004000;
const ALWAYS_ON_TOP = 0x00008000;
const SKIP_TASKBAR = 0x00010000;
const UTILITY = 0x00020000;
const TOOLTIP = 0x00040000;
const POPUP_MENU = 0x00080000;
const VULKAN = 0x10000000;
const METAL = 0x20000000;
}
}
#[repr(u32)]
#[derive(Clone, Copy)]
pub enum EventType {
Quit = 0x100,
AppTerminating,
AppLowMemory,
AppWillEnterBackground,
AppDidEnterBackground,
AppWillEnterForeground,
AppDidEnterForeground,
LocaleChanged,
DisplayEvent = 0x150,
WindowEvent = 0x200,
SysWmEvent,
KeyDown = 0x300,
KeyUp,
TextEditing,
TextInput,
KeyMapChanged,
MouseMotion = 0x400,
MouseButtonDown,
MouseButtonUp,
MouseWheel,
JoyAxisMotion = 0x600,
JoyBallMotion,
JoyHatMotion,
JoyButtonDown,
JoyButtonUp,
JoyDeviceAdded,
JoyDeviceRemoved,
ControllerAxisMotion = 0x650,
ControllerButtonDown,
ControllerButtonUp,
ControllerDeviceAdded,
ControllerDeviceRemoved,
ControllerDeviceRemapped,
ControllerTouchPadDown,
ControllerTouchPadMotion,
ControllerTouchPadUp,
ControllerSensorUpdate,
FingerDown = 0x700,
FingerUp,
FingerMotion,
DollarGesture = 0x800,
DollarRecord,
MultiGesture,
ClipboardUpdate = 0x900,
DropFile = 0x1000,
DropText,
DropBegin,
DropComplete,
AudioDeviceAdded = 0x1100,
AudioDeviceRemoved,
SensorUpdate = 0x1200,
RenderTargetsReset = 0x2000,
RenderDeviceReset,
}
#[repr(C)]
#[derive(Copy, Clone)]
pub struct CommonEvent {
pub ty: EventType,
pub time_stamp: u32,
}
#[repr(C)]
pub union Event {
pub ty: EventType,
pub common: CommonEvent,
_forced_size: [u8; 56],
}
opaque_struct!(pub Window);
#[link(name = "SDL2")]
extern "C" {
// initialization
#[link_name = "SDL_SetMainReady"]
pub fn set_main_ready();
#[link_name = "SDL_Init"]
pub fn init(flags: InitFlags) -> raw::c_int;
#[link_name = "SDL_Quit"]
pub fn quit();
// errors
#[link_name = "SDL_GetError"]
pub fn get_error() -> *const raw::c_char;
// events
#[link_name = "SDL_PollEvent"]
pub fn poll_event(event: *mut Event) -> raw::c_int;
// windows
#[link_name = "SDL_CreateWindow"]
pub fn create_window(
title: *const raw::c_char, x: raw::c_int, y: raw::c_int, w: raw::c_int,
h: raw::c_int, flags: WindowFlags,
) -> *mut Window;
#[link_name = "SDL_DestroyWindow"]
pub fn destroy_window(window: *mut Window);
// vulkan
#[link_name = "SDL_Vulkan_GetInstanceExtensions"]
pub fn vulkan_get_instance_extensions(
window: *mut Window, p_count: *mut raw::c_uint,
p_names: *mut *const raw::c_char,
) -> Bool;
#[link_name = "SDL_Vulkan_CreateSurface"]
pub fn vulkan_create_surface(
window: *mut Window, instance: ash::vk::Instance,
surface: *mut ash::vk::SurfaceKHR,
) -> Bool;
}
// EOF

45
source/framework/hal/win.rs

@ -1,33 +1,30 @@
use super::*;
use crate::ffi;
use ash::{
version::InstanceV1_0,
vk::{self, Handle},
};
use std::{marker::PhantomData, os::raw::c_int};
use ash::{version::InstanceV1_0, vk};
use std::marker::PhantomData;
pub struct Window<'a> {
handle: *mut sdl::Window,
hal: PhantomData<&'a ctx::Context>,
handle: *mut sdl::SDL_Window,
}
impl<'a> Window<'a> {
pub fn new(
_hal: &'a ctx::Context, title: ffi::Nts, w: i16, h: i16,
_hal: &'a ctx::Context, title: ffi::Nts, w: u16, h: u16,
) -> Result<Self, Err> {
unsafe {
let handle = sdl::SDL_CreateWindow(
let handle = sdl::create_window(
title,
sdl::SDL_WINDOWPOS_UNDEFINED_MASK as c_int,
sdl::SDL_WINDOWPOS_UNDEFINED_MASK as c_int,
sdl::WINDOW_POS_UNDEF,
sdl::WINDOW_POS_UNDEF,
w.into(),
h.into(),
sdl::SDL_WindowFlags::SDL_WINDOW_SHOWN as u32
| sdl::SDL_WindowFlags::SDL_WINDOW_VULKAN as u32
| sdl::SDL_WindowFlags::SDL_WINDOW_RESIZABLE as u32,
sdl::WindowFlags::SHOWN
| sdl::WindowFlags::VULKAN
| sdl::WindowFlags::RESIZABLE,
);
if !handle.is_null() {
Ok(Self { hal: PhantomData, handle })
Ok(Self { handle, hal: PhantomData })
} else {
Err(Err::new_sdl())
}
@ -38,19 +35,19 @@ impl<'a> Window<'a> {
&self,
) -> Result<Vec<ffi::Nts>, Err> {
let mut count = 0;
let res = sdl::SDL_Vulkan_GetInstanceExtensions(
let res = sdl::vulkan_get_instance_extensions(
self.handle,
&mut count,
std::ptr::null_mut(),
);
if res != sdl::SDL_bool::SDL_FALSE {
if res.is_true() {
let mut names = vec![std::ptr::null(); count as usize];
let res = sdl::SDL_Vulkan_GetInstanceExtensions(
let res = sdl::vulkan_get_instance_extensions(
self.handle,
&mut count,
names.as_mut_ptr(),
);
if res != sdl::SDL_bool::SDL_FALSE {
if res.is_true() {
Ok(names)
} else {
Err(Err::new_sdl())
@ -63,14 +60,14 @@ impl<'a> Window<'a> {
pub unsafe fn vulkan_create_surface(
&self, instance: &ash::Instance,
) -> Result<vk::SurfaceKHR, Err> {
let mut surface = 0;
let res = sdl::SDL_Vulkan_CreateSurface(
let mut surface = vk::SurfaceKHR::null();
let res = sdl::vulkan_create_surface(
self.handle,
instance.handle().as_raw() as usize,
instance.handle(),
&mut surface,
);
if res != sdl::SDL_bool::SDL_FALSE {
Ok(vk::SurfaceKHR::from_raw(surface))
if res.is_true() {
Ok(surface)
} else {
Err(Err::new_sdl())
}
@ -80,7 +77,7 @@ impl<'a> Window<'a> {
impl Drop for Window<'_> {
fn drop(&mut self) {
unsafe {
sdl::SDL_DestroyWindow(self.handle);
sdl::destroy_window(self.handle);
}
}
}

1
source/framework/render/conf.rs

@ -2,7 +2,6 @@ use ash::vk;
use std::num::NonZeroUsize;
#[blonkus_ma::serialize_config]
#[derive(Clone, Copy)]
pub enum PresentMode {
Fifo,
FifoRelaxed,

94
source/framework/vire/compiler.rs

@ -1,14 +1,12 @@
pub mod function;
pub mod nat;
pub mod types;
#[doc(hidden)]
pub mod llvm;
pub(self) use self::{function::*, types::*};
pub(self) use super::parser::Datum;
pub(self) use crate::ffi;
pub(self) use llvm_sys::{
analysis::*, core::*, execution_engine::*, prelude::*, target::*,
target_machine::*,
};
pub(self) use crate::ffi::{self, Bool};
#[derive(Error, Debug)]
pub enum Err {
@ -23,10 +21,10 @@ pub enum Err {
}
pub struct Context {
contx: LLVMContextRef,
modul: LLVMModuleRef,
build: LLVMBuilderRef,
engin: LLVMExecutionEngineRef,
contx: *mut llvm::Context,
modul: *mut llvm::Module,
build: *mut llvm::Builder,
engin: *mut llvm::ExecutionEngine,
types: Vec<ComplType>,
funcs: Vec<Function>,
}
@ -44,27 +42,27 @@ impl Context {
];
unsafe {
init_llvm();
}
//init_llvm();
let contx = unsafe { LLVMContextCreate() };
let modul = unsafe { LLVMModuleCreateWithNameInContext(MODULE, contx) };
let build = unsafe { LLVMCreateBuilderInContext(contx) };
let engin = unsafe { jit_engine(modul)? };
let types = Vec::new();
let funcs = Vec::new();
let contx = llvm::context_new();
let modul = llvm::module_new_with_name_in_context(MODULE, contx);
let build = llvm::builder_new_in_context(contx);
let engin = jit_engine(modul)?;
let types = Vec::new();
let funcs = Vec::new();
let mut c = Self { contx, modul, build, engin, types, funcs };
let mut c = Self { contx, modul, build, engin, types, funcs };
for ty in types::Basic::iter() {
c.types.push(types::ComplType::Basic(types::BasicType::new(ty)));
}
for ty in types::Basic::iter() {
c.types.push(types::ComplType::Basic(types::BasicType::new(ty)));
}
for decl in NAT_FUNCTIONS.iter() {
decl(&mut c);
}
for decl in NAT_FUNCTIONS.iter() {
decl(&mut c);
}
Ok(c)
Ok(c)
}
}
pub fn basic_type(&self, ty: Basic) -> &ComplType {
@ -93,7 +91,7 @@ impl Context {
pub fn execute(&self) -> Result<(), Err> {
unsafe {
let func: unsafe extern "C" fn() = std::mem::transmute(
LLVMGetFunctionAddress(self.engin, c_str!("-main")),
llvm::engine_get_function_address(self.engin, c_str!("-main")),
);
func();
}
@ -104,53 +102,55 @@ impl Context {
impl Drop for Context {
fn drop(&mut self) {
unsafe {
LLVMDisposeExecutionEngine(self.engin);
LLVMDisposeBuilder(self.build);
LLVMContextDispose(self.contx);
llvm::engine_drop(self.engin);
llvm::builder_drop(self.build);
llvm::context_drop(self.contx);
}
}
}
unsafe fn jit_engine(
modul: LLVMModuleRef,
) -> Result<LLVMExecutionEngineRef, Err> {
let mut opt = LLVMMCJITCompilerOptions {
OptLevel: LLVMCodeGenOptLevel::LLVMCodeGenLevelAggressive as _,
CodeModel: LLVMCodeModel::LLVMCodeModelJITDefault,
NoFramePointerElim: 0,
EnableFastISel: 0,
MCJMM: std::ptr::null_mut(),
modul: *mut llvm::Module,
) -> Result<*mut llvm::ExecutionEngine, Err> {
let mut opt = llvm::McJitCompilerOptions {
opt_level: llvm::CodeGenOptLevel::Aggressive,
code_model: llvm::CodeModel::JitDefault,
no_frame_pointer_elim: Bool::False,
enable_fast_i_sel: Bool::False,
mc_jmm: std::ptr::null_mut(),
};
let mut jit = std::ptr::null_mut();
let mut msg = std::ptr::null_mut();
let res = LLVMCreateMCJITCompilerForModule(
let res = llvm::engine_new_mcjit_compiler_for_module(
&mut jit,
modul,
&mut opt,
std::mem::size_of::<LLVMMCJITCompilerOptions>(),
std::mem::size_of::<llvm::McJitCompilerOptions>(),
&mut msg,
);
if res != 0 {
let msg =
ffi::cstr_from_ptr(msg).unwrap_or("Couldn't parse error").to_owned();
Err(Err::JitInit(msg))
if res.is_true() {
Err(Err::JitInit(
ffi::cstr_from_ptr(msg).unwrap_or("Couldn't parse error").to_owned()
))
} else {
Ok(jit)
}
}
/*
unsafe fn init_llvm() {
static INIT: std::sync::Once = std::sync::Once::new();
INIT.call_once(|| {
LLVMLinkInMCJIT();
llvm::link_jit();
LLVM_InitializeNativeTarget();
LLVM_InitializeNativeAsmPrinter();
LLVM_InitializeNativeAsmParser();
_InitializeNativeTarget();
_InitializeNativeAsmPrinter();
_InitializeNativeAsmParser();
});
}
*/
// EOF

85
source/framework/vire/compiler/function.rs

@ -10,26 +10,29 @@ enum ErrCapture {
}
pub struct IncompleteFunction<'a> {
value: LLVMValueRef,
block: LLVMBasicBlockRef,
value: *mut llvm::Value,
block: *mut llvm::BasicBlock,
contx: &'a Context,
in_context: bool,
}
pub struct Function {
value: LLVMValueRef,
value: *mut llvm::Value,
}
impl<'a> IncompleteFunction<'a> {
pub fn new(c: &'a Context, name: ffi::Nts, ftyp: &FunctType) -> Self {
const ENT: ffi::Nts = c_str!("entry");
let value = unsafe { LLVMAddFunction(c.modul, name, ftyp.handle()) };
let block =
unsafe { LLVMAppendBasicBlockInContext(c.contx, value, ENT) };
Self { value, block, contx: c, in_context: false }
unsafe {
let value = llvm::module_add_function(c.modul, name, ftyp.handle());
let block = llvm::context_append_basic_block(c.contx, value, ENT);
Self { value, block, contx: c, in_context: false }
}
}
pub fn compile(&mut self, datum: &Datum) -> Result<LLVMValueRef, Err> {
pub fn compile(
&mut self, datum: &Datum
) -> Result<(*mut llvm::Type, *mut llvm::Value), Err> {
if !self.in_context {
return Err(Err::Context);
}
@ -37,18 +40,20 @@ impl<'a> IncompleteFunction<'a> {
unsafe {
match datum {
| Datum::Null => {
Ok(LLVMGetUndef(self.contx.basic_type(Basic::Void).handle()))
let ty = self.contx.basic_type(Basic::Void).handle();
let vl = llvm::value_undef(ty);
Ok((ty, vl))
}
| Datum::Bool(val) => {
let ty = self.contx.basic_type(Basic::Bool).handle();
let vl = llvm::value_const_int(ty, *val as _, Bool::False);
Ok((ty, vl))
}
| Datum::Char(chr) => {
let ty = self.contx.basic_type(Basic::Q32_0U).handle();
let vl = llvm::value_const_int(ty, *chr as _, Bool::False);
Ok((ty, vl))
}
| Datum::Bool(value) => Ok(LLVMConstInt(
self.contx.basic_type(Basic::Bool).handle(),
*value as _,
0,
)),
| Datum::Char(character) => Ok(LLVMConstInt(
self.contx.basic_type(Basic::Q32_0U).handle(),
*character as _,
0,
)),
| Datum::Strn(_) => {
// TODO
Err(Err::Syntax)
@ -56,33 +61,39 @@ impl<'a> IncompleteFunction<'a> {
| Datum::Symb(name) => {
// TODO: must support more than global function symbols
let name = CString::new(name.as_bytes()).unwrap().into_raw();
let func = LLVMGetNamedFunction(self.contx.modul, name);
let func = llvm::module_get_named_function(
self.contx.modul,
name,
);
CString::from_raw(name);
Ok(func)
Ok((llvm::value_type(func), func))
}
| Datum::Numb(num) => {
let ty = self.contx.basic_type(Basic::Q64_0).handle();
let vl = llvm::value_const_int(ty, *num as _, Bool::False);
Ok((ty, vl))
}
| Datum::Numb(number) => Ok(LLVMConstInt(
self.contx.basic_type(Basic::Q64_0).handle(),
*number as _,
0,
)),
| Datum::Cons { cdr, car } => {
// function call
let func = self.compile(car)?;
let (ftyp, func) = self.compile(car)?;
let mut args = Vec::new();
let mut cdr = cdr.as_ref();
while let Datum::Cons { cdr: cdr_next, car: car_next } = cdr {
args.push(self.compile(car_next)?);
args.push(self.compile(car_next)?.1);
cdr = cdr_next.as_ref();
}
Ok(LLVMBuildCall(
let call = llvm::builder_call(
self.contx.build,
ftyp,
func,
args.as_mut_ptr(),
args.len() as u32,
args.len() as _,
c_str!(""),
))
);
Ok((llvm::value_type(call), call))
}
}
}
@ -92,7 +103,7 @@ impl<'a> IncompleteFunction<'a> {
&mut self, block: impl FnOnce(&mut Self) -> Result<(), Err>,
) -> Result<(), Err> {
unsafe {
LLVMPositionBuilderAtEnd(self.contx.build, self.block);
llvm::builder_position_at_end(self.contx.build, self.block);
}
self.in_context = true;
let res = block(self);
@ -103,7 +114,7 @@ impl<'a> IncompleteFunction<'a> {
pub fn complete(self) -> Result<Function, Err> {
// insert ret void
unsafe {
LLVMBuildRetVoid(self.contx.build);
llvm::builder_ret_void(self.contx.build);
}
// redirect stderr to a buffer so we can actually see what
@ -130,10 +141,10 @@ impl<'a> IncompleteFunction<'a> {
// verify
let verified = unsafe {
LLVMVerifyFunction(
!llvm::value_verify_func(
self.value,
LLVMVerifierFailureAction::LLVMPrintMessageAction,
) != 1
llvm::VerifierFailureAction::PrintMessage,
).is_true()
};
// it's okay if the sender errors because the receiver will only
@ -158,7 +169,7 @@ impl<'a> IncompleteFunction<'a> {
}
impl Function {
pub fn new(value: LLVMValueRef) -> Self {
pub fn new(value: *mut llvm::Value) -> Self {
Self { value }
}
}

176
source/framework/vire/compiler/llvm.rs

@ -0,0 +1,176 @@
use crate::ffi::Bool;
use std::os::raw;
opaque_struct!(pub BasicBlock);
opaque_struct!(pub Builder);
opaque_struct!(pub Context);
opaque_struct!(pub ExecutionEngine);
opaque_struct!(pub McJitMemoryManager);
opaque_struct!(pub Module);
opaque_struct!(pub Type);
opaque_struct!(pub Value);
#[repr(C)]
pub enum CodeGenOptLevel {
None,
Less,
Default,
Aggressive,
}
#[repr(C)]
pub enum CodeModel {
Default,
JitDefault,
Tiny,
Small,
Kernel,
Medium,
Large,
}
#[repr(C)]
pub enum VerifierFailureAction {
AbortProcess,
PrintMessage,
ReturnStatus,
}
#[repr(C)]
pub struct McJitCompilerOptions {
pub opt_level: CodeGenOptLevel,
pub code_model: CodeModel,
pub no_frame_pointer_elim: Bool,
pub enable_fast_i_sel: Bool,
pub mc_jmm: *mut McJitMemoryManager,
}
extern "C" {
// contexts
#[link_name = "LLVMContextCreate"]
pub fn context_new() -> *mut Context;
#[link_name = "LLVMContextDispose"]
pub fn context_drop(contx: *mut Context);
#[link_name = "LLVMAppendBasicBlockInContext"]
pub fn context_append_basic_block(
contx: *mut Context, func: *mut Value, name: *const raw::c_char
) -> *mut BasicBlock;
// modules
#[link_name = "LLVMModuleCreateWithNameInContext"]
pub fn module_new_with_name_in_context(
module_id: *const raw::c_char, contx: *mut Context
) -> *mut Module;
#[link_name = "LLVMAddFunction"]
pub fn module_add_function(
modul: *mut Module, name: *const raw::c_char, func_ty: *mut Type
) -> *mut Value;
#[link_name = "LLVMGetNamedFunction"]
pub fn module_get_named_function(
modul: *mut Module, name: *const raw::c_char
) -> *mut Value;
// builders
#[link_name = "LLVMCreateBuilderInContext"]
pub fn builder_new_in_context(contx: *mut Context) -> *mut Builder;
#[link_name = "LLVMDisposeBuilder"]
pub fn builder_drop(build: *mut Builder);
#[link_name = "LLVMBuildCall2"]
pub fn builder_call(
build: *mut Builder, ftyp: *mut Type, func: *mut Value,
args: *mut *mut Value, count: raw::c_uint, name: *const raw::c_char
) -> *mut Value;
#[link_name = "LLVMBuildRetVoid"]
pub fn builder_ret_void(build: *mut Builder) -> *mut Value;
#[link_name = "LLVMBuildRet"]
pub fn builder_ret(build: *mut Builder, retn: *mut Value) -> *mut Value;
#[link_name = "LLVMPositionBuilderAtEnd"]
pub fn builder_position_at_end(build: *mut Builder, block: *mut BasicBlock);
// execution engines
#[link_name = "LLVMCreateMCJITCompilerForModule"]
pub fn engine_new_mcjit_compiler_for_module(
engin: *mut *mut ExecutionEngine, modul: *mut Module,
options: *mut McJitCompilerOptions, size_of_options: libc::size_t,
out_error: *mut *mut raw::c_char
) -> Bool;
#[link_name = "LLVMDisposeExecutionEngine"]
pub fn engine_drop(engin: *mut ExecutionEngine);
#[link_name = "LLVMAddGlobalMapping"]
pub fn engine_add_global_mapping(
engin: *mut ExecutionEngine, value: *mut Value, addr: *mut raw::c_void
);
#[link_name = "LLVMGetFunctionAddress"]
pub fn engine_get_function_address(
engin: *mut ExecutionEngine, name: *const raw::c_char
) -> u64;
// types
#[link_name = "LLVMPrintTypeToString"]
pub fn type_print_to_string(handle: *mut Type) -> *mut raw::c_char;
#[link_name = "LLVMArrayType"]
pub fn type_array(element: *mut Type, count: raw::c_uint) -> *mut Type;
#[link_name = "LLVMFunctionType"]
pub fn type_function(
retn: *mut Type, params: *mut *mut Type, count: raw::c_uint,
is_var_arg: Bool
) -> *mut Type;
#[link_name = "LLVMVoidType"]
pub fn type_void() -> *mut Type;
#[link_name = "LLVMInt1Type"]
pub fn type_int1() -> *mut Type;
#[link_name = "LLVMInt8Type"]
pub fn type_int8() -> *mut Type;
#[link_name = "LLVMInt16Type"]
pub fn type_int16() -> *mut Type;
#[link_name = "LLVMInt32Type"]
pub fn type_int32() -> *mut Type;
#[link_name = "LLVMInt64Type"]
pub fn type_int64() -> *mut Type;
// values
#[link_name = "LLVMGetUndef"]
pub fn value_undef(ty: *mut Type) -> *mut Value;
#[link_name = "LLVMConstInt"]
pub fn value_const_int(
ty: *mut Type, num: libc::c_ulonglong, sign_extend: Bool
) -> *mut Value;
#[link_name = "LLVMTypeOf"]
pub fn value_type(value: *mut Value) -> *mut Type;
#[link_name = "LLVMVerifyFunction"]
pub fn value_verify_func(
func: *mut Value, action: VerifierFailureAction
) -> Bool;
// errors
#[link_name = "LLVMCreateMessage"]
pub fn message_new(msg: *const raw::c_char) -> *mut raw::c_char;
#[link_name = "LLVMDisposeMessage"]
pub fn message_drop(msg: *mut raw::c_char);
}
// EOF

50
source/framework/vire/compiler/types.rs

@ -34,27 +34,27 @@ impl Basic {
#[derive(Clone, Copy)]
pub struct BasicType {
btyp: Basic,
handle: LLVMTypeRef,
handle: *mut llvm::Type,
}
#[derive(Clone)]
pub struct ArrayType {
size: usize,