| //===- llvm/InlineAsm.h - Class to represent inline asm strings -*- C++ -*-===// |
| // |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| // See https://llvm.org/LICENSE.txt for license information. |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| // |
| //===----------------------------------------------------------------------===// |
| // |
| // This class represents the inline asm strings, which are Value*'s that are |
| // used as the callee operand of call instructions. InlineAsm's are uniqued |
| // like constants, and created via InlineAsm::get(...). |
| // |
| //===----------------------------------------------------------------------===// |
| |
| #ifndef LLVM_IR_INLINEASM_H |
| #define LLVM_IR_INLINEASM_H |
| |
| #include "llvm/ADT/Bitfields.h" |
| #include "llvm/ADT/SmallVector.h" |
| #include "llvm/ADT/StringRef.h" |
| #include "llvm/IR/Value.h" |
| #include "llvm/Support/ErrorHandling.h" |
| #include <cassert> |
| #include <string> |
| #include <vector> |
| |
| namespace llvm { |
| |
| class Error; |
| class FunctionType; |
| class PointerType; |
| template <class ConstantClass> class ConstantUniqueMap; |
| |
| class InlineAsm final : public Value { |
| public: |
| enum AsmDialect { |
| AD_ATT, |
| AD_Intel |
| }; |
| |
| private: |
| friend struct InlineAsmKeyType; |
| friend class ConstantUniqueMap<InlineAsm>; |
| |
| std::string AsmString, Constraints; |
| FunctionType *FTy; |
| bool HasSideEffects; |
| bool IsAlignStack; |
| AsmDialect Dialect; |
| bool CanThrow; |
| |
| InlineAsm(FunctionType *Ty, const std::string &AsmString, |
| const std::string &Constraints, bool hasSideEffects, |
| bool isAlignStack, AsmDialect asmDialect, bool canThrow); |
| |
| /// When the ConstantUniqueMap merges two types and makes two InlineAsms |
| /// identical, it destroys one of them with this method. |
| void destroyConstant(); |
| |
| public: |
| InlineAsm(const InlineAsm &) = delete; |
| InlineAsm &operator=(const InlineAsm &) = delete; |
| |
| /// InlineAsm::get - Return the specified uniqued inline asm string. |
| /// |
| static InlineAsm *get(FunctionType *Ty, StringRef AsmString, |
| StringRef Constraints, bool hasSideEffects, |
| bool isAlignStack = false, |
| AsmDialect asmDialect = AD_ATT, bool canThrow = false); |
| |
| bool hasSideEffects() const { return HasSideEffects; } |
| bool isAlignStack() const { return IsAlignStack; } |
| AsmDialect getDialect() const { return Dialect; } |
| bool canThrow() const { return CanThrow; } |
| |
| /// getType - InlineAsm's are always pointers. |
| /// |
| PointerType *getType() const { |
| return reinterpret_cast<PointerType*>(Value::getType()); |
| } |
| |
| /// getFunctionType - InlineAsm's are always pointers to functions. |
| /// |
| FunctionType *getFunctionType() const; |
| |
| const std::string &getAsmString() const { return AsmString; } |
| const std::string &getConstraintString() const { return Constraints; } |
| void collectAsmStrs(SmallVectorImpl<StringRef> &AsmStrs) const; |
| |
| /// This static method can be used by the parser to check to see if the |
| /// specified constraint string is legal for the type. |
| static Error verify(FunctionType *Ty, StringRef Constraints); |
| |
| // Constraint String Parsing |
| enum ConstraintPrefix { |
| isInput, // 'x' |
| isOutput, // '=x' |
| isClobber, // '~x' |
| isLabel, // '!x' |
| }; |
| |
| using ConstraintCodeVector = std::vector<std::string>; |
| |
| struct SubConstraintInfo { |
| /// MatchingInput - If this is not -1, this is an output constraint where an |
| /// input constraint is required to match it (e.g. "0"). The value is the |
| /// constraint number that matches this one (for example, if this is |
| /// constraint #0 and constraint #4 has the value "0", this will be 4). |
| int MatchingInput = -1; |
| |
| /// Code - The constraint code, either the register name (in braces) or the |
| /// constraint letter/number. |
| ConstraintCodeVector Codes; |
| |
| /// Default constructor. |
| SubConstraintInfo() = default; |
| }; |
| |
| using SubConstraintInfoVector = std::vector<SubConstraintInfo>; |
| struct ConstraintInfo; |
| using ConstraintInfoVector = std::vector<ConstraintInfo>; |
| |
| struct ConstraintInfo { |
| /// Type - The basic type of the constraint: input/output/clobber/label |
| /// |
| ConstraintPrefix Type = isInput; |
| |
| /// isEarlyClobber - "&": output operand writes result before inputs are all |
| /// read. This is only ever set for an output operand. |
| bool isEarlyClobber = false; |
| |
| /// MatchingInput - If this is not -1, this is an output constraint where an |
| /// input constraint is required to match it (e.g. "0"). The value is the |
| /// constraint number that matches this one (for example, if this is |
| /// constraint #0 and constraint #4 has the value "0", this will be 4). |
| int MatchingInput = -1; |
| |
| /// hasMatchingInput - Return true if this is an output constraint that has |
| /// a matching input constraint. |
| bool hasMatchingInput() const { return MatchingInput != -1; } |
| |
| /// isCommutative - This is set to true for a constraint that is commutative |
| /// with the next operand. |
| bool isCommutative = false; |
| |
| /// isIndirect - True if this operand is an indirect operand. This means |
| /// that the address of the source or destination is present in the call |
| /// instruction, instead of it being returned or passed in explicitly. This |
| /// is represented with a '*' in the asm string. |
| bool isIndirect = false; |
| |
| /// Code - The constraint code, either the register name (in braces) or the |
| /// constraint letter/number. |
| ConstraintCodeVector Codes; |
| |
| /// isMultipleAlternative - '|': has multiple-alternative constraints. |
| bool isMultipleAlternative = false; |
| |
| /// multipleAlternatives - If there are multiple alternative constraints, |
| /// this array will contain them. Otherwise it will be empty. |
| SubConstraintInfoVector multipleAlternatives; |
| |
| /// The currently selected alternative constraint index. |
| unsigned currentAlternativeIndex = 0; |
| |
| /// Default constructor. |
| ConstraintInfo() = default; |
| |
| /// Parse - Analyze the specified string (e.g. "=*&{eax}") and fill in the |
| /// fields in this structure. If the constraint string is not understood, |
| /// return true, otherwise return false. |
| bool Parse(StringRef Str, ConstraintInfoVector &ConstraintsSoFar); |
| |
| /// selectAlternative - Point this constraint to the alternative constraint |
| /// indicated by the index. |
| void selectAlternative(unsigned index); |
| |
| /// Whether this constraint corresponds to an argument. |
| bool hasArg() const { |
| return Type == isInput || (Type == isOutput && isIndirect); |
| } |
| }; |
| |
| /// ParseConstraints - Split up the constraint string into the specific |
| /// constraints and their prefixes. If this returns an empty vector, and if |
| /// the constraint string itself isn't empty, there was an error parsing. |
| static ConstraintInfoVector ParseConstraints(StringRef ConstraintString); |
| |
| /// ParseConstraints - Parse the constraints of this inlineasm object, |
| /// returning them the same way that ParseConstraints(str) does. |
| ConstraintInfoVector ParseConstraints() const { |
| return ParseConstraints(Constraints); |
| } |
| |
| // Methods for support type inquiry through isa, cast, and dyn_cast: |
| static bool classof(const Value *V) { |
| return V->getValueID() == Value::InlineAsmVal; |
| } |
| |
| enum : uint32_t { |
| // Fixed operands on an INLINEASM SDNode. |
| Op_InputChain = 0, |
| Op_AsmString = 1, |
| Op_MDNode = 2, |
| Op_ExtraInfo = 3, // HasSideEffects, IsAlignStack, AsmDialect. |
| Op_FirstOperand = 4, |
| |
| // Fixed operands on an INLINEASM MachineInstr. |
| MIOp_AsmString = 0, |
| MIOp_ExtraInfo = 1, // HasSideEffects, IsAlignStack, AsmDialect. |
| MIOp_FirstOperand = 2, |
| |
| // Interpretation of the MIOp_ExtraInfo bit field. |
| Extra_HasSideEffects = 1, |
| Extra_IsAlignStack = 2, |
| Extra_AsmDialect = 4, |
| Extra_MayLoad = 8, |
| Extra_MayStore = 16, |
| Extra_IsConvergent = 32, |
| }; |
| |
| // Inline asm operands map to multiple SDNode / MachineInstr operands. |
| // The first operand is an immediate describing the asm operand, the low |
| // bits is the kind: |
| enum class Kind : uint8_t { |
| RegUse = 1, // Input register, "r". |
| RegDef = 2, // Output register, "=r". |
| RegDefEarlyClobber = 3, // Early-clobber output register, "=&r". |
| Clobber = 4, // Clobbered register, "~r". |
| Imm = 5, // Immediate. |
| Mem = 6, // Memory operand, "m", or an address, "p". |
| Func = 7, // Address operand of function call |
| }; |
| |
| // Memory constraint codes. |
| // Addresses are included here as they need to be treated the same by the |
| // backend, the only difference is that they are not used to actaully |
| // access memory by the instruction. |
| enum class ConstraintCode : uint32_t { |
| Unknown = 0, |
| es, |
| i, |
| k, |
| m, |
| o, |
| v, |
| A, |
| Q, |
| R, |
| S, |
| T, |
| Um, |
| Un, |
| Uq, |
| Us, |
| Ut, |
| Uv, |
| Uy, |
| X, |
| Z, |
| ZB, |
| ZC, |
| Zy, |
| |
| // Address constraints |
| p, |
| ZQ, |
| ZR, |
| ZS, |
| ZT, |
| |
| Max = ZT, |
| }; |
| |
| // This class is intentionally packed into a 32b value as it is used as a |
| // MVT::i32 ConstantSDNode SDValue for SelectionDAG and as immediate operands |
| // on INLINEASM and INLINEASM_BR MachineInstr's. |
| // |
| // The encoding of Flag is currently: |
| // Bits 2-0 - A Kind::* value indicating the kind of the operand. |
| // (KindField) |
| // Bits 15-3 - The number of SDNode operands associated with this inline |
| // assembly operand. Once lowered to MIR, this represents the |
| // number of MachineOperands necessary to refer to a |
| // MachineOperandType::MO_FrameIndex. (NumOperands) |
| // Bit 31 - Determines if this is a matched operand. (IsMatched) |
| // If bit 31 is set: |
| // Bits 30-16 - The operand number that this operand must match. |
| // (MatchedOperandNo) |
| // Else if bits 2-0 are Kind::Mem: |
| // Bits 30-16 - A ConstraintCode:: value indicating the original |
| // constraint code. (MemConstraintCode) |
| // Else: |
| // Bits 29-16 - The register class ID to use for the operand. (RegClass) |
| // Bit 30 - If the register is permitted to be spilled. |
| // (RegMayBeFolded) |
| // Defaults to false "r", may be set for constraints like |
| // "rm" (or "g"). |
| // |
| // As such, MatchedOperandNo, MemConstraintCode, and |
| // (RegClass+RegMayBeFolded) are views of the same slice of bits, but are |
| // mutually exclusive depending on the fields IsMatched then KindField. |
| class Flag { |
| uint32_t Storage; |
| using KindField = Bitfield::Element<Kind, 0, 3, Kind::Func>; |
| using NumOperands = Bitfield::Element<unsigned, 3, 13>; |
| using MatchedOperandNo = Bitfield::Element<unsigned, 16, 15>; |
| using MemConstraintCode = Bitfield::Element<ConstraintCode, 16, 15, ConstraintCode::Max>; |
| using RegClass = Bitfield::Element<unsigned, 16, 14>; |
| using RegMayBeFolded = Bitfield::Element<bool, 30, 1>; |
| using IsMatched = Bitfield::Element<bool, 31, 1>; |
| |
| |
| unsigned getMatchedOperandNo() const { return Bitfield::get<MatchedOperandNo>(Storage); } |
| unsigned getRegClass() const { return Bitfield::get<RegClass>(Storage); } |
| bool isMatched() const { return Bitfield::get<IsMatched>(Storage); } |
| |
| public: |
| Flag() : Storage(0) {} |
| explicit Flag(uint32_t F) : Storage(F) {} |
| Flag(enum Kind K, unsigned NumOps) : Storage(0) { |
| Bitfield::set<KindField>(Storage, K); |
| Bitfield::set<NumOperands>(Storage, NumOps); |
| } |
| operator uint32_t() { return Storage; } |
| Kind getKind() const { return Bitfield::get<KindField>(Storage); } |
| bool isRegUseKind() const { return getKind() == Kind::RegUse; } |
| bool isRegDefKind() const { return getKind() == Kind::RegDef; } |
| bool isRegDefEarlyClobberKind() const { |
| return getKind() == Kind::RegDefEarlyClobber; |
| } |
| bool isClobberKind() const { return getKind() == Kind::Clobber; } |
| bool isImmKind() const { return getKind() == Kind::Imm; } |
| bool isMemKind() const { return getKind() == Kind::Mem; } |
| bool isFuncKind() const { return getKind() == Kind::Func; } |
| StringRef getKindName() const { |
| switch (getKind()) { |
| case Kind::RegUse: |
| return "reguse"; |
| case Kind::RegDef: |
| return "regdef"; |
| case Kind::RegDefEarlyClobber: |
| return "regdef-ec"; |
| case Kind::Clobber: |
| return "clobber"; |
| case Kind::Imm: |
| return "imm"; |
| case Kind::Mem: |
| case Kind::Func: |
| return "mem"; |
| } |
| llvm_unreachable("impossible kind"); |
| } |
| |
| /// getNumOperandRegisters - Extract the number of registers field from the |
| /// inline asm operand flag. |
| unsigned getNumOperandRegisters() const { |
| return Bitfield::get<NumOperands>(Storage); |
| } |
| |
| /// isUseOperandTiedToDef - Return true if the flag of the inline asm |
| /// operand indicates it is an use operand that's matched to a def operand. |
| bool isUseOperandTiedToDef(unsigned &Idx) const { |
| if (!isMatched()) |
| return false; |
| Idx = getMatchedOperandNo(); |
| return true; |
| } |
| |
| /// hasRegClassConstraint - Returns true if the flag contains a register |
| /// class constraint. Sets RC to the register class ID. |
| bool hasRegClassConstraint(unsigned &RC) const { |
| if (isMatched()) |
| return false; |
| // setRegClass() uses 0 to mean no register class, and otherwise stores |
| // RC + 1. |
| if (!getRegClass()) |
| return false; |
| RC = getRegClass() - 1; |
| return true; |
| } |
| |
| ConstraintCode getMemoryConstraintID() const { |
| assert((isMemKind() || isFuncKind()) && |
| "Not expected mem or function flag!"); |
| return Bitfield::get<MemConstraintCode>(Storage); |
| } |
| |
| /// setMatchingOp - Augment an existing flag with information indicating |
| /// that this input operand is tied to a previous output operand. |
| void setMatchingOp(unsigned OperandNo) { |
| assert(getMatchedOperandNo() == 0 && "Matching operand already set"); |
| Bitfield::set<MatchedOperandNo>(Storage, OperandNo); |
| Bitfield::set<IsMatched>(Storage, true); |
| } |
| |
| /// setRegClass - Augment an existing flag with the required register class |
| /// for the following register operands. A tied use operand cannot have a |
| /// register class, use the register class from the def operand instead. |
| void setRegClass(unsigned RC) { |
| assert(!isImmKind() && "Immediates cannot have a register class"); |
| assert(!isMemKind() && "Memory operand cannot have a register class"); |
| assert(getRegClass() == 0 && "Register class already set"); |
| // Store RC + 1, reserve the value 0 to mean 'no register class'. |
| Bitfield::set<RegClass>(Storage, RC + 1); |
| } |
| |
| /// setMemConstraint - Augment an existing flag with the constraint code for |
| /// a memory constraint. |
| void setMemConstraint(ConstraintCode C) { |
| assert(getMemoryConstraintID() == ConstraintCode::Unknown && "Mem constraint already set"); |
| Bitfield::set<MemConstraintCode>(Storage, C); |
| } |
| /// clearMemConstraint - Similar to setMemConstraint(0), but without the |
| /// assertion checking that the constraint has not been set previously. |
| void clearMemConstraint() { |
| assert((isMemKind() || isFuncKind()) && |
| "Flag is not a memory or function constraint!"); |
| Bitfield::set<MemConstraintCode>(Storage, ConstraintCode::Unknown); |
| } |
| |
| /// Set a bit to denote that while this operand is some kind of register |
| /// (use, def, ...), a memory flag did appear in the original constraint |
| /// list. This is set by the instruction selection framework, and consumed |
| /// by the register allocator. While the register allocator is generally |
| /// responsible for spilling registers, we need to be able to distinguish |
| /// between registers that the register allocator has permission to fold |
| /// ("rm") vs ones it does not ("r"). This is because the inline asm may use |
| /// instructions which don't support memory addressing modes for that |
| /// operand. |
| void setRegMayBeFolded(bool B) { |
| assert((isRegDefKind() || isRegDefEarlyClobberKind() || isRegUseKind()) && |
| "Must be reg"); |
| Bitfield::set<RegMayBeFolded>(Storage, B); |
| } |
| bool getRegMayBeFolded() const { |
| assert((isRegDefKind() || isRegDefEarlyClobberKind() || isRegUseKind()) && |
| "Must be reg"); |
| return Bitfield::get<RegMayBeFolded>(Storage); |
| } |
| }; |
| |
| static std::vector<StringRef> getExtraInfoNames(unsigned ExtraInfo) { |
| std::vector<StringRef> Result; |
| if (ExtraInfo & InlineAsm::Extra_HasSideEffects) |
| Result.push_back("sideeffect"); |
| if (ExtraInfo & InlineAsm::Extra_MayLoad) |
| Result.push_back("mayload"); |
| if (ExtraInfo & InlineAsm::Extra_MayStore) |
| Result.push_back("maystore"); |
| if (ExtraInfo & InlineAsm::Extra_IsConvergent) |
| Result.push_back("isconvergent"); |
| if (ExtraInfo & InlineAsm::Extra_IsAlignStack) |
| Result.push_back("alignstack"); |
| |
| AsmDialect Dialect = |
| InlineAsm::AsmDialect((ExtraInfo & InlineAsm::Extra_AsmDialect)); |
| |
| if (Dialect == InlineAsm::AD_ATT) |
| Result.push_back("attdialect"); |
| if (Dialect == InlineAsm::AD_Intel) |
| Result.push_back("inteldialect"); |
| |
| return Result; |
| } |
| |
| static StringRef getMemConstraintName(ConstraintCode C) { |
| switch (C) { |
| case ConstraintCode::es: |
| return "es"; |
| case ConstraintCode::i: |
| return "i"; |
| case ConstraintCode::k: |
| return "k"; |
| case ConstraintCode::m: |
| return "m"; |
| case ConstraintCode::o: |
| return "o"; |
| case ConstraintCode::v: |
| return "v"; |
| case ConstraintCode::A: |
| return "A"; |
| case ConstraintCode::Q: |
| return "Q"; |
| case ConstraintCode::R: |
| return "R"; |
| case ConstraintCode::S: |
| return "S"; |
| case ConstraintCode::T: |
| return "T"; |
| case ConstraintCode::Um: |
| return "Um"; |
| case ConstraintCode::Un: |
| return "Un"; |
| case ConstraintCode::Uq: |
| return "Uq"; |
| case ConstraintCode::Us: |
| return "Us"; |
| case ConstraintCode::Ut: |
| return "Ut"; |
| case ConstraintCode::Uv: |
| return "Uv"; |
| case ConstraintCode::Uy: |
| return "Uy"; |
| case ConstraintCode::X: |
| return "X"; |
| case ConstraintCode::Z: |
| return "Z"; |
| case ConstraintCode::ZB: |
| return "ZB"; |
| case ConstraintCode::ZC: |
| return "ZC"; |
| case ConstraintCode::Zy: |
| return "Zy"; |
| case ConstraintCode::p: |
| return "p"; |
| case ConstraintCode::ZQ: |
| return "ZQ"; |
| case ConstraintCode::ZR: |
| return "ZR"; |
| case ConstraintCode::ZS: |
| return "ZS"; |
| case ConstraintCode::ZT: |
| return "ZT"; |
| default: |
| llvm_unreachable("Unknown memory constraint"); |
| } |
| } |
| }; |
| |
| } // end namespace llvm |
| |
| #endif // LLVM_IR_INLINEASM_H |