int128 on firstOrd, lastOrd and lengthOrd (#11701)

* fixes #11847
This commit is contained in:
Arne Döring 2019-08-07 15:53:16 +02:00 • committed by Andreas Rumpf
commit afbcd1b330
34 changed files with 530 additions and 314 deletions

View file

@ -10,7 +10,9 @@
# abstract syntax tree + symbol table # abstract syntax tree + symbol table
import import
lineinfos, hashes, options, ropes, idents, idgen lineinfos, hashes, options, ropes, idents, idgen, int128
export int128
type type
TCallingConvention* = enum 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 template `[]=`*(n: Indexable, i: BackwardsIndex; x: Indexable) = n[n.len - i.int] = x
when defined(useNodeIds): when defined(useNodeIds):
const nodeIdToDebug* = -1 # 299750 # 300761 #300863 # 300879 const nodeIdToDebug* = 2322967# 2322968
var gNodeId: int var gNodeId: int
proc newNode*(kind: TNodeKind): PNode = proc newNode*(kind: TNodeKind): PNode =
@ -1233,10 +1235,48 @@ proc newIntNode*(kind: TNodeKind, intVal: BiggestInt): PNode =
result = newNode(kind) result = newNode(kind)
result.intVal = intVal result.intVal = intVal
proc newIntTypeNode*(kind: TNodeKind, intVal: BiggestInt, typ: PType): PNode = proc newIntNode*(kind: TNodeKind, intVal: Int128): PNode =
result = newIntNode(kind, intVal) 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 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 = proc newFloatNode*(kind: TNodeKind, floatVal: BiggestFloat): PNode =
result = newNode(kind) result = newNode(kind)
result.floatVal = floatVal result.floatVal = floatVal
@ -1325,7 +1365,6 @@ proc sonsLen*(n: PType): int = n.sons.len
proc len*(n: PType): int = n.sons.len proc len*(n: PType): int = n.sons.len
proc sonsLen*(n: PNode): int = n.sons.len proc sonsLen*(n: PNode): int = n.sons.len
proc lastSon*(n: PNode): PNode = n.sons[^1] proc lastSon*(n: PNode): PNode = n.sons[^1]
proc lastSon*(n: PType): PType = n.sons[^1]
proc assignType*(dest, src: PType) = proc assignType*(dest, src: PType) =
dest.kind = src.kind dest.kind = src.kind
@ -1421,14 +1460,6 @@ proc initNodeTable*(x: var TNodeTable) =
x.counter = 0 x.counter = 0
newSeq(x.data, StartSize) 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 = proc skipTypes*(t: PType, kinds: TTypeKinds; maxIters: int): PType =
result = t result = t
var i = maxIters var i = maxIters
@ -1604,14 +1635,25 @@ proc hasSubnodeWith*(n: PNode, kind: TNodeKind): bool =
return true return true
result = false result = false
proc getInt*(a: PNode): BiggestInt = proc getInt*(a: PNode): Int128 =
case a.kind case a.kind
of nkCharLit..nkUInt64Lit: result = a.intVal 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, nkUIntLit..nkUInt64Lit, nkIntLit..nkInt64Lit:
result = a.intVal
else: else:
raiseRecoverableError("cannot extract number from invalid AST node") raiseRecoverableError("cannot extract number from invalid AST node")
#internalError(a.info, "getInt")
#doAssert false, "getInt"
#result = 0
proc getFloat*(a: PNode): BiggestFloat = proc getFloat*(a: PNode): BiggestFloat =
case a.kind case a.kind

View file

@ -92,7 +92,7 @@ proc openArrayLoc(p: BProc, n: PNode): Rope =
let ty = skipTypes(a.t, abstractVar+{tyPtr}) let ty = skipTypes(a.t, abstractVar+{tyPtr})
case ty.kind case ty.kind
of tyArray: of tyArray:
let first = firstOrd(p.config, ty) let first = toInt64(firstOrd(p.config, ty))
if first == 0: if first == 0:
result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)] result = "($1)+($2), ($3)-($2)+1" % [rdLoc(a), rdLoc(b), rdLoc(c)]
else: else:

View file

@ -30,6 +30,9 @@ proc intLiteral(i: BiggestInt): Rope =
else: else:
result = ~"(IL64(-9223372036854775807) - IL64(1))" result = ~"(IL64(-9223372036854775807) - IL64(1))"
proc intLiteral(i: Int128): Rope =
intLiteral(toInt64(i))
proc genLiteral(p: BProc, n: PNode, ty: PType): Rope = proc genLiteral(p: BProc, n: PNode, ty: PType): Rope =
case n.kind case n.kind
of nkCharLit..nkUInt64Lit: of nkCharLit..nkUInt64Lit:
@ -1436,7 +1439,7 @@ proc genArrToSeq(p: BProc, n: PNode, d: var TLoc) =
if d.k == locNone: if d.k == locNone:
getTemp(p, n.typ, d) getTemp(p, n.typ, d)
# generate call to newSeq before adding the elements per hand: # 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: if p.config.selectedGC == gcDestructors:
let seqtype = n.typ let seqtype = n.typ
linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n", linefmt(p, cpsStmts, "$1.len = $2; $1.p = ($4*) #newSeqPayload($2, sizeof($3));$n",

View file

@ -7,6 +7,8 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# included from cgen.nim
## This include file contains the logic to produce constant string ## This include file contains the logic to produce constant string
## and seq literals. The code here is responsible that ## and seq literals. The code here is responsible that
## ``const x = ["a", "b"]`` works without hidden runtime creation code. ## ``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: if core == nil or core.kind != skConst:
m.g.field = 1 m.g.field = 1
else: else:
m.g.field = int ast.getInt(core.ast) m.g.field = toInt(ast.getInt(core.ast))
result = m.g.field result = m.g.field
proc detectStrVersion(m: BModule): int = proc detectStrVersion(m: BModule): int =

View file

@ -246,10 +246,10 @@ proc genGotoState(p: BProc, n: PNode) =
lineF(p, cpsStmts, " goto BeforeRet_;$n", []) lineF(p, cpsStmts, " goto BeforeRet_;$n", [])
var statesCounter = lastOrd(p.config, n.sons[0].typ) var statesCounter = lastOrd(p.config, n.sons[0].typ)
if n.len >= 2 and n[1].kind == nkIntLit: 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 let prefix = if n.len == 3 and n[2].kind == nkStrLit: n[2].strVal.rope
else: rope"STATE" 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, "case $2: goto $1$2;$n", [prefix, rope(i)])
lineF(p, cpsStmts, "}$n", []) lineF(p, cpsStmts, "}$n", [])
@ -494,7 +494,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
if aSize > 10_000: if aSize > 10_000:
localError(p.config, it.info, localError(p.config, it.info,
"case statement has too many cases for computed goto"); return "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: if firstOrd(p.config, it.sons[0].typ) != 0:
localError(p.config, it.info, localError(p.config, it.info,
"case statement has to start at 0 for computed goto"); return "case statement has to start at 0 for computed goto"); return
@ -527,7 +527,7 @@ proc genComputedGoto(p: BProc; n: PNode) =
return return
let val = getOrdValue(it.sons[j]) 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) genStmts(p, it.lastSon)
@ -1211,7 +1211,7 @@ proc genDiscriminantCheck(p: BProc, a, tmp: TLoc, objtype: PType,
var t = skipTypes(objtype, abstractVar) var t = skipTypes(objtype, abstractVar)
assert t.kind == tyObject assert t.kind == tyObject
discard genTypeInfo(p.module, t, a.lode.info) 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): if not containsOrIncl(p.module.declaredThings, field.id):
appcg(p.module, cfsVars, "extern $1", appcg(p.module, cfsVars, "extern $1",
[discriminatorTableDecl(p.module, t, field)]) [discriminatorTableDecl(p.module, t, field)])

View file

@ -805,7 +805,7 @@ proc getTypeDescAux(m: BModule, origTyp: PType, check: var IntSet): Rope =
let foo = getTypeDescAux(m, t.sons[0], check) let foo = getTypeDescAux(m, t.sons[0], check)
addf(m.s[cfsTypes], "typedef $1 $2[1];$n", [foo, result]) addf(m.s[cfsTypes], "typedef $1 $2[1];$n", [foo, result])
of tyArray: 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 if n <= 0: n = 1 # make an array of at least one element
result = getTypeName(m, origTyp, sig) result = getTypeName(m, origTyp, sig)
m.typeCache[sig] = result 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") internalError(m.config, d.info, "anonymous obj with discriminator")
result = "NimDT_$1_$2" % [rope($hashType(objtype)), rope(d.name.s.mangle)] 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 = proc discriminatorTableDecl(m: BModule, objtype: PType, d: PSym): Rope =
discard cgsym(m, "TNimNode") discard cgsym(m, "TNimNode")
var tmp = discriminatorTableName(m, objtype, d) 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") internalError(m.config, b.info, "genObjectFields; nkOfBranch broken")
for j in 0 .. sonsLen(b) - 2: for j in 0 .. sonsLen(b) - 2:
if b.sons[j].kind == nkRange: if b.sons[j].kind == nkRange:
var x = int(getOrdValue(b.sons[j].sons[0])) var x = toInt(getOrdValue(b.sons[j].sons[0]))
var y = int(getOrdValue(b.sons[j].sons[1])) var y = toInt(getOrdValue(b.sons[j].sons[1]))
while x <= y: while x <= y:
addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2]) addf(m.s[cfsTypeInit3], "$1[$2] = &$3;$n", [tmp, rope(x), tmp2])
inc(x) inc(x)

