How to Fix: PCC facts checking failed on some workloads
PCC fact checking fails on some PolyBenchC workloads because the generated proof uses operations the validator does not yet support.
If you see an error like Proof-carrying-code validation error: Unsupported… while running PCC checks against PolyBenchC 4.2.1, the problem is usually not the benchmark itself. The failure typically comes from a mismatch between the workload’s compiled IR or machine-level constructs and the subset of instructions, facts, or proof rules currently implemented by the PCC validator. Some PolyBenchC kernels trigger code patterns that simpler workloads never hit, so validation fails only on specific programs.
Understanding the Root Cause
This bug appears when PCC validation encounters a construct it cannot reason about. In practice, that usually means one of these things:
- The compiler emits an instruction form or optimization pattern that the checker does not support.
- The benchmark triggers memory access shapes, loop transformations, or integer arithmetic forms that are outside the validator’s supported proof model.
- The proof generator and proof checker are built from different revisions, causing a format or semantic mismatch.
- A specific PolyBenchC workload enables aggressive optimization behavior, such as loop unrolling, vectorization, or strength reduction, and the generated facts no longer match what the checker expects.
PolyBenchC is especially good at surfacing this class of bug because its kernels contain dense numerical loops, affine indexing, and optimization-friendly code. That makes it more likely to produce edge-case IR compared with smaller test inputs.
The key idea is this: PCC validation does not fail randomly. It fails because a workload produces a proof obligation that the checker cannot currently validate. So the fix is usually to either reduce the unsupported construct, align tool versions, or extend/patch the validator.
Step-by-Step Solution
Use the following workflow to isolate and fix the issue systematically.
1. Identify the exact failing workload
Run the PCC pipeline on one benchmark at a time so you can see which kernel triggers the unsupported validation path.
for bench in $(find PolyBenchC-4.2.1 -name "*.c"); do
echo "Checking $bench"
./run-pcc-check.sh "$bench" || break
done
If your project already has a dedicated runner, use that instead. The goal is to reduce the failure to one reproducible source file.
2. Re-run with debug or verbose logging enabled
Most PCC toolchains expose additional diagnostics through a debug flag, environment variable, or validator verbosity switch. Re-run the failing case and capture the full message.
./run-pcc-check.sh path/to/failing_workload.c --verbose 2>&1 | tee pcc-failure.log
Look for details such as:
- Unsupported opcode
- Unsupported fact kind
- Unsupported expression form
- Failure in a specific function or basic block
This tells you whether the issue is in code generation, proof generation, or proof validation.
3. Disable optimization passes that commonly trigger unsupported proofs
If the failure only appears under optimized builds, try recompiling the workload with lower optimization. This is the fastest way to confirm whether a compiler transform is responsible.
clang -O0 -g -c path/to/failing_workload.c -o workload.o
./run-pcc-check.sh path/to/failing_workload.c
Then compare with:
clang -O2 -g -c path/to/failing_workload.c -o workload.o
./run-pcc-check.sh path/to/failing_workload.c
If -O0 passes and -O2 fails, the root cause is likely an optimization-introduced construct. In that case, try selectively disabling transforms such as vectorization or loop unrolling:
clang -O2 -fno-vectorize -fno-slp-vectorize -fno-unroll-loops -g \
-c path/to/failing_workload.c -o workload.o
./run-pcc-check.sh path/to/failing_workload.c
This often works for PolyBenchC because many kernels are highly vectorizable.
4. Ensure the proof generator and validator come from the same build or commit
A surprisingly common cause is a toolchain version mismatch. Rebuild the full PCC stack from a clean state.
git rev-parse HEAD
git submodule update --init --recursive
make clean
make -j
Then verify that the binary producing the proof and the binary checking it are from the same source revision. If your project uses separate components, rebuild both before retrying.
5. Minimize the failing program
If one PolyBenchC benchmark fails, reduce it to the smallest source that still reproduces the unsupported construct. This is the fastest way to determine whether the checker lacks support for a specific operation.
cp path/to/failing_workload.c /tmp/reduced.c
# Manually remove unrelated functions, arrays, and loops.
# Re-run after each reduction.
./run-pcc-check.sh /tmp/reduced.c
Keep trimming until only the essential loop or expression remains. Once reduced, inspect for patterns like:
- 64-bit index arithmetic
- pointer casts
- nonlinear expressions
- fused multiply-add style transformations
- vector operations
6. Work around unsupported constructs in the workload
If you need a practical fix immediately, adjust the benchmark build to avoid the unsupported pattern. For example, simplify the compilation flags or rewrite one local construct in the failing kernel.
clang -O1 -fno-vectorize -fno-slp-vectorize -g \
-I utilities -DPOLYBENCH_TIME \
path/to/failing_workload.c -o workload
Possible source-level workarounds include:
- Replacing tricky pointer arithmetic with simpler indexed accesses
- Reducing macro indirection that expands into complex expressions
- Avoiding mixed-width arithmetic where possible
- Temporarily disabling problematic kernels from the PCC test suite
7. Patch the validator if unsupported behavior is legitimate and expected
If the workload is valid and the proof is semantically correct, the durable fix is to add support in the validator for the missing case. Use the failing log and reduced test case to implement coverage for the unsupported opcode or fact form.
# Typical workflow
# 1. Add a regression test using the reduced workload
# 2. Extend validator logic for the unsupported construct
# 3. Rebuild and re-run PCC checks
make -j
ctest --output-on-failure
./run-pcc-check.sh /tmp/reduced.c
This is the right fix when PolyBenchC is exposing a real validator gap rather than a bad benchmark configuration.
8. Add the failing kernel as a permanent regression test
Once fixed, keep the workload or its minimized variant in your automated test suite so the unsupported case does not reappear later.
mkdir -p tests/regressions/pcc
cp /tmp/reduced.c tests/regressions/pcc/polybench_unsupported_case.c
ctest --output-on-failure
Common Edge Cases
- Floating-point specific kernels fail, integer kernels pass: the validator may support integer reasoning better than floating-point semantics.
- Only release builds fail: optimized builds can introduce SSA forms, folded expressions, or vector instructions not seen in debug builds.
- Only one architecture fails: backend-specific codegen can emit different instructions on x86_64 versus AArch64.
- Proof generation succeeds but validation fails: this usually points to a checker limitation, not a frontend compilation failure.
- The error message is truncated: rerun with full logs redirected to a file so the unsupported construct name is not lost.
- Multiple kernels fail differently: do not assume one root cause. PolyBenchC can expose several unsupported patterns across separate benchmarks.
FAQ
Why does PCC fail on PolyBenchC but work on simpler programs?
PolyBenchC kernels are rich in nested loops, affine indexing, and optimization-sensitive numerical code. That makes them much more likely to trigger instruction patterns or proof obligations that a partially implemented validator does not yet support.
Is this a benchmark bug or a PCC validator bug?
Usually it is a validator support gap or a toolchain mismatch, not a bug in PolyBenchC itself. The benchmark is often just the first realistic workload that exercises an unsupported path.
What is the fastest workaround if I just need the checks to pass?
Rebuild the failing workload with less aggressive optimization, especially by disabling vectorization and loop unrolling. If that works, you can keep moving while preparing a proper validator fix.
In short, this issue happens because some PolyBenchC workloads generate proofs that exceed the current PCC validation support boundary. The most reliable path is to isolate the exact kernel, compare optimized versus non-optimized builds, align tool versions, reduce the reproducer, and then either work around the construct or extend the validator with a regression test.