1//===- InlineAsm.cpp - Implement the InlineAsm class ----------------------===//
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 file implements the InlineAsm class.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/IR/InlineAsm.h"
14#include "ConstantsContext.h"
15#include "LLVMContextImpl.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/IR/DerivedTypes.h"
18#include "llvm/IR/LLVMContext.h"
19#include "llvm/IR/Value.h"
20#include "llvm/Support/Casting.h"
21#include "llvm/Support/Compiler.h"
22#include <algorithm>
23#include <cassert>
24#include <cctype>
25#include <cstddef>
26#include <cstdlib>
27
28using namespace llvm;
29
30InlineAsm::InlineAsm(FunctionType *FTy, const std::string &asmString,
31                     const std::string &constraints, bool hasSideEffects,
32                     bool isAlignStack, AsmDialect asmDialect)
33    : Value(PointerType::getUnqual(FTy), Value::InlineAsmVal),
34      AsmString(asmString), Constraints(constraints), FTy(FTy),
35      HasSideEffects(hasSideEffects), IsAlignStack(isAlignStack),
36      Dialect(asmDialect) {
37  // Do various checks on the constraint string and type.
38  assert(Verify(getFunctionType(), constraints) &&
39         "Function type not legal for constraints!");
40}
41
42InlineAsm *InlineAsm::get(FunctionType *FTy, StringRef AsmString,
43                          StringRef Constraints, bool hasSideEffects,
44                          bool isAlignStack, AsmDialect asmDialect) {
45  InlineAsmKeyType Key(AsmString, Constraints, FTy, hasSideEffects,
46                       isAlignStack, asmDialect);
47  LLVMContextImpl *pImpl = FTy->getContext().pImpl;
48  return pImpl->InlineAsms.getOrCreate(PointerType::getUnqual(FTy), Key);
49}
50
51void InlineAsm::destroyConstant() {
52  getType()->getContext().pImpl->InlineAsms.remove(this);
53  delete this;
54}
55
56FunctionType *InlineAsm::getFunctionType() const {
57  return FTy;
58}
59
60/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the
61/// fields in this structure.  If the constraint string is not understood,
62/// return true, otherwise return false.
63bool InlineAsm::ConstraintInfo::Parse(StringRef Str,
64                     InlineAsm::ConstraintInfoVector &ConstraintsSoFar) {
65  StringRef::iterator I = Str.begin(), E = Str.end();
66  unsigned multipleAlternativeCount = Str.count('|') + 1;
67  unsigned multipleAlternativeIndex = 0;
68  ConstraintCodeVector *pCodes = &Codes;
69
70  // Initialize
71  isMultipleAlternative = multipleAlternativeCount > 1;
72  if (isMultipleAlternative) {
73    multipleAlternatives.resize(multipleAlternativeCount);
74    pCodes = &multipleAlternatives[0].Codes;
75  }
76  Type = isInput;
77  isEarlyClobber = false;
78  MatchingInput = -1;
79  isCommutative = false;
80  isIndirect = false;
81  currentAlternativeIndex = 0;
82
83  // Parse prefixes.
84  if (*I == '~') {
85    Type = isClobber;
86    ++I;
87
88    // '{' must immediately follow '~'.
89    if (I != E && *I != '{')
90      return true;
91  } else if (*I == '=') {
92    ++I;
93    Type = isOutput;
94  }
95
96  if (*I == '*') {
97    isIndirect = true;
98    ++I;
99  }
100
101  if (I == E) return true;  // Just a prefix, like "==" or "~".
102
103  // Parse the modifiers.
104  bool DoneWithModifiers = false;
105  while (!DoneWithModifiers) {
106    switch (*I) {
107    default:
108      DoneWithModifiers = true;
109      break;
110    case '&':     // Early clobber.
111      if (Type != isOutput ||      // Cannot early clobber anything but output.
112          isEarlyClobber)          // Reject &&&&&&
113        return true;
114      isEarlyClobber = true;
115      break;
116    case '%':     // Commutative.
117      if (Type == isClobber ||     // Cannot commute clobbers.
118          isCommutative)           // Reject %%%%%
119        return true;
120      isCommutative = true;
121      break;
122    case '#':     // Comment.
123    case '*':     // Register preferencing.
124      return true;     // Not supported.
125    }
126
127    if (!DoneWithModifiers) {
128      ++I;
129      if (I == E) return true;   // Just prefixes and modifiers!
130    }
131  }
132
133  // Parse the various constraints.
134  while (I != E) {
135    if (*I == '{') {   // Physical register reference.
136      // Find the end of the register name.
137      StringRef::iterator ConstraintEnd = std::find(I+1, E, '}');
138      if (ConstraintEnd == E) return true;  // "{foo"
139      pCodes->push_back(std::string(StringRef(I, ConstraintEnd + 1 - I)));
140      I = ConstraintEnd+1;
141    } else if (isdigit(static_cast<unsigned char>(*I))) { // Matching Constraint
142      // Maximal munch numbers.
143      StringRef::iterator NumStart = I;
144      while (I != E && isdigit(static_cast<unsigned char>(*I)))
145        ++I;
146      pCodes->push_back(std::string(StringRef(NumStart, I - NumStart)));
147      unsigned N = atoi(pCodes->back().c_str());
148      // Check that this is a valid matching constraint!
149      if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput||
150          Type != isInput)
151        return true;  // Invalid constraint number.
152
153      // If Operand N already has a matching input, reject this.  An output
154      // can't be constrained to the same value as multiple inputs.
155      if (isMultipleAlternative) {
156        if (multipleAlternativeIndex >=
157            ConstraintsSoFar[N].multipleAlternatives.size())
158          return true;
159        InlineAsm::SubConstraintInfo &scInfo =
160          ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex];
161        if (scInfo.MatchingInput != -1)
162          return true;
163        // Note that operand #n has a matching input.
164        scInfo.MatchingInput = ConstraintsSoFar.size();
165        assert(scInfo.MatchingInput >= 0);
166      } else {
167        if (ConstraintsSoFar[N].hasMatchingInput() &&
168            (size_t)ConstraintsSoFar[N].MatchingInput !=
169                ConstraintsSoFar.size())
170          return true;
171        // Note that operand #n has a matching input.
172        ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size();
173        assert(ConstraintsSoFar[N].MatchingInput >= 0);
174        }
175    } else if (*I == '|') {
176      multipleAlternativeIndex++;
177      pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes;
178      ++I;
179    } else if (*I == '^') {
180      // Multi-letter constraint
181      // FIXME: For now assuming these are 2-character constraints.
182      pCodes->push_back(std::string(StringRef(I + 1, 2)));
183      I += 3;
184    } else if (*I == '@') {
185      // Multi-letter constraint
186      ++I;
187      unsigned char C = static_cast<unsigned char>(*I);
188      assert(isdigit(C) && "Expected a digit!");
189      int N = C - '0';
190      assert(N > 0 && "Found a zero letter constraint!");
191      ++I;
192      pCodes->push_back(std::string(StringRef(I, N)));
193      I += N;
194    } else {
195      // Single letter constraint.
196      pCodes->push_back(std::string(StringRef(I, 1)));
197      ++I;
198    }
199  }
200
201  return false;
202}
203
204/// selectAlternative - Point this constraint to the alternative constraint
205/// indicated by the index.
206void InlineAsm::ConstraintInfo::selectAlternative(unsigned index) {
207  if (index < multipleAlternatives.size()) {
208    currentAlternativeIndex = index;
209    InlineAsm::SubConstraintInfo &scInfo =
210      multipleAlternatives[currentAlternativeIndex];
211    MatchingInput = scInfo.MatchingInput;
212    Codes = scInfo.Codes;
213  }
214}
215
216InlineAsm::ConstraintInfoVector
217InlineAsm::ParseConstraints(StringRef Constraints) {
218  ConstraintInfoVector Result;
219
220  // Scan the constraints string.
221  for (StringRef::iterator I = Constraints.begin(),
222         E = Constraints.end(); I != E; ) {
223    ConstraintInfo Info;
224
225    // Find the end of this constraint.
226    StringRef::iterator ConstraintEnd = std::find(I, E, ',');
227
228    if (ConstraintEnd == I ||  // Empty constraint like ",,"
229        Info.Parse(StringRef(I, ConstraintEnd-I), Result)) {
230      Result.clear();          // Erroneous constraint?
231      break;
232    }
233
234    Result.push_back(Info);
235
236    // ConstraintEnd may be either the next comma or the end of the string.  In
237    // the former case, we skip the comma.
238    I = ConstraintEnd;
239    if (I != E) {
240      ++I;
241      if (I == E) {
242        Result.clear();
243        break;
244      } // don't allow "xyz,"
245    }
246  }
247
248  return Result;
249}
250
251/// Verify - Verify that the specified constraint string is reasonable for the
252/// specified function type, and otherwise validate the constraint string.
253bool InlineAsm::Verify(FunctionType *Ty, StringRef ConstStr) {
254  if (Ty->isVarArg()) return false;
255
256  ConstraintInfoVector Constraints = ParseConstraints(ConstStr);
257
258  // Error parsing constraints.
259  if (Constraints.empty() && !ConstStr.empty()) return false;
260
261  unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;
262  unsigned NumIndirect = 0;
263
264  for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
265    switch (Constraints[i].Type) {
266    case InlineAsm::isOutput:
267      if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0)
268        return false;  // outputs before inputs and clobbers.
269      if (!Constraints[i].isIndirect) {
270        ++NumOutputs;
271        break;
272      }
273      ++NumIndirect;
274      LLVM_FALLTHROUGH; // We fall through for Indirect Outputs.
275    case InlineAsm::isInput:
276      if (NumClobbers) return false;               // inputs before clobbers.
277      ++NumInputs;
278      break;
279    case InlineAsm::isClobber:
280      ++NumClobbers;
281      break;
282    }
283  }
284
285  switch (NumOutputs) {
286  case 0:
287    if (!Ty->getReturnType()->isVoidTy()) return false;
288    break;
289  case 1:
290    if (Ty->getReturnType()->isStructTy()) return false;
291    break;
292  default:
293    StructType *STy = dyn_cast<StructType>(Ty->getReturnType());
294    if (!STy || STy->getNumElements() != NumOutputs)
295      return false;
296    break;
297  }
298
299  if (Ty->getNumParams() != NumInputs) return false;
300  return true;
301}
302