// // Cforall Version 1.0.0 Copyright (C) 2015 University of Waterloo // // The contents of this file are covered under the licence agreement in the // file "LICENCE" distributed with Cforall. // // MultiLevelExit.cpp -- Replaces CFA's local control flow with C's versions. // // Author : Andrew Beach // Created On : Mon Nov 1 13:48:00 2021 // Last Modified By : Andrew Beach // Last Modified On : Mon Mar 28 9:42:00 2022 // Update Count : 34 // #include "MultiLevelExit.hpp" #include "AST/Pass.hpp" #include "AST/Stmt.hpp" #include "Common/CodeLocationTools.hpp" #include "LabelGeneratorNew.hpp" #include using namespace std; using namespace ast; namespace ControlStruct { class Entry { public: const Stmt * stmt; private: // Organized like a manual ADT. Avoids creating a bunch of dead data. struct Target { Label label; bool used = false; Target( const Label & label ) : label( label ) {} Target() : label( CodeLocation() ) {} }; Target firstTarget; Target secondTarget; enum Kind { ForStmtK, WhileDoStmtK, CompoundStmtK, IfStmtK, CaseClauseK, SwitchStmtK, TryStmtK } kind; bool fallDefaultValid = true; static Label & useTarget( Target & target ) { target.used = true; return target.label; } public: Entry( const ForStmt * stmt, Label breakExit, Label contExit ) : stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( ForStmtK ) {} Entry( const WhileDoStmt * stmt, Label breakExit, Label contExit ) : stmt( stmt ), firstTarget( breakExit ), secondTarget( contExit ), kind( WhileDoStmtK ) {} Entry( const CompoundStmt *stmt, Label breakExit ) : stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( CompoundStmtK ) {} Entry( const IfStmt *stmt, Label breakExit ) : stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( IfStmtK ) {} Entry( const CaseClause *, const CompoundStmt *stmt, Label fallExit ) : stmt( stmt ), firstTarget( fallExit ), secondTarget(), kind( CaseClauseK ) {} Entry( const SwitchStmt *stmt, Label breakExit, Label fallDefaultExit ) : stmt( stmt ), firstTarget( breakExit ), secondTarget( fallDefaultExit ), kind( SwitchStmtK ) {} Entry( const TryStmt *stmt, Label breakExit ) : stmt( stmt ), firstTarget( breakExit ), secondTarget(), kind( TryStmtK ) {} bool isContTarget() const { return kind <= WhileDoStmtK; } bool isBreakTarget() const { return kind != CaseClauseK; } bool isFallTarget() const { return kind == CaseClauseK; } bool isFallDefaultTarget() const { return kind == SwitchStmtK; } // These routines set a target as being "used" by a BranchStmt Label useContExit() { assert( kind <= WhileDoStmtK ); return useTarget(secondTarget); } Label useBreakExit() { assert( kind != CaseClauseK ); return useTarget(firstTarget); } Label useFallExit() { assert( kind == CaseClauseK ); return useTarget(firstTarget); } Label useFallDefaultExit() { assert( kind == SwitchStmtK ); return useTarget(secondTarget); } // These routines check if a specific label for a statement is used by a BranchStmt bool isContUsed() const { assert( kind <= WhileDoStmtK ); return secondTarget.used; } bool isBreakUsed() const { assert( kind != CaseClauseK ); return firstTarget.used; } bool isFallUsed() const { assert( kind == CaseClauseK ); return firstTarget.used; } bool isFallDefaultUsed() const { assert( kind == SwitchStmtK ); return secondTarget.used; } void seenDefault() { fallDefaultValid = false; } bool isFallDefaultValid() const { return fallDefaultValid; } }; // Helper predicates used in find_if calls (it doesn't take methods): bool isBreakTarget( const Entry & entry ) { return entry.isBreakTarget(); } bool isContinueTarget( const Entry & entry ) { return entry.isContTarget(); } bool isFallthroughTarget( const Entry & entry ) { return entry.isFallTarget(); } bool isFallthroughDefaultTarget( const Entry & entry ) { return entry.isFallDefaultTarget(); } struct MultiLevelExitCore final : public WithVisitorRef, public WithShortCircuiting, public WithGuards { MultiLevelExitCore( const LabelToStmt & lt ); void previsit( const FunctionDecl * ); const CompoundStmt * previsit( const CompoundStmt * ); const BranchStmt * postvisit( const BranchStmt * ); void previsit( const WhileDoStmt * ); const WhileDoStmt * postvisit( const WhileDoStmt * ); void previsit( const ForStmt * ); const ForStmt * postvisit( const ForStmt * ); const CaseClause * previsit( const CaseClause * ); void previsit( const IfStmt * ); const IfStmt * postvisit( const IfStmt * ); void previsit( const SwitchStmt * ); const SwitchStmt * postvisit( const SwitchStmt * ); void previsit( const ReturnStmt * ); void previsit( const TryStmt * ); void postvisit( const TryStmt * ); void previsit( const FinallyClause * ); const Stmt * mutateLoop( const Stmt * body, Entry& ); const LabelToStmt & target_table; set