10b57cec5SDimitry Andric //===- InlineAsm.cpp - Implement the InlineAsm class ----------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This file implements the InlineAsm class.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric
130b57cec5SDimitry Andric #include "llvm/IR/InlineAsm.h"
140b57cec5SDimitry Andric #include "ConstantsContext.h"
150b57cec5SDimitry Andric #include "LLVMContextImpl.h"
160b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
170b57cec5SDimitry Andric #include "llvm/IR/DerivedTypes.h"
180b57cec5SDimitry Andric #include "llvm/IR/LLVMContext.h"
190b57cec5SDimitry Andric #include "llvm/IR/Value.h"
200b57cec5SDimitry Andric #include "llvm/Support/Casting.h"
210b57cec5SDimitry Andric #include "llvm/Support/Compiler.h"
22753f127fSDimitry Andric #include "llvm/Support/Errc.h"
230b57cec5SDimitry Andric #include <algorithm>
240b57cec5SDimitry Andric #include <cassert>
250b57cec5SDimitry Andric #include <cctype>
260b57cec5SDimitry Andric #include <cstdlib>
270b57cec5SDimitry Andric
280b57cec5SDimitry Andric using namespace llvm;
290b57cec5SDimitry Andric
InlineAsm(FunctionType * FTy,const std::string & asmString,const std::string & constraints,bool hasSideEffects,bool isAlignStack,AsmDialect asmDialect,bool canThrow)300b57cec5SDimitry Andric InlineAsm::InlineAsm(FunctionType *FTy, const std::string &asmString,
310b57cec5SDimitry Andric const std::string &constraints, bool hasSideEffects,
32fe6060f1SDimitry Andric bool isAlignStack, AsmDialect asmDialect, bool canThrow)
330b57cec5SDimitry Andric : Value(PointerType::getUnqual(FTy), Value::InlineAsmVal),
340b57cec5SDimitry Andric AsmString(asmString), Constraints(constraints), FTy(FTy),
350b57cec5SDimitry Andric HasSideEffects(hasSideEffects), IsAlignStack(isAlignStack),
36fe6060f1SDimitry Andric Dialect(asmDialect), CanThrow(canThrow) {
37753f127fSDimitry Andric #ifndef NDEBUG
380b57cec5SDimitry Andric // Do various checks on the constraint string and type.
39753f127fSDimitry Andric cantFail(verify(getFunctionType(), constraints));
40753f127fSDimitry Andric #endif
410b57cec5SDimitry Andric }
420b57cec5SDimitry Andric
get(FunctionType * FTy,StringRef AsmString,StringRef Constraints,bool hasSideEffects,bool isAlignStack,AsmDialect asmDialect,bool canThrow)430b57cec5SDimitry Andric InlineAsm *InlineAsm::get(FunctionType *FTy, StringRef AsmString,
440b57cec5SDimitry Andric StringRef Constraints, bool hasSideEffects,
45fe6060f1SDimitry Andric bool isAlignStack, AsmDialect asmDialect,
46fe6060f1SDimitry Andric bool canThrow) {
470b57cec5SDimitry Andric InlineAsmKeyType Key(AsmString, Constraints, FTy, hasSideEffects,
48fe6060f1SDimitry Andric isAlignStack, asmDialect, canThrow);
490b57cec5SDimitry Andric LLVMContextImpl *pImpl = FTy->getContext().pImpl;
500b57cec5SDimitry Andric return pImpl->InlineAsms.getOrCreate(PointerType::getUnqual(FTy), Key);
510b57cec5SDimitry Andric }
520b57cec5SDimitry Andric
destroyConstant()530b57cec5SDimitry Andric void InlineAsm::destroyConstant() {
540b57cec5SDimitry Andric getType()->getContext().pImpl->InlineAsms.remove(this);
550b57cec5SDimitry Andric delete this;
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric
getFunctionType() const580b57cec5SDimitry Andric FunctionType *InlineAsm::getFunctionType() const {
590b57cec5SDimitry Andric return FTy;
600b57cec5SDimitry Andric }
610b57cec5SDimitry Andric
collectAsmStrs(SmallVectorImpl<StringRef> & AsmStrs) const62*bdd1243dSDimitry Andric void InlineAsm::collectAsmStrs(SmallVectorImpl<StringRef> &AsmStrs) const {
63*bdd1243dSDimitry Andric StringRef AsmStr(AsmString);
64*bdd1243dSDimitry Andric AsmStrs.clear();
65*bdd1243dSDimitry Andric
66*bdd1243dSDimitry Andric // TODO: 1) Unify delimiter for inline asm, we also meet other delimiters
67*bdd1243dSDimitry Andric // for example "\0A", ";".
68*bdd1243dSDimitry Andric // 2) Enhance StringRef. Some of the special delimiter ("\0") can't be
69*bdd1243dSDimitry Andric // split in StringRef. Also empty StringRef can not call split (will stuck).
70*bdd1243dSDimitry Andric if (AsmStr.empty())
71*bdd1243dSDimitry Andric return;
72*bdd1243dSDimitry Andric AsmStr.split(AsmStrs, "\n\t", -1, false);
73*bdd1243dSDimitry Andric }
74*bdd1243dSDimitry Andric
750b57cec5SDimitry Andric /// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the
760b57cec5SDimitry Andric /// fields in this structure. If the constraint string is not understood,
770b57cec5SDimitry Andric /// return true, otherwise return false.
Parse(StringRef Str,InlineAsm::ConstraintInfoVector & ConstraintsSoFar)780b57cec5SDimitry Andric bool InlineAsm::ConstraintInfo::Parse(StringRef Str,
790b57cec5SDimitry Andric InlineAsm::ConstraintInfoVector &ConstraintsSoFar) {
800b57cec5SDimitry Andric StringRef::iterator I = Str.begin(), E = Str.end();
810b57cec5SDimitry Andric unsigned multipleAlternativeCount = Str.count('|') + 1;
820b57cec5SDimitry Andric unsigned multipleAlternativeIndex = 0;
830b57cec5SDimitry Andric ConstraintCodeVector *pCodes = &Codes;
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric // Initialize
860b57cec5SDimitry Andric isMultipleAlternative = multipleAlternativeCount > 1;
870b57cec5SDimitry Andric if (isMultipleAlternative) {
880b57cec5SDimitry Andric multipleAlternatives.resize(multipleAlternativeCount);
890b57cec5SDimitry Andric pCodes = &multipleAlternatives[0].Codes;
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric Type = isInput;
920b57cec5SDimitry Andric isEarlyClobber = false;
930b57cec5SDimitry Andric MatchingInput = -1;
940b57cec5SDimitry Andric isCommutative = false;
950b57cec5SDimitry Andric isIndirect = false;
960b57cec5SDimitry Andric currentAlternativeIndex = 0;
970b57cec5SDimitry Andric
980b57cec5SDimitry Andric // Parse prefixes.
990b57cec5SDimitry Andric if (*I == '~') {
1000b57cec5SDimitry Andric Type = isClobber;
1010b57cec5SDimitry Andric ++I;
1020b57cec5SDimitry Andric
1030b57cec5SDimitry Andric // '{' must immediately follow '~'.
1040b57cec5SDimitry Andric if (I != E && *I != '{')
1050b57cec5SDimitry Andric return true;
1060b57cec5SDimitry Andric } else if (*I == '=') {
1070b57cec5SDimitry Andric ++I;
1080b57cec5SDimitry Andric Type = isOutput;
109fcaf7f86SDimitry Andric } else if (*I == '!') {
110fcaf7f86SDimitry Andric ++I;
111fcaf7f86SDimitry Andric Type = isLabel;
1120b57cec5SDimitry Andric }
1130b57cec5SDimitry Andric
1140b57cec5SDimitry Andric if (*I == '*') {
1150b57cec5SDimitry Andric isIndirect = true;
1160b57cec5SDimitry Andric ++I;
1170b57cec5SDimitry Andric }
1180b57cec5SDimitry Andric
1190b57cec5SDimitry Andric if (I == E) return true; // Just a prefix, like "==" or "~".
1200b57cec5SDimitry Andric
1210b57cec5SDimitry Andric // Parse the modifiers.
1220b57cec5SDimitry Andric bool DoneWithModifiers = false;
1230b57cec5SDimitry Andric while (!DoneWithModifiers) {
1240b57cec5SDimitry Andric switch (*I) {
1250b57cec5SDimitry Andric default:
1260b57cec5SDimitry Andric DoneWithModifiers = true;
1270b57cec5SDimitry Andric break;
1280b57cec5SDimitry Andric case '&': // Early clobber.
1290b57cec5SDimitry Andric if (Type != isOutput || // Cannot early clobber anything but output.
1300b57cec5SDimitry Andric isEarlyClobber) // Reject &&&&&&
1310b57cec5SDimitry Andric return true;
1320b57cec5SDimitry Andric isEarlyClobber = true;
1330b57cec5SDimitry Andric break;
1340b57cec5SDimitry Andric case '%': // Commutative.
1350b57cec5SDimitry Andric if (Type == isClobber || // Cannot commute clobbers.
1360b57cec5SDimitry Andric isCommutative) // Reject %%%%%
1370b57cec5SDimitry Andric return true;
1380b57cec5SDimitry Andric isCommutative = true;
1390b57cec5SDimitry Andric break;
1400b57cec5SDimitry Andric case '#': // Comment.
1410b57cec5SDimitry Andric case '*': // Register preferencing.
1420b57cec5SDimitry Andric return true; // Not supported.
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
1450b57cec5SDimitry Andric if (!DoneWithModifiers) {
1460b57cec5SDimitry Andric ++I;
1470b57cec5SDimitry Andric if (I == E) return true; // Just prefixes and modifiers!
1480b57cec5SDimitry Andric }
1490b57cec5SDimitry Andric }
1500b57cec5SDimitry Andric
1510b57cec5SDimitry Andric // Parse the various constraints.
1520b57cec5SDimitry Andric while (I != E) {
1530b57cec5SDimitry Andric if (*I == '{') { // Physical register reference.
1540b57cec5SDimitry Andric // Find the end of the register name.
1550b57cec5SDimitry Andric StringRef::iterator ConstraintEnd = std::find(I+1, E, '}');
1560b57cec5SDimitry Andric if (ConstraintEnd == E) return true; // "{foo"
1575ffd83dbSDimitry Andric pCodes->push_back(std::string(StringRef(I, ConstraintEnd + 1 - I)));
1580b57cec5SDimitry Andric I = ConstraintEnd+1;
1590b57cec5SDimitry Andric } else if (isdigit(static_cast<unsigned char>(*I))) { // Matching Constraint
1600b57cec5SDimitry Andric // Maximal munch numbers.
1610b57cec5SDimitry Andric StringRef::iterator NumStart = I;
1620b57cec5SDimitry Andric while (I != E && isdigit(static_cast<unsigned char>(*I)))
1630b57cec5SDimitry Andric ++I;
1645ffd83dbSDimitry Andric pCodes->push_back(std::string(StringRef(NumStart, I - NumStart)));
1650b57cec5SDimitry Andric unsigned N = atoi(pCodes->back().c_str());
1660b57cec5SDimitry Andric // Check that this is a valid matching constraint!
1670b57cec5SDimitry Andric if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput||
1680b57cec5SDimitry Andric Type != isInput)
1690b57cec5SDimitry Andric return true; // Invalid constraint number.
1700b57cec5SDimitry Andric
1710b57cec5SDimitry Andric // If Operand N already has a matching input, reject this. An output
1720b57cec5SDimitry Andric // can't be constrained to the same value as multiple inputs.
1730b57cec5SDimitry Andric if (isMultipleAlternative) {
1740b57cec5SDimitry Andric if (multipleAlternativeIndex >=
1750b57cec5SDimitry Andric ConstraintsSoFar[N].multipleAlternatives.size())
1760b57cec5SDimitry Andric return true;
1770b57cec5SDimitry Andric InlineAsm::SubConstraintInfo &scInfo =
1780b57cec5SDimitry Andric ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex];
1790b57cec5SDimitry Andric if (scInfo.MatchingInput != -1)
1800b57cec5SDimitry Andric return true;
1810b57cec5SDimitry Andric // Note that operand #n has a matching input.
1820b57cec5SDimitry Andric scInfo.MatchingInput = ConstraintsSoFar.size();
1830b57cec5SDimitry Andric assert(scInfo.MatchingInput >= 0);
1840b57cec5SDimitry Andric } else {
1850b57cec5SDimitry Andric if (ConstraintsSoFar[N].hasMatchingInput() &&
1860b57cec5SDimitry Andric (size_t)ConstraintsSoFar[N].MatchingInput !=
1870b57cec5SDimitry Andric ConstraintsSoFar.size())
1880b57cec5SDimitry Andric return true;
1890b57cec5SDimitry Andric // Note that operand #n has a matching input.
1900b57cec5SDimitry Andric ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size();
1910b57cec5SDimitry Andric assert(ConstraintsSoFar[N].MatchingInput >= 0);
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric } else if (*I == '|') {
1940b57cec5SDimitry Andric multipleAlternativeIndex++;
1950b57cec5SDimitry Andric pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes;
1960b57cec5SDimitry Andric ++I;
1970b57cec5SDimitry Andric } else if (*I == '^') {
1980b57cec5SDimitry Andric // Multi-letter constraint
1990b57cec5SDimitry Andric // FIXME: For now assuming these are 2-character constraints.
2005ffd83dbSDimitry Andric pCodes->push_back(std::string(StringRef(I + 1, 2)));
2010b57cec5SDimitry Andric I += 3;
2028bcb0991SDimitry Andric } else if (*I == '@') {
2038bcb0991SDimitry Andric // Multi-letter constraint
2048bcb0991SDimitry Andric ++I;
2058bcb0991SDimitry Andric unsigned char C = static_cast<unsigned char>(*I);
2068bcb0991SDimitry Andric assert(isdigit(C) && "Expected a digit!");
2078bcb0991SDimitry Andric int N = C - '0';
2088bcb0991SDimitry Andric assert(N > 0 && "Found a zero letter constraint!");
2098bcb0991SDimitry Andric ++I;
2105ffd83dbSDimitry Andric pCodes->push_back(std::string(StringRef(I, N)));
2118bcb0991SDimitry Andric I += N;
2120b57cec5SDimitry Andric } else {
2130b57cec5SDimitry Andric // Single letter constraint.
2145ffd83dbSDimitry Andric pCodes->push_back(std::string(StringRef(I, 1)));
2150b57cec5SDimitry Andric ++I;
2160b57cec5SDimitry Andric }
2170b57cec5SDimitry Andric }
2180b57cec5SDimitry Andric
2190b57cec5SDimitry Andric return false;
2200b57cec5SDimitry Andric }
2210b57cec5SDimitry Andric
2220b57cec5SDimitry Andric /// selectAlternative - Point this constraint to the alternative constraint
2230b57cec5SDimitry Andric /// indicated by the index.
selectAlternative(unsigned index)2240b57cec5SDimitry Andric void InlineAsm::ConstraintInfo::selectAlternative(unsigned index) {
2250b57cec5SDimitry Andric if (index < multipleAlternatives.size()) {
2260b57cec5SDimitry Andric currentAlternativeIndex = index;
2270b57cec5SDimitry Andric InlineAsm::SubConstraintInfo &scInfo =
2280b57cec5SDimitry Andric multipleAlternatives[currentAlternativeIndex];
2290b57cec5SDimitry Andric MatchingInput = scInfo.MatchingInput;
2300b57cec5SDimitry Andric Codes = scInfo.Codes;
2310b57cec5SDimitry Andric }
2320b57cec5SDimitry Andric }
2330b57cec5SDimitry Andric
2340b57cec5SDimitry Andric InlineAsm::ConstraintInfoVector
ParseConstraints(StringRef Constraints)2350b57cec5SDimitry Andric InlineAsm::ParseConstraints(StringRef Constraints) {
2360b57cec5SDimitry Andric ConstraintInfoVector Result;
2370b57cec5SDimitry Andric
2380b57cec5SDimitry Andric // Scan the constraints string.
2390b57cec5SDimitry Andric for (StringRef::iterator I = Constraints.begin(),
2400b57cec5SDimitry Andric E = Constraints.end(); I != E; ) {
2410b57cec5SDimitry Andric ConstraintInfo Info;
2420b57cec5SDimitry Andric
2430b57cec5SDimitry Andric // Find the end of this constraint.
2440b57cec5SDimitry Andric StringRef::iterator ConstraintEnd = std::find(I, E, ',');
2450b57cec5SDimitry Andric
2460b57cec5SDimitry Andric if (ConstraintEnd == I || // Empty constraint like ",,"
2470b57cec5SDimitry Andric Info.Parse(StringRef(I, ConstraintEnd-I), Result)) {
2480b57cec5SDimitry Andric Result.clear(); // Erroneous constraint?
2490b57cec5SDimitry Andric break;
2500b57cec5SDimitry Andric }
2510b57cec5SDimitry Andric
2520b57cec5SDimitry Andric Result.push_back(Info);
2530b57cec5SDimitry Andric
2540b57cec5SDimitry Andric // ConstraintEnd may be either the next comma or the end of the string. In
2550b57cec5SDimitry Andric // the former case, we skip the comma.
2560b57cec5SDimitry Andric I = ConstraintEnd;
2570b57cec5SDimitry Andric if (I != E) {
2580b57cec5SDimitry Andric ++I;
2590b57cec5SDimitry Andric if (I == E) {
2600b57cec5SDimitry Andric Result.clear();
2610b57cec5SDimitry Andric break;
2620b57cec5SDimitry Andric } // don't allow "xyz,"
2630b57cec5SDimitry Andric }
2640b57cec5SDimitry Andric }
2650b57cec5SDimitry Andric
2660b57cec5SDimitry Andric return Result;
2670b57cec5SDimitry Andric }
2680b57cec5SDimitry Andric
makeStringError(const char * Msg)269753f127fSDimitry Andric static Error makeStringError(const char *Msg) {
270753f127fSDimitry Andric return createStringError(errc::invalid_argument, Msg);
271753f127fSDimitry Andric }
272753f127fSDimitry Andric
verify(FunctionType * Ty,StringRef ConstStr)273753f127fSDimitry Andric Error InlineAsm::verify(FunctionType *Ty, StringRef ConstStr) {
274753f127fSDimitry Andric if (Ty->isVarArg())
275753f127fSDimitry Andric return makeStringError("inline asm cannot be variadic");
2760b57cec5SDimitry Andric
2770b57cec5SDimitry Andric ConstraintInfoVector Constraints = ParseConstraints(ConstStr);
2780b57cec5SDimitry Andric
2790b57cec5SDimitry Andric // Error parsing constraints.
280753f127fSDimitry Andric if (Constraints.empty() && !ConstStr.empty())
281753f127fSDimitry Andric return makeStringError("failed to parse constraints");
2820b57cec5SDimitry Andric
2830b57cec5SDimitry Andric unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0;
284fcaf7f86SDimitry Andric unsigned NumIndirect = 0, NumLabels = 0;
2850b57cec5SDimitry Andric
2860eae32dcSDimitry Andric for (const ConstraintInfo &Constraint : Constraints) {
2870eae32dcSDimitry Andric switch (Constraint.Type) {
2880b57cec5SDimitry Andric case InlineAsm::isOutput:
289fcaf7f86SDimitry Andric if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0 || NumLabels != 0)
290fcaf7f86SDimitry Andric return makeStringError("output constraint occurs after input, "
291fcaf7f86SDimitry Andric "clobber or label constraint");
292753f127fSDimitry Andric
2930eae32dcSDimitry Andric if (!Constraint.isIndirect) {
2940b57cec5SDimitry Andric ++NumOutputs;
2950b57cec5SDimitry Andric break;
2960b57cec5SDimitry Andric }
2970b57cec5SDimitry Andric ++NumIndirect;
298*bdd1243dSDimitry Andric [[fallthrough]]; // We fall through for Indirect Outputs.
2990b57cec5SDimitry Andric case InlineAsm::isInput:
300753f127fSDimitry Andric if (NumClobbers)
301753f127fSDimitry Andric return makeStringError("input constraint occurs after clobber "
302753f127fSDimitry Andric "constraint");
3030b57cec5SDimitry Andric ++NumInputs;
3040b57cec5SDimitry Andric break;
3050b57cec5SDimitry Andric case InlineAsm::isClobber:
3060b57cec5SDimitry Andric ++NumClobbers;
3070b57cec5SDimitry Andric break;
308fcaf7f86SDimitry Andric case InlineAsm::isLabel:
309fcaf7f86SDimitry Andric if (NumClobbers)
310fcaf7f86SDimitry Andric return makeStringError("label constraint occurs after clobber "
311fcaf7f86SDimitry Andric "constraint");
312fcaf7f86SDimitry Andric
313fcaf7f86SDimitry Andric ++NumLabels;
314fcaf7f86SDimitry Andric break;
3150b57cec5SDimitry Andric }
3160b57cec5SDimitry Andric }
3170b57cec5SDimitry Andric
3180b57cec5SDimitry Andric switch (NumOutputs) {
3190b57cec5SDimitry Andric case 0:
320753f127fSDimitry Andric if (!Ty->getReturnType()->isVoidTy())
321753f127fSDimitry Andric return makeStringError("inline asm without outputs must return void");
3220b57cec5SDimitry Andric break;
3230b57cec5SDimitry Andric case 1:
324753f127fSDimitry Andric if (Ty->getReturnType()->isStructTy())
325753f127fSDimitry Andric return makeStringError("inline asm with one output cannot return struct");
3260b57cec5SDimitry Andric break;
3270b57cec5SDimitry Andric default:
3280b57cec5SDimitry Andric StructType *STy = dyn_cast<StructType>(Ty->getReturnType());
3290b57cec5SDimitry Andric if (!STy || STy->getNumElements() != NumOutputs)
330753f127fSDimitry Andric return makeStringError("number of output constraints does not match "
331753f127fSDimitry Andric "number of return struct elements");
3320b57cec5SDimitry Andric break;
3330b57cec5SDimitry Andric }
3340b57cec5SDimitry Andric
335753f127fSDimitry Andric if (Ty->getNumParams() != NumInputs)
336753f127fSDimitry Andric return makeStringError("number of input constraints does not match number "
337753f127fSDimitry Andric "of parameters");
338fcaf7f86SDimitry Andric
339fcaf7f86SDimitry Andric // We don't have access to labels here, NumLabels will be checked separately.
340753f127fSDimitry Andric return Error::success();
3410b57cec5SDimitry Andric }
342