View file

@ -113,6 +113,9 @@ proc cgFormatValue(result: var string; value: string): void =
proc cgFormatValue(result: var string; value: BiggestInt): void = proc cgFormatValue(result: var string; value: BiggestInt): void =
result.addInt value result.addInt value
proc cgFormatValue(result: var string; value: Int128): void =
result.addInt128 value
# TODO: please document # TODO: please document
macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope = macro ropecg(m: BModule, frmt: static[FormatStr], args: untyped): Rope =
args.expectKind nnkBracket args.expectKind nnkBracket

View file

@ -174,7 +174,7 @@ proc newStateAssgn(ctx: var Ctx, toValue: PNode): PNode =
proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode = proc newStateAssgn(ctx: var Ctx, stateNo: int = -2): PNode =
# Creates state assignment: # Creates state assignment:
# :state = stateNo # :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 = proc newEnvVar(ctx: var Ctx, name: string, typ: PType): PSym =
result = newSym(skVar, getIdent(ctx.g.cache, name), ctx.fn, ctx.fn.info) 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 block: # :unrollFinally = true
branchBody.add(newTree(nkAsgn, branchBody.add(newTree(nkAsgn,
ctx.newUnrollFinallyAccess(n.info), ctx.newUnrollFinallyAccess(n.info),
newIntTypeNode(nkIntLit, 1, ctx.g.getSysType(n.info, tyBool)))) newIntTypeNode(1, ctx.g.getSysType(n.info, tyBool))))
block: # :curExc = getCurrentException() block: # :curExc = getCurrentException()
branchBody.add(newTree(nkAsgn, branchBody.add(newTree(nkAsgn,
@ -832,7 +832,7 @@ proc transformReturnsInTry(ctx: var Ctx, n: PNode): PNode =
block: # :unrollFinally = true block: # :unrollFinally = true
let asgn = newNodeI(nkAsgn, n.info) let asgn = newNodeI(nkAsgn, n.info)
asgn.add(ctx.newUnrollFinallyAccess(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) result.add(asgn)
if n[0].kind != nkEmpty: if n[0].kind != nkEmpty:
@ -1162,7 +1162,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
let cond = newTree(nkCall, let cond = newTree(nkCall,
ctx.g.getSysMagic(info, "==", mEqI).newSymNode(), ctx.g.getSysMagic(info, "==", mEqI).newSymNode(),
ctx.newStateAccess(), ctx.newStateAccess(),
newIntTypeNode(nkIntLit, 0, intTyp)) newIntTypeNode(0, intTyp))
cond.typ = boolTyp cond.typ = boolTyp
let raiseStmt = newTree(nkRaiseStmt, ctx.g.emptyNode) let raiseStmt = newTree(nkRaiseStmt, ctx.g.emptyNode)
@ -1174,7 +1174,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
block: block:
let cond = newTree(nkCall, let cond = newTree(nkCall,
ctx.g.getSysMagic(info, "<", mLtI).newSymNode, ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
newIntTypeNode(nkIntLit, 0, intTyp), newIntTypeNode(0, intTyp),
ctx.newStateAccess()) ctx.newStateAccess())
cond.typ = boolTyp cond.typ = boolTyp
@ -1186,7 +1186,7 @@ proc newCatchBody(ctx: var Ctx, info: TLineInfo): PNode {.inline.} =
let cond = newTree(nkCall, let cond = newTree(nkCall,
ctx.g.getSysMagic(info, "<", mLtI).newSymNode, ctx.g.getSysMagic(info, "<", mLtI).newSymNode,
ctx.newStateAccess(), ctx.newStateAccess(),
newIntTypeNode(nkIntLit, 0, intTyp)) newIntTypeNode(0, intTyp))
cond.typ = boolTyp cond.typ = boolTyp
let negateState = newTree(nkCall, let negateState = newTree(nkCall,

View file

@ -10,7 +10,7 @@
## This module implements the 'implies' relation for guards. ## This module implements the 'implies' relation for guards.
import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents, import ast, astalgo, msgs, magicsys, nimsets, trees, types, renderer, idents,
saturate, modulegraphs, options, lineinfos saturate, modulegraphs, options, lineinfos, int128
const const
someEq = {mEqI, mEqF64, mEqEnum, mEqCh, mEqB, mEqRef, mEqProc, 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) var value = newIntNode(c.kind, c.intVal)
let max = lastOrd(nil, x.typ) let max = lastOrd(nil, x.typ)
# don't iterate too often: # don't iterate too often:
if max - value.intVal < 1000: if max - getInt(value) < toInt128(1000):
var i, pos, neg: int var i, pos, neg: int
while value.intVal <= max: while value.intVal <= max:
if inSet(aSet, value): inc pos if inSet(aSet, value): inc pos

View file

@ -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 type
Int128* = object Int128* = object
@ -24,6 +29,7 @@ const
Ten* = Int128(udata: [10'u32,0,0,0]) Ten* = Int128(udata: [10'u32,0,0,0])
Min = Int128(udata: [0'u32,0,0,0x80000000'u32]) Min = Int128(udata: [0'u32,0,0,0x80000000'u32])
Max = Int128(udata: [high(uint32),high(uint32),high(uint32),uint32(high(int32))]) 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 low*(t: typedesc[Int128]): Int128 = Min
template high*(t: typedesc[Int128]): Int128 = Max 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])) 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 = proc toUInt64*(arg: Int128): uint64 =
assert(arg.udata[3] == 0) assert(arg.udata[3] == 0)
assert(arg.udata[2] == 0) assert(arg.udata[2] == 0)
bitconcat(arg.udata[1], arg.udata[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) = proc addToHex(result: var string; arg: uint32) =
for i in 0 ..< 8: for i in 0 ..< 8:
let idx = (arg shr ((7-i) * 4)) and 0xf 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[2] = 0
result.udata[3] = a.udata[0] shl (b and 31) result.udata[3] = a.udata[0] shl (b and 31)
proc `+`*(a,b: Int128): Int128 = proc `+`*(a,b: Int128): Int128 =
let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0]) let tmp0 = uint64(a.udata[0]) + uint64(b.udata[0])
result.udata[0] = cast[uint32](tmp0) result.udata[0] = cast[uint32](tmp0)
@ -319,7 +398,8 @@ proc fastLog2*(a: Int128): int =
proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] = proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
assert(divisor != Zero) assert(divisor != Zero)
let isNegative = isNegative(dividend) xor isNegative(divisor) let isNegativeA = isNegative(dividend)
let isNegativeB = isNegative(divisor)
var dividend = abs(dividend) var dividend = abs(dividend)
let divisor = abs(divisor) let divisor = abs(divisor)
@ -351,8 +431,14 @@ proc divMod*(dividend, divisor: Int128): tuple[quotient, remainder: Int128] =
denominator = denominator shr 1 denominator = denominator shr 1
result.quotient = quotient if isNegativeA xor isNegativeB:
result.remainder = dividend result.quotient = -quotient
else:
result.quotient = quotient
if isNegativeB:
result.remainder = -dividend
else:
result.remainder = dividend
proc `div`*(a,b: Int128): Int128 = proc `div`*(a,b: Int128): Int128 =
let (a,b) = divMod(a,b) let (a,b) = divMod(a,b)
@ -362,28 +448,32 @@ proc `mod`*(a,b: Int128): Int128 =
let (a,b) = divMod(a,b) let (a,b) = divMod(a,b)
return b return b
proc `$`*(a: Int128): string = proc addInt128*(result: var string; value: Int128) =
if a == Zero: let initialSize = result.len
result = "0" if value == Zero:
elif a == low(Int128): result.add "0"
result = "-170141183460469231731687303715884105728" elif value == low(Int128):
result.add "-170141183460469231731687303715884105728"
else: else:
let isNegative = isNegative(a) let isNegative = isNegative(value)
var a = abs(a) var value = abs(value)
while a > Zero: while value > Zero:
let (quot, rem) = divMod(a, Ten) let (quot, rem) = divMod(value, Ten)
result.add "0123456789"[rem.toInt64] result.add "0123456789"[rem.toInt64]
a = quot value = quot
if isNegative: if isNegative:
result.add '-' result.add '-'
var i = 0 var i = initialSize
var j = high(result) var j = high(result)
while i < j: while i < j:
swap(result[i], result[j]) swap(result[i], result[j])
i += 1 i += 1
j -= 1 j -= 1
proc `$`*(a: Int128): string =
result.addInt128(a)
proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 = proc parseDecimalInt128*(arg: string, pos: int = 0): Int128 =
assert(pos < arg.len) assert(pos < arg.len)
assert(arg[pos] in {'-','0'..'9'}) assert(arg[pos] in {'-','0'..'9'})
@ -435,6 +525,77 @@ proc `+`*(a: BiggestInt, b: Int128): Int128 =
proc `+`*(a: Int128, b: BiggestInt): Int128 = proc `+`*(a: Int128, b: BiggestInt): Int128 =
a + toInt128(b) 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: when isMainModule:
let (a,b) = divMod(Ten,Ten) let (a,b) = divMod(Ten,Ten)

View file

@ -1173,7 +1173,7 @@ proc genCheckedFieldOp(p: PProc, n: PNode, addrTyp: PType, r: var TCompRes) =
proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) = proc genArrayAddr(p: PProc, n: PNode, r: var TCompRes) =
var var
a, b: TCompRes a, b: TCompRes
first: BiggestInt first: Int128
r.typ = etyBaseIndex r.typ = etyBaseIndex
let m = if n.kind == nkHiddenAddr: n.sons[0] else: n let m = if n.kind == nkHiddenAddr: n.sons[0] else: n
gen(p, m.sons[0], a) 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) let (x, tmp) = maybeMakeTemp(p, m[0], a)
r.address = x r.address = x
var typ = skipTypes(m.sons[0].typ, abstractPtrs) var typ = skipTypes(m.sons[0].typ, abstractPtrs)
if typ.kind == tyArray: first = firstOrd(p.config, typ.sons[0]) if typ.kind == tyArray:
else: first = 0 first = firstOrd(p.config, typ.sons[0])
if optBoundsCheck in p.options: if optBoundsCheck in p.options:
useMagic(p, "chckIndx") useMagic(p, "chckIndx")
r.res = "chckIndx($1, $2, $3.length+$2-1)-$2" % [b.res, rope(first), tmp] 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: of tyBool:
result = putToSeq("false", indirect) result = putToSeq("false", indirect)
of tyArray: of tyArray:
let length = int(lengthOrd(p.config, t)) let length = toInt(lengthOrd(p.config, t))
let e = elemType(t) let e = elemType(t)
let jsTyp = arrayTypeForElemType(e) let jsTyp = arrayTypeForElemType(e)
if jsTyp.len > 0: if jsTyp.len > 0:

