<commit_before>/*-
 * Copyright (c) 2013 <NAME>.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <lua.h>
#include <lauxlib.h>

#include <sljitLir.h>

#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>

/* Metatables. */
#define COMPILER_METATABLE "sljit.compiler"
#define LABEL_METATABLE    "sljit.label"
#define JUMP_METATABLE     "sljit.jump"
#define SW_METATABLE       "sljit.sw"

/* Errors. */
#define ERR_NOCONV(type) "conversion to " type " failed"

/* Lua cmod exports only one function. */
int luaopen_sljit_api(lua_State *L);

static const sljit_si regs[] = {
	SLJIT_IMM,
	SLJIT_LOCALS_REG,
	SLJIT_PREF_SHIFT_REG, /* XXX get a real name of PREF_SHIFT_REG */
	SLJIT_RETURN_REG,     /* XXX get a real name of RETURN_REG */
	SLJIT_SAVED_EREG1,
	SLJIT_SAVED_EREG2,
	SLJIT_SAVED_REG1,
	SLJIT_SAVED_REG2,
	SLJIT_SAVED_REG3,
	SLJIT_SCRATCH_REG1,
	SLJIT_SCRATCH_REG2,
	SLJIT_SCRATCH_REG3,
	SLJIT_TEMPORARY_EREG1,
	SLJIT_TEMPORARY_EREG2,
	SLJIT_UNUSED,
};

static const char * const regstrings[] = {
	"IMM",
	"LOCALS_REG",
	"PREF_SHIFT_REG",
	"RETURN_REG",
	"SAVED_EREG1",
	"SAVED_EREG2",
	"SAVED_REG1",
	"SAVED_REG2",
	"SAVED_REG3",
	"SCRATCH_REG1",
	"SCRATCH_REG2",
	"SCRATCH_REG3",
	"TEMPORARY_EREG1",
	"TEMPORARY_EREG2",
	"UNUSED",
	NULL
};

static const sljit_si ops0[] = {
	SLJIT_BREAKPOINT,
	SLJIT_ISDIV,
	SLJIT_IUDIV,
	SLJIT_NOP,
	SLJIT_SDIV,
	SLJIT_SMUL,
	SLJIT_UDIV,
	SLJIT_UMUL,
};

static const char * const op0strings[] = {
	"BREAKPOINT",
	"ISDIV",
	"IUDIV",
	"NOP",
	"SDIV",
	"SMUL",
	"UDIV",
	"UMUL",
	NULL
};

static const sljit_si ops1[] = {
	SLJIT_CLZ,
	SLJIT_ICLZ,
	SLJIT_IMOV,
	SLJIT_IMOVU,
	SLJIT_IMOVU_SB,
	SLJIT_IMOVU_SH,
	SLJIT_IMOVU_UB,
	SLJIT_IMOVU_UH,
	SLJIT_IMOV_SB,
	SLJIT_IMOV_SH,
	SLJIT_IMOV_UB,
	SLJIT_IMOV_UH,
	SLJIT_INEG,
	SLJIT_INOT,
	SLJIT_MOV,
	SLJIT_MOVU,
	SLJIT_MOVU_P,
	SLJIT_MOVU_SB,
	SLJIT_MOVU_SH,
	SLJIT_MOVU_SI,
	SLJIT_MOVU_UB,
	SLJIT_MOVU_UH,
	SLJIT_MOVU_UI,
	SLJIT_MOV_P,
	SLJIT_MOV_SB,
	SLJIT_MOV_SH,
	SLJIT_MOV_SI,
	SLJIT_MOV_UB,
	SLJIT_MOV_UH,
	SLJIT_MOV_UI,
	SLJIT_NEG,
	SLJIT_NOT,
};

static const char * const op1strings[] = {
	"CLZ",
	"ICLZ",
	"IMOV",
	"IMOVU",
	"IMOVU_SB",
	"IMOVU_SH",
	"IMOVU_UB",
	"IMOVU_UH",
	"IMOV_SB",
	"IMOV_SH",
	"IMOV_UB",
	"IMOV_UH",
	"INEG",
	"INOT",
	"MOV",
	"MOVU",
	"MOVU_P",
	"MOVU_SB",
	"MOVU_SH",
	"MOVU_SI",
	"MOVU_UB",
	"MOVU_UH",
	"MOVU_UI",
	"MOV_P",
	"MOV_SB",
	"MOV_SH",
	"MOV_SI",
	"MOV_UB",
	"MOV_UH",
	"MOV_UI",
	"NEG",
	"NOT",
	NULL
};

