Easiest way to evaluate constant SVal - c++

I'm trying to find the easiest way to get the value in a constant SVal. Currently I am doing something along the lines of:
SVal s = ...; // Get valid SVal from somewhere
int64_t val = 0; // Will hold value of SVal
if (!s.isUnknownOrUndef() && s.isConstant()) {
switch (s.getBaseKind()) {
case NonLocKind: {
s_val = s.getAs<nonloc::ConcreteInt>().getValue();
val = s_val.getValue().getExtValue();
}
// handle other cases
// ...
}
}
llvm::outs() << "Value is " << val << "\n";
I didn't show it here but there more code checking that values are known, checking the sign and type of constants, etc. I feel like there is probably a better way.

Related

Make compiler assume that all cases are handled in switch without default

Let's start with some code. This is an extremely simplified version of my program.
#include <stdint.h>
volatile uint16_t dummyColorRecepient;
void updateColor(const uint8_t iteration)
{
uint16_t colorData;
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
case 2:
colorData = 345;
break;
}
dummyColorRecepient = colorData;
}
// dummy main function
int main()
{
uint8_t iteration = 0;
while (true)
{
updateColor(iteration);
if (++iteration == 3)
iteration = 0;
}
}
The program compiles with a warning:
./test.cpp: In function ‘void updateColor(uint8_t)’:
./test.cpp:20:25: warning: ‘colorData’ may be used uninitialized in this function [-Wmaybe-uninitialized]
dummyColorRecepient = colorData;
~~~~~~~~~~~~~~~~~~~~^~~~~~~~~~~
As you can see, there is an absolute certainty that the variable iteration is always 0, 1 or 2. However, the compiler doesn't know that and it assumes that switch may not initialize colorData. (Any amount of static analysis during compilation won't help here because the real program is spread over multiple files.)
Of course I could just add a default statement, like default: colorData = 0; but this adds additional 24 bytes to the program. This is a program for a microcontroller and I have very strict limits for its size.
I would like to inform the compiler that this switch is guaranteed to cover all possible values of iteration.
As you can see, there is an absolute certainty that the variable iteration is always 0, 1 or 2.
From the perspective of the toolchain, this is not true. You can call this function from someplace else, even from another translation unit. The only place that your constraint is enforced is in main, and even there it's done in a such a way that might be difficult for the compiler to reason about.
For our purposes, though, let's take as read that you're not going to link any other translation units, and that we want to tell the toolchain about that. Well, fortunately, we can!
If you don't mind being unportable, then there's GCC's __builtin_unreachable built-in to inform it that the default case is not expected to be reached, and should be considered unreachable. My GCC is smart enough to know that this means colorData is never going to be left uninitialised unless all bets are off anyway.
#include <stdint.h>
volatile uint16_t dummyColorRecepient;
void updateColor(const uint8_t iteration)
{
uint16_t colorData;
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
case 2:
colorData = 345;
break;
// Comment out this default case to get the warnings back!
default:
__builtin_unreachable();
}
dummyColorRecepient = colorData;
}
// dummy main function
int main()
{
uint8_t iteration = 0;
while (true)
{
updateColor(iteration);
if (++iteration == 3)
iteration = 0;
}
}
(live demo)
This won't add an actual default branch, because there's no "code" inside it. In fact, when I plugged this into Godbolt using x86_64 GCC with -O2, the program was smaller with this addition than without it — logically, you've just added a major optimisation hint.
There's actually a proposal to make this a standard attribute in C++ so it could be an even more attractive solution in the future.
Use the "immediately invoked lambda expression" idiom and an assert:
void updateColor(const uint8_t iteration)
{
const auto colorData = [&]() -> uint16_t
{
switch(iteration)
{
case 0: return 123;
case 1: return 234;
}
assert(iteration == 2);
return 345;
}();
dummyColorRecepient = colorData;
}
The lambda expression allows you to mark colorData as const. const variables must always be initialized.
The combination of assert + return statements allows you to avoid warnings and handle all possible cases.
assert doesn't get compiled in release mode, preventing overhead.
You can also factor out the function:
uint16_t getColorData(const uint8_t iteration)
{
switch(iteration)
{
case 0: return 123;
case 1: return 234;
}
assert(iteration == 2);
return 345;
}
void updateColor(const uint8_t iteration)
{
const uint16_t colorData = getColorData(iteration);
dummyColorRecepient = colorData;
}
You can get this to compile without warnings simply by adding a default label to one of the cases:
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
case 2: default:
colorData = 345;
break;
}
Alternatively:
uint16_t colorData = 345;
switch(iteration)
{
case 0:
colorData = 123;
break;
case 1:
colorData = 234;
break;
}
Try both, and use the shorter of the two.
I know there have been some good solutions, but alternatively If your values are going to be known at compile time, instead of a switch statement you can use constexpr with a static function template and a couple of enumerators; it would look something like this within a single class:
#include <iostream>
class ColorInfo {
public:
enum ColorRecipient {
CR_0 = 0,
CR_1,
CR_2
};
enum ColorType {
CT_0 = 123,
CT_1 = 234,
CT_2 = 345
};
template<const uint8_t Iter>
static constexpr uint16_t updateColor() {
if constexpr (Iter == CR_0) {
std::cout << "ColorData updated to: " << CT_0 << '\n';
return CT_0;
}
if constexpr (Iter == CR_1) {
std::cout << "ColorData updated to: " << CT_1 << '\n';
return CT_1;
}
if constexpr (Iter == CR_2) {
std::cout << "ColorData updated to: " << CT_2 << '\n';
return CT_2;
}
}
};
int main() {
const uint16_t colorRecipient0 = ColorInfo::updateColor<ColorInfo::CR_0>();
const uint16_t colorRecipient1 = ColorInfo::updateColor<ColorInfo::CR_1>();
const uint16_t colorRecipient2 = ColorInfo::updateColor<ColorInfo::CR_2>();
std::cout << "\n--------------------------------\n";
std::cout << "Recipient0: " << colorRecipient0 << '\n'
<< "Recipient1: " << colorRecipient1 << '\n'
<< "Recipient2: " << colorRecipient2 << '\n';
return 0;
}
The cout statements within the if constexpr are only added for testing purposes, but this should illustrate another possible way to do this without having to use a switch statement provided your values will be known at compile time. If these values are generated at runtime I'm not completely sure if there is a way to use constexpr to achieve this type of code structure, but if there is I'd appreciate it if someone else with a little more experience could elaborate on how this could be done with constexpr using runtime values. However, this code is very readable as there are no magic numbers and the code is quite expressive.
-Update-
After reading more about constexpr it has come to my attention that they can be used to generate compile time constants. I also learned that they can not generate runtime constants but they can be used within a runtime function. We can take the above class structure and use it within a runtime function as such by adding this static function to the class:
static uint16_t colorUpdater(const uint8_t input) {
// Don't forget to offset input due to std::cin with ASCII value.
if ( (input - '0') == CR_0)
return updateColor<CR_0>();
if ( (input - '0') == CR_1)
return updateColor<CR_1>();
if ( (input - '0') == CR_2)
return updateColor<CR_2>();
return updateColor<CR_2>(); // Return the default type
}
However I want to change the naming conventions of the two functions. The first function I will name colorUpdater() and this new function that I just shown above I will name it updateColor() as it seems more intuitive this way. So the updated class will now look like this:
class ColorInfo {
public:
enum ColorRecipient {
CR_0 = 0,
CR_1,
CR_2
};
enum ColorType {
CT_0 = 123,
CT_1 = 234,
CT_2 = 345
};
static uint16_t updateColor(uint8_t input) {
if ( (input - '0') == CR_0 ) {
return colorUpdater<CR_0>();
}
if ( (input - '0') == CR_1 ) {
return colorUpdater<CR_1>();
}
if ( (input - '0') == CR_2 ) {
return colorUpdater<CR_2>();
}
return colorUpdater<CR_0>(); // Return the default type
}
template<const uint8_t Iter>
static constexpr uint16_t colorUpdater() {
if constexpr (Iter == CR_0) {
std::cout << "ColorData updated to: " << CT_0 << '\n';
return CT_0;
}
if constexpr (Iter == CR_1) {
std::cout << "ColorData updated to: " << CT_1 << '\n';
return CT_1;
}
if constexpr (Iter == CR_2) {
std::cout << "ColorData updated to: " << CT_2 << '\n';
return CT_2;
}
}
};
If you want to use this with compile time constants only you can use it just as before but with the function's updated name.
#include <iostream>
int main() {
auto output0 = ColorInfo::colorUpdater<ColorInfo::CR_0>();
auto output1 = ColorInfo::colorUpdater<ColorInfo::CR_1>();
auto output2 = ColorInfo::colorUpdater<ColorInfo::CR_2>();
std::cout << "\n--------------------------------\n";
std::cout << "Recipient0: " << output0 << '\n'
<< "Recipient1: " << output1 << '\n'
<< "Recipient2: " << output2 << '\n';
return 0;
}
And if you want to use this mechanism with runtime values you can simply do the following:
int main() {
uint8_t input;
std::cout << "Please enter input value [0,2]\n";
std::cin >> input;
auto output = ColorInfo::updateColor(input);
std::cout << "Output: " << output << '\n';
return 0;
}
And this will work with runtime values.
Well, if you are sure you won't have to handle other possible values, you can just use arithmetic. Gets rid of he branching and the load.
void updateColor(const uint8_t iteration)
{
dummyColorRecepient = 123 + 111 * iteration;
}
I'm going to extend the Lightness Races in Orbit's answer.
The code I'm using currently is:
#ifdef __GNUC__
__builtin_unreachable();
#else
__assume(false);
#endif
__builtin_unreachable() works in GCC and Clang but not MSVC. I used __GNUC__ to check whether it is one of the first two (or another compatible compiler) and used __assume(false) for MSVC instead.

