(*
 * Copyright (c) 2001-2002 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 features a set of rules to optimize the code produced by
 * the vectorizer. 
 *)

open List
open Util
open Id
open Number
open VFpBasics
open VSimdBasics
open VSimdIndexing
open NonDetMonad
open NonDetUtils

type istore' =
  | IStore of				(* INSTRUCTION STORE ***************)
	Id.t list VSimdRegMap.t * 	(*   table of readers (0..n)  	   *)
	Id.t list VSimdRegMap.t * 	(*   table of writers (0..1) 	   *)
	Id.t list VSICMap.t *		(*   all instrs in some category   *)
	vsimdinstr IdMap.t		(*   all instructions		   *)

let fetchIStoreM    = fetchStateM >>= fun s -> unitM (fst s)
let fetchVisitedM   = fetchStateM >>= fun s -> unitM (snd s)

let storeIStoreM x  = fetchStateM >>= fun s -> storeStateM (repl1of2 x s)
let storeVisitedM x = fetchStateM >>= fun s -> storeStateM (repl2of2 x s)

(****************************************************************************)

let isUnusedM reg =
  fetchVisitedM >>= fun visited ->
  fetchIStoreM >>= fun (IStore(readers,_,_,_)) ->
    let readers_of_reg = vsimdregmap_findE reg readers in
      posAssertM (for_all (fun i -> mem i visited) readers_of_reg)

let getSuitableInstructionM mapM instrs =
  fetchIStoreM >>= fun (IStore(_,_,_,idmap)) ->
  fetchVisitedM >>= fun visited ->
    memberM instrs >>= fun id ->
      negAssertM (mem id visited) >>= fun _ ->		(* not visited yet *)
        mapM (IdMap.find id idmap) >>= fun info_tupel ->
          storeVisitedM (id::visited) >>= fun _ ->	(* mark as visited *)
	    unitM (id,info_tupel)

let getInstr1M mapM c =
  fetchIStoreM >>= fun (IStore(_,_,categories,_)) ->
    getSuitableInstructionM mapM (vsicmap_findE c categories)

let getInstr2M mapM cs = memberM cs >>= getInstr1M mapM

let getReaderOfM mapM reg =
  fetchIStoreM >>= fun (IStore(readers,_,_,_)) ->
    getSuitableInstructionM mapM (VSimdRegMap.find reg readers)

let getWriterOfM mapM reg =
  fetchIStoreM >>= fun (IStore(_,writers,_,_)) ->
    getSuitableInstructionM mapM (VSimdRegMap.find reg writers)

(****************************************************************************)

let copyinstrToTupelM = function
  | V_SimdUnaryOp(V_Id,s,d) -> unitM (s,d)
  | _ -> failM

let swapinstrToTupelM = function
  | V_SimdUnaryOp(V_Swap,s,d) -> unitM (s,d)
  | _ -> failM

let mulconstinstrToTupelM p q = function
  | V_SimdUnaryOp(V_MulConst(k1,k2),s,d) when p k1 && q k2 -> unitM (s,k1,k2,d)
  | _ -> failM

let mulconstinstrToTupelM' = function
  | V_SimdUnaryOp(V_MulConst(k1,k2),s,d) -> unitM (s,k1,k2,d)
  | _ -> failM

let chsloinstrToTupelM = function
  | V_SimdUnaryOp(V_Chs V_ChsLo,s,d) -> unitM (s,d)
  | _ -> failM

let chshiinstrToTupelM = function
  | V_SimdUnaryOp(V_Chs V_ChsHi,s,d) -> unitM (s,d)
  | _ -> failM

let chslohiinstrToTupelM = function
  | V_SimdUnaryOp(V_Chs V_ChsLoHi,s,d) -> unitM (s,d)
  | _ -> failM

let unaryopinstrToTupelM = function
  | V_SimdUnaryOp(op,s,d) -> unitM (op,s,d)
  | _ -> failM

let chsinstrToTupelM = function
  | V_SimdUnaryOp(V_Chs p,s,d) -> unitM (p,s,d)
  | _ -> failM

let binopinstrToTupelM = function
  | V_SimdBinaryOp(op,s1,s2,d) -> unitM (op,s1,s2,d)
  | _ -> failM

let parbinopinstrToTupelM = function
  | V_SimdBinaryOp(op,s1,s2,d) when vsimdbinopIsParallel op -> unitM (op,s1,s2,d)
  | _ -> failM

let subinstrToTupelM = function
  | V_SimdBinaryOp(V_Sub2,s1,s2,d) -> unitM (s1,s2,d)
  | _ -> failM

let addinstrToTupelM = function
  | V_SimdBinaryOp(V_Add2,s1,s2,d) -> unitM (s1,s2,d)
  | _ -> failM

let mulinstrToTupelM = function
  | V_SimdBinaryOp(V_Mul2,s1,s2,d) -> unitM (s1,s2,d)
  | _ -> failM

let accinstrToTupelM p1 p2 = function
  | V_SimdBinaryOp(V_Acc2(m1,m2),s1,s2,d) when p1 m1 && p2 m2 -> unitM (p1,p2,s1,s2,d)
  | _ -> failM

let fmca2instrToTupelM p1 p2 = function
  | V_SimdBinaryOp(V_FMcA2(k1,k2),a,b,c) when p1 k1 && p2 k2 -> unitM (a,k1,k2,b,c)
  | _ -> failM

let fnmca2instrToTupelM p1 p2 = function
  | V_SimdBinaryOp(V_FNMcA2(k1,k2),a,b,c) when p1 k1 && p2 k2 -> unitM (a,k1,k2,b,c)
  | _ -> failM

let fmcs2instrToTupelM p1 p2 = function
  | V_SimdBinaryOp(V_FMcS2(k1,k2),a,b,c) when p1 k1 && p2 k2 -> unitM (a,k1,k2,b,c)
  | _ -> failM

let fmca2instrToTupelM' = function
  | V_SimdBinaryOp(V_FMcA2(k1,k2),a,b,c) -> unitM (a,k1,k2,b,c)
  | _ -> failM

let fnmca2instrToTupelM' = function
  | V_SimdBinaryOp(V_FNMcA2(k1,k2),a,b,c) -> unitM (a,k1,k2,b,c)
  | _ -> failM

