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