diff --git a/include/llvm/InlineAsm.h b/include/llvm/InlineAsm.h index 105b1bcd94c..0cb55b7f6e3 100644 --- a/include/llvm/InlineAsm.h +++ b/include/llvm/InlineAsm.h @@ -87,6 +87,19 @@ public: isClobber // '~x' }; + struct SubConstraintInfo { + /// MatchingInput - If this is not -1, this is an output constraint where an + /// input constraint is required to match it (e.g. "0"). The value is the + /// constraint number that matches this one (for example, if this is + /// constraint #0 and constraint #4 has the value "0", this will be 4). + signed char MatchingInput; + /// Code - The constraint code, either the register name (in braces) or the + /// constraint letter/number. + std::vector Codes; + /// Default constructor. + SubConstraintInfo() : MatchingInput(-1) {} + }; + struct ConstraintInfo { /// Type - The basic type of the constraint: input/output/clobber /// @@ -120,11 +133,31 @@ public: /// constraint letter/number. std::vector Codes; + /// isMultipleAlternative - '|': has multiple-alternative constraints. + bool isMultipleAlternative; + + /// multipleAlternatives - If there are multiple alternative constraints, + /// this array will contain them. Otherwise it will be empty. + std::vector multipleAlternatives; + + /// The currently selected alternative constraint index. + unsigned currentAlternativeIndex; + + ///Default constructor. + ConstraintInfo(); + + /// Copy constructor. + ConstraintInfo(const ConstraintInfo &other); + /// Parse - Analyze the specified string (e.g. "=*&{eax}") and fill in the /// fields in this structure. If the constraint string is not understood, /// return true, otherwise return false. bool Parse(StringRef Str, std::vector &ConstraintsSoFar); + + /// selectAlternative - Point this constraint to the alternative constraint + /// indicated by the index. + void selectAlternative(unsigned index); }; /// ParseConstraints - Split up the constraint string into the specific diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index 29de994a21c..73ab11a2540 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -45,6 +45,7 @@ namespace llvm { class Function; class FastISel; class FunctionLoweringInfo; + class ImmutableCallSite; class MachineBasicBlock; class MachineFunction; class MachineFrameInfo; @@ -1356,12 +1357,42 @@ public: /// returns the output operand it matches. unsigned getMatchedOperand() const; + /// Copy constructor for copying from an AsmOperandInfo. + AsmOperandInfo(const AsmOperandInfo &info) + : InlineAsm::ConstraintInfo(info), + ConstraintCode(info.ConstraintCode), + ConstraintType(info.ConstraintType), + CallOperandVal(info.CallOperandVal), + ConstraintVT(info.ConstraintVT) { + } + + /// Copy constructor for copying from a ConstraintInfo. AsmOperandInfo(const InlineAsm::ConstraintInfo &info) : InlineAsm::ConstraintInfo(info), ConstraintType(TargetLowering::C_Unknown), CallOperandVal(0), ConstraintVT(MVT::Other) { } }; + + /// ParseConstraints - Split up the constraint string from the inline + /// assembly value into the specific constraints and their prefixes, + /// and also tie in the associated operand values. + /// If this returns an empty vector, and if the constraint string itself + /// isn't empty, there was an error parsing. + virtual std::vector ParseConstraints( + ImmutableCallSite CS) const; + + /// Examine constraint type and operand type and determine a weight value, + /// where: -1 = invalid match, and 0 = so-so match to 5 = good match. + /// The operand object must already have been set up with the operand type. + virtual int getMultipleConstraintMatchWeight( + AsmOperandInfo &info, int maIndex) const; + + /// Examine constraint string and operand type and determine a weight value, + /// where: -1 = invalid match, and 0 = so-so match to 3 = good match. + /// The operand object must already have been set up with the operand type. + virtual int getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const; /// ComputeConstraintToUse - Determines the constraint code and constraint /// type to use for the specific AsmOperandInfo, setting diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp index e65744592c8..1e77a66a066 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -5008,7 +5008,7 @@ public: /// contains the set of register corresponding to the operand. RegsForValue AssignedRegs; - explicit SDISelAsmOperandInfo(const InlineAsm::ConstraintInfo &info) + explicit SDISelAsmOperandInfo(const TargetLowering::AsmOperandInfo &info) : TargetLowering::AsmOperandInfo(info), CallOperand(0,0) { } @@ -5069,7 +5069,7 @@ public: return TLI.getValueType(OpTy, true); } - + private: /// MarkRegAndAliases - Mark the specified register and all aliases in the /// specified set. @@ -5324,28 +5324,15 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { std::set OutputRegs, InputRegs; - // Do a prepass over the constraints, canonicalizing them, and building up the - // ConstraintOperands list. - std::vector - ConstraintInfos = IA->ParseConstraints(); - - bool hasMemory = hasInlineAsmMemConstraint(ConstraintInfos, TLI); - - SDValue Chain, Flag; - - // We won't need to flush pending loads if this asm doesn't touch - // memory and is nonvolatile. - if (hasMemory || IA->hasSideEffects()) - Chain = getRoot(); - else - Chain = DAG.getRoot(); - + std::vector TargetConstraints = TLI.ParseConstraints(CS); + bool hasMemory = false; + unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. unsigned ResNo = 0; // ResNo - The result number of the next output. - for (unsigned i = 0, e = ConstraintInfos.size(); i != e; ++i) { - ConstraintOperands.push_back(SDISelAsmOperandInfo(ConstraintInfos[i])); + for (unsigned i = 0, e = TargetConstraints.size(); i != e; ++i) { + ConstraintOperands.push_back(SDISelAsmOperandInfo(TargetConstraints[i])); SDISelAsmOperandInfo &OpInfo = ConstraintOperands.back(); - + EVT OpVT = MVT::Other; // Compute the value type for each operand. @@ -5393,33 +5380,35 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { } OpInfo.ConstraintVT = OpVT; + + // Indirect operand accesses access memory. + if (OpInfo.isIndirect) + hasMemory = true; + else { + for (unsigned j = 0, ee = OpInfo.Codes.size(); j != ee; ++j) { + TargetLowering::ConstraintType CType = TLI.getConstraintType(OpInfo.Codes[j]); + if (CType == TargetLowering::C_Memory) { + hasMemory = true; + break; + } + } + } } + SDValue Chain, Flag; + + // We won't need to flush pending loads if this asm doesn't touch + // memory and is nonvolatile. + if (hasMemory || IA->hasSideEffects()) + Chain = getRoot(); + else + Chain = DAG.getRoot(); + // Second pass over the constraints: compute which constraint option to use // and assign registers to constraints that want a specific physreg. - for (unsigned i = 0, e = ConstraintInfos.size(); i != e; ++i) { + for (unsigned i = 0, e = ConstraintOperands.size(); i != e; ++i) { SDISelAsmOperandInfo &OpInfo = ConstraintOperands[i]; - // If this is an output operand with a matching input operand, look up the - // matching input. If their types mismatch, e.g. one is an integer, the - // other is floating point, or their sizes are different, flag it as an - // error. - if (OpInfo.hasMatchingInput()) { - SDISelAsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; - - if (OpInfo.ConstraintVT != Input.ConstraintVT) { - if ((OpInfo.ConstraintVT.isInteger() != - Input.ConstraintVT.isInteger()) || - (OpInfo.ConstraintVT.getSizeInBits() != - Input.ConstraintVT.getSizeInBits())) { - report_fatal_error("Unsupported asm: input constraint" - " with a matching output constraint of" - " incompatible type!"); - } - Input.ConstraintVT = OpInfo.ConstraintVT; - } - } - // Compute the constraint code and ConstraintType to use. TLI.ComputeConstraintToUse(OpInfo, OpInfo.CallOperand, &DAG); @@ -5427,7 +5416,7 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { // need to to provide an address for the memory input. if (OpInfo.ConstraintType == TargetLowering::C_Memory && !OpInfo.isIndirect) { - assert(OpInfo.Type == InlineAsm::isInput && + assert((OpInfo.isMultipleAlternative || (OpInfo.Type == InlineAsm::isInput)) && "Can only indirectify direct input operands!"); // Memory operands really want the address of the value. If we don't have @@ -5469,8 +5458,6 @@ void SelectionDAGBuilder::visitInlineAsm(ImmutableCallSite CS) { GetRegistersForValue(OpInfo, OutputRegs, InputRegs); } - ConstraintInfos.clear(); - // Second pass - Loop over all of the operands, assigning virtual or physregs // to register class operands. for (unsigned i = 0, e = ConstraintOperands.size(); i != e; ++i) { diff --git a/lib/CodeGen/SelectionDAG/TargetLowering.cpp b/lib/CodeGen/SelectionDAG/TargetLowering.cpp index b74f600cfa2..419784d47a4 100644 --- a/lib/CodeGen/SelectionDAG/TargetLowering.cpp +++ b/lib/CodeGen/SelectionDAG/TargetLowering.cpp @@ -2654,6 +2654,156 @@ unsigned TargetLowering::AsmOperandInfo::getMatchedOperand() const { return atoi(ConstraintCode.c_str()); } + +/// ParseConstraints - Split up the constraint string from the inline +/// assembly value into the specific constraints and their prefixes, +/// and also tie in the associated operand values. +/// If this returns an empty vector, and if the constraint string itself +/// isn't empty, there was an error parsing. +std::vector TargetLowering::ParseConstraints( + ImmutableCallSite CS) const { + /// ConstraintOperands - Information about all of the constraints. + std::vector ConstraintOperands; + const InlineAsm *IA = cast(CS.getCalledValue()); + + // Do a prepass over the constraints, canonicalizing them, and building up the + // ConstraintOperands list. + std::vector + ConstraintInfos = IA->ParseConstraints(); + + unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. + unsigned ResNo = 0; // ResNo - The result number of the next output. + + for (unsigned i = 0, e = ConstraintInfos.size(); i != e; ++i) { + ConstraintOperands.push_back(AsmOperandInfo(ConstraintInfos[i])); + AsmOperandInfo &OpInfo = ConstraintOperands.back(); + + EVT OpVT = MVT::Other; + + // Compute the value type for each operand. + switch (OpInfo.Type) { + case InlineAsm::isOutput: + // Indirect outputs just consume an argument. + if (OpInfo.isIndirect) { + OpInfo.CallOperandVal = const_cast(CS.getArgument(ArgNo++)); + break; + } + + // The return value of the call is this value. As such, there is no + // corresponding argument. + assert(!CS.getType()->isVoidTy() && + "Bad inline asm!"); + if (const StructType *STy = dyn_cast(CS.getType())) { + OpVT = getValueType(STy->getElementType(ResNo)); + } else { + assert(ResNo == 0 && "Asm only has one result!"); + OpVT = getValueType(CS.getType()); + } + ++ResNo; + break; + case InlineAsm::isInput: + OpInfo.CallOperandVal = const_cast(CS.getArgument(ArgNo++)); + break; + case InlineAsm::isClobber: + // Nothing to do. + break; + } + } + + // If we have multiple alternative constraints, select the best alternative. + if (ConstraintInfos.size()) { + unsigned maCount = ConstraintInfos[0].multipleAlternatives.size(); + if (maCount) { + unsigned bestMAIndex = 0; + int bestWeight = -1; + // weight: -1 = invalid match, and 0 = so-so match to 5 = good match. + int weight = -1; + unsigned maIndex; + // Compute the sums of the weights for each alternative, keeping track + // of the best (highest weight) one so far. + for (maIndex = 0; maIndex < maCount; ++maIndex) { + int weightSum = 0; + for (unsigned cIndex = 0, eIndex = ConstraintOperands.size(); + cIndex != eIndex; ++cIndex) { + AsmOperandInfo& OpInfo = ConstraintOperands[cIndex]; + if (OpInfo.Type == InlineAsm::isClobber) + continue; + assert((OpInfo.multipleAlternatives.size() == maCount) + && "Constraint has inconsistent multiple alternative count."); + + // If this is an output operand with a matching input operand, look up the + // matching input. If their types mismatch, e.g. one is an integer, the + // other is floating point, or their sizes are different, flag it as an + // maCantMatch. + if (OpInfo.hasMatchingInput()) { + AsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; + + if (OpInfo.ConstraintVT != Input.ConstraintVT) { + if ((OpInfo.ConstraintVT.isInteger() != + Input.ConstraintVT.isInteger()) || + (OpInfo.ConstraintVT.getSizeInBits() != + Input.ConstraintVT.getSizeInBits())) { + weightSum = -1; // Can't match. + break; + } + Input.ConstraintVT = OpInfo.ConstraintVT; + } + } + + weight = getMultipleConstraintMatchWeight(OpInfo, maIndex); + if (weight == -1) { + weightSum = -1; + break; + } + weightSum += weight; + } + // Update best. + if (weightSum > bestWeight) { + bestWeight = weightSum; + bestMAIndex = maIndex; + } + } + + // Now select chosen alternative in each constraint. + for (unsigned cIndex = 0, eIndex = ConstraintOperands.size(); + cIndex != eIndex; ++cIndex) { + AsmOperandInfo& cInfo = ConstraintOperands[cIndex]; + if (cInfo.Type == InlineAsm::isClobber) + continue; + cInfo.selectAlternative(bestMAIndex); + } + } + } + + // Check and hook up tied operands, choose constraint code to use. + for (unsigned cIndex = 0, eIndex = ConstraintOperands.size(); + cIndex != eIndex; ++cIndex) { + AsmOperandInfo& OpInfo = ConstraintOperands[cIndex]; + + // If this is an output operand with a matching input operand, look up the + // matching input. If their types mismatch, e.g. one is an integer, the + // other is floating point, or their sizes are different, flag it as an + // error. + if (OpInfo.hasMatchingInput()) { + AsmOperandInfo &Input = ConstraintOperands[OpInfo.MatchingInput]; + + if (OpInfo.ConstraintVT != Input.ConstraintVT) { + if ((OpInfo.ConstraintVT.isInteger() != + Input.ConstraintVT.isInteger()) || + (OpInfo.ConstraintVT.getSizeInBits() != + Input.ConstraintVT.getSizeInBits())) { + report_fatal_error("Unsupported asm: input constraint" + " with a matching output constraint of" + " incompatible type!"); + } + Input.ConstraintVT = OpInfo.ConstraintVT; + } + } + } + + return ConstraintOperands; +} + /// getConstraintGenerality - Return an integer indicating how general CT /// is. @@ -2672,6 +2822,76 @@ static unsigned getConstraintGenerality(TargetLowering::ConstraintType CT) { } } +/// Examine constraint type and operand type and determine a weight value, +/// where: -1 = invalid match, and 0 = so-so match to 3 = good match. +/// This object must already have been set up with the operand type +/// and the current alternative constraint selected. +int TargetLowering::getMultipleConstraintMatchWeight( + AsmOperandInfo &info, int maIndex) const { + std::vector &rCodes = info.multipleAlternatives[maIndex].Codes; + int matchingInput = info.multipleAlternatives[maIndex].MatchingInput; + TargetLowering::ConstraintType BestType = TargetLowering::C_Unknown; + int BestWeight = -1; + + // Loop over the options, keeping track of the most general one. + for (unsigned i = 0, e = rCodes.size(); i != e; ++i) { + int weight = getSingleConstraintMatchWeight(info, rCodes[i].c_str()); + if (weight > BestWeight) + BestWeight = weight; + } + + return BestWeight; +} + +/// Examine constraint type and operand type and determine a weight value, +/// where: -1 = invalid match, and 0 = so-so match to 3 = good match. +/// This object must already have been set up with the operand type +/// and the current alternative constraint selected. +int TargetLowering::getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const { + int weight = -1; + Value *CallOperandVal = info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (CallOperandVal == NULL) + return 0; + // Look at the constraint type. + switch (*constraint) { + case 'i': // immediate integer. + case 'n': // immediate integer with a known value. + weight = 0; + if (info.CallOperandVal) { + if (isa(info.CallOperandVal)) + weight = 3; + else + weight = -1; + } + break; + case 's': // non-explicit intregal immediate. + weight = 0; + if (info.CallOperandVal) { + if (isa(info.CallOperandVal)) + weight = 3; + else + weight = -1; + } + break; + case 'm': // memory operand. + case 'o': // offsettable memory operand + case 'V': // non-offsettable memory operand + weight = 2; + break; + case 'g': // general register, memory operand or immediate integer. + case 'X': // any operand. + weight = 1; + break; + default: + weight = 0; + break; + } + return weight; +} + /// ChooseConstraint - If there are multiple different constraints that we /// could pick for this operand (e.g. "imr") try to pick the 'best' one. /// This is somewhat tricky: constraints fall into four classes: diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index b1ce35ac523..797c2fcf805 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -11193,6 +11193,34 @@ X86TargetLowering::getConstraintType(const std::string &Constraint) const { return TargetLowering::getConstraintType(Constraint); } +/// Examine constraint type and operand type and determine a weight value, +/// where: -1 = invalid match, and 0 = so-so match to 3 = good match. +/// This object must already have been set up with the operand type +/// and the current alternative constraint selected. +int X86TargetLowering::getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const { + int weight = -1; + Value *CallOperandVal = info.CallOperandVal; + // If we don't have a value, we can't do a match, + // but allow it at the lowest weight. + if (CallOperandVal == NULL) + return 0; + // Look at the constraint type. + switch (*constraint) { + default: + return TargetLowering::getSingleConstraintMatchWeight(info, constraint); + break; + case 'I': + if (ConstantInt *C = dyn_cast(info.CallOperandVal)) { + if (C->getZExtValue() <= 31) + weight = 3; + } + break; + // etc. + } + return weight; +} + /// LowerXConstraint - try to replace an X constraint, which matches anything, /// with another that has more specific requirements based on the type of the /// corresponding operand. diff --git a/lib/Target/X86/X86ISelLowering.h b/lib/Target/X86/X86ISelLowering.h index d2d9b28a039..6e6f25c93a9 100644 --- a/lib/Target/X86/X86ISelLowering.h +++ b/lib/Target/X86/X86ISelLowering.h @@ -531,6 +531,12 @@ namespace llvm { virtual bool ExpandInlineAsm(CallInst *CI) const; ConstraintType getConstraintType(const std::string &Constraint) const; + + /// Examine constraint string and operand type and determine a weight value, + /// where: -1 = invalid match, and 0 = so-so match to 3 = good match. + /// The operand object must already have been set up with the operand type. + virtual int getSingleConstraintMatchWeight( + AsmOperandInfo &info, const char *constraint) const; std::vector getRegClassForInlineAsmConstraint(const std::string &Constraint, diff --git a/lib/Transforms/Scalar/CodeGenPrepare.cpp b/lib/Transforms/Scalar/CodeGenPrepare.cpp index e07b761e589..8c3f574b4ce 100644 --- a/lib/Transforms/Scalar/CodeGenPrepare.cpp +++ b/lib/Transforms/Scalar/CodeGenPrepare.cpp @@ -738,33 +738,10 @@ bool CodeGenPrepare::OptimizeInlineAsmInst(Instruction *I, CallSite CS, bool MadeChange = false; InlineAsm *IA = cast(CS.getCalledValue()); - // Do a prepass over the constraints, canonicalizing them, and building up the - // ConstraintOperands list. - std::vector - ConstraintInfos = IA->ParseConstraints(); - - /// ConstraintOperands - Information about all of the constraints. - std::vector ConstraintOperands; - unsigned ArgNo = 0; // ArgNo - The argument of the CallInst. - for (unsigned i = 0, e = ConstraintInfos.size(); i != e; ++i) { - ConstraintOperands. - push_back(TargetLowering::AsmOperandInfo(ConstraintInfos[i])); - TargetLowering::AsmOperandInfo &OpInfo = ConstraintOperands.back(); - - // Compute the value type for each operand. - switch (OpInfo.Type) { - case InlineAsm::isOutput: - if (OpInfo.isIndirect) - OpInfo.CallOperandVal = CS.getArgument(ArgNo++); - break; - case InlineAsm::isInput: - OpInfo.CallOperandVal = CS.getArgument(ArgNo++); - break; - case InlineAsm::isClobber: - // Nothing to do. - break; - } - + std::vector TargetConstraints = TLI->ParseConstraints(CS); + for (unsigned i = 0, e = TargetConstraints.size(); i != e; ++i) { + TargetLowering::AsmOperandInfo &OpInfo = TargetConstraints[i]; + // Compute the constraint code and ConstraintType to use. TLI->ComputeConstraintToUse(OpInfo, SDValue()); diff --git a/lib/Transforms/Utils/AddrModeMatcher.cpp b/lib/Transforms/Utils/AddrModeMatcher.cpp index 4d64c8578ef..b803521e871 100644 --- a/lib/Transforms/Utils/AddrModeMatcher.cpp +++ b/lib/Transforms/Utils/AddrModeMatcher.cpp @@ -21,6 +21,7 @@ #include "llvm/Support/GetElementPtrTypeIterator.h" #include "llvm/Support/PatternMatch.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Support/CallSite.h" using namespace llvm; using namespace llvm::PatternMatch; @@ -379,27 +380,10 @@ bool AddressingModeMatcher::MatchAddr(Value *Addr, unsigned Depth) { /// return false. static bool IsOperandAMemoryOperand(CallInst *CI, InlineAsm *IA, Value *OpVal, const TargetLowering &TLI) { - std::vector - Constraints = IA->ParseConstraints(); - - unsigned ArgNo = 0; // The argument of the CallInst. - for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { - TargetLowering::AsmOperandInfo OpInfo(Constraints[i]); - - // Compute the value type for each operand. - switch (OpInfo.Type) { - case InlineAsm::isOutput: - if (OpInfo.isIndirect) - OpInfo.CallOperandVal = CI->getArgOperand(ArgNo++); - break; - case InlineAsm::isInput: - OpInfo.CallOperandVal = CI->getArgOperand(ArgNo++); - break; - case InlineAsm::isClobber: - // Nothing to do. - break; - } - + std::vector TargetConstraints = TLI.ParseConstraints(ImmutableCallSite(CI)); + for (unsigned i = 0, e = TargetConstraints.size(); i != e; ++i) { + TargetLowering::AsmOperandInfo &OpInfo = TargetConstraints[i]; + // Compute the constraint code and ConstraintType to use. TLI.ComputeConstraintToUse(OpInfo, SDValue()); diff --git a/lib/VMCore/InlineAsm.cpp b/lib/VMCore/InlineAsm.cpp index 69f713b2c42..814b31aeb38 100644 --- a/lib/VMCore/InlineAsm.cpp +++ b/lib/VMCore/InlineAsm.cpp @@ -53,6 +53,24 @@ void InlineAsm::destroyConstant() { const FunctionType *InlineAsm::getFunctionType() const { return cast(getType()->getElementType()); } + +///Default constructor. +InlineAsm::ConstraintInfo::ConstraintInfo() : + isMultipleAlternative(false), + Type(isInput), isEarlyClobber(false), + MatchingInput(-1), isCommutative(false), + isIndirect(false), currentAlternativeIndex(0) { +} + +/// Copy constructor. +InlineAsm::ConstraintInfo::ConstraintInfo(const ConstraintInfo &other) : + isMultipleAlternative(other.isMultipleAlternative), + Type(other.Type), isEarlyClobber(other.isEarlyClobber), + MatchingInput(other.MatchingInput), isCommutative(other.isCommutative), + isIndirect(other.isIndirect), Codes(other.Codes), + multipleAlternatives(other.multipleAlternatives), + currentAlternativeIndex(other.currentAlternativeIndex) { +} /// Parse - Analyze the specified string (e.g. "==&{eax}") and fill in the /// fields in this structure. If the constraint string is not understood, @@ -60,13 +78,22 @@ const FunctionType *InlineAsm::getFunctionType() const { bool InlineAsm::ConstraintInfo::Parse(StringRef Str, std::vector &ConstraintsSoFar) { StringRef::iterator I = Str.begin(), E = Str.end(); + unsigned multipleAlternativeCount = Str.count('|') + 1; + unsigned multipleAlternativeIndex = 0; + std::vector *pCodes = &Codes; // Initialize + isMultipleAlternative = (multipleAlternativeCount > 1 ? true : false); + if (isMultipleAlternative) { + multipleAlternatives.resize(multipleAlternativeCount); + pCodes = &multipleAlternatives[0].Codes; + } Type = isInput; isEarlyClobber = false; MatchingInput = -1; isCommutative = false; isIndirect = false; + currentAlternativeIndex = 0; // Parse prefixes. if (*I == '~') { @@ -120,15 +147,15 @@ bool InlineAsm::ConstraintInfo::Parse(StringRef Str, // Find the end of the register name. StringRef::iterator ConstraintEnd = std::find(I+1, E, '}'); if (ConstraintEnd == E) return true; // "{foo" - Codes.push_back(std::string(I, ConstraintEnd+1)); + pCodes->push_back(std::string(I, ConstraintEnd+1)); I = ConstraintEnd+1; } else if (isdigit(*I)) { // Matching Constraint // Maximal munch numbers. StringRef::iterator NumStart = I; while (I != E && isdigit(*I)) ++I; - Codes.push_back(std::string(NumStart, I)); - unsigned N = atoi(Codes.back().c_str()); + pCodes->push_back(std::string(NumStart, I)); + unsigned N = atoi(pCodes->back().c_str()); // Check that this is a valid matching constraint! if (N >= ConstraintsSoFar.size() || ConstraintsSoFar[N].Type != isOutput|| Type != isInput) @@ -136,14 +163,26 @@ bool InlineAsm::ConstraintInfo::Parse(StringRef Str, // If Operand N already has a matching input, reject this. An output // can't be constrained to the same value as multiple inputs. - if (ConstraintsSoFar[N].hasMatchingInput()) - return true; - - // Note that operand #n has a matching input. - ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size(); + if (isMultipleAlternative) { + InlineAsm::SubConstraintInfo &scInfo = + ConstraintsSoFar[N].multipleAlternatives[multipleAlternativeIndex]; + if (scInfo.MatchingInput != -1) + return true; + // Note that operand #n has a matching input. + scInfo.MatchingInput = ConstraintsSoFar.size(); + } else { + if (ConstraintsSoFar[N].hasMatchingInput()) + return true; + // Note that operand #n has a matching input. + ConstraintsSoFar[N].MatchingInput = ConstraintsSoFar.size(); + } + } else if (*I == '|') { + multipleAlternativeIndex++; + pCodes = &multipleAlternatives[multipleAlternativeIndex].Codes; + ++I; } else { // Single letter constraint. - Codes.push_back(std::string(I, I+1)); + pCodes->push_back(std::string(I, I+1)); ++I; } } @@ -151,6 +190,18 @@ bool InlineAsm::ConstraintInfo::Parse(StringRef Str, return false; } +/// selectAlternative - Point this constraint to the alternative constraint +/// indicated by the index. +void InlineAsm::ConstraintInfo::selectAlternative(unsigned index) { + if (index < multipleAlternatives.size()) { + currentAlternativeIndex = index; + InlineAsm::SubConstraintInfo &scInfo = + multipleAlternatives[currentAlternativeIndex]; + MatchingInput = scInfo.MatchingInput; + Codes = scInfo.Codes; + } +} + std::vector InlineAsm::ParseConstraints(StringRef Constraints) { std::vector Result; @@ -183,7 +234,6 @@ InlineAsm::ParseConstraints(StringRef Constraints) { return Result; } - /// Verify - Verify that the specified constraint string is reasonable for the /// specified function type, and otherwise validate the constraint string. bool InlineAsm::Verify(const FunctionType *Ty, StringRef ConstStr) {