(*
 * Copyright (c) 2000-2001 Stefan Kral
 *
 * 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 2 of the License, 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 *)

(* This module provides two levels of machine-dependent instruction types 
 * that utilize x86-style address formats. Also,
 *	. 2-operand instruction forms are used.
 *	. unary operations are classified as either 'destructive' or 'copying'.
 *	. almost all binary operations are assumed to be destructive.
 *	  (which is true for almost all int/SIMD binary operations).
 *	. there is one 'copying' integer binary operation ('lea').
 *)

open List
open Util
open Number
open Variable
open VSimdBasics

(* DATA TYPE DEFINITIONS ***************************************************)

type p4stack =				(* STACKS SUPPORTED *****************)
  | P4_INTStack				(*   Integer Stack for Saving Args  *)
  | P4_MMXStack				(*   MMX Stack 			    *)

type p4memop =				(* MEMORY OPERAND *******************)
  | P4_MConst of string			(*   Named Constant (read-only)     *)
  | P4_MVar of string			(*   Named Variable (read-write)    *)
  | P4_MFunArg of			(*   Function Argument (1-based)    *)
	int				(*	= i (the i-th argument)	    *)
  | P4_MStackCell of 			(*   Stackcell (0-based)	    *)
	p4stack * 			(*	= stack type (int/mmx)	    *)
	int				(*	= position on stack	    *)

type p4intunaryop =			(* P4 INTEGER UNARY OPERATION *******)
  | P4_IPush				(*   Store on the Stack		    *)
  | P4_IPop				(*   Load from the Stack	    *)
  | P4_INegate				(*   Negate Signed Integer          *)
  | P4_IClear				(*   Clear Integer Register	    *)
  | P4_IInc				(*   Increment Integer (= add one)  *)
  | P4_IDec				(*   Decrement Integer (= sub one)  *)
  | P4_IAddImm of int			(*   Add Constant to Register	    *)
  | P4_ISubImm of int			(*   Subtract Constant from Reg     *)
  | P4_IShlImm of int			(*   Signed Shift Left by N bits    *)
  | P4_IShrImm of int			(*   Signed Shift Right by N bits   *)
  | P4_ILoadValue of int		(*   Load Const into Int Register   *)

type p4intcpyunaryop =			(* P4 INTEGER COPYING UNARY OP ******)
  | P4_ICopy				(*   Copy Integer Register          *)
  | P4_IMulImm of int			(*   Signed Multiply w/Int-Constant *)

type p4intbinop = 			(* P4 INTEGER BINARY OPERATION ******)
  | P4_IAdd				(*   Signed Integer Addition	    *)
  | P4_ISub				(*   Signed Integer Subtraction     *)

type p4simdunaryop = 			(* P4 FP-SIMD UNARY OPERATION *******)
  | P4_FPChs of vsimdpos		(*   Change Sign 		    *)
  | P4_FPMulC1 of 			(*   Scalar Mul with Constant:      *) 
	number				(*	= constant c		    *)
  | P4_FPMulC2 of			(*   2-way SIMD Mul w/Constant:     *)
	number *			(*	= lower part of constant    *)
	number				(*	= upper part of constant    *)

type p4simdcpyunaryop =			(* P4 FP-SIMD COPYING UNARY OP ******)
  | P4_FPId				(*   Copy Simd Register		    *)

type p4simdbinop = 			(* P4 SIMD BINARY OPERATION *********)
  | P4_FPAdd1 				(*   FP Addition (Scalar)	    *)
  | P4_FPAdd2				(*   FP Addition (2-way SIMD)	    *)
  | P4_FPSub1				(*   FP Subtraction (Scalar)	    *)
  | P4_FPSub2				(*   FP Subtraction (2-way SIMD)    *)
  | P4_FPMul1				(*   FP Multiplication (Scalar)	    *)
  | P4_FPMul2				(*   FP Multiplication (2-way SIMD) *)
  | P4_UnpckLo				(*   Join Lo Parts of 2 Simd Words  *)
  | P4_UnpckHi				(*   Join Hi Parts of 2 Simd Words  *)
  | P4_Shuffle of int			(*   Shuffle Operation		    *)