/* sljit_emit_return */
static const sljit_si retops[] = {
	SLJIT_IMOV,
	SLJIT_IMOV_SB,
	SLJIT_IMOV_SH,
	SLJIT_IMOV_UB,
	SLJIT_IMOV_UH,
	SLJIT_MOV,
	SLJIT_MOV_P,
	SLJIT_MOV_SB,
	SLJIT_MOV_SH,
	SLJIT_MOV_SI,
	SLJIT_MOV_UB,
	SLJIT_MOV_UH,
	SLJIT_MOV_UI,
	SLJIT_UNUSED, /* XXX hmm, I thought it's a register, not op. */
};

static const char * const retopstrings[] = {
	"IMOV",
	"IMOV_SB",
	"IMOV_SH",
	"IMOV_UB",
	"IMOV_UH",
	"MOV",
	"MOV_P",
	"MOV_SB",
	"MOV_SH",
	"MOV_SI",
	"MOV_UB",
	"MOV_UH",
	"MOV_UI",
	"UNUSED",
	NULL
};

static const sljit_si jumptypes[] = {
	SLJIT_CALL0,
	SLJIT_CALL1,
	SLJIT_CALL2,
	SLJIT_CALL3,
	SLJIT_C_EQUAL,
	SLJIT_C_FLOAT_EQUAL,
	SLJIT_C_FLOAT_GREATER,
	SLJIT_C_FLOAT_GREATER_EQUAL,
	SLJIT_C_FLOAT_LESS,
	SLJIT_C_FLOAT_LESS_EQUAL,
	SLJIT_C_FLOAT_NOT_EQUAL,
	SLJIT_C_FLOAT_ORDERED,
	SLJIT_C_FLOAT_UNORDERED,
	SLJIT_C_GREATER,
	SLJIT_C_GREATER_EQUAL,
	SLJIT_C_LESS,
	SLJIT_C_LESS_EQUAL,
	SLJIT_C_MUL_NOT_OVERFLOW,
	SLJIT_C_MUL_OVERFLOW,
	SLJIT_C_NOT_EQUAL,
	SLJIT_C_NOT_OVERFLOW,
	SLJIT_C_NOT_ZERO,
	SLJIT_C_OVERFLOW,
	SLJIT_C_SIG_GREATER,
	SLJIT_C_SIG_GREATER_EQUAL,
	SLJIT_C_SIG_LESS,
	SLJIT_C_SIG_LESS_EQUAL,
	SLJIT_C_ZERO,
	SLJIT_FAST_CALL,
	SLJIT_JUMP,
};

/* XXX "type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP" */
static const char * const jumptypestrings[] = {
	"CALL0",
	"CALL1",
	"CALL2",
	"CALL3",
	"C_EQUAL",
	"C_FLOAT_EQUAL",
	"C_FLOAT_GREATER",
	"C_FLOAT_GREATER_EQUAL",
	"C_FLOAT_LESS",
	"C_FLOAT_LESS_EQUAL",
	"C_FLOAT_NOT_EQUAL",
	"C_FLOAT_ORDERED",
	"C_FLOAT_UNORDERED",
	"C_GREATER",
	"C_GREATER_EQUAL",
	"C_LESS",
	"C_LESS_EQUAL",
	"C_MUL_NOT_OVERFLOW",
	"C_MUL_OVERFLOW",
	"C_NOT_EQUAL",
	"C_NOT_OVERFLOW",
	"C_NOT_ZERO",
	"C_OVERFLOW",
	"C_SIG_GREATER",
	"C_SIG_GREATER_EQUAL",
	"C_SIG_LESS",
	"C_SIG_LESS_EQUAL",
	"C_ZERO",
	"FAST_CALL",
	"JUMP",
	NULL
};

/*
 * XXX "type can be combined (or'ed) with
 * SLJIT_REWRITABLE_JUMP or SLJIT_INT_OP"
 */
static const sljit_si cmptypes[] = {
	SLJIT_C_EQUAL,
	SLJIT_C_GREATER,
	SLJIT_C_GREATER_EQUAL,
	SLJIT_C_LESS,
	SLJIT_C_LESS_EQUAL,
	SLJIT_C_NOT_EQUAL,
	SLJIT_C_NOT_ZERO,
	SLJIT_C_SIG_GREATER,
	SLJIT_C_SIG_GREATER_EQUAL,
	SLJIT_C_SIG_LESS,
	SLJIT_C_SIG_LESS_EQUAL,
	SLJIT_C_ZERO,
};

