Discussion:
Division by zero
via Digitalmars-d
2014-10-03 12:31:52 UTC
Permalink
http://dlang.org/expression#MulExpression says:

"For integral operands of the / and % operators, [...]. If the
divisor is zero, an Exception is thrown."

However, DMD behaves differently. Consider this simple test
program:

int test_int() {
int x;
return x/x;
}

long test_long() {
long x;
return x/x;
}

int test_runtime(int x) {
return x/x;
}

int main() {
return test_runtime(0);
}

When compiled without optimization, the program receives SIGFPE
at runtime (i.e. not an exception, but a signal).

The generated code for `test_int` and `test_long` looks like
this, with the constants returned changing on each compilation:

Disassembly of section .text._D2xx8test_intFZi:

0000000000000000 <_D2xx8test_intFZi>:
0: 55 push %rbp
1: 48 8b ec mov %rsp,%rbp
4: b8 80 63 54 02 mov $0x2546380,%eax
9: 5d pop %rbp
a: c3 retq
b: 0f 1f 44 00 00 nopl 0x0(%rax,%rax,1)

Disassembly of section .text._D2xx9test_longFZl:

0000000000000000 <_D2xx9test_longFZl>:
0: 55 push %rbp
1: 48 8b ec mov %rsp,%rbp
4: 48 b8 e0 63 54 02 00 movabs $0x25463e0,%rax
b: 00 00 00
e: 5d pop %rbp
f: c3 retq

When compiled with "-O -inline", it doesn't receive the signal,
but returns a nonsense value. This is to be expected, because
inlining just propagates the wrong value to the main function.

The same exercise for LDC 0.14.0: When run, the program behaves
the similarly as with DMD (SIGFPE without optimization, always
return value "1" with -O3). The disassembly without optimization:

Disassembly of section .text._D2xx8test_intFZi:

0000000000000000 <_D2xx8test_intFZi>:
0: c7 44 24 fc 00 00 00 movl $0x0,-0x4(%rsp)
7: 00
8: 8b 44 24 fc mov -0x4(%rsp),%eax
c: 99 cltd
d: f7 7c 24 fc idivl -0x4(%rsp)
11: c3 retq

Disassembly of section .text._D2xx9test_longFZl:

0000000000000000 <_D2xx9test_longFZl>:
0: 48 c7 44 24 f8 00 00 movq $0x0,-0x8(%rsp)
7: 00 00
9: 48 8b 44 24 f8 mov -0x8(%rsp),%rax
e: 48 99 cqto
10: 48 f7 7c 24 f8 idivq -0x8(%rsp)
15: c3 retq

However, with -O3, it gets interesting:

Disassembly of section .text._D2xx8test_intFZi:

0000000000000000 <_D2xx8test_intFZi>:
0: c3 retq

Disassembly of section .text._D2xx9test_longFZl:

0000000000000000 <_D2xx9test_longFZl>:
0: c3 retq

Disassembly of section .text._D2xx12test_runtimeFiZi:

0000000000000000 <_D2xx12test_runtimeFiZi>:
0: b8 01 00 00 00 mov $0x1,%eax
5: c3 retq

test_int() and test_long() return ...nothing! And test_runtime()
always returns 1.

Now the big question: How many bugs are there, and where are
they? Candidates: The specification, DMD's frontend (in two
versions: DMD master, and 2.065 used by LDC), DMD's backend and
LDC's backend.
David Nadlinger via Digitalmars-d
2014-10-03 12:54:36 UTC
Permalink
Post by via Digitalmars-d
test_int() and test_long() return ...nothing!
Note that they just return whatever is in eax/rax at that time,
just like DMD returns a garbage value.

The fact that integer division by zero is undefined behavior on
the LLVM side but defined in the D spec may well be an LDC bug,
though.

David
Adam D. Ruppe via Digitalmars-d
2014-10-03 12:55:34 UTC
Permalink
Post by via Digitalmars-d
"For integral operands of the / and % operators, [...]. If the
divisor is zero, an Exception is thrown."
It should probably just say that is implementation defined. I'm
pretty sure it does throw an exception on Windows (at least 32
bit), but doing that on linux is a pain in the butt since the
operating system sends a signal and transformaing that into an
exception is hacky.
monarch_dodra via Digitalmars-d
2014-10-03 13:11:56 UTC
Permalink
Post by Adam D. Ruppe via Digitalmars-d
Post by via Digitalmars-d
"For integral operands of the / and % operators, [...]. If the
divisor is zero, an Exception is thrown."
It should probably just say that is implementation defined. I'm
pretty sure it does throw an exception on Windows (at least 32
bit)...
Technically, the doc is also wrong for windows, since it's an
*Error* that is thrown:
object.Error@(0): Integer Division by 0
Walter Bright via Digitalmars-d
2014-10-03 13:29:16 UTC
Permalink
Post by via Digitalmars-d
"For integral operands of the / and % operators, [...]. If the
divisor is zero, an Exception is thrown."
It should probably just say that is implementation defined. I'm pretty
sure it does throw an exception on Windows (at least 32 bit)...
Technically, the doc is also wrong for windows, since it's an *Error*
In any case, a bugzilla issue should be filed for this.
monarch_dodra via Digitalmars-d
2014-10-03 14:22:09 UTC
Permalink
Post by Walter Bright via Digitalmars-d
In any case, a bugzilla issue should be filed for this.
https://issues.dlang.org/show_bug.cgi?id=13569
Walter Bright via Digitalmars-d
2014-10-04 20:42:43 UTC
Permalink
Post by monarch_dodra via Digitalmars-d
Post by Walter Bright via Digitalmars-d
In any case, a bugzilla issue should be filed for this.
https://issues.dlang.org/show_bug.cgi?id=13569
Thanks!

Daniel Murphy via Digitalmars-d
2014-10-03 14:55:01 UTC
Permalink
"Marc SchÃŒtz" " wrote in message
Now the big question: How many bugs are there, and where are they?
Candidates: The specification, DMD's frontend (in two versions: DMD
master, and 2.065 used by LDC), DMD's backend and LDC's backend.
https://issues.dlang.org/show_bug.cgi?id=5908
David Nadlinger via Digitalmars-d
2014-10-03 15:09:32 UTC
Permalink
Post by Daniel Murphy via Digitalmars-d
https://issues.dlang.org/show_bug.cgi?id=5908
By the way, this (just emitting an x86 idiv even if it the
operands are known to trap) will likely be a pain to implement
for LDC. There has been an (overly aggressive, on the side of two
LLVM devs) discussion about this a year ago or so:
http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/060930.html.

Personally, I find their stance highly troublesome, as they have
introduced undefined behavior that is hard to circumvent for
practically no potential performance gain. I just hope we can
somehow avoid emitting a branch on every integer division


Cheers,
David
Daniel Murphy via Digitalmars-d
2014-10-03 15:59:10 UTC
Permalink
"David Nadlinger" wrote in message
By the way, this (just emitting an x86 idiv even if it the operands are
known to trap) will likely be a pain to implement for LDC. There has been
an (overly aggressive, on the side of two LLVM devs) discussion about this
http://lists.cs.uiuc.edu/pipermail/llvmdev/2013-April/060930.html.
Personally, I find their stance highly troublesome, as they have
introduced undefined behavior that is hard to circumvent for practically
no potential performance gain. I just hope we can somehow avoid emitting a
branch on every integer division

That's annoying, but I guess it makes sense given how much division varies
across platforms.
Continue reading on narkive:
Loading...