[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.

This patch fixes PR17193 (and a long time FIXME in the tests).

llvm-svn: 262507
This commit is contained in:
Renato Golin 2016-03-02 19:35:45 +00:00
parent cbbaeb1307
commit 93e42d9934
3 changed files with 14 additions and 2 deletions

View File

@ -2153,8 +2153,9 @@ SDValue DAGCombiner::useDivRem(SDNode *Node) {
if (Node->use_empty()) if (Node->use_empty())
return SDValue(); // This is a dead node, leave it alone. return SDValue(); // This is a dead node, leave it alone.
// DivMod lib calls can still work on non-legal types if using lib-calls.
EVT VT = Node->getValueType(0); EVT VT = Node->getValueType(0);
if (!TLI.isTypeLegal(VT)) if (VT.isVector() || !VT.isInteger())
return SDValue(); return SDValue();
unsigned Opcode = Node->getOpcode(); unsigned Opcode = Node->getOpcode();

View File

@ -809,6 +809,8 @@ ARMTargetLowering::ARMTargetLowering(const TargetMachine &TM,
setOperationAction(ISD::SDIVREM, MVT::i32, Custom); setOperationAction(ISD::SDIVREM, MVT::i32, Custom);
setOperationAction(ISD::UDIVREM, MVT::i32, Custom); setOperationAction(ISD::UDIVREM, MVT::i32, Custom);
setOperationAction(ISD::SDIVREM, MVT::i64, Custom);
setOperationAction(ISD::UDIVREM, MVT::i64, Custom);
} else { } else {
setOperationAction(ISD::SDIVREM, MVT::i32, Expand); setOperationAction(ISD::SDIVREM, MVT::i32, Expand);
setOperationAction(ISD::UDIVREM, MVT::i32, Expand); setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
@ -7054,6 +7056,13 @@ void ARMTargetLowering::ReplaceNodeResults(SDNode *N,
case ISD::UREM: case ISD::UREM:
Res = LowerREM(N, DAG); Res = LowerREM(N, DAG);
break; 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: case ISD::READCYCLECOUNTER:
ReplaceREADCYCLECOUNTER(N, Results, DAG, Subtarget); ReplaceREADCYCLECOUNTER(N, Results, DAG, Subtarget);
return; return;

View File

@ -79,7 +79,6 @@ entry:
ret i32 %add2 ret i32 %add2
} }
; FIXME: AEABI is not lowering long u/srem into u/ldivmod
define i64 @longf(i64 %a, i64 %b) { define i64 @longf(i64 %a, i64 %b) {
; EABI-LABEL: longf: ; EABI-LABEL: longf:
; DARWIN-LABEL: longf: ; DARWIN-LABEL: longf:
@ -87,6 +86,9 @@ entry:
%div = sdiv i64 %a, %b %div = sdiv i64 %a, %b
%rem = srem i64 %a, %b %rem = srem i64 %a, %b
; EABI: __aeabi_ldivmod ; EABI: __aeabi_ldivmod
; EABI-NEXT: adds r0
; EABI-NEXT: adc r1
; EABI-NOT: __aeabi_ldivmod
; DARWIN: ___divdi3 ; DARWIN: ___divdi3
; DARWIN: mov [[div1:r[0-9]+]], r0 ; DARWIN: mov [[div1:r[0-9]+]], r0
; DARWIN: mov [[div2:r[0-9]+]], r1 ; DARWIN: mov [[div2:r[0-9]+]], r1