diff --git a/pruner/src/compiler_pruner.cpp b/pruner/src/compiler_pruner.cpp index bc9b3e0..f1969b1 100644 --- a/pruner/src/compiler_pruner.cpp +++ b/pruner/src/compiler_pruner.cpp @@ -1,3 +1,5 @@ +#include + #include "frontends/common/constantFolding.h" #include "frontends/common/resolveReferences/resolveReferences.h" #include "frontends/p4/createBuiltins.h" @@ -47,10 +49,9 @@ const IR::P4Program *apply_unused_decls(const IR::P4Program *program, P4::ReferenceMap refMap; P4::TypeMap typeMap; const IR::P4Program *temp = nullptr; - - PassManager pass_manager({new ExtendedUnusedDeclarations(&refMap)}); - - INFO("Applying custom RemoveAllUnusedDeclarations..."); + std::vector used_structs; + PassManager pass_manager( + {new ExtendedUnusedDeclarations(&refMap, &used_structs)}); temp = program->apply(pass_manager); check_pruned_program(&program, temp, pruner_conf); @@ -64,7 +65,6 @@ const IR::P4Program *apply_compiler_passes(const IR::P4Program *program, auto action = DiagnosticAction::Ignore; P4CContext::get().setDefaultWarningDiagnosticAction(action); INFO("\nPruning with compiler passes") - bool genericPassesApplied = false; // apply the compiler passes program = apply_generic_passes(program, pruner_conf, &genericPassesApplied); diff --git a/pruner/src/expression_pruner.h b/pruner/src/expression_pruner.h index 442ddb9..8f3c6dd 100644 --- a/pruner/src/expression_pruner.h +++ b/pruner/src/expression_pruner.h @@ -43,7 +43,7 @@ class ExpressionPruner : public Transform { // const IR::Node *postorder(const IR::Slice *s); // const IR::Node *postorder(const IR::Mux *m); // const IR::Node *postorder(const IR::Member *m); - // const IR::Node *postorder(const IR::PathExpression *p); + // const IR::Node *postorder(IR::Member *p) override; // const IR::Node *postorder(const IR::SerEnumMember *m); // const IR::Node *postorder(const IR::DefaultExpression *de); // const IR::Node *postorder(const IR::ListExpression *le); diff --git a/pruner/src/extended_unused.cpp b/pruner/src/extended_unused.cpp index 5b005a0..671415e 100644 --- a/pruner/src/extended_unused.cpp +++ b/pruner/src/extended_unused.cpp @@ -1,17 +1,42 @@ #include "extended_unused.h" #include "frontends/p4/sideEffects.h" +#include "pruner_util.h" namespace P4PRUNER { +bool PruneUnused::check_if_field_used(cstring name_of_struct, + cstring name_of_field) { + for (const auto *s : *used_structs) { + if (s->name == name_of_struct) { + for (auto f : *(s->fields)) { + if (f == name_of_field) { + return true; + } + } + } + } + return false; +} + const IR::Node *PruneUnused::preorder(IR::Type_StructLike *ts) { - prune(); // do not remove individual struct members yet if (!unused_refMap->isUsed(getOriginal())) { return nullptr; } return ts; } +const IR::Node *PruneUnused::preorder(IR::StructField *sf) { + const auto *p = getParent(); + cstring p_name = p->getP4Type()->toString(); + cstring f_name = sf->toString(); + bool res = check_if_field_used(p_name, f_name); + if (res) { + return sf; + } + return nullptr; +} + const IR::Node *PruneUnused::preorder(IR::Type_Extern *te) { if (!unused_refMap->isUsed(getOriginal())) { return nullptr; @@ -33,4 +58,70 @@ const IR::Node *PruneUnused::preorder(IR::Function *f) { return f; } +// List unused struct declarations + +bool ListStructs::preorder(const IR::Member *p) { + const auto *pexpr = p->expr->to(); + if (pexpr == nullptr) { + return true; // i.e, expr was not a path expression + } + const IR::IDeclaration *decl = + unused_refMap->getDeclaration(pexpr->path, false); + if (decl == nullptr) { + return true; + } + const auto *v = decl->to(); + if (v == nullptr) { + return true; // Only handle parameters for now + } + cstring mem = p->member.name; + cstring parent = v->type->getP4Type()->toString(); + insertField(parent, mem); + return true; +} + +Visitor::profile_t ListStructs::init_apply(const IR::Node *node) { + return Inspector::init_apply(node); +} + +void ListStructs::insertField(cstring name_of_struct, cstring name_of_field) { + bool foundStruct = false; + bool foundField = false; + + for (auto *s : *used_structs) { + if (name_of_struct == s->name) { + foundStruct = true; + for (auto f : *s->fields) { + foundField = name_of_field == f; + } + if (!foundField) { + s->fields->push_back(name_of_field); + } + } + } + if (!foundStruct) { + // Lets have this on the heap + auto *f = new std::vector(); + f->push_back(name_of_field); + auto *s = new struct_obj; + s->name = name_of_struct; + s->fields = f; + used_structs->push_back(s); + } +} + +void PruneUnused::show_used_structs() { + LOG2("Printing Used Structs"); + if (used_structs->empty()) { + LOG1("used_structs is empty"); + return; + } + for (struct_obj *s : *used_structs) { + LOG2("Struct: " << s->name); + for (cstring f : *(s->fields)) { + LOG2("\tField: " << f); + } + } +} + } // namespace P4PRUNER diff --git a/pruner/src/extended_unused.h b/pruner/src/extended_unused.h index b77811c..a24a58c 100644 --- a/pruner/src/extended_unused.h +++ b/pruner/src/extended_unused.h @@ -1,36 +1,69 @@ #ifndef _PRUNE_UNUSED_H_ #define _PRUNE_UNUSED_H_ +#include + #include "frontends/common/resolveReferences/resolveReferences.h" #include "frontends/p4/unusedDeclarations.h" #include "ir/ir.h" namespace P4PRUNER { +struct struct_obj { + cstring name; + std::vector *fields{}; +}; + class PruneUnused : public P4::RemoveUnusedDeclarations { // the refmap of the parent class is private so we have to use our own // a little bit unfortunate but the pointer is the same // we also do not modify the map so this is fairly safe const P4::ReferenceMap *unused_refMap; + const std::vector *used_structs; public: - explicit PruneUnused(const P4::ReferenceMap *refMap) - : P4::RemoveUnusedDeclarations(refMap), unused_refMap(refMap) { + explicit PruneUnused(const P4::ReferenceMap *refMap, + std::vector *_used_structs) + : P4::RemoveUnusedDeclarations(refMap), unused_refMap(refMap), + used_structs(_used_structs) { CHECK_NULL(refMap); setName("PruneUnused"); } const IR::Node *preorder(IR::Type_StructLike *ts) override; + const IR::Node *preorder(IR::StructField *sf) override; const IR::Node *preorder(IR::Type_Extern *te) override; const IR::Node *preorder(IR::Method *m) override; const IR::Node *preorder(IR::Function *f) override; + void show_used_structs(); + bool check_if_field_used(cstring name_of_struct, cstring name_of_field); +}; + +class ListStructs : public Inspector { + const P4::ReferenceMap *unused_refMap; + std::vector *used_structs; + + public: + explicit ListStructs(const P4::ReferenceMap *refMap, + std::vector *_used_structs) + : unused_refMap(refMap), used_structs(_used_structs) { + CHECK_NULL(refMap); + CHECK_NULL(_used_structs); + setName("ListStructs"); + } + Visitor::profile_t init_apply(const IR::Node *node) override; + bool preorder(const IR::Member *p) override; + void insertField(cstring name_of_struct, cstring name_of_field); }; class ExtendedUnusedDeclarations : public PassManager { public: - explicit ExtendedUnusedDeclarations(P4::ReferenceMap *refMap) { + explicit ExtendedUnusedDeclarations( + P4::ReferenceMap *refMap, std::vector *used_structs) { CHECK_NULL(refMap); - passes.emplace_back(new PassRepeated{new P4::ResolveReferences(refMap), - new PruneUnused(refMap)}); + passes.emplace_back( + new PassRepeated{new P4::ResolveReferences(refMap), + new ListStructs(refMap, used_structs), + new PruneUnused(refMap, used_structs)}); setName("ExtendedUnusedDeclarations"); } }; diff --git a/pruner/src/statement_pruner.cpp b/pruner/src/statement_pruner.cpp index 156d5ec..d81ef07 100644 --- a/pruner/src/statement_pruner.cpp +++ b/pruner/src/statement_pruner.cpp @@ -30,8 +30,11 @@ const IR::Node *Pruner::preorder(IR::BlockStatement *s) { return s; } -const IR::Node *Pruner::preorder(IR::EmptyStatement * /*e*/) { - // Always remove empty statements. +const IR::Node *Pruner::preorder(IR::EmptyStatement *e) { + // Don't remove empty statements if they are children of an if block. + if (this->getParent() != nullptr) { + return e; + } return nullptr; } diff --git a/pruner/tests/references/crash_bugs/crash_one_reference.p4 b/pruner/tests/references/crash_bugs/crash_one_reference.p4 index c0b7a11..6fb7beb 100644 --- a/pruner/tests/references/crash_bugs/crash_one_reference.p4 +++ b/pruner/tests/references/crash_bugs/crash_one_reference.p4 @@ -9,17 +9,52 @@ header ethernet_t { bit<16> eth_type; } +struct zRDuhm { + bit<128> LEQY; + bit<8> KOcO; + ethernet_t EWpj; + bit<32> BUWO; + bit<32> NnjD; +} + header PguzcJ { bit<4> YRcl; bit<32> vGcj; bit<16> CazW; } +header yLNoil { + bit<128> ILBe; + bit<64> MXzB; +} + +header vuOVMH { + bit<8> GPVl; + bit<4> hrds; + bit<128> HoON; + bit<32> Wsxt; +} + +struct avXIXF { + bit<64> Vpbo; + bit<32> CeRJ; + zRDuhm tkyq; +} + header gPTIia { bit<32> pvdW; bit<8> HQZo; } +struct OXxQuH { + bit<8> xBZh; +} + +header jUHTpn { + bit<4> yrVX; + bit<32> bZKC; +} + struct Headers { ethernet_t eth_hdr; ethernet_t[6] gvFM; @@ -30,9 +65,32 @@ struct Headers { } bit<16> SaTkzAX(PguzcJ Oofi) { + bool cmdluC = true; + bit<32> cqckxY = 32w10; + bit<128> RfSkhs = 128w10; + bit<64> nZqXev = 64w10; + bit<128> xYhUqh = RfSkhs; return 16w10; } +yLNoil wClaYko(jUHTpn DoHl) { + bit<4> wgIKEQ = 4w14; + const zRDuhm zTQmam = (zRDuhm){LEQY = 128w232569008864530135157127505601818385808,KOcO = 8w10,EWpj = (ethernet_t){dst_addr = 48w211703505640505,src_addr = 48w10,eth_type = 16w10},BUWO = 32w10,NnjD = 32w2274055191}; + return (yLNoil){ILBe = 128w10,MXzB = 64w10}; +} +bit<4> rjsgGkN(bit<16> SOZw) { + const bit<128> cMIrQM = 128w10; + bit<16> YVHHin = (bit<16>)16w10; + return 4w10; + bit<8> XmGxDm = (bit<8>)8w143; + bit<16> aneguV = 16w46085; + return 4w12; +} parser p(packet_in pkt, out Headers hdr) { + bit<4> WCyPOo = 145w10[106:58][12:9]; + bit<4> OpKEBC = 4w14; + yLNoil LnJSsf = (yLNoil){ILBe = 128w10,MXzB = 64w8739799105651448972}; + bool MHFZYM = false; + bit<8> AfRsJs = 8w38; state start { transition parse_hdrs; } @@ -42,8 +100,68 @@ parser p(packet_in pkt, out Headers hdr) { } control ingress(inout Headers h) { + bit<128> WbiJDx = 128w230764102599282411499082228184235706426; + action AWhhg(inout bit<16> HpDQ, OXxQuH GSUK) { + } + action TyIkj(bit<8> cFUf, bit<64> UYcs) { + const bool naGUDB = false; + return; + const bit<32> kFhgzn = 32w10; + return; + } + action isfLJ(inout bit<4> zayb, bit<32> ezim, bit<16> pxcw) { + { + } + { + avXIXF paUCEG = (avXIXF){Vpbo = 64w10,CeRJ = 32w10,tkyq = (zRDuhm){LEQY = 128w10,KOcO = (bit<8>)h.uAdg.HQZo,EWpj = (ethernet_t){dst_addr = 48w10,src_addr = 48w10,eth_type = pxcw},BUWO = 32w502793114,NnjD = 32w10}}; + } + const gPTIia khmurm = (gPTIia){pvdW = 32w10,HQZo = 8w10}; + } + table xLdpWu { + key = { + 16w19744: exact @name("wvtOpl") ; + } + actions = { + isfLJ(h.IDZn.YRcl); + @defaultonly NoAction(); + } + default_action = NoAction(); + } + table uiTHkJ { + key = { + } + actions = { + @defaultonly NoAction(); + } + default_action = NoAction(); + } + table YfGdXm { + key = { + } + actions = { + isfLJ(h.uAdg.pvdW[20:17]); + @defaultonly NoAction(); + } + default_action = NoAction(); + } + table ObUSpl { + key = { + 4w9 : exact @name("LzviDL") ; + 16w19115 : exact @name("SBnBQt") ; + 48w145114785635731: exact @name("JEgqHq") ; + } + actions = { + isfLJ(h.IDZn.YRcl); + @defaultonly NoAction(); + } + default_action = NoAction(); + } apply { + const int XsZqcA = 181433741; + bit<128> CYNOag = 128w334026077963046502987531789306364882607; + const bit<4> lgWdgD = 4w10; h.gvFM[max((bit<3>)SaTkzAX({ 4w6, 32w10, 16w10 }), 3w5)].src_addr = 48w10; + bit<64> GTZTgt = 64w10; } } diff --git a/pruner/tests/references/create_references.sh b/pruner/tests/references/create_references.sh index 6e3c366..9e8c0fa 100755 --- a/pruner/tests/references/create_references.sh +++ b/pruner/tests/references/create_references.sh @@ -2,10 +2,8 @@ for f in crash_bugs/*.p4; do if [[ "$f" != *"reference.p4" ]]; then - # echo "$f" bf=$(basename "$f" .p4) - # echo "${f}, ${bf}" - ../../../../../p4c/build/extensions/toz3/pruner/p4pruner --seed 1 --compiler-bin ../../broken_p4c/24895c1b28a35352f1d9ad1f43878c4f7061d3ab crash_bugs/$f --bug-type CRASH --output crash_bugs/${bf}_reference.p4 + ../../../../p4c/build/extensions/toz3/pruner/p4pruner --seed 1 --compiler-bin ../broken_p4c/24895c1b28a35352f1d9ad1f43878c4f7061d3ab $f --bug-type CRASH --output crash_bugs/${bf}_reference.p4 fi done rm -rf crash_bugs/pruned/ crash_bugs/*stripped*