/* Automatically generated by
	SmartSyntaxPluginCodeGenerator VMMaker.oscog-eem.2495 uuid: fcbf4c90-4c50-4ff3-8690-0edfded4f9c4
   from
	LargeIntegersPlugin VMMaker.oscog-eem.2495 uuid: fcbf4c90-4c50-4ff3-8690-0edfded4f9c4
 */
static char __buildInfo[] = "LargeIntegersPlugin VMMaker.oscog-eem.2495 uuid: fcbf4c90-4c50-4ff3-8690-0edfded4f9c4 " __DATE__ ;



#include "config.h"
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

/* Default EXPORT macro that does nothing (see comment in sq.h): */
#define EXPORT(returnType) returnType

/* Do not include the entire sq.h file but just those parts needed. */
#include "sqConfig.h"			/* Configuration options */
#include "sqVirtualMachine.h"	/*  The virtual machine proxy definition */
#include "sqPlatformSpecific.h"	/* Platform specific definitions */

#define true 1
#define false 0
#define null 0  /* using 'null' because nil is predefined in Think C */
#ifdef SQUEAK_BUILTIN_PLUGIN
# undef EXPORT
# define EXPORT(returnType) static returnType
#endif

#include "sqMemoryAccess.h"


/*** Constants ***/
#define PrimErrBadArgument 3
#define PrimErrNoMemory 9


/*** Function Prototypes ***/
static sqInt anyBitOfLargeIntfromto(sqInt anOop, sqInt start, sqInt stopArg);
static sqInt byteSizeOfCSI(sqInt csi);
static unsigned int cDigitAddlenwithleninto(unsigned int *pWordShort, sqInt shortLen, unsigned int *pWordLong, sqInt longLen, unsigned int *pWordRes);
static sqInt cDigitComparewithlen(unsigned int *pFirst, unsigned int *pSecond, sqInt len);
static sqInt cDigitCopyFromtolen(unsigned int *pFrom, unsigned int *pTo, sqInt len);
static sqInt cDigitDivlenremlenquolen(unsigned int *pDiv, sqInt divLen, unsigned int *pRem, sqInt remLen, unsigned int *pQuo, sqInt quoLen);
static sqInt cDigitHighBitlen(unsigned int *pUint32, sqInt len);
static sqInt cDigitLshiftfromlentolen(sqInt shiftCount, unsigned int *pFrom, sqInt lenFrom, unsigned int *pTo, sqInt lenTo);
static sqInt cDigitMontgomerylentimeslenmodulolenmInvModBinto(unsigned int *pFirst, sqInt firstLen, unsigned int *pSecond, sqInt secondLen, unsigned int *pThird, sqInt thirdLen, unsigned int mInv, unsigned int *pRes);
static unsigned int cDigitMultiplylenwithlenintolen(unsigned int *pWordShort, sqInt shortLen, unsigned int *pWordLong, sqInt longLen, unsigned int *pWordRes, sqInt resLen);
static unsigned int cDigitOfat(unsigned int *cPointer, sqInt zeroBasedDigitIndex);
static unsigned int cDigitOfatput(unsigned int *cPointer, sqInt zeroBasedDigitIndex, unsigned int aValue);
static sqInt cDigitOpshortlenlongleninto(sqInt opIndex, unsigned int *pWordShort, sqInt shortLen, unsigned int *pWordLong, sqInt longLen, unsigned int *pWordRes);
static sqInt cDigitReplacefromtowithstartingAt(unsigned int *pTo, sqInt start, sqInt stop, unsigned int *pFrom, sqInt repStart);
static sqInt cDigitRshiftfromlentolen(sqInt shiftCount, unsigned int *pFrom, sqInt lenFrom, unsigned int *pTo, sqInt lenTo);
static sqInt cDigitSublenwithleninto(unsigned int *pWordSmall, sqInt smallLen, unsigned int *pWordLarge, sqInt largeLen, unsigned int *pWordRes);
static sqInt cHighBit32(unsigned int anUnsignedInt32);
static sqInt createLargeFromSmallInteger(sqInt anOop);
static sqInt digitAddLargewith(sqInt firstInteger, sqInt secondInteger);
static sqInt digitBitLogicwithopIndex(sqInt firstInteger, sqInt secondInteger, sqInt opIx);
static sqInt digitCompareLargewith(sqInt firstInteger, sqInt secondInteger);
static sqInt digitDivLargewithnegative(sqInt firstInteger, sqInt secondInteger, sqInt neg);
static sqInt digitMontgomerytimesmodulomInvModB(sqInt firstLarge, sqInt secondLarge, sqInt thirdLarge, unsigned int mInv);
static sqInt digitMultiplyLargewithnegative(sqInt firstInteger, sqInt secondInteger, sqInt neg);
static sqInt digitOfCSIat(sqInt csi, sqInt ix);
static sqInt digitOfLargeIntat(sqInt aBytesOop, sqInt ix);
static sqInt digitSizeOfCSI(sqInt csi);
static sqInt digitSizeOfLargeInt(sqInt anOop);
static sqInt digitSubLargewith(sqInt firstInteger, sqInt secondInteger);
static sqInt digitLshift(sqInt anOop, sqInt shiftCount);
static sqInt digitRshiftlookfirst(sqInt anOop, sqInt shiftCount, sqInt a);
EXPORT(const char*) getModuleName(void);
static sqInt highBitOfLargeInt(sqInt anOop);
static sqInt isNormalized(sqInt aLargeInteger);
static sqInt largeIntgrowTo(sqInt aBytesObject, sqInt newByteLen);
static sqInt msg(char *s);
static sqInt normalizeNegative(sqInt aLargeNegativeInteger);
static sqInt normalizePositive(sqInt aLargePositiveInteger);
static sqInt normalize(sqInt aLargeInteger);
EXPORT(sqInt) primAnyBitFromTo(void);
EXPORT(sqInt) primDigitAdd(void);
EXPORT(sqInt) primDigitBitAnd(void);
EXPORT(sqInt) primDigitBitOr(void);
EXPORT(sqInt) primDigitBitShiftMagnitude(void);
EXPORT(sqInt) primDigitBitXor(void);
EXPORT(sqInt) primDigitCompare(void);
EXPORT(sqInt) primDigitDivNegative(void);
EXPORT(sqInt) primDigitMultiplyNegative(void);
EXPORT(sqInt) primDigitSubtract(void);
EXPORT(sqInt) primGetModuleName(void);
EXPORT(sqInt) primMontgomeryDigitLength(void);
EXPORT(sqInt) primMontgomeryTimesModulo(void);
EXPORT(sqInt) primNormalizeNegative(void);
EXPORT(sqInt) primNormalizePositive(void);
EXPORT(sqInt) setInterpreter(struct VirtualMachine *anInterpreter);
static sqInt sqAssert(sqInt aBool);
static unsigned char unsafeByteOfLargeIntat(sqInt bytesObj, sqInt ix);


/*** Variables ***/
static const int  andOpIndex = 0;

#if defined(SQUEAK_BUILTIN_PLUGIN)

# define isIntegerObject(oop) ((oop) & 1)

# if SPURVM
extern sqInt classIndexOf(sqInt);
#	define LargeNegativeIntegerClassIndex 32
#	define LargePositiveIntegerClassIndex 33
#	if BytesPerOop == 4
#	  define isImmediate(oop) ((oop) & 3)
#	else
#	  define isImmediate(oop) ((oop) & 7)
#	endif
#	define isKindOfInteger(oop) (isImmediate(oop) ? isIntegerObject(oop) : (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)
#	define isLargeIntegerObject(oop) (!isImmediate(oop) && (unsigned)(classIndexOf(oop) - LargeNegativeIntegerClassIndex) <= 1)
#	define isLargeNegativeIntegerObject(oop) (!isImmediate(oop) && classIndexOf(oop) == LargeNegativeIntegerClassIndex)
#	define isLargePositiveIntegerObject(oop) (!isImmediate(oop) && classIndexOf(oop) == LargePositiveIntegerClassIndex)
# endif /* SPURVM */
#endif /* defined(SQUEAK_BUILTIN_PLUGIN) */

#if !defined(isKindOfInteger)
# define isLargeNegativeIntegerObject(oop) (fetchClassOf(oop) == classLargeNegativeInteger())
# define isLargePositiveIntegerObject(oop) (fetchClassOf(oop) == classLargePositiveInteger())
# define isLargeIntegerObject(oop) (isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))
# define isKindOfInteger(oop) (isIntegerObject(oop) || isLargeNegativeIntegerObject(oop) || isLargePositiveIntegerObject(oop))
#endif

#if !defined(SQUEAK_BUILTIN_PLUGIN)
static sqInt (*booleanValueOf)(sqInt obj);
static sqInt (*classArray)(void);
static sqInt (*classLargeNegativeInteger)(void);
static sqInt (*classLargePositiveInteger)(void);
static sqInt (*classString)(void);
static sqInt (*failed)(void);
static sqInt (*falseObject)(void);
static sqInt (*fetchClassOf)(sqInt oop);
static void * (*firstIndexableField)(sqInt oop);
static sqInt (*instantiateClassindexableSize)(sqInt classPointer, sqInt size);
static sqInt (*integerObjectOf)(sqInt value);
static sqInt (*integerValueOf)(sqInt oop);
static sqInt (*isBooleanObject)(sqInt oop);
static sqInt (*isIntegerObject)(sqInt objectPointer);
static sqInt (*popthenPush)(sqInt nItems, sqInt oop);
static sqInt (*popRemappableOop)(void);
static usqInt (*positive32BitValueOf)(sqInt oop);
static sqInt (*primitiveFail)(void);
static sqInt (*primitiveFailFor)(sqInt reasonCode);
static sqInt (*pushRemappableOop)(sqInt oop);
static sqInt (*slotSizeOf)(sqInt oop);
static sqInt (*stObjectatput)(sqInt array, sqInt index, sqInt value);
static sqInt (*stackIntegerValue)(sqInt offset);
static sqInt (*stackValue)(sqInt offset);
static sqInt (*success)(sqInt aBoolean);
static sqInt (*trueObject)(void);
#else /* !defined(SQUEAK_BUILTIN_PLUGIN) */
extern sqInt booleanValueOf(sqInt obj);
extern sqInt classArray(void);
extern sqInt classLargeNegativeInteger(void);
extern sqInt classLargePositiveInteger(void);
extern sqInt classString(void);
extern sqInt failed(void);
extern sqInt falseObject(void);
extern sqInt fetchClassOf(sqInt oop);
extern void * firstIndexableField(sqInt oop);
extern sqInt instantiateClassindexableSize(sqInt classPointer, sqInt size);
extern sqInt integerObjectOf(sqInt value);
extern sqInt integerValueOf(sqInt oop);
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 15)
extern sqInt isBooleanObject(sqInt oop);
#else
# define isBooleanObject(oop) 0
#endif
#if !defined(isIntegerObject)
extern sqInt isIntegerObject(sqInt objectPointer);
#endif
extern sqInt popthenPush(sqInt nItems, sqInt oop);
extern sqInt popRemappableOop(void);
extern usqInt positive32BitValueOf(sqInt oop);
extern sqInt primitiveFail(void);
extern sqInt primitiveFailFor(sqInt reasonCode);
extern sqInt pushRemappableOop(sqInt oop);
extern sqInt slotSizeOf(sqInt oop);
extern sqInt stObjectatput(sqInt array, sqInt index, sqInt value);
extern sqInt stackIntegerValue(sqInt offset);
extern sqInt stackValue(sqInt offset);
extern sqInt success(sqInt aBoolean);
extern sqInt trueObject(void);
extern
#endif
struct VirtualMachine* interpreterProxy;
static const char *moduleName =
#ifdef SQUEAK_BUILTIN_PLUGIN
	"LargeIntegers v2.0 VMMaker.oscog-eem.2495 (i)"
#else
	"LargeIntegers v2.0 VMMaker.oscog-eem.2495 (e)"
#endif
;
static const int  orOpIndex = 1;
static const int  xorOpIndex = 2;



/*	Argument has to be a Large Integer! */
/*	Tests for any magnitude bits in the interval from start to stopArg. */

	/* LargeIntegersPlugin>>#anyBitOfLargeInt:from:to: */
static sqInt
anyBitOfLargeIntfromto(sqInt anOop, sqInt start, sqInt stopArg)
{
	unsigned int *cPointer;
	unsigned int digit;
	usqInt firstDigitIx;
	unsigned int firstMask;
	usqInt ix;
	usqInt lastDigitIx;
	unsigned int lastMask;
	sqInt magnitude;
	sqInt stop;
	sqInt zeroBasedDigitIndex;

	/* missing DebugCode */;
	if ((start < 1) || (stopArg < 1)) {
		return primitiveFail();
	}
	magnitude = anOop;
	stop = ((stopArg < (cDigitHighBitlen(((unsigned int *) (firstIndexableField(magnitude))), ((slotSizeOf(magnitude)) + 3) / 4))) ? stopArg : (cDigitHighBitlen(((unsigned int *) (firstIndexableField(magnitude))), ((slotSizeOf(magnitude)) + 3) / 4)));
	if (start > stop) {
		return 0;
	}
	firstDigitIx = ((start - 1) / 32) + 1;
	lastDigitIx = ((stop - 1) / 32) + 1;

	/* Note asUnsignedLong required to avoid ULLL suffix bug */
	firstMask = (((unsigned long)0xFFFFFFFFU)) << ((start - 1) & 0x1F);
	lastMask = ((usqInt) 0xFFFFFFFFU) >> (0x1F - ((stop - 1) & 0x1F));
	if (firstDigitIx == lastDigitIx) {
		/* begin cDigitOf:at: */
		cPointer = ((unsigned int *) (firstIndexableField(magnitude)));
		zeroBasedDigitIndex = firstDigitIx - 1;
		digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((cPointer[zeroBasedDigitIndex]));
		return (digit & (firstMask & lastMask)) != 0;
	}
	if (((cDigitOfat(((unsigned int *) (firstIndexableField(magnitude))), firstDigitIx - 1)) & firstMask) != 0) {
		return 1;
	}
	for (ix = (firstDigitIx + 1); ix < lastDigitIx; ix += 1) {
		if ((cDigitOfat(((unsigned int *) (firstIndexableField(magnitude))), ix - 1)) != 0) {
			return 1;
		}
	}
	if (((cDigitOfat(((unsigned int *) (firstIndexableField(magnitude))), lastDigitIx - 1)) & lastMask) != 0) {
		return 1;
	}
	return 0;
}


/*	Answer the number of bytes required to represent the value of a
	C-SmallInteger. 
 */

	/* LargeIntegersPlugin>>#byteSizeOfCSI: */
static sqInt
byteSizeOfCSI(sqInt csi)
{
	if (csi >= 0) {
		if (csi < 256) {
			return 1;
		}
		if (csi < 65536) {
			return 2;
		}
		if (csi < 0x1000000) {
			return 3;
		}
		
#    if BytesPerOop == 4
		return 4;
#    else /* BytesPerOop == 4 */
		if (csi < 0x100000000LL) {
			return 4;
		}
		if (csi < 0x10000000000LL) {
			return 5;
		}
		if (csi < 0x1000000000000LL) {
			return 6;
		}
		if (csi < 0x100000000000000LL) {
			return 7;
		}
		return 8;
#    endif /* BytesPerOop == 4 */
	}
	if (csi > -256) {
		return 1;
	}
	if (csi > -65536) {
		return 2;
	}
	if (csi > -16777216) {
		return 3;
	}
	
#  if BytesPerOop == 4
	return 4;
#  else /* BytesPerOop == 4 */
	if (csi > -4294967296LL) {
		return 4;
	}
	if (csi > -1099511627776LL) {
		return 5;
	}
	if (csi > -281474976710656LL) {
		return 6;
	}
	if (csi > -72057594037927936LL) {
		return 7;
	}
	return 8;
#  endif /* BytesPerOop == 4 */
	return 0;
}


