text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

Class(DRAMGlobals, rec(
    getOpts := meth(arg)
        local opts, brules, nrules, br, size, k, rb, lm, n, dram_datawidth, precision, dram_addrwidth,bb,throttle;

	rb := When (Length(arg) >= 2, arg[2], 2);
	#k := When (Length(arg) >= 2, arg[2], 2);
	lm := When (Length(arg) >= 3, arg[3], 8);
	n := When (Length(arg) >= 4, arg[4], 4);
	dram_datawidth := When (Length(arg) >= 5, arg[5], 256);
	precision := When (Length(arg) >= 6, arg[6], 64);
	dram_addrwidth := When (Length(arg) >= 7, arg[7], 27);
	bb := When (Length(arg) >= 8, arg[8], 1);
	throttle := When (Length(arg) >= 9, arg[9], 1);

	PrintLine("rb=",rb,", lm=",lm,", n=",n,", dram_datawidth=",dram_datawidth,", precision=",precision,", dram_addrwidth=",dram_addrwidth,", bb(BlackBoxMems)=",bb," throttle=",throttle);
	#PrintLine("k=",k,", lm=",lm,", n=",n,", dram_datawidth=",dram_datawidth,", precision=",precision,", dram_addrwidth=",dram_addrwidth,", bb(BlackBoxMems)=",bb);

	# Move this warning to breakdown rules
	# if(k*n > lm) then
	# 	PrintLine("Warning: Problem specification requires more than 2 stages!");
	# 	PrintLine("Warning: I can't handle it for now, sorry.");
	# 	lm := k*n;
	# 	PrintLine("Local memory size (lm) is assumed to be ",lm,"!");
	# 	PrintLine("..........");
	# fi;

    brules := When(IsRec(SpiralDefaults.breakdownRules),
        UserRecFields(SpiralDefaults.breakdownRules),
        Filtered(Dir(SpiralDefaults.breakdownRules), i->not i in SystemRecFields));
    nrules := rec();
    for br in brules do
        nrules.(br) := List(SpiralDefaults.breakdownRules.(br), i->CopyFields(i));
    od;
    opts := CopyFields(SpiralDefaults);
    opts.breakdownRules := nrules;

    #opts.breakdownRules.TCompose := [TCompose_tag];
    opts.breakdownRules.DFT := [DFT_Base, DFT_tSPL_CT_tiled, DFT_tSPL_push_tiled];
    #opts.breakdownRules.DFT := [];

	#opts.breakdownRules.MDDFT := [MDDFT_Base, MDDFT_tSPL_RowCol_break, MDDFT_tSPL_RowCol_push];
    opts.breakdownRules.MDDFT := [MDDFT_Base, MDDFT_tSPL_RowCol_break_2D, MDDFT_tSPL_RowCol_break_3D, MDDFT_tSPL_RowCol_push];

	opts.breakdownRules.TTwiddle := [ TTwiddle_dram ];

	#opts.breakdownRules.WHT := [WHT_tSPL_BinSplit, WHT_Base, WHT_BinSplit];

	# full applicable set of rules, should be used for all the algorithms
	opts.breakdownRules.TTensor := [AxI_IxB, IxB_AxI, L_BxI__L_AxI, AxI_L__BxI_L];
	#opts.breakdownRules.TTensor := [AxI_L__BxI_L];
	# restricted to only AxI_L__BxI_L since verification scripts assume that the
	# generated hardware is based this breakdown

	#opts.breakdownRules.TTensorI := Concat([IxA_scratch_push, IxA_base, AxI_base, IxA_L_base, L_IxA_base], [IxA_scratch, AxI_scratch, IxAL_scratch]);

	opts.breakdownRules.TTensorI := [IxA_tile_base, AxI_tile_base, L_IxA_tile_base, IxA_L_tile_base, IxA_tile, AxI_tile, L_IxA_tile, IxA_L_tile];
	opts.breakdownRules.TL := [L_base, I_tileRd, I_tileWr, L_tileRd, L_tileWr, I_cubeRd, I_cubeWr, Ln3n2_cubeRd, Ln3n_cubeWr,
								InLn2n_cubeRd, InLn2n_cubeWr];
	#opts.breakdownRules.TCompose := [AB_tile];

	opts.throttle := throttle;

	opts.tags := [ADram(rb,lm)];
	#opts.tags := [ATile(k,lm)];

#	opts.formulaStrategies.sigmaSpl := [ MergedRuleSet(RulesSumsScratch, RulesFuncSimpScratch, RulesDiag, RulesDiagStandalone, RulesStrengthReduce, RulesRCScratch,RulesII,OLRules) ];
#    opts.formulaStrategies.preRC := [ MergedRuleSet(RulesSumsScratch, RulesFuncSimpScratch, RulesDiag, RulesDiagStandalone, RulesStrengthReduce, RulesRCScratch, RulesII, OLRules), (s,o) -> ScratchModel.updateInfo(s) ];
#	opts.formulaStrategies.rc := [ MergedRuleSet(RulesSums, RulesFuncSimp, RulesDiag, RulesDiagStandalone, RulesStrengthReduce, RulesRCScratch, RulesII, OLRules) ];
    #opts.formulaStrategies.postProcess := [(s, opts) -> compiler.BlockSums(opts.globalUnrolling, s)];
    opts.size := [n,n];
	#opts.swp := swp;
    #opts.globalUnrolling := globalUnrolling;

	opts.dram_datawidth := dram_datawidth;
	opts.precision := precision;
	opts.dram_addrwidth := dram_addrwidth;
	opts.bb := bb;

#    opts.sumsgen := ScratchSumsGen;
#	opts.codegen := ScratchCodegen;
#    opts.unparser := CScratchUnparserProg;

    opts.memModifier := "__memory";
    opts.scratchModifier := "__scratch";
    opts.arrayDataModifier := "__rom";
    opts.romModifier := "__rom";

	opts.includes := [];
    Add(opts.includes, "\"scratch.h\"");

    opts.dmaSignal := (self, opts) >> "DMA_signal";
    opts.dmaWait := (self, opts) >> "DMA_wait";
    opts.cpuSignal := (self, opts) >> "CPU_signal";
    opts.cpuWait := (self, opts) >> "CPU_wait";
    opts.dmaFence := (self, opts) >> "DMA_fence";
    opts.dmaLoad := (self, opts) >> "DMA_load";
    opts.dmaStore := (self, opts) >> "DMA_store";
#    opts.model := ScratchModel;

    return opts;
    end
));


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

########################################################################
# If RulesXYOffset correctly takes out base addresses out of H into RecursStep
# we can use the following hack to pass into the function only the stride
#
# H.codeletParNums := [4];
# H.signature := self >> [IntVar("s")];
# H.mkCodelet := self >> let(ss := self.signature(), H(self.params[1], self.params[2], 0, ss[1]));
#
#########################################################################

CollectRecursSteps := s -> Collect(s, RecursStep);

#F Shape(<obj>) - returns a LISP-style structural list, i.e. add(1,2) -> [add, 1, 2]
#F
Shape := x-> Cond(IsRec(x) and IsBound(x.shape), x.shape(),  x);

ClassSPL.shape := self >> Concatenation([ObjId(self)],
    List(self.rChildren(), Shape));

Exp.shape := self >> Concatenation([ObjId(self)],
    List(self.rChildren(), Shape));

RTWrap.shape := self >> self.rt.node.shape();

#F CodeletShape(<obj>) - returns a LISP-style structural list for a codelet
#F    In this case parameters that are passed into a codelet functions do not
#F    show up, i.e. Scat(H(16,2,0,1))*DFT(16)*... -> [Compose, [Scat, H], DFT, ...]
#F
CodeletShape := x-> Cond(IsRec(x) and IsBound(x.codeletShape), x.codeletShape(),  x);
ClassSPL.codeletShape := self >> Concatenation([ObjId(self)],
    List(self.rChildren(), CodeletShape));
FuncClassOper.codeletShape := ClassSPL.codeletShape;
RTWrap.codeletShape := self >> CodeletShape(self.rt.node);
NonTerminal.codeletShape := self >> Concatenation(
    [ObjId(self)],
    List(self.params, CodeletShape),
    When(self.transposed, ["T"], []));

#F CodeletSignature(<obj>) - codelet function signature
#F
CodeletSignature := x-> Cond(IsRec(x) and IsBound(x.signature), x.signature(),
    IsRec(x), Error(".signature() field missing (objid = ", ObjId(x), ")"), []);
ClassSPL.signature := self >> Concatenation(List(self.rChildren(), CodeletSignature));
FuncClassOper.signature := ClassSPL.signature;
RTWrap.signature := self >> CodeletSignature(self.rt.node);
Value.signature := self >> [];

#F CodeletParams(<obj>) - codelet function call params
#F
CodeletParams := x-> Cond(IsRec(x) and IsBound(x.codeletParams), x.codeletParams(),
    IsRec(x), Error(".codeletParams() field missing (objid = ", ObjId(x), ")"), []);
ClassSPL.codeletParams := self >> Concatenation(List(self.rChildren(), CodeletParams));
FuncClassOper.codeletParams := ClassSPL.codeletParams;
RTWrap.codeletParams := self >> CodeletParams(self.rt.node);
Value.codeletParams := self >> [];

#F MkCodelet(<obj>) - generalize <obj> by changing codelet params to be variables
#F
MkCodelet := x -> Cond(IsRec(x) and IsBound(x.mkCodelet), x.mkCodelet(),
    IsRec(x), Error(".mkCodelet() field missing (objid = ", ObjId(x), ")"), x);
#ClassSPL.codeletParams := self >> Concatenation(List(self.rChildren(), CodeletParams));
ClassSPL.mkCodelet := self >> ApplyFunc(ObjId(self),
    List(self.rChildren(), MkCodelet));
FuncClassOper.mkCodelet := BaseOperation.mkCodelet;
RTWrap.mkCodelet := self >> self;
NonTerminal.mkCodelet := self >> self;
Value.mkCodelet := self >> self;

#F CodeletName(<shape>)
#F
CodeletName := shape -> Cond(
    IsInt(shape),
        When(shape < 0, Concat("_n", String(-shape)), Concat("_",String(shape))),
    IsRat(shape),
        Concat(When(shape < 0, "_n", "_"), StringInt(AbsInt(Numerator(shape))), "d", StringInt(Denominator(shape))),
    IsValue(shape),
        CodeletName(shape.v),

    IsRec(shape), Concat(When(IsBound(shape.codeletNameNo_), "", "_"),
    When(IsBound(shape.codeletName), shape.codeletName, shape.name)),
    IsString(shape),
        shape,

    IsList(shape) and not (Length(shape) > 2 and IsRec(shape[1]) and IsBound(shape[1].codeletNameInfix)),
        When(Length(shape)=2 and not (IsRec(shape[2]) or IsList(shape[2])),
         Concat("", CodeletName(shape[1]), String(shape[2])),
         Concat("", Concatenation(List(shape, CodeletName)))),

    IsList(shape), let(cc := shape{[2..Length(shape)-1]}, op := shape[1].codeletName,
        Concat(
        ConcatList(cc, x->Concat(CodeletName(x), "_", op)), CodeletName(Last(shape)))),

    IsFunc(shape), "GAPFunc",

    Concat("_", String(shape)));

####################################################################################
Compose.codeletNameNo_ := true;
Scat.codeletNameNo_ := true;
fTensor.codeletNameNo_ := true;
Compose.codeletName := "";
fId.codeletName := "I";
fTensor.codeletName := "x";
Diag.codeletName := "D";
RCDiag.codeletName := "RD";
Gath.codeletName:= "G";
Scat.codeletName:= "S";

H.codeletShape     := self >> ObjId(self);
FList.codeletShape := self >> Concatenation([ObjId(self)], self.list);
FData.codeletShape := self >> ObjId(self);
FDataOfs.codeletShape := self >> ObjId(self);
#RCDiag.codeletShape:= self >> ObjId(self);

H.signature     := self >> List(["b", "s"], IntVar);
RM.signature    := self >> List(["N", "phi", "g"], IntVar);
FData.signature := self >> [ var.fresh_t("D", TPtr(self.var.t.t)) ];
FDataOfs.signature := self >> [ var.fresh_t("D", TPtr(self.var.t.t)) ];
FList.signature := self >> [];

FuncClass.codeletParams := self >> self.params{self.codeletParNums};
FuncClass.codeletParNums := [];
FuncClass.mkCodelet := self >> let(sig := self.signature(), ApplyFunc(ObjId(self),
    List([1..Length(self.params)], i -> let(parnums := self.codeletParNums,
    When(i in parnums, sig[Position(parnums,i)], self.params[i])))));
Sym.mkCodelet := FuncClass.mkCodelet;
Sym.codeletParNums := [];

H.codeletParNums    := [3, 4];
RM.codeletParNums   := [1, 3, 4];

FList.codeletParams := self >> [];
FData.codeletParams := self >> [self.var];
FData.mkCodelet := self >> FDataOfs(self.signature()[1], self.domain(), 0);

FDataOfs.codeletParams := self >> When(self.ofs=0, [self.var], [self.var+self.ofs]);
FDataOfs.mkCodelet := self >> FDataOfs(self.signature()[1], self.len, 0);
FList.mkCodelet := self >> self;

#
# Here we set some fields required by libgen for objects defined in transforms.*
# This system will change in the future to require less fields, and be
# more streamlined.
#
# Note: This code fragment depends on transforms. NOTE.
#
DFT.codeletShape := self >> When(self.params[2]=1, [ObjId(self), self.params[1]],
                                  [ObjId(self), self.params[1], self.params[2]]);

BHD.codeletShape := self >> ObjId(self);
BHD.mkCodelet    := self >> self; # NOTE?

Twid.signature  := self >> [ ];
Twid.codeletShape  := self >> [ObjId(self), self.params[1], self.params[2], self.params[3]];
Twid.codeletParams := self >> [];

BH.signature    := self >> List(["R", "b", "s"], IntVar);
BH.codeletShape    := self >> ObjId(self);
BH.codeletParNums  := [2, 4, 5];

RCData.signature  := self >> self.func.signature();
RCData.codeletShape  := self >> [ObjId(self), CodeletShape(self.func)];
RCData.codeletParams := self >> self.func.codeletParams();
RCData.mkCodelet := self >> ObjId(self)(self.func.mkCodelet());

