1249259Sdim//===-- InlineAsm.cpp - Implement the InlineAsm class ---------------------===// 2249259Sdim// 3249259Sdim// The LLVM Compiler Infrastructure 4249259Sdim// 5249259Sdim// This file is distributed under the University of Illinois Open Source 6249259Sdim// License. See LICENSE.TXT for details. 7249259Sdim// 8249259Sdim//===----------------------------------------------------------------------===// 9249259Sdim// 10249259Sdim// This file implements the InlineAsm class. 11249259Sdim// 12249259Sdim//===----------------------------------------------------------------------===// 13249259Sdim 14249259Sdim#include "llvm/IR/InlineAsm.h" 15249259Sdim#include "ConstantsContext.h" 16249259Sdim#include "LLVMContextImpl.h" 17249259Sdim#include "llvm/IR/DerivedTypes.h" 18249259Sdim#include <algorithm> 19249259Sdim#include <cctype> 20249259Sdimusing namespace llvm; 21249259Sdim 22249259Sdim// Implement the first virtual method in this class in this file so the 23249259Sdim// InlineAsm vtable is emitted here. 24249259SdimInlineAsm::~InlineAsm() { 25249259Sdim} 26249259Sdim 27249259Sdim 28249259SdimInlineAsm *InlineAsm::get(FunctionType *Ty, StringRef AsmString, 29249259Sdim StringRef Constraints, bool hasSideEffects, 30249259Sdim bool isAlignStack, AsmDialect asmDialect) { 31249259Sdim InlineAsmKeyType Key(AsmString, Constraints, hasSideEffects, isAlignStack, 32249259Sdim asmDialect); 33249259Sdim LLVMContextImpl *pImpl = Ty->getContext().pImpl; 34249259Sdim return pImpl->InlineAsms.getOrCreate(PointerType::getUnqual(Ty), Key); 35249259Sdim} 36249259Sdim 37249259SdimInlineAsm::InlineAsm(PointerType *Ty, const std::string &asmString, 38249259Sdim const std::string &constraints, bool hasSideEffects, 39249259Sdim bool isAlignStack, AsmDialect asmDialect) 40249259Sdim : Value(Ty, Value::InlineAsmVal), 41249259Sdim AsmString(asmString), Constraints(constraints), 42249259Sdim HasSideEffects(hasSideEffects), IsAlignStack(isAlignStack), 43249259Sdim Dialect(asmDialect) { 44249259Sdim 45249259Sdim // Do various checks on the constraint string and type. 46249259Sdim assert(Verify(getFunctionType(), constraints) && 47249259Sdim "Function type not legal for constraints!"); 48249259Sdim} 49249259Sdim 50249259Sdimvoid InlineAsm::destroyConstant() { 51249259Sdim getType()->getContext().pImpl->InlineAsms.remove(this); 52249259Sdim delete this; 53249259Sdim} 54249259Sdim 55249259SdimFunctionType *InlineAsm::getFunctionType() const { 56249259Sdim return cast<FunctionType>(getType()->getElementType()); 57249259Sdim} 58249259Sdim 59249259Sdim///Default constructor. 60249259SdimInlineAsm::ConstraintInfo::ConstraintInfo() : 61249259Sdim Type(isInput), isEarlyClobber(false), 62249259Sdim MatchingInput(-1), isCommutative(false), 63249259Sdim isIndirect(false), isMultipleAlternative(false), 64249259Sdim currentAlternativeIndex(0) { 65249259Sdim} 66249259Sdim 67249259Sdim/// Copy constructor. 68249259SdimInlineAsm::ConstraintInfo::ConstraintInfo(const ConstraintInfo &other) : 69249259Sdim Type(other.Type), isEarlyClobber(other.isEarlyClobber), 70249259Sdim MatchingInput(other.MatchingInput), isCommutative(other.isCommutative), 71249259Sdim isIndirect(other.isIndirect), Codes(other.Codes), 72249259Sdim isMultipleAlternative(other.isMultipleAlternative), 73249259Sdim multipleAlternatives(other.multipleAlternatives), 74249259Sdim currentAlternativeIndex(other.currentAlternativeIndex) { 75249259Sdim} 76249259Sdim 77249259Sdim/// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the 78249259Sdim/// fields in this structure. If the constraint string is not understood, 79249259Sdim/// return true, otherwise return false. 80249259Sdimbool InlineAsm::ConstraintInfo::Parse(StringRef Str, 81249259Sdim InlineAsm::ConstraintInfoVector &ConstraintsSoFar) { 82249259Sdim StringRef::iterator I = Str.begin(), E = Str.end(); 83249259Sdim unsigned multipleAlternativeCount = Str.count('|') + 1; 84249259Sdim unsigned multipleAlternativeIndex = 0; 85249259Sdim ConstraintCodeVector *pCodes = &Codes; 86249259Sdim 87249259Sdim // Initialize 88249259Sdim isMultipleAlternative = (multipleAlternativeCount > 1 ? true : false); 89249259Sdim if (isMultipleAlternative) { 90249259Sdim multipleAlternatives.resize(multipleAlternativeCount); 91249259Sdim pCodes = &multipleAlternatives[0].Codes; 92249259Sdim } 93249259Sdim Type = isInput; 94249259Sdim isEarlyClobber = false; 95249259Sdim MatchingInput = -1; 96249259Sdim isCommutative = false; 97249259Sdim isIndirect = false; 98249259Sdim currentAlternativeIndex = 0; 99249259Sdim 100249259Sdim // Parse prefixes. 101249259Sdim if (*I == '~') { 102249259Sdim Type = isClobber; 103249259Sdim ++I; 104249259Sdim } else if (*I == '=') { 105249259Sdim ++I; 106249259Sdim Type = isOutput; 107249259Sdim } 108249259Sdim 109249259Sdim if (*I == '*') { 110249259Sdim isIndirect = true; 111249259Sdim ++I; 112249259Sdim } 113249259Sdim 114249259Sdim if (I == E) return true; // Just a prefix, like "==" or "~". 115249259Sdim 116249259Sdim // Parse the modifiers. 117249259Sdim bool DoneWithModifiers = false; 118249259Sdim while (!DoneWithModifiers) { 119249259Sdim switch (*I) { 120249259Sdim default: 121249259Sdim DoneWithModifiers = true; 122249259Sdim break; 123249259Sdim case '&': // Early clobber. 124249259Sdim if (Type != isOutput || // Cannot early clobber anything but output. 125249259Sdim isEarlyClobber) // Reject &&&&&& 126249259Sdim return true; 127249259Sdim isEarlyClobber = true; 128249259Sdim break; 129249259Sdim case '%': // Commutative. 130249259Sdim if (Type == isClobber || // Cannot commute clobbers. 131249259Sdim isCommutative) // Reject %%%%% 132249259Sdim return true; 133249259Sdim isCommutative = true; 134249259Sdim break; 135249259Sdim case '#': // Comment. 136249259Sdim case '*': // Register preferencing. 137249259Sdim return true; // Not supported. 138249259Sdim } 139249259Sdim 140249259Sdim if (!DoneWithModifiers) { 141249259Sdim ++I; 142249259Sdim if (I == E) return true; // Just prefixes and modifiers! 143249259Sdim } 144249259Sdim } 145249259Sdim 146249259Sdim // Parse the various constraints. 147249259Sdim while (I != E) { 148249259Sdim if (*I == '{') { // Physical register reference. 149249259Sdim // Find the end of the register name. 150249259Sdim StringRef::iterator ConstraintEnd = std::find(I+1, E, '}'); 151249259Sdim if (ConstraintEnd == E) return true; // "{foo" 152249259Sdim pCodes->push_back(std::string(I, ConstraintEnd+1)); 153249259Sdim I = ConstraintEnd+1; 154249259Sdim } else if (isdigit(static_cast<unsigned char>(*I))) { // Matching Constraint 155249259Sdim // Maximal munch numbers. 156249259Sdim StringRef::iterator NumStart = I; 157249259Sdim while (I != E && isdigit(static_cast<unsigned char>(*I))) 158249259Sdim ++I; 159249259Sdim pCodes->push_back(std::string(NumStart, I)); 160249259Sdim unsigned N = atoi(pCodes->back().c_str()); 161249259Sdim // Check that this is a valid matching constraint! 162249259Sdim if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput|| 163249259Sdim Type != isInput) 164249259Sdim return true; // Invalid constraint number. 165249259Sdim 166249259Sdim // If Operand N already has a matching input, reject this. An output 167249259Sdim // can't be constrained to the same value as multiple inputs. 168249259Sdim if (isMultipleAlternative) { 169249259Sdim InlineAsm::SubConstraintInfo &scInfo = 170249259Sdim ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex]; 171249259Sdim if (scInfo.MatchingInput != -1) 172249259Sdim return true; 173249259Sdim // Note that operand #n has a matching input. 174249259Sdim scInfo.MatchingInput = ConstraintsSoFar.size(); 175249259Sdim } else { 176249259Sdim if (ConstraintsSoFar[N].hasMatchingInput()) 177249259Sdim return true; 178249259Sdim // Note that operand #n has a matching input. 179249259Sdim ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size(); 180249259Sdim } 181249259Sdim } else if (*I == '|') { 182249259Sdim multipleAlternativeIndex++; 183249259Sdim pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes; 184249259Sdim ++I; 185249259Sdim } else if (*I == '^') { 186249259Sdim // Multi-letter constraint 187249259Sdim // FIXME: For now assuming these are 2-character constraints. 188249259Sdim pCodes->push_back(std::string(I+1, I+3)); 189249259Sdim I += 3; 190249259Sdim } else { 191249259Sdim // Single letter constraint. 192249259Sdim pCodes->push_back(std::string(I, I+1)); 193249259Sdim ++I; 194249259Sdim } 195249259Sdim } 196249259Sdim 197249259Sdim return false; 198249259Sdim} 199249259Sdim 200249259Sdim/// selectAlternative - Point this constraint to the alternative constraint 201249259Sdim/// indicated by the index. 202249259Sdimvoid InlineAsm::ConstraintInfo::selectAlternative(unsigned index) { 203249259Sdim if (index < multipleAlternatives.size()) { 204249259Sdim currentAlternativeIndex = index; 205249259Sdim InlineAsm::SubConstraintInfo &scInfo = 206249259Sdim multipleAlternatives[currentAlternativeIndex]; 207249259Sdim MatchingInput = scInfo.MatchingInput; 208249259Sdim Codes = scInfo.Codes; 209249259Sdim } 210249259Sdim} 211249259Sdim 212249259SdimInlineAsm::ConstraintInfoVector 213249259SdimInlineAsm::ParseConstraints(StringRef Constraints) { 214249259Sdim ConstraintInfoVector Result; 215249259Sdim 216249259Sdim // Scan the constraints string. 217249259Sdim for (StringRef::iterator I = Constraints.begin(), 218249259Sdim E = Constraints.end(); I != E; ) { 219249259Sdim ConstraintInfo Info; 220249259Sdim 221249259Sdim // Find the end of this constraint. 222249259Sdim StringRef::iterator ConstraintEnd = std::find(I, E, ','); 223249259Sdim 224249259Sdim if (ConstraintEnd == I || // Empty constraint like ",," 225249259Sdim Info.Parse(StringRef(I, ConstraintEnd-I), Result)) { 226249259Sdim Result.clear(); // Erroneous constraint? 227249259Sdim break; 228249259Sdim } 229249259Sdim 230249259Sdim Result.push_back(Info); 231249259Sdim 232249259Sdim // ConstraintEnd may be either the next comma or the end of the string. In 233249259Sdim // the former case, we skip the comma. 234249259Sdim I = ConstraintEnd; 235249259Sdim if (I != E) { 236249259Sdim ++I; 237249259Sdim if (I == E) { Result.clear(); break; } // don't allow "xyz," 238249259Sdim } 239249259Sdim } 240249259Sdim 241249259Sdim return Result; 242249259Sdim} 243249259Sdim 244249259Sdim/// Verify - Verify that the specified constraint string is reasonable for the 245249259Sdim/// specified function type, and otherwise validate the constraint string. 246249259Sdimbool InlineAsm::Verify(FunctionType *Ty, StringRef ConstStr) { 247249259Sdim if (Ty->isVarArg()) return false; 248249259Sdim 249249259Sdim ConstraintInfoVector Constraints = ParseConstraints(ConstStr); 250249259Sdim 251249259Sdim // Error parsing constraints. 252249259Sdim if (Constraints.empty() && !ConstStr.empty()) return false; 253249259Sdim 254249259Sdim unsigned NumOutputs = 0, NumInputs = 0, NumClobbers = 0; 255249259Sdim unsigned NumIndirect = 0; 256249259Sdim 257249259Sdim for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { 258249259Sdim switch (Constraints[i].Type) { 259249259Sdim case InlineAsm::isOutput: 260249259Sdim if ((NumInputs-NumIndirect) != 0 || NumClobbers != 0) 261249259Sdim return false; // outputs before inputs and clobbers. 262249259Sdim if (!Constraints[i].isIndirect) { 263249259Sdim ++NumOutputs; 264249259Sdim break; 265249259Sdim } 266249259Sdim ++NumIndirect; 267249259Sdim // FALLTHROUGH for Indirect Outputs. 268249259Sdim case InlineAsm::isInput: 269249259Sdim if (NumClobbers) return false; // inputs before clobbers. 270249259Sdim ++NumInputs; 271249259Sdim break; 272249259Sdim case InlineAsm::isClobber: 273249259Sdim ++NumClobbers; 274249259Sdim break; 275249259Sdim } 276249259Sdim } 277249259Sdim 278249259Sdim switch (NumOutputs) { 279249259Sdim case 0: 280249259Sdim if (!Ty->getReturnType()->isVoidTy()) return false; 281249259Sdim break; 282249259Sdim case 1: 283249259Sdim if (Ty->getReturnType()->isStructTy()) return false; 284249259Sdim break; 285249259Sdim default: 286249259Sdim StructType *STy = dyn_cast<StructType>(Ty->getReturnType()); 287249259Sdim if (STy == 0 || STy->getNumElements() != NumOutputs) 288249259Sdim return false; 289249259Sdim break; 290249259Sdim } 291249259Sdim 292249259Sdim if (Ty->getNumParams() != NumInputs) return false; 293249259Sdim return true; 294249259Sdim} 295249259Sdim 296