From 0c58340aead6880876076ee4e3abf3aca92a2647 Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Sat, 28 Apr 2007 20:49:53 +0000 Subject: [PATCH] Significant refactoring of the inline asm stuff, to support future changes. No functionality change. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@36544 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp | 189 ++++++++++-------- 1 file changed, 107 insertions(+), 82 deletions(-) diff --git a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 2cd925187c8..8febf823fa5 100644 --- a/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -3172,85 +3172,109 @@ static std::string GetMostGeneralConstraint(std::vector &C, return *Current; } +namespace { +/// AsmOperandInfo - This contains information for each constraint that we are +/// lowering. +struct AsmOperandInfo : public InlineAsm::ConstraintInfo { + /// ConstraintCode - This contains the actual string for the code, like "m". + std::string ConstraintCode; + + /// CallOperand/CallOperandval - If this is the result output operand or a + /// clobber, this is null, otherwise it is the incoming operand to the + /// CallInst. This gets modified as the asm is processed. + SDOperand CallOperand; + Value *CallOperandVal; + + /// ConstraintVT - The ValueType for the operand value. + MVT::ValueType ConstraintVT; + + AsmOperandInfo(const InlineAsm::ConstraintInfo &info) + : InlineAsm::ConstraintInfo(info), + CallOperand(0,0), CallOperandVal(0), ConstraintVT(MVT::Other) { + } +}; +} // end anon namespace. /// visitInlineAsm - Handle a call to an InlineAsm object. /// void SelectionDAGLowering::visitInlineAsm(CallInst &I) { InlineAsm *IA = cast(I.getOperand(0)); - - SDOperand AsmStr = DAG.getTargetExternalSymbol(IA->getAsmString().c_str(), - MVT::Other); - std::vector Constraints = IA->ParseConstraints(); - std::vector ConstraintVTs; - - /// AsmNodeOperands - A list of pairs. The first element is a register, the - /// second is a bitfield where bit #0 is set if it is a use and bit #1 is set - /// if it is a def of that register. - std::vector AsmNodeOperands; - AsmNodeOperands.push_back(SDOperand()); // reserve space for input chain - AsmNodeOperands.push_back(AsmStr); + /// ConstraintOperands - Information about all of the constraints. + std::vector ConstraintOperands; SDOperand Chain = getRoot(); SDOperand Flag; - // We fully assign registers here at isel time. This is not optimal, but - // should work. For register classes that correspond to LLVM classes, we - // could let the LLVM RA do its thing, but we currently don't. Do a prepass - // over the constraints, collecting fixed registers that we know we can't use. std::set OutputRegs, InputRegs; - unsigned OpNum = 1; - for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { - std::string ConstraintCode = - GetMostGeneralConstraint(Constraints[i].Codes, TLI); + + // Do a prepass over the constraints, canonicalizing them, and building up the + // ConstraintOperands list. + std::vector + ConstraintInfos = IA->ParseConstraints(); + unsigned OpNo = 1; + for (unsigned i = 0, e = ConstraintInfos.size(); i != e; ++i) { + ConstraintOperands.push_back(AsmOperandInfo(ConstraintInfos[i])); + AsmOperandInfo &OpInfo = ConstraintOperands.back(); + + // Compute the constraint code to use. + OpInfo.ConstraintCode = GetMostGeneralConstraint(OpInfo.Codes, TLI); - MVT::ValueType OpVT; + MVT::ValueType OpVT = MVT::Other; - // Compute the value type for each operand and add it to ConstraintVTs. - switch (Constraints[i].Type) { + // Compute the value type for each operand. + switch (OpInfo.Type) { case InlineAsm::isOutput: - if (!Constraints[i].isIndirect) { - // The return value of the call is this value. + if (!OpInfo.isIndirect) { + // The return value of the call is this value. As such, there is no + // corresponding argument. assert(I.getType() != Type::VoidTy && "Bad inline asm!"); OpVT = TLI.getValueType(I.getType()); } else { - const Type *OpTy = I.getOperand(OpNum)->getType(); - OpVT = TLI.getValueType(cast(OpTy)->getElementType(),true); - OpNum++; // Consumes a call operand. + OpInfo.CallOperandVal = I.getOperand(OpNo++); } break; case InlineAsm::isInput: - if (!Constraints[i].isIndirect) { - OpVT = TLI.getValueType(I.getOperand(OpNum)->getType()); - } else { - const Type *OpTy = I.getOperand(OpNum)->getType(); - OpVT = TLI.getValueType(cast(OpTy)->getElementType(),true); - } - OpNum++; // Consumes a call operand. + OpInfo.CallOperandVal = I.getOperand(OpNo++); break; case InlineAsm::isClobber: - OpVT = MVT::Other; + // Nothing to do. break; } + + // If this is an input or an indirect output, process the call argument. + if (OpInfo.CallOperandVal) { + OpInfo.CallOperand = getValue(OpInfo.CallOperandVal); + const Type *OpTy = OpInfo.CallOperandVal->getType(); + if (!OpInfo.isIndirect) { + // Must be an input. + OpVT = TLI.getValueType(OpTy); + } else { + OpVT = TLI.getValueType(cast(OpTy)->getElementType(),true); + } + } - ConstraintVTs.push_back(OpVT); + OpInfo.ConstraintVT = OpVT; - if (TLI.getRegForInlineAsmConstraint(ConstraintCode, OpVT).first == 0) + if (TLI.getRegForInlineAsmConstraint(OpInfo.ConstraintCode, OpVT).first ==0) continue; // Not assigned a fixed reg. + // For GCC register classes where we don't have a direct match, we fully + // assign registers at isel time. This is not optimal, but works. + // Build a list of regs that this operand uses. This always has a single // element for promoted/expanded operands. - RegsForValue Regs = GetRegistersForValue(ConstraintCode, OpVT, + RegsForValue Regs = GetRegistersForValue(OpInfo.ConstraintCode, OpVT, false, false, OutputRegs, InputRegs); - switch (Constraints[i].Type) { + switch (OpInfo.Type) { case InlineAsm::isOutput: // We can't assign any other output to this register. OutputRegs.insert(Regs.Regs.begin(), Regs.Regs.end()); // If this is an early-clobber output, it cannot be assigned to the same // value as the input reg. - if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput) + if (OpInfo.isEarlyClobber || OpInfo.hasMatchingInput) InputRegs.insert(Regs.Regs.begin(), Regs.Regs.end()); break; case InlineAsm::isInput: @@ -3263,44 +3287,45 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { OutputRegs.insert(Regs.Regs.begin(), Regs.Regs.end()); break; } - } + } + + ConstraintInfos.clear(); + + + // AsmNodeOperands - The operands for the ISD::INLINEASM node. + std::vector AsmNodeOperands; + AsmNodeOperands.push_back(SDOperand()); // reserve space for input chain + AsmNodeOperands.push_back( + DAG.getTargetExternalSymbol(IA->getAsmString().c_str(), MVT::Other)); + // Loop over all of the inputs, copying the operand values into the // appropriate registers and processing the output regs. RegsForValue RetValRegs; + + // IndirectStoresToEmit - The set of stores to emit after the inline asm node. std::vector > IndirectStoresToEmit; - OpNum = 1; - for (unsigned i = 0, e = Constraints.size(); i != e; ++i) { - std::string ConstraintCode = - GetMostGeneralConstraint(Constraints[i].Codes, TLI); + for (unsigned i = 0, e = ConstraintOperands.size(); i != e; ++i) { + AsmOperandInfo &OpInfo = ConstraintOperands[i]; - switch (Constraints[i].Type) { + switch (OpInfo.Type) { case InlineAsm::isOutput: { TargetLowering::ConstraintType CTy = TargetLowering::C_RegisterClass; - if (ConstraintCode.size() == 1) // not a physreg name. - CTy = TLI.getConstraintType(ConstraintCode); + if (OpInfo.ConstraintCode.size() == 1) // not a physreg name. + CTy = TLI.getConstraintType(OpInfo.ConstraintCode); if (CTy != TargetLowering::C_RegisterClass) { // Memory output, or 'other' output (e.g. 'X' constraint). - SDOperand InOperandVal = getValue(I.getOperand(OpNum)); + SDOperand InOperandVal = OpInfo.CallOperand; // Check that the operand (the address to store to) isn't a float. if (!MVT::isInteger(InOperandVal.getValueType())) assert(0 && "MATCH FAIL!"); - if (!Constraints[i].isIndirect) + if (!OpInfo.isIndirect) assert(0 && "MATCH FAIL!"); - OpNum++; // Consumes a call operand. - - // Extend/truncate to the right pointer type if needed. - MVT::ValueType PtrType = TLI.getPointerTy(); - if (InOperandVal.getValueType() < PtrType) - InOperandVal = DAG.getNode(ISD::ZERO_EXTEND, PtrType, InOperandVal); - else if (InOperandVal.getValueType() > PtrType) - InOperandVal = DAG.getNode(ISD::TRUNCATE, PtrType, InOperandVal); - // Add information to the INLINEASM node to know about this output. unsigned ResOpType = 4/*MEM*/ | (1 << 3); AsmNodeOperands.push_back(DAG.getConstant(ResOpType, MVT::i32)); @@ -3315,30 +3340,30 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { // constraint that matches this, we need to reserve the input register // so no other inputs allocate to it. bool UsesInputRegister = false; - if (Constraints[i].isEarlyClobber || Constraints[i].hasMatchingInput) + if (OpInfo.isEarlyClobber || OpInfo.hasMatchingInput) UsesInputRegister = true; // Copy the output from the appropriate register. Find a register that // we can use. RegsForValue Regs = - GetRegistersForValue(ConstraintCode, ConstraintVTs[i], + GetRegistersForValue(OpInfo.ConstraintCode, OpInfo.ConstraintVT, true, UsesInputRegister, OutputRegs, InputRegs); if (Regs.Regs.empty()) { cerr << "Couldn't allocate output reg for contraint '" - << ConstraintCode << "'!\n"; + << OpInfo.ConstraintCode << "'!\n"; exit(1); } - if (!Constraints[i].isIndirect) { + if (!OpInfo.isIndirect) { + // This is the result value of the call. assert(RetValRegs.Regs.empty() && "Cannot have multiple output constraints yet!"); assert(I.getType() != Type::VoidTy && "Bad inline asm!"); RetValRegs = Regs; } else { - IndirectStoresToEmit.push_back(std::make_pair(Regs, - I.getOperand(OpNum))); - OpNum++; // Consumes a call operand. + IndirectStoresToEmit.push_back(std::make_pair(Regs, + OpInfo.CallOperandVal)); } // Add information to the INLINEASM node to know that this register is @@ -3347,13 +3372,12 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { break; } case InlineAsm::isInput: { - SDOperand InOperandVal = getValue(I.getOperand(OpNum)); - OpNum++; // Consumes a call operand. + SDOperand InOperandVal = OpInfo.CallOperand; - if (isdigit(ConstraintCode[0])) { // Matching constraint? + if (isdigit(OpInfo.ConstraintCode[0])) { // Matching constraint? // If this is required to match an output register we have already set, // just use its register. - unsigned OperandNo = atoi(ConstraintCode.c_str()); + unsigned OperandNo = atoi(OpInfo.ConstraintCode.c_str()); // Scan until we find the definition we already emitted of this operand. // When we find it, create a RegsForValue operand. @@ -3393,18 +3417,19 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { } TargetLowering::ConstraintType CTy = TargetLowering::C_RegisterClass; - if (ConstraintCode.size() == 1) // not a physreg name. - CTy = TLI.getConstraintType(ConstraintCode); + if (OpInfo.ConstraintCode.size() == 1) // not a physreg name. + CTy = TLI.getConstraintType(OpInfo.ConstraintCode); if (CTy == TargetLowering::C_Other) { - assert(!Constraints[i].isIndirect && + assert(!OpInfo.isIndirect && "Don't know how to handle indirect other inputs yet!"); InOperandVal = TLI.isOperandValidForConstraint(InOperandVal, - ConstraintCode[0], DAG); + OpInfo.ConstraintCode[0], + DAG); if (!InOperandVal.Val) { cerr << "Invalid operand for inline asm constraint '" - << ConstraintCode << "'!\n"; + << OpInfo.ConstraintCode << "'!\n"; exit(1); } @@ -3418,10 +3443,10 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { // so we want an indirect input. If we don't have an indirect input, // spill the value somewhere if we can, otherwise spill it to a stack // slot. - if (!Constraints[i].isIndirect) { + if (!OpInfo.isIndirect) { // If the operand is a float, integer, or vector constant, spill to a // constant pool entry to get its address. - Value *OpVal = I.getOperand(OpNum-1); + Value *OpVal = OpInfo.CallOperandVal; if (isa(OpVal) || isa(OpVal) || isa(OpVal)) { InOperandVal = DAG.getConstantPool(cast(OpVal), @@ -3451,12 +3476,12 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { } assert(CTy == TargetLowering::C_RegisterClass && "Unknown op type!"); - assert(!Constraints[i].isIndirect && + assert(!OpInfo.isIndirect && "Don't know how to handle indirect register inputs yet!"); // Copy the input into the appropriate registers. RegsForValue InRegs = - GetRegistersForValue(ConstraintCode, ConstraintVTs[i], + GetRegistersForValue(OpInfo.ConstraintCode, OpInfo.ConstraintVT, false, true, OutputRegs, InputRegs); // FIXME: should be match fail. assert(!InRegs.Regs.empty() && "Couldn't allocate input reg!"); @@ -3468,7 +3493,7 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { } case InlineAsm::isClobber: { RegsForValue ClobberedRegs = - GetRegistersForValue(ConstraintCode, MVT::Other, false, false, + GetRegistersForValue(OpInfo.ConstraintCode, MVT::Other, false, false, OutputRegs, InputRegs); // Add the clobbered value to the operand list, so that the register // allocator is aware that the physreg got clobbered. @@ -3523,7 +3548,7 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) { // Emit the non-flagged stores from the physregs. SmallVector OutChains; for (unsigned i = 0, e = StoresToEmit.size(); i != e; ++i) - OutChains.push_back(DAG.getStore(Chain, StoresToEmit[i].first, + OutChains.push_back(DAG.getStore(Chain, StoresToEmit[i].first, getValue(StoresToEmit[i].second), StoresToEmit[i].second, 0)); if (!OutChains.empty()) -- 2.34.1