Previous work:
This work is extending the work done in D56802 which implemented treating iVar Offsets as constant for classes which directly inherit from NSObject. This behavior is possible because the size of NSObject is considered to be constant.
See “FIXME: Can we do this if see a chain of super classes with implementations leading to NSObject?“
Description:
In certain situations we know at compile time what the offset of an instance variable will be. In these situations we can avoid generating a load of the iVar offset from the global offset variable by treating the iVar offset as constant.
We can do this if the entire class layout is defined at compile time and the base class is NSObject (NSObject size is basically ABI and we’re already treating it as such via D56802).
Previously, D56802 did this for the most basic case where a class inherits directly from NSObject.
With this patch, by taking advantage of LTO, we can apply the optimization in all scenarios where the iVar offset can be known at compile-time. We optimize iVar accesses for any class who’s inheritance chain ends in NSObject, even if instance variables are present in the @implementation of base classes.
Implementation details:
- From each compile unit we now export an @interface summary ( this is a newly introduced type of summary ) which contains information about the iVars
- During LLVM IR generation we still do the normal IRGen where the iVar offset is not constant (generate a load)
- During LTO initial stage/ThinLTO thinLink stage we read the interface summaries and analyze the information to figure out which classes have compile-time constant iVar offsets and compute these iVar offsets
- During LTO / ThinLTO optimization we recognize load instructions from compile-time-constant iVar offsets and replace the load with a constant variable
Ex:
Original llvm:
%ivar1 = load i64,i64* @"OBJC_IVAR_$_Class01.the_iVar_Impl", align 8 Result = 12
%add.ptr2 = getelementptr inbounds i8, i8* %0, i64 %ivar1
// Transforms Into:
%add.ptr2 = getelementptr inbounds i8, i8* %0, i64 12
Note:
- This will have an approx 2% code size reduction - when (benchmarked on a >10MB binary)
- The attached patch is a proof of concept, we will break up this big patch in multiple smaller patches to make review easier
- Will add lit tests as necessary
- Will probably remove the extensive logging that is in this diff
clang-format: please reformat the code