/*	pWordRes len = longLen; returns over.. */

	/* LargeIntegersPlugin>>#cDigitAdd:len:with:len:into: */
static unsigned int
cDigitAddlenwithleninto(unsigned int *pWordShort, sqInt shortLen, unsigned int *pWordLong, sqInt longLen, unsigned int *pWordRes)
{
	unsigned long long accum;
	sqInt i;

	accum = 0;
	for (i = 0; i < shortLen; i += 1) {
		accum = ((accum >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordShort[i])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[i])));
		pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
	}
	for (i = shortLen; i < longLen; i += 1) {
		accum = (accum >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[i])));
		pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
	}
	return accum >> 32;
}


/*	Precondition: pFirst len = pSecond len. */

	/* LargeIntegersPlugin>>#cDigitCompare:with:len: */
static sqInt
cDigitComparewithlen(unsigned int *pFirst, unsigned int *pSecond, sqInt len)
{
	unsigned int firstDigit;
	sqInt ix;
	unsigned int secondDigit;

	ix = len - 1;
	while (ix >= 0) {
		if (((secondDigit = pSecond[ix])) != ((firstDigit = pFirst[ix]))) {
			if ((SQ_SWAP_4_BYTES_IF_BIGENDIAN(secondDigit)) < (SQ_SWAP_4_BYTES_IF_BIGENDIAN(firstDigit))) {
				return 1;
			}
			else {
				return -1;
			}
		}
		ix -= 1;
	}
	return 0;
}

	/* LargeIntegersPlugin>>#cDigitCopyFrom:to:len: */
static sqInt
cDigitCopyFromtolen(unsigned int *pFrom, unsigned int *pTo, sqInt len)
{
	sqInt i;

	for (i = 0; i < len; i += 1) {
		pTo[i] = (pFrom[i]);
	}
	return 0;
}

	/* LargeIntegersPlugin>>#cDigitDiv:len:rem:len:quo:len: */
static sqInt
cDigitDivlenremlenquolen(unsigned int *pDiv, sqInt divLen, unsigned int *pRem, sqInt remLen, unsigned int *pQuo, sqInt quoLen)
{
	unsigned long long a;
	unsigned long long b;
	sqInt cond;
	unsigned int dh;
	sqInt dl;
	unsigned int dnh;
	unsigned long long hi;
	sqInt i;
	sqInt j;
	sqInt k;
	sqInt l;
	unsigned long long lo;
	unsigned long long mul;
	unsigned long long q;
	sqInt ql;
	unsigned long long r1r2;
	unsigned int r3;
	unsigned long long t;


	/* Last actual byte of data (ST ix) */
	dl = divLen - 1;
	ql = quoLen;
	dh = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[dl - 1]));
	if (dl == 1) {
		dnh = 0;
	}
	else {
		dnh = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[dl - 2]));
	}
	for (k = 1; k <= ql; k += 1) {

		/* maintain quo*arg+rem=self */
		/* Estimate rem/div by dividing the leading two unint32 of rem by dh. */
		/* The estimate is q = qhi*16r100000000+qlo, where qhi and qlo are uint32. */

		/* r1 := rem digitAt: j. */
		j = (remLen + 1) - k;
		if ((SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 1]))) == dh) {
			q = 0xFFFFFFFFU;
		}
		else {

			/* Compute q = (r1,r2)//dh, t = (r1,r2)\\dh.
			   Note that r1,r2 are uint64, not uint32. */
			/* r2 := (rem digitAt: j - 2). */
			r1r2 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 1]));
			r1r2 = (r1r2 << 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 2])));
			t = r1r2 % dh;

			/* Next compute (hi,lo) := q*dnh */
			q = r1r2 / dh;
			mul = q * dnh;
			hi = mul >> 32;

			/* Correct overestimate of q.
			   Max of 2 iterations through loop -- see Knuth vol. 2 */
			lo = mul & 0xFFFFFFFFU;
			if (j < 3) {
				r3 = 0;
			}
			else {
				r3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 3]));
			}
			while (1) {
				if ((t < hi)
				 || ((t == hi)
				 && (r3 < lo))) {

					/* i.e. (t,r3) < (hi,lo) */
					q -= 1;
					if (hi == 0) {

						/* since hi is unsigned we must have this guard */
						cond = 0;
					}
					else {
						if (lo < dnh) {
							hi -= 1;
							lo = (lo + 0x100000000LL) - dnh;
						}
						else {
							lo -= dnh;
						}
						cond = hi >= dh;
					}
				}
				else {
					cond = 0;
				}
				if (!(cond)) break;
				hi -= dh;
			}
		}
		l = j - dl;
		a = 0;
		for (i = 1; i <= divLen; i += 1) {
			hi = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1]))) * (q >> 32);
			lo = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1]))) * (q & 0xFFFFFFFFU);
			b = ((SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[l - 1]))) - a) - (lo & 0xFFFFFFFFU);
			pRem[l - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((b & 0xFFFFFFFFU)));
			b = (b >> 32) | ((0 - (b >> 0x3F)) & 0xFFFFFFFF00000000ULL);
			a = (hi + (lo >> 32)) - b;
			l += 1;
		}
		if (a > 0) {

			/* Add div back into rem, decrease q by 1 */
			q -= 1;
			l = j - dl;
			a = 0;
			for (i = 1; i <= divLen; i += 1) {
				a = ((a >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[l - 1])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1])));
				pRem[l - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((a & 0xFFFFFFFFU)));
				l += 1;
			}
		}
		pQuo[quoLen - k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) q))));
	}
	return 0;
}


/*	Answer the index (in bits) of the high order bit of the receiver, or zero
	if the 
	receiver is zero. This method is allowed (and needed) for 
	LargeNegativeIntegers as well, since Squeak's LargeIntegers are
	sign/magnitude. Work with 32 bits digits. */

	/* LargeIntegersPlugin>>#cDigitHighBit:len: */
static sqInt
cDigitHighBitlen(unsigned int *pUint32, sqInt len)
{
	unsigned int lastDigit;
	sqInt realLength;

	realLength = len;
	do {
		if (realLength == 0) {
			return 0;
		}
	} while(((lastDigit = cDigitOfat(pUint32, (realLength -= 1)))) == 0);
	return (cHighBit32(lastDigit)) + (32 * realLength);
}


/*	C indexed! */

	/* LargeIntegersPlugin>>#cDigitLshift:from:len:to:len: */
static sqInt
cDigitLshiftfromlentolen(sqInt shiftCount, unsigned int *pFrom, sqInt lenFrom, unsigned int *pTo, sqInt lenTo)
{
	sqInt bitShift;
	unsigned int carry;
	unsigned int digit;
	sqInt digitShift;
	sqInt i;
	sqInt i1;
	sqInt limit;
	sqInt rshift;

	digitShift = shiftCount / 32;
	bitShift = shiftCount % 32;

	/* Note: 0 is endian neutral, use direct access */
	limit = digitShift - 1;
	for (i = 0; i <= limit; i += 1) {
		pTo[i] = 0;
	}
	if (bitShift == 0) {

		/* Fast version for digit-aligned shifts */
		/* C indexed! */
		/* begin cDigitCopyFrom:to:len: */
		for (i1 = 0; i1 < (((lenTo - 1) - digitShift) + 1); i1 += 1) {
			(pTo + digitShift)[i1] = ((pFrom)[i1]);
		}
		return 0;
	}
	rshift = 32 - bitShift;
	carry = 0;
	limit = lenFrom - 1;
	for (i = 0; i <= limit; i += 1) {
		digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFrom[i]));
		pTo[i + digitShift] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(((carry | (((usqInt)(digit) << bitShift))) & 0xFFFFFFFFU)));
		carry = ((usqInt) digit) >> rshift;
	}
	if (!(carry == 0)) {
		pTo[lenTo - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
	}
	return 0;
}

	/* LargeIntegersPlugin>>#cDigitMontgomery:len:times:len:modulo:len:mInvModB:into: */
static sqInt
cDigitMontgomerylentimeslenmodulolenmInvModBinto(unsigned int *pFirst, sqInt firstLen, unsigned int *pSecond, sqInt secondLen, unsigned int *pThird, sqInt thirdLen, unsigned int mInv, unsigned int *pRes)
{
	unsigned long long accum;
	unsigned long long accum2;
	unsigned long long accum3;
	sqInt i;
	sqInt k;
	unsigned int lastDigit;
	sqInt limit1;
	sqInt limit2;
	sqInt limit3;
	unsigned long long u;

	limit1 = firstLen - 1;
	limit2 = secondLen - 1;
	limit3 = thirdLen - 1;
	lastDigit = 0;
	for (i = 0; i <= limit1; i += 1) {
		accum3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFirst[i]));
		accum3 = (accum3 * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pSecond[0])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[0])));
		u = (accum3 * mInv) & 0xFFFFFFFFU;
		accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[0])));
		accum = (accum2 & 0xFFFFFFFFU) + (accum3 & 0xFFFFFFFFU);
		accum = ((accum >> 32) + (accum2 >> 32)) + (accum3 >> 32);
		for (k = 1; k <= limit2; k += 1) {
			accum3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFirst[i]));
			accum3 = (accum3 * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pSecond[k])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])));
			accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
			accum = (accum + (accum2 & 0xFFFFFFFFU)) + (accum3 & 0xFFFFFFFFU);
			pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			accum = ((accum >> 32) + (accum2 >> 32)) + (accum3 >> 32);
		}
		for (k = secondLen; k <= limit3; k += 1) {
			accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
			accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])))) + (accum2 & 0xFFFFFFFFU);
			pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			accum = (accum >> 32) + (accum2 >> 32);
		}
		accum += lastDigit;
		pRes[limit3] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
		lastDigit = accum >> 32;
	}
	for (i = firstLen; i <= limit3; i += 1) {
		accum = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[0]));
		u = (accum * mInv) & 0xFFFFFFFFU;
		accum += u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[0])));
		accum = accum >> 32;
		for (k = 1; k <= limit3; k += 1) {
			accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
			accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])))) + (accum2 & 0xFFFFFFFFU);
			pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			accum = (accum >> 32) + (accum2 >> 32);
		}
		accum += lastDigit;
		pRes[limit3] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
		lastDigit = accum >> 32;
	}
	if (!((lastDigit == 0)
		 && ((cDigitComparewithlen(pThird, pRes, thirdLen)) == 1))) {

		/* self cDigitSub: pThird len: thirdLen with: pRes len: thirdLen into: pRes */
		accum = 0;
		for (i = 0; i <= limit3; i += 1) {
			accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[i])))) - (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[i])));
			pRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			accum = 0 - (accum >> 0x3F);
		}
	}
	return 0;
}

	/* LargeIntegersPlugin>>#cDigitMultiply:len:with:len:into:len: */
static unsigned int
cDigitMultiplylenwithlenintolen(unsigned int *pWordShort, sqInt shortLen, unsigned int *pWordLong, sqInt longLen, unsigned int *pWordRes, sqInt resLen)
{
	unsigned long long ab;
	unsigned int carry;
	unsigned int digit;
	sqInt i;
	sqInt j;
	sqInt k;
	sqInt limitLong;
	sqInt limitShort;

	if ((shortLen == 1)
	 && ((pWordShort[0]) == 0)) {
		return 0;
	}
	if ((longLen == 1)
	 && ((pWordLong[0]) == 0)) {
		return 0;
	}
	limitShort = shortLen - 1;
	limitLong = longLen - 1;
	for (i = 0; i <= limitShort; i += 1) {
		if (((digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordShort[i])))) != 0) {
			k = i;

			/* Loop invariant: 0<=carry<=16rFFFFFFFF, k=i+j-1 (ST) */
			/* -> Loop invariant: 0<=carry<=16rFFFFFFFF, k=i+j (C) (?) */
			carry = 0;
			for (j = 0; j <= limitLong; j += 1) {
				ab = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[j]));
				ab = ((ab * digit) + carry) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordRes[k])));
				carry = ab >> 32;
				pWordRes[k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((ab & 0xFFFFFFFFU)));
				k += 1;
			}
			if (k < resLen) {
				pWordRes[k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
			}
		}
	}
	return 0;
}

	/* LargeIntegersPlugin>>#cDigitOf:at: */
static unsigned int
cDigitOfat(unsigned int *cPointer, sqInt zeroBasedDigitIndex)
{
	return SQ_SWAP_4_BYTES_IF_BIGENDIAN((cPointer[zeroBasedDigitIndex]));
}

	/* LargeIntegersPlugin>>#cDigitOf:at:put: */
static unsigned int
cDigitOfatput(unsigned int *cPointer, sqInt zeroBasedDigitIndex, unsigned int aValue)
{
	return cPointer[zeroBasedDigitIndex] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(aValue));
}


/*	pWordRes len = longLen.
	NOTE: we don't bother with endianness here, those bit opes are
	endian-neutral 
 */

	/* LargeIntegersPlugin>>#cDigitOp:short:len:long:len:into: */
static sqInt
cDigitOpshortlenlongleninto(sqInt opIndex, unsigned int *pWordShort, sqInt shortLen, unsigned int *pWordLong, sqInt longLen, unsigned int *pWordRes)
{
	sqInt i;
	sqInt limit;

	limit = shortLen - 1;
	if (opIndex == andOpIndex) {
		for (i = 0; i <= limit; i += 1) {
			pWordRes[i] = ((pWordShort[i]) & (pWordLong[i]));
		}
		limit = longLen - 1;
		for (i = shortLen; i <= limit; i += 1) {
			pWordRes[i] = 0;
		}
		return 0;
	}
	if (opIndex == orOpIndex) {
		for (i = 0; i <= limit; i += 1) {
			pWordRes[i] = ((pWordShort[i]) | (pWordLong[i]));
		}
		limit = longLen - 1;
		for (i = shortLen; i <= limit; i += 1) {
			pWordRes[i] = (pWordLong[i]);
		}
		return 0;
	}
	if (opIndex == xorOpIndex) {
		for (i = 0; i <= limit; i += 1) {
			pWordRes[i] = ((pWordShort[i]) ^ (pWordLong[i]));
		}
		limit = longLen - 1;
		for (i = shortLen; i <= limit; i += 1) {
			pWordRes[i] = (pWordLong[i]);
		}
		return 0;
	}
	return primitiveFail();
}


/*	C indexed! */

	/* LargeIntegersPlugin>>#cDigitReplace:from:to:with:startingAt: */
static sqInt
cDigitReplacefromtowithstartingAt(unsigned int *pTo, sqInt start, sqInt stop, unsigned int *pFrom, sqInt repStart)
{
	sqInt i;

	/* begin cDigitCopyFrom:to:len: */
	for (i = 0; i < ((stop - start) + 1); i += 1) {
		(pTo + start)[i] = ((pFrom + repStart)[i]);
	}
	return 0;
}

	/* LargeIntegersPlugin>>#cDigitRshift:from:len:to:len: */
