// File: /workspace/github_cpp_makefile_star2_O2/rossy[P]crossc/SPIRV-Cross/spirv_cross.cpp
// Function: spirv_cross::Compiler::CombinedImageSamplerHandler::handle(spv::Op, unsigned int const*, unsigned int)
bool Compiler::CombinedImageSamplerHandler::handle(Op opcode, const uint32_t *args, uint32_t length)
{
	// We need to figure out where samplers and images are loaded from, so do only the bare bones compilation we need.
	bool is_fetch = false;

	switch (opcode)
	{
	case OpLoad:
	{
		if (length < 3)
			return false;

		uint32_t result_type = args[0];

		auto &type = compiler.get<SPIRType>(result_type);
		bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
		bool separate_sampler = type.basetype == SPIRType::Sampler;

		// If not separate image or sampler, don't bother.
		if (!separate_image && !separate_sampler)
			return true;

		uint32_t id = args[1];
		uint32_t ptr = args[2];
		compiler.set<SPIRExpression>(id, "", result_type, true);
		compiler.register_read(id, ptr, true);
		return true;
	}

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

		// Technically, it is possible to have arrays of textures and arrays of samplers and combine them, but this becomes essentially
		// impossible to implement, since we don't know which concrete sampler we are accessing.
		// One potential way is to create a combinatorial explosion where N textures and M samplers are combined into N * M sampler2Ds,
		// but this seems ridiculously complicated for a problem which is easy to work around.
		// Checking access chains like this assumes we don't have samplers or textures inside uniform structs, but this makes no sense.

		uint32_t result_type = args[0];

		auto &type = compiler.get<SPIRType>(result_type);
		bool separate_image = type.basetype == SPIRType::Image && type.image.sampled == 1;
		bool separate_sampler = type.basetype == SPIRType::Sampler;
		if (separate_sampler)
			SPIRV_CROSS_THROW(
			    "Attempting to use arrays or structs of separate samplers. This is not possible to statically "
			    "remap to plain GLSL.");

		if (separate_image)
		{
			uint32_t id = args[1];
			uint32_t ptr = args[2];
			compiler.set<SPIRExpression>(id, "", result_type, true);
			compiler.register_read(id, ptr, true);
		}
		return true;
	}

	case OpImageFetch:
	case OpImageQuerySizeLod:
	case OpImageQuerySize:
	case OpImageQueryLevels:
	case OpImageQuerySamples:
	{
		// If we are fetching from a plain OpTypeImage or querying LOD, we must pre-combine with our dummy sampler.
		auto *var = compiler.maybe_get_backing_variable(args[2]);
		if (!var)
			return true;

		auto &type = compiler.get<SPIRType>(var->basetype);
		if (type.basetype == SPIRType::Image && type.image.sampled == 1 && type.image.dim != DimBuffer)
		{
			if (compiler.dummy_sampler_id == 0)
				SPIRV_CROSS_THROW("texelFetch without sampler was found, but no dummy sampler has been created with "
				                  "build_dummy_sampler_for_combined_images().");

			// Do it outside.
			is_fetch = true;
			break;
		}

		return true;
	}

	case OpSampledImage:
		// Do it outside.
		break;

	default:
		return true;
	}

	// Registers sampler2D calls used in case they are parameters so
	// that their callees know which combined image samplers to propagate down the call stack.
	if (!functions.empty())
	{
		auto &callee = *functions.top();
		if (callee.do_combined_parameters)
		{
			uint32_t image_id = args[2];

			auto *image = compiler.maybe_get_backing_variable(image_id);
			if (image)
				image_id = image->self;

			uint32_t sampler_id = is_fetch ? compiler.dummy_sampler_id : args[3];
			auto *sampler = compiler.maybe_get_backing_variable(sampler_id);
			if (sampler)
				sampler_id = sampler->self;

			auto &combined_type = compiler.get<SPIRType>(args[0]);
			register_combined_image_sampler(callee, image_id, sampler_id, combined_type.image.depth);
		}
	}

	// For function calls, we need to remap IDs which are function parameters into global variables.
	// This information is statically known from the current place in the call stack.
	// Function parameters are not necessarily pointers, so if we don't have a backing variable, remapping will know
	// which backing variable the image/sample came from.
	uint32_t image_id = remap_parameter(args[2]);
	uint32_t sampler_id = is_fetch ? compiler.dummy_sampler_id : remap_parameter(args[3]);

	auto itr = find_if(begin(compiler.combined_image_samplers), end(compiler.combined_image_samplers),
	                   [image_id, sampler_id](const CombinedImageSampler &combined) {
		                   return combined.image_id == image_id && combined.sampler_id == sampler_id;
	                   });

	if (itr == end(compiler.combined_image_samplers))
	{
		uint32_t sampled_type;
		if (is_fetch)
		{
			// Have to invent the sampled image type.
			sampled_type = compiler.ir.increase_bound_by(1);
			auto &type = compiler.set<SPIRType>(sampled_type);
			type = compiler.expression_type(args[2]);
			type.self = sampled_type;
			type.basetype = SPIRType::SampledImage;
			type.image.depth = false;
		}
		else
		{
			sampled_type = args[0];
		}

		auto id = compiler.ir.increase_bound_by(2);
		auto type_id = id + 0;
		auto combined_id = id + 1;

		// Make a new type, pointer to OpTypeSampledImage, so we can make a variable of this type.
		// We will probably have this type lying around, but it doesn't hurt to make duplicates for internal purposes.
		auto &type = compiler.set<SPIRType>(type_id);
		auto &base = compiler.get<SPIRType>(sampled_type);
		type = base;
		type.pointer = true;
		type.storage = StorageClassUniformConstant;

		// Build new variable.
		compiler.set<SPIRVariable>(combined_id, type_id, StorageClassUniformConstant, 0);

		// Inherit RelaxedPrecision (and potentially other useful flags if deemed relevant).
		auto &new_flags = compiler.ir.meta[combined_id].decoration.decoration_flags;
		// Fetch inherits precision from the image, not sampler (there is no sampler).
		auto &old_flags = compiler.ir.meta[is_fetch ? image_id : sampler_id].decoration.decoration_flags;
		new_flags.reset();
		if (old_flags.get(DecorationRelaxedPrecision))
			new_flags.set(DecorationRelaxedPrecision);

		// Propagate the array type for the original image as well.
		auto *var = compiler.maybe_get_backing_variable(image_id);
		if (var)
		{
			auto &parent_type = compiler.get<SPIRType>(var->basetype);
			type.array = parent_type.array;
			type.array_size_literal = parent_type.array_size_literal;
		}

		compiler.combined_image_samplers.push_back({ combined_id, image_id, sampler_id });
	}

	return true;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x48, %rsp