C++ using 1 function for multiple varaibles. Only first run works

Newish to C++ but been researching alot so please bear with me.
I've been trying to use 1 function to relate 8 global double variables [ mA mB ... mG which ranges from values 1 to 10] to another double value.
I first obtain these 8 variables by obtaining the data from a csv file, throwing them to an array and then equating the set global variables. This all works fine. I cout the values correctly.
mA =10, mB=1 ,.... mG=2
However I need to use these variables to relate to another set value. So i Use:
double Function1(double Mvalue1)
{
if (Mvalue1 == 1) { double value = 10; return value ; }
if (Mvalue1 == 2) { double value = 20; return value ; }
.... // cont to 10 only increasing value by 10
if (Mvalue1 == 10) { double value = 110; return value ; }
}
void VarFunction()
{
mA2= Function1(mA); **//SHOULD output 110**
cout << "Vaule A " << mA2 << endl;
mB2= Function1(mB); **//SHOULD output 10**
cout << "Vaule B " << mB2 << endl;
....//.... 8 times
mG2 = Function1(mG); **//SHOULD output 20**
cout << "Vaule G " << mG2 << endl;
}
int main()
{
VarFunction()
return 0;
}
So the output i get here is
Value A 110
Value B -1.#IND
....
Value G -1.#IND
Why isnt the next call of function1 with the next variable not working?
In your code you have mA set to 12, but Function1 doesn't have a case for 12. So, I'm surprised you're even getting 110 printed for the first line. You aren't handling the case inside Function1 where Mvalue1 isn't one of the desired values, so this is the first thing to fix.
Also, assigning a number to a double and then returning it is unnecessarily complicated. A case statement would work well, assuming you really want to pass integers:
double Function1(int Mvalue1)
{
switch(Mvalue1) {
case 1: return 10;
case 2: return 20;
//...
case 10: return 110; // are you sure you don't want 100?
default: return -1; // handle the case here so that you always return a value.
}
}
Of course, if you really just want 10 times your input, why not:
double Function1(double mValue1)
{
return mValue1*10;
}
Not all paths in your function return a defined value, i.e. there's no return statement after all the conditionals.
The compiler is probably telling you that. If not - compile with higher warning level.
Use the std::map container when building relationships like this.
#include <iostream>
#include <map>
typedef std::map<double, double> rel_t;
int main()
{
rel_t mymap;
// You can directly
// std::map<double, double> mymap;
mymap[1] = 10;
mymap[2] = 20;
mymap[10] = 110;
std::cout << mymap[1] << std::endl; // Prints 10
std::cout << mymap[2] << std::endl; // Prints 20
std::cout << mymap[10] << std::endl; // Prints 110
}
This program seems to be working for me when I run it. However, I had to add declarations for mA2, mB2, and mG2 in your VarFunction(). You're also missing a semicolon after your call to VarFunction() in main().
I'd also suggest you return some default double in the function double Function(double Mvalue1), just in case Mvalue1 does not satisfy any of the if statements.
As already said, Function1() should return a value in case all if statements are false!
If the numbers your are dealing with have no fractional digits, use short, int, long or any other integer type for the variables. Then you can use a switch()/case construct or keep on using the comparison operator ==.
In case you must deal with floating point values, never use the == operator! When reading floating point values from text files (like CSV) or a database, a conversion from text to float/double is done. The result from such conversion can end in e.g. 9.999999999 or 10.000000001 instead of 10. And then the comparison with == is false!
To compare two double variables use a method like this:
bool dEqual( double dVal1, double dVal2, double dTolerance)
{
if( fabs( dVar1 - dVar2) < dTolerance) {
// dVar1 is nearly equal to dVar2
return true;
}
// dVar1 is not equal to dVar2
return false;
}
Then this comparison is true:
if( dEqual( 10.0, 9.999999998, 0.000001))
Apply a value for tolerance that meets the accuracy you need.

How to use boost::optional

I am trying to use boost::optional as below.
#include <iostream>
#include <string>
#include <boost/optional.hpp>
struct myClass
{
int myInt;
void setInt(int input) { myInt = input; }
int getInt(){return myInt; }
};
boost::optional<myClass> func(const std::string &str)
{
boost::optional<myClass> value;
if(str.length() > 5)
{
// If greater than 5 length string. Set value to 10
value.get().setInt(10);
}
else if (str.length() < 5)
{
// Else set it to 0
value.get().setInt(0);
}
else
{
// If it is 5 set the value to 5
value.get().setInt(5);
}
return value;
}
int main()
{
boost::optional<myClass> v1 = func("3124");
boost::optional<myClass> v2 = func("helloWorld");
boost::optional<myClass> v3 = func("hello");
if (v1)
std::cout << "v1 is valid" << std::endl;
else
std::cout << "v1 is not valid" << std::endl;
if (v2)
std::cout << "v2 is valid" << std::endl;
else
std::cout << "v3 is not valid" << std::endl;
if (v3)
std::cout << "v3 is valid" << std::endl;
else
std::cout << "v3 is not valid" << std::endl;
return 0;
}
I get following error
prog.exe:
/usr/local/boost-1.55.0/include/boost/optional/optional.hpp:631:
boost::optional::reference_type boost::optional::get() [with T =
myClass; boost::optional::reference_type = myClass&]: Assertion
`this->is_initialized()' failed.
Presumably, the optional variable is not initialized properly. How to do it the correct way?
EDIT:: Got some very good answers, just couple of more questions 1. Is it a good idea to use make_optional at the end of 'func' function and return it? Also 2. I was thinking of assigning boost::none to emphasize that I have no value to assign and that's why boost::none. But not sure if that is valid?
A default-constructed boost::optional is empty - it does not contain a value, so you can't call get() on it. You have to initialise it with a valid value:
boost::optional<myClass> value = myClass();
Alternatively, you can use an in-place factory to avoid copy initialisation (but the copy will most likely be elided anyway); however, I have no experience with that, so I can't provide an example.
As a side note, you can use -> in place of get(), like this:
value->setInt(10);
But that's just a matter of stylistic preference, both are equally valid.
How to do it the correct way?
boost::optional<myClass> func(const std::string &str)
{
if(str.length() > 5)
return myClass{10};
if(str.length() < 5)
return myClass{0};
return myClass{5};
}
As a side note, this code doesn't need boost::optional, because there is no code branch that returns an empty object (it is semantically equivalent to returning a myClass instance).
To return an empty optional, use this:
boost::optional<myClass> func(const std::string &str)
{
if(str.length() > 5)
return myClass{10};
if(str.length() < 5)
return myClass{0};
return boost::none; // return empty object
}
Idiomatic client code (don't pre-initialize your values):
int main()
{
if (auto v1 = func("3214"))
// use *v1 to access value
std::cout << "v1 is valid" << std::endl;
else
std::cout << "v1 is not valid" << std::endl;
return 0;
}
Two easy approaches:
boost::optional<myClass> func(const std::string &str)
{
boost::optional<myClass> value;
if(str.length() > 5) // If greater than 5 length string. Set value to 10
value = 10;
else if (str.length() < 5) // Else set it to 0
value = 0;
else // If it is 5 set the value to 5
value = 5;
return value;
}
boost::optional<myClass> func(const std::string &str)
{
if(str.length() > 5) // If greater than 5 length string. Set value to 10
return 10;
else if (str.length() < 5) // Else set it to 0
return 0;
else // If it is 5 set the value to 5
return 5;
}
note that returning an optional from a function that never returns an empty optional is a bad idea.
optional behaves like a pointer on read access -- you can only read the value from it if you have already verified there is something there to read. You can check if there is something to read by doing bool something_to_read = opt;.
You can, however, write to it whenever. If there is nothing there, it creates something. If there is something there, it overwrites it.
.get() is a reading, not a writing, operation. (it "reads" the reference) It is only safe to use when the optional is engaged and has data. Confusingly, you can write to the "read access" .get() return value, as it is a non-const reference.
So maybe "read" and "write" are bad words to use. :)
It is sometimes helpful to think of optional as a value-and-pointer mixed together. There is a possibly null pointer to an owned buffer of memory that may, or may not hold a copy of the type.
If the pointer inside the optional is null, then the buffer is uninitialized. If it points at the buffer, then the buffer is initialized.
.get() dereferences that pointer and returns the resulting reference without checking. = checks the pointer, if it is null, it does a copy-construct from the rhs into the buffer and sets the pointer. If not, it just assigns to the buffer.
(The pointer is conceptual: usually implemented as a bool flag).
I find using *optional to be better than optional.get(), as the "you must check before you dereference" is more obvious with the dereference operator.
boost::optional<myClass> func(const std::string &str)
{
boost::optional<myClass> value; //not init is invalid
if(str.length() > 5) // If greater than 5 length string. Set value to 10
value = 10;
else if (str.length() < 5) // Else set it to 0
value = 0;
return value;
}
v1 is valid
v2 is valid
v3 is not valid
according to boost,optional default ctor will create an optional obj as invalid
optional<T> def ; //not initalize with a obj T
assert ( !def ) ;

How to find out shared variables among functions by using LLVM API?

Recently I used LLVM API to test C++ program. Now I want to find out the shared variables among different functions, is there any way to do that? It seems that the AliasAnalysis doesn't work!
I write a Function Pass as following:
bool EscapeAnalysis::runOnFunction(Function& F) {
EscapePoints.clear();
TargetData& TD = getAnalysis<TargetData>();
AliasAnalysis& AA = getAnalysis<AliasAnalysis>();
Module* M = F.getParent();
// errs() << *M << "\n";
// Walk through all instructions in the function, identifying those that
// may allow their inputs to escape.
for(inst_iterator II = inst_begin(F), IE = inst_end(F); II != IE; ++II) {
Instruction* I = &*II;
// The most obvious case is stores. Any store that may write to global
// memory or to a function argument potentially allows its input to escape.
if (StoreInst* S = dyn_cast<StoreInst>(I)) {
Type* StoreType = S->getOperand(0)->getType();
unsigned StoreSize = TD.getTypeStoreSize(StoreType);
Value* Pointer = S->getPointerOperand();
bool inserted = false;
for (Function::arg_iterator AI = F.arg_begin(), AE = F.arg_end();
AI != AE; ++AI) {
if (!isa<PointerType>(AI->getType())) continue;
AliasAnalysis::AliasResult R = AA.alias(Pointer, StoreSize, AI, ~0UL);
if (R != AliasAnalysis::NoAlias) {
EscapePoints.insert(S);
inserted = true;
break;
}
}
if (inserted)
continue;
for (Module::global_iterator GI = M->global_begin(), GE = M->global_end();
GI != GE; ++GI) {
errs() << *GI << "\n";
AliasAnalysis::AliasResult R = AA.alias(Pointer, StoreSize, GI, ~0UL);
errs() << "R: " << R << " , NoAlias: " << AliasAnalysis::NoAlias << "\n";
if (R != AliasAnalysis::NoAlias) {
EscapePoints.insert(S);
break;
}
}
// Calls and invokes potentially allow their parameters to escape.
// FIXME: This can and should be refined. Intrinsics have known escape
// behavior, and alias analysis may be able to tell us more about callees.
} else if (isa<CallInst>(I) || isa<InvokeInst>(I)) {
EscapePoints.insert(I);
// Returns allow the return value to escape. This is mostly important
// for malloc to alloca promotion.
} else if (isa<ReturnInst>(I)) {
EscapePoints.insert(I);
// Branching on the value of a pointer may allow the value to escape through
// methods not discoverable via def-use chaining.
} else if(isa<BranchInst>(I) || isa<SwitchInst>(I)) {
EscapePoints.insert(I);
}
// FIXME: Are there any other possible escape points?
}
return false;
}
Test the main.cpp as following:
#include
using namespace std;
int X = 0;
int foo() {
X = 1;
int b = 1;
return 0;
}
int bar(int param) {
int y = X;
int z = 9;
int a = z;
++a;
return 0;
}
int main(int argc, char *argv[])
{
cout << "Hello world!" << endl;
return 0;
}
the global variable X is the shared variable between function bar and function foo.
But when I use the command as following to run the pass:
opt -load ./EscapeAnalysis.so -escape-analysis main.o | llc > main.ss
I get the result:
R: 1 , NoAlias: 0
all result are the same.
I print out the variables in escapePoint, find that variable a, z, y in function bar are in escapePoint. It is not right!
Note: I write a opt pass to test program.
Alias analysis is required if you want to identify when two different variables might point to the same memory. If you just want to check which variables are shared with other functions in the same module, you can:
Iterate over all instructions, and for each:
Iterate over all its operands, and for each:
Check whether it's a GlobalVariable (via isa, for instance), and if so:
Iterate over all the global's uses (via use_begin and use_end), and for each:
Check whether it's an Instruction, and if so:
Retrieve the enclosing function (via getParent()->getParent()), and for that function:
Check whether it is the currently-processed function. If not, it means you found a variable shared between the current function and another function.
There are also other ways of checking this, for example going over all the globals in the current module.

Modern equivalent of LLVM AnnotationManager?

Now that LLVM's AnnotationManager is gone (it disappeared in the 2.6 release, I think?), how can I get the annotations for specific functions, globals, and instructions?
(For example, I have bitcode compiled from C void myFunction(__attribute__((annotate("foo"))) int var) --- given an Argument * reference to this int var argument, how might I determine which annotate attributes are attached to it?)
To get annotations for a specific function, traverse the entry BasicBlock of the function to find its calls to the #llvm.var.annotation intrinsic, as follows:
Module *module;
[...]
std::string getGlobalVariableString(std::string name)
{
// assumption: the zeroth operand of a Value::GlobalVariableVal is the actual Value
Value *v = module->getNamedValue(name)->getOperand(0);
if(v->getValueID() == Value::ConstantArrayVal)
{
ConstantArray *ca = (ConstantArray *)v;
return ca->getAsString();
}
return "";
}
void dumpFunctionArgAnnotations(std::string funcName)
{
std::map<Value *,Argument*> mapValueToArgument;
Function *func = module->getFunction(funcName);
if(!func)
{
std::cout << "no function by that name.\n";
return;
}
std::cout << funcName << "() ====================\n";
// assumption: #llvm.var.annotation calls are always in the function's entry block.
BasicBlock *b = &func->getEntryBlock();
// run through entry block first to build map of pointers to arguments
for(BasicBlock::iterator it = b->begin();it!=b->end();++it)
{
Instruction *inst = it;
if(inst->getOpcode()!=Instruction::Store)
continue;
// `store` operands: http://llvm.org/docs/LangRef.html#i_store
mapValueToArgument[inst->getOperand(1)] = (Argument *)inst->getOperand(0);
}
// run through entry block a second time, to associate annotations with arguments
for(BasicBlock::iterator it = b->begin();it!=b->end();++it)
{
Instruction *inst = it;
if(inst->getOpcode()!=Instruction::Call)
continue;
// assumption: Instruction::Call's operands are the function arguments, followed by the function name
Value *calledFunction = inst->getOperand(inst->getNumOperands()-1);
if(calledFunction->getName().str() != "llvm.var.annotation")
continue;
// `llvm.var.annotation` operands: http://llvm.org/docs/LangRef.html#int_var_annotation
Value *annotatedValue = inst->getOperand(0);
if(annotatedValue->getValueID() != Value::InstructionVal + Instruction::BitCast)
continue;
Argument *a = mapValueToArgument[annotatedValue->getUnderlyingObject()];
if(!a)
continue;
Value *annotation = inst->getOperand(1);
if(annotation->getValueID() != Value::ConstantExprVal)
continue;
ConstantExpr *ce = (ConstantExpr *)annotation;
if(ce->getOpcode() != Instruction::GetElementPtr)
continue;
// `ConstantExpr` operands: http://llvm.org/docs/LangRef.html#constantexprs
Value *gv = ce->getOperand(0);
if(gv->getValueID() != Value::GlobalVariableVal)
continue;
std::cout << " argument " << a->getType()->getDescription() << " " << a->getName().str()
<< " has annotation \"" << getGlobalVariableString(gv->getName().str()) << "\"\n";
}
}
AnnotationManager was deleted because it was useless (and it won't solve your problem). All the annotations are handled via the global named 'llvm.global.annotations' and annotation intrinsics, which you can surely parse and obtain the information you needed.
Look into IR to have an idea, how your C code was transformed into IR and what annotation attribute was turned into.