Performance Tips for Frontend Authors#

Abstract#

The intended audience of this document is developers of language frontends targeting LLVM IR. This document is home to a collection of tips on how to generate IR that optimizes well.

IR Best Practices#

As with any optimizer, LLVM has its strengths and weaknesses. In some cases, surprisingly small changes in the source IR can have a large effect on the generated code.

Beyond the specific items on the list below, it’s worth noting that the most mature frontend for LLVM is Clang. As a result, the further your IR gets from what Clang might emit, the less likely it is to be effectively optimized. It can often be useful to write a quick C program with the semantics you’re trying to model and see what decisions Clang’s IRGen makes about what IR to emit. Studying Clang’s CodeGen directory can also be a good source of ideas. Note that Clang and LLVM are explicitly version locked so you’ll need to make sure you’re using a Clang built from the same git revision or release as the LLVM library you’re using. As always, it’s strongly recommended that you track tip of tree development, particularly during bring up of a new project.

The Basics#

  1. Make sure that your Modules contain both a data layout specification and target triple. Without these pieces, non of the target-specific optimization will be enabled. This can have a major effect on the generated code quality.

  2. For each function or global emitted, use the most private linkage type possible (private, internal or linkonce_odr preferably). Doing so will make LLVM’s inter-procedural optimizations much more effective.

  3. Avoid high in-degree basic blocks (e.g. basic blocks with dozens or hundreds of predecessors). Among other issues, the register allocator is known to perform badly with confronted with such structures. The only exception to this guidance is that a unified return block with high in-degree is fine.

Use of allocas#

An alloca instruction can be used to represent a function scoped stack slot, but can also represent dynamic frame expansion. When representing function scoped variables or locations, placing alloca instructions at the beginning of the entry block should be preferred. In particular, place them before any call instructions. Call instructions might get inlined and replaced with multiple basic blocks. The end result is that a following alloca instruction would no longer be in the entry basic block afterward.

The SROA (Scalar Replacement Of Aggregates) and Mem2Reg passes only attempt to eliminate alloca instructions that are in the entry basic block. Given SSA is the canonical form expected by much of the optimizer; if allocas can not be eliminated by Mem2Reg or SROA, the optimizer is likely to be less effective than it could be.

Avoid creating values of aggregate type#

Avoid creating values of