Skip to content

Commit

Permalink
Fix for issue #562 (#1605)
Browse files Browse the repository at this point in the history
* Fix for issue #562
  • Loading branch information
Mihai Budiu authored Nov 28, 2018
1 parent d21be88 commit 22a5a13
Show file tree
Hide file tree
Showing 13 changed files with 678 additions and 4 deletions.
2 changes: 2 additions & 0 deletions backends/bmv2/simple_switch/midend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ limitations under the License.
#include "midend/eliminateTuples.h"
#include "midend/eliminateNewtype.h"
#include "midend/eliminateSerEnums.h"
#include "midend/flattenInterfaceStructs.h"
#include "midend/local_copyprop.h"
#include "midend/nestedStructs.h"
#include "midend/removeLeftSlices.h"
Expand Down Expand Up @@ -84,6 +85,7 @@ SimpleSwitchMidEnd::SimpleSwitchMidEnd(CompilerOptions& options) : MidEnd(option
new P4::NestedStructs(&refMap, &typeMap),
new P4::SimplifySelectList(&refMap, &typeMap),
new P4::RemoveSelectBooleans(&refMap, &typeMap),
new P4::FlattenInterfaceStructs(&refMap, &typeMap),
new P4::Predication(&refMap),
new P4::MoveDeclarations(), // more may have been introduced
new P4::ConstantFolding(&refMap, &typeMap),
Expand Down
2 changes: 2 additions & 0 deletions ir/ir.def
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,8 @@ class Declaration_Constant : Declaration, IAnnotated {

/// Like a variable, but for a statically allocated instance.
/// The syntax is Contructor(args) name = initializer;
/// Initializers are an experimental features, used for externs with
/// abstract methods.
class Declaration_Instance : Declaration, IAnnotated, IInstance {
optional Annotations annotations = Annotations::empty;
Type type; // Either Type_Name or Type_Specialized or Type_Extern
Expand Down
2 changes: 2 additions & 0 deletions midend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ set (MIDEND_SRCS
eliminateSerEnums.cpp
expandEmit.cpp
expandLookahead.cpp
flattenInterfaceStructs.cpp
interpreter.cpp
local_copyprop.cpp
nestedStructs.cpp
Expand Down Expand Up @@ -55,6 +56,7 @@ set (MIDEND_HDRS
expandEmit.h
expandLookahead.h
expr_uses.h
flattenInterfaceStructs.h
has_side_effects.h
interpreter.h
local_copyprop.h
Expand Down
179 changes: 179 additions & 0 deletions midend/flattenInterfaceStructs.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
/*
Copyright 2018 VMware, 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 "flattenInterfaceStructs.h"

namespace P4 {

void StructTypeReplacement::flatten(const P4::TypeMap* typeMap,
cstring prefix,
const IR::Type* type,
IR::IndexedVector<IR::StructField> *fields) {
if (auto st = type->to<IR::Type_Struct>()) {
structFieldMap.emplace(prefix, st);
for (auto f : st->fields)
flatten(typeMap, prefix + "." + f->name, f->type, fields);
return;
}
cstring fieldName = prefix.replace(".", "_") +
cstring::to_cstring(fieldNameRemap.size());
fieldNameRemap.emplace(prefix, fieldName);
fields->push_back(new IR::StructField(IR::ID(fieldName), type));
}

StructTypeReplacement::StructTypeReplacement(
const P4::TypeMap* typeMap, const IR::Type_Struct* type) {
auto vec = new IR::IndexedVector<IR::StructField>();
flatten(typeMap, "", type, vec);
replacementType = new IR::Type_Struct(type->name, IR::Annotations::empty, *vec);
}

const IR::StructInitializerExpression* StructTypeReplacement::explode(
const IR::Expression *root, cstring prefix) {
auto vec = new IR::IndexedVector<IR::NamedExpression>();
auto fieldType = ::get(structFieldMap, prefix);
CHECK_NULL(fieldType);
for (auto f : fieldType->fields) {
cstring fieldName = prefix + "." + f->name.name;
auto newFieldname = ::get(fieldNameRemap, fieldName);
const IR::Expression* expr;
if (!newFieldname.isNullOrEmpty()) {
expr = new IR::Member(root, newFieldname);
} else {
expr = explode(root, fieldName);
}
vec->push_back(new IR::NamedExpression(f->name, expr));
}
return new IR::StructInitializerExpression(fieldType->name, *vec, false);
}

static const IR::Type_Struct* isNestedStruct(const P4::TypeMap* typeMap, const IR::Type* type) {
if (auto st = type->to<IR::Type_Struct>()) {
for (auto f : st->fields) {
auto ft = typeMap->getType(f, true);
if (ft->is<IR::Type_Struct>())
return st;
}
}
return nullptr;
}

void NestedStructMap::createReplacement(const IR::Type_Struct* type) {
auto repl = ::get(replacement, type);
if (repl != nullptr)
return;
repl = new StructTypeReplacement(typeMap, type);
LOG3("Replacement for " << type << " is " << repl);
replacement.emplace(type, repl);
}

bool FindTypesToReplace::preorder(const IR::Declaration_Instance* inst) {
auto type = map->typeMap->getTypeType(inst->type, true);
auto ts = type->to<IR::Type_SpecializedCanonical>();
if (ts == nullptr)
return false;
if (!ts->baseType->is<IR::Type_Package>())
return false;
for (auto t : *ts->arguments) {
if (auto st = isNestedStruct(map->typeMap, t))
map->createReplacement(st);
}
return false;
}

/////////////////////////////////

const IR::Node* ReplaceStructs::preorder(IR::P4Program* program) {
if (replacementMap->empty()) {
// nothing to do
prune();
}
return program;
}

const IR::Node* ReplaceStructs::postorder(IR::Type_Struct* type) {
auto canon = replacementMap->typeMap->getTypeType(getOriginal(), true);
auto repl = replacementMap->getReplacement(canon);
if (repl != nullptr)
return repl->replacementType;
return type;
}

const IR::Node* ReplaceStructs::postorder(IR::Member* expression) {
// Find out if this applies to one of the parameters that are being replaced.
if (getParent<IR::Member>() != nullptr)
// We only want to process the outermost Member
return expression;
const IR::Expression* e = expression;
cstring prefix = "";
while (auto mem = e->to<IR::Member>()) {
e = mem->expr;
prefix = cstring(".") + mem->member + prefix;
}
auto pe = e->to<IR::PathExpression>();
if (pe == nullptr)
return expression;
// At this point we know that pe is an expression of the form
// param.field1.etc.fieldN, where param has a type that needs to be replaced.
auto decl = replacementMap->refMap->getDeclaration(pe->path, true);
auto param = decl->to<IR::Parameter>();
if (param == nullptr)
return expression;
auto repl = ::get(toReplace, param);
if (repl == nullptr)
return expression;
auto newFieldName = ::get(repl->fieldNameRemap, prefix);
const IR::Expression* result;
if (newFieldName.isNullOrEmpty()) {
// Prefix is a reference to a field of the original struct whose
// type is actually a struct itself. We need to replace the field
// with a struct initializer expression. (This won't work if the
// field is being used as a left-value. Hopefully, all such uses
// of a struct-valued field as a left-value have been already
// replaced by the NestedStructs pass.)
result = repl->explode(pe, prefix);
} else {
result = new IR::Member(pe, newFieldName);
}
LOG3("Replacing " << expression << " with " << result);
return result;
}

const IR::Node* ReplaceStructs::preorder(IR::P4Parser* parser) {
for (auto p : parser->getApplyParameters()->parameters) {
auto pt = replacementMap->typeMap->getType(p, true);
auto repl = replacementMap->getReplacement(pt);
if (repl != nullptr) {
toReplace.emplace(p, repl);
LOG3("Replacing parameter " << dbp(p) << " of " << dbp(parser));
}
}
return parser;
}

const IR::Node* ReplaceStructs::preorder(IR::P4Control* control) {
for (auto p : control->getApplyParameters()->parameters) {
auto pt = replacementMap->typeMap->getType(p, true);
auto repl = replacementMap->getReplacement(pt);
if (repl != nullptr) {
toReplace.emplace(p, repl);
LOG3("Replacing parameter " << dbp(p) << " of " << dbp(control));
}
}
return control;
}

} // namespace P4
Loading

0 comments on commit 22a5a13

Please sign in to comment.