// File: /workspace/github_cpp_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x58, %rsp
movq %rdx, %rbx
movq %rdi, %r14
addq $0x3a0, %rdi            # imm = 0x3A0
addq $0x8, %rsi
callq 0x1ea20
movq 0x10(%rax), %rax
movq %rax, 0x20(%rsp)
leaq 0x28(%rbx), %r13
leaq 0xc0(%rbx), %rax
movq %rax, 0x18(%rsp)
addq $0xf8, %rbx
movq (%r13), %r13
testq %r13, %r13
je 0x154f3
movl 0x8(%r13), %esi
movq %r14, %rdi
callq 0x9c0e
movq %rax, %rbp
movl 0x8(%r13), %esi
movq %r14, %rdi
callq 0x104b0
cmpl $0x7, 0x10(%rbp)
jne 0x15344
cmpb $0x0, 0x5a(%rbp)
jne 0x15344
movq 0x20(%rax), %rcx
cmpq 0x28(%rax), %rcx
je 0x15344
cmpl $0xc, 0xc(%rax)
je 0x15344
movl 0x18(%rbp), %r15d
testq %r15, %r15
je 0x153f2
movq 0x20(%r14), %rax
movq %r15, %rcx
shlq $0x4, %rcx
cmpl $0x3, 0x8(%rax,%rcx)
jne 0x15344
movq %rbp, %r12
addq $0x8, %r12
movq 0x18(%rsp), %rdi
movq %r12, %rsi
callq 0x1ea9c
testq %rax, %rax
jne 0x15344
movq %rbx, %rdi
movq %r12, %rsi
callq 0x1ea9c
testq %rax, %rax
jne 0x15344
movq %r14, %rdi
movl %r15d, %esi
callq 0x17bce
movb $0x1, %cl
movb %cl, 0x10a(%rax)
movl %r15d, 0x3c(%rbp)
movb %cl, 0x39(%rbp)
movb %cl, 0x5b(%rbp)
jmp 0x15344
movq %rbp, %r15
addq $0x8, %r15
movq %rbx, %rdi
movq %r15, %rsi
callq 0x1ea9c
testq %rax, %rax
jne 0x15344
movq 0x18(%rsp), %rdi
movq %r15, %rsi
callq 0x1e5dc
testq %rax, %rax
je 0x15344
movq %rax, %r12
cmpq $0x1, 0x28(%rax)
jne 0x15344
movq %rbx, 0x10(%rsp)
addq $0x10, %r12
leaq 0x28(%rsp), %rdi
movq 0x20(%rsp), %rsi
callq 0x6a16
leaq 0x20(%r13), %rbx
movq (%rbx), %rbx
testq %rbx, %rbx
je 0x15464
movl 0x8(%rbx), %esi
leaq 0x28(%rsp), %rdi
callq 0x6a1e
jmp 0x1544d
movl 0x30(%rsp), %eax
movl %eax, 0xc(%rsp)
movq %r12, %rdi
leaq 0xc(%rsp), %rsi
callq 0x1aeea
testq %rax, %rax
je 0x154e9
movl (%r15), %edx
leaq 0x38(%rsp), %rbx
movq %rbx, %rdi
movq %r14, %rsi
callq 0x15290
movl 0xc(%rsp), %esi
movq %r14, %rdi
callq 0x6bf0
movq %r14, %rdi
movq %rax, %rsi
movq %rbx, %rdx
callq 0x1259c
movl 0x4c(%rsp), %r15d
cmpl $0x1, 0x50(%rsp)
setne %al
testl %r15d, %r15d
sete %cl
orb %al, %cl
cmpb $0x1, %cl
movq 0x10(%rsp), %rbx
je 0x15344
movl %r15d, %eax
movq 0x20(%r14), %rcx
shlq $0x4, %rax
cmpl $0x3, 0x8(%rcx,%rax)
jne 0x15344
jmp 0x153d0
movq 0x10(%rsp), %rbx
jmp 0x15344
addq $0x58, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq