I am trying to get all the predecessor basic blocks from an IR file not during a pass. I can iterate over all the basic blocks using
for (auto iter1 = m->getFunctionList().begin();
iter1 != m->getFunctionList().end();
iter1++)
{
for (auto iter2 = f.getBasicBlockList().begin();
iter2 != f.getBasicBlockList().end();
iter2++)
{
BasicBlock &bb = *iter2;
std::cout << " BasicBlock: " << bb.getName().str() << std::endl;
}
}
However, when I add for (BasicBlock *Pred : pred_iterator(bb)) {} from this link, I get an error
for (auto iter1 = m->getFunctionList().begin();
iter1 != m->getFunctionList().end();
iter1++)
{
for (auto iter2 = f.getBasicBlockList().begin();
iter2 != f.getBasicBlockList().end();
iter2++)
{
BasicBlock &bb = *iter2;
std::cout << " BasicBlock: " << bb.getName().str() << std::endl;
for (BasicBlock *Pred : pred_iterator(bb)) {}
}
}
The errors are shown below
test2.cpp:63:37: error: no matching conversion for functional-style cast from 'llvm::BasicBlock' to 'pred_iterator' (aka 'PredIterator<llvm::BasicBlock, user_iterator_impl<llvm::User> >')
for (BasicBlock *Pred : pred_iterator(bb)) {
^~~~~~~~~~~~~~~~
Here is some additional Information:
/usr/local/include/llvm/IR/CFG.h:48:19: note: candidate constructor not viable: no known conversion from 'llvm::BasicBlock' to 'llvm::BasicBlock *' for 1st argument; take the address of the
argument with &
explicit inline PredIterator(Ptr *bb) : It(bb->user_begin()) {
^
Additional Informatino is below.
/usr/local/include/llvm/IR/CFG.h:30:7: note: candidate constructor (the implicit copy constructor) not viable: no known conversion from 'llvm::BasicBlock' to 'const
llvm::PredIterator<llvm::BasicBlock, llvm::Value::user_iterator_impl<llvm::User> >' for 1st argument
class PredIterator : public std::iterator<std::forward_iterator_tag,
^
/usr/local/include/llvm/IR/CFG.h:30:7: note: candidate constructor (the implicit move constructor) not viable: no known conversion from 'llvm::BasicBlock' to
'llvm::PredIterator<llvm::BasicBlock, llvm::Value::user_iterator_impl<llvm::User> >' for 1st argument
/usr/local/include/llvm/IR/CFG.h:47:3: note: candidate constructor not viable: requires 0 arguments, but 1 was provided
PredIterator() {}
^
/usr/local/include/llvm/IR/CFG.h:51:10: note: candidate constructor not viable: requires 2 arguments, but 1 was provided
inline PredIterator(Ptr *bb, bool) : It(bb->user_end()) {}
How do I convert from 'llvm::BasicBlock' to a 'pred_iterator'?
As shown in the error message you posted, pred_iterator constructor takes BasicBlock*, not BasicBlock&.
The other problem with your example is that in order to iterate with a range-based loop, you need a range, not an iterator. You should use a helper called llvm::predecessors for that.
Fixing these errors, we arrive at the following:
for (BasicBlock *Pred : predecessors(&bb)) {}
Related
Here is a code snippet I have :
struct PairHasher {
size_t operator()(const std::pair<std::string_view, std::string_view>& stop_stop) const {
return hasher(stop_stop.first) + 37*hasher(stop_stop.second);
}
std::hash<std::string_view> hasher;
};
BOOST_FIXTURE_TEST_CASE(unordered_map_string_view_pair_must_be_ok, TestCaseStartStopMessager)
{
const std::vector<std::string> from_stops = {"from_0", "from_1", "from_2"};
const std::vector<std::string> to_stops = {"to_0", "to_1", "to_2"};
std::unordered_map<std::pair<std::string_view, std::string_view>, std::int32_t, TransportCatalogue::PairHasher> distance_between_stops;
for ( std::size_t idx = 0; idx < from_stops.size(); ++idx) {
std::cout << from_stops[idx] << " : " << to_stops[idx] << std::endl;
distance_between_stops[std::pair(from_stops[idx], to_stops[idx])] = idx;
}
std::cout << "MAP CONTENT :" << std::endl;
for (auto const& x : distance_between_stops)
{
std::cout << x.first.first << " : " << x.first.second << std::endl;
}
}
I expect to see 3 pairs inside the container, but there is only 1 concerning to the output :
MAP CONTENT :
from_2 : to_2
So, where are two more pair lost? What am I doing wrong?
Moving my comment to an answer.
This is pretty sneaky. I noticed in Compiler Explorer that changing:
distance_between_stops[std::pair(from_stops[idx], to_stops[idx])] = idx;
to
distance_between_stops[std::pair(std::string_view{from_stops[idx]}, std::string_view{to_stops[idx]})] = idx;
fixes the bug. This hints that the problem lies in some implicit string -> string_view conversion. And indeed that is the case, but it is hidden behind one extra layer.
std::pair(from_stops[idx], to_stops[idx]) creates a std::pair<std::string, std::string>, but distance_between_stops requires a std::pair<std::string_view, std::string_view>. When we insert values into the map, this conversion happens implicitly via overload #5 here:
template <class U1, class U2>
constexpr pair(pair<U1, U2>&& p);
Initializes first with std::forward<U1>(p.first) and second with std::forward<U2>(p.second).
This constructor participates in overload resolution if and only if std::is_constructible_v<first_type, U1&&> and std::is_constructible_v<second_type, U2&&> are both true.
This constructor is explicit if and only if std::is_convertible_v<U1&&, first_type> is false or std::is_convertible_v<U2&&, second_type> is false.
(For reference, std::is_constructible_v<std::string_view, std::string&&> and std::is_convertible_v<std::string&&, std::string_view> are both true, so we know this overload is viable and implicit.)
See the problem yet? When we use the map's operator[], it has to do an implicit conversion to create a key with the proper type. This implicit conversion constructs a pair of string_views that are viewing the temporary memory from the local pair of strings, not the underlying strings in the vector. In other words, it is conceptually similar to:
std::string_view foo(const std::string& s) {
std::string temp = s + " foo";
return temp;
}
int main() {
std::string_view sv = foo("hello");
std::cout << sv << "\n";
}
Clang emits a warning for this small example, but not OP's full example, which is unfortunate:
warning: address of stack memory associated with local variable 'temp' returned [-Wreturn-stack-address]
return temp;
^~~~
Imagine you have the following code where logDebug() is expensive or is not appropriate to call more than once:
QDebug d = logDebug();
d << __FUNCTION__ << ":";
d << "positions separated with \" --- \":";
for (const auto& str : positions)
{
d << "---" << str;
}
A macro (just to replace the function name correctly) already exists which replaces the first 2 lines:
#define LOG_FUNCTION this->logDebug() << __FUNCTION__ << ":"
It creates the local variable by calling logDebug(). Once called, you can only use the operator<< onto the macro.
The problem is you can't attach the for loop body to logger.
Q: Is there a way I could use the macro for pasting all the positions (without calling logDebug again?
I would guess this should be possible using lambdas, but I quite don't know how to.
Please help, the shortest answer wins!
Q: Is there a way I could use the macro for pasting all the positions (without calling logDebug again? I would guess this should be possible using lambdas, but I quite don't know how to.
I suppose it's possible with something as follows (used std::cout instead of logDebug())
#include <iostream>
#define LOG_FUNCTION std::cout << __FUNCTION__ << ": "
#define LOG_DEB(ps) \
[](auto & s, auto const & _ps) { for ( auto const & p : _ps ) s << p; } \
(LOG_FUNCTION, ps)
int main ()
{
int a[] { 0, 1, 2, 3, 4 };
LOG_DEB(a);
}
I've used a couple of auto as types of the lambda arguments and this works only starting from C++14.
In C++11 you have to replace they with the correct types.
Well the macro can be coerced to return your debug object:
#define LOG_FUNCTION() this->logDebug() << __FUNCTION__ << ":"
Then use it like this:
auto& d = LOG_FUNCTION();
d << "positions separated with \" --- \":";
for (const auto& str : positions)
{
d << "---" << str;
}
I've come across this "feature" in MSVC++ and I'm now not sure if it's a bug or my understanding of lvalues/rvalues in C++ is just plain wrong.
I've added some seriously dumbed-down code to illustrate, but basically the issue is that MSVC++ 2013 (both base and NOV 2013 CTP compilers) allows assignment to temporary objects, which should really be rvalues and hence disallow any assignment attempts at compile time.
#include <iostream>
struct account {
int value;
explicit account(int v) : value{ v } {
std::cout << "account ctor: " << value << std::endl;
}
account(const account & acc) : value{ acc.value } {
std::cout << "account copy ctor" << std::endl;
}
account(account && acc) : value{ acc.value } {
std::cout << "account move ctor" << std::endl;
}
account & operator=(const account & acc) {
value = acc.value;
std::cout << "account copy assign" << std::endl;
return *this;
}
account & operator=(account && acc) {
value = acc.value;
std::cout << "account move assign" << std::endl;
return *this;
}
};
int get_int() { return 42; }
account get_account() {
return account(123);
}
int main() {
//get_int() = 5; // this predictably fails to compile
// with '=' : left operand must be l-value
// everything below succeeds
get_account() = account(42); // console trace for this
// account ctor: 42
// account ctor: 123
// account move assign
account(123) = account(42); // console trace same as above
account acc(0); // account ctor: 0
account(42) = acc; // account ctor: 42
// account copy assign
get_account() = acc; // console trace same as above
}
Surely get_account() = acc; or account(42) = acc; is not C++ Standard's prescribed behaviour?! Both get_account() & account(42) should result in rvalues, which by definition do not allow assignments.
Incidentally, overloading member functions based on lvalue/rvalue qualifiers
...
void memberFn() const &;
void memberFn() &&;
...
which is supported in NOV 2013 CTP is not working properly or at all. I assume this is a result of failing to recognise rvalues, so that this is always an lvalue.
PS Unfortunately, I do not have an opportunity to test this with other compilers.
According to my understanding, this is perfectly valid C++11.
Only built-in assignment to prvalues is prohibited.
From [5, expr]:
Note: Operators can be overloaded, that is, given meaning when applied to expressions of class type (Clause
9) or enumeration type (7.2). Uses of overloaded operators are transformed into function calls as described
in 13.5. Overloaded operators obey the rules for syntax specified in Clause 5, but the requirements of
operand type, value category, and evaluation order are replaced by the rules for function call.
So the requirements on
get_account() = account(42);
are the same as on any other member-function call
get_account().foo_bar(account(42));
which makes sense since it is just a nicer syntax for
get_account().operator=(account(42));
The section 3.10 on Lvalues and rvalues makes this as clear well [basic.lval]:
For example, the built-in assignment operators expect that the left operand is an lvalue and that the right operand is a prvalue and yield an lvalue as the result. User-defined operators are functions, and the categories of values they expect and yield are determined by their parameter and return
types.
I think I might have missed the subtlety in move construction because when I change the line Foo copy(*this); to decltype(*this) copy(*this);, I am thoroughly surprised by the output.
I checked it against, clang++-3.5 and g++-4.9, with the same behavior.
Would really appreciate a quick tip from the C++11 guru.
Update: Just forced the compiler to print the type of decltype(*this), it is actually a reference type i.e. Foo&.
class Foo {
public:
Foo(int a): val(a) {}
operator int() { return val; }
auto& operator++() {
val++;
return *this;
}
auto operator++(int) {
//Foo copy(*this);
decltype(*this) copy(*this);
++(*this);
return copy;
}
private:
int val;
};
int main()
{
Foo foo=1;
cout << "foo++ = " << foo++ << "\n";
cout << "foo++ = " << foo++ << "\n";
cout << "foo = " << foo << "\n";
return 0;
}
The output
foo++ = 2
foo++ = 3
foo = 3
There seems to be a confusion as to why decltyp(*this) is Foo& and not Foo in your case. Firstly, think about dereferencing a pointer always resulting in a reference to the pointed to object.
temp = *ptr // this would work if dereferencing returned by value or by reference
*ptr = expr // this would only work if dereferencing results in a reference.
Now decltype(expr) always gives you exactly the same type as the expr. For you *this is of type Foo&.
If you want type deduction without it resulting in a reference use auto instead of decltype, so:
auto copy(*this);
instead of
decltype(*this) copy(*this);
Also I don't know why your question is talking about move construction so much as there is no move involved anywhere.
Just when I thought I kind of understand rvalue reference, I ran into this problem. The code is probably unnecessarily long, but the idea is quite simple. There is a main() function, and returnRValueRef() function.
#include <iostream>
#define NV(x) "[" << #x << "=" << (x) << "]"
#define log(x) cout << __FILE__ << ":" << __LINE__ << " " << x << endl
using namespace std;
class AClass {
public:
int a_;
AClass() : a_(0) {
log("inside default constructor");
}
AClass(int aa) : a_(aa) {
log("inside constructor");
}
int getInt() const {
return a_;
}
void setInt(int a) {
a_ = a;
}
AClass(AClass const & other) : a_(other.a_) {
log("inside copy constructor");
}
AClass & operator=(AClass const & rhs) {
log("inside assignment operator" << "left value" << NV(a_) << "right value" << NV(rhs.a_));
a_ = rhs.a_;
return *this;
}
AClass & operator=(AClass && rhs) {
log("inside assignment operator (rvalue ref)" << "left" << NV(a_) << "right" << NV(rhs.a_));
a_ = rhs.a_;
return *this;
}
};
AClass && returnRValueRef() {
AClass a1(4);
return move(a1);
}
int main() {
AClass a;
a = returnRValueRef();
}
Okay, I would expect this code to first print "inside default constructor" (for a), then "inside constructor" (for a1), and then assignment operator message with rhs.a_ = 4. But the output is
testcpp/return_rvalue_ref.cpp:14 inside default constructor
testcpp/return_rvalue_ref.cpp:17 inside constructor
testcpp/return_rvalue_ref.cpp:39 inside assignment operator (rvalue ref)left[a_=0]right[rhs.a_=0]
Can somebody explain why the last line in the output prints right[rhs.a_=0] instead of right[rhs.a_=4]? I thought the move() just makes lvalue into rvalue without changing its contents. But I am clearly missing something.
Thanks so much for your help. :-)
Edit: I think I know what might be going on. May be the destructor for a1 in function returnRValueRef() is being called when it goes out of scope (even if it is turned into rvalue), and after that the memory location for a1 (or rvalue reference for it) contains undefined stuff! Not sure if that is what is happening, but seems plausible.
An rvalue reference is still a reference. In your case, you are referencing the local variable that has been destructed. Therefore it is undefined behavior to access the members. What you want to do is to return the object:
AClass returnRValueRef() {
AClass a1(4);
return move(a1);
}
However, a move happens automatically with a local variable, so you really only need to do this:
AClass returnRValueRef() {
AClass a1(4);
return a1;
}