FConj.signature  := self >> self.func.signature();
FConj.codeletShape  := self >> [ObjId(self), CodeletShape(self.func)];
FConj.codeletParams := self >> self.func.codeletParams();
FConj.mkCodelet := self >> ObjId(self)(self.func.mkCodelet());

Typ.signature := self >> [];
Typ.codeletShape := self >> [ObjId(self)];
Typ.codeletParams := self >> [];
Typ.mkCodelet := self >> self;

ext: gi


text:
# Solving equations over Free Groups

InstallGlobalFunction(FreeGroupEquationSolve,
function(w,u)
    local vars, consts;

    vars := GeneratorsOfGroup(FreeGroupOfWord(w));
    consts := GeneratorsOfGroup(FreeGroupOfWord(u));

end);

#	ex and ey are the x- and y-exponent sums of the word w respectively.
#	q is the quotient of the exponent sums, e.g. if exponent sums are 3 and 7 then q=2, as 2x3+1=7
#	aut:=[x', y'] is a list consisting of the Neilsen generating pair corresponding to the Moldovanskii rewriting.
#	That is, if w' is the rewritten form of w then there exists an automorphism
#	\phi of F(x, y) such that \phi(w)=w'. In aut, x' and y' are such that
#	\phi(x)=x', \phi(y)=y'. For example, for mold:=Moldovanskii(u); where u is
#	some word over x and y, then mold[1]; and MappedWord(u, [x, y], mold[2]); are
#	the same word.
# NOTE: It may be that MappedWord is better than Eliminated word
#	for our purposes? As might not use syllable notation! (Section 36.3-1 of GAP
#	documentation.)

# TODO: Tests: Some words to rewrite + test that applying the auotmorphism
#              stabilises them.
#       Check whether w is a commutator, and error if it is
#       Error("w is a commutator");
#       Error("");

InstallGlobalFunction(MoldovanskiiRewritingByGenerators,
function(w,x,y)
	  local ex, ey, q, aut;

	  ex := ExponentSumWord(w, x);
	  ey := ExponentSumWord(w, y);
	  aut := [x, y];

	  while ex<>0 and ey<>0 do
		    if AbsInt(ey)>=AbsInt(ex) then
			      q := -QuoInt(ey, ex); # QuoInt is quotient of integers
			      w := MappedWord(w, [x], [x*y^q] );
			      aut[1] := MappedWord(aut[1], [x], [x*y^q] );
			      aut[2] := MappedWord(aut[2], [x], [x*y^q] );
			      ey := ExponentSumWord(w, y);
		    elif AbsInt(ex)>AbsInt(ey) then
			      q := -QuoInt(ex, ey);
			      w := MappedWord(w, [y], [y*x^q] );
			      aut[1] := MappedWord(aut[1], [y], [y*x^q] );
			      aut[2] := MappedWord(aut[2], [y], [y*x^q] );
			      ex := ExponentSumWord(w, x);
		    fi;
	  od;
	  return [w, aut];
end);

# We're looking for solutions to w(x,y) = u(a,b)
# 1. Rewrite w(x,y) as w_0(xy^-1x, y)
#    If expoent sum of x <> 0 or y <> 0 then do
#    Moldovanski rewriting to get one of htem to 0.
#    Also remember the rewriting step
# 2. If  w_0 is in <x^eps y x, y> or <y^eps x y, x >
#    (If w_0 in <y^-1xy, x> then reinterpret x->x_0, y->x_0y_0

# Solves the equation w(x,y) = u(a,b) where w in F(x,y) :wq
# There is no real reason to not use
# list and not just 2 variables
InstallGlobalFunction(IsSolution,
function(w, u, xs, ixs)
    return MappedWord(w, xs, ixs) = u;
end);

InstallGlobalFunction(SubwordLength,
function(word_string, i)
	local subword, exp, next_exp, subcount, letter, j;
	subcount := 0;
	while i <= Length(word_string) do
		next_exp := 0;
		letter := word_string[i];
		if IsAlphaChar(letter) then
			if word_string[i+1] = '^' then
				next_exp := Int([word_string[i+2]]);
				i := i + 3;
				while IsDigitChar(word_string[i]) do
					next_exp := 10*next_exp;
					next_exp := next_exp + Int([word_string[i]]);
					i := i + 1;
				od;
				subcount := subcount + next_exp;
			else
				subcount := subcount + 1;
				i := i + 1;
			fi;
		elif letter = ')' then
			return subcount;
		elif letter = '(' then
			subword := SubwordLength(word_string, i + 1);
			j := 0;
			while word_string[i + j] <> ')' do
				j := j + 1;
			od;
			i := i + j + 1;
			exp := 1;
			if i >= Length(word_string) then
				return -1;
			fi;
			if word_string[i] = '^' then
				exp := Int([word_string[i + 1]]);
				i := i + 2;
				while IsDigitChar(word_string[i]) do
					exp := 10*exp;
					exp := exp + Int([word_string[i]]);
					i := i + 1;
				od;
			fi;
			subcount := subcount + (exp * subword);
			if i >= Length(word_string) then
				return -1;
			fi;
		else
			i := i + 1;
		fi;
	od;
end);

# Find solutions to an equation w(x,y) = u(a,b)
# up to length n by brute force
# w(x, y) is a function of variables
# u(a, b) is a function of constants
# Trying to solve for x and y

InstallGlobalFunction(ShortSolutions,
function(w, u, n)
    local variables, constants, f, gens, const, consts, vars, copy, solutions, tree, c1, c2, c3, c4, nodes, word_string, letter, subcount, i, next_exp, start_consts, exps;
	solutions := [];
	tree := rec();
	nodes := [1];

    variables := FreeGroupOfWord(w);
	constants := FreeGroupOfWord(u);

	f := FreeGroup(Concatenation(List(GeneratorsOfGroup(constants), String),
								 List(GeneratorsOfGroup(variables), String)));
	gens := GeneratorsOfGroup(f){[1 .. Length(GeneratorsOfGroup(variables))]};
	vars := GeneratorsOfGroup(f){[Length(GeneratorsOfGroup(variables)) + 1 ..
								  Length(GeneratorsOfGroup(f))]};
	consts := Concatenation(gens, List(gens, Inverse));
	start_consts := Concatenation(consts, [f.1*f.1^-1]);
	tree.children := List(start_consts, x -> rec(value := x, parent := tree));
	tree.value := f.1 * f.1^-1;
	w := MappedWord(w, GeneratorsOfGroup(variables), vars);
	u := MappedWord(u, GeneratorsOfGroup(constants), consts);

	if u = f.1 * f.1^-1 then
		word_string := String(w);
		if IsDigitChar(word_string[Length(word_string)]) then
			if word_string[1] = '(' then
				subcount := SubwordLength(word_string, 2);
				if subcount > 0 then
					w := Subword(w, 1, subcount);
				fi;
			fi;
		fi;
		exps := ExponentSums(w);
		if RemInt(exps[3], exps[4]) <> 0 and RemInt(exps[4], exps[3]) <> 0 then
			return [[f.1 * f.1^-1, f.1 * f.1^-1]];
		fi;
	fi;

	for const in start_consts do
		copy := MappedWord(w, [vars[1]], [const]);
		if copy = u then
			Add(solutions, [const, 0]);
		fi;
		solutions := BuildTree(const, consts, tree, copy, u, f, solutions, 0, n, nodes);
	od;
	# Print(nodes[1]);
	# Print("\n");
	return solutions;
end);

InstallGlobalFunction(BuildTree,
function(x, consts, node, copy, u, f, solutions, n, limit, nodes)
	local child, const, word, grandchild, c, child_rec;
	nodes[1] := nodes[1] + 1;
	if n > limit then
		return solutions;
	fi;
	for child in node.children do
		child.children := [];
		c := MappedWord(copy, [f.4], [child.value]);
		if c = u then
			Add(solutions, [x, child.value]);
		fi;
		if child.value <> (f.1*f.1^-1) then
			for const in consts do
				word := child.value * const;
				if word = child.parent.value then
					continue;
				fi;
				child_rec := rec();
				child_rec.value := word;
				child_rec.parent := child;
				Add(child.children, child_rec);
			od;
		fi;
	od;
	for child in node.children do
		BuildTree(x, consts, child, copy, u, f, solutions, n + 1, limit, nodes);
	od;
	return solutions;
end);

InstallMethod(FreeGroupOfWord, "for a word over the free group",
              [IsWord], w -> FamilyObj(w)!.freeGroup);

GreenTest := function(n)
    local w, u, F, U, x, y, a, b;

    F := FreeGroup("x", "y");
    x := F.1; y := F.2;

    w := x * y * x;
    u := a^2 * b^2 * a^2;

    return ShortSolutions(w, u, n);
end;


text:
%options package=$PACKAGE_NAME$
%options template=$TEMPLATE$F.gi
$KEYWORD_FILTER$
--
-- This is just a sample lexer and not a real lexer for $LANG_NAME$
--

%Globals
    /.

    ./
%End

%Define
    $additional_interfaces /., ILexer./
    $kw_lexer_class /.$KEYWORD_LEXER$./
%End

%Include
    $LEXER_MAP$F.gi
%End

%Export
    --
    -- List all the token types the lexer will directly process
    -- and export to the parser. If a keyword lexer is used as
    -- a filter for this lexer, it may export a set of keywords
    -- that will also be passed along to the parser.
    --
    -- For example:
    --
        SINGLE_LINE_COMMENT
        IDENTIFIER
        NUMBER
        DoubleLiteral
        COMMA
        SEMICOLON
        PLUS
        MINUS
        TIMES
        DIVIDE
        GREATER
        LESS
        EQUAL
        NOTEQUAL
        ASSIGN
        LEFTPAREN
        RIGHTPAREN
        LEFTBRACE
        RIGHTBRACE
%End

%Terminals
    CtlCharNotWS

    LF   CR   HT   FF

    a    b    c    d    e    f    g    h    i    j    k    l    m
    n    o    p    q    r    s    t    u    v    w    x    y    z
    _

    A    B    C    D    E    F    G    H    I    J    K    L    M
    N    O    P    Q    R    S    T    U    V    W    X    Y    Z

    0    1    2    3    4    5    6    7    8    9

    AfterASCII   ::= '\u0080..\ufffe'
    Space        ::= ' '
    LF           ::= NewLine
    CR           ::= Return
    HT           ::= HorizontalTab
    FF           ::= FormFeed
    DoubleQuote  ::= '"'
    SingleQuote  ::= "'"
    Percent      ::= '%'
    VerticalBar  ::= '|'
    Exclamation  ::= '!'
    AtSign       ::= '@'
    BackQuote    ::= '`'
    Tilde        ::= '~'
    Sharp        ::= '#'
    DollarSign   ::= '$'
    Ampersand    ::= '&'
    Caret        ::= '^'
    Colon        ::= ':'
    SemiColon    ::= ';'
    BackSlash    ::= '\'
    LeftBrace    ::= '{'
    RightBrace   ::= '}'
    LeftBracket  ::= '['
    RightBracket ::= ']'
    QuestionMark ::= '?'
    Comma        ::= ','
    Dot          ::= '.'
    LessThan     ::= '<'
    GreaterThan  ::= '>'
    Plus         ::= '+'
    Minus        ::= '-'
    Slash        ::= '/'
    Star         ::= '*'
    LeftParen    ::= '('
    RightParen   ::= ')'
    Equal        ::= '='
%End

%Start
    Token
%End

%Rules
    Token ::= identifier    /.    checkForKeyWord();./
            | number        /.    makeToken($_NUMBER);./
            | DoubleLiteral /.    makeToken($_DoubleLiteral);./
            | white         /.    skipToken();./
            | slc           /.    makeComment($_SINGLE_LINE_COMMENT);./
            | ';'           /.    makeToken($_SEMICOLON);./
            | ','           /.    makeToken($_COMMA);./
            | '+'           /.    makeToken($_PLUS);./
            | '-'           /.    makeToken($_MINUS);./
            | '='           /.    makeToken($_ASSIGN);./
            | '('           /.    makeToken($_LEFTPAREN);./
            | ')'           /.    makeToken($_RIGHTPAREN);./
            | '{'           /.    makeToken($_LEFTBRACE);./
            | '}'           /.    makeToken($_RIGHTBRACE);./
            | '*'           /.    makeToken($_TIMES);./
            | '/'           /.    makeToken($_DIVIDE);./
            | '>'           /.    makeToken($_GREATER);./
            | '<'           /.    makeToken($_LESS);./
            | '=' '='       /.    makeToken($_EQUAL);./
            | '!' '='       /.    makeToken($_NOTEQUAL);./

    identifier -> letter
                | identifier letter
                | identifier digit

    number ::= digit
             | number digit

    DoubleLiteral ::= Decimal
                    | Decimal Exponent
                    | number Exponent

    Exponent ::= LetterEe number
               | LetterEe '-' number
               | LetterEe '+' number

    LetterEe ::= 'e'
               | 'E'

    Decimal ::= '.' number
              | number '.'
              | number '.' number

    white ::= whiteChar
            | white whiteChar

    slc ::= '/' '/'
          | slc notEOL

    digit ::= 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9

    aA ::= a | A
    bB ::= b | B
    cC ::= c | C
    dD ::= d | D
    eE ::= e | E
    fF ::= f | F
    gG ::= g | G
    hH ::= h | H
    iI ::= i | I
    jJ ::= j | J
    kK ::= k | K
    lL ::= l | L
    mM ::= m | M
    nN ::= n | N
    oO ::= o | O
    pP ::= p | P
    qQ ::= q | Q
    rR ::= r | R
    sS ::= s | S
    tT ::= t | T
    uU ::= u | U
    vV ::= v | V
    wW ::= w | W
    xX ::= x | X
    yY ::= y | Y
    zZ ::= z | Z

    letter ::= aA | bB | cC | dD | eE | fF | gG | hH | iI | jJ | kK | lL | mM | nN | oO | pP | qQ | rR | sS | tT | uU | vV | wW | xX | yY | zZ

    -- any ::= letter | digit | special | white

    whiteChar ::= Space | LF | CR | HT | FF

    special ::= '+' | '-' | '(' | ')' | '"' | '!' | '@' | '`' | '~' | '.' |
                '%' | '&' | '^' | ':' | ';' | "'" | '\' | '|' | '{' | '}' |
                '[' | ']' | '?' | ',' | '<' | '>' | '=' | '#' | '*' | '_' |
                '/' | '$'

    notEOL ::= letter | digit | special | Space | HT | FF
%End

max_stars_repo_name: kuafuwang/LPG-VScode

max_issues_repo_name: kuafuwang/LPG-VScode

max_forks_repo_name: kuafuwang/LPG-VScode


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

# NOTE: The first section is Intel SSE/2/3 specific, and has to be ported
# over to SPU

unpacklo := (l1,l2,n,k) -> Flat(List([1..n/(2*k)], i-> [
        List([1..k], j->l1[(i-1)*k+j]),
        List([1..k], j->l2[(i-1)*k+j])
]));

unpackhi := (l1,l2,n,k) -> Flat(List([1..n/(2*k)], i -> [
        List([1..k], j->l1[n/2+(i-1)*k+j]),
        List([1..k], j->l2[n/2+(i-1)*k+j])
]));

sparams := (l,n) -> List([1..l], i->[1..n]);

shuffle := (in1, in2, p, n, k) -> Flat([
    List([1..n/(2*k)],     i->List([1..k], j->in1[(p[i]-1)*k+j])),
    List([n/(2*k)+1..n/k], i->List([1..k], j->in2[(p[i]-1)*k+j]))
]);

iperm4 := self >> Filtered(Cartesian(self.params()), i->i[1]<>i[2] and i[3] <> i[4]);


text:
local reps,tori,labels,I,II,ords,blocks;

#......Ross
reps:=[[[1,1],[2,1],[3,1]],    # C_3
       [[3,1],[1,1],[7,1]]     # C_3(a_1)
       ];

I:=[[1,2,3],
    [1,2,3]
    ];

#
# The parabolic where the representative is distinguished
#
II:=[[],
     [2]
     ];

labels:=["C_3",
         "C_3(a_1)"
         ];

tori:=[
       [],
       []
    ];

blocks:=[];

ords:=[];

return [reps,tori,labels,I,II,ords,blocks];


text:
# Copyright 2018-2019, Carnegie Mellon University
# See LICENSE for details
#F
#F SPL Objects for directly-implementable gates
#F

#F -----------------------------------------------------------------------------
#F H - 2x2 Hadamard SPL object
#F -----------------------------------------------------------------------------
Class(qH, Sym, rec(
    def := () ->  Sqrt(1/2) * Mat([[1,1], [1,-1]]),
    isReal := False,
    isPermutation := False,
    transpose := self >> self,
    conjTranspose := self >> self,
    inverse := self >> self,
    toAMat := self >> self.def(),
));

#F -----------------------------------------------------------------------------
#F X - 2x2 180 degree rotation along the X axis of the bloch sphere
#F Specific case of Rotx with theta = pi
#F -----------------------------------------------------------------------------
Class(qX, Sym, rec(
    def := () -> Mat( [[0, 1], [1, 0]] ),
    isReal := False,
    isPermutation := False,
    transpose := self >> self,
    conjTranspose := self >> self,
    inverse := self >> self,
    toAMat := self >> self.def(),
));

#F -----------------------------------------------------------------------------
#F Y - 2x2 180 degree rotation along the Y axis of the bloch sphere
#F Specific case of Roty with theta = pi
#F -----------------------------------------------------------------------------
Class(qY, Sym, rec(
    def := () -> Mat( [[0, E(2)], [-E(2), 0]] ), #Mat( [[0, Cplx(0, -1)], [Cplx(0, 1), 0]] ),
    isReal := False,
    isPermutation := False,
    transpose := self >> Mat( [[0, -E(2)], [E(2), 0]] ), #Mat( [[0, Cplx(0, 1)], [Cplx(0, -1), 0]] ),
    conjTranspose := self >> Mat( [[0, -E(2)], [E(2), 0]] ), #Mat( [[0, Cplx(0, 1)], [Cplx(0, -1), 0]] ),
    inverse := self >> self,
    toAMat := self >> self.def(),
));

#F -----------------------------------------------------------------------------
#F Z - 2x2 180 degree rotation along the Z axis of the bloch sphere
#F Specific case of Rotz with theta = pi
#F -----------------------------------------------------------------------------
Class(qZ, Sym, rec(
    def := () -> Mat( [[1, 0], [0, -1]] ),
    isReal := False,
    isPermutation := False,
    transpose := self >> self,
    conjTranspose := self >> self,
    inverse := self >> self,
    toAMat := self >> self.def(),
));

#F -----------------------------------------------------------------------------
#F S - 2x2 90 degree rotation along the Z axis of the bloch sphere
#F Specific case of Rotz with theta = pi/2, or commonly notated as sqrt(Z)
#F -----------------------------------------------------------------------------
Class(qS, Sym, rec(
    def := () -> Mat( [[1, 0], [0, -E(2)]] ), #Mat( [[1, 0], [0, Cplx(0, 1)]] ),
    isReal := False,
    isPermutation := False,
    transpose := self >> self,
    conjTranspose := self >> Mat( [[1, 0], [0, E(2)]] ),
    inverse := self >> Mat( [[1, 0], [0, E(2)]] ),
    toAMat := self >> self.def(),
));

#F -----------------------------------------------------------------------------
#F Sdag - 2x2 -90 degree rotation along the Z axis of the bloch sphere
#F Specific case of Rotz with theta = -pi/2, or commonly notated as -sqrt(Z)
#F -----------------------------------------------------------------------------
Class(qSdag, Sym, rec(
    def := () -> Mat( [[1, 0], [0, E(2)]] ), #Mat( [[1, 0], [0, Cplx(0, -1)]] ),
    isReal := False,
    isPermutation := False,
    transpose := self >> self,
    conjTranspose := self >> qS(),
    inverse := self >> qS(),
    toAMat := self >> self.def(),
));

#F -----------------------------------------------------------------------------
#F T - 2x2 45 degree rotation along the Z axis of the bloch sphere
#F Specific case of Rotz with theta = pi/4, or commonly notated as sqrt(S)
#F -----------------------------------------------------------------------------
Class(qT, Sym, rec(
    def := () -> Mat( [[1, 0], [0, E(8)]] ),
    isReal := False,
    isPermutation := False,
    transpose := self >> self,
    conjTranspose := self >> Mat( [[1, 0], [0, E(8)^3]] ),
    inverse := self >> Mat( [[1, 0], [0, E(8)^3]] ),
    toAMat := self >> self.def(),
));

#F -----------------------------------------------------------------------------
#F Tdag - 2x2 -90 degree rotation along the Z axis of the bloch sphere
#F Specific case of Rotz with theta = -pi/4, or commonly notated as sqrt(S)
#F -----------------------------------------------------------------------------
Class(qTdag, Sym, rec(
    def := () -> Mat( [[1, 0], [0, E(8)^3]] ),
    isReal := False,
    isPermutation := False,
    transpose := self >> self,
    conjTranspose := self >> qT(),
    inverse := self >> qT(),
    toAMat := self >> self.def(),
));

##
#F GenSwapMat( <i>, <j>, <n> )
##
## Helper functioj to create a matrix swapping qubits i and j
GenSwapMat := function (i, j, n)
    local mi, mj, swap, pre;
    mi := Minimum([i, j]);
    mj := Maximum([i, j]);
    if (i = j) then
        return I(2^(n));
    fi;
    pre := Tensor(   Tensor(I(2^(mj-1)), L(4,2)),    I(2^(n-mj-1)) );
    swap := pre * GenSwapMat(mi, mj-1, n) * pre;
    return swap;
end;

##
#F PerfSwap( <target>, <l>, <n> )
##
## generates a 2^n by 2^n matrix that swaps the qubits in target with those in l
## *Not* conscious of the architecture, just generates the equivalent matrix for terminate()
PerfSwap := function (target, l, n)
    local swap, qub, e, a, ls, tmp_l, r, idx;
    swap := I(2^n);
    qub := 1;
    tmp_l := l;
    # Generate the forward swap matrix,
    for e in tmp_l do
        swap := swap * GenSwapMat(target[qub], e, n);
        ls := SplitAt(tmp_l, 1)[2];
        idx := 1;
        for r in ls do
            # if we affected another qubit in our list
            if r = qub then
                tmp_l[idx] := e;
            fi;
            idx := idx + 1;
        od;
        qub := qub + 1;
    od;
    return swap;
end;

##
#F JuncTerm( <l>, <n>, <dir> )
##
## Terminate a Junction object into a permutation matrix
JuncTerm := function (l, n, dir)
    local  size, swap1, swap2, trans, tmp_l;
    size := Length(l);
    tmp_l := [1..Length(l)];
    tmp_l := Map(tmp_l, i -> l[i]);
    # Generate swap matrix
    swap1 := PerfSwap([0..size-1], tmp_l, n);
    # Generate the reverse swap matrix
    swap2 := PerfSwap(Reversed([0..size-1]), Reversed(tmp_l), n);
    if (dir >= 0) then
        return swap1;
    fi;
    return swap2;
end;

#F -----------------------------------------------------------------------------
#F Junc - reordering of the logical qubit vector (l is the ordering, d is the direction)
#F -----------------------------------------------------------------------------
Class(Junc, Sym, rec(
    def := (l, d) -> JuncTerm(l, Length(l), d),
    isReal := False,
    isPermutation := False,
    inverse := self >> self.def(self.params[1], -self.params[2]),
    toAMat := self >> self.def(self.params[1], self.params[2]),
));

#F -----------------------------------------------------------------------------
#F Reord - reordering of the physical qubit positions (l = ordering, arch = architecture, d = direction)
#F -----------------------------------------------------------------------------
Class(Reord, Sym, rec(
    def := (l, arch, d) -> JuncTerm(l, Length(l), d),
    isReal := False,
    isPermutation := False,
    inverse := self >> self.def(self.params[1], -self.params[2]),
    toAMat := self >> self.def(self.params[1], self.params[2]),
));

max_stars_repo_name: spiral-software/spiral-package-quantum

max_issues_repo_name: spiral-software/spiral-package-quantum

max_forks_repo_name: spiral-software/spiral-package-quantum


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

#Declare (CellCGenSIMD, CellCompileStrategyVector, CellVHackUnparser);

#   IBM AltiVec specific (av is for "AltiVec")

vconstpr_av := (self, v) >> Cond(v.t=TInt, v.idx_cprint(),
                                  v.t = TDouble, Print("(", self.vconst1, "((float)", v.cprint(), "))"),
                                  Print("(", self.vconstv, "{", PrintCS(v.v), "})")); #changed Reversed(v.v) to v.v

prep_perm_string := function(p)
    local base_string, final_string, i_counter;
    base_string := [0,1,2,3];
    final_string := [];
    for i_counter in (p-1) do # changed Reversed(p-1) to (p-1)
        Append(final_string, (base_string+i_counter*4));
    od;
    return final_string;
end;
avshuffle := (p) -> Print("((vector unsigned char){", PrintCS(prep_perm_string(p)), "})");
avprintop := (self) >> Chain(Print(self.altivec, "("), spiral.compiler._cprintcs(self.args), Print(")"));

spushuffle := (p) -> Print("((vector unsigned char){", PrintCS(prep_perm_string(p)), "})");
spuprintop := (self) >> Chain(Print(self.spu, "("), spiral.compiler._cprintcs(self.args), Print(")"));

vpermop := (in1, in2, p, v)-> List(p, i->When(i<=v, in1[i], in2[i-v]));

#aperm := meth(self)
#    local l1, l2, l3, res, el, v;
#    res := [];
#    v := self.v();
#    l1 := Cartesian(self.params());
#    for el in l1 do
#        l2 := Filtered(el, i->i<=v);
#        l3 := Filtered(el, i->i>v);
#        if Length(l2) = Length(l3) and Try([PermList(l2-Minimum(l2)+1)])[1] and Try(PermList(l3-Minimum(l3)+1))[1] then
#            Add(res, el);
#        fi;
#    od;
#    return res;
#end;

aperm := meth(self)
    local l1, l2, l3, res, el, v;
    res := [];
    v := self.v();
    res := Cartesian(self.params());
    return Filtered(res, i->Length(Set(Copy(i)))=v);
end;

Class(vparam_av, Value,
    rec(
        __call__ := arg >> WithBases(
            arg[1],
            rec(
                p := arg[2],
                args := [],
                operations := PrintOps
            )
        ),
        t := TUnknown,
        print := self >> Print(self.p),
        cprint := self >> avshuffle(self.p),
        isVparam := true
    )
); #Class added for AltiVec

Class(vparam_spu, Value,
    rec(
        __call__ := arg >> WithBases(
            arg[1],
            rec(
                p := arg[2],
                args := [],
                operations := PrintOps
            )
        ),
        t := TUnknown,
        print := self >> Print(self.p),
        cprint := self >> spushuffle(self.p),
        #from_rChildren := (self, rch) >> ApplyFunc(ObjId(self), [rch[1], rch[2]]),
        isVparam := true
    )
); #Class added for SPU

Class(vop_av, Exp, rec(
        __call__ := arg >> _computeExpType(WithBases(arg[1], rec(
                    p := When(Length(arg) >= arg[1].numargs+2, arg[arg[1].numargs+2], []),
                    args  := Concat(List(Sublist(arg, [2..arg[1].numargs+1]), toExpArg),
                                When(Length(arg) >= arg[1].numargs+2 and arg[arg[1].numargs+2] <> [],
                                    [vparam_av(arg[arg[1].numargs+2])], [])),
                    operations := PrintOps
                )
            )),
        params := self >> [],
        permparams := self >> Cartesian(self.params()),
        cprint := avprintop,
        vcprint := self>>self.cprint(),
        isBinop := self >> self.numargs = 2,
        isUnop := self >> self.numargs = 1,
        isLoadop := False,
        isStoreop := False,
    )
); #Class added for AltiVec

Class(vop_spu, Exp, rec(
        __call__ := arg >> code._computeExpType(
            WithBases(arg[1], rec(
                    p := When(Length(arg) >= arg[1].numargs+2, arg[arg[1].numargs+2], []),
                    args  := Concat(List(Sublist(arg, [2..arg[1].numargs+1]), toExpArg),
                                When(Length(arg) >= arg[1].numargs+2 and arg[arg[1].numargs+2] <> [],
                                    [vparam_spu(arg[arg[1].numargs+2])], [])),
                    operations := PrintOps
                )
                )),
        params := self >> [],
        permparams := self >> Cartesian(self.params()),
        cprint := spuprintop,
        vcprint := self>>self.cprint(),
        isBinop := self >> self.numargs = 2,
        isUnop := self >> self.numargs = 1,
        isLoadop := False,
        isStoreop := False,
    )
); #Class added for SPU

