// File: pfnet-research[P]pml/src/mdp_expr.cpp
// Function: mdp::operator<<(std::ostream&, mdp::expr_t const&)
std::ostream& operator<<(std::ostream& os, expr_t const& e) {
    switch (e.kind()) {
    case expr_kind_t::Int:
        os << cast<int_expr_t>(e).n; break;
    case expr_kind_t::Real:
        os << cast<real_expr_t>(e).d; break;
    case expr_kind_t::Bool:
        os << cast<bool_expr_t>(e).b; break;
    case expr_kind_t::Var:
        os << cast<var_expr_t>(e).name; break;
    case expr_kind_t::Neg:
        os << "!(" << *cast<neg_expr_t>(e).inner << ")";
        break;
    case expr_kind_t::BinOp:
        if (cast<binop_expr_t>(e).binop_kind != binop_kind_t::Eq) {
            os <<
                *cast<binop_expr_t>(e).lhs <<
                cast<binop_expr_t>(e).binop_kind <<
                *cast<binop_expr_t>(e).rhs;
        } else {
            os << "(" <<
                *cast<binop_expr_t>(e).lhs <<
                cast<binop_expr_t>(e).binop_kind <<
                *cast<binop_expr_t>(e).rhs << ")";
        }
        break;
    case expr_kind_t::If:
        os << "(" <<
            *cast<if_expr_t>(e).cond << "?" <<
            *cast<if_expr_t>(e).true_branch << ":" <<
            *cast<if_expr_t>(e).false_branch << ")";
        break;
    case expr_kind_t::Min: {
        auto const& args = cast<min_expr_t>(e).elems;
        os << "min(" << args[0];
        for (size_t i=1; i<args.size(); ++i)
            os << ", " << args[i];
        os << ")";
        break;
        }
    case expr_kind_t::Max: {
        auto const& args = cast<max_expr_t>(e).elems;
        os << "max(" << args[0];
        for (size_t i=1; i<args.size(); ++i)
            os << ", " << args[i];
        os << ")";
        break;
        }
    case expr_kind_t::Floor:
        os << "floor(" << *cast<floor_expr_t>(e).inner << ")";
        break;
    case expr_kind_t::Ceil:
        os << "ceil(" << *cast<ceil_expr_t>(e).inner << ")";
        break;
    case expr_kind_t::Pow:
        os << "pow(" <<
            *cast<pow_expr_t>(e).x << "" <<
            *cast<pow_expr_t>(e).y << ")";
        break;
    case expr_kind_t::Mod:
        os << "mod(" <<
            *cast<mod_expr_t>(e).i << "" <<
            *cast<mod_expr_t>(e).n << ")";
        break;
    case expr_kind_t::Log:
        os << "log(" <<
            *cast<log_expr_t>(e).x << "" <<
            *cast<log_expr_t>(e).b << ")";
        break;
    }
    return os;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x120, %rsp            # imm = 0x120
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x10(%rbp), %rdi
movq (%rdi), %rax
movq (%rax), %rax
callq *%rax
movl %eax, %ecx
movq %rcx, -0x38(%rbp)
subl $0xd, %eax
ja 0x3290d
movq -0x38(%rbp), %rax
leaq 0x6a337(%rip), %rcx     # 0x9c5d0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x8(%rbp), %rax
movq %rax, -0x40(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32920
movq -0x40(%rbp), %rdi
movl 0x8(%rax), %esi
callq 0xa630
jmp 0x3290d
movq -0x8(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32960
movq -0x48(%rbp), %rdi
movsd 0x8(%rax), %xmm0
callq 0xa6c0
jmp 0x3290d
movq -0x8(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x10(%rbp), %rdi
callq 0x329a0
movq -0x50(%rbp), %rdi
movb 0x8(%rax), %al
andb $0x1, %al
movzbl %al, %esi
callq 0xa670
jmp 0x3290d
movq -0x8(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x10(%rbp), %rdi
callq 0x329e0
movq -0x58(%rbp), %rdi
movq %rax, %rsi
addq $0x8, %rsi
callq 0xa340
jmp 0x3290d
movq -0x8(%rbp), %rdi
leaq 0x69922(%rip), %rsi     # 0x9bc62
callq 0xa3b0
movq %rax, -0x60(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32a20
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x60(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x6703e(%rip), %rsi     # 0x993b2
callq 0xa3b0
jmp 0x3290d
movq -0x10(%rbp), %rdi
callq 0x32a60
cmpl $0x8, 0x28(%rax)
je 0x323f9
movq -0x8(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32a60
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x78(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, -0x70(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32a60
movq -0x70(%rbp), %rdi
movl 0x28(%rax), %esi
callq 0x32110
movq %rax, -0x68(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32a60
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0x68(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
jmp 0x32487
movq -0x8(%rbp), %rdi
leaq 0x6985f(%rip), %rsi     # 0x9bc63
callq 0xa3b0
movq %rax, -0x90(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32a60
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x90(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, -0x88(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32a60
movq -0x88(%rbp), %rdi
movl 0x28(%rax), %esi
callq 0x32110
movq %rax, -0x80(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32a60
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0x80(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x66f30(%rip), %rsi     # 0x993b2
callq 0xa3b0
jmp 0x3290d
movq -0x8(%rbp), %rdi
leaq 0x697cc(%rip), %rsi     # 0x9bc63
callq 0xa3b0
movq %rax, -0xa8(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32aa0
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0xa8(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x6a13e(%rip), %rsi     # 0x9c60f
callq 0xa3b0
movq %rax, -0xa0(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32aa0
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0xa0(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x6a106(%rip), %rsi     # 0x9c611
callq 0xa3b0
movq %rax, -0x98(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32aa0
movq %rax, %rdi
addq $0x28, %rdi
callq 0xc3d0
movq -0x98(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x66e6d(%rip), %rsi     # 0x993b2
callq 0xa3b0
jmp 0x3290d
movq -0x10(%rbp), %rdi
callq 0x32ae0
addq $0x8, %rax
movq %rax, -0x18(%rbp)
movq -0x8(%rbp), %rdi
leaq 0x6a0a8(%rip), %rsi     # 0x9c613
callq 0xa3b0
movq %rax, -0xb0(%rbp)
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x335d0
movq -0xb0(%rbp), %rdi
movq %rax, %rsi
callq 0x33590
movq $0x1, -0x20(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0xb8(%rbp)
movq -0x18(%rbp), %rdi
callq 0x335f0
movq %rax, %rcx
movq -0xb8(%rbp), %rax
cmpq %rcx, %rax
jae 0x325ff
movq -0x8(%rbp), %rdi
leaq 0x6930a(%rip), %rsi     # 0x9b8d3
callq 0xa3b0
movq %rax, -0xc0(%rbp)
movq -0x18(%rbp), %rdi
movq -0x20(%rbp), %rsi
callq 0x335d0
movq -0xc0(%rbp), %rdi
movq %rax, %rsi
callq 0x33590
movq -0x20(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x20(%rbp)
jmp 0x3259b
movq -0x8(%rbp), %rdi
leaq 0x66da8(%rip), %rsi     # 0x993b2
callq 0xa3b0
jmp 0x3290d
movq -0x10(%rbp), %rdi
callq 0x32b20
addq $0x8, %rax
movq %rax, -0x28(%rbp)
movq -0x8(%rbp), %rdi
leaq 0x69fe8(%rip), %rsi     # 0x9c618
callq 0xa3b0
movq %rax, -0xc8(%rbp)
movq -0x28(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
callq 0x335d0
movq -0xc8(%rbp), %rdi
movq %rax, %rsi
callq 0x33590
movq $0x1, -0x30(%rbp)
movq -0x30(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0x28(%rbp), %rdi
callq 0x335f0
movq %rax, %rcx
movq -0xd0(%rbp), %rax
cmpq %rcx, %rax
jae 0x326c4
movq -0x8(%rbp), %rdi
leaq 0x69245(%rip), %rsi     # 0x9b8d3
callq 0xa3b0
movq %rax, -0xd8(%rbp)
movq -0x28(%rbp), %rdi
movq -0x30(%rbp), %rsi
callq 0x335d0
movq -0xd8(%rbp), %rdi
movq %rax, %rsi
callq 0x33590
movq -0x30(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x30(%rbp)
jmp 0x32660
movq -0x8(%rbp), %rdi
leaq 0x66ce3(%rip), %rsi     # 0x993b2
callq 0xa3b0
jmp 0x3290d
movq -0x8(%rbp), %rdi
leaq 0x69f39(%rip), %rsi     # 0x9c61d
callq 0xa3b0
movq %rax, -0xe0(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32b60
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0xe0(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x66c94(%rip), %rsi     # 0x993b2
callq 0xa3b0
jmp 0x3290d
movq -0x8(%rbp), %rdi
leaq 0x69ef1(%rip), %rsi     # 0x9c624
callq 0xa3b0
movq %rax, -0xe8(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32ba0
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0xe8(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x66c45(%rip), %rsi     # 0x993b2
callq 0xa3b0
jmp 0x3290d
movq -0x8(%rbp), %rdi
leaq 0x69ea8(%rip), %rsi     # 0x9c62a
callq 0xa3b0
movq %rax, -0xf8(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32be0
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0xf8(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x69119(%rip), %rsi     # 0x9b8d5
callq 0xa3b0
movq %rax, -0xf0(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32be0
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0xf0(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x66bbc(%rip), %rsi     # 0x993b2
callq 0xa3b0
jmp 0x3290d
movq -0x8(%rbp), %rdi
leaq 0x69e24(%rip), %rsi     # 0x9c62f
callq 0xa3b0
movq %rax, -0x108(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32c20
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x108(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x69090(%rip), %rsi     # 0x9b8d5
callq 0xa3b0
movq %rax, -0x100(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32c20
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0x100(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x66b33(%rip), %rsi     # 0x993b2
callq 0xa3b0
jmp 0x3290d
movq -0x8(%rbp), %rdi
leaq 0x69da0(%rip), %rsi     # 0x9c634
callq 0xa3b0
movq %rax, -0x118(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32c60
movq %rax, %rdi
addq $0x8, %rdi
callq 0xc3d0
movq -0x118(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x69007(%rip), %rsi     # 0x9b8d5
callq 0xa3b0
movq %rax, -0x110(%rbp)
movq -0x10(%rbp), %rdi
callq 0x32c60
movq %rax, %rdi
addq $0x18, %rdi
callq 0xc3d0
movq -0x110(%rbp), %rdi
movq %rax, %rsi
callq 0x32260
movq %rax, %rdi
leaq 0x66aaa(%rip), %rsi     # 0x993b2
callq 0xa3b0
movq -0x8(%rbp), %rax
addq $0x120, %rsp            # imm = 0x120
popq %rbp
retq
nopw (%rax,%rax)