[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
diff --git a/llvm/lib/AsmParser/LLLexer.cpp b/llvm/lib/AsmParser/LLLexer.cpp
index eb1209a..2a39e19 100644
--- a/llvm/lib/AsmParser/LLLexer.cpp
+++ b/llvm/lib/AsmParser/LLLexer.cpp
@@ -758,6 +758,8 @@
KEYWORD(alwaysInline);
KEYWORD(calls);
KEYWORD(callee);
+ KEYWORD(params);
+ KEYWORD(param);
KEYWORD(hotness);
KEYWORD(unknown);
KEYWORD(hot);
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index fb6e61f..117ec2c 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -11,6 +11,8 @@
//===----------------------------------------------------------------------===//
#include "LLParser.h"
+#include "LLToken.h"
+#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/None.h"
#include "llvm/ADT/STLExtras.h"
@@ -22,6 +24,7 @@
#include "llvm/IR/BasicBlock.h"
#include "llvm/IR/CallingConv.h"
#include "llvm/IR/Comdat.h"
+#include "llvm/IR/ConstantRange.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/DebugInfoMetadata.h"
#include "llvm/IR/DerivedTypes.h"
@@ -8209,7 +8212,8 @@
/// FunctionSummary
/// ::= 'function' ':' '(' 'module' ':' ModuleReference ',' GVFlags
/// ',' 'insts' ':' UInt32 [',' OptionalFFlags]? [',' OptionalCalls]?
-/// [',' OptionalTypeIdInfo]? [',' OptionalRefs]? ')'
+/// [',' OptionalTypeIdInfo]? [',' OptionalParamAccesses]?
+/// [',' OptionalRefs]? ')'
bool LLParser::ParseFunctionSummary(std::string Name, GlobalValue::GUID GUID,
unsigned ID) {
assert(Lex.getKind() == lltok::kw_function);
@@ -8222,6 +8226,7 @@
unsigned InstCount;
std::vector<FunctionSummary::EdgeTy> Calls;
FunctionSummary::TypeIdInfo TypeIdInfo;
+ std::vector<FunctionSummary::ParamAccess> ParamAccesses;
std::vector<ValueInfo> Refs;
// Default is all-zeros (conservative values).
FunctionSummary::FFlags FFlags = {};
@@ -8253,6 +8258,10 @@
if (ParseOptionalRefs(Refs))
return true;
break;
+ case lltok::kw_params:
+ if (ParseOptionalParamAccesses(ParamAccesses))
+ return true;
+ break;
default:
return Error(Lex.getLoc(), "expected optional function summary field");
}
@@ -8267,7 +8276,8 @@
std::move(TypeIdInfo.TypeTestAssumeVCalls),
std::move(TypeIdInfo.TypeCheckedLoadVCalls),
std::move(TypeIdInfo.TypeTestAssumeConstVCalls),
- std::move(TypeIdInfo.TypeCheckedLoadConstVCalls));
+ std::move(TypeIdInfo.TypeCheckedLoadConstVCalls),
+ std::move(ParamAccesses));
FS->setModulePath(ModulePath);
@@ -8616,13 +8626,133 @@
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
/// := 'refs' ':' '(' GVReference [',' GVReference]* ')'
bool LLParser::ParseOptionalRefs(std::vector<ValueInfo> &Refs) {
assert(Lex.getKind() == lltok::kw_refs);
Lex.Lex();
- if (ParseToken(lltok::colon, "expected ':' in refs") |
+ if (ParseToken(lltok::colon, "expected ':' in refs") ||
ParseToken(lltok::lparen, "expected '(' in refs"))
return true;
diff --git a/llvm/lib/AsmParser/LLParser.h b/llvm/lib/AsmParser/LLParser.h
index be23ba4..cc3aae6 100644
--- a/llvm/lib/AsmParser/LLParser.h
+++ b/llvm/lib/AsmParser/LLParser.h
@@ -365,6 +365,12 @@
bool ParseVFuncId(FunctionSummary::VFuncId &VFuncId,
IdToIndexMapType &IdToIndexMap, unsigned Index);
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 ParseTypeIdEntry(unsigned ID);
bool ParseTypeIdSummary(TypeIdSummary &TIS);
diff --git a/llvm/lib/AsmParser/LLToken.h b/llvm/lib/AsmParser/LLToken.h
index a8b4ad9..0c190bf 100644
--- a/llvm/lib/AsmParser/LLToken.h
+++ b/llvm/lib/AsmParser/LLToken.h
@@ -391,6 +391,8 @@
kw_alwaysInline,
kw_calls,
kw_callee,
+ kw_params,
+ kw_param,
kw_hotness,
kw_unknown,
kw_hot,