OpenCL worker: on an Intel platform rotr_var is rewritten to the shift form before the build (the Intel rotate fold, the Arc B580 bisect of 7 October 2026)

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)
This commit is contained in:
igneum-labs 2026-10-07 11:21:21 +00:00
parent d2028b9454
commit 11e2dec70b
4 changed files with 104 additions and 1 deletions

View file

@ -508,8 +508,17 @@ typedef struct {
static const char* exchangeName(int m) { return m == 1 ? "sub_group_shuffle_xor (cl_khr_subgroup_shuffle)" : m == 2 ? "intel_sub_group_shuffle_xor (cl_intel_subgroups)" : "local-memory exchange with barrier"; }
// Returns 0 on success, 1 on build failure (log printed).
#include "intel_rotr.h" /* the Intel rotate fold: rotr_var rewritten on an Intel platform (7 October 2026) */
static char* intelRotrPatch(const DeviceInfo* di, const char* src, size_t* srcLen, int* patched) {
if (!di) { *patched = 0; return (char*)src; }
return igneum_intel_rotr_patch(di->vendor, di->platformName, src, srcLen, patched, 0);
}
static int buildProgram(Device* dv, const DeviceInfo* di, const char* src, size_t srcLen, int exchangeMode, int groupSize, const char* extra) {
cl_int err = 0;
int patched = 0;
char* psrc = intelRotrPatch(di, src, &srcLen, &patched);
src = psrc;
double tb = wallMs(); /* the pack's compile cost (Counter ASIC 3.0 item 2, 6 October 2026): printed as one line below */
const char* std;
// The sub-group built-ins need OpenCL C 2.0 or 3.0. OpenCL 3.0 devices may report "OpenCL C 1.2" as the default
@ -522,6 +531,7 @@ static int buildProgram(Device* dv, const DeviceInfo* di, const char* src, size_
else std = "-cl-std=CL1.2";
snprintf(dv->buildOptions, sizeof(dv->buildOptions), "%s -D IGNEUM_GROUP=%d -D IGNEUM_EXCHANGE=%d %s", std, groupSize, exchangeMode, extra);
dv->prog = clCreateProgramWithSource(dv->ctx, 1, &src, &srcLen, &err);
if (patched) free(psrc);
CL_CHECK_ERR(err, "clCreateProgramWithSource");
err = clBuildProgram(dv->prog, 1, &di->device, dv->buildOptions, NULL, NULL);
if (err != CL_SUCCESS) {
@ -1315,7 +1325,12 @@ static void prepareRun(PrepareTask* t) {
src = readFile(path, &srcLen);
if (!src) { snprintf(t->error, sizeof(t->error), "cannot read %s", path); releasePair(p); t->doneAt = wallMs(); t->done = 1; return; }
tb = wallMs();
p->prog = clCreateProgramWithSource(t->dv->ctx, 1, (const char**)&src, &srcLen, &err);
{
int patched = 0;
char* psrc = intelRotrPatch(t->di, src, &srcLen, &patched);
p->prog = clCreateProgramWithSource(t->dv->ctx, 1, (const char**)&psrc, &srcLen, &err);
if (patched) free(psrc);
}
free(src);
if (err != CL_SUCCESS) { prepareFail(t, "clCreateProgramWithSource", err); releasePair(p); t->doneAt = wallMs(); t->done = 1; return; }
err = clBuildProgram(p->prog, 1, &t->di->device, t->dv->buildOptions, NULL, NULL);

40
proto-opencl/intel_rotr.h Normal file
View file

@ -0,0 +1,40 @@
/* 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

View file

@ -0,0 +1,47 @@
/* test_intel_rotr.c: the gate's test of intel_rotr.h (7 October 2026). Feeds a kernel text holding the pack's rotr_var
* helper line through the rewrite under an Intel vendor string and under AMD's and NVIDIA's, and asserts: the Intel
* output carries the shift form and nothing else changed (the bytes before and after the line equal), the AMD and
* NVIDIA outputs are the input pointer, untouched; a text without the line is returned untouched on Intel too.
* cc -std=c99 -Wall -Wextra -o test_intel_rotr proto-opencl/test_intel_rotr.c && ./test_intel_rotr */
#include "intel_rotr.h"
#include <assert.h>
int main(void) {
const char* pre = "static inline uint rotl_imm(uint x, uint n) { return rotate(x, n); }\n";
const char* post = "\nstatic inline uint ds_elem(uint i, uint d0, uint d1) { return i ^ d0 ^ d1; }\n";
char text[1024];
size_t len, plen, blen = strlen(IGNEUM_ROTR_BUILTIN), slen = strlen(IGNEUM_ROTR_SHIFTS);
int patched = -1;
char* out;
snprintf(text, sizeof(text), "%s%s%s", pre, IGNEUM_ROTR_BUILTIN, post);
len = strlen(text);
/* Intel: the one line becomes the shift form, the rest is byte for byte the same */
plen = len;
out = igneum_intel_rotr_patch("Intel(R) Corporation", "Intel(R) OpenCL Graphics", text, &plen, &patched, 1);
assert(patched == 1);
assert(out != text);
assert(plen == len - blen + slen);
assert(strlen(out) == plen);
assert(memcmp(out, pre, strlen(pre)) == 0);
assert(memcmp(out + strlen(pre), IGNEUM_ROTR_SHIFTS, slen) == 0);
assert(strcmp(out + strlen(pre) + slen, post) == 0);
assert(strstr(out, "rotate(x, (0u - n)") == NULL);
free(out);
/* the platform name alone names Intel too (a vendor string of another spelling) */
plen = len; patched = -1;
out = igneum_intel_rotr_patch("GenuineIntel", "Intel(R) OpenCL Graphics", text, &plen, &patched, 1);
assert(patched == 1 && out != text); free(out);
/* AMD and NVIDIA: untouched, the input pointer back, the length unchanged */
plen = len; patched = -1;
out = igneum_intel_rotr_patch("Advanced Micro Devices, Inc.", "AMD Accelerated Parallel Processing", text, &plen, &patched, 1);
assert(patched == 0 && out == text && plen == len && strstr(text, IGNEUM_ROTR_BUILTIN) != NULL);
plen = len; patched = -1;
out = igneum_intel_rotr_patch("NVIDIA Corporation", "NVIDIA CUDA", text, &plen, &patched, 1);
assert(patched == 0 && out == text && plen == len);
/* Intel with no helper line (a probe kernel): untouched */
plen = strlen(pre); patched = -1;
out = igneum_intel_rotr_patch("Intel(R) Corporation", "Intel(R) OpenCL Graphics", pre, &plen, &patched, 1);
assert(patched == 0 && out == pre && plen == strlen(pre));
printf("test_intel_rotr: ok (Intel rewritten to the shift form, AMD and NVIDIA untouched, no line untouched)\n");
return 0;
}

View file

@ -83,6 +83,7 @@ tree_checks() {
run "heat gate reader self-test (a known hold passes, a known drift fails)" node tools/heat-gate.mjs --self-test
run "relay unit tests" node --test relay/test/parse.test.mjs relay/test/auth.test.mjs relay/test/wake.test.mjs relay/test/ember.test.mjs
run "miner app notice strip and update card tests" node --test app/igneum-app/ui/notices.test.mjs app/igneum-app/ui/update-card.test.mjs app/igneum-app/ui/view.test.mjs app/igneum-app/ui/tune-line.test.mjs app/igneum-app/ui/ui-ota.test.mjs
run "the Intel rotate-fold rewrite: Intel gets the shift form, AMD and NVIDIA untouched (proto-opencl/test_intel_rotr.c)" bash -c 'cc -std=c99 -Wall -Wextra -o "${TMPDIR:-/tmp}/test_intel_rotr.$$" proto-opencl/test_intel_rotr.c && "${TMPDIR:-/tmp}/test_intel_rotr.$$"; s=$?; rm -f "${TMPDIR:-/tmp}/test_intel_rotr.$$"; exit $s'
run "no secret file names and no 64-hex secrets in the tree" bash -c 'bash tools/ci/no-secrets-check.sh --self-test && bash tools/ci/no-secrets-check.sh'
}