1249259Sdim//===-- InlineAsm.cpp - Implement the InlineAsm class ---------------------===//
2249259Sdim//
3249259Sdim//                     The LLVM Compiler Infrastructure
4249259Sdim//
5249259Sdim// This file is distributed under the University of Illinois Open Source
6249259Sdim// License. See LICENSE.TXT for details.
7249259Sdim//
8249259Sdim//===----------------------------------------------------------------------===//
9249259Sdim//
10249259Sdim// This file implements the InlineAsm class.
11249259Sdim//
12249259Sdim//===----------------------------------------------------------------------===//
13249259Sdim
14249259Sdim#include "llvm/IR/InlineAsm.h"
15249259Sdim#include "ConstantsContext.h"
16249259Sdim#include "LLVMContextImpl.h"
17249259Sdim#include "llvm/IR/DerivedTypes.h"
18249259Sdim#include <algorithm>
19249259Sdim#include <cctype>
20249259Sdimusing namespace llvm;
21249259Sdim
22249259Sdim// Implement the first virtual method in this class in this file so the
23249259Sdim// InlineAsm vtable is emitted here.
24249259SdimInlineAsm::~InlineAsm() {
25249259Sdim}
26249259Sdim
27249259Sdim
28249259SdimInlineAsm *InlineAsm::get(FunctionType *Ty, StringRef AsmString,
29249259Sdim                          StringRef Constraints, bool hasSideEffects,
30249259Sdim                          bool isAlignStack, AsmDialect asmDialect) {
31249259Sdim  InlineAsmKeyType Key(AsmString, Constraints, hasSideEffects, isAlignStack,
32249259Sdim                       asmDialect);
33249259Sdim  LLVMContextImpl *pImpl = Ty->getContext().pImpl;
34249259Sdim  return pImpl->InlineAsms.getOrCreate(PointerType::getUnqual(Ty), Key);
35249259Sdim}
36249259Sdim
37249259SdimInlineAsm::InlineAsm(PointerType *Ty, const std::string &asmString,
38249259Sdim                     const std::string &constraints, bool hasSideEffects,
39249259Sdim                     bool isAlignStack, AsmDialect asmDialect)
40249259Sdim  : Value(Ty, Value::InlineAsmVal),
41249259Sdim    AsmString(asmString), Constraints(constraints),
42249259Sdim    HasSideEffects(hasSideEffects), IsAlignStack(isAlignStack),
43249259Sdim    Dialect(asmDialect) {
44249259Sdim
45249259Sdim  // Do various checks on the constraint string and type.
46249259Sdim  assert(Verify(getFunctionType(), constraints) &&
47249259Sdim         "Function type not legal for constraints!");
48249259Sdim}
49249259Sdim
50249259Sdimvoid InlineAsm::destroyConstant() {
51249259Sdim  getType()->getContext().pImpl->InlineAsms.remove(this);
52249259Sdim  delete this;
53249259Sdim}
54249259Sdim
55249259SdimFunctionType *InlineAsm::getFunctionType() const {
56249259Sdim  return cast<FunctionType>(getType()->getElementType());
57249259Sdim}
58249259Sdim
59249259Sdim///Default constructor.
60249259SdimInlineAsm::ConstraintInfo::ConstraintInfo() :
61249259Sdim  Type(isInput), isEarlyClobber(false),
62249259Sdim  MatchingInput(-1), isCommutative(false),
63249259Sdim  isIndirect(false), isMultipleAlternative(false),
64249259Sdim  currentAlternativeIndex(0) {
65249259Sdim}
66249259Sdim
67249259Sdim/// Copy constructor.
68249259SdimInlineAsm::ConstraintInfo::ConstraintInfo(const ConstraintInfo &other) :
69249259Sdim  Type(other.Type), isEarlyClobber(other.isEarlyClobber),
70249259Sdim  MatchingInput(other.MatchingInput), isCommutative(other.isCommutative),
71249259Sdim  isIndirect(other.isIndirect), Codes(other.Codes),
72249259Sdim  isMultipleAlternative(other.isMultipleAlternative),
73249259Sdim  multipleAlternatives(other.multipleAlternatives),
74249259Sdim  currentAlternativeIndex(other.currentAlternativeIndex) {
75249259Sdim}
76249259Sdim
77249259Sdim/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the
78249259Sdim/// fields in this structure.  If the constraint string is not understood,
79249259Sdim/// return true, otherwise return false.
80249259Sdimbool InlineAsm::ConstraintInfo::Parse(StringRef Str,
81249259Sdim                     InlineAsm::ConstraintInfoVector &ConstraintsSoFar) {
82249259Sdim  StringRef::iterator I = Str.begin(), E = Str.end();
83249259Sdim  unsigned multipleAlternativeCount = Str.count('|') + 1;
84249259Sdim  unsigned multipleAlternativeIndex = 0;
85249259Sdim  ConstraintCodeVector *pCodes = &Codes;
86249259Sdim
87249259Sdim  // Initialize
88249259Sdim  isMultipleAlternative = (multipleAlternativeCount > 1 ? true : false);
89249259Sdim  if (isMultipleAlternative) {
90249259Sdim    multipleAlternatives.resize(multipleAlternativeCount);
91249259Sdim    pCodes = &multipleAlternatives[0].Codes;
92249259Sdim  }
93249259Sdim  Type = isInput;
94249259Sdim  isEarlyClobber = false;
95249259Sdim  MatchingInput = -1;
96249259Sdim  isCommutative = false;
97249259Sdim  isIndirect = false;
98249259Sdim  currentAlternativeIndex = 0;
99249259Sdim
100249259Sdim  // Parse prefixes.
101249259Sdim  if (*I == '~') {
102249259Sdim    Type = isClobber;
103249259Sdim    ++I;
104249259Sdim  } else if (*I == '=') {
105249259Sdim    ++I;
106249259Sdim    Type = isOutput;
107249259Sdim  }
108249259Sdim
109249259Sdim  if (*I == '*') {
110249259Sdim    isIndirect = true;
111249259Sdim    ++I;
112249259Sdim  }
113249259Sdim
114249259Sdim  if (I == E) return true;  // Just a prefix, like "==" or "~".
115249259Sdim
116249259Sdim  // Parse the modifiers.
117249259Sdim  bool DoneWithModifiers = false;
118249259Sdim  while (!DoneWithModifiers) {
119249259Sdim    switch (*I) {
120249259Sdim    default:
121249259Sdim      DoneWithModifiers = true;
122249259Sdim      break;
123249259Sdim    case '&':     // Early clobber.
124249259Sdim      if (Type != isOutput ||      // Cannot early clobber anything but output.
125249259Sdim          isEarlyClobber)          // Reject &&&&&&
126249259Sdim        return true;
127249259Sdim      isEarlyClobber = true;
128249259Sdim      break;
129249259Sdim    case '%':     // Commutative.
130249259Sdim      if (Type == isClobber ||     // Cannot commute clobbers.
131249259Sdim          isCommutative)           // Reject %%%%%
132249259Sdim        return true;
133249259Sdim      isCommutative = true;
134249259Sdim      break;
135249259Sdim    case '#':     // Comment.
136249259Sdim    case '*':     // Register preferencing.
137249259Sdim      return true;     // Not supported.
138249259Sdim    }
139249259Sdim
140249259Sdim    if (!DoneWithModifiers) {
141249259Sdim      ++I;
142249259Sdim      if (I == E) return true;   // Just prefixes and modifiers!
143249259Sdim    }
144249259Sdim  }
145249259Sdim
146249259Sdim  // Parse the various constraints.
147249259Sdim  while (I != E) {
148249259Sdim    if (*I == '{') {   // Physical register reference.
149249259Sdim      // Find the end of the register name.
150249259Sdim      StringRef::iterator ConstraintEnd = std::find(I+1, E, '}');
151249259Sdim      if (ConstraintEnd == E) return true;  // "{foo"
152249259Sdim      pCodes->push_back(std::string(I, ConstraintEnd+1));
153249259Sdim      I = ConstraintEnd+1;
154249259Sdim    } else if (isdigit(static_cast<unsigned char>(*I))) { // Matching Constraint
155249259Sdim      // Maximal munch numbers.
156249259Sdim      StringRef::iterator NumStart = I;
157249259Sdim      while (I != E && isdigit(static_cast<unsigned char>(*I)))
158249259Sdim        ++I;
159249259Sdim      pCodes->push_back(std::string(NumStart, I));
160249259Sdim      unsigned N = atoi(pCodes->back().c_str());
161249259Sdim      // Check that this is a valid matching constraint!
162249259Sdim      if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput||
163249259Sdim          Type != isInput)
164249259Sdim        return true;  // Invalid constraint number.
165249259Sdim
166249259Sdim      // If Operand N already has a matching input, reject this.  An output
167249259Sdim      // can't be constrained to the same value as multiple inputs.
168249259Sdim      if (isMultipleAlternative) {
169249259Sdim        InlineAsm::SubConstraintInfo &scInfo =
170249259Sdim          ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex];
171249259Sdim        if (scInfo.MatchingInput != -1)
172249259Sdim          return true;
173249259Sdim        // Note that operand #n has a matching input.
174249259Sdim        scInfo.MatchingInput = ConstraintsSoFar.size();
175249259Sdim      } else {
176249259Sdim        if (ConstraintsSoFar[N].hasMatchingInput())
177249259Sdim          return true;
178249259Sdim        // Note that operand #n has a matching input.
179249259Sdim        ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size();
180249259Sdim        }
181249259Sdim    } else if (*I == '|') {
182249259Sdim      multipleAlternativeIndex++;
183249259Sdim      pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes;
184249259Sdim      ++I;
185249259Sdim    } else if (*I == '^') {
186249259Sdim      // Multi-letter constraint
187249259Sdim      // FIXME: For now assuming these are 2-character constraints.
188249259Sdim      pCodes->push_back(std::string(I+1, I+3));
189249259Sdim      I += 3;
190249259Sdim    } else {
191249259Sdim      // Single letter constraint.
192249259Sdim      pCodes->push_back(std::string(I, I+1));
193249259Sdim      ++I;
194249259Sdim    }
195249259Sdim  }
196249259Sdim
197249259Sdim  return false;
198249259Sdim}
199249259Sdim
200249259Sdim/// selectAlternative - Point this constraint to the alternative constraint
201249259Sdim/// indicated by the index.
202249259Sdimvoid InlineAsm::ConstraintInfo::selectAlternative(unsigned index) {
203249259Sdim  if (index < multipleAlternatives.size()) {
204249259Sdim    currentAlternativeIndex = index;
205249259Sdim    InlineAsm::SubConstraintInfo &scInfo =
206249259Sdim      multipleAlternatives[currentAlternativeIndex];
207249259Sdim    MatchingInput = scInfo.MatchingInput;
208249259Sdim    Codes = scInfo.Codes;
209249259Sdim  }
210249259Sdim}
211249259Sdim
212249259SdimInlineAsm::ConstraintInfoVector
213249259SdimInlineAsm::ParseConstraints(StringRef Constraints) {
214249259Sdim  ConstraintInfoVector Result;
215249259Sdim
216249259Sdim  // Scan the constraints string.
217249259Sdim  for (StringRef::iterator I = Constraints.begin(),
218249259Sdim         E = Constraints.end(); I != E; ) {
219249259Sdim    ConstraintInfo Info;
220249259Sdim
221249259Sdim    // Find the end of this constraint.
222249259Sdim    StringRef::iterator ConstraintEnd = std::find(I, E, ',');
223249259Sdim
224249259Sdim    if (ConstraintEnd == I ||  // Empty constraint like ",,"
225249259Sdim        Info.Parse(StringRef(I, ConstraintEnd-I), Result)) {
226249259Sdim      Result.clear();          // Erroneous constraint?
227249259Sdim      break;
228249259Sdim    }
229249259Sdim
230249259Sdim    Result.push_back(Info);
231249259Sdim
232249259Sdim    // ConstraintEnd may be either the next comma or the end of the string.  In
233249259Sdim    // the former case, we skip the comma.
234249259Sdim    I = ConstraintEnd;
235249259Sdim    if (I != E) {
236249259Sdim      ++I;
237249259Sdim      if (I == E) { Result.clear(); break; }    // don't allow "xyz,"
238249259Sdim    }
239249259Sdim  }
240249259Sdim
241249259Sdim  return Result;
242249259Sdim}
243249259Sdim
244249259Sdim/// Verify - Verify that the specified constraint string is reasonable for the
245249259Sdim/// specified function type, and otherwise validate the constraint string.
246249259Sdimbool InlineAsm::Verify(FunctionType *Ty, StringRef ConstStr) {
247249259Sdim  if (Ty->isVarArg()) return false;
248249259Sdim
249249259Sdim  ConstraintInfoVector Constraints = ParseConstraints(ConstStr);
250249259Sdim
251249259Sdim  // Error parsing constraints.
252249259Sdim  if (Constraints.empty() && !ConstStr.empty()) return false;
253249259Sdim
254249259Sdim  unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;
255249259Sdim  unsigned NumIndirect = 0;
256249259Sdim
257249259Sdim  for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
258249259Sdim    switch (Constraints[i].Type) {
259249259Sdim    case InlineAsm::isOutput:
260249259Sdim      if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0)
261249259Sdim        return false;  // outputs before inputs and clobbers.
262249259Sdim      if (!Constraints[i].isIndirect) {
263249259Sdim        ++NumOutputs;
264249259Sdim        break;
265249259Sdim      }
266249259Sdim      ++NumIndirect;
267249259Sdim      // FALLTHROUGH for Indirect Outputs.
268249259Sdim    case InlineAsm::isInput:
269249259Sdim      if (NumClobbers) return false;               // inputs before clobbers.
270249259Sdim      ++NumInputs;
271249259Sdim      break;
272249259Sdim    case InlineAsm::isClobber:
273249259Sdim      ++NumClobbers;
274249259Sdim      break;
275249259Sdim    }
276249259Sdim  }
277249259Sdim
278249259Sdim  switch (NumOutputs) {
279249259Sdim  case 0:
280249259Sdim    if (!Ty->getReturnType()->isVoidTy()) return false;
281249259Sdim    break;
282249259Sdim  case 1:
283249259Sdim    if (Ty->getReturnType()->isStructTy()) return false;
284249259Sdim    break;
285249259Sdim  default:
286249259Sdim    StructType *STy = dyn_cast<StructType>(Ty->getReturnType());
287249259Sdim    if (STy == 0 || STy->getNumElements() != NumOutputs)
288249259Sdim      return false;
289249259Sdim    break;
290249259Sdim  }
291249259Sdim
292249259Sdim  if (Ty->getNumParams() != NumInputs) return false;
293249259Sdim  return true;
294249259Sdim}
295249259Sdim
296