//#####################################################################
// Copyright 2012.
// This file is part of PhysBAM whose distribution is governed by the license contained in the accompanying file PHYSBAM_COPYREGHT.txt.
//#####################################################################
#include <Core/Symbolics/INSTRUCTION.h>
#include <Core/Arrays/ARRAY.h>
#include <Core/Log/LOG.h>
#include <iomanip>
#include <iostream>
namespace PhysBAM{
static constexpr int flag_1=flag_reg_dest|flag_reg_src0;
static constexpr int flag_2=flag_reg_dest|flag_reg_src0|flag_reg_src1;
int OPERATION::op_flags_table[op_last]=
{
    flag_none, // op_nop
    flag_1|flag_adjoint, // op_copy
    flag_2|flag_commute|flag_adjoint, // op_add
    flag_2|flag_adjoint, // op_sub
    flag_2|flag_can_deduce|flag_commute|flag_adjoint, // op_mul
    flag_2|flag_can_deduce|flag_adjoint, // op_div
    flag_1|flag_adjoint, // op_neg
    flag_1|flag_adjoint, // op_inv
    flag_1|flag_adjoint, // op_sqrt
    flag_1|flag_adjoint, // op_exp
    flag_1|flag_adjoint, // op_ln
    flag_2|flag_can_deduce|flag_adjoint, // op_pow
    flag_1|flag_adjoint, // op_sin
    flag_1|flag_adjoint, // op_cos
    flag_1|flag_adjoint, // op_asin
    flag_1|flag_adjoint, // op_acos
    flag_1|flag_adjoint, // op_atan
    flag_2|flag_adjoint, // op_atan2
    flag_1|flag_adjoint, // op_floor
    flag_1|flag_adjoint, // op_ceil
    flag_1|flag_adjoint, // op_rint
    flag_2|flag_commute, // op_min
    flag_2|flag_commute, // op_max
    flag_1, // op_abs
    flag_2|flag_adjoint, // op_lt
    flag_2|flag_adjoint, // op_le
    flag_2|flag_adjoint, // op_gt
    flag_2|flag_adjoint, // op_ge
    flag_2|flag_commute|flag_adjoint, // op_eq
    flag_2|flag_commute|flag_adjoint, // op_ne
    flag_1|flag_adjoint, // op_not
    flag_2|flag_can_deduce|flag_commute|flag_adjoint, // op_or
    flag_2|flag_can_deduce|flag_commute|flag_adjoint, // op_and
    flag_2|flag_reg_src2, // op_if
    flag_reg_src0, // op_brz
    flag_reg_src0, // op_brnz
    flag_none, // op_jmp
    flag_2, // op_phi
};
const char* OPERATION::names[op_last]=
{
    "nop","copy","add","sub","mul","div","neg","inv",
    "sqrt","exp","ln","pow",
    "sin","cos","asin","acos","atan","atan2",
    "floor","ceil","rint","min","max","abs",
    "lt","le","gt","ge","eq","ne","not","or","and","if",
    "brz","brnz","jmp","phi"
};

std::ostream& operator<<(std::ostream& o,const INSTRUCTION& I)
{
    o<<std::left<<std::setw(6)<<I.type.Name();
    const char* sep="";
    if(I.type.Has_Dest() || I.type.Is_Jump()){o<<sep<<I.dest;sep=", ";}
    if(I.type.Has_Src0()){o<<sep<<I.src0;sep=", ";}
    if(I.type.Has_Src1()){o<<sep<<I.src1;sep=", ";}
    if(I.type.Has_Src2()) o<<sep<<I.src2;
    return o;
}
std::ostream& operator<<(std::ostream& o,const RAW_INSTRUCTION& I)
{
    INSTRUCTION i{I.type,MEM_REG(I.dest),MEM_REG(I.src0),MEM_REG(I.src1),MEM_REG(I.src2)};
    if(I.type.Is_Jump()) i.dest=MEM_LABEL(I.dest);
    if(I.type.Is_Branch()) i.src1=MEM_LABEL(I.src1);
    return o<<i;
}
//#####################################################################
// Function Print
//#####################################################################
void Print(const ARRAY<INSTRUCTION,MEM_LABEL>& code)
{
    for(MEM_LABEL i{};i<code.m;i++)
        LOG::printf("% 3d  %P\n",i,code(i));
}
void Print(const ARRAY<RAW_INSTRUCTION>& code)
{
    for(int i=0;i<code.m;i++)
        LOG::printf("% 3d  %P\n",i,code(i));
}
// INSTRUCTION::INSTRUCTION(op_type type,int dest,int src0,int src1,int src2)
//     :type(type),dest(dest),src0(src0),src1(src1),src2(src2)
// {
//     if(op_flags_table[type]&flag_reg_src0) assert(src0>=0);
//     if(op_flags_table[type]&flag_reg_src1) assert(src1>=0);
//     if(op_flags_table[type]&flag_reg_src2) assert(src2>=0);
// }
}
