blob: b938513f8158b57ce36a19430aaba49999eb7440 [file] [log] [blame]
/*
* Copyright (C) 2015-2019 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
* EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
* PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#if ENABLE(B3_JIT)
#include "B3HeapRange.h"
#include "B3Kind.h"
#include "B3Origin.h"
#include "B3Type.h"
#include <wtf/HashTable.h>
namespace JSC { namespace B3 {
class Procedure;
class Value;
// ValueKeys are useful for CSE. They abstractly describe the value that a Value returns when it
// executes. Any Value that has the same ValueKey is guaranteed to return the same value, provided
// that they return a non-empty ValueKey. Operations that have effects, or that can have their
// behavior affected by other operations' effects, will return an empty ValueKey. You have to use
// other mechanisms for doing CSE for impure operations.
class ValueKey {
public:
ValueKey()
{
}
ValueKey(Kind kind, Type type)
: m_kind(kind)
, m_type(type)
{
}
ValueKey(Kind, Type, Value* child);
ValueKey(Kind, Type, Value* left, Value* right);
ValueKey(Kind, Type, Value* a, Value* b, Value* c);
ValueKey(Kind kind, Type type, int64_t value)
: m_kind(kind)
, m_type(type)
{
u.value = value;
}
ValueKey(Kind kind, Type type, double value)
: m_kind(kind)
, m_type(type)
{
u.doubleValue = value;
}
ValueKey(Kind kind, Type type, float value)
: m_kind(kind)
, m_type(type)
{
// This means that upper 32bit of u.value is 0.
u.floatValue = value;
}
static ValueKey intConstant(Type type, int64_t value);
Kind kind() const { return m_kind; }
Opcode opcode() const { return kind().opcode(); }
Type type() const { return m_type; }
unsigned childIndex(unsigned index) const { return u.indices[index]; }
Value* child(Procedure&, unsigned index) const;
int64_t value() const { return u.value; }
double doubleValue() const { return u.doubleValue; }
float floatValue() const { return u.floatValue; }
bool operator==(const ValueKey& other) const
{
return m_kind == other.m_kind
&& m_type == other.m_type
&& u == other.u;
}
bool operator!=(const ValueKey& other) const
{
return !(*this == other);
}
unsigned hash() const
{
return m_kind.hash() + m_type.hash() + WTF::IntHash<int32_t>::hash(u.indices[0]) + u.indices[1] + u.indices[2];
}
explicit operator bool() const { return *this != ValueKey(); }
void dump(PrintStream&) const;
bool canMaterialize() const
{
if (!*this)
return false;
switch (opcode()) {
case CheckAdd:
case CheckSub:
case CheckMul:
return false;
default:
return true;
}
}
bool isConstant() const
{
return B3::isConstant(opcode());
}
// Attempts to materialize the Value for this ValueKey. May return nullptr if the value cannot
// be materialized. This happens for CheckAdd and friends. You can use canMaterialize() to check
// if your key is materializable.
Value* materialize(Procedure&, Origin) const;
ValueKey(WTF::HashTableDeletedValueType)
: m_type { Int32 }
{
}
bool isHashTableDeletedValue() const
{
return *this == ValueKey(WTF::HashTableDeletedValue);
}
private:
Kind m_kind;
Type m_type { Void };
union U {
unsigned indices[3];
int64_t value;
double doubleValue;
float floatValue;
U()
{
indices[0] = 0;
indices[1] = 0;
indices[2] = 0;
}
bool operator==(const U& other) const
{
return indices[0] == other.indices[0]
&& indices[1] == other.indices[1]
&& indices[2] == other.indices[2];
}
} u;
};
struct ValueKeyHash {
static unsigned hash(const ValueKey& key) { return key.hash(); }
static bool equal(const ValueKey& a, const ValueKey& b) { return a == b; }
static constexpr bool safeToCompareToEmptyOrDeleted = true;
};
} } // namespace JSC::B3
namespace WTF {
template<typename T> struct DefaultHash;
template<> struct DefaultHash<JSC::B3::ValueKey> {
typedef JSC::B3::ValueKeyHash Hash;
};
template<typename T> struct HashTraits;
template<> struct HashTraits<JSC::B3::ValueKey> : public SimpleClassHashTraits<JSC::B3::ValueKey> {
static constexpr bool emptyValueIsZero = false;
};
} // namespace WTF
#endif // ENABLE(B3_JIT)