View file

@ -7,8 +7,12 @@
# distribution, for details about the copyright. # distribution, for details about the copyright.
# #
# included from jsgen.nim
## Type info generation for the JS backend. ## Type info generation for the JS backend.
proc rope(arg: Int128): Rope = rope($arg)
proc genTypeInfo(p: PProc, typ: PType): Rope proc genTypeInfo(p: PProc, typ: PType): Rope
proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope = proc genObjectFields(p: PProc, typ: PType, n: PNode): Rope =
var var

View file

@ -933,7 +933,7 @@ proc liftForLoop*(g: ModuleGraph; body: PNode; owner: PSym): PNode =
var loopBody = newNodeI(nkStmtList, body.info, 3) var loopBody = newNodeI(nkStmtList, body.info, 3)
var whileLoop = newNodeI(nkWhileStmt, body.info, 2) 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 whileLoop.sons[1] = loopBody
result.add whileLoop result.add whileLoop

View file

@ -288,7 +288,7 @@ proc setLenSeqCall(c: var TLiftCtx; t: PType; x, y: PNode): PNode =
result = newTree(nkCall, newSymNode(op, x.info), x, lenCall) result = newTree(nkCall, newSymNode(op, x.info), x, lenCall)
proc forallElements(c: var TLiftCtx; t: PType; body, x, y: PNode) = 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 whileLoop = genWhileLoop(c, i, x)
let elemType = t.lastSon let elemType = t.lastSon
fillBody(c, elemType, whileLoop.sons[1], x.at(i, elemType), fillBody(c, elemType, whileLoop.sons[1], x.at(i, elemType),

View file

@ -330,7 +330,7 @@ proc newIntLit*(g: ModuleGraph; info: TLineInfo; value: BiggestInt): PNode =
proc genHigh*(g: ModuleGraph; n: PNode): PNode = proc genHigh*(g: ModuleGraph; n: PNode): PNode =
if skipTypes(n.typ, abstractVar).kind == tyArray: 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: else:
result = newNodeI(nkCall, n.info, 2) result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(g, n.info, tyInt) 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 = proc genLen*(g: ModuleGraph; n: PNode): PNode =
if skipTypes(n.typ, abstractVar).kind == tyArray: 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: else:
result = newNodeI(nkCall, n.info, 2) result = newNodeI(nkCall, n.info, 2)
result.typ = getSysType(g, n.info, tyInt) result.typ = getSysType(g, n.info, tyInt)

View file

@ -59,17 +59,17 @@ proc someInSet*(s: PNode, a, b: PNode): bool =
result = false result = false
proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) = proc toBitSet*(conf: ConfigRef; s: PNode, b: var TBitSet) =
var first, j: BiggestInt var first, j: Int128
first = firstOrd(conf, s.typ.sons[0]) first = firstOrd(conf, s.typ.sons[0])
bitSetInit(b, int(getSize(conf, s.typ))) bitSetInit(b, int(getSize(conf, s.typ)))
for i in 0 ..< sonsLen(s): for i in 0 ..< sonsLen(s):
if s.sons[i].kind == nkRange: if s.sons[i].kind == nkRange:
j = getOrdValue(s.sons[i].sons[0], first) j = getOrdValue(s.sons[i].sons[0], first)
while j <= getOrdValue(s.sons[i].sons[1], first): while j <= getOrdValue(s.sons[i].sons[1], first):
bitSetIncl(b, j - first) bitSetIncl(b, toInt64(j - first))
inc(j) inc(j)
else: 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 = proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): PNode =
var var
@ -77,7 +77,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
elemType: PType elemType: PType
n: PNode n: PNode
elemType = settype.sons[0] elemType = settype.sons[0]
first = firstOrd(conf, elemType) first = firstOrd(conf, elemType).toInt64
result = newNodeI(nkCurly, info) result = newNodeI(nkCurly, info)
result.typ = settype result.typ = settype
result.info = info result.info = info
@ -90,7 +90,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
inc(b) inc(b)
if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break if (b >= len(s) * ElemSize) or not bitSetIn(s, b): break
dec(b) dec(b)
let aa = newIntTypeNode(nkIntLit, a + first, elemType) let aa = newIntTypeNode(a + first, elemType)
aa.info = info aa.info = info
if a == b: if a == b:
addSon(result, aa) addSon(result, aa)
@ -98,7 +98,7 @@ proc toTreeSet*(conf: ConfigRef; s: TBitSet, settype: PType, info: TLineInfo): P
n = newNodeI(nkRange, info) n = newNodeI(nkRange, info)
n.typ = elemType n.typ = elemType
addSon(n, aa) addSon(n, aa)
let bb = newIntTypeNode(nkIntLit, b + first, elemType) let bb = newIntTypeNode(b + first, elemType)
bb.info = info bb.info = info
addSon(n, bb) addSon(n, bb)
addSon(result, n) addSon(result, n)

View file

@ -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) if nfBase2 in n.flags: result = "0b" & toBin(x, size * 8)
elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3) elif nfBase8 in n.flags: result = "0o" & toOct(x, size * 3)
elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2) elif nfBase16 in n.flags: result = "0x" & toHex(x, size * 2)
else: result = $x else: result = $cast[BiggestUInt](x)
# XXX proper unsigned output!
proc atom(g: TSrcGen; n: PNode): string = proc atom(g: TSrcGen; n: PNode): string =
when defined(nimpretty): when defined(nimpretty):

View file

@ -367,7 +367,7 @@ proc makeRangeWithStaticExpr*(c: PContext, n: PNode): PType =
if n.typ != nil and n.typ.n == nil: if n.typ != nil and n.typ.n == nil:
result.flags.incl tfUnresolved result.flags.incl tfUnresolved
result.n = newNode(nkRange, n.info, @[ result.n = newNode(nkRange, n.info, @[
newIntTypeNode(nkIntLit, 0, intType), newIntTypeNode(0, intType),
makeStaticExpr(c, nMinusOne(c, n))]) makeStaticExpr(c, nMinusOne(c, n))])
template rangeHasUnresolvedStatic*(t: PType): bool = template rangeHasUnresolvedStatic*(t: PType): bool =
@ -391,8 +391,8 @@ proc makeRangeType*(c: PContext; first, last: BiggestInt;
info: TLineInfo; intType: PType = nil): PType = info: TLineInfo; intType: PType = nil): PType =
let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt) let intType = if intType != nil: intType else: getSysType(c.graph, info, tyInt)
var n = newNodeI(nkRange, info) var n = newNodeI(nkRange, info)
addSon(n, newIntTypeNode(nkIntLit, first, intType)) addSon(n, newIntTypeNode(first, intType))
addSon(n, newIntTypeNode(nkIntLit, last, intType)) addSon(n, newIntTypeNode(last, intType))
result = newTypeS(tyRange, c) result = newTypeS(tyRange, c)
result.n = n result.n = n
addSonSkipIntLit(result, intType) # basetype of range addSonSkipIntLit(result, intType) # basetype of range

