-
Notifications
You must be signed in to change notification settings - Fork 446
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Combo of duplication action name check and LocalizeAllActions fix #4975
base: main
Are you sure you want to change the base?
Changes from 46 commits
e429c8a
39538bf
98940fb
a2792ce
a553fe1
26f0501
da456fe
b683571
ad40fe9
91166c8
9acb7e0
b133b28
76bf24f
f7ec2fe
1cc8224
4b03eb5
93daba5
66a0a0a
083db34
99beb30
2b7c58a
54007df
d89f214
7424db3
55ad18f
799448a
377f41a
682564b
bb88b7d
d265e1c
606300e
6bcb614
55da2c3
d67df83
42c1dee
95dc4e2
efd0d52
4540f2a
39a9251
62fe180
b614ff9
968af1f
a2e913b
72827dd
b9a0ee9
019f3c6
bb50cc6
a840163
19956fc
e563b90
62ee2c1
c3feb19
31f0b10
bd31e6b
a853313
c111ab1
b542540
beb87b0
87feba6
e586849
381ec48
2f861cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
@@ -0,0 +1,99 @@ | ||||||
/* | ||||||
Copyright 2024 Cisco Systems, Inc. | ||||||
|
||||||
Licensed under the Apache License, Version 2.0 (the "License"); | ||||||
you may not use this file except in compliance with the License. | ||||||
You may obtain a copy of the License at | ||||||
|
||||||
http://www.apache.org/licenses/LICENSE-2.0 | ||||||
|
||||||
Unless required by applicable law or agreed to in writing, software | ||||||
distributed under the License is distributed on an "AS IS" BASIS, | ||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||||
See the License for the specific language governing permissions and | ||||||
limitations under the License. | ||||||
*/ | ||||||
|
||||||
#include "duplicateActionControlPlaneNameCheck.h" | ||||||
|
||||||
#include "lib/log.h" | ||||||
|
||||||
namespace P4 { | ||||||
|
||||||
cstring DuplicateActionControlPlaneNameCheck::getName(const IR::IDeclaration *decl) { | ||||||
return decl->getName(); | ||||||
} | ||||||
|
||||||
void DuplicateActionControlPlaneNameCheck::checkForDuplicateName(cstring name, | ||||||
const IR::Node *node) { | ||||||
bool foundDuplicate = false; | ||||||
auto *otherNode = node; | ||||||
auto [it, inserted] = actions.insert(std::pair(name, node)); | ||||||
if (!inserted) { | ||||||
foundDuplicate = true; | ||||||
otherNode = (*it).second; | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed in commit 57 |
||||||
} | ||||||
if (foundDuplicate) { | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could probably fold into There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed in commit 57 |
||||||
error(ErrorType::ERR_DUPLICATE, "%1%: conflicting control plane name: %2%", node, | ||||||
otherNode); | ||||||
} | ||||||
} | ||||||
|
||||||
const IR::Node *DuplicateActionControlPlaneNameCheck::postorder(IR::P4Action *action) { | ||||||
// Actions declared at the top level that the developer did not | ||||||
// write a @name annotation for it, should be included in the | ||||||
// duplicate name check. They do not yet have a @name annotation | ||||||
// by the time this pass executes, so this method will handle | ||||||
// such actions. | ||||||
if (findContext<IR::P4Control>() == nullptr) { | ||||||
auto annos = action->annotations; | ||||||
bool hasNameAnnotation = false; | ||||||
if (annos != nullptr) { | ||||||
auto nameAnno = annos->getSingle(IR::Annotation::nameAnnotation); | ||||||
if (nameAnno) { | ||||||
hasNameAnnotation = true; | ||||||
} | ||||||
} | ||||||
if (!hasNameAnnotation) { | ||||||
// name is what this top-level action's @name annotation | ||||||
// will be, after LocalizeAllActions pass adds one. | ||||||
cstring name = "." + action->name; | ||||||
checkForDuplicateName(name, action); | ||||||
} | ||||||
} | ||||||
return action; | ||||||
} | ||||||
|
||||||
const IR::Node *DuplicateActionControlPlaneNameCheck::postorder(IR::Annotation *annotation) { | ||||||
if (annotation->name != IR::Annotation::nameAnnotation) return annotation; | ||||||
// The node the annotation belongs to | ||||||
CHECK_NULL(getContext()->parent); | ||||||
auto *annotatedNode = getContext()->parent->node; | ||||||
CHECK_NULL(annotatedNode); | ||||||
// We are only interested in name annotations on actions here, as | ||||||
// the P4Runtime API control plane generation code already checks | ||||||
// for duplicate control plane names for other kinds of objects. | ||||||
if (!annotatedNode->is<IR::P4Action>()) { | ||||||
return annotation; | ||||||
} | ||||||
cstring name = annotation->getName(); | ||||||
if (!name.startsWith(".")) { | ||||||
// Create a fully hierarchical name beginning with ".", so we | ||||||
// can compare it against any other @name annotation value | ||||||
// that begins with "." and is equal. | ||||||
if (stack.empty()) { | ||||||
name = absl::StrCat(".", name.string_view()); | ||||||
} else { | ||||||
name = absl::StrCat(".", | ||||||
absl::StrJoin(stack, ".", | ||||||
[](std::string *out, cstring s) { | ||||||
absl::StrAppend(out, s.string_view()); | ||||||
}), | ||||||
".", name.string_view()); | ||||||
} | ||||||
} | ||||||
checkForDuplicateName(name, annotatedNode); | ||||||
return annotation; | ||||||
} | ||||||
|
||||||
} // namespace P4 |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
/* | ||
Copyright 2024 Cisco Systems, Inc. | ||
|
||
Licensed under the Apache License, Version 2.0 (the "License"); | ||
you may not use this file except in compliance with the License. | ||
You may obtain a copy of the License at | ||
|
||
http://www.apache.org/licenses/LICENSE-2.0 | ||
|
||
Unless required by applicable law or agreed to in writing, software | ||
distributed under the License is distributed on an "AS IS" BASIS, | ||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
See the License for the specific language governing permissions and | ||
limitations under the License. | ||
*/ | ||
|
||
#ifndef FRONTENDS_P4_DUPLICATEACTIONCONTROLPLANENAMECHECK_H_ | ||
#define FRONTENDS_P4_DUPLICATEACTIONCONTROLPLANENAMECHECK_H_ | ||
|
||
#include "ir/ir.h" | ||
#include "ir/visitor.h" | ||
Comment on lines
+22
to
+23
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added in commit 57 |
||
|
||
namespace P4 { | ||
|
||
/** | ||
* This pass does not change anything in the IR. It only gives an | ||
* error if it finds two objects with the same hierarchical name. I | ||
* am not certain, but it might be that at this point in the front | ||
* end, the only way such a duplicate can happen is due to @name | ||
* annotations. @name annotations are definitely taken into account | ||
* in this duplicate check. | ||
* | ||
* See also the pass HierarchicalNames, on which the implementation of | ||
* this pass was based. | ||
* | ||
* This pass should be run before pass LocalizeAllActions, because | ||
* LocalizeAllActions can create actions with duplicate names, by | ||
* design, that were not created by the P4 developer. We should not | ||
* issue an error if that pass creates duplicate hierarchical names. | ||
*/ | ||
class DuplicateActionControlPlaneNameCheck : public Transform { | ||
std::vector<cstring> stack; | ||
/// Used for detection of conflicting control plane names among actions. | ||
string_map<const IR::Node *> actions; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changes in commit 57 |
||
|
||
public: | ||
cstring getName(const IR::IDeclaration *decl); | ||
|
||
DuplicateActionControlPlaneNameCheck() { | ||
setName("DuplicateActionControlPlaneNameCheck"); | ||
visitDagOnce = false; | ||
} | ||
const IR::Node *preorder(IR::P4Parser *parser) override { | ||
stack.push_back(getName(parser)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if we call I think, pushing the parser onto the stack can be removed as we never use parser names to build hierarchical action names. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Agreed there should be no need to walk through sub-nodes within a parser. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed in commit 57 |
||
return parser; | ||
} | ||
const IR::Node *postorder(IR::P4Parser *parser) override { | ||
stack.pop_back(); | ||
return parser; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If we apply the change proposed in the previous comment, this overload can be removed, I believe. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed in commit 57 |
||
|
||
const IR::Node *preorder(IR::P4Control *control) override { | ||
stack.push_back(getName(control)); | ||
return control; | ||
} | ||
const IR::Node *postorder(IR::P4Control *control) override { | ||
stack.pop_back(); | ||
return control; | ||
} | ||
kfcripps marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
const IR::Node *preorder(IR::P4Table *table) override { | ||
visit(table->annotations); | ||
prune(); | ||
return table; | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you please elaborate why we need to visit the table's annotations here? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It most likely is not needed, and I will try removing it. This looks like something left over from when I started by copying-and-pasting the HierarchicalNames pass, and never noticed it could/should be removed. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I left the method, but removed the visit call, but left the call to prune, since there should be no need to traverse the sub-nodes of a P4 table. |
||
|
||
void checkForDuplicateName(cstring name, const IR::Node *node); | ||
|
||
const IR::Node *postorder(IR::P4Action *action) override; | ||
|
||
const IR::Node *postorder(IR::Annotation *annotation) override; | ||
// Do not change name annotations on parameters | ||
const IR::Node *preorder(IR::Parameter *parameter) override { | ||
prune(); | ||
return parameter; | ||
} | ||
}; | ||
|
||
} // namespace P4 | ||
|
||
#endif /* FRONTENDS_P4_DUPLICATEACTIONCONTROLPLANENAMECHECK_H_ */ |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -60,6 +60,18 @@ class FrontEndPolicy : public RemoveUnusedPolicy { | |
return options.optimizationLevel > 0; | ||
} | ||
|
||
/// Indicates whether control plane API generation is enabled. | ||
/// @returns default to false unless a command line option was | ||
/// given explicitly enabling control plane API generation. | ||
virtual bool controlPlaneAPIGenEnabled(const CompilerOptions &options) const { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This function should probably be part of the Options class, which owns these members. I believe CompilerOptions? You could also make this virtual since Options are usually target-specific. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Although I also can see it make sense as part of the FrontEndPolicy. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I moved method controlPlaneAPIGenEnabled into class CompilerOptions in commits 47 & 48. |
||
if (options.p4RuntimeFile.isNullOrEmpty() && options.p4RuntimeFiles.isNullOrEmpty() && | ||
options.p4RuntimeEntriesFile.isNullOrEmpty() && | ||
options.p4RuntimeEntriesFiles.isNullOrEmpty()) { | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
/// Get policy for the constant folding pass. @see ConstantFoldingPolicy | ||
/// @returns Defaults to nullptr, which causes constant folding to use the default policy, which | ||
/// does not modify the pass defaults in any way. | ||
|
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -43,9 +43,24 @@ const IR::Node *TagGlobalActions::preorder(IR::P4Action *action) { | |||||
if (findContext<IR::P4Control>() == nullptr) { | ||||||
auto annos = action->annotations; | ||||||
if (annos == nullptr) annos = IR::Annotations::empty; | ||||||
cstring name = "."_cs + action->name; | ||||||
annos = annos->addAnnotationIfNew(IR::Annotation::nameAnnotation, | ||||||
new IR::StringLiteral(name), false); | ||||||
auto nameAnno = annos->getSingle(IR::Annotation::nameAnnotation); | ||||||
if (nameAnno) { | ||||||
// If the value of the existing name annotation does not | ||||||
// begin with ".", prepend "." so that the name remains | ||||||
// global if control plane APIs are generated later. | ||||||
const auto *e0 = nameAnno->expr.at(0); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Suggested change
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Changed in commit 55, IIRC |
||||||
auto nameString = e0->to<IR::StringLiteral>()->value; | ||||||
if (!nameString.startsWith(".")) { | ||||||
nameString = "."_cs + nameString; | ||||||
auto newLit = new IR::StringLiteral(e0->srcInfo, nameString); | ||||||
annos = annos->addOrReplace(IR::Annotation::nameAnnotation, newLit); | ||||||
} | ||||||
} else { | ||||||
// Add new name annotation beginning with "." | ||||||
cstring name = "."_cs + action->name; | ||||||
annos = annos->addAnnotationIfNew(IR::Annotation::nameAnnotation, | ||||||
new IR::StringLiteral(name), false); | ||||||
} | ||||||
action->annotations = annos; | ||||||
} | ||||||
prune(); | ||||||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed in commit 57