Class(vbinop_av, vop_av, rec(numargs:=2, vcost := 1)); #Class added for AltiVec
Class(vbinop_spu, vop_spu, rec(numargs:=2, vcost := 1)); #Class added for SPU

Class(vunop_av, vop_av, rec(numargs:=1, vcost := 1)); #Class added for AltiVec
Class(vunop_spu, vop_spu, rec(numargs:=1, vcost := 1)); #Class added for SPU

Class(vunbinop_av, vop_av,
    rec(
        numargs := 1,
        params := self >> self.binop.params(),
        v := self >> self.binop.v(),
        ctype := self >> self.binop.ctype(),
        cprint := self >> self.binop(self.args[1], self.args[1], self.p).cprint(),
        semantic := (self, in1, p) >> self.binop.semantic(in1, in1, p),
        vcost := 1
    )
); #Class added for AltiVec

Class(vunbinop_spu, vop_spu,
    rec(
        numargs := 1,
        params := self >> self.binop.params(),
        v := self >> self.binop.v(),
        ctype := self >> self.binop.ctype(),
        cprint := self >> self.binop(self.args[1], self.args[1], self.p).cprint(),
        semantic := (self, in1, p) >> self.binop.semantic(in1, in1, p),
        vcost := 1
    )
); #Class added for SPU


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

Import(paradigms.distributed);

# local functions and variables are prefixed with an underscore.

_WriteStub := function(code, opts)
    local outstr, s, stub, i, testvec, multiline;

    # build the generic stub info
    stub := CopyFields(rec(
        MEM_SIZE := When(IsBound(code.dimensions), EvalScalar(code.dimensions[1]) * 4, 0),
        DATATYPE := Concat("\"", DeriveScalarType(opts), "\""),
        DATATYPE_NO_QUOTES := DeriveScalarType(opts),
        PAGESIZE := 4096,
        INITFUNC := "init_sub",
        FUNC := "sub",
        DESTROYFUNC := "destroy_sub",
        DATATYPE_SIZEINBYTES := Cond(DeriveScalarType(opts) = "float", 4, Cond(DeriveScalarType(opts) = "double", 8, 0)),
        NUMTHREADS := When(IsBound(opts.smp) and IsInt(opts.smp.numproc), opts.smp.numproc, 1),
        RADIX :=      When(IsBound(opts.smp) and IsInt(opts.smp.numproc) and IsBound(code.dimensions), (code.dimensions[1]/(2 * opts.smp.numproc)), 2),
        QUICKVERIFIER := When(IsBound(opts.quickverifier), opts.quickverifier, "nulltransform")
    ));

    if IsBound(code.dimensions) then
        stub.ALLOCATE_MEMORY := "1";
        stub.ROWS := EvalScalar(code.dimensions[1]);
        stub.COLUMNS := EvalScalar(code.dimensions[2]);
    else
        stub.ALLOCATE_MEMORY := "0";
    fi;

    outstr := opts.unparser.generated_by;
    for s in UserRecFields(stub) do
        if s <> "operations" then
            if IsList(stub.(s)) and not IsString(stub.(s)) then
                outstr := Concat(outstr, "#define ", s, " { ");
                for i in [1..Length(stub.(s))-1] do
                   outstr := Concat(outstr, String(stub.(s)[i]), ", ");
                od;
                outstr := Concat(outstr, String(Last(stub.(s))), " }\n");
            else
                outstr := Concat(outstr, "#define ", s, " ", String(stub.(s)), "\n");
            fi;
        fi;
    od;

    Print(outstr);

    ##  add extern function declarations ... required for cuda
    Print("\nextern void INITFUNC();\n");
    Print("extern void DESTROYFUNC();\n");
    Print("extern void FUNC( ", DeriveScalarType(opts), " *out, ", DeriveScalarType(opts), " *in );\n");

	#add testvector if specified in opts

	if IsBound(opts.testvector) then
		testvec := opts.testvector;
		multiline := false;
		if not IsVector(testvec) then
			Error("opts.testvector must be a valid vector");
		fi;
		Print("\n\nstatic ", DeriveScalarType(opts), " testvector[] = {");
		if Length(testvec) > 10 then
			Print("\n    ");
		fi;
		for i in [1 .. Length(testvec)] do
			if i > 1 then
				Print(", ");
				if Mod(i, 10) = 1 then
					Print("\n    ");
					multiline := true;
				fi;
			fi;
			Print(testvec[i]);
		od;
		if multiline then
			Print("\n");
		fi;
		Print("};\n");
	fi;

end;

_MakeOutDirString := function(opts)
	local tmp;

	tmp := GetEnv("SPIRAL_TEMP_OUT_PATH");
	if (tmp = "") then
        tmp := "/tmp";
    fi;
    return Concat(
		Cond(IsBound(opts.outdir), opts.outdir, tmp),
		"/",
		String(GetPid()));
end;

#
## _MakeOutDir
#
# create the output directory.
#

_MakeOutDir := function(opts)
    local outdir;

    outdir := _MakeOutDirString(opts);

    if '~' in outdir or '$' in outdir then
        Error("No shell vars are allowed at the moment.");
    fi;

    MakeDir(outdir);

    return outdir;
end;

_CallProfiler := function(request, code, opts)
    local outdir, fullcmd, errorvalue, retval, target, outputFile, operations;

	if (request = "") then
		request := "time";
	fi;

    outdir := _MakeOutDir(opts);

    # output the spiral 'code' representation to the output dir.
    PrintTo(Concat(outdir, "/code.g"), code);

    # output the full options and profile info
    # PrintRec would be great if it didn't freeze the second time you call it for some reason
    if IsBound( opts.operations )  then
        operations := opts.operations;
    fi;
    Unbind(opts.operations);
    PrintTo(Concat(outdir, "/opts.g"), Print(opts));
    if IsBound( operations )  then
        opts.operations := operations;
    fi;

    # generate C code to testcode file
    PrintTo(Concat(outdir, "/testcode.c"), opts.unparser.gen("sub", code, opts));

    # write testcode.h
    PrintTo(Concat(outdir, "/testcode.h"), _WriteStub(code, opts));

    target := When(IsBound(opts.target), opts.target, rec());
    outputFile := Concat(outdir, "/", request, ".txt");
    fullcmd := Concat("spiralprofiler -d ", outdir);
    fullcmd := Concat(fullcmd, " -r ", request);

    if IsBound(target.forward) then
        fullcmd := Concat(fullcmd, " -f ", String(target.forward));
    fi;

    if IsBound(target.name) then
        fullcmd := Concat(fullcmd, " -t ", String(target.name));
    fi;

    if IsBound(target.prefix) then
        fullcmd := Concat(fullcmd, " -P ", String(target.prefix));
	else
		fullcmd := Concat(fullcmd, " -P ", String(GetPid()), "_");
    fi;

    # Exec the profiler
	# uncomment following line to hide profiler debug and error messages
	#fullcmd := Concat(fullcmd, " 2> NUL");

	PrintLine(fullcmd);

	errorvalue := IntExec(fullcmd);

    if (errorvalue <> 0) then
        Print("Profiler failed with error value ", errorvalue, ":\n", fullcmd, "\n");
        return 1e100;
    fi;

	retval := ReadVal(outputFile);

    return retval;
end;

## CMeasure(code, opts)
##
## Call profiler to time transform implemented by code

CMeasure := (code, opts) -> _CallProfiler("time", code, opts);

## CMatrix(code, opts)
##
## Call profiler to generate matrix equivalent of transform implemented by code

CMatrix := function(code, opts)
	local retmat;
	retmat := _CallProfiler("matrix", code, opts);
	return Cond(IsMat(retmat), TransposedMat(retmat), retmat);
end;

## CVector(code, vector, opts)
##
## Call profiler to apply transform implemented by code to vector

CVector := function (code, vector, opts)
	local retvec;
	opts.testvector := vector;
	retvec :=  _CallProfiler("vector", code, opts);
	return retvec;
end;

#F Find maximum memory requirement of all arrays
#F Used to determine memory arena size (for temp array reuse)
findMaxMemReq := function(c)
   local i, maxOfChildren, thisChild, myMem, arrays, other;

   if not IsRec(c) or not IsBound(c.rChildren) then
      return 0;
   fi;

   # Catch init functions and return 0
   if ObjId(c) = func and c.id = "init" then
      return 0;
   fi;

   # Determine the mem requirements of each of our children recursively, and
   # take the max of this.
   maxOfChildren := 0;
   for i in c.rChildren() do
      thisChild := findMaxMemReq(i);
      if (thisChild > maxOfChildren) then
         maxOfChildren := thisChild;
      fi;
   od;

   # Determine our own memory requirements (recursion leaf also)
   myMem := 0;
   if ObjId(c) = decl then
      [arrays, other] := SplitBy(c.vars, x->IsArray(x.t));
      for i in arrays do
        #HACK to exclude twiddles
        if i.id[1] <> 'D' then
           myMem := myMem + (i.t.size * When(IsBound(i.t.t) and ObjId(i.t.t)=TVect, i.t.t.size, 1));
        fi;
      od;
   fi;

   #Print(ObjId(c), " myMem = ", myMem, ". maxOfChildren = ", maxOfChildren, "\n");
   return(myMem + maxOfChildren);
end;

#F This function is exclusively for the Cell
BuildStubOpts := function (code, opts)
    local arena_size, dist_loops, mbuf_its, memloop_its, parallel_its;
    if IsBound(opts.useMemoryArena) and opts.useMemoryArena then
       arena_size := findMaxMemReq(code);
       if ObjId(arena_size) = Value then arena_size := arena_size.v; fi;
       opts.profile.stubopts.ARENA_SIZE := arena_size;
    else
       opts.profile.stubopts.ARENA_SIZE := 1;
    fi;

    # # For the Cell: add parallelization param to profile.
    # if IsBound(opts.spus) then
    #    opts.profile.stubopts.SPUS := opts.spus;
    # fi;
    # NOTE (clean this up)
    # Override spus with info extracted from code - for DP to work properly.
    dist_loops := Collect(code, dist_loop);
    if Length(dist_loops) >=1 then
       opts.profile.stubopts.SPUS := dist_loops[1].P;
    else
       opts.profile.stubopts.SPUS := 1;
    fi;

    mbuf_its := Collect(code, multibuffer_loop);
    if Length(mbuf_its) >=1 then
       # Write the loop with the smallest mbuf_its range to stub.h since the backend uses this value to divide and declare arrays
       opts.profile.stubopts.MULTIBUFFER_ITERATIONS :=  Minimum(List([1..Length(mbuf_its)], i->Length(mbuf_its[i].range)));
       # Write info on whether last mbuf stage is a ping or a pong (will result of computation end up in X or Y)?
       opts.profile.stubopts.MBUF_ENDS_IN_Y :=  Length(mbuf_its) mod 2;

       # We're probably doing internal streaming, so let the backend know of that.
       opts.profile.stubopts.INTERNAL_MULTIBUFFERING  := 1;
    else
       opts.profile.stubopts.MULTIBUFFER_ITERATIONS := 1;
       opts.profile.stubopts.MBUF_ENDS_IN_Y := 1;
    fi;

    memloop_its := Collect(code, mem_loop);
    if Length(memloop_its) >=1 then
       opts.profile.stubopts.VECTOR_IN_MEM := Length(memloop_its[1].range);
       opts.profile.stubopts.MBUF_ENDS_IN_Y :=  Length(memloop_its) mod 2;
    else
       if IsBound(opts.profile.stubopts.VECTOR_IN_MEM) then
        Unbind(opts.profile.stubopts.VECTOR_IN_MEM);
       fi;
    fi;

    parallel_its := Collect(code, @(1, func, e->ObjId(e.cmd)=dist_loop)); # Only checking for topmost level of parallelism
    if Length(parallel_its) >=1 then
       opts.profile.stubopts.PARALLEL_ITERATIONS := parallel_its[1].cmd.P;
    else
       opts.profile.stubopts.PARALLEL_ITERATIONS := 1;
    fi;
end;

_StandardMeasure := (code, opts) -> _CallProfiler("time", code, opts);

_StandardBuild := (code, opts) -> _CallProfiler("build", code, opts);

_StandardMeasureVerify := function(code, opts, makeTarget)
	#PrintLine("_StandardMeasureVerify(), makeTarget: \"", makeTarget, "\"");
	if (makeTarget = "") then
		makeTarget := "time";
	fi;
	return _CallProfiler(makeTarget, code, opts);
end;


text:
#
#
#

Read("~/Workspace/Chevalley.gap/init.gi");

Read(Filename(home_dir,"lib/rsys.gd"));
Read(Filename(home_dir,"lib/rsys.gi"));

Read(Filename(home_dir,"lib/chvadj.gd"));
Read(Filename(home_dir,"lib/chvadj.gi"));

Read(Filename(home_dir,"lib/nilchv.gd"));
Read(Filename(home_dir,"lib/nilchv.gi"));

Read(Filename(home_dir,"lib/algU.gd"));
Read(Filename(home_dir,"lib/algU.gi"));

#
# UipotentChv needs SolveRelations
#
Read(Filename(home_dir,"lib/poly.gd"));
Read(Filename(home_dir,"lib/poly.gi"));

#
# UipotentChv needs Descend for Unipotent
# ... and Unipotent has to be declared before
#
# UniAlg needs Witt and UniMod
#
Read(Filename(home_dir,"lib/unichv.gd"));
Read(Filename(home_dir,"lib/witt.gd"));
Read(Filename(home_dir,"lib/unimod.gd"));
Read(Filename(home_dir,"lib/unialg.gd"));

Read(Filename(home_dir,"lib/unichv.gi"));
Read(Filename(home_dir,"lib/witt.gi"));
Read(Filename(home_dir,"lib/unimod.gi"));
Read(Filename(home_dir,"lib/unialg.gi"));


text:
# Built-in
Binomial(5, 3);
# 10

ext: gap

max_issues_repo_name: seanwallawalla-forks/RosettaCodeData

max_forks_repo_name: seanwallawalla-forks/RosettaCodeData


text:
#############################################################################
##
##                         equivalent mappings
##  named-pipes.gi
##                                                          Sergio Siccha
##
##  Copyright 2017 by the authors.
##  This file is free software, see license file.
##
##  Provides a means to communicate with another process
##  via a named pipe.
##
#############################################################################

