Skip to content

[Mips] mips1 DivByZeroTrap #81311

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 47 additions & 16 deletions llvm/lib/Target/Mips/MipsISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1268,24 +1268,53 @@ addLiveIn(MachineFunction &MF, unsigned PReg, const TargetRegisterClass *RC)
static MachineBasicBlock *insertDivByZeroTrap(MachineInstr &MI,
MachineBasicBlock &MBB,
const TargetInstrInfo &TII,
bool Is64Bit, bool IsMicroMips) {
bool Is64Bit, bool IsMicroMips,
bool IsMips1) {
if (NoZeroDivCheck)
return &MBB;

// Insert instruction "teq $divisor_reg, $zero, 7".
MachineBasicBlock::iterator I(MI);
MachineInstrBuilder MIB;
MachineOperand &Divisor = MI.getOperand(2);
MIB = BuildMI(MBB, std::next(I), MI.getDebugLoc(),
TII.get(IsMicroMips ? Mips::TEQ_MM : Mips::TEQ))
.addReg(Divisor.getReg(), getKillRegState(Divisor.isKill()))
.addReg(Mips::ZERO)
.addImm(7);

// Use the 32-bit sub-register if this is a 64-bit division.
if (Is64Bit)
MIB->getOperand(0).setSubReg(Mips::sub_32);
if (IsMips1) {

// Insert "beq $divisor_reg, $zero, label"
// Insert "break 7"
DebugLoc DL = MI.getDebugLoc();
MachineBasicBlock *BMBB = MBB.splitAt(MI, true);
MachineInstrBuilder MIB;
// Add branch after div
MIB = BuildMI(MBB, std::next(MI.getIterator()), DL, TII.get(Mips::BNE))
.addReg(Divisor.getReg(), getKillRegState(Divisor.isKill()))
.addReg(Mips::ZERO);

// insert break at start of next block
BuildMI(*BMBB, BMBB->instr_front(), DL, TII.get(Mips::BREAK))
.addImm(0)
.addImm(7);

// split break into own block
MachineBasicBlock *EndMBB = BMBB->splitAt(BMBB->front(), true);
// add branch target
MBB.addSuccessor(EndMBB);
MIB.addMBB(EndMBB);

Divisor.setIsKill(false);
return EndMBB;

} else {
MachineBasicBlock::iterator I(MI);
// Insert instruction "teq $divisor_reg, $zero, 7".
MachineInstrBuilder MIB;
MIB = BuildMI(MBB, std::next(I), MI.getDebugLoc(),
TII.get(IsMicroMips ? Mips::TEQ_MM : Mips::TEQ))
.addReg(Divisor.getReg(), getKillRegState(Divisor.isKill()))
.addReg(Mips::ZERO)
.addImm(7);

// Use the 32-bit sub-register if this is a 64-bit division.
if (Is64Bit)
MIB->getOperand(0).setSubReg(Mips::sub_32);
}
// Clear Divisor's kill flag.
Divisor.setIsKill(false);

Expand Down Expand Up @@ -1415,8 +1444,8 @@ MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case Mips::DIVU:
case Mips::MOD:
case Mips::MODU:
return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo(), false,
false);
return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo(), false, false,
!Subtarget.hasMips2());
case Mips::SDIV_MM_Pseudo:
case Mips::UDIV_MM_Pseudo:
case Mips::SDIV_MM:
Expand All @@ -1425,14 +1454,16 @@ MipsTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case Mips::DIVU_MMR6:
case Mips::MOD_MMR6:
case Mips::MODU_MMR6:
return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo(), false, true);
return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo(), false, true,
false);
case Mips::PseudoDSDIV:
case Mips::PseudoDUDIV:
case Mips::DDIV:
case Mips::DDIVU:
case Mips::DMOD:
case Mips::DMODU:
return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo(), true, false);
return insertDivByZeroTrap(MI, *BB, *Subtarget.getInstrInfo(), true, false,
false);

