#pragma once // // This file is distributed under the MIT License. See LICENSE.md for details. // #include "revng/Clift/Clift.h" namespace clift { struct BlockPosition { mlir::Block *Block; mlir::Block::iterator Pos; static BlockPosition get(mlir::Operation *Op) { return BlockPosition{ Op->getBlock(), Op->getIterator() }; } static BlockPosition getNext(mlir::Operation *Op) { return BlockPosition{ Op->getBlock(), std::next(Op->getIterator()) }; } static BlockPosition getBegin(mlir::Region &R) { revng_assert(not R.empty()); return { &R.front(), R.front().begin() }; } static BlockPosition getEnd(mlir::Region &R) { revng_assert(R.hasOneBlock()); return { &R.front(), R.front().end() }; } template OpT getOperation() const { if (Block == nullptr) return {}; if (Pos == Block->end()) return {}; return mlir::dyn_cast(&*Pos); } explicit operator bool() const { return Block != nullptr; } friend bool operator==(BlockPosition const &, BlockPosition const &) = default; }; inline bool isEmptyRegionOrBlock(mlir::Region &R) { return R.empty() or R.front().empty(); } inline bool hasEmptyBlock(mlir::Region &R) { return not R.empty() and R.front().empty(); } inline bool isFirstInBlock(mlir::Operation *Op) { return Op->getIterator() == Op->getBlock()->begin(); } inline bool isLastInBlock(mlir::Operation *Op) { return std::next(Op->getIterator()) == Op->getBlock()->end(); } inline mlir::Block *getOnlyBlock(mlir::Region &R) { return R.hasOneBlock() ? &R.front() : nullptr; } inline mlir::Block *extractOnlyBlock(mlir::Region &R) { mlir::Block *Block = getOnlyBlock(R); if (Block != nullptr) R.getBlocks().remove(Block); return Block; } inline void setOnlyBlock(mlir::Region &R, mlir::Block *Block) { if (not R.empty()) R.getBlocks().clear(); if (Block != nullptr) R.push_back(Block); } template OpT getOnlyOpIf(mlir::Region &R, PredicateT &&Predicate) { if (R.empty()) return {}; revng_assert(R.hasOneBlock()); mlir::Block &B = R.front(); auto Beg = B.begin(); auto End = B.end(); if (Beg == End) return {}; mlir::Operation *Op = &*Beg; if (++Beg != End) return {}; if constexpr (std::is_same_v) { if (Predicate(Op)) return Op; } else { if (auto Op2 = mlir::dyn_cast(Op)) { if (Predicate(Op2)) return Op2; } } return {}; } template OpT getOnlyOp(mlir::Region &R) { return getOnlyOpIf(R, [](OpT) { return true; }); } template OpT getFirstOpIf(mlir::Region &R, PredicateT &&Predicate) { if (R.empty()) return {}; revng_assert(R.hasOneBlock()); mlir::Block &B = R.front(); if (B.empty()) return {}; mlir::Operation *Op = &B.front(); if constexpr (std::is_same_v) { if (Predicate(Op)) return Op; } else { if (auto Op2 = mlir::dyn_cast(Op)) { if (Predicate(Op2)) return Op2; } } return {}; } template OpT getFirstOp(mlir::Region &Region) { return getFirstOpIf(Region, [](OpT) { return true; }); } template OpT getLastOpIf(mlir::Region &R, PredicateT &&Predicate) { if (R.empty()) return {}; revng_assert(R.hasOneBlock()); mlir::Block &B = R.front(); if (B.empty()) return {}; mlir::Operation *Op = &B.back(); if constexpr (std::is_same_v) { if (Predicate(Op)) return Op; } else { if (auto Op2 = mlir::dyn_cast(Op)) { if (Predicate(Op2)) return Op2; } } return {}; } template OpT getLastOp(mlir::Region &Region) { return getLastOpIf(Region, [](OpT) { return true; }); } template OpT getNextOpIf(mlir::Operation *Op, PredicateT &&Predicate) { auto NextIterator = std::next(Op->getIterator()); if (NextIterator == Op->getBlock()->end()) return {}; mlir::Operation *NextOp = &*NextIterator; if constexpr (std::is_same_v) { if (Predicate(NextOp)) return NextOp; } else { if (auto NextOp2 = mlir::dyn_cast(NextOp)) { if (Predicate(NextOp2)) return NextOp2; } } return {}; } template OpT getNextOp(mlir::Operation *Op) { return getNextOpIf(Op, [](OpT) { return true; }); } //===----------------------------- Statements -----------------------------===// inline BlockPosition getJumpTarget(JumpStatementOpInterface Jump) { mlir::Operation *Op = Jump.getLabelAssignmentOp(); if (auto Loop = mlir::dyn_cast(Op)) { auto Label = Jump.getLabel(); if (Label == Loop.getBreakLabel()) return BlockPosition::getNext(Loop); if (Label == Loop.getContinueLabel()) return BlockPosition::getEnd(Loop.getBody()); } return BlockPosition::get(Op); } template StatementOpInterface getLastStatementIf(mlir::Region &R, PredicateT &&Predicate) { return getLastOpIf(R, std::forward(Predicate)); } inline StatementOpInterface getLastStatement(mlir::Region &R) { return getLastOp(R); } inline StatementOpInterface getLastNoFallthroughStatement(mlir::Region &R) { return getLastStatementIf(R, [](auto Op) { return Op->template hasTrait(); }); } inline bool isIndirectlyNoFallthrough(mlir::Region &R) { StatementOpInterface Op = getLastStatement(R); if (not Op) return false; if (Op->template hasTrait()) return true; return Op.isIndirectlyNoFallthrough(); } //===----------------------------- Expressions ----------------------------===// inline YieldOp getYieldOp(mlir::Region &R) { return getLastOp(R); } inline ExpressionOpInterface getRootExpression(mlir::Region &R) { if (auto Yield = getYieldOp(R)) return Yield.getValue().getDefiningOp(); return {}; } inline bool isBooleanExpression(mlir::Value Value) { mlir::Operation *Op = Value.getDefiningOp(); return Op and Op->hasTrait(); } inline mlir::OpOperand *getOnlyUse(mlir::Value Value) { auto Begin = Value.use_begin(); auto End = Value.use_end(); if (Begin == End) return nullptr; return &*Begin; } template OpT getOnlyUser(mlir::Value Value) { if (mlir::OpOperand *Operand = getOnlyUse(Value)) { if constexpr (std::is_same_v) { return Operand->getOwner(); } else { return mlir::dyn_cast(Operand->getOwner()); } } return nullptr; } //===-------------------------- Expression usage --------------------------===// /// Returns true if the value is discarded. A value might be discarded by for /// instance by an expression statement or a comma expression. bool isDiscarded(mlir::Value Value); /// Returns true if the value is boolean-tested. A value might be boolean-tested /// for instance by a control flow condition, a ternary expression or a logical /// expression. bool isBooleanTested(mlir::Value Value); } // namespace clift