Index: include/llvm/Target/TargetLowering.h =================================================================== --- include/llvm/Target/TargetLowering.h +++ include/llvm/Target/TargetLowering.h @@ -2805,6 +2805,9 @@ // TargetLowering::LowerCall that perform tail call conversions. bool IsTailCall = false; + // Is Call lowering done post SelectionDAG type legalization. + bool IsPostTypeLegalization = false; + unsigned NumFixedArgs = -1; CallingConv::ID CallConv = CallingConv::C; SDValue Callee; @@ -2816,7 +2819,7 @@ SmallVector OutVals; SmallVector Ins; SmallVector InVals; - + CallLoweringInfo(SelectionDAG &DAG) : RetSExt(false), RetZExt(false), IsVarArg(false), IsInReg(false), DoesNotReturn(false), IsReturnValueUsed(true), IsConvergent(false), @@ -2927,6 +2930,11 @@ return *this; } + CallLoweringInfo &setIsPostTypeLegalization(bool Value=true){ + IsPostTypeLegalization = Value; + return *this; + } + ArgListTy &getArgs() { return Args; } Index: lib/CodeGen/SelectionDAG/LegalizeDAG.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeDAG.cpp +++ lib/CodeGen/SelectionDAG/LegalizeDAG.cpp @@ -1991,7 +1991,8 @@ std::move(Args)) .setTailCall(isTailCall) .setSExtResult(isSigned) - .setZExtResult(!isSigned); + .setZExtResult(!isSigned) + .setIsPostTypeLegalization(true); std::pair CallInfo = TLI.LowerCallTo(CLI); @@ -2029,7 +2030,8 @@ .setLibCallee(TLI.getLibcallCallingConv(LC), RetTy, Callee, std::move(Args)) .setSExtResult(isSigned) - .setZExtResult(!isSigned); + .setZExtResult(!isSigned) + .setIsPostTypeLegalization(true); std::pair CallInfo = TLI.LowerCallTo(CLI); @@ -3565,16 +3567,11 @@ SDValue Args[] = { HiLHS, LHS, HiRHS, RHS }; Ret = ExpandLibCall(LC, WideVT, Args, 4, isSigned, dl); } - BottomHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Ret, - DAG.getIntPtrConstant(0, dl)); - TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT, Ret, - DAG.getIntPtrConstant(1, dl)); - // Ret is a node with an illegal type. Because such things are not - // generally permitted during this phase of legalization, make sure the - // node has no more uses. The above EXTRACT_ELEMENT nodes should have been - // folded. - assert(Ret->use_empty() && - "Unexpected uses of illegally type from expanded lib call."); + assert((Ret.getOpcode() == ISD::BUILD_PAIR || + Ret.getOpcode() == ISD::MERGE_VALUES ) && + "Ret value is a collection of constituent nodes holding result."); + BottomHalf = Ret.getOperand(0); + TopHalf = Ret.getOperand(1); } if (isSigned) { Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -8085,6 +8085,9 @@ SmallVector ReturnValues; if (!CanLowerReturn) { + unsigned NumValues; + SmallVector Chains; + // The instruction result is the result of loading from the // hidden sret parameter. SmallVector PVTs; @@ -8092,11 +8095,37 @@ ComputeValueVTs(*this, DL, PtrRetTy, PVTs); assert(PVTs.size() == 1 && "Pointers should fit in one register"); - EVT PtrVT = PVTs[0]; + EVT PartPtrVT = PVTs[0]; - unsigned NumValues = RetTys.size(); + // During node legalization expansion of larger integer + // results into constituents is done during call lowering, + // whereas during type legalization this is handled post + // call lowering. + if (!CLI.IsPostTypeLegalization) { + NumValues = RetTys.size(); + } else { + int i = 0; + LLVMContext &LC = OrigRetTy->getContext(); + EVT OrigRetVT = getValueType(DL, OrigRetTy); + MVT PartVT = getRegisterType(LC, OrigRetVT); + PartPtrVT = getValueType(DL, + PointerType::getUnqual(EVT(PartVT).getTypeForEVT(LC))); + + NumValues = getNumRegisters(LC, OrigRetVT); + unsigned ByteOffset = (PartVT.getSizeInBits()+7)/8; + Offsets.resize(NumValues); + for(auto & val : Offsets) { + val = i*ByteOffset; + i++; + } + + RetTys.clear(); + RetTys.resize(NumValues); + std::for_each(RetTys.begin(),RetTys.end(), + [&](EVT & val){val = EVT(PartVT);}); + } ReturnValues.resize(NumValues); - SmallVector Chains(NumValues); + Chains.resize(NumValues); // An aggregate return value cannot wrap around the address space, so // offsets to its parts don't wrap either. @@ -8104,9 +8133,9 @@ Flags.setNoUnsignedWrap(true); for (unsigned i = 0; i < NumValues; ++i) { - SDValue Add = CLI.DAG.getNode(ISD::ADD, CLI.DL, PtrVT, DemoteStackSlot, + SDValue Add = CLI.DAG.getNode(ISD::ADD, CLI.DL, PartPtrVT, DemoteStackSlot, CLI.DAG.getConstant(Offsets[i], CLI.DL, - PtrVT), Flags); + PartPtrVT), Flags); SDValue L = CLI.DAG.getLoad( RetTys[i], CLI.DL, CLI.Chain, Add, MachinePointerInfo::getFixedStack(CLI.DAG.getMachineFunction(), Index: test/CodeGen/WebAssembly/umulo-i64.ll =================================================================== --- /dev/null +++ test/CodeGen/WebAssembly/umulo-i64.ll @@ -0,0 +1,24 @@ +; RUN: llc < %s -asm-verbose=false | FileCheck %s +; Test that UMULO works correctly on 64-bit operands. +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-emscripten" + +; CHECK-LABEL: _ZN4core3num21_$LT$impl$u20$u64$GT$15overflowing_mul17h07be88b4cbac028fE: +; CHECK: __multi3 +; Function Attrs: inlinehint +define void @"_ZN4core3num21_$LT$impl$u20$u64$GT$15overflowing_mul17h07be88b4cbac028fE"(i64, i64) unnamed_addr #0 { +start: + %2 = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %0, i64 %1) + %3 = extractvalue { i64, i1 } %2, 0 + store i64 %3, i64* undef + unreachable +} + +; Function Attrs: nounwind readnone speculatable +declare { i64, i1 } @llvm.umul.with.overflow.i64(i64, i64) #1 + +attributes #0 = { inlinehint } +attributes #1 = { nounwind readnone speculatable } + + +