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