This is an archive of the discontinued LLVM Phabricator instance.

[GlobalOpt] Generalize malloc-to-global for any allocation function
ClosedPublic

Authored by reames on Jan 17 2022, 9:58 AM.

Details

Summary

We can generalize the malloc-to-global transform for other allocation functions which are both a) removable, and b) have a known initialization value.

One subtlety that I want to point out - mostly because I hadn't realized it was true until I took a closer look - is that the existing code doesn't prove that initialization/malloc happens only once. The initialization function can be called multiple times. This is correct without special handling for malloc as undef can map to any value previously written, but a non-undef initializing allocation it means we may end up memseting the new global repeatedly. In particular, this means it's not legal to fold the memset into the initializer of the global.

Diff Detail

Event Timeline

reames created this revision.Jan 17 2022, 9:58 AM
reames requested review of this revision.Jan 17 2022, 9:58 AM
Herald added a project: Restricted Project. · View Herald TranscriptJan 17 2022, 9:58 AM

A couple of side notes:

With both the new and old code, we might be loosing some ability to prune loads from uninitialized state of the allocation. We could consider using lifetime markers at the point of the original allocation to preserve this. I'm a little leery of introducing them though as their semantics on globals are a bit vague. Thankfully, I think this is a minor opt quality issue at worst, and I don't have any motivating examples to justify exploring this further.

It would be interesting to explore whether we could prove the memory was allocated once. This might actually be easier for a nullable global than a non-null one. (e.g. for the idiomatic pattern if (!g) g = malloc()) I don't have a strong motivating example for this, but it seems like we're leaving something on the floor here. If we do the init once thing, we also need to be careful about data section size and profitability. What's profitable for undef and zero (e.g. effecting bss size), and what's profitably for other init constants (e.g. effecting .data sizes) might not be the same - i.e. we have to account for load time initialization costs.

nikic accepted this revision.Jan 17 2022, 12:58 PM

LGTM

A couple of side notes:

With both the new and old code, we might be loosing some ability to prune loads from uninitialized state of the allocation. We could consider using lifetime markers at the point of the original allocation to preserve this. I'm a little leery of introducing them though as their semantics on globals are a bit vague. Thankfully, I think this is a minor opt quality issue at worst, and I don't have any motivating examples to justify exploring this further.

Yeah, definitely don't want lifetime intrinsics on globals!

It would be interesting to explore whether we could prove the memory was allocated once. This might actually be easier for a nullable global than a non-null one. (e.g. for the idiomatic pattern if (!g) g = malloc()) I don't have a strong motivating example for this, but it seems like we're leaving something on the floor here. If we do the init once thing, we also need to be careful about data section size and profitability. What's profitable for undef and zero (e.g. effecting bss size), and what's profitably for other init constants (e.g. effecting .data sizes) might not be the same - i.e. we have to account for load time initialization costs.

This seems like a more general optimization -- what we currently do is optimize stored-once globals (one store, multiple reads) and arbitrary initialization in global ctors. We could try to determine that some initialization code can only be reached once (e.g. by detecting a "global initialization flag" pattern) and then treat that like global ctor initialization. Don't think this is worth bothering with at this point though.

llvm/test/Transforms/GlobalOpt/calloc-promote.ll
3

Duplicate run line

This revision is now accepted and ready to land.Jan 17 2022, 12:58 PM
This revision was landed with ongoing or failed builds.Jan 17 2022, 3:07 PM
This revision was automatically updated to reflect the committed changes.