type p4operandsize =				(* P4 OPERAND SIZE **********)
  | P4_QWord					(*   Quad Word (64 bits)    *)
  | P4_OWord					(*   Octa Word (128 bits)   *)

type p4branchcondition =			(* P4 BRANCH CONDITION ******)
  | P4_BCond_NotZero
  | P4_BCond_Zero
  | P4_BCond_GreaterZero
  | P4_BCond_EqualZero


(****************************************************************************
 * P4V DATA TYPES ***********************************************************
 ****************************************************************************)

type p4vaddr =					(* P4 VIRTUAL ADDRESS *******)
  | P4V_RID of vintreg * int 			(*   %2(%1)		    *)
  | P4V_SID of vintreg * int * int		(*   %3(,%1,%2)		    *)
  | P4V_RISID of vintreg * vintreg * int * int 	(*   %4(%1,%2,%3)	    *)

type p4vbranchtarget =			(* P4 VIRTUAL BRANCH TARGET *********)
  | P4V_BTarget_Named of string		(*   Named Branch Target (string)   *)

type p4vinstr = 			(* P4 VIRTUAL INSTRUCTION ***********)
  | P4V_IntLoadMem of 			(*   Load Integer from Memory	    *)
	p4memop *			(*	= source operand (s_mem)    *)
	vintreg				(*	= dest register (d_reg)     *)
  | P4V_IntStoreMem of 			(*   Store Integer to Memory	    *)
	vintreg *			(*	= source register (s)	    *)
	p4memop				(*	= destination (d_mem)	    *)
  | P4V_IntLoadEA of			(*   Load Effective Address	    *)
	p4vaddr *			(*      = source address (s_mem)    *)
	vintreg				(*	= destination register (d)  *)
  | P4V_IntUnaryOp of 			(*   Destructive Int Unary Op       *)
	p4intunaryop *			(*      = operation identifier (op) *) 
	vintreg				(*	= source/dest register (sd) *)
  | P4V_IntUnaryOpMem of 		(*   Destructive Int Unary Op w/Mem *)
	p4intunaryop *			(*      = operation identifier (op) *)
	p4memop				(*	= src/dest operand (sd_mem) *)
  | P4V_IntCpyUnaryOp of 		(*   Copying Int Unary Operation    *)
	p4intcpyunaryop *		(*      = operation identifier (op) *)
	vintreg *			(*      = source register (s)	    *)
	vintreg				(*	= destination register (d)  *)
  | P4V_IntBinOp of			(*   Integer Binary Operation	    *)
	p4intbinop *			(* 	= operation identifier (op) *)
	vintreg *			(* 	= source register (s)	    *)
	vintreg				(*	= source/dest register (sd) *)
  | P4V_IntBinOpMem of			(*   Integer Binary Operation w/Mem *)
	p4intbinop *			(* 	= operation identifier (op) *)
	p4memop *			(* 	= source operand (s_mem)    *)
	vintreg				(*	= source/dest register (sd) *)
  | P4V_SimdLoad of 			(*   SIMD Load Data		    *)
	p4operandsize *			(*	= operand size (s_size)	    *)
	p4vaddr * 			(*	= source address (s_addr)   *)
	vsimdreg			(*	= destination register (d)  *)
  | P4V_SimdStore of			(*   SIMD Store Data		    *)
	vsimdreg * 			(*	= source register (s)	    *)
	p4operandsize *			(*	= operand size (d_size)	    *)
	p4vaddr				(*	= dest address (d_addr)     *)
  | P4V_SimdLoad1 of 			(*   SIMD Load Data		    *)
	p4vaddr * 			(*	= source address (s_addr)   *)
	vsimdpos *			(*	= interesting part (d_part) *)
	vsimdreg			(*	= destination register (d)  *)
  | P4V_SimdStore1 of			(*   SIMD Store Data		    *)
	vsimdpos *			(*	= interesting part (s_part) *)
	vsimdreg * 			(*	= source register (s)	    *)
	p4vaddr				(*	= dest address (d_addr)     *)
  | P4V_SimdUnaryOp of 			(*   Destructive SIMD Unary Op	    *)
	p4simdunaryop *			(*	= operation identifier (op) *)
	vsimdreg 			(*	= source/dest register (sd) *)
  | P4V_SimdCpyUnaryOp of 		(*   Copying SIMD Unary Operation   *)
	p4simdcpyunaryop *		(*	= operation identifier (op) *)
	vsimdreg *			(*	= source register (s)	    *)
	vsimdreg 			(*	= destination register (d)  *)
  | P4V_SimdCpyUnaryOpMem of		(*   Copying SIMD Unary Op w/Mem    *)
	p4simdcpyunaryop *		(*	= operation identifier (op) *)
	p4memop *			(*	= source operand (s_memop)  *)
	vsimdreg 			(*	= destination register (d)  *)
  | P4V_SimdBinOp of			(*   SIMD Binary Operation	    *)
	p4simdbinop *			(*	= operation identifier (op) *)
	vsimdreg *			(*      = source register (s)	    *)
	vsimdreg			(*	= source/dest register (sd) *)
  | P4V_SimdBinOpMem of			(*   SIMD Binary Operation w/Mem    *)
	p4simdbinop *			(*	= operation identifier (op) *)
	p4memop *			(*      = source operand (s_memop)  *)
	vsimdreg			(*	= source/dest register (sd) *)
  | P4V_SimdLoadStoreBarrier		(*   SIMD Load/Store Barrier	    *)
  | P4V_RefInts of			(*   Reference Integer Registers    *)
	vintreg list			(*	= source registers (s) 	    *)
  | P4V_Label of			(*   Label (Named Branch Target)    *)
	string				(*	= label name (s_str)	    *)
  | P4V_Jump of				(*   Unconditional Branch	    *)
	p4vbranchtarget			(*	= branch target 	    *)
  | P4V_CondBranch of			(*   Conditional Branch		    *)
	p4branchcondition *		(*	= branch condition	    *)
	p4vbranchtarget			(*	= branch target		    *)
  | P4V_SimdPromiseCellSize of 		(*   Specify Size of MMX Stackcells *)
	p4operandsize


