// File: rossy[P]crossc/SPIRV-Cross/spirv_cross.cpp
// Function: spirv_cross::Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op, unsigned int const*, unsigned int)
bool Compiler::AnalyzeVariableScopeAccessHandler::handle(spv::Op op, const uint32_t *args, uint32_t length)
{
	// Keep track of the types of temporaries, so we can hoist them out as necessary.
	uint32_t result_type, result_id;
	if (compiler.instruction_to_result_type(result_type, result_id, op, args, length))
		result_id_to_type[result_id] = result_type;

	switch (op)
	{
	case OpStore:
	{
		if (length < 2)
			return false;

		uint32_t ptr = args[0];
		auto *var = compiler.maybe_get_backing_variable(ptr);

		// If we store through an access chain, we have a partial write.
		if (var)
		{
			accessed_variables_to_block[var->self].insert(current_block->self);
			if (var->self == ptr)
				complete_write_variables_to_block[var->self].insert(current_block->self);
			else
				partial_write_variables_to_block[var->self].insert(current_block->self);
		}

		// Might try to store a Phi variable here.
		notify_variable_access(args[1], current_block->self);
		break;
	}

	case OpAccessChain:
	case OpInBoundsAccessChain:
	{
		if (length < 3)
			return false;

		uint32_t ptr = args[2];
		auto *var = compiler.maybe_get<SPIRVariable>(ptr);
		if (var)
			accessed_variables_to_block[var->self].insert(current_block->self);

		for (uint32_t i = 3; i < length; i++)
			notify_variable_access(args[i], current_block->self);

		// The result of an access chain is a fixed expression and is not really considered a temporary.
		auto &e = compiler.set<SPIRExpression>(args[1], "", args[0], true);
		auto *backing_variable = compiler.maybe_get_backing_variable(ptr);
		e.loaded_from = backing_variable ? backing_variable->self : 0;

		// Other backends might use SPIRAccessChain for this later.
		compiler.ir.ids[args[1]].set_allow_type_rewrite();
		break;
	}

	case OpCopyMemory:
	{
		if (length < 2)
			return false;

		uint32_t lhs = args[0];
		uint32_t rhs = args[1];
		auto *var = compiler.maybe_get_backing_variable(lhs);

		// If we store through an access chain, we have a partial write.
		if (var)
		{
			accessed_variables_to_block[var->self].insert(current_block->self);
			if (var->self == lhs)
				complete_write_variables_to_block[var->self].insert(current_block->self);
			else
				partial_write_variables_to_block[var->self].insert(current_block->self);
		}

		var = compiler.maybe_get_backing_variable(rhs);
		if (var)
			accessed_variables_to_block[var->self].insert(current_block->self);
		break;
	}

	case OpCopyObject:
	{
		if (length < 3)
			return false;

		auto *var = compiler.maybe_get_backing_variable(args[2]);
		if (var)
			accessed_variables_to_block[var->self].insert(current_block->self);

		// Might try to copy a Phi variable here.
		notify_variable_access(args[2], current_block->self);
		break;
	}

	case OpLoad:
	{
		if (length < 3)
			return false;
		uint32_t ptr = args[2];
		auto *var = compiler.maybe_get_backing_variable(ptr);
		if (var)
			accessed_variables_to_block[var->self].insert(current_block->self);

		// Loaded value is a temporary.
		notify_variable_access(args[1], current_block->self);
		break;
	}

	case OpFunctionCall:
	{
		if (length < 3)
			return false;

		length -= 3;
		args += 3;

		for (uint32_t i = 0; i < length; i++)
		{
			auto *var = compiler.maybe_get_backing_variable(args[i]);
			if (var)
			{
				accessed_variables_to_block[var->self].insert(current_block->self);
				// Assume we can get partial writes to this variable.
				partial_write_variables_to_block[var->self].insert(current_block->self);
			}

			// Cannot easily prove if argument we pass to a function is completely written.
			// Usually, functions write to a dummy variable,
			// which is then copied to in full to the real argument.

			// Might try to copy a Phi variable here.
			notify_variable_access(args[i], current_block->self);
		}

		// Return value may be a temporary.
		notify_variable_access(args[1], current_block->self);
		break;
	}

	case OpExtInst:
	{
		for (uint32_t i = 4; i < length; i++)
			notify_variable_access(args[i], current_block->self);
		notify_variable_access(args[1], current_block->self);
		break;
	}

	case OpArrayLength:
		// Uses literals, but cannot be a phi variable, so ignore.
		break;

		// Atomics shouldn't be able to access function-local variables.
		// Some GLSL builtins access a pointer.

	case OpCompositeInsert:
	case OpVectorShuffle:
		// Specialize for opcode which contains literals.
		for (uint32_t i = 1; i < 4; i++)
			notify_variable_access(args[i], current_block->self);
		break;

	case OpCompositeExtract:
		// Specialize for opcode which contains literals.
		for (uint32_t i = 1; i < 3; i++)
			notify_variable_access(args[i], current_block->self);
		break;

	default:
	{
		// Rather dirty way of figuring out where Phi variables are used.
		// As long as only IDs are used, we can scan through instructions and try to find any evidence that
		// the ID of a variable has been used.
		// There are potential false positives here where a literal is used in-place of an ID,
		// but worst case, it does not affect the correctness of the compile.
		// Exhaustive analysis would be better here, but it's not worth it for now.
		for (uint32_t i = 0; i < length; i++)
			notify_variable_access(args[i], current_block->self);
		break;
	}
	}
	return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x190, %rsp            # imm = 0x190
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movq %rdx, -0x20(%rbp)
movl %ecx, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x178(%rbp)
movq 0x8(%rax), %rdi
movl -0x14(%rbp), %ecx
movq -0x20(%rbp), %r8
movl -0x24(%rbp), %r9d
leaq -0x28(%rbp), %rsi
leaq -0x2c(%rbp), %rdx
callq 0x291b0
testb $0x1, %al
jne 0x28926
jmp 0x2894e
movq -0x178(%rbp), %rdi
movl -0x28(%rbp), %eax
movl %eax, -0x17c(%rbp)
addq $0x88, %rdi
leaq -0x2c(%rbp), %rsi
callq 0x30850
movl -0x17c(%rbp), %ecx
movl %ecx, (%rax)
movl -0x14(%rbp), %eax
addl $-0xc, %eax
movl %eax, %ecx
movq %rcx, -0x188(%rbp)
subl $0x47, %eax
ja 0x29147
movq -0x188(%rbp), %rax
leaq 0x11669c(%rip), %rcx    # 0x13f010
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
cmpl $0x2, -0x24(%rbp)
jae 0x2898c
movb $0x0, -0x1(%rbp)
jmp 0x29196
movq -0x178(%rbp), %rax
movq -0x20(%rbp), %rcx
movl (%rcx), %ecx
movl %ecx, -0x30(%rbp)
movq 0x8(%rax), %rdi
movl -0x30(%rbp), %esi
callq 0x1fa90
movq %rax, -0x38(%rbp)
cmpq $0x0, -0x38(%rbp)
je 0x28a78
movq -0x178(%rbp), %rdi
addq $0x18, %rdi
movq -0x38(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0x48(%rbp)
movb %dl, -0x40(%rbp)
movq -0x38(%rbp), %rax
movl 0x8(%rax), %eax
cmpl -0x30(%rbp), %eax
jne 0x28a3a
movq -0x178(%rbp), %rdi
addq $0xc0, %rdi
movq -0x38(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0x58(%rbp)
movb %dl, -0x50(%rbp)
jmp 0x28a76
movq -0x178(%rbp), %rdi
addq $0xf8, %rdi
movq -0x38(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0x68(%rbp)
movb %dl, -0x60(%rbp)
jmp 0x28a78
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl 0x4(%rax), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
jmp 0x29192
cmpl $0x3, -0x24(%rbp)
jae 0x28aa9
movb $0x0, -0x1(%rbp)
jmp 0x29196
movq -0x178(%rbp), %rax
movq -0x20(%rbp), %rcx
movl 0x8(%rcx), %ecx
movl %ecx, -0x6c(%rbp)
movq 0x8(%rax), %rdi
movl -0x6c(%rbp), %esi
callq 0x116b0
movq %rax, -0x78(%rbp)
cmpq $0x0, -0x78(%rbp)
je 0x28b0d
movq -0x178(%rbp), %rdi
addq $0x18, %rdi
movq -0x78(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0x88(%rbp)
movb %dl, -0x80(%rbp)
movl $0x3, -0x8c(%rbp)
movl -0x8c(%rbp), %eax
cmpl -0x24(%rbp), %eax
jae 0x28b56
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl -0x8c(%rbp), %ecx
movl (%rax,%rcx,4), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x8c(%rbp)
jmp 0x28b17
movq -0x178(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x20(%rbp), %rax
movl 0x4(%rax), %esi
movq -0x20(%rbp), %rcx
movb $0x1, -0x99(%rbp)
leaq 0x115d24(%rip), %rdx    # 0x13e89e
leaq -0x99(%rbp), %r8
callq 0x31aa0
movq %rax, %rcx
movq -0x178(%rbp), %rax
movq %rcx, -0x98(%rbp)
movq 0x8(%rax), %rdi
movl -0x6c(%rbp), %esi
callq 0x1fa90
movq %rax, -0xa8(%rbp)
cmpq $0x0, -0xa8(%rbp)
je 0x28bc6
movq -0xa8(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, -0x18c(%rbp)
jmp 0x28bd0
xorl %eax, %eax
movl %eax, -0x18c(%rbp)
jmp 0x28bd0
movq -0x178(%rbp), %rax
movl -0x18c(%rbp), %edx
movq -0x98(%rbp), %rcx
movl %edx, 0x34(%rcx)
movq 0x8(%rax), %rdi
addq $0x8, %rdi
addq $0x18, %rdi
movq -0x20(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, %esi
callq 0xbdb0
movq %rax, %rdi
callq 0x30f50
jmp 0x29192
cmpl $0x2, -0x24(%rbp)
jae 0x28c1d
movb $0x0, -0x1(%rbp)
jmp 0x29196
movq -0x178(%rbp), %rax
movq -0x20(%rbp), %rcx
movl (%rcx), %ecx
movl %ecx, -0xac(%rbp)
movq -0x20(%rbp), %rcx
movl 0x4(%rcx), %ecx
movl %ecx, -0xb0(%rbp)
movq 0x8(%rax), %rdi
movl -0xac(%rbp), %esi
callq 0x1fa90
movq %rax, -0xb8(%rbp)
cmpq $0x0, -0xb8(%rbp)
je 0x28d43
movq -0x178(%rbp), %rdi
addq $0x18, %rdi
movq -0xb8(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0xc8(%rbp)
movb %dl, -0xc0(%rbp)
movq -0xb8(%rbp), %rax
movl 0x8(%rax), %eax
cmpl -0xac(%rbp), %eax
jne 0x28cfc
movq -0x178(%rbp), %rdi
addq $0xc0, %rdi
movq -0xb8(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0xd8(%rbp)
movb %dl, -0xd0(%rbp)
jmp 0x28d41
movq -0x178(%rbp), %rdi
addq $0xf8, %rdi
movq -0xb8(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0xe8(%rbp)
movb %dl, -0xe0(%rbp)
jmp 0x28d43
movq -0x178(%rbp), %rax
movq 0x8(%rax), %rdi
movl -0xb0(%rbp), %esi
callq 0x1fa90
movq %rax, -0xb8(%rbp)
cmpq $0x0, -0xb8(%rbp)
je 0x28dac
movq -0x178(%rbp), %rdi
addq $0x18, %rdi
movq -0xb8(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0xf8(%rbp)
movb %dl, -0xf0(%rbp)
jmp 0x29192
cmpl $0x3, -0x24(%rbp)
jae 0x28dc0
movb $0x0, -0x1(%rbp)
jmp 0x29196
movq -0x178(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x20(%rbp), %rax
movl 0x8(%rax), %esi
callq 0x1fa90
movq %rax, -0x100(%rbp)
cmpq $0x0, -0x100(%rbp)
je 0x28e2a
movq -0x178(%rbp), %rdi
addq $0x18, %rdi
movq -0x100(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0x110(%rbp)
movb %dl, -0x108(%rbp)
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl 0x8(%rax), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
jmp 0x29192
cmpl $0x3, -0x24(%rbp)
jae 0x28e5b
movb $0x0, -0x1(%rbp)
jmp 0x29196
movq -0x178(%rbp), %rax
movq -0x20(%rbp), %rcx
movl 0x8(%rcx), %ecx
movl %ecx, -0x114(%rbp)
movq 0x8(%rax), %rdi
movl -0x114(%rbp), %esi
callq 0x1fa90
movq %rax, -0x120(%rbp)
cmpq $0x0, -0x120(%rbp)
je 0x28ed1
movq -0x178(%rbp), %rdi
addq $0x18, %rdi
movq -0x120(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0x130(%rbp)
movb %dl, -0x128(%rbp)
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl 0x4(%rax), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
jmp 0x29192
cmpl $0x3, -0x24(%rbp)
jae 0x28f02
movb $0x0, -0x1(%rbp)
jmp 0x29196
movl -0x24(%rbp), %eax
subl $0x3, %eax
movl %eax, -0x24(%rbp)
movq -0x20(%rbp), %rax
addq $0xc, %rax
movq %rax, -0x20(%rbp)
movl $0x0, -0x134(%rbp)
movl -0x134(%rbp), %eax
cmpl -0x24(%rbp), %eax
jae 0x29020
movq -0x178(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x20(%rbp), %rax
movl -0x134(%rbp), %ecx
movl (%rax,%rcx,4), %esi
callq 0x1fa90
movq %rax, -0x140(%rbp)
cmpq $0x0, -0x140(%rbp)
je 0x28fe9
movq -0x178(%rbp), %rdi
addq $0x18, %rdi
movq -0x140(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq -0x178(%rbp), %rdi
movq %rax, -0x150(%rbp)
movb %dl, -0x148(%rbp)
addq $0xf8, %rdi
movq -0x140(%rbp), %rsi
addq $0x8, %rsi
callq 0x31a50
movq %rax, %rdi
movq -0x178(%rbp), %rax
movq 0x130(%rax), %rsi
addq $0x8, %rsi
callq 0x2e890
movq %rax, -0x160(%rbp)
movb %dl, -0x158(%rbp)
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl -0x134(%rbp), %ecx
movl (%rax,%rcx,4), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
movl -0x134(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x134(%rbp)
jmp 0x28f21
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl 0x4(%rax), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
jmp 0x29192
movl $0x4, -0x164(%rbp)
movl -0x164(%rbp), %eax
cmpl -0x24(%rbp), %eax
jae 0x2908b
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl -0x164(%rbp), %ecx
movl (%rax,%rcx,4), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
movl -0x164(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x164(%rbp)
jmp 0x2904c
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl 0x4(%rax), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
jmp 0x29192
jmp 0x29192
movl $0x1, -0x168(%rbp)
cmpl $0x4, -0x168(%rbp)
jae 0x290f9
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl -0x168(%rbp), %ecx
movl (%rax,%rcx,4), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
movl -0x168(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x168(%rbp)
jmp 0x290bc
jmp 0x29192
movl $0x1, -0x16c(%rbp)
cmpl $0x3, -0x16c(%rbp)
jae 0x29145
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl -0x16c(%rbp), %ecx
movl (%rax,%rcx,4), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
movl -0x16c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x16c(%rbp)
jmp 0x29108
jmp 0x29192
movl $0x0, -0x170(%rbp)
movl -0x170(%rbp), %eax
cmpl -0x24(%rbp), %eax
jae 0x29190
movq -0x178(%rbp), %rdi
movq -0x20(%rbp), %rax
movl -0x170(%rbp), %ecx
movl (%rax,%rcx,4), %esi
movq 0x130(%rdi), %rax
movl 0x8(%rax), %edx
callq 0x28600
movl -0x170(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x170(%rbp)
jmp 0x29151
jmp 0x29192
movb $0x1, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x190, %rsp            # imm = 0x190
popq %rbp
retq
nopw %cs:(%rax,%rax)