brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.1 KiB · 9220814 Raw
343 lines · cpp
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-exception6//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 "llvm/Support/Errc.h"23#include <algorithm>24#include <cassert>25#include <cctype>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, bool canThrow)33    : Value(PointerType::getUnqual(FTy->getContext()), Value::InlineAsmVal),34      AsmString(asmString), Constraints(constraints), FTy(FTy),35      HasSideEffects(hasSideEffects), IsAlignStack(isAlignStack),36      Dialect(asmDialect), CanThrow(canThrow) {37#ifndef NDEBUG38  // Do various checks on the constraint string and type.39  cantFail(verify(getFunctionType(), constraints));40#endif41}42 43InlineAsm *InlineAsm::get(FunctionType *FTy, StringRef AsmString,44                          StringRef Constraints, bool hasSideEffects,45                          bool isAlignStack, AsmDialect asmDialect,46                          bool canThrow) {47  InlineAsmKeyType Key(AsmString, Constraints, FTy, hasSideEffects,48                       isAlignStack, asmDialect, canThrow);49  LLVMContextImpl *pImpl = FTy->getContext().pImpl;50  return pImpl->InlineAsms.getOrCreate(51      PointerType::getUnqual(FTy->getContext()), Key);52}53 54void InlineAsm::destroyConstant() {55  getType()->getContext().pImpl->InlineAsms.remove(this);56  delete this;57}58 59FunctionType *InlineAsm::getFunctionType() const {60  return FTy;61}62 63void InlineAsm::collectAsmStrs(SmallVectorImpl<StringRef> &AsmStrs) const {64  StringRef AsmStr(AsmString);65  AsmStrs.clear();66 67  // TODO: 1) Unify delimiter for inline asm, we also meet other delimiters68  // for example "\0A", ";".69  // 2) Enhance StringRef. Some of the special delimiter ("\0") can't be70  // split in StringRef. Also empty StringRef can not call split (will stuck).71  if (AsmStr.empty())72    return;73  AsmStr.split(AsmStrs, "\n\t", -1, false);74}75 76/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the77/// fields in this structure.  If the constraint string is not understood,78/// return true, otherwise return false.79bool InlineAsm::ConstraintInfo::Parse(StringRef Str,80                     InlineAsm::ConstraintInfoVector &ConstraintsSoFar) {81  StringRef::iterator I = Str.begin(), E = Str.end();82  unsigned multipleAlternativeCount = Str.count('|') + 1;83  unsigned multipleAlternativeIndex = 0;84  ConstraintCodeVector *pCodes = &Codes;85 86  // Initialize87  isMultipleAlternative = multipleAlternativeCount > 1;88  if (isMultipleAlternative) {89    multipleAlternatives.resize(multipleAlternativeCount);90    pCodes = &multipleAlternatives[0].Codes;91  }92  Type = isInput;93  isEarlyClobber = false;94  MatchingInput = -1;95  isCommutative = false;96  isIndirect = false;97  currentAlternativeIndex = 0;98 99  // Parse prefixes.100  if (*I == '~') {101    Type = isClobber;102    ++I;103 104    // '{' must immediately follow '~'.105    if (I != E && *I != '{')106      return true;107  } else if (*I == '=') {108    ++I;109    Type = isOutput;110  } else if (*I == '!') {111    ++I;112    Type = isLabel;113  }114 115  if (*I == '*') {116    isIndirect = true;117    ++I;118  }119 120  if (I == E) return true;  // Just a prefix, like "==" or "~".121 122  // Parse the modifiers.123  bool DoneWithModifiers = false;124  while (!DoneWithModifiers) {125    switch (*I) {126    default:127      DoneWithModifiers = true;128      break;129    case '&':     // Early clobber.130      if (Type != isOutput ||      // Cannot early clobber anything but output.131          isEarlyClobber)          // Reject &&&&&&132        return true;133      isEarlyClobber = true;134      break;135    case '%':     // Commutative.136      if (Type == isClobber ||     // Cannot commute clobbers.137          isCommutative)           // Reject %%%%%138        return true;139      isCommutative = true;140      break;141    case '#':     // Comment.142    case '*':     // Register preferencing.143      return true;     // Not supported.144    }145 146    if (!DoneWithModifiers) {147      ++I;148      if (I == E) return true;   // Just prefixes and modifiers!149    }150  }151 152  // Parse the various constraints.153  while (I != E) {154    if (*I == '{') {   // Physical register reference.155      // Find the end of the register name.156      StringRef::iterator ConstraintEnd = std::find(I+1, E, '}');157      if (ConstraintEnd == E) return true;  // "{foo"158      pCodes->push_back(std::string(StringRef(I, ConstraintEnd + 1 - I)));159      I = ConstraintEnd+1;160    } else if (isdigit(static_cast<unsigned char>(*I))) { // Matching Constraint161      // Maximal munch numbers.162      StringRef::iterator NumStart = I;163      while (I != E && isdigit(static_cast<unsigned char>(*I)))164        ++I;165      pCodes->push_back(std::string(StringRef(NumStart, I - NumStart)));166      unsigned N = atoi(pCodes->back().c_str());167      // Check that this is a valid matching constraint!168      if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput||169          Type != isInput)170        return true;  // Invalid constraint number.171 172      // If Operand N already has a matching input, reject this.  An output173      // can't be constrained to the same value as multiple inputs.174      if (isMultipleAlternative) {175        if (multipleAlternativeIndex >=176            ConstraintsSoFar[N].multipleAlternatives.size())177          return true;178        InlineAsm::SubConstraintInfo &scInfo =179          ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex];180        if (scInfo.MatchingInput != -1)181          return true;182        // Note that operand #n has a matching input.183        scInfo.MatchingInput = ConstraintsSoFar.size();184        assert(scInfo.MatchingInput >= 0);185      } else {186        if (ConstraintsSoFar[N].hasMatchingInput() &&187            (size_t)ConstraintsSoFar[N].MatchingInput !=188                ConstraintsSoFar.size())189          return true;190        // Note that operand #n has a matching input.191        ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size();192        assert(ConstraintsSoFar[N].MatchingInput >= 0);193        }194    } else if (*I == '|') {195      multipleAlternativeIndex++;196      pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes;197      ++I;198    } else if (*I == '^') {199      // Multi-letter constraint200      // FIXME: For now assuming these are 2-character constraints.201      pCodes->push_back(std::string(StringRef(I + 1, 2)));202      I += 3;203    } else if (*I == '@') {204      // Multi-letter constraint205      ++I;206      unsigned char C = static_cast<unsigned char>(*I);207      assert(isdigit(C) && "Expected a digit!");208      int N = C - '0';209      assert(N > 0 && "Found a zero letter constraint!");210      ++I;211      pCodes->push_back(std::string(StringRef(I, N)));212      I += N;213    } else {214      // Single letter constraint.215      pCodes->push_back(std::string(StringRef(I, 1)));216      ++I;217    }218  }219 220  return false;221}222 223/// selectAlternative - Point this constraint to the alternative constraint224/// indicated by the index.225void InlineAsm::ConstraintInfo::selectAlternative(unsigned index) {226  if (index < multipleAlternatives.size()) {227    currentAlternativeIndex = index;228    InlineAsm::SubConstraintInfo &scInfo =229      multipleAlternatives[currentAlternativeIndex];230    MatchingInput = scInfo.MatchingInput;231    Codes = scInfo.Codes;232  }233}234 235InlineAsm::ConstraintInfoVector236InlineAsm::ParseConstraints(StringRef Constraints) {237  ConstraintInfoVector Result;238 239  // Scan the constraints string.240  for (StringRef::iterator I = Constraints.begin(),241         E = Constraints.end(); I != E; ) {242    ConstraintInfo Info;243 244    // Find the end of this constraint.245    StringRef::iterator ConstraintEnd = std::find(I, E, ',');246 247    if (ConstraintEnd == I ||  // Empty constraint like ",,"248        Info.Parse(StringRef(I, ConstraintEnd-I), Result)) {249      Result.clear();          // Erroneous constraint?250      break;251    }252 253    Result.push_back(Info);254 255    // ConstraintEnd may be either the next comma or the end of the string.  In256    // the former case, we skip the comma.257    I = ConstraintEnd;258    if (I != E) {259      ++I;260      if (I == E) {261        Result.clear();262        break;263      } // don't allow "xyz,"264    }265  }266 267  return Result;268}269 270static Error makeStringError(const char *Msg) {271  return createStringError(errc::invalid_argument, Msg);272}273 274Error InlineAsm::verify(FunctionType *Ty, StringRef ConstStr) {275  if (Ty->isVarArg())276    return makeStringError("inline asm cannot be variadic");277 278  ConstraintInfoVector Constraints = ParseConstraints(ConstStr);279 280  // Error parsing constraints.281  if (Constraints.empty() && !ConstStr.empty())282    return makeStringError("failed to parse constraints");283 284  unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;285  unsigned NumIndirect = 0, NumLabels = 0;286 287  for (const ConstraintInfo &Constraint : Constraints) {288    switch (Constraint.Type) {289    case InlineAsm::isOutput:290      if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0 || NumLabels != 0)291        return makeStringError("output constraint occurs after input, "292                               "clobber or label constraint");293 294      if (!Constraint.isIndirect) {295        ++NumOutputs;296        break;297      }298      ++NumIndirect;299      [[fallthrough]]; // We fall through for Indirect Outputs.300    case InlineAsm::isInput:301      if (NumClobbers)302        return makeStringError("input constraint occurs after clobber "303                               "constraint");304      ++NumInputs;305      break;306    case InlineAsm::isClobber:307      ++NumClobbers;308      break;309    case InlineAsm::isLabel:310      if (NumClobbers)311        return makeStringError("label constraint occurs after clobber "312                               "constraint");313 314      ++NumLabels;315      break;316    }317  }318 319  switch (NumOutputs) {320  case 0:321    if (!Ty->getReturnType()->isVoidTy())322      return makeStringError("inline asm without outputs must return void");323    break;324  case 1:325    if (Ty->getReturnType()->isStructTy())326      return makeStringError("inline asm with one output cannot return struct");327    break;328  default:329    StructType *STy = dyn_cast<StructType>(Ty->getReturnType());330    if (!STy || STy->getNumElements() != NumOutputs)331      return makeStringError("number of output constraints does not match "332                             "number of return struct elements");333    break;334  }335 336  if (Ty->getNumParams() != NumInputs)337    return makeStringError("number of input constraints does not match number "338                           "of parameters");339 340  // We don't have access to labels here, NumLabels will be checked separately.341  return Error::success();342}343