Home | History | Annotate | Download | only in GlobalISel
      1 //==-- llvm/CodeGen/GlobalISel/LegalizerInfo.h -------------------*- C++ -*-==//
      2 //
      3 //                     The LLVM Compiler Infrastructure
      4 //
      5 // This file is distributed under the University of Illinois Open Source
      6 // License. See LICENSE.TXT for details.
      7 //
      8 //===----------------------------------------------------------------------===//
      9 //
     10 /// Interface for Targets to specify which operations they can successfully
     11 /// select and how the others should be expanded most efficiently.
     12 //
     13 //===----------------------------------------------------------------------===//
     14 
     15 #ifndef LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZER_H
     16 #define LLVM_CODEGEN_GLOBALISEL_MACHINELEGALIZER_H
     17 
     18 #include "llvm/ADT/DenseMap.h"
     19 #include "llvm/CodeGen/LowLevelType.h"
     20 #include "llvm/Target/TargetOpcodes.h"
     21 
     22 #include <cstdint>
     23 #include <functional>
     24 
     25 namespace llvm {
     26 class LLVMContext;
     27 class MachineInstr;
     28 class MachineIRBuilder;
     29 class MachineRegisterInfo;
     30 class Type;
     31 class VectorType;
     32 
     33 /// Legalization is decided based on an instruction's opcode, which type slot
     34 /// we're considering, and what the existing type is. These aspects are gathered
     35 /// together for convenience in the InstrAspect class.
     36 struct InstrAspect {
     37   unsigned Opcode;
     38   unsigned Idx;
     39   LLT Type;
     40 
     41   InstrAspect(unsigned Opcode, LLT Type) : Opcode(Opcode), Idx(0), Type(Type) {}
     42   InstrAspect(unsigned Opcode, unsigned Idx, LLT Type)
     43       : Opcode(Opcode), Idx(Idx), Type(Type) {}
     44 
     45   bool operator==(const InstrAspect &RHS) const {
     46     return Opcode == RHS.Opcode && Idx == RHS.Idx && Type == RHS.Type;
     47   }
     48 };
     49 
     50 class LegalizerInfo {
     51 public:
     52   enum LegalizeAction : std::uint8_t {
     53     /// The operation is expected to be selectable directly by the target, and
     54     /// no transformation is necessary.
     55     Legal,
     56 
     57     /// The operation should be synthesized from multiple instructions acting on
     58     /// a narrower scalar base-type. For example a 64-bit add might be
     59     /// implemented in terms of 32-bit add-with-carry.
     60     NarrowScalar,
     61 
     62     /// The operation should be implemented in terms of a wider scalar
     63     /// base-type. For example a <2 x s8> add could be implemented as a <2
     64     /// x s32> add (ignoring the high bits).
     65     WidenScalar,
     66 
     67     /// The (vector) operation should be implemented by splitting it into
     68     /// sub-vectors where the operation is legal. For example a <8 x s64> add
     69     /// might be implemented as 4 separate <2 x s64> adds.
     70     FewerElements,
     71 
     72     /// The (vector) operation should be implemented by widening the input
     73     /// vector and ignoring the lanes added by doing so. For example <2 x i8> is
     74     /// rarely legal, but you might perform an <8 x i8> and then only look at
     75     /// the first two results.
     76     MoreElements,
     77 
     78     /// The operation itself must be expressed in terms of simpler actions on
     79     /// this target. E.g. a SREM replaced by an SDIV and subtraction.
     80     Lower,
     81 
     82     /// The operation should be implemented as a call to some kind of runtime
     83     /// support library. For example this usually happens on machines that don't
     84     /// support floating-point operations natively.
     85     Libcall,
     86 
     87     /// The target wants to do something special with this combination of
     88     /// operand and type. A callback will be issued when it is needed.
     89     Custom,
     90 
     91     /// This operation is completely unsupported on the target. A programming
     92     /// error has occurred.
     93     Unsupported,
     94 
     95     /// Sentinel value for when no action was found in the specified table.
     96     NotFound,
     97   };
     98 
     99   LegalizerInfo();
    100   virtual ~LegalizerInfo() = default;
    101 
    102   /// Compute any ancillary tables needed to quickly decide how an operation
    103   /// should be handled. This must be called after all "set*Action"methods but
    104   /// before any query is made or incorrect results may be returned.
    105   void computeTables();
    106 
    107   /// More friendly way to set an action for common types that have an LLT
    108   /// representation.
    109   void setAction(const InstrAspect &Aspect, LegalizeAction Action) {
    110     TablesInitialized = false;
    111     unsigned Opcode = Aspect.Opcode - FirstOp;
    112     if (Actions[Opcode].size() <= Aspect.Idx)
    113       Actions[Opcode].resize(Aspect.Idx + 1);
    114     Actions[Aspect.Opcode - FirstOp][Aspect.Idx][Aspect.Type] = Action;
    115   }
    116 
    117   /// If an operation on a given vector type (say <M x iN>) isn't explicitly
    118   /// specified, we proceed in 2 stages. First we legalize the underlying scalar
    119   /// (so that there's at least one legal vector with that scalar), then we
    120   /// adjust the number of elements in the vector so that it is legal. The
    121   /// desired action in the first step is controlled by this function.
    122   void setScalarInVectorAction(unsigned Opcode, LLT ScalarTy,
    123                                LegalizeAction Action) {
    124     assert(!ScalarTy.isVector());
    125     ScalarInVectorActions[std::make_pair(Opcode, ScalarTy)] = Action;
    126   }
    127 
    128 
    129   /// Determine what action should be taken to legalize the given generic
    130   /// instruction opcode, type-index and type. Requires computeTables to have
    131   /// been called.
    132   ///
    133   /// \returns a pair consisting of the kind of legalization that should be
    134   /// performed and the destination type.
    135   std::pair<LegalizeAction, LLT> getAction(const InstrAspect &Aspect) const;
    136 
    137   /// Determine what action should be taken to legalize the given generic
    138   /// instruction.
    139   ///
    140   /// \returns a tuple consisting of the LegalizeAction that should be
    141   /// performed, the type-index it should be performed on and the destination
    142   /// type.
    143   std::tuple<LegalizeAction, unsigned, LLT>
    144   getAction(const MachineInstr &MI, const MachineRegisterInfo &MRI) const;
    145 
    146   /// Iterate the given function (typically something like doubling the width)
    147   /// on Ty until we find a legal type for this operation.
    148   LLT findLegalType(const InstrAspect &Aspect,
    149                     function_ref<LLT(LLT)> NextType) const {
    150     LegalizeAction Action;
    151     const TypeMap &Map = Actions[Aspect.Opcode - FirstOp][Aspect.Idx];
    152     LLT Ty = Aspect.Type;
    153     do {
    154       Ty = NextType(Ty);
    155       auto ActionIt = Map.find(Ty);
    156       if (ActionIt == Map.end())
    157         Action = DefaultActions.find(Aspect.Opcode)->second;
    158       else
    159         Action = ActionIt->second;
    160     } while(Action != Legal);
    161     return Ty;
    162   }
    163 
    164   /// Find what type it's actually OK to perform the given operation on, given
    165   /// the general approach we've decided to take.
    166   LLT findLegalType(const InstrAspect &Aspect, LegalizeAction Action) const;
    167 
    168   std::pair<LegalizeAction, LLT> findLegalAction(const InstrAspect &Aspect,
    169                                                  LegalizeAction Action) const {
    170     return std::make_pair(Action, findLegalType(Aspect, Action));
    171   }
    172 
    173   /// Find the specified \p Aspect in the primary (explicitly set) Actions
    174   /// table. Returns either the action the target requested or NotFound if there
    175   /// was no setAction call.
    176   LegalizeAction findInActions(const InstrAspect &Aspect) const {
    177     if (Aspect.Opcode < FirstOp || Aspect.Opcode > LastOp)
    178       return NotFound;
    179     if (Aspect.Idx >= Actions[Aspect.Opcode - FirstOp].size())
    180       return NotFound;
    181     const TypeMap &Map = Actions[Aspect.Opcode - FirstOp][Aspect.Idx];
    182     auto ActionIt =  Map.find(Aspect.Type);
    183     if (ActionIt == Map.end())
    184       return NotFound;
    185 
    186     return ActionIt->second;
    187   }
    188 
    189   bool isLegal(const MachineInstr &MI, const MachineRegisterInfo &MRI) const;
    190 
    191   virtual bool legalizeCustom(MachineInstr &MI,
    192                               MachineRegisterInfo &MRI,
    193                               MachineIRBuilder &MIRBuilder) const;
    194 
    195 private:
    196   static const int FirstOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_START;
    197   static const int LastOp = TargetOpcode::PRE_ISEL_GENERIC_OPCODE_END;
    198 
    199   typedef DenseMap<LLT, LegalizeAction> TypeMap;
    200   typedef DenseMap<std::pair<unsigned, LLT>, LegalizeAction> SIVActionMap;
    201 
    202   SmallVector<TypeMap, 1> Actions[LastOp - FirstOp + 1];
    203   SIVActionMap ScalarInVectorActions;
    204   DenseMap<std::pair<unsigned, LLT>, uint16_t> MaxLegalVectorElts;
    205   DenseMap<unsigned, LegalizeAction> DefaultActions;
    206 
    207   bool TablesInitialized;
    208 };
    209 
    210 
    211 } // End namespace llvm.
    212 
    213 #endif
    214