Elektrine lite

← Feed

@david_chisnall@infosec.exchange

Post #2639736

2025-05-16 07:41 UTC

@loke@functional.cafe @ela@infosec.exchange I would expect that this is the combination of a few things: First, the compiler will turn a tail-recursive function into a loop. This is a fairly trivial transform (Python explicitly prohibits it because it loses backtrace information)l it’s just replacing the tail call with a branch to the entry point. After that, you have a simple loop. There will be a bit of canonicalisation to make it easier to analyse. My guess is that this would then be handled by scalar evolution, which tries to model outputs from the loop as polynomials computed from the induction variable. Note that the loop has no side effects. This means each value in each iteration can be calculated from the previous one, which means that there must be a function that goes from the induction variable to the input to the output, so you’re just solving for that. This particular case might be simpler because the value at the end depends on a single bit in the input, so it might be that known-bits analysis gives you the answer. If you pass -mllvm -print-after-all to Clang, it will print the LLVM IR after each pass has run, so you can see all of the intermediate steps.

Replies (2)

  • @ela@infosec.exchange 2025-05-16 08:03

    @david_chisnall@infosec.exchange @loke@functional.cafe Reading https://llvm.org/devmtg/2018-04/slides/Absar-ScalarEvolution.pdf I would say that's a pretty good guess.

    Open ##2639737

  • @hyphen@duwa.ng 2025-05-16 08:38

    @david_chisnall@infosec.exchange First, the compiler will turn a tail-recursive function into a loop. so is the implication here that the compiler would also recognize this non-tailrec example above and transform it to tailrec first?

    Open ##2639738