%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% -*- fundamental -*-
% fftwgel_simdvectoration_core.pl
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Description:	The core of the 2-way SIMD-vectorization process in FFTW-GEL.
% Language:	SICStus Prolog 3
% Copyright:	2003, Stefan Kral
% Author: 	Stefan Kral (URL mailto:skral@complang.tuwien.ac.at)
% License:	GNU General Public License (GPL) Version 2 (or higher)
% History:	Fri Feb 21 12:06:45 CET 2003: created
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

:- use_module(fftw_isdefinitions).
:- use_module(fftwgel_isdefinitions).
:- use_module(fftwgel_simdvectorization_isdefinitions).
:- use_module(fftwgel_auxcode).
:- use_module(fftwgel_simdvectorization_basics).


scalarinstrs_bindings_simdinstrs(FPInstrs, Bindings, SIMDInstrs) :-
   scalarinstrs_stores_rest(FPInstrs, FP_Stores, FP_Others),
   phrase(vectitems_bindings_(FP_Stores, [], Bindings, FP_Others), SIMDInstrs).
   
vectitems_bindings_([], Bs, Bs, []) -->
   [].
vectitems_bindings_([X|Xs0], Bs0, Bs, Is0) -->
   vectitem_bindings_(X, Bs0, Bs1, Is0, Is, Xs0, Xs),
   vectitems_bindings_(Xs, Bs1, Bs, Is).

vectitem_bindings_(store(S,P,A,X), Bs0, Bs, Is0, Is, Xs0, Xs) -->
   { member_of_rest(I2, Xs0, Xs1) },
   i1_i2_bindings_(store(S,P,A,X), I2, Bs0, Bs, Is0, Is, Xs1, Xs).
vectitem_bindings_(R1+R2, Bs0, Bs, Is0, Is, Xs0, Xs) -->
   { member_of_rest(I1, Is0, Is1) }, 
   { scalarinstr_dst(I1, R1) },
   { member_of_rest(I2, Is1, Is2) },
   { scalarinstr_dst(I2, R2) },
   i1_i2_bindings_(I1, I2, Bs0, Bs, Is2, Is, Xs0, Xs).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% code for joining two instructions
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

i1_i2_bindings_(load(P,A,X,D1), binop(Op,S1,S2,D2),	% (1) LOAD + BINOP
		Bs0, Bs, Is, Is, Xs0, Xs) -->
   { binop_binop_bindingtypes(Op, Op, BTypes) },
   { member_of(acc, BTypes) },
   { bind_(S1, S2, Bs0, Bs, Xs0, Xs) },
   [simd_load1(P,A,X,D1+0)],
   [simd_binop2(acc, Op, Op, D1+0, S1+S2, D1+D2)].
i1_i2_bindings_(binop(Op,S1,S2,D1), load(P,A,X,D2), 	% (2) BINOP + LOAD
		Bs0, Bs, Is, Is, Xs0, Xs) -->
   { binop_binop_bindingtypes(Op, Op, BTypes) },
   { member_of(acc, BTypes) },
   { bind_(S1, S2, Bs0, Bs, Xs0, Xs) },
   [simd_load1(P,A,X,D2+0)],
   [simd_binop2(acc, Op, Op, S1+S2, D2+0, D1+D2)].
i1_i2_bindings_(load(P1,A1,X1,D1), load(P2,A2,X2,D2), 	% (3) LOAD + LOAD
		Bs, Bs, Is, Is, Xs, Xs) -->
   { validSplitAccessPair_(P1, P2) },
   [simd_load2(P1,A1,X1,P2,A2,X2,D1+D2)].
i1_i2_bindings_(load(P1,A,X,D1), load(P2,A,X,D2), 	% (4) LOAD + LOAD
		Bs, Bs, Is, Is, Xs, Xs) -->
   { validInterleavedAccessPair_(P1, P2) },
   [simd_load2(P1,A,X,P2,A,X,D1+D2)].
i1_i2_bindings_(store(S1,P1,A1,X1), store(S2,P2,A2,X2),	% (5) STORE + STORE
		Bs0, Bs, Is, Is, Xs0, Xs) -->
   { validSplitAccessPair_(P1, P2) },
   { bind_(S1, S2, Bs0, Bs, Xs0, Xs) },
   [simd_store2(S1+S2,P1,A1,X1,P2,A2,X2)].
i1_i2_bindings_(store(S1,P1,A,X), store(S2,P2,A,X), 	% (6) STORE + STORE
		Bs0, Bs, Is, Is, Xs0, Xs) -->
   { validInterleavedAccessPair_(P1, P2) },
   { bind_(S1, S2, Bs0, Bs, Xs0, Xs) },
   [simd_store2(S1+S2,P1,A,X,P2,A,X)].
i1_i2_bindings_(unaryop(Op1,S1,D1), unaryop(Op2,S2,D2),	% (7) UNARYOP + UNARYOP
		Bs0, Bs, Is, Is, Xs0, Xs) -->
   { bind_(S1, S2, Bs0, Bs, Xs0, Xs) },
   [simd_unaryop2(Op1,Op2,S1+S2,D1+D2)].
i1_i2_bindings_(binop(Op1,S1,S2,D1), binop(Op2,T1,T2,D2), % (8) BINOP + BINOP
		Bs0, Bs, Is, Is, Xs0, Xs) -->
   { binop_binop_bindingtypes(Op1, Op2, BTypes) },
   { member_of(BType, BTypes) },
   { bindingtype_(BType, S1, S2, T1, T2, Xl, Xh, Yl, Yh) },
   { bind_(Xl, Xh, Bs0, Bs1, Xs0, Xs1) },
   { bind_(Yl, Yh, Bs1, Bs, Xs1, Xs) },
   [simd_binop2(BType, Op1, Op2, Xl+Xh, Yl+Yh, D1+D2)].
i1_i2_bindings_(unaryop(Op,S1,D1), I2,			% (9) UNARYOP + ANY
		Bs0, Bs, Is0, Is, Xs0, Xs) -->
   { nounaryopinstr_dst(I2, D2) },
   { newbind_(I2, S1, D2, Bs0, Bs, Is0, Is, Xs0, Xs) },
   [simd_unaryop1(lo, Op, S1+D2, D1+D2)].
i1_i2_bindings_(I1, unaryop(Op,S2,D2),			% (10) ANY + UNARYOP
		Bs0, Bs, Is0, Is, Xs0, Xs) -->
   { nounaryopinstr_dst(I1, D1) },
   { newbind_(I1, D1, S2, Bs0, Bs, Is0, Is, Xs0, Xs) },
   [simd_unaryop1(hi, Op, D1+S2, D1+D2)].
