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