// // This file is distributed under the MIT License. See LICENSE.md for details. // #include #include #include #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinTypes.h" #include "revng/Clift/CliftEnums.h" #include "revng/CliftTransforms/Passes.h" #include "revng/Support/CTarget.h" #include "BestTraversal.h" #include "EmitFieldAccesses.h" #include "FieldAccessReplacement.h" #include "PointerArithmetic.h" namespace mlir { namespace clift { #define GEN_PASS_DEF_CLIFTEMITFIELDACCESSES #include "revng/CliftTransforms/Passes.h.inc" } // namespace clift } // namespace mlir namespace clift = mlir::clift; using namespace clift; namespace { struct EmitFieldAccessesPass : clift::impl::CliftEmitFieldAccessesBase { void runOnOperation() override { if (emitFieldAccesses(getOperation()).failed()) { signalPassFailure(); } } }; /// Holds the planned `Replacement` for a single expression struct PlannedReplacement { clift::ExpressionOpInterface Op; PointerArithmetic PA; Traversal BestTraversal; }; /// Implementation of the high level `emitFieldAccesses` phases inside the /// anonymous namespace in this translation unit mlir::LogicalResult emitFieldAccessesImpl(clift::FunctionOp Function) { // `TraversalInfoMap` cache. Even if not elegant, we store the data computed // at the pass level so that we can cache it instead of recomputing it every // time TraversalInfoMap TraversalMap; // Phase 1-2: Collect all planned `Replacement`s without modifying the IR llvm::SmallVector Replacements; Function->walk([&TraversalMap, &Replacements](clift::ExpressionOpInterface Op) { // 1. We inspect all the `ExpressionOp`s in the current `Function` std::optional PA = computePointerArithmetic(Op); // The `PointerArithmetic` returned object could be empty at the moment of // return, and this is a signal that we could not compute a // `PointerArithmetic` for the current `ExpressionOpInterface` // 2. We proceed with the computation of the `BestTraversal` for the current // `PointerArithmetic` if (PA) { std::optional BT = computeBestTraversal(Op, *PA, TraversalMap); if (BT) { Replacements.push_back({ Op, std::move(*PA), std::move(*BT) }); } } }); // Phase 3: Apply all replacements for (const auto &R : Replacements) { replaceFieldAccess(R.Op, R.PA, R.BestTraversal); } // The IR is always in a valid state, regardless of whether we performed an // operation rewrite or not. return mlir::success(); } } // namespace /// `emitFieldAccesses` driver that can be called by importing the header mlir::LogicalResult emitFieldAccesses(clift::FunctionOp Function) { return emitFieldAccessesImpl(Function); } clift::PassPtr clift::createEmitFieldAccessesPass() { return std::make_unique(); }