Index: lib/Target/Mips/MipsFastISel.cpp =================================================================== --- lib/Target/Mips/MipsFastISel.cpp +++ lib/Target/Mips/MipsFastISel.cpp @@ -101,6 +101,7 @@ bool selectTrunc(const Instruction *I); bool selectIntExt(const Instruction *I); bool selectShift(const Instruction *I); + bool selectDiv(const Instruction *I, unsigned ISDOpcode); // Utility helper routines. bool isTypeLegal(Type *Ty, MVT &VT); @@ -1617,6 +1618,41 @@ return true; } +bool MipsFastISel::selectDiv(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: + DivOpc = Mips::SDIV; + break; + case ISD::UDIV: + DivOpc = Mips::UDIV; + break; + } + unsigned Src0Reg = getRegForValue(I->getOperand(0)); + if (!Src0Reg) + return false; + unsigned Src1Reg = getRegForValue(I->getOperand(1)); + if (!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; + emitInst(Mips::MFLO, ResultReg); + updateValueMap(I, ResultReg); + return true; +} + bool MipsFastISel::fastSelectInstruction(const Instruction *I) { if (!TargetSupported) return false; @@ -1627,6 +1663,14 @@ return selectLoad(I); case Instruction::Store: return selectStore(I); + case Instruction::SDiv: + if (!selectBinaryOp(I, ISD::SDIV)) + return selectDiv(I, ISD::SDIV); + return true; + case Instruction::UDiv: + if (!selectBinaryOp(I, ISD::UDIV)) + return selectDiv(I, ISD::UDIV); + return true; case Instruction::SRem: if (!selectBinaryOp(I, ISD::SREM)) return selectRem(I, ISD::SREM); Index: test/CodeGen/Mips/Fast-ISel/div1.ll =================================================================== --- /dev/null +++ test/CodeGen/Mips/Fast-ISel/div1.ll @@ -0,0 +1,98 @@ +; RUN: llc -march=mipsel -relocation-model=pic -O0 -mips-fast-isel -fast-isel -fast-isel-abort -mcpu=mips32r2 \ +; RUN: < %s | 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 + +; Function Attrs: noinline nounwind +define void @divs() #0 { +entry: +; CHECK-LABEL: .ent divs + %0 = load i32* @sj, align 4 + %1 = load i32* @sk, align 4 + %div = sdiv i32 %0, %1 + store i32 %div, i32* @si, align 4 +; 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]]) + + ret void +} + +; Function Attrs: noinline nounwind +define void @divu() #0 { +entry: +; CHECK-LABEL: .ent divu + %0 = load i32* @uj, align 4 + %1 = load i32* @uk, align 4 + %div = udiv i32 %0, %1 + store i32 %div, i32* @ui, align 4 +; 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]]) + ret void +} + +; Function Attrs: nounwind +define i32 @main() #1 { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval + call void @divs() + call void @divu() + %0 = load i32* @si, align 4 + %cmp = icmp ne i32 %0, -4255 + br i1 %cmp, label %if.then, label %if.end + +if.then: ; preds = %entry + call void @abort() #3 + unreachable + +if.end: ; preds = %entry + %1 = load i32* @ui, align 4 + %cmp1 = icmp ne i32 %1, 4651 + br i1 %cmp1, label %if.then2, label %if.end3 + +if.then2: ; preds = %if.end + call void @abort() #3 + unreachable + +if.end3: ; preds = %if.end + ret i32 0 +} + +; Function Attrs: noreturn +declare void @abort() #2 + +attributes #0 = { noinline nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #2 = { noreturn "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #3 = { noreturn } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"PIC Level", i32 2} +!1 = !{!"clang version 3.7.0 (gitosis@dmz-portal.mips.com:clang.git 1d11866537a9bf722c9c5b516151c23434242e24) (gitosis@dmz-portal.mips.com:llvm.git bad245f051b31c78846be1afe26a31eb2337deb2)"}