// File: pfnet-research[P]pml/src/mdp_expr.cpp
// Function: mdp::operator==(mdp::expr_t const&, mdp::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::Int)
        return cast<int_expr_t>(lhs).n == cast<int_expr_t>(rhs).n;
    if (lhs.kind() == expr_kind_t::Real)
        return cast<real_expr_t>(lhs).d == cast<real_expr_t>(rhs).d;
    if (lhs.kind() == expr_kind_t::Bool)
        return cast<bool_expr_t>(lhs).b == cast<bool_expr_t>(rhs).b;
    if (lhs.kind() == expr_kind_t::Var)
        return cast<var_expr_t>(lhs).name == cast<var_expr_t>(rhs).name;
    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::BinOp) {
        auto const& lhs_ = cast<binop_expr_t>(lhs);
        auto const& rhs_ = cast<binop_expr_t>(rhs);
        return
            *lhs_.lhs == *rhs_.lhs && *lhs_.rhs == *rhs_.rhs &&
            lhs_.binop_kind == rhs_.binop_kind;
    }
    if (lhs.kind() == expr_kind_t::If) {
        auto const& lhs_ = cast<if_expr_t>(lhs);
        auto const& rhs_ = cast<if_expr_t>(rhs);
        return
            *lhs_.cond == *rhs_.cond &&
            *lhs_.true_branch == *rhs_.true_branch &&
            *lhs_.false_branch == *rhs_.false_branch;
    }
    if (lhs.kind() == expr_kind_t::Min) {
        auto const& lhs_args = cast<min_expr_t>(lhs).elems;
        auto const& rhs_args = cast<min_expr_t>(rhs).elems;
        if (lhs_args.size() != rhs_args.size())
            return false;
        for (size_t i=0; i<lhs_args.size(); ++i) {
            if (*lhs_args[i] != *rhs_args[i])
                return false;
        }
        return true;
    }
    if (lhs.kind() == expr_kind_t::Max) {
        auto const& lhs_args = cast<max_expr_t>(lhs).elems;
        auto const& rhs_args = cast<max_expr_t>(rhs).elems;
        if (lhs_args.size() != rhs_args.size())
            return false;
        for (size_t i=0; i<lhs_args.size(); ++i) {
            if (*lhs_args[i] != *rhs_args[i])
                return false;
        }
        return true;
    }
    if (lhs.kind() == expr_kind_t::Floor)
        return *cast<floor_expr_t>(lhs).inner == *cast<floor_expr_t>(rhs).inner;
    if (lhs.kind() == expr_kind_t::Ceil)
        return *cast<ceil_expr_t>(lhs).inner == *cast<ceil_expr_t>(rhs).inner;
    if (lhs.kind() == expr_kind_t::Pow) {
        return
            *cast<pow_expr_t>(lhs).x == *cast<pow_expr_t>(rhs).x &&
            *cast<pow_expr_t>(lhs).y == *cast<pow_expr_t>(rhs).y;
    }
    if (lhs.kind() == expr_kind_t::Mod) {
        return
            *cast<mod_expr_t>(lhs).i == *cast<mod_expr_t>(rhs).i &&
            *cast<mod_expr_t>(lhs).n == *cast<mod_expr_t>(rhs).n;
    }
    if (lhs.kind() == expr_kind_t::Log) {
        return
            *cast<log_expr_t>(lhs).x == *cast<log_expr_t>(rhs).x &&
            *cast<log_expr_t>(lhs).b == *cast<log_expr_t>(rhs).b;
    }
    throw std::logic_error{"unreachable"};
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x170, %rsp            # imm = 0x170
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
movl %eax, -0x78(%rbp)
movq -0x18(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
movl %eax, %ecx
movl -0x78(%rbp), %eax
cmpl %ecx, %eax
je 0x32cda
movb $0x0, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x0, %eax
jne 0x32d16
movq -0x10(%rbp), %rdi
callq 0x32920
movl 0x8(%rax), %eax
movl %eax, -0x7c(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32920
movq %rax, %rcx
movl -0x7c(%rbp), %eax
cmpl 0x8(%rcx), %eax
sete %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x1, %eax
jne 0x32d62
movq -0x10(%rbp), %rdi
callq 0x32960
movsd 0x8(%rax), %xmm0
movsd %xmm0, -0x88(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32960
movsd -0x88(%rbp), %xmm0
ucomisd 0x8(%rax), %xmm0
sete %al
setnp %cl
andb %cl, %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x2, %eax
jne 0x32db1
movq -0x10(%rbp), %rdi
callq 0x329a0
movb 0x8(%rax), %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x8c(%rbp)
movq -0x18(%rbp), %rdi
callq 0x329a0
movq %rax, %rcx
movl -0x8c(%rbp), %eax
movb 0x8(%rcx), %cl
andb $0x1, %cl
movzbl %cl, %ecx
cmpl %ecx, %eax
sete %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x3, %eax
jne 0x32df9
movq -0x10(%rbp), %rdi
callq 0x329e0
addq $0x8, %rax
movq %rax, -0x98(%rbp)
movq -0x18(%rbp), %rdi
callq 0x329e0
movq -0x98(%rbp), %rdi
movq %rax, %rsi
addq $0x8, %rsi
callq 0xf040
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x4, %eax
jne 0x32e51
movq -0x10(%rbp), %rdi
callq 0x32a20
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq %rax, -0xa0(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32a20
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0xa0(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x5, %eax
jne 0x32f26
movq -0x10(%rbp), %rdi
callq 0x32a60
movq %rax, -0x20(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32a60
movq %rax, -0x28(%rbp)
movq -0x20(%rbp), %rdi
addq $0x8, %rdi
callq 0xc3d0
movq %rax, -0xb0(%rbp)
movq -0x28(%rbp), %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0xb0(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xa1(%rbp)
jne 0x32ebe
jmp 0x32f16
movq -0x20(%rbp), %rdi
addq $0x18, %rdi
callq 0xc3d0
movq %rax, -0xb8(%rbp)
movq -0x28(%rbp), %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0xb8(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xa1(%rbp)
jne 0x32eff
jmp 0x32f16
movq -0x20(%rbp), %rax
movl 0x28(%rax), %eax
movq -0x28(%rbp), %rcx
cmpl 0x28(%rcx), %eax
sete %al
movb %al, -0xa1(%rbp)
movb -0xa1(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x6, %eax
jne 0x3301a
movq -0x10(%rbp), %rdi
callq 0x32aa0
movq %rax, -0x30(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32aa0
movq %rax, -0x38(%rbp)
movq -0x30(%rbp), %rdi
addq $0x8, %rdi
callq 0xc3d0
movq %rax, -0xc8(%rbp)
movq -0x38(%rbp), %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0xc8(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xb9(%rbp)
jne 0x32f93
jmp 0x3300a
movq -0x30(%rbp), %rdi
addq $0x18, %rdi
callq 0xc3d0
movq %rax, -0xd0(%rbp)
movq -0x38(%rbp), %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0xd0(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0xb9(%rbp)
jne 0x32fd4
jmp 0x3300a
movq -0x30(%rbp), %rdi
addq $0x28, %rdi
callq 0xc3d0
movq %rax, -0xd8(%rbp)
movq -0x38(%rbp), %rdi
addq $0x28, %rdi
callq 0xc3d0
movq -0xd8(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, -0xb9(%rbp)
movb -0xb9(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x7, %eax
jne 0x33115
movq -0x10(%rbp), %rdi
callq 0x32ae0
addq $0x8, %rax
movq %rax, -0x40(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32ae0
addq $0x8, %rax
movq %rax, -0x48(%rbp)
movq -0x40(%rbp), %rdi
callq 0x335f0
movq %rax, -0xe0(%rbp)
movq -0x48(%rbp), %rdi
callq 0x335f0
movq %rax, %rcx
movq -0xe0(%rbp), %rax
cmpq %rcx, %rax
je 0x3307f
movb $0x0, -0x1(%rbp)
jmp 0x33541
movq $0x0, -0x50(%rbp)
movq -0x50(%rbp), %rax
movq %rax, -0xe8(%rbp)
movq -0x40(%rbp), %rdi
callq 0x335f0
movq %rax, %rcx
movq -0xe8(%rbp), %rax
cmpq %rcx, %rax
jae 0x3310c
movq -0x40(%rbp), %rdi
movq -0x50(%rbp), %rsi
callq 0x335d0
movq %rax, %rdi
callq 0xc3d0
movq %rax, -0xf0(%rbp)
movq -0x48(%rbp), %rdi
movq -0x50(%rbp), %rsi
callq 0x335d0
movq %rax, %rdi
callq 0xc3d0
movq -0xf0(%rbp), %rdi
movq %rax, %rsi
callq 0x33560
testb $0x1, %al
jne 0x330f0
jmp 0x330f9
movb $0x0, -0x1(%rbp)
jmp 0x33541
jmp 0x330fb
movq -0x50(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x50(%rbp)
jmp 0x33087
movb $0x1, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x8, %eax
jne 0x33210
movq -0x10(%rbp), %rdi
callq 0x32b20
addq $0x8, %rax
movq %rax, -0x58(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32b20
addq $0x8, %rax
movq %rax, -0x60(%rbp)
movq -0x58(%rbp), %rdi
callq 0x335f0
movq %rax, -0xf8(%rbp)
movq -0x60(%rbp), %rdi
callq 0x335f0
movq %rax, %rcx
movq -0xf8(%rbp), %rax
cmpq %rcx, %rax
je 0x3317a
movb $0x0, -0x1(%rbp)
jmp 0x33541
movq $0x0, -0x68(%rbp)
movq -0x68(%rbp), %rax
movq %rax, -0x100(%rbp)
movq -0x58(%rbp), %rdi
callq 0x335f0
movq %rax, %rcx
movq -0x100(%rbp), %rax
cmpq %rcx, %rax
jae 0x33207
movq -0x58(%rbp), %rdi
movq -0x68(%rbp), %rsi
callq 0x335d0
movq %rax, %rdi
callq 0xc3d0
movq %rax, -0x108(%rbp)
movq -0x60(%rbp), %rdi
movq -0x68(%rbp), %rsi
callq 0x335d0
movq %rax, %rdi
callq 0xc3d0
movq -0x108(%rbp), %rdi
movq %rax, %rsi
callq 0x33560
testb $0x1, %al
jne 0x331eb
jmp 0x331f4
movb $0x0, -0x1(%rbp)
jmp 0x33541
jmp 0x331f6
movq -0x68(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x68(%rbp)
jmp 0x33182
movb $0x1, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0x9, %eax
jne 0x33268
movq -0x10(%rbp), %rdi
callq 0x32b60
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq %rax, -0x110(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32b60
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x110(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xa, %eax
jne 0x332c0
movq -0x10(%rbp), %rdi
callq 0x32ba0
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq %rax, -0x118(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32ba0
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x118(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xb, %eax
jne 0x33379
movq -0x10(%rbp), %rdi
callq 0x32be0
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq %rax, -0x128(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32be0
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x128(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0x119(%rbp)
jne 0x33323
jmp 0x33369
movq -0x10(%rbp), %rdi
callq 0x32be0
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq %rax, -0x130(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32be0
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0x130(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, -0x119(%rbp)
movb -0x119(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xc, %eax
jne 0x33432
movq -0x10(%rbp), %rdi
callq 0x32c20
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq %rax, -0x140(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32c20
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x140(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0x131(%rbp)
jne 0x333dc
jmp 0x33422
movq -0x10(%rbp), %rdi
callq 0x32c20
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq %rax, -0x148(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32c20
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0x148(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, -0x131(%rbp)
movb -0x131(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
callq *(%rax)
cmpl $0xd, %eax
jne 0x334e8
movq -0x10(%rbp), %rdi
callq 0x32c60
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq %rax, -0x158(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32c60
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x158(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, %cl
xorl %eax, %eax
testb $0x1, %cl
movb %al, -0x149(%rbp)
jne 0x33495
jmp 0x334db
movq -0x10(%rbp), %rdi
callq 0x32c60
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq %rax, -0x160(%rbp)
movq -0x18(%rbp), %rdi
callq 0x32c60
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0x160(%rbp), %rdi
movq %rax, %rsi
callq 0x32ca0
movb %al, -0x149(%rbp)
movb -0x149(%rbp), %al
andb $0x1, %al
movb %al, -0x1(%rbp)
jmp 0x33541
movl $0x10, %edi
callq 0xa1d0
movq %rax, %rdi
movq %rdi, %rax
movq %rax, -0x168(%rbp)
leaq 0x695ad(%rip), %rsi     # 0x9cab3
callq 0xa540
jmp 0x3350d
movq -0x168(%rbp), %rdi
movq 0xb3ab5(%rip), %rsi     # 0xe6fd0
movq 0xb3a6e(%rip), %rdx     # 0xe6f90
callq 0xa610
movq -0x168(%rbp), %rdi
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x70(%rbp)
movl %eax, -0x74(%rbp)
callq 0xa2c0
jmp 0x3354f
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x170, %rsp            # imm = 0x170
popq %rbp
retq
movq -0x70(%rbp), %rdi
callq 0xa650
nopl (%rax,%rax)