#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"
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
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;
+ }
+ }
+}
class ARMLegalizerInfo : public LegalizerInfo {
public:
ARMLegalizerInfo(const ARMSubtarget &ST);
+
+ bool legalizeCustom(MachineInstr &MI, MachineRegisterInfo &MRI,
+ MachineIRBuilder &MIRBuilder) const override;
};
} // End llvm namespace.
#endif
-; 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:
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
+}
+
--- |
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
%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
+...