Comparison mismatch causes assert using VStudio STL

Hola LLVMers,

We saw a problem with some code in LiveIntervalAnalysis.h/.c which we’ve fixed locally. We’d like to get a patch to the mainline and want to know how you’d like it fixed. A couple of things come together to cause the problem:

struct Idx2MBBCompare {

bool operator()(const IdxMBBPair &LHS, const IdxMBBPair &RHS) const {

return LHS.first < RHS.first;

}

This comparator function compares the first elements of the IdxMBBPair. This is in contrast to the default comparator for std::pairs, which compares the second element if the first elements are equal before making a final decision. In this case, it makes a lot of sense given that the second in the pair is just a pointer.

In LiveIntervals::runOnMachineFunction, the map is sorted with this:

std::sort(Idx2MBBMap.begin(), Idx2MBBMap.end(), Idx2MBBCompare());

Ok so far.

Here is where the problem arises:

std::lower_bound(Idx2MBBMap.begin(), Idx2MBBMap.end(), LR.start);

By omitting the explicit comparator operator, the default is used which looks at second. Not a huge problem in general, since you don’t really care that the pointers are sorted.

Visual Studio’s debug STL, however, is quite the stickler. Debug lower_bound checks to see that the container is sorted and since lower_bound isn’t given a comparison function, it uses the default one which isn’t the one used to sort the container, and (boom!) it asserts if the memory stars aren’t aligned properly.

In our code we fixed this by ditching the Idx2MBBCompare operator and just added:

  • inline bool operator<(const IdxMBBPair &LHS, const IdxMBBPair &RHS) {

  • return (LHS.first < RHS.first);

  • }

The alternative is to make sure the Idx2MBBCompare is passed into the appropriate places.

How would you like this to be fixed? I can tool it up, but I don’t want to step on someone else’s feet.

Thanks,

Chuck.

Hello llvm dev peeps

I would like to use an LLVMBuilder pointer as a base pointer to reference either an LLVMBuilder or an LLVMFoldingBuilder. As the methods in the Folding builder have the same names as the base class, I thought about submitting a patch whereby the base class methods would become virtual. However, the base class methods return specific types while the Folding builder, for good reason, return more general Value* types.

Would it be reasonable for me to submit a patch whereby the LLVMBuilder methods also return the general Value* type and the LLVMFoldingBuilder methods become virtual overrides of the base class methods?

Users (such as myself) could then decide at runtime which type of builder they wish to use.

Another option that was discussed in #llvm is to nuke LLVMBuilder and rename LLVMFoldingBuilder to LLVMBuilder. If this was the case, I'd argue for a flag in the Builder that could retain the old non-folding functionality for debugging purposes.

Your thoughts please?

Hola LLVMers,

We saw a problem with some code in LiveIntervalAnalysis.h/.c which we’ve fixed locally. We’d like to get a patch to the mainline and want to know how you’d like it fixed. A couple of things come together to cause the problem:

struct Idx2MBBCompare {
bool operator()(const IdxMBBPair &LHS, const IdxMBBPair &RHS) const {
return LHS.first < RHS.first;
}

This comparator function compares the first elements of the IdxMBBPair. This is in contrast to the default comparator for std::pairs, which compares the second element if the first elements are equal before making a final decision. In this case, it makes a lot of sense given that the second in the pair is just a pointer.

In LiveIntervals::runOnMachineFunction, the map is sorted with this:

std::sort(Idx2MBBMap.begin(), Idx2MBBMap.end(), Idx2MBBCompare());

Ok so far.

Here is where the problem arises:

std::lower_bound(Idx2MBBMap.begin(), Idx2MBBMap.end(), LR.start);

By omitting the explicit comparator operator, the default is used which looks at second. Not a huge problem in general, since you don’t really care that the pointers are sorted.

Visual Studio’s debug STL, however, is quite the stickler. Debug lower_bound checks to see that the container is sorted and since lower_bound isn’t given a comparison function, it uses the default one which isn’t the one used to sort the container, and (boom!) it asserts if the memory stars aren’t aligned properly.

In our code we fixed this by ditching the Idx2MBBCompare operator and just added:

