#pragma once
#if ENABLE(B3_JIT)
#include "AirCode.h"
#include "AirGenerationContext.h"
#include "AirInst.h"
#include "AirSpecial.h"
#include "B3ValueInlines.h"
#include "B3WasmBoundsCheckValue.h"
namespace JSC { namespace B3 { namespace Air {
struct PatchCustom {
static void forEachArg(Inst& inst, ScopedLambda<Inst::EachArgCallback> lambda)
{
lambda(inst.args[0], Arg::Use, GP, pointerWidth());
inst.args[0].special()->forEachArg(inst, lambda);
}
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 bool admitsExtendedOffsetAddr(Inst& inst, unsigned argIndex)
{
if (!argIndex)
return false;
return inst.args[0].special()->admitsExtendedOffsetAddr(inst, argIndex);
}
static Optional<unsigned> shouldTryAliasingDef(Inst& inst)
{
return inst.args[0].special()->shouldTryAliasingDef(inst);
}
static bool isTerminal(Inst& inst)
{
return inst.args[0].special()->isTerminal(inst);
}
static bool hasNonArgEffects(Inst& inst)
{
return inst.args[0].special()->hasNonArgEffects(inst);
}
static bool hasNonArgNonControlEffects(Inst& inst)
{
return inst.args[0].special()->hasNonArgNonControlEffects(inst);
}
static CCallHelpers::Jump generate(
Inst& inst, CCallHelpers& jit, GenerationContext& context)
{
return inst.args[0].special()->generate(inst, jit, context);
}
};
template<typename Subtype>
struct CommonCustomBase {
static bool hasNonArgEffects(Inst& inst)
{
return Subtype::isTerminal(inst) || Subtype::hasNonArgNonControlEffects(inst);
}
};
struct CCallCustom : public CommonCustomBase<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, GP, pointerWidth());
if (value->type() != Void) {
functor(
inst.args[index++], Arg::Def,
bankForType(value->type()),
widthForType(value->type()));
}
for (unsigned i = 1; i < value->numChildren(); ++i) {
Value* child = value->child(i);
functor(
inst.args[index++], Arg::Use,
bankForType(child->type()),
widthForType(child->type()));
}
}
template<typename... Arguments>
static bool isValidFormStatic(Arguments...)
{
return false;
}
static bool isValidForm(Inst&);
static bool admitsStack(Inst&, unsigned)
{
return true;
}
static bool admitsExtendedOffsetAddr(Inst&, unsigned)
{
return false;
}
static bool isTerminal(Inst&)
{
return false;
}
static bool hasNonArgNonControlEffects(Inst&)
{
return true;
}
static CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&);
};
struct ColdCCallCustom : CCallCustom {
template<typename Functor>
static void forEachArg(Inst& inst, const Functor& functor)
{
CCallCustom::forEachArg(
inst,
[&] (Arg& arg, Arg::Role role, Bank bank, Width width) {
functor(arg, Arg::cooled(role), bank, width);
});
}
};
struct ShuffleCustom : public CommonCustomBase<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];
Width width = widthArg.width();
Bank bank = src.isGP() && dst.isGP() ? GP : FP;
functor(src, Arg::Use, bank, width);
functor(dst, Arg::Def, bank, width);
functor(widthArg, Arg::Use, GP, 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 admitsExtendedOffsetAddr(Inst&, unsigned)
{
return false;
}
static bool isTerminal(Inst&)
{
return false;
}
static bool hasNonArgNonControlEffects(Inst&)
{
return false;
}
static CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&);
};
struct EntrySwitchCustom : public CommonCustomBase<EntrySwitchCustom> {
template<typename Func>
static void forEachArg(Inst&, const Func&)
{
}
template<typename... Arguments>
static bool isValidFormStatic(Arguments...)
{
return !sizeof...(Arguments);
}
static bool isValidForm(Inst& inst)
{
return inst.args.isEmpty();
}
static bool admitsStack(Inst&, unsigned)
{
return false;
}
static bool admitsExtendedOffsetAddr(Inst&, unsigned)
{
return false;
}
static bool isTerminal(Inst&)
{
return true;
}
static bool hasNonArgNonControlEffects(Inst&)
{
return false;
}
static CCallHelpers::Jump generate(Inst&, CCallHelpers&, GenerationContext&)
{
UNREACHABLE_FOR_PLATFORM();
return CCallHelpers::Jump();
}
};
struct WasmBoundsCheckCustom : public CommonCustomBase<WasmBoundsCheckCustom> {
template<typename Func>
static void forEachArg(Inst& inst, const Func& functor)
{
functor(inst.args[0], Arg::Use, GP, Width64);
functor(inst.args[1], Arg::Use, GP, Width64);
}
template<typename... Arguments>
static bool isValidFormStatic(Arguments...)
{
return false;
}
static bool isValidForm(Inst&);
static bool admitsStack(Inst&, unsigned)
{
return false;
}
static bool admitsExtendedOffsetAddr(Inst&, unsigned)
{
return false;
}
static bool isTerminal(Inst&)
{
return false;
}
static bool hasNonArgNonControlEffects(Inst&)
{
return true;
}
static CCallHelpers::Jump generate(Inst& inst, CCallHelpers& jit, GenerationContext& context)
{
WasmBoundsCheckValue* value = inst.origin->as<WasmBoundsCheckValue>();
CCallHelpers::Jump outOfBounds = Inst(Air::Branch64, value, Arg::relCond(CCallHelpers::AboveOrEqual), inst.args[0], inst.args[1]).generate(jit, context);
context.latePaths.append(createSharedTask<GenerationContext::LatePathFunction>(
[outOfBounds, value] (CCallHelpers& jit, Air::GenerationContext& context) {
outOfBounds.link(&jit);
switch (value->boundsType()) {
case WasmBoundsCheckValue::Type::Pinned:
context.code->wasmBoundsCheckGenerator()->run(jit, value->bounds().pinnedSize);
break;
case WasmBoundsCheckValue::Type::Maximum:
context.code->wasmBoundsCheckGenerator()->run(jit, InvalidGPRReg);
break;
}
}));
return CCallHelpers::Jump();
}
};
} } }
#endif // ENABLE(B3_JIT)