View file

@ -532,12 +532,12 @@ proc semArrayConstr(c: PContext, n: PNode, flags: TExprFlags): PNode =
result.typ = newTypeS(tyArray, c) result.typ = newTypeS(tyArray, c)
rawAddSon(result.typ, nil) # index type rawAddSon(result.typ, nil) # index type
var var
firstIndex, lastIndex: BiggestInt = 0 firstIndex, lastIndex: Int128
indexType = getSysType(c.graph, n.info, tyInt) indexType = getSysType(c.graph, n.info, tyInt)
lastValidIndex = lastOrd(c.config, indexType) lastValidIndex = lastOrd(c.config, indexType)
if sonsLen(n) == 0: if sonsLen(n) == 0:
rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype! rawAddSon(result.typ, newTypeS(tyEmpty, c)) # needs an empty basetype!
lastIndex = -1 lastIndex = toInt128(-1)
else: else:
var x = n.sons[0] var x = n.sons[0]
if x.kind == nkExprColonExpr and sonsLen(x) == 2: 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}) #var typ = skipTypes(result.sons[0].typ, {tyGenericInst, tyVar, tyLent, tyOrdinal})
for i in 1 ..< sonsLen(n): for i in 1 ..< sonsLen(n):
if lastIndex == lastValidIndex: if lastIndex == lastValidIndex:
let validIndex = makeRangeType(c, firstIndex, lastValidIndex, n.info, let validIndex = makeRangeType(c, toInt64(firstIndex), toInt64(lastValidIndex), n.info,
indexType) indexType)
localError(c.config, n.info, "size of array exceeds range of index " & localError(c.config, n.info, "size of array exceeds range of index " &
"type '$1' by $2 elements" % [typeToString(validIndex), $(n.len-i)]) "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) addSonSkipIntLit(result.typ, typ)
for i in 0 ..< result.len: for i in 0 ..< result.len:
result.sons[i] = fitNode(c, typ, result.sons[i], result.sons[i].info) 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) indexType)
proc fixAbstractType(c: PContext, n: PNode) = 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 if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal, tyAlias, tySink}).kind in
{tyInt..tyInt64}: {tyInt..tyInt64}:
let idx = getOrdValue(n.sons[1]) 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") else: localError(c.config, n.info, "invalid index value for tuple subscript")
result = n result = n
else: else:

View file

