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