changed integer promotion rules; breaks bootstrapping and lots of code
This commit is contained in:
parent
36247e0947
commit
4fbba0a65a
42 changed files with 643 additions and 261 deletions
|
|
@ -224,7 +224,8 @@ type
|
|||
sfMainModule, # module is the main module
|
||||
sfSystemModule, # module is the system module
|
||||
sfNoReturn, # proc never returns (an exit proc)
|
||||
sfAddrTaken, # the variable's address is taken (ex- or implicitely)
|
||||
sfAddrTaken, # the variable's address is taken (ex- or implicitely);
|
||||
# *OR*: a proc is indirectly called (used as first class)
|
||||
sfCompilerProc, # proc is a compiler proc, that is a C proc that is
|
||||
# needed for the code generator
|
||||
sfProcvar, # proc can be passed to a proc var
|
||||
|
|
|
|||
|
|
@ -1037,8 +1037,9 @@ proc genRepr(p: BProc, e: PNode, d: var TLoc) =
|
|||
InitLocExpr(p, e.sons[1], a)
|
||||
var t = skipTypes(e.sons[1].typ, abstractVarRange)
|
||||
case t.kind
|
||||
of tyInt..tyInt64:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprInt($1)", [rdLoc(a)]))
|
||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
||||
putIntoDest(p, d, e.typ,
|
||||
ropecg(p.module, "#reprInt((NI64)$1)", [rdLoc(a)]))
|
||||
of tyFloat..tyFloat128:
|
||||
putIntoDest(p, d, e.typ, ropecg(p.module, "#reprFloat($1)", [rdLoc(a)]))
|
||||
of tyBool:
|
||||
|
|
|
|||
|
|
@ -1066,7 +1066,8 @@ proc createVar(p: var TProc, typ: PType, indirect: bool): PRope =
|
|||
result = nil
|
||||
|
||||
proc isIndirect(v: PSym): bool =
|
||||
result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject)
|
||||
result = (sfAddrTaken in v.flags) and (mapType(v.typ) != etyObject) and
|
||||
v.kind notin {skProc, skConverter, skMethod, skIterator}
|
||||
|
||||
proc genVarInit(p: var TProc, v: PSym, n: PNode, r: var TCompRes) =
|
||||
var
|
||||
|
|
|
|||
|
|
@ -74,24 +74,51 @@ proc getSysType(kind: TTypeKind): PType =
|
|||
InternalError("wanted: " & $kind & " got: " & $result.kind)
|
||||
if result == nil: InternalError("type not found: " & $kind)
|
||||
|
||||
when false:
|
||||
var
|
||||
intTypeCache: array[-5..64, PType]
|
||||
var
|
||||
intTypeCache: array[-5..64, PType]
|
||||
|
||||
proc getIntLitType*(literal: PNode): PType =
|
||||
# we cache some common integer literal types for performance:
|
||||
let value = literal.intVal
|
||||
if value >= low(intTypeCache) and value <= high(intTypeCache):
|
||||
result = intTypeCache[value.int]
|
||||
if result == nil:
|
||||
let ti = getSysType(tyInt)
|
||||
result = copyType(ti, ti.owner, false)
|
||||
result.n = literal
|
||||
intTypeCache[value.int] = result
|
||||
else:
|
||||
proc getIntLitType*(literal: PNode): PType =
|
||||
# we cache some common integer literal types for performance:
|
||||
let value = literal.intVal
|
||||
if value >= low(intTypeCache) and value <= high(intTypeCache):
|
||||
result = intTypeCache[value.int]
|
||||
if result == nil:
|
||||
let ti = getSysType(tyInt)
|
||||
result = copyType(ti, ti.owner, false)
|
||||
result.n = literal
|
||||
intTypeCache[value.int] = result
|
||||
else:
|
||||
let ti = getSysType(tyInt)
|
||||
result = copyType(ti, ti.owner, false)
|
||||
result.n = literal
|
||||
|
||||
proc setIntLitType*(result: PNode) =
|
||||
let i = result.intVal
|
||||
case platform.IntSize
|
||||
of 8: result.typ = getIntLitType(result)
|
||||
of 4:
|
||||
if i >= low(int32) and i <= high(int32):
|
||||
result.typ = getIntLitType(result)
|
||||
else:
|
||||
result.typ = getSysType(tyInt64)
|
||||
of 2:
|
||||
if i >= low(int16) and i <= high(int16):
|
||||
result.typ = getIntLitType(result)
|
||||
elif i >= low(int32) and i <= high(int32):
|
||||
result.typ = getSysType(tyInt32)
|
||||
else:
|
||||
result.typ = getSysType(tyInt64)
|
||||
of 1:
|
||||
# 8 bit CPUs are insane ...
|
||||
if i >= low(int8) and i <= high(int8):
|
||||
result.typ = getIntLitType(result)
|
||||
elif i >= low(int16) and i <= high(int16):
|
||||
result.typ = getSysType(tyInt16)
|
||||
elif i >= low(int32) and i <= high(int32):
|
||||
result.typ = getSysType(tyInt32)
|
||||
else:
|
||||
result.typ = getSysType(tyInt64)
|
||||
else: InternalError(result.info, "invalid int size")
|
||||
|
||||
proc getCompilerProc(name: string): PSym =
|
||||
var ident = getIdent(name, hashIgnoreStyle(name))
|
||||
|
|
|
|||
79
compiler/saturate.nim
Normal file
79
compiler/saturate.nim
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
#
|
||||
#
|
||||
# The Nimrod Compiler
|
||||
# (c) Copyright 2012 Andreas Rumpf
|
||||
#
|
||||
# See the file "copying.txt", included in this
|
||||
# distribution, for details about the copyright.
|
||||
#
|
||||
|
||||
## Saturated arithmetic routines. XXX Make part of the stdlib?
|
||||
|
||||
proc `|+|`*(a, b: biggestInt): biggestInt =
|
||||
## saturated addition.
|
||||
result = a +% b
|
||||
if (result xor a) >= 0'i64 or (result xor b) >= 0'i64:
|
||||
return result
|
||||
if a < 0 or b < 0:
|
||||
result = low(result)
|
||||
else:
|
||||
result = high(result)
|
||||
|
||||
proc `|-|`*(a, b: biggestInt): biggestInt =
|
||||
result = a -% b
|
||||
if (result xor a) >= 0'i64 or (result xor not b) >= 0'i64:
|
||||
return result
|
||||
if b > 0:
|
||||
result = low(result)
|
||||
else:
|
||||
result = high(result)
|
||||
|
||||
proc `|abs|`*(a: biggestInt): biggestInt =
|
||||
if a != low(a):
|
||||
if a >= 0: result = a
|
||||
else: result = -a
|
||||
else:
|
||||
result = low(a)
|
||||
|
||||
proc `|div|`*(a, b: biggestInt): biggestInt =
|
||||
# (0..5) div (0..4) == (0..5) div (1..4) == (0 div 4) .. (5 div 1)
|
||||
if b == 0'i64:
|
||||
# make the same as ``div 1``:
|
||||
result = a
|
||||
elif a == low(a) and b == -1'i64:
|
||||
result = high(result)
|
||||
else:
|
||||
result = a div b
|
||||
|
||||
proc `|mod|`*(a, b: biggestInt): biggestInt =
|
||||
if b == 0'i64:
|
||||
result = a
|
||||
else:
|
||||
result = a mod b
|
||||
|
||||
proc `|*|`*(a, b: biggestInt): biggestInt =
|
||||
var
|
||||
resAsFloat, floatProd: float64
|
||||
result = a *% b
|
||||
floatProd = toBiggestFloat(a) # conversion
|
||||
floatProd = floatProd * toBiggestFloat(b)
|
||||
resAsFloat = toBiggestFloat(result)
|
||||
|
||||
# Fast path for normal case: small multiplicands, and no info
|
||||
# is lost in either method.
|
||||
if resAsFloat == floatProd: return result
|
||||
|
||||
# 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):
|
||||
return result
|
||||
|
||||
if floatProd >= 0.0:
|
||||
result = high(result)
|
||||
else:
|
||||
result = low(result)
|
||||
|
|
@ -18,8 +18,8 @@ proc sameMethodDispatcher(a, b: PSym): bool =
|
|||
if aa.kind == nkSym and bb.kind == nkSym and aa.sym == bb.sym:
|
||||
result = true
|
||||
|
||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
filter: TSymKinds): TCandidate =
|
||||
proc resolveOverloads(c: PContext, n, orig: PNode,
|
||||
filter: TSymKinds): TCandidate =
|
||||
var initialBinding: PNode
|
||||
var f = n.sons[0]
|
||||
if f.kind == nkBracketExpr:
|
||||
|
|
@ -67,9 +67,17 @@ proc resolveOverloads(c: PContext, n, orig: PNode,
|
|||
not sameMethodDispatcher(best.calleeSym, alt.calleeSym):
|
||||
if best.state != csMatch:
|
||||
InternalError(n.info, "x.state is not csMatch")
|
||||
#writeMatches(best)
|
||||
#writeMatches(alt)
|
||||
var args = "("
|
||||
for i in countup(1, sonsLen(n) - 1):
|
||||
if i > 1: add(args, ", ")
|
||||
add(args, typeToString(n.sons[i].typ))
|
||||
add(args, ")")
|
||||
|
||||
LocalError(n.Info, errGenerated, msgKindToString(errAmbiguousCallXYZ) % [
|
||||
getProcHeader(best.calleeSym), getProcHeader(alt.calleeSym),
|
||||
best.calleeSym.Name.s])
|
||||
args])
|
||||
|
||||
proc semResolvedCall(c: PContext, n: PNode, x: TCandidate): PNode =
|
||||
assert x.state == csMatch
|
||||
|
|
|
|||
|
|
@ -213,6 +213,11 @@ proc markUsed*(n: PNode, s: PSym) =
|
|||
if sfDeprecated in s.flags: Message(n.info, warnDeprecated, s.name.s)
|
||||
if sfError in s.flags: LocalError(n.info, errWrongSymbolX, s.name.s)
|
||||
|
||||
proc markIndirect*(c: PContext, s: PSym) =
|
||||
if s.kind in {skProc, skConverter, skMethod, skIterator}:
|
||||
incl(s.flags, sfAddrTaken)
|
||||
# XXX add to 'c' for global analysis
|
||||
|
||||
proc useSym*(sym: PSym): PNode =
|
||||
result = newSymNode(sym)
|
||||
markUsed(result, sym)
|
||||
|
|
|
|||
|
|
@ -74,8 +74,10 @@ proc semSym(c: PContext, n: PNode, s: PSym, flags: TExprFlags): PNode =
|
|||
smoduleId != c.module.id and smoduleId != c.friendModule.id:
|
||||
LocalError(n.info, errXCannotBePassedToProcVar, s.name.s)
|
||||
result = symChoice(c, n, s)
|
||||
if result.kind == nkSym and isGenericRoutine(result.sym):
|
||||
LocalError(n.info, errInstantiateXExplicitely, s.name.s)
|
||||
if result.kind == nkSym:
|
||||
markIndirect(c, result.sym)
|
||||
if isGenericRoutine(result.sym):
|
||||
LocalError(n.info, errInstantiateXExplicitely, s.name.s)
|
||||
of skConst:
|
||||
markUsed(n, s)
|
||||
case skipTypes(s.typ, abstractInst).kind
|
||||
|
|
@ -129,10 +131,11 @@ proc checkConversionBetweenObjects(info: TLineInfo, castDest, src: PType) =
|
|||
if diff == high(int):
|
||||
GlobalError(info, errGenerated, MsgKindToString(errIllegalConvFromXtoY) % [
|
||||
src.typeToString, castDest.typeToString])
|
||||
|
||||
|
||||
const
|
||||
IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
|
||||
|
||||
proc checkConvertible(info: TLineInfo, castDest, src: PType) =
|
||||
const
|
||||
IntegralTypes = {tyBool, tyEnum, tyChar, tyInt..tyUInt64}
|
||||
if sameType(castDest, src) and castDest.sym == src.sym:
|
||||
# don't annoy conversions that may be needed on another processor:
|
||||
if castDest.kind notin {tyInt..tyUInt64, tyNil}:
|
||||
|
|
@ -177,8 +180,8 @@ proc isCastable(dst, src: PType): bool =
|
|||
result = false
|
||||
else:
|
||||
result = (ds >= ss) or
|
||||
(skipTypes(dst, abstractInst).kind in {tyInt..tyFloat128}) or
|
||||
(skipTypes(src, abstractInst).kind in {tyInt..tyFloat128})
|
||||
(skipTypes(dst, abstractInst).kind in IntegralTypes) or
|
||||
(skipTypes(src, abstractInst).kind in IntegralTypes)
|
||||
|
||||
proc semConv(c: PContext, n: PNode, s: PSym): PNode =
|
||||
if sonsLen(n) != 2: GlobalError(n.info, errConvNeedsOneArg)
|
||||
|
|
@ -190,10 +193,12 @@ proc semConv(c: PContext, n: PNode, s: PSym): PNode =
|
|||
if op.kind != nkSymChoice:
|
||||
checkConvertible(result.info, result.typ, op.typ)
|
||||
else:
|
||||
for i in countup(0, sonsLen(op) - 1):
|
||||
if sameType(result.typ, op.sons[i].typ):
|
||||
markUsed(n, op.sons[i].sym)
|
||||
return op.sons[i]
|
||||
for i in countup(0, sonsLen(op) - 1):
|
||||
let it = op.sons[i]
|
||||
if sameType(result.typ, it.typ):
|
||||
markUsed(n, it.sym)
|
||||
markIndirect(c, it.sym)
|
||||
return it
|
||||
localError(n.info, errUseQualifier, op.sons[0].sym.name.s)
|
||||
|
||||
proc semCast(c: PContext, n: PNode): PNode =
|
||||
|
|
@ -222,7 +227,7 @@ proc semLowHigh(c: PContext, n: PNode, m: TMagic): PNode =
|
|||
n.typ = getSysType(tyInt)
|
||||
of tyArrayConstr, tyArray:
|
||||
n.typ = n.sons[1].typ.sons[0] # indextype
|
||||
of tyInt..tyInt64, tyChar, tyBool, tyEnum:
|
||||
of tyInt..tyInt64, tyChar, tyBool, tyEnum, tyUInt8, tyUInt16, tyUInt32:
|
||||
n.typ = n.sons[1].typ
|
||||
else: GlobalError(n.info, errInvalidArgForX, opToStr[m])
|
||||
result = n
|
||||
|
|
@ -498,6 +503,24 @@ proc evalAtCompileTime(c: PContext, n: PNode): PNode =
|
|||
if n.kind notin nkCallKinds or n.sons[0].kind != nkSym: return
|
||||
var callee = n.sons[0].sym
|
||||
|
||||
# constant folding that is necessary for correctness of semantic pass:
|
||||
if callee.magic != mNone and callee.magic in ctfeWhitelist and n.typ != nil:
|
||||
var call = newNodeIT(nkCall, n.info, n.typ)
|
||||
call.add(n.sons[0])
|
||||
var allConst = true
|
||||
for i in 1 .. < n.len:
|
||||
let a = getConstExpr(c.module, n.sons[i])
|
||||
if a != nil: call.add(a)
|
||||
else:
|
||||
allConst = false
|
||||
call.add(n.sons[i])
|
||||
if allConst:
|
||||
result = semfold.getConstExpr(c.module, call)
|
||||
if result.isNil: result = n
|
||||
else: return result
|
||||
result.typ = semfold.getIntervalType(callee.magic, call)
|
||||
|
||||
# optimization pass: not necessary for correctness of the semantic pass
|
||||
if {sfNoSideEffect, sfCompileTime} * callee.flags != {} and
|
||||
{sfForward, sfImportc} * callee.flags == {}:
|
||||
if sfCompileTime notin callee.flags and
|
||||
|
|
@ -901,7 +924,7 @@ proc semSubscript(c: PContext, n: PNode, flags: TExprFlags): PNode =
|
|||
if skipTypes(n.sons[1].typ, {tyGenericInst, tyRange, tyOrdinal}).kind in
|
||||
{tyInt..tyInt64}:
|
||||
var idx = getOrdValue(n.sons[1])
|
||||
if (idx >= 0) and (idx < sonsLen(arr)): n.typ = arr.sons[int(idx)]
|
||||
if idx >= 0 and idx < sonsLen(arr): n.typ = arr.sons[int(idx)]
|
||||
else: GlobalError(n.info, errInvalidIndexValueForTuple)
|
||||
else:
|
||||
GlobalError(n.info, errIndexTypesDoNotMatch)
|
||||
|
|
@ -1301,15 +1324,9 @@ proc semExpr(c: PContext, n: PNode, flags: TExprFlags = {}): PNode =
|
|||
nil
|
||||
of nkNilLit:
|
||||
result.typ = getSysType(tyNil)
|
||||
of nkIntLit:
|
||||
# XXX this is stupid:
|
||||
if result.typ == nil:
|
||||
let i = result.intVal
|
||||
if i >= low(int32) and i <= high(int32):
|
||||
result.typ = getSysType(tyInt)
|
||||
else:
|
||||
result.typ = getSysType(tyInt64)
|
||||
of nkInt8Lit:
|
||||
of nkIntLit:
|
||||
if result.typ == nil: setIntLitType(result)
|
||||
of nkInt8Lit:
|
||||
if result.typ == nil: result.typ = getSysType(tyInt8)
|
||||
of nkInt16Lit:
|
||||
if result.typ == nil: result.typ = getSysType(tyInt16)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@
|
|||
import
|
||||
strutils, lists, options, ast, astalgo, trees, treetab, nimsets, times,
|
||||
nversion, platform, math, msgs, os, condsyms, idents, renderer, types,
|
||||
commands, magicsys
|
||||
commands, magicsys, saturate
|
||||
|
||||
proc getConstExpr*(m: PSym, n: PNode): PNode
|
||||
# evaluates the constant expression or returns nil if it is no constant
|
||||
|
|
@ -26,12 +26,19 @@ proc newStrNodeT*(strVal: string, n: PNode): PNode
|
|||
|
||||
# implementation
|
||||
|
||||
proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
|
||||
if skipTypes(n.typ, abstractVarRange).kind == tyChar:
|
||||
result = newIntNode(nkCharLit, intVal)
|
||||
else:
|
||||
proc newIntNodeT(intVal: BiggestInt, n: PNode): PNode =
|
||||
case skipTypes(n.typ, abstractVarRange).kind
|
||||
of tyInt:
|
||||
result = newIntNode(nkIntLit, intVal)
|
||||
result.typ = n.typ
|
||||
result.typ = getIntLitType(result)
|
||||
# hrm, this is not correct: 1 + high(int) shouldn't produce tyInt64 ...
|
||||
#setIntLitType(result)
|
||||
of tyChar:
|
||||
result = newIntNode(nkCharLit, intVal)
|
||||
result.typ = n.typ
|
||||
else:
|
||||
result = newIntNode(nkIntLit, intVal)
|
||||
result.typ = n.typ
|
||||
result.info = n.info
|
||||
|
||||
proc newFloatNodeT(floatVal: BiggestFloat, n: PNode): PNode =
|
||||
|
|
@ -67,6 +74,150 @@ proc ordinalValToString(a: PNode): string =
|
|||
else:
|
||||
result = $x
|
||||
|
||||
proc isFloatRange(t: PType): bool {.inline.} =
|
||||
result = t.kind == tyRange and t.sons[0].kind in {tyFloat..tyFloat128}
|
||||
|
||||
proc isIntRange(t: PType): bool {.inline.} =
|
||||
result = t.kind == tyRange and t.sons[0].kind in {
|
||||
tyInt..tyInt64, tyUInt8..tyUInt32}
|
||||
|
||||
proc pickIntRange(a, b: PType): PType =
|
||||
if isIntRange(a): result = a
|
||||
elif isIntRange(b): result = b
|
||||
else: result = a
|
||||
|
||||
proc isIntRangeOrLit(t: PType): bool =
|
||||
result = isIntRange(t) or isIntLit(t)
|
||||
|
||||
proc pickMinInt(n: PNode): biggestInt =
|
||||
if n.kind in {nkIntLit..nkUInt64Lit}:
|
||||
result = n.intVal
|
||||
elif isIntLit(n.typ):
|
||||
result = n.typ.n.intVal
|
||||
elif isIntRange(n.typ):
|
||||
result = firstOrd(n.typ)
|
||||
else:
|
||||
InternalError(n.info, "pickMinInt")
|
||||
|
||||
proc pickMaxInt(n: PNode): biggestInt =
|
||||
if n.kind in {nkIntLit..nkUInt64Lit}:
|
||||
result = n.intVal
|
||||
elif isIntLit(n.typ):
|
||||
result = n.typ.n.intVal
|
||||
elif isIntRange(n.typ):
|
||||
result = lastOrd(n.typ)
|
||||
else:
|
||||
InternalError(n.info, "pickMaxInt")
|
||||
|
||||
proc makeRange(typ: PType, first, last: biggestInt): PType =
|
||||
var n = newNode(nkRange)
|
||||
addSon(n, newIntNode(nkIntLit, min(first, last)))
|
||||
addSon(n, newIntNode(nkIntLit, max(first, last)))
|
||||
result = newType(tyRange, typ.owner)
|
||||
result.n = n
|
||||
addSon(result, skipTypes(typ, {tyRange}))
|
||||
|
||||
proc makeRangeF(typ: PType, first, last: biggestFloat): PType =
|
||||
var n = newNode(nkRange)
|
||||
addSon(n, newFloatNode(nkFloatLit, min(first.float, last.float)))
|
||||
addSon(n, newFloatNode(nkFloatLit, max(first.float, last.float)))
|
||||
result = newType(tyRange, typ.owner)
|
||||
result.n = n
|
||||
addSon(result, skipTypes(typ, {tyRange}))
|
||||
|
||||
proc getIntervalType*(m: TMagic, n: PNode): PType =
|
||||
# Nimrod requires interval arithmetic for ``range`` types. Lots of tedious
|
||||
# work but the feature is very nice for reducing explicit conversions.
|
||||
result = n.typ
|
||||
|
||||
template commutativeOp(opr: expr) {.immediate.} =
|
||||
let a = n.sons[1]
|
||||
let b = n.sons[2]
|
||||
if isIntRangeOrLit(a.typ) and isIntRangeOrLit(b.typ):
|
||||
result = makeRange(pickIntRange(a.typ, b.typ),
|
||||
opr(pickMinInt(a), pickMinInt(b)),
|
||||
opr(pickMaxInt(a), pickMaxInt(b)))
|
||||
|
||||
template binaryOp(opr: expr) {.immediate.} =
|
||||
let a = n.sons[1]
|
||||
let b = n.sons[2]
|
||||
if isIntRange(a.typ) and b.kind in {nkIntLit..nkUInt64Lit}:
|
||||
result = makeRange(a.typ,
|
||||
opr(pickMinInt(a), pickMinInt(b)),
|
||||
opr(pickMaxInt(a), pickMaxInt(b)))
|
||||
|
||||
case m
|
||||
of mUnaryMinusI, mUnaryMinusI64:
|
||||
let a = n.sons[1].typ
|
||||
if isIntRange(a):
|
||||
# (1..3) * (-1) == (-3.. -1)
|
||||
result = makeRange(a, 0|-|lastOrd(a), 0|-|firstOrd(a))
|
||||
of mUnaryMinusF64:
|
||||
let a = n.sons[1].typ
|
||||
if isFloatRange(a):
|
||||
result = makeRangeF(a, -getFloat(a.n.sons[1]),
|
||||
-getFloat(a.n.sons[0]))
|
||||
of mAbsF64:
|
||||
let a = n.sons[1].typ
|
||||
if isFloatRange(a):
|
||||
# abs(-5.. 1) == (1..5)
|
||||
result = makeRangeF(a, abs(getFloat(a.n.sons[1])),
|
||||
abs(getFloat(a.n.sons[0])))
|
||||
of mAbsI, mAbsI64:
|
||||
let a = n.sons[1].typ
|
||||
if isIntRange(a):
|
||||
result = makeRange(a, `|abs|`(getInt(a.n.sons[1])),
|
||||
`|abs|`(getInt(a.n.sons[0])))
|
||||
of mSucc:
|
||||
let a = n.sons[1].typ
|
||||
let b = n.sons[2].typ
|
||||
if isIntRange(a) and isIntLit(b):
|
||||
# (-5.. 1) + 6 == (-5 + 6)..(-1 + 6)
|
||||
result = makeRange(a, pickMinInt(n.sons[1]) |+| pickMinInt(n.sons[2]),
|
||||
pickMaxInt(n.sons[1]) |+| pickMaxInt(n.sons[2]))
|
||||
of mPred:
|
||||
let a = n.sons[1].typ
|
||||
let b = n.sons[2].typ
|
||||
if isIntRange(a) and isIntLit(b):
|
||||
result = makeRange(a, pickMinInt(n.sons[1]) |-| pickMinInt(n.sons[2]),
|
||||
pickMaxInt(n.sons[1]) |-| pickMaxInt(n.sons[2]))
|
||||
of mAddI, mAddI64, mAddU, mAddU64:
|
||||
commutativeOp(`|+|`)
|
||||
of mMulI, mMulI64, mMulU, mMulU64:
|
||||
commutativeOp(`|*|`)
|
||||
of mSubI, mSubI64, mSubU, mSubU64:
|
||||
binaryOp(`|-|`)
|
||||
of mBitandI, mBitandI64:
|
||||
var a = n.sons[1]
|
||||
var b = n.sons[2]
|
||||
# symmetrical:
|
||||
if b.kind notin {nkIntLit..nkUInt64Lit}: swap(a, b)
|
||||
if b.kind in {nkIntLit..nkUInt64Lit}:
|
||||
let x = b.intVal|+|1
|
||||
if (x and -x) == x and x >= 0:
|
||||
result = makeRange(a.typ, 0, b.intVal)
|
||||
of mModI, mModI64, mModU, mModU64:
|
||||
# so ... if you ever wondered about modulo's signedness; this defines it:
|
||||
let a = n.sons[1]
|
||||
let b = n.sons[2]
|
||||
if b.kind in {nkIntLit..nkUInt64Lit}:
|
||||
if b.intVal >= 0:
|
||||
result = makeRange(a.typ, 0, b.intVal-1)
|
||||
else:
|
||||
result = makeRange(a.typ, b.intVal+1, 0)
|
||||
of mDivI, mDivI64, mDivU, mDivU64:
|
||||
binaryOp(`|div|`)
|
||||
of mMinI, mMinI64:
|
||||
commutativeOp(min)
|
||||
of mMaxI, mMaxI64:
|
||||
commutativeOp(max)
|
||||
else: nil
|
||||
|
||||
discard """
|
||||
mShlI, mShlI64,
|
||||
mShrI, mShrI64, mAddF64, mSubF64, mMulF64, mDivF64, mMaxF64, mMinF64
|
||||
"""
|
||||
|
||||
proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
|
||||
# b and c may be nil
|
||||
result = nil
|
||||
|
|
|
|||
|
|
@ -40,6 +40,11 @@ proc semTypeTraits(c: PContext, n: PNode): PNode =
|
|||
# pass unmodified to evals
|
||||
result = n
|
||||
|
||||
proc semOrd(c: PContext, n: PNode): PNode =
|
||||
result = n
|
||||
result.typ = makeRangeType(c, firstOrd(n.sons[1].typ),
|
||||
lastOrd(n.sons[1].typ), n.info)
|
||||
|
||||
proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
||||
flags: TExprFlags): PNode =
|
||||
case n[0].sym.magic
|
||||
|
|
@ -49,5 +54,6 @@ proc magicsAfterOverloadResolution(c: PContext, n: PNode,
|
|||
result = newStrNodeT(renderTree(n[1], {renderNoComments}), n)
|
||||
result.typ = getSysType(tyString)
|
||||
of mInstantiationInfo: result = semInstantiationInfo(c, n)
|
||||
of mOrd: result = semOrd(c, n)
|
||||
else: result = n
|
||||
|
||||
|
|
|
|||
|
|
@ -132,7 +132,8 @@ proc semRangeAux(c: PContext, n: PNode, prev: PType): PType =
|
|||
var a = semConstExpr(c, n[1])
|
||||
var b = semConstExpr(c, n[2])
|
||||
if not sameType(a.typ, b.typ): GlobalError(n.info, errPureTypeMismatch)
|
||||
if a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,tyFloat..tyFloat128}:
|
||||
if a.typ.kind notin {tyInt..tyInt64,tyEnum,tyBool,tyChar,tyFloat..tyFloat128,
|
||||
tyUInt8..tyUInt32}:
|
||||
GlobalError(n.info, errOrdinalTypeExpected)
|
||||
if enumHasHoles(a.typ):
|
||||
GlobalError(n.info, errEnumXHasHoles, a.typ.sym.name.s)
|
||||
|
|
|
|||
|
|
@ -34,8 +34,13 @@ type
|
|||
# for example
|
||||
|
||||
TTypeRelation* = enum # order is important!
|
||||
isNone, isConvertible, isIntConv, isSubtype,
|
||||
isGeneric
|
||||
isNone, isConvertible,
|
||||
isIntConv,
|
||||
isSubtype,
|
||||
isSubrange, # subrange of the wanted type; no type conversion
|
||||
# but apart from that counts as ``isSubtype``
|
||||
isGeneric,
|
||||
isFromIntLit, # conversion *from* int literal; proven safe
|
||||
isEqual
|
||||
|
||||
proc initCandidateAux(c: var TCandidate, callee: PType) {.inline.} =
|
||||
|
|
@ -56,10 +61,6 @@ proc initCandidate*(c: var TCandidate, callee: PType) =
|
|||
|
||||
proc put(t: var TIdTable, key, val: PType) {.inline.} =
|
||||
IdTablePut(t, key, val)
|
||||
when false:
|
||||
if val.kind == tyObject and isDefined"testme" and
|
||||
IdentEq(val.sym.name, "TTable"):
|
||||
assert false
|
||||
|
||||
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1) =
|
||||
initCandidateAux(c, callee.typ)
|
||||
|
|
@ -100,7 +101,7 @@ proc cmpCandidates*(a, b: TCandidate): int =
|
|||
if (a.calleeScope != -1) and (b.calleeScope != -1):
|
||||
result = a.calleeScope - b.calleeScope
|
||||
|
||||
proc writeMatches(c: TCandidate) =
|
||||
proc writeMatches*(c: TCandidate) =
|
||||
Writeln(stdout, "exact matches: " & $c.exactMatches)
|
||||
Writeln(stdout, "subtype matches: " & $c.subtypeMatches)
|
||||
Writeln(stdout, "conv matches: " & $c.convMatches)
|
||||
|
|
@ -160,15 +161,25 @@ proc handleRange(f, a: PType, min, max: TTypeKind): TTypeRelation =
|
|||
if a.kind == f.kind:
|
||||
result = isEqual
|
||||
else:
|
||||
var k = skipTypes(a, {tyRange}).kind
|
||||
if k == f.kind: result = isSubtype
|
||||
elif k == tyInt and f.kind in {tyRange, tyInt8..tyUInt64}:
|
||||
# and a.n != nil and a.n.intVal >= firstOrd(f) and
|
||||
# a.n.intVal <= lastOrd(f):
|
||||
let ab = skipTypes(a, {tyRange})
|
||||
let k = ab.kind
|
||||
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(f) and
|
||||
ab.n.intVal <= lastOrd(f):
|
||||
# integer literal in the proper range; we want ``i16 + 4`` to stay an
|
||||
# ``int16`` operation so we declare the ``4`` pseudo-equal to int16
|
||||
result = isFromIntLit
|
||||
elif f.kind == tyInt and k in {tyInt8..tyInt32}:
|
||||
result = isIntConv
|
||||
elif k >= min and k <= max: result = isConvertible
|
||||
elif k >= min and k <= max:
|
||||
result = isConvertible
|
||||
elif a.kind == tyRange and a.sons[0].kind in {tyInt..tyInt64,
|
||||
tyUInt8..tyUInt32} and
|
||||
a.n[0].intVal >= firstOrd(f) and
|
||||
a.n[1].intVal <= lastOrd(f):
|
||||
result = isConvertible
|
||||
else: result = isNone
|
||||
#elif f.kind == tyInt and k in {tyInt..tyInt32}: result = isIntConv
|
||||
#elif f.kind == tyUInt and k in {tyUInt..tyUInt32}: result = isIntConv
|
||||
|
|
@ -186,10 +197,10 @@ proc handleFloatRange(f, a: PType): TTypeRelation =
|
|||
if a.kind == f.kind:
|
||||
result = isEqual
|
||||
else:
|
||||
var k = skipTypes(a, {tyRange}).kind
|
||||
if k == f.kind: result = isSubtype
|
||||
elif k == tyInt and f.kind >= tyFloat and f.kind <= tyFloat128:
|
||||
result = isIntConv
|
||||
let ab = skipTypes(a, {tyRange})
|
||||
var k = ab.kind
|
||||
if k == f.kind: result = isSubrange
|
||||
elif isIntLit(ab): result = isConvertible
|
||||
elif k >= tyFloat and k <= tyFloat128: result = isConvertible
|
||||
else: result = isNone
|
||||
|
||||
|
|
@ -229,7 +240,7 @@ proc tupleRel(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
|||
proc matchTypeClass(mapping: var TIdTable, f, a: PType): TTypeRelation =
|
||||
for i in countup(0, f.sonsLen - 1):
|
||||
let son = f.sons[i]
|
||||
var match = son.kind == a.kind
|
||||
var match = son.kind == skipTypes(a, {tyRange}).kind
|
||||
|
||||
if not match:
|
||||
case son.kind
|
||||
|
|
@ -584,12 +595,17 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
|||
of isConvertible:
|
||||
inc(m.convMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
of isIntConv:
|
||||
of isIntConv:
|
||||
# too lazy to introduce another ``*matches`` field, so we conflate
|
||||
# ``isIntConv`` and ``isIntLit`` here:
|
||||
inc(m.intConvMatches)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
of isSubtype:
|
||||
inc(m.subtypeMatches)
|
||||
result = implicitConv(nkHiddenSubConv, f, copyTree(arg), m, c)
|
||||
of isSubrange:
|
||||
inc(m.subtypeMatches)
|
||||
result = copyTree(arg)
|
||||
of isGeneric:
|
||||
inc(m.genericMatches)
|
||||
if m.calleeSym != nil and m.calleeSym.kind in {skMacro, skTemplate}:
|
||||
|
|
@ -601,6 +617,11 @@ proc ParamTypesMatchAux(c: PContext, m: var TCandidate, f, a: PType,
|
|||
if skipTypes(result.typ, abstractVar).kind in {tyTuple}:
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
# BUGFIX: use ``result.typ`` and not `f` here
|
||||
of isFromIntLit:
|
||||
# too lazy to introduce another ``*matches`` field, so we conflate
|
||||
# ``isIntConv`` and ``isIntLit`` here:
|
||||
inc(m.intConvMatches, 256)
|
||||
result = implicitConv(nkHiddenStdConv, f, copyTree(arg), m, c)
|
||||
of isEqual:
|
||||
inc(m.exactMatches)
|
||||
result = copyTree(arg)
|
||||
|
|
|
|||
|
|
@ -734,7 +734,6 @@ proc transform(c: PTransf, n: PNode): PTransNode =
|
|||
# we inline constants if they are not complex constants:
|
||||
if cnst != nil and not dontInlineConstant(n, cnst):
|
||||
result = PTransNode(cnst) # do not miss an optimization
|
||||
warnNarrowingConversion(result.pnode)
|
||||
|
||||
proc processTransf(context: PPassContext, n: PNode): PNode =
|
||||
# Note: For interactive mode we cannot call 'passes.skipCodegen' and skip
|
||||
|
|
|
|||
|
|
@ -102,6 +102,9 @@ proc getOrdValue(n: PNode): biggestInt =
|
|||
LocalError(n.info, errOrdinalTypeExpected)
|
||||
result = 0
|
||||
|
||||
proc isIntLit*(t: PType): bool {.inline.} =
|
||||
result = t.n != nil and t.n.kind == nkIntLit
|
||||
|
||||
proc isCompatibleToCString(a: PType): bool =
|
||||
if a.kind == tyArray:
|
||||
if (firstOrd(a.sons[0]) == 0) and
|
||||
|
|
@ -400,8 +403,15 @@ proc TypeToString(typ: PType, prefer: TPreferedDesc = preferName): string =
|
|||
result = ""
|
||||
if t == nil: return
|
||||
if prefer == preferName and t.sym != nil and sfAnon notin t.sym.flags:
|
||||
if t.kind == tyInt and isIntLit(t):
|
||||
return t.sym.Name.s & "(" & $t.n.intVal & ")"
|
||||
return t.sym.Name.s
|
||||
case t.Kind
|
||||
of tyInt:
|
||||
if not isIntLit(t):
|
||||
result = typeToStr[t.kind]
|
||||
else:
|
||||
result = "intLit(" & $t.n.intVal & ")"
|
||||
of tyGenericBody, tyGenericInst, tyGenericInvokation:
|
||||
result = typeToString(t.sons[0]) & '['
|
||||
for i in countup(1, sonsLen(t) -1 -ord(t.kind != tyGenericInvokation)):
|
||||
|
|
@ -536,7 +546,7 @@ proc lastOrd(t: PType): biggestInt =
|
|||
of tyUInt8: result = 0xFF
|
||||
of tyUInt16: result = 0xFFFF
|
||||
of tyUInt32: result = 0xFFFFFFFF
|
||||
of tyUInt64: result = -1
|
||||
of tyUInt64: result = 0x7FFFFFFFFFFFFFFF'i64
|
||||
of tyEnum:
|
||||
assert(t.n.sons[sonsLen(t.n) - 1].kind == nkSym)
|
||||
result = t.n.sons[sonsLen(t.n) - 1].sym.position
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue