I’ll give you the answer, but it isn’t a good answer. I support the move to opaque pointers.
The background on this has to do with where LLVM came from: Vikram and I (and his research group) were working on heroic optimizations for data structure optimization of C/C++ programs, e.g. automatic pool allocation and pointer compression, and aggressive field sensitive pointer analysis.
As part of this, you need to do field sensitive analysis of the IR and need to decide when things are too unstructured to bother. As such, it made sense to build this info into the IR. This was all great research and I think there are still a bunch of good ideas there that could be explored further and have more impact. That said, while It was an impressive tour-de-force, LLVM is really the wrong level of abstraction to do this sort of thing. I’ve also learned with bitter experience that heroic compiler optimizations are not great for users of the compiler so if someone were to build these sorts of tools, I think it makes more sense to be in the context of a static analysis helper tool than an automatic optimization.
There was also an idea that GEP would be useful for dependence analysis of fortran style loops etc, which never seriously came to pass because LLVM is too low level for interesting fortran style loop transformations (something that has long been a problem in the llvm community). There are also some SPEC hacks in GlobalOpt that this sort of info made convenient, they are similar heroic optimizations.
In short, my current opinion is that LLVM should be true to what it is good at. It is an abstraction for CPUs with vectors, and it supports a capable suite of mid-level optimizations and codegen. The ConstantExpr representation does not need to reflect the SSA IR, that was a mistake - as @nikic mentions, the important thing to model (beyond simple int/float/pointer/vector constants) are relocatable constants, constant arrays for global initializers, etc.
I think it would also be interesting to consider making the initializers of GlobalVariable not be a Value* at all, it could be its own separate class. This would make Constant* just need to the simple constants that occur in function bodies.
-Chris