// File: /workspace/github_c_makefile_star2_O1/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 0x2376
movq %rdi, %rbx
cmpb $0x1, 0x11335(%rip)     # 0x13200
jne 0x1f3b
movq 0x50(%rbx), %rax
movq 0x20(%rax), %rdi
leaq 0x11334(%rip), %rax     # 0x13210
movq (%rax), %rsi
callq 0x5050
movl %eax, %ebp
movq 0x50(%rbx), %rax
movq 0x20(%rax), %rdi
callq 0x5225
movl %eax, %r14d
leaq 0x11323(%rip), %r15     # 0x13220
movq (%r15), %rdi
leaq 0xa947(%rip), %rsi      # 0xc84e
movl %ebp, %edx
xorl %eax, %eax
callq 0x10f0
movq %rbx, %rdi
callq 0x40b0
movq (%r15), %rsi
movl $0xa, %edi
callq 0x10c0
movq (%r15), %rdi
leaq 0xa92b(%rip), %rsi      # 0xc85a
movl %r14d, %edx
movl %ebp, %ecx
xorl %eax, %eax
callq 0x10f0
movl (%rbx), %eax
decl %eax
cmpl $0x26, %eax
ja 0x252b
leaq 0xa0d9(%rip), %rcx      # 0xc028
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x8(%rbx), %rdi
callq 0xb354
movq %rax, %r14
movq 0x10(%rbx), %rdi
callq 0xb354
movq %rax, %r15
movl (%rbx), %eax
cmpl $0xd, %eax
je 0x1f86
cmpl $0xc, %eax
jne 0x1fa9
movq %rbx, %rdi
callq 0x3257
jmp 0x1f8e
movq %rbx, %rdi
callq 0x3431
leaq 0x1128b(%rip), %rax     # 0x13220
movq (%rax), %rcx
leaq 0xa8c8(%rip), %rdi      # 0xc867
movl $0xb, %esi
jmp 0x2786
movq 0x8(%rbx), %rdi
callq 0x1ead
movq 0x10(%rbx), %rdi
callq 0x1ead
leaq 0x1125e(%rip), %r12     # 0x13220
movq (%r12), %rcx
leaq 0xa4b3(%rip), %rdi      # 0xc480
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa369(%rip), %rdi      # 0xc350
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movl (%rbx), %eax
addl $-0x4, %eax
cmpl $0xf, %eax
ja 0x2714
leaq 0xa0b9(%rip), %rcx      # 0xc0c4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq %r14, %rdi
movq %r15, %rsi
callq 0xb1e5
testb %al, %al
jne 0x2034
leaq 0xa759(%rip), %rsi      # 0xc783
movq %rbx, %rdi
xorl %eax, %eax
callq 0x552e
movq %r14, %rdi
movq %r15, %rsi
callq 0xaf0f
movq %rax, %rdi
callq 0x1b36
movl (%rbx), %ecx
addl $-0x9, %ecx
cmpl $0x2, %ecx
ja 0x254b
movl %ecx, %ecx
leaq 0xa0ee(%rip), %rdx      # 0xc14c
movslq (%rdx,%rcx,4), %rbx
addq %rdx, %rbx
jmp 0x2552
movq %rbx, %rdi
callq 0xb354
movq %rax, %rdi
callq 0xaeb5
testb %al, %al
je 0x2086
movq %rbx, %rdi
jmp 0x2408
movq %rbx, %rdi
callq 0x1dd5
jmp 0x210e
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2c8a
movq 0x8(%rbx), %rdi
callq 0xb354
movq %rax, %rdi
callq 0xaea0
testb %al, %al
jne 0x20cd
movq 0x8(%rbx), %rdi
leaq 0xa8d9(%rip), %rsi      # 0xc99f
xorl %eax, %eax
callq 0x552e
movq 0x8(%rbx), %rdi
callq 0x1ead
movq %rbx, %rdi
callq 0xb354
movq %rax, %rdi
callq 0xaeb5
testb %al, %al
jne 0x2376
leaq 0x1112b(%rip), %rax     # 0x13220
movq (%rax), %rcx
leaq 0xa251(%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 0x1b6e
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2d4f
movq 0x8(%rbx), %rdi
testq %rdi, %rdi
je 0x2168
callq 0x1ead
leaq 0x110d1(%rip), %rax     # 0x13220
movq (%rax), %rcx
leaq 0xa1f7(%rip), %rdi      # 0xc350
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq 0x11089(%rip), %rax     # 0x131f8
leaq 0x110aa(%rip), %rcx     # 0x13220
movq (%rcx), %rdi
movq 0x50(%rax), %rax
movl 0x28(%rax), %edx
movq 0x20(%rax), %rcx
leaq 0xa010(%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 0x2a03
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2b18
leaq 0x1101d(%rip), %r14     # 0x131f0
movq (%r14), %r14
testq %r14, %r14
je 0x25af
cmpq $0x0, 0x18(%r14)
je 0x21d3
jmp 0x25bd
movq 0x8(%rbx), %rdi
movq 0x10(%rbx), %rsi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x3918
movq %rbx, %rdi
callq 0x1a64
movq 0x30(%rbx), %rax
leaq 0x11007(%rip), %r12     # 0x13220
movq (%r12), %rdi
movl 0x18(%rax), %edx
leaq 0xa162(%rip), %rsi      # 0xc389
xorl %eax, %eax
callq 0x10f0
movq (%r12), %rcx
leaq 0xa100(%rip), %rdi      # 0xc339
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq 0x8(%rbx), %rdi
callq 0x1ead
movq (%r12), %rcx
leaq 0xa224(%rip), %rdi      # 0xc480
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa0da(%rip), %rdi      # 0xc350
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa6d2(%rip), %rdi      # 0xc962
movl $0x11, %esi
movl $0x1, %edx
callq 0x1190
movq 0x10(%rbx), %rdi
callq 0x29c8
cmpq $0x0, 0x10f40(%rip)     # 0x131f0
jne 0x22c2
leaq 0x9f2d(%rip), %rsi      # 0xc1e6
xorl %edi, %edi
xorl %eax, %eax
callq 0x52f9
movq 0x10f27(%rip), %rax     # 0x131f0
movq 0x10(%rax), %rdx
movq (%r12), %rdi
leaq 0x9ea8(%rip), %rsi      # 0xc180
xorl %eax, %eax
callq 0x10f0
movq 0x48(%rbx), %rdi
callq 0x3f62
testl %eax, %eax
jle 0x232e
leaq 0x9e88(%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 0x29c8
incq %r13
movq 0x48(%rbx), %rdi
callq 0x3f62
cltq
cmpq %rax, %r13
jl 0x22f6
cmpq $0x0, 0x10eba(%rip)     # 0x131f0
jne 0x2348
leaq 0x9ea7(%rip), %rsi      # 0xc1e6
xorl %edi, %edi
xorl %eax, %eax
callq 0x52f9
movq 0x10ea1(%rip), %rax     # 0x131f0
movq 0x10(%rax), %rdx
movq (%r12), %rdi
leaq 0x9e1d(%rip), %rsi      # 0xc17b
xorl %eax, %eax
callq 0x10f0
movq 0x10e84(%rip), %rax     # 0x131f0
movq (%rax), %rax
movq %rax, 0x10e7a(%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 0x2f6a
movq %rbx, %rdi
callq 0x360b
leaq 0x10e76(%rip), %rax     # 0x13220
movq (%rax), %rcx
jmp 0x277a
cmpq $0x0, 0x10e36(%rip)     # 0x131f0
jne 0x23ce
movq 0x50(%rbx), %rdi
leaq 0x9e1f(%rip), %rsi      # 0xc1e6
xorl %eax, %eax
callq 0x52f9
movq 0x10e1b(%rip), %rax     # 0x131f0
movq 0x10(%rax), %rdx
jmp 0x24d5
movq 0x20(%rbx), %rdx
movslq %edx, %rax
leaq 0x10e34(%rip), %rbx     # 0x13220
movq (%rbx), %rdi
cmpq %rdx, %rax
jne 0x2674
leaq 0xa585(%rip), %rsi      # 0xc984
jmp 0x24e6
movq 0x8(%rbx), %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x279e
movq 0x8(%rbx), %rdi
callq 0x1ead
leaq 0x10df5(%rip), %rbx     # 0x13220
movq (%rbx), %rcx
leaq 0x9f1b(%rip), %rdi      # 0xc350
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%rbx), %rcx
leaq 0xa586(%rip), %rdi      # 0xc9d4
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
jmp 0x2682
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x28fa
movq 0x8(%rbx), %rdi
callq 0x1ead
movq 0x8(%rbx), %rdi
callq 0xb354
movq %rax, %r14
movq %rbx, %rdi
callq 0xb354
movq %r14, %rdi
movq %rax, %rsi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1c63
cmpq $0x0, 0x10d3a(%rip)     # 0x131f0
jne 0x24ca
movq 0x50(%rbx), %rdi
leaq 0x9cee(%rip), %rsi      # 0xc1b1
xorl %eax, %eax
callq 0x52f9
movq 0x10d1f(%rip), %rax     # 0x131f0
movq 0x8(%rax), %rdx
leaq 0x10d44(%rip), %rax     # 0x13220
movq (%rax), %rdi
leaq 0x9c9a(%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 0x10d16(%rip), %rax     # 0x13220
movq (%rax), %rdi
leaq 0x9c6c(%rip), %rsi      # 0xc180
movq %r14, %rdx
xorl %eax, %eax
callq 0x10f0
movq 0x8(%rbx), %rsi
movq %r14, 0x40(%rsi)
jmp 0x2661
movq 0x50(%rbx), %rdi
leaq 0xa4a9(%rip), %rsi      # 0xc9df
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x52f9
leaq 0xb3dc(%rip), %rbx      # 0xd92e
movq (%r12), %rdi
cltq
leaq 0x10ba1(%rip), %rcx     # 0x13100
leaq (%rcx,%rax,4), %rdx
leaq 0x10ba6(%rip), %rcx     # 0x13110
leaq (%rcx,%rax,4), %rcx
leaq 0xa3a5(%rip), %rsi      # 0xc91a
xorl %eax, %eax
callq 0x10f0
movq (%r12), %rdi
leaq 0xa3a1(%rip), %rsi      # 0xc928
movq %rbx, %rdx
xorl %eax, %eax
callq 0x10f0
movq (%r12), %rdi
leaq 0xa397(%rip), %rsi      # 0xc933
leaq 0x10b61(%rip), %rdx     # 0x13104
xorl %eax, %eax
callq 0x10f0
jmp 0x2776
leaq 0x9c6c(%rip), %rdi      # 0xc222
xorl %eax, %eax
callq 0x50b0
movq 0x18(%r14), %r15
movq 0x8(%rbx), %rdi
callq 0x1ead
movq 0x30(%r15), %rax
leaq 0x10c4b(%rip), %r12     # 0x13220
movq (%r12), %rdi
movl 0x18(%rax), %edx
leaq 0x9da6(%rip), %rsi      # 0xc389
xorl %eax, %eax
callq 0x10f0
movq (%r12), %rcx
leaq 0x9c9f(%rip), %rdi      # 0xc294
movl $0x11, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0x9e71(%rip), %rdi      # 0xc480
movl $0xa, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa34b(%rip), %rdi      # 0xc974
movl $0xf, %esi
movl $0x1, %edx
callq 0x1190
callq 0x1958
movq %rax, %r14
movq (%r12), %rdi
leaq 0x9e6a(%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 0x3f66
leaq 0xa314(%rip), %rsi      # 0xc98f
xorl %eax, %eax
callq 0x10f0
movq (%rbx), %rcx
jmp 0x277a
movq (%r12), %rcx
leaq 0xa244(%rip), %rdi      # 0xc8d9
jmp 0x2767
movq (%r12), %rcx
leaq 0xa244(%rip), %rdi      # 0xc8e9
movl $0xf, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa249(%rip), %rdi      # 0xc908
jmp 0x26e6
movq (%r12), %rcx
leaq 0xa21d(%rip), %rdi      # 0xc8e9
movl $0xf, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa213(%rip), %rdi      # 0xc8f9
movl $0xe, %esi
jmp 0x276c
movq (%r12), %rcx
leaq 0xa1ab(%rip), %rdi      # 0xc8a3
movl $0x5, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0xa197(%rip), %rdi      # 0xc8a9
jmp 0x2767
movq 0x50(%rbx), %rdi
leaq 0xa223(%rip), %rsi      # 0xc942
xorl %eax, %eax
callq 0x52f9
jmp 0x2776
movq (%r12), %rcx
leaq 0xa140(%rip), %rdi      # 0xc873
jmp 0x2767
movq (%r12), %rcx
leaq 0xa153(%rip), %rdi      # 0xc893
jmp 0x2767
movq (%r12), %rcx
leaq 0xa136(%rip), %rdi      # 0xc883
jmp 0x2767
movq (%r12), %rcx
leaq 0xa16f(%rip), %rdi      # 0xc8c9
jmp 0x2767
movq (%r12), %rcx
leaq 0xa152(%rip), %rdi      # 0xc8b9
movl $0xf, %esi
movl $0x1, %edx
callq 0x1190
movq (%r12), %rcx
leaq 0x9bb8(%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