summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--compiler/jsgen.nim83
-rw-r--r--tests/int/tints.nim49
2 files changed, 101 insertions, 31 deletions
diff --git a/compiler/jsgen.nim b/compiler/jsgen.nim
index 4a62cbf9e..ce1fdb1a5 100644
--- a/compiler/jsgen.nim
+++ b/compiler/jsgen.nim
@@ -556,16 +556,16 @@ template binaryExpr(p: PProc, n: PNode, r: var TCompRes, magic, frmt: string,
   r.res = frmt % [a, b, tmp, tmp2]
   r.kind = resExpr
 
-proc unsignedTrimmerJS(size: BiggestInt): Rope =
+proc unsignedTrimmer(size: BiggestInt): string =
   case size
-  of 1: rope"& 0xff"
-  of 2: rope"& 0xffff"
-  of 4: rope">>> 0"
-  else: rope""
-
+  of 1: "& 0xff"
+  of 2: "& 0xffff"
+  of 4: ">>> 0"
+  else: ""
 
-template unsignedTrimmer(size: BiggestInt): Rope =
-  size.unsignedTrimmerJS
+proc signedTrimmer(size: BiggestInt): string =
+  # sign extension is done by shifting to the left and then back to the right
+  "<< $1 >> $1" % [$(32 - size * 8)]
 
 proc binaryUintExpr(p: PProc, n: PNode, r: var TCompRes, op: string,
                     reassign: static[bool] = false) =
@@ -626,6 +626,13 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
   template applyFormat(frmtA, frmtB) =
     if i == 0: applyFormat(frmtA) else: applyFormat(frmtB)
 
+  template bitwiseExpr(op: string) =
+    let typ = n[1].typ.skipTypes(abstractVarRange)
+    if typ.kind in {tyUInt, tyUInt32}:
+      r.res = "(($1 $2 $3) >>> 0)" % [xLoc, op, yLoc]
+    else:
+      r.res = "($1 $2 $3)" % [xLoc, op, yLoc]
+
   case op
   of mAddI:
     if i == 0:
@@ -672,7 +679,19 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
   of mSubF64: applyFormat("($1 - $2)", "($1 - $2)")
   of mMulF64: applyFormat("($1 * $2)", "($1 * $2)")
   of mDivF64: applyFormat("($1 / $2)", "($1 / $2)")
-  of mShrI: applyFormat("", "")
+  of mShrI:
+    let typ = n[1].typ.skipTypes(abstractVarRange)
+    if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
+      applyFormat("BigInt.asIntN(64, BigInt.asUintN(64, $1) >> BigInt($2))")
+    elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
+      applyFormat("($1 >> BigInt($2))")
+    else:
+      if typ.kind in {tyInt..tyInt32}:
+        let trimmerU = unsignedTrimmer(typ.size)
+        let trimmerS = signedTrimmer(typ.size)
+        r.res = "((($1 $2) >>> $3) $4)" % [xLoc, trimmerU, yLoc, trimmerS]
+      else:
+        applyFormat("($1 >>> $2)")
   of mShlI:
     let typ = n[1].typ.skipTypes(abstractVarRange)
     if typ.size == 8:
@@ -683,21 +702,27 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
       else:
         applyFormat("($1 * Math.pow(2, $2))")
     else:
-      applyFormat("($1 << $2)", "($1 << $2)")
+      if typ.kind in {tyUInt..tyUInt32}:
+        let trimmer = unsignedTrimmer(typ.size)
+        r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer]
+      else:
+        let trimmer = signedTrimmer(typ.size)
+        r.res = "(($1 << $2) $3)" % [xLoc, yLoc, trimmer]
   of mAshrI:
     let typ = n[1].typ.skipTypes(abstractVarRange)
     if typ.size == 8:
-      if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
-        applyFormat("BigInt.asIntN(64, $1 >> BigInt($2))")
-      elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
-        applyFormat("BigInt.asUintN(64, $1 >> BigInt($2))")
+      if optJsBigInt64 in p.config.globalOptions:
+        applyFormat("($1 >> BigInt($2))")
       else:
         applyFormat("Math.floor($1 / Math.pow(2, $2))")
     else:
-      applyFormat("($1 >> $2)", "($1 >> $2)")
-  of mBitandI: applyFormat("($1 & $2)", "($1 & $2)")
-  of mBitorI: applyFormat("($1 | $2)", "($1 | $2)")
-  of mBitxorI: applyFormat("($1 ^ $2)", "($1 ^ $2)")
+      if typ.kind in {tyUInt..tyUInt32}:
+        applyFormat("($1 >>> $2)")
+      else:
+        applyFormat("($1 >> $2)")
+  of mBitandI: bitwiseExpr("&")
+  of mBitorI: bitwiseExpr("|")
+  of mBitxorI: bitwiseExpr("^")
   of mMinI: applyFormat("nimMin($1, $2)", "nimMin($1, $2)")
   of mMaxI: applyFormat("nimMax($1, $2)", "nimMax($1, $2)")
   of mAddU: applyFormat("", "")
