// File: 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
movq %rsp, %rbp
subq $0x3e0, %rsp            # imm = 0x3E0
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0x280(%rbp)
movq -0x10(%rbp), %rsi
movq -0x18(%rbp), %rdx
callq 0x21b20
movq -0x280(%rbp), %rdi
addq $0x3a0, %rdi            # imm = 0x3A0
movq -0x10(%rbp), %rsi
addq $0x8, %rsi
callq 0x31b00
movq %rax, -0x28(%rbp)
leaq -0x28(%rbp), %rdi
callq 0x31b30
movq %rax, %rdi
addq $0x8, %rdi
callq 0x31b60
movq -0x280(%rbp), %rdi
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rsi
movq -0x20(%rbp), %rdx
movq -0x18(%rbp), %rcx
addq $0x18, %rcx
movq -0x18(%rbp), %r8
addq $0xc0, %r8
callq 0x28120
leaq -0x60(%rbp), %rdi
callq 0x30830
movq -0x18(%rbp), %rax
addq $0x18, %rax
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rdi
callq 0x31dd0
movq %rax, -0x70(%rbp)
movq -0x68(%rbp), %rdi
callq 0x31e00
movq %rax, -0x78(%rbp)
leaq -0x70(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x31bf0
testb $0x1, %al
jne 0x29933
jmp 0x29ca2
leaq -0x70(%rbp), %rdi
callq 0x31e30
movq %rax, -0x80(%rbp)
movq -0x10(%rbp), %rdi
addq $0x48, %rdi
callq 0x85d0
movq %rax, -0x288(%rbp)
jmp 0x29956
movq -0x288(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x10(%rbp), %rdi
addq $0x48, %rdi
callq 0x8600
movq %rax, -0x290(%rbp)
jmp 0x2997a
movq -0x290(%rbp), %rax
movq %rax, -0xa8(%rbp)
movq -0x80(%rbp), %rdx
movq -0x90(%rbp), %rdi
movq -0xa8(%rbp), %rsi
callq 0x8e40
movq %rax, -0x298(%rbp)
jmp 0x299a8
movq -0x298(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x10(%rbp), %rdi
addq $0x48, %rdi
callq 0x8600
movq %rax, -0x2a0(%rbp)
jmp 0x299cc
movq -0x2a0(%rbp), %rax
movq %rax, -0xb0(%rbp)
leaq -0x88(%rbp), %rdi
leaq -0xb0(%rbp), %rsi
callq 0x8e90
testb $0x1, %al
jne 0x299f3
jmp 0x29a0f
jmp 0x29c94
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
jmp 0x2a5ec
movq -0x20(%rbp), %rsi
leaq -0xc0(%rbp), %rdi
callq 0x7fc0
jmp 0x29a21
movq -0x280(%rbp), %rdi
movq -0x80(%rbp), %rax
addq $0x8, %rax
movq %rax, -0xc8(%rbp)
movq -0x80(%rbp), %rax
movl (%rax), %esi
callq 0x1f760
movq %rax, -0x2a8(%rbp)
jmp 0x29a4b
movq -0x2a8(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0xc8(%rbp), %rax
movq %rax, -0xd8(%rbp)
movq -0xd8(%rbp), %rdi
callq 0x31e60
movq %rax, -0xe0(%rbp)
movq -0xd8(%rbp), %rdi
callq 0x31e90
movq %rax, -0xe8(%rbp)
leaq -0xe0(%rbp), %rdi
leaq -0xe8(%rbp), %rsi
callq 0x2fed0
testb $0x1, %al
jne 0x29aa9
jmp 0x29be2
leaq -0xe0(%rbp), %rdi
callq 0x31ec0
movq -0x280(%rbp), %rdi
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rax
movl (%rax), %esi
callq 0x2fdb0
movb %al, -0x2a9(%rbp)
jmp 0x29ad9
movb -0x2a9(%rbp), %al
testb $0x1, %al
jne 0x29ae8
jmp 0x29bb8
movq -0x280(%rbp), %rdi
addq $0x98, %rdi
movq -0xf0(%rbp), %rsi
callq 0x30850
movq %rax, -0x2b8(%rbp)
jmp 0x29b0b
movq -0x2b8(%rbp), %rax
movl (%rax), %esi
leaq -0xc0(%rbp), %rdi
callq 0x7fe0
jmp 0x29b22
movq -0xd0(%rbp), %rax
cmpl $0x1, 0x14(%rax)
jne 0x29bb6
movq -0xd0(%rbp), %rax
cmpl $0x1, 0x18(%rax)
jne 0x29bb6
movq -0xd0(%rbp), %rax
cmpl $0xc, 0xc(%rax)
je 0x29bb6
movq -0xd0(%rbp), %rdi
addq $0x20, %rdi
callq 0x8690
testb $0x1, %al
jne 0x29b63
jmp 0x29bb6
movq -0x80(%rbp), %rsi
leaq -0x60(%rbp), %rdi
callq 0x30850
movq %rax, -0x2c0(%rbp)
jmp 0x29b79
movq -0x2c0(%rbp), %rax
movq %rax, -0xf8(%rbp)
movq -0xf8(%rbp), %rax
cmpl $0x0, (%rax)
jne 0x29ba7
movq -0xf0(%rbp), %rax
movl (%rax), %ecx
movq -0xf8(%rbp), %rax
movl %ecx, (%rax)
jmp 0x29bb4
movq -0xf8(%rbp), %rax
movl $0xffffffff, (%rax)     # imm = 0xFFFFFFFF
jmp 0x29bb6
jmp 0x29bb8
movq -0xf0(%rbp), %rax
movl (%rax), %esi
leaq -0xc0(%rbp), %rdi
callq 0x7fe0
jmp 0x29bcf
jmp 0x29bd1
leaq -0xe0(%rbp), %rdi
callq 0x31ef0
jmp 0x29a8d
leaq -0xc0(%rbp), %rdi
callq 0x8050
jmp 0x29bf0
leaq -0xc0(%rbp), %rdi
callq 0x31d60
movl %eax, -0x2c4(%rbp)
jmp 0x29c04
movl -0x2c4(%rbp), %eax
movl %eax, -0xfc(%rbp)
cmpl $0x0, -0xfc(%rbp)
je 0x29c92
movq -0x280(%rbp), %rdi
movl -0xfc(%rbp), %esi
callq 0x87d0
movq %rax, -0x2d0(%rbp)
jmp 0x29c34
movq -0x2d0(%rbp), %rax
movq %rax, -0x108(%rbp)
movq -0x108(%rbp), %rdi
addq $0xb8, %rdi
movq -0x80(%rbp), %rsi
callq 0x88f0
jmp 0x29c5b
movq -0x280(%rbp), %rdi
movl -0xfc(%rbp), %eax
movl %eax, -0x2dc(%rbp)
movq -0x80(%rbp), %rax
movl (%rax), %esi
callq 0xfec0
movq %rax, -0x2d8(%rbp)
jmp 0x29c82
movq -0x2d8(%rbp), %rax
movl -0x2dc(%rbp), %ecx
movl %ecx, 0x60(%rax)
jmp 0x29c94
leaq -0x70(%rbp), %rdi
callq 0x31f20
jmp 0x2991d
movq -0x18(%rbp), %rax
addq $0x50, %rax
movq %rax, -0x110(%rbp)
movq -0x110(%rbp), %rdi
callq 0x31dd0
movq %rax, -0x118(%rbp)
movq -0x110(%rbp), %rdi
callq 0x31e00
movq %rax, -0x120(%rbp)
leaq -0x118(%rbp), %rdi
leaq -0x120(%rbp), %rsi
callq 0x31bf0
testb $0x1, %al
jne 0x29cf3
jmp 0x2a105
leaq -0x118(%rbp), %rdi
callq 0x31e30
movq %rax, -0x128(%rbp)
movq -0x18(%rbp), %rdi
addq $0x88, %rdi
movq -0x128(%rbp), %rsi
callq 0x30930
movq %rax, -0x2e8(%rbp)
jmp 0x29d26
movq -0x2e8(%rbp), %rax
movq %rax, -0x130(%rbp)
movq -0x18(%rbp), %rdi
addq $0x88, %rdi
callq 0x30990
movq %rax, -0x2f0(%rbp)
jmp 0x29d4d
movq -0x2f0(%rbp), %rax
movq %rax, -0x138(%rbp)
leaq -0x130(%rbp), %rdi
leaq -0x138(%rbp), %rsi
callq 0x2fba0
testb $0x1, %al
jne 0x29d74
jmp 0x29d79
jmp 0x2a0f4
movq -0x20(%rbp), %rsi
leaq -0x148(%rbp), %rdi
callq 0x7fc0
jmp 0x29d8b
movb $0x0, -0x149(%rbp)
movq -0x128(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x158(%rbp)
movq -0x158(%rbp), %rax
movq %rax, -0x160(%rbp)
movq -0x160(%rbp), %rdi
callq 0x31e60
movq %rax, -0x168(%rbp)
movq -0x160(%rbp), %rdi
callq 0x31e90
movq %rax, -0x170(%rbp)
leaq -0x168(%rbp), %rdi
leaq -0x170(%rbp), %rsi
callq 0x2fed0
testb $0x1, %al
jne 0x29df4
jmp 0x29eec
leaq -0x168(%rbp), %rdi
callq 0x31ec0
movq %rax, -0x178(%rbp)
movq -0x178(%rbp), %rax
movl (%rax), %esi
leaq -0x148(%rbp), %rdi
callq 0x7fe0
jmp 0x29e1e
movq -0x158(%rbp), %rdi
callq 0x31c80
cmpq $0x1, %rax
je 0x29e95
movq -0x280(%rbp), %rdi
movq -0x178(%rbp), %rax
movl (%rax), %esi
callq 0x2fdb0
movb %al, -0x2f1(%rbp)
jmp 0x29e4d
movb -0x2f1(%rbp), %al
testb $0x1, %al
jne 0x29e59
jmp 0x29e95
movq -0x280(%rbp), %rdi
addq $0x98, %rdi
movq -0x178(%rbp), %rsi
callq 0x30850
movq %rax, -0x300(%rbp)
jmp 0x29e7c
movq -0x300(%rbp), %rax
movl (%rax), %esi
leaq -0x148(%rbp), %rdi
callq 0x7fe0
jmp 0x29e93
jmp 0x29ed9
movq -0x158(%rbp), %rdi
callq 0x31c80
cmpq $0x1, %rax
je 0x29ed7
movq -0x280(%rbp), %rdi
movq -0x178(%rbp), %rax
movl (%rax), %esi
callq 0x31f50
movb %al, -0x301(%rbp)
jmp 0x29ec4
movb -0x301(%rbp), %al
testb $0x1, %al
jne 0x29ed0
jmp 0x29ed7
movb $0x1, -0x149(%rbp)
jmp 0x29ed9
jmp 0x29edb
leaq -0x168(%rbp), %rdi
callq 0x31ef0
jmp 0x29dd8
leaq -0x148(%rbp), %rdi
callq 0x31d60
movl %eax, -0x308(%rbp)
jmp 0x29f00
movl -0x308(%rbp), %eax
movl %eax, -0x17c(%rbp)
cmpl $0x0, -0x17c(%rbp)
je 0x2a0f2
movq -0x158(%rbp), %rdi
leaq -0x17c(%rbp), %rsi
callq 0x13520
movq %rax, -0x310(%rbp)
jmp 0x29f35
movq -0x310(%rbp), %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, -0x17d(%rbp)
testb $0x1, -0x17d(%rbp)
je 0x29f61
testb $0x1, -0x149(%rbp)
je 0x2a063
movq -0x280(%rbp), %rdi
addq $0x298, %rdi            # imm = 0x298
movq -0x128(%rbp), %rsi
callq 0x2e890
movb %dl, -0x319(%rbp)
movq %rax, -0x318(%rbp)
jmp 0x29f8a
movq -0x280(%rbp), %rdi
movb -0x319(%rbp), %al
movq -0x318(%rbp), %rcx
movq %rcx, -0x190(%rbp)
movb %al, -0x188(%rbp)
addq $0x228, %rdi            # imm = 0x228
movq -0x128(%rbp), %rsi
callq 0x2e890
movb %dl, -0x329(%rbp)
movq %rax, -0x328(%rbp)
jmp 0x29fcd
movq -0x280(%rbp), %rdi
movb -0x329(%rbp), %al
movq -0x328(%rbp), %rcx
movq %rcx, -0x1a0(%rbp)
movb %al, -0x198(%rbp)
movl -0x17c(%rbp), %esi
callq 0x87d0
movq %rax, -0x338(%rbp)
jmp 0x2a002
movq -0x338(%rbp), %rax
addq $0x68, %rax
movq %rax, -0x1a8(%rbp)
movq -0x1a8(%rbp), %rax
movq %rax, -0x348(%rbp)
movq -0x18(%rbp), %rdi
addq $0x88, %rdi
movq -0x128(%rbp), %rsi
callq 0x30850
movq %rax, -0x340(%rbp)
jmp 0x2a042
movq -0x340(%rbp), %rsi
movq -0x348(%rbp), %rdi
movq -0x128(%rbp), %rdx
callq 0x31fa0
jmp 0x2a05e
jmp 0x2a0f0
movq -0x158(%rbp), %rdi
callq 0x31c80
cmpq $0x1, %rax
jbe 0x2a0ee
movq -0x280(%rbp), %rdi
movl -0x17c(%rbp), %esi
callq 0x87d0
movq %rax, -0x350(%rbp)
jmp 0x2a090
movq -0x350(%rbp), %rax
subq $-0x80, %rax
movq %rax, -0x1b0(%rbp)
movq -0x1b0(%rbp), %rax
movq %rax, -0x360(%rbp)
movq -0x18(%rbp), %rdi
addq $0x88, %rdi
movq -0x128(%rbp), %rsi
callq 0x30850
movq %rax, -0x358(%rbp)
jmp 0x2a0d0
movq -0x358(%rbp), %rsi
movq -0x360(%rbp), %rdi
movq -0x128(%rbp), %rdx
callq 0x31fa0
jmp 0x2a0ec
jmp 0x2a0ee
jmp 0x2a0f0
jmp 0x2a0f2
jmp 0x2a0f4
leaq -0x118(%rbp), %rdi
callq 0x31f20
jmp 0x29cd7
leaq -0x1e8(%rbp), %rdi
callq 0x13cb0
leaq -0x60(%rbp), %rax
movq %rax, -0x1f0(%rbp)
movq -0x1f0(%rbp), %rdi
callq 0x32020
movq %rax, -0x1f8(%rbp)
movq -0x1f0(%rbp), %rdi
callq 0x32050
movq %rax, -0x200(%rbp)
leaq -0x1f8(%rbp), %rdi
leaq -0x200(%rbp), %rsi
callq 0x30960
testb $0x1, %al
jne 0x2a15e
jmp 0x2a5ce
leaq -0x1f8(%rbp), %rdi
callq 0x32080
movq -0x280(%rbp), %rdi
movq %rax, -0x208(%rbp)
movq -0x208(%rbp), %rax
movl (%rax), %esi
callq 0xfec0
movq %rax, -0x368(%rbp)
jmp 0x2a18f
movq -0x368(%rbp), %rax
movq %rax, -0x210(%rbp)
movq -0x210(%rbp), %rax
movl 0x60(%rax), %eax
movl %eax, -0x214(%rbp)
movq -0x208(%rbp), %rax
movl 0x4(%rax), %eax
movl %eax, -0x218(%rbp)
cmpl $-0x1, -0x218(%rbp)
je 0x2a1cf
cmpl $0x0, -0x218(%rbp)
jne 0x2a1f7
jmp 0x2a5bd
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
leaq -0x1e8(%rbp), %rdi
callq 0x13900
jmp 0x2a5ec
cmpl $0x0, -0x214(%rbp)
jne 0x2a205
jmp 0x2a5bd
movq -0x280(%rbp), %rdi
movl $0x0, -0x21c(%rbp)
addq $0x98, %rdi
leaq -0x218(%rbp), %rsi
callq 0x30930
movq %rax, -0x370(%rbp)
jmp 0x2a232
movq -0x280(%rbp), %rdi
movq -0x370(%rbp), %rax
movq %rax, -0x228(%rbp)
addq $0x98, %rdi
callq 0x30990
movq %rax, -0x378(%rbp)
jmp 0x2a25c
movq -0x378(%rbp), %rax
movq %rax, -0x230(%rbp)
leaq -0x228(%rbp), %rdi
leaq -0x230(%rbp), %rsi
callq 0x30960
testb $0x1, %al
jne 0x2a283
jmp 0x2a29a
leaq -0x228(%rbp), %rdi
callq 0x309c0
movl 0x4(%rax), %eax
movl %eax, -0x21c(%rbp)
jmp 0x2a2d5
movq -0x280(%rbp), %rdi
movl -0x218(%rbp), %esi
callq 0x87d0
movq %rax, -0x380(%rbp)
jmp 0x2a2b5
movq -0x380(%rbp), %rax
movl 0x20(%rax), %eax
cmpl -0x218(%rbp), %eax
jne 0x2a2d3
movl -0x218(%rbp), %eax
movl %eax, -0x21c(%rbp)
jmp 0x2a2d5
cmpl $0x0, -0x21c(%rbp)
je 0x2a2e0
jmp 0x2a2ff
leaq 0x115595(%rip), %rdi    # 0x13f87c
leaq 0x11522b(%rip), %rsi    # 0x13f519
movl $0xbd2, %edx            # imm = 0xBD2
leaq 0x115589(%rip), %rcx    # 0x13f883
callq 0x7260
movq -0x280(%rbp), %rdi
movl -0x21c(%rbp), %esi
callq 0x87d0
movq %rax, -0x388(%rbp)
jmp 0x2a31a
movq -0x388(%rbp), %rax
movq %rax, -0x238(%rbp)
movq -0x18(%rbp), %rdi
addq $0x18, %rdi
movq -0x208(%rbp), %rsi
callq 0x31a50
movq %rax, -0x390(%rbp)
jmp 0x2a345
movq -0x390(%rbp), %rax
movq %rax, -0x240(%rbp)
movq -0x240(%rbp), %rdi
leaq -0x21c(%rbp), %rsi
callq 0x13520
movq %rax, -0x398(%rbp)
jmp 0x2a36f
movq -0x398(%rbp), %rax
cmpq $0x0, %rax
setne %al
andb $0x1, %al
movb %al, -0x241(%rbp)
movb $0x1, -0x242(%rbp)
movl -0x214(%rbp), %eax
cmpl -0x21c(%rbp), %eax
je 0x2a498
movq -0x240(%rbp), %rdi
leaq -0x214(%rbp), %rsi
callq 0x13520
movq %rax, -0x3a0(%rbp)
jmp 0x2a3ba
movq -0x3a0(%rbp), %rax
cmpq $0x0, %rax
je 0x2a3ce
movb $0x1, -0x241(%rbp)
movq -0x20(%rbp), %rdi
movl -0x214(%rbp), %esi
callq 0x320b0
movq %rax, -0x3a8(%rbp)
jmp 0x2a3e6
movq -0x3a8(%rbp), %rax
movq %rax, -0x250(%rbp)
movq -0x250(%rbp), %rdi
callq 0x8650
cmpq $0x1, %rax
je 0x2a412
movb $0x0, -0x242(%rbp)
jmp 0x2a498
movq -0x20(%rbp), %rax
movq %rax, -0x3b8(%rbp)
movq -0x250(%rbp), %rdi
callq 0x32110
movq -0x3b8(%rbp), %rdi
movl (%rax), %esi
callq 0x320e0
movq %rax, -0x3b0(%rbp)
jmp 0x2a440
movq -0x3b0(%rbp), %rax
movq %rax, -0x258(%rbp)
movq -0x258(%rbp), %rdi
callq 0x8650
cmpq $0x1, %rax
jne 0x2a476
movq -0x258(%rbp), %rdi
callq 0x32110
movl (%rax), %eax
cmpl -0x214(%rbp), %eax
je 0x2a47f
movb $0x0, -0x242(%rbp)
jmp 0x2a498
movq -0x250(%rbp), %rdi
callq 0x32110
movl (%rax), %eax
movl %eax, -0x214(%rbp)
jmp 0x2a38c
testb $0x1, -0x242(%rbp)
je 0x2a4aa
testb $0x1, -0x241(%rbp)
jne 0x2a4af
jmp 0x2a5bd
leaq -0x1e8(%rbp), %rdi
movq %rdi, -0x3c0(%rbp)
callq 0x32140
movq -0x3c0(%rbp), %rsi
movq -0x20(%rbp), %rdi
movq -0x238(%rbp), %rax
movl 0x1c(%rax), %edx
movq -0x240(%rbp), %rax
movq %rax, -0x268(%rbp)
leaq -0x242(%rbp), %rax
movq %rax, -0x260(%rbp)
leaq -0x268(%rbp), %rcx
callq 0x2a610
jmp 0x2a501
testb $0x1, -0x242(%rbp)
jne 0x2a50f
jmp 0x2a5bd
movq -0x238(%rbp), %rdi
addq $0xd0, %rdi
movq -0x208(%rbp), %rsi
callq 0x88f0
jmp 0x2a52b
movq -0x238(%rbp), %rdi
addq $0xd0, %rdi
callq 0x85d0
movq %rax, -0x3c8(%rbp)
jmp 0x2a547
movq -0x3c8(%rbp), %rax
movq %rax, -0x270(%rbp)
movq -0x238(%rbp), %rdi
addq $0xd0, %rdi
callq 0x8600
movq %rax, -0x3d0(%rbp)
jmp 0x2a571
movq -0x3d0(%rbp), %rax
movq %rax, -0x278(%rbp)
movq -0x270(%rbp), %rdi
movq -0x278(%rbp), %rsi
callq 0x30280
jmp 0x2a594
movq -0x280(%rbp), %rdi
movq -0x208(%rbp), %rax
movl (%rax), %esi
callq 0xfec0
movq %rax, -0x3d8(%rbp)
jmp 0x2a5b2
movq -0x3d8(%rbp), %rax
movb $0x1, 0x64(%rax)
leaq -0x1f8(%rbp), %rdi
callq 0x32160
jmp 0x2a142
leaq -0x1e8(%rbp), %rdi
callq 0x13900
leaq -0x60(%rbp), %rdi
callq 0x150d0
addq $0x3e0, %rsp            # imm = 0x3E0
popq %rbp
retq
leaq -0x60(%rbp), %rdi
callq 0x150d0
movq -0x98(%rbp), %rdi
callq 0x7640
nopw %cs:(%rax,%rax)