/*
 * Copyright (C) 2012 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


/*! \file ncg_o1_data.h
    \brief A header file to define data structures used by register allocator & const folding
*/
#ifndef _DALVIK_NCG_ANALYSISO1_H
#define _DALVIK_NCG_ANALYSISO1_H

#include "Dalvik.h"
#include "enc_wrapper.h"
#include "Lower.h"
#ifdef WITH_JIT
#include "compiler/CompilerIR.h"
#endif

//! maximal number of edges per basic block
#define MAX_NUM_EDGE_PER_BB 300
//! maximal number of basic blocks per method
#define MAX_NUM_BBS_PER_METHOD 1000
//! maximal number of virtual registers per basic block
#define MAX_REG_PER_BASICBLOCK 140
//! maximal number of virtual registers per bytecode
#define MAX_REG_PER_BYTECODE 40
//! maximal number of virtual registers per method
#define MAX_REG_PER_METHOD 200
//! maximal number of temporaries per bytecode
#define MAX_TEMP_REG_PER_BYTECODE 30
//! maximal number of GG GPR VRs in a method
#define MAX_GLOBAL_VR      2
//! maximal number of GG XMM VRs in a method
#define MAX_GLOBAL_VR_XMM  4
#define MAX_CONST_REG 150

#define MASK_FOR_TYPE 7 //last 3 bits 111

#define LOOP_COUNT 10
//! maximal number of entries in compileTable
#define COMPILE_TABLE_SIZE 200
//! maximal number of transfer points per basic block
#define MAX_XFER_PER_BB 1000  //on Jan 4
#define PC_FOR_END_OF_BB -999
#define PC_FOR_START_OF_BB -998

//! various cases of overlapping between 2 variables
typedef enum OverlapCase {
  OVERLAP_ALIGN = 0,
  OVERLAP_B_IS_LOW_OF_A,
  OVERLAP_B_IS_HIGH_OF_A,
  OVERLAP_LOW_OF_A_IS_HIGH_OF_B,
  OVERLAP_HIGH_OF_A_IS_LOW_OF_B,
  OVERLAP_A_IS_LOW_OF_B,
  OVERLAP_A_IS_HIGH_OF_B,
  OVERLAP_B_COVER_A,
  OVERLAP_B_COVER_LOW_OF_A,
  OVERLAP_B_COVER_HIGH_OF_A,
  OVERLAP_NO
} OverlapCase;

//!access type of a variable
typedef enum RegAccessType {
  REGACCESS_D = 0,
  REGACCESS_U,
  REGACCESS_DU,
  REGACCESS_UD,
  REGACCESS_L,
  REGACCESS_H,
  REGACCESS_UL,
  REGACCESS_UH,
  REGACCESS_LU,
  REGACCESS_HU,
  REGACCESS_N, //no access
  REGACCESS_UNKNOWN
} RegAccessType;
//! a variable can be local (L), globally local (GL) or global (GG)
typedef enum GlobalType {
  GLOBALTYPE_GG,
  GLOBALTYPE_GL,
  GLOBALTYPE_L
} GlobalType;
typedef enum VRState {
  VRSTATE_SPILLED,
  VRSTATE_UPDATED,
  VRSTATE_CLEAN
} VRState;
//! helper state to determine if freeing VRs needs to be delayed
enum VRDelayFreeFlags {
  VRDELAY_NONE = 0, // used when VR can be freed from using physical register if needed
  VRDELAY_NULLCHECK = 1 << 0, // used when VR is used for null check and freeing must be delayed
  VRDELAY_BOUNDCHECK = 1 << 1 // used when VR is used for bound check and freeing must be delayed
};
typedef enum TRState { //state of temporary registers
  TRSTATE_SPILLED,
  TRSTATE_UNSPILLED,
  TRSTATE_CLEAN
} TRState;
//!information about a physical register
typedef struct RegisterInfo {
  PhysicalReg physicalReg;
  bool isUsed;
  bool isCalleeSaved;
  int freeTimeStamp;
} RegisterInfo;
typedef struct UniqueRegister {
  LowOpndRegType physicalType;
  int regNum;
  int numExposedUsage;
  PhysicalReg physicalReg;
} UniqueRegister;
//!specifies the weight of a VR allocated to a specific physical register
//!it is used for GPR VR only
typedef struct RegAllocConstraint {
  PhysicalReg physicalReg;
  int count;
} RegAllocConstraint;

