% -*- fundamental -*- 

:- op(500, fx, =).

%%%

member_of_rest(X, [X|Xs], Xs).
member_of_rest(X, [Y|Xs], [Y|Zs]) :-
   member_of_rest(X, Xs, Zs).

list_list_concatenated([], Xs, Xs).
list_list_concatenated([X|Xs], Ys, [X|Zs]) :-
   list_list_concatenated(Xs, Ys, Zs).

list_nonmember([], _X).
list_nonmember([X|Xs], Z) :-
   dif(X,Z),
   list_nonmember(Xs, Z).

%%%

+(P, Is-Ms, Is-[P|Ms]).

-(P, Is0-Ms, Is-Ms) :-
   member_of_rest(P, Is0, Is).

=(P, Is0-Ms, Is-[P|Ms]) :-
   member_of_rest(P, Is0, Is).

%%%

unusedReg(R, State, State) :-
   State = Is-_Ms,
   instrs_donotuse(Is, R).

unusedRegs([]) -->
   [].
unusedRegs([R|Rs]) -->
   unusedReg(R),
   unusedRegs(Rs).

instrs_donotuse([], _R).
instrs_donotuse([I|Is], R) :-
   instr_uses(I, IRegs),
   list_nonmember(IRegs, R),
   instrs_donotuse(Is, R).   

%%%

instr_writes(unaryop(_UOp, _S, D), D).
instr_writes(binop(_BOp, _S1, _S2, D), D).
instr_writes(loadQ(_A, _I, D), D).
instr_writes(loadD(_Access, _Arr, _I, _P, D), D).

instr_uses(unaryop(_UOp, S, D), [S,D]).
instr_uses(binop(_BOp, S1, S2, D), [S1,S2,D]).
instr_uses(loadQ(_A, _I, D), [D]).
instr_uses(loadD(_Access, _Arr, _I, _P, D), [D]).
instr_uses(storeD(_P, S, _Access, _Arr, _I), [S]).
instr_uses(storeQ(S, _A, _I), [S]).

%%%

is_vsimdinstrs([]).
is_vsimdinstrs([I|Is]) :-
   is_vsimdinstr(I),
   is_vsimdinstrs(Is).

is_vsimdinstr(unaryop(UOp, S, D)) :-
   is_vsimdunaryop(UOp),
   is_vsimdregs([S,D]).
is_vsimdinstr(binop(BOp, S1, S2, D)) :-
   is_vsimdbinop(BOp),
   is_vsimdregs([S1,S2,D]).
is_vsimdinstr(loadQ(Array, Index, D)) :-
   is_inputarray(Array),
   integer(Index),
   is_vsimdreg(D).
is_vsimdinstr(loadD(Access, Array, Index, P, D)) :-
   is_vfpaccess(Access),
   is_inputarray(Array),
   integer(Index),
   is_lohi(P),
   is_vsimdreg(D).
is_vsimdinstr(storeQ(S, Array, Index)) :-
   is_vsimdreg(S),
   is_outputarray(Array),
   integer(Index).
is_vsimdinstr(storeD(P, S, Access, Array, Index)) :-
   is_lohi(P),
   is_vsimdreg(S),
   is_vfpaccess(Access),
   is_outputarray(Array),
   integer(Index).

is_vfpaccess(realOfComplex).
is_vfpaccess(imagOfComplex).
is_vfpaccess(real).

is_outputarray(output).

is_inputarray(input).
is_inputarray(twiddle).

is_vsimdregs([]).
is_vsimdregs([R|Rs]) :-
   is_vsimdreg(R),
   is_vsimdregs(Rs).

is_vsimdreg(R) :-
   atom(R).

is_vsimdunaryop(copy).
is_vsimdunaryop(swap).
is_vsimdunaryop(chs(P)) :-
   is_vsimdpos(P).
is_vsimdunaryop(mulconst(K1,K2)) :-
   atom(K1),				% symbolic representation
   atom(K2).

is_vsimdbinop(add).
is_vsimdbinop(sub).
is_vsimdbinop(mul).
is_vsimdbinop(acc(P1,P2)) :-
   is_posneg(P1),
   is_posneg(P2).
is_vsimdbinop(unpack(P)) :-
   is_lohi(P).

is_lohi(lo).
is_lohi(hi).

is_vsimdpos(lo).
is_vsimdpos(hi).
is_vsimdpos(lohi).

%%%

items_peepholeoptimized(Is0, Ps) -->
   (  { peepholerule(RuleName, Is0-Is1, Is1-Is) }
   -> [RuleName], 
      items_peepholeoptimized(Is, Ps)
   ;  { Is0 = Ps }
   ).

%%%

peepholerule(copy_propagation(unaryop)) --> 
   =unaryop(copy,A,B), 
   -unaryop(Op,B,C),
   +unaryop(Op,A,C).
peepholerule(eliminate_dead_code) -->
   -I,
   {instr_writes(I, R)},
   unusedReg(R).

/*
?- phrase(items_peepholeoptimized([unaryop(copy,t1,t2),unaryop(mulconst(k1,k2),t2,t3),storeQ(t3,output,0)], Zs), Rs).

?- phrase(items_peepholeoptimized([unaryop(copy,t1,t2),unaryop(mulconst(k1,k2),t2,t3),binop(add,t2,t3,t4),storeQ(t4,output,0)], Zs), Rs).
*/

