    ! Addition
    ! The fixnum case is done in line, so if the operands are fixnums, we had
    ! an overflow and must box the result in a bignum.

    EXTNAME(m_generic_add):
    	and	%RESULT, TAGMASK, %TMP0
    	and	%ARGREG2, TAGMASK, %TMP1
    	cmp	%TMP0, BVEC_TAG
    	be,a	Ladd_bvec
    	cmp	%TMP1, BVEC_TAG
    	or	%RESULT, %ARGREG2, %TMP2
    	andcc	%TMP2, 3, %g0
    	be,a	Ladd_fix
    	nop
    	cmp	%TMP0, VEC_TAG
    	be,a	Ladd_vec
    	cmp	%TMP1, VEC_TAG
    	b	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    Ladd_bvec:
    	be,a	Ladd_bvec2
    	ldub	[ %RESULT + 3 - BVEC_TAG ], %TMP0
    	b	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    Ladd_bvec2:
    	ldub	[ %ARGREG2 + 3 - BVEC_TAG ], %TMP1
    	cmp	%TMP0, FLONUM_HDR
    	be,a	Ladd_flo
    	cmp	%TMP1, FLONUM_HDR
    	cmp	%TMP0, COMPNUM_HDR
    	be,a	Ladd_comp
    	cmp	%TMP1, COMPNUM_HDR
    	cmp	%TMP0, BIGNUM_HDR
    	be,a	Ladd_big
    	cmp	%TMP1, BIGNUM_HDR
    	b	Lnumeric_error
    	mov	EX_ADD, %TMP0
    Ladd_flo:
    	be,a	Ladd_flo2
    	ldd	[ %RESULT + 8 - BVEC_TAG ], %f2
    	! Got a flonum and something; check for compnum with 0i.
    	cmp	%TMP1, COMPNUM_HDR
    	bne	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    	ldd	[ %ARGREG2 - BVEC_TAG + 16 ], %f2
    	fcmpd	%f0, %f2
    	nop
    	fbe,a	Ladd_flo2
    	ldd	[ %RESULT + 8 - BVEC_TAG ], %f2
    	b	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    Ladd_flo2:
    	ldd	[ %ARGREG2 + 8 - BVEC_TAG ], %f4
    	b	_box_flonum
    	faddd	%f2, %f4, %f2
    Ladd_comp:
    	be,a	Ladd_comp2
    	ldd	[ %RESULT + 8 - BVEC_TAG ], %f2
    	! op1 is a compnum, but perhaps op2 is a flonum and op1 has 0i.
    	cmp	%TMP1, FLONUM_HDR
    	bne	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    	ldd	[ %RESULT - BVEC_TAG + 16 ], %f2
    	fcmpd	%f0, %f2
    	nop
    	fbe,a	Ladd_flo2
    	ldd	[ %RESULT + 8 - BVEC_TAG ], %f2
    	b	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    Ladd_comp2:
    	ldd	[ %ARGREG2 + 8 - BVEC_TAG ], %f4
    	ldd	[ %RESULT + 16 - BVEC_TAG ], %f6
    	faddd	%f2, %f4, %f2
    	ldd	[ %ARGREG2 + 16 - BVEC_TAG ], %f8
    	b	_box_compnum
    	faddd	%f6, %f8, %f4
    Ladd_big:
    	be,a	Ladd_big2
    	mov	2, %TMP1
    	b	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    Ladd_big2:
    	b	internal_scheme_call
    	mov	MS_BIGNUM_ADD, %TMP2
    Ladd_vec:
    	be,a	Ladd_vec2
    	ldub	[ %RESULT - VEC_TAG + 3 ], %TMP0
    	b	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    Ladd_vec2:
    	ldub	[ %RESULT - VEC_TAG + 3 ], %TMP1
    	cmp	%TMP0, RATNUM_HDR
    	be,a	Ladd_rat
    	cmp	%TMP1, RATNUM_HDR
    	cmp	%TMP0, RECTNUM_HDR
    	be,a	Ladd_rect
    	cmp	%TMP1, RECTNUM_HDR
    	b	Lnumeric_error
    	mov	EX_ADD, %TMP0
    Ladd_rat:
    	be,a	Ladd_rat2
    	mov	2, %TMP1
    	b	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    Ladd_rat2:
    	b	internal_scheme_call
    	mov	MS_RATNUM_ADD, %TMP2
    Ladd_rect:
    	be,a	Ladd_rect2
    	mov	2, %TMP1
    	b	_contagion
    	mov	MS_GENERIC_ADD, %TMP2
    Ladd_rect2:
    	b	internal_scheme_call
    	mov	MS_RECTNUM_ADD, %TMP2
    Ladd_fix:
    	sra	%RESULT, 2, %TMP0
    	sra	%ARGREG2, 2, %TMP1
    	b	_box_single_bignum
    	add	%TMP0, %TMP1, %TMP0

    ! ...

    ! The following subroutines are common.
    !
    ! Box the double in %f2/f3 as a flonum. Return tagged pointer in RESULT.
    ! Scheme return address in %o7.

    _box_flonum:
    	st	%o7, [ %GLOBALS + G_RETADDR ]
    	call	EXTNAME(mem_internal_alloc)
    	mov	16, %RESULT
    	ld	[ %GLOBALS + G_RETADDR ], %o7
    	std	%f2, [ %RESULT + 8 ]
    	set	(12 << 8) | FLONUM_HDR, %TMP1
    	st	%TMP1, [ %RESULT ]
    	jmp	%o7 + 8
    	add	%RESULT, BVEC_TAG, %RESULT

    ! Box the two doubles in %f2/%f3 and %f4/%f5 as a compnum.
    ! Return tagged pointer in RESULT.
    ! Scheme return address in %o7.

    _box_compnum:
    	st	%o7, [ %GLOBALS + G_RETADDR ]
    	call	EXTNAME(mem_internal_alloc)
    	mov	24, %RESULT
    	ld	[ %GLOBALS + G_RETADDR ], %o7
    	std	%f2, [ %RESULT + 8 ]
    	std	%f4, [ %RESULT + 16 ]
    	set	(20 << 8) | COMPNUM_HDR, %TMP0
    	st	%TMP0, [ %RESULT ]
    	jmp	%o7+8
    	add	%RESULT, BVEC_TAG, %RESULT

    ! Box an integer in a bignum with one digit. The integer is passed in %TMP0.
    ! %o7 has the Scheme return address.

    _box_single_bignum:
    	cmp	%TMP0, 0
    	bge,a	_box_single_positive_bignum
    	mov	0, %TMP2
    	mov	1, %TMP2
    	neg	%TMP0

    ! Sign (0 or 1) is in %TMP2, untagged, positive number in %TMP0.

    _box_single_positive_bignum:
    	st	%TMP0, [ %GLOBALS + G_GENERIC_NRTMP1 ]
    	st	%TMP2, [ %GLOBALS + G_GENERIC_NRTMP2 ]
    	st	%o7, [ %GLOBALS + G_RETADDR ]
    	call	EXTNAME(mem_internal_alloc)
    	mov	12, %RESULT
    	ld	[ %GLOBALS + G_RETADDR ], %o7
    	ld	[ %GLOBALS + G_GENERIC_NRTMP1 ], %TMP0
    	ld	[ %GLOBALS + G_GENERIC_NRTMP2 ], %TMP2
    	sll	%TMP2, 16, %TMP2
    	add	%TMP2, 1, %TMP1
    	st	%TMP1, [ %RESULT + 4 ]		! store sign, length
    	st	%TMP0, [ %RESULT + 8 ]		! store number
    	set	(8 << 8) | BIGNUM_HDR, %TMP0
    	st	%TMP0, [ %RESULT ]
    	jmp	%o7+8
    	or	%RESULT, BVEC_TAG, %RESULT