static sqInt
cDigitRshiftfromlentolen(sqInt shiftCount, unsigned int *pFrom, sqInt lenFrom, unsigned int *pTo, sqInt lenTo)
{
	sqInt bitShift;
	unsigned int carry;
	unsigned int digit;
	sqInt digitShift;
	sqInt i;
	sqInt j;
	sqInt leftShift;
	sqInt limit;
	sqInt start;

	digitShift = shiftCount / 32;
	bitShift = shiftCount % 32;
	if (bitShift == 0) {

		/* Fast version for digit-aligned shifts */
		/* C indexed! */
		/* begin cDigitReplace:from:to:with:startingAt: */
		for (i = 0; i < (((lenTo - 1)) + 1); i += 1) {
			(pTo)[i] = ((pFrom + digitShift)[i]);
		}
		return 0;
	}
	leftShift = 32 - bitShift;
	carry = ((usqInt) (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFrom[digitShift])))) >> bitShift;
	start = digitShift + 1;
	limit = lenFrom - 1;
	for (j = start; j <= limit; j += 1) {
		/* begin cDigitOf:at: */
		digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFrom[j]));
		/* begin cDigitOf:at:put: */
		pTo[j - start] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(((carry | (((usqInt)(digit) << leftShift))) & 0xFFFFFFFFU)));
		carry = ((usqInt) digit) >> bitShift;
	}
	if (!(carry == 0)) {
		/* begin cDigitOf:at:put: */
		pTo[lenTo - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
	}
	return 0;
}

	/* LargeIntegersPlugin>>#cDigitSub:len:with:len:into: */
static sqInt
cDigitSublenwithleninto(unsigned int *pWordSmall, sqInt smallLen, unsigned int *pWordLarge, sqInt largeLen, unsigned int *pWordRes)
{
	sqInt i;
	unsigned long long z;

	z = 0;
	for (i = 0; i < smallLen; i += 1) {
		z = (z + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLarge[i])))) - (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordSmall[i])));
		/* begin cDigitOf:at:put: */
		pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) (z & 0xFFFFFFFFU)))));
		z = 0 - (z >> 0x3F);
	}
	for (i = smallLen; i < largeLen; i += 1) {
		z += SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLarge[i]));
		/* begin cDigitOf:at:put: */
		pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) (z & 0xFFFFFFFFU)))));
		z = 0 - (z >> 0x3F);
	}
	return 0;
}


/*	Answer the index of the high order bit of the argument, or zero if the 
	argument is zero. */

	/* LargeIntegersPlugin>>#cHighBit32: */
static sqInt
cHighBit32(unsigned int anUnsignedInt32)
{
	sqInt bitNo;
	unsigned int shifted;

	shifted = anUnsignedInt32;
	bitNo = 0;
	if (!(shifted < (1U << 16))) {
		shifted = ((usqInt) shifted) >> 16;
		bitNo += 16;
	}
	if (!(shifted < (1U << 8))) {
		shifted = ((usqInt) shifted) >> 8;
		bitNo += 8;
	}
	if (!(shifted < (1U << 4))) {
		shifted = ((usqInt) shifted) >> 4;
		bitNo += 4;
	}
	if (!(shifted < (1U << 2))) {
		shifted = ((usqInt) shifted) >> 2;
		bitNo += 2;
	}
	if (!(shifted < (1U << 1))) {
		shifted = ((usqInt) shifted) >> 1;
		bitNo += 1;
	}
	return bitNo + shifted;
}


/*	anOop has to be a SmallInteger! */

	/* LargeIntegersPlugin>>#createLargeFromSmallInteger: */
static sqInt
createLargeFromSmallInteger(sqInt anOop)
{
	unsigned int aValue;
	sqInt byteSize;
	sqInt digitSize;
	sqInt ix;
	unsigned int *pDigit;
	sqInt res;
	sqInt val;

	val = integerValueOf(anOop);
	/* begin byteSizeOfCSI: */
	if (val >= 0) {
		if (val < 256) {
			byteSize = 1;
			goto l2;
		}
		if (val < 65536) {
			byteSize = 2;
			goto l2;
		}
		if (val < 0x1000000) {
			byteSize = 3;
			goto l2;
		}
		
#    if BytesPerOop == 4
		byteSize = 4;
		goto l2;
#    else /* BytesPerOop == 4 */
		if (val < 0x100000000LL) {
			byteSize = 4;
			goto l2;
		}
		if (val < 0x10000000000LL) {
			byteSize = 5;
			goto l2;
		}
		if (val < 0x1000000000000LL) {
			byteSize = 6;
			goto l2;
		}
		if (val < 0x100000000000000LL) {
			byteSize = 7;
			goto l2;
		}
		byteSize = 8;
		goto l2;
#    endif /* BytesPerOop == 4 */
	}
	if (val > -256) {
		byteSize = 1;
		goto l2;
	}
	if (val > -65536) {
		byteSize = 2;
		goto l2;
	}
	if (val > -16777216) {
		byteSize = 3;
		goto l2;
	}
	
#  if BytesPerOop == 4
	byteSize = 4;
	goto l2;
#  else /* BytesPerOop == 4 */
	if (val > -4294967296LL) {
		byteSize = 4;
		goto l2;
	}
	if (val > -1099511627776LL) {
		byteSize = 5;
		goto l2;
	}
	if (val > -281474976710656LL) {
		byteSize = 6;
		goto l2;
	}
	if (val > -72057594037927936LL) {
		byteSize = 7;
		goto l2;
	}
	byteSize = 8;
	goto l2;
#  endif /* BytesPerOop == 4 */
	l2:	/* end byteSizeOfCSI: */;
	res = instantiateClassindexableSize((val < 0
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), byteSize);
	pDigit = ((unsigned int *) (firstIndexableField(res)));
	digitSize = (byteSize + 3) / 4;
	for (ix = 1; ix <= digitSize; ix += 1) {
		/* begin cDigitOf:at:put: */
		aValue = ((unsigned int) (((usqInt) ((val < 0
	? 0 - val
	: val))) >> ((ix - 1) * 32)));
		pDigit[ix - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(aValue));
	}
	return res;
}


/*	Does not need to normalize! */

	/* LargeIntegersPlugin>>#digitAddLarge:with: */
static sqInt
digitAddLargewith(sqInt firstInteger, sqInt secondInteger)
{
	unsigned long long accum;
	unsigned int *cPointer;
	sqInt firstDigitLen;
	sqInt i;
	sqInt i1;
	sqInt longDigitLen;
	sqInt longInt;
	sqInt neg;
	sqInt newSum;
	unsigned int over;
	unsigned int *pFrom;
	unsigned int *pTo;
	unsigned int *pWordLong;
	unsigned int *pWordRes;
	unsigned int *pWordShort;
	sqInt secondDigitLen;
	sqInt shortDigitLen;
	sqInt shortInt;
	sqInt sum;

	firstDigitLen = ((slotSizeOf(firstInteger)) + 3) / 4;
	secondDigitLen = ((slotSizeOf(secondInteger)) + 3) / 4;
	neg = isLargeNegativeIntegerObject(firstInteger);
	if (firstDigitLen <= secondDigitLen) {
		shortInt = firstInteger;
		shortDigitLen = firstDigitLen;
		longInt = secondInteger;
		longDigitLen = secondDigitLen;
	}
	else {
		shortInt = secondInteger;
		shortDigitLen = secondDigitLen;
		longInt = firstInteger;
		longDigitLen = firstDigitLen;
	}
	
#if SPURVM
	/* begin createLargeIntegerNeg:digitLength: */
	sum = instantiateClassindexableSize((neg
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), longDigitLen * 4);

#else /* SPURVM */
	pushRemappableOop(shortInt);
	pushRemappableOop(longInt);
	/* begin createLargeIntegerNeg:digitLength: */
	sum = instantiateClassindexableSize((neg
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), longDigitLen * 4);
	longInt = popRemappableOop();
	shortInt = popRemappableOop()
#endif /* SPURVM */
;
	if (!(sum)) {
		return primitiveFailFor(PrimErrNoMemory);
	}
	/* begin cDigitAdd:len:with:len:into: */
	pWordShort = ((unsigned int *) (firstIndexableField(shortInt)));
	pWordLong = ((unsigned int *) (firstIndexableField(longInt)));
	pWordRes = ((unsigned int *) (firstIndexableField(sum)));
	accum = 0;
	for (i1 = 0; i1 < shortDigitLen; i1 += 1) {
		accum = ((accum >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordShort[i1])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[i1])));
		pWordRes[i1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
	}
	for (i1 = shortDigitLen; i1 < longDigitLen; i1 += 1) {
		accum = (accum >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[i1])));
		pWordRes[i1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
	}
	over = accum >> 32;
	if (over > 0) {

		/* sum := sum growby: 1. */
		
#if SPURVM
		/* begin createLargeIntegerNeg:byteLength: */
		newSum = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), (longDigitLen * 4) + 1);

#else /* SPURVM */
		pushRemappableOop(sum);
		/* begin createLargeIntegerNeg:byteLength: */
		newSum = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), (longDigitLen * 4) + 1);
		sum = popRemappableOop()
#endif /* SPURVM */
;
		if (!(newSum)) {
			return primitiveFailFor(PrimErrNoMemory);
		}
		/* begin cDigitCopyFrom:to:len: */
		pFrom = ((unsigned int *) (firstIndexableField(sum)));
		pTo = ((unsigned int *) (firstIndexableField(newSum)));
		for (i = 0; i < longDigitLen; i += 1) {
			pTo[i] = (pFrom[i]);
		}

		/* C index! */
		sum = newSum;
		/* begin cDigitOf:at:put: */
		cPointer = ((unsigned int *) (firstIndexableField(sum)));
		cPointer[longDigitLen] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(over));
	}
	else {
		sum = (neg
			? normalizeNegative(sum)
			: normalizePositive(sum));
	}
	return sum;
}


/*	Bit logic here is only implemented for positive integers or Zero;
	if rec or arg is negative, it fails. */

	/* LargeIntegersPlugin>>#digitBitLogic:with:opIndex: */
