cancel
Showing results for 
Show  only  | Search instead for 
Did you mean: 
dbrinks
Visitor
Visitor
6,437 Views
Registered: ‎10-13-2009

Mod operation causes an infinite loop for MicroBlaze

Something I noticed today is that the implementation for the mod operator as implemented on a microblaze will go into an infinite loop when the numerator is the most negative number. Example:

 

 

xil_printf("here\r\n"); int y = 2147483647; int x = y % 1000000; xil_printf("done 1 %d\r\n", x); y++; x = y % 1000000; xil_printf("done 2 %d\r\n", x);

 

The first two printfs will occur, but the third never will. Essentially, this is the result of the mod function, which tries to negate a negative parameter. However, for the most negative number, the twos complement results in the same number (still negative). The mod assumes from that point forward that the number is positive, when it isn't. This causes an infinite loop.

 

Clearly, clever coding can avoid this (don't mod the most negative number!). However, I found it interesting and it seems like a bug which should be fixed.

 

Cheers,

Dan 

 

0 Kudos
5 Replies
jagron
Adventurer
Adventurer
6,427 Views
Registered: ‎01-04-2008

Can you disassemble your executable using mb-objdump (mb-objdump D <elfFile> > out.dsm) to check to see what is generated to implement the 'mod' operator?

 

MB-GCC should generate a call to the __modsi3 function, but you may have it configured to use a DIV instruction that may not be available with your processor's configuration.

 

Another guess is to try to run the code through the debugger to see where it's getting stuck at.  The __modsi3 function is iterative, and may be getting stuck in a loop for some strange reason.

 

- Jason

0 Kudos
dbrinks
Visitor
Visitor
6,424 Views
Registered: ‎10-13-2009

I'm not at work right now, so I can't give you specifics. However, I do know that the mod operator is being implemented with the __modsi3 function. However, that function checks to see if your parameter is negative. If it is, then it tries to invert it using rsubi. However, for the maximum negative integer the returns the maximum negative integer. This ends up causing a problem because the function is expecting a positive number at this point. I'll link the exact code tomorrow with a walk through of where the infinite loop is occurring.

 

Dan 

0 Kudos
dbrinks
Visitor
Visitor
6,409 Views
Registered: ‎10-13-2009

So here's the code for my __modsi3 function:

 

 

00007610 <__modsi3>: 7610: 3021fff0 addik r1, r1, -16 7614: fb810000 swi r28, r1, 0 7618: fba10004 swi r29, r1, 4 761c: fbc10008 swi r30, r1, 8 7620: fbe1000c swi r31, r1, 12 7624: bc060068 beqi r6, 104 // 768c 7628: bc050064 beqi r5, 100 // 768c 762c: bea5000c bgeid r5, 12 // 7638 7630: 03850000 add r28, r5, r0 7634: 24a50000 rsubi r5, r5, 0 7638: bca60008 bgei r6, 8 // 7640 763c: 24c60000 rsubi r6, r6, 0 7640: 30600000 addik r3, r0, 0 7644: 33c00000 addik r30, r0, 0 7648: 33a00020 addik r29, r0, 32 // 20 <_vector_hw_exception> 764c: 00a52800 add r5, r5, r5 7650: bea5fffc bgeid r5, -4 // 764c

 

So, the first operand to the mod will be in r5. Here's a walk through of what happens if r5 contains 0x80000000 and r6 (the second operand) contains some positive number.

 

--The stack pointer is decremented (0x7610) 

--Some registers (r28-r31) are stored on the stack (0x7614-0x7620)

--If r6 or r5 is 0, the code jumps to 0x768c (0x7624-7628)

--If r6 is greater than 0, the code jumps to 0x7638 (0x762c) else:

----r5 is stored in r28 (0x7630)

----r5 is negated using rsubi. However, this results in the value 0x80000000 in r5 (0x7634)

--If r6 is greater than 0, the code jumps to 0x7640 (0x7638). This jump is taken.

--0 is placed in r3 and r30 (0x7640-0x7644)

--32 is placed in r29 (0x7648)

--do 

--r5 is added to itself and stored in r5. This is stored in r5 (0x764c). The result is 0x00000000

--while(r5 >= 0) (0x7650).

 

The loop infinitely loops between 0x7650 and 0x764c.

 

Cheers,

Dan 

 

 

0 Kudos
dbrinks
Visitor
Visitor
6,406 Views
Registered: ‎10-13-2009

Sorry about the formatting, for some reason the code insertion isn't working. Here's a straight text of the code. You can copy it into an editor.

 

 00007610 <__modsi3>:

    7610: 3021fff0 addik r1, r1, -16

    7614: fb810000 swi r28, r1, 0

    7618: fba10004 swi r29, r1, 4

    761c: fbc10008 swi r30, r1, 8

    7620: fbe1000c swi r31, r1, 12

    7624: bc060068 beqi r6, 104 // 768c

    7628: bc050064 beqi r5, 100 // 768c

    762c: bea5000c bgeid r5, 12 // 7638

    7630: 03850000 add r28, r5, r0

    7634: 24a50000 rsubi r5, r5, 0

    7638: bca60008 bgei r6, 8 // 7640

    763c: 24c60000 rsubi r6, r6, 0

    7640: 30600000 addik r3, r0, 0

    7644: 33c00000 addik r30, r0, 0

    7648: 33a00020 addik r29, r0, 32 // 20 <_vector_hw_exception>

    764c: 00a52800 add r5, r5, r5

    7650: bea5fffc bgeid r5, -4 // 764c

 
Dan 
0 Kudos
jagron
Adventurer
Adventurer
6,394 Views
Registered: ‎01-04-2008

I wonder what will happen if you re-implement the 'mod' operator as your own function.  Something like this...

 

https://llvm.org/svn/llvm-project/compiler-rt/trunk/lib/modsi3.c

 

... but it looks like it's a bug in some of the architecture-specific code used by mb-gcc.  I would open up a WebCase, and see if Xilinx will escalate it as a developer issue.

 

-Jason

0 Kudos