Skip to content
This repository was archived by the owner on Aug 28, 2026. It is now read-only.

whitelist pocl_flush_printf_buffer - #1

Closed
vchuravy wants to merge 6 commits into
release_7_2from
vc/flush_printf
Closed

whitelist pocl_flush_printf_buffer#1
vchuravy wants to merge 6 commits into
release_7_2from
vc/flush_printf

Conversation

@vchuravy

@vchuravy vchuravy commented Jul 4, 2026

Copy link
Copy Markdown
Member

No description provided.

maleadt and others added 6 commits July 2, 2026 10:58
GNU ld is pathologically slow at linking the static LLVM/Clang archives
into a PE/COFF DLL (tens of minutes for libpocl). ld.lld is far faster,
but its COFF driver doesn't implement GNU ld's --exclude-libs, which
libpocl used to keep the static-lib symbols out of its auto-generated
export table. Without that, auto-exporting the whole static LLVM blob
overflows the 64K PE export-ordinal limit.

Switch MinGW to the MSVC-style export model, which works with both GNU ld
and lld:

- stamp __declspec(dllexport) on the OpenCL API for any Windows toolchain
  (defined(_WIN32)), not just _MSC_VER;
- define EXPORT_POCL_LIB / IMPORT_POCL_LIB for any WIN32 shared build, not
  just MSVC;
- export only the dllexport'd symbols (--exclude-all-symbols) instead of
  auto-export-minus-static-libs (--exclude-libs).

Because libpocl now exports only its public API, its internal symbols are
no longer visible to separately-dlopen'd driver modules, so consumers must
build with ENABLE_LOADABLE_DRIVERS=OFF (drivers linked into libpocl).

Also make the spirv_fix_atomic_compare_exchange helper compile its own copy
of spirv_parser.cc in the non-ICD case, mirroring the ICD branch, so it no
longer relies on SPIRVParser being exported from libpocl.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
With cl_khr_fp16 enabled, the host CPU kernel library must provide half
overloads for the OpenCL math builtins exposed through the FP16 wrappers. Some
of those builtins have Clang/LLVM FP16 lowerings, but others have no native
FP16 lowering and no SLEEF FP16 implementation. In vectorized host builds those
promoted-only overloads were still missing, so half kernels could fail at build
time with unresolved _cl_<fn>(half) symbols or unresolved host libm calls.

Split the implementations by lowering path. additionalf16.cl now contains only
the overloads backed directly by Clang/LLVM FP16 intrinsics, and remains limited
to the non-vectorized build where those definitions do not collide with the
generic vectorized sources. promotedf16.cl contains the overloads that have to
be built in both configurations: logb, ilogb, ldexp, rootn, pown, remainder,
nextafter, powr, modf, and remquo.

The promoted overloads call pocl's renamed float OpenCL builtins and round back
to half, or compute nextafter directly on the half bit pattern. This keeps the
kernel library self-contained instead of lowering to unresolved host libm
symbols such as logbf, modff, or remquof. pown and powr move out of powf16.cl
for the same reason: powf16.cl is non-vectorized-only, while pown and powr have
no native FP16 provider in the vectorized configuration.

Define scalar, vector, and address-space pointer forms for modf and remquo by
doing the pointer work through private temporaries before storing to the
requested output address space. Add the small FP16 binary and ternary template
helpers used by the intrinsic-backed definitions.

Add an OpenCL C regression test that keeps the scalar and vector half builtin
calls live and catches the unresolved-symbol failure in the vectorized host
configuration.
Instead of linking each compiled kernel object into a shared library
and dlopen()ing it, load the object directly into the process with
LLVM's ORC LLJIT, using the JITLink object-linking layer. JITLink
resolves relocations, maps the code into executable memory and
registers EH frames, so it acts as both the linker and the loader: no
shared library is written and the OS loader is not involved. That makes
the CPU drivers work with the kernel cache on a noexec filesystem and
in statically linked deployments, and lets kernels be unloaded again.