let fmcs2instrToTupelM' = function
  | V_SimdBinaryOp(V_FMcS2(k1,k2),a,b,c) -> unitM (a,k1,k2,b,c)
  | _ -> failM

let unpacklohiinstrToTupelM = function
  | V_SimdBinaryOp(V_UnpackLH,s1,s2,d) -> unitM (s1,s2,d)
  | _ -> failM

let unpackloinstrToTupelM = function
  | V_SimdBinaryOp(V_UnpackL,s1,s2,d) -> unitM (s1,s2,d)
  | _ -> failM

let unpackhiinstrToTupelM = function
  | V_SimdBinaryOp(V_UnpackH,s1,s2,d) -> unitM (s1,s2,d)
  | _ -> failM

(****************************************************************************)

let getUnaryopInstrM = 
  getInstr2M unaryopinstrToTupelM vsimdunaryopcategories_all

let getUnaryopInstrM_NoCopy = 
  getInstr2M unaryopinstrToTupelM vsimdunaryopcategories_nocopy

let getBinopInstrM = 
  getInstr2M binopinstrToTupelM vsimdbinopcategories_all

let getParbinopInstrM = 
  getInstr2M parbinopinstrToTupelM vsimdbinopcategories_par

let getCopyInstrM = getInstr1M copyinstrToTupelM VSIC_UnaryCopy
let getSwapInstrM = getInstr1M swapinstrToTupelM VSIC_UnarySwap

let getMulconstInstrM' = 
  getInstr1M mulconstinstrToTupelM' VSIC_UnaryMulConst

let getMulconstInstrM p1 p2 = 
  getInstr1M (mulconstinstrToTupelM p1 p2) VSIC_UnaryMulConst

let getChsInstrM = getInstr2M chsinstrToTupelM vsimdunaryopcategories_chs
let getChsloInstrM = getInstr1M chsloinstrToTupelM VSIC_UnaryChsLo
let getChshiInstrM = getInstr1M chshiinstrToTupelM VSIC_UnaryChsHi
let getChslohiInstrM = getInstr1M chslohiinstrToTupelM VSIC_UnaryChsLoHi

let getUnpackloInstrM = getInstr1M unpackloinstrToTupelM VSIC_BinUnpackL
let getUnpacklohiInstrM = getInstr1M unpacklohiinstrToTupelM VSIC_BinUnpackLH
let getUnpackhiInstrM = getInstr1M unpackhiinstrToTupelM VSIC_BinUnpackH

let getAccInstrM p1 p2 = getInstr1M (accinstrToTupelM p1 p2) VSIC_BinAcc2
let getAddInstrM = getInstr1M addinstrToTupelM VSIC_BinAdd2
let getSubInstrM = getInstr1M subinstrToTupelM VSIC_BinSub2
let getMulInstrM = getInstr1M mulinstrToTupelM VSIC_BinMul2

let getFMcA2InstrM'  = getInstr1M fmca2instrToTupelM'  VSIC_BinFMcA2
let getFNMcA2InstrM' = getInstr1M fnmca2instrToTupelM' VSIC_BinFNMcA2
let getFMcS2InstrM'  = getInstr1M fmcs2instrToTupelM'  VSIC_BinFMcS2

let getFMcA2InstrM  p q = getInstr1M (fmca2instrToTupelM p q)  VSIC_BinFMcA2
let getFNMcA2InstrM p q = getInstr1M (fnmca2instrToTupelM p q) VSIC_BinFNMcA2
let getFMcS2InstrM  p q = getInstr1M (fmcs2instrToTupelM p q)  VSIC_BinFMcS2

(****************************************************************************)

