namespace asm_code {
typedef array<reg_scalar, 2> reg_scalar_128;
void shift_right(
const reg_alloc& regs, array<reg_scalar, 2> v, reg_scalar amount, reg_scalar res,
reg_scalar tmp_rcx, reg_scalar tmp_res_2
) {
EXPAND_MACROS_SCOPE;
m.bind(v, "v");
m.bind(amount, "amount");
m.bind(res, "res");
assert(tmp_rcx.value==reg_rcx.value);
m.bind(tmp_res_2, "res_2");
APPEND_M(str( "MOV RCX, `amount" ));
APPEND_M(str( "MOV `res, `v_0" ));
APPEND_M(str( "SHRD `res, `v_1, CL" ));
APPEND_M(str( "XOR `res_2, `res_2" ));
APPEND_M(str( "SUB RCX, 64" ));
APPEND_M(str( "CMOVAE `res, `res_2" ));
APPEND_M(str( "CMOVAE `res_2, `v_1" ));
APPEND_M(str( "SHR `res_2, CL" ));
APPEND_M(str( "OR `res, `res_2" ));
}
void dot_product_exact(reg_alloc regs, array<reg_scalar, 2> a, array<reg_scalar, 2> b, reg_scalar out, string overflow_label) {
EXPAND_MACROS_SCOPE;
m.bind(a, "a");
m.bind(b, "b");
m.bind(out, "out");
reg_scalar rax=regs.bind_scalar(m, "rax", reg_rax);
reg_scalar rdx=regs.bind_scalar(m, "rdx", reg_rdx);
APPEND_M(str( "MOV RAX, `a_0" ));
APPEND_M(str( "MUL `b_0" ));
APPEND_M(str( "JC #", overflow_label ));
APPEND_M(str( "MOV `out, RAX" ));
APPEND_M(str( "MOV RAX, `a_1" ));
APPEND_M(str( "MUL `b_1" ));
APPEND_M(str( "JC #", overflow_label ));
APPEND_M(str( "ADD `out, RAX" ));
APPEND_M(str( "JC #", overflow_label ));
}
void gcd_128(
reg_alloc regs_parent,
array<reg_spill, 2> spill_ab_start, array<reg_spill, 2> spill_u, array<reg_spill, 2> spill_v,
reg_spill spill_parity, reg_spill spill_is_lehmer, reg_spill spill_ab_threshold,
string no_progress_label
) {
EXPAND_MACROS_SCOPE_PUBLIC;
track_asm( "gcd_128" );
m.bind(spill_ab_start[0], "spill_ab_start_0_0");
m.bind(spill_ab_start[0]+8, "spill_ab_start_0_1");
m.bind(spill_ab_start[1], "spill_ab_start_1_0");
m.bind(spill_ab_start[1]+8, "spill_ab_start_1_1");
m.bind(spill_u, "spill_u");
m.bind(spill_v, "spill_v");
m.bind(spill_parity, "spill_parity");
m.bind(spill_is_lehmer, "spill_is_lehmer");
m.bind(spill_ab_threshold, "spill_ab_threshold_0");
m.bind(spill_ab_threshold+8, "spill_ab_threshold_1");
reg_vector vector_ab=regs_parent.bind_vector(m, "vector_ab");
reg_vector vector_u=regs_parent.bind_vector(m, "vector_u");
reg_vector vector_v=regs_parent.bind_vector(m, "vector_v");
reg_vector vector_is_lehmer=regs_parent.bind_vector(m, "vector_is_lehmer");
reg_vector vector_ab_threshold=regs_parent.bind_vector(m, "vector_ab_threshold");
reg_spill spill_iter=regs_parent.bind_spill(m, "spill_iter");
APPEND_M(str( "MOV QWORD PTR `spill_u_0, 1" ));
APPEND_M(str( "MOV QWORD PTR `spill_u_1, 0" ));
APPEND_M(str( "MOV QWORD PTR `spill_v_0, 0" ));
APPEND_M(str( "MOV QWORD PTR `spill_v_1, 1" ));
APPEND_M(str( "MOV QWORD PTR `spill_parity, 0" ));
APPEND_M(str( "MOV QWORD PTR `spill_iter, #", to_hex(gcd_128_max_iter) ));
string start_label=m.alloc_label();
string loop_label=m.alloc_label();
string exit_label=m.alloc_label();
string exit_iter_0_label=m.alloc_label();
string start_assign_label=m.alloc_label();
APPEND_M(str( "JMP #", start_assign_label ));
APPEND_M(str( "#:", loop_label ));
track_asm( "gcd_128 iter" );
reg_scalar new_u_0=regs_parent.bind_scalar(m, "new_u_0"); reg_scalar new_u_1=regs_parent.bind_scalar(m, "new_u_1"); reg_scalar new_v_0=regs_parent.bind_scalar(m, "new_v_0"); reg_scalar new_v_1=regs_parent.bind_scalar(m, "new_v_1");
if (use_divide_table) {
string base_exit_label=m.alloc_label();
string base_loop_label=m.alloc_label();
APPEND_M(str( "MOV `new_v_1, #", to_hex(gcd_base_max_iter_divide_table) ));
APPEND_M(str( "MOVDQA `vector_u, #", constant_address_uint64(1ull, 0ull) ));
APPEND_M(str( "MOVDQA `vector_v, #", constant_address_uint64(0ull, 1ull) ));
APPEND_M(str( "#:", base_loop_label ));
gcd_64_iteration(regs_parent, vector_is_lehmer, {new_u_0, new_u_1}, {vector_u, vector_v}, new_v_0, base_exit_label);
APPEND_M(str( "DEC `new_v_1" ));
APPEND_M(str( "JNZ #", base_loop_label ));
APPEND_M(str( "#:", base_exit_label ));
APPEND_M(str( "CMP `new_v_1, #", to_hex(gcd_base_max_iter_divide_table) ));
APPEND_M(str( "JE #", track_asm( "gcd_128 base no progress", exit_label ) ));
} else {
gcd_base_continued_fraction(
regs_parent, vector_ab, vector_u, vector_v, vector_is_lehmer, vector_ab_threshold,
track_asm( "gcd_128 base no progress", exit_label )
);
}
{
EXPAND_MACROS_SCOPE;
reg_alloc regs=regs_parent;
reg_scalar m_0_0=regs.bind_scalar(m, "m_0_0");
reg_scalar m_0_1=regs.bind_scalar(m, "m_0_1");
reg_scalar m_1_0=regs.bind_scalar(m, "m_1_0");
reg_scalar m_1_1=regs.bind_scalar(m, "m_1_1");
reg_scalar tmp_0=regs.bind_scalar(m, "tmp_0");
reg_scalar tmp_1=regs.bind_scalar(m, "tmp_1");
reg_vector tmp_a=regs.bind_vector(m, "tmp_a");
reg_vector tmp_b=regs.bind_vector(m, "tmp_b");
reg_vector tmp_c=regs.bind_vector(m, "tmp_c");
reg_vector c_double_abs_mask=regs.bind_vector(m, "double_abs_mask");
if (!use_divide_table) {
APPEND_M(str( "MOVAPD `double_abs_mask, #", constant_address_uint64(double_abs_mask, double_abs_mask) ));
}
auto abs_tmp_a=[&]() {
if (use_divide_table) {
APPEND_M(str( "MOVDQA `tmp_b, `tmp_a" ));
APPEND_M(str( "PSRAD `tmp_b, 32" )); APPEND_M(str( "PSHUFD `tmp_b, `tmp_b, #", to_hex( 0b11110101 ) ));
APPEND_M(str( "PADDQ `tmp_a, `tmp_b" ));
APPEND_M(str( "PXOR `tmp_a, `tmp_b" ));
} else {
APPEND_M(str( "PAND `tmp_a, `double_abs_mask" ));
}
};
auto mov_low_tmp_a=[&](string target) {
if (use_divide_table) {
APPEND_M(str( "MOVQ `#, `tmp_a", target ));
} else {
APPEND_M(str( "CVTTSD2SI `#, `tmp_a", target ));
}
};
APPEND_M(str( "MOVAPD `tmp_a, `vector_u" ));
abs_tmp_a();
mov_low_tmp_a( (use_divide_table)? "m_0_0" : "m_0_0" );
APPEND_M(str( "SHUFPD `tmp_a, `tmp_a, 3" ));
mov_low_tmp_a( (use_divide_table)? "m_0_1" : "m_1_0" );
APPEND_M(str( "MOVAPD `tmp_a, `vector_v" ));
abs_tmp_a();
mov_low_tmp_a( (use_divide_table)? "m_1_0" : "m_0_1" );
APPEND_M(str( "SHUFPD `tmp_a, `tmp_a, 3" ));
mov_low_tmp_a( (use_divide_table)? "m_1_1" : "m_1_1" );
APPEND_M(str( "MOV `tmp_0, `spill_u_0" ));
APPEND_M(str( "MOV `tmp_1, `spill_u_1" ));
dot_product_exact(regs, {m_0_0, m_0_1}, {tmp_0, tmp_1}, new_u_0, track_asm( "gcd_128 uv overflow", exit_label ));
dot_product_exact(regs, {m_1_0, m_1_1}, {tmp_0, tmp_1}, new_u_1, track_asm( "gcd_128 uv overflow", exit_label ));
APPEND_M(str( "MOV `tmp_0, `spill_v_0" ));
APPEND_M(str( "MOV `tmp_1, `spill_v_1" ));
dot_product_exact(regs, {m_0_0, m_0_1}, {tmp_0, tmp_1}, new_v_0, track_asm( "gcd_128 uv overflow", exit_label ));
dot_product_exact(regs, {m_1_0, m_1_1}, {tmp_0, tmp_1}, new_v_1, track_asm( "gcd_128 uv overflow", exit_label ));
}
reg_scalar new_ab_0_0=regs_parent.bind_scalar(m, "new_ab_0_0");
reg_scalar new_ab_0_1=regs_parent.bind_scalar(m, "new_ab_0_1");
reg_scalar new_ab_1_0=regs_parent.bind_scalar(m, "new_ab_1_0");
reg_scalar new_ab_1_1=regs_parent.bind_scalar(m, "new_ab_1_1");
reg_scalar new_parity=regs_parent.bind_scalar(m, "new_parity");
{
EXPAND_MACROS_SCOPE;
reg_alloc regs=regs_parent;
reg_scalar rax=regs.bind_scalar(m, "rax", reg_rax);
reg_scalar rdx=regs.bind_scalar(m, "rdx", reg_rdx);
reg_vector tmp_a=regs.bind_vector(m, "tmp_a");
reg_scalar ab_start_0_0=regs.bind_scalar(m, "ab_start_0_0");
reg_scalar ab_start_0_1=regs.bind_scalar(m, "ab_start_0_1");
reg_scalar ab_start_1_0=regs.bind_scalar(m, "ab_start_1_0");
reg_scalar ab_start_1_1=regs.bind_scalar(m, "ab_start_1_1");
APPEND_M(str( "MOV `ab_start_0_0, `spill_ab_start_0_0" ));
APPEND_M(str( "MOV `ab_start_0_1, `spill_ab_start_0_1" ));
APPEND_M(str( "MOV `ab_start_1_0, `spill_ab_start_1_0" ));
APPEND_M(str( "MOV `ab_start_1_1, `spill_ab_start_1_1" ));
APPEND_M(str( "MOVAPD `tmp_a, `vector_v" ));
APPEND_M(str( "SHUFPD `tmp_a, `tmp_a, 3" ));
APPEND_M(str( "MOVQ RAX, `tmp_a" ));
APPEND_M(str( "SHR RAX, 63" ));
APPEND_M(str( "MOV `new_parity, `spill_parity" ));
APPEND_M(str( "XOR `new_parity, RAX" ));
auto dot_product_subtract=[&](string a0, string a1, string b0, string b1, string u, string v, string out0, string out1) {
APPEND_M(str( "MOV RAX, `#", a0 ));
APPEND_M(str( "MUL `#", u ));
APPEND_M(str( "MOV `#, RAX", out0 ));
APPEND_M(str( "MOV `#, RDX", out1 ));
APPEND_M(str( "MOV RAX, `#", a1 ));
APPEND_M(str( "MUL `#", u ));
APPEND_M(str( "ADD `#, RAX", out1 ));
APPEND_M(str( "MOV RAX, `#", b0 ));
APPEND_M(str( "MUL `#", v ));
APPEND_M(str( "SUB `#, RAX", out0 ));
APPEND_M(str( "SBB `#, RDX", out1 ));
APPEND_M(str( "MOV RAX, `#", b1 ));
APPEND_M(str( "MUL `#", v ));
APPEND_M(str( "SUB `#, RAX", out1 ));
};
dot_product_subtract(
"ab_start_0_0", "ab_start_0_1",
"ab_start_1_0", "ab_start_1_1",
"new_u_0", "new_v_0",
"new_ab_0_0", "new_ab_0_1"
);
dot_product_subtract(
"ab_start_1_0", "ab_start_1_1",
"ab_start_0_0", "ab_start_0_1",
"new_v_1", "new_u_1",
"new_ab_1_0", "new_ab_1_1"
);
APPEND_M(str( "MOV RAX, -1" ));
APPEND_M(str( "ADD RAX, `new_parity" )); APPEND_M(str( "NOT RAX" ));
auto conditional_negate=[&](string out0, string out1) {
APPEND_M(str( "XOR `#, RAX", out0 ));
APPEND_M(str( "XOR `#, RAX", out1 ));
APPEND_M(str( "ADD `#, `new_parity", out0 ));
APPEND_M(str( "ADC `#, 0", out1 ));
};
conditional_negate( "new_ab_0_0", "new_ab_0_1" );
conditional_negate( "new_ab_1_0", "new_ab_1_1" );
}
reg_scalar ab_threshold_0=regs_parent.bind_scalar(m, "ab_threshold_0");
reg_scalar ab_threshold_1=regs_parent.bind_scalar(m, "ab_threshold_1");
{
EXPAND_MACROS_SCOPE;
reg_alloc regs=regs_parent;
reg_scalar ab_delta_0=regs.bind_scalar(m, "ab_delta_0");
reg_scalar ab_delta_1=regs.bind_scalar(m, "ab_delta_1");
reg_scalar b_new_min=regs.bind_scalar(m, "b_new_min");
reg_scalar is_lehmer=regs.bind_scalar(m, "is_lehmer");
APPEND_M(str( "MOV `is_lehmer, `spill_is_lehmer" ));
APPEND_M(str( "MOV `ab_delta_0, `new_ab_0_0" ));
APPEND_M(str( "MOV `ab_delta_1, `new_ab_0_1" ));
APPEND_M(str( "SUB `ab_delta_0, `new_ab_1_0" ));
APPEND_M(str( "SBB `ab_delta_1, `new_ab_1_1" ));
APPEND_M(str( "CMP `new_parity, 0" ));
APPEND_M(str( "MOV `ab_threshold_0, `new_u_1" ));
APPEND_M(str( "CMOVE `ab_threshold_0, `new_v_1" ));
APPEND_M(str( "MOV `ab_threshold_1, `new_u_0" ));
APPEND_M(str( "CMOVE `ab_threshold_1, `new_v_0" ));
APPEND_M(str( "MOV `b_new_min, `new_v_1" ));
APPEND_M(str( "CMOVE `b_new_min, `new_u_1" ));
APPEND_M(str( "CMP `is_lehmer, 0" ));
APPEND_M(str( "CMOVE `ab_threshold_0, `is_lehmer" )); APPEND_M(str( "CMOVE `ab_threshold_1, `is_lehmer" ));
APPEND_M(str( "CMOVE `b_new_min, `is_lehmer" ));
APPEND_M(str( "ADD `ab_threshold_0, `ab_threshold_1" ));
APPEND_M(str( "MOV `ab_threshold_1, 0" ));
APPEND_M(str( "ADC `ab_threshold_1, 0" ));
APPEND_M(str( "SUB `ab_delta_0, `ab_threshold_0" ));
APPEND_M(str( "SBB `ab_delta_1, `ab_threshold_1" ));
APPEND_M(str( "JC #", track_asm( "gcd_128 lehmer fail ab_delta<uv_delta", exit_label ) ));
APPEND_M(str( "CMP `new_ab_1_0, `b_new_min" ));
APPEND_M(str( "MOV `b_new_min, `new_ab_1_1" ));
APPEND_M(str( "SBB `b_new_min, 0" ));
APPEND_M(str( "JC #", track_asm( "gcd_128 lehmer fail new_ab[1]<b_new_min", exit_label ) ));
APPEND_M(str( "MOV `ab_threshold_0, `spill_ab_threshold_0" ));
APPEND_M(str( "MOV `ab_threshold_1, `spill_ab_threshold_1" ));
APPEND_M(str( "MOV `ab_delta_0, `ab_threshold_0" ));
APPEND_M(str( "MOV `ab_delta_1, `ab_threshold_1" ));
APPEND_M(str( "SUB `ab_delta_0, `new_ab_0_0" ));
APPEND_M(str( "SBB `ab_delta_1, `new_ab_0_1" ));
APPEND_M(str( "JNC #", track_asm( "gcd_128 went too far ab_threshold>=new_ab[0]", exit_label ) ));
APPEND_M(str( "MOV `spill_u_0, `new_u_0" ));
APPEND_M(str( "MOV `spill_u_1, `new_u_1" ));
APPEND_M(str( "MOV `spill_v_0, `new_v_0" ));
APPEND_M(str( "MOV `spill_v_1, `new_v_1" ));
APPEND_M(str( "MOV `spill_parity, `new_parity" ));
track_asm( "gcd_128 good iter" );
APPEND_M(str( "MOV `ab_delta_0, `spill_iter" ));
APPEND_M(str( "DEC `ab_delta_0" ));
APPEND_M(str( "MOV `spill_iter, `ab_delta_0" ));
APPEND_M(str( "JZ #", track_asm( "gcd_128 good exit", exit_iter_0_label ) ));
}
APPEND_M(str( "#:", start_label ));
{
EXPAND_MACROS_SCOPE;
reg_alloc regs=regs_parent;
reg_scalar tmp_0=regs.bind_scalar(m, "tmp_0", reg_rax);
reg_scalar tmp_1=regs.bind_scalar(m, "tmp_1", reg_rdx);
reg_scalar tmp_2=regs.bind_scalar(m, "tmp_2");
reg_scalar tmp_3=regs.bind_scalar(m, "tmp_3", reg_rcx);
reg_scalar ab_0_0=new_ab_0_0;
reg_scalar ab_0_1=new_ab_0_1;
reg_scalar ab_1_0=new_ab_1_0;
reg_scalar ab_1_1=new_ab_1_1;
m.bind(new_ab_0_0, "ab_0_0");
m.bind(new_ab_0_1, "ab_0_1");
m.bind(new_ab_1_0, "ab_1_0");
m.bind(new_ab_1_1, "ab_1_1");
m.bind(ab_threshold_0, "ab_threshold_0");
m.bind(ab_threshold_1, "ab_threshold_1");
APPEND_M(str( "XOR `tmp_3, `tmp_3" ));
APPEND_M(str( "MOV `tmp_0, `ab_1_0" ));
APPEND_M(str( "MOV `tmp_1, `ab_1_1" ));
APPEND_M(str( "SUB `tmp_0, `ab_threshold_0" ));
APPEND_M(str( "SBB `tmp_1, `ab_threshold_1" ));
APPEND_M(str( "JC #", track_asm( "gcd_128 ab[1]<ab_threshold", exit_label ) ));
APPEND_M(str( "MOV `tmp_2, `tmp_0" ));
APPEND_M(str( "OR `tmp_2, `tmp_1" )); APPEND_M(str( "JZ #", track_asm( "gcd_128 ab[1]==ab_threshold", exit_label ) ));
APPEND_M(str( "MOV `tmp_0, `ab_0_1" ));
APPEND_M(str( "MOV `tmp_1, 64" ));
APPEND_M(str( "CMP `ab_0_1, 0" ));
#ifdef CHIAOSX
string cmoveq_label1=m.alloc_label();
APPEND_M(str( "JNE #", cmoveq_label1));
APPEND_M(str( "MOV `tmp_0, `ab_0_0" ));
APPEND_M(str("#:", cmoveq_label1));
string cmoveq_label2=m.alloc_label();
APPEND_M(str( "JNE #", cmoveq_label2));
APPEND_M(str( "MOV `tmp_1, `tmp_3" ));
APPEND_M(str("#:", cmoveq_label2));
#else
APPEND_M(str( "CMOVEQ `tmp_0, `ab_0_0" ));
APPEND_M(str( "CMOVEQ `tmp_1, `tmp_3" ));
#endif
APPEND_M(str( "BSR `tmp_0, `tmp_0" ));
APPEND_M(str( "ADD `tmp_1, `tmp_0" ));
APPEND_M(str( "INC `tmp_1" ));
APPEND_M(str( "XOR `tmp_0, `tmp_0" ));
APPEND_M(str( "MOV `tmp_2, `spill_is_lehmer" ));
APPEND_M(str( "CMP `tmp_2, 0" ));
APPEND_M(str( "MOV `tmp_3, 96" ));
APPEND_M(str( "CMOVNE `tmp_0, `tmp_3" ));
APPEND_M(str( "XOR `tmp_3, `tmp_3" ));
APPEND_M(str( "CMP `tmp_1, `tmp_0" ));
APPEND_M(str( "CMOVB `tmp_1, `tmp_0" ));
APPEND_M(str( "SUB `tmp_1, #", to_hex(gcd_base_bits) ));
APPEND_M(str( "CMOVB `tmp_1, `tmp_3" ));
APPEND_M(str( "OR `tmp_2, `tmp_1" ));
if (!use_divide_table) {
#ifdef CHIAOSX
APPEND_M(str( "LEA `tmp_3, [RIP+#]", constant_address_uint64(0ull, 0ull, false) ));
APPEND_M(str( "LEA `tmp_0, [RIP+#]", constant_address_uint64(~(0ull), ~(0ull), false) ));
#else
APPEND_M(str( "MOV `tmp_3, OFFSET FLAT:#", constant_address_uint64(0ull, 0ull, false) ));
APPEND_M(str( "MOV `tmp_0, OFFSET FLAT:#", constant_address_uint64(~(0ull), ~(0ull), false) ));
#endif
} else {
#ifdef CHIAOSX
APPEND_M(str( "LEA `tmp_3, [RIP+#]", constant_address_uint64(gcd_mask_exact[0], gcd_mask_exact[1], false) ));
APPEND_M(str( "LEA `tmp_0, [RIP+#]", constant_address_uint64(gcd_mask_approximate[0], gcd_mask_approximate[1], false) ));
#else
APPEND_M(str( "MOV `tmp_3, OFFSET FLAT:#", constant_address_uint64(gcd_mask_exact[0], gcd_mask_exact[1], false) ));
APPEND_M(str( "MOV `tmp_0, OFFSET FLAT:#", constant_address_uint64(gcd_mask_approximate[0], gcd_mask_approximate[1], false) ));
#endif
}
APPEND_M(str( "CMOVZ `tmp_0, `tmp_3" ));
APPEND_M(str( "MOVAPD `vector_is_lehmer, [`tmp_0]" ));
shift_right(regs, {ab_1_0, ab_1_1}, tmp_1, new_u_1, tmp_3, tmp_2);
if (!use_divide_table) {
APPEND_M(str( "CVTSI2SD `vector_ab, `new_u_1" ));
}
if (!use_divide_table) {
APPEND_M(str( "SHUFPD `vector_ab, `vector_ab, 0" ));
}
shift_right(regs, {ab_0_0, ab_0_1}, tmp_1, new_u_0, tmp_3, tmp_2);
if (!use_divide_table) {
APPEND_M(str( "CVTSI2SD `vector_ab, `new_u_0" ));
}
shift_right(regs, {ab_threshold_0, ab_threshold_1}, tmp_1, new_v_0, tmp_3, tmp_2);
if (!use_divide_table) {
APPEND_M(str( "CVTSI2SD `vector_ab_threshold, `new_v_0" ));
APPEND_M(str( "SHUFPD `vector_ab_threshold, `vector_ab_threshold, 0" ));
}
}
APPEND_M(str( "JMP #", loop_label ));
APPEND_M(str( "#:", exit_label ));
{
EXPAND_MACROS_SCOPE;
reg_alloc regs=regs_parent;
reg_scalar tmp=regs.bind_scalar(m, "tmp");
APPEND_M(str( "MOV `tmp, `spill_iter" ));
APPEND_M(str( "CMP `tmp, #", to_hex(gcd_128_max_iter) ));
APPEND_M(str( "JE #", track_asm( "gcd_128 no progress", no_progress_label ) ));
}
APPEND_M(str( "JMP #", track_asm( "gcd_128 premature exit", exit_iter_0_label ) ));
APPEND_M(str( "#:", start_assign_label ));
APPEND_M(str( "MOV `new_ab_0_0, `spill_ab_start_0_0" ));
APPEND_M(str( "MOV `new_ab_0_1, `spill_ab_start_0_1" ));
APPEND_M(str( "MOV `new_ab_1_0, `spill_ab_start_1_0" ));
APPEND_M(str( "MOV `new_ab_1_1, `spill_ab_start_1_1" ));
APPEND_M(str( "MOV `ab_threshold_0, `spill_ab_threshold_0" ));
APPEND_M(str( "MOV `ab_threshold_1, `spill_ab_threshold_1" ));
APPEND_M(str( "JMP #", start_label ));
APPEND_M(str( "#:", exit_iter_0_label ));
}
}