The JIT is gated by the new HOST_CPU_ENABLE_JIT CMake option, on by
default wherever JITLink has a backend: ELF and Mach-O hosts, plus
Windows x86-64 (MinGW) via COFF_x86_64 (with the large code model,
since that backend synthesizes no far-call stubs). POCL_CPU_JIT=0
selects the link path at run time, and a failed JIT bring-up latches it
automatically. Symbols resolve against the process and libpocl's own
handle; the configure-time vector-math library is exposed to the JIT as
well (libmvec/SLEEF dynamically, SVML from its static archives).

The cached artifact is the relocatable object itself (<kernel>.o
instead of <kernel>.so), but caches and poclbinaries stay
mode-agnostic: the loader accepts either artifact, linking or
JIT-loading whatever it finds, and poclbinary export links any
JIT-only objects into shared libraries so consumers without the JIT or
without LLVM can still use them. Lookup failures surface JITLink's
diagnostic through pocl_jit_last_error(), a dlerror() analogue.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
parseModuleIR/parseModuleIRMem can return null for a corrupt or
version-incompatible program.bc (e.g. a stale kernel-cache entry left by an
older driver build). The callers only had asserts, compiled out in a release
driver, so this dereferenced null in parseModuleGVarSize and crashed the whole
process.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
pocl_read_file2/pocl_write_file2 obtained a descriptor from openFileForRead /
openFileForWrite / createUniqueFile but released it via
closeFile(convertFDToNativeFile(fd)). On Windows that fd wraps a HANDLE created
through _open_osfhandle(): closing the HANDLE leaves the CRT fd-table slot
allocated. pocl.dll shares that table with the host process, so every kernel
compilation leaked a couple of slots and the host eventually hit EMFILE. Close
the fd directly with Process::SafelyCloseFileDescriptor() instead.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
maleadt added a commit to maleadt/pocl that referenced this pull request Jul 5, 2026
Commit 107dd8e made JIT work-group objects self-contained by running link() over parallel.bc again. At program build time link() runs its unresolved-symbol check before handleDeviceSidePrintf() adds the pocl_flush_printf_buffer declaration. The second JIT relink therefore sees that host-only declaration as an unresolved kernel-library symbol and rejects printf-using kernels on Linux/macOS where ENABLE_PRINTF_IMMEDIATE_FLUSH is enabled.

Teach link() whether unresolved declarations should be errors. Keep the program-stage link strict, but skip the post-link unresolved-symbol check for the JIT relink. Any declarations still unresolved after copying kernel-library bodies are resolved by the later runtime stage, matching the ORC process-symbol path used for pocl host callbacks and the shared-library path's dynamic linker contract.

This fixes KernelAbstractions.jl CI failures for JIT kernels carrying printf machinery and supersedes the symbol-whitelist workaround from JuliaGPU#1.

No new test; cpu_jit/printf_flush covers the regression.
@maleadt

maleadt commented Jul 5, 2026

Copy link
Copy Markdown
Member

Alternative: pocl@098f5a2, being built in JuliaPackaging/Yggdrasil#14140.

@vchuravy vchuravy closed this Jul 5, 2026
maleadt added a commit to maleadt/pocl that referenced this pull request Jul 8, 2026
Commit 107dd8e made JIT work-group objects self-contained by running link() over parallel.bc again. At program build time link() runs its unresolved-symbol check before handleDeviceSidePrintf() adds the pocl_flush_printf_buffer declaration. The second JIT relink therefore sees that host-only declaration as an unresolved kernel-library symbol and rejects printf-using kernels on Linux/macOS where ENABLE_PRINTF_IMMEDIATE_FLUSH is enabled.

Teach link() whether unresolved declarations should be errors. Keep the program-stage link strict, but skip the post-link unresolved-symbol check for the JIT relink. Any declarations still unresolved after copying kernel-library bodies are resolved by the later runtime stage, matching the ORC process-symbol path used for pocl host callbacks and the shared-library path's dynamic linker contract.

This fixes KernelAbstractions.jl CI failures for JIT kernels carrying printf machinery and supersedes the symbol-whitelist workaround from JuliaGPU#1.

No new test; cpu_jit/printf_flush covers the regression.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants