# Terminal tails (doc/adr-structure-dominator-tree.md §5; tests/corpus/branchy.c, gcc -O0). The
# compiler joins every `return` of a function into one epilogue, and the value each arm returns
# arrives as a merge of distinct values. The source wrote a `return` in each arm.

NAME=a return of a merge of distinct values is written in each arm that falls to it
FILE=tests/coverage/pinned/branchy_gcc_x64_O0
CMDS=<<EOF
pdd @ sym.gate_one
pdd @ sym.inverted_guard
EOF
EXPECT=<<EOF
uint64_t gate_one(uint32_t arg0)
{
    uint64_t rax_3;

    /* r2dec proof: no individual construct is marked; 18 source obligations: 11 rendered, 7 elided, 0 refused; 5 statements rendered */
    {
        if ((uint8_t)((uint32_t)arg0 != (uint32_t)0xbeefU)) {
            rax_3 = 0;
            return (uint64_t)rax_3;
        } else {
            rax_3 = 1;
            return (uint64_t)rax_3;
        }
    }
}

uint64_t inverted_guard(uint32_t arg0)
{
    extern char g_sink[];
    extern char g_note[];

    uint64_t rax_5;
    uint64_t rax_7;

    /* r2dec proof: no individual construct is marked; 21 source obligations: 14 rendered, 7 elided, 0 refused; 8 statements rendered; 2 data object types refused */
    {
        if ((uint8_t)((int32_t)arg0 <= (int32_t)9U)) {
            rax_7 = (uint64_t)0xffffffffU;
            return (uint64_t)rax_7;
        } else {
            r2sleigh_store_u64((void*)&g_note, (uint64_t)(int32_t)((uint32_t)arg0 + (uint32_t)2U));
            r2sleigh_store_u32((void*)&g_sink, (uint32_t)arg0);
            rax_5 = r2sleigh_load_u64((void*)&g_note);
            rax_7 = rax_5;
            return (uint64_t)rax_7;
        }
    }
}

EOF
RUN

# A terminal block of at most four statements (a `return`, or a call that never returns) is
# written at each `goto` that reaches it, and the block goes once nothing falls into it. `classify`
# is a switch whose every case sets the result and jumps to the one epilogue.

NAME=a terminal block is written at each jump to it
FILE=tests/fixtures/rv_O0g
CMDS=<<EOF
pdd @ sym.classify
EOF
EXPECT=<<EOF
int32_t classify(int32_t x)
{
    uint64_t rax_14;

    /* r2dec proof: no individual construct is marked; 38 source obligations: 22 rendered, 16 elided, 0 refused; 18 statements rendered */
    {
        if ((uint8_t)((uint32_t)7U < (uint32_t)x)) {
        } else {
            switch ((uint32_t)x) {
            case 7:
                {
                    rax_14 = 87;
                    return (int32_t)rax_14;
                }
            case 5:
                {
                    rax_14 = 65;
                    return (int32_t)rax_14;
                }
            case 4:
                {
                    rax_14 = 54;
                    return (int32_t)rax_14;
                }
            case 3:
                {
                    rax_14 = 43;
                    return (int32_t)rax_14;
                }
            case 2:
                {
                    rax_14 = 32;
                    return (int32_t)rax_14;
                }
            case 1:
                {
                    rax_14 = 21;
                    return (int32_t)rax_14;
                }
            case 0:
                {
                    rax_14 = 10;
                    return (int32_t)rax_14;
                }
            case 6:
                break;
            }
        }
        {
            rax_14 = (uint64_t)0xffffffffU;
        }
        {
            return (int32_t)rax_14;
        }
    }
}

EOF
RUN

# A loop's exit that only one edge of the loop reaches, and whose dominator subtree no edge leaves,
# is written where that edge leaves the loop (doc/adr-structure-dominator-tree.md §4). The first
# exit stays after the loop, where `break` reaches it. `find_then_choose`'s match is a test and
# two returns of its own; `skip_then_find` leaves from inside its first loop with a store and a
# return, and from its second with a return.

NAME=an exit with one way in and a closed subtree is written where its edge leaves the loop
FILE=tests/fixtures/loop_exits_gcc_x64_O2
CMDS=<<EOF
pdd @ sym.find_then_choose
pdd @ sym.skip_then_find
EOF
EXPECT=<<EOF
uint64_t find_then_choose(uint64_t arg0, uint32_t arg1, uint32_t arg2)
{
    extern char sink[];

    uint64_t rdi_1;
    uint8_t tmp_40105e_0_1;
    uint32_t tmp_lane_40105e_1_0_1;

    /* r2dec proof: no individual construct is marked; 44 source obligations: 34 rendered, 10 elided, 0 refused; 16 statements rendered; 1 data object type refused */
    {
        rdi_1 = arg0;
        for (; ; ) {
            tmp_40105e_0_1 = r2sleigh_load_u8((void*)rdi_1);
            tmp_lane_40105e_1_0_1 = (uint32_t)(int8_t)tmp_40105e_0_1;
            if ((uint8_t)((uint8_t)tmp_40105e_0_1 != (uint8_t)0U)) {
                r2sleigh_store_u32((void*)&sink, (uint32_t)tmp_lane_40105e_1_0_1);
                if ((uint8_t)((uint32_t)tmp_lane_40105e_1_0_1 == (uint32_t)arg1)) {
                    if ((uint8_t)((uint32_t)arg2 == (uint32_t)0U)) {
                        r2sleigh_store_u32((void*)&sink, (uint32_t)2U);
                        return 20;
                    } else {
                        r2sleigh_store_u32((void*)&sink, (uint32_t)1U);
                        return 10;
                    }
                } else {
                    rdi_1 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
                }
            } else {
                break;
            }
        }
        {
            r2sleigh_store_u32((void*)&sink, (uint32_t)3U);
            return 0;
        }
    }
}

uint64_t skip_then_find(uint64_t arg0, uint32_t arg1, uint32_t arg2)
{
    extern char sink[];

    uint64_t rcx_2;
    uint64_t rdi_1;
    uint8_t tmp_4010bb_0_1;
    uint64_t rax_1;
    uint64_t rax_3;
    uint64_t rdx_2;
    uint32_t tmp_lane_4010e2_2_0_1;
    uint8_t tmp_4010d0_8_1;
    uint32_t tmp_lane_4010b0_6_0_1;

    /* r2dec proof: no individual construct is marked; 79 source obligations: 69 rendered, 10 elided, 0 refused; 26 statements rendered; 1 data object type refused */
    {
        rcx_2 = 0;
        rdi_1 = arg0;
        for (; ; ) {
            tmp_4010bb_0_1 = r2sleigh_load_u8((void*)rdi_1);
            rax_1 = (uint64_t)(uint32_t)(int8_t)tmp_4010bb_0_1;
            if ((uint8_t)((uint8_t)tmp_4010bb_0_1 == (uint8_t)32U)) {
                tmp_lane_4010b0_6_0_1 = (uint32_t)((uint32_t)((uint64_t)rcx_2 >> 0U) + (uint32_t)1U);
                if ((uint8_t)((int32_t)arg2 < (int32_t)tmp_lane_4010b0_6_0_1)) {
                    r2sleigh_store_u32((void*)&sink, (uint32_t)tmp_lane_4010b0_6_0_1);
                    return (uint64_t)0xffffffffU;
                } else {
                    rcx_2 = (uint64_t)(uint32_t)tmp_lane_4010b0_6_0_1;
                    rdi_1 = (uint64_t)((uint64_t)rdi_1 + (uint64_t)1U);
                }
            } else {
                break;
            }
        }
        {
            if ((uint8_t)((uint8_t)tmp_4010bb_0_1 == (uint8_t)0U)) {
            } else {
                rax_3 = rax_1;
                rdx_2 = rdi_1;
                while ((uint8_t)((uint32_t)((uint64_t)rax_3 >> 0U) != (uint32_t)arg1)) {
                    tmp_4010d0_8_1 = r2sleigh_load_u8((void*)(uint64_t)((uint64_t)rdx_2 + (uint64_t)1U));
                    if ((uint8_t)((uint8_t)tmp_4010d0_8_1 == (uint8_t)0U)) {
                        return 0;
                    } else {
                        rax_3 = (uint64_t)(uint32_t)(int8_t)tmp_4010d0_8_1;
                        rdx_2 = (uint64_t)((uint64_t)rdx_2 + (uint64_t)1U);
                    }
                }
                {
                    tmp_lane_4010e2_2_0_1 = (uint32_t)((uint64_t)((uint64_t)(uint32_t)((uint32_t)((uint64_t)rcx_2 >> 0U) - (uint32_t)((uint64_t)rdi_1 >> 0U)) + (uint64_t)rdx_2) >> 0U);
                    r2sleigh_store_u32((void*)&sink, (uint32_t)tmp_lane_4010e2_2_0_1);
                    return (uint64_t)(uint32_t)((uint32_t)tmp_lane_4010e2_2_0_1 + (uint32_t)100U);
                }
            }
            {
                return 0;
            }
        }
    }
}

EOF
RUN
