1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-22 18:54:02 +01:00

[StackSafety,NFC] Update documentation

It's follow up for D80908

Reviewed By: tejohnson

Differential Revision: https://reviews.llvm.org/D82941
This commit is contained in:
Vitaly Buka 2020-07-08 23:57:13 -07:00
parent ce4cb5a65c
commit b4bde7a6b6
4 changed files with 67 additions and 8 deletions

View File

@ -6843,7 +6843,9 @@ function and looks like:
param: 4, offset: [0, 5][, calls: ((Callee)[, (Callee)]*)]?
where the first ``param`` is the number of the parameter it describes,
``offset`` is the known access range of the paramenter inside of the function.
``offset`` is the inclusive range of offsets from the pointer parameter to bytes
which can be accessed by the function. This range does not include accesses by
function calls from ``calls`` list.
where each ``Callee`` decribes how parameter is forwared into other
functions and looks like:
@ -6854,7 +6856,44 @@ functions and looks like:
The ``callee`` refers to the summary entry id of the callee, ``param`` is
the number of the callee parameter which points into the callers parameter
with offset known to be inside of the ``offset`` range.
with offset known to be inside of the ``offset`` range. ``calls`` will be
consumed and removed by thin link stage to update ``Param::offset`` so it
covers all accesses possible by ``calls``.
Pointer parameter without corresponding ``Param`` is considered unsafe and we
assume that access with any offset is possible.
Example:
If we have the following function:
.. code-block:: text
define i64 @foo(i64* %0, i32* %1, i8* %2, i8 %3) {
store i32* %1, i32** @x
%5 = getelementptr inbounds i8, i8* %2, i64 5
%6 = load i8, i8* %5
%7 = getelementptr inbounds i8, i8* %2, i8 %3
tail call void @bar(i8 %3, i8* %7)
%8 = load i64, i64* %0
ret i64 %8
}
We can expect the record like this:
.. code-block:: text
params: ((param: 0, offset: [0, 7]),(param: 2, offset: [5, 5], calls: ((callee: ^3, param: 1, offset: [-128, 127]))))
The function may access just 8 bytes of the paramenter %0 . ``calls`` is empty,
so the parameter is either not used for function calls or ``offset`` already
covers all accesses from nested function calls.
Parameter %1 escapes, so access is unknown.
The function itself can access just a single byte of the parameter %2. Additional
access is possible inside of the ``@bar`` or ``^3``. The function adds signed
offset to the pointer and passes the result as the argument %1 into ``^3``.
This record itself does not tell us how ``^3`` will access the parameter.
Parameter %3 is not a pointer.
.. _refs_summary:

View File

@ -45,6 +45,12 @@ public:
void print(raw_ostream &O) const;
/// Parameters use for a FunctionSummary.
/// Function collects access information of all pointer parameters.
/// Information includes a range of direct access of parameters by the
/// functions and all call sites accepting the parameter.
/// StackSafety assumes that missing parameter information means possibility
/// of access to the parameter with any offset, so we can correctly link
/// code without StackSafety information, e.g. non-ThinLTO.
std::vector<FunctionSummary::ParamAccess> getParamAccesses() const;
};

View File

@ -553,8 +553,7 @@ public:
unsigned AlwaysInline : 1;
};
/// Describes the uses of a parameter by the range of offsets accessed in the
/// function and all of the call targets it is passed to.
/// Describes the uses of a parameter by the function.
struct ParamAccess {
static constexpr uint32_t RangeWidth = 64;
@ -564,7 +563,7 @@ public:
struct Call {
uint64_t ParamNo = 0;
GlobalValue::GUID Callee = 0;
ConstantRange Offsets{RangeWidth, true};
ConstantRange Offsets{/*BitWidth=*/RangeWidth, /*isFullSet=*/true};
Call() = default;
Call(uint64_t ParamNo, GlobalValue::GUID Callee,
@ -573,7 +572,15 @@ public:
};
uint64_t ParamNo = 0;
ConstantRange Use{RangeWidth, true};
/// The range contains byte offsets from the parameter pointer which
/// accessed by the function. In the per-module summary, it only includes
/// accesses made by the function instructions. In the combined summary, it
/// also includes accesses by nested function calls.
ConstantRange Use{/*BitWidth=*/RangeWidth, /*isFullSet=*/true};
/// In the per-module summary, it summarizes the byte offset applied to each
/// pointer parameter before passing to each corresponding callee.
/// In the combined summary, it's empty and information is propagated by
/// inter-procedural analysis and applied to the Use field.
std::vector<Call> Calls;
ParamAccess() = default;

View File

@ -748,13 +748,16 @@ const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const {
return *Info;
}
// Converts a StackSafetyFunctionInfo to the relevant FunctionSummary
// constructor fields
std::vector<FunctionSummary::ParamAccess>
StackSafetyInfo::getParamAccesses() const {
// Implementation transforms internal representation of parameter information
// into FunctionSummary format.
std::vector<FunctionSummary::ParamAccess> ParamAccesses;
for (const auto &KV : getInfo().Info.Params) {
auto &PS = KV.second;
// Parameter accessed by any or unknown offset, represented as FullSet by
// StackSafety, is handled as the parameter for which we have no
// StackSafety info at all. So drop it to reduce summary size.
if (PS.Range.isFullSet())
continue;
@ -763,6 +766,10 @@ StackSafetyInfo::getParamAccesses() const {
Param.Calls.reserve(PS.Calls.size());
for (auto &C : PS.Calls) {
// Parameter forwarded into another function by any or unknown offset
// will make ParamAccess::Range as FullSet anyway. So we can drop the
// entire parameter like we did above.
// TODO(vitalybuka): Return already filtered parameters from getInfo().
if (C.Offset.isFullSet()) {
ParamAccesses.pop_back();
break;