// File: hey-yahei[P]ConvNet/src/Eltwise.cpp
// Function: Eltwise::Run(float*, float*, bool, bool)
float* Eltwise::Run(float* in1_data, float* in2_data, bool keep_in1, bool keep_in2) {
	int elt_idx;

	if (!keep_in1) {
		out_data = in1_data;
		keep_in1 = true;
	} else if (!keep_in2) {   // keep_in1 == true
		out_data = in2_data;
		in2_data = in1_data;  // now, in2 -> in1
		keep_in2 = true;
	} else {
		out_data = (float*)malloc(sizeof(float) * out_chw * out_shape[0]);
		memcpy(out_data, in1_data, sizeof(float) * out_chw * out_shape[0]);
	}

	for (int idx_bs = 0; idx_bs < out_shape[0]; idx_bs++) {
		for (int idx_c = 0; idx_c < out_shape[1]; idx_c++) {
			for (int idx_h = 0; idx_h < out_shape[2]; idx_h++) {
				for (int idx_w = 0; idx_w < out_shape[3]; idx_w++) {
					elt_idx = idx_bs * out_chw + idx_c * out_hw + idx_h * out_w + idx_w;
					if (!strcmp(elt_t, "add")) {
						out_data[elt_idx] += in2_data[elt_idx];
						if (with_relu && out_data[elt_idx] < 0.)
							out_data[elt_idx] = 0.;
					} else if (!strcmp(elt_t, "max")){
						out_data[elt_idx] = MAX(out_data[elt_idx], in2_data[elt_idx]);
						if (with_relu && out_data[elt_idx] < 0.)
							out_data[elt_idx] = 0.;
					} else {
						cerr << "Eltwise: unknown type" << endl;
						exit(1);
					}
				}
			}
		}
	}

	if (!keep_in1)
		free(in1_data);
	if (!keep_in2)
		free(in2_data);

	return out_data;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x40, %rsp
movb %r8b, %al
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
andb $0x1, %cl
movb %cl, -0x19(%rbp)
andb $0x1, %al
movb %al, -0x1a(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x38(%rbp)
testb $0x1, -0x19(%rbp)
jne 0x6cf2
movq -0x38(%rbp), %rax
movq -0x10(%rbp), %rcx
movq %rcx, 0x38(%rax)
movb $0x1, -0x19(%rbp)
jmp 0x6d55
testb $0x1, -0x1a(%rbp)
jne 0x6d12
movq -0x38(%rbp), %rax
movq -0x18(%rbp), %rcx
movq %rcx, 0x38(%rax)
movq -0x10(%rbp), %rax
movq %rax, -0x18(%rbp)
movb $0x1, -0x1a(%rbp)
jmp 0x6d53
movq -0x38(%rbp), %rax
movslq 0x30(%rax), %rdi
shlq $0x2, %rdi
movslq 0x18(%rax), %rax
imulq %rax, %rdi
callq 0x22e0
movq %rax, %rcx
movq -0x38(%rbp), %rax
movq %rcx, 0x38(%rax)
movq 0x38(%rax), %rdi
movq -0x10(%rbp), %rsi
movslq 0x30(%rax), %rdx
shlq $0x2, %rdx
movslq 0x18(%rax), %rax
imulq %rax, %rdx
callq 0x2180
jmp 0x6d55
movl $0x0, -0x24(%rbp)
movq -0x38(%rbp), %rcx
movl -0x24(%rbp), %eax
cmpl 0x18(%rcx), %eax
jge 0x6f6b
movl $0x0, -0x28(%rbp)
movq -0x38(%rbp), %rcx
movl -0x28(%rbp), %eax
cmpl 0x1c(%rcx), %eax
jge 0x6f5b
movl $0x0, -0x2c(%rbp)
movq -0x38(%rbp), %rcx
movl -0x2c(%rbp), %eax
cmpl 0x20(%rcx), %eax
jge 0x6f4b
movl $0x0, -0x30(%rbp)
movq -0x38(%rbp), %rcx
movl -0x30(%rbp), %eax
cmpl 0x24(%rcx), %eax
jge 0x6f3b
movq -0x38(%rbp), %rax
movl -0x24(%rbp), %ecx
imull 0x30(%rax), %ecx
movl -0x28(%rbp), %edx
imull 0x2c(%rax), %edx
addl %edx, %ecx
movl -0x2c(%rbp), %edx
imull 0x28(%rax), %edx
addl %edx, %ecx
addl -0x30(%rbp), %ecx
movl %ecx, -0x20(%rbp)
movq (%rax), %rdi
leaq 0x526a(%rip), %rsi      # 0xc048
callq 0x22f0
cmpl $0x0, %eax
jne 0x6e48
movq -0x38(%rbp), %rax
movq -0x18(%rbp), %rcx
movslq -0x20(%rbp), %rdx
movss (%rcx,%rdx,4), %xmm0
movq 0x38(%rax), %rcx
movslq -0x20(%rbp), %rdx
addss (%rcx,%rdx,4), %xmm0
movss %xmm0, (%rcx,%rdx,4)
testb $0x1, 0x40(%rax)
je 0x6e43
movq -0x38(%rbp), %rax
movq 0x38(%rax), %rax
movslq -0x20(%rbp), %rcx
movss (%rax,%rcx,4), %xmm0
cvtss2sd %xmm0, %xmm1
xorps %xmm0, %xmm0
ucomisd %xmm1, %xmm0
jbe 0x6e43
movq -0x38(%rbp), %rax
movq 0x38(%rax), %rax
movslq -0x20(%rbp), %rcx
xorps %xmm0, %xmm0
movss %xmm0, (%rax,%rcx,4)
jmp 0x6f2b
movq -0x38(%rbp), %rax
movq (%rax), %rdi
leaq 0x51f6(%rip), %rsi      # 0xc04c
callq 0x22f0
cmpl $0x0, %eax
jne 0x6efd
movq -0x38(%rbp), %rax
movq 0x38(%rax), %rax
movslq -0x20(%rbp), %rcx
movss (%rax,%rcx,4), %xmm0
movq -0x18(%rbp), %rax
movslq -0x20(%rbp), %rcx
ucomiss (%rax,%rcx,4), %xmm0
jbe 0x6e9b
movq -0x38(%rbp), %rax
movq 0x38(%rax), %rax
movslq -0x20(%rbp), %rcx
movss (%rax,%rcx,4), %xmm0
movss %xmm0, -0x3c(%rbp)
jmp 0x6ead
movq -0x18(%rbp), %rax
movslq -0x20(%rbp), %rcx
movss (%rax,%rcx,4), %xmm0
movss %xmm0, -0x3c(%rbp)
movq -0x38(%rbp), %rax
movss -0x3c(%rbp), %xmm0
movq 0x38(%rax), %rcx
movslq -0x20(%rbp), %rdx
movss %xmm0, (%rcx,%rdx,4)
testb $0x1, 0x40(%rax)
je 0x6efb
movq -0x38(%rbp), %rax
movq 0x38(%rax), %rax
movslq -0x20(%rbp), %rcx
movss (%rax,%rcx,4), %xmm0
cvtss2sd %xmm0, %xmm1
xorps %xmm0, %xmm0
ucomisd %xmm1, %xmm0
jbe 0x6efb
movq -0x38(%rbp), %rax
movq 0x38(%rax), %rax
movslq -0x20(%rbp), %rcx
xorps %xmm0, %xmm0
movss %xmm0, (%rax,%rcx,4)
jmp 0x6f29
movq 0xb0ec(%rip), %rdi      # 0x11ff0
leaq 0x5426(%rip), %rsi      # 0xc331
callq 0x21c0
movq %rax, %rdi
movq 0xb0a6(%rip), %rsi      # 0x11fc0
callq 0x2200
movl $0x1, %edi
callq 0x2290
jmp 0x6f2b
jmp 0x6f2d
movl -0x30(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x30(%rbp)
jmp 0x6da1
jmp 0x6f3d
movl -0x2c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x2c(%rbp)
jmp 0x6d8a
jmp 0x6f4d
movl -0x28(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x28(%rbp)
jmp 0x6d73
jmp 0x6f5d
movl -0x24(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x24(%rbp)
jmp 0x6d5c
testb $0x1, -0x19(%rbp)
jne 0x6f7a
movq -0x10(%rbp), %rdi
callq 0x2280
testb $0x1, -0x1a(%rbp)
jne 0x6f89
movq -0x18(%rbp), %rdi
callq 0x2280
movq -0x38(%rbp), %rax
movq 0x38(%rax), %rax
addq $0x40, %rsp
popq %rbp
retq
nopw (%rax,%rax)