// File: /workspace/github_c_makefile_star2_O0/hsjoihs[P]c-compiler/codegen.c
// Function: print_toplevel_definition
static void print_toplevel_definition(struct PrinterState *ptr_prs,
                                      const struct Toplevel *ref_def)
{
	if (ref_def->category == TOPLEVEL_VAR_DEFINITION) {
		if (ref_def->declarator_name && !ref_def->is_extern_global_var) {
			gen_global_declaration(ref_def->declarator_name,
			                       ref_def->size_of_declarator_type);
		}
		return;
	}
	if (ref_def->category == TOPLEVEL_FUNCTION_DECLARATION) {
		return;
	}

	assert(ref_def->category == TOPLEVEL_FUNCTION_DEFINITION);

	const struct Statement sta = ref_def->func.sta;
	struct Vector /*<LocalVarInfo>*/ offsets_and_types =
	    ref_def->func.offsets_and_types;
	struct Type ret_type = ref_def->func.ret_type;
	const char *declarator_name = ref_def->declarator_name;

	ptr_prs->return_label_name = -1;   /* -1 means invalid */
	ptr_prs->break_label_name = -1;    /* -1 means invalid */
	ptr_prs->continue_label_name = -1; /* -1 means invalid */
	ptr_prs->is_va = ref_def->func.is_va;
	if (ref_def->func.is_va) {
		ptr_prs->integral_explicit_arg_num = offsets_and_types.length;
	}
	// int label1;
	// int label2;
	// label1 = get_new_label_name(ptr_prs);
	// label2 = get_new_label_name(ptr_prs);

	int capacity = ref_def->func.capacity;
	if (ref_def->func.is_va) {
		capacity += 8 /* stack_check */ + 8 * 6 + 16 * 8 /* reg_save_area */
		            + 8;                                 /* just to be safe */
	}
	if (ref_def->func.is_static_function) {
		gen_prologue_static(capacity, declarator_name);
	} else {
		gen_prologue(capacity, declarator_name);
	}
	for (int counter = 0; counter < offsets_and_types.length; ++counter) {
		if (counter >= 6) {
			unsupported("7 or more args detected in function definition");
		}
		const struct LocalVarInfo *ptr_info = offsets_and_types.vector[counter];

		int offset = ptr_info->offset;
		const struct Type type = ptr_info->type;
		switch (size_of_basic(&type, "argument to be passed to function")) {
		case 1:
			gen_write_register_to_local_1byte(
			    /* yes, the register is 4byte */
			    get_reg_name_from_arg_pos_4byte(counter), offset);
			break;
		case 4:
			gen_write_register_to_local_4byte(
			    get_reg_name_from_arg_pos_4byte(counter), offset);
			break;
		case 8:
			gen_write_register_to_local_8byte(
			    get_reg_name_from_arg_pos_8byte(counter), offset);
			break;
		default:
			unsupported("Unsupported width in function parameter");
		}
	}

	if (ref_def->func.is_va) {
		int another_label = get_new_label_name(ptr_prs);
		ptr_prs->reg_save_area = -capacity + 8;
		ptr_prs->stack_chk_offset = -capacity;
		gen_store_regs_to_local(ptr_prs->reg_save_area, 1, another_label);
		gen_write_stack_chk_guard_to_local(ptr_prs->stack_chk_offset);
	}

	struct Vector /*<SourceLabel>*/ source_labels = collect_named_labels(&sta);

	struct Map2 /*<SourceLabelAndAssemblyLabel>*/
	    *source_label_to_assembly_label = init_map();
	for (int i = 0; i < source_labels.length; i++) {
		const struct SourceLabel *ptr = source_labels.vector[i];
		switch (ptr->category) {
		case DEFAULT_LABEL:
		case CASE_LABEL:
			continue;
		case IDENT_LABEL: {
			struct SourceLabelAndAssemblyLabel *p =
			    calloc(1, sizeof(struct SourceLabelAndAssemblyLabel));
			p->assembly_label = get_new_label_name(ptr_prs);
			p->source_label = *ptr;
			insert(source_label_to_assembly_label, ptr->ident_str, p);
		}
		}
	}

	ptr_prs->source_label_to_assembly_label = source_label_to_assembly_label;

	print_statement(ptr_prs, &sta);

	if (ret_type.type_category == VOID_) {
		if (ptr_prs->return_label_name != -1) {
			gen_label(ptr_prs->return_label_name);
		}
		gen_return_garbage();
		return;
	}

	if (ptr_prs->return_label_name == -1) {
		simple_error("the return type is not void, but `return` is not found");
	}
	if (is_struct_or_union(&ret_type)) {
		enum SystemVAbiClass abi_class = ref_def->func.abi_class;
		int ret_struct_or_union_size = ref_def->func.ret_struct_or_union_size;

		if (ref_def->func.is_va) {
			unsupported(
			    "variable argument function that returns a struct/union");
		}

		if (abi_class == INTEGER_CLASS) {
			gen_epilogue_returning_integerclass_struct_or_union(
			    ret_struct_or_union_size, ptr_prs->return_label_name);
		} else {
			gen_label(ptr_prs->return_label_name);
			gen_push_from_local_nbyte(8, ref_def->func.hidden_var_offset);
			gen_copy_2nd_struct_or_union_to_1st_and_discard(
			    ret_struct_or_union_size);
			gen_return_garbage();
		}
	} else {
		if (ref_def->func.is_va) {
			int label = get_new_label_name(ptr_prs);
			gen_epilogue_nbyte_with_stack_check(
			    size_of_basic(&ret_type, "return value"),
			    ptr_prs->return_label_name, ptr_prs->stack_chk_offset, label);
		} else {
			gen_epilogue_nbyte(size_of_basic(&ret_type, "return value"),
			                   ptr_prs->return_label_name);
		}
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x4c0, %rsp            # imm = 0x4C0
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x10(%rbp), %rax
cmpl $0x0, (%rax)
jne 0x1c80
movq -0x10(%rbp), %rax
cmpq $0x0, 0x8(%rax)
je 0x1c7b
movq -0x10(%rbp), %rax
cmpl $0x0, 0x46c(%rax)
jne 0x1c7b
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x10(%rbp), %rax
movl 0x468(%rax), %esi
callq 0xdd40
jmp 0x21c4
movq -0x10(%rbp), %rax
cmpl $0x2, (%rax)
jne 0x1c8e
jmp 0x21c4
movq -0x10(%rbp), %rax
cmpl $0x1, (%rax)
sete %al
andb $0x1, %al
movzbl %al, %edi
movb $0x0, %al
callq 0x1260
movq -0x10(%rbp), %rsi
addq $0x60, %rsi
leaq -0x3a0(%rbp), %rdi
movl $0x390, %edx            # imm = 0x390
callq 0x10e0
movq -0x10(%rbp), %rax
movq 0x3f0(%rax), %rcx
movq %rcx, -0x3b0(%rbp)
movq 0x3f8(%rax), %rax
movq %rax, -0x3a8(%rbp)
movq -0x10(%rbp), %rsi
addq $0x60, %rsi
addq $0x3a0, %rsi            # imm = 0x3A0
leaq -0x400(%rbp), %rdi
movl $0x50, %edx
callq 0x10e0
movq -0x10(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x408(%rbp)
movq -0x8(%rbp), %rax
movl $0xffffffff, 0x4(%rax)  # imm = 0xFFFFFFFF
movq -0x8(%rbp), %rax
movl $0xffffffff, 0x8(%rax)  # imm = 0xFFFFFFFF
movq -0x8(%rbp), %rax
movl $0xffffffff, 0xc(%rax)  # imm = 0xFFFFFFFF
movq -0x10(%rbp), %rax
movl 0x464(%rax), %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x40(%rax)
movq -0x10(%rbp), %rax
cmpl $0x0, 0x464(%rax)
je 0x1d58
movl -0x3b0(%rbp), %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x44(%rax)
movq -0x10(%rbp), %rax
movl 0x450(%rax), %eax
movl %eax, -0x40c(%rbp)
movq -0x10(%rbp), %rax
cmpl $0x0, 0x464(%rax)
je 0x1d86
movl -0x40c(%rbp), %eax
addl $0xc0, %eax
movl %eax, -0x40c(%rbp)
movq -0x10(%rbp), %rax
cmpl $0x0, 0x454(%rax)
je 0x1da7
movl -0x40c(%rbp), %edi
movq -0x408(%rbp), %rsi
callq 0xcee0
jmp 0x1db9
movl -0x40c(%rbp), %edi
movq -0x408(%rbp), %rsi
callq 0xcd50
movl $0x0, -0x410(%rbp)
movl -0x410(%rbp), %eax
cmpl -0x3b0(%rbp), %eax
jge 0x1eff
cmpl $0x6, -0x410(%rbp)
jl 0x1dea
leaq 0x114bf(%rip), %rdi     # 0x132a4
callq 0xb1f0
movq -0x3a8(%rbp), %rax
movslq -0x410(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x418(%rbp)
movq -0x418(%rbp), %rax
movl 0x50(%rax), %eax
movl %eax, -0x41c(%rbp)
movq -0x418(%rbp), %rax
movups 0x40(%rax), %xmm0
movaps %xmm0, -0x430(%rbp)
movups (%rax), %xmm0
movups 0x10(%rax), %xmm1
movups 0x20(%rax), %xmm2
movups 0x30(%rax), %xmm3
movaps %xmm3, -0x440(%rbp)
movaps %xmm2, -0x450(%rbp)
movaps %xmm1, -0x460(%rbp)
movaps %xmm0, -0x470(%rbp)
leaq 0x1147c(%rip), %rsi     # 0x132d3
leaq -0x470(%rbp), %rdi
callq 0xb280
movl %eax, %ecx
movl %ecx, -0x4b8(%rbp)
subl $0x1, %eax
je 0x1e8c
jmp 0x1e72
movl -0x4b8(%rbp), %eax
subl $0x4, %eax
je 0x1ea7
jmp 0x1e7f
movl -0x4b8(%rbp), %eax
subl $0x8, %eax
je 0x1ec2
jmp 0x1edd
movl -0x410(%rbp), %edi
callq 0xe4c0
movq %rax, %rdi
movl -0x41c(%rbp), %esi
callq 0xde30
jmp 0x1ee9
movl -0x410(%rbp), %edi
callq 0xe4c0
movq %rax, %rdi
movl -0x41c(%rbp), %esi
callq 0xde90
jmp 0x1ee9
movl -0x410(%rbp), %edi
callq 0xe390
movq %rax, %rdi
movl -0x41c(%rbp), %esi
callq 0xdef0
jmp 0x1ee9
leaq 0x11411(%rip), %rdi     # 0x132f5
callq 0xb1f0
jmp 0x1eeb
movl -0x410(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x410(%rbp)
jmp 0x1dc3
movq -0x10(%rbp), %rax
cmpl $0x0, 0x464(%rax)
je 0x1f5f
movq -0x8(%rbp), %rdi
callq 0x12b0
movl %eax, -0x474(%rbp)
xorl %ecx, %ecx
subl -0x40c(%rbp), %ecx
addl $0x8, %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x48(%rax)
xorl %ecx, %ecx
subl -0x40c(%rbp), %ecx
movq -0x8(%rbp), %rax
movl %ecx, 0x4c(%rax)
movq -0x8(%rbp), %rax
movl 0x48(%rax), %edi
movl -0x474(%rbp), %edx
movl $0x1, %esi
callq 0xe2b0
movq -0x8(%rbp), %rax
movl 0x4c(%rax), %edi
callq 0xe1c0
leaq -0x3a0(%rbp), %rdi
callq 0x21d0
movq %rax, -0x488(%rbp)
movq %rdx, -0x480(%rbp)
callq 0xccc0
movq %rax, -0x490(%rbp)
movl $0x0, -0x494(%rbp)
movl -0x494(%rbp), %eax
cmpl -0x488(%rbp), %eax
jge 0x205a
movq -0x480(%rbp), %rax
movslq -0x494(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0x4a0(%rbp)
movq -0x4a0(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x4bc(%rbp)
subl $0x2, %eax
jb 0x1fdd
jmp 0x1fd0
movl -0x4bc(%rbp), %eax
subl $0x2, %eax
je 0x1fdf
jmp 0x2044
jmp 0x2046
movl $0x1, %edi
movl $0x18, %esi
callq 0x10b0
movq %rax, -0x4a8(%rbp)
movq -0x8(%rbp), %rdi
callq 0x12b0
movl %eax, %ecx
movq -0x4a8(%rbp), %rax
movl %ecx, (%rax)
movq -0x4a8(%rbp), %rax
movq -0x4a0(%rbp), %rcx
movq (%rcx), %rdx
movq %rdx, 0x8(%rax)
movq 0x8(%rcx), %rcx
movq %rcx, 0x10(%rax)
movq -0x490(%rbp), %rdi
movq -0x4a0(%rbp), %rax
movq 0x8(%rax), %rsi
movq -0x4a8(%rbp), %rdx
callq 0xcb50
jmp 0x2046
movl -0x494(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x494(%rbp)
jmp 0x1f8f
movq -0x490(%rbp), %rcx
movq -0x8(%rbp), %rax
movq %rcx, 0x38(%rax)
movq -0x8(%rbp), %rdi
leaq -0x3a0(%rbp), %rsi
callq 0x12d0
cmpl $0x7, -0x400(%rbp)
jne 0x20a2
movq -0x8(%rbp), %rax
cmpl $-0x1, 0x4(%rax)
je 0x2098
movq -0x8(%rbp), %rax
movl 0x4(%rax), %edi
callq 0xd6f0
callq 0xd160
jmp 0x21c4
movq -0x8(%rbp), %rax
cmpl $-0x1, 0x4(%rax)
jne 0x20b8
leaq 0x1126a(%rip), %rdi     # 0x1331d
callq 0xb150
leaq -0x400(%rbp), %rdi
callq 0xb250
cmpl $0x0, %eax
je 0x2155
movq -0x10(%rbp), %rax
movl 0x458(%rax), %eax
movl %eax, -0x4ac(%rbp)
movq -0x10(%rbp), %rax
movl 0x45c(%rax), %eax
movl %eax, -0x4b0(%rbp)
movq -0x10(%rbp), %rax
cmpl $0x0, 0x464(%rax)
je 0x2106
leaq 0x11253(%rip), %rdi     # 0x13354
callq 0xb1f0
cmpl $0x0, -0x4ac(%rbp)
jne 0x2123
movl -0x4b0(%rbp), %edi
movq -0x8(%rbp), %rax
movl 0x4(%rax), %esi
callq 0xcfb0
jmp 0x2153
movq -0x8(%rbp), %rax
movl 0x4(%rax), %edi
callq 0xd6f0
movq -0x10(%rbp), %rax
movl 0x460(%rax), %esi
movl $0x8, %edi
callq 0xd260
movl -0x4b0(%rbp), %edi
callq 0xe120
callq 0xd160
jmp 0x21c4
movq -0x10(%rbp), %rax
cmpl $0x0, 0x464(%rax)
je 0x21a1
movq -0x8(%rbp), %rdi
callq 0x12b0
movl %eax, -0x4b4(%rbp)
leaq -0x400(%rbp), %rdi
leaq 0x11858(%rip), %rsi     # 0x139d7
callq 0xb280
movl %eax, %edi
movq -0x8(%rbp), %rax
movl 0x4(%rax), %esi
movq -0x8(%rbp), %rax
movl 0x4c(%rax), %edx
movl -0x4b4(%rbp), %ecx
callq 0xe210
jmp 0x21c2
leaq -0x400(%rbp), %rdi
leaq 0x11828(%rip), %rsi     # 0x139d7
callq 0xb280
movl %eax, %edi
movq -0x8(%rbp), %rax
movl 0x4(%rax), %esi
callq 0xcf40
jmp 0x21c4
addq $0x4c0, %rsp            # imm = 0x4C0
popq %rbp
retq
nopl (%rax)