// File: /workspace/github_c_makefile_star2_O2/cyb70289[P]tt/src/apn/decimal/basic.c
// Function: add_sub_dec
static int add_sub_dec(struct tt_dec *dst, const struct tt_dec *src1,
		const struct tt_dec *src2, int sub)
{
	int ret = 0;

	int sign1 = src1->_sign;
	int sign2 = src2->_sign;
	if (sub)
		sign2 = !sign2;

	/* Check NaN, Inf */
	if (src1->_inf_nan == TT_DEC_NAN || src2->_inf_nan == TT_DEC_NAN) {
		dst->_inf_nan = TT_DEC_NAN;
		return TT_APN_EINVAL;
	}
	if (src1->_inf_nan == TT_DEC_INF || src2->_inf_nan == TT_DEC_INF) {
		dst->_inf_nan = TT_DEC_INF;
		dst->_sign = (src1->_inf_nan == TT_DEC_INF ? sign1 : sign2);
		return TT_APN_EOVERFLOW;
	}
	dst->_inf_nan = 0;

	/* Allocate a new DEC if dst and src overlaps */
	struct tt_dec *dst2 = dst;
	if (dst == src1 || dst == src2) {
		dst2 = tt_dec_alloc(dst->_prec);
		if (!dst2)
			return TT_ENOMEM;
	} else {
		_tt_dec_zero(dst);
	}

	/* Check exponent alignment.
	 * Swap src1 and src2 if exponent of src1 is smaller, and make src1
	 * the one needs to adjust exponent(left shift signifcands).
	 */
	int exp_adj1 = src1->_exp - src2->_exp, exp_adj2 = 0;
	if (exp_adj1 < 0) {
		exp_adj1 = -exp_adj1;
		__tt_swap(src1, src2);
		__tt_swap(sign1, sign2);
	}

	/* Check rounding */
	int msb_dst = src1->_msb;
	/* Shifting "0" can't influence precision */
	if (!_tt_dec_is_zero(src1))
		msb_dst += exp_adj1;
	if (msb_dst < src2->_msb)
		msb_dst = src2->_msb;
	if (msb_dst > dst2->_prec) {
		int adj_adj = msb_dst - dst2->_prec;
		exp_adj1 -= adj_adj;
		exp_adj2 -= adj_adj;
	}
	if ((exp_adj1 < 0 && !_tt_dec_is_true_zero(src1)) ||
			(exp_adj2 < 0 && !_tt_dec_is_true_zero(src2)))
		ret = TT_APN_EROUNDED;

	/* Set result exponent, may adjust later */
	dst2->_exp = src1->_exp - exp_adj1;

	/* Use rounding guard digits to gain precision */
	int adj_adj = 0;
	if (exp_adj2 < 0) {
		int guard_adj = -exp_adj2;
		if (guard_adj > TT_DEC_PREC_RND)
			guard_adj = TT_DEC_PREC_RND;
		if (-(exp_adj2 + guard_adj) < src2->_msb) {
			exp_adj1 += guard_adj;
			exp_adj2 += guard_adj;
			adj_adj += guard_adj;
		}
	}

	/* If both operands need shift, make src1 align-9 shifting */
	if ((exp_adj1 % 9) && (exp_adj2 % 9)) {
		int align_adj = 9 - exp_adj1 % 9;
		if (align_adj > 9)	/* exp_adj may be negative */
			align_adj -= 9;
		exp_adj1 += align_adj;
		exp_adj2 += align_adj;
		adj_adj += align_adj;
	}

	/* "0" needn't shift */
	if (_tt_dec_is_zero(src1))
		exp_adj1 = 0;
	if (_tt_dec_is_zero(src2))
		exp_adj2 = 0;

	/* Copy adjusted significand of src1 to dst */
	tt_assert_fa(dst2->_prec_full > (src1->_msb + exp_adj1));
	shift_digs(dst2->_dig32, dst2->_digsz, src1->_dig32, src1->_msb, exp_adj1);

	/* Copy adjusted significand of src2 to temporary buffer */
	uint *tmpdig = malloc(dst2->_digsz);
	if (!tmpdig) {
		if (dst2 != dst)
			free(dst2);
		return TT_ENOMEM;
	}
	memset(tmpdig, 0, dst2->_digsz);
	tt_assert_fa(dst2->_prec_full > (src2->_msb + exp_adj2));
	shift_digs(tmpdig, dst2->_digsz, src2->_dig32, src2->_msb, exp_adj2);

	/* Compare sign, decide to do "+" or "-" */
	int msb;
	if (sign1 == sign2) {
		/* Adding... */
		dst2->_sign = sign1;
		/* Add aligned significands */
		msb = add_digs(dst2->_dig32, src1->_msb + exp_adj1,
				tmpdig, src2->_msb + exp_adj2);
	} else {
		/* Substracting... */
		/* Pick bigger value */
		int cmp12 = cmp_digs(dst2->_dig32, src1->_msb + exp_adj1,
				tmpdig, src2->_msb + exp_adj2);
		/* Substract aligned significands */
		if (cmp12 >= 0) {
			dst2->_sign = sign1;
			msb = sub_digs(dst2->_dig32,
					dst2->_dig32, src1->_msb + exp_adj1,
					tmpdig, src2->_msb + exp_adj2);
		} else {
			dst2->_sign = sign2;
			msb = sub_digs(dst2->_dig32,
					tmpdig, src2->_msb + exp_adj2,
					dst2->_dig32, src1->_msb + exp_adj1);
		}
	}

	/* Check rounding */
	if (adj_adj) {
		if (_tt_round(_tt_dec_get_dig(dst2->_dig32, adj_adj) & 1,
				_tt_dec_get_dig(dst2->_dig32, adj_adj-1), 0)) {
			/* Construct 10^adj_adj */
			tt_assert_fa(adj_adj < 36);
			uint one[4] = { 0, 0, 0, 0 };
			one[adj_adj / 9] = one_tbl[adj_adj % 9];
			msb = add_digs(dst2->_dig32, msb, one, adj_adj+1);
		}
	}
	/* Adjust significand, msb */
	dst2->_msb = msb - adj_adj;
	/* Only happen on substracting */
	if (dst2->_msb <= 0)
		dst2->_msb = 1;
	tt_assert_fa(dst2->_msb >= 1 && dst2->_msb <= (dst2->_prec+1));
	/* Only happen on adding */
	if (dst2->_msb > dst2->_prec) {
		adj_adj++;
		dst2->_msb--;
		dst2->_exp++;
		ret = TT_APN_EROUNDED;
	}
	shift_digs(dst2->_dig32, dst2->_digsz, dst2->_dig32, msb, -adj_adj);

	free(tmpdig);

	/* Switch buffer if dst overlap with src */
	if (dst2 != dst) {
		free(dst->_dig32);
		memcpy(dst, dst2, sizeof(struct tt_dec));
		free(dst2);
	}

	return ret;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x68, %rsp
movq %rdx, %r12
movq %rdi, %r14
movzwl 0x2(%rsi), %eax
movswl (%rdx), %edx
xorl %ebx, %ebx
testl %edx, %edx
sete %bl
testl %ecx, %ecx
cmovel %edx, %ebx
cmpw $0x2, %ax
je 0x279d
movzwl 0x2(%r12), %ecx
cmpw $0x2, %cx
jne 0x27ba
movw $0x2, 0x2(%r14)
movl $0xffffff32, %ebp       # imm = 0xFFFFFF32
movl %ebp, %eax
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rsi, %r15
movzwl (%rsi), %r13d
movswl %r13w, %edx
cmpw $0x1, %ax
setne %al
cmpw $0x1, %cx
setne %cl
testb %cl, %al
jne 0x27f2
movw $0x1, 0x2(%r14)
cmpw $0x1, 0x2(%r15)
cmovel %edx, %ebx
movw %bx, (%r14)
movl $0xffffff36, %ebp       # imm = 0xFFFFFF36
jmp 0x27a9
movl %edx, 0x2c(%rsp)
andw $0x0, 0x2(%r14)
cmpq %r15, %r14
setne %al
cmpq %r12, %r14
setne %cl
pushq $-0x1
popq %rbp
testb %cl, %al
jne 0x2824
movl 0x8(%r14), %edi
callq 0x1a14
movq %rax, 0x18(%rsp)
testq %rax, %rax
jne 0x2831
jmp 0x27a9
movq %r14, %rdi
callq 0x1b01
movq %r14, 0x18(%rsp)
movw %r13w, 0xe(%rsp)
movl 0x4(%r15), %r13d
subl 0x4(%r12), %r13d
movq %r14, 0x30(%rsp)
js 0x2853
movl %ebx, 0x24(%rsp)
movq %r12, %r14
movq %r15, %r12
jmp 0x2866
negl %r13d
movl 0x2c(%rsp), %eax
movl %eax, 0x24(%rsp)
movw %bx, 0xe(%rsp)
movq %r15, %r14
movl 0x14(%r12), %r15d
movq %r12, %rdi
callq 0x3009
xorl %edx, %edx
testb %al, %al
movl %r13d, %eax
cmovnel %edx, %eax
movq %r15, 0x38(%rsp)
addl %r15d, %eax
movq %r14, 0x40(%rsp)
movl 0x14(%r14), %r14d
cmpl %r14d, %eax
cmovlel %r14d, %eax
movq 0x18(%rsp), %rcx
movl 0x8(%rcx), %ecx
movl %eax, %r15d
subl %ecx, %r15d
negl %r15d
subl %ecx, %eax
cmovlel %edx, %eax
movl $0x0, 0x28(%rsp)
cmovlel %edx, %r15d
subl %eax, %r13d
jns 0x28c8
movq %r12, %rdi
callq 0x3e36
testb %al, %al
je 0x28db
testl %r15d, %r15d
jns 0x28e3
movq 0x40(%rsp), %rdi
callq 0x3e36
testb %al, %al
jne 0x28e3
movl $0xc9, 0x28(%rsp)
movl 0x4(%r12), %eax
subl %r13d, %eax
movq 0x18(%rsp), %rcx
movl %eax, 0x4(%rcx)
movq $0x0, 0x10(%rsp)
pushq $0x9
popq %rdi
testl %r15d, %r15d
jns 0x292e
movl %r15d, %eax
negl %eax
cmpl $0x9, %eax
cmovael %edi, %eax
leal (%rax,%r15), %ecx
movl %ecx, %edx
negl %edx
xorl %esi, %esi
cmpl %edx, %r14d
cmovgl %eax, %esi
cmovlel %r15d, %ecx
movq %rsi, 0x10(%rsp)
addl %esi, %r13d
movl %ecx, %r15d
movl %r13d, %eax
cltd
idivl %edi
movl %edx, %ecx
movl %r15d, %eax
cltd
idivl %edi
testl %ecx, %ecx
je 0x295f
testl %edx, %edx
je 0x295f
movl %ecx, %eax
notl %eax
shrl $0x1f, %eax
leal (%rax,%rax,8), %eax
subl %ecx, %eax
addl %eax, %r13d
addl %eax, %r15d
addl 0x10(%rsp), %eax
movq %rax, 0x10(%rsp)
movq %r12, %rdi
callq 0x3009
xorl %r14d, %r14d
testb %al, %al
cmovnel %r14d, %r13d
movq 0x40(%rsp), %rdi
callq 0x3009
testb %al, %al
cmovnel %r14d, %r15d
movq 0x38(%rsp), %rcx
leal (%rcx,%r13), %eax
movq 0x18(%rsp), %r14
cmpl %eax, 0xc(%r14)
jle 0x2baf
movq 0x18(%r14), %rdi
movl 0x10(%r14), %esi
movq 0x18(%r12), %rdx
movl %r13d, %r8d
callq 0x3024
movl 0x10(%r14), %esi
pushq $0x1
popq %rdi
movq %rsi, 0x38(%rsp)
callq 0x1100
testq %rax, %rax
je 0x2a35
movq 0x40(%rsp), %rbp
movl 0x14(%rbp), %ecx
leal (%rcx,%r15), %edx
cmpl %edx, 0xc(%r14)
jle 0x2bce
movq 0x18(%rbp), %rdx
movq %rax, %r14
movq %rax, %rdi
movq 0x38(%rsp), %rsi
movl %r15d, %r8d
callq 0x3024
cmpl 0x2c(%rsp), %ebx
movq %r14, 0x48(%rsp)
jne 0x2a48
movq 0x18(%rsp), %rbx
movzwl 0xe(%rsp), %eax
movw %ax, (%rbx)
movq 0x18(%rbx), %rdi
addl 0x14(%r12), %r13d
addl 0x14(%rbp), %r15d
movl %r13d, %esi
movq %r14, %rdx
movl %r15d, %ecx
callq 0x32b5
movl %eax, %r15d
movq 0x30(%rsp), %r14
movq 0x10(%rsp), %r12
jmp 0x2ab6
cmpq 0x30(%rsp), %r14
je 0x27a9
movq %r14, %rdi
jmp 0x2ba5
movq 0x18(%rsp), %rbx
movq 0x18(%rbx), %rax
addl 0x14(%r12), %r13d
movq %rax, %r12
addl 0x14(%rbp), %r15d
movq %rax, %rdi
movl %r13d, %esi
movq %r14, %rdx
movl %r15d, %ecx
callq 0x3b0a
testl %eax, %eax
movq 0x30(%rsp), %rbp
js 0x2a90
movzwl 0xe(%rsp), %eax
movw %ax, (%rbx)
movq %r12, %rdi
movq %r12, %rsi
movl %r13d, %edx
movq %r14, %rcx
movl %r15d, %r8d
jmp 0x2aa6
movl 0x24(%rsp), %eax
movw %ax, (%rbx)
movq %r12, %rdi
movq %r14, %rsi
movl %r15d, %edx
movq %r12, %rcx
movl %r13d, %r8d
callq 0x3b5e
movl %eax, %r15d
movq 0x10(%rsp), %r12
movq %rbp, %r14
testl %r12d, %r12d
je 0x2b24
movq 0x18(%rbx), %rdi
movl %r12d, %esi
callq 0x1c07
movl %eax, %ebp
andl $0x1, %ebp
movq 0x18(%rbx), %rdi
leal -0x1(%r12), %esi
callq 0x1c07
movl %ebp, %edi
movl %eax, %esi
xorl %edx, %edx
callq 0x829c
testl %eax, %eax
je 0x2b24
xorps %xmm0, %xmm0
leaq 0x50(%rsp), %r8
movaps %xmm0, (%r8)
movl %r12d, %eax
xorl %edx, %edx
pushq $0x9
popq %rcx
divl %ecx
leaq 0x766a(%rip), %rcx      # 0xa170
movl (%rcx,%rdx,4), %ecx
movl %ecx, 0x50(%rsp,%rax,4)
movq 0x18(%rbx), %rdi
leal 0x1(%r12), %ecx
movl %r15d, %esi
movq %r8, %rdx
callq 0x32b5
movl %eax, %r15d
movl %r15d, %ecx
subl %r12d, %ecx
cmpl $0x2, %ecx
pushq $0x1
popq %rax
cmovgel %ecx, %eax
movl %eax, 0x14(%rbx)
movl 0x8(%rbx), %ecx
leal 0x1(%rcx), %edx
cmpl %edx, %eax
jg 0x2bed
cmpl %ecx, %eax
jbe 0x2b5a
incl %r12d
decl %eax
movl %eax, 0x14(%rbx)
incl 0x4(%rbx)
movl $0xc9, %ebp
jmp 0x2b5e
movl 0x28(%rsp), %ebp
movq 0x18(%rbx), %rdi
movl 0x10(%rbx), %esi
negl %r12d
movq %rdi, %rdx
movl %r15d, %ecx
movl %r12d, %r8d
callq 0x3024
movq 0x48(%rsp), %rdi
callq 0x1030
cmpq %r14, %rbx
je 0x27a9
movq 0x18(%r14), %rdi
callq 0x1030
movups (%rbx), %xmm0
movups 0x10(%rbx), %xmm1
movups %xmm1, 0x10(%r14)
movups %xmm0, (%r14)
movq %rbx, %rdi
callq 0x1030
jmp 0x27a9
leaq 0x13cd0(%rip), %rsi     # 0x16886
leaq 0x74c5(%rip), %rdx      # 0xa082
leaq 0x13c90(%rip), %rcx     # 0x16854
xorl %edi, %edi
movl $0x1e6, %r8d            # imm = 0x1E6
jmp 0x2c0a
leaq 0x13cb1(%rip), %rsi     # 0x16886
leaq 0x74a6(%rip), %rdx      # 0xa082
leaq 0x13c71(%rip), %rcx     # 0x16854
xorl %edi, %edi
movl $0x1f1, %r8d            # imm = 0x1F1
jmp 0x2c0a
leaq 0x13c92(%rip), %rsi     # 0x16886
leaq 0x7487(%rip), %rdx      # 0xa082
leaq 0x13c52(%rip), %rcx     # 0x16854
xorl %edi, %edi
movl $0x21f, %r8d            # imm = 0x21F
xorl %eax, %eax
callq 0x7de8
callq 0x1050