(****************************************************************************
 * P4R DATA TYPES ***********************************************************
 ****************************************************************************)

type p4rmmxreg = P4R_MMXReg of string	     (* P4 REAL MMX (SIMD) REGISTER *)
type p4rintreg = P4R_IntReg of string	     (* P4 REAL INTEGER REGISTER    *)

let toP4rintreg i = P4R_IntReg i
let toP4rmmxreg m = P4R_MMXReg m

module RIntRegMap  = Map.Make(struct type t=p4rintreg let compare=compare end)
module RSimdRegMap = Map.Make(struct type t=p4rmmxreg let compare=compare end)

(* The modes 'RID' and 'SID' exist because they introduce fewer 
 * dependencies between registers. *)
type p4raddr =						(* P4 REAL ADDRESS **)
  | P4R_RID of p4rintreg * int 				(*   %2(%1)	    *)
  | P4R_SID of p4rintreg * int * int			(*   %3(,%1,%2)	    *)
  | P4R_RISID of p4rintreg * p4rintreg * int * int	(*   %4(%1,%2,%3)   *)

type p4rbranchtarget =			(* P4 REAL BRANCH TARGET ************)
  | P4R_BTarget_Named of string		(*   Named Branch Target (string)   *)

type p4rinstr =				(* P4 REAL INSTRUCTION **************)
  | P4R_IntLoadMem of			(*   Load Integer From Memory	    *)
	p4memop *			(*	= source operand (s_memop)  *)
	p4rintreg			(*	= destination register (d)  *)
  | P4R_IntStoreMem of			(*   Store Integer To Memory	    *)
	p4rintreg *			(*	= source register (s)	    *)
	p4memop				(*	= destination (d_memop)	    *)
  | P4R_IntLoadEA of 			(*   Load Effective Address	    *)
	p4raddr *			(*	= source address (s_addr)   *)
	p4rintreg			(*	= destination register (d)  *)
  | P4R_IntUnaryOp of			(*   Destructive Integer Unary Op   *)
	p4intunaryop *			(*	= operation identifier (op) *)
	p4rintreg			(*	= source/dest register (sd) *)
  | P4R_IntUnaryOpMem of		(*   Destructive Int Unary Op w/Mem *)
	p4intunaryop *			(*	= operation identifier (op) *)
	p4memop				(*	= source/dest (sd_memop)    *)
  | P4R_IntCpyUnaryOp of		(*   Copying Integer Unary Op	    *)
	p4intcpyunaryop *		(*	= operation identifier (op) *)
	p4rintreg *			(*	= source register (s)	    *)
	p4rintreg			(*	= destination register (d)  *)
  | P4R_IntBinOp of			(*   Integer Binary Operation	    *)
	p4intbinop *			(*	= operation identifier (op) *)
	p4rintreg *			(*	= source register (s)	    *)
	p4rintreg 			(*	= source/dest register (sd) *)
  | P4R_IntBinOpMem of			(*   Int Binary Op w/Mem Operand    *)
	p4intbinop *			(*	= operation identifier (op) *)
	p4memop *			(*	= source operand (s_memop)  *)
	p4rintreg 			(*	= source/dest register (sd) *)
  | P4R_SimdLoad of 			(*   SIMD Load Data		    *)
	p4operandsize *			(*	= operand size (s_size)	    *)
	p4raddr * 			(*	= source address (s_addr)   *)
	p4rmmxreg			(*	= dest register (d_reg)	    *)
  | P4R_SimdStore of 			(*   SIMD Store Data		    *)
	p4rmmxreg * 			(*	= source register (s)	    *)
	p4operandsize *			(*	= operand size (d_size)	    *)
	p4raddr				(*	= destination addr (d_addr) *)
  | P4R_SimdLoad1 of 			(*   SIMD Load Data		    *)
	p4raddr * 			(*	= source address (s_addr)   *)
	vsimdpos *			(*	= interesting part (d_part) *)
	p4rmmxreg			(*	= dest register (d_reg)	    *)
  | P4R_SimdStore1 of 			(*   SIMD Store Data		    *)
	vsimdpos *			(*	= interesting part (s_part) *)
	p4rmmxreg * 			(*	= source register (s)	    *)
	p4raddr				(*	= destination addr (d_addr) *)
  | P4R_SimdSpill of 			(*   Spill SIMD Register To Stack   *)
	p4rmmxreg * 			(*	= source register (s)	    *)
	int				(*	= dest cell-index (d_idx)   *)
  | P4R_SimdUnaryOp of			(*   SIMD Destructive Unary Op	    *)
	p4simdunaryop *			(*	= operation identifier (op) *)
	p4rmmxreg			(*	= source/dest register (sd) *)
  | P4R_SimdCpyUnaryOp of		(*   SIMD Copying Unary Op	    *)
	p4simdcpyunaryop *		(*	= operation identifier (op) *)
	p4rmmxreg *			(*	= source register (s)	    *)
	p4rmmxreg			(*	= destination register (d)  *)
  | P4R_SimdCpyUnaryOpMem of		(*   SIMD Copying Unary Op w/Mem    *)
	p4simdcpyunaryop *		(*	= operation identifier (op) *)
	p4memop *			(*	= source operand (s_memop)  *)
	p4rmmxreg			(*	= destination register (d)  *)
  | P4R_SimdBinOp of 			(*   SIMD Binary Operation	    *)
	p4simdbinop * 			(*	= operation identifier (op) *)
	p4rmmxreg * 			(*	= source register (s)	    *)
	p4rmmxreg			(*	= source/dest register (sd) *)
  | P4R_SimdBinOpMem of 		(*   SIMD Binary Op w/Mem Operand   *)
	p4simdbinop *			(*	= operation identifier (op) *)
	p4memop *			(*	= source operand (s_memop)  *)
	p4rmmxreg			(*	= source/dest register (d)  *)
  | P4R_SimdLoadStoreBarrier		(*   SIMD Load/Store Barrier	    *)
  | P4R_Label of			(*   Label (Named Branch Target)    *)
	string				(*	= label name (s_str)	    *)
  | P4R_Jump of				(*   Unconditional Branch	    *)
	p4rbranchtarget			(*	= branch target 	    *)
  | P4R_CondBranch of			(*   Conditional Branch		    *)
	p4branchcondition *		(*	= branch condition	    *)
	p4rbranchtarget			(*	= branch target		    *)
  | P4R_Ret				(*   Return From Subroutine	    *)
  | P4R_SimdPromiseCellSize of 		(*   Specify Size of MMX Stackcells *)
	p4operandsize


(* DEFINITION OF CONSTANTS **************************************************)

let p4rmmxregs_names = ["xmm0"; "xmm1"; "xmm2"; "xmm3"; 
			"xmm4"; "xmm5"; "xmm6"; "xmm7"]

let p4rintregs_names = ["eax"; "ecx"; "edx"; "ebx"; "esi"; "edi"; "ebp"]
let p4rintregs_calleesaved_names = ["ebx"; "esi"; "edi"; "ebp"]
let p4rintreg_stackpointer_name  = "esp"

let p4rmmxregs = map toP4rmmxreg p4rmmxregs_names
let p4rintregs = map toP4rintreg p4rintregs_names
let p4rintregs_calleesaved = map toP4rintreg p4rintregs_calleesaved_names
let p4rintreg_stackpointer = toP4rintreg p4rintreg_stackpointer_name


(* FUNCTIONS OPERATING ON VALUES OF TYPE P4... ******************************)

let p4operandsizeToString = function
  | P4_QWord -> "P4_QWord"
  | P4_OWord -> "P4_OWord"

let p4operandsizeToInteger = function
  | P4_QWord -> 8
  | P4_OWord -> 16

let p4simdbinopIsParallel = function
  | P4_FPAdd2 | P4_FPSub2 | P4_FPMul2 -> true
  | P4_FPAdd1 | P4_FPSub1 | P4_FPMul1 -> false
  | P4_UnpckLo | P4_UnpckHi | P4_Shuffle _ -> false

