]> granicus.if.org Git - llvm/commitdiff
[ARM] Check for correct HW div when lowering divmod
authorDiana Picus <diana.picus@linaro.org>
Tue, 18 Apr 2017 08:32:27 +0000 (08:32 +0000)
committerDiana Picus <diana.picus@linaro.org>
Tue, 18 Apr 2017 08:32:27 +0000 (08:32 +0000)
For subtargets that use the custom lowering for divmod, e.g. gnueabi,
we used to check if the subtarget has hardware divide and then lower to
a div-mul-sub sequence if true, or to a libcall if false.

However, judging by the usage of hasDivide vs hasDivideInARMMode, it
seems that hasDivide only refers to Thumb. For instance, in the
ARMTargetLowering constructor, the code that specifies whether to use
libcalls for (S|U)DIV looks like this:

bool hasDivide = Subtarget->isThumb() ? Subtarget->hasDivide()
                                      : Subtarget->hasDivideInARMMode();

In the case of divmod for arm-gnueabi, using only hasDivide() to
determine what to do means that instead of lowering to __aeabi_idivmod
to get the remainder, we lower to div-mul-sub and then further lower the
div to __aeabi_idiv. Even worse, if we have hardware divide in ARM but
not in Thumb, we generate a libcall instead of using it (this is not an
issue in practice since AFAICT none of the cores that we support have
hardware divide in ARM but not Thumb).

This patch fixes the code dealing with custom lowering to take into
account the mode (Thumb or ARM) when deciding whether or not hardware
division is available.

Differential Revision: https://reviews.llvm.org/D32005

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@300536 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMISelLowering.cpp
test/CodeGen/ARM/divmod-hwdiv.ll [new file with mode: 0644]

index e697c8ca5339e873f3e55d7f0fb378f138317c0e..1cc7da3c9a067846ad56ce70e60fbbe0a15a84d5 100644 (file)
@@ -13052,7 +13052,9 @@ SDValue ARMTargetLowering::LowerDivRem(SDValue Op, SelectionDAG &DAG) const {
   //     rem = a - b * div
   //     return {div, rem}
   // This should be lowered into UDIV/SDIV + MLS later on.
-  if (Subtarget->hasDivide() && Op->getValueType(0).isSimple() &&
+  bool hasDivide = Subtarget->isThumb() ? Subtarget->hasDivide()
+                                        : Subtarget->hasDivideInARMMode();
+  if (hasDivide && Op->getValueType(0).isSimple() &&
       Op->getSimpleValueType(0) == MVT::i32) {
     unsigned DivOpcode = isSigned ? ISD::SDIV : ISD::UDIV;
     const SDValue Dividend = Op->getOperand(0);
diff --git a/test/CodeGen/ARM/divmod-hwdiv.ll b/test/CodeGen/ARM/divmod-hwdiv.ll
new file mode 100644 (file)
index 0000000..4cc316f
--- /dev/null
@@ -0,0 +1,37 @@
+; The hwdiv subtarget feature should only influence thumb, not arm.
+; RUN: llc < %s -mtriple=arm-gnueabi -mattr=+hwdiv | FileCheck %s -check-prefixes=ALL,AEABI-NOHWDIV
+; RUN: llc < %s -mtriple=arm-gnueabi -mattr=-hwdiv | FileCheck %s -check-prefixes=ALL,AEABI-NOHWDIV
+; RUN: llc < %s -mtriple=thumbv7-gnueabi -mattr=+hwdiv | FileCheck %s -check-prefixes=ALL,THUMB-HWDIV
+; RUN: llc < %s -mtriple=thumbv7-gnueabi -mattr=-hwdiv | FileCheck %s -check-prefixes=ALL,AEABI-NOHWDIV
+
+; The hwdiv-arm subtarget feature should only influence arm, not thumb.
+; RUN: llc < %s -mtriple=arm-gnueabi -mattr=+hwdiv-arm | FileCheck %s -check-prefixes=ALL,ARM-HWDIV
+; RUN: llc < %s -mtriple=arm-gnueabi -mattr=-hwdiv-arm | FileCheck %s -check-prefixes=ALL,AEABI-NOHWDIV
+; RUN: llc < %s -mtriple=thumbv7-gnueabi -mattr=+hwdiv-arm | FileCheck %s -check-prefixes=ALL,AEABI-NOHWDIV
+; RUN: llc < %s -mtriple=thumbv7-gnueabi -mattr=-hwdiv-arm | FileCheck %s -check-prefixes=ALL,AEABI-NOHWDIV
+
+define arm_aapcscc i32 @test_i32_srem(i32 %x, i32 %y) {
+; ALL-LABEL: test_i32_srem:
+; ARM-HWDIV: sdiv [[Q:r[0-9]+]], r0, r1
+; ARM-HWDIV: mul [[P:r[0-9]+]], [[Q]], r1
+; ARM-HWDIV: sub r0, r0, [[P]]
+; THUMB-HWDIV: sdiv [[Q:r[0-9]+]], r0, r1
+; THUMB-HWDIV: mls r0, [[Q]], r1, r0
+; AEABI-NOHWDIV: bl __aeabi_idivmod
+; AEABI-NOHWDIV: mov r0, r1
+  %r = srem i32 %x, %y
+  ret i32 %r
+}
+
+define arm_aapcscc i32 @test_i32_urem(i32 %x, i32 %y) {
+; ALL-LABEL: test_i32_urem:
+; ARM-HWDIV: udiv [[Q:r[0-9]+]], r0, r1
+; ARM-HWDIV: mul [[P:r[0-9]+]], [[Q]], r1
+; ARM-HWDIV: sub r0, r0, [[P]]
+; THUMB-HWDIV: udiv [[Q:r[0-9]+]], r0, r1
+; THUMB-HWDIV: mls r0, [[Q]], r1, r0
+; AEABI-NOHWDIV: bl __aeabi_uidivmod
+; AEABI-NOHWDIV: mov r0, r1
+  %r = urem i32 %x, %y
+  ret i32 %r
+}