|
| 1 | +#include <iostream> |
| 2 | +#include <sstream> |
| 3 | + |
| 4 | +#include "midend/hsIndexSimplify.h" |
| 5 | +#include "midend/simplifyKey.h" |
| 6 | + |
| 7 | +namespace P4 { |
| 8 | + |
| 9 | +void HSIndexFinder::postorder(const IR::ArrayIndex* curArrayIndex) { |
| 10 | + if (arrayIndex == nullptr && !curArrayIndex->right->is<IR::Constant>()) { |
| 11 | + arrayIndex = curArrayIndex; |
| 12 | + addNewVariable(); |
| 13 | + } |
| 14 | +} |
| 15 | + |
| 16 | +void HSIndexFinder::addNewVariable() { |
| 17 | + BUG_CHECK(arrayIndex != nullptr, "Can't generate new name for empty ArrayIndex"); |
| 18 | + // If index is an expression then create new variable. |
| 19 | + if (locals != nullptr && (arrayIndex->right->is<IR::Operation_Ternary>() || |
| 20 | + arrayIndex->right->is<IR::Operation_Binary>() || |
| 21 | + arrayIndex->right->is<IR::Operation_Unary>() || |
| 22 | + arrayIndex->right->is<IR::PathExpression>())) { |
| 23 | + // Generate new local variable if needed. |
| 24 | + std::ostringstream ostr; |
| 25 | + ostr << arrayIndex->right; |
| 26 | + cstring indexString = ostr.str(); |
| 27 | + if (arrayIndex->right->is<IR::PathExpression>()) { |
| 28 | + newVariable = arrayIndex->right->to<IR::PathExpression>(); |
| 29 | + } else if (generatedVariables->count(indexString) == 0) { |
| 30 | + // Generate new temporary variable. |
| 31 | + auto type = typeMap->getTypeType(arrayIndex->right->type, true); |
| 32 | + auto name = refMap->newName("hsiVar"); |
| 33 | + auto decl = new IR::Declaration_Variable(name, type); |
| 34 | + locals->push_back(decl); |
| 35 | + typeMap->setType(decl, type); |
| 36 | + newVariable = new IR::PathExpression(arrayIndex->srcInfo, type, new IR::Path(name)); |
| 37 | + generatedVariables->emplace(indexString, newVariable); |
| 38 | + } else { |
| 39 | + newVariable = generatedVariables->at(indexString); |
| 40 | + } |
| 41 | + } |
| 42 | +} |
| 43 | + |
| 44 | +const IR::Node* HSIndexTransform::postorder(IR::ArrayIndex* curArrayIndex) { |
| 45 | + if (hsIndexFinder.arrayIndex != nullptr && curArrayIndex->equiv(*hsIndexFinder.arrayIndex)) { |
| 46 | + // Translating current array index. |
| 47 | + auto* newArrayIndex = hsIndexFinder.arrayIndex->clone(); |
| 48 | + newArrayIndex->right = new IR::Constant(newArrayIndex->right->type, index); |
| 49 | + return newArrayIndex; |
| 50 | + } |
| 51 | + return curArrayIndex; |
| 52 | +} |
| 53 | + |
| 54 | +IR::Node* HSIndexSimplifier::eliminateArrayIndexes(HSIndexFinder& aiFinder, |
| 55 | + IR::Statement* statement, |
| 56 | + const IR::Expression* expr) { |
| 57 | + if (aiFinder.arrayIndex == nullptr) { |
| 58 | + return statement; |
| 59 | + } |
| 60 | + const IR::Statement* elseBody = nullptr; |
| 61 | + auto* curIf = statement->to<IR::IfStatement>(); |
| 62 | + if (curIf != nullptr) { |
| 63 | + elseBody = curIf->ifFalse; |
| 64 | + } |
| 65 | + IR::IndexedVector<IR::StatOrDecl> newComponents; |
| 66 | + if (aiFinder.newVariable != nullptr) { |
| 67 | + if (!aiFinder.newVariable->equiv(*aiFinder.arrayIndex->right)) { |
| 68 | + newComponents.push_back(new IR::AssignmentStatement( |
| 69 | + aiFinder.arrayIndex->srcInfo, aiFinder.newVariable, aiFinder.arrayIndex->right)); |
| 70 | + } |
| 71 | + } |
| 72 | + IR::IfStatement* result = nullptr; |
| 73 | + IR::IfStatement* curResult = nullptr; |
| 74 | + IR::IfStatement* newIf = nullptr; |
| 75 | + const auto* typeStack = aiFinder.arrayIndex->left->type->checkedTo<IR::Type_Stack>(); |
| 76 | + size_t sz = typeStack->getSize(); |
| 77 | + for (size_t i = 0; i < sz; i++) { |
| 78 | + HSIndexTransform aiRewriter(aiFinder, i); |
| 79 | + auto* newStatement = statement->apply(aiRewriter)->to<IR::Statement>(); |
| 80 | + auto* newIndex = new IR::Constant(aiFinder.arrayIndex->right->type, i); |
| 81 | + auto* newCondition = new IR::Equ(aiFinder.newVariable, newIndex); |
| 82 | + if (curIf != nullptr) { |
| 83 | + newIf = newStatement->checkedTo<IR::IfStatement>()->clone(); |
| 84 | + newIf->condition = new IR::LAnd(newCondition, newIf->condition); |
| 85 | + } else { |
| 86 | + newIf = new IR::IfStatement(newCondition, newStatement, nullptr); |
| 87 | + } |
| 88 | + if (result == nullptr) { |
| 89 | + result = newIf; |
| 90 | + } else { |
| 91 | + curResult->ifFalse = newIf; |
| 92 | + } |
| 93 | + curResult = newIf; |
| 94 | + } |
| 95 | + if (expr != nullptr && locals != nullptr) { |
| 96 | + // Add case for write out of bound. |
| 97 | + cstring typeString = expr->type->node_type_name(); |
| 98 | + const IR::PathExpression* pathExpr = nullptr; |
| 99 | + if (generatedVariables->count(typeString) == 0) { |
| 100 | + // Add assigment of undefined header. |
| 101 | + auto name = refMap->newName("hsVar"); |
| 102 | + auto decl = new IR::Declaration_Variable(name, expr->type); |
| 103 | + locals->push_back(decl); |
| 104 | + typeMap->setType(decl, expr->type); |
| 105 | + pathExpr = new IR::PathExpression(aiFinder.arrayIndex->srcInfo, expr->type, |
| 106 | + new IR::Path(name)); |
| 107 | + generatedVariables->emplace(typeString, pathExpr); |
| 108 | + } else { |
| 109 | + pathExpr = generatedVariables->at(typeString); |
| 110 | + } |
| 111 | + auto* newStatement = |
| 112 | + new IR::AssignmentStatement(aiFinder.arrayIndex->srcInfo, expr, pathExpr); |
| 113 | + auto* newCondition = new IR::Geq( |
| 114 | + aiFinder.newVariable, new IR::Constant(aiFinder.arrayIndex->right->type, sz - 1)); |
| 115 | + newIf = new IR::IfStatement(newCondition, newStatement, nullptr); |
| 116 | + curResult->ifFalse = newIf; |
| 117 | + } |
| 118 | + newIf->ifFalse = elseBody; |
| 119 | + newComponents.push_back(result); |
| 120 | + return new IR::BlockStatement(newComponents); |
| 121 | +} |
| 122 | + |
| 123 | +IR::Node* HSIndexSimplifier::preorder(IR::AssignmentStatement* assignmentStatement) { |
| 124 | + HSIndexFinder aiFinder(locals, refMap, typeMap, generatedVariables); |
| 125 | + assignmentStatement->left->apply(aiFinder); |
| 126 | + if (aiFinder.arrayIndex == nullptr) { |
| 127 | + assignmentStatement->right->apply(aiFinder); |
| 128 | + return eliminateArrayIndexes(aiFinder, assignmentStatement, assignmentStatement->left); |
| 129 | + } else { |
| 130 | + return eliminateArrayIndexes(aiFinder, assignmentStatement, nullptr); |
| 131 | + } |
| 132 | +} |
| 133 | + |
| 134 | +/** |
| 135 | + * Policy that treats a key as ArrayIndex with non constant index. |
| 136 | + */ |
| 137 | +class IsNonConstantArrayIndex : public KeyIsSimple, public Inspector { |
| 138 | + protected: |
| 139 | + bool simple; |
| 140 | + |
| 141 | + public: |
| 142 | + IsNonConstantArrayIndex() { setName("IsNonConstantArrayIndex"); } |
| 143 | + |
| 144 | + void postorder(const IR::ArrayIndex* arrayIndex) override { |
| 145 | + if (simple) { |
| 146 | + simple = arrayIndex->right->is<IR::Constant>(); |
| 147 | + } |
| 148 | + } |
| 149 | + profile_t init_apply(const IR::Node* root) override { |
| 150 | + simple = true; |
| 151 | + return Inspector::init_apply(root); |
| 152 | + } |
| 153 | + |
| 154 | + bool isSimple(const IR::Expression* expression, const Visitor::Context*) override { |
| 155 | + (void)expression->apply(*this); |
| 156 | + return simple; |
| 157 | + } |
| 158 | +}; |
| 159 | + |
| 160 | +IR::Node* HSIndexSimplifier::preorder(IR::P4Control* control) { |
| 161 | + DoSimplifyKey keySimplifier(refMap, typeMap, new IsNonConstantArrayIndex()); |
| 162 | + const auto* controlKeySimplified = control->apply(keySimplifier)->to<IR::P4Control>(); |
| 163 | + auto* newControl = controlKeySimplified->clone(); |
| 164 | + IR::IndexedVector<IR::Declaration> newControlLocals; |
| 165 | + HSIndexSimplifier hsSimplifier(refMap, typeMap, &newControlLocals, generatedVariables); |
| 166 | + newControl->body = newControl->body->apply(hsSimplifier)->to<IR::BlockStatement>(); |
| 167 | + for (auto* declaration : controlKeySimplified->controlLocals) { |
| 168 | + if (declaration->is<IR::P4Action>()) { |
| 169 | + newControlLocals.push_back(declaration->apply(hsSimplifier)->to<IR::Declaration>()); |
| 170 | + } else { |
| 171 | + newControlLocals.push_back(declaration); |
| 172 | + } |
| 173 | + } |
| 174 | + newControl->controlLocals = newControlLocals; |
| 175 | + return newControl; |
| 176 | +} |
| 177 | + |
| 178 | +IR::Node* HSIndexSimplifier::preorder(IR::P4Parser* parser) { |
| 179 | + prune(); |
| 180 | + return parser; |
| 181 | +} |
| 182 | + |
| 183 | +IR::Node* HSIndexSimplifier::preorder(IR::BlockStatement* blockStatement) { |
| 184 | + generatedVariablesMap blockGeneratedVariables; |
| 185 | + HSIndexFinder aiFinder(locals, refMap, typeMap, &blockGeneratedVariables); |
| 186 | + blockStatement->apply(aiFinder); |
| 187 | + if (aiFinder.arrayIndex == nullptr) { |
| 188 | + return blockStatement; |
| 189 | + } |
| 190 | + HSIndexSimplifier hsSimplifier(refMap, typeMap, locals, &blockGeneratedVariables); |
| 191 | + auto* newBlock = blockStatement->clone(); |
| 192 | + IR::IndexedVector<IR::StatOrDecl> newComponents; |
| 193 | + for (auto& component : blockStatement->components) { |
| 194 | + const auto* newComponent = component->apply(hsSimplifier)->to<IR::StatOrDecl>(); |
| 195 | + if (const auto* newComponentBlock = newComponent->to<IR::BlockStatement>()) { |
| 196 | + for (auto& blockComponent : newComponentBlock->components) { |
| 197 | + newComponents.push_back(blockComponent); |
| 198 | + } |
| 199 | + } else { |
| 200 | + newComponents.push_back(newComponent); |
| 201 | + } |
| 202 | + } |
| 203 | + newBlock->components = newComponents; |
| 204 | + return newBlock; |
| 205 | +} |
| 206 | + |
| 207 | +IR::Node* HSIndexSimplifier::preorder(IR::IfStatement* ifStatement) { |
| 208 | + HSIndexFinder aiFinder(locals, refMap, typeMap, generatedVariables); |
| 209 | + ifStatement->condition->apply(aiFinder); |
| 210 | + return eliminateArrayIndexes(aiFinder, ifStatement, nullptr); |
| 211 | +} |
| 212 | + |
| 213 | +IR::Node* HSIndexSimplifier::preorder(IR::MethodCallStatement* methodCallStatement) { |
| 214 | + HSIndexFinder aiFinder(locals, refMap, typeMap, generatedVariables); |
| 215 | + methodCallStatement->apply(aiFinder); |
| 216 | + // Here we mean that in/out parameter will be replaced by correspondent assignments. |
| 217 | + // In this case no need to consider assignment to undefined value. |
| 218 | + return eliminateArrayIndexes(aiFinder, methodCallStatement, nullptr); |
| 219 | +} |
| 220 | + |
| 221 | +IR::Node* HSIndexSimplifier::preorder(IR::SwitchStatement* switchStatement) { |
| 222 | + HSIndexFinder aiFinder(locals, refMap, typeMap, generatedVariables); |
| 223 | + switchStatement->expression->apply(aiFinder); |
| 224 | + return eliminateArrayIndexes(aiFinder, switchStatement, nullptr); |
| 225 | +} |
| 226 | + |
| 227 | +} // namespace P4 |
0 commit comments