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