let addInstrM instr = 
  let id = Id.makeNew ()
  and instr_category = vsimdinstrToCategory instr
  and (rs,ws) = vsimdinstrToReadswritespair instr in
    fetchIStoreM >>= fun (IStore(readers,writers,categories,idmap)) ->
      storeIStoreM (IStore(fold_right (vsimdregmap_addE' id) rs readers,
			   fold_right (vsimdregmap_addE' id) ws writers,
			   vsicmap_addE instr_category id categories,
			   IdMap.add id instr idmap))

(*********************************************************************)

let rec kickInstrWithIdM' id =
  let delId = list_removefirst (Id.equal id) in
  let del' k map = VSimdRegMap.add k (delId (VSimdRegMap.find k map)) map in
  fetchIStoreM >>= fun (IStore(readers,writers,categories,idmap)) ->
    let instr = IdMap.find id idmap in
      let (rs,ws) = vsimdinstrToReadswritespair instr
      and category = vsimdinstrToCategory instr in
        let c_entries = VSICMap.find category categories in
          storeIStoreM (IStore(fold_right del' rs readers,
			       fold_right del' ws writers,
			       VSICMap.add category 
					   (delId c_entries) 
					   categories,
			       IdMap.remove id idmap))
and kickInstrWithIdM id = 
  fetchIStoreM >>= fun (IStore(_,_,_,idmap)) ->
    kickInstrWithIdM' id >>= fun _ ->
      iterM maybeKickWriterOfM (vsimdinstrToReads (IdMap.find id idmap))
and maybeKickWriterOfM reg =
  fetchIStoreM >>= fun (IStore(readers,writers,_,_)) ->
    match VSimdRegMap.find reg readers with
      | _::_ -> unitM ()
      | [] ->
          match VSimdRegMap.find reg writers with
	    | [] -> unitM () 		(* has already been kicked *)
	    | [x] -> 
		 let _ = debugOutputString "eliminating dead code" in
		   kickInstrWithIdM x
 	    | _ -> failwith "maybeKickWriterOfM (2)"

(*********************************************************************)

let doOneStepM rules = 
  memberM rules >>= fun (rule_description, rule_fn) ->
    rule_fn () >>= fun (to_be_kicked, to_be_added) ->
      let info_string = "firing optimization rule: " ^ rule_description in
      let _ = debugOutputString info_string in
	iterM addInstrM to_be_added >>= fun _ ->
	  iterM kickInstrWithIdM to_be_kicked >>= fun _ ->
	    fetchIStoreM

let istoreDoOnestep ruleset istore = 
  match runM doOneStepM ruleset (istore,[]) with
    | Some(istore',_) -> (true,  istore')
    | None	      -> (false, istore)

let vsimdinstrsToIstore instrs = 
  let m = listToIdmap instrs in
    IStore(idmapToXs vsimdregmap_addE vsimdinstrToReads m VSimdRegMap.empty,
	   idmapToXs vsimdregmap_addE vsimdinstrToWrites m VSimdRegMap.empty,
   	   idmapToXs vsicmap_addE vsimdinstrToCategories m VSICMap.empty, m)

let istoreFixpoint (description,rules) = 
  info description;
  fixpoint (istoreDoOnestep rules)

let istoreToVsimdinstrs (IStore(_,_,_,m)) = IdMap.fold (fun _ -> cons) m [] 
let istoreToSize (IStore(_,_,_,m)) = IdMap.fold (fun _ _ -> succ) m 0

(*********************************************************************)

(* not all pairs are combinable *)
let vsimdunaryopCombineM = function
  | (V_Id, op) -> unitM op
  | (op, V_Id) -> unitM op
  | (V_Swap, V_Swap) -> unitM V_Id
  | (V_Chs V_ChsLo), (V_Chs V_ChsLo) -> unitM V_Id
  | (V_Chs V_ChsLo), (V_Chs V_ChsHi) -> unitM (V_Chs V_ChsLoHi)
  | (V_Chs V_ChsLo), (V_Chs V_ChsLoHi) -> unitM (V_Chs V_ChsHi)
  | (V_Chs V_ChsHi), (V_Chs V_ChsLo) -> unitM (V_Chs V_ChsLoHi)
  | (V_Chs V_ChsHi), (V_Chs V_ChsHi) -> unitM V_Id
  | (V_Chs V_ChsHi), (V_Chs V_ChsLoHi) -> unitM (V_Chs V_ChsLo)
  | (V_Chs V_ChsLoHi), (V_Chs V_ChsLo) -> unitM (V_Chs V_ChsHi)
  | (V_Chs V_ChsLoHi), (V_Chs V_ChsHi) -> unitM (V_Chs V_ChsLo)
  | (V_Chs V_ChsLoHi), (V_Chs V_ChsLoHi) -> unitM V_Id
  | (V_Chs V_ChsLo), (V_MulConst(n,m)) -> unitM (V_MulConst(negate n,m))
  | (V_Chs V_ChsHi), (V_MulConst(n,m)) -> unitM (V_MulConst(n,negate m))
  | (V_Chs V_ChsLoHi), (V_MulConst(n,m)) -> unitM (V_MulConst(negate n, negate m))
  | (V_MulConst(n1,m1)), (V_MulConst(n2,m2)) ->
	unitM (V_MulConst(mul n1 n2, mul m1 m2))
  | (V_MulConst(n,m)), (V_Chs V_ChsLo) -> unitM (V_MulConst(negate n,m))
  | (V_MulConst(n,m)), (V_Chs V_ChsHi) -> unitM (V_MulConst(n, negate m))
  | (V_MulConst(n,m)), (V_Chs V_ChsLoHi) -> unitM (V_MulConst(negate n, negate m))
  | _ -> failM

let substVsimdreg' map = function
  | V_SimdLoad2(array,idx,d) -> 
      V_SimdLoad2(array,idx,map d)
  | V_SimdStore2(s,array,idx) -> 
      V_SimdStore2(map s,array,idx)
  | V_SimdUnaryOp(op,s,d) -> 
      V_SimdUnaryOp(op,map s,map d)
  | V_SimdBinaryOp(op,s1,s2,d) -> 
      V_SimdBinaryOp(op,map s1,map s2,map d)
  | V_SimdTernaryOp(op,s1,s2,s3,d) ->
      V_SimdTernaryOp(op,map s1,map s2,map s3,map d)

let substVsimdreg s d = substVsimdreg' (fun x -> if x=s then d else x)

let difM a b = if a=b then failM else unitM ()

(****************************************************************************)

let optimization_rules = 
    [
     "perform substitution",
     (fun _ ->
	getCopyInstrM >>= fun (_,(i1_s,i1_d)) ->
	  getReaderOfM unitM i1_d >>= fun (i2_id,i2_instr) ->
	    unitM ([i2_id], [substVsimdreg i1_d i1_s i2_instr]));

     "create substitution (for unaryop)",
     (fun _ ->
	getUnaryopInstrM_NoCopy >>= fun (i1_id,(i1_op,i1_s,i1_d)) ->
	  getReaderOfM unaryopinstrToTupelM i1_s >>= 
	    fun (i2_id,(i2_op,i2_s,i2_d)) ->
	      posAssertM (eq_vsimdunaryop i1_op i2_op) >>= fun _ ->
	        unitM ([i2_id], [V_SimdUnaryOp(V_Id,i1_d,i2_d)]));

   "
    CPR_R3 @ mulconst(A,[1,1],B) 
	 <=> copy(A,B)
   ",
   (fun _ ->
      getMulconstInstrM is_one is_one >>= fun (i1,(a,_,_,b)) ->
	unitM ([i1], [V_SimdUnaryOp(V_Id,a,b)]));

     "combine unary operations",
     (fun _ ->
	getUnaryopInstrM_NoCopy >>= fun (i2_id,(i2_op,i2_s,i2_d)) ->
	  getWriterOfM unaryopinstrToTupelM i2_s >>= 
	    fun (i1_id,(i1_op,i1_s,i1_d)) ->
	      negAssertM (eq_vsimdunaryop V_Id i1_op) >>= fun _ ->
	        vsimdunaryopCombineM (i1_op,i2_op) >>= fun combined_op ->
		  unitM ([i2_id], [V_SimdUnaryOp(combined_op,i1_s,i2_d)]));

     "eliminate superfluous changesign instrs",
     (fun _ ->
	getChsloInstrM >>= fun (i1_id,(i1_s,i1_d)) ->
	  getReaderOfM chshiinstrToTupelM i1_s >>= fun (i2_id,(i2_s,i2_d)) ->
	  getReaderOfM addinstrToTupelM i1_d >>= fun (_,(i3_s1,i3_s2,i3_d)) ->
	    isUnusedM i1_d >>= fun _ ->
	      getReaderOfM addinstrToTupelM i2_d >>= 
	        fun (i4_id,(i4_s1,i4_s2,i4_d)) ->
		  isUnusedM i2_d >>= fun _ ->
		    let i4_othersrc = if i4_s1=i2_d then i4_s2 else i4_s1 in
		      unitM ([i2_id; i4_id],
			     [V_SimdBinaryOp(V_Sub2,i4_othersrc,i1_d,i4_d)]));

     "gen34 @ chshi+chslo+add-> sub+chshi",
     (fun _ ->
	getAddInstrM >>= fun (i3_id,(i3_s1,i3_s2,i3_d)) ->
	  isUnusedM i3_s1 >>= fun _ ->
	  isUnusedM i3_s2 >>= fun _ ->
	    getWriterOfM chsinstrToTupelM i3_s1 >>= 
	      fun (i1_id,(i1_chspos,i1_s,i1_d)) ->
	        getWriterOfM chsinstrToTupelM i3_s2 >>= 
		  fun (i2_id,(i2_chspos,i2_s,i2_d)) ->
	            (match (i1_chspos,i2_chspos) with
		       | (V_ChsHi, V_ChsLo) -> unitM V_ChsHi
		       | (V_ChsLo, V_ChsHi) -> unitM V_ChsLo
		       | _ -> failM) 
		    >>= fun pos ->
	 	      unitM ([i1_id; i2_id; i3_id],
		             [V_SimdBinaryOp(V_Sub2,i1_s,i2_s,i2_d);
		              V_SimdUnaryOp(V_Chs pos,i2_d,i3_d)]));
   
     "up2/up3 @ chshi(A,B), swap(A,A') \ chslo(A',B') <=> swap(B,B')",
     (fun _ ->
	getSwapInstrM >>= fun (i2_id,(i2_s,i2_d)) ->
	  getReaderOfM chsinstrToTupelM i2_d >>= 
	    fun (i3_id,(i3_chspos,i3_s,i3_d)) ->
	      isUnusedM i3_s >>= fun _ ->
	      getReaderOfM chsinstrToTupelM i2_s >>= 
	 	fun (i1_id,(i1_chspos,i1_s,i1_d)) ->
	          posAssertM (i1_chspos=V_ChsHi && i3_chspos=V_ChsLo ||
			      i1_chspos=V_ChsLo && i3_chspos=V_ChsHi) >>= fun _ ->
		    unitM ([i3_id], [V_SimdUnaryOp(V_Swap,i1_d,i3_d)]));

     "down5: swap+swap+parbinop ==> parbinop+swap",
     (fun _ ->
	getSwapInstrM >>= fun (i2_id,(i2_s,i2_d)) ->
	  getReaderOfM parbinopinstrToTupelM i2_d >>= 
	    fun (i3_id,(i3_op,i3_s1,i3_s2,i3_d)) ->
	      isUnusedM i2_d >>= fun _ ->
	        posAssertM (i3_s2 = i2_d) >>= fun _ ->
		  getWriterOfM swapinstrToTupelM i3_s1 >>= 
		    fun (i1_id,(i1_s,i1_d)) ->
		      unitM ([i2_id; i3_id],
			     [V_SimdBinaryOp(i3_op,i1_s,i2_s,i2_d);
			      V_SimdUnaryOp(V_Swap,i2_d,i3_d)]));

     "up12 @ mulconst,swap => swap,mulconst",
     (fun _ ->
	getSwapInstrM >>= fun (i2_id,(i2_s,i2_d)) ->
	  isUnusedM i2_s >>= fun _ ->
	    getWriterOfM mulconstinstrToTupelM' i2_s >>= 
	      fun (i1_id,(i1_s,i1_c1,i1_c2,i1_d)) ->
	        unitM ([i1_id; i2_id],
		       [V_SimdUnaryOp(V_Swap,i1_s,i1_d);
		        V_SimdUnaryOp(V_MulConst(i1_c2,i1_c1),i2_s,i2_d)]));

     "DOWN6: swap+parbinop+swap ==> swap+parbinop",
     (fun _ ->
	getParbinopInstrM >>= fun (i2_id,(i2_op,i2_s1,i2_s2,i2_d)) ->
	  getWriterOfM swapinstrToTupelM i2_s1 >>= fun (i1_id,(i1_s,i1_d)) ->
	  getReaderOfM swapinstrToTupelM i2_d  >>= fun (i3_id,(i3_s,i3_d)) ->
	    isUnusedM i3_s >>= fun _ ->
	      unitM ([i2_id; i3_id],
		     [V_SimdUnaryOp(V_Swap,i2_s2,i2_d);
		      V_SimdBinaryOp(i2_op,i1_s,i2_d,i3_d)]));

     "DOWN6B @ swap+parbinop+swap ==> swap+parbinop",
     (fun _ ->
	getParbinopInstrM >>= fun (i2_id,(i2_op,i2_s1,i2_s2,i2_d)) ->
	  getWriterOfM swapinstrToTupelM i2_s2 >>= fun (i1_id,(i1_s,i1_d)) ->
	  getReaderOfM swapinstrToTupelM i2_d  >>= fun (i3_id,(i3_s,i3_d)) ->
	    isUnusedM i3_s >>= fun _ ->
	      unitM ([i2_id; i3_id],
		     [V_SimdUnaryOp(V_Swap,i2_s1,i2_d);
		      V_SimdBinaryOp(i2_op,i1_s,i2_d,i3_d)]));
    ]

(***************************************************************************)

let optimization_rules_pass1 = 
   ("optimization_pass1",

    optimization_rules @ 
    [
     "PASS1: swap,chs -> chs,swap",
     (fun _ ->
        getChsInstrM >>= fun (i2_id,(i2_pos,i2_s,i2_d)) ->
          isUnusedM i2_s >>= fun _ ->
            getWriterOfM swapinstrToTupelM i2_s >>= fun (i1_id,(i1_s,i1_d)) ->
              let pos' = vsimdchsposToSwapped i2_pos in
                unitM ([i1_id; i2_id],
                       [V_SimdUnaryOp(V_Chs pos',i1_s,i1_d);
                        V_SimdUnaryOp(V_Swap,i2_s,i2_d)]));
    ]
   )

let optimization_rules_pass2 =
   ("optimization_pass2",

    optimization_rules @
    [
     "PASS2: chs,swap -> swap,chs",
     (fun _ ->
        getSwapInstrM >>= fun (i2_id,(i2_s,i2_d)) ->
          isUnusedM i2_s >>= fun _ ->
            getWriterOfM chsinstrToTupelM i2_s >>=
              fun (i1_id,(i1_pos,i1_s,i1_d)) ->
                let pos' = vsimdchsposToSwapped i1_pos in
                  unitM ([i1_id; i2_id],
                         [V_SimdUnaryOp(V_Swap,i1_s,i1_d);
                          V_SimdUnaryOp(V_Chs pos',i2_s,i2_d)]));
    ]
   )


let ia64_subst_instrs_pass_1 = 
 (
  "substitute instructions pass 1",
  [
   "
    IA64_SP1_R1 @ ppacc2(A,B,C) 
	      <=> unpckL2(A,B,X), unpckH2(A,B,Y), add2(X,Y,C)
   ",
   (fun _ ->
      getAccInstrM ((=)V_Pos) ((=)V_Pos) >>= fun (i1,(_,_,a,b,c)) ->
        let (x,y) = (makeNewVsimdreg (), makeNewVsimdreg ()) in
	  unitM ([i1], [V_SimdBinaryOp(V_UnpackL,a,b,x);
		        V_SimdBinaryOp(V_UnpackH,a,b,y);
			V_SimdBinaryOp(V_Add2,x,y,c)]));

   "
    IA64_SP1_R2 @ nnacc2(A,B,C)
	      <=> unpckL2(A,B,X), unpckH2(A,B,Y), sub2(X,Y,C)
   ",
   (fun _ ->
      getAccInstrM ((=)V_Neg) ((=)V_Neg) >>= fun (i1,(_,_,a,b,c)) ->
	let (x,y) = (makeNewVsimdreg (), makeNewVsimdreg ()) in
	  unitM ([i1], [V_SimdBinaryOp(V_UnpackL,a,b,x);
		        V_SimdBinaryOp(V_UnpackH,a,b,y);
			V_SimdBinaryOp(V_Sub2,x,y,c)]));

   "
    IA64_SP1_R3 @ pnacc2(A,B,C)
	      <=> unpckL2(A,B,X), unpckH2(A,B,Y), fmca2(Y,[1,-1],X,C)
   ",
   (fun _ ->
      getAccInstrM ((=)V_Pos) ((=)V_Neg) >>= fun (i1,(_,_,a,b,c)) ->
	let (x,y) = (makeNewVsimdreg (), makeNewVsimdreg ()) in
	  unitM ([i1], [V_SimdBinaryOp(V_UnpackL,a,b,x);
		        V_SimdBinaryOp(V_UnpackH,a,b,y);
			V_SimdBinaryOp(V_FMcA2(one,mone),y,x,c)]));

   "
    IA64_SP1_R4 @ npacc2(A,B,C)
	      <=> unpckL2(A,B,X), unpckH2(A,B,Y), fmca2(Y,[-1,1],X,C)
   ",
   (fun _ ->
      getAccInstrM ((=)V_Neg) ((=)V_Pos) >>= fun (i1,(_,_,a,b,c)) ->
	let (x,y) = (makeNewVsimdreg (), makeNewVsimdreg ()) in
	  unitM ([i1], [V_SimdBinaryOp(V_UnpackL,a,b,x);
			V_SimdBinaryOp(V_UnpackH,a,b,y);
			V_SimdBinaryOp(V_FMcA2(mone,one),y,x,c)]));

   "
    IA64_SP1_R5 @ chsL2(A,B)
              <=> mulconst2(A,[-1,1],B)
   ",
   (fun _ ->
      getChsloInstrM >>= fun (i1,(a,b)) ->
	unitM ([i1], [V_SimdUnaryOp(V_MulConst(mone,one),a,b)]));
	
   "
    IA64_SP1_R6 @ chsH2(A,B)
              <=> mulconst2(A,[1,-1],B)
   ",
   (fun _ ->
      getChshiInstrM >>= fun (i1,(a,b)) ->
	unitM ([i1], [V_SimdUnaryOp(V_MulConst(one,mone),a,b)]));

   "
    IA64_SP1_R7 @ chsLH2(A,B)
	      <=> mulconst2(A,[-1,-1],B)
   ",
   (fun _ ->
      getChslohiInstrM >>= fun (i1,(a,b)) ->
	unitM ([i1], [V_SimdUnaryOp(V_MulConst(mone,mone),a,b)]));
  ]
 )

let ia64_subst_instrs_pass_2 = 
 (
  "substitute instructions pass 2",
  [
   "
    IA64_SP2_R1 @ fmca2(A,[-1,-1],B,C)
	      <=> sub2(B,A,C)
   ",
   (fun _ ->
     getFMcA2InstrM is_mone is_mone >>= fun (i1,(a,_,_,b,c)) ->
       unitM ([i1], [V_SimdBinaryOp(V_Sub2,b,a,c)]));

   "
    IA64_SP2_R2 @ fmca2(A,[1,1],B,C)
	      <=> add2(A,B,C)
   ",
   (fun _ ->
     getFMcA2InstrM is_one is_one >>= fun (i1,(a,_,_,b,c)) ->
       unitM ([i1], [V_SimdBinaryOp(V_Add2,a,b,c)]));

   "
    IA64_SP2_R3 @ fmcs2(A,[1,1],B,C)
              <=> sub2(A,B,C)
   ",
   (fun _ ->
      getFMcS2InstrM is_one is_one >>= fun (i1,(a,_,_,b,c)) ->
        unitM ([i1], [V_SimdBinaryOp(V_Sub2,a,b,c)]));

   "
    IA64_SP2_R4 @ fnmca2(A,[1,1],B,C)
	      <=> sub2(B,A,C)
   ",
   (fun _ ->
      getFNMcA2InstrM is_one is_one >>= fun (i1,(a,_,_,b,c)) ->
        unitM ([i1], [V_SimdBinaryOp(V_Sub2,b,a,c)]));

   "
    IA64_SP2_R5 @ fnmca2(A,[-1,-1],B,C) 
	      <=> add2(A,B,C)
   ",
   (fun _ ->
      getFNMcA2InstrM is_mone is_mone >>= fun (i1,(a,_,_,b,c)) ->
        unitM ([i1], [V_SimdBinaryOp(V_Add2,a,b,c)]));
  ]
 )


let optimization_rules_ia64 = 
 ("optimization_rules_ia64",

  optimization_rules @
  [
   "
    IA64_XIa @ fmca2(A,[-KL,KH],B,C)
	   <=> fnmca2(A,[KL,-KH],B,C)
   ",
   (fun _ ->
      getFMcA2InstrM negative toTrue >>= fun (i1,(a,kL,kH,b,c)) ->
	unitM ([i1], [V_SimdBinaryOp(V_FNMcA2(negate kL, negate kH),a,b,c)]));

   "
    IA64_XIb @ fnmca2(A,[-KL,KH],B,C) 
	   <=> fmca2(A,[KL,-KH],B,C)
   ",
   (fun _ ->
      getFNMcA2InstrM negative toTrue >>= fun (i1,(a,kL,kH,b,c)) ->
	unitM ([i1], [V_SimdBinaryOp(V_FMcA2(negate kL, negate kH),a,b,c)]));

   "
    IA64_CPR_R1 @ mulconst2(A,[K1,K2],A') 
	        / unpckL2(A',B,C) 
	      <=> unpckL2(A,B,C'), mulconst2(C',[K1,1],C)
   ",
   (fun _ ->
      getUnpackloInstrM >>= fun (i2,(a',b,c)) ->
	getWriterOfM mulconstinstrToTupelM' a' >>= fun (_,(a,k1,k2,a')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i2], [V_SimdBinaryOp(V_UnpackL,a,b,c');
			  V_SimdUnaryOp(V_MulConst(k1,one),c',c)]));

   "
    IA64_CPR_R2 @ mulconst2(B,[K1,K2],B') 
	        / unpckL2(A,B',C)
	      <=> unpckL2(A,B,C), mulconst2(C',[1,K1],C)
   ",
   (fun _ ->
      getUnpackloInstrM >>= fun (i2,(a,b',c)) ->
	getWriterOfM mulconstinstrToTupelM' b' >>= fun (_,(b,k1,k2,b')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i2], [V_SimdBinaryOp(V_UnpackL,a,b,c');
		          V_SimdUnaryOp(V_MulConst(one,k1),c',c)]));

   "
    IA64_CPR_R3 @ mulconst2(A,[K1,K2],A') 
	        / unpckLH2(A',B,C)
	      <=> unpckLH2(A,B,C'), mulconst2(C',[K1,1],C)
   ",
   (fun _ ->
      getUnpacklohiInstrM >>= fun (i2,(a',b,c)) ->
	getWriterOfM mulconstinstrToTupelM' a' >>= fun (_,(a,k1,k2,a')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i2], [V_SimdBinaryOp(V_UnpackLH,a,b,c');
		          V_SimdUnaryOp(V_MulConst(k1,one),c',c)]));

   "
    IA64_CPR_R4 @ mulconst2(B,[K1,K2],B') 
	        / unpackLH2(A,B',C)
	      <=> unpackLH2(A,B,C'), mulconst2(C',[1,K2],C)
   ",
   (fun _ ->
      getUnpacklohiInstrM >>= fun (i2,(a,b',c)) ->
	getWriterOfM mulconstinstrToTupelM' b' >>= fun (_,(b,k1,k2,b')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i2], [V_SimdBinaryOp(V_UnpackLH,a,b,c');
		          V_SimdUnaryOp(V_MulConst(one,k2),c',c)]));

   "
    IA64_CPR_R5 @ mulconst2(A,[K1,K2],A') 
	        / unpackH2(A',B,C)
	      <=> unpackH2(A,B,C'), mulconst2(C',[K2,1],C)
   ",
   (fun _ ->
      getUnpackhiInstrM >>= fun (i2,(a',b,c)) ->
	getWriterOfM mulconstinstrToTupelM' a' >>= fun (_,(a,k1,k2,a')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i2], [V_SimdBinaryOp(V_UnpackH,a,b,c');
		          V_SimdUnaryOp(V_MulConst(k2,one),c',c)]));

   "
    IA64_CPR_R6 @ mulconst2(B,[K1,K2],B') 
	        / unpackH2(A,B',C)
	      <=> unpackH2(A,B,C'), mulconst2(C',[1,K2],C)
   ",
   (fun _ ->
      getUnpackhiInstrM >>= fun (i2,(a,b',c)) ->
	getWriterOfM mulconstinstrToTupelM' b' >>= fun (_,(b,k1,k2,b')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i2], [V_SimdBinaryOp(V_UnpackH,a,b,c');
		          V_SimdUnaryOp(V_MulConst(one,k2),c',c)]));

   "
    IA64_CPR_R7 @ swap2(B,B')
	        / unpackL2(A,B',C)
	      <=> unpackLH2(A,B,C)
   ",
   (fun _ ->
      getUnpackloInstrM >>= fun (i2,(a,b',c)) ->
	getWriterOfM swapinstrToTupelM b' >>= fun (_,(b,b')) ->
	  unitM ([i2], [V_SimdBinaryOp(V_UnpackLH,a,b,c)]));


   "
    IA64_CPR_R8 @ swap2(A,A') 
		/ unpackH2(A',B,C)
	      <=> unpackLH2(A,B,C)
   ",
   (fun _ ->
      getUnpackhiInstrM >>= fun (i2,(a',b,c)) ->
	getWriterOfM swapinstrToTupelM a' >>= fun (_,(a,a')) ->
	  unitM ([i2], [V_SimdBinaryOp(V_UnpackLH,a,b,c)]));

   "
    IA64_CPR_R9 @ swap2(A,A'), unpackLH2(B,A,C')
		/ unpackL2(A',B,C)
	      <=> swap2(C',C)
   ",
   (fun _ ->
      getUnpackloInstrM >>= fun (i3,(a',b,c)) ->
	getWriterOfM swapinstrToTupelM a' >>= fun (i1,(a,a')) ->
	  getReaderOfM unpacklohiinstrToTupelM a >>= fun (i2,(x,y,c')) ->
	    posAssertM (x=b && y=a) >>= fun _ ->
	      unitM ([i3], [V_SimdUnaryOp(V_Swap,c',c)]));

   "
    IA64_CPR_R10 @ swap2(B,B'), unpackLH2(B,A,C')
		 / unpackH2(A,B',C)
	       <=> swap2(C,C')
   ",
   (fun _ ->
      getUnpackhiInstrM >>= fun (i3,(a,b',c)) ->
	getWriterOfM swapinstrToTupelM b' >>= fun (_,(b,b')) ->
	  getReaderOfM unpacklohiinstrToTupelM a >>= fun (_,(x,y,c')) ->
	    posAssertM (x=b && y=a) >>= fun _ ->
	      unitM ([i3], [V_SimdUnaryOp(V_Swap,c',c)]));

   "
    IA64_CPR_R11 @ swap2(A,A') 
		 / unpackLH2(A',B,C)
	       <=> unpackH2(A,B,C)
   ",
   (fun _ ->
      getUnpacklohiInstrM >>= fun (i2,(a',b,c)) ->
	getWriterOfM swapinstrToTupelM a' >>= fun (_,(a,a')) ->
	  unitM ([i2], [V_SimdBinaryOp(V_UnpackH,a,b,c)]));

   "
    IA64_CPR_R12 @ swap2(B,B') 
		 / unpackLH2(A,B',C)
	       <=> unpackL2(A,B,C)
   ",
   (fun _ ->
      getUnpacklohiInstrM >>= fun (i2,(a,b',c)) ->
	getWriterOfM swapinstrToTupelM b' >>= fun (_,(b,b')) ->
	  unitM ([i2], [V_SimdBinaryOp(V_UnpackL,a,b,c)]));


   "
    IA64_CPR_Xa @ mulconst(B,[IL,IH],B') 
		/ fmca2(A,[KL,KH],B',C)
	      <=> fmca2(A,[KL/IL,KH/IH],B,C'), mulconst(C',[IL,IH],C)
   ",
   (fun _ ->
      getFMcA2InstrM' >>= fun (i2,(a,kL,kH,b',c)) ->
	getWriterOfM mulconstinstrToTupelM' b' >>= fun (_,(b,iL,iH,b')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i2], [V_SimdBinaryOp(V_FMcA2(div kL iL,div kH iH),a,b,c');
			  V_SimdUnaryOp(V_MulConst(iL,iH),c',c)]));

   "
    IA64_CPR_Xb @ mulconst(B,[IL,IH],B') 
		/ fmcs2(A,[KL,KH],B',C)
	      <=> fmcs2(A,[KL/IL,KH/IH],B,C'), mulconst(C',[IL,IH],C)
   ",
   (fun _ ->
      getFMcS2InstrM' >>= fun (i2,(a,kL,kH,b',c)) ->
	getWriterOfM mulconstinstrToTupelM' b' >>= fun (_,(b,iL,iH,b')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i2], [V_SimdBinaryOp(V_FMcS2(div kL iL,div kH iH),a,b,c');
			  V_SimdUnaryOp(V_MulConst(iL,iH),c',c)]));

   "
    IA64_CPR_Xc @ mulconst(B,[IL,IH],B') 
		/ fnmca2(A,[KL,KH],B',C)
	      <=> fnmca2(A,[KL/IL,KH/IH],B,C'), mulconst(C',[IL,IH],C)
   ",
   (fun _ ->
      getFNMcA2InstrM' >>= fun (i2,(a,kL,kH,b',c)) ->
	getWriterOfM mulconstinstrToTupelM' b' >>= fun (_,(b,iL,iH,b')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i2], [V_SimdBinaryOp(V_FNMcA2(div kL iL,div kH iH),a,b,c');
			  V_SimdUnaryOp(V_MulConst(iL,iH),c',c)]));

   "
    IA64_CPR_IIa @ mulconst2(A,[KL,KH],A')
		 / add2(A',B,C)
		 | dif(A',B)
	       <=> fmca2(A,[KL,KH],B,C)
   ",
   (fun _ ->
      getAddInstrM >>= fun (i2,(a',b,c)) ->
	difM a' b >>= fun _ ->
	getWriterOfM mulconstinstrToTupelM' a' >>= fun (_,(a,kL,kH,a')) ->
	  unitM ([i2], [V_SimdBinaryOp(V_FMcA2(kL,kH),a,b,c)]));

   "
    IA64_CPR_IIb @ mulconst2(A,[KL,KH],A')
		 / add2(B,A',C)
		 | dif(A',B)
	       <=> fmca2(A,[KL,KH],B,C)
   ",
   (fun _ ->
      getAddInstrM >>= fun (i2,(b,a',c)) ->
	difM a' b >>= fun _ ->
	getWriterOfM mulconstinstrToTupelM' a' >>= fun (_,(a,kL,kH,a')) ->
	  unitM ([i2], [V_SimdBinaryOp(V_FMcA2(kL,kH),a,b,c)]));

   "
    IA64_CPR_IIIa @ sub2(A,B,C)
	        <=> dif(A,B) 
		  | fmca2(B,[-1,-1],A,C)
   ",
   (fun _ ->
      getSubInstrM >>= fun (i1,(a,b,c)) ->
	difM a b >>= fun _ ->
	  let b' = makeNewVsimdreg () in
	    unitM ([i1], [V_SimdBinaryOp(V_FMcA2(mone,mone),b,a,c)]));

   "
    IA64_CPR_Va @ mulconst2(A,[KL,KH],A') 
		/ fmCa2(A',[IL,IH],B,C)
	      <=> fmCa2(A,[KL*IL,KH*IH],B,C)
   ",
   (fun _ ->
      getFMcA2InstrM' >>= fun (i2,(a',iL,iH,b,c)) ->
	posAssertM (a' <> b) >>= fun _ ->
	getWriterOfM mulconstinstrToTupelM' a' >>= fun (_,(a,kL,kH,a')) ->
	  unitM ([i2], [V_SimdBinaryOp(V_FMcA2(mul kL iL, mul kH iH),a,b,c)]));

   "
    IA64_CPR_Vb @ mulconst2(A,[KL,KH],A')
	        / fmCs2(A',[IL,IH],B,C)
	      <=> fmCs2(A,[KL*IL,KH*IH],B,C)
   ",
   (fun _ ->
      getFMcS2InstrM' >>= fun (i2,(a',iL,iH,b,c)) ->
	posAssertM (a' <> b) >>= fun _ ->
	getWriterOfM mulconstinstrToTupelM' a' >>= fun (_,(a,kL,kH,a')) ->
	  unitM ([i2], [V_SimdBinaryOp(V_FMcS2(mul kL iL, mul kH iH),a,b,c)]));

   "
    IA64_CPR_Vc @ mulconst2(A,[KL,KH],A')
		/ fnmca2(A',[IL,IH],B,C)
	      <=> fnmca2(A,[KL*IL,KH*IH],B,C)
   ",
   (fun _ ->
      getFNMcA2InstrM' >>= fun (i2,(a',iL,iH,b,c)) ->
	posAssertM (a' <> b) >>= fun _ ->
	getWriterOfM mulconstinstrToTupelM' a' >>= fun (_,(a,kL,kH,a')) ->
	  unitM ([i2], [V_SimdBinaryOp(V_FNMcA2(mul kL iL, mul kH iH),a,b,c)]));

   "
    IA64_VIIa @ swap2(A,A'), swap2(B,B')
	      / fmca2(A',[KL,KH],B',C) 
	    <=> dif(A',B')
	      | fmca2(A,[KH,KL],B,C'), swap2(C',C)
   ",
   (fun _ ->
      getFMcA2InstrM' >>= fun (i3,(a',kL,kH,b',c)) ->
        posAssertM (a' <> b') >>= fun _ ->
	getWriterOfM swapinstrToTupelM a' >>= fun (_,(a,a')) ->
	getWriterOfM swapinstrToTupelM b' >>= fun (_,(b,b')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i3], [V_SimdBinaryOp(V_FMcA2(kH,kL),a,b,c');
		    	  V_SimdUnaryOp(V_Swap,c',c)]));

   "
    IA64_VIIb @ swap2(A,A'), swap2(B,B')
	      / fnmca2(A',[KL,KH],B',C) 
	    <=> dif(A',B')
	      | fnmca2(A,[KH,KL],B,C'), swap2(C',C)
   ",
   (fun _ ->
      getFNMcA2InstrM' >>= fun (i3,(a',kL,kH,b',c)) ->
        posAssertM (a' <> b') >>= fun _ ->
	getWriterOfM swapinstrToTupelM a' >>= fun (_,(a,a')) ->
	getWriterOfM swapinstrToTupelM b' >>= fun (_,(b,b')) ->
	  let c' = makeNewVsimdreg () in
	    unitM ([i3], [V_SimdBinaryOp(V_FNMcA2(kH,kL),a,b,c');
		    	  V_SimdUnaryOp(V_Swap,c',c)]));


   "
    IA64_XIIa @ swap2(A,A'), fmca2(A',[+KL,-KH],B,C), fnmca2(A',[+IL,-IH],D,E)
	    <=> dif(A',B), dif(A',D), unused(A')
	      | swapchsH(A,A') fmca2(A',[KL,KH],B,C), fnmca2(A',[IL,IH],D,E)
   ",
   (fun _ ->
      getFMcA2InstrM positive negative >>= fun (i2,(a',kL,kH,b,c)) ->
	difM a' b >>= fun _ ->
	getWriterOfM swapinstrToTupelM a' >>= fun (i1,(a,a')) ->
	  getReaderOfM (fnmca2instrToTupelM positive negative) a' >>=
	    fun (i3,(a'',iL,iH,d,e)) ->
	      posAssertM (a'' = a') >>= fun _ ->
	      difM a' d >>= fun _ ->
	 	isUnusedM a' >>= fun _ ->
		  unitM ([i1;i2;i3],
			 [V_SimdUnaryOp(V_SwapChsH,a,a');
			  V_SimdBinaryOp(V_FMcA2(kL,negate kH),a',b,c);
			  V_SimdBinaryOp(V_FNMcA2(iL,negate iH),a',d,e)]));

   "
    IA64_XIIb @ swap2(A,A'), fmca2(A',[+KL,-KH],B,C)
	    <=> dif(A',B), unused(A')
	      | swapchsH(A,A'), fmca2(A',[KL,KH],B,C)
   ",
   (fun _ ->
      getFMcA2InstrM positive negative >>= fun (i2,(a',kL,kH,b,c)) ->
	isUnusedM a' >>= fun _ ->
	difM a' b >>= fun _ ->
 	  getWriterOfM swapinstrToTupelM a' >>= fun (i1,(a,a')) ->
	    unitM ([i1;i2],
		   [V_SimdUnaryOp(V_SwapChsH,a,a');
		    V_SimdBinaryOp(V_FMcA2(kL,negate kH),a',b,c)]));

   "
    IA64_XIIc @ swap2(A,A'), fnmca2(A',[+KL,-KH],B,C)
	    <=> dif(A',B), unused(A')
	      | swapchsH(A,A'), fnmca2(A',[KL,KH],B,C)
   ",
   (fun _ ->
      getFNMcA2InstrM positive negative >>= fun (i2,(a',kL,kH,b,c)) ->
	isUnusedM a' >>= fun _ ->
	difM a' b >>= fun _ ->
 	  getWriterOfM swapinstrToTupelM a' >>= fun (i1,(a,a')) ->
	    unitM ([i1;i2],
		   [V_SimdUnaryOp(V_SwapChsH,a,a');
		    V_SimdBinaryOp(V_FNMcA2(kL,negate kH),a',b,c)]));
  ]
 )

(***************************************************************************)

open Magic

let apply_optrules instrs =				(* exported *)
  let _ = Util.info "vK7Optimization.apply_optrules" in
  let istore0 = vsimdinstrsToIstore instrs in
  let istore1 = istoreFixpoint optimization_rules_pass1 istore0 in
  let istore2 = istoreFixpoint optimization_rules_pass2 istore1 in
  let istore3 = istoreFixpoint ia64_subst_instrs_pass_1 istore2 in
  let istore4 = istoreFixpoint optimization_rules_ia64 istore3 in
  let istore' = istoreFixpoint ia64_subst_instrs_pass_2 istore4 in
    istoreToVsimdinstrs istore'
