-Wstrict-aliasing=3 non-diagnosed union type punning under -O2
0 reputation · 24 Oct 2021, 14:34 UTC
0 reputation · 24 Oct 2021, 14:34 UTC
When profiling C performance bottlenecks involving type-punned pointers, compiler strict-aliasing assumptions under -O2/-O3 can silently restructure loads and stores, potentially obscuring whether measured cycles-instructions reflect genuine hotspots or aliasing-driven optimizations. GCC and Clang assume pointers of incompatible types do not alias per C99 6.5/7, enabling transformations such as redundant load elimination that alter instruction counts and cache behavior. The -Wstrict-aliasing warning levels (1–3) provide partial diagnostics, but level 3 frequently misses union-based punning patterns that C99 6.5.2.3/3 explicitly permits, creating a diagnostic gap between compiler assumptions and source intent. UBSan strict-aliasing instrumentation reports violations at runtime with approximately 2–3× overhead and does not cover code compiled without sanitization, such as system allocators. The -fno-strict-aliasing flag disables these assumptions globally, costing 5–15% performance in pointer-heavy code (e.g., network packet parsing) but lacks a standard per-function or per-pointer disable mechanism. Which profiling approach reliably isolates true hotspots without perturbing aliasing behavior or incurring prohibitive overhead? How does -fno-strict-aliasing interact with link-time optimization across GCC 13 and Clang 17? Does restrict qualify on destination pointers recover auto-vectorization while preserving intended aliasing assumptions?
35275 reputation · 25 Oct 2021, 00:50 UTC
Profiling without perturbing aliasing: Use hardware PMU sampling, not sanitizers. On Linux: perf stat -e cycles,instructions,cache-references,cache-misses and perf record -g -F 99 with a build that has -g -fno-omit-frame-pointer and no UBSan. VTune or AMD uProf give the same class of measurement. Overhead is ~1-3% versus ~2-3× for UBSan strict-aliasing instrumentation. Sampling measures retired instructions/cycles after compiler aliasing decisions have been applied, so it isolates the true runtime cost of the optimized binary without changing aliasing behavior.
-fno-strict-aliasing with LTO: GCC 13 and Clang 17 apply strict-aliasing per translation unit. With -flto the flag must be consistent across the LTO unit. If all TUs are built with -fno-strict-aliasing, the whole program is built without strict aliasing assumptions. Mixing TUs with different settings yields per-TU behavior and can inline strict-aliasing code into non-strict code, which is unsafe. There is no standard per-pointer disable. Per-function workarounds exist as non-portable attributes: __attribute__((optimize("no-strict-aliasing"))) works in GCC/Clang but is not portable. Clang ThinLTO may propagate the flag more aggressively via summaries.
restrict on destination pointers: Yes, it can recover auto-vectorization while preserving intended aliasing. restrict is a contract that the qualified pointer does not alias any other pointer in scope. It enables vectorization of loops with a restrict-qualified destination, e.g., memcpy-like loops, under -fstrict-aliasing at -O2. It does not relax strict-aliasing rules for incompatible-type pointers elsewhere and does not make union punning safe. Violating the restrict contract is undefined behavior.
perf annotate or VTune source view is required to map samples to code.-O2 -g -fno-omit-frame-pointer with consistent strict-aliasing flags across all TUs. Keep LTO flags identical.perf stat -r 5 ./workload and perf record -g -F 99 ./workload. Inspect hot functions with perf annotate.-fno-strict-aliasing and repeat perf stat. Difference in instructions/cycles shows the optimization headroom attributable to aliasing assumptions.restrict to destination pointers in loops and rebuild with -O2 -fopt-info-vec GCC or -Rpass=loop-vectorize Clang to confirm vectorization recovery.One missing diagnostic detail that changes the recommendation: Are you profiling C or C++? Union type punning is well-defined in C per C99 6.5.2.3/3, but in C++ accessing an inactive union member is undefined behavior. If this is C++, the safe remediation is memcpy or std::bit_cast rather than relying on union punning, which affects both profiling interpretation and restrict usage.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.