user: 请从给定的汇编指令推导出C源代码:

```asm
<bn_add_part_words>:
  endbr64
  push   %r14
  mov    %rdx,%r14
  push   %r13
  mov    %rsi,%r13
  push   %r12
  mov    %r8d,%r12d
  push   %rbp
  mov    %rdi,%rbp
  mov    %ecx,%edi
  push   %rbx
  not    %edi
  mov    %ecx,%ebx
  shr    $0x1f,%edi
  call   <assert@plt>
  mov    %ebx,%ecx
  mov    %r14,%rdx
  mov    %r13,%rsi
  mov    %rbp,%rdi
  call   <bn_add_words@plt>
  test   %r12d,%r12d
  je     L89
  movslq %ebx,%rdx
  shl    $0x2,%rdx
  add    %rdx,%rbp
  test   %r12d,%r12d
  js     L330
  add    %r13,%rdx
  mov    (%rdx),%ecx
  test   %eax,%eax
  je     L60
  add    %eax,%ecx
  setb   %al
  mov    %ecx,0x0(%rbp)
  movzbl %al,%eax
  cmp    $0x1,%r12d
  jne    L35
  jmp    L89
  nopw   0x0(%rax,%rax,1)
L146:
  add    0x8(%rdx),%eax
  mov    %eax,%ecx
  setb   %al
  mov    %ecx,0x8(%rbp)
  movzbl %al,%eax
  cmp    $0x3,%r12d
  je     L89
  xor    %ecx,%ecx
  add    0xc(%rdx),%eax
  mov    %eax,0xc(%rbp)
  setb   %cl
  sub    $0x4,%r12d
  je     L17
  add    $0x10,%rdx
  add    $0x10,%rbp
  mov    (%rdx),%eax
  test   %ecx,%ecx
  je     L60
  add    $0x1,%eax
  mov    %eax,%ecx
  sete   %al
  mov    %ecx,0x0(%rbp)
  movzbl %al,%eax
  cmp    $0x1,%r12d
  je     L89
L35:
  add    0x4(%rdx),%eax
  mov    %eax,%ecx
  setb   %al
  mov    %ecx,0x4(%rbp)
  movzbl %al,%eax
  cmp    $0x2,%r12d
  jne    L146
L89:
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  ret
  nopl   0x0(%rax)
L330:
  add    %r14,%rdx
  mov    (%rdx),%ecx
  test   %eax,%eax
  je     L235
  add    %eax,%ecx
  setb   %al
  mov    %ecx,0x0(%rbp)
  movzbl %al,%eax
  cmp    $0xffffffff,%r12d
  jne    L301
  jmp    L89
  nopl   0x0(%rax,%rax,1)
L21:
  add    0x8(%rdx),%eax
  mov    %eax,%ecx
  setb   %al
  mov    %ecx,0x8(%rbp)
  movzbl %al,%eax
  cmp    $0xfffffffd,%r12d
  je     L89
  xor    %ecx,%ecx
  add    0xc(%rdx),%eax
  mov    %eax,0xc(%rbp)
  setb   %cl
  add    $0x4,%r12d
  je     L17
  add    $0x10,%rdx
  add    $0x10,%rbp
  mov    (%rdx),%eax
  test   %ecx,%ecx
  je     L235
  add    $0x1,%eax
  mov    %eax,%ecx
  sete   %al
  mov    %ecx,0x0(%rbp)
  movzbl %al,%eax
  cmp    $0xffffffff,%r12d
  je     L89
L301:
  add    0x4(%rdx),%eax
  mov    %eax,%ecx
  setb   %al
  mov    %ecx,0x4(%rbp)
  movzbl %al,%eax
  cmp    $0xfffffffe,%r12d
  jne    L21
  jmp    L89
  nopl   0x0(%rax)
L17:
  pop    %rbx
  mov    %ecx,%eax
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  ret
  nopl   0x0(%rax,%rax,1)
L60:
  mov    (%rdx),%eax
  mov    %eax,0x0(%rbp)
  cmp    $0x1,%r12d
  je     L354
  mov    0x4(%rdx),%eax
  mov    %eax,0x4(%rbp)
  cmp    $0x2,%r12d
  je     L354
  mov    0x8(%rdx),%eax
  mov    %eax,0x8(%rbp)
  cmp    $0x3,%r12d
  je     L354
  mov    0xc(%rdx),%eax
  mov    %r12d,%r8d
  mov    %eax,0xc(%rbp)
  sub    $0x4,%r8d
  jne    L75
  jmp    L354
  nopl   0x0(%rax)
L276:
  mov    0x4(%rdx),%eax
  mov    %eax,0x4(%rbp)
  cmp    $0x2,%r8d
  je     L354
  mov    0x8(%rdx),%eax
  mov    %eax,0x8(%rbp)
  cmp    $0x3,%r8d
  je     L354
  mov    0xc(%rdx),%eax
  mov    %eax,0xc(%rbp)
  sub    $0x4,%r8d
  je     L354
L75:
  mov    0x10(%rdx),%eax
  add    $0x10,%rdx
  add    $0x10,%rbp
  mov    %eax,0x0(%rbp)
  cmp    $0x1,%r8d
  jne    L276
  nopl   0x0(%rax,%rax,1)
L354:
  xor    %eax,%eax
L133:
  pop    %rbx
  pop    %rbp
  pop    %r12
  pop    %r13
  pop    %r14
  ret
  nopl   0x0(%rax,%rax,1)
L235:
  mov    (%rdx),%eax
  mov    %eax,0x0(%rbp)
  cmp    $0xffffffff,%r12d
  je     L354
  mov    0x4(%rdx),%eax
  mov    %eax,0x4(%rbp)
  cmp    $0xfffffffe,%r12d
  je     L354
  mov    0x8(%rdx),%eax
  mov    %eax,0x8(%rbp)
  cmp    $0xfffffffd,%r12d
  je     L354
  mov    0xc(%rdx),%eax
  mov    %r12d,%r8d
  mov    %eax,0xc(%rbp)
  add    $0x4,%r8d
  jne    L92
  jmp    L354
  nopl   0x0(%rax)
L107:
  mov    0x4(%rdx),%eax
  mov    %eax,0x4(%rbp)
  cmp    $0xfffffffe,%r8d
  je     L354
  mov    0x8(%rdx),%eax
  mov    %eax,0x8(%rbp)
  cmp    $0xfffffffd,%r8d
  je     L354
  mov    0xc(%rdx),%eax
  mov    %eax,0xc(%rbp)
  add    $0x4,%r8d
  je     L354
L92:
  mov    0x10(%rdx),%eax
  add    $0x10,%rdx
  add    $0x10,%rbp
  mov    %eax,0x0(%rbp)
  cmp    $0xffffffff,%r8d
  jne    L107
  xor    %eax,%eax
  jmp    L133
```

assistant: ```c
unsigned int bn_add_part_words(unsigned int *r, const unsigned int *a, const unsigned int *b, int cl, int dl) {
  unsigned int c, l, t;
  assert(cl >= 0);
  c = bn_add_words(r, a, b, cl);
  if (dl == 0)
    return c;
  r += cl;
  a += cl;
  b += cl;
  if (dl < 0) {
    int save_dl = dl;
    while (c) {
      l = (c + b[0]) & (0xffffffffL);
      c = (l < c);
      r[0] = l;
      if (++dl >= 0)
        break;
      l = (c + b[1]) & (0xffffffffL);
      c = (l < c);
      r[1] = l;
      if (++dl >= 0)
        break;
      l = (c + b[2]) & (0xffffffffL);
      c = (l < c);
      r[2] = l;
      if (++dl >= 0)
        break;
      l = (c + b[3]) & (0xffffffffL);
      c = (l < c);
      r[3] = l;
      if (++dl >= 0)
        break;
      save_dl = dl;
      b += 4;
      r += 4;
    }
    if (dl < 0) {
      if (save_dl < dl) {
        switch (dl - save_dl) {
        case 1:
          r[1] = b[1];
          if (++dl >= 0)
            break;
        case 2:
          r[2] = b[2];
          if (++dl >= 0)
            break;
        case 3:
          r[3] = b[3];
          if (++dl >= 0)
            break;
        }
        b += 4;
        r += 4;
      }
    }
    if (dl < 0) {
      for (;;) {
        r[0] = b[0];
        if (++dl >= 0)
          break;
        r[1] = b[1];
        if (++dl >= 0)
          break;
        r[2] = b[2];
        if (++dl >= 0)
          break;
        r[3] = b[3];
        if (++dl >= 0)
          break;
        b += 4;
        r += 4;
      }
    }
  } else {
    int save_dl = dl;
    while (c) {
      t = (a[0] + c) & (0xffffffffL);
      c = (t < c);
      r[0] = t;
      if (--dl <= 0)
        break;
      t = (a[1] + c) & (0xffffffffL);
      c = (t < c);
      r[1] = t;
      if (--dl <= 0)
        break;
      t = (a[2] + c) & (0xffffffffL);
      c = (t < c);
      r[2] = t;
      if (--dl <= 0)
        break;
      t = (a[3] + c) & (0xffffffffL);
      c = (t < c);
      r[3] = t;
      if (--dl <= 0)
        break;
      save_dl = dl;
      a += 4;
      r += 4;
    }
    if (dl > 0)
      if (save_dl > dl) {
        switch (save_dl - dl) {
        case 1:
          r[1] = a[1];
          if (--dl <= 0)
            break;
        case 2:
          r[2] = a[2];
          if (--dl <= 0)
            break;
        case 3:
          r[3] = a[3];
          if (--dl <= 0)
            break;
        }
        a += 4;
        r += 4;
      }
    if (dl > 0) {
      for (;;) {
        r[0] = a[0];
        if (--dl <= 0)
          break;
        r[1] = a[1];
        if (--dl <= 0)
          break;
        r[2] = a[2];
        if (--dl <= 0)
          break;
        r[3] = a[3];
        if (--dl <= 0)
          break;
        a += 4;
        r += 4;
      }
    }
  }
  return c;
}
```