1 //===- ReductionRules.h - Reduction Rules -----------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
11 //===----------------------------------------------------------------------===//
13 #ifndef LLVM_CODEGEN_PBQP_REDUCTIONRULES_H
14 #define LLVM_CODEGEN_PBQP_REDUCTIONRULES_H
25 /// Reduce a node of degree one.
27 /// Propagate costs from the given node, which must be of degree one, to its
28 /// neighbor. Notify the problem domain.
29 template <typename GraphT
>
30 void applyR1(GraphT
&G
, typename
GraphT::NodeId NId
) {
31 using NodeId
= typename
GraphT::NodeId
;
32 using EdgeId
= typename
GraphT::EdgeId
;
33 using Vector
= typename
GraphT::Vector
;
34 using Matrix
= typename
GraphT::Matrix
;
35 using RawVector
= typename
GraphT::RawVector
;
37 assert(G
.getNodeDegree(NId
) == 1 &&
38 "R1 applied to node with degree != 1.");
40 EdgeId EId
= *G
.adjEdgeIds(NId
).begin();
41 NodeId MId
= G
.getEdgeOtherNodeId(EId
, NId
);
43 const Matrix
&ECosts
= G
.getEdgeCosts(EId
);
44 const Vector
&XCosts
= G
.getNodeCosts(NId
);
45 RawVector YCosts
= G
.getNodeCosts(MId
);
47 // Duplicate a little to avoid transposing matrices.
48 if (NId
== G
.getEdgeNode1Id(EId
)) {
49 for (unsigned j
= 0; j
< YCosts
.getLength(); ++j
) {
50 PBQPNum Min
= ECosts
[0][j
] + XCosts
[0];
51 for (unsigned i
= 1; i
< XCosts
.getLength(); ++i
) {
52 PBQPNum C
= ECosts
[i
][j
] + XCosts
[i
];
59 for (unsigned i
= 0; i
< YCosts
.getLength(); ++i
) {
60 PBQPNum Min
= ECosts
[i
][0] + XCosts
[0];
61 for (unsigned j
= 1; j
< XCosts
.getLength(); ++j
) {
62 PBQPNum C
= ECosts
[i
][j
] + XCosts
[j
];
69 G
.setNodeCosts(MId
, YCosts
);
70 G
.disconnectEdge(EId
, MId
);
73 template <typename GraphT
>
74 void applyR2(GraphT
&G
, typename
GraphT::NodeId NId
) {
75 using NodeId
= typename
GraphT::NodeId
;
76 using EdgeId
= typename
GraphT::EdgeId
;
77 using Vector
= typename
GraphT::Vector
;
78 using Matrix
= typename
GraphT::Matrix
;
79 using RawMatrix
= typename
GraphT::RawMatrix
;
81 assert(G
.getNodeDegree(NId
) == 2 &&
82 "R2 applied to node with degree != 2.");
84 const Vector
&XCosts
= G
.getNodeCosts(NId
);
86 typename
GraphT::AdjEdgeItr AEItr
= G
.adjEdgeIds(NId
).begin();
87 EdgeId YXEId
= *AEItr
,
90 NodeId YNId
= G
.getEdgeOtherNodeId(YXEId
, NId
),
91 ZNId
= G
.getEdgeOtherNodeId(ZXEId
, NId
);
93 bool FlipEdge1
= (G
.getEdgeNode1Id(YXEId
) == NId
),
94 FlipEdge2
= (G
.getEdgeNode1Id(ZXEId
) == NId
);
96 const Matrix
*YXECosts
= FlipEdge1
?
97 new Matrix(G
.getEdgeCosts(YXEId
).transpose()) :
98 &G
.getEdgeCosts(YXEId
);
100 const Matrix
*ZXECosts
= FlipEdge2
?
101 new Matrix(G
.getEdgeCosts(ZXEId
).transpose()) :
102 &G
.getEdgeCosts(ZXEId
);
104 unsigned XLen
= XCosts
.getLength(),
105 YLen
= YXECosts
->getRows(),
106 ZLen
= ZXECosts
->getRows();
108 RawMatrix
Delta(YLen
, ZLen
);
110 for (unsigned i
= 0; i
< YLen
; ++i
) {
111 for (unsigned j
= 0; j
< ZLen
; ++j
) {
112 PBQPNum Min
= (*YXECosts
)[i
][0] + (*ZXECosts
)[j
][0] + XCosts
[0];
113 for (unsigned k
= 1; k
< XLen
; ++k
) {
114 PBQPNum C
= (*YXECosts
)[i
][k
] + (*ZXECosts
)[j
][k
] + XCosts
[k
];
129 EdgeId YZEId
= G
.findEdge(YNId
, ZNId
);
131 if (YZEId
== G
.invalidEdgeId()) {
132 YZEId
= G
.addEdge(YNId
, ZNId
, Delta
);
134 const Matrix
&YZECosts
= G
.getEdgeCosts(YZEId
);
135 if (YNId
== G
.getEdgeNode1Id(YZEId
)) {
136 G
.updateEdgeCosts(YZEId
, Delta
+ YZECosts
);
138 G
.updateEdgeCosts(YZEId
, Delta
.transpose() + YZECosts
);
142 G
.disconnectEdge(YXEId
, YNId
);
143 G
.disconnectEdge(ZXEId
, ZNId
);
145 // TODO: Try to normalize newly added/modified edge.
149 // Does this Cost vector have any register options ?
150 template <typename VectorT
>
151 bool hasRegisterOptions(const VectorT
&V
) {
152 unsigned VL
= V
.getLength();
154 // An empty or spill only cost vector does not provide any register option.
158 // If there are registers in the cost vector, but all of them have infinite
159 // costs, then ... there is no available register.
160 for (unsigned i
= 1; i
< VL
; ++i
)
161 if (V
[i
] != std::numeric_limits
<PBQP::PBQPNum
>::infinity())
168 // Find a solution to a fully reduced graph by backpropagation.
170 // Given a graph and a reduction order, pop each node from the reduction
171 // order and greedily compute a minimum solution based on the node costs, and
172 // the dependent costs due to previously solved nodes.
174 // Note - This does not return the graph to its original (pre-reduction)
175 // state: the existing solvers destructively alter the node and edge
176 // costs. Given that, the backpropagate function doesn't attempt to
177 // replace the edges either, but leaves the graph in its reduced
179 template <typename GraphT
, typename StackT
>
180 Solution
backpropagate(GraphT
& G
, StackT stack
) {
181 using NodeId
= GraphBase::NodeId
;
182 using Matrix
= typename
GraphT::Matrix
;
183 using RawVector
= typename
GraphT::RawVector
;
187 while (!stack
.empty()) {
188 NodeId NId
= stack
.back();
191 RawVector v
= G
.getNodeCosts(NId
);
194 // Although a conservatively allocatable node can be allocated to a register,
195 // spilling it may provide a lower cost solution. Assert here that spilling
196 // is done by choice, not because there were no register available.
197 if (G
.getNodeMetadata(NId
).wasConservativelyAllocatable())
198 assert(hasRegisterOptions(v
) && "A conservatively allocatable node "
199 "must have available register options");
202 for (auto EId
: G
.adjEdgeIds(NId
)) {
203 const Matrix
& edgeCosts
= G
.getEdgeCosts(EId
);
204 if (NId
== G
.getEdgeNode1Id(EId
)) {
205 NodeId mId
= G
.getEdgeNode2Id(EId
);
206 v
+= edgeCosts
.getColAsVector(s
.getSelection(mId
));
208 NodeId mId
= G
.getEdgeNode1Id(EId
);
209 v
+= edgeCosts
.getRowAsVector(s
.getSelection(mId
));
213 s
.setSelection(NId
, v
.minIndex());
219 } // end namespace PBQP
220 } // end namespace llvm
222 #endif // LLVM_CODEGEN_PBQP_REDUCTIONRULES_H