@ -15,7 +15,12 @@ import
platform, math, msgs, idents, renderer, types, platform, math, msgs, idents, renderer, types,
commands, magicsys, modulegraphs, strtabs, lineinfos 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 case skipTypes(n.typ, abstractVarRange).kind
of tyInt: of tyInt:
result = newIntNode(nkIntLit, intVal) result = newIntNode(nkIntLit, intVal)
@ -35,6 +40,15 @@ proc newIntNodeT*(intVal: BiggestInt, n: PNode; g: ModuleGraph): PNode =
result.typ = n.typ result.typ = n.typ
result.info = n.info 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 = proc newFloatNodeT*(floatVal: BiggestFloat, n: PNode; g: ModuleGraph): PNode =
result = newFloatNode(nkFloatLit, floatVal) result = newFloatNode(nkFloatLit, floatVal)
result.typ = n.typ result.typ = n.typ
@ -50,65 +64,30 @@ proc getConstExpr*(m: PSym, n: PNode; g: ModuleGraph): PNode
# expression # expression
proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode proc evalOp*(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode
proc checkInRange(conf: ConfigRef; n: PNode, res: BiggestInt): bool = proc checkInRange(conf: ConfigRef; n: PNode, res: Int128): bool =
if res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ): res in firstOrd(conf, n.typ)..lastOrd(conf, n.typ)
result = true
proc foldAdd(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc foldAdd(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
let res = a +% b let res = a + b
if ((res xor a) >= 0'i64 or (res xor b) >= 0'i64) and if checkInRange(g.config, n, res):
checkInRange(g.config, n, res):
result = newIntNodeT(res, n, g) result = newIntNodeT(res, n, g)
proc foldSub*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc foldSub(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
let res = a -% b let res = a - b
if ((res xor a) >= 0'i64 or (res xor not b) >= 0'i64) and if checkInRange(g.config, n, res):
checkInRange(g.config, n, res):
result = newIntNodeT(res, n, g) 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): if a != firstOrd(g.config, n.typ):
result = newIntNodeT(-a, n, g) 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): if a != firstOrd(g.config, n.typ):
result = newIntNodeT(abs(a), n, g) result = newIntNodeT(abs(a), n, g)
proc foldMod*(a, b: BiggestInt, n: PNode; g: ModuleGraph): PNode = proc foldMul(a, b: Int128, n: PNode; g: ModuleGraph): PNode =
if b != 0'i64: let res = a * b
result = newIntNodeT(a mod b, n, g) if checkInRange(g.config, n, res):
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):
return newIntNodeT(res, n, g) return newIntNodeT(res, n, g)
proc ordinalValToString*(a: PNode; g: ModuleGraph): string = proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
@ -119,7 +98,7 @@ proc ordinalValToString*(a: PNode; g: ModuleGraph): string =
var t = skipTypes(a.typ, abstractRange) var t = skipTypes(a.typ, abstractRange)
case t.kind case t.kind
of tyChar: of tyChar:
result = $chr(int(x) and 0xff) result = $chr(toInt64(x) and 0xff)
of tyEnum: of tyEnum:
var n = t.n var n = t.n
for i in 0 ..< sonsLen(n): for i in 0 ..< sonsLen(n):
@ -176,7 +155,7 @@ proc makeRangeF(typ: PType, first, last: BiggestFloat; g: ModuleGraph): PType =
result.n = n result.n = n
addSonSkipIntLit(result, skipTypes(typ, {tyRange})) 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 # Trim the literal value in order to make it fit in the destination type
if n == nil: if n == nil:
# `n` may be nil if the overflow check kicks in # `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) let typ = n.typ.skipTypes(abstractRange)
if typ.kind in tyUInt..tyUInt32: 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 = 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 # b and c may be nil
result = nil result = nil
case m 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 mChr: result = newIntNodeT(getInt(a), n, g)
of mUnaryMinusI, mUnaryMinusI64: result = foldUnarySub(getInt(a), n, g) of mUnaryMinusI, mUnaryMinusI64: result = foldUnarySub(getInt(a), n, g)
of mUnaryMinusF64: result = newFloatNodeT(- getFloat(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 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 mLengthArray: result = newIntNodeT(lengthOrd(g.config, a.typ), n, g)
of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr: of mLengthSeq, mLengthOpenArray, mXLenSeq, mLengthStr, mXLenStr:
if a.kind == nkNilLit: if a.kind == nkNilLit:
result = newIntNodeT(0, n, g) result = newIntNodeT(Zero, n, g)
elif a.kind in {nkStrLit..nkTripleStrLit}: elif a.kind in {nkStrLit..nkTripleStrLit}:
result = newIntNodeT(len a.strVal, n, g) result = newIntNodeT(toInt128(a.strVal.len), n, g)
else: else:
result = newIntNodeT(sonsLen(a), n, g) result = newIntNodeT(toInt128(sonsLen(a)), n, g)
of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away of mUnaryPlusI, mUnaryPlusF64: result = a # throw `+` away
of mToFloat, mToBiggestFloat: of mToFloat, mToBiggestFloat:
result = newFloatNodeT(toFloat(int(getInt(a))), n, g) result = newFloatNodeT(toFloat64(getInt(a)), n, g)
# XXX: Hides overflow/underflow # XXX: Hides overflow/underflow
of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n, g) of mToInt, mToBiggestInt: result = newIntNodeT(system.toInt(getFloat(a)), n, g)
of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g) of mAbsF64: result = newFloatNodeT(abs(getFloat(a)), n, g)
of mAbsI: result = foldAbs(getInt(a), n, g) of mAbsI: result = foldAbs(getInt(a), n, g)
of mUnaryLt: result = doAndFit(foldSub(getOrdValue(a), 1, n, g)) of mUnaryLt: result = foldSub(getOrdValue(a), One, n, g)
of mSucc: result = doAndFit(foldAdd(getOrdValue(a), getInt(b), n, g)) of mSucc: result = foldAdd(getOrdValue(a), getInt(b), n, g)
of mPred: result = doAndFit(foldSub(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 mAddI: result = foldAdd(getInt(a), getInt(b), n, g)
of mSubI: result = foldSub(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 mMulI: result = foldMul(getInt(a), getInt(b), n, g)
of mMinI: of mMinI:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(b), n, g) if getInt(a) > getInt(b): result = newIntNodeT(getInt64(b), n, g)
else: result = newIntNodeT(getInt(a), n, g) else: result = newIntNodeT(getInt64(a), n, g)
of mMaxI: of mMaxI:
if getInt(a) > getInt(b): result = newIntNodeT(getInt(a), n, g) let argA = getInt(a)
else: result = newIntNodeT(getInt(b), n, g) let argB = getInt(b)
result = newIntNodeT(if argA > argB: argA else: argB, n, g)
of mShlI: of mShlI:
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n, g) of tyInt8: result = newIntNodeT(toInt8(getInt(a)) shl getInt64(b), n, g)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n, g) of tyInt16: result = newIntNodeT(toInt16(getInt(a)) shl getInt64(b), n, g)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n, g) of tyInt32: result = newIntNodeT(toInt32(getInt(a)) shl getInt64(b), n, g)
of tyInt64, tyInt: of tyInt64: result = newIntNodeT(toInt64(getInt(a)) shl getInt64(b), n, g)
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n, g) of tyInt:
of tyUInt..tyUInt64: if g.config.target.intSize == 4:
result = doAndFit(newIntNodeT(`shl`(getInt(a), getInt(b)), n, g)) 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") else: internalError(g.config, n.info, "constant folding for shl")
of mShrI: of mShrI:
var a = cast[uint64](getInt(a)) 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) result = newIntNodeT(c, n, g)
of mAshrI: of mAshrI:
case skipTypes(n.typ, abstractRange).kind case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(ashr(int8(getInt(a)), int8(getInt(b))), n, g) of tyInt8: result = newIntNodeT(ashr(int8(getInt64(a)), int8(getInt64(b))), n, g)
of tyInt16: result = newIntNodeT(ashr(int16(getInt(a)), int16(getInt(b))), n, g) of tyInt16: result = newIntNodeT(ashr(int16(getInt64(a)), int16(getInt64(b))), n, g)
of tyInt32: result = newIntNodeT(ashr(int32(getInt(a)), int32(getInt(b))), n, g) of tyInt32: result = newIntNodeT(ashr(int32(getInt64(a)), int32(getInt64(b))), n, g)
of tyInt64, tyInt: 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") else: internalError(g.config, n.info, "constant folding for ashr")
of mDivI: result = foldDiv(getInt(a), getInt(b), n, g) of mDivI:
of mModI: result = foldMod(getInt(a), getInt(b), n, g) 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 mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n, g)
of mSubF64: 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) 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 mLeStr: result = newIntNodeT(ord(getStr(a) <= getStr(b)), n, g)
of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n, g) of mEqStr: result = newIntNodeT(ord(getStr(a) == getStr(b)), n, g)
of mLtU, mLtU64: of mLtU, mLtU64:
result = newIntNodeT(ord(`<%`(getOrdValue(a), getOrdValue(b))), n, g) result = newIntNodeT(ord(`<%`(getOrdValue64(a), getOrdValue64(b))), n, g)
of mLeU, mLeU64: of mLeU, mLeU64:
result = newIntNodeT(ord(`<=%`(getOrdValue(a), getOrdValue(b))), n, g) result = newIntNodeT(ord(`<=%`(getOrdValue64(a), getOrdValue64(b))), n, g)
of mBitandI, mAnd: result = doAndFit(newIntNodeT(a.getInt and b.getInt, n, g)) of mBitandI, mAnd: result = newIntNodeT(bitand(a.getInt, b.getInt), n, g)
of mBitorI, mOr: result = doAndFit(newIntNodeT(getInt(a) or getInt(b), n, g)) of mBitorI, mOr: result = newIntNodeT(bitor(getInt(a), getInt(b)), n, g)
of mBitxorI, mXor: result = doAndFit(newIntNodeT(a.getInt xor b.getInt, n, g)) of mBitxorI, mXor: result = newIntNodeT(bitxor(getInt(a), getInt(b)), n, g)
of mAddU: result = doAndFit(newIntNodeT(`+%`(getInt(a), getInt(b)), n, g)) of mAddU:
of mSubU: result = doAndFit(newIntNodeT(`-%`(getInt(a), getInt(b)), n, g)) let val = maskBytes(getInt(a) + getInt(b), int(n.typ.size))
of mMulU: result = doAndFit(newIntNodeT(`*%`(getInt(a), getInt(b)), n, g)) result = newIntNodeT(val, n, g)
of mModU: result = doAndFit(foldModU(getInt(a), getInt(b), n, g)) of mSubU:
of mDivU: result = doAndFit(foldDivU(getInt(a), getInt(b), n, g)) 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 mLeSet: result = newIntNodeT(ord(containsSets(g.config, a, b)), n, g)
of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g) of mEqSet: result = newIntNodeT(ord(equalSets(g.config, a, b)), n, g)
of mLtSet: of mLtSet:
@ -332,10 +347,10 @@ proc evalOp(m: TMagic, n, a, b, c: PNode; g: ModuleGraph): PNode =
of mBoolToStr: of mBoolToStr:
if getOrdValue(a) == 0: result = newStrNodeT("false", n, g) if getOrdValue(a) == 0: result = newStrNodeT("false", n, g)
else: result = newStrNodeT("true", 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: of mCopyStrLast:
result = newStrNodeT(substr(getStr(a), int(getOrdValue(b)), result = newStrNodeT(substr(getStr(a), toInt(getOrdValue(b)),
int(getOrdValue(c))), n, g) toInt(getOrdValue(c))), n, g)
of mFloatToStr: result = newStrNodeT($getFloat(a), n, g) of mFloatToStr: result = newStrNodeT($getFloat(a), n, g)
of mCStrToStr, mCharToStr: of mCStrToStr, mCharToStr:
if a.kind == nkBracket: if a.kind == nkBracket:
@ -415,13 +430,8 @@ proc getAppType(n: PNode; g: ModuleGraph): PNode =
else: else:
result = newStrNodeT("console", n, g) result = newStrNodeT("console", n, g)
proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) = proc rangeCheck(n: PNode, value: Int128; g: ModuleGraph) =
var err = false if value < firstOrd(g.config, n.typ) or value > lastOrd(g.config, n.typ):
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:
localError(g.config, n.info, "cannot convert " & $value & localError(g.config, n.info, "cannot convert " & $value &
" to " & typeToString(n.typ)) " 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 dstTyp = skipTypes(n.typ, abstractRange)
let srcTyp = skipTypes(a.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? # XXX range checks?
case dstTyp.kind case dstTyp.kind
of tyInt..tyInt64, tyUInt..tyUInt64: of tyInt..tyInt64, tyUInt..tyUInt64:
case srcTyp.kind case srcTyp.kind
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
result = newIntNodeT(int(getFloat(a)), n, g) result = newIntNodeT(BiggestInt(getFloat(a)), n, g)
of tyChar: of tyChar, tyUInt..tyUInt64, tyInt..tyInt64:
result = newIntNodeT(getOrdValue(a), n, g)
of tyUInt..tyUInt64, tyInt..tyInt64:
let toSigned = dstTyp.kind in tyInt..tyInt64
var val = a.getOrdValue var val = a.getOrdValue
if check: rangeCheck(n, val, g)
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
result = newIntNodeT(val, n, g) result = newIntNodeT(val, n, g)
if dstTyp.kind in {tyUInt .. tyUInt64}:
result.kind = nkUIntLit
else: else:
result = a result = a
result.typ = n.typ result.typ = n.typ
if check and result.kind in {nkCharLit..nkUInt64Lit}: if check and result.kind in {nkCharLit..nkUInt64Lit}:
rangeCheck(n, result.intVal, g) rangeCheck(n, getInt(result), g)
of tyFloat..tyFloat64: of tyFloat..tyFloat64:
case srcTyp.kind case srcTyp.kind
of tyInt..tyInt64, tyEnum, tyBool, tyChar: of tyInt..tyInt64, tyEnum, tyBool, tyChar:
result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g) result = newFloatNodeT(toFloat64(getOrdValue(a)), n, g)
else: else:
result = a result = a
result.typ = n.typ 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) var y = getConstExpr(m, n.sons[1], g)
if y == nil: return if y == nil: return
var idx = getOrdValue(y) var idx = toInt64(getOrdValue(y))
case x.kind case x.kind
of nkPar, nkTupleConstr: of nkPar, nkTupleConstr:
if idx >= 0 and idx < sonsLen(x): if idx >= 0 and idx < sonsLen(x):
result = x.sons[int(idx)] result = x.sons[idx]
if result.kind == nkExprColonExpr: result = result.sons[1] if result.kind == nkExprColonExpr: result = result.sons[1]
else: else:
localError(g.config, n.info, formatErrorIndexBound(idx, sonsLen(x)-1) & $n) localError(g.config, n.info, formatErrorIndexBound(idx, sonsLen(x)-1) & $n)
of nkBracket: 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)] if idx >= 0 and idx < x.len: result = x.sons[int(idx)]
else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n) else: localError(g.config, n.info, formatErrorIndexBound(idx, x.len-1) & $n)
of nkStrLit..nkTripleStrLit: of nkStrLit..nkTripleStrLit:
@ -729,8 +731,7 @@ proc getConstExpr(m: PSym, n: PNode; g: ModuleGraph): PNode =
of nkHiddenStdConv, nkHiddenSubConv, nkConv: of nkHiddenStdConv, nkHiddenSubConv, nkConv:
var a = getConstExpr(m, n.sons[1], g) var a = getConstExpr(m, n.sons[1], g)
if a == nil: return if a == nil: return
# XXX: we should enable `check` for other conversion types too result = foldConv(n, a, g, check=true)
result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv)
of nkCast: of nkCast:
var a = getConstExpr(m, n.sons[1], g) var a = getConstExpr(m, n.sons[1], g)
if a == nil: return if a == nil: return

View file

@ -186,7 +186,9 @@ proc semOrd(c: PContext, n: PNode): PNode =
if isOrdinalType(parType, allowEnumWithHoles=true): if isOrdinalType(parType, allowEnumWithHoles=true):
discard discard
elif parType.kind == tySet: 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: else:
localError(c.config, n.info, errOrdinalTypeExpected) localError(c.config, n.info, errOrdinalTypeExpected)
result.typ = errorType(c) result.typ = errorType(c)
@ -273,7 +275,7 @@ proc semDynamicBindSym(c: PContext, n: PNode): PNode =
# executed like 'normal' VM callback # executed like 'normal' VM callback
idx = vm.registerCallback("bindSymImpl", bindSymWrapper) idx = vm.registerCallback("bindSymImpl", bindSymWrapper)
# dummy node to carry idx information to VM # 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) result = copyNode(n)
for x in n: result.add x for x in n: result.add x

View file

@ -100,7 +100,7 @@ proc allPossibleValues(c: PContext, t: PType): IntSet =
for field in t.n.sons: for field in t.n.sons:
result.incl(field.sym.position) result.incl(field.sym.position)
else: 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) result.incl(i.int)
proc branchVals(c: PContext, caseNode: PNode, caseIdx: int, proc branchVals(c: PContext, caseNode: PNode, caseIdx: int,

View file

@ -69,7 +69,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
base = semTypeNode(c, n.sons[0].sons[0], nil) base = semTypeNode(c, n.sons[0].sons[0], nil)
if base.kind != tyEnum: if base.kind != tyEnum:
localError(c.config, n.sons[0].info, "inheritance only works with an enum") 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) rawAddSon(result, base)
let isPure = result.sym != nil and sfPure in result.sym.flags let isPure = result.sym != nil and sfPure in result.sym.flags
var symbols: TStrTable 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 skipTypes(strVal.typ, abstractInst).kind in {tyString, tyCString}:
if not isOrdinalType(v.sons[0].typ, allowEnumWithHoles=true): if not isOrdinalType(v.sons[0].typ, allowEnumWithHoles=true):
localError(c.config, v.sons[0].info, errOrdinalTypeExpected & "; given: " & typeToString(v.sons[0].typ, preferDesc)) 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: else:
localError(c.config, strVal.info, errStringLiteralExpected) localError(c.config, strVal.info, errStringLiteralExpected)
else: else:
@ -104,7 +104,7 @@ proc semEnum(c: PContext, n: PNode, prev: PType): PType =
else: else:
if not isOrdinalType(v.typ, allowEnumWithHoles=true): if not isOrdinalType(v.typ, allowEnumWithHoles=true):
localError(c.config, v.info, errOrdinalTypeExpected & "; given: " & typeToString(v.typ, preferDesc)) localError(c.config, v.info, errOrdinalTypeExpected & "; given: " & typeToString(v.typ, preferDesc))
x = getOrdValue(v) x = toInt64(getOrdValue(v))
if i != 1: if i != 1:
if x != counter: incl(result.flags, tfEnumHasHoles) if x != counter: incl(result.flags, tfEnumHasHoles)
if x < counter: if x < counter:
@ -507,7 +507,7 @@ proc semBranchRange(c: PContext, t, a, b: PNode, covered: var Int128): PNode =
result.add(at) result.add(at)
result.add(bt) result.add(bt)
if emptyRange(ac, bc): localError(c.config, b.info, "range is empty") 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, proc semCaseBranchRange(c: PContext, t, b: PNode,
covered: var Int128): PNode = covered: var Int128): PNode =
@ -582,7 +582,7 @@ proc toCover(c: PContext, t: PType): Int128 =
elif t.kind in {tyInt, tyUInt}: elif t.kind in {tyInt, tyUInt}:
result = toInt128(1) shl (c.config.target.intSize * 8) result = toInt128(1) shl (c.config.target.intSize * 8)
else: else:
result = toInt128(lengthOrd(c.config, t)) result = lengthOrd(c.config, t)
proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int, proc semRecordNodeAux(c: PContext, n: PNode, check: var IntSet, pos: var int,
father: PNode, rectype: PType, hasCaseFields = false) father: PNode, rectype: PType, hasCaseFields = false)

View file

