File indexing completed on 2026-05-10 08:44:01
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015 #ifndef LLVM_IR_INLINEASM_H
0016 #define LLVM_IR_INLINEASM_H
0017
0018 #include "llvm/ADT/Bitfields.h"
0019 #include "llvm/ADT/SmallVector.h"
0020 #include "llvm/ADT/StringRef.h"
0021 #include "llvm/IR/Value.h"
0022 #include "llvm/Support/ErrorHandling.h"
0023 #include <cassert>
0024 #include <string>
0025 #include <vector>
0026
0027 namespace llvm {
0028
0029 class Error;
0030 class FunctionType;
0031 class PointerType;
0032 template <class ConstantClass> class ConstantUniqueMap;
0033
0034 class InlineAsm final : public Value {
0035 public:
0036 enum AsmDialect {
0037 AD_ATT,
0038 AD_Intel
0039 };
0040
0041 private:
0042 friend struct InlineAsmKeyType;
0043 friend class ConstantUniqueMap<InlineAsm>;
0044
0045 std::string AsmString, Constraints;
0046 FunctionType *FTy;
0047 bool HasSideEffects;
0048 bool IsAlignStack;
0049 AsmDialect Dialect;
0050 bool CanThrow;
0051
0052 InlineAsm(FunctionType *Ty, const std::string &AsmString,
0053 const std::string &Constraints, bool hasSideEffects,
0054 bool isAlignStack, AsmDialect asmDialect, bool canThrow);
0055
0056
0057
0058 void destroyConstant();
0059
0060 public:
0061 InlineAsm(const InlineAsm &) = delete;
0062 InlineAsm &operator=(const InlineAsm &) = delete;
0063
0064
0065
0066 static InlineAsm *get(FunctionType *Ty, StringRef AsmString,
0067 StringRef Constraints, bool hasSideEffects,
0068 bool isAlignStack = false,
0069 AsmDialect asmDialect = AD_ATT, bool canThrow = false);
0070
0071 bool hasSideEffects() const { return HasSideEffects; }
0072 bool isAlignStack() const { return IsAlignStack; }
0073 AsmDialect getDialect() const { return Dialect; }
0074 bool canThrow() const { return CanThrow; }
0075
0076
0077
0078 PointerType *getType() const {
0079 return reinterpret_cast<PointerType*>(Value::getType());
0080 }
0081
0082
0083
0084 FunctionType *getFunctionType() const;
0085
0086 const std::string &getAsmString() const { return AsmString; }
0087 const std::string &getConstraintString() const { return Constraints; }
0088 void collectAsmStrs(SmallVectorImpl<StringRef> &AsmStrs) const;
0089
0090
0091
0092 static Error verify(FunctionType *Ty, StringRef Constraints);
0093
0094
0095 enum ConstraintPrefix {
0096 isInput,
0097 isOutput,
0098 isClobber,
0099 isLabel,
0100 };
0101
0102 using ConstraintCodeVector = std::vector<std::string>;
0103
0104 struct SubConstraintInfo {
0105
0106
0107
0108
0109 int MatchingInput = -1;
0110
0111
0112
0113 ConstraintCodeVector Codes;
0114
0115
0116 SubConstraintInfo() = default;
0117 };
0118
0119 using SubConstraintInfoVector = std::vector<SubConstraintInfo>;
0120 struct ConstraintInfo;
0121 using ConstraintInfoVector = std::vector<ConstraintInfo>;
0122
0123 struct ConstraintInfo {
0124
0125
0126 ConstraintPrefix Type = isInput;
0127
0128
0129
0130 bool isEarlyClobber = false;
0131
0132
0133
0134
0135
0136 int MatchingInput = -1;
0137
0138
0139
0140 bool hasMatchingInput() const { return MatchingInput != -1; }
0141
0142
0143
0144 bool isCommutative = false;
0145
0146
0147
0148
0149
0150 bool isIndirect = false;
0151
0152
0153
0154 ConstraintCodeVector Codes;
0155
0156
0157 bool isMultipleAlternative = false;
0158
0159
0160
0161 SubConstraintInfoVector multipleAlternatives;
0162
0163
0164 unsigned currentAlternativeIndex = 0;
0165
0166
0167 ConstraintInfo() = default;
0168
0169
0170
0171
0172 bool Parse(StringRef Str, ConstraintInfoVector &ConstraintsSoFar);
0173
0174
0175
0176 void selectAlternative(unsigned index);
0177
0178
0179 bool hasArg() const {
0180 return Type == isInput || (Type == isOutput && isIndirect);
0181 }
0182 };
0183
0184
0185
0186
0187 static ConstraintInfoVector ParseConstraints(StringRef ConstraintString);
0188
0189
0190
0191 ConstraintInfoVector ParseConstraints() const {
0192 return ParseConstraints(Constraints);
0193 }
0194
0195
0196 static bool classof(const Value *V) {
0197 return V->getValueID() == Value::InlineAsmVal;
0198 }
0199
0200 enum : uint32_t {
0201
0202 Op_InputChain = 0,
0203 Op_AsmString = 1,
0204 Op_MDNode = 2,
0205 Op_ExtraInfo = 3,
0206 Op_FirstOperand = 4,
0207
0208
0209 MIOp_AsmString = 0,
0210 MIOp_ExtraInfo = 1,
0211 MIOp_FirstOperand = 2,
0212
0213
0214 Extra_HasSideEffects = 1,
0215 Extra_IsAlignStack = 2,
0216 Extra_AsmDialect = 4,
0217 Extra_MayLoad = 8,
0218 Extra_MayStore = 16,
0219 Extra_IsConvergent = 32,
0220 };
0221
0222
0223
0224
0225 enum class Kind : uint8_t {
0226 RegUse = 1,
0227 RegDef = 2,
0228 RegDefEarlyClobber = 3,
0229 Clobber = 4,
0230 Imm = 5,
0231 Mem = 6,
0232 Func = 7,
0233 };
0234
0235
0236
0237
0238
0239 enum class ConstraintCode : uint32_t {
0240 Unknown = 0,
0241 es,
0242 i,
0243 k,
0244 m,
0245 o,
0246 v,
0247 A,
0248 Q,
0249 R,
0250 S,
0251 T,
0252 Um,
0253 Un,
0254 Uq,
0255 Us,
0256 Ut,
0257 Uv,
0258 Uy,
0259 X,
0260 Z,
0261 ZB,
0262 ZC,
0263 Zy,
0264
0265
0266 p,
0267 ZQ,
0268 ZR,
0269 ZS,
0270 ZT,
0271
0272 Max = ZT,
0273 };
0274
0275
0276
0277
0278
0279
0280
0281
0282
0283
0284
0285
0286
0287
0288
0289
0290
0291
0292
0293
0294
0295
0296
0297
0298
0299
0300
0301
0302
0303 class Flag {
0304 uint32_t Storage;
0305 using KindField = Bitfield::Element<Kind, 0, 3, Kind::Func>;
0306 using NumOperands = Bitfield::Element<unsigned, 3, 13>;
0307 using MatchedOperandNo = Bitfield::Element<unsigned, 16, 15>;
0308 using MemConstraintCode = Bitfield::Element<ConstraintCode, 16, 15, ConstraintCode::Max>;
0309 using RegClass = Bitfield::Element<unsigned, 16, 14>;
0310 using RegMayBeFolded = Bitfield::Element<bool, 30, 1>;
0311 using IsMatched = Bitfield::Element<bool, 31, 1>;
0312
0313
0314 unsigned getMatchedOperandNo() const { return Bitfield::get<MatchedOperandNo>(Storage); }
0315 unsigned getRegClass() const { return Bitfield::get<RegClass>(Storage); }
0316 bool isMatched() const { return Bitfield::get<IsMatched>(Storage); }
0317
0318 public:
0319 Flag() : Storage(0) {}
0320 explicit Flag(uint32_t F) : Storage(F) {}
0321 Flag(enum Kind K, unsigned NumOps) : Storage(0) {
0322 Bitfield::set<KindField>(Storage, K);
0323 Bitfield::set<NumOperands>(Storage, NumOps);
0324 }
0325 operator uint32_t() { return Storage; }
0326 Kind getKind() const { return Bitfield::get<KindField>(Storage); }
0327 bool isRegUseKind() const { return getKind() == Kind::RegUse; }
0328 bool isRegDefKind() const { return getKind() == Kind::RegDef; }
0329 bool isRegDefEarlyClobberKind() const {
0330 return getKind() == Kind::RegDefEarlyClobber;
0331 }
0332 bool isClobberKind() const { return getKind() == Kind::Clobber; }
0333 bool isImmKind() const { return getKind() == Kind::Imm; }
0334 bool isMemKind() const { return getKind() == Kind::Mem; }
0335 bool isFuncKind() const { return getKind() == Kind::Func; }
0336 StringRef getKindName() const {
0337 switch (getKind()) {
0338 case Kind::RegUse:
0339 return "reguse";
0340 case Kind::RegDef:
0341 return "regdef";
0342 case Kind::RegDefEarlyClobber:
0343 return "regdef-ec";
0344 case Kind::Clobber:
0345 return "clobber";
0346 case Kind::Imm:
0347 return "imm";
0348 case Kind::Mem:
0349 case Kind::Func:
0350 return "mem";
0351 }
0352 llvm_unreachable("impossible kind");
0353 }
0354
0355
0356
0357 unsigned getNumOperandRegisters() const {
0358 return Bitfield::get<NumOperands>(Storage);
0359 }
0360
0361
0362
0363 bool isUseOperandTiedToDef(unsigned &Idx) const {
0364 if (!isMatched())
0365 return false;
0366 Idx = getMatchedOperandNo();
0367 return true;
0368 }
0369
0370
0371
0372 bool hasRegClassConstraint(unsigned &RC) const {
0373 if (isMatched())
0374 return false;
0375
0376
0377 if (!getRegClass())
0378 return false;
0379 RC = getRegClass() - 1;
0380 return true;
0381 }
0382
0383 ConstraintCode getMemoryConstraintID() const {
0384 assert((isMemKind() || isFuncKind()) &&
0385 "Not expected mem or function flag!");
0386 return Bitfield::get<MemConstraintCode>(Storage);
0387 }
0388
0389
0390
0391 void setMatchingOp(unsigned OperandNo) {
0392 assert(getMatchedOperandNo() == 0 && "Matching operand already set");
0393 Bitfield::set<MatchedOperandNo>(Storage, OperandNo);
0394 Bitfield::set<IsMatched>(Storage, true);
0395 }
0396
0397
0398
0399
0400 void setRegClass(unsigned RC) {
0401 assert(!isImmKind() && "Immediates cannot have a register class");
0402 assert(!isMemKind() && "Memory operand cannot have a register class");
0403 assert(getRegClass() == 0 && "Register class already set");
0404
0405 Bitfield::set<RegClass>(Storage, RC + 1);
0406 }
0407
0408
0409
0410 void setMemConstraint(ConstraintCode C) {
0411 assert(getMemoryConstraintID() == ConstraintCode::Unknown && "Mem constraint already set");
0412 Bitfield::set<MemConstraintCode>(Storage, C);
0413 }
0414
0415
0416 void clearMemConstraint() {
0417 assert((isMemKind() || isFuncKind()) &&
0418 "Flag is not a memory or function constraint!");
0419 Bitfield::set<MemConstraintCode>(Storage, ConstraintCode::Unknown);
0420 }
0421
0422
0423
0424
0425
0426
0427
0428
0429
0430
0431 void setRegMayBeFolded(bool B) {
0432 assert((isRegDefKind() || isRegDefEarlyClobberKind() || isRegUseKind()) &&
0433 "Must be reg");
0434 Bitfield::set<RegMayBeFolded>(Storage, B);
0435 }
0436 bool getRegMayBeFolded() const {
0437 assert((isRegDefKind() || isRegDefEarlyClobberKind() || isRegUseKind()) &&
0438 "Must be reg");
0439 return Bitfield::get<RegMayBeFolded>(Storage);
0440 }
0441 };
0442
0443 static std::vector<StringRef> getExtraInfoNames(unsigned ExtraInfo) {
0444 std::vector<StringRef> Result;
0445 if (ExtraInfo & InlineAsm::Extra_HasSideEffects)
0446 Result.push_back("sideeffect");
0447 if (ExtraInfo & InlineAsm::Extra_MayLoad)
0448 Result.push_back("mayload");
0449 if (ExtraInfo & InlineAsm::Extra_MayStore)
0450 Result.push_back("maystore");
0451 if (ExtraInfo & InlineAsm::Extra_IsConvergent)
0452 Result.push_back("isconvergent");
0453 if (ExtraInfo & InlineAsm::Extra_IsAlignStack)
0454 Result.push_back("alignstack");
0455
0456 AsmDialect Dialect =
0457 InlineAsm::AsmDialect((ExtraInfo & InlineAsm::Extra_AsmDialect));
0458
0459 if (Dialect == InlineAsm::AD_ATT)
0460 Result.push_back("attdialect");
0461 if (Dialect == InlineAsm::AD_Intel)
0462 Result.push_back("inteldialect");
0463
0464 return Result;
0465 }
0466
0467 static StringRef getMemConstraintName(ConstraintCode C) {
0468 switch (C) {
0469 case ConstraintCode::es:
0470 return "es";
0471 case ConstraintCode::i:
0472 return "i";
0473 case ConstraintCode::k:
0474 return "k";
0475 case ConstraintCode::m:
0476 return "m";
0477 case ConstraintCode::o:
0478 return "o";
0479 case ConstraintCode::v:
0480 return "v";
0481 case ConstraintCode::A:
0482 return "A";
0483 case ConstraintCode::Q:
0484 return "Q";
0485 case ConstraintCode::R:
0486 return "R";
0487 case ConstraintCode::S:
0488 return "S";
0489 case ConstraintCode::T:
0490 return "T";
0491 case ConstraintCode::Um:
0492 return "Um";
0493 case ConstraintCode::Un:
0494 return "Un";
0495 case ConstraintCode::Uq:
0496 return "Uq";
0497 case ConstraintCode::Us:
0498 return "Us";
0499 case ConstraintCode::Ut:
0500 return "Ut";
0501 case ConstraintCode::Uv:
0502 return "Uv";
0503 case ConstraintCode::Uy:
0504 return "Uy";
0505 case ConstraintCode::X:
0506 return "X";
0507 case ConstraintCode::Z:
0508 return "Z";
0509 case ConstraintCode::ZB:
0510 return "ZB";
0511 case ConstraintCode::ZC:
0512 return "ZC";
0513 case ConstraintCode::Zy:
0514 return "Zy";
0515 case ConstraintCode::p:
0516 return "p";
0517 case ConstraintCode::ZQ:
0518 return "ZQ";
0519 case ConstraintCode::ZR:
0520 return "ZR";
0521 case ConstraintCode::ZS:
0522 return "ZS";
0523 case ConstraintCode::ZT:
0524 return "ZT";
0525 default:
0526 llvm_unreachable("Unknown memory constraint");
0527 }
0528 }
0529 };
0530
0531 }
0532
0533 #endif