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