## Recognize whether we're running HPCGAP
if IsBound( HPCGAP ) then
    ## Transfer IO record to the public region.
    MakeImmutable( IO );
fi;

## Opens a pipe for both read and write access
## TODO change this later to include parameter for RDONLY or WRONLY
PipeOpen := function( pipeFilename )
    local pipe;
    ## Use `mkfifo pipe-test` to create named pipe
    pipe := IO_open( pipeFilename, IO.O_RDWR, 0 );
    if pipe = fail then
        Error( "Could not open ", pipeFilename );
    fi;
    ## 2^16 corresponds to the default buffer size
    pipe := IO_WrapFD( pipe, 2^16, 2^16 );
    return pipe;
end;

##################################################
# Operation NamedPipeHandle
# Input:
#   pipeFilename - string
#   options - an options record
# Filters:
#   IsString, IsRecord
#
# Output:
#   newPipeHandle
##################################################
InstallMethod( NamedPipeHandle,
"for a pipe-filename string",
[ IsString ],
function( pipeFilename )
    return NamedPipeHandle( pipeFilename, rec() );
end );

##################################################
# Operation NamedPipeHandle
# Input:
#   pipeFilename - string
#   options - an options record
# Filters:
#   IsString, IsRecord
#
# Output:
#   newPipeHandle
##################################################
InstallMethod( NamedPipeHandle,
"for a pipe-filename string and an options record",
[ IsString, IsRecord ],
function( pipeFilename, options )
    local pipe, newPipeHandle, type;
    pipe := PipeOpen( pipeFilename );
    newPipeHandle := rec( pipe := pipe );
    type := NamedPipeHandleType;
    Objectify( type, newPipeHandle );
    return newPipeHandle;
end );

##################################################
# Operation ReadLine
# Input:
#   namedPipeHandle
# Filters:
#   IsNamedPipeHandle
#
# Output:
#   string
##################################################
InstallMethod( ReadLine,
"for a named-pipe-handle",
[ IsNamedPipeHandle ],
function( namedPipeHandle )
    local string;
    string := IO_ReadLine( namedPipeHandle!.pipe );
    ## Ignore lines that start with a '#'
    if string[1] = '#' then
        Info( InfoWarning, 1, "Ignoring input starting with '#'." );
        return ReadLine( namedPipeHandle );
    fi;
    ## Ctrl-D character was passed into pipe
    if string[1] = '\004' and Length( string ) = 2 then
        ## TODO propagate '\004' signal?
        IO_close( namedPipeHandle!.pipe );
        return fail;
    fi;
    return string;
end );
#IO_ReadLine( pipe );
#IO_Flush

max_stars_repo_name: ssiccha/equivalent-mappings

max_issues_repo_name: ssiccha/equivalent-mappings

max_forks_repo_name: ssiccha/equivalent-mappings


text:
# MPI Baseline options

ImportAll(fftx);
ImportAll(simt);

Declare(MPIOpts);
Declare(MPIGPUDeviceOpts);

Class(MPIDefaultConf, LocalConfig, rec(
    getOpts := meth(self, t)
                   local _opts;
                   _opts := CopyFields(MPIOpts, rec(tags := self.tags));
                   _opts.breakdownRules.TTensorI := [IxA_base];
                   _opts.breakdownRules.TRC := [CopyFields(TRC_tag, rec(applicable := True))];
                   _opts.breakdownRules.TPrm := [TPrm_MPI];
                   return _opts;
               end,

    operations := rec(Print := s -> Print("<MPI Default Configuration>")),
    tags := []
));

Class(MPIGPUDeviceConf, fftx.platforms.cuda.FFTXCUDADeviceOpts, rec(
    getOpts := meth(self, t)
                   local opts;

                   opts := batchFftCUDADeviceOpts();
                   opts.operations := rec(Print := s -> Print("<MPI Distributed FFT/CUDA Device options>"));

                   opts.tags := self.tags::opts.tags;
                   opts.breakdownRules.TTensorI := [IxA_MPI, IxA_base]::opts.breakdownRules.TTensorI;
                   opts.breakdownRules.TTensorII := [batch_cuFFT_cuberot_3D];
                   opts.breakdownRules.TRC := [CopyFields(TRC_tag, rec(applicable := True))];
                   opts.breakdownRules.TPrm := [TPrm_MPI];

                   opts.breakdownRules.MDDFT := When(Length(self.copts) > 0 and IsRec(self.copts[1]) and IsBound(self.copts[1].useCUFFT) and self.copts[1].useCUFFT,
                       [ MDDFT_tSPL_pencil_cuFFT_MPI ], [ MDDFT_tSPL_pencil ]);

                   opts.includes := [ "\"include/fftx_mpi_int.h\"" ];
                   opts.preProcess := (self, t) >> RulesMPIPromoteNT(t);

                   opts.preProcess := t -> ApplyStrategy(t,
                    [ RulesMPIPromoteNT,
                      RulesFFTXPromoteNT,
                      RulesFFTXPromoteNT_Cleanup ],
                       BUA, opts);

                   opts.fftxGen := MPIGPUDeviceOpts.fftxGen;
                   opts._sumsRuleTree := opts.sumsRuleTree;
                   opts.sumsRuleTree := MPIGPUDeviceOpts.sumsRuleTree;

                   opts.codegen.MPIRCPrm := MPICUDACodeGenMixin.MPIRCPrm;
                   opts.unparser.mpi_rcperm := MPICUDAUnparserMixin.mpi_rcperm;
                   opts.sumsgen.MPITensor := MPISumsgenMixin.MPITensor;

                   opts.dynamicDeviceMemory := true;

                   return opts;
               end,

    operations := rec(Print := s -> Print("<MPI GPU Device Configuration>")),
    tags := []
));

Class(MPIGPUDeviceOpts, SpiralDefaults, rec(
    tags := [],
    includes := [ "\"include/fftx_mpi_int.h\"" ],
    tagIt := (self, t) >> t.withTags(self.tags),
    operations := rec(Print := s -> Print("<MPI default options>")),

    preProcess := (self, t) >> RulesMPIPromoteNT(t),

    search := (self, t) >> RandomRuleTree(t, self),

    sumsRuleTree := meth(self, rt)
        local ss;
        ss := self._sumsRuleTree(rt);
        ss := ApplyStrategy(ss, FullLocalizeMPI, BUA, self);
        return ss;
    end,

    fftxGen := meth(self, tt)
        local _tt, rt, ss, c, plist, plist1, tf, tf2;

        _tt := self.preProcess(tt);
        rt := self.search(_tt);
        ss := self.sumsRuleTree(rt);

        self.symbol := When(IsBound(rt.node.params[2].params), rt.node.params[2].params, []);

        c := CodeSums(ss, self);
        c := FixUpMPICUDAPerm(c);
        c := fixReplicatedData(c, self);

        plist := Collect(c, @(1,func, e->e.id="transform"))[1].params;
        plist1 := _orderedUniquify(plist);
        if Length(plist1) = 2 then
            plist1 := plist1 :: self.symbol;
        fi;
        c := SubstTopDown(c, @(1).cond(e->IsList(e) and e = plist), e->plist1);

        if self.symbol <> [] then
            c := SubstTopDown(c, @(1,func, e->e.id="transform"),
                e->SubstVars(e, rec((self.symbol[1].id) := var("_"::self.symbol[1].id, TPtr(TReal)))));

            c := SubstTopDown(c, @(1,specifiers_func),
                e->SubstVars(e, rec((self.symbol[1].id) := var("__"::self.symbol[1].id, TPtr(TReal)))));

            c := SubstTopDown(c, @(1, decl, e-> self.symbol[1] in e.vars),
                e-> decl(Filtered(e.vars, j->j <> self.symbol[1]), e.cmd));
        fi;

        c.ruletree := rt;
        c.ss := ss;
        return c;
    end
));

buildMPIGPUDeviceConf := function(arg)
    local conf;

    conf := CopyFields(MPIGPUDeviceConf,
        rec(
            tags := arg{[1]},
            copts := Drop(arg,1),
            gpuconf := fftx.platforms.cuda.FFTXCUDADeviceDefaultConf
        ));

    return conf;
end;

Class(MPIOpts, SpiralDefaults, rec(
    tags := [],
    includes := [ "\"include/fftx_mpi_int.h\"" ],
    tagIt := (self, t) >> t.withTags(self.tags),
        operations := rec(Print := s -> Print("<MPI default options>")),

    preProcess := (self, t) >> RulesMPIPromoteNT(t),

    search := (self, t) >> RandomRuleTree(t, self),
));

Class(MPIGlobals, rec(
    confMPI := (arg) >> CopyFields(MPIDefaultConf, rec(tags := [arg[2]])),
    defaultConf := arg >> ApplyFunc(arg[1].confMPI, Drop(arg, 1)),
    confMPIGPUDevice := arg >> ApplyFunc(buildMPIGPUDeviceConf, Drop(arg, 1))
));

spiral.LocalConfig.mpi := MPIGlobals;

max_stars_repo_name: spiral-software/spiral-package-mpi

max_issues_repo_name: spiral-software/spiral-package-mpi

max_forks_repo_name: spiral-software/spiral-package-mpi


text:
# Apply a function to a value, given variable names for both function and value
CheckEval := function(fun, val)
	local f, x;
	if IsBoundGlobal(fun) and IsBoundGlobal(val) then
		f := ValueGlobal(fun);
		x := ValueGlobal(val);
		return f(x);
	fi;
end;

bloop := -1;
CheckEval("AbsInt", "bloop");
# 1

# Sum of integer variables
GlobalIntegers := function()
	local s, x;
	s := 0;
	for name in SortedList(NamesGVars()) do
		if IsBoundGlobal(name) then
			x := ValueGlobal(name);
			if IsInt(x) then
				Print(name, " ", x, "\n");
				s := s + x;
			fi;
		fi;
	od;
	return s;
end;

max_stars_repo_name: djgoku/RosettaCodeData

max_issues_repo_name: djgoku/RosettaCodeData

max_forks_repo_name: djgoku/RosettaCodeData


text:
InsertionSort := function(L)
  local n, i, j, x;
  n := Length(L);
  for i in [ 2 .. n ] do
    x := L[i];
    j := i - 1;
    while j >= 1 and L[j] > x do
      L[j + 1] := L[j];
      j := j - 1;
    od;
    L[j + 1] := x;
  od;
end;

s := "BFKRIMPOQACNESWUTXDGLVZHYJ";
InsertionSort(s);
s;
# "ABCDEFGHIJKLMNOPQRSTUVWXYZ"


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

runDramSysGen2D := function(k,n,sw,prec)
	local opts,t,rt,srt,path,cmd;

	opts := DRAMGlobals.getOpts(k*k, k*n, n, prec*2*sw, prec, 27, 0, 0);
	# restrict the TTensor rule to match the verification script assumptions
	opts.breakdownRules.TTensor := [AxI_L__BxI_L];
	t := MDDFT([n,n]).withTags(opts.tags);
	rt := RandomRuleTree(t, opts);
	srt := SPLRuleTree(rt);
	path := DRAMSystemGen(srt,opts);

	PrintLine(path);

	return path;
	#
	# cmd := ConcatenationString("mkdir /afs/ece.cmu.edu/project/trac/vol3/users/bakin/dramSysGen/",
	# 		"2D-n-",String(n),"-k-",String(k),"-sw-",String(sw),"-prec-",String(prec));
	#
	# Exec(cmd);
	#
	# cmd := ConcatenationString("mv ",path,"*"," /afs/ece.cmu.edu/project/trac/vol3/users/bakin/dramSysGen/",
	# 		"2D-n-",String(n),"-k-",String(k),"-sw-",String(sw),"-prec-",String(prec),"/");
	#
	# Exec(cmd);
end;

#runDramSysGen1D := function(k,n,sw,prec)
#	local opts,t,rt,srt,path,cmd;
#
#	opts := DRAMGlobals.getOpts(k*k, k*n, n, prec*2*sw, prec, 27);
#	t := DFT(n*n).withTags(opts.tags);
#	rt := RandomRuleTree(t, opts);
#	srt := SPLRuleTree(rt);
#	path := DRAMSystemGen(srt,opts);
#
#	# cmd := ConcatenationString("mkdir /afs/ece.cmu.edu/project/trac/vol3/users/bakin/dramSysGen/",
#	# 		"1D-n-",String(n),"-k-",String(k),"-sw-",String(sw),"-prec-",String(prec));
#	#
#	# Exec(cmd);
#	#
#	# cmd := ConcatenationString("mv ",path,"*"," /afs/ece.cmu.edu/project/trac/vol3/users/bakin/dramSysGen/",
#	# 		"1D-n-",String(n),"-k-",String(k),"-sw-",String(sw),"-prec-",String(prec),"/");
#	#
#	# Exec(cmd);
#end;
#
#runDramSysGen3D := function(k,n,sw,prec)
#	local opts,t,rt,srt,path,cmd;
#
#	opts := DRAMGlobals.getOpts(k*k*k, k*k*n, n, prec*2*sw, prec, 27);
#	t := MDDFT([n,n,n]).withTags(opts.tags);
#	rt := RandomRuleTree(t, opts);
#	srt := SPLRuleTree(rt);
#	path := DRAMSystemGen(srt,opts);
#
#	# cmd := ConcatenationString("mkdir /afs/ece.cmu.edu/project/trac/vol3/users/bakin/dramSysGen/",
#	# 		"3D-n-",String(n),"-k-",String(k),"-sw-",String(sw),"-prec-",String(prec));
#	#
#	# Exec(cmd);
#	#
#	# cmd := ConcatenationString("mv ",path,"*"," /afs/ece.cmu.edu/project/trac/vol3/users/bakin/dramSysGen/",
#	# 		"3D-n-",String(n),"-k-",String(k),"-sw-",String(sw),"-prec-",String(prec),"/");
#	#
#	# Exec(cmd);
#end;
#
#
#
#runDramSysGenAll := function()
#	local k,n,sw,prec;
#
#	k := 8;		n := 128;	sw := 2;	prec := 32;
#	runDramSysGen2D(k,n,sw,prec);
#	runDramSysGen1D(k,n,sw,prec);
#	k := 8;		n := 128;	sw := 4;	prec := 32;
#	runDramSysGen2D(k,n,sw,prec);
#	runDramSysGen1D(k,n,sw,prec);
#	k := 16;		n := 512;	sw := 2;	prec := 32;
#	runDramSysGen2D(k,n,sw,prec);
#	runDramSysGen1D(k,n,sw,prec);
#	k := 16;		n := 512;	sw := 4;	prec := 32;
#	runDramSysGen2D(k,n,sw,prec);
#	runDramSysGen1D(k,n,sw,prec);
#	k := 16;		n := 512;	sw := 8;	prec := 32;
#	runDramSysGen2D(k,n,sw,prec);
#	runDramSysGen1D(k,n,sw,prec);
#
#end;

runDramSysGenAll := function(k,n,sw,prec)
	local path,cmd;

	path := runDramSysGen2D(k,n,sw,prec);
	cmd := ConcatenationString("cd ",path,"; source verify.sh; grep SNR matlab.log > /afs/ece.cmu.edu/project/trac/vol3/users/bakin/perfect/snr-summary/snr.n",String(n),
								".k",String(k),".s",String(sw),".p",String(prec));
	Exec(cmd);

end;

runDramSysGenTest := function()
#	runDramSysGenAll(4,128,2,32);
#	runDramSysGenAll(8,128,2,32);
#	runDramSysGenAll(4,128,4,32);

#	runDramSysGenAll(4,256,2,32);
#	runDramSysGenAll(8,256,4,32);
#	runDramSysGenAll(16,256,4,32);

#	runDramSysGenAll(16,512,8,32);

	runDramSysGenAll(32,1024,4,32);

	runDramSysGenAll(16,2048,4,32);

end;


text:
method vfHistItem vfHistItem.mLoad <alias=vfHistItem_mLoad>( )
{
//	this->vForm.mCreateWin()
	ustr ustmp
	uint comp
	comp as this
	with comp
	{
		.AutoLang=1
		.Border=$fbrdSizeable
		.Bottom=0
		.Caption=ustmp.fromutf8("")
		.Enabled=1
		.FormStyle=$fsPopup
		.Height=429
		.HelpTopic=ustmp.fromutf8("")
		.Hint=ustmp.fromutf8("")
		.HorzAlign=$alhLeft
		.IconName=ustmp.fromutf8("")
		.Left=0
		.Name="fHistItem"
		.Right=0
		.StartPos=$spScreenCenter
		.Style=""
		.TabOrder=0
		.Tag=0
		.Top=0
		.TopMost=0
		.VertAlign=$alvTop
		.Visible=0
		.Width=608
		.WindowState=$wsNormal
		.OnCreate.Set( this, fHistItem_Create )

		uint comp
		comp as this.Splitter0
		comp.Owner = this
		with comp
		{
			.AutoLang=1
			.AutoSize=1
			.Bottom=0
			.Enabled=1
			.FixedPart=$sfpRight
			.Height=400
			.HelpTopic=ustmp.fromutf8("")
			.Hint=ustmp.fromutf8("")
			.HorzAlign=$alhClient
			.Left=0
			.LeftMinSize=0
			.Name="Splitter0"
			.Orientation=$soHorizontal
			.Right=0
			.RightMinSize=0
			.SplitterWidth=0
			.Style=""
			.TabOrder=0
			.Tag=0
			.Top=0
			.VertAlign=$alvClient
			.Visible=1
			.Width=600

			uint comp
			comp as this.Panel0
			comp.Owner = this.Splitter0
			with comp
			{
				.AutoLang=1
				.Border=$brdNone
				.Bottom=0
				.Caption=ustmp.fromutf8("")
				.Enabled=1
				.Height=350
				.HelpTopic=ustmp.fromutf8("")
				.Hint=ustmp.fromutf8("")
				.HorzAlign=$alhLeft
				.Left=0
				.Name="Panel0"
				.Right=0
				.Style=""
				.TabOrder=0
				.Tag=0
				.Top=0
				.VertAlign=$alvTop
				.Visible=1
				.Width=600

				uint comp
				comp as this.pTop
				comp.Owner = this.Panel0
				with comp
				{
					.AutoLang=1
					.Border=$brdNone
					.Bottom=65
					.Caption=ustmp.fromutf8("")
					.Enabled=1
					.Height=285
					.HelpTopic=ustmp.fromutf8("")
					.Hint=ustmp.fromutf8("")
					.HorzAlign=$alhClient
					.Left=0
					.Name="pTop"
					.Right=0
					.Style=""
					.TabOrder=0
					.Tag=0
					.Top=0
					.VertAlign=$alvTopBottom
					.Visible=1
					.Width=600
				}
				comp as this.e_wincaption
				comp.Owner = this.Panel0
				with comp
				{
					.AddColon=1
					.AutoLang=1
					.Bottom=38
					.Btn1Hint=ustmp.fromutf8("")
					.Btn1Image=ustmp.fromutf8("")
					.Btn2Hint=ustmp.fromutf8("")
					.Btn2Image=ustmp.fromutf8("")
					.Caption=ustmp.fromutf8("wincaption")
					.Enabled=1
					.Height=25
					.HelpTopic=ustmp.fromutf8("")
					.Hint=ustmp.fromutf8("")
					.HorzAlign=$alhLeftRight
					.LabelPos=$lpLeft
					.Left=160
					.LEStyle=$lsSimple
					.MaxLen=32768
					.Multiline=0
					.Name="e_wincaption"
					.Password=0
					.ReadOnly=1
					.Right=10
					.ScrollBars=0
					.Style=""
					.TabOrder=1
					.Tag=33
					.Text=ustmp.fromutf8("")
					.Top=287
					.VertAlign=$alvBottom
					.Visible=1
					.Width=430

					uint comp
				}
				comp as this.e_fileexe
				comp.Owner = this.Panel0
				with comp
				{
					.AddColon=1
					.AutoLang=1
					.Bottom=8
					.Btn1Hint=ustmp.fromutf8("")
					.Btn1Image=ustmp.fromutf8("")
					.Btn2Hint=ustmp.fromutf8("")
					.Btn2Image=ustmp.fromutf8("")
					.Caption=ustmp.fromutf8("fileexe")
					.Enabled=1
					.Height=25
					.HelpTopic=ustmp.fromutf8("")
					.Hint=ustmp.fromutf8("")
					.HorzAlign=$alhLeftRight
					.LabelPos=$lpLeft
					.Left=160
					.LEStyle=$lsSimple
					.MaxLen=32768
					.Multiline=0
					.Name="e_fileexe"
					.Password=0
					.ReadOnly=1
					.Right=10
					.ScrollBars=0
					.Style=""
					.TabOrder=3
					.Tag=33
					.Text=ustmp.fromutf8("")
					.Top=317
					.VertAlign=$alvBottom
					.Visible=1
					.Width=430

					uint comp
				}
			}
			comp as this.DlgBtns0
			comp.Owner = this.Splitter0
			with comp
			{
				.AutoLang=1
				.Border=$brdNone
				.Bottom=0
				.Caption=ustmp.fromutf8("")
				.CurWizard=0
				.CustomCaption=ustmp.fromutf8("")
				.DisableNext=0
				.Enabled=1
				.Height=50
				.HelpTopic=ustmp.fromutf8("")
				.Hint=ustmp.fromutf8("")
				.HorzAlign=$alhLeft
				.Indent=15
				.Left=0
				.MaxWizard=0
				.Name="DlgBtns0"
				.Right=0
				.ShowApply=1
				.ShowCancel=0
				.ShowClose=1
				.ShowCustom=0
				.ShowDone=$dsdNone
				.ShowHelp=1
				.ShowLine=1
				.Style=""
				.TabOrder=1
				.Tag=0
				.Top=350
				.VertAlign=$alvTop
				.Visible=1
				.Width=600
				.Wizard=1

				uint comp
			}
			.Distance=350
		}
		.ClientHeight=400
		.ClientWidth=600
	}

	return this
}

method vfHistItem vfHistItem.init( )
{
   this.pTypeId = vfHistItem
   return this
}
func init_vfHistItem <entry>()
{
   regcomp( vfHistItem, "vfHistItem", vForm, $vForm_last,
      %{ %{$mLoad,     vfHistItem_mLoad}},
      0->collection )

}

max_stars_repo_name: novostrim/macroclip

max_issues_repo_name: novostrim/macroclip

max_forks_repo_name: novostrim/macroclip


text:
# Copyright (c) 2018-2021, Carnegie Mellon University
# See LICENSE for details

##################################################################################
#   vector strength reduction - experimental!!!

zero_one   := @.cond(e -> (IsValue(e) and (e.v=[0,1]  or e.v=[0.0,1.0])));
one_zero    := @.cond(e -> (IsValue(e) and (e.v=[1,0]  or e.v=[1.0,0.0])));

zero_mone   := @.cond(e -> (IsValue(e) and (e.v=[0,-1]  or e.v=[0.0,-1.0])));
mone_zero    := @.cond(e -> (IsValue(e) and (e.v=[-1,0]  or e.v=[-1.0,0.0])));

#   WARNING: these rules may be SSE2-specific. Especially the order of @2, @1 may be because of _mm_shuffle_pd
# NOTE: YSV reenable this

# Checks alignment of an expr.
# Pointers are assumed to be aligned.
# Type of the expression is assumed to be the "natural" one (i.e. float for 4-way)
# e.g.: for SSE_4x32f: X+3 is unaligned and X+4 is aligned
Declare(_isAligned);
_isAligned := function(c, v)
     if ObjId(c)=add then
         return ForAll(c.args, x->_isAligned(x, v));
     elif ObjId(c)=tcast then
         return _isAligned(c.args[2], v);
     elif ObjId(c) = var and ObjId(c.t)=TPtr then
         return not IsUnalignedPtrT(c.t);
     elif ObjId(c) = mul then
         return ForAny(c.args, x->_isAligned(x, v));

     elif ObjId(c) = Value and (IsVecT(c.t) or IsArrayT(c.t)) then # XXX YSV: is this correct?
	 return true;

     elif ObjId(c) = Value then
         return (Mod(c.v,v)=0);
     elif ObjId(c) = var then
         return false;
     else
         return false; #By default, return false
     fi;
     return true;
end;

_isISA := (t, vec_isa, opts) -> IsVecT(t) and t.size=vec_isa.t.size
                             and ((IsBound(opts.isas) and vec_isa in opts.isas) or
                                  (IsBound(opts.vector) and vec_isa = opts.vector.isa));

# pull "change sign" from add and sub
_rule_addSub_chs_chs := (chs) -> Rule( [@(3, [add, sub]), [chs, @(1)], [chs, @(2)]], e -> chs(ObjId(@(3).val)(@(1).val, @(2).val)));

