Skip to content
This repository was archived by the owner on Mar 28, 2020. It is now read-only.

Commit 4747310

Browse files
author
Alexander Ivchenko
committed
[GlobalIsel][X86] Support for G_SDIV instruction
Reviewed By: igorb Differential Revision: https://reviews.llvm.org/D44430 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@327520 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent a816f42 commit 4747310

File tree

7 files changed

+695
-4
lines changed

7 files changed

+695
-4
lines changed

lib/Target/X86/X86InstructionSelector.cpp

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,8 @@ class X86InstructionSelector : public InstructionSelector {
114114
bool selectImplicitDefOrPHI(MachineInstr &I, MachineRegisterInfo &MRI) const;
115115
bool selectShift(MachineInstr &I, MachineRegisterInfo &MRI,
116116
MachineFunction &MF) const;
117+
bool selectSDiv(MachineInstr &I, MachineRegisterInfo &MRI,
118+
MachineFunction &MF) const;
117119

118120
// emit insert subreg instruction and insert it before MachineInstr &I
119121
bool emitInsertSubreg(unsigned DstReg, unsigned SrcReg, MachineInstr &I,
@@ -379,6 +381,8 @@ bool X86InstructionSelector::select(MachineInstr &I,
379381
case TargetOpcode::G_ASHR:
380382
case TargetOpcode::G_LSHR:
381383
return selectShift(I, MRI, MF);
384+
case TargetOpcode::G_SDIV:
385+
return selectSDiv(I, MRI, MF);
382386
}
383387

384388
return false;
@@ -1481,6 +1485,86 @@ bool X86InstructionSelector::selectShift(MachineInstr &I,
14811485
return true;
14821486
}
14831487

1488+
bool X86InstructionSelector::selectSDiv(MachineInstr &I,
1489+
MachineRegisterInfo &MRI,
1490+
MachineFunction &MF) const {
1491+
1492+
assert(I.getOpcode() == TargetOpcode::G_SDIV && "unexpected instruction");
1493+
1494+
const unsigned DstReg = I.getOperand(0).getReg();
1495+
const unsigned DividentReg = I.getOperand(1).getReg();
1496+
const unsigned DiviserReg = I.getOperand(2).getReg();
1497+
1498+
const LLT RegTy = MRI.getType(DstReg);
1499+
assert(RegTy == MRI.getType(DividentReg) &&
1500+
RegTy == MRI.getType(DiviserReg) &&
1501+
"Arguments and return value types must match");
1502+
1503+
const RegisterBank &RegRB = *RBI.getRegBank(DstReg, MRI, TRI);
1504+
1505+
// For the X86 IDIV instruction, in most cases the dividend
1506+
// (numerator) must be in a specific register pair highreg:lowreg,
1507+
// producing the quotient in lowreg and the remainder in highreg.
1508+
// For most data types, to set up the instruction, the dividend is
1509+
// copied into lowreg, and lowreg is sign-extended into highreg. The
1510+
// exception is i8, where the dividend is defined as a single register rather
1511+
// than a register pair, and we therefore directly sign-extend the dividend
1512+
// into lowreg, instead of copying, and ignore the highreg.
1513+
const static struct SDivEntry {
1514+
unsigned SizeInBits;
1515+
unsigned QuotientReg;
1516+
unsigned DividentRegUpper;
1517+
unsigned DividentRegLower;
1518+
unsigned OpSignExtend;
1519+
unsigned OpCopy;
1520+
unsigned OpDiv;
1521+
} OpTable[] = {
1522+
{8, X86::AL, X86::NoRegister, X86::AX, 0, X86::MOVSX16rr8,
1523+
X86::IDIV8r}, // i8
1524+
{16, X86::AX, X86::DX, X86::AX, X86::CWD, TargetOpcode::COPY,
1525+
X86::IDIV16r}, // i16
1526+
{32, X86::EAX, X86::EDX, X86::EAX, X86::CDQ, TargetOpcode::COPY,
1527+
X86::IDIV32r}, // i32
1528+
{64, X86::RAX, X86::RDX, X86::RAX, X86::CQO, TargetOpcode::COPY,
1529+
X86::IDIV64r} // i64
1530+
};
1531+
1532+
if (RegRB.getID() != X86::GPRRegBankID)
1533+
return false;
1534+
1535+
auto SDivEntryIt = std::find_if(
1536+
std::begin(OpTable), std::end(OpTable), [RegTy](const SDivEntry &El) {
1537+
return El.SizeInBits == RegTy.getSizeInBits();
1538+
});
1539+
1540+
if (SDivEntryIt == std::end(OpTable))
1541+
return false;
1542+
1543+
const TargetRegisterClass *RegRC = getRegClass(RegTy, RegRB);
1544+
if (!RBI.constrainGenericRegister(DividentReg, *RegRC, MRI) ||
1545+
!RBI.constrainGenericRegister(DiviserReg, *RegRC, MRI) ||
1546+
!RBI.constrainGenericRegister(DstReg, *RegRC, MRI)) {
1547+
DEBUG(dbgs() << "Failed to constrain " << TII.getName(I.getOpcode())
1548+
<< " operand\n");
1549+
return false;
1550+
}
1551+
1552+
BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SDivEntryIt->OpCopy),
1553+
SDivEntryIt->DividentRegLower)
1554+
.addReg(DividentReg);
1555+
if (SDivEntryIt->DividentRegUpper != X86::NoRegister)
1556+
BuildMI(*I.getParent(), I, I.getDebugLoc(),
1557+
TII.get(SDivEntryIt->OpSignExtend));
1558+
BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(SDivEntryIt->OpDiv))
1559+
.addReg(DiviserReg);
1560+
BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(TargetOpcode::COPY),
1561+
DstReg)
1562+
.addReg(SDivEntryIt->QuotientReg);
1563+
1564+
I.eraseFromParent();
1565+
return true;
1566+
}
1567+
14841568
InstructionSelector *
14851569
llvm::createX86InstructionSelector(const X86TargetMachine &TM,
14861570
X86Subtarget &Subtarget,

lib/Target/X86/X86LegalizerInfo.cpp

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,8 +131,8 @@ void X86LegalizerInfo::setLegalizerInfo32bit() {
131131
.widenScalarToNextPow2(0, /*Min*/ 8);
132132
getActionDefinitionsBuilder(G_INTTOPTR).legalFor({s32, p0});
133133

134-
// Shifts
135-
getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
134+
// Shifts and SDIV
135+
getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR, G_SDIV})
136136
.legalFor({s8, s16, s32})
137137
.clampScalar(0, s8, s32);
138138
}
@@ -214,8 +214,8 @@ void X86LegalizerInfo::setLegalizerInfo64bit() {
214214
// Comparison
215215
setAction({G_ICMP, 1, s64}, Legal);
216216

217-
// Shifts
218-
getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR})
217+
// Shifts and SDIV
218+
getActionDefinitionsBuilder({G_SHL, G_LSHR, G_ASHR, G_SDIV})
219219
.legalFor({s8, s16, s32, s64})
220220
.clampScalar(0, s8, s64);
221221

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=i686-linux-gnu -global-isel -run-pass=legalizer -verify-machineinstrs %s -o - | FileCheck %s
3+
4+
--- |
5+
; ModuleID = 'sdiv.ll'
6+
source_filename = "sdiv.ll"
7+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
8+
9+
define i8 @test_sdiv_i8(i8 %arg1, i8 %arg2) {
10+
%res = sdiv i8 %arg1, %arg2
11+
ret i8 %res
12+
}
13+
14+
define i16 @test_sdiv_i16(i16 %arg1, i16 %arg2) {
15+
%res = sdiv i16 %arg1, %arg2
16+
ret i16 %res
17+
}
18+
19+
define i32 @test_sdiv_i32(i32 %arg1, i32 %arg2) {
20+
%res = sdiv i32 %arg1, %arg2
21+
ret i32 %res
22+
}
23+
24+
...
25+
---
26+
name: test_sdiv_i8
27+
alignment: 4
28+
tracksRegLiveness: true
29+
registers:
30+
- { id: 0, class: _ }
31+
- { id: 1, class: _ }
32+
- { id: 2, class: _ }
33+
- { id: 3, class: _ }
34+
- { id: 4, class: _ }
35+
body: |
36+
bb.1 (%ir-block.0):
37+
liveins: $edi, $esi
38+
39+
; CHECK-LABEL: name: test_sdiv_i8
40+
; CHECK: liveins: $edi, $esi
41+
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
42+
; CHECK: [[TRUNC:%[0-9]+]]:_(s8) = G_TRUNC [[COPY]](s32)
43+
; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $esi
44+
; CHECK: [[TRUNC1:%[0-9]+]]:_(s8) = G_TRUNC [[COPY1]](s32)
45+
; CHECK: [[SDIV:%[0-9]+]]:_(s8) = G_SDIV [[TRUNC]], [[TRUNC1]]
46+
; CHECK: $al = COPY [[SDIV]](s8)
47+
; CHECK: RET 0, implicit $al
48+
%2:_(s32) = COPY $edi
49+
%0:_(s8) = G_TRUNC %2(s32)
50+
%3:_(s32) = COPY $esi
51+
%1:_(s8) = G_TRUNC %3(s32)
52+
%4:_(s8) = G_SDIV %0, %1
53+
$al = COPY %4(s8)
54+
RET 0, implicit $al
55+
56+
...
57+
---
58+
name: test_sdiv_i16
59+
alignment: 4
60+
tracksRegLiveness: true
61+
registers:
62+
- { id: 0, class: _ }
63+
- { id: 1, class: _ }
64+
- { id: 2, class: _ }
65+
- { id: 3, class: _ }
66+
- { id: 4, class: _ }
67+
body: |
68+
bb.1 (%ir-block.0):
69+
liveins: $edi, $esi
70+
71+
; CHECK-LABEL: name: test_sdiv_i16
72+
; CHECK: liveins: $edi, $esi
73+
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
74+
; CHECK: [[TRUNC:%[0-9]+]]:_(s16) = G_TRUNC [[COPY]](s32)
75+
; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $esi
76+
; CHECK: [[TRUNC1:%[0-9]+]]:_(s16) = G_TRUNC [[COPY1]](s32)
77+
; CHECK: [[SDIV:%[0-9]+]]:_(s16) = G_SDIV [[TRUNC]], [[TRUNC1]]
78+
; CHECK: $ax = COPY [[SDIV]](s16)
79+
; CHECK: RET 0, implicit $ax
80+
%2:_(s32) = COPY $edi
81+
%0:_(s16) = G_TRUNC %2(s32)
82+
%3:_(s32) = COPY $esi
83+
%1:_(s16) = G_TRUNC %3(s32)
84+
%4:_(s16) = G_SDIV %0, %1
85+
$ax = COPY %4(s16)
86+
RET 0, implicit $ax
87+
88+
...
89+
---
90+
name: test_sdiv_i32
91+
alignment: 4
92+
tracksRegLiveness: true
93+
registers:
94+
- { id: 0, class: _ }
95+
- { id: 1, class: _ }
96+
- { id: 2, class: _ }
97+
body: |
98+
bb.1 (%ir-block.0):
99+
liveins: $edi, $esi
100+
101+
; CHECK-LABEL: name: test_sdiv_i32
102+
; CHECK: liveins: $edi, $esi
103+
; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $edi
104+
; CHECK: [[COPY1:%[0-9]+]]:_(s32) = COPY $esi
105+
; CHECK: [[SDIV:%[0-9]+]]:_(s32) = G_SDIV [[COPY]], [[COPY1]]
106+
; CHECK: $eax = COPY [[SDIV]](s32)
107+
; CHECK: RET 0, implicit $eax
108+
%0:_(s32) = COPY $edi
109+
%1:_(s32) = COPY $esi
110+
%2:_(s32) = G_SDIV %0, %1
111+
$eax = COPY %2(s32)
112+
RET 0, implicit $eax
113+
114+
...
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
2+
# RUN: llc -mtriple=i386-linux-gnu -global-isel -run-pass=instruction-select -verify-machineinstrs %s -o - | FileCheck %s
3+
4+
--- |
5+
; ModuleID = 'sdiv.ll'
6+
source_filename = "sdiv.ll"
7+
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
8+
9+
define i8 @test_sdiv_i8(i8 %arg1, i8 %arg2) {
10+
%res = sdiv i8 %arg1, %arg2
11+
ret i8 %res
12+
}
13+
14+
define i16 @test_sdiv_i16(i16 %arg1, i16 %arg2) {
15+
%res = sdiv i16 %arg1, %arg2
16+
ret i16 %res
17+
}
18+
19+
define i32 @test_sdiv_i32(i32 %arg1, i32 %arg2) {
20+
%res = sdiv i32 %arg1, %arg2
21+
ret i32 %res
22+
}
23+
24+
...
25+
---
26+
name: test_sdiv_i8
27+
alignment: 4
28+
legalized: true
29+
regBankSelected: true
30+
tracksRegLiveness: true
31+
registers:
32+
- { id: 0, class: gpr }
33+
- { id: 1, class: gpr }
34+
- { id: 2, class: gpr }
35+
- { id: 3, class: gpr }
36+
- { id: 4, class: gpr }
37+
body: |
38+
bb.1 (%ir-block.0):
39+
liveins: $edi, $esi
40+
41+
; CHECK-LABEL: name: test_sdiv_i8
42+
; CHECK: liveins: $edi, $esi
43+
; CHECK: [[COPY:%[0-9]+]]:gr32_abcd = COPY $edi
44+
; CHECK: [[COPY1:%[0-9]+]]:gr8 = COPY [[COPY]].sub_8bit
45+
; CHECK: [[COPY2:%[0-9]+]]:gr32_abcd = COPY $esi
46+
; CHECK: [[COPY3:%[0-9]+]]:gr8 = COPY [[COPY2]].sub_8bit
47+
; CHECK: $ax = MOVSX16rr8 [[COPY1]]
48+
; CHECK: IDIV8r [[COPY3]], implicit-def $al, implicit-def $ah, implicit-def $eflags, implicit $ax
49+
; CHECK: [[COPY4:%[0-9]+]]:gr8 = COPY $al
50+
; CHECK: $al = COPY [[COPY4]]
51+
; CHECK: RET 0, implicit $al
52+
%2:gpr(s32) = COPY $edi
53+
%0:gpr(s8) = G_TRUNC %2(s32)
54+
%3:gpr(s32) = COPY $esi
55+
%1:gpr(s8) = G_TRUNC %3(s32)
56+
%4:gpr(s8) = G_SDIV %0, %1
57+
$al = COPY %4(s8)
58+
RET 0, implicit $al
59+
60+
...
61+
---
62+
name: test_sdiv_i16
63+
alignment: 4
64+
legalized: true
65+
regBankSelected: true
66+
tracksRegLiveness: true
67+
registers:
68+
- { id: 0, class: gpr }
69+
- { id: 1, class: gpr }
70+
- { id: 2, class: gpr }
71+
- { id: 3, class: gpr }
72+
- { id: 4, class: gpr }
73+
body: |
74+
bb.1 (%ir-block.0):
75+
liveins: $edi, $esi
76+
77+
; CHECK-LABEL: name: test_sdiv_i16
78+
; CHECK: liveins: $edi, $esi
79+
; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $edi
80+
; CHECK: [[COPY1:%[0-9]+]]:gr16 = COPY [[COPY]].sub_16bit
81+
; CHECK: [[COPY2:%[0-9]+]]:gr32 = COPY $esi
82+
; CHECK: [[COPY3:%[0-9]+]]:gr16 = COPY [[COPY2]].sub_16bit
83+
; CHECK: $ax = COPY [[COPY1]]
84+
; CHECK: CWD implicit-def $ax, implicit-def $dx, implicit $ax
85+
; CHECK: IDIV16r [[COPY3]], implicit-def $ax, implicit-def $dx, implicit-def $eflags, implicit $ax, implicit $dx
86+
; CHECK: [[COPY4:%[0-9]+]]:gr16 = COPY $ax
87+
; CHECK: $ax = COPY [[COPY4]]
88+
; CHECK: RET 0, implicit $ax
89+
%2:gpr(s32) = COPY $edi
90+
%0:gpr(s16) = G_TRUNC %2(s32)
91+
%3:gpr(s32) = COPY $esi
92+
%1:gpr(s16) = G_TRUNC %3(s32)
93+
%4:gpr(s16) = G_SDIV %0, %1
94+
$ax = COPY %4(s16)
95+
RET 0, implicit $ax
96+
97+
...
98+
---
99+
name: test_sdiv_i32
100+
alignment: 4
101+
legalized: true
102+
regBankSelected: true
103+
tracksRegLiveness: true
104+
registers:
105+
- { id: 0, class: gpr }
106+
- { id: 1, class: gpr }
107+
- { id: 2, class: gpr }
108+
body: |
109+
bb.1 (%ir-block.0):
110+
liveins: $edi, $esi
111+
112+
; CHECK-LABEL: name: test_sdiv_i32
113+
; CHECK: liveins: $edi, $esi
114+
; CHECK: [[COPY:%[0-9]+]]:gr32 = COPY $edi
115+
; CHECK: [[COPY1:%[0-9]+]]:gr32 = COPY $esi
116+
; CHECK: $eax = COPY [[COPY]]
117+
; CHECK: CDQ implicit-def $eax, implicit-def $edx, implicit $eax
118+
; CHECK: IDIV32r [[COPY1]], implicit-def $eax, implicit-def $edx, implicit-def $eflags, implicit $eax, implicit $edx
119+
; CHECK: [[COPY2:%[0-9]+]]:gr32 = COPY $eax
120+
; CHECK: $eax = COPY [[COPY2]]
121+
; CHECK: RET 0, implicit $eax
122+
%0:gpr(s32) = COPY $edi
123+
%1:gpr(s32) = COPY $esi
124+
%2:gpr(s32) = G_SDIV %0, %1
125+
$eax = COPY %2(s32)
126+
RET 0, implicit $eax
127+
128+
...

0 commit comments

Comments
 (0)