Search code examples
cassemblyx86permutationinline-assembly

assembly - Issue with permutations generation


I'm trying to list all the permutations of the first N natural numbers (N <= 6) with MSVC Assembly 8086 inline. I can't change anything of the C program, I can only manage the assembly code. So this is what I've done (and works with N <= 3), using the lexicographic algorithm:

#include <stdio.h>
int main() {
// Variabili
int N=4;    // N <= 6
int Perm[4326];    // permutations array: the dimension is sufficient for N <= 6
int Num;     // At the end it must contains the number of generated permutations
// Assembler block
__asm
{
    XOR EAX, EAX    ; Reset EAX (permutations counter)
    MOV ECX, N        ; Put N into ECX
    CMP ECX, 1        ; Compare ECX and 1
    JBE Piccolo        ; If ECX <= 1 go to Piccolo (particular cases 1 and 0)
    DEC ECX        ; Decrement ECX (so ECX = N - 1)
    MOV EAX, N    ; Put N into EAX
    MaxPerm:
        MUL ECX            ; Do EDX:EAX = EAX * ECX
        LOOP MaxPerm    ; Loop to find permutations number
    MOV Num, EAX    ; Move EAX (permutations number) into Num
    MOV EAX, 1        ; Set EAX (permutations number) to 1
    MOV EBX, 0        ; Reset EBX (EBX = 0)
    MOV ECX, 1        ; Reset ECX
    CicloIniziale:
        DEC ECX                    ; Decrement ECX (to compare it with N)
        CMP ECX, N                ; Compare ECX and N
        JE Permutazione            ; If ECX == N the first permutation has been written, skip to the generation of the next ones
        INC ECX                    ; Else increment ECX
        MOV Perm[4*EBX], ECX    ; Insert ECX into the Perm array
        INC ECX                    ; Increment ECX
        INC EBX                    ; Increment EBX
        JMP CicloIniziale        ; Continue the loop
    Permutazione:
        XOR EAX, EAX    ; Local index
        XOR EBX, EBX    ; Previous permutation index
        MOV ECX, N        ; Current permutation index
        MOV EDI, 1        ; Value of k
        MOV ESI, 1        ; New position of k
        
        CicloPermutazione:
            CMP EAX, N                ; Compare ECX and EAX
            JE ResetPerm            ; If the end of the permutation has been reached, go to ResetPerm
            MOV EDX, Perm[4*EBX]    ; Otherwise save the element of the previous permutation in position EBX in EDX
            CMP EDX, EDI            ; Compare EDX and EDI
            JE ValoreUguale            ; If they are equal, then go to ValoreUguale
            CMP EAX, ESI            ; Otherwise compare EBX and ESI
            JE InserisciElSpostato    ; If it's time to move the item, go to InserisciElSpostato
            MOV Perm[4*ECX], EDX    ; Returns the value of the previous permutation to the new permutation
            ContinuaCiclo:
                INC EBX                    ; Increment the previous permutation index
                INC EAX                    ; Increment the local index
                INC ECX                    ; Increment the new permutation index
                JMP CicloPermutazione    ; Continue the loop
        
            InserisciElSpostato:
                MOV Perm[4*ECX], EDI    ; Put EDI in the new permutation
                MOV EDX, N                ; EDX = N
                DEC EDX                    ; EDX -= 1
                CMP ESI, EDX            ; Compare ESI and EDX
                JE ResettaK                ; If ESI == EDX go to ResettaK
                JMP ContinuaCiclo        ; Continue the loop
            
            ValoreUguale:
                CMP EAX, 0                ; Confronta EAX e 0
                JZ PrimaPos                ; If EAX == 0 (first position) go to PrimaPos
                MOV EDX, Perm[4*EBX+4]    ; Else save the element into position EBX - 1
                MOV Perm[4*ECX], EDX    ; Insert EDX in the new permutation
                JMP ContinuaCiclo        ; Continue the loop
                
                PrimaPos:
                    MOV EDX, Perm[4*EBX+4]    ; Save into EDX the element in position ECX + 1
                    MOV Perm[4*ECX], EDX    ; Insert EDX into the new permutation
                    JMP ContinuaCiclo        ; Continue the loop
            ResettaK:
                XOR ESI, ESI            ; Reset ESI
                MOV EDI, Perm[4*EDI]    ; EDI = Perm[EDI]
                JMP ContinuaCiclo        ; Continue the loop
            ResettaKN:
                CMP EDI, N            ; Compare EDI and N
                JNE ContinuaCiclo    ; if EDI != N then continue the loop
                JMP ResettaK        ; Else go to ResettaK
        ResetPerm:
            MOV EAX, Num            ; EAX = Num
            MUL DWORD PTR N            ; EAX *= N (Elements of number of all the permutations)
            CMP EAX, ECX            ; Compare EAX and ECX
            JE Fine                    ; If EAX == ECX (permutations done) then finish the program
            XOR EAX, EAX            ; Otherwise reset EAX
            INC ESI                    ; Increment k index
            JMP CicloPermutazione    ; Continue the loop
    Piccolo:            ; If N = 0 or N = 1, the only permutation that can exists is made by only 1 element
        MOV Num, 1
        MOV Perm[0], ECX
        
    Fine:
}
// Print
{
    int i,j,k;
    printf("%d permutations of the first %d natural numbers\n", Num, N);
    for (i=k=0;i<Num;i++)
    {
        for (j=0;j<N;j++)
        {
            printf("%3d",Perm[k++]);
        }
        printf("\n");
    }
}
return 0;
}

The issue is that this program works only for N <= 3 and I didn't found the issue! These are the outputs I get:

N = 3 and below works fine:

6 permutations of the first 3 natural numbers
1  2  3
2  1  3
2  3  1
3  2  1
3  1  2
1  3  2

N = 4 (the same with 5 and 6):

24 permutations of the first 4 natural numbers
1  2  3  4
2  1  3  4
2  3  1  4
2  3  4  1
3  2  4  1
3  4  2  1
3  4  1  2
4  3  1  2
4  1  3  2
4  1  2  3
1  4  2  3
1  2  4  3
1  2  3  4
1  3  3  4
1  3  2  4
1  3  4  2
1  4  4  2
1  4  3  2
1  4  2  3
1  2  2  3
1  2  4  3
1  2  3  4
1  3  3  4
1  3  2  4

As you can see after the last permutation of the first cycle the next ones are messed up...

Can you help me? Thanks


Solution

  • In the end, I've managed to write a C program that does the job using the algorithm fo the next_permutation function of the C++ STD lib. Then, I've translated the C code into assembly with the help of Godbolt (online compiler).

    So:

    1. Write the C program using the next_permutation function: https://godbolt.org/z/7avGaWfha
    2. Flatten all the functions in the main: https://godbolt.org/z/7z9MGWefK
    3. Finally, with the great help of Godbolt, translate it to assembly