Intel's compiler turns rotate(x, (0u - n) & 31u) into a rotate LEFT by n: lane 0's register trace on the B580 diverged at instruction 6 of iteration 0 (rotr) and nowhere before, in both exchange modes, with every other family and the dataset kernels bit-exact. proto-opencl/intel_rotr.h rewrites the one helper line when the device's vendor or platform string holds Intel (host.c's buildProgram and the prepare path), no other vendor sees a change, no pack or consensus text moves. proto-opencl/test_intel_rotr.c (the pre-push gate runs it) feeds the line through the rewrite under Intel, AMD and NVIDIA strings and asserts the outputs. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> (cherry picked from commit 26e135a362718a68a842da59080b43e93afd9dc2)
40 lines
2.4 KiB
C
40 lines
2.4 KiB
C
/* intel_rotr.h: the Intel rotate fold (7 October 2026, the Arc B580 register-trace bisect, docs/plans/intel-arc.md
|
|
* section 7). Intel's OpenCL compiler turns the pack's `rotr_var(x, n) = rotate(x, (0u - n) & 31u)` into a rotate LEFT
|
|
* by n (the negation dropped), so every variable right-rotate of every program came out wrong on the Arc while every
|
|
* other family and the dataset kernels were bit-exact (lane 0's trace diverged at instruction 6 of iteration 0, rotr,
|
|
* and nowhere before; job run-ia-arc-trace-20261007-b). On an Intel platform the worker rewrites that one helper line
|
|
* to the shift form the CPU interpreter and the family probe compute, before clCreateProgramWithSource; the text is
|
|
* otherwise untouched and no other vendor sees a change. Shared by host.c and test_intel_rotr.c (the gate's test). */
|
|
#ifndef IGNEUM_INTEL_ROTR_H
|
|
#define IGNEUM_INTEL_ROTR_H
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
static const char* IGNEUM_ROTR_BUILTIN = "static inline uint rotr_var(uint x, uint n) { return rotate(x, (0u - n) & 31u); }";
|
|
static const char* IGNEUM_ROTR_SHIFTS = "static inline uint rotr_var(uint x, uint n) { n &= 31u; return (x >> n) | (x << ((32u - n) & 31u)); }";
|
|
|
|
/* Returns the source to build: the original pointer when nothing applies, else a new buffer (the caller frees it when
|
|
* `*patched` is set) with the one line replaced and `*srcLen` updated. `vendor` and `platform` are the device's
|
|
* CL_DEVICE_VENDOR and the platform name; only a string holding "Intel" is rewritten. `quiet` suppresses the line. */
|
|
static char* igneum_intel_rotr_patch(const char* vendor, const char* platform, const char* src, size_t* srcLen, int* patched, int quiet) {
|
|
const char* at;
|
|
char* out;
|
|
size_t a = strlen(IGNEUM_ROTR_BUILTIN), b = strlen(IGNEUM_ROTR_SHIFTS), pre;
|
|
*patched = 0;
|
|
if (!((vendor && strstr(vendor, "Intel")) || (platform && strstr(platform, "Intel")))) return (char*)src;
|
|
at = strstr(src, IGNEUM_ROTR_BUILTIN);
|
|
if (!at) return (char*)src;
|
|
pre = (size_t)(at - src);
|
|
out = (char*)malloc(*srcLen - a + b + 1);
|
|
if (!out) return (char*)src;
|
|
memcpy(out, src, pre);
|
|
memcpy(out + pre, IGNEUM_ROTR_SHIFTS, b);
|
|
memcpy(out + pre + b, at + a, *srcLen - pre - a);
|
|
out[*srcLen - a + b] = 0;
|
|
*srcLen = *srcLen - a + b;
|
|
*patched = 1;
|
|
if (!quiet) printf("intel: rotr_var rewritten to the shift form before the build (the rotate fold of 7 October 2026)\n");
|
|
return out;
|
|
}
|
|
#endif
|