#ifndef V8_COMPILER_OPERATOR_H_
#define V8_COMPILER_OPERATOR_H_
#include <ostream>
#include <type_traits>
#include "src/base/compiler-specific.h"
#include "src/base/flags.h"
#include "src/base/hashing.h"
#include "src/common/globals.h"
#include "src/handles/handles.h"
#include "src/zone/zone.h"
namespace v8 {
namespace internal {
namespace compiler {
class V8_EXPORT_PRIVATE Operator : public NON_EXPORTED_BASE(ZoneObject) {
public:
using Opcode = uint16_t;
enum Property {
kNoProperties = 0,
kCommutative = 1 << 0,
kAssociative = 1 << 1,
kIdempotent = 1 << 2,
kNoRead = 1 << 3,
kNoWrite = 1 << 4,
kNoThrow = 1 << 5,
kNoDeopt = 1 << 6,
kFoldable = kNoRead | kNoWrite,
kEliminatable = kNoDeopt | kNoWrite | kNoThrow,
kKontrol = kNoDeopt | kFoldable | kNoThrow,
kPure = kKontrol | kIdempotent
};
#define OPERATOR_PROPERTY_LIST(V) \
V(Commutative) \
V(Associative) V(Idempotent) V(NoRead) V(NoWrite) V(NoThrow) V(NoDeopt)
using Properties = base::Flags<Property, uint8_t>;
enum class PrintVerbosity { kVerbose, kSilent };
Operator(Opcode opcode, Properties properties, const char* mnemonic,
size_t value_in, size_t effect_in, size_t control_in,
size_t value_out, size_t effect_out, size_t control_out);
Operator(const Operator&) = delete;
Operator& operator=(const Operator&) = delete;
virtual ~Operator() = default;
constexpr Opcode opcode() const { return opcode_; }
const char* mnemonic() const { return mnemonic_; }
virtual bool Equals(const Operator* that) const {
return this->opcode() == that->opcode();
}
virtual size_t HashCode() const { return base::hash<Opcode>()(opcode()); }
bool HasProperty(Property property) const {
return (properties() & property) == property;
}
Properties properties() const { return properties_; }
int ValueInputCount() const { return value_in_; }
int EffectInputCount() const { return effect_in_; }
int ControlInputCount() const { return control_in_; }
int ValueOutputCount() const { return value_out_; }
int EffectOutputCount() const { return effect_out_; }
int ControlOutputCount() const { return control_out_; }
static size_t ZeroIfEliminatable(Properties properties) {
return (properties & kEliminatable) == kEliminatable ? 0 : 1;
}
static size_t ZeroIfNoThrow(Properties properties) {
return (properties & kNoThrow) == kNoThrow ? 0 : 2;
}
static size_t ZeroIfPure(Properties properties) {
return (properties & kPure) == kPure ? 0 : 1;
}
void PrintTo(std::ostream& os,
PrintVerbosity verbose = PrintVerbosity::kVerbose) const {
return PrintToImpl(os, verbose);
}
void PrintPropsTo(std::ostream& os) const;
#if defined(DEBUG) && !defined(COMPONENT_BUILD)
struct ClassTag_t {};
virtual const ClassTag_t* ClassTag() const {
static constexpr ClassTag_t kCanonicalClassTag = {};
return &kCanonicalClassTag;
}
#endif
protected:
virtual void PrintToImpl(std::ostream& os, PrintVerbosity verbose) const;
private:
const char* mnemonic_;
Opcode opcode_;
Properties properties_;
uint8_t effect_out_;
uint32_t value_in_;
uint32_t effect_in_;
uint32_t control_in_;
uint32_t value_out_;
uint32_t control_out_;
};
DEFINE_OPERATORS_FOR_FLAGS(Operator::Properties)
V8_EXPORT_PRIVATE std::ostream& operator<<(std::ostream& os,
const Operator& op);
template <typename T>
struct OpEqualTo : public std::equal_to<T> {};
template <typename T>
struct OpHash : public base::hash<T> {};
template <typename T, typename Pred = OpEqualTo<T>, typename Hash = OpHash<T>>
class Operator1 : public Operator {
static_assert(std::is_empty_v<Pred>);
static_assert(std::is_empty_v<Hash>);
public:
static const Operator1* Cast(const Operator* op) {
#if defined(DEBUG) && !defined(COMPONENT_BUILD)
DCHECK_EQ(op->ClassTag(), &kCanonicalClassTag);
#endif
return static_cast<const Operator1*>(op);
}
Operator1(Opcode opcode, Properties properties, const char* mnemonic,
size_t value_in, size_t effect_in, size_t control_in,
size_t value_out, size_t effect_out, size_t control_out,
T parameter)
: Operator(opcode, properties, mnemonic, value_in, effect_in, control_in,
value_out, effect_out, control_out),
parameter_(parameter) {}
T const& parameter() const { return parameter_; }
bool Equals(const Operator* other) const final {
if (opcode() != other->opcode()) return false;
return Pred{}(this->parameter(), Cast(other)->parameter());
}
size_t HashCode() const final {
return base::hash_combine(this->opcode(), Hash{}(this->parameter()));
}
virtual void PrintParameter(std::ostream& os, PrintVerbosity verbose) const {
os << "[" << parameter() << "]";
}
void PrintToImpl(std::ostream& os, PrintVerbosity verbose) const override {
os << mnemonic();
PrintParameter(os, verbose);
}
#if defined(DEBUG) && !defined(COMPONENT_BUILD)
const ClassTag_t* ClassTag() const final { return &kCanonicalClassTag; }
#endif
private:
#if defined(DEBUG) && !defined(COMPONENT_BUILD)
static constexpr ClassTag_t kCanonicalClassTag = {};
#endif
T const parameter_;
};
template <typename T>
inline T const& OpParameter(const Operator* op) {
return Operator1<T>::Cast(op)->parameter();
}
template <>
struct OpEqualTo<float> : public base::bit_equal_to<float> {};
template <>
struct OpHash<float> : public base::bit_hash<float> {};
template <>
struct OpEqualTo<double> : public base::bit_equal_to<double> {};
template <>
struct OpHash<double> : public base::bit_hash<double> {};
template <class T>
struct OpEqualTo<IndirectHandle<T>> : public IndirectHandle<T>::equal_to {};
template <class T>
struct OpHash<IndirectHandle<T>> : public IndirectHandle<T>::hash {};
}
}
}
#endif