1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225
|
/*
* 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 "AirArg.h"
#include "AirKind.h"
#include "MacroAssembler.h"
#include <wtf/ScopedLambda.h>
namespace JSC {
class CCallHelpers;
class RegisterSetBuilder;
namespace B3 {
class Value;
namespace Air {
struct GenerationContext;
struct Inst {
typedef Vector<Arg, 3> ArgList;
Inst()
: origin(nullptr)
{
}
Inst(Kind kind, Value* origin)
: origin(origin)
, kind(kind)
{
}
template<typename... Arguments>
Inst(Kind kind, Value* origin, Arg arg, Arguments... arguments)
: args{ arg, arguments... }
, origin(origin)
, kind(kind)
{
}
Inst(Kind kind, Value* origin, const ArgList& arguments)
: args(arguments)
, origin(origin)
, kind(kind)
{
}
Inst(Kind kind, Value* origin, ArgList&& arguments)
: args(WTFMove(arguments))
, origin(origin)
, kind(kind)
{
}
explicit operator bool() const { return origin || kind || 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, Bank, 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, Bank bank, Width width) {
arg.forEachTmp(role, bank, 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.
RegisterSetBuilder extraClobberedRegs();
RegisterSetBuilder 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&);
template<typename Thing, typename Functor>
static void forEachUse(Inst* prevInst, Inst* nextInst, const Functor&);
// Some summaries about all arguments. These are useful for needsPadding().
bool hasEarlyDef();
bool hasLateUseOrDef();
// Check if there needs to be a padding Nop between these two instructions.
static bool needsPadding(Inst* prevInst, Inst* nextInst);
// 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 RegisterSetBuilder&);
// 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&);
bool admitsExtendedOffsetAddr(unsigned argIndex);
bool admitsExtendedOffsetAddr(Arg&);
// Defined by opcode_generator.rb.
bool isTerminal();
// 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();
// Tells you if this operation has non-control effects.
bool hasNonControlEffects() { return hasNonArgNonControlEffects() || 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.
MacroAssembler::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.
std::optional<unsigned> shouldTryAliasingDef();
// This computes a hash for comparing this to JSAir's Inst.
unsigned jsHash() const;
void dump(PrintStream&) const;
ArgList args;
Value* origin; // The B3::Value that this originated from.
Kind kind;
private:
template<typename Func>
void forEachArgSimple(const Func&);
void forEachArgCustom(ScopedLambda<EachArgCallback>);
};
} } } // namespace JSC::B3::Air
#endif // ENABLE(B3_JIT)
|