RewriteRules(RulesStrengthReduce, rec(
    #
    # These rules replaces unaligned accesses by aligned accesses whenever possible
    #
    # This rules are disabled because _isAligned may incorrectly return true when pointer expression
    # splitted in compiler
    #
    #replace_unaligned_load := Rule(
    #    [ @(1, [vloadu_2x64f, vloadu_4x32f, vloadu_8x16i, vloadu_16x8i]),
    #      @(2).cond(e -> _isAligned(e, @(1).val.v)) ],
    #    e -> deref(tcast(TPtr(@(1).val.t), @(2).val))
    #),

    #replace_unaligned_store := Rule(
    #    [ @(1, [vstoreu_2x64f, vstoreu_4x32f, vstoreu_8x16i, vstoreu_16x8i]),
    #      @(2),
    #      @(3).cond(e -> _isAligned(@(2).val, e.t.size)) ],
    #    e -> assign(deref(tcast(TPtr(@(3).val.t), @(2).val)),@(3).val)
    #),

#     add_mul1001a := Rule([add, [mul, @(1), one_zero], [mul, @(2), zero_one]],  e ->
#         let(ins := _SIMDArch().rules.x_I_vby2[1][2], ins.instr(@(1).val, @(2).val, ins.p))), #oddly I had to switch order of @1, @2 and not [1][2]->[2][1] ??
#     add_mul1001b := Rule([add, [mul, one_zero, @(1)], [mul, zero_one, @(2)]],  e ->
#         let(ins := _SIMDArch().rules.x_I_vby2[1][2], ins.instr(@(1).val, @(2).val, ins.p))),

#     add_mul0110a := Rule([add, [mul, @(1), zero_one], [mul, @(2), one_zero]],  e ->
#         let(ins := _SIMDArch().rules.x_I_vby2[1][2], ins.instr(@(2).val, @(1).val, ins.p))),
#     add_mul0110b := Rule([add, [mul, zero_one, @(1)], [mul, one_zero, @(2)]],  e ->
#         let(ins := _SIMDArch().rules.x_I_vby2[1][2], ins.instr(@(2).val, @(1).val, ins.p))),

#     sub_mul1001b := Rule([sub, [mul, one_zero, @(1)], [mul, zero_one, @(2)]],  e ->
#         let(ins := _SIMDArch().rules.x_I_vby2[1][2], ins.instr(@(1).val, neg(@(2).val), ins.p))),
#     sub_mul0110b := Rule([sub, [mul, zero_one, @(1)], [mul, one_zero, @(2)]],  e ->
#         let(ins := _SIMDArch().rules.x_I_vby2[1][2], ins.instr(@(1).val, @(2).val, ins.p))),

# replace unaligned->aligned if possible
#    align_load:= Rule([@(1, [vloadu_2x64f, vloadu_4x32f, vloadu_8x16i]), @(2, vref, e->IsValue(e.idx) and IsInt(e.idx.ev()/@1.val.v)) ], e->vref(@2.val.loc, @2.val.idx, @1.val.v)),

    ushuffle_neg := Rule([@(1, [vushuffle_2x64f, vushuffle_4x32f]), [neg, @(2)], @(3)],
        e -> neg(ObjId(@(1).val)(@(2).val, @(3).val))),

    addsub00 := Rule([@(1,addsub_2x64f), _0, _0], e->v0),
    addsubA0 := Rule([@(1,addsub_2x64f), @(2).cond(e->ObjId(e) <> Value), _0], e->@(2).val),

    mul1A := Rule([@(1, addsub_2x64f), [@(2, mul), zero_one, @(3)], [@(4, mul), one_zero, @(5)]], e->
        addsub_2x64f(0, vshuffle_2x64f(@(5).val, @(3).val, [1,2]))),

    mul1B := Rule([@(1, addsub_2x64f), [@(2, mul), one_zero, @(3)], [@(4, mul), zero_one, @(5)]], e->
        vshuffle_2x64f(@(3).val, @(5).val, [2,1])),

    mul2A := Rule([@(1, addsub_2x64f), [@(2, mul), zero_mone, @(3)], [@(4, mul), mone_zero, @(5)]], e->
        let(v01 := Value(TVectDouble(2), [0, 1]), v10 := Value(TVectDouble(2), [1, 0]),
            vushuffle_2x64f(addsub_2x64f(v01 * @(5).val, v10 * @(3).val), [2,1]))),

    mul2B := Rule([@(1, addsub_2x64f), [@(2, mul), mone_zero, @(3)], [@(4, mul), zero_mone, @(5)]], e->
        let(v01 := Value(TVectDouble(2), [0, 1]), v10 := Value(TVectDouble(2), [1, 0]),
            neg(vshuffle_2x64f(@(3).val, @(5).val, [2,1])))),

    shuf1 := Rule([@(1, vshuffle_2x64f), @(2, vushuffle_2x64f), @(3, vushuffle_2x64f), @(4, vparam)], e->
        let(p :=@(4).val.p, p1:=@(2).val.args[2].p, p2:=@(3).val.args[2].p,
            v1 := @(2).val.args[1], v2 := @(2).val.args[1],
            vshuffle_2x64f(v1, v2, [p1[p[1]], p2[p[2]]]))),

    shuf2 := Rule([@(1, vshuffle_2x64f), @(2), @(3).cond(e->e=@(2).val), @(4, vparam)], e->
        vushuffle_2x64f(@(2).val, @(4).val.p)),

    shuf3 := Rule([@(1, vushuffle_2x64f), @(2), @(3, vparam, e->e.p = [1,2])], e-> @(2).val),

    _mm_min_4way_noSSE41_replace := Rule(@@(1,min, (e,cx) -> not(LocalConfig.cpuinfo.SIMD().hasSSE4_1()) and
        IsBound(cx.opts.vector) and
            cx.opts.vector.isa=SSE_4x32i and
            e.t=TVect(TReal, 4)),
	e -> bin_or(bin_andnot(gt(@@(1).val.args[2],@@(1).val.args[1]),@@(1).val.args[2]),
	            bin_and(gt(@@(1).val.args[2],@@(1).val.args[1]),@@(1).val.args[1]))),

    _rshift_16way_replace := Rule(@@(1, bin_shr, (e,cx) -> (
            IsBound(cx.opts.vector) and
            cx.opts.vector.isa=SSE_16x8i and
            e.t=cx.opts.vector.isa.t)),
	e -> bin_and(tcast(e.t, bin_shr(tcast(TVect(TReal, 8), @@(1).val.args[1]), @@(1).val.args[2])),
	             vdup(TInt.value(bin_shr(256,@@(1).val.args[2])-1), 16))),

    #note: this does a gte and not a gt
    _gt_16way_unsigned_replace := Rule(@@(1, gt, (e,cx) -> (
            IsBound(cx.opts.vector) and
            cx.opts.vector.isa=SSE_16x8i and
            not (cx.opts.vector.isa.isSigned) and
            e.t=cx.opts.vector.isa.t)),
        e -> eq(min(@@(1).val.args[2], @@(1).val.args[1]), @@(1).val.args[2])
    ),

    vload1_4x32f_cond := Rule( [vload1_4x32f, @(1, cond)],
        e -> _map_cond(@(1).val, p->p, exp->vload1_4x32f(exp))),
    vload1_4x32f_funcExp := Rule( [vload1_4x32f, [funcExp, @(1, Value)]],
        e -> e.t.value([@(1).val, 0, 0, 0])),  # must be _mm_set_ss

    vload_2h_4x32f_cond := Rule( [vload_2h_4x32f, @(1), @(2, cond)],
        e -> _map_cond(@(2).val, p->p, exp->vload_2h_4x32f(@(1).val, exp))),
    vload_2l_4x32f_cond := Rule( [vload_2l_4x32f, @(1), @(2, cond)],
        e -> _map_cond(@(2).val, p->p, exp->vload_2l_4x32f(@(1).val, exp))),

    vload_2h_4x32f_funcExp := Rule( [vload_2h_4x32f, @(1, Value), [funcExp, @(2, Value)]],
        e -> vshuffle_4x32f(@(1).val, @(2).val, [1,2,3,4])),
    vload_2l_4x32f_funcExp := Rule( [vload_2l_4x32f, @(1, Value), [funcExp, @(2, Value)]],
        e -> vshuffle_4x32f(@(2).val, @(1).val, [1,2,3,4])),

    vshuffle_4x32f_cond_r := Rule( [vshuffle_4x32f, @(1), @(2, cond), @(3)],
        e -> _map_cond(@(2).val, p->p, exp->vshuffle_4x32f(@(1).val, exp, @(3).val))),
    vshuffle_4x32f_cond_l := Rule( [vshuffle_4x32f, @(1, cond), @(2), @(3)],
        e -> _map_cond(@(1).val, p->p, exp->vshuffle_4x32f(exp, @(2).val, @(3).val))),
    vushuffle_4x32f_cond := Rule( [vushuffle_4x32f, @(1, cond), @(2)],
        e -> _map_cond(@(1).val, p->p, exp->vshuffle_4x32f(exp, @(2).val))),

));

Class(RulesPreStrengthReduce, RuleSet);
RewriteRules(RulesPreStrengthReduce, rec(
    _avg_16way_replace := Rule([@@(1, add, (e,cx) -> (
            IsBound(cx.opts.vector) and
            cx.opts.vector.isa=SSE_16x8i and
            e.t=cx.opts.vector.isa.t)),[bin_shr,@(2),@(3,Value,e->e.v=1)],[bin_shr,@(4),@(5,Value,e->e.v=1)]],
        (e, cx)-> cx.opts.vector.isa.average(@(2).val,@(4).val)),
));

# recursive condition function for push_change_sign rule.
# if tree consists from sub and add with [mul, Value, @] leaves only  we can
# merge "change sign" with values.

Declare(_canEliminateChangeSign);
_canEliminateChangeSign := (tree) -> CondPat( tree,
    add, ForAll(tree.args, _canEliminateChangeSign),
    sub, ForAll(tree.args, _canEliminateChangeSign),
    [mul, Value, @], true,
    false);

