Skip to content

Commit

Permalink
[mips][FastISel] Implement srem/urem and sdiv/udiv instructions.
Browse files Browse the repository at this point in the history
Summary: Implement the LLVM assembly urem/srem and sdiv/udiv instructions in MIPS FastISel.

Based on a patch by Reed Kotler.

Test Plan:
srem1.ll
div1.ll
test-suite at O0/O2 for mips32 r1/r2

Reviewers: dsanders, rkotler

Subscribers: llvm-commits, rfuhler

Differential Revision: http://reviews.llvm.org/D7028

llvm-svn: 238757
  • Loading branch information
Vasileios Kalintiris authored and Vasileios Kalintiris committed Jun 1, 2015
1 parent 127f894 commit 8fcb398
Show file tree
Hide file tree
Showing 3 changed files with 172 additions and 0 deletions.
61 changes: 61 additions & 0 deletions llvm/lib/Target/Mips/MipsFastISel.cpp
Expand Up @@ -103,6 +103,7 @@ class MipsFastISel final : public FastISel {
bool selectTrunc(const Instruction *I);
bool selectIntExt(const Instruction *I);
bool selectShift(const Instruction *I);
bool selectDivRem(const Instruction *I, unsigned ISDOpcode);

// Utility helper routines.
bool isTypeLegal(Type *Ty, MVT &VT);
Expand Down Expand Up @@ -1471,6 +1472,50 @@ unsigned MipsFastISel::emitIntExt(MVT SrcVT, unsigned SrcReg, MVT DestVT,
return Success ? DestReg : 0;
}

bool MipsFastISel::selectDivRem(const Instruction *I, unsigned ISDOpcode) {
EVT DestEVT = TLI.getValueType(I->getType(), true);
if (!DestEVT.isSimple())
return false;

MVT DestVT = DestEVT.getSimpleVT();
if (DestVT != MVT::i32)
return false;

unsigned DivOpc;
switch (ISDOpcode) {
default:
return false;
case ISD::SDIV:
case ISD::SREM:
DivOpc = Mips::SDIV;
break;
case ISD::UDIV:
case ISD::UREM:
DivOpc = Mips::UDIV;
break;
}

unsigned Src0Reg = getRegForValue(I->getOperand(0));
unsigned Src1Reg = getRegForValue(I->getOperand(1));
if (!Src0Reg || !Src1Reg)
return false;

emitInst(DivOpc).addReg(Src0Reg).addReg(Src1Reg);
emitInst(Mips::TEQ).addReg(Src1Reg).addReg(Mips::ZERO).addImm(7);

unsigned ResultReg = createResultReg(&Mips::GPR32RegClass);
if (!ResultReg)
return false;

unsigned MFOpc = (ISDOpcode == ISD::SREM || ISDOpcode == ISD::UREM)
? Mips::MFHI
: Mips::MFLO;
emitInst(MFOpc, ResultReg);

updateValueMap(I, ResultReg);
return true;
}

bool MipsFastISel::selectShift(const Instruction *I) {
MVT RetVT;

Expand Down Expand Up @@ -1556,6 +1601,22 @@ bool MipsFastISel::fastSelectInstruction(const Instruction *I) {
return selectLoad(I);
case Instruction::Store:
return selectStore(I);
case Instruction::SDiv:
if (!selectBinaryOp(I, ISD::SDIV))
return selectDivRem(I, ISD::SDIV);
return true;
case Instruction::UDiv:
if (!selectBinaryOp(I, ISD::UDIV))
return selectDivRem(I, ISD::UDIV);
return true;
case Instruction::SRem:
if (!selectBinaryOp(I, ISD::SREM))
return selectDivRem(I, ISD::SREM);
return true;
case Instruction::URem:
if (!selectBinaryOp(I, ISD::UREM))
return selectDivRem(I, ISD::UREM);
return true;
case Instruction::Shl:
case Instruction::LShr:
case Instruction::AShr:
Expand Down
55 changes: 55 additions & 0 deletions llvm/test/CodeGen/Mips/Fast-ISel/div1.ll
@@ -0,0 +1,55 @@
; RUN: llc < %s -march=mipsel -mcpu=mips32 -O0 -relocation-model=pic \
; RUN: -fast-isel=true -mips-fast-isel -fast-isel-abort=1 | FileCheck %s
; RUN: llc < %s -march=mipsel -mcpu=mips32r2 -O0 -relocation-model=pic \
; RUN: -fast-isel=true -mips-fast-isel -fast-isel-abort=1 | FileCheck %s

@sj = global i32 200000, align 4
@sk = global i32 -47, align 4
@uj = global i32 200000, align 4
@uk = global i32 43, align 4
@si = common global i32 0, align 4
@ui = common global i32 0, align 4

define void @divs() {
; CHECK-LABEL: divs:

; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp)
; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp)
; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25
; CHECK-DAG: lw $[[I_ADDR:[0-9]+]], %got(si)($[[GOT]])
; CHECK-DAG: lw $[[K_ADDR:[0-9]+]], %got(sk)($[[GOT]])
; CHECK-DAG: lw $[[J_ADDR:[0-9]+]], %got(sj)($[[GOT]])
; CHECK-DAG: lw $[[J:[0-9]+]], 0($[[J_ADDR]])
; CHECK-DAG: lw $[[K:[0-9]+]], 0($[[K_ADDR]])
; CHECK-DAG: div $zero, $[[J]], $[[K]]
; CHECK_DAG: teq $[[K]], $zero, 7
; CHECK-DAG: mflo $[[RESULT:[0-9]+]]
; CHECK: sw $[[RESULT]], 0($[[I_ADDR]])
%1 = load i32, i32* @sj, align 4
%2 = load i32, i32* @sk, align 4
%div = sdiv i32 %1, %2
store i32 %div, i32* @si, align 4
ret void
}

define void @divu() {
; CHECK-LABEL: divu:

; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp)
; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp)
; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25
; CHECK-DAG: lw $[[I_ADDR:[0-9]+]], %got(ui)($[[GOT]])
; CHECK-DAG: lw $[[K_ADDR:[0-9]+]], %got(uk)($[[GOT]])
; CHECK-DAG: lw $[[J_ADDR:[0-9]+]], %got(uj)($[[GOT]])
; CHECK-DAG: lw $[[J:[0-9]+]], 0($[[J_ADDR]])
; CHECK-DAG: lw $[[K:[0-9]+]], 0($[[K_ADDR]])
; CHECK-DAG: divu $zero, $[[J]], $[[K]]
; CHECK_DAG: teq $[[K]], $zero, 7
; CHECK-DAG: mflo $[[RESULT:[0-9]+]]
; CHECK: sw $[[RESULT]], 0($[[I_ADDR]])
%1 = load i32, i32* @uj, align 4
%2 = load i32, i32* @uk, align 4
%div = udiv i32 %1, %2
store i32 %div, i32* @ui, align 4
ret void
}
56 changes: 56 additions & 0 deletions llvm/test/CodeGen/Mips/Fast-ISel/rem1.ll
@@ -0,0 +1,56 @@
; RUN: llc < %s -march=mipsel -mcpu=mips32 -O0 -relocation-model=pic \
; RUN: -fast-isel=true -mips-fast-isel -fast-isel-abort=1 | FileCheck %s
; RUN: llc < %s -march=mipsel -mcpu=mips32r2 -O0 -relocation-model=pic \
; RUN: -fast-isel=true -mips-fast-isel -fast-isel-abort=1 | FileCheck %s