@ -377,8 +377,8 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
if k == f.kind: result = isSubrange if k == f.kind: result = isSubrange
elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64, elif k == tyInt and f.kind in {tyRange, tyInt8..tyInt64,
tyUInt..tyUInt64} and tyUInt..tyUInt64} and
isIntLit(ab) and ab.n.intVal >= firstOrd(nil, f) and isIntLit(ab) and getInt(ab.n) >= firstOrd(nil, f) and
ab.n.intVal <= lastOrd(nil, f): getInt(ab.n) <= lastOrd(nil, f):
# passing 'nil' to firstOrd/lastOrd here as type checking rules should # passing 'nil' to firstOrd/lastOrd here as type checking rules should
# not depent on the target integer size configurations! # not depent on the target integer size configurations!
# integer literal in the proper range; we want ``i16 + 4`` to stay an # integer literal in the proper range; we want ``i16 + 4`` to stay an
@ -902,10 +902,10 @@ proc inferStaticsInRange(c: var TCandidate,
allowUnresolved = true) allowUnresolved = true)
let upperBound = tryResolvingStaticExpr(c, inferred.n[1], let upperBound = tryResolvingStaticExpr(c, inferred.n[1],
allowUnresolved = true) allowUnresolved = true)
template doInferStatic(e: PNode, r: BiggestInt) = template doInferStatic(e: PNode, r: Int128) =
var exp = e var exp = e
var rhs = r var rhs = r
if inferStaticParam(c, exp, rhs): if inferStaticParam(c, exp, toInt64(rhs)):
return isGeneric return isGeneric
else: else:
failureToInferStaticParam(c.c.config, exp) failureToInferStaticParam(c.c.config, exp)
@ -918,7 +918,7 @@ proc inferStaticsInRange(c: var TCandidate,
return isNone return isNone
doInferStatic(upperBound, lengthOrd(c.c.config, concrete) + lowerBound.intVal - 1) doInferStatic(upperBound, lengthOrd(c.c.config, concrete) + lowerBound.intVal - 1)
elif upperBound.kind == nkIntLit: 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() = template subtypeCheck() =
if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in { if result <= isSubrange and f.lastSon.skipTypes(abstractInst).kind in {

View file

@ -332,7 +332,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
typ.size = elemSize typ.size = elemSize
typ.align = int16(elemSize) typ.align = int16(elemSize)
else: 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 typ.align = typ.sons[1].align
of tyUncheckedArray: of tyUncheckedArray:
@ -341,11 +341,11 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
typ.size = 0 typ.size = 0
typ.align = base.align typ.align = base.align
of tyEnum: of tyEnum:
if firstOrd(conf, typ) < 0: if firstOrd(conf, typ) < Zero:
typ.size = 4 # use signed int32 typ.size = 4 # use signed int32
typ.align = 4 typ.align = 4
else: else:
length = lastOrd(conf, typ) # BUGFIX: use lastOrd! length = toInt64(lastOrd(conf, typ)) # BUGFIX: use lastOrd!
if length + 1 < `shl`(1, 8): if length + 1 < `shl`(1, 8):
typ.size = 1 typ.size = 1
typ.align = 1 typ.align = 1
@ -363,7 +363,7 @@ proc computeSizeAlign(conf: ConfigRef; typ: PType) =
typ.size = szUncomputedSize typ.size = szUncomputedSize
typ.align = szUncomputedSize # in original version this was 1 typ.align = szUncomputedSize # in original version this was 1
else: else:
length = lengthOrd(conf, typ.sons[0]) length = toInt64(lengthOrd(conf, typ.sons[0]))
if length <= 8: if length <= 8:
typ.size = 1 typ.size = 1
elif length <= 16: elif length <= 16:

View file

@ -489,8 +489,8 @@ proc transformConv(c: PTransf, n: PNode): PTransNode =
result = newTransNode(nkChckRange, n, 3) result = newTransNode(nkChckRange, n, 3)
dest = skipTypes(n.typ, abstractVar) dest = skipTypes(n.typ, abstractVar)
result[0] = transform(c, n.sons[1]) result[0] = transform(c, n.sons[1])
result[1] = newIntTypeNode(nkIntLit, firstOrd(c.graph.config, dest), dest).PTransNode result[1] = newIntTypeNode(firstOrd(c.graph.config, dest), dest).PTransNode
result[2] = newIntTypeNode(nkIntLit, lastOrd(c.graph.config, dest), dest).PTransNode result[2] = newIntTypeNode(lastOrd(c.graph.config, dest), dest).PTransNode
of tyFloat..tyFloat128: of tyFloat..tyFloat128:
# XXX int64 -> float conversion? # XXX int64 -> float conversion?
if skipTypes(n.typ, abstractVar).kind == tyRange: if skipTypes(n.typ, abstractVar).kind == tyRange:

View file

@ -11,7 +11,7 @@
import import
intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options, intsets, ast, astalgo, trees, msgs, strutils, platform, renderer, options,
lineinfos lineinfos, int128
type type
TPreferedDesc* = enum TPreferedDesc* = enum
@ -77,12 +77,35 @@ proc isPureObject*(typ: PType): bool =
t = t.sons[0].skipTypes(skipPtrs) t = t.sons[0].skipTypes(skipPtrs)
result = t.sym != nil and sfPure in t.sym.flags 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 case n.kind
of nkCharLit..nkUInt64Lit: n.intVal of nkCharLit..nkUInt64Lit: n.intVal
of nkNilLit: 0 of nkNilLit: 0
of nkHiddenStdConv: getOrdValue(n.sons[1], onError) of nkHiddenStdConv: getOrdValue64(n.sons[1])
else: onError else: high(BiggestInt)
proc getFloatValue*(n: PNode): BiggestFloat = proc getFloatValue*(n: PNode): BiggestFloat =
case n.kind case n.kind
@ -629,10 +652,10 @@ proc typeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
result = typeToStr[t.kind] result = typeToStr[t.kind]
result.addTypeFlags(t) result.addTypeFlags(t)
proc firstOrd*(conf: ConfigRef; t: PType): BiggestInt = proc firstOrd*(conf: ConfigRef; t: PType): Int128 =
case t.kind case t.kind
of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy: of tyBool, tyChar, tySequence, tyOpenArray, tyString, tyVarargs, tyProxy:
result = 0 result = Zero
of tySet, tyVar: result = firstOrd(conf, t.sons[0]) of tySet, tyVar: result = firstOrd(conf, t.sons[0])
of tyArray: result = firstOrd(conf, t.sons[0]) of tyArray: result = firstOrd(conf, t.sons[0])
of tyRange: of tyRange:
@ -640,20 +663,22 @@ proc firstOrd*(conf: ConfigRef; t: PType): BiggestInt =
assert(t.n.kind == nkRange) assert(t.n.kind == nkRange)
result = getOrdValue(t.n.sons[0]) result = getOrdValue(t.n.sons[0])
of tyInt: of tyInt:
if conf != nil and conf.target.intSize == 4: result = - (2147483646) - 2 if conf != nil and conf.target.intSize == 4:
else: result = 0x8000000000000000'i64 result = toInt128(-2147483648)
of tyInt8: result = - 128 else:
of tyInt16: result = - 32768 result = toInt128(0x8000000000000000'i64)
of tyInt32: result = - 2147483646 - 2 of tyInt8: result = toInt128(-128)
of tyInt64: result = 0x8000000000000000'i64 of tyInt16: result = toInt128(-32768)
of tyUInt..tyUInt64: result = 0 of tyInt32: result = toInt128(-2147483648)
of tyInt64: result = toInt128(0x8000000000000000'i64)
of tyUInt..tyUInt64: result = Zero
of tyEnum: of tyEnum:
# if basetype <> nil then return firstOrd of basetype # if basetype <> nil then return firstOrd of basetype
if sonsLen(t) > 0 and t.sons[0] != nil: if sonsLen(t) > 0 and t.sons[0] != nil:
result = firstOrd(conf, t.sons[0]) result = firstOrd(conf, t.sons[0])
else: else:
assert(t.n.sons[0].kind == nkSym) 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, of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
tyStatic, tyInferred, tyUserTypeClasses: tyStatic, tyInferred, tyUserTypeClasses:
result = firstOrd(conf, lastSon(t)) 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)) if t.len > 0: result = firstOrd(conf, lastSon(t))
else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') else: internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
of tyUncheckedArray: of tyUncheckedArray:
result = 0 result = Zero
else: else:
internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')') internalError(conf, "invalid kind for firstOrd(" & $t.kind & ')')
result = 0 result = Zero
proc firstFloat*(t: PType): BiggestFloat = proc firstFloat*(t: PType): BiggestFloat =
case t.kind case t.kind
@ -682,10 +706,10 @@ proc firstFloat*(t: PType): BiggestFloat =
internalError(newPartialConfigRef(), "invalid kind for firstFloat(" & $t.kind & ')') internalError(newPartialConfigRef(), "invalid kind for firstFloat(" & $t.kind & ')')
NaN NaN
proc lastOrd*(conf: ConfigRef; t: PType; fixedUnsigned = false): BiggestInt = proc lastOrd*(conf: ConfigRef; t: PType): Int128 =
case t.kind case t.kind
of tyBool: result = 1 of tyBool: result = toInt128(1'u)
of tyChar: result = 255 of tyChar: result = toInt128(255'u)
of tySet, tyVar: result = lastOrd(conf, t.sons[0]) of tySet, tyVar: result = lastOrd(conf, t.sons[0])
of tyArray: result = lastOrd(conf, t.sons[0]) of tyArray: result = lastOrd(conf, t.sons[0])
of tyRange: of tyRange:
@ -693,38 +717,37 @@ proc lastOrd*(conf: ConfigRef; t: PType; fixedUnsigned = false): BiggestInt =
assert(t.n.kind == nkRange) assert(t.n.kind == nkRange)
result = getOrdValue(t.n.sons[1]) result = getOrdValue(t.n.sons[1])
of tyInt: of tyInt:
if conf != nil and conf.target.intSize == 4: result = 0x7FFFFFFF if conf != nil and conf.target.intSize == 4: result = toInt128(0x7FFFFFFF)
else: result = 0x7FFFFFFFFFFFFFFF'i64 else: result = toInt128(0x7FFFFFFFFFFFFFFF'u64)
of tyInt8: result = 0x0000007F of tyInt8: result = toInt128(0x0000007F)
of tyInt16: result = 0x00007FFF of tyInt16: result = toInt128(0x00007FFF)
of tyInt32: result = 0x7FFFFFFF of tyInt32: result = toInt128(0x7FFFFFFF)
of tyInt64: result = 0x7FFFFFFFFFFFFFFF'i64 of tyInt64: result = toInt128(0x7FFFFFFFFFFFFFFF'u64)
of tyUInt: of tyUInt:
if conf != nil and conf.target.intSize == 4: result = 0xFFFFFFFF if conf != nil and conf.target.intSize == 4:
elif fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64 result = toInt128(0xFFFFFFFF)
else: result = 0x7FFFFFFFFFFFFFFF'i64 else:
of tyUInt8: result = 0xFF result = toInt128(0xFFFFFFFFFFFFFFFF'u64)
of tyUInt16: result = 0xFFFF of tyUInt8: result = toInt128(0xFF)
of tyUInt32: result = 0xFFFFFFFF of tyUInt16: result = toInt128(0xFFFF)
of tyUInt32: result = toInt128(0xFFFFFFFF)
of tyUInt64: of tyUInt64:
if fixedUnsigned: result = 0xFFFFFFFFFFFFFFFF'i64 result = toInt128(0xFFFFFFFFFFFFFFFF'u64)
else: result = 0x7FFFFFFFFFFFFFFF'i64
of tyEnum: of tyEnum:
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym) 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, of tyGenericInst, tyDistinct, tyTypeDesc, tyAlias, tySink,
tyStatic, tyInferred, tyUserTypeClasses: tyStatic, tyInferred, tyUserTypeClasses:
result = lastOrd(conf, lastSon(t)) result = lastOrd(conf, lastSon(t))
of tyProxy: result = 0 of tyProxy: result = Zero
of tyOrdinal: of tyOrdinal:
if t.len > 0: result = lastOrd(conf, lastSon(t)) if t.len > 0: result = lastOrd(conf, lastSon(t))
else: internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')') else: internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
of tyUncheckedArray: of tyUncheckedArray:
result = high(BiggestInt) result = Zero
else: else:
internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')') internalError(conf, "invalid kind for lastOrd(" & $t.kind & ')')
result = 0 result = Zero
proc lastFloat*(t: PType): BiggestFloat = proc lastFloat*(t: PType): BiggestFloat =
case t.kind case t.kind
@ -758,7 +781,7 @@ proc floatRangeCheck*(x: BiggestFloat, t: PType): bool =
internalError(newPartialConfigRef(), "invalid kind for floatRangeCheck:" & $t.kind) internalError(newPartialConfigRef(), "invalid kind for floatRangeCheck:" & $t.kind)
false false
proc lengthOrd*(conf: ConfigRef; t: PType): BiggestInt = proc lengthOrd*(conf: ConfigRef; t: PType): Int128 =
case t.skipTypes(tyUserTypeClasses).kind case t.skipTypes(tyUserTypeClasses).kind
of tyInt64, tyInt32, tyInt: of tyInt64, tyInt32, tyInt:
# XXX: this is just wrong # XXX: this is just wrong
@ -767,11 +790,7 @@ proc lengthOrd*(conf: ConfigRef; t: PType): BiggestInt =
else: else:
let last = lastOrd(conf, t) let last = lastOrd(conf, t)
let first = firstOrd(conf, t) let first = firstOrd(conf, t)
# XXX use a better overflow check here: result = last - first + One
if last == high(BiggestInt) and first <= 0:
result = last
else:
result = last - first + 1
# -------------- type equality ----------------------------------------------- # -------------- type equality -----------------------------------------------

