Vedant Kumar via llvm-dev
2015-Oct-10 02:20 UTC
[llvm-dev] [RFC] Clean up the way we store optional Function data
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
Sanjoy Das via llvm-dev
2015-Oct-10 06:07 UTC
[llvm-dev] [RFC] Clean up the way we store optional Function data
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
Vedant Kumar via llvm-dev
2015-Oct-12 16:01 UTC
[llvm-dev] [RFC] Clean up the way we store optional Function data
Hi Sanjoy,> 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]?Yep. Though not operands exactly, since they wouldn't be in Function's use list.> 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).That's a neat idea. To summarize: make Function have 3 optional operands. (For context -- Function currently has 1 optional operand, and my proposal is to move to 0.) Could someone else chime in on what they'd like to see? vedant
Apparently Analagous Threads
- [RFC] Clean up the way we store optional Function data
- [RFC] Clean up the way we store optional Function data
- [RFC] Clean up the way we store optional Function data
- [RFC] Clean up the way we store optional Function data
- [RFC] Clean up the way we store optional Function data