1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2025-01-31 12:41:49 +01:00

[StackSafety] Add info into function summary

Summary:
This patch adds optional field into function summary,
implements asm and bitcode serialization. YAML
serialization is omitted and can be added later if
needed.

This patch includes this information into summary only
if module contains at least one sanitize_memtag function.
In a near future MTE is the user of the analysis.
Later if needed we can provede more direct control
on when information is included into summary.

Reviewers: eugenis

Subscribers: hiraditya, steven_wu, dexonsmith, arphaman, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D80908
This commit is contained in:
Vitaly Buka 2020-05-31 23:49:57 -07:00
parent a8c59c6124
commit 63df17ad8b
18 changed files with 664 additions and 25 deletions

View File

@ -6728,7 +6728,7 @@ If the global value is a function, the ``Summary`` entry will look like:
.. code-block:: text .. code-block:: text
function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 2[, FuncFlags]?[, Calls]?[, TypeIdInfo]?[, Refs]? function: (module: ^0, flags: (linkage: external, notEligibleToImport: 0, live: 0, dsoLocal: 0), insts: 2[, FuncFlags]?[, Calls]?[, TypeIdInfo]?[, Params]?[, Refs]?
The ``module`` field includes the summary entry id for the module containing The ``module`` field includes the summary entry id for the module containing
this definition, and the ``flags`` field contains information such as this definition, and the ``flags`` field contains information such as
@ -6738,7 +6738,7 @@ to a local definition (the latter two are populated during the thin link).
The ``insts`` field contains the number of IR instructions in the function. The ``insts`` field contains the number of IR instructions in the function.
Finally, there are several optional fields: :ref:`FuncFlags<funcflags_summary>`, Finally, there are several optional fields: :ref:`FuncFlags<funcflags_summary>`,
:ref:`Calls<calls_summary>`, :ref:`TypeIdInfo<typeidinfo_summary>`, :ref:`Calls<calls_summary>`, :ref:`TypeIdInfo<typeidinfo_summary>`,
:ref:`Refs<refs_summary>`. :ref:`Params<params_summary>`, :ref:`Refs<refs_summary>`.
.. _variable_summary: .. _variable_summary:
@ -6806,6 +6806,38 @@ of ``hotness`` (which can take the values ``Unknown``, ``Cold``, ``None``,
branch frequency relative to the entry frequency, scaled down by 2^8) branch frequency relative to the entry frequency, scaled down by 2^8)
may be specified. The defaults are ``Unknown`` and ``0``, respectively. may be specified. The defaults are ``Unknown`` and ``0``, respectively.
.. _stacksafety_summary:
Params
^^^^^^
The optional ``Params`` is used by ``StackSafety`` and looks like:
.. code-block:: text
Params: ((Param)[, (Param)]*)
where each ``Param`` describes pointer parameter access inside of the
function and looks like:
.. code-block:: text
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.
where each ``Callee`` decribes how parameter is forwared into other
functions and looks like:
.. code-block:: text
callee: ^3, param: 5, offset: [-3, 3]
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.
.. _refs_summary: .. _refs_summary:
Refs Refs

View File

@ -25,6 +25,7 @@ class BlockFrequencyInfo;
class Function; class Function;
class Module; class Module;
class ProfileSummaryInfo; class ProfileSummaryInfo;
class StackSafetyInfo;
/// Direct function to compute a \c ModuleSummaryIndex from a given module. /// Direct function to compute a \c ModuleSummaryIndex from a given module.
/// ///
@ -35,7 +36,9 @@ class ProfileSummaryInfo;
ModuleSummaryIndex buildModuleSummaryIndex( ModuleSummaryIndex buildModuleSummaryIndex(
const Module &M, const Module &M,
std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback, std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback,
ProfileSummaryInfo *PSI); ProfileSummaryInfo *PSI,
std::function<const StackSafetyInfo *(const Function &F)> GetSSICallback =
[](const Function &F) -> const StackSafetyInfo * { return nullptr; });
/// Analysis pass to provide the ModuleSummaryIndex object. /// Analysis pass to provide the ModuleSummaryIndex object.
class ModuleSummaryIndexAnalysis class ModuleSummaryIndexAnalysis

View File

@ -13,6 +13,7 @@
#ifndef LLVM_ANALYSIS_STACKSAFETYANALYSIS_H #ifndef LLVM_ANALYSIS_STACKSAFETYANALYSIS_H
#define LLVM_ANALYSIS_STACKSAFETYANALYSIS_H #define LLVM_ANALYSIS_STACKSAFETYANALYSIS_H
#include "llvm/IR/ModuleSummaryIndex.h"
#include "llvm/IR/PassManager.h" #include "llvm/IR/PassManager.h"
#include "llvm/Pass.h" #include "llvm/Pass.h"
@ -42,6 +43,9 @@ public:
// TODO: Add useful for client methods. // TODO: Add useful for client methods.
void print(raw_ostream &O) const; void print(raw_ostream &O) const;
/// Parameters use for a FunctionSummary.
std::vector<FunctionSummary::ParamAccess> getParamAccesses() const;
}; };
class StackSafetyGlobalInfo { class StackSafetyGlobalInfo {
@ -143,6 +147,8 @@ public:
bool runOnModule(Module &M) override; bool runOnModule(Module &M) override;
}; };
bool needsParamAccessSummary(const Module &M);
} // end namespace llvm } // end namespace llvm
#endif // LLVM_ANALYSIS_STACKSAFETYANALYSIS_H #endif // LLVM_ANALYSIS_STACKSAFETYANALYSIS_H

View File

