// File: /workspace/github_cpp_makefile_star2_O3/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 0x13dbc
leaq 0x3a0(%rbx), %rdi
leaq 0x8(%r15), %rsi
callq 0x23544
movq 0x10(%rax), %rdx
leaq 0x18(%r14), %rcx
leaq 0xc0(%r14), %r8
movq %rbx, %rdi
movq %r15, %rsi
movq %rdx, 0x30(%rsp)
movq %rcx, 0x60(%rsp)
callq 0x182bc
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, 0x40(%rsp)
movq 0x28(%r14), %r12
testq %r12, %r12
je 0x1938f
leaq 0x98(%rbx), %r13
leaq 0x68(%rsp), %rbp
movq %r15, 0x38(%rsp)
leaq 0x8(%r12), %rdx
movq 0x48(%r15), %rdi
movq 0x50(%r15), %rsi
movq %rdx, 0x18(%rsp)
callq 0x78d8
cmpq 0x50(%r15), %rax
je 0x19382
movq %rbp, %rdi
movq 0x30(%rsp), %rsi
callq 0x7648
movq 0x18(%rsp), %rax
movl (%rax), %esi
movq %rbx, %rdi
callq 0x130d0
movq %rbx, %rdi
movl %eax, %esi
callq 0x1b382
movq %rax, %r14
movq %r12, 0x20(%rsp)
addq $0x20, %r12
movq (%r12), %r12
testq %r12, %r12
je 0x1930f
leaq 0x8(%r12), %r15
movl 0x8(%r12), %eax
movq 0x80(%rbx), %rcx
testb $0x2, (%rcx,%rax)
je 0x192ff
movq %r13, %rdi
movq %r15, %rsi
callq 0x21d9e
movl (%rax), %esi
movq %rbp, %rdi
callq 0x7654
cmpl $0x1, 0x14(%r14)
jne 0x192ff
cmpl $0x1, 0x18(%r14)
jne 0x192ff
cmpl $0xc, 0xc(%r14)
je 0x192ff
movq 0x20(%r14), %rax
cmpq 0x28(%r14), %rax
jne 0x192ff
leaq 0xa0(%rsp), %rdi
movq 0x18(%rsp), %rsi
callq 0x21d9e
xorl %ecx, %ecx
cmpl (%rax), %ecx
movl $0x0, %ecx
sbbl %ecx, %ecx
orl (%r15), %ecx
movl %ecx, (%rax)
movl (%r15), %esi
movq %rbp, %rdi
callq 0x7654
jmp 0x19289
movq %rbp, %rdi
callq 0x7694
movq 0x20(%rsp), %r12
movl 0x70(%rsp), %r14d
testl %r14d, %r14d
movq 0x38(%rsp), %r15
je 0x19382
movq %rbx, %rdi
movl %r14d, %esi
callq 0x7870
movq 0xc0(%rax), %rsi
cmpq 0xc8(%rax), %rsi
je 0x1935c
movq 0x18(%rsp), %rcx
movl (%rcx), %ecx
movl %ecx, (%rsi)
addq $0x4, %rsi
movq %rsi, 0xc0(%rax)
jmp 0x1936f
addq $0xb8, %rax
movq %rax, %rdi
movq 0x18(%rsp), %rdx
callq 0x797e
movq 0x18(%rsp), %rax
movl (%rax), %esi
movq %rbx, %rdi
callq 0xb3ca
movl %r14d, 0x60(%rax)
movq (%r12), %r12
testq %r12, %r12
jne 0x19236
movq 0x40(%rsp), %rbp
movq 0x60(%rbp), %r12
testq %r12, %r12
je 0x19547
addq $0x88, %rbp
leaq 0x98(%rbx), %rax
movq %rax, 0x18(%rsp)
leaq 0x298(%rbx), %rax
movq %rax, 0x38(%rsp)
leaq 0x228(%rbx), %rax
movq %rax, 0x58(%rsp)
leaq 0x68(%rsp), %r13
movq %rbp, 0x40(%rsp)
leaq 0x8(%r12), %rsi
movq %rbp, %rdi
movq %rsi, 0x20(%rsp)
callq 0x2235e
testq %rax, %rax
je 0x1953a
movq %r13, %rdi
movq 0x30(%rsp), %rsi
callq 0x7648
movq 0x20(%r12), %rbp
xorl %r15d, %r15d
testq %rbp, %rbp
je 0x1946d
movl 0x8(%rbp), %esi
movq %r13, %rdi
callq 0x7654
cmpq $0x1, 0x28(%r12)
je 0x19467
leaq 0x8(%rbp), %rsi
movl (%rsi), %r14d
movq 0x80(%rbx), %rax
testb $0x2, (%rax,%r14)
jne 0x19453
movq %rbx, %rdi
movl %r14d, %esi
callq 0x78a4
movl 0x10(%rax), %ecx
xorl 0x20(%rax), %r14d
xorl $0x1, %ecx
orl %ecx, %r14d
sete %al
orb %al, %r15b
jmp 0x19467
movq 0x18(%rsp), %rdi
callq 0x21d9e
movl (%rax), %esi
movq %r13, %rdi
callq 0x7654
movq (%rbp), %rbp
jmp 0x19406
movl 0x70(%rsp), %eax
movl %eax, 0x10(%rsp)
testl %eax, %eax
movq 0x40(%rsp), %rbp
je 0x1953a
leaq 0x10(%r12), %rdi
leaq 0x10(%rsp), %rsi
callq 0x1f4b4
testq %rax, %rax
sete %al
orb %r15b, %al
testb $0x1, %al
je 0x19502
movq 0x38(%rsp), %rdi
movq %rdi, 0x48(%rsp)
movq 0x20(%rsp), %rsi
leaq 0x48(%rsp), %rdx
callq 0x1f510
movq 0x58(%rsp), %rdi
movq %rdi, 0x48(%rsp)
movq 0x20(%rsp), %rsi
leaq 0x48(%rsp), %rdx
callq 0x1f510
movl 0x10(%rsp), %esi
movq %rbx, %rdi
callq 0x7870
movq %rax, %r14
movq %rbp, %rdi
movq 0x20(%rsp), %rsi
callq 0x21d9e
addq $0x68, %r14
movq %r14, %rdi
movq %rax, %rsi
movq 0x20(%rsp), %rdx
callq 0x1c0b2
jmp 0x1953a
cmpq $0x2, 0x28(%r12)
jb 0x1953a
movl 0x10(%rsp), %esi
movq %rbx, %rdi
callq 0x7870
movq %rax, %r14
movq %rbp, %rdi
movq 0x20(%rsp), %rsi
callq 0x21d9e
subq $-0x80, %r14
movq %r14, %rdi
movq %rax, %rsi
movq 0x20(%rsp), %rdx
callq 0x1c0b2
movq (%r12), %r12
testq %r12, %r12
jne 0x193d6
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), %r15
testq %r15, %r15
je 0x197e7
leaq 0x98(%rbx), %rax
movq %rax, 0x18(%rsp)
movl 0x8(%r15), %esi
movq %rbx, %rdi
callq 0xb3ca
movl 0x60(%rax), %eax
movl %eax, 0x10(%rsp)
movl 0xc(%r15), %ecx
movl %ecx, 0x2c(%rsp)
incl %ecx
cmpl $0x2, %ecx
jb 0x197db
testl %eax, %eax
je 0x197db
movl $0x0, 0x14(%rsp)
movq 0x18(%rsp), %rdi
leaq 0x2c(%rsp), %rsi
callq 0x2235e
testq %rax, %rax
je 0x195d9
movl 0xc(%rax), %esi
jmp 0x195f2
movl 0x2c(%rsp), %esi
movq %rbx, %rdi
callq 0x7870
movl 0x20(%rax), %esi
cmpl 0x2c(%rsp), %esi
jne 0x19777
movl %esi, 0x14(%rsp)
testl %esi, %esi
je 0x19810
movq %rbx, %rdi
callq 0x7870
movq %rax, %rbp
leaq 0x8(%r15), %r13
movq 0x60(%rsp), %rdi
movq %r13, %rsi
callq 0x23124
movq %rax, %r12
movq %rax, %rdi
leaq 0x14(%rsp), %rsi
callq 0x1f4b4
testq %rax, %rax
setne %r14b
movb $0x1, 0xf(%rsp)
movl 0x10(%rsp), %ecx
cmpl 0x14(%rsp), %ecx
jne 0x196f2
testq %rax, %rax
je 0x197db
movq 0x78(%rsp), %rdi
testq %rdi, %rdi
je 0x1966c
movq (%rdi), %r14
movl $0x10, %esi
callq 0x6260
movq %r14, %rdi
testq %r14, %r14
jne 0x19657
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, 0x48(%rsp)
leaq 0xf(%rsp), %rax
movq %rax, 0x50(%rsp)
movq 0x30(%rsp), %rdi
leaq 0x68(%rsp), %rsi
leaq 0x48(%rsp), %rcx
callq 0x1987a
cmpb $0x0, 0xf(%rsp)
je 0x197db
movq %rbp, %r12
addq $0xd0, %r12
movq 0xd8(%rbp), %r14
cmpq 0xe0(%rbp), %r14
je 0x19780
movl (%r13), %eax
movl %eax, (%r14)
addq $0x4, %r14
movq %r14, 0xd8(%rbp)
jmp 0x19795
movq %r12, %rdi
leaq 0x10(%rsp), %rsi
callq 0x1f4b4
testq %rax, %rax
setne %al
movl 0x10(%rsp), %ecx
movq 0x30(%rsp), %rdx
movq 0x28(%rdx), %rsi
leaq (%rcx,%rcx,2), %rdi
movq (%rsi,%rdi,8), %rdx
movq 0x8(%rsi,%rdi,8), %rsi
subq %rdx, %rsi
cmpq $0x4, %rsi
jne 0x197db
movl (%rdx), %edx
movq 0x30(%rsp), %rsi
movq 0x10(%rsi), %rdi
leaq (%rdx,%rdx,2), %r8
movq (%rdi,%r8,8), %rsi
movq 0x8(%rdi,%r8,8), %rdi
subq %rsi, %rdi
cmpq $0x4, %rdi
jne 0x197db
cmpl %ecx, (%rsi)
jne 0x197db
orb %al, %r14b
movl %edx, 0x10(%rsp)
cmpl 0x14(%rsp), %edx
jne 0x196f2
andb 0xf(%rsp), %r14b
testb $0x1, %r14b
jne 0x1964d
jmp 0x197db
movl 0x14(%rsp), %esi
jmp 0x195f6
movq %r12, %rdi
movq %r14, %rsi
movq %r13, %rdx
callq 0x797e
movq 0xd8(%rbp), %r14
movq (%r12), %r12
cmpq %r14, %r12
je 0x197cb
movq %r14, %rax
subq %r12, %rax
sarq $0x2, %rax
bsrq %rax, %rdx
xorl $0x3f, %edx
addl %edx, %edx
xorq $0x7e, %rdx
movq %r12, %rdi
movq %r14, %rsi
callq 0x214b1
movq %r12, %rdi
movq %r14, %rsi
callq 0x21594
movl (%r13), %esi
movq %rbx, %rdi
callq 0xb3ca
movb $0x1, 0x64(%rax)
movq (%r15), %r15
testq %r15, %r15
jne 0x1958a
leaq 0x68(%rsp), %rdi
callq 0xd570
leaq 0xa0(%rsp), %rdi
callq 0xdcda
addq $0xd8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x9b852(%rip), %rdi     # 0xb5069
leaq 0x9b4e8(%rip), %rsi     # 0xb4d06
leaq 0x9b84b(%rip), %rcx     # 0xb5070
movl $0xbd2, %edx            # imm = 0xBD2
callq 0x61b0
jmp 0x19851
jmp 0x19851
jmp 0x19862
jmp 0x19851
jmp 0x19851
jmp 0x19851
jmp 0x19862
jmp 0x19862
jmp 0x19862
jmp 0x19851
jmp 0x19862
jmp 0x19862
jmp 0x19862
jmp 0x19851
jmp 0x19862
jmp 0x19862
jmp 0x19862
movq %rax, %rbx
leaq 0x68(%rsp), %rdi
callq 0xd570
jmp 0x19865
jmp 0x19862
movq %rax, %rbx
leaq 0xa0(%rsp), %rdi
callq 0xdcda
movq %rbx, %rdi
callq 0x64a0