// File: rossy[P]crossc/SPIRV-Cross/spirv_cross.cpp
// Function: spirv_cross::Compiler::ActiveBuiltinHandler::handle(spv::Op, unsigned int const*, unsigned int)
bool Compiler::ActiveBuiltinHandler::handle(spv::Op opcode, const uint32_t *args, uint32_t length)
{
	const auto add_if_builtin = [&](uint32_t id) {
		// Only handles variables here.
		// Builtins which are part of a block are handled in AccessChain.
		auto *var = compiler.maybe_get<SPIRVariable>(id);
		auto &decorations = compiler.ir.meta[id].decoration;
		if (var && decorations.builtin)
		{
			auto &type = compiler.get<SPIRType>(var->basetype);
			auto &flags =
			    type.storage == StorageClassInput ? compiler.active_input_builtins : compiler.active_output_builtins;
			flags.set(decorations.builtin_type);
			handle_builtin(type, decorations.builtin_type, decorations.decoration_flags);
		}
	};

	switch (opcode)
	{
	case OpStore:
		if (length < 1)
			return false;

		add_if_builtin(args[0]);
		break;

	case OpCopyMemory:
		if (length < 2)
			return false;

		add_if_builtin(args[0]);
		add_if_builtin(args[1]);
		break;

	case OpCopyObject:
	case OpLoad:
		if (length < 3)
			return false;

		add_if_builtin(args[2]);
		break;

	case OpFunctionCall:
	{
		if (length < 3)
			return false;

		uint32_t count = length - 3;
		args += 3;
		for (uint32_t i = 0; i < count; i++)
			add_if_builtin(args[i]);
		break;
	}

	case OpAccessChain:
	case OpInBoundsAccessChain:
	{
		if (length < 4)
			return false;

		// Only consider global variables, cannot consider variables in functions yet, or other
		// access chains as they have not been created yet.
		auto *var = compiler.maybe_get<SPIRVariable>(args[2]);
		if (!var)
			break;

		// Required if we access chain into builtins like gl_GlobalInvocationID.
		add_if_builtin(args[2]);

		// Start traversing type hierarchy at the proper non-pointer types.
		auto *type = &compiler.get_non_pointer_type(var->basetype);

		auto &flags =
		    type->storage == StorageClassInput ? compiler.active_input_builtins : compiler.active_output_builtins;

		uint32_t count = length - 3;
		args += 3;
		for (uint32_t i = 0; i < count; i++)
		{
			// Arrays
			if (!type->array.empty())
			{
				type = &compiler.get<SPIRType>(type->parent_type);
			}
			// Structs
			else if (type->basetype == SPIRType::Struct)
			{
				uint32_t index = compiler.get<SPIRConstant>(args[i]).scalar();

				if (index < uint32_t(compiler.ir.meta[type->self].members.size()))
				{
					auto &decorations = compiler.ir.meta[type->self].members[index];
					if (decorations.builtin)
					{
						flags.set(decorations.builtin_type);
						handle_builtin(compiler.get<SPIRType>(type->member_types[index]), decorations.builtin_type,
						               decorations.decoration_flags);
					}
				}

				type = &compiler.get<SPIRType>(type->member_types[index]);
			}
			else
			{
				// No point in traversing further. We won't find any extra builtins.
				break;
			}
		}
		break;
	}

	default:
		break;
	}

	return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xa0, %rsp
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movq %rdx, -0x20(%rbp)
movl %ecx, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0x78(%rbp)
movq %rax, -0x30(%rbp)
movl -0x14(%rbp), %eax
addl $-0x39, %eax
movl %eax, %ecx
movq %rcx, -0x70(%rbp)
subl $0x1a, %eax
ja 0x2aff7
movq -0x70(%rbp), %rax
leaq 0x11446b(%rip), %rcx    # 0x13f130
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
cmpl $0x1, -0x24(%rbp)
jae 0x2acdd
movb $0x0, -0x1(%rbp)
jmp 0x2affd
movq -0x20(%rbp), %rax
movl (%rax), %esi
leaq -0x30(%rbp), %rdi
callq 0x2b010
jmp 0x2aff9
cmpl $0x2, -0x24(%rbp)
jae 0x2ad00
movb $0x0, -0x1(%rbp)
jmp 0x2affd
movq -0x20(%rbp), %rax
movl (%rax), %esi
leaq -0x30(%rbp), %rdi
callq 0x2b010
movq -0x20(%rbp), %rax
movl 0x4(%rax), %esi
leaq -0x30(%rbp), %rdi
callq 0x2b010
jmp 0x2aff9
cmpl $0x3, -0x24(%rbp)
jae 0x2ad33
movb $0x0, -0x1(%rbp)
jmp 0x2affd
movq -0x20(%rbp), %rax
movl 0x8(%rax), %esi
leaq -0x30(%rbp), %rdi
callq 0x2b010
jmp 0x2aff9
cmpl $0x3, -0x24(%rbp)
jae 0x2ad57
movb $0x0, -0x1(%rbp)
jmp 0x2affd
movl -0x24(%rbp), %eax
subl $0x3, %eax
movl %eax, -0x34(%rbp)
movq -0x20(%rbp), %rax
addq $0xc, %rax
movq %rax, -0x20(%rbp)
movl $0x0, -0x38(%rbp)
movl -0x38(%rbp), %eax
cmpl -0x34(%rbp), %eax
jae 0x2ad99
movq -0x20(%rbp), %rax
movl -0x38(%rbp), %ecx
movl (%rax,%rcx,4), %esi
leaq -0x30(%rbp), %rdi
callq 0x2b010
movl -0x38(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x38(%rbp)
jmp 0x2ad73
jmp 0x2aff9
cmpl $0x4, -0x24(%rbp)
jae 0x2adad
movb $0x0, -0x1(%rbp)
jmp 0x2affd
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x20(%rbp), %rax
movl 0x8(%rax), %esi
callq 0x116b0
movq %rax, -0x40(%rbp)
cmpq $0x0, -0x40(%rbp)
jne 0x2add1
jmp 0x2aff9
movq -0x20(%rbp), %rax
movl 0x8(%rax), %esi
leaq -0x30(%rbp), %rdi
callq 0x2b010
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x40(%rbp), %rax
movl 0xc(%rax), %esi
callq 0x22e80
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
cmpl $0x1, 0x64(%rax)
jne 0x2ae17
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rax
addq $0x2d0, %rax            # imm = 0x2D0
movq %rax, -0x80(%rbp)
jmp 0x2ae29
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rax
addq $0x310, %rax            # imm = 0x310
movq %rax, -0x80(%rbp)
movq -0x80(%rbp), %rax
movq %rax, -0x50(%rbp)
movl -0x24(%rbp), %eax
subl $0x3, %eax
movl %eax, -0x54(%rbp)
movq -0x20(%rbp), %rax
addq $0xc, %rax
movq %rax, -0x20(%rbp)
movl $0x0, -0x58(%rbp)
movl -0x58(%rbp), %eax
cmpl -0x54(%rbp), %eax
jae 0x2aff5
movq -0x48(%rbp), %rdi
addq $0x20, %rdi
callq 0x8690
testb $0x1, %al
jne 0x2ae8a
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x48(%rbp), %rax
movl 0x9c(%rax), %esi
callq 0xea90
movq %rax, -0x48(%rbp)
jmp 0x2afe5
movq -0x48(%rbp), %rax
cmpl $0xc, 0xc(%rax)
jne 0x2afe1
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rdi
movq -0x20(%rbp), %rax
movl -0x58(%rbp), %ecx
movl (%rax,%rcx,4), %esi
callq 0x31910
movq %rax, %rdi
xorl %edx, %edx
movl %edx, %esi
callq 0x2f560
movl %eax, %ecx
movq -0x78(%rbp), %rax
movl %ecx, -0x5c(%rbp)
movl -0x5c(%rbp), %ecx
movl %ecx, -0x84(%rbp)
movq 0x8(%rax), %rdi
addq $0x8, %rdi
addq $0x30, %rdi
movq -0x48(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, %esi
callq 0xead0
movq %rax, %rdi
addq $0xd0, %rdi
callq 0x2eca0
movq %rax, %rcx
movl -0x84(%rbp), %eax
cmpl %ecx, %eax
jae 0x2afac
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rdi
addq $0x8, %rdi
addq $0x30, %rdi
movq -0x48(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, %esi
callq 0xead0
movq %rax, %rdi
addq $0xd0, %rdi
movl -0x5c(%rbp), %eax
movl %eax, %esi
callq 0x2fa30
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rax
testb $0x1, 0xcc(%rax)
je 0x2afaa
movq -0x50(%rbp), %rdi
movq -0x68(%rbp), %rax
movl 0xa0(%rax), %esi
callq 0x300d0
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x90(%rbp)
movq -0x48(%rbp), %rdi
addq $0x68, %rdi
movl -0x5c(%rbp), %eax
movl %eax, %esi
callq 0x8570
movq -0x90(%rbp), %rdi
movl (%rax), %esi
callq 0xea90
movq -0x78(%rbp), %rdi
movq %rax, %rsi
movq -0x68(%rbp), %rax
movl 0xa0(%rax), %edx
movq -0x68(%rbp), %rcx
addq $0x60, %rcx
callq 0x2a830
jmp 0x2afac
movq -0x78(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x98(%rbp)
movq -0x48(%rbp), %rdi
addq $0x68, %rdi
movl -0x5c(%rbp), %eax
movl %eax, %esi
callq 0x8570
movq -0x98(%rbp), %rdi
movl (%rax), %esi
callq 0xea90
movq %rax, -0x48(%rbp)
jmp 0x2afe3
jmp 0x2aff5
jmp 0x2afe5
jmp 0x2afe7
movl -0x58(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x58(%rbp)
jmp 0x2ae4d
jmp 0x2aff9
jmp 0x2aff9
movb $0x1, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0xa0, %rsp
popq %rbp
retq
nopl (%rax,%rax)