17#ifndef FRONTENDS_P4_INLINING_H_
18#define FRONTENDS_P4_INLINING_H_
20#include "commonInlining.h"
21#include "frontends/common/resolveReferences/referenceMap.h"
22#include "frontends/p4/evaluator/evaluator.h"
23#include "frontends/p4/evaluator/substituteParameters.h"
24#include "frontends/p4/typeChecking/typeChecker.h"
25#include "frontends/p4/unusedDeclarations.h"
27#include "lib/ordered_map.h"
37 const IR::IContainer *caller;
38 const IR::IContainer *callee;
39 const IR::Declaration_Instance *instantiation;
41 std::set<const IR::MethodCallStatement *> invocations;
43 CallInfo(
const IR::IContainer *caller,
const IR::IContainer *callee,
44 const IR::Declaration_Instance *instantiation)
45 : caller(caller), callee(callee), instantiation(instantiation) {
48 CHECK_NULL(instantiation);
50 void addInvocation(
const IR::MethodCallStatement *statement) { invocations.emplace(statement); }
51 void dbprint(std::ostream &out)
const {
52 out <<
"Inline " << callee <<
" into " << caller <<
" with " << invocations.size()
58 std::map<const IR::IDeclaration *, cstring> internalName;
59 std::map<const IR::IDeclaration *, cstring> externalName;
64 BUG_CHECK(!name.isNullOrEmpty() && !extName.isNullOrEmpty(),
"Empty name");
65 LOG3(
"setNewName " << dbp(decl) <<
" to " << name);
66 if (internalName.find(decl) != internalName.end()) BUG(
"%1%: already renamed", decl);
67 internalName.emplace(decl, name);
68 externalName.emplace(decl, extName);
72 BUG_CHECK(internalName.find(decl) != internalName.end(),
"%1%: no new name", decl);
73 auto result = ::P4::get(internalName, decl);
78 BUG_CHECK(externalName.find(decl) != externalName.end(),
"%1%: no external name", decl);
79 auto result = ::P4::get(externalName, decl);
84 return internalName.find(decl) != internalName.end();
88struct PerInstanceSubstitutions {
92 PerInstanceSubstitutions() =
default;
93 PerInstanceSubstitutions(
const PerInstanceSubstitutions &other)
94 : paramSubst(other.paramSubst), tvs(other.tvs), renameMap(other.renameMap) {}
131 typedef std::pair<const IR::MethodCallStatement *, const IR::PathExpression *>
141 std::ostringstream oss;
142 std::get<0>(k)->dbprint(oss);
143 std::get<1>(k)->dbprint(oss);
144 return std::hash<std::string>{}(oss.str());
156 return std::get<0>(v0)->equiv(*std::get<0>(v1)) &&
157 std::get<1>(v0)->equiv(*std::get<1>(v1));
162 std::map<const IR::Declaration_Instance *, const IR::IContainer *>
declToCallee;
164 std::map<const IR::Declaration_Instance *, PerInstanceSubstitutions *>
substitutions;
166 std::map<const IR::MethodCallStatement *, const IR::Declaration_Instance *>
callToInstance;
276 std::unordered_map<const InlinedInvocationInfo, const IR::ID, key_hash, key_equal>
282 const IR::Declaration_Instance *instance)
const {
283 const IR::MethodCallStatement *call =
nullptr;
285 if (m.second == instance) {
295 std::map<const IR::IContainer *, PerCaller> callerToWork;
298 callerToWork[cci->caller].declToCallee[cci->instantiation] = cci->callee;
299 for (
auto mcs : cci->invocations)
300 callerToWork[cci->caller].callToInstance[mcs] = cci->instantiation;
302 void dbprint(std::ostream &out)
const {
303 out <<
"Inline " << callerToWork.size() <<
" call sites";
311 std::vector<CallInfo *> toInline;
312 const bool allowMultipleCalls =
true;
315 void addInstantiation(
const IR::IContainer *caller,
const IR::IContainer *callee,
316 const IR::Declaration_Instance *instantiation) {
319 CHECK_NULL(instantiation);
320 LOG3(
"Inline instantiation " << dbp(instantiation));
321 auto inst =
new CallInfo(caller, callee, instantiation);
322 inlineMap[instantiation] = inst;
325 size_t size()
const {
return inlineMap.size(); }
327 void addInvocation(
const IR::Declaration_Instance *instance,
328 const IR::MethodCallStatement *statement) {
329 CHECK_NULL(instance);
330 CHECK_NULL(statement);
331 LOG3(
"Inline invocation " << dbp(instance) <<
" at " << dbp(statement));
332 auto info = inlineMap[instance];
333 BUG_CHECK(
info,
"Could not locate instance %1% invoked by %2%", instance, statement);
334 info->addInvocation(statement);
337 void replace(
const IR::IContainer *container,
const IR::IContainer *replacement) {
338 CHECK_NULL(container);
339 CHECK_NULL(replacement);
340 LOG3(
"Replacing " << dbp(container) <<
" with " << dbp(replacement));
341 for (
auto e : toInline) {
342 if (e->callee == container) e->callee = replacement;
343 if (e->caller == container) e->caller = replacement;
357 IR::ToplevelBlock *toplevel;
360 bool allowParsers =
true;
361 bool allowControls =
true;
365 : inlineList(inlineList),
368 evaluator(evaluator),
370 CHECK_NULL(inlineList);
373 CHECK_NULL(evaluator);
374 setName(
"DiscoverInlining");
375 visitDagOnce =
false;
378 toplevel = evaluator->getToplevelBlock();
379 CHECK_NULL(toplevel);
380 return Inspector::init_apply(node);
382 void visit_all(
const IR::Block *block);
383 bool preorder(
const IR::Block *block)
override {
387 bool preorder(
const IR::ControlBlock *block)
override;
388 bool preorder(
const IR::ParserBlock *block)
override;
389 void postorder(
const IR::MethodCallStatement *statement)
override;
391 bool preorder(
const IR::P4Program *)
override {
398class GeneralInliner :
public AbstractInliner<InlineList, InlineSummary> {
402 bool optimizeParserInlining;
405 explicit GeneralInliner(
ReferenceMap *refMap,
bool _optimizeParserInlining)
409 optimizeParserInlining(_optimizeParserInlining) {
410 setName(
"GeneralInliner");
411 visitDagOnce =
false;
414 const IR::Node *preorder(IR::MethodCallStatement *statement)
override;
419 template <
class P4Block,
class P4BlockType>
421 const P4BlockType *P4Block::*blockType);
422 const IR::Node *preorder(IR::P4Control *caller)
override;
423 const IR::Node *preorder(IR::P4Parser *caller)
override;
424 const IR::Node *preorder(IR::ParserState *state)
override;
429class InlinePass :
public PassManager {
440 setName(
"InlinePass");
449class Inline :
public PassRepeated {
450 static std::set<cstring> noPropagateAnnotations;
Must be run after an evaluator; uses the blocks to discover caller/callee relationships.
Definition inlining.h:352
Definition evaluator.h:114
Performs actual inlining work.
Definition inlining.h:398
void inline_subst(P4Block *caller, IR::IndexedVector< IR::Declaration > P4Block::*blockLocals, const P4BlockType *P4Block::*blockType)
Definition inlining.cpp:461
Definition evaluator.h:27
Definition stringify.h:33
The Declaration interface, representing objects with names.
Definition declaration.h:26
Definition indexed_vector.h:40
Definition commonInlining.h:178
static bool isAnnotationNoPropagate(cstring name)
Is annotation name excluded from inline propagation?
Definition inlining.h:466
static void setAnnotationNoPropagate(cstring name)
Do not propagate annotation name during inlining.
Definition inlining.h:463
Definition inlining.h:308
Performs one round of inlining bottoms-up.
Definition inlining.h:429
Definition parameterSubstitution.h:30
Definition pass_manager.h:40
Class used to encode maps from paths to declarations.
Definition referenceMap.h:66
Iterates RemoveUnusedDeclarations until convergence.
Definition unusedDeclarations.h:146
Definition unusedDeclarations.h:28
Definition typeChecker.h:55
Definition typeSubstitution.h:73
Definition ordered_map.h:32
TODO: this is not really specific to BMV2, it should reside somewhere else.
Definition applyOptionsPragmas.cpp:24
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 error.h:148
Describes information about a caller-callee pair.
Definition inlining.h:36
Definition inlining.h:153
Definition inlining.h:139
Various substitutions that must be applied for each instance.
Definition inlining.h:102
const IR::MethodCallStatement * uniqueCaller(const IR::Declaration_Instance *instance) const
Definition inlining.h:281
std::map< const IR::Declaration_Instance *, const IR::IContainer * > declToCallee
For each instance (key) the container that is intantiated.
Definition inlining.h:162
std::unordered_map< const InlinedInvocationInfo, const IR::ID, key_hash, key_equal > invocationToState
Definition inlining.h:277
std::map< const IR::MethodCallStatement *, const IR::Declaration_Instance * > callToInstance
For each invocation (key) call the instance that is invoked.
Definition inlining.h:166
std::map< const IR::Declaration_Instance *, PerInstanceSubstitutions * > substitutions
For each instance (key) we must apply a bunch of substitutions.
Definition inlining.h:164
std::pair< const IR::MethodCallStatement *, const IR::PathExpression * > InlinedInvocationInfo
Definition inlining.h:132
Summarizes all inline operations to be performed.
Definition inlining.h:100