case Mips::PseudoSELECT_I:
case Mips::PseudoSELECT_I64:
Expand Down
220 changes: 176 additions & 44 deletions llvm/test/CodeGen/Mips/llvm-ir/sdiv.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=mips -mcpu=mips1 -relocation-model=pic \
; RUN: -mips-jalr-reloc=false | FileCheck %s -check-prefixes=GP32,GP32R0R1
; RUN: llc < %s -mtriple=mips -mcpu=mips2 -relocation-model=pic \
; RUN: -mips-jalr-reloc=false | FileCheck %s -check-prefixes=GP32,GP32R0R2
; RUN: llc < %s -mtriple=mips -mcpu=mips32 -relocation-model=pic \
Expand Down Expand Up @@ -70,6 +72,19 @@ entry:
}

define signext i8 @sdiv_i8(i8 signext %a, i8 signext %b) {
; GP32R0R1-LABEL: sdiv_i8:
; GP32R0R1: # %bb.0: # %entry
; GP32R0R1-NEXT: div $zero, $4, $5
; GP32R0R1-NEXT: bnez $5, $BB1_2
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: # %bb.1: # %entry
; GP32R0R1-NEXT: break 0, 7
; GP32R0R1-NEXT: $BB1_2: # %entry
; GP32R0R1-NEXT: mflo $1
; GP32R0R1-NEXT: sll $1, $1, 24
; GP32R0R1-NEXT: jr $ra
; GP32R0R1-NEXT: sra $2, $1, 24
;
; GP32R0R2-LABEL: sdiv_i8:
; GP32R0R2: # %bb.0: # %entry
; GP32R0R2-NEXT: div $zero, $4, $5
Expand Down Expand Up @@ -138,6 +153,19 @@ entry:
}

define signext i16 @sdiv_i16(i16 signext %a, i16 signext %b) {
; GP32R0R1-LABEL: sdiv_i16:
; GP32R0R1: # %bb.0: # %entry
; GP32R0R1-NEXT: div $zero, $4, $5
; GP32R0R1-NEXT: bnez $5, $BB2_2
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: # %bb.1: # %entry
; GP32R0R1-NEXT: break 0, 7
; GP32R0R1-NEXT: $BB2_2: # %entry
; GP32R0R1-NEXT: mflo $1
; GP32R0R1-NEXT: sll $1, $1, 16
; GP32R0R1-NEXT: jr $ra
; GP32R0R1-NEXT: sra $2, $1, 16
;
; GP32R0R2-LABEL: sdiv_i16:
; GP32R0R2: # %bb.0: # %entry
; GP32R0R2-NEXT: div $zero, $4, $5
Expand Down Expand Up @@ -206,12 +234,30 @@ entry:
}