static sqInt
digitBitLogicwithopIndex(sqInt firstInteger, sqInt secondInteger, sqInt opIx)
{
	sqInt firstLarge;
	sqInt firstLen;
	sqInt i;
	sqInt limit;
	sqInt longLarge;
	sqInt longLen;
	unsigned int *pWordLong;
	unsigned int *pWordRes;
	unsigned int *pWordShort;
	sqInt result;
	sqInt secondLarge;
	sqInt secondLen;
	sqInt shortLarge;
	sqInt shortLen;

	if (isIntegerObject(firstInteger)) {
		if ((integerValueOf(firstInteger)) < 0) {
			return primitiveFail();
		}
		
#if SPURVM
		firstLarge = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondInteger);
		firstLarge = createLargeFromSmallInteger(firstInteger);
		secondInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		if (!(isLargePositiveIntegerObject(firstInteger))) {
			return primitiveFail();
		}
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {
		if ((integerValueOf(secondInteger)) < 0) {
			return primitiveFail();
		}
		
#if SPURVM
		secondLarge = createLargeFromSmallInteger(secondInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		secondLarge = createLargeFromSmallInteger(secondInteger);
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		if (!(isLargePositiveIntegerObject(secondInteger))) {
			return primitiveFail();
		}
		secondLarge = secondInteger;
	}
	/* begin byteSizeOfLargeInt: */
	firstLen = slotSizeOf(firstLarge);
	/* begin byteSizeOfLargeInt: */
	secondLen = slotSizeOf(secondLarge);
	if (firstLen < secondLen) {
		shortLen = firstLen;
		shortLarge = firstLarge;
		longLen = secondLen;
		longLarge = secondLarge;
	}
	else {
		shortLen = secondLen;
		shortLarge = secondLarge;
		longLen = firstLen;
		longLarge = firstLarge;
	}
	
#if SPURVM
	result = instantiateClassindexableSize(classLargePositiveInteger(), longLen);

#else /* SPURVM */
	pushRemappableOop(shortLarge);
	pushRemappableOop(longLarge);
	result = instantiateClassindexableSize(classLargePositiveInteger(), longLen);
	longLarge = popRemappableOop();
	shortLarge = popRemappableOop()
#endif /* SPURVM */
;
	if (!(result)) {
		return primitiveFailFor(PrimErrNoMemory);
	}
	/* begin cDigitOp:short:len:long:len:into: */
	pWordShort = ((unsigned int *) (firstIndexableField(shortLarge)));
	pWordLong = ((unsigned int *) (firstIndexableField(longLarge)));
	pWordRes = ((unsigned int *) (firstIndexableField(result)));
	limit = ((shortLen + 3) / 4) - 1;
	if (opIx == andOpIndex) {
		for (i = 0; i <= limit; i += 1) {
			pWordRes[i] = ((pWordShort[i]) & (pWordLong[i]));
		}
		limit = ((longLen + 3) / 4) - 1;
		for (i = ((shortLen + 3) / 4); i <= limit; i += 1) {
			pWordRes[i] = 0;
		}
		goto l3;
	}
	if (opIx == orOpIndex) {
		for (i = 0; i <= limit; i += 1) {
			pWordRes[i] = ((pWordShort[i]) | (pWordLong[i]));
		}
		limit = ((longLen + 3) / 4) - 1;
		for (i = ((shortLen + 3) / 4); i <= limit; i += 1) {
			pWordRes[i] = (pWordLong[i]);
		}
		goto l3;
	}
	if (opIx == xorOpIndex) {
		for (i = 0; i <= limit; i += 1) {
			pWordRes[i] = ((pWordShort[i]) ^ (pWordLong[i]));
		}
		limit = ((longLen + 3) / 4) - 1;
		for (i = ((shortLen + 3) / 4); i <= limit; i += 1) {
			pWordRes[i] = (pWordLong[i]);
		}
		goto l3;
	}
	primitiveFail();
	l3:	/* end cDigitOp:short:len:long:len:into: */;
	if (failed()) {
		return 0;
	}
	return normalizePositive(result);
}


/*	Compare the magnitude of firstInteger with that of secondInteger. 
	Return a code of 1, 0, -1 for firstInteger >, = , < secondInteger */

	/* LargeIntegersPlugin>>#digitCompareLarge:with: */
static sqInt
digitCompareLargewith(sqInt firstInteger, sqInt secondInteger)
{
	sqInt firstDigitLen;
	sqInt secondDigitLen;

	firstDigitLen = ((slotSizeOf(firstInteger)) + 3) / 4;
	secondDigitLen = ((slotSizeOf(secondInteger)) + 3) / 4;
	if (secondDigitLen != firstDigitLen) {
		if (secondDigitLen > firstDigitLen) {
			return integerObjectOf(-1);
		}
		else {
			return integerObjectOf(1);
		}
	}
	return integerObjectOf((cDigitComparewithlen(((unsigned int *) (firstIndexableField(firstInteger))), ((unsigned int *) (firstIndexableField(secondInteger))), firstDigitLen)));
}


/*	Does not normalize. */
/*	Division by zero has to be checked in caller. */

	/* LargeIntegersPlugin>>#digitDivLarge:with:negative: */
static sqInt
digitDivLargewithnegative(sqInt firstInteger, sqInt secondInteger, sqInt neg)
{
	unsigned long long a;
	unsigned long long b;
	sqInt cond;
	sqInt d;
	unsigned int dh;
	sqInt div;
	sqInt divLen;
	sqInt dl;
	unsigned int dnh;
	sqInt firstDigitLen;
	unsigned long long hi;
	sqInt i;
	sqInt j;
	sqInt k;
	sqInt l;
	unsigned long long lo;
	unsigned long long mul;
	unsigned int *pDiv;
	unsigned int *pQuo;
	unsigned int *pRem;
	unsigned long long q;
	sqInt ql;
	sqInt quo;
	sqInt quoDigitLen;
	sqInt quoLen;
	unsigned long long r1r2;
	unsigned int r3;
	sqInt rem;
	sqInt remLen;
	sqInt result;
	sqInt secondDigitLen;
	unsigned long long t;

	firstDigitLen = ((slotSizeOf(firstInteger)) + 3) / 4;
	secondDigitLen = ((slotSizeOf(secondInteger)) + 3) / 4;
	quoDigitLen = (firstDigitLen - secondDigitLen) + 1;
	if (quoDigitLen <= 0) {
		
#if SPURVM
		result = instantiateClassindexableSize(classArray(), 2);

#else /* SPURVM */
		pushRemappableOop(firstInteger);
		result = instantiateClassindexableSize(classArray(), 2);
		firstInteger = popRemappableOop()
#endif /* SPURVM */
;
		if (!(result == null)) {
			stObjectatput(result, 1, integerObjectOf(0));
			stObjectatput(result, 2, firstInteger);
		}
		return result;
	}
	d = 32 - (cHighBit32(cDigitOfat(((unsigned int *) (firstIndexableField(secondInteger))), secondDigitLen - 1)));
	
#if SPURVM
	div = digitLshift(secondInteger, d);
	if (!(div == null)) {
		div = largeIntgrowTo(div, ((((slotSizeOf(div)) + 3) / 4) + 1) * 4);
	}
	if (!(div)) {
		return div;
	}

#else /* SPURVM */
	pushRemappableOop(firstInteger);
	div = digitLshift(secondInteger, d);
	if (!(div == null)) {
		div = largeIntgrowTo(div, ((((slotSizeOf(div)) + 3) / 4) + 1) * 4);
	}
	if (!(div)) {
		return div;
	}
	firstInteger = popRemappableOop()
#endif /* SPURVM */
;
	
#if SPURVM
	rem = digitLshift(firstInteger, d);
	if (!(rem == null)) {
		if ((((slotSizeOf(rem)) + 3) / 4) == firstDigitLen) {
			rem = largeIntgrowTo(rem, (firstDigitLen + 1) * 4);
		}
	}
	if (!(rem)) {
		return rem;
	}

#else /* SPURVM */
	pushRemappableOop(div);
	rem = digitLshift(firstInteger, d);
	if (!(rem == null)) {
		if ((((slotSizeOf(rem)) + 3) / 4) == firstDigitLen) {
			rem = largeIntgrowTo(rem, (firstDigitLen + 1) * 4);
		}
	}
	if (!(rem)) {
		return rem;
	}
	div = popRemappableOop()
#endif /* SPURVM */
;
	
#if SPURVM
	/* begin createLargeIntegerNeg:digitLength: */
	quo = instantiateClassindexableSize((neg
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), quoDigitLen * 4);

#else /* SPURVM */
	pushRemappableOop(div);
	pushRemappableOop(rem);
	/* begin createLargeIntegerNeg:digitLength: */
	quo = instantiateClassindexableSize((neg
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), quoDigitLen * 4);
	rem = popRemappableOop();
	div = popRemappableOop()
#endif /* SPURVM */
;
	/* begin cDigitDiv:len:rem:len:quo:len: */
	pDiv = ((unsigned int *) (firstIndexableField(div)));
	divLen = ((slotSizeOf(div)) + 3) / 4;
	pRem = ((unsigned int *) (firstIndexableField(rem)));
	remLen = ((slotSizeOf(rem)) + 3) / 4;
	pQuo = ((unsigned int *) (firstIndexableField(quo)));
	quoLen = ((slotSizeOf(quo)) + 3) / 4;

	/* Last actual byte of data (ST ix) */
	dl = divLen - 1;
	ql = quoLen;
	dh = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[dl - 1]));
	if (dl == 1) {
		dnh = 0;
	}
	else {
		dnh = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[dl - 2]));
	}
	for (k = 1; k <= ql; k += 1) {

		/* maintain quo*arg+rem=self */
		/* Estimate rem/div by dividing the leading two unint32 of rem by dh. */
		/* The estimate is q = qhi*16r100000000+qlo, where qhi and qlo are uint32. */

		/* r1 := rem digitAt: j. */
		j = (remLen + 1) - k;
		if ((SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 1]))) == dh) {
			q = 0xFFFFFFFFU;
		}
		else {

			/* Compute q = (r1,r2)//dh, t = (r1,r2)\\dh.
			   Note that r1,r2 are uint64, not uint32. */
			/* r2 := (rem digitAt: j - 2). */
			r1r2 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 1]));
			r1r2 = (r1r2 << 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 2])));
			t = r1r2 % dh;

			/* Next compute (hi,lo) := q*dnh */
			q = r1r2 / dh;
			mul = q * dnh;
			hi = mul >> 32;

			/* Correct overestimate of q.
			   Max of 2 iterations through loop -- see Knuth vol. 2 */
			lo = mul & 0xFFFFFFFFU;
			if (j < 3) {
				r3 = 0;
			}
			else {
				r3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 3]));
			}
			while (1) {
				if ((t < hi)
				 || ((t == hi)
				 && (r3 < lo))) {

					/* i.e. (t,r3) < (hi,lo) */
					q -= 1;
					if (hi == 0) {

						/* since hi is unsigned we must have this guard */
						cond = 0;
					}
					else {
						if (lo < dnh) {
							hi -= 1;
							lo = (lo + 0x100000000LL) - dnh;
						}
						else {
							lo -= dnh;
						}
						cond = hi >= dh;
					}
				}
				else {
					cond = 0;
				}
				if (!(cond)) break;
				hi -= dh;
			}
		}
		l = j - dl;
		a = 0;
		for (i = 1; i <= divLen; i += 1) {
			hi = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1]))) * (q >> 32);
			lo = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1]))) * (q & 0xFFFFFFFFU);
			b = ((SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[l - 1]))) - a) - (lo & 0xFFFFFFFFU);
			pRem[l - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((b & 0xFFFFFFFFU)));
			b = (b >> 32) | ((0 - (b >> 0x3F)) & 0xFFFFFFFF00000000ULL);
			a = (hi + (lo >> 32)) - b;
			l += 1;
		}
		if (a > 0) {

			/* Add div back into rem, decrease q by 1 */
			q -= 1;
			l = j - dl;
			a = 0;
			for (i = 1; i <= divLen; i += 1) {
				a = ((a >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[l - 1])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1])));
				pRem[l - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((a & 0xFFFFFFFFU)));
				l += 1;
			}
		}
		pQuo[quoLen - k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) q))));
	}
	
#if SPURVM
	rem = digitRshiftlookfirst(rem, d, (((slotSizeOf(div)) + 3) / 4) - 1);

#else /* SPURVM */
	pushRemappableOop(quo);
	rem = digitRshiftlookfirst(rem, d, (((slotSizeOf(div)) + 3) / 4) - 1);
	quo = popRemappableOop()
#endif /* SPURVM */
;
	
#if SPURVM
	result = instantiateClassindexableSize(classArray(), 2);

#else /* SPURVM */
	pushRemappableOop(quo);
	pushRemappableOop(rem);
	result = instantiateClassindexableSize(classArray(), 2);
	rem = popRemappableOop();
	quo = popRemappableOop()
#endif /* SPURVM */
;
	if (!(result == null)) {
		stObjectatput(result, 1, quo);
		stObjectatput(result, 2, rem);
	}
	return result;
}

	/* LargeIntegersPlugin>>#digitMontgomery:times:modulo:mInvModB: */
static sqInt
digitMontgomerytimesmodulomInvModB(sqInt firstLarge, sqInt secondLarge, sqInt thirdLarge, unsigned int mInv)
{
	unsigned long long accum;
	unsigned long long accum2;
	unsigned long long accum3;
	sqInt firstLen;
	sqInt i;
	sqInt k;
	unsigned int lastDigit;
	sqInt limit1;
	sqInt limit2;
	sqInt limit3;
	unsigned int *pFirst;
	unsigned int *pRes;
	sqInt prod;
	unsigned int *pSecond;
	unsigned int *pThird;
	sqInt secondLen;
	sqInt thirdLen;
	unsigned long long u;

	firstLen = ((slotSizeOf(firstLarge)) + 3) / 4;
	secondLen = ((slotSizeOf(secondLarge)) + 3) / 4;
	thirdLen = ((slotSizeOf(thirdLarge)) + 3) / 4;
	if (!((firstLen <= thirdLen)
		 && (secondLen <= thirdLen))) {
		return primitiveFail();
	}
	
#if SPURVM
	prod = instantiateClassindexableSize(classLargePositiveInteger(), thirdLen * 4);

#else /* SPURVM */
	pushRemappableOop(firstLarge);
	pushRemappableOop(secondLarge);
	pushRemappableOop(thirdLarge);
	prod = instantiateClassindexableSize(classLargePositiveInteger(), thirdLen * 4);
	thirdLarge = popRemappableOop();
	secondLarge = popRemappableOop();
	firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	if (!(prod)) {
		return primitiveFailFor(PrimErrNoMemory);
	}
	/* begin cDigitMontgomery:len:times:len:modulo:len:mInvModB:into: */
	pFirst = ((unsigned int *) (firstIndexableField(firstLarge)));
	pSecond = ((unsigned int *) (firstIndexableField(secondLarge)));
	pThird = ((unsigned int *) (firstIndexableField(thirdLarge)));
	pRes = ((unsigned int *) (firstIndexableField(prod)));
	limit1 = firstLen - 1;
	limit2 = secondLen - 1;
	limit3 = thirdLen - 1;
	lastDigit = 0;
	for (i = 0; i <= limit1; i += 1) {
		accum3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFirst[i]));
		accum3 = (accum3 * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pSecond[0])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[0])));
		u = (accum3 * mInv) & 0xFFFFFFFFU;
		accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[0])));
		accum = (accum2 & 0xFFFFFFFFU) + (accum3 & 0xFFFFFFFFU);
		accum = ((accum >> 32) + (accum2 >> 32)) + (accum3 >> 32);
		for (k = 1; k <= limit2; k += 1) {
			accum3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFirst[i]));
			accum3 = (accum3 * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pSecond[k])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])));
			accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
			accum = (accum + (accum2 & 0xFFFFFFFFU)) + (accum3 & 0xFFFFFFFFU);
			pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			accum = ((accum >> 32) + (accum2 >> 32)) + (accum3 >> 32);
		}
		for (k = secondLen; k <= limit3; k += 1) {
			accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
			accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])))) + (accum2 & 0xFFFFFFFFU);
			pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			accum = (accum >> 32) + (accum2 >> 32);
		}
		accum += lastDigit;
		pRes[limit3] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
		lastDigit = accum >> 32;
	}
	for (i = firstLen; i <= limit3; i += 1) {
		accum = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[0]));
		u = (accum * mInv) & 0xFFFFFFFFU;
		accum += u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[0])));
		accum = accum >> 32;
		for (k = 1; k <= limit3; k += 1) {
			accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
			accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])))) + (accum2 & 0xFFFFFFFFU);
			pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			accum = (accum >> 32) + (accum2 >> 32);
		}
		accum += lastDigit;
		pRes[limit3] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
		lastDigit = accum >> 32;
	}
	if (!((lastDigit == 0)
		 && ((cDigitComparewithlen(pThird, pRes, thirdLen)) == 1))) {

		/* self cDigitSub: pThird len: thirdLen with: pRes len: thirdLen into: pRes */
		accum = 0;
		for (i = 0; i <= limit3; i += 1) {
			accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[i])))) - (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[i])));
			pRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			accum = 0 - (accum >> 0x3F);
		}
	}
	return normalizePositive(prod);
}


/*	Normalizes. */

	/* LargeIntegersPlugin>>#digitMultiplyLarge:with:negative: */
static sqInt
digitMultiplyLargewithnegative(sqInt firstInteger, sqInt secondInteger, sqInt neg)
{
	unsigned long long ab;
	unsigned int carry;
	unsigned int digit;
	sqInt firstLen;
	sqInt i;
	sqInt j;
	sqInt k;
	sqInt limitLong;
	sqInt limitShort;
	sqInt longInt;
	sqInt longLen;
	sqInt prod;
	unsigned int *pWordLong;
	unsigned int *pWordRes;
	unsigned int *pWordShort;
	sqInt secondLen;
	sqInt shortInt;
	sqInt shortLen;

	/* begin byteSizeOfLargeInt: */
	firstLen = slotSizeOf(firstInteger);
	/* begin byteSizeOfLargeInt: */
	secondLen = slotSizeOf(secondInteger);
	if (firstLen <= secondLen) {
		shortInt = firstInteger;
		shortLen = firstLen;
		longInt = secondInteger;
		longLen = secondLen;
	}
	else {
		shortInt = secondInteger;
		shortLen = secondLen;
		longInt = firstInteger;
		longLen = firstLen;
	}
	
#if SPURVM
	/* begin createLargeIntegerNeg:byteLength: */
	prod = instantiateClassindexableSize((neg
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), longLen + shortLen);

#else /* SPURVM */
	pushRemappableOop(shortInt);
	pushRemappableOop(longInt);
	/* begin createLargeIntegerNeg:byteLength: */
	prod = instantiateClassindexableSize((neg
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), longLen + shortLen);
	longInt = popRemappableOop();
	shortInt = popRemappableOop()
#endif /* SPURVM */
;
	if (!(prod)) {
		return primitiveFailFor(PrimErrNoMemory);
	}
	/* begin cDigitMultiply:len:with:len:into:len: */
	pWordShort = ((unsigned int *) (firstIndexableField(shortInt)));
	pWordLong = ((unsigned int *) (firstIndexableField(longInt)));
	pWordRes = ((unsigned int *) (firstIndexableField(prod)));
	if ((((shortLen + 3) / 4) == 1)
	 && ((pWordShort[0]) == 0)) {
		goto l4;
	}
	if ((((longLen + 3) / 4) == 1)
	 && ((pWordLong[0]) == 0)) {
		goto l4;
	}
	limitShort = ((shortLen + 3) / 4) - 1;
	limitLong = ((longLen + 3) / 4) - 1;
	for (i = 0; i <= limitShort; i += 1) {
		if (((digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordShort[i])))) != 0) {
			k = i;

			/* Loop invariant: 0<=carry<=16rFFFFFFFF, k=i+j-1 (ST) */
			/* -> Loop invariant: 0<=carry<=16rFFFFFFFF, k=i+j (C) (?) */
			carry = 0;
			for (j = 0; j <= limitLong; j += 1) {
				ab = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[j]));
				ab = ((ab * digit) + carry) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordRes[k])));
				carry = ab >> 32;
				pWordRes[k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((ab & 0xFFFFFFFFU)));
				k += 1;
			}
			if (k < (((longLen + shortLen) + 3) / 4)) {
				pWordRes[k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
			}
		}
	}
	l4:	/* end cDigitMultiply:len:with:len:into:len: */;
	return (neg
		? normalizeNegative(prod)
		: normalizePositive(prod));
}


/*	Answer the value of a 32 bits digit in a C-SmallInteger. */
/*	ST indexed! */

	/* LargeIntegersPlugin>>#digitOfCSI:at: */
static sqInt
digitOfCSIat(sqInt csi, sqInt ix)
{
	return ((usqInt) ((csi < 0
		? 0 - csi
		: csi))) >> ((ix - 1) * 32);
}


/*	Argument has to be aLargeInteger! */

	/* LargeIntegersPlugin>>#digitOfLargeInt:at: */
static sqInt
digitOfLargeIntat(sqInt aBytesOop, sqInt ix)
{
	unsigned int *cPointer;

	if (ix > (((slotSizeOf(aBytesOop)) + 3) / 4)) {
		return 0;
	}
	else {
		/* begin cDigitOf:at: */
		cPointer = ((unsigned int *) (firstIndexableField(aBytesOop)));
		return SQ_SWAP_4_BYTES_IF_BIGENDIAN((cPointer[ix - 1]));
	}
}