@sj = global i32 200, align 4
@sk = global i32 -47, align 4
@uj = global i32 200, align 4
@uk = global i32 43, align 4
@si = common global i32 0, align 4
@ui = common global i32 0, align 4

define void @rems() {
; CHECK-LABEL: rems:

; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp)
; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp)
; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25
; CHECK-DAG: lw $[[I_ADDR:[0-9]+]], %got(si)($[[GOT]])
; CHECK-DAG: lw $[[K_ADDR:[0-9]+]], %got(sk)($[[GOT]])
; CHECK-DAG: lw $[[J_ADDR:[0-9]+]], %got(sj)($[[GOT]])
; CHECK-DAG: lw $[[J:[0-9]+]], 0($[[J_ADDR]])
; CHECK-DAG: lw $[[K:[0-9]+]], 0($[[K_ADDR]])
; CHECK-DAG: div $zero, $[[J]], $[[K]]
; CHECK_DAG: teq $[[K]], $zero, 7
; CHECK-DAG: mfhi $[[RESULT:[0-9]+]]
; CHECK: sw $[[RESULT]], 0($[[I_ADDR]])
%1 = load i32, i32* @sj, align 4
%2 = load i32, i32* @sk, align 4
%rem = srem i32 %1, %2
store i32 %rem, i32* @si, align 4
ret void
}

; Function Attrs: noinline nounwind
define void @remu() {
; CHECK-LABEL: remu:

; CHECK: lui $[[GOT1:[0-9]+]], %hi(_gp_disp)
; CHECK: addiu $[[GOT2:[0-9]+]], $[[GOT1]], %lo(_gp_disp)
; CHECK: addu $[[GOT:[0-9]+]], $[[GOT2:[0-9]+]], $25
; CHECK-DAG: lw $[[I_ADDR:[0-9]+]], %got(ui)($[[GOT]])
; CHECK-DAG: lw $[[K_ADDR:[0-9]+]], %got(uk)($[[GOT]])
; CHECK-DAG: lw $[[J_ADDR:[0-9]+]], %got(uj)($[[GOT]])
; CHECK-DAG: lw $[[J:[0-9]+]], 0($[[J_ADDR]])
; CHECK-DAG: lw $[[K:[0-9]+]], 0($[[K_ADDR]])
; CHECK-DAG: divu $zero, $[[J]], $[[K]]
; CHECK_DAG: teq $[[K]], $zero, 7
; CHECK-DAG: mfhi $[[RESULT:[0-9]+]]
; CHECK: sw $[[RESULT]], 0($[[I_ADDR]])
%1 = load i32, i32* @uj, align 4
%2 = load i32, i32* @uk, align 4
%rem = urem i32 %1, %2
store i32 %rem, i32* @ui, align 4
ret void
}

0 comments on commit 8fcb398

Please sign in to comment.