Skip to content

Investigate guarded non-aliasing specialization #2179

Open

Description

@c0d1f1ed

Description

Determine whether a CPU kernel variant selected by runtime non-aliasing checks can improve vectorization and throughput beyond LLVM's existing alias analysis and runtime checks. Prototype a narrowly scoped variant and retain it only if measurements justify the guard overhead, compilation cost, and code size.

Context

This follows up on the pointer-aliasing portion of GH-1358. GH-1954 added guarded specialization for eligible one-dimensional, contiguous CPU launches with block_dim=1. That path exposes constant strides and simpler thread indexing, but makes no non-aliasing promise. LLVM can already vectorize some such loops by generating its own runtime alias checks, so the absence of restrict does not establish a performance problem.

Warp supports in-place operations and overlapping array views. TestCpuVectorization.test_contiguous_specialization_preserves_aliasing explicitly checks both, including a loop where writes affect subsequent reads. Unconditional restrict annotations would invalidate that behavior. A safe optimization must prove its assumptions at runtime and retain the existing path when it cannot.

Investigation

  • Identify representative arithmetic kernels whose optimization records or assembly show that alias uncertainty prevents useful vectorization or adds significant checks. Compare against the current compiler output before introducing another specialization.
  • Start with eligible serial CPU kernels and direct contiguous array arguments. Check actual accessed memory ranges, including view offsets and element sizes, rather than allocation identity or pointer inequality. Disjoint slices of one allocation can be independent; distinct pointers can still overlap.
  • Select the variant only when all accesses covered by the non-aliasing promise are accounted for. Use a conservative fallback for overlapping ranges or accesses through structs, indirect views, or other handles that the prototype cannot analyze. If backward execution is included, account for primal and gradient pointers as well.
  • Confirm that the promise reaches LLVM through the generated array-access code. A local restrict declaration that does not convey the required information to the optimizer is insufficient.
  • Treat alignment separately. Contiguous views and external arrays may have offset addresses, so non-overlap does not justify assuming the allocator's alignment.

Validation and decision

  • Extend warp/tests/test_cpu_vectorization.py for the selected path, reusing its existing correctness tests for in-place, overlapping, and strided access. Include disjoint offset views and empty arrays; retain forward and gradient behavior for every path affected by the prototype.
  • Extend asv/benchmarks/cpu_vectorization.py to compare the guarded variant with the current implementation. Measure small and large launches, both guard outcomes, compilation time, and object size on available x86-64 and AArch64 hosts. Check fallback performance as well as the optimized path, since an extra variant can change inlining and code layout.
  • Record which loops gain SIMD instructions or avoid redundant checks, and whether those changes improve representative workloads. Keep timing assertions out of unit tests.

The outcome may be an implementation proposal or a documented decision that LLVM's existing checks are sufficient. Ship another specialization only if it preserves supported aliasing behavior and provides a repeatable benefit that outweighs its costs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

feature requestRequest for something to be added

Type

Projects

No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions