// File: /workspace/github_cpp_makefile_star2_O2/rossy[P]crossc/SPIRV-Cross/spirv_cross.cpp
// Function: spirv_cross::Compiler::analyze_parameter_preservation(spirv_cross::SPIRFunction&, spirv_cross::CFG const&, std::unordered_map<unsigned int, std::unordered_set<unsigned int, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<unsigned int>>, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, std::unordered_set<unsigned int, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<unsigned int>>>>> const&, std::unordered_map<unsigned int, std::unordered_set<unsigned int, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<unsigned int>>, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<std::pair<unsigned int const, std::unordered_set<unsigned int, std::hash<unsigned int>, std::equal_to<unsigned int>, std::allocator<unsigned int>>>>> const&)
void Compiler::analyze_parameter_preservation(
    SPIRFunction &entry, const CFG &cfg, const unordered_map<uint32_t, unordered_set<uint32_t>> &variable_to_blocks,
    const unordered_map<uint32_t, unordered_set<uint32_t>> &complete_write_blocks)
{
	for (auto &arg : entry.arguments)
	{
		// Non-pointers are always inputs.
		auto &type = get<SPIRType>(arg.type);
		if (!type.pointer)
			continue;

		// Opaque argument types are always in
		bool potential_preserve;
		switch (type.basetype)
		{
		case SPIRType::Sampler:
		case SPIRType::Image:
		case SPIRType::SampledImage:
		case SPIRType::AtomicCounter:
			potential_preserve = false;
			break;

		default:
			potential_preserve = true;
			break;
		}

		if (!potential_preserve)
			continue;

		auto itr = variable_to_blocks.find(arg.id);
		if (itr == end(variable_to_blocks))
		{
			// Variable is never accessed.
			continue;
		}

		// We have accessed a variable, but there was no complete writes to that variable.
		// We deduce that we must preserve the argument.
		itr = complete_write_blocks.find(arg.id);
		if (itr == end(complete_write_blocks))
		{
			arg.read_count++;
			continue;
		}

		// If there is a path through the CFG where no block completely writes to the variable, the variable will be in an undefined state
		// when the function returns. We therefore need to implicitly preserve the variable in case there are writers in the function.
		// Major case here is if a function is
		// void foo(int &var) { if (cond) var = 10; }
		// Using read/write counts, we will think it's just an out variable, but it really needs to be inout,
		// because if we don't write anything whatever we put into the function must return back to the caller.
		if (exists_unaccessed_path_to_return(cfg, entry.entry_block, itr->second))
			arg.read_count++;
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %r8, 0x8(%rsp)
movq %rcx, 0x10(%rsp)
movq %rdx, (%rsp)
movq %rsi, %r12
movq %rdi, %r13
movq 0x18(%rsi), %r15
movq 0x20(%rsi), %rbx
movl $0xe100, %r14d          # imm = 0xE100
cmpq %rbx, %r15
je 0x14a3b
movl (%r15), %esi
movq %r13, %rdi
callq 0x90a4
cmpb $0x1, 0x60(%rax)
jne 0x149ee
movl 0xc(%rax), %eax
cmpl $0xf, %eax
ja 0x149f4
btl %eax, %r14d
jae 0x149f4
addq $0x14, %r15
jmp 0x149ca
leaq 0x4(%r15), %rbp
movq 0x10(%rsp), %rdi
movq %rbp, %rsi
callq 0x1e5dc
testq %rax, %rax
je 0x149ee
movq 0x8(%rsp), %rdi
movq %rbp, %rsi
callq 0x1e5dc
testq %rax, %rax
je 0x14a35
movl 0x60(%r12), %esi
addq $0x10, %rax
movq (%rsp), %rdi
movq %rax, %rdx
callq 0x14a4a
testb %al, %al
je 0x149ee
incl 0x8(%r15)
jmp 0x149ee
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq