// File: rossy[P]crossc/SPIRV-Cross/spirv_glsl.cpp
// Function: spirv_cross::CompilerGLSL::buffer_is_packing_standard(spirv_cross::SPIRType const&, spirv_cross::BufferPackingStandard, unsigned int, unsigned int)
bool CompilerGLSL::buffer_is_packing_standard(const SPIRType &type, BufferPackingStandard packing,
                                              uint32_t start_offset, uint32_t end_offset)
{
	// This is very tricky and error prone, but try to be exhaustive and correct here.
	// SPIR-V doesn't directly say if we're using std430 or std140.
	// SPIR-V communicates this using Offset and ArrayStride decorations (which is what really matters),
	// so we have to try to infer whether or not the original GLSL source was std140 or std430 based on this information.
	// We do not have to consider shared or packed since these layouts are not allowed in Vulkan SPIR-V (they are useless anyways, and custom offsets would do the same thing).
	//
	// It is almost certain that we're using std430, but it gets tricky with arrays in particular.
	// We will assume std430, but infer std140 if we can prove the struct is not compliant with std430.
	//
	// The only two differences between std140 and std430 are related to padding alignment/array stride
	// in arrays and structs. In std140 they take minimum vec4 alignment.
	// std430 only removes the vec4 requirement.

	uint32_t offset = 0;
	uint32_t pad_alignment = 1;

	for (uint32_t i = 0; i < type.member_types.size(); i++)
	{
		auto &memb_type = get<SPIRType>(type.member_types[i]);
		auto member_flags = ir.meta[type.self].members.at(i).decoration_flags;

		// Verify alignment rules.
		uint32_t packed_alignment = type_to_packed_alignment(memb_type, member_flags, packing);
		uint32_t packed_size = type_to_packed_size(memb_type, member_flags, packing);

		if (packing_is_hlsl(packing))
		{
			// If a member straddles across a vec4 boundary, alignment is actually vec4.
			uint32_t begin_word = offset / 16;
			uint32_t end_word = (offset + packed_size - 1) / 16;
			if (begin_word != end_word)
				packed_alignment = max(packed_alignment, 16u);
		}

		uint32_t alignment = max(packed_alignment, pad_alignment);
		offset = (offset + alignment - 1) & ~(alignment - 1);

		// Field is not in the specified range anymore and we can ignore any further fields.
		if (offset >= end_offset)
			break;

		// The next member following a struct member is aligned to the base alignment of the struct that came before.
		// GL 4.5 spec, 7.6.2.2.
		if (memb_type.basetype == SPIRType::Struct)
			pad_alignment = packed_alignment;
		else
			pad_alignment = 1;

		// Only care about packing if we are in the given range
		if (offset >= start_offset)
		{
			// We only care about offsets in std140, std430, etc ...
			// For EnhancedLayout variants, we have the flexibility to choose our own offsets.
			if (!packing_has_flexible_offset(packing))
			{
				uint32_t actual_offset = type_struct_member_offset(type, i);
				if (actual_offset != offset) // This cannot be the packing we're looking for.
					return false;
			}

			// Verify array stride rules.
			if (!memb_type.array.empty() && type_to_packed_array_stride(memb_type, member_flags, packing) !=
			                                    type_struct_member_array_stride(type, i))
				return false;

			// Verify that sub-structs also follow packing rules.
			// We cannot use enhanced layouts on substructs, so they better be up to spec.
			auto substruct_packing = packing_to_substruct_packing(packing);

			if (!memb_type.member_types.empty() && !buffer_is_packing_standard(memb_type, substruct_packing))
				return false;
		}

		// Bump size.
		offset += packed_size;
	}

	return true;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x110, %rsp            # imm = 0x110
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movl %edx, -0x1c(%rbp)
movl %ecx, -0x20(%rbp)
movl %r8d, -0x24(%rbp)
movq -0x10(%rbp), %rax
movq %rax, -0xb8(%rbp)
movl $0x0, -0x28(%rbp)
movl $0x1, -0x2c(%rbp)
movl $0x0, -0x30(%rbp)
movl -0x30(%rbp), %eax
movq %rax, -0xc0(%rbp)
movq -0x18(%rbp), %rdi
addq $0x68, %rdi
callq 0x8650
movq %rax, %rcx
movq -0xc0(%rbp), %rax
cmpq %rcx, %rax
jae 0x5e416
movq -0x18(%rbp), %rdi
addq $0x68, %rdi
movl -0x30(%rbp), %eax
movl %eax, %esi
callq 0x8570
movq -0xb8(%rbp), %rdi
movl (%rax), %esi
callq 0xea90
movq -0xb8(%rbp), %rdi
movq %rax, -0x38(%rbp)
addq $0x38, %rdi
movq -0x18(%rbp), %rax
movl 0x8(%rax), %eax
movl %eax, %esi
callq 0xead0
movq %rax, %rdi
addq $0xd0, %rdi
movl -0x30(%rbp), %eax
movl %eax, %esi
callq 0x9f820
movq %rax, %rsi
addq $0x60, %rsi
leaq -0x78(%rbp), %rdi
movq %rdi, -0xd0(%rbp)
callq 0xef10
movq -0xb8(%rbp), %rdi
movq -0xd0(%rbp), %rdx
movq -0x38(%rbp), %rsi
movl -0x1c(%rbp), %ecx
callq 0x5d5c0
movl %eax, -0xc4(%rbp)
jmp 0x5e131
movq -0xb8(%rbp), %rdi
movl -0xc4(%rbp), %eax
movl %eax, -0x7c(%rbp)
movq -0x38(%rbp), %rsi
movl -0x1c(%rbp), %ecx
leaq -0x78(%rbp), %rdx
callq 0x5dbd0
movl %eax, -0xd4(%rbp)
jmp 0x5e159
movl -0xd4(%rbp), %eax
movl %eax, -0x90(%rbp)
movl -0x1c(%rbp), %edi
callq 0x5dad0
movb %al, -0xd5(%rbp)
jmp 0x5e175
movb -0xd5(%rbp), %al
testb $0x1, %al
jne 0x5e184
jmp 0x5e206
movl -0x28(%rbp), %eax
shrl $0x4, %eax
movl %eax, -0x94(%rbp)
movl -0x28(%rbp), %eax
addl -0x90(%rbp), %eax
subl $0x1, %eax
shrl $0x4, %eax
movl %eax, -0x98(%rbp)
movl -0x94(%rbp), %eax
cmpl -0x98(%rbp), %eax
je 0x5e204
movl $0x10, -0x9c(%rbp)
leaq -0x7c(%rbp), %rdi
leaq -0x9c(%rbp), %rsi
callq 0x9f7e0
movq %rax, -0xe0(%rbp)
jmp 0x5e1d6
movq -0xe0(%rbp), %rax
movl (%rax), %eax
movl %eax, -0x7c(%rbp)
jmp 0x5e204
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x88(%rbp)
movl %eax, -0x8c(%rbp)
leaq -0x78(%rbp), %rdi
callq 0xf250
jmp 0x5e428
jmp 0x5e206
leaq -0x7c(%rbp), %rdi
leaq -0x2c(%rbp), %rsi
callq 0x9f7e0
movq %rax, -0xe8(%rbp)
jmp 0x5e21c
movq -0xe8(%rbp), %rax
movl (%rax), %eax
movl %eax, -0xa0(%rbp)
movl -0x28(%rbp), %eax
addl -0xa0(%rbp), %eax
subl $0x1, %eax
movl -0xa0(%rbp), %ecx
subl $0x1, %ecx
xorl $-0x1, %ecx
andl %ecx, %eax
movl %eax, -0x28(%rbp)
movl -0x28(%rbp), %eax
cmpl -0x24(%rbp), %eax
jb 0x5e25f
movl $0x2, -0xa4(%rbp)
jmp 0x5e3dc
movq -0x38(%rbp), %rax
cmpl $0xc, 0xc(%rax)
jne 0x5e271
movl -0x7c(%rbp), %eax
movl %eax, -0x2c(%rbp)
jmp 0x5e278
movl $0x1, -0x2c(%rbp)
movl -0x28(%rbp), %eax
cmpl -0x20(%rbp), %eax
jb 0x5e3c6
movl -0x1c(%rbp), %edi
callq 0x5e440
movb %al, -0xe9(%rbp)
jmp 0x5e294
movb -0xe9(%rbp), %al
testb $0x1, %al
jne 0x5e2e7
jmp 0x5e2a0
movq -0xb8(%rbp), %rdi
movq -0x18(%rbp), %rsi
movl -0x30(%rbp), %edx
callq 0x24050
movl %eax, -0xf0(%rbp)
jmp 0x5e2bb
movl -0xf0(%rbp), %eax
movl %eax, -0xa8(%rbp)
movl -0xa8(%rbp), %eax
cmpl -0x28(%rbp), %eax
je 0x5e2e5
movb $0x0, -0x1(%rbp)
movl $0x1, -0xa4(%rbp)
jmp 0x5e3dc
jmp 0x5e2e7
movq -0x38(%rbp), %rdi
addq $0x20, %rdi
callq 0x8690
testb $0x1, %al
jne 0x5e355
movq -0xb8(%rbp), %rdi
movq -0x38(%rbp), %rsi
movl -0x1c(%rbp), %ecx
leaq -0x78(%rbp), %rdx
callq 0x5db00
movl %eax, -0xf4(%rbp)
jmp 0x5e317
movq -0xb8(%rbp), %rdi
movq -0x18(%rbp), %rsi
movl -0x30(%rbp), %edx
callq 0x24170
movl %eax, -0xf8(%rbp)
jmp 0x5e332
movl -0xf4(%rbp), %eax
movl -0xf8(%rbp), %ecx
cmpl %ecx, %eax
je 0x5e355
movb $0x0, -0x1(%rbp)
movl $0x1, -0xa4(%rbp)
jmp 0x5e3dc
movl -0x1c(%rbp), %edi
callq 0x5e470
movl %eax, -0xfc(%rbp)
jmp 0x5e365
movl -0xfc(%rbp), %eax
movl %eax, -0xac(%rbp)
movq -0x38(%rbp), %rdi
addq $0x68, %rdi
callq 0x8690
testb $0x1, %al
jne 0x5e3c4
movq -0xb8(%rbp), %rdi
movq -0x38(%rbp), %rsi
movl -0xac(%rbp), %edx
xorl %ecx, %ecx
movl $0xffffffff, %r8d       # imm = 0xFFFFFFFF
callq 0x5e040
movb %al, -0xfd(%rbp)
jmp 0x5e3a8
movb -0xfd(%rbp), %al
testb $0x1, %al
jne 0x5e3c4
jmp 0x5e3b4
movb $0x0, -0x1(%rbp)
movl $0x1, -0xa4(%rbp)
jmp 0x5e3dc
jmp 0x5e3c6
movl -0x90(%rbp), %eax
addl -0x28(%rbp), %eax
movl %eax, -0x28(%rbp)
movl $0x0, -0xa4(%rbp)
leaq -0x78(%rbp), %rdi
callq 0xf250
movl -0xa4(%rbp), %eax
movl %eax, -0x104(%rbp)
testl %eax, %eax
je 0x5e406
jmp 0x5e3f7
movl -0x104(%rbp), %eax
subl $0x1, %eax
je 0x5e41a
jmp 0x5e404
jmp 0x5e416
jmp 0x5e408
movl -0x30(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x30(%rbp)
jmp 0x5e07d
movb $0x1, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x110, %rsp            # imm = 0x110
popq %rbp
retq
movq -0x88(%rbp), %rdi
callq 0x7640
nopw %cs:(%rax,%rax)