// File: A-deLuna[P]encora-cpp-test/main.cpp
// Function: testBitwiseAdd()
void testBitwiseAdd() {
  struct TestCase {
    int a;
    int b;
    int result;
    bool overflow;
  };
  // I know designated initializers are not part of the standard yet...
  // but I feel they make the code a lot better and they're supported by
  // clang and gcc.
  TestCase cases[] = {
      {.a = 0, .b = 0, .result = 0, .overflow = false},
      {.a = 1, .b = 1, .result = 2, .overflow = false},
      {.a = -1, .b = -1, .result = -2, .overflow = false},
      {.a = -1, .b = 1, .result = 0, .overflow = false},
      {.a = -10, .b = 5, .result = -5, .overflow = false},
      {.a = 10, .b = -5, .result = 5, .overflow = false},

      {.a = std::numeric_limits<int>::max(), .b = 1, .overflow = true},
      {.a = std::numeric_limits<int>::min(), .b = -1, .overflow = true},
  };

  int failedCases = 0;
  for (const TestCase& c : cases) {
    bool threw = false;
    int result = 0;
    try {
      result = add(c.a, c.b);
    } catch (const std::overflow_error& e) {
      threw = true;
    }
    if (c.overflow && !threw) {
      std::cout << "error on test case add(" << c.a << ", " << c.b << ");\n";
      std::cout << "expected exception and did not throw.\n";
      failedCases++;
      continue;
    }
    if (!c.overflow && threw) {
      std::cout << "error on test case add(" << c.a << ", " << c.b << ");\n";
      std::cout << "received exception but did not expect any.\n";
      failedCases++;
      continue;
    }

    if (result != c.result) {
      std::cout << "result of add(" << c.a << ", " << c.b << ") was " << result
                << "\n";
      std::cout << "but expected " << c.result << "\n";
      failedCases++;
      continue;
    }
  }
  if (failedCases == 0) {
    std::cout << "bitwise add: All cases succeeded\n";
  } else {
    std::cout << "bitwise add: failed a total of " << failedCases << " cases\n";
  }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xd0, %rsp
leaq -0x80(%rbp), %rdi
leaq 0x345a(%rip), %rsi      # 0x8090
movl $0x80, %edx
callq 0x20d0
movl $0x0, -0x84(%rbp)
leaq -0x80(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x90(%rbp), %rax
addq $0x80, %rax
movq %rax, -0xa0(%rbp)
movq -0x98(%rbp), %rax
cmpq -0xa0(%rbp), %rax
je 0x4f24
movq -0x98(%rbp), %rax
movq %rax, -0xa8(%rbp)
movb $0x0, -0xa9(%rbp)
movl $0x0, -0xb0(%rbp)
movq -0xa8(%rbp), %rax
movl (%rax), %edi
movl 0x4(%rax), %esi
callq 0x2370
movl %eax, -0xcc(%rbp)
jmp 0x4cc3
movl -0xcc(%rbp), %eax
movl %eax, -0xb0(%rbp)
jmp 0x4d15
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xb8(%rbp)
movl %eax, -0xbc(%rbp)
movl -0xbc(%rbp), %eax
movl $0x1, %ecx
cmpl %ecx, %eax
jne 0x4f7b
movq -0xb8(%rbp), %rdi
callq 0x2070
movq %rax, -0xc8(%rbp)
movb $0x1, -0xa9(%rbp)
callq 0x2160
movq -0xa8(%rbp), %rax
testb $0x1, 0xc(%rax)
je 0x4daa
testb $0x1, -0xa9(%rbp)
jne 0x4daa
movq 0x82a2(%rip), %rdi      # 0xcfd8
leaq 0x343f(%rip), %rsi      # 0x817c
callq 0x20f0
movq %rax, %rdi
movq -0xa8(%rbp), %rax
movl (%rax), %esi
callq 0x2180
movq %rax, %rdi
leaq 0x3437(%rip), %rsi      # 0x8194
callq 0x20f0
movq %rax, %rdi
movq -0xa8(%rbp), %rax
movl 0x4(%rax), %esi
callq 0x2180
movq %rax, %rdi
leaq 0x3419(%rip), %rsi      # 0x8197
callq 0x20f0
movq 0x824e(%rip), %rdi      # 0xcfd8
leaq 0x340a(%rip), %rsi      # 0x819b
callq 0x20f0
movl -0x84(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x84(%rbp)
jmp 0x4f0d
movq -0xa8(%rbp), %rax
testb $0x1, 0xc(%rax)
jne 0x4e3f
testb $0x1, -0xa9(%rbp)
je 0x4e3f
movq 0x820d(%rip), %rdi      # 0xcfd8
leaq 0x33aa(%rip), %rsi      # 0x817c
callq 0x20f0
movq %rax, %rdi
movq -0xa8(%rbp), %rax
movl (%rax), %esi
callq 0x2180
movq %rax, %rdi
leaq 0x33a2(%rip), %rsi      # 0x8194
callq 0x20f0
movq %rax, %rdi
movq -0xa8(%rbp), %rax
movl 0x4(%rax), %esi
callq 0x2180
movq %rax, %rdi
leaq 0x3384(%rip), %rsi      # 0x8197
callq 0x20f0
movq 0x81b9(%rip), %rdi      # 0xcfd8
leaq 0x339c(%rip), %rsi      # 0x81c2
callq 0x20f0
movl -0x84(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x84(%rbp)
jmp 0x4f0d
movl -0xb0(%rbp), %eax
movq -0xa8(%rbp), %rcx
cmpl 0x8(%rcx), %eax
je 0x4f0b
movq 0x817c(%rip), %rdi      # 0xcfd8
leaq 0x338b(%rip), %rsi      # 0x81ee
callq 0x20f0
movq %rax, %rdi
movq -0xa8(%rbp), %rax
movl (%rax), %esi
callq 0x2180
movq %rax, %rdi
leaq 0x3311(%rip), %rsi      # 0x8194
callq 0x20f0
movq %rax, %rdi
movq -0xa8(%rbp), %rax
movl 0x4(%rax), %esi
callq 0x2180
movq %rax, %rdi
leaq 0x3359(%rip), %rsi      # 0x81fd
callq 0x20f0
movq %rax, %rdi
movl -0xb0(%rbp), %esi
callq 0x2180
movq %rax, %rdi
leaq 0x32ff(%rip), %rsi      # 0x81c0
callq 0x20f0
movq 0x810b(%rip), %rdi      # 0xcfd8
leaq 0x3330(%rip), %rsi      # 0x8204
callq 0x20f0
movq %rax, %rdi
movq -0xa8(%rbp), %rax
movl 0x8(%rax), %esi
callq 0x2180
movq %rax, %rdi
leaq 0x32cb(%rip), %rsi      # 0x81c0
callq 0x20f0
movl -0x84(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x84(%rbp)
jmp 0x4f0d
jmp 0x4f0d
movq -0x98(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x98(%rbp)
jmp 0x4c77
cmpl $0x0, -0x84(%rbp)
jne 0x4f42
movq 0x80a4(%rip), %rdi      # 0xcfd8
leaq 0x32d7(%rip), %rsi      # 0x8212
callq 0x20f0
jmp 0x4f72
movq 0x808f(%rip), %rdi      # 0xcfd8
leaq 0x32e4(%rip), %rsi      # 0x8234
callq 0x20f0
movq %rax, %rdi
movl -0x84(%rbp), %esi
callq 0x2180
movq %rax, %rdi
leaq 0x32e7(%rip), %rsi      # 0x8254
callq 0x20f0
addq $0xd0, %rsp
popq %rbp
retq
movq -0xb8(%rbp), %rdi
callq 0x2190
nopw (%rax,%rax)