//==============================================================================
//
// d/wilson_d520/asm_code.cc
//
//------------------------------------------------------------------------------
//
// Copyright (C) 2010 Thomas Streuer 
//
// This file is part of BQCD -- Berlin Quantum ChromoDynamics program
//
// BQCD is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// BQCD is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with BQCD.  If not, see <http://www.gnu.org/licenses/>.
//
//------------------------------------------------------------------------------
#include "asm_code.h"

#include <iostream>
#include <string>
#include <sstream>
#include <vector>

using std::ostringstream;
using std::string;
using std::vector;


asm_code_element_t& asm_code_element_t::add_comment(const string& comment)
{
  comm_ = comment;
  return *this;
}

void asm_code_element_t::print() const
{
  std::cout << str_ << "\t# " << comm_ << "\n";
}


// asm_code_element::asm_code_element(
//   char* _str, int n_mod, int* mod, int n_used, int* used,
//   bool _fixed, bool _jump)
// {
//   str=new char[strlen(_str)+1];
//   strcpy(str, _str);
//   n_res_mod=n_mod;
//   n_res_used=n_used;
//   res_mod=new int[n_mod];
//   res_used=new int[n_used];
//   for (int i=0; i<n_mod; i++)
//     res_mod[i]=mod[i];
//   for (int i=0; i<n_used; i++)
//     res_used[i]=used[i];
//   fixed=_fixed;
//   jump=_jump;
// }


void asm_code_t::init()
{
  el_.resize(0);
}

void asm_code_t::add(const asm_code_element_t& e)
{
  el_.push_back(e);
}

void asm_code_t::listing() const
{
  for (vector<asm_code_element_t>::const_iterator it=el_.begin();
       it!=el_.end(); ++it)
    it->print();
}

register_file_t::register_file_t(unsigned n)
  : n_(n),
    max_(0),
    state_(n, reg_free)
{
}

void register_file_t::reset()
{
  for (vector<unsigned>::iterator it=state_.begin();
       it!=state_.end(); ++it)
    *it = reg_free;
}

void register_file_t::get_regs(unsigned num, vector<unsigned>& r)
{
  r.resize(0);
  unsigned i = 0;
  while (i < n_ && num)
  {
    if (state_[i] == reg_free)
    {
      state_[i] = reg_used;
      r.push_back(i);
      --num;
      if (i > max_)
	max_ = i;
    }
    ++i;
  }
  if (num)
  {
    std::cerr << "error allocating registers\n";
    exit(1);
  }
}

unsigned register_file_t::get_reg()
{
  vector<unsigned> r;
  get_regs(1, r);
  return r[0];
}

void register_file_t::get_these_regs(vector<unsigned>& r)
{
  for (vector<unsigned>::iterator it=r.begin();
       it!=r.end(); ++it)
    if (state_[*it] == reg_free)
    {
      state_[*it] = reg_used;
      if (*it > max_)
	max_ = *it;
    }
    else
    {
      std::cerr << "error allocating these registers\n";
      exit(1);
    }
}

void register_file_t::get_this_reg(unsigned r)
{
  vector<unsigned> regs(1, r);
  get_these_regs(regs);
}

void register_file_t::release_regs(const vector<unsigned>& r)
{
  for (vector<unsigned>::const_iterator it=r.begin();
       it!=r.end(); ++it)
    state_[*it] = reg_free;
}

void register_file_t::release_reg(unsigned r)
{
  release_regs(vector<unsigned>(1, r));
}

int asm_stack_t::add(int sz)
{
  size_ += sz;
  return size_-sz;
}

string asm_label_t::get_label()
{
  ostringstream oss;
  oss << base_ << "_label_" << count++;
  return oss.str();
}

asm_code_element_t asm_label_t::set_label(string& l)
{
  if (l.length() == 0)
    l = get_label();
  ostringstream oss;
  oss << l << ":";
  return asm_code_element_t(oss.str());
}


const unsigned register_file_t::reg_free(1);
const unsigned register_file_t::reg_used(2);