RewriteRules(RulesStrengthReduce, rec(
    require_load := Rule(@@(1, deref, (e,cx) -> IsBound(cx.opts.vector) and
	    IsBound(cx.opts.vector.isa.requireLoad) and cx.opts.vector.isa.requireLoad and
        ((IsBound(cx.assign) and cx.assign<>[] and cx.assign[1].exp = @@(1).val) or (ForAny([add, sub, mul,
            vunpacklo_4x32f, vunpackhi_4x32f, addsub_4x32f, hadd_4x32f, vshuffle_4x32f, vushuffle_4x32f], i-> IsBound(cx.(i.name)) and cx.(i.name)<>[] ))) ),
#        ((IsBound(cx.assign) and cx.assign<>[] and ObjId(cx.assign[1].exp) = deref and ObjId(cx.assign[1].loc) <> deref) or (ForAny([add, sub, mul, vunpacklo_4x32f], i-> IsBound(cx.(i.name)) and cx.(i.name)<>[] ))) ),
        (e, cx)-> cx.opts.vector.isa.loadop(@@(1).val.loc)),

    require_store := Rule([@@(1, assign, (e,cx) -> (
            IsBound(cx.opts.vector) and IsBound(cx.opts.vector.isa.requireStore) and cx.opts.vector.isa.requireStore)),
            @(2, deref), @(3)],
        (e, cx)-> cx.opts.vector.isa.storeop(@(2).val, @(3).val)),

    require_store_var_SSE_2x32f := Rule([@@(1, assign, (e,cx) -> (IsBound(cx.opts.vector) and cx.opts.vector.isa = SSE_2x32f)),
            @(2, deref), @(3, Value)],
        (e, cx)-> let(vv := var.fresh_t("V", TVect(TReal, cx.opts.vector.isa.v)),
            decl(vv, chain(assign(vv, @(3).val), cx.opts.vector.isa.storeop(@(2).val, vv))))),

    fix_unpackhi_2x32f := Rule(@(1, vunpackhi_2x32f),
        e -> vshuffle_4x32f(vunpacklo_4x32f(@(1).val.args[1], @(1).val.args[2]), vunpacklo_4x32f(@(1).val.args[1], @(1).val.args[2]), vparam([3,4,3,4]))),

    fix_unpacklo_2x32f := Rule(@(1, vunpacklo_2x32f), e -> vunpacklo_4x32f(@(1).val.args[1], @(1).val.args[2])),

    # fix_vzero_2x32f := Rule(@(1, vzero_2x32f), e -> vzero_4x32f()),

    fix_vload_2x32f := Rule(@(1, vload_2x32f), e -> vload_2l_4x32f(@(1).val.args[1], @(1).val.args[2])),
    fix_vstore_2x32f := Rule(@(1, vstore_2x32f), e -> vstore_2l_4x32f(@(1).val.loc, @(1).val.exp)),
    fix_addsub_2x32f := Rule(@(1, addsub_2x32f), e -> addsub_4x32f(@(1).val.args[1], @(1).val.args[2])),

    addsub_zero_r := Rule([@(1, addsub_4x32f), @(2), _0], e -> @(2).val),

    # NOTE: verify this rule
    addsub_zero_l := Rule([@(1, addsub_4x32f), _0, @(2)], e -> chslo_4x32f(@(2).val)),

    chslo_4x32f_neg := Rule([chslo_4x32f, [neg, @(1)]], e -> chshi_4x32f(@(1).val)),
    chshi_4x32f_neg := Rule([chshi_4x32f, [neg, @(1)]], e -> chslo_4x32f(@(1).val)),
    chslo_2x64f_neg := Rule([chslo_2x64f, [neg, @(1)]], e -> chshi_2x64f(@(1).val)),
    chshi_2x64f_neg := Rule([chshi_2x64f, [neg, @(1)]], e -> chslo_2x64f(@(1).val)),

    chslo_4x32f_neg_2 := Rule([neg, [chslo_4x32f, @(1)]], e -> chshi_4x32f(@(1).val)),
    chshi_4x32f_neg_2 := Rule([neg, [chshi_4x32f, @(1)]], e -> chslo_4x32f(@(1).val)),
    chslo_2x64f_neg_2 := Rule([neg, [chslo_2x64f, @(1)]], e -> chshi_2x64f(@(1).val)),
    chshi_2x64f_neg_2 := Rule([neg, [chshi_2x64f, @(1)]], e -> chslo_2x64f(@(1).val)),

    # try to use same "change sign" everywhere
    add_@_chshi_4x32f := Rule([add, @(1), @(2, chshi_4x32f, x -> not (ObjId(@(1).val) in [chslo_4x32f, chshi_4x32f]))],
        e -> sub(@(1).val, chslo_4x32f(@(2).val.args[1]))),

    # put value to front in mul
    # NOTE: ESReduce has something like this one; rules below work only when Value is in front.
    mul_value_to_front := Rule( [mul, ...,  @(1), @(2, Value, x -> not IsValue(@(1).val)), ...],
        e -> let( a := SplitBy(e.args, IsValue), ApplyFunc(mul, [Product(a[1])] :: a[2]))),

    # "change sign" elimination
    mul_val_chs := ARule( mul, [@(1, Value), [@(2, [chshi_2x64f, chslo_2x64f, chshi_4x32f, chslo_4x32f]), @(3)] ],
        e -> let( chs := @(2).val,
                  [@(1).val * ObjId(chs)(chs.t.one()).ev(), @(3).val] )),

    chs_mul_val := Rule( [@(2, [chshi_2x64f, chslo_2x64f, chshi_4x32f, chslo_4x32f]), [mul, @(1, Value), @(3)]],
        e -> let( chs := @(2).val,
                  mul(@(1).val * ObjId(chs)(chs.t.one()).ev(), @(3).val))),

    mul_val_vushuffle_2x64f_chs := ARule( mul, [@(1, Value), [vushuffle_2x64f, [@(2, [chshi_2x64f, chslo_2x64f]), @(3)], @(4)] ],
        e -> let( chs := @(2).val,
                  vp  := @(4).val,
                  val := vushuffle_2x64f( ObjId(chs)(chs.t.one()).ev(), vp).ev(),
                  [@(1).val * val, vushuffle_2x64f( @(3).val, vp)] )),

    mul_val_vushuffle_4x32f_chs := ARule( mul, [@(1, Value), [vushuffle_4x32f, [@(2, [chshi_4x32f, chslo_4x32f]), @(3)], @(4)] ],
        e -> let( chs := @(2).val,
                  vp  := @(4).val,
                  val := vushuffle_4x32f( ObjId(chs)(chs.t.one()).ev(), vp).ev(),
                  [@(1).val * val, vushuffle_4x32f( @(3).val, vp)] )),

    # pull "change sign" from [add, sub]
    addSub_chshi_2x64f_chshi_2x64f := _rule_addSub_chs_chs(chshi_2x64f),
    addSub_chslo_2x64f_chslo_2x64f := _rule_addSub_chs_chs(chslo_2x64f),
    addSub_chshi_4x32f_chshi_4x32f := _rule_addSub_chs_chs(chshi_4x32f),
    addSub_chslo_4x32f_chslo_4x32f := _rule_addSub_chs_chs(chslo_4x32f),

    # push change sign into mul so it can be eliminated later
    push_change_sign := Rule([@(1, [chshi_2x64f, chslo_2x64f, chshi_4x32f, chslo_4x32f]), @(2, [add, sub], _canEliminateChangeSign)],
       e -> SubstTopDownNR( @(2).val, [mul, @(3, Value), @(4)], x -> mul(@(3).val, ObjId(@(1).val)(@(4).val)))),

    # pull same unary shuffle from add, sub and mul
    addSubMul_vushuffle_2x64f_vushuffle_2x64f := Rule( [@(5, [add, sub, mul]), [vushuffle_2x64f, @(1), @(2)], [vushuffle_2x64f, @(3), @(4).cond(x -> x=@(2).val)]],
        e -> vushuffle_2x64f( ObjId(@(5).val)( @(1).val, @(3).val ), @(2).val )),
    addSubMul_vushuffle_4x32f_vushuffle_4x32f := Rule( [@(5, [add, sub, mul]), [vushuffle_4x32f, @(1), @(2)], [vushuffle_4x32f, @(3), @(4).cond(x -> x=@(2).val)]],
        e -> vushuffle_4x32f( ObjId(@(5).val)( @(1).val, @(3).val ), @(2).val )),

    # pull value multiplier from unary shuffle. Disabled for now as it causing stalls on Core i7 2x64f
    # vushuffle_mul_value := Rule( [@(1, [vushuffle_2x64f, vushuffle_4x32f]), [mul, @(2, Value), @(3)], @(4)],
    #    e -> mul( ObjId(@(1).val)(@(2).val, @(4).val), ObjId(@(1).val)(@(3).val, @(4).val)) ),

    # V1*A + V2*vushuffle(A, P), V1*V2=0 => (V1+V2)*vushuffle(A, P`)
    merge_add_mul_mul_vushuffle_4x32f := ARule( add, [ [mul, @(1, Value), @(2)], [mul, @(3, Value), [@(0, vushuffle_4x32f), @(4), @(5).cond(x -> @(4).val = @(2).val and @(3).val*@(1).val = @(0).val.t.zero())]] ],
        e -> let( vp := @(5).val.p,
                  V1 := @(1).val,
                  V2 := @(3).val,
                  new_vp := List([1..Length(vp)], i -> When( V1.v[i] = 0, vp[i], i)),
                  [ mul( add(V1 + V2), vushuffle_4x32f( @(4).val, new_vp ))] )),

    # V1*A + vushuffle(V2*A, P), V1*vushuffle(V2,P)=0 => (V1+vushuffle(V2,P))*vushuffle(A, P`)
    merge_add_mul_vushuffle4x32f_mul := ARule( add, [ [mul, @(1, Value), @(2)], [@(0, vushuffle_4x32f), [mul, @(3, Value), @(4)], @(5).cond(x -> @(4).val = @(2).val and vushuffle_4x32f(@(3).val, x).ev()*@(1).val = @(0).val.t.zero())] ],
        e -> let( vp := @(5).val.p,
                  V1 := @(1).val,
                  V2 := @(3).val,
                  new_vp := List([1..Length(vp)], i -> When( V1.v[i] = 0, vp[i], i)),
                  [ mul( add(V1 + vushuffle_4x32f(V2, vp).ev()), vushuffle_4x32f( @(4).val, new_vp ))] )),

    remove_mul_load_2l_4x32f := Rule( [mul, @(1, Value), [@(2, vload_2l_4x32f, x -> @(1).val * x.t.value([ 1, 1, 0, 0]) = @(1).val), _0, @]],
        e -> @(2).val),

    store_zero := Rule([@(1, vstore_2l_4x32f), @(2), _0], e -> vstore_2l_4x32f(@(2).val, vzero_4x32f())),

    fix_vushuffle_2x32f := Rule([@(1, vushuffle_2x32f), @(2).cond(e->ObjId(e) <> Value), @(3)],
        e -> vshuffle_4x32f(@(1).val.args[1], @(1).val.args[1], vparam(Concat(@(1).val.args[2].p, @(1).val.args[2].p)))),

#   FF: NOTE: Why are all thes unaligned stores showing up?? This is a temporary fix. Yevgen, please tell me!
    fix_vstoreu_2x32f := Rule(@(1, vstoreu_2x32f), e -> vstore_2l_4x32f(@(1).val.loc, @(1).val.exp)),

    remove_shuffle := Rule([@(1, vstore_2l_4x32f), @(2), @(3, vushuffle_4x32f, e->e.args[2].p=[3,4,3,4])],
        e -> vstore_2h_4x32f(@(2).val, @(3).val.args[1])),

#    propagate_vushuffle := Rule(@(1, [add, sub, mul], e->ForAll(e.args, i->ObjId(i)=vushuffle_4x32f)),
#        e -> Error("Chaught")),
#
    assign_zero_xor := Rule([@@(1, assign, (e,cx)->IsBound(cx.opts.vector) and cx.opts.vector.isa = SSE_2x32f), @(2), @(3, Value, e->e.v=0)],
        (e, cx) -> let(zv := var.fresh_t("Z", TVect(TReal, cx.opts.vector.isa.v)), decl(zv, assign(@(2).val, vzero_2x32f())))),

    sreduce_vushuffle_1 := Rule([@(1, vushuffle_2x32f), @(2, Value, e->ObjId(e.t)=TVect), @(3)],
        e -> Value(@(2).val.t, List([1..@(2).val.t.size], i->@(2).val.v[@(3).val.p[i]]))),

    sreduce_vushuffle_2 := Rule([@(1, vushuffle_2x32f), @(2, Value, e->e.t=TInt), @(3)],
        e -> @(2).val),

#    fix_noneExp := Rule(@(1, noneExp), e->e.t.value(0)),

    addsub_noneExp_l := Rule([@(1, [addsub_2x64f, addsub_4x32f]), @(2, noneExp), @(3)], (e,cx)-> ObjId(@(1).val)(cx.opts.vector.isa.vzero(), @(3).val)),
    addsub_noneExp_r := Rule([@(1, [addsub_2x64f, addsub_4x32f]), @(2), @(3, noneExp)], (e,cx)-> @(2).val),

    add_addsub_zero_l := Rule([add, @(3), [@(1, [addsub_2x64f, addsub_4x32f]), _0, @(2)]], e -> ObjId(@(1).val)(@(3).val, @(2).val)),
    add_addsub_zero_r := Rule([add, [@(1, [addsub_2x64f, addsub_4x32f]), _0, @(2)], @(3)], e -> ObjId(@(1).val)(@(3).val, @(2).val)),

    addsub_addsub_zero_l := Rule( [@(1, [addsub_2x64f, addsub_4x32f]), [@(2, [addsub_2x64f, addsub_4x32f]), _0, @(3)], @(4)],
        e -> ObjId(@(1).val)(@(0).val, add(@(3).val, @(4).val))),
    addsub_addsub_zero_r := Rule( [@(1, [addsub_2x64f, addsub_4x32f]), @(4), [@(2, [addsub_2x64f, addsub_4x32f]), _0, @(3)]],
        e -> add(@(3).val, @(4).val)),

    addsub_zero_neg  := Rule([@(1, [addsub_2x64f, addsub_4x32f]), _0, [neg, @(2)]], e -> neg(ObjId(@(1).val)(@(0).val, @(2).val))),
    sub_addsub_zero := Rule([sub, [@(1, [addsub_2x64f, addsub_4x32f]), _0, @(2)], [@(3, [addsub_2x64f, addsub_4x32f]), _0, @(4)]],
        e -> ObjId(@(1).val)(@(0).val, sub(@(2).val, @(4).val))),

    sse_vshuffle_noneExp2 := Rule([@(1, [vshuffle_2x64f, vshuffle_4x32f]), @(2, noneExp), @(3, noneExp), @(4)], e->@(2).val),

    sse_vshuffle_noneExp1L := Rule([@(1, [vshuffle_2x64f, vshuffle_4x32f]), @(2, noneExp), @(3), @(4)],
	(e,cx)-> ObjId(@(1).val)(cx.opts.vector.isa.vzero(), @(3).val, @(4).val)),

    sse_vshuffle_noneExp1R := Rule([@(1, [vshuffle_2x64f, vshuffle_4x32f]), @(2), @(3, noneExp), @(4)],
	(e,cx)-> ObjId(@(1).val)(@(2).val, cx.opts.vector.isa.vzero(), @(4).val)),

    sse_unary_noneExp := Rule(
	[@(1, [
          vushuffle_16x8i, vushuffle_2x32f, vushuffle_2x64f, vushuffle_2x64i,
	  vushuffle_4x32f, vushuffle_4x32i,
	  chslo_2x32f, chslo_2x64f, chslo_2x64i, chslo_4x32f,
	  chshi_2x32f, chshi_2x64f, chshi_2x64i, chshi_4x32f ]),
	 @(2, noneExp), ...],
	e -> @(2).val),

## SSE_8x16i SSSE3 rules
    vushuffle_8x16i := Rule([@(1, vushuffle_8x16i), @(2, Value, e->ObjId(e.t)=TVect), @(3)],
        e -> Value(@(2).val.t, List(2*[0..@(2).val.t.size-1], i->@(2).val.v[@(3).val.v[i+1].v/2+1]))),

# complex loopcode load operations rules
    SSE_4x32f_load_TComplex := Rule([@@(1, vpack, (e,cx)-> IsBound(cx.opts) and IsBound(cx.opts.vector) and IsBound(cx.opts.vector.isa) and
        cx.opts.vector.isa = SSE_4x32f),
        [@(2,re), nth], @(3, im, e->e.args[1]=@(2).val.args[1]), @(4,re, e->e.args[1]=@(2).val.args[1]), @(5,im, e->e.args[1]=@(2).val.args[1])],
        e->let(dptr := @(2).val.args[1].toPtr(TVect(TReal, 2)),
            vushuffle_4x32f(vload_2l_4x32f(vzero_4x32f(),dptr), [1,2,1,2]))),

    SSE_4x32f_fold_vushuffle := Rule([@(1, vushuffle_4x32f), @(2, vushuffle_4x32f), @(3)],
        e->vushuffle_4x32f(@(2).val.args[1], List(@(1).val.args[2].p, i->@(2).val.args[2].p[i]))),

    SSE_4x32f_fold_vushuffle_vshuffle := Rule([@(1, vushuffle_4x32f), [vshuffle_4x32f, @(2), @(3), @(4)], @(5)],
        e->vshuffle_4x32f(@(2).val, @(3).val, List(@(5).val.p, i->@(4).val.p[i]))),

    SSE_4x32f_load_TVect := Rule([@@(1, vpack, (e,cx)-> IsBound(cx.opts) and IsBound(cx.opts.vector) and IsBound(cx.opts.vector.isa) and
        cx.opts.vector.isa = SSE_4x32f),
        @(2,nth,e->IsBound(e.loc.init)), @(3, nth, e->e.loc=@(2).val.loc), @(4,nth, e->e.loc=@(2).val.loc), @(5,nth, e->e.loc=@(2).val.loc)],
        e->deref(@(2).val.toPtr(TVect(TReal, 4)))),

    # movldup is an SSE3 instruction
    SSE_4x32f_movldup := Rule([@@(1, vushuffle_4x32f,
        (e,cx) -> IsBound(cx.opts) and IsBound(cx.opts.vector) and IsBound(cx.opts.vector.SIMD) and not cx.opts.vector.SIMD in ["SSE2", "SSE", "MMX"]),
        @(2).cond(e->ObjId(e) <> Value), @(3, vparam, e->e.p=[1,1,3,3])],
        e->vldup_4x32f(@(2).val)),

    # movhdup is an SSE3 instruction
    SSE_4x32f_movhdup := Rule([@@(1,vushuffle_4x32f,
        (e,cx) -> IsBound(cx.opts) and IsBound(cx.opts.vector) and IsBound(cx.opts.vector.SIMD) and not cx.opts.vector.SIMD in ["SSE2", "SSE", "MMX"]),
        @(2).cond(e->ObjId(e) <> Value), @(3, vparam, e->e.p=[2,2,4,4])],
        e->vhdup_4x32f(@(2).val)),

    SSE_2x64f_load_TVect := Rule([@@(1, vpack, (e,cx)-> IsBound(cx.opts) and IsBound(cx.opts.vector) and IsBound(cx.opts.vector.isa) and
        cx.opts.vector.isa = SSE_2x64f),
        @(2,nth,e->IsBound(e.loc.init)), @(3, nth, e->e.loc=@(2).val.loc)],
        e->deref(@(2).val.toPtr(TVect(TReal, 2)))),

    SSE_16x8i_add_ddiv2 := ARule(add, [[ddiv, @(1), @(2, Value, x -> x=2)], ..., [@(3, ddiv), @(4),
        @@(5, Value, (x, cx) -> x=2 and _isISA(@(3).val.t, SSE_16x8i, cx.opts) and IsUIntT(@(3).val.t.base_t()))]],
        e -> [average_16x8i(@(1).val, @(4).val)]),
    SSE_16x8i_add_ddiv2_absdiff2 := ARule(add, [[ddiv, @(1, absdiff2), @(2, Value, x -> x=2)], ..., [@(3, ddiv), @(4, absdiff2),
        @@(5, Value, (x, cx) -> x=2 and _isISA(@(3).val.t, SSE_16x8i, cx.opts))]],
        e -> [average_16x8i(@(1).val, @(4).val)]),

    SSE_16x8i_didiv2_add := Rule([@(0, [ddiv, idiv]), [add, @(1), @(2)],
        @@(3, Value, (x, cx) -> x=2 and _isISA(@(0).val.t, SSE_16x8i, cx.opts) and IsUIntT(@(0).val.t.base_t()))],
        e -> [average_16x8i(@(1).val, @(2).val)]),
    SSE_16x8i_didiv2_add_absdiff2 := Rule([@(0, [ddiv, idiv]), [add, @(1, absdiff2), @(2, absdiff2)],
        @@(3, Value, (x, cx) -> x=2 and _isISA(@(0).val.t, SSE_16x8i, cx.opts))],
        e -> [average_16x8i(@(1).val, @(2).val)]),
));

Class(RulesSSEPostProcess, RuleSet);
RewriteRules(RulesSSEPostProcess, rec(
    div_16x := Rule( [ @@(1, [idiv, ddiv], (x, cx) -> IsOrdT(x.t.base_t()) and _isISA(x.t, SSE_16x8i, cx.opts)),
                       @(2), @(3, Value, x -> let( v := Set(Flat([x.v])), Length(v)=1 and 2^CeilLog2(_unwrap(v[1])) = v[1])) ],
        e -> let( v :=  _unwrap(Set(Flat([@(3).val.v]))[1]),
                  bin_and(tcast(e.t, bin_shr(tcast(TVect(T_Int(16), 8), @(2).val), CeilLog2(v))), e.t.value(idiv(255, v))))),

    SSE_absdiff2_to_xor := Rule( @(1, absdiff2, x -> IsOrdT(x.t.base_t())),
        e -> bin_xor(e.args[1], e.args[2])),

    SSE_fixUnalignedLoadStore := Rule(@@(1,[vstoreu2_4x32f, vstoreu_4x32f],(e,cx)->ObjId(e.args[2])=noneExp and cx.opts.fixUnalignedLoadStore = true), e->skip())
));