blob: 504050d2b18bce87c0e4108287f3b2ebcd6eb16c [file] [log] [blame]
/*
* 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.
*/
#pragma once
#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();
JS_EXPORT_PRIVATE 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 bool admitsExtendedOffsetAddr(Inst&, unsigned argIndex) = 0;
virtual std::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 RegisterSet extraEarlyClobberedRegs(Inst&) = 0;
virtual RegisterSet extraClobberedRegs(Inst&) = 0;
// By default, this returns false.
virtual bool isTerminal(Inst&);
// By default, this returns true.
virtual bool hasNonArgEffects(Inst&);
// By default, this returns true.
virtual bool hasNonArgNonControlEffects(Inst&);
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)