@@ -733,7 +758,16 @@ proc arithAux(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
   of mAbsI: applyFormat("absInt($1)", "Math.abs($1)")
   of mNot: applyFormat("!($1)", "!($1)")
   of mUnaryPlusI: applyFormat("+($1)", "+($1)")
-  of mBitnotI: applyFormat("~($1)", "~($1)")
+  of mBitnotI:
+    let typ = n[1].typ.skipTypes(abstractVarRange)
+    if typ.kind in {tyUInt..tyUInt64}:
+      if typ.size == 8 and optJsBigInt64 in p.config.globalOptions:
+        applyFormat("BigInt.asUintN(64, ~($1))")
+      else:
+        let trimmer = unsignedTrimmer(typ.size)
+        r.res = "(~($1) $2)" % [xLoc, trimmer]
+    else:
+      applyFormat("~($1)")
   of mUnaryPlusF64: applyFormat("+($1)", "+($1)")
   of mUnaryMinusF64: applyFormat("-($1)", "-($1)")
   of mCharToStr: applyFormat("nimCharToStr($1)", "nimCharToStr($1)")
@@ -760,17 +794,6 @@ proc arith(p: PProc, n: PNode, r: var TCompRes, op: TMagic) =
     arithAux(p, n, r, op)
   of mModI:
     arithAux(p, n, r, op)
-  of mShrI:
-    var x, y: TCompRes
-    gen(p, n[1], x)
-    gen(p, n[2], y)
-    let typ = n[1].typ.skipTypes(abstractVarRange)
-    if typ.kind == tyInt64 and optJsBigInt64 in p.config.globalOptions:
-      r.res = "BigInt.asIntN(64, BigInt.asUintN(64, $1) >> BigInt($2))" % [x.rdLoc, y.rdLoc]
-    elif typ.kind == tyUInt64 and optJsBigInt64 in p.config.globalOptions:
-      r.res = "($1 >> BigInt($2))" % [x.rdLoc, y.rdLoc]
-    else:
-      r.res = "($1 >>> $2)" % [x.rdLoc, y.rdLoc]
   of mCharToStr, mBoolToStr, mIntToStr, mInt64ToStr, mCStrToStr, mStrToStr, mEnumToStr:
     arithAux(p, n, r, op)
   of mEqRef:
diff --git a/tests/int/tints.nim b/tests/int/tints.nim
index cb77d4d89..a7d27d736 100644
--- a/tests/int/tints.nim
+++ b/tests/int/tints.nim
@@ -92,6 +92,53 @@ block: # Casts to uint
 # issue #7174
 let c = 1'u
 let val = c > 0
-doAssert val 
+doAssert val
+
+block: # bug #6752
+  when not defined(js) or (defined(js) and compileOption("jsbigint64")):
+    let x = 711127'i64
+    doAssert x * 86400'i64 == 61441372800'i64
+
+block: # bug #17604
+  let a = 2147483648'u
+  doAssert (a and a) == a
+  doAssert (a or 0) == a
+
+block: # bitwise not
+  let
+    z8 = 0'u8
+    z16 = 0'u16
+    z32 = 0'u32
+    z64 = 0'u64
+  doAssert (not z8) == uint8.high
+  doAssert (not z16) == uint16.high
+  doAssert (not z32) == uint32.high
+  when not defined(js) or (defined(js) and compileOption("jsbigint64")):
+    doAssert (not z64) == uint64.high
+
+block: # shl
+  let i8 = int8.high
+  let i16 = int16.high
+  let i32 = int32.high
+  let i64 = int64.high
+  doAssert i8 shl 1 == -2
+  doAssert i8 shl 2 == -4
+  doAssert i16 shl 1 == -2
+  doAssert i16 shl 2 == -4
+  doAssert i32 shl 1 == -2
+  doAssert i32 shl 2 == -4
+  when not defined(js) or (defined(js) and compileOption("jsbigint64")):
+    doAssert i64 shl 1 == -2
+    doAssert i64 shl 2 == -4
+
+  let u8 = uint8.high
+  let u16 = uint16.high
+  let u32 = uint32.high
+  let u64 = uint64.high
+  doAssert u8 shl 1 == u8 - 1
+  doAssert u16 shl 1 == u16 - 1
+  doAssert u32 shl 1 == u32 - 1
+  when not defined(js) or (defined(js) and compileOption("jsbigint64")):
+    doAssert u64 shl 1 == u64 - 1
 
 echo("Success") #OUT Success