Changing operation attribute storage

So I have concrete results now: Inlining intrinsic attributes with the Operation makes ODS attribute getters/setters really fast. However, everything gets slower. StringRef and Identifier attributes are slower because they have to check two lists, and iterations over ranges of attributes are slower because the range is now AttributeRange, which hides the complexity of dealing with two separate lists, one of which may contain null values, instead of ArrayRef<NamedAttribute>.

@clattner I’m not sure what your particular case is. If 99% of your attribute lookups are through ODS getters, then this change is a sure win (assuming the performance increase is worth the implementation complexity). However, the cases I have been using as benchmarks are very heavy on generic attribute lookups (lots of unregistered ops, etc. lookupSymbolIn is quite hot). I see a performance decrease of 20-30%.

Not that it was a waste of time: I found a handful of things along the way that will improve MLIR’s performance (as well as bugs…).

@River707 Had a “compromise” idea, where an ODS attribute that knows it has n non-optional/default-valued attributes less than it and m greater can search a subrange of attributes attrs[n:#attrs-m).