@ -292,6 +292,9 @@ enum GlobalValueSummarySymtabCodes {
FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS = 23, FS_PERMODULE_VTABLE_GLOBALVAR_INIT_REFS = 23,
// The total number of basic blocks in the module. // The total number of basic blocks in the module.
FS_BLOCK_COUNT = 24, FS_BLOCK_COUNT = 24,
// Range information for accessed offsets for every argument.
// [n x (paramno, range, numcalls, numcalls x (callee_guid, paramno, range))]
FS_PARAM_ACCESS = 25,
}; };
enum MetadataCodes { enum MetadataCodes {

View File

@ -23,6 +23,7 @@
#include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h" #include "llvm/ADT/StringRef.h"
#include "llvm/ADT/TinyPtrVector.h" #include "llvm/ADT/TinyPtrVector.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/GlobalValue.h" #include "llvm/IR/GlobalValue.h"
#include "llvm/IR/Module.h" #include "llvm/IR/Module.h"
#include "llvm/Support/Allocator.h" #include "llvm/Support/Allocator.h"
@ -552,6 +553,34 @@ public:
unsigned AlwaysInline : 1; 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.
struct ParamAccess {
static constexpr uint32_t RangeWidth = 64;
/// Describes the use of a value in a call instruction, specifying the
/// call's target, the value's parameter number, and the possible range of
/// offsets from the beginning of the value that are passed.
struct Call {
uint64_t ParamNo = 0;
GlobalValue::GUID Callee = 0;
ConstantRange Offsets{RangeWidth, true};
Call() = default;
Call(uint64_t ParamNo, GlobalValue::GUID Callee,
const ConstantRange &Offsets)
: ParamNo(ParamNo), Callee(Callee), Offsets(Offsets) {}
};
uint64_t ParamNo = 0;
ConstantRange Use{RangeWidth, true};
std::vector<Call> Calls;
ParamAccess() = default;
ParamAccess(uint64_t ParamNo, const ConstantRange &Use)
: ParamNo(ParamNo), Use(Use) {}
};
/// Create an empty FunctionSummary (with specified call edges). /// Create an empty FunctionSummary (with specified call edges).
/// Used to represent external nodes and the dummy root node. /// Used to represent external nodes and the dummy root node.
static FunctionSummary static FunctionSummary
@ -567,7 +596,8 @@ public:
std::vector<FunctionSummary::VFuncId>(), std::vector<FunctionSummary::VFuncId>(),
std::vector<FunctionSummary::VFuncId>(), std::vector<FunctionSummary::VFuncId>(),
std::vector<FunctionSummary::ConstVCall>(), std::vector<FunctionSummary::ConstVCall>(),
std::vector<FunctionSummary::ConstVCall>()); std::vector<FunctionSummary::ConstVCall>(),
std::vector<FunctionSummary::ParamAccess>());
} }
/// A dummy node to reference external functions that aren't in the index /// A dummy node to reference external functions that aren't in the index
@ -591,6 +621,9 @@ private:
std::unique_ptr<TypeIdInfo> TIdInfo; std::unique_ptr<TypeIdInfo> TIdInfo;
/// Uses for every parameter to this function.
std::vector<ParamAccess> ParamAccesses;
public: public:
FunctionSummary(GVFlags Flags, unsigned NumInsts, FFlags FunFlags, FunctionSummary(GVFlags Flags, unsigned NumInsts, FFlags FunFlags,
uint64_t EntryCount, std::vector<ValueInfo> Refs, uint64_t EntryCount, std::vector<ValueInfo> Refs,
@ -599,10 +632,12 @@ public:
std::vector<VFuncId> TypeTestAssumeVCalls, std::vector<VFuncId> TypeTestAssumeVCalls,
std::vector<VFuncId> TypeCheckedLoadVCalls, std::vector<VFuncId> TypeCheckedLoadVCalls,
std::vector<ConstVCall> TypeTestAssumeConstVCalls, std::vector<ConstVCall> TypeTestAssumeConstVCalls,
std::vector<ConstVCall> TypeCheckedLoadConstVCalls) std::vector<ConstVCall> TypeCheckedLoadConstVCalls,
std::vector<ParamAccess> ParamAccesses)
: GlobalValueSummary(FunctionKind, Flags, std::move(Refs)), : GlobalValueSummary(FunctionKind, Flags, std::move(Refs)),
InstCount(NumInsts), FunFlags(FunFlags), EntryCount(EntryCount), InstCount(NumInsts), FunFlags(FunFlags), EntryCount(EntryCount),
CallGraphEdgeList(std::move(CGEdges)) { CallGraphEdgeList(std::move(CGEdges)),
ParamAccesses(std::move(ParamAccesses)) {
if (!TypeTests.empty() || !TypeTestAssumeVCalls.empty() || if (!TypeTests.empty() || !TypeTestAssumeVCalls.empty() ||
!TypeCheckedLoadVCalls.empty() || !TypeTestAssumeConstVCalls.empty() || !TypeCheckedLoadVCalls.empty() || !TypeTestAssumeConstVCalls.empty() ||
!TypeCheckedLoadConstVCalls.empty()) !TypeCheckedLoadConstVCalls.empty())
@ -681,6 +716,14 @@ public:
return {}; return {};
} }
/// Returns the list of known uses of pointer parameters.
ArrayRef<ParamAccess> paramAccesses() const { return ParamAccesses; }
/// Sets the list of known uses of pointer parameters.
void setParamAccesses(std::vector<ParamAccess> NewParams) {
ParamAccesses = std::move(NewParams);
}
/// Add a type test to the summary. This is used by WholeProgramDevirt if we /// Add a type test to the summary. This is used by WholeProgramDevirt if we
/// were unable to devirtualize a checked call. /// were unable to devirtualize a checked call.
void addTypeTest(GlobalValue::GUID Guid) { void addTypeTest(GlobalValue::GUID Guid) {

View File

@ -223,13 +223,15 @@ template <> struct CustomMappingTraits<GlobalValueSummaryMapTy> {
Elem.SummaryList.push_back(std::make_unique<FunctionSummary>( Elem.SummaryList.push_back(std::make_unique<FunctionSummary>(
GlobalValueSummary::GVFlags( GlobalValueSummary::GVFlags(
static_cast<GlobalValue::LinkageTypes>(FSum.Linkage), static_cast<GlobalValue::LinkageTypes>(FSum.Linkage),
FSum.NotEligibleToImport, FSum.Live, FSum.IsLocal, FSum.CanAutoHide), FSum.NotEligibleToImport, FSum.Live, FSum.IsLocal,
FSum.CanAutoHide),
/*NumInsts=*/0, FunctionSummary::FFlags{}, /*EntryCount=*/0, Refs, /*NumInsts=*/0, FunctionSummary::FFlags{}, /*EntryCount=*/0, Refs,
ArrayRef<FunctionSummary::EdgeTy>{}, std::move(FSum.TypeTests), ArrayRef<FunctionSummary::EdgeTy>{}, std::move(FSum.TypeTests),
std::move(FSum.TypeTestAssumeVCalls), std::move(FSum.TypeTestAssumeVCalls),
std::move(FSum.TypeCheckedLoadVCalls), std::move(FSum.TypeCheckedLoadVCalls),
std::move(FSum.TypeTestAssumeConstVCalls), std::move(FSum.TypeTestAssumeConstVCalls),
std::move(FSum.TypeCheckedLoadConstVCalls))); std::move(FSum.TypeCheckedLoadConstVCalls),
ArrayRef<FunctionSummary::ParamAccess>{}));
} }
} }
static void output(IO &io, GlobalValueSummaryMapTy &V) { static void output(IO &io, GlobalValueSummaryMapTy &V) {

View File

@ -25,6 +25,7 @@
#include "llvm/Analysis/IndirectCallPromotionAnalysis.h" #include "llvm/Analysis/IndirectCallPromotionAnalysis.h"
#include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/Analysis/ProfileSummaryInfo.h"
#include "llvm/Analysis/StackSafetyAnalysis.h"
#include "llvm/Analysis/TypeMetadataUtils.h" #include "llvm/Analysis/TypeMetadataUtils.h"
#include "llvm/IR/Attributes.h" #include "llvm/IR/Attributes.h"
#include "llvm/IR/BasicBlock.h" #include "llvm/IR/BasicBlock.h"
@ -238,12 +239,12 @@ static bool isNonVolatileStore(const Instruction *I) {
return false; return false;
} }
static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M, static void computeFunctionSummary(
const Function &F, BlockFrequencyInfo *BFI, ModuleSummaryIndex &Index, const Module &M, const Function &F,
ProfileSummaryInfo *PSI, DominatorTree &DT, BlockFrequencyInfo *BFI, ProfileSummaryInfo *PSI, DominatorTree &DT,
bool HasLocalsInUsedOrAsm, bool HasLocalsInUsedOrAsm, DenseSet<GlobalValue::GUID> &CantBePromoted,
DenseSet<GlobalValue::GUID> &CantBePromoted, bool IsThinLTO,
bool IsThinLTO) { std::function<const StackSafetyInfo *(const Function &F)> GetSSICallback) {
// Summary not currently supported for anonymous functions, they should // Summary not currently supported for anonymous functions, they should
// have been named. // have been named.
assert(F.hasName()); assert(F.hasName());
@ -469,12 +470,15 @@ static void computeFunctionSummary(ModuleSummaryIndex &Index, const Module &M,
// Don't try to import functions with noinline attribute. // Don't try to import functions with noinline attribute.
F.getAttributes().hasFnAttribute(Attribute::NoInline), F.getAttributes().hasFnAttribute(Attribute::NoInline),
F.hasFnAttribute(Attribute::AlwaysInline)}; F.hasFnAttribute(Attribute::AlwaysInline)};
std::vector<FunctionSummary::ParamAccess> ParamAccesses;
if (auto *SSI = GetSSICallback(F))
ParamAccesses = SSI->getParamAccesses();
auto FuncSummary = std::make_unique<FunctionSummary>( auto FuncSummary = std::make_unique<FunctionSummary>(
Flags, NumInsts, FunFlags, /*EntryCount=*/0, std::move(Refs), Flags, NumInsts, FunFlags, /*EntryCount=*/0, std::move(Refs),
CallGraphEdges.takeVector(), TypeTests.takeVector(), CallGraphEdges.takeVector(), TypeTests.takeVector(),
TypeTestAssumeVCalls.takeVector(), TypeCheckedLoadVCalls.takeVector(), TypeTestAssumeVCalls.takeVector(), TypeCheckedLoadVCalls.takeVector(),
TypeTestAssumeConstVCalls.takeVector(), TypeTestAssumeConstVCalls.takeVector(),
TypeCheckedLoadConstVCalls.takeVector()); TypeCheckedLoadConstVCalls.takeVector(), std::move(ParamAccesses));
if (NonRenamableLocal) if (NonRenamableLocal)
CantBePromoted.insert(F.getGUID()); CantBePromoted.insert(F.getGUID());
Index.addGlobalValueSummary(F, std::move(FuncSummary)); Index.addGlobalValueSummary(F, std::move(FuncSummary));
@ -643,7 +647,8 @@ static void setLiveRoot(ModuleSummaryIndex &Index, StringRef Name) {
ModuleSummaryIndex llvm::buildModuleSummaryIndex( ModuleSummaryIndex llvm::buildModuleSummaryIndex(
const Module &M, const Module &M,
std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback, std::function<BlockFrequencyInfo *(const Function &F)> GetBFICallback,
ProfileSummaryInfo *PSI) { ProfileSummaryInfo *PSI,
std::function<const StackSafetyInfo *(const Function &F)> GetSSICallback) {
assert(PSI); assert(PSI);
bool EnableSplitLTOUnit = false; bool EnableSplitLTOUnit = false;
if (auto *MD = mdconst::extract_or_null<ConstantInt>( if (auto *MD = mdconst::extract_or_null<ConstantInt>(
@ -716,7 +721,8 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
ArrayRef<FunctionSummary::VFuncId>{}, ArrayRef<FunctionSummary::VFuncId>{},
ArrayRef<FunctionSummary::VFuncId>{}, ArrayRef<FunctionSummary::VFuncId>{},
ArrayRef<FunctionSummary::ConstVCall>{}, ArrayRef<FunctionSummary::ConstVCall>{},
ArrayRef<FunctionSummary::ConstVCall>{}); ArrayRef<FunctionSummary::ConstVCall>{},
ArrayRef<FunctionSummary::ParamAccess>{});
Index.addGlobalValueSummary(*GV, std::move(Summary)); Index.addGlobalValueSummary(*GV, std::move(Summary));
} else { } else {
std::unique_ptr<GlobalVarSummary> Summary = std::unique_ptr<GlobalVarSummary> Summary =
@ -756,7 +762,7 @@ ModuleSummaryIndex llvm::buildModuleSummaryIndex(
computeFunctionSummary(Index, M, F, BFI, PSI, DT, computeFunctionSummary(Index, M, F, BFI, PSI, DT,
!LocalsUsed.empty() || HasLocalInlineAsmSymbol, !LocalsUsed.empty() || HasLocalInlineAsmSymbol,
CantBePromoted, IsThinLTO); CantBePromoted, IsThinLTO, GetSSICallback);
} }
// Compute summaries for all variables defined in module, and save in the // Compute summaries for all variables defined in module, and save in the
@ -838,13 +844,19 @@ ModuleSummaryIndex
ModuleSummaryIndexAnalysis::run(Module &M, ModuleAnalysisManager &AM) { ModuleSummaryIndexAnalysis::run(Module &M, ModuleAnalysisManager &AM) {
ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M); ProfileSummaryInfo &PSI = AM.getResult<ProfileSummaryAnalysis>(M);
auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); auto &FAM = AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
bool NeedSSI = needsParamAccessSummary(M);
return buildModuleSummaryIndex( return buildModuleSummaryIndex(
M, M,
[&FAM](const Function &F) { [&FAM](const Function &F) {
return &FAM.getResult<BlockFrequencyAnalysis>( return &FAM.getResult<BlockFrequencyAnalysis>(
*const_cast<Function *>(&F)); *const_cast<Function *>(&F));
}, },
&PSI); &PSI,
[&FAM, NeedSSI](const Function &F) -> const StackSafetyInfo * {
return NeedSSI ? &FAM.getResult<StackSafetyAnalysis>(
const_cast<Function &>(F))
: nullptr;
});
} }
char ModuleSummaryIndexWrapperPass::ID = 0; char ModuleSummaryIndexWrapperPass::ID = 0;
@ -853,6 +865,7 @@ INITIALIZE_PASS_BEGIN(ModuleSummaryIndexWrapperPass, "module-summary-analysis",
"Module Summary Analysis", false, true) "Module Summary Analysis", false, true)
INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(BlockFrequencyInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass) INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass)
INITIALIZE_PASS_DEPENDENCY(StackSafetyInfoWrapperPass)
INITIALIZE_PASS_END(ModuleSummaryIndexWrapperPass, "module-summary-analysis", INITIALIZE_PASS_END(ModuleSummaryIndexWrapperPass, "module-summary-analysis",
"Module Summary Analysis", false, true) "Module Summary Analysis", false, true)
@ -867,6 +880,7 @@ ModuleSummaryIndexWrapperPass::ModuleSummaryIndexWrapperPass()
bool ModuleSummaryIndexWrapperPass::runOnModule(Module &M) { bool ModuleSummaryIndexWrapperPass::runOnModule(Module &M) {
auto *PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI(); auto *PSI = &getAnalysis<ProfileSummaryInfoWrapperPass>().getPSI();
bool NeedSSI = needsParamAccessSummary(M);
Index.emplace(buildModuleSummaryIndex( Index.emplace(buildModuleSummaryIndex(
M, M,
[this](const Function &F) { [this](const Function &F) {
@ -874,7 +888,13 @@ bool ModuleSummaryIndexWrapperPass::runOnModule(Module &M) {
*const_cast<Function *>(&F)) *const_cast<Function *>(&F))
.getBFI()); .getBFI());
}, },
PSI)); PSI,
[&](const Function &F) -> const StackSafetyInfo * {
return NeedSSI ? &getAnalysis<StackSafetyInfoWrapperPass>(
const_cast<Function &>(F))
.getResult()
: nullptr;
}));
return false; return false;
} }
@ -887,4 +907,5 @@ void ModuleSummaryIndexWrapperPass::getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll(); AU.setPreservesAll();
AU.addRequired<BlockFrequencyInfoWrapperPass>(); AU.addRequired<BlockFrequencyInfoWrapperPass>();
AU.addRequired<ProfileSummaryInfoWrapperPass>(); AU.addRequired<ProfileSummaryInfoWrapperPass>();
AU.addRequired<StackSafetyInfoWrapperPass>();
} }

