Two suggestions for improving LLVM error reporting

I realize that LLVM assertion results aren’t intended to be seen by end-users ever - they are there to tell front-end developers that they screwed up. Even so, I can think of two things that would make it easier for front-end developers to track down what they did wrong without having to jump into the debugger:

  1. Be able to set a “default module” for dump(). The version of dump() in llvm::Type takes a module parameter, which allows the type to be printed out using the type names registered in that module. However, the various asserts which call dump() or str() don’t have a module pointer handy, which causes the type to be printed out as unrecognizable gobbledygook. If there was some way that we could associate either a default module with the LLVMContext - or perhaps register type names with the LLVMContext directly - and have dump() with no arguments use these name mappings - it would make the output more readable. (I kind of like the idea of having a type name dictionary in the LLVM context which is used whenever there is no module pointer handy. For one thing, I could fill it with more readable names than the ones I use in the module’s name table.)

  2. In the case where type names are available, never print out type names in the form of “%26”. I realize that not all types have names - but at least always expand one level, so we can tell whether it’s a struct or a pointer or whatever. “{ %32 }” or “%32*” tells me a lot more than just a number by itself. Got a CreateLoad() call that failed? Well if it prints out “{ %32 }” for the assertion argument you instantly know why, even if you don’t know what “%32” resolves to.

In fact, what would be even cooler would be to set a threshold for the number of levels that were always expanded. I hate trying to read 400-character-long type names, but expanding two or three levels would be quite useful.

I realize that LLVM assertion results aren't intended to be seen by end-users ever - they are there to tell front-end developers that they screwed up. Even so, I can think of two things that would make it easier for front-end developers to track down what they did wrong without having to jump into the debugger:

Ok.

1) Be able to set a "default module" for dump(). The version of dump() in llvm::Type takes a module parameter, which allows the type to be printed out using the type names registered in that module. However, the various asserts which call dump() or str() don't have a module pointer handy, which causes the type to be printed out as unrecognizable gobbledygook.

Yes, this is lame.

If there was some way that we could associate either a default module with the LLVMContext - or perhaps register type names with the LLVMContext directly - and have dump() with no arguments use these name mappings - it would make the output more readable. (I kind of like the idea of having a type name dictionary in the LLVM context which is used whenever there is no module pointer handy. For one thing, I could fill it with more readable names than the ones I use in the module's name table.)

My eventual goal (perhaps for LLVM 3.0) is to eliminate our current structural type system altogether. The benefits are blown away by the costs, eventually we should just fix this design mistake. In the meantime, I'm not opposed to adding a Module* to VMCore that type dumping defaults to if non-null.

2) In the case where type names are available, never print out type names in the form of "%26". I realize that not all types have names - but at least always expand one level, so we can tell whether it's a struct or a pointer or whatever. "{ %32 }" or "%32*" tells me a lot more than just a number by itself. Got a CreateLoad() call that failed? Well if it prints out "{ %32 }" for the assertion argument you instantly know why, even if you don't know what "%32" resolves to.

Sure. I think the asmwriter already has this capability, it uses it when actually printing out the %42 = type { blah} lines. It wouldn't do to print out "%42 = type %42" after all :slight_smile:

In fact, what would be even cooler would be to set a threshold for the number of levels that were always expanded. I hate trying to read 400-character-long type names, but expanding two or three levels would be quite useful.

:slight_smile:

-Chris

Can you elaborate on this? I'm loving LLVM's structural types and they're
making my work a lot easier.

Having to come up with names for all of the structural types in my language
just to satisfy LLVM's new type system would suck...

There are two things I don't like about our current system:

1. Type resolution is really slow in some cases, because it has to incrementally detect when mutating type graphs become isomorphic and zap them. This is seen during bc/ll loading and particularly during module linking. This is one of the biggest sources of LTO slowness that I'm aware of.

2. Our implementation of type resolution uses union find to lazily update Type*'s in values etc. This means that Value::getType() is not a trivial accessor that returns a pointer - it has to check to see if the pointer is forwarded, and if so, forward the pointer in the type.

I'm not advocating elimination of pointer equality tests, but I am advocating the elimination of pointer equality tests for type *structure*. I want to introduce a first class "named type" type, and allow only *them* to be abstract, instead of having our current Opaque type.

This means that if you have a "%foo***" and %foo gets resolved to "i32", that "%foo***" would not get implicitly unioned with "i32***". This would also eliminate the current complexity forming circular types, make many frontends simpler etc. It would mean that a cyclic type would be *required* to go through a named type though.

It would also allow elimination of upreferences, PATypeHolder, PATypeHandle, etc. It would also eliminate the frequent confusion around "my function should take a %foo*, it the IR dump shows it as %bar*" (because they have the same type structure).

OTOH, it would mean that we couldn't have the totally awesome and oh-so-useful \1* type :wink:

-Chris

Sweet! Could named types also be concrete in this scheme?

Yep,

-Chris