static const char * const cmptypestrings[] = {
	"C_EQUAL",
	"C_GREATER",
	"C_GREATER_EQUAL",
	"C_LESS",
	"C_LESS_EQUAL",
	"C_NOT_EQUAL",
	"C_NOT_ZERO",
	"C_SIG_GREATER",
	"C_SIG_GREATER_EQUAL",
	"C_SIG_LESS",
	"C_SIG_LESS_EQUAL",
	"C_ZERO",
	NULL
};

/* sljit_compiler userdata. */
struct luaSljitCompiler
{
	struct sljit_compiler *compiler;
};

/* sljit_jump userdata. */
struct luaSljitJump
{
	struct sljit_jump *jump;
};

/* sljit_label userdata. */
struct luaSljitLabel
{
	struct sljit_label *label;
};

static sljit_sw
tosw(lua_State *L, int narg1, int narg2)
{
	sljit_sw rv;
	const char *s;
	char *se;
	size_t slen;
	lua_Number n;
	unsigned long long ull;
	int badarg, type;
	const int base = 0; /* 8, 10, or 16 */
	bool err;

#define TABLE_WITH_TWO_NUMBERS "table with two uint32_t values"

	rv = 0;
	badarg = narg1;

	type = lua_type(L, narg1);

	switch (type) {
		case LUA_TSTRING:
			s = lua_tolstring(L, narg1, &slen);
			if (s == NULL)
				luaL_argerror(L, badarg, "lua_tolstring failed");

			errno = 0;
			err = false;

			ull = strtoull(s, &se, base);

			if (slen == 0 || se != s + slen)
				err = true;
			if (ull != (sljit_uw)ull)
				err = true;
			if (ull == LLONG_MAX && errno != 0)
				err = true;

			rv = ull;

			if (err)
				luaL_argerror(L, badarg, ERR_NOCONV("sljit_sw"));

			return rv;

		case LUA_TTABLE:
			lua_rawgeti(L, narg1, 1);
			lua_rawgeti(L, narg1, 2);
			narg2 = lua_gettop(L);
			narg1 = narg2 - 1;
			type = lua_type(L, narg1);
			break;

		case LUA_TNUMBER:
			break;

		default:
			luaL_typerror(L, badarg, "number, string or table");
	}

	if (type != LUA_TNUMBER)
		luaL_typerror(L, badarg, TABLE_WITH_TWO_NUMBERS);

	n = lua_tonumber(L, narg1);

	if (n < 0 || n > UINT32_MAX || n != (lua_Integer)n)
		luaL_argerror(L, badarg, ERR_NOCONV("uint32_t"));

	rv = n;

	if (narg2 != narg1) {
		s = NULL;
		switch (lua_type(L, narg2)) {
			case LUA_TNIL:
			case LUA_TNONE:
				break;

			case LUA_TNUMBER:
				n = lua_tonumber(L, narg2);
				if (n < 0 || n > UINT32_MAX ||
				    n != (lua_Integer)n) {
					s = TABLE_WITH_TWO_NUMBERS;
				}

				/* Check for overflow when sizeof(sljit_sw) == 4 */
				rv = (rv << 31 << 1) | (sljit_sw)n;
				break;

			default:
				s = (badarg == narg1) ?
				    "number" : TABLE_WITH_TWO_NUMBERS;
		}

		if (s != NULL)
			luaL_typerror(L, (badarg == narg1) ? narg2 : badarg, s);
	}

	return rv;
}

/* XXX push userdata. */
static int
l_mem0(lua_State *L)
{

	lua_pushnumber(L, SLJIT_MEM0());

	return 1;
}

