text: /*
  ** Bit manipulation library.
  ** Copyright (C) 2005-2020 Mike Pall. See Copyright Notice in luajit.h
  * /
  
  #define lib_bit_c
  #define LUA_LIB
  
  #include "lua.h"
  #include "lauxlib.h"
  #include "lualib.h"
  
  #include "lj_obj.h"
  #include "lj_err.h"
  #include "lj_buf.h"
  #include "lj_strscan.h"
  #include "lj_strfmt.h"
  #if LJ_HASFFI
  #include "lj_ctype.h"
  #include "lj_cdata.h"
  #include "lj_cconv.h"
  #include "lj_carith.h"
  #endif
  #include "lj_ff.h"
  #include "lj_lib.h"
  #include <fenv.h>
  
  /* ------------------------------------------------------------------------ * /
  
  #define LJLIB_MODULE_bit
  
  #if LJ_HASFFI
  static int bit_result64(lua_State *L, CTypeID id, uint64_t x)
  {
    GCcdata *cd = lj_cdata_new_(L, id, 8);
    *(uint64_t *)cdataptr(cd) = x;
    setcdataV(L, L->base-1-LJ_FR2, cd);
    return FFH_RES(1);
  }
  #else
  static int32_t bit_checkbit(lua_State *L, int narg)
  {
    TValue *o = L->base + narg-1;
    if (!(o < L->top && lj_strscan_numberobj(o)))
      lj_err_argt(L, narg, LUA_TNUMBER);
    if (LJ_LIKELY(tvisint(o))) {
      return intV(o);
    } else {
      int32_t i = lj_num2bit(numV(o));
      if (LJ_DUALNUM) setintV(o, i);
      return i;
    }
  }
  #endif
  
  LJLIB_ASM(bit_tobit)		LJLIB_REC(bit_tobit)
  {
  #if LJ_HASFFI
    CTypeID id = 0;
    setintV(L->base-1-LJ_FR2, (int32_t)lj_carith_check64(L, 1, &id));
    return FFH_RES(1);
  #else
    lj_lib_checknumber(L, 1);
    return FFH_RETRY;
  #endif
  }
  
  LJLIB_ASM(bit_bnot)		LJLIB_REC(bit_unary IR_BNOT)
  {
  #if LJ_HASFFI
    CTypeID id = 0;
    uint64_t x = lj_carith_check64(L, 1, &id);
    return id ? bit_result64(L, id, ~x) : FFH_RETRY;
  #else
    lj_lib_checknumber(L, 1);
    return FFH_RETRY;
  #endif
  }
  
  LJLIB_ASM(bit_bswap)		LJLIB_REC(bit_unary IR_BSWAP)
  {
  #if LJ_HASFFI
    CTypeID id = 0;
    uint64_t x = lj_carith_check64(L, 1, &id);
    return id ? bit_result64(L, id, lj_bswap64(x)) : FFH_RETRY;
  #else
    lj_lib_checknumber(L, 1);
    return FFH_RETRY;
  #endif
  }
  
  LJLIB_ASM(bit_lshift)		LJLIB_REC(bit_shift IR_BSHL)
  {
  #if LJ_HASFFI
    CTypeID id = 0, id2 = 0;
    uint64_t x = lj_carith_check64(L, 1, &id);
    int32_t sh = (int32_t)lj_carith_check64(L, 2, &id2);
    if (id) {
      x = lj_carith_shift64(x, sh, curr_func(L)->c.ffid - (int)FF_bit_lshift);
      return bit_result64(L, id, x);
    }
    if (id2) setintV(L->base+1, sh);
    return FFH_RETRY;
  #else
    lj_lib_checknumber(L, 1);
    bit_checkbit(L, 2);
    return FFH_RETRY;
  #endif
  }
  LJLIB_ASM_(bit_rshift)		LJLIB_REC(bit_shift IR_BSHR)
  LJLIB_ASM_(bit_arshift)		LJLIB_REC(bit_shift IR_BSAR)
  LJLIB_ASM_(bit_rol)		LJLIB_REC(bit_shift IR_BROL)
  LJLIB_ASM_(bit_ror)		LJLIB_REC(bit_shift IR_BROR)
  
  LJLIB_ASM(bit_band)		LJLIB_REC(bit_nary IR_BAND)
  {
  #if LJ_HASFFI
    CTypeID id = 0;
    TValue *o = L->base, *top = L->top;
    int i = 0;
    do { lj_carith_check64(L, ++i, &id); } while (++o < top);
    if (id) {
      CTState *cts = ctype_cts(L);
      CType *ct = ctype_get(cts, id);
      int op = curr_func(L)->c.ffid - (int)FF_bit_bor;
      uint64_t x, y = op >= 0 ? 0 : ~(uint64_t)0;
      o = L->base;
      do {
        lj_cconv_ct_tv(cts, ct, (uint8_t *)&x, o, 0);
        if (op < 0) y &= x; else if (op == 0) y |= x; else y ^= x;
      } while (++o < top);
      return bit_result64(L, id, y);
    }
    return FFH_RETRY;
  #else
    int i = 0;
    do { lj_lib_checknumber(L, ++i); } while (L->base+i < L->top);
    return FFH_RETRY;
  #endif
  }
  LJLIB_ASM_(bit_bor)		LJLIB_REC(bit_nary IR_BOR)
  LJLIB_ASM_(bit_bxor)		LJLIB_REC(bit_nary IR_BXOR)
  
  /* ------------------------------------------------------------------------ * /
  
  LJLIB_CF(bit_tohex)		LJLIB_REC(.)
  {
  #if LJ_HASFFI
    CTypeID id = 0, id2 = 0;
    uint64_t b = lj_carith_check64(L, 1, &id);
    int32_t n = L->base+1>=L->top ? (id ? 16 : 8) :
  				  (int32_t)lj_carith_check64(L, 2, &id2);
  #else
    uint32_t b = (uint32_t)bit_checkbit(L, 1);
    int32_t n = L->base+1>=L->top ? 8 : bit_checkbit(L, 2);
  #endif
    SBuf *sb = lj_buf_tmp_(L);
    SFormat sf = (STRFMT_UINT|STRFMT_T_HEX);
    if (n < 0) { n = -n; sf |= STRFMT_F_UPPER; }
    sf |= ((SFormat)((n+1)&255) << STRFMT_SH_PREC);
  #if LJ_HASFFI
    if (n < 16) b &= ((uint64_t)1 << 4*n)-1;
  #else
    if (n < 8) b &= (1u << 4*n)-1;
  #endif
    sb = lj_strfmt_putfxint(sb, sf, b);
    setstrV(L, L->top-1, lj_buf_str(L, sb));
    lj_gc_check(L);
    return 1;
  }
  
  /* ------------------------------------------------------------------------ * /
  
  #include "lj_libdef.h"
  
  LUALIB_API int luaopen_bit(lua_State *L)
  {
    fesetround(FE_TOWARDZERO);
    LJ_LIB_REG(L, LUA_BITLIBNAME, bit);
    return 1;
  }
  
  /*
   The LuaJIT BitOp library uses the FPU's rounding mode to convert floats to ints.
   Unfortunately, the FPU is set to half-round mode, which is incompatible with
   bit32's behavior, which is to floor (truncate) all floats.
   
   As seen above, I experimented with setting the FPU to round toward zero, but 
   this totally broke all operations on numbers, as even a slight rounding error
   would truncate the entire number. For example, ((1 / 255) + 255) would result
   in 0.99999999999999988 internally, but would be rounded up to 1 by Lua when
   displayed. However, converting the number to an integer in C would yield 0, not
   1 as expected.
  
   So for now, we're not going to be using the BitOp library. Instead, we're just
   going to use the standard PUC Lua implementation, which does not rely on FPU
   rounding as everything is implemented in C. This may cost some performance as
   the operations will no longer be traced in assembly, but it will fix any
   compatibility issues with `bit32`.
  */
  
  /*
  ** $Id: lbitlib.c,v 1.18.1.2 2013/07/09 18:01:41 roberto Exp $
  ** Standard library for bitwise operations
  ** See Copyright Notice in lua.h
  */
  
  #define lbitlib_c
  #define LUA_LIB
  
  #include "lua.h"
  
  #include "lauxlib.h"
  #include "lualib.h"
  #include "luaconf.h"
  
  
  /* number of bits to consider in a number */
  #if !defined(LUA_NBITS)
  #define LUA_NBITS       32
  #endif
  
  
  #define ALLONES         (~(((~(b_uint)0) << (LUA_NBITS - 1)) << 1))
  
  /* macro to trim extra bits */
  #define trim(x)         ((x) & ALLONES)
  
  
  /* builds a number with 'n' ones (1 <= n <= LUA_NBITS) */
  #define mask(n)         (~((ALLONES << 1) << ((n) - 1)))
  
  
  typedef unsigned int b_uint;
  
  
  
  static b_uint andaux(lua_State *L) {
      int i, n = lua_gettop(L);
      b_uint r = ~(b_uint)0;
      for (i = 1; i <= n; i++)
          r &= (b_uint)luaL_checkinteger(L, i);
      return trim(r);
  }
  
  
  static int b_and(lua_State *L) {
      b_uint r = andaux(L);
      lua_pushinteger(L, r);
      return 1;
  }
  
  
  static int b_test(lua_State *L) {
      b_uint r = andaux(L);
      lua_pushboolean(L, r != 0);
      return 1;
  }
  
  
  static int b_or(lua_State *L) {
      int i, n = lua_gettop(L);
      b_uint r = 0;
      for (i = 1; i <= n; i++)
          r |= (b_uint)luaL_checkinteger(L, i);
      lua_pushinteger(L, trim(r));
      return 1;
  }
  
  
  static int b_xor(lua_State *L) {
      int i, n = lua_gettop(L);
      b_uint r = 0;
      for (i = 1; i <= n; i++)
          r ^= (b_uint)luaL_checkinteger(L, i);
      lua_pushinteger(L, trim(r));
      return 1;
  }
  
  
  static int b_not(lua_State *L) {
      b_uint r = ~(b_uint)luaL_checkinteger(L, 1);
      lua_pushinteger(L, trim(r));
      return 1;
  }
  
  
  static int b_shift(lua_State *L, b_uint r, int i) {
      if (i < 0) {  /* shift right? */
          i = -i;
          r = trim(r);
          if (i >= LUA_NBITS) r = 0;
          else r >>= i;
      } else {  /* shift left */
          if (i >= LUA_NBITS) r = 0;
          else r <<= i;
          r = trim(r);
      }
      lua_pushinteger(L, r);
      return 1;
  }
  
  
  static int b_lshift(lua_State *L) {
      return b_shift(L, (b_uint)luaL_checkinteger(L, 1), luaL_checkint(L, 2));
  }
  
  
  static int b_rshift(lua_State *L) {
      return b_shift(L, (b_uint)luaL_checkinteger(L, 1), -luaL_checkint(L, 2));
  }
  
  
  static int b_arshift(lua_State *L) {
      b_uint r = (b_uint)luaL_checkinteger(L, 1);
      int i = luaL_checkint(L, 2);
      if (i < 0 || !(r & ((b_uint)1 << (LUA_NBITS - 1))))
          return b_shift(L, r, -i);
      else {  /* arithmetic shift for 'negative' number */
          if (i >= LUA_NBITS) r = ALLONES;
          else
              r = trim((r >> i) | ~(~(b_uint)0 >> i));  /* add signal bit */
          lua_pushinteger(L, r);
          return 1;
      }
  }
  
  
  static int b_rot(lua_State *L, int i) {
      b_uint r = (b_uint)luaL_checkinteger(L, 1);
      i &= (LUA_NBITS - 1);  /* i = i % NBITS */
      r = trim(r);
      if (i != 0)  /* avoid undefined shift of LUA_NBITS when i == 0 */
          r = (r << i) | (r >> (LUA_NBITS - i));
      lua_pushinteger(L, trim(r));
      return 1;
  }
  
  
  static int b_lrot(lua_State *L) {
      return b_rot(L, luaL_checkint(L, 2));
  }
  
  
  static int b_rrot(lua_State *L) {
      return b_rot(L, -luaL_checkint(L, 2));
  }
  
  
  /*
  ** get field and width arguments for field-manipulation functions,
  ** checking whether they are valid.
  ** ('luaL_error' called without 'return' to avoid later warnings about
  ** 'width' being used uninitialized.)
  */
  static int fieldargs(lua_State *L, int farg, int *width) {
      int f = luaL_checkint(L, farg);
      int w = luaL_optint(L, farg + 1, 1);
      luaL_argcheck(L, 0 <= f, farg, "field cannot be negative");
      luaL_argcheck(L, 0 < w, farg + 1, "width must be positive");
      if (f + w > LUA_NBITS)
          luaL_error(L, "trying to access non-existent bits");
      *width = w;
      return f;
  }
  
  
  static int b_extract(lua_State *L) {
      int w;
      b_uint r = (b_uint)luaL_checkinteger(L, 1);
      int f = fieldargs(L, 2, &w);
      r = (r >> f) & mask(w);
      lua_pushinteger(L, r);
      return 1;
  }
  
  
  static int b_replace(lua_State *L) {
      int w;
      b_uint r = (b_uint)luaL_checkinteger(L, 1);
      b_uint v = (b_uint)luaL_checkinteger(L, 2);
      int f = fieldargs(L, 3, &w);
      int m = mask(w);
      v &= m;  /* erase bits outside given width */
      r = (r & ~(m << f)) | (v << f);
      lua_pushinteger(L, r);
      return 1;
  }
  
  
  static const luaL_Reg bitlib[] = {
    {"arshift", b_arshift},
    {"band", b_and},
    {"bnot", b_not},
    {"bor", b_or},
    {"bxor", b_xor},
    {"btest", b_test},
    {"extract", b_extract},
    {"lrotate", b_lrot},
    {"lshift", b_lshift},
    {"replace", b_replace},
    {"rrotate", b_rrot},
    {"rshift", b_rshift},
    {NULL, NULL}
  };
  
  
  
  LUALIB_API int luaopen_bit(lua_State *L) {
      luaL_register(L, LUA_BITLIBNAME, bitlib);
      return 1;
  }
  
  