#ifndef LLVM_IR_INLINEASM_H
#define LLVM_IR_INLINEASM_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);
void destroyConstant();
public:
InlineAsm(const InlineAsm &) = delete;
InlineAsm &operator=(const InlineAsm &) = delete;
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; }
PointerType *getType() const {
return reinterpret_cast<PointerType*>(Value::getType());
}
FunctionType *getFunctionType() const;
const std::string &getAsmString() const { return AsmString; }
const std::string &getConstraintString() const { return Constraints; }
static Error verify(FunctionType *Ty, StringRef Constraints);
enum ConstraintPrefix {
isInput, isOutput, isClobber, isLabel, };
using ConstraintCodeVector = std::vector<std::string>;
struct SubConstraintInfo {
int MatchingInput = -1;
ConstraintCodeVector Codes;
SubConstraintInfo() = default;
};
using SubConstraintInfoVector = std::vector<SubConstraintInfo>;
struct ConstraintInfo;
using ConstraintInfoVector = std::vector<ConstraintInfo>;
struct ConstraintInfo {
ConstraintPrefix Type = isInput;
bool isEarlyClobber = false;
int MatchingInput = -1;
bool hasMatchingInput() const { return MatchingInput != -1; }
bool isCommutative = false;
bool isIndirect = false;
ConstraintCodeVector Codes;
bool isMultipleAlternative = false;
SubConstraintInfoVector multipleAlternatives;
unsigned currentAlternativeIndex = 0;
ConstraintInfo() = default;
bool Parse(StringRef Str, ConstraintInfoVector &ConstraintsSoFar);
void selectAlternative(unsigned index);
bool hasArg() const {
return Type == isInput || (Type == isOutput && isIndirect);
}
};
static ConstraintInfoVector ParseConstraints(StringRef ConstraintString);
ConstraintInfoVector ParseConstraints() const {
return ParseConstraints(Constraints);
}
static bool classof(const Value *V) {
return V->getValueID() == Value::InlineAsmVal;
}
enum : uint32_t {
Op_InputChain = 0,
Op_AsmString = 1,
Op_MDNode = 2,
Op_ExtraInfo = 3, Op_FirstOperand = 4,
MIOp_AsmString = 0,
MIOp_ExtraInfo = 1, MIOp_FirstOperand = 2,
Extra_HasSideEffects = 1,
Extra_IsAlignStack = 2,
Extra_AsmDialect = 4,
Extra_MayLoad = 8,
Extra_MayStore = 16,
Extra_IsConvergent = 32,
Kind_RegUse = 1, Kind_RegDef = 2, Kind_RegDefEarlyClobber = 3, Kind_Clobber = 4, Kind_Imm = 5, Kind_Mem = 6,
Constraint_Unknown = 0,
Constraint_es,
Constraint_i,
Constraint_m,
Constraint_o,
Constraint_v,
Constraint_A,
Constraint_Q,
Constraint_R,
Constraint_S,
Constraint_T,
Constraint_Um,
Constraint_Un,
Constraint_Uq,
Constraint_Us,
Constraint_Ut,
Constraint_Uv,
Constraint_Uy,
Constraint_X,
Constraint_Z,
Constraint_ZC,
Constraint_Zy,
Constraint_p,
Constraint_ZQ,
Constraint_ZR,
Constraint_ZS,
Constraint_ZT,
Constraints_Max = Constraint_ZT,
Constraints_ShiftAmount = 16,
Flag_MatchingOperand = 0x80000000
};
static unsigned getFlagWord(unsigned Kind, unsigned NumOps) {
assert(((NumOps << 3) & ~0xffff) == 0 && "Too many inline asm operands!");
assert(Kind >= Kind_RegUse && Kind <= Kind_Mem && "Invalid Kind");
return Kind | (NumOps << 3);
}
static bool isRegDefKind(unsigned Flag){ return getKind(Flag) == Kind_RegDef;}
static bool isImmKind(unsigned Flag) { return getKind(Flag) == Kind_Imm; }
static bool isMemKind(unsigned Flag) { return getKind(Flag) == Kind_Mem; }
static bool isRegDefEarlyClobberKind(unsigned Flag) {
return getKind(Flag) == Kind_RegDefEarlyClobber;
}
static bool isClobberKind(unsigned Flag) {
return getKind(Flag) == Kind_Clobber;
}
static unsigned getFlagWordForMatchingOp(unsigned InputFlag,
unsigned MatchedOperandNo) {
assert(MatchedOperandNo <= 0x7fff && "Too big matched operand");
assert((InputFlag & ~0xffff) == 0 && "High bits already contain data");
return InputFlag | Flag_MatchingOperand | (MatchedOperandNo << 16);
}
static unsigned getFlagWordForRegClass(unsigned InputFlag, unsigned RC) {
++RC;
assert(!isImmKind(InputFlag) && "Immediates cannot have a register class");
assert(!isMemKind(InputFlag) && "Memory operand cannot have a register class");
assert(RC <= 0x7fff && "Too large register class ID");
assert((InputFlag & ~0xffff) == 0 && "High bits already contain data");
return InputFlag | (RC << 16);
}
static unsigned getFlagWordForMem(unsigned InputFlag, unsigned Constraint) {
assert(isMemKind(InputFlag) && "InputFlag is not a memory constraint!");
assert(Constraint <= 0x7fff && "Too large a memory constraint ID");
assert(Constraint <= Constraints_Max && "Unknown constraint ID");
assert((InputFlag & ~0xffff) == 0 && "High bits already contain data");
return InputFlag | (Constraint << Constraints_ShiftAmount);
}
static unsigned convertMemFlagWordToMatchingFlagWord(unsigned InputFlag) {
assert(isMemKind(InputFlag));
return InputFlag & ~(0x7fff << Constraints_ShiftAmount);
}
static unsigned getKind(unsigned Flags) {
return Flags & 7;
}
static unsigned getMemoryConstraintID(unsigned Flag) {
assert(isMemKind(Flag));
return (Flag >> Constraints_ShiftAmount) & 0x7fff;
}
static unsigned getNumOperandRegisters(unsigned Flag) {
return (Flag & 0xffff) >> 3;
}
static bool isUseOperandTiedToDef(unsigned Flag, unsigned &Idx) {
if ((Flag & Flag_MatchingOperand) == 0)
return false;
Idx = (Flag & ~Flag_MatchingOperand) >> 16;
return true;
}
static bool hasRegClassConstraint(unsigned Flag, unsigned &RC) {
if (Flag & Flag_MatchingOperand)
return false;
unsigned High = Flag >> 16;
if (!High)
return false;
RC = High - 1;
return true;
}
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 getKindName(unsigned Kind) {
switch (Kind) {
case InlineAsm::Kind_RegUse:
return "reguse";
case InlineAsm::Kind_RegDef:
return "regdef";
case InlineAsm::Kind_RegDefEarlyClobber:
return "regdef-ec";
case InlineAsm::Kind_Clobber:
return "clobber";
case InlineAsm::Kind_Imm:
return "imm";
case InlineAsm::Kind_Mem:
return "mem";
default:
llvm_unreachable("Unknown operand kind");
}
}
static StringRef getMemConstraintName(unsigned Constraint) {
switch (Constraint) {
case InlineAsm::Constraint_es:
return "es";
case InlineAsm::Constraint_i:
return "i";
case InlineAsm::Constraint_m:
return "m";
case InlineAsm::Constraint_o:
return "o";
case InlineAsm::Constraint_v:
return "v";
case InlineAsm::Constraint_Q:
return "Q";
case InlineAsm::Constraint_R:
return "R";
case InlineAsm::Constraint_S:
return "S";
case InlineAsm::Constraint_T:
return "T";
case InlineAsm::Constraint_Um:
return "Um";
case InlineAsm::Constraint_Un:
return "Un";
case InlineAsm::Constraint_Uq:
return "Uq";
case InlineAsm::Constraint_Us:
return "Us";
case InlineAsm::Constraint_Ut:
return "Ut";
case InlineAsm::Constraint_Uv:
return "Uv";
case InlineAsm::Constraint_Uy:
return "Uy";
case InlineAsm::Constraint_X:
return "X";
case InlineAsm::Constraint_Z:
return "Z";
case InlineAsm::Constraint_ZC:
return "ZC";
case InlineAsm::Constraint_Zy:
return "Zy";
case InlineAsm::Constraint_p:
return "p";
case InlineAsm::Constraint_ZQ:
return "ZQ";
case InlineAsm::Constraint_ZR:
return "ZR";
case InlineAsm::Constraint_ZS:
return "ZS";
case InlineAsm::Constraint_ZT:
return "ZT";
default:
llvm_unreachable("Unknown memory constraint");
}
}
};
}
#endif