This post describes how to add a custom attribute to LLVM and Clang. Why would you want to do such a thing?
- You have semantic information of which the front-end is aware, but the back-end discards in the Intermediate Representation (IR), and an existing attribute can't be used to retain this information. Adding the attribute using the front-end analysis preserves the information into the back-end generated IR.
- You've considered using the GCC/LLVM
annotate
attribute to hold arbitrary strings, but you also need to add a parameter (or more!) to that annotation.
The Clang Internals Manual discusses how to do this, but not with the detail you might like to see. Its description is high-level, and only lists one file that needs to be modified. Tracking down all of the other files that must be changed is left as a frustrating exercise to the reader.
We will be creating a new function attribute appropriately named newattribute
. These steps may be different if you want to make an attribute type other than a Function attribute. This is beyond the scope of this post.
In this post, we'll use the following variables as shorthand for some of the paths specified in Getting Started with the LLVM System.
Variable | Description |
---|---|
$(LLVM_SRC) |
The directory containing the LLVM sources. It will be llvm-project/llvm under both the monorepo and nested repo. |
$(CLANG_SRC) |
The directory containing the Clang sources. It will be llvm-project/clang under the monorepo, and llvm-project/llvm/tools/clang under the nested repo. |
- Read the Clang Internals Manual for technical details of adding an attribute.
- Look at code for an existing attribute that functions similarly and imitate it. Use
grep -R <attribute>
over the$(LLVM_SRC)
and$(CLANG_SRC)
directories to find every file in which the existing attribute has a presence. Careful: there's a lot of them!
Broadly:
- Build the entire LLVM project.
- Complete changes to the Clang Front End.
- Complete changes to the LLVM Back End.
- Rebuild the entire LLVM project using your build system (e.g.
make all
,cmake --build .
, etc.)
- $(CLANG_SRC)/include/clang/Basic/Attr.td Add the new front-end attribute definition.
- $(CLANG_SRC)/lib/AST/ASTContext.cpp Add your function attribute to
ASTContext::DeclMustBeEmitted()
. This helps ensure that your attribute is not discarded in the translation from the front end's AST to the back end's IR. - $(CLANG_SRC)/lib/CodeGen/CodeGenModule.cpp Add your attribute to the AttributeBuilder so that it gets emitted to the IR.
- $(CLANG_SRC)/lib/Sema/SemaDeclAttr.cpp This file implements llvm::Decl processing for attributes. There are two changes.
- Note that each attribute has a
static
handler function (e.g.static void handleSectionAttr(...)
) and optionally other helper functions (e.g.SectionAttr *Sema::mergeSectionAttr(...)
) where the attributes may be processed before they are handled. We only need to write a handler function for our new attribute, and do so after all other handlers. - Add a case statement to the function which applies your attribute to the specified declaration.
- Note that each attribute has a
- $(LLVM_SRC)/lib/Bitcode/Reader/BitcodeReader.cpp There are two changes here:
- Get the attribute kind mask. This was previously done in
$(LLVM_SRC)/include/llvm/Bitcode/LLVMBitCodes.h
- Provide a case statement for Bitcode decoding.
- Get the attribute kind mask. This was previously done in
- $(LLVM_SRC)/lib/Bitcode/Writer/BitcodeWriter.cpp
- $(LLVM_SRC)/lib/IR/Attributes.cpp This file implements attributes, including
AttrBuilder
andAttributeList
, both of which we use in this tutorial. Add a case to return the string for our new attribute, which is used for emitting human-readable IR. - $(LLVM_SRC)/include/llvm/Bitcode/LLVMBitCodes.h
- $(LLVM_SRC)/include/llvm/IR/Attributes.td
- $(LLVM_SRC)/lib/IR/Verifier.cpp
GCC/LLVM
annotate
attributehttps://bholt.org/posts/llvm-quick-tricks.html