compiler-optimizations-deep
Dive into compiler internals: understand why loops fail to vectorize, how register pressure causes spills, and when to deploy PGO or BOLT. Covers mid-level IR optimizations, instruction selection, and post-link optimization strategies with practical triage workflows.
Compiler Optimizations (Deep) explains vectorization failures and teaches register allocation, instruction selection, and profile-guided optimization beyond standard compiler flags.
AI-generated summary based on this skill's SKILL.md
Install
mohitmishra786/low-level-dev-skills/compiler-optimizations-deep · repository language: JavaScript
git clone https://github.com/mohitmishra786/low-level-dev-skills
cp -r low-level-dev-skills/skills/compiler-internals/compiler-optimizations-deep ~/.claude/skills/compiler-optimizations-deepnpx skillfed install mohitmishra786/low-level-dev-skills/compiler-optimizations-deepFrequently asked questions
AI-generated answers based on this skill's SKILL.md and metadata
Why didn't my loop vectorize with -O3?
compiler-optimizations-deep covers vectorization failures across multiple dimensions. Common blockers include data dependencies (loop-carried or memory aliasing), unknown trip counts, non-unit strides, and unsupported operations. Enable diagnostics with `-Rpass=loop-vectorize -Rpass-missed=loop-vectorize` to see rejection reasons. Check for pointer aliasing with `restrict` qualifiers, ensure loop bounds are compile-time constants or predictable, and verify that inner operations map to SIMD instructions. Compiler optimization passes order matters—vectorization runs after loop normalization and LICM, so invariant hoisting may unlock vectorization.
How does register allocation work in LLVM?
compiler-optimizations-deep explains that LLVM's greedy register allocator assigns virtual registers to physical registers by processing live ranges in priority order. Live ranges define the instruction span where a value must reside; overlapping ranges compete for registers. When demand exceeds supply, the allocator spills—writing values to stack memory. Register pressure (count of simultaneously live values) determines spill frequency. The allocator considers rematerialization (recomputing cheap values) versus spilling. Understanding live range pressure helps you restructure code to reduce simultaneous live values, cutting spills and improving cache locality.
What causes register pressure spills?
compiler-optimizations-deep identifies register spilling as the result of too many live values competing for too few physical registers. Spills occur when live ranges overlap and the allocator cannot fit all values in available registers. Common causes: long basic blocks with many intermediate results, complex expressions with deep dependency chains, and aggressive inlining that merges register demands. Spills force loads/stores to stack, destroying performance. Mitigation: break long blocks into smaller functions, reduce expression depth via intermediate variables, and use compiler flags like `-fno-inline` to control inlining pressure during optimization.
How do I set up PGO or BOLT for production optimization?
compiler-optimizations-deep covers both workflows. PGO (Profile-Guided Optimization) requires three steps: compile with `-fprofile-generate`, run representative training workloads to collect `.profraw` files, merge with `llvm-profdata merge`, then recompile with `-fprofile-use`. BOLT (post-link optimization) instruments the final binary, runs training, then reorders code blocks for cache locality. PGO works at compile time; BOLT operates on linked binaries without recompilation. Choose PGO for development; BOLT for production binaries where recompilation is costly. Both require representative training data—use production traffic samples or synthetic workloads matching real usage patterns.
How does LICM loop invariant code motion improve performance?
compiler-optimizations-deep explains that LICM hoists computations outside loops when operands don't change across iterations. This eliminates redundant work: a loop-invariant multiplication executed N times moves outside, running once. LICM runs early in the optimization pipeline, enabling downstream passes like vectorization by simplifying loop bodies. It reduces register pressure inside loops and improves instruction-level parallelism. Limitations: LICM cannot hoist operations with side effects or memory dependencies it cannot prove safe. Use `-Rpass=licm` to see what moved; if expected hoisting doesn't occur, check for aliasing or side-effect annotations blocking the pass.
Why is my -O3 code slower than -O2?
compiler-optimizations-deep identifies unexpected -O3 regressions as stemming from aggressive pass interactions: over-inlining exhausts register pressure, aggressive loop unrolling bloats instruction cache, or vectorization introduces expensive type conversions. Debug by profiling with perf or VTune to pinpoint hot regions, then selectively disable passes using `-fno-unroll-loops`, `-fno-inline`, or `-fno-vectorize`. Compiler optimization pass ordering matters—a pass optimizing for one metric may degrade another. Profile-guided optimization (-fprofile-use) often recovers -O3 performance by making inlining and unrolling decisions based on actual execution frequency rather than heuristics.
SKILL.md
rendered from the published skill — quoted content, verbatim
Compiler Optimizations (Deep)
Purpose
Explain optimization phases beyond flags: mid-level IR opts, register allocation, instruction selection/scheduling, vectorization boundaries, PGO, and post-link BOLT — bridging skills/compilers/pgo and LLVM/GCC internals.
When to Use
-O3did not vectorize a hot loop- Teaching why register pressure causes spills
- Planning PGO or BOLT deployment
- Understanding pass interaction (e.g., LICM before vectorize)
Workflow
1. Compiler pipeline map
Frontend → LLVM IR / GCC GIMPLE
├── Mid-level: DCE, GVN, LICM, inlining
├── Loop opts: unroll, vectorize
├── Codegen prep: legalize types
├── Instruction selection (DAG → machine ops)
├── Register allocation (greedy, linear scan)
└── Peephole / scheduling
2. Vectorization failure triage
```bash clang -O3
(truncated - see the full file via the links below)
Read as markdown · JSON record · Browse the source repository
File tree — 1 file
skills/compiler-internals/compiler-optimizations-deep/SKILL.md