| /* |
| * Copyright (C) 2015-2017 Apple Inc. All rights reserved. |
| * |
| * Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
| * are met: |
| * 1. Redistributions of source code must retain the above copyright |
| * notice, this list of conditions and the following disclaimer. |
| * 2. Redistributions in binary form must reproduce the above copyright |
| * notice, this list of conditions and the following disclaimer in the |
| * documentation and/or other materials provided with the distribution. |
| * |
| * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY |
| * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
| * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR |
| * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY |
| * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| */ |
| |
| #pragma once |
| |
| #if ENABLE(B3_JIT) |
| |
| #include "AirBasicBlock.h" |
| #include "AirCFG.h" |
| #include "AirCode.h" |
| #include "AirInstInlines.h" |
| #include "AirStackSlot.h" |
| #include "AirTmpInlines.h" |
| #include <wtf/IndexMap.h> |
| |
| namespace JSC { namespace B3 { namespace Air { |
| |
| template<typename Adapter> |
| struct LivenessAdapter { |
| typedef Air::CFG CFG; |
| |
| typedef Vector<unsigned, 4> ActionsList; |
| |
| struct Actions { |
| Actions() { } |
| |
| ActionsList use; |
| ActionsList def; |
| }; |
| |
| typedef Vector<Actions, 0, UnsafeVectorOverflow> ActionsForBoundary; |
| |
| LivenessAdapter(Code& code) |
| : code(code) |
| , actions(code.size()) |
| { |
| } |
| |
| Adapter& adapter() |
| { |
| return *static_cast<Adapter*>(this); |
| } |
| |
| void prepareToCompute() |
| { |
| for (BasicBlock* block : code) { |
| ActionsForBoundary& actionsForBoundary = actions[block]; |
| actionsForBoundary.resize(block->size() + 1); |
| |
| for (size_t instIndex = block->size(); instIndex--;) { |
| Inst& inst = block->at(instIndex); |
| inst.forEach<typename Adapter::Thing>( |
| [&] (typename Adapter::Thing& thing, Arg::Role role, Bank bank, Width) { |
| if (!Adapter::acceptsBank(bank) || !Adapter::acceptsRole(role)) |
| return; |
| |
| unsigned index = adapter().valueToIndex(thing); |
| |
| if (Arg::isEarlyUse(role)) |
| actionsForBoundary[instIndex].use.appendIfNotContains(index); |
| if (Arg::isEarlyDef(role)) |
| actionsForBoundary[instIndex].def.appendIfNotContains(index); |
| if (Arg::isLateUse(role)) |
| actionsForBoundary[instIndex + 1].use.appendIfNotContains(index); |
| if (Arg::isLateDef(role)) |
| actionsForBoundary[instIndex + 1].def.appendIfNotContains(index); |
| }); |
| } |
| } |
| } |
| |
| Actions& actionsAt(BasicBlock* block, unsigned instBoundaryIndex) |
| { |
| return actions[block][instBoundaryIndex]; |
| } |
| |
| unsigned blockSize(BasicBlock* block) |
| { |
| return block->size(); |
| } |
| |
| template<typename Func> |
| void forEachUse(BasicBlock* block, size_t instBoundaryIndex, const Func& func) |
| { |
| for (unsigned index : actionsAt(block, instBoundaryIndex).use) |
| func(index); |
| } |
| |
| template<typename Func> |
| void forEachDef(BasicBlock* block, size_t instBoundaryIndex, const Func& func) |
| { |
| for (unsigned index : actionsAt(block, instBoundaryIndex).def) |
| func(index); |
| } |
| |
| Code& code; |
| IndexMap<BasicBlock*, ActionsForBoundary> actions; |
| }; |
| |
| template<Bank adapterBank, Arg::Temperature minimumTemperature = Arg::Cold> |
| struct TmpLivenessAdapter : LivenessAdapter<TmpLivenessAdapter<adapterBank, minimumTemperature>> { |
| typedef LivenessAdapter<TmpLivenessAdapter<adapterBank, minimumTemperature>> Base; |
| |
| static constexpr const char* name = "TmpLiveness"; |
| typedef Tmp Thing; |
| |
| TmpLivenessAdapter(Code& code) |
| : Base(code) |
| { |
| } |
| |
| unsigned numIndices() |
| { |
| return Tmp::absoluteIndexEnd(Base::code, adapterBank); |
| } |
| static bool acceptsBank(Bank bank) { return bank == adapterBank; } |
| static bool acceptsRole(Arg::Role role) { return Arg::temperature(role) >= minimumTemperature; } |
| static unsigned valueToIndex(Tmp tmp) { return AbsoluteTmpMapper<adapterBank>::absoluteIndex(tmp); } |
| static Tmp indexToValue(unsigned index) { return AbsoluteTmpMapper<adapterBank>::tmpFromAbsoluteIndex(index); } |
| }; |
| |
| struct UnifiedTmpLivenessAdapter : LivenessAdapter<UnifiedTmpLivenessAdapter> { |
| typedef LivenessAdapter<UnifiedTmpLivenessAdapter> Base; |
| |
| static constexpr const char* name = "UnifiedTmpLiveness"; |
| |
| typedef Tmp Thing; |
| |
| UnifiedTmpLivenessAdapter(Code& code) |
| : Base(code) |
| { |
| } |
| |
| unsigned numIndices() |
| { |
| return Tmp::linearIndexEnd(code); |
| } |
| |
| static bool acceptsBank(Bank) { return true; } |
| static bool acceptsRole(Arg::Role) { return true; } |
| unsigned valueToIndex(Tmp tmp) { return tmp.linearlyIndexed(code).index(); } |
| Tmp indexToValue(unsigned index) { return Tmp::tmpForLinearIndex(code, index); } |
| }; |
| |
| struct StackSlotLivenessAdapter : LivenessAdapter<StackSlotLivenessAdapter> { |
| static constexpr const char* name = "StackSlotLiveness"; |
| typedef StackSlot* Thing; |
| |
| StackSlotLivenessAdapter(Code& code) |
| : LivenessAdapter(code) |
| { |
| } |
| |
| unsigned numIndices() |
| { |
| return code.stackSlots().size(); |
| } |
| static bool acceptsBank(Bank) { return true; } |
| static bool acceptsRole(Arg::Role) { return true; } |
| static unsigned valueToIndex(StackSlot* stackSlot) { return stackSlot->index(); } |
| StackSlot* indexToValue(unsigned index) { return code.stackSlots()[index]; } |
| }; |
| |
| } } } // namespace JSC::B3::Air |
| |
| #endif // ENABLE(B3_JIT) |
| |