diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst --- a/llvm/docs/LangRef.rst +++ b/llvm/docs/LangRef.rst @@ -6825,7 +6825,9 @@ 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: @@ -6836,7 +6838,27 @@ 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: + +.. code-block:: text + + params: ((param: 2, offset: [0, 15]),(param: 3, offset: [5, 5], calls: ((callee: ^3, param: 5, offset: [-1, 1])))) + +Parameter #0 and #1 are either not pointers or access is unknown. Parameter #2 +will not be accessed outside of 16 bytes starting from the byte pointed by the +parameter. ``calls`` is empty, so the parameter is either not used for function +calls or ``offset`` already covers all accesses from nested function calls. Then +function itself can access just a single byte of the parameter #3. Additional +access is possible when the function calls ``^3``. The function increment or +decrement parameter pointer and pass it as the argument #5 into ``^3``. This +record itself does not tell us how ``^3`` will access the parameter. .. _refs_summary: diff --git a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h --- a/llvm/include/llvm/Analysis/StackSafetyAnalysis.h +++ b/llvm/include/llvm/Analysis/StackSafetyAnalysis.h @@ -45,6 +45,12 @@ 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 getParamAccesses() const; }; diff --git a/llvm/include/llvm/IR/ModuleSummaryIndex.h b/llvm/include/llvm/IR/ModuleSummaryIndex.h --- a/llvm/include/llvm/IR/ModuleSummaryIndex.h +++ b/llvm/include/llvm/IR/ModuleSummaryIndex.h @@ -553,8 +553,8 @@ 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 range of byte offsets of direct + /// access in in the function and by all of the call targets it is passed to. struct ParamAccess { static constexpr uint32_t RangeWidth = 64; @@ -564,7 +564,7 @@ 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 +573,7 @@ }; uint64_t ParamNo = 0; - ConstantRange Use{RangeWidth, true}; + ConstantRange Use{/*BitWidth=*/RangeWidth, /*isFullSet=*/true}; std::vector Calls; ParamAccess() = default; diff --git a/llvm/lib/Analysis/StackSafetyAnalysis.cpp b/llvm/lib/Analysis/StackSafetyAnalysis.cpp --- a/llvm/lib/Analysis/StackSafetyAnalysis.cpp +++ b/llvm/lib/Analysis/StackSafetyAnalysis.cpp @@ -748,13 +748,16 @@ return *Info; } -// Converts a StackSafetyFunctionInfo to the relevant FunctionSummary -// constructor fields std::vector StackSafetyInfo::getParamAccesses() const { + // Implementation transforms internal representation of parameter information + // into FunctionSummary format. std::vector 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 @@ 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;