/***************************************************************************
    FPGA Brook Source Code
    Copyright (C) by Frank Franjo Plavec 2006-2012
    Please note that some sections of this file were adopted from GPU Brook
    and are Copyright (c) 2003, Stanford University.

    This program 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 1, or (at your option)
    any later version.

    This program 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 this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.

    The full text of the GNU General Public License in the file named
    LICENSE.cTool.
*****************************************************************************/


#ifndef __MAIN_H__
#define __MAIN_H__

#include "graph.h"
#include <vector>

#define BRCC_DIV_OPERATOR_TO_REPLACE " <__BRCC_DIV_OPERATOR_TO_REPLACE> "
#define BRCC_MOD_OPERATOR_TO_REPLACE " <__BRCC_MOD_OPERATOR_TO_REPLACE> "
#define BRCC_MOD_DIV_DECL_BEGIN "\n<__BRCC_MOD_DIV_DECL_BEGIN>_"
#define BRCC_MOD_DIV_DECL_END "\n<__BRCC_MOD_DIV_DECL_END>_"
#define BRCC_MOD_DIV_AFTER_DECL_BEGIN "\n<__BRCC_MOD_DIV_AFTER_DECL_BEGIN>_"
#define BRCC_MOD_DIV_AFTER_DECL_END "\n<__BRCC_MOD_DIV_AFTER_DECL_END>_"
#define BRCC_MOD_DIV_BLOCK_0_BEGIN "\n<__BRCC_MOD_DIV_BLOCK_0_BEGIN>_"
#define BRCC_MOD_DIV_BLOCK_0_END "\n<__BRCC_MOD_DIV_BLOCK_0_END>_"
#define BRCC_MOD_DIV_BLOCK_1_BEGIN "\n<__BRCC_MOD_DIV_BLOCK_1_BEGIN>_"
#define BRCC_MOD_DIV_BLOCK_1_END "\n<__BRCC_MOD_DIV_BLOCK_1_END>_"
#define BRCC_INDEXOF_REPLICATED_UPDATE_BLOCK_BEGIN "\n<__BRCC_INDEXOF_REPLICATED_UPDATE_BLOCK_BEGIN>_"
#define BRCC_INDEXOF_REPLICATED_UPDATE_BLOCK_END "\n<__BRCC_INDEXOF_REPLICATED_UPDATE_BLOCK_END>_"
#define BRCC_REPLICATE_PRAGMA "br2c_speed_up"
#define BRCC_REPLICA_SUFFIX "_replica_"
#define BRCC_REDUCE_REPLICA_REPLACEMENT_TAG "__REDUCE_REPLICA_REPLACEMENT_TAG__"
#define BRCC_REDUCE_MODULO_ITERATOR_TAG_0 "__BRCC_REDUCE_MODULO_ITERATOR_TAG_0__"
#define BRCC_REDUCE_TOTAL_ELEMENTS_TAG_0 "__BRCC_REDUCE_TOTAL_ELEMENTS_TAG_0__"
#define BRCC_REDUCE_TOTAL_ELEMENTS_TAG_1 "__BRCC_REDUCE_TOTAL_ELEMENTS_TAG_1__"
#define BRCC_REDUCE_OUTPUT_ELEMENTS_TAG_0 "__BRCC_REDUCE_OUTPUT_ELEMENTS_TAG_0__"
#define BRCC_REDUCE_OUTPUT_ELEMENTS_TAG_1 "__BRCC_REDUCE_OUTPUT_ELEMENTS_TAG_1__"
#define BRCC_REDUCE_MODULO_ITERATOR_0 "brcc_reduce_mod_iterator_0"
#define BRCC_NEXT_REDUCE_MODULO_ITERATOR_0 "brcc_next_reduce_mod_iterator_0"
#define BRCC_REDUCE_MODULO_USAGE_TAG_0 "__BRCC_REDUCE_MODULO_USAGE_TAG_0__"
#define BRCC_REDUCE_MODULO_UPDATE_TAG_0 "__BRCC_REDUCE_MODULO_UPDATE_TAG_0__"
#define BRCC_STREAM_ARRAY_POINTER_INIT "\n<__BRCC_STREAM_ARRAY_POINTER_INIT>_"

// Defines maximum allowed size of a line in the input program.
#define MAX_LINE_SIZE 4096



// Old definitions from the original GPU Brook compiler.
#define TARGET_CPU      (1<<0)
#define TARGET_PS20     (1<<1)
#define TARGET_FP30     (1<<2)
#define TARGET_ARB      (1<<3)
#define TARGET_MULTITHREADED_CPU (1<<4)
#define TARGET_FP40     (1<<5)
#define TARGET_PS30     (1<<6)
#define TARGET_PS2B     (1<<7)
#define TARGET_PS2A     (1<<8)

#define COMPILER_DEFAULT 0
#define COMPILER_CGC     1
#define COMPILER_FXC     2

#define GPU_ARCH_DEFAULT 0
#define GPU_ARCH_X800    1
#define GPU_ARCH_6800    2


struct replication_info {
	std::string function_name;
	int replication_factor;
};

struct collector_distributor_info {
	std::string name;
	int inputs;
	int outputs;
	int trees;
	int leaves;
	int x_over_y;
	bool array_fifo;		// Does the FIFO store arrays or not?
	int array_size;			// Number of words in the array
	int word_size;			// Number of bytes in each word
	collector_distributor_info():array_fifo(false), word_size(4){};
};

struct fifo_info {
	std::string fifo_name;	// Name given to the FIFO
	bool array_fifo;		// Is it a FIFO that stores arrays or not
	int depth;				// FIFO depth
	int array_size;			// Number of words in the array
	int word_size;			// Number of bytes in each word
	fifo_info():array_fifo(false), word_size(4){};
};

struct globals_struct {
  globals_struct() {
      verbose=false,parseOnly=false;
      keepFiles=false,fponly=0,target=0,workspace=0;
      printLineDirectives=false,allowDX9MultiOut=false;
      enableGPUAddressTranslation=false;
      allowKernelToKernel=true,noTypeChecks=false;
      favorcompiler=0,arch=0;
  }             
  bool verbose;
  bool parseOnly;
  bool keepFiles;
  char *sourcename;
  char *compilername;
  char *shaderoutputname;
  char *coutputname;
  char *elfoutputname;
  char *targetfolder;
  char *dataflowdotfilename;
  char *dataflowreplicateddotfilename;
  std::vector <struct fifo_info> fifos;
  std::vector <std::string> kernelnames;
  std::vector <struct replication_info> replicated_kernels;
  std::vector <struct collector_distributor_info> collectors;
  std::vector <struct collector_distributor_info> distributors;
  std::vector <struct collector_distributor_info> collectors_distributors;
  std::vector <struct collector_distributor_info> double_distributors;
  std::vector <struct collector_distributor_info> collectors_double_distributors;
  std::string SOPC_TEMPLATE_FILE;
  std::string SOPC_TARGET_FILE;
  std::string FIFO_TEMPLATE_FILE;
  std::string HARDWARE_FIFO_FOLDER;
  std::string BSP_TEMPLATE_FILE;
  std::string APP_TEMPLATE_FILE;
  std::string COPY_FOLDER;
  std::string SOPC_COMPONENT_PATH;
  int INITIAL_SOPC_ELEMENT_COUNT;
  int FIFO_BASE_ADDRESS;
  Graph dataflow;
  Graph replicated;
  int fponly;
  int target;
  int workspace;
  bool printLineDirectives;
  bool allowDX9MultiOut;
  bool enableGPUAddressTranslation;
  bool allowKernelToKernel;
  bool noTypeChecks;
  int favorcompiler;
  int arch;
  // TIM: hacked flag for now
  bool enableKernelSplitting;
};

extern struct globals_struct globals;

struct var_info {
	bool used;
};


void fatal (std::string msg);
int findVarInArray (Decl **var_array, int array_size, Symbol *variable);
int findVarInVector (DeclVector &dec_vector, Symbol *variable);
int findVarInVector (StreamInfoVector &dec_vector, Symbol *variable);
void printBinOp (std::ostream& out, BinaryOp op);
std::string analyzeExpression (Expression *expr, Statement *ste, std::string function_name, DeclVector &funcdecs, std::vector <PPDirective *> &ppdirectives, StreamInfoVector &declstreams, Decl **streamins, unsigned int ins, Decl **streamouts, unsigned int outs, Decl **streamreduces, unsigned int reduces, Decl** streamvouts, unsigned int vouts, std::string right_var_before_dot, unsigned int reduce_index, unsigned int version, bool main_function, int replication_factor, int replica_number, std::stringstream &out);
void countKernelArgs (FunctionType *ft, unsigned int &ins, unsigned int &outs, unsigned int &nonstreams, unsigned int &vouts);
void handleKernelArgs (Decl* declaration, Decl** &streamins, Decl** &streamouts, Decl** &streamreduces, Decl** &nonstreamargs, Decl** &streamvouts, unsigned int ins, unsigned int outs, unsigned int reduces, unsigned int nonstreams, unsigned int vouts, StreamInfoVector &declstreams, Location &statement_location, unsigned int reduce_index, unsigned int version, int replica_number, std::stringstream &out);
void handleAssignment (BinaryExpr *binexp, Statement *ste, std::string function_name, DeclVector &funcdecs, std::vector <PPDirective *> &ppdirectives, StreamInfoVector &declstreams, Decl **streamouts, unsigned int outs, Decl **streamins, unsigned int ins, Decl **streamreduces, unsigned int reduces, Decl** streamvouts, unsigned int vouts, unsigned int reduce_index, unsigned int version, unsigned int statement_count, bool main_function, std::vector <Decl *> &declarations_with_initializations, int replication_factor, int replica_number, std::stringstream &out);
void handleFunctionCall (FunctionCall *fcall, Statement *ste, DeclVector &funcdecs, StreamInfoVector &declstreams, bool main_function, std::stringstream &out);
void handleVarDeclaration (DeclStemnt *ste, StreamInfoVector &declstreams, std::vector <PPDirective *> &ppdirectives, std::vector <DeclStemnt *> &declarations_with_initializations, std::stringstream &out);
void handleBlockStatement (Statement *block_ste, std::string function_name, DeclVector &funcdecs, StreamInfoVector &declstreams, Decl **streamouts, unsigned int outs, Decl **streamins, var_info *in_info, unsigned int ins, Decl **streamreduces, unsigned int reduces, Decl** streamvouts, unsigned int vouts, std::vector <PPDirective *> &ppdirectives, unsigned int reduce_index, unsigned int version, unsigned int &statement_count, bool main_function, std::vector <DeclStemnt *> &declarations_with_initializations, int replication_factor, int replica_number, std::stringstream &out);
void handleBlock (Block *ste, std::string function_name, DeclVector &funcdecs, StreamInfoVector &declstreams, Decl **streamouts, unsigned int outs, Decl **streamins, var_info *in_info, unsigned int ins, Decl **streamreduces, unsigned int reduces, Decl** streamvouts, unsigned int vouts, std::vector <PPDirective *> &ppdirectives, unsigned int reduce_index, unsigned int version, unsigned int &statement_count, bool main_function, bool block_inside_block, int replication_factor, int replica_number, std::stringstream &out);
void handleProgramStatement (Statement *ste, DeclVector &funcdecs, std::vector <PPDirective *> &ppdirectives, std::stringstream &out);
void replaceKernelPointerInit (std::string function_name, std::string var_name, bool stream_of_arrays, std::string init_string, std::stringstream &out);

#endif
