Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -7088,10 +7088,11 @@ /// uses features that we can't model on machineinstrs, we have SDISel do the /// allocation. This produces generally horrible, but correct, code. /// -/// OpInfo describes the operand. +/// OpInfo describes the operand +/// RefOpInfo describes the matching operand if any, the operand otherwise static void GetRegistersForValue(SelectionDAG &DAG, const TargetLowering &TLI, - const SDLoc &DL, - SDISelAsmOperandInfo &OpInfo) { + const SDLoc &DL, SDISelAsmOperandInfo &OpInfo, + SDISelAsmOperandInfo &RefOpInfo) { LLVMContext &Context = *DAG.getContext(); MachineFunction &MF = DAG.getMachineFunction(); @@ -7101,32 +7102,42 @@ // If this is a constraint for a single physreg, or a constraint for a // register class, find it. std::pair PhysReg = - TLI.getRegForInlineAsmConstraint(&TRI, OpInfo.ConstraintCode, - OpInfo.ConstraintVT); + TLI.getRegForInlineAsmConstraint(&TRI, RefOpInfo.ConstraintCode, + RefOpInfo.ConstraintVT); unsigned NumRegs = 1; if (OpInfo.ConstraintVT != MVT::Other) { - // If this is a FP input in an integer register (or visa versa) insert a bit - // cast of the input value. More generally, handle any case where the input - // value disagrees with the register class we plan to stick this in. - if (OpInfo.Type == InlineAsm::isInput && PhysReg.second && + // If this is a FP operand in an integer register (or visa versa), or more + // generally if the operand value disagrees with the register class we plan + // to stick it in, fix the operand type. + // + // If this is an input value, the bitcast to the new type is done now. + // Bitcast for output value is done at the end of visitInlineAsm(). + if ((OpInfo.Type == InlineAsm::isOutput || + OpInfo.Type == InlineAsm::isInput) && + PhysReg.second && !TRI.isTypeLegalForClass(*PhysReg.second, OpInfo.ConstraintVT)) { // Try to convert to the first EVT that the reg class contains. If the // types are identical size, use a bitcast to convert (e.g. two differing - // vector types). + // vector types). Note: output bitcast is done at the end of + // visitInlineAsm(). MVT RegVT = *TRI.legalclasstypes_begin(*PhysReg.second); - if (RegVT.getSizeInBits() == OpInfo.CallOperand.getValueSizeInBits()) { - OpInfo.CallOperand = DAG.getNode(ISD::BITCAST, DL, - RegVT, OpInfo.CallOperand); + if (RegVT.getSizeInBits() == OpInfo.ConstraintVT.getSizeInBits()) { + // Exclude indirect inputs while they are unsupported because the code + // to perform the load is missing and thus OpInfo.CallOperand still + // refer to the input address rather than the pointed-to value. + if (OpInfo.Type == InlineAsm::isInput && !OpInfo.isIndirect) + OpInfo.CallOperand = + DAG.getNode(ISD::BITCAST, DL, RegVT, OpInfo.CallOperand); OpInfo.ConstraintVT = RegVT; + // If the operand is a FP value and we want it in integer registers, + // use the corresponding integer type. This turns an f64 value into + // i64, which can be passed with two i32 values on a 32-bit machine. } else if (RegVT.isInteger() && OpInfo.ConstraintVT.isFloatingPoint()) { - // If the input is a FP value and we want it in FP registers, do a - // bitcast to the corresponding integer type. This turns an f64 value - // into i64, which can be passed with two i32 values on a 32-bit - // machine. RegVT = MVT::getIntegerVT(OpInfo.ConstraintVT.getSizeInBits()); - OpInfo.CallOperand = DAG.getNode(ISD::BITCAST, DL, - RegVT, OpInfo.CallOperand); + if (OpInfo.Type == InlineAsm::isInput) + OpInfo.CallOperand = + DAG.getNode(ISD::BITCAST, DL, RegVT, OpInfo.CallOperand); OpInfo.ConstraintVT = RegVT; } } @@ -7134,6 +7145,11 @@ NumRegs = TLI.getNumRegisters(Context, OpInfo.ConstraintVT); } + // No need to allocate a matching input constraint since the constraint it's + // matching to has already been allocated. + if (OpInfo.isMatchingInputConstraint()) + return; + MVT RegVT; EVT ValueVT = OpInfo.ConstraintVT; @@ -7382,19 +7398,27 @@ // If this constraint is for a specific register, allocate it before // anything else. + SDISelAsmOperandInfo &RefOpInfo = + OpInfo.isMatchingInputConstraint() + ? ConstraintOperands[OpInfo.getMatchedOperand()] + : ConstraintOperands[i]; if (OpInfo.ConstraintType == TargetLowering::C_Register) - GetRegistersForValue(DAG, TLI, getCurSDLoc(), OpInfo); + GetRegistersForValue(DAG, TLI, getCurSDLoc(), OpInfo, RefOpInfo); } // Third 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) { SDISelAsmOperandInfo &OpInfo = ConstraintOperands[i]; + SDISelAsmOperandInfo &RefOpInfo = + OpInfo.isMatchingInputConstraint() + ? ConstraintOperands[OpInfo.getMatchedOperand()] + : ConstraintOperands[i]; // C_Register operands have already been allocated, Other/Memory don't need // to be. - if (OpInfo.ConstraintType == TargetLowering::C_RegisterClass) - GetRegistersForValue(DAG, TLI, getCurSDLoc(), OpInfo); + if (RefOpInfo.ConstraintType == TargetLowering::C_RegisterClass) + GetRegistersForValue(DAG, TLI, getCurSDLoc(), OpInfo, RefOpInfo); } // AsmNodeOperands - The operands for the ISD::INLINEASM node. @@ -7638,12 +7662,18 @@ if (CS.getType()->isSingleValueType() && CS.getType()->isSized()) { EVT ResultType = TLI.getValueType(DAG.getDataLayout(), CS.getType()); - // If any of the results of the inline asm is a vector, it may have the - // wrong width/num elts. This can happen for register classes that can - // contain multiple different value types. The preg or vreg allocated may - // not have the same VT as was expected. Convert it to the right type - // with bit_convert. - if (ResultType != Val.getValueType() && Val.getValueType().isVector()) { + // If the type of the inline asm call site return value is different but + // has same size as the type of the asm output bitcast it. One example + // of this is for vectors with different width / number of elements. + // This can happen for register classes that can contain multiple + // different value types. The preg or vreg allocated may not have the + // same VT as was expected. + // + // This can also happen for a return value that disagrees with the + // register class it is put in, eg. a double in a general-purpose + // register on a 32-bit machine. + if (ResultType != Val.getValueType() && + ResultType.getSizeInBits() == Val.getValueSizeInBits()) { Val = DAG.getNode(ISD::BITCAST, getCurSDLoc(), ResultType, Val); Index: test/CodeGen/ARM/pr34170.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/pr34170.ll @@ -0,0 +1,22 @@ +; RUN: llc -mtriple armv7-arm-linux-gnueabihf -O2 -mcpu=cortex-a7 < %s | FileCheck %s + +; Check support for returning a double in GPR +define double @zerobits_double() #0 { +; CHECK-LABEL: zerobits_double +; CHECK: mov r0, #0 +; CHECK-NEXT: mov r1, #0 +; CHECK: vmov d0, r0, r1 + %1 = tail call double asm "mov ${0:Q}, #0\0Amov ${0:R}, #0", "=&r"() + ret double %1 +} + +; Check support for returning a double in GPR with matching double input +define double @dbl_gpr_matching_in_op(double %d) nounwind { +; CHECK-LABEL: dbl_gpr_matching_in_op +; CHECK: mov r1, r0 +; CHECK: vmov d0, r0, r1 + %1 = call double asm "mov ${0:R}, ${1:Q}", "=&r,0"(double %d) + ret double %1 +} + +attributes #0 = { nounwind "target-features"="+d16,+vfp2,+vfp3,-fp-only-sp" }