[llvm-dev] [RFC] Clean up the way we store optional Function data

Sanjoy Das via llvm-dev llvm-dev at lists.llvm.org
Fri Oct 9 23:07:07 PDT 2015


I don't know how prologue and prefix data is used -- is it correct to
say that you're basically trying to give `llvm::Function` s some
"optional" operands, and that you know during construction of an
`llvm::Function` how many optional operands the `llvm::Function` will
need[1]?  If so, you might want to consider using the "descriptor"
functionality that was added recently[2].  It allows classes deriving
from `llvm::User` to allocate an arbitrary number of bookkeeping bytes
before the normal `Use &` array.  Instructions with operand bundles
use these bytes to remember which where the individual operand bundles
start and end, and an `llvm::Function` could easily use the extra
storage to remember if / where optional operands like the personality
function are in the `Use &` array.  And by making the operands part of
the regular `Use &` array, functionality like RAUW that use Def-Use
chains should Just Work(TM).

Keep in mind, I'm biased here, so take with a grain of salt! :)

[1]: I see there are methods like `setPrologueData`, but they're only
   used from files that I'd expect to be creating `llvm::Function`
   instances from scratch.

[2]: See `DescBytes` in `User::User`

-- Sanjoy


Vedant Kumar wrote:
 > Function's have three kinds of optional data: prefix data, prologue data, and
 > personalities. We don't have a consistent way of storing this data, IMO. This
 > RFC discusses a new way of managing optional data that makes llvm::Function
 > cleaner, more consistent, and a little smaller.
 >
 >
 > What do we do currently?
 > ========================
 >
 > Prefix and prologue data are attached to Functions via DenseMaps in
 > LLVMContextImpl:
 >
 >      typedef DenseMap<const Function *, ReturnInst *>  FunctionDataMapTy;
 >      FunctionDataMapTy PrefixDataMap;
 >      FunctionDataMapTy PrologueDataMap;
 >
 > To attach prefix data to a Function, we create an orphan ReturnInst:
 >
 >      RI = ReturnInst::Create(F->getContext(), PrefixData);
 >      PrefixDataMap[F] = RI;
 >
 > Personalities are stored as ``optional`` Function operands. We actually always
 > allocate the space for this ``optional`` operand: there's a FIXME in the
 > destructor for Function about this.
 >
 >
 > What's wrong with this?
 > =======================
 >
 > 1. Functions without personalities pay the space-cost for them.
 >
 > 2. We handle personalities differently from prefix and prologue data.
 >
 > 3. Suppose N functions share the same prefix or prologue data. We create N
 >     different ReturnInsts to point to the same thing. I think that's wasteful.
 >
 > 4. These hidden ReturnInsts effectively make a Function an indirect user of
 >     its optional data. This relationship should be made explicit to avoid bugs.
 >
 >
 > Proposal: Introduce a new Constant, llvm::IndirectUser
 > ======================================================
 >
 > This is my take on Duncan's proposed solution to PR24755 [1].
 >
 > It involves creating a new type of Constant. A sketch:
 >
 >      struct llvm::IndirectUser : llvm::Constant {
 >          Constant *Data;     // Operand 0
 >          unsigned  RefCount; // Metadata (not an operand)
 >
 >          /// Get or create an IndirectUser for C.
 >          static IndirectUser *GetOrCreateIndirectUser(Constant *C);
 >
 >          /// Drop a reference to C's IndirectUser.
 >          static void ReleaseIndirectUser(Constant *C);
 >      };
 >
 > Here's how to attach prefix data to a Function:
 >
 >      IU = IndirectUser::GetOrCreateIndirectUser(PrefixData);
 >      PrefixDataMap[F] = IU;
 >
 > Prologue data and personality functions work the same way (though we'll need to
 > add a PersonalityFnMap).
 >
 > If two functions share prefix/prologue data, or personalities, they get the
 > same IndirectUser (with a bumped refcount).
 >
 > This addresses all the points in the previous section.
 >
 >
 > Implementation details
 > ======================
 >
 > When an IndirectUser is constructed, it adds itself to its Constant's users
 > list. When the IndirectUser's refcount hits 0, we can invoke destroyConstant().
 > The only tricky part is handling ReplaceAllUsesWith.
 >
 > There are two RAUW cases. Case 1 is easy:
 >
 >      <IndirectUser 1>  = { Data = A, RefCount = X }
 >      RAUW(A, B)
 >
 > Result:
 >
 >      <IndirectUser 1>  = { Data = B, RefCount = X }
 >
 > Case 2 is a bit more involved:
 >
 >      <IndirectUser 1>  = { Data = A, RefCount = X }
 >      <IndirectUser 2>  = { Data = B, RefCount = Y }
 >      RAUW(A, B)
 >
 > Result:
 >
 >      <IndirectUser 2>  = { Data = B, RefCount = X + Y }
 >      <IndirectUser 1>  = { Data =<IndirectUser 2>, RefCount = 0 }
 >
 > I've left out a sub-case where<IndirectUser 2>  is already part of a daisy
 > chain. There are strict asserts in place to keep the daisy-chaining sane.
 >
 > I have this mostly working. There's just one outstanding issue in clang. The
 > PersonalityHasOnlyCXXUses() routine needs to look up all the Function objects
 > which refer to a particular personality function.  I plan on supporting this by
 > defining a ``Function::getPersonalityFnUsers(Fn)`` routine.
 >
 > I'm hoping to have patches out for review by Monday. I thought I'd send this
 > out now to get feedback on my approach -- plus, I didn't want to send stuff in
 > out of the blue.
 >
 > Let me know what you think!
 >
 > vedant
 >
 > [1] https://llvm.org/bugs/show_bug.cgi?id=24755


More information about the llvm-dev mailing list