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