let p4simdbinopIsCommutative = function
  | P4_FPAdd1 | P4_FPAdd2 -> true
  | P4_FPMul1 | P4_FPMul2 -> true
  | P4_FPSub1 | P4_FPSub2 -> false
  | P4_UnpckLo | P4_UnpckHi | P4_Shuffle _ -> false

let p4simdbinopToCommutativeCounterpart x = match x with
  | P4_FPAdd1 | P4_FPAdd2 -> x
  | P4_FPMul1 | P4_FPMul2 -> x
  | _ -> failwith "p4simdbinopToCommutativeCounterpart: not supported!"


(* FUNCTIONS OPERATING ON VALUES OF TYPE P4V... *****************************)

let vsimdunaryopToP4simdcpyunaryop = function
  | V_Id -> P4_FPId
  | _	 -> failwith "vsimdunaryopToP4simdcpyunaryop"

let vsimdbinopToP4simdbinop = function
  | V_Add1     -> P4_FPAdd1
  | V_Add2     -> P4_FPAdd2
  | V_Sub1     -> P4_FPSub1
  | V_Sub2     -> P4_FPSub2
  | V_Mul1     -> P4_FPMul1
  | V_Mul2     -> P4_FPMul2
  | V_UnpckLo -> P4_UnpckLo
  | V_UnpckHi -> P4_UnpckHi
  | V_Shuffle x -> P4_Shuffle x
  | V_PNAcc | V_NNAcc | V_NPAcc | V_PPAcc -> failwith "vsimdbinopToP4simdbinop"


