Skip to content
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

Assembler - Instructions div/divu expand into macros without means of disabling them #62

Open
Souzooka opened this issue May 3, 2020 · 4 comments

Comments

@Souzooka
Copy link

Souzooka commented May 3, 2020

When compiling assembly .s files which contain division instructions (div/divu), these instructions expand into multiple instructions which check if the divisor is 0, or (for div) if the divisor is -1 and the dividend is INT_MIN.

There seems to be no means of disabling this macro if unwanted, however. Command line arguments -mno-check-zero-division, --no-break, --no-trap, appear to have no effect on the compiled output.

@rickgaiser
Copy link
Member

I'll need a little more information to be able to help and reproduce the issue. Can you provide:

  • example code (few lines)
  • commands used to compile
  • commands used to decompile
  • expected result
  • received result

Hints:

  • Are you using .S or .s ?
  • Are you using gcc or as ?

@Souzooka
Copy link
Author

Souzooka commented May 5, 2020

I am using .s files and using ee-gcc to assemble. The issue can be replicated with an input file containing text such as

  .text
  .global main
  .set noreorder
  .set noat
main:
  div $v0, $v0
  jr $ra
  nop

When assembled with

ee-gcc input.s -mno-check-zero-division

I expect the main subroutine to compile into

main:
  div $v0, $v0
  jr $ra
  nop

While the actual result is:

main:
  bnez $v0, L1
  div $v0, $v0
  break 7
L1:
  dli $at, -1
  bne $v0, $at, L2
  lui $at, 0x8000
  bne $v0, $at, L2
  nop
  break 6
L2:
  mflo $v0
  jr $ra
  nop

@rickgaiser
Copy link
Member

The behaviour is strage, but there's a solution. The ps2's DIV instruction has only 2 operands and places the result in the HI/LO register. However, binutils will always want to see 3 operands, so we have to use $0 as the third operand.
You'll have to get the result out of the LO register with mflo $2.

So:

main:
  div $0, $v0, $v0
  mflo $2
  jr $ra

Should work. Don't add the NOP so binutils can optimize the branch delay slot, so the end result woll look like:

main:
  div $0, $v0, $v0
  jr $ra
  mflo $2

@Souzooka
Copy link
Author

Souzooka commented May 5, 2020

That does work as a workaround to the issue, thank you. Certainly a lot easier than writing it out using a .byte directive.

I think it's also worth nothing that this behavior does not apply to div1 and divu1; checking division arguments and mflo only occurs for div/divu.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants