8#ifndef FRONTENDS_P4_INLINING_H_
9#define FRONTENDS_P4_INLINING_H_
11#include "commonInlining.h"
12#include "frontends/common/parser_options.h"
13#include "frontends/common/resolveReferences/referenceMap.h"
14#include "frontends/p4/evaluator/evaluator.h"
15#include "frontends/p4/evaluator/substituteParameters.h"
16#include "frontends/p4/typeChecking/typeChecker.h"
17#include "frontends/p4/unusedDeclarations.h"
19#include "lib/ordered_map.h"
29 const IR::IContainer *caller;
30 const IR::IContainer *callee;
31 const IR::Declaration_Instance *instantiation;
33 std::set<const IR::MethodCallStatement *> invocations;
35 CallInfo(
const IR::IContainer *caller,
const IR::IContainer *callee,
36 const IR::Declaration_Instance *instantiation)
37 : caller(caller), callee(callee), instantiation(instantiation) {
40 CHECK_NULL(instantiation);
42 void addInvocation(
const IR::MethodCallStatement *statement) { invocations.emplace(statement); }
43 void dbprint(std::ostream &out)
const {
44 out <<
"Inline " << callee <<
" into " << caller <<
" with " << invocations.size()
50 std::map<const IR::IDeclaration *, cstring> internalName;
51 std::map<const IR::IDeclaration *, cstring> externalName;
56 BUG_CHECK(!name.isNullOrEmpty() && !extName.isNullOrEmpty(),
"Empty name");
57 LOG3(
"setNewName " << dbp(decl) <<
" to " << name);
58 if (internalName.find(decl) != internalName.end()) BUG(
"%1%: already renamed", decl);
59 internalName.emplace(decl, name);
60 externalName.emplace(decl, extName);
64 BUG_CHECK(internalName.find(decl) != internalName.end(),
"%1%: no new name", decl);
65 auto result = ::P4::get(internalName, decl);
70 BUG_CHECK(externalName.find(decl) != externalName.end(),
"%1%: no external name", decl);
71 auto result = ::P4::get(externalName, decl);
76 return internalName.find(decl) != internalName.end();
80struct PerInstanceSubstitutions {
84 PerInstanceSubstitutions() =
default;
85 PerInstanceSubstitutions(
const PerInstanceSubstitutions &other)
86 : paramSubst(other.paramSubst), tvs(other.tvs), renameMap(other.renameMap) {}
123 typedef std::pair<const IR::MethodCallStatement *, const IR::PathExpression *>
133 std::ostringstream oss;
134 std::get<0>(k)->dbprint(oss);
135 std::get<1>(k)->dbprint(oss);
136 return std::hash<std::string>{}(oss.str());
148 return std::get<0>(v0)->equiv(*std::get<0>(v1)) &&
149 std::get<1>(v0)->equiv(*std::get<1>(v1));
154 std::map<const IR::Declaration_Instance *, const IR::IContainer *>
declToCallee;
156 std::map<const IR::Declaration_Instance *, PerInstanceSubstitutions *>
substitutions;
158 std::map<const IR::MethodCallStatement *, const IR::Declaration_Instance *>
callToInstance;
268 std::unordered_map<const InlinedInvocationInfo, const IR::ID, key_hash, key_equal>
274 const IR::Declaration_Instance *instance)
const {
275 const IR::MethodCallStatement *call =
nullptr;
277 if (m.second == instance) {
287 std::map<const IR::IContainer *, PerCaller> callerToWork;
290 callerToWork[cci->caller].declToCallee[cci->instantiation] = cci->callee;
291 for (
auto mcs : cci->invocations)
292 callerToWork[cci->caller].callToInstance[mcs] = cci->instantiation;
294 void dbprint(std::ostream &out)
const {
295 out <<
"Inline " << callerToWork.size() <<
" call sites";
303 std::vector<CallInfo *> toInline;
304 const bool allowMultipleCalls =
true;
307 void addInstantiation(
const IR::IContainer *caller,
const IR::IContainer *callee,
308 const IR::Declaration_Instance *instantiation) {
311 CHECK_NULL(instantiation);
312 LOG3(
"Inline instantiation " << dbp(instantiation));
313 auto inst =
new CallInfo(caller, callee, instantiation);
314 inlineMap[instantiation] = inst;
317 size_t size()
const {
return inlineMap.size(); }
319 void addInvocation(
const IR::Declaration_Instance *instance,
320 const IR::MethodCallStatement *statement) {
321 CHECK_NULL(instance);
322 CHECK_NULL(statement);
323 LOG3(
"Inline invocation " << dbp(instance) <<
" at " << dbp(statement));
324 auto info = inlineMap[instance];
325 BUG_CHECK(
info,
"Could not locate instance %1% invoked by %2%", instance, statement);
326 info->addInvocation(statement);
329 void replace(
const IR::IContainer *container,
const IR::IContainer *replacement) {
330 CHECK_NULL(container);
331 CHECK_NULL(replacement);
332 LOG3(
"Replacing " << dbp(container) <<
" with " << dbp(replacement));
333 for (
auto e : toInline) {
334 if (e->callee == container) e->callee = replacement;
335 if (e->caller == container) e->caller = replacement;
349 IR::ToplevelBlock *toplevel;
352 bool allowParsers =
true;
353 bool allowControls =
true;
357 : inlineList(inlineList),
360 evaluator(evaluator),
362 CHECK_NULL(inlineList);
365 CHECK_NULL(evaluator);
366 setName(
"DiscoverInlining");
367 visitDagOnce =
false;
370 toplevel = evaluator->getToplevelBlock();
371 CHECK_NULL(toplevel);
372 return Inspector::init_apply(node);
374 void visit_all(
const IR::Block *block);
375 bool preorder(
const IR::Block *block)
override {
379 bool preorder(
const IR::ControlBlock *block)
override;
380 bool preorder(
const IR::ParserBlock *block)
override;
381 void postorder(
const IR::MethodCallStatement *statement)
override;
383 bool preorder(
const IR::P4Program *)
override {
390class GeneralInliner :
public AbstractInliner<InlineList, InlineSummary> {
394 bool optimizeParserInlining;
397 explicit GeneralInliner(
ReferenceMap *refMap,
bool _optimizeParserInlining)
401 optimizeParserInlining(_optimizeParserInlining) {
402 setName(
"GeneralInliner");
403 visitDagOnce =
false;
406 const IR::Node *preorder(IR::MethodCallStatement *statement)
override;
411 template <
class P4Block,
class P4BlockType>
413 const P4BlockType *P4Block::*blockType);
414 const IR::Node *preorder(IR::P4Control *caller)
override;
415 const IR::Node *preorder(IR::P4Parser *caller)
override;
416 const IR::Node *preorder(IR::ParserState *state)
override;
421class InlinePass :
public PassManager {
432 setName(
"InlinePass");
441class Inline :
public PassManager {
442 static std::set<cstring> noPropagateAnnotations;
449 auto *evInstance = evaluator ? evaluator :
new EvaluatorPass(&refMap, typeMap);
453 {
new InlinePass(&refMap, typeMap, evInstance, policy, optimizeParserInlining),
Must be run after an evaluator; uses the blocks to discover caller/callee relationships.
Definition inlining.h:344
Definition evaluator.h:115
Performs actual inlining work.
Definition inlining.h:390
void inline_subst(P4Block *caller, IR::IndexedVector< IR::Declaration > P4Block::*blockLocals, const P4BlockType *P4Block::*blockType)
Definition inlining.cpp:444
Definition evaluator.h:28
Definition stringify.h:33
The Declaration interface, representing objects with names.
Definition declaration.h:17
Definition indexed_vector.h:31
Definition commonInlining.h:169
static bool isAnnotationNoPropagate(cstring name)
Is annotation name excluded from inline propagation?
Definition inlining.h:465
static void setAnnotationNoPropagate(cstring name)
Do not propagate annotation name during inlining.
Definition inlining.h:462
Definition inlining.h:300
Performs one round of inlining bottoms-up.
Definition inlining.h:421
static P4CContext & get()
Definition parser_options.cpp:523
Definition parameterSubstitution.h:30
Definition ir/pass_manager.h:146
Class used to encode maps from paths to declarations.
Definition referenceMap.h:67
void setIsV1(bool isv1)
Set boolean indicating whether map is for a P4_14 program to isV1.
Definition referenceMap.h:106
Iterates UnusedDeclarations until convergence.
Definition unusedDeclarations.h:196
Definition unusedDeclarations.h:48
Definition typeChecker.h:55
Definition typeSubstitution.h:64
Definition ordered_map.h:32
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:13
void info(const int kind, const char *format, const T *node, Args &&...args)
Report info messages of type kind. Requires that the node argument have source info.
Definition lib/error.h:167
Describes information about a caller-callee pair.
Definition inlining.h:28
Definition inlining.h:145
Definition inlining.h:131
Various substitutions that must be applied for each instance.
Definition inlining.h:94
const IR::MethodCallStatement * uniqueCaller(const IR::Declaration_Instance *instance) const
Definition inlining.h:273
std::map< const IR::Declaration_Instance *, const IR::IContainer * > declToCallee
For each instance (key) the container that is intantiated.
Definition inlining.h:154
std::unordered_map< const InlinedInvocationInfo, const IR::ID, key_hash, key_equal > invocationToState
Definition inlining.h:269
std::map< const IR::MethodCallStatement *, const IR::Declaration_Instance * > callToInstance
For each invocation (key) call the instance that is invoked.
Definition inlining.h:158
std::map< const IR::Declaration_Instance *, PerInstanceSubstitutions * > substitutions
For each instance (key) we must apply a bunch of substitutions.
Definition inlining.h:156
std::pair< const IR::MethodCallStatement *, const IR::PathExpression * > InlinedInvocationInfo
Definition inlining.h:124
Summarizes all inline operations to be performed.
Definition inlining.h:92