define signext i32 @sdiv_i32(i32 signext %a, i32 signext %b) {
; GP32-LABEL: sdiv_i32:
; GP32: # %bb.0: # %entry
; GP32-NEXT: div $zero, $4, $5
; GP32-NEXT: teq $5, $zero, 7
; GP32-NEXT: jr $ra
; GP32-NEXT: mflo $2
; GP32R0R1-LABEL: sdiv_i32:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note, MIPS32R1 is not same as MIPS I.
The road map of MIPS Rev is like

32bit I II 32R1
64bit III IV V. 64R1

This name scheme is quite confusion.

Copy link
Author

@cmccord-dev cmccord-dev Feb 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I based the naming here off the entries that already existed for MIPS II, my changes are specifically for MIPS I, not Mips32R1, though I agree the naming scheme is very confusing. Whoever wrote this originally referred to MIPSII as MIPS32R0R2, then MIPS32R1 as just MIPS32R1 Would you recommend changing the names for both mips1 and mips2?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since MIPS I is not supported well yet for LLVM, and I guess the 32R0 was supposed to be equal with MIPS II in this context.

If we need MIPS I, we may use a new name for it, maybe 32_I?

; GP32R0R1: # %bb.0: # %entry
; GP32R0R1-NEXT: div $zero, $4, $5
; GP32R0R1-NEXT: bnez $5, $BB3_2
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: # %bb.1: # %entry
; GP32R0R1-NEXT: break 0, 7
; GP32R0R1-NEXT: $BB3_2: # %entry
; GP32R0R1-NEXT: jr $ra
; GP32R0R1-NEXT: mflo $2
;
; GP32R0R2-LABEL: sdiv_i32:
; GP32R0R2: # %bb.0: # %entry
; GP32R0R2-NEXT: div $zero, $4, $5
; GP32R0R2-NEXT: teq $5, $zero, 7
; GP32R0R2-NEXT: jr $ra
; GP32R0R2-NEXT: mflo $2
;
; GP32R2R5-LABEL: sdiv_i32:
; GP32R2R5: # %bb.0: # %entry
; GP32R2R5-NEXT: div $zero, $4, $5
; GP32R2R5-NEXT: teq $5, $zero, 7
; GP32R2R5-NEXT: jr $ra
; GP32R2R5-NEXT: mflo $2
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

R0R2 is same with R2R5?
If so, why not merge them?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

good point, these test cases were autogenerated by utils/update_llc_test_checks.py, I just changed the header bit. I can merge them, but if the test cases change again later, they'll have to be remerged.

;
; GP32R6-LABEL: sdiv_i32:
; GP32R6: # %bb.0: # %entry
Expand Down Expand Up @@ -250,21 +296,55 @@ entry:
}

define signext i64 @sdiv_i64(i64 signext %a, i64 signext %b) {
; GP32-LABEL: sdiv_i64:
; GP32: # %bb.0: # %entry
; GP32-NEXT: lui $2, %hi(_gp_disp)
; GP32-NEXT: addiu $2, $2, %lo(_gp_disp)
; GP32-NEXT: addiu $sp, $sp, -24
; GP32-NEXT: .cfi_def_cfa_offset 24
; GP32-NEXT: sw $ra, 20($sp) # 4-byte Folded Spill
; GP32-NEXT: .cfi_offset 31, -4
; GP32-NEXT: addu $gp, $2, $25
; GP32-NEXT: lw $25, %call16(__divdi3)($gp)
; GP32-NEXT: jalr $25
; GP32-NEXT: nop
; GP32-NEXT: lw $ra, 20($sp) # 4-byte Folded Reload
; GP32-NEXT: jr $ra
; GP32-NEXT: addiu $sp, $sp, 24
; GP32R0R1-LABEL: sdiv_i64:
; GP32R0R1: # %bb.0: # %entry
; GP32R0R1-NEXT: lui $2, %hi(_gp_disp)
; GP32R0R1-NEXT: addiu $2, $2, %lo(_gp_disp)
; GP32R0R1-NEXT: addiu $sp, $sp, -24
; GP32R0R1-NEXT: .cfi_def_cfa_offset 24
; GP32R0R1-NEXT: sw $ra, 20($sp) # 4-byte Folded Spill
; GP32R0R1-NEXT: .cfi_offset 31, -4
; GP32R0R1-NEXT: addu $gp, $2, $25
; GP32R0R1-NEXT: lw $25, %call16(__divdi3)($gp)
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: jalr $25
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: lw $ra, 20($sp) # 4-byte Folded Reload
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: jr $ra
; GP32R0R1-NEXT: addiu $sp, $sp, 24
;
; GP32R0R2-LABEL: sdiv_i64:
; GP32R0R2: # %bb.0: # %entry
; GP32R0R2-NEXT: lui $2, %hi(_gp_disp)
; GP32R0R2-NEXT: addiu $2, $2, %lo(_gp_disp)
; GP32R0R2-NEXT: addiu $sp, $sp, -24
; GP32R0R2-NEXT: .cfi_def_cfa_offset 24
; GP32R0R2-NEXT: sw $ra, 20($sp) # 4-byte Folded Spill
; GP32R0R2-NEXT: .cfi_offset 31, -4
; GP32R0R2-NEXT: addu $gp, $2, $25
; GP32R0R2-NEXT: lw $25, %call16(__divdi3)($gp)
; GP32R0R2-NEXT: jalr $25
; GP32R0R2-NEXT: nop
; GP32R0R2-NEXT: lw $ra, 20($sp) # 4-byte Folded Reload
; GP32R0R2-NEXT: jr $ra
; GP32R0R2-NEXT: addiu $sp, $sp, 24
;
; GP32R2R5-LABEL: sdiv_i64:
; GP32R2R5: # %bb.0: # %entry
; GP32R2R5-NEXT: lui $2, %hi(_gp_disp)
; GP32R2R5-NEXT: addiu $2, $2, %lo(_gp_disp)
; GP32R2R5-NEXT: addiu $sp, $sp, -24
; GP32R2R5-NEXT: .cfi_def_cfa_offset 24
; GP32R2R5-NEXT: sw $ra, 20($sp) # 4-byte Folded Spill
; GP32R2R5-NEXT: .cfi_offset 31, -4
; GP32R2R5-NEXT: addu $gp, $2, $25
; GP32R2R5-NEXT: lw $25, %call16(__divdi3)($gp)
; GP32R2R5-NEXT: jalr $25
; GP32R2R5-NEXT: nop
; GP32R2R5-NEXT: lw $ra, 20($sp) # 4-byte Folded Reload
; GP32R2R5-NEXT: jr $ra
; GP32R2R5-NEXT: addiu $sp, $sp, 24
;
; GP32R6-LABEL: sdiv_i64:
; GP32R6: # %bb.0: # %entry
Expand Down Expand Up @@ -332,29 +412,81 @@ entry:
}