typedef enum XferType {
  XFER_MEM_TO_XMM, //for usage
  XFER_DEF_TO_MEM, //def is gp
  XFER_DEF_TO_GP_MEM,
  XFER_DEF_TO_GP,
  XFER_DEF_IS_XMM //def is xmm
} XferType;
typedef struct XferPoint {
  int tableIndex; //generated from a def-use pair
  XferType xtype;
  int offsetPC;
  int regNum; //get or set VR at offsetPC
  LowOpndRegType physicalType;

  //if XFER_DEF_IS_XMM
  int vr_gpl; //a gp VR that uses the lower half of the def
  int vr_gph;
  bool dumpToXmm;
  bool dumpToMem;
} XferPoint;

//!for def: accessType means which part of the VR defined at offestPC is live now
//!for use: accessType means which part of the usage comes from the reachingDef
typedef struct DefOrUse {
  int offsetPC; //!the program point
  int regNum; //!access the virtual reg
  LowOpndRegType physicalType; //!xmm or gp or ss
  RegAccessType accessType; //!D, L, H, N
} DefOrUse;
//!a link list of DefOrUse
typedef struct DefOrUseLink {
  int offsetPC;
  int regNum; //access the virtual reg
  LowOpndRegType physicalType; //xmm or gp
  RegAccessType accessType; //D, L, H, N
  struct DefOrUseLink* next;
} DefOrUseLink;
//!pair of def and uses
typedef struct DefUsePair {
  DefOrUseLink* uses;
  DefOrUseLink* useTail;
  int num_uses;
  DefOrUse def;
  struct DefUsePair* next;
} DefUsePair;

//!information associated with a virtual register
//!the pair <regNum, physicalType> uniquely determines a variable
typedef struct VirtualRegInfo {
  int regNum;
  LowOpndRegType physicalType;
  int refCount;
  RegAccessType accessType;
  GlobalType gType;
  int physicalReg_GG;
  RegAllocConstraint allocConstraints[8];
  RegAllocConstraint allocConstraintsSorted[8];

  DefOrUse reachingDefs[3]; //!reaching defs to the virtual register
  int num_reaching_defs;
} VirtualRegInfo;
//!information of whether a VR is constant and its value
typedef struct ConstVRInfo {
  int regNum;
  int value;
  bool isConst;
} ConstVRInfo;
#define NUM_ACCESS_IN_LIVERANGE 10
//!specifies one live range
typedef struct LiveRange {
  int start;
  int end; //inclusive
  //all accesses in the live range
  int num_access;
  int num_alloc;
  int* accessPC;
  struct LiveRange* next;
} LiveRange;
typedef struct BoundCheckIndex {
  int indexVR;
  bool checkDone;
} BoundCheckIndex;
//!information for a virtual register such as live ranges, in memory
typedef struct MemoryVRInfo {
  int regNum;
  bool inMemory;
  bool nullCheckDone;
  BoundCheckIndex boundCheck;
  int num_ranges;
  LiveRange* ranges;
  u4 delayFreeFlags; //! for use with flags defined by VRDelayFreeFlags enum
} MemoryVRInfo;
//!information of a temporary
//!the pair <regNum, physicalType> uniquely determines a variable
typedef struct TempRegInfo {
  int regNum;
  int physicalType;
  int refCount;
  int linkageToVR;
  int versionNum;
  bool shareWithVR; //for temp. regs updated by get_virtual_reg
  bool is8Bit;
} TempRegInfo;
struct BasicBlock_O1;
//!all variables accessed
//!the pair <regNum, physicalType> uniquely determines a variable
typedef struct compileTableEntry {
  int regNum;
  int physicalType; //gp, xmm or scratch, virtual
  int physicalReg;
  int physicalReg_prev; //for spilled GG VR
  RegAccessType accessType;

  bool isConst;
  int value[2]; //[0]: lower [1]: higher
  int refCount;

  int linkageToVR; //for temporary registers only
  GlobalType gType;
  struct BasicBlock_O1* bb; //bb VR belongs to
  int indexToInfoBB;

  VRState regState;
  TRState trState; //for temporary registers only
  int spill_loc_index; //for temporary registers only
} compileTableEntry;
//!to save the state of register allocator
typedef struct regAllocStateEntry1 {
  int spill_loc_index;
  int physicalReg;
} regAllocStateEntry1;
typedef struct regAllocStateEntry2 {
  int regNum; //
  bool inMemory; //whether 4-byte virtual reg is in memory
} regAllocStateEntry2;
//!edge in control flow graph
typedef struct Edge_O1 {
  struct BasicBlock_O1* src;
  struct BasicBlock_O1* dst;
} Edge_O1;
//!information associated with a basic block
typedef struct BasicBlock_O1 {
  int bb_index;
  int bb_index2;
  int pc_start;       //!inclusive
#ifndef WITH_JIT
  int pc_end;         //!exclusive
  Edge_O1* in_edges[MAX_NUM_EDGE_PER_BB]; //array of Edge*
  int num_in_edges;
  Edge_O1* out_edges[MAX_NUM_EDGE_PER_BB];
  int num_out_edges;
#else
  int pc_end;
  BasicBlock* jitBasicBlock;
#endif
  VirtualRegInfo infoBasicBlock[MAX_REG_PER_BASICBLOCK];
  int num_regs;

  RegAllocConstraint allocConstraints[8]; //# of times a hardcoded register is used in this basic block
  //a physical register that is used many times has a lower priority to get picked in getFreeReg
  RegAllocConstraint allocConstraintsSorted[8]; //count from low to high

  DefUsePair* defUseTable;
  DefUsePair* defUseTail;
  int num_defs;
  XferPoint xferPoints[MAX_XFER_PER_BB]; //program points where the transfer is required
  int num_xfer_points;

  bool endsWithReturn;
  bool hasAccessToGlue;
} BasicBlock_O1;
typedef struct CFG_O1 {
  BasicBlock_O1* head;
} CFG_O1;
//!worklist to create a control flow graph
typedef struct CFGWork {
  BasicBlock_O1* bb_prev;
  int targetOff;
  struct CFGWork* nextItem;
} CFGWork;

