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->getContext()), 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( 51 PointerType::getUnqual(FTy->getContext()), Key); 52 } 53 54 void InlineAsm::destroyConstant() { 55 getType()->getContext().pImpl->InlineAsms.remove(this); 56 delete this; 57 } 58 59 FunctionType *InlineAsm::getFunctionType() const { 60 return FTy; 61 } 62 63 void 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 delimiters 68 // for example "\0A", ";". 69 // 2) Enhance StringRef. Some of the special delimiter ("\0") can't be 70 // 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 the 77 /// fields in this structure. If the constraint string is not understood, 78 /// return true, otherwise return false. 79 bool 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 // Initialize 87 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 Constraint 161 // 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 output 173 // 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 constraint 200 // 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 constraint 205 ++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 constraint 224 /// indicated by the index. 225 void 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 235 InlineAsm::ConstraintInfoVector 236 InlineAsm::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. In 256 // 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 270 static Error makeStringError(const char *Msg) { 271 return createStringError(errc::invalid_argument, Msg); 272 } 273 274 Error 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