// File: rossy[P]crossc/SPIRV-Cross/spirv_cross.cpp
// Function: spirv_cross::Compiler::find_function_local_luts(spirv_cross::SPIRFunction&, spirv_cross::Compiler::AnalyzeVariableScopeAccessHandler const&)
void Compiler::find_function_local_luts(SPIRFunction &entry, const AnalyzeVariableScopeAccessHandler &handler)
{
	auto &cfg = *function_cfgs.find(entry.self)->second;

	// For each variable which is statically accessed.
	for (auto &accessed_var : handler.accessed_variables_to_block)
	{
		auto &blocks = accessed_var.second;
		auto &var = get<SPIRVariable>(accessed_var.first);
		auto &type = expression_type(accessed_var.first);

		// Only consider function local variables here.
		if (var.storage != StorageClassFunction)
			continue;

		// We cannot be a phi variable.
		if (var.phi_variable)
			continue;

		// Only consider arrays here.
		if (type.array.empty())
			continue;

		// HACK: Do not consider structs. This is a quirk with how types are currently being emitted.
		// Structs are emitted after specialization constants and composite constants.
		// FIXME: Fix declaration order so declared constants can have struct types.
		if (type.basetype == SPIRType::Struct)
			continue;

		// If the variable has an initializer, make sure it is a constant expression.
		uint32_t static_constant_expression = 0;
		if (var.initializer)
		{
			if (ir.ids[var.initializer].get_type() != TypeConstant)
				continue;
			static_constant_expression = var.initializer;

			// There can be no stores to this variable, we have now proved we have a LUT.
			if (handler.complete_write_variables_to_block.count(var.self) != 0 ||
			    handler.partial_write_variables_to_block.count(var.self) != 0)
				continue;
		}
		else
		{
			// We can have one, and only one write to the variable, and that write needs to be a constant.

			// No partial writes allowed.
			if (handler.partial_write_variables_to_block.count(var.self) != 0)
				continue;

			auto itr = handler.complete_write_variables_to_block.find(var.self);

			// No writes?
			if (itr == end(handler.complete_write_variables_to_block))
				continue;

			// We write to the variable in more than one block.
			auto &write_blocks = itr->second;
			if (write_blocks.size() != 1)
				continue;

			// The write needs to happen in the dominating block.
			DominatorBuilder builder(cfg);
			for (auto &block : blocks)
				builder.add_block(block);
			uint32_t dominator = builder.get_dominator();

			// The complete write happened in a branch or similar, cannot deduce static expression.
			if (write_blocks.count(dominator) == 0)
				continue;

			// Find the static expression for this variable.
			StaticExpressionAccessHandler static_expression_handler(*this, var.self);
			traverse_all_reachable_opcodes(get<SPIRBlock>(dominator), static_expression_handler);

			// We want one, and exactly one write
			if (static_expression_handler.write_count != 1 || static_expression_handler.static_expression == 0)
				continue;

			// Is it a constant expression?
			if (ir.ids[static_expression_handler.static_expression].get_type() != TypeConstant)
				continue;

			// We found a LUT!
			static_constant_expression = static_expression_handler.static_expression;
		}

		get<SPIRConstant>(static_constant_expression).is_used_as_lut = true;
		var.static_expression = static_constant_expression;
		var.statically_assigned = true;
		var.remapped_variable = true;
	}
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x100, %rsp            # imm = 0x100
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq -0x8(%rbp), %rdi
movq %rdi, -0xf0(%rbp)
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 %rax, -0x20(%rbp)
movq -0x18(%rbp), %rax
addq $0x18, %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rdi
callq 0x31b90
movq %rax, -0x38(%rbp)
movq -0x30(%rbp), %rdi
callq 0x31bc0
movq %rax, -0x40(%rbp)
leaq -0x38(%rbp), %rdi
leaq -0x40(%rbp), %rsi
callq 0x31bf0
testb $0x1, %al
jne 0x2949f
jmp 0x29844
leaq -0x38(%rbp), %rdi
callq 0x31c20
movq -0xf0(%rbp), %rdi
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x50(%rbp)
movq -0x48(%rbp), %rax
movl (%rax), %esi
callq 0xfec0
movq -0xf0(%rbp), %rdi
movq %rax, -0x58(%rbp)
movq -0x48(%rbp), %rax
movl (%rax), %esi
callq 0x1f760
movq %rax, -0x60(%rbp)
movq -0x58(%rbp), %rax
cmpl $0x7, 0x10(%rax)
je 0x294f3
jmp 0x29836
movq -0x58(%rbp), %rax
testb $0x1, 0x5a(%rax)
je 0x29502
jmp 0x29836
movq -0x60(%rbp), %rdi
addq $0x20, %rdi
callq 0x8690
testb $0x1, %al
jne 0x29515
jmp 0x2951a
jmp 0x29836
movq -0x60(%rbp), %rax
cmpl $0xc, 0xc(%rax)
jne 0x29529
jmp 0x29836
movl $0x0, -0x64(%rbp)
movq -0x58(%rbp), %rax
cmpl $0x0, 0x18(%rax)
je 0x295b9
movq -0xf0(%rbp), %rdi
addq $0x8, %rdi
addq $0x18, %rdi
movq -0x58(%rbp), %rax
movl 0x18(%rax), %eax
movl %eax, %esi
callq 0xbdb0
movq %rax, %rdi
callq 0xfa00
cmpl $0x3, %eax
je 0x29569
jmp 0x29836
movq -0x58(%rbp), %rax
movl 0x18(%rax), %eax
movl %eax, -0x64(%rbp)
movq -0x18(%rbp), %rdi
addq $0xc0, %rdi
movq -0x58(%rbp), %rsi
addq $0x8, %rsi
callq 0x31c50
cmpq $0x0, %rax
jne 0x295af
movq -0x18(%rbp), %rdi
addq $0xf8, %rdi
movq -0x58(%rbp), %rsi
addq $0x8, %rsi
callq 0x31c50
cmpq $0x0, %rax
je 0x295b4
jmp 0x29836
jmp 0x29806
movq -0x18(%rbp), %rdi
addq $0xf8, %rdi
movq -0x58(%rbp), %rsi
addq $0x8, %rsi
callq 0x31c50
cmpq $0x0, %rax
je 0x295dc
jmp 0x29836
movq -0x18(%rbp), %rdi
addq $0xc0, %rdi
movq -0x58(%rbp), %rsi
addq $0x8, %rsi
callq 0x31950
movq %rax, -0x70(%rbp)
movq -0x18(%rbp), %rdi
addq $0xc0, %rdi
callq 0x319b0
movq %rax, -0x78(%rbp)
leaq -0x70(%rbp), %rdi
leaq -0x78(%rbp), %rsi
callq 0x31980
testb $0x1, %al
jne 0x2961f
jmp 0x29624
jmp 0x29836
leaq -0x70(%rbp), %rdi
callq 0x319e0
addq $0x8, %rax
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rdi
callq 0x31c80
cmpq $0x1, %rax
je 0x29649
jmp 0x29836
movq -0x20(%rbp), %rsi
leaq -0x90(%rbp), %rdi
callq 0x7fc0
movq -0x50(%rbp), %rax
movq %rax, -0x98(%rbp)
movq -0x98(%rbp), %rdi
callq 0x31ca0
movq %rax, -0xa0(%rbp)
movq -0x98(%rbp), %rdi
callq 0x31cd0
movq %rax, -0xa8(%rbp)
leaq -0xa0(%rbp), %rdi
leaq -0xa8(%rbp), %rsi
callq 0x2fed0
testb $0x1, %al
jne 0x296a3
jmp 0x296d9
leaq -0xa0(%rbp), %rdi
callq 0x31d00
movq %rax, -0xb0(%rbp)
movq -0xb0(%rbp), %rax
movl (%rax), %esi
leaq -0x90(%rbp), %rdi
callq 0x7fe0
leaq -0xa0(%rbp), %rdi
callq 0x31d30
jmp 0x2968a
leaq -0x90(%rbp), %rdi
callq 0x31d60
movl %eax, -0xb4(%rbp)
movq -0x80(%rbp), %rdi
leaq -0xb4(%rbp), %rsi
callq 0x13520
cmpq $0x0, %rax
jne 0x29706
jmp 0x29836
movq -0xf0(%rbp), %rsi
movq -0x58(%rbp), %rax
movl 0x8(%rax), %edx
leaq -0xd8(%rbp), %rdi
callq 0x292b0
movq -0xf0(%rbp), %rdi
movl -0xb4(%rbp), %esi
callq 0x87d0
movq %rax, -0xf8(%rbp)
jmp 0x2973b
movq -0xf8(%rbp), %rsi
movq -0xf0(%rbp), %rdi
leaq -0xd8(%rbp), %rdx
callq 0x23ee0
jmp 0x29757
cmpl $0x1, -0xc0(%rbp)
jne 0x29769
cmpl $0x0, -0xc4(%rbp)
jne 0x29798
movl $0x3, -0xe8(%rbp)
jmp 0x297ea
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0xe0(%rbp)
movl %eax, -0xe4(%rbp)
leaq -0xd8(%rbp), %rdi
callq 0x31d80
jmp 0x2984d
movq -0xf0(%rbp), %rdi
addq $0x20, %rdi
movl -0xc4(%rbp), %eax
movl %eax, %esi
callq 0xbdb0
movq %rax, %rdi
callq 0xfa00
movl %eax, -0xfc(%rbp)
jmp 0x297c0
movl -0xfc(%rbp), %eax
cmpl $0x3, %eax
je 0x297d7
movl $0x3, -0xe8(%rbp)
jmp 0x297ea
movl -0xc4(%rbp), %eax
movl %eax, -0x64(%rbp)
movl $0x0, -0xe8(%rbp)
leaq -0xd8(%rbp), %rdi
callq 0x31d80
movl -0xe8(%rbp), %eax
testl %eax, %eax
je 0x29804
jmp 0x29802
jmp 0x29836
jmp 0x29806
movq -0xf0(%rbp), %rdi
movl -0x64(%rbp), %esi
callq 0x31910
movb $0x1, 0x10a(%rax)
movl -0x64(%rbp), %ecx
movq -0x58(%rbp), %rax
movl %ecx, 0x3c(%rax)
movq -0x58(%rbp), %rax
movb $0x1, 0x39(%rax)
movq -0x58(%rbp), %rax
movb $0x1, 0x5b(%rax)
leaq -0x38(%rbp), %rdi
callq 0x31da0
jmp 0x29489
addq $0x100, %rsp            # imm = 0x100
popq %rbp
retq
movq -0xe0(%rbp), %rdi
callq 0x7640
nopl (%rax)