Constant folding for integer casts (#8095)
This commit is contained in:
parent
b74faf354e
commit
2c8361bd39
3 changed files with 86 additions and 8 deletions
|
|
@ -450,21 +450,38 @@ proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) =
|
||||||
localError(g.config, n.info, "cannot convert " & $value &
|
localError(g.config, n.info, "cannot convert " & $value &
|
||||||
" to " & typeToString(n.typ))
|
" to " & typeToString(n.typ))
|
||||||
|
|
||||||
proc foldConv*(n, a: PNode; g: ModuleGraph; check = false): PNode =
|
proc foldConv(n, a: PNode; g: ModuleGraph; check = false): PNode =
|
||||||
|
let dstTyp = skipTypes(n.typ, abstractRange)
|
||||||
|
let srcTyp = skipTypes(a.typ, abstractRange)
|
||||||
|
|
||||||
# XXX range checks?
|
# XXX range checks?
|
||||||
case skipTypes(n.typ, abstractRange).kind
|
case dstTyp.kind
|
||||||
of tyInt..tyInt64, tyUInt..tyUInt64:
|
of tyInt..tyInt64, tyUint..tyUInt64:
|
||||||
case skipTypes(a.typ, abstractRange).kind
|
case srcTyp.kind
|
||||||
of tyFloat..tyFloat64:
|
of tyFloat..tyFloat64:
|
||||||
result = newIntNodeT(int(getFloat(a)), n, g)
|
result = newIntNodeT(int(getFloat(a)), n, g)
|
||||||
of tyChar: result = newIntNodeT(getOrdValue(a), n, g)
|
of tyChar:
|
||||||
|
result = newIntNodeT(getOrdValue(a), n, g)
|
||||||
|
of tyUInt8..tyUInt32, tyInt8..tyInt32:
|
||||||
|
let fromSigned = srcTyp.kind in tyInt..tyInt64
|
||||||
|
let toSigned = dstTyp.kind in tyInt..tyInt64
|
||||||
|
|
||||||
|
let mask = lastOrd(g.config, dstTyp, fixedUnsigned=true)
|
||||||
|
|
||||||
|
var val =
|
||||||
|
if toSigned:
|
||||||
|
a.getOrdValue mod mask
|
||||||
|
else:
|
||||||
|
a.getOrdValue and mask
|
||||||
|
|
||||||
|
result = newIntNodeT(val, n, g)
|
||||||
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, result.intVal, g)
|
||||||
of tyFloat..tyFloat64:
|
of tyFloat..tyFloat64:
|
||||||
case skipTypes(a.typ, abstractRange).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(toBiggestFloat(getOrdValue(a)), n, g)
|
||||||
else:
|
else:
|
||||||
|
|
@ -742,7 +759,8 @@ 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
|
||||||
result = foldConv(n, a, g, check=n.kind == nkHiddenStdConv)
|
# XXX: we should enable `check` for other conversion types too
|
||||||
|
result = foldConv(n, a, g, check=n.kind == nkHiddenSubConv)
|
||||||
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
|
||||||
|
|
|
||||||
|
|
@ -300,7 +300,7 @@ const IPPROTO_TCP* = cint(6)
|
||||||
const IPPROTO_UDP* = cint(17)
|
const IPPROTO_UDP* = cint(17)
|
||||||
const INADDR_ANY* = InAddrScalar(0)
|
const INADDR_ANY* = InAddrScalar(0)
|
||||||
const INADDR_LOOPBACK* = InAddrScalar(2130706433)
|
const INADDR_LOOPBACK* = InAddrScalar(2130706433)
|
||||||
const INADDR_BROADCAST* = InAddrScalar(-1)
|
const INADDR_BROADCAST* = InAddrScalar(4294967295)
|
||||||
const INET_ADDRSTRLEN* = cint(16)
|
const INET_ADDRSTRLEN* = cint(16)
|
||||||
const INET6_ADDRSTRLEN* = cint(46)
|
const INET6_ADDRSTRLEN* = cint(46)
|
||||||
const IPV6_JOIN_GROUP* = cint(20)
|
const IPV6_JOIN_GROUP* = cint(20)
|
||||||
|
|
|
||||||
60
tests/arithm/tcast.nim
Normal file
60
tests/arithm/tcast.nim
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
discard """
|
||||||
|
output: '''
|
||||||
|
B0
|
||||||
|
B1
|
||||||
|
B2
|
||||||
|
B3
|
||||||
|
'''
|
||||||
|
"""
|
||||||
|
|
||||||
|
template crossCheck(ty: untyped, exp: untyped) =
|
||||||
|
let rt = ty(exp)
|
||||||
|
const ct = ty(exp)
|
||||||
|
if $rt != $ct:
|
||||||
|
echo "Got ", ct
|
||||||
|
echo "Expected ", rt
|
||||||
|
|
||||||
|
block:
|
||||||
|
when true:
|
||||||
|
echo "B0"
|
||||||
|
crossCheck(int8, 0'i16 - 5'i16)
|
||||||
|
crossCheck(int16, 0'i32 - 5'i32)
|
||||||
|
crossCheck(int32, 0'i64 - 5'i64)
|
||||||
|
|
||||||
|
echo "B1"
|
||||||
|
crossCheck(uint8, 0'u8 - 5'u8)
|
||||||
|
crossCheck(uint16, 0'u16 - 5'u16)
|
||||||
|
crossCheck(uint32, 0'u32 - 5'u32)
|
||||||
|
crossCheck(uint64, 0'u64 - 5'u64)
|
||||||
|
|
||||||
|
echo "B2"
|
||||||
|
crossCheck(uint8, uint8.high + 5'u8)
|
||||||
|
crossCheck(uint16, uint16.high + 5'u16)
|
||||||
|
crossCheck(uint32, uint32.high + 5'u32)
|
||||||
|
crossCheck(uint64, (-1).uint64 + 5'u64)
|
||||||
|
|
||||||
|
echo "B3"
|
||||||
|
crossCheck(int8, 0'u8 - 5'u8)
|
||||||
|
crossCheck(int16, 0'u16 - 5'u16)
|
||||||
|
crossCheck(int32, 0'u32 - 5'u32)
|
||||||
|
crossCheck(int64, 0'u64 - 5'u64)
|
||||||
|
|
||||||
|
# crossCheck(int8, 0'u16 - 129'u16)
|
||||||
|
# crossCheck(uint8, 0'i16 + 257'i16)
|
||||||
|
|
||||||
|
# Signed integer {under,over}flow is guarded against
|
||||||
|
|
||||||
|
# crossCheck(int8, int8.high + 5'i8)
|
||||||
|
# crossCheck(int16, int16.high + 5'i16)
|
||||||
|
# crossCheck(int32, int32.high + 5'i32)
|
||||||
|
# crossCheck(int64, int64.high + 5'i64)
|
||||||
|
|
||||||
|
# crossCheck(int8, int8.low - 5'i8)
|
||||||
|
# crossCheck(int16, int16.low - 5'i16)
|
||||||
|
# crossCheck(int32, int32.low - 5'i32)
|
||||||
|
# crossCheck(int64, int64.low - 5'i64)
|
||||||
|
|
||||||
|
# crossCheck(uint8, 0'i8 - 5'i8)
|
||||||
|
# crossCheck(uint16, 0'i16 - 5'i16)
|
||||||
|
# crossCheck(uint32, 0'i32 - 5'i32)
|
||||||
|
# crossCheck(uint64, 0'i64 - 5'i64)
|
||||||
Loading…
Add table
Add a link
Reference in a new issue