xref: /openbsd/gnu/llvm/llvm/lib/IR/InlineAsm.cpp (revision d415bd75)
109467b48Spatrick //===- InlineAsm.cpp - Implement the InlineAsm class ----------------------===//
209467b48Spatrick //
309467b48Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
409467b48Spatrick // See https://llvm.org/LICENSE.txt for license information.
509467b48Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
609467b48Spatrick //
709467b48Spatrick //===----------------------------------------------------------------------===//
809467b48Spatrick //
909467b48Spatrick // This file implements the InlineAsm class.
1009467b48Spatrick //
1109467b48Spatrick //===----------------------------------------------------------------------===//
1209467b48Spatrick 
1309467b48Spatrick #include "llvm/IR/InlineAsm.h"
1409467b48Spatrick #include "ConstantsContext.h"
1509467b48Spatrick #include "LLVMContextImpl.h"
1609467b48Spatrick #include "llvm/ADT/StringRef.h"
1709467b48Spatrick #include "llvm/IR/DerivedTypes.h"
1809467b48Spatrick #include "llvm/IR/LLVMContext.h"
1909467b48Spatrick #include "llvm/IR/Value.h"
2009467b48Spatrick #include "llvm/Support/Casting.h"
2109467b48Spatrick #include "llvm/Support/Compiler.h"
22*d415bd75Srobert #include "llvm/Support/Errc.h"
2309467b48Spatrick #include <algorithm>
2409467b48Spatrick #include <cassert>
2509467b48Spatrick #include <cctype>
2609467b48Spatrick #include <cstdlib>
2709467b48Spatrick 
2809467b48Spatrick using namespace llvm;
2909467b48Spatrick 
InlineAsm(FunctionType * FTy,const std::string & asmString,const std::string & constraints,bool hasSideEffects,bool isAlignStack,AsmDialect asmDialect,bool canThrow)3009467b48Spatrick InlineAsm::InlineAsm(FunctionType *FTy, const std::string &asmString,
3109467b48Spatrick                      const std::string &constraints, bool hasSideEffects,
3273471bf0Spatrick                      bool isAlignStack, AsmDialect asmDialect, bool canThrow)
3309467b48Spatrick     : Value(PointerType::getUnqual(FTy), Value::InlineAsmVal),
3409467b48Spatrick       AsmString(asmString), Constraints(constraints), FTy(FTy),
3509467b48Spatrick       HasSideEffects(hasSideEffects), IsAlignStack(isAlignStack),
3673471bf0Spatrick       Dialect(asmDialect), CanThrow(canThrow) {
37*d415bd75Srobert #ifndef NDEBUG
3809467b48Spatrick   // Do various checks on the constraint string and type.
39*d415bd75Srobert   cantFail(verify(getFunctionType(), constraints));
40*d415bd75Srobert #endif
4109467b48Spatrick }
4209467b48Spatrick 
get(FunctionType * FTy,StringRef AsmString,StringRef Constraints,bool hasSideEffects,bool isAlignStack,AsmDialect asmDialect,bool canThrow)4309467b48Spatrick InlineAsm *InlineAsm::get(FunctionType *FTy, StringRef AsmString,
4409467b48Spatrick                           StringRef Constraints, bool hasSideEffects,
4573471bf0Spatrick                           bool isAlignStack, AsmDialect asmDialect,
4673471bf0Spatrick                           bool canThrow) {
4709467b48Spatrick   InlineAsmKeyType Key(AsmString, Constraints, FTy, hasSideEffects,
4873471bf0Spatrick                        isAlignStack, asmDialect, canThrow);
4909467b48Spatrick   LLVMContextImpl *pImpl = FTy->getContext().pImpl;
5009467b48Spatrick   return pImpl->InlineAsms.getOrCreate(PointerType::getUnqual(FTy), Key);
5109467b48Spatrick }
5209467b48Spatrick 
destroyConstant()5309467b48Spatrick void InlineAsm::destroyConstant() {
5409467b48Spatrick   getType()->getContext().pImpl->InlineAsms.remove(this);
5509467b48Spatrick   delete this;
5609467b48Spatrick }
5709467b48Spatrick 
getFunctionType() const5809467b48Spatrick FunctionType *InlineAsm::getFunctionType() const {
5909467b48Spatrick   return FTy;
6009467b48Spatrick }
6109467b48Spatrick 
collectAsmStrs(SmallVectorImpl<StringRef> & AsmStrs) const62*d415bd75Srobert void InlineAsm::collectAsmStrs(SmallVectorImpl<StringRef> &AsmStrs) const {
63*d415bd75Srobert   StringRef AsmStr(AsmString);
64*d415bd75Srobert   AsmStrs.clear();
65*d415bd75Srobert 
66*d415bd75Srobert   // TODO: 1) Unify delimiter for inline asm, we also meet other delimiters
67*d415bd75Srobert   // for example "\0A", ";".
68*d415bd75Srobert   // 2) Enhance StringRef. Some of the special delimiter ("\0") can't be
69*d415bd75Srobert   // split in StringRef. Also empty StringRef can not call split (will stuck).
70*d415bd75Srobert   if (AsmStr.empty())
71*d415bd75Srobert     return;
72*d415bd75Srobert   AsmStr.split(AsmStrs, "\n\t", -1, false);
73*d415bd75Srobert }
74*d415bd75Srobert 
7509467b48Spatrick /// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the
7609467b48Spatrick /// fields in this structure.  If the constraint string is not understood,
7709467b48Spatrick /// return true, otherwise return false.
Parse(StringRef Str,InlineAsm::ConstraintInfoVector & ConstraintsSoFar)7809467b48Spatrick bool InlineAsm::ConstraintInfo::Parse(StringRef Str,
7909467b48Spatrick                      InlineAsm::ConstraintInfoVector &ConstraintsSoFar) {
8009467b48Spatrick   StringRef::iterator I = Str.begin(), E = Str.end();
8109467b48Spatrick   unsigned multipleAlternativeCount = Str.count('|') + 1;
8209467b48Spatrick   unsigned multipleAlternativeIndex = 0;
8309467b48Spatrick   ConstraintCodeVector *pCodes = &Codes;
8409467b48Spatrick 
8509467b48Spatrick   // Initialize
8609467b48Spatrick   isMultipleAlternative = multipleAlternativeCount > 1;
8709467b48Spatrick   if (isMultipleAlternative) {
8809467b48Spatrick     multipleAlternatives.resize(multipleAlternativeCount);
8909467b48Spatrick     pCodes = &multipleAlternatives[0].Codes;
9009467b48Spatrick   }
9109467b48Spatrick   Type = isInput;
9209467b48Spatrick   isEarlyClobber = false;
9309467b48Spatrick   MatchingInput = -1;
9409467b48Spatrick   isCommutative = false;
9509467b48Spatrick   isIndirect = false;
9609467b48Spatrick   currentAlternativeIndex = 0;
9709467b48Spatrick 
9809467b48Spatrick   // Parse prefixes.
9909467b48Spatrick   if (*I == '~') {
10009467b48Spatrick     Type = isClobber;
10109467b48Spatrick     ++I;
10209467b48Spatrick 
10309467b48Spatrick     // '{' must immediately follow '~'.
10409467b48Spatrick     if (I != E && *I != '{')
10509467b48Spatrick       return true;
10609467b48Spatrick   } else if (*I == '=') {
10709467b48Spatrick     ++I;
10809467b48Spatrick     Type = isOutput;
109*d415bd75Srobert   } else if (*I == '!') {
110*d415bd75Srobert     ++I;
111*d415bd75Srobert     Type = isLabel;
11209467b48Spatrick   }
11309467b48Spatrick 
11409467b48Spatrick   if (*I == '*') {
11509467b48Spatrick     isIndirect = true;
11609467b48Spatrick     ++I;
11709467b48Spatrick   }
11809467b48Spatrick 
11909467b48Spatrick   if (I == E) return true;  // Just a prefix, like "==" or "~".
12009467b48Spatrick 
12109467b48Spatrick   // Parse the modifiers.
12209467b48Spatrick   bool DoneWithModifiers = false;
12309467b48Spatrick   while (!DoneWithModifiers) {
12409467b48Spatrick     switch (*I) {
12509467b48Spatrick     default:
12609467b48Spatrick       DoneWithModifiers = true;
12709467b48Spatrick       break;
12809467b48Spatrick     case '&':     // Early clobber.
12909467b48Spatrick       if (Type != isOutput ||      // Cannot early clobber anything but output.
13009467b48Spatrick           isEarlyClobber)          // Reject &&&&&&
13109467b48Spatrick         return true;
13209467b48Spatrick       isEarlyClobber = true;
13309467b48Spatrick       break;
13409467b48Spatrick     case '%':     // Commutative.
13509467b48Spatrick       if (Type == isClobber ||     // Cannot commute clobbers.
13609467b48Spatrick           isCommutative)           // Reject %%%%%
13709467b48Spatrick         return true;
13809467b48Spatrick       isCommutative = true;
13909467b48Spatrick       break;
14009467b48Spatrick     case '#':     // Comment.
14109467b48Spatrick     case '*':     // Register preferencing.
14209467b48Spatrick       return true;     // Not supported.
14309467b48Spatrick     }
14409467b48Spatrick 
14509467b48Spatrick     if (!DoneWithModifiers) {
14609467b48Spatrick       ++I;
14709467b48Spatrick       if (I == E) return true;   // Just prefixes and modifiers!
14809467b48Spatrick     }
14909467b48Spatrick   }
15009467b48Spatrick 
15109467b48Spatrick   // Parse the various constraints.
15209467b48Spatrick   while (I != E) {
15309467b48Spatrick     if (*I == '{') {   // Physical register reference.
15409467b48Spatrick       // Find the end of the register name.
15509467b48Spatrick       StringRef::iterator ConstraintEnd = std::find(I+1, E, '}');
15609467b48Spatrick       if (ConstraintEnd == E) return true;  // "{foo"
157097a140dSpatrick       pCodes->push_back(std::string(StringRef(I, ConstraintEnd + 1 - I)));
15809467b48Spatrick       I = ConstraintEnd+1;
15909467b48Spatrick     } else if (isdigit(static_cast<unsigned char>(*I))) { // Matching Constraint
16009467b48Spatrick       // Maximal munch numbers.
16109467b48Spatrick       StringRef::iterator NumStart = I;
16209467b48Spatrick       while (I != E && isdigit(static_cast<unsigned char>(*I)))
16309467b48Spatrick         ++I;
164097a140dSpatrick       pCodes->push_back(std::string(StringRef(NumStart, I - NumStart)));
16509467b48Spatrick       unsigned N = atoi(pCodes->back().c_str());
16609467b48Spatrick       // Check that this is a valid matching constraint!
16709467b48Spatrick       if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput||
16809467b48Spatrick           Type != isInput)
16909467b48Spatrick         return true;  // Invalid constraint number.
17009467b48Spatrick 
17109467b48Spatrick       // If Operand N already has a matching input, reject this.  An output
17209467b48Spatrick       // can't be constrained to the same value as multiple inputs.
17309467b48Spatrick       if (isMultipleAlternative) {
17409467b48Spatrick         if (multipleAlternativeIndex >=
17509467b48Spatrick             ConstraintsSoFar[N].multipleAlternatives.size())
17609467b48Spatrick           return true;
17709467b48Spatrick         InlineAsm::SubConstraintInfo &scInfo =
17809467b48Spatrick           ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex];
17909467b48Spatrick         if (scInfo.MatchingInput != -1)
18009467b48Spatrick           return true;
18109467b48Spatrick         // Note that operand #n has a matching input.
18209467b48Spatrick         scInfo.MatchingInput = ConstraintsSoFar.size();
18309467b48Spatrick         assert(scInfo.MatchingInput >= 0);
18409467b48Spatrick       } else {
18509467b48Spatrick         if (ConstraintsSoFar[N].hasMatchingInput() &&
18609467b48Spatrick             (size_t)ConstraintsSoFar[N].MatchingInput !=
18709467b48Spatrick                 ConstraintsSoFar.size())
18809467b48Spatrick           return true;
18909467b48Spatrick         // Note that operand #n has a matching input.
19009467b48Spatrick         ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size();
19109467b48Spatrick         assert(ConstraintsSoFar[N].MatchingInput >= 0);
19209467b48Spatrick         }
19309467b48Spatrick     } else if (*I == '|') {
19409467b48Spatrick       multipleAlternativeIndex++;
19509467b48Spatrick       pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes;
19609467b48Spatrick       ++I;
19709467b48Spatrick     } else if (*I == '^') {
19809467b48Spatrick       // Multi-letter constraint
19909467b48Spatrick       // FIXME: For now assuming these are 2-character constraints.
200097a140dSpatrick       pCodes->push_back(std::string(StringRef(I + 1, 2)));
20109467b48Spatrick       I += 3;
20209467b48Spatrick     } else if (*I == '@') {
20309467b48Spatrick       // Multi-letter constraint
20409467b48Spatrick       ++I;
20509467b48Spatrick       unsigned char C = static_cast<unsigned char>(*I);
20609467b48Spatrick       assert(isdigit(C) && "Expected a digit!");
20709467b48Spatrick       int N = C - '0';
20809467b48Spatrick       assert(N > 0 && "Found a zero letter constraint!");
20909467b48Spatrick       ++I;
210097a140dSpatrick       pCodes->push_back(std::string(StringRef(I, N)));
21109467b48Spatrick       I += N;
21209467b48Spatrick     } else {
21309467b48Spatrick       // Single letter constraint.
214097a140dSpatrick       pCodes->push_back(std::string(StringRef(I, 1)));
21509467b48Spatrick       ++I;
21609467b48Spatrick     }
21709467b48Spatrick   }
21809467b48Spatrick 
21909467b48Spatrick   return false;
22009467b48Spatrick }
22109467b48Spatrick 
22209467b48Spatrick /// selectAlternative - Point this constraint to the alternative constraint
22309467b48Spatrick /// indicated by the index.
selectAlternative(unsigned index)22409467b48Spatrick void InlineAsm::ConstraintInfo::selectAlternative(unsigned index) {
22509467b48Spatrick   if (index < multipleAlternatives.size()) {
22609467b48Spatrick     currentAlternativeIndex = index;
22709467b48Spatrick     InlineAsm::SubConstraintInfo &scInfo =
22809467b48Spatrick       multipleAlternatives[currentAlternativeIndex];
22909467b48Spatrick     MatchingInput = scInfo.MatchingInput;
23009467b48Spatrick     Codes = scInfo.Codes;
23109467b48Spatrick   }
23209467b48Spatrick }
23309467b48Spatrick 
23409467b48Spatrick InlineAsm::ConstraintInfoVector
ParseConstraints(StringRef Constraints)23509467b48Spatrick InlineAsm::ParseConstraints(StringRef Constraints) {
23609467b48Spatrick   ConstraintInfoVector Result;
23709467b48Spatrick 
23809467b48Spatrick   // Scan the constraints string.
23909467b48Spatrick   for (StringRef::iterator I = Constraints.begin(),
24009467b48Spatrick          E = Constraints.end(); I != E; ) {
24109467b48Spatrick     ConstraintInfo Info;
24209467b48Spatrick 
24309467b48Spatrick     // Find the end of this constraint.
24409467b48Spatrick     StringRef::iterator ConstraintEnd = std::find(I, E, ',');
24509467b48Spatrick 
24609467b48Spatrick     if (ConstraintEnd == I ||  // Empty constraint like ",,"
24709467b48Spatrick         Info.Parse(StringRef(I, ConstraintEnd-I), Result)) {
24809467b48Spatrick       Result.clear();          // Erroneous constraint?
24909467b48Spatrick       break;
25009467b48Spatrick     }
25109467b48Spatrick 
25209467b48Spatrick     Result.push_back(Info);
25309467b48Spatrick 
25409467b48Spatrick     // ConstraintEnd may be either the next comma or the end of the string.  In
25509467b48Spatrick     // the former case, we skip the comma.
25609467b48Spatrick     I = ConstraintEnd;
25709467b48Spatrick     if (I != E) {
25809467b48Spatrick       ++I;
25909467b48Spatrick       if (I == E) {
26009467b48Spatrick         Result.clear();
26109467b48Spatrick         break;
26209467b48Spatrick       } // don't allow "xyz,"
26309467b48Spatrick     }
26409467b48Spatrick   }
26509467b48Spatrick 
26609467b48Spatrick   return Result;
26709467b48Spatrick }
26809467b48Spatrick 
makeStringError(const char * Msg)269*d415bd75Srobert static Error makeStringError(const char *Msg) {
270*d415bd75Srobert   return createStringError(errc::invalid_argument, Msg);
271*d415bd75Srobert }
272*d415bd75Srobert 
verify(FunctionType * Ty,StringRef ConstStr)273*d415bd75Srobert Error InlineAsm::verify(FunctionType *Ty, StringRef ConstStr) {
274*d415bd75Srobert   if (Ty->isVarArg())
275*d415bd75Srobert     return makeStringError("inline asm cannot be variadic");
27609467b48Spatrick 
27709467b48Spatrick   ConstraintInfoVector Constraints = ParseConstraints(ConstStr);
27809467b48Spatrick 
27909467b48Spatrick   // Error parsing constraints.
280*d415bd75Srobert   if (Constraints.empty() && !ConstStr.empty())
281*d415bd75Srobert     return makeStringError("failed to parse constraints");
28209467b48Spatrick 
28309467b48Spatrick   unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;
284*d415bd75Srobert   unsigned NumIndirect = 0, NumLabels = 0;
28509467b48Spatrick 
286*d415bd75Srobert   for (const ConstraintInfo &Constraint : Constraints) {
287*d415bd75Srobert     switch (Constraint.Type) {
28809467b48Spatrick     case InlineAsm::isOutput:
289*d415bd75Srobert       if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0 || NumLabels != 0)
290*d415bd75Srobert         return makeStringError("output constraint occurs after input, "
291*d415bd75Srobert                                "clobber or label constraint");
292*d415bd75Srobert 
293*d415bd75Srobert       if (!Constraint.isIndirect) {
29409467b48Spatrick         ++NumOutputs;
29509467b48Spatrick         break;
29609467b48Spatrick       }
29709467b48Spatrick       ++NumIndirect;
298*d415bd75Srobert       [[fallthrough]]; // We fall through for Indirect Outputs.
29909467b48Spatrick     case InlineAsm::isInput:
300*d415bd75Srobert       if (NumClobbers)
301*d415bd75Srobert         return makeStringError("input constraint occurs after clobber "
302*d415bd75Srobert                                "constraint");
30309467b48Spatrick       ++NumInputs;
30409467b48Spatrick       break;
30509467b48Spatrick     case InlineAsm::isClobber:
30609467b48Spatrick       ++NumClobbers;
30709467b48Spatrick       break;
308*d415bd75Srobert     case InlineAsm::isLabel:
309*d415bd75Srobert       if (NumClobbers)
310*d415bd75Srobert         return makeStringError("label constraint occurs after clobber "
311*d415bd75Srobert                                "constraint");
312*d415bd75Srobert 
313*d415bd75Srobert       ++NumLabels;
314*d415bd75Srobert       break;
31509467b48Spatrick     }
31609467b48Spatrick   }
31709467b48Spatrick 
31809467b48Spatrick   switch (NumOutputs) {
31909467b48Spatrick   case 0:
320*d415bd75Srobert     if (!Ty->getReturnType()->isVoidTy())
321*d415bd75Srobert       return makeStringError("inline asm without outputs must return void");
32209467b48Spatrick     break;
32309467b48Spatrick   case 1:
324*d415bd75Srobert     if (Ty->getReturnType()->isStructTy())
325*d415bd75Srobert       return makeStringError("inline asm with one output cannot return struct");
32609467b48Spatrick     break;
32709467b48Spatrick   default:
32809467b48Spatrick     StructType *STy = dyn_cast<StructType>(Ty->getReturnType());
32909467b48Spatrick     if (!STy || STy->getNumElements() != NumOutputs)
330*d415bd75Srobert       return makeStringError("number of output constraints does not match "
331*d415bd75Srobert                              "number of return struct elements");
33209467b48Spatrick     break;
33309467b48Spatrick   }
33409467b48Spatrick 
335*d415bd75Srobert   if (Ty->getNumParams() != NumInputs)
336*d415bd75Srobert     return makeStringError("number of input constraints does not match number "
337*d415bd75Srobert                            "of parameters");
338*d415bd75Srobert 
339*d415bd75Srobert   // We don't have access to labels here, NumLabels will be checked separately.
340*d415bd75Srobert   return Error::success();
34109467b48Spatrick }
342