// File: /workspace/github_c_makefile_star2_O3/sisshiki1969[P]monocc/src/codegen.c
// Function: gen
void gen(Node *node) {
  if (!node) return;
  if (verbose) {
    int line = get_line(node->token->str, source_text);
    int file_no = get_file_no(node->token->str);
    fprintf(output, "// Line %d ", line);
    print_node(node);
    fprintf(output, "\n");
    fprintf(output, "\t.loc %d %d\n", file_no, line);
  }

  if (is_binary_op(node->kind)) {
    Type *l_ty = type(node->lhs);
    Type *r_ty = type(node->rhs);
    int reg_mode;
    if (node->kind == ND_LAND) {
      gen_land(node);
      fprintf(output, "\tpush  rax\n");
      return;
    }
    if (node->kind == ND_LOR) {
      gen_lor(node);
      fprintf(output, "\tpush  rax\n");
      return;
    }
    gen(node->lhs);
    gen(node->rhs);

    fprintf(output, "\tpop  rdi\n");
    fprintf(output, "\tpop  rax\n");
    char *cmp_op;

    switch (node->kind) {
      case ND_ADD:
        fprintf(output, "\tadd  rax, rdi\n");
        break;
      case ND_SUB:
        fprintf(output, "\tsub  rax, rdi\n");
        break;
      case ND_MUL:
        fprintf(output, "\timul rax, rdi\n");
        break;
      case ND_DIV:
        fprintf(output, "\tcqo\n");
        fprintf(output, "\tidiv rax, rdi\n");
        break;
      case ND_AND:
        fprintf(output, "\tand  rax, rdi\n");
        break;
      case ND_OR:
        fprintf(output, "\tor   rax, rdi\n");
        break;
      case ND_XOR:
        fprintf(output, "\txor  rax, rdi\n");
        break;
      case ND_SHR:
        fprintf(output, "\tmov  cl , dil\n");
        fprintf(output, "\tshr  rax, cl\n");
        break;
      case ND_SHL:
        fprintf(output, "\tmov  cl , dil\n");
        fprintf(output, "\tshl  rax, cl\n");
        break;

      case ND_EQ:
      case ND_NEQ:
      case ND_GE:
      case ND_GT:
        if (!is_compatible_type(l_ty, r_ty))
          error_at_node(node, "Illegal operation. (Type mismatch)");
        reg_mode = reg_size(get_common_type(l_ty, r_ty));
        switch (node->kind) {
          case ND_EQ:
            cmp_op = "e";
            break;
          case ND_NEQ:
            cmp_op = "ne";
            break;
          case ND_GE:
            cmp_op = "ge";
            break;
          case ND_GT:
            cmp_op = "g";
            break;
        }
        fprintf(output, "\tcmp  %s, %s\n", reg_rax[reg_mode],
                reg_rdi[reg_mode]);
        fprintf(output, "\tset%s al\n", cmp_op);
        fprintf(output, "\tmovzb %s, al\n", reg_rax[1]);
        break;
      default:
        error_at_token(node->token, "gen(): Unimplemented binary op.");
    }
    fprintf(output, "\tpush rax\n");
    return;
  }
  char *label;
  Node *parent;
  switch (node->kind) {
    // statement
    case ND_IF:
      gen_if(node);
      return;
    case ND_WHILE:
      gen_while(node);
      return;
    case ND_FOR:
      gen_for(node);
      return;
    case ND_SWITCH:
      push_loop_switch(node);
      // evaluate const-expr and save as a local var.
      emit_lvar_addr(node->lvar);
      fprintf(output, "\tpush rax\n");
      gen(node->lhs);
      fprintf(output, "\tpop  rdi\n");
      fprintf(output, "\tpop  rax\n");
      fprintf(output, "\tmov  [rax], edi\n");
      gen_stmt(node->rhs);
      emit_jmp(get_break(NULL));
      for (int i = 0; i < vec_len(node->nodes); i++) {
        Node *parent = node->nodes->data[i];
        emit_label(parent->label);
        gen_stmt(parent);
      }
      emit_label(get_break(NULL));
      pop_loop();
      return;
    case ND_BLOCK:
      gen_block(node);
      return;
    case ND_RETURN:
      // TODO: return without expression returns undefined value.
      if (node->lhs) {
        gen(node->lhs);
        fprintf(output, "\tpop  rax\n");
      }
      emit_return(current_fn);
      return;
    case ND_CASE:
      parent = get_inner_switch();
      gen(node->lhs);
      emit_lvar_addr(parent->lvar);
      fprintf(output, "\tmov  eax, [rax]\n");
      fprintf(output, "\tpop  rdi\n");
      fprintf(output, "\tcmp  eax, edi\n");
      label = new_label();
      fprintf(output, "\tje   %s\n", label);
      node->rhs->label = label;
      vec_push(parent->nodes, node->rhs);
      return;
    case ND_DEFAULT:
      label = new_label();
      emit_jmp(label);
      node->lhs->label = label;
      vec_push(parent->nodes, node->lhs);
      return;
    case ND_BREAK:
      emit_jmp(get_break(node->token));
      return;
    case ND_CONTINUE:
      emit_jmp(get_continue(node->token));
      return;

    // expression
    case ND_NUM:
      if (-2147483648 <= node->num_val && node->num_val <= 2147483647)
        fprintf(output, "\tpush %ld\n", node->num_val);
      else {
        fprintf(output, "\tmov  rax, %ld\n", node->num_val);
        fprintf(output, "\tpush rax\n");
      }
      return;
    case ND_LVAR:
    case ND_GVAR:
    case ND_MEMBER:
      if (is_struct(type(node))) {
        gen_addr(node);
      } else {
        gen_addr_to_rax(node);
        load(node);
      }
      return;
    case ND_ADDR:
      gen_addr(node->lhs);
      return;
    case ND_DEREF:
      if (!is_ptr(type(node->lhs)))
        error_at_node(node->lhs,
                      "Illegal operation. (dereference of non-pointer type)");
      gen(node->lhs);
      if (!is_struct(type(node))) {
        fprintf(output, "\tpop  rax\n");
        load(node);
      }
      return;
    case ND_CAST:
      gen(node->lhs);
      cast(type(node->lhs), type(node));
      return;
    case ND_ASSIGN:
      gen_assign(node->lhs, node->rhs);
      return;
    case ND_CALL:
      gen_call(node);
      return;
    case ND_FDECL:
      gen_fdecl(node);
      return;

    case ND_STR:
      gen_addr(node);
      return;
    case ND_NOT:
      gen_lnot(node);
      fprintf(output, "\tpush rax\n");
      return;
    case ND_CMP:
      gen(node->lhs);
      fprintf(output, "\tpop  rax\n");
      fprintf(output, "\tnot  rax\n");
      fprintf(output, "\tpush rax\n");
      return;
  }
  error_at_token(node->token, "gen(): Unimplemented NodeKind.");
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
testq %rdi, %rdi
je 0x237e
movq %rdi, %rbx
cmpb $0x1, 0x11333(%rip)     # 0x13200
jne 0x1f3d
movq 0x50(%rbx), %rax
movq 0x20(%rax), %rdi
leaq 0x11332(%rip), %rax     # 0x13210
movq (%rax), %rsi
callq 0x502c
movl %eax, %ebp
movq 0x50(%rbx), %rax
movq 0x20(%rax), %rdi
callq 0x51f9
movl %eax, %r14d
leaq 0x11321(%rip), %r15     # 0x13220
movq (%r15), %rdi
leaq 0xa945(%rip), %rsi      # 0xc84e
movl %ebp, %edx
xorl %eax, %eax
callq 0x10f0
movq %rbx, %rdi
callq 0x408c
movq (%r15), %rsi
movl $0xa, %edi
callq 0x10c0
movq (%r15), %rdi
leaq 0xa929(%rip), %rsi      # 0xc85a
movl %r14d, %edx
movl %ebp, %ecx
xorl %eax, %eax
callq 0x10f0
movl (%rbx), %eax
decl %eax
cmpl $0x26, %eax
ja 0x2537
leaq 0xa0d7(%rip), %rcx      # 0xc028
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x8(%rbx), %rdi
callq 0xb225
movq %rax, %r14
movq 0x10(%rbx), %rdi
callq 0xb225
movq %rax, %r15
movl (%rbx), %eax
cmpl $0xd, %eax
je 0x1f88
cmpl $0xc, %eax
jne 0x1fab
movq %rbx, %rdi
callq 0x322f
jmp 0x1f90
movq %rbx, %rdi
callq 0x3409
leaq 0x11289(%rip), %rax     # 0x13220
movq (%rax), %rcx
leaq 0xa8c6(%rip), %rdi      # 0xc867
movl $0xb, %esi
jmp 0x2796
movq 0x8(%rbx), %rdi
callq 0x1eaf
movq 0x10(%rbx), %rdi
callq 0x1eaf
leaq 0x1125c(%rip), %r12     # 0x13220
movq (%r12), %rcx
leaq 0xa4b1(%rip), %rdi      # 0xc480
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa367(%rip), %rdi      # 0xc350
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movl (%rbx), %eax
addl $-0x4, %eax
cmpl $0xf, %eax
ja 0x2724
leaq 0xa0b7(%rip), %rcx      # 0xc0c4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq %r14, %rdi
movq %r15, %rsi
callq 0xb0c5
testb %al, %al
jne 0x2036
leaq 0xa757(%rip), %rsi      # 0xc783
movq %rbx, %rdi
xorl %eax, %eax
callq 0x5502
movq %r14, %rdi
movq %r15, %rsi
callq 0xade3
movq %rax, %rdi
callq 0x1b38
movl (%rbx), %ecx
addl $-0x9, %ecx
cmpl $0x2, %ecx
ja 0x2557
movl %ecx, %ecx
leaq 0xa0ec(%rip), %rdx      # 0xc14c
movslq (%rdx,%rcx,4), %rbx
addq %rdx, %rbx
jmp 0x255e
movq %rbx, %rdi
callq 0xb225
movq %rax, %rdi
callq 0xad89
testb %al, %al
je 0x2088
movq %rbx, %rdi
jmp 0x2412
movq %rbx, %rdi
callq 0x1dd7
jmp 0x2110
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2c62
movq 0x8(%rbx), %rdi
callq 0xb225
movq %rax, %rdi
callq 0xad74
testb %al, %al
jne 0x20cf
movq 0x8(%rbx), %rdi
leaq 0xa8d7(%rip), %rsi      # 0xc99f
xorl %eax, %eax
callq 0x5502
movq 0x8(%rbx), %rdi
callq 0x1eaf
movq %rbx, %rdi
callq 0xb225
movq %rax, %rdi
callq 0xad89
testb %al, %al
jne 0x237e
leaq 0x11129(%rip), %rax     # 0x13220
movq (%rax), %rcx
leaq 0xa24f(%rip), %rdi      # 0xc350
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1b70
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2d27
movq 0x8(%rbx), %rdi
testq %rdi, %rdi
je 0x216a
callq 0x1eaf
leaq 0x110cf(%rip), %rax     # 0x13220
movq (%rax), %rcx
leaq 0xa1f5(%rip), %rdi      # 0xc350
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq 0x11087(%rip), %rax     # 0x131f8
leaq 0x110a8(%rip), %rcx     # 0x13220
movq (%rcx), %rdi
movq 0x50(%rax), %rax
movl 0x28(%rax), %edx
movq 0x20(%rax), %rcx
leaq 0xa00e(%rip), %rsi      # 0xc19b
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x10f0
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2a13
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2b0c
leaq 0x1101b(%rip), %rax     # 0x131f0
movq (%rax), %rax
testq %rax, %rax
je 0x25bb
movq 0x18(%rax), %r15
testq %r15, %r15
je 0x21d5
jmp 0x25d1
movq 0x8(%rbx), %rdi
movq 0x10(%rbx), %rsi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x38f0
movq %rbx, %rdi
callq 0x1a64
movq 0x30(%rbx), %rax
leaq 0x11003(%rip), %r12     # 0x13220
movq (%r12), %rdi
movl 0x18(%rax), %edx
leaq 0xa15e(%rip), %rsi      # 0xc389
xorl %eax, %eax
callq 0x10f0
movq (%r12), %rcx
leaq 0xa0fc(%rip), %rdi      # 0xc339
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq 0x8(%rbx), %rdi
callq 0x1eaf
movq (%r12), %rcx
leaq 0xa220(%rip), %rdi      # 0xc480
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa0d6(%rip), %rdi      # 0xc350
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa6ce(%rip), %rdi      # 0xc962
movl $0x11, %esi
movl $0x1, %edx
callq 0x1190
movq 0x10(%rbx), %rdi
callq 0x29d8
movq 0x10f3d(%rip), %rax     # 0x131f0
testq %rax, %rax
jne 0x22cf
leaq 0x9f27(%rip), %rsi      # 0xc1e6
xorl %edi, %edi
xorl %eax, %eax
callq 0x52cd
movq 0x10f21(%rip), %rax     # 0x131f0
movq 0x10(%rax), %rdx
movq (%r12), %rdi
leaq 0x9ea2(%rip), %rsi      # 0xc180
xorl %eax, %eax
callq 0x10f0
movq 0x48(%rbx), %rdi
callq 0x3f3a
testl %eax, %eax
jle 0x2334
leaq 0x9e82(%rip), %r14      # 0xc17b
xorl %r13d, %r13d
movq 0x48(%rbx), %rax
movq (%rax), %rax
movq (%rax,%r13,8), %r15
movq 0x40(%r15), %rdx
movq (%r12), %rdi
movq %r14, %rsi
xorl %eax, %eax
callq 0x10f0
movq %r15, %rdi
callq 0x29d8
incq %r13
movq 0x48(%rbx), %rdi
callq 0x3f3a
cltq
cmpq %rax, %r13
jl 0x22fc
movq 0x10eb5(%rip), %rax     # 0x131f0
testq %rax, %rax
jne 0x2357
leaq 0x9e9f(%rip), %rsi      # 0xc1e6
xorl %edi, %edi
xorl %eax, %eax
callq 0x52cd
movq 0x10e99(%rip), %rax     # 0x131f0
movq 0x10(%rax), %rdx
movq (%r12), %rdi
leaq 0x9e15(%rip), %rsi      # 0xc17b
xorl %eax, %eax
callq 0x10f0
movq 0x10e7c(%rip), %rax     # 0x131f0
movq (%rax), %rax
movq %rax, 0x10e72(%rip)     # 0x131f0
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2f42
movq %rbx, %rdi
callq 0x35e3
leaq 0x10e6e(%rip), %rax     # 0x13220
movq (%rax), %rcx
jmp 0x278a
movq 0x10e2f(%rip), %rax     # 0x131f0
testq %rax, %rax
jne 0x23df
movq 0x50(%rbx), %rdi
leaq 0x9e15(%rip), %rsi      # 0xc1e6
xorl %eax, %eax
callq 0x52cd
movq 0x10e11(%rip), %rax     # 0x131f0
movq 0x10(%rax), %rdx
jmp 0x24e1
movq 0x20(%rbx), %rdx
movslq %edx, %rax
leaq 0x10e2a(%rip), %rbx     # 0x13220
movq (%rbx), %rdi
cmpq %rdx, %rax
jne 0x2684
leaq 0xa57b(%rip), %rsi      # 0xc984
jmp 0x24f2
movq 0x8(%rbx), %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x27ae
movq 0x8(%rbx), %rdi
callq 0x1eaf
leaq 0x10deb(%rip), %rbx     # 0x13220
movq (%rbx), %rcx
leaq 0x9f11(%rip), %rdi      # 0xc350
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%rbx), %rcx
leaq 0xa57c(%rip), %rdi      # 0xc9d4
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
jmp 0x2692
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x290a
movq 0x8(%rbx), %rdi
callq 0x1eaf
movq 0x8(%rbx), %rdi
callq 0xb225
movq %rax, %r14
movq %rbx, %rdi
callq 0xb225
movq %r14, %rdi
movq %rax, %rsi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1c65
movq 0x10d31(%rip), %rax     # 0x131f0
testq %rax, %rax
jne 0x24dd
movq 0x50(%rbx), %rdi
leaq 0x9ce2(%rip), %rsi      # 0xc1b1
xorl %eax, %eax
callq 0x52cd
movq 0x10d13(%rip), %rax     # 0x131f0
movq 0x8(%rax), %rdx
leaq 0x10d38(%rip), %rax     # 0x13220
movq (%rax), %rdi
leaq 0x9c8e(%rip), %rsi      # 0xc180
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x10f0
callq 0x1958
movq %rax, %r14
leaq 0x10d0a(%rip), %rax     # 0x13220
movq (%rax), %rdi
leaq 0x9c60(%rip), %rsi      # 0xc180
movq %r14, %rdx
xorl %eax, %eax
callq 0x10f0
movq 0x8(%rbx), %rsi
movq %r14, 0x40(%rsi)
jmp 0x2671
movq 0x50(%rbx), %rdi
leaq 0xa49d(%rip), %rsi      # 0xc9df
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x52cd
leaq 0xb40c(%rip), %rbx      # 0xd96a
movq (%r12), %rdi
cltq
leaq 0x10b95(%rip), %rcx     # 0x13100
leaq (%rcx,%rax,4), %rdx
leaq 0x10b9a(%rip), %rcx     # 0x13110
leaq (%rcx,%rax,4), %rcx
leaq 0xa399(%rip), %rsi      # 0xc91a
xorl %eax, %eax
callq 0x10f0
movq (%r12), %rdi
leaq 0xa395(%rip), %rsi      # 0xc928
movq %rbx, %rdx
xorl %eax, %eax
callq 0x10f0
movq (%r12), %rdi
leaq 0xa38b(%rip), %rsi      # 0xc933
leaq 0x10b55(%rip), %rdx     # 0x13104
xorl %eax, %eax
callq 0x10f0
jmp 0x2786
leaq 0x9c60(%rip), %rdi      # 0xc222
xorl %eax, %eax
callq 0x508c
movq 0x18, %r15
movq 0x8(%rbx), %rdi
callq 0x1eaf
movq 0x30(%r15), %rax
leaq 0x10c3b(%rip), %r12     # 0x13220
movq (%r12), %rdi
movl 0x18(%rax), %edx
leaq 0x9d96(%rip), %rsi      # 0xc389
xorl %eax, %eax
callq 0x10f0
movq (%r12), %rcx
leaq 0x9c8f(%rip), %rdi      # 0xc294
movl $0x11, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0x9e61(%rip), %rdi      # 0xc480
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa33b(%rip), %rdi      # 0xc974
movl $0xf, %esi
movl $0x1, %edx
callq 0x1190
callq 0x1958
movq %rax, %r14
movq (%r12), %rdi
leaq 0x9e5a(%rip), %rsi      # 0xc4b5
movq %rax, %rdx
xorl %eax, %eax
callq 0x10f0
movq 0x10(%rbx), %rsi
movq %r14, 0x40(%rsi)
movq 0x48(%r15), %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x3f3e
leaq 0xa304(%rip), %rsi      # 0xc98f
xorl %eax, %eax
callq 0x10f0
movq (%rbx), %rcx
jmp 0x278a
movq (%r12), %rcx
leaq 0xa234(%rip), %rdi      # 0xc8d9
jmp 0x2777
movq (%r12), %rcx
leaq 0xa234(%rip), %rdi      # 0xc8e9
movl $0xf, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa239(%rip), %rdi      # 0xc908
jmp 0x26f6
movq (%r12), %rcx
leaq 0xa20d(%rip), %rdi      # 0xc8e9
movl $0xf, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa203(%rip), %rdi      # 0xc8f9
movl $0xe, %esi
jmp 0x277c
movq (%r12), %rcx
leaq 0xa19b(%rip), %rdi      # 0xc8a3
movl $0x5, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa187(%rip), %rdi      # 0xc8a9
jmp 0x2777
movq 0x50(%rbx), %rdi
leaq 0xa213(%rip), %rsi      # 0xc942
xorl %eax, %eax
callq 0x52cd
jmp 0x2786
movq (%r12), %rcx
leaq 0xa130(%rip), %rdi      # 0xc873
jmp 0x2777
movq (%r12), %rcx
leaq 0xa143(%rip), %rdi      # 0xc893
jmp 0x2777
movq (%r12), %rcx
leaq 0xa126(%rip), %rdi      # 0xc883
jmp 0x2777
movq (%r12), %rcx
leaq 0xa15f(%rip), %rdi      # 0xc8c9
jmp 0x2777
movq (%r12), %rcx
leaq 0xa142(%rip), %rdi      # 0xc8b9
movl $0xf, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0x9ba8(%rip), %rdi      # 0xc339
movl $0xa, %esi
movl $0x1, %edx
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1190