1
0
This repository has been archived on 2025-03-06. You can view files and clone it, but cannot push or open issues or pull requests.

518 lines
17 KiB
MiniZinc

% Copyright (c) 2013-2015, Gabriel Hjort Blindell <ghb@kth.se>
% All rights reserved.
%
% Redistribution and use in source and binary forms, with or without
% modification, are permitted provided that the following conditions are met:
%
% 1. Redistributions of source code must retain the above copyright notice,
% this list of conditions and the following disclaimer.
% 2. Redistributions in binary form must reproduce the above copyright notice,
% this list of conditions and the following disclaimer in the documentation
% and/or other materials provided with the distribution.
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
% AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
% IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
% ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
% LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
% CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
% SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
% INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
% CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
% ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
% POSSIBILITY OF SUCH DAMAGE.
%=====================
% EXTERNAL PARAMETERS
%=====================
% Function data.
int: numOperationsInFunction;
int: numDataInFunction;
int: numBlocksInFunction;
int: entryBlockOfFunction;
array[allBlocksInFunction] of set of int: domSetOfBlockInFunction;
array[allBlocksInFunction] of set of int: defEdgesForBlockInFunction;
array[int] of allDataInFunction: statesInFunction;
array[allBlocksInFunction] of int: execFrequencyOfBlockInFunction;
% Target machine data.
int: numLocations;
% Match data.
int: numMatches;
array[allMatches] of set of int: operationsCoveredByMatch;
array[allMatches] of set of int: dataDefinedByMatch;
array[allMatches] of set of int: dataUsedByMatch;
array[allMatches] of set of int: entryBlockOfMatch;
array[allMatches] of set of int: spannedBlocksInMatch;
array[allMatches] of set of int: consumedBlocksInMatch;
array[allMatches] of int: codeSizeOfMatch;
array[allMatches] of int: latencyOfMatch;
array[allMatches] of bool: applyDefDomUseConstraintForMatch;
set of allMatches: nonCopyMatches;
% Arrays that encode constraints
array[int,int] of int: sameLoc;
array[int,int] of int: inBlockSucc;
array[int,int] of int: inBlock;
array[int,int] of int: locDomain;
array[int,int] of int: funLocDomain;
set of allMatches: Dominated;
%=====================
% INTERNAL PARAMETERS
%=====================
% Total number of location values (an additional value will be needed for
% representing the null location, for when the datum cannot be reused by other
% matches).
int: numLocValues = numLocations + 1;
% Total number of blocks values (an additional value will be needed for
% representing the null block, to which non-selected matches will be placed).
int: numBlockValues = numBlocksInFunction + 1;
% Reference to the null-block value.
int: blockValueForNull = numBlockValues - 1;
% Reference to to the null-location value.
int: locValueForNull = numLocValues - 1;
% Extends the external parameter 'domSetOfBlockInFunction' with a value
% for the null block (which is assumed to be dominated by all blocks).
array[allBlocksInFunctionPlusNull] of set of int:
domSetOfBlockInFunctionPlusNull =
array1d( allBlocksInFunctionPlusNull
, domSetOfBlockInFunction
++
array1d( blockValueForNull..blockValueForNull,
[allBlocksInFunction]
)
);
% Extends the external parameter 'execFrequencyOfBlockInFunction' with a value
% of 0 for the null block.
array[allBlocksInFunctionPlusNull] of int: execFrequencyOfBlocksPlusNull =
array1d( allBlocksInFunctionPlusNull
, execFrequencyOfBlockInFunction
++
array1d(blockValueForNull..blockValueForNull, [0])
);
% Sets to be used as array ranges.
set of int: allOperationsInFunction = 0..numOperationsInFunction-1;
set of int: allDataInFunction = 0..numDataInFunction-1;
set of int: allBlocksInFunction = 0..numBlocksInFunction-1;
set of int: allBlocksInFunctionPlusNull = 0..numBlockValues-1;
set of int: allMatches = 0..numMatches-1;
set of int: allLocValues = 0..numLocValues-1;
%===========
% VARIABLES
%===========
% Data definitions and locations.
array[allDataInFunction] of var allBlocksInFunction: def;
array[allDataInFunction] of var allLocValues: loc;
% Match selection.
array[allMatches] of var bool: sel;
% Blocks wherein the matches are placed.
array[allMatches] of var allBlocksInFunctionPlusNull: place;
% Block ordering (succ[b] is the block appearing immeditely after block b in the
% generated code).
array[allBlocksInFunctionPlusNull] of var allBlocksInFunctionPlusNull: succ;
% Cost.
var 0..sum (m in allMatches diff Dominated)( latencyOfMatch[m]* max ([execFrequencyOfBlocksPlusNull[x] | x in allBlocksInFunction])): objective;
%====================
% GLOBAL CONSTRAINTS
%====================
include "circuit.mzn";
include "table.mzn";
%============
% CONSTRAINTS
%============
% Enforce that, for each operation, exactly one match must be selected such that
% the operation is covered.
constraint
forall (o in allOperationsInFunction)
(
let {
set of int: mset = { m | m in allMatches diff Dominated
where o in operationsCoveredByMatch[m]
}
}
in if card(mset) = 1
then sel[min(mset)]
else if card(mset) = 2
then sel[min(mset)] xor sel[max(mset)]
else sum (m in mset)
(
bool2int(sel[m])
) = 1
endif
endif
);
% Enforce that, for each datum, exactly one match must be selected such that
% the datum is defined.
%
% This is an implied constraint, but it also enforces that the patterns for
% defining the function input and constants are selected. Such patterns do not
% cover any operations, they are not entailed in the above constraint for
% exactly covering each operation.
constraint
forall (e in allDataInFunction)
(
let {
set of int: mset = { m | m in allMatches diff Dominated
where e in dataDefinedByMatch[m]
}
}
in if card(mset) = 1
then sel[min(mset)]
else if card(mset) = 2
then sel[min(mset)] xor sel[max(mset)]
else sum (m in mset)
(
bool2int(sel[m])
) = 1
endif
endif
);
% Implied: The total number of data defined by the selected matches must be
% equal to the number of data in the function graph.
constraint redundant_constraint (
sum (m in allMatches diff Dominated)
(
card(dataDefinedByMatch[m]) * bool2int(sel[m])
) = numDataInFunction
);
% Selected matches must not be placed in the null block.
constraint
forall (m in allMatches)
(
sel[m] <-> place[m] != blockValueForNull
);
% Selected matches that have an entry block must be placed in entry block.
constraint
forall (m in allMatches diff Dominated)
(
% If a match has no entry block, then this set will be empty and hence there
% will be no such constraint. It is assumed that there will be at most one
% entry.
forall (r in entryBlockOfMatch[m])
(
place[m] in {r, blockValueForNull}
)
);
% Data defined by a selected match must be defined in either the block wherein
% the match is placed or in one of the blocks spanned by the match.
constraint
forall (m in allMatches diff Dominated)
(
forall (e in dataDefinedByMatch[m])
(
if (card(spannedBlocksInMatch[m]) > 0)
then
sel[m] -> def[e] in spannedBlocksInMatch[m]
else
sel[m] -> def[e] = place[m]
endif
)
);
% No selected matches may be placed in a block which is consumed by some
% selected match.
constraint
forall (m, mm in allMatches, b in consumedBlocksInMatch[m])
(
sel[m] -> place[mm] != b
);
% For every block wherein a datum is defined, there must exist some selected
% match such that it is either placed in that block or that block is part of
% one of the blocks that appear in the selected match.
%
% I am not certain whether this is a strictly required or just an implied
% constraint...
constraint
forall (e in allDataInFunction, l in allBlocksInFunction)
(
def[e] = l
->
exists (m in allMatches diff Dominated)
(
place[m] = l \/ (sel[m] /\ l in spannedBlocksInMatch[m])
)
);
% A datum with a definition edge with a block must be defined in the block of
% that block.
constraint
forall (l in allBlocksInFunction)
(
forall (e in defEdgesForBlockInFunction[l])
(
def[e] = l
)
);
% Enforce that every datum is defined in a block such that the block dominates
% all blocks wherein the datum is used. This constraint shall not be applied to
% the generic phi patterns.
%
% The code below is essentially a more efficient implementation of:
% constraint
% forall ( m in allMatches, e in dataUsedByMatch[m]
% where applyDefDomUseConstraintForMatch[m]
% )
% (
% def[e] in domSetOfBlockInFunctionPlusNull[place[m]]
% );
int: DomRelSize =
sum (l in allBlocksInFunction)
(
card(domSetOfBlockInFunction[l])
) + numBlocksInFunction;
array[1..DomRelSize, 1..2] of allBlocksInFunctionPlusNull: DomRel =
array2d(1..DomRelSize, 1..2,
[ if k=1 then i else j endif | i in allBlocksInFunctionPlusNull,
j in domSetOfBlockInFunctionPlusNull[i],
k in 1..2
]);
constraint
forall ( m in allMatches diff Dominated, e in dataUsedByMatch[m]
where applyDefDomUseConstraintForMatch[m]
)
(
table([place[m], def[e]], DomRel)
);
% Ensure that succ forms a circuit (thus resulting in an ordering of blocks).
constraint
circuit(succ) :: domain;
% The block of the entry block (i.e. function entry point) must be placed as the
% first block, and the block of the null block must be placed as the last block.
constraint
succ[blockValueForNull] = entryBlockOfFunction;
% Constrain the loc value for all data that are states.
constraint
forall (e in statesInFunction)
(
loc[e] = locValueForNull
);
% Accumulate cost of selected patterns.
% TODO: make this part generic
constraint
objective = sum (m in allMatches diff Dominated)
( latencyOfMatch[m]
* execFrequencyOfBlocksPlusNull[place[m]]
);
%===========================
% PARAMETERIZED CONSTRAINTS
%===========================
constraint
forall(i in index_set_1of2(sameLoc))(
let {int: m = sameLoc[i,1],
int: p = sameLoc[i,2],
int: q = sameLoc[i,3]} in
sel[m] -> loc[p] = loc[q]
);
constraint
forall(i in index_set_1of2(inBlockSucc))(
let {int: m = inBlockSucc[i,1],
int: p = inBlockSucc[i,2],
int: q = inBlockSucc[i,3]} in
place[m] in {p,blockValueForNull} /\
(sel[m] -> succ[p] = q)
);
constraint
forall(i in index_set_1of2(inBlock))(
let {int: m = inBlock[i,1],
int: p = inBlock[i,2]} in
place[m] in {p,blockValueForNull}
);
constraint
forall(i in index_set_1of2(locDomain))(
let {int: m = locDomain[i,1],
int: l = locDomain[i,2]} in
sel[m] -> loc[l] in locDomain[i,3]..locDomain[i,4]
);
constraint
forall(i in index_set_1of2(funLocDomain))(
let {int: l = funLocDomain[i,1]} in
loc[l] in funLocDomain[i,2]..funLocDomain[i,3]
);
%======================================
% IMPLIED BY PARAMETERIZED CONSTRAINTS
%======================================
% Two matches can't both be selected, if they imply conflicting successor blocks.
constraint redundant_constraint(
forall(i in index_set_1of2(inBlockSucc), j in index_set_1of2(inBlockSucc) where i<j)(
let {int: mi = inBlockSucc[i,1],
int: pi = inBlockSucc[i,2],
int: qi = inBlockSucc[i,3],
int: mj = inBlockSucc[j,1],
int: pj = inBlockSucc[j,2],
int: qj = inBlockSucc[j,3]} in
(pi=pj xor qi=qj) -> (not sel[mi] \/ not sel[mj])
)
);
% Two matches can't both be selected, if the first implies that two locations
% are equal, and the second implies that the intersection of their domains is
% empty
constraint redundant_constraint(
forall(i in index_set_1of2(sameLoc))(
let {int: m1 = sameLoc[i,1],
int: p = sameLoc[i,2],
int: q = sameLoc[i,3]} in
forall(j1 in index_set_1of2(locDomain) where locDomain[j1,2]=p)(
forall(j2 in index_set_1of2(locDomain) where locDomain[j2,1]=locDomain[j1,1] /\
locDomain[j2,2]=q)(
let {int: m2 = locDomain[j1,1]} in
card((locDomain[j1,3]..locDomain[j1,4]) intersect (locDomain[j2,3]..locDomain[j2,4]))=0 ->
not sel[m1] \/ not sel[m2]
)
)
)
);
% Ad hoc: detect symmetry among location values 1..31
constraint redundant_constraint (
forall(i in index_set_1of2(funLocDomain))(
let {int: lo = funLocDomain[i,2],
int: hi = funLocDomain[i,3]} in
lo<=31 -> hi>=31 \/ hi=0
) /\
forall(i in index_set_1of2(locDomain))(
let {int: lo = locDomain[i,3],
int: hi = locDomain[i,4]} in
lo<=31 -> hi>=31 \/ hi=0
) ->
forall(i in allDataInFunction)(loc[i] in {0} union (31..numLocValues-1))
);
%===================================================
% DOMINATION DERIVED FROM PARAMETERIZED CONSTRAINTS
%===================================================
% Match m1 dominates match m2 if:
% - neither match occurs in sameLoc, inBlock, inBlockSucc (relax later?)
% - [latencyOfMatch[m1], m1] lex_lt [latencyOfMatch[m2], m2]
% - operationsCoveredByMatch is the same for both matches
% - dataDefinedByMatch is the same for both matches
% - dataUsedByMatch is the same for both matches
% - entryBlockOfMatch is the same for both matches
% - spannedBlocksInMatch is the same for both matches
% - applyDefDomUseConstraintForMatch is the same for both matches
% - if m1 defines any side-constraints in locDomain,
% then m2 defines side-constraints that are at least as strong
test is_dominated(int: m2) =
let {set of allMatches: exclude = {sameLoc[i,1] | i in index_set_1of2(sameLoc)} % relax later
union {inBlock[i,1] | i in index_set_1of2(inBlock)}
union {inBlockSucc[i,1] | i in index_set_1of2(inBlockSucc)}} in
exists(m1 in allMatches where not (m1=m2 \/ m1 in exclude \/ m2 in exclude))(
((latencyOfMatch[m1] < latencyOfMatch[m2]) \/
(latencyOfMatch[m1] = latencyOfMatch[m2] /\ m1 < m2)) /\
operationsCoveredByMatch[m1] = operationsCoveredByMatch[m2] /\
dataDefinedByMatch[m1] = dataDefinedByMatch[m2] /\
dataUsedByMatch[m1] = dataUsedByMatch[m2] /\
entryBlockOfMatch[m1] = entryBlockOfMatch[m2] /\
spannedBlocksInMatch[m1] = spannedBlocksInMatch[m2] /\
applyDefDomUseConstraintForMatch[m1] = applyDefDomUseConstraintForMatch[m2] /\
forall(i in index_set_1of2(locDomain) where locDomain[i,1] = m1)(
exists(j in index_set_1of2(locDomain)
where locDomain[j,1] = m2
/\ locDomain[j,2] = locDomain[i,2])(
(locDomain[j,3]..locDomain[j,4]) subset (locDomain[i,3]..locDomain[i,4])
)
)
);
Dominated = {m | m in allMatches where is_dominated(m)};
constraint
forall(d in Dominated)(not sel[d]);
%==================
% SOLVE AND OUTPUT
%==================
solve ::
seq_search(
[ bool_search([ sel[m] | m in nonCopyMatches diff Dominated
where card(operationsCoveredByMatch[m])
+
card(dataDefinedByMatch[m])
> 2
], input_order, indomain_max, complete)
, bool_search([ sel[m] | m in nonCopyMatches diff Dominated
where card(operationsCoveredByMatch[m])
+
card(dataDefinedByMatch[m])
= 2
], input_order, indomain_max, complete)
, bool_search([ sel[m] | m in nonCopyMatches diff Dominated
where card(operationsCoveredByMatch[m])
+
card(dataDefinedByMatch[m])
= 1
], input_order, indomain_max, complete)
, int_search( def, first_fail, indomain_min, complete)
, int_search( loc, first_fail, indomain_min, complete)
, int_search( place, first_fail, indomain_min, complete)
, int_search( succ, first_fail, indomain_min, complete)
]
)
minimize objective;
output [ "sel = array1d(\(allMatches), \(sel));\n"
, "def = array1d(\(allDataInFunction), \(def));\n"
, "loc = array1d(\(allDataInFunction), \(loc));\n"
, "place = array1d(\(allMatches), \(place));\n"
, "succ = array1d(\(allBlocksInFunctionPlusNull), \(succ));\n"
, "objective = \(objective);\n"
];