From b70e88bdec9791538624399131071e56e124641a Mon Sep 17 00:00:00 2001 From: Diana Picus Date: Mon, 24 Apr 2017 08:20:05 +0000 Subject: [PATCH] [ARM] GlobalISel: Support G_(S|U)DIV for s32 Add support for both targets with hardware division and without. For hardware division we have to add support throughout the pipeline (legalizer, reg bank select, instruction select). For targets without hardware division, we only need to mark it as a libcall. llvm-svn: 301164 --- .../lib/Target/ARM/ARMInstructionSelector.cpp | 10 +++ llvm/lib/Target/ARM/ARMLegalizerInfo.cpp | 7 ++ llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp | 2 + .../ARM/GlobalISel/arm-instruction-select.mir | 70 +++++++++++++++++ .../CodeGen/ARM/GlobalISel/arm-isel-divmod.ll | 23 ++++++ .../ARM/GlobalISel/arm-legalize-divmod.mir | 76 +++++++++++++++++++ .../ARM/GlobalISel/arm-regbankselect.mir | 56 ++++++++++++++ 7 files changed, 244 insertions(+) create mode 100644 llvm/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll create mode 100644 llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir diff --git a/llvm/lib/Target/ARM/ARMInstructionSelector.cpp b/llvm/lib/Target/ARM/ARMInstructionSelector.cpp index a99dc159d113..1c13d51a468e 100644 --- a/llvm/lib/Target/ARM/ARMInstructionSelector.cpp +++ b/llvm/lib/Target/ARM/ARMInstructionSelector.cpp @@ -332,6 +332,16 @@ bool ARMInstructionSelector::select(MachineInstr &I) const { } MIB.add(predOps(ARMCC::AL)).add(condCodeOp()); break; + case G_SDIV: + assert(TII.getSubtarget().hasDivideInARMMode() && "Unsupported operation"); + I.setDesc(TII.get(ARM::SDIV)); + MIB.add(predOps(ARMCC::AL)); + break; + case G_UDIV: + assert(TII.getSubtarget().hasDivideInARMMode() && "Unsupported operation"); + I.setDesc(TII.get(ARM::UDIV)); + MIB.add(predOps(ARMCC::AL)); + break; case G_FADD: if (!selectFAdd(MIB, TII, MRI)) return false; diff --git a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp index fe9681439e6b..d1c5d964d95c 100644 --- a/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp +++ b/llvm/lib/Target/ARM/ARMLegalizerInfo.cpp @@ -47,6 +47,13 @@ ARMLegalizerInfo::ARMLegalizerInfo(const ARMSubtarget &ST) { for (auto Ty : {s1, s8, s16, s32}) setAction({Op, Ty}, Legal); + for (unsigned Op : {G_SDIV, G_UDIV}) { + if (ST.hasDivideInARMMode()) + setAction({Op, s32}, Legal); + else + setAction({Op, s32}, Libcall); + } + for (unsigned Op : {G_SEXT, G_ZEXT}) { setAction({Op, s32}, Legal); for (auto Ty : {s1, s8, s16}) diff --git a/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp b/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp index 7c5ba499550b..7325817d446b 100644 --- a/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp +++ b/llvm/lib/Target/ARM/ARMRegisterBankInfo.cpp @@ -221,6 +221,8 @@ ARMRegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { case G_ADD: case G_SUB: case G_MUL: + case G_SDIV: + case G_UDIV: case G_SEXT: case G_ZEXT: case G_TRUNC: diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir index 5fd6e93263a1..83ab2659ef4a 100644 --- a/llvm/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-instruction-select.mir @@ -23,6 +23,9 @@ define void @test_mul_s32() #1 { ret void } define void @test_mulv5_s32() { ret void } + define void @test_sdiv_s32() #2 { ret void } + define void @test_udiv_s32() #2 { ret void } + define void @test_load_from_stack() { ret void } define void @test_load_f32() #0 { ret void } define void @test_load_f64() #0 { ret void } @@ -37,6 +40,7 @@ attributes #0 = { "target-features"="+vfp2,-neonfp" } attributes #1 = { "target-features"="+v6" } + attributes #2 = { "target-features"="+hwdiv-arm" } ... --- name: test_zext_s1 @@ -569,6 +573,72 @@ body: | ; CHECK: BX_RET 14, _, implicit %r0 ... --- +name: test_sdiv_s32 +# CHECK-LABEL: name: test_sdiv_s32 +legalized: true +regBankSelected: true +selected: false +# CHECK: selected: true +registers: + - { id: 0, class: gprb } + - { id: 1, class: gprb } + - { id: 2, class: gprb } +# CHECK: id: 0, class: gpr +# CHECK: id: 1, class: gpr +# CHECK: id: 2, class: gpr +body: | + bb.0: + liveins: %r0, %r1 + + %0(s32) = COPY %r0 + ; CHECK: [[VREGX:%[0-9]+]] = COPY %r0 + + %1(s32) = COPY %r1 + ; CHECK: [[VREGY:%[0-9]+]] = COPY %r1 + + %2(s32) = G_SDIV %0, %1 + ; CHECK: [[VREGRES:%[0-9]+]] = SDIV [[VREGX]], [[VREGY]], 14, _ + + %r0 = COPY %2(s32) + ; CHECK: %r0 = COPY [[VREGRES]] + + BX_RET 14, _, implicit %r0 + ; CHECK: BX_RET 14, _, implicit %r0 +... +--- +name: test_udiv_s32 +# CHECK-LABEL: name: test_udiv_s32 +legalized: true +regBankSelected: true +selected: false +# CHECK: selected: true +registers: + - { id: 0, class: gprb } + - { id: 1, class: gprb } + - { id: 2, class: gprb } +# CHECK: id: 0, class: gpr +# CHECK: id: 1, class: gpr +# CHECK: id: 2, class: gpr +body: | + bb.0: + liveins: %r0, %r1 + + %0(s32) = COPY %r0 + ; CHECK: [[VREGX:%[0-9]+]] = COPY %r0 + + %1(s32) = COPY %r1 + ; CHECK: [[VREGY:%[0-9]+]] = COPY %r1 + + %2(s32) = G_UDIV %0, %1 + ; CHECK: [[VREGRES:%[0-9]+]] = UDIV [[VREGX]], [[VREGY]], 14, _ + + %r0 = COPY %2(s32) + ; CHECK: %r0 = COPY [[VREGRES]] + + BX_RET 14, _, implicit %r0 + ; CHECK: BX_RET 14, _, implicit %r0 +... +--- name: test_load_from_stack # CHECK-LABEL: name: test_load_from_stack legalized: true diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll b/llvm/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll new file mode 100644 index 000000000000..87655b53bf03 --- /dev/null +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-isel-divmod.ll @@ -0,0 +1,23 @@ +; 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 + +define arm_aapcscc i32 @test_sdiv_i32(i32 %a, i32 %b) { +; CHECK-LABEL: test_sdiv_i32: +; HWDIV: sdiv r0, r0, r1 +; SOFT-AEABI: blx __aeabi_idiv +; SOFT-DEFAULT: blx __divsi3 + %r = sdiv i32 %a, %b + ret i32 %r +} + +define arm_aapcscc i32 @test_udiv_i32(i32 %a, i32 %b) { +; CHECK-LABEL: test_udiv_i32: +; HWDIV: udiv r0, r0, r1 +; SOFT-AEABI: blx __aeabi_uidiv +; SOFT-DEFAULT: blx __udivsi3 + %r = udiv i32 %a, %b + ret i32 %r +} + diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir new file mode 100644 index 000000000000..1f056067e8da --- /dev/null +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-legalize-divmod.mir @@ -0,0 +1,76 @@ +# RUN: llc -mtriple arm-linux-gnueabi -mattr=+hwdiv-arm -global-isel -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,HWDIV +# RUN: llc -mtriple arm-linux-gnueabi -mattr=-hwdiv-arm -global-isel -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,SOFT,SOFT-AEABI +# RUN: llc -mtriple arm-linux-gnu -mattr=+hwdiv-arm -global-isel -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,HWDIV +# RUN: llc -mtriple arm-linux-gnu -mattr=-hwdiv-arm -global-isel -run-pass=legalizer %s -o - | FileCheck %s -check-prefixes=CHECK,SOFT,SOFT-DEFAULT +--- | + define void @test_sdiv_i32() { ret void } + define void @test_udiv_i32() { ret void } +... +--- +name: test_sdiv_i32 +# CHECK-LABEL: name: test_sdiv_i32 +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]+]](s32) = COPY %r0 + ; CHECK-DAG: [[Y:%[0-9]+]](s32) = COPY %r1 + %0(s32) = COPY %r0 + %1(s32) = COPY %r1 + ; HWDIV: [[R:%[0-9]+]](s32) = G_SDIV [[X]], [[Y]] + ; SOFT: ADJCALLSTACKDOWN + ; SOFT-DAG: %r0 = COPY [[X]] + ; SOFT-DAG: %r1 = COPY [[Y]] + ; SOFT-AEABI: BLX $__aeabi_idiv, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0 + ; SOFT-AEABI: [[R:%[0-9]+]](s32) = COPY %r0 + ; SOFT-DEFAULT: BLX $__divsi3, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0 + ; SOFT-DEFAULT: [[R:%[0-9]+]](s32) = COPY %r0 + ; SOFT: ADJCALLSTACKUP + %2(s32) = G_SDIV %0, %1 + ; CHECK: %r0 = COPY [[R]] + %r0 = COPY %2(s32) + BX_RET 14, _, implicit %r0 +... +--- +name: test_udiv_i32 +# CHECK-LABEL: name: test_udiv_i32 +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]+]](s32) = COPY %r0 + ; CHECK-DAG: [[Y:%[0-9]+]](s32) = COPY %r1 + %0(s32) = COPY %r0 + %1(s32) = COPY %r1 + ; HWDIV: [[R:%[0-9]+]](s32) = G_UDIV [[X]], [[Y]] + ; SOFT: ADJCALLSTACKDOWN + ; SOFT-DAG: %r0 = COPY [[X]] + ; SOFT-DAG: %r1 = COPY [[Y]] + ; SOFT-AEABI: BLX $__aeabi_uidiv, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0 + ; SOFT-AEABI: [[R:%[0-9]+]](s32) = COPY %r0 + ; SOFT-DEFAULT: BLX $__udivsi3, {{.*}}, implicit %r0, implicit %r1, implicit-def %r0 + ; SOFT-DEFAULT: [[R:%[0-9]+]](s32) = COPY %r0 + ; SOFT: ADJCALLSTACKUP + %2(s32) = G_UDIV %0, %1 + ; CHECK: %r0 = COPY [[R]] + %r0 = COPY %2(s32) + BX_RET 14, _, implicit %r0 +... diff --git a/llvm/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir b/llvm/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir index dc9163497ce7..4e94fb4e3481 100644 --- a/llvm/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir +++ b/llvm/test/CodeGen/ARM/GlobalISel/arm-regbankselect.mir @@ -13,6 +13,9 @@ define void @test_mul_s16() { ret void } define void @test_mul_s8() { ret void } + define void @test_sdiv_s32() #1 { ret void } + define void @test_udiv_s32() #1 { ret void } + define void @test_loads() #0 { ret void } define void @test_stores() #0 { ret void } @@ -30,6 +33,7 @@ define void @test_soft_fp_s64() #0 { ret void } attributes #0 = { "target-features"="+vfp2"} + attributes #1 = { "target-features"="+hwdiv-arm" } ... --- name: test_add_s32 @@ -290,6 +294,58 @@ body: | %r0 = COPY %2(s8) BX_RET 14, _, implicit %r0 +... +--- +name: test_sdiv_s32 +# CHECK-LABEL: name: test_sdiv_s32 +legalized: true +regBankSelected: false +selected: false +# CHECK: registers: +# CHECK: - { id: 0, class: gprb } +# CHECK: - { id: 1, class: gprb } +# CHECK: - { id: 2, class: gprb } + +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0: + liveins: %r0, %r1 + + %0(s32) = COPY %r0 + %1(s32) = COPY %r1 + %2(s32) = G_SDIV %0, %1 + %r0 = COPY %2(s32) + BX_RET 14, _, implicit %r0 + +... +--- +name: test_udiv_s32 +# CHECK-LABEL: name: test_udiv_s32 +legalized: true +regBankSelected: false +selected: false +# CHECK: registers: +# CHECK: - { id: 0, class: gprb } +# CHECK: - { id: 1, class: gprb } +# CHECK: - { id: 2, class: gprb } + +registers: + - { id: 0, class: _ } + - { id: 1, class: _ } + - { id: 2, class: _ } +body: | + bb.0: + liveins: %r0, %r1 + + %0(s32) = COPY %r0 + %1(s32) = COPY %r1 + %2(s32) = G_UDIV %0, %1 + %r0 = COPY %2(s32) + BX_RET 14, _, implicit %r0 + ... --- name: test_loads -- 2.34.1