From 2c8361bd39f98c869df7b23ee682c25a9929f64f Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Fri, 31 Aug 2018 13:45:42 +0200 Subject: [PATCH] Constant folding for integer casts (#8095) --- compiler/semfold.nim | 32 +++++++++++--- lib/posix/posix_linux_amd64_consts.nim | 2 +- tests/arithm/tcast.nim | 60 ++++++++++++++++++++++++++ 3 files changed, 86 insertions(+), 8 deletions(-) create mode 100644 tests/arithm/tcast.nim diff --git a/compiler/semfold.nim b/compiler/semfold.nim index 444940144..fe1871881 100644 --- a/compiler/semfold.nim +++ b/compiler/semfold.nim @@ -450,21 +450,38 @@ proc rangeCheck(n: PNode, value: BiggestInt; g: ModuleGraph) = localError(g.config, n.info, "cannot convert " & $value & " 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? - case skipTypes(n.typ, abstractRange).kind - of tyInt..tyInt64, tyUInt..tyUInt64: - case skipTypes(a.typ, abstractRange).kind + 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 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: result = a result.typ = n.typ if check and result.kind in {nkCharLit..nkUInt64Lit}: rangeCheck(n, result.intVal, g) of tyFloat..tyFloat64: - case skipTypes(a.typ, abstractRange).kind + case srcTyp.kind of tyInt..tyInt64, tyEnum, tyBool, tyChar: result = newFloatNodeT(toBiggestFloat(getOrdValue(a)), n, g) else: @@ -742,7 +759,8 @@ 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 - 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: var a = getConstExpr(m, n.sons[1], g) if a == nil: return diff --git a/lib/posix/posix_linux_amd64_consts.nim b/lib/posix/posix_linux_amd64_consts.nim index ee4fac1e8..50b227635 100644 --- a/lib/posix/posix_linux_amd64_consts.nim +++ b/lib/posix/posix_linux_amd64_consts.nim @@ -300,7 +300,7 @@ const IPPROTO_TCP* = cint(6) const IPPROTO_UDP* = cint(17) const INADDR_ANY* = InAddrScalar(0) const INADDR_LOOPBACK* = InAddrScalar(2130706433) -const INADDR_BROADCAST* = InAddrScalar(-1) +const INADDR_BROADCAST* = InAddrScalar(4294967295) const INET_ADDRSTRLEN* = cint(16) const INET6_ADDRSTRLEN* = cint(46) const IPV6_JOIN_GROUP* = cint(20) diff --git a/tests/arithm/tcast.nim b/tests/arithm/tcast.nim new file mode 100644 index 000000000..954e2e677 --- /dev/null +++ b/tests/arithm/tcast.nim @@ -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)