/////////////////////////////////////////
extern compileTableEntry compileTable[COMPILE_TABLE_SIZE];
extern int num_compile_entries;
extern VirtualRegInfo infoByteCode[MAX_REG_PER_BYTECODE];
extern int num_regs_per_bytecode;
extern TempRegInfo infoByteCodeTemp[MAX_TEMP_REG_PER_BYTECODE];
extern int num_temp_regs_per_bytecode;
extern VirtualRegInfo infoMethod[MAX_REG_PER_METHOD];
extern int num_regs_per_method;
extern BasicBlock_O1* currentBB;

extern BasicBlock_O1* method_bbs[MAX_NUM_BBS_PER_METHOD];
extern int num_bbs_for_method;
extern BasicBlock_O1* method_bbs_sorted[MAX_NUM_BBS_PER_METHOD];
extern BasicBlock_O1* bb_entry;
extern int pc_start;
extern int pc_end;
extern int current_bc_size;
extern int num_exception_handlers;
extern int exceptionHandlers[10];

extern int num_const_vr;
extern ConstVRInfo constVRTable[MAX_CONST_REG];

extern int genSet[MAX_REG_PER_BYTECODE];
extern int killSet[MAX_REG_PER_BYTECODE];
extern int num_regs_gen; //per bytecode
extern int num_regs_kill; //per bytecode

extern int genSetBB[MAX_NUM_BBS_PER_METHOD][40];
extern int killSetBB[MAX_NUM_BBS_PER_METHOD][40]; //same as size of memVRTable
extern int num_gen_bb[MAX_NUM_BBS_PER_METHOD];
extern int num_kill_bb[MAX_NUM_BBS_PER_METHOD];

extern int nullCheck_inB[MAX_NUM_BBS_PER_METHOD][40];
extern int nullCheck_inSize[MAX_NUM_BBS_PER_METHOD];
extern int nullCheck_outB[MAX_NUM_BBS_PER_METHOD][40];
extern int nullCheck_outSize[MAX_NUM_BBS_PER_METHOD];

typedef enum GlueVarType {
  RES_CLASS = 0,
  RES_METHOD,
  RES_FIELD,
  RES_STRING,
  GLUE_DVMDEX,
  GLUE_METHOD_CLASS,
  GLUE_METHOD
} GlueVarType;

void forwardAnalysis(int type);

//functions in bc_visitor.c
int getByteCodeSize();
bool getConstInfo(BasicBlock_O1* bb);
int getVirtualRegInfo(VirtualRegInfo* infoArray);
int getTempRegInfo(TempRegInfo* infoArray);
int createCFGHandler(Method* method);

int findVirtualRegInTable(u2 vA, LowOpndRegType type, bool printError);
int searchCompileTable(int type, int regNum);
BasicBlock_O1* createBasicBlock(int src_pc, int end_pc);
void handleJump(BasicBlock_O1* bb_prev, int relOff);
void connectBasicBlock(BasicBlock_O1* src, BasicBlock_O1* dst);
int insertWorklist(BasicBlock_O1* bb_prev, int targetOff);

int collectInfoOfBasicBlock(Method* method, BasicBlock_O1* bb); //update bb->infoBasicBlock

void updateCurrentBBWithConstraints(PhysicalReg reg);
void updateConstInfo(BasicBlock_O1*);
OpndSize getRegSize(int type);
void invalidateVRDueToConst(int reg, OpndSize size);
#endif