// File: /workspace/github_cpp_makefile_star2_O2/pfnet-research[P]pml/src/expr_ast.cpp
// Function: ast::operator==(ast::expr_t const&, ast::expr_t const&)
bool operator==(expr_t const& lhs, expr_t const& rhs) {
    if (lhs.kind() != rhs.kind())
        return false;

    if (lhs.kind() == expr_kind_t::Let) {
        auto const& l = cast<let_expr_t>(lhs);
        auto const& r = cast<let_expr_t>(rhs);
        return l.name == r.name && *l.init == *r.init && *l.body == *r.body;
    }
    if (lhs.kind() == expr_kind_t::LetFun) {
        auto const& l = cast<letfun_expr_t>(lhs);
        auto const& r = cast<letfun_expr_t>(rhs);
        return
            l.name == r.name && l.type == r.type &&
            *l.init == *r.init && *l.body == *r.body;
    }
    if (lhs.kind() == expr_kind_t::If) {
        auto const& l = cast<if_expr_t>(lhs);
        auto const& r = cast<if_expr_t>(rhs);
        return
            *l.cond_expr == *r.cond_expr &&
            *l.true_expr == *r.true_expr && *l.false_expr == *r.false_expr;
    }
    if (lhs.kind() == expr_kind_t::App) {
        auto const& l = cast<app_expr_t>(lhs);
        auto const& r = cast<app_expr_t>(rhs);
        if (*l.f != *r.f || l.args.size() != r.args.size())
            return false;
        for (size_t i=0; i<l.args.size(); ++i) {
            if (*l.args[i] != *r.args[i])
                return false;
        }
        return true;
    }
    if (lhs.kind() == expr_kind_t::Rand) {
        auto const& l = cast<rand_expr_t>(lhs);
        auto const& r = cast<rand_expr_t>(rhs);
        return l.start == r.start && l.end == r.end;
    }
    if (lhs.kind() == expr_kind_t::Eq ||
            lhs.kind() == expr_kind_t::Neq ||
            lhs.kind() == expr_kind_t::Leq ||
            lhs.kind() == expr_kind_t::Geq ||
            lhs.kind() == expr_kind_t::Add ||
            lhs.kind() == expr_kind_t::Sub ||
            lhs.kind() == expr_kind_t::Mul ||
            lhs.kind() == expr_kind_t::Div ||
            lhs.kind() == expr_kind_t::And ||
            lhs.kind() == expr_kind_t::Or) {
        auto const& l = cast<binop_expr_t>(lhs);
        auto const& r = cast<binop_expr_t>(rhs);
        return *l.lhs == *r.lhs && *l.rhs == *r.rhs;
    }
    if (lhs.kind() == expr_kind_t::Neg)
        return *cast<neg_expr_t>(lhs).inner == *cast<neg_expr_t>(rhs).inner;
    if (lhs.kind() == expr_kind_t::Typed) {
        auto const& l = cast<typed_expr_t>(lhs);
        auto const& r = cast<typed_expr_t>(rhs);
        return *l.expr == *r.expr && l.type == r.type;
    }
    if (lhs.kind() == expr_kind_t::Int) {
        return cast<int_expr_t>(lhs) == cast<int_expr_t>(rhs);
    }
    if (lhs.kind() == expr_kind_t::Bool)
        return cast<bool_expr_t>(lhs) == cast<bool_expr_t>(rhs);
    throw std::logic_error{"unreachable!!"};
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movq %rsi, %rbx
movq %rdi, %r14
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
movl %eax, %ebp
movq (%rbx), %rax
movq %rbx, %rdi
callq *(%rax)
cmpl %eax, %ebp
jne 0xd8a2
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
testl %eax, %eax
je 0xd5dd
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x1, %eax
jne 0xd62a
movq %r14, %rdi
callq 0xd972
movq %rax, %r14
movq %rbx, %rdi
callq 0xd972
movq %rax, %rbx
leaq 0x8(%r14), %rdi
leaq 0x8(%rax), %rsi
callq 0xa5de
testb %al, %al
je 0xd8a2
leaq 0x28(%r14), %rdi
leaq 0x28(%rbx), %rsi
callq 0x35053
testb %al, %al
je 0xd8a2
movq 0x78(%r14), %rdi
movq 0x78(%rbx), %rsi
callq 0xd52d
testb %al, %al
je 0xd8a2
movq 0x88(%r14), %r14
addq $0x88, %rbx
jmp 0xd75b
movq %r14, %rdi
callq 0xd950
movq %rax, %r14
movq %rbx, %rdi
callq 0xd950
movq %rax, %rbx
leaq 0x8(%r14), %rdi
leaq 0x8(%rax), %rsi
callq 0xa5de
testb %al, %al
je 0xd8a2
movq 0x28(%r14), %rdi
movq 0x28(%rbx), %rsi
callq 0xd52d
testb %al, %al
je 0xd8a2
movq 0x38(%r14), %r14
addq $0x38, %rbx
jmp 0xd75b
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x2, %eax
jne 0xd684
movq %r14, %rdi
callq 0xd994
movq %rax, %r14
movq %rbx, %rdi
callq 0xd994
movq %rax, %rbx
movq 0x8(%r14), %rdi
movq 0x8(%rax), %rsi
callq 0xd52d
testb %al, %al
je 0xd8a2
movq 0x18(%r14), %rdi
movq 0x18(%rbx), %rsi
callq 0xd52d
testb %al, %al
je 0xd8a2
movq 0x28(%r14), %r14
addq $0x28, %rbx
jmp 0xd75b
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x3, %eax
je 0xd791
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x4, %eax
je 0xd81a
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0xb, %eax
je 0xd728
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0xc, %eax
je 0xd728
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0xd, %eax
je 0xd728
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0xe, %eax
je 0xd728
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x6, %eax
je 0xd728
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x7, %eax
je 0xd728
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x8, %eax
je 0xd728
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x9, %eax
je 0xd728
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0xf, %eax
je 0xd728
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x10, %eax
jne 0xd763
movq %r14, %rdi
callq 0xda04
movq %rax, %r14
movq %rbx, %rdi
callq 0xda04
movq %rax, %rbx
movq 0x8(%r14), %rdi
movq 0x8(%rax), %rsi
callq 0xd52d
testb %al, %al
je 0xd8a2
movq 0x18(%r14), %r14
addq $0x18, %rbx
movq (%rbx), %rbx
jmp 0xd53e
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0xa, %eax
jne 0xd84d
movq %r14, %rdi
callq 0xda26
movq 0x8(%rax), %r14
movq %rbx, %rdi
callq 0xda26
movq %rax, %rbx
addq $0x8, %rbx
jmp 0xd75b
movq %r14, %rdi
callq 0xd9b6
movq %rax, %r14
movq %rbx, %rdi
callq 0xd9b6
movq %rax, %r15
movq 0x8(%r14), %rdi
movq 0x8(%rax), %rsi
callq 0xd9d8
testb %al, %al
jne 0xd8a2
movq 0x20(%r14), %rax
subq 0x18(%r14), %rax
movq 0x20(%r15), %rcx
subq 0x18(%r15), %rcx
cmpq %rcx, %rax
jne 0xd8a2
pushq $-0x1
popq %r12
xorl %ecx, %ecx
movq 0x18(%r14), %rax
movq 0x20(%r14), %rdx
subq %rax, %rdx
sarq $0x4, %rdx
incq %r12
cmpq %rdx, %r12
setae %bl
jae 0xd8a4
leaq 0x10(%rcx), %r13
movq (%rax,%rcx), %rdi
movq 0x18(%r15), %rax
movq (%rax,%rcx), %rsi
callq 0xd9d8
movq %r13, %rcx
testb %al, %al
je 0xd7db
jmp 0xd8a4
movq %r14, %rdi
callq 0xd9e2
movq %rax, %r14
movq %rbx, %rdi
callq 0xd9e2
movq 0x8(%r14), %xmm0
movq 0x8(%rax), %xmm1
pcmpeqd %xmm0, %xmm1
pshufd $0x50, %xmm1, %xmm0     # xmm0 = xmm1[0,0,1,1]
movmskpd %xmm0, %eax
cmpl $0x3, %eax
sete %bl
jmp 0xd8a4
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x5, %eax
jne 0xd8b5
movq %r14, %rdi
callq 0xda48
movq %rax, %r14
movq %rbx, %rdi
callq 0xda48
movq %rax, %rbx
movq 0x8(%r14), %rdi
movq 0x8(%rax), %rsi
callq 0xd52d
testb %al, %al
je 0xd8a2
addq $0x18, %r14
addq $0x18, %rbx
movq %r14, %rdi
movq %rbx, %rsi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x34db0
xorl %ebx, %ebx
movl %ebx, %eax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x11, %eax
jne 0xd8e1
movq %r14, %rdi
callq 0xda6a
movq %rax, %r14
movq %rbx, %rdi
callq 0xda6a
movl 0x8(%r14), %ecx
cmpl 0x8(%rax), %ecx
jmp 0xd848
movq (%r14), %rax
movq %r14, %rdi
callq *(%rax)
cmpl $0x12, %eax
jne 0xd90d
movq %r14, %rdi
callq 0xda8c
movq %rax, %r14
movq %rbx, %rdi
callq 0xda8c
movb 0x8(%r14), %cl
cmpb 0x8(%rax), %cl
jmp 0xd848
pushq $0x10
popq %rdi
callq 0x9150
movq %rax, %rbx
leaq 0x2ab65(%rip), %rsi     # 0x38484
movq %rax, %rdi
callq 0x93c0
movq 0x4e6a2(%rip), %rsi     # 0x5bfd0
movq 0x4e663(%rip), %rdx     # 0x5bf98
movq %rbx, %rdi
callq 0x94b0
movq %rax, %r14
movq %rbx, %rdi
callq 0x9210
movq %r14, %rdi
callq 0x94d0