2 * Copyright (C) 2015-2016 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
14 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include "B3ArgumentRegValue.h"
32 #include "B3BasicBlockInlines.h"
33 #include "B3BottomProvider.h"
34 #include "B3CCallValue.h"
35 #include "B3FenceValue.h"
36 #include "B3MemoryValue.h"
37 #include "B3OriginDump.h"
38 #include "B3ProcedureInlines.h"
39 #include "B3SlotBaseValue.h"
40 #include "B3StackSlot.h"
41 #include "B3UpsilonValue.h"
42 #include "B3ValueInlines.h"
43 #include "B3ValueKeyInlines.h"
44 #include "B3VariableValue.h"
45 #include <wtf/CommaPrinter.h>
46 #include <wtf/ListDump.h>
47 #include <wtf/StringPrintStream.h>
49 namespace JSC { namespace B3 {
51 const char* const Value::dumpPrefix = "@";
57 void Value::replaceWithIdentity(Value* value)
59 // This is a bit crazy. It does an in-place replacement of whatever Value subclass this is with
60 // a plain Identity Value. We first collect all of the information we need, then we destruct the
61 // previous value in place, and then we construct the Identity Value in place.
63 ASSERT(m_type == value->m_type);
66 replaceWithNopIgnoringType();
70 unsigned index = m_index;
72 Origin origin = m_origin;
73 BasicBlock* owner = this->owner;
75 RELEASE_ASSERT(type == value->type());
79 new (this) Value(Identity, type, origin, value);
82 this->m_index = index;
85 void Value::replaceWithBottom(InsertionSet& insertionSet, size_t index)
87 replaceWithBottom(BottomProvider(insertionSet, index));
90 void Value::replaceWithNop()
92 RELEASE_ASSERT(m_type == Void);
93 replaceWithNopIgnoringType();
96 void Value::replaceWithNopIgnoringType()
98 unsigned index = m_index;
99 Origin origin = m_origin;
100 BasicBlock* owner = this->owner;
104 new (this) Value(Nop, Void, origin);
107 this->m_index = index;
110 void Value::replaceWithPhi()
112 if (m_type == Void) {
117 unsigned index = m_index;
118 Origin origin = m_origin;
119 BasicBlock* owner = this->owner;
124 new (this) Value(Phi, type, origin);
127 this->m_index = index;
130 void Value::replaceWithJump(BasicBlock* owner, FrequentedBlock target)
132 RELEASE_ASSERT(owner->last() == this);
134 unsigned index = m_index;
135 Origin origin = m_origin;
139 new (this) Value(Jump, Void, origin);
142 this->m_index = index;
144 owner->setSuccessors(target);
147 void Value::replaceWithOops(BasicBlock* owner)
149 RELEASE_ASSERT(owner->last() == this);
151 unsigned index = m_index;
152 Origin origin = m_origin;
156 new (this) Value(Oops, Void, origin);
159 this->m_index = index;
161 owner->clearSuccessors();
164 void Value::replaceWithJump(FrequentedBlock target)
166 replaceWithJump(owner, target);
169 void Value::replaceWithOops()
171 replaceWithOops(owner);
174 void Value::dump(PrintStream& out) const
176 bool isConstant = false;
180 out.print("$", asInt32(), "(");
184 out.print("$", asInt64(), "(");
188 out.print("$", asFloat(), "(");
192 out.print("$", asDouble(), "(");
199 out.print(dumpPrefix, m_index);
205 Value* Value::cloneImpl() const
207 return new Value(*this);
210 void Value::dumpChildren(CommaPrinter& comma, PrintStream& out) const
212 for (Value* child : children())
213 out.print(comma, pointerDump(child));
216 void Value::deepDump(const Procedure* proc, PrintStream& out) const
218 out.print(m_type, " ", dumpPrefix, m_index, " = ", m_kind);
222 dumpChildren(comma, out);
225 out.print(comma, OriginDump(proc, m_origin));
227 dumpMeta(comma, out);
230 CString string = toCString(effects());
232 out.print(comma, string);
238 void Value::dumpSuccessors(const BasicBlock* block, PrintStream& out) const
240 // Note that this must not crash if we have the wrong number of successors, since someone
241 // debugging a number-of-successors bug will probably want to dump IR!
243 if (opcode() == Branch && block->numSuccessors() == 2) {
244 out.print("Then:", block->taken(), ", Else:", block->notTaken());
248 out.print(listDump(block->successors()));
251 Value* Value::negConstant(Procedure&) const
256 Value* Value::addConstant(Procedure&, int32_t) const
261 Value* Value::addConstant(Procedure&, const Value*) const
266 Value* Value::subConstant(Procedure&, const Value*) const
271 Value* Value::mulConstant(Procedure&, const Value*) const
276 Value* Value::checkAddConstant(Procedure&, const Value*) const
281 Value* Value::checkSubConstant(Procedure&, const Value*) const
286 Value* Value::checkMulConstant(Procedure&, const Value*) const
291 Value* Value::checkNegConstant(Procedure&) const
296 Value* Value::divConstant(Procedure&, const Value*) const
301 Value* Value::modConstant(Procedure&, const Value*) const
306 Value* Value::bitAndConstant(Procedure&, const Value*) const
311 Value* Value::bitOrConstant(Procedure&, const Value*) const
316 Value* Value::bitXorConstant(Procedure&, const Value*) const
321 Value* Value::shlConstant(Procedure&, const Value*) const
326 Value* Value::sShrConstant(Procedure&, const Value*) const
331 Value* Value::zShrConstant(Procedure&, const Value*) const
336 Value* Value::bitwiseCastConstant(Procedure&) const
341 Value* Value::iToDConstant(Procedure&) const
346 Value* Value::iToFConstant(Procedure&) const
351 Value* Value::doubleToFloatConstant(Procedure&) const
356 Value* Value::floatToDoubleConstant(Procedure&) const
361 Value* Value::absConstant(Procedure&) const
366 Value* Value::ceilConstant(Procedure&) const
371 Value* Value::floorConstant(Procedure&) const
376 Value* Value::sqrtConstant(Procedure&) const
381 TriState Value::equalConstant(const Value*) const
383 return MixedTriState;
386 TriState Value::notEqualConstant(const Value*) const
388 return MixedTriState;
391 TriState Value::lessThanConstant(const Value*) const
393 return MixedTriState;
396 TriState Value::greaterThanConstant(const Value*) const
398 return MixedTriState;
401 TriState Value::lessEqualConstant(const Value*) const
403 return MixedTriState;
406 TriState Value::greaterEqualConstant(const Value*) const
408 return MixedTriState;
411 TriState Value::aboveConstant(const Value*) const
413 return MixedTriState;
416 TriState Value::belowConstant(const Value*) const
418 return MixedTriState;
421 TriState Value::aboveEqualConstant(const Value*) const
423 return MixedTriState;
426 TriState Value::belowEqualConstant(const Value*) const
428 return MixedTriState;
431 TriState Value::equalOrUnorderedConstant(const Value*) const
433 return MixedTriState;
436 Value* Value::invertedCompare(Procedure& proc) const
440 if (Optional<Opcode> invertedOpcode = B3::invertedCompare(opcode(), child(0)->type())) {
441 ASSERT(!kind().hasExtraBits());
442 return proc.add<Value>(*invertedOpcode, type(), origin(), children());
447 bool Value::isRounded() const
449 ASSERT(isFloat(type()));
458 double value = asDouble();
459 return std::isfinite(value) && value == ceil(value);
463 float value = asFloat();
464 return std::isfinite(value) && value == ceilf(value);
472 bool Value::returnsBool() const
478 return asInt32() == 0 || asInt32() == 1;
480 return child(1)->isInt32(1)
481 || (child(0)->returnsBool() && child(1)->hasInt() && child(1)->asInt() & 1);
492 case EqualOrUnordered:
495 // FIXME: We should have a story here.
496 // https://bugs.webkit.org/show_bug.cgi?id=150725
503 TriState Value::asTriState() const
507 return triState(!!asInt32());
509 return triState(!!asInt64());
511 // Use "!= 0" to really emphasize what this mean with respect to NaN and such.
512 return triState(asDouble() != 0);
514 return triState(asFloat() != 0.);
516 return MixedTriState;
520 Effects Value::effects() const
568 case EqualOrUnordered:
573 result.controlDependent = true;
580 result.reads = as<MemoryValue>()->range();
581 result.controlDependent = true;
586 result.writes = as<MemoryValue>()->range();
587 result.controlDependent = true;
590 const FenceValue* fence = as<FenceValue>();
591 result.reads = fence->read;
592 result.writes = fence->write;
594 // Prevent killing of fences that claim not to write anything. It's a bit weird that we use
595 // local state as the way to do this, but it happens to work: we must assume that we cannot
596 // kill writesLocalState unless we understands exactly what the instruction is doing (like
597 // the way that fixSSA understands Set/Get and the way that reduceStrength and others
598 // understand Upsilon). This would only become a problem if we had some analysis that was
599 // looking to use the writesLocalState bit to invalidate a CSE over local state operations.
600 // Then a Fence would look block, say, the elimination of a redundant Get. But it like
601 // that's not at all how our optimizations for Set/Get/Upsilon/Phi work - they grok their
602 // operations deeply enough that they have no need to check this bit - so this cheat is
604 result.writesLocalState = true;
608 result = as<CCallValue>()->effects;
611 result = as<PatchpointValue>()->effects;
617 result.exitsSideways = true;
618 // The program could read anything after exiting, and it's on us to declare this.
619 result.reads = HeapRange::top();
623 result.writesLocalState = true;
627 result.readsLocalState = true;
635 result.terminal = true;
639 result.exitsSideways = true;
640 result.reads = HeapRange::top();
645 ValueKey Value::key() const
649 return ValueKey(kind(), type());
668 return ValueKey(kind(), type(), child(0));
688 case EqualOrUnordered:
692 return ValueKey(kind(), type(), child(0), child(1));
694 return ValueKey(kind(), type(), child(0), child(1), child(2));
696 return ValueKey(Const32, type(), static_cast<int64_t>(asInt32()));
698 return ValueKey(Const64, type(), asInt64());
700 return ValueKey(ConstDouble, type(), asDouble());
702 return ValueKey(ConstFloat, type(), asFloat());
706 static_cast<int64_t>(as<ArgumentRegValue>()->argumentReg().index()));
710 static_cast<int64_t>(as<SlotBaseValue>()->slot()->index()));
716 void Value::performSubstitution()
718 for (Value*& child : children()) {
719 while (child->opcode() == Identity)
720 child = child->child(0);
724 bool Value::isFree() const
739 void Value::dumpMeta(CommaPrinter&, PrintStream&) const
743 Type Value::typeFor(Kind kind, Value* firstChild, Value* secondChild)
745 switch (kind.opcode()) {
767 return firstChild->type();
769 return pointerType();
783 case EqualOrUnordered:
795 switch (firstChild->type()) {
805 ASSERT_NOT_REACHED();
817 return secondChild->type();
819 RELEASE_ASSERT_NOT_REACHED();
823 void Value::badKind(Kind kind, unsigned numArgs)
825 dataLog("Bad kind ", kind, " with ", numArgs, " args.\n");
826 RELEASE_ASSERT_NOT_REACHED();
829 } } // namespace JSC::B3
831 #endif // ENABLE(B3_JIT)