// File: /workspace/github_cpp_makefile_star2_O3/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 $0x68, %rsp
movq %rdx, %rbx
movq %rdi, %r14
addq $0x3a0, %rdi            # imm = 0x3A0
addq $0x8, %rsi
callq 0x23544
movq 0x28(%rbx), %r12
testq %r12, %r12
je 0x1918b
movq %rbx, %rcx
movq 0x10(%rax), %rax
movq %rax, 0x30(%rsp)
leaq 0xc0(%rbx), %rax
movq %rax, 0x10(%rsp)
addq $0xf8, %rcx
movq %rcx, 0x18(%rsp)
leaq 0x38(%rsp), %rdx
movl 0x8(%r12), %esi
movq %rdx, %rbx
movq %r14, %rdi
callq 0xb3ca
movq %rax, %rbp
movl 0x8(%r12), %esi
movq %r14, %rdi
callq 0x130d0
movq %r14, %rdi
movl %eax, %esi
callq 0x1b382
movq %rbx, %rdx
cmpl $0x7, 0x10(%rbp)
jne 0x18ff1
cmpb $0x0, 0x5a(%rbp)
je 0x18fff
movq (%r12), %r12
testq %r12, %r12
jne 0x18fb8
jmp 0x1918b
movq 0x20(%rax), %rcx
cmpq 0x28(%rax), %rcx
je 0x18ff1
cmpl $0xc, 0xc(%rax)
je 0x18ff1
movl 0x18(%rbp), %r15d
testq %r15, %r15
je 0x19080
movq 0x20(%r14), %rax
movq %r15, %rcx
shlq $0x4, %rcx
cmpl $0x3, 0x8(%rax,%rcx)
jne 0x18ff1
movq %rbp, %r13
addq $0x8, %r13
movq 0x10(%rsp), %rdi
movq %r13, %rsi
callq 0x230c8
movq %rbx, %rdx
testq %rax, %rax
jne 0x18ff1
movq 0x18(%rsp), %rdi
movq %r13, %rsi
callq 0x230c8
movq %rbx, %rdx
testq %rax, %rax
jne 0x18ff1
movq %r14, %rdi
movl %r15d, %esi
callq 0x1c036
movq %rbx, %rdx
movb $0x1, %cl
movb %cl, 0x10a(%rax)
movl %r15d, 0x3c(%rbp)
movb %cl, 0x39(%rbp)
movb %cl, 0x5b(%rbp)
jmp 0x18ff1
movq %rbp, %r15
addq $0x8, %r15
movq 0x18(%rsp), %rdi
movq %r15, %rsi
callq 0x230c8
movq %rbx, %rdx
testq %rax, %rax
jne 0x18ff1
movq 0x10(%rsp), %rdi
movq %r15, %rsi
callq 0x230c8
movq %rbx, %rdx
testq %rax, %rax
je 0x18ff1
cmpq $0x1, 0x28(%rax)
jne 0x18ff1
movq %rax, 0x28(%rsp)
movq %r15, 0x20(%rsp)
movq %rdx, %r15
movq %rdx, %rdi
movq 0x30(%rsp), %rsi
callq 0x7648
movq 0x20(%r12), %r13
testq %r13, %r13
je 0x190fa
movl 0x8(%r13), %esi
movq %r15, %rdi
callq 0x7654
movq (%r13), %r13
jmp 0x190e3
movq 0x28(%rsp), %rdi
addq $0x10, %rdi
movl 0x40(%rsp), %eax
movl %eax, 0xc(%rsp)
leaq 0xc(%rsp), %rsi
callq 0x1f4b4
testq %rax, %rax
je 0x19165
movq 0x20(%rsp), %rax
movl (%rax), %edx
leaq 0x48(%rsp), %r15
movq %r15, %rdi
movq %r14, %rsi
callq 0x18eec
movl 0xc(%rsp), %esi
movq %r14, %rdi
callq 0x7870
movq %r14, %rdi
movq %rax, %rsi
movq %r15, %rdx
callq 0x1531a
movl 0x5c(%rsp), %r15d
cmpl $0x1, 0x60(%rsp)
setne %al
testl %r15d, %r15d
sete %cl
orb %al, %cl
cmpb $0x1, %cl
jne 0x1916d
movq %rbx, %rdx
jmp 0x18ff1
movl %r15d, %eax
movq 0x20(%r14), %rcx
shlq $0x4, %rax
cmpl $0x3, 0x8(%rcx,%rax)
movq %rbx, %rdx
jne 0x18ff1
jmp 0x1905b
addq $0x68, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq