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