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