LLVM Programmer’s Manual¶
Warning
This is always a work in progress.
Introduction¶
This document is meant to highlight some of the important classes and interfacesavailable in the LLVM source-base. This manual is not intended to explain whatLLVM is, how it works, and what LLVM code looks like. It assumes that you knowthe basics of LLVM and are interested in writing transformations or otherwiseanalyzing or manipulating the code.
This document should get you oriented so that you can find your way in thecontinuously growing source code that makes up the LLVM infrastructure. Notethat this manual is not intended to serve as a replacement for reading thesource code, so if you think there should be a method in one of these classes todo something, but it’s not listed, check the source. Links to thedoxygen sources are provided to make this as easy aspossible.
The first section of this document describes general information that is usefulto know when working in the LLVM infrastructure, and the second describes theCore LLVM classes. In the future this manual will be extended with informationdescribing how to use extension libraries, such as dominator information, CFGtraversal routines, and useful utilities like theInstVisitor
(doxygen) template.
General Information¶
This section contains general information that is useful if you are working inthe LLVM source-base, but that isn’t specific to any particular API.
The C++ Standard Template Library¶
LLVM makes heavy use of the C++ Standard Template Library (STL), perhaps muchmore than you are used to, or have seen before. Because of this, you might wantto do a little background reading in the techniques used and capabilities of thelibrary. There are many good pages that discuss the STL, and several books onthe subject that you can get, so it will not be discussed in this document.
Here are some useful links:
cppreference.com - an excellentreference for the STL and other parts of the standard C++ library.
cplusplus.com - another excellentreference like the one above.
C++ In a Nutshell - This is an O’Reillybook in the making. It has a decent Standard Library Reference that rivalsDinkumware’s, and is unfortunately no longer free since the book has beenpublished.
Bruce Eckel’s Thinking in C++, 2nd ed. Volume 2.(even better, get the book).
You are also encouraged to take a look at theLLVM Coding Standards guide which focuses on how to write maintainable code morethan where to put your curly braces.
Other useful references¶
Important and useful LLVM APIs¶
Here we highlight some LLVM APIs that are generally useful and good to knowabout when writing transformations.
Theisa<>
,cast<>
anddyn_cast<>
templates¶
The LLVM source-base makes extensive use of a custom form of RTTI. Thesetemplates have many similarities to the C++dynamic_cast<>
operator, butthey don’t have some drawbacks (primarily stemming from the fact thatdynamic_cast<>
only works on classes that have a v-table). Because they areused so often, you must know what they do and how they work. All of thesetemplates are defined in thellvm/Support/Casting.h
(doxygen) file (note that you veryrarely have to include this file directly).
isa<>
:The
isa<>
operator works exactly like the Java “instanceof
” operator.It returns true or false depending on whether a reference or pointer points toan instance of the specified class. This can be very useful for constraintchecking of various sorts (example below).cast<>
:The
cast<>
operator is a “checked cast” operation. It converts a pointeror reference from a base class to a derived class, causing an assertionfailure if it is not really an instance of the right type. This should beused in cases where you have some information that makes you believe thatsomething is of the right type. An example of theisa<>
andcast<>
template is:staticboolisLoopInvariant(constValue*V,constLoop*L){if(isa<Constant>(V)||isa<Argument>(V)||isa<GlobalValue>(V))returntrue;// Otherwise, it must be an instruction...return!L->contains(cast<Instruction>(V)->getParent());}
Note that you shouldnot use an
isa<>
test followed by acast<>
,for that use thedyn_cast<>
operator.dyn_cast<>
:The
dyn_cast<>
operator is a “checking cast” operation. It checks to seeif the operand is of the specified type, and if so, returns a pointer to it(this operator does not work with references). If the operand is not of thecorrect type, a null pointer is returned. Thus, this works very much likethedynamic_cast<>
operator in C++, and should be used in the samecircumstances. Typically, thedyn_cast<>
operator is used in anif
statement or some other flow control statement like this:if(auto*AI=dyn_cast<AllocationInst>(Val)){// ...}
This form of the
if
statement effectively combines together a call toisa<>
and a call tocast<>
into one statement, which is veryconvenient.Note that the
dyn_cast<>
operator, like C++’sdynamic_cast<>
or Java’sinstanceof
operator, can be abused. In particular, you should not use bigchainedif/then/else
blocks to check for lots of different variants ofclasses. If you find yourself wanting to do this, it is much cleaner and moreefficient to use theInstVisitor
class to dispatch over the instructiontype directly.isa_and_present<>
:The
isa_and_present<>
operator works just like theisa<>
operator,except that it allows for a null pointer as an argument (which it thenreturns false). This can sometimes be useful, allowing you to combine severalnull checks into one.cast_if_present<>
:The
cast_if_present<>
operator works just like thecast<>
operator,except that it allows for a null pointer as an argument (which it thenpropagates). This can sometimes be useful, allowing you to combine severalnull checks into one.dyn_cast_if_present<>
:The
dyn_cast_if_present<>
operator works just like thedyn_cast<>
operator, except that it allows for a null pointer as an argument (which itthen propagates). This can sometimes be useful, allowing you to combineseveral null checks into one.
These five templates can be used with any classes, whether they have a v-tableor not. If you want to add support for these templates, see the documentHow to set up LLVM-style RTTI for your class hierarchy
Passing strings (theStringRef
andTwine
classes)¶
Although LLVM generally does not do much string manipulation, we do have severalimportant APIs which take strings. Two important examples are the Value class– which has names for instructions, functions, etc. – and theStringMap
class which is used extensively in LLVM and Clang.
These are generic classes, and they need to be able to accept strings which mayhave embedded null characters. Therefore, they cannot simply take aconstchar*
, and taking aconststd::string&
requires clients to perform a heapallocation which is usually unnecessary. Instead, many LLVM APIs use aStringRef
or aconstTwine&
for passing strings efficiently.
TheStringRef
class¶
TheStringRef
data type represents a reference to a constant string (acharacter array and a length) and supports the common operations available onstd::string
, but does not require heap allocation.
It can be implicitly constructed using a C style null-terminated string, anstd::string
, or explicitly with a character pointer and length. Forexample, theStringMap
find function is declared as:
iteratorfind(StringRefKey);
and clients can call it using any one of:
Map.find("foo");// Lookup "foo"Map.find(std::string("bar"));// Lookup "bar"Map.find(StringRef("\0baz",4));// Lookup "\0baz"
Similarly, APIs which need to return a string may return aStringRef
instance, which can be used directly or converted to anstd::string
usingthestr
member function. Seellvm/ADT/StringRef.h
(doxygen) for moreinformation.
You should rarely use theStringRef
class directly, because it containspointers to external memory it is not generally safe to store an instance of theclass (unless you know that the external storage will not be freed).StringRef
is small and pervasive enough in LLVM that it should always bepassed by value.
TheTwine
class¶
TheTwine
(doxygen)class is an efficient way for APIs to accept concatenated strings. For example,a common LLVM paradigm is to name one instruction based on the name of anotherinstruction with a suffix, for example:
New=CmpInst::Create(...,SO->getName()+".cmp");
TheTwine
class is effectively a lightweightrope which points totemporary (stack allocated) objects. Twines can be implicitly constructed asthe result of the plus operator applied to strings (i.e., a C strings, anstd::string
, or aStringRef
). The twine delays the actual concatenationof strings until it is actually required, at which point it can be efficientlyrendered directly into a character array. This avoids unnecessary heapallocation involved in constructing the temporary results of stringconcatenation. Seellvm/ADT/Twine.h
(doxygen) andherefor more information.
As with aStringRef
,Twine
objects point to external memory and shouldalmost never be stored or mentioned directly. They are intended solely for usewhen defining a function which should be able to efficiently accept concatenatedstrings.
Formatting strings (theformatv
function)¶
While LLVM doesn’t necessarily do a lot of string manipulation and parsing, itdoes do a lot of string formatting. From diagnostic messages, to llvm tooloutputs such asllvm-readobj
to printing verbose disassembly listings andLLDB runtime logging, the need for string formatting is pervasive.
Theformatv
is similar in spirit toprintf
, but uses a different syntaxwhich borrows heavily from Python and C#. Unlikeprintf
it deduces the typeto be formatted at compile time, so it does not need a format specifier such as%d
. This reduces the mental overhead of trying to construct portable formatstrings, especially for platform-specific types likesize_t
or pointer types.Unlike bothprintf
and Python, it additionally fails to compile if LLVM doesnot know how to format the type. These two properties ensure that the functionis both safer and simpler to use than traditional formatting methods such astheprintf
family of functions.
Simple formatting¶
A call toformatv
involves a singleformat string consisting of 0 or morereplacement sequences, followed by a variable length list ofreplacement values.A replacement sequence is a string of the form{N[[,align]:style]}
.
N
refers to the 0-based index of the argument from the list of replacementvalues. Note that this means it is possible to reference the same parametermultiple times, possibly with different style and/or alignment options, in any order.
align
is an optional string specifying the width of the field to formatthe value into, and the alignment of the value within the field. It is specified asan optionalalignment style followed by a positive integralfield width. Thealignment style can be one of the characters-
(left align),=
(center align),or+
(right align). The default is right aligned.
style
is an optional string consisting of a type specific that controls theformatting of the value. For example, to format a floating point value as a percentage,you can use the style optionP
.
Custom formatting¶
There are two ways to customize the formatting behavior for a type.
Provide a template specialization of
llvm::format_provider<T>
for yourtypeT
with the appropriate static format method.
namespacellvm{template<>structformat_provider<MyFooBar>{staticvoidformat(constMyFooBar&V,raw_ostream&Stream,StringRefStyle){// Do whatever is necessary to format `V` into `Stream`}};voidfoo(){MyFooBarX;std::stringS=formatv("{0}",X);}}This is a useful extensibility mechanism for adding support for formatting your owncustom types with your own custom Style options. But it does not help when you wantto extend the mechanism for formatting a type that the library already knows how toformat. For that, we need something else.
Provide aformat adapter inheriting from
llvm::FormatAdapter<T>
.
namespaceanything{structformat_int_custom:publicllvm::FormatAdapter<int>{explicitformat_int_custom(intN):llvm::FormatAdapter<int>(N){}voidformat(llvm::raw_ostream&Stream,StringRefStyle)override{// Do whatever is necessary to format ``this->Item`` into ``Stream``}};}namespacellvm{voidfoo(){std::stringS=formatv("{0}",anything::format_int_custom(42));}}If the type is detected to be derived from
FormatAdapter<T>
,formatv
will call theformat
method on the argument passing in the specified style. This allowsone to provide custom formatting of any type, including one which already hasa builtin format provider.
formatv
Examples¶
Below is intended to provide an incomplete set of examples demonstratingthe usage offormatv
. More information can be found by reading thedoxygen documentation or by looking at the unit test suite.
std::stringS;// Simple formatting of basic types and implicit string conversion.S=formatv("{0} ({1:P})",7,0.35);// S == "7 (35.00%)"// Out-of-order referencing and multi-referencingouts()<<formatv("{0} {2} {1} {0}",1,"test",3);// prints "1 3 test 1"// Left, right, and center alignmentS=formatv("{0,7}",'a');// S == " a";S=formatv("{0,-7}",'a');// S == "a ";S=formatv("{0,=7}",'a');// S == " a ";S=formatv("{0,+7}",'a');// S == " a";// Custom stylesS=formatv("{0:N} - {0:x} - {1:E}",12345,123908342);// S == "12,345 - 0x3039 - 1.24E8"// AdaptersS=formatv("{0}",fmt_align(42,AlignStyle::Center,7));// S == " 42 "S=formatv("{0}",fmt_repeat("hi",3));// S == "hihihi"S=formatv("{0}",fmt_pad("hi",2,6));// S == " hi "// Rangesstd::vector<int>V={8,9,10};S=formatv("{0}",make_range(V.begin(),V.end()));// S == "8, 9, 10"S=formatv("{0:$[+]}",make_range(V.begin(),V.end()));// S == "8+9+10"S=formatv("{0:$[ + ]@[x]}",make_range(V.begin(),V.end()));// S == "0x8 + 0x9 + 0xA"
Error handling¶
Proper error handling helps us identify bugs in our code, and helps end-usersunderstand errors in their tool usage. Errors fall into two broad categories:programmatic andrecoverable, with different strategies for handling andreporting.
Programmatic Errors¶
Programmatic errors are violations of program invariants or API contracts, andrepresent bugs within the program itself. Our aim is to document invariants, andto abort quickly at the point of failure (providing some basic diagnostic) wheninvariants are broken at runtime.
The fundamental tools for handling programmatic errors are assertions and thellvm_unreachable function. Assertions are used to express invariant conditions,and should include a message describing the invariant:
assert(isPhysReg(R)&&"All virt regs should have been allocated already.");
The llvm_unreachable function can be used to document areas of control flowthat should never be entered if the program invariants hold:
enum{Foo,Bar,Baz}X=foo();switch(X){caseFoo:/* Handle Foo */;break;caseBar:/* Handle Bar */;break;default:llvm_unreachable("X should be Foo or Bar here");}
Additionally,reportFatalInternalError
can be used to report invariantviolations even in builds that do not enable assertions:
if(VerifyFooAnalysis&&!Foo.verify()){reportFatalInternalError("Analysis 'foo' not preserved");}
Recoverable Errors¶
Recoverable errors represent an error in the program’s environment, for examplea resource failure (a missing file, a dropped network connection, etc.), ormalformed input. These errors should be detected and communicated to a level ofthe program where they can be handled appropriately. Handling the error may beas simple as reporting the issue to the user, or it may involve attempts atrecovery.
Note
While it would be ideal to use this error handling scheme throughoutLLVM, there are places where this hasn’t been practical to apply. Insituations where you absolutely must emit a non-programmatic error andtheError
model isn’t workable you can callreportFatalUsageError
,which will call installed error handlers, print a message, and exit theprogram. The use ofreportFatalUsageError in this case is discouraged.
Recoverable errors are modeled using LLVM’sError
scheme. This schemerepresents errors using function return values, similar to classic C integererror codes, or C++’sstd::error_code
. However, theError
class isactually a lightweight wrapper for user-defined error types, allowing arbitraryinformation to be attached to describe the error. This is similar to the way C++exceptions allow throwing of user-defined types.
Success values are created by callingError::success()
, E.g.:
Errorfoo(){// Do something.// Return success.returnError::success();}
Success values are very cheap to construct and return - they have minimalimpact on program performance.
Failure values are constructed usingmake_error<T>
, whereT
is any classthat inherits from the ErrorInfo utility, E.g.:
classBadFileFormat:publicErrorInfo<BadFileFormat>{public:staticcharID;std::stringPath;BadFileFormat(StringRefPath):Path(Path.str()){}voidlog(raw_ostream&OS)constoverride{OS<<Path<<" is malformed";}std::error_codeconvertToErrorCode()constoverride{returnmake_error_code(object_error::parse_failed);}};charBadFileFormat::ID;// This should be declared in the C++ file.ErrorprintFormattedFile(StringRefPath){if(<checkforvalidformat>)returnmake_error<BadFileFormat>(Path);// print file contents.returnError::success();}
Error values can be implicitly converted to bool: true for error, false forsuccess, enabling the following idiom:
ErrormayFail();Errorfoo(){if(autoErr=mayFail())returnErr;// Success! We can proceed....
For functions that can fail but need to return a value theExpected<T>
utility can be used. Values of this type can be constructed with either aT
, or anError
. Expected<T> values are also implicitly convertible toboolean, but with the opposite convention toError
: true for success, falsefor error. If success, theT
value can be accessed via the dereferenceoperator. If failure, theError
value can be extracted using thetakeError()
method. Idiomatic usage looks like:
Expected<FormattedFile>openFormattedFile(StringRefPath){// If badly formatted, return an error.if(autoErr=checkFormat(Path))returnstd::move(Err);// Otherwise return a FormattedFile instance.returnFormattedFile(Path);}ErrorprocessFormattedFile(StringRefPath){// Try to open a formatted fileif(autoFileOrErr=openFormattedFile(Path)){// On success, grab a reference to the file and continue.auto&File=*FileOrErr;...}else// On error, extract the Error value and return it.returnFileOrErr.takeError();}
If anExpected<T>
value is in success mode then thetakeError()
methodwill return a success value. Using this fact, the above function can berewritten as:
ErrorprocessFormattedFile(StringRefPath){// Try to open a formatted fileautoFileOrErr=openFormattedFile(Path);if(autoErr=FileOrErr.takeError())// On error, extract the Error value and return it.returnErr;// On success, grab a reference to the file and continue.auto&File=*FileOrErr;...}
This second form is often more readable for functions that involve multipleExpected<T>
values as it limits the indentation required.
If anExpected<T>
value will be moved into an existing variable then themoveInto()
method avoids the need to name an extra variable. This isuseful to enableoperator->()
theExpected<T>
value has pointer-likesemantics. For example:
Expected<std::unique_ptr<MemoryBuffer>>openBuffer(StringRefPath);ErrorprocessBuffer(StringRefBuffer);ErrorprocessBufferAtPath(StringRefPath){// Try to open a buffer.std::unique_ptr<MemoryBuffer>MB;if(autoErr=openBuffer(Path).moveInto(MB))// On error, return the Error value.returnErr;// On success, use MB.returnprocessBuffer(MB->getBuffer());}
This third form works with any type that can be assigned to fromT&&
. Thiscan be useful if theExpected<T>
value needs to be stored an already-declaredstd::optional<T>
. For example:
Expected<StringRef>extractClassName(StringRefDefinition);structClassData{StringRefDefinition;std::optional<StringRef>LazyName;...Errorinitialize(){if(autoErr=extractClassName(Path).moveInto(LazyName))// On error, return the Error value.returnErr;// On success, LazyName has been initialized....}};
AllError
instances, whether success or failure, must be either checked ormoved from (viastd::move
or a return) before they are destructed.Accidentally discarding an unchecked error will cause a program abort at thepoint where the unchecked value’s destructor is run, making it easy to identifyand fix violations of this rule.
Success values are considered checked once they have been tested (by invokingthe boolean conversion operator):
if(autoErr=mayFail(...))returnErr;// Failure value - move error to caller.// Safe to continue: Err was checked.
In contrast, the following code will always cause an abort, even ifmayFail
returns a success value:
mayFail();// Program will always abort here, even if mayFail() returns Success, since// the value is not checked.
Failure values are considered checked once a handler for the error type hasbeen activated:
handleErrors(processFormattedFile(...),[](constBadFileFormat&BFF){report("Unable to process "+BFF.Path+": bad format");},[](constFileNotFound&FNF){report("File not found "+FNF.Path);});
ThehandleErrors
function takes an error as its first argument, followed bya variadic list of “handlers”, each of which must be a callable type (afunction, lambda, or class with a call operator) with one argument. ThehandleErrors
function will visit each handler in the sequence and check itsargument type against the dynamic type of the error, running the first handlerthat matches. This is the same decision process that is used decide which catchclause to run for a C++ exception.
Since the list of handlers passed tohandleErrors
may not cover every errortype that can occur, thehandleErrors
function also returns an Error valuethat must be checked or propagated. If the error value that is passed tohandleErrors
does not match any of the handlers it will be returned fromhandleErrors. Idiomatic use ofhandleErrors
thus looks like:
if(autoErr=handleErrors(processFormattedFile(...),[](constBadFileFormat&BFF){report("Unable to process "+BFF.Path+": bad format");},[](constFileNotFound&FNF){report("File not found "+FNF.Path);}))returnErr;
In cases where you truly know that the handler list is exhaustive thehandleAllErrors
function can be used instead. This is identical tohandleErrors
except that it will terminate the program if an unhandlederror is passed in, and can therefore return void. ThehandleAllErrors
function should generally be avoided: the introduction of a new error typeelsewhere in the program can easily turn a formerly exhaustive list of errorsinto a non-exhaustive list, risking unexpected program termination. Wherepossible, use handleErrors and propagate unknown errors up the stack instead.
For tool code, where errors can be handled by printing an error message thenexiting with an error code, theExitOnError utilitymay be a better choice than handleErrors, as it simplifies control flow whencalling fallible functions.
In situations where it is known that a particular call to a fallible functionwill always succeed (for example, a call to a function that can only fail on asubset of inputs with an input that is known to be safe) thecantFail functions can be used to remove the error type,simplifying control flow.
StringError¶
Many kinds of errors have no recovery strategy, the only action that can betaken is to report them to the user so that the user can attempt to fix theenvironment. In this case representing the error as a string makes perfectsense. LLVM provides theStringError
class for this purpose. It takes twoarguments: A string error message, and an equivalentstd::error_code
forinteroperability. It also provides acreateStringError
function to simplifycommon usage of this class:
// These two lines of code are equivalent:make_error<StringError>("Bad executable",errc::executable_format_error);createStringError(errc::executable_format_error,"Bad executable");
If you’re certain that the error you’re building will never need to be convertedto astd::error_code
you can use theinconvertibleErrorCode()
function:
createStringError(inconvertibleErrorCode(),"Bad executable");
This should be done only after careful consideration. If any attempt is made toconvert this error to astd::error_code
it will trigger immediate programtermination. Unless you are certain that your errors will not needinteroperability you should look for an existingstd::error_code
that youcan convert to, and even (as painful as it is) consider introducing a new one asa stopgap measure.
createStringError
can takeprintf
style format specifiers to provide aformatted message:
createStringError(errc::executable_format_error,"Bad executable: %s",FileName);
Interoperability with std::error_code and ErrorOr¶
Many existing LLVM APIs usestd::error_code
and its partnerErrorOr<T>
(which plays the same role asExpected<T>
, but wraps astd::error_code
rather than anError
). The infectious nature of error types means that anattempt to change one of these functions to returnError
orExpected<T>
instead often results in an avalanche of changes to callers, callers of callers,and so on. (The first such attempt, returning anError
fromMachOObjectFile’s constructor, was abandoned after the diff reached 3000 lines,impacted half a dozen libraries, and was still growing).
To solve this problem, theError
/std::error_code
interoperability requirement wasintroduced. Two pairs of functions allow anyError
value to be converted to astd::error_code
, anyExpected<T>
to be converted to anErrorOr<T>
, and viceversa:
std::error_codeerrorToErrorCode(ErrorErr);ErrorerrorCodeToError(std::error_codeEC);template<typenameT>ErrorOr<T>expectedToErrorOr(Expected<T>TOrErr);template<typenameT>Expected<T>errorOrToExpected(ErrorOr<T>TOrEC);
Using these APIs it is easy to make surgical patches that update individualfunctions fromstd::error_code
toError
, and fromErrorOr<T>
toExpected<T>
.
Returning Errors from error handlers¶
Error recovery attempts may themselves fail. For that reason,handleErrors
actually recognises three different forms of handler signature:
// Error must be handled, no new errors produced:void(UserDefinedError&E);// Error must be handled, new errors can be produced:Error(UserDefinedError&E);// Original error can be inspected, then re-wrapped and returned (or a new// error can be produced):Error(std::unique_ptr<UserDefinedError>E);
Any error returned from a handler will be returned from thehandleErrors
function so that it can be handled itself, or propagated up the stack.
Using ExitOnError to simplify tool code¶
Library code should never callexit
for a recoverable error, however in toolcode (especially command line tools) this can be a reasonable approach. Callingexit
upon encountering an error dramatically simplifies control flow as theerror no longer needs to be propagated up the stack. This allows code to bewritten in straight-line style, as long as each fallible call is wrapped in acheck and call to exit. TheExitOnError
class supports this pattern byproviding call operators that inspectError
values, stripping the error awayin the success case and logging tostderr
then exiting in the failure case.
To use this class, declare a globalExitOnError
variable in your program:
ExitOnErrorExitOnErr;
Calls to fallible functions can then be wrapped with a call toExitOnErr
,turning them into non-failing calls:
ErrormayFail();Expected<int>mayFail2();voidfoo(){ExitOnErr(mayFail());intX=ExitOnErr(mayFail2());}
On failure, the error’s log message will be written tostderr
, optionallypreceded by a string “banner” that can be set by calling the setBanner method. Amapping can also be supplied fromError
values to exit codes using thesetExitCodeMapper
method:
intmain(intargc,char*argv[]){ExitOnErr.setBanner(std::string(argv[0])+" error:");ExitOnErr.setExitCodeMapper([](constError&Err){if(Err.isA<BadFileFormat>())return2;return1;});
UseExitOnError
in your tool code where possible as it can greatly improvereadability.
Using cantFail to simplify safe callsites¶
Some functions may only fail for a subset of their inputs, so calls using knownsafe inputs can be assumed to succeed.
The cantFail functions encapsulate this by wrapping an assertion that theirargument is a success value and, in the case of Expected<T>, unwrapping theT value:
ErroronlyFailsForSomeXValues(intX);Expected<int>onlyFailsForSomeXValues2(intX);voidfoo(){cantFail(onlyFailsForSomeXValues(KnownSafeValue));intY=cantFail(onlyFailsForSomeXValues2(KnownSafeValue));...}
Like the ExitOnError utility, cantFail simplifies control flow. Their treatmentof error cases is very different however: Where ExitOnError is guaranteed toterminate the program on an error input, cantFail simply asserts that the resultis success. In debug builds this will result in an assertion failure if an erroris encountered. In release builds the behavior of cantFail for failure values isundefined. As such, care must be taken in the use of cantFail: clients must becertain that a cantFail wrapped call really can not fail with the givenarguments.
Use of the cantFail functions should be rare in library code, but they arelikely to be of more use in tool and unit-test code where inputs and/ormocked-up classes or functions may be known to be safe.
Fallible constructors¶
Some classes require resource acquisition or other complex initialization thatcan fail during construction. Unfortunately constructors can’t return errors,and having clients test objects after they’re constructed to ensure that they’revalid is error prone as it’s all too easy to forget the test. To work aroundthis, use the named constructor idiom and return anExpected<T>
:
classFoo{public:staticExpected<Foo>Create(ResourceR1,ResourceR2){ErrorErr=Error::success();FooF(R1,R2,Err);if(Err)returnstd::move(Err);returnstd::move(F);}private:Foo(ResourceR1,ResourceR2,Error&Err){ErrorAsOutParameterEAO(&Err);if(autoErr2=R1.acquire()){Err=std::move(Err2);return;}Err=R2.acquire();}};
Here, the named constructor passes anError
by reference into the actualconstructor, which the constructor can then use to return errors. TheErrorAsOutParameter
utility sets theError
value’s checked flag on entryto the constructor so that the error can be assigned to, then resets it on exitto force the client (the named constructor) to check the error.
By using this idiom, clients attempting to construct a Foo receive either awell-formed Foo or an Error, never an object in an invalid state.
Propagating and consuming errors based on types¶
In some contexts, certain types of error are known to be benign. For example,when walking an archive, some clients may be happy to skip over badly formattedobject files rather than terminating the walk immediately. Skipping badlyformatted objects could be achieved using an elaborate handler method, but theError.h header provides two utilities that make this idiom much cleaner: thetype inspection method,isA
, and theconsumeError
function:
ErrorwalkArchive(ArchiveA){for(unsignedI=0;I!=A.numMembers();++I){autoChildOrErr=A.getMember(I);if(autoErr=ChildOrErr.takeError()){if(Err.isA<BadFileFormat>())consumeError(std::move(Err))elsereturnErr;}auto&Child=*ChildOrErr;// Use Child...}returnError::success();}
Concatenating Errors with joinErrors¶
In the archive walking example aboveBadFileFormat
errors are simplyconsumed and ignored. If the client had wanted report these errors aftercompleting the walk over the archive they could use thejoinErrors
utility:
ErrorwalkArchive(ArchiveA){ErrorDeferredErrs=Error::success();for(unsignedI=0;I!=A.numMembers();++I){autoChildOrErr=A.getMember(I);if(autoErr=ChildOrErr.takeError())if(Err.isA<BadFileFormat>())DeferredErrs=joinErrors(std::move(DeferredErrs),std::move(Err));elsereturnErr;auto&Child=*ChildOrErr;// Use Child...}returnDeferredErrs;}
ThejoinErrors
routine builds a special error type calledErrorList
,which holds a list of user defined errors. ThehandleErrors
routinerecognizes this type and will attempt to handle each of the contained errors inorder. If all contained errors can be handled,handleErrors
will returnError::success()
, otherwisehandleErrors
will concatenate the remainingerrors and return the resultingErrorList
.
Building fallible iterators and iterator ranges¶
The archive walking examples above retrieve archive members by index, howeverthis requires considerable boiler-plate for iteration and error checking. We canclean this up by using the “fallible iterator” pattern, which supports thefollowing natural iteration idiom for fallible containers like Archive:
ErrorErr=Error::success();for(auto&Child:Ar->children(Err)){// Use Child - only enter the loop when it's valid// Allow early exit from the loop body, since we know that Err is success// when we're inside the loop.if(BailOutOn(Child))return;...}// Check Err after the loop to ensure it didn't break due to an error.if(Err)returnErr;
To enable this idiom, iterators over fallible containers are written in anatural style, with their++
and--
operators replaced with fallibleErrorinc()
andErrordec()
functions. E.g.:
classFallibleChildIterator{public:FallibleChildIterator(Archive&A,unsignedChildIdx);Archive::Child&operator*();friendbooloperator==(constArchiveIterator&LHS,constArchiveIterator&RHS);// operator++/operator-- replaced with fallible increment / decrement:Errorinc(){if(!A.childValid(ChildIdx+1))returnmake_error<BadArchiveMember>(...);++ChildIdx;returnError::success();}Errordec(){...}};
Instances of this kind of fallible iterator interface are then wrapped with thefallible_iterator utility which providesoperator++
andoperator--
,returning any errors via a reference passed in to the wrapper at constructiontime. The fallible_iterator wrapper takes care of (a) jumping to the end of therange on error, and (b) marking the error as checked whenever an iterator iscompared toend
and found to be inequal (in particular: this marks theerror as checked throughout the body of a range-based for loop), enabling earlyexit from the loop without redundant error checking.
Instances of the fallible iterator interface (e.g. FallibleChildIterator above)are wrapped using themake_fallible_itr
andmake_fallible_end
functions. E.g.:
classArchive{public:usingchild_iterator=fallible_iterator<FallibleChildIterator>;child_iteratorchild_begin(Error&Err){returnmake_fallible_itr(FallibleChildIterator(*this,0),Err);}child_iteratorchild_end(){returnmake_fallible_end(FallibleChildIterator(*this,size()));}iterator_range<child_iterator>children(Error&Err){returnmake_range(child_begin(Err),child_end());}};
Using the fallible_iterator utility allows for both natural construction offallible iterators (using failinginc
anddec
operations) andrelatively natural use of c++ iterator/loop idioms.
More information on Error and its related utilities can be found in theError.h header file.
Passing functions and other callable objects¶
Sometimes you may want a function to be passed a callback object. In order tosupport lambda expressions and other function objects, you should not use thetraditional C approach of taking a function pointer and an opaque cookie:
voidtakeCallback(bool(*Callback)(Function*,void*),void*Cookie);
Instead, use one of the following approaches:
Function template¶
If you don’t mind putting the definition of your function into a header file,make it a function template that is templated on the callable type.
template<typenameCallable>voidtakeCallback(CallableCallback){Callback(1,2,3);}
Thefunction_ref
class template¶
Thefunction_ref
(doxygen) classtemplate represents a reference to a callable object, templated over the typeof the callable. This is a good choice for passing a callback to a function,if you don’t need to hold onto the callback after the function returns. In thisway,function_ref
is tostd::function
asStringRef
is tostd::string
.
function_ref<Ret(Param1,Param2,...)>
can be implicitly constructed fromany callable object that can be called with arguments of typeParam1
,Param2
, …, and returns a value that can be converted to typeRet
.For example:
voidvisitBasicBlocks(Function*F,function_ref<bool(BasicBlock*)>Callback){for(BasicBlock&BB:*F)if(Callback(&BB))return;}
can be called using:
visitBasicBlocks(F,[&](BasicBlock*BB){if(process(BB))returnisEmpty(BB);returnfalse;});
Note that afunction_ref
object contains pointers to external memory, so itis not generally safe to store an instance of the class (unless you know thatthe external storage will not be freed). If you need this ability, considerusingstd::function
.function_ref
is small enough that it should alwaysbe passed by value.
TheLLVM_DEBUG()
macro and-debug
option¶
Often when working on your pass you will put a bunch of debugging printouts andother code into your pass. After you get it working, you want to remove it, butyou may need it again in the future (to work out new bugs that you run across).
Naturally, because of this, you don’t want to delete the debug printouts, butyou don’t want them to always be noisy. A standard compromise is to commentthem out, allowing you to enable them if you need them in the future.
Thellvm/Support/Debug.h
(doxygen) file provides a macro namedLLVM_DEBUG()
that is a much nicer solution to this problem. Basically, you canput arbitrary code into the argument of theLLVM_DEBUG
macro, and it is onlyexecuted if ‘opt
’ (or any other tool) is run with the ‘-debug
’ commandline argument:
LLVM_DEBUG(dbgs()<<"I am here!\n");
Then you can run your pass like this:
$ opt < a.bc > /dev/null -mypass<no output>$ opt < a.bc > /dev/null -mypass -debugI am here!
Using theLLVM_DEBUG()
macro instead of a home-brewed solution allows you to nothave to create “yet another” command line option for the debug output for yourpass. Note thatLLVM_DEBUG()
macros are disabled for non-asserts builds, so theydo not cause a performance impact at all (for the same reason, they should alsonot contain side-effects!).
One additional nice thing about theLLVM_DEBUG()
macro is that you can enable ordisable it directly in gdb. Just use “setDebugFlag=0
” or “setDebugFlag=1
” from the gdb if the program is running. If the program hasn’tbeen started yet, you can always just run it with-debug
.
Fine grained debug info withDEBUG_TYPE
and the-debug-only
option¶
Sometimes you may find yourself in a situation where enabling-debug
justturns ontoo much information (such as when working on the code generator).If you want to enable debug information with more fine-grained control, youshould define theDEBUG_TYPE
macro and use the-debug-only
option asfollows:
#define DEBUG_TYPE "foo"LLVM_DEBUG(dbgs()<<"'foo' debug type\n");#undef DEBUG_TYPE#define DEBUG_TYPE "bar"LLVM_DEBUG(dbgs()<<"'bar' debug type\n");#undef DEBUG_TYPE
Then you can run your pass like this:
$ opt < a.bc > /dev/null -mypass<no output>$ opt < a.bc > /dev/null -mypass -debug'foo' debug type'bar' debug type$ opt < a.bc > /dev/null -mypass -debug-only=foo'foo' debug type$ opt < a.bc > /dev/null -mypass -debug-only=bar'bar' debug type$ opt < a.bc > /dev/null -mypass -debug-only=foo,bar'foo' debug type'bar' debug type
Of course, in practice, you should only setDEBUG_TYPE
at the top of a file,to specify the debug type for the entire module. Be careful that you only dothis after including Debug.h and not around any #include of headers. Also, youshould use names more meaningful than “foo” and “bar”, because there is nosystem in place to ensure that names do not conflict. If two different modulesuse the same string, they will all be turned on when the name is specified.This allows, for example, all debug information for instruction scheduling to beenabled with-debug-only=InstrSched
, even if the source lives in multiplefiles. The name must not include a comma (,) as that is used to separate thearguments of the-debug-only
option.
For performance reasons, -debug-only is not available in optimized build(--enable-optimized
) of LLVM.
TheDEBUG_WITH_TYPE
macro is also available for situations where you wouldlike to setDEBUG_TYPE
, but only for one specificDEBUG
statement. Ittakes an additional first parameter, which is the type to use. For example, thepreceding example could be written as:
DEBUG_WITH_TYPE("foo",dbgs()<<"'foo' debug type\n");DEBUG_WITH_TYPE("bar",dbgs()<<"'bar' debug type\n");
TheStatistic
class &-stats
option¶
Thellvm/ADT/Statistic.h
(doxygen) file provides a classnamedStatistic
that is used as a unified way to keep track of what the LLVMcompiler is doing and how effective various optimizations are. It is useful tosee what optimizations are contributing to making a particular program runfaster.
Often you may run your pass on some big program, and you’re interested to seehow many times it makes a certain transformation. Although you can do this withhand inspection, or some ad-hoc method, this is a real pain and not very usefulfor big programs. Using theStatistic
class makes it very easy to keeptrack of this information, and the calculated information is presented in auniform manner with the rest of the passes being executed.
There are many examples ofStatistic
uses, but the basics of using it are asfollows:
Define your statistic like this:
#define DEBUG_TYPE "mypassname"// This goes after any #includes.STATISTIC(NumXForms,"The # of times I did stuff");
TheSTATISTIC
macro defines a static variable, whose name is specified bythe first argument. The pass name is taken from theDEBUG_TYPE
macro, andthe description is taken from the second argument. The variable defined(“NumXForms” in this case) acts like an unsigned integer.
Whenever you make a transformation, bump the counter:
++NumXForms;// I did stuff!
That’s all you have to do. To get ‘opt
’ to print out the statisticsgathered, use the ‘-stats
’ option:
$ opt -stats -mypassname < program.bc > /dev/null... statistics output ...
Note that in order to use the ‘-stats
’ option, LLVM must becompiled with assertions enabled.
When runningopt
on a C file from the SPEC benchmark suite, it gives areport that looks like this:
7646 bitcodewriter - Number of normal instructions 725 bitcodewriter - Number of oversized instructions129996 bitcodewriter - Number of bitcode bytes written 2817 raise - Number of insts DCEd or constprop'd 3213 raise - Number of cast-of-self removed 5046 raise - Number of expression trees converted 75 raise - Number of other getelementptr's formed 138 raise - Number of load/store peepholes 42 deadtypeelim - Number of unused typenames removed from symtab 392 funcresolve - Number of varargs functions resolved 27 globaldce - Number of global variables removed 2 adce - Number of basic blocks removed 134 cee - Number of branches revectored 49 cee - Number of setcc instruction eliminated 532 gcse - Number of loads removed 2919 gcse - Number of instructions removed 86 indvars - Number of canonical indvars added 87 indvars - Number of aux indvars removed 25 instcombine - Number of dead inst eliminate 434 instcombine - Number of insts combined 248 licm - Number of load insts hoisted 1298 licm - Number of insts hoisted to a loop pre-header 3 licm - Number of insts hoisted to multiple loop preds (bad, no loop pre-header) 75 mem2reg - Number of alloca's promoted 1444 cfgsimplify - Number of blocks simplified
Obviously, with so many optimizations, having a unified framework for this stuffis very nice. Making your pass fit well into the framework makes it moremaintainable and useful.
Adding debug counters to aid in debugging your code¶
Sometimes, when writing new passes, or trying to track down bugs, itis useful to be able to control whether certain things in your passhappen or not. For example, there are times the minimization toolingcan only easily give you large testcases. You would like to narrowyour bug down to a specific transformation happening or not happening,automatically, using bisection. This is where debug counters help.They provide a framework for making parts of your code only execute acertain number of times.
Thellvm/Support/DebugCounter.h
(doxygen) fileprovides a class namedDebugCounter
that can be used to createcommand line counter options that control execution of parts of your code.
Define your DebugCounter like this:
DEBUG_COUNTER(DeleteAnInstruction,"passname-delete-instruction","Controls which instructions get delete");
TheDEBUG_COUNTER
macro defines a static variable, whose nameis specified by the first argument. The name of the counter(which is used on the command line) is specified by the secondargument, and the description used in the help is specified by thethird argument.
Whatever code you want that control, useDebugCounter::shouldExecute
to control it.
if(DebugCounter::shouldExecute(DeleteAnInstruction))I->eraseFromParent();
That’s all you have to do. Now, using opt, you can control when this code triggers usingthe ‘--debug-counter
’ Options. To specify when to execute the codepath.
$ opt --debug-counter=passname-delete-instruction=2-3 -passname
This will skip the above code the first two times we hit it, then execute it 2 times, then skip the rest of the executions.
So if executed on the following code:
%1=addi32%a,%b%2=addi32%a,%b%3=addi32%a,%b%4=addi32%a,%b
It would delete number%2
and%3
.
A utility is provided inutils/bisect-skip-count to binary searchthe begin and end of the range argument. It can be used to automatically minimize therange for a debug-counter variable.
A more general utility is provided inllvm/tools/reduce-chunk-list/reduce-chunk-list.cpp to minimize debug counter chunks lists.
How to use reduce-chunk-list:First, Figure out the number of calls to the debug counter you want to minimize.To do so, run the compilation command causing you want to minimize with-print-debug-counter adding a-mllvm if needed.Than find the line with the counter of interest. it should look like:
my-counter : {5678,empty}
The number of calls tomy-counter is 5678
Than Find the minimum set of chunks that is interesting, withreduce-chunk-list.Build a reproducer script like:
#! /bin/bashopt-debug-counter=my-counter=$1# ... Test result of the command. Failure of the script is considered interesting
Than runreduce-chunk-list my-script.sh 0-5678 2>&1 | tee dump_bisectThis command may take some time.but when it is done, it will print the result like:Minimal Chunks = 0:1:5:11-12:33-34
Viewing graphs while debugging code¶
Several of the important data structures in LLVM are graphs: for example CFGsmade out of LLVMBasicBlocks, CFGs made out of LLVMMachineBasicBlocks, andInstruction SelectionDAGs. In many cases, while debugging various parts of thecompiler, it is nice to instantly visualize these graphs.
LLVM provides several callbacks that are available in a debug build to doexactly that. If you call theFunction::viewCFG()
method, for example, thecurrent LLVM tool will pop up a window containing the CFG for the function whereeach basic block is a node in the graph, and each node contains the instructionsin the block. Similarly, there also existsFunction::viewCFGOnly()
(doesnot include the instructions), theMachineFunction::viewCFG()
andMachineFunction::viewCFGOnly()
, and theSelectionDAG::viewGraph()
methods. Within GDB, for example, you can usually use something likecallDAG.viewGraph()
to pop up a window. Alternatively, you can sprinkle calls tothese functions in your code in places you want to debug.
Getting this to work requires a small amount of setup. On Unix systemswith X11, install thegraphviz toolkit, and makesure ‘dot’ and ‘gv’ are in your path. If you are running on macOS, downloadand install the macOSGraphviz program and add/Applications/Graphviz.app/Contents/MacOS/
(or wherever you install it) toyour path. The programs need not be present when configuring, building orrunning LLVM and can simply be installed when needed during an active debugsession.
SelectionDAG
has been extended to make it easier to locateinterestingnodes in large complex graphs. From gdb, if youcallDAG.setGraphColor(node,"color")
, then the nextcallDAG.viewGraph()
would highlight the node inthe specified color (choices of colors can be found atcolors.) More complex node attributescan be provided withcallDAG.setGraphAttrs(node,"attributes")
(choices canbe found atGraph attributes.)If you want to restart and clear all the current graph attributes, then you cancallDAG.clearGraphAttrs()
.
Note that graph visualization features are compiled out of Release builds toreduce file size. This means that you need a Debug+Asserts or Release+Assertsbuild to use these features.
Picking the Right Data Structure for a Task¶
LLVM has a plethora of data structures in thellvm/ADT/
directory, and wecommonly use STL data structures. This section describes the trade-offs youshould consider when you pick one.
The first step is a choose your own adventure: do you want a sequentialcontainer, a set-like container, or a map-like container? The most importantthing when choosing a container is the algorithmic properties of how you plan toaccess the container. Based on that, you should use:
amap-like container if you need efficient look-up of avalue based on another value. Map-like containers also support efficientqueries for containment (whether a key is in the map). Map-like containersgenerally do not support efficient reverse mapping (values to keys). If youneed that, use two maps. Some map-like containers also support efficientiteration through the keys in sorted order. Map-like containers are the mostexpensive sort, only use them if you need one of these capabilities.
aset-like container if you need to put a bunch of stuff intoa container that automatically eliminates duplicates. Some set-likecontainers support efficient iteration through the elements in sorted order.Set-like containers are more expensive than sequential containers.
asequential container provides the most efficient wayto add elements and keeps track of the order they are added to the collection.They permit duplicates and support efficient iteration, but do not supportefficient look-up based on a key.
astring container is a specialized sequential container orreference structure that is used for character or byte arrays.
abit container provides an efficient way to store andperform set operations on sets of numeric id’s, while automaticallyeliminating duplicates. Bit containers require a maximum of 1 bit for eachidentifier you want to store.
Once the proper category of container is determined, you can fine tune thememory use, constant factors, and cache behaviors of access by intelligentlypicking a member of the category. Note that constant factors and cache behaviorcan be a big deal. If you have a vector that usually only contains a fewelements (but could contain many), for example, it’s much better to useSmallVector thanvector. Doing soavoids (relatively) expensive malloc/free calls, which dwarf the cost of addingthe elements to the container.
Sequential Containers (std::vector, std::list, etc)¶
There are a variety of sequential containers available for you, based on yourneeds. Pick the first in this section that will do what you want.
llvm/ADT/ArrayRef.h¶
Thellvm::ArrayRef
class is the preferred class to use in an interface thataccepts a sequential list of elements in memory and just reads from them. Bytaking anArrayRef
, the API can be passed a fixed size array, anstd::vector
, anllvm::SmallVector
and anything else that is contiguousin memory.
Fixed Size Arrays¶
Fixed size arrays are very simple and very fast. They are good if you knowexactly how many elements you have, or you have a (low) upper bound on how manyyou have.
Heap Allocated Arrays¶
Heap allocated arrays (new[]
+delete[]
) are also simple. They are goodif the number of elements is variable, if you know how many elements you willneed before the array is allocated, and if the array is usually large (if not,consider aSmallVector). The cost of a heap allocatedarray is the cost of the new/delete (aka malloc/free). Also note that if youare allocating an array of a type with a constructor, the constructor anddestructors will be run for every element in the array (re-sizable vectors onlyconstruct those elements actually used).
llvm/ADT/TinyPtrVector.h¶
TinyPtrVector<Type>
is a highly specialized collection class that isoptimized to avoid allocation in the case when a vector has zero or oneelements. It has two major restrictions: 1) it can only hold values of pointertype, and 2) it cannot hold a null pointer.
Since this container is highly specialized, it is rarely used.
llvm/ADT/SmallVector.h¶
SmallVector<Type,N>
is a simple class that looks and smells just likevector<Type>
: it supports efficient iteration, lays out elements in memoryorder (so you can do pointer arithmetic between elements), supports efficientpush_back/pop_back operations, supports efficient random access to its elements,etc.
The main advantage of SmallVector is that it allocates space for some number ofelements (N)in the object itself. Because of this, if the SmallVector isdynamically smaller than N, no malloc is performed. This can be a big win incases where the malloc/free call is far more expensive than the code thatfiddles around with the elements.
This is good for vectors that are “usually small” (e.g. the number ofpredecessors/successors of a block is usually less than 8). On the other hand,this makes the size of the SmallVector itself large, so you don’t want toallocate lots of them (doing so will waste a lot of space). As such,SmallVectors are most useful when on the stack.
In the absence of a well-motivated choice for the number ofinlined elementsN
, it is recommended to useSmallVector<T>
(that is,omitting theN
). This will choose a default number ofinlined elements reasonable for allocation on the stack (for example, tryingto keepsizeof(SmallVector<T>)
around 64 bytes).
SmallVector also provides a nice portable and efficient replacement foralloca
.
SmallVector has grown a few other minor advantages over std::vector, causingSmallVector<Type,0>
to be preferred overstd::vector<Type>
.
std::vector is exception-safe, and some implementations have pessimizationsthat copy elements when SmallVector would move them.
SmallVector understands
std::is_trivially_copyable<Type>
and uses realloc aggressively.Many LLVM APIs take a SmallVectorImpl as an out parameter (see the notebelow).
SmallVector with N equal to 0 is smaller than std::vector on 64-bitplatforms, since it uses
unsigned
(instead ofvoid*
) for its sizeand capacity.
Note
Prefer to useArrayRef<T>
orSmallVectorImpl<T>
as a parameter type.
It’s rarely appropriate to useSmallVector<T,N>
as a parameter type.If an API only reads from the vector, it should useArrayRef. Even if an API updates the vector the “small size” isunlikely to be relevant; such an API should use theSmallVectorImpl<T>
class, which is the “vector header” (and methods) without the elementsallocated after it. Note thatSmallVector<T,N>
inherits fromSmallVectorImpl<T>
so the conversion is implicit and costs nothing. E.g.
// DISCOURAGED: Clients cannot pass e.g. raw arrays.hardcodedContiguousStorage(constSmallVectorImpl<Foo>&In);// ENCOURAGED: Clients can pass any contiguous storage of Foo.allowsAnyContiguousStorage(ArrayRef<Foo>In);voidsomeFunc1(){FooVec[]={/* ... */};hardcodedContiguousStorage(Vec);// Error.allowsAnyContiguousStorage(Vec);// Works.}// DISCOURAGED: Clients cannot pass e.g. SmallVector<Foo, 8>.hardcodedSmallSize(SmallVector<Foo,2>&Out);// ENCOURAGED: Clients can pass any SmallVector<Foo, N>.allowsAnySmallSize(SmallVectorImpl<Foo>&Out);voidsomeFunc2(){SmallVector<Foo,8>Vec;hardcodedSmallSize(Vec);// Error.allowsAnySmallSize(Vec);// Works.}
Even though it has “Impl
” in the name, SmallVectorImpl is widely usedand is no longer “private to the implementation”. A name likeSmallVectorHeader
might be more appropriate.
llvm/ADT/PagedVector.h¶
PagedVector<Type,PageSize>
is a random access container that allocatesPageSize
elements of typeType
when the first element of a page isaccessed via theoperator[]
. This is useful for cases where the number ofelements is known in advance; their actual initialization is expensive; andthey are sparsely used. This utility uses page-granular lazy initializationwhen the element is accessed. When the number of used pages is smallsignificant memory savings can be achieved.
The main advantage is that aPagedVector
allows to delay the actualallocation of the page until it’s needed, at the extra cost of one pointer perpage and one extra indirection when accessing elements with their positionalindex.
In order to minimise the memory footprint of this container, it’s important tobalance the PageSize so that it’s not too small (otherwise the overhead of thepointer per page might become too high) and not too big (otherwise the memoryis wasted if the page is not fully used).
Moreover, while retaining the order of the elements based on their insertionindex, like a vector, iterating over the elements viabegin()
andend()
is not provided in the API, due to the fact accessing the elements in orderwould allocate all the iterated pages, defeating memory savings and the purposeof thePagedVector
.
Finally amaterialized_begin()
andmaterialized_end
iterators areprovided to access the elements associated to the accessed pages, which couldspeed up operations that need to iterate over initialized elements in anon-ordered manner.
<vector>¶
std::vector<T>
is well loved and respected. However,SmallVector<T,0>
is often a better option due to the advantages listed above. std::vector isstill useful when you need to store more thanUINT32_MAX
elements or wheninterfacing with code that expects vectors :).
One worthwhile note about std::vector: avoid code like this:
for(...){std::vector<foo>V;// make use of V.}
Instead, write this as:
std::vector<foo>V;for(...){// make use of V.V.clear();}
Doing so will save (at least) one heap allocation and free per iteration of theloop.
<deque>¶
std::deque
is, in some senses, a generalized version ofstd::vector
.Likestd::vector
, it provides constant time random access and other similarproperties, but it also provides efficient access to the front of the list. Itdoes not guarantee continuity of elements within memory.
In exchange for this extra flexibility,std::deque
has significantly higherconstant factor costs thanstd::vector
. If possible, usestd::vector
orsomething cheaper.
<list>¶
std::list
is an extremely inefficient class that is rarely useful. Itperforms a heap allocation for every element inserted into it, thus having anextremely high constant factor, particularly for small data types.std::list
also only supports bidirectional iteration, not random accessiteration.
In exchange for this high cost, std::list supports efficient access to both endsof the list (likestd::deque
, but unlikestd::vector
orSmallVector
). In addition, the iterator invalidation characteristics ofstd::list are stronger than that of a vector class: inserting or removing anelement into the list does not invalidate iterator or pointers to other elementsin the list.
llvm/ADT/ilist.h¶
ilist<T>
implements an ‘intrusive’ doubly-linked list. It is intrusive,because it requires the element to store and provide access to the prev/nextpointers for the list.
ilist
has the same drawbacks asstd::list
, and additionally requires anilist_traits
implementation for the element type, but it provides some novelcharacteristics. In particular, it can efficiently store polymorphic objects,the traits class is informed when an element is inserted or removed from thelist, andilist
s are guaranteed to support a constant-time spliceoperation.
Anilist
and aniplist
areusing
aliases to one another and thelatter only currently exists for historical purposes.
These properties are exactly what we want for things likeInstruction
s andbasic blocks, which is why these are implemented withilist
s.
Related classes of interest are explained in the following subsections:
llvm/ADT/PackedVector.h¶
Useful for storing a vector of values using only a few number of bits for eachvalue. Apart from the standard operations of a vector-like container, it canalso perform an ‘or’ set operation.
For example:
enumState{None=0x0,FirstCondition=0x1,SecondCondition=0x2,Both=0x3};Stateget(){PackedVector<State,2>Vec1;Vec1.push_back(FirstCondition);PackedVector<State,2>Vec2;Vec2.push_back(SecondCondition);Vec1|=Vec2;returnVec1[0];// returns 'Both'.}
ilist_traits¶
ilist_traits<T>
isilist<T>
’s customization mechanism.ilist<T>
publicly derives from this traits class.
llvm/ADT/ilist_node.h¶
ilist_node<T>
implements the forward and backward links that are expectedby theilist<T>
(and analogous containers) in the default manner.
ilist_node<T>
s are meant to be embedded in the node typeT
, usuallyT
publicly derives fromilist_node<T>
.
Sentinels¶
ilist
s have another specialty that must be considered. To be a goodcitizen in the C++ ecosystem, it needs to support the standard containeroperations, such asbegin
andend
iterators, etc. Also, theoperator--
must work correctly on theend
iterator in the case ofnon-emptyilist
s.
The only sensible solution to this problem is to allocate a so-calledsentinelalong with the intrusive list, which serves as theend
iterator, providingthe back-link to the last element. However conforming to the C++ convention itis illegal tooperator++
beyond the sentinel and it also must not bedereferenced.
These constraints allow for some implementation freedom to theilist
how toallocate and store the sentinel. The corresponding policy is dictated byilist_traits<T>
. By default aT
gets heap-allocated whenever the needfor a sentinel arises.
While the default policy is sufficient in most cases, it may break down whenT
does not provide a default constructor. Also, in the case of manyinstances ofilist
s, the memory overhead of the associated sentinels iswasted. To alleviate the situation with numerous and voluminousT
-sentinels, sometimes a trick is employed, leading toghostly sentinels.
Ghostly sentinels are obtained by specially-craftedilist_traits<T>
whichsuperpose the sentinel with theilist
instance in memory. Pointerarithmetic is used to obtain the sentinel, which is relative to theilist
’sthis
pointer. Theilist
is augmented by an extra pointer, which servesas the back-link of the sentinel. This is the only field in the ghostlysentinel which can be legally accessed.
Other Sequential Container options¶
Other STL containers are available, such asstd::string
.
There are also various STL adapter classes such asstd::queue
,std::priority_queue
,std::stack
, etc. These provide simplified accessto an underlying container but don’t affect the cost of the container itself.
String-like containers¶
There are a variety of ways to pass around and use strings in C and C++, andLLVM adds a few new options to choose from. Pick the first option on this listthat will do what you need, they are ordered according to their relative cost.
Note that it is generally preferred tonot pass strings around asconstchar*
’s. These have a number of problems, including the fact that theycannot represent embedded nul (”0”) characters, and do not have a lengthavailable efficiently. The general replacement for ‘constchar*
’ isStringRef.
For more information on choosing string containers for APIs, please seePassing Strings.
llvm/ADT/StringRef.h¶
The StringRef class is a simple value class that contains a pointer to acharacter and a length, and is quite related to theArrayRef class (but specialized for arrays of characters). BecauseStringRef carries a length with it, it safely handles strings with embedded nulcharacters in it, getting the length does not require a strlen call, and it evenhas very convenient APIs for slicing and dicing the character range that itrepresents.
StringRef is ideal for passing simple strings around that are known to be live,either because they are C string literals, std::string, a C array, or aSmallVector. Each of these cases has an efficient implicit conversion toStringRef, which doesn’t result in a dynamic strlen being executed.
StringRef has a few major limitations which make more powerful string containersuseful:
You cannot directly convert a StringRef to a ‘const char*’ because there isno way to add a trailing nul (unlike the .c_str() method on various strongerclasses).
StringRef doesn’t own or keep alive the underlying string bytes.As such it can easily lead to dangling pointers, and is not suitable forembedding in datastructures in most cases (instead, use an std::string orsomething like that).
For the same reason, StringRef cannot be used as the return value of amethod if the method “computes” the result string. Instead, use std::string.
StringRef’s do not allow you to mutate the pointed-to string bytes and itdoesn’t allow you to insert or remove bytes from the range. For editingoperations like this, it interoperates with theTwineclass.
Because of its strengths and limitations, it is very common for a function totake a StringRef and for a method on an object to return a StringRef that pointsinto some string that it owns.
llvm/ADT/Twine.h¶
The Twine class is used as an intermediary datatype for APIs that want to take astring that can be constructed inline with a series of concatenations. Twineworks by forming recursive instances of the Twine datatype (a simple valueobject) on the stack as temporary objects, linking them together into a treewhich is then linearized when the Twine is consumed. Twine is only safe to useas the argument to a function, and should always be a const reference, e.g.:
voidfoo(constTwine&T);...StringRefX=...unsignedi=...foo(X+"."+Twine(i));
This example forms a string like “blarg.42” by concatenating the valuestogether, and does not form intermediate strings containing “blarg” or “blarg.”.
Because Twine is constructed with temporary objects on the stack, and becausethese instances are destroyed at the end of the current statement, it is aninherently dangerous API. For example, this simple variant contains undefinedbehavior and will probably crash:
voidfoo(constTwine&T);...StringRefX=...unsignedi=...constTwine&Tmp=X+"."+Twine(i);foo(Tmp);
… because the temporaries are destroyed before the call. That said, Twine’sare much more efficient than intermediate std::string temporaries, and they workreally well with StringRef. Just be aware of their limitations.
llvm/ADT/SmallString.h¶
SmallString is a subclass ofSmallVector that adds someconvenience APIs like += that takes StringRef’s. SmallString avoids allocatingmemory in the case when the preallocated space is enough to hold its data, andit calls back to general heap allocation when required. Since it owns its data,it is very safe to use and supports full mutation of the string.
Like SmallVector’s, the big downside to SmallString is their sizeof. While theyare optimized for small strings, they themselves are not particularly small.This means that they work great for temporary scratch buffers on the stack, butshould not generally be put into the heap: it is very rare to see a SmallStringas the member of a frequently-allocated heap data structure or returnedby-value.
std::string¶
The standard C++ std::string class is a very general class that (likeSmallString) owns its underlying data. sizeof(std::string) is very reasonableso it can be embedded into heap data structures and returned by-value. On theother hand, std::string is highly inefficient for inline editing (e.g.concatenating a bunch of stuff together) and because it is provided by thestandard library, its performance characteristics depend a lot of the hoststandard library (e.g. libc++ and MSVC provide a highly optimized string class,GCC contains a really slow implementation).
The major disadvantage of std::string is that almost every operation that makesthem larger can allocate memory, which is slow. As such, it is better to useSmallVector or Twine as a scratch buffer, but then use std::string to persistthe result.
Set-Like Containers (std::set, SmallSet, SetVector, etc)¶
Set-like containers are useful when you need to canonicalize multiple valuesinto a single representation. There are several different choices for how to dothis, providing various trade-offs.
A sorted ‘vector’¶
If you intend to insert a lot of elements, then do a lot of queries, a greatapproach is to use an std::vector (or other sequential container) withstd::sort+std::unique to remove duplicates. This approach works really well ifyour usage pattern has these two distinct phases (insert then query), and can becoupled with a good choice ofsequential container.
This combination provides the several nice properties: the result data iscontiguous in memory (good for cache locality), has few allocations, is easy toaddress (iterators in the final vector are just indices or pointers), and can beefficiently queried with a standard binary search (e.g.std::lower_bound
; if you want the whole range of elements comparingequal, usestd::equal_range
).
llvm/ADT/SmallSet.h¶
If you have a set-like data structure that is usually small and whose elementsare reasonably small, aSmallSet<Type,N>
is a good choice. This set hasspace for N elements in place (thus, if the set is dynamically smaller than N,no malloc traffic is required) and accesses them with a simple linear search.When the set grows beyond N elements, it allocates a more expensiverepresentation that guarantees efficient access (for most types, it falls backtostd::set, but for pointers it uses something far better,SmallPtrSet.
The magic of this class is that it handles small sets extremely efficiently, butgracefully handles extremely large sets without loss of efficiency.
llvm/ADT/SmallPtrSet.h¶
SmallPtrSet
has all the advantages ofSmallSet
(and aSmallSet
ofpointers is transparently implemented with aSmallPtrSet
). If more than Ninsertions are performed, a single quadratically probed hash table is allocatedand grows as needed, providing extremely efficient access (constant timeinsertion/deleting/queries with low constant factors) and is very stingy withmalloc traffic.
Note that, unlikestd::set, the iterators ofSmallPtrSet
are invalidated whenever an insertion or erasure occurs. Theremove_if
method can be used to remove elements while iterating over the set.
Also, the values visited by the iterators are not visited in sorted order.
llvm/ADT/StringSet.h¶
StringSet
is a thin wrapper aroundStringMap<char>,and it allows efficient storage and retrieval of unique strings.
Functionally analogous toSmallSet<StringRef>
,StringSet
also supportsiteration. (The iterator dereferences to aStringMapEntry<char>
, so youneed to calli->getKey()
to access the item of the StringSet.) On theother hand,StringSet
doesn’t support range-insertion andcopy-construction, whichSmallSet andSmallPtrSet do support.
llvm/ADT/DenseSet.h¶
DenseSet is a simple quadratically probed hash table. It excels at supportingsmall values: it uses a single allocation to hold all of the pairs that arecurrently inserted in the set. DenseSet is a great way to unique small valuesthat are not simple pointers (useSmallPtrSet forpointers). Note that DenseSet has the same requirements for the value type thatDenseMap has.
llvm/ADT/SparseSet.h¶
SparseSet holds a small number of objects identified by unsigned keys ofmoderate size. It uses a lot of memory, but provides operations that are almostas fast as a vector. Typical keys are physical registers, virtual registers, ornumbered basic blocks.
SparseSet is useful for algorithms that need very fast clear/find/insert/eraseand fast iteration over small sets. It is not intended for building compositedata structures.
llvm/ADT/SparseMultiSet.h¶
SparseMultiSet adds multiset behavior to SparseSet, while retaining SparseSet’sdesirable attributes. Like SparseSet, it typically uses a lot of memory, butprovides operations that are almost as fast as a vector. Typical keys arephysical registers, virtual registers, or numbered basic blocks.
SparseMultiSet is useful for algorithms that need very fastclear/find/insert/erase of the entire collection, and iteration over sets ofelements sharing a key. It is often a more efficient choice than using compositedata structures (e.g. vector-of-vectors, map-of-vectors). It is not intended forbuilding composite data structures.
llvm/ADT/FoldingSet.h¶
FoldingSet is an aggregate class that is really good at uniquingexpensive-to-create or polymorphic objects. It is a combination of a chainedhash table with intrusive links (uniqued objects are required to inherit fromFoldingSetNode) that usesSmallVector as part of its IDprocess.
Consider a case where you want to implement a “getOrCreateFoo” method for acomplex object (for example, a node in the code generator). The client has adescription ofwhat it wants to generate (it knows the opcode and all theoperands), but we don’t want to ‘new’ a node, then try inserting it into a setonly to find out it already exists, at which point we would have to delete itand return the node that already exists.
To support this style of client, FoldingSet perform a query with aFoldingSetNodeID (which wraps SmallVector) that can be used to describe theelement that we want to query for. The query either returns the elementmatching the ID or it returns an opaque ID that indicates where insertion shouldtake place. Construction of the ID usually does not require heap traffic.
Because FoldingSet uses intrusive links, it can support polymorphic objects inthe set (for example, you can have SDNode instances mixed with LoadSDNodes).Because the elements are individually allocated, pointers to the elements arestable: inserting or removing elements does not invalidate any pointers to otherelements.
<set>¶
std::set
is a reasonable all-around set class, which is decent at manythings but great at nothing. std::set allocates memory for each elementinserted (thus it is very malloc intensive) and typically stores three pointersper element in the set (thus adding a large amount of per-element spaceoverhead). It offers guaranteed log(n) performance, which is not particularlyfast from a complexity standpoint (particularly if the elements of the set areexpensive to compare, like strings), and has extremely high constant factors forlookup, insertion and removal.
The advantages of std::set are that its iterators are stable (deleting orinserting an element from the set does not affect iterators or pointers to otherelements) and that iteration over the set is guaranteed to be in sorted order.If the elements in the set are large, then the relative overhead of the pointersand malloc traffic is not a big deal, but if the elements of the set are small,std::set is almost never a good choice.
llvm/ADT/SetVector.h¶
LLVM’sSetVector<Type>
is an adapter class that combines your choice of aset-like container along with aSequential Container Theimportant property that this provides is efficient insertion with uniquing(duplicate elements are ignored) with iteration support. It implements this byinserting elements into both a set-like container and the sequential container,using the set-like container for uniquing and the sequential container foriteration.
The difference between SetVector and other sets is that the order of iterationis guaranteed to match the order of insertion into the SetVector. This propertyis really important for things like sets of pointers. Because pointer valuesare non-deterministic (e.g. vary across runs of the program on differentmachines), iterating over the pointers in the set will not be in a well-definedorder.
The drawback of SetVector is that it requires twice as much space as a normalset and has the sum of constant factors from the set-like container and thesequential container that it uses. Use itonly if you need to iterate overthe elements in a deterministic order. SetVector is also expensive to deleteelements out of (linear time), unless you use its “pop_back” method, which isfaster.
SetVector
is an adapter class that defaults to usingstd::vector
and asize 16SmallSet
for the underlying containers, so it is quite expensive.However,"llvm/ADT/SetVector.h"
also provides aSmallSetVector
class,which defaults to using aSmallVector
andSmallSet
of a specified size.If you use this, and if your sets are dynamically smaller thanN
, you willsave a lot of heap traffic.
llvm/ADT/UniqueVector.h¶
UniqueVector is similar toSetVector but it retains aunique ID for each element inserted into the set. It internally contains a mapand a vector, and it assigns a unique ID for each value inserted into the set.
UniqueVector is very expensive: its cost is the sum of the cost of maintainingboth the map and vector, it has high complexity, high constant factors, andproduces a lot of malloc traffic. It should be avoided.
llvm/ADT/ImmutableSet.h¶
ImmutableSet is an immutable (functional) set implementation based on an AVLtree. Adding or removing elements is done through a Factory object and resultsin the creation of a new ImmutableSet object. If an ImmutableSet already existswith the given contents, then the existing one is returned; equality is comparedwith a FoldingSetNodeID. The time and space complexity of add or removeoperations is logarithmic in the size of the original set.
There is no method for returning an element of the set, you can only check formembership.
Other Set-Like Container Options¶
The STL provides several other options, such as std::multiset andstd::unordered_set. We never use containers like unordered_set becausethey are generally very expensive (each insertion requires a malloc).
std::multiset is useful if you’re not interested in elimination of duplicates,but has all the drawbacks ofstd::set. A sorted vector(where you don’t delete duplicate entries) or some other approach is almostalways better.
Map-Like Containers (std::map, DenseMap, etc)¶
Map-like containers are useful when you want to associate data to a key. Asusual, there are a lot of different ways to do this. :)
A sorted ‘vector’¶
If your usage pattern follows a strict insert-then-query approach, you cantrivially use the same approach assorted vectors for set-like containers. The only difference is that your query function (whichuses std::lower_bound to get efficient log(n) lookup) should only compare thekey, not both the key and value. This yields the same advantages as sortedvectors for sets.
llvm/ADT/StringMap.h¶
Strings are commonly used as keys in maps, and they are difficult to supportefficiently: they are variable length, inefficient to hash and compare whenlong, expensive to copy, etc. StringMap is a specialized container designed tocope with these issues. It supports mapping an arbitrary range of bytes to anarbitrary other object.
The StringMap implementation uses a quadratically-probed hash table, where thebuckets store a pointer to the heap allocated entries (and some other stuff).The entries in the map must be heap allocated because the strings are variablelength. The string data (key) and the element object (value) are stored in thesame allocation with the string data immediately after the element object.This container guarantees the “(char*)(&Value+1)
” points to the key stringfor a value.
The StringMap is very fast for several reasons: quadratic probing is very cacheefficient for lookups, the hash value of strings in buckets is not recomputedwhen looking up an element, StringMap rarely has to touch the memory forunrelated objects when looking up a value (even when hash collisions happen),hash table growth does not recompute the hash values for strings already in thetable, and each pair in the map is store in a single allocation (the string datais stored in the same allocation as the Value of a pair).
StringMap also provides query methods that take byte ranges, so it only evercopies a string if a value is inserted into the table.
StringMap iteration order, however, is not guaranteed to be deterministic, soany uses which require that should instead use a std::map.
llvm/ADT/IndexedMap.h¶
IndexedMap is a specialized container for mapping small dense integers (orvalues that can be mapped to small dense integers) to some other type. It isinternally implemented as a vector with a mapping function that maps the keysto the dense integer range.
This is useful for cases like virtual registers in the LLVM code generator: theyhave a dense mapping that is offset by a compile-time constant (the firstvirtual register ID).
llvm/ADT/DenseMap.h¶
DenseMap is a simple quadratically probed hash table. It excels at supportingsmall keys and values: it uses a single allocation to hold all of the pairsthat are currently inserted in the map. DenseMap is a great way to mappointers to pointers, or map other small types to each other.
There are several aspects of DenseMap that you should be aware of, however.The iterators in a DenseMap are invalidated whenever an insertion occurs,unlike map. Also, because DenseMap allocates space for a large number ofkey/value pairs (it starts with 64 by default), it will waste a lot of space ifyour keys or values are large. Finally, you must implement a partialspecialization of DenseMapInfo for the key that you want, if it isn’t alreadysupported. This is required to tell DenseMap about two special marker values(which can never be inserted into the map) that it needs internally.
DenseMap’s find_as() method supports lookup operations using an alternate keytype. This is useful in cases where the normal key type is expensive toconstruct, but cheap to compare against. The DenseMapInfo is responsible fordefining the appropriate comparison and hashing methods for each alternate keytype used.
DenseMap.h also contains a SmallDenseMap variant, that similar toSmallVector performs no heap allocation until thenumber of elements in the template parameter N are exceeded.
llvm/IR/ValueMap.h¶
ValueMap is a wrapper around aDenseMap mappingValue*
s (or subclasses) to another type. When a Value is deleted orRAUW’ed, ValueMap will update itself so the new version of the key is mapped tothe same value, just as if the key were a WeakVH. You can configure exactly howthis happens, and what else happens on these two events, by passing aConfig
parameter to the ValueMap template.
llvm/ADT/IntervalMap.h¶
IntervalMap is a compact map for small keys and values. It maps key intervalsinstead of single keys, and it will automatically coalesce adjacent intervals.When the map only contains a few intervals, they are stored in the map objectitself to avoid allocations.
The IntervalMap iterators are quite big, so they should not be passed around asSTL iterators. The heavyweight iterators allow a smaller data structure.
llvm/ADT/IntervalTree.h¶
llvm::IntervalTree
is a light tree data structure to hold intervals. Itallows finding all intervals that overlap with any given point. At this time,it does not support any deletion or rebalancing operations.
The IntervalTree is designed to be set up once, and then queried without anyfurther additions.
<map>¶
std::map has similar characteristics tostd::set: it uses asingle allocation per pair inserted into the map, it offers log(n) lookup withan extremely large constant factor, imposes a space penalty of 3 pointers perpair in the map, etc.
std::map is most useful when your keys or values are very large, if you need toiterate over the collection in sorted order, or if you need stable iteratorsinto the map (i.e. they don’t get invalidated if an insertion or deletion ofanother element takes place).
llvm/ADT/MapVector.h¶
MapVector<KeyT,ValueT>
provides a subset of the DenseMap interface. Themain difference is that the iteration order is guaranteed to be the insertionorder, making it an easy (but somewhat expensive) solution for non-deterministiciteration over maps of pointers.
It is implemented by mapping from key to an index in a vector of key,valuepairs. This provides fast lookup and iteration, but has two main drawbacks:the key is stored twice and removing elements takes linear time. If it isnecessary to remove elements, it’s best to remove them in bulk usingremove_if()
.
llvm/ADT/IntEqClasses.h¶
IntEqClasses provides a compact representation of equivalence classes of smallintegers. Initially, each integer in the range 0..n-1 has its own equivalenceclass. Classes can be joined by passing two class representatives to thejoin(a, b) method. Two integers are in the same class when findLeader() returnsthe same representative.
Once all equivalence classes are formed, the map can be compressed so eachinteger 0..n-1 maps to an equivalence class number in the range 0..m-1, where mis the total number of equivalence classes. The map must be uncompressed beforeit can be edited again.
llvm/ADT/ImmutableMap.h¶
ImmutableMap is an immutable (functional) map implementation based on an AVLtree. Adding or removing elements is done through a Factory object and resultsin the creation of a new ImmutableMap object. If an ImmutableMap already existswith the given key set, then the existing one is returned; equality is comparedwith a FoldingSetNodeID. The time and space complexity of add or removeoperations is logarithmic in the size of the original map.
Other Map-Like Container Options¶
The STL provides several other options, such as std::multimap andstd::unordered_map. We never use containers like unordered_map becausethey are generally very expensive (each insertion requires a malloc).
std::multimap is useful if you want to map a key to multiple values, but has allthe drawbacks of std::map. A sorted vector or some other approach is almostalways better.
Bit storage containers¶
There are several bit storage containers, and choosing when to use each isrelatively straightforward.
One additional option isstd::vector<bool>
: we discourage its use for tworeasons 1) the implementation in many common compilers (e.g. commonlyavailable versions of GCC) is extremely inefficient and 2) the C++ standardscommittee is likely to deprecate this container and/or change it significantlysomehow. In any case, please don’t use it.
BitVector¶
The BitVector container provides a dynamic size set of bits for manipulation.It supports individual bit setting/testing, as well as set operations. The setoperations take time O(size of bitvector), but operations are performed one wordat a time, instead of one bit at a time. This makes the BitVector very fast forset operations compared to other containers. Use the BitVector when you expectthe number of set bits to be high (i.e. a dense set).
SmallBitVector¶
The SmallBitVector container provides the same interface as BitVector, but it isoptimized for the case where only a small number of bits, less than 25 or so,are needed. It also transparently supports larger bit counts, but slightly lessefficiently than a plain BitVector, so SmallBitVector should only be used whenlarger counts are rare.
At this time, SmallBitVector does not support set operations (and, or, xor), andits operator[] does not provide an assignable lvalue.
SparseBitVector¶
The SparseBitVector container is much like BitVector, with one major difference:Only the bits that are set, are stored. This makes the SparseBitVector muchmore space efficient than BitVector when the set is sparse, as well as makingset operations O(number of set bits) instead of O(size of universe). Thedownside to the SparseBitVector is that setting and testing of random bits isO(N), and on large SparseBitVectors, this can be slower than BitVector. In ourimplementation, setting or testing bits in sorted order (either forwards orreverse) is O(1) worst case. Testing and setting bits within 128 bits (dependson size) of the current bit is also O(1). As a general statement,testing/setting bits in a SparseBitVector is O(distance away from last set bit).
CoalescingBitVector¶
The CoalescingBitVector container is similar in principle to a SparseBitVector,but is optimized to represent large contiguous ranges of set bits compactly. Itdoes this by coalescing contiguous ranges of set bits into intervals. Searchingfor a bit in a CoalescingBitVector is O(log(gaps between contiguous ranges)).
CoalescingBitVector is a better choice than BitVector when gaps between rangesof set bits are large. It’s a better choice than SparseBitVector when find()operations must have fast, predictable performance. However, it’s not a goodchoice for representing sets which have lots of very short ranges. E.g. the set{2*x : x in [0, n)} would be a pathological input.
Useful Utility Functions¶
LLVM implements a number of general utility functions used across thecodebase. You can find the most common ones inSTLExtras.h
(doxygen). Some of these wrapwell-known C++ standard library functions, while others are unique to LLVM.
Iterating over ranges¶
Sometimes you may want to iterate over more than range at a time or know theindex of the index. LLVM provides custom utility functions to make that easier,without having to manually manage all iterators and/or indices:
Thezip
* functions¶
zip
* functions allow for iterating over elements from two or more rangesat the same time. For example:
SmallVector<size_t>Counts=...;charLetters[26]=...;for(auto[Letter,Count]:zip_equal(Letters,Counts))errs()<<Letter<<": "<<Count<<"\n";
Note that the elements are provided through a ‘reference wrapper’ proxy type(tuple of references), which combined with the structured bindings declarationmakesLetter
andCount
references to range elements. Any modificationto these references will affect the elements ofLetters
orCounts
.
Thezip
* functions support temporary ranges, for example:
for(auto[Letter,Count]:zip(SmallVector<char>{'a','b','c'},Counts))errs()<<Letter<<": "<<Count<<"\n";
The difference between the functions in thezip
family is how they behavewhen the supplied ranges have different lengths:
zip_equal
– requires all input ranges have the same length.zip
– iteration stops when the end of the shortest range is reached.zip_first
– requires the first range is the shortest one.zip_longest
– iteration continues until the end of the longest range isreached. The non-existent elements of shorter ranges are replaced withstd::nullopt
.
The length requirements are checked withassert
s.
As a rule of thumb, prefer to usezip_equal
when you expect allranges to have the same lengths, and consider alternativezip
functions onlywhen this is not the case. This is becausezip_equal
clearly communicatesthis same-length assumption and has the best (release-mode) runtime performance.
enumerate
¶
Theenumerate
functions allows to iterate over one or more ranges whilekeeping track of the index of the current loop iteration. For example:
for(auto[Idx,BB,Value]:enumerate(Phi->blocks(),Phi->incoming_values()))errs()<<"#"<<Idx<<" "<<BB->getName()<<": "<<*Value<<"\n";
The current element index is provided as the first structured bindings element.Alternatively, the index and the element value can be obtained with theindex()
andvalue()
member functions:
charLetters[26]=...;for(autoEn:enumerate(Letters))errs()<<"#"<<En.index()<<" "<<En.value()<<"\n";
Note thatenumerate
haszip_equal
semantics and provides elementsthrough a ‘reference wrapper’ proxy, which makes them modifiable when accessedthrough structured bindings or thevalue()
member function. When two or moreranges are passed,enumerate
requires them to have equal lengths (checkedwith anassert
).
Debugging¶
A handful ofGDB pretty printers areprovided for some of the core LLVM libraries. To use them, execute thefollowing (or add it to your~/.gdbinit
):
source/path/to/llvm/src/utils/gdb-scripts/prettyprinters.py
It also might be handy to enable theprint pretty option toavoid data structures being printed as a big block of text.
Helpful Hints for Common Operations¶
This section describes how to perform some very simple transformations of LLVMcode. This is meant to give examples of common idioms used, showing thepractical side of LLVM transformations.
Because this is a “how-to” section, you should also read about the main classesthat you will be working with. TheCore LLVM Class Hierarchy Reference contains details and descriptions of the main classes that youshould know about.
Basic Inspection and Traversal Routines¶
The LLVM compiler infrastructure have many different data structures that may betraversed. Following the example of the C++ standard template library, thetechniques used to traverse these various data structures are all basically thesame. For an enumerable sequence of values, theXXXbegin()
function (ormethod) returns an iterator to the start of the sequence, theXXXend()
function returns an iterator pointing to one past the last valid element of thesequence, and there is someXXXiterator
data type that is common between thetwo operations.
Because the pattern for iteration is common across many different aspects of theprogram representation, the standard template library algorithms may be used onthem, and it is easier to remember how to iterate. First we show a few commonexamples of the data structures that need to be traversed. Other datastructures are traversed in very similar ways.
Iterating over theBasicBlock
in aFunction
¶
It’s quite common to have aFunction
instance that you’d like to transformin some way; in particular, you’d like to manipulate itsBasicBlock
s. Tofacilitate this, you’ll need to iterate over all of theBasicBlock
s thatconstitute theFunction
. The following is an example that prints the nameof aBasicBlock
and the number ofInstruction
s it contains:
Function&Func=...for(BasicBlock&BB:Func)// Print out the name of the basic block if it has one, and then the// number of instructions that it containserrs()<<"Basic block (name="<<BB.getName()<<") has "<<BB.size()<<" instructions.\n";
Iterating over theInstruction
in aBasicBlock
¶
Just like when dealing withBasicBlock
s inFunction
s, it’s easy toiterate over the individual instructions that make upBasicBlock
s. Here’sa code snippet that prints out each instruction in aBasicBlock
:
BasicBlock&BB=...for(Instruction&I:BB)// The next statement works since operator<<(ostream&,...)// is overloaded for Instruction&errs()<<I<<"\n";
However, this isn’t really the best way to print out the contents of aBasicBlock
! Since the ostream operators are overloaded for virtuallyanything you’ll care about, you could have just invoked the print routine on thebasic block itself:errs()<<BB<<"\n";
.
Iterating over theInstruction
in aFunction
¶
If you’re finding that you commonly iterate over aFunction
’sBasicBlock
s and then thatBasicBlock
’sInstruction
s,InstIterator
should be used instead. You’ll need to includellvm/IR/InstIterator.h
(doxygen) and then instantiateInstIterator
s explicitly in your code. Here’s a small example that showshow to dump all instructions in a function to the standard error stream:
#include"llvm/IR/InstIterator.h"// F is a pointer to a Function instancefor(inst_iteratorI=inst_begin(F),E=inst_end(F);I!=E;++I)errs()<<*I<<"\n";
Easy, isn’t it? You can also useInstIterator
s to fill a work list withits initial contents. For example, if you wanted to initialize a work list tocontain all instructions in aFunction
F, all you would need to do issomething like:
std::set<Instruction*>worklist;// or better yet, SmallPtrSet<Instruction*, 64> worklist;for(inst_iteratorI=inst_begin(F),E=inst_end(F);I!=E;++I)worklist.insert(&*I);
The STL setworklist
would now contain all instructions in theFunction
pointed to by F.
Turning an iterator into a class pointer (and vice-versa)¶
Sometimes, it’ll be useful to grab a reference (or pointer) to a class instancewhen all you’ve got at hand is an iterator. Well, extracting a reference or apointer from an iterator is very straight-forward. Assuming thati
is aBasicBlock::iterator
andj
is aBasicBlock::const_iterator
:
Instruction&inst=*i;// Grab reference to instruction referenceInstruction*pinst=&*i;// Grab pointer to instruction referenceconstInstruction&inst=*j;
It’s also possible to turn a class pointer into the corresponding iterator, andthis is a constant time operation (very efficient). The following code snippetillustrates use of the conversion constructors provided by LLVM iterators. Byusing these, you can explicitly grab the iterator of something without actuallyobtaining it via iteration over some structure:
voidprintNextInstruction(Instruction*inst){BasicBlock::iteratorit(inst);++it;// After this line, it refers to the instruction after *instif(it!=inst->getParent()->end())errs()<<*it<<"\n";}
Finding call sites: a slightly more complex example¶
Say that you’re writing a FunctionPass and would like to count all the locationsin the entire module (that is, across everyFunction
) where a certainfunction (i.e., someFunction*
) is already in scope. As you’ll learnlater, you may want to use anInstVisitor
to accomplish this in a much morestraight-forward manner, but this example will allow us to explore how you’d doit if you didn’t haveInstVisitor
around. In pseudo-code, this is what wewant to do:
initialize callCounter to zerofor each Function f in the Module for each BasicBlock b in f for each Instruction i in b if (i a Call and calls the given function) increment callCounter
And the actual code is (remember, because we’re writing aFunctionPass
, ourFunctionPass
-derived class simply has to override therunOnFunction
method):
Function*targetFunc=...;classOurFunctionPass:publicFunctionPass{public:OurFunctionPass():callCounter(0){}virtualrunOnFunction(Function&F){for(BasicBlock&B:F){for(Instruction&I:B){if(auto*CB=dyn_cast<CallBase>(&I)){// We know we've encountered some kind of call instruction (call,// invoke, or callbr), so we need to determine if it's a call to// the function pointed to by m_func or not.if(CB->getCalledFunction()==targetFunc)++callCounter;}}}}private:unsignedcallCounter;};
Iterating over def-use & use-def chains¶
Frequently, we might have an instance of theValue
class (doxygen) and we want to determinewhichUser
s use theValue
. The list of allUser
s of a particularValue
is called adef-use chain. For example, let’s say we have aFunction*
namedF
to a particular functionfoo
. Finding all of theinstructions thatusefoo
is as simple as iterating over thedef-usechain ofF
:
Function*F=...;for(User*U:F->users()){if(Instruction*Inst=dyn_cast<Instruction>(U)){errs()<<"F is used in instruction:\n";errs()<<*Inst<<"\n";}
Alternatively, it’s common to have an instance of theUser
Class (doxygen) and need to know whatValue
s are used by it. The list of allValue
s used by aUser
isknown as ause-def chain. Instances of classInstruction
are commonUser
s, so we might want to iterate over all of the values that a particularinstruction uses (that is, the operands of the particularInstruction
):
Instruction*pi=...;for(Use&U:pi->operands()){Value*v=U.get();// ...}
Declaring objects asconst
is an important tool of enforcing mutation freealgorithms (such as analyses, etc.). For this purpose above iterators come inconstant flavors asValue::const_use_iterator
andValue::const_op_iterator
. They automatically arise when callinguse/op_begin()
onconstValue*
s orconstUser*
s respectively.Upon dereferencing, they returnconstUse*
s. Otherwise the above patternsremain unchanged.
Iterating over predecessors & successors of blocks¶
Iterating over the predecessors and successors of a block is quite easy with theroutines defined in"llvm/IR/CFG.h"
. Just use code like this toiterate over all predecessors of BB:
#include"llvm/IR/CFG.h"BasicBlock*BB=...;for(BasicBlock*Pred:predecessors(BB)){// ...}
Similarly, to iterate over successors usesuccessors
.
Making simple changes¶
There are some primitive transformation operations present in the LLVMinfrastructure that are worth knowing about. When performing transformations,it’s fairly common to manipulate the contents of basic blocks. This sectiondescribes some of the common methods for doing so and gives example code.
Creating and inserting newInstruction
s¶
Instantiating Instructions
Creation ofInstruction
s is straight-forward: simply call the constructorfor the kind of instruction to instantiate and provide the necessary parameters.For example, anAllocaInst
onlyrequires a (const-ptr-to)Type
. Thus:
auto*ai=newAllocaInst(Type::Int32Ty);
will create anAllocaInst
instance that represents the allocation of oneinteger in the current stack frame, at run time. EachInstruction
subclassis likely to have varying default parameters which change the semantics of theinstruction, so refer to thedoxygen documentation for the subclass ofInstruction thatyou’re interested in instantiating.
Naming values
It is very useful to name the values of instructions when you’re able to, asthis facilitates the debugging of your transformations. If you end up lookingat generated LLVM machine code, you definitely want to have logical namesassociated with the results of instructions! By supplying a value for theName
(default) parameter of theInstruction
constructor, you associate alogical name with the result of the instruction’s execution at run time. Forexample, say that I’m writing a transformation that dynamically allocates spacefor an integer on the stack, and that integer is going to be used as some kindof index by some other code. To accomplish this, I place anAllocaInst
atthe first point in the firstBasicBlock
of someFunction
, and I’mintending to use it within the sameFunction
. I might do:
auto*pa=newAllocaInst(Type::Int32Ty,0,"indexLoc");
whereindexLoc
is now the logical name of the instruction’s execution value,which is a pointer to an integer on the run time stack.
Inserting instructions
There are essentially three ways to insert anInstruction
into an existingsequence of instructions that form aBasicBlock
:
Insertion into the instruction list of the
BasicBlock
Given a
BasicBlock*pb
, anInstruction*pi
within thatBasicBlock
,and a newly-created instruction we wish to insert before*pi
, we do thefollowing:BasicBlock*pb=...;Instruction*pi=...;auto*newInst=newInstruction(...);newInst->insertBefore(pi);// Inserts newInst before pi
Appending to the end of a
BasicBlock
is so common that theInstruction
class andInstruction
-derived classes provide constructors which take apointer to aBasicBlock
to be appended to. For example code that lookedlike:BasicBlock*pb=...;auto*newInst=newInstruction(...);newInst->insertInto(pb,pb->end());// Appends newInst to pb
becomes:
BasicBlock*pb=...;auto*newInst=newInstruction(...,pb);
which is much cleaner, especially if you are creating long instructionstreams.
Insertion using an instance of
IRBuilder
Inserting several
Instruction
s can be quite laborious using the previousmethods. TheIRBuilder
is a convenience class that can be used to addseveral instructions to the end of aBasicBlock
or before a particularInstruction
. It also supports constant folding and renaming namedregisters (seeIRBuilder
’s template arguments).The example below demonstrates a very simple use of the
IRBuilder
wherethree instructions are inserted before the instructionpi
. The first twoinstructions are Call instructions and third instruction multiplies the returnvalue of the two calls.Instruction*pi=...;IRBuilder<>Builder(pi);CallInst*callOne=Builder.CreateCall(...);CallInst*callTwo=Builder.CreateCall(...);Value*result=Builder.CreateMul(callOne,callTwo);
The example below is similar to the above example except that the created
IRBuilder
inserts instructions at the end of theBasicBlock
pb
.BasicBlock*pb=...;IRBuilder<>Builder(pb);CallInst*callOne=Builder.CreateCall(...);CallInst*callTwo=Builder.CreateCall(...);Value*result=Builder.CreateMul(callOne,callTwo);
SeeKaleidoscope Tutorial for a practical use of the
IRBuilder
.
Deleting Instructions¶
Deleting an instruction from an existing sequence of instructions that form aBasicBlock is very straight-forward: just call the instruction’seraseFromParent()
method. For example:
Instruction*I=..;I->eraseFromParent();
This unlinks the instruction from its containing basic block and deletes it. Ifyou’d just like to unlink the instruction from its containing basic block butnot delete it, you can use theremoveFromParent()
method.
Replacing an Instruction with another Value¶
Replacing individual instructions¶
Including “llvm/Transforms/Utils/BasicBlockUtils.h” permits use of twovery useful replace functions:ReplaceInstWithValue
andReplaceInstWithInst
.
Deleting Instructions¶
ReplaceInstWithValue
This function replaces all uses of a given instruction with a value, and thenremoves the original instruction. The following example illustrates thereplacement of the result of a particular
AllocaInst
that allocates memoryfor a single integer with a null pointer to an integer.AllocaInst*instToReplace=...;BasicBlock::iteratorii(instToReplace);ReplaceInstWithValue(ii,Constant::getNullValue(PointerType::getUnqual(Type::Int32Ty)));
ReplaceInstWithInst
This function replaces a particular instruction with another instruction,inserting the new instruction into the basic block at the location where theold instruction was, and replacing any uses of the old instruction with thenew instruction. The following example illustrates the replacement of one
AllocaInst
with another.AllocaInst*instToReplace=...;BasicBlock::iteratorii(instToReplace);ReplaceInstWithInst(instToReplace->getParent(),ii,newAllocaInst(Type::Int32Ty,0,"ptrToReplacedInt"));
Replacing multiple uses of Users and Values¶
You can useValue::replaceAllUsesWith
andUser::replaceUsesOfWith
tochange more than one use at a time. See the doxygen documentation for theValue Class andUser Class, respectively, for moreinformation.
Deleting GlobalVariables¶
Deleting a global variable from a module is just as easy as deleting anInstruction. First, you must have a pointer to the global variable that youwish to delete. You use this pointer to erase it from its parent, the module.For example:
GlobalVariable*GV=..;GV->eraseFromParent();
Threads and LLVM¶
This section describes the interaction of the LLVM APIs with multithreading,both on the part of client applications, and in the JIT, in the hostedapplication.
Note that LLVM’s support for multithreading is still relatively young. Upthrough version 2.5, the execution of threaded hosted applications wassupported, but not threaded client access to the APIs. While this use case isnow supported, clientsmust adhere to the guidelines specified below to ensureproper operation in multithreaded mode.
Note that, on Unix-like platforms, LLVM requires the presence of GCC’s atomicintrinsics in order to support threaded operation. If you need amultithreading-capable LLVM on a platform without a suitably modern systemcompiler, consider compiling LLVM and LLVM-GCC in single-threaded mode, andusing the resultant compiler to build a copy of LLVM with multithreadingsupport.
Ending Execution withllvm_shutdown()
¶
When you are done using the LLVM APIs, you should callllvm_shutdown()
todeallocate memory used for internal structures.
Lazy Initialization withManagedStatic
¶
ManagedStatic
is a utility class in LLVM used to implement staticinitialization of static resources, such as the global type tables. In asingle-threaded environment, it implements a simple lazy initialization scheme.When LLVM is compiled with support for multi-threading, however, it usesdouble-checked locking to implement thread-safe lazy initialization.
Achieving Isolation withLLVMContext
¶
LLVMContext
is an opaque class in the LLVM API which clients can use tooperate multiple, isolated instances of LLVM concurrently within the sameaddress space. For instance, in a hypothetical compile-server, the compilationof an individual translation unit is conceptually independent from all theothers, and it would be desirable to be able to compile incoming translationunits concurrently on independent server threads. Fortunately,LLVMContext
exists to enable just this kind of scenario!
Conceptually,LLVMContext
provides isolation. Every LLVM entity(Module
s,Value
s,Type
s,Constant
s, etc.) in LLVM’sin-memory IR belongs to anLLVMContext
. Entities in different contextscannot interact with each other:Module
s in different contexts cannot belinked together,Function
s cannot be added toModule
s in differentcontexts, etc. What this means is that is safe to compile on multiplethreads simultaneously, as long as no two threads operate on entities within thesame context.
In practice, very few places in the API require the explicit specification of aLLVMContext
, other than theType
creation/lookup APIs. Because everyType
carries a reference to its owning context, most other entities candetermine what context they belong to by looking at their ownType
. If youare adding new entities to LLVM IR, please try to maintain this interfacedesign.
Threads and the JIT¶
LLVM’s “eager” JIT compiler is safe to use in threaded programs. Multiplethreads can callExecutionEngine::getPointerToFunction()
orExecutionEngine::runFunction()
concurrently, and multiple threads can runcode output by the JIT concurrently. The user must still ensure that only onethread accesses IR in a givenLLVMContext
while another thread might bemodifying it. One way to do that is to always hold the JIT lock while accessingIR outside the JIT (the JITmodifies the IR by addingCallbackVH
s).Another way is to only callgetPointerToFunction()
from theLLVMContext
’s thread.
When the JIT is configured to compile lazily (usingExecutionEngine::DisableLazyCompilation(false)
), there is currently aracecondition in updating call sitesafter a function is lazily-jitted. It’s still possible to use the lazy JIT in athreaded program if you ensure that only one thread at a time can call anyparticular lazy stub and that the JIT lock guards any IR access, but we suggestusing only the eager JIT in threaded programs.
Advanced Topics¶
This section describes some of the advanced or obscure API’s that most clientsdo not need to be aware of. These API’s tend manage the inner workings of theLLVM system, and only need to be accessed in unusual circumstances.
TheValueSymbolTable
class¶
TheValueSymbolTable
(doxygen) class providesa symbol table that theFunction andModule classes use fornaming value definitions. The symbol table can provide a name for anyValue.
Note that theSymbolTable
class should not be directly accessed by mostclients. It should only be used when iteration over the symbol table namesthemselves are required, which is very special purpose. Note that not all LLVMValues have names, and those without names (i.e. they have an empty name) donot exist in the symbol table.
Symbol tables support iteration over the values in the symbol table withbegin/end/iterator
and supports querying to see if a specific name is in thesymbol table (withlookup
). TheValueSymbolTable
class exposes nopublic mutator methods, instead, simply callsetName
on a value, which willautoinsert it into the appropriate symbol table.
TheUser
and ownedUse
classes’ memory layout¶
TheUser
(doxygen)class provides a basis for expressing the ownership ofUser
towards otherValue instances. TheUse
(doxygen) helperclass is employed to do the bookkeeping and to facilitateO(1) addition andremoval.
Interaction and relationship betweenUser
andUse
objects¶
A subclass ofUser
can choose between incorporating itsUse
objects orrefer to them out-of-line by means of a pointer. A mixed variant (someUse
s inline others hung off) is impractical and breaks the invariant that theUse
objects belonging to the sameUser
form a contiguous array.
We have 2 different layouts in theUser
(sub)classes:
Layout a)
The
Use
object(s) are inside (resp. at fixed offset) of theUser
object and there are a fixed number of them.Layout b)
The
Use
object(s) are referenced by a pointer to an array from theUser
object and there may be a variable number of them.
As of v2.4 each layout still possesses a direct pointer to the start of thearray ofUse
s. Though not mandatory for layout a), we stick to thisredundancy for the sake of simplicity. TheUser
object also stores thenumber ofUse
objects it has. (Theoretically this information can also becalculated given the scheme presented below.)
Special forms of allocation operators (operatornew
) enforce the followingmemory layouts:
Layout a) is modelled by prepending the
User
object by theUse[]
array....---.---.---.---.-------... | P | P | P | P | User'''---'---'---'---'-------'''
Layout b) is modelled by pointing at the
Use[]
array..-------...| User'-------''' | v .---.---.---.---... | P | P | P | P | '---'---'---'---'''
(In the above figures ‘P
’stands for theUse**
that is stored ineachUse
object in the memberUse::Prev
)
Designing Type Hierarchies and Polymorphic Interfaces¶
There are two different design patterns that tend to result in the use ofvirtual dispatch for methods in a type hierarchy in C++ programs. The first isa genuine type hierarchy where different types in the hierarchy modela specific subset of the functionality and semantics, and these types neststrictly within each other. Good examples of this can be seen in theValue
orType
type hierarchies.
A second is the desire to dispatch dynamically across a collection ofpolymorphic interface implementations. This latter use case can be modeled withvirtual dispatch and inheritance by defining an abstract interface base classwhich all implementations derive from and override. However, thisimplementation strategy forces an“is-a” relationship to exist that is notactually meaningful. There is often not some nested hierarchy of usefulgeneralizations which code might interact with and move up and down. Instead,there is a singular interface which is dispatched across a range ofimplementations.
The preferred implementation strategy for the second use case is that ofgeneric programming (sometimes called “compile-time duck typing” or “staticpolymorphism”). For example, a template over some type parameterT
can beinstantiated across any particular implementation that conforms to theinterface orconcept. A good example here is the highly generic properties ofany type which models a node in a directed graph. LLVM models these primarilythrough templates and generic programming. Such templates include theLoopInfoBase
andDominatorTreeBase
. When this type of polymorphismtruly needsdynamic dispatch you can generalize it using a techniquecalledconcept-based polymorphism. This pattern emulates the interfaces andbehaviors of templates using a very limited form of virtual dispatch for typeerasure inside its implementation. You can find examples of this technique inthePassManager.h
system, and there is a more detailed introduction to itby Sean Parent in several of his talks and papers:
Inheritance Is The Base Class of Evil- The GoingNative 2013 talk describing this technique, and probably the bestplace to start.
Value Semantics and Concepts-based Polymorphism - The C++Now! 2012 talkdescribing this technique in more detail.
Sean Parent’s Papers and Presentations- Links to slides, videos, and sometimes code.
When deciding between creating a type hierarchy (with either tagged or virtualdispatch) and using templates or concepts-based polymorphism, consider whetherthere is some refinement of an abstract base class which is a semanticallymeaningful type on an interface boundary. If anything more refined than theroot abstract interface is meaningless to talk about as a partial extension ofthe semantic model, then your use case likely fits better with polymorphism andyou should avoid using virtual dispatch. However, there may be some exigentcircumstances that require one technique or the other to be used.
If you do need to introduce a type hierarchy, we prefer to use explicitlyclosed type hierarchies with manual tagged dispatch and/or RTTI rather than theopen inheritance model and virtual dispatch that is more common in C++ code.This is because LLVM rarely encourages library consumers to extend its coretypes, and leverages the closed and tag-dispatched nature of its hierarchies togenerate significantly more efficient code. We have also found that a largeamount of our usage of type hierarchies fits better with tag-based patternmatching rather than dynamic dispatch across a common interface. Within LLVM wehave built custom helpers to facilitate this design. See this document’ssection onisa and dyn_cast and ourdetailed document which describes how you can implement thispattern for use with the LLVM helpers.
ABI Breaking Checks¶
Checks and asserts that alter the LLVM C++ ABI are predicated on thepreprocessor symbolLLVM_ENABLE_ABI_BREAKING_CHECKS – LLVMlibraries built withLLVM_ENABLE_ABI_BREAKING_CHECKS are not ABIcompatible LLVM libraries built without it defined. By default,turning on assertions also turns onLLVM_ENABLE_ABI_BREAKING_CHECKSso a default +Asserts build is not ABI compatible with adefault -Asserts build. Clients that want ABI compatibilitybetween +Asserts and -Asserts builds should use the CMake build systemto setLLVM_ENABLE_ABI_BREAKING_CHECKS independentlyofLLVM_ENABLE_ASSERTIONS.
The Core LLVM Class Hierarchy Reference¶
#include"llvm/IR/Type.h"
header source:Type.h
doxygen info:Type Classes
The Core LLVM classes are the primary means of representing the program beinginspected or transformed. The core LLVM classes are defined in header files intheinclude/llvm/IR
directory, and implemented in thelib/IR
directory. It’s worth noting that, for historical reasons, this library iscalledlibLLVMCore.so
, notlibLLVMIR.so
as you might expect.
The Type class and Derived Types¶
Type
is a superclass of all type classes. EveryValue
has aType
.Type
cannot be instantiated directly but only through its subclasses.Certain primitive types (VoidType
,LabelType
,FloatType
andDoubleType
) have hidden subclasses. They are hidden because they offer nouseful functionality beyond what theType
class offers except to distinguishthemselves from other subclasses ofType
.
All other types are subclasses ofDerivedType
. Types can be named, but thisis not a requirement. There exists exactly one instance of a given shape at anyone time. This allows type equality to be performed with address equality ofthe Type Instance. That is, given twoType*
values, the types are identicalif the pointers are identical.
Important Public Methods¶
boolisIntegerTy()const
: Returns true for any integer type.boolisFloatingPointTy()
: Return true if this is one of the fivefloating point types.boolisSized()
: Return true if the type has known size. Thingsthat don’t have a size are abstract types, labels and void.
Important Derived Types¶
IntegerType
Subclass of DerivedType that represents integer types of any bit width. Anybit width between
IntegerType::MIN_INT_BITS
(1) andIntegerType::MAX_INT_BITS
(~8 million) can be represented.staticconstIntegerType*get(unsignedNumBits)
: get an integertype of a specific bit width.unsignedgetBitWidth()const
: Get the bit width of an integer type.
SequentialType
This is subclassed by ArrayType and VectorType.
constType*getElementType()const
: Returns the type of eachof the elements in the sequential type.uint64_tgetNumElements()const
: Returns the number of elementsin the sequential type.
ArrayType
This is a subclass of SequentialType and defines the interface for arraytypes.
PointerType
Subclass of Type for pointer types.
VectorType
Subclass of SequentialType for vector types. A vector type is similar to anArrayType but is distinguished because it is a first class type whereasArrayType is not. Vector types are used for vector operations and are usuallysmall vectors of an integer or floating point type.
StructType
Subclass of DerivedTypes for struct types.
FunctionType
Subclass of DerivedTypes for function types.
boolisVarArg()const
: Returns true if it’s a vararg function.constType*getReturnType()const
: Returns the return type of thefunction.constType*getParamType(unsignedi)
: Returns the type of the ithparameter.constunsignedgetNumParams()const
: Returns the number of formalparameters.
TheModule
class¶
#include"llvm/IR/Module.h"
header source:Module.h
doxygen info:Module Class
TheModule
class represents the top level structure present in LLVMprograms. An LLVM module is effectively either a translation unit of theoriginal program or a combination of several translation units merged by thelinker. TheModule
class keeps track of a list ofFunctions, a list ofGlobalVariables, and aSymbolTable.Additionally, it contains a few helpful member functions that try to make commonoperations easy.
Important Public Members of theModule
class¶
Module::Module(std::stringname="")
Constructing aModule is easy. You can optionally provide a name for it(probably based on the name of the translation unit).
Module::iterator
- Typedef for function list iteratorModule::const_iterator
- Typedef for const_iterator.begin()
,end()
,size()
,empty()
These are forwarding methods that make it easy to access the contents of a
Module
object’sFunction list.Module::FunctionListType&getFunctionList()
Returns the list ofFunctions. This is necessary to usewhen you need to update the list or perform a complex action that doesn’t havea forwarding method.
Module::global_iterator
- Typedef for global variable list iteratorModule::const_global_iterator
- Typedef for const_iterator.Module::insertGlobalVariable()
- Inserts a global variable to the list.Module::removeGlobalVariable()
- Removes a global variable from the list.Module::eraseGlobalVariable()
- Removes a global variable from the list and deletes it.global_begin()
,global_end()
,global_size()
,global_empty()
These are forwarding methods that make it easy to access the contents of a
Module
object’sGlobalVariable list.
SymbolTable*getSymbolTable()
Return a reference to theSymbolTable for this
Module
.
Function*getFunction(StringRefName)const
Look up the specified function in the
Module
SymbolTable. If it does notexist, returnnull
.FunctionCalleegetOrInsertFunction(conststd::string&Name,constFunctionType*T)
Look up the specified function in the
Module
SymbolTable. Ifit does not exist, add an external declaration for the function andreturn it. Note that the function signature already present may notmatch the requested signature. Thus, in order to enable the commonusage of passing the result directly to EmitCall, the return type isa struct of{FunctionType*T,Constant*FunctionPtr}
, ratherthan simply theFunction*
with potentially an unexpectedsignature.std::stringgetTypeName(constType*Ty)
If there is at least one entry in theSymbolTable for the specifiedType,return it. Otherwise return the empty string.
booladdTypeName(conststd::string&Name,constType*Ty)
Insert an entry in theSymbolTable mapping
Name
toTy
. If there isalready an entry for this name, true is returned and theSymbolTable is notmodified.
TheValue
class¶
#include"llvm/IR/Value.h"
header source:Value.h
doxygen info:Value Class
TheValue
class is the most important class in the LLVM Source base. Itrepresents a typed value that may be used (among other things) as an operand toan instruction. There are many different types ofValue
s, such asConstants,Arguments. EvenInstructions andFunctions areValue
s.
A particularValue
may be used many times in the LLVM representation for aprogram. For example, an incoming argument to a function (represented with aninstance of theArgument class) is “used” by every instruction in the functionthat references the argument. To keep track of this relationship, theValue
class keeps a list of all of theUser
s that is using it (theUser classis a base class for all nodes in the LLVM graph that can refer toValue
s).This use list is how LLVM represents def-use information in the program, and isaccessible through theuse_*
methods, shown below.
Because LLVM is a typed representation, every LLVMValue
is typed, and thisType is available through thegetType()
method. In addition, all LLVMvalues can be named. The “name” of theValue
is a symbolic string printedin the LLVM code:
%foo=addi321,2
The name of this instruction is “foo”.NOTE that the name of any value maybe missing (an empty string), so names shouldONLY be used for debugging(making the source code easier to read, debugging printouts), they should not beused to keep track of values or map between them. For this purpose, use astd::map
of pointers to theValue
itself instead.
One important aspect of LLVM is that there is no distinction between an SSAvariable and the operation that produces it. Because of this, any reference tothe value produced by an instruction (or the value available as an incomingargument, for example) is represented as a direct pointer to the instance of theclass that represents this value. Although this may take some getting used to,it simplifies the representation and makes it easier to manipulate.
Important Public Members of theValue
class¶
Value::use_iterator
- Typedef for iterator over the use-listValue::const_use_iterator
- Typedef for const_iterator over theuse-listunsigneduse_size()
- Returns the number of users of the value.booluse_empty()
- Returns true if there are no users.use_iteratoruse_begin()
- Get an iterator to the start of theuse-list.use_iteratoruse_end()
- Get an iterator to the end of the use-list.User*use_back()
- Returns the last element in the list.These methods are the interface to access the def-use information in LLVM.As with all other iterators in LLVM, the naming conventions follow theconventions defined by theSTL.
Type*getType()const
This method returns the Type of the Value.boolhasName()const
std::stringgetName()const
voidsetName(conststd::string&Name)
This family of methods is used to access and assign a name to a
Value
, beaware of theprecaution above.voidreplaceAllUsesWith(Value*V)
This method traverses the use list of a
Value
changing allUsers of thecurrent value to refer to “V
” instead. For example, if you detect that aninstruction always produces a constant value (for example through constantfolding), you can replace all uses of the instruction with the constant likethis:Inst->replaceAllUsesWith(ConstVal);
TheUser
class¶
#include"llvm/IR/User.h"
header source:User.h
doxygen info:User Class
Superclass:Value
TheUser
class is the common base class of all LLVM nodes that may refer toValue
s. It exposes a list of “Operands” that are all of theValue
sthat the User is referring to. TheUser
class itself is a subclass ofValue
.
The operands of aUser
point directly to the LLVMValue
that it refersto. Because LLVM uses Static Single Assignment (SSA) form, there can only beone definition referred to, allowing this direct connection. This connectionprovides the use-def information in LLVM.
Important Public Members of theUser
class¶
TheUser
class exposes the operand list in two ways: through an index accessinterface and through an iterator based interface.
Value*getOperand(unsignedi)
unsignedgetNumOperands()
These two methods expose the operands of the
User
in a convenient form fordirect access.User::op_iterator
- Typedef for iterator over the operand listop_iteratorop_begin()
- Get an iterator to the start of the operandlist.op_iteratorop_end()
- Get an iterator to the end of the operand list.Together, these methods make up the iterator based interface to the operandsof a
User
.
TheInstruction
class¶
#include"llvm/IR/Instruction.h"
header source:Instruction.h
doxygen info:Instruction Class
TheInstruction
class is the common base class for all LLVM instructions.It provides only a few methods, but is a very commonly used class. The primarydata tracked by theInstruction
class itself is the opcode (instructiontype) and the parentBasicBlock theInstruction
is embedded into. Torepresent a specific type of instruction, one of many subclasses ofInstruction
are used.
Because theInstruction
class subclasses theUser class, its operands canbe accessed in the same way as for otherUser
s (with thegetOperand()
/getNumOperands()
andop_begin()
/op_end()
methods).An important file for theInstruction
class is thellvm/Instruction.def
file. This file contains some meta-data about the various different types ofinstructions in LLVM. It describes the enum values that are used as opcodes(for exampleInstruction::Add
andInstruction::ICmp
), as well as theconcrete sub-classes ofInstruction
that implement the instruction (forexampleBinaryOperator andCmpInst). Unfortunately, the use of macros in thisfile confuses doxygen, so these enum values don’t show up correctly in thedoxygen output.
Important Subclasses of theInstruction
class¶
BinaryOperator
This subclasses represents all two operand instructions whose operands must bethe same type, except for the comparison instructions.
CastInst
This subclass is the parent of the 12 casting instructions. It providescommon operations on cast instructions.
Important Public Members of theInstruction
class¶
BasicBlock*getParent()
Returns theBasicBlock that this
Instruction
is embedded into.boolmayWriteToMemory()
Returns true if the instruction writes to memory, i.e. it is a
call
,free
,invoke
, orstore
.unsignedgetOpcode()
Returns the opcode for the
Instruction
.Instruction*clone()const
Returns another instance of the specified instruction, identical in all waysto the original except that the instruction has no parent (i.e. it’s notembedded into aBasicBlock), and it has no name.
TheConstant
class and subclasses¶
Constant represents a base class for different types of constants. It issubclassed by ConstantInt, ConstantArray, etc. for representing the varioustypes of Constants.GlobalValue is also a subclass, which represents theaddress of a global variable or function.
Important Subclasses of Constant¶
ConstantInt : This subclass of Constant represents an integer constant ofany width.
constAPInt&getValue()const
: Returns the underlyingvalue of this constant, an APInt value.int64_tgetSExtValue()const
: Converts the underlying APInt value to anint64_t via sign extension. If the value (not the bit width) of the APIntis too large to fit in an int64_t, an assertion will result. For thisreason, use of this method is discouraged.uint64_tgetZExtValue()const
: Converts the underlying APInt valueto a uint64_t via zero extension. IF the value (not the bit width) of theAPInt is too large to fit in a uint64_t, an assertion will result. For thisreason, use of this method is discouraged.staticConstantInt*get(constAPInt&Val)
: Returns the ConstantIntobject that represents the value provided byVal
. The type is impliedas the IntegerType that corresponds to the bit width ofVal
.staticConstantInt*get(constType*Ty,uint64_tVal)
: Returns theConstantInt object that represents the value provided byVal
for integertypeTy
.
ConstantFP : This class represents a floating point constant.
doublegetValue()const
: Returns the underlying value of this constant.
ConstantArray : This represents a constant array.
conststd::vector<Use>&getValues()const
: Returns a vector ofcomponent constants that makeup this array.
ConstantStruct : This represents a constant struct.
conststd::vector<Use>&getValues()const
: Returns a vector ofcomponent constants that makeup this array.
GlobalValue : This represents either a global variable or a function. Ineither case, the value is a constant fixed address (after linking).
TheGlobalValue
class¶
#include"llvm/IR/GlobalValue.h"
header source:GlobalValue.h
doxygen info:GlobalValue Class
Superclasses:Constant,User,Value
Global values (GlobalVariables orFunctions) are theonly LLVM values that are visible in the bodies of allFunctions. Because they are visible at global scope, they are alsosubject to linking with other globals defined in different translation units.To control the linking process,GlobalValue
s know their linkage rules.Specifically,GlobalValue
s know whether they have internal or externallinkage, as defined by theLinkageTypes
enumeration.
If aGlobalValue
has internal linkage (equivalent to beingstatic
in C),it is not visible to code outside the current translation unit, and does notparticipate in linking. If it has external linkage, it is visible to externalcode, and does participate in linking. In addition to linkage information,GlobalValue
s keep track of whichModule they are currently part of.
BecauseGlobalValue
s are memory objects, they are always referred to bytheiraddress. As such, theType of a global is always a pointer to itscontents. It is important to remember this when using theGetElementPtrInst
instruction because this pointer must be dereferenced first. For example, ifyou have aGlobalVariable
(a subclass ofGlobalValue)
that is an arrayof 24 ints, type[24xi32]
, then theGlobalVariable
is a pointer tothat array. Although the address of the first element of this array and thevalue of theGlobalVariable
are the same, they have different types. TheGlobalVariable
’s type is[24xi32]
. The first element’s type isi32.
Because of this, accessing a global value requires you to dereferencethe pointer withGetElementPtrInst
first, then its elements can be accessed.This is explained in theLLVM Language Reference Manual.
Important Public Members of theGlobalValue
class¶
boolhasInternalLinkage()const
boolhasExternalLinkage()const
voidsetInternalLinkage(boolHasInternalLinkage)
These methods manipulate the linkage characteristics of the
GlobalValue
.Module*getParent()
This returns theModule that theGlobalValue is currently embedded into.
TheFunction
class¶
#include"llvm/IR/Function.h"
header source:Function.h
doxygen info:Function Class
Superclasses:GlobalValue,Constant,User,Value
TheFunction
class represents a single procedure in LLVM. It is actuallyone of the more complex classes in the LLVM hierarchy because it must keep trackof a large amount of data. TheFunction
class keeps track of a list ofBasicBlocks, a list of formalArguments, and aSymbolTable.
The list ofBasicBlocks is the most commonly used part ofFunction
objects. The list imposes an implicit ordering of the blocks in the function,which indicate how the code will be laid out by the backend. Additionally, thefirstBasicBlock is the implicit entry node for theFunction
. It is notlegal in LLVM to explicitly branch to this initial block. There are no implicitexit nodes, and in fact there may be multiple exit nodes from a singleFunction
. If theBasicBlock list is empty, this indicates that theFunction
is actually a function declaration: the actual body of the functionhasn’t been linked in yet.
In addition to a list ofBasicBlocks, theFunction
class also keeps trackof the list of formalArguments that the function receives. This containermanages the lifetime of theArgument nodes, just like theBasicBlock list doesfor theBasicBlocks.
TheSymbolTable is a very rarely used LLVM feature that is only used when youhave to look up a value by name. Aside from that, theSymbolTable is usedinternally to make sure that there are not conflicts between the names ofInstructions,BasicBlocks, orArguments in the function body.
Note thatFunction
is aGlobalValue and therefore also aConstant. Thevalue of the function is its address (after linking) which is guaranteed to beconstant.
Important Public Members of theFunction
¶
Function(constFunctionType*Ty,LinkageTypesLinkage,conststd::string&N="",Module*Parent=0)
Constructor used when you need to create new
Function
s to add theprogram. The constructor must specify the type of the function to create andwhat type of linkage the function should have. TheFunctionType argumentspecifies the formal arguments and return value for the function. The sameFunctionType value can be used to create multiple functions. TheParent
argument specifies the Module in which the function is defined. If thisargument is provided, the function will automatically be inserted into thatmodule’s list of functions.boolisDeclaration()
Return whether or not the
Function
has a body defined. If the function is“external”, it does not have a body, and thus must be resolved by linking witha function defined in a different translation unit.Function::iterator
- Typedef for basic block list iteratorFunction::const_iterator
- Typedef for const_iterator.begin()
,end()
,size()
,empty()
,insert()
,splice()
,erase()
These are forwarding methods that make it easy to access the contents of a
Function
object’sBasicBlock list.Function::arg_iterator
- Typedef for the argument list iteratorFunction::const_arg_iterator
- Typedef for const_iterator.arg_begin()
,arg_end()
,arg_size()
,arg_empty()
These are forwarding methods that make it easy to access the contents of a
Function
object’sArgument list.Function::ArgumentListType&getArgumentList()
Returns the list ofArgument. This is necessary to use when you need toupdate the list or perform a complex action that doesn’t have a forwardingmethod.
BasicBlock&getEntryBlock()
Returns the entry
BasicBlock
for the function. Because the entry blockfor the function is always the first block, this returns the first block oftheFunction
.Type*getReturnType()
FunctionType*getFunctionType()
This traverses theType of the
Function
and returns the return type ofthe function, or theFunctionType of the actual function.SymbolTable*getSymbolTable()
Return a pointer to theSymbolTable for this
Function
.
TheGlobalVariable
class¶
#include"llvm/IR/GlobalVariable.h"
header source:GlobalVariable.h
doxygen info:GlobalVariable Class
Superclasses:GlobalValue,Constant,User,Value
Global variables are represented with the (surprise surprise)GlobalVariable
class. Like functions,GlobalVariable
s are also subclasses ofGlobalValue, and as such are always referenced by their address (global valuesmust live in memory, so their “name” refers to their constant address). SeeGlobalValue for more on this. Global variables may have an initial value(which must be aConstant), and if they have an initializer, they may be markedas “constant” themselves (indicating that their contents never change atruntime).
Important Public Members of theGlobalVariable
class¶
GlobalVariable(constType*Ty,boolisConstant,LinkageTypes&Linkage,Constant*Initializer=0,conststd::string&Name="",Module*Parent=0)
Create a new global variable of the specified type. If
isConstant
is truethen the global variable will be marked as unchanging for the program. TheLinkage parameter specifies the type of linkage (internal, external, weak,linkonce, appending) for the variable. If the linkage is InternalLinkage,WeakAnyLinkage, WeakODRLinkage, LinkOnceAnyLinkage or LinkOnceODRLinkage, thenthe resultant global variable will have internal linkage. AppendingLinkageconcatenates together all instances (in different translation units) of thevariable into a single variable but is only applicable to arrays. See theLLVM Language Reference for further detailson linkage types. Optionally an initializer, a name, and the module to putthe variable into may be specified for the global variable as well.boolisConstant()const
Returns true if this is a global variable that is known not to be modified atruntime.
boolhasInitializer()
Returns true if this
GlobalVariable
has an initializer.Constant*getInitializer()
Returns the initial value for a
GlobalVariable
. It is not legal to callthis method if there is no initializer.
TheBasicBlock
class¶
#include"llvm/IR/BasicBlock.h"
header source:BasicBlock.h
doxygen info:BasicBlock Class
Superclass:Value
This class represents a single entry single exit section of the code, commonlyknown as a basic block by the compiler community. TheBasicBlock
classmaintains a list ofInstructions, which form the body of the block. Matchingthe language definition, the last element of this list of instructions is alwaysa terminator instruction.
In addition to tracking the list of instructions that make up the block, theBasicBlock
class also keeps track of theFunction thatit is embedded into.
Note thatBasicBlock
s themselves areValues, because they arereferenced by instructions like branches and can go in the switch tables.BasicBlock
s have typelabel
.
Important Public Members of theBasicBlock
class¶
BasicBlock(conststd::string&Name="",Function*Parent=0)
The
BasicBlock
constructor is used to create new basic blocks forinsertion into a function. The constructor optionally takes a name for thenew block, and aFunction to insert it into. If theParent
parameter is specified, the newBasicBlock
is automaticallyinserted at the end of the specifiedFunction, if notspecified, the BasicBlock must be manually inserted into theFunction.BasicBlock::iterator
- Typedef for instruction list iteratorBasicBlock::const_iterator
- Typedef for const_iterator.begin()
,end()
,front()
,back()
,size()
,empty()
,splice()
STL-style functions for accessing the instruction list.These methods and typedefs are forwarding functions that have the samesemantics as the standard library methods of the same names. These methodsexpose the underlying instruction list of a basic block in a way that is easyto manipulate.
Function*getParent()
Returns a pointer toFunction the block is embedded into,or a null pointer if it is homeless.
Instruction*getTerminator()
Returns a pointer to the terminator instruction that appears at the end of the
BasicBlock
. If there is no terminator instruction, or if the lastinstruction in the block is not a terminator, then a null pointer is returned.
TheArgument
class¶
This subclass of Value defines the interface for incoming formal arguments to afunction. A Function maintains a list of its formal arguments. An argument hasa pointer to the parent Function.