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(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(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(StringRef(I+1, 2)); 183 I += 3; 184 } else { 185 // Single letter constraint. 186 pCodes->push_back(StringRef(I, 1)); 187 ++I; 188 } 189 } 190 191 return false; 192 } 193 194 /// selectAlternative - Point this constraint to the alternative constraint 195 /// indicated by the index. 196 void InlineAsm::ConstraintInfo::selectAlternative(unsigned index) { 197 if (index < multipleAlternatives.size()) { 198 currentAlternativeIndex = index; 199 InlineAsm::SubConstraintInfo &scInfo = 200 multipleAlternatives[currentAlternativeIndex]; 201 MatchingInput = scInfo.MatchingInput; 202 Codes = scInfo.Codes; 203 } 204 } 205 206 InlineAsm::ConstraintInfoVector 207 InlineAsm::ParseConstraints(StringRef Constraints) { 208 ConstraintInfoVector Result; 209 210 // Scan the constraints string. 211 for (StringRef::iterator I = Constraints.begin(), 212 E = Constraints.end(); I != E; ) { 213 ConstraintInfo Info; 214 215 // Find the end of this constraint. 216 StringRef::iterator ConstraintEnd = std::find(I, E, ','); 217 218 if (ConstraintEnd == I || // Empty constraint like ",," 219 Info.Parse(StringRef(I, ConstraintEnd-I), Result)) { 220 Result.clear(); // Erroneous constraint? 221 break; 222 } 223 224 Result.push_back(Info); 225 226 // ConstraintEnd may be either the next comma or the end of the string. In 227 // the former case, we skip the comma. 228 I = ConstraintEnd; 229 if (I != E) { 230 ++I; 231 if (I == E) { 232 Result.clear(); 233 break; 234 } // don't allow "xyz," 235 } 236 } 237 238 return Result; 239 } 240 241 /// Verify - Verify that the specified constraint string is reasonable for the 242 /// specified function type, and otherwise validate the constraint string. 243 bool InlineAsm::Verify(FunctionType *Ty, StringRef ConstStr) { 244 if (Ty->isVarArg()) return false; 245 246 ConstraintInfoVector Constraints = ParseConstraints(ConstStr); 247 248 // Error parsing constraints. 249 if (Constraints.empty() && !ConstStr.empty()) return false; 250 251 unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0; 252 unsigned NumIndirect = 0; 253 254 for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { 255 switch (Constraints[i].Type) { 256 case InlineAsm::isOutput: 257 if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0) 258 return false; // outputs before inputs and clobbers. 259 if (!Constraints[i].isIndirect) { 260 ++NumOutputs; 261 break; 262 } 263 ++NumIndirect; 264 LLVM_FALLTHROUGH; // We fall through for Indirect Outputs. 265 case InlineAsm::isInput: 266 if (NumClobbers) return false; // inputs before clobbers. 267 ++NumInputs; 268 break; 269 case InlineAsm::isClobber: 270 ++NumClobbers; 271 break; 272 } 273 } 274 275 switch (NumOutputs) { 276 case 0: 277 if (!Ty->getReturnType()->isVoidTy()) return false; 278 break; 279 case 1: 280 if (Ty->getReturnType()->isStructTy()) return false; 281 break; 282 default: 283 StructType *STy = dyn_cast<StructType>(Ty->getReturnType()); 284 if (!STy || STy->getNumElements() != NumOutputs) 285 return false; 286 break; 287 } 288 289 if (Ty->getNumParams() != NumInputs) return false; 290 return true; 291 } 292