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 | = 3, // HasSideEffects, IsAlignStack, AsmDialect. |
213 | Op_FirstOperand = 4, |
214 | |
215 | // Fixed operands on an INLINEASM MachineInstr. |
216 | MIOp_AsmString = 0, |
217 | = 1, // HasSideEffects, IsAlignStack, AsmDialect. |
218 | MIOp_FirstOperand = 2, |
219 | |
220 | // Interpretation of the MIOp_ExtraInfo bit field. |
221 | = 1, |
222 | = 2, |
223 | = 4, |
224 | = 8, |
225 | = 16, |
226 | = 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> (unsigned ) { |
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 | |