/*	Answer the number of 32-bits fields of a C-SmallInteger. This value is 
	the same as the largest legal subscript. */

	/* LargeIntegersPlugin>>#digitSizeOfCSI: */
static sqInt
digitSizeOfCSI(sqInt csi)
{
	return ((MaxSmallInteger) <= 0x3FFFFFFF
		? 1
		: (csi > (((sqIntptr_t)0xFFFFFFFFU))
				? 2
				: (csi < -4294967295LL
						? 2
						: 1)));
}


/*	answer number of 32 bits digits of a Large Integer */

	/* LargeIntegersPlugin>>#digitSizeOfLargeInt: */
static sqInt
digitSizeOfLargeInt(sqInt anOop)
{
	return ((slotSizeOf(anOop)) + 3) / 4;
}


/*	Normalizes. */

	/* LargeIntegersPlugin>>#digitSubLarge:with: */
static sqInt
digitSubLargewith(sqInt firstInteger, sqInt secondInteger)
{
	sqInt firstDigitLen;
	sqInt firstNeg;
	sqInt i;
	sqInt largeDigitLen;
	sqInt larger;
	int neg;
	unsigned int *pWordLarge;
	unsigned int *pWordRes;
	unsigned int *pWordSmall;
	sqInt res;
	sqInt resDigitLen;
	sqInt secondDigitLen;
	sqInt smaller;
	sqInt smallerDigitLen;
	unsigned long long z;

	firstNeg = isLargeNegativeIntegerObject(firstInteger);
	/* begin digitSizeOfLargeInt: */
	firstDigitLen = ((slotSizeOf(firstInteger)) + 3) / 4;
	/* begin digitSizeOfLargeInt: */
	secondDigitLen = ((slotSizeOf(secondInteger)) + 3) / 4;
	if (firstDigitLen == secondDigitLen) {
		while ((firstDigitLen > 1)
		 && ((cDigitOfat(((unsigned int *) (firstIndexableField(firstInteger))), firstDigitLen - 1)) == (cDigitOfat(((unsigned int *) (firstIndexableField(secondInteger))), firstDigitLen - 1)))) {
			firstDigitLen -= 1;
		}
		secondDigitLen = firstDigitLen;
	}
	if ((firstDigitLen < secondDigitLen)
	 || ((firstDigitLen == secondDigitLen)
	 && ((cDigitOfat(((unsigned int *) (firstIndexableField(firstInteger))), firstDigitLen - 1)) < (cDigitOfat(((unsigned int *) (firstIndexableField(secondInteger))), firstDigitLen - 1))))) {
		larger = secondInteger;
		largeDigitLen = secondDigitLen;
		smaller = firstInteger;
		smallerDigitLen = firstDigitLen;
		neg = firstNeg == 0;
	}
	else {
		larger = firstInteger;
		largeDigitLen = firstDigitLen;
		smaller = secondInteger;
		smallerDigitLen = secondDigitLen;
		neg = firstNeg;
	}
	resDigitLen = largeDigitLen;
	
#if SPURVM
	/* begin createLargeIntegerNeg:digitLength: */
	res = instantiateClassindexableSize((neg
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), resDigitLen * 4);

#else /* SPURVM */
	pushRemappableOop(smaller);
	pushRemappableOop(larger);
	/* begin createLargeIntegerNeg:digitLength: */
	res = instantiateClassindexableSize((neg
		? classLargeNegativeInteger()
		: classLargePositiveInteger()), resDigitLen * 4);
	larger = popRemappableOop();
	smaller = popRemappableOop()
#endif /* SPURVM */
;
	if (!(res)) {
		return primitiveFailFor(PrimErrNoMemory);
	}
	/* begin cDigitSub:len:with:len:into: */
	pWordSmall = ((unsigned int *) (firstIndexableField(smaller)));
	pWordLarge = ((unsigned int *) (firstIndexableField(larger)));
	pWordRes = ((unsigned int *) (firstIndexableField(res)));
	z = 0;
	for (i = 0; i < smallerDigitLen; i += 1) {
		z = (z + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLarge[i])))) - (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordSmall[i])));
		/* begin cDigitOf:at:put: */
		pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) (z & 0xFFFFFFFFU)))));
		z = 0 - (z >> 0x3F);
	}
	for (i = smallerDigitLen; i < largeDigitLen; i += 1) {
		z += SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLarge[i]));
		/* begin cDigitOf:at:put: */
		pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) (z & 0xFFFFFFFFU)))));
		z = 0 - (z >> 0x3F);
	}
	return (neg
		? normalizeNegative(res)
		: normalizePositive(res));
}


/*	Attention: this method invalidates all oop's! Only newOop is valid at
	return. 
 */
/*	Does not normalize. */

	/* LargeIntegersPlugin>>#digit:Lshift: */
static sqInt
digitLshift(sqInt anOop, sqInt shiftCount)
{
	sqInt bitShift;
	unsigned int carry;
	unsigned int digit;
	sqInt digitShift;
	sqInt highBit;
	sqInt i;
	sqInt i1;
	sqInt limit;
	sqInt newByteLen;
	sqInt newDigitLen;
	sqInt newOop;
	sqInt oldDigitLen;
	unsigned int *pFrom;
	unsigned int *pTo;
	sqInt rshift;

	/* begin digitSizeOfLargeInt: */
	oldDigitLen = ((slotSizeOf(anOop)) + 3) / 4;
	if (((highBit = cDigitHighBitlen(((unsigned int *) (firstIndexableField(anOop))), oldDigitLen))) == 0) {
		return instantiateClassindexableSize(fetchClassOf(anOop), 1);
	}
	newByteLen = ((highBit + shiftCount) + 7) / 8;
	
#if SPURVM
	newOop = instantiateClassindexableSize(fetchClassOf(anOop), newByteLen);

#else /* SPURVM */
	pushRemappableOop(anOop);
	newOop = instantiateClassindexableSize(fetchClassOf(anOop), newByteLen);
	anOop = popRemappableOop()
#endif /* SPURVM */
;
	if (!(newOop)) {
		primitiveFailFor(PrimErrNoMemory);
		return null;
	}
	newDigitLen = (newByteLen + 3) / 4;
	/* begin cDigitLshift:from:len:to:len: */
	pFrom = ((unsigned int *) (firstIndexableField(anOop)));
	pTo = ((unsigned int *) (firstIndexableField(newOop)));
	digitShift = shiftCount / 32;
	bitShift = shiftCount % 32;

	/* Note: 0 is endian neutral, use direct access */
	limit = digitShift - 1;
	for (i = 0; i <= limit; i += 1) {
		pTo[i] = 0;
	}
	if (bitShift == 0) {

		/* Fast version for digit-aligned shifts */
		/* C indexed! */
		/* begin cDigitCopyFrom:to:len: */
		for (i1 = 0; i1 < (((newDigitLen - 1) - digitShift) + 1); i1 += 1) {
			(pTo + digitShift)[i1] = ((pFrom)[i1]);
		}
		goto l2;
	}
	rshift = 32 - bitShift;
	carry = 0;
	limit = oldDigitLen - 1;
	for (i = 0; i <= limit; i += 1) {
		digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFrom[i]));
		pTo[i + digitShift] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(((carry | (((usqInt)(digit) << bitShift))) & 0xFFFFFFFFU)));
		carry = ((usqInt) digit) >> rshift;
	}
	if (!(carry == 0)) {
		pTo[newDigitLen - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
	}
	l2:	/* end cDigitLshift:from:len:to:len: */;
	return newOop;
}


/*	Attention: this method invalidates all oop's! Only newBytes is valid at
	return. 
 */
/*	Shift right 32*digitShift+bitShift bits, 0<=bitShift<32. 
	Discard all digits beyond a, and all zeroes at or below a. */
/*	Does not normalize. */

	/* LargeIntegersPlugin>>#digit:Rshift:lookfirst: */
static sqInt
digitRshiftlookfirst(sqInt anOop, sqInt shiftCount, sqInt a)
{
	sqInt bitShift;
	unsigned int carry;
	unsigned int digit;
	sqInt digitShift;
	sqInt i;
	sqInt j;
	unsigned int lastDigit;
	sqInt leftShift;
	sqInt limit;
	sqInt newBitLen;
	sqInt newByteLen;
	sqInt newDigitLen;
	sqInt newOop;
	sqInt oldBitLen;
	sqInt oldDigitLen;
	unsigned int *pFrom;
	unsigned int *pTo;
	unsigned int *pUint32;
	sqInt realLength;
	sqInt start;

	/* begin cDigitHighBit:len: */
	pUint32 = ((unsigned int *) (firstIndexableField(anOop)));
	realLength = a;
	do {
		if (realLength == 0) {
			oldBitLen = 0;
			goto l5;
		}
	} while(((lastDigit = cDigitOfat(pUint32, (realLength -= 1)))) == 0);
	oldBitLen = (cHighBit32(lastDigit)) + (32 * realLength);
	l5:	/* end cDigitHighBit:len: */;
	oldDigitLen = (oldBitLen + 0x1F) / 32;
	newBitLen = oldBitLen - shiftCount;
	if (newBitLen <= 0) {

		/* All bits lost */
		return instantiateClassindexableSize(fetchClassOf(anOop), 0);
	}
	newByteLen = (newBitLen + 7) / 8;
	newDigitLen = (newByteLen + 3) / 4;
	
#if SPURVM
	newOop = instantiateClassindexableSize(fetchClassOf(anOop), newByteLen);

#else /* SPURVM */
	pushRemappableOop(anOop);
	newOop = instantiateClassindexableSize(fetchClassOf(anOop), newByteLen);
	anOop = popRemappableOop()
#endif /* SPURVM */
;
	if (!(newOop)) {
		return primitiveFailFor(PrimErrNoMemory);
	}
	/* begin cDigitRshift:from:len:to:len: */
	pFrom = ((unsigned int *) (firstIndexableField(anOop)));
	pTo = ((unsigned int *) (firstIndexableField(newOop)));
	digitShift = shiftCount / 32;
	bitShift = shiftCount % 32;
	if (bitShift == 0) {

		/* Fast version for digit-aligned shifts */
		/* C indexed! */
		/* begin cDigitReplace:from:to:with:startingAt: */
		for (i = 0; i < (((newDigitLen - 1)) + 1); i += 1) {
			(pTo)[i] = ((pFrom + digitShift)[i]);
		}
		goto l4;
	}
	leftShift = 32 - bitShift;
	carry = ((usqInt) (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFrom[digitShift])))) >> bitShift;
	start = digitShift + 1;
	limit = oldDigitLen - 1;
	for (j = start; j <= limit; j += 1) {
		/* begin cDigitOf:at: */
		digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFrom[j]));
		/* begin cDigitOf:at:put: */
		pTo[j - start] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(((carry | (((usqInt)(digit) << leftShift))) & 0xFFFFFFFFU)));
		carry = ((usqInt) digit) >> bitShift;
	}
	if (!(carry == 0)) {
		/* begin cDigitOf:at:put: */
		pTo[newDigitLen - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
	}
	l4:	/* end cDigitRshift:from:len:to:len: */;
	return newOop;
}


/*	Note: This is hardcoded so it can be run from Squeak.
	The module name is used for validating a module *after*
	it is loaded to check if it does really contain the module
	we're thinking it contains. This is important! */

	/* InterpreterPlugin>>#getModuleName */
EXPORT(const char*)
getModuleName(void)
{
	return moduleName;
}

	/* LargeIntegersPlugin>>#highBitOfLargeInt: */
static sqInt
highBitOfLargeInt(sqInt anOop)
{
	unsigned int lastDigit;
	sqInt len;
	unsigned int *pUint32;
	sqInt realLength;

	/* begin cDigitHighBit:len: */
	pUint32 = ((unsigned int *) (firstIndexableField(anOop)));
	len = ((slotSizeOf(anOop)) + 3) / 4;
	realLength = len;
	do {
		if (realLength == 0) {
			return 0;
		}
	} while(((lastDigit = cDigitOfat(pUint32, (realLength -= 1)))) == 0);
	return (cHighBit32(lastDigit)) + (32 * realLength);
}


/*	Check for leading zero of LargeInteger */

	/* LargeIntegersPlugin>>#isNormalized: */
static sqInt
isNormalized(sqInt aLargeInteger)
{
	sqInt len;

	/* begin byteSizeOfLargeInt: */
	len = slotSizeOf(aLargeInteger);
	if (len == 0) {
		return 0;
	}
	if ((unsafeByteOfLargeIntat(aLargeInteger, len)) == 0) {
		return 0;
	}
	return 1;
}


/*	Attention: this method invalidates all oop's! Only newBytes is valid at
	return. 
 */
/*	Does not normalize. */

	/* LargeIntegersPlugin>>#largeInt:growTo: */
static sqInt
largeIntgrowTo(sqInt aBytesObject, sqInt newByteLen)
{
	sqInt copyLen;
	sqInt i;
	sqInt newBytes;
	sqInt newDigitLen;
	sqInt oldDigitLen;
	unsigned int *pFrom;
	unsigned int *pTo;

	
#if SPURVM
	newBytes = instantiateClassindexableSize(fetchClassOf(aBytesObject), newByteLen);
	if (!(newBytes)) {
		primitiveFailFor(PrimErrNoMemory);
		return null;
	}

#else /* SPURVM */
	pushRemappableOop(aBytesObject);
	newBytes = instantiateClassindexableSize(fetchClassOf(aBytesObject), newByteLen);
	if (!(newBytes)) {
		primitiveFailFor(PrimErrNoMemory);
		return null;
	}
	aBytesObject = popRemappableOop()
#endif /* SPURVM */
;
	newDigitLen = (newByteLen + 3) / 4;
	/* begin digitSizeOfLargeInt: */
	oldDigitLen = ((slotSizeOf(aBytesObject)) + 3) / 4;
	copyLen = (oldDigitLen < newDigitLen
		? oldDigitLen
		: newDigitLen);
	/* begin cDigitCopyFrom:to:len: */
	pFrom = ((unsigned int *) (firstIndexableField(aBytesObject)));
	pTo = ((unsigned int *) (firstIndexableField(newBytes)));
	for (i = 0; i < copyLen; i += 1) {
		pTo[i] = (pFrom[i]);
	}
	return newBytes;
}

	/* InterpreterPlugin>>#msg: */
static sqInt
msg(char *s)
{
	fprintf(stderr, "\n%s: %s", moduleName, s);
	return 0;
}


/*	Check for leading zeroes and return shortened copy if so. */
/*	First establish len = significant length. */

	/* LargeIntegersPlugin>>#normalizeNegative: */
