From 99ec2660227f15244e3e0fa69acbb129354265ba Mon Sep 17 00:00:00 2001 From: Renato Golin Date: Fri, 4 Mar 2016 19:19:36 +0000 Subject: [PATCH] [ARM] Merging 64-bit divmod lib calls into one When div+rem calls on the same arguments are found, the ARM back-end merges the two calls into one __aeabi_divmod call for up to 32-bits values. However, for 64-bit values, which also have a lib call (__aeabi_ldivmod), it wasn't merging the calls, and thus calling ldivmod twice and spilling the temporary results, which generated pretty bad code. This patch legalises 64-bit lib calls for divmod, so that now all the spilling and the second call are gone. It also relaxes the DivRem combiner a bit on the legal type check, since it was already checking for isLegalOrCustom on every value, so the extra check for isTypeLegal was redundant. Second attempt, creating TLI.isOperationCustom like isOperationExpand, to make sure we only emit valid types or the ones that were explicitly marked as custom. Now, passing check-all and test-suite on x86, ARM and AArch64. This patch fixes PR17193 (and a long time FIXME in the tests). git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@262738 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Target/TargetLowering.h | 7 +++++++ lib/CodeGen/SelectionDAG/DAGCombiner.cpp | 14 +++++++++----- lib/Target/ARM/ARMISelLowering.cpp | 9 +++++++++ test/CodeGen/ARM/divmod-eabi.ll | 19 ++++++++++++++++++- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/include/llvm/Target/TargetLowering.h b/include/llvm/Target/TargetLowering.h index ad3e26c7207..649a8b606be 100644 --- a/include/llvm/Target/TargetLowering.h +++ b/include/llvm/Target/TargetLowering.h @@ -571,6 +571,13 @@ public: getOperationAction(Op, VT) == Promote); } + /// Return true if the specified operation is ilegal but has a custom lowering + /// on that type. This is used to help guide high-level lowering + /// decisions. + bool isOperationCustom(unsigned Op, EVT VT) const { + return (!isTypeLegal(VT) && getOperationAction(Op, VT) == Custom); + } + /// Return true if the specified operation is illegal on this target or /// unlikely to be made legal with custom lowering. This is used to help guide /// high-level lowering decisions. diff --git a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp index 76187e29116..dfae183723f 100644 --- a/lib/CodeGen/SelectionDAG/DAGCombiner.cpp +++ b/lib/CodeGen/SelectionDAG/DAGCombiner.cpp @@ -2155,14 +2155,18 @@ SDValue DAGCombiner::useDivRem(SDNode *Node) { if (Node->use_empty()) return SDValue(); // This is a dead node, leave it alone. - EVT VT = Node->getValueType(0); - if (!TLI.isTypeLegal(VT)) - return SDValue(); - unsigned Opcode = Node->getOpcode(); bool isSigned = (Opcode == ISD::SDIV) || (Opcode == ISD::SREM); - unsigned DivRemOpc = isSigned ? ISD::SDIVREM : ISD::UDIVREM; + + // DivMod lib calls can still work on non-legal types if using lib-calls. + EVT VT = Node->getValueType(0); + if (VT.isVector() || !VT.isInteger()) + return SDValue(); + + if (!TLI.isTypeLegal(VT) && !TLI.isOperationCustom(DivRemOpc, VT)) + return SDValue(); + // If DIVREM is going to get expanded into a libcall, // but there is no libcall available, then don't combine. if (!TLI.isOperationLegalOrCustom(DivRemOpc, VT) && diff --git a/lib/Target/ARM/ARMISelLowering.cpp b/lib/Target/ARM/ARMISelLowering.cpp index 479b6d29be9..a0bf9179427 100644 --- a/lib/Target/ARM/ARMISelLowering.cpp +++ b/lib/Target/ARM/ARMISelLowering.cpp @@ -809,6 +809,8 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM, setOperationAction(ISD::SDIVREM, MVT::i32, Custom); setOperationAction(ISD::UDIVREM, MVT::i32, Custom); + setOperationAction(ISD::SDIVREM, MVT::i64, Custom); + setOperationAction(ISD::UDIVREM, MVT::i64, Custom); } else { setOperationAction(ISD::SDIVREM, MVT::i32, Expand); setOperationAction(ISD::UDIVREM, MVT::i32, Expand); @@ -7054,6 +7056,13 @@ void ARMTargetLowering::ReplaceNodeResults(SDNode *N, case ISD::UREM: Res = LowerREM(N, DAG); break; + case ISD::SDIVREM: + case ISD::UDIVREM: + Res = LowerDivRem(SDValue(N, 0), DAG); + assert(Res.getNumOperands() == 2 && "DivRem needs two values"); + Results.push_back(Res.getValue(0)); + Results.push_back(Res.getValue(1)); + return; case ISD::READCYCLECOUNTER: ReplaceREADCYCLECOUNTER(N, Results, DAG, Subtarget); return; diff --git a/test/CodeGen/ARM/divmod-eabi.ll b/test/CodeGen/ARM/divmod-eabi.ll index 35f2014317b..778a82038d7 100644 --- a/test/CodeGen/ARM/divmod-eabi.ll +++ b/test/CodeGen/ARM/divmod-eabi.ll @@ -79,7 +79,6 @@ entry: ret i32 %add2 } -; FIXME: AEABI is not lowering long u/srem into u/ldivmod define i64 @longf(i64 %a, i64 %b) { ; EABI-LABEL: longf: ; DARWIN-LABEL: longf: @@ -87,6 +86,9 @@ entry: %div = sdiv i64 %a, %b %rem = srem i64 %a, %b ; EABI: __aeabi_ldivmod +; EABI-NEXT: adds r0 +; EABI-NEXT: adc r1 +; EABI-NOT: __aeabi_ldivmod ; DARWIN: ___divdi3 ; DARWIN: mov [[div1:r[0-9]+]], r0 ; DARWIN: mov [[div2:r[0-9]+]], r1 @@ -97,6 +99,21 @@ entry: ret i64 %add } +define i16 @shortf(i16 %a, i16 %b) { +; EABI-LABEL: shortf: +; DARWIN-LABEL: shortf: +entry: + %div = sdiv i16 %a, %b + %rem = srem i16 %a, %b +; EABI: __aeabi_idivmod +; DARWIN: ___divsi3 +; DARWIN: mov [[div1:r[0-9]+]], r0 +; DARWIN: __modsi3 + %add = add nsw i16 %rem, %div +; DARWIN: add r0{{.*}}[[div1]] + ret i16 %add +} + define i32 @g1(i32 %a, i32 %b) { ; EABI-LABEL: g1: ; DARWIN-LABEL: g1: