summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/b3/air
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-04-10 09:28:39 +0000
commit32761a6cee1d0dee366b885b7b9c777e67885688 (patch)
treed6bec92bebfb216f4126356e55518842c2f476a1 /Source/JavaScriptCore/b3/air
parenta4e969f4965059196ca948db781e52f7cfebf19e (diff)
downloadWebKitGtk-tarball-32761a6cee1d0dee366b885b7b9c777e67885688.tar.gz
webkitgtk-2.4.11webkitgtk-2.4.11
Diffstat (limited to 'Source/JavaScriptCore/b3/air')
-rw-r--r--Source/JavaScriptCore/b3/air/AirAllocateStack.cpp307
-rw-r--r--Source/JavaScriptCore/b3/air/AirAllocateStack.h47
-rw-r--r--Source/JavaScriptCore/b3/air/AirArg.cpp330
-rw-r--r--Source/JavaScriptCore/b3/air/AirArg.h1345
-rw-r--r--Source/JavaScriptCore/b3/air/AirArgInlines.h116
-rw-r--r--Source/JavaScriptCore/b3/air/AirBasicBlock.cpp87
-rw-r--r--Source/JavaScriptCore/b3/air/AirBasicBlock.h176
-rw-r--r--Source/JavaScriptCore/b3/air/AirBlockWorklist.h56
-rw-r--r--Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp167
-rw-r--r--Source/JavaScriptCore/b3/air/AirCCallSpecial.h88
-rw-r--r--Source/JavaScriptCore/b3/air/AirCCallingConvention.cpp127
-rw-r--r--Source/JavaScriptCore/b3/air/AirCCallingConvention.h55
-rw-r--r--Source/JavaScriptCore/b3/air/AirCode.cpp139
-rw-r--r--Source/JavaScriptCore/b3/air/AirCode.h243
-rw-r--r--Source/JavaScriptCore/b3/air/AirCustom.cpp184
-rw-r--r--Source/JavaScriptCore/b3/air/AirCustom.h213
-rw-r--r--Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp153
-rw-r--r--Source/JavaScriptCore/b3/air/AirEliminateDeadCode.h47
-rw-r--r--Source/JavaScriptCore/b3/air/AirEmitShuffle.cpp542
-rw-r--r--Source/JavaScriptCore/b3/air/AirEmitShuffle.h118
-rw-r--r--Source/JavaScriptCore/b3/air/AirFixObviousSpills.cpp532
-rw-r--r--Source/JavaScriptCore/b3/air/AirFixObviousSpills.h45
-rw-r--r--Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp237
-rw-r--r--Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.h49
-rw-r--r--Source/JavaScriptCore/b3/air/AirFrequentedBlock.h44
-rw-r--r--Source/JavaScriptCore/b3/air/AirGenerate.cpp248
-rw-r--r--Source/JavaScriptCore/b3/air/AirGenerate.h52
-rw-r--r--Source/JavaScriptCore/b3/air/AirGenerated.cpp33
-rw-r--r--Source/JavaScriptCore/b3/air/AirGenerationContext.h55
-rw-r--r--Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.cpp77
-rw-r--r--Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.h50
-rw-r--r--Source/JavaScriptCore/b3/air/AirInsertionSet.cpp57
-rw-r--r--Source/JavaScriptCore/b3/air/AirInsertionSet.h84
-rw-r--r--Source/JavaScriptCore/b3/air/AirInst.cpp60
-rw-r--r--Source/JavaScriptCore/b3/air/AirInst.h203
-rw-r--r--Source/JavaScriptCore/b3/air/AirInstInlines.h299
-rw-r--r--Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp1542
-rw-r--r--Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.h44
-rw-r--r--Source/JavaScriptCore/b3/air/AirLiveness.h396
-rw-r--r--Source/JavaScriptCore/b3/air/AirLogRegisterPressure.cpp102
-rw-r--r--Source/JavaScriptCore/b3/air/AirLogRegisterPressure.h43
-rw-r--r--Source/JavaScriptCore/b3/air/AirLowerAfterRegAlloc.cpp247
-rw-r--r--Source/JavaScriptCore/b3/air/AirLowerAfterRegAlloc.h44
-rw-r--r--Source/JavaScriptCore/b3/air/AirLowerMacros.cpp105
-rw-r--r--Source/JavaScriptCore/b3/air/AirLowerMacros.h45
-rw-r--r--Source/JavaScriptCore/b3/air/AirOpcode.opcodes850
-rw-r--r--Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp182
-rw-r--r--Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.h53
-rw-r--r--Source/JavaScriptCore/b3/air/AirPhaseScope.cpp60
-rw-r--r--Source/JavaScriptCore/b3/air/AirPhaseScope.h57
-rw-r--r--Source/JavaScriptCore/b3/air/AirRegisterPriority.cpp104
-rw-r--r--Source/JavaScriptCore/b3/air/AirRegisterPriority.h62
-rw-r--r--Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp95
-rw-r--r--Source/JavaScriptCore/b3/air/AirReportUsedRegisters.h45
-rw-r--r--Source/JavaScriptCore/b3/air/AirSimplifyCFG.cpp172
-rw-r--r--Source/JavaScriptCore/b3/air/AirSimplifyCFG.h44
-rw-r--r--Source/JavaScriptCore/b3/air/AirSpecial.cpp79
-rw-r--r--Source/JavaScriptCore/b3/air/AirSpecial.h138
-rw-r--r--Source/JavaScriptCore/b3/air/AirSpillEverything.cpp187
-rw-r--r--Source/JavaScriptCore/b3/air/AirSpillEverything.h53
-rw-r--r--Source/JavaScriptCore/b3/air/AirStackSlot.cpp69
-rw-r--r--Source/JavaScriptCore/b3/air/AirStackSlot.h134
-rw-r--r--Source/JavaScriptCore/b3/air/AirStackSlotKind.cpp52
-rw-r--r--Source/JavaScriptCore/b3/air/AirStackSlotKind.h67
-rw-r--r--Source/JavaScriptCore/b3/air/AirTmp.cpp55
-rw-r--r--Source/JavaScriptCore/b3/air/AirTmp.h302
-rw-r--r--Source/JavaScriptCore/b3/air/AirTmpInlines.h101
-rw-r--r--Source/JavaScriptCore/b3/air/AirTmpWidth.cpp183
-rw-r--r--Source/JavaScriptCore/b3/air/AirTmpWidth.h110
-rw-r--r--Source/JavaScriptCore/b3/air/AirUseCounts.h122
-rw-r--r--Source/JavaScriptCore/b3/air/AirValidate.cpp141
-rw-r--r--Source/JavaScriptCore/b3/air/AirValidate.h42
-rw-r--r--Source/JavaScriptCore/b3/air/opcode_generator.rb1092
-rw-r--r--Source/JavaScriptCore/b3/air/testair.cpp1753
74 files changed, 0 insertions, 15637 deletions
diff --git a/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp b/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp
deleted file mode 100644
index de73fd025..000000000
--- a/Source/JavaScriptCore/b3/air/AirAllocateStack.cpp
+++ /dev/null
@@ -1,307 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirAllocateStack.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInsertionSet.h"
-#include "AirInstInlines.h"
-#include "AirLiveness.h"
-#include "AirPhaseScope.h"
-#include "StackAlignment.h"
-#include <wtf/ListDump.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-namespace {
-
-const bool verbose = false;
-
-bool attemptAssignment(
- StackSlot* slot, intptr_t offsetFromFP, const Vector<StackSlot*>& otherSlots)
-{
- if (verbose)
- dataLog("Attempting to assign ", pointerDump(slot), " to ", offsetFromFP, " with interference ", pointerListDump(otherSlots), "\n");
-
- // Need to align it to the slot's desired alignment.
- offsetFromFP = -WTF::roundUpToMultipleOf(slot->alignment(), -offsetFromFP);
-
- for (StackSlot* otherSlot : otherSlots) {
- if (!otherSlot->offsetFromFP())
- continue;
- bool overlap = WTF::rangesOverlap(
- offsetFromFP,
- offsetFromFP + static_cast<intptr_t>(slot->byteSize()),
- otherSlot->offsetFromFP(),
- otherSlot->offsetFromFP() + static_cast<intptr_t>(otherSlot->byteSize()));
- if (overlap)
- return false;
- }
-
- if (verbose)
- dataLog("Assigned ", pointerDump(slot), " to ", offsetFromFP, "\n");
- slot->setOffsetFromFP(offsetFromFP);
- return true;
-}
-
-void assign(StackSlot* slot, const Vector<StackSlot*>& otherSlots)
-{
- if (verbose)
- dataLog("Attempting to assign ", pointerDump(slot), " with interference ", pointerListDump(otherSlots), "\n");
-
- if (attemptAssignment(slot, -static_cast<intptr_t>(slot->byteSize()), otherSlots))
- return;
-
- for (StackSlot* otherSlot : otherSlots) {
- if (!otherSlot->offsetFromFP())
- continue;
- bool didAssign = attemptAssignment(
- slot, otherSlot->offsetFromFP() - static_cast<intptr_t>(slot->byteSize()), otherSlots);
- if (didAssign)
- return;
- }
-
- RELEASE_ASSERT_NOT_REACHED();
-}
-
-} // anonymous namespace
-
-void allocateStack(Code& code)
-{
- PhaseScope phaseScope(code, "allocateStack");
-
- // Allocate all of the escaped slots in order. This is kind of a crazy algorithm to allow for
- // the possibility of stack slots being assigned frame offsets before we even get here.
- ASSERT(!code.frameSize());
- Vector<StackSlot*> assignedEscapedStackSlots;
- Vector<StackSlot*> escapedStackSlotsWorklist;
- for (StackSlot* slot : code.stackSlots()) {
- if (slot->isLocked()) {
- if (slot->offsetFromFP())
- assignedEscapedStackSlots.append(slot);
- else
- escapedStackSlotsWorklist.append(slot);
- } else {
- // It would be super strange to have an unlocked stack slot that has an offset already.
- ASSERT(!slot->offsetFromFP());
- }
- }
- // This is a fairly expensive loop, but it's OK because we'll usually only have a handful of
- // escaped stack slots.
- while (!escapedStackSlotsWorklist.isEmpty()) {
- StackSlot* slot = escapedStackSlotsWorklist.takeLast();
- assign(slot, assignedEscapedStackSlots);
- assignedEscapedStackSlots.append(slot);
- }
-
- // Now we handle the spill slots.
- StackSlotLiveness liveness(code);
- IndexMap<StackSlot, HashSet<StackSlot*>> interference(code.stackSlots().size());
- Vector<StackSlot*> slots;
-
- for (BasicBlock* block : code) {
- StackSlotLiveness::LocalCalc localCalc(liveness, block);
-
- auto interfere = [&] (unsigned instIndex) {
- if (verbose)
- dataLog("Interfering: ", WTF::pointerListDump(localCalc.live()), "\n");
-
- Inst::forEachDef<Arg>(
- block->get(instIndex), block->get(instIndex + 1),
- [&] (Arg& arg, Arg::Role, Arg::Type, Arg::Width) {
- if (!arg.isStack())
- return;
- StackSlot* slot = arg.stackSlot();
- if (slot->kind() != StackSlotKind::Spill)
- return;
-
- for (StackSlot* otherSlot : localCalc.live()) {
- interference[slot].add(otherSlot);
- interference[otherSlot].add(slot);
- }
- });
- };
-
- for (unsigned instIndex = block->size(); instIndex--;) {
- if (verbose)
- dataLog("Analyzing: ", block->at(instIndex), "\n");
-
- // Kill dead stores. For simplicity we say that a store is killable if it has only late
- // defs and those late defs are to things that are dead right now. We only do that
- // because that's the only kind of dead stack store we will see here.
- Inst& inst = block->at(instIndex);
- if (!inst.hasNonArgEffects()) {
- bool ok = true;
- inst.forEachArg(
- [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) {
- if (Arg::isEarlyDef(role)) {
- ok = false;
- return;
- }
- if (!Arg::isLateDef(role))
- return;
- if (!arg.isStack()) {
- ok = false;
- return;
- }
- StackSlot* slot = arg.stackSlot();
- if (slot->kind() != StackSlotKind::Spill) {
- ok = false;
- return;
- }
-
- if (localCalc.isLive(slot)) {
- ok = false;
- return;
- }
- });
- if (ok)
- inst = Inst();
- }
-
- interfere(instIndex);
- localCalc.execute(instIndex);
- }
- interfere(-1);
-
- block->insts().removeAllMatching(
- [&] (const Inst& inst) -> bool {
- return !inst;
- });
- }
-
- if (verbose) {
- for (StackSlot* slot : code.stackSlots())
- dataLog("Interference of ", pointerDump(slot), ": ", pointerListDump(interference[slot]), "\n");
- }
-
- // Now we assign stack locations. At its heart this algorithm is just first-fit. For each
- // StackSlot we just want to find the offsetFromFP that is closest to zero while ensuring no
- // overlap with other StackSlots that this overlaps with.
- Vector<StackSlot*> otherSlots = assignedEscapedStackSlots;
- for (StackSlot* slot : code.stackSlots()) {
- if (slot->offsetFromFP()) {
- // Already assigned an offset.
- continue;
- }
-
- HashSet<StackSlot*>& interferingSlots = interference[slot];
- otherSlots.resize(assignedEscapedStackSlots.size());
- otherSlots.resize(assignedEscapedStackSlots.size() + interferingSlots.size());
- unsigned nextIndex = assignedEscapedStackSlots.size();
- for (StackSlot* otherSlot : interferingSlots)
- otherSlots[nextIndex++] = otherSlot;
-
- assign(slot, otherSlots);
- }
-
- // Figure out how much stack we're using for stack slots.
- unsigned frameSizeForStackSlots = 0;
- for (StackSlot* slot : code.stackSlots()) {
- frameSizeForStackSlots = std::max(
- frameSizeForStackSlots,
- static_cast<unsigned>(-slot->offsetFromFP()));
- }
-
- frameSizeForStackSlots = WTF::roundUpToMultipleOf(stackAlignmentBytes(), frameSizeForStackSlots);
-
- // Now we need to deduce how much argument area we need.
- for (BasicBlock* block : code) {
- for (Inst& inst : *block) {
- for (Arg& arg : inst.args) {
- if (arg.isCallArg()) {
- // For now, we assume that we use 8 bytes of the call arg. But that's not
- // such an awesome assumption.
- // FIXME: https://bugs.webkit.org/show_bug.cgi?id=150454
- ASSERT(arg.offset() >= 0);
- code.requestCallArgAreaSize(arg.offset() + 8);
- }
- }
- }
- }
-
- code.setFrameSize(frameSizeForStackSlots + code.callArgAreaSize());
-
- // Finally, transform the code to use Addr's instead of StackSlot's. This is a lossless
- // transformation since we can search the StackSlots array to figure out which StackSlot any
- // offset-from-FP refers to.
-
- // FIXME: This may produce addresses that aren't valid if we end up with a ginormous stack frame.
- // We would have to scavenge for temporaries if this happened. Fortunately, this case will be
- // extremely rare so we can do crazy things when it arises.
- // https://bugs.webkit.org/show_bug.cgi?id=152530
-
- InsertionSet insertionSet(code);
- for (BasicBlock* block : code) {
- for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
- Inst& inst = block->at(instIndex);
- inst.forEachArg(
- [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width width) {
- auto stackAddr = [&] (int32_t offset) -> Arg {
- return Arg::stackAddr(offset, code.frameSize(), width);
- };
-
- switch (arg.kind()) {
- case Arg::Stack: {
- StackSlot* slot = arg.stackSlot();
- if (Arg::isZDef(role)
- && slot->kind() == StackSlotKind::Spill
- && slot->byteSize() > Arg::bytes(width)) {
- // Currently we only handle this simple case because it's the only one
- // that arises: ZDef's are only 32-bit right now. So, when we hit these
- // assertions it means that we need to implement those other kinds of
- // zero fills.
- RELEASE_ASSERT(slot->byteSize() == 8);
- RELEASE_ASSERT(width == Arg::Width32);
-
- RELEASE_ASSERT(isValidForm(StoreZero32, Arg::Stack));
- insertionSet.insert(
- instIndex + 1, StoreZero32, inst.origin,
- stackAddr(arg.offset() + 4 + slot->offsetFromFP()));
- }
- arg = stackAddr(arg.offset() + slot->offsetFromFP());
- break;
- }
- case Arg::CallArg:
- arg = stackAddr(arg.offset() - code.frameSize());
- break;
- default:
- break;
- }
- }
- );
- }
- insertionSet.execute(block);
- }
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-
diff --git a/Source/JavaScriptCore/b3/air/AirAllocateStack.h b/Source/JavaScriptCore/b3/air/AirAllocateStack.h
deleted file mode 100644
index 74d347e01..000000000
--- a/Source/JavaScriptCore/b3/air/AirAllocateStack.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirAllocateStack_h
-#define AirAllocateStack_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// This allocates StackSlots to places on the stack. It first allocates the pinned ones in index
-// order and then it allocates the rest using first fit. Takes the opportunity to kill dead
-// assignments to stack slots, since it knows which ones are live. Also fixes ZDefs to anonymous
-// stack slots.
-
-void allocateStack(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirAllocateStack_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirArg.cpp b/Source/JavaScriptCore/b3/air/AirArg.cpp
deleted file mode 100644
index 2edd8e729..000000000
--- a/Source/JavaScriptCore/b3/air/AirArg.cpp
+++ /dev/null
@@ -1,330 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirArg.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirSpecial.h"
-#include "AirStackSlot.h"
-#include "B3Value.h"
-#include "FPRInfo.h"
-#include "GPRInfo.h"
-
-#if COMPILER(GCC) && ASSERT_DISABLED
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wreturn-type"
-#endif // COMPILER(GCC) && ASSERT_DISABLED
-
-namespace JSC { namespace B3 { namespace Air {
-
-bool Arg::isStackMemory() const
-{
- switch (kind()) {
- case Addr:
- return base() == Air::Tmp(GPRInfo::callFrameRegister)
- || base() == Air::Tmp(MacroAssembler::stackPointerRegister);
- case Stack:
- case CallArg:
- return true;
- default:
- return false;
- }
-}
-
-bool Arg::isRepresentableAs(Width width, Signedness signedness) const
-{
- switch (signedness) {
- case Signed:
- switch (width) {
- case Width8:
- return isRepresentableAs<int8_t>();
- case Width16:
- return isRepresentableAs<int16_t>();
- case Width32:
- return isRepresentableAs<int32_t>();
- case Width64:
- return isRepresentableAs<int64_t>();
- }
- case Unsigned:
- switch (width) {
- case Width8:
- return isRepresentableAs<uint8_t>();
- case Width16:
- return isRepresentableAs<uint16_t>();
- case Width32:
- return isRepresentableAs<uint32_t>();
- case Width64:
- return isRepresentableAs<uint64_t>();
- }
- }
- ASSERT_NOT_REACHED();
-}
-
-bool Arg::usesTmp(Air::Tmp tmp) const
-{
- bool uses = false;
- const_cast<Arg*>(this)->forEachTmpFast(
- [&] (Air::Tmp otherTmp) {
- if (otherTmp == tmp)
- uses = true;
- });
- return uses;
-}
-
-bool Arg::canRepresent(Value* value) const
-{
- return isType(typeForB3Type(value->type()));
-}
-
-bool Arg::isCompatibleType(const Arg& other) const
-{
- if (hasType())
- return other.isType(type());
- if (other.hasType())
- return isType(other.type());
- return true;
-}
-
-void Arg::dump(PrintStream& out) const
-{
- switch (m_kind) {
- case Invalid:
- out.print("<invalid>");
- return;
- case Tmp:
- out.print(tmp());
- return;
- case Imm:
- out.print("$", m_offset);
- return;
- case BigImm:
- out.printf("$0x%llx", static_cast<long long unsigned>(m_offset));
- return;
- case BitImm:
- out.print("$", m_offset);
- return;
- case BitImm64:
- out.printf("$0x%llx", static_cast<long long unsigned>(m_offset));
- return;
- case Addr:
- if (offset())
- out.print(offset());
- out.print("(", base(), ")");
- return;
- case Index:
- if (offset())
- out.print(offset());
- out.print("(", base(), ",", index());
- if (scale() != 1)
- out.print(",", scale());
- out.print(")");
- return;
- case Stack:
- if (offset())
- out.print(offset());
- out.print("(", pointerDump(stackSlot()), ")");
- return;
- case CallArg:
- if (offset())
- out.print(offset());
- out.print("(callArg)");
- return;
- case RelCond:
- out.print(asRelationalCondition());
- return;
- case ResCond:
- out.print(asResultCondition());
- return;
- case DoubleCond:
- out.print(asDoubleCondition());
- return;
- case Special:
- out.print(pointerDump(special()));
- return;
- case WidthArg:
- out.print(width());
- return;
- }
-
- RELEASE_ASSERT_NOT_REACHED();
-}
-
-} } } // namespace JSC::B3::Air
-
-namespace WTF {
-
-using namespace JSC::B3::Air;
-
-void printInternal(PrintStream& out, Arg::Kind kind)
-{
- switch (kind) {
- case Arg::Invalid:
- out.print("Invalid");
- return;
- case Arg::Tmp:
- out.print("Tmp");
- return;
- case Arg::Imm:
- out.print("Imm");
- return;
- case Arg::BigImm:
- out.print("BigImm");
- return;
- case Arg::BitImm:
- out.print("BitImm");
- return;
- case Arg::BitImm64:
- out.print("BitImm64");
- return;
- case Arg::Addr:
- out.print("Addr");
- return;
- case Arg::Stack:
- out.print("Stack");
- return;
- case Arg::CallArg:
- out.print("CallArg");
- return;
- case Arg::Index:
- out.print("Index");
- return;
- case Arg::RelCond:
- out.print("RelCond");
- return;
- case Arg::ResCond:
- out.print("ResCond");
- return;
- case Arg::DoubleCond:
- out.print("DoubleCond");
- return;
- case Arg::Special:
- out.print("Special");
- return;
- case Arg::WidthArg:
- out.print("WidthArg");
- return;
- }
-
- RELEASE_ASSERT_NOT_REACHED();
-}
-
-void printInternal(PrintStream& out, Arg::Role role)
-{
- switch (role) {
- case Arg::Use:
- out.print("Use");
- return;
- case Arg::Def:
- out.print("Def");
- return;
- case Arg::UseDef:
- out.print("UseDef");
- return;
- case Arg::ZDef:
- out.print("ZDef");
- return;
- case Arg::UseZDef:
- out.print("UseZDef");
- return;
- case Arg::UseAddr:
- out.print("UseAddr");
- return;
- case Arg::ColdUse:
- out.print("ColdUse");
- return;
- case Arg::LateUse:
- out.print("LateUse");
- return;
- case Arg::LateColdUse:
- out.print("LateColdUse");
- return;
- case Arg::EarlyDef:
- out.print("EarlyDef");
- return;
- case Arg::Scratch:
- out.print("Scratch");
- return;
- }
-
- RELEASE_ASSERT_NOT_REACHED();
-}
-
-void printInternal(PrintStream& out, Arg::Type type)
-{
- switch (type) {
- case Arg::GP:
- out.print("GP");
- return;
- case Arg::FP:
- out.print("FP");
- return;
- }
-
- RELEASE_ASSERT_NOT_REACHED();
-}
-
-void printInternal(PrintStream& out, Arg::Width width)
-{
- switch (width) {
- case Arg::Width8:
- out.print("8");
- return;
- case Arg::Width16:
- out.print("16");
- return;
- case Arg::Width32:
- out.print("32");
- return;
- case Arg::Width64:
- out.print("64");
- return;
- }
-
- RELEASE_ASSERT_NOT_REACHED();
-}
-
-void printInternal(PrintStream& out, Arg::Signedness signedness)
-{
- switch (signedness) {
- case Arg::Signed:
- out.print("Signed");
- return;
- case Arg::Unsigned:
- out.print("Unsigned");
- return;
- }
-
- RELEASE_ASSERT_NOT_REACHED();
-}
-
-} // namespace WTF
-
-#if COMPILER(GCC) && ASSERT_DISABLED
-#pragma GCC diagnostic pop
-#endif // COMPILER(GCC) && ASSERT_DISABLED
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirArg.h b/Source/JavaScriptCore/b3/air/AirArg.h
deleted file mode 100644
index 0cc818d4a..000000000
--- a/Source/JavaScriptCore/b3/air/AirArg.h
+++ /dev/null
@@ -1,1345 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirArg_h
-#define AirArg_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirTmp.h"
-#include "B3Common.h"
-#include "B3Type.h"
-#include <wtf/Optional.h>
-
-#if COMPILER(GCC) && ASSERT_DISABLED
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wreturn-type"
-#endif // COMPILER(GCC) && ASSERT_DISABLED
-
-namespace JSC { namespace B3 {
-
-class Value;
-
-namespace Air {
-
-class Special;
-class StackSlot;
-
-// This class name is also intentionally terse because we will say it a lot. You'll see code like
-// Inst(..., Arg::imm(5), Arg::addr(thing, blah), ...)
-class Arg {
-public:
- // These enum members are intentionally terse because we have to mention them a lot.
- enum Kind : int8_t {
- Invalid,
-
- // This is either an unassigned temporary or a register. All unassigned temporaries
- // eventually become registers.
- Tmp,
-
- // This is an immediate that the instruction will materialize. Imm is the immediate that can be
- // inlined into most instructions, while BigImm indicates a constant materialization and is
- // usually only usable with Move. Specials may also admit it, for example for stackmaps used for
- // OSR exit and tail calls.
- // BitImm is an immediate for Bitwise operation (And, Xor, etc).
- Imm,
- BigImm,
- BitImm,
- BitImm64,
-
- // These are the addresses. Instructions may load from (Use), store to (Def), or evaluate
- // (UseAddr) addresses.
- Addr,
- Stack,
- CallArg,
- Index,
-
- // Immediate operands that customize the behavior of an operation. You can think of them as
- // secondary opcodes. They are always "Use"'d.
- RelCond,
- ResCond,
- DoubleCond,
- Special,
- WidthArg
- };
-
- enum Role : int8_t {
- // Use means that the Inst will read from this value before doing anything else.
- //
- // For Tmp: The Inst will read this Tmp.
- // For Arg::addr and friends: The Inst will load from this address.
- // For Arg::imm and friends: The Inst will materialize and use this immediate.
- // For RelCond/ResCond/Special: This is the only valid role for these kinds.
- //
- // Note that Use of an address does not mean escape. It only means that the instruction will
- // load from the address before doing anything else. This is a bit tricky; for example
- // Specials could theoretically squirrel away the address and effectively escape it. However,
- // this is not legal. On the other hand, any address other than Stack is presumed to be
- // always escaping, and Stack is presumed to be always escaping if it's Locked.
- Use,
-
- // Exactly like Use, except that it also implies that the use is cold: that is, replacing the
- // use with something on the stack is free.
- ColdUse,
-
- // LateUse means that the Inst will read from this value after doing its Def's. Note that LateUse
- // on an Addr or Index still means Use on the internal temporaries. Note that specifying the
- // same Tmp once as Def and once as LateUse has undefined behavior: the use may happen before
- // the def, or it may happen after it.
- LateUse,
-
- // Combination of LateUse and ColdUse.
- LateColdUse,
-
- // Def means that the Inst will write to this value after doing everything else.
- //
- // For Tmp: The Inst will write to this Tmp.
- // For Arg::addr and friends: The Inst will store to this address.
- // This isn't valid for any other kinds.
- //
- // Like Use of address, Def of address does not mean escape.
- Def,
-
- // This is a special variant of Def that implies that the upper bits of the target register are
- // zero-filled. Specifically, if the Width of a ZDef is less than the largest possible width of
- // the argument (for example, we're on a 64-bit machine and we have a Width32 ZDef of a GPR) then
- // this has different implications for the upper bits (i.e. the top 32 bits in our example)
- // depending on the kind of the argument:
- //
- // For register: the upper bits are zero-filled.
- // For anonymous stack slot: the upper bits are zero-filled.
- // For address: the upper bits are not touched (i.e. we do a 32-bit store in our example).
- // For tmp: either the upper bits are not touched or they are zero-filled, and we won't know
- // which until we lower the tmp to either a StackSlot or a Reg.
- //
- // The behavior of ZDef is consistent with what happens when you perform 32-bit operations on a
- // 64-bit GPR. It's not consistent with what happens with 8-bit or 16-bit Defs on x86 GPRs, or
- // what happens with float Defs in ARM NEON or X86 SSE. Hence why we have both Def and ZDef.
- ZDef,
-
- // This is a combined Use and Def. It means that both things happen.
- UseDef,
-
- // This is a combined Use and ZDef. It means that both things happen.
- UseZDef,
-
- // This is like Def, but implies that the assignment occurs before the start of the Inst's
- // execution rather than after. Note that specifying the same Tmp once as EarlyDef and once
- // as Use has undefined behavior: the use may happen before the def, or it may happen after
- // it.
- EarlyDef,
-
- // Some instructions need a scratch register. We model this by saying that the temporary is
- // defined early and used late. This role implies that.
- Scratch,
-
- // This is a special kind of use that is only valid for addresses. It means that the
- // instruction will evaluate the address expression and consume the effective address, but it
- // will neither load nor store. This is an escaping use, because now the address may be
- // passed along to who-knows-where. Note that this isn't really a Use of the Arg, but it does
- // imply that we're Use'ing any registers that the Arg contains.
- UseAddr
- };
-
- enum Type : int8_t {
- GP,
- FP
- };
-
- static const unsigned numTypes = 2;
-
- template<typename Functor>
- static void forEachType(const Functor& functor)
- {
- functor(GP);
- functor(FP);
- }
-
- enum Width : int8_t {
- Width8,
- Width16,
- Width32,
- Width64
- };
-
- static Width pointerWidth()
- {
- if (sizeof(void*) == 8)
- return Width64;
- return Width32;
- }
-
- enum Signedness : int8_t {
- Signed,
- Unsigned
- };
-
- // Returns true if the Role implies that the Inst will Use the Arg. It's deliberately false for
- // UseAddr, since isAnyUse() for an Arg::addr means that we are loading from the address.
- static bool isAnyUse(Role role)
- {
- switch (role) {
- case Use:
- case ColdUse:
- case UseDef:
- case UseZDef:
- case LateUse:
- case LateColdUse:
- case Scratch:
- return true;
- case Def:
- case ZDef:
- case UseAddr:
- case EarlyDef:
- return false;
- }
- ASSERT_NOT_REACHED();
- }
-
- static bool isColdUse(Role role)
- {
- switch (role) {
- case ColdUse:
- case LateColdUse:
- return true;
- case Use:
- case UseDef:
- case UseZDef:
- case LateUse:
- case Def:
- case ZDef:
- case UseAddr:
- case Scratch:
- case EarlyDef:
- return false;
- }
- ASSERT_NOT_REACHED();
- }
-
- static bool isWarmUse(Role role)
- {
- return isAnyUse(role) && !isColdUse(role);
- }
-
- static Role cooled(Role role)
- {
- switch (role) {
- case ColdUse:
- case LateColdUse:
- case UseDef:
- case UseZDef:
- case Def:
- case ZDef:
- case UseAddr:
- case Scratch:
- case EarlyDef:
- return role;
- case Use:
- return ColdUse;
- case LateUse:
- return LateColdUse;
- }
- ASSERT_NOT_REACHED();
- }
-
- // Returns true if the Role implies that the Inst will Use the Arg before doing anything else.
- static bool isEarlyUse(Role role)
- {
- switch (role) {
- case Use:
- case ColdUse:
- case UseDef:
- case UseZDef:
- return true;
- case Def:
- case ZDef:
- case UseAddr:
- case LateUse:
- case LateColdUse:
- case Scratch:
- case EarlyDef:
- return false;
- }
- ASSERT_NOT_REACHED();
- }
-
- // Returns true if the Role implies that the Inst will Use the Arg after doing everything else.
- static bool isLateUse(Role role)
- {
- switch (role) {
- case LateUse:
- case LateColdUse:
- case Scratch:
- return true;
- case ColdUse:
- case Use:
- case UseDef:
- case UseZDef:
- case Def:
- case ZDef:
- case UseAddr:
- case EarlyDef:
- return false;
- }
- ASSERT_NOT_REACHED();
- }
-
- // Returns true if the Role implies that the Inst will Def the Arg.
- static bool isAnyDef(Role role)
- {
- switch (role) {
- case Use:
- case ColdUse:
- case UseAddr:
- case LateUse:
- case LateColdUse:
- return false;
- case Def:
- case UseDef:
- case ZDef:
- case UseZDef:
- case EarlyDef:
- case Scratch:
- return true;
- }
- ASSERT_NOT_REACHED();
- }
-
- // Returns true if the Role implies that the Inst will Def the Arg before start of execution.
- static bool isEarlyDef(Role role)
- {
- switch (role) {
- case Use:
- case ColdUse:
- case UseAddr:
- case LateUse:
- case Def:
- case UseDef:
- case ZDef:
- case UseZDef:
- case LateColdUse:
- return false;
- case EarlyDef:
- case Scratch:
- return true;
- }
- ASSERT_NOT_REACHED();
- }
-
- // Returns true if the Role implies that the Inst will Def the Arg after the end of execution.
- static bool isLateDef(Role role)
- {
- switch (role) {
- case Use:
- case ColdUse:
- case UseAddr:
- case LateUse:
- case EarlyDef:
- case Scratch:
- case LateColdUse:
- return false;
- case Def:
- case UseDef:
- case ZDef:
- case UseZDef:
- return true;
- }
- ASSERT_NOT_REACHED();
- }
-
- // Returns true if the Role implies that the Inst will ZDef the Arg.
- static bool isZDef(Role role)
- {
- switch (role) {
- case Use:
- case ColdUse:
- case UseAddr:
- case LateUse:
- case Def:
- case UseDef:
- case EarlyDef:
- case Scratch:
- case LateColdUse:
- return false;
- case ZDef:
- case UseZDef:
- return true;
- }
- ASSERT_NOT_REACHED();
- }
-
- static Type typeForB3Type(B3::Type type)
- {
- switch (type) {
- case Void:
- ASSERT_NOT_REACHED();
- return GP;
- case Int32:
- case Int64:
- return GP;
- case Float:
- case Double:
- return FP;
- }
- ASSERT_NOT_REACHED();
- return GP;
- }
-
- static Width widthForB3Type(B3::Type type)
- {
- switch (type) {
- case Void:
- ASSERT_NOT_REACHED();
- return Width8;
- case Int32:
- case Float:
- return Width32;
- case Int64:
- case Double:
- return Width64;
- }
- ASSERT_NOT_REACHED();
- }
-
- static Width conservativeWidth(Type type)
- {
- return type == GP ? pointerWidth() : Width64;
- }
-
- static Width minimumWidth(Type type)
- {
- return type == GP ? Width8 : Width32;
- }
-
- static unsigned bytes(Width width)
- {
- return 1 << width;
- }
-
- static Width widthForBytes(unsigned bytes)
- {
- switch (bytes) {
- case 0:
- case 1:
- return Width8;
- case 2:
- return Width16;
- case 3:
- case 4:
- return Width32;
- default:
- return Width64;
- }
- }
-
- Arg()
- : m_kind(Invalid)
- {
- }
-
- Arg(Air::Tmp tmp)
- : m_kind(Tmp)
- , m_base(tmp)
- {
- }
-
- Arg(Reg reg)
- : Arg(Air::Tmp(reg))
- {
- }
-
- static Arg imm(int64_t value)
- {
- Arg result;
- result.m_kind = Imm;
- result.m_offset = value;
- return result;
- }
-
- static Arg bigImm(int64_t value)
- {
- Arg result;
- result.m_kind = BigImm;
- result.m_offset = value;
- return result;
- }
-
- static Arg bitImm(int64_t value)
- {
- Arg result;
- result.m_kind = BitImm;
- result.m_offset = value;
- return result;
- }
-
- static Arg bitImm64(int64_t value)
- {
- Arg result;
- result.m_kind = BitImm64;
- result.m_offset = value;
- return result;
- }
-
- static Arg immPtr(const void* address)
- {
- return bigImm(bitwise_cast<intptr_t>(address));
- }
-
- static Arg addr(Air::Tmp base, int32_t offset = 0)
- {
- ASSERT(base.isGP());
- Arg result;
- result.m_kind = Addr;
- result.m_base = base;
- result.m_offset = offset;
- return result;
- }
-
- static Arg stack(StackSlot* value, int32_t offset = 0)
- {
- Arg result;
- result.m_kind = Stack;
- result.m_offset = bitwise_cast<intptr_t>(value);
- result.m_scale = offset; // I know, yuck.
- return result;
- }
-
- static Arg callArg(int32_t offset)
- {
- Arg result;
- result.m_kind = CallArg;
- result.m_offset = offset;
- return result;
- }
-
- static Arg stackAddr(int32_t offsetFromFP, unsigned frameSize, Width width)
- {
- Arg result = Arg::addr(Air::Tmp(GPRInfo::callFrameRegister), offsetFromFP);
- if (!result.isValidForm(width)) {
- result = Arg::addr(
- Air::Tmp(MacroAssembler::stackPointerRegister),
- offsetFromFP + frameSize);
- }
- return result;
- }
-
- // If you don't pass a Width, this optimistically assumes that you're using the right width.
- static bool isValidScale(unsigned scale, Optional<Width> width = Nullopt)
- {
- switch (scale) {
- case 1:
- if (isX86() || isARM64())
- return true;
- return false;
- case 2:
- case 4:
- case 8:
- if (isX86())
- return true;
- if (isARM64()) {
- if (!width)
- return true;
- return scale == 1 || scale == bytes(*width);
- }
- return false;
- default:
- return false;
- }
- }
-
- static unsigned logScale(unsigned scale)
- {
- switch (scale) {
- case 1:
- return 0;
- case 2:
- return 1;
- case 4:
- return 2;
- case 8:
- return 3;
- default:
- ASSERT_NOT_REACHED();
- return 0;
- }
- }
-
- static Arg index(Air::Tmp base, Air::Tmp index, unsigned scale = 1, int32_t offset = 0)
- {
- ASSERT(base.isGP());
- ASSERT(index.isGP());
- ASSERT(isValidScale(scale));
- Arg result;
- result.m_kind = Index;
- result.m_base = base;
- result.m_index = index;
- result.m_scale = static_cast<int32_t>(scale);
- result.m_offset = offset;
- return result;
- }
-
- static Arg relCond(MacroAssembler::RelationalCondition condition)
- {
- Arg result;
- result.m_kind = RelCond;
- result.m_offset = condition;
- return result;
- }
-
- static Arg resCond(MacroAssembler::ResultCondition condition)
- {
- Arg result;
- result.m_kind = ResCond;
- result.m_offset = condition;
- return result;
- }
-
- static Arg doubleCond(MacroAssembler::DoubleCondition condition)
- {
- Arg result;
- result.m_kind = DoubleCond;
- result.m_offset = condition;
- return result;
- }
-
- static Arg special(Air::Special* special)
- {
- Arg result;
- result.m_kind = Special;
- result.m_offset = bitwise_cast<intptr_t>(special);
- return result;
- }
-
- static Arg widthArg(Width width)
- {
- Arg result;
- result.m_kind = WidthArg;
- result.m_offset = width;
- return result;
- }
-
- bool operator==(const Arg& other) const
- {
- return m_offset == other.m_offset
- && m_kind == other.m_kind
- && m_base == other.m_base
- && m_index == other.m_index
- && m_scale == other.m_scale;
- }
-
- bool operator!=(const Arg& other) const
- {
- return !(*this == other);
- }
-
- explicit operator bool() const { return *this != Arg(); }
-
- Kind kind() const
- {
- return m_kind;
- }
-
- bool isTmp() const
- {
- return kind() == Tmp;
- }
-
- bool isImm() const
- {
- return kind() == Imm;
- }
-
- bool isBigImm() const
- {
- return kind() == BigImm;
- }
-
- bool isBitImm() const
- {
- return kind() == BitImm;
- }
-
- bool isBitImm64() const
- {
- return kind() == BitImm64;
- }
-
- bool isSomeImm() const
- {
- return isImm() || isBigImm() || isBitImm() || isBitImm64();
- }
-
- bool isAddr() const
- {
- return kind() == Addr;
- }
-
- bool isStack() const
- {
- return kind() == Stack;
- }
-
- bool isCallArg() const
- {
- return kind() == CallArg;
- }
-
- bool isIndex() const
- {
- return kind() == Index;
- }
-
- bool isMemory() const
- {
- switch (kind()) {
- case Addr:
- case Stack:
- case CallArg:
- case Index:
- return true;
- default:
- return false;
- }
- }
-
- bool isStackMemory() const;
-
- bool isRelCond() const
- {
- return kind() == RelCond;
- }
-
- bool isResCond() const
- {
- return kind() == ResCond;
- }
-
- bool isDoubleCond() const
- {
- return kind() == DoubleCond;
- }
-
- bool isCondition() const
- {
- switch (kind()) {
- case RelCond:
- case ResCond:
- case DoubleCond:
- return true;
- default:
- return false;
- }
- }
-
- bool isSpecial() const
- {
- return kind() == Special;
- }
-
- bool isWidthArg() const
- {
- return kind() == WidthArg;
- }
-
- bool isAlive() const
- {
- return isTmp() || isStack();
- }
-
- Air::Tmp tmp() const
- {
- ASSERT(kind() == Tmp);
- return m_base;
- }
-
- int64_t value() const
- {
- ASSERT(isSomeImm());
- return m_offset;
- }
-
- template<typename T>
- bool isRepresentableAs() const
- {
- return B3::isRepresentableAs<T>(value());
- }
-
- bool isRepresentableAs(Width, Signedness) const;
-
- template<typename T>
- T asNumber() const
- {
- return static_cast<T>(value());
- }
-
- void* pointerValue() const
- {
- ASSERT(kind() == BigImm);
- return bitwise_cast<void*>(static_cast<intptr_t>(m_offset));
- }
-
- Air::Tmp base() const
- {
- ASSERT(kind() == Addr || kind() == Index);
- return m_base;
- }
-
- bool hasOffset() const { return isMemory(); }
-
- int32_t offset() const
- {
- if (kind() == Stack)
- return static_cast<int32_t>(m_scale);
- ASSERT(kind() == Addr || kind() == CallArg || kind() == Index);
- return static_cast<int32_t>(m_offset);
- }
-
- StackSlot* stackSlot() const
- {
- ASSERT(kind() == Stack);
- return bitwise_cast<StackSlot*>(m_offset);
- }
-
- Air::Tmp index() const
- {
- ASSERT(kind() == Index);
- return m_index;
- }
-
- unsigned scale() const
- {
- ASSERT(kind() == Index);
- return m_scale;
- }
-
- unsigned logScale() const
- {
- return logScale(scale());
- }
-
- Air::Special* special() const
- {
- ASSERT(kind() == Special);
- return bitwise_cast<Air::Special*>(m_offset);
- }
-
- Width width() const
- {
- ASSERT(kind() == WidthArg);
- return static_cast<Width>(m_offset);
- }
-
- bool isGPTmp() const
- {
- return isTmp() && tmp().isGP();
- }
-
- bool isFPTmp() const
- {
- return isTmp() && tmp().isFP();
- }
-
- // Tells us if this Arg can be used in a position that requires a GP value.
- bool isGP() const
- {
- switch (kind()) {
- case Imm:
- case BigImm:
- case BitImm:
- case BitImm64:
- case Addr:
- case Index:
- case Stack:
- case CallArg:
- case RelCond:
- case ResCond:
- case DoubleCond:
- case Special:
- case WidthArg:
- return true;
- case Tmp:
- return isGPTmp();
- case Invalid:
- return false;
- }
- ASSERT_NOT_REACHED();
- }
-
- // Tells us if this Arg can be used in a position that requires a FP value.
- bool isFP() const
- {
- switch (kind()) {
- case Imm:
- case BitImm:
- case BitImm64:
- case RelCond:
- case ResCond:
- case DoubleCond:
- case Special:
- case WidthArg:
- case Invalid:
- return false;
- case Addr:
- case Index:
- case Stack:
- case CallArg:
- case BigImm: // Yes, we allow BigImm as a double immediate. We use this for implementing stackmaps.
- return true;
- case Tmp:
- return isFPTmp();
- }
- ASSERT_NOT_REACHED();
- }
-
- bool hasType() const
- {
- switch (kind()) {
- case Imm:
- case BitImm:
- case BitImm64:
- case Special:
- case Tmp:
- return true;
- default:
- return false;
- }
- }
-
- // The type is ambiguous for some arg kinds. Call with care.
- Type type() const
- {
- return isGP() ? GP : FP;
- }
-
- bool isType(Type type) const
- {
- switch (type) {
- case GP:
- return isGP();
- case FP:
- return isFP();
- }
- ASSERT_NOT_REACHED();
- }
-
- bool canRepresent(Value* value) const;
-
- bool isCompatibleType(const Arg& other) const;
-
- bool isGPR() const
- {
- return isTmp() && tmp().isGPR();
- }
-
- GPRReg gpr() const
- {
- return tmp().gpr();
- }
-
- bool isFPR() const
- {
- return isTmp() && tmp().isFPR();
- }
-
- FPRReg fpr() const
- {
- return tmp().fpr();
- }
-
- bool isReg() const
- {
- return isTmp() && tmp().isReg();
- }
-
- Reg reg() const
- {
- return tmp().reg();
- }
-
- unsigned gpTmpIndex() const
- {
- return tmp().gpTmpIndex();
- }
-
- unsigned fpTmpIndex() const
- {
- return tmp().fpTmpIndex();
- }
-
- unsigned tmpIndex() const
- {
- return tmp().tmpIndex();
- }
-
- // If 'this' is an address Arg, then it returns a new address Arg with the additional offset applied.
- // Note that this does not consider whether doing so produces a valid Arg or not. Unless you really
- // know what you're doing, you should call Arg::isValidForm() on the result. Some code won't do that,
- // like if you're applying a very small offset to a Arg::stack() that you know has no offset to begin
- // with. It's safe to assume that all targets allow small offsets (like, 0..7) for Addr, Stack, and
- // CallArg.
- Arg withOffset(int64_t additionalOffset) const
- {
- if (!hasOffset())
- return Arg();
- if (sumOverflows<int64_t>(offset(), additionalOffset))
- return Arg();
- switch (kind()) {
- case Addr:
- return addr(base(), offset() + additionalOffset);
- case Stack:
- return stack(stackSlot(), offset() + additionalOffset);
- case CallArg:
- return callArg(offset() + additionalOffset);
- case Index:
- return index(base(), index(), scale(), offset() + additionalOffset);
- default:
- RELEASE_ASSERT_NOT_REACHED();
- return Arg();
- }
- }
-
- static bool isValidImmForm(int64_t value)
- {
- if (isX86())
- return B3::isRepresentableAs<int32_t>(value);
- if (isARM64())
- return isUInt12(value);
- return false;
- }
-
- static bool isValidBitImmForm(int64_t value)
- {
- if (isX86())
- return B3::isRepresentableAs<int32_t>(value);
- if (isARM64())
- return ARM64LogicalImmediate::create32(value).isValid();
- return false;
- }
-
- static bool isValidBitImm64Form(int64_t value)
- {
- if (isX86())
- return B3::isRepresentableAs<int32_t>(value);
- if (isARM64())
- return ARM64LogicalImmediate::create64(value).isValid();
- return false;
- }
-
- static bool isValidAddrForm(int32_t offset, Optional<Width> width = Nullopt)
- {
- if (isX86())
- return true;
- if (isARM64()) {
- if (!width)
- return true;
-
- if (isValidSignedImm9(offset))
- return true;
-
- switch (*width) {
- case Width8:
- return isValidScaledUImm12<8>(offset);
- case Width16:
- return isValidScaledUImm12<16>(offset);
- case Width32:
- return isValidScaledUImm12<32>(offset);
- case Width64:
- return isValidScaledUImm12<64>(offset);
- }
- }
- return false;
- }
-
- static bool isValidIndexForm(unsigned scale, int32_t offset, Optional<Width> width = Nullopt)
- {
- if (!isValidScale(scale, width))
- return false;
- if (isX86())
- return true;
- if (isARM64())
- return !offset;
- return false;
- }
-
- // If you don't pass a width then this optimistically assumes that you're using the right width. But
- // the width is relevant to validity, so passing a null width is only useful for assertions. Don't
- // pass null widths when cascading through Args in the instruction selector!
- bool isValidForm(Optional<Width> width = Nullopt) const
- {
- switch (kind()) {
- case Invalid:
- return false;
- case Tmp:
- return true;
- case Imm:
- return isValidImmForm(value());
- case BigImm:
- return true;
- case BitImm:
- return isValidBitImmForm(value());
- case BitImm64:
- return isValidBitImm64Form(value());
- case Addr:
- case Stack:
- case CallArg:
- return isValidAddrForm(offset(), width);
- case Index:
- return isValidIndexForm(scale(), offset(), width);
- case RelCond:
- case ResCond:
- case DoubleCond:
- case Special:
- case WidthArg:
- return true;
- }
- ASSERT_NOT_REACHED();
- }
-
- template<typename Functor>
- void forEachTmpFast(const Functor& functor)
- {
- switch (m_kind) {
- case Tmp:
- case Addr:
- functor(m_base);
- break;
- case Index:
- functor(m_base);
- functor(m_index);
- break;
- default:
- break;
- }
- }
-
- bool usesTmp(Air::Tmp tmp) const;
-
- template<typename Thing>
- bool is() const;
-
- template<typename Thing>
- Thing as() const;
-
- template<typename Thing, typename Functor>
- void forEachFast(const Functor&);
-
- template<typename Thing, typename Functor>
- void forEach(Role, Type, Width, const Functor&);
-
- // This is smart enough to know that an address arg in a Def or UseDef rule will use its
- // tmps and never def them. For example, this:
- //
- // mov %rax, (%rcx)
- //
- // This defs (%rcx) but uses %rcx.
- template<typename Functor>
- void forEachTmp(Role argRole, Type argType, Width argWidth, const Functor& functor)
- {
- switch (m_kind) {
- case Tmp:
- ASSERT(isAnyUse(argRole) || isAnyDef(argRole));
- functor(m_base, argRole, argType, argWidth);
- break;
- case Addr:
- functor(m_base, Use, GP, argRole == UseAddr ? argWidth : pointerWidth());
- break;
- case Index:
- functor(m_base, Use, GP, argRole == UseAddr ? argWidth : pointerWidth());
- functor(m_index, Use, GP, argRole == UseAddr ? argWidth : pointerWidth());
- break;
- default:
- break;
- }
- }
-
- MacroAssembler::TrustedImm32 asTrustedImm32() const
- {
- ASSERT(isImm() || isBitImm());
- return MacroAssembler::TrustedImm32(static_cast<int32_t>(m_offset));
- }
-
-#if USE(JSVALUE64)
- MacroAssembler::TrustedImm64 asTrustedImm64() const
- {
- ASSERT(isBigImm() || isBitImm64());
- return MacroAssembler::TrustedImm64(value());
- }
-#endif
-
- MacroAssembler::TrustedImmPtr asTrustedImmPtr() const
- {
- if (is64Bit())
- ASSERT(isBigImm());
- else
- ASSERT(isImm());
- return MacroAssembler::TrustedImmPtr(pointerValue());
- }
-
- MacroAssembler::Address asAddress() const
- {
- ASSERT(isAddr());
- return MacroAssembler::Address(m_base.gpr(), static_cast<int32_t>(m_offset));
- }
-
- MacroAssembler::BaseIndex asBaseIndex() const
- {
- ASSERT(isIndex());
- return MacroAssembler::BaseIndex(
- m_base.gpr(), m_index.gpr(), static_cast<MacroAssembler::Scale>(logScale()),
- static_cast<int32_t>(m_offset));
- }
-
- MacroAssembler::RelationalCondition asRelationalCondition() const
- {
- ASSERT(isRelCond());
- return static_cast<MacroAssembler::RelationalCondition>(m_offset);
- }
-
- MacroAssembler::ResultCondition asResultCondition() const
- {
- ASSERT(isResCond());
- return static_cast<MacroAssembler::ResultCondition>(m_offset);
- }
-
- MacroAssembler::DoubleCondition asDoubleCondition() const
- {
- ASSERT(isDoubleCond());
- return static_cast<MacroAssembler::DoubleCondition>(m_offset);
- }
-
- // Tells you if the Arg is invertible. Only condition arguments are invertible, and even for those, there
- // are a few exceptions - notably Overflow and Signed.
- bool isInvertible() const
- {
- switch (kind()) {
- case RelCond:
- case DoubleCond:
- return true;
- case ResCond:
- return MacroAssembler::isInvertible(asResultCondition());
- default:
- return false;
- }
- }
-
- // This is valid for condition arguments. It will invert them.
- Arg inverted(bool inverted = true) const
- {
- if (!inverted)
- return *this;
- switch (kind()) {
- case RelCond:
- return relCond(MacroAssembler::invert(asRelationalCondition()));
- case ResCond:
- return resCond(MacroAssembler::invert(asResultCondition()));
- case DoubleCond:
- return doubleCond(MacroAssembler::invert(asDoubleCondition()));
- default:
- RELEASE_ASSERT_NOT_REACHED();
- return Arg();
- }
- }
-
- Arg flipped(bool flipped = true) const
- {
- if (!flipped)
- return Arg();
- return relCond(MacroAssembler::flip(asRelationalCondition()));
- }
-
- bool isSignedCond() const
- {
- return isRelCond() && MacroAssembler::isSigned(asRelationalCondition());
- }
-
- bool isUnsignedCond() const
- {
- return isRelCond() && MacroAssembler::isUnsigned(asRelationalCondition());
- }
-
- void dump(PrintStream&) const;
-
- Arg(WTF::HashTableDeletedValueType)
- : m_base(WTF::HashTableDeletedValue)
- {
- }
-
- bool isHashTableDeletedValue() const
- {
- return *this == Arg(WTF::HashTableDeletedValue);
- }
-
- unsigned hash() const
- {
- // This really doesn't have to be that great.
- return WTF::IntHash<int64_t>::hash(m_offset) + m_kind + m_scale + m_base.hash() +
- m_index.hash();
- }
-
-private:
- int64_t m_offset { 0 };
- Kind m_kind { Invalid };
- int32_t m_scale { 1 };
- Air::Tmp m_base;
- Air::Tmp m_index;
-};
-
-struct ArgHash {
- static unsigned hash(const Arg& key) { return key.hash(); }
- static bool equal(const Arg& a, const Arg& b) { return a == b; }
- static const bool safeToCompareToEmptyOrDeleted = true;
-};
-
-} } } // namespace JSC::B3::Air
-
-namespace WTF {
-
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Kind);
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Role);
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Type);
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Width);
-void printInternal(PrintStream&, JSC::B3::Air::Arg::Signedness);
-
-template<typename T> struct DefaultHash;
-template<> struct DefaultHash<JSC::B3::Air::Arg> {
- typedef JSC::B3::Air::ArgHash Hash;
-};
-
-template<typename T> struct HashTraits;
-template<> struct HashTraits<JSC::B3::Air::Arg> : SimpleClassHashTraits<JSC::B3::Air::Arg> {
- // Because m_scale is 1 in the empty value.
- static const bool emptyValueIsZero = false;
-};
-
-} // namespace WTF
-
-#if COMPILER(GCC) && ASSERT_DISABLED
-#pragma GCC diagnostic pop
-#endif // COMPILER(GCC) && ASSERT_DISABLED
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirArg_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirArgInlines.h b/Source/JavaScriptCore/b3/air/AirArgInlines.h
deleted file mode 100644
index 90572ef0b..000000000
--- a/Source/JavaScriptCore/b3/air/AirArgInlines.h
+++ /dev/null
@@ -1,116 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef AirArgInlines_h
-#define AirArgInlines_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirArg.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-template<typename T> struct ArgThingHelper;
-
-template<> struct ArgThingHelper<Tmp> {
- static bool is(const Arg& arg)
- {
- return arg.isTmp();
- }
-
- static Tmp as(const Arg& arg)
- {
- if (is(arg))
- return arg.tmp();
- return Tmp();
- }
-
- template<typename Functor>
- static void forEachFast(Arg& arg, const Functor& functor)
- {
- arg.forEachTmpFast(functor);
- }
-
- template<typename Functor>
- static void forEach(Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width, const Functor& functor)
- {
- arg.forEachTmp(role, type, width, functor);
- }
-};
-
-template<> struct ArgThingHelper<Arg> {
- static bool is(const Arg&)
- {
- return true;
- }
-
- static Arg as(const Arg& arg)
- {
- return arg;
- }
-
- template<typename Functor>
- static void forEachFast(Arg& arg, const Functor& functor)
- {
- functor(arg);
- }
-
- template<typename Functor>
- static void forEach(Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width, const Functor& functor)
- {
- functor(arg, role, type, width);
- }
-};
-
-template<typename Thing>
-bool Arg::is() const
-{
- return ArgThingHelper<Thing>::is(*this);
-}
-
-template<typename Thing>
-Thing Arg::as() const
-{
- return ArgThingHelper<Thing>::as(*this);
-}
-
-template<typename Thing, typename Functor>
-void Arg::forEachFast(const Functor& functor)
-{
- ArgThingHelper<Thing>::forEachFast(*this, functor);
-}
-
-template<typename Thing, typename Functor>
-void Arg::forEach(Role role, Type type, Width width, const Functor& functor)
-{
- ArgThingHelper<Thing>::forEach(*this, role, type, width, functor);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirArgInlines_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirBasicBlock.cpp b/Source/JavaScriptCore/b3/air/AirBasicBlock.cpp
deleted file mode 100644
index fa3ad8e4d..000000000
--- a/Source/JavaScriptCore/b3/air/AirBasicBlock.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * 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 "AirBasicBlock.h"
-
-#if ENABLE(B3_JIT)
-
-#include "B3BasicBlockUtils.h"
-#include <wtf/ListDump.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-const char* const BasicBlock::dumpPrefix = "#";
-
-bool BasicBlock::addPredecessor(BasicBlock* block)
-{
- return B3::addPredecessor(this, block);
-}
-
-bool BasicBlock::removePredecessor(BasicBlock* block)
-{
- return B3::removePredecessor(this, block);
-}
-
-bool BasicBlock::replacePredecessor(BasicBlock* from, BasicBlock* to)
-{
- return B3::replacePredecessor(this, from, to);
-}
-
-void BasicBlock::dump(PrintStream& out) const
-{
- out.print(dumpPrefix, m_index);
-}
-
-void BasicBlock::deepDump(PrintStream& out) const
-{
- dumpHeader(out);
- for (const Inst& inst : *this)
- out.print(" ", inst, "\n");
- dumpFooter(out);
-}
-
-void BasicBlock::dumpHeader(PrintStream& out) const
-{
- out.print("BB", *this, ": ; frequency = ", m_frequency, "\n");
- if (predecessors().size())
- out.print(" Predecessors: ", pointerListDump(predecessors()), "\n");
-}
-
-void BasicBlock::dumpFooter(PrintStream& out) const
-{
- if (successors().size())
- out.print(" Successors: ", listDump(successors()), "\n");
-}
-
-BasicBlock::BasicBlock(unsigned index, double frequency)
- : m_index(index)
- , m_frequency(frequency)
-{
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirBasicBlock.h b/Source/JavaScriptCore/b3/air/AirBasicBlock.h
deleted file mode 100644
index 0f56e0b09..000000000
--- a/Source/JavaScriptCore/b3/air/AirBasicBlock.h
+++ /dev/null
@@ -1,176 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirBasicBlock_h
-#define AirBasicBlock_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirFrequentedBlock.h"
-#include "AirInst.h"
-#include "B3SuccessorCollection.h"
-#include <wtf/FastMalloc.h>
-#include <wtf/Noncopyable.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-class BlockInsertionSet;
-class Code;
-class InsertionSet;
-
-class BasicBlock {
- WTF_MAKE_NONCOPYABLE(BasicBlock);
- WTF_MAKE_FAST_ALLOCATED;
-public:
- static const char* const dumpPrefix;
-
- typedef Vector<Inst> InstList;
- typedef Vector<BasicBlock*, 2> PredecessorList;
- typedef Vector<FrequentedBlock, 2> SuccessorList;
-
- unsigned index() const { return m_index; }
-
- // This method is exposed for phases that mess with the layout of basic blocks. Currently that means just
- // optimizeBlockOrder().
- void setIndex(unsigned index) { m_index = index; }
-
- unsigned size() const { return m_insts.size(); }
- InstList::iterator begin() { return m_insts.begin(); }
- InstList::iterator end() { return m_insts.end(); }
- InstList::const_iterator begin() const { return m_insts.begin(); }
- InstList::const_iterator end() const { return m_insts.end(); }
-
- const Inst& at(unsigned index) const { return m_insts[index]; }
- Inst& at(unsigned index) { return m_insts[index]; }
-
- Inst* get(unsigned index)
- {
- return index < size() ? &at(index) : nullptr;
- }
-
- const Inst& last() const { return m_insts.last(); }
- Inst& last() { return m_insts.last(); }
-
- void resize(unsigned size) { m_insts.resize(size); }
-
- const InstList& insts() const { return m_insts; }
- InstList& insts() { return m_insts; }
-
- template<typename Inst>
- Inst& appendInst(Inst&& inst)
- {
- m_insts.append(std::forward<Inst>(inst));
- return m_insts.last();
- }
-
- template<typename... Arguments>
- Inst& append(Arguments&&... arguments)
- {
- m_insts.append(Inst(std::forward<Arguments>(arguments)...));
- return m_insts.last();
- }
-
- // The "0" case is the case to which the branch jumps, so the "then" case. The "1" case is the
- // "else" case, and is used to represent the fall-through of a conditional branch.
- unsigned numSuccessors() const { return m_successors.size(); }
- FrequentedBlock successor(unsigned index) const { return m_successors[index]; }
- FrequentedBlock& successor(unsigned index) { return m_successors[index]; }
- const SuccessorList& successors() const { return m_successors; }
- SuccessorList& successors() { return m_successors; }
-
- BasicBlock* successorBlock(unsigned index) const { return successor(index).block(); }
- BasicBlock*& successorBlock(unsigned index) { return successor(index).block(); }
- SuccessorCollection<BasicBlock, SuccessorList> successorBlocks()
- {
- return SuccessorCollection<BasicBlock, SuccessorList>(m_successors);
- }
- SuccessorCollection<const BasicBlock, const SuccessorList> successorBlocks() const
- {
- return SuccessorCollection<const BasicBlock, const SuccessorList>(m_successors);
- }
-
- unsigned numPredecessors() const { return m_predecessors.size(); }
- BasicBlock* predecessor(unsigned index) const { return m_predecessors[index]; }
- BasicBlock*& predecessor(unsigned index) { return m_predecessors[index]; }
- const PredecessorList& predecessors() const { return m_predecessors; }
- PredecessorList& predecessors() { return m_predecessors; }
-
- bool addPredecessor(BasicBlock*);
- bool removePredecessor(BasicBlock*);
- bool replacePredecessor(BasicBlock* from, BasicBlock* to);
- bool containsPredecessor(BasicBlock* predecessor) const { return m_predecessors.contains(predecessor); }
-
- double frequency() const { return m_frequency; }
-
- void dump(PrintStream&) const;
- void deepDump(PrintStream&) const;
-
- void dumpHeader(PrintStream&) const;
- void dumpFooter(PrintStream&) const;
-
-private:
- friend class BlockInsertionSet;
- friend class Code;
- friend class InsertionSet;
-
- BasicBlock(unsigned index, double frequency);
-
- unsigned m_index;
- InstList m_insts;
- SuccessorList m_successors;
- PredecessorList m_predecessors;
- double m_frequency;
-};
-
-class DeepBasicBlockDump {
-public:
- DeepBasicBlockDump(const BasicBlock* block)
- : m_block(block)
- {
- }
-
- void dump(PrintStream& out) const
- {
- if (m_block)
- m_block->deepDump(out);
- else
- out.print("<null>");
- }
-
-private:
- const BasicBlock* m_block;
-};
-
-inline DeepBasicBlockDump deepDump(const BasicBlock* block)
-{
- return DeepBasicBlockDump(block);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirBasicBlock_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirBlockWorklist.h b/Source/JavaScriptCore/b3/air/AirBlockWorklist.h
deleted file mode 100644
index eb7cfcee9..000000000
--- a/Source/JavaScriptCore/b3/air/AirBlockWorklist.h
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirBlockWorklist_h
-#define AirBlockWorklist_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirBasicBlock.h"
-#include "B3BlockWorklist.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-typedef GraphNodeWorklist<BasicBlock*, IndexSet<BasicBlock>> BlockWorklist;
-
-// When you say BlockWith<int> you should read it as "block with an int".
-template<typename T> using BlockWith = GraphNodeWith<BasicBlock*, T>;
-
-// Extended block worklist is useful for enqueueing some meta-data along with the block. It also
-// permits forcibly enqueueing things even if the block has already been seen. It's useful for
-// things like building a spanning tree, in which case T (the auxiliary payload) would be the
-// successor index.
-template<typename T> using ExtendedBlockWorklist = ExtendedGraphNodeWorklist<BasicBlock*, T, IndexSet<BasicBlock>>;
-
-typedef GraphNodeWithOrder<BasicBlock*> BlockWithOrder;
-
-typedef PostOrderGraphNodeWorklist<BasicBlock*, IndexSet<BasicBlock>> PostOrderBlockWorklist;
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirBlockWorklist_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp b/Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp
deleted file mode 100644
index 72b5fdeef..000000000
--- a/Source/JavaScriptCore/b3/air/AirCCallSpecial.cpp
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * 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 "AirCCallSpecial.h"
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-CCallSpecial::CCallSpecial()
-{
- m_clobberedRegs = RegisterSet::allRegisters();
- m_clobberedRegs.exclude(RegisterSet::stackRegisters());
- m_clobberedRegs.exclude(RegisterSet::reservedHardwareRegisters());
- m_clobberedRegs.exclude(RegisterSet::calleeSaveRegisters());
- m_clobberedRegs.clear(GPRInfo::returnValueGPR);
- m_clobberedRegs.clear(GPRInfo::returnValueGPR2);
- m_clobberedRegs.clear(FPRInfo::returnValueFPR);
-}
-
-CCallSpecial::~CCallSpecial()
-{
-}
-
-void CCallSpecial::forEachArg(Inst& inst, const ScopedLambda<Inst::EachArgCallback>& callback)
-{
- for (unsigned i = 0; i < numCalleeArgs; ++i)
- callback(inst.args[calleeArgOffset + i], Arg::Use, Arg::GP, Arg::pointerWidth());
- for (unsigned i = 0; i < numReturnGPArgs; ++i)
- callback(inst.args[returnGPArgOffset + i], Arg::Def, Arg::GP, Arg::pointerWidth());
- for (unsigned i = 0; i < numReturnFPArgs; ++i)
- callback(inst.args[returnFPArgOffset + i], Arg::Def, Arg::FP, Arg::Width64);
-
- for (unsigned i = argArgOffset; i < inst.args.size(); ++i) {
- // For the type, we can just query the arg's type. The arg will have a type, because we
- // require these args to be argument registers.
- Arg::Type type = inst.args[i].type();
- callback(inst.args[i], Arg::Use, type, Arg::conservativeWidth(type));
- }
-}
-
-bool CCallSpecial::isValid(Inst& inst)
-{
- if (inst.args.size() < argArgOffset)
- return false;
-
- for (unsigned i = 0; i < numCalleeArgs; ++i) {
- Arg& arg = inst.args[i + calleeArgOffset];
- if (!arg.isGP())
- return false;
- switch (arg.kind()) {
- case Arg::Imm:
- if (is32Bit())
- break;
- return false;
- case Arg::BigImm:
- if (is64Bit())
- break;
- return false;
- case Arg::Tmp:
- case Arg::Addr:
- case Arg::Stack:
- case Arg::CallArg:
- break;
- default:
- return false;
- }
- }
-
- // Return args need to be exact.
- if (inst.args[returnGPArgOffset + 0] != Tmp(GPRInfo::returnValueGPR))
- return false;
- if (inst.args[returnGPArgOffset + 1] != Tmp(GPRInfo::returnValueGPR2))
- return false;
- if (inst.args[returnFPArgOffset + 0] != Tmp(FPRInfo::returnValueFPR))
- return false;
-
- for (unsigned i = argArgOffset; i < inst.args.size(); ++i) {
- if (!inst.args[i].isReg())
- return false;
-
- if (inst.args[i] == Tmp(scratchRegister))
- return false;
- }
- return true;
-}
-
-bool CCallSpecial::admitsStack(Inst&, unsigned argIndex)
-{
- // The callee can be on the stack.
- if (argIndex == calleeArgOffset)
- return true;
-
- return false;
-}
-
-void CCallSpecial::reportUsedRegisters(Inst&, const RegisterSet&)
-{
-}
-
-CCallHelpers::Jump CCallSpecial::generate(Inst& inst, CCallHelpers& jit, GenerationContext&)
-{
- switch (inst.args[calleeArgOffset].kind()) {
- case Arg::Imm:
- case Arg::BigImm:
- jit.move(inst.args[calleeArgOffset].asTrustedImmPtr(), scratchRegister);
- jit.call(scratchRegister);
- break;
- case Arg::Tmp:
- jit.call(inst.args[calleeArgOffset].gpr());
- break;
- case Arg::Addr:
- jit.call(inst.args[calleeArgOffset].asAddress());
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
- return CCallHelpers::Jump();
-}
-
-const RegisterSet& CCallSpecial::extraEarlyClobberedRegs(Inst&)
-{
- return m_emptyRegs;
-}
-
-const RegisterSet& CCallSpecial::extraClobberedRegs(Inst&)
-{
- return m_clobberedRegs;
-}
-
-void CCallSpecial::dumpImpl(PrintStream& out) const
-{
- out.print("CCall");
-}
-
-void CCallSpecial::deepDumpImpl(PrintStream& out) const
-{
- out.print("function call that uses the C calling convention.");
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirCCallSpecial.h b/Source/JavaScriptCore/b3/air/AirCCallSpecial.h
deleted file mode 100644
index d8ed867ac..000000000
--- a/Source/JavaScriptCore/b3/air/AirCCallSpecial.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirCCallSpecial_h
-#define AirCCallSpecial_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirSpecial.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-// Use this special for constructing a C call. Arg 0 is of course a Special arg that refers to the
-// CCallSpecial object. Arg 1 is the callee, and it can be an ImmPtr, a register, or an address. The
-// next three args - arg 2, arg 3, and arg 4 - hold the return value GPRs and FPR. The remaining args
-// are just the set of argument registers used by this call. For arguments that go to the stack, you
-// have to do the grunt work of doing those stack stores. In fact, the only reason why we specify the
-// argument registers as arguments to a call is so that the liveness analysis can see that they get
-// used here. It would be wrong to automagically report all argument registers as being used because
-// if we had a call that didn't pass them, then they'd appear to be live until some clobber point or
-// the prologue, whichever happened sooner.
-
-class CCallSpecial : public Special {
-public:
- CCallSpecial();
- ~CCallSpecial();
-
- // You cannot use this register to pass arguments. It just so happens that this register is not
- // used for arguments in the C calling convention. By the way, this is the only thing that causes
- // this special to be specific to C calls.
- static const GPRReg scratchRegister = GPRInfo::nonArgGPR0;
-
-protected:
- void forEachArg(Inst&, const ScopedLambda<Inst::EachArgCallback>&) override;
- bool isValid(Inst&) override;
- bool admitsStack(Inst&, unsigned argIndex) override;
- void reportUsedRegisters(Inst&, const RegisterSet&) override;
- CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&) override;
- const RegisterSet& extraEarlyClobberedRegs(Inst&) override;
- const RegisterSet& extraClobberedRegs(Inst&) override;
-
- void dumpImpl(PrintStream&) const override;
- void deepDumpImpl(PrintStream&) const override;
-
-private:
- static const unsigned specialArgOffset = 0;
- static const unsigned numSpecialArgs = 1;
- static const unsigned calleeArgOffset = numSpecialArgs;
- static const unsigned numCalleeArgs = 1;
- static const unsigned returnGPArgOffset = numSpecialArgs + numCalleeArgs;
- static const unsigned numReturnGPArgs = 2;
- static const unsigned returnFPArgOffset = numSpecialArgs + numCalleeArgs + numReturnGPArgs;
- static const unsigned numReturnFPArgs = 1;
- static const unsigned argArgOffset =
- numSpecialArgs + numCalleeArgs + numReturnGPArgs + numReturnFPArgs;
-
- RegisterSet m_clobberedRegs;
- RegisterSet m_emptyRegs;
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirCCallSpecial_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirCCallingConvention.cpp b/Source/JavaScriptCore/b3/air/AirCCallingConvention.cpp
deleted file mode 100644
index 63128a7c9..000000000
--- a/Source/JavaScriptCore/b3/air/AirCCallingConvention.cpp
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2016 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 "AirCCallingConvention.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCCallSpecial.h"
-#include "AirCode.h"
-#include "B3CCallValue.h"
-#include "B3ValueInlines.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-namespace {
-
-template<typename BankInfo>
-Arg marshallCCallArgumentImpl(unsigned& argumentCount, unsigned& stackOffset, Value* child)
-{
- unsigned argumentIndex = argumentCount++;
- if (argumentIndex < BankInfo::numberOfArgumentRegisters)
- return Tmp(BankInfo::toArgumentRegister(argumentIndex));
-
- unsigned slotSize;
- if (isARM64() && isIOS()) {
- // Arguments are packed.
- slotSize = sizeofType(child->type());
- } else {
- // Arguments are aligned.
- slotSize = 8;
- }
-
- stackOffset = WTF::roundUpToMultipleOf(slotSize, stackOffset);
- Arg result = Arg::callArg(stackOffset);
- stackOffset += slotSize;
- return result;
-}
-
-Arg marshallCCallArgument(
- unsigned& gpArgumentCount, unsigned& fpArgumentCount, unsigned& stackOffset, Value* child)
-{
- switch (Arg::typeForB3Type(child->type())) {
- case Arg::GP:
- return marshallCCallArgumentImpl<GPRInfo>(gpArgumentCount, stackOffset, child);
- case Arg::FP:
- return marshallCCallArgumentImpl<FPRInfo>(fpArgumentCount, stackOffset, child);
- }
- RELEASE_ASSERT_NOT_REACHED();
- return Arg();
-}
-
-} // anonymous namespace
-
-Vector<Arg> computeCCallingConvention(Code& code, CCallValue* value)
-{
- Vector<Arg> result;
- result.append(Tmp(CCallSpecial::scratchRegister));
- unsigned gpArgumentCount = 0;
- unsigned fpArgumentCount = 0;
- unsigned stackOffset = 0;
- for (unsigned i = 1; i < value->numChildren(); ++i) {
- result.append(
- marshallCCallArgument(gpArgumentCount, fpArgumentCount, stackOffset, value->child(i)));
- }
- code.requestCallArgAreaSize(WTF::roundUpToMultipleOf(stackAlignmentBytes(), stackOffset));
- return result;
-}
-
-Tmp cCallResult(Type type)
-{
- switch (type) {
- case Void:
- return Tmp();
- case Int32:
- case Int64:
- return Tmp(GPRInfo::returnValueGPR);
- case Float:
- case Double:
- return Tmp(FPRInfo::returnValueFPR);
- }
-
- RELEASE_ASSERT_NOT_REACHED();
- return Tmp();
-}
-
-Inst buildCCall(Code& code, Value* origin, const Vector<Arg>& arguments)
-{
- Inst inst(Patch, origin, Arg::special(code.cCallSpecial()));
- inst.args.append(arguments[0]);
- inst.args.append(Tmp(GPRInfo::returnValueGPR));
- inst.args.append(Tmp(GPRInfo::returnValueGPR2));
- inst.args.append(Tmp(FPRInfo::returnValueFPR));
- for (unsigned i = 1; i < arguments.size(); ++i) {
- Arg arg = arguments[i];
- if (arg.isTmp())
- inst.args.append(arg);
- }
- return inst;
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirCCallingConvention.h b/Source/JavaScriptCore/b3/air/AirCCallingConvention.h
deleted file mode 100644
index 11005e890..000000000
--- a/Source/JavaScriptCore/b3/air/AirCCallingConvention.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef AirCCallingConvention_h
-#define AirCCallingConvention_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirArg.h"
-#include "AirInst.h"
-#include "B3Type.h"
-#include <wtf/Vector.h>
-
-namespace JSC { namespace B3 {
-
-class CCallValue;
-
-namespace Air {
-
-class Code;
-
-Vector<Arg> computeCCallingConvention(Code&, CCallValue*);
-
-Tmp cCallResult(Type);
-
-Inst buildCCall(Code&, Value* origin, const Vector<Arg>&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirCCallingConvention_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirCode.cpp b/Source/JavaScriptCore/b3/air/AirCode.cpp
deleted file mode 100644
index 6664186c9..000000000
--- a/Source/JavaScriptCore/b3/air/AirCode.cpp
+++ /dev/null
@@ -1,139 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirCode.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCCallSpecial.h"
-#include "B3BasicBlockUtils.h"
-#include "B3StackSlot.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-Code::Code(Procedure& proc)
- : m_proc(proc)
- , m_lastPhaseName("initial")
-{
-}
-
-Code::~Code()
-{
-}
-
-BasicBlock* Code::addBlock(double frequency)
-{
- std::unique_ptr<BasicBlock> block(new BasicBlock(m_blocks.size(), frequency));
- BasicBlock* result = block.get();
- m_blocks.append(WTFMove(block));
- return result;
-}
-
-StackSlot* Code::addStackSlot(unsigned byteSize, StackSlotKind kind, B3::StackSlot* b3Slot)
-{
- return m_stackSlots.addNew(byteSize, kind, b3Slot);
-}
-
-StackSlot* Code::addStackSlot(B3::StackSlot* b3Slot)
-{
- return addStackSlot(b3Slot->byteSize(), StackSlotKind::Locked, b3Slot);
-}
-
-Special* Code::addSpecial(std::unique_ptr<Special> special)
-{
- special->m_code = this;
- return m_specials.add(WTFMove(special));
-}
-
-CCallSpecial* Code::cCallSpecial()
-{
- if (!m_cCallSpecial) {
- m_cCallSpecial = static_cast<CCallSpecial*>(
- addSpecial(std::make_unique<CCallSpecial>()));
- }
-
- return m_cCallSpecial;
-}
-
-void Code::resetReachability()
-{
- B3::resetReachability(
- m_blocks,
- [&] (BasicBlock*) {
- // We don't have to do anything special for deleted blocks.
- });
-}
-
-void Code::dump(PrintStream& out) const
-{
- for (BasicBlock* block : *this)
- out.print(deepDump(block));
- if (stackSlots().size()) {
- out.print("Stack slots:\n");
- for (StackSlot* slot : stackSlots())
- out.print(" ", pointerDump(slot), ": ", deepDump(slot), "\n");
- }
- if (specials().size()) {
- out.print("Specials:\n");
- for (Special* special : specials())
- out.print(" ", deepDump(special), "\n");
- }
- if (m_frameSize)
- out.print("Frame size: ", m_frameSize, "\n");
- if (m_callArgAreaSize)
- out.print("Call arg area size: ", m_callArgAreaSize, "\n");
- if (m_calleeSaveRegisters.size())
- out.print("Callee saves: ", m_calleeSaveRegisters, "\n");
-}
-
-unsigned Code::findFirstBlockIndex(unsigned index) const
-{
- while (index < size() && !at(index))
- index++;
- return index;
-}
-
-unsigned Code::findNextBlockIndex(unsigned index) const
-{
- return findFirstBlockIndex(index + 1);
-}
-
-BasicBlock* Code::findNextBlock(BasicBlock* block) const
-{
- unsigned index = findNextBlockIndex(block->index());
- if (index < size())
- return at(index);
- return nullptr;
-}
-
-void Code::addFastTmp(Tmp tmp)
-{
- m_fastTmps.add(tmp);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirCode.h b/Source/JavaScriptCore/b3/air/AirCode.h
deleted file mode 100644
index a647addfb..000000000
--- a/Source/JavaScriptCore/b3/air/AirCode.h
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirCode_h
-#define AirCode_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirArg.h"
-#include "AirBasicBlock.h"
-#include "AirSpecial.h"
-#include "AirStackSlot.h"
-#include "AirTmp.h"
-#include "B3SparseCollection.h"
-#include "RegisterAtOffsetList.h"
-#include "StackAlignment.h"
-
-namespace JSC { namespace B3 {
-
-class Procedure;
-
-#if COMPILER(GCC) && ASSERT_DISABLED
-#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wreturn-type"
-#endif // COMPILER(GCC) && ASSERT_DISABLED
-
-namespace Air {
-
-class BlockInsertionSet;
-class CCallSpecial;
-
-// This is an IR that is very close to the bare metal. It requires about 40x more bytes than the
-// generated machine code - for example if you're generating 1MB of machine code, you need about
-// 40MB of Air.
-
-class Code {
- WTF_MAKE_NONCOPYABLE(Code);
- WTF_MAKE_FAST_ALLOCATED;
-public:
- ~Code();
-
- Procedure& proc() { return m_proc; }
-
- JS_EXPORT_PRIVATE BasicBlock* addBlock(double frequency = 1);
-
- // Note that you can rely on stack slots always getting indices that are larger than the index
- // of any prior stack slot. In fact, all stack slots you create in the future will have an index
- // that is >= stackSlots().size().
- JS_EXPORT_PRIVATE StackSlot* addStackSlot(
- unsigned byteSize, StackSlotKind, B3::StackSlot* = nullptr);
- StackSlot* addStackSlot(B3::StackSlot*);
-
- Special* addSpecial(std::unique_ptr<Special>);
-
- // This is the special you need to make a C call!
- CCallSpecial* cCallSpecial();
-
- Tmp newTmp(Arg::Type type)
- {
- switch (type) {
- case Arg::GP:
- return Tmp::gpTmpForIndex(m_numGPTmps++);
- case Arg::FP:
- return Tmp::fpTmpForIndex(m_numFPTmps++);
- }
- ASSERT_NOT_REACHED();
- }
-
- unsigned numTmps(Arg::Type type)
- {
- switch (type) {
- case Arg::GP:
- return m_numGPTmps;
- case Arg::FP:
- return m_numFPTmps;
- }
- ASSERT_NOT_REACHED();
- }
-
- unsigned callArgAreaSize() const { return m_callArgAreaSize; }
-
- // You can call this before code generation to force a minimum call arg area size.
- void requestCallArgAreaSize(unsigned size)
- {
- m_callArgAreaSize = std::max(
- m_callArgAreaSize,
- static_cast<unsigned>(WTF::roundUpToMultipleOf(stackAlignmentBytes(), size)));
- }
-
- unsigned frameSize() const { return m_frameSize; }
-
- // Only phases that do stack allocation are allowed to set this. Currently, only
- // Air::allocateStack() does this.
- void setFrameSize(unsigned frameSize)
- {
- m_frameSize = frameSize;
- }
-
- const RegisterAtOffsetList& calleeSaveRegisters() const { return m_calleeSaveRegisters; }
- RegisterAtOffsetList& calleeSaveRegisters() { return m_calleeSaveRegisters; }
-
- // Recomputes predecessors and deletes unreachable blocks.
- void resetReachability();
-
- void dump(PrintStream&) const;
-
- unsigned size() const { return m_blocks.size(); }
- BasicBlock* at(unsigned index) const { return m_blocks[index].get(); }
- BasicBlock* operator[](unsigned index) const { return at(index); }
-
- // This is used by phases that optimize the block list. You shouldn't use this unless you really know
- // what you're doing.
- Vector<std::unique_ptr<BasicBlock>>& blockList() { return m_blocks; }
-
- // Finds the smallest index' such that at(index') != null and index' >= index.
- unsigned findFirstBlockIndex(unsigned index) const;
-
- // Finds the smallest index' such that at(index') != null and index' > index.
- unsigned findNextBlockIndex(unsigned index) const;
-
- BasicBlock* findNextBlock(BasicBlock*) const;
-
- class iterator {
- public:
- iterator()
- : m_code(nullptr)
- , m_index(0)
- {
- }
-
- iterator(const Code& code, unsigned index)
- : m_code(&code)
- , m_index(m_code->findFirstBlockIndex(index))
- {
- }
-
- BasicBlock* operator*()
- {
- return m_code->at(m_index);
- }
-
- iterator& operator++()
- {
- m_index = m_code->findFirstBlockIndex(m_index + 1);
- return *this;
- }
-
- bool operator==(const iterator& other) const
- {
- return m_index == other.m_index;
- }
-
- bool operator!=(const iterator& other) const
- {
- return !(*this == other);
- }
-
- private:
- const Code* m_code;
- unsigned m_index;
- };
-
- iterator begin() const { return iterator(*this, 0); }
- iterator end() const { return iterator(*this, size()); }
-
- const SparseCollection<StackSlot>& stackSlots() const { return m_stackSlots; }
- SparseCollection<StackSlot>& stackSlots() { return m_stackSlots; }
-
- const SparseCollection<Special>& specials() const { return m_specials; }
- SparseCollection<Special>& specials() { return m_specials; }
-
- template<typename Callback>
- void forAllTmps(const Callback& callback) const
- {
- for (unsigned i = m_numGPTmps; i--;)
- callback(Tmp::gpTmpForIndex(i));
- for (unsigned i = m_numFPTmps; i--;)
- callback(Tmp::fpTmpForIndex(i));
- }
-
- void addFastTmp(Tmp);
- bool isFastTmp(Tmp tmp) const { return m_fastTmps.contains(tmp); }
-
- // The name has to be a string literal, since we don't do any memory management for the string.
- void setLastPhaseName(const char* name)
- {
- m_lastPhaseName = name;
- }
-
- const char* lastPhaseName() const { return m_lastPhaseName; }
-
-private:
- friend class ::JSC::B3::Procedure;
- friend class BlockInsertionSet;
-
- Code(Procedure&);
-
- Procedure& m_proc; // Some meta-data, like byproducts, is stored in the Procedure.
- SparseCollection<StackSlot> m_stackSlots;
- Vector<std::unique_ptr<BasicBlock>> m_blocks;
- SparseCollection<Special> m_specials;
- HashSet<Tmp> m_fastTmps;
- CCallSpecial* m_cCallSpecial { nullptr };
- unsigned m_numGPTmps { 0 };
- unsigned m_numFPTmps { 0 };
- unsigned m_frameSize { 0 };
- unsigned m_callArgAreaSize { 0 };
- RegisterAtOffsetList m_calleeSaveRegisters;
- const char* m_lastPhaseName;
-};
-
-} } } // namespace JSC::B3::Air
-
-#if COMPILER(GCC) && ASSERT_DISABLED
-#pragma GCC diagnostic pop
-#endif // COMPILER(GCC) && ASSERT_DISABLED
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirCode_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirCustom.cpp b/Source/JavaScriptCore/b3/air/AirCustom.cpp
deleted file mode 100644
index f6eb5f38d..000000000
--- a/Source/JavaScriptCore/b3/air/AirCustom.cpp
+++ /dev/null
@@ -1,184 +0,0 @@
-/*
- * Copyright (C) 2016 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 "AirCustom.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirInstInlines.h"
-#include "B3CCallValue.h"
-#include "B3ValueInlines.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-bool PatchCustom::isValidForm(Inst& inst)
-{
- if (inst.args.size() < 1)
- return false;
- if (!inst.args[0].isSpecial())
- return false;
- if (!inst.args[0].special()->isValid(inst))
- return false;
- RegisterSet clobberedEarly = inst.extraEarlyClobberedRegs();
- RegisterSet clobberedLate = inst.extraClobberedRegs();
- bool ok = true;
- inst.forEachTmp(
- [&] (Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) {
- if (!tmp.isReg())
- return;
- if (Arg::isLateDef(role) || Arg::isLateUse(role))
- ok &= !clobberedLate.get(tmp.reg());
- else
- ok &= !clobberedEarly.get(tmp.reg());
- });
- return ok;
-}
-
-bool CCallCustom::isValidForm(Inst& inst)
-{
- CCallValue* value = inst.origin->as<CCallValue>();
- if (!value)
- return false;
-
- if (inst.args.size() != (value->type() == Void ? 0 : 1) + value->numChildren())
- return false;
-
- // The arguments can only refer to the stack, tmps, or immediates.
- for (Arg& arg : inst.args) {
- if (!arg.isTmp() && !arg.isStackMemory() && !arg.isSomeImm())
- return false;
- }
-
- unsigned offset = 0;
-
- if (!inst.args[0].isGP())
- return false;
-
- // If there is a result then it cannot be an immediate.
- if (value->type() != Void) {
- if (inst.args[1].isSomeImm())
- return false;
- if (!inst.args[1].canRepresent(value))
- return false;
- offset++;
- }
-
- for (unsigned i = value->numChildren(); i-- > 1;) {
- Value* child = value->child(i);
- Arg arg = inst.args[offset + i];
- if (!arg.canRepresent(child))
- return false;
- }
-
- return true;
-}
-
-CCallHelpers::Jump CCallCustom::generate(Inst& inst, CCallHelpers&, GenerationContext&)
-{
- dataLog("FATAL: Unlowered C call: ", inst, "\n");
- UNREACHABLE_FOR_PLATFORM();
- return CCallHelpers::Jump();
-}
-
-bool ShuffleCustom::isValidForm(Inst& inst)
-{
- if (inst.args.size() % 3)
- return false;
-
- // A destination may only appear once. This requirement allows us to avoid the undefined behavior
- // of having a destination that is supposed to get multiple inputs simultaneously. It also
- // imposes some interesting constraints on the "shape" of the shuffle. If we treat a shuffle pair
- // as an edge and the Args as nodes, then the single-destination requirement means that the
- // shuffle graph consists of two kinds of subgraphs:
- //
- // - Spanning trees. We call these shifts. They can be executed as a sequence of Move
- // instructions and don't usually require scratch registers.
- //
- // - Closed loops. These loops consist of nodes that have one successor and one predecessor, so
- // there is no way to "get into" the loop from outside of it. These can be executed using swaps
- // or by saving one of the Args to a scratch register and executing it as a shift.
- HashSet<Arg> dsts;
-
- for (unsigned i = 0; i < inst.args.size(); ++i) {
- Arg arg = inst.args[i];
- unsigned mode = i % 3;
-
- if (mode == 2) {
- // It's the width.
- if (!arg.isWidthArg())
- return false;
- continue;
- }
-
- // The source can be an immediate.
- if (!mode) {
- if (arg.isSomeImm())
- continue;
-
- if (!arg.isCompatibleType(inst.args[i + 1]))
- return false;
- } else {
- ASSERT(mode == 1);
- if (!dsts.add(arg).isNewEntry)
- return false;
- }
-
- if (arg.isTmp() || arg.isMemory())
- continue;
-
- return false;
- }
-
- // No destination register may appear in any address expressions. The lowering can't handle it
- // and it's not useful for the way we end up using Shuffles. Normally, Shuffles only used for
- // stack addresses and non-stack registers.
- for (Arg& arg : inst.args) {
- if (!arg.isMemory())
- continue;
- bool ok = true;
- arg.forEachTmpFast(
- [&] (Tmp tmp) {
- if (dsts.contains(tmp))
- ok = false;
- });
- if (!ok)
- return false;
- }
-
- return true;
-}
-
-CCallHelpers::Jump ShuffleCustom::generate(Inst& inst, CCallHelpers&, GenerationContext&)
-{
- dataLog("FATAL: Unlowered shuffle: ", inst, "\n");
- UNREACHABLE_FOR_PLATFORM();
- return CCallHelpers::Jump();
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirCustom.h b/Source/JavaScriptCore/b3/air/AirCustom.h
deleted file mode 100644
index bcc41ce4a..000000000
--- a/Source/JavaScriptCore/b3/air/AirCustom.h
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef AirCustom_h
-#define AirCustom_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirInst.h"
-#include "AirSpecial.h"
-#include "B3Value.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-// This defines the behavior of custom instructions - i.e. those whose behavior cannot be
-// described using AirOpcode.opcodes. If you define an opcode as "custom Foo" in that file, then
-// you will need to create a "struct FooCustom" here that implements the custom behavior
-// methods.
-//
-// The customizability granted by the custom instruction mechanism is strictly less than what
-// you get using the Patch instruction and implementing a Special. However, that path requires
-// allocating a Special object and ensuring that it's the first operand. For many instructions,
-// that is not as convenient as using Custom, which makes the instruction look like any other
-// instruction. Note that both of those extra powers of the Patch instruction happen because we
-// special-case that instruction in many phases and analyses. Non-special-cased behaviors of
-// Patch are implemented using the custom instruction mechanism.
-//
-// Specials are still more flexible if you need to list extra clobbered registers and you'd like
-// that to be expressed as a bitvector rather than an arglist. They are also more flexible if
-// you need to carry extra state around with the instruction. Also, Specials mean that you
-// always have access to Code& even in methods that don't take a GenerationContext.
-
-// Definition of Patch instruction. Patch is used to delegate the behavior of the instruction to the
-// Special object, which will be the first argument to the instruction.
-struct PatchCustom {
- template<typename Functor>
- static void forEachArg(Inst& inst, const Functor& functor)
- {
- // This is basically bogus, but it works for analyses that model Special as an
- // immediate.
- functor(inst.args[0], Arg::Use, Arg::GP, Arg::pointerWidth());
-
- inst.args[0].special()->forEachArg(inst, scopedLambda<Inst::EachArgCallback>(functor));
- }
-
- template<typename... Arguments>
- static bool isValidFormStatic(Arguments...)
- {
- return false;
- }
-
- static bool isValidForm(Inst& inst);
-
- static bool admitsStack(Inst& inst, unsigned argIndex)
- {
- if (!argIndex)
- return false;
- return inst.args[0].special()->admitsStack(inst, argIndex);
- }
-
- static Optional<unsigned> shouldTryAliasingDef(Inst& inst)
- {
- return inst.args[0].special()->shouldTryAliasingDef(inst);
- }
-
- static bool hasNonArgNonControlEffects(Inst& inst)
- {
- return inst.args[0].special()->hasNonArgNonControlEffects();
- }
-
- static CCallHelpers::Jump generate(
- Inst& inst, CCallHelpers& jit, GenerationContext& context)
- {
- return inst.args[0].special()->generate(inst, jit, context);
- }
-};
-
-// Definition of CCall instruction. CCall is used for hot path C function calls. It's lowered to a
-// Patch with an Air CCallSpecial along with code to marshal instructions. The lowering happens
-// before register allocation, so that the register allocator sees the clobbers.
-struct CCallCustom {
- template<typename Functor>
- static void forEachArg(Inst& inst, const Functor& functor)
- {
- Value* value = inst.origin;
-
- unsigned index = 0;
-
- functor(inst.args[index++], Arg::Use, Arg::GP, Arg::pointerWidth()); // callee
-
- if (value->type() != Void) {
- functor(
- inst.args[index++], Arg::Def,
- Arg::typeForB3Type(value->type()),
- Arg::widthForB3Type(value->type()));
- }
-
- for (unsigned i = 1; i < value->numChildren(); ++i) {
- Value* child = value->child(i);
- functor(
- inst.args[index++], Arg::Use,
- Arg::typeForB3Type(child->type()),
- Arg::widthForB3Type(child->type()));
- }
- }
-
- template<typename... Arguments>
- static bool isValidFormStatic(Arguments...)
- {
- return false;
- }
-
- static bool isValidForm(Inst&);
-
- static bool admitsStack(Inst&, unsigned)
- {
- return true;
- }
-
- static bool hasNonArgNonControlEffects(Inst&)
- {
- return true;
- }
-
- // This just crashes, since we expect C calls to be lowered before generation.
- static CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&);
-};
-
-struct ColdCCallCustom : CCallCustom {
- template<typename Functor>
- static void forEachArg(Inst& inst, const Functor& functor)
- {
- // This is just like a call, but uses become cold.
- CCallCustom::forEachArg(
- inst,
- [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) {
- functor(arg, Arg::cooled(role), type, width);
- });
- }
-};
-
-struct ShuffleCustom {
- template<typename Functor>
- static void forEachArg(Inst& inst, const Functor& functor)
- {
- unsigned limit = inst.args.size() / 3 * 3;
- for (unsigned i = 0; i < limit; i += 3) {
- Arg& src = inst.args[i + 0];
- Arg& dst = inst.args[i + 1];
- Arg& widthArg = inst.args[i + 2];
- Arg::Width width = widthArg.width();
- Arg::Type type = src.isGP() && dst.isGP() ? Arg::GP : Arg::FP;
- functor(src, Arg::Use, type, width);
- functor(dst, Arg::Def, type, width);
- functor(widthArg, Arg::Use, Arg::GP, Arg::Width8);
- }
- }
-
- template<typename... Arguments>
- static bool isValidFormStatic(Arguments...)
- {
- return false;
- }
-
- static bool isValidForm(Inst&);
-
- static bool admitsStack(Inst&, unsigned index)
- {
- switch (index % 3) {
- case 0:
- case 1:
- return true;
- default:
- return false;
- }
- }
-
- static bool hasNonArgNonControlEffects(Inst&)
- {
- return false;
- }
-
- static CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&);
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirCustom_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp b/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp
deleted file mode 100644
index 3663eaa99..000000000
--- a/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirEliminateDeadCode.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include "AirPhaseScope.h"
-#include "B3IndexSet.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-bool eliminateDeadCode(Code& code)
-{
- PhaseScope phaseScope(code, "eliminateDeadCode");
-
- HashSet<Tmp> liveTmps;
- IndexSet<StackSlot> liveStackSlots;
- bool changed;
-
- auto isArgLive = [&] (const Arg& arg) -> bool {
- switch (arg.kind()) {
- case Arg::Tmp:
- if (arg.isReg())
- return true;
- return liveTmps.contains(arg.tmp());
- case Arg::Stack:
- if (arg.stackSlot()->isLocked())
- return true;
- return liveStackSlots.contains(arg.stackSlot());
- default:
- return true;
- }
- };
-
- auto addLiveArg = [&] (const Arg& arg) -> bool {
- switch (arg.kind()) {
- case Arg::Tmp:
- if (arg.isReg())
- return false;
- return liveTmps.add(arg.tmp()).isNewEntry;
- case Arg::Stack:
- if (arg.stackSlot()->isLocked())
- return false;
- return liveStackSlots.add(arg.stackSlot());
- default:
- return false;
- }
- };
-
- auto isInstLive = [&] (Inst& inst) -> bool {
- if (inst.hasNonArgEffects())
- return true;
-
- // This instruction should be presumed dead, if its Args are all dead.
- bool storesToLive = false;
- inst.forEachArg(
- [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) {
- if (!Arg::isAnyDef(role))
- return;
- if (role == Arg::Scratch)
- return;
- storesToLive |= isArgLive(arg);
- });
- return storesToLive;
- };
-
- auto handleInst = [&] (Inst& inst) {
- if (!isInstLive(inst))
- return;
-
- // We get here if the Inst is live. For simplicity we say that a live instruction forces
- // liveness upon everything it mentions.
- for (Arg& arg : inst.args) {
- changed |= addLiveArg(arg);
- arg.forEachTmpFast(
- [&] (Tmp& tmp) {
- changed |= addLiveArg(tmp);
- });
- }
- };
-
- auto runForward = [&] () -> bool {
- changed = false;
- for (BasicBlock* block : code) {
- for (Inst& inst : *block)
- handleInst(inst);
- }
- return changed;
- };
-
- auto runBackward = [&] () -> bool {
- changed = false;
- for (unsigned blockIndex = code.size(); blockIndex--;) {
- BasicBlock* block = code[blockIndex];
- for (unsigned instIndex = block->size(); instIndex--;)
- handleInst(block->at(instIndex));
- }
- return changed;
- };
-
- for (;;) {
- // Propagating backward is most likely to be profitable.
- if (!runBackward())
- break;
- if (!runBackward())
- break;
-
- // Occasionally propagating forward greatly reduces the likelihood of pathologies.
- if (!runForward())
- break;
- }
-
- unsigned removedInstCount = 0;
- for (BasicBlock* block : code) {
- removedInstCount += block->insts().removeAllMatching(
- [&] (Inst& inst) -> bool {
- return !isInstLive(inst);
- });
- }
-
- return !!removedInstCount;
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.h b/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.h
deleted file mode 100644
index d458bc91d..000000000
--- a/Source/JavaScriptCore/b3/air/AirEliminateDeadCode.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirEliminateDeadCode_h
-#define AirEliminateDeadCode_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// This eliminates instructions that have no observable effect. These are instructions whose only
-// effect would be storing to some Arg, except that we proved that the location specified by the Arg
-// is never loaded from. The only Args for which we can do such analysis are non-Reg Tmps and
-// anonymous StackSlots.
-
-bool eliminateDeadCode(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirEliminateDeadCode_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirEmitShuffle.cpp b/Source/JavaScriptCore/b3/air/AirEmitShuffle.cpp
deleted file mode 100644
index 5faf133d8..000000000
--- a/Source/JavaScriptCore/b3/air/AirEmitShuffle.cpp
+++ /dev/null
@@ -1,542 +0,0 @@
-/*
- * Copyright (C) 2016 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 "AirEmitShuffle.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirInstInlines.h"
-#include "AirRegisterPriority.h"
-#include <wtf/GraphNodeWorklist.h>
-#include <wtf/ListDump.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-namespace {
-
-bool verbose = false;
-
-template<typename Functor>
-Tmp findPossibleScratch(Arg::Type type, const Functor& functor) {
- for (Reg reg : regsInPriorityOrder(type)) {
- Tmp tmp(reg);
- if (functor(tmp))
- return tmp;
- }
- return Tmp();
-}
-
-Tmp findPossibleScratch(Arg::Type type, const Arg& arg1, const Arg& arg2) {
- return findPossibleScratch(
- type,
- [&] (Tmp tmp) -> bool {
- return !arg1.usesTmp(tmp) && !arg2.usesTmp(tmp);
- });
-}
-
-// Example: (a => b, b => a, a => c, b => d)
-struct Rotate {
- Vector<ShufflePair> loop; // in the example, this is the loop: (a => b, b => a)
- Vector<ShufflePair> fringe; // in the example, these are the associated shifts: (a => c, b => d)
-};
-
-} // anonymous namespace
-
-void ShufflePair::dump(PrintStream& out) const
-{
- out.print(width(), ":", src(), "=>", dst());
-}
-
-Inst createShuffle(Value* origin, const Vector<ShufflePair>& pairs)
-{
- Inst result(Shuffle, origin);
- for (const ShufflePair& pair : pairs)
- result.append(pair.src(), pair.dst(), Arg::widthArg(pair.width()));
- return result;
-}
-
-Vector<Inst> emitShuffle(
- Vector<ShufflePair> pairs, std::array<Arg, 2> scratches, Arg::Type type, Value* origin)
-{
- if (verbose) {
- dataLog(
- "Dealing with pairs: ", listDump(pairs), " and scratches ", scratches[0], ", ",
- scratches[1], "\n");
- }
-
- pairs.removeAllMatching(
- [&] (const ShufflePair& pair) -> bool {
- return pair.src() == pair.dst();
- });
-
- // First validate that this is the kind of shuffle that we know how to deal with.
-#if !ASSERT_DISABLED
- for (const ShufflePair& pair : pairs) {
- ASSERT(pair.src().isType(type));
- ASSERT(pair.dst().isType(type));
- ASSERT(pair.dst().isTmp() || pair.dst().isMemory());
- }
-#endif // !ASSERT_DISABLED
-
- // There are two possible kinds of operations that we will do:
- //
- // - Shift. Example: (a => b, b => c). We emit this as "Move b, c; Move a, b". This only requires
- // scratch registers if there are memory->memory moves. We want to find as many of these as
- // possible because they are cheaper. Note that shifts can involve the same source mentioned
- // multiple times. Example: (a => b, a => c, b => d, b => e).
- //
- // - Rotate. Example: (a => b, b => a). We want to emit this as "Swap a, b", but that instruction
- // may not be available, in which case we may need a scratch register or a scratch memory
- // location. A gnarlier example is (a => b, b => c, c => a). We can emit this as "Swap b, c;
- // Swap a, b". Note that swapping has to be careful about differing widths.
- //
- // Note that a rotate can have "fringe". For example, we might have (a => b, b => a, a =>c,
- // b => d). This has a rotate loop (a => b, b => a) and some fringe (a => c, b => d). We treat
- // the whole thing as a single rotate.
- //
- // We will find multiple disjoint such operations. We can execute them in any order.
-
- // We interpret these as Moves that should be executed backwards. All shifts are keyed by their
- // starting source.
- HashMap<Arg, Vector<ShufflePair>> shifts;
-
- // We interpret these as Swaps over src()'s that should be executed backwards, i.e. for a list
- // of size 3 we would do "Swap list[1].src(), list[2].src(); Swap list[0].src(), list[1].src()".
- // Note that we actually can't do that if the widths don't match or other bad things happen.
- // But, prior to executing all of that, we need to execute the fringe: the shifts comming off the
- // rotate.
- Vector<Rotate> rotates;
-
- {
- HashMap<Arg, Vector<ShufflePair>> mapping;
- for (const ShufflePair& pair : pairs)
- mapping.add(pair.src(), Vector<ShufflePair>()).iterator->value.append(pair);
-
- Vector<ShufflePair> currentPairs;
-
- while (!mapping.isEmpty()) {
- ASSERT(currentPairs.isEmpty());
- Arg originalSrc = mapping.begin()->key;
- ASSERT(!shifts.contains(originalSrc));
- if (verbose)
- dataLog("Processing from ", originalSrc, "\n");
-
- GraphNodeWorklist<Arg> worklist;
- worklist.push(originalSrc);
- while (Arg src = worklist.pop()) {
- HashMap<Arg, Vector<ShufflePair>>::iterator iter = mapping.find(src);
- if (iter == mapping.end()) {
- // With a shift it's possible that we previously built the tail of this shift.
- // See if that's the case now.
- if (verbose)
- dataLog("Trying to append shift at ", src, "\n");
- currentPairs.appendVector(shifts.take(src));
- continue;
- }
- Vector<ShufflePair> pairs = WTFMove(iter->value);
- mapping.remove(iter);
-
- for (const ShufflePair& pair : pairs) {
- currentPairs.append(pair);
- ASSERT(pair.src() == src);
- worklist.push(pair.dst());
- }
- }
-
- ASSERT(currentPairs.size());
- ASSERT(currentPairs[0].src() == originalSrc);
-
- if (verbose)
- dataLog("currentPairs = ", listDump(currentPairs), "\n");
-
- bool isRotate = false;
- for (const ShufflePair& pair : currentPairs) {
- if (pair.dst() == originalSrc) {
- isRotate = true;
- break;
- }
- }
-
- if (isRotate) {
- if (verbose)
- dataLog("It's a rotate.\n");
- Rotate rotate;
-
- // The common case is that the rotate does not have fringe. The only way to
- // check for this is to examine the whole rotate.
- bool ok;
- if (currentPairs.last().dst() == originalSrc) {
- ok = true;
- for (unsigned i = currentPairs.size() - 1; i--;)
- ok &= currentPairs[i].dst() == currentPairs[i + 1].src();
- } else
- ok = false;
-
- if (ok)
- rotate.loop = WTFMove(currentPairs);
- else {
- // This is the slow path. The rotate has fringe.
-
- HashMap<Arg, ShufflePair> dstMapping;
- for (const ShufflePair& pair : currentPairs)
- dstMapping.add(pair.dst(), pair);
-
- ShufflePair pair = dstMapping.take(originalSrc);
- for (;;) {
- rotate.loop.append(pair);
-
- auto iter = dstMapping.find(pair.src());
- if (iter == dstMapping.end())
- break;
- pair = iter->value;
- dstMapping.remove(iter);
- }
-
- rotate.loop.reverse();
-
- // Make sure that the fringe appears in the same order as how it appeared in the
- // currentPairs, since that's the DFS order.
- for (const ShufflePair& pair : currentPairs) {
- // But of course we only include it if it's not in the loop.
- if (dstMapping.contains(pair.dst()))
- rotate.fringe.append(pair);
- }
- }
-
- // If the graph search terminates because we returned to the first source, then the
- // pair list has to have a very particular shape.
- for (unsigned i = rotate.loop.size() - 1; i--;)
- ASSERT(rotate.loop[i].dst() == rotate.loop[i + 1].src());
- rotates.append(WTFMove(rotate));
- currentPairs.resize(0);
- } else {
- if (verbose)
- dataLog("It's a shift.\n");
- shifts.add(originalSrc, WTFMove(currentPairs));
- }
- }
- }
-
- if (verbose) {
- dataLog("Shifts:\n");
- for (auto& entry : shifts)
- dataLog(" ", entry.key, ": ", listDump(entry.value), "\n");
- dataLog("Rotates:\n");
- for (auto& rotate : rotates)
- dataLog(" loop = ", listDump(rotate.loop), ", fringe = ", listDump(rotate.fringe), "\n");
- }
-
- // In the worst case, we need two scratch registers. The way we do this is that the client passes
- // us what scratch registers he happens to have laying around. We will need scratch registers in
- // the following cases:
- //
- // - Shuffle pairs where both src and dst refer to memory.
- // - Rotate when no Swap instruction is available.
- //
- // Lucky for us, we are guaranteed to have extra scratch registers anytime we have a Shift that
- // ends with a register. We search for such a register right now.
-
- auto moveForWidth = [&] (Arg::Width width) -> Opcode {
- switch (width) {
- case Arg::Width32:
- return type == Arg::GP ? Move32 : MoveFloat;
- case Arg::Width64:
- return type == Arg::GP ? Move : MoveDouble;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- }
- };
-
- Opcode conservativeMove = moveForWidth(Arg::conservativeWidth(type));
-
- // We will emit things in reverse. We maintain a list of packs of instructions, and then we emit
- // append them together in reverse (for example the thing at the end of resultPacks is placed
- // first). This is useful because the last thing we emit frees up its destination registers, so
- // it affects how we emit things before it.
- Vector<Vector<Inst>> resultPacks;
- Vector<Inst> result;
-
- auto commitResult = [&] () {
- resultPacks.append(WTFMove(result));
- };
-
- auto getScratch = [&] (unsigned index, Tmp possibleScratch) -> Tmp {
- if (scratches[index].isTmp())
- return scratches[index].tmp();
-
- if (!possibleScratch)
- return Tmp();
- result.append(Inst(conservativeMove, origin, possibleScratch, scratches[index]));
- return possibleScratch;
- };
-
- auto returnScratch = [&] (unsigned index, Tmp tmp) {
- if (Arg(tmp) != scratches[index])
- result.append(Inst(conservativeMove, origin, scratches[index], tmp));
- };
-
- auto handleShiftPair = [&] (const ShufflePair& pair, unsigned scratchIndex) {
- Opcode move = moveForWidth(pair.width());
-
- if (!isValidForm(move, pair.src().kind(), pair.dst().kind())) {
- Tmp scratch =
- getScratch(scratchIndex, findPossibleScratch(type, pair.src(), pair.dst()));
- RELEASE_ASSERT(scratch);
- if (isValidForm(move, pair.src().kind(), Arg::Tmp))
- result.append(Inst(moveForWidth(pair.width()), origin, pair.src(), scratch));
- else {
- ASSERT(pair.src().isSomeImm());
- ASSERT(move == Move32);
- result.append(Inst(Move, origin, Arg::bigImm(pair.src().value()), scratch));
- }
- result.append(Inst(moveForWidth(pair.width()), origin, scratch, pair.dst()));
- returnScratch(scratchIndex, scratch);
- return;
- }
-
- result.append(Inst(move, origin, pair.src(), pair.dst()));
- };
-
- auto handleShift = [&] (Vector<ShufflePair>& shift) {
- // FIXME: We could optimize the spill behavior of the shifter by checking if any of the
- // shifts need spills. If they do, then we could try to get a register out here. Note that
- // this may fail where the current strategy succeeds: out here we need a register that does
- // not interfere with any of the shifts, while the current strategy only needs to find a
- // scratch register that does not interfer with a particular shift. So, this optimization
- // will be opportunistic: if it succeeds, then the individual shifts can use that scratch,
- // otherwise they will do what they do now.
-
- for (unsigned i = shift.size(); i--;)
- handleShiftPair(shift[i], 0);
-
- Arg lastDst = shift.last().dst();
- if (lastDst.isTmp()) {
- for (Arg& scratch : scratches) {
- ASSERT(scratch != lastDst);
- if (!scratch.isTmp()) {
- scratch = lastDst;
- break;
- }
- }
- }
- };
-
- // First handle shifts whose last destination is a tmp because these free up scratch registers.
- // These end up last in the final sequence, so the final destination of these shifts will be
- // available as a scratch location for anything emitted prior (so, after, since we're emitting in
- // reverse).
- for (auto& entry : shifts) {
- Vector<ShufflePair>& shift = entry.value;
- if (shift.last().dst().isTmp())
- handleShift(shift);
- commitResult();
- }
-
- // Now handle the rest of the shifts.
- for (auto& entry : shifts) {
- Vector<ShufflePair>& shift = entry.value;
- if (!shift.last().dst().isTmp())
- handleShift(shift);
- commitResult();
- }
-
- for (Rotate& rotate : rotates) {
- if (!rotate.fringe.isEmpty()) {
- // Make sure we do the fringe first! This won't clobber any of the registers that are
- // part of the rotation.
- handleShift(rotate.fringe);
- }
-
- bool canSwap = false;
- Opcode swap = Oops;
- Arg::Width swapWidth = Arg::Width8; // bogus value
-
- // Currently, the swap instruction is not available for floating point on any architecture we
- // support.
- if (type == Arg::GP) {
- // Figure out whether we will be doing 64-bit swaps or 32-bit swaps. If we have a mix of
- // widths we handle that by fixing up the relevant register with zero-extends.
- swap = Swap32;
- swapWidth = Arg::Width32;
- bool hasMemory = false;
- bool hasIndex = false;
- for (ShufflePair& pair : rotate.loop) {
- switch (pair.width()) {
- case Arg::Width32:
- break;
- case Arg::Width64:
- swap = Swap64;
- swapWidth = Arg::Width64;
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
-
- hasMemory |= pair.src().isMemory() || pair.dst().isMemory();
- hasIndex |= pair.src().isIndex() || pair.dst().isIndex();
- }
-
- canSwap = isValidForm(swap, Arg::Tmp, Arg::Tmp);
-
- // We can totally use swaps even if there are shuffles involving memory. But, we play it
- // safe in that case. There are corner cases we don't handle, and our ability to do it is
- // contingent upon swap form availability.
-
- if (hasMemory) {
- canSwap &= isValidForm(swap, Arg::Tmp, Arg::Addr);
-
- // We don't take the swapping path if there is a mix of widths and some of the
- // shuffles involve memory. That gets too confusing. We might be able to relax this
- // to only bail if there are subwidth pairs involving memory, but I haven't thought
- // about it very hard. Anyway, this case is not common: rotates involving memory
- // don't arise for function calls, and they will only happen for rotates in user code
- // if some of the variables get spilled. It's hard to imagine a program that rotates
- // data around in variables while also doing a combination of uint32->uint64 and
- // int64->int32 casts.
- for (ShufflePair& pair : rotate.loop)
- canSwap &= pair.width() == swapWidth;
- }
-
- if (hasIndex)
- canSwap &= isValidForm(swap, Arg::Tmp, Arg::Index);
- }
-
- if (canSwap) {
- for (unsigned i = rotate.loop.size() - 1; i--;) {
- Arg left = rotate.loop[i].src();
- Arg right = rotate.loop[i + 1].src();
-
- if (left.isMemory() && right.isMemory()) {
- // Note that this is a super rare outcome. Rotates are rare. Spills are rare.
- // Moving data between two spills is rare. To get here a lot of rare stuff has to
- // all happen at once.
-
- Tmp scratch = getScratch(0, findPossibleScratch(type, left, right));
- RELEASE_ASSERT(scratch);
- result.append(Inst(moveForWidth(swapWidth), origin, left, scratch));
- result.append(Inst(swap, origin, scratch, right));
- result.append(Inst(moveForWidth(swapWidth), origin, scratch, left));
- returnScratch(0, scratch);
- continue;
- }
-
- if (left.isMemory())
- std::swap(left, right);
-
- result.append(Inst(swap, origin, left, right));
- }
-
- for (ShufflePair pair : rotate.loop) {
- if (pair.width() == swapWidth)
- continue;
-
- RELEASE_ASSERT(pair.width() == Arg::Width32);
- RELEASE_ASSERT(swapWidth == Arg::Width64);
- RELEASE_ASSERT(pair.dst().isTmp());
-
- // Need to do an extra zero extension.
- result.append(Inst(Move32, origin, pair.dst(), pair.dst()));
- }
- } else {
- // We can treat this as a shift so long as we take the last destination (i.e. first
- // source) and save it first. Then we handle the first entry in the pair in the rotate
- // specially, after we restore the last destination. This requires some special care to
- // find a scratch register. It's possible that we have a rotate that uses the entire
- // available register file.
-
- Tmp scratch = findPossibleScratch(
- type,
- [&] (Tmp tmp) -> bool {
- for (ShufflePair pair : rotate.loop) {
- if (pair.src().usesTmp(tmp))
- return false;
- if (pair.dst().usesTmp(tmp))
- return false;
- }
- return true;
- });
-
- // NOTE: This is the most likely use of scratch registers.
- scratch = getScratch(0, scratch);
-
- // We may not have found a scratch register. When this happens, we can just use the spill
- // slot directly.
- Arg rotateSave = scratch ? Arg(scratch) : scratches[0];
-
- handleShiftPair(
- ShufflePair(rotate.loop.last().dst(), rotateSave, rotate.loop[0].width()), 1);
-
- for (unsigned i = rotate.loop.size(); i-- > 1;)
- handleShiftPair(rotate.loop[i], 1);
-
- handleShiftPair(
- ShufflePair(rotateSave, rotate.loop[0].dst(), rotate.loop[0].width()), 1);
-
- if (scratch)
- returnScratch(0, scratch);
- }
-
- commitResult();
- }
-
- ASSERT(result.isEmpty());
-
- for (unsigned i = resultPacks.size(); i--;)
- result.appendVector(resultPacks[i]);
-
- return result;
-}
-
-Vector<Inst> emitShuffle(
- const Vector<ShufflePair>& pairs,
- const std::array<Arg, 2>& gpScratch, const std::array<Arg, 2>& fpScratch,
- Value* origin)
-{
- Vector<ShufflePair> gpPairs;
- Vector<ShufflePair> fpPairs;
- for (const ShufflePair& pair : pairs) {
- if (pair.src().isMemory() && pair.dst().isMemory() && pair.width() > Arg::pointerWidth()) {
- // 8-byte memory-to-memory moves on a 32-bit platform are best handled as float moves.
- fpPairs.append(pair);
- } else if (pair.src().isGP() && pair.dst().isGP()) {
- // This means that gpPairs gets memory-to-memory shuffles. The assumption is that we
- // can do that more efficiently using GPRs, except in the special case above.
- gpPairs.append(pair);
- } else
- fpPairs.append(pair);
- }
-
- Vector<Inst> result;
- result.appendVector(emitShuffle(gpPairs, gpScratch, Arg::GP, origin));
- result.appendVector(emitShuffle(fpPairs, fpScratch, Arg::FP, origin));
- return result;
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirEmitShuffle.h b/Source/JavaScriptCore/b3/air/AirEmitShuffle.h
deleted file mode 100644
index f4ac0d27a..000000000
--- a/Source/JavaScriptCore/b3/air/AirEmitShuffle.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef AirEmitShuffle_h
-#define AirEmitShuffle_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirArg.h"
-#include "AirInst.h"
-#include <wtf/Vector.h>
-
-namespace JSC { namespace B3 {
-
-class Value;
-
-namespace Air {
-
-class ShufflePair {
-public:
- ShufflePair()
- {
- }
-
- ShufflePair(const Arg& src, const Arg& dst, Arg::Width width)
- : m_src(src)
- , m_dst(dst)
- , m_width(width)
- {
- }
-
- const Arg& src() const { return m_src; }
- const Arg& dst() const { return m_dst; }
-
- // The width determines the kind of move we do. You can only choose Width32 or Width64 right now.
- // For GP, it picks between Move32 and Move. For FP, it picks between MoveFloat and MoveDouble.
- Arg::Width width() const { return m_width; }
-
- void dump(PrintStream&) const;
-
-private:
- Arg m_src;
- Arg m_dst;
- Arg::Width m_width { Arg::Width8 };
-};
-
-// Create a Shuffle instruction.
-Inst createShuffle(Value* origin, const Vector<ShufflePair>&);
-
-// Perform a shuffle of a given type. The scratch argument is mandatory. You should pass it as
-// follows: If you know that you have scratch registers or temporaries available - that is, they're
-// registers that are not mentioned in the shuffle, have the same type as the shuffle, and are not
-// live at the shuffle - then you can pass them. If you don't have scratch registers available or if
-// you don't feel like looking for them, you can pass memory locations. It's always safe to pass a
-// pair of memory locations, and replacing either memory location with a register can be viewed as an
-// optimization. It's a pretty important optimization. Some more notes:
-//
-// - We define scratch registers as things that are not live before the shuffle and are not one of
-// the destinations of the shuffle. Not being live before the shuffle also means that they cannot
-// be used for any of the sources of the shuffle.
-//
-// - A second scratch location is only needed when you have shuffle pairs where memory is used both
-// as source and destination.
-//
-// - You're guaranteed not to need any scratch locations if there is a Swap instruction available for
-// the type and you don't have any memory locations that are both the source and the destination of
-// some pairs. GP supports Swap on x86 while FP never supports Swap.
-//
-// - Passing memory locations as scratch if are running emitShuffle() before register allocation is
-// silly, since that will cause emitShuffle() to pick some specific registers when it does need
-// scratch. One easy way to avoid that predicament is to ensure that you call emitShuffle() after
-// register allocation. For this reason we could add a Shuffle instruction so that we can defer
-// shufflings until after regalloc.
-//
-// - Shuffles with memory=>memory pairs are not very well tuned. You should avoid them if you want
-// performance. If you need to do them, then making sure that you reserve a temporary is one way to
-// get acceptable performance.
-//
-// NOTE: Use this method (and its friend below) to emit shuffles after register allocation. Before
-// register allocation it is much better to simply use the Shuffle instruction.
-Vector<Inst> emitShuffle(
- Vector<ShufflePair>, std::array<Arg, 2> scratch, Arg::Type, Value* origin);
-
-// Perform a shuffle that involves any number of types. Pass scratch registers or memory locations
-// for each type according to the rules above.
-Vector<Inst> emitShuffle(
- const Vector<ShufflePair>&,
- const std::array<Arg, 2>& gpScratch, const std::array<Arg, 2>& fpScratch,
- Value* origin);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirEmitShuffle_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirFixObviousSpills.cpp b/Source/JavaScriptCore/b3/air/AirFixObviousSpills.cpp
deleted file mode 100644
index dc01103b9..000000000
--- a/Source/JavaScriptCore/b3/air/AirFixObviousSpills.cpp
+++ /dev/null
@@ -1,532 +0,0 @@
-/*
- * Copyright (C) 2016 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 "AirFixObviousSpills.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include "AirPhaseScope.h"
-#include "B3IndexMap.h"
-#include <wtf/ListDump.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-namespace {
-
-bool verbose = false;
-
-class FixObviousSpills {
-public:
- FixObviousSpills(Code& code)
- : m_code(code)
- , m_atHead(code.size())
- {
- }
-
- void run()
- {
- if (verbose)
- dataLog("Code before fixObviousSpills:\n", m_code);
-
- computeAliases();
- fixCode();
- }
-
-private:
- void computeAliases()
- {
- m_atHead[m_code[0]].wasVisited = true;
-
- bool changed = true;
- while (changed) {
- changed = false;
-
- for (BasicBlock* block : m_code) {
- m_block = block;
- m_state = m_atHead[block];
- if (!m_state.wasVisited)
- continue;
-
- if (verbose)
- dataLog("Executing block ", *m_block, ": ", m_state, "\n");
-
- for (m_instIndex = 0; m_instIndex < block->size(); ++m_instIndex)
- executeInst();
-
- for (BasicBlock* successor : block->successorBlocks()) {
- State& toState = m_atHead[successor];
- if (toState.wasVisited)
- changed |= toState.merge(m_state);
- else {
- toState = m_state;
- changed = true;
- }
- }
- }
- }
- }
-
- void fixCode()
- {
- for (BasicBlock* block : m_code) {
- m_block = block;
- m_state = m_atHead[block];
- RELEASE_ASSERT(m_state.wasVisited);
-
- for (m_instIndex = 0; m_instIndex < block->size(); ++m_instIndex) {
- fixInst();
- executeInst();
- }
- }
- }
-
- void executeInst()
- {
- Inst& inst = m_block->at(m_instIndex);
-
- if (verbose)
- dataLog(" Executing ", inst, ": ", m_state, "\n");
-
- Inst::forEachDefWithExtraClobberedRegs<Arg>(
- &inst, &inst,
- [&] (const Arg& arg, Arg::Role, Arg::Type, Arg::Width) {
- if (verbose)
- dataLog(" Clobbering ", arg, "\n");
- m_state.clobber(arg);
- });
-
- switch (inst.opcode) {
- case Move:
- if (inst.args[0].isSomeImm()) {
- if (inst.args[1].isReg())
- m_state.addAlias(RegConst(inst.args[1].reg(), inst.args[0].value()));
- else if (isSpillSlot(inst.args[1]))
- m_state.addAlias(SlotConst(inst.args[1].stackSlot(), inst.args[0].value()));
- } else if (isSpillSlot(inst.args[0]) && inst.args[1].isReg()) {
- if (Optional<int64_t> constant = m_state.constantFor(inst.args[0]))
- m_state.addAlias(RegConst(inst.args[1].reg(), *constant));
- m_state.addAlias(
- RegSlot(inst.args[1].reg(), inst.args[0].stackSlot(), RegSlot::AllBits));
- } else if (inst.args[0].isReg() && isSpillSlot(inst.args[1])) {
- if (Optional<int64_t> constant = m_state.constantFor(inst.args[0]))
- m_state.addAlias(SlotConst(inst.args[1].stackSlot(), *constant));
- m_state.addAlias(
- RegSlot(inst.args[0].reg(), inst.args[1].stackSlot(), RegSlot::AllBits));
- }
- break;
-
- case Move32:
- if (inst.args[0].isSomeImm()) {
- if (inst.args[1].isReg())
- m_state.addAlias(RegConst(inst.args[1].reg(), static_cast<uint32_t>(inst.args[0].value())));
- else if (isSpillSlot(inst.args[1]))
- m_state.addAlias(SlotConst(inst.args[1].stackSlot(), static_cast<uint32_t>(inst.args[0].value())));
- } else if (isSpillSlot(inst.args[0]) && inst.args[1].isReg()) {
- if (Optional<int64_t> constant = m_state.constantFor(inst.args[0]))
- m_state.addAlias(RegConst(inst.args[1].reg(), static_cast<uint32_t>(*constant)));
- m_state.addAlias(
- RegSlot(inst.args[1].reg(), inst.args[0].stackSlot(), RegSlot::ZExt32));
- } else if (inst.args[0].isReg() && isSpillSlot(inst.args[1])) {
- if (Optional<int64_t> constant = m_state.constantFor(inst.args[0]))
- m_state.addAlias(SlotConst(inst.args[1].stackSlot(), static_cast<int32_t>(*constant)));
- m_state.addAlias(
- RegSlot(inst.args[0].reg(), inst.args[1].stackSlot(), RegSlot::Match32));
- }
- break;
-
- case MoveFloat:
- if (isSpillSlot(inst.args[0]) && inst.args[1].isReg()) {
- m_state.addAlias(
- RegSlot(inst.args[1].reg(), inst.args[0].stackSlot(), RegSlot::Match32));
- } else if (inst.args[0].isReg() && isSpillSlot(inst.args[1])) {
- m_state.addAlias(
- RegSlot(inst.args[0].reg(), inst.args[1].stackSlot(), RegSlot::Match32));
- }
- break;
-
- case MoveDouble:
- if (isSpillSlot(inst.args[0]) && inst.args[1].isReg()) {
- m_state.addAlias(
- RegSlot(inst.args[1].reg(), inst.args[0].stackSlot(), RegSlot::AllBits));
- } else if (inst.args[0].isReg() && isSpillSlot(inst.args[1])) {
- m_state.addAlias(
- RegSlot(inst.args[0].reg(), inst.args[1].stackSlot(), RegSlot::AllBits));
- }
- break;
-
- default:
- break;
- }
- }
-
- void fixInst()
- {
- Inst& inst = m_block->at(m_instIndex);
-
- if (verbose)
- dataLog("Fixing inst ", inst, ": ", m_state, "\n");
-
- // Create a copy in case we invalidate the instruction. That doesn't happen often.
- Inst instCopy = inst;
-
- // The goal is to replace references to stack slots. We only care about early uses. We can't
- // handle UseDefs. We could teach this to handle UseDefs if we inserted a store instruction
- // after and we proved that the register aliased to the stack slot dies here. We can get that
- // information from the liveness analysis. We also can't handle late uses, because we don't
- // look at late clobbers when doing this.
- bool didThings = false;
- auto handleArg = [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width width) {
- if (!isSpillSlot(arg))
- return;
- if (!Arg::isEarlyUse(role))
- return;
- if (Arg::isAnyDef(role))
- return;
-
- // Try to get a register if at all possible.
- if (const RegSlot* alias = m_state.getRegSlot(arg.stackSlot())) {
- switch (width) {
- case Arg::Width64:
- if (alias->mode != RegSlot::AllBits)
- return;
- if (verbose)
- dataLog(" Replacing ", arg, " with ", alias->reg, "\n");
- arg = Tmp(alias->reg);
- didThings = true;
- return;
- case Arg::Width32:
- if (verbose)
- dataLog(" Replacing ", arg, " with ", alias->reg, " (subwidth case)\n");
- arg = Tmp(alias->reg);
- didThings = true;
- return;
- default:
- return;
- }
- }
-
- // Revert to immediate if that didn't work.
- if (const SlotConst* alias = m_state.getSlotConst(arg.stackSlot())) {
- if (verbose)
- dataLog(" Replacing ", arg, " with constant ", alias->constant, "\n");
- if (Arg::isValidImmForm(alias->constant))
- arg = Arg::imm(alias->constant);
- else
- arg = Arg::bigImm(alias->constant);
- didThings = true;
- return;
- }
- };
-
- inst.forEachArg(handleArg);
- if (!didThings || inst.isValidForm())
- return;
-
- // We introduced something invalid along the way. Back up and carefully handle each argument.
- inst = instCopy;
- ASSERT(inst.isValidForm());
- inst.forEachArg(
- [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) {
- Arg argCopy = arg;
- handleArg(arg, role, type, width);
- if (!inst.isValidForm())
- arg = argCopy;
- });
- }
-
- static bool isSpillSlot(const Arg& arg)
- {
- return arg.isStack() && arg.stackSlot()->isSpill();
- }
-
- struct RegConst {
- RegConst()
- {
- }
-
- RegConst(Reg reg, int64_t constant)
- : reg(reg)
- , constant(constant)
- {
- }
-
- explicit operator bool() const
- {
- return !!reg;
- }
-
- void dump(PrintStream& out) const
- {
- out.print(reg, "->", constant);
- }
-
- Reg reg;
- int64_t constant { 0 };
- };
-
- struct RegSlot {
- enum Mode : int8_t {
- AllBits,
- ZExt32, // Register contains zero-extended contents of stack slot.
- Match32 // Low 32 bits of register match low 32 bits of stack slot.
- };
-
- RegSlot()
- {
- }
-
- RegSlot(Reg reg, StackSlot* slot, Mode mode)
- : slot(slot)
- , reg(reg)
- , mode(mode)
- {
- }
-
- explicit operator bool() const
- {
- return slot && reg;
- }
-
- void dump(PrintStream& out) const
- {
- out.print(pointerDump(slot), "->", reg);
- switch (mode) {
- case AllBits:
- out.print("(AllBits)");
- break;
- case ZExt32:
- out.print("(ZExt32)");
- break;
- case Match32:
- out.print("(Match32)");
- break;
- }
- }
-
- StackSlot* slot { nullptr };
- Reg reg;
- Mode mode { AllBits };
- };
-
- struct SlotConst {
- SlotConst()
- {
- }
-
- SlotConst(StackSlot* slot, int64_t constant)
- : slot(slot)
- , constant(constant)
- {
- }
-
- explicit operator bool() const
- {
- return slot;
- }
-
- void dump(PrintStream& out) const
- {
- out.print(pointerDump(slot), "->", constant);
- }
-
- StackSlot* slot { nullptr };
- int64_t constant { 0 };
- };
-
- struct State {
- void addAlias(const RegConst& newAlias)
- {
- regConst.append(newAlias);
- }
- void addAlias(const RegSlot& newAlias)
- {
- regSlot.append(newAlias);
- }
- void addAlias(const SlotConst& newAlias)
- {
- slotConst.append(newAlias);
- }
-
- const RegConst* getRegConst(Reg reg) const
- {
- for (const RegConst& alias : regConst) {
- if (alias.reg == reg)
- return &alias;
- }
- return nullptr;
- }
-
- const RegSlot* getRegSlot(Reg reg) const
- {
- for (const RegSlot& alias : regSlot) {
- if (alias.reg == reg)
- return &alias;
- }
- return nullptr;
- }
-
- const RegSlot* getRegSlot(StackSlot* slot) const
- {
- for (const RegSlot& alias : regSlot) {
- if (alias.slot == slot)
- return &alias;
- }
- return nullptr;
- }
-
- const RegSlot* getRegSlot(Reg reg, StackSlot* slot) const
- {
- for (const RegSlot& alias : regSlot) {
- if (alias.reg == reg && alias.slot == slot)
- return &alias;
- }
- return nullptr;
- }
-
- const SlotConst* getSlotConst(StackSlot* slot) const
- {
- for (const SlotConst& alias : slotConst) {
- if (alias.slot == slot)
- return &alias;
- }
- return nullptr;
- }
-
- Optional<int64_t> constantFor(const Arg& arg)
- {
- if (arg.isReg()) {
- if (const RegConst* alias = getRegConst(arg.reg()))
- return alias->constant;
- return Nullopt;
- }
- if (arg.isStack()) {
- if (const SlotConst* alias = getSlotConst(arg.stackSlot()))
- return alias->constant;
- return Nullopt;
- }
- return Nullopt;
- }
-
- void clobber(const Arg& arg)
- {
- if (arg.isReg()) {
- regConst.removeAllMatching(
- [&] (const RegConst& alias) -> bool {
- return alias.reg == arg.reg();
- });
- regSlot.removeAllMatching(
- [&] (const RegSlot& alias) -> bool {
- return alias.reg == arg.reg();
- });
- return;
- }
- if (arg.isStack()) {
- slotConst.removeAllMatching(
- [&] (const SlotConst& alias) -> bool {
- return alias.slot == arg.stackSlot();
- });
- regSlot.removeAllMatching(
- [&] (const RegSlot& alias) -> bool {
- return alias.slot == arg.stackSlot();
- });
- }
- }
-
- bool merge(const State& other)
- {
- bool changed = false;
-
- changed |= !!regConst.removeAllMatching(
- [&] (RegConst& alias) -> bool {
- const RegConst* otherAlias = other.getRegConst(alias.reg);
- if (!otherAlias)
- return true;
- if (alias.constant != otherAlias->constant)
- return true;
- return false;
- });
-
- changed |= !!slotConst.removeAllMatching(
- [&] (SlotConst& alias) -> bool {
- const SlotConst* otherAlias = other.getSlotConst(alias.slot);
- if (!otherAlias)
- return true;
- if (alias.constant != otherAlias->constant)
- return true;
- return false;
- });
-
- changed |= !!regSlot.removeAllMatching(
- [&] (RegSlot& alias) -> bool {
- const RegSlot* otherAlias = other.getRegSlot(alias.reg, alias.slot);
- if (!otherAlias)
- return true;
- if (alias.mode != RegSlot::Match32 && alias.mode != otherAlias->mode) {
- alias.mode = RegSlot::Match32;
- changed = true;
- }
- return false;
- });
-
- return changed;
- }
-
- void dump(PrintStream& out) const
- {
- out.print(
- "{regConst = [", listDump(regConst), "], slotConst = [", listDump(slotConst),
- "], regSlot = [", listDump(regSlot), "], wasVisited = ", wasVisited, "}");
- }
-
- Vector<RegConst> regConst;
- Vector<SlotConst> slotConst;
- Vector<RegSlot> regSlot;
- bool wasVisited { false };
- };
-
- Code& m_code;
- IndexMap<BasicBlock, State> m_atHead;
- State m_state;
- BasicBlock* m_block { nullptr };
- unsigned m_instIndex { 0 };
-};
-
-} // anonymous namespace
-
-void fixObviousSpills(Code& code)
-{
- PhaseScope phaseScope(code, "fixObviousSpills");
-
- FixObviousSpills fixObviousSpills(code);
- fixObviousSpills.run();
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirFixObviousSpills.h b/Source/JavaScriptCore/b3/air/AirFixObviousSpills.h
deleted file mode 100644
index 92b1d2a01..000000000
--- a/Source/JavaScriptCore/b3/air/AirFixObviousSpills.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef AirFixObviousSpills_h
-#define AirFixObviousSpills_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// This is a forward flow phase that tracks equivalence between spills slots and registers. It
-// removes loads from spill slots in cases when the contents of the spill slot can be found in (or
-// computed from) a register.
-void fixObviousSpills(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirFixObviousSpills_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp b/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp
deleted file mode 100644
index c3640d60f..000000000
--- a/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.cpp
+++ /dev/null
@@ -1,237 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirFixPartialRegisterStalls.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirBasicBlock.h"
-#include "AirCode.h"
-#include "AirInsertionSet.h"
-#include "AirInst.h"
-#include "AirInstInlines.h"
-#include "AirPhaseScope.h"
-#include "B3IndexMap.h"
-#include "B3IndexSet.h"
-#include "MacroAssembler.h"
-#include <wtf/Vector.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-namespace {
-
-bool hasPartialXmmRegUpdate(const Inst& inst)
-{
- switch (inst.opcode) {
- case ConvertDoubleToFloat:
- case ConvertFloatToDouble:
- case ConvertInt32ToDouble:
- case ConvertInt64ToDouble:
- case SqrtDouble:
- case SqrtFloat:
- case CeilDouble:
- case CeilFloat:
- case FloorDouble:
- case FloorFloat:
- return true;
- default:
- break;
- }
- return false;
-}
-
-bool isDependencyBreaking(const Inst& inst)
-{
- // "xorps reg, reg" is used by the frontend to remove the dependency on its argument.
- return inst.opcode == MoveZeroToDouble;
-}
-
-// FIXME: find a good distance per architecture experimentally.
-// LLVM uses a distance of 16 but that comes from Nehalem.
-unsigned char minimumSafeDistance = 16;
-
-struct FPDefDistance {
- FPDefDistance()
- {
- for (unsigned i = 0; i < MacroAssembler::numberOfFPRegisters(); ++i)
- distance[i] = 255;
- }
-
- void reset(FPRReg reg)
- {
- unsigned index = MacroAssembler::fpRegisterIndex(reg);
- distance[index] = 255;
- }
-
- void add(FPRReg reg, unsigned registerDistance)
- {
- unsigned index = MacroAssembler::fpRegisterIndex(reg);
- if (registerDistance < distance[index])
- distance[index] = static_cast<unsigned char>(registerDistance);
- }
-
- bool updateFromPrecessor(FPDefDistance& precessorDistance, unsigned constantOffset = 0)
- {
- bool changed = false;
- for (unsigned i = 0; i < MacroAssembler::numberOfFPRegisters(); ++i) {
- unsigned regDistance = precessorDistance.distance[i] + constantOffset;
- if (regDistance < minimumSafeDistance && regDistance < distance[i]) {
- distance[i] = regDistance;
- changed = true;
- }
- }
- return changed;
- }
-
- unsigned char distance[MacroAssembler::numberOfFPRegisters()];
-};
-
-void updateDistances(Inst& inst, FPDefDistance& localDistance, unsigned& distanceToBlockEnd)
-{
- --distanceToBlockEnd;
-
- if (isDependencyBreaking(inst)) {
- localDistance.reset(inst.args[0].tmp().fpr());
- return;
- }
-
- inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) {
- ASSERT_WITH_MESSAGE(tmp.isReg(), "This phase must be run after register allocation.");
-
- if (tmp.isFPR() && Arg::isAnyDef(role))
- localDistance.add(tmp.fpr(), distanceToBlockEnd);
- });
-}
-
-}
-
-void fixPartialRegisterStalls(Code& code)
-{
- if (!isX86())
- return;
-
- PhaseScope phaseScope(code, "fixPartialRegisterStalls");
-
- Vector<BasicBlock*> candidates;
-
- for (BasicBlock* block : code) {
- for (const Inst& inst : *block) {
- if (hasPartialXmmRegUpdate(inst)) {
- candidates.append(block);
- break;
- }
- }
- }
-
- // Fortunately, Partial Stalls are rarely used. Return early if no block
- // cares about them.
- if (candidates.isEmpty())
- return;
-
- // For each block, this provides the distance to the last instruction setting each register
- // on block *entry*.
- IndexMap<BasicBlock, FPDefDistance> lastDefDistance(code.size());
-
- // Blocks with dirty distance at head.
- IndexSet<BasicBlock> dirty;
-
- // First, we compute the local distance for each block and push it to the successors.
- for (BasicBlock* block : code) {
- FPDefDistance localDistance;
-
- unsigned distanceToBlockEnd = block->size();
- for (Inst& inst : *block)
- updateDistances(inst, localDistance, distanceToBlockEnd);
-
- for (BasicBlock* successor : block->successorBlocks()) {
- if (lastDefDistance[successor].updateFromPrecessor(localDistance))
- dirty.add(successor);
- }
- }
-
- // Now we propagate the minimums accross blocks.
- bool changed;
- do {
- changed = false;
-
- for (BasicBlock* block : code) {
- if (!dirty.remove(block))
- continue;
-
- // Little shortcut: if the block is big enough, propagating it won't add any information.
- if (block->size() >= minimumSafeDistance)
- continue;
-
- unsigned blockSize = block->size();
- FPDefDistance& blockDistance = lastDefDistance[block];
- for (BasicBlock* successor : block->successorBlocks()) {
- if (lastDefDistance[successor].updateFromPrecessor(blockDistance, blockSize)) {
- dirty.add(successor);
- changed = true;
- }
- }
- }
- } while (changed);
-
- // Finally, update each block as needed.
- InsertionSet insertionSet(code);
- for (BasicBlock* block : candidates) {
- unsigned distanceToBlockEnd = block->size();
- FPDefDistance& localDistance = lastDefDistance[block];
-
- for (unsigned i = 0; i < block->size(); ++i) {
- Inst& inst = block->at(i);
-
- if (hasPartialXmmRegUpdate(inst)) {
- RegisterSet defs;
- RegisterSet uses;
- inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type, Arg::Width) {
- if (tmp.isFPR()) {
- if (Arg::isAnyDef(role))
- defs.set(tmp.fpr());
- if (Arg::isAnyUse(role))
- uses.set(tmp.fpr());
- }
- });
- // We only care about values we define but not use. Otherwise we have to wait
- // for the value to be resolved anyway.
- defs.exclude(uses);
-
- defs.forEach([&] (Reg reg) {
- if (localDistance.distance[MacroAssembler::fpRegisterIndex(reg.fpr())] < minimumSafeDistance)
- insertionSet.insert(i, MoveZeroToDouble, inst.origin, Tmp(reg));
- });
- }
-
- updateDistances(inst, localDistance, distanceToBlockEnd);
- }
- insertionSet.execute(block);
- }
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.h b/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.h
deleted file mode 100644
index 32ea6890b..000000000
--- a/Source/JavaScriptCore/b3/air/AirFixPartialRegisterStalls.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirFixPartialRegisterStalls_h
-#define AirFixPartialRegisterStalls_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// x86 has a pipelining hazard caused by false dependencies between instructions.
-//
-// Some instructions update only part of a register, they can only be scheduled after
-// the previous definition is computed. This problem can be avoided by the compiler
-// by explicitely resetting the entire register before executing the instruction with
-// partial update.
-//
-// See "Partial XMM Register Stalls" and "Dependency Breaking Idioms" in the manual.
-void fixPartialRegisterStalls(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirFixPartialRegisterStalls_h
diff --git a/Source/JavaScriptCore/b3/air/AirFrequentedBlock.h b/Source/JavaScriptCore/b3/air/AirFrequentedBlock.h
deleted file mode 100644
index f4317d255..000000000
--- a/Source/JavaScriptCore/b3/air/AirFrequentedBlock.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirFrequentedBlock_h
-#define AirFrequentedBlock_h
-
-#if ENABLE(B3_JIT)
-
-#include "B3GenericFrequentedBlock.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-class BasicBlock;
-
-typedef GenericFrequentedBlock<BasicBlock> FrequentedBlock;
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirFrequentedBlock_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirGenerate.cpp b/Source/JavaScriptCore/b3/air/AirGenerate.cpp
deleted file mode 100644
index 5dca75212..000000000
--- a/Source/JavaScriptCore/b3/air/AirGenerate.cpp
+++ /dev/null
@@ -1,248 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirGenerate.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirAllocateStack.h"
-#include "AirCode.h"
-#include "AirEliminateDeadCode.h"
-#include "AirFixObviousSpills.h"
-#include "AirFixPartialRegisterStalls.h"
-#include "AirGenerationContext.h"
-#include "AirHandleCalleeSaves.h"
-#include "AirIteratedRegisterCoalescing.h"
-#include "AirLogRegisterPressure.h"
-#include "AirLowerAfterRegAlloc.h"
-#include "AirLowerMacros.h"
-#include "AirOpcodeUtils.h"
-#include "AirOptimizeBlockOrder.h"
-#include "AirReportUsedRegisters.h"
-#include "AirSimplifyCFG.h"
-#include "AirSpillEverything.h"
-#include "AirValidate.h"
-#include "B3Common.h"
-#include "B3IndexMap.h"
-#include "B3Procedure.h"
-#include "B3TimingScope.h"
-#include "CCallHelpers.h"
-#include "DisallowMacroScratchRegisterUsage.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-void prepareForGeneration(Code& code)
-{
- TimingScope timingScope("Air::prepareForGeneration");
-
- // We don't expect the incoming code to have predecessors computed.
- code.resetReachability();
-
- if (shouldValidateIR())
- validate(code);
-
- // If we're doing super verbose dumping, the phase scope of any phase will already do a dump.
- if (shouldDumpIR(AirMode) && !shouldDumpIRAtEachPhase(AirMode)) {
- dataLog("Initial air:\n");
- dataLog(code);
- }
-
- lowerMacros(code);
-
- // This is where we run our optimizations and transformations.
- // FIXME: Add Air optimizations.
- // https://bugs.webkit.org/show_bug.cgi?id=150456
-
- eliminateDeadCode(code);
-
- // Register allocation for all the Tmps that do not have a corresponding machine register.
- // After this phase, every Tmp has a reg.
- //
- // For debugging, you can use spillEverything() to put everything to the stack between each Inst.
- if (Options::airSpillsEverything())
- spillEverything(code);
- else
- iteratedRegisterCoalescing(code);
-
- if (Options::logAirRegisterPressure()) {
- dataLog("Register pressure after register allocation:\n");
- logRegisterPressure(code);
- }
-
- // This replaces uses of spill slots with registers or constants if possible. It does this by
- // minimizing the amount that we perturb the already-chosen register allocation. It may extend
- // the live ranges of registers though.
- fixObviousSpills(code);
-
- lowerAfterRegAlloc(code);
-
- // Prior to this point the prologue and epilogue is implicit. This makes it explicit. It also
- // does things like identify which callee-saves we're using and saves them.
- handleCalleeSaves(code);
-
- // This turns all Stack and CallArg Args into Addr args that use the frame pointer. It does
- // this by first-fit allocating stack slots. It should be pretty darn close to optimal, so we
- // shouldn't have to worry about this very much.
- allocateStack(code);
-
- // If we coalesced moves then we can unbreak critical edges. This is the main reason for this
- // phase.
- simplifyCFG(code);
-
- // This sorts the basic blocks in Code to achieve an ordering that maximizes the likelihood that a high
- // frequency successor is also the fall-through target.
- optimizeBlockOrder(code);
-
- // This is needed to satisfy a requirement of B3::StackmapValue.
- reportUsedRegisters(code);
-
- // Attempt to remove false dependencies between instructions created by partial register changes.
- // This must be executed as late as possible as it depends on the instructions order and register
- // use. We _must_ run this after reportUsedRegisters(), since that kills variable assignments
- // that seem dead. Luckily, this phase does not change register liveness, so that's OK.
- fixPartialRegisterStalls(code);
-
- if (shouldValidateIR())
- validate(code);
-
- // Do a final dump of Air. Note that we have to do this even if we are doing per-phase dumping,
- // since the final generation is not a phase.
- if (shouldDumpIR(AirMode)) {
- dataLog("Air after ", code.lastPhaseName(), ", before generation:\n");
- dataLog(code);
- }
-}
-
-void generate(Code& code, CCallHelpers& jit)
-{
- TimingScope timingScope("Air::generate");
-
- DisallowMacroScratchRegisterUsage disallowScratch(jit);
-
- // And now, we generate code.
- jit.emitFunctionPrologue();
- if (code.frameSize())
- jit.addPtr(CCallHelpers::TrustedImm32(-code.frameSize()), MacroAssembler::stackPointerRegister);
-
- auto argFor = [&] (const RegisterAtOffset& entry) -> CCallHelpers::Address {
- return CCallHelpers::Address(GPRInfo::callFrameRegister, entry.offset());
- };
-
- for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
- if (entry.reg().isGPR())
- jit.storePtr(entry.reg().gpr(), argFor(entry));
- else
- jit.storeDouble(entry.reg().fpr(), argFor(entry));
- }
-
- GenerationContext context;
- context.code = &code;
- IndexMap<BasicBlock, CCallHelpers::Label> blockLabels(code.size());
- IndexMap<BasicBlock, CCallHelpers::JumpList> blockJumps(code.size());
-
- auto link = [&] (CCallHelpers::Jump jump, BasicBlock* target) {
- if (blockLabels[target].isSet()) {
- jump.linkTo(blockLabels[target], &jit);
- return;
- }
-
- blockJumps[target].append(jump);
- };
-
- PCToOriginMap& pcToOriginMap = code.proc().pcToOriginMap();
- auto addItem = [&] (Inst& inst) {
- if (!inst.origin) {
- pcToOriginMap.appendItem(jit.label(), Origin());
- return;
- }
- pcToOriginMap.appendItem(jit.label(), inst.origin->origin());
- };
-
- for (BasicBlock* block : code) {
- blockJumps[block].link(&jit);
- blockLabels[block] = jit.label();
- ASSERT(block->size() >= 1);
- for (unsigned i = 0; i < block->size() - 1; ++i) {
- Inst& inst = block->at(i);
- addItem(inst);
- CCallHelpers::Jump jump = inst.generate(jit, context);
- ASSERT_UNUSED(jump, !jump.isSet());
- }
-
- if (block->last().opcode == Jump
- && block->successorBlock(0) == code.findNextBlock(block))
- continue;
-
- addItem(block->last());
-
- if (isReturn(block->last().opcode)) {
- // We currently don't represent the full prologue/epilogue in Air, so we need to
- // have this override.
- if (code.frameSize()) {
- for (const RegisterAtOffset& entry : code.calleeSaveRegisters()) {
- if (entry.reg().isGPR())
- jit.loadPtr(argFor(entry), entry.reg().gpr());
- else
- jit.loadDouble(argFor(entry), entry.reg().fpr());
- }
- jit.emitFunctionEpilogue();
- } else
- jit.emitFunctionEpilogueWithEmptyFrame();
- jit.ret();
- addItem(block->last());
- continue;
- }
-
- CCallHelpers::Jump jump = block->last().generate(jit, context);
- switch (block->numSuccessors()) {
- case 0:
- ASSERT(!jump.isSet());
- break;
- case 1:
- link(jump, block->successorBlock(0));
- break;
- case 2:
- link(jump, block->successorBlock(0));
- if (block->successorBlock(1) != code.findNextBlock(block))
- link(jit.jump(), block->successorBlock(1));
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
- addItem(block->last());
- }
-
- pcToOriginMap.appendItem(jit.label(), Origin());
- // FIXME: Make late paths have Origins: https://bugs.webkit.org/show_bug.cgi?id=153689
- for (auto& latePath : context.latePaths)
- latePath->run(jit, context);
- pcToOriginMap.appendItem(jit.label(), Origin());
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirGenerate.h b/Source/JavaScriptCore/b3/air/AirGenerate.h
deleted file mode 100644
index e4c2aeec1..000000000
--- a/Source/JavaScriptCore/b3/air/AirGenerate.h
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirGenerate_h
-#define AirGenerate_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC {
-
-class CCallHelpers;
-
-namespace B3 { namespace Air {
-
-class Code;
-
-// This takes an Air::Code that hasn't had any stack allocation and optionally hasn't had any
-// register allocation and does both of those things.
-JS_EXPORT_PRIVATE void prepareForGeneration(Code&);
-
-// This generates the code using the given CCallHelpers instance. Note that this may call callbacks
-// in the supplied code as it is generating.
-JS_EXPORT_PRIVATE void generate(Code&, CCallHelpers&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirGenerate_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirGenerated.cpp b/Source/JavaScriptCore/b3/air/AirGenerated.cpp
deleted file mode 100644
index 6dd2304a9..000000000
--- a/Source/JavaScriptCore/b3/air/AirGenerated.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * 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"
-
-#if ENABLE(B3_JIT)
-
-// This is generated by opcode_generator.rb.
-#include "AirOpcodeGenerated.h"
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirGenerationContext.h b/Source/JavaScriptCore/b3/air/AirGenerationContext.h
deleted file mode 100644
index 50f75e17d..000000000
--- a/Source/JavaScriptCore/b3/air/AirGenerationContext.h
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirGenerationContext_h
-#define AirGenerationContext_h
-
-#if ENABLE(B3_JIT)
-
-#include <wtf/SharedTask.h>
-#include <wtf/Vector.h>
-
-namespace JSC {
-
-class CCallHelpers;
-
-namespace B3 { namespace Air {
-
-class Code;
-
-struct GenerationContext {
- typedef void LatePathFunction(CCallHelpers&, GenerationContext&);
- typedef SharedTask<LatePathFunction> LatePath;
-
- Vector<RefPtr<LatePath>> latePaths;
- Code* code;
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirGenerationContext_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.cpp b/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.cpp
deleted file mode 100644
index 90b226764..000000000
--- a/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.cpp
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirHandleCalleeSaves.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include "AirPhaseScope.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-void handleCalleeSaves(Code& code)
-{
- PhaseScope phaseScope(code, "handleCalleeSaves");
-
- RegisterSet usedCalleeSaves;
-
- for (BasicBlock* block : code) {
- for (Inst& inst : *block) {
- inst.forEachTmpFast(
- [&] (Tmp& tmp) {
- // At first we just record all used regs.
- usedCalleeSaves.set(tmp.reg());
- });
-
- if (inst.opcode == Patch)
- usedCalleeSaves.merge(inst.extraClobberedRegs());
- }
- }
-
- // Now we filter to really get the callee saves.
- usedCalleeSaves.filter(RegisterSet::calleeSaveRegisters());
- usedCalleeSaves.exclude(RegisterSet::stackRegisters()); // We don't need to save FP here.
-
- if (!usedCalleeSaves.numberOfSetRegisters())
- return;
-
- code.calleeSaveRegisters() = RegisterAtOffsetList(usedCalleeSaves);
-
- size_t byteSize = 0;
- for (const RegisterAtOffset& entry : code.calleeSaveRegisters())
- byteSize = std::max(static_cast<size_t>(-entry.offset()), byteSize);
-
- StackSlot* savesArea = code.addStackSlot(byteSize, StackSlotKind::Locked);
- // This is a bit weird since we could have already pinned a different stack slot to this
- // area. Also, our runtime does not require us to pin the saves area. Maybe we shouldn't pin it?
- savesArea->setOffsetFromFP(-byteSize);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.h b/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.h
deleted file mode 100644
index 422229944..000000000
--- a/Source/JavaScriptCore/b3/air/AirHandleCalleeSaves.h
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirHandleCalleeSaves_h
-#define AirHandleCalleeSaves_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// This phase identifies callee-save registers and adds code to save/restore them in the
-// prologue/epilogue to the code. It's a mandatory phase.
-
-// FIXME: It would be cool to make this more interactive with the Air client and also more
-// powerful.
-// We should have shrink wrapping: https://bugs.webkit.org/show_bug.cgi?id=150458
-// We should make this interact with the client: https://bugs.webkit.org/show_bug.cgi?id=150459
-
-void handleCalleeSaves(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirHandleCalleeSaves_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirInsertionSet.cpp b/Source/JavaScriptCore/b3/air/AirInsertionSet.cpp
deleted file mode 100644
index 90891e3f7..000000000
--- a/Source/JavaScriptCore/b3/air/AirInsertionSet.cpp
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirInsertionSet.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirBasicBlock.h"
-#include <wtf/BubbleSort.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-void InsertionSet::insertInsts(size_t index, const Vector<Inst>& insts)
-{
- for (const Inst& inst : insts)
- insertInst(index, inst);
-}
-
-void InsertionSet::insertInsts(size_t index, Vector<Inst>&& insts)
-{
- for (Inst& inst : insts)
- insertInst(index, WTFMove(inst));
-}
-
-void InsertionSet::execute(BasicBlock* block)
-{
- bubbleSort(m_insertions.begin(), m_insertions.end());
- executeInsertions(block->m_insts, m_insertions);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirInsertionSet.h b/Source/JavaScriptCore/b3/air/AirInsertionSet.h
deleted file mode 100644
index cabafb71c..000000000
--- a/Source/JavaScriptCore/b3/air/AirInsertionSet.h
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirInsertionSet_h
-#define AirInsertionSet_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirInst.h"
-#include <wtf/Insertion.h>
-#include <wtf/Vector.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-class BasicBlock;
-class Code;
-
-typedef WTF::Insertion<Inst> Insertion;
-
-class InsertionSet {
-public:
- InsertionSet(Code& code)
- : m_code(code)
- {
- }
-
- Code& code() { return m_code; }
-
- template<typename T>
- void appendInsertion(T&& insertion)
- {
- m_insertions.append(std::forward<T>(insertion));
- }
-
- template<typename Inst>
- void insertInst(size_t index, Inst&& inst)
- {
- appendInsertion(Insertion(index, std::forward<Inst>(inst)));
- }
-
- void insertInsts(size_t index, const Vector<Inst>&);
- void insertInsts(size_t index, Vector<Inst>&&);
-
- template<typename... Arguments>
- void insert(size_t index, Arguments&&... arguments)
- {
- insertInst(index, Inst(std::forward<Arguments>(arguments)...));
- }
-
- void execute(BasicBlock*);
-
-private:
- Code& m_code;
- Vector<Insertion, 8> m_insertions;
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirInsertionSet_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirInst.cpp b/Source/JavaScriptCore/b3/air/AirInst.cpp
deleted file mode 100644
index 297e50dfc..000000000
--- a/Source/JavaScriptCore/b3/air/AirInst.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirInst.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirInstInlines.h"
-#include "B3Value.h"
-#include <wtf/ListDump.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-bool Inst::hasArgEffects()
-{
- bool result = false;
- forEachArg(
- [&] (Arg&, Arg::Role role, Arg::Type, Arg::Width) {
- if (Arg::isAnyDef(role))
- result = true;
- });
- return result;
-}
-
-void Inst::dump(PrintStream& out) const
-{
- out.print(opcode, " ", listDump(args));
- if (origin) {
- if (args.size())
- out.print(", ");
- out.print(*origin);
- }
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirInst.h b/Source/JavaScriptCore/b3/air/AirInst.h
deleted file mode 100644
index 88e5df7dd..000000000
--- a/Source/JavaScriptCore/b3/air/AirInst.h
+++ /dev/null
@@ -1,203 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirInst_h
-#define AirInst_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirArg.h"
-#include "AirOpcode.h"
-#include "CCallHelpers.h"
-
-namespace JSC {
-
-class CCallHelpers;
-class RegisterSet;
-
-namespace B3 {
-
-class Value;
-
-namespace Air {
-
-struct GenerationContext;
-
-struct Inst {
-public:
- typedef Vector<Arg, 3> ArgList;
-
- Inst()
- : origin(nullptr)
- , opcode(Nop)
- {
- }
-
- Inst(Opcode opcode, Value* origin)
- : origin(origin)
- , opcode(opcode)
- {
- }
-
- template<typename... Arguments>
- Inst(Opcode opcode, Value* origin, Arg arg, Arguments... arguments)
- : args{ arg, arguments... }
- , origin(origin)
- , opcode(opcode)
- {
- }
-
- Inst(Opcode opcode, Value* origin, const ArgList& arguments)
- : args(arguments)
- , origin(origin)
- , opcode(opcode)
- {
- }
-
- Inst(Opcode opcode, Value* origin, ArgList&& arguments)
- : args(WTFMove(arguments))
- , origin(origin)
- , opcode(opcode)
- {
- }
-
- explicit operator bool() const { return origin || opcode != Nop || args.size(); }
-
- void append() { }
-
- template<typename... Arguments>
- void append(Arg arg, Arguments... arguments)
- {
- args.append(arg);
- append(arguments...);
- }
-
- // Note that these functors all avoid using "const" because we want to use them for things that
- // edit IR. IR is meant to be edited; if you're carrying around a "const Inst&" then you're
- // probably doing it wrong.
-
- // This only walks those Tmps that are explicitly mentioned, and it doesn't tell you their role
- // or type.
- template<typename Functor>
- void forEachTmpFast(const Functor& functor)
- {
- for (Arg& arg : args)
- arg.forEachTmpFast(functor);
- }
-
- typedef void EachArgCallback(Arg&, Arg::Role, Arg::Type, Arg::Width);
-
- // Calls the functor with (arg, role, type, width). This function is auto-generated by
- // opcode_generator.rb.
- template<typename Functor>
- void forEachArg(const Functor&);
-
- // Calls the functor with (tmp, role, type, width).
- template<typename Functor>
- void forEachTmp(const Functor& functor)
- {
- forEachArg(
- [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) {
- arg.forEachTmp(role, type, width, functor);
- });
- }
-
- // Thing can be either Arg, Tmp, or StackSlot*.
- template<typename Thing, typename Functor>
- void forEach(const Functor&);
-
- // Reports any additional registers clobbered by this operation. Note that for efficiency,
- // extraClobberedRegs() only works for the Patch opcode.
- const RegisterSet& extraClobberedRegs();
- const RegisterSet& extraEarlyClobberedRegs();
-
- // Iterate over all Def's that happen at the end of an instruction. You supply a pair
- // instructions. The instructions must appear next to each other, in that order, in some basic
- // block. You can pass null for the first instruction when analyzing what happens at the top of
- // a basic block. You can pass null for the second instruction when analyzing what happens at the
- // bottom of a basic block.
- template<typename Thing, typename Functor>
- static void forEachDef(Inst* prevInst, Inst* nextInst, const Functor&);
-
- // Iterate over all Def's that happen at the end of this instruction, including extra clobbered
- // registers. Note that Thing can only be Arg or Tmp when you use this functor.
- template<typename Thing, typename Functor>
- static void forEachDefWithExtraClobberedRegs(Inst* prevInst, Inst* nextInst, const Functor&);
-
- // Use this to report which registers are live. This should be done just before codegen. Note
- // that for efficiency, reportUsedRegisters() only works for the Patch opcode.
- void reportUsedRegisters(const RegisterSet&);
-
- // Is this instruction in one of the valid forms right now? This function is auto-generated by
- // opcode_generator.rb.
- bool isValidForm();
-
- // Assuming this instruction is in a valid form right now, will it still be in one of the valid
- // forms if we put an Addr referencing the stack (or a StackSlot or CallArg, of course) in the
- // given index? Spilling uses this: it walks the args by index to find Tmps that need spilling;
- // if it finds one, it calls this to see if it can replace the Arg::Tmp with an Arg::Addr. If it
- // finds a non-Tmp Arg, then it calls that Arg's forEachTmp to do a replacement that way.
- //
- // This function is auto-generated by opcode_generator.rb.
- bool admitsStack(unsigned argIndex);
- bool admitsStack(Arg&);
-
- // Returns true if this instruction can have any effects other than control flow or arguments.
- bool hasNonArgNonControlEffects();
-
- // Returns true if this instruction can have any effects other than what is implied by arguments.
- // For example, "Move $42, (%rax)" will return false because the effect of storing to (%rax) is
- // implied by the second argument.
- bool hasNonArgEffects();
-
- // Tells you if this operation has arg effects.
- bool hasArgEffects();
-
- // Generate some code for this instruction. This is, like, literally our backend. If this is the
- // terminal, it returns the jump that needs to be linked for the "then" case, with the "else"
- // case being fall-through. This function is auto-generated by opcode_generator.rb.
- CCallHelpers::Jump generate(CCallHelpers&, GenerationContext&);
-
- // If source arguments benefits from being aliased to a destination argument,
- // this return the index of the destination argument.
- // The source are assumed to be at (index - 1) and (index - 2)
- // For example,
- // Add Tmp1, Tmp2, Tmp3
- // returns 2 if 0 and 1 benefit from aliasing to Tmp3.
- Optional<unsigned> shouldTryAliasingDef();
-
- void dump(PrintStream&) const;
-
- ArgList args;
- Value* origin; // The B3::Value that this originated from.
- Opcode opcode;
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirInst_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirInstInlines.h b/Source/JavaScriptCore/b3/air/AirInstInlines.h
deleted file mode 100644
index 990d930d0..000000000
--- a/Source/JavaScriptCore/b3/air/AirInstInlines.h
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirInstInlines_h
-#define AirInstInlines_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirInst.h"
-#include "AirOpcodeUtils.h"
-#include "AirSpecial.h"
-#include "AirStackSlot.h"
-#include "B3Value.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-template<typename T> struct ForEach;
-template<> struct ForEach<Tmp> {
- template<typename Functor>
- static void forEach(Inst& inst, const Functor& functor)
- {
- inst.forEachTmp(functor);
- }
-};
-
-template<> struct ForEach<Arg> {
- template<typename Functor>
- static void forEach(Inst& inst, const Functor& functor)
- {
- inst.forEachArg(functor);
- }
-};
-
-template<> struct ForEach<StackSlot*> {
- template<typename Functor>
- static void forEach(Inst& inst, const Functor& functor)
- {
- inst.forEachArg(
- [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) {
- if (!arg.isStack())
- return;
- StackSlot* stackSlot = arg.stackSlot();
-
- // FIXME: This is way too optimistic about the meaning of "Def". It gets lucky for
- // now because our only use of "Anonymous" stack slots happens to want the optimistic
- // semantics. We could fix this by just changing the comments that describe the
- // semantics of "Anonymous".
- // https://bugs.webkit.org/show_bug.cgi?id=151128
-
- functor(stackSlot, role, type, width);
- arg = Arg::stack(stackSlot, arg.offset());
- });
- }
-};
-
-template<> struct ForEach<Reg> {
- template<typename Functor>
- static void forEach(Inst& inst, const Functor& functor)
- {
- inst.forEachTmp(
- [&] (Tmp& tmp, Arg::Role role, Arg::Type type, Arg::Width width) {
- if (!tmp.isReg())
- return;
-
- Reg reg = tmp.reg();
- functor(reg, role, type, width);
- tmp = Tmp(reg);
- });
- }
-};
-
-template<typename Thing, typename Functor>
-void Inst::forEach(const Functor& functor)
-{
- ForEach<Thing>::forEach(*this, functor);
-}
-
-inline const RegisterSet& Inst::extraClobberedRegs()
-{
- ASSERT(opcode == Patch);
- return args[0].special()->extraClobberedRegs(*this);
-}
-
-inline const RegisterSet& Inst::extraEarlyClobberedRegs()
-{
- ASSERT(opcode == Patch);
- return args[0].special()->extraEarlyClobberedRegs(*this);
-}
-
-template<typename Thing, typename Functor>
-inline void Inst::forEachDef(Inst* prevInst, Inst* nextInst, const Functor& functor)
-{
- if (prevInst) {
- prevInst->forEach<Thing>(
- [&] (Thing& thing, Arg::Role role, Arg::Type argType, Arg::Width argWidth) {
- if (Arg::isLateDef(role))
- functor(thing, role, argType, argWidth);
- });
- }
-
- if (nextInst) {
- nextInst->forEach<Thing>(
- [&] (Thing& thing, Arg::Role role, Arg::Type argType, Arg::Width argWidth) {
- if (Arg::isEarlyDef(role))
- functor(thing, role, argType, argWidth);
- });
- }
-}
-
-template<typename Thing, typename Functor>
-inline void Inst::forEachDefWithExtraClobberedRegs(
- Inst* prevInst, Inst* nextInst, const Functor& functor)
-{
- forEachDef<Thing>(prevInst, nextInst, functor);
-
- Arg::Role regDefRole;
-
- auto reportReg = [&] (Reg reg) {
- Arg::Type type = reg.isGPR() ? Arg::GP : Arg::FP;
- functor(Thing(reg), regDefRole, type, Arg::conservativeWidth(type));
- };
-
- if (prevInst && prevInst->opcode == Patch) {
- regDefRole = Arg::Def;
- prevInst->extraClobberedRegs().forEach(reportReg);
- }
-
- if (nextInst && nextInst->opcode == Patch) {
- regDefRole = Arg::EarlyDef;
- nextInst->extraEarlyClobberedRegs().forEach(reportReg);
- }
-}
-
-inline void Inst::reportUsedRegisters(const RegisterSet& usedRegisters)
-{
- ASSERT(opcode == Patch);
- args[0].special()->reportUsedRegisters(*this, usedRegisters);
-}
-
-inline bool Inst::admitsStack(Arg& arg)
-{
- return admitsStack(&arg - &args[0]);
-}
-
-inline Optional<unsigned> Inst::shouldTryAliasingDef()
-{
- if (!isX86())
- return Nullopt;
-
- switch (opcode) {
- case Add32:
- case Add64:
- case And32:
- case And64:
- case Mul32:
- case Mul64:
- case Or32:
- case Or64:
- case Xor32:
- case Xor64:
- case AddDouble:
- case AddFloat:
- case AndFloat:
- case AndDouble:
- case MulDouble:
- case MulFloat:
- case XorDouble:
- case XorFloat:
- if (args.size() == 3)
- return 2;
- break;
- case BranchAdd32:
- case BranchAdd64:
- if (args.size() == 4)
- return 3;
- break;
- case MoveConditionally32:
- case MoveConditionally64:
- case MoveConditionallyTest32:
- case MoveConditionallyTest64:
- case MoveConditionallyDouble:
- case MoveConditionallyFloat:
- case MoveDoubleConditionally32:
- case MoveDoubleConditionally64:
- case MoveDoubleConditionallyTest32:
- case MoveDoubleConditionallyTest64:
- case MoveDoubleConditionallyDouble:
- case MoveDoubleConditionallyFloat:
- if (args.size() == 6)
- return 5;
- break;
- break;
- case Patch:
- return PatchCustom::shouldTryAliasingDef(*this);
- default:
- break;
- }
- return Nullopt;
-}
-
-inline bool isShiftValid(const Inst& inst)
-{
-#if CPU(X86) || CPU(X86_64)
- return inst.args[0] == Tmp(X86Registers::ecx);
-#else
- UNUSED_PARAM(inst);
- return true;
-#endif
-}
-
-inline bool isLshift32Valid(const Inst& inst)
-{
- return isShiftValid(inst);
-}
-
-inline bool isLshift64Valid(const Inst& inst)
-{
- return isShiftValid(inst);
-}
-
-inline bool isRshift32Valid(const Inst& inst)
-{
- return isShiftValid(inst);
-}
-
-inline bool isRshift64Valid(const Inst& inst)
-{
- return isShiftValid(inst);
-}
-
-inline bool isUrshift32Valid(const Inst& inst)
-{
- return isShiftValid(inst);
-}
-
-inline bool isUrshift64Valid(const Inst& inst)
-{
- return isShiftValid(inst);
-}
-
-inline bool isX86DivHelperValid(const Inst& inst)
-{
-#if CPU(X86) || CPU(X86_64)
- return inst.args[0] == Tmp(X86Registers::eax)
- && inst.args[1] == Tmp(X86Registers::edx);
-#else
- UNUSED_PARAM(inst);
- return false;
-#endif
-}
-
-inline bool isX86ConvertToDoubleWord32Valid(const Inst& inst)
-{
- return isX86DivHelperValid(inst);
-}
-
-inline bool isX86ConvertToQuadWord64Valid(const Inst& inst)
-{
- return isX86DivHelperValid(inst);
-}
-
-inline bool isX86Div32Valid(const Inst& inst)
-{
- return isX86DivHelperValid(inst);
-}
-
-inline bool isX86Div64Valid(const Inst& inst)
-{
- return isX86DivHelperValid(inst);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirInstInlines_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp b/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp
deleted file mode 100644
index 9f9fe8145..000000000
--- a/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.cpp
+++ /dev/null
@@ -1,1542 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirIteratedRegisterCoalescing.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInsertionSet.h"
-#include "AirInstInlines.h"
-#include "AirLiveness.h"
-#include "AirPhaseScope.h"
-#include "AirRegisterPriority.h"
-#include "AirTmpInlines.h"
-#include "AirTmpWidth.h"
-#include "AirUseCounts.h"
-#include <wtf/ListDump.h>
-#include <wtf/ListHashSet.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-namespace {
-
-bool debug = false;
-bool traceDebug = false;
-bool reportStats = false;
-
-// The AbstractColoringAllocator defines all the code that is independant
-// from the type or register and can be shared when allocating registers.
-template<typename IndexType>
-class AbstractColoringAllocator {
-public:
- AbstractColoringAllocator(const Vector<Reg>& regsInPriorityOrder, IndexType lastPrecoloredRegisterIndex, unsigned tmpArraySize, const HashSet<unsigned>& unspillableTmp)
- : m_regsInPriorityOrder(regsInPriorityOrder)
- , m_lastPrecoloredRegisterIndex(lastPrecoloredRegisterIndex)
- , m_unspillableTmps(unspillableTmp)
- {
- initializeDegrees(tmpArraySize);
-
- m_adjacencyList.resize(tmpArraySize);
- m_moveList.resize(tmpArraySize);
- m_coalescedTmps.fill(0, tmpArraySize);
- m_isOnSelectStack.ensureSize(tmpArraySize);
- }
-
-protected:
- IndexType getAlias(IndexType tmpIndex) const
- {
- IndexType alias = tmpIndex;
- while (IndexType nextAlias = m_coalescedTmps[alias])
- alias = nextAlias;
- return alias;
- }
-
- void addEdge(IndexType a, IndexType b)
- {
- if (a == b)
- return;
- addEdgeDistinct(a, b);
- }
-
- void makeWorkList()
- {
- IndexType firstNonRegIndex = m_lastPrecoloredRegisterIndex + 1;
- for (IndexType i = firstNonRegIndex; i < m_degrees.size(); ++i) {
- unsigned degree = m_degrees[i];
- if (!degree)
- continue;
-
- if (degree >= m_regsInPriorityOrder.size())
- addToSpill(i);
- else if (!m_moveList[i].isEmpty())
- m_freezeWorklist.add(i);
- else
- m_simplifyWorklist.append(i);
- }
- }
-
- void addToSpill(unsigned toSpill)
- {
- if (m_unspillableTmps.contains(toSpill))
- return;
-
- m_spillWorklist.add(toSpill);
- }
-
- // Low-degree vertex can always be colored: just pick any of the color taken by any
- // other adjacent verices.
- // The "Simplify" phase takes a low-degree out of the interference graph to simplify it.
- void simplify()
- {
- IndexType lastIndex = m_simplifyWorklist.takeLast();
-
- ASSERT(!m_selectStack.contains(lastIndex));
- ASSERT(!m_isOnSelectStack.get(lastIndex));
- m_selectStack.append(lastIndex);
- m_isOnSelectStack.quickSet(lastIndex);
-
- forEachAdjacent(lastIndex, [this](IndexType adjacentTmpIndex) {
- decrementDegree(adjacentTmpIndex);
- });
- }
-
- void freeze()
- {
- IndexType victimIndex = m_freezeWorklist.takeAny();
- ASSERT_WITH_MESSAGE(getAlias(victimIndex) == victimIndex, "coalesce() should not leave aliased Tmp in the worklist.");
- m_simplifyWorklist.append(victimIndex);
- freezeMoves(victimIndex);
- }
-
- void freezeMoves(IndexType tmpIndex)
- {
- forEachNodeMoves(tmpIndex, [this, tmpIndex] (IndexType moveIndex) {
- if (!m_activeMoves.quickClear(moveIndex))
- m_worklistMoves.takeMove(moveIndex);
-
- const MoveOperands& moveOperands = m_coalescingCandidates[moveIndex];
- IndexType srcTmpIndex = moveOperands.srcIndex;
- IndexType dstTmpIndex = moveOperands.dstIndex;
-
- IndexType originalOtherTmp = srcTmpIndex != tmpIndex ? srcTmpIndex : dstTmpIndex;
- IndexType otherTmpIndex = getAlias(originalOtherTmp);
- if (m_degrees[otherTmpIndex] < m_regsInPriorityOrder.size() && !isMoveRelated(otherTmpIndex)) {
- if (m_freezeWorklist.remove(otherTmpIndex))
- m_simplifyWorklist.append(otherTmpIndex);
- }
- });
- }
-
- void coalesce()
- {
- unsigned moveIndex = m_worklistMoves.takeLastMove();
- const MoveOperands& moveOperands = m_coalescingCandidates[moveIndex];
- IndexType u = getAlias(moveOperands.srcIndex);
- IndexType v = getAlias(moveOperands.dstIndex);
-
- if (isPrecolored(v))
- std::swap(u, v);
-
- if (traceDebug)
- dataLog("Coalescing move at index", moveIndex, " u = ", u, " v = ", v, "\n");
-
- if (u == v) {
- addWorkList(u);
-
- if (traceDebug)
- dataLog(" Coalesced\n");
- } else if (isPrecolored(v)
- || m_interferenceEdges.contains(InterferenceEdge(u, v))
- || (u == m_framePointerIndex && m_interferesWithFramePointer.quickGet(v))) {
- addWorkList(u);
- addWorkList(v);
-
- if (traceDebug)
- dataLog(" Constrained\n");
- } else if (canBeSafelyCoalesced(u, v)) {
- combine(u, v);
- addWorkList(u);
- m_hasCoalescedNonTrivialMove = true;
-
- if (traceDebug)
- dataLog(" Safe Coalescing\n");
- } else {
- m_activeMoves.quickSet(moveIndex);
-
- if (traceDebug)
- dataLog(" Failed coalescing, added to active moves.\n");
- }
- }
-
- void assignColors()
- {
- ASSERT(m_simplifyWorklist.isEmpty());
- ASSERT(m_worklistMoves.isEmpty());
- ASSERT(m_freezeWorklist.isEmpty());
- ASSERT(m_spillWorklist.isEmpty());
-
- // Reclaim as much memory as possible.
- m_interferenceEdges.clear();
- m_degrees.clear();
- m_moveList.clear();
- m_worklistMoves.clear();
- m_simplifyWorklist.clear();
- m_spillWorklist.clear();
- m_freezeWorklist.clear();
-
- // Try to color the Tmp on the stack.
- m_coloredTmp.resize(m_adjacencyList.size());
-
- while (!m_selectStack.isEmpty()) {
- unsigned tmpIndex = m_selectStack.takeLast();
- ASSERT(!isPrecolored(tmpIndex));
- ASSERT(!m_coloredTmp[tmpIndex]);
-
- RegisterSet coloredRegisters;
- for (IndexType adjacentTmpIndex : m_adjacencyList[tmpIndex]) {
- IndexType aliasTmpIndex = getAlias(adjacentTmpIndex);
- Reg reg = m_coloredTmp[aliasTmpIndex];
-
- ASSERT(!isPrecolored(aliasTmpIndex) || (isPrecolored(aliasTmpIndex) && reg));
-
- if (reg)
- coloredRegisters.set(reg);
- }
-
- bool colorAssigned = false;
- for (Reg reg : m_regsInPriorityOrder) {
- if (!coloredRegisters.get(reg)) {
- m_coloredTmp[tmpIndex] = reg;
- colorAssigned = true;
- break;
- }
- }
-
- if (!colorAssigned)
- m_spilledTmps.append(tmpIndex);
- }
- m_selectStack.clear();
-
- if (m_spilledTmps.isEmpty())
- m_coalescedTmpsAtSpill.clear();
- else
- m_coloredTmp.clear();
- }
-
-private:
- void initializeDegrees(unsigned tmpArraySize)
- {
- m_degrees.resize(tmpArraySize);
-
- // All precolored registers have an "infinite" degree.
- unsigned firstNonRegIndex = m_lastPrecoloredRegisterIndex + 1;
- for (unsigned i = 0; i < firstNonRegIndex; ++i)
- m_degrees[i] = std::numeric_limits<unsigned>::max();
-
- memset(m_degrees.data() + firstNonRegIndex, 0, (tmpArraySize - firstNonRegIndex) * sizeof(unsigned));
- }
-
- void addEdgeDistinct(IndexType a, IndexType b)
- {
- ASSERT(a != b);
- if (m_interferenceEdges.add(InterferenceEdge(a, b)).isNewEntry) {
- if (!isPrecolored(a)) {
- ASSERT(!m_adjacencyList[a].contains(b));
- m_adjacencyList[a].append(b);
- m_degrees[a]++;
- }
-
- if (!isPrecolored(b)) {
- ASSERT(!m_adjacencyList[b].contains(a));
- m_adjacencyList[b].append(a);
- m_degrees[b]++;
- }
- }
- }
-
- void decrementDegree(IndexType tmpIndex)
- {
- ASSERT(m_degrees[tmpIndex]);
-
- unsigned oldDegree = m_degrees[tmpIndex]--;
- if (oldDegree == m_regsInPriorityOrder.size()) {
- enableMovesOnValueAndAdjacents(tmpIndex);
- m_spillWorklist.remove(tmpIndex);
- if (isMoveRelated(tmpIndex))
- m_freezeWorklist.add(tmpIndex);
- else
- m_simplifyWorklist.append(tmpIndex);
- }
- }
-
-
- bool addEdgeDistinctWithoutDegreeChange(IndexType a, IndexType b)
- {
- ASSERT(a != b);
- if (m_interferenceEdges.add(InterferenceEdge(a, b)).isNewEntry) {
- if (!isPrecolored(a)) {
- ASSERT(!m_adjacencyList[a].contains(b));
- m_adjacencyList[a].append(b);
- }
-
- if (!isPrecolored(b)) {
- ASSERT(!m_adjacencyList[b].contains(a));
- m_adjacencyList[b].append(a);
- }
- return true;
- }
- return false;
- }
-
- bool isMoveRelated(IndexType tmpIndex)
- {
- for (unsigned moveIndex : m_moveList[tmpIndex]) {
- if (m_activeMoves.quickGet(moveIndex) || m_worklistMoves.contains(moveIndex))
- return true;
- }
- return false;
- }
-
- template<typename Function>
- void forEachAdjacent(IndexType tmpIndex, Function function)
- {
- for (IndexType adjacentTmpIndex : m_adjacencyList[tmpIndex]) {
- if (!hasBeenSimplified(adjacentTmpIndex))
- function(adjacentTmpIndex);
- }
- }
-
- bool hasBeenSimplified(IndexType tmpIndex)
- {
- return m_isOnSelectStack.quickGet(tmpIndex) || !!m_coalescedTmps[tmpIndex];
- }
-
- template<typename Function>
- void forEachNodeMoves(IndexType tmpIndex, Function function)
- {
- for (unsigned moveIndex : m_moveList[tmpIndex]) {
- if (m_activeMoves.quickGet(moveIndex) || m_worklistMoves.contains(moveIndex))
- function(moveIndex);
- }
- }
-
- void enableMovesOnValue(IndexType tmpIndex)
- {
- for (unsigned moveIndex : m_moveList[tmpIndex]) {
- if (m_activeMoves.quickClear(moveIndex))
- m_worklistMoves.returnMove(moveIndex);
- }
- }
-
- void enableMovesOnValueAndAdjacents(IndexType tmpIndex)
- {
- enableMovesOnValue(tmpIndex);
-
- forEachAdjacent(tmpIndex, [this] (IndexType adjacentTmpIndex) {
- enableMovesOnValue(adjacentTmpIndex);
- });
- }
-
- bool isPrecolored(IndexType tmpIndex)
- {
- return tmpIndex <= m_lastPrecoloredRegisterIndex;
- }
-
- void addWorkList(IndexType tmpIndex)
- {
- if (!isPrecolored(tmpIndex) && m_degrees[tmpIndex] < m_regsInPriorityOrder.size() && !isMoveRelated(tmpIndex)) {
- m_freezeWorklist.remove(tmpIndex);
- m_simplifyWorklist.append(tmpIndex);
- }
- }
-
- void combine(IndexType u, IndexType v)
- {
- if (!m_freezeWorklist.remove(v))
- m_spillWorklist.remove(v);
-
- ASSERT(!m_coalescedTmps[v]);
- m_coalescedTmps[v] = u;
-
- auto& vMoves = m_moveList[v];
- m_moveList[u].add(vMoves.begin(), vMoves.end());
-
- forEachAdjacent(v, [this, u] (IndexType adjacentTmpIndex) {
- if (addEdgeDistinctWithoutDegreeChange(adjacentTmpIndex, u)) {
- // If we added a new edge between the adjacentTmp and u, it replaces the edge
- // that existed with v.
- // The degree of adjacentTmp remains the same since the edge just changed from u to v.
- // All we need to do is update the degree of u.
- if (!isPrecolored(u))
- m_degrees[u]++;
- } else {
- // If we already had an edge between the adjacentTmp and u, the degree of u
- // is already correct. The degree of the adjacentTmp decreases since the edge
- // with v is no longer relevant (we can think of it as merged with the edge with u).
- decrementDegree(adjacentTmpIndex);
- }
- });
-
- if (m_framePointerIndex && m_interferesWithFramePointer.quickGet(v))
- m_interferesWithFramePointer.quickSet(u);
-
- if (m_degrees[u] >= m_regsInPriorityOrder.size() && m_freezeWorklist.remove(u))
- addToSpill(u);
- }
-
- bool canBeSafelyCoalesced(IndexType u, IndexType v)
- {
- ASSERT(!isPrecolored(v));
- if (isPrecolored(u))
- return precoloredCoalescingHeuristic(u, v);
- return conservativeHeuristic(u, v);
- }
-
- bool conservativeHeuristic(IndexType u, IndexType v)
- {
- // This is using the Briggs' conservative coalescing rule:
- // If the number of combined adjacent node with a degree >= K is less than K,
- // it is safe to combine the two nodes. The reason is that we know that if the graph
- // is colorable, we have fewer than K adjacents with high order and there is a color
- // for the current node.
- ASSERT(u != v);
- ASSERT(!isPrecolored(u));
- ASSERT(!isPrecolored(v));
-
- const auto& adjacentsOfU = m_adjacencyList[u];
- const auto& adjacentsOfV = m_adjacencyList[v];
-
- if (adjacentsOfU.size() + adjacentsOfV.size() < m_regsInPriorityOrder.size()) {
- // Shortcut: if the total number of adjacents is less than the number of register, the condition is always met.
- return true;
- }
-
- HashSet<IndexType> highOrderAdjacents;
-
- for (IndexType adjacentTmpIndex : adjacentsOfU) {
- ASSERT(adjacentTmpIndex != v);
- ASSERT(adjacentTmpIndex != u);
- if (!hasBeenSimplified(adjacentTmpIndex) && m_degrees[adjacentTmpIndex] >= m_regsInPriorityOrder.size()) {
- auto addResult = highOrderAdjacents.add(adjacentTmpIndex);
- if (addResult.isNewEntry && highOrderAdjacents.size() >= m_regsInPriorityOrder.size())
- return false;
- }
- }
- for (IndexType adjacentTmpIndex : adjacentsOfV) {
- ASSERT(adjacentTmpIndex != u);
- ASSERT(adjacentTmpIndex != v);
- if (!hasBeenSimplified(adjacentTmpIndex) && m_degrees[adjacentTmpIndex] >= m_regsInPriorityOrder.size()) {
- auto addResult = highOrderAdjacents.add(adjacentTmpIndex);
- if (addResult.isNewEntry && highOrderAdjacents.size() >= m_regsInPriorityOrder.size())
- return false;
- }
- }
-
- ASSERT(highOrderAdjacents.size() < m_regsInPriorityOrder.size());
- return true;
- }
-
- bool precoloredCoalescingHeuristic(IndexType u, IndexType v)
- {
- ASSERT(isPrecolored(u));
- ASSERT(!isPrecolored(v));
-
- // If any adjacent of the non-colored node is not an adjacent of the colored node AND has a degree >= K
- // there is a risk that this node needs to have the same color as our precolored node. If we coalesce such
- // move, we may create an uncolorable graph.
- const auto& adjacentsOfV = m_adjacencyList[v];
- for (unsigned adjacentTmpIndex : adjacentsOfV) {
- if (!isPrecolored(adjacentTmpIndex)
- && !hasBeenSimplified(adjacentTmpIndex)
- && m_degrees[adjacentTmpIndex] >= m_regsInPriorityOrder.size()
- && !m_interferenceEdges.contains(InterferenceEdge(u, adjacentTmpIndex)))
- return false;
- }
- return true;
- }
-
-protected:
-#if PLATFORM(COCOA)
-#pragma mark -
-#endif
-
- // Interference edges are not directed. An edge between any two Tmps is represented
- // by the concatenated values of the smallest Tmp followed by the bigger Tmp.
- class InterferenceEdge {
- public:
- InterferenceEdge()
- {
- }
-
- InterferenceEdge(IndexType a, IndexType b)
- {
- ASSERT(a);
- ASSERT(b);
- ASSERT_WITH_MESSAGE(a != b, "A Tmp can never interfere with itself. Doing so would force it to be the superposition of two registers.");
-
- if (b < a)
- std::swap(a, b);
- m_value = static_cast<uint64_t>(a) << 32 | b;
- }
-
- InterferenceEdge(WTF::HashTableDeletedValueType)
- : m_value(std::numeric_limits<uint64_t>::max())
- {
- }
-
- IndexType first() const
- {
- return m_value >> 32 & 0xffffffff;
- }
-
- IndexType second() const
- {
- return m_value & 0xffffffff;
- }
-
- bool operator==(const InterferenceEdge other) const
- {
- return m_value == other.m_value;
- }
-
- bool isHashTableDeletedValue() const
- {
- return *this == InterferenceEdge(WTF::HashTableDeletedValue);
- }
-
- unsigned hash() const
- {
- return WTF::IntHash<uint64_t>::hash(m_value);
- }
-
- void dump(PrintStream& out) const
- {
- out.print(first(), "<=>", second());
- }
-
- private:
- uint64_t m_value { 0 };
- };
-
- struct InterferenceEdgeHash {
- static unsigned hash(const InterferenceEdge& key) { return key.hash(); }
- static bool equal(const InterferenceEdge& a, const InterferenceEdge& b) { return a == b; }
- static const bool safeToCompareToEmptyOrDeleted = true;
- };
- typedef SimpleClassHashTraits<InterferenceEdge> InterferenceEdgeHashTraits;
-
- const Vector<Reg>& m_regsInPriorityOrder;
- IndexType m_lastPrecoloredRegisterIndex { 0 };
-
- // The interference graph.
- HashSet<InterferenceEdge, InterferenceEdgeHash, InterferenceEdgeHashTraits> m_interferenceEdges;
- Vector<Vector<IndexType, 0, UnsafeVectorOverflow, 4>, 0, UnsafeVectorOverflow> m_adjacencyList;
- Vector<IndexType, 0, UnsafeVectorOverflow> m_degrees;
-
- // Instead of keeping track of the move instructions, we just keep their operands around and use the index
- // in the vector as the "identifier" for the move.
- struct MoveOperands {
- IndexType srcIndex;
- IndexType dstIndex;
- };
- Vector<MoveOperands, 0, UnsafeVectorOverflow> m_coalescingCandidates;
-
- // List of every move instruction associated with a Tmp.
- Vector<HashSet<IndexType, typename DefaultHash<IndexType>::Hash, WTF::UnsignedWithZeroKeyHashTraits<IndexType>>> m_moveList;
-
- // Colors.
- Vector<Reg, 0, UnsafeVectorOverflow> m_coloredTmp;
- Vector<IndexType> m_spilledTmps;
-
- // Values that have been coalesced with an other value.
- Vector<IndexType, 0, UnsafeVectorOverflow> m_coalescedTmps;
-
- // The stack of Tmp removed from the graph and ready for coloring.
- BitVector m_isOnSelectStack;
- Vector<IndexType> m_selectStack;
-
- IndexType m_framePointerIndex { 0 };
- BitVector m_interferesWithFramePointer;
-
- struct OrderedMoveSet {
- unsigned addMove()
- {
- ASSERT(m_lowPriorityMoveList.isEmpty());
- ASSERT(!m_firstLowPriorityMoveIndex);
-
- unsigned nextIndex = m_positionInMoveList.size();
- unsigned position = m_moveList.size();
- m_moveList.append(nextIndex);
- m_positionInMoveList.append(position);
- return nextIndex;
- }
-
- void startAddingLowPriorityMoves()
- {
- ASSERT(m_lowPriorityMoveList.isEmpty());
- m_firstLowPriorityMoveIndex = m_moveList.size();
- }
-
- unsigned addLowPriorityMove()
- {
- ASSERT(m_firstLowPriorityMoveIndex == m_moveList.size());
-
- unsigned nextIndex = m_positionInMoveList.size();
- unsigned position = m_lowPriorityMoveList.size();
- m_lowPriorityMoveList.append(nextIndex);
- m_positionInMoveList.append(position);
-
- ASSERT(nextIndex >= m_firstLowPriorityMoveIndex);
-
- return nextIndex;
- }
-
- bool isEmpty() const
- {
- return m_moveList.isEmpty() && m_lowPriorityMoveList.isEmpty();
- }
-
- bool contains(unsigned index)
- {
- return m_positionInMoveList[index] != std::numeric_limits<unsigned>::max();
- }
-
- void takeMove(unsigned moveIndex)
- {
- unsigned positionInMoveList = m_positionInMoveList[moveIndex];
- if (positionInMoveList == std::numeric_limits<unsigned>::max())
- return;
-
- if (moveIndex < m_firstLowPriorityMoveIndex) {
- ASSERT(m_moveList[positionInMoveList] == moveIndex);
- unsigned lastIndex = m_moveList.last();
- m_positionInMoveList[lastIndex] = positionInMoveList;
- m_moveList[positionInMoveList] = lastIndex;
- m_moveList.removeLast();
- } else {
- ASSERT(m_lowPriorityMoveList[positionInMoveList] == moveIndex);
- unsigned lastIndex = m_lowPriorityMoveList.last();
- m_positionInMoveList[lastIndex] = positionInMoveList;
- m_lowPriorityMoveList[positionInMoveList] = lastIndex;
- m_lowPriorityMoveList.removeLast();
- }
-
- m_positionInMoveList[moveIndex] = std::numeric_limits<unsigned>::max();
-
- ASSERT(!contains(moveIndex));
- }
-
- unsigned takeLastMove()
- {
- ASSERT(!isEmpty());
-
- unsigned lastIndex;
- if (!m_moveList.isEmpty()) {
- lastIndex = m_moveList.takeLast();
- ASSERT(m_positionInMoveList[lastIndex] == m_moveList.size());
- } else {
- lastIndex = m_lowPriorityMoveList.takeLast();
- ASSERT(m_positionInMoveList[lastIndex] == m_lowPriorityMoveList.size());
- }
- m_positionInMoveList[lastIndex] = std::numeric_limits<unsigned>::max();
-
- ASSERT(!contains(lastIndex));
- return lastIndex;
- }
-
- void returnMove(unsigned index)
- {
- // This assertion is a bit strict but that is how the move list should be used. The only kind of moves that can
- // return to the list are the ones that we previously failed to coalesce with the conservative heuristics.
- // Values should not be added back if they were never taken out when attempting coalescing.
- ASSERT(!contains(index));
-
- if (index < m_firstLowPriorityMoveIndex) {
- unsigned position = m_moveList.size();
- m_moveList.append(index);
- m_positionInMoveList[index] = position;
- } else {
- unsigned position = m_lowPriorityMoveList.size();
- m_lowPriorityMoveList.append(index);
- m_positionInMoveList[index] = position;
- }
-
- ASSERT(contains(index));
- }
-
- void clear()
- {
- m_positionInMoveList.clear();
- m_moveList.clear();
- m_lowPriorityMoveList.clear();
- }
-
- private:
- Vector<unsigned, 0, UnsafeVectorOverflow> m_positionInMoveList;
- Vector<unsigned, 0, UnsafeVectorOverflow> m_moveList;
- Vector<unsigned, 0, UnsafeVectorOverflow> m_lowPriorityMoveList;
- unsigned m_firstLowPriorityMoveIndex { 0 };
- };
-
- // Work lists.
- // Set of "move" enabled for possible coalescing.
- OrderedMoveSet m_worklistMoves;
- // Set of "move" not yet ready for coalescing.
- BitVector m_activeMoves;
- // Low-degree, non-Move related.
- Vector<IndexType> m_simplifyWorklist;
- // High-degree Tmp.
- HashSet<IndexType> m_spillWorklist;
- // Low-degree, Move related.
- HashSet<IndexType> m_freezeWorklist;
-
- bool m_hasSelectedSpill { false };
- bool m_hasCoalescedNonTrivialMove { false };
-
- // The mapping of Tmp to their alias for Moves that are always coalescing regardless of spilling.
- Vector<IndexType, 0, UnsafeVectorOverflow> m_coalescedTmpsAtSpill;
-
- const HashSet<unsigned>& m_unspillableTmps;
-};
-
-// This perform all the tasks that are specific to certain register type.
-template<Arg::Type type>
-class ColoringAllocator : public AbstractColoringAllocator<unsigned> {
-public:
- ColoringAllocator(Code& code, TmpWidth& tmpWidth, const UseCounts<Tmp>& useCounts, const HashSet<unsigned>& unspillableTmp)
- : AbstractColoringAllocator<unsigned>(regsInPriorityOrder(type), AbsoluteTmpMapper<type>::lastMachineRegisterIndex(), tmpArraySize(code), unspillableTmp)
- , m_code(code)
- , m_tmpWidth(tmpWidth)
- , m_useCounts(useCounts)
- {
- if (type == Arg::GP) {
- m_framePointerIndex = AbsoluteTmpMapper<type>::absoluteIndex(Tmp(MacroAssembler::framePointerRegister));
- m_interferesWithFramePointer.ensureSize(tmpArraySize(code));
- }
-
- initializePrecoloredTmp();
- build();
- allocate();
- }
-
- Tmp getAlias(Tmp tmp) const
- {
- return AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(getAlias(AbsoluteTmpMapper<type>::absoluteIndex(tmp)));
- }
-
- // This tells you if a Move will be coalescable if the src and dst end up matching. This method
- // relies on an analysis that is invalidated by register allocation, so you it's only meaningful to
- // call this *before* replacing the Tmp's in this Inst with registers or spill slots.
- bool mayBeCoalescable(const Inst& inst) const
- {
- return mayBeCoalescableImpl(inst, &m_tmpWidth);
- }
-
- bool isUselessMove(const Inst& inst) const
- {
- return mayBeCoalescableImpl(inst, nullptr) && inst.args[0].tmp() == inst.args[1].tmp();
- }
-
- Tmp getAliasWhenSpilling(Tmp tmp) const
- {
- ASSERT_WITH_MESSAGE(!m_spilledTmps.isEmpty(), "This function is only valid for coalescing during spilling.");
-
- if (m_coalescedTmpsAtSpill.isEmpty())
- return tmp;
-
- unsigned aliasIndex = AbsoluteTmpMapper<type>::absoluteIndex(tmp);
- while (unsigned nextAliasIndex = m_coalescedTmpsAtSpill[aliasIndex])
- aliasIndex = nextAliasIndex;
-
- Tmp alias = AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(aliasIndex);
-
- ASSERT_WITH_MESSAGE(!m_spilledTmps.contains(aliasIndex) || alias == tmp, "The aliases at spill should always be colorable. Something went horribly wrong.");
-
- return alias;
- }
-
- template<typename IndexIterator>
- class IndexToTmpIteratorAdaptor {
- public:
- IndexToTmpIteratorAdaptor(IndexIterator&& indexIterator)
- : m_indexIterator(WTFMove(indexIterator))
- {
- }
-
- Tmp operator*() const { return AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(*m_indexIterator); }
- IndexToTmpIteratorAdaptor& operator++() { ++m_indexIterator; return *this; }
-
- bool operator==(const IndexToTmpIteratorAdaptor& other) const
- {
- return m_indexIterator == other.m_indexIterator;
- }
-
- bool operator!=(const IndexToTmpIteratorAdaptor& other) const
- {
- return !(*this == other);
- }
-
- private:
- IndexIterator m_indexIterator;
- };
-
- template<typename Collection>
- class IndexToTmpIterableAdaptor {
- public:
- IndexToTmpIterableAdaptor(const Collection& collection)
- : m_collection(collection)
- {
- }
-
- IndexToTmpIteratorAdaptor<typename Collection::const_iterator> begin() const
- {
- return m_collection.begin();
- }
-
- IndexToTmpIteratorAdaptor<typename Collection::const_iterator> end() const
- {
- return m_collection.end();
- }
-
- private:
- const Collection& m_collection;
- };
-
- IndexToTmpIterableAdaptor<Vector<unsigned>> spilledTmps() const { return m_spilledTmps; }
-
- bool requiresSpilling() const { return !m_spilledTmps.isEmpty(); }
-
- Reg allocatedReg(Tmp tmp) const
- {
- ASSERT(!tmp.isReg());
- ASSERT(m_coloredTmp.size());
- ASSERT(tmp.isGP() == (type == Arg::GP));
-
- Reg reg = m_coloredTmp[AbsoluteTmpMapper<type>::absoluteIndex(tmp)];
- if (!reg) {
- // We only care about Tmps that interfere. A Tmp that never interfere with anything
- // can take any register.
- reg = regsInPriorityOrder(type).first();
- }
- return reg;
- }
-
-private:
- static unsigned tmpArraySize(Code& code)
- {
- unsigned numTmps = code.numTmps(type);
- return AbsoluteTmpMapper<type>::absoluteIndex(numTmps);
- }
-
- void initializePrecoloredTmp()
- {
- m_coloredTmp.resize(m_lastPrecoloredRegisterIndex + 1);
- for (unsigned i = 1; i <= m_lastPrecoloredRegisterIndex; ++i) {
- Tmp tmp = AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(i);
- ASSERT(tmp.isReg());
- m_coloredTmp[i] = tmp.reg();
- }
- }
-
- bool mayBeCoalesced(Arg left, Arg right)
- {
- if (!left.isTmp() || !right.isTmp())
- return false;
-
- Tmp leftTmp = left.tmp();
- Tmp rightTmp = right.tmp();
-
- if (leftTmp == rightTmp)
- return false;
-
- if (leftTmp.isGP() != (type == Arg::GP) || rightTmp.isGP() != (type == Arg::GP))
- return false;
-
- unsigned leftIndex = AbsoluteTmpMapper<type>::absoluteIndex(leftTmp);
- unsigned rightIndex = AbsoluteTmpMapper<type>::absoluteIndex(rightTmp);
-
- return !m_interferenceEdges.contains(InterferenceEdge(leftIndex, rightIndex));
- }
-
- void addToLowPriorityCoalescingCandidates(Arg left, Arg right)
- {
- ASSERT(mayBeCoalesced(left, right));
- Tmp leftTmp = left.tmp();
- Tmp rightTmp = right.tmp();
-
- unsigned leftIndex = AbsoluteTmpMapper<type>::absoluteIndex(leftTmp);
- unsigned rightIndex = AbsoluteTmpMapper<type>::absoluteIndex(rightTmp);
-
- unsigned nextMoveIndex = m_coalescingCandidates.size();
- m_coalescingCandidates.append({ leftIndex, rightIndex });
-
- unsigned newIndexInWorklist = m_worklistMoves.addLowPriorityMove();
- ASSERT_UNUSED(newIndexInWorklist, newIndexInWorklist == nextMoveIndex);
-
- ASSERT(nextMoveIndex <= m_activeMoves.size());
- m_activeMoves.ensureSize(nextMoveIndex + 1);
-
- m_moveList[leftIndex].add(nextMoveIndex);
- m_moveList[rightIndex].add(nextMoveIndex);
- }
-
- void build()
- {
- TmpLiveness<type> liveness(m_code);
- for (BasicBlock* block : m_code) {
- typename TmpLiveness<type>::LocalCalc localCalc(liveness, block);
- for (unsigned instIndex = block->size(); instIndex--;) {
- Inst& inst = block->at(instIndex);
- Inst* nextInst = block->get(instIndex + 1);
- build(&inst, nextInst, localCalc);
- localCalc.execute(instIndex);
- }
- build(nullptr, &block->at(0), localCalc);
- }
- buildLowPriorityMoveList();
- }
-
- void build(Inst* prevInst, Inst* nextInst, const typename TmpLiveness<type>::LocalCalc& localCalc)
- {
- Inst::forEachDefWithExtraClobberedRegs<Tmp>(
- prevInst, nextInst,
- [&] (const Tmp& arg, Arg::Role, Arg::Type argType, Arg::Width) {
- if (argType != type)
- return;
-
- // All the Def()s interfere with each other and with all the extra clobbered Tmps.
- // We should not use forEachDefWithExtraClobberedRegs() here since colored Tmps
- // do not need interference edges in our implementation.
- Inst::forEachDef<Tmp>(
- prevInst, nextInst,
- [&] (Tmp& otherArg, Arg::Role, Arg::Type argType, Arg::Width) {
- if (argType != type)
- return;
-
- this->addEdge(arg, otherArg);
- });
- });
-
- if (prevInst && mayBeCoalescable(*prevInst)) {
- // We do not want the Use() of this move to interfere with the Def(), even if it is live
- // after the Move. If we were to add the interference edge, it would be impossible to
- // coalesce the Move even if the two Tmp never interfere anywhere.
- Tmp defTmp;
- Tmp useTmp;
- prevInst->forEachTmp([&defTmp, &useTmp] (Tmp& argTmp, Arg::Role role, Arg::Type, Arg::Width) {
- if (Arg::isLateDef(role))
- defTmp = argTmp;
- else {
- ASSERT(Arg::isEarlyUse(role));
- useTmp = argTmp;
- }
- });
- ASSERT(defTmp);
- ASSERT(useTmp);
-
- unsigned nextMoveIndex = m_coalescingCandidates.size();
- m_coalescingCandidates.append({ AbsoluteTmpMapper<type>::absoluteIndex(useTmp), AbsoluteTmpMapper<type>::absoluteIndex(defTmp) });
-
- unsigned newIndexInWorklist = m_worklistMoves.addMove();
- ASSERT_UNUSED(newIndexInWorklist, newIndexInWorklist == nextMoveIndex);
-
- ASSERT(nextMoveIndex <= m_activeMoves.size());
- m_activeMoves.ensureSize(nextMoveIndex + 1);
-
- for (const Arg& arg : prevInst->args) {
- auto& list = m_moveList[AbsoluteTmpMapper<type>::absoluteIndex(arg.tmp())];
- list.add(nextMoveIndex);
- }
-
- for (const Tmp& liveTmp : localCalc.live()) {
- if (liveTmp != useTmp)
- addEdge(defTmp, liveTmp);
- }
-
- // The next instruction could have early clobbers or early def's. We need to consider
- // those now.
- addEdges(nullptr, nextInst, localCalc.live());
- } else
- addEdges(prevInst, nextInst, localCalc.live());
- }
-
- void buildLowPriorityMoveList()
- {
- if (!isX86())
- return;
-
- m_worklistMoves.startAddingLowPriorityMoves();
- for (BasicBlock* block : m_code) {
- for (Inst& inst : *block) {
- if (Optional<unsigned> defArgIndex = inst.shouldTryAliasingDef()) {
- Arg op1 = inst.args[*defArgIndex - 2];
- Arg op2 = inst.args[*defArgIndex - 1];
- Arg dest = inst.args[*defArgIndex];
-
- if (op1 == dest || op2 == dest)
- continue;
-
- if (mayBeCoalesced(op1, dest))
- addToLowPriorityCoalescingCandidates(op1, dest);
- if (op1 != op2 && mayBeCoalesced(op2, dest))
- addToLowPriorityCoalescingCandidates(op2, dest);
- }
- }
- }
- }
-
- void addEdges(Inst* prevInst, Inst* nextInst, typename TmpLiveness<type>::LocalCalc::Iterable liveTmps)
- {
- // All the Def()s interfere with everthing live.
- Inst::forEachDefWithExtraClobberedRegs<Tmp>(
- prevInst, nextInst,
- [&] (const Tmp& arg, Arg::Role, Arg::Type argType, Arg::Width) {
- if (argType != type)
- return;
-
- for (const Tmp& liveTmp : liveTmps) {
- ASSERT(liveTmp.isGP() == (type == Arg::GP));
- addEdge(arg, liveTmp);
- }
-
- if (type == Arg::GP && !arg.isGPR())
- m_interferesWithFramePointer.quickSet(AbsoluteTmpMapper<type>::absoluteIndex(arg));
- });
- }
-
- void addEdge(Tmp a, Tmp b)
- {
- ASSERT_WITH_MESSAGE(a.isGP() == b.isGP(), "An interference between registers of different types does not make sense, it can lead to non-colorable graphs.");
-
- addEdge(AbsoluteTmpMapper<type>::absoluteIndex(a), AbsoluteTmpMapper<type>::absoluteIndex(b));
- }
-
- // Calling this without a tmpWidth will perform a more conservative coalescing analysis that assumes
- // that Move32's are not coalescable.
- static bool mayBeCoalescableImpl(const Inst& inst, TmpWidth* tmpWidth)
- {
- switch (type) {
- case Arg::GP:
- switch (inst.opcode) {
- case Move:
- case Move32:
- break;
- default:
- return false;
- }
- break;
- case Arg::FP:
- switch (inst.opcode) {
- case MoveFloat:
- case MoveDouble:
- break;
- default:
- return false;
- }
- break;
- }
-
- ASSERT_WITH_MESSAGE(inst.args.size() == 2, "We assume coalecable moves only have two arguments in a few places.");
-
- if (!inst.args[0].isTmp() || !inst.args[1].isTmp())
- return false;
-
- ASSERT(inst.args[0].type() == type);
- ASSERT(inst.args[1].type() == type);
-
- // We can coalesce a Move32 so long as either of the following holds:
- // - The input is already zero-filled.
- // - The output only cares about the low 32 bits.
- //
- // Note that the input property requires an analysis over ZDef's, so it's only valid so long
- // as the input gets a register. We don't know if the input gets a register, but we do know
- // that if it doesn't get a register then we will still emit this Move32.
- if (inst.opcode == Move32) {
- if (!tmpWidth)
- return false;
-
- if (tmpWidth->defWidth(inst.args[0].tmp()) > Arg::Width32
- && tmpWidth->useWidth(inst.args[1].tmp()) > Arg::Width32)
- return false;
- }
-
- return true;
- }
-
- void selectSpill()
- {
- if (!m_hasSelectedSpill) {
- m_hasSelectedSpill = true;
-
- if (m_hasCoalescedNonTrivialMove)
- m_coalescedTmpsAtSpill = m_coalescedTmps;
- }
-
- auto iterator = m_spillWorklist.begin();
-
- RELEASE_ASSERT_WITH_MESSAGE(iterator != m_spillWorklist.end(), "selectSpill() called when there was no spill.");
- RELEASE_ASSERT_WITH_MESSAGE(!m_unspillableTmps.contains(*iterator), "trying to spill unspillable tmp");
-
- // Higher score means more desirable to spill. Lower scores maximize the likelihood that a tmp
- // gets a register.
- auto score = [&] (Tmp tmp) -> double {
- // Air exposes the concept of "fast tmps", and we interpret that to mean that the tmp
- // should always be in a register.
- if (m_code.isFastTmp(tmp))
- return 0;
-
- // All else being equal, the score should be directly related to the degree.
- double degree = static_cast<double>(m_degrees[AbsoluteTmpMapper<type>::absoluteIndex(tmp)]);
-
- // All else being equal, the score should be inversely related to the number of warm uses and
- // defs.
- const UseCounts<Tmp>::Counts* counts = m_useCounts[tmp];
- if (!counts)
- return std::numeric_limits<double>::infinity();
-
- double uses = counts->numWarmUses + counts->numDefs;
-
- // If it's a constant, then it's not as bad to spill. We can rematerialize it in many
- // cases.
- if (counts->numConstDefs == counts->numDefs)
- uses /= 2;
-
- return degree / uses;
- };
-
- auto victimIterator = iterator;
- double maxScore = score(AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(*iterator));
-
- ++iterator;
- for (;iterator != m_spillWorklist.end(); ++iterator) {
- double tmpScore = score(AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(*iterator));
- if (tmpScore > maxScore) {
- ASSERT(!m_unspillableTmps.contains(*iterator));
- victimIterator = iterator;
- maxScore = tmpScore;
- }
- }
-
- unsigned victimIndex = *victimIterator;
- m_spillWorklist.remove(victimIterator);
- m_simplifyWorklist.append(victimIndex);
-
- freezeMoves(victimIndex);
- }
-
- void allocate()
- {
- ASSERT_WITH_MESSAGE(m_activeMoves.size() >= m_coalescingCandidates.size(), "The activeMove set should be big enough for the quick operations of BitVector.");
-
- makeWorkList();
-
- if (debug) {
- dataLog("Interference: ", listDump(m_interferenceEdges), "\n");
- dumpInterferenceGraphInDot(WTF::dataFile());
- dataLog("Coalescing candidates:\n");
- for (MoveOperands& moveOp : m_coalescingCandidates) {
- dataLog(" ", AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(moveOp.srcIndex),
- " -> ", AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(moveOp.dstIndex), "\n");
- }
- dataLog("Initial work list\n");
- dumpWorkLists(WTF::dataFile());
- }
-
- do {
- if (traceDebug) {
- dataLog("Before Graph simplification iteration\n");
- dumpWorkLists(WTF::dataFile());
- }
-
- if (!m_simplifyWorklist.isEmpty())
- simplify();
- else if (!m_worklistMoves.isEmpty())
- coalesce();
- else if (!m_freezeWorklist.isEmpty())
- freeze();
- else if (!m_spillWorklist.isEmpty())
- selectSpill();
-
- if (traceDebug) {
- dataLog("After Graph simplification iteration\n");
- dumpWorkLists(WTF::dataFile());
- }
- } while (!m_simplifyWorklist.isEmpty() || !m_worklistMoves.isEmpty() || !m_freezeWorklist.isEmpty() || !m_spillWorklist.isEmpty());
-
- assignColors();
- }
-
-#if PLATFORM(COCOA)
-#pragma mark - Debugging helpers.
-#endif
-
- void dumpInterferenceGraphInDot(PrintStream& out)
- {
- out.print("graph InterferenceGraph { \n");
-
- HashSet<Tmp> tmpsWithInterferences;
- for (const auto& edge : m_interferenceEdges) {
- tmpsWithInterferences.add(AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(edge.first()));
- tmpsWithInterferences.add(AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(edge.second()));
- }
-
- for (const auto& tmp : tmpsWithInterferences) {
- unsigned tmpIndex = AbsoluteTmpMapper<type>::absoluteIndex(tmp);
- if (tmpIndex < m_degrees.size())
- out.print(" ", tmp.internalValue(), " [label=\"", tmp, " (", m_degrees[tmpIndex], ")\"];\n");
- else
- out.print(" ", tmp.internalValue(), " [label=\"", tmp, "\"];\n");
- }
-
- for (const auto& edge : m_interferenceEdges)
- out.print(" ", edge.first(), " -- ", edge.second(), ";\n");
- out.print("}\n");
- }
-
- void dumpWorkLists(PrintStream& out)
- {
- out.print("Simplify work list:\n");
- for (unsigned tmpIndex : m_simplifyWorklist)
- out.print(" ", AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(tmpIndex), "\n");
- out.printf("Moves work list is empty? %d\n", m_worklistMoves.isEmpty());
- out.print("Freeze work list:\n");
- for (unsigned tmpIndex : m_freezeWorklist)
- out.print(" ", AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(tmpIndex), "\n");
- out.print("Spill work list:\n");
- for (unsigned tmpIndex : m_spillWorklist)
- out.print(" ", AbsoluteTmpMapper<type>::tmpFromAbsoluteIndex(tmpIndex), "\n");
- }
-
- using AbstractColoringAllocator<unsigned>::addEdge;
- using AbstractColoringAllocator<unsigned>::getAlias;
-
- Code& m_code;
- TmpWidth& m_tmpWidth;
- // FIXME: spilling should not type specific. It is only a side effect of using UseCounts.
- const UseCounts<Tmp>& m_useCounts;
-};
-
-class IteratedRegisterCoalescing {
-public:
- IteratedRegisterCoalescing(Code& code)
- : m_code(code)
- , m_useCounts(code)
- {
- }
-
- void run()
- {
- iteratedRegisterCoalescingOnType<Arg::GP>();
- iteratedRegisterCoalescingOnType<Arg::FP>();
-
- if (reportStats)
- dataLog("Num iterations = ", m_numIterations, "\n");
- }
-
-private:
- template<Arg::Type type>
- void iteratedRegisterCoalescingOnType()
- {
- HashSet<unsigned> unspillableTmps = computeUnspillableTmps<type>();
-
- // FIXME: If a Tmp is used only from a Scratch role and that argument is !admitsStack, then
- // we should add the Tmp to unspillableTmps. That will help avoid relooping only to turn the
- // Tmp into an unspillable Tmp.
- // https://bugs.webkit.org/show_bug.cgi?id=152699
-
- while (true) {
- ++m_numIterations;
-
- if (traceDebug)
- dataLog("Code at iteration ", m_numIterations, ":\n", m_code);
-
- // FIXME: One way to optimize this code is to remove the recomputation inside the fixpoint.
- // We need to recompute because spilling adds tmps, but we could just update tmpWidth when we
- // add those tmps. Note that one easy way to remove the recomputation is to make any newly
- // added Tmps get the same use/def widths that the original Tmp got. But, this may hurt the
- // spill code we emit. Since we currently recompute TmpWidth after spilling, the newly
- // created Tmps may get narrower use/def widths. On the other hand, the spiller already
- // selects which move instruction to use based on the original Tmp's widths, so it may not
- // matter than a subsequent iteration sees a coservative width for the new Tmps. Also, the
- // recomputation may not actually be a performance problem; it's likely that a better way to
- // improve performance of TmpWidth is to replace its HashMap with something else. It's
- // possible that most of the TmpWidth overhead is from queries of TmpWidth rather than the
- // recomputation, in which case speeding up the lookup would be a bigger win.
- // https://bugs.webkit.org/show_bug.cgi?id=152478
- m_tmpWidth.recompute(m_code);
-
- ColoringAllocator<type> allocator(m_code, m_tmpWidth, m_useCounts, unspillableTmps);
- if (!allocator.requiresSpilling()) {
- assignRegistersToTmp(allocator);
- if (traceDebug)
- dataLog("Successfull allocation at iteration ", m_numIterations, ":\n", m_code);
-
- return;
- }
- addSpillAndFill<type>(allocator, unspillableTmps);
- }
- }
-
- template<Arg::Type type>
- HashSet<unsigned> computeUnspillableTmps()
- {
- HashSet<unsigned> unspillableTmps;
-
- struct Range {
- unsigned first { std::numeric_limits<unsigned>::max() };
- unsigned last { 0 };
- unsigned count { 0 };
- unsigned admitStackCount { 0 };
- };
-
- unsigned numTmps = m_code.numTmps(type);
- unsigned arraySize = AbsoluteTmpMapper<type>::absoluteIndex(numTmps);
-
- Vector<Range, 0, UnsafeVectorOverflow> ranges;
- ranges.fill(Range(), arraySize);
-
- unsigned globalIndex = 0;
- for (BasicBlock* block : m_code) {
- for (Inst& inst : *block) {
- inst.forEachArg([&] (Arg& arg, Arg::Role, Arg::Type argType, Arg::Width) {
- if (arg.isTmp() && inst.admitsStack(arg)) {
- if (argType != type)
- return;
-
- Tmp tmp = arg.tmp();
- Range& range = ranges[AbsoluteTmpMapper<type>::absoluteIndex(tmp)];
- range.count++;
- range.admitStackCount++;
- if (globalIndex < range.first) {
- range.first = globalIndex;
- range.last = globalIndex;
- } else
- range.last = globalIndex;
-
- return;
- }
-
- arg.forEachTmpFast([&] (Tmp& tmp) {
- if (tmp.isGP() != (type == Arg::GP))
- return;
-
- Range& range = ranges[AbsoluteTmpMapper<type>::absoluteIndex(tmp)];
- range.count++;
- if (globalIndex < range.first) {
- range.first = globalIndex;
- range.last = globalIndex;
- } else
- range.last = globalIndex;
- });
- });
-
- ++globalIndex;
- }
- ++globalIndex;
- }
- for (unsigned i = AbsoluteTmpMapper<type>::lastMachineRegisterIndex() + 1; i < ranges.size(); ++i) {
- Range& range = ranges[i];
- if (range.last - range.first <= 1 && range.count > range.admitStackCount)
- unspillableTmps.add(i);
- }
-
- return unspillableTmps;
- }
-
- template<Arg::Type type>
- void assignRegistersToTmp(const ColoringAllocator<type>& allocator)
- {
- for (BasicBlock* block : m_code) {
- // Give Tmp a valid register.
- for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
- Inst& inst = block->at(instIndex);
-
- // The mayBeCoalescable() method will change its mind for some operations after we
- // complete register allocation. So, we record this before starting.
- bool mayBeCoalescable = allocator.mayBeCoalescable(inst);
-
- // Move32 is cheaper if we know that it's equivalent to a Move. It's
- // equivalent if the destination's high bits are not observable or if the source's high
- // bits are all zero. Note that we don't have the opposite optimization for other
- // architectures, which may prefer Move over Move32, because Move is canonical already.
- if (type == Arg::GP && inst.opcode == Move
- && inst.args[0].isTmp() && inst.args[1].isTmp()) {
- if (m_tmpWidth.useWidth(inst.args[1].tmp()) <= Arg::Width32
- || m_tmpWidth.defWidth(inst.args[0].tmp()) <= Arg::Width32)
- inst.opcode = Move32;
- }
-
- inst.forEachTmpFast([&] (Tmp& tmp) {
- if (tmp.isReg() || tmp.isGP() == (type != Arg::GP))
- return;
-
- Tmp aliasTmp = allocator.getAlias(tmp);
- Tmp assignedTmp;
- if (aliasTmp.isReg())
- assignedTmp = Tmp(aliasTmp.reg());
- else {
- auto reg = allocator.allocatedReg(aliasTmp);
- ASSERT(reg);
- assignedTmp = Tmp(reg);
- }
- ASSERT(assignedTmp.isReg());
- tmp = assignedTmp;
- });
-
- if (mayBeCoalescable && inst.args[0].isTmp() && inst.args[1].isTmp()
- && inst.args[0].tmp() == inst.args[1].tmp())
- inst = Inst();
- }
-
- // Remove all the useless moves we created in this block.
- block->insts().removeAllMatching([&] (const Inst& inst) {
- return !inst;
- });
- }
- }
-
- template<Arg::Type type>
- void addSpillAndFill(const ColoringAllocator<type>& allocator, HashSet<unsigned>& unspillableTmps)
- {
- HashMap<Tmp, StackSlot*> stackSlots;
- for (Tmp tmp : allocator.spilledTmps()) {
- // All the spilled values become unspillable.
- unspillableTmps.add(AbsoluteTmpMapper<type>::absoluteIndex(tmp));
-
- // Allocate stack slot for each spilled value.
- StackSlot* stackSlot = m_code.addStackSlot(
- m_tmpWidth.width(tmp) <= Arg::Width32 ? 4 : 8, StackSlotKind::Spill);
- bool isNewTmp = stackSlots.add(tmp, stackSlot).isNewEntry;
- ASSERT_UNUSED(isNewTmp, isNewTmp);
- }
-
- // Rewrite the program to get rid of the spilled Tmp.
- InsertionSet insertionSet(m_code);
- for (BasicBlock* block : m_code) {
- bool hasAliasedTmps = false;
-
- for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
- Inst& inst = block->at(instIndex);
-
- // The TmpWidth analysis will say that a Move only stores 32 bits into the destination,
- // if the source only had 32 bits worth of non-zero bits. Same for the source: it will
- // only claim to read 32 bits from the source if only 32 bits of the destination are
- // read. Note that we only apply this logic if this turns into a load or store, since
- // Move is the canonical way to move data between GPRs.
- bool forceMove32IfDidSpill = false;
- bool didSpill = false;
- if (type == Arg::GP && inst.opcode == Move) {
- if ((inst.args[0].isTmp() && m_tmpWidth.width(inst.args[0].tmp()) <= Arg::Width32)
- || (inst.args[1].isTmp() && m_tmpWidth.width(inst.args[1].tmp()) <= Arg::Width32))
- forceMove32IfDidSpill = true;
- }
-
- // Try to replace the register use by memory use when possible.
- inst.forEachArg(
- [&] (Arg& arg, Arg::Role, Arg::Type argType, Arg::Width width) {
- if (arg.isTmp() && argType == type && !arg.isReg()) {
- auto stackSlotEntry = stackSlots.find(arg.tmp());
- if (stackSlotEntry != stackSlots.end()
- && inst.admitsStack(arg)) {
- stackSlotEntry->value->ensureSize(
- forceMove32IfDidSpill ? 4 : Arg::bytes(width));
- arg = Arg::stack(stackSlotEntry->value);
- didSpill = true;
- }
- }
- });
-
- if (didSpill && forceMove32IfDidSpill)
- inst.opcode = Move32;
-
- // For every other case, add Load/Store as needed.
- inst.forEachTmp([&] (Tmp& tmp, Arg::Role role, Arg::Type argType, Arg::Width) {
- if (tmp.isReg() || argType != type)
- return;
-
- auto stackSlotEntry = stackSlots.find(tmp);
- if (stackSlotEntry == stackSlots.end()) {
- Tmp alias = allocator.getAliasWhenSpilling(tmp);
- if (alias != tmp) {
- tmp = alias;
- hasAliasedTmps = true;
- }
- return;
- }
-
- Arg arg = Arg::stack(stackSlotEntry->value);
- Opcode move = Oops;
- switch (stackSlotEntry->value->byteSize()) {
- case 4:
- move = type == Arg::GP ? Move32 : MoveFloat;
- break;
- case 8:
- move = type == Arg::GP ? Move : MoveDouble;
- break;
- default:
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
-
- tmp = m_code.newTmp(type);
- unspillableTmps.add(AbsoluteTmpMapper<type>::absoluteIndex(tmp));
-
- if (Arg::isAnyUse(role) && role != Arg::Scratch)
- insertionSet.insert(instIndex, move, inst.origin, arg, tmp);
- if (Arg::isAnyDef(role))
- insertionSet.insert(instIndex + 1, move, inst.origin, tmp, arg);
- });
- }
- insertionSet.execute(block);
-
- if (hasAliasedTmps) {
- block->insts().removeAllMatching([&] (const Inst& inst) {
- return allocator.isUselessMove(inst);
- });
- }
- }
- }
-
- Code& m_code;
- TmpWidth m_tmpWidth;
- UseCounts<Tmp> m_useCounts;
- unsigned m_numIterations { 0 };
-};
-
-} // anonymous namespace
-
-void iteratedRegisterCoalescing(Code& code)
-{
- PhaseScope phaseScope(code, "iteratedRegisterCoalescing");
-
- IteratedRegisterCoalescing iteratedRegisterCoalescing(code);
- iteratedRegisterCoalescing.run();
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.h b/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.h
deleted file mode 100644
index fbeec1675..000000000
--- a/Source/JavaScriptCore/b3/air/AirIteratedRegisterCoalescing.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirIteratedRegisterCoalescing_h
-#define AirIteratedRegisterCoalescing_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// This is a register allocation phase based on Andrew Appel's Iterated Register Coalescing
-// http://www.cs.cmu.edu/afs/cs/academic/class/15745-s07/www/papers/george.pdf
-void iteratedRegisterCoalescing(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirIteratedRegisterCoalescing_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirLiveness.h b/Source/JavaScriptCore/b3/air/AirLiveness.h
deleted file mode 100644
index ac118aaf5..000000000
--- a/Source/JavaScriptCore/b3/air/AirLiveness.h
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirLiveness_h
-#define AirLiveness_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirBasicBlock.h"
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include "AirStackSlot.h"
-#include "AirTmpInlines.h"
-#include "B3IndexMap.h"
-#include "B3IndexSet.h"
-#include <wtf/IndexSparseSet.h>
-#include <wtf/ListDump.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-template<Arg::Type adapterType>
-struct TmpLivenessAdapter {
- typedef Tmp Thing;
- typedef HashSet<unsigned> IndexSet;
-
- TmpLivenessAdapter(Code&) { }
-
- static unsigned maxIndex(Code& code)
- {
- unsigned numTmps = code.numTmps(adapterType);
- return AbsoluteTmpMapper<adapterType>::absoluteIndex(numTmps);
- }
- static bool acceptsType(Arg::Type type) { return type == adapterType; }
- static unsigned valueToIndex(Tmp tmp) { return AbsoluteTmpMapper<adapterType>::absoluteIndex(tmp); }
- static Tmp indexToValue(unsigned index) { return AbsoluteTmpMapper<adapterType>::tmpFromAbsoluteIndex(index); }
-};
-
-struct StackSlotLivenessAdapter {
- typedef StackSlot* Thing;
- typedef HashSet<unsigned, DefaultHash<unsigned>::Hash, WTF::UnsignedWithZeroKeyHashTraits<unsigned>> IndexSet;
-
- StackSlotLivenessAdapter(Code& code)
- : m_code(code)
- {
- }
-
- static unsigned maxIndex(Code& code)
- {
- return code.stackSlots().size() - 1;
- }
- static bool acceptsType(Arg::Type) { return true; }
- static unsigned valueToIndex(StackSlot* stackSlot) { return stackSlot->index(); }
- StackSlot* indexToValue(unsigned index) { return m_code.stackSlots()[index]; }
-
-private:
- Code& m_code;
-};
-
-struct RegLivenessAdapter {
- typedef Reg Thing;
- typedef BitVector IndexSet;
-
- RegLivenessAdapter(Code&) { }
-
- static unsigned maxIndex(Code&)
- {
- return Reg::maxIndex();
- }
-
- static bool acceptsType(Arg::Type) { return true; }
- static unsigned valueToIndex(Reg reg) { return reg.index(); }
- Reg indexToValue(unsigned index) { return Reg::fromIndex(index); }
-};
-
-template<typename Adapter>
-class AbstractLiveness : public Adapter {
- struct Workset;
-public:
- typedef typename Adapter::Thing Thing;
-
- AbstractLiveness(Code& code)
- : Adapter(code)
- , m_workset(Adapter::maxIndex(code))
- , m_liveAtHead(code.size())
- , m_liveAtTail(code.size())
- {
- // The liveAtTail of each block automatically contains the LateUse's of the terminal.
- for (BasicBlock* block : code) {
- typename Adapter::IndexSet& liveAtTail = m_liveAtTail[block];
-
- block->last().forEach<typename Adapter::Thing>(
- [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
- if (Arg::isLateUse(role) && Adapter::acceptsType(type))
- liveAtTail.add(Adapter::valueToIndex(thing));
- });
- }
-
- // Blocks with new live values at tail.
- BitVector dirtyBlocks;
- for (size_t blockIndex = 0; blockIndex < code.size(); ++blockIndex)
- dirtyBlocks.set(blockIndex);
-
- bool changed;
- do {
- changed = false;
-
- for (size_t blockIndex = code.size(); blockIndex--;) {
- BasicBlock* block = code.at(blockIndex);
- if (!block)
- continue;
-
- if (!dirtyBlocks.quickClear(blockIndex))
- continue;
-
- LocalCalc localCalc(*this, block);
- for (size_t instIndex = block->size(); instIndex--;)
- localCalc.execute(instIndex);
-
- // Handle the early def's of the first instruction.
- block->at(0).forEach<typename Adapter::Thing>(
- [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
- if (Arg::isEarlyDef(role) && Adapter::acceptsType(type))
- m_workset.remove(Adapter::valueToIndex(thing));
- });
-
- Vector<unsigned>& liveAtHead = m_liveAtHead[block];
-
- // We only care about Tmps that were discovered in this iteration. It is impossible
- // to remove a live value from the head.
- // We remove all the values we already knew about so that we only have to deal with
- // what is new in LiveAtHead.
- if (m_workset.size() == liveAtHead.size())
- m_workset.clear();
- else {
- for (unsigned liveIndexAtHead : liveAtHead)
- m_workset.remove(liveIndexAtHead);
- }
-
- if (m_workset.isEmpty())
- continue;
-
- liveAtHead.reserveCapacity(liveAtHead.size() + m_workset.size());
- for (unsigned newValue : m_workset)
- liveAtHead.uncheckedAppend(newValue);
-
- for (BasicBlock* predecessor : block->predecessors()) {
- typename Adapter::IndexSet& liveAtTail = m_liveAtTail[predecessor];
- for (unsigned newValue : m_workset) {
- if (liveAtTail.add(newValue)) {
- if (!dirtyBlocks.quickSet(predecessor->index()))
- changed = true;
- }
- }
- }
- }
- } while (changed);
- }
-
- // This calculator has to be run in reverse.
- class LocalCalc {
- public:
- LocalCalc(AbstractLiveness& liveness, BasicBlock* block)
- : m_liveness(liveness)
- , m_block(block)
- {
- auto& workset = liveness.m_workset;
- workset.clear();
- typename Adapter::IndexSet& liveAtTail = liveness.m_liveAtTail[block];
- for (unsigned index : liveAtTail)
- workset.add(index);
- }
-
- struct Iterator {
- Iterator(Adapter& adapter, IndexSparseSet<UnsafeVectorOverflow>::const_iterator sparceSetIterator)
- : m_adapter(adapter)
- , m_sparceSetIterator(sparceSetIterator)
- {
- }
-
- Iterator& operator++()
- {
- ++m_sparceSetIterator;
- return *this;
- }
-
- typename Adapter::Thing operator*() const
- {
- return m_adapter.indexToValue(*m_sparceSetIterator);
- }
-
- bool operator==(const Iterator& other) { return m_sparceSetIterator == other.m_sparceSetIterator; }
- bool operator!=(const Iterator& other) { return m_sparceSetIterator != other.m_sparceSetIterator; }
-
- private:
- Adapter& m_adapter;
- IndexSparseSet<UnsafeVectorOverflow>::const_iterator m_sparceSetIterator;
- };
-
- struct Iterable {
- Iterable(AbstractLiveness& liveness)
- : m_liveness(liveness)
- {
- }
-
- Iterator begin() const { return Iterator(m_liveness, m_liveness.m_workset.begin()); }
- Iterator end() const { return Iterator(m_liveness, m_liveness.m_workset.end()); }
-
- bool contains(const typename Adapter::Thing& thing) const
- {
- return m_liveness.m_workset.contains(Adapter::valueToIndex(thing));
- }
-
- private:
- AbstractLiveness& m_liveness;
- };
-
- Iterable live() const
- {
- return Iterable(m_liveness);
- }
-
- bool isLive(const typename Adapter::Thing& thing) const
- {
- return live().contains(thing);
- }
-
- void execute(unsigned instIndex)
- {
- Inst& inst = m_block->at(instIndex);
- auto& workset = m_liveness.m_workset;
-
- // First handle the early def's of the next instruction.
- if (instIndex + 1 < m_block->size()) {
- Inst& nextInst = m_block->at(instIndex + 1);
- nextInst.forEach<typename Adapter::Thing>(
- [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
- if (Arg::isEarlyDef(role) && Adapter::acceptsType(type))
- workset.remove(Adapter::valueToIndex(thing));
- });
- }
-
- // Then handle def's.
- inst.forEach<typename Adapter::Thing>(
- [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
- if (Arg::isLateDef(role) && Adapter::acceptsType(type))
- workset.remove(Adapter::valueToIndex(thing));
- });
-
- // Then handle use's.
- inst.forEach<typename Adapter::Thing>(
- [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
- if (Arg::isEarlyUse(role) && Adapter::acceptsType(type))
- workset.add(Adapter::valueToIndex(thing));
- });
-
- // And finally, handle the late use's of the previous instruction.
- if (instIndex) {
- Inst& prevInst = m_block->at(instIndex - 1);
- prevInst.forEach<typename Adapter::Thing>(
- [&] (typename Adapter::Thing& thing, Arg::Role role, Arg::Type type, Arg::Width) {
- if (Arg::isLateUse(role) && Adapter::acceptsType(type))
- workset.add(Adapter::valueToIndex(thing));
- });
- }
- }
-
- private:
- AbstractLiveness& m_liveness;
- BasicBlock* m_block;
- };
-
- const Vector<unsigned>& rawLiveAtHead(BasicBlock* block)
- {
- return m_liveAtHead[block];
- }
-
- template<typename UnderlyingIterable>
- class Iterable {
- public:
- Iterable(AbstractLiveness& liveness, const UnderlyingIterable& iterable)
- : m_liveness(liveness)
- , m_iterable(iterable)
- {
- }
-
- class iterator {
- public:
- iterator()
- : m_liveness(nullptr)
- , m_iter()
- {
- }
-
- iterator(AbstractLiveness& liveness, typename UnderlyingIterable::const_iterator iter)
- : m_liveness(&liveness)
- , m_iter(iter)
- {
- }
-
- typename Adapter::Thing operator*()
- {
- return m_liveness->indexToValue(*m_iter);
- }
-
- iterator& operator++()
- {
- ++m_iter;
- return *this;
- }
-
- bool operator==(const iterator& other) const
- {
- ASSERT(m_liveness == other.m_liveness);
- return m_iter == other.m_iter;
- }
-
- bool operator!=(const iterator& other) const
- {
- return !(*this == other);
- }
-
- private:
- AbstractLiveness* m_liveness;
- typename UnderlyingIterable::const_iterator m_iter;
- };
-
- iterator begin() const { return iterator(m_liveness, m_iterable.begin()); }
- iterator end() const { return iterator(m_liveness, m_iterable.end()); }
-
- bool contains(const typename Adapter::Thing& thing) const
- {
- return m_liveness.m_workset.contains(Adapter::valueToIndex(thing));
- }
-
- private:
- AbstractLiveness& m_liveness;
- const UnderlyingIterable& m_iterable;
- };
-
- Iterable<Vector<unsigned>> liveAtHead(BasicBlock* block)
- {
- return Iterable<Vector<unsigned>>(*this, m_liveAtHead[block]);
- }
-
- Iterable<typename Adapter::IndexSet> liveAtTail(BasicBlock* block)
- {
- return Iterable<typename Adapter::IndexSet>(*this, m_liveAtTail[block]);
- }
-
- IndexSparseSet<UnsafeVectorOverflow>& workset() { return m_workset; }
-
-private:
- friend class LocalCalc;
- friend struct LocalCalc::Iterable;
-
- IndexSparseSet<UnsafeVectorOverflow> m_workset;
- IndexMap<BasicBlock, Vector<unsigned>> m_liveAtHead;
- IndexMap<BasicBlock, typename Adapter::IndexSet> m_liveAtTail;
-};
-
-template<Arg::Type type>
-using TmpLiveness = AbstractLiveness<TmpLivenessAdapter<type>>;
-
-typedef AbstractLiveness<TmpLivenessAdapter<Arg::GP>> GPLiveness;
-typedef AbstractLiveness<TmpLivenessAdapter<Arg::FP>> FPLiveness;
-typedef AbstractLiveness<StackSlotLivenessAdapter> StackSlotLiveness;
-typedef AbstractLiveness<RegLivenessAdapter> RegLiveness;
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirLiveness_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirLogRegisterPressure.cpp b/Source/JavaScriptCore/b3/air/AirLogRegisterPressure.cpp
deleted file mode 100644
index ab323a1ab..000000000
--- a/Source/JavaScriptCore/b3/air/AirLogRegisterPressure.cpp
+++ /dev/null
@@ -1,102 +0,0 @@
-/*
- * Copyright (C) 2016 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 "AirLogRegisterPressure.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include "AirLiveness.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-void logRegisterPressure(Code& code)
-{
- const unsigned totalColumns = 200;
- const unsigned registerColumns = 100;
-
- RegLiveness liveness(code);
-
- for (BasicBlock* block : code) {
- RegLiveness::LocalCalc localCalc(liveness, block);
-
- block->dumpHeader(WTF::dataFile());
-
- Vector<CString> instDumps;
- for (unsigned instIndex = block->size(); instIndex--;) {
- Inst& inst = block->at(instIndex);
- Inst* prevInst = block->get(instIndex - 1);
-
- localCalc.execute(instIndex);
-
- RegisterSet set;
- set.setAll(localCalc.live());
- Inst::forEachDefWithExtraClobberedRegs<Reg>(
- prevInst, &inst,
- [&] (Reg reg, Arg::Role, Arg::Type, Arg::Width) {
- set.set(reg);
- });
-
- StringPrintStream instOut;
- StringPrintStream lineOut;
- lineOut.print(" ");
- if (set.numberOfSetRegisters()) {
- set.forEach(
- [&] (Reg reg) {
- CString text = toCString(" ", reg);
- if (text.length() + lineOut.length() > totalColumns) {
- instOut.print(lineOut.toCString(), "\n");
- lineOut.reset();
- lineOut.print(" ");
- }
- lineOut.print(text);
- });
- lineOut.print(":");
- }
- if (lineOut.length() > registerColumns) {
- instOut.print(lineOut.toCString(), "\n");
- lineOut.reset();
- }
- while (lineOut.length() < registerColumns)
- lineOut.print(" ");
- lineOut.print(" ");
- lineOut.print(inst);
- instOut.print(lineOut.toCString(), "\n");
- instDumps.append(instOut.toCString());
- }
-
- for (unsigned i = instDumps.size(); i--;)
- dataLog(instDumps[i]);
-
- block->dumpFooter(WTF::dataFile());
- }
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirLogRegisterPressure.h b/Source/JavaScriptCore/b3/air/AirLogRegisterPressure.h
deleted file mode 100644
index 6cc0323e5..000000000
--- a/Source/JavaScriptCore/b3/air/AirLogRegisterPressure.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef AirLogRegisterPressure_h
-#define AirLogRegisterPressure_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// Dumps the registers that are used at each instruction.
-void logRegisterPressure(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirLogRegisterPressure_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirLowerAfterRegAlloc.cpp b/Source/JavaScriptCore/b3/air/AirLowerAfterRegAlloc.cpp
deleted file mode 100644
index 84f7bd76f..000000000
--- a/Source/JavaScriptCore/b3/air/AirLowerAfterRegAlloc.cpp
+++ /dev/null
@@ -1,247 +0,0 @@
-/*
- * Copyright (C) 2016 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 "AirLowerAfterRegAlloc.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCCallingConvention.h"
-#include "AirCode.h"
-#include "AirEmitShuffle.h"
-#include "AirInsertionSet.h"
-#include "AirInstInlines.h"
-#include "AirLiveness.h"
-#include "AirPhaseScope.h"
-#include "AirRegisterPriority.h"
-#include "B3CCallValue.h"
-#include "B3ValueInlines.h"
-#include "RegisterSet.h"
-#include <wtf/HashMap.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-namespace {
-
-bool verbose = false;
-
-} // anonymous namespace
-
-void lowerAfterRegAlloc(Code& code)
-{
- PhaseScope phaseScope(code, "lowerAfterRegAlloc");
-
- if (verbose)
- dataLog("Code before lowerAfterRegAlloc:\n", code);
-
- HashMap<Inst*, RegisterSet> usedRegisters;
-
- RegLiveness liveness(code);
- for (BasicBlock* block : code) {
- RegLiveness::LocalCalc localCalc(liveness, block);
-
- for (unsigned instIndex = block->size(); instIndex--;) {
- Inst& inst = block->at(instIndex);
-
- RegisterSet set;
-
- bool isRelevant = inst.opcode == Shuffle || inst.opcode == ColdCCall;
-
- if (isRelevant) {
- for (Reg reg : localCalc.live())
- set.set(reg);
- }
-
- localCalc.execute(instIndex);
-
- if (isRelevant)
- usedRegisters.add(&inst, set);
- }
- }
-
- auto getScratches = [&] (RegisterSet set, Arg::Type type) -> std::array<Arg, 2> {
- std::array<Arg, 2> result;
- for (unsigned i = 0; i < 2; ++i) {
- bool found = false;
- for (Reg reg : regsInPriorityOrder(type)) {
- if (!set.get(reg)) {
- result[i] = Tmp(reg);
- set.set(reg);
- found = true;
- break;
- }
- }
- if (!found) {
- result[i] = Arg::stack(
- code.addStackSlot(
- Arg::bytes(Arg::conservativeWidth(type)),
- StackSlotKind::Spill));
- }
- }
- return result;
- };
-
- // Now transform the code.
- InsertionSet insertionSet(code);
- for (BasicBlock* block : code) {
- for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
- Inst& inst = block->at(instIndex);
-
- switch (inst.opcode) {
- case Shuffle: {
- RegisterSet set = usedRegisters.get(&inst);
- Vector<ShufflePair> pairs;
- for (unsigned i = 0; i < inst.args.size(); i += 3) {
- Arg src = inst.args[i + 0];
- Arg dst = inst.args[i + 1];
- Arg::Width width = inst.args[i + 2].width();
-
- // The used register set contains things live after the shuffle. But
- // emitShuffle() wants a scratch register that is not just dead but also does not
- // interfere with either sources or destinations.
- auto excludeRegisters = [&] (Tmp tmp) {
- if (tmp.isReg())
- set.set(tmp.reg());
- };
- src.forEachTmpFast(excludeRegisters);
- dst.forEachTmpFast(excludeRegisters);
-
- pairs.append(ShufflePair(src, dst, width));
- }
- std::array<Arg, 2> gpScratch = getScratches(set, Arg::GP);
- std::array<Arg, 2> fpScratch = getScratches(set, Arg::FP);
- insertionSet.insertInsts(
- instIndex, emitShuffle(pairs, gpScratch, fpScratch, inst.origin));
- inst = Inst();
- break;
- }
-
- case ColdCCall: {
- CCallValue* value = inst.origin->as<CCallValue>();
-
- RegisterSet liveRegs = usedRegisters.get(&inst);
- RegisterSet regsToSave = liveRegs;
- regsToSave.exclude(RegisterSet::calleeSaveRegisters());
- regsToSave.exclude(RegisterSet::stackRegisters());
- regsToSave.exclude(RegisterSet::reservedHardwareRegisters());
-
- RegisterSet preUsed = regsToSave;
- Vector<Arg> destinations = computeCCallingConvention(code, value);
- Tmp result = cCallResult(value->type());
- Arg originalResult = result ? inst.args[1] : Arg();
-
- Vector<ShufflePair> pairs;
- for (unsigned i = 0; i < destinations.size(); ++i) {
- Value* child = value->child(i);
- Arg src = inst.args[result ? (i >= 1 ? i + 1 : i) : i ];
- Arg dst = destinations[i];
- Arg::Width width = Arg::widthForB3Type(child->type());
- pairs.append(ShufflePair(src, dst, width));
-
- auto excludeRegisters = [&] (Tmp tmp) {
- if (tmp.isReg())
- preUsed.set(tmp.reg());
- };
- src.forEachTmpFast(excludeRegisters);
- dst.forEachTmpFast(excludeRegisters);
- }
-
- std::array<Arg, 2> gpScratch = getScratches(preUsed, Arg::GP);
- std::array<Arg, 2> fpScratch = getScratches(preUsed, Arg::FP);
-
- // Also need to save all live registers. Don't need to worry about the result
- // register.
- if (originalResult.isReg())
- regsToSave.clear(originalResult.reg());
- Vector<StackSlot*> stackSlots;
- regsToSave.forEach(
- [&] (Reg reg) {
- Tmp tmp(reg);
- Arg arg(tmp);
- Arg::Width width = Arg::conservativeWidth(arg.type());
- StackSlot* stackSlot =
- code.addStackSlot(Arg::bytes(width), StackSlotKind::Spill);
- pairs.append(ShufflePair(arg, Arg::stack(stackSlot), width));
- stackSlots.append(stackSlot);
- });
-
- if (verbose)
- dataLog("Pre-call pairs for ", inst, ": ", listDump(pairs), "\n");
-
- insertionSet.insertInsts(
- instIndex, emitShuffle(pairs, gpScratch, fpScratch, inst.origin));
-
- inst = buildCCall(code, inst.origin, destinations);
-
- // Now we need to emit code to restore registers.
- pairs.resize(0);
- unsigned stackSlotIndex = 0;
- regsToSave.forEach(
- [&] (Reg reg) {
- Tmp tmp(reg);
- Arg arg(tmp);
- Arg::Width width = Arg::conservativeWidth(arg.type());
- StackSlot* stackSlot = stackSlots[stackSlotIndex++];
- pairs.append(ShufflePair(Arg::stack(stackSlot), arg, width));
- });
- if (result) {
- ShufflePair pair(result, originalResult, Arg::widthForB3Type(value->type()));
- pairs.append(pair);
- }
-
- // For finding scratch registers, we need to account for the possibility that
- // the result is dead.
- if (originalResult.isReg())
- liveRegs.set(originalResult.reg());
-
- gpScratch = getScratches(liveRegs, Arg::GP);
- fpScratch = getScratches(liveRegs, Arg::FP);
-
- insertionSet.insertInsts(
- instIndex + 1, emitShuffle(pairs, gpScratch, fpScratch, inst.origin));
- break;
- }
-
- default:
- break;
- }
- }
-
- insertionSet.execute(block);
-
- block->insts().removeAllMatching(
- [&] (Inst& inst) -> bool {
- return !inst;
- });
- }
-
- if (verbose)
- dataLog("Code after lowerAfterRegAlloc:\n", code);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirLowerAfterRegAlloc.h b/Source/JavaScriptCore/b3/air/AirLowerAfterRegAlloc.h
deleted file mode 100644
index ae29b74ff..000000000
--- a/Source/JavaScriptCore/b3/air/AirLowerAfterRegAlloc.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef AirLowerAfterRegAlloc_h
-#define AirLowerAfterRegAlloc_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// This lowers Shuffle and ColdCCall instructions. This phase is designed to be run after register
-// allocation.
-
-void lowerAfterRegAlloc(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirLowerAfterRegAlloc_h
diff --git a/Source/JavaScriptCore/b3/air/AirLowerMacros.cpp b/Source/JavaScriptCore/b3/air/AirLowerMacros.cpp
deleted file mode 100644
index 12bd89d24..000000000
--- a/Source/JavaScriptCore/b3/air/AirLowerMacros.cpp
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2016 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 "AirLowerMacros.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCCallingConvention.h"
-#include "AirCode.h"
-#include "AirInsertionSet.h"
-#include "AirInstInlines.h"
-#include "AirPhaseScope.h"
-#include "B3CCallValue.h"
-#include "B3ValueInlines.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-void lowerMacros(Code& code)
-{
- PhaseScope phaseScope(code, "lowerMacros");
-
- InsertionSet insertionSet(code);
- for (BasicBlock* block : code) {
- for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
- Inst& inst = block->at(instIndex);
-
- switch (inst.opcode) {
- case CCall: {
- CCallValue* value = inst.origin->as<CCallValue>();
-
- Vector<Arg> destinations = computeCCallingConvention(code, value);
-
- Inst shuffleArguments(Shuffle, value);
- unsigned offset = value->type() == Void ? 0 : 1;
- for (unsigned i = 1; i < destinations.size(); ++i) {
- Value* child = value->child(i);
- shuffleArguments.args.append(inst.args[offset + i]);
- shuffleArguments.args.append(destinations[i]);
- shuffleArguments.args.append(Arg::widthArg(Arg::widthForB3Type(child->type())));
- }
- insertionSet.insertInst(instIndex, WTFMove(shuffleArguments));
-
- // Indicate that we're using our original callee argument.
- destinations[0] = inst.args[0];
-
- // Save where the original instruction put its result.
- Arg resultDst = value->type() == Void ? Arg() : inst.args[1];
-
- inst = buildCCall(code, inst.origin, destinations);
-
- Tmp result = cCallResult(value->type());
- switch (value->type()) {
- case Void:
- break;
- case Float:
- insertionSet.insert(instIndex + 1, MoveFloat, value, result, resultDst);
- break;
- case Double:
- insertionSet.insert(instIndex + 1, MoveDouble, value, result, resultDst);
- break;
- case Int32:
- insertionSet.insert(instIndex + 1, Move32, value, result, resultDst);
- break;
- case Int64:
- insertionSet.insert(instIndex + 1, Move, value, result, resultDst);
- break;
- }
- break;
- }
-
- default:
- break;
- }
- }
- insertionSet.execute(block);
- }
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirLowerMacros.h b/Source/JavaScriptCore/b3/air/AirLowerMacros.h
deleted file mode 100644
index fa2d11d89..000000000
--- a/Source/JavaScriptCore/b3/air/AirLowerMacros.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2016 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.
- */
-
-#ifndef AirLowerMacros_h
-#define AirLowerMacros_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// Air has some opcodes that are very high-level and are meant to reduce the amount of low-level
-// knowledge in the B3->Air lowering. The current example is CCall.
-
-void lowerMacros(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirLowerMacros_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirOpcode.opcodes b/Source/JavaScriptCore/b3/air/AirOpcode.opcodes
deleted file mode 100644
index 46a5cf71f..000000000
--- a/Source/JavaScriptCore/b3/air/AirOpcode.opcodes
+++ /dev/null
@@ -1,850 +0,0 @@
-# Copyright (C) 2015-2016 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. AND ITS CONTRIBUTORS ``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 ITS 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.
-
-# Syllabus:
-#
-# Examples of some roles, types, and widths:
-# U:G:32 => use of the low 32 bits of a general-purpose register or value
-# D:G:32 => def of the low 32 bits of a general-purpose register or value
-# UD:G:32 => use and def of the low 32 bits of a general-purpose register or value
-# U:G:64 => use of the low 64 bits of a general-purpose register or value
-# ZD:G:32 => def of all bits of a general-purpose register, where all but the low 32 bits are guaranteed to be zeroed.
-# UA:G:Ptr => UseAddr (see comment in Arg.h)
-# U:F:32 => use of a float register or value
-# U:F:64 => use of a double register or value
-# D:F:32 => def of a float register or value
-# UD:F:32 => use and def of a float register or value
-# S:F:32 => scratch float register.
-#
-# Argument kinds:
-# Tmp => temporary or register
-# Imm => 32-bit immediate int
-# BigImm => TrustedImm64
-# Addr => address as temporary/register+offset
-# Index => BaseIndex address
-# Abs => AbsoluteAddress
-#
-# The parser views these things as keywords, and understands that they fall into two distinct classes
-# of things. So, although this file uses a particular indentation style, none of the whitespace or
-# even newlines are meaningful to the parser. For example, you could write:
-#
-# Foo42 U:G:32, UD:F:32 Imm, Tmp Addr, Tmp
-#
-# And the parser would know that this is the same as:
-#
-# Foo42 U:G:32, UD:F:32
-# Imm, Tmp
-# Addr, Tmp
-#
-# I.e. a two-form instruction that uses a GPR or an int immediate and uses+defs a float register.
-#
-# Any opcode or opcode form can be preceded with an architecture list, which restricts the opcode to the
-# union of those architectures. For example, if this is the only overload of the opcode, then it makes the
-# opcode only available on x86_64:
-#
-# x86_64: Fuzz UD:G:64, D:G:64
-# Tmp, Tmp
-# Tmp, Addr
-#
-# But this only restricts the two-operand form, the other form is allowed on all architectures:
-#
-# x86_64: Fuzz UD:G:64, D:G:64
-# Tmp, Tmp
-# Tmp, Addr
-# Fuzz UD:G:Ptr, D:G:Ptr, U:F:Ptr
-# Tmp, Tmp, Tmp
-# Tmp, Addr, Tmp
-#
-# And you can also restrict individual forms:
-#
-# Thingy UD:G:32, D:G:32
-# Tmp, Tmp
-# arm64: Tmp, Addr
-#
-# Additionally, you can have an intersection between the architectures of the opcode overload and the
-# form. In this example, the version that takes an address is only available on armv7 while the other
-# versions are available on armv7 or x86_64:
-#
-# x86_64 armv7: Buzz U:G:32, UD:F:32
-# Tmp, Tmp
-# Imm, Tmp
-# armv7: Addr, Tmp
-#
-# Finally, you can specify architectures using helpful architecture groups. Here are all of the
-# architecture keywords that we support:
-#
-# x86: means x86-32 or x86-64.
-# x86_32: means just x86-32.
-# x86_64: means just x86-64.
-# arm: means armv7 or arm64.
-# armv7: means just armv7.
-# arm64: means just arm64.
-# 32: means x86-32 or armv7.
-# 64: means x86-64 or arm64.
-
-# Note that the opcodes here have a leading capital (Add32) but must correspond to MacroAssembler
-# API that has a leading lower-case (add32).
-
-Nop
-
-Add32 U:G:32, U:G:32, ZD:G:32
- Imm, Tmp, Tmp
- Tmp, Tmp, Tmp
-
-Add32 U:G:32, UZD:G:32
- Tmp, Tmp
- x86: Imm, Addr
- x86: Imm, Index
- Imm, Tmp
- x86: Addr, Tmp
- x86: Tmp, Addr
- x86: Tmp, Index
-
-x86: Add8 U:G:8, UD:G:8
- Imm, Addr
- Imm, Index
- Tmp, Addr
- Tmp, Index
-
-x86: Add16 U:G:16, UD:G:16
- Imm, Addr
- Imm, Index
- Tmp, Addr
- Tmp, Index
-
-64: Add64 U:G:64, UD:G:64
- Tmp, Tmp
- x86: Imm, Addr
- Imm, Tmp
- x86: Addr, Tmp
- x86: Tmp, Addr
-
-64: Add64 U:G:64, U:G:64, D:G:64
- Imm, Tmp, Tmp
- Tmp, Tmp, Tmp
-
-AddDouble U:F:64, U:F:64, D:F:64
- Tmp, Tmp, Tmp
- x86: Addr, Tmp, Tmp
- x86: Tmp, Addr, Tmp
-
-x86: AddDouble U:F:64, UD:F:64
- Tmp, Tmp
- Addr, Tmp
-
-AddFloat U:F:32, U:F:32, D:F:32
- Tmp, Tmp, Tmp
- x86: Addr, Tmp, Tmp
- x86: Tmp, Addr, Tmp
-
-x86: AddFloat U:F:32, UD:F:32
- Tmp, Tmp
- Addr, Tmp
-
-Sub32 U:G:32, UZD:G:32
- Tmp, Tmp
- x86: Imm, Addr
- Imm, Tmp
- x86: Addr, Tmp
- x86: Tmp, Addr
-
-64: Sub64 U:G:64, UD:G:64
- Tmp, Tmp
- x86: Imm, Addr
- Imm, Tmp
- x86: Addr, Tmp
- x86: Tmp, Addr
-
-arm64: SubDouble U:F:64, U:F:64, D:F:64
- Tmp, Tmp, Tmp
-
-x86: SubDouble U:F:64, UD:F:64
- Tmp, Tmp
- Addr, Tmp
-
-arm64: SubFloat U:F:32, U:F:32, D:F:32
- Tmp, Tmp, Tmp
-
-x86: SubFloat U:F:32, UD:F:32
- Tmp, Tmp
- Addr, Tmp
-
-Neg32 UZD:G:32
- Tmp
- x86: Addr
-
-64: Neg64 UD:G:64
- Tmp
-
-arm64: NegateDouble U:F:64, D:F:64
- Tmp, Tmp
-
-Mul32 U:G:32, UZD:G:32
- Tmp, Tmp
- x86: Addr, Tmp
-
-Mul32 U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp
- x86: Addr, Tmp, Tmp
- x86: Tmp, Addr, Tmp
- x86: Imm, Tmp, Tmp
-
-64: Mul64 U:G:64, UD:G:64
- Tmp, Tmp
-
-Mul64 U:G:64, U:G:64, D:G:64
- Tmp, Tmp, Tmp
-
-arm64: MultiplyAdd32 U:G:32, U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp, Tmp
-
-arm64: MultiplyAdd64 U:G:64, U:G:64, U:G:64, D:G:64
- Tmp, Tmp, Tmp, Tmp
-
-arm64: MultiplySub32 U:G:32, U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp, Tmp
-
-arm64: MultiplySub64 U:G:64, U:G:64, U:G:64, D:G:64
- Tmp, Tmp, Tmp, Tmp
-
-arm64: MultiplyNeg32 U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp
-
-arm64: MultiplyNeg64 U:G:64, U:G:64, ZD:G:64
- Tmp, Tmp, Tmp
-
-arm64: Div32 U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp
-
-arm64: Div64 U:G:64, U:G:64, D:G:64
- Tmp, Tmp, Tmp
-
-MulDouble U:F:64, U:F:64, D:F:64
- Tmp, Tmp, Tmp
- x86: Addr, Tmp, Tmp
- x86: Tmp, Addr, Tmp
-
-x86: MulDouble U:F:64, UD:F:64
- Tmp, Tmp
- Addr, Tmp
-
-MulFloat U:F:32, U:F:32, D:F:32
- Tmp, Tmp, Tmp
- x86: Addr, Tmp, Tmp
- x86: Tmp, Addr, Tmp
-
-x86: MulFloat U:F:32, UD:F:32
- Tmp, Tmp
- Addr, Tmp
-
-arm64: DivDouble U:F:64, U:F:32, D:F:64
- Tmp, Tmp, Tmp
-
-x86: DivDouble U:F:64, UD:F:64
- Tmp, Tmp
- Addr, Tmp
-
-arm64: DivFloat U:F:32, U:F:32, D:F:32
- Tmp, Tmp, Tmp
-
-x86: DivFloat U:F:32, UD:F:32
- Tmp, Tmp
- Addr, Tmp
-
-x86: X86ConvertToDoubleWord32 U:G:32, ZD:G:32
- Tmp*, Tmp*
-
-x86_64: X86ConvertToQuadWord64 U:G:64, D:G:64
- Tmp*, Tmp*
-
-x86: X86Div32 UZD:G:32, UZD:G:32, U:G:32
- Tmp*, Tmp*, Tmp
-
-x86_64: X86Div64 UZD:G:64, UZD:G:64, U:G:64
- Tmp*, Tmp*, Tmp
-
-Lea UA:G:Ptr, D:G:Ptr
- Addr, Tmp
-
-And32 U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp
- arm64: BitImm, Tmp, Tmp
- x86: Tmp, Addr, Tmp
- x86: Addr, Tmp, Tmp
-
-And32 U:G:32, UZD:G:32
- Tmp, Tmp
- x86: Imm, Tmp
- x86: Tmp, Addr
- x86: Addr, Tmp
- x86: Imm, Addr
-
-64: And64 U:G:64, U:G:64, D:G:64
- Tmp, Tmp, Tmp
- arm64: BitImm64, Tmp, Tmp
-
-x86_64: And64 U:G:64, UD:G:64
- Tmp, Tmp
- x86: Imm, Tmp
-
-AndDouble U:F:64, U:F:64, D:F:64
- Tmp, Tmp, Tmp
-
-x86: AndDouble U:F:64, UD:F:64
- Tmp, Tmp
-
-AndFloat U:F:32, U:F:32, D:F:32
- Tmp, Tmp, Tmp
-
-x86: AndFloat U:F:32, UD:F:32
- Tmp, Tmp
-
-x86: XorDouble U:F:64, U:F:64, D:F:64
- Tmp, Tmp, Tmp
-
-x86: XorDouble U:F:64, UD:F:64
- Tmp, Tmp
-
-x86: XorFloat U:F:32, U:F:32, D:F:32
- Tmp, Tmp, Tmp
-
-x86: XorFloat U:F:32, UD:F:32
- Tmp, Tmp
-
-arm64: Lshift32 U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp
- Tmp, Imm, Tmp
-
-x86:Lshift32 U:G:32, UZD:G:32
- Tmp*, Tmp
- Imm, Tmp
-
-arm64: Lshift64 U:G:64, U:G:64, ZD:G:64
- Tmp, Tmp, Tmp
- Tmp, Imm, Tmp
-
-x86_64: Lshift64 U:G:64, UD:G:64
- Tmp*, Tmp
- Imm, Tmp
-
-arm64: Rshift32 U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp
- Tmp, Imm, Tmp
-
-x86: Rshift32 U:G:32, UZD:G:32
- Tmp*, Tmp
- Imm, Tmp
-
-arm64: Rshift64 U:G:64, U:G:64, ZD:G:64
- Tmp, Tmp, Tmp
- Tmp, Imm, Tmp
-
-x86_64: Rshift64 U:G:64, UD:G:64
- Tmp*, Tmp
- Imm, Tmp
-
-arm64: Urshift32 U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp
- Tmp, Imm, Tmp
-
-x86: Urshift32 U:G:32, UZD:G:32
- Tmp*, Tmp
- Imm, Tmp
-
-arm64: Urshift64 U:G:64, U:G:64, ZD:G:64
- Tmp, Tmp, Tmp
- Tmp, Imm, Tmp
-
-x86_64: Urshift64 U:G:64, UD:G:64
- Tmp*, Tmp
- Imm, Tmp
-
-Or32 U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp
- arm64: BitImm, Tmp, Tmp
- x86: Tmp, Addr, Tmp
- x86: Addr, Tmp, Tmp
-
-Or32 U:G:32, UZD:G:32
- Tmp, Tmp
- x86: Imm, Tmp
- x86: Tmp, Addr
- x86: Addr, Tmp
- x86: Imm, Addr
-
-64: Or64 U:G:64, U:G:64, D:G:64
- Tmp, Tmp, Tmp
- arm64: BitImm64, Tmp, Tmp
-
-64: Or64 U:G:64, UD:G:64
- Tmp, Tmp
- x86: Imm, Tmp
-
-Xor32 U:G:32, U:G:32, ZD:G:32
- Tmp, Tmp, Tmp
- arm64: BitImm, Tmp, Tmp
- x86: Tmp, Addr, Tmp
- x86: Addr, Tmp, Tmp
-
-Xor32 U:G:32, UZD:G:32
- Tmp, Tmp
- x86: Imm, Tmp
- x86: Tmp, Addr
- x86: Addr, Tmp
- x86: Imm, Addr
-
-64: Xor64 U:G:64, U:G:64, D:G:64
- Tmp, Tmp, Tmp
- arm64: BitImm64, Tmp, Tmp
-
-64: Xor64 U:G:64, UD:G:64
- Tmp, Tmp
- x86: Tmp, Addr
- x86: Imm, Tmp
-
-arm64: Not32 U:G:32, ZD:G:32
- Tmp, Tmp
-
-x86: Not32 UZD:G:32
- Tmp
- Addr
-
-arm64: Not64 U:G:64, D:G:64
- Tmp, Tmp
-
-x86: Not64 UD:G:64
- Tmp
- Addr
-
-arm64: AbsDouble U:F:64, D:F:64
- Tmp, Tmp
-
-arm64: AbsFloat U:F:32, D:F:32
- Tmp, Tmp
-
-CeilDouble U:F:64, D:F:64
- Tmp, Tmp
- x86: Addr, Tmp
-
-CeilFloat U:F:32, D:F:32
- Tmp, Tmp
- x86: Addr, Tmp
-
-FloorDouble U:F:64, D:F:64
- Tmp, Tmp
- x86: Addr, Tmp
-
-FloorFloat U:F:32, D:F:32
- Tmp, Tmp
- x86: Addr, Tmp
-
-SqrtDouble U:F:64, D:F:64
- Tmp, Tmp
- x86: Addr, Tmp
-
-SqrtFloat U:F:32, D:F:32
- Tmp, Tmp
- x86: Addr, Tmp
-
-ConvertInt32ToDouble U:G:32, D:F:64
- Tmp, Tmp
- x86: Addr, Tmp
-
-64: ConvertInt64ToDouble U:G:64, D:F:64
- Tmp, Tmp
-
-CountLeadingZeros32 U:G:32, ZD:G:32
- Tmp, Tmp
- x86: Addr, Tmp
-
-64: CountLeadingZeros64 U:G:64, D:G:64
- Tmp, Tmp
- x86: Addr, Tmp
-
-ConvertDoubleToFloat U:F:64, D:F:32
- Tmp, Tmp
- x86: Addr, Tmp
-
-ConvertFloatToDouble U:F:32, D:F:64
- Tmp, Tmp
- x86: Addr, Tmp
-
-# Note that Move operates over the full register size, which is either 32-bit or 64-bit depending on
-# the platform. I'm not entirely sure that this is a good thing; it might be better to just have a
-# Move64 instruction. OTOH, our MacroAssemblers already have this notion of "move()" that basically
-# means movePtr.
-Move U:G:Ptr, D:G:Ptr
- Tmp, Tmp
- Imm, Tmp as signExtend32ToPtr
- BigImm, Tmp
- Addr, Tmp as loadPtr # This means that "Move Addr, Tmp" is code-generated as "load" not "move".
- Index, Tmp as loadPtr
- Tmp, Addr as storePtr
- Tmp, Index as storePtr
- x86: Imm, Addr as storePtr
-
-x86: Swap32 UD:G:32, UD:G:32
- Tmp, Tmp
- Tmp, Addr
-
-x86_64: Swap64 UD:G:64, UD:G:64
- Tmp, Tmp
- Tmp, Addr
-
-Move32 U:G:32, ZD:G:32
- Tmp, Tmp as zeroExtend32ToPtr
- Addr, Tmp as load32
- Index, Tmp as load32
- Tmp, Addr as store32
- Tmp, Index as store32
- x86: Imm, Tmp as zeroExtend32ToPtr
- x86: Imm, Addr as store32
- x86: Imm, Index as store32
-
-StoreZero32 U:G:32
- Addr
- Index
-
-SignExtend32ToPtr U:G:32, D:G:Ptr
- Tmp, Tmp
-
-ZeroExtend8To32 U:G:8, ZD:G:32
- Tmp, Tmp
- x86: Addr, Tmp as load8
- x86: Index, Tmp as load8
-
-SignExtend8To32 U:G:8, ZD:G:32
- Tmp, Tmp
- x86: Addr, Tmp as load8SignedExtendTo32
- x86: Index, Tmp as load8SignedExtendTo32
-
-ZeroExtend16To32 U:G:16, ZD:G:32
- Tmp, Tmp
- x86: Addr, Tmp as load16
- x86: Index, Tmp as load16
-
-SignExtend16To32 U:G:16, ZD:G:32
- Tmp, Tmp
- x86: Addr, Tmp as load16SignedExtendTo32
- x86: Index, Tmp as load16SignedExtendTo32
-
-MoveFloat U:F:32, D:F:32
- Tmp, Tmp as moveDouble
- Addr, Tmp as loadFloat
- Index, Tmp as loadFloat
- Tmp, Addr as storeFloat
- Tmp, Index as storeFloat
-
-MoveDouble U:F:64, D:F:64
- Tmp, Tmp
- Addr, Tmp as loadDouble
- Index, Tmp as loadDouble
- Tmp, Addr as storeDouble
- Tmp, Index as storeDouble
-
-MoveZeroToDouble D:F:64
- Tmp
-
-64: Move64ToDouble U:G:64, D:F:64
- Tmp, Tmp
- x86: Addr, Tmp as loadDouble
- Index, Tmp as loadDouble
-
-Move32ToFloat U:G:32, D:F:32
- Tmp, Tmp
- x86: Addr, Tmp as loadFloat
- Index, Tmp as loadFloat
-
-64: MoveDoubleTo64 U:F:64, D:G:64
- Tmp, Tmp
- Addr, Tmp as load64
- Index, Tmp as load64
-
-MoveFloatTo32 U:F:32, D:G:32
- Tmp, Tmp
- Addr, Tmp as load32
- Index, Tmp as load32
-
-Load8 U:G:8, ZD:G:32
- Addr, Tmp
- Index, Tmp
-
-Store8 U:G:8, D:G:8
- Tmp, Index
- Tmp, Addr
- x86: Imm, Index
- x86: Imm, Addr
-
-Load8SignedExtendTo32 U:G:8, ZD:G:32
- Addr, Tmp
- Index, Tmp
-
-Load16 U:G:16, ZD:G:32
- Addr, Tmp
- Index, Tmp
-
-Load16SignedExtendTo32 U:G:16, ZD:G:32
- Addr, Tmp
- Index, Tmp
-
-Store16 U:G:16, D:G:16
- Tmp, Index
- Tmp, Addr
-
-Compare32 U:G:32, U:G:32, U:G:32, ZD:G:32
- RelCond, Tmp, Tmp, Tmp
- RelCond, Tmp, Imm, Tmp
-
-64: Compare64 U:G:32, U:G:64, U:G:64, ZD:G:32
- RelCond, Tmp, Tmp, Tmp
- x86: RelCond, Tmp, Imm, Tmp
-
-Test32 U:G:32, U:G:32, U:G:32, ZD:G:32
- x86: ResCond, Addr, Imm, Tmp
- ResCond, Tmp, Tmp, Tmp
- ResCond, Tmp, BitImm, Tmp
-
-64: Test64 U:G:32, U:G:64, U:G:64, ZD:G:32
- x86: ResCond, Tmp, Imm, Tmp
- ResCond, Tmp, Tmp, Tmp
-
-CompareDouble U:G:32, U:F:64, U:F:64, ZD:G:32
- DoubleCond, Tmp, Tmp, Tmp
-
-CompareFloat U:G:32, U:F:32, U:F:32, ZD:G:32
- DoubleCond, Tmp, Tmp, Tmp
-
-# Note that branches have some logic in AirOptimizeBlockOrder.cpp. If you add new branches, please make sure
-# you opt them into the block order optimizations.
-
-Branch8 U:G:32, U:G:8, U:G:8 /branch
- x86: RelCond, Addr, Imm
- x86: RelCond, Index, Imm
-
-Branch32 U:G:32, U:G:32, U:G:32 /branch
- x86: RelCond, Addr, Imm
- RelCond, Tmp, Tmp
- RelCond, Tmp, Imm
- x86: RelCond, Tmp, Addr
- x86: RelCond, Addr, Tmp
- x86: RelCond, Index, Imm
-
-64: Branch64 U:G:32, U:G:64, U:G:64 /branch
- RelCond, Tmp, Tmp
- RelCond, Tmp, Imm
- x86: RelCond, Tmp, Addr
- x86: RelCond, Addr, Tmp
- x86: RelCond, Addr, Imm
- x86: RelCond, Index, Tmp
-
-BranchTest8 U:G:32, U:G:8, U:G:8 /branch
- x86: ResCond, Addr, Imm
- x86: ResCond, Index, Imm
-
-BranchTest32 U:G:32, U:G:32, U:G:32 /branch
- ResCond, Tmp, Tmp
- ResCond, Tmp, BitImm
- x86: ResCond, Addr, Imm
- x86: ResCond, Index, Imm
-
-# Warning: forms that take an immediate will sign-extend their immediate. You probably want
-# BranchTest32 in most cases where you use an immediate.
-64: BranchTest64 U:G:32, U:G:64, U:G:64 /branch
- ResCond, Tmp, Tmp
- ResCond, Tmp, BitImm64
- x86: ResCond, Addr, Imm
- x86: ResCond, Addr, Tmp
- x86: ResCond, Index, Imm
-
-BranchDouble U:G:32, U:F:64, U:F:64 /branch
- DoubleCond, Tmp, Tmp
-
-BranchFloat U:G:32, U:F:32, U:F:32 /branch
- DoubleCond, Tmp, Tmp
-
-BranchAdd32 U:G:32, U:G:32, U:G:32, ZD:G:32 /branch
- ResCond, Tmp, Tmp, Tmp
- x86:ResCond, Tmp, Addr, Tmp
- x86:ResCond, Addr, Tmp, Tmp
-
-BranchAdd32 U:G:32, U:G:32, UZD:G:32 /branch
- ResCond, Tmp, Tmp
- ResCond, Imm, Tmp
- x86: ResCond, Imm, Addr
- x86: ResCond, Tmp, Addr
- x86: ResCond, Addr, Tmp
-
-BranchAdd64 U:G:32, U:G:64, U:G:64, ZD:G:64 /branch
- ResCond, Tmp, Tmp, Tmp
- x86:ResCond, Tmp, Addr, Tmp
- x86:ResCond, Addr, Tmp, Tmp
-
-64: BranchAdd64 U:G:32, U:G:64, UD:G:64 /branch
- ResCond, Imm, Tmp
- ResCond, Tmp, Tmp
- x86:ResCond, Addr, Tmp
-
-x86: BranchMul32 U:G:32, U:G:32, UZD:G:32 /branch
- ResCond, Tmp, Tmp
- ResCond, Addr, Tmp
-
-x86: BranchMul32 U:G:32, U:G:32, U:G:32, ZD:G:32 /branch
- ResCond, Tmp, Imm, Tmp
-
-arm64: BranchMul32 U:G:32, U:G:32, U:G:32, S:G:32, S:G:32, ZD:G:32 /branch
- ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
-
-x86_64: BranchMul64 U:G:32, U:G:64, UZD:G:64 /branch
- ResCond, Tmp, Tmp
-
-arm64: BranchMul64 U:G:32, U:G:64, U:G:64, S:G:64, S:G:64, ZD:G:64 /branch
- ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
-
-BranchSub32 U:G:32, U:G:32, UZD:G:32 /branch
- ResCond, Tmp, Tmp
- ResCond, Imm, Tmp
- x86: ResCond, Imm, Addr
- x86: ResCond, Tmp, Addr
- x86: ResCond, Addr, Tmp
-
-64: BranchSub64 U:G:32, U:G:64, UD:G:64 /branch
- ResCond, Imm, Tmp
- ResCond, Tmp, Tmp
-
-BranchNeg32 U:G:32, UZD:G:32 /branch
- ResCond, Tmp
-
-64: BranchNeg64 U:G:32, UZD:G:64 /branch
- ResCond, Tmp
-
-MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
- RelCond, Tmp, Tmp, Tmp, Tmp
-
-MoveConditionally32 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
- RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
- RelCond, Tmp, Imm, Tmp, Tmp, Tmp
-
-64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
- RelCond, Tmp, Tmp, Tmp, Tmp
-
-64: MoveConditionally64 U:G:32, U:G:64, U:G:64, U:G:Ptr, U:G:Ptr, D:G:Ptr
- RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
- RelCond, Tmp, Imm, Tmp, Tmp, Tmp
-
-MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, UD:G:Ptr
- ResCond, Tmp, Tmp, Tmp, Tmp
- x86: ResCond, Tmp, Imm, Tmp, Tmp
-
-MoveConditionallyTest32 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
- ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
- ResCond, Tmp, BitImm, Tmp, Tmp, Tmp
-
-64: MoveConditionallyTest64 U:G:32, U:G:64, U:G:64, U:G:Ptr, UD:G:Ptr
- ResCond, Tmp, Tmp, Tmp, Tmp
- x86: ResCond, Tmp, Imm, Tmp, Tmp
-
-64: MoveConditionallyTest64 U:G:32, U:G:32, U:G:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
- ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
- x86_64: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
-
-MoveConditionallyDouble U:G:32, U:F:64, U:F:64, U:G:Ptr, U:G:Ptr, D:G:Ptr
- DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
-
-MoveConditionallyDouble U:G:32, U:F:64, U:F:64, U:G:Ptr, UD:G:Ptr
- DoubleCond, Tmp, Tmp, Tmp, Tmp
-
-MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, U:G:Ptr, D:G:Ptr
- DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
-
-MoveConditionallyFloat U:G:32, U:F:32, U:F:32, U:G:Ptr, UD:G:Ptr
- DoubleCond, Tmp, Tmp, Tmp, Tmp
-
-MoveDoubleConditionally32 U:G:32, U:G:32, U:G:32, U:F:64, U:F:64, D:F:64
- RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
- RelCond, Tmp, Imm, Tmp, Tmp, Tmp
- x86: RelCond, Addr, Imm, Tmp, Tmp, Tmp
- x86: RelCond, Tmp, Addr, Tmp, Tmp, Tmp
- x86: RelCond, Addr, Tmp, Tmp, Tmp, Tmp
- x86: RelCond, Index, Imm, Tmp, Tmp, Tmp
-
-64: MoveDoubleConditionally64 U:G:32, U:G:64, U:G:64, U:F:64, U:F:64, D:F:64
- RelCond, Tmp, Tmp, Tmp, Tmp, Tmp
- RelCond, Tmp, Imm, Tmp, Tmp, Tmp
- x86_64: RelCond, Tmp, Addr, Tmp, Tmp, Tmp
- x86_64: RelCond, Addr, Tmp, Tmp, Tmp, Tmp
- x86_64: RelCond, Addr, Imm, Tmp, Tmp, Tmp
- x86_64: RelCond, Index, Tmp, Tmp, Tmp, Tmp
-
-MoveDoubleConditionallyTest32 U:G:32, U:G:32, U:G:32, U:F:64, U:F:64, D:F:64
- ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
- ResCond, Tmp, BitImm, Tmp, Tmp, Tmp
- x86: ResCond, Addr, Imm, Tmp, Tmp, Tmp
- x86: ResCond, Index, Imm, Tmp, Tmp, Tmp
-
-# Warning: forms that take an immediate will sign-extend their immediate. You probably want
-# MoveDoubleConditionallyTest32 in most cases where you use an immediate.
-64: MoveDoubleConditionallyTest64 U:G:32, U:G:64, U:G:64, U:F:64, U:F:64, D:F:64
- ResCond, Tmp, Tmp, Tmp, Tmp, Tmp
- x86_64: ResCond, Tmp, Imm, Tmp, Tmp, Tmp
- x86_64: ResCond, Addr, Imm, Tmp, Tmp, Tmp
- x86_64: ResCond, Addr, Tmp, Tmp, Tmp, Tmp
- x86_64: ResCond, Index, Imm, Tmp, Tmp, Tmp
-
-MoveDoubleConditionallyDouble U:G:32, U:F:64, U:F:64, U:F:64, U:F:64, D:F:64
- DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
-
-MoveDoubleConditionallyFloat U:G:32, U:F:32, U:F:32, U:F:64, U:F:64, D:F:64
- DoubleCond, Tmp, Tmp, Tmp, Tmp, Tmp
-
-Jump /branch
-
-Ret32 U:G:32 /return
- Tmp
-
-64: Ret64 U:G:64 /return
- Tmp
-
-RetFloat U:F:32 /return
- Tmp
-
-RetDouble U:F:64 /return
- Tmp
-
-Oops /terminal
-
-# A Shuffle is a multi-source, multi-destination move. It simultaneously does multiple moves at once.
-# The moves are specified as triplets of src, dst, and width. For example you can request a swap this
-# way:
-# Shuffle %tmp1, %tmp2, 64, %tmp2, %tmp1, 64
-custom Shuffle
-
-# Air allows for exotic behavior. A Patch's behavior is determined entirely by the Special operand,
-# which must be the first operand.
-custom Patch
-
-# Instructions used for lowering C calls. These don't make it to Air generation. They get lowered to
-# something else first. The origin Value must be a CCallValue.
-custom CCall
-custom ColdCCall
-
-
diff --git a/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp b/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp
deleted file mode 100644
index 3e84a0bd8..000000000
--- a/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.cpp
+++ /dev/null
@@ -1,182 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirOptimizeBlockOrder.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirBlockWorklist.h"
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include "AirPhaseScope.h"
-#include <wtf/BubbleSort.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-namespace {
-
-class SortedSuccessors {
-public:
- SortedSuccessors()
- {
- }
-
- void append(BasicBlock* block)
- {
- m_successors.append(block);
- }
-
- void process(BlockWorklist& worklist)
- {
- // We prefer a stable sort, and we don't want it to go off the rails if we see NaN. Also, the number
- // of successors is bounded. In fact, it currently cannot be more than 2. :-)
- bubbleSort(
- m_successors.begin(), m_successors.end(),
- [] (BasicBlock* left, BasicBlock* right) {
- return left->frequency() < right->frequency();
- });
-
- // Pushing the successors in ascending order of frequency ensures that the very next block we visit
- // is our highest-frequency successor (unless that successor has already been visited).
- for (unsigned i = 0; i < m_successors.size(); ++i)
- worklist.push(m_successors[i]);
-
- m_successors.resize(0);
- }
-
-private:
- Vector<BasicBlock*, 2> m_successors;
-};
-
-} // anonymous namespace
-
-Vector<BasicBlock*> blocksInOptimizedOrder(Code& code)
-{
- Vector<BasicBlock*> blocksInOrder;
-
- BlockWorklist fastWorklist;
- SortedSuccessors sortedSuccessors;
- SortedSuccessors sortedSlowSuccessors;
-
- fastWorklist.push(code[0]);
-
- while (BasicBlock* block = fastWorklist.pop()) {
- blocksInOrder.append(block);
- for (FrequentedBlock& successor : block->successors()) {
- if (successor.isRare())
- sortedSlowSuccessors.append(successor.block());
- else
- sortedSuccessors.append(successor.block());
- }
- sortedSuccessors.process(fastWorklist);
- }
-
- BlockWorklist slowWorklist;
- sortedSlowSuccessors.process(slowWorklist);
-
- while (BasicBlock* block = slowWorklist.pop()) {
- // We might have already processed this block.
- if (fastWorklist.saw(block))
- continue;
-
- blocksInOrder.append(block);
- for (BasicBlock* successor : block->successorBlocks())
- sortedSuccessors.append(successor);
- sortedSuccessors.process(slowWorklist);
- }
-
- ASSERT(fastWorklist.isEmpty());
- ASSERT(slowWorklist.isEmpty());
-
- return blocksInOrder;
-}
-
-void optimizeBlockOrder(Code& code)
-{
- PhaseScope phaseScope(code, "optimizeBlockOrder");
-
- Vector<BasicBlock*> blocksInOrder = blocksInOptimizedOrder(code);
-
- // Place blocks into Code's block list according to the ordering in blocksInOrder. We do this by leaking
- // all of the blocks and then readopting them.
- for (auto& entry : code.blockList())
- entry.release();
-
- code.blockList().resize(0);
-
- for (unsigned i = 0; i < blocksInOrder.size(); ++i) {
- BasicBlock* block = blocksInOrder[i];
- block->setIndex(i);
- code.blockList().append(std::unique_ptr<BasicBlock>(block));
- }
-
- // Finally, flip any branches that we recognize. It's most optimal if the taken successor does not point
- // at the next block.
- for (BasicBlock* block : code) {
- Inst& branch = block->last();
-
- // It's somewhat tempting to just say that if the block has two successors and the first arg is
- // invertible, then we can do the optimization. But that's wagging the dog. The fact that an
- // instruction happens to have an argument that is invertible doesn't mean it's a branch, even though
- // it is true that currently only branches have invertible arguments. It's also tempting to say that
- // the /branch flag in AirOpcode.opcodes tells us that something is a branch - except that there,
- // /branch also means Jump. The approach taken here means that if you add new branch instructions and
- // forget about this phase, then at worst your new instructions won't opt into the inversion
- // optimization. You'll probably realize that as soon as you look at the disassembly, and it
- // certainly won't cause any correctness issues.
-
- switch (branch.opcode) {
- case Branch8:
- case Branch32:
- case Branch64:
- case BranchTest8:
- case BranchTest32:
- case BranchTest64:
- case BranchFloat:
- case BranchDouble:
- case BranchAdd32:
- case BranchAdd64:
- case BranchMul32:
- case BranchMul64:
- case BranchSub32:
- case BranchSub64:
- case BranchNeg32:
- case BranchNeg64:
- if (code.findNextBlock(block) == block->successorBlock(0) && branch.args[0].isInvertible()) {
- std::swap(block->successor(0), block->successor(1));
- branch.args[0] = branch.args[0].inverted();
- }
- break;
-
- default:
- break;
- }
- }
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.h b/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.h
deleted file mode 100644
index 647c541d5..000000000
--- a/Source/JavaScriptCore/b3/air/AirOptimizeBlockOrder.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirOptimizeBlockOrder_h
-#define AirOptimizeBlockOrder_h
-
-#if ENABLE(B3_JIT)
-
-#include <wtf/Vector.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-class BasicBlock;
-class Code;
-
-// Returns a list of blocks sorted according to what would be the current optimal order. This shares
-// some properties with a pre-order traversal. In particular, each block will appear after at least
-// one of its predecessors.
-Vector<BasicBlock*> blocksInOptimizedOrder(Code&);
-
-// Reorders the basic blocks to keep hot blocks at the top, and maximize the likelihood that a frequently
-// taken edge is just a fall-through.
-
-void optimizeBlockOrder(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirOptimizeBlockOrder_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirPhaseScope.cpp b/Source/JavaScriptCore/b3/air/AirPhaseScope.cpp
deleted file mode 100644
index 062ea2483..000000000
--- a/Source/JavaScriptCore/b3/air/AirPhaseScope.cpp
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * 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 "AirPhaseScope.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirValidate.h"
-#include "B3Common.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-PhaseScope::PhaseScope(Code& code, const char* name)
- : m_code(code)
- , m_name(name)
- , m_timingScope(name)
-{
- if (shouldDumpIRAtEachPhase(AirMode)) {
- dataLog("Air after ", code.lastPhaseName(), ", before ", name, ":\n");
- dataLog(code);
- }
-
- if (shouldSaveIRBeforePhase())
- m_dumpBefore = toCString(code);
-}
-
-PhaseScope::~PhaseScope()
-{
- m_code.setLastPhaseName(m_name);
- if (shouldValidateIRAtEachPhase())
- validate(m_code, m_dumpBefore.data());
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirPhaseScope.h b/Source/JavaScriptCore/b3/air/AirPhaseScope.h
deleted file mode 100644
index 7c3a947ba..000000000
--- a/Source/JavaScriptCore/b3/air/AirPhaseScope.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirPhaseScope_h
-#define AirPhaseScope_h
-
-#if ENABLE(B3_JIT)
-
-#include "B3TimingScope.h"
-#include <wtf/Noncopyable.h>
-#include <wtf/text/CString.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-class PhaseScope {
- WTF_MAKE_NONCOPYABLE(PhaseScope);
-public:
- PhaseScope(Code&, const char* name);
- ~PhaseScope(); // this does validation
-
-private:
- Code& m_code;
- const char* m_name;
- TimingScope m_timingScope;
- CString m_dumpBefore;
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirPhaseScope_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirRegisterPriority.cpp b/Source/JavaScriptCore/b3/air/AirRegisterPriority.cpp
deleted file mode 100644
index f535884a0..000000000
--- a/Source/JavaScriptCore/b3/air/AirRegisterPriority.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * 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 "AirRegisterPriority.h"
-
-#if ENABLE(B3_JIT)
-
-#include "RegisterSet.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-const Vector<GPRReg>& gprsInPriorityOrder()
-{
- static Vector<GPRReg>* result;
- static std::once_flag once;
- std::call_once(
- once,
- [] {
- result = new Vector<GPRReg>();
- RegisterSet all = RegisterSet::allGPRs();
- all.exclude(RegisterSet::stackRegisters());
- all.exclude(RegisterSet::reservedHardwareRegisters());
- RegisterSet calleeSave = RegisterSet::calleeSaveRegisters();
- all.forEach(
- [&] (Reg reg) {
- if (!calleeSave.get(reg))
- result->append(reg.gpr());
- });
- all.forEach(
- [&] (Reg reg) {
- if (calleeSave.get(reg))
- result->append(reg.gpr());
- });
- });
- return *result;
-}
-
-const Vector<FPRReg>& fprsInPriorityOrder()
-{
- static Vector<FPRReg>* result;
- static std::once_flag once;
- std::call_once(
- once,
- [] {
- result = new Vector<FPRReg>();
- RegisterSet all = RegisterSet::allFPRs();
- RegisterSet calleeSave = RegisterSet::calleeSaveRegisters();
- all.forEach(
- [&] (Reg reg) {
- if (!calleeSave.get(reg))
- result->append(reg.fpr());
- });
- all.forEach(
- [&] (Reg reg) {
- if (calleeSave.get(reg))
- result->append(reg.fpr());
- });
- });
- return *result;
-}
-
-const Vector<Reg>& regsInPriorityOrder(Arg::Type type)
-{
- static Vector<Reg>* result[Arg::numTypes];
- static std::once_flag once;
- std::call_once(
- once,
- [] {
- result[Arg::GP] = new Vector<Reg>();
- for (GPRReg reg : gprsInPriorityOrder())
- result[Arg::GP]->append(Reg(reg));
- result[Arg::FP] = new Vector<Reg>();
- for (FPRReg reg : fprsInPriorityOrder())
- result[Arg::FP]->append(Reg(reg));
- });
- return *result[type];
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirRegisterPriority.h b/Source/JavaScriptCore/b3/air/AirRegisterPriority.h
deleted file mode 100644
index f0ef8a0ec..000000000
--- a/Source/JavaScriptCore/b3/air/AirRegisterPriority.h
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirRegisterPriority_h
-#define AirRegisterPriority_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirArg.h"
-#include "FPRInfo.h"
-#include "GPRInfo.h"
-#include <wtf/Vector.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-const Vector<GPRReg>& gprsInPriorityOrder();
-const Vector<FPRReg>& fprsInPriorityOrder();
-
-template<typename Bank> struct RegistersInPriorityOrder;
-template<> struct RegistersInPriorityOrder<GPRInfo> {
- const Vector<GPRReg>& inPriorityOrder() { return gprsInPriorityOrder(); }
-};
-template<> struct RegistersInPriorityOrder<FPRInfo> {
- const Vector<FPRReg>& inPriorityOrder() { return fprsInPriorityOrder(); }
-};
-
-template<typename Bank>
-const Vector<typename Bank::RegisterType>& regsInPriorityOrder()
-{
- return RegistersInPriorityOrder<Bank>::inPriorityOrder();
-}
-
-JS_EXPORT_PRIVATE const Vector<Reg>& regsInPriorityOrder(Arg::Type);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirRegisterPriority_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp b/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp
deleted file mode 100644
index edcc885ec..000000000
--- a/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.cpp
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirReportUsedRegisters.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include "AirLiveness.h"
-#include "AirPhaseScope.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-void reportUsedRegisters(Code& code)
-{
- PhaseScope phaseScope(code, "reportUsedRegisters");
-
- RegLiveness liveness(code);
-
- for (BasicBlock* block : code) {
- RegLiveness::LocalCalc localCalc(liveness, block);
-
- for (unsigned instIndex = block->size(); instIndex--;) {
- Inst& inst = block->at(instIndex);
-
- // Kill dead assignments to registers. For simplicity we say that a store is killable if
- // it has only late defs and those late defs are to registers that are dead right now.
- if (!inst.hasNonArgEffects()) {
- bool canDelete = true;
- inst.forEachArg(
- [&] (Arg& arg, Arg::Role role, Arg::Type, Arg::Width) {
- if (Arg::isEarlyDef(role)) {
- canDelete = false;
- return;
- }
- if (!Arg::isLateDef(role))
- return;
- if (!arg.isReg()) {
- canDelete = false;
- return;
- }
- if (localCalc.isLive(arg.reg())) {
- canDelete = false;
- return;
- }
- });
- if (canDelete)
- inst = Inst();
- }
-
- if (inst.opcode == Patch) {
- RegisterSet registerSet;
- for (Reg reg : localCalc.live())
- registerSet.set(reg);
- inst.reportUsedRegisters(registerSet);
- }
- localCalc.execute(instIndex);
- }
-
- block->insts().removeAllMatching(
- [&] (const Inst& inst) -> bool {
- return !inst;
- });
- }
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-
diff --git a/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.h b/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.h
deleted file mode 100644
index 2f81198fe..000000000
--- a/Source/JavaScriptCore/b3/air/AirReportUsedRegisters.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirReportUsedRegisters_h
-#define AirReportUsedRegisters_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// Performs a liveness analysis over registers and reports the live registers to every Special. Takes
-// the opportunity to kill dead assignments to registers, since it has access to register liveness.
-
-void reportUsedRegisters(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirReportUsedRegisters_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirSimplifyCFG.cpp b/Source/JavaScriptCore/b3/air/AirSimplifyCFG.cpp
deleted file mode 100644
index 65e8680fd..000000000
--- a/Source/JavaScriptCore/b3/air/AirSimplifyCFG.cpp
+++ /dev/null
@@ -1,172 +0,0 @@
-/*
- * 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 "AirSimplifyCFG.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include "AirPhaseScope.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-bool simplifyCFG(Code& code)
-{
- const bool verbose = false;
-
- PhaseScope phaseScope(code, "simplifyCFG");
-
- // We have three easy simplification rules:
- //
- // 1) If a successor is a block that just jumps to another block, then jump directly to
- // that block.
- //
- // 2) If all successors are the same and the operation has no effects, then use a jump
- // instead.
- //
- // 3) If you jump to a block that is not you and has one predecessor, then merge.
- //
- // Note that because of the first rule, this phase may introduce critical edges. That's fine.
- // If you need broken critical edges, then you have to break them yourself.
-
- bool result = false;
- for (;;) {
- if (verbose) {
- dataLog("Air before an iteration of simplifyCFG:\n");
- dataLog(code);
- }
-
- bool changed = false;
- for (BasicBlock* block : code) {
- // We rely on predecessors being conservatively correct. Verify this here.
- if (shouldValidateIRAtEachPhase()) {
- for (BasicBlock* block : code) {
- for (BasicBlock* successor : block->successorBlocks())
- RELEASE_ASSERT(successor->containsPredecessor(block));
- }
- }
-
- // We don't care about blocks that don't have successors.
- if (!block->numSuccessors())
- continue;
-
- // First check if any of the successors of this block can be forwarded over.
- for (BasicBlock*& successor : block->successorBlocks()) {
- if (successor != block
- && successor->size() == 1
- && successor->last().opcode == Jump) {
- BasicBlock* newSuccessor = successor->successorBlock(0);
- if (newSuccessor != successor) {
- if (verbose) {
- dataLog(
- "Replacing ", pointerDump(block), "->", pointerDump(successor),
- " with ", pointerDump(block), "->", pointerDump(newSuccessor), "\n");
- }
- // Note that we do not do replacePredecessor() because the block we're
- // skipping will still have newSuccessor as its successor.
- newSuccessor->addPredecessor(block);
- successor = newSuccessor;
- changed = true;
- }
- }
- }
-
- // Now check if the block's terminal can be replaced with a jump.
- if (block->numSuccessors() > 1) {
- // The terminal must not have weird effects.
- if (!block->last().hasArgEffects()
- && !block->last().hasNonArgNonControlEffects()) {
- // All of the successors must be the same.
- bool allSame = true;
- BasicBlock* firstSuccessor = block->successorBlock(0);
- for (unsigned i = 1; i < block->numSuccessors(); ++i) {
- if (block->successorBlock(i) != firstSuccessor) {
- allSame = false;
- break;
- }
- }
- if (allSame) {
- if (verbose)
- dataLog("Changing ", pointerDump(block), "'s terminal to a Jump.\n");
- block->last() = Inst(Jump, block->last().origin);
- block->successors().resize(1);
- block->successors()[0].frequency() = FrequencyClass::Normal;
- changed = true;
- }
- }
- }
-
- // Finally handle jumps to a block with one predecessor.
- if (block->numSuccessors() == 1) {
- BasicBlock* successor = block->successorBlock(0);
- if (successor != block && successor->numPredecessors() == 1) {
- RELEASE_ASSERT(successor->predecessor(0) == block);
-
- // We can merge the two blocks because the predecessor only jumps to the successor
- // and the successor is only reachable from the predecessor.
-
- // Remove the terminal.
- Value* origin = block->insts().takeLast().origin;
-
- // Append the full contents of the successor to the predecessor.
- block->insts().reserveCapacity(block->size() + successor->size());
- for (Inst& inst : *successor)
- block->appendInst(WTFMove(inst));
-
- // Make sure that our successors are the successor's successors.
- block->successors() = WTFMove(successor->successors());
-
- // Make sure that the successor has nothing left in it except an oops.
- successor->resize(1);
- successor->last() = Inst(Oops, origin);
- successor->successors().clear();
-
- // Ensure that the predecessors of block's new successors know what's up.
- for (BasicBlock* newSuccessor : block->successorBlocks())
- newSuccessor->replacePredecessor(successor, block);
-
- if (verbose)
- dataLog("Merged ", pointerDump(block), "->", pointerDump(successor), "\n");
- changed = true;
- }
- }
- }
-
- if (!changed)
- break;
- result = true;
- code.resetReachability();
- }
-
- return result;
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-
diff --git a/Source/JavaScriptCore/b3/air/AirSimplifyCFG.h b/Source/JavaScriptCore/b3/air/AirSimplifyCFG.h
deleted file mode 100644
index 8ec5106db..000000000
--- a/Source/JavaScriptCore/b3/air/AirSimplifyCFG.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirSimplifyCFG_h
-#define AirSimplifyCFG_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// Simplifies the control flow graph by removing jump-only blocks and merging jumps.
-
-bool simplifyCFG(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirSimplifyCFG_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirSpecial.cpp b/Source/JavaScriptCore/b3/air/AirSpecial.cpp
deleted file mode 100644
index ec66ab1df..000000000
--- a/Source/JavaScriptCore/b3/air/AirSpecial.cpp
+++ /dev/null
@@ -1,79 +0,0 @@
-/*
- * 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 "AirSpecial.h"
-
-#if ENABLE(B3_JIT)
-
-#include <limits.h>
-#include <wtf/StringPrintStream.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-const char* const Special::dumpPrefix = "&";
-
-Special::Special()
-{
-}
-
-Special::~Special()
-{
-}
-
-CString Special::name() const
-{
- StringPrintStream out;
- dumpImpl(out);
- return out.toCString();
-}
-
-Optional<unsigned> Special::shouldTryAliasingDef(Inst&)
-{
- return Nullopt;
-}
-
-bool Special::hasNonArgNonControlEffects()
-{
- return true;
-}
-
-void Special::dump(PrintStream& out) const
-{
- out.print(dumpPrefix);
- dumpImpl(out);
- if (m_index != UINT_MAX)
- out.print(m_index);
-}
-
-void Special::deepDump(PrintStream& out) const
-{
- out.print(*this, ": ");
- deepDumpImpl(out);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirSpecial.h b/Source/JavaScriptCore/b3/air/AirSpecial.h
deleted file mode 100644
index b0a79cd96..000000000
--- a/Source/JavaScriptCore/b3/air/AirSpecial.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirSpecial_h
-#define AirSpecial_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirInst.h"
-#include "B3SparseCollection.h"
-#include <wtf/FastMalloc.h>
-#include <wtf/Noncopyable.h>
-#include <wtf/ScopedLambda.h>
-#include <wtf/text/CString.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-struct GenerationContext;
-
-class Special {
- WTF_MAKE_NONCOPYABLE(Special);
- WTF_MAKE_FAST_ALLOCATED;
-public:
- static const char* const dumpPrefix;
-
- Special();
- virtual ~Special();
-
- Code& code() const { return *m_code; }
-
- CString name() const;
-
- virtual void forEachArg(Inst&, const ScopedLambda<Inst::EachArgCallback>&) = 0;
- virtual bool isValid(Inst&) = 0;
- virtual bool admitsStack(Inst&, unsigned argIndex) = 0;
- virtual Optional<unsigned> shouldTryAliasingDef(Inst&);
-
- // This gets called on for each Inst that uses this Special. Note that there is no way to
- // guarantee that a Special gets used from just one Inst, because Air might taildup late. So,
- // if you want to pass this information down to generate(), then you have to either:
- //
- // 1) Generate Air that starts with a separate Special per Patch Inst, and then merge
- // usedRegister sets. This is probably not great, but it optimizes for the common case that
- // Air didn't duplicate code or that such duplication didn't cause any interesting changes to
- // register assignment.
- //
- // 2) Have the Special maintain a HashMap<Inst*, RegisterSet>. This works because the analysis
- // that feeds into this call is performed just before code generation and there is no way
- // for the Vector<>'s that contain the Insts to be reallocated. This allows generate() to
- // consult the HashMap.
- //
- // 3) Hybrid: you could use (1) and fire up a HashMap if you see multiple calls.
- //
- // Note that it's not possible to rely on reportUsedRegisters() being called in the same order
- // as generate(). If we could rely on that, then we could just have each Special instance
- // maintain a Vector of RegisterSet's and then process that vector in the right order in
- // generate(). But, the ordering difference is unlikely to change since it would harm the
- // performance of the liveness analysis.
- //
- // Currently, we do (1) for B3 stackmaps.
- virtual void reportUsedRegisters(Inst&, const RegisterSet&) = 0;
-
- virtual CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&) = 0;
-
- virtual const RegisterSet& extraEarlyClobberedRegs(Inst&) = 0;
- virtual const RegisterSet& extraClobberedRegs(Inst&) = 0;
-
- // By default, this returns true.
- virtual bool hasNonArgNonControlEffects();
-
- void dump(PrintStream&) const;
- void deepDump(PrintStream&) const;
-
-protected:
- virtual void dumpImpl(PrintStream&) const = 0;
- virtual void deepDumpImpl(PrintStream&) const = 0;
-
-private:
- friend class Code;
- friend class SparseCollection<Special>;
-
- unsigned m_index { UINT_MAX };
- Code* m_code { nullptr };
-};
-
-class DeepSpecialDump {
-public:
- DeepSpecialDump(const Special* special)
- : m_special(special)
- {
- }
-
- void dump(PrintStream& out) const
- {
- if (m_special)
- m_special->deepDump(out);
- else
- out.print("<null>");
- }
-
-private:
- const Special* m_special;
-};
-
-inline DeepSpecialDump deepDump(const Special* special)
-{
- return DeepSpecialDump(special);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirSpecial_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp b/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp
deleted file mode 100644
index 18224e409..000000000
--- a/Source/JavaScriptCore/b3/air/AirSpillEverything.cpp
+++ /dev/null
@@ -1,187 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirSpillEverything.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInsertionSet.h"
-#include "AirInstInlines.h"
-#include "AirLiveness.h"
-#include "AirPhaseScope.h"
-#include "AirRegisterPriority.h"
-#include "B3IndexMap.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-void spillEverything(Code& code)
-{
- PhaseScope phaseScope(code, "spillEverything");
-
- // We want to know the set of registers used at every point in every basic block.
- IndexMap<BasicBlock, Vector<RegisterSet>> usedRegisters(code.size());
- GPLiveness gpLiveness(code);
- FPLiveness fpLiveness(code);
- for (BasicBlock* block : code) {
- GPLiveness::LocalCalc gpLocalCalc(gpLiveness, block);
- FPLiveness::LocalCalc fpLocalCalc(fpLiveness, block);
-
- usedRegisters[block].resize(block->size() + 1);
-
- auto setUsedRegisters = [&] (unsigned index) {
- RegisterSet& registerSet = usedRegisters[block][index];
- for (Tmp tmp : gpLocalCalc.live()) {
- if (tmp.isReg())
- registerSet.set(tmp.reg());
- }
- for (Tmp tmp : fpLocalCalc.live()) {
- if (tmp.isReg())
- registerSet.set(tmp.reg());
- }
-
- // Gotta account for dead assignments to registers. These may happen because the input
- // code is suboptimal.
- Inst::forEachDefWithExtraClobberedRegs<Tmp>(
- block->get(index - 1), block->get(index),
- [&] (const Tmp& tmp, Arg::Role, Arg::Type, Arg::Width) {
- if (tmp.isReg())
- registerSet.set(tmp.reg());
- });
- };
-
- for (unsigned instIndex = block->size(); instIndex--;) {
- setUsedRegisters(instIndex + 1);
- gpLocalCalc.execute(instIndex);
- fpLocalCalc.execute(instIndex);
- }
- setUsedRegisters(0);
- }
-
- // Allocate a stack slot for each tmp.
- Vector<StackSlot*> allStackSlots[Arg::numTypes];
- for (unsigned typeIndex = 0; typeIndex < Arg::numTypes; ++typeIndex) {
- Vector<StackSlot*>& stackSlots = allStackSlots[typeIndex];
- Arg::Type type = static_cast<Arg::Type>(typeIndex);
- stackSlots.resize(code.numTmps(type));
- for (unsigned tmpIndex = code.numTmps(type); tmpIndex--;)
- stackSlots[tmpIndex] = code.addStackSlot(8, StackSlotKind::Spill);
- }
-
- InsertionSet insertionSet(code);
- for (BasicBlock* block : code) {
- for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
- RegisterSet& setBefore = usedRegisters[block][instIndex];
- RegisterSet& setAfter = usedRegisters[block][instIndex + 1];
- Inst& inst = block->at(instIndex);
-
- // First try to spill directly.
- for (unsigned i = 0; i < inst.args.size(); ++i) {
- Arg& arg = inst.args[i];
-
- if (arg.isTmp()) {
- if (arg.isReg())
- continue;
-
- if (inst.admitsStack(i)) {
- StackSlot* stackSlot = allStackSlots[arg.type()][arg.tmpIndex()];
- arg = Arg::stack(stackSlot);
- continue;
- }
- }
- }
-
- // Now fall back on spilling using separate Move's to load/store the tmp.
- inst.forEachTmp(
- [&] (Tmp& tmp, Arg::Role role, Arg::Type type, Arg::Width) {
- if (tmp.isReg())
- return;
-
- StackSlot* stackSlot = allStackSlots[type][tmp.tmpIndex()];
- Arg arg = Arg::stack(stackSlot);
-
- // Need to figure out a register to use. How we do that depends on the role.
- Reg chosenReg;
- switch (role) {
- case Arg::Use:
- case Arg::ColdUse:
- for (Reg reg : regsInPriorityOrder(type)) {
- if (!setBefore.get(reg)) {
- setBefore.set(reg);
- chosenReg = reg;
- break;
- }
- }
- break;
- case Arg::Def:
- case Arg::ZDef:
- for (Reg reg : regsInPriorityOrder(type)) {
- if (!setAfter.get(reg)) {
- setAfter.set(reg);
- chosenReg = reg;
- break;
- }
- }
- break;
- case Arg::UseDef:
- case Arg::UseZDef:
- case Arg::LateUse:
- case Arg::LateColdUse:
- case Arg::Scratch:
- case Arg::EarlyDef:
- for (Reg reg : regsInPriorityOrder(type)) {
- if (!setBefore.get(reg) && !setAfter.get(reg)) {
- setAfter.set(reg);
- setBefore.set(reg);
- chosenReg = reg;
- break;
- }
- }
- break;
- case Arg::UseAddr:
- // We will never UseAddr a Tmp, that doesn't make sense.
- RELEASE_ASSERT_NOT_REACHED();
- break;
- }
- RELEASE_ASSERT(chosenReg);
-
- tmp = Tmp(chosenReg);
-
- Opcode move = type == Arg::GP ? Move : MoveDouble;
-
- if (Arg::isAnyUse(role) && role != Arg::Scratch)
- insertionSet.insert(instIndex, move, inst.origin, arg, tmp);
- if (Arg::isAnyDef(role))
- insertionSet.insert(instIndex + 1, move, inst.origin, tmp, arg);
- });
- }
- insertionSet.execute(block);
- }
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirSpillEverything.h b/Source/JavaScriptCore/b3/air/AirSpillEverything.h
deleted file mode 100644
index 5d1eeee15..000000000
--- a/Source/JavaScriptCore/b3/air/AirSpillEverything.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirSpillEverything_h
-#define AirSpillEverything_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// This is a phase for testing. It behaves like a register allocator in the sense that it
-// eliminates temporaries from the program. It accomplishes this by always spilling all
-// temporaries. The resulting code is going to be very inefficient. This phase is great if you
-// think that there is a bug in the register allocator. You can confirm this by running this
-// phase instead of the register allocator.
-//
-// Note that even though this phase does the cheapest thing possible, it's not even written in a
-// particularly efficient way. So, don't get any ideas about using this phase to reduce compiler
-// latency. If you wanted to do that, you should come up with a clever algorithm instead of using
-// this silly thing.
-
-void spillEverything(Code&);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirSpillEverything_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirStackSlot.cpp b/Source/JavaScriptCore/b3/air/AirStackSlot.cpp
deleted file mode 100644
index d0ab082eb..000000000
--- a/Source/JavaScriptCore/b3/air/AirStackSlot.cpp
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirStackSlot.h"
-
-#if ENABLE(B3_JIT)
-
-#include "B3StackSlot.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-void StackSlot::setOffsetFromFP(intptr_t value)
-{
- m_offsetFromFP = value;
- if (m_b3Slot)
- m_b3Slot->m_offsetFromFP = value;
-}
-
-void StackSlot::dump(PrintStream& out) const
-{
- if (isSpill())
- out.print("spill");
- else
- out.print("stack");
- out.print(m_index);
-}
-
-void StackSlot::deepDump(PrintStream& out) const
-{
- out.print("byteSize = ", m_byteSize, ", offsetFromFP = ", m_offsetFromFP, ", kind = ", m_kind);
- if (m_b3Slot)
- out.print(", b3Slot = ", *m_b3Slot, ": (", B3::deepDump(m_b3Slot), ")");
-}
-
-StackSlot::StackSlot(unsigned byteSize, StackSlotKind kind, B3::StackSlot* b3Slot)
- : m_byteSize(byteSize)
- , m_offsetFromFP(b3Slot ? b3Slot->offsetFromFP() : 0)
- , m_kind(kind)
- , m_b3Slot(b3Slot)
-{
- ASSERT(byteSize);
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirStackSlot.h b/Source/JavaScriptCore/b3/air/AirStackSlot.h
deleted file mode 100644
index 6c07390a2..000000000
--- a/Source/JavaScriptCore/b3/air/AirStackSlot.h
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirStackSlot_h
-#define AirStackSlot_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirStackSlotKind.h"
-#include "B3SparseCollection.h"
-#include <limits.h>
-#include <wtf/FastMalloc.h>
-#include <wtf/Noncopyable.h>
-#include <wtf/PrintStream.h>
-
-namespace JSC { namespace B3 {
-
-class StackSlot;
-
-namespace Air {
-
-class StackSlot {
- WTF_MAKE_NONCOPYABLE(StackSlot);
- WTF_MAKE_FAST_ALLOCATED;
-public:
- unsigned byteSize() const { return m_byteSize; }
- StackSlotKind kind() const { return m_kind; }
- bool isLocked() const { return m_kind == StackSlotKind::Locked; }
- bool isSpill() const { return m_kind == StackSlotKind::Spill; }
- unsigned index() const { return m_index; }
-
- void ensureSize(unsigned requestedSize)
- {
- ASSERT(!m_offsetFromFP);
- m_byteSize = std::max(m_byteSize, requestedSize);
- }
-
- unsigned alignment() const
- {
- if (byteSize() <= 1)
- return 1;
- if (byteSize() <= 2)
- return 2;
- if (byteSize() <= 4)
- return 4;
- return 8;
- }
-
- B3::StackSlot* b3Slot() const { return m_b3Slot; }
-
- // Zero means that it's not yet assigned.
- intptr_t offsetFromFP() const { return m_offsetFromFP; }
-
- // This should usually just be called from phases that do stack allocation. But you can
- // totally force a stack slot to land at some offset.
- void setOffsetFromFP(intptr_t);
-
- void dump(PrintStream&) const;
- void deepDump(PrintStream&) const;
-
-private:
- friend class Code;
- friend class SparseCollection<StackSlot>;
-
- StackSlot(unsigned byteSize, StackSlotKind, B3::StackSlot*);
-
- unsigned m_byteSize { 0 };
- unsigned m_index { UINT_MAX };
- intptr_t m_offsetFromFP { 0 };
- StackSlotKind m_kind { StackSlotKind::Locked };
- B3::StackSlot* m_b3Slot { nullptr };
-};
-
-class DeepStackSlotDump {
-public:
- DeepStackSlotDump(const StackSlot* slot)
- : m_slot(slot)
- {
- }
-
- void dump(PrintStream& out) const
- {
- if (m_slot)
- m_slot->deepDump(out);
- else
- out.print("<null>");
- }
-
-private:
- const StackSlot* m_slot;
-};
-
-inline DeepStackSlotDump deepDump(const StackSlot* slot)
-{
- return DeepStackSlotDump(slot);
-}
-
-} } } // namespace JSC::B3::Air
-
-namespace WTF {
-
-inline void printInternal(PrintStream& out, JSC::B3::Air::StackSlot* stackSlot)
-{
- out.print(pointerDump(stackSlot));
-}
-
-} // namespace WTF
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirStackSlot_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirStackSlotKind.cpp b/Source/JavaScriptCore/b3/air/AirStackSlotKind.cpp
deleted file mode 100644
index af83de1b9..000000000
--- a/Source/JavaScriptCore/b3/air/AirStackSlotKind.cpp
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * 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 "AirStackSlotKind.h"
-
-#if ENABLE(B3_JIT)
-
-#include <wtf/PrintStream.h>
-
-namespace WTF {
-
-using namespace JSC::B3::Air;
-
-void printInternal(PrintStream& out, StackSlotKind kind)
-{
- switch (kind) {
- case StackSlotKind::Locked:
- out.print("Locked");
- return;
- case StackSlotKind::Spill:
- out.print("Spill");
- return;
- }
- RELEASE_ASSERT_NOT_REACHED();
-}
-
-} // namespace WTF
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirStackSlotKind.h b/Source/JavaScriptCore/b3/air/AirStackSlotKind.h
deleted file mode 100644
index 9236183ef..000000000
--- a/Source/JavaScriptCore/b3/air/AirStackSlotKind.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirStackSlotKind_h
-#define AirStackSlotKind_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-enum class StackSlotKind : uint8_t {
- // A locked stack slot is an area of stack requested by the client. It cannot be killed. The
- // client can get its FP offset and write to it from stack walking code, so we must assume
- // that reads and writes to a locked stack slot can be clobbered the same way as reads and
- // writes to any memory location.
- Locked,
-
- // A spill slot. These have fundamentally different behavior than a typical memory location.
- // They are lowered to from temporaries. This means for example that a 32-bit ZDef store to a
- // 8 byte stack slot will zero the top 4 bytes, even though a 32-bit ZDef store to any other
- // kind of memory location would do no such thing. UseAddr on a spill slot is not allowed, so
- // they never escape.
- Spill
-
- // FIXME: We should add a third mode, which means that the stack slot will be read asynchronously
- // as with Locked, but never written to asynchronously. Then, Air could optimize spilling and
- // filling by tracking whether the value had been stored to a read-only locked slot. If it had,
- // then we can refill from that slot.
- // https://bugs.webkit.org/show_bug.cgi?id=150587
-};
-
-} } } // namespace JSC::B3::Air
-
-namespace WTF {
-
-class PrintStream;
-
-void printInternal(PrintStream&, JSC::B3::Air::StackSlotKind);
-
-} // namespace WTF
-
-#endif // ENABLE(B3_JIT)
-
-#endif // B3StackSlotKind_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirTmp.cpp b/Source/JavaScriptCore/b3/air/AirTmp.cpp
deleted file mode 100644
index 487f52177..000000000
--- a/Source/JavaScriptCore/b3/air/AirTmp.cpp
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * 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 "AirTmp.h"
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-void Tmp::dump(PrintStream& out) const
-{
- if (!*this) {
- out.print("<none>");
- return;
- }
-
- if (isReg()) {
- out.print(reg());
- return;
- }
-
- if (isGP()) {
- out.print("%tmp", gpTmpIndex());
- return;
- }
-
- out.print("%ftmp", fpTmpIndex());
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
diff --git a/Source/JavaScriptCore/b3/air/AirTmp.h b/Source/JavaScriptCore/b3/air/AirTmp.h
deleted file mode 100644
index b0d158d3d..000000000
--- a/Source/JavaScriptCore/b3/air/AirTmp.h
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirTmp_h
-#define AirTmp_h
-
-#if ENABLE(B3_JIT)
-
-#include "FPRInfo.h"
-#include "GPRInfo.h"
-#include "Reg.h"
-#include <wtf/HashMap.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Arg;
-
-// A Tmp is a generalization of a register. It can be used to refer to any GPR or FPR. It can also
-// be used to refer to an unallocated register (i.e. a temporary). Like many Air classes, we use
-// deliberately terse naming since we will have to use this name a lot.
-
-class Tmp {
-public:
- Tmp()
- : m_value(0)
- {
- }
-
- explicit Tmp(Reg reg)
- {
- if (reg) {
- if (reg.isGPR())
- m_value = encodeGPR(reg.gpr());
- else
- m_value = encodeFPR(reg.fpr());
- } else
- m_value = 0;
- }
-
- explicit Tmp(const Arg&);
-
- static Tmp gpTmpForIndex(unsigned index)
- {
- Tmp result;
- result.m_value = encodeGPTmp(index);
- return result;
- }
-
- static Tmp fpTmpForIndex(unsigned index)
- {
- Tmp result;
- result.m_value = encodeFPTmp(index);
- return result;
- }
-
- explicit operator bool() const { return !!m_value; }
-
- bool isGP() const
- {
- return isEncodedGP(m_value);
- }
-
- bool isFP() const
- {
- return isEncodedFP(m_value);
- }
-
- bool isGPR() const
- {
- return isEncodedGPR(m_value);
- }
-
- bool isFPR() const
- {
- return isEncodedFPR(m_value);
- }
-
- bool isReg() const
- {
- return isGPR() || isFPR();
- }
-
- GPRReg gpr() const
- {
- return decodeGPR(m_value);
- }
-
- FPRReg fpr() const
- {
- return decodeFPR(m_value);
- }
-
- Reg reg() const
- {
- if (isGP())
- return gpr();
- return fpr();
- }
-
- bool hasTmpIndex() const
- {
- return !isReg();
- }
-
- unsigned gpTmpIndex() const
- {
- return decodeGPTmp(m_value);
- }
-
- unsigned fpTmpIndex() const
- {
- return decodeFPTmp(m_value);
- }
-
- unsigned tmpIndex() const
- {
- if (isGP())
- return gpTmpIndex();
- return fpTmpIndex();
- }
-
- bool isAlive() const
- {
- return !!*this;
- }
-
- bool operator==(const Tmp& other) const
- {
- return m_value == other.m_value;
- }
-
- bool operator!=(const Tmp& other) const
- {
- return !(*this == other);
- }
-
- void dump(PrintStream& out) const;
-
- Tmp(WTF::HashTableDeletedValueType)
- : m_value(std::numeric_limits<int>::max())
- {
- }
-
- bool isHashTableDeletedValue() const
- {
- return *this == Tmp(WTF::HashTableDeletedValue);
- }
-
- unsigned hash() const
- {
- return WTF::IntHash<int>::hash(m_value);
- }
-
- unsigned internalValue() const { return static_cast<unsigned>(m_value); }
-
- static Tmp tmpForInternalValue(unsigned index)
- {
- Tmp result;
- result.m_value = static_cast<int>(index);
- return result;
- }
-
-private:
- static int encodeGP(unsigned index)
- {
- return 1 + index;
- }
-
- static int encodeFP(unsigned index)
- {
- return -1 - index;
- }
-
- static int encodeGPR(GPRReg gpr)
- {
- return encodeGP(gpr - MacroAssembler::firstRegister());
- }
-
- static int encodeFPR(FPRReg fpr)
- {
- return encodeFP(fpr - MacroAssembler::firstFPRegister());
- }
-
- static int encodeGPTmp(unsigned index)
- {
- return encodeGPR(MacroAssembler::lastRegister()) + 1 + index;
- }
-
- static int encodeFPTmp(unsigned index)
- {
- return encodeFPR(MacroAssembler::lastFPRegister()) - 1 - index;
- }
-
- static bool isEncodedGP(int value)
- {
- return value > 0;
- }
-
- static bool isEncodedFP(int value)
- {
- return value < 0;
- }
-
- static bool isEncodedGPR(int value)
- {
- return isEncodedGP(value) && value <= encodeGPR(MacroAssembler::lastRegister());
- }
-
- static bool isEncodedFPR(int value)
- {
- return isEncodedFP(value) && value >= encodeFPR(MacroAssembler::lastFPRegister());
- }
-
- static bool isEncodedGPTmp(int value)
- {
- return isEncodedGP(value) && !isEncodedGPR(value);
- }
-
- static bool isEncodedFPTmp(int value)
- {
- return isEncodedFP(value) && !isEncodedFPR(value);
- }
-
- static GPRReg decodeGPR(int value)
- {
- ASSERT(isEncodedGPR(value));
- return static_cast<GPRReg>(
- (value - encodeGPR(MacroAssembler::firstRegister())) + MacroAssembler::firstRegister());
- }
-
- static FPRReg decodeFPR(int value)
- {
- ASSERT(isEncodedFPR(value));
- return static_cast<FPRReg>(
- (encodeFPR(MacroAssembler::firstFPRegister()) - value) +
- MacroAssembler::firstFPRegister());
- }
-
- static unsigned decodeGPTmp(int value)
- {
- ASSERT(isEncodedGPTmp(value));
- return value - (encodeGPR(MacroAssembler::lastRegister()) + 1);
- }
-
- static unsigned decodeFPTmp(int value)
- {
- ASSERT(isEncodedFPTmp(value));
- return (encodeFPR(MacroAssembler::lastFPRegister()) - 1) - value;
- }
-
- // 0: empty Tmp
- // positive: GPRs and then GP temps.
- // negative: FPRs and then FP temps.
- int m_value;
-};
-
-struct TmpHash {
- static unsigned hash(const Tmp& key) { return key.hash(); }
- static bool equal(const Tmp& a, const Tmp& b) { return a == b; }
- static const bool safeToCompareToEmptyOrDeleted = true;
-};
-
-} } } // namespace JSC::B3::Air
-
-namespace WTF {
-
-template<typename T> struct DefaultHash;
-template<> struct DefaultHash<JSC::B3::Air::Tmp> {
- typedef JSC::B3::Air::TmpHash Hash;
-};
-
-template<typename T> struct HashTraits;
-template<> struct HashTraits<JSC::B3::Air::Tmp> : SimpleClassHashTraits<JSC::B3::Air::Tmp> { };
-
-} // namespace WTF
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirTmp_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirTmpInlines.h b/Source/JavaScriptCore/b3/air/AirTmpInlines.h
deleted file mode 100644
index 2e42b9b96..000000000
--- a/Source/JavaScriptCore/b3/air/AirTmpInlines.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirTmpInlines_h
-#define AirTmpInlines_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirArg.h"
-#include "AirTmp.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-inline Tmp::Tmp(const Arg& arg)
-{
- *this = arg.tmp();
-}
-
-// When a Hash structure is too slow or when Sets contains most values, you can
-// use direct array addressing with Tmps.
-template<Arg::Type type>
-struct AbsoluteTmpMapper;
-
-template<>
-struct AbsoluteTmpMapper<Arg::GP> {
- static unsigned absoluteIndex(const Tmp& tmp)
- {
- ASSERT(tmp.isGP());
- ASSERT(static_cast<int>(tmp.internalValue()) > 0);
- return tmp.internalValue();
- }
-
- static unsigned absoluteIndex(unsigned tmpIndex)
- {
- return absoluteIndex(Tmp::gpTmpForIndex(tmpIndex));
- }
-
- static unsigned lastMachineRegisterIndex()
- {
- return absoluteIndex(Tmp(MacroAssembler::lastRegister()));
- }
-
- static Tmp tmpFromAbsoluteIndex(unsigned tmpIndex)
- {
- return Tmp::tmpForInternalValue(tmpIndex);
- }
-};
-
-template<>
-struct AbsoluteTmpMapper<Arg::FP> {
- static unsigned absoluteIndex(const Tmp& tmp)
- {
- ASSERT(tmp.isFP());
- ASSERT(static_cast<int>(tmp.internalValue()) < 0);
- return -tmp.internalValue();
- }
-
- static unsigned absoluteIndex(unsigned tmpIndex)
- {
- return absoluteIndex(Tmp::fpTmpForIndex(tmpIndex));
- }
-
- static unsigned lastMachineRegisterIndex()
- {
- return absoluteIndex(Tmp(MacroAssembler::lastFPRegister()));
- }
-
- static Tmp tmpFromAbsoluteIndex(unsigned tmpIndex)
- {
- return Tmp::tmpForInternalValue(-tmpIndex);
- }
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirTmpInlines_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp b/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp
deleted file mode 100644
index 7c7227a7a..000000000
--- a/Source/JavaScriptCore/b3/air/AirTmpWidth.cpp
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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 "AirTmpWidth.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include <wtf/ListDump.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-TmpWidth::TmpWidth()
-{
-}
-
-TmpWidth::TmpWidth(Code& code)
-{
- recompute(code);
-}
-
-TmpWidth::~TmpWidth()
-{
-}
-
-void TmpWidth::recompute(Code& code)
-{
- // Set this to true to cause this analysis to always return pessimistic results.
- const bool beCareful = false;
-
- const bool verbose = false;
-
- if (verbose) {
- dataLog("Code before TmpWidth:\n");
- dataLog(code);
- }
-
- m_width.clear();
-
- auto assumeTheWorst = [&] (Tmp tmp) {
- Widths& widths = m_width.add(tmp, Widths()).iterator->value;
- Arg::Type type = Arg(tmp).type();
- widths.use = Arg::conservativeWidth(type);
- widths.def = Arg::conservativeWidth(type);
- };
-
- // Assume the worst for registers.
- RegisterSet::allRegisters().forEach(
- [&] (Reg reg) {
- assumeTheWorst(Tmp(reg));
- });
-
- if (beCareful) {
- code.forAllTmps(assumeTheWorst);
-
- // We fall through because the fixpoint that follows can only make things even more
- // conservative. This mode isn't meant to be fast, just safe.
- }
-
- // Now really analyze everything but Move's over Tmp's, but set aside those Move's so we can find
- // them quickly during the fixpoint below. Note that we can make this analysis stronger by
- // recognizing more kinds of Move's or anything that has Move-like behavior, though it's probably not
- // worth it.
- Vector<Inst*> moves;
- for (BasicBlock* block : code) {
- for (Inst& inst : *block) {
- if (inst.opcode == Move && inst.args[1].isTmp()) {
- if (inst.args[0].isTmp()) {
- // Make sure that both sides of the Move have a width already initialized. The
- // fixpoint below assumes that it never has to add things to the HashMap.
- m_width.add(inst.args[0].tmp(), Widths(Arg::GP));
- m_width.add(inst.args[1].tmp(), Widths(Arg::GP));
-
- moves.append(&inst);
- continue;
- }
- if (inst.args[0].isImm()
- && inst.args[0].value() >= 0) {
- Tmp tmp = inst.args[1].tmp();
- Widths& widths = m_width.add(tmp, Widths(Arg::GP)).iterator->value;
-
- if (inst.args[0].value() <= std::numeric_limits<int8_t>::max())
- widths.def = std::max(widths.def, Arg::Width8);
- else if (inst.args[0].value() <= std::numeric_limits<int16_t>::max())
- widths.def = std::max(widths.def, Arg::Width16);
- else if (inst.args[0].value() <= std::numeric_limits<int32_t>::max())
- widths.def = std::max(widths.def, Arg::Width32);
- else
- widths.def = std::max(widths.def, Arg::Width64);
-
- continue;
- }
- }
- inst.forEachTmp(
- [&] (Tmp& tmp, Arg::Role role, Arg::Type type, Arg::Width width) {
- Widths& widths = m_width.add(tmp, Widths(type)).iterator->value;
-
- if (Arg::isAnyUse(role))
- widths.use = std::max(widths.use, width);
-
- if (Arg::isZDef(role))
- widths.def = std::max(widths.def, width);
- else if (Arg::isAnyDef(role))
- widths.def = Arg::conservativeWidth(type);
- });
- }
- }
-
- // Finally, fixpoint over the Move's.
- bool changed = true;
- while (changed) {
- changed = false;
- for (Inst* move : moves) {
- ASSERT(move->opcode == Move);
- ASSERT(move->args[0].isTmp());
- ASSERT(move->args[1].isTmp());
-
- // We already ensure that both tmps are added to the width map. That's important
- // because you cannot add both tmps here while simultaneously getting a reference to
- // their values, since the second add would invalidate the reference returned by the
- // first one.
- Widths& srcWidths = m_width.find(move->args[0].tmp())->value;
- Widths& dstWidths = m_width.find(move->args[1].tmp())->value;
-
- // Legend:
- //
- // Move %src, %dst
-
- // defWidth(%dst) is a promise about how many high bits are zero. The smaller the width, the
- // stronger the promise. This Move may weaken that promise if we know that %src is making a
- // weaker promise. Such forward flow is the only thing that determines defWidth().
- if (dstWidths.def < srcWidths.def) {
- dstWidths.def = srcWidths.def;
- changed = true;
- }
-
- // srcWidth(%src) is a promise about how many high bits are ignored. The smaller the width,
- // the stronger the promise. This Move may weaken that promise if we know that %dst is making
- // a weaker promise. Such backward flow is the only thing that determines srcWidth().
- if (srcWidths.use < dstWidths.use) {
- srcWidths.use = dstWidths.use;
- changed = true;
- }
- }
- }
-
- if (verbose)
- dataLog("width: ", mapDump(m_width), "\n");
-}
-
-void TmpWidth::Widths::dump(PrintStream& out) const
-{
- out.print("{use = ", use, ", def = ", def, "}");
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirTmpWidth.h b/Source/JavaScriptCore/b3/air/AirTmpWidth.h
deleted file mode 100644
index 5ff0552a3..000000000
--- a/Source/JavaScriptCore/b3/air/AirTmpWidth.h
+++ /dev/null
@@ -1,110 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirTmpWidth_h
-#define AirTmpWidth_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirArg.h"
-#include <wtf/HashSet.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-class TmpWidth {
-public:
- TmpWidth();
- TmpWidth(Code&);
- ~TmpWidth();
-
- void recompute(Code&);
-
- // The width of a Tmp is the number of bits that you need to be able to track without some trivial
- // recovery. A Tmp may have a "subwidth" (say, Width32 on a 64-bit system) if either of the following
- // is true:
- //
- // - The high bits are never read.
- // - The high bits are always zero.
- //
- // This doesn't tell you which of those properties holds, but you can query that using the other
- // methods.
- Arg::Width width(Tmp tmp) const
- {
- auto iter = m_width.find(tmp);
- if (iter == m_width.end())
- return Arg::minimumWidth(Arg(tmp).type());
- return std::min(iter->value.use, iter->value.def);
- }
-
- // This indirectly tells you how much of the tmp's high bits are guaranteed to be zero. The number of
- // high bits that are zero are:
- //
- // TotalBits - defWidth(tmp)
- //
- // Where TotalBits are the total number of bits in the register, so 64 on a 64-bit system.
- Arg::Width defWidth(Tmp tmp) const
- {
- auto iter = m_width.find(tmp);
- if (iter == m_width.end())
- return Arg::minimumWidth(Arg(tmp).type());
- return iter->value.def;
- }
-
- // This tells you how much of Tmp is going to be read.
- Arg::Width useWidth(Tmp tmp) const
- {
- auto iter = m_width.find(tmp);
- if (iter == m_width.end())
- return Arg::minimumWidth(Arg(tmp).type());
- return iter->value.use;
- }
-
-private:
- struct Widths {
- Widths() { }
-
- Widths(Arg::Type type)
- {
- use = Arg::minimumWidth(type);
- def = Arg::minimumWidth(type);
- }
-
- void dump(PrintStream& out) const;
-
- Arg::Width use;
- Arg::Width def;
- };
-
- HashMap<Tmp, Widths> m_width;
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirTmpWidth_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirUseCounts.h b/Source/JavaScriptCore/b3/air/AirUseCounts.h
deleted file mode 100644
index 0c39da333..000000000
--- a/Source/JavaScriptCore/b3/air/AirUseCounts.h
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2015-2016 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.
- */
-
-#ifndef AirUseCounts_h
-#define AirUseCounts_h
-
-#if ENABLE(B3_JIT)
-
-#include "AirArgInlines.h"
-#include "AirBlockWorklist.h"
-#include "AirCode.h"
-#include "AirInstInlines.h"
-#include <wtf/HashMap.h>
-#include <wtf/ListDump.h>
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-// Computes the number of uses of a variable based on frequency of execution. The frequency of blocks
-// that are only reachable by rare edges is scaled by Options::rareBlockPenalty().
-
-// Thing can be either Tmp or Arg.
-template<typename Thing>
-class UseCounts {
-public:
- struct Counts {
- void dump(PrintStream& out) const
- {
- out.print(
- "{numWarmUses = ", numWarmUses, ", numColdUses = ", numColdUses, ", numDefs = ",
- numDefs, "}");
- }
-
- double numWarmUses { 0 };
- double numColdUses { 0 };
- double numDefs { 0 };
- double numConstDefs { 0 };
- };
-
- UseCounts(Code& code)
- {
- // Find non-rare blocks.
- BlockWorklist fastWorklist;
- fastWorklist.push(code[0]);
- while (BasicBlock* block = fastWorklist.pop()) {
- for (FrequentedBlock& successor : block->successors()) {
- if (!successor.isRare())
- fastWorklist.push(successor.block());
- }
- }
-
- for (BasicBlock* block : code) {
- double frequency = block->frequency();
- if (!fastWorklist.saw(block))
- frequency *= Options::rareBlockPenalty();
- for (Inst& inst : *block) {
- inst.forEach<Thing>(
- [&] (Thing& arg, Arg::Role role, Arg::Type, Arg::Width) {
- Counts& counts = m_counts.add(arg, Counts()).iterator->value;
-
- if (Arg::isWarmUse(role))
- counts.numWarmUses += frequency;
- if (Arg::isColdUse(role))
- counts.numColdUses += frequency;
- if (Arg::isAnyDef(role))
- counts.numDefs += frequency;
- });
-
- if ((inst.opcode == Move || inst.opcode == Move32)
- && inst.args[0].isSomeImm()
- && inst.args[1].is<Thing>())
- m_counts.add(inst.args[1].as<Thing>(), Counts()).iterator->value.numConstDefs++;
- }
- }
- }
-
- const Counts* operator[](const Thing& arg) const
- {
- auto iter = m_counts.find(arg);
- if (iter == m_counts.end())
- return nullptr;
- return &iter->value;
- }
-
- void dump(PrintStream& out) const
- {
- out.print(mapDump(m_counts));
- }
-
-private:
- HashMap<Thing, Counts> m_counts;
-};
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirUseCounts_h
-
diff --git a/Source/JavaScriptCore/b3/air/AirValidate.cpp b/Source/JavaScriptCore/b3/air/AirValidate.cpp
deleted file mode 100644
index bc8171469..000000000
--- a/Source/JavaScriptCore/b3/air/AirValidate.cpp
+++ /dev/null
@@ -1,141 +0,0 @@
-/*
- * 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 "AirValidate.h"
-
-#if ENABLE(B3_JIT)
-
-#include "AirCode.h"
-#include "AirInstInlines.h"
-
-namespace JSC { namespace B3 { namespace Air {
-
-namespace {
-
-class Validater {
-public:
- Validater(Code& code, const char* dumpBefore)
- : m_code(code)
- , m_dumpBefore(dumpBefore)
- {
- }
-
-#define VALIDATE(condition, message) do { \
- if (condition) \
- break; \
- fail(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #condition, toCString message); \
- } while (false)
-
- void run()
- {
- HashSet<StackSlot*> validSlots;
- HashSet<BasicBlock*> validBlocks;
- HashSet<Special*> validSpecials;
-
- for (BasicBlock* block : m_code)
- validBlocks.add(block);
- for (StackSlot* slot : m_code.stackSlots())
- validSlots.add(slot);
- for (Special* special : m_code.specials())
- validSpecials.add(special);
-
- for (BasicBlock* block : m_code) {
- for (unsigned instIndex = 0; instIndex < block->size(); ++instIndex) {
- Inst& inst = block->at(instIndex);
- for (Arg& arg : inst.args) {
- switch (arg.kind()) {
- case Arg::Stack:
- VALIDATE(validSlots.contains(arg.stackSlot()), ("At ", inst, " in ", *block));
- break;
- case Arg::Special:
- VALIDATE(validSpecials.contains(arg.special()), ("At ", inst, " in ", *block));
- break;
- default:
- break;
- }
- }
- VALIDATE(inst.isValidForm(), ("At ", inst, " in ", *block));
- if (instIndex == block->size() - 1)
- VALIDATE(isTerminal(inst.opcode), ("At ", inst, " in ", *block));
- else
- VALIDATE(!isTerminal(inst.opcode), ("At ", inst, " in ", *block));
-
- // forEachArg must return Arg&'s that point into the args array.
- inst.forEachArg(
- [&] (Arg& arg, Arg::Role, Arg::Type, Arg::Width) {
- VALIDATE(&arg >= &inst.args[0], ("At ", arg, " in ", inst, " in ", *block));
- VALIDATE(&arg <= &inst.args.last(), ("At ", arg, " in ", inst, " in ", *block));
- });
- }
- for (BasicBlock* successor : block->successorBlocks())
- VALIDATE(validBlocks.contains(successor), ("In ", *block));
- }
- }
-
-private:
- NO_RETURN_DUE_TO_CRASH void fail(
- const char* filename, int lineNumber, const char* function, const char* condition,
- CString message)
- {
- CString failureMessage;
- {
- StringPrintStream out;
- out.print("AIR VALIDATION FAILURE\n");
- out.print(" ", condition, " (", filename, ":", lineNumber, ")\n");
- out.print(" ", message, "\n");
- out.print(" After ", m_code.lastPhaseName(), "\n");
- failureMessage = out.toCString();
- }
-
- dataLog(failureMessage);
- if (m_dumpBefore) {
- dataLog("Before ", m_code.lastPhaseName(), ":\n");
- dataLog(m_dumpBefore);
- }
- dataLog("At time of failure:\n");
- dataLog(m_code);
-
- dataLog(failureMessage);
- WTFReportAssertionFailure(filename, lineNumber, function, condition);
- CRASH();
- }
-
- Code& m_code;
- const char* m_dumpBefore;
-};
-
-} // anonymous namespace
-
-void validate(Code& code, const char* dumpBefore)
-{
- Validater validater(code, dumpBefore);
- validater.run();
-}
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
diff --git a/Source/JavaScriptCore/b3/air/AirValidate.h b/Source/JavaScriptCore/b3/air/AirValidate.h
deleted file mode 100644
index 3b31c9625..000000000
--- a/Source/JavaScriptCore/b3/air/AirValidate.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * 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.
- */
-
-#ifndef AirValidate_h
-#define AirValidate_h
-
-#if ENABLE(B3_JIT)
-
-namespace JSC { namespace B3 { namespace Air {
-
-class Code;
-
-void validate(Code&, const char* dumpBefore = nullptr);
-
-} } } // namespace JSC::B3::Air
-
-#endif // ENABLE(B3_JIT)
-
-#endif // AirValidate_h
-
diff --git a/Source/JavaScriptCore/b3/air/opcode_generator.rb b/Source/JavaScriptCore/b3/air/opcode_generator.rb
deleted file mode 100644
index 8795d2e5b..000000000
--- a/Source/JavaScriptCore/b3/air/opcode_generator.rb
+++ /dev/null
@@ -1,1092 +0,0 @@
-#!/usr/bin/env ruby
-
-# Copyright (C) 2015-2016 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. AND ITS CONTRIBUTORS ``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 ITS 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.
-
-require "pathname"
-
-class Opcode
- attr_reader :name, :custom, :overloads
- attr_reader :attributes
-
- def initialize(name, custom)
- @name = name
- @custom = custom
- @attributes = {}
- unless custom
- @overloads = []
- end
- end
-
- def masmName
- name[0].downcase + name[1..-1]
- end
-end
-
-class Arg
- attr_reader :role, :type, :width
-
- def initialize(role, type, width)
- @role = role
- @type = type
- @width = width
- end
-
- def widthCode
- if width == "Ptr"
- "Arg::pointerWidth()"
- else
- "Arg::Width#{width}"
- end
- end
-end
-
-class Overload
- attr_reader :signature, :forms
-
- def initialize(signature, forms)
- @signature = signature
- @forms = forms
- end
-end
-
-class Kind
- attr_reader :name
- attr_accessor :custom
-
- def initialize(name)
- @name = name
- @custom = false
- end
-
- def ==(other)
- if other.is_a? String
- @name == other
- else
- @name == other.name and @custom == other.custom
- end
- end
-
- def Kind.argKinds(kind)
- if kind == "Addr"
- ["Addr", "Stack", "CallArg"]
- else
- [kind]
- end
- end
-
- def argKinds
- Kind.argKinds(kind)
- end
-end
-
-class Form
- attr_reader :kinds, :altName, :archs
-
- def initialize(kinds, altName, archs)
- @kinds = kinds
- @altName = altName
- @archs = archs
- end
-end
-
-class Origin
- attr_reader :fileName, :lineNumber
-
- def initialize(fileName, lineNumber)
- @fileName = fileName
- @lineNumber = lineNumber
- end
-
- def to_s
- "#{fileName}:#{lineNumber}"
- end
-end
-
-class Token
- attr_reader :origin, :string
-
- def initialize(origin, string)
- @origin = origin
- @string = string
- end
-
- def ==(other)
- if other.is_a? Token
- @string == other.string
- else
- @string == other
- end
- end
-
- def =~(other)
- @string =~ other
- end
-
- def to_s
- "#{@string.inspect} at #{origin}"
- end
-
- def parseError(*comment)
- if comment.empty?
- raise "Parse error: #{to_s}"
- else
- raise "Parse error: #{to_s}: #{comment[0]}"
- end
- end
-end
-
-def lex(str, fileName)
- fileName = Pathname.new(fileName)
- result = []
- lineNumber = 1
- while not str.empty?
- case str
- when /\A\#([^\n]*)/
- # comment, ignore
- when /\A\n/
- # newline, ignore
- lineNumber += 1
- when /\A([a-zA-Z0-9_]+)/
- result << Token.new(Origin.new(fileName, lineNumber), $&)
- when /\A([ \t\r]+)/
- # whitespace, ignore
- when /\A[,:*\/]/
- result << Token.new(Origin.new(fileName, lineNumber), $&)
- else
- raise "Lexer error at #{Origin.new(fileName, lineNumber).to_s}, unexpected sequence #{str[0..20].inspect}"
- end
- str = $~.post_match
- end
- result
-end
-
-def isRole(token)
- token =~ /\A((U)|(D)|(UD)|(ZD)|(UZD)|(UA)|(S))\Z/
-end
-
-def isGF(token)
- token =~ /\A((G)|(F))\Z/
-end
-
-def isKind(token)
- token =~ /\A((Tmp)|(Imm)|(BigImm)|(BitImm)|(BitImm64)|(Addr)|(Index)|(RelCond)|(ResCond)|(DoubleCond))\Z/
-end
-
-def isArch(token)
- token =~ /\A((x86)|(x86_32)|(x86_64)|(arm)|(armv7)|(arm64)|(32)|(64))\Z/
-end
-
-def isWidth(token)
- token =~ /\A((8)|(16)|(32)|(64)|(Ptr))\Z/
-end
-
-def isKeyword(token)
- isRole(token) or isGF(token) or isKind(token) or isArch(token) or isWidth(token) or
- token == "custom" or token == "as"
-end
-
-def isIdentifier(token)
- token =~ /\A([a-zA-Z0-9_]+)\Z/ and not isKeyword(token)
-end
-
-class Parser
- def initialize(data, fileName)
- @tokens = lex(data, fileName)
- @idx = 0
- end
-
- def token
- @tokens[@idx]
- end
-
- def advance
- @idx += 1
- end
-
- def parseError(*comment)
- if token
- token.parseError(*comment)
- else
- if comment.empty?
- raise "Parse error at end of file"
- else
- raise "Parse error at end of file: #{comment[0]}"
- end
- end
- end
-
- def consume(string)
- parseError("Expected #{string}") unless token == string
- advance
- end
-
- def consumeIdentifier
- result = token.string
- parseError("Expected identifier") unless isIdentifier(result)
- advance
- result
- end
-
- def consumeRole
- result = token.string
- parseError("Expected role (U, D, UD, ZD, UZD, UA, or S)") unless isRole(result)
- advance
- result
- end
-
- def consumeType
- result = token.string
- parseError("Expected type (G or F)") unless isGF(result)
- advance
- result
- end
-
- def consumeKind
- result = token.string
- parseError("Expected kind (Imm, BigImm, BitImm, BitImm64, Tmp, Addr, Index, RelCond, ResCond, or DoubleCond)") unless isKind(result)
- advance
- result
- end
-
- def consumeWidth
- result = token.string
- parseError("Expected width (8, 16, 32, or 64)") unless isWidth(result)
- advance
- result
- end
-
- def parseArchs
- return nil unless isArch(token)
-
- result = []
- while isArch(token)
- case token.string
- when "x86"
- result << "X86"
- result << "X86_64"
- when "x86_32"
- result << "X86"
- when "x86_64"
- result << "X86_64"
- when "arm"
- result << "ARMv7"
- result << "ARM64"
- when "armv7"
- result << "ARMv7"
- when "arm64"
- result << "ARM64"
- when "32"
- result << "X86"
- result << "ARMv7"
- when "64"
- result << "X86_64"
- result << "ARM64"
- else
- raise token.string
- end
- advance
- end
-
- consume(":")
- @lastArchs = result
- end
-
- def consumeArchs
- result = @lastArchs
- @lastArchs = nil
- result
- end
-
- def parseAndConsumeArchs
- parseArchs
- consumeArchs
- end
-
- def intersectArchs(left, right)
- return left unless right
- return right unless left
-
- left.select {
- | value |
- right.find {
- | otherValue |
- value == otherValue
- }
- }
- end
-
- def parse
- result = {}
-
- loop {
- break if @idx >= @tokens.length
-
- if token == "custom"
- consume("custom")
- opcodeName = consumeIdentifier
-
- parseError("Cannot overload a custom opcode") if result[opcodeName]
-
- result[opcodeName] = Opcode.new(opcodeName, true)
- else
- opcodeArchs = parseAndConsumeArchs
-
- opcodeName = consumeIdentifier
-
- if result[opcodeName]
- opcode = result[opcodeName]
- parseError("Cannot overload a custom opcode") if opcode.custom
- else
- opcode = Opcode.new(opcodeName, false)
- result[opcodeName] = opcode
- end
-
- signature = []
- forms = []
-
- if isRole(token)
- loop {
- role = consumeRole
- consume(":")
- type = consumeType
- consume(":")
- width = consumeWidth
-
- signature << Arg.new(role, type, width)
-
- break unless token == ","
- consume(",")
- }
- end
-
- while token == "/"
- consume("/")
- case token.string
- when "branch"
- opcode.attributes[:branch] = true
- opcode.attributes[:terminal] = true
- when "terminal"
- opcode.attributes[:terminal] = true
- when "effects"
- opcode.attributes[:effects] = true
- when "return"
- opcode.attributes[:return] = true
- opcode.attributes[:terminal] = true
- else
- parseError("Bad / directive")
- end
- advance
- end
-
- parseArchs
- if isKind(token)
- loop {
- kinds = []
- altName = nil
- formArchs = consumeArchs
- loop {
- kinds << Kind.new(consumeKind)
-
- if token == "*"
- parseError("Can only apply * to Tmp") unless kinds[-1].name == "Tmp"
- kinds[-1].custom = true
- consume("*")
- end
-
- break unless token == ","
- consume(",")
- }
-
- if token == "as"
- consume("as")
- altName = consumeIdentifier
- end
-
- parseError("Form has wrong number of arguments for overload") unless kinds.length == signature.length
- kinds.each_with_index {
- | kind, index |
- if kind.name == "Imm" or kind.name == "BigImm" or kind.name == "BitImm" or kind.name == "BitImm64"
- if signature[index].role != "U"
- parseError("Form has an immediate for a non-use argument")
- end
- if signature[index].type != "G"
- parseError("Form has an immediate for a non-general-purpose argument")
- end
- end
- }
- forms << Form.new(kinds, altName, intersectArchs(opcodeArchs, formArchs))
-
- parseArchs
- break unless isKind(token)
- }
- end
-
- if signature.length == 0
- raise unless forms.length == 0
- forms << Form.new([], nil, opcodeArchs)
- end
-
- opcode.overloads << Overload.new(signature, forms)
- end
- }
-
- result
- end
-end
-
-$fileName = ARGV[0]
-
-parser = Parser.new(IO::read($fileName), $fileName)
-$opcodes = parser.parse
-
-def writeH(filename)
- File.open("Air#{filename}.h", "w") {
- | outp |
-
- outp.puts "// Generated by opcode_generator.rb from #{$fileName} -- do not edit!"
-
- outp.puts "#ifndef Air#{filename}_h"
- outp.puts "#define Air#{filename}_h"
-
- yield outp
-
- outp.puts "#endif // Air#{filename}_h"
- }
-end
-
-writeH("Opcode") {
- | outp |
- outp.puts "namespace JSC { namespace B3 { namespace Air {"
- outp.puts "enum Opcode : int16_t {"
- $opcodes.keys.sort.each {
- | opcode |
- outp.puts " #{opcode},"
- }
- outp.puts "};"
-
- outp.puts "static const unsigned numOpcodes = #{$opcodes.keys.size};"
- outp.puts "} } } // namespace JSC::B3::Air"
-
- outp.puts "namespace WTF {"
- outp.puts "class PrintStream;"
- outp.puts "void printInternal(PrintStream&, JSC::B3::Air::Opcode);"
- outp.puts "} // namespace WTF"
-}
-
-# From here on, we don't try to emit properly indented code, since we're using a recursive pattern
-# matcher.
-
-def matchForms(outp, speed, forms, columnIndex, columnGetter, filter, callback)
- return if forms.length == 0
-
- if filter[forms]
- return
- end
-
- if columnIndex >= forms[0].kinds.length
- raise "Did not reduce to one form: #{forms.inspect}" unless forms.length == 1
- callback[forms[0]]
- outp.puts "break;"
- return
- end
-
- groups = {}
- forms.each {
- | form |
- kind = form.kinds[columnIndex].name
- if groups[kind]
- groups[kind] << form
- else
- groups[kind] = [form]
- end
- }
-
- if speed == :fast and groups.length == 1
- matchForms(outp, speed, forms, columnIndex + 1, columnGetter, filter, callback)
- return
- end
-
- outp.puts "switch (#{columnGetter[columnIndex]}) {"
- groups.each_pair {
- | key, value |
- outp.puts "#if USE(JSVALUE64)" if key == "BigImm" or key == "BitImm64"
- Kind.argKinds(key).each {
- | argKind |
- outp.puts "case Arg::#{argKind}:"
- }
- matchForms(outp, speed, value, columnIndex + 1, columnGetter, filter, callback)
- outp.puts "break;"
- outp.puts "#endif // USE(JSVALUE64)" if key == "BigImm" or key == "BitImm64"
- }
- outp.puts "default:"
- outp.puts "break;"
- outp.puts "}"
-end
-
-def matchInstOverload(outp, speed, inst)
- outp.puts "switch (#{inst}->opcode) {"
- $opcodes.values.each {
- | opcode |
- outp.puts "case #{opcode.name}:"
- if opcode.custom
- yield opcode, nil
- else
- needOverloadSwitch = ((opcode.overloads.size != 1) or speed == :safe)
- outp.puts "switch (#{inst}->args.size()) {" if needOverloadSwitch
- opcode.overloads.each {
- | overload |
- outp.puts "case #{overload.signature.length}:" if needOverloadSwitch
- yield opcode, overload
- outp.puts "break;" if needOverloadSwitch
- }
- if needOverloadSwitch
- outp.puts "default:"
- outp.puts "break;"
- outp.puts "}"
- end
- end
- outp.puts "break;"
- }
- outp.puts "default:"
- outp.puts "break;"
- outp.puts "}"
-end
-
-def matchInstOverloadForm(outp, speed, inst)
- matchInstOverload(outp, speed, inst) {
- | opcode, overload |
- if opcode.custom
- yield opcode, nil, nil
- else
- columnGetter = proc {
- | columnIndex |
- "#{inst}->args[#{columnIndex}].kind()"
- }
- filter = proc { false }
- callback = proc {
- | form |
- yield opcode, overload, form
- }
- matchForms(outp, speed, overload.forms, 0, columnGetter, filter, callback)
- end
- }
-end
-
-def beginArchs(outp, archs)
- return unless archs
- if archs.empty?
- outp.puts "#if 0"
- return
- end
- outp.puts("#if " + archs.map {
- | arch |
- "CPU(#{arch})"
- }.join(" || "))
-end
-
-def endArchs(outp, archs)
- return unless archs
- outp.puts "#endif"
-end
-
-writeH("OpcodeUtils") {
- | outp |
- outp.puts "#include \"AirCustom.h\""
- outp.puts "#include \"AirInst.h\""
- outp.puts "namespace JSC { namespace B3 { namespace Air {"
-
- outp.puts "inline bool opgenHiddenTruth() { return true; }"
- outp.puts "template<typename T>"
- outp.puts "inline T* opgenHiddenPtrIdentity(T* pointer) { return pointer; }"
- outp.puts "#define OPGEN_RETURN(value) do {\\"
- outp.puts " if (opgenHiddenTruth())\\"
- outp.puts " return value;\\"
- outp.puts "} while (false)"
-
- outp.puts "template<typename Functor>"
- outp.puts "void Inst::forEachArg(const Functor& functor)"
- outp.puts "{"
- matchInstOverload(outp, :fast, "this") {
- | opcode, overload |
- if opcode.custom
- outp.puts "#{opcode.name}Custom::forEachArg(*this, functor);"
- else
- overload.signature.each_with_index {
- | arg, index |
-
- role = nil
- case arg.role
- when "U"
- role = "Use"
- when "D"
- role = "Def"
- when "ZD"
- role = "ZDef"
- when "UD"
- role = "UseDef"
- when "UZD"
- role = "UseZDef"
- when "UA"
- role = "UseAddr"
- when "S"
- role = "Scratch"
- else
- raise
- end
-
- outp.puts "functor(args[#{index}], Arg::#{role}, Arg::#{arg.type}P, #{arg.widthCode});"
- }
- end
- }
- outp.puts "}"
-
- outp.puts "template<typename... Arguments>"
- outp.puts "ALWAYS_INLINE bool isValidForm(Opcode opcode, Arguments... arguments)"
- outp.puts "{"
- outp.puts "Arg::Kind kinds[sizeof...(Arguments)] = { arguments... };"
- outp.puts "switch (opcode) {"
- $opcodes.values.each {
- | opcode |
- outp.puts "case #{opcode.name}:"
- if opcode.custom
- outp.puts "OPGEN_RETURN(#{opcode.name}Custom::isValidFormStatic(arguments...));"
- else
- outp.puts "switch (sizeof...(Arguments)) {"
- opcode.overloads.each {
- | overload |
- outp.puts "case #{overload.signature.length}:"
- columnGetter = proc { | columnIndex | "opgenHiddenPtrIdentity(kinds)[#{columnIndex}]" }
- filter = proc { false }
- callback = proc {
- | form |
- # This conservatively says that Stack is not a valid form for UseAddr,
- # because it's only valid if it's not a spill slot. This is consistent with
- # isValidForm() being conservative and it also happens to be practical since
- # we don't really use isValidForm for deciding when Stack is safe.
- overload.signature.length.times {
- | index |
- if overload.signature[index].role == "UA"
- outp.puts "if (opgenHiddenPtrIdentity(kinds)[#{index}] == Arg::Stack)"
- outp.puts " return false;"
- end
- }
-
- notCustom = (not form.kinds.detect { | kind | kind.custom })
- if notCustom
- beginArchs(outp, form.archs)
- outp.puts "OPGEN_RETURN(true);"
- endArchs(outp, form.archs)
- end
- }
- matchForms(outp, :safe, overload.forms, 0, columnGetter, filter, callback)
- outp.puts "break;"
- }
- outp.puts "default:"
- outp.puts "break;"
- outp.puts "}"
- end
- outp.puts "break;"
- }
- outp.puts "default:"
- outp.puts "break;"
- outp.puts "}"
- outp.puts "return false; "
- outp.puts "}"
-
- outp.puts "inline bool isTerminal(Opcode opcode)"
- outp.puts "{"
- outp.puts "switch (opcode) {"
- didFindTerminals = false
- $opcodes.values.each {
- | opcode |
- if opcode.attributes[:terminal]
- outp.puts "case #{opcode.name}:"
- didFindTerminals = true
- end
- }
- if didFindTerminals
- outp.puts "return true;"
- end
- outp.puts "default:"
- outp.puts "return false;"
- outp.puts "}"
- outp.puts "}"
-
- outp.puts "inline bool isReturn(Opcode opcode)"
- outp.puts "{"
- outp.puts "switch (opcode) {"
- didFindReturns = false
- $opcodes.values.each {
- | opcode |
- if opcode.attributes[:return]
- outp.puts "case #{opcode.name}:"
- didFindReturns = true
- end
- }
- if didFindReturns
- outp.puts "return true;"
- end
- outp.puts "default:"
- outp.puts "return false;"
- outp.puts "}"
- outp.puts "}"
-
- outp.puts "} } } // namespace JSC::B3::Air"
-}
-
-writeH("OpcodeGenerated") {
- | outp |
- outp.puts "#include \"AirInstInlines.h\""
- outp.puts "#include \"wtf/PrintStream.h\""
- outp.puts "namespace WTF {"
- outp.puts "using namespace JSC::B3::Air;"
- outp.puts "void printInternal(PrintStream& out, Opcode opcode)"
- outp.puts "{"
- outp.puts " switch (opcode) {"
- $opcodes.keys.each {
- | opcode |
- outp.puts " case #{opcode}:"
- outp.puts " out.print(\"#{opcode}\");"
- outp.puts " return;"
- }
- outp.puts " }"
- outp.puts " RELEASE_ASSERT_NOT_REACHED();"
- outp.puts "}"
- outp.puts "} // namespace WTF"
- outp.puts "namespace JSC { namespace B3 { namespace Air {"
- outp.puts "bool Inst::isValidForm()"
- outp.puts "{"
- matchInstOverloadForm(outp, :safe, "this") {
- | opcode, overload, form |
- if opcode.custom
- outp.puts "OPGEN_RETURN(#{opcode.name}Custom::isValidForm(*this));"
- else
- beginArchs(outp, form.archs)
- needsMoreValidation = false
- overload.signature.length.times {
- | index |
- arg = overload.signature[index]
- kind = form.kinds[index]
- needsMoreValidation |= kind.custom
-
- # Some kinds of Args reqire additional validation.
- case kind.name
- when "Tmp"
- outp.puts "if (!args[#{index}].tmp().is#{arg.type}P())"
- outp.puts "OPGEN_RETURN(false);"
- when "Imm"
- outp.puts "if (!Arg::isValidImmForm(args[#{index}].value()))"
- outp.puts "OPGEN_RETURN(false);"
- when "BitImm"
- outp.puts "if (!Arg::isValidBitImmForm(args[#{index}].value()))"
- outp.puts "OPGEN_RETURN(false);"
- when "BitImm64"
- outp.puts "if (!Arg::isValidBitImm64Form(args[#{index}].value()))"
- outp.puts "OPGEN_RETURN(false);"
- when "Addr"
- if arg.role == "UA"
- outp.puts "if (args[#{index}].isStack() && args[#{index}].stackSlot()->isSpill())"
- outp.puts "OPGEN_RETURN(false);"
- end
-
- outp.puts "if (!Arg::isValidAddrForm(args[#{index}].offset()))"
- outp.puts "OPGEN_RETURN(false);"
- when "Index"
- outp.puts "if (!Arg::isValidIndexForm(args[#{index}].scale(), args[#{index}].offset(), #{arg.widthCode}))"
- outp.puts "OPGEN_RETURN(false);"
- when "BigImm"
- when "RelCond"
- when "ResCond"
- when "DoubleCond"
- else
- raise "Unexpected kind: #{kind.name}"
- end
- }
- if needsMoreValidation
- outp.puts "if (!is#{opcode.name}Valid(*this))"
- outp.puts "OPGEN_RETURN(false);"
- end
- outp.puts "OPGEN_RETURN(true);"
- endArchs(outp, form.archs)
- end
- }
- outp.puts "return false;"
- outp.puts "}"
-
- outp.puts "bool Inst::admitsStack(unsigned argIndex)"
- outp.puts "{"
- outp.puts "switch (opcode) {"
- $opcodes.values.each {
- | opcode |
- outp.puts "case #{opcode.name}:"
-
- if opcode.custom
- outp.puts "OPGEN_RETURN(#{opcode.name}Custom::admitsStack(*this, argIndex));"
- else
- # Switch on the argIndex.
- outp.puts "switch (argIndex) {"
-
- numArgs = opcode.overloads.map {
- | overload |
- overload.signature.length
- }.max
-
- numArgs.times {
- | argIndex |
- outp.puts "case #{argIndex}:"
-
- # Check if all of the forms of all of the overloads either do, or don't, admit an address
- # at this index. We expect this to be a very common case.
- numYes = 0
- numNo = 0
- opcode.overloads.each {
- | overload |
- useAddr = (overload.signature[argIndex] and
- overload.signature[argIndex].role == "UA")
- overload.forms.each {
- | form |
- if form.kinds[argIndex] == "Addr" and not useAddr
- numYes += 1
- else
- numNo += 1
- end
- }
- }
-
- # Note that we deliberately test numYes first because if we end up with no forms, we want
- # to say that Address is inadmissible.
- if numYes == 0
- outp.puts "OPGEN_RETURN(false);"
- elsif numNo == 0
- outp.puts "OPGEN_RETURN(true);"
- else
- # Now do the full test.
-
- needOverloadSwitch = (opcode.overloads.size != 1)
-
- outp.puts "switch (args.size()) {" if needOverloadSwitch
- opcode.overloads.each {
- | overload |
-
- useAddr = (overload.signature[argIndex] and
- overload.signature[argIndex].role == "UA")
-
- # Again, check if all of them do what we want.
- numYes = 0
- numNo = 0
- overload.forms.each {
- | form |
- if form.kinds[argIndex] == "Addr" and not useAddr
- numYes += 1
- else
- numNo += 1
- end
- }
-
- if numYes == 0
- # Don't emit anything, just drop to default.
- elsif numNo == 0
- outp.puts "case #{overload.signature.length}:" if needOverloadSwitch
- outp.puts "OPGEN_RETURN(true);"
- outp.puts "break;" if needOverloadSwitch
- else
- outp.puts "case #{overload.signature.length}:" if needOverloadSwitch
-
- # This is how we test the hypothesis that changing this argument to an
- # address yields a valid form.
- columnGetter = proc {
- | columnIndex |
- if columnIndex == argIndex
- "Arg::Addr"
- else
- "args[#{columnIndex}].kind()"
- end
- }
- filter = proc {
- | forms |
- numYes = 0
-
- forms.each {
- | form |
- if form.kinds[argIndex] == "Addr"
- numYes += 1
- end
- }
-
- if numYes == 0
- # Drop down, emit no code, since we cannot match.
- true
- else
- # Keep going.
- false
- end
- }
- callback = proc {
- | form |
- beginArchs(outp, form.archs)
- outp.puts "OPGEN_RETURN(true);"
- endArchs(outp, form.archs)
- }
- matchForms(outp, :safe, overload.forms, 0, columnGetter, filter, callback)
-
- outp.puts "break;" if needOverloadSwitch
- end
- }
- if needOverloadSwitch
- outp.puts "default:"
- outp.puts "break;"
- outp.puts "}"
- end
- end
-
- outp.puts "break;"
- }
-
- outp.puts "default:"
- outp.puts "break;"
- outp.puts "}"
- end
-
- outp.puts "break;"
- }
- outp.puts "default:";
- outp.puts "break;"
- outp.puts "}"
- outp.puts "return false;"
- outp.puts "}"
-
- outp.puts "bool Inst::hasNonArgNonControlEffects()"
- outp.puts "{"
- outp.puts "switch (opcode) {"
- foundTrue = false
- $opcodes.values.each {
- | opcode |
- if opcode.attributes[:effects]
- outp.puts "case #{opcode.name}:"
- foundTrue = true
- end
- }
- if foundTrue
- outp.puts "return true;"
- end
- $opcodes.values.each {
- | opcode |
- if opcode.custom
- outp.puts "case #{opcode.name}:"
- outp.puts "return #{opcode.name}Custom::hasNonArgNonControlEffects(*this);"
- end
- }
- outp.puts "default:"
- outp.puts "return false;"
- outp.puts "}"
- outp.puts "}"
-
- outp.puts "bool Inst::hasNonArgEffects()"
- outp.puts "{"
- outp.puts "switch (opcode) {"
- foundTrue = false
- $opcodes.values.each {
- | opcode |
- if opcode.attributes[:terminal] or opcode.attributes[:effects]
- outp.puts "case #{opcode.name}:"
- foundTrue = true
- end
- }
- if foundTrue
- outp.puts "return true;"
- end
- $opcodes.values.each {
- | opcode |
- if opcode.custom
- outp.puts "case #{opcode.name}:"
- outp.puts "return #{opcode.name}Custom::hasNonArgNonControlEffects(*this);"
- end
- }
- outp.puts "default:"
- outp.puts "return false;"
- outp.puts "}"
- outp.puts "}"
-
- outp.puts "CCallHelpers::Jump Inst::generate(CCallHelpers& jit, GenerationContext& context)"
- outp.puts "{"
- outp.puts "UNUSED_PARAM(jit);"
- outp.puts "UNUSED_PARAM(context);"
- outp.puts "CCallHelpers::Jump result;"
- matchInstOverloadForm(outp, :fast, "this") {
- | opcode, overload, form |
- if opcode.custom
- outp.puts "OPGEN_RETURN(#{opcode.name}Custom::generate(*this, jit, context));"
- else
- beginArchs(outp, form.archs)
- if form.altName
- methodName = form.altName
- else
- methodName = opcode.masmName
- end
- if opcode.attributes[:branch]
- outp.print "result = "
- end
- outp.print "jit.#{methodName}("
-
- form.kinds.each_with_index {
- | kind, index |
- if index != 0
- outp.print ", "
- end
- case kind.name
- when "Tmp"
- if overload.signature[index].type == "G"
- outp.print "args[#{index}].gpr()"
- else
- outp.print "args[#{index}].fpr()"
- end
- when "Imm", "BitImm"
- outp.print "args[#{index}].asTrustedImm32()"
- when "BigImm", "BitImm64"
- outp.print "args[#{index}].asTrustedImm64()"
- when "Addr"
- outp.print "args[#{index}].asAddress()"
- when "Index"
- outp.print "args[#{index}].asBaseIndex()"
- when "RelCond"
- outp.print "args[#{index}].asRelationalCondition()"
- when "ResCond"
- outp.print "args[#{index}].asResultCondition()"
- when "DoubleCond"
- outp.print "args[#{index}].asDoubleCondition()"
- end
- }
-
- outp.puts ");"
- outp.puts "OPGEN_RETURN(result);"
- endArchs(outp, form.archs)
- end
- }
- outp.puts "RELEASE_ASSERT_NOT_REACHED();"
- outp.puts "return result;"
- outp.puts "}"
-
- outp.puts "} } } // namespace JSC::B3::Air"
-}
-
diff --git a/Source/JavaScriptCore/b3/air/testair.cpp b/Source/JavaScriptCore/b3/air/testair.cpp
deleted file mode 100644
index 652498fcd..000000000
--- a/Source/JavaScriptCore/b3/air/testair.cpp
+++ /dev/null
@@ -1,1753 +0,0 @@
-/*
- * Copyright (C) 2016 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 "AirCode.h"
-#include "AirGenerate.h"
-#include "AirInstInlines.h"
-#include "AirRegisterPriority.h"
-#include "AllowMacroScratchRegisterUsage.h"
-#include "B3Compilation.h"
-#include "B3Procedure.h"
-#include "CCallHelpers.h"
-#include "InitializeThreading.h"
-#include "JSCInlines.h"
-#include "LinkBuffer.h"
-#include "PureNaN.h"
-#include "VM.h"
-#include <cmath>
-#include <map>
-#include <string>
-#include <wtf/Lock.h>
-#include <wtf/NumberOfCores.h>
-#include <wtf/Threading.h>
-
-// We don't have a NO_RETURN_DUE_TO_EXIT, nor should we. That's ridiculous.
-static bool hiddenTruthBecauseNoReturnIsStupid() { return true; }
-
-static void usage()
-{
- dataLog("Usage: testb3 [<filter>]\n");
- if (hiddenTruthBecauseNoReturnIsStupid())
- exit(1);
-}
-
-#if ENABLE(B3_JIT)
-
-using namespace JSC;
-using namespace JSC::B3::Air;
-
-namespace {
-
-StaticLock crashLock;
-
-// Nothing fancy for now; we just use the existing WTF assertion machinery.
-#define CHECK(x) do { \
- if (!!(x)) \
- break; \
- crashLock.lock(); \
- WTFReportAssertionFailure(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, #x); \
- CRASH(); \
- } while (false)
-
-VM* vm;
-
-std::unique_ptr<B3::Compilation> compile(B3::Procedure& proc)
-{
- prepareForGeneration(proc.code());
- CCallHelpers jit(vm);
- generate(proc.code(), jit);
- LinkBuffer linkBuffer(*vm, jit, nullptr);
-
- return std::make_unique<B3::Compilation>(
- FINALIZE_CODE(linkBuffer, ("testair compilation")), proc.releaseByproducts());
-}
-
-template<typename T, typename... Arguments>
-T invoke(const B3::Compilation& code, Arguments... arguments)
-{
- T (*function)(Arguments...) = bitwise_cast<T(*)(Arguments...)>(code.code().executableAddress());
- return function(arguments...);
-}
-
-template<typename T, typename... Arguments>
-T compileAndRun(B3::Procedure& procedure, Arguments... arguments)
-{
- return invoke<T>(*compile(procedure), arguments...);
-}
-
-void testSimple()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- root->append(Move, nullptr, Arg::imm(42), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- CHECK(compileAndRun<int>(proc) == 42);
-}
-
-// Use this to put a constant into a register without Air being able to see the constant.
-template<typename T>
-void loadConstantImpl(BasicBlock* block, T value, B3::Air::Opcode move, Tmp tmp, Tmp scratch)
-{
- static StaticLock lock;
- static std::map<T, T*>* map; // I'm not messing with HashMap's problems with integers.
-
- LockHolder locker(lock);
- if (!map)
- map = new std::map<T, T*>();
-
- if (!map->count(value))
- (*map)[value] = new T(value);
-
- T* ptr = (*map)[value];
- block->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(ptr)), scratch);
- block->append(move, nullptr, Arg::addr(scratch), tmp);
-}
-
-void loadConstant(BasicBlock* block, intptr_t value, Tmp tmp)
-{
- loadConstantImpl<intptr_t>(block, value, Move, tmp, tmp);
-}
-
-void loadDoubleConstant(BasicBlock* block, double value, Tmp tmp, Tmp scratch)
-{
- loadConstantImpl<double>(block, value, MoveDouble, tmp, scratch);
-}
-
-void testShuffleSimpleSwap()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32));
-
- int32_t things[4];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 2);
- CHECK(things[2] == 4);
- CHECK(things[3] == 3);
-}
-
-void testShuffleSimpleShift()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32));
-
- int32_t things[5];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 2);
- CHECK(things[2] == 3);
- CHECK(things[3] == 3);
- CHECK(things[4] == 4);
-}
-
-void testShuffleLongShift()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- loadConstant(root, 7, Tmp(GPRInfo::regT6));
- loadConstant(root, 8, Tmp(GPRInfo::regT7));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT6), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT6), Tmp(GPRInfo::regT7), Arg::widthArg(Arg::Width32));
-
- int32_t things[8];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 1);
- CHECK(things[2] == 2);
- CHECK(things[3] == 3);
- CHECK(things[4] == 4);
- CHECK(things[5] == 5);
- CHECK(things[6] == 6);
- CHECK(things[7] == 7);
-}
-
-void testShuffleLongShiftBackwards()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- loadConstant(root, 7, Tmp(GPRInfo::regT6));
- loadConstant(root, 8, Tmp(GPRInfo::regT7));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT6), Tmp(GPRInfo::regT7), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT6), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32));
-
- int32_t things[8];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 1);
- CHECK(things[2] == 2);
- CHECK(things[3] == 3);
- CHECK(things[4] == 4);
- CHECK(things[5] == 5);
- CHECK(things[6] == 6);
- CHECK(things[7] == 7);
-}
-
-void testShuffleSimpleRotate()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Arg::Width32));
-
- int32_t things[4];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 3);
- CHECK(things[1] == 1);
- CHECK(things[2] == 2);
- CHECK(things[3] == 4);
-}
-
-void testShuffleSimpleBroadcast()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32));
-
- int32_t things[4];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 1);
- CHECK(things[2] == 1);
- CHECK(things[3] == 1);
-}
-
-void testShuffleBroadcastAllRegs()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- const Vector<Reg>& regs = regsInPriorityOrder(Arg::GP);
-
- BasicBlock* root = code.addBlock();
- root->append(Move, nullptr, Arg::imm(35), Tmp(GPRInfo::regT0));
- unsigned count = 1;
- for (Reg reg : regs) {
- if (reg != Reg(GPRInfo::regT0))
- loadConstant(root, count++, Tmp(reg));
- }
- Inst& shuffle = root->append(Shuffle, nullptr);
- for (Reg reg : regs) {
- if (reg != Reg(GPRInfo::regT0))
- shuffle.append(Tmp(GPRInfo::regT0), Tmp(reg), Arg::widthArg(Arg::Width32));
- }
-
- StackSlot* slot = code.addStackSlot(sizeof(int32_t) * regs.size(), StackSlotKind::Locked);
- for (unsigned i = 0; i < regs.size(); ++i)
- root->append(Move32, nullptr, Tmp(regs[i]), Arg::stack(slot, i * sizeof(int32_t)));
-
- Vector<int32_t> things(regs.size(), 666);
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), base);
- for (unsigned i = 0; i < regs.size(); ++i) {
- root->append(Move32, nullptr, Arg::stack(slot, i * sizeof(int32_t)), Tmp(GPRInfo::regT0));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, i * sizeof(int32_t)));
- }
-
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- CHECK(!compileAndRun<int>(proc));
-
- for (int32_t thing : things)
- CHECK(thing == 35);
-}
-
-void testShuffleTreeShift()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- loadConstant(root, 7, Tmp(GPRInfo::regT6));
- loadConstant(root, 8, Tmp(GPRInfo::regT7));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT6), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT7), Arg::widthArg(Arg::Width32));
-
- int32_t things[8];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 1);
- CHECK(things[2] == 1);
- CHECK(things[3] == 2);
- CHECK(things[4] == 2);
- CHECK(things[5] == 3);
- CHECK(things[6] == 3);
- CHECK(things[7] == 4);
-}
-
-void testShuffleTreeShiftBackward()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- loadConstant(root, 7, Tmp(GPRInfo::regT6));
- loadConstant(root, 8, Tmp(GPRInfo::regT7));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT7), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT6), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32));
-
- int32_t things[8];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 1);
- CHECK(things[2] == 1);
- CHECK(things[3] == 2);
- CHECK(things[4] == 2);
- CHECK(things[5] == 3);
- CHECK(things[6] == 3);
- CHECK(things[7] == 4);
-}
-
-void testShuffleTreeShiftOtherBackward()
-{
- // NOTE: This test was my original attempt at TreeShiftBackward but mistakes were made. So, this
- // ends up being just a weird test. But weird tests are useful, so I kept it.
-
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- loadConstant(root, 7, Tmp(GPRInfo::regT6));
- loadConstant(root, 8, Tmp(GPRInfo::regT7));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT7), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT6), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT6), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT6), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT7), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT7), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32));
-
- int32_t things[8];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT6), Arg::addr(base, 6 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT7), Arg::addr(base, 7 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 8);
- CHECK(things[2] == 8);
- CHECK(things[3] == 7);
- CHECK(things[4] == 7);
- CHECK(things[5] == 6);
- CHECK(things[6] == 6);
- CHECK(things[7] == 5);
-}
-
-void testShuffleMultipleShifts()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32));
-
- int32_t things[6];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 1);
- CHECK(things[2] == 3);
- CHECK(things[3] == 3);
- CHECK(things[4] == 3);
- CHECK(things[5] == 1);
-}
-
-void testShuffleRotateWithFringe()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32));
-
- int32_t things[6];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 3);
- CHECK(things[1] == 1);
- CHECK(things[2] == 2);
- CHECK(things[3] == 1);
- CHECK(things[4] == 2);
- CHECK(things[5] == 3);
-}
-
-void testShuffleRotateWithFringeInWeirdOrder()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32));
-
- int32_t things[6];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 3);
- CHECK(things[1] == 1);
- CHECK(things[2] == 2);
- CHECK(things[3] == 1);
- CHECK(things[4] == 2);
- CHECK(things[5] == 3);
-}
-
-void testShuffleRotateWithLongFringe()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32));
-
- int32_t things[6];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 3);
- CHECK(things[1] == 1);
- CHECK(things[2] == 2);
- CHECK(things[3] == 1);
- CHECK(things[4] == 4);
- CHECK(things[5] == 5);
-}
-
-void testShuffleMultipleRotates()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT5), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32));
-
- int32_t things[6];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 3);
- CHECK(things[1] == 1);
- CHECK(things[2] == 2);
- CHECK(things[3] == 6);
- CHECK(things[4] == 4);
- CHECK(things[5] == 5);
-}
-
-void testShuffleShiftAndRotate()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- loadConstant(root, 4, Tmp(GPRInfo::regT3));
- loadConstant(root, 5, Tmp(GPRInfo::regT4));
- loadConstant(root, 6, Tmp(GPRInfo::regT5));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT1), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT0), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT4), Tmp(GPRInfo::regT5), Arg::widthArg(Arg::Width32));
-
- int32_t things[6];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT5), Arg::addr(base, 5 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 3);
- CHECK(things[1] == 1);
- CHECK(things[2] == 2);
- CHECK(things[3] == 4);
- CHECK(things[4] == 4);
- CHECK(things[5] == 5);
-}
-
-void testShuffleShiftAllRegs()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- const Vector<Reg>& regs = regsInPriorityOrder(Arg::GP);
-
- BasicBlock* root = code.addBlock();
- for (unsigned i = 0; i < regs.size(); ++i)
- loadConstant(root, 35 + i, Tmp(regs[i]));
- Inst& shuffle = root->append(Shuffle, nullptr);
- for (unsigned i = 1; i < regs.size(); ++i)
- shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Arg::Width32));
-
- StackSlot* slot = code.addStackSlot(sizeof(int32_t) * regs.size(), StackSlotKind::Locked);
- for (unsigned i = 0; i < regs.size(); ++i)
- root->append(Move32, nullptr, Tmp(regs[i]), Arg::stack(slot, i * sizeof(int32_t)));
-
- Vector<int32_t> things(regs.size(), 666);
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), base);
- for (unsigned i = 0; i < regs.size(); ++i) {
- root->append(Move32, nullptr, Arg::stack(slot, i * sizeof(int32_t)), Tmp(GPRInfo::regT0));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, i * sizeof(int32_t)));
- }
-
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 35);
- for (unsigned i = 1; i < regs.size(); ++i)
- CHECK(things[i] == 35 + static_cast<int32_t>(i) - 1);
-}
-
-void testShuffleRotateAllRegs()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- const Vector<Reg>& regs = regsInPriorityOrder(Arg::GP);
-
- BasicBlock* root = code.addBlock();
- for (unsigned i = 0; i < regs.size(); ++i)
- loadConstant(root, 35 + i, Tmp(regs[i]));
- Inst& shuffle = root->append(Shuffle, nullptr);
- for (unsigned i = 1; i < regs.size(); ++i)
- shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Arg::Width32));
- shuffle.append(Tmp(regs.last()), Tmp(regs[0]), Arg::widthArg(Arg::Width32));
-
- StackSlot* slot = code.addStackSlot(sizeof(int32_t) * regs.size(), StackSlotKind::Locked);
- for (unsigned i = 0; i < regs.size(); ++i)
- root->append(Move32, nullptr, Tmp(regs[i]), Arg::stack(slot, i * sizeof(int32_t)));
-
- Vector<int32_t> things(regs.size(), 666);
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), base);
- for (unsigned i = 0; i < regs.size(); ++i) {
- root->append(Move32, nullptr, Arg::stack(slot, i * sizeof(int32_t)), Tmp(GPRInfo::regT0));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, i * sizeof(int32_t)));
- }
-
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 35 + static_cast<int32_t>(regs.size()) - 1);
- for (unsigned i = 1; i < regs.size(); ++i)
- CHECK(things[i] == 35 + static_cast<int32_t>(i) - 1);
-}
-
-void testShuffleSimpleSwap64()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 10000000000000000ll, Tmp(GPRInfo::regT0));
- loadConstant(root, 20000000000000000ll, Tmp(GPRInfo::regT1));
- loadConstant(root, 30000000000000000ll, Tmp(GPRInfo::regT2));
- loadConstant(root, 40000000000000000ll, Tmp(GPRInfo::regT3));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width64),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width64));
-
- int64_t things[4];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int64_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 10000000000000000ll);
- CHECK(things[1] == 20000000000000000ll);
- CHECK(things[2] == 40000000000000000ll);
- CHECK(things[3] == 30000000000000000ll);
-}
-
-void testShuffleSimpleShift64()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 10000000000000000ll, Tmp(GPRInfo::regT0));
- loadConstant(root, 20000000000000000ll, Tmp(GPRInfo::regT1));
- loadConstant(root, 30000000000000000ll, Tmp(GPRInfo::regT2));
- loadConstant(root, 40000000000000000ll, Tmp(GPRInfo::regT3));
- loadConstant(root, 50000000000000000ll, Tmp(GPRInfo::regT4));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width64),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width64));
-
- int64_t things[5];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int64_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 10000000000000000ll);
- CHECK(things[1] == 20000000000000000ll);
- CHECK(things[2] == 30000000000000000ll);
- CHECK(things[3] == 30000000000000000ll);
- CHECK(things[4] == 40000000000000000ll);
-}
-
-void testShuffleSwapMixedWidth()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 10000000000000000ll, Tmp(GPRInfo::regT0));
- loadConstant(root, 20000000000000000ll, Tmp(GPRInfo::regT1));
- loadConstant(root, 30000000000000000ll, Tmp(GPRInfo::regT2));
- loadConstant(root, 40000000000000000ll, Tmp(GPRInfo::regT3));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width32),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT2), Arg::widthArg(Arg::Width64));
-
- int64_t things[4];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int64_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 10000000000000000ll);
- CHECK(things[1] == 20000000000000000ll);
- CHECK(things[2] == 40000000000000000ll);
- CHECK(things[3] == static_cast<uint32_t>(30000000000000000ll));
-}
-
-void testShuffleShiftMixedWidth()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 10000000000000000ll, Tmp(GPRInfo::regT0));
- loadConstant(root, 20000000000000000ll, Tmp(GPRInfo::regT1));
- loadConstant(root, 30000000000000000ll, Tmp(GPRInfo::regT2));
- loadConstant(root, 40000000000000000ll, Tmp(GPRInfo::regT3));
- loadConstant(root, 50000000000000000ll, Tmp(GPRInfo::regT4));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT2), Tmp(GPRInfo::regT3), Arg::widthArg(Arg::Width64),
- Tmp(GPRInfo::regT3), Tmp(GPRInfo::regT4), Arg::widthArg(Arg::Width32));
-
- int64_t things[5];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT3), Arg::addr(base, 3 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT4), Arg::addr(base, 4 * sizeof(int64_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 10000000000000000ll);
- CHECK(things[1] == 20000000000000000ll);
- CHECK(things[2] == 30000000000000000ll);
- CHECK(things[3] == 30000000000000000ll);
- CHECK(things[4] == static_cast<uint32_t>(40000000000000000ll));
-}
-
-void testShuffleShiftMemory()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int32_t memory[2];
- memory[0] = 35;
- memory[1] = 36;
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT2));
- root->append(
- Shuffle, nullptr,
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
- Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int32_t)),
- Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int32_t)), Arg::widthArg(Arg::Width32));
-
- int32_t things[2];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 1);
- CHECK(memory[0] == 35);
- CHECK(memory[1] == 35);
-}
-
-void testShuffleShiftMemoryLong()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int32_t memory[2];
- memory[0] = 35;
- memory[1] = 36;
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- loadConstant(root, 3, Tmp(GPRInfo::regT2));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT3));
- root->append(
- Shuffle, nullptr,
-
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
-
- Tmp(GPRInfo::regT1), Arg::addr(Tmp(GPRInfo::regT3), 0 * sizeof(int32_t)),
- Arg::widthArg(Arg::Width32),
-
- Arg::addr(Tmp(GPRInfo::regT3), 0 * sizeof(int32_t)),
- Arg::addr(Tmp(GPRInfo::regT3), 1 * sizeof(int32_t)), Arg::widthArg(Arg::Width32),
-
- Arg::addr(Tmp(GPRInfo::regT3), 1 * sizeof(int32_t)), Tmp(GPRInfo::regT2),
- Arg::widthArg(Arg::Width32));
-
- int32_t things[3];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT2), Arg::addr(base, 2 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 1);
- CHECK(things[2] == 36);
- CHECK(memory[0] == 2);
- CHECK(memory[1] == 35);
-}
-
-void testShuffleShiftMemoryAllRegs()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int32_t memory[2];
- memory[0] = 35;
- memory[1] = 36;
-
- Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
- regs.removeFirst(Reg(GPRInfo::regT0));
-
- BasicBlock* root = code.addBlock();
- for (unsigned i = 0; i < regs.size(); ++i)
- loadConstant(root, i + 1, Tmp(regs[i]));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
- Inst& shuffle = root->append(
- Shuffle, nullptr,
-
- Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int32_t)),
- Arg::widthArg(Arg::Width32),
-
- Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int32_t)),
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int32_t)), Arg::widthArg(Arg::Width32),
-
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int32_t)), Tmp(regs[1]),
- Arg::widthArg(Arg::Width32));
-
- for (unsigned i = 2; i < regs.size(); ++i)
- shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Arg::Width32));
-
- Vector<int32_t> things(regs.size(), 666);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
- for (unsigned i = 0; i < regs.size(); ++i) {
- root->append(
- Move32, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int32_t)));
- }
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 36);
- for (unsigned i = 2; i < regs.size(); ++i)
- CHECK(things[i] == static_cast<int32_t>(i));
- CHECK(memory[0] == 1);
- CHECK(memory[1] == 35);
-}
-
-void testShuffleShiftMemoryAllRegs64()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int64_t memory[2];
- memory[0] = 35000000000000ll;
- memory[1] = 36000000000000ll;
-
- Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
- regs.removeFirst(Reg(GPRInfo::regT0));
-
- BasicBlock* root = code.addBlock();
- for (unsigned i = 0; i < regs.size(); ++i)
- loadConstant(root, (i + 1) * 1000000000000ll, Tmp(regs[i]));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
- Inst& shuffle = root->append(
- Shuffle, nullptr,
-
- Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
- Arg::widthArg(Arg::Width64),
-
- Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Arg::widthArg(Arg::Width64),
-
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Tmp(regs[1]),
- Arg::widthArg(Arg::Width64));
-
- for (unsigned i = 2; i < regs.size(); ++i)
- shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Arg::Width64));
-
- Vector<int64_t> things(regs.size(), 666);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
- for (unsigned i = 0; i < regs.size(); ++i) {
- root->append(
- Move, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int64_t)));
- }
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1000000000000ll);
- CHECK(things[1] == 36000000000000ll);
- for (unsigned i = 2; i < regs.size(); ++i)
- CHECK(things[i] == static_cast<int64_t>(i) * 1000000000000ll);
- CHECK(memory[0] == 1000000000000ll);
- CHECK(memory[1] == 35000000000000ll);
-}
-
-int64_t combineHiLo(int64_t high, int64_t low)
-{
- union {
- int64_t value;
- int32_t halves[2];
- } u;
- u.value = high;
- u.halves[0] = static_cast<int32_t>(low);
- return u.value;
-}
-
-void testShuffleShiftMemoryAllRegsMixedWidth()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int64_t memory[2];
- memory[0] = 35000000000000ll;
- memory[1] = 36000000000000ll;
-
- Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
- regs.removeFirst(Reg(GPRInfo::regT0));
-
- BasicBlock* root = code.addBlock();
- for (unsigned i = 0; i < regs.size(); ++i)
- loadConstant(root, (i + 1) * 1000000000000ll, Tmp(regs[i]));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
- Inst& shuffle = root->append(
- Shuffle, nullptr,
-
- Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
- Arg::widthArg(Arg::Width32),
-
- Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Arg::widthArg(Arg::Width64),
-
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Tmp(regs[1]),
- Arg::widthArg(Arg::Width32));
-
- for (unsigned i = 2; i < regs.size(); ++i) {
- shuffle.append(
- Tmp(regs[i - 1]), Tmp(regs[i]),
- (i & 1) ? Arg::widthArg(Arg::Width32) : Arg::widthArg(Arg::Width64));
- }
-
- Vector<int64_t> things(regs.size(), 666);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
- for (unsigned i = 0; i < regs.size(); ++i) {
- root->append(
- Move, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int64_t)));
- }
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1000000000000ll);
- CHECK(things[1] == static_cast<uint32_t>(36000000000000ll));
- for (unsigned i = 2; i < regs.size(); ++i) {
- int64_t value = static_cast<int64_t>(i) * 1000000000000ll;
- CHECK(things[i] == ((i & 1) ? static_cast<uint32_t>(value) : value));
- }
- CHECK(memory[0] == combineHiLo(35000000000000ll, 1000000000000ll));
- CHECK(memory[1] == 35000000000000ll);
-}
-
-void testShuffleRotateMemory()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int32_t memory[2];
- memory[0] = 35;
- memory[1] = 36;
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1, Tmp(GPRInfo::regT0));
- loadConstant(root, 2, Tmp(GPRInfo::regT1));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT2));
- root->append(
- Shuffle, nullptr,
-
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
-
- Tmp(GPRInfo::regT1), Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int32_t)),
- Arg::widthArg(Arg::Width32),
-
- Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int32_t)),
- Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int32_t)), Arg::widthArg(Arg::Width32),
-
- Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int32_t)), Tmp(GPRInfo::regT0),
- Arg::widthArg(Arg::Width32));
-
- int32_t things[2];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move32, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int32_t)));
- root->append(Move32, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int32_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 36);
- CHECK(things[1] == 1);
- CHECK(memory[0] == 2);
- CHECK(memory[1] == 35);
-}
-
-void testShuffleRotateMemory64()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int64_t memory[2];
- memory[0] = 35000000000000ll;
- memory[1] = 36000000000000ll;
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1000000000000ll, Tmp(GPRInfo::regT0));
- loadConstant(root, 2000000000000ll, Tmp(GPRInfo::regT1));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT2));
- root->append(
- Shuffle, nullptr,
-
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width64),
-
- Tmp(GPRInfo::regT1), Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int64_t)),
- Arg::widthArg(Arg::Width64),
-
- Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int64_t)),
- Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int64_t)), Arg::widthArg(Arg::Width64),
-
- Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int64_t)), Tmp(GPRInfo::regT0),
- Arg::widthArg(Arg::Width64));
-
- int64_t things[2];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 36000000000000ll);
- CHECK(things[1] == 1000000000000ll);
- CHECK(memory[0] == 2000000000000ll);
- CHECK(memory[1] == 35000000000000ll);
-}
-
-void testShuffleRotateMemoryMixedWidth()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int64_t memory[2];
- memory[0] = 35000000000000ll;
- memory[1] = 36000000000000ll;
-
- BasicBlock* root = code.addBlock();
- loadConstant(root, 1000000000000ll, Tmp(GPRInfo::regT0));
- loadConstant(root, 2000000000000ll, Tmp(GPRInfo::regT1));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT2));
- root->append(
- Shuffle, nullptr,
-
- Tmp(GPRInfo::regT0), Tmp(GPRInfo::regT1), Arg::widthArg(Arg::Width32),
-
- Tmp(GPRInfo::regT1), Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int64_t)),
- Arg::widthArg(Arg::Width64),
-
- Arg::addr(Tmp(GPRInfo::regT2), 0 * sizeof(int64_t)),
- Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int64_t)), Arg::widthArg(Arg::Width32),
-
- Arg::addr(Tmp(GPRInfo::regT2), 1 * sizeof(int64_t)), Tmp(GPRInfo::regT0),
- Arg::widthArg(Arg::Width64));
-
- int64_t things[2];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(Move, nullptr, Tmp(GPRInfo::regT0), Arg::addr(base, 0 * sizeof(int64_t)));
- root->append(Move, nullptr, Tmp(GPRInfo::regT1), Arg::addr(base, 1 * sizeof(int64_t)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 36000000000000ll);
- CHECK(things[1] == static_cast<uint32_t>(1000000000000ll));
- CHECK(memory[0] == 2000000000000ll);
- CHECK(memory[1] == combineHiLo(36000000000000ll, 35000000000000ll));
-}
-
-void testShuffleRotateMemoryAllRegs64()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int64_t memory[2];
- memory[0] = 35000000000000ll;
- memory[1] = 36000000000000ll;
-
- Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
- regs.removeFirst(Reg(GPRInfo::regT0));
-
- BasicBlock* root = code.addBlock();
- for (unsigned i = 0; i < regs.size(); ++i)
- loadConstant(root, (i + 1) * 1000000000000ll, Tmp(regs[i]));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
- Inst& shuffle = root->append(
- Shuffle, nullptr,
-
- Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
- Arg::widthArg(Arg::Width64),
-
- Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Arg::widthArg(Arg::Width64),
-
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Tmp(regs[1]),
- Arg::widthArg(Arg::Width64),
-
- regs.last(), regs[0], Arg::widthArg(Arg::Width64));
-
- for (unsigned i = 2; i < regs.size(); ++i)
- shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Arg::Width64));
-
- Vector<int64_t> things(regs.size(), 666);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
- for (unsigned i = 0; i < regs.size(); ++i) {
- root->append(
- Move, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int64_t)));
- }
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == static_cast<int64_t>(regs.size()) * 1000000000000ll);
- CHECK(things[1] == 36000000000000ll);
- for (unsigned i = 2; i < regs.size(); ++i)
- CHECK(things[i] == static_cast<int64_t>(i) * 1000000000000ll);
- CHECK(memory[0] == 1000000000000ll);
- CHECK(memory[1] == 35000000000000ll);
-}
-
-void testShuffleRotateMemoryAllRegsMixedWidth()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- int64_t memory[2];
- memory[0] = 35000000000000ll;
- memory[1] = 36000000000000ll;
-
- Vector<Reg> regs = regsInPriorityOrder(Arg::GP);
- regs.removeFirst(Reg(GPRInfo::regT0));
-
- BasicBlock* root = code.addBlock();
- for (unsigned i = 0; i < regs.size(); ++i)
- loadConstant(root, (i + 1) * 1000000000000ll, Tmp(regs[i]));
- root->append(Move, nullptr, Arg::immPtr(&memory), Tmp(GPRInfo::regT0));
- Inst& shuffle = root->append(
- Shuffle, nullptr,
-
- Tmp(regs[0]), Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
- Arg::widthArg(Arg::Width32),
-
- Arg::addr(Tmp(GPRInfo::regT0), 0 * sizeof(int64_t)),
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Arg::widthArg(Arg::Width64),
-
- Arg::addr(Tmp(GPRInfo::regT0), 1 * sizeof(int64_t)), Tmp(regs[1]),
- Arg::widthArg(Arg::Width32),
-
- regs.last(), regs[0], Arg::widthArg(Arg::Width32));
-
- for (unsigned i = 2; i < regs.size(); ++i)
- shuffle.append(Tmp(regs[i - 1]), Tmp(regs[i]), Arg::widthArg(Arg::Width64));
-
- Vector<int64_t> things(regs.size(), 666);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things[0])), Tmp(GPRInfo::regT0));
- for (unsigned i = 0; i < regs.size(); ++i) {
- root->append(
- Move, nullptr, Tmp(regs[i]), Arg::addr(Tmp(GPRInfo::regT0), i * sizeof(int64_t)));
- }
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == static_cast<uint32_t>(static_cast<int64_t>(regs.size()) * 1000000000000ll));
- CHECK(things[1] == static_cast<uint32_t>(36000000000000ll));
- for (unsigned i = 2; i < regs.size(); ++i)
- CHECK(things[i] == static_cast<int64_t>(i) * 1000000000000ll);
- CHECK(memory[0] == combineHiLo(35000000000000ll, 1000000000000ll));
- CHECK(memory[1] == 35000000000000ll);
-}
-
-void testShuffleSwapDouble()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadDoubleConstant(root, 1, Tmp(FPRInfo::fpRegT0), Tmp(GPRInfo::regT0));
- loadDoubleConstant(root, 2, Tmp(FPRInfo::fpRegT1), Tmp(GPRInfo::regT0));
- loadDoubleConstant(root, 3, Tmp(FPRInfo::fpRegT2), Tmp(GPRInfo::regT0));
- loadDoubleConstant(root, 4, Tmp(FPRInfo::fpRegT3), Tmp(GPRInfo::regT0));
- root->append(
- Shuffle, nullptr,
- Tmp(FPRInfo::fpRegT2), Tmp(FPRInfo::fpRegT3), Arg::widthArg(Arg::Width64),
- Tmp(FPRInfo::fpRegT3), Tmp(FPRInfo::fpRegT2), Arg::widthArg(Arg::Width64));
-
- double things[4];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT0), Arg::addr(base, 0 * sizeof(double)));
- root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT1), Arg::addr(base, 1 * sizeof(double)));
- root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT2), Arg::addr(base, 2 * sizeof(double)));
- root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT3), Arg::addr(base, 3 * sizeof(double)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 2);
- CHECK(things[2] == 4);
- CHECK(things[3] == 3);
-}
-
-void testShuffleShiftDouble()
-{
- B3::Procedure proc;
- Code& code = proc.code();
-
- BasicBlock* root = code.addBlock();
- loadDoubleConstant(root, 1, Tmp(FPRInfo::fpRegT0), Tmp(GPRInfo::regT0));
- loadDoubleConstant(root, 2, Tmp(FPRInfo::fpRegT1), Tmp(GPRInfo::regT0));
- loadDoubleConstant(root, 3, Tmp(FPRInfo::fpRegT2), Tmp(GPRInfo::regT0));
- loadDoubleConstant(root, 4, Tmp(FPRInfo::fpRegT3), Tmp(GPRInfo::regT0));
- root->append(
- Shuffle, nullptr,
- Tmp(FPRInfo::fpRegT2), Tmp(FPRInfo::fpRegT3), Arg::widthArg(Arg::Width64));
-
- double things[4];
- Tmp base = code.newTmp(Arg::GP);
- root->append(Move, nullptr, Arg::bigImm(bitwise_cast<intptr_t>(&things)), base);
- root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT0), Arg::addr(base, 0 * sizeof(double)));
- root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT1), Arg::addr(base, 1 * sizeof(double)));
- root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT2), Arg::addr(base, 2 * sizeof(double)));
- root->append(MoveDouble, nullptr, Tmp(FPRInfo::fpRegT3), Arg::addr(base, 3 * sizeof(double)));
- root->append(Move, nullptr, Arg::imm(0), Tmp(GPRInfo::returnValueGPR));
- root->append(Ret32, nullptr, Tmp(GPRInfo::returnValueGPR));
-
- memset(things, 0, sizeof(things));
-
- CHECK(!compileAndRun<int>(proc));
-
- CHECK(things[0] == 1);
- CHECK(things[1] == 2);
- CHECK(things[2] == 3);
- CHECK(things[3] == 3);
-}
-
-#define RUN(test) do { \
- if (!shouldRun(#test)) \
- break; \
- tasks.append( \
- createSharedTask<void()>( \
- [&] () { \
- dataLog(#test "...\n"); \
- test; \
- dataLog(#test ": OK!\n"); \
- })); \
- } while (false);
-
-void run(const char* filter)
-{
- JSC::initializeThreading();
- vm = &VM::create(LargeHeap).leakRef();
-
- Deque<RefPtr<SharedTask<void()>>> tasks;
-
- auto shouldRun = [&] (const char* testName) -> bool {
- return !filter || !!strcasestr(testName, filter);
- };
-
- RUN(testSimple());
-
- RUN(testShuffleSimpleSwap());
- RUN(testShuffleSimpleShift());
- RUN(testShuffleLongShift());
- RUN(testShuffleLongShiftBackwards());
- RUN(testShuffleSimpleRotate());
- RUN(testShuffleSimpleBroadcast());
- RUN(testShuffleBroadcastAllRegs());
- RUN(testShuffleTreeShift());
- RUN(testShuffleTreeShiftBackward());
- RUN(testShuffleTreeShiftOtherBackward());
- RUN(testShuffleMultipleShifts());
- RUN(testShuffleRotateWithFringe());
- RUN(testShuffleRotateWithFringeInWeirdOrder());
- RUN(testShuffleRotateWithLongFringe());
- RUN(testShuffleMultipleRotates());
- RUN(testShuffleShiftAndRotate());
- RUN(testShuffleShiftAllRegs());
- RUN(testShuffleRotateAllRegs());
- RUN(testShuffleSimpleSwap64());
- RUN(testShuffleSimpleShift64());
- RUN(testShuffleSwapMixedWidth());
- RUN(testShuffleShiftMixedWidth());
- RUN(testShuffleShiftMemory());
- RUN(testShuffleShiftMemoryLong());
- RUN(testShuffleShiftMemoryAllRegs());
- RUN(testShuffleShiftMemoryAllRegs64());
- RUN(testShuffleShiftMemoryAllRegsMixedWidth());
- RUN(testShuffleRotateMemory());
- RUN(testShuffleRotateMemory64());
- RUN(testShuffleRotateMemoryMixedWidth());
- RUN(testShuffleRotateMemoryAllRegs64());
- RUN(testShuffleRotateMemoryAllRegsMixedWidth());
- RUN(testShuffleSwapDouble());
- RUN(testShuffleShiftDouble());
-
- if (tasks.isEmpty())
- usage();
-
- Lock lock;
-
- Vector<ThreadIdentifier> threads;
- for (unsigned i = filter ? 1 : WTF::numberOfProcessorCores(); i--;) {
- threads.append(
- createThread(
- "testb3 thread",
- [&] () {
- for (;;) {
- RefPtr<SharedTask<void()>> task;
- {
- LockHolder locker(lock);
- if (tasks.isEmpty())
- return;
- task = tasks.takeFirst();
- }
-
- task->run();
- }
- }));
- }
-
- for (ThreadIdentifier thread : threads)
- waitForThreadCompletion(thread);
- crashLock.lock();
-}
-
-} // anonymois namespace
-
-#else // ENABLE(B3_JIT)
-
-static void run(const char*)
-{
- dataLog("B3 JIT is not enabled.\n");
-}
-
-#endif // ENABLE(B3_JIT)
-
-int main(int argc, char** argv)
-{
- const char* filter = nullptr;
- switch (argc) {
- case 1:
- break;
- case 2:
- filter = argv[1];
- break;
- default:
- usage();
- break;
- }
-
- run(filter);
- return 0;
-}