improved unsigned support

This commit is contained in:
Araq
2012-07-14 14:03:13 +02:00
parent 1005961192
commit b4084df434
9 changed files with 121 additions and 98 deletions

View File

@@ -409,32 +409,32 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
"($1 - $2)", # SubF64
"($1 * $2)", # MulF64
"($1 / $2)", # DivF64
"(NI$3)((NU$3)($1) >> (NU$3)($2))", # ShrI
"(NI$3)((NU$3)($1) << (NU$3)($2))", # ShlI
"(NI$3)($1 & $2)", # BitandI
"(NI$3)($1 | $2)", # BitorI
"(NI$3)($1 ^ $2)", # BitxorI
"($4)((NU$3)($1) >> (NU$3)($2))", # ShrI
"($4)((NU$3)($1) << (NU$3)($2))", # ShlI
"($4)($1 & $2)", # BitandI
"($4)($1 | $2)", # BitorI
"($4)($1 ^ $2)", # BitxorI
"(($1 <= $2) ? $1 : $2)", # MinI
"(($1 >= $2) ? $1 : $2)", # MaxI
"(NI64)((NU64)($1) >> (NU64)($2))", # ShrI64
"(NI64)((NU64)($1) << (NU64)($2))", # ShlI64
"($1 & $2)", # BitandI64
"($1 | $2)", # BitorI64
"($1 ^ $2)", # BitxorI64
"($4)((NU64)($1) >> (NU64)($2))", # ShrI64
"($4)((NU64)($1) << (NU64)($2))", # ShlI64
"($4)($1 & $2)", # BitandI64
"($4)($1 | $2)", # BitorI64
"($4)($1 ^ $2)", # BitxorI64
"(($1 <= $2) ? $1 : $2)", # MinI64
"(($1 >= $2) ? $1 : $2)", # MaxI64
"(($1 <= $2) ? $1 : $2)", # MinF64
"(($1 >= $2) ? $1 : $2)", # MaxF64
"(NI$3)((NU$3)($1) + (NU$3)($2))", # AddU
"(NI$3)((NU$3)($1) - (NU$3)($2))", # SubU
"(NI$3)((NU$3)($1) * (NU$3)($2))", # MulU
"(NI$3)((NU$3)($1) / (NU$3)($2))", # DivU
"(NI$3)((NU$3)($1) % (NU$3)($2))", # ModU
"(NI64)((NU64)($1) + (NU64)($2))", # AddU64
"(NI64)((NU64)($1) - (NU64)($2))", # SubU64
"(NI64)((NU64)($1) * (NU64)($2))", # MulU64
"(NI64)((NU64)($1) / (NU64)($2))", # DivU64
"(NI64)((NU64)($1) % (NU64)($2))", # ModU64
"($4)((NU$3)($1) + (NU$3)($2))", # AddU
"($4)((NU$3)($1) - (NU$3)($2))", # SubU
"($4)((NU$3)($1) * (NU$3)($2))", # MulU
"($4)((NU$3)($1) / (NU$3)($2))", # DivU
"($4)((NU$3)($1) % (NU$3)($2))", # ModU
"($4)((NU64)($1) + (NU64)($2))", # AddU64
"($4)((NU64)($1) - (NU64)($2))", # SubU64
"($4)((NU64)($1) * (NU64)($2))", # MulU64
"($4)((NU64)($1) / (NU64)($2))", # DivU64
"($4)((NU64)($1) % (NU64)($2))", # ModU64
"($1 == $2)", # EqI
"($1 <= $2)", # LeI
"($1 < $2)", # LtI
@@ -474,28 +474,29 @@ proc binaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
# BUGFIX: cannot use result-type here, as it may be a boolean
s = max(getSize(a.t), getSize(b.t)) * 8
putIntoDest(p, d, e.typ,
ropef(binArithTab[op], [rdLoc(a), rdLoc(b), toRope(s)]))
ropef(binArithTab[op], [rdLoc(a), rdLoc(b), toRope(s),
getSimpleTypeDesc(p.module, e.typ)]))
proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
const
unArithTab: array[mNot..mToBiggestInt, string] = ["!($1)", # Not
"$1", # UnaryPlusI
"(NI$2)((NU$2) ~($1))", # BitnotI
"($3)((NU$2) ~($1))", # BitnotI
"$1", # UnaryPlusI64
"~($1)", # BitnotI64
"($3)((NU$2) ~($1))", # BitnotI64
"$1", # UnaryPlusF64
"-($1)", # UnaryMinusF64
"($1 > 0? ($1) : -($1))", # AbsF64; BUGFIX: fabs() makes problems
# for Tiny C, so we don't use it
"((NI)(NU)(NU8)($1))", # mZe8ToI
"((NI64)(NU64)(NU8)($1))", # mZe8ToI64
"((NI)(NU)(NU16)($1))", # mZe16ToI
"((NI64)(NU64)(NU16)($1))", # mZe16ToI64
"((NI64)(NU64)(NU32)($1))", # mZe32ToI64
"((NI64)(NU64)(NU)($1))", # mZeIToI64
"((NI8)(NU8)(NU)($1))", # ToU8
"((NI16)(NU16)(NU)($1))", # ToU16
"((NI32)(NU32)(NU64)($1))", # ToU32
"(($3)(NU)(NU8)($1))", # mZe8ToI
"(($3)(NU64)(NU8)($1))", # mZe8ToI64
"(($3)(NU)(NU16)($1))", # mZe16ToI
"(($3)(NU64)(NU16)($1))", # mZe16ToI64
"(($3)(NU64)(NU32)($1))", # mZe32ToI64
"(($3)(NU64)(NU)($1))", # mZeIToI64
"(($3)(NU8)(NU)($1))", # ToU8
"(($3)(NU16)(NU)($1))", # ToU16
"(($3)(NU32)(NU64)($1))", # ToU32
"((double) ($1))", # ToFloat
"((double) ($1))", # ToBiggestFloat
"float64ToInt32($1)", # ToInt XXX: this is not correct!
@@ -507,7 +508,8 @@ proc unaryArith(p: BProc, e: PNode, d: var TLoc, op: TMagic) =
InitLocExpr(p, e.sons[1], a)
t = skipTypes(e.typ, abstractRange)
putIntoDest(p, d, e.typ,
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8)]))
ropef(unArithTab[op], [rdLoc(a), toRope(getSize(t) * 8),
getSimpleTypeDesc(p.module, e.typ)]))
proc genDeref(p: BProc, e: PNode, d: var TLoc) =
var a: TLoc

