44#include < memory>
55#include < vector>
66
7+ #include " lib/Dialect/HEIRInterfaces.h"
78#include " lib/Dialect/TensorExt/IR/TensorExtOps.h"
89#include " lib/Kernel/AbstractValue.h"
910#include " lib/Kernel/ArithmeticDag.h"
@@ -135,6 +136,29 @@ FailureOr<NodePtr> DagBuilder::visit(scf::ForOp op) {
135136 return dagNode;
136137}
137138
139+ FailureOr<NodePtr> DagBuilder::visit (scf::IfOp op) {
140+ if (op.getElseRegion ().empty ()) {
141+ op.emitOpError ()
142+ << " skipped: If/Else without an else branch is not supported\n " ;
143+ return failure ();
144+ }
145+
146+ auto condition = findNodeOrMakeNewVariable (op.getCondition ());
147+ auto thenRes = visitBlockWithSingleTerminator (&op.getThenRegion ().front ());
148+ if (failed (thenRes)) return failure ();
149+ NodePtr thenBody = thenRes.value ();
150+
151+ auto elseRes = visitBlockWithSingleTerminator (&op.getElseRegion ().front ());
152+ if (failed (elseRes)) return failure ();
153+ NodePtr elseBody = elseRes.value ();
154+
155+ auto dagNode = Node::ifElse (condition, thenBody, elseBody);
156+ for (OpResult opResult : op->getOpResults ()) {
157+ valueToNode[opResult] = Node::resultAt (dagNode, opResult.getResultNumber ());
158+ }
159+ return dagNode;
160+ }
161+
138162FailureOr<NodePtr> DagBuilder::visit (scf::YieldOp op) {
139163 std::vector<NodePtr> operands;
140164 operands.reserve (op->getNumOperands ());
@@ -144,11 +168,32 @@ FailureOr<NodePtr> DagBuilder::visit(scf::YieldOp op) {
144168 return Node::yield (operands);
145169}
146170
147- FailureOr<NodePtr> DagBuilder::visit (tensor_ext::RotateOp op) {
148- auto tensor = findNodeOrMakeNewVariable (op.getTensor ());
149- auto shift = findNodeOrMakeNewVariable (op.getShift ());
150- auto dagNode = Node::leftRotate (tensor, shift);
151- valueToNode[op.getResult ()] = dagNode;
171+ FailureOr<NodePtr> DagBuilder::visit (RotationOpInterface op) {
172+ LDBG () << " Processing RotationOpInterface " << op;
173+ OpFoldResult ofr = op.getRotationIndex ();
174+ NodePtr shift;
175+ if (auto attr = dyn_cast<Attribute>(ofr)) {
176+ auto intAttr = cast<IntegerAttr>(attr);
177+ shift = Node::constantScalar (intAttr.getInt (),
178+ mlirTypeToDagType (intAttr.getType ()));
179+ } else {
180+ shift = findNodeOrMakeNewVariable (cast<Value>(ofr));
181+ }
182+
183+ // Find the rotatable operand.
184+ // We assume it's the operand that has the same type as the result.
185+ OpOperand* rotatedOperand = op.getRotatedOperand ();
186+
187+ if (!rotatedOperand) {
188+ LDBG () << " Could not find a rotated operand for op " << op
189+ << " . It may be that the default implementation of "
190+ " getRotatedOperand is incorrect for this RotationOpInterface." ;
191+ return failure ();
192+ }
193+
194+ auto tensorNode = findNodeOrMakeNewVariable (rotatedOperand->get ());
195+ auto dagNode = Node::leftRotate (tensorNode, shift);
196+ valueToNode[op->getResult (0 )] = dagNode;
152197 return dagNode;
153198}
154199
@@ -176,6 +221,41 @@ FailureOr<NodePtr> DagBuilder::visit(arith::SubIOp op) {
176221 return dagNode;
177222}
178223
224+ FailureOr<NodePtr> DagBuilder::visit (arith::CmpIOp op) {
225+ auto lhs = findNodeOrMakeNewVariable (op.getLhs ());
226+ auto rhs = findNodeOrMakeNewVariable (op.getRhs ());
227+
228+ kernel::ComparisonPredicate pred;
229+ switch (op.getPredicate ()) {
230+ case arith::CmpIPredicate::slt:
231+ case arith::CmpIPredicate::ult:
232+ pred = kernel::ComparisonPredicate::LT ;
233+ break ;
234+ case arith::CmpIPredicate::sle:
235+ case arith::CmpIPredicate::ule:
236+ pred = kernel::ComparisonPredicate::LE ;
237+ break ;
238+ case arith::CmpIPredicate::sgt:
239+ case arith::CmpIPredicate::ugt:
240+ pred = kernel::ComparisonPredicate::GT ;
241+ break ;
242+ case arith::CmpIPredicate::sge:
243+ case arith::CmpIPredicate::uge:
244+ pred = kernel::ComparisonPredicate::GE ;
245+ break ;
246+ case arith::CmpIPredicate::eq:
247+ pred = kernel::ComparisonPredicate::EQ ;
248+ break ;
249+ case arith::CmpIPredicate::ne:
250+ pred = kernel::ComparisonPredicate::NE ;
251+ break ;
252+ }
253+
254+ auto dagNode = Node::comparison (lhs, rhs, pred);
255+ valueToNode[op.getResult ()] = dagNode;
256+ return dagNode;
257+ }
258+
179259FailureOr<NodePtr> DagBuilder::visit (arith::ConstantOp op) {
180260 NodePtr dagNode =
181261 TypeSwitch<Attribute, NodePtr>(op.getValue ())
@@ -234,16 +314,61 @@ FailureOr<NodePtr> DagBuilder::visit(arith::DivSIOp op) {
234314 return dagNode;
235315}
236316
317+ FailureOr<NodePtr> DagBuilder::visit (arith::AddFOp op) {
318+ auto lhs = findNodeOrMakeNewVariable (op.getLhs ());
319+ auto rhs = findNodeOrMakeNewVariable (op.getRhs ());
320+ auto dagNode = Node::add (lhs, rhs);
321+ valueToNode[op.getResult ()] = dagNode;
322+ return dagNode;
323+ }
324+
325+ FailureOr<NodePtr> DagBuilder::visit (arith::MulFOp op) {
326+ auto lhs = findNodeOrMakeNewVariable (op.getLhs ());
327+ auto rhs = findNodeOrMakeNewVariable (op.getRhs ());
328+ auto dagNode = Node::mul (lhs, rhs);
329+ valueToNode[op.getResult ()] = dagNode;
330+ return dagNode;
331+ }
332+
333+ FailureOr<NodePtr> DagBuilder::visit (arith::SubFOp op) {
334+ auto lhs = findNodeOrMakeNewVariable (op.getLhs ());
335+ auto rhs = findNodeOrMakeNewVariable (op.getRhs ());
336+ auto dagNode = Node::sub (lhs, rhs);
337+ valueToNode[op.getResult ()] = dagNode;
338+ return dagNode;
339+ }
340+
341+ FailureOr<NodePtr> DagBuilder::visit (arith::NegFOp op) {
342+ auto lhs = findNodeOrMakeNewVariable (op.getOperand ());
343+ // ArithmeticDag doesn't have NegNode, so we can use (0 - lhs)
344+ auto zero = Node::constantScalar (0.0 , mlirTypeToDagType (op.getType ()));
345+ auto dagNode = Node::sub (zero, lhs);
346+ valueToNode[op.getResult ()] = dagNode;
347+ return dagNode;
348+ }
349+
350+ FailureOr<NodePtr> DagBuilder::visit (tensor::ExtractSliceOp op) {
351+ // For rotation analysis, we can approximate extract_slice as just returning
352+ // the source tensor if we don't care about the specific values, or we can
353+ // try to be more precise. Since rotation analysis usually only cares about
354+ // the fact that *some* tensor is being rotated, returning the source is
355+ // enough to keep the DAG connected.
356+ auto source = findNodeOrMakeNewVariable (op.getSource ());
357+ valueToNode[op.getResult ()] = source;
358+ return source;
359+ }
360+
237361FailureOr<NodePtr> DagBuilder::build (Operation* op) {
238362 LDBG () << " Visiting op " << *op;
239363 return llvm::TypeSwitch<Operation*, FailureOr<NodePtr>>(op)
240- .Case <arith::AddIOp, arith::ConstantOp, arith::DivSIOp, arith::MulIOp,
241- arith::SubIOp, scf::ForOp, scf::YieldOp, tensor::ExtractOp,
242- tensor::SplatOp, tensor_ext::RotateOp>(
243- [&](auto op) { return visit (op); })
244- .Default ([&](auto op) {
245- LDBG () << " Unsupported op type " << op->getName ();
246- return failure ();
364+ .Case <arith::AddFOp, arith::AddIOp, arith::CmpIOp, arith::ConstantOp,
365+ arith::DivSIOp, arith::MulFOp, arith::MulIOp, arith::SubFOp,
366+ arith::SubIOp, arith::NegFOp, scf::ForOp, scf::IfOp, scf::YieldOp,
367+ tensor::ExtractOp, tensor::ExtractSliceOp, tensor::SplatOp,
368+ RotationOpInterface>([&](auto op) { return visit (op); })
369+ .Default ([&](Operation* op) -> FailureOr<NodePtr> {
370+ LDBG () << " Unsupported op type " << op->getName () << " , skipping" ;
371+ return NodePtr (nullptr );
247372 });
248373}
249374
0 commit comments