i'm starting to learn llvm api and i wrote my first pass.
My goal is to print how functions call each others.
Lately i wanted to add some loop information to the display to look if a function can be call several time or not. But when i try to use LoopInfo i got this compilation error :
llvm[0]: Compiling cfg.cpp for Debug+Asserts build (PIC)
In file included from cfg.cpp:19:
In file included from /home/llvm-lab/llvm/include/llvm/Pass.h:378:
/home/llvm-lab/llvm/include/llvm/PassAnalysisSupport.h:56:37: error:
no member named 'ID' in 'llvm::LoopInfo'
return addRequiredID(PassClass::ID);
^
cfg.cpp:33:10: note: in instantiation of function template
specialization 'llvm::AnalysisUsage::addRequired<llvm::LoopInfo>'
requested here
AU.addRequired<LoopInfo>();
^
1 error generated.
Here is my code :
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "iostream"
#include "llvm/Pass.h"
#include "llvm/IR/InstIterator.h"
#include <llvm/IR/Instructions.h>
#include <llvm/Analysis/LoopInfo.h>
using namespace llvm;
namespace {
struct CFG : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
CFG() : FunctionPass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.addRequired<LoopInfo>();
}
bool runOnFunction(Function &F) override {
errs().write_escaped(F.getName());
errs() << " : ";
for( Function::iterator b = F.begin() , be = F.end(); b != be; ++b){
errs() << "\n\t BB : ";
LoopInfo *loop = new LoopInfo();
bool isLoop = loop->getLoopFor(b);
if(isLoop){
errs() << "loop{";
}
for(BasicBlock::iterator i = b->begin() , ie = b->end(); i!=ie; ++i){
if( isa<CallInst>(&(*i)) || isa<InvokeInst>(&(*i))){
errs() << cast<CallInst>(&(*i))->getCalledFunction()->getName() << "\t";
}
}
if(isLoop){
errs() << "}";
}
}
errs() << '\n';
return false;
}
};
}
char CFG::ID = 0;
static RegisterPass<CFG> X("CFG", "Gen CFG",true ,true);
I can't find any reference to an "no member named 'ID' in 'llvm::LoopInfo'" error anywhere, does anyone have an idea about what's is wrong here ?
Why your code could not be build
AU.addRequired<typename passclass>() need a type of LLMV::Pass, however what you pass in is LoopInfo, which is just an LLVM internal class for loop information maintenance. It does not has a field ID.
LoopInfoWrapperPass should be used instead
If you want to get the loop information. Try to change it to AU.addRequired<LoopInfoWrapperPass> as shown in the LLVM Write a new Pass document. LoopInfoWrapperPass is used to generate LoopInfo.
LoopInfo should be get from the pass
There is also a problem in your code about how to get the LoopInfo, you are trying to use new to create a LoopInfo, what you get will be an empty LoopInfo.
The "should work" code for your question
Following is a modified version of your code, which could printout expected informations.
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Function.h"
#include "llvm/Support/raw_ostream.h"
#include "iostream"
#include "llvm/Pass.h"
#include "llvm/IR/InstIterator.h"
#include <llvm/IR/Instructions.h>
#include <llvm/Analysis/LoopInfo.h>
using namespace llvm;
namespace {
struct CFG : public FunctionPass {
static char ID; // Pass identification, replacement for typeid
CFG() : FunctionPass(ID) {}
void getAnalysisUsage(AnalysisUsage &AU) const override {
AU.setPreservesCFG();
AU.addRequired<LoopInfoWrapperPass>();
}
bool runOnFunction(Function &F) override {
LoopInfo &LI = getAnalysis<LoopInfoWrapperPass>().getLoopInfo();
errs().write_escaped(F.getName());
errs() << " : ";
for( Function::iterator b = F.begin() , be = F.end(); b != be; ++b){
errs() << "\n\t BB : ";
bool isLoop = LI.getLoopFor(b);
if(isLoop){
errs() << "loop{";
}
for(BasicBlock::iterator i = b->begin() , ie = b->end(); i!=ie; ++i){
if( isa<CallInst>(&(*i)) || isa<InvokeInst>(&(*i))){
errs() << cast<CallInst>(&(*i))->getCalledFunction()->getName() << "\t";
}
}
if(isLoop){
errs() << "}";
}
}
errs() << '\n';
return false;
}
};
}
char CFG::ID = 0;
static RegisterPass<CFG> X("CFG", "Gen CFG",true ,true);
For the following code feed to LLVM opt:
#include <stdio.h>
#define ARRAY_SIZE 100
int foo(int* a , int n) {
int i;
int sum = 0;
for (; i < n; i++) {
sum += a[i];
}
return sum;
}
int main() {
int a[ARRAY_SIZE] = {1};
int sum = foo(a, ARRAY_SIZE);
printf("sum:0x%x\n", sum);
return 0;
}
The output will be:
foo :
BB :
BB : loop{}
BB : loop{}
BB : loop{}
BB :
main :
BB : llvm.memset.p0i8.i64 foo printf
Related
Maybe it's my sinuses and that I fact that I just started learning about smart pointers today I'm trying to do the following:
Push to the queue
Get the element in the front
Pop the element (I think it will automatically deque once the address out of scope)
Here is the error
main.cpp:50:25: error: cannot convert ‘std::remove_reference&>::type’ {aka ‘std::unique_ptr’} to ‘std::unique_ptr*’ in assignment
50 | inputFrame = std::move(PacketQueue.front());
| ~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~
| |
| std::remove_reference<std::unique_ptr<MyObject::Packet>&>::type {aka std::unique_ptr<MyObject::Packet>}
Here is the code
#include <iostream>
#include <memory>
#include <queue>
using namespace std;
class MyObject
{
public:
struct Packet
{
uint8_t message;
uint8_t index;
};
void pushToQueue(void);
void FrontOfQueue(std::unique_ptr<Packet> *inputFrame);
private:
std::queue<std::unique_ptr<Packet>> PacketQueue;
};
void MyObject::pushToQueue(void)
{
Packet frame;
static int counter = 1;
frame.message = counter;
frame.index =counter;
counter++;
std::unique_ptr<Packet> passthru_ptr = std::make_unique<Packet>(std::move(frame));
PacketQueue.push(std::move(passthru_ptr));
cout<<"Pushed to queue\n" ;
}
void MyObject::FrontOfQueue(std::unique_ptr<Packet> *inputFrame)
{
inputFrame = std::move(PacketQueue.front());
}
int main()
{
cout<<"Hello World\n";
MyObject object;
object.pushToQueue();
object.pushToQueue();
{
// Scope
std::unique_ptr<MyObject::Packet> *frame;
object.FrontOfQueue(frame);
cout<< frame << endl;
}
{
// Scope
std::unique_ptr<MyObject::Packet> *frame2;
object.FrontOfQueue(frame2);
cout<< frame2 << endl;
}
return 0;
}
Link to the code (Online Compiler)
If I got your aim correctly, you definitely want
std::unique_ptr<MyObject::Packet> MyObject::FrontOfQueue()
{
auto rv = std::move(PacketQueue.front());
PacketQueue.pop();
return rv;
}
// ...
std::unique_ptr<MyObject::Packet> frame = object.FrontOfQueue();
Notice, no raw pointers are used.
I think it will automatically deque once the address out of scope.
This assumption is wrong. Nothing is dequeued until .pop() is called.
Here is my example with some extra logging to show whats going on.
includes an introduction of returning const references as well.
Live demo : https://onlinegdb.com/P2nFkdMy0
#include <iostream>
#include <memory>
#include <queue>
#include <string>
//-----------------------------------------------------------------------------
// do NOT use : using namespace std;
//-----------------------------------------------------------------------------
struct Packet
{
// moved to uint32_t for std::cout reasons.
// uint8_t is displayed as(special) characters
std::uint32_t index;
std::uint32_t message;
Packet() :
index{ next_index() },
message{ index }
{
std::cout << "created packet : " << index << "\n";
}
~Packet()
{
std::cout << "destroyed packet : " << index << "\n";
}
// small helper to not have to declare the static variable seperatly
static std::uint8_t next_index()
{
static int counter;
return counter++;
}
};
//-----------------------------------------------------------------------------
class MyObject
{
public:
void push_packet();
std::unique_ptr<Packet> pop_packet();
// this function returns a const reference (observation only)
// of the packet at the front of the queue
// while leaving the unique pointer on the queue (no moves needed
// packet will still be owned by the queue)
const Packet& front();
private:
std::queue<std::unique_ptr<Packet>> m_queue;
};
void MyObject::push_packet()
{
std::cout << "push_packet\n";
// push a packet
m_queue.push(std::make_unique<Packet>());
std::cout << "push_packet done...\n";
}
std::unique_ptr<Packet> MyObject::pop_packet()
{
std::unique_ptr<Packet> packet = std::move(m_queue.front());
m_queue.pop();
return packet;
}
const Packet& MyObject::front()
{
return *m_queue.front();
}
//-----------------------------------------------------------------------------
int main()
{
const std::size_t n_packets = 3ul;
MyObject object;
for (std::size_t n = 0; n < n_packets; ++n)
{
std::cout << "pushing packet\n";
object.push_packet();
}
for (std::size_t n = 0; n < n_packets; ++n)
{
std::cout << "packet at front : ";
std::cout << object.front().index << "\n";
std::cout << "popping front\n";
auto packet_ptr = object.pop_packet();
std::cout << "popped packet : " << packet_ptr->index << "\n";
}
return 0;
}
I'm new to using hash tables (AFAIK unordered_multimap is a hash table) and I'm trying to insert a struct in it using a function. My code:
Nod.h
#pragma once
#include <iostream>
#include <unordered_map>
struct nod {
int stare[100], pathManhattan, depth;
nod* nodParinte;
char actiune;
nod();
void Citire(int n);
void Init(std::unordered_multimap<int, nod*> hashTable);
};
Nod.cpp
#include "Nod.h"
#include <unordered_map>
nod::nod()
{
pathManhattan = 0;
depth = 0;
nodParinte = NULL;
}
void nod::Citire(int n)
{
for (int i = 0; i < n*n; i++)
{
std::cin >> stare[i];
}
}
void nod::Init(std::unordered_multimap<int, nod*> hashTable)
{
hashTable.insert({ pathManhattan + depth, this });
hashTable.empty() ? std::cout << "da" : std::cout << "nu";
}
Consoleapplication.cpp
#include <iostream>
#include <string>
#include <unordered_map>
#include "Nod.h"
std::unordered_multimap<int, nod*> theExplored;
std::unordered_multimap<int, nod*> theFrontier;
int main()
{
nod nodInitial; int n, t[1000];
nodInitial.Init(theExplored);
theExplored.empty() ? std::cout << "da" : std::cout << "nu";
return 0;
}
This line from Init
hashTable.empty() ? std::cout << "da" : std::cout << "nu";
returns false
while this line from Consoleapplication.cpp returns true
theExplored.empty() ? std::cout << "da" : std::cout << "nu";
and I don't understand why.
Can anybody explain this to me?
I wanted to make a function inside the struct which would insert the specific variable of type nod into theExplored hash table, with an int as a key, but I don't know how to do it - I thought this might be the appropiate approach, but it seems like it isn't.
void nod::Init(std::unordered_multimap<int, nod*> hashTable)
This takes it's parameter by value. That means it makes a copy and only modifies this local copy. The original map remains unchanged. Pass by reference instead:
void nod::Init(std::unordered_multimap<int, nod*> &hashTable)
// ~^~
I am trying to implement observer design pattern in C++ as below
#include <iostream>
#include <vector>
using namespace std;
class observer
{
public:
observer() = default;
~observer() = default;
virtual void notify() = 0;
};
class subject
{
vector <observer *> vec;
public:
subject() = default;
~subject() = default;
void _register(observer *obj)
{
vec.push_back(obj);
}
void unregister(observer *obj)
{
int i;
for(i = 0; i < vec.size(); i++)
{
if(vec[i] == obj)
{
cout << "found elem. unregistering" << endl;
vec.erase(vec.begin() + i);
break;
}
}
if(i == vec.size())
{
cout << "elem not found to unregister" << endl;
}
}
void notify()
{
vector <observer *>::iterator it = vec.begin();
while(it != vec.end())
{
(*it)->notify();
it ++;
}
}
};
class obsone : public observer
{
void notify()
{
cout << "in obsone notify" << endl;
}
};
class obstwo : public observer
{
void notify()
{
cout << "in obstwo notify" << endl;
}
};
int main()
{
subject sub;
obsone *one = new obsone();
obstwo *two = new obstwo();
sub._register(one);
sub._register(two);
sub.notify();
sub.unregister(one);
sub.notify();
//delete two;
//sub.notify();
return 0;
}
I am registering the objects with the subject explicitly. Is it the correct way of doing it or do I need to register through observer class only. Are there any problems with the above approach?
Here's an example of doing the callbacks with lambdas and function objects in the callback collection.
The details can vary greatly! So, this code is not “the” way, but just your code rewritten in one specific way, out of a myriad possibilities. But it hopefully shows the general idea in modern C++.
#include <iostream>
#include <functional> // std::function
#include <stdint.h> // uint64_t
#include <unordered_map> // std::unordered_map
#include <utility> // std::move
#include <vector> // std::vector
using namespace std;
namespace my
{
using Callback = function<void()>;
template< class Key, class Value > using Map_ = unordered_map<Key, Value>;
class Subject
{
public:
enum Id: uint64_t {};
private:
Map_<uint64_t, Callback> m_callbacks;
static auto id_value()
-> uint64_t&
{
static uint64_t the_id;
return the_id;
}
public:
auto add_listener( Callback cb )
-> Id
{
const auto id = Id( ++id_value() );
m_callbacks.emplace( id, move( cb ) );
return id;
}
auto remove_listener( const Id id )
-> bool
{
const auto it = m_callbacks.find( id );
if( it == m_callbacks.end() )
{
return false;
}
m_callbacks.erase( it );
return true;
}
void notify_all() const
{
for( const auto& pair : m_callbacks )
{
pair.second();
}
}
};
}
struct Observer_1
{
void notify() { cout << "Observer_1::notify() called." << endl; }
};
struct Observer_2
{
void notify() { cout << "Observer_2::notify() called." << endl; }
};
auto main()
-> int
{
my::Subject subject;
Observer_1 one;
Observer_2 two;
using Id = my::Subject::Id;
const Id listener_id_1 = subject.add_listener( [&]{ one.notify(); } );
const Id listener_id_2 = subject.add_listener( [&]{ two.notify(); } );
cout << "After adding two listeners:" << endl;
subject.notify_all();
cout << endl;
subject.remove_listener( listener_id_1 )
and (cout << "Removed listener 1." << endl)
or (cout << "Did not find registration of listener 1." << endl);
cout << endl;
cout << "After removing or attempting to remove listener 1:" << endl;
subject.notify_all();
}
#include "json.hpp"
#include <memory>
#include <vector>
#include <iostream>
struct json_node;
using json_node_ptr = std::shared_ptr<json_node>;
struct json_node
{
int id;
std::vector<json_node_ptr> children;
json_node(int _id)
: id{ _id }
{
}
};
void to_json(nlohmann::json& j, const json_node_ptr& node)
{
j = {{"ID", node->id}};
if (!node->children.empty()) {
j.push_back( nlohmann::json {"children", node->children});
//j["children"] = node->children;
}
}
int main()
{
}
I am getting the following error. How do I resolve this? What is the problem behind it?
Any easy workaround? It is not easy to change client library.
error: no matching function for call to ‘basic_json<>::push_back(<brace-enclosed initializer list>)’
j.push_back( {"children", node->children} );
Header file is here: https://github.com/nlohmann/json/blob/v2.0.10/src/json.hpp
UPDATE: THIS PROBLEM OCCURS WITH OLDER VERSIONS OF THE LIBRARY. IT IS
FIXED IN LATEST VERSION.
Here the code that converts the struct to string and then parses string back to json object
#include <vector>
#include <string>
#include <iostream>
#include <sstream>
#include <string>
#include "json.hpp"
struct json_node;
using json_node_ptr = std::shared_ptr<json_node>;
struct json_node
{
int id;
std::vector<json_node_ptr> children;
json_node(int _id)
: id{ _id }
{
}
std::ostringstream& print(std::ostringstream& ss) const
{
ss << "{\"ID\" :" << id ;
if (children.size() > 0) {
ss << ", \"children\" : [";
std::string prefix = "";
for (auto& ch : children) {
ss << prefix;
ch->print(ss);
prefix = ", ";
}
ss << "]";
}
ss << "}";
return ss;
};
};
std::ostringstream& operator<<(std::ostringstream& ss,const json_node & node)
{
return node.print(ss);
}
void to_json(nlohmann::json& j, const json_node_ptr& node)
{
std::ostringstream ss;
ss << *node;
std::string str = ss.str();
j = nlohmann::json::parse(str);
}
int main()
{
json_node_ptr p = std::make_shared<json_node>(1);
json_node_ptr child_1 = std::make_shared<json_node>(2);
p->children.push_back(child_1);
json_node_ptr child_2 = std::make_shared<json_node>(3);
json_node_ptr child_3 = std::make_shared<json_node>(4);
child_2->children.push_back(child_3);
p->children.push_back(child_2);
nlohmann::json j;
to_json(j, p);
std::cout << j << '\n';
nlohmann::json j1 = nlohmann::json::array();
j1.push_back(j);
j1.push_back(p);
std::cout << j1 << "\n";
}
Output
{"ID":1,"children":[{"ID":2},{"ID":3,"children":[{"ID":4}]}]}
Here is another vesion of the to_json - that does not use to string serialization
void to_json(nlohmann::json& j, const json_node_ptr& node)
{
j["ID"] = node->id;
if (node->children.size() > 0)
{
j["children"] = nlohmann::json::array();
for (auto& ch : node->children)
{
nlohmann::json j_child;
to_json(j_child, ch);
j["children"].push_back(j_child);
}
}
}
I have sth like this:
User.idl:
#ifndef __USER_IDL__
#define __USER_IDL__
interface Group;
interface User
{
typedef sequence<Group> Groups;
Groups getGroups();
void setGroups(in Groups g);
};
#endif
UserImpl.h and UserImpl.cpp:
class UserImpl : public POA_User
{
private :
User::Groups groups;
public :
User::Groups* getGroups();
void setGroups(const ::User::Groups& g);
};
#endif
#include "UserImpl.h"
User::Groups* UserImpl::getGroups()
{
return &(this->groups);
}
void UserImpl::setGroups(const ::User::Groups& g)
{
this->groups.length(g.length());
for(int i=0; i<g.length(); i++)
{
this->groups[i] = this->groups[i];
}
}
And Group.idl:
#ifndef __GROUP_IDL__
#define __GROUP_IDL__
#include "User.idl"
interface Group
{
typedef sequence<User> Users;
User getFounder();
void setFounder(in User u);
Users getUsers();
void setUsers(in Users u);
};
#endif
GroupImpl.h, GroupImpl.cpp:
class UserImpl;
class GroupImpl : public POA_Group
{
private :
UserImpl *founder;
Group::Users members;
public :
User_ptr getFounder();
void setFounder(::User_ptr u);
Group::Users* getUsers();
void setUsers(const ::Group::Users& u);
};
User_ptr GroupImpl::getFounder()
{
return this->founder->_this();
}
void GroupImpl::setFounder(::User_ptr u)
{
}
Group::Users* GroupImpl::getUsers()
{
}
void GroupImpl::setUsers(const ::Group::Users& u)
{
}
The question I got here: did I do it right? I mean, is everything ok with this code? I still learn how to write in CORBA and sometimes have doubts especially if it comes to sequences...
The second question: how do I properly set group's founder and get and set group's members?
I mean, I would like to do sth like this in my main file:
#include "UserImpl.h"
#include "GroupImpl.h"
#include <omniORB4/CORBA.h>
#include <omniORB4/Naming.hh>
#include <iostream>
using std::cout;
using std::cerr;
int main(int argc, char **argv)
{
UserImpl u;
u.setLogin("yak");
u.setID(123);
cout << u.getLogin() << "\n";
cout << u.getID() << "\n";
cout << u.toString() << "\n";
GroupImpl **g = new GroupImpl*[1];
for(int i=0; i<1; i++)
{
g[i] = new GroupImpl();
}
u.setGroups(g);
return 0;
}
Please, help:) I use omniORB and C++ language
Ok I think I figured out how to write an implementation of getGroups and getUsers:
User::Groups* UserImpl::getGroups()
{
const size_t size = this->groups.size();
User::Groups_var seqOfObjects = new User::Groups(size);
seqOfObjects->length(size);
size_t i = 0;
vector<GroupImpl*>::const_iterator it = groups.begin();
while (it != groups.end())
{
seqOfObjects[i] = Group::_duplicate((*it)->_this());
++it;
++i;
}
return seqOfObjects._retn();
}
Is that right? But I still have problems with setUsers and setGroups implementations.