forked from M-Labs/artiq
compiler: correct semantics of floating point % operator (fix #830).
This commit is contained in:
parent
62f2693e36
commit
491c7ef898
@ -400,8 +400,7 @@ class LLVMIRGenerator:
|
|||||||
*/
|
*/
|
||||||
if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) {
|
if (xmody && ((y ^ xmody) < 0) /* i.e. and signs differ */) {
|
||||||
xmody += y;
|
xmody += y;
|
||||||
--xdivy;
|
// ...
|
||||||
assert(xmody && ((y ^ xmody) >= 0));
|
|
||||||
}
|
}
|
||||||
"""
|
"""
|
||||||
llx, lly = llfun.args
|
llx, lly = llfun.args
|
||||||
@ -417,7 +416,45 @@ class LLVMIRGenerator:
|
|||||||
llbuilder.ret(llbuilder.add(llxremy, lly))
|
llbuilder.ret(llbuilder.add(llxremy, lly))
|
||||||
llbuilder.ret(llxremy)
|
llbuilder.ret(llxremy)
|
||||||
elif name == "__py_moddf4":
|
elif name == "__py_moddf4":
|
||||||
assert False
|
"""
|
||||||
|
Reference Objects/floatobject.c
|
||||||
|
mod = fmod(vx, wx);
|
||||||
|
/* fmod is typically exact, so vx-mod is *mathematically* an
|
||||||
|
exact multiple of wx. But this is fp arithmetic, and fp
|
||||||
|
vx - mod is an approximation; the result is that div may
|
||||||
|
not be an exact integral value after the division, although
|
||||||
|
it will always be very close to one.
|
||||||
|
*/
|
||||||
|
// ...
|
||||||
|
if (mod) {
|
||||||
|
/* ensure the remainder has the same sign as the denominator */
|
||||||
|
if ((wx < 0) != (mod < 0)) {
|
||||||
|
mod += wx;
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
/* the remainder is zero, and in the presence of signed zeroes
|
||||||
|
fmod returns different results across platforms; ensure
|
||||||
|
it has the same sign as the denominator; we'd like to do
|
||||||
|
"mod = wx * 0.0", but that may get optimized away */
|
||||||
|
mod *= mod; /* hide "mod = +0" from optimizer */
|
||||||
|
if (wx < 0.0)
|
||||||
|
mod = -mod;
|
||||||
|
}
|
||||||
|
"""
|
||||||
|
llv, llw = llfun.args
|
||||||
|
llrem = llbuilder.frem(llv, llw)
|
||||||
|
|
||||||
|
llremnonzero = llbuilder.fcmp_unordered('!=', llrem, ll.Constant(lldouble, 0.0))
|
||||||
|
llwltzero = llbuilder.fcmp_ordered('<', llw, ll.Constant(lldouble, 0.0))
|
||||||
|
llremltzero = llbuilder.fcmp_ordered('<', llrem, ll.Constant(lldouble, 0.0))
|
||||||
|
lldiffsign = llbuilder.icmp_unsigned('!=', llwltzero, llremltzero)
|
||||||
|
|
||||||
|
llcond = llbuilder.and_(llremnonzero, lldiffsign)
|
||||||
|
with llbuilder.if_then(llcond):
|
||||||
|
llbuilder.ret(llbuilder.fadd(llrem, llw))
|
||||||
|
llbuilder.ret(llrem)
|
||||||
|
|
||||||
def get_function(self, typ, name):
|
def get_function(self, typ, name):
|
||||||
llfun = self.llmodule.get_global(name)
|
llfun = self.llmodule.get_global(name)
|
||||||
|
@ -26,10 +26,10 @@ assert -1 % 8 == 7
|
|||||||
#ARTIQ#assert int64(3) % -2 == -1
|
#ARTIQ#assert int64(3) % -2 == -1
|
||||||
#ARTIQ#assert int64(-3) % -2 == -1
|
#ARTIQ#assert int64(-3) % -2 == -1
|
||||||
assert -1 % 8 == 7
|
assert -1 % 8 == 7
|
||||||
# assert 3.0 % 2.0 == 1.0
|
assert 3.0 % 2.0 == 1.0
|
||||||
# assert -3.0 % 2.0 == 1.0
|
assert -3.0 % 2.0 == 1.0
|
||||||
# assert 3.0 % -2.0 == -1.0
|
assert 3.0 % -2.0 == -1.0
|
||||||
# assert -3.0 % -2.0 == -1.0
|
assert -3.0 % -2.0 == -1.0
|
||||||
assert 3 ** 2 == 9
|
assert 3 ** 2 == 9
|
||||||
assert 3.0 ** 2.0 == 9.0
|
assert 3.0 ** 2.0 == 9.0
|
||||||
assert 9.0 ** 0.5 == 3.0
|
assert 9.0 ** 0.5 == 3.0
|
||||||
|
Loading…
Reference in New Issue
Block a user