blob: 18531c7b9e9869a3c5f4d3f81836887acc90960c [file] [log] [blame]
/*
* 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)