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