summary refs log tree commit diff stats
path: root/compiler
diff options
context:
space:
mode:
authorArne Döring <arne.doering@gmx.net>2019-08-07 15:53:16 +0200
committerAndreas Rumpf <rumpf_a@web.de>2019-08-07 15:53:16 +0200
commitafbcd1b330f16294cee32efca1b2f9060874a497 (patch)
treed0406792478fa58d3c487ff6f72f999c29f25343 /compiler
parent8407a574992ebd6bccec647a902cf54a4de8db18 (diff)
downloadNim-afbcd1b330f16294cee32efca1b2f9060874a497.tar.gz
int128 on firstOrd, lastOrd and lengthOrd (#11701)
* fixes #11847
Diffstat (limited to 'compiler')
-rw-r--r--compiler/ast.nim78
-rw-r--r--compiler/ccgcalls.nim2
-rw-r--r--compiler/ccgexprs.nim5
-rw-r--r--compiler/ccgliterals.nim4
-rw-r--r--compiler/ccgstmts.nim10
-rw-r--r--compiler/ccgtypes.nim8
-rw-r--r--compiler/cgen.nim3
-rw-r--r--compiler/closureiters.nim12
-rw-r--r--compiler/guards.nim4
-rw-r--r--compiler/int128.nim191
-rw-r--r--compiler/jsgen.nim8
-rw-r--r--compiler/jstypes.nim4
-rw-r--r--compiler/lambdalifting.nim2
-rw-r--r--compiler/liftdestructors.nim2
-rw-r--r--compiler/lowerings.nim4
-rw-r--r--compiler/nimsets.nim12
-rw-r--r--compiler/renderer.nim3
-rw-r--r--compiler/semdata.nim6
-rw-r--r--compiler/semexprs.nim10
-rw-r--r--compiler/semfold.nim259
-rw-r--r--compiler/semmagic.nim6
-rw-r--r--compiler/semobjconstr.nim2
-rw-r--r--compiler/semtypes.nim10
-rw-r--r--compiler/sigmatch.nim10
-rw-r--r--compiler/sizealignoffsetimpl.nim8
-rw-r--r--compiler/transf.nim4
-rw-r--r--compiler/types.nim109
-rw-r--r--compiler/vm.nim6
-rw-r--r--compiler/vmgen.nim6
29 files changed, 513 insertions, 275 deletions
diff --git a/compiler/ast.nim b/compiler/ast.nim
index 8d52f12ff..6238acb14 100644
--- a/compiler/ast.nim
+++ b/compiler/ast.nim
@@ -10,7 +10,9 @@
 # abstract syntax tree + symbol table
 
 import
-  lineinfos, hashes, options, ropes, idents, idgen
+  lineinfos, hashes, options, ropes, idents, idgen, int128
+
+export int128
 
 type
   TCallingConvention* = enum
@@ -1055,7 +1057,7 @@ template `[]`*(n: Indexable, i: BackwardsIndex): Indexable = n[n.len - i.int]
 template `[]=`*(n: Indexable, i: BackwardsIndex; x: Indexable) = n[n.len - i.int] = x
 
 when defined(useNodeIds):
-  const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879
+  const nodeIdToDebug* = 2322967# 2322968
   var gNodeId: int
 
 proc newNode*(kind: TNodeKind): PNode =
@@ -1233,10 +1235,48 @@ proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
   result = newNode(kind)
   result.intVal = intVal
 
-proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode =
-  result = newIntNode(kind, intVal)
+proc newIntNode*(kind: TNodeKind, intVal: Int128): PNode =
+  result = newNode(kind)
+  result.intVal = castToInt64(intVal)
+
+proc lastSon*(n: PType): PType = n.sons[^1]
+
+proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
+  ## Used throughout the compiler code to test whether a type tree contains or
+  ## doesn't contain a specific type/types - it is often the case that only the
+  ## last child nodes of a type tree need to be searched. This is a really hot
+  ## path within the compiler!
+  result = t
+  while result.kind in kinds: result = lastSon(result)
+
+proc newIntTypeNode*(intVal: BiggestInt, typ: PType): PNode =
+
+  # this is dirty. abstractVarRange isn't defined yet and therefor it
+  # is duplicated here.
+  const abstractVarRange = {tyGenericInst, tyRange, tyVar, tyDistinct, tyOrdinal,
+                       tyTypeDesc, tyAlias, tyInferred, tySink, tyOwned}
+  case skipTypes(typ, abstractVarRange).kind
+  of tyInt:     result = newNode(nkIntLit)
+  of tyInt8:    result = newNode(nkInt8Lit)
+  of tyInt16:   result = newNode(nkInt16Lit)
+  of tyInt32:   result = newNode(nkInt32Lit)
+  of tyInt64:   result = newNode(nkInt64Lit)
+  of tyChar:    result = newNode(nkCharLit)
+  of tyUInt:    result = newNode(nkUIntLit)
+  of tyUInt8:   result = newNode(nkUInt8Lit)
+  of tyUInt16:  result = newNode(nkUInt16Lit)
+  of tyUInt32:  result = newNode(nkUInt32Lit)
+  of tyUInt64:  result = newNode(nkUInt64Lit)
+  else: # tyBool, tyEnum
+    # XXX: does this really need to be the kind nkIntLit?
+    result = newNode(nkIntLit)
+  result.intVal = intVal
   result.typ = typ
 
+proc newIntTypeNode*(intVal: Int128, typ: PType): PNode =
+  # XXX: introduce range check
+  newIntTypeNode(castToInt64(intVal), typ)
+
 proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
   result = newNode(kind)
   result.floatVal = floatVal
@@ -1325,7 +1365,6 @@ proc sonsLen*(n: PType): int = n.sons.len
 proc len*(n: PType): int = n.sons.len
 proc sonsLen*(n: PNode): int = n.sons.len
 proc lastSon*(n: PNode): PNode = n.sons[^1]
-proc lastSon*(n: PType): PType = n.sons[^1]
 
 proc assignType*(dest, src: PType) =
   dest.kind = src.kind
@@ -1421,14 +1460,6 @@ proc initNodeTable*(x: var TNodeTable) =
   x.counter = 0
   newSeq(x.data, StartSize)
 
-proc skipTypes*(t: PType, kinds: TTypeKinds): PType =
-  ## Used throughout the compiler code to test whether a type tree contains or
-  ## doesn't contain a specific type/types - it is often the case that only the
-  ## last child nodes of a type tree need to be searched. This is a really hot
-  ## path within the compiler!
-  result = t
-  while result.kind in kinds: result = lastSon(result)
-
 proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
   result = t
   var i = maxIters
@@ -1604,14 +1635,25 @@ proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
         return true
     result = false
 
-proc getInt*(a: PNode): BiggestInt =
+proc getInt*(a: PNode): Int128 =
+  case a.kind
+  of nkCharLit, nkUIntLit..nkUInt64Lit:
+    result = toInt128(cast[uint64](a.intVal))
+  of nkInt8Lit..nkInt64Lit:
+    result = toInt128(a.intVal)
+  of nkIntLit:
+    # XXX: enable this assert
+    # assert a.typ.kind notin {tyChar, tyUint..tyUInt64}
+    result = toInt128(a.intVal)
+  else:
+    raiseRecoverableError("cannot extract number from invalid AST node")
+
+proc getInt64*(a: PNode): int64 {.deprecated: "use getInt".} =
   case a.kind
-  of nkCharLit..nkUInt64Lit: result = a.intVal
+  of nkCharLit, nkUIntLit..nkUInt64Lit, nkIntLit..nkInt64Lit:
+    result = a.intVal
   else:
     raiseRecoverableError("cannot extract number from invalid AST node")
-    #internalError(a.info, "getInt")
-    #doAssert false, "getInt"
-    #result = 0
 
 proc getFloat*(a: PNode): BiggestFloat =
   case a.kind
diff --git a/compiler/ccgcalls.nim b/compiler/ccgcalls.nim
index 0950a301d..9201af466 100644
--- a/compiler/ccgcalls.nim
+++ b/compiler/ccgcalls.nim
@@ -92,7 +92,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
     let ty = skipTypes(a.t, abstractVar+{tyPtr})
     case ty.kind
     of tyArray:
-      let first = firstOrd(p.config, ty)
+      let first = toInt64(firstOrd(p.config, ty))
       if first == 0:
         result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
       else:
diff --git a/compiler/ccgexprs.nim b/compiler/ccgexprs.nim
index 273117bc7..a9932a0ce 100644
--- a/compiler/ccgexprs.nim
+++ b/compiler/ccgexprs.nim
@@ -30,6 +30,9 @@ proc intLiteral(i: BiggestInt): Rope =
   else:
     result = ~"(IL64(-9223372036854775807) - IL64(1))"
 
+proc intLiteral(i: Int128): Rope =
+  intLiteral(toInt64(i))
+
 proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
   case n.kind
   of nkCharLit..nkUInt64Lit:
@@ -1436,7 +1439,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
   if d.k == locNone:
     getTemp(p, n.typ, d)
   # generate call to newSeq before adding the elements per hand:
-  let L = int(lengthOrd(p.config, n.sons[1].typ))
+  let L = toInt(lengthOrd(p.config, n.sons[1].typ))
   if p.config.selectedGC == gcDestructors:
     let seqtype = n.typ
     linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",
diff --git a/compiler/ccgliterals.nim b/compiler/ccgliterals.nim
index da3668028..0dd12452c 100644
--- a/compiler/ccgliterals.nim
+++ b/compiler/ccgliterals.nim
@@ -7,6 +7,8 @@
 #    distribution, for details about the copyright.
 #
 
+# included from cgen.nim
+
 ## This include file contains the logic to produce constant string
 ## and seq literals. The code here is responsible that
 ## ``const x = ["a", "b"]`` works without hidden runtime creation code.
@@ -19,7 +21,7 @@ template detectVersion(field, corename) =
     if core == nil or core.kind != skConst:
       m.g.field = 1
     else:
-      m.g.field = int ast.getInt(core.ast)
+      m.g.field = toInt(ast.getInt(core.ast))
   result = m.g.field
 
 proc detectStrVersion(m: BModule): int =
diff --git a/compiler/ccgstmts.nim b/compiler/ccgstmts.nim
index 6190cb3f6..bf07c1af7 100644
--- a/compiler/ccgstmts.nim
+++ b/compiler/ccgstmts.nim
@@ -246,10 +246,10 @@ proc genGotoState(p: BProc, n: PNode) =
   lineF(p, cpsStmts, " goto BeforeRet_;$n", [])
   var statesCounter = lastOrd(p.config, n.sons[0].typ)
   if n.len >= 2 and n[1].kind == nkIntLit:
-    statesCounter = n[1].intVal
+    statesCounter = getInt(n[1])
   let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
                else: rope"STATE"
-  for i in 0i64 .. statesCounter:
+  for i in 0i64 .. toInt64(statesCounter):
     lineF(p, cpsStmts, "case $2: goto $1$2;$n", [prefix, rope(i)])
   lineF(p, cpsStmts, "}$n", [])
 
@@ -494,7 +494,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
       if aSize > 10_000:
         localError(p.config, it.info,
             "case statement has too many cases for computed goto"); return
-      arraySize = aSize.int
+      arraySize = toInt(aSize)
       if firstOrd(p.config, it.sons[0].typ) != 0:
         localError(p.config, it.info,
             "case statement has to start at 0 for computed goto"); return
@@ -527,7 +527,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
         return
 
       let val = getOrdValue(it.sons[j])
-      lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(val+id+1)])
+      lineF(p, cpsStmts, "TMP$#_:$n", [intLiteral(toInt64(val)+id+1)])
 
     genStmts(p, it.lastSon)
 
@@ -1211,7 +1211,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
   var t = skipTypes(objtype, abstractVar)
   assert t.kind == tyObject
   discard genTypeInfo(p.module, t, a.lode.info)
-  var L = lengthOrd(p.config, field.typ)
+  var L = toInt64(lengthOrd(p.config, field.typ))
   if not containsOrIncl(p.module.declaredThings, field.id):
     appcg(p.module, cfsVars, "extern $1",
           [discriminatorTableDecl(p.module, t, field)])
diff --git a/compiler/ccgtypes.nim b/compiler/ccgtypes.nim
index bf7bf6795..28a9bf028 100644
--- a/compiler/ccgtypes.nim
+++ b/compiler/ccgtypes.nim
@@ -805,7 +805,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
       let foo = getTypeDescAux(m, t.sons[0], check)
       addf(m.s[cfsTypes], "typedef $1 $2[1];$n", [foo, result])
   of tyArray:
-    var n: BiggestInt = lengthOrd(m.config, t)
+    var n: BiggestInt = toInt64(lengthOrd(m.config, t))
     if n <= 0: n = 1   # make an array of at least one element
     result = getTypeName(m, origTyp, sig)
     m.typeCache[sig] = result
@@ -1047,6 +1047,8 @@ proc discriminatorTableName(m: BModule, objtype: PType, d: PSym): Rope =
     internalError(m.config, d.info, "anonymous obj with discriminator")
   result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)]
 
+proc rope(arg: Int128): Rope = rope($arg)
+
 proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
   discard cgsym(m, "TNimNode")
   var tmp = discriminatorTableName(m, objtype, d)
@@ -1105,8 +1107,8 @@ proc genObjectFields(m: BModule, typ, origType: PType, n: PNode, expr: Rope;
           internalError(m.config, b.info, "genObjectFields; nkOfBranch broken")
         for j in 0 .. sonsLen(b) - 2:
           if b.sons[j].kind == nkRange:
-            var x = int(getOrdValue(b.sons[j].sons[0]))
-            var y = int(getOrdValue(b.sons[j].sons[1]))
+            var x = toInt(getOrdValue(b.sons[j].sons[0]))
+            var y = toInt(getOrdValue(b.sons[j].sons[1]))
             while x <= y:
               addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
               inc(x)
diff --git a/compiler/cgen.nim b/compiler/cgen.nim
index 1ab7f6db2..c8906f380 100644
--- a/compiler/cgen.nim
+++ b/compiler/cgen.nim
@@ -113,6 +113,9 @@ proc cgFormatValue(result: var string; value: string): void =
 proc cgFormatValue(result: var string; value: BiggestInt): void =
   result.addInt value
 
+proc cgFormatValue(result: var string; value: Int128): void =
+  result.addInt128 value
+
 # TODO: please document
 macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
   args.expectKind nnkBracket
diff --git a/compiler/closureiters.nim b/compiler/closureiters.nim
index 22595b772..c60ce96a2 100644
--- a/compiler/closureiters.nim
+++ b/compiler/closureiters.nim
@@ -174,7 +174,7 @@ proc newStateAssgn(ctx: var Ctx, toValue: PNode): PNode =
 proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
   # Creates state assignment:
   #   :state = stateNo
-  ctx.newStateAssgn(newIntTypeNode(nkIntLit, stateNo, ctx.g.getSysType(TLineInfo(), tyInt)))
+  ctx.newStateAssgn(newIntTypeNode(stateNo, ctx.g.getSysType(TLineInfo(), tyInt)))
 
 proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
   result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.fn, ctx.fn.info)
@@ -359,7 +359,7 @@ proc addElseToExcept(ctx: var Ctx, n: PNode) =
     block: # :unrollFinally = true
       branchBody.add(newTree(nkAsgn,
         ctx.newUnrollFinallyAccess(n.info),
-        newIntTypeNode(nkIntLit, 1, ctx.g.getSysType(n.info, tyBool))))
+        newIntTypeNode(1, ctx.g.getSysType(n.info, tyBool))))
 
     block: # :curExc = getCurrentException()
       branchBody.add(newTree(nkAsgn,
@@ -832,7 +832,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
     block: # :unrollFinally = true
       let asgn = newNodeI(nkAsgn, n.info)
       asgn.add(ctx.newUnrollFinallyAccess(n.info))
-      asgn.add(newIntTypeNode(nkIntLit, 1, ctx.g.getSysType(n.info, tyBool)))
+      asgn.add(newIntTypeNode(1, ctx.g.getSysType(n.info, tyBool)))
       result.add(asgn)
 
     if n[0].kind != nkEmpty:
@@ -1162,7 +1162,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
     let cond = newTree(nkCall,
       ctx.g.getSysMagic(info, "==", mEqI).newSymNode(),
       ctx.newStateAccess(),
-      newIntTypeNode(nkIntLit, 0, intTyp))
+      newIntTypeNode(0, intTyp))
     cond.typ = boolTyp
 
     let raiseStmt = newTree(nkRaiseStmt, ctx.g.emptyNode)
@@ -1174,7 +1174,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
   block:
     let cond = newTree(nkCall,
       ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
-      newIntTypeNode(nkIntLit, 0, intTyp),
+      newIntTypeNode(0, intTyp),
       ctx.newStateAccess())
     cond.typ = boolTyp
 
@@ -1186,7 +1186,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
     let cond = newTree(nkCall,
       ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
       ctx.newStateAccess(),
-      newIntTypeNode(nkIntLit, 0, intTyp))
+      newIntTypeNode(0, intTyp))
     cond.typ = boolTyp
 
     let negateState = newTree(nkCall,
diff --git a/compiler/guards.nim b/compiler/guards.nim
index 0a1c5640d..1ab50b8b6 100644
--- a/compiler/guards.nim
+++ b/compiler/guards.nim
@@ -10,7 +10,7 @@
 ## This module implements the 'implies' relation for guards.
 
 import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
-  saturate, modulegraphs, options, lineinfos
+  saturate, modulegraphs, options, lineinfos, int128
 
 const
   someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc,
@@ -522,7 +522,7 @@ proc geImpliesIn(x, c, aSet: PNode): TImplication =
     var value = newIntNode(c.kind, c.intVal)
     let max = lastOrd(nil, x.typ)
     # don't iterate too often:
-    if max - value.intVal < 1000:
+    if max - getInt(value) < toInt128(1000):
       var i, pos, neg: int
       while value.intVal <= max:
         if inSet(aSet, value): inc pos
diff --git a/compiler/int128.nim b/compiler/int128.nim
index 5df1201c0..efa55f9c7 100644
--- a/compiler/int128.nim
+++ b/compiler/int128.nim
@@ -1,4 +1,9 @@
+## This module is for compiler internal use only. For reliable error
+## messages and range checks, the compiler needs a data type that can
+## hold all from ``low(BiggestInt)`` to ``high(BiggestUInt)``, This
+## type is for that purpose.
 
+from math import trunc
 
 type
   Int128* = object
@@ -24,6 +29,7 @@ const
   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))])
+  NegOne* = Int128(udata: [0xffffffff'u32,0xffffffff'u32,0xffffffff'u32,0xffffffff'u32])
 
 template low*(t: typedesc[Int128]): Int128 = Min
 template high*(t: typedesc[Int128]): Int128 = Max
@@ -74,11 +80,85 @@ proc toInt64*(arg: Int128): int64 =
 
   cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
 
+proc toInt32*(arg: Int128): int32 =
+  if isNegative(arg):
+    assert(arg.sdata(3) == -1, "out of range")
+    assert(arg.sdata(2) == -1, "out of range")
+    assert(arg.sdata(1) == -1, "out of range")
+  else:
+    assert(arg.sdata(3) == 0, "out of range")
+    assert(arg.sdata(2) == 0, "out of range")
+    assert(arg.sdata(1) == 0, "out of range")
+
+  arg.sdata(0)
+
+proc toInt16*(arg: Int128): int16 =
+  if isNegative(arg):
+    assert(arg.sdata(3) == -1, "out of range")
+    assert(arg.sdata(2) == -1, "out of range")
+    assert(arg.sdata(1) == -1, "out of range")
+  else:
+    assert(arg.sdata(3) == 0, "out of range")
+    assert(arg.sdata(2) == 0, "out of range")
+    assert(arg.sdata(1) == 0, "out of range")
+
+  int16(arg.sdata(0))
+
+proc toInt8*(arg: Int128): int8 =
+  if isNegative(arg):
+    assert(arg.sdata(3) == -1, "out of range")
+    assert(arg.sdata(2) == -1, "out of range")
+    assert(arg.sdata(1) == -1, "out of range")
+  else:
+    assert(arg.sdata(3) == 0, "out of range")
+    assert(arg.sdata(2) == 0, "out of range")
+    assert(arg.sdata(1) == 0, "out of range")
+
+  int8(arg.sdata(0))
+
+proc toInt*(arg: Int128): int =
+  when sizeof(int) == 4:
+    cast[int](toInt32(arg))
+  else:
+    cast[int](toInt64(arg))
+
 proc toUInt64*(arg: Int128): uint64 =
   assert(arg.udata[3] == 0)
   assert(arg.udata[2] == 0)
   bitconcat(arg.udata[1], arg.udata[0])
 
+proc toUInt32*(arg: Int128): uint32 =
+  assert(arg.udata[3] == 0)
+  assert(arg.udata[2] == 0)
+  assert(arg.udata[1] == 0)
+  arg.udata[0]
+
+proc toUInt16*(arg: Int128): uint16 =
+  assert(arg.udata[3] == 0)
+  assert(arg.udata[2] == 0)
+  assert(arg.udata[1] == 0)
+  uint16(arg.udata[0])
+
+proc toUInt8*(arg: Int128): uint8 =
+  assert(arg.udata[3] == 0)
+  assert(arg.udata[2] == 0)
+  assert(arg.udata[1] == 0)
+  uint8(arg.udata[0])
+
+proc toUInt*(arg: Int128): uint =
+  when sizeof(int) == 4:
+    cast[uint](toInt32(arg))
+  else:
+    cast[uint](toInt64(arg))
+
+proc castToInt64*(arg: Int128): int64 =
+  ## Conversion to int64 without range check.
+  cast[int64](bitconcat(arg.udata[1], arg.udata[0]))
+
+proc castToUInt64*(arg: Int128): uint64 =
+  ## Conversion to uint64 without range check.
+  cast[uint64](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
@@ -206,7 +286,6 @@ proc `shl`*(a: Int128, b: int): Int128 =
     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)
@@ -319,7 +398,8 @@ proc fastLog2*(a: Int128): int =
 
 proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
   assert(divisor != Zero)
-  let isNegative = isNegative(dividend) xor isNegative(divisor)
+  let isNegativeA = isNegative(dividend)
+  let isNegativeB = isNegative(divisor)
 
   var dividend = abs(dividend)
   let divisor = abs(divisor)
@@ -351,8 +431,14 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
 
     denominator = denominator shr 1
 
-  result.quotient = quotient
-  result.remainder = dividend
+  if isNegativeA xor isNegativeB:
+    result.quotient = -quotient
+  else:
+    result.quotient = quotient
+  if isNegativeB:
+    result.remainder = -dividend
+  else:
+    result.remainder = dividend
 
 proc `div`*(a,b: Int128): Int128 =
   let (a,b) = divMod(a,b)
@@ -362,28 +448,32 @@ 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"
+proc addInt128*(result: var string; value: Int128) =
+  let initialSize = result.len
+  if value == Zero:
+    result.add "0"
+  elif value == low(Int128):
+    result.add "-170141183460469231731687303715884105728"
   else:
-    let isNegative = isNegative(a)
-    var a = abs(a)
-    while a > Zero:
-      let (quot, rem) = divMod(a, Ten)
+    let isNegative = isNegative(value)
+    var value = abs(value)
+    while value > Zero:
+      let (quot, rem) = divMod(value, Ten)
       result.add "0123456789"[rem.toInt64]
-      a = quot
+      value = quot
     if isNegative:
       result.add '-'
 
-    var i = 0
+    var i = initialSize
     var j = high(result)
     while i < j:
       swap(result[i], result[j])
       i += 1
       j -= 1
 
+proc `$`*(a: Int128): string =
+  result.addInt128(a)
+
 proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 =
   assert(pos < arg.len)
   assert(arg[pos] in {'-','0'..'9'})
@@ -435,6 +525,77 @@ proc `+`*(a: BiggestInt, b: Int128): Int128 =
 proc `+`*(a: Int128, b: BiggestInt): Int128 =
   a + toInt128(b)
 
+proc toFloat64*(arg: Int128): float64 =
+  let isNegative = isNegative(arg)
+  let arg = abs(arg)
+
+  let a = float64(bitconcat(arg.udata[1], arg.udata[0]))
+  let b = float64(bitconcat(arg.udata[3], arg.udata[2]))
+
+  result = a + 18446744073709551616'f64 * b # a + 2^64 * b
+  if isNegative:
+    result = -result
+
+proc ldexp(x: float64, exp: cint): float64 {.importc: "ldexp", header: "<math.h>".}
+
+template bitor(a,b,c: Int128): Int128 = bitor(bitor(a,b), c)
+
+proc toInt128*(arg: float64): Int128 =
+  let isNegative = arg < 0
+  assert(arg <  0x47E0000000000000'f64, "out of range")
+  assert(arg >= 0xC7E0000000000000'f64, "out of range")
+  let v0 = ldexp(abs(arg), -100)
+  let w0 = uint64(trunc(v0))
+  let v1 = ldexp(v0 - float64(w0), 50)
+  let w1 = uint64(trunc(v1))
+  let v2 = ldexp(v1 - float64(w1), 50)
+  let w2 = uint64(trunc(v2))
+
+  let res = bitor(toInt128(w0) shl 100, toInt128(w1) shl 50, toInt128(w2))
+  if isNegative:
+    return -res
+  else:
+    return res
+
+proc maskUInt64*(arg: Int128): Int128 {.noinit, inline.} =
+  result.udata[0] = arg.udata[0]
+  result.udata[1] = arg.udata[1]
+  result.udata[2] = 0
+  result.udata[3] = 0
+
+proc maskUInt32*(arg: Int128): Int128 {.noinit, inline.} =
+  result.udata[0] = arg.udata[0]
+  result.udata[1] = 0
+  result.udata[2] = 0
+  result.udata[3] = 0
+
+proc maskUInt16*(arg: Int128): Int128 {.noinit, inline.} =
+  result.udata[0] = arg.udata[0] and 0xffff
+  result.udata[1] = 0
+  result.udata[2] = 0
+  result.udata[3] = 0
+
+proc maskUInt8*(arg: Int128): Int128 {.noinit, inline.} =
+  result.udata[0] = arg.udata[0] and 0xff
+  result.udata[1] = 0
+  result.udata[2] = 0
+  result.udata[3] = 0
+
+proc maskBytes*(arg: Int128, numbytes: int): Int128 {.noinit.} =
+  case numbytes
+  of 1:
+    return maskUInt8(arg)
+  of 2:
+    return maskUInt16(arg)
+  of 4:
+    return maskUInt32(arg)
+  of 8:
+    return maskUInt64(arg)
+  else:
+    assert(false, "masking only implemented for 1, 2, 4 and 8 bytes")
+
+
+
 
 when isMainModule:
   let (a,b) = divMod(Ten,Ten)
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 788e3e75b..82f445352 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -1173,7 +1173,7 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
 proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
   var
     a, b: TCompRes
-    first: BiggestInt
+    first: Int128
   r.typ = etyBaseIndex
   let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
   gen(p, m.sons[0], a)
@@ -1182,8 +1182,8 @@ proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
   let (x, tmp) = maybeMakeTemp(p, m[0], a)
   r.address = x
   var typ = skipTypes(m.sons[0].typ, abstractPtrs)
-  if typ.kind == tyArray: first = firstOrd(p.config, typ.sons[0])
-  else: first = 0
+  if typ.kind == tyArray:
+    first = firstOrd(p.config, typ.sons[0])
   if optBoundsCheck in p.options:
     useMagic(p, "chckIndx")
     r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), tmp]
@@ -1612,7 +1612,7 @@ proc createVar(p: PProc, typ: PType, indirect: bool): Rope =
   of tyBool:
     result = putToSeq("false", indirect)
   of tyArray:
-    let length = int(lengthOrd(p.config, t))
+    let length = toInt(lengthOrd(p.config, t))
     let e = elemType(t)
     let jsTyp = arrayTypeForElemType(e)
     if jsTyp.len > 0:
diff --git a/compiler/jstypes.nim b/compiler/jstypes.nim
index b49985cbf..c037fd22a 100644
--- a/compiler/jstypes.nim
+++ b/compiler/jstypes.nim
@@ -7,8 +7,12 @@
 #    distribution, for details about the copyright.
 #
 
+# included from jsgen.nim
+
 ## Type info generation for the JS backend.
 
+proc rope(arg: Int128): Rope = rope($arg)
+
 proc genTypeInfo(p: PProc, typ: PType): Rope
 proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
   var
diff --git a/compiler/lambdalifting.nim b/compiler/lambdalifting.nim
index 679391224..d783e0554 100644
--- a/compiler/lambdalifting.nim
+++ b/compiler/lambdalifting.nim
@@ -933,7 +933,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
 
   var loopBody = newNodeI(nkStmtList, body.info, 3)
   var whileLoop = newNodeI(nkWhileStmt, body.info, 2)
-  whileLoop.sons[0] = newIntTypeNode(nkIntLit, 1, getSysType(g, body.info, tyBool))
+  whileLoop.sons[0] = newIntTypeNode(1, getSysType(g, body.info, tyBool))
   whileLoop.sons[1] = loopBody
   result.add whileLoop
 
diff --git a/compiler/liftdestructors.nim b/compiler/liftdestructors.nim
index 5619350ef..abd294e5a 100644
--- a/compiler/liftdestructors.nim
+++ b/compiler/liftdestructors.nim
@@ -288,7 +288,7 @@ proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
   result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
 
 proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) =
-  let i = declareCounter(c, body, firstOrd(c.g.config, t))
+  let i = declareCounter(c, body, toInt64(firstOrd(c.g.config, t)))
   let whileLoop = genWhileLoop(c, i, x)
   let elemType = t.lastSon
   fillBody(c, elemType, whileLoop.sons[1], x.at(i, elemType),
diff --git a/compiler/lowerings.nim b/compiler/lowerings.nim
index 727b88760..9ff3ece33 100644
--- a/compiler/lowerings.nim
+++ b/compiler/lowerings.nim
@@ -330,7 +330,7 @@ proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
 
 proc genHigh*(g: ModuleGraph; n: PNode): PNode =
   if skipTypes(n.typ, abstractVar).kind == tyArray:
-    result = newIntLit(g, n.info, lastOrd(g.config, skipTypes(n.typ, abstractVar)))
+    result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar))))
   else:
     result = newNodeI(nkCall, n.info, 2)
     result.typ = getSysType(g, n.info, tyInt)
@@ -339,7 +339,7 @@ proc genHigh*(g: ModuleGraph; n: PNode): PNode =
 
 proc genLen*(g: ModuleGraph; n: PNode): PNode =
   if skipTypes(n.typ, abstractVar).kind == tyArray:
-    result = newIntLit(g, n.info, lastOrd(g.config, skipTypes(n.typ, abstractVar)) + 1)
+    result = newIntLit(g, n.info, toInt64(lastOrd(g.config, skipTypes(n.typ, abstractVar)) + 1))
   else:
     result = newNodeI(nkCall, n.info, 2)
     result.typ = getSysType(g, n.info, tyInt)
diff --git a/compiler/nimsets.nim b/compiler/nimsets.nim
index f4ef0cc39..bd070f2c7 100644
--- a/compiler/nimsets.nim
+++ b/compiler/nimsets.nim
@@ -59,17 +59,17 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
   result = false
 
 proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) =
-  var first, j: BiggestInt
+  var first, j: Int128
   first = firstOrd(conf, s.typ.sons[0])
   bitSetInit(b, int(getSize(conf, s.typ)))
   for i in 0 ..< sonsLen(s):
     if s.sons[i].kind == nkRange:
       j = getOrdValue(s.sons[i].sons[0], first)
       while j <= getOrdValue(s.sons[i].sons[1], first):
-        bitSetIncl(b, j - first)
+        bitSetIncl(b, toInt64(j - first))
         inc(j)
     else:
-      bitSetIncl(b, getOrdValue(s.sons[i], first) - first)
+      bitSetIncl(b, toInt64(getOrdValue(s.sons[i]) - first))
 
 proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): PNode =
   var
@@ -77,7 +77,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
     elemType: PType
     n: PNode
   elemType = settype.sons[0]
-  first = firstOrd(conf, elemType)
+  first = firstOrd(conf, elemType).toInt64
   result = newNodeI(nkCurly, info)
   result.typ = settype
   result.info = info
@@ -90,7 +90,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
         inc(b)
         if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
       dec(b)
-      let aa = newIntTypeNode(nkIntLit, a + first, elemType)
+      let aa = newIntTypeNode(a + first, elemType)
       aa.info = info
       if a == b:
         addSon(result, aa)
@@ -98,7 +98,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
         n = newNodeI(nkRange, info)
         n.typ = elemType
         addSon(n, aa)
-        let bb = newIntTypeNode(nkIntLit, b + first, elemType)
+        let bb = newIntTypeNode(b + first, elemType)
         bb.info = info
         addSon(n, bb)
         addSon(result, n)
diff --git a/compiler/renderer.nim b/compiler/renderer.nim
index 11eaec146..c018a2cad 100644
--- a/compiler/renderer.nim
+++ b/compiler/renderer.nim
@@ -330,8 +330,7 @@ proc ulitAux(g: TSrcGen; n: PNode, x: BiggestInt, size: int): string =
   if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
   elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
   elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
-  else: result = $x
-  # XXX proper unsigned output!
+  else: result = $cast[BiggestUInt](x)
 
 proc atom(g: TSrcGen; n: PNode): string =
   when defined(nimpretty):
diff --git a/compiler/semdata.nim b/compiler/semdata.nim
index 257415383..5638fd29e 100644
--- a/compiler/semdata.nim
+++ b/compiler/semdata.nim
@@ -367,7 +367,7 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
   if n.typ != nil and n.typ.n == nil:
     result.flags.incl tfUnresolved
   result.n = newNode(nkRange, n.info, @[
-    newIntTypeNode(nkIntLit, 0, intType),
+    newIntTypeNode(0, intType),
     makeStaticExpr(c, nMinusOne(c, n))])
 
 template rangeHasUnresolvedStatic*(t: PType): bool =
@@ -391,8 +391,8 @@ proc makeRangeType*(c: PContext; first, last: BiggestInt;
                     info: TLineInfo; intType: PType = nil): PType =
   let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt)
   var n = newNodeI(nkRange, info)
-  addSon(n, newIntTypeNode(nkIntLit, first, intType))
-  addSon(n, newIntTypeNode(nkIntLit, last, intType))
+  addSon(n, newIntTypeNode(first, intType))
+  addSon(n, newIntTypeNode(last, intType))
   result = newTypeS(tyRange, c)
   result.n = n
   addSonSkipIntLit(result, intType) # basetype of range
diff --git a/compiler/semexprs.nim b/compiler/semexprs.nim
index 733df2c40..439a0070e 100644
--- a/compiler/semexprs.nim
+++ b/compiler/semexprs.nim
@@ -532,12 +532,12 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
   result.typ = newTypeS(tyArray, c)
   rawAddSon(result.typ, nil)     # index type
   var
-    firstIndex, lastIndex: BiggestInt = 0
+    firstIndex, lastIndex: Int128
     indexType = getSysType(c.graph, n.info, tyInt)
     lastValidIndex = lastOrd(c.config, indexType)
   if sonsLen(n) == 0:
     rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
-    lastIndex = -1
+    lastIndex = toInt128(-1)
   else:
     var x = n.sons[0]
     if x.kind == nkExprColonExpr and sonsLen(x) == 2:
@@ -558,7 +558,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     #var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
     for i in 1 ..< sonsLen(n):
       if lastIndex == lastValidIndex:
-        let validIndex = makeRangeType(c, firstIndex, lastValidIndex, n.info,
+        let validIndex = makeRangeType(c, toInt64(firstIndex), toInt64(lastValidIndex), n.info,
                                        indexType)
         localError(c.config, n.info, "size of array exceeds range of index " &
           "type '$1' by $2 elements" % [typeToString(validIndex), $(n.len-i)])
@@ -580,7 +580,7 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
     addSonSkipIntLit(result.typ, typ)
     for i in 0 ..< result.len:
       result.sons[i] = fitNode(c, typ, result.sons[i], result.sons[i].info)
-  result.typ.sons[0] = makeRangeType(c, firstIndex, lastIndex, n.info,
+  result.typ.sons[0] = makeRangeType(c, toInt64(firstIndex), toInt64(lastIndex), n.info,
                                      indexType)
 
 proc fixAbstractType(c: PContext, n: PNode) =
@@ -1478,7 +1478,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
     if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in
         {tyInt..tyInt64}:
       let idx = getOrdValue(n.sons[1])
-      if idx >= 0 and idx < len(arr): n.typ = arr.sons[int(idx)]
+      if idx >= 0 and idx < len(arr): n.typ = arr.sons[toInt(idx)]
       else: localError(c.config, n.info, "invalid index value for tuple subscript")
       result = n
     else:
diff --git a/compiler/semfold.nim b/compiler/semfold.nim
index c7efa1a87..38b29344f 100644
--- a/compiler/semfold.nim
+++ b/compiler/semfold.nim
@@ -15,7 +15,12 @@ import
   platform, math, msgs, idents, renderer, types,
   commands, magicsys, modulegraphs, strtabs, lineinfos
 
-proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
+proc errorType*(g: ModuleGraph): PType =
+  ## creates a type representing an error state
+  result = newType(tyError, g.owners[^1])
+  result.flags.incl tfCheckedForDestructor
+
+proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode {.deprecated: "intVal should be Int128".} =
   case skipTypes(n.typ, abstractVarRange).kind
   of tyInt:
     result = newIntNode(nkIntLit, intVal)
@@ -35,6 +40,15 @@ proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
     result.typ = n.typ
   result.info = n.info
 
+proc newIntNodeT*(intVal: Int128, n: PNode; g: ModuleGraph): PNode =
+  result = newIntTypeNode(intVal, n.typ)
+  # See bug #6989. 'pred' et al only produce an int literal type if the
+  # original type was 'int', not a distinct int etc.
+  if n.typ.kind == tyInt:
+    # access cache for the int lit type
+    result.typ = getIntLitType(g, result)
+  result.info = n.info
+
 proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
   result = newFloatNode(nkFloatLit, floatVal)
   result.typ = n.typ
@@ -50,65 +64,30 @@ proc getConstExpr*(m: PSym, n: PNode; g: ModuleGraph): PNode
   # expression
 proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
 
-proc checkInRange(conf: ConfigRef; n: PNode, res: BiggestInt): bool =
-  if res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ):
-    result = true
+proc checkInRange(conf: ConfigRef; n: PNode, res: Int128): bool =
+  res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ)
 
-proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
-  let res = a +% b
-  if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and
-      checkInRange(g.config, n, res):
+proc foldAdd(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
+  let res = a + b
+  if checkInRange(g.config, n, res):
     result = newIntNodeT(res, n, g)
 
-proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
-  let res = a -% b
-  if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and
-      checkInRange(g.config, n, res):
+proc foldSub(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
+  let res = a - b
+  if checkInRange(g.config, n, res):
     result = newIntNodeT(res, n, g)
 
-proc foldUnarySub(a: BiggestInt, n: PNode, g: ModuleGraph): PNode =
+proc foldUnarySub(a: Int128, n: PNode, g: ModuleGraph): PNode =
   if a != firstOrd(g.config, n.typ):
     result = newIntNodeT(-a, n, g)
 
-proc foldAbs*(a: BiggestInt, n: PNode; g: ModuleGraph): PNode =
+proc foldAbs(a: Int128, n: PNode; g: ModuleGraph): PNode =
   if a != firstOrd(g.config, n.typ):
     result = newIntNodeT(abs(a), n, g)
 
-proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
-  if b != 0'i64:
-    result = newIntNodeT(a mod b, n, g)
-
-proc foldModU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
-  if b != 0'i64:
-    result = newIntNodeT(a %% b, n, g)
-
-proc foldDiv*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
-  if b != 0'i64 and (a != firstOrd(g.config, n.typ) or b != -1'i64):
-    result = newIntNodeT(a div b, n, g)
-
-proc foldDivU*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
-  if b != 0'i64:
-    result = newIntNodeT(a /% b, n, g)
-
-proc foldMul*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode =
-  let res = a *% b
-  let floatProd = toBiggestFloat(a) * toBiggestFloat(b)
-  let resAsFloat = toBiggestFloat(res)
-
-  # Fast path for normal case: small multiplicands, and no info
-  # is lost in either method.
-  if resAsFloat == floatProd and checkInRange(g.config, n, res):
-    return newIntNodeT(res, n, g)
-
-  # Somebody somewhere lost info. Close enough, or way off? Note
-  # that a != 0 and b != 0 (else resAsFloat == floatProd == 0).
-  # The difference either is or isn't significant compared to the
-  # true value (of which floatProd is a good approximation).
-
-  # abs(diff)/abs(prod) <= 1/32 iff
-  #   32 * abs(diff) <= abs(prod) -- 5 good bits is "close enough"
-  if 32.0 * abs(resAsFloat - floatProd) <= abs(floatProd) and
-      checkInRange(g.config, n, res):
+proc foldMul(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
+  let res = a * b
+  if checkInRange(g.config, n, res):
     return newIntNodeT(res, n, g)
 
 proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
@@ -119,7 +98,7 @@ proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
   var t = skipTypes(a.typ, abstractRange)
   case t.kind
   of tyChar:
-    result = $chr(int(x) and 0xff)
+    result = $chr(toInt64(x) and 0xff)
   of tyEnum:
     var n = t.n
     for i in 0 ..< sonsLen(n):
@@ -176,7 +155,7 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat; g: ModuleGraph): PType =
   result.n = n
   addSonSkipIntLit(result, skipTypes(typ, {tyRange}))
 
-proc fitLiteral(c: ConfigRef, n: PNode): PNode =
+proc fitLiteral(c: ConfigRef, n: PNode): PNode {.deprecated: "no substitute".} =
   # Trim the literal value in order to make it fit in the destination type
   if n == nil:
     # `n` may be nil if the overflow check kicks in
@@ -188,12 +167,9 @@ proc fitLiteral(c: ConfigRef, n: PNode): PNode =
 
   let typ = n.typ.skipTypes(abstractRange)
   if typ.kind in tyUInt..tyUInt32:
-    result.intVal = result.intVal and lastOrd(c, typ, fixedUnsigned=true)
+    result.intVal = result.intVal and castToInt64(lastOrd(c, typ))
 
 proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
-  template doAndFit(op: untyped): untyped =
-    # Implements wrap-around behaviour for unsigned types
-    fitLiteral(g.config, op)
   # b and c may be nil
   result = nil
   case m
@@ -201,45 +177,61 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
   of mChr: result = newIntNodeT(getInt(a), n, g)
   of mUnaryMinusI, mUnaryMinusI64: result = foldUnarySub(getInt(a), n, g)
   of mUnaryMinusF64: result = newFloatNodeT(- getFloat(a), n, g)
-  of mNot: result = newIntNodeT(1 - getInt(a), n, g)
+  of mNot: result = newIntNodeT(One - getInt(a), n, g)
   of mCard: result = newIntNodeT(nimsets.cardSet(g.config, a), n, g)
-  of mBitnotI: result = doAndFit(newIntNodeT(not getInt(a), n, g))
+  of mBitnotI:
+    if n.typ.isUnsigned:
+      result = newIntNodeT(bitnot(getInt(a)).maskBytes(int(n.typ.size)), n, g)
+    else:
+      result = newIntNodeT(bitnot(getInt(a)), n, g)
   of mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
   of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
     if a.kind == nkNilLit:
-      result = newIntNodeT(0, n, g)
+      result = newIntNodeT(Zero, n, g)
     elif a.kind in {nkStrLit..nkTripleStrLit}:
-      result = newIntNodeT(len a.strVal, n, g)
+      result = newIntNodeT(toInt128(a.strVal.len), n, g)
     else:
-      result = newIntNodeT(sonsLen(a), n, g)
+      result = newIntNodeT(toInt128(sonsLen(a)), n, g)
   of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
   of mToFloat, mToBiggestFloat:
-    result = newFloatNodeT(toFloat(int(getInt(a))), n, g)
+    result = newFloatNodeT(toFloat64(getInt(a)), n, g)
   # XXX: Hides overflow/underflow
   of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n, g)
   of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g)
   of mAbsI: result = foldAbs(getInt(a), n, g)
-  of mUnaryLt: result = doAndFit(foldSub(getOrdValue(a), 1, n, g))
-  of mSucc: result = doAndFit(foldAdd(getOrdValue(a), getInt(b), n, g))
-  of mPred: result = doAndFit(foldSub(getOrdValue(a), getInt(b), n, g))
+  of mUnaryLt: result = foldSub(getOrdValue(a), One, n, g)
+  of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
+  of mPred: result = foldSub(getOrdValue(a), getInt(b), n, g)
   of mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
   of mSubI: result = foldSub(getInt(a), getInt(b), n, g)
   of mMulI: result = foldMul(getInt(a), getInt(b), n, g)
   of mMinI:
-    if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n, g)
-    else: result = newIntNodeT(getInt(a), n, g)
+    if getInt(a) > getInt(b): result = newIntNodeT(getInt64(b), n, g)
+    else: result = newIntNodeT(getInt64(a), n, g)
   of mMaxI:
-    if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n, g)
-    else: result = newIntNodeT(getInt(b), n, g)
+    let argA = getInt(a)
+    let argB = getInt(b)
+    result = newIntNodeT(if argA > argB: argA else: argB, n, g)
   of mShlI:
     case skipTypes(n.typ, abstractRange).kind
-    of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g)
-    of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g)
-    of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g)
-    of tyInt64, tyInt:
-      result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)
-    of tyUInt..tyUInt64:
-      result = doAndFit(newIntNodeT(`shl`(getInt(a), getInt(b)), n, g))
+    of tyInt8: result = newIntNodeT(toInt8(getInt(a)) shl getInt64(b), n, g)
+    of tyInt16: result = newIntNodeT(toInt16(getInt(a)) shl getInt64(b), n, g)
+    of tyInt32: result = newIntNodeT(toInt32(getInt(a)) shl getInt64(b), n, g)
+    of tyInt64: result = newIntNodeT(toInt64(getInt(a)) shl getInt64(b), n, g)
+    of tyInt:
+      if g.config.target.intSize == 4:
+        result = newIntNodeT(toInt128(toInt32(getInt(a)) shl getInt64(b)), n, g)
+      else:
+        result = newIntNodeT(toInt128(toInt64(getInt(a)) shl getInt64(b)), n, g)
+    of tyUInt8: result = newIntNodeT(toInt128(toUInt8(getInt(a)) shl getInt64(b)), n, g)
+    of tyUInt16: result = newIntNodeT(toInt128(toUInt16(getInt(a)) shl getInt64(b)), n, g)
+    of tyUInt32: result = newIntNodeT(toInt128(toUInt32(getInt(a)) shl getInt64(b)), n, g)
+    of tyUInt64: result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl getInt64(b)), n, g)
+    of tyUInt:
+      if g.config.target.intSize == 4:
+        result = newIntNodeT(BiggestInt(toUInt32(getInt(a)) shl getInt64(b)), n, g)
+      else:
+        result = newIntNodeT(toInt128(toUInt64(getInt(a)) shl getInt64(b)), n, g)
     else: internalError(g.config, n.info, "constant folding for shl")
   of mShrI:
     var a = cast[uint64](getInt(a))
@@ -263,14 +255,22 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
     result = newIntNodeT(c, n, g)
   of mAshrI:
     case skipTypes(n.typ, abstractRange).kind
-    of tyInt8: result = newIntNodeT(ashr(int8(getInt(a)), int8(getInt(b))), n, g)
-    of tyInt16: result = newIntNodeT(ashr(int16(getInt(a)), int16(getInt(b))), n, g)
-    of tyInt32: result = newIntNodeT(ashr(int32(getInt(a)), int32(getInt(b))), n, g)
+    of tyInt8: result = newIntNodeT(ashr(int8(getInt64(a)), int8(getInt64(b))), n, g)
+    of tyInt16: result = newIntNodeT(ashr(int16(getInt64(a)), int16(getInt64(b))), n, g)
+    of tyInt32: result = newIntNodeT(ashr(int32(getInt64(a)), int32(getInt64(b))), n, g)
     of tyInt64, tyInt:
-      result = newIntNodeT(ashr(getInt(a), getInt(b)), n, g)
+      result = newIntNodeT(ashr(getInt64(a), getInt64(b)), n, g)
     else: internalError(g.config, n.info, "constant folding for ashr")
-  of mDivI: result = foldDiv(getInt(a), getInt(b), n, g)
-  of mModI: result = foldMod(getInt(a), getInt(b), n, g)
+  of mDivI:
+    let argA = getInt(a)
+    let argB = getInt(b)
+    if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne):
+      result = newIntNodeT(argA div argB, n, g)
+  of mModI:
+    let argA = getInt(a)
+    let argB = getInt(b)
+    if argB != Zero and (argA != firstOrd(g.config, n.typ) or argB != NegOne):
+      result = newIntNodeT(argA mod argB, n, g)
   of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
   of mSubF64: result = newFloatNodeT(getFloat(a) - getFloat(b), n, g)
   of mMulF64: result = newFloatNodeT(getFloat(a) * getFloat(b), n, g)
@@ -296,17 +296,32 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
   of mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n, g)
   of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n, g)
   of mLtU, mLtU64:
-    result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g)
+    result = newIntNodeT(ord(`<%`(getOrdValue64(a), getOrdValue64(b))), n, g)
   of mLeU, mLeU64:
-    result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g)
-  of mBitandI, mAnd: result = doAndFit(newIntNodeT(a.getInt and b.getInt, n, g))
-  of mBitorI, mOr: result = doAndFit(newIntNodeT(getInt(a) or getInt(b), n, g))
-  of mBitxorI, mXor: result = doAndFit(newIntNodeT(a.getInt xor b.getInt, n, g))
-  of mAddU: result = doAndFit(newIntNodeT(`+%`(getInt(a), getInt(b)), n, g))
-  of mSubU: result = doAndFit(newIntNodeT(`-%`(getInt(a), getInt(b)), n, g))
-  of mMulU: result = doAndFit(newIntNodeT(`*%`(getInt(a), getInt(b)), n, g))
-  of mModU: result = doAndFit(foldModU(getInt(a), getInt(b), n, g))
-  of mDivU: result = doAndFit(foldDivU(getInt(a), getInt(b), n, g))
+    result = newIntNodeT(ord(`<=%`(getOrdValue64(a), getOrdValue64(b))), n, g)
+  of mBitandI, mAnd: result = newIntNodeT(bitand(a.getInt, b.getInt), n, g)
+  of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, g)
+  of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, g)
+  of mAddU:
+    let val = maskBytes(getInt(a) + getInt(b), int(n.typ.size))
+    result = newIntNodeT(val, n, g)
+  of mSubU:
+    let val = maskBytes(getInt(a) - getInt(b), int(n.typ.size))
+    result = newIntNodeT(val, n, g)
+    # echo "subU: ", val, " n: ", n, " result: ", val
+  of mMulU:
+    let val = maskBytes(getInt(a) * getInt(b), int(n.typ.size))
+    result = newIntNodeT(val, n, g)
+  of mModU:
+    let argA = maskBytes(getInt(a), int(a.typ.size))
+    let argB = maskBytes(getInt(b), int(a.typ.size))
+    if argB != Zero:
+      result = newIntNodeT(argA mod argB, n, g)
+  of mDivU:
+    let argA = maskBytes(getInt(a), int(a.typ.size))
+    let argB = maskBytes(getInt(b), int(a.typ.size))
+    if argB != Zero:
+      result = newIntNodeT(argA div argB, n, g)
   of mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g)
   of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g)
   of mLtSet:
@@ -332,10 +347,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
   of mBoolToStr:
     if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
     else: result = newStrNodeT("true", n, g)
-  of mCopyStr: result = newStrNodeT(substr(getStr(a), int(getOrdValue(b))), n, g)
+  of mCopyStr: result = newStrNodeT(substr(getStr(a), int(toInt64(getOrdValue(b)))), n, g)
   of mCopyStrLast:
-    result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)),
-                                           int(getOrdValue(c))), n, g)
+    result = newStrNodeT(substr(getStr(a), toInt(getOrdValue(b)),
+                                           toInt(getOrdValue(c))), n, g)
   of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
   of mCStrToStr, mCharToStr:
     if a.kind == nkBracket:
@@ -415,13 +430,8 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
   else:
     result = newStrNodeT("console", n, g)
 
-proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
-  var err = false
-  if n.typ.skipTypes({tyRange}).kind in {tyUInt..tyUInt64}:
-    err = value <% firstOrd(g.config, n.typ) or value >% lastOrd(g.config, n.typ, fixedUnsigned=true)
-  else:
-    err = value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ)
-  if err:
+proc rangeCheck(n: PNode, value: Int128; g: ModuleGraph) =
+  if value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ):
     localError(g.config, n.info, "cannot convert " & $value &
                                     " to " & typeToString(n.typ))
 
@@ -429,43 +439,35 @@ proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
   let dstTyp = skipTypes(n.typ, abstractRange)
   let srcTyp = skipTypes(a.typ, abstractRange)
 
+
+  # if srcTyp.kind == tyUInt64 and "FFFFFF" in $n:
+  #   echo "n: ", n, " a: ", a
+  #   echo "from: ", srcTyp, " to: ", dstTyp, " check: ", check
+  #   echo getInt(a)
+  #   echo high(int64)
+  #   writeStackTrace()
+
   # XXX range checks?
   case dstTyp.kind
   of tyInt..tyInt64, tyUInt..tyUInt64:
     case srcTyp.kind
     of tyFloat..tyFloat64:
-      result = newIntNodeT(int(getFloat(a)), n, g)
-    of tyChar:
-      result = newIntNodeT(getOrdValue(a), n, g)
-    of tyUInt..tyUInt64, tyInt..tyInt64:
-      let toSigned = dstTyp.kind in tyInt..tyInt64
+      result = newIntNodeT(BiggestInt(getFloat(a)), n, g)
+    of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
       var val = a.getOrdValue
-
-      if dstTyp.kind in {tyInt, tyInt64, tyUInt, tyUInt64}:
-        # No narrowing needed
-        discard
-      elif dstTyp.kind in {tyInt..tyInt64}:
-        # Signed type: Overflow check (if requested) and conversion
-        if check: rangeCheck(n, val, g)
-        let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1)
-        let valSign = val < 0
-        val = abs(val) and mask
-        if valSign: val = -val
-      else:
-        # Unsigned type: Conversion
-        let mask = (`shl`(1, getSize(g.config, dstTyp) * 8) - 1)
-        val = val and mask
-
+      if check: rangeCheck(n, val, g)
       result = newIntNodeT(val, n, g)
+      if dstTyp.kind in {tyUInt .. tyUInt64}:
+        result.kind = nkUIntLit
     else:
       result = a
       result.typ = n.typ
     if check and result.kind in {nkCharLit..nkUInt64Lit}:
-      rangeCheck(n, result.intVal, g)
+      rangeCheck(n, getInt(result), g)
   of tyFloat..tyFloat64:
     case srcTyp.kind
     of tyInt..tyInt64, tyEnum, tyBool, tyChar:
-      result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g)
+      result = newFloatNodeT(toFloat64(getOrdValue(a)), n, g)
     else:
       result = a
       result.typ = n.typ
@@ -490,16 +492,16 @@ proc foldArrayAccess(m: PSym, n: PNode; g: ModuleGraph): PNode =
   var y = getConstExpr(m, n.sons[1], g)
   if y == nil: return
 
-  var idx = getOrdValue(y)
+  var idx = toInt64(getOrdValue(y))
   case x.kind
   of nkPar, nkTupleConstr:
     if idx >= 0 and idx < sonsLen(x):
-      result = x.sons[int(idx)]
+      result = x.sons[idx]
       if result.kind == nkExprColonExpr: result = result.sons[1]
     else:
       localError(g.config, n.info, formatErrorIndexBound(idx, sonsLen(x)-1) & $n)
   of nkBracket:
-    idx = idx - firstOrd(g.config, x.typ)
+    idx = idx - toInt64(firstOrd(g.config, x.typ))
     if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
     else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
   of nkStrLit..nkTripleStrLit:
@@ -729,8 +731,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
   of nkHiddenStdConv, nkHiddenSubConv, nkConv:
     var a = getConstExpr(m, n.sons[1], g)
     if a == nil: return
-    # XXX: we should enable `check` for other conversion types too
-    result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv)
+    result = foldConv(n, a, g, check=true)
   of nkCast:
     var a = getConstExpr(m, n.sons[1], g)
     if a == nil: return
diff --git a/compiler/semmagic.nim b/compiler/semmagic.nim
index 6956e9eca..7f6bf8fa3 100644
--- a/compiler/semmagic.nim
+++ b/compiler/semmagic.nim
@@ -186,7 +186,9 @@ proc semOrd(c: PContext, n: PNode): PNode =
   if isOrdinalType(parType, allowEnumWithHoles=true):
     discard
   elif parType.kind == tySet:
-    result.typ = makeRangeType(c, firstOrd(c.config, parType), lastOrd(c.config, parType), n.info)
+    let a = toInt64(firstOrd(c.config, parType))
+    let b = toInt64(lastOrd(c.config, parType))
+    result.typ = makeRangeType(c, a, b, n.info)
   else:
     localError(c.config, n.info, errOrdinalTypeExpected)
     result.typ = errorType(c)
@@ -273,7 +275,7 @@ proc semDynamicBindSym(c: PContext, n: PNode): PNode =
     # executed like 'normal' VM callback
     idx = vm.registerCallback("bindSymImpl", bindSymWrapper)
     # dummy node to carry idx information to VM
-    idxNode = newIntTypeNode(nkIntLit, idx, c.graph.getSysType(TLineInfo(), tyInt))
+    idxNode = newIntTypeNode(idx, c.graph.getSysType(TLineInfo(), tyInt))
 
   result = copyNode(n)
   for x in n: result.add x
diff --git a/compiler/semobjconstr.nim b/compiler/semobjconstr.nim
index b4db5e47f..719b5e18d 100644
--- a/compiler/semobjconstr.nim
+++ b/compiler/semobjconstr.nim
@@ -100,7 +100,7 @@ proc allPossibleValues(c: PContext, t: PType): IntSet =
     for field in t.n.sons:
       result.incl(field.sym.position)
   else:
-    for i in firstOrd(c.config, t) .. lastOrd(c.config, t):
+    for i in toInt64(firstOrd(c.config, t)) .. toInt64(lastOrd(c.config, t)):
       result.incl(i.int)
 
 proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,
diff --git a/compiler/semtypes.nim b/compiler/semtypes.nim
index a2425e9fa..cece00ba0 100644
--- a/compiler/semtypes.nim
+++ b/compiler/semtypes.nim
@@ -69,7 +69,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
     base = semTypeNode(c, n.sons[0].sons[0], nil)
     if base.kind != tyEnum:
       localError(c.config, n.sons[0].info, "inheritance only works with an enum")
-    counter = lastOrd(c.config, base) + 1
+    counter = toInt64(lastOrd(c.config, base)) + 1
   rawAddSon(result, base)
   let isPure = result.sym != nil and sfPure in result.sym.flags
   var symbols: TStrTable
@@ -93,7 +93,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
           if skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
             if not isOrdinalType(v.sons[0].typ, allowEnumWithHoles=true):
               localError(c.config, v.sons[0].info, errOrdinalTypeExpected & "; given: " & typeToString(v.sons[0].typ, preferDesc))
-            x = getOrdValue(v.sons[0]) # first tuple part is the ordinal
+            x = toInt64(getOrdValue(v.sons[0])) # first tuple part is the ordinal
           else:
             localError(c.config, strVal.info, errStringLiteralExpected)
         else:
@@ -104,7 +104,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
       else:
         if not isOrdinalType(v.typ, allowEnumWithHoles=true):
           localError(c.config, v.info, errOrdinalTypeExpected & "; given: " & typeToString(v.typ, preferDesc))
-        x = getOrdValue(v)
+        x = toInt64(getOrdValue(v))
       if i != 1:
         if x != counter: incl(result.flags, tfEnumHasHoles)
         if x < counter:
@@ -507,7 +507,7 @@ proc semBranchRange(c: PContext, t, a, b: PNode, covered: var Int128): PNode =
   result.add(at)
   result.add(bt)
   if emptyRange(ac, bc): localError(c.config, b.info, "range is empty")
-  else: covered = covered + getOrdValue(bc) - getOrdValue(ac) + 1
+  else: covered = covered + getOrdValue(bc) + 1 - getOrdValue(ac)
 
 proc semCaseBranchRange(c: PContext, t, b: PNode,
                         covered: var Int128): PNode =
@@ -582,7 +582,7 @@ proc toCover(c: PContext, t: PType): Int128 =
     elif t.kind in {tyInt, tyUInt}:
       result = toInt128(1) shl (c.config.target.intSize * 8)
     else:
-      result = toInt128(lengthOrd(c.config, t))
+      result = lengthOrd(c.config, t)
 
 proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
                       father: PNode, rectype: PType, hasCaseFields = false)
diff --git a/compiler/sigmatch.nim b/compiler/sigmatch.nim
index 07ed5c3bc..6610158ae 100644
--- a/compiler/sigmatch.nim
+++ b/compiler/sigmatch.nim
@@ -377,8 +377,8 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
     if k == f.kind: result = isSubrange
     elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
                                    tyUInt..tyUInt64} and
-        isIntLit(ab) and ab.n.intVal >= firstOrd(nil, f) and
-                         ab.n.intVal <= lastOrd(nil, f):
+        isIntLit(ab) and getInt(ab.n) >= firstOrd(nil, f) and
+                         getInt(ab.n) <= lastOrd(nil, f):
       # passing 'nil' to firstOrd/lastOrd here as type checking rules should
       # not depent on the target integer size configurations!
       # integer literal in the proper range; we want ``i16 + 4`` to stay an
@@ -902,10 +902,10 @@ proc inferStaticsInRange(c: var TCandidate,
                                           allowUnresolved = true)
   let upperBound = tryResolvingStaticExpr(c, inferred.n[1],
                                           allowUnresolved = true)
-  template doInferStatic(e: PNode, r: BiggestInt) =
+  template doInferStatic(e: PNode, r: Int128) =
     var exp = e
     var rhs = r
-    if inferStaticParam(c, exp, rhs):
+    if inferStaticParam(c, exp, toInt64(rhs)):
       return isGeneric
     else:
       failureToInferStaticParam(c.c.config, exp)
@@ -918,7 +918,7 @@ proc inferStaticsInRange(c: var TCandidate,
         return isNone
     doInferStatic(upperBound, lengthOrd(c.c.config, concrete) + lowerBound.intVal - 1)
   elif upperBound.kind == nkIntLit:
-    doInferStatic(lowerBound, upperBound.intVal + 1 - lengthOrd(c.c.config, concrete))
+    doInferStatic(lowerBound, getInt(upperBound) + 1 - lengthOrd(c.c.config, concrete))
 
 template subtypeCheck() =
   if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {
diff --git a/compiler/sizealignoffsetimpl.nim b/compiler/sizealignoffsetimpl.nim
index 34384fa1f..6028ba5ee 100644
--- a/compiler/sizealignoffsetimpl.nim
+++ b/compiler/sizealignoffsetimpl.nim
@@ -332,7 +332,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
       typ.size = elemSize
       typ.align = int16(elemSize)
     else:
-      typ.size = lengthOrd(conf, typ.sons[0]) * elemSize
+      typ.size = toInt64(lengthOrd(conf, typ.sons[0]) * int32(elemSize))
       typ.align = typ.sons[1].align
 
   of tyUncheckedArray:
@@ -341,11 +341,11 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
     typ.size = 0
     typ.align = base.align
   of tyEnum:
-    if firstOrd(conf, typ) < 0:
+    if firstOrd(conf, typ) < Zero:
       typ.size = 4              # use signed int32
       typ.align = 4
     else:
-      length = lastOrd(conf, typ)   # BUGFIX: use lastOrd!
+      length = toInt64(lastOrd(conf, typ))   # BUGFIX: use lastOrd!
       if length + 1 < `shl`(1, 8):
         typ.size = 1
         typ.align = 1
@@ -363,7 +363,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
       typ.size = szUncomputedSize
       typ.align = szUncomputedSize # in original version this was 1
     else:
-      length = lengthOrd(conf, typ.sons[0])
+      length = toInt64(lengthOrd(conf, typ.sons[0]))
       if length <= 8:
         typ.size = 1
       elif length <= 16:
diff --git a/compiler/transf.nim b/compiler/transf.nim
index 60a7ce224..0435ca322 100644
--- a/compiler/transf.nim
+++ b/compiler/transf.nim
@@ -489,8 +489,8 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
         result = newTransNode(nkChckRange, n, 3)
       dest = skipTypes(n.typ, abstractVar)
       result[0] = transform(c, n.sons[1])
-      result[1] = newIntTypeNode(nkIntLit, firstOrd(c.graph.config, dest), dest).PTransNode
-      result[2] = newIntTypeNode(nkIntLit, lastOrd(c.graph.config, dest), dest).PTransNode
+      result[1] = newIntTypeNode(firstOrd(c.graph.config, dest), dest).PTransNode
+      result[2] = newIntTypeNode(lastOrd(c.graph.config, dest), dest).PTransNode
   of tyFloat..tyFloat128:
     # XXX int64 -> float conversion?
     if skipTypes(n.typ, abstractVar).kind == tyRange:
diff --git a/compiler/types.nim b/compiler/types.nim
index 20f0d516e..fcf21fc54 100644
--- a/compiler/types.nim
+++ b/compiler/types.nim
@@ -11,7 +11,7 @@
 
 import
   intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options,
-  lineinfos
+  lineinfos, int128
 
 type
   TPreferedDesc* = enum
@@ -77,12 +77,35 @@ proc isPureObject*(typ: PType): bool =
     t = t.sons[0].skipTypes(skipPtrs)
   result = t.sym != nil and sfPure in t.sym.flags
 
-proc getOrdValue*(n: PNode; onError = high(BiggestInt)): BiggestInt =
+proc isUnsigned*(t: PType): bool =
+  t.skipTypes(abstractInst).kind in {tyChar, tyUInt..tyUInt64}
+
+proc getOrdValue*(n: PNode; onError = high(Int128)): Int128 =
+  case n.kind
+  of nkCharLit, nkUIntLit..nkUInt64Lit:
+    # XXX: enable this assert
+    #assert n.typ == nil or isUnsigned(n.typ), $n.typ
+    toInt128(cast[uint64](n.intVal))
+  of nkIntLit..nkInt64Lit:
+    # XXX: enable this assert
+    #assert n.typ == nil or not isUnsigned(n.typ), $n.typ.kind
+    toInt128(n.intVal)
+  of nkNilLit:
+    int128.Zero
+  of nkHiddenStdConv: getOrdValue(n.sons[1], onError)
+  else:
+    # XXX: The idea behind the introduction of int128 was to finally
+    # have all calculations numerically far away from any
+    # overflows. This command just introduces such overflows and
+    # should therefore really be revisited.
+    onError
+
+proc getOrdValue64*(n: PNode): BiggestInt {.deprecated: "use getOrdvalue".} =
   case n.kind
   of nkCharLit..nkUInt64Lit: n.intVal
   of nkNilLit: 0
-  of nkHiddenStdConv: getOrdValue(n.sons[1], onError)
-  else: onError
+  of nkHiddenStdConv: getOrdValue64(n.sons[1])
+  else: high(BiggestInt)
 
 proc getFloatValue*(n: PNode): BiggestFloat =
   case n.kind
@@ -629,10 +652,10 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
     result = typeToStr[t.kind]
   result.addTypeFlags(t)
 
-proc firstOrd*(conf: ConfigRef; t: PType): BiggestInt =
+proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
   case t.kind
   of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
-    result = 0
+    result = Zero
   of tySet, tyVar: result = firstOrd(conf, t.sons[0])
   of tyArray: result = firstOrd(conf, t.sons[0])
   of tyRange:
@@ -640,20 +663,22 @@ proc firstOrd*(conf: ConfigRef; t: PType): BiggestInt =
     assert(t.n.kind == nkRange)
     result = getOrdValue(t.n.sons[0])
   of tyInt:
-    if conf != nil and conf.target.intSize == 4: result = - (2147483646) - 2
-    else: result = 0x8000000000000000'i64
-  of tyInt8: result = - 128
-  of tyInt16: result = - 32768
-  of tyInt32: result = - 2147483646 - 2
-  of tyInt64: result = 0x8000000000000000'i64
-  of tyUInt..tyUInt64: result = 0
+    if conf != nil and conf.target.intSize == 4:
+      result = toInt128(-2147483648)
+    else:
+      result = toInt128(0x8000000000000000'i64)
+  of tyInt8: result =  toInt128(-128)
+  of tyInt16: result = toInt128(-32768)
+  of tyInt32: result = toInt128(-2147483648)
+  of tyInt64: result = toInt128(0x8000000000000000'i64)
+  of tyUInt..tyUInt64: result = Zero
   of tyEnum:
     # if basetype <> nil then return firstOrd of basetype
     if sonsLen(t) > 0 and t.sons[0] != nil:
       result = firstOrd(conf, t.sons[0])
     else:
       assert(t.n.sons[0].kind == nkSym)
-      result = t.n.sons[0].sym.position
+      result = toInt128(t.n.sons[0].sym.position)
   of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
      tyStatic, tyInferred, tyUserTypeClasses:
     result = firstOrd(conf, lastSon(t))
@@ -661,11 +686,10 @@ proc firstOrd*(conf: ConfigRef; t: PType): BiggestInt =
     if t.len > 0: result = firstOrd(conf, lastSon(t))
     else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
   of tyUncheckedArray:
-    result = 0
+    result = Zero
   else:
     internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
-    result = 0
-
+    result = Zero
 
 proc firstFloat*(t: PType): BiggestFloat =
   case t.kind
@@ -682,10 +706,10 @@ proc firstFloat*(t: PType): BiggestFloat =
     internalError(newPartialConfigRef(), "invalid kind for firstFloat(" & $t.kind & ')')
     NaN
 
-proc lastOrd*(conf: ConfigRef; t: PType; fixedUnsigned = false): BiggestInt =
+proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
   case t.kind
-  of tyBool: result = 1
-  of tyChar: result = 255
+  of tyBool: result = toInt128(1'u)
+  of tyChar: result = toInt128(255'u)
   of tySet, tyVar: result = lastOrd(conf, t.sons[0])
   of tyArray: result = lastOrd(conf, t.sons[0])
   of tyRange:
@@ -693,38 +717,37 @@ proc lastOrd*(conf: ConfigRef; t: PType; fixedUnsigned = false): BiggestInt =
     assert(t.n.kind == nkRange)
     result = getOrdValue(t.n.sons[1])
   of tyInt:
-    if conf != nil and conf.target.intSize == 4: result = 0x7FFFFFFF
-    else: result = 0x7FFFFFFFFFFFFFFF'i64
-  of tyInt8: result = 0x0000007F
-  of tyInt16: result = 0x00007FFF
-  of tyInt32: result = 0x7FFFFFFF
-  of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64
+    if conf != nil and conf.target.intSize == 4: result = toInt128(0x7FFFFFFF)
+    else: result = toInt128(0x7FFFFFFFFFFFFFFF'u64)
+  of tyInt8: result = toInt128(0x0000007F)
+  of tyInt16: result = toInt128(0x00007FFF)
+  of tyInt32: result = toInt128(0x7FFFFFFF)
+  of tyInt64: result = toInt128(0x7FFFFFFFFFFFFFFF'u64)
   of tyUInt:
-    if conf != nil and conf.target.intSize == 4: result = 0xFFFFFFFF
-    elif fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64
-    else: result = 0x7FFFFFFFFFFFFFFF'i64
-  of tyUInt8: result = 0xFF
-  of tyUInt16: result = 0xFFFF
-  of tyUInt32: result = 0xFFFFFFFF
+    if conf != nil and conf.target.intSize == 4:
+      result = toInt128(0xFFFFFFFF)
+    else:
+      result = toInt128(0xFFFFFFFFFFFFFFFF'u64)
+  of tyUInt8: result = toInt128(0xFF)
+  of tyUInt16: result = toInt128(0xFFFF)
+  of tyUInt32: result = toInt128(0xFFFFFFFF)
   of tyUInt64:
-    if fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64
-    else: result = 0x7FFFFFFFFFFFFFFF'i64
+    result = toInt128(0xFFFFFFFFFFFFFFFF'u64)
   of tyEnum:
     assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
-    result = t.n.sons[sonsLen(t.n) - 1].sym.position
+    result = toInt128(t.n.sons[sonsLen(t.n) - 1].sym.position)
   of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
      tyStatic, tyInferred, tyUserTypeClasses:
     result = lastOrd(conf, lastSon(t))
-  of tyProxy: result = 0
+  of tyProxy: result = Zero
   of tyOrdinal:
     if t.len > 0: result = lastOrd(conf, lastSon(t))
     else: internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
   of tyUncheckedArray:
-    result = high(BiggestInt)
+    result = Zero
   else:
     internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
-    result = 0
-
+    result = Zero
 
 proc lastFloat*(t: PType): BiggestFloat =
   case t.kind
@@ -758,7 +781,7 @@ proc floatRangeCheck*(x: BiggestFloat, t: PType): bool =
     internalError(newPartialConfigRef(), "invalid kind for floatRangeCheck:" & $t.kind)
     false
 
-proc lengthOrd*(conf: ConfigRef; t: PType): BiggestInt =
+proc lengthOrd*(conf: ConfigRef; t: PType): Int128 =
   case t.skipTypes(tyUserTypeClasses).kind
   of tyInt64, tyInt32, tyInt:
     # XXX: this is just wrong
@@ -767,11 +790,7 @@ proc lengthOrd*(conf: ConfigRef; t: PType): BiggestInt =
   else:
     let last = lastOrd(conf, t)
     let first = firstOrd(conf, t)
-    # XXX use a better overflow check here:
-    if last == high(BiggestInt) and first <= 0:
-      result = last
-    else:
-      result = last - first + 1
+    result = last - first + One
 
 # -------------- type equality -----------------------------------------------
 
diff --git a/compiler/vm.nim b/compiler/vm.nim
index 30ba6f32f..26b7ab5a9 100644
--- a/compiler/vm.nim
+++ b/compiler/vm.nim
@@ -16,7 +16,7 @@ import
   strutils, msgs, vmdef, vmgen, nimsets, types, passes,
   parser, vmdeps, idents, trees, renderer, options, transf, parseutils,
   vmmarshal, gorgeimpl, lineinfos, tables, btrees, macrocacheimpl,
-  modulegraphs, sighashes
+  modulegraphs, sighashes, int128
 
 from semfold import leValueConv, ordinalValToString
 from evaltempl import evalTemplate
@@ -411,7 +411,7 @@ proc opConv(c: PCtx; dest: var TFullReg, src: TFullReg, desttyp, srctyp: PType):
         dest.intVal = int(src.floatVal)
       else:
         dest.intVal = src.intVal
-      if dest.intVal < firstOrd(c.config, desttyp) or dest.intVal > lastOrd(c.config, desttyp):
+      if toInt128(dest.intVal) < firstOrd(c.config, desttyp) or toInt128(dest.intVal) > lastOrd(c.config, desttyp):
         return true
     of tyUInt..tyUInt64:
       if dest.kind != rkInt:
@@ -1312,7 +1312,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
     of opcQuit:
       if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
         message(c.config, c.debug[pc], hintQuitCalled)
-        msgQuit(int8(getOrdValue(regs[ra].regToNode)))
+        msgQuit(int8(toInt(getOrdValue(regs[ra].regToNode))))
       else:
         return TFullReg(kind: rkNone)
     of opcSetLenStr:
diff --git a/compiler/vmgen.nim b/compiler/vmgen.nim
index d1ed78bf2..9cd3b841e 100644
--- a/compiler/vmgen.nim
+++ b/compiler/vmgen.nim
@@ -596,12 +596,12 @@ proc genField(c: PCtx; n: PNode): TRegister =
 
 proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
   if arr.skipTypes(abstractInst).kind == tyArray and (let x = firstOrd(c.config, arr);
-      x != 0):
+      x != Zero):
     let tmp = c.genx(n)
     # freeing the temporary here means we can produce:  regA = regA - Imm
     c.freeTemp(tmp)
     result = c.getTemp(n.typ)
-    c.gABI(n, opcSubImmInt, result, tmp, x.int)
+    c.gABI(n, opcSubImmInt, result, tmp, toInt(x))
   else:
     result = c.genx(n)
 
@@ -1767,7 +1767,7 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
     getNullValueAux(t, t.n, result, conf, currPosition)
   of tyArray:
     result = newNodeIT(nkBracket, info, t)
-    for i in 0 ..< int(lengthOrd(conf, t)):
+    for i in 0 ..< toInt(lengthOrd(conf, t)):
       addSon(result, getNullValue(elemType(t), info, conf))
   of tyTuple:
     result = newNodeIT(nkTupleConstr, info, t)