Commit cc6dea76 by Jaydeep Patil Committed by Jim Stichnoth

[SubZero] Use DIV instruction instead of TargetHelperCall

Use DIV/DIVU instructions provided by MIPS32 ISA instead of calling target helper function (__divsi3 etc.). These instructions give 32-bit quotient and remainder in 32-bit special LO/HI registers respectively. An additional instructions to check for divide-by-zero (Trap if equal) is emitted after the DIV/DIVU instructions. R=stichnot@chromium.org Review URL: https://codereview.chromium.org/2339323004 . Patch from Jaydeep Patil <jaydeep.patil@imgtec.com>.
parent 464df5b9
......@@ -140,6 +140,7 @@ template <> const char *InstMIPS32Sub_s::Opcode = "sub.s";
template <> const char *InstMIPS32Subu::Opcode = "subu";
template <> const char *InstMIPS32Sw::Opcode = "sw";
template <> const char *InstMIPS32Swc1::Opcode = "swc1";
template <> const char *InstMIPS32Teq::Opcode = "teq";
template <> const char *InstMIPS32Trunc_l_d::Opcode = "trunc.l.d";
template <> const char *InstMIPS32Trunc_l_s::Opcode = "trunc.l.s";
template <> const char *InstMIPS32Trunc_w_d::Opcode = "trunc.w.d";
......
......@@ -265,6 +265,7 @@ public:
Subu,
Sw,
Swc1,
Teq,
Trunc_l_d,
Trunc_l_s,
Trunc_w_d,
......@@ -913,6 +914,60 @@ private:
static const char *Opcode;
};
// Trap
template <InstMIPS32::InstKindMIPS32 K>
class InstMIPS32Trap : public InstMIPS32 {
InstMIPS32Trap() = delete;
InstMIPS32Trap(const InstMIPS32Trap &) = delete;
InstMIPS32Trap &operator=(const InstMIPS32Trap &) = delete;
public:
static InstMIPS32Trap *create(Cfg *Func, Operand *Src0, Operand *Src1,
uint32_t Tcode) {
return new (Func->allocate<InstMIPS32Trap>())
InstMIPS32Trap(Func, Src0, Src1, Tcode);
}
void emit(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
Str << "\t" << Opcode << "\t";
getSrc(0)->emit(Func);
Str << ", ";
getSrc(1)->emit(Func);
Str << ", " << TrapCode;
}
void emitIAS(const Cfg *Func) const override {
(void)Func;
llvm_unreachable("Not yet implemented");
}
void dump(const Cfg *Func) const override {
if (!BuildDefs::dump())
return;
Ostream &Str = Func->getContext()->getStrEmit();
Str << "\t" << Opcode << "\t";
getSrc(0)->emit(Func);
Str << ", ";
getSrc(1)->emit(Func);
Str << ", " << TrapCode;
}
static bool classof(const Inst *Inst) { return isClassof(Inst, K); }
private:
InstMIPS32Trap(Cfg *Func, Operand *Src0, Operand *Src1, const uint32_t Tcode)
: InstMIPS32(Func, K, 2, nullptr), TrapCode(Tcode) {
addSource(Src0);
addSource(Src1);
}
static const char *Opcode;
const uint32_t TrapCode;
};
template <InstMIPS32::InstKindMIPS32 K, bool Signed = false>
class InstMIPS32Imm16 : public InstMIPS32 {
InstMIPS32Imm16() = delete;
......@@ -1120,6 +1175,7 @@ using InstMIPS32Sub_s = InstMIPS32ThreeAddrFPR<InstMIPS32::Sub_s>;
using InstMIPS32Subu = InstMIPS32ThreeAddrGPR<InstMIPS32::Subu>;
using InstMIPS32Sw = InstMIPS32Store<InstMIPS32::Sw>;
using InstMIPS32Swc1 = InstMIPS32Store<InstMIPS32::Swc1>;
using InstMIPS32Teq = InstMIPS32Trap<InstMIPS32::Teq>;
using InstMIPS32Trunc_l_d = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_l_d>;
using InstMIPS32Trunc_l_s = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_l_s>;
using InstMIPS32Trunc_w_d = InstMIPS32TwoAddrFPR<InstMIPS32::Trunc_w_d>;
......
......@@ -277,71 +277,6 @@ void TargetMIPS32::genTargetHelperCallFor(Inst *Instr) {
Instr->setDeleted();
return;
}
case IceType_i32:
case IceType_i16:
case IceType_i8: {
InstCast::OpKind CastKind;
RuntimeHelper HelperID = RuntimeHelper::H_Num;
switch (Op) {
default:
return;
case InstArithmetic::Udiv:
HelperID = RuntimeHelper::H_udiv_i32;
CastKind = InstCast::Zext;
break;
case InstArithmetic::Sdiv:
HelperID = RuntimeHelper::H_sdiv_i32;
CastKind = InstCast::Sext;
break;
case InstArithmetic::Urem:
HelperID = RuntimeHelper::H_urem_i32;
CastKind = InstCast::Zext;
break;
case InstArithmetic::Srem:
HelperID = RuntimeHelper::H_srem_i32;
CastKind = InstCast::Sext;
break;
}
if (HelperID == RuntimeHelper::H_Num) {
return;
}
Operand *Src0 = Instr->getSrc(0);
Operand *Src1 = Instr->getSrc(1);
if (DestTy != IceType_i32) {
// Src0 and Src1 have to be zero-, or signed-extended to i32. For Src0,
// we just insert a InstCast right before the call to the helper.
Variable *Src0_32 = Func->makeVariable(IceType_i32);
Context.insert<InstCast>(CastKind, Src0_32, Src0);
Src0 = Src0_32;
if (auto *C = llvm::dyn_cast<ConstantInteger32>(Src1)) {
const int32_t ShAmt = (DestTy == IceType_i16) ? 16 : 24;
int32_t NewC = C->getValue();
if (CastKind == InstCast::Zext) {
NewC &= ~(0x80000000l >> ShAmt);
} else {
NewC = (NewC << ShAmt) >> ShAmt;
}
Src1 = Ctx->getConstantInt32(NewC);
} else {
Variable *Src1_32 = Func->makeVariable(IceType_i32);
Context.insert<InstCast>(CastKind, Src1_32, Src1);
Src1 = Src1_32;
}
}
Operand *TargetHelper = Ctx->getRuntimeHelperFunc(HelperID);
constexpr SizeT MaxArgs = 2;
auto *Call = Context.insert<InstCall>(MaxArgs, Dest, TargetHelper,
NoTailCall, IsTargetHelperCall);
assert(Src0->getType() == IceType_i32);
Call->addArg(Src0);
assert(Src1->getType() == IceType_i32);
Call->addArg(Src1);
Instr->setDeleted();
return;
}
case IceType_f32:
case IceType_f64: {
if (Op != InstArithmetic::Frem) {
......@@ -1910,6 +1845,7 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Instr) {
Variable *T = makeReg(Dest->getType());
Variable *Src0R = legalizeToReg(Src0);
Variable *Src1R = legalizeToReg(Src1);
constexpr uint32_t DivideByZeroTrapCode = 7;
switch (Instr->getOp()) {
case InstArithmetic::_num:
......@@ -1957,6 +1893,7 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Instr) {
case InstArithmetic::Udiv: {
auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
_divu(T_Zero, Src0R, Src1R);
_teq(Src1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
_mflo(T, T_Zero);
_mov(Dest, T);
return;
......@@ -1964,6 +1901,7 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Instr) {
case InstArithmetic::Sdiv: {
auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
_div(T_Zero, Src0R, Src1R);
_teq(Src1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
_mflo(T, T_Zero);
_mov(Dest, T);
return;
......@@ -1971,6 +1909,7 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Instr) {
case InstArithmetic::Urem: {
auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
_divu(T_Zero, Src0R, Src1R);
_teq(Src1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
_mfhi(T, T_Zero);
_mov(Dest, T);
return;
......@@ -1978,6 +1917,7 @@ void TargetMIPS32::lowerArithmetic(const InstArithmetic *Instr) {
case InstArithmetic::Srem: {
auto *T_Zero = I32Reg(RegMIPS32::Reg_ZERO);
_div(T_Zero, Src0R, Src1R);
_teq(Src1R, T_Zero, DivideByZeroTrapCode); // Trap if divide-by-zero
_mfhi(T, T_Zero);
_mov(Dest, T);
return;
......
......@@ -505,6 +505,10 @@ public:
Context.insert<InstMIPS32Swc1>(Value, Mem);
}
void _teq(Variable *Src0, Variable *Src1, uint32_t TrapCode) {
Context.insert<InstMIPS32Teq>(Src0, Src1, TrapCode);
}
void _trunc_l_d(Variable *Dest, Variable *Src) {
Context.insert<InstMIPS32Trunc_l_d>(Dest, Src);
}
......
......@@ -171,7 +171,9 @@ entry:
; ARM32HWDIV: sdiv
; MIPS32-LABEL: Sdiv
; MIPS32: jal {{.*}} __divsi3
; MIPS32: div zero,{{.*}},[[REG:.*]]
; MIPS32: teq [[REG]],zero,0x7
; MIPS32: mflo
define internal i32 @SdivConst(i32 %a) {
entry:
......@@ -190,7 +192,9 @@ entry:
; ARM32HWDIV: sdiv
; MIPS32-LABEL: SdivConst
; MIPS32: jal {{.*}} __divsi3
; MIPS32: div zero,{{.*}},[[REG:.*]]
; MIPS32: teq [[REG]],zero,0x7
; MIPS32: mflo
define internal i32 @Srem(i32 %a, i32 %b) {
entry:
......@@ -212,7 +216,9 @@ entry:
; ARM32HWDIV: mls
; MIPS32-LABEL: Srem
; MIPS32: jal {{.*}} __modsi3
; MIPS32: div zero,{{.*}},[[REG:.*]]
; MIPS32: teq [[REG]],zero,0x7
; MIPS32: mfhi
define internal i32 @Udiv(i32 %a, i32 %b) {
entry:
......@@ -232,7 +238,9 @@ entry:
; ARM32HWDIV: udiv
; MIPS32-LABEL: Udiv
; MIPS32: jal {{.*}} __udivsi3
; MIPS32: divu zero,{{.*}},[[REG:.*]]
; MIPS32: teq [[REG]],zero,0x7
; MIPS32: mflo
define internal i32 @Urem(i32 %a, i32 %b) {
entry:
......@@ -253,7 +261,9 @@ entry:
; ARM32HWDIV: mls
; MIPS32-LABEL: Urem
; MIPS32: jal {{.*}} __umodsi3
; MIPS32: divu zero,{{.*}},[[REG:.*]]
; MIPS32: teq [[REG]],zero,0x7
; MIPS32: mfhi
; The following tests check that shift instructions don't try to use a
; ConstantRelocatable as an immediate operand.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment