//#####################################################################
// Copyright 2012.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYREGHT.txt.
//#####################################################################
// Class INSTRUCTION
//#####################################################################
#ifndef __INSTRUCTION__
#define __INSTRUCTION__

#include <Core/Arrays/ARRAY.h>
#include <Core/Arrays/ARRAYS_FORWARD.h>
#include <Core/Data_Structures/ELEMENT_ID.h>
#include <Core/Data_Structures/HASH_REDUCE.h>
#include <Core/Symbolics/REG.h>
#include <cassert>
#include <iosfwd>
#include <utility>

namespace PhysBAM{

enum op_type
{
    op_nop,op_copy,op_add,op_sub,op_mul,op_div,op_neg,op_inv,
    op_sqrt,op_exp,op_ln,op_pow,
    op_sin,op_cos,op_asin,op_acos,op_atan,op_atan2,
    op_floor,op_ceil,op_rint,op_min,op_max,op_abs,
    op_lt,op_le,op_gt,op_ge,op_eq,op_ne,op_not,op_or,op_and,op_if,
    op_brz,op_brnz,op_jmp,op_phi,
    op_last
};

enum op_flags
{
    flag_none=0x00,
    flag_reg_dest=0x01,flag_reg_src0=0x02,flag_reg_src1=0x04,flag_reg_src2=0x08,
    flag_can_deduce=0x10,flag_commute=0x20,flag_adjoint=0x40
};

struct OPERATION
{
    op_type op=op_nop;
    OPERATION(op_type a=op_nop):op(a){}
    bool Has_Dest() const {return op_flags_table[op]&flag_reg_dest;}
    bool Has_Src0() const {return op_flags_table[op]&flag_reg_src0;}
    bool Has_Src1() const {return op_flags_table[op]&flag_reg_src1;}
    bool Has_Src2() const {return op_flags_table[op]&flag_reg_src2;}
    bool Can_Deduce() const {return op_flags_table[op]&flag_can_deduce;}
    bool Commutes() const {return op_flags_table[op]&flag_commute;}
    bool Is_Branch() const {return op==op_brz || op==op_brnz;}
    bool Is_Jump() const {return op==op_jmp || op==op_brz || op==op_brnz;}
    bool Use_Adjoint() const {return op_flags_table[op]&flag_adjoint;}
    bool operator==(op_type p) const{return op==p;}
    bool operator!=(op_type p) const{return op!=p;}
    const char* Name() const{return names[(int)op];}
private:
    static const char* names[(int)op_last];
    static int op_flags_table[(int)op_last];
};

struct INSTRUCTION
{
    OPERATION type=op_nop;
    REG dest,src0,src1,src2;
};

struct RAW_INSTRUCTION
{
    OPERATION type=op_nop;
    int dest,src0,src1,src2;
};

std::ostream& operator<<(std::ostream& o,const INSTRUCTION& I);
std::ostream& operator<<(std::ostream& o,const RAW_INSTRUCTION& I);

//void Print(const ARRAY<INSTRUCTION>& code);
void Print(const ARRAY<RAW_INSTRUCTION>& code);

}
#endif
