// File: /workspace/github_cpp_makefile_star2_O2/Pyboon[P]sage/./Eigen/src/Core/products/TriangularSolverMatrix.h
// Function: Eigen::internal::triangular_solve_matrix<std::complex<double>, long, 1, 5, false, 0, 0>::run(long, long, std::complex<double> const*, long, std::complex<double>*, long, Eigen::internal::level3_blocking<std::complex<double>, std::complex<double>>&)
EIGEN_DONT_INLINE void triangular_solve_matrix<Scalar,Index,OnTheLeft,Mode,Conjugate,TriStorageOrder,ColMajor>::run(
    Index size, Index otherSize,
    const Scalar* _tri, Index triStride,
    Scalar* _other, Index otherStride,
    level3_blocking<Scalar,Scalar>& blocking)
  {
    Index cols = otherSize;

    typedef const_blas_data_mapper<Scalar, Index, TriStorageOrder> TriMapper;
    typedef blas_data_mapper<Scalar, Index, ColMajor> OtherMapper;
    TriMapper tri(_tri, triStride);
    OtherMapper other(_other, otherStride);

    typedef gebp_traits<Scalar,Scalar> Traits;

    enum {
      SmallPanelWidth   = EIGEN_PLAIN_ENUM_MAX(Traits::mr,Traits::nr),
      IsLower = (Mode&Lower) == Lower
    };

    Index kc = blocking.kc();                   // cache block size along the K direction
    Index mc = (std::min)(size,blocking.mc());  // cache block size along the M direction

    std::size_t sizeA = kc*mc;
    std::size_t sizeB = kc*cols;

    ei_declare_aligned_stack_constructed_variable(Scalar, blockA, sizeA, blocking.blockA());
    ei_declare_aligned_stack_constructed_variable(Scalar, blockB, sizeB, blocking.blockB());

    conj_if<Conjugate> conj;
    gebp_kernel<Scalar, Scalar, Index, OtherMapper, Traits::mr, Traits::nr, Conjugate, false> gebp_kernel;
    gemm_pack_lhs<Scalar, Index, TriMapper, Traits::mr, Traits::LhsProgress, TriStorageOrder> pack_lhs;
    gemm_pack_rhs<Scalar, Index, OtherMapper, Traits::nr, ColMajor, false, true> pack_rhs;

    // the goal here is to subdivise the Rhs panels such that we keep some cache
    // coherence when accessing the rhs elements
    std::ptrdiff_t l1, l2, l3;
    manage_caching_sizes(GetAction, &l1, &l2, &l3);
    Index subcols = cols>0 ? l2/(4 * sizeof(Scalar) * std::max<Index>(otherStride,size)) : 0;
    subcols = std::max<Index>((subcols/Traits::nr)*Traits::nr, Traits::nr);

    for(Index k2=IsLower ? 0 : size;
        IsLower ? k2<size : k2>0;
        IsLower ? k2+=kc : k2-=kc)
    {
      const Index actual_kc = (std::min)(IsLower ? size-k2 : k2, kc);

      // We have selected and packed a big horizontal panel R1 of rhs. Let B be the packed copy of this panel,
      // and R2 the remaining part of rhs. The corresponding vertical panel of lhs is split into
      // A11 (the triangular part) and A21 the remaining rectangular part.
      // Then the high level algorithm is:
      //  - B = R1                    => general block copy (done during the next step)
      //  - R1 = A11^-1 B             => tricky part
      //  - update B from the new R1  => actually this has to be performed continuously during the above step
      //  - R2 -= A21 * B             => GEPP

      // The tricky part: compute R1 = A11^-1 B while updating B from R1
      // The idea is to split A11 into multiple small vertical panels.
      // Each panel can be split into a small triangular part T1k which is processed without optimization,
      // and the remaining small part T2k which is processed using gebp with appropriate block strides
      for(Index j2=0; j2<cols; j2+=subcols)
      {
        Index actual_cols = (std::min)(cols-j2,subcols);
        // for each small vertical panels [T1k^T, T2k^T]^T of lhs
        for (Index k1=0; k1<actual_kc; k1+=SmallPanelWidth)
        {
          Index actualPanelWidth = std::min<Index>(actual_kc-k1, SmallPanelWidth);
          // tr solve
          for (Index k=0; k<actualPanelWidth; ++k)
          {
            // TODO write a small kernel handling this (can be shared with trsv)
            Index i  = IsLower ? k2+k1+k : k2-k1-k-1;
            Index rs = actualPanelWidth - k - 1; // remaining size
            Index s  = TriStorageOrder==RowMajor ? (IsLower ? k2+k1 : i+1)
                                                 :  IsLower ? i+1 : i-rs;

            Scalar a = (Mode & UnitDiag) ? Scalar(1) : Scalar(1)/conj(tri(i,i));
            for (Index j=j2; j<j2+actual_cols; ++j)
            {
              if (TriStorageOrder==RowMajor)
              {
                Scalar b(0);
                const Scalar* l = &tri(i,s);
                Scalar* r = &other(s,j);
                for (Index i3=0; i3<k; ++i3)
                  b += conj(l[i3]) * r[i3];

                other(i,j) = (other(i,j) - b)*a;
              }
              else
              {
                Scalar b = (other(i,j) *= a);
                Scalar* r = &other(s,j);
                const Scalar* l = &tri(s,i);
                for (Index i3=0;i3<rs;++i3)
                  r[i3] -= b * conj(l[i3]);
              }
            }
          }

          Index lengthTarget = actual_kc-k1-actualPanelWidth;
          Index startBlock   = IsLower ? k2+k1 : k2-k1-actualPanelWidth;
          Index blockBOffset = IsLower ? k1 : lengthTarget;

          // update the respective rows of B from other
          pack_rhs(blockB+actual_kc*j2, other.getSubMapper(startBlock,j2), actualPanelWidth, actual_cols, actual_kc, blockBOffset);

          // GEBP
          if (lengthTarget>0)
          {
            Index startTarget  = IsLower ? k2+k1+actualPanelWidth : k2-actual_kc;

            pack_lhs(blockA, tri.getSubMapper(startTarget,startBlock), actualPanelWidth, lengthTarget);

            gebp_kernel(other.getSubMapper(startTarget,j2), blockA, blockB+actual_kc*j2, lengthTarget, actualPanelWidth, actual_cols, Scalar(-1),
                        actualPanelWidth, actual_kc, 0, blockBOffset);
          }
        }
      }
      
      // R2 -= A21 * B => GEPP
      {
        Index start = IsLower ? k2+kc : 0;
        Index end   = IsLower ? size : k2-kc;
        for(Index i2=start; i2<end; i2+=mc)
        {
          const Index actual_mc = (std::min)(mc,end-i2);
          if (actual_mc>0)
          {
            pack_lhs(blockA, tri.getSubMapper(i2, IsLower ? k2 : k2-kc), actual_kc, actual_mc);

            gebp_kernel(other.getSubMapper(i2, 0), blockA, blockB, actual_mc, actual_kc, cols, Scalar(-1), -1, -1, 0, 0);
          }
        }
      }
    }
  }

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x1f8, %rsp            # imm = 0x1F8
movq %r9, -0x50(%rbp)
movq %r8, -0xc0(%rbp)
movq %rcx, -0xa8(%rbp)
movq %rdx, -0x108(%rbp)
movq %rsi, -0x80(%rbp)
movq 0x10(%rbp), %r14
movq 0x10(%r14), %r15
movq 0x20(%r14), %rax
cmpq %rdi, %r15
movq %rdi, -0x90(%rbp)
cmovgeq %rdi, %r15
movq %r15, -0xa0(%rbp)
movq %rax, -0x78(%rbp)
imulq %rax, %r15
movq %r15, %rax
shrq $0x3c, %rax
je 0x14680
callq 0x5906
movabsq $0xfffffffffffffff, %r12 # imm = 0xFFFFFFFFFFFFFFF
movq -0x78(%rbp), %rbx
imulq -0x80(%rbp), %rbx
movq (%r14), %rax
movq %r15, %rdi
shlq $0x4, %rdi
testq %rax, %rax
je 0x146b4
movq %rax, -0x60(%rbp)
cmpq $0x20001, %rdi          # imm = 0x20001
setae %al
xorl %ecx, %ecx
jmp 0x146eb
cmpq $0x20000, %rdi          # imm = 0x20000
ja 0x146d6
movq %rsp, %rcx
addq $0x1e, %rdi
andq $-0x10, %rdi
subq %rdi, %rcx
movq %rcx, %rsp
xorl %eax, %eax
movq %rcx, -0x60(%rbp)
jmp 0x146eb
callq 0x595a
xorl %ecx, %ecx
cmpq $0x0, (%r14)
movq %rax, -0x60(%rbp)
cmoveq %rax, %rcx
movb $0x1, %al
movq %rcx, -0x200(%rbp)
movq %r15, -0x1f8(%rbp)
movb %al, -0x1f0(%rbp)
cmpq %r12, %rbx
jbe 0x14709
callq 0x5906
movq 0x8(%r14), %r12
movq %rbx, %r15
shlq $0x4, %r15
testq %r12, %r12
je 0x1471d
xorl %eax, %eax
jmp 0x14752
cmpq $0x20000, %r15          # imm = 0x20000
ja 0x1473c
movq %rsp, %rax
leaq 0x1e(%r15), %rcx
andq $-0x10, %rcx
subq %rcx, %rax
movq %rax, %rsp
movq %rax, %r12
jmp 0x14752
movq %r15, %rdi
callq 0x595a
movq %rax, %r12
xorl %eax, %eax
cmpq $0x0, 0x8(%r14)
cmoveq %r12, %rax
cmpq $0x20001, %r15          # imm = 0x20001
movq %rax, -0x1e8(%rbp)
movq %rbx, -0x1e0(%rbp)
setae -0x1d8(%rbp)
leaq -0x220(%rbp), %rsi
leaq -0x1d0(%rbp), %rdx
leaq -0x218(%rbp), %rcx
xorl %edi, %edi
callq 0xfa6c
pushq $0x4
popq %r9
cmpq $0x0, -0x80(%rbp)
movq -0x50(%rbp), %rsi
movq -0x90(%rbp), %rdi
movq -0x78(%rbp), %r8
jle 0x147c9
movq -0x1d0(%rbp), %rax
cmpq %rdi, %rsi
movq %rdi, %rcx
cmovgq %rsi, %rcx
shlq $0x6, %rcx
xorl %edx, %edx
divq %rcx
cqto
idivq %r9
shlq $0x2, %rax
jmp 0x147cb
xorl %eax, %eax
cmpq $0x5, %rax
cmovlq %r9, %rax
movq -0x108(%rbp), %rcx
leaq 0x10(%rcx), %rdx
movq %rdx, -0xf8(%rbp)
movq -0xa8(%rbp), %rdx
movq %rdx, %r9
shlq $0x4, %r9
addq $0x10, %r9
movq %r8, %r10
movq %r9, -0x198(%rbp)
imulq %r9, %r10
movq %r10, -0x158(%rbp)
shlq $0x6, %rdx
addq $0x40, %rdx
movq %rdx, -0x180(%rbp)
movq -0xc0(%rbp), %rdx
leaq 0x10(%rdx), %r9
movq %r9, -0xf0(%rbp)
movq %r8, %r9
shlq $0x4, %r9
movq %rsi, %r10
movq %rax, -0x100(%rbp)
imulq %rax, %r10
shlq $0x4, %r10
movq %r10, -0x168(%rbp)
shlq $0x4, %rsi
movq %rsi, -0x1b8(%rbp)
leaq (%rdx,%r9), %rax
movq %rax, -0xe8(%rbp)
movq -0xa0(%rbp), %rax
shlq $0x4, %rax
movq %rax, -0x170(%rbp)
movq %r9, -0x150(%rbp)
leaq (%rcx,%r9), %rax
movq %rax, -0xe0(%rbp)
movq %rdi, %rax
subq %r8, %rax
movq %rax, -0xd8(%rbp)
xorl %eax, %eax
leaq -0x210(%rbp), %r15
movq %rdi, %rdx
movq %r12, -0x138(%rbp)
cmpq %rdx, %r8
movq %rdx, -0x160(%rbp)
cmovlq %r8, %rdx
movq %rdx, -0x178(%rbp)
movq %rax, -0x88(%rbp)
subq %rax, %rdi
jle 0x14e0f
cmpq %rdi, %r8
cmovlq %r8, %rdi
movq -0xf0(%rbp), %rax
movq %rax, -0x98(%rbp)
xorl %ecx, %ecx
movq %rdi, -0x68(%rbp)
movq -0x80(%rbp), %rax
subq %rcx, %rax
jle 0x14c9d
movq %rax, %rdx
movq -0x100(%rbp), %rax
cmpq %rdx, %rax
cmovlq %rax, %rdx
movq %rdx, -0x120(%rbp)
leaq (%rdx,%rcx), %rax
movq %rax, -0x1c8(%rbp)
movq %rcx, %rax
imulq %rdi, %rax
shlq $0x4, %rax
addq %r12, %rax
movq %rax, -0x118(%rbp)
movq %rcx, -0x140(%rbp)
imulq -0x50(%rbp), %rcx
shlq $0x4, %rcx
addq -0xc0(%rbp), %rcx
movq %rcx, -0x110(%rbp)
movq -0x98(%rbp), %rax
movq %rax, -0x128(%rbp)
movq -0xf8(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq -0x178(%rbp), %rax
xorl %edx, %edx
cmpq $0x4, %rax
movq %rax, %rcx
pushq $0x4
popq %rax
movq %rax, %rsi
movq %rcx, -0x130(%rbp)
cmovlq %rcx, %rsi
testq %rsi, %rsi
movl $0x0, %ecx
cmovgq %rsi, %rcx
movq %rcx, -0x1a0(%rbp)
movq -0x68(%rbp), %rcx
subq %rdx, %rcx
jle 0x14c71
decq %rsi
cmpq $0x4, %rcx
movq %rcx, -0x188(%rbp)
cmovlq %rcx, %rax
movq %rax, -0x190(%rbp)
movq -0x88(%rbp), %rax
movq %rdx, -0xb8(%rbp)
addq %rdx, %rax
movq %rax, -0xc8(%rbp)
movq -0x128(%rbp), %rax
movq %rax, -0x148(%rbp)
movq -0xb0(%rbp), %rax
movq %rax, -0x70(%rbp)
xorl %ecx, %ecx
testq %rsi, %rsi
movl $0x0, %eax
movq %rsi, -0x1b0(%rbp)
cmovgq %rsi, %rax
movq %rax, -0xd0(%rbp)
cmpq -0x1a0(%rbp), %rcx
je 0x14b19
movq -0xc8(%rbp), %rax
movq %rcx, -0x1a8(%rbp)
addq %rcx, %rax
movsd 0x89a5(%rip), %xmm0     # 0x1d3d8
movapd %xmm0, -0x40(%rbp)
shlq $0x4, %rax
addq -0xc0(%rbp), %rax
movq %rax, -0x1c0(%rbp)
movq -0x148(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x140(%rbp), %r12
cmpq -0x1c8(%rbp), %r12
jge 0x14ae2
movq %r12, %rdi
imulq -0x50(%rbp), %rdi
shlq $0x4, %rdi
addq -0x1c0(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0xc12c
movupd (%rax), %xmm0
movapd %xmm0, -0x210(%rbp)
movq -0x58(%rbp), %r13
movq -0x70(%rbp), %r14
movq -0xd0(%rbp), %rbx
subq $0x1, %rbx
jb 0x14acb
movq %r15, %rdi
movq %r14, %rsi
callq 0xab66
movupd (%r13), %xmm2
unpcklpd %xmm1, %xmm0            # xmm0 = xmm0[0],xmm1[0]
subpd %xmm0, %xmm2
movupd %xmm2, (%r13)
addq $0x10, %r14
addq $0x10, %r13
jmp 0x14a9c
incq %r12
movq -0x58(%rbp), %rax
addq -0x1b8(%rbp), %rax
movq %rax, -0x58(%rbp)
jmp 0x14a5c
movq -0x1a8(%rbp), %rcx
incq %rcx
movq -0x1b0(%rbp), %rsi
decq %rsi
movq -0x70(%rbp), %rax
addq -0x198(%rbp), %rax
movq %rax, -0x70(%rbp)
addq $0x10, -0x148(%rbp)
movq -0x138(%rbp), %r12
jmp 0x149f3
movq -0xc8(%rbp), %rax
shlq $0x4, %rax
addq -0x110(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0x38(%rbp)
subq $0x8, %rsp
leaq -0x41(%rbp), %rdi
movq -0x118(%rbp), %rsi
leaq -0x40(%rbp), %rdx
movq -0x190(%rbp), %r14
movq %r14, %rcx
movq -0x120(%rbp), %r8
movq -0x68(%rbp), %r9
pushq -0xb8(%rbp)
callq 0x15180
popq %rax
popq %rcx
movq -0x188(%rbp), %r8
subq %r14, %r8
testq %r8, %r8
movq -0x130(%rbp), %rax
jle 0x14c3a
movq -0xc8(%rbp), %rsi
leaq (%r14,%rsi), %rbx
movq -0xa8(%rbp), %rcx
imulq %rcx, %rsi
shlq $0x4, %rsi
shlq $0x4, %rbx
movq -0x108(%rbp), %rax
addq %rbx, %rax
addq %rax, %rsi
movq %rsi, -0x40(%rbp)
movq %rcx, -0x38(%rbp)
subq $0x8, %rsp
leaq -0x29(%rbp), %rdi
movq -0x60(%rbp), %rsi
leaq -0x40(%rbp), %rdx
movq %r8, %r13
movq %r14, %rcx
xorl %r9d, %r9d
pushq $0x0
callq 0x15370
popq %rax
popq %rcx
addq -0x110(%rbp), %rbx
movq %rbx, -0x40(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0x38(%rbp)
subq $0x8, %rsp
xorpd %xmm1, %xmm1
leaq -0x2a(%rbp), %rdi
leaq -0x40(%rbp), %rsi
movq -0x60(%rbp), %rdx
movq -0x118(%rbp), %rcx
movq %r13, %r8
movq %r14, %r9
movsd 0x87e9(%rip), %xmm0     # 0x1d400
pushq -0xb8(%rbp)
pushq $0x0
pushq -0x68(%rbp)
pushq %r14
pushq -0x120(%rbp)
callq 0x153f2
addq $0x30, %rsp
movq -0x130(%rbp), %rax
movq -0xb8(%rbp), %rdx
addq $0x4, %rdx
addq $-0x4, %rax
movq %rax, %rcx
movq -0xb0(%rbp), %rax
addq -0x180(%rbp), %rax
movq %rax, -0xb0(%rbp)
movq %rcx, %rax
addq $0x40, -0x128(%rbp)
jmp 0x1496f
movq -0x140(%rbp), %rcx
addq -0x100(%rbp), %rcx
movq -0x98(%rbp), %rax
addq -0x168(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x68(%rbp), %rdi
jmp 0x148e7
movq -0x88(%rbp), %r13
addq -0x78(%rbp), %r13
movq -0xd8(%rbp), %r14
movq -0xe0(%rbp), %rcx
movq -0xe8(%rbp), %rdx
movq %r13, -0x88(%rbp)
cmpq -0x90(%rbp), %r13
jge 0x14dbd
movq %r14, %rbx
movq -0xa0(%rbp), %rax
subq %rax, %rbx
cmovgeq %rax, %r14
testq %r14, %r14
jle 0x14da1
movq %r13, -0xd0(%rbp)
movq %rdx, -0x58(%rbp)
movq %rcx, -0x70(%rbp)
movq %rcx, -0x40(%rbp)
movq -0xa8(%rbp), %rax
movq %rax, -0x38(%rbp)
subq $0x8, %rsp
leaq -0x29(%rbp), %rdi
movq -0x60(%rbp), %r12
movq %r12, %rsi
leaq -0x40(%rbp), %rdx
movq -0x68(%rbp), %r13
movq %r13, %rcx
movq %r14, %r8
xorl %r9d, %r9d
pushq $0x0
callq 0x15370
popq %rax
popq %rcx
movq -0x58(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0x38(%rbp)
subq $0x30, %rsp
xorps %xmm0, %xmm0
movups %xmm0, 0x18(%rsp)
orq $-0x1, 0x10(%rsp)
movq -0x80(%rbp), %rax
movq %rax, (%rsp)
orq $-0x1, 0x8(%rsp)
xorpd %xmm1, %xmm1
leaq -0x2a(%rbp), %rdi
leaq -0x40(%rbp), %rsi
movq %r12, %rdx
movq -0x138(%rbp), %r12
movq %r12, %rcx
movq %r14, %r8
movq %r13, %r9
movsd 0x8677(%rip), %xmm0     # 0x1d400
callq 0x153f2
addq $0x30, %rsp
movq -0x70(%rbp), %rcx
movq -0x58(%rbp), %rdx
movq -0xd0(%rbp), %r13
addq -0xa0(%rbp), %r13
movq -0x170(%rbp), %rax
addq %rax, %rdx
addq %rax, %rcx
movq %rbx, %r14
jmp 0x14cc4
movq -0x78(%rbp), %r8
movq -0x160(%rbp), %rdx
subq %r8, %rdx
movq -0x158(%rbp), %rax
addq %rax, -0xf8(%rbp)
movq -0x150(%rbp), %rcx
addq %rcx, -0xf0(%rbp)
addq %rcx, -0xe8(%rbp)
addq %rax, -0xe0(%rbp)
subq %r8, -0xd8(%rbp)
movq -0x90(%rbp), %rdi
movq -0x88(%rbp), %rax
jmp 0x148a7
leaq -0x1e8(%rbp), %rdi
callq 0xe734
leaq -0x200(%rbp), %rdi
callq 0xe734
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
jmp 0x14e38
movq %rax, %rbx
jmp 0x14e58
jmp 0x14e49
jmp 0x14e49
jmp 0x14e49
jmp 0x14e49
jmp 0x14e49
jmp 0x14e49
movq %rax, %rbx
leaq -0x1e8(%rbp), %rdi
callq 0xe734
leaq -0x200(%rbp), %rdi
callq 0xe734
movq %rbx, %rdi
callq 0x3430