View File

@ -665,6 +665,33 @@ const StackSafetyGlobalInfo::InfoTy &StackSafetyGlobalInfo::getInfo() const {
return *Info; return *Info;
} }
// Converts a StackSafetyFunctionInfo to the relevant FunctionSummary
// constructor fields
std::vector<FunctionSummary::ParamAccess>
StackSafetyInfo::getParamAccesses() const {
assert(needsParamAccessSummary(*F->getParent()));
std::vector<FunctionSummary::ParamAccess> ParamAccesses;
for (const auto &KV : getInfo().Info.Params) {
auto &PS = KV.second;
if (PS.Range.isFullSet())
continue;
ParamAccesses.emplace_back(KV.first, PS.Range);
FunctionSummary::ParamAccess &Param = ParamAccesses.back();
Param.Calls.reserve(PS.Calls.size());
for (auto &C : PS.Calls) {
if (C.Offset.isFullSet()) {
ParamAccesses.pop_back();
break;
}
Param.Calls.emplace_back(C.ParamNo, C.Callee->getGUID(), C.Offset);
}
}
return ParamAccesses;
}
StackSafetyGlobalInfo::StackSafetyGlobalInfo() = default; StackSafetyGlobalInfo::StackSafetyGlobalInfo() = default;
StackSafetyGlobalInfo::StackSafetyGlobalInfo( StackSafetyGlobalInfo::StackSafetyGlobalInfo(
@ -785,6 +812,13 @@ bool StackSafetyGlobalInfoWrapperPass::runOnModule(Module &M) {
return false; return false;
} }
bool llvm::needsParamAccessSummary(const Module &M) {
for (auto &F : M.functions())
if (F.hasFnAttribute(Attribute::SanitizeMemTag))
return true;
return false;
}
static const char LocalPassArg[] = "stack-safety-local"; static const char LocalPassArg[] = "stack-safety-local";
static const char LocalPassName[] = "Stack Safety Local Analysis"; static const char LocalPassName[] = "Stack Safety Local Analysis";
INITIALIZE_PASS_BEGIN(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName, INITIALIZE_PASS_BEGIN(StackSafetyInfoWrapperPass, LocalPassArg, LocalPassName,

View File

@ -758,6 +758,8 @@ lltok::Kind LLLexer::LexIdentifier() {
KEYWORD(alwaysInline); KEYWORD(alwaysInline);
KEYWORD(calls); KEYWORD(calls);
KEYWORD(callee); KEYWORD(callee);
KEYWORD(params);
KEYWORD(param);
KEYWORD(hotness); KEYWORD(hotness);
KEYWORD(unknown); KEYWORD(unknown);
KEYWORD(hot); KEYWORD(hot);

View File

@ -11,6 +11,8 @@
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
#include "LLParser.h" #include "LLParser.h"
#include "LLToken.h"
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h" #include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/STLExtras.h"
@ -22,6 +24,7 @@
#include "llvm/IR/BasicBlock.h" #include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallingConv.h" #include "llvm/IR/CallingConv.h"
#include "llvm/IR/Comdat.h" #include "llvm/IR/Comdat.h"
#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h" #include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h" #include "llvm/IR/DerivedTypes.h"
@ -8209,7 +8212,8 @@ bool LLParser::ParseGVEntry(unsigned ID) {
/// FunctionSummary /// FunctionSummary
/// ::= 'function' ':' '(' 'module' ':' ModuleReference ',' GVFlags /// ::= 'function' ':' '(' 'module' ':' ModuleReference ',' GVFlags
/// ',' 'insts' ':' UInt32 [',' OptionalFFlags]? [',' OptionalCalls]? /// ',' 'insts' ':' UInt32 [',' OptionalFFlags]? [',' OptionalCalls]?
/// [',' OptionalTypeIdInfo]? [',' OptionalRefs]? ')' /// [',' OptionalTypeIdInfo]? [',' OptionalParamAccesses]?
/// [',' OptionalRefs]? ')'
bool LLParser::ParseFunctionSummary(std::string Name, GlobalValue::GUID GUID, bool LLParser::ParseFunctionSummary(std::string Name, GlobalValue::GUID GUID,
unsigned ID) { unsigned ID) {
assert(Lex.getKind() == lltok::kw_function); assert(Lex.getKind() == lltok::kw_function);
@ -8222,6 +8226,7 @@ bool LLParser::ParseFunctionSummary(std::string Name, GlobalValue::GUID GUID,
unsigned InstCount; unsigned InstCount;
std::vector<FunctionSummary::EdgeTy> Calls; std::vector<FunctionSummary::EdgeTy> Calls;
FunctionSummary::TypeIdInfo TypeIdInfo; FunctionSummary::TypeIdInfo TypeIdInfo;
std::vector<FunctionSummary::ParamAccess> ParamAccesses;
std::vector<ValueInfo> Refs; std::vector<ValueInfo> Refs;
// Default is all-zeros (conservative values). // Default is all-zeros (conservative values).
FunctionSummary::FFlags FFlags = {}; FunctionSummary::FFlags FFlags = {};
@ -8253,6 +8258,10 @@ bool LLParser::ParseFunctionSummary(std::string Name, GlobalValue::GUID GUID,
if (ParseOptionalRefs(Refs)) if (ParseOptionalRefs(Refs))
return true; return true;
break; break;
case lltok::kw_params:
if (ParseOptionalParamAccesses(ParamAccesses))
return true;
break;
default: default:
return Error(Lex.getLoc(), "expected optional function summary field"); return Error(Lex.getLoc(), "expected optional function summary field");
} }
@ -8267,7 +8276,8 @@ bool LLParser::ParseFunctionSummary(std::string Name, GlobalValue::GUID GUID,
std::move(TypeIdInfo.TypeTestAssumeVCalls), std::move(TypeIdInfo.TypeTestAssumeVCalls),
std::move(TypeIdInfo.TypeCheckedLoadVCalls), std::move(TypeIdInfo.TypeCheckedLoadVCalls),
std::move(TypeIdInfo.TypeTestAssumeConstVCalls), std::move(TypeIdInfo.TypeTestAssumeConstVCalls),
std::move(TypeIdInfo.TypeCheckedLoadConstVCalls)); std::move(TypeIdInfo.TypeCheckedLoadConstVCalls),
std::move(ParamAccesses));
FS->setModulePath(ModulePath); FS->setModulePath(ModulePath);
@ -8616,13 +8626,133 @@ bool LLParser::ParseOptionalVTableFuncs(VTableFuncList &VTableFuncs) {
return false; return false;
} }
/// ParamNo := 'param' ':' UInt64
bool LLParser::ParseParamNo(uint64_t &ParamNo) {
if (ParseToken(lltok::kw_param, "expected 'param' here") ||
ParseToken(lltok::colon, "expected ':' here") || ParseUInt64(ParamNo))
return true;
return false;
}
/// ParamAccessOffset := 'offset' ':' '[' APSINTVAL ',' APSINTVAL ']'
bool LLParser::ParseParamAccessOffset(ConstantRange &Range) {
APSInt Lower;
APSInt Upper;
auto ParseAPSInt = [&](APSInt &Val) {
if (Lex.getKind() != lltok::APSInt)
return TokError("expected integer");
Val = Lex.getAPSIntVal();
Val = Val.extOrTrunc(FunctionSummary::ParamAccess::RangeWidth);
Val.setIsSigned(true);
Lex.Lex();
return false;
};
if (ParseToken(lltok::kw_offset, "expected 'offset' here") ||
ParseToken(lltok::colon, "expected ':' here") ||
ParseToken(lltok::lsquare, "expected '[' here") || ParseAPSInt(Lower) ||
ParseToken(lltok::comma, "expected ',' here") || ParseAPSInt(Upper) ||
ParseToken(lltok::rsquare, "expected ']' here"))
return true;
++Upper;
Range =
(Lower == Upper && !Lower.isMaxValue())
? ConstantRange::getEmpty(FunctionSummary::ParamAccess::RangeWidth)
: ConstantRange(Lower, Upper);
return false;
}
/// ParamAccessCall
/// := '(' 'callee' ':' GVReference ',' ParamNo ',' ParamAccessOffset ')'
bool LLParser::ParseParamAccessCall(FunctionSummary::ParamAccess::Call &Call) {
if (ParseToken(lltok::lparen, "expected '(' here") ||
ParseToken(lltok::kw_callee, "expected 'callee' here") ||
ParseToken(lltok::colon, "expected ':' here"))
return true;
unsigned GVId;
ValueInfo VI;
if (ParseGVReference(VI, GVId))
return true;
Call.Callee = VI.getGUID();
if (ParseToken(lltok::comma, "expected ',' here") ||
ParseParamNo(Call.ParamNo) ||
ParseToken(lltok::comma, "expected ',' here") ||
ParseParamAccessOffset(Call.Offsets))
return true;
if (ParseToken(lltok::rparen, "expected ')' here"))
return true;
return false;
}
/// ParamAccess
/// := '(' ParamNo ',' ParamAccessOffset [',' OptionalParamAccessCalls]? ')'
/// OptionalParamAccessCalls := '(' Call [',' Call]* ')'
bool LLParser::ParseParamAccess(FunctionSummary::ParamAccess &Param) {
if (ParseToken(lltok::lparen, "expected '(' here") ||
ParseParamNo(Param.ParamNo) ||
ParseToken(lltok::comma, "expected ',' here") ||
ParseParamAccessOffset(Param.Use))
return true;
if (EatIfPresent(lltok::comma)) {
if (ParseToken(lltok::kw_calls, "expected 'calls' here") ||
ParseToken(lltok::colon, "expected ':' here") ||
ParseToken(lltok::lparen, "expected '(' here"))
return true;
do {
FunctionSummary::ParamAccess::Call Call;
if (ParseParamAccessCall(Call))
return true;
Param.Calls.push_back(Call);
} while (EatIfPresent(lltok::comma));
if (ParseToken(lltok::rparen, "expected ')' here"))
return true;
}
if (ParseToken(lltok::rparen, "expected ')' here"))
return true;
return false;
}
/// OptionalParamAccesses
/// := 'params' ':' '(' ParamAccess [',' ParamAccess]* ')'
bool LLParser::ParseOptionalParamAccesses(
std::vector<FunctionSummary::ParamAccess> &Params) {
assert(Lex.getKind() == lltok::kw_params);
Lex.Lex();
if (ParseToken(lltok::colon, "expected ':' here") ||
ParseToken(lltok::lparen, "expected '(' here"))
return true;
do {
FunctionSummary::ParamAccess ParamAccess;
if (ParseParamAccess(ParamAccess))
return true;
Params.push_back(ParamAccess);
} while (EatIfPresent(lltok::comma));
if (ParseToken(lltok::rparen, "expected ')' here"))
return true;
return false;
}
/// OptionalRefs /// OptionalRefs
/// := 'refs' ':' '(' GVReference [',' GVReference]* ')' /// := 'refs' ':' '(' GVReference [',' GVReference]* ')'
bool LLParser::ParseOptionalRefs(std::vector<ValueInfo> &Refs) { bool LLParser::ParseOptionalRefs(std::vector<ValueInfo> &Refs) {
assert(Lex.getKind() == lltok::kw_refs); assert(Lex.getKind() == lltok::kw_refs);
Lex.Lex(); Lex.Lex();
if (ParseToken(lltok::colon, "expected ':' in refs") | if (ParseToken(lltok::colon, "expected ':' in refs") ||
ParseToken(lltok::lparen, "expected '(' in refs")) ParseToken(lltok::lparen, "expected '(' in refs"))
return true; return true;

View File

@ -365,6 +365,12 @@ namespace llvm {
bool ParseVFuncId(FunctionSummary::VFuncId &VFuncId, bool ParseVFuncId(FunctionSummary::VFuncId &VFuncId,
IdToIndexMapType &IdToIndexMap, unsigned Index); IdToIndexMapType &IdToIndexMap, unsigned Index);
bool ParseOptionalVTableFuncs(VTableFuncList &VTableFuncs); bool ParseOptionalVTableFuncs(VTableFuncList &VTableFuncs);
bool ParseOptionalParamAccesses(
std::vector<FunctionSummary::ParamAccess> &Params);
bool ParseParamNo(uint64_t &ParamNo);
bool ParseParamAccess(FunctionSummary::ParamAccess &Param);
bool ParseParamAccessCall(FunctionSummary::ParamAccess::Call &Call);
bool ParseParamAccessOffset(ConstantRange &range);
bool ParseOptionalRefs(std::vector<ValueInfo> &Refs); bool ParseOptionalRefs(std::vector<ValueInfo> &Refs);
bool ParseTypeIdEntry(unsigned ID); bool ParseTypeIdEntry(unsigned ID);
bool ParseTypeIdSummary(TypeIdSummary &TIS); bool ParseTypeIdSummary(TypeIdSummary &TIS);

View File

@ -391,6 +391,8 @@ enum Kind {
kw_alwaysInline, kw_alwaysInline,
kw_calls, kw_calls,
kw_callee, kw_callee,
kw_params,
kw_param,
kw_hotness, kw_hotness,
kw_unknown, kw_unknown,
kw_hot, kw_hot,

View File

@ -306,6 +306,7 @@ static Optional<const char *> GetCodeName(unsigned CodeID, unsigned BlockID,
STRINGIFY_CODE(FS, TYPE_ID) STRINGIFY_CODE(FS, TYPE_ID)
STRINGIFY_CODE(FS, TYPE_ID_METADATA) STRINGIFY_CODE(FS, TYPE_ID_METADATA)
STRINGIFY_CODE(FS, BLOCK_COUNT) STRINGIFY_CODE(FS, BLOCK_COUNT)
STRINGIFY_CODE(FS, PARAM_ACCESS)
} }
case bitc::METADATA_ATTACHMENT_ID: case bitc::METADATA_ATTACHMENT_ID:
switch (CodeID) { switch (CodeID) {

View File

@ -5804,6 +5804,41 @@ static void parseTypeIdSummaryRecord(ArrayRef<uint64_t> Record,
parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId); parseWholeProgramDevirtResolution(Record, Strtab, Slot, TypeId);
} }
static std::vector<FunctionSummary::ParamAccess>
parseParamAccesses(ArrayRef<uint64_t> Record) {
auto ReadRange = [&]() {
APInt Lower(FunctionSummary::ParamAccess::RangeWidth,
BitcodeReader::decodeSignRotatedValue(Record.front()));
Record = Record.drop_front();
APInt Upper(FunctionSummary::ParamAccess::RangeWidth,
BitcodeReader::decodeSignRotatedValue(Record.front()));
Record = Record.drop_front();
ConstantRange Range{Lower, Upper};
assert(!Range.isFullSet());
assert(!Range.isUpperSignWrapped());
return Range;
};
std::vector<FunctionSummary::ParamAccess> PendingParamAccesses;
while (!Record.empty()) {
PendingParamAccesses.emplace_back();
FunctionSummary::ParamAccess &ParamAccess = PendingParamAccesses.back();
ParamAccess.ParamNo = Record.front();
Record = Record.drop_front();
ParamAccess.Use = ReadRange();
ParamAccess.Calls.resize(Record.front());
Record = Record.drop_front();
for (auto &Call : ParamAccess.Calls) {
Call.ParamNo = Record.front();
Record = Record.drop_front();
Call.Callee = Record.front();
Record = Record.drop_front();
Call.Offsets = ReadRange();
}
}
return PendingParamAccesses;
}
void ModuleSummaryIndexBitcodeReader::parseTypeIdCompatibleVtableInfo( void ModuleSummaryIndexBitcodeReader::parseTypeIdCompatibleVtableInfo(
ArrayRef<uint64_t> Record, size_t &Slot, ArrayRef<uint64_t> Record, size_t &Slot,
TypeIdCompatibleVtableInfo &TypeId) { TypeIdCompatibleVtableInfo &TypeId) {
@ -5881,6 +5916,7 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
PendingTypeCheckedLoadVCalls; PendingTypeCheckedLoadVCalls;
std::vector<FunctionSummary::ConstVCall> PendingTypeTestAssumeConstVCalls, std::vector<FunctionSummary::ConstVCall> PendingTypeTestAssumeConstVCalls,
PendingTypeCheckedLoadConstVCalls; PendingTypeCheckedLoadConstVCalls;
std::vector<FunctionSummary::ParamAccess> PendingParamAccesses;
while (true) { while (true) {
Expected<BitstreamEntry> MaybeEntry = Stream.advanceSkippingSubblocks(); Expected<BitstreamEntry> MaybeEntry = Stream.advanceSkippingSubblocks();
@ -5979,7 +6015,8 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeTestAssumeVCalls),
std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeCheckedLoadVCalls),
std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeTestAssumeConstVCalls),
std::move(PendingTypeCheckedLoadConstVCalls)); std::move(PendingTypeCheckedLoadConstVCalls),
std::move(PendingParamAccesses));
auto VIAndOriginalGUID = getValueInfoFromValueId(ValueID); auto VIAndOriginalGUID = getValueInfoFromValueId(ValueID);
FS->setModulePath(getThisModule()->first()); FS->setModulePath(getThisModule()->first());
FS->setOriginalName(VIAndOriginalGUID.second); FS->setOriginalName(VIAndOriginalGUID.second);
@ -6121,7 +6158,8 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
std::move(PendingTypeTestAssumeVCalls), std::move(PendingTypeTestAssumeVCalls),
std::move(PendingTypeCheckedLoadVCalls), std::move(PendingTypeCheckedLoadVCalls),
std::move(PendingTypeTestAssumeConstVCalls), std::move(PendingTypeTestAssumeConstVCalls),
std::move(PendingTypeCheckedLoadConstVCalls)); std::move(PendingTypeCheckedLoadConstVCalls),
std::move(PendingParamAccesses));
LastSeenSummary = FS.get(); LastSeenSummary = FS.get();
LastSeenGUID = VI.getGUID(); LastSeenGUID = VI.getGUID();
FS->setModulePath(ModuleIdMap[ModuleId]); FS->setModulePath(ModuleIdMap[ModuleId]);
@ -6242,6 +6280,12 @@ Error ModuleSummaryIndexBitcodeReader::parseEntireSummary(unsigned ID) {
case bitc::FS_BLOCK_COUNT: case bitc::FS_BLOCK_COUNT:
TheIndex.addBlockCount(Record[0]); TheIndex.addBlockCount(Record[0]);
break;
case bitc::FS_PARAM_ACCESS: {
PendingParamAccesses = parseParamAccesses(Record);
break;
}
} }
} }
llvm_unreachable("Exit infinite loop"); llvm_unreachable("Exit infinite loop");

View File

@ -3576,6 +3576,29 @@ static void writeFunctionTypeMetadataRecords(BitstreamWriter &Stream,
FS->type_test_assume_const_vcalls()); FS->type_test_assume_const_vcalls());
WriteConstVCallVec(bitc::FS_TYPE_CHECKED_LOAD_CONST_VCALL, WriteConstVCallVec(bitc::FS_TYPE_CHECKED_LOAD_CONST_VCALL,
FS->type_checked_load_const_vcalls()); FS->type_checked_load_const_vcalls());
auto WriteRange = [&](ConstantRange Range) {
Range = Range.sextOrTrunc(FunctionSummary::ParamAccess::RangeWidth);
assert(Range.getLower().getNumWords() == 1);
assert(Range.getUpper().getNumWords() == 1);
emitSignedInt64(Record, *Range.getLower().getRawData());
emitSignedInt64(Record, *Range.getUpper().getRawData());
};
if (!FS->paramAccesses().empty()) {
Record.clear();
for (auto &Arg : FS->paramAccesses()) {
Record.push_back(Arg.ParamNo);
WriteRange(Arg.Use);
Record.push_back(Arg.Calls.size());
for (auto &Call : Arg.Calls) {
Record.push_back(Call.ParamNo);
Record.push_back(Call.Callee);
WriteRange(Call.Offsets);
}
}
Stream.EmitRecord(bitc::FS_PARAM_ACCESS, Record);
}
} }
/// Collect type IDs from type tests used by function. /// Collect type IDs from type tests used by function.

