blob: 57dd8288079b9e173095b2ebcb073d927b7ea52a [file] [log] [blame]
//===- 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