//===- subzero/src/IceSwitchLowering.h - Switch lowering --------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// /// /// \file /// \brief Helpers for switch lowering. /// //===----------------------------------------------------------------------===// #ifndef SUBZERO_SRC_ICESWITCHLOWERING_H #define SUBZERO_SRC_ICESWITCHLOWERING_H #include "IceDefs.h" #include "IceStringPool.h" #include <string> namespace Ice { class CaseCluster; using CaseClusterArray = CfgVector<CaseCluster>; /// A cluster of cases can be tested by a common method during switch lowering. class CaseCluster { CaseCluster() = delete; public: enum CaseClusterKind { Range, /// Numerically adjacent case values with same target. JumpTable, /// Different targets and possibly sparse. }; CaseCluster(const CaseCluster &) = default; CaseCluster &operator=(const CaseCluster &) = default; /// Create a cluster of a single case represented by a unitary range. CaseCluster(uint64_t Value, CfgNode *Target) : Kind(Range), Low(Value), High(Value), Target(Target) {} /// Create a case consisting of a jump table. CaseCluster(uint64_t Low, uint64_t High, InstJumpTable *JT) : Kind(JumpTable), Low(Low), High(High), JT(JT) {} CaseClusterKind getKind() const { return Kind; } uint64_t getLow() const { return Low; } uint64_t getHigh() const { return High; } CfgNode *getTarget() const { assert(Kind == Range); return Target; } InstJumpTable *getJumpTable() const { assert(Kind == JumpTable); return JT; } bool isUnitRange() const { return Low == High; } bool isPairRange() const { return Low == High - 1; } /// Discover cases which can be clustered together and return the clusters /// ordered by case value. static CaseClusterArray clusterizeSwitch(Cfg *Func, const InstSwitch *Instr); private: CaseClusterKind Kind; uint64_t Low; uint64_t High; union { CfgNode *Target; /// Target for a range. InstJumpTable *JT; /// Jump table targets. }; /// Try and append a cluster returning whether or not it was successful. bool tryAppend(const CaseCluster &New); }; /// Store the jump table data so that it can be emitted later in the correct ELF /// section once the offsets from the start of the function are known. class JumpTableData { JumpTableData() = delete; JumpTableData &operator=(const JumpTableData &) = delete; public: using TargetList = std::vector<intptr_t>; JumpTableData(GlobalString Name, GlobalString FuncName, SizeT Id, const TargetList &TargetOffsets) : Name(Name), FuncName(FuncName), Id(Id), TargetOffsets(TargetOffsets) {} JumpTableData(const JumpTableData &) = default; JumpTableData(JumpTableData &&) = default; JumpTableData &operator=(JumpTableData &&) = default; GlobalString getName() const { return Name; } GlobalString getFunctionName() const { return FuncName; } SizeT getId() const { return Id; } const TargetList &getTargetOffsets() const { return TargetOffsets; } static std::string createSectionName(const GlobalString Name) { if (Name.hasStdString()) { return Name.toString() + "$jumptable"; } return std::to_string(Name.getID()) + "$jumptable"; } std::string getSectionName() const { return createSectionName(FuncName); } private: GlobalString Name; GlobalString FuncName; SizeT Id; TargetList TargetOffsets; }; using JumpTableDataList = std::vector<JumpTableData>; } // end of namespace Ice #endif // SUBZERO_SRC_ICESWITCHLOWERING_H