]> granicus.if.org Git - llvm/commitdiff
[ARM] GlobalISel: Legalize s8 and s16 G_(S|U)DIV
authorDiana Picus <diana.picus@linaro.org>
Mon, 24 Apr 2017 09:12:19 +0000 (09:12 +0000)
committerDiana Picus <diana.picus@linaro.org>
Mon, 24 Apr 2017 09:12:19 +0000 (09:12 +0000)
We have to widen the operands to 32 bits and then we can either use
hardware division if it is available or lower to a libcall otherwise.

At the moment it is not enough to set the Legalizer action to
WidenScalar, since for libcalls it won't know what to do (it won't be
able to find what size to widen to, because it will find Libcall and not
Legal for 32 bits). To hack around this limitation, we request Custom
lowering, and as part of that we widen first and then we run another
legalizeInstrStep on the widened DIV.

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

lib/Target/ARM/ARMLegalizerInfo.cpp
lib/Target/ARM/ARMLegalizerInfo.h
test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll
test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir

index d1c5d964d95cf3dc9ef17c98af63e9fca2bb128d..9b86030fdd2956fde37e8b58bbbc73c08caa3f70 100644 (file)
@@ -13,6 +13,8 @@
 
 #include "ARMLegalizerInfo.h"
 #include "ARMSubtarget.h"
+#include "llvm/CodeGen/GlobalISel/LegalizerHelper.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/ValueTypes.h"
 #include "llvm/IR/DerivedTypes.h"
 #include "llvm/IR/Type.h"
@@ -48,6 +50,11 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
       setAction({Op, Ty}, Legal);
 
   for (unsigned Op : {G_SDIV, G_UDIV}) {
+    for (auto Ty : {s8, s16})
+      // FIXME: We need WidenScalar here, but in the case of targets with
+      // software division we'll also need Libcall afterwards. Treat as Custom
+      // until we have better support for chaining legalization actions.
+      setAction({Op, Ty}, Custom);
     if (ST.hasDivideInARMMode())
       setAction({Op, s32}, Legal);
     else
@@ -82,3 +89,48 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) {
 
   computeTables();
 }
+
+bool ARMLegalizerInfo::legalizeCustom(MachineInstr &MI,
+                                      MachineRegisterInfo &MRI,
+                                      MachineIRBuilder &MIRBuilder) const {
+  using namespace TargetOpcode;
+
+  switch (MI.getOpcode()) {
+  default:
+    return false;
+  case G_SDIV:
+  case G_UDIV: {
+    LLT Ty = MRI.getType(MI.getOperand(0).getReg());
+    if (Ty != LLT::scalar(16) && Ty != LLT::scalar(8))
+      return false;
+
+    // We need to widen to 32 bits and then maybe, if the target requires,
+    // transform into a libcall.
+    LegalizerHelper Helper(MIRBuilder.getMF());
+
+    MachineInstr *NewMI = nullptr;
+    Helper.MIRBuilder.recordInsertions([&](MachineInstr *MI) {
+      // Store the new, 32-bit div instruction.
+      if (MI->getOpcode() == G_SDIV || MI->getOpcode() == G_UDIV)
+        NewMI = MI;
+    });
+
+    auto Result = Helper.widenScalar(MI, 0, LLT::scalar(32));
+    Helper.MIRBuilder.stopRecordingInsertions();
+    if (Result == LegalizerHelper::UnableToLegalize) {
+      return false;
+    }
+    assert(NewMI && "Couldn't find widened instruction");
+    assert((NewMI->getOpcode() == G_SDIV || NewMI->getOpcode() == G_UDIV) &&
+           "Unexpected widened instruction");
+    assert(MRI.getType(NewMI->getOperand(0).getReg()).getSizeInBits() == 32 &&
+           "Unexpected type for the widened instruction");
+
+    Result = Helper.legalizeInstrStep(*NewMI);
+    if (Result == LegalizerHelper::UnableToLegalize) {
+      return false;
+    }
+    return true;
+  }
+  }
+}
index 0b8a608a6bdea077b811bb9c5d13d747bcc026cc..a9bdd367737e50d3c7ff90e3c5c2b730e7cb9644 100644 (file)
@@ -24,6 +24,9 @@ class ARMSubtarget;
 class ARMLegalizerInfo : public LegalizerInfo {
 public:
   ARMLegalizerInfo(const ARMSubtarget &ST);
+
+  bool legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI,
+                      MachineIRBuilder &MIRBuilder) const override;
 };
 } // End llvm namespace.
 #endif