static sqInt
normalizeNegative(sqInt aLargeNegativeInteger)
{
	sqInt byteLen;
	unsigned int *cPointer;
	sqInt digitLen;
	usqInt minVal;
	sqInt oldByteLen;
	int sLen;
	usqInt val;
	usqInt val2;

	/* begin digitSizeOfLargeInt: */
	digitLen = ((slotSizeOf(aLargeNegativeInteger)) + 3) / 4;
	while ((digitLen != 0)
	 && ((cDigitOfat(((unsigned int *) (firstIndexableField(aLargeNegativeInteger))), digitLen - 1)) == 0)) {
		digitLen -= 1;
	}
	if (digitLen == 0) {
		return integerObjectOf(0);
	}
	/* begin cDigitOf:at: */
	cPointer = ((unsigned int *) (firstIndexableField(aLargeNegativeInteger)));
	val = SQ_SWAP_4_BYTES_IF_BIGENDIAN((cPointer[digitLen - 1]));

	/* SmallInteger minVal digitLength */
	sLen = ((MinSmallInteger) < -1073741824LL
		? 2
		: 1);
	if (digitLen <= sLen) {
		minVal = 0 - (MinSmallInteger);
		val2 = val;
		if (digitLen > 1) {
			val2 = (val2 << 32) + (cDigitOfat(((unsigned int *) (firstIndexableField(aLargeNegativeInteger))), 1 - 1));
		}
		if (val2 <= minVal) {
			return integerObjectOf((0 - val2));
		}
	}
	byteLen = digitLen * 4;
	if (val <= 0xFFFF) {
		byteLen -= 2;
	}
	else {
		val = ((usqInt) val) >> 16;
	}
	if (val <= 0xFF) {
		byteLen -= 1;
	}
	/* begin byteSizeOfLargeInt: */
	oldByteLen = slotSizeOf(aLargeNegativeInteger);
	if (byteLen < oldByteLen) {
		return largeIntgrowTo(aLargeNegativeInteger, byteLen);
	}
	else {
		return aLargeNegativeInteger;
	}
}


/*	Check for leading zeroes and return shortened copy if so. */
/*	First establish len = significant length. */

	/* LargeIntegersPlugin>>#normalizePositive: */
static sqInt
normalizePositive(sqInt aLargePositiveInteger)
{
	sqInt byteLen;
	unsigned int *cPointer;
	sqInt digitLen;
	usqInt maxVal;
	sqInt oldByteLen;
	int sLen;
	usqInt val;
	usqInt val2;

	/* begin digitSizeOfLargeInt: */
	digitLen = ((slotSizeOf(aLargePositiveInteger)) + 3) / 4;
	while ((digitLen != 0)
	 && ((cDigitOfat(((unsigned int *) (firstIndexableField(aLargePositiveInteger))), digitLen - 1)) == 0)) {
		digitLen -= 1;
	}
	if (digitLen == 0) {
		return integerObjectOf(0);
	}
	/* begin cDigitOf:at: */
	cPointer = ((unsigned int *) (firstIndexableField(aLargePositiveInteger)));
	val = SQ_SWAP_4_BYTES_IF_BIGENDIAN((cPointer[digitLen - 1]));

	/* SmallInteger maxVal digitLength */
	sLen = ((MaxSmallInteger) > 0x3FFFFFFF
		? 2
		: 1);
	if (digitLen <= sLen) {
		maxVal = MaxSmallInteger;
		val2 = val;
		if (digitLen > 1) {

			/* Note: asUnsignedLongLong is not necessary because this branch is for 64 bits only.
			   but we want to avoid a C Compiler warning on 32 bits */
			val2 = ((((unsigned long long)val2)) << 32) + (cDigitOfat(((unsigned int *) (firstIndexableField(aLargePositiveInteger))), 1 - 1));
		}
		if (val2 <= maxVal) {
			return integerObjectOf(val2);
		}
	}
	byteLen = digitLen * 4;
	if (val <= 0xFFFF) {
		byteLen -= 2;
	}
	else {
		val = ((usqInt) val) >> 16;
	}
	if (val <= 0xFF) {
		byteLen -= 1;
	}
	/* begin byteSizeOfLargeInt: */
	oldByteLen = slotSizeOf(aLargePositiveInteger);
	if (byteLen < oldByteLen) {
		return largeIntgrowTo(aLargePositiveInteger, byteLen);
	}
	else {
		return aLargePositiveInteger;
	}
}


/*	Check for leading zeroes and return shortened copy if so. */

	/* LargeIntegersPlugin>>#normalize: */
static sqInt
normalize(sqInt aLargeInteger)
{
	/* missing DebugCode */;
	if (isLargePositiveIntegerObject(aLargeInteger)) {
		return normalizePositive(aLargeInteger);
	}
	else {
		return normalizeNegative(aLargeInteger);
	}
}

	/* LargeIntegersPlugin>>#primAnyBitFrom:to: */
EXPORT(sqInt)
primAnyBitFromTo(void)
{
	sqInt from;
	sqInt integer;
	sqInt large;
	sqInt to;
	sqInt _return_value;

	if (!((isIntegerObject(stackValue(1)))
		 && (isIntegerObject(stackValue(0))))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	from = stackIntegerValue(1);
	to = stackIntegerValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(2)));
	integer = stackValue(2);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(integer)) {

		/* convert it to a not normalized LargeInteger */
		large = createLargeFromSmallInteger(integer);
	}
	else {
		large = integer;
	}
	if (!(failed())) {
		_return_value = (((anyBitOfLargeIntfromto(large, from, to))) ? trueObject() : falseObject());
		if (!(failed())) {
			popthenPush(3, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primDigitAdd: */
EXPORT(sqInt)
primDigitAdd(void)
{
	unsigned long long accum;
	unsigned int *cPointer;
	sqInt firstDigitLen;
	sqInt firstInteger;
	sqInt firstLarge;
	sqInt i;
	sqInt i1;
	sqInt longDigitLen;
	sqInt longInt;
	sqInt neg;
	sqInt newSum;
	unsigned int over;
	unsigned int *pFrom;
	unsigned int *pTo;
	unsigned int *pWordLong;
	unsigned int *pWordRes;
	unsigned int *pWordShort;
	sqInt secondDigitLen;
	sqInt secondInteger;
	sqInt secondLarge;
	sqInt shortDigitLen;
	sqInt shortInt;
	sqInt sum;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		firstLarge = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondInteger);
		firstLarge = createLargeFromSmallInteger(firstInteger);
		secondInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		secondLarge = createLargeFromSmallInteger(secondInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		secondLarge = createLargeFromSmallInteger(secondInteger);
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		secondLarge = secondInteger;
	}
	if (!(failed())) {
		/* begin digitAddLarge:with: */
		firstDigitLen = ((slotSizeOf(firstLarge)) + 3) / 4;
		secondDigitLen = ((slotSizeOf(secondLarge)) + 3) / 4;
		neg = isLargeNegativeIntegerObject(firstLarge);
		if (firstDigitLen <= secondDigitLen) {
			shortInt = firstLarge;
			shortDigitLen = firstDigitLen;
			longInt = secondLarge;
			longDigitLen = secondDigitLen;
		}
		else {
			shortInt = secondLarge;
			shortDigitLen = secondDigitLen;
			longInt = firstLarge;
			longDigitLen = firstDigitLen;
		}
		
#if SPURVM
		/* begin createLargeIntegerNeg:digitLength: */
		sum = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), longDigitLen * 4);

#else /* SPURVM */
		pushRemappableOop(shortInt);
		pushRemappableOop(longInt);
		/* begin createLargeIntegerNeg:digitLength: */
		sum = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), longDigitLen * 4);
		longInt = popRemappableOop();
		shortInt = popRemappableOop()
#endif /* SPURVM */
;
		if (!(sum)) {
			_return_value = primitiveFailFor(PrimErrNoMemory);
			goto l6;
		}
		/* begin cDigitAdd:len:with:len:into: */
		pWordShort = ((unsigned int *) (firstIndexableField(shortInt)));
		pWordLong = ((unsigned int *) (firstIndexableField(longInt)));
		pWordRes = ((unsigned int *) (firstIndexableField(sum)));
		accum = 0;
		for (i1 = 0; i1 < shortDigitLen; i1 += 1) {
			accum = ((accum >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordShort[i1])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[i1])));
			pWordRes[i1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
		}
		for (i1 = shortDigitLen; i1 < longDigitLen; i1 += 1) {
			accum = (accum >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[i1])));
			pWordRes[i1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
		}
		over = accum >> 32;
		if (over > 0) {

			/* sum := sum growby: 1. */
			
#if SPURVM
			/* begin createLargeIntegerNeg:byteLength: */
			newSum = instantiateClassindexableSize((neg
				? classLargeNegativeInteger()
				: classLargePositiveInteger()), (longDigitLen * 4) + 1);

#else /* SPURVM */
			pushRemappableOop(sum);
			/* begin createLargeIntegerNeg:byteLength: */
			newSum = instantiateClassindexableSize((neg
				? classLargeNegativeInteger()
				: classLargePositiveInteger()), (longDigitLen * 4) + 1);
			sum = popRemappableOop()
#endif /* SPURVM */
;
			if (!(newSum)) {
				_return_value = primitiveFailFor(PrimErrNoMemory);
				goto l6;
			}
			/* begin cDigitCopyFrom:to:len: */
			pFrom = ((unsigned int *) (firstIndexableField(sum)));
			pTo = ((unsigned int *) (firstIndexableField(newSum)));
			for (i = 0; i < longDigitLen; i += 1) {
				pTo[i] = (pFrom[i]);
			}

			/* C index! */
			sum = newSum;
			/* begin cDigitOf:at:put: */
			cPointer = ((unsigned int *) (firstIndexableField(sum)));
			cPointer[longDigitLen] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(over));
		}
		else {
			sum = (neg
				? normalizeNegative(sum)
				: normalizePositive(sum));
		}
		_return_value = sum;
	l6:	/* end digitAddLarge:with: */;
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}


/*	Bit logic here is only implemented for positive integers or Zero; if rec 
	or arg is negative, it fails. */

	/* LargeIntegersPlugin>>#primDigitBitAnd: */
EXPORT(sqInt)
primDigitBitAnd(void)
{
	sqInt firstInteger;
	sqInt secondInteger;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, andOpIndex);
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}


/*	Bit logic here is only implemented for positive integers or Zero; if rec 
	or arg is negative, it fails. */

	/* LargeIntegersPlugin>>#primDigitBitOr: */