let p4vaddrToP4raddr map = function
  | P4V_RID(base,ofs)		   -> P4R_RID(map base, ofs)
  | P4V_SID(idx,scalar,ofs)	   -> P4R_SID(map idx, scalar, ofs)
  | P4V_RISID(base,idx,scalar,ofs) -> P4R_RISID(map base, map idx, scalar, ofs)

let p4vaddrToSimplified = function
  | P4V_SID(index,2,ofs)	   -> P4V_RISID(index,index,1,ofs)
  | P4V_RISID(base,index,0,ofs)	   -> P4V_RID(base,ofs)
  | vaddr 			   -> vaddr

let p4vaddrToVintregs = function	(* output may contain duplicates *)
  | P4V_RID(base,_)	      -> [base]
  | P4V_SID(base,_,_)	      -> [base]
  | P4V_RISID(base,index,_,_) -> [base; index]

let p4vbranchtargetToVintregs (P4V_BTarget_Named _) = []

let p4vinstrToSrcvregs = function	(* output may contain duplicates *)
  | P4V_SimdLoadStoreBarrier  -> [],	 []
  | P4V_SimdPromiseCellSize _ -> [],	 []
  | P4V_Label _		      -> [],     []
  | P4V_RefInts xs	      -> [],     xs
  | P4V_CondBranch(cond,d)    -> [],     p4vbranchtargetToVintregs d
  | P4V_Jump d		      -> [],     p4vbranchtargetToVintregs d
  | P4V_IntCpyUnaryOp(_,s,_)  -> [],	 [s]
  | P4V_IntUnaryOp(P4_IPop,_) -> [],	 []
  | P4V_IntUnaryOp(_,sd)      -> [],	 [sd]
  | P4V_IntUnaryOpMem _	      -> [],	 []
  | P4V_IntBinOp(_,s,sd)      -> [],	 [s;sd]
  | P4V_IntBinOpMem(_,_,sd)   -> [],     [sd]
  | P4V_IntLoadEA(s,_) 	      -> [],	 p4vaddrToVintregs s
  | P4V_IntLoadMem _	      -> [],	 []
  | P4V_IntStoreMem(s,_)      -> [],	 [s]
  | P4V_SimdLoad(_,s,_)       -> [],	 p4vaddrToVintregs s
  | P4V_SimdStore(s,_,d)      -> [s],    p4vaddrToVintregs d
  | P4V_SimdLoad1(s,_,_)      -> [],	 p4vaddrToVintregs s
  | P4V_SimdStore1(_,s,d)     -> [s],    p4vaddrToVintregs d
  | P4V_SimdBinOp(_,s,sd)     -> [s;sd], []
  | P4V_SimdBinOpMem(_,_,sd)  -> [sd],   []
  | P4V_SimdUnaryOp(_,sd)     -> [sd],   []
  | P4V_SimdCpyUnaryOp(_,s,_) -> [s],    []
  | P4V_SimdCpyUnaryOpMem _   -> [],     []

let p4vinstrToDstvregs = function	(* output may contain duplicates :-) *)
  | P4V_SimdLoadStoreBarrier	 -> [],	  []
  | P4V_SimdPromiseCellSize _    -> [],   []
  | P4V_Label _		         -> [],   []
  | P4V_RefInts _	         -> [],   []
  | P4V_CondBranch(cond,d)       -> [],   []
  | P4V_Jump d		         -> [],   []
  | P4V_IntLoadMem(_,d)		 -> [],   [d]
  | P4V_IntStoreMem _		 -> [],   []
  | P4V_IntLoadEA(_,d)		 -> [],   [d]
  | P4V_IntUnaryOp(P4_IPush,_) 	 -> [],   []
  | P4V_IntUnaryOp(_,sd) 	 -> [],   [sd]
  | P4V_IntUnaryOpMem _		 -> [],   []
  | P4V_IntCpyUnaryOp(_,_,d)     -> [],   [d]
  | P4V_IntBinOp(_,_,sd) 	 -> [],   [sd]
  | P4V_IntBinOpMem _		 -> [],	  []
  | P4V_SimdLoad(_,_,d) 	 -> [d],  []
  | P4V_SimdStore _  		 -> [],   []
  | P4V_SimdLoad1(_,_,d) 	 -> [d],  []
  | P4V_SimdStore1 _  		 -> [],   []
  | P4V_SimdBinOp(_,_,sd) 	 -> [sd], []
  | P4V_SimdBinOpMem(_,_,sd) 	 -> [sd], []
  | P4V_SimdUnaryOp(_,sd) 	 -> [sd], []
  | P4V_SimdCpyUnaryOp(_,_,d)    -> [d],  []
  | P4V_SimdCpyUnaryOpMem(_,_,d) -> [d],  []

