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:
lowerCamelCasefor 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 withis/has/should. - Constants and enumerators: Either
UpperCamelCaseorkCamelCasedepending 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.
autois 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-exceptionsand-fno-rtti. Usellvm::isa<>/llvm::cast<>/llvm::dyn_cast<>for downcasts; they hook into LLVM's lightweight RTTI (llvm/include/llvm/Support/Casting.h). overrideon every override.finalon classes/methods that aren't meant to be subclassed; the compiler can devirtualize and the human can read the intent.= defaultand= deletefor special members.std::optional,std::variant,std::string_vieware available; some areas still usellvm::Optional(now an alias) orllvm::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;
}Errorcarries 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 withif (!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:
- Write a
RUN:lit test that demonstrates the bug. It will fail. - Write the fix.
- 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,\seewhere 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— useouts()/errs(). - Don't
throwexceptions — useError. - Don't use
std::regex— usellvm::Regex.std::regexis 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.