View File

@ -3083,6 +3083,36 @@ void AssemblyWriter::printFunctionSummary(const FunctionSummary *FS) {
if (const auto *TIdInfo = FS->getTypeIdInfo()) if (const auto *TIdInfo = FS->getTypeIdInfo())
printTypeIdInfo(*TIdInfo); printTypeIdInfo(*TIdInfo);
auto PrintRange = [&](const ConstantRange &Range) {
Out << "[" << Range.getLower() << ", " << Range.getSignedMax() << "]";
};
if (!FS->paramAccesses().empty()) {
Out << ", params: (";
FieldSeparator IFS;
for (auto &PS : FS->paramAccesses()) {
Out << IFS;
Out << "(param: " << PS.ParamNo;
Out << ", offset: ";
PrintRange(PS.Use);
if (!PS.Calls.empty()) {
Out << ", calls: (";
FieldSeparator IFS;
for (auto &Call : PS.Calls) {
Out << IFS;
Out << "(callee: ^" << Machine.getGUIDSlot(Call.Callee);
Out << ", param: " << Call.ParamNo;
Out << ", offset: ";
PrintRange(Call.Offsets);
Out << ")";
}
Out << ")";
}
Out << ")";
}
Out << ")";
}
} }
void AssemblyWriter::printTypeIdInfo( void AssemblyWriter::printTypeIdInfo(

View File

@ -35,6 +35,8 @@ static cl::opt<bool> ImportConstantsWithRefs(
"import-constants-with-refs", cl::init(true), cl::Hidden, "import-constants-with-refs", cl::init(true), cl::Hidden,
cl::desc("Import constant global variables with references")); cl::desc("Import constant global variables with references"));
constexpr uint32_t FunctionSummary::ParamAccess::RangeWidth;
FunctionSummary FunctionSummary::ExternalNode = FunctionSummary FunctionSummary::ExternalNode =
FunctionSummary::makeDummyFunctionSummary({}); FunctionSummary::makeDummyFunctionSummary({});

View File

@ -0,0 +1,255 @@
; REQUIRES: aarch64-registered-target
; For convenience, to show what is being serialized.
; RUN: opt -S -passes="print<stack-safety-local>" -disable-output < %s 2>&1 | FileCheck %s --check-prefixes=SSI
; RUN: opt -module-summary %s -o %t.bc
; RUN: llvm-bcanalyzer -dump %t.bc | FileCheck %s -check-prefixes=BC
; RUN: llvm-dis -o - %t.bc | FileCheck %s --check-prefix=DIS
; Round trip it through llvm-as
; RUN: llvm-dis -o - %t.bc | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=DIS
; RUN: opt -thinlto-bc %s -o %t.bc
; RUN: llvm-bcanalyzer -dump %t.bc | FileCheck %s -check-prefixes=BC
; RUN: llvm-dis -o - %t.bc | FileCheck %s --check-prefix=DIS
; Round trip it through llvm-as
; RUN: llvm-dis -o - %t.bc | llvm-as -o - | llvm-dis -o - | FileCheck %s --check-prefix=DIS
; DIS: ^0 = module: (path: "{{.*}}", hash: ({{.*}}))
; ModuleID = 'thinlto-function-summary-paramaccess.ll'
target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128"
target triple = "aarch64-unknown-linux"
attributes #0 = { noinline sanitize_memtag "target-features"="+mte,+neon" }
; BC-LABEL: <GLOBALVAL_SUMMARY_BLOCK
; BC-NEXT: <VERSION
; BC-NEXT: <FLAGS
; DIS-DAG: = gv: (name: "Callee") ; guid = 900789920918863816
declare void @Callee(i8* %p)
; DIS-DAG: = gv: (name: "Callee2") ; guid = 72710208629861106
declare void @Callee2(i32 %x, i8* %p)
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "NoParam", summaries: {{.*}} guid = 10287433468618421703
define void @NoParam() #0 {
entry:
ret void
}
; SSI-LABEL: function 'IntParam'
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "IntParam", summaries: {{.*}} guid = 13164714711077064397
define void @IntParam(i32 %x) #0 {
entry:
ret void
}
; SSI-LABEL: for function 'WriteNone'
; SSI: p[]: empty-set
; BC-NEXT: <PARAM_ACCESS op0=0 op1=0 op2=0 op3=0/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "WriteNone", summaries: {{.*}} params: ((param: 0, offset: [0, -1]))))) ; guid = 15261848357689602442
define void @WriteNone(i8* %p) #0 {
entry:
ret void
}
; SSI-LABEL: for function 'Write0'
; SSI: p[]: [0,1)
; BC-NEXT: <PARAM_ACCESS op0=0 op1=0 op2=2 op3=0/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "Write0", summaries: {{.*}} params: ((param: 0, offset: [0, 0]))))) ; guid = 5540766144860458461
define void @Write0(i8* %p) #0 {
entry:
store i8 0, i8* %p
ret void
}
; SSI-LABEL: for function 'WriteOffset'
; SSI: p[]: [12,16)
; BC-NEXT: <PARAM_ACCESS op0=0 op1=24 op2=32 op3=0/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "WriteOffset", summaries: {{.*}} params: ((param: 0, offset: [12, 15]))))) ; guid = 1417835201204712148
define void @WriteOffset(i8* %p) #0 {
entry:
%0 = bitcast i8* %p to i32*
%1 = getelementptr i32, i32* %0, i64 3
store i32 0, i32* %1
ret void
}
; SSI-LABEL: for function 'WriteNegOffset'
; SSI: p[]: [-56,-48)
; BC-NEXT: <PARAM_ACCESS op0=0 op1=113 op2=97 op3=0/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "WriteNegOffset", summaries: {{.*}} params: ((param: 0, offset: [-56, -49]))))) ; guid = 11847411556962310546
define void @WriteNegOffset(i8* %p) #0 {
entry:
%0 = bitcast i8* %p to i64*
%1 = getelementptr i64, i64* %0, i64 -7
store i64 0, i64* %1
ret void
}
; SSI-LABEL: for function 'WriteAnyOffset'
; SSI: p[]: [-9223372036854775808,9223372036854775807)
; BC-NEXT: <PARAM_ACCESS op0=0 op1=1 op2=-2 op3=0/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "WriteAnyOffset", summaries: {{.*}} params: ((param: 0, offset: [-9223372036854775808, 9223372036854775806]))))) ; guid = 16159595372881907190
define void @WriteAnyOffset(i8* %p, i64 %i) #0 {
entry:
%0 = bitcast i8* %p to i24*
%1 = getelementptr i24, i24* %0, i64 %i
store i24 0, i24* %1
ret void
}
; SSI-LABEL: for function 'WritePQ'
; SSI: p[]: [0,1)
; SSI: q[]: [0,4)
; BC-NEXT: <PARAM_ACCESS op0=0 op1=0 op2=2 op3=0 op4=1 op5=0 op6=8 op7=0/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "WritePQ", summaries: {{.*}} params: ((param: 0, offset: [0, 0]), (param: 1, offset: [0, 3]))))) ; guid = 6187077497926519485
define void @WritePQ(i8* %p, i32* %q) #0 {
entry:
store i8 5, i8* %p
store i32 6, i32* %q
ret void
}
; SSI-LABEL: for function 'WriteTwoPIQ'
; SSI: p[]: [0,1)
; SSI: q[]: [0,4)
; BC-NEXT: <PARAM_ACCESS op0=0 op1=0 op2=2 op3=0 op4=2 op5=0 op6=8 op7=0/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "WriteTwoPIQ", summaries: {{.*}} params: ((param: 0, offset: [0, 0]), (param: 2, offset: [0, 3]))))) ; guid = 2949024673554120799
define void @WriteTwoPIQ(i8* %p, i32 %i, i32* %q) #0 {
entry:
store i8 7, i8* %p
store i32 %i, i32* %q
ret void
}
; SSI-LABEL: for function 'Call'
; SSI: p[]: empty-set, @Callee(arg0, [0,1))
; BC-NEXT: <PARAM_ACCESS op0=0 op1=0 op2=0 op3=1 op4=0 op5=[[CALLEE:-?[0-9]+]] op6=0 op7=2/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "Call", summaries: {{.*}} calls: ((callee: ^{{.*}})), params: ((param: 0, offset: [0, -1], calls: ((callee: ^{{.*}}, param: 0, offset: [0, 0]))))))) ; guid = 8411925997558855107
define void @Call(i8* %p) #0 {
entry:
call void @Callee(i8* %p)
ret void
}
; SSI-LABEL: for function 'CallOffset'
; SSI: p[]: empty-set, @Callee(arg0, [2,3))
; BC-NEXT: <PARAM_ACCESS op0=0 op1=0 op2=0 op3=1 op4=0 op5=[[CALLEE]] op6=4 op7=6/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "CallOffset", summaries: {{.*}} calls: ((callee: ^{{.*}})), params: ((param: 0, offset: [0, -1], calls: ((callee: ^{{.*}}, param: 0, offset: [2, 2]))))))) ; guid = 1075564720951610524
define void @CallOffset(i8* %p) #0 {
entry:
%p1 = getelementptr i8, i8* %p, i64 2
call void @Callee(i8* %p1)
ret void
}
; SSI-LABEL: for function 'CallNegOffset'
; SSI: p[]: empty-set, @Callee(arg0, [-715,-714))
; BC-NEXT: <PARAM_ACCESS op0=0 op1=0 op2=0 op3=1 op4=0 op5=[[CALLEE]] op6=1431 op7=1429/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "CallNegOffset", summaries: {{.*}} calls: ((callee: ^{{.*}})), params: ((param: 0, offset: [0, -1], calls: ((callee: ^{{.*}}, param: 0, offset: [-715, -715]))))))) ; guid = 16532891468562335146
define void @CallNegOffset(i8* %p) #0 {
entry:
%p1 = getelementptr i8, i8* %p, i64 -715
call void @Callee(i8* %p1)
ret void
}
; BC-NEXT: <PERMODULE
; SSI-LABEL: for function 'CallAnyOffset'
; SSI: p[]: empty-set, @Callee(arg0, full-set)
; DIS-DAG: = gv: (name: "CallAnyOffset", summaries: {{.*}} calls: ((callee: ^{{.*}}))))) ; guid = 4179978066780831873
define void @CallAnyOffset(i8* %p, i64 %i) #0 {
entry:
%p1 = getelementptr i8, i8* %p, i64 %i
call void @Callee(i8* %p1)
ret void
}
; SSI-LABEL: for function 'CallMany'
; SSI: p[]: empty-set, @Callee(arg0, [-715,-714)), @Callee(arg0, [-33,-32)), @Callee(arg0, [124,125))
; BC-NEXT: <PARAM_ACCESS op0=0 op1=0 op2=0 op3=3 op4=0 op5=[[CALLEE]] op6=1431 op7=1429 op8=0 op9=[[CALLEE]] op10=67 op11=65 op12=0 op13=[[CALLEE]] op14=248 op15=250/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "CallMany", summaries: {{.*}} calls: ((callee: ^{{.*}})), params: ((param: 0, offset: [0, -1], calls: ((callee: ^{{.*}}, param: 0, offset: [-715, -715]), (callee: ^{{.*}}, param: 0, offset: [-33, -33]), (callee: ^{{.*}}, param: 0, offset: [124, 124]))))))) ; guid = 17150418543861409076
define void @CallMany(i8* %p) #0 {
entry:
%p0 = getelementptr i8, i8* %p, i64 -715
call void @Callee(i8* %p0)
%p1 = getelementptr i8, i8* %p, i64 -33
call void @Callee(i8* %p1)
%p2 = getelementptr i8, i8* %p, i64 124
call void @Callee(i8* %p2)
ret void
}
; SSI-LABEL: for function 'CallMany2'
; SSI: p[]: empty-set, @Callee(arg0, [-715,-714)), @Callee2(arg1, [-33,-32)), @Callee(arg0, [124,125))
; BC-NEXT: <PARAM_ACCESS op0=0 op1=0 op2=0 op3=3 op4=0 op5=[[CALLEE]] op6=1431 op7=1429 op8=1 op9=[[CALLEE2:-?[0-9]+]] op10=67 op11=65 op12=0 op13=[[CALLEE]] op14=248 op15=250/>
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "CallMany2", summaries: {{.*}} calls: ((callee: ^{{.*}}), (callee: ^{{.*}})), params: ((param: 0, offset: [0, -1], calls: ((callee: ^{{.*}}, param: 0, offset: [-715, -715]), (callee: ^{{.*}}, param: 1, offset: [-33, -33]), (callee: ^{{.*}}, param: 0, offset: [124, 124]))))))) ; guid = 16654048340802466690
define void @CallMany2(i8* %p) #0 {
entry:
%p0 = getelementptr i8, i8* %p, i64 -715
call void @Callee(i8* %p0)
%p1 = getelementptr i8, i8* %p, i64 -33
call void @Callee2(i32 6, i8* %p1)
%p2 = getelementptr i8, i8* %p, i64 124
call void @Callee(i8* %p2)
ret void
}
; SSI-LABEL: for function 'CallManyUnsafe'
; SSI: p[]: full-set, @Callee(arg0, [-715,-714)), @Callee(arg0, [-33,-32)), @Callee(arg0, [124,125))
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "CallManyUnsafe", summaries: {{.*}} calls: ((callee: ^{{.*}}))))) ; guid = 15696680128757863301
define void @CallManyUnsafe(i8* %p, i64 %i) #0 {
entry:
%pi = getelementptr i8, i8* %p, i64 %i
store i8 5, i8* %pi
%p0 = getelementptr i8, i8* %p, i64 -715
call void @Callee(i8* %p0)
%p1 = getelementptr i8, i8* %p, i64 -33
call void @Callee(i8* %p1)
%p2 = getelementptr i8, i8* %p, i64 124
call void @Callee(i8* %p2)
ret void
}
; SSI-LABEL: for function 'Ret'
; SSI: p[]: full-set
; BC-NEXT: <PERMODULE
; DIS-DAG: = gv: (name: "Ret", summaries: {{.*}} ; guid = 6707380319572075172
define i8* @Ret(i8* %p) #0 {
entry:
ret i8* %p
}
; BC-NOT: <PERMODULE
; BC-NOT: <PARAM_ACCESS1