/* XXX push userdata. */
static int
l_mem1(lua_State *L)
{
	sljit_si r1;<commit_msg>Improve tosw().<commit_after>/*-
 * Copyright (c) 2013 <NAME>.
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
 * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */

#include <lua.h>
#include <lauxlib.h>

#include <sljitLir.h>

#include <errno.h>
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#include <stdlib.h>

/* Metatables. */
#define COMPILER_METATABLE "sljit.compiler"
#define LABEL_METATABLE    "sljit.label"
#define JUMP_METATABLE     "sljit.jump"
#define SW_METATABLE       "sljit.sw"

/* Errors. */
#define ERR_NOCONV(type) "conversion to " type " failed"

/* Lua cmod exports only one function. */
int luaopen_sljit_api(lua_State *L);

static const sljit_si regs[] = {
	SLJIT_IMM,
	SLJIT_LOCALS_REG,
	SLJIT_PREF_SHIFT_REG, /* XXX get a real name of PREF_SHIFT_REG */
	SLJIT_RETURN_REG,     /* XXX get a real name of RETURN_REG */
	SLJIT_SAVED_EREG1,
	SLJIT_SAVED_EREG2,
	SLJIT_SAVED_REG1,
	SLJIT_SAVED_REG2,
	SLJIT_SAVED_REG3,
	SLJIT_SCRATCH_REG1,
	SLJIT_SCRATCH_REG2,
	SLJIT_SCRATCH_REG3,
	SLJIT_TEMPORARY_EREG1,
	SLJIT_TEMPORARY_EREG2,
	SLJIT_UNUSED,
};

static const char * const regstrings[] = {
	"IMM",
	"LOCALS_REG",
	"PREF_SHIFT_REG",
	"RETURN_REG",
	"SAVED_EREG1",
	"SAVED_EREG2",
	"SAVED_REG1",
	"SAVED_REG2",
	"SAVED_REG3",
	"SCRATCH_REG1",
	"SCRATCH_REG2",
	"SCRATCH_REG3",
	"TEMPORARY_EREG1",
	"TEMPORARY_EREG2",
	"UNUSED",
	NULL
};

static const sljit_si ops0[] = {
	SLJIT_BREAKPOINT,
	SLJIT_ISDIV,
	SLJIT_IUDIV,
	SLJIT_NOP,
	SLJIT_SDIV,
	SLJIT_SMUL,
	SLJIT_UDIV,
	SLJIT_UMUL,
};

static const char * const op0strings[] = {
	"BREAKPOINT",
	"ISDIV",
	"IUDIV",
	"NOP",
	"SDIV",
	"SMUL",
	"UDIV",
	"UMUL",
	NULL
};

static const sljit_si ops1[] = {
	SLJIT_CLZ,
	SLJIT_ICLZ,
	SLJIT_IMOV,
	SLJIT_IMOVU,
	SLJIT_IMOVU_SB,
	SLJIT_IMOVU_SH,
	SLJIT_IMOVU_UB,
	SLJIT_IMOVU_UH,
	SLJIT_IMOV_SB,
	SLJIT_IMOV_SH,
	SLJIT_IMOV_UB,
	SLJIT_IMOV_UH,
	SLJIT_INEG,
	SLJIT_INOT,
	SLJIT_MOV,
	SLJIT_MOVU,
	SLJIT_MOVU_P,
	SLJIT_MOVU_SB,
	SLJIT_MOVU_SH,
	SLJIT_MOVU_SI,
	SLJIT_MOVU_UB,
	SLJIT_MOVU_UH,
	SLJIT_MOVU_UI,
	SLJIT_MOV_P,
	SLJIT_MOV_SB,
	SLJIT_MOV_SH,
	SLJIT_MOV_SI,
	SLJIT_MOV_UB,
	SLJIT_MOV_UH,
	SLJIT_MOV_UI,
	SLJIT_NEG,
	SLJIT_NOT,
};

static const char * const op1strings[] = {
	"CLZ",
	"ICLZ",
	"IMOV",
	"IMOVU",
	"IMOVU_SB",
	"IMOVU_SH",
	"IMOVU_UB",
	"IMOVU_UH",
	"IMOV_SB",
	"IMOV_SH",
	"IMOV_UB",
	"IMOV_UH",
	"INEG",
	"INOT",
	"MOV",
	"MOVU",
	"MOVU_P",
	"MOVU_SB",
	"MOVU_SH",
	"MOVU_SI",
	"MOVU_UB",
	"MOVU_UH",
	"MOVU_UI",
	"MOV_P",
	"MOV_SB",
	"MOV_SH",
	"MOV_SI",
	"MOV_UB",
	"MOV_UH",
	"MOV_UI",
	"NEG",
	"NOT",
	NULL
};

/* sljit_emit_return */
static const sljit_si retops[] = {
	SLJIT_IMOV,
	SLJIT_IMOV_SB,
	SLJIT_IMOV_SH,
	SLJIT_IMOV_UB,
	SLJIT_IMOV_UH,
	SLJIT_MOV,
	SLJIT_MOV_P,
	SLJIT_MOV_SB,
	SLJIT_MOV_SH,
	SLJIT_MOV_SI,
	SLJIT_MOV_UB,
	SLJIT_MOV_UH,
	SLJIT_MOV_UI,
	SLJIT_UNUSED, /* XXX hmm, I thought it's a register, not op. */
};

static const char * const retopstrings[] = {
	"IMOV",
	"IMOV_SB",
	"IMOV_SH",
	"IMOV_UB",
	"IMOV_UH",
	"MOV",
	"MOV_P",
	"MOV_SB",
	"MOV_SH",
	"MOV_SI",
	"MOV_UB",
	"MOV_UH",
	"MOV_UI",
	"UNUSED",
	NULL
};

static const sljit_si jumptypes[] = {
	SLJIT_CALL0,
	SLJIT_CALL1,
	SLJIT_CALL2,
	SLJIT_CALL3,
	SLJIT_C_EQUAL,
	SLJIT_C_FLOAT_EQUAL,
	SLJIT_C_FLOAT_GREATER,
	SLJIT_C_FLOAT_GREATER_EQUAL,
	SLJIT_C_FLOAT_LESS,
	SLJIT_C_FLOAT_LESS_EQUAL,
	SLJIT_C_FLOAT_NOT_EQUAL,
	SLJIT_C_FLOAT_ORDERED,
	SLJIT_C_FLOAT_UNORDERED,
	SLJIT_C_GREATER,
	SLJIT_C_GREATER_EQUAL,
	SLJIT_C_LESS,
	SLJIT_C_LESS_EQUAL,
	SLJIT_C_MUL_NOT_OVERFLOW,
	SLJIT_C_MUL_OVERFLOW,
	SLJIT_C_NOT_EQUAL,
	SLJIT_C_NOT_OVERFLOW,
	SLJIT_C_NOT_ZERO,
	SLJIT_C_OVERFLOW,
	SLJIT_C_SIG_GREATER,
	SLJIT_C_SIG_GREATER_EQUAL,
	SLJIT_C_SIG_LESS,
	SLJIT_C_SIG_LESS_EQUAL,
	SLJIT_C_ZERO,
	SLJIT_FAST_CALL,
	SLJIT_JUMP,
};

/* XXX "type can be combined (or'ed) with SLJIT_REWRITABLE_JUMP" */
static const char * const jumptypestrings[] = {
	"CALL0",
	"CALL1",
	"CALL2",
	"CALL3",
	"C_EQUAL",
	"C_FLOAT_EQUAL",
	"C_FLOAT_GREATER",
	"C_FLOAT_GREATER_EQUAL",
	"C_FLOAT_LESS",
	"C_FLOAT_LESS_EQUAL",
	"C_FLOAT_NOT_EQUAL",
	"C_FLOAT_ORDERED",
	"C_FLOAT_UNORDERED",
	"C_GREATER",
	"C_GREATER_EQUAL",
	"C_LESS",
	"C_LESS_EQUAL",
	"C_MUL_NOT_OVERFLOW",
	"C_MUL_OVERFLOW",
	"C_NOT_EQUAL",
	"C_NOT_OVERFLOW",
	"C_NOT_ZERO",
	"C_OVERFLOW",
	"C_SIG_GREATER",
	"C_SIG_GREATER_EQUAL",
	"C_SIG_LESS",
	"C_SIG_LESS_EQUAL",
	"C_ZERO",
	"FAST_CALL",
	"JUMP",
	NULL
};

/*
 * XXX "type can be combined (or'ed) with
 * SLJIT_REWRITABLE_JUMP or SLJIT_INT_OP"
 */
static const sljit_si cmptypes[] = {
	SLJIT_C_EQUAL,
	SLJIT_C_GREATER,
	SLJIT_C_GREATER_EQUAL,
	SLJIT_C_LESS,
	SLJIT_C_LESS_EQUAL,
	SLJIT_C_NOT_EQUAL,
	SLJIT_C_NOT_ZERO,
	SLJIT_C_SIG_GREATER,
	SLJIT_C_SIG_GREATER_EQUAL,
	SLJIT_C_SIG_LESS,
	SLJIT_C_SIG_LESS_EQUAL,
	SLJIT_C_ZERO,
};

static const char * const cmptypestrings[] = {
	"C_EQUAL",
	"C_GREATER",
	"C_GREATER_EQUAL",
	"C_LESS",
	"C_LESS_EQUAL",
	"C_NOT_EQUAL",
	"C_NOT_ZERO",
	"C_SIG_GREATER",
	"C_SIG_GREATER_EQUAL",
	"C_SIG_LESS",
	"C_SIG_LESS_EQUAL",
	"C_ZERO",
	NULL
};

/* sljit_compiler userdata. */
struct luaSljitCompiler
{
	struct sljit_compiler *compiler;
};

/* sljit_jump userdata. */
struct luaSljitJump
{
	struct sljit_jump *jump;
};

/* sljit_label userdata. */
struct luaSljitLabel
{
	struct sljit_label *label;
};

static sljit_sw
tosw(lua_State *L, int narg1, int narg2)
{
	sljit_sw rv;
	const char *s;
	char *se;
	size_t slen;
	lua_Number n;
	unsigned long long ull;
	int earg, type;
	const int base = 0; /* 8, 10, or 16 */
	bool err;

#if defined(SLJIT_32BIT_ARCHITECTURE) && SLJIT_32BIT_ARCHITECTURE
#define TABLE_WITH_NUMBERS "table with a uint32_t value"
#elif defined(SLJIT_64BIT_ARCHITECTURE) && SLJIT_64BIT_ARCHITECTURE
#define TABLE_WITH_NUMBERS "table with one or two uint32_t values"
#endif

	rv = 0;
	earg = narg1;

	type = lua_type(L, narg1);

	switch (type) {
		case LUA_TSTRING:
			s = lua_tolstring(L, narg1, &slen);
			if (s == NULL)
				luaL_argerror(L, earg, "lua_tolstring failed");

			errno = 0;
			err = false;

			ull = strtoull(s, &se, base);

			if (slen == 0 || se != s + slen)
				err = true;
			if (ull != (sljit_uw)ull)
				err = true;
			if (ull == LLONG_MAX && errno != 0)
				err = true;

			rv = ull;

			if (err)
				luaL_argerror(L, earg, ERR_NOCONV("sljit_sw"));

			return rv;

		case LUA_TTABLE:
			lua_rawgeti(L, narg1, 1);
			lua_rawgeti(L, narg1, 2);
			narg2 = lua_gettop(L);
			narg1 = narg2 - 1;
			type = lua_type(L, narg1);
			break;

		case LUA_TNUMBER:
			break;

		default:
			luaL_typerror(L, earg, "number, string or table");
	}

	if (type != LUA_TNUMBER)
		luaL_typerror(L, earg, TABLE_WITH_NUMBERS);

	n = lua_tonumber(L, narg1);

	if (n < 0 || n > UINT32_MAX || n != (lua_Integer)n)
		luaL_argerror(L, earg, ERR_NOCONV("uint32_t"));

	rv = n;

	if (narg2 != narg1) {
		s = NULL;
		type = lua_type(L, narg2);
		switch (type) {
			case LUA_TNIL:
			case LUA_TNONE:
				break;

			case LUA_TNUMBER:
				n = lua_tonumber(L, narg2);
				if (n < 0 || n > UINT32_MAX ||
				    n != (lua_Integer)n) {
					s = TABLE_WITH_NUMBERS;
				}

#if defined(SLJIT_32BIT_ARCHITECTURE) && SLJIT_32BIT_ARCHITECTURE
				/* Check overflow. */
				if (rv != 0)
					s = TABLE_WITH_NUMBERS;
#endif

				rv = (rv << 31 << 1) | (sljit_sw)n;
				break;

			default:
				s = (narg1 == earg) ?
				    "number" : TABLE_WITH_NUMBERS;
		}

		if (s != NULL)
			luaL_typerror(L, (narg1 == earg) ? narg2 : earg, s);
	}

	return rv;
}

/* XXX push userdata. */
static int
l_mem0(lua_State *L)
{

	lua_pushnumber(L, SLJIT_MEM0());

	return 1;
}

/* XXX push userdata. */
static int
l_mem1(lua_State *L)
{
	sljit_si r1;
{'fraction_non_alphanumeric': 0.12163715796734882, 'fraction_numerical': 0.011037020004598759, 'mean_word_length': 4.412881144990666, 'pattern_counts': {'":': 0, '<': 33, '<?xml version=': 0, '>': 25, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5468308', 'n_tokens_mistral': 8973, 'n_tokens_neox': 8234, 'n_words': 1641}