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/StringRef.h" |

19 | #include "llvm/IR/Value.h" |

20 | #include "llvm/Support/ErrorHandling.h" |

21 | #include <cassert> |

22 | #include <string> |

23 | #include <vector> |

24 | |

25 | namespace llvm { |

26 | |

27 | class FunctionType; |

28 | class PointerType; |

29 | template <class ConstantClass> class ConstantUniqueMap; |

30 | |

31 | class InlineAsm final : public Value { |

32 | public: |

33 | enum AsmDialect { |

34 | AD_ATT, |

35 | AD_Intel |

36 | }; |

37 | |

38 | private: |

39 | friend struct InlineAsmKeyType; |

40 | friend class ConstantUniqueMap<InlineAsm>; |

41 | |

42 | std::string AsmString, Constraints; |

43 | FunctionType *FTy; |

44 | bool HasSideEffects; |

45 | bool IsAlignStack; |

46 | AsmDialect Dialect; |

47 | |

48 | InlineAsm(FunctionType *Ty, const std::string &AsmString, |

49 | const std::string &Constraints, bool hasSideEffects, |

50 | bool isAlignStack, AsmDialect asmDialect); |

51 | |

52 | /// When the ConstantUniqueMap merges two types and makes two InlineAsms |

53 | /// identical, it destroys one of them with this method. |

54 | void destroyConstant(); |

55 | |

56 | public: |

57 | InlineAsm(const InlineAsm &) = delete; |

58 | InlineAsm &operator=(const InlineAsm &) = delete; |

59 | |

60 | /// InlineAsm::get - Return the specified uniqued inline asm string. |

61 | /// |

62 | static InlineAsm *get(FunctionType *Ty, StringRef AsmString, |

63 | StringRef Constraints, bool hasSideEffects, |

64 | bool isAlignStack = false, |

65 | AsmDialect asmDialect = AD_ATT); |

66 | |

67 | bool hasSideEffects() const { return HasSideEffects; } |

68 | bool isAlignStack() const { return IsAlignStack; } |

69 | AsmDialect getDialect() const { return Dialect; } |

70 | |

71 | /// getType - InlineAsm's are always pointers. |

72 | /// |

73 | PointerType *getType() const { |

74 | return reinterpret_cast<PointerType*>(Value::getType()); |

75 | } |

76 | |

77 | /// getFunctionType - InlineAsm's are always pointers to functions. |

78 | /// |

79 | FunctionType *getFunctionType() const; |

80 | |

81 | const std::string &getAsmString() const { return AsmString; } |

82 | const std::string &getConstraintString() const { return Constraints; } |

83 | |

84 | /// Verify - This static method can be used by the parser to check to see if |

85 | /// the specified constraint string is legal for the type. This returns true |

86 | /// if legal, false if not. |

87 | /// |

88 | static bool Verify(FunctionType *Ty, StringRef Constraints); |

89 | |

90 | // Constraint String Parsing |

91 | enum ConstraintPrefix { |

92 | isInput, // 'x' |

93 | isOutput, // '=x' |

94 | isClobber // '~x' |

95 | }; |

96 | |

97 | using ConstraintCodeVector = std::vector<std::string>; |

98 | |

99 | struct SubConstraintInfo { |

100 | /// MatchingInput - If this is not -1, this is an output constraint where an |

101 | /// input constraint is required to match it (e.g. "0"). The value is the |

102 | /// constraint number that matches this one (for example, if this is |

103 | /// constraint #0 and constraint #4 has the value "0", this will be 4). |

104 | int MatchingInput = -1; |

105 | |

106 | /// Code - The constraint code, either the register name (in braces) or the |

107 | /// constraint letter/number. |

108 | ConstraintCodeVector Codes; |

109 | |

110 | /// Default constructor. |

111 | SubConstraintInfo() = default; |

112 | }; |

113 | |

114 | using SubConstraintInfoVector = std::vector<SubConstraintInfo>; |

115 | struct ConstraintInfo; |

116 | using ConstraintInfoVector = std::vector<ConstraintInfo>; |

117 | |

118 | struct ConstraintInfo { |

119 | /// Type - The basic type of the constraint: input/output/clobber |

120 | /// |

121 | ConstraintPrefix Type = isInput; |

122 | |

123 | /// isEarlyClobber - "&": output operand writes result before inputs are all |

124 | /// read. This is only ever set for an output operand. |

125 | bool isEarlyClobber = false; |

126 | |

127 | /// MatchingInput - If this is not -1, this is an output constraint where an |

128 | /// input constraint is required to match it (e.g. "0"). The value is the |

129 | /// constraint number that matches this one (for example, if this is |

130 | /// constraint #0 and constraint #4 has the value "0", this will be 4). |

131 | int MatchingInput = -1; |

132 | |

133 | /// hasMatchingInput - Return true if this is an output constraint that has |

134 | /// a matching input constraint. |

135 | bool hasMatchingInput() const { return MatchingInput != -1; } |

136 | |

137 | /// isCommutative - This is set to true for a constraint that is commutative |

138 | /// with the next operand. |

139 | bool isCommutative = false; |

140 | |

141 | /// isIndirect - True if this operand is an indirect operand. This means |

142 | /// that the address of the source or destination is present in the call |

143 | /// instruction, instead of it being returned or passed in explicitly. This |

144 | /// is represented with a '*' in the asm string. |

145 | bool isIndirect = false; |

146 | |

147 | /// Code - The constraint code, either the register name (in braces) or the |

148 | /// constraint letter/number. |

149 | ConstraintCodeVector Codes; |

150 | |

151 | /// isMultipleAlternative - '|': has multiple-alternative constraints. |

152 | bool isMultipleAlternative = false; |

153 | |

154 | /// multipleAlternatives - If there are multiple alternative constraints, |

155 | /// this array will contain them. Otherwise it will be empty. |

156 | SubConstraintInfoVector multipleAlternatives; |

157 | |

158 | /// The currently selected alternative constraint index. |

159 | unsigned currentAlternativeIndex = 0; |

160 | |

161 | /// Default constructor. |

162 | ConstraintInfo() = default; |

163 | |

164 | /// Parse - Analyze the specified string (e.g. "=*&{eax}") and fill in the |

165 | /// fields in this structure. If the constraint string is not understood, |

166 | /// return true, otherwise return false. |

167 | bool Parse(StringRef Str, ConstraintInfoVector &ConstraintsSoFar); |

168 | |

169 | /// selectAlternative - Point this constraint to the alternative constraint |

170 | /// indicated by the index. |

171 | void selectAlternative(unsigned index); |

172 | }; |

173 | |

174 | /// ParseConstraints - Split up the constraint string into the specific |

175 | /// constraints and their prefixes. If this returns an empty vector, and if |

176 | /// the constraint string itself isn't empty, there was an error parsing. |

177 | static ConstraintInfoVector ParseConstraints(StringRef ConstraintString); |

178 | |

179 | /// ParseConstraints - Parse the constraints of this inlineasm object, |

180 | /// returning them the same way that ParseConstraints(str) does. |

181 | ConstraintInfoVector ParseConstraints() const { |

182 | return ParseConstraints(Constraints); |

183 | } |

184 | |

185 | // Methods for support type inquiry through isa, cast, and dyn_cast: |

186 | static bool classof(const Value *V) { |

187 | return V->getValueID() == Value::InlineAsmVal; |

188 | } |

189 | |

190 | // These are helper methods for dealing with flags in the INLINEASM SDNode |

191 | // in the backend. |

192 | // |

193 | // The encoding of the flag word is currently: |

194 | // Bits 2-0 - A Kind_* value indicating the kind of the operand. |

195 | // Bits 15-3 - The number of SDNode operands associated with this inline |

196 | // assembly operand. |

197 | // If bit 31 is set: |

198 | // Bit 30-16 - The operand number that this operand must match. |

199 | // When bits 2-0 are Kind_Mem, the Constraint_* value must be |

200 | // obtained from the flags for this operand number. |

201 | // Else if bits 2-0 are Kind_Mem: |

202 | // Bit 30-16 - A Constraint_* value indicating the original constraint |

203 | // code. |

204 | // Else: |

205 | // Bit 30-16 - The register class ID to use for the operand. |

206 | |

207 | enum : uint32_t { |

208 | // Fixed operands on an INLINEASM SDNode. |

209 | Op_InputChain = 0, |

210 | Op_AsmString = 1, |

211 | Op_MDNode = 2, |

212 | Op_ExtraInfo = 3, // HasSideEffects, IsAlignStack, AsmDialect. |

213 | Op_FirstOperand = 4, |

214 | |

215 | // Fixed operands on an INLINEASM MachineInstr. |

216 | MIOp_AsmString = 0, |

217 | MIOp_ExtraInfo = 1, // HasSideEffects, IsAlignStack, AsmDialect. |

218 | MIOp_FirstOperand = 2, |

219 | |

220 | // Interpretation of the MIOp_ExtraInfo bit field. |

221 | Extra_HasSideEffects = 1, |

222 | Extra_IsAlignStack = 2, |

223 | Extra_AsmDialect = 4, |

224 | Extra_MayLoad = 8, |

225 | Extra_MayStore = 16, |

226 | Extra_IsConvergent = 32, |

227 | |

228 | // Inline asm operands map to multiple SDNode / MachineInstr operands. |

229 | // The first operand is an immediate describing the asm operand, the low |

230 | // bits is the kind: |

231 | Kind_RegUse = 1, // Input register, "r". |

232 | Kind_RegDef = 2, // Output register, "=r". |

233 | Kind_RegDefEarlyClobber = 3, // Early-clobber output register, "=&r". |

234 | Kind_Clobber = 4, // Clobbered register, "~r". |

235 | Kind_Imm = 5, // Immediate. |

236 | Kind_Mem = 6, // Memory operand, "m". |

237 | |

238 | // Memory constraint codes. |

239 | // These could be tablegenerated but there's little need to do that since |

240 | // there's plenty of space in the encoding to support the union of all |

241 | // constraint codes for all targets. |

242 | Constraint_Unknown = 0, |

243 | Constraint_es, |

244 | Constraint_i, |

245 | Constraint_m, |

246 | Constraint_o, |

247 | Constraint_v, |

248 | Constraint_A, |

249 | Constraint_Q, |

250 | Constraint_R, |

251 | Constraint_S, |

252 | Constraint_T, |

253 | Constraint_Um, |

254 | Constraint_Un, |

255 | Constraint_Uq, |

256 | Constraint_Us, |

257 | Constraint_Ut, |

258 | Constraint_Uv, |

259 | Constraint_Uy, |

260 | Constraint_X, |

261 | Constraint_Z, |

262 | Constraint_ZC, |

263 | Constraint_Zy, |

264 | Constraints_Max = Constraint_Zy, |

265 | Constraints_ShiftAmount = 16, |

266 | |

267 | Flag_MatchingOperand = 0x80000000 |

268 | }; |

269 | |

270 | static unsigned getFlagWord(unsigned Kind, unsigned NumOps) { |

271 | assert(((NumOps << 3) & ~0xffff) == 0 && "Too many inline asm operands!"); |

272 | assert(Kind >= Kind_RegUse && Kind <= Kind_Mem && "Invalid Kind"); |

273 | return Kind | (NumOps << 3); |

274 | } |

275 | |

276 | static bool isRegDefKind(unsigned Flag){ return getKind(Flag) == Kind_RegDef;} |

277 | static bool isImmKind(unsigned Flag) { return getKind(Flag) == Kind_Imm; } |

278 | static bool isMemKind(unsigned Flag) { return getKind(Flag) == Kind_Mem; } |

279 | static bool isRegDefEarlyClobberKind(unsigned Flag) { |

280 | return getKind(Flag) == Kind_RegDefEarlyClobber; |

281 | } |

282 | static bool isClobberKind(unsigned Flag) { |

283 | return getKind(Flag) == Kind_Clobber; |

284 | } |

285 | |

286 | /// getFlagWordForMatchingOp - Augment an existing flag word returned by |

287 | /// getFlagWord with information indicating that this input operand is tied |

288 | /// to a previous output operand. |

289 | static unsigned getFlagWordForMatchingOp(unsigned InputFlag, |

290 | unsigned MatchedOperandNo) { |

291 | assert(MatchedOperandNo <= 0x7fff && "Too big matched operand"); |

292 | assert((InputFlag & ~0xffff) == 0 && "High bits already contain data"); |

293 | return InputFlag | Flag_MatchingOperand | (MatchedOperandNo << 16); |

294 | } |

295 | |

296 | /// getFlagWordForRegClass - Augment an existing flag word returned by |

297 | /// getFlagWord with the required register class for the following register |

298 | /// operands. |

299 | /// A tied use operand cannot have a register class, use the register class |

300 | /// from the def operand instead. |

301 | static unsigned getFlagWordForRegClass(unsigned InputFlag, unsigned RC) { |

302 | // Store RC + 1, reserve the value 0 to mean 'no register class'. |

303 | ++RC; |

304 | assert(!isImmKind(InputFlag) && "Immediates cannot have a register class"); |

305 | assert(!isMemKind(InputFlag) && "Memory operand cannot have a register class"); |

306 | assert(RC <= 0x7fff && "Too large register class ID"); |

307 | assert((InputFlag & ~0xffff) == 0 && "High bits already contain data"); |

308 | return InputFlag | (RC << 16); |

309 | } |

310 | |

311 | /// Augment an existing flag word returned by getFlagWord with the constraint |

312 | /// code for a memory constraint. |

313 | static unsigned getFlagWordForMem(unsigned InputFlag, unsigned Constraint) { |

314 | assert(isMemKind(InputFlag) && "InputFlag is not a memory constraint!"); |

315 | assert(Constraint <= 0x7fff && "Too large a memory constraint ID"); |

316 | assert(Constraint <= Constraints_Max && "Unknown constraint ID"); |

317 | assert((InputFlag & ~0xffff) == 0 && "High bits already contain data"); |

318 | return InputFlag | (Constraint << Constraints_ShiftAmount); |

319 | } |

320 | |

321 | static unsigned convertMemFlagWordToMatchingFlagWord(unsigned InputFlag) { |

322 | assert(isMemKind(InputFlag)); |

323 | return InputFlag & ~(0x7fff << Constraints_ShiftAmount); |

324 | } |

325 | |

326 | static unsigned getKind(unsigned Flags) { |

327 | return Flags & 7; |

328 | } |

329 | |

330 | static unsigned getMemoryConstraintID(unsigned Flag) { |

331 | assert(isMemKind(Flag)); |

332 | return (Flag >> Constraints_ShiftAmount) & 0x7fff; |

333 | } |

334 | |

335 | /// getNumOperandRegisters - Extract the number of registers field from the |

336 | /// inline asm operand flag. |

337 | static unsigned getNumOperandRegisters(unsigned Flag) { |

338 | return (Flag & 0xffff) >> 3; |

339 | } |

340 | |

341 | /// isUseOperandTiedToDef - Return true if the flag of the inline asm |

342 | /// operand indicates it is an use operand that's matched to a def operand. |

343 | static bool isUseOperandTiedToDef(unsigned Flag, unsigned &Idx) { |

344 | if ((Flag & Flag_MatchingOperand) == 0) |

345 | return false; |

346 | Idx = (Flag & ~Flag_MatchingOperand) >> 16; |

347 | return true; |

348 | } |

349 | |

350 | /// hasRegClassConstraint - Returns true if the flag contains a register |

351 | /// class constraint. Sets RC to the register class ID. |

352 | static bool hasRegClassConstraint(unsigned Flag, unsigned &RC) { |

353 | if (Flag & Flag_MatchingOperand) |

354 | return false; |

355 | unsigned High = Flag >> 16; |

356 | // getFlagWordForRegClass() uses 0 to mean no register class, and otherwise |

357 | // stores RC + 1. |

358 | if (!High) |

359 | return false; |

360 | RC = High - 1; |

361 | return true; |

362 | } |

363 | |

364 | static std::vector<StringRef> getExtraInfoNames(unsigned ExtraInfo) { |

365 | std::vector<StringRef> Result; |

366 | if (ExtraInfo & InlineAsm::Extra_HasSideEffects) |

367 | Result.push_back("sideeffect"); |

368 | if (ExtraInfo & InlineAsm::Extra_MayLoad) |

369 | Result.push_back("mayload"); |

370 | if (ExtraInfo & InlineAsm::Extra_MayStore) |

371 | Result.push_back("maystore"); |

372 | if (ExtraInfo & InlineAsm::Extra_IsConvergent) |

373 | Result.push_back("isconvergent"); |

374 | if (ExtraInfo & InlineAsm::Extra_IsAlignStack) |

375 | Result.push_back("alignstack"); |

376 | |

377 | AsmDialect Dialect = |

378 | InlineAsm::AsmDialect((ExtraInfo & InlineAsm::Extra_AsmDialect)); |

379 | |

380 | if (Dialect == InlineAsm::AD_ATT) |

381 | Result.push_back("attdialect"); |

382 | if (Dialect == InlineAsm::AD_Intel) |

383 | Result.push_back("inteldialect"); |

384 | |

385 | return Result; |

386 | } |

387 | |

388 | static StringRef getKindName(unsigned Kind) { |

389 | switch (Kind) { |

390 | case InlineAsm::Kind_RegUse: |

391 | return "reguse"; |

392 | case InlineAsm::Kind_RegDef: |

393 | return "regdef"; |

394 | case InlineAsm::Kind_RegDefEarlyClobber: |

395 | return "regdef-ec"; |

396 | case InlineAsm::Kind_Clobber: |

397 | return "clobber"; |

398 | case InlineAsm::Kind_Imm: |

399 | return "imm"; |

400 | case InlineAsm::Kind_Mem: |

401 | return "mem"; |

402 | default: |

403 | llvm_unreachable("Unknown operand kind"); |

404 | } |

405 | } |

406 | |

407 | static StringRef getMemConstraintName(unsigned Constraint) { |

408 | switch (Constraint) { |

409 | case InlineAsm::Constraint_es: |

410 | return "es"; |

411 | case InlineAsm::Constraint_i: |

412 | return "i"; |

413 | case InlineAsm::Constraint_m: |

414 | return "m"; |

415 | case InlineAsm::Constraint_o: |

416 | return "o"; |

417 | case InlineAsm::Constraint_v: |

418 | return "v"; |

419 | case InlineAsm::Constraint_Q: |

420 | return "Q"; |

421 | case InlineAsm::Constraint_R: |

422 | return "R"; |

423 | case InlineAsm::Constraint_S: |

424 | return "S"; |

425 | case InlineAsm::Constraint_T: |

426 | return "T"; |

427 | case InlineAsm::Constraint_Um: |

428 | return "Um"; |

429 | case InlineAsm::Constraint_Un: |

430 | return "Un"; |

431 | case InlineAsm::Constraint_Uq: |

432 | return "Uq"; |

433 | case InlineAsm::Constraint_Us: |

434 | return "Us"; |

435 | case InlineAsm::Constraint_Ut: |

436 | return "Ut"; |

437 | case InlineAsm::Constraint_Uv: |

438 | return "Uv"; |

439 | case InlineAsm::Constraint_Uy: |

440 | return "Uy"; |

441 | case InlineAsm::Constraint_X: |

442 | return "X"; |

443 | case InlineAsm::Constraint_Z: |

444 | return "Z"; |

445 | case InlineAsm::Constraint_ZC: |

446 | return "ZC"; |

447 | case InlineAsm::Constraint_Zy: |

448 | return "Zy"; |

449 | default: |

450 | llvm_unreachable("Unknown memory constraint"); |

451 | } |

452 | } |

453 | }; |

454 | |

455 | } // end namespace llvm |

456 | |

457 | #endif // LLVM_IR_INLINEASM_H |

458 |