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