Details | Last modification | View Log | RSS feed
| Rev | Author | Line No. | Line |
|---|---|---|---|
| 14 | pmbaty | 1 | //===- llvm/InlineAsm.h - Class to represent inline asm strings -*- C++ -*-===// |
| 2 | // |
||
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
||
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
||
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
||
| 6 | // |
||
| 7 | //===----------------------------------------------------------------------===// |
||
| 8 | // |
||
| 9 | // This class represents the inline asm strings, which are Value*'s that are |
||
| 10 | // used as the callee operand of call instructions. InlineAsm's are uniqued |
||
| 11 | // like constants, and created via InlineAsm::get(...). |
||
| 12 | // |
||
| 13 | //===----------------------------------------------------------------------===// |
||
| 14 | |||
| 15 | #ifndef LLVM_IR_INLINEASM_H |
||
| 16 | #define LLVM_IR_INLINEASM_H |
||
| 17 | |||
| 18 | #include "llvm/ADT/SmallVector.h" |
||
| 19 | #include "llvm/ADT/StringRef.h" |
||
| 20 | #include "llvm/IR/Value.h" |
||
| 21 | #include "llvm/Support/ErrorHandling.h" |
||
| 22 | #include <cassert> |
||
| 23 | #include <string> |
||
| 24 | #include <vector> |
||
| 25 | |||
| 26 | namespace llvm { |
||
| 27 | |||
| 28 | class Error; |
||
| 29 | class FunctionType; |
||
| 30 | class PointerType; |
||
| 31 | template <class ConstantClass> class ConstantUniqueMap; |
||
| 32 | |||
| 33 | class InlineAsm final : public Value { |
||
| 34 | public: |
||
| 35 | enum AsmDialect { |
||
| 36 | AD_ATT, |
||
| 37 | AD_Intel |
||
| 38 | }; |
||
| 39 | |||
| 40 | private: |
||
| 41 | friend struct InlineAsmKeyType; |
||
| 42 | friend class ConstantUniqueMap<InlineAsm>; |
||
| 43 | |||
| 44 | std::string AsmString, Constraints; |
||
| 45 | FunctionType *FTy; |
||
| 46 | bool HasSideEffects; |
||
| 47 | bool IsAlignStack; |
||
| 48 | AsmDialect Dialect; |
||
| 49 | bool CanThrow; |
||
| 50 | |||
| 51 | InlineAsm(FunctionType *Ty, const std::string &AsmString, |
||
| 52 | const std::string &Constraints, bool hasSideEffects, |
||
| 53 | bool isAlignStack, AsmDialect asmDialect, bool canThrow); |
||
| 54 | |||
| 55 | /// When the ConstantUniqueMap merges two types and makes two InlineAsms |
||
| 56 | /// identical, it destroys one of them with this method. |
||
| 57 | void destroyConstant(); |
||
| 58 | |||
| 59 | public: |
||
| 60 | InlineAsm(const InlineAsm &) = delete; |
||
| 61 | InlineAsm &operator=(const InlineAsm &) = delete; |
||
| 62 | |||
| 63 | /// InlineAsm::get - Return the specified uniqued inline asm string. |
||
| 64 | /// |
||
| 65 | static InlineAsm *get(FunctionType *Ty, StringRef AsmString, |
||
| 66 | StringRef Constraints, bool hasSideEffects, |
||
| 67 | bool isAlignStack = false, |
||
| 68 | AsmDialect asmDialect = AD_ATT, bool canThrow = false); |
||
| 69 | |||
| 70 | bool hasSideEffects() const { return HasSideEffects; } |
||
| 71 | bool isAlignStack() const { return IsAlignStack; } |
||
| 72 | AsmDialect getDialect() const { return Dialect; } |
||
| 73 | bool canThrow() const { return CanThrow; } |
||
| 74 | |||
| 75 | /// getType - InlineAsm's are always pointers. |
||
| 76 | /// |
||
| 77 | PointerType *getType() const { |
||
| 78 | return reinterpret_cast<PointerType*>(Value::getType()); |
||
| 79 | } |
||
| 80 | |||
| 81 | /// getFunctionType - InlineAsm's are always pointers to functions. |
||
| 82 | /// |
||
| 83 | FunctionType *getFunctionType() const; |
||
| 84 | |||
| 85 | const std::string &getAsmString() const { return AsmString; } |
||
| 86 | const std::string &getConstraintString() const { return Constraints; } |
||
| 87 | void collectAsmStrs(SmallVectorImpl<StringRef> &AsmStrs) const; |
||
| 88 | |||
| 89 | /// This static method can be used by the parser to check to see if the |
||
| 90 | /// specified constraint string is legal for the type. |
||
| 91 | static Error verify(FunctionType *Ty, StringRef Constraints); |
||
| 92 | |||
| 93 | // Constraint String Parsing |
||
| 94 | enum ConstraintPrefix { |
||
| 95 | isInput, // 'x' |
||
| 96 | isOutput, // '=x' |
||
| 97 | isClobber, // '~x' |
||
| 98 | isLabel, // '!x' |
||
| 99 | }; |
||
| 100 | |||
| 101 | using ConstraintCodeVector = std::vector<std::string>; |
||
| 102 | |||
| 103 | struct SubConstraintInfo { |
||
| 104 | /// MatchingInput - If this is not -1, this is an output constraint where an |
||
| 105 | /// input constraint is required to match it (e.g. "0"). The value is the |
||
| 106 | /// constraint number that matches this one (for example, if this is |
||
| 107 | /// constraint #0 and constraint #4 has the value "0", this will be 4). |
||
| 108 | int MatchingInput = -1; |
||
| 109 | |||
| 110 | /// Code - The constraint code, either the register name (in braces) or the |
||
| 111 | /// constraint letter/number. |
||
| 112 | ConstraintCodeVector Codes; |
||
| 113 | |||
| 114 | /// Default constructor. |
||
| 115 | SubConstraintInfo() = default; |
||
| 116 | }; |
||
| 117 | |||
| 118 | using SubConstraintInfoVector = std::vector<SubConstraintInfo>; |
||
| 119 | struct ConstraintInfo; |
||
| 120 | using ConstraintInfoVector = std::vector<ConstraintInfo>; |
||
| 121 | |||
| 122 | struct ConstraintInfo { |
||
| 123 | /// Type - The basic type of the constraint: input/output/clobber/label |
||
| 124 | /// |
||
| 125 | ConstraintPrefix Type = isInput; |
||
| 126 | |||
| 127 | /// isEarlyClobber - "&": output operand writes result before inputs are all |
||
| 128 | /// read. This is only ever set for an output operand. |
||
| 129 | bool isEarlyClobber = false; |
||
| 130 | |||
| 131 | /// MatchingInput - If this is not -1, this is an output constraint where an |
||
| 132 | /// input constraint is required to match it (e.g. "0"). The value is the |
||
| 133 | /// constraint number that matches this one (for example, if this is |
||
| 134 | /// constraint #0 and constraint #4 has the value "0", this will be 4). |
||
| 135 | int MatchingInput = -1; |
||
| 136 | |||
| 137 | /// hasMatchingInput - Return true if this is an output constraint that has |
||
| 138 | /// a matching input constraint. |
||
| 139 | bool hasMatchingInput() const { return MatchingInput != -1; } |
||
| 140 | |||
| 141 | /// isCommutative - This is set to true for a constraint that is commutative |
||
| 142 | /// with the next operand. |
||
| 143 | bool isCommutative = false; |
||
| 144 | |||
| 145 | /// isIndirect - True if this operand is an indirect operand. This means |
||
| 146 | /// that the address of the source or destination is present in the call |
||
| 147 | /// instruction, instead of it being returned or passed in explicitly. This |
||
| 148 | /// is represented with a '*' in the asm string. |
||
| 149 | bool isIndirect = false; |
||
| 150 | |||
| 151 | /// Code - The constraint code, either the register name (in braces) or the |
||
| 152 | /// constraint letter/number. |
||
| 153 | ConstraintCodeVector Codes; |
||
| 154 | |||
| 155 | /// isMultipleAlternative - '|': has multiple-alternative constraints. |
||
| 156 | bool isMultipleAlternative = false; |
||
| 157 | |||
| 158 | /// multipleAlternatives - If there are multiple alternative constraints, |
||
| 159 | /// this array will contain them. Otherwise it will be empty. |
||
| 160 | SubConstraintInfoVector multipleAlternatives; |
||
| 161 | |||
| 162 | /// The currently selected alternative constraint index. |
||
| 163 | unsigned currentAlternativeIndex = 0; |
||
| 164 | |||
| 165 | /// Default constructor. |
||
| 166 | ConstraintInfo() = default; |
||
| 167 | |||
| 168 | /// Parse - Analyze the specified string (e.g. "=*&{eax}") and fill in the |
||
| 169 | /// fields in this structure. If the constraint string is not understood, |
||
| 170 | /// return true, otherwise return false. |
||
| 171 | bool Parse(StringRef Str, ConstraintInfoVector &ConstraintsSoFar); |
||
| 172 | |||
| 173 | /// selectAlternative - Point this constraint to the alternative constraint |
||
| 174 | /// indicated by the index. |
||
| 175 | void selectAlternative(unsigned index); |
||
| 176 | |||
| 177 | /// Whether this constraint corresponds to an argument. |
||
| 178 | bool hasArg() const { |
||
| 179 | return Type == isInput || (Type == isOutput && isIndirect); |
||
| 180 | } |
||
| 181 | }; |
||
| 182 | |||
| 183 | /// ParseConstraints - Split up the constraint string into the specific |
||
| 184 | /// constraints and their prefixes. If this returns an empty vector, and if |
||
| 185 | /// the constraint string itself isn't empty, there was an error parsing. |
||
| 186 | static ConstraintInfoVector ParseConstraints(StringRef ConstraintString); |
||
| 187 | |||
| 188 | /// ParseConstraints - Parse the constraints of this inlineasm object, |
||
| 189 | /// returning them the same way that ParseConstraints(str) does. |
||
| 190 | ConstraintInfoVector ParseConstraints() const { |
||
| 191 | return ParseConstraints(Constraints); |
||
| 192 | } |
||
| 193 | |||
| 194 | // Methods for support type inquiry through isa, cast, and dyn_cast: |
||
| 195 | static bool classof(const Value *V) { |
||
| 196 | return V->getValueID() == Value::InlineAsmVal; |
||
| 197 | } |
||
| 198 | |||
| 199 | // These are helper methods for dealing with flags in the INLINEASM SDNode |
||
| 200 | // in the backend. |
||
| 201 | // |
||
| 202 | // The encoding of the flag word is currently: |
||
| 203 | // Bits 2-0 - A Kind_* value indicating the kind of the operand. |
||
| 204 | // Bits 15-3 - The number of SDNode operands associated with this inline |
||
| 205 | // assembly operand. |
||
| 206 | // If bit 31 is set: |
||
| 207 | // Bit 30-16 - The operand number that this operand must match. |
||
| 208 | // When bits 2-0 are Kind_Mem, the Constraint_* value must be |
||
| 209 | // obtained from the flags for this operand number. |
||
| 210 | // Else if bits 2-0 are Kind_Mem: |
||
| 211 | // Bit 30-16 - A Constraint_* value indicating the original constraint |
||
| 212 | // code. |
||
| 213 | // Else: |
||
| 214 | // Bit 30-16 - The register class ID to use for the operand. |
||
| 215 | |||
| 216 | enum : uint32_t { |
||
| 217 | // Fixed operands on an INLINEASM SDNode. |
||
| 218 | Op_InputChain = 0, |
||
| 219 | Op_AsmString = 1, |
||
| 220 | Op_MDNode = 2, |
||
| 221 | Op_ExtraInfo = 3, // HasSideEffects, IsAlignStack, AsmDialect. |
||
| 222 | Op_FirstOperand = 4, |
||
| 223 | |||
| 224 | // Fixed operands on an INLINEASM MachineInstr. |
||
| 225 | MIOp_AsmString = 0, |
||
| 226 | MIOp_ExtraInfo = 1, // HasSideEffects, IsAlignStack, AsmDialect. |
||
| 227 | MIOp_FirstOperand = 2, |
||
| 228 | |||
| 229 | // Interpretation of the MIOp_ExtraInfo bit field. |
||
| 230 | Extra_HasSideEffects = 1, |
||
| 231 | Extra_IsAlignStack = 2, |
||
| 232 | Extra_AsmDialect = 4, |
||
| 233 | Extra_MayLoad = 8, |
||
| 234 | Extra_MayStore = 16, |
||
| 235 | Extra_IsConvergent = 32, |
||
| 236 | |||
| 237 | // Inline asm operands map to multiple SDNode / MachineInstr operands. |
||
| 238 | // The first operand is an immediate describing the asm operand, the low |
||
| 239 | // bits is the kind: |
||
| 240 | Kind_RegUse = 1, // Input register, "r". |
||
| 241 | Kind_RegDef = 2, // Output register, "=r". |
||
| 242 | Kind_RegDefEarlyClobber = 3, // Early-clobber output register, "=&r". |
||
| 243 | Kind_Clobber = 4, // Clobbered register, "~r". |
||
| 244 | Kind_Imm = 5, // Immediate. |
||
| 245 | Kind_Mem = 6, // Memory operand, "m", or an address, "p". |
||
| 246 | Kind_Func = 7, // Address operand of function call |
||
| 247 | |||
| 248 | // Memory constraint codes. |
||
| 249 | // These could be tablegenerated but there's little need to do that since |
||
| 250 | // there's plenty of space in the encoding to support the union of all |
||
| 251 | // constraint codes for all targets. |
||
| 252 | // Addresses are included here as they need to be treated the same by the |
||
| 253 | // backend, the only difference is that they are not used to actaully |
||
| 254 | // access memory by the instruction. |
||
| 255 | Constraint_Unknown = 0, |
||
| 256 | Constraint_es, |
||
| 257 | Constraint_i, |
||
| 258 | Constraint_k, |
||
| 259 | Constraint_m, |
||
| 260 | Constraint_o, |
||
| 261 | Constraint_v, |
||
| 262 | Constraint_A, |
||
| 263 | Constraint_Q, |
||
| 264 | Constraint_R, |
||
| 265 | Constraint_S, |
||
| 266 | Constraint_T, |
||
| 267 | Constraint_Um, |
||
| 268 | Constraint_Un, |
||
| 269 | Constraint_Uq, |
||
| 270 | Constraint_Us, |
||
| 271 | Constraint_Ut, |
||
| 272 | Constraint_Uv, |
||
| 273 | Constraint_Uy, |
||
| 274 | Constraint_X, |
||
| 275 | Constraint_Z, |
||
| 276 | Constraint_ZB, |
||
| 277 | Constraint_ZC, |
||
| 278 | Constraint_Zy, |
||
| 279 | |||
| 280 | // Address constraints |
||
| 281 | Constraint_p, |
||
| 282 | Constraint_ZQ, |
||
| 283 | Constraint_ZR, |
||
| 284 | Constraint_ZS, |
||
| 285 | Constraint_ZT, |
||
| 286 | |||
| 287 | Constraints_Max = Constraint_ZT, |
||
| 288 | Constraints_ShiftAmount = 16, |
||
| 289 | |||
| 290 | Flag_MatchingOperand = 0x80000000 |
||
| 291 | }; |
||
| 292 | |||
| 293 | static unsigned getFlagWord(unsigned Kind, unsigned NumOps) { |
||
| 294 | assert(((NumOps << 3) & ~0xffff) == 0 && "Too many inline asm operands!"); |
||
| 295 | assert(Kind >= Kind_RegUse && Kind <= Kind_Func && "Invalid Kind"); |
||
| 296 | return Kind | (NumOps << 3); |
||
| 297 | } |
||
| 298 | |||
| 299 | static bool isRegDefKind(unsigned Flag){ return getKind(Flag) == Kind_RegDef;} |
||
| 300 | static bool isImmKind(unsigned Flag) { return getKind(Flag) == Kind_Imm; } |
||
| 301 | static bool isMemKind(unsigned Flag) { return getKind(Flag) == Kind_Mem; } |
||
| 302 | static bool isFuncKind(unsigned Flag) { return getKind(Flag) == Kind_Func; } |
||
| 303 | static bool isRegDefEarlyClobberKind(unsigned Flag) { |
||
| 304 | return getKind(Flag) == Kind_RegDefEarlyClobber; |
||
| 305 | } |
||
| 306 | static bool isClobberKind(unsigned Flag) { |
||
| 307 | return getKind(Flag) == Kind_Clobber; |
||
| 308 | } |
||
| 309 | |||
| 310 | /// getFlagWordForMatchingOp - Augment an existing flag word returned by |
||
| 311 | /// getFlagWord with information indicating that this input operand is tied |
||
| 312 | /// to a previous output operand. |
||
| 313 | static unsigned getFlagWordForMatchingOp(unsigned InputFlag, |
||
| 314 | unsigned MatchedOperandNo) { |
||
| 315 | assert(MatchedOperandNo <= 0x7fff && "Too big matched operand"); |
||
| 316 | assert((InputFlag & ~0xffff) == 0 && "High bits already contain data"); |
||
| 317 | return InputFlag | Flag_MatchingOperand | (MatchedOperandNo << 16); |
||
| 318 | } |
||
| 319 | |||
| 320 | /// getFlagWordForRegClass - Augment an existing flag word returned by |
||
| 321 | /// getFlagWord with the required register class for the following register |
||
| 322 | /// operands. |
||
| 323 | /// A tied use operand cannot have a register class, use the register class |
||
| 324 | /// from the def operand instead. |
||
| 325 | static unsigned getFlagWordForRegClass(unsigned InputFlag, unsigned RC) { |
||
| 326 | // Store RC + 1, reserve the value 0 to mean 'no register class'. |
||
| 327 | ++RC; |
||
| 328 | assert(!isImmKind(InputFlag) && "Immediates cannot have a register class"); |
||
| 329 | assert(!isMemKind(InputFlag) && "Memory operand cannot have a register class"); |
||
| 330 | assert(RC <= 0x7fff && "Too large register class ID"); |
||
| 331 | assert((InputFlag & ~0xffff) == 0 && "High bits already contain data"); |
||
| 332 | return InputFlag | (RC << 16); |
||
| 333 | } |
||
| 334 | |||
| 335 | /// Augment an existing flag word returned by getFlagWord with the constraint |
||
| 336 | /// code for a memory constraint. |
||
| 337 | static unsigned getFlagWordForMem(unsigned InputFlag, unsigned Constraint) { |
||
| 338 | assert((isMemKind(InputFlag) || isFuncKind(InputFlag)) && |
||
| 339 | "InputFlag is not a memory (include function) constraint!"); |
||
| 340 | assert(Constraint <= 0x7fff && "Too large a memory constraint ID"); |
||
| 341 | assert(Constraint <= Constraints_Max && "Unknown constraint ID"); |
||
| 342 | assert((InputFlag & ~0xffff) == 0 && "High bits already contain data"); |
||
| 343 | return InputFlag | (Constraint << Constraints_ShiftAmount); |
||
| 344 | } |
||
| 345 | |||
| 346 | static unsigned convertMemFlagWordToMatchingFlagWord(unsigned InputFlag) { |
||
| 347 | assert(isMemKind(InputFlag)); |
||
| 348 | return InputFlag & ~(0x7fff << Constraints_ShiftAmount); |
||
| 349 | } |
||
| 350 | |||
| 351 | static unsigned getKind(unsigned Flags) { |
||
| 352 | return Flags & 7; |
||
| 353 | } |
||
| 354 | |||
| 355 | static unsigned getMemoryConstraintID(unsigned Flag) { |
||
| 356 | assert((isMemKind(Flag) || isFuncKind(Flag)) && |
||
| 357 | "Not expected mem or function flang!"); |
||
| 358 | return (Flag >> Constraints_ShiftAmount) & 0x7fff; |
||
| 359 | } |
||
| 360 | |||
| 361 | /// getNumOperandRegisters - Extract the number of registers field from the |
||
| 362 | /// inline asm operand flag. |
||
| 363 | static unsigned getNumOperandRegisters(unsigned Flag) { |
||
| 364 | return (Flag & 0xffff) >> 3; |
||
| 365 | } |
||
| 366 | |||
| 367 | /// isUseOperandTiedToDef - Return true if the flag of the inline asm |
||
| 368 | /// operand indicates it is an use operand that's matched to a def operand. |
||
| 369 | static bool isUseOperandTiedToDef(unsigned Flag, unsigned &Idx) { |
||
| 370 | if ((Flag & Flag_MatchingOperand) == 0) |
||
| 371 | return false; |
||
| 372 | Idx = (Flag & ~Flag_MatchingOperand) >> 16; |
||
| 373 | return true; |
||
| 374 | } |
||
| 375 | |||
| 376 | /// hasRegClassConstraint - Returns true if the flag contains a register |
||
| 377 | /// class constraint. Sets RC to the register class ID. |
||
| 378 | static bool hasRegClassConstraint(unsigned Flag, unsigned &RC) { |
||
| 379 | if (Flag & Flag_MatchingOperand) |
||
| 380 | return false; |
||
| 381 | unsigned High = Flag >> 16; |
||
| 382 | // getFlagWordForRegClass() uses 0 to mean no register class, and otherwise |
||
| 383 | // stores RC + 1. |
||
| 384 | if (!High) |
||
| 385 | return false; |
||
| 386 | RC = High - 1; |
||
| 387 | return true; |
||
| 388 | } |
||
| 389 | |||
| 390 | static std::vector<StringRef> getExtraInfoNames(unsigned ExtraInfo) { |
||
| 391 | std::vector<StringRef> Result; |
||
| 392 | if (ExtraInfo & InlineAsm::Extra_HasSideEffects) |
||
| 393 | Result.push_back("sideeffect"); |
||
| 394 | if (ExtraInfo & InlineAsm::Extra_MayLoad) |
||
| 395 | Result.push_back("mayload"); |
||
| 396 | if (ExtraInfo & InlineAsm::Extra_MayStore) |
||
| 397 | Result.push_back("maystore"); |
||
| 398 | if (ExtraInfo & InlineAsm::Extra_IsConvergent) |
||
| 399 | Result.push_back("isconvergent"); |
||
| 400 | if (ExtraInfo & InlineAsm::Extra_IsAlignStack) |
||
| 401 | Result.push_back("alignstack"); |
||
| 402 | |||
| 403 | AsmDialect Dialect = |
||
| 404 | InlineAsm::AsmDialect((ExtraInfo & InlineAsm::Extra_AsmDialect)); |
||
| 405 | |||
| 406 | if (Dialect == InlineAsm::AD_ATT) |
||
| 407 | Result.push_back("attdialect"); |
||
| 408 | if (Dialect == InlineAsm::AD_Intel) |
||
| 409 | Result.push_back("inteldialect"); |
||
| 410 | |||
| 411 | return Result; |
||
| 412 | } |
||
| 413 | |||
| 414 | static StringRef getKindName(unsigned Kind) { |
||
| 415 | switch (Kind) { |
||
| 416 | case InlineAsm::Kind_RegUse: |
||
| 417 | return "reguse"; |
||
| 418 | case InlineAsm::Kind_RegDef: |
||
| 419 | return "regdef"; |
||
| 420 | case InlineAsm::Kind_RegDefEarlyClobber: |
||
| 421 | return "regdef-ec"; |
||
| 422 | case InlineAsm::Kind_Clobber: |
||
| 423 | return "clobber"; |
||
| 424 | case InlineAsm::Kind_Imm: |
||
| 425 | return "imm"; |
||
| 426 | case InlineAsm::Kind_Mem: |
||
| 427 | case InlineAsm::Kind_Func: |
||
| 428 | return "mem"; |
||
| 429 | default: |
||
| 430 | llvm_unreachable("Unknown operand kind"); |
||
| 431 | } |
||
| 432 | } |
||
| 433 | |||
| 434 | static StringRef getMemConstraintName(unsigned Constraint) { |
||
| 435 | switch (Constraint) { |
||
| 436 | case InlineAsm::Constraint_es: |
||
| 437 | return "es"; |
||
| 438 | case InlineAsm::Constraint_i: |
||
| 439 | return "i"; |
||
| 440 | case InlineAsm::Constraint_k: |
||
| 441 | return "k"; |
||
| 442 | case InlineAsm::Constraint_m: |
||
| 443 | return "m"; |
||
| 444 | case InlineAsm::Constraint_o: |
||
| 445 | return "o"; |
||
| 446 | case InlineAsm::Constraint_v: |
||
| 447 | return "v"; |
||
| 448 | case InlineAsm::Constraint_Q: |
||
| 449 | return "Q"; |
||
| 450 | case InlineAsm::Constraint_R: |
||
| 451 | return "R"; |
||
| 452 | case InlineAsm::Constraint_S: |
||
| 453 | return "S"; |
||
| 454 | case InlineAsm::Constraint_T: |
||
| 455 | return "T"; |
||
| 456 | case InlineAsm::Constraint_Um: |
||
| 457 | return "Um"; |
||
| 458 | case InlineAsm::Constraint_Un: |
||
| 459 | return "Un"; |
||
| 460 | case InlineAsm::Constraint_Uq: |
||
| 461 | return "Uq"; |
||
| 462 | case InlineAsm::Constraint_Us: |
||
| 463 | return "Us"; |
||
| 464 | case InlineAsm::Constraint_Ut: |
||
| 465 | return "Ut"; |
||
| 466 | case InlineAsm::Constraint_Uv: |
||
| 467 | return "Uv"; |
||
| 468 | case InlineAsm::Constraint_Uy: |
||
| 469 | return "Uy"; |
||
| 470 | case InlineAsm::Constraint_X: |
||
| 471 | return "X"; |
||
| 472 | case InlineAsm::Constraint_Z: |
||
| 473 | return "Z"; |
||
| 474 | case InlineAsm::Constraint_ZB: |
||
| 475 | return "ZB"; |
||
| 476 | case InlineAsm::Constraint_ZC: |
||
| 477 | return "ZC"; |
||
| 478 | case InlineAsm::Constraint_Zy: |
||
| 479 | return "Zy"; |
||
| 480 | case InlineAsm::Constraint_p: |
||
| 481 | return "p"; |
||
| 482 | case InlineAsm::Constraint_ZQ: |
||
| 483 | return "ZQ"; |
||
| 484 | case InlineAsm::Constraint_ZR: |
||
| 485 | return "ZR"; |
||
| 486 | case InlineAsm::Constraint_ZS: |
||
| 487 | return "ZS"; |
||
| 488 | case InlineAsm::Constraint_ZT: |
||
| 489 | return "ZT"; |
||
| 490 | default: |
||
| 491 | llvm_unreachable("Unknown memory constraint"); |
||
| 492 | } |
||
| 493 | } |
||
| 494 | }; |
||
| 495 | |||
| 496 | } // end namespace llvm |
||
| 497 | |||
| 498 | #endif // LLVM_IR_INLINEASM_H |