summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/int128.nim516
-rw-r--r--compiler/sem.nim2
-rw-r--r--compiler/semstmts.nim2
-rw-r--r--compiler/semtypes.nim26
-rw-r--r--compiler/types.nim4
-rw-r--r--tests/casestmt/tcasestmt.nim11
6 files changed, 550 insertions, 11 deletions
diff --git a/compiler/int128.nim b/compiler/int128.nim
new file mode 100644
index 000000000..d67ec4add
--- /dev/null
+++ b/compiler/int128.nim
@@ -0,0 +1,516 @@
+
+
+type
+  Int128* = object
+    udata: array[4,uint32]
+
+template sdata(arg: Int128, idx: int): int32 =
+  # udata and sdata was supposed to be in a union, but unions are
+  # handled incorrectly in the VM.
+  cast[ptr int32](arg.udata[idx].unsafeAddr)[]
+
+# encoding least significant int first (like LittleEndian)
+
+type
+  InvalidArgument = object of Exception
+
+template require(cond: bool) =
+  if unlikely(not cond):
+    raise newException(InvalidArgument, "")
+
+const
+  Zero* = Int128(udata: [0'u32,0,0,0])
+  One* = Int128(udata: [1'u32,0,0,0])
+  Ten* = Int128(udata: [10'u32,0,0,0])
+  Min = Int128(udata: [0'u32,0,0,0x80000000'u32])
+  Max = Int128(udata: [high(uint32),high(uint32),high(uint32),uint32(high(int32))])
+
+template low*(t: typedesc[Int128]): Int128 = Min
+template high*(t: typedesc[Int128]): Int128 = Max
+
+proc `$`*(a: Int128): string
+
+proc toInt128*[T: SomeInteger](arg: T): Int128 =
+  when T is SomeUnsignedInt:
+    when sizeof(arg) <= 4:
+      result.udata[0] = uint32(arg)
+    else:
+      result.udata[0] = uint32(arg and T(0xffffffff))
+      result.udata[1] = uint32(arg shr 32)
+  else:
+    when sizeof(arg) <= 4:
+      result.sdata(0) = int32(arg)
+      if arg < 0: # sign extend
+        result.sdata(1) = -1
+        result.sdata(2) = -1
+        result.sdata(3) = -1
+    else:
+      let tmp = int64(arg)
+      result.udata[0] = uint32(tmp and 0xffffffff)
+      result.sdata(1) = int32(tmp shr 32)
+      if arg < 0: # sign extend
+        result.sdata(2) = -1
+        result.sdata(3) = -1
+
+template isNegative(arg: Int128): bool =
+  arg.sdata(3) < 0
+
+template isNegative(arg: int32): bool =
+  arg < 0
+
+proc bitconcat(a,b: uint32): uint64 =
+  (uint64(a) shl 32) or uint64(b)
+
+proc bitsplit(a: uint64): (uint32,uint32) =
+  (cast[uint32](a shr 32), cast[uint32](a))
+
+proc toInt64*(arg: Int128): int64 =
+  if isNegative(arg):
+    assert(arg.sdata(3) == -1, "out of range")
+    assert(arg.sdata(2) == -1, "out of range")
+  else:
+    assert(arg.sdata(3) == 0, "out of range")
+    assert(arg.sdata(2) == 0, "out of range")
+
+  cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
+
+proc toUInt64*(arg: Int128): uint64 =
+  assert(arg.udata[3] == 0)
+  assert(arg.udata[2] == 0)
+  bitconcat(arg.udata[1], arg.udata[0])
+
+proc addToHex(result: var string; arg: uint32) =
+  for i in 0 ..< 8:
+    let idx = (arg shr ((7-i) * 4)) and 0xf
+    result.add "0123456789abcdef"[idx]
+
+proc addToHex*(result: var string; arg: Int128) =
+  var i = 3
+  while i >= 0:
+    result.addToHex(arg.udata[i])
+    i -= 1
+
+proc toHex*(arg: Int128): string =
+  result.addToHex(arg)
+
+proc inc*(a: var Int128, y: uint32 = 1) =
+  let input = a
+  a.udata[0] += y
+  if unlikely(a.udata[0] < y):
+    a.udata[1].inc
+    if unlikely(a.udata[1] == 0):
+      a.udata[2].inc
+      if unlikely(a.udata[2] == 0):
+        a.udata[3].inc
+        doAssert(a.sdata(3) != low(int32), "overflow")
+
+proc cmp*(a,b: Int128): int =
+  let tmp1 = cmp(a.sdata(3), b.sdata(3))
+  if tmp1 != 0: return tmp1
+  let tmp2 = cmp(a.udata[2], b.udata[2])
+  if tmp2 != 0: return tmp2
+  let tmp3 = cmp(a.udata[1], b.udata[1])
+  if tmp3 != 0: return tmp3
+  let tmp4 = cmp(a.udata[0], b.udata[0])
+  return tmp4
+
+proc `<`*(a,b: Int128): bool =
+  cmp(a,b) < 0
+
+proc `<=`*(a,b: Int128): bool =
+  cmp(a,b) <= 0
+
+proc `==`*(a,b: Int128): bool =
+  if a.udata[0] != b.udata[0]: return false
+  if a.udata[1] != b.udata[1]: return false
+  if a.udata[2] != b.udata[2]: return false
+  if a.udata[3] != b.udata[3]: return false
+  return true
+
+proc inplaceBitnot(a: var Int128) =
+  a.udata[0] = not a.udata[0]
+  a.udata[1] = not a.udata[1]
+  a.udata[2] = not a.udata[2]
+  a.udata[3] = not a.udata[3]
+
+proc bitnot*(a: Int128): Int128 =
+  result.udata[0] = not a.udata[0]
+  result.udata[1] = not a.udata[1]
+  result.udata[2] = not a.udata[2]
+  result.udata[3] = not a.udata[3]
+
+proc bitand*(a,b: Int128): Int128 =
+  result.udata[0] = a.udata[0] and b.udata[0]
+  result.udata[1] = a.udata[1] and b.udata[1]
+  result.udata[2] = a.udata[2] and b.udata[2]
+  result.udata[3] = a.udata[3] and b.udata[3]
+
+proc bitor*(a,b: Int128): Int128 =
+  result.udata[0] = a.udata[0] or b.udata[0]
+  result.udata[1] = a.udata[1] or b.udata[1]
+  result.udata[2] = a.udata[2] or b.udata[2]
+  result.udata[3] = a.udata[3] or b.udata[3]
+
+proc bitxor*(a,b: Int128): Int128 =
+  result.udata[0] = a.udata[0] xor b.udata[0]
+  result.udata[1] = a.udata[1] xor b.udata[1]
+  result.udata[2] = a.udata[2] xor b.udata[2]
+  result.udata[3] = a.udata[3] xor b.udata[3]
+
+proc `shr`*(a: Int128, b: int): Int128 =
+  let b = b and 127
+  if b < 32:
+    result.sdata(3) = a.sdata(3) shr b
+    result.udata[2] = cast[uint32](bitconcat(a.udata[3], a.udata[2]) shr b)
+    result.udata[1] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr b)
+    result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr b)
+  elif b < 64:
+    if isNegative(a):
+      result.sdata(3) = -1
+    result.sdata(2) = a.sdata(3) shr (b and 31)
+    result.udata[1] = cast[uint32](bitconcat(a.udata[2], a.udata[1]) shr (b and 31))
+    result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31))
+  elif b < 96:
+    if isNegative(a):
+      result.sdata(3) = -1
+      result.sdata(2) = -1
+    result.sdata(1) = a.sdata(3) shr (b and 31)
+    result.udata[0] = cast[uint32](bitconcat(a.udata[1], a.udata[0]) shr (b and 31))
+  else: # b < 128
+    if isNegative(a):
+      result.sdata(3) = -1
+      result.sdata(2) = -1
+      result.sdata(1) = -1
+    result.sdata(0) = a.sdata(3) shr (b and 31)
+
+proc `shl`*(a: Int128, b: int): Int128 =
+  let b = b and 127
+  if b < 32:
+    result.udata[0] = a.udata[0] shl b
+    result.udata[1] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl b) shr 32)
+    result.udata[2] = cast[uint32]((bitconcat(a.udata[2], a.udata[1]) shl b) shr 32)
+    result.udata[3] = cast[uint32]((bitconcat(a.udata[3], a.udata[2]) shl b) shr 32)
+  elif b < 64:
+    result.udata[0] = 0
+    result.udata[1] = a.udata[0] shl (b and 31)
+    result.udata[2] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl (b and 31)) shr 32)
+    result.udata[3] = cast[uint32]((bitconcat(a.udata[2], a.udata[1]) shl (b and 31)) shr 32)
+  elif b < 96:
+    result.udata[0] = 0
+    result.udata[1] = 0
+    result.udata[2] = a.udata[0] shl (b and 31)
+    result.udata[3] = cast[uint32]((bitconcat(a.udata[1], a.udata[0]) shl (b and 31)) shr 32)
+  else:
+    result.udata[0] = 0
+    result.udata[1] = 0
+    result.udata[2] = 0
+    result.udata[3] = a.udata[0] shl (b and 31)
+
+
+proc `+`*(a,b: Int128): Int128 =
+  let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0])
+  result.udata[0] = cast[uint32](tmp0)
+  let tmp1 = uint64(a.udata[1]) + uint64(b.udata[1]) + (tmp0 shr 32)
+  result.udata[1] = cast[uint32](tmp1)
+  let tmp2 = uint64(a.udata[2]) + uint64(b.udata[2]) + (tmp1 shr 32)
+  result.udata[2] = cast[uint32](tmp2)
+  let tmp3 = uint64(a.udata[3]) + uint64(b.udata[3]) + (tmp2 shr 32)
+  result.udata[3] = cast[uint32](tmp3)
+
+proc `+=`*(a: var Int128, b: Int128) =
+  a = a + b
+
+proc `-`*(a: Int128): Int128 =
+  result = bitnot(a)
+  result.inc
+
+proc `-`*(a,b: Int128): Int128 =
+  a + (-b)
+
+proc `-=`*(a: var Int128, b: Int128) =
+  a = a - b
+
+proc abs*(a: Int128): Int128 =
+  if isNegative(a):
+    -a
+  else:
+    a
+
+proc abs(a: int32): int =
+  if a < 0: -a else: a
+
+proc `*`(a: Int128, b: uint32): Int128 =
+  let tmp0 = uint64(a.udata[0]) * uint64(b)
+  let tmp1 = uint64(a.udata[1]) * uint64(b)
+  let tmp2 = uint64(a.udata[2]) * uint64(b)
+  let tmp3 = uint64(a.udata[3]) * uint64(b)
+
+  if unlikely(tmp3 > uint64(high(int32))):
+    assert(false, "overflow")
+
+  result.udata[0] = cast[uint32](tmp0)
+  result.udata[1] = cast[uint32](tmp1) + cast[uint32](tmp0 shr 32)
+  result.udata[2] = cast[uint32](tmp2) + cast[uint32](tmp1 shr 32)
+  result.udata[3] = cast[uint32](tmp3) + cast[uint32](tmp2 shr 32)
+
+proc `*`*(a: Int128, b: int32): Int128 =
+  let isNegative = isNegative(a) xor isNegative(b)
+  result = a * cast[uint32](abs(b))
+  if b < 0:
+    result = -result
+
+proc `*=`*(a: var Int128, b: int32): Int128 =
+  result = result * b
+
+proc makeint128(high,low: uint64): Int128 =
+  result.udata[0] = cast[uint32](low)
+  result.udata[1] = cast[uint32](low shr 32)
+  result.udata[2] = cast[uint32](high)
+  result.udata[3] = cast[uint32](high shr 32)
+
+proc high64(a: Int128): uint64 =
+  bitconcat(a.udata[3], a.udata[2])
+
+proc low64(a: Int128): uint64 =
+  bitconcat(a.udata[1], a.udata[0])
+
+proc `*`*(lhs,rhs: Int128): Int128 =
+  let isNegative = isNegative(lhs) xor isNegative(rhs)
+
+  let
+    a = cast[uint64](lhs.udata[0])
+    b = cast[uint64](lhs.udata[1])
+    c = cast[uint64](lhs.udata[2])
+    d = cast[uint64](lhs.udata[3])
+
+    e = cast[uint64](rhs.udata[0])
+    f = cast[uint64](rhs.udata[1])
+    g = cast[uint64](rhs.udata[2])
+    h = cast[uint64](rhs.udata[3])
+
+
+  let a32 = cast[uint64](lhs.udata[1])
+  let a00 = cast[uint64](lhs.udata[0])
+  let b32 = cast[uint64](rhs.udata[1])
+  let b00 = cast[uint64](rhs.udata[0])
+
+  result = makeInt128(high64(lhs) * low64(rhs) + low64(lhs) * high64(rhs) + a32 * b32, a00 * b00)
+  result = result + toInt128(a32 * b00) shl 32
+  result = result + toint128(a00 * b32) shl 32
+
+  if isNegative != isNegative(result):
+    echo result
+    assert(false, "overflow")
+
+proc `*=`*(a: var Int128, b: Int128) =
+  a = a * b
+
+import bitops
+
+proc fastLog2*(a: Int128): int =
+  if a.udata[3] != 0:
+    return 96 + fastLog2(a.udata[3])
+  if a.udata[2] != 0:
+    return 64 + fastLog2(a.udata[2])
+  if a.udata[1] != 0:
+    return 32 + fastLog2(a.udata[1])
+  if a.udata[0] != 0:
+    return      fastLog2(a.udata[0])
+
+proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
+  assert(divisor != Zero)
+  let isNegative = isNegative(dividend) xor isNegative(divisor)
+
+  var dividend = abs(dividend)
+  let divisor = abs(divisor)
+
+  if divisor > dividend:
+    result.quotient = Zero
+    result.remainder = dividend
+    return
+
+  if divisor == dividend:
+    result.quotient = One
+    result.remainder = Zero
+    return
+
+  var denominator = divisor
+  var quotient = Zero
+
+  # Left aligns the MSB of the denominator and the dividend.
+  let shift = fastLog2(dividend) - fastLog2(denominator)
+  denominator = denominator shl shift
+
+  # Uses shift-subtract algorithm to divide dividend by denominator. The
+  # remainder will be left in dividend.
+  for i in 0 .. shift:
+    quotient = quotient shl 1
+    if dividend >= denominator:
+      dividend = dividend - denominator
+      quotient = bitor(quotient, One)
+
+    denominator = denominator shr 1
+
+  result.quotient = quotient
+  result.remainder = dividend
+
+proc `div`*(a,b: Int128): Int128 =
+  let (a,b) = divMod(a,b)
+  return a
+
+proc `mod`*(a,b: Int128): Int128 =
+  let (a,b) = divMod(a,b)
+  return b
+
+proc `$`*(a: Int128): string =
+  if a == Zero:
+    result = "0"
+  elif a == low(Int128):
+    result = "-170141183460469231731687303715884105728"
+  else:
+    let isNegative = isNegative(a)
+    var a = abs(a)
+    while a > Zero:
+      let (quot, rem) = divMod(a, Ten)
+      result.add "0123456789"[rem.toInt64]
+      a = quot
+    if isNegative:
+      result.add '-'
+
+    var i = 0
+    var j = high(result)
+    while i < j:
+      swap(result[i], result[j])
+      i += 1
+      j -= 1
+
+proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 =
+  assert(pos < arg.len)
+  assert(arg[pos] in {'-','0'..'9'})
+
+  var isNegative = false
+  var pos = pos
+  if arg[pos] == '-':
+    isNegative = true
+    pos += 1
+
+  result = Zero
+  while pos < arg.len and arg[pos] in '0' .. '9':
+    result = result * Ten
+    result.inc(uint32(arg[pos]) - uint32('0'))
+    pos += 1
+
+  if isNegative:
+    result = -result
+
+# fluff
+
+proc `<`*(a: Int128, b: BiggestInt): bool =
+  cmp(a,toInt128(b)) < 0
+
+proc `<`*(a: BiggestInt, b: Int128): bool =
+  cmp(toInt128(a), b) < 0
+
+proc `<=`*(a: Int128, b: BiggestInt): bool =
+  cmp(a,toInt128(b)) <= 0
+
+proc `<=`*(a: BiggestInt, b: Int128): bool =
+  cmp(toInt128(a), b) <= 0
+
+proc `==`*(a: Int128, b: BiggestInt): bool =
+  a == toInt128(b)
+
+proc `==`*(a: BiggestInt, b: Int128): bool =
+  toInt128(a) == b
+
+proc `-`*(a: BiggestInt, b: Int128): Int128 =
+  toInt128(a) - b
+
+proc `-`*(a: Int128, b: BiggestInt): Int128 =
+  a - toInt128(b)
+
+proc `+`*(a: BiggestInt, b: Int128): Int128 =
+  toInt128(a) + b
+
+proc `+`*(a: Int128, b: BiggestInt): Int128 =
+  a + toInt128(b)
+
+
+when isMainModule:
+  let (a,b) = divMod(Ten,Ten)
+
+  doAssert $One == "1"
+  doAssert $Ten == "10"
+  doAssert $Zero == "0"
+  let c = parseDecimalInt128("12345678989876543210123456789")
+  doAssert $c == "12345678989876543210123456789"
+
+  var d : array[39, Int128]
+  d[0] =  parseDecimalInt128("1")
+  d[1] =  parseDecimalInt128("10")
+  d[2] =  parseDecimalInt128("100")
+  d[3] =  parseDecimalInt128("1000")
+  d[4] =  parseDecimalInt128("10000")
+  d[5] =  parseDecimalInt128("100000")
+  d[6] =  parseDecimalInt128("1000000")
+  d[7] =  parseDecimalInt128("10000000")
+  d[8] =  parseDecimalInt128("100000000")
+  d[9] =  parseDecimalInt128("1000000000")
+  d[10] = parseDecimalInt128("10000000000")
+  d[11] = parseDecimalInt128("100000000000")
+  d[12] = parseDecimalInt128("1000000000000")
+  d[13] = parseDecimalInt128("10000000000000")
+  d[14] = parseDecimalInt128("100000000000000")
+  d[15] = parseDecimalInt128("1000000000000000")
+  d[16] = parseDecimalInt128("10000000000000000")
+  d[17] = parseDecimalInt128("100000000000000000")
+  d[18] = parseDecimalInt128("1000000000000000000")
+  d[19] = parseDecimalInt128("10000000000000000000")
+  d[20] = parseDecimalInt128("100000000000000000000")
+  d[21] = parseDecimalInt128("1000000000000000000000")
+  d[22] = parseDecimalInt128("10000000000000000000000")
+  d[23] = parseDecimalInt128("100000000000000000000000")
+  d[24] = parseDecimalInt128("1000000000000000000000000")
+  d[25] = parseDecimalInt128("10000000000000000000000000")
+  d[26] = parseDecimalInt128("100000000000000000000000000")
+  d[27] = parseDecimalInt128("1000000000000000000000000000")
+  d[28] = parseDecimalInt128("10000000000000000000000000000")
+  d[29] = parseDecimalInt128("100000000000000000000000000000")
+  d[30] = parseDecimalInt128("1000000000000000000000000000000")
+  d[31] = parseDecimalInt128("10000000000000000000000000000000")
+  d[32] = parseDecimalInt128("100000000000000000000000000000000")
+  d[33] = parseDecimalInt128("1000000000000000000000000000000000")
+  d[34] = parseDecimalInt128("10000000000000000000000000000000000")
+  d[35] = parseDecimalInt128("100000000000000000000000000000000000")
+  d[36] = parseDecimalInt128("1000000000000000000000000000000000000")
+  d[37] = parseDecimalInt128("10000000000000000000000000000000000000")
+  d[38] = parseDecimalInt128("100000000000000000000000000000000000000")
+
+  for i in 0 ..< d.len:
+    for j in 0 ..< d.len:
+      doAssert(cmp(d[i], d[j]) == cmp(i,j))
+      if i + j < d.len:
+        doAssert d[i] * d[j] == d[i+j]
+      if i - j >= 0:
+        doAssert d[i] div d[j] == d[i-j]
+
+  var sum: Int128
+
+  for it in d:
+    sum += it
+
+  doAssert $sum == "111111111111111111111111111111111111111"
+
+  for it in d.mitems:
+    it = -it
+
+  for i in 0 ..< d.len:
+    for j in 0 ..< d.len:
+      doAssert(cmp(d[i], d[j]) == -cmp(i,j))
+      if i + j < d.len:
+        doAssert d[i] * d[j] == -d[i+j]
+      if i - j >= 0:
+        doAssert d[i] div d[j] == -d[i-j]
+
+  doAssert $high(Int128) == "170141183460469231731687303715884105727"
+  doAssert $low(Int128) == "-170141183460469231731687303715884105728"
diff --git a/compiler/sem.nim b/compiler/sem.nim
index 918c4eeff..cbef3b170 100644
--- a/compiler/sem.nim
+++ b/compiler/sem.nim
@@ -16,7 +16,7 @@ import
   procfind, lookups, pragmas, passes, semdata, semtypinst, sigmatch,
   intsets, transf, vmdef, vm, idgen, aliases, cgmeth, lambdalifting,
   evaltempl, patterns, parampatterns, sempass2, linter, semmacrosanity,
-  lowerings, pluginsupport, plugins/active, rod, lineinfos, strtabs
+  lowerings, pluginsupport, plugins/active, rod, lineinfos, strtabs, int128
 
 from modulegraphs import ModuleGraph, PPassContext, onUse, onDef, onDefResolveForward
 
diff --git a/compiler/semstmts.nim b/compiler/semstmts.nim
index d77e619f9..9718331d0 100644
--- a/compiler/semstmts.nim
+++ b/compiler/semstmts.nim
@@ -877,7 +877,7 @@ proc semCase(c: PContext, n: PNode; flags: TExprFlags): PNode =
   pushCaseContext(c, n)
   n.sons[0] = semExprWithType(c, n.sons[0])
   var chckCovered = false
-  var covered: BiggestInt = 0
+  var covered: Int128 = toInt128(0)
   var typ = commonTypeBegin
   var hasElse = false
   let caseTyp = skipTypes(n.sons[0].typ, abstractVar-{tyTypeDesc})
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index 3e364e18e..3954fa2d1 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -496,7 +496,7 @@ proc checkForOverlap(c: PContext, t: PNode, currentEx, branchIndex: int) =
       if overlap(t.sons[i].sons[j].skipConv, ex):
         localError(c.config, ex.info, errDuplicateCaseLabel)
 
-proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode =
+proc semBranchRange(c: PContext, t, a, b: PNode, covered: var Int128): PNode =
   checkMinSonsLen(t, 1, c.config)
   let ac = semConstExpr(c, a)
   let bc = semConstExpr(c, b)
@@ -510,12 +510,12 @@ proc semBranchRange(c: PContext, t, a, b: PNode, covered: var BiggestInt): PNode
   else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
 
 proc semCaseBranchRange(c: PContext, t, b: PNode,
-                        covered: var BiggestInt): PNode =
+                        covered: var Int128): PNode =
   checkSonsLen(b, 3, c.config)
   result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
 
 proc semCaseBranchSetElem(c: PContext, t, b: PNode,
-                          covered: var BiggestInt): PNode =
+                          covered: var Int128): PNode =
   if isRange(b):
     checkSonsLen(b, 3, c.config)
     result = semBranchRange(c, t, b.sons[1], b.sons[2], covered)
@@ -527,7 +527,7 @@ proc semCaseBranchSetElem(c: PContext, t, b: PNode,
     inc(covered)
 
 proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
-                   covered: var BiggestInt) =
+                   covered: var Int128) =
   let lastIndex = sonsLen(branch) - 2
   for i in 0..lastIndex:
     var b = branch.sons[i]
@@ -567,12 +567,22 @@ proc semCaseBranch(c: PContext, t, branch: PNode, branchIndex: int,
   for i in lastIndex.succ..(sonsLen(branch) - 2):
     checkForOverlap(c, t, i, branchIndex)
 
-proc toCover(c: PContext, t: PType): BiggestInt =
+proc toCover(c: PContext, t: PType): Int128 =
   let t2 = skipTypes(t, abstractVarRange-{tyTypeDesc})
   if t2.kind == tyEnum and enumHasHoles(t2):
-    result = sonsLen(t2.n)
+    result = toInt128(sonsLen(t2.n))
   else:
-    result = lengthOrd(c.config, skipTypes(t, abstractVar-{tyTypeDesc}))
+    # <----
+    let t = skipTypes(t, abstractVar-{tyTypeDesc})
+    # XXX: hack incoming. lengthOrd is incorrect for 64bit integer
+    # types because it doesn't uset Int128 yet.  This entire branching
+    # should be removed as soon as lengthOrd uses int128.
+    if t.kind in {tyInt64, tyUInt64}:
+      result = toInt128(1) shl 64
+    elif t.kind in {tyInt, tyUInt}:
+      result = toInt128(1) shl (c.config.target.intSize * 8)
+    else:
+      result = toInt128(lengthOrd(c.config, t))
 
 proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
                       father: PNode, rectype: PType, hasCaseFields = false)
@@ -603,7 +613,7 @@ proc semRecordCase(c: PContext, n: PNode, check: var IntSet, pos: var int,
     internalError(c.config, "semRecordCase: discriminant is no symbol")
     return
   incl(a.sons[0].sym.flags, sfDiscriminant)
-  var covered: BiggestInt = 0
+  var covered: Int128 = toInt128(0)
   var chckCovered = false
   var typ = skipTypes(a.sons[0].typ, abstractVar-{tyTypeDesc})
   const shouldChckCovered = {tyInt..tyInt64, tyChar, tyEnum, tyUInt..tyUInt32, tyBool}
diff --git a/compiler/types.nim b/compiler/types.nim
index d879c0f56..0b5fa7ef7 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -760,7 +760,9 @@ proc floatRangeCheck*(x: BiggestFloat, t: PType): bool =
 
 proc lengthOrd*(conf: ConfigRef; t: PType): BiggestInt =
   case t.skipTypes(tyUserTypeClasses).kind
-  of tyInt64, tyInt32, tyInt: result = lastOrd(conf, t)
+  of tyInt64, tyInt32, tyInt:
+    # XXX: this is just wrong
+    result = lastOrd(conf, t)
   of tyDistinct: result = lengthOrd(conf, t.sons[0])
   else:
     let last = lastOrd(conf, t)
diff --git a/tests/casestmt/tcasestmt.nim b/tests/casestmt/tcasestmt.nim
index 465080e84..d86b3b0dd 100644
--- a/tests/casestmt/tcasestmt.nim
+++ b/tests/casestmt/tcasestmt.nim
@@ -226,3 +226,14 @@ block tcasestm:
         true
       else: raise newException(ValueError, "Invalid")
   ))
+
+#issue #11552
+
+proc positiveOrNegative(num: int): string =
+  result = case num
+  of (low(int)+2) .. -1:
+    "negative"
+  of 0:
+    "zero"
+  else:
+    "impossible"