// File: rossy[P]crossc/SPIRV-Cross/spirv_glsl.cpp
// Function: spirv_cross::CompilerGLSL::build_composite_combiner[abi:cxx11](unsigned int, unsigned int const*, unsigned int)
string CompilerGLSL::build_composite_combiner(uint32_t return_type, const uint32_t *elems, uint32_t length)
{
	uint32_t base = 0;
	string op;
	string subop;

	// Can only merge swizzles for vectors.
	auto &type = get<SPIRType>(return_type);
	bool can_apply_swizzle_opt = type.basetype != SPIRType::Struct && type.array.empty() && type.columns == 1;
	bool swizzle_optimization = false;

	for (uint32_t i = 0; i < length; i++)
	{
		auto *e = maybe_get<SPIRExpression>(elems[i]);

		// If we're merging another scalar which belongs to the same base
		// object, just merge the swizzles to avoid triggering more than 1 expression read as much as possible!
		if (can_apply_swizzle_opt && e && e->base_expression && e->base_expression == base)
		{
			// Only supposed to be used for vector swizzle -> scalar.
			assert(!e->expression.empty() && e->expression.front() == '.');
			subop += e->expression.substr(1, string::npos);
			swizzle_optimization = true;
		}
		else
		{
			// We'll likely end up with duplicated swizzles, e.g.
			// foobar.xyz.xyz from patterns like
			// OpVectorShuffle
			// OpCompositeExtract x 3
			// OpCompositeConstruct 3x + other scalar.
			// Just modify op in-place.
			if (swizzle_optimization)
			{
				if (backend.swizzle_is_function)
					subop += "()";

				// Don't attempt to remove unity swizzling if we managed to remove duplicate swizzles.
				// The base "foo" might be vec4, while foo.xyz is vec3 (OpVectorShuffle) and looks like a vec3 due to the .xyz tacked on.
				// We only want to remove the swizzles if we're certain that the resulting base will be the same vecsize.
				// Essentially, we can only remove one set of swizzles, since that's what we have control over ...
				// Case 1:
				//  foo.yxz.xyz: Duplicate swizzle kicks in, giving foo.yxz, we are done.
				//               foo.yxz was the result of OpVectorShuffle and we don't know the type of foo.
				// Case 2:
				//  foo.xyz: Duplicate swizzle won't kick in.
				//           If foo is vec3, we can remove xyz, giving just foo.
				if (!remove_duplicate_swizzle(subop))
					remove_unity_swizzle(base, subop);

				// Strips away redundant parens if we created them during component extraction.
				strip_enclosed_expression(subop);
				swizzle_optimization = false;
				op += subop;
			}
			else
				op += subop;

			if (i)
				op += ", ";
			subop = to_expression(elems[i]);
		}

		base = e ? e->base_expression : 0;
	}

	if (swizzle_optimization)
	{
		if (backend.swizzle_is_function)
			subop += "()";

		if (!remove_duplicate_swizzle(subop))
			remove_unity_swizzle(base, subop);
		// Strips away redundant parens if we created them during component extraction.
		strip_enclosed_expression(subop);
	}

	op += subop;
	return op;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x100, %rsp            # imm = 0x100
movq %rdi, -0xd8(%rbp)
movq %rdi, %rax
movq %rax, -0xd0(%rbp)
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movl %edx, -0x14(%rbp)
movq %rcx, -0x20(%rbp)
movl %r8d, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0xc8(%rbp)
movl $0x0, -0x28(%rbp)
movb $0x0, -0x29(%rbp)
callq 0x7530
leaq -0x50(%rbp), %rdi
callq 0x7530
movq -0xc8(%rbp), %rdi
movl -0x14(%rbp), %esi
callq 0xea90
movq %rax, -0xc0(%rbp)
jmp 0x88afb
movq -0xc0(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x58(%rbp), %rcx
xorl %eax, %eax
cmpl $0xc, 0xc(%rcx)
movb %al, -0xd9(%rbp)
je 0x88b47
movq -0x58(%rbp), %rdi
addq $0x20, %rdi
callq 0x8690
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xd9(%rbp)
jne 0x88b36
jmp 0x88b47
movq -0x58(%rbp), %rax
cmpl $0x1, 0x18(%rax)
sete %al
movb %al, -0xd9(%rbp)
movb -0xd9(%rbp), %al
andb $0x1, %al
movb %al, -0x65(%rbp)
movb $0x0, -0x66(%rbp)
movl $0x0, -0x6c(%rbp)
movl -0x6c(%rbp), %eax
cmpl -0x24(%rbp), %eax
jae 0x88dd8
movq -0xc8(%rbp), %rdi
movq -0x20(%rbp), %rax
movl -0x6c(%rbp), %ecx
movl (%rax,%rcx,4), %esi
callq 0x2e790
movq %rax, -0xe8(%rbp)
jmp 0x88b88
movq -0xe8(%rbp), %rax
movq %rax, -0x78(%rbp)
testb $0x1, -0x65(%rbp)
je 0x88ca2
cmpq $0x0, -0x78(%rbp)
je 0x88ca2
movq -0x78(%rbp), %rax
cmpl $0x0, 0xc(%rax)
je 0x88ca2
movq -0x78(%rbp), %rax
movl 0xc(%rax), %eax
cmpl -0x28(%rbp), %eax
jne 0x88ca2
movq -0x78(%rbp), %rdi
addq $0x10, %rdi
callq 0x75f0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xe9(%rbp)
jne 0x88bfe
movq -0x78(%rbp), %rdi
addq $0x10, %rdi
callq 0x70e0
movsbl (%rax), %eax
cmpl $0x2e, %eax
sete %al
movb %al, -0xe9(%rbp)
movb -0xe9(%rbp), %al
testb $0x1, %al
jne 0x88c0a
jmp 0x88c0c
jmp 0x88c3c
leaq 0xbb490(%rip), %rdi     # 0x1440a3
leaq 0xb8612(%rip), %rsi     # 0x14122c
movl $0x17ba, %edx           # imm = 0x17BA
leaq 0xbb4b4(%rip), %rcx     # 0x1440da
callq 0x7260
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
jmp 0x88e78
movq -0x78(%rbp), %rsi
addq $0x10, %rsi
leaq -0x98(%rbp), %rdi
movl $0x1, %edx
movq $-0x1, %rcx
callq 0x73a0
jmp 0x88c5e
leaq -0x50(%rbp), %rdi
leaq -0x98(%rbp), %rsi
callq 0x7470
jmp 0x88c70
leaq -0x98(%rbp), %rdi
callq 0x7708
movb $0x1, -0x66(%rbp)
jmp 0x88da1
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x60(%rbp)
movl %eax, -0x64(%rbp)
leaq -0x98(%rbp), %rdi
callq 0x7708
jmp 0x88e78
testb $0x1, -0x66(%rbp)
je 0x88d35
movq -0xc8(%rbp), %rax
testb $0x1, 0x620(%rax)
je 0x88cd0
leaq 0xba171(%rip), %rsi     # 0x142e34
leaq -0x50(%rbp), %rdi
callq 0x7340
jmp 0x88cce
jmp 0x88cd0
movq -0xc8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x70230
movb %al, -0xea(%rbp)
jmp 0x88ce8
movb -0xea(%rbp), %al
testb $0x1, %al
jne 0x88d0b
jmp 0x88cf4
movq -0xc8(%rbp), %rdi
movl -0x28(%rbp), %esi
leaq -0x50(%rbp), %rdx
callq 0x887b0
jmp 0x88d09
jmp 0x88d0b
movq -0xc8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x724d0
jmp 0x88d1d
movq -0xd8(%rbp), %rdi
movb $0x0, -0x66(%rbp)
leaq -0x50(%rbp), %rsi
callq 0x7470
jmp 0x88d33
jmp 0x88d49
movq -0xd8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x7470
jmp 0x88d47
jmp 0x88d49
cmpl $0x0, -0x6c(%rbp)
je 0x88d66
movq -0xd8(%rbp), %rdi
leaq 0xbb832(%rip), %rsi     # 0x14458f
callq 0x7340
jmp 0x88d64
jmp 0x88d66
movq -0xc8(%rbp), %rsi
movq -0x20(%rbp), %rax
movl -0x6c(%rbp), %ecx
movl (%rax,%rcx,4), %edx
leaq -0xb8(%rbp), %rdi
callq 0x71b50
jmp 0x88d85
leaq -0x50(%rbp), %rdi
leaq -0xb8(%rbp), %rsi
callq 0x7430
leaq -0xb8(%rbp), %rdi
callq 0x7708
cmpq $0x0, -0x78(%rbp)
je 0x88db7
movq -0x78(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, -0xf0(%rbp)
jmp 0x88dc1
xorl %eax, %eax
movl %eax, -0xf0(%rbp)
jmp 0x88dc1
movl -0xf0(%rbp), %eax
movl %eax, -0x28(%rbp)
movl -0x6c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x6c(%rbp)
jmp 0x88b5d
testb $0x1, -0x66(%rbp)
je 0x88e51
movq -0xc8(%rbp), %rax
testb $0x1, 0x620(%rax)
je 0x88e02
leaq 0xba03f(%rip), %rsi     # 0x142e34
leaq -0x50(%rbp), %rdi
callq 0x7340
jmp 0x88e00
jmp 0x88e02
movq -0xc8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x70230
movb %al, -0xf1(%rbp)
jmp 0x88e1a
movb -0xf1(%rbp), %al
testb $0x1, %al
jne 0x88e3d
jmp 0x88e26
movq -0xc8(%rbp), %rdi
movl -0x28(%rbp), %esi
leaq -0x50(%rbp), %rdx
callq 0x887b0
jmp 0x88e3b
jmp 0x88e3d
movq -0xc8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x724d0
jmp 0x88e4f
jmp 0x88e51
movq -0xd8(%rbp), %rdi
leaq -0x50(%rbp), %rsi
callq 0x7470
jmp 0x88e63
movb $0x1, -0x29(%rbp)
leaq -0x50(%rbp), %rdi
callq 0x7708
testb $0x1, -0x29(%rbp)
jne 0x88e9b
jmp 0x88e8f
leaq -0x50(%rbp), %rdi
callq 0x7708
movq -0xd8(%rbp), %rdi
callq 0x7708
jmp 0x88eab
movq -0xd8(%rbp), %rdi
callq 0x7708
movq -0xd0(%rbp), %rax
addq $0x100, %rsp            # imm = 0x100
popq %rbp
retq
movq -0x60(%rbp), %rdi
callq 0x7640
nopw %cs:(%rax,%rax)