View File

@@ -263,15 +263,17 @@ proc evalOp(m: TMagic, n, a, b, c: PNode): PNode =
of tyInt8: result = newIntNodeT(int8(getInt(a)) shl int8(getInt(b)), n)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shl int16(getInt(b)), n)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shl int32(getInt(b)), n)
of tyInt64, tyInt: result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shl`(getInt(a), getInt(b)), n)
else: InternalError(n.info, "constant folding for shl")
of mShrI, mShrI64:
case skipTypes(n.typ, abstractRange).kind
of tyInt8: result = newIntNodeT(int8(getInt(a)) shr int8(getInt(b)), n)
of tyInt16: result = newIntNodeT(int16(getInt(a)) shr int16(getInt(b)), n)
of tyInt32: result = newIntNodeT(int32(getInt(a)) shr int32(getInt(b)), n)
of tyInt64, tyInt: result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
else: InternalError(n.info, "constant folding for shl")
of tyInt64, tyInt, tyUInt..tyUInt64:
result = newIntNodeT(`shr`(getInt(a), getInt(b)), n)
else: InternalError(n.info, "constant folding for shr")
of mDivI, mDivI64: result = newIntNodeT(getInt(a) div getInt(b), n)
of mModI, mModI64: result = newIntNodeT(getInt(a) mod getInt(b), n)
of mAddF64: result = newFloatNodeT(getFloat(a) + getFloat(b), n)

View File

@@ -64,7 +64,8 @@ proc initCandidate*(c: var TCandidate, callee: PType) =
proc put(t: var TIdTable, key, val: PType) {.inline.} =
IdTablePut(t, key, val)
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode, calleeScope = -1) =
proc initCandidate*(c: var TCandidate, callee: PSym, binding: PNode,
calleeScope = -1) =
initCandidateAux(c, callee.typ)
c.calleeSym = callee
c.calleeScope = calleeScope

View File

@@ -31,6 +31,11 @@ Core
implicitly by the compiler. Do not import it directly. It relies on compiler
magic to work.
* `unsigned <unsigned.html>`_
This module implements basic arithmetic operators for unsigned integers.
To discourage users from using unsigned integers, it's not part
of ``system``, but an extra import.
* `threads <threads.html>`_
Nimrod thread support. **Note**: This is part of the system module. Do not
import it explicitely.

59
lib/core/unsigned.nim Normal file
View File

@@ -0,0 +1,59 @@
#
#
# Nimrod's Runtime Library
# (c) Copyright 2012 Andreas Rumpf
#
# See the file "copying.txt", included in this
# distribution, for details about the copyright.
#
## This module implements basic arithmetic operators for unsigned integers.
## To discourage users from using ``unsigned``, it's not part of ``system``,
## but an extra import.
type
SomeUInt = uint|uint8|uint16|uint32|uint64
proc `not`*[T: SomeUInt](x: T): T {.magic: "BitnotI", noSideEffect.}
## computes the `bitwise complement` of the integer `x`.
proc `shr`*[T: SomeUInt](x, y: T): T {.magic: "ShrI", noSideEffect.}
## computes the `shift right` operation of `x` and `y`.
proc `shl`*[T: SomeUInt](x, y: T): T {.magic: "ShlI", noSideEffect.}
## computes the `shift left` operation of `x` and `y`.
proc `and`*[T: SomeUInt](x, y: T): T {.magic: "BitandI", noSideEffect.}
## computes the `bitwise and` of numbers `x` and `y`.
proc `or`*[T: SomeUInt](x, y: T): T {.magic: "BitorI", noSideEffect.}
## computes the `bitwise or` of numbers `x` and `y`.
proc `xor`*[T: SomeUInt](x, y: T): T {.magic: "BitxorI", noSideEffect.}
## computes the `bitwise xor` of numbers `x` and `y`.
proc `==`*[T: SomeUInt](x, y: T): bool {.magic: "EqI", noSideEffect.}
## Compares two unsigned integers for equality.
proc `+`*[T: SomeUInt](x, y: T): T {.magic: "AddU", noSideEffect.}
## Binary `+` operator for unsigned integers.
proc `-`*[T: SomeUInt](x, y: T): T {.magic: "SubU", noSideEffect.}
## Binary `-` operator for unsigned integers.
proc `*`*[T: SomeUInt](x, y: T): T {.magic: "MulU", noSideEffect.}
## Binary `*` operator for unsigned integers.
proc `div`*[T: SomeUInt](x, y: T): T {.magic: "DivU", noSideEffect.}
## computes the integer division. This is roughly the same as
## ``floor(x/y)``.
proc `mod`*[T: SomeUInt](x, y: T): T {.magic: "ModU", noSideEffect.}
## computes the integer modulo operation. This is the same as
## ``x - (x div y) * y``.
proc `<=`*[T: SomeUInt](x, y: SomeUInt): bool {.magic: "LeU", noSideEffect.}
## Returns true iff ``x <= y``.
proc `<`*[T: SomeUInt](x, y: T): bool {.magic: "LtU", noSideEffect.}
## Returns true iff ``unsigned(x) < unsigned(y)``.

View File

@@ -107,10 +107,10 @@ type
PPixels = ptr TPixels
template setPix(video, pitch, x, y, col: expr): stmt =
video[y * pitch.int + x] = int32(col)
video[y * pitch + x] = int32(col)
template getPix(video, pitch, x, y: expr): expr =
colors.TColor(video[y * pitch.int + x])
colors.TColor(video[y * pitch + x])
const
ColSize = 4
@@ -118,7 +118,7 @@ const
proc getPixel(sur: PSurface, x, y: Natural): colors.TColor {.inline.} =
assert x <% sur.w
assert y <% sur.h
result = getPix(cast[PPixels](sur.s.pixels), sur.s.pitch div ColSize.uint16,
result = getPix(cast[PPixels](sur.s.pixels), sur.s.pitch.int div ColSize,
x, y)
proc setPixel(sur: PSurface, x, y: Natural, col: colors.TColor) {.inline.} =
@@ -126,7 +126,7 @@ proc setPixel(sur: PSurface, x, y: Natural, col: colors.TColor) {.inline.} =
assert y <% sur.h
var pixs = cast[PPixels](sur.s.pixels)
#pixs[y * (sur.s.pitch div colSize) + x] = int(col)
setPix(pixs, sur.s.pitch div ColSize.uint16, x, y, col)
setPix(pixs, sur.s.pitch.int div ColSize, x, y, col)
proc `[]`*(sur: PSurface, p: TPoint): TColor =
## get pixel at position `p`. No range checking is done!
@@ -252,7 +252,7 @@ proc drawLine*(sur: PSurface, p1, p2: TPoint, color: TColor) =
dy = dy * 2
dx = dx * 2
var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch div ColSize
var pitch = sur.s.pitch.int div ColSize
setPix(video, pitch, x0, y0, color)
if dx > dy:
var fraction = dy - (dx div 2)
@@ -276,7 +276,7 @@ proc drawLine*(sur: PSurface, p1, p2: TPoint, color: TColor) =
proc drawHorLine*(sur: PSurface, x, y, w: Natural, Color: TColor) =
## draws a horizontal line from (x,y) to (x+w-1, y).
var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch div ColSize
var pitch = sur.s.pitch.int div ColSize
if y >= 0 and y <= sur.s.h:
for i in 0 .. min(sur.s.w-x, w)-1:
@@ -285,7 +285,7 @@ proc drawHorLine*(sur: PSurface, x, y, w: Natural, Color: TColor) =
proc drawVerLine*(sur: PSurface, x, y, h: Natural, Color: TColor) =
## draws a vertical line from (x,y) to (x, y+h-1).
var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch div ColSize
var pitch = sur.s.pitch.int div ColSize
if x >= 0 and x <= sur.s.w:
for i in 0 .. min(sur.s.h-y, h)-1:
@@ -322,7 +322,7 @@ proc fillCircle*(s: PSurface, p: TPoint, r: Natural, color: TColor) =
proc drawRect*(sur: PSurface, r: TRect, color: TColor) =
## draws a rectangle.
var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch div ColSize
var pitch = sur.s.pitch.int div ColSize
if (r.x >= 0 and r.x <= sur.s.w) and (r.y >= 0 and r.y <= sur.s.h):
var minW = min(sur.s.w - r.x, r.width - 1)
var minH = min(sur.s.h - r.y, r.height - 1)
@@ -345,7 +345,7 @@ proc fillRect*(sur: PSurface, r: TRect, col: TColor) =
proc Plot4EllipsePoints(sur: PSurface, CX, CY, X, Y: Natural, col: TColor) =
var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch div ColSize
var pitch = sur.s.pitch.int div ColSize
if CX+X <= sur.s.w-1:
if CY+Y <= sur.s.h-1: setPix(video, pitch, CX+X, CY+Y, col)
if CY-Y <= sur.s.h-1: setPix(video, pitch, CX+X, CY-Y, col)
@@ -409,14 +409,13 @@ proc drawEllipse*(sur: PSurface, CX, CY, XRadius, YRadius: Natural,
proc plotAA(sur: PSurface, x, y: int, c: float, color: TColor) =
if (x > 0 and x < sur.s.w) and (y > 0 and
y < sur.s.h):
if (x > 0 and x < sur.s.w) and (y > 0 and y < sur.s.h):
var video = cast[PPixels](sur.s.pixels)
var pitch = sur.s.pitch div ColSize
var pitch = sur.s.pitch.int div ColSize
var pixColor = getPix(video, pitch, x, y)
setPix(video, pitch, x, y,
setPix(video, pitch, x, y,
pixColor.intensity(1.0 - c) + color.intensity(c))
@@ -561,7 +560,7 @@ when isMainModule:
else:
#echo(event.kind)
SDL.UpdateRect(surf.s, int32(0), int32(0), int32(800), int32(600))
SDL.UpdateRect(surf.s, 0, 0, 800, 600)
surf.writeToBMP("test.bmp")
SDL.Quit()

View File

@@ -64,7 +64,7 @@ type
TInteger* = TSignedInt|TUnsignedInt
## type class matching all integer types
TOrdinal* = TInteger|bool|enum
TOrdinal* = int|int8|int16|int32|int64|bool|enum|uint8|uint16|uint32
## type class matching all ordinal types; however this includes enums with
## holes.
@@ -533,85 +533,44 @@ proc abs*(x: int64): int64 {.magic: "AbsI64", noSideEffect.}
## checking is turned on).
type
UIntMax32 = distinct uint|uint8|uint16|uint32
IntMax32 = distinct int|int8|int16|int32
proc `+` *(x, y: UIntMax32): UIntMax32 {.magic: "AddU", noSideEffect.}
proc `+` *(x, y: UInt64): uint64 {.magic: "AddU64", noSideEffect.}
## Binary `+` operator for unsigned integers.
proc `+%` *(x, y: IntMax32): IntMax32 {.magic: "AddU", noSideEffect.}
proc `+%` *(x, y: Int64): Int64 {.magic: "AddU64", noSideEffect.}
## treats `x` and `y` as unsigned and adds them. The result is truncated to
## fit into the result. This implements modulo arithmetic. No overflow
## errors are possible.
proc `-` *(x, y: UIntMax32): UIntMax32 {.magic: "SubU", noSideEffect.}
proc `-` *(x, y: UInt64): UInt64 {.magic: "SubU64", noSideEffect.}
## Binary `-` operator for unsigned integers.
proc `-%` *(x, y: IntMax32): IntMax32 {.magic: "SubU", noSideEffect.}
proc `-%` *(x, y: Int64): Int64 {.magic: "SubU64", noSideEffect.}
## treats `x` and `y` as unsigned and subtracts them. The result is
## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible.
proc `*` *(x, y: UIntMax32): UIntMax32 {.magic: "MulU", noSideEffect.}
proc `*` *(x, y: UInt64): UInt64 {.magic: "MulU64", noSideEffect.}
## Binary `*` operator for unsigned integers.
proc `*%` *(x, y: IntMax32): IntMax32 {.magic: "MulU", noSideEffect.}
proc `*%` *(x, y: Int64): Int64 {.magic: "MulU64", noSideEffect.}
## treats `x` and `y` as unsigned and multiplies them. The result is
## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible.
proc `div` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `div` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
## computes the integer division. This is roughly the same as
## ``floor(x/y)``.
proc `/` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `/` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
## computes the integer division. This is roughly the same as
## ``floor(x/y)``.
proc `/%` *(x, y: IntMax32): IntMax32 {.magic: "DivU", noSideEffect.}
proc `/%` *(x, y: Int64): Int64 {.magic: "DivU64", noSideEffect.}
## treats `x` and `y` as unsigned and divides them. The result is
## truncated to fit into the result. This implements modulo arithmetic.
## No overflow errors are possible.
proc `%` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `%` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
## computes the integer modulo operation. This is the same as
## ``x - (x div y) * y``.
proc `mod` *(x, y: UIntMax32): UIntMax32 {.magic: "DivU", noSideEffect.}
proc `mod` *(x, y: UInt64): UInt64 {.magic: "DivU64", noSideEffect.}
## computes the integer modulo operation. This is the same as
## ``x - (x div y) * y``.
proc `%%` *(x, y: IntMax32): IntMax32 {.magic: "ModU", noSideEffect.}
proc `%%` *(x, y: Int64): Int64 {.magic: "ModU64", noSideEffect.}
## treats `x` and `y` as unsigned and compute the modulo of `x` and `y`.
## The result is truncated to fit into the result.
## This implements modulo arithmetic.
## No overflow errors are possible.
proc `<=` *(x, y: UIntMax32): bool {.magic: "LeU", noSideEffect.}
proc `<=` *(x, y: UInt64): bool {.magic: "LeU64", noSideEffect.}
## Returns true iff ``x <= y``.
proc `<=%` *(x, y: IntMax32): bool {.magic: "LeU", noSideEffect.}
proc `<=%` *(x, y: Int64): bool {.magic: "LeU64", noSideEffect.}
## treats `x` and `y` as unsigned and compares them.
## Returns true iff ``unsigned(x) <= unsigned(y)``.
proc `<` *(x, y: UIntMax32): bool {.magic: "LtU", noSideEffect.}
proc `<` *(x, y: UInt64): bool {.magic: "LtU64", noSideEffect.}
## Returns true iff ``unsigned(x) < unsigned(y)``.
proc `<%` *(x, y: IntMax32): bool {.magic: "LtU", noSideEffect.}
proc `<%` *(x, y: Int64): bool {.magic: "LtU64", noSideEffect.}
## treats `x` and `y` as unsigned and compares them.

View File

@@ -3,10 +3,6 @@ version 0.9.0
- implicit deref for parameter matching
- deprecate ``var x, y = 0`` as it's confusing for tuple consistency
- finish support for unsigned ints:
- support more unsigned operations
- test codegen
- test sequence of closures; especially that the GC does not leak for those!
New pragmas:

View File

@@ -24,7 +24,7 @@ file: ticker
doc: "endb;intern;apis;lib;manual;tut1;tut2;nimrodc;overview;filters"
doc: "tools;c2nim;niminst;nimgrep"
pdf: "manual;lib;tut1;tut2;nimrodc;c2nim;niminst;gc"
srcdoc: "core/macros;pure/marshal;core/typeinfo"
srcdoc: "core/macros;pure/marshal;core/typeinfo;core/unsigned"
srcdoc: "impure/graphics;impure/re;pure/sockets"
srcdoc: "system.nim;system/threads.nim;system/channels.nim"
srcdoc: "pure/os;pure/strutils;pure/math;pure/matchers;pure/algorithm"