// File: /workspace/github_cpp_makefile_star2_O2/rossy[P]crossc/SPIRV-Cross/spirv_msl.cpp
// Function: spirv_cross::CompilerMSL::extract_global_variables_from_function(unsigned int, std::set<unsigned int, std::less<unsigned int>, std::allocator<unsigned int>>&, std::unordered_set<unsigned int, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<unsigned int>>&, std::unordered_set<unsigned int, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<unsigned int>>&)
void CompilerMSL::extract_global_variables_from_function(uint32_t func_id, std::set<uint32_t> &added_arg_ids,
                                                         unordered_set<uint32_t> &global_var_ids,
                                                         unordered_set<uint32_t> &processed_func_ids)
{
	// Avoid processing a function more than once
	if (processed_func_ids.find(func_id) != processed_func_ids.end())
	{
		// Return function global variables
		added_arg_ids = function_global_vars[func_id];
		return;
	}

	processed_func_ids.insert(func_id);

	auto &func = get<SPIRFunction>(func_id);

	// Recursively establish global args added to functions on which we depend.
	for (auto block : func.blocks)
	{
		auto &b = get<SPIRBlock>(block);
		for (auto &i : b.ops)
		{
			auto ops = stream(i);
			auto op = static_cast<Op>(i.op);

			switch (op)
			{
			case OpLoad:
			case OpInBoundsAccessChain:
			case OpAccessChain:
			{
				uint32_t base_id = ops[2];
				if (global_var_ids.find(base_id) != global_var_ids.end())
					added_arg_ids.insert(base_id);

				auto &type = get<SPIRType>(ops[0]);
				if (type.basetype == SPIRType::Image && type.image.dim == DimSubpassData)
				{
					// Implicitly reads gl_FragCoord.
					assert(builtin_frag_coord_id != 0);
					added_arg_ids.insert(builtin_frag_coord_id);
				}

				if (msl_options.swizzle_texture_samples && has_sampled_images && is_sampled_image_type(type))
				{
					// Implicitly reads spvAuxBuffer.
					assert(aux_buffer_id != 0);
					added_arg_ids.insert(aux_buffer_id);
				}

				break;
			}

			case OpFunctionCall:
			{
				// First see if any of the function call args are globals
				for (uint32_t arg_idx = 3; arg_idx < i.length; arg_idx++)
				{
					uint32_t arg_id = ops[arg_idx];
					if (global_var_ids.find(arg_id) != global_var_ids.end())
						added_arg_ids.insert(arg_id);
				}

				// Then recurse into the function itself to extract globals used internally in the function
				uint32_t inner_func_id = ops[2];
				std::set<uint32_t> inner_func_args;
				extract_global_variables_from_function(inner_func_id, inner_func_args, global_var_ids,
				                                       processed_func_ids);
				added_arg_ids.insert(inner_func_args.begin(), inner_func_args.end());
				break;
			}

			case OpStore:
			{
				uint32_t base_id = ops[0];
				if (global_var_ids.find(base_id) != global_var_ids.end())
					added_arg_ids.insert(base_id);
				break;
			}

			default:
				break;
			}

			// TODO: Add all other operations which can affect memory.
			// We should consider a more unified system here to reduce boiler-plate.
			// This kind of analysis is done in several places ...
		}
	}

	function_global_vars[func_id] = added_arg_ids;

	// Add the global variables as arguments to the function
	if (func_id != ir.default_entry_point)
	{
		for (uint32_t arg_id : added_arg_ids)
		{
			auto &var = get<SPIRVariable>(arg_id);
			uint32_t type_id = var.basetype;
			auto *p_type = &get<SPIRType>(type_id);

			if (is_builtin_variable(var) && p_type->basetype == SPIRType::Struct)
			{
				// Get the non-pointer type
				type_id = get_non_pointer_type_id(type_id);
				p_type = &get<SPIRType>(type_id);

				uint32_t mbr_idx = 0;
				for (auto &mbr_type_id : p_type->member_types)
				{
					BuiltIn builtin;
					bool is_builtin = is_member_builtin(*p_type, mbr_idx, &builtin);
					if (is_builtin && has_active_builtin(builtin, var.storage))
					{
						// Add a arg variable with the same type and decorations as the member
						uint32_t next_ids = ir.increase_bound_by(2);
						uint32_t ptr_type_id = next_ids + 0;
						uint32_t var_id = next_ids + 1;

						// Make sure we have an actual pointer type,
						// so that we will get the appropriate address space when declaring these builtins.
						auto &ptr = set<SPIRType>(ptr_type_id, get<SPIRType>(mbr_type_id));
						ptr.self = mbr_type_id;
						ptr.storage = var.storage;
						ptr.pointer = true;

						func.add_parameter(mbr_type_id, var_id, true);
						set<SPIRVariable>(var_id, ptr_type_id, StorageClassFunction);
						ir.meta[var_id].decoration = ir.meta[type_id].members[mbr_idx];
					}
					mbr_idx++;
				}
			}
			else
			{
				uint32_t next_id = ir.increase_bound_by(1);
				func.add_parameter(type_id, next_id, true);
				set<SPIRVariable>(next_id, type_id, StorageClassFunction, 0, arg_id);

				// Ensure the existing variable has a valid name and the new variable has all the same meta info
				set_name(arg_id, ensure_valid_name(to_name(arg_id), "v"));
				ir.meta[next_id] = ir.meta[arg_id];
			}
		}
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xc8, %rsp
movq %r8, %r15
movq %rcx, %r12
movq %rdx, %rbx
movq %rdi, %r14
leaq 0xc(%rsp), %rax
movl %esi, (%rax)
movq %r8, %rdi
movq %rax, %rsi
callq 0x1c722
testq %rax, %rax
je 0x73062
addq $0x788, %r14            # imm = 0x788
leaq 0xc(%rsp), %rsi
movq %r14, %rdi
callq 0x836cc
movq %rbx, %rdi
movq %rax, %rsi
callq 0x8297c
jmp 0x732aa
movq %r15, %rdi
leaq 0xc(%rsp), %r15
movq %rdi, 0x18(%rsp)
movq %r15, %rsi
callq 0x1af30
movl (%r15), %esi
movq %r14, %rdi
callq 0xa048
movq 0x68(%rax), %rcx
movq %rax, 0x40(%rsp)
movq 0x70(%rax), %rax
movq %rax, 0x78(%rsp)
leaq 0x7c0(%r14), %rax
movq %rax, 0x30(%rsp)
leaq 0x7c8(%r14), %rax
movq %rax, 0x20(%rsp)
leaq 0x48(%rsp), %r15
movq %r14, 0x80(%rsp)
cmpq 0x78(%rsp), %rcx
je 0x7327f
movq %rcx, 0x28(%rsp)
movl (%rcx), %esi
movq %r14, %rdi
callq 0x6bf0
movq 0x38(%rax), %r13
movq 0x40(%rax), %rax
movq %rax, 0x10(%rsp)
cmpq 0x10(%rsp), %r13
je 0x73271
movq %r14, %rdi
movq %r13, %rsi
callq 0x16f1e
movq %rax, %rbp
movzwl (%r13), %eax
addl $-0x39, %eax
cmpl $0x9, %eax
ja 0x73268
leaq 0x27797(%rip), %rcx     # 0x9a8a8
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movl 0x8(%rbp), %eax
movl %eax, 0x48(%rsp)
movq %r12, %rdi
movq %r15, %rsi
callq 0x1c722
testq %rax, %rax
je 0x7313c
movq %rbx, %rdi
movq %r15, %rsi
callq 0x83a26
movl (%rbp), %esi
movq %r14, %rdi
callq 0x90a4
movq %rax, %rbp
cmpl $0xd, 0xc(%rax)
jne 0x7316f
cmpl $0x6, 0x84(%rbp)
jne 0x7316f
movq 0x30(%rsp), %rsi
cmpl $0x0, (%rsi)
je 0x7353a
movq %rbx, %rdi
callq 0x83a26
cmpb $0x1, 0x7df(%r14)
jne 0x73268
cmpb $0x1, 0x934(%r14)
jne 0x73268
movq %r14, %rdi
movq %rbp, %rsi
callq 0x11ea2
testb %al, %al
je 0x73268
movq 0x20(%rsp), %rsi
cmpl $0x0, (%rsi)
je 0x73559
movq %rbx, %rdi
jmp 0x731d2
movl (%rbp), %eax
movl %eax, 0x48(%rsp)
movq %r12, %rdi
movq %r15, %rsi
callq 0x1c722
testq %rax, %rax
je 0x73268
movq %rbx, %rdi
movq %r15, %rsi
callq 0x83a26
jmp 0x73268
pushq $0x3
popq %r14
movl 0x8(%r13), %eax
cmpq %rax, %r14
jae 0x73212
movl (%rbp,%r14,4), %eax
movl %eax, 0x48(%rsp)
movq %r12, %rdi
movq %r15, %rsi
callq 0x1c722
testq %rax, %rax
je 0x7320d
movq %rbx, %rdi
movq %r15, %rsi
callq 0x83a26
incq %r14
jmp 0x731e0
movl 0x8(%rbp), %esi
andl $0x0, 0x50(%rsp)
andq $0x0, 0x58(%rsp)
leaq 0x50(%rsp), %rbp
movq %rbp, 0x60(%rsp)
movq %rbp, 0x68(%rsp)
andq $0x0, 0x70(%rsp)
movq 0x80(%rsp), %r14
movq %r14, %rdi
movq %r15, %rdx
movq %r12, %rcx
movq 0x18(%rsp), %r8
callq 0x7300a
movq 0x60(%rsp), %rsi
movq %rbx, %rdi
movq %rbp, %rdx
callq 0x83b24
movq %r15, %rdi
callq 0x82924
addq $0xc, %r13
jmp 0x730e0
movq 0x28(%rsp), %rcx
addq $0x4, %rcx
jmp 0x730b9
leaq 0x788(%r14), %rdi
leaq 0xc(%rsp), %r15
movq %r15, %rsi
callq 0x836cc
movq %rax, %rdi
movq %rbx, %rsi
callq 0x8297c
movl (%r15), %eax
cmpl 0x108(%r14), %eax
jne 0x732bc
addq $0xc8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x8(%r14), %rax
movq %rax, 0x18(%rsp)
movq 0x18(%rbx), %rax
addq $0x8, %rbx
leaq 0x48(%rsp), %r13
cmpq %rbx, %rax
je 0x732aa
movq %rax, 0x20(%rsp)
movl 0x20(%rax), %esi
movl %esi, 0x8(%rsp)
movq %r14, %rdi
callq 0x9c0e
movq %rax, %r15
movl 0xc(%rax), %esi
movl %esi, (%rsp)
movq %r14, %rdi
callq 0x90a4
movq %rax, %r12
movq %r14, %rdi
movq %r15, %rsi
callq 0x10c60
testb %al, %al
je 0x73442
cmpl $0xc, 0xc(%r12)
jne 0x73442
movl (%rsp), %esi
movq %r14, %rdi
callq 0x11e00
movl %eax, (%rsp)
movq %r14, %rdi
movl %eax, %esi
callq 0x90a4
movq 0x68(%rax), %rbp
movq %rax, 0x30(%rsp)
movq 0x70(%rax), %rax
movq %rax, 0x10(%rsp)
xorl %r12d, %r12d
movq %r15, 0x28(%rsp)
cmpq 0x10(%rsp), %rbp
je 0x7352b
movq %r14, %rdi
movq 0x30(%rsp), %rsi
movl %r12d, %edx
movq %r13, %rcx
callq 0x10cdc
testb %al, %al
je 0x73436
movl 0x48(%rsp), %esi
movl 0x10(%r15), %edx
movq %r14, %rdi
callq 0x160ec
testb %al, %al
je 0x73436
movq 0x18(%rsp), %rdi
pushq $0x2
popq %rsi
callq 0x202bc
movl %eax, %r15d
movl %eax, 0x4(%rsp)
leal 0x1(%r15), %r13d
movl (%rbp), %esi
movq %r14, %rdi
callq 0x90a4
movq %r14, %rdi
movl %r15d, %esi
movq 0x28(%rsp), %r15
movq %rax, %rdx
callq 0x63e9e
movl (%rbp), %esi
movl %esi, 0x8(%rax)
movl 0x10(%r15), %ecx
movl %ecx, 0x64(%rax)
movb $0x1, 0x60(%rax)
movq 0x40(%rsp), %rdi
movl %r13d, %edx
pushq $0x1
popq %rcx
callq 0x7fbb4
movl $0x7, 0x3c(%rsp)
movq %r14, %rdi
movl %r13d, %esi
leaq 0x4(%rsp), %rdx
leaq 0x3c(%rsp), %rcx
callq 0x63ec6
movl (%rsp), %eax
movq 0x38(%r14), %rcx
imulq $0x148, %rax, %rax      # imm = 0x148
movl %r12d, %edx
imulq $0xd0, %rdx, %rsi
addq 0xd0(%rcx,%rax), %rsi
imulq $0x148, %r13, %rdi      # imm = 0x148
leaq 0x48(%rsp), %r13
addq %rcx, %rdi
callq 0x18ff8
incl %r12d
addq $0x4, %rbp
jmp 0x73350
movq 0x18(%rsp), %rdi
pushq $0x1
popq %r12
movl %r12d, %esi
callq 0x202bc
movl %eax, %ebp
movl (%rsp), %esi
movq 0x40(%rsp), %rdi
movl %eax, %edx
movl %r12d, %ecx
callq 0x7fbb4
movl $0x7, 0x48(%rsp)
andl $0x0, 0x4(%rsp)
movq %r14, %rdi
movl %ebp, 0x10(%rsp)
movl %ebp, %esi
movq %rsp, %rdx
movq %r13, %rcx
leaq 0x4(%rsp), %r8
leaq 0x8(%rsp), %r9
callq 0x7fbdc
movl 0x8(%rsp), %r15d
movq (%r14), %rax
leaq 0xa8(%rsp), %r12
movq %r12, %rdi
movq %r14, %rsi
movl %r15d, %edx
pushq $0x1
popq %rcx
callq *0x38(%rax)
leaq 0x88(%rsp), %rbp
movq %rbp, %rdi
leaq 0x27fc1(%rip), %rsi     # 0x9b484
leaq 0x4(%rsp), %rdx
callq 0x6100
movq %r13, %rdi
movq %r12, %rdx
movq %rbp, %rcx
callq 0x735c0
movq %r14, %rdi
movl %r15d, %esi
movq %r13, %rdx
callq 0x11dda
movq %r13, %rdi
callq 0x6548
leaq 0x88(%rsp), %rdi
callq 0x6548
movq %r12, %rdi
callq 0x6548
movl 0x8(%rsp), %eax
movq 0x38(%r14), %rcx
imulq $0x148, %rax, %rsi      # imm = 0x148
addq %rcx, %rsi
movl 0x10(%rsp), %eax
imulq $0x148, %rax, %rdi      # imm = 0x148
addq %rcx, %rdi
callq 0x18f9c
movq 0x20(%rsp), %rdi
callq 0x62f0
jmp 0x732d2
leaq 0x27e5f(%rip), %rdi     # 0x9b3a0
leaq 0x27e73(%rip), %rsi     # 0x9b3bb
leaq 0x27e86(%rip), %rcx     # 0x9b3d5
movl $0x276, %edx            # imm = 0x276
callq 0x61c0
leaq 0x27f11(%rip), %rdi     # 0x9b471
leaq 0x27e54(%rip), %rsi     # 0x9b3bb
leaq 0x27e67(%rip), %rcx     # 0x9b3d5
movl $0x27d, %edx            # imm = 0x27D
callq 0x61c0
movq %rax, %rbx
jmp 0x7358f
movq %rax, %rbx
jmp 0x7359c
movq %rax, %rbx
leaq 0x48(%rsp), %rdi
callq 0x6548
leaq 0x88(%rsp), %rdi
callq 0x6548
leaq 0xa8(%rsp), %rdi
callq 0x6548
jmp 0x735b8
movq %rax, %rbx
leaq 0x48(%rsp), %rdi
callq 0x82924
movq %rbx, %rdi
callq 0x64b0