| /* |
| * 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 "CCallHelpers.h" |
| |
| namespace JSC { |
| |
| class CCallHelpers; |
| class RegisterSet; |
| |
| 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. |
| RegisterSet extraClobberedRegs(); |
| RegisterSet 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&); |
| |
| // 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 RegisterSet&); |
| |
| // 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. |
| CCallHelpers::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) |