<commit_before>#include "master.hpp"

namespace factor
{

void factor_vm::primitive_bignum_to_fixnum()
{
	ctx->replace(tag_fixnum(bignum_to_fixnum(untag<bignum>(ctx->peek()))));
}

void factor_vm::primitive_float_to_fixnum()
{
	ctx->replace(tag_fixnum(float_to_fixnum(ctx->peek())));
}

/* does not allocate, even though from_signed_cell can allocate */
/* Division can only overflow when we are dividing the most negative fixnum
by -1. */
void factor_vm::primitive_fixnum_divint()
{
	fixnum y = untag_fixnum(ctx->pop());
	fixnum x = untag_fixnum(ctx->peek());
	fixnum result = x / y;
	if(result == -fixnum_min)
		/* Does not allocate */
		ctx->replace(from_signed_cell(-fixnum_min));
	else
		ctx->replace(tag_fixnum(result));
}

/* does not allocate, even though from_signed_cell can allocate */
void factor_vm::primitive_fixnum_divmod()
{
	cell *s0 = (cell *)(ctx->datastack);
	cell *s1 = (cell *)(ctx->datastack - sizeof(cell));
	fixnum y = untag_fixnum(*s0);
	fixnum x = untag_fixnum(*s1);
	if(y == -1 && x == fixnum_min)
	{
		/* Does not allocate */
		*s1 = from_signed_cell(-fixnum_min);
		*s0 = tag_fixnum(0);
	}
	else
	{
		*s1 = tag_fixnum(x / y);
		*s0 = tag_fixnum(x % y);
	}
}

/*
 * If we're shifting right by n bits, we won't overflow as long as none of the
 * high WORD_SIZE-TAG_BITS-n bits are set.
 */
inline fixnum factor_vm::sign_mask(fixnum x)
{
	return x >> (WORD_SIZE - 1);
}

inline fixnum factor_vm::branchless_max(fixnum x, fixnum y)
{
	return (x - ((x - y) & sign_mask(x - y)));
}

inline fixnum factor_vm::branchless_abs(fixnum x)
{
	return (x ^ sign_mask(x)) - sign_mask(x);
}

void factor_vm::primitive_fixnum_shift()
{
	fixnum y = untag_fixnum(ctx->pop());
	fixnum x = untag_fixnum(ctx->peek());

	if(x == 0)
		return;
	else if(y < 0)
	{
		y = branchless_max(y,-WORD_SIZE + 1);
		ctx->replace(tag_fixnum(x >> -y));
		return;
	}
	else if(y < WORD_SIZE - TAG_BITS)
	{
		fixnum mask = -((fixnum)1 << (WORD_SIZE - 1 - TAG_BITS - y));
		if(!(branchless_abs(x) & mask))
		{
			ctx->replace(tag_fixnum(x << y));
			return;
		}
	}

	ctx->replace(tag<bignum>(bignum_arithmetic_shift(
		fixnum_to_bignum(x),y)));
}

void factor_vm::primitive_fixnum_to_bignum()
{
	ctx->replace(tag<bignum>(fixnum_to_bignum(untag_fixnum(ctx->peek()))));
}

void factor_vm::primitive_float_to_bignum()
{
	ctx->replace(tag<bignum>(float_to_bignum(ctx->peek())));
}

#define POP_BIGNUMS(x,y) \
	bignum * y = untag<bignum>(ctx->pop()); \
	bignum * x = untag<bignum>(ctx->peek());

void factor_vm::primitive_bignum_eq()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag_boolean(bignum_equal_p(x,y)));
}

void factor_vm::primitive_bignum_add()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_add(x,y)));
}

void factor_vm::primitive_bignum_subtract()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_subtract(x,y)));
}

void factor_vm::primitive_bignum_multiply()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_multiply(x,y)));
}

void factor_vm::primitive_bignum_divint()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_quotient(x,y)));
}

void factor_vm::primitive_bignum_divmod()
{
	bignum *q, *r;
	POP_BIGNUMS(x,y);
	bignum_divide(x,y,&q,&r);
	ctx->replace(tag<bignum>(q));
	ctx->push(tag<bignum>(r));
}

void factor_vm::primitive_bignum_mod()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_remainder(x,y)));
}

void factor_vm::primitive_bignum_gcd()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_gcd(x,y)));
}

