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
parent 8407a57499
commit afbcd1b330
34 changed files with 530 additions and 314 deletions

View File

@@ -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..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:
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

View File

@@ -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:

View File

@@ -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",

View File

@@ -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 =

View File

@@ -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)])

View File

@@ -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)

View File

@@ -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

View File

@@ -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,

View File

@@ -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

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
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)

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) =
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:

View File

@@ -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

View File

@@ -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

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)
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),

View File

@@ -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)

View File

@@ -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)

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)
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):

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -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

View File

@@ -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,

View File

@@ -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)

View File

@@ -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 {

View File

@@ -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:

View File

@@ -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:

View File

@@ -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 -----------------------------------------------

View File

@@ -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:

View File

@@ -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)

View File

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

View File

@@ -29,6 +29,7 @@ block tcast:
let rt = ty(exp)
const ct = ty(exp)
if $rt != $ct:
echo astToStr(exp)
echo "Got ", ct
echo "Expected ", rt
@@ -52,7 +53,7 @@ block tcast:
crossCheck(uint8, uint8.high + 5'u8)
crossCheck(uint16, uint16.high + 5'u16)
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'u16) == "65535"
@@ -69,12 +70,10 @@ block tcast:
crossCheck(int64, high(int8).int16.int32.int64)
crossCheck(int64, low(int8).int16.int32.int64)
crossCheck(int64, 0xFFFFFFFFFFFFFFFF'u64)
crossCheck(int32, 0xFFFFFFFFFFFFFFFF'u64)
crossCheck(int16, 0xFFFFFFFFFFFFFFFF'u64)
crossCheck(int8 , 0xFFFFFFFFFFFFFFFF'u64)
doAssert not compiles(echo int64(0xFFFFFFFFFFFFFFFF'u64))
doAssert not compiles(echo int32(0xFFFFFFFFFFFFFFFF'u64))
doAssert not compiles(echo int16(0xFFFFFFFFFFFFFFFF'u64))
doAssert not compiles(echo int8(0xFFFFFFFFFFFFFFFF'u64))
block tnot:
# Signed types
@@ -116,32 +115,6 @@ block tnot:
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:
proc T() =
# let VI = -8

View File

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

View File

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

View File

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