[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
This commit is contained in:
Diana Picus 2017-04-24 08:20:05 +00:00
parent e97822e1b7
commit b70e88bdec
7 changed files with 244 additions and 0 deletions

View File

@ -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;

View File

@ -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})

View File

@ -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:

View File

@ -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

View File

@ -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
}

View File

@ -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
...

View File

@ -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