1. Motivation
DSE is a function pass and only removes redundant stores intra-procedurally. It cannot cross function boundaries and eliminate inter-procedural dead stores as shown in this example:
class MyType {
public:
MyType(int foo, int bar, int baz) : foo_(foo), bar_(bar), baz_(baz) {}
private:
int foo_, bar_, baz_;
};
define void @myState()(ptr noalias sret(%class.MyType) %0) {
store i32 10, ptr %0, align 4, !dbg !11
%2 = getelementptr inbounds %class.MyType, ptr %0, i64 0, i32 1, !dbg !14
store i32 20, ptr %2, align 4, !dbg !14
%3 = getelementptr inbounds %class.MyType, ptr %0, i64 0, i32 2, !dbg !15
store i32 100, ptr %3, align 4, !dbg !15
ret void, !dbg !16
}
define void @forFun()() {
%x = alloca %class.MyType, align 4
call void @llvm.lifetime.start.p0(i64 12, ptr nonnull %x) #5
// A redundant memset call as "%x" is fully initialized in myState().
call void @llvm.memset.p0.i64(ptr align 4 %x, i8 0, i64 12, i1 false)
call void @myState()(ptr writable sret(%class.MyType) align 4 %x)
...
}
Itâs highly desirable to solve this issue especially when â-ftrivial-auto-var-initâ is set, which emits initialization conservatively at each auto var declaration and relies on the backend optimizers to eliminate redundant initializations as much as possible.
2. Proposal
LangRef draft: https://github.com/llvm/llvm-project/commit/69b09bâŚ
We propose adding a new LLVM attribute, initialized((Lo1,Hi1),(Lo2,Hi2),...)
, which expresses the notion of memory space (i.e., intervals, in bytes) that the argument pointing to is initialized in the function. Our current dereferenceable(n)
, writable
, or writeonly/readonly/readnone
attribute doesnât quite fit the bill.
2.1 Attribute syntax
The initialized((Lo1,Hi1),(Lo2,Hi2),...)
attribute is a ParamAttr, allowing it to be attached to each parameterâs attribute list. The attribute value provided in parentheses is a non-empty list of const ranges concatenated with commas: (Lo1,Hi1),(Lo2,Hi2),...
This attribute may only be applied to pointer typed parameters.
initialized attribute syntax: initialized((Lo1,Hi1),(Lo2,Hi2),...)
Parameter syntax: <type> [parameter Attrs] [name]
Example: ptr initialized((0,4),(8,16)) %ptr
Note that a). LoN/HiN
are 64-bit ints; Negative values are allowed in case a pointer to something partway through the allocation is passed to. b). continuous or overlapping intervals are not allowed, and the ranges will be stored in ascending order. In the motivation example, %0
is initialized with 3 store instructions in 3 ranges [0,4), [4,8), and [8,12). The initialized
attribute for %0
would be initialized((0,12))
.
2.2 Attribute semantics
initialized((Lo1,Hi1),(Lo2,Hi2),...)
implies that the memory (in bytes) pointed by the parameter and each range, [%p+LoN, %p+HiN)
, are initialized in the function and are not read before initialization within the function.
Initializations are non-volatile writes (StoreInst
or CallInst
to library APIs like memset
) to a memory location pointed to by the parameter, [%p+LoN, %p+HiN)
, that satisfy: a). Dominate any other memory access to the pointer in the function; b). Post-dominate the function entry.
Note that this attribute does not apply to the unwind edge. In the motivating example, assuming @myState
unwinds, DSE can still apply the initialized
attribute and eliminate the redundant store in @forFun
only if the %0
argument is marked dead_on_unwind
. This wonât affect the optimization for -ftrivial-auto-var-init
as we are typically trying to eliminate dead stores to an alloca, and allocas are essentially implicitly dead_on_unwind
.
This attribute implies that the function initializes and does not read before initialization through this pointer argument, even though it may read the memory before initialization that the pointer points to, such as through other arguments.
The writable or dereferenceable
attribute doesnât imply the initialized
attribute. Note that initialized
does not imply writeonly
since cases that read from the pointer after write, can be initialized
but not writeonly
.
2.3 Attribute representation
To properly represent const range list attributes, we propose adding a new kind of attribute, ConstRangeListAttribute
.
2.4 Follow-ups
With this attribute, we plan to:
- Infer in FunctionAttrs.cpp: https://github.com/llvm/llvm-project/commit/0bd68aâŚ
- Apply it in DSE: https://github.com/llvm/llvm-project/commit/b3866dâŚ