logicaffeine_compile/codegen_cuda/
runtime.rs1pub const CUDA_DEVICE_PREAMBLE: &str = r#"// Auto-generated by LOGOS codegen_cuda — do not edit.
14// A whole LOGOS program lowered to ONE CUDA kernel (launched <<<1,1>>>). Only the runtime slice the
15// program references is lifted here as __device__ functions (tree-shaken from the C oracle), plus the
16// program's own code; `Show` rides CUDA's native device printf, so output is byte-identical to the VM.
17#include <cstdio>
18#include <cstdint>
19#include <cinttypes>
20#include <cstring>
21#include <cstdlib>
22#include <cmath>
23
24// --- lifted LOGOS runtime slice (device) ----------------------------------------
25"#;
26
27pub const CUDA_DEVICE_ALLOC_SHIM: &str = r#"// --- device allocator shim (header-carrying malloc so realloc works) ------------
34__device__ static void* logos_malloc(size_t n){ size_t* p=(size_t*)malloc(n+16); if(!p) return (void*)0; p[0]=n; return (void*)((char*)p+16); }
35__device__ static void logos_free(void* q){ if(q) free((void*)((char*)q-16)); }
36__device__ static void* logos_realloc(void* q, size_t n){ if(!q) return logos_malloc(n); size_t old=((size_t*)((char*)q-16))[0]; void* r=logos_malloc(n); if(r){ size_t m=old<n?old:n; memcpy(r,q,m); logos_free(q);} return r; }
37__device__ static void* logos_calloc(size_t c, size_t s){ size_t n=c*s; void* r=logos_malloc(n); if(r) memset(r,0,n); return r; }
38__device__ static char* logos_strdup(const char* s){ size_t n=0; while(s[n]) n++; char* r=(char*)logos_malloc(n+1); if(r){ memcpy(r,s,n); r[n]=0; } return r; }
39// --- lifted LOGOS runtime slice (device) ----------------------------------------
40"#;
41
42pub const CUDA_DEVICE_INTRIN_SHIM: &str = r#"// --- device checked-overflow builtins (via __int128) ----------------------------
47__device__ static int logos_add_overflow(int64_t a, int64_t b, int64_t* r){ __int128 s=(__int128)a+(__int128)b; *r=(int64_t)s; return s != (__int128)(int64_t)s; }
48__device__ static int logos_sub_overflow(int64_t a, int64_t b, int64_t* r){ __int128 s=(__int128)a-(__int128)b; *r=(int64_t)s; return s != (__int128)(int64_t)s; }
49__device__ static int logos_mul_overflow(int64_t a, int64_t b, int64_t* r){ __int128 s=(__int128)a*(__int128)b; *r=(int64_t)s; return s != (__int128)(int64_t)s; }
50"#;
51
52pub const CUDA_DEVICE_INTEGRAL_ROUNDING: &str = r#"// --- floor/ceil/round of an integer argument (C's double conversion) ------------
57__host__ __device__ static inline double floor(long long x){ return (double)x; }
58__host__ __device__ static inline double floor(long x){ return (double)x; }
59__host__ __device__ static inline double floor(int x){ return (double)x; }
60__host__ __device__ static inline double ceil(long long x){ return (double)x; }
61__host__ __device__ static inline double ceil(long x){ return (double)x; }
62__host__ __device__ static inline double ceil(int x){ return (double)x; }
63__host__ __device__ static inline double round(long long x){ return (double)x; }
64__host__ __device__ static inline double round(long x){ return (double)x; }
65__host__ __device__ static inline double round(int x){ return (double)x; }
66"#;
67
68pub const CUDA_DEVICE_FAULT_SHIM: &str = r#"// --- device runtime-error path (stderr elided; nonzero exit / abort -> trap) ----
79__device__ static int logos_stderr_sink = 0;
80__device__ static int logos_stdout_sink = 0;
81__device__ static int logos_fprintf(int sink, const char *fmt, ...) { (void)sink; (void)fmt; return 0; }
82__device__ static int logos_fflush(int sink) { (void)sink; return 0; }
83__device__ static void logos_exit(int code) { if (code != 0) { asm("trap;"); } }
84__device__ static void logos_abort(void) { asm("trap;"); }
85"#;
86
87pub const CUDA_DEVICE_CLOCK: &str = r#"// --- device clock (host injects the fixed instant before launch) ----------------
94__device__ long long logos_dev_fixed_days = 0;
95__device__ long long logos_dev_fixed_nanos = 0;
96"#;
97
98pub const CUDA_DEVICE_STEPPED_PROLOGUE: &str = r#"// --- the stepped scheduler (device) ---------------------------------------------
105#define LOGOS_FN __device__ static
106#define LOGOS_VAR __device__ static
107#define LOGOS_API __device__ static
108#define logos_alloc(n) logos_calloc(1, (n))
109#define logos_release(p) logos_free(p)
110typedef int (*logos_step_fn)(void *);
111#define LOGOS_TASK_TIER logos_step_fn step; void *frame;
112#define LOGOS_STEP_NO_ESCAPE
113__device__ unsigned long long logos_dev_seed = 0;
114#define LOGOS_RUN_SEED logos_dev_seed
115__device__ int logos_dev_failed = 0;
116__device__ char logos_dev_failure[256];
117__device__ static void logos_dev_fail(const char *message) {
118 int i = 0;
119 for (; message[i] && i < 255; i++) logos_dev_failure[i] = message[i];
120 logos_dev_failure[i] = 0;
121 logos_dev_failed = 1;
122}
123#define LOGOS_RUN_FAILS(message) logos_dev_fail(message)
124"#;
125
126pub const CUDA_HOST_SEED_READER: &str = include_str!("../codegen_c/host_seed.c");
130pub const CUDA_HOST_RUN_SEED: &str =
131 " { unsigned long long seed = logos_env_seed(0); cudaMemcpyToSymbol(logos_dev_seed, &seed, sizeof seed); }\n";
132pub const CUDA_HOST_RUN_FAILED: &str = " { int failed = 0; cudaMemcpyFromSymbol(&failed, logos_dev_failed, sizeof failed);\n \
133 if (failed) { char message[256]; cudaMemcpyFromSymbol(message, logos_dev_failure, sizeof message); \
134 fprintf(stderr, \"%s\\n\", message); return 1; } }\n";
135
136pub const CUDA_HOST_TEMPLATE: &str = r#"
140__global__ void logos_kernel() { (void) logos_main(0, (char **)0); }
141
142// --- host orchestrator ----------------------------------------------------------
143#include <cstdlib>
144#include <ctime>
145#include <cstring>
146/*LOGOS_HOST_SEED_READER*/
147int main(int argc, char **argv) {
148 (void)argc; (void)argv;
149 // The device runtime uses recursion + a fixed-limb bignum on the stack (the shortest-float
150 // formatter) and device malloc (string/heap builders); raise both limits above their small
151 // defaults so a whole program runs on one thread.
152 cudaDeviceSetLimit(cudaLimitStackSize, (size_t)64 * 1024);
153 cudaDeviceSetLimit(cudaLimitMallocHeapSize, (size_t)256 * 1024 * 1024);
154 // Inject the deterministic fixed clock the device `today`/`now` read, mirroring codegen_c's
155 // getenv(LOGOS_FIXED_*)-or-time() shim on the HOST, then copy it into the device globals. Always set;
156 // a non-temporal program simply never reads them.
157 { const char *e; long long v;
158 e = getenv("LOGOS_FIXED_DAYS"); v = e ? atoll(e) : (long long)(time(NULL) / 86400);
159 cudaMemcpyToSymbol(logos_dev_fixed_days, &v, sizeof(v));
160 e = getenv("LOGOS_FIXED_NANOS"); v = e ? atoll(e) : (long long)time(NULL) * 1000000000LL;
161 cudaMemcpyToSymbol(logos_dev_fixed_nanos, &v, sizeof(v)); }
162/*LOGOS_ARGV_MARSHAL*/
163/*LOGOS_HOST_RUN_SEED*/
164 logos_kernel<<<1, 1>>>();
165 cudaError_t err = cudaGetLastError();
166 if (err != cudaSuccess) { fprintf(stderr, "kernel launch: %s\n", cudaGetErrorString(err)); return 1; }
167 err = cudaDeviceSynchronize();
168 if (err != cudaSuccess) { fprintf(stderr, "kernel exec: %s\n", cudaGetErrorString(err)); return 1; }
169/*LOGOS_HOST_RUN_FAILED*/
170 return 0;
171}
172"#;
173
174pub const KERNEL_FILE_NAME: &str = "logos_cuda.cu";
176
177pub const CUDA_MAKEFILE_TEMPLATE: &str = r#"# Auto-generated by LOGOS codegen_cuda.
181# Builds the single-file CUDA program with nvcc. Override ARCH for other GPUs.
182ARCH ?= sm_86
183NVCC ?= nvcc
184logos_cuda: {KERNEL_FILE}
185 $(NVCC) -O2 -arch=$(ARCH) -fmad=false $< -o $@
186.PHONY: clean
187clean:
188 rm -f logos_cuda
189"#;