movq %rdx, %r15
movq %rdi, %r14
movb $0x1, %r13b
leal -0x41(%rsi), %eax
cmpl $0x2a, %eax
ja 0x142ae
movabsq $0x6c040000000, %rdx    # imm = 0x6C040000000
btq %rax, %rdx
jae 0x1417b
movq 0x8(%r14), %rdi
movl 0x8(%r15), %esi
callq 0x1067e
testq %rax, %rax
je 0x14579
movq 0x8(%r14), %rdi
movl 0xc(%rax), %esi
callq 0x90a4
cmpl $0xd, 0xc(%rax)
jne 0x14579
cmpl $0x1, 0x8c(%rax)
jne 0x14579
cmpl $0x5, 0x84(%rax)
je 0x14579
movq 0x8(%r14), %rax
movb $0x1, %r13b
cmpl $0x0, 0x39c(%rax)
jne 0x141f2
pushq $0x10
popq %rdi
callq 0x6140
movq %rax, %rbx
leaq 0x7be68(%rip), %rsi     # 0x8ffa7
leaq 0x18(%rsp), %rdi
leaq 0xc(%rsp), %rdx
callq 0x6100
movb $0x1, %bpl
leaq 0x18(%rsp), %rsi
movq %rbx, %rdi
callq 0x6f6e
xorl %ebp, %ebp
leaq 0xd2c59(%rip), %rsi     # 0xe6dc0
movq 0xd3e72(%rip), %rdx     # 0xe7fe0
movq %rbx, %rdi
callq 0x6490
jmp 0x14614
pushq $0x3
popq %rdx
btq %rax, %rdx
jae 0x141e5
cmpl $0x3, %ecx
jb 0x142c0
movl (%r15), %esi
movl %esi, 0xc(%rsp)
movq 0x8(%r14), %rdi
callq 0x90a4
movl 0xc(%rax), %ecx
cmpl $0xf, %ecx
je 0x145cb
cmpl $0xd, %ecx
jne 0x14579
cmpl $0x1, 0x8c(%rax)
jne 0x14579
movl 0x4(%r15), %ebx
movl 0x8(%r15), %ebp
movq 0x8(%r14), %rdi
leaq 0x18(%rsp), %r8
movb $0x1, (%r8)
leaq 0x7b6ac(%rip), %rdx     # 0x8f887
leaq 0xc(%rsp), %rcx
jmp 0x143dc
cmpq $0x15, %rax
jne 0x142ae
xorl %r13d, %r13d
movq 0x90(%r14), %rax
cmpq 0x70(%r14), %rax
je 0x1428e
cmpq 0x98(%r14), %rax
jne 0x1421c
movq 0xa8(%r14), %rcx
movl $0x200, %eax            # imm = 0x200
addq -0x8(%rcx), %rax
movq -0x8(%rax), %rbx
cmpb $0x1, 0xca(%rbx)
jne 0x1428e
movl 0x8(%r15), %ebp
movq 0x8(%r14), %rdi
movl %ebp, %esi
callq 0x1067e
testq %rax, %rax
je 0x14240
movl 0x8(%rax), %ebp
movq 0x8(%r14), %rdi
leaq 0x39c(%rdi), %rax
leaq 0xc(%r15), %rcx
testb %r13b, %r13b
cmovneq %rax, %rcx
movl (%rcx), %r12d
movl %r12d, %esi
callq 0x1067e
testq %rax, %rax
je 0x1426a
movl 0x8(%rax), %r12d
movq 0x8(%r14), %rdi
movl (%r15), %esi
callq 0x90a4
movzbl 0x88(%rax), %r8d
movq %r14, %rdi
movq %rbx, %rsi
movl %ebp, %edx
movl %r12d, %ecx
callq 0x13a42
movl 0x8(%r15), %esi
movq %r14, %rdi
callq 0x1381a
movl %eax, %ebp
testb %r13b, %r13b
je 0x142c8
movq 0x8(%r14), %rdi
movl 0x39c(%rdi), %r12d
jmp 0x142db
cmpl $0x3d, %esi
jne 0x14579
cmpl $0x3, %ecx
jae 0x14388
xorl %r13d, %r13d
jmp 0x14579
movl 0xc(%r15), %esi
movq %r14, %rdi
callq 0x1381a
movl %eax, %r12d
movq 0x8(%r14), %rdi
movq 0x1d8(%rdi), %r8
movq 0x1e0(%rdi), %rsi
movq %rsi, %rcx
subq %r8, %rcx
pushq $0xc
popq %r9
movq %rcx, %rax
cqto
idivq %r9
sarq $0x2, %rax
addq $0x18, %r8
testq %rax, %rax
jle 0x1434d
cmpl %ebp, -0x14(%r8)
jne 0x14314
cmpl %r12d, -0x10(%r8)
je 0x1437c
cmpl %ebp, -0x8(%r8)
jne 0x14320
cmpl %r12d, -0x4(%r8)
je 0x14382
cmpl %ebp, 0x4(%r8)
jne 0x14330
cmpl %r12d, 0x8(%r8)
je 0x143fc
cmpl %ebp, 0x10(%r8)
jne 0x14340
cmpl %r12d, 0x14(%r8)
je 0x143f8
decq %rax
addq $0x30, %r8
addq $-0x30, %rcx
jmp 0x14303
movq %rcx, %rax
cqto
idivq %r9
leaq -0x18(%r8), %rcx
cmpq $0x1, %rax
je 0x145b5
cmpq $0x3, %rax
je 0x1458b
cmpq $0x2, %rax
je 0x145a2
jmp 0x1440c
addq $-0x18, %r8
jmp 0x143fc
addq $-0xc, %r8
jmp 0x143fc
movl (%r15), %esi
movl %esi, 0x18(%rsp)
movq 0x8(%r14), %rdi
callq 0x90a4
movl 0xc(%rax), %ecx
movl 0x8c(%rax), %eax
movl %ecx, %edx
xorl $0xd, %edx
xorl $0x1, %eax
orl %edx, %eax
sete %al
cmpl $0xf, %ecx
je 0x143bb
testb %al, %al
je 0x14579
movl 0x4(%r15), %ebx
movl 0x8(%r15), %ebp
movq 0x8(%r14), %rdi
leaq 0xc(%rsp), %r8
movb $0x1, (%r8)
leaq 0x7b4b0(%rip), %rdx     # 0x8f887
leaq 0x18(%rsp), %rcx
movl %ebx, %esi
callq 0x17816
movq 0x8(%r14), %rdi
pushq $0x1
popq %rcx
movl %ebx, %esi
movl %ebp, %edx
callq 0x106dc
jmp 0x14579
addq $0xc, %r8
movq %r8, %rcx
cmpq %rsi, %rcx
je 0x1440c
movb $0x1, %r13b
jmp 0x14579
testb %r13b, %r13b
je 0x1445f
addq $0x8, %rdi
pushq $0x1
popq %rsi
callq 0x202bc
movl %eax, %ebx
movq 0x8(%r14), %rdi
movl %eax, %esi
callq 0x17718
movq %rax, %r13
movq 0x8(%r14), %rdi
movl 0x8(%r15), %esi
callq 0x104b0
movq %r13, %rdi
movq %rax, %rsi
callq 0x173b0
movl %ebx, 0x8(%r13)
movl $0xe, 0xc(%r13)
movb $0x0, 0x88(%r13)
movl %ebp, 0x10(%rsp)
jmp 0x14467
movl (%r15), %ebx
movl %r12d, 0x10(%rsp)
movq 0x8(%r14), %rdi
addq $0x8, %rdi
pushq $0x2
popq %rsi
callq 0x202bc
leaq 0xc(%rsp), %rcx
movl %eax, (%rcx)
leal 0x1(%rax), %r13d
movq 0x8(%r14), %rdi
movl %eax, %esi
callq 0x17718
movq %rax, %r15
movq 0x8(%r14), %rdi
movl %ebx, %esi
callq 0x90a4
movq %r15, %rdi
movq %rax, %rsi
callq 0x173b0
movb $0x1, 0x60(%r15)
movq %r15, 0x38(%rsp)
andl $0x0, 0x64(%r15)
movq 0x8(%r14), %rdi
leaq 0x18(%rsp), %rcx
andl $0x0, (%rcx)
leaq 0x14(%rsp), %r8
andl $0x0, (%r8)
movl %r13d, %esi
leaq 0xc(%rsp), %rdx
callq 0x17734
movq 0x8(%r14), %rax
movq 0x38(%rax), %r15
movq %r13, 0x40(%rsp)
imulq $0x148, %r13, %rax      # imm = 0x148
leaq (%r15,%rax), %rbx
addq $0x60, %rbx
movl 0x10(%rsp), %eax
imulq $0x148, %rax, %r13      # imm = 0x148
movq %rbx, %rdi
callq 0x17770
testb $0x1, 0x60(%r15,%r13)
je 0x14511
orb $0x1, (%rbx)
movq 0x8(%r14), %rdi
movl %ebp, %esi
callq 0x1067e
testq %rax, %rax
movb $0x1, %r13b
je 0x14558
movq 0x8(%r14), %rdi
movl 0xc(%rax), %esi
callq 0x90a4
movq %rax, %rbx
leaq 0x20(%rax), %rsi
movq 0x38(%rsp), %r15
leaq 0x20(%r15), %rdi
callq 0x17852
addq $0x38, %rbx
addq $0x38, %r15
movq %r15, %rdi
movq %rbx, %rsi
callq 0x1791c
movl $0x1d8, %edi            # imm = 0x1D8
addq 0x8(%r14), %rdi
leaq 0x18(%rsp), %rsi
movq 0x40(%rsp), %rax
movl %eax, (%rsi)
movl %ebp, 0x4(%rsi)
movl %r12d, 0x8(%rsi)
callq 0x1e2ba
movl %r13d, %eax
addq $0x48, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
cmpl %ebp, -0x14(%r8)
jne 0x1459b
cmpl %r12d, -0x10(%r8)
je 0x143ff
addq $-0xc, %r8
movq %r8, %rcx
cmpl %ebp, 0x4(%rcx)
jne 0x145b1
cmpl %r12d, 0x8(%rcx)
je 0x143ff
addq $0xc, %rcx
movl 0x4(%rcx), %eax
xorl %ebp, %eax
movl 0x8(%rcx), %edx
xorl %r12d, %edx
orl %eax, %edx
cmovneq %rsi, %rcx
jmp 0x143ff
pushq $0x10
popq %rdi
callq 0x6140
movq %rax, %rbx
leaq 0x7b958(%rip), %rsi     # 0x8ff35
leaq 0x18(%rsp), %rdi
leaq 0x14(%rsp), %rdx
callq 0x6100
movb $0x1, %bpl
leaq 0x18(%rsp), %rsi
movq %rbx, %rdi
callq 0x6f6e
xorl %ebp, %ebp
leaq 0xd27bb(%rip), %rsi     # 0xe6dc0
movq 0xd39d4(%rip), %rdx     # 0xe7fe0
movq %rbx, %rdi
callq 0x6490
jmp 0x14618
jmp 0x1462c
movq %rax, %r14
leaq 0x18(%rsp), %rdi
callq 0x6548
testb %bpl, %bpl
jne 0x1462f
jmp 0x14637
movq %rax, %r14
movq %rbx, %rdi
callq 0x6200
movq %r14, %rdi
callq 0x64b0
nop