7 #include <gtest/gtest.h>
16 TEST(JlmToMlirConverterTests, TestLambda)
19 using namespace mlir::rvsdg;
22 auto graph = &rvsdgModule->Rvsdg();
26 std::cout <<
"Function Setup" << std::endl;
32 graph->GetRootRegion(),
34 auto iOStateArgument = lambda->GetFunctionArguments()[0];
35 auto memoryStateArgument = lambda->GetFunctionArguments()[1];
39 lambda->finalize({ constant, iOStateArgument, memoryStateArgument });
42 std::cout <<
"Convert to MLIR" << std::endl;
47 std::cout <<
"Validate MLIR" << std::endl;
48 auto & omegaRegion = omega.getRegion();
49 EXPECT_EQ(omegaRegion.getBlocks().size(), 1);
50 auto & omegaBlock = omegaRegion.front();
52 EXPECT_EQ(omegaBlock.getOperations().size(), 2);
53 auto & mlirLambda = omegaBlock.front();
55 mlirLambda.getName().getStringRef().equals(mlir::rvsdg::LambdaNode::getOperationName()));
58 std::cout <<
"Verify function name" << std::endl;
59 auto functionNameAttribute = mlirLambda.getAttr(::llvm::StringRef(
"sym_name"));
60 auto * functionName =
static_cast<mlir::StringAttr *
>(&functionNameAttribute);
61 auto string = functionName->getValue().str();
62 EXPECT_EQ(
string,
"test");
65 std::cout <<
"Verify function signature" << std::endl;
67 auto result = mlirLambda.getResult(0).getType();
68 EXPECT_EQ(result.getTypeID(), mlir::FunctionType::getTypeID());
70 auto lambdaOp = ::mlir::dyn_cast<::mlir::rvsdg::LambdaNode>(&mlirLambda);
72 auto lamdbaTerminator = lambdaOp.getRegion().front().getTerminator();
73 auto lambdaResult = mlir::dyn_cast<mlir::rvsdg::LambdaResult>(lamdbaTerminator);
74 EXPECT_NE(lambdaResult,
nullptr);
77 std::vector<mlir::Type> arguments;
78 for (
auto argument : lambdaOp->getRegion(0).getArguments())
80 arguments.push_back(argument.getType());
82 EXPECT_EQ(arguments[0].getTypeID(), IOStateEdgeType::getTypeID());
83 EXPECT_EQ(arguments[1].getTypeID(), MemStateEdgeType::getTypeID());
84 std::vector<mlir::Type> results;
85 for (
auto returnType : lambdaResult->getOperandTypes())
87 results.push_back(returnType);
89 EXPECT_TRUE(results[0].isa<mlir::IntegerType>());
90 EXPECT_TRUE(results[1].isa<mlir::rvsdg::IOStateEdgeType>());
91 EXPECT_TRUE(results[2].isa<mlir::rvsdg::MemStateEdgeType>());
93 auto & lambdaRegion = mlirLambda.getRegion(0);
94 auto & lambdaBlock = lambdaRegion.front();
96 EXPECT_EQ(lambdaBlock.getOperations().size(), 2);
97 EXPECT_TRUE(lambdaBlock.front().getName().getStringRef().equals(
98 mlir::arith::ConstantIntOp::getOperationName()));
117 if (definingOperations.empty())
119 std::cout <<
"Checking if operation: "
120 << operation->getOperand(0).getDefiningOp()->getName().getStringRef().data()
121 <<
" is equal to: " << definingOperations.back().data() << std::endl;
122 EXPECT_TRUE(operation->getOperand(0).getDefiningOp()->getName().getStringRef().equals(
123 definingOperations.back()));
124 definingOperations.pop_back();
140 TEST(JlmToMlirConverterTests, TestAddOperation)
143 using namespace mlir::rvsdg;
146 auto graph = &rvsdgModule->Rvsdg();
150 std::cout <<
"Function Setup" << std::endl;
156 graph->GetRootRegion(),
158 auto iOStateArgument = lambda->GetFunctionArguments()[0];
159 auto memoryStateArgument = lambda->GetFunctionArguments()[1];
162 std::cout <<
"Add Operation" << std::endl;
167 lambda->finalize({
add, iOStateArgument, memoryStateArgument });
170 std::cout <<
"Convert to MLIR" << std::endl;
175 std::cout <<
"Checking blocks and operations count" << std::endl;
176 auto & omegaRegion = omega.getRegion();
177 EXPECT_EQ(omegaRegion.getBlocks().size(), 1);
178 auto & omegaBlock = omegaRegion.front();
180 EXPECT_EQ(omegaBlock.getOperations().size(), 2);
183 std::cout <<
"Checking lambda block operations" << std::endl;
184 auto & mlirLambda = omegaBlock.front();
185 auto & lambdaRegion = mlirLambda.getRegion(0);
186 auto & lambdaBlock = lambdaRegion.front();
188 EXPECT_EQ(lambdaBlock.getOperations().size(), 4);
191 std::cout <<
"Checking lambda block operations types" << std::endl;
192 std::vector<mlir::Operation *> operations;
193 for (
auto & operation : lambdaBlock.getOperations())
195 operations.push_back(&operation);
199 for (
auto & operation : operations)
201 if (operation->getName().getStringRef().equals(mlir::rvsdg::LambdaResult::getOperationName()))
203 if (operation->getName().getStringRef().equals(
204 mlir::arith::ConstantIntOp::getOperationName()))
210 std::cout <<
"Checking add operation" << std::endl;
211 EXPECT_TRUE(operation->getName().getStringRef().equals(
212 mlir::arith::AddIOp::getOperationName()));
214 EXPECT_EQ(operation->getNumOperands(), 2);
215 auto addOperand1 = operation->getOperand(0);
216 auto addOperand2 = operation->getOperand(1);
217 EXPECT_TRUE(addOperand1.getType().isInteger(32));
218 EXPECT_TRUE(addOperand2.getType().isInteger(32));
220 EXPECT_EQ(constCount, 2);
223 &lambdaBlock.getOperations().back(),
224 { mlir::arith::ConstantIntOp::getOperationName(),
225 mlir::arith::AddIOp::getOperationName() });
237 TEST(JlmToMlirConverterTests, TestComZeroExt)
240 using namespace mlir::rvsdg;
243 auto graph = &rvsdgModule->Rvsdg();
247 std::cout <<
"Function Setup" << std::endl;
253 graph->GetRootRegion(),
255 auto iOStateArgument = lambda->GetFunctionArguments()[0];
256 auto memoryStateArgument = lambda->GetFunctionArguments()[1];
259 std::cout <<
"Add Operation" << std::endl;
265 const auto zeroExt = jlm::rvsdg::CreateOpNode<ZExtOperation>({ constant1 }, 8, 16).output(0);
271 lambda->finalize({ comp, iOStateArgument, memoryStateArgument });
274 std::cout <<
"Convert to MLIR" << std::endl;
279 std::cout <<
"Checking blocks and operations count" << std::endl;
280 auto & omegaRegion = omega.getRegion();
281 EXPECT_EQ(omegaRegion.getBlocks().size(), 1);
282 auto & omegaBlock = omegaRegion.front();
284 EXPECT_EQ(omegaBlock.getOperations().size(), 2);
287 std::cout <<
"Checking lambda block operations" << std::endl;
288 auto & mlirLambda = omegaBlock.front();
289 auto & lambdaRegion = mlirLambda.getRegion(0);
290 auto & lambdaBlock = lambdaRegion.front();
292 EXPECT_EQ(lambdaBlock.getOperations().size(), 7);
295 std::cout <<
"Checking lambda block operations types" << std::endl;
296 std::vector<mlir::Operation *> operations;
297 for (
auto & operation : lambdaBlock.getOperations())
299 std::cout <<
"Operation: " << operation.getName().getStringRef().data() << std::endl;
300 operations.push_back(&operation);
307 for (
auto & operation : operations)
309 if (operation->getName().getStringRef().equals(mlir::rvsdg::LambdaResult::getOperationName()))
311 if (operation->getName().getStringRef().equals(
312 mlir::arith::ConstantIntOp::getOperationName()))
315 operation->getResult(0).getType().isInteger(8)
316 || operation->getResult(0).getType().isInteger(16));
320 if (operation->getName().getStringRef().equals(mlir::arith::ExtUIOp::getOperationName()))
322 EXPECT_EQ(operation->getNumOperands(), 1);
323 EXPECT_TRUE(operation->getOperand(0).getType().isInteger(8));
324 EXPECT_EQ(operation->getNumResults(), 1);
325 EXPECT_TRUE(operation->getResult(0).getType().isInteger(16));
329 if (operation->getName().getStringRef().equals(mlir::arith::MulIOp::getOperationName()))
331 EXPECT_EQ(operation->getNumOperands(), 2);
332 EXPECT_TRUE(operation->getOperand(0).getType().isInteger(16));
333 EXPECT_TRUE(operation->getOperand(1).getType().isInteger(16));
334 EXPECT_EQ(operation->getNumResults(), 1);
335 EXPECT_TRUE(operation->getResult(0).getType().isInteger(16));
339 if (operation->getName().getStringRef().equals(mlir::arith::CmpIOp::getOperationName()))
341 auto comparisonOp = mlir::cast<mlir::arith::CmpIOp>(operation);
342 EXPECT_EQ(comparisonOp.getPredicate(), mlir::arith::CmpIPredicate::sgt);
343 EXPECT_EQ(operation->getNumOperands(), 2);
344 EXPECT_TRUE(operation->getOperand(0).getType().isInteger(16));
345 EXPECT_TRUE(operation->getOperand(1).getType().isInteger(16));
346 EXPECT_EQ(operation->getNumResults(), 1);
354 std::cout <<
"Checking counts" << std::endl;
355 EXPECT_EQ(constCount, 3);
356 EXPECT_EQ(extCount, 1);
357 EXPECT_EQ(mulCount, 1);
358 EXPECT_EQ(compCount, 1);
361 &lambdaBlock.getOperations().back(),
362 { mlir::arith::ConstantIntOp::getOperationName(),
363 mlir::arith::ExtUIOp::getOperationName(),
364 mlir::arith::MulIOp::getOperationName(),
365 mlir::arith::CmpIOp::getOperationName() });
375 TEST(JlmToMlirConverterTests, TestMatch)
378 using namespace mlir::rvsdg;
381 auto graph = &rvsdgModule->Rvsdg();
385 std::cout <<
"Function Setup" << std::endl;
391 graph->GetRootRegion(),
393 auto iOStateArgument = lambda->GetFunctionArguments()[0];
394 auto memoryStateArgument = lambda->GetFunctionArguments()[1];
397 std::cout <<
"Match Operation" << std::endl;
403 lambda->finalize({ match, iOStateArgument, memoryStateArgument });
406 std::cout <<
"Convert to MLIR" << std::endl;
411 std::cout <<
"Checking blocks and operations count" << std::endl;
412 auto & omegaRegion = omega.getRegion();
413 EXPECT_EQ(omegaRegion.getBlocks().size(), 1);
414 auto & omegaBlock = omegaRegion.front();
416 EXPECT_EQ(omegaBlock.getOperations().size(), 2);
419 std::cout <<
"Checking lambda block operations" << std::endl;
420 auto & mlirLambda = omegaBlock.front();
421 auto & lambdaRegion = mlirLambda.getRegion(0);
422 auto & lambdaBlock = lambdaRegion.front();
424 EXPECT_EQ(lambdaBlock.getOperations().size(), 3);
426 bool matchFound =
false;
427 for (
auto & operation : lambdaBlock.getOperations())
429 if (mlir::isa<mlir::rvsdg::Match>(operation))
432 std::cout <<
"Checking match operation" << std::endl;
433 auto matchOp = mlir::cast<mlir::rvsdg::Match>(operation);
435 EXPECT_TRUE(mlir::isa<mlir::arith::ConstantIntOp>(matchOp.getInput().getDefiningOp()));
436 auto constant = mlir::cast<mlir::arith::ConstantIntOp>(matchOp.getInput().getDefiningOp());
437 EXPECT_EQ(constant.value(), 4);
438 EXPECT_TRUE(constant.getType().isInteger(8));
440 auto mapping = matchOp.getMapping();
443 EXPECT_EQ(mapping.size(), 4);
446 for (
auto & attr : mapping)
448 EXPECT_TRUE(attr.isa<::mlir::rvsdg::MatchRuleAttr>());
449 auto matchRuleAttr = attr.cast<::mlir::rvsdg::MatchRuleAttr>();
450 if (matchRuleAttr.isDefault())
452 EXPECT_EQ(matchRuleAttr.getIndex(), 2);
453 EXPECT_TRUE(matchRuleAttr.getValues().empty());
457 EXPECT_EQ(matchRuleAttr.getValues().size(), 1);
459 const int64_t value = matchRuleAttr.getValues().front();
462 (matchRuleAttr.getIndex() == 0 && value == 4)
463 || (matchRuleAttr.getIndex() == 1 && (value == 5 || value == 6)));
468 EXPECT_TRUE(matchFound);
478 TEST(JlmToMlirConverterTests, TestGamma)
481 using namespace mlir::rvsdg;
484 auto graph = &rvsdgModule->Rvsdg();
489 std::cout <<
"Gamma Operation" << std::endl;
498 rvsdgGammaNode->AddEntryVar(entryvar1);
499 rvsdgGammaNode->AddEntryVar(entryvar2);
501 std::vector<jlm::rvsdg::Output *> exitvars1;
502 std::vector<jlm::rvsdg::Output *> exitvars2;
503 for (
int i = 0; i < 3; i++)
508 *rvsdgGammaNode->subregion(i),
509 { 32, 10 * (i + 1) }));
512 rvsdgGammaNode->AddExitVar(exitvars1);
513 rvsdgGammaNode->AddExitVar(exitvars2);
516 std::cout <<
"Convert to MLIR" << std::endl;
521 std::cout <<
"Checking blocks and operations count" << std::endl;
522 auto & omegaRegion = omega.getRegion();
523 EXPECT_EQ(omegaRegion.getBlocks().size(), 1);
524 auto & omegaBlock = omegaRegion.front();
526 EXPECT_EQ(omegaBlock.getOperations().size(), 5);
528 bool gammaFound =
false;
529 for (
auto & operation : omegaBlock.getOperations())
531 if (mlir::isa<mlir::rvsdg::GammaNode>(operation))
534 std::cout <<
"Checking gamma operation" << std::endl;
535 auto gammaOp = mlir::cast<mlir::rvsdg::GammaNode>(operation);
536 EXPECT_EQ(gammaOp.getNumRegions(), 3);
538 EXPECT_EQ(gammaOp.getNumOperands(), 3);
539 EXPECT_EQ(gammaOp.getNumResults(), 2);
541 std::cout <<
"Checking gamma predicate" << std::endl;
542 EXPECT_TRUE(mlir::isa<mlir::rvsdg::ConstantCtrl>(gammaOp.getPredicate().getDefiningOp()));
543 auto controlConstant =
544 mlir::cast<mlir::rvsdg::ConstantCtrl>(gammaOp.getPredicate().getDefiningOp());
545 EXPECT_EQ(controlConstant.getValue(), 1);
546 EXPECT_TRUE(mlir::isa<mlir::rvsdg::RVSDG_CTRLType>(controlConstant.getType()));
547 auto ctrlType = mlir::cast<mlir::rvsdg::RVSDG_CTRLType>(controlConstant.getType());
548 EXPECT_EQ(ctrlType.getNumOptions(), 3);
550 std::cout <<
"Checking gamma entryVars" << std::endl;
552 auto entryVars = gammaOp.getInputs();
553 EXPECT_EQ(entryVars.size(), 2);
554 EXPECT_TRUE(mlir::isa<mlir::arith::ConstantIntOp>(entryVars[0].getDefiningOp()));
555 EXPECT_TRUE(mlir::isa<mlir::arith::ConstantIntOp>(entryVars[1].getDefiningOp()));
556 auto entryVar1 = mlir::cast<mlir::arith::ConstantIntOp>(entryVars[0].getDefiningOp());
557 auto entryVar2 = mlir::cast<mlir::arith::ConstantIntOp>(entryVars[1].getDefiningOp());
558 EXPECT_EQ(entryVar1.value(), 5);
559 EXPECT_EQ(entryVar2.value(), 6);
561 std::cout <<
"Checking gamma subregions" << std::endl;
562 for (
size_t i = 0; i < gammaOp.getNumRegions(); i++)
564 EXPECT_EQ(gammaOp.getRegion(i).getBlocks().size(), 1);
565 auto & gammaBlock = gammaOp.getRegion(i).front();
567 EXPECT_EQ(gammaBlock.getOperations().size(), 3);
569 std::cout <<
"Checking gamma exitVars" << std::endl;
570 auto gammaResult = gammaBlock.getTerminator();
571 EXPECT_TRUE(mlir::isa<mlir::rvsdg::GammaResult>(gammaResult));
572 auto gammaResultOp = mlir::cast<mlir::rvsdg::GammaResult>(gammaResult);
573 EXPECT_EQ(gammaResultOp.getNumOperands(), 2);
574 for (
size_t j = 0; j < gammaResultOp.getNumOperands(); j++)
577 mlir::isa<mlir::arith::ConstantIntOp>(gammaResultOp.getOperand(j).getDefiningOp()));
579 mlir::cast<mlir::arith::ConstantIntOp>(gammaResultOp.getOperand(j).getDefiningOp());
580 EXPECT_EQ(
static_cast<size_t>(constant.value()), (1 - j) * (i + 1) + 10 * (i + 1) * j);
585 EXPECT_TRUE(gammaFound);
594 TEST(JlmToMlirConverterTests, TestTheta)
597 using namespace mlir::rvsdg;
600 auto graph = &rvsdgModule->Rvsdg();
604 std::cout <<
"Theta Operation" << std::endl;
617 std::cout <<
"Convert to MLIR" << std::endl;
622 std::cout <<
"Checking blocks and operations count" << std::endl;
623 auto & omegaRegion = omega.getRegion();
624 EXPECT_EQ(omegaRegion.getBlocks().size(), 1);
625 auto & omegaBlock = omegaRegion.front();
627 EXPECT_EQ(omegaBlock.getOperations().size(), 4);
629 bool thetaFound =
false;
630 for (
auto & operation : omegaBlock.getOperations())
632 if (mlir::isa<mlir::rvsdg::ThetaNode>(operation))
635 std::cout <<
"Checking theta operation" << std::endl;
636 auto thetaOp = mlir::cast<mlir::rvsdg::ThetaNode>(operation);
638 EXPECT_EQ(thetaOp.getNumOperands(), 2);
639 EXPECT_EQ(thetaOp.getNumResults(), 2);
641 auto & thetaBlock = thetaOp.getRegion().front();
642 auto thetaResult = thetaBlock.getTerminator();
644 EXPECT_TRUE(mlir::isa<mlir::rvsdg::ThetaResult>(thetaResult));
645 auto thetaResultOp = mlir::cast<mlir::rvsdg::ThetaResult>(thetaResult);
647 std::cout <<
"Checking theta predicate" << std::endl;
650 mlir::isa<mlir::rvsdg::ConstantCtrl>(thetaResultOp.getPredicate().getDefiningOp()));
651 auto controlConstant =
652 mlir::cast<mlir::rvsdg::ConstantCtrl>(thetaResultOp.getPredicate().getDefiningOp());
654 EXPECT_EQ(controlConstant.getValue(), 0);
656 EXPECT_TRUE(mlir::isa<mlir::rvsdg::RVSDG_CTRLType>(controlConstant.getType()));
657 auto ctrlType = mlir::cast<mlir::rvsdg::RVSDG_CTRLType>(controlConstant.getType());
658 EXPECT_EQ(ctrlType.getNumOptions(), 2);
660 std::cout <<
"Checking theta loop vars" << std::endl;
662 auto loopVars = thetaOp.getInputs();
663 EXPECT_EQ(loopVars.size(), 2);
664 EXPECT_TRUE(mlir::isa<mlir::arith::ConstantIntOp>(loopVars[0].getDefiningOp()));
665 EXPECT_TRUE(mlir::isa<mlir::arith::ConstantIntOp>(loopVars[1].getDefiningOp()));
666 auto loopVar1 = mlir::cast<mlir::arith::ConstantIntOp>(loopVars[0].getDefiningOp());
667 auto loopVar2 = mlir::cast<mlir::arith::ConstantIntOp>(loopVars[1].getDefiningOp());
668 EXPECT_EQ(loopVar1.value(), 5);
669 EXPECT_EQ(loopVar2.value(), 6);
672 EXPECT_EQ(thetaBlock.getOperations().size(), 2);
674 std::cout <<
"Checking loop exitVars" << std::endl;
675 std::cout << thetaResultOp.getNumOperands() << std::endl;
677 std::cout <<
"Checking theta subregion" << std::endl;
680 EXPECT_EQ(thetaResultOp.getNumOperands(), 3);
684 EXPECT_TRUE(thetaFound);
TEST(JlmToMlirConverterTests, TestLambda)
static void useChainsUpTraverse(mlir::Operation *operation, std::vector< llvm::StringRef > definingOperations)
useChainsUpTraverse
static std::shared_ptr< const IOStateType > Create()
static std::unique_ptr< LlvmLambdaOperation > Create(std::shared_ptr< const jlm::rvsdg::FunctionType > type, std::string name, const jlm::llvm::Linkage &linkage, jlm::llvm::CallingConvention callingConvention, jlm::llvm::AttributeSet attributes)
static std::unique_ptr< LlvmRvsdgModule > Create(const util::FilePath &sourceFileName, const std::string &targetTriple, const std::string &dataLayout)
static std::shared_ptr< const MemoryStateType > Create()
::mlir::rvsdg::OmegaNode ConvertModule(const llvm::LlvmRvsdgModule &rvsdgModule)
static Output & create(Region ®ion, BitValueRepresentation value)
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
static Output & create(Region ®ion, ControlValueRepresentation value)
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
static std::shared_ptr< const FunctionType > Create(std::vector< std::shared_ptr< const jlm::rvsdg::Type >> argumentTypes, std::vector< std::shared_ptr< const jlm::rvsdg::Type >> resultTypes)
static GammaNode * create(jlm::rvsdg::Output *predicate, size_t nalternatives)
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
std::unique_ptr< BitBinaryOperation > create(size_t nbits) const override
std::unique_ptr< BitCompareOperation > create(size_t nbits) const override
static Output * Create(Output &predicate, const std::unordered_map< uint64_t, uint64_t > &mapping, const uint64_t defaultAlternative, const size_t numAlternatives)
rvsdg::Region * subregion() const noexcept
void set_predicate(jlm::rvsdg::Output *p)
static ThetaNode * create(rvsdg::Region *parent)
LoopVar AddLoopVar(rvsdg::Output *origin)
Creates a new loop-carried variable.
Global memory state passed between functions.