void factor_vm::primitive_bignum_and()
{
	POP_BIGNUMS(x,y);<commit_msg>vm: don't ctx-pop() in bignum_divmod.<commit_after>#include "master.hpp"

namespace factor
{

void factor_vm::primitive_bignum_to_fixnum()
{
	ctx->replace(tag_fixnum(bignum_to_fixnum(untag<bignum>(ctx->peek()))));
}

void factor_vm::primitive_float_to_fixnum()
{
	ctx->replace(tag_fixnum(float_to_fixnum(ctx->peek())));
}

/* does not allocate, even though from_signed_cell can allocate */
/* Division can only overflow when we are dividing the most negative fixnum
by -1. */
void factor_vm::primitive_fixnum_divint()
{
	fixnum y = untag_fixnum(ctx->pop());
	fixnum x = untag_fixnum(ctx->peek());
	fixnum result = x / y;
	if(result == -fixnum_min)
		/* Does not allocate */
		ctx->replace(from_signed_cell(-fixnum_min));
	else
		ctx->replace(tag_fixnum(result));
}

/* does not allocate, even though from_signed_cell can allocate */
void factor_vm::primitive_fixnum_divmod()
{
	cell *s0 = (cell *)(ctx->datastack);
	cell *s1 = (cell *)(ctx->datastack - sizeof(cell));
	fixnum y = untag_fixnum(*s0);
	fixnum x = untag_fixnum(*s1);
	if(y == -1 && x == fixnum_min)
	{
		/* Does not allocate */
		*s1 = from_signed_cell(-fixnum_min);
		*s0 = tag_fixnum(0);
	}
	else
	{
		*s1 = tag_fixnum(x / y);
		*s0 = tag_fixnum(x % y);
	}
}

/*
 * If we're shifting right by n bits, we won't overflow as long as none of the
 * high WORD_SIZE-TAG_BITS-n bits are set.
 */
inline fixnum factor_vm::sign_mask(fixnum x)
{
	return x >> (WORD_SIZE - 1);
}

inline fixnum factor_vm::branchless_max(fixnum x, fixnum y)
{
	return (x - ((x - y) & sign_mask(x - y)));
}

inline fixnum factor_vm::branchless_abs(fixnum x)
{
	return (x ^ sign_mask(x)) - sign_mask(x);
}

void factor_vm::primitive_fixnum_shift()
{
	fixnum y = untag_fixnum(ctx->pop());
	fixnum x = untag_fixnum(ctx->peek());

	if(x == 0)
		return;
	else if(y < 0)
	{
		y = branchless_max(y,-WORD_SIZE + 1);
		ctx->replace(tag_fixnum(x >> -y));
		return;
	}
	else if(y < WORD_SIZE - TAG_BITS)
	{
		fixnum mask = -((fixnum)1 << (WORD_SIZE - 1 - TAG_BITS - y));
		if(!(branchless_abs(x) & mask))
		{
			ctx->replace(tag_fixnum(x << y));
			return;
		}
	}

	ctx->replace(tag<bignum>(bignum_arithmetic_shift(
		fixnum_to_bignum(x),y)));
}

void factor_vm::primitive_fixnum_to_bignum()
{
	ctx->replace(tag<bignum>(fixnum_to_bignum(untag_fixnum(ctx->peek()))));
}

void factor_vm::primitive_float_to_bignum()
{
	ctx->replace(tag<bignum>(float_to_bignum(ctx->peek())));
}

#define POP_BIGNUMS(x,y) \
	bignum * y = untag<bignum>(ctx->pop()); \
	bignum * x = untag<bignum>(ctx->peek());

void factor_vm::primitive_bignum_eq()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag_boolean(bignum_equal_p(x,y)));
}

void factor_vm::primitive_bignum_add()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_add(x,y)));
}

void factor_vm::primitive_bignum_subtract()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_subtract(x,y)));
}

void factor_vm::primitive_bignum_multiply()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_multiply(x,y)));
}

void factor_vm::primitive_bignum_divint()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_quotient(x,y)));
}

void factor_vm::primitive_bignum_divmod()
{
	cell *s0 = (cell *)(ctx->datastack);
	cell *s1 = (cell *)(ctx->datastack - sizeof(cell));
	bignum *y = untag<bignum>(*s0);
	bignum *x = untag<bignum>(*s1);
	bignum *q, *r;
	bignum_divide(x, y, &q, &r);
	*s1 = tag<bignum>(q);
	*s0 = tag<bignum>(r);
}

void factor_vm::primitive_bignum_mod()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_remainder(x,y)));
}

void factor_vm::primitive_bignum_gcd()
{
	POP_BIGNUMS(x,y);
	ctx->replace(tag<bignum>(bignum_gcd(x,y)));
}

void factor_vm::primitive_bignum_and()
{
	POP_BIGNUMS(x,y);
{'fraction_non_alphanumeric': 0.18084216397099834, 'fraction_numerical': 0.005577244841048522, 'mean_word_length': 5.479674796747967, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 101, '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': '1587871', 'n_tokens_mistral': 3274, 'n_tokens_neox': 3204, 'n_words': 494}