Skip to content

Commit

Permalink
port __muloti4 to pony and use it in I128.mulc
Browse files Browse the repository at this point in the history
  • Loading branch information
mfelsche committed Apr 12, 2018
1 parent e16f474 commit f0c0fb8
Showing 1 changed file with 24 additions and 6 deletions.
30 changes: 24 additions & 6 deletions packages/builtin/signed.pony
Original file line number Diff line number Diff line change
Expand Up @@ -517,12 +517,30 @@ primitive I128 is _SignedInteger[I128, U128]
end

fun mulc(y: I128): (I128, Bool) =>
ifdef native128 then
@"llvm.smul.with.overflow.i128"[(I128, Bool)](this, y)
else
let result = this * y
let overflow = (this != 0) and ((result / this) != y)
(result, overflow)
// using llvm.smul.with.overflow.i128 would require to link
// llvm compiler-rt where the function implementing it lives: https://github.com/llvm-mirror/compiler-rt/blob/master/lib/builtins/muloti4.c
// See this bug for reference:
// the following implementation is more or less exactly was __muloti4 is
// doing
let result = this * y
if this == I128.min_value() then
return (result, (y != 0) and (y != 1))
end
if y == I128.min_value() then
return (result, (this != 0) and (this != 1))
end
let this_neg = this >> (this.bitwidth() - 1)
let this_abs = (this xor this_neg) - this_neg
let y_neg = y >> (this.bitwidth() - 1)
let y_abs = (y xor y_neg) - y_neg

if ((this_abs < 2) or (y_abs < 2)) then
return (result, false)
end
if (this_neg == y_neg) then
(result, (this_abs > (I128.max_value() / y_abs)))
else
(result, (this_abs > (I128.min_value() / -y_abs)))
end

type Signed is (I8 | I16 | I32 | I64 | I128 | ILong | ISize)

0 comments on commit f0c0fb8

Please sign in to comment.