// File: /workspace/github_cpp_makefile_star2_O1/rossy[P]crossc/SPIRV-Cross/spirv_cross.cpp
// Function: spirv_cross::Compiler::analyze_variable_scope(spirv_cross::SPIRFunction&, spirv_cross::Compiler::AnalyzeVariableScopeAccessHandler&)
void Compiler::analyze_variable_scope(SPIRFunction &entry, AnalyzeVariableScopeAccessHandler &handler)
{
	// First, we map out all variable access within a function.
	// Essentially a map of block -> { variables accessed in the basic block }
	traverse_all_reachable_opcodes(entry, handler);

	auto &cfg = *function_cfgs.find(entry.self)->second;

	// Analyze if there are parameters which need to be implicitly preserved with an "in" qualifier.
	analyze_parameter_preservation(entry, cfg, handler.accessed_variables_to_block,
	                               handler.complete_write_variables_to_block);

	unordered_map<uint32_t, uint32_t> potential_loop_variables;

	// For each variable which is statically accessed.
	for (auto &var : handler.accessed_variables_to_block)
	{
		// Only deal with variables which are considered local variables in this function.
		if (find(begin(entry.local_variables), end(entry.local_variables), var.first) == end(entry.local_variables))
			continue;

		DominatorBuilder builder(cfg);
		auto &blocks = var.second;
		auto &type = expression_type(var.first);

		// Figure out which block is dominating all accesses of those variables.
		for (auto &block : blocks)
		{
			// If we're accessing a variable inside a continue block, this variable might be a loop variable.
			// We can only use loop variables with scalars, as we cannot track static expressions for vectors.
			if (is_continue(block))
			{
				// Potentially awkward case to check for.
				// We might have a variable inside a loop, which is touched by the continue block,
				// but is not actually a loop variable.
				// The continue block is dominated by the inner part of the loop, which does not make sense in high-level
				// language output because it will be declared before the body,
				// so we will have to lift the dominator up to the relevant loop header instead.
				builder.add_block(ir.continue_block_to_loop_header[block]);

				// Arrays or structs cannot be loop variables.
				if (type.vecsize == 1 && type.columns == 1 && type.basetype != SPIRType::Struct && type.array.empty())
				{
					// The variable is used in multiple continue blocks, this is not a loop
					// candidate, signal that by setting block to -1u.
					auto &potential = potential_loop_variables[var.first];

					if (potential == 0)
						potential = block;
					else
						potential = ~(0u);
				}
			}
			builder.add_block(block);
		}

		builder.lift_continue_block_dominator();

		// Add it to a per-block list of variables.
		uint32_t dominating_block = builder.get_dominator();

		// If all blocks here are dead code, this will be 0, so the variable in question
		// will be completely eliminated.
		if (dominating_block)
		{
			auto &block = get<SPIRBlock>(dominating_block);
			block.dominated_variables.push_back(var.first);
			get<SPIRVariable>(var.first).dominator = dominating_block;
		}
	}

	for (auto &var : handler.accessed_temporaries_to_block)
	{
		auto itr = handler.result_id_to_type.find(var.first);

		if (itr == end(handler.result_id_to_type))
		{
			// We found a false positive ID being used, ignore.
			// This should probably be an assert.
			continue;
		}

		DominatorBuilder builder(cfg);
		bool force_temporary = false;

		// Figure out which block is dominating all accesses of those temporaries.
		auto &blocks = var.second;
		for (auto &block : blocks)
		{
			builder.add_block(block);

			// If a temporary is used in more than one block, we might have to lift continue block
			// access up to loop header like we did for variables.
			if (blocks.size() != 1 && is_continue(block))
				builder.add_block(ir.continue_block_to_loop_header[block]);
			else if (blocks.size() != 1 && is_single_block_loop(block))
			{
				// Awkward case, because the loop header is also the continue block.
				force_temporary = true;
			}
		}

		uint32_t dominating_block = builder.get_dominator();
		if (dominating_block)
		{
			// If we touch a variable in the dominating block, this is the expected setup.
			// SPIR-V normally mandates this, but we have extra cases for temporary use inside loops.
			bool first_use_is_dominator = blocks.count(dominating_block) != 0;

			if (!first_use_is_dominator || force_temporary)
			{
				// This should be very rare, but if we try to declare a temporary inside a loop,
				// and that temporary is used outside the loop as well (spirv-opt inliner likes this)
				// we should actually emit the temporary outside the loop.
				hoisted_temporaries.insert(var.first);
				forced_temporaries.insert(var.first);

				auto &block_temporaries = get<SPIRBlock>(dominating_block).declare_temporary;
				block_temporaries.emplace_back(handler.result_id_to_type[var.first], var.first);
			}
			else if (blocks.size() > 1)
			{
				// Keep track of the temporary as we might have to declare this temporary.
				// This can happen if the loop header dominates a temporary, but we have a complex fallback loop.
				// In this case, the header is actually inside the for (;;) {} block, and we have problems.
				// What we need to do is hoist the temporaries outside the for (;;) {} block in case the header block
				// declares the temporary.
				auto &block_temporaries = get<SPIRBlock>(dominating_block).potential_declare_temporary;
				block_temporaries.emplace_back(handler.result_id_to_type[var.first], var.first);
			}
		}
	}

	unordered_set<uint32_t> seen_blocks;

	// Now, try to analyze whether or not these variables are actually loop variables.
	for (auto &loop_variable : potential_loop_variables)
	{
		auto &var = get<SPIRVariable>(loop_variable.first);
		auto dominator = var.dominator;
		auto block = loop_variable.second;

		// The variable was accessed in multiple continue blocks, ignore.
		if (block == ~(0u) || block == 0)
			continue;

		// Dead code.
		if (dominator == 0)
			continue;

		uint32_t header = 0;

		// Find the loop header for this block if we are a continue block.
		{
			auto itr = ir.continue_block_to_loop_header.find(block);
			if (itr != end(ir.continue_block_to_loop_header))
			{
				header = itr->second;
			}
			else if (get<SPIRBlock>(block).continue_block == block)
			{
				// Also check for self-referential continue block.
				header = block;
			}
		}

		assert(header);
		auto &header_block = get<SPIRBlock>(header);
		auto &blocks = handler.accessed_variables_to_block[loop_variable.first];

		// If a loop variable is not used before the loop, it's probably not a loop variable.
		bool has_accessed_variable = blocks.count(header) != 0;

		// Now, there are two conditions we need to meet for the variable to be a loop variable.
		// 1. The dominating block must have a branch-free path to the loop header,
		// this way we statically know which expression should be part of the loop variable initializer.

		// Walk from the dominator, if there is one straight edge connecting
		// dominator and loop header, we statically know the loop initializer.
		bool static_loop_init = true;
		while (dominator != header)
		{
			if (blocks.count(dominator) != 0)
				has_accessed_variable = true;

			auto &succ = cfg.get_succeeding_edges(dominator);
			if (succ.size() != 1)
			{
				static_loop_init = false;
				break;
			}

			auto &pred = cfg.get_preceding_edges(succ.front());
			if (pred.size() != 1 || pred.front() != dominator)
			{
				static_loop_init = false;
				break;
			}

			dominator = succ.front();
		}

		if (!static_loop_init || !has_accessed_variable)
			continue;

		// The second condition we need to meet is that no access after the loop
		// merge can occur. Walk the CFG to see if we find anything.

		seen_blocks.clear();
		cfg.walk_from(seen_blocks, header_block.merge_block, [&](uint32_t walk_block) {
			// We found a block which accesses the variable outside the loop.
			if (blocks.find(walk_block) != end(blocks))
				static_loop_init = false;
		});

		if (!static_loop_init)
			continue;

		// We have a loop variable.
		header_block.loop_variables.push_back(loop_variable.first);
		// Need to sort here as variables come from an unordered container, and pushing stuff in wrong order
		// will break reproducability in regression runs.
		sort(begin(header_block.loop_variables), end(header_block.loop_variables));
		get<SPIRVariable>(loop_variable.first).loop_variable = true;
	}
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0xd8, %rsp
movq %rdx, %r14
movq %rsi, %r15
movq %rdi, %rbx
callq 0x13ece
leaq 0x3a0(%rbx), %rdi
leaq 0x8(%r15), %rcx
movl 0x8(%r15), %r8d
movq %r8, %rax
xorl %edx, %edx
divq 0x3a8(%rbx)
movq %rdx, %rsi
movq %rcx, %rdx
movq %r8, %rcx
callq 0x23bfa
movq (%rax), %rax
movq 0x10(%rax), %rdx
leaq 0x18(%r14), %rcx
leaq 0xc0(%r14), %r8
movq %rbx, 0x10(%rsp)
movq %rbx, %rdi
movq %r15, %rsi
movq %rdx, 0x28(%rsp)
movq %rcx, 0x60(%rsp)
callq 0x18764
leaq 0xd0(%rsp), %rax
movq %rax, -0x30(%rax)
movq $0x1, -0x28(%rax)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, -0x10(%rax) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
movq %r14, 0x38(%rsp)
movq 0x28(%r14), %rbx
testq %rbx, %rbx
je 0x1991b
movq 0x10(%rsp), %rax
leaq 0x98(%rax), %r12
leaq 0x68(%rsp), %r13
movq %r15, 0x30(%rsp)
leaq 0x8(%rbx), %rdx
movq 0x48(%r15), %rdi
movq 0x50(%r15), %rsi
movq %rdx, 0x20(%rsp)
callq 0x7966
cmpq 0x50(%r15), %rax
je 0x1990f
movq %r13, %rdi
movq 0x28(%rsp), %rsi
callq 0x76aa
movq 0x20(%rsp), %rax
movl (%rax), %esi
movq 0x10(%rsp), %rdi
callq 0x13116
movq 0x10(%rsp), %rdi
movl %eax, %esi
callq 0x1b9de
movq %rax, %r14
leaq 0x20(%rbx), %rbp
movq (%rbp), %rbp
testq %rbp, %rbp
je 0x1989d
leaq 0x8(%rbp), %r15
movl 0x8(%rbp), %eax
movq 0x10(%rsp), %rcx
movq 0x80(%rcx), %rcx
testb $0x2, (%rcx,%rax)
je 0x1988d
movq %r12, %rdi
movq %r15, %rsi
callq 0x22474
movl (%rax), %esi
movq %r13, %rdi
callq 0x76b6
cmpl $0x1, 0x14(%r14)
jne 0x1988d
cmpl $0x1, 0x18(%r14)
jne 0x1988d
cmpl $0xc, 0xc(%r14)
je 0x1988d
movq 0x20(%r14), %rax
cmpq 0x28(%r14), %rax
jne 0x1988d
leaq 0xa0(%rsp), %rdi
movq 0x20(%rsp), %rsi
callq 0x22474
xorl %ecx, %ecx
cmpl (%rax), %ecx
movl $0x0, %ecx
sbbl %ecx, %ecx
orl (%r15), %ecx
movl %ecx, (%rax)
movl (%r15), %esi
movq %r13, %rdi
callq 0x76b6
jmp 0x19815
movq %r13, %rdi
callq 0x76f6
movl 0x70(%rsp), %r14d
testl %r14d, %r14d
movq 0x30(%rsp), %r15
je 0x1990f
movq 0x10(%rsp), %rdi
movl %r14d, %esi
callq 0x78fe
movq 0xc0(%rax), %rsi
cmpq 0xc8(%rax), %rsi
je 0x198e7
movq 0x20(%rsp), %rcx
movl (%rcx), %ecx
movl %ecx, (%rsi)
addq $0x4, %rsi
movq %rsi, 0xc0(%rax)
jmp 0x198fa
addq $0xb8, %rax
movq %rax, %rdi
movq 0x20(%rsp), %rdx
callq 0x7a00
movq 0x20(%rsp), %rax
movl (%rax), %esi
movq 0x10(%rsp), %rdi
callq 0xb40a
movl %r14d, 0x60(%rax)
movq (%rbx), %rbx
testq %rbx, %rbx
jne 0x197c4
movq 0x38(%rsp), %rax
movq 0x60(%rax), %r13
testq %r13, %r13
movq 0x28(%rsp), %rbx
je 0x19b0b
movq 0x38(%rsp), %rax
leaq 0x88(%rax), %rbp
movq 0x10(%rsp), %rax
leaq 0x98(%rax), %rcx
movq %rcx, 0x20(%rsp)
leaq 0x298(%rax), %rcx
movq %rcx, 0x58(%rsp)
addq $0x228, %rax            # imm = 0x228
movq %rax, 0x50(%rsp)
leaq 0x68(%rsp), %r15
movq %rbp, 0x30(%rsp)
leaq 0x8(%r13), %r12
movl 0x8(%r13), %ecx
movq %rcx, %rax
xorl %edx, %edx
movq 0x38(%rsp), %rsi
divq 0x90(%rsi)
movq %rbp, %rdi
movq %rdx, %rsi
movq %r12, %rdx
callq 0x217a2
testq %rax, %rax
je 0x19afe
cmpq $0x0, (%rax)
je 0x19afe
movq %r15, %rdi
movq %rbx, %rsi
callq 0x76aa
movq 0x20(%r13), %rbp
xorl %ebx, %ebx
testq %rbp, %rbp
je 0x19a37
movl 0x8(%rbp), %esi
movq %r15, %rdi
callq 0x76b6
movq 0x28(%r13), %rax
cmpq $0x1, %rax
je 0x19a31
leaq 0x8(%rbp), %rsi
movl (%rsi), %ecx
movq 0x10(%rsp), %rdx
movq 0x80(%rdx), %rdx
testb $0x2, (%rdx,%rcx)
jne 0x19a1d
cmpq $0x1, %rax
je 0x19a31
movl (%rsi), %r14d
movq 0x10(%rsp), %rdi
movl %r14d, %esi
callq 0x7932
movl 0x10(%rax), %ecx
xorl $0x1, %ecx
xorl 0x20(%rax), %r14d
orl %ecx, %r14d
movzbl %bl, %ebx
movl $0x1, %eax
cmovel %eax, %ebx
jmp 0x19a31
movq 0x20(%rsp), %rdi
callq 0x22474
movl (%rax), %esi
movq %r15, %rdi
callq 0x76b6
movq (%rbp), %rbp
jmp 0x199bb
movl 0x70(%rsp), %eax
movl %eax, 0xc(%rsp)
testl %eax, %eax
movq 0x30(%rsp), %rbp
je 0x19af9
leaq 0x10(%r13), %rdi
leaq 0xc(%rsp), %rsi
callq 0x1fbce
testq %rax, %rax
sete %al
orb %bl, %al
testb $0x1, %al
je 0x19ac4
movq 0x58(%rsp), %rdi
movq %rdi, 0x40(%rsp)
movq %r12, %rsi
leaq 0x40(%rsp), %rdx
callq 0x1fc02
movq 0x50(%rsp), %rdi
movq %rdi, 0x40(%rsp)
movq %r12, %rsi
leaq 0x40(%rsp), %rdx
callq 0x1fc02
movl 0xc(%rsp), %esi
movq 0x10(%rsp), %rdi
callq 0x78fe
movq %rax, %r14
movq %rbp, %rdi
movq %r12, %rsi
callq 0x22474
addq $0x68, %r14
movq %r14, %rdi
movq %rax, %rsi
movq %r12, %rdx
callq 0x1c6ea
jmp 0x19af9
cmpq $0x2, 0x28(%r13)
jb 0x19af9
movl 0xc(%rsp), %esi
movq 0x10(%rsp), %rdi
callq 0x78fe
movq %rax, %r14
movq %rbp, %rdi
movq %r12, %rsi
callq 0x22474
subq $-0x80, %r14
movq %r14, %rdi
movq %rax, %rsi
movq %r12, %rdx
callq 0x1c6ea
movq 0x28(%rsp), %rbx
movq (%r13), %r13
testq %r13, %r13
jne 0x19970
leaq 0x98(%rsp), %rax
movq %rax, -0x30(%rax)
movq $0x1, -0x28(%rax)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, -0x10(%rax) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
movq 0xb0(%rsp), %r13
testq %r13, %r13
je 0x19ddf
movl 0x8(%r13), %esi
movq 0x10(%rsp), %rdi
callq 0xb40a
movl 0x60(%rax), %eax
movl %eax, 0xc(%rsp)
movl 0xc(%r13), %r15d
leal 0x1(%r15), %ecx
cmpl $0x2, %ecx
jb 0x19dd6
testl %eax, %eax
je 0x19dd6
movl $0x0, 0x1c(%rsp)
movq 0x10(%rsp), %rax
movq 0x98(%rax), %rsi
movq 0xa0(%rax), %rdi
movq %r15, %rax
xorl %edx, %edx
divq %rdi
movq %rdx, %rcx
movq (%rsi,%rdx,8), %rdx
movl $0x0, %eax
testq %rdx, %rdx
je 0x19bdd
movq (%rdx), %r8
movq %rdx, %rax
cmpl 0x8(%r8), %r15d
je 0x19bdd
movq %r8, %r9
movq (%r8), %r8
testq %r8, %r8
je 0x19bdb
movl 0x8(%r8), %esi
movq %rsi, %rax
xorl %edx, %edx
divq %rdi
movl $0x0, %eax
cmpq %rcx, %rdx
jne 0x19bdd
movq %r9, %rax
cmpl %esi, %r15d
jne 0x19bb0
jmp 0x19bdd
xorl %eax, %eax
testq %rax, %rax
je 0x19be7
movq (%rax), %rax
jmp 0x19be9
xorl %eax, %eax
testq %rax, %rax
je 0x19bf7
movl 0xc(%rax), %eax
movl %eax, 0x1c(%rsp)
jmp 0x19c0f
movq 0x10(%rsp), %rdi
movl %r15d, %esi
callq 0x78fe
cmpl %r15d, 0x20(%rax)
jne 0x19c0f
movl %r15d, 0x1c(%rsp)
movl 0x1c(%rsp), %esi
testl %esi, %esi
je 0x19e08
movq 0x10(%rsp), %rdi
callq 0x78fe
movq %rax, %rbp
leaq 0x8(%r13), %r15
movq 0x60(%rsp), %rdi
movq %r15, %rsi
callq 0x237d8
movq %rax, %r12
movq %rax, %rdi
leaq 0x1c(%rsp), %rsi
callq 0x1fbce
testq %rax, %rax
setne %bl
movb $0x1, 0xb(%rsp)
movl 0xc(%rsp), %eax
cmpl 0x1c(%rsp), %eax
je 0x19ccd
movq %r12, %rdi
leaq 0xc(%rsp), %rsi
callq 0x1fbce
testq %rax, %rax
movzbl %bl, %ebx
movl $0x1, %eax
cmovnel %eax, %ebx
movl 0xc(%rsp), %eax
movq 0x28(%rsp), %rdi
movq 0x28(%rdi), %rdx
leaq (%rax,%rax,2), %rsi
movq (%rdx,%rsi,8), %rcx
movq 0x8(%rdx,%rsi,8), %rdx
subq %rcx, %rdx
cmpq $0x4, %rdx
jne 0x19cc8
movl (%rcx), %ecx
movq 0x10(%rdi), %rsi
leaq (%rcx,%rcx,2), %rdi
movq (%rsi,%rdi,8), %rdx
movq 0x8(%rsi,%rdi,8), %rsi
subq %rdx, %rsi
cmpq $0x4, %rsi
jne 0x19cc8
cmpl %eax, (%rdx)
jne 0x19cc8
movl %ecx, 0xc(%rsp)
cmpl 0x1c(%rsp), %ecx
jne 0x19c5e
jmp 0x19ccd
movb $0x0, 0xb(%rsp)
cmpb $0x1, 0xb(%rsp)
jne 0x19dd6
testb $0x1, %bl
je 0x19dd6
movq 0x78(%rsp), %rdi
testq %rdi, %rdi
je 0x19d00
movq (%rdi), %rbx
movl $0x10, %esi
callq 0x6260
movq %rbx, %rdi
testq %rbx, %rbx
jne 0x19ceb
movq 0x68(%rsp), %rdi
movq 0x70(%rsp), %rdx
shlq $0x3, %rdx
xorl %esi, %esi
callq 0x6180
xorps %xmm0, %xmm0
leaq 0x78(%rsp), %rax
movups %xmm0, (%rax)
movl 0x1c(%rbp), %edx
movq %r12, 0x40(%rsp)
leaq 0xb(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0x28(%rsp), %rdi
leaq 0x68(%rsp), %rsi
leaq 0x40(%rsp), %rcx
callq 0x19e72
cmpb $0x0, 0xb(%rsp)
je 0x19dd6
movq 0xd8(%rbp), %rsi
cmpq 0xe0(%rbp), %rsi
je 0x19d73
movl (%r15), %eax
movl %eax, (%rsi)
addq $0x4, %rsi
movq %rsi, 0xd8(%rbp)
jmp 0x19d85
movq %rbp, %rdi
addq $0xd0, %rdi
movq %r15, %rdx
callq 0x7a00
movq 0xd0(%rbp), %r14
movq 0xd8(%rbp), %r12
cmpq %r12, %r14
je 0x19dc5
movq %r12, %rax
subq %r14, %rax
sarq $0x2, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
movq %r14, %rdi
movq %r12, %rsi
callq 0x21b53
movq %r14, %rdi
movq %r12, %rsi
callq 0x21c36
movl (%r15), %esi
movq 0x10(%rsp), %rdi
callq 0xb40a
movb $0x1, 0x64(%rax)
movq (%r13), %r13
jmp 0x19b39
leaq 0x68(%rsp), %rdi
callq 0xd5b0
leaq 0xa0(%rsp), %rdi
callq 0xdd10
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x9c25d(%rip), %rdi     # 0xb606c
leaq 0x9bef3(%rip), %rsi     # 0xb5d09
leaq 0x9c256(%rip), %rcx     # 0xb6073
movl $0xbd2, %edx            # imm = 0xBD2
callq 0x61b0
jmp 0x19e49
jmp 0x19e49
jmp 0x19e5a
jmp 0x19e49
jmp 0x19e5a
jmp 0x19e5a
jmp 0x19e5a
jmp 0x19e49
jmp 0x19e49
jmp 0x19e49
jmp 0x19e5a
jmp 0x19e5a
jmp 0x19e5a
jmp 0x19e5a
jmp 0x19e49
jmp 0x19e5a
jmp 0x19e5a
movq %rax, %rbx
leaq 0x68(%rsp), %rdi
callq 0xd5b0
jmp 0x19e5d
jmp 0x19e5a
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
callq 0xdd10
movq %rbx, %rdi
callq 0x64a0