// File: /workspace/github_cpp_makefile_star2_O2/sokolcom[P]tp-blockchain-task06/uint256_t/uint128_t.cpp
// Function: uint128_t::operator*(uint128_t const&) const
uint128_t uint128_t::operator*(const uint128_t & rhs) const{
    // split values into 4 32-bit parts
    uint64_t top[4] = {UPPER >> 32, UPPER & 0xffffffff, LOWER >> 32, LOWER & 0xffffffff};
    uint64_t bottom[4] = {rhs.UPPER >> 32, rhs.UPPER & 0xffffffff, rhs.LOWER >> 32, rhs.LOWER & 0xffffffff};
    uint64_t products[4][4];

    // multiply each component of the values
    for(int y = 3; y > -1; y--){
        for(int x = 3; x > -1; x--){
            products[3 - x][y] = top[x] * bottom[y];
        }
    }

    // first row
    uint64_t fourth32 = (products[0][3] & 0xffffffff);
    uint64_t third32  = (products[0][2] & 0xffffffff) + (products[0][3] >> 32);
    uint64_t second32 = (products[0][1] & 0xffffffff) + (products[0][2] >> 32);
    uint64_t first32  = (products[0][0] & 0xffffffff) + (products[0][1] >> 32);

    // second row
    third32  += (products[1][3] & 0xffffffff);
    second32 += (products[1][2] & 0xffffffff) + (products[1][3] >> 32);
    first32  += (products[1][1] & 0xffffffff) + (products[1][2] >> 32);

    // third row
    second32 += (products[2][3] & 0xffffffff);
    first32  += (products[2][2] & 0xffffffff) + (products[2][3] >> 32);

    // fourth row
    first32  += (products[3][3] & 0xffffffff);

    // move carry to next digit
    third32  += fourth32 >> 32;
    second32 += third32  >> 32;
    first32  += second32 >> 32;

    // remove carry from current digit
    fourth32 &= 0xffffffff;
    third32  &= 0xffffffff;
    second32 &= 0xffffffff;
    first32  &= 0xffffffff;

    // combine components
    return uint128_t((first32 << 32) | second32, (third32 << 32) | fourth32);
}

// Assembly:
subq $0x48, %rsp
movq 0x8(%rdi), %rax
movl %eax, %ecx
shrq $0x20, %rax
movq %rax, -0x60(%rsp)
movq %rcx, -0x58(%rsp)
movq (%rdi), %rax
movl %eax, %ecx
shrq $0x20, %rax
movq %rax, -0x50(%rsp)
movq %rcx, -0x48(%rsp)
movq 0x8(%rsi), %rax
movl %eax, %ecx
shrq $0x20, %rax
movq %rax, -0x80(%rsp)
movq %rcx, -0x78(%rsp)
movq (%rsi), %rax
movl %eax, %ecx
shrq $0x20, %rax
movq %rax, -0x70(%rsp)
movq %rcx, -0x68(%rsp)
movl $0x3, %eax
movabsq $0x3, %rcx
testl %eax, %eax
js 0x28c9
movl %eax, %esi
leaq (%rsp,%rsi,8), %rdx
addq $-0x40, %rdx
movq -0x80(%rsp,%rsi,8), %rsi
movq %rcx, %rdi
testq %rdi, %rdi
js 0x28c5
movq -0x60(%rsp,%rdi,8), %r8
imulq %rsi, %r8
movq %r8, (%rdx)
decq %rdi
addq $0x20, %rdx
jmp 0x28ab
decl %eax
jmp 0x2895
movq -0x28(%rsp), %r8
movl %r8d, %ecx
movq -0x38(%rsp), %rsi
movq -0x30(%rsp), %rdx
movl %edx, %eax
shrq $0x20, %r8
addq %rax, %r8
movl %esi, %eax
shrq $0x20, %rdx
addq %rax, %rdx
shrq $0x20, %rsi
movq -0x8(%rsp), %rdi
movl %edi, %eax
addq %r8, %rax
movq -0x10(%rsp), %r8
movl %r8d, %r9d
shrq $0x20, %rdi
addq %r9, %rdi
addq %rdx, %rdi
shrq $0x20, %r8
movq 0x18(%rsp), %rdx
addl -0x40(%rsp), %esi
movl %edx, %r9d
addl %esi, %r8d
addl -0x18(%rsp), %r8d
shrq $0x20, %rdx
addl %r8d, %edx
addl 0x10(%rsp), %edx
addq %rdi, %r9
addl 0x38(%rsp), %edx
movq %rax, %rsi
shrq $0x20, %rsi
addq %r9, %rsi
shlq $0x20, %rdx
addq %rsi, %rdx
shlq $0x20, %rax
orq %rcx, %rax
addq $0x48, %rsp
retq