Summary
elasticity_p1 (plain isotropic linear elasticity, P1 tet, no automatic differentiation) still runs ~1.20x slower than a reference compiler's equivalent generated kernel after landing the codegen-backend fixes in #862 and #863. Disassembly with line-level attribution (gcc -g + objdump -dl) shows this gap is not in the tensor-accumulation loop -- that's now smaller than the reference kernel's (128 vs 157 tagged instructions) and both compilers fail to vectorise it identically (-fopt-info-vec: "complicated access pattern" on both sides, an inherent property of scattering several 3-term sums into runtime-computed matrix offsets, not an FFCx-specific weakness).
The gap is upstream, in the Jacobian/metric-tensor setup phase that runs before the accumulation loop: FFCx's generated code declares 388 distinct scalar temporaries there; the reference compiler's needs only 193 -- almost exactly double, for the identical mathematical problem. Checked for the obvious explanation (duplicate/redundant expressions, the same class of bug fixed in licm() for #863) and found none: all 388 are structurally distinct expressions, not redundant computation of the same value.
Why this matters beyond elasticity_p1
This is the same class of gap already noted for HyperElasticity (a form built via ufl.derivative, i.e. automatic differentiation) elsewhere in this survey, where FFCx's factorization graph was found to be ~5.6x larger than the reference compiler's for the identical kernel. That was plausibly attributed to AD introducing extra structure. Seeing an equivalent gap on elasticity_p1 -- a plain, hand-written bilinear form with no AD anywhere in it -- suggests the underlying cause is broader: FFCx's IR-level factorization (ffcx/ir/analysis) likely isn't recognising algebraic structure in bilinear forms that couple multiple tensor/vector components through more than one material parameter (here, the Lame parameters lambda and mu), where the reference compiler's factorization does.
Why this needs its own investigation
Every fix landed this session (#861, #862, #863) was a codegen-backend rewrite: same IR in, fewer or cheaper instructions out, each bounded and independently verifiable by disassembly/instruction-count/benchmark. This is different in kind -- it's a question of whether the factorization stage that builds the expression graph before codegen ever runs could represent the same computation with far fewer distinct scalars, by recognising decomposable structure (e.g. that the elasticity tensor's action can be written as a sum of just a handful of lambda/mu-weighted pieces rather than requiring a bespoke scalar per matrix entry). That's a change to how ffcx/ir/analysis builds and CSEs its graph, not a local, mechanical rewrite -- materially larger in scope and risk than anything in #861-#863.
Suggested next step
Scope a follow-up investigation into ffcx/ir/analysis's factorization/CSE logic, starting from a side-by-side comparison of the expression graph FFCx builds for elasticity_p1 against what a reference compiler builds for the same form, to identify concretely which algebraic structure is or isn't being exploited.
Full writeup, benchmark numbers, and the codegen-backend fixes referenced above: see the linked report.
Summary
elasticity_p1(plain isotropic linear elasticity, P1 tet, no automatic differentiation) still runs ~1.20x slower than a reference compiler's equivalent generated kernel after landing the codegen-backend fixes in #862 and #863. Disassembly with line-level attribution (gcc -g+objdump -dl) shows this gap is not in the tensor-accumulation loop -- that's now smaller than the reference kernel's (128 vs 157 tagged instructions) and both compilers fail to vectorise it identically (-fopt-info-vec: "complicated access pattern" on both sides, an inherent property of scattering several 3-term sums into runtime-computed matrix offsets, not an FFCx-specific weakness).The gap is upstream, in the Jacobian/metric-tensor setup phase that runs before the accumulation loop: FFCx's generated code declares 388 distinct scalar temporaries there; the reference compiler's needs only 193 -- almost exactly double, for the identical mathematical problem. Checked for the obvious explanation (duplicate/redundant expressions, the same class of bug fixed in
licm()for #863) and found none: all 388 are structurally distinct expressions, not redundant computation of the same value.Why this matters beyond
elasticity_p1This is the same class of gap already noted for
HyperElasticity(a form built viaufl.derivative, i.e. automatic differentiation) elsewhere in this survey, where FFCx's factorization graph was found to be ~5.6x larger than the reference compiler's for the identical kernel. That was plausibly attributed to AD introducing extra structure. Seeing an equivalent gap onelasticity_p1-- a plain, hand-written bilinear form with no AD anywhere in it -- suggests the underlying cause is broader: FFCx's IR-level factorization (ffcx/ir/analysis) likely isn't recognising algebraic structure in bilinear forms that couple multiple tensor/vector components through more than one material parameter (here, the Lame parameters lambda and mu), where the reference compiler's factorization does.Why this needs its own investigation
Every fix landed this session (#861, #862, #863) was a codegen-backend rewrite: same IR in, fewer or cheaper instructions out, each bounded and independently verifiable by disassembly/instruction-count/benchmark. This is different in kind -- it's a question of whether the factorization stage that builds the expression graph before codegen ever runs could represent the same computation with far fewer distinct scalars, by recognising decomposable structure (e.g. that the elasticity tensor's action can be written as a sum of just a handful of lambda/mu-weighted pieces rather than requiring a bespoke scalar per matrix entry). That's a change to how
ffcx/ir/analysisbuilds and CSEs its graph, not a local, mechanical rewrite -- materially larger in scope and risk than anything in #861-#863.Suggested next step
Scope a follow-up investigation into
ffcx/ir/analysis's factorization/CSE logic, starting from a side-by-side comparison of the expression graph FFCx builds forelasticity_p1against what a reference compiler builds for the same form, to identify concretely which algebraic structure is or isn't being exploited.Full writeup, benchmark numbers, and the codegen-backend fixes referenced above: see the linked report.