diff options
-rw-r--r-- | llvm/lib/Target/ARM/ARMLegalizerInfo.cpp | 52 | ||||
-rw-r--r-- | llvm/lib/Target/ARM/ARMLegalizerInfo.h | 3 | ||||
-rw-r--r-- | llvm/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll | 53 | ||||
-rw-r--r-- | llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir | 154 |
4 files changed, 258 insertions, 4 deletions
diff --git a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp index d1c5d964d95..9b86030fdd2 100644 --- a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp +++ b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp @@ -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; + } + } +} diff --git a/llvm/lib/Target/ARM/ARMLegalizerInfo.h b/llvm/lib/Target/ARM/ARMLegalizerInfo.h index 0b8a608a6bd..a9bdd367737 100644 --- a/llvm/lib/Target/ARM/ARMLegalizerInfo.h +++ b/llvm/lib/Target/ARM/ARMLegalizerInfo.h @@ -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 diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll b/llvm/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll index 87655b53bf0..2881740b016 100644 --- a/llvm/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll @@ -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 +} + diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir index 1f056067e8d..6f3e09d328c 100644 --- a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir @@ -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 +... |