简体   繁体   中英

Can all code optimization by Lisp compile-time evaluation be achieved by an ideal compiler in other languages (such as C++)?

In Lisp you can optimize code by evaluating conditionals during compile time in a Macro. As in, you have a macro (compute-for-N 1) evaluate to code-1 and (compute-for-N 2) evaluate to code-2 .

If you write something similar in C++, a very naïve compiler would evaluate the conditional during execution, slowing the program down.

My question is, can all of possible Lisp evaluation time optimizations also be done by an ideal compiler? As a follow up, if an ideal compiler can in fact achieve similar or better results than any manually written compile time optimization, would it be bad code practice to attempt to write manual code optimizations?

PS: There are obviously many more advantages to using a language such as Lisp, so this question is not contesting Lisp's potential utility.

Yes, C++ compilers are allowed to generate efficient code, and an ideal C++ compiler would be capable of making the code as efficient as possible.

An ideal compiler would make use of every optimization technique you can think of. Unlike a real compiler, an ideal one is not subject to those pesky limitations of time and space (and human ingenuity), so it would implement even the most outlandish optimization ideas. Optimizations that are currently possible in another language (such as Lisp) are not outlandish and certainly fall within the capabilities of an ideal C++ compiler.

I would think that the above applies to all compiled languages, not just C++. However, the C++ standard does make this explicit with the as-if rule , which establishes that the standard mandates only the observable behavior; compilers are allowed to achieve this behavior however they see fit. In fact, as far as the standard is concerned, a compiler could generate a magic crystal ball and be compliant, as long as the crystal ball causes the correct observable behavior.

Truly, the C++ standard does not prohibit speed.

Compilers are generally (and should generally, and it looks as if the C++ specification explicitly allows this) be allowed to do whatever they like to improve the performance of the program while not changing how it observably behaves, and (I would say) also not causing undue compile-time-side-effects: you don't want the process of compiling your program to launch nuclear missiles, even if the program itself is intended to do that. Perhaps you also want to add the constraint that the compiler should terminate: this has not not always been true for real compilers.

The only difference between Lisp-family languages and most other languages is that it is, perhaps, easier for user code to do this kind of thing in Lisp, or has historically been so.

As an example, in Common Lisp, consider this:

(defun sum-to-n (n)
  (declare (type (integer 0) n))
  (if (zerop n)
      0
    (+ n (sum-to-n (1- n)))))

Well, that's a terrible function, but:

(define-compiler-macro sum-to-n (n)
  (typecase n
    ((integer 0)
     (/ (* n (1+ n)) 2))
    (number
     (error "you are a sponge"))
    (t
     `(let ((m ,n))
        (declare (type (integer 0) m))
        (/ (* m (1+ m)) 2)))))

And now, (sum-to-n 101010101) is a compile-time constant ( 5101520302520151 in fact) (sum-to-n (fq)) is turned into

(let ((m (f q)))
  (declare (type (integer 0) m))
  (/ (* m (1+ m)) 2))

and (sum-to-n 12.0) is a compile-time error.

So that's nice, and quite easy to do, and it and things like it are largely easy to do because it is easy, in Lisp, for programs to reason about their own source code.

But there is absolutely nothing which prevents a C++, or any other, compiler from doing whatever optimisations it thinks are possible, even extremely heroic ones. And indeed there is absolutely nothing except, perhaps, user effort, to prevent anyone writing programs which take C++ programs as arguments and emit optimised versions of the same code.

You have constexpr and things of this sort as people pointed out, and most C++ optimizers are very aggressive with constant folding and do near-magic stuff there.

There is one conceptual advantage in constant folding though if you treat a LISP compiler or even C++ compiler as a JIT. I'm not sure if that's what you were after but it's an interest of mine as one dabbling in compiler design.

Even the most aggressive optimizer can't anticipate what users will do at runtime. So say a user types a value for N as 128 at runtime and then we do some intensive task using N as an input (say path tracing which might involve billions of iterations). If we compile new code on the fly with 128 for N and the overhead of compilation is dwarfed by the time spent processing code involving N , then constant-folding applies for N provided we assigned its value before we compile the code in ways it can't otherwise in any language/compiler if N wasn't assigned a value at compile-time. It would be a variable otherwise if we compiled the code before runtime.

So that seems like a huge potential source of optimization to me of code compiled on the fly in response to user inputs. I don't know how much that answers your question but there's always the gap where even the most aggressive optimizer can't know what users will do at runtime. That said, C++ optimizers do an amazing job with information that can be known at compile/link-time.

One of the things I've always found with C++ optimizers as well as optimizers is that they seem completely stupid in some cases and brilliant in others. For example, I found a profiler hotspot in our code involving division and modulo against a variable which was guaranteed, through our runtime code (but not at compile-time since it was based on user inputs), to be a power of two size. But it wasn't determined at compile-time, so the optimizer actually used expensive instructions for division and modulo. So I found I could optimize with around a 30% boost in performance by just precomputing log2(N) and N-1 and using manual bitshift and bitwise-and operations for divison and modulo.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM