Can anyone point me to a good definition of the term \"lowering\" in the context of compilers?
From what I can tell, it is the translation of a higher-level operation in
The Dragon Book doesn't use the term. Kennedy+Allen's Optimizing Compilers for Modern Architectures A Dependence-based Approach doesn't use the term. Steve Muchnick's Advanced Compiler Design and Implementation doesn't use the term.
Engineering A Compiler uses the term but doesn't define it. Bob Morgan's Building an Optimizing Compiler (1998) uses the term a lot and defines it.
Lowering : The instructions are lowered so that each operation in the flow graph represents a single instruction in the target machine.
It is a more general term and there is no single definition. My own understand is that a compiler lowers an operation from a higher abstraction layer to a lower, for example, in LLVM lowering from MachineInstr to MCInst.
I can't find a good link with a definition, but I think I can give a good example. In LLVM, the LLVM IR supports several sizes of integers. Most C/C++ compilers, including clang, support long long and a 64 bit data type. Many 32 bit processors, like the mips (32 bit), don't have instructions that can do, for example, a 64 bit add or compare. LLVM will "lower" these 64 bit operations to operations, usually 32 bit, that the processor can do.
In the case of a int64_t compare for example, LLVM will lower it to
compare the upper 32 bits with a signed comparison
if they are equal, compare the lower 32 bits with an unsigned comparison
Some lowering can get pretty fancy. For example on a processor that does not support a multiply instruction, simple multiplies might turn into shifts and adds while more complicated ones might turn into a call to a run-time supprt library.
Dr. Dobbs just published an article by Walter Bright (of dlang fame), where he mentions the term:
Lowering
One semantic technique that is obvious in hindsight (but took Andrei Alexandrescu to point out to me) is called "lowering." It consists of, internally, rewriting more complex semantic constructs in terms of simpler ones. For example,
while
loops andforeach
loops can be rewritten in terms offor
loops. Then, the rest of the code only has to deal withfor
loops. This turned out to uncover a couple of latent bugs in how while loops were implemented in D, and so was a nice win. It's also used to rewritescope guard
statements in terms oftry-finally
statements, etc. Every case where this can be found in the semantic processing will be win for the implementation.If it turns out that there are some special-case rules in the language that prevent this "lowering" rewriting, it might be a good idea to go back and revisit the language design.
Any time you can find commonality in the handling of semantic constructs, it's an opportunity to reduce implementation effort and bugs.