/* * 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. */ #ifndef AirInst_h #define AirInst_h #if ENABLE(B3_JIT) #include "AirArg.h" #include "AirOpcode.h" #include "CCallHelpers.h" namespace JSC { class CCallHelpers; class RegisterSet; namespace B3 { class Value; namespace Air { struct GenerationContext; struct Inst { public: typedef Vector ArgList; Inst() : origin(nullptr) , opcode(Nop) { } Inst(Opcode opcode, Value* origin) : origin(origin) , opcode(opcode) { } template Inst(Opcode opcode, Value* origin, Arg arg, Arguments... arguments) : args{ arg, arguments... } , origin(origin) , opcode(opcode) { } Inst(Opcode opcode, Value* origin, const ArgList& arguments) : args(arguments) , origin(origin) , opcode(opcode) { } Inst(Opcode opcode, Value* origin, ArgList&& arguments) : args(WTFMove(arguments)) , origin(origin) , opcode(opcode) { } explicit operator bool() const { return origin || opcode != Nop || args.size(); } void append() { } template 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 void forEachTmpFast(const Functor& functor) { for (Arg& arg : args) arg.forEachTmpFast(functor); } typedef void EachArgCallback(Arg&, Arg::Role, Arg::Type, Arg::Width); // Calls the functor with (arg, role, type, width). This function is auto-generated by // opcode_generator.rb. template void forEachArg(const Functor&); // Calls the functor with (tmp, role, type, width). template void forEachTmp(const Functor& functor) { forEachArg( [&] (Arg& arg, Arg::Role role, Arg::Type type, Arg::Width width) { arg.forEachTmp(role, type, width, functor); }); } // Thing can be either Arg, Tmp, or StackSlot*. template void forEach(const Functor&); // Reports any additional registers clobbered by this operation. Note that for efficiency, // extraClobberedRegs() only works for the Patch opcode. const RegisterSet& extraClobberedRegs(); const 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 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 static void forEachDefWithExtraClobberedRegs(Inst* prevInst, Inst* nextInst, const Functor&); // 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&); // 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(); // 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. Optional 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. Opcode opcode; }; } } } // namespace JSC::B3::Air #endif // ENABLE(B3_JIT) #endif // AirInst_h