mirror of
https://github.com/nim-lang/Nim.git
synced 2025-12-28 17:04:41 +00:00
[JS] Fix bitwise ops & shifts (#22340)
* [JS] Fix bitwise ops & shifts * Test `int64` & `uint64` only with `jsbigint64`
This commit is contained in:
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user