// File: 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
movq %rsp, %rbp
subq $0x160, %rsp            # imm = 0x160
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
movl %eax, -0xa0(%rbp)
movq -0x18(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
movl %eax, %ecx
movl -0xa0(%rbp), %eax
cmpl %ecx, %eax
je 0x1b570
movb $0x0, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x0, %eax
jne 0x1b649
movq -0x10(%rbp), %rdi
callq 0x1bd20
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1bd20
movq %rax, -0x28(%rbp)
movq -0x20(%rbp), %rdi
addq $0x8, %rdi
movq -0x28(%rbp), %rsi
addq $0x8, %rsi
callq 0xf040
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xa1(%rbp)
jne 0x1b5c2
jmp 0x1b639
movq -0x20(%rbp), %rdi
addq $0x28, %rdi
callq 0x13020
movq %rax, -0xb0(%rbp)
movq -0x28(%rbp), %rdi
addq $0x28, %rdi
callq 0x13020
movq -0xb0(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xa1(%rbp)
jne 0x1b603
jmp 0x1b639
movq -0x20(%rbp), %rdi
addq $0x38, %rdi
callq 0x13020
movq %rax, -0xb8(%rbp)
movq -0x28(%rbp), %rdi
addq $0x38, %rdi
callq 0x13020
movq -0xb8(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, -0xa1(%rbp)
movb -0xa1(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x1, %eax
jne 0x1b751
movq -0x10(%rbp), %rdi
callq 0x1bd60
movq %rax, -0x30(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1bd60
movq %rax, -0x38(%rbp)
movq -0x30(%rbp), %rdi
addq $0x8, %rdi
movq -0x38(%rbp), %rsi
addq $0x8, %rsi
callq 0xf040
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xb9(%rbp)
jne 0x1b69e
jmp 0x1b741
movq -0x30(%rbp), %rdi
addq $0x28, %rdi
movq -0x38(%rbp), %rsi
addq $0x28, %rsi
callq 0x961d0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xb9(%rbp)
jne 0x1b6c4
jmp 0x1b741
movq -0x30(%rbp), %rdi
addq $0x78, %rdi
callq 0x13020
movq %rax, -0xc8(%rbp)
movq -0x38(%rbp), %rdi
addq $0x78, %rdi
callq 0x13020
movq -0xc8(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xb9(%rbp)
jne 0x1b705
jmp 0x1b741
movq -0x30(%rbp), %rdi
addq $0x88, %rdi
callq 0x13020
movq %rax, -0xd0(%rbp)
movq -0x38(%rbp), %rdi
addq $0x88, %rdi
callq 0x13020
movq -0xd0(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, -0xb9(%rbp)
movb -0xb9(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x2, %eax
jne 0x1b845
movq -0x10(%rbp), %rdi
callq 0x1bda0
movq %rax, -0x40(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1bda0
movq %rax, -0x48(%rbp)
movq -0x40(%rbp), %rdi
addq $0x8, %rdi
callq 0x13020
movq %rax, -0xe0(%rbp)
movq -0x48(%rbp), %rdi
addq $0x8, %rdi
callq 0x13020
movq -0xe0(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xd1(%rbp)
jne 0x1b7be
jmp 0x1b835
movq -0x40(%rbp), %rdi
addq $0x18, %rdi
callq 0x13020
movq %rax, -0xe8(%rbp)
movq -0x48(%rbp), %rdi
addq $0x18, %rdi
callq 0x13020
movq -0xe8(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xd1(%rbp)
jne 0x1b7ff
jmp 0x1b835
movq -0x40(%rbp), %rdi
addq $0x28, %rdi
callq 0x13020
movq %rax, -0xf0(%rbp)
movq -0x48(%rbp), %rdi
addq $0x28, %rdi
callq 0x13020
movq -0xf0(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, -0xd1(%rbp)
movb -0xd1(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x3, %eax
jne 0x1b980
movq -0x10(%rbp), %rdi
callq 0x1bde0
movq %rax, -0x50(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1bde0
movq %rax, -0x58(%rbp)
movq -0x50(%rbp), %rdi
addq $0x8, %rdi
callq 0x13020
movq %rax, -0xf8(%rbp)
movq -0x58(%rbp), %rdi
addq $0x8, %rdi
callq 0x13020
movq -0xf8(%rbp), %rdi
movq %rax, %rsi
callq 0x1be20
testb $0x1, %al
jne 0x1b8d5
movq -0x50(%rbp), %rdi
addq $0x18, %rdi
callq 0x13370
movq %rax, -0x100(%rbp)
movq -0x58(%rbp), %rdi
addq $0x18, %rdi
callq 0x13370
movq %rax, %rcx
movq -0x100(%rbp), %rax
cmpq %rcx, %rax
je 0x1b8de
movb $0x0, -0x1(%rbp)
jmp 0x1bcfa
movq $0x0, -0x60(%rbp)
movq -0x60(%rbp), %rax
movq %rax, -0x108(%rbp)
movq -0x50(%rbp), %rdi
addq $0x18, %rdi
callq 0x13370
movq %rax, %rcx
movq -0x108(%rbp), %rax
cmpq %rcx, %rax
jae 0x1b977
movq -0x50(%rbp), %rdi
addq $0x18, %rdi
movq -0x60(%rbp), %rsi
callq 0x133e0
movq %rax, %rdi
callq 0x13020
movq %rax, -0x110(%rbp)
movq -0x58(%rbp), %rdi
addq $0x18, %rdi
movq -0x60(%rbp), %rsi
callq 0x133e0
movq %rax, %rdi
callq 0x13020
movq -0x110(%rbp), %rdi
movq %rax, %rsi
callq 0x1be20
testb $0x1, %al
jne 0x1b95b
jmp 0x1b964
movb $0x0, -0x1(%rbp)
jmp 0x1bcfa
jmp 0x1b966
movq -0x60(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x60(%rbp)
jmp 0x1b8e6
movb $0x1, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x4, %eax
jne 0x1b9e7
movq -0x10(%rbp), %rdi
callq 0x1be50
movq %rax, -0x68(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1be50
movq %rax, -0x70(%rbp)
movq -0x68(%rbp), %rax
movl 0x8(%rax), %ecx
movq -0x70(%rbp), %rdx
xorl %eax, %eax
cmpl 0x8(%rdx), %ecx
movb %al, -0x111(%rbp)
jne 0x1b9d7
movq -0x68(%rbp), %rax
movl 0xc(%rax), %eax
movq -0x70(%rbp), %rcx
cmpl 0xc(%rcx), %eax
sete %al
movb %al, -0x111(%rbp)
movb -0x111(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xb, %eax
je 0x1ba7b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xc, %eax
je 0x1ba7b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xd, %eax
je 0x1ba7b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xe, %eax
je 0x1ba7b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x6, %eax
je 0x1ba7b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x7, %eax
je 0x1ba7b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x8, %eax
je 0x1ba7b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x9, %eax
je 0x1ba7b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xf, %eax
je 0x1ba7b
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x10, %eax
jne 0x1bb1c
movq -0x10(%rbp), %rdi
callq 0x1be90
movq %rax, -0x78(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1be90
movq %rax, -0x80(%rbp)
movq -0x78(%rbp), %rdi
addq $0x8, %rdi
callq 0x13020
movq %rax, -0x120(%rbp)
movq -0x80(%rbp), %rdi
addq $0x8, %rdi
callq 0x13020
movq -0x120(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0x112(%rbp)
jne 0x1bad6
jmp 0x1bb0c
movq -0x78(%rbp), %rdi
addq $0x18, %rdi
callq 0x13020
movq %rax, -0x128(%rbp)
movq -0x80(%rbp), %rdi
addq $0x18, %rdi
callq 0x13020
movq -0x128(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, -0x112(%rbp)
movb -0x112(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xa, %eax
jne 0x1bb74
movq -0x10(%rbp), %rdi
callq 0x1bed0
movq %rax, %rdi
addq $0x8, %rdi
callq 0x13020
movq %rax, -0x130(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1bed0
movq %rax, %rdi
addq $0x8, %rdi
callq 0x13020
movq -0x130(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x5, %eax
jne 0x1bc1e
movq -0x10(%rbp), %rdi
callq 0x1bf10
movq %rax, -0x88(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1bf10
movq %rax, -0x90(%rbp)
movq -0x88(%rbp), %rdi
addq $0x8, %rdi
callq 0x13020
movq %rax, -0x140(%rbp)
movq -0x90(%rbp), %rdi
addq $0x8, %rdi
callq 0x13020
movq -0x140(%rbp), %rdi
movq %rax, %rsi
callq 0x1b530
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0x131(%rbp)
jne 0x1bbed
jmp 0x1bc0e
movq -0x88(%rbp), %rdi
addq $0x18, %rdi
movq -0x90(%rbp), %rsi
addq $0x18, %rsi
callq 0x95d80
movb %al, -0x131(%rbp)
movb -0x131(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x11, %eax
jne 0x1bc5e
movq -0x10(%rbp), %rdi
callq 0x1bf80
movq %rax, -0x148(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1bf80
movq -0x148(%rbp), %rdi
movq %rax, %rsi
callq 0x1bf50
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x1bcfa
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x12, %eax
jne 0x1bc9b
movq -0x10(%rbp), %rdi
callq 0x1bff0
movq %rax, -0x150(%rbp)
movq -0x18(%rbp), %rdi
callq 0x1bff0
movq -0x150(%rbp), %rdi
movq %rax, %rsi
callq 0x1bfc0
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x1bcfa
movl $0x10, %edi
callq 0xa1d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x158(%rbp)
leaq 0x7fc07(%rip), %rsi     # 0x9b8c0
callq 0xa540
jmp 0x1bcc0
movq -0x158(%rbp), %rdi
movq 0xcb302(%rip), %rsi     # 0xe6fd0
movq 0xcb2bb(%rip), %rdx     # 0xe6f90
callq 0xa610
movq -0x158(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x98(%rbp)
movl %eax, -0x9c(%rbp)
callq 0xa2c0
jmp 0x1bd08
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x160, %rsp            # imm = 0x160
popq %rbp
retq
movq -0x98(%rbp), %rdi
callq 0xa650
nopw %cs:(%rax,%rax)