index 87655b53bf03e3ecab6ad5e87894ac3b9af2fcb9..2881740b016fde7be2529c2f09f6f6010ec7ae15 100644 (file)
@@ -1,7 +1,8 @@
-; RUN: llc -mtriple arm-gnueabi -mattr=+hwdiv-arm -global-isel %s -o - | FileCheck %s -check-prefixes=CHECK,HWDIV
-; RUN: llc -mtriple arm-gnueabi -mattr=-hwdiv-arm -global-isel %s -o - | FileCheck %s -check-prefixes=CHECK,SOFT-AEABI
-; RUN: llc -mtriple arm-gnu -mattr=+hwdiv-arm -global-isel %s -o - | FileCheck %s -check-prefixes=CHECK,HWDIV
-; RUN: llc -mtriple arm-gnu -mattr=-hwdiv-arm -global-isel %s -o - | FileCheck %s -check-prefixes=CHECK,SOFT-DEFAULT
+; We use V6 ops so we can easily check for the extensions (sxth vs bit tricks).
+; RUN: llc -mtriple arm-gnueabi -mattr=+v6,+hwdiv-arm -global-isel %s -o - | FileCheck %s -check-prefixes=CHECK,HWDIV
+; RUN: llc -mtriple arm-gnueabi -mattr=+v6,-hwdiv-arm -global-isel %s -o - | FileCheck %s -check-prefixes=CHECK,SOFT-AEABI
+; RUN: llc -mtriple arm-gnu -mattr=+v6,+hwdiv-arm -global-isel %s -o - | FileCheck %s -check-prefixes=CHECK,HWDIV
+; RUN: llc -mtriple arm-gnu -mattr=+v6,-hwdiv-arm -global-isel %s -o - | FileCheck %s -check-prefixes=CHECK,SOFT-DEFAULT
 
 define arm_aapcscc i32 @test_sdiv_i32(i32 %a, i32 %b) {
 ; CHECK-LABEL: test_sdiv_i32:
@@ -21,3 +22,47 @@ define arm_aapcscc i32 @test_udiv_i32(i32 %a, i32 %b) {
   ret i32 %r
 }
 
+define arm_aapcscc i16 @test_sdiv_i16(i16 %a, i16 %b) {
+; CHECK-LABEL: test_sdiv_i16:
+; CHECK-DAG: sxth r0, r0
+; CHECK-DAG: sxth r1, r1
+; HWDIV: sdiv r0, r0, r1
+; SOFT-AEABI: blx __aeabi_idiv
+; SOFT-DEFAULT: blx __divsi3
+  %r = sdiv i16 %a, %b
+  ret i16 %r
+}
+
+define arm_aapcscc i16 @test_udiv_i16(i16 %a, i16 %b) {
+; CHECK-LABEL: test_udiv_i16:
+; CHECK-DAG: uxth r0, r0
+; CHECK-DAG: uxth r1, r1
+; HWDIV: udiv r0, r0, r1
+; SOFT-AEABI: blx __aeabi_uidiv
+; SOFT-DEFAULT: blx __udivsi3
+  %r = udiv i16 %a, %b
+  ret i16 %r
+}
+
+define arm_aapcscc i8 @test_sdiv_i8(i8 %a, i8 %b) {
+; CHECK-LABEL: test_sdiv_i8:
+; CHECK-DAG: sxtb r0, r0
+; CHECK-DAG: sxtb r1, r1
+; HWDIV: sdiv r0, r0, r1
+; SOFT-AEABI: blx __aeabi_idiv
+; SOFT-DEFAULT: blx __divsi3
+  %r = sdiv i8 %a, %b
+  ret i8 %r
+}
+
+define arm_aapcscc i8 @test_udiv_i8(i8 %a, i8 %b) {
+; CHECK-LABEL: test_udiv_i8:
+; CHECK-DAG: uxtb r0, r0
+; CHECK-DAG: uxtb r1, r1
+; HWDIV: udiv r0, r0, r1
+; SOFT-AEABI: blx __aeabi_uidiv
+; SOFT-DEFAULT: blx __udivsi3
+  %r = udiv i8 %a, %b
+  ret i8 %r
+}
+
index 1f056067e8da5ea2606372b6d539653ce3282aba..6f3e09d328cfe354967a3c3be5947224fbb352e2 100644 (file)
@@ -5,6 +5,12 @@
 --- |
   define void @test_sdiv_i32() { ret void }
   define void @test_udiv_i32() { ret void }
+
+  define void @test_sdiv_i16() { ret void }
+  define void @test_udiv_i16() { ret void }
+
+  define void @test_sdiv_i8() { ret void }
+  define void @test_udiv_i8() { ret void }
 ...
 ---
 name:            test_sdiv_i32
@@ -74,3 +80,151 @@ body:             |
     %r0 = COPY %2(s32)
     BX_RET 14, _, implicit %r0
 ...
+---
+name:            test_sdiv_i16
+# CHECK-LABEL: name: test_sdiv_i16
+legalized:       false
+# CHECK: legalized: true
+regBankSelected: false
+selected:        false
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+  - { id: 2, class: _ }
+body:             |
+  bb.0:
+    liveins: %r0, %r1
+
+    ; CHECK-DAG: [[X:%[0-9]+]](s16) = COPY %r0
+    ; CHECK-DAG: [[Y:%[0-9]+]](s16) = COPY %r1
+    ; CHECK-DAG: [[X32:%[0-9]+]](s32) = G_SEXT [[X]](s16)
+    ; CHECK-DAG: [[Y32:%[0-9]+]](s32) = G_SEXT [[Y]](s16)
+    %0(s16) = COPY %r0
+    %1(s16) = COPY %r1
+    ; HWDIV: [[R32:%[0-9]+]](s32) = G_SDIV [[X32]], [[Y32]]
+    ; SOFT: ADJCALLSTACKDOWN
+    ; SOFT-DAG: %r0 = COPY [[X32]]
+    ; SOFT-DAG: %r1 = COPY [[Y32]]
+    ; SOFT-AEABI: BLX $__aeabi_idiv, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0
+    ; SOFT-AEABI: [[R32:%[0-9]+]](s32) = COPY %r0
+    ; SOFT-DEFAULT: BLX $__divsi3, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0
+    ; SOFT-DEFAULT: [[R32:%[0-9]+]](s32) = COPY %r0
+    ; SOFT: ADJCALLSTACKUP
+    ; CHECK: [[R:%[0-9]+]](s16) = G_TRUNC [[R32]]
+    %2(s16) = G_SDIV %0, %1
+    ; CHECK: %r0 = COPY [[R]]
+    %r0 = COPY %2(s16)
+    BX_RET 14, _, implicit %r0
+...
+---
+name:            test_udiv_i16
+# CHECK-LABEL: name: test_udiv_i16
+legalized:       false
+# CHECK: legalized: true
+regBankSelected: false
+selected:        false
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+  - { id: 2, class: _ }
+body:             |
+  bb.0:
+    liveins: %r0, %r1
+
+    ; CHECK-DAG: [[X:%[0-9]+]](s16) = COPY %r0
+    ; CHECK-DAG: [[Y:%[0-9]+]](s16) = COPY %r1
+    ; CHECK-DAG: [[X32:%[0-9]+]](s32) = G_ZEXT [[X]](s16)
+    ; CHECK-DAG: [[Y32:%[0-9]+]](s32) = G_ZEXT [[Y]](s16)
+    %0(s16) = COPY %r0
+    %1(s16) = COPY %r1
+    ; HWDIV: [[R32:%[0-9]+]](s32) = G_UDIV [[X32]], [[Y32]]
+    ; SOFT: ADJCALLSTACKDOWN
+    ; SOFT-DAG: %r0 = COPY [[X32]]
+    ; SOFT-DAG: %r1 = COPY [[Y32]]
+    ; SOFT-AEABI: BLX $__aeabi_uidiv, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0
+    ; SOFT-AEABI: [[R32:%[0-9]+]](s32) = COPY %r0
+    ; SOFT-DEFAULT: BLX $__udivsi3, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0
+    ; SOFT-DEFAULT: [[R32:%[0-9]+]](s32) = COPY %r0
+    ; SOFT: ADJCALLSTACKUP
+    ; CHECK: [[R:%[0-9]+]](s16) = G_TRUNC [[R32]]
+    %2(s16) = G_UDIV %0, %1
+    ; CHECK: %r0 = COPY [[R]]
+    %r0 = COPY %2(s16)
+    BX_RET 14, _, implicit %r0
+...
+---
+name:            test_sdiv_i8
+# CHECK-LABEL: name: test_sdiv_i8
+legalized:       false
+# CHECK: legalized: true
+regBankSelected: false
+selected:        false
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+  - { id: 2, class: _ }
+body:             |
+  bb.0:
+    liveins: %r0, %r1
+
+    ; CHECK-DAG: [[X:%[0-9]+]](s8) = COPY %r0
+    ; CHECK-DAG: [[Y:%[0-9]+]](s8) = COPY %r1
+    ; CHECK-DAG: [[X32:%[0-9]+]](s32) = G_SEXT [[X]](s8)
+    ; CHECK-DAG: [[Y32:%[0-9]+]](s32) = G_SEXT [[Y]](s8)
+    %0(s8) = COPY %r0
+    %1(s8) = COPY %r1
+    ; HWDIV: [[R32:%[0-9]+]](s32) = G_SDIV [[X32]], [[Y32]]
+    ; SOFT: ADJCALLSTACKDOWN
+    ; SOFT-DAG: %r0 = COPY [[X32]]
+    ; SOFT-DAG: %r1 = COPY [[Y32]]
+    ; SOFT-AEABI: BLX $__aeabi_idiv, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0
+    ; SOFT-AEABI: [[R32:%[0-9]+]](s32) = COPY %r0
+    ; SOFT-DEFAULT: BLX $__divsi3, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0
+    ; SOFT-DEFAULT: [[R32:%[0-9]+]](s32) = COPY %r0
+    ; SOFT: ADJCALLSTACKUP
+    ; CHECK: [[R:%[0-9]+]](s8) = G_TRUNC [[R32]]
+    %2(s8) = G_SDIV %0, %1
+    ; CHECK: %r0 = COPY [[R]]
+    %r0 = COPY %2(s8)
+    BX_RET 14, _, implicit %r0
+...
+---
+name:            test_udiv_i8
+# CHECK-LABEL: name: test_udiv_i8
+legalized:       false
+# CHECK: legalized: true
+regBankSelected: false
+selected:        false
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: _ }
+  - { id: 1, class: _ }
+  - { id: 2, class: _ }
+body:             |
+  bb.0:
+    liveins: %r0, %r1
+
+    ; CHECK-DAG: [[X:%[0-9]+]](s8) = COPY %r0
+    ; CHECK-DAG: [[Y:%[0-9]+]](s8) = COPY %r1
+    ; CHECK-DAG: [[X32:%[0-9]+]](s32) = G_ZEXT [[X]](s8)
+    ; CHECK-DAG: [[Y32:%[0-9]+]](s32) = G_ZEXT [[Y]](s8)
+    %0(s8) = COPY %r0
+    %1(s8) = COPY %r1
+    ; HWDIV: [[R32:%[0-9]+]](s32) = G_UDIV [[X32]], [[Y32]]
+    ; SOFT: ADJCALLSTACKDOWN
+    ; SOFT-DAG: %r0 = COPY [[X32]]
+    ; SOFT-DAG: %r1 = COPY [[Y32]]
+    ; SOFT-AEABI: BLX $__aeabi_uidiv, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0
+    ; SOFT-AEABI: [[R32:%[0-9]+]](s32) = COPY %r0
+    ; SOFT-DEFAULT: BLX $__udivsi3, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0
+    ; SOFT-DEFAULT: [[R32:%[0-9]+]](s32) = COPY %r0
+    ; SOFT: ADJCALLSTACKUP
+    ; CHECK: [[R:%[0-9]+]](s8) = G_TRUNC [[R32]]
+    %2(s8) = G_UDIV %0, %1
+    ; CHECK: %r0 = COPY [[R]]
+    %r0 = COPY %2(s8)
+    BX_RET 14, _, implicit %r0
+...