blob: ad5439df5444c8e4b5822bf24922220a51360b5d [file] [log] [blame]
/*
* Copyright (C) 2015 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.
*/
#include "config.h"
#include "B3Value.h"
#if ENABLE(B3_JIT)
#include "B3ArgumentRegValue.h"
#include "B3CCallValue.h"
#include "B3ControlValue.h"
#include "B3MemoryValue.h"
#include "B3ProcedureInlines.h"
#include "B3StackSlotValue.h"
#include "B3UpsilonValue.h"
#include "B3ValueInlines.h"
#include "B3ValueKeyInlines.h"
#include <wtf/CommaPrinter.h>
#include <wtf/StringPrintStream.h>
namespace JSC { namespace B3 {
const char* const Value::dumpPrefix = "@";
Value::~Value()
{
}
void Value::replaceWithIdentity(Value* value)
{
// This is a bit crazy. It does an in-place replacement of whatever Value subclass this is with
// a plain Identity Value. We first collect all of the information we need, then we destruct the
// previous value in place, and then we construct the Identity Value in place.
unsigned index = m_index;
Type type = m_type;
Origin origin = m_origin;
BasicBlock* owner = this->owner;
RELEASE_ASSERT(type == value->type());
this->Value::~Value();
new (this) Value(index, Identity, type, origin, value);
this->owner = owner;
}
void Value::replaceWithNop()
{
unsigned index = m_index;
Origin origin = m_origin;
BasicBlock* owner = this->owner;
this->Value::~Value();
new (this) Value(index, Nop, Void, origin);
this->owner = owner;
}
void Value::dump(PrintStream& out) const
{
out.print(dumpPrefix, m_index);
}
void Value::dumpChildren(CommaPrinter& comma, PrintStream& out) const
{
for (Value* child : children())
out.print(comma, pointerDump(child));
}
void Value::deepDump(PrintStream& out) const
{
out.print(m_type, " ", *this, " = ", m_opcode);
out.print("(");
CommaPrinter comma;
dumpChildren(comma, out);
if (m_origin)
out.print(comma, m_origin);
dumpMeta(comma, out);
{
CString string = toCString(effects());
if (string.length())
out.print(comma, string);
}
out.print(")");
}
Value* Value::negConstant(Procedure&) const
{
return nullptr;
}
Value* Value::addConstant(Procedure&, int32_t) const
{
return nullptr;
}
Value* Value::addConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::subConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::mulConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::checkAddConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::checkSubConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::checkMulConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::checkNegConstant(Procedure&) const
{
return nullptr;
}
Value* Value::divConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::bitAndConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::bitOrConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::bitXorConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::shlConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::sShrConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::zShrConstant(Procedure&, const Value*) const
{
return nullptr;
}
Value* Value::bitwiseCastConstant(Procedure&) const
{
return nullptr;
}
TriState Value::equalConstant(const Value*) const
{
return MixedTriState;
}
TriState Value::notEqualConstant(const Value*) const
{
return MixedTriState;
}
TriState Value::lessThanConstant(const Value*) const
{
return MixedTriState;
}
TriState Value::greaterThanConstant(const Value*) const
{
return MixedTriState;
}
TriState Value::lessEqualConstant(const Value*) const
{
return MixedTriState;
}
TriState Value::greaterEqualConstant(const Value*) const
{
return MixedTriState;
}
TriState Value::aboveConstant(const Value*) const
{
return MixedTriState;
}
TriState Value::belowConstant(const Value*) const
{
return MixedTriState;
}
TriState Value::aboveEqualConstant(const Value*) const
{
return MixedTriState;
}
TriState Value::belowEqualConstant(const Value*) const
{
return MixedTriState;
}
Value* Value::invertedCompare(Procedure& proc) const
{
if (!numChildren())
return nullptr;
if (Optional<Opcode> invertedOpcode = B3::invertedCompare(opcode(), child(0)->type()))
return proc.add<Value>(*invertedOpcode, type(), origin(), children());
return nullptr;
}
bool Value::returnsBool() const
{
if (type() != Int32)
return false;
switch (opcode()) {
case Const32:
return asInt32() == 0 || asInt32() == 1;
case BitAnd:
return child(1)->isInt32(1);
case Equal:
case NotEqual:
case LessThan:
case GreaterThan:
case LessEqual:
case GreaterEqual:
case Above:
case Below:
case AboveEqual:
case BelowEqual:
return true;
case Phi:
// FIXME: We should have a story here.
// https://bugs.webkit.org/show_bug.cgi?id=150725
return false;
default:
return false;
}
}
TriState Value::asTriState() const
{
switch (opcode()) {
case Const32:
return triState(!!asInt32());
case Const64:
return triState(!!asInt64());
case ConstDouble:
// Use "!= 0" to really emphasize what this mean with respect to NaN and such.
return triState(asDouble() != 0);
default:
return MixedTriState;
}
}
Effects Value::effects() const
{
Effects result;
switch (opcode()) {
case Nop:
case Identity:
case Const32:
case Const64:
case ConstDouble:
case StackSlot:
case ArgumentReg:
case FramePointer:
case Add:
case Sub:
case Mul:
case ChillDiv:
case Mod:
case BitAnd:
case BitOr:
case BitXor:
case Shl:
case SShr:
case ZShr:
case Sqrt:
case BitwiseCast:
case SExt8:
case SExt16:
case SExt32:
case ZExt32:
case Trunc:
case FRound:
case IToD:
case DToI32:
case Equal:
case NotEqual:
case LessThan:
case GreaterThan:
case LessEqual:
case GreaterEqual:
case Above:
case Below:
case AboveEqual:
case BelowEqual:
case Select:
break;
case Div:
result.controlDependent = true;
break;
case Load8Z:
case Load8S:
case Load16Z:
case Load16S:
case LoadFloat:
case Load:
result.reads = as<MemoryValue>()->range();
result.controlDependent = true;
break;
case Store8:
case Store16:
case StoreFloat:
case Store:
result.writes = as<MemoryValue>()->range();
result.controlDependent = true;
break;
case CCall:
result = as<CCallValue>()->effects;
break;
case Patchpoint:
result = as<PatchpointValue>()->effects;
break;
case CheckAdd:
case CheckSub:
case CheckMul:
case Check:
result.exitsSideways = true;
break;
case Upsilon:
result.writesSSAState = true;
break;
case Phi:
result.readsSSAState = true;
break;
case Jump:
case Branch:
case Switch:
case Return:
case Oops:
result.terminal = true;
break;
}
return result;
}
ValueKey Value::key() const
{
switch (opcode()) {
case FramePointer:
return ValueKey(opcode(), type());
case Identity:
case Sqrt:
case SExt8:
case SExt16:
case SExt32:
case ZExt32:
case Trunc:
case FRound:
case IToD:
case DToI32:
case Check:
return ValueKey(opcode(), type(), child(0));
case Add:
case Sub:
case Mul:
case ChillDiv:
case Mod:
case BitAnd:
case BitOr:
case BitXor:
case Shl:
case SShr:
case ZShr:
case Equal:
case NotEqual:
case LessThan:
case GreaterThan:
case Above:
case Below:
case AboveEqual:
case BelowEqual:
case Div:
case CheckAdd:
case CheckSub:
case CheckMul:
return ValueKey(opcode(), type(), child(0), child(1));
case Select:
return ValueKey(opcode(), type(), child(0), child(1), child(2));
case Const32:
return ValueKey(Const32, type(), static_cast<int64_t>(asInt32()));
case Const64:
return ValueKey(Const64, type(), asInt64());
case ConstDouble:
return ValueKey(ConstDouble, type(), asDouble());
case ArgumentReg:
return ValueKey(
ArgumentReg, type(),
static_cast<int64_t>(as<ArgumentRegValue>()->argumentReg().index()));
default:
return ValueKey();
}
}
void Value::performSubstitution()
{
for (Value*& child : children()) {
while (child->opcode() == Identity)
child = child->child(0);
}
}
void Value::dumpMeta(CommaPrinter&, PrintStream&) const
{
}
#if !ASSERT_DISABLED
void Value::checkOpcode(Opcode opcode)
{
ASSERT(!ArgumentRegValue::accepts(opcode));
ASSERT(!CCallValue::accepts(opcode));
ASSERT(!CheckValue::accepts(opcode));
ASSERT(!Const32Value::accepts(opcode));
ASSERT(!Const64Value::accepts(opcode));
ASSERT(!ConstDoubleValue::accepts(opcode));
ASSERT(!ControlValue::accepts(opcode));
ASSERT(!MemoryValue::accepts(opcode));
ASSERT(!PatchpointValue::accepts(opcode));
ASSERT(!StackSlotValue::accepts(opcode));
ASSERT(!UpsilonValue::accepts(opcode));
}
#endif // !ASSERT_DISABLED
Type Value::typeFor(Opcode opcode, Value* firstChild, Value* secondChild)
{
switch (opcode) {
case Identity:
case Add:
case Sub:
case Mul:
case Div:
case ChillDiv:
case Mod:
case BitAnd:
case BitOr:
case BitXor:
case Shl:
case SShr:
case ZShr:
case Sqrt:
case CheckAdd:
case CheckSub:
case CheckMul:
return firstChild->type();
case FramePointer:
return pointerType();
case SExt8:
case SExt16:
case Trunc:
case DToI32:
case Equal:
case NotEqual:
case LessThan:
case GreaterThan:
case LessEqual:
case GreaterEqual:
case Above:
case Below:
case AboveEqual:
case BelowEqual:
return Int32;
case SExt32:
case ZExt32:
return Int64;
case FRound:
case IToD:
return Double;
case BitwiseCast:
if (firstChild->type() == Int64)
return Double;
if (firstChild->type() == Double)
return Int64;
ASSERT_NOT_REACHED();
return Void;
case Nop:
return Void;
case Select:
ASSERT(secondChild);
return secondChild->type();
default:
RELEASE_ASSERT_NOT_REACHED();
}
}
} } // namespace JSC::B3
#endif // ENABLE(B3_JIT)