(* the lists returned do not have duplicates. *)
let p4vinstrToVregs instr = 
  let (s_simd0,s_int0) = p4vinstrToSrcvregs instr in
  let (s_simd, s_int) as src_regs = uniq s_simd0, uniq s_int0 in
  let (d_simd0,d_int0) = p4vinstrToDstvregs instr in
  let (d_simd,d_int) as dst_regs = diff d_simd0 s_simd, diff d_int0 s_int in
    (src_regs, dst_regs, src_regs @. dst_regs)


(* FUNCTIONS OPERATING ON VALUES OF TYPE P4R... *****************************)

let p4raddrToP4rintregs = function	(* output may contain duplicates *)
  | P4R_RID(base,_)	      -> [base]
  | P4R_SID(base,_,_)	      -> [base]
  | P4R_RISID(base,index,_,_) -> [base; index]

let p4raddrToSimplified = function
  | P4R_SID(index,2,ofs)	-> P4R_RISID(index,index,1,ofs)
  | P4R_RISID(base,index,0,ofs)	-> P4R_RID(base,ofs)
  | raddr 			-> raddr

(* returns pair (simds,ints) *)
let p4rinstrToSrcp4rregs = function
  | P4R_SimdLoadStoreBarrier  -> [],	 []
  | P4R_SimdPromiseCellSize _ -> [],     []
  | P4R_IntLoadMem _ 	      -> [], 	 []
  | P4R_IntStoreMem(s,_)      -> [], 	 [s]
  | P4R_IntLoadEA(s,_) 	      -> [], 	 p4raddrToP4rintregs s
  | P4R_IntUnaryOp(_,sd)      -> [], 	 [sd]		(* conservative *)
  | P4R_IntUnaryOpMem _       -> [], 	 []
  | P4R_IntCpyUnaryOp(_,s,_)  -> [], 	 [s]
  | P4R_IntBinOp(_,s,sd)      -> [], 	 [s;sd]
  | P4R_IntBinOpMem(_,_,sd)   -> [], 	 [sd]
  | P4R_SimdLoad(_,s,_)       -> [], 	 p4raddrToP4rintregs s
  | P4R_SimdStore(s,_,d)      -> [s], 	 p4raddrToP4rintregs d
  | P4R_SimdLoad1(s,_,d)      -> [d], 	 p4raddrToP4rintregs s
  | P4R_SimdStore1(_,s,d)     -> [s], 	 p4raddrToP4rintregs d
  | P4R_SimdSpill(s,_) 	      -> [s], 	 []
  | P4R_SimdUnaryOp(_,sd)     -> [sd], 	 []
  | P4R_SimdCpyUnaryOp(_,s,_) -> [s], 	 []
  | P4R_SimdCpyUnaryOpMem _   -> [], 	 []
  | P4R_SimdBinOp(_,s,sd)     -> [s;sd], []
  | P4R_SimdBinOpMem(_,_,sd)  -> [sd], 	 []
  | P4R_Label _ 	      -> [], 	 []
  | P4R_Jump _ 		      -> [], 	 []
  | P4R_CondBranch _ 	      -> [], 	 []
  | P4R_Ret 		      -> [],     []

