Open-Source Wikis

/

LLVM

/

How to contribute

/

Patterns and conventions

llvm/llvm-project

Patterns and conventions

The canonical reference for LLVM's coding style is llvm/docs/CodingStandards.rst. This page covers the patterns a new contributor will encounter day to day. When this page disagrees with the coding standards document, the coding standards document wins.

Naming

  • Types and classes: UpperCamelCase. Examples: BasicBlock, MachineFunction, TargetLowering.
  • Variables: lowerCamelCase for locals, lowerCamelCase (no leading capital) for parameters and members. The codebase has historical exceptions; follow the surrounding code.
  • Functions and methods: lowerCamelCase. Examples: getNumOperands(), isAligned(). Predicate functions start with is/has/should.
  • Constants and enumerators: Either UpperCamelCase or kCamelCase depending on the file's convention.
  • Macros: SCREAMING_SNAKE_CASE, prefixed (LLVM_, GET_, etc.).

C++ style

  • C++17. The host C++ standard is C++17 across the codebase. auto is fine where it removes redundancy or is required by lambda return-type deduction. Use it sparingly when the type is non-obvious.
  • No exceptions, no RTTI in core LLVM libraries. The build configures -fno-exceptions and -fno-rtti. Use llvm::isa<> / llvm::cast<> / llvm::dyn_cast<> for downcasts; they hook into LLVM's lightweight RTTI (llvm/include/llvm/Support/Casting.h).
  • override on every override.
  • final on classes/methods that aren't meant to be subclassed; the compiler can devirtualize and the human can read the intent.
  • = default and = delete for special members.
  • std::optional, std::variant, std::string_view are available; some areas still use llvm::Optional (now an alias) or llvm::StringRef.

LLVM-specific helpers

The llvm::Support and llvm::ADT directories contain replacements for many standard-library types:

LLVM helper Stand-in for
StringRef non-owning string
Twine concatenation builder for diagnostic and log messages
SmallVector<T, N> small-buffer-optimized vector
SmallString<N> small-buffer string
ArrayRef<T> / MutableArrayRef<T> non-owning span
DenseMap / DenseSet open-addressing hash table
StringMap string-keyed map
MapVector insertion-ordered map
BitVector / SmallBitVector dynamic / small-buffer bitset
cl::opt<T> (llvm/include/llvm/Support/CommandLine.h) command-line flag declaration

Prefer the LLVM helpers in code that lives under llvm/. They're tuned for compiler workloads and avoid issues with the standard library on niche platforms.

Errors

LLVM has a typed error system in llvm/include/llvm/Support/Error.h:

Expected<int> parseNumber(StringRef S) {
  int Result;
  if (S.consumeInteger(10, Result))
    return createStringError(inconvertibleErrorCode(),
                             "not a number: %s", S.str().c_str());
  return Result;
}
  • Error carries an error chain, must be consumed (consumeError, handleErrors, cantFail, etc.), and aborts the program if dropped on the floor in debug builds.
  • Expected<T> is the value-or-error result type. Check with if (!E) return E.takeError();.
  • report_fatal_error() is for "the IR is broken in a way the user cannot fix" situations. Don't use it for normal error paths.

Logging and debug output

#define DEBUG_TYPE "instcombine"
#include "llvm/Support/Debug.h"

LLVM_DEBUG(dbgs() << "Folding " << *I << "\n");

LLVM_DEBUG() is a no-op in release builds. The DEBUG_TYPE is selected at runtime with -debug-only=instcombine. Don't pre-declare a global flag; that's what DEBUG_TYPE is for.

For user-facing diagnostic output use errs() and outs() (raw_ostream) — iostream is not used in this codebase.

Pass authoring (new pass manager)

A modern function pass:

struct FoldFooPass : PassInfoMixin<FoldFooPass> {
  PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM) {
    auto &DT = FAM.getResult<DominatorTreeAnalysis>(F);
    bool Changed = doIt(F, DT);
    return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
  }
};

Register it in llvm/lib/Passes/PassRegistry.def. For codegen passes (still on the legacy PM as of this snapshot) the registration goes through INITIALIZE_PASS macros in the corresponding .cpp.

Test-driven development

The project culture treats failing tests as authoritative. The expected workflow:

  1. Write a RUN: lit test that demonstrates the bug. It will fail.
  2. Write the fix.
  3. The test passes. Add it to the PR alongside the fix.

For codegen and IR passes, prefer to use update_test_checks.py (or one of its siblings under llvm/utils/) to generate ; CHECK: lines from the actual output, then commit the result.

Comments

  • File-level comments use the LLVM banner: a //===---=== rule with a brief description on the next line. Most existing files have one — copy from a neighbor.
  • Function-level comments are Doxygen-style (/// for declarations, // for in-body explanation). Mark \param, \returns, \note, \see where they help.
  • "Why this is here" comments outweigh "what this does" comments. Code rarely needs paraphrasing; intent does.

Cross-cutting "don'ts"

  • Don't use std::cout/std::cerr — use outs()/errs().
  • Don't throw exceptions — use Error.
  • Don't use std::regex — use llvm::Regex. std::regex is slow and has implementation quirks.
  • Don't add a Boost dependency. The third-party libraries that ship in third-party/ are a closed set.
  • Don't modify code in third-party/ unless you are deliberately updating the import. The update scripts are checked in alongside the imports (e.g. third-party/update_boost_math.sh).

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Patterns and conventions – LLVM wiki | Factory