As an example, MontConfig::into_bigint generates some 6000 lines of rust code, which expand into 40000 lines of LLVM IR. This is due to the loop unrolling macro which unrolls a nested loop. this single function can take up to 500ms to codegen and optimize alone, multiplied by each MontConfig implementation. This applies to all functions using the unroll macro as far as I can tell, which all use nested loops.
The problem is exacerbated by inner calls being marked #[inline(always)], which happens regardless of caller or callee size.
I would suggest not doing that, or figuring out a better way to get good codegen than unrolling source code 144 times. For example, extracting the body of the loop into a non-inline-always function which still gets inlined by llvm but not by rust frontend (avoiding evaluating and generating gigantic functions), or unrolling only one of the inner/outer loops instead of both.
Here's an example cargo llvm-lines output:
Lines Copies Function name
----- ------ -------------
141625 1401 (TOTAL)
34765 (24.5%, 24.5%) 1 (0.1%, 0.1%) <ark_bn254[1508b4c01d874b3e]::fields::fq::FqConfig as ark_ff[412259b66fc872b]::fields::models::fp::montgomery_backend::MontConfig<4usize>>::into_bigint
34765 (24.5%, 49.1%) 1 (0.1%, 0.1%) <ark_bn254[1508b4c01d874b3e]::fields::fr::FrConfig as ark_ff[412259b66fc872b]::fields::models::fp::montgomery_backend::MontConfig<4usize>>::into_bigint
As an example, MontConfig::into_bigint generates some 6000 lines of rust code, which expand into 40000 lines of LLVM IR. This is due to the loop unrolling macro which unrolls a nested loop. this single function can take up to 500ms to codegen and optimize alone, multiplied by each MontConfig implementation. This applies to all functions using the unroll macro as far as I can tell, which all use nested loops.
The problem is exacerbated by inner calls being marked
#[inline(always)], which happens regardless of caller or callee size.I would suggest not doing that, or figuring out a better way to get good codegen than unrolling source code 144 times. For example, extracting the body of the loop into a non-inline-always function which still gets inlined by llvm but not by rust frontend (avoiding evaluating and generating gigantic functions), or unrolling only one of the inner/outer loops instead of both.
Here's an example cargo llvm-lines output: