diff options
author | Arne Döring <arne.doering@gmx.net> | 2019-08-07 15:53:16 +0200 |
---|---|---|
committer | Andreas Rumpf <rumpf_a@web.de> | 2019-08-07 15:53:16 +0200 |
commit | afbcd1b330f16294cee32efca1b2f9060874a497 (patch) | |
tree | d0406792478fa58d3c487ff6f72f999c29f25343 /compiler | |
parent | 8407a574992ebd6bccec647a902cf54a4de8db18 (diff) | |
download | Nim-afbcd1b330f16294cee32efca1b2f9060874a497.tar.gz |
int128 on firstOrd, lastOrd and lengthOrd (#11701)
* fixes #11847
Diffstat (limited to 'compiler')
-rw-r--r-- | compiler/ast.nim | 78 | ||||
-rw-r--r-- | compiler/ccgcalls.nim | 2 | ||||
-rw-r--r-- | compiler/ccgexprs.nim | 5 | ||||
-rw-r--r-- | compiler/ccgliterals.nim | 4 | ||||
-rw-r--r-- | compiler/ccgstmts.nim | 10 | ||||
-rw-r--r-- | compiler/ccgtypes.nim | 8 | ||||
-rw-r--r-- | compiler/cgen.nim | 3 | ||||
-rw-r--r-- | compiler/closureiters.nim | 12 | ||||
-rw-r--r-- | compiler/guards.nim | 4 | ||||
-rw-r--r-- | compiler/int128.nim | 191 | ||||
-rw-r--r-- | compiler/jsgen.nim | 8 | ||||
-rw-r--r-- | compiler/jstypes.nim | 4 | ||||
-rw-r--r-- | compiler/lambdalifting.nim | 2 | ||||
-rw-r--r-- | compiler/liftdestructors.nim | 2 | ||||
-rw-r--r-- | compiler/lowerings.nim | 4 | ||||
-rw-r--r-- | compiler/nimsets.nim | 12 | ||||
-rw-r--r-- | compiler/renderer.nim | 3 | ||||
-rw-r--r-- | compiler/semdata.nim | 6 | ||||
-rw-r--r-- | compiler/semexprs.nim | 10 | ||||
-rw-r--r-- | compiler/semfold.nim | 259 | ||||
-rw-r--r-- | compiler/semmagic.nim | 6 | ||||
-rw-r--r-- | compiler/semobjconstr.nim | 2 | ||||
-rw-r--r-- | compiler/semtypes.nim | 10 | ||||
-rw-r--r-- | compiler/sigmatch.nim | 10 | ||||
-rw-r--r-- | compiler/sizealignoffsetimpl.nim | 8 | ||||
-rw-r--r-- | compiler/transf.nim | 4 | ||||
-rw-r--r-- | compiler/types.nim | 109 | ||||
-rw-r--r-- | compiler/vm.nim | 6 | ||||
-rw-r--r-- | compiler/vmgen.nim | 6 |
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) |