(* returns pair (simds,ints) *)
let p4rinstrToDstp4rregs = function
  | P4R_SimdLoadStoreBarrier     -> [],   []
  | P4R_SimdPromiseCellSize _    -> [],   []
  | P4R_IntLoadMem(_,d)		 -> [],   [d]
  | P4R_IntStoreMem _   	 -> [],   []
  | P4R_IntLoadEA(_,d) 		 -> [],   [d]
  | P4R_IntUnaryOp(_,sd)	 -> [],   [sd]		(* conservative *)
  | P4R_IntUnaryOpMem _ 	 -> [],   []
  | P4R_IntCpyUnaryOp(_,_,d)     -> [],   [d]
  | P4R_IntBinOp(_,_,sd)	 -> [],   [sd]
  | P4R_IntBinOpMem(_,_,sd)      -> [],   [sd]
  | P4R_SimdLoad(_,_,d)		 -> [d],  []
  | P4R_SimdStore _		 -> [],   []
  | P4R_SimdLoad1(_,_,d)	 -> [d],  []
  | P4R_SimdStore1 _		 -> [],   []
  | P4R_SimdSpill _ 		 -> [],   []
  | P4R_SimdUnaryOp(_,sd)	 -> [sd], []
  | P4R_SimdCpyUnaryOp(_,_,d)	 -> [d],  []
  | P4R_SimdCpyUnaryOpMem(_,_,d) -> [d],  []
  | P4R_SimdBinOp(_,_,sd)	 -> [sd], []
  | P4R_SimdBinOpMem(_,_,sd)	 -> [sd], []
  | P4R_Label _			 -> [],   []
  | P4R_Jump _ 			 -> [],   []
  | P4R_CondBranch _ 		 -> [],   []
  | P4R_Ret 			 -> [],   []

let p4rinstrIsMMX = function
  | P4R_SimdLoadStoreBarrier  -> true
  | P4R_SimdPromiseCellSize _ -> true
  | P4R_SimdLoad _	      -> true
  | P4R_SimdStore _	      -> true
  | P4R_SimdLoad1 _	      -> true
  | P4R_SimdStore1 _	      -> true
  | P4R_SimdSpill _	      -> true
  | P4R_SimdUnaryOp _	      -> true
  | P4R_SimdCpyUnaryOp _      -> true
  | P4R_SimdCpyUnaryOpMem _   -> true
  | P4R_SimdBinOp _	      -> true
  | P4R_SimdBinOpMem _	      -> true
  | P4R_IntLoadMem _	      -> false
  | P4R_IntStoreMem _	      -> false
  | P4R_IntLoadEA _	      -> false
  | P4R_IntUnaryOp _	      -> false
  | P4R_IntUnaryOpMem _       -> false
  | P4R_IntCpyUnaryOp _	      -> false
  | P4R_IntBinOp _	      -> false
  | P4R_IntBinOpMem _	      -> false
  | P4R_Label _		      -> false
  | P4R_Jump _		      -> false
  | P4R_CondBranch _	      -> false
  | P4R_Ret		      -> false

let p4rinstrReadsP4rreg sel rreg instr  = 
  mem rreg (sel (p4rinstrToSrcp4rregs instr))

let p4rinstrWritesP4rreg sel rreg instr = 
  mem rreg (sel (p4rinstrToDstp4rregs instr))

let p4rinstrReadsP4rmmxreg rreg instr  = p4rinstrReadsP4rreg fst rreg instr
let p4rinstrReadsP4rintreg rreg instr  = p4rinstrReadsP4rreg snd rreg instr

let p4rinstrWritesP4rmmxreg rreg instr = p4rinstrWritesP4rreg fst rreg instr
let p4rinstrWritesP4rintreg rreg instr = p4rinstrWritesP4rreg snd rreg instr

let p4rinstrUsesP4rmmxreg rreg instr = 
  p4rinstrReadsP4rmmxreg rreg instr || p4rinstrWritesP4rmmxreg rreg instr

let p4rinstrUsesP4rintreg rreg instr = 
  p4rinstrReadsP4rintreg rreg instr || p4rinstrWritesP4rintreg rreg instr