View file

@ -16,7 +16,7 @@ import
strutils, msgs, vmdef, vmgen, nimsets, types, passes, strutils, msgs, vmdef, vmgen, nimsets, types, passes,
parser, vmdeps, idents, trees, renderer, options, transf, parseutils, parser, vmdeps, idents, trees, renderer, options, transf, parseutils,
vmmarshal, gorgeimpl, lineinfos, tables, btrees, macrocacheimpl, vmmarshal, gorgeimpl, lineinfos, tables, btrees, macrocacheimpl,
modulegraphs, sighashes modulegraphs, sighashes, int128
from semfold import leValueConv, ordinalValToString from semfold import leValueConv, ordinalValToString
from evaltempl import evalTemplate 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) dest.intVal = int(src.floatVal)
else: else:
dest.intVal = src.intVal 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 return true
of tyUInt..tyUInt64: of tyUInt..tyUInt64:
if dest.kind != rkInt: if dest.kind != rkInt:
@ -1312,7 +1312,7 @@ proc rawExecute(c: PCtx, start: int, tos: PStackFrame): TFullReg =
of opcQuit: of opcQuit:
if c.mode in {emRepl, emStaticExpr, emStaticStmt}: if c.mode in {emRepl, emStaticExpr, emStaticStmt}:
message(c.config, c.debug[pc], hintQuitCalled) message(c.config, c.debug[pc], hintQuitCalled)
msgQuit(int8(getOrdValue(regs[ra].regToNode))) msgQuit(int8(toInt(getOrdValue(regs[ra].regToNode))))
else: else:
return TFullReg(kind: rkNone) return TFullReg(kind: rkNone)
of opcSetLenStr: of opcSetLenStr:

View file

@ -596,12 +596,12 @@ proc genField(c: PCtx; n: PNode): TRegister =
proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister = proc genIndex(c: PCtx; n: PNode; arr: PType): TRegister =
if arr.skipTypes(abstractInst).kind == tyArray and (let x = firstOrd(c.config, arr); if arr.skipTypes(abstractInst).kind == tyArray and (let x = firstOrd(c.config, arr);
x != 0): x != Zero):
let tmp = c.genx(n) let tmp = c.genx(n)
# freeing the temporary here means we can produce: regA = regA - Imm # freeing the temporary here means we can produce: regA = regA - Imm
c.freeTemp(tmp) c.freeTemp(tmp)
result = c.getTemp(n.typ) result = c.getTemp(n.typ)
c.gABI(n, opcSubImmInt, result, tmp, x.int) c.gABI(n, opcSubImmInt, result, tmp, toInt(x))
else: else:
result = c.genx(n) result = c.genx(n)
@ -1767,7 +1767,7 @@ proc getNullValue(typ: PType, info: TLineInfo; conf: ConfigRef): PNode =
getNullValueAux(t, t.n, result, conf, currPosition) getNullValueAux(t, t.n, result, conf, currPosition)
of tyArray: of tyArray:
result = newNodeIT(nkBracket, info, t) 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)) addSon(result, getNullValue(elemType(t), info, conf))
of tyTuple: of tyTuple:
result = newNodeIT(nkTupleConstr, info, t) result = newNodeIT(nkTupleConstr, info, t)

View file

@ -122,7 +122,7 @@ proc hash*(x: int): Hash {.inline.} =
proc hash*(x: int64): Hash {.inline.} = proc hash*(x: int64): Hash {.inline.} =
## Efficient hashing of `int64` integers. ## Efficient hashing of `int64` integers.
result = toU32(x) result = cast[int](x)
proc hash*(x: uint): Hash {.inline.} = proc hash*(x: uint): Hash {.inline.} =
## Efficient hashing of unsigned integers. ## Efficient hashing of unsigned integers.
@ -130,7 +130,7 @@ proc hash*(x: uint): Hash {.inline.} =
proc hash*(x: uint64): Hash {.inline.} = proc hash*(x: uint64): Hash {.inline.} =
## Efficient hashing of `uint64` integers. ## Efficient hashing of `uint64` integers.
result = toU32(cast[int](x)) result = cast[int](x)
proc hash*(x: char): Hash {.inline.} = proc hash*(x: char): Hash {.inline.} =
## Efficient hashing of characters. ## Efficient hashing of characters.

View file

@ -29,6 +29,7 @@ block tcast:
let rt = ty(exp) let rt = ty(exp)
const ct = ty(exp) const ct = ty(exp)
if $rt != $ct: if $rt != $ct:
echo astToStr(exp)
echo "Got ", ct echo "Got ", ct
echo "Expected ", rt echo "Expected ", rt
@ -52,7 +53,7 @@ block tcast:
crossCheck(uint8, uint8.high + 5'u8) crossCheck(uint8, uint8.high + 5'u8)
crossCheck(uint16, uint16.high + 5'u16) crossCheck(uint16, uint16.high + 5'u16)
crossCheck(uint32, uint32.high + 5'u32) crossCheck(uint32, uint32.high + 5'u32)
crossCheck(uint64, (-1).uint64 + 5'u64) crossCheck(uint64, 0xFFFFFFFFFFFFFFFF'u64 + 5'u64)
doAssert $sub1(0'u8) == "255" doAssert $sub1(0'u8) == "255"
doAssert $sub1(0'u16) == "65535" doAssert $sub1(0'u16) == "65535"
@ -69,12 +70,10 @@ block tcast:
crossCheck(int64, high(int8).int16.int32.int64) crossCheck(int64, high(int8).int16.int32.int64)
crossCheck(int64, low(int8).int16.int32.int64) crossCheck(int64, low(int8).int16.int32.int64)
crossCheck(int64, 0xFFFFFFFFFFFFFFFF'u64) doAssert not compiles(echo int64(0xFFFFFFFFFFFFFFFF'u64))
crossCheck(int32, 0xFFFFFFFFFFFFFFFF'u64) doAssert not compiles(echo int32(0xFFFFFFFFFFFFFFFF'u64))
crossCheck(int16, 0xFFFFFFFFFFFFFFFF'u64) doAssert not compiles(echo int16(0xFFFFFFFFFFFFFFFF'u64))
crossCheck(int8 , 0xFFFFFFFFFFFFFFFF'u64) doAssert not compiles(echo int8(0xFFFFFFFFFFFFFFFF'u64))
block tnot: block tnot:
# Signed types # Signed types
@ -116,32 +115,6 @@ block tnot:
doAssert t7 == 4 doAssert t7 == 4
block tshl:
# Signed types
block:
const t0: int8 = 1'i8 shl 8
const t1: int16 = 1'i16 shl 16
const t2: int32 = 1'i32 shl 32
const t3: int64 = 1'i64 shl 64
doAssert t0 == 0
doAssert t1 == 0
doAssert t2 == 1
doAssert t3 == 1
# Unsigned types
block:
const t0: uint8 = 1'u8 shl 8
const t1: uint16 = 1'u16 shl 16
const t2: uint32 = 1'u32 shl 32
const t3: uint64 = 1'u64 shl 64
doAssert t0 == 0
doAssert t1 == 0
doAssert t2 == 0
doAssert t3 == 1
block tshr: block tshr:
proc T() = proc T() =
# let VI = -8 # let VI = -8

View file

@ -122,8 +122,13 @@ let expLines = splitLines(expected.strip)
if resLines.len != expLines.len: if resLines.len != expLines.len:
echo("Not matched! Wrong number of lines!") echo("Not matched! Wrong number of lines!")
echo() echo expLines.len
echo(result) echo resLines.len
echo("Expected: -----------")
echo expected
echo("Gotten: -------------")
echo result
echo("---------------------")
quit(QuitFailure) quit(QuitFailure)
var ok = true var ok = true

View file

@ -24,4 +24,4 @@ doAssertRaises(OverflowError): discard high(int64) * 2
doAssert abs(-1) == 1 doAssert abs(-1) == 1
doAssert 2 div 2 == 1 doAssert 2 div 2 == 1
doAssert 2 * 3 == 6 doAssert 2 * 3 == 6

View file

@ -5,7 +5,7 @@ discard """
static: static:
proc p = proc p =
var var
x = 1 shl 62 x = 1'i64 shl 62
discard x * 2 discard x * 2
assert false assert false
p() p()