Twines are used to avoid constructing temporary std::string, right? If so, AttributeMap should also be changed from StringMap<std::string> to StringMap<Twine>, but that's not possible because Twine's operator= is deleted.
Also, the label will immediately be passed into escapeString, which requires converting it into an std::string again. With this in mind, is there actually any benefit of using Twine here?
The new output looks much better IMO. As a final test (you don't have to upload this one), can you check that it produces something reasonable on a larger function? says thousands/low tens of thousands of ops? I've produced CFG dot graphs in LLVM for functions like that, and they get quite large. If the output is even semi reasonable at that scale, we should delete ViewRegionGraph.
It isn't obvious to me that control flow edges should be off by default, I'd say that is more a matter of which dialect you are in. What is the downside to having it always enabled?
If it is being converted to std::string anyways, that is fine. The one nice benefit of Twine though, is that it results in a single std::string creation instead of potentially multiple (depending on what the user does).
(Also, I didn't read the code that far, seeing std::string in an LLVM code base is just a code smell)
I had them enabled by default, but some guys from a hardware team said that the CFG edges were confusing to them. They are working with TF graphs (or some lowering thereof), so they didn't really need them.
I have also seen cases where a constant is defined at the beginning of a function and then used further down. Having both data flow and control flow edges at the same time lead to a quite unreadable rendering with very long edges.
Which one you want (control/data flow) depends on the dialect I guess... But I think the default should be either data flow or control flow.
This description likely needs an update.