  • inline bool operator<(const IdxMBBPair &LHS, const IdxMBBPair &RHS) {
  • return (LHS.first < RHS.first);
  • }

I think this is right fix for it. Any chance you can do some sanity testing? Please commit after you have run it though MultiSource portion of llvm test suite. Thanks!

Evan

Hi,

Another option that was discussed in #llvm is to nuke LLVMBuilder and
rename LLVMFoldingBuilder to LLVMBuilder. If this was the case, I'd
argue for a flag in the Builder that could retain the old non-folding
functionality for debugging purposes.

this plan sounds good to me. However it's not clear to me how useful a
debug flag would really be.

Ciao,

Duncan.

Duncan Sands wrote:

Another option that was discussed in #llvm is to nuke LLVMBuilder and rename LLVMFoldingBuilder to LLVMBuilder. If this was the case, I'd argue for a flag in the Builder that could retain the old non-folding functionality for debugging purposes.
    
this plan sounds good to me. However it's not clear to me how useful a
debug flag would really be.

I know that using the LLVMBuilder was useful to me in the early days of my work with LLVM to see exactly how the IR matched with what I expected it to given the input. It's only now that I'm working on global variables that require ConstantExpr types for initialisers that I started to use the LLVMFoldingBuilder.

I'll work on the patch and submit it here when it's ready.

Thanks

Hello llvm dev peeps

I would like to use an LLVMBuilder pointer as a base pointer to
reference either an LLVMBuilder or an LLVMFoldingBuilder. As the methods
in the Folding builder have the same names as the base class, I thought
about submitting a patch whereby the base class methods would become
virtual. However, the base class methods return specific types while the
Folding builder, for good reason, return more general Value* types.

Would it be reasonable for me to submit a patch whereby the LLVMBuilder
methods also return the general Value* type and the LLVMFoldingBuilder
methods become virtual overrides of the base class methods?

No, please don't do this. The idea of llvmbuilder is that it is a "free" wrapper around the other existing API calls. Making the methods virtual would make them much more expensive.

Users (such as myself) could then decide at runtime which type of
builder they wish to use.

Why do you want this?

Another option that was discussed in #llvm is to nuke LLVMBuilder and
rename LLVMFoldingBuilder to LLVMBuilder.

I'd strongly prefer this. The non-folding builder is not very useful for anything, and anyone who wants unfolded instructions can call the instruction ctors directly.

If this was the case, I'd
argue for a flag in the Builder that could retain the old non-folding
functionality for debugging purposes.

Why?

-Chris

Wouldn't the class of the objects be known at compile time in most
cases? This is essentially just a case of precomputing constants, so I
think this should be possible.

If yes, the compiler can predetermine the type, hence the virtual method
table that will be used, and can replace the virtual call with a static
one.

Does such an approach make sense with LLVM?
(I'd want to do such things for my personal language project, so the
answer would be affecting compilation strategy.)

Regards,
Jo

Chris Lattner wrote:

  

Would it be reasonable for me to submit a patch whereby the LLVMBuilder
methods also return the general Value* type and the LLVMFoldingBuilder
methods become virtual overrides of the base class methods?
    
No, please don't do this. The idea of llvmbuilder is that it is a "free" wrapper around the other existing API calls. Making the methods virtual would make them much more expensive.

Is this why the other API calls are all inline in the class? To avoid the overhead of the function call?

Users (such as myself) could then decide at runtime which type of
builder they wish to use.
    
Why do you want this?
  

At the time that I was considering this, I saw that the Folding Builder was a derived class of Builder and assumed, apparently wrongly, that the intention was to create further derived versions of the Builder with other potential optimisations.

If the Folding Builder is meant as a general replacement for the Builder, then the second approach does make much more sense.

Another option that was discussed in #llvm is to nuke LLVMBuilder and
rename LLVMFoldingBuilder to LLVMBuilder.
    
I'd strongly prefer this. The non-folding builder is not very useful for anything, and anyone who wants unfolded instructions can call the instruction ctors directly.

If this was the case, I'd
argue for a flag in the Builder that could retain the old non-folding
functionality for debugging purposes.
    
Why?

I used this non-folding functionality to create more explicit IR that I could check against my input to my parser. It made debugging far easier in the early stages of adding new parsing functionality.

Dom

Please verify that this actually happens in practice with llvm-gcc and gcc.

-Chris

If that's already the case (which I'll gladly believe), where does the
performance overhead for virtual functions come from?
(Just curious.)

Regards,
Jo

In general, the C++ compiler does NOT know the type of the leaf class
when performing a virtual method invocation. In particular, a parameter
(including "this") alleging to be a Foo* (Foo being some class) may
actually be any subclass of Foo, so unless the compiler can trace the
value flow all the way from the instantiation, it can't tell.

The necessary tracing is (a) hard, (b) whole-program, and (c) therefore
not supportable without a lot of linker support that isn't available in
practice.

I don't understand what you're asking. Please rephrase.

-Chris

Rephrased answer going to Jonathan's post.

Regards,
Jo

In general, the C++ compiler does NOT know the type of the leaf class
when performing a virtual method invocation. In particular, a parameter
(including "this") alleging to be a Foo* (Foo being some class) may
actually be any subclass of Foo, so unless the compiler can trace the
value flow all the way from the instantiation, it can't tell.

Right.

The necessary tracing is (a) hard, (b) whole-program, and (c) therefore
not supportable without a lot of linker support that isn't available in
practice.

I'm not sure how hard (a) really is. It's being done in other imperative
OO languages, and quite successful there (the SmartEiffel folks have
reported they can eliminate the vtable lookup in about 90% of call
sites, reaping all the rewards of inlining etc. for these; you can
assume that practically all functions in Eiffel are declared virtual, in
fact you have to declare them nonvirtual if you want that and people
almost never do it).
In C++, integer-to-pointer tricks and array indexing via pointers could
make alias analysis more difficult. Is it that much harder that the
percentage of call sites to replace with static calls drops
significantly?

I agree with (b).

I agree with the "lot of linker support" bit in (c), but not quite with
the "isn't available in practice" part - isn't link-time optimization
one of LLVM's particular highlights?

I agree with Chris' reservations about virtual functions if a
gcc-compiled llvm-gcc is the norm.
If a bootstrapped llvm-gcc, compiled with itself, is the norm, *and*
alias analysis is good enough to deal with C++ as it is used in
llvm-gcc, then using virtual functions should not be a serious problem.

This all, of course, assuming I didn't overlook anything relevant.
Which is exactly my question: did I overlook something?

Oh, and this one, of course: are there ramifications for compilers that
use LLVM as a backend?
In particular: If a language makes any and all functions virtual, is
LLVM able to unvirtualize them (at the link stage, if necessary)?

Regards,
Jo

Are those the folks that don't do separate compilation or dynamic libraries? :slight_smile:

Exactly.
But then they don't have have the architecture for smart linking. (Well,
they didn't when I last looked, which was a few years ago.)

Regards,
Jo

Duncan Sands wrote:

Another option that was discussed in #llvm is to nuke LLVMBuilder and rename LLVMFoldingBuilder to LLVMBuilder. If this was the case, I'd argue for a flag in the Builder that could retain the old non-folding functionality for debugging purposes.
    
this plan sounds good to me. However it's not clear to me how useful a
debug flag would really be.

After further discussion in #llvm, and lots of compiling and re-compiling, please find attached the first attempt at the patch with this change. There are two patches attached, one for llvm and one for llvm-gcc42.

Please note, there's quite a substantial API change in this patch: LLVMBuilder has been renamed to IRBuilder and has absorbed the constant-folding functionality from LLVMFoldingBuilder.

I've updated the tutorial html to refer to the correct includes and classes and tweaked Chapter 4 in particular to explain the constant folding optimizations rather than to explain how to use the LLVMFoldingBuilder to improve the code generation and these changes are included in the patch.

This is my first patch so please let me know if there are any problems or anything I need to do differently.

Thanks

llvm-gcc42.IRBuilder.patch (3.17 KB)

llvm.IRBuilder.patch (92.4 KB)

Dominic Hamon wrote:

Duncan Sands wrote:

Another option that was discussed in #llvm is to nuke LLVMBuilder and rename LLVMFoldingBuilder to LLVMBuilder. If this was the case, I'd argue for a flag in the Builder that could retain the old non-folding functionality for debugging purposes.
    
this plan sounds good to me. However it's not clear to me how useful a
debug flag would really be.

This is my first patch so please let me know if there are any problems or anything I need to do differently.

And there were. updated patches attached.

llvm.IRBuilder.patch (92.4 KB)

llvm-gcc42.IRBuilder.patch (3.04 KB)

Dominic Hamon wrote:

Duncan Sands wrote:

Another option that was discussed in #llvm is to nuke LLVMBuilder and rename LLVMFoldingBuilder to LLVMBuilder. If this was the case, I'd argue for a flag in the Builder that could retain the old non-folding functionality for debugging purposes.

this plan sounds good to me. However it's not clear to me how useful a
debug flag would really be.

This is my first patch so please let me know if there are any problems or anything I need to do differently.

And there were. updated patches attached.

Looking good. One big comment: Please attach patches to email instead of including them inline.

Some nits:

+ Value *CreateMul(Value *LHS, Value *RHS, const char *Name = "") {
+ if (Constant *LC = dyn_cast<Constant>(LHS))
+ if (Constant *RC = dyn_cast<Constant>(RHS))
+ return ConstantExpr::getMul(LC, RC);
+ return Insert(BinaryOperator::createMul(LHS, RHS, Name));
+ }

Please consistently indent by 2, not 4.

+
+ Value *CreateInsertElement(Value *Vec, Value *NewElt, Value *Idx,
+ const char *Name = "") {

Very picky, but 'const char *Name' should line up with 'Value *Vec'.

Index: gcc/llvm-convert.cpp

--- gcc/llvm-convert.cpp (revision 49475)
+++ gcc/llvm-convert.cpp (working copy)

Please attach llvm-gcc patches as a separate patch file.

Otherwise looks great!

-Chris

Thunderbird and Mail are once again conspiring against Chris. The fix is to make Thunderbird attach attachments instead of placing them inline:

http://lists.cs.uiuc.edu/pipermail/llvmdev/2008-January/011992.html

— Gordon