EXPORT(sqInt)
primDigitBitOr(void)
{
	sqInt firstInteger;
	sqInt secondInteger;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, orOpIndex);
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primDigitBitShiftMagnitude: */
EXPORT(sqInt)
primDigitBitShiftMagnitude(void)
{
	sqInt aLarge;
	sqInt aLargeInteger;
	sqInt anInteger;
	sqInt rShift;
	sqInt shiftCount;
	sqInt _return_value;

	if (!(isIntegerObject(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	shiftCount = stackIntegerValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	anInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(anInteger)) {

		/* convert it to a not normalized LargeInteger */
		aLarge = createLargeFromSmallInteger(anInteger);
	}
	else {
		aLarge = anInteger;
	}
	if (shiftCount >= 0) {
		_return_value = digitLshift(aLarge, shiftCount);
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
		return null;
	}
	else {
		rShift = 0 - shiftCount;
		if (!(failed())) {
			/* begin normalize: */
			aLargeInteger = digitRshiftlookfirst(aLarge, rShift, ((slotSizeOf(aLarge)) + 3) / 4);
			/* missing DebugCode */;
			if (isLargePositiveIntegerObject(aLargeInteger)) {
				_return_value = normalizePositive(aLargeInteger);
				goto l1;
			}
			else {
				_return_value = normalizeNegative(aLargeInteger);
				goto l1;
			}
	l1:	/* end normalize: */;
			if (!(failed())) {
				popthenPush(2, _return_value);
			}
		}
		return null;
	}
}


/*	Bit logic here is only implemented for positive integers or Zero; if rec 
	or arg is negative, it fails. */

	/* LargeIntegersPlugin>>#primDigitBitXor: */
EXPORT(sqInt)
primDigitBitXor(void)
{
	sqInt firstInteger;
	sqInt secondInteger;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = digitBitLogicwithopIndex(firstInteger, secondInteger, xorOpIndex);
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}


/*	Compare the magnitude of self with that of arg. 
	Answer a code of 1, 0, -1 for self >, = , < arg */

	/* LargeIntegersPlugin>>#primDigitCompare: */
EXPORT(sqInt)
primDigitCompare(void)
{
	sqInt firstDigitLen;
	sqInt firstInteger;
	sqInt firstVal;
	sqInt secondDigitLen;
	sqInt secondInteger;
	sqInt secondVal;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {
		if (isIntegerObject(secondInteger)) {
			firstVal = integerValueOf(firstInteger);

			/* Compute their magnitudes.  Since SmallIntegers are tagged they have
			   fewer bits than an integer on the platform; therefore in computing their
			   magnitude they cannot overflow. */
			secondVal = integerValueOf(secondInteger);
			if (firstVal < 0) {
				firstVal = 0 - firstVal;
			}
			if (secondVal < 0) {
				secondVal = 0 - secondVal;
			}
			if (!(failed())) {
				_return_value = (firstVal == secondVal
					? integerObjectOf(0)
					: (firstVal < secondVal
							? integerObjectOf(-1)
							: integerObjectOf(1)));
				if (!(failed())) {
					popthenPush(2, _return_value);
				}
			}
			return null;
		}
		if (!(failed())) {
			_return_value = integerObjectOf(-1);
			if (!(failed())) {
				popthenPush(2, _return_value);
			}
		}
		return null;
	}
	if (isIntegerObject(secondInteger)) {
		_return_value = integerObjectOf(1);
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
		return null;
	}
	if (!(failed())) {
		/* begin digitCompareLarge:with: */
		firstDigitLen = ((slotSizeOf(firstInteger)) + 3) / 4;
		secondDigitLen = ((slotSizeOf(secondInteger)) + 3) / 4;
		if (secondDigitLen != firstDigitLen) {
			if (secondDigitLen > firstDigitLen) {
				_return_value = integerObjectOf(-1);
				goto l1;
			}
			else {
				_return_value = integerObjectOf(1);
				goto l1;
			}
		}
		_return_value = integerObjectOf((cDigitComparewithlen(((unsigned int *) (firstIndexableField(firstInteger))), ((unsigned int *) (firstIndexableField(secondInteger))), firstDigitLen)));
	l1:	/* end digitCompareLarge:with: */;
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}


/*	Answer the result of dividing firstInteger by secondInteger. 
	Fail if parameters are not integers, not normalized or secondInteger is 
	zero. */

	/* LargeIntegersPlugin>>#primDigitDiv:negative: */
EXPORT(sqInt)
primDigitDivNegative(void)
{
	unsigned long long a;
	unsigned long long b;
	sqInt cond;
	sqInt d;
	unsigned int dh;
	sqInt div;
	sqInt divLen;
	sqInt dl;
	unsigned int dnh;
	sqInt firstAsLargeInteger;
	sqInt firstDigitLen;
	sqInt firstInteger;
	unsigned long long hi;
	sqInt i;
	sqInt j;
	sqInt k;
	sqInt l;
	unsigned long long lo;
	unsigned long long mul;
	sqInt neg;
	unsigned int *pDiv;
	unsigned int *pQuo;
	unsigned int *pRem;
	unsigned long long q;
	sqInt ql;
	sqInt quo;
	sqInt quoDigitLen;
	sqInt quoLen;
	unsigned long long r1r2;
	unsigned int r3;
	sqInt rem;
	sqInt remLen;
	sqInt result;
	sqInt secondAsLargeInteger;
	sqInt secondDigitLen;
	sqInt secondInteger;
	unsigned long long t;
	sqInt _return_value;

	if (!((isKindOfInteger(stackValue(1)))
		 && (isBooleanObject(stackValue(0))))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(1);
	neg = booleanValueOf(stackValue(0));
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(2)));
	firstInteger = stackValue(2);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {

		/* convert to LargeInteger */
		
#if SPURVM
		firstAsLargeInteger = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondInteger);
		firstAsLargeInteger = createLargeFromSmallInteger(firstInteger);
		secondInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {

		/* Avoid crashes in case of getting unnormalized args. */
		if (!(isNormalized(firstInteger))) {
			/* missing DebugCode */;
			primitiveFail();
			return null;
		}
		firstAsLargeInteger = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {

		/* check for zerodivide and convert to LargeInteger */
		if ((integerValueOf(secondInteger)) == 0) {
			primitiveFail();
			return null;
		}
		
#if SPURVM
		secondAsLargeInteger = createLargeFromSmallInteger(secondInteger);

#else /* SPURVM */
		pushRemappableOop(firstAsLargeInteger);
		secondAsLargeInteger = createLargeFromSmallInteger(secondInteger);
		firstAsLargeInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {

		/* Avoid crashes in case of getting unnormalized args. */
		if (!(isNormalized(secondInteger))) {
			/* missing DebugCode */;
			primitiveFail();
			return null;
		}
		secondAsLargeInteger = secondInteger;
	}
	if (!(failed())) {
		/* begin digitDivLarge:with:negative: */
		firstDigitLen = ((slotSizeOf(firstAsLargeInteger)) + 3) / 4;
		secondDigitLen = ((slotSizeOf(secondAsLargeInteger)) + 3) / 4;
		quoDigitLen = (firstDigitLen - secondDigitLen) + 1;
		if (quoDigitLen <= 0) {
			
#if SPURVM
			result = instantiateClassindexableSize(classArray(), 2);

#else /* SPURVM */
			pushRemappableOop(firstAsLargeInteger);
			result = instantiateClassindexableSize(classArray(), 2);
			firstAsLargeInteger = popRemappableOop()
#endif /* SPURVM */
;
			if (!(result == null)) {
				stObjectatput(result, 1, integerObjectOf(0));
				stObjectatput(result, 2, firstAsLargeInteger);
			}
			_return_value = result;
			goto l3;
		}
		d = 32 - (cHighBit32(cDigitOfat(((unsigned int *) (firstIndexableField(secondAsLargeInteger))), secondDigitLen - 1)));
		
#if SPURVM
		div = digitLshift(secondAsLargeInteger, d);
		if (!(div == null)) {
			div = largeIntgrowTo(div, ((((slotSizeOf(div)) + 3) / 4) + 1) * 4);
		}
		if (!(div)) {
			_return_value = div;
			goto l3;
		}

#else /* SPURVM */
		pushRemappableOop(firstAsLargeInteger);
		div = digitLshift(secondAsLargeInteger, d);
		if (!(div == null)) {
			div = largeIntgrowTo(div, ((((slotSizeOf(div)) + 3) / 4) + 1) * 4);
		}
		if (!(div)) {
			_return_value = div;
			goto l3;
		}
		firstAsLargeInteger = popRemappableOop()
#endif /* SPURVM */
;
		
#if SPURVM
		rem = digitLshift(firstAsLargeInteger, d);
		if (!(rem == null)) {
			if ((((slotSizeOf(rem)) + 3) / 4) == firstDigitLen) {
				rem = largeIntgrowTo(rem, (firstDigitLen + 1) * 4);
			}
		}
		if (!(rem)) {
			_return_value = rem;
			goto l3;
		}

#else /* SPURVM */
		pushRemappableOop(div);
		rem = digitLshift(firstAsLargeInteger, d);
		if (!(rem == null)) {
			if ((((slotSizeOf(rem)) + 3) / 4) == firstDigitLen) {
				rem = largeIntgrowTo(rem, (firstDigitLen + 1) * 4);
			}
		}
		if (!(rem)) {
			_return_value = rem;
			goto l3;
		}
		div = popRemappableOop()
#endif /* SPURVM */
;
		
#if SPURVM
		/* begin createLargeIntegerNeg:digitLength: */
		quo = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), quoDigitLen * 4);

#else /* SPURVM */
		pushRemappableOop(div);
		pushRemappableOop(rem);
		/* begin createLargeIntegerNeg:digitLength: */
		quo = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), quoDigitLen * 4);
		rem = popRemappableOop();
		div = popRemappableOop()
#endif /* SPURVM */
;
		/* begin cDigitDiv:len:rem:len:quo:len: */
		pDiv = ((unsigned int *) (firstIndexableField(div)));
		divLen = ((slotSizeOf(div)) + 3) / 4;
		pRem = ((unsigned int *) (firstIndexableField(rem)));
		remLen = ((slotSizeOf(rem)) + 3) / 4;
		pQuo = ((unsigned int *) (firstIndexableField(quo)));
		quoLen = ((slotSizeOf(quo)) + 3) / 4;

		/* Last actual byte of data (ST ix) */
		dl = divLen - 1;
		ql = quoLen;
		dh = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[dl - 1]));
		if (dl == 1) {
			dnh = 0;
		}
		else {
			dnh = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[dl - 2]));
		}
		for (k = 1; k <= ql; k += 1) {

			/* maintain quo*arg+rem=self */
			/* Estimate rem/div by dividing the leading two unint32 of rem by dh. */
			/* The estimate is q = qhi*16r100000000+qlo, where qhi and qlo are uint32. */

			/* r1 := rem digitAt: j. */
			j = (remLen + 1) - k;
			if ((SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 1]))) == dh) {
				q = 0xFFFFFFFFU;
			}
			else {

				/* Compute q = (r1,r2)//dh, t = (r1,r2)\\dh.
				   Note that r1,r2 are uint64, not uint32. */
				/* r2 := (rem digitAt: j - 2). */
				r1r2 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 1]));
				r1r2 = (r1r2 << 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 2])));
				t = r1r2 % dh;

				/* Next compute (hi,lo) := q*dnh */
				q = r1r2 / dh;
				mul = q * dnh;
				hi = mul >> 32;

				/* Correct overestimate of q.
				   Max of 2 iterations through loop -- see Knuth vol. 2 */
				lo = mul & 0xFFFFFFFFU;
				if (j < 3) {
					r3 = 0;
				}
				else {
					r3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[j - 3]));
				}
				while (1) {
					if ((t < hi)
					 || ((t == hi)
					 && (r3 < lo))) {

						/* i.e. (t,r3) < (hi,lo) */
						q -= 1;
						if (hi == 0) {

							/* since hi is unsigned we must have this guard */
							cond = 0;
						}
						else {
							if (lo < dnh) {
								hi -= 1;
								lo = (lo + 0x100000000LL) - dnh;
							}
							else {
								lo -= dnh;
							}
							cond = hi >= dh;
						}
					}
					else {
						cond = 0;
					}
					if (!(cond)) break;
					hi -= dh;
				}
			}
			l = j - dl;
			a = 0;
			for (i = 1; i <= divLen; i += 1) {
				hi = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1]))) * (q >> 32);
				lo = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1]))) * (q & 0xFFFFFFFFU);
				b = ((SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[l - 1]))) - a) - (lo & 0xFFFFFFFFU);
				pRem[l - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((b & 0xFFFFFFFFU)));
				b = (b >> 32) | ((0 - (b >> 0x3F)) & 0xFFFFFFFF00000000ULL);
				a = (hi + (lo >> 32)) - b;
				l += 1;
			}
			if (a > 0) {

				/* Add div back into rem, decrease q by 1 */
				q -= 1;
				l = j - dl;
				a = 0;
				for (i = 1; i <= divLen; i += 1) {
					a = ((a >> 32) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRem[l - 1])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pDiv[i - 1])));
					pRem[l - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((a & 0xFFFFFFFFU)));
					l += 1;
				}
			}
			pQuo[quoLen - k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) q))));
		}
		
#if SPURVM
		rem = digitRshiftlookfirst(rem, d, (((slotSizeOf(div)) + 3) / 4) - 1);

#else /* SPURVM */
		pushRemappableOop(quo);
		rem = digitRshiftlookfirst(rem, d, (((slotSizeOf(div)) + 3) / 4) - 1);
		quo = popRemappableOop()
#endif /* SPURVM */
;
		
#if SPURVM
		result = instantiateClassindexableSize(classArray(), 2);

#else /* SPURVM */
		pushRemappableOop(quo);
		pushRemappableOop(rem);
		result = instantiateClassindexableSize(classArray(), 2);
		rem = popRemappableOop();
		quo = popRemappableOop()
#endif /* SPURVM */
;
		if (!(result == null)) {
			stObjectatput(result, 1, quo);
			stObjectatput(result, 2, rem);
		}
		_return_value = result;
	l3:	/* end digitDivLarge:with:negative: */;
		if (!(failed())) {
			popthenPush(3, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primDigitMultiply:negative: */
EXPORT(sqInt)
primDigitMultiplyNegative(void)
{
	unsigned long long ab;
	unsigned int carry;
	unsigned int digit;
	sqInt firstInteger;
	sqInt firstLarge;
	sqInt firstLen;
	sqInt i;
	sqInt j;
	sqInt k;
	sqInt limitLong;
	sqInt limitShort;
	sqInt longInt;
	sqInt longLen;
	sqInt neg;
	sqInt prod;
	unsigned int *pWordLong;
	unsigned int *pWordRes;
	unsigned int *pWordShort;
	sqInt secondInteger;
	sqInt secondLarge;
	sqInt secondLen;
	sqInt shortInt;
	sqInt shortLen;
	sqInt _return_value;

	if (!((isKindOfInteger(stackValue(1)))
		 && (isBooleanObject(stackValue(0))))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(1);
	neg = booleanValueOf(stackValue(0));
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(2)));
	firstInteger = stackValue(2);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		firstLarge = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondInteger);
		firstLarge = createLargeFromSmallInteger(firstInteger);
		secondInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		secondLarge = createLargeFromSmallInteger(secondInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		secondLarge = createLargeFromSmallInteger(secondInteger);
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		secondLarge = secondInteger;
	}
	if (!(failed())) {
		/* begin digitMultiplyLarge:with:negative: */
		firstLen = slotSizeOf(firstLarge);
		/* begin byteSizeOfLargeInt: */
		secondLen = slotSizeOf(secondLarge);
		if (firstLen <= secondLen) {
			shortInt = firstLarge;
			shortLen = firstLen;
			longInt = secondLarge;
			longLen = secondLen;
		}
		else {
			shortInt = secondLarge;
			shortLen = secondLen;
			longInt = firstLarge;
			longLen = firstLen;
		}
		
#if SPURVM
		/* begin createLargeIntegerNeg:byteLength: */
		prod = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), longLen + shortLen);

#else /* SPURVM */
		pushRemappableOop(shortInt);
		pushRemappableOop(longInt);
		/* begin createLargeIntegerNeg:byteLength: */
		prod = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), longLen + shortLen);
		longInt = popRemappableOop();
		shortInt = popRemappableOop()
#endif /* SPURVM */
;
		if (!(prod)) {
			_return_value = primitiveFailFor(PrimErrNoMemory);
			goto l5;
		}
		/* begin cDigitMultiply:len:with:len:into:len: */
		pWordShort = ((unsigned int *) (firstIndexableField(shortInt)));
		pWordLong = ((unsigned int *) (firstIndexableField(longInt)));
		pWordRes = ((unsigned int *) (firstIndexableField(prod)));
		if ((((shortLen + 3) / 4) == 1)
		 && ((pWordShort[0]) == 0)) {
			goto l4;
		}
		if ((((longLen + 3) / 4) == 1)
		 && ((pWordLong[0]) == 0)) {
			goto l4;
		}
		limitShort = ((shortLen + 3) / 4) - 1;
		limitLong = ((longLen + 3) / 4) - 1;
		for (i = 0; i <= limitShort; i += 1) {
			if (((digit = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordShort[i])))) != 0) {
				k = i;

				/* Loop invariant: 0<=carry<=16rFFFFFFFF, k=i+j-1 (ST) */
				/* -> Loop invariant: 0<=carry<=16rFFFFFFFF, k=i+j (C) (?) */
				carry = 0;
				for (j = 0; j <= limitLong; j += 1) {
					ab = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLong[j]));
					ab = ((ab * digit) + carry) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordRes[k])));
					carry = ab >> 32;
					pWordRes[k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((ab & 0xFFFFFFFFU)));
					k += 1;
				}
				if (k < (((longLen + shortLen) + 3) / 4)) {
					pWordRes[k] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN(carry));
				}
			}
		}
	l4:	/* end cDigitMultiply:len:with:len:into:len: */;
		_return_value = (neg
			? normalizeNegative(prod)
			: normalizePositive(prod));
	l5:	/* end digitMultiplyLarge:with:negative: */;
		if (!(failed())) {
			popthenPush(3, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primDigitSubtract: */
EXPORT(sqInt)
primDigitSubtract(void)
{
	sqInt firstDigitLen;
	sqInt firstInteger;
	sqInt firstLarge;
	sqInt firstNeg;
	sqInt i;
	sqInt largeDigitLen;
	sqInt larger;
	int neg;
	unsigned int *pWordLarge;
	unsigned int *pWordRes;
	unsigned int *pWordSmall;
	sqInt res;
	sqInt resDigitLen;
	sqInt secondDigitLen;
	sqInt secondInteger;
	sqInt secondLarge;
	sqInt smaller;
	sqInt smallerDigitLen;
	unsigned long long z;
	sqInt _return_value;

	if (!(isKindOfInteger(stackValue(0)))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(1)));
	firstInteger = stackValue(1);
	if (failed()) {
		return null;
	}
	if (isIntegerObject(firstInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		firstLarge = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondInteger);
		firstLarge = createLargeFromSmallInteger(firstInteger);
		secondInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		secondLarge = createLargeFromSmallInteger(secondInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		secondLarge = createLargeFromSmallInteger(secondInteger);
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		secondLarge = secondInteger;
	}
	if (!(failed())) {
		/* begin digitSubLarge:with: */
		firstNeg = isLargeNegativeIntegerObject(firstLarge);
		/* begin digitSizeOfLargeInt: */
		firstDigitLen = ((slotSizeOf(firstLarge)) + 3) / 4;
		/* begin digitSizeOfLargeInt: */
		secondDigitLen = ((slotSizeOf(secondLarge)) + 3) / 4;
		if (firstDigitLen == secondDigitLen) {
			while ((firstDigitLen > 1)
			 && ((cDigitOfat(((unsigned int *) (firstIndexableField(firstLarge))), firstDigitLen - 1)) == (cDigitOfat(((unsigned int *) (firstIndexableField(secondLarge))), firstDigitLen - 1)))) {
				firstDigitLen -= 1;
			}
			secondDigitLen = firstDigitLen;
		}
		if ((firstDigitLen < secondDigitLen)
		 || ((firstDigitLen == secondDigitLen)
		 && ((cDigitOfat(((unsigned int *) (firstIndexableField(firstLarge))), firstDigitLen - 1)) < (cDigitOfat(((unsigned int *) (firstIndexableField(secondLarge))), firstDigitLen - 1))))) {
			larger = secondLarge;
			largeDigitLen = secondDigitLen;
			smaller = firstLarge;
			smallerDigitLen = firstDigitLen;
			neg = firstNeg == 0;
		}
		else {
			larger = firstLarge;
			largeDigitLen = firstDigitLen;
			smaller = secondLarge;
			smallerDigitLen = secondDigitLen;
			neg = firstNeg;
		}
		resDigitLen = largeDigitLen;
		
#if SPURVM
		/* begin createLargeIntegerNeg:digitLength: */
		res = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), resDigitLen * 4);

#else /* SPURVM */
		pushRemappableOop(smaller);
		pushRemappableOop(larger);
		/* begin createLargeIntegerNeg:digitLength: */
		res = instantiateClassindexableSize((neg
			? classLargeNegativeInteger()
			: classLargePositiveInteger()), resDigitLen * 4);
		larger = popRemappableOop();
		smaller = popRemappableOop()
#endif /* SPURVM */
;
		if (!(res)) {
			_return_value = primitiveFailFor(PrimErrNoMemory);
			goto l7;
		}
		/* begin cDigitSub:len:with:len:into: */
		pWordSmall = ((unsigned int *) (firstIndexableField(smaller)));
		pWordLarge = ((unsigned int *) (firstIndexableField(larger)));
		pWordRes = ((unsigned int *) (firstIndexableField(res)));
		z = 0;
		for (i = 0; i < smallerDigitLen; i += 1) {
			z = (z + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLarge[i])))) - (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordSmall[i])));
			/* begin cDigitOf:at:put: */
			pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) (z & 0xFFFFFFFFU)))));
			z = 0 - (z >> 0x3F);
		}
		for (i = smallerDigitLen; i < largeDigitLen; i += 1) {
			z += SQ_SWAP_4_BYTES_IF_BIGENDIAN((pWordLarge[i]));
			/* begin cDigitOf:at:put: */
			pWordRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((((unsigned int) (z & 0xFFFFFFFFU)))));
			z = 0 - (z >> 0x3F);
		}
		_return_value = (neg
			? normalizeNegative(res)
			: normalizePositive(res));
	l7:	/* end digitSubLarge:with: */;
		if (!(failed())) {
			popthenPush(2, _return_value);
		}
	}
	return null;
}


