Not the OP, but one I think about a lot is converting functional, monadic code that uses first class functions/closures to equivalent imperative variants.
For example, manipulating collections with functions like map, flatMap, filter, etc. has become common, even in popular imperative languages like C# and Java. These calls are can be chained together to create non-strict sequences (IEnumerable, Stream, etc.) which are made strict at a later time. Each call creates a new sequence, and many take closures. Both of these require memory allocation and indirect dispatch.
However, in many cases it extremely straightforward to convert these into loops. For example, the following C# code:
list.Select(f).Where(p).SelectMany(g).ToList()
Could be turned into:
var outList = new List();
foreach(var x in list) {
var y = f(x);
if(!p(y))
continue;
foreach(var z in g(y)) {
outList.Add(z)
}
}
This works, even if we known nothing about f, p, and g (e.g. they can be impure functions). This optimization is especially effective if these functions are lambdas. It is also always going to be faster and safe; the only difference is that we removed a series of extra allocations and indirect function calls. This example is admittedly simple, but many functional patterns and behaviors can be rewritten into longer imperative variants that avoid extra allocations.
You are right that you can have subtle changes in behavior with similar high level optimizations. For example, most functional languages make calls like these actually create a new collection at each call. If any of these functions can throw and exception or cause an effect, then we cannot perform the above rewriting because if will call the functions out of order. But if a compiler can take the time to analyze functions for external purity, these can be optimized as well.