// File: /workspace/github_c_makefile_star2_O0/taeguk[P]Compiler-Proj-Cminus/src/cgen.c
// Function: codeGen
void codeGen(TreeNode *syntaxTree, FILE *codeStream)
{
  int i;
  TreeNode *t;

  fprintf(codeStream, ".data\n");
  fprintf(codeStream, "newline: .asciiz \"\\n\"\n");
  fprintf(codeStream, "output_str: .asciiz \"Output : \"\n");
  fprintf(codeStream, "input_str: .asciiz \"Input : \"\n");


  fprintf(codeStream, "\n.text\n");
  for(t = syntaxTree;
      t != NULL;
      t = t->sibling)
    {
      if(t->nodeKind == VariableDeclarationK)
        {
          t->attr.varDecl._var->symbolInfo->attr.intInfo.memloc = globalMemAlloc(sizeof(int));
          t->attr.varDecl._var->symbolInfo->attr.intInfo.globalFlag = TRUE;
        }
      else if(t->nodeKind == ArrayDeclarationK)
        {
          t->attr.arrDecl._var->symbolInfo->attr.arrInfo.memloc =
            globalMemAlloc(sizeof(int) * t->attr.arrDecl._var->symbolInfo->attr.arrInfo.arrLen);
          t->attr.arrDecl._var->symbolInfo->attr.arrInfo.globalFlag = TRUE;
        }
      else if(t->nodeKind == FunctionDeclarationK)
        {
          // Function labeling
          fprintf(codeStream, "# Function declaration\n");
          fprintf(codeStream, "%s:\n", t->attr.funcDecl._var->attr.ID);

          // Function parameter's total memory
          TreeNode *param;
          int accLoc = 0;
          for(param = t->attr.funcDecl.params;
              param != NULL;
              param = param->sibling)
            {
              TreeNode *var = param->attr.funcDecl._var;
              if(var->symbolInfo->nodeType == IntT)
                accLoc += sizeof(int);
              else if(var->nodeType == IntArrayT)
                accLoc += regSize;
            }

          // real location
          // ex. f(a, b, c)
          // a: 8(fp), b: 4(fp), c:0(fp)
          // pushed early <--> pushed late
          for(param = t->attr.funcDecl.params;
              param != NULL;
              param = param->sibling)
            {
              switch(param->nodeType)
                {
                case VariableParameterK:
                  accLoc -= sizeof(int);
                  param->attr.varParam._var->symbolInfo->attr.intInfo.memloc = accLoc;
                  break;
                case ArrayParameterK:
                  accLoc -= regSize;
                  // TODO:
                  param->attr.arrParam._var->symbolInfo->attr.arrInfo.memloc = accLoc;
                  break;
                default:
                  DONT_OCCUR_PRINT;
                }
            }

          // allocate stack
          fprintf(codeStream, "\n# Allocate stack\n");
          fprintf(codeStream, "addiu $sp, $sp, %d\n", -10 * regSize);

          // save register $fp
          fprintf(codeStream, "# Save registers\n");
          fprintf(codeStream, "sw $fp, %d($sp)\n", 0 * regSize);
          // save registers $s0~$s7
          for(i=0; i<8; ++i)
            fprintf(codeStream, "sw $s%d, %d($sp)\n", i, (i+1) * regSize);
          // save register $ra
          fprintf(codeStream, "sw $ra, %d($sp)\n", 9 * regSize);

          // set frame
          fprintf(codeStream, "addiu $fp, $sp, %d\n", 10 * regSize);

          L_cleanup = labelAlloc();

          // cmpd statement generation
          fprintf(codeStream, "\n# Compound statement for function\n");
          int updateStack = localCodeGen(t->attr.funcDecl.cmpd_stmt, codeStream, 10 * regSize, 1);
          if(updateStack != 10 * regSize)
            DONT_OCCUR_PRINT;

          // cleanup for function with no return
          fprintf(codeStream, "\n# Stack cleanup\n");
          fprintf(codeStream, "L%d:\n", L_cleanup);

          // cleanup remained local stack.
          fprintf(codeStream, "addiu $sp, $fp, %d\n", -10 * regSize);

          // load registers
          fprintf(codeStream, "lw $fp, %d($sp)\n", 0 * regSize);
          // load registers $s0~$s7
          for(i=0; i<8; ++i)
            fprintf(codeStream, "lw $s%d, %d($sp)\n", i, (i+1) * regSize);
          // load register $ra
          fprintf(codeStream, "lw $ra, %d($sp)\n", 9 * regSize);
          fprintf(codeStream, "addiu $sp, $sp, %d\n", 10 * regSize);

          // return
          fprintf(codeStream, "\n# Return to caller\n");
          fprintf(codeStream, "jr $ra\n\n");
        }
      else
        DONT_OCCUR_PRINT;
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x40, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x10(%rbp), %rdi
leaq 0x6dd9(%rip), %rsi      # 0x9644
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
leaq 0x6dce(%rip), %rsi      # 0x964b
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
leaq 0x6dd3(%rip), %rsi      # 0x9662
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
leaq 0x6de2(%rip), %rsi      # 0x9683
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
leaq 0x6def(%rip), %rsi      # 0x96a2
movb $0x0, %al
callq 0x1120
movq -0x8(%rbp), %rax
movq %rax, -0x20(%rbp)
cmpq $0x0, -0x20(%rbp)
je 0x2c98
movq -0x20(%rbp), %rax
cmpl $0x1, 0xc(%rax)
jne 0x290a
movl $0x4, %edi
callq 0x2ca0
movl %eax, %ecx
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rax
movl %ecx, 0xc(%rax)
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rax
movl $0x1, 0x10(%rax)
jmp 0x2c86
movq -0x20(%rbp), %rax
cmpl $0x2, 0xc(%rax)
jne 0x2958
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rax
movslq 0x14(%rax), %rax
shlq $0x2, %rax
movl %eax, %edi
callq 0x2ca0
movl %eax, %ecx
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rax
movl %ecx, 0xc(%rax)
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rax
movl $0x1, 0x10(%rax)
jmp 0x2c84
movq -0x20(%rbp), %rax
cmpl $0x3, 0xc(%rax)
jne 0x2c80
movq -0x10(%rbp), %rdi
leaq 0x6d39(%rip), %rsi      # 0x96aa
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x20(%rax), %rdx
leaq 0x6d33(%rip), %rsi      # 0x96c2
movb $0x0, %al
callq 0x1120
movl $0x0, -0x2c(%rbp)
movq -0x20(%rbp), %rax
movq 0x30(%rax), %rax
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
je 0x29fd
movq -0x28(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0x38(%rbp)
movq -0x38(%rbp), %rax
movq 0x18(%rax), %rax
cmpl $0x4, (%rax)
jne 0x29d6
movslq -0x2c(%rbp), %rax
addq $0x4, %rax
movl %eax, -0x2c(%rbp)
jmp 0x29ee
movq -0x38(%rbp), %rax
cmpl $0x5, 0x10(%rax)
jne 0x29ec
movl 0xb722(%rip), %eax      # 0xe108
addl -0x2c(%rbp), %eax
movl %eax, -0x2c(%rbp)
jmp 0x29ee
jmp 0x29f0
movq -0x28(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x28(%rbp)
jmp 0x29a9
movq -0x20(%rbp), %rax
movq 0x30(%rax), %rax
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x28(%rbp)
je 0x2a7d
movq -0x28(%rbp), %rax
movl 0x10(%rax), %eax
movl %eax, -0x40(%rbp)
subl $0x4, %eax
je 0x2a2b
jmp 0x2a21
movl -0x40(%rbp), %eax
subl $0x5, %eax
je 0x2a4a
jmp 0x2a6c
movslq -0x2c(%rbp), %rax
subq $0x4, %rax
movl %eax, -0x2c(%rbp)
movl -0x2c(%rbp), %ecx
movq -0x28(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rax
movl %ecx, 0xc(%rax)
jmp 0x2a6e
movl 0xb6b8(%rip), %ecx      # 0xe108
movl -0x2c(%rbp), %eax
subl %ecx, %eax
movl %eax, -0x2c(%rbp)
movl -0x2c(%rbp), %ecx
movq -0x28(%rbp), %rax
movq 0x28(%rax), %rax
movq 0x18(%rax), %rax
movl %ecx, 0xc(%rax)
jmp 0x2a6e
jmp 0x2a6e
jmp 0x2a70
movq -0x28(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x28(%rbp)
jmp 0x2a09
movq -0x10(%rbp), %rdi
leaq 0x6c3f(%rip), %rsi      # 0x96c7
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
imull $0xfffffff6, 0xb66b(%rip), %edx # imm = 0xFFFFFFF6
leaq 0x6c36(%rip), %rsi      # 0x96da
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
leaq 0x6c38(%rip), %rsi      # 0x96ee
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
imull $0x0, 0xb640(%rip), %edx # 0xe108
leaq 0x6c31(%rip), %rsi      # 0x9700
movb $0x0, %al
callq 0x1120
movl $0x0, -0x14(%rbp)
cmpl $0x8, -0x14(%rbp)
jge 0x2b10
movq -0x10(%rbp), %rdi
movl -0x14(%rbp), %edx
movl -0x14(%rbp), %ecx
addl $0x1, %ecx
imull 0xb611(%rip), %ecx      # 0xe108
leaq 0x6c13(%rip), %rsi      # 0x9711
movb $0x0, %al
callq 0x1120
movl -0x14(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
jmp 0x2add
movq -0x10(%rbp), %rdi
imull $0x9, 0xb5ed(%rip), %edx # 0xe108
leaq 0x6c01(%rip), %rsi      # 0x9723
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
imull $0xa, 0xb5d4(%rip), %edx # 0xe108
leaq 0x6bf9(%rip), %rsi      # 0x9734
movb $0x0, %al
callq 0x1120
callq 0x2cd0
movl %eax, 0xb5eb(%rip)      # 0xe138
movq -0x10(%rbp), %rdi
leaq 0x6bf0(%rip), %rsi      # 0x9748
movb $0x0, %al
callq 0x1120
movq -0x20(%rbp), %rax
movq 0x38(%rax), %rdi
movq -0x10(%rbp), %rsi
imull $0xa, 0xb596(%rip), %edx # 0xe108
movl $0x1, %ecx
callq 0x2cf0
movl %eax, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
imull $0xa, 0xb57f(%rip), %ecx # 0xe108
cmpl %ecx, %eax
je 0x2b8f
jmp 0x2b8f
movq -0x10(%rbp), %rdi
leaq 0x6bd2(%rip), %rsi      # 0x976c
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
movl 0xb58d(%rip), %edx      # 0xe138
leaq 0x6bcc(%rip), %rsi      # 0x977e
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
imull $0xfffffff6, 0xb541(%rip), %edx # imm = 0xFFFFFFF6
leaq 0x6bb6(%rip), %rsi      # 0x9784
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
imull $0x0, 0xb528(%rip), %edx # 0xe108
leaq 0x6bb1(%rip), %rsi      # 0x9798
movb $0x0, %al
callq 0x1120
movl $0x0, -0x14(%rbp)
cmpl $0x8, -0x14(%rbp)
jge 0x2c28
movq -0x10(%rbp), %rdi
movl -0x14(%rbp), %edx
movl -0x14(%rbp), %ecx
addl $0x1, %ecx
imull 0xb4f9(%rip), %ecx      # 0xe108
leaq 0x6b93(%rip), %rsi      # 0x97a9
movb $0x0, %al
callq 0x1120
movl -0x14(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x14(%rbp)
jmp 0x2bf5
movq -0x10(%rbp), %rdi
imull $0x9, 0xb4d5(%rip), %edx # 0xe108
leaq 0x6b81(%rip), %rsi      # 0x97bb
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
imull $0xa, 0xb4bc(%rip), %edx # 0xe108
leaq 0x6a87(%rip), %rsi      # 0x96da
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
leaq 0x6b67(%rip), %rsi      # 0x97cc
movb $0x0, %al
callq 0x1120
movq -0x10(%rbp), %rdi
leaq 0x6b6a(%rip), %rsi      # 0x97e1
movb $0x0, %al
callq 0x1120
jmp 0x2c82
jmp 0x2c82
jmp 0x2c84
jmp 0x2c86
jmp 0x2c88
movq -0x20(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x20(%rbp)
jmp 0x28c2
addq $0x40, %rsp
popq %rbp
retq
nop