/*	If calling this primitive fails, then C module does not exist. */

	/* LargeIntegersPlugin>>#primGetModuleName */
EXPORT(sqInt)
primGetModuleName(void)
{
	sqInt strLen;
	sqInt strOop;

	/* missing DebugCode */;
	strLen = strlen(getModuleName());
	strOop = instantiateClassindexableSize(classString(), strLen);
	strncpy(firstIndexableField(strOop), getModuleName(), strLen);
	if (!(failed())) {
		popthenPush(1, strOop);
	}
	return null;
}

	/* LargeIntegersPlugin>>#primMontgomeryDigitLength */
EXPORT(sqInt)
primMontgomeryDigitLength(void)
{
	sqInt _return_value;

	/* missing DebugCode */;
	if (!(failed())) {
		_return_value = integerObjectOf(32);
		if (!(failed())) {
			popthenPush(1, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primMontgomeryTimes:modulo:mInvModB: */
EXPORT(sqInt)
primMontgomeryTimesModulo(void)
{
	unsigned long long accum;
	unsigned long long accum2;
	unsigned long long accum3;
	sqInt firstInteger;
	sqInt firstLarge;
	sqInt firstLen;
	sqInt i;
	sqInt k;
	unsigned int lastDigit;
	sqInt limit1;
	sqInt limit2;
	sqInt limit3;
	unsigned int mInv;
	sqInt mInverseInteger;
	unsigned int *pFirst;
	unsigned int *pRes;
	sqInt prod;
	unsigned int *pSecond;
	unsigned int *pThird;
	sqInt secondLarge;
	sqInt secondLen;
	sqInt secondOperandInteger;
	sqInt thirdLarge;
	sqInt thirdLen;
	sqInt thirdModuloInteger;
	unsigned long long u;
	sqInt _return_value;

	if (!((isKindOfInteger(stackValue(2)))
		 && ((isKindOfInteger(stackValue(1)))
		 && (isKindOfInteger(stackValue(0)))))) {
		primitiveFailFor(PrimErrBadArgument);
		return null;
	}
	secondOperandInteger = stackValue(2);
	thirdModuloInteger = stackValue(1);
	mInverseInteger = stackValue(0);
	/* missing DebugCode */;
	success(isKindOfInteger(stackValue(3)));
	firstInteger = stackValue(3);
	if (failed()) {
		return null;
	}
	mInv = positive32BitValueOf(mInverseInteger);
	if (isIntegerObject(firstInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		firstLarge = createLargeFromSmallInteger(firstInteger);

#else /* SPURVM */
		pushRemappableOop(secondOperandInteger);
		pushRemappableOop(thirdModuloInteger);
		firstLarge = createLargeFromSmallInteger(firstInteger);
		thirdModuloInteger = popRemappableOop();
		secondOperandInteger = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		firstLarge = firstInteger;
	}
	if (isIntegerObject(secondOperandInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		secondLarge = createLargeFromSmallInteger(secondOperandInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		pushRemappableOop(thirdModuloInteger);
		secondLarge = createLargeFromSmallInteger(secondOperandInteger);
		thirdModuloInteger = popRemappableOop();
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		secondLarge = secondOperandInteger;
	}
	if (isIntegerObject(thirdModuloInteger)) {

		/* convert it to a not normalized LargeInteger */
		
#if SPURVM
		thirdLarge = createLargeFromSmallInteger(thirdModuloInteger);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		pushRemappableOop(secondLarge);
		thirdLarge = createLargeFromSmallInteger(thirdModuloInteger);
		secondLarge = popRemappableOop();
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
	}
	else {
		thirdLarge = thirdModuloInteger;
	}
	if (!(failed())) {
		/* begin digitMontgomery:times:modulo:mInvModB: */
		firstLen = ((slotSizeOf(firstLarge)) + 3) / 4;
		secondLen = ((slotSizeOf(secondLarge)) + 3) / 4;
		thirdLen = ((slotSizeOf(thirdLarge)) + 3) / 4;
		if (!((firstLen <= thirdLen)
			 && (secondLen <= thirdLen))) {
			_return_value = primitiveFail();
			goto l2;
		}
		
#if SPURVM
		prod = instantiateClassindexableSize(classLargePositiveInteger(), thirdLen * 4);

#else /* SPURVM */
		pushRemappableOop(firstLarge);
		pushRemappableOop(secondLarge);
		pushRemappableOop(thirdLarge);
		prod = instantiateClassindexableSize(classLargePositiveInteger(), thirdLen * 4);
		thirdLarge = popRemappableOop();
		secondLarge = popRemappableOop();
		firstLarge = popRemappableOop()
#endif /* SPURVM */
;
		if (!(prod)) {
			_return_value = primitiveFailFor(PrimErrNoMemory);
			goto l2;
		}
		/* begin cDigitMontgomery:len:times:len:modulo:len:mInvModB:into: */
		pFirst = ((unsigned int *) (firstIndexableField(firstLarge)));
		pSecond = ((unsigned int *) (firstIndexableField(secondLarge)));
		pThird = ((unsigned int *) (firstIndexableField(thirdLarge)));
		pRes = ((unsigned int *) (firstIndexableField(prod)));
		limit1 = firstLen - 1;
		limit2 = secondLen - 1;
		limit3 = thirdLen - 1;
		lastDigit = 0;
		for (i = 0; i <= limit1; i += 1) {
			accum3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFirst[i]));
			accum3 = (accum3 * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pSecond[0])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[0])));
			u = (accum3 * mInv) & 0xFFFFFFFFU;
			accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[0])));
			accum = (accum2 & 0xFFFFFFFFU) + (accum3 & 0xFFFFFFFFU);
			accum = ((accum >> 32) + (accum2 >> 32)) + (accum3 >> 32);
			for (k = 1; k <= limit2; k += 1) {
				accum3 = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pFirst[i]));
				accum3 = (accum3 * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pSecond[k])))) + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])));
				accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
				accum = (accum + (accum2 & 0xFFFFFFFFU)) + (accum3 & 0xFFFFFFFFU);
				pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
				accum = ((accum >> 32) + (accum2 >> 32)) + (accum3 >> 32);
			}
			for (k = secondLen; k <= limit3; k += 1) {
				accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
				accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])))) + (accum2 & 0xFFFFFFFFU);
				pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
				accum = (accum >> 32) + (accum2 >> 32);
			}
			accum += lastDigit;
			pRes[limit3] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			lastDigit = accum >> 32;
		}
		for (i = firstLen; i <= limit3; i += 1) {
			accum = SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[0]));
			u = (accum * mInv) & 0xFFFFFFFFU;
			accum += u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[0])));
			accum = accum >> 32;
			for (k = 1; k <= limit3; k += 1) {
				accum2 = u * (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[k])));
				accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[k])))) + (accum2 & 0xFFFFFFFFU);
				pRes[k - 1] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
				accum = (accum >> 32) + (accum2 >> 32);
			}
			accum += lastDigit;
			pRes[limit3] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
			lastDigit = accum >> 32;
		}
		if (!((lastDigit == 0)
			 && ((cDigitComparewithlen(pThird, pRes, thirdLen)) == 1))) {

			/* self cDigitSub: pThird len: thirdLen with: pRes len: thirdLen into: pRes */
			accum = 0;
			for (i = 0; i <= limit3; i += 1) {
				accum = (accum + (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pRes[i])))) - (SQ_SWAP_4_BYTES_IF_BIGENDIAN((pThird[i])));
				pRes[i] = (SQ_SWAP_4_BYTES_IF_BIGENDIAN((accum & 0xFFFFFFFFU)));
				accum = 0 - (accum >> 0x3F);
			}
		}
		_return_value = normalizePositive(prod);
	l2:	/* end digitMontgomery:times:modulo:mInvModB: */;
		if (!(failed())) {
			popthenPush(4, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primNormalizeNegative */
EXPORT(sqInt)
primNormalizeNegative(void)
{
	sqInt rcvr;
	sqInt _return_value;

	/* missing DebugCode */;
	success(isLargeNegativeIntegerObject(stackValue(0)));
	rcvr = stackValue(0);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = normalizeNegative(rcvr);
		if (!(failed())) {
			popthenPush(1, _return_value);
		}
	}
	return null;
}

	/* LargeIntegersPlugin>>#primNormalizePositive */
EXPORT(sqInt)
primNormalizePositive(void)
{
	sqInt rcvr;
	sqInt _return_value;

	/* missing DebugCode */;
	success(isLargePositiveIntegerObject(stackValue(0)));
	rcvr = stackValue(0);
	if (failed()) {
		return null;
	}
	if (!(failed())) {
		_return_value = normalizePositive(rcvr);
		if (!(failed())) {
			popthenPush(1, _return_value);
		}
	}
	return null;
}


/*	Note: This is coded so that it can be run in Squeak. */

	/* InterpreterPlugin>>#setInterpreter: */
EXPORT(sqInt)
setInterpreter(struct VirtualMachine *anInterpreter)
{
	sqInt ok;

	interpreterProxy = anInterpreter;
	ok = ((interpreterProxy->majorVersion()) == (VM_PROXY_MAJOR))
	 && ((interpreterProxy->minorVersion()) >= (VM_PROXY_MINOR));
	if (ok) {
		
#if !defined(SQUEAK_BUILTIN_PLUGIN)
		booleanValueOf = interpreterProxy->booleanValueOf;
		classArray = interpreterProxy->classArray;
		classLargeNegativeInteger = interpreterProxy->classLargeNegativeInteger;
		classLargePositiveInteger = interpreterProxy->classLargePositiveInteger;
		classString = interpreterProxy->classString;
		failed = interpreterProxy->failed;
		falseObject = interpreterProxy->falseObject;
		fetchClassOf = interpreterProxy->fetchClassOf;
		firstIndexableField = interpreterProxy->firstIndexableField;
		instantiateClassindexableSize = interpreterProxy->instantiateClassindexableSize;
		integerObjectOf = interpreterProxy->integerObjectOf;
		integerValueOf = interpreterProxy->integerValueOf;
#if VM_PROXY_MAJOR > 1 || (VM_PROXY_MAJOR == 1 && VM_PROXY_MINOR >= 15)
		isBooleanObject = interpreterProxy->isBooleanObject;
#else
#if !defined(isBooleanObject)
		isBooleanObject = 0;
#endif
#endif
		isIntegerObject = interpreterProxy->isIntegerObject;
		popthenPush = interpreterProxy->popthenPush;
		popRemappableOop = interpreterProxy->popRemappableOop;
		positive32BitValueOf = interpreterProxy->positive32BitValueOf;
		primitiveFail = interpreterProxy->primitiveFail;
		primitiveFailFor = interpreterProxy->primitiveFailFor;
		pushRemappableOop = interpreterProxy->pushRemappableOop;
		slotSizeOf = interpreterProxy->slotSizeOf;
		stObjectatput = interpreterProxy->stObjectatput;
		stackIntegerValue = interpreterProxy->stackIntegerValue;
		stackValue = interpreterProxy->stackValue;
		success = interpreterProxy->success;
		trueObject = interpreterProxy->trueObject;
#endif /* !defined(SQUEAK_BUILTIN_PLUGIN) */
	}
	return ok;
}

	/* SmartSyntaxInterpreterPlugin>>#sqAssert: */
static sqInt
sqAssert(sqInt aBool)
{
	/* missing DebugCode */;
	return aBool;
}


/*	Argument bytesObj must not be aSmallInteger! */

	/* LargeIntegersPlugin>>#unsafeByteOfLargeInt:at: */
static unsigned char
unsafeByteOfLargeIntat(sqInt bytesObj, sqInt ix)
{
	return (((unsigned char *) (firstIndexableField(bytesObj))))[ix - 1];
}


#ifdef SQUEAK_BUILTIN_PLUGIN

static char _m[] = "LargeIntegers";
void* LargeIntegers_exports[][3] = {
	{(void*)_m, "getModuleName", (void*)getModuleName},
	{(void*)_m, "primAnyBitFromTo\000\001", (void*)primAnyBitFromTo},
	{(void*)_m, "primDigitAdd\000\001", (void*)primDigitAdd},
	{(void*)_m, "primDigitBitAnd\000\001", (void*)primDigitBitAnd},
	{(void*)_m, "primDigitBitOr\000\001", (void*)primDigitBitOr},
	{(void*)_m, "primDigitBitShiftMagnitude\000\003", (void*)primDigitBitShiftMagnitude},
	{(void*)_m, "primDigitBitXor\000\001", (void*)primDigitBitXor},
	{(void*)_m, "primDigitCompare\000\000", (void*)primDigitCompare},
	{(void*)_m, "primDigitDivNegative\000\002", (void*)primDigitDivNegative},
	{(void*)_m, "primDigitMultiplyNegative\000\001", (void*)primDigitMultiplyNegative},
	{(void*)_m, "primDigitSubtract\000\001", (void*)primDigitSubtract},
	{(void*)_m, "primGetModuleName\000\377", (void*)primGetModuleName},
	{(void*)_m, "primMontgomeryDigitLength\000\377", (void*)primMontgomeryDigitLength},
	{(void*)_m, "primMontgomeryTimesModulo\000\001", (void*)primMontgomeryTimesModulo},
	{(void*)_m, "primNormalizeNegative\000\001", (void*)primNormalizeNegative},
	{(void*)_m, "primNormalizePositive\000\001", (void*)primNormalizePositive},
	{(void*)_m, "setInterpreter", (void*)setInterpreter},
	{NULL, NULL, NULL}
};

#else /* ifdef SQ_BUILTIN_PLUGIN */

signed char primAnyBitFromToAccessorDepth = 1;
signed char primDigitAddAccessorDepth = 1;
signed char primDigitBitAndAccessorDepth = 1;
signed char primDigitBitOrAccessorDepth = 1;
signed char primDigitBitShiftMagnitudeAccessorDepth = 3;
signed char primDigitBitXorAccessorDepth = 1;
signed char primDigitCompareAccessorDepth = 0;
signed char primDigitDivNegativeAccessorDepth = 2;
signed char primDigitMultiplyNegativeAccessorDepth = 1;
signed char primDigitSubtractAccessorDepth = 1;
signed char primMontgomeryTimesModuloAccessorDepth = 1;
signed char primNormalizeNegativeAccessorDepth = 1;
signed char primNormalizePositiveAccessorDepth = 1;

#endif /* ifdef SQ_BUILTIN_PLUGIN */