define signext i128 @sdiv_i128(i128 signext %a, i128 signext %b) {
; GP32-LABEL: sdiv_i128:
; GP32: # %bb.0: # %entry
; GP32-NEXT: lui $2, %hi(_gp_disp)
; GP32-NEXT: addiu $2, $2, %lo(_gp_disp)
; GP32-NEXT: addiu $sp, $sp, -40
; GP32-NEXT: .cfi_def_cfa_offset 40
; GP32-NEXT: sw $ra, 36($sp) # 4-byte Folded Spill
; GP32-NEXT: .cfi_offset 31, -4
; GP32-NEXT: addu $gp, $2, $25
; GP32-NEXT: lw $1, 60($sp)
; GP32-NEXT: lw $2, 64($sp)
; GP32-NEXT: lw $3, 68($sp)
; GP32-NEXT: sw $3, 28($sp)
; GP32-NEXT: sw $2, 24($sp)
; GP32-NEXT: sw $1, 20($sp)
; GP32-NEXT: lw $1, 56($sp)
; GP32-NEXT: sw $1, 16($sp)
; GP32-NEXT: lw $25, %call16(__divti3)($gp)
; GP32-NEXT: jalr $25
; GP32-NEXT: nop
; GP32-NEXT: lw $ra, 36($sp) # 4-byte Folded Reload
; GP32-NEXT: jr $ra
; GP32-NEXT: addiu $sp, $sp, 40
; GP32R0R1-LABEL: sdiv_i128:
; GP32R0R1: # %bb.0: # %entry
; GP32R0R1-NEXT: lui $2, %hi(_gp_disp)
; GP32R0R1-NEXT: addiu $2, $2, %lo(_gp_disp)
; GP32R0R1-NEXT: addiu $sp, $sp, -40
; GP32R0R1-NEXT: .cfi_def_cfa_offset 40
; GP32R0R1-NEXT: sw $ra, 36($sp) # 4-byte Folded Spill
; GP32R0R1-NEXT: .cfi_offset 31, -4
; GP32R0R1-NEXT: addu $gp, $2, $25
; GP32R0R1-NEXT: lw $1, 60($sp)
; GP32R0R1-NEXT: lw $2, 64($sp)
; GP32R0R1-NEXT: lw $3, 68($sp)
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: sw $3, 28($sp)
; GP32R0R1-NEXT: sw $2, 24($sp)
; GP32R0R1-NEXT: sw $1, 20($sp)
; GP32R0R1-NEXT: lw $1, 56($sp)
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: sw $1, 16($sp)
; GP32R0R1-NEXT: lw $25, %call16(__divti3)($gp)
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: jalr $25
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: lw $ra, 36($sp) # 4-byte Folded Reload
; GP32R0R1-NEXT: nop
; GP32R0R1-NEXT: jr $ra
; GP32R0R1-NEXT: addiu $sp, $sp, 40
;
; GP32R0R2-LABEL: sdiv_i128:
; GP32R0R2: # %bb.0: # %entry
; GP32R0R2-NEXT: lui $2, %hi(_gp_disp)
; GP32R0R2-NEXT: addiu $2, $2, %lo(_gp_disp)
; GP32R0R2-NEXT: addiu $sp, $sp, -40
; GP32R0R2-NEXT: .cfi_def_cfa_offset 40
; GP32R0R2-NEXT: sw $ra, 36($sp) # 4-byte Folded Spill
; GP32R0R2-NEXT: .cfi_offset 31, -4
; GP32R0R2-NEXT: addu $gp, $2, $25
; GP32R0R2-NEXT: lw $1, 60($sp)
; GP32R0R2-NEXT: lw $2, 64($sp)
; GP32R0R2-NEXT: lw $3, 68($sp)
; GP32R0R2-NEXT: sw $3, 28($sp)
; GP32R0R2-NEXT: sw $2, 24($sp)
; GP32R0R2-NEXT: sw $1, 20($sp)
; GP32R0R2-NEXT: lw $1, 56($sp)
; GP32R0R2-NEXT: sw $1, 16($sp)
; GP32R0R2-NEXT: lw $25, %call16(__divti3)($gp)
; GP32R0R2-NEXT: jalr $25
; GP32R0R2-NEXT: nop
; GP32R0R2-NEXT: lw $ra, 36($sp) # 4-byte Folded Reload
; GP32R0R2-NEXT: jr $ra
; GP32R0R2-NEXT: addiu $sp, $sp, 40
;
; GP32R2R5-LABEL: sdiv_i128:
; GP32R2R5: # %bb.0: # %entry
; GP32R2R5-NEXT: lui $2, %hi(_gp_disp)
; GP32R2R5-NEXT: addiu $2, $2, %lo(_gp_disp)
; GP32R2R5-NEXT: addiu $sp, $sp, -40
; GP32R2R5-NEXT: .cfi_def_cfa_offset 40
; GP32R2R5-NEXT: sw $ra, 36($sp) # 4-byte Folded Spill
; GP32R2R5-NEXT: .cfi_offset 31, -4
; GP32R2R5-NEXT: addu $gp, $2, $25
; GP32R2R5-NEXT: lw $1, 60($sp)
; GP32R2R5-NEXT: lw $2, 64($sp)
; GP32R2R5-NEXT: lw $3, 68($sp)
; GP32R2R5-NEXT: sw $3, 28($sp)
; GP32R2R5-NEXT: sw $2, 24($sp)
; GP32R2R5-NEXT: sw $1, 20($sp)
; GP32R2R5-NEXT: lw $1, 56($sp)
; GP32R2R5-NEXT: sw $1, 16($sp)
; GP32R2R5-NEXT: lw $25, %call16(__divti3)($gp)
; GP32R2R5-NEXT: jalr $25
; GP32R2R5-NEXT: nop
; GP32R2R5-NEXT: lw $ra, 36($sp) # 4-byte Folded Reload
; GP32R2R5-NEXT: jr $ra
; GP32R2R5-NEXT: addiu $sp, $sp, 40
;
; GP32R6-LABEL: sdiv_i128:
; GP32R6: # %bb.0: # %entry
Expand Down
Loading