// File: /workspace/github_c_makefile_star2_O2/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 0x1c76
movq %rdi, %rbx
cmpb $0x1, 0xf9fd(%rip)      # 0x11200
jne 0x1871
movq 0x50(%rbx), %rax
movq 0x20(%rax), %rdi
leaq 0xf9fc(%rip), %rax      # 0x11210
movq (%rax), %rsi
callq 0x45e8
movl %eax, %ebp
movq 0x50(%rbx), %rax
movq 0x20(%rax), %rdi
callq 0x4774
movl %eax, %r14d
leaq 0xf9eb(%rip), %r15      # 0x11220
movq (%r15), %rdi
leaq 0x900f(%rip), %rsi      # 0xa84e
movl %ebp, %edx
xorl %eax, %eax
callq 0x10f0
movq %rbx, %rdi
callq 0x36e0
movq (%r15), %rsi
pushq $0xa
popq %rdi
callq 0x10c0
movq (%r15), %rdi
leaq 0x8ff5(%rip), %rsi      # 0xa85a
movl %r14d, %edx
movl %ebp, %ecx
xorl %eax, %eax
callq 0x10f0
movl (%rbx), %eax
decl %eax
cmpl $0x26, %eax
ja 0x1df9
leaq 0x87a3(%rip), %rcx      # 0xa028
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x8(%rbx), %rdi
callq 0x9610
movq %rax, %r14
movq 0x10(%rbx), %rdi
callq 0x9610
movq %rax, %r15
movl (%rbx), %eax
cmpl $0xd, %eax
je 0x18bc
cmpl $0xc, %eax
jne 0x18dc
movq %rbx, %rdi
callq 0x28e5
jmp 0x18c4
movq %rbx, %rdi
callq 0x2a9b
leaq 0xf955(%rip), %rax      # 0x11220
movq (%rax), %rcx
leaq 0x8f92(%rip), %rdi      # 0xa867
pushq $0xb
jmp 0x1f88
movq 0x8(%rbx), %rdi
callq 0x17e5
movq 0x10(%rbx), %rdi
callq 0x17e5
leaq 0xf92b(%rip), %rbp      # 0x11220
movq (%rbp), %rcx
leaq 0x8b80(%rip), %rdi      # 0xa480
pushq $0xa
popq %r12
pushq $0x1
popq %r13
movq %r12, %rsi
movq %r13, %rdx
callq 0x1190
movq (%rbp), %rcx
leaq 0x8a32(%rip), %rdi      # 0xa350
movq %r12, %rsi
movq %r13, %rdx
callq 0x1190
movl (%rbx), %eax
addl $-0x4, %eax
cmpl $0xf, %eax
ja 0x1f1d
leaq 0x8786(%rip), %rcx      # 0xa0c4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq %r14, %rdi
movq %r15, %rsi
callq 0x94a5
testb %al, %al
jne 0x1967
leaq 0x8e26(%rip), %rsi      # 0xa783
movq %rbx, %rdi
xorl %eax, %eax
callq 0x4a9e
movq %r14, %rdi
movq %r15, %rsi
callq 0x9207
movq %rax, %rdi
callq 0x14be
movl (%rbx), %ecx
addl $-0x9, %ecx
cmpl $0x2, %ecx
ja 0x1e19
movl %ecx, %ecx
leaq 0x87bb(%rip), %rdx      # 0xa14c
movslq (%rdx,%rcx,4), %rbx
addq %rdx, %rbx
jmp 0x1e20
movq %rbx, %rdi
callq 0x9610
movq %rax, %rdi
callq 0x91ad
testb %al, %al
je 0x19b9
movq %rbx, %rdi
jmp 0x1cfa
movq %rbx, %rdi
callq 0x173c
jmp 0x1a3d
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x238d
movq 0x8(%rbx), %rdi
callq 0x9610
movq %rax, %rdi
callq 0x9198
testb %al, %al
jne 0x1a00
movq 0x8(%rbx), %rdi
leaq 0x8fa6(%rip), %rsi      # 0xa99f
xorl %eax, %eax
callq 0x4a9e
movq 0x8(%rbx), %rdi
callq 0x17e5
movq %rbx, %rdi
callq 0x9610
movq %rax, %rdi
callq 0x91ad
testb %al, %al
jne 0x1c76
leaq 0xf7f8(%rip), %rax      # 0x11220
movq (%rax), %rcx
leaq 0x891e(%rip), %rdi      # 0xa350
pushq $0xa
popq %rsi
pushq $0x1
popq %rdx
callq 0x1190
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x14f6
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2454
movq 0x8(%rbx), %rdi
testq %rdi, %rdi
je 0x1a93
callq 0x17e5
leaq 0xf7a2(%rip), %rax      # 0x11220
movq (%rax), %rcx
leaq 0x88c8(%rip), %rdi      # 0xa350
pushq $0xa
popq %rsi
pushq $0x1
popq %rdx
callq 0x1190
movq 0xf75e(%rip), %rdi      # 0x111f8
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1388
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x21cd
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2287
callq 0x148b
movq %rax, %r14
movq 0x8(%rbx), %rdi
callq 0x17e5
movq 0x30(%r14), %rdi
callq 0x16f8
leaq 0xf726(%rip), %r12      # 0x11220
movq (%r12), %rcx
leaq 0x878f(%rip), %rdi      # 0xa294
pushq $0x11
popq %rsi
pushq $0x1
popq %r15
movq %r15, %rdx
callq 0x1190
movq (%r12), %rcx
leaq 0x8961(%rip), %rdi      # 0xa480
pushq $0xa
popq %rsi
movq %r15, %rdx
callq 0x1190
movq (%r12), %rcx
leaq 0x8e3f(%rip), %rdi      # 0xa974
pushq $0xf
popq %rsi
movq %r15, %rdx
callq 0x1190
callq 0x12e8
movq %rax, %r15
movq (%r12), %rdi
leaq 0x8962(%rip), %rsi      # 0xa4b5
movq %rax, %rdx
xorl %eax, %eax
callq 0x10f0
movq 0x10(%rbx), %rsi
movq %r15, 0x40(%rsi)
movq 0x48(%r14), %rdi
jmp 0x1de6
movq 0x8(%rbx), %rdi
movq 0x10(%rbx), %rsi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2ef7
movq %rbx, %rdi
callq 0x13ee
movq 0x30(%rbx), %rdi
callq 0x16f8
leaq 0xf67f(%rip), %r12      # 0x11220
movq (%r12), %rcx
leaq 0x878d(%rip), %rdi      # 0xa339
pushq $0xa
popq %r15
pushq $0x1
popq %r14
movq %r15, %rsi
movq %r14, %rdx
callq 0x1190
movq 0x8(%rbx), %rdi
callq 0x17e5
movq (%r12), %rcx
leaq 0x88ad(%rip), %rdi      # 0xa480
movq %r15, %rsi
movq %r14, %rdx
callq 0x1190
movq (%r12), %rcx
leaq 0x8767(%rip), %rdi      # 0xa350
movq %r15, %rsi
movq %r14, %rdx
callq 0x1190
movq (%r12), %rcx
leaq 0x8d63(%rip), %rdi      # 0xa962
pushq $0x11
popq %rsi
movq %r14, %rdx
callq 0x1190
movq 0x10(%rbx), %rdi
callq 0x2196
xorl %r15d, %r15d
xorl %edi, %edi
callq 0x1463
movq %rax, %rdi
callq 0x1347
movq 0x48(%rbx), %rdi
callq 0x34f2
cltq
cmpq %rax, %r15
jge 0x1c56
movq 0x48(%rbx), %rax
movq (%rax), %rax
movq (%rax,%r15,8), %r14
movq 0x40(%r14), %rdi
callq 0x132c
movq %r14, %rdi
callq 0x2196
incq %r15
jmp 0x1c25
xorl %edi, %edi
callq 0x1463
movq %rax, %rdi
callq 0x132c
movq 0xf584(%rip), %rax      # 0x111f0
movq (%rax), %rax
movq %rax, 0xf57a(%rip)      # 0x111f0
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 0x2624
movq %rbx, %rdi
callq 0x2c51
leaq 0xf576(%rip), %rax      # 0x11220
movq (%rax), %rcx
jmp 0x1f7f
movq 0x50(%rbx), %rdi
callq 0x1463
jmp 0x1db8
movq 0x20(%rbx), %rdx
movslq %edx, %rax
leaq 0xf552(%rip), %rbx      # 0x11220
movq (%rbx), %rdi
cmpq %rdx, %rax
jne 0x1e7d
leaq 0x8ca3(%rip), %rsi      # 0xa984
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x10f0
movq 0x8(%rbx), %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1f9f
movq 0x8(%rbx), %rdi
callq 0x17e5
leaq 0xf503(%rip), %r15      # 0x11220
movq (%r15), %rcx
leaq 0x8629(%rip), %rdi      # 0xa350
pushq $0xa
popq %rbx
pushq $0x1
popq %r14
movq %rbx, %rsi
movq %r14, %rdx
callq 0x1190
movq (%r15), %rcx
leaq 0x8c91(%rip), %rdi      # 0xa9d4
movq %rbx, %rsi
movq %r14, %rdx
callq 0x1190
movq (%r15), %rcx
leaq 0x85e1(%rip), %rdi      # 0xa339
movq %rbx, %rsi
movq %r14, %rdx
jmp 0x1f8c
movq %rbx, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x20f2
movq 0x8(%rbx), %rdi
callq 0x17e5
movq 0x8(%rbx), %rdi
callq 0x9610
movq %rax, %r14
movq %rbx, %rdi
callq 0x9610
movq %r14, %rdi
movq %rax, %rsi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x15dd
movq 0x50(%rbx), %rdi
callq 0x143b
movq %rax, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1347
callq 0x12e8
movq %rax, %r14
movq %rax, %rdi
callq 0x1347
movq 0x8(%rbx), %rsi
movq %r14, 0x40(%rsi)
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x34f6
movq 0x50(%rbx), %rdi
leaq 0x8bdb(%rip), %rsi      # 0xa9df
xorl %eax, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x48b3
leaq 0x9b32(%rip), %rbx      # 0xb952
movq (%rbp), %rdi
cltq
leaq 0xf2d3(%rip), %rcx      # 0x11100
leaq (%rcx,%rax,4), %rdx
leaq 0xf2d8(%rip), %rcx      # 0x11110
leaq (%rcx,%rax,4), %rcx
leaq 0x8ad7(%rip), %rsi      # 0xa91a
xorl %eax, %eax
callq 0x10f0
movq (%rbp), %rdi
leaq 0x8ad3(%rip), %rsi      # 0xa928
movq %rbx, %rdx
xorl %eax, %eax
callq 0x10f0
movq (%rbp), %rdi
leaq 0x8ac9(%rip), %rsi      # 0xa933
leaq 0xf293(%rip), %rdx      # 0x11104
xorl %eax, %eax
callq 0x10f0
jmp 0x1f7b
leaq 0x8b0b(%rip), %rsi      # 0xa98f
xorl %eax, %eax
callq 0x10f0
movq (%rbx), %rcx
jmp 0x1f7f
movq (%rbp), %rcx
leaq 0x8a3b(%rip), %rdi      # 0xa8d9
jmp 0x1f70
movq (%rbp), %rcx
leaq 0x8a3b(%rip), %rdi      # 0xa8e9
pushq $0xf
popq %rsi
pushq $0x1
popq %rbx
movq %rbx, %rdx
callq 0x1190
movq (%rbp), %rcx
leaq 0x8a41(%rip), %rdi      # 0xa908
jmp 0x1eed
movq (%rbp), %rcx
leaq 0x8a15(%rip), %rdi      # 0xa8e9
pushq $0xf
popq %rsi
pushq $0x1
popq %rbx
movq %rbx, %rdx
callq 0x1190
movq (%rbp), %rcx
leaq 0x8a0c(%rip), %rdi      # 0xa8f9
pushq $0xe
jmp 0x1f17
movq (%rbp), %rcx
leaq 0x89a7(%rip), %rdi      # 0xa8a3
pushq $0x5
popq %rsi
pushq $0x1
popq %rbx
movq %rbx, %rdx
callq 0x1190
movq (%rbp), %rcx
leaq 0x8994(%rip), %rdi      # 0xa8a9
pushq $0xf
popq %rsi
movq %rbx, %rdx
jmp 0x1f76
movq 0x50(%rbx), %rdi
leaq 0x8a1a(%rip), %rsi      # 0xa942
xorl %eax, %eax
callq 0x48b3
jmp 0x1f7b
movq (%rbp), %rcx
leaq 0x8937(%rip), %rdi      # 0xa873
jmp 0x1f70
movq (%rbp), %rcx
leaq 0x894a(%rip), %rdi      # 0xa893
jmp 0x1f70
movq (%rbp), %rcx
leaq 0x892d(%rip), %rdi      # 0xa883
jmp 0x1f70
movq (%rbp), %rcx
leaq 0x8966(%rip), %rdi      # 0xa8c9
jmp 0x1f70
movq (%rbp), %rcx
leaq 0x8949(%rip), %rdi      # 0xa8b9
pushq $0xf
popq %rsi
pushq $0x1
popq %rdx
callq 0x1190
movq (%rbp), %rcx
leaq 0x83b3(%rip), %rdi      # 0xa339
pushq $0xa
popq %rsi
pushq $0x1
popq %rdx
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1190