Polly Polyhedral Framework: LLVM's Mathematical Loop Optimizer
Polly is LLVM's polyhedral optimizer that transforms loop nests into mathematical representations to perform advanced optimizations like tiling, fusion, and automatic parallelization on Static Control Parts (SCoPs).
Polly is a high-level optimization framework integrated into the LLVM compiler infrastructure. According to the llvm/llvm-project repository, it analyzes and transforms loop nests using the polyhedral model—a mathematical approach that enables global optimization across entire computational kernels. The framework serves as a bridge between traditional compiler optimizations and advanced loop transformations typically found in high-performance computing.
How Polly Works: The Three-Stage Pipeline
Polly operates through a strictly defined pipeline of LLVM passes that convert imperative loop code into polyhedral representations, optimize them mathematically, then regenerate LLVM IR.
Front-End: Detection and Canonicalization
The first phase prepares LLVM IR and identifies optimizable regions. In polly/lib/Pass/PollyFunctionPass.cpp, the front-end orchestrates three critical passes:
polly-canonicalize– Normalizes IR by expanding affine maps and inserting metadata to ensure subsequent analyses can recognize loop patternspolly-detect– Scans each function for Static Control Parts (SCoPs)—regions that satisfy polyhedral constraints such as affine loop bounds and memory accessespolly-scops– Emits a polyhedral description containing iteration domains and access functions for every detected SCoP, stored in internal data structures
These passes ensure that only well-formed loop nests with affine control flow enter the optimization pipeline.
Middle-End: Dependence Analysis and Scheduling
Once SCoPs are identified, Polly performs sophisticated mathematical optimization using the Integer Set Library (ISL) integrated in polly/lib/External/isl:
polly-dependences– Computes precise data dependences between all memory accesses within a SCoP using ISL's polyhedral algorithmspolly-opt-isl– Invokes ISL's optimizer to explore legal transformations (tiling, loop interchange, skewing) and selects optimal schedules according to cost models for latency, bandwidth, or parallelism
This stage provides research utilities including polly-export-jscop and polly-import-jscop, which serialize SCoPs to JSON format (.jscop files) for offline analysis and reproducible experiments. Visualization tools like dot-scops and view-scops generate Graphviz representations of the polyhedral structure.
Back-End: Code Generation
The final phase converts mathematical schedules back to executable code:
polly-ast– Generates an Abstract Syntax Tree (AST) from ISL's optimized schedule, representing the transformed loop structurepolly-codegen– Lowers the AST back to LLVM IR, producing the optimized loop nest with transformations applied
The entire pipeline is registered as an LLVM plugin in polly/lib/Plugin/Polly.cpp, which injects these passes into the LLVM pass manager when users enable the -polly flag. The PhaseManager (polly/include/polly/Pass/PhaseManager.h) coordinates execution based on command-line options.
Key Source Files in llvm-project
Understanding Polly's architecture requires familiarity with these critical files:
| File Path | Role |
|---|---|
polly/README |
High-level overview of Polly's purpose and polyhedral model capabilities |
polly/lib/Plugin/Polly.cpp |
Plugin registration and command-line flag definitions (-polly, -polly-*) |
polly/include/polly/Pass/PollyFunctionPass.h |
Declaration of the function-level pass driver |
polly/lib/Pass/PollyFunctionPass.cpp |
Implementation orchestrating front-, middle-, and back-end phases for single functions |
polly/lib/Pass/PollyModulePass.cpp |
Module-level driver for inter-procedural analyses crossing function boundaries |
polly/www/documentation/passes.html |
Human-readable catalog of all Polly LLVM passes |
polly/lib/External/isl |
Integration of the ISL library providing the mathematical optimization engine |
Practical Usage Examples
Enabling Polly in Clang
The most common entry point activates Polly through Clang's driver:
/* matmul.c */
int A[1024][1024], B[1024][1024], C[1024][1024];
void matmul(void) {
for (int i = 0; i < 1024; ++i)
for (int j = 0; j < 1024; ++j)
for (int k = 0; k < 1024; ++k)
C[i][j] += A[i][k] * B[k][j];
}
Compile with optimization flags:
clang -O3 -march=native -mllvm -polly -mllvm -polly-vectorizer-choose=latency matmul.c
The -mllvm -polly flag activates the plugin, automatically tiling and vectorizing the inner loops to reduce cache misses and expose SIMD parallelism.
Running Individual Passes with opt
For research or custom pipelines, load the plugin directly in opt:
opt -load=./lib/Polly.so \
-polly-canonicalize -polly-detect -polly-scops \
-polly-dependences -polly-opt-isl \
-polly-ast -polly-codegen \
-S < input.ll > optimized.ll
Each -polly-* flag corresponds to a specific pass, allowing fine-grained control over the optimization process.
Exporting SCoPs for Offline Analysis
Researchers can export the polyhedral representation to JSON:
opt -load=./lib/Polly.so -polly-export-jscop -S -o /dev/null input.ll
This generates .jscop files alongside the original IR, which can be inspected manually or re-imported via -polly-import-jscop for reproducible experiments.
Summary
- Polly is a LLVM plugin that applies the polyhedral model to optimize Static Control Parts (SCoPs)—loop nests with affine control flow and memory accesses.
- The framework provides a global view of entire loop nests, enabling cross-loop optimizations like tiling and fusion that traditional LLVM passes cannot perform.
- Optimization relies on the ISL (Integer Set Library) to solve integer-linear programming problems and find schedules minimizing latency or maximizing parallelism.
- The pipeline consists of distinct front-end (detection), middle-end (mathematical optimization), and back-end (code generation) phases implemented in
PollyFunctionPass.cppand related files. - Users activate Polly via Clang's
-pollyflag or manually orchestrate individual passes throughoptfor research purposes.
Frequently Asked Questions
What exactly constitutes a SCoP in Polly?
A Static Control Part (SCoP) is a program region contained within polly/lib/Pass/PollyFunctionPass.cpp's detection logic that has strictly affine loop bounds, affine array subscripts, and no data-dependent control flow. This regularity allows Polly to represent the region as a polyhedron and apply mathematical transformations that preserve program semantics.
How does Polly differ from standard LLVM loop optimizations?
Standard LLVM loop passes operate locally on individual loops using heuristics, whereas Polly, as implemented in polly/lib/External/isl, considers the entire loop nest simultaneously through integer-linear programming. This global analysis enables transformations requiring cross-loop reasoning—such as full-program tiling and software pipelining—that traditional -O3 optimizations cannot legally perform.
Is Polly included in standard LLVM builds?
Polly is included in the llvm/llvm-project repository but may require explicit enabling during the build process. When building LLVM, set LLVM_ENABLE_POLLY=ON to compile the shared library (Polly.so) and headers. Once built, the plugin automatically registers passes with opt and Clang when loaded.
Can Polly optimize loops with non-affine array accesses?
No—Polly's polyhedral model requires affine relationships between loop iterators and memory addresses. The polly-detect pass strictly filters out non-affine regions, leaving them for LLVM's traditional loop optimization passes. This limitation ensures mathematical correctness but means Polly skips code with pointer chasing, indirect indexing, or data-dependent bounds.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →