// File: 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
movq %rsp, %rbp
subq $0x90, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x10(%rbp), %rax
addq $0x18, %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rdi
callq 0x115b0
movq %rax, -0x38(%rbp)
movq -0x30(%rbp), %rdi
callq 0x115e0
movq %rax, -0x40(%rbp)
leaq -0x38(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x11610
testb $0x1, %al
jne 0x28183
jmp 0x282ce
leaq -0x38(%rbp), %rdi
callq 0x11650
movq -0x80(%rbp), %rdi
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movl (%rax), %esi
callq 0xea90
movq %rax, -0x50(%rbp)
movq -0x50(%rbp), %rax
testb $0x1, 0x60(%rax)
jne 0x281b2
jmp 0x282c0
movq -0x50(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, -0x84(%rbp)
subl $0x8, %eax
je 0x281d6
jmp 0x281c6
movl -0x84(%rbp), %eax
addl $-0xd, %eax
subl $0x2, %eax
ja 0x281dc
jmp 0x281d6
movb $0x0, -0x51(%rbp)
jmp 0x281e0
movb $0x1, -0x51(%rbp)
testb $0x1, -0x51(%rbp)
jne 0x281eb
jmp 0x282c0
movq -0x20(%rbp), %rdi
movq -0x48(%rbp), %rsi
addq $0x4, %rsi
callq 0x31950
movq %rax, -0x60(%rbp)
movq -0x20(%rbp), %rdi
callq 0x319b0
movq %rax, -0x68(%rbp)
leaq -0x60(%rbp), %rdi
leaq -0x68(%rbp), %rsi
callq 0x31980
testb $0x1, %al
jne 0x28220
jmp 0x28225
jmp 0x282c0
movq -0x28(%rbp), %rdi
movq -0x48(%rbp), %rsi
addq $0x4, %rsi
callq 0x31950
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x28(%rbp), %rdi
callq 0x319b0
movq %rax, -0x78(%rbp)
leaq -0x60(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x31980
testb $0x1, %al
jne 0x28262
jmp 0x28271
movq -0x48(%rbp), %rax
movl 0x8(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x8(%rax)
jmp 0x282c0
movq -0x18(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x10(%rbp), %rax
movl 0x60(%rax), %eax
movl %eax, -0x88(%rbp)
leaq -0x60(%rbp), %rdi
callq 0x319e0
movq -0x90(%rbp), %rdi
movl -0x88(%rbp), %esi
movq %rax, %rdx
addq $0x8, %rdx
callq 0x282e0
testb $0x1, %al
jne 0x282b1
jmp 0x282be
movq -0x48(%rbp), %rax
movl 0x8(%rax), %ecx
addl $0x1, %ecx
movl %ecx, 0x8(%rax)
jmp 0x282c0
leaq -0x38(%rbp), %rdi
callq 0x11710
jmp 0x2816d
addq $0x90, %rsp
popq %rbp
retq
nopw (%rax,%rax)