From 2a619adec9d34a53143eee9bfd0376d7be08d8e4 Mon Sep 17 00:00:00 2001 From: Emil Pedersen Date: Tue, 27 Jan 2026 02:54:27 +0100 Subject: [PATCH 01/10] feat: basic c++/zig demo --- demo/benchmarker/build.sh | 1 + demo/benchmarker/compute.zig | 19 +++++ demo/benchmarker/main.glu | 26 ++++++ demo/benchmarker/timer.cpp | 161 +++++++++++++++++++++++++++++++++++ 4 files changed, 207 insertions(+) create mode 100755 demo/benchmarker/build.sh create mode 100644 demo/benchmarker/compute.zig create mode 100644 demo/benchmarker/main.glu create mode 100644 demo/benchmarker/timer.cpp diff --git a/demo/benchmarker/build.sh b/demo/benchmarker/build.sh new file mode 100755 index 00000000..6e3384fb --- /dev/null +++ b/demo/benchmarker/build.sh @@ -0,0 +1 @@ +gluc main.glu diff --git a/demo/benchmarker/compute.zig b/demo/benchmarker/compute.zig new file mode 100644 index 00000000..0ce18bc8 --- /dev/null +++ b/demo/benchmarker/compute.zig @@ -0,0 +1,19 @@ +const std = @import("std"); +const sha256 = std.crypto.hash.sha2.Sha256; + +/// Compute SHA256 hash of data +export fn hashBytes(data: [*]const u8, len: usize, output: *[32]u8) void { + sha256.hash(data[0..len], output, .{}); +} + +/// Verify if data matches expected hash +export fn verifyHash(data: [*]const u8, len: usize, expected: *const [32]u8) bool { + var actual: [32]u8 = undefined; + sha256.hash(data[0..len], &actual, .{}); + return std.mem.eql(u8, &actual, expected); +} + +/// Compare two hashes for equality +export fn compareHashes(hash1: *const [32]u8, hash2: *const [32]u8) bool { + return std.mem.eql(u8, hash1, hash2); +} diff --git a/demo/benchmarker/main.glu b/demo/benchmarker/main.glu new file mode 100644 index 00000000..055f4b47 --- /dev/null +++ b/demo/benchmarker/main.glu @@ -0,0 +1,26 @@ +import timer::Timer; + +import compute; + +func doWork() { + var data: UInt8[100]; + data[0] = 42; + for i in 0..<10 { + var result: UInt8[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + compute::hashBytes(data, 1, &result); + for j in 0..<32 { + std::printf("%02hhx", result[j]); + } + std::printf("\n"); + } +} + +func main() { + let timer = Timer::getInstance(); + + let handle = Timer::start(timer); + doWork(); + Timer::stop(timer, handle); + + std::printf("Elapsed time: %lldms\n", Timer::getElapsed(timer, handle)); +} diff --git a/demo/benchmarker/timer.cpp b/demo/benchmarker/timer.cpp new file mode 100644 index 00000000..30ee4294 --- /dev/null +++ b/demo/benchmarker/timer.cpp @@ -0,0 +1,161 @@ +#include +#include + +using Clock = std::chrono::steady_clock; +using TimePoint = std::chrono::time_point; +using Duration = std::chrono::milliseconds; + +// Structure to represent a timer interval +struct TimerInterval { + TimePoint startTime; + TimePoint endTime; + bool _isRunning; + + TimerInterval(); + + /// @brief Mark the interval as complete + void stop(); + + /// @brief Check if the interval is still running + /// @return True if active, false otherwise + bool isRunning() const; + + /// @brief Get the elapsed time for this interval + /// @return Duration in milliseconds + Duration getElapsed() const; +}; + +/// @brief Singleton timer class for tracking time intervals +class Timer { + std::vector _intervals; + + Timer(); + +public: + Timer(Timer const &) = delete; + Timer &operator=(Timer const &) = delete; + + /// @brief Get the singleton instance + /// @return Reference to the global Timer instance + static Timer &getInstance(); + + /// @brief Start a new timer interval + /// @return Index of the newly created interval + size_t start(); + + /// @brief Stop a specific timer interval + /// @param index The index of the interval to stop + /// @return True if interval was found and stopped, false otherwise + bool stop(size_t index); + + /// @brief Get elapsed time for a specific interval + /// @param index The index of the interval + /// @return Duration in milliseconds, or 0 if index is invalid + Duration getElapsed(size_t index) const; + + /// @brief Get total elapsed time across all intervals + /// @return Total duration in milliseconds + Duration getTotalElapsed() const; + + /// @brief Count currently active intervals + /// @return Number of running intervals + size_t countActive() const; + + /// @brief Get all intervals + /// @return Vector of all timer intervals + std::vector const &getIntervals() const; + + /// @brief Reset all intervals + void reset(); +}; + +// TimerInterval method definitions +TimerInterval::TimerInterval() + : startTime(Clock::now()), endTime(), _isRunning(true) +{ +} + +void TimerInterval::stop() +{ + endTime = Clock::now(); + _isRunning = false; +} + +bool TimerInterval::isRunning() const +{ + return _isRunning; +} + +Duration TimerInterval::getElapsed() const +{ + TimePoint end = _isRunning ? Clock::now() : endTime; + return std::chrono::duration_cast(end - startTime); +} + +// Timer method definitions +Timer::Timer() { } + +Timer &Timer::getInstance() +{ + static Timer *_instance = nullptr; + if (!_instance) { + _instance = new Timer(); + } + return *_instance; +} + +size_t Timer::start() +{ + _intervals.emplace_back(); + return _intervals.size() - 1; +} + +bool Timer::stop(size_t index) +{ + if (index >= _intervals.size()) { + return false; + } + if (!_intervals[index].isRunning()) { + return false; + } + _intervals[index].stop(); + return true; +} + +Duration Timer::getElapsed(size_t index) const +{ + if (index >= _intervals.size()) { + return Duration(0); + } + return _intervals[index].getElapsed(); +} + +Duration Timer::getTotalElapsed() const +{ + Duration total(0); + for (auto const &interval : _intervals) { + total += interval.getElapsed(); + } + return total; +} + +size_t Timer::countActive() const +{ + size_t count = 0; + for (auto const &interval : _intervals) { + if (interval.isRunning()) { + count++; + } + } + return count; +} + +std::vector const &Timer::getIntervals() const +{ + return _intervals; +} + +void Timer::reset() +{ + _intervals.clear(); +} From a74f429d06a03e6ab23596913ba7af8ae2fff7fe Mon Sep 17 00:00:00 2001 From: Emil Pedersen Date: Tue, 27 Jan 2026 16:05:10 +0100 Subject: [PATCH 02/10] docs(demo): expand on demo, currently rust 1.90 doesnt work --- demo/benchmarker/compute.swift | 40 ++++++++++++++++++++++++++++++++++ demo/benchmarker/hexprint.rs | 15 +++++++++++++ demo/benchmarker/main.glu | 25 +++++++++++++-------- 3 files changed, 71 insertions(+), 9 deletions(-) create mode 100644 demo/benchmarker/compute.swift create mode 100644 demo/benchmarker/hexprint.rs diff --git a/demo/benchmarker/compute.swift b/demo/benchmarker/compute.swift new file mode 100644 index 00000000..0ed00a6a --- /dev/null +++ b/demo/benchmarker/compute.swift @@ -0,0 +1,40 @@ +import Foundation +import CryptoKit + +/// Compute SHA256 hash of data +public func hashBytes( + data: UnsafeRawPointer, + len: Int, + output: UnsafeMutableRawPointer +) { + let buffer = UnsafeRawBufferPointer(start: data, count: len) + let digest = SHA256.hash(data: buffer) + digest.withUnsafeBytes { bytes in + output.copyMemory(from: bytes.baseAddress!, byteCount: 32) + } +} + +/// Verify if data matches expected hash +public func verifyHash( + data: UnsafeRawPointer, + len: Int, + expected: UnsafeRawPointer +) -> Bool { + let buffer = UnsafeRawBufferPointer(start: data, count: len) + let digest = SHA256.hash(data: buffer) + + let expectedBuffer = UnsafeRawBufferPointer(start: expected, count: 32) + return digest.withUnsafeBytes { actual in + return actual.elementsEqual(expectedBuffer) + } +} + +/// Compare two hashes for equality +public func compareHashes( + hash1: UnsafeRawPointer, + hash2: UnsafeRawPointer +) -> Bool { + let buffer1 = UnsafeRawBufferPointer(start: hash1, count: 32) + let buffer2 = UnsafeRawBufferPointer(start: hash2, count: 32) + return buffer1.elementsEqual(buffer2) +} diff --git a/demo/benchmarker/hexprint.rs b/demo/benchmarker/hexprint.rs new file mode 100644 index 00000000..6edcc418 --- /dev/null +++ b/demo/benchmarker/hexprint.rs @@ -0,0 +1,15 @@ + +#![no_main] + +/// Print byte slice as hex to stdout +pub fn print_hex(data: &[u8]) { + for byte in data { + print!("{:02x}", byte); + } + println!(); +} + +/// Print 32-byte hash array as hex to stdout +pub fn print_hash(hash: &[u8; 32]) { + print_hex(hash); +} diff --git a/demo/benchmarker/main.glu b/demo/benchmarker/main.glu index 055f4b47..7bceb293 100644 --- a/demo/benchmarker/main.glu +++ b/demo/benchmarker/main.glu @@ -1,17 +1,24 @@ import timer::Timer; -import compute; +@file_extension("zig") import compute as compute_zig; +@file_extension("swift") import compute::compute as compute_swift; + +import hexprint::hexprint; func doWork() { - var data: UInt8[100]; - data[0] = 42; + var data: UInt8[1] = {42}; for i in 0..<10 { - var result: UInt8[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - compute::hashBytes(data, 1, &result); - for j in 0..<32 { - std::printf("%02hhx", result[j]); - } - std::printf("\n"); + var zig: UInt8[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + var swift: UInt8[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + compute_zig::hashBytes(data, 1, &zig); + compute_swift::hashBytes({&data as *Char}, {1}, {&swift as *Char}); + std::assert(compute_zig::verifyHash(data, 1, &swift)); + std::assert(compute_swift::verifyHash({&data as *Char}, {1}, {&zig as *Char})); + std::printf("Iteration %d:\n", i); + std::printf(" Swift hash: "); + hexprint::print_hash(&swift); + std::printf(" Zig hash: "); + hexprint::print_hash(&zig); } } From ee8f0aeb1cec0ce3cbe2a99bc8733cf7a886c26f Mon Sep 17 00:00:00 2001 From: Emil Pedersen Date: Tue, 27 Jan 2026 18:01:59 +0100 Subject: [PATCH 03/10] docs(demo): fix rust printing --- demo/benchmarker/hexprint.rs | 2 ++ demo/benchmarker/main.glu | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/demo/benchmarker/hexprint.rs b/demo/benchmarker/hexprint.rs index 6edcc418..69de4369 100644 --- a/demo/benchmarker/hexprint.rs +++ b/demo/benchmarker/hexprint.rs @@ -2,6 +2,7 @@ #![no_main] /// Print byte slice as hex to stdout +#[no_mangle] pub fn print_hex(data: &[u8]) { for byte in data { print!("{:02x}", byte); @@ -10,6 +11,7 @@ pub fn print_hex(data: &[u8]) { } /// Print 32-byte hash array as hex to stdout +#[no_mangle] pub fn print_hash(hash: &[u8; 32]) { print_hex(hash); } diff --git a/demo/benchmarker/main.glu b/demo/benchmarker/main.glu index 7bceb293..2bd126c9 100644 --- a/demo/benchmarker/main.glu +++ b/demo/benchmarker/main.glu @@ -15,9 +15,9 @@ func doWork() { std::assert(compute_zig::verifyHash(data, 1, &swift)); std::assert(compute_swift::verifyHash({&data as *Char}, {1}, {&zig as *Char})); std::printf("Iteration %d:\n", i); - std::printf(" Swift hash: "); + std::print("Swift hash:"); hexprint::print_hash(&swift); - std::printf(" Zig hash: "); + std::print("Zig hash:"); hexprint::print_hash(&zig); } } From 2b3bf3c03471ec1ec24ea91c924bf67687c2dbde Mon Sep 17 00:00:00 2001 From: Emil Pedersen Date: Tue, 27 Jan 2026 19:10:45 +0100 Subject: [PATCH 04/10] docs(demo): add random generation using D --- demo/benchmarker/main.glu | 29 ++++++++++++++++++----------- demo/benchmarker/random.d | 10 ++++++++++ 2 files changed, 28 insertions(+), 11 deletions(-) create mode 100644 demo/benchmarker/random.d diff --git a/demo/benchmarker/main.glu b/demo/benchmarker/main.glu index 2bd126c9..0ace2903 100644 --- a/demo/benchmarker/main.glu +++ b/demo/benchmarker/main.glu @@ -4,21 +4,28 @@ import timer::Timer; @file_extension("swift") import compute::compute as compute_swift; import hexprint::hexprint; +import random::random; + +let debug_print: Bool = false; func doWork() { - var data: UInt8[1] = {42}; - for i in 0..<10 { + var data: UInt8[100]; + let length: UInt64 = 100; + for i in 0..<1000000 { + random::fill_random(data, length); var zig: UInt8[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; var swift: UInt8[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - compute_zig::hashBytes(data, 1, &zig); - compute_swift::hashBytes({&data as *Char}, {1}, {&swift as *Char}); - std::assert(compute_zig::verifyHash(data, 1, &swift)); - std::assert(compute_swift::verifyHash({&data as *Char}, {1}, {&zig as *Char})); - std::printf("Iteration %d:\n", i); - std::print("Swift hash:"); - hexprint::print_hash(&swift); - std::print("Zig hash:"); - hexprint::print_hash(&zig); + compute_zig::hashBytes(data, length, &zig); + compute_swift::hashBytes({(&data) as *Char}, {length}, {&swift as *Char}); + std::assert(compute_zig::verifyHash(data, length, &swift)); + std::assert(compute_swift::verifyHash({(&data) as *Char}, {length}, {&zig as *Char})); + if debug_print { + std::printf("Iteration %d:\n", i); + std::print("Swift hash:"); + hexprint::print_hash(&swift); + std::print("Zig hash:"); + hexprint::print_hash(&zig); + } } } diff --git a/demo/benchmarker/random.d b/demo/benchmarker/random.d new file mode 100644 index 00000000..fc580b11 --- /dev/null +++ b/demo/benchmarker/random.d @@ -0,0 +1,10 @@ +import std.random; + +/// Fill array with random bytes +void fill_random(ubyte* data, size_t len) { + auto rng = Random(unpredictableSeed); + foreach (i; 0 .. len) { + data[i] = cast(ubyte)(rng.front % 256); + rng.popFront(); + } +} From c930974152bb72606bba4cea1dbd8566cb5eaf5e Mon Sep 17 00:00:00 2001 From: Emil Pedersen Date: Tue, 27 Jan 2026 19:23:13 +0100 Subject: [PATCH 05/10] docs(demo): initialize array with new shorthand syntax --- demo/benchmarker/main.glu | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/demo/benchmarker/main.glu b/demo/benchmarker/main.glu index 0ace2903..c31dd658 100644 --- a/demo/benchmarker/main.glu +++ b/demo/benchmarker/main.glu @@ -13,8 +13,8 @@ func doWork() { let length: UInt64 = 100; for i in 0..<1000000 { random::fill_random(data, length); - var zig: UInt8[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; - var swift: UInt8[32] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; + var zig: UInt8[32] = {0}; + var swift: UInt8[32] = {0}; compute_zig::hashBytes(data, length, &zig); compute_swift::hashBytes({(&data) as *Char}, {length}, {&swift as *Char}); std::assert(compute_zig::verifyHash(data, length, &swift)); From 0e2b52d9077d07992e3fb05fb95ffda56ed45fb0 Mon Sep 17 00:00:00 2001 From: Emil Pedersen Date: Thu, 29 Jan 2026 10:35:38 +0100 Subject: [PATCH 06/10] feat: add setup script for environment configuration for macOS --- demo/benchmarker/setup.sh | 2 ++ 1 file changed, 2 insertions(+) create mode 100755 demo/benchmarker/setup.sh diff --git a/demo/benchmarker/setup.sh b/demo/benchmarker/setup.sh new file mode 100755 index 00000000..7df358c2 --- /dev/null +++ b/demo/benchmarker/setup.sh @@ -0,0 +1,2 @@ +export PATH="$(cd ../../build/tools/gluc && pwd):/opt/homebrew/opt/llvm@20/bin/:$PATH" +export GLU_LINKER=/usr/bin/clang++ From 5548f2873b9b935b55404d15d3885e46ff6f3f9e Mon Sep 17 00:00:00 2001 From: LindonAliu Date: Thu, 29 Jan 2026 12:15:18 +0100 Subject: [PATCH 07/10] fixed: csfml demo --- demo/csfml/build_csfml.sh | 27 ++++++++ demo/csfml/csfml.h | 8 +++ demo/csfml/csfml_demo.glu | 25 +++++++ demo/csfml/jitter.d | 17 +++++ demo/csfml/motion.zig | 40 +++++++++++ demo/csfml/palette.rs | 20 ++++++ demo/csfml/sfml_host.cpp | 98 +++++++++++++++++++++++++++ demo/csfml/sfml_host.h | 20 ++++++ demo/csfml/stdbool.h | 14 ++++ lib/ClangImporter/DeclImporter.cpp | 6 ++ lib/ClangImporter/DeclImporter.hpp | 1 + lib/ClangImporter/TypeConverter.cpp | 68 +++++++++++++++---- lib/ClangImporter/TypeConverter.hpp | 15 +++- tools/gluc/sources/CompilerDriver.cpp | 5 ++ 14 files changed, 346 insertions(+), 18 deletions(-) create mode 100755 demo/csfml/build_csfml.sh create mode 100644 demo/csfml/csfml.h create mode 100644 demo/csfml/csfml_demo.glu create mode 100644 demo/csfml/jitter.d create mode 100644 demo/csfml/motion.zig create mode 100644 demo/csfml/palette.rs create mode 100644 demo/csfml/sfml_host.cpp create mode 100644 demo/csfml/sfml_host.h create mode 100644 demo/csfml/stdbool.h diff --git a/demo/csfml/build_csfml.sh b/demo/csfml/build_csfml.sh new file mode 100755 index 00000000..08282d01 --- /dev/null +++ b/demo/csfml/build_csfml.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +set -euo pipefail + +ROOT_DIR="$(cd "$(dirname "$0")" && pwd)" +BUILD_DIR="$ROOT_DIR/build" + +SFML_INCLUDE="${SFML_INCLUDE:-/opt/homebrew/include}" +SFML_LIB="${SFML_LIB:-/opt/homebrew/lib}" + +mkdir -p "$BUILD_DIR" + +clang++ -std=c++17 -g -O2 \ + -I "$SFML_INCLUDE" \ + -c "$ROOT_DIR/sfml_host.cpp" \ + -o "$BUILD_DIR/sfml_host.o" + +export CPATH="$ROOT_DIR:$SFML_INCLUDE:$CPATH" +export GLU_LINKER="${GLU_LINKER:-clang++}" +gluc "$ROOT_DIR/csfml_demo.glu" \ + -Wl,"$BUILD_DIR/sfml_host.o" \ + -Wl,-L"$SFML_LIB" \ + -Wl,-lsfml-graphics \ + -Wl,-lsfml-window \ + -Wl,-lsfml-system \ + -o "$BUILD_DIR/sfml_demo" + +printf "Built: %s\n" "$BUILD_DIR/sfml_demo" diff --git a/demo/csfml/csfml.h b/demo/csfml/csfml.h new file mode 100644 index 00000000..1bcf0ccd --- /dev/null +++ b/demo/csfml/csfml.h @@ -0,0 +1,8 @@ +#ifndef CSFML_H +#define CSFML_H + +#include +#include +#include + +#endif diff --git a/demo/csfml/csfml_demo.glu b/demo/csfml/csfml_demo.glu new file mode 100644 index 00000000..c06b4b1f --- /dev/null +++ b/demo/csfml/csfml_demo.glu @@ -0,0 +1,25 @@ +@file_extension("zig") import motion as motion_zig; +@file_extension("rs") import palette as palette_mod; +@file_extension("d") import jitter as jitter_mod; + +@file_extension("h") @implement import sfml_host::glu_update_motion; +@file_extension("h") @implement import sfml_host::glu_color_from_frame; +@file_extension("h") @implement import sfml_host::glu_jitter; + +func glu_update_motion( + pos_xy: *Float32, + vel_xy: *Float32, + bounds_xy: *Float32, + radius: Float32, + dt: Float32 +) -> Void { + motion_zig::updateMotion(pos_xy, vel_xy, bounds_xy, radius, dt); +} + +func glu_color_from_frame(frame: UInt32, out_rgba: *UInt8) -> Void { + palette_mod::palette::color_from_frame(frame, out_rgba); +} + +func glu_jitter(frame: UInt32, strength: Float32, out_xy: *Float32) -> Void { + jitter_mod::jitter::jitter(frame, strength, out_xy); +} diff --git a/demo/csfml/jitter.d b/demo/csfml/jitter.d new file mode 100644 index 00000000..bbbd2a0f --- /dev/null +++ b/demo/csfml/jitter.d @@ -0,0 +1,17 @@ +module jitter; + +extern(C): + +void jitter(uint seed, float strength, float* out_xy) { + if (out_xy is null) { + return; + } + + uint s = seed * 1664525u + 1013904223u; + float dx = (cast(float)(s & 0xFF) / 255.0f - 0.5f) * strength; + s = s * 1664525u + 1013904223u; + float dy = (cast(float)((s >> 8) & 0xFF) / 255.0f - 0.5f) * strength; + + out_xy[0] = dx; + out_xy[1] = dy; +} diff --git a/demo/csfml/motion.zig b/demo/csfml/motion.zig new file mode 100644 index 00000000..a70341bd --- /dev/null +++ b/demo/csfml/motion.zig @@ -0,0 +1,40 @@ +/// Update position/velocity with simple edge bouncing. +export fn updateMotion( + pos: [*]f32, + vel: [*]f32, + bounds: [*]const f32, + radius: f32, + dt: f32, +) void { + var x = pos[0]; + var y = pos[1]; + var vx = vel[0]; + var vy = vel[1]; + + x += vx * dt; + y += vy * dt; + + const max_x = bounds[0] - radius * 2.0; + const max_y = bounds[1] - radius * 2.0; + + if (x <= 0.0) { + x = 0.0; + vx = -vx; + } else if (x >= max_x) { + x = max_x; + vx = -vx; + } + + if (y <= 0.0) { + y = 0.0; + vy = -vy; + } else if (y >= max_y) { + y = max_y; + vy = -vy; + } + + pos[0] = x; + pos[1] = y; + vel[0] = vx; + vel[1] = vy; +} diff --git a/demo/csfml/palette.rs b/demo/csfml/palette.rs new file mode 100644 index 00000000..dd893641 --- /dev/null +++ b/demo/csfml/palette.rs @@ -0,0 +1,20 @@ +#![no_main] + +#[no_mangle] +pub extern "C" fn color_from_frame(frame: u32, out_rgba: *mut u8) { + if out_rgba.is_null() { + return; + } + + let t = frame as f32 * 0.025; + let r = (t.sin() * 127.0 + 128.0) as u8; + let g = ((t + 2.0943952).sin() * 127.0 + 128.0) as u8; + let b = ((t + 4.1887903).sin() * 127.0 + 128.0) as u8; + + unsafe { + *out_rgba.add(0) = r; + *out_rgba.add(1) = g; + *out_rgba.add(2) = b; + *out_rgba.add(3) = 255; + } +} diff --git a/demo/csfml/sfml_host.cpp b/demo/csfml/sfml_host.cpp new file mode 100644 index 00000000..bc53d593 --- /dev/null +++ b/demo/csfml/sfml_host.cpp @@ -0,0 +1,98 @@ +#include "sfml_host.h" + +#include + +#include + +#if defined(__GNUC__) + #define GLU_WEAK __attribute__((weak)) +#else + #define GLU_WEAK +#endif + +extern "C" GLU_WEAK void glu_update_motion( + float *pos_xy, float *vel_xy, float *bounds_xy, float radius, float dt +) +{ + (void) pos_xy; + (void) vel_xy; + (void) bounds_xy; + (void) radius; + (void) dt; +} + +extern "C" GLU_WEAK void glu_color_from_frame(uint32_t frame, uint8_t *out_rgba) +{ + (void) frame; + if (!out_rgba) { + return; + } + out_rgba[0] = 255; + out_rgba[1] = 255; + out_rgba[2] = 255; + out_rgba[3] = 255; +} + +extern "C" GLU_WEAK void +glu_jitter(uint32_t frame, float strength, float *out_xy) +{ + (void) frame; + (void) strength; + if (!out_xy) { + return; + } + out_xy[0] = 0.0f; + out_xy[1] = 0.0f; +} + +int main() +{ + constexpr unsigned int width = 800; + constexpr unsigned int height = 600; + constexpr float radius = 28.0f; + constexpr float dt = 1.0f / 60.0f; + constexpr float jitter_strength = 3.5f; + + sf::RenderWindow window( + sf::VideoMode(sf::Vector2u { width, height }), "Glu + SFML demo" + ); + window.setFramerateLimit(60); + + sf::CircleShape circle(radius); + + std::array pos = { 120.0f, 160.0f }; + std::array vel = { 180.0f, 140.0f }; + std::array bounds + = { static_cast(width), static_cast(height) }; + + std::array rgba = { 255, 255, 255, 255 }; + sf::Color const background(18, 20, 28, 255); + uint32_t frame = 0; + + while (window.isOpen()) { + while (auto const event = window.pollEvent()) { + if (event->is()) { + window.close(); + } + } + + glu_update_motion(pos.data(), vel.data(), bounds.data(), radius, dt); + glu_color_from_frame(frame, rgba.data()); + + float wiggle[2] = { 0.0f, 0.0f }; + glu_jitter(frame, jitter_strength, wiggle); + + circle.setPosition( + sf::Vector2f { pos[0] + wiggle[0], pos[1] + wiggle[1] } + ); + circle.setFillColor(sf::Color(rgba[0], rgba[1], rgba[2], rgba[3])); + + window.clear(background); + window.draw(circle); + window.display(); + + frame += 1; + } + + return 0; +} diff --git a/demo/csfml/sfml_host.h b/demo/csfml/sfml_host.h new file mode 100644 index 00000000..dc42660b --- /dev/null +++ b/demo/csfml/sfml_host.h @@ -0,0 +1,20 @@ +#ifndef GLU_DEMO_SFML_HOST_H +#define GLU_DEMO_SFML_HOST_H + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +void glu_update_motion( + float *pos_xy, float *vel_xy, float *bounds_xy, float radius, float dt +); +void glu_color_from_frame(uint32_t frame, uint8_t *out_rgba); +void glu_jitter(uint32_t frame, float strength, float *out_xy); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/demo/csfml/stdbool.h b/demo/csfml/stdbool.h new file mode 100644 index 00000000..a6e9dcf6 --- /dev/null +++ b/demo/csfml/stdbool.h @@ -0,0 +1,14 @@ +#ifndef _STDBOOL_H +#define _STDBOOL_H + +#ifndef __cplusplus + #ifndef __bool_true_false_are_defined + #define __bool_true_false_are_defined 1 + +typedef _Bool bool; + #define true 1 + #define false 0 + #endif +#endif + +#endif diff --git a/lib/ClangImporter/DeclImporter.cpp b/lib/ClangImporter/DeclImporter.cpp index 19d0b1f9..5f7935af 100644 --- a/lib/ClangImporter/DeclImporter.cpp +++ b/lib/ClangImporter/DeclImporter.cpp @@ -101,4 +101,10 @@ bool DeclImporter::VisitEnumDecl(clang::EnumDecl *enumDecl) return true; } +bool DeclImporter::VisitTypedefNameDecl(clang::TypedefNameDecl *typedefDecl) +{ + _typeConverter.importTypedefDecl(typedefDecl); + return true; +} + } // namespace glu::clangimporter diff --git a/lib/ClangImporter/DeclImporter.hpp b/lib/ClangImporter/DeclImporter.hpp index 6c84f2c8..e44444bf 100644 --- a/lib/ClangImporter/DeclImporter.hpp +++ b/lib/ClangImporter/DeclImporter.hpp @@ -21,6 +21,7 @@ class DeclImporter : public clang::RecursiveASTVisitor { bool VisitFunctionDecl(clang::FunctionDecl *funcDecl); bool VisitRecordDecl(clang::RecordDecl *recordDecl); bool VisitEnumDecl(clang::EnumDecl *enumDecl); + bool VisitTypedefNameDecl(clang::TypedefNameDecl *typedefDecl); }; } // namespace glu::clangimporter diff --git a/lib/ClangImporter/TypeConverter.cpp b/lib/ClangImporter/TypeConverter.cpp index c4f6aaf7..c32b67ef 100644 --- a/lib/ClangImporter/TypeConverter.cpp +++ b/lib/ClangImporter/TypeConverter.cpp @@ -64,7 +64,8 @@ glu::types::TypeBase *TypeConverter::convert(clang::QualType clangType) } glu::types::TypeBase *TypeConverter::importRecordDecl( - clang::RecordDecl *recordDecl, bool allowIncomplete + clang::RecordDecl *recordDecl, bool allowIncomplete, + llvm::StringRef forcedName ) { if (!recordDecl) { @@ -75,17 +76,18 @@ glu::types::TypeBase *TypeConverter::importRecordDecl( recordDecl = definition; } - // Skip anonymous structs for now - if (!recordDecl->getIdentifier()) { - return nullptr; - } - auto *canonicalType = _ctx.clang->getRecordType(recordDecl).getCanonicalType().getTypePtr(); if (auto cached = _ctx.typeCache.lookup(canonicalType)) { return cached; } + bool hasName = recordDecl->getIdentifier() != nullptr; + if (!hasName && forcedName.empty()) { + // Skip anonymous structs unless a typedef name is provided. + return nullptr; + } + bool isComplete = recordDecl->isCompleteDefinition(); if (!allowIncomplete && !isComplete) { return nullptr; @@ -121,7 +123,8 @@ glu::types::TypeBase *TypeConverter::importRecordDecl( } auto structLoc = _ctx.translateSourceLocation(recordDecl->getLocation()); - llvm::StringRef structName = copyString(recordDecl->getName(), allocator); + llvm::StringRef structName = hasName ? recordDecl->getName() : forcedName; + structName = copyString(structName, allocator); auto *structDecl = glu::ast::StructDecl::create( allocator, _ctx.glu, structLoc, nullptr, structName, fields, nullptr, glu::ast::Visibility::Public, nullptr @@ -152,8 +155,9 @@ TypeConverter::convertRecordType(clang::RecordType const *type) return importRecordDecl(type->getDecl(), true); } -glu::types::TypeBase * -TypeConverter::importEnumDecl(clang::EnumDecl *enumDecl, bool allowIncomplete) +glu::types::TypeBase *TypeConverter::importEnumDecl( + clang::EnumDecl *enumDecl, bool allowIncomplete, llvm::StringRef forcedName +) { if (!enumDecl) { return nullptr; @@ -163,17 +167,18 @@ TypeConverter::importEnumDecl(clang::EnumDecl *enumDecl, bool allowIncomplete) enumDecl = definition; } - // Skip anonymous enums for now - if (!enumDecl->getIdentifier()) { - return nullptr; - } - auto *canonicalType = _ctx.clang->getEnumType(enumDecl).getCanonicalType().getTypePtr(); if (auto cached = _ctx.typeCache.lookup(canonicalType)) { return cached; } + bool hasName = enumDecl->getIdentifier() != nullptr; + if (!hasName && forcedName.empty()) { + // Skip anonymous enums unless a typedef name is provided. + return nullptr; + } + bool isComplete = enumDecl->isCompleteDefinition(); if (!allowIncomplete && !isComplete) { return nullptr; @@ -202,7 +207,8 @@ TypeConverter::importEnumDecl(clang::EnumDecl *enumDecl, bool allowIncomplete) = isComplete ? convert(enumDecl->getIntegerType()) : nullptr; auto enumLoc = _ctx.translateSourceLocation(enumDecl->getLocation()); - llvm::StringRef enumName = copyString(enumDecl->getName(), allocator); + llvm::StringRef enumName = hasName ? enumDecl->getName() : forcedName; + enumName = copyString(enumName, allocator); auto *gluEnumDecl = glu::ast::EnumDecl::create( allocator, _ctx.glu, enumLoc, nullptr, enumName, cases, underlyingType, glu::ast::Visibility::Public, nullptr @@ -215,6 +221,38 @@ TypeConverter::importEnumDecl(clang::EnumDecl *enumDecl, bool allowIncomplete) return enumType; } +glu::types::TypeBase * +TypeConverter::importTypedefDecl(clang::TypedefNameDecl *typedefDecl) +{ + if (!typedefDecl) { + return nullptr; + } + + llvm::StringRef typedefName = typedefDecl->getName(); + if (typedefName.empty()) { + return nullptr; + } + + auto underlying = typedefDecl->getUnderlyingType(); + if (auto *recordType = underlying->getAs()) { + auto *recordDecl = recordType->getDecl(); + if (recordDecl && !recordDecl->getIdentifier()) { + return importRecordDecl(recordDecl, true, typedefName); + } + return importRecordDecl(recordDecl, true); + } + + if (auto *enumType = underlying->getAs()) { + auto *enumDecl = enumType->getDecl(); + if (enumDecl && !enumDecl->getIdentifier()) { + return importEnumDecl(enumDecl, true, typedefName); + } + return importEnumDecl(enumDecl, true); + } + + return nullptr; +} + glu::types::TypeBase * TypeConverter::convertEnumType(clang::EnumType const *type) { diff --git a/lib/ClangImporter/TypeConverter.hpp b/lib/ClangImporter/TypeConverter.hpp index cd54f09f..ae798e94 100644 --- a/lib/ClangImporter/TypeConverter.hpp +++ b/lib/ClangImporter/TypeConverter.hpp @@ -3,9 +3,12 @@ #include "ImporterContext.hpp" +#include + namespace clang { class EnumDecl; class RecordDecl; +class TypedefNameDecl; } // namespace clang #include @@ -20,10 +23,16 @@ class TypeConverter { TypeConverter(ImporterContext &ctx) : _ctx(ctx) { } glu::types::TypeBase *convert(clang::QualType clangType); + glu::types::TypeBase *importRecordDecl( + clang::RecordDecl *recordDecl, bool allowIncomplete, + llvm::StringRef forcedName = {} + ); + glu::types::TypeBase *importEnumDecl( + clang::EnumDecl *enumDecl, bool allowIncomplete, + llvm::StringRef forcedName = {} + ); glu::types::TypeBase * - importRecordDecl(clang::RecordDecl *recordDecl, bool allowIncomplete); - glu::types::TypeBase * - importEnumDecl(clang::EnumDecl *enumDecl, bool allowIncomplete); + importTypedefDecl(clang::TypedefNameDecl *typedefDecl); private: glu::types::TypeBase *convertBuiltinType(clang::BuiltinType const *type); diff --git a/tools/gluc/sources/CompilerDriver.cpp b/tools/gluc/sources/CompilerDriver.cpp index f96bf424..7bb1991d 100644 --- a/tools/gluc/sources/CompilerDriver.cpp +++ b/tools/gluc/sources/CompilerDriver.cpp @@ -53,6 +53,11 @@ std::vector CompilerDriver::findImportedObjectFiles() for (auto const &entry : importedFilesMap) { glu::FileID fileID = entry.first; llvm::StringRef filePath = sourceManager->getBufferName(fileID); + if (filePath.ends_with(".h")) { + // Headers are imported for declarations only and should not be + // linked. + continue; + } if (filePath.ends_with(".glu")) { std::string objPath = filePath.str(); objPath.replace(objPath.length() - 4, 4, ".o"); From 4b6f4172c8b5a250b01bbf7252b655e503a7685b Mon Sep 17 00:00:00 2001 From: Jeremy Elalouf Date: Thu, 29 Jan 2026 12:38:01 +0100 Subject: [PATCH 08/10] feat: simplify build for sfml demonstration --- demo/csfml/build.sh | 13 +++++++++++++ demo/csfml/build_csfml.sh | 27 --------------------------- demo/csfml/csfml_demo.glu | 25 ------------------------- demo/csfml/link.glu | 10 ++++++++++ 4 files changed, 23 insertions(+), 52 deletions(-) create mode 100755 demo/csfml/build.sh delete mode 100755 demo/csfml/build_csfml.sh delete mode 100644 demo/csfml/csfml_demo.glu create mode 100644 demo/csfml/link.glu diff --git a/demo/csfml/build.sh b/demo/csfml/build.sh new file mode 100755 index 00000000..b2e55286 --- /dev/null +++ b/demo/csfml/build.sh @@ -0,0 +1,13 @@ +#!/usr/bin/env bash + +SFML_INCLUDE="${SFML_INCLUDE:-/opt/homebrew/include}" +SFML_LIB="${SFML_LIB:-/opt/homebrew/lib}" + +export CPATH="$SFML_INCLUDE:$CPATH" +export GLU_LINKER="${GLU_LINKER:-clang++}" +xcrun gluc "./link.glu" \ + -Wl,-L"$SFML_LIB" \ + -Wl,-lsfml-graphics \ + -Wl,-lsfml-window \ + -Wl,-lsfml-system + diff --git a/demo/csfml/build_csfml.sh b/demo/csfml/build_csfml.sh deleted file mode 100755 index 08282d01..00000000 --- a/demo/csfml/build_csfml.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail - -ROOT_DIR="$(cd "$(dirname "$0")" && pwd)" -BUILD_DIR="$ROOT_DIR/build" - -SFML_INCLUDE="${SFML_INCLUDE:-/opt/homebrew/include}" -SFML_LIB="${SFML_LIB:-/opt/homebrew/lib}" - -mkdir -p "$BUILD_DIR" - -clang++ -std=c++17 -g -O2 \ - -I "$SFML_INCLUDE" \ - -c "$ROOT_DIR/sfml_host.cpp" \ - -o "$BUILD_DIR/sfml_host.o" - -export CPATH="$ROOT_DIR:$SFML_INCLUDE:$CPATH" -export GLU_LINKER="${GLU_LINKER:-clang++}" -gluc "$ROOT_DIR/csfml_demo.glu" \ - -Wl,"$BUILD_DIR/sfml_host.o" \ - -Wl,-L"$SFML_LIB" \ - -Wl,-lsfml-graphics \ - -Wl,-lsfml-window \ - -Wl,-lsfml-system \ - -o "$BUILD_DIR/sfml_demo" - -printf "Built: %s\n" "$BUILD_DIR/sfml_demo" diff --git a/demo/csfml/csfml_demo.glu b/demo/csfml/csfml_demo.glu deleted file mode 100644 index c06b4b1f..00000000 --- a/demo/csfml/csfml_demo.glu +++ /dev/null @@ -1,25 +0,0 @@ -@file_extension("zig") import motion as motion_zig; -@file_extension("rs") import palette as palette_mod; -@file_extension("d") import jitter as jitter_mod; - -@file_extension("h") @implement import sfml_host::glu_update_motion; -@file_extension("h") @implement import sfml_host::glu_color_from_frame; -@file_extension("h") @implement import sfml_host::glu_jitter; - -func glu_update_motion( - pos_xy: *Float32, - vel_xy: *Float32, - bounds_xy: *Float32, - radius: Float32, - dt: Float32 -) -> Void { - motion_zig::updateMotion(pos_xy, vel_xy, bounds_xy, radius, dt); -} - -func glu_color_from_frame(frame: UInt32, out_rgba: *UInt8) -> Void { - palette_mod::palette::color_from_frame(frame, out_rgba); -} - -func glu_jitter(frame: UInt32, strength: Float32, out_xy: *Float32) -> Void { - jitter_mod::jitter::jitter(frame, strength, out_xy); -} diff --git a/demo/csfml/link.glu b/demo/csfml/link.glu new file mode 100644 index 00000000..f157d855 --- /dev/null +++ b/demo/csfml/link.glu @@ -0,0 +1,10 @@ +@file_extension("cpp") import sfml_host; + +@file_extension("zig") import motion::updateMotion; +@file_extension("rs") import palette::palette::color_from_frame; +@file_extension("d") import jitter::jitter::jitter; + +@file_extension("h") @implement import sfml_host::glu_update_motion as updateMotion; +@file_extension("h") @implement import sfml_host::glu_color_from_frame as color_from_frame; +@file_extension("h") @implement import sfml_host::glu_jitter as jitter; + From 774c8f26d4eb831fe7a7bc7e8a3a08e39bf407a6 Mon Sep 17 00:00:00 2001 From: Jeremy Elalouf Date: Thu, 29 Jan 2026 13:09:22 +0100 Subject: [PATCH 09/10] feat: over simplified sfml demo with glu --- demo/benchmarker/main.glu | 2 +- demo/csfml/build.sh | 1 - demo/csfml/csfml.h | 8 ---- demo/csfml/jitter.d | 2 - demo/csfml/link.glu | 8 ++-- demo/csfml/palette.rs | 2 +- demo/csfml/{sfml_host.cpp => sfml.cpp} | 43 +------------------ demo/csfml/sfml.hpp | 20 +++++++++ demo/csfml/sfml_host.h | 20 --------- demo/csfml/stdbool.h | 14 ------ .../ConstraintSystem/ConversionVisitor.cpp | 27 +++++++++++- 11 files changed, 52 insertions(+), 95 deletions(-) delete mode 100644 demo/csfml/csfml.h rename demo/csfml/{sfml_host.cpp => sfml.cpp} (65%) create mode 100644 demo/csfml/sfml.hpp delete mode 100644 demo/csfml/sfml_host.h delete mode 100644 demo/csfml/stdbool.h diff --git a/demo/benchmarker/main.glu b/demo/benchmarker/main.glu index c31dd658..3e9100b8 100644 --- a/demo/benchmarker/main.glu +++ b/demo/benchmarker/main.glu @@ -6,7 +6,7 @@ import timer::Timer; import hexprint::hexprint; import random::random; -let debug_print: Bool = false; +let debug_print: Bool = true; func doWork() { var data: UInt8[100]; diff --git a/demo/csfml/build.sh b/demo/csfml/build.sh index b2e55286..6bf95322 100755 --- a/demo/csfml/build.sh +++ b/demo/csfml/build.sh @@ -10,4 +10,3 @@ xcrun gluc "./link.glu" \ -Wl,-lsfml-graphics \ -Wl,-lsfml-window \ -Wl,-lsfml-system - diff --git a/demo/csfml/csfml.h b/demo/csfml/csfml.h deleted file mode 100644 index 1bcf0ccd..00000000 --- a/demo/csfml/csfml.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef CSFML_H -#define CSFML_H - -#include -#include -#include - -#endif diff --git a/demo/csfml/jitter.d b/demo/csfml/jitter.d index bbbd2a0f..56cebe5d 100644 --- a/demo/csfml/jitter.d +++ b/demo/csfml/jitter.d @@ -1,7 +1,5 @@ module jitter; -extern(C): - void jitter(uint seed, float strength, float* out_xy) { if (out_xy is null) { return; diff --git a/demo/csfml/link.glu b/demo/csfml/link.glu index f157d855..9a8caece 100644 --- a/demo/csfml/link.glu +++ b/demo/csfml/link.glu @@ -1,10 +1,10 @@ -@file_extension("cpp") import sfml_host; +@file_extension("cpp") import sfml; @file_extension("zig") import motion::updateMotion; @file_extension("rs") import palette::palette::color_from_frame; @file_extension("d") import jitter::jitter::jitter; -@file_extension("h") @implement import sfml_host::glu_update_motion as updateMotion; -@file_extension("h") @implement import sfml_host::glu_color_from_frame as color_from_frame; -@file_extension("h") @implement import sfml_host::glu_jitter as jitter; +@implement import sfml::glu_update_motion as updateMotion; +@implement import sfml::glu_color_from_frame as color_from_frame; +@implement import sfml::glu_jitter as jitter; diff --git a/demo/csfml/palette.rs b/demo/csfml/palette.rs index dd893641..a90ae954 100644 --- a/demo/csfml/palette.rs +++ b/demo/csfml/palette.rs @@ -1,7 +1,7 @@ #![no_main] #[no_mangle] -pub extern "C" fn color_from_frame(frame: u32, out_rgba: *mut u8) { +pub fn color_from_frame(frame: u32, out_rgba: *mut u8) { if out_rgba.is_null() { return; } diff --git a/demo/csfml/sfml_host.cpp b/demo/csfml/sfml.cpp similarity index 65% rename from demo/csfml/sfml_host.cpp rename to demo/csfml/sfml.cpp index bc53d593..4f8a58ef 100644 --- a/demo/csfml/sfml_host.cpp +++ b/demo/csfml/sfml.cpp @@ -1,50 +1,9 @@ -#include "sfml_host.h" +#include "sfml.hpp" #include #include -#if defined(__GNUC__) - #define GLU_WEAK __attribute__((weak)) -#else - #define GLU_WEAK -#endif - -extern "C" GLU_WEAK void glu_update_motion( - float *pos_xy, float *vel_xy, float *bounds_xy, float radius, float dt -) -{ - (void) pos_xy; - (void) vel_xy; - (void) bounds_xy; - (void) radius; - (void) dt; -} - -extern "C" GLU_WEAK void glu_color_from_frame(uint32_t frame, uint8_t *out_rgba) -{ - (void) frame; - if (!out_rgba) { - return; - } - out_rgba[0] = 255; - out_rgba[1] = 255; - out_rgba[2] = 255; - out_rgba[3] = 255; -} - -extern "C" GLU_WEAK void -glu_jitter(uint32_t frame, float strength, float *out_xy) -{ - (void) frame; - (void) strength; - if (!out_xy) { - return; - } - out_xy[0] = 0.0f; - out_xy[1] = 0.0f; -} - int main() { constexpr unsigned int width = 800; diff --git a/demo/csfml/sfml.hpp b/demo/csfml/sfml.hpp new file mode 100644 index 00000000..21596cbc --- /dev/null +++ b/demo/csfml/sfml.hpp @@ -0,0 +1,20 @@ +#ifndef GLU_DEMO_SFML_HOST_H +#define GLU_DEMO_SFML_HOST_H + +#include + +#if defined(__GNUC__) + #define GLU_WEAK __attribute__((weak)) +#else + #define GLU_WEAK +#endif + +GLU_WEAK void glu_update_motion( + float *pos_xy, float *vel_xy, float *bounds_xy, float radius, float dt +) +{ +} +GLU_WEAK void glu_color_from_frame(uint32_t frame, uint8_t *out_rgba) { } +GLU_WEAK void glu_jitter(uint32_t frame, float strength, float *out_xy) { } + +#endif diff --git a/demo/csfml/sfml_host.h b/demo/csfml/sfml_host.h deleted file mode 100644 index dc42660b..00000000 --- a/demo/csfml/sfml_host.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef GLU_DEMO_SFML_HOST_H -#define GLU_DEMO_SFML_HOST_H - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -void glu_update_motion( - float *pos_xy, float *vel_xy, float *bounds_xy, float radius, float dt -); -void glu_color_from_frame(uint32_t frame, uint8_t *out_rgba); -void glu_jitter(uint32_t frame, float strength, float *out_xy); - -#ifdef __cplusplus -} -#endif - -#endif diff --git a/demo/csfml/stdbool.h b/demo/csfml/stdbool.h deleted file mode 100644 index a6e9dcf6..00000000 --- a/demo/csfml/stdbool.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef _STDBOOL_H -#define _STDBOOL_H - -#ifndef __cplusplus - #ifndef __bool_true_false_are_defined - #define __bool_true_false_are_defined 1 - -typedef _Bool bool; - #define true 1 - #define false 0 - #endif -#endif - -#endif diff --git a/lib/Sema/ConstraintSystem/ConversionVisitor.cpp b/lib/Sema/ConstraintSystem/ConversionVisitor.cpp index fac242e8..ca985699 100644 --- a/lib/Sema/ConstraintSystem/ConversionVisitor.cpp +++ b/lib/Sema/ConstraintSystem/ConversionVisitor.cpp @@ -192,8 +192,31 @@ class ConversionVisitor : public types::TypeVisitor { } // Implicit pointer conversions are more restrictive - // For now, only allow compatible pointee types (including type - // variables) + // Allow Int8/UInt8/Char pointee types to be considered equivalent + auto *fromPointee = fromPtr->getPointee(); + auto *toPointee = toPtr->getPointee(); + + // Check for Int8/UInt8/Char equivalence + if (!llvm::isa(fromPointee) + && !llvm::isa(toPointee)) { + + auto isCharOrByte = [](types::TypeBase *type) -> bool { + if (llvm::isa(type)) { + return true; + } + if (auto *intType = llvm::dyn_cast(type)) { + return intType->getBitWidth() == 8; // Int8 or UInt8 + } + return false; + }; + + if (isCharOrByte(fromPointee) && isCharOrByte(toPointee)) { + return true; + } + } + + // For other types, only allow compatible pointee types (including + // type variables) return _system->unify( fromPtr->getPointee(), toPtr->getPointee(), _state ); From 7c3570ee61151ebcff9697d9d3fc9b7b5280af0e Mon Sep 17 00:00:00 2001 From: Emil Pedersen Date: Sat, 31 Jan 2026 22:14:54 +0100 Subject: [PATCH 10/10] feat: add comparison between c and glu for benchmarking --- demo/comparison/via-c/Makefile | 34 +++++++++++++++++++++++++++++ demo/comparison/via-c/compute.zig | 19 ++++++++++++++++ demo/comparison/via-c/main.c | 22 +++++++++++++++++++ demo/comparison/via-c/random.d | 10 +++++++++ demo/comparison/via-glu/compute.zig | 19 ++++++++++++++++ demo/comparison/via-glu/main.glu | 14 ++++++++++++ demo/comparison/via-glu/random.d | 10 +++++++++ 7 files changed, 128 insertions(+) create mode 100644 demo/comparison/via-c/Makefile create mode 100644 demo/comparison/via-c/compute.zig create mode 100644 demo/comparison/via-c/main.c create mode 100644 demo/comparison/via-c/random.d create mode 100644 demo/comparison/via-glu/compute.zig create mode 100644 demo/comparison/via-glu/main.glu create mode 100644 demo/comparison/via-glu/random.d diff --git a/demo/comparison/via-c/Makefile b/demo/comparison/via-c/Makefile new file mode 100644 index 00000000..5fdc4f94 --- /dev/null +++ b/demo/comparison/via-c/Makefile @@ -0,0 +1,34 @@ +.PHONY: all clean run + +CC = clang +DC = ldc2 +ZIG = zig + +CFLAGS = -O3 +DFLAGS = -O3 +ZIGFLAGS = -O ReleaseFast + +TARGET = a.out +C_SRC = main.c +D_SRC = random.d +ZIG_SRC = compute.zig + +D_OBJ = random.o +ZIG_OBJ = compute.o + +all: $(TARGET) + +$(D_OBJ): $(D_SRC) + $(DC) $(DFLAGS) -c $(D_SRC) -of=$(D_OBJ) + +$(ZIG_OBJ): $(ZIG_SRC) + $(ZIG) build-obj $(ZIG_SRC) $(ZIGFLAGS) -femit-bin=$(ZIG_OBJ) + +$(TARGET): $(C_SRC) $(D_OBJ) $(ZIG_OBJ) + $(DC) $(C_SRC) $(D_OBJ) $(ZIG_OBJ) -of=$(TARGET) -L-w + +run: $(TARGET) + time ./$(TARGET) + +clean: + rm -f $(TARGET) $(D_OBJ) $(ZIG_OBJ) diff --git a/demo/comparison/via-c/compute.zig b/demo/comparison/via-c/compute.zig new file mode 100644 index 00000000..0ce18bc8 --- /dev/null +++ b/demo/comparison/via-c/compute.zig @@ -0,0 +1,19 @@ +const std = @import("std"); +const sha256 = std.crypto.hash.sha2.Sha256; + +/// Compute SHA256 hash of data +export fn hashBytes(data: [*]const u8, len: usize, output: *[32]u8) void { + sha256.hash(data[0..len], output, .{}); +} + +/// Verify if data matches expected hash +export fn verifyHash(data: [*]const u8, len: usize, expected: *const [32]u8) bool { + var actual: [32]u8 = undefined; + sha256.hash(data[0..len], &actual, .{}); + return std.mem.eql(u8, &actual, expected); +} + +/// Compare two hashes for equality +export fn compareHashes(hash1: *const [32]u8, hash2: *const [32]u8) bool { + return std.mem.eql(u8, hash1, hash2); +} diff --git a/demo/comparison/via-c/main.c b/demo/comparison/via-c/main.c new file mode 100644 index 00000000..7c06e7b5 --- /dev/null +++ b/demo/comparison/via-c/main.c @@ -0,0 +1,22 @@ +#include +#include + +// External function declarations from Zig (compute.zig) +extern void hashBytes(uint8_t const *data, size_t len, uint8_t output[32]); + +// External function declarations from D (random.d) +extern void fill_random(uint8_t *data, size_t len); + +int main() +{ + for (int i = 0; i < 1000000; i++) { + uint8_t data[100]; + size_t length = 100; + uint8_t hash[32] = { 0 }; + + fill_random(data, length); + hashBytes(data, length, hash); + } + + return 0; +} diff --git a/demo/comparison/via-c/random.d b/demo/comparison/via-c/random.d new file mode 100644 index 00000000..5aa2bcb2 --- /dev/null +++ b/demo/comparison/via-c/random.d @@ -0,0 +1,10 @@ +import std.random; + +/// Fill array with random bytes +extern(C) void fill_random(ubyte* data, size_t len) { + auto rng = Random(unpredictableSeed); + foreach (i; 0 .. len) { + data[i] = cast(ubyte)(rng.front % 256); + rng.popFront(); + } +} diff --git a/demo/comparison/via-glu/compute.zig b/demo/comparison/via-glu/compute.zig new file mode 100644 index 00000000..0ce18bc8 --- /dev/null +++ b/demo/comparison/via-glu/compute.zig @@ -0,0 +1,19 @@ +const std = @import("std"); +const sha256 = std.crypto.hash.sha2.Sha256; + +/// Compute SHA256 hash of data +export fn hashBytes(data: [*]const u8, len: usize, output: *[32]u8) void { + sha256.hash(data[0..len], output, .{}); +} + +/// Verify if data matches expected hash +export fn verifyHash(data: [*]const u8, len: usize, expected: *const [32]u8) bool { + var actual: [32]u8 = undefined; + sha256.hash(data[0..len], &actual, .{}); + return std.mem.eql(u8, &actual, expected); +} + +/// Compare two hashes for equality +export fn compareHashes(hash1: *const [32]u8, hash2: *const [32]u8) bool { + return std.mem.eql(u8, hash1, hash2); +} diff --git a/demo/comparison/via-glu/main.glu b/demo/comparison/via-glu/main.glu new file mode 100644 index 00000000..820cc769 --- /dev/null +++ b/demo/comparison/via-glu/main.glu @@ -0,0 +1,14 @@ + +import compute; +import random::random; + +func main() { + for i in 0..<1000000 { + var data: UInt8[100]; + let length: UInt64 = 100; + var hash: UInt8[32] = {0}; + + random::fill_random(data, length); + compute::hashBytes(data, length, &hash); + } +} diff --git a/demo/comparison/via-glu/random.d b/demo/comparison/via-glu/random.d new file mode 100644 index 00000000..fc580b11 --- /dev/null +++ b/demo/comparison/via-glu/random.d @@ -0,0 +1,10 @@ +import std.random; + +/// Fill array with random bytes +void fill_random(ubyte* data, size_t len) { + auto rng = Random(unpredictableSeed); + foreach (i; 0 .. len) { + data[i] = cast(ubyte)(rng.front % 256); + rng.popFront(); + } +}