Jlm
MlirToJlmConverterTests.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2024 Louis Maurin <louis7maurin@gmail.com>
3  * Copyright 2024 Magnus Själander <work@sjalander.com>
4  * See COPYING for terms of redistribution.
5  */
6 
7 #include <gtest/gtest.h>
8 
14 #include <jlm/rvsdg/traverser.hpp>
15 
16 #include <jlm/rvsdg/view.hpp>
17 
18 TEST(MlirToJlmConverterTests, TestLambda)
19 {
20  {
21  using namespace mlir::rvsdg;
22  using namespace mlir::jlm;
23 
24  // Setup MLIR Context and load dialects
25  std::cout << "Creating MLIR context" << std::endl;
26  auto context = std::make_unique<mlir::MLIRContext>();
27  context->getOrLoadDialect<RVSDGDialect>();
28  context->getOrLoadDialect<JLMDialect>();
29  context->getOrLoadDialect<mlir::arith::ArithDialect>();
30  context->getOrLoadDialect<mlir::LLVM::LLVMDialect>();
31  auto Builder_ = std::make_unique<mlir::OpBuilder>(context.get());
32 
33  auto omega = Builder_->create<OmegaNode>(Builder_->getUnknownLoc());
34  auto & omegaRegion = omega.getRegion();
35  auto * omegaBlock = new mlir::Block;
36  omegaRegion.push_back(omegaBlock);
37 
38  // Handle function arguments
39  std::cout << "Creating function arguments" << std::endl;
40  ::llvm::SmallVector<mlir::Type> arguments;
41  arguments.push_back(Builder_->getType<IOStateEdgeType>());
42  arguments.push_back(Builder_->getType<MemStateEdgeType>());
43  ::llvm::ArrayRef argumentsArray(arguments);
44 
45  // Handle function results
46  std::cout << "Creating function results" << std::endl;
47  ::llvm::SmallVector<mlir::Type> results;
48  results.push_back(Builder_->getIntegerType(32));
49  results.push_back(Builder_->getType<IOStateEdgeType>());
50  results.push_back(Builder_->getType<MemStateEdgeType>());
51  ::llvm::ArrayRef resultsArray(results);
52 
53  // Add function attributes
54  std::cout << "Creating function attributes" << std::endl;
55  ::llvm::SmallVector<mlir::NamedAttribute> attributes;
56  auto attributeName = Builder_->getStringAttr("sym_name");
57  auto attributeValue = Builder_->getStringAttr("test");
58  auto symbolName = Builder_->getNamedAttr(attributeName, attributeValue);
59  attributes.push_back(symbolName);
60  ::llvm::ArrayRef<::mlir::NamedAttribute> attributesRef(attributes);
61 
62  // Add inputs to the function
63  ::llvm::SmallVector<mlir::Value> inputs;
64 
65  // Create the lambda node and add it to the region/block it resides in
66  std::cout << "Creating LambdaNode" << std::endl;
67  auto lambda = Builder_->create<LambdaNode>(
68  Builder_->getUnknownLoc(),
69  Builder_->getType<mlir::FunctionType>(arguments, results),
70  inputs,
71  attributesRef);
72  omegaBlock->push_back(lambda);
73  auto & lambdaRegion = lambda.getRegion();
74  auto * lambdaBlock = new mlir::Block;
75  lambdaRegion.push_back(lambdaBlock);
76 
77  // Add arguments to the region
78  std::cout << "Adding arguments to the region" << std::endl;
79  lambdaBlock->addArgument(Builder_->getType<IOStateEdgeType>(), Builder_->getUnknownLoc());
80  lambdaBlock->addArgument(Builder_->getType<MemStateEdgeType>(), Builder_->getUnknownLoc());
81 
82  auto constOp = Builder_->create<mlir::arith::ConstantIntOp>(Builder_->getUnknownLoc(), 1, 32);
83  lambdaBlock->push_back(constOp);
84 
85  ::llvm::SmallVector<mlir::Value> regionResults;
86  regionResults.push_back(constOp);
87  regionResults.push_back(lambdaBlock->getArgument(0));
88  regionResults.push_back(lambdaBlock->getArgument(1));
89 
90  // Handle the result of the lambda
91  std::cout << "Creating LambdaResult" << std::endl;
92  auto lambdaResult = Builder_->create<LambdaResult>(Builder_->getUnknownLoc(), regionResults);
93  lambdaBlock->push_back(lambdaResult);
94 
95  // Handle the result of the omega
96  std::cout << "Creating OmegaResult" << std::endl;
97  ::llvm::SmallVector<mlir::Value> omegaRegionResults;
98  omegaRegionResults.push_back(lambda.getResult());
99  auto omegaResult = Builder_->create<OmegaResult>(Builder_->getUnknownLoc(), omegaRegionResults);
100  omegaBlock->push_back(omegaResult);
101 
102  std::unique_ptr<mlir::Block> rootBlock = std::make_unique<mlir::Block>();
103  rootBlock->push_back(omega);
104 
105  // Convert the MLIR to RVSDG and check the result
106  std::cout << "Converting MLIR to RVSDG" << std::endl;
107  auto rvsdgModule = jlm::mlir::MlirToJlmConverter::CreateAndConvert(rootBlock);
108  auto region = &rvsdgModule->Rvsdg().GetRootRegion();
109  {
110  using namespace jlm::rvsdg;
111  std::cout << "Checking the result" << std::endl;
112 
113  EXPECT_EQ(region->numNodes(), 1);
114  auto convertedLambda =
115  jlm::util::assertedCast<jlm::rvsdg::LambdaNode>(region->Nodes().begin().ptr());
116  EXPECT_TRUE(is<jlm::llvm::LlvmLambdaOperation>(convertedLambda->GetOperation()));
117 
118  EXPECT_EQ(convertedLambda->subregion()->numNodes(), 1);
119  EXPECT_TRUE(is<jlm::llvm::IntegerConstantOperation>(
120  convertedLambda->subregion()->Nodes().begin().ptr()));
121  }
122  }
123 }
124 
131 TEST(MlirToJlmConverterTests, TestDivOperation)
132 {
133  {
134  using namespace mlir::rvsdg;
135  using namespace mlir::jlm;
136 
137  // Setup MLIR Context and load dialects
138  std::cout << "Creating MLIR context" << std::endl;
139  auto context = std::make_unique<mlir::MLIRContext>();
140  context->getOrLoadDialect<RVSDGDialect>();
141  context->getOrLoadDialect<JLMDialect>();
142  context->getOrLoadDialect<mlir::arith::ArithDialect>();
143  context->getOrLoadDialect<mlir::LLVM::LLVMDialect>();
144  auto Builder_ = std::make_unique<mlir::OpBuilder>(context.get());
145 
146  auto omega = Builder_->create<OmegaNode>(Builder_->getUnknownLoc());
147  auto & omegaRegion = omega.getRegion();
148  auto * omegaBlock = new mlir::Block;
149  omegaRegion.push_back(omegaBlock);
150 
151  // Handle function arguments
152  std::cout << "Creating function arguments" << std::endl;
153  ::llvm::SmallVector<mlir::Type> arguments;
154  arguments.push_back(Builder_->getIntegerType(32));
155  arguments.push_back(Builder_->getType<IOStateEdgeType>());
156  arguments.push_back(Builder_->getType<MemStateEdgeType>());
157  ::llvm::ArrayRef argumentsArray(arguments);
158 
159  // Handle function results
160  std::cout << "Creating function results" << std::endl;
161  ::llvm::SmallVector<mlir::Type> results;
162  results.push_back(Builder_->getIntegerType(32));
163  results.push_back(Builder_->getType<IOStateEdgeType>());
164  results.push_back(Builder_->getType<MemStateEdgeType>());
165  ::llvm::ArrayRef resultsArray(results);
166 
167  // Add function attributes
168  std::cout << "Creating function attributes" << std::endl;
169  ::llvm::SmallVector<mlir::NamedAttribute> attributes;
170  auto attributeName = Builder_->getStringAttr("sym_name");
171  auto attributeValue = Builder_->getStringAttr("test");
172  auto symbolName = Builder_->getNamedAttr(attributeName, attributeValue);
173  attributes.push_back(symbolName);
174  ::llvm::ArrayRef<::mlir::NamedAttribute> attributesRef(attributes);
175 
176  // Add inputs to the function
177  ::llvm::SmallVector<mlir::Value> inputs;
178 
179  // Create the lambda node and add it to the region/block it resides in
180  std::cout << "Creating LambdaNode" << std::endl;
181  auto lambda = Builder_->create<LambdaNode>(
182  Builder_->getUnknownLoc(),
183  Builder_->getType<mlir::FunctionType>(arguments, results),
184  inputs,
185  attributesRef);
186  omegaBlock->push_back(lambda);
187  auto & lambdaRegion = lambda.getRegion();
188  auto * lambdaBlock = new mlir::Block;
189  lambdaRegion.push_back(lambdaBlock);
190 
191  // Add arguments to the region
192  std::cout << "Adding arguments to the region" << std::endl;
193  lambdaBlock->addArgument(Builder_->getIntegerType(32), Builder_->getUnknownLoc());
194  lambdaBlock->addArgument(Builder_->getType<IOStateEdgeType>(), Builder_->getUnknownLoc());
195  lambdaBlock->addArgument(Builder_->getType<MemStateEdgeType>(), Builder_->getUnknownLoc());
196 
197  // ConstOp1 is not connected to anything
198  auto constOp1 = Builder_->create<mlir::arith::ConstantIntOp>(Builder_->getUnknownLoc(), 20, 32);
199  lambdaBlock->push_back(constOp1);
200 
201  // ConstOp2 is connected as second argument of the divide operation
202  auto constOp2 = Builder_->create<mlir::arith::ConstantIntOp>(Builder_->getUnknownLoc(), 5, 32);
203  lambdaBlock->push_back(constOp2);
204 
205  // lambdaBlock->getArguments();
206  for (unsigned int i = 0; i < lambdaBlock->getNumArguments(); ++i)
207  {
208  auto arg = lambdaBlock->getArgument(i);
209  if (arg.getType().isa<IOStateEdgeType>())
210  {
211  std::cout << "Argument " << i << " is an IOStateEdgeType" << std::endl;
212  }
213  else if (arg.getType().isa<MemStateEdgeType>())
214  {
215  std::cout << "Argument " << i << " is a MemStateEdgeType" << std::endl;
216  }
217  else if (arg.getType().isa<mlir::IntegerType>())
218  {
219  std::cout << "Argument " << i << " is an IntegerType" << std::endl;
220  }
221  }
222 
225  auto divideOp = Builder_->create<mlir::arith::DivUIOp>(
226  Builder_->getUnknownLoc(),
227  lambdaBlock->getArgument(0),
228  constOp2);
229  lambdaBlock->push_back(divideOp);
230 
231  ::llvm::SmallVector<mlir::Value> regionResults;
232  regionResults.push_back(divideOp->getResult(0));
233  regionResults.push_back(lambdaBlock->getArgument(1));
234  regionResults.push_back(lambdaBlock->getArgument(2));
235 
236  // Handle the result of the lambda
237  std::cout << "Creating LambdaResult" << std::endl;
238  auto lambdaResult = Builder_->create<LambdaResult>(Builder_->getUnknownLoc(), regionResults);
239  lambdaBlock->push_back(lambdaResult);
240 
241  // Handle the result of the omega
242  std::cout << "Creating OmegaResult" << std::endl;
243  ::llvm::SmallVector<mlir::Value> omegaRegionResults;
244  omegaRegionResults.push_back(lambda.getResult());
245  auto omegaResult = Builder_->create<OmegaResult>(Builder_->getUnknownLoc(), omegaRegionResults);
246  omegaBlock->push_back(omegaResult);
247 
248  std::unique_ptr<mlir::Block> rootBlock = std::make_unique<mlir::Block>();
249  rootBlock->push_back(omega);
250 
251  // Convert the MLIR to RVSDG and check the result
252  std::cout << "Converting MLIR to RVSDG" << std::endl;
253  auto rvsdgModule = jlm::mlir::MlirToJlmConverter::CreateAndConvert(rootBlock);
254  auto region = &rvsdgModule->Rvsdg().GetRootRegion();
255 
256  jlm::rvsdg::view(region, stdout);
257 
258  {
259  using namespace jlm::rvsdg;
260 
261  EXPECT_EQ(region->numNodes(), 1);
262 
263  // Get the lambda block
264  auto convertedLambda =
265  jlm::util::assertedCast<jlm::rvsdg::LambdaNode>(region->Nodes().begin().ptr());
266  EXPECT_TRUE(is<jlm::llvm::LlvmLambdaOperation>(convertedLambda));
267 
268  // 2 Constants + 1 DivUIOp
269  EXPECT_EQ(convertedLambda->subregion()->numNodes(), 3);
270 
271  // Traverse the rvsgd graph upwards to check connections
272  NodeOutput * lambdaResultOriginNodeOutput =
273  dynamic_cast<jlm::rvsdg::NodeOutput *>(convertedLambda->subregion()->result(0)->origin());
274  EXPECT_NE(lambdaResultOriginNodeOutput, nullptr);
275  Node * lambdaResultOriginNode = lambdaResultOriginNodeOutput->node();
276  EXPECT_TRUE(is<jlm::llvm::IntegerUDivOperation>(lambdaResultOriginNode->GetOperation()));
277  EXPECT_EQ(lambdaResultOriginNode->ninputs(), 2);
278 
279  // Check first input
280  RegionArgument * DivInput0 =
281  dynamic_cast<jlm::rvsdg::RegionArgument *>(lambdaResultOriginNode->input(0)->origin());
282  EXPECT_NE(DivInput0, nullptr);
283  EXPECT_TRUE(jlm::rvsdg::is<BitType>(DivInput0->Type()));
284  EXPECT_EQ(std::dynamic_pointer_cast<const BitType>(DivInput0->Type())->nbits(), 32);
285 
286  // Check second input
287  auto DivInput1Node = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(
288  *lambdaResultOriginNode->input(1)->origin());
289  EXPECT_NE(DivInput1Node, nullptr);
290  EXPECT_TRUE(is<jlm::llvm::IntegerConstantOperation>(DivInput1Node->GetOperation()));
291  auto DivInput1Constant =
292  dynamic_cast<const jlm::llvm::IntegerConstantOperation *>(&DivInput1Node->GetOperation());
293  EXPECT_EQ(DivInput1Constant->Representation().to_int(), 5);
294  EXPECT_TRUE(is<const BitType>(DivInput1Constant->result(0)));
295  EXPECT_EQ(
296  std::dynamic_pointer_cast<const BitType>(DivInput1Constant->result(0))->nbits(),
297  32);
298  }
299  }
300 }
301 
309 TEST(MlirToJlmConverterTests, TestCompZeroExt)
310 {
311  {
312  using namespace mlir::rvsdg;
313  using namespace mlir::jlm;
314 
315  // Setup MLIR Context and load dialects
316  std::cout << "Creating MLIR context" << std::endl;
317  auto context = std::make_unique<mlir::MLIRContext>();
318  context->getOrLoadDialect<RVSDGDialect>();
319  context->getOrLoadDialect<JLMDialect>();
320  context->getOrLoadDialect<mlir::arith::ArithDialect>();
321  context->getOrLoadDialect<mlir::LLVM::LLVMDialect>();
322  auto Builder_ = std::make_unique<mlir::OpBuilder>(context.get());
323 
324  auto omega = Builder_->create<OmegaNode>(Builder_->getUnknownLoc());
325  auto & omegaRegion = omega.getRegion();
326  auto * omegaBlock = new mlir::Block;
327  omegaRegion.push_back(omegaBlock);
328 
329  // Handle function arguments
330  std::cout << "Creating function arguments" << std::endl;
331  ::llvm::SmallVector<mlir::Type> arguments;
332  arguments.push_back(Builder_->getIntegerType(32));
333  arguments.push_back(Builder_->getType<IOStateEdgeType>());
334  arguments.push_back(Builder_->getType<MemStateEdgeType>());
335  ::llvm::ArrayRef argumentsArray(arguments);
336 
337  // Handle function results
338  std::cout << "Creating function results" << std::endl;
339  ::llvm::SmallVector<mlir::Type> results;
340  results.push_back(Builder_->getIntegerType(32));
341  results.push_back(Builder_->getType<IOStateEdgeType>());
342  results.push_back(Builder_->getType<MemStateEdgeType>());
343  ::llvm::ArrayRef resultsArray(results);
344 
345  // Add function attributes
346  std::cout << "Creating function attributes" << std::endl;
347  ::llvm::SmallVector<mlir::NamedAttribute> attributes;
348  auto attributeName = Builder_->getStringAttr("sym_name");
349  auto attributeValue = Builder_->getStringAttr("test");
350  auto symbolName = Builder_->getNamedAttr(attributeName, attributeValue);
351  attributes.push_back(symbolName);
352  ::llvm::ArrayRef<::mlir::NamedAttribute> attributesRef(attributes);
353 
354  // Add inputs to the function
355  ::llvm::SmallVector<mlir::Value> inputs;
356 
357  // Create the lambda node and add it to the region/block it resides in
358  std::cout << "Creating LambdaNode" << std::endl;
359  auto lambda = Builder_->create<LambdaNode>(
360  Builder_->getUnknownLoc(),
361  Builder_->getType<mlir::FunctionType>(arguments, results),
362  inputs,
363  attributesRef);
364  omegaBlock->push_back(lambda);
365  auto & lambdaRegion = lambda.getRegion();
366  auto * lambdaBlock = new mlir::Block;
367  lambdaRegion.push_back(lambdaBlock);
368 
369  // Add arguments to the region
370  std::cout << "Adding arguments to the region" << std::endl;
371  lambdaBlock->addArgument(Builder_->getIntegerType(32), Builder_->getUnknownLoc());
372  lambdaBlock->addArgument(Builder_->getType<IOStateEdgeType>(), Builder_->getUnknownLoc());
373  lambdaBlock->addArgument(Builder_->getType<MemStateEdgeType>(), Builder_->getUnknownLoc());
374 
375  // ConstOp1 is connected to the second argument of the add operation
376  auto constOp1 = Builder_->create<mlir::arith::ConstantIntOp>(Builder_->getUnknownLoc(), 20, 32);
377  lambdaBlock->push_back(constOp1);
378 
379  // ConstOp2 is connected as second argument of the compare operation
380  auto constOp2 = Builder_->create<mlir::arith::ConstantIntOp>(Builder_->getUnknownLoc(), 5, 32);
381  lambdaBlock->push_back(constOp2);
382 
385  auto AddOp = Builder_->create<mlir::arith::AddIOp>(
386  Builder_->getUnknownLoc(),
387  lambdaBlock->getArgument(0),
388  constOp1);
389  lambdaBlock->push_back(AddOp);
390 
391  auto compOp = Builder_->create<mlir::arith::CmpIOp>(
392  Builder_->getUnknownLoc(),
393  mlir::arith::CmpIPredicate::eq,
394  AddOp.getResult(),
395  constOp2);
396  lambdaBlock->push_back(compOp);
397 
398  auto zeroExtOp = Builder_->create<mlir::arith::ExtUIOp>(
399  Builder_->getUnknownLoc(),
400  Builder_->getIntegerType(32),
401  compOp.getResult());
402  lambdaBlock->push_back(zeroExtOp);
403 
404  // Handle the result of the lambda
405  ::llvm::SmallVector<mlir::Value> regionResults;
406  regionResults.push_back(zeroExtOp->getResult(0));
407  regionResults.push_back(lambdaBlock->getArgument(1));
408  regionResults.push_back(lambdaBlock->getArgument(2));
409  std::cout << "Creating LambdaResult" << std::endl;
410  auto lambdaResult = Builder_->create<LambdaResult>(Builder_->getUnknownLoc(), regionResults);
411  lambdaBlock->push_back(lambdaResult);
412 
413  // Handle the result of the omega
414  std::cout << "Creating OmegaResult" << std::endl;
415  ::llvm::SmallVector<mlir::Value> omegaRegionResults;
416  omegaRegionResults.push_back(lambda.getResult());
417  auto omegaResult = Builder_->create<OmegaResult>(Builder_->getUnknownLoc(), omegaRegionResults);
418  omegaBlock->push_back(omegaResult);
419 
420  std::unique_ptr<mlir::Block> rootBlock = std::make_unique<mlir::Block>();
421  rootBlock->push_back(omega);
422 
423  // Convert the MLIR to RVSDG and check the result
424  std::cout << "Converting MLIR to RVSDG" << std::endl;
425  auto rvsdgModule = jlm::mlir::MlirToJlmConverter::CreateAndConvert(rootBlock);
426  auto region = &rvsdgModule->Rvsdg().GetRootRegion();
427 
428  {
429  using namespace jlm::rvsdg;
430 
431  std::cout << "Checking the result" << std::endl;
432 
433  EXPECT_EQ(region->numNodes(), 1);
434 
435  // Get the lambda block
436  auto convertedLambda =
437  jlm::util::assertedCast<jlm::rvsdg::LambdaNode>(region->Nodes().begin().ptr());
438  EXPECT_TRUE(is<jlm::llvm::LlvmLambdaOperation>(convertedLambda));
439 
440  // 2 Constants + AddOp + CompOp + ZeroExtOp
441  EXPECT_EQ(convertedLambda->subregion()->numNodes(), 5);
442 
443  // Traverse the rvsgd graph upwards to check connections
444  std::cout << "Testing lambdaResultOriginNodeOuput\n";
445  auto ZExtNode = jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(
446  *convertedLambda->subregion()->result(0)->origin());
447  EXPECT_NE(ZExtNode, nullptr);
448  EXPECT_TRUE(is<jlm::llvm::ZExtOperation>(ZExtNode->GetOperation()));
449  EXPECT_EQ(ZExtNode->ninputs(), 1);
450 
451  // Check ZExt
452  auto ZExtOp = dynamic_cast<const jlm::llvm::ZExtOperation *>(&ZExtNode->GetOperation());
453  EXPECT_EQ(ZExtOp->nsrcbits(), 1);
454  EXPECT_EQ(ZExtOp->ndstbits(), 32);
455 
456  // Check ZExt input
457  std::cout << "Testing input 0\n";
458  auto BitEqNode =
459  jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*ZExtNode->input(0)->origin());
460  EXPECT_TRUE(is<jlm::llvm::IntegerEqOperation>(BitEqNode->GetOperation()));
461 
462  // Check BitEq
463  EXPECT_EQ(
464  dynamic_cast<const jlm::llvm::IntegerEqOperation *>(&BitEqNode->GetOperation())
465  ->Type()
466  .nbits(),
467  32);
468  EXPECT_EQ(BitEqNode->ninputs(), 2);
469 
470  // Check BitEq input 0
471  auto AddNode =
472  jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*BitEqNode->input(0)->origin());
473  EXPECT_TRUE(is<jlm::llvm::IntegerAddOperation>(AddNode->GetOperation()));
474  EXPECT_EQ(AddNode->ninputs(), 2);
475 
476  // Check BitEq input 1
477  auto Const2Node =
478  jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*BitEqNode->input(1)->origin());
479  EXPECT_TRUE(is<jlm::llvm::IntegerConstantOperation>(Const2Node->GetOperation()));
480 
481  // Check Const2
482  auto Const2Op =
483  dynamic_cast<const jlm::llvm::IntegerConstantOperation *>(&Const2Node->GetOperation());
484  EXPECT_EQ(Const2Op->Representation().to_int(), 5);
485  EXPECT_TRUE(is<const BitType>(Const2Op->result(0)));
486  EXPECT_EQ(std::dynamic_pointer_cast<const BitType>(Const2Op->result(0))->nbits(), 32);
487 
488  // Check add op
489  auto AddOp = dynamic_cast<const jlm::llvm::IntegerAddOperation *>(&AddNode->GetOperation());
490  EXPECT_EQ(AddOp->Type().nbits(), 32);
491 
492  // Check add input0
493  RegionArgument * AddInput0 =
494  dynamic_cast<jlm::rvsdg::RegionArgument *>(AddNode->input(0)->origin());
495  EXPECT_NE(AddInput0, nullptr);
496  EXPECT_TRUE(jlm::rvsdg::is<BitType>(AddInput0->Type()));
497  EXPECT_EQ(std::dynamic_pointer_cast<const BitType>(AddInput0->Type())->nbits(), 32);
498 
499  // Check add input1
500  auto Const1Node =
501  jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*AddNode->input(1)->origin());
502  EXPECT_TRUE(is<jlm::llvm::IntegerConstantOperation>(Const1Node->GetOperation()));
503 
504  // Check Const1
505  auto Const1Op =
506  dynamic_cast<const jlm::llvm::IntegerConstantOperation *>(&Const1Node->GetOperation());
507  EXPECT_EQ(Const1Op->Representation().to_int(), 20);
508  EXPECT_TRUE(is<const BitType>(Const1Op->result(0)));
509  EXPECT_EQ(std::dynamic_pointer_cast<const BitType>(Const1Op->result(0))->nbits(), 32);
510  }
511  }
512 }
513 
519 TEST(MlirToJlmConverterTests, TestMatchOp)
520 {
521  {
522  using namespace mlir::rvsdg;
523  using namespace mlir::jlm;
524 
525  // Setup MLIR Context and load dialects
526  std::cout << "Creating MLIR context" << std::endl;
527  auto context = std::make_unique<mlir::MLIRContext>();
528  context->getOrLoadDialect<RVSDGDialect>();
529  context->getOrLoadDialect<JLMDialect>();
530  context->getOrLoadDialect<mlir::arith::ArithDialect>();
531  context->getOrLoadDialect<mlir::LLVM::LLVMDialect>();
532  auto Builder_ = std::make_unique<mlir::OpBuilder>(context.get());
533 
534  auto omega = Builder_->create<OmegaNode>(Builder_->getUnknownLoc());
535  auto & omegaRegion = omega.getRegion();
536  auto * omegaBlock = new mlir::Block;
537  omegaRegion.push_back(omegaBlock);
538 
539  // Handle function arguments
540  std::cout << "Creating function arguments" << std::endl;
541  ::llvm::SmallVector<mlir::Type> arguments;
542  arguments.push_back(Builder_->getIntegerType(32));
543  arguments.push_back(Builder_->getType<IOStateEdgeType>());
544  arguments.push_back(Builder_->getType<MemStateEdgeType>());
545  ::llvm::ArrayRef argumentsArray(arguments);
546 
547  // Handle function results
548  std::cout << "Creating function results" << std::endl;
549  ::llvm::SmallVector<mlir::Type> results;
550  results.push_back(::mlir::rvsdg::RVSDG_CTRLType::get(Builder_->getContext(), 4));
551  results.push_back(Builder_->getType<IOStateEdgeType>());
552  results.push_back(Builder_->getType<MemStateEdgeType>());
553  ::llvm::ArrayRef resultsArray(results);
554 
555  // Add function attributes
556  std::cout << "Creating function attributes" << std::endl;
557  ::llvm::SmallVector<mlir::NamedAttribute> attributes;
558  auto attributeName = Builder_->getStringAttr("sym_name");
559  auto attributeValue = Builder_->getStringAttr("test");
560  auto symbolName = Builder_->getNamedAttr(attributeName, attributeValue);
561  attributes.push_back(symbolName);
562  ::llvm::ArrayRef<::mlir::NamedAttribute> attributesRef(attributes);
563 
564  // Add inputs to the function
565  ::llvm::SmallVector<mlir::Value> inputs;
566 
567  // Create the lambda node and add it to the region/block it resides in
568  std::cout << "Creating LambdaNode" << std::endl;
569  auto lambda = Builder_->create<LambdaNode>(
570  Builder_->getUnknownLoc(),
571  Builder_->getType<mlir::FunctionType>(arguments, results),
572  inputs,
573  attributesRef);
574  omegaBlock->push_back(lambda);
575  auto & lambdaRegion = lambda.getRegion();
576  auto * lambdaBlock = new mlir::Block;
577  lambdaRegion.push_back(lambdaBlock);
578 
579  // Add arguments to the region
580  std::cout << "Adding arguments to the region" << std::endl;
581  lambdaBlock->addArgument(Builder_->getIntegerType(32), Builder_->getUnknownLoc());
582  lambdaBlock->addArgument(Builder_->getType<IOStateEdgeType>(), Builder_->getUnknownLoc());
583  lambdaBlock->addArgument(Builder_->getType<MemStateEdgeType>(), Builder_->getUnknownLoc());
584 
585  ::llvm::SmallVector<::mlir::Attribute> mappingVector;
586 
587  mappingVector.push_back(::mlir::rvsdg::MatchRuleAttr::get(
588  Builder_->getContext(),
589  ::llvm::ArrayRef(static_cast<int64_t>(0)),
590  4));
591  mappingVector.push_back(::mlir::rvsdg::MatchRuleAttr::get(
592  Builder_->getContext(),
593  ::llvm::ArrayRef(static_cast<int64_t>(1)),
594  5));
595  mappingVector.push_back(::mlir::rvsdg::MatchRuleAttr::get(
596  Builder_->getContext(),
597  ::llvm::ArrayRef(static_cast<int64_t>(1)),
598  6));
600  mappingVector.push_back(
601  ::mlir::rvsdg::MatchRuleAttr::get(Builder_->getContext(), ::llvm::ArrayRef<int64_t>(), 2));
602 
603  auto Match = Builder_->create<::mlir::rvsdg::Match>(
604  Builder_->getUnknownLoc(),
605  ::mlir::rvsdg::RVSDG_CTRLType::get(
606  Builder_->getContext(),
607  mappingVector.size()), // Control, ouput type
608  // omegaBlock->getArgument(0), // input
609  lambdaBlock->getArgument(0), // input
610  ::mlir::ArrayAttr::get(Builder_->getContext(), ::llvm::ArrayRef(mappingVector)));
611  lambdaBlock->push_back(Match);
612 
613  // Handle the result of the lambda
614  ::llvm::SmallVector<mlir::Value> regionResults;
615  regionResults.push_back(Match->getResult(0));
616  regionResults.push_back(lambdaBlock->getArgument(1));
617  regionResults.push_back(lambdaBlock->getArgument(2));
618  std::cout << "Creating LambdaResult" << std::endl;
619  auto lambdaResult = Builder_->create<LambdaResult>(Builder_->getUnknownLoc(), regionResults);
620  lambdaBlock->push_back(lambdaResult);
621 
622  // Handle the result of the omega
623  std::cout << "Creating OmegaResult" << std::endl;
624  ::llvm::SmallVector<mlir::Value> omegaRegionResults;
625  omegaRegionResults.push_back(lambda.getResult());
626  auto omegaResult = Builder_->create<OmegaResult>(Builder_->getUnknownLoc(), omegaRegionResults);
627  omegaBlock->push_back(omegaResult);
628 
629  // Convert the MLIR to RVSDG and check the result
630  std::cout << "Converting MLIR to RVSDG" << std::endl;
631  std::unique_ptr<mlir::Block> rootBlock = std::make_unique<mlir::Block>();
632  rootBlock->push_back(omega);
633  auto rvsdgModule = jlm::mlir::MlirToJlmConverter::CreateAndConvert(rootBlock);
634  auto region = &rvsdgModule->Rvsdg().GetRootRegion();
635 
636  {
637  using namespace jlm::rvsdg;
638 
639  // Get the lambda block
640  auto convertedLambda =
641  jlm::util::assertedCast<jlm::rvsdg::LambdaNode>(region->Nodes().begin().ptr());
642  EXPECT_TRUE(is<jlm::llvm::LlvmLambdaOperation>(convertedLambda));
643 
644  auto lambdaRegion = convertedLambda->subregion();
645 
646  auto matchNode =
647  jlm::rvsdg::TryGetOwnerNode<jlm::rvsdg::SimpleNode>(*lambdaRegion->result(0)->origin());
648  EXPECT_TRUE(is<MatchOperation>(matchNode->GetOperation()));
649 
650  auto matchOp = dynamic_cast<const MatchOperation *>(&matchNode->GetOperation());
651  EXPECT_EQ(matchOp->narguments(), 1);
652  EXPECT_TRUE(is<const BitType>(matchOp->argument(0)));
653  EXPECT_EQ(std::dynamic_pointer_cast<const BitType>(matchOp->argument(0))->nbits(), 32);
654 
655  // 3 alternatives + default
656  EXPECT_EQ(matchOp->nalternatives(), 4);
657 
658  EXPECT_EQ(matchOp->default_alternative(), 2);
659 
660  for (auto mapping : *matchOp)
661  {
662  EXPECT_TRUE(
663  (mapping.first == 0 && mapping.second == 4)
664  || (mapping.first == 1 && mapping.second == 5)
665  || (mapping.first == 1 && mapping.second == 6));
666  }
667  }
668  }
669 }
670 
676 TEST(MlirToJlmConverterTests, TestGammaOp)
677 {
678  {
679  using namespace mlir::rvsdg;
680  using namespace mlir::jlm;
681 
682  // Setup MLIR Context and load dialects
683  std::cout << "Creating MLIR context" << std::endl;
684  auto context = std::make_unique<mlir::MLIRContext>();
685  context->getOrLoadDialect<RVSDGDialect>();
686  context->getOrLoadDialect<JLMDialect>();
687  context->getOrLoadDialect<mlir::arith::ArithDialect>();
688  context->getOrLoadDialect<mlir::LLVM::LLVMDialect>();
689  auto Builder_ = std::make_unique<mlir::OpBuilder>(context.get());
690 
691  auto omega = Builder_->create<OmegaNode>(Builder_->getUnknownLoc());
692  auto & omegaRegion = omega.getRegion();
693  auto * omegaBlock = new mlir::Block;
694  omegaRegion.push_back(omegaBlock);
695 
696  // Handle function arguments
697  std::cout << "Creating function arguments" << std::endl;
698  ::llvm::SmallVector<mlir::Type> arguments;
699  arguments.push_back(::mlir::rvsdg::RVSDG_CTRLType::get(Builder_->getContext(), 3));
700  arguments.push_back(Builder_->getType<IOStateEdgeType>());
701  arguments.push_back(Builder_->getType<MemStateEdgeType>());
702  ::llvm::ArrayRef argumentsArray(arguments);
703 
704  // Handle function results
705  std::cout << "Creating function results" << std::endl;
706  ::llvm::SmallVector<mlir::Type> results;
707  results.push_back(Builder_->getIntegerType(32));
708  results.push_back(Builder_->getIntegerType(32));
709  results.push_back(Builder_->getType<IOStateEdgeType>());
710  results.push_back(Builder_->getType<MemStateEdgeType>());
711  ::llvm::ArrayRef resultsArray(results);
712 
713  // Add function attributes
714  std::cout << "Creating function attributes" << std::endl;
715  ::llvm::SmallVector<mlir::NamedAttribute> attributes;
716  auto attributeName = Builder_->getStringAttr("sym_name");
717  auto attributeValue = Builder_->getStringAttr("test");
718  auto symbolName = Builder_->getNamedAttr(attributeName, attributeValue);
719  attributes.push_back(symbolName);
720  ::llvm::ArrayRef<::mlir::NamedAttribute> attributesRef(attributes);
721 
722  // Add inputs to the function
723  ::llvm::SmallVector<mlir::Value> inputs;
724 
725  // Create the lambda node and add it to the region/block it resides in
726  std::cout << "Creating LambdaNode" << std::endl;
727  auto lambda = Builder_->create<LambdaNode>(
728  Builder_->getUnknownLoc(),
729  Builder_->getType<mlir::FunctionType>(arguments, results),
730  inputs,
731  attributesRef);
732  omegaBlock->push_back(lambda);
733  auto & lambdaRegion = lambda.getRegion();
734  auto * lambdaBlock = new mlir::Block;
735  lambdaRegion.push_back(lambdaBlock);
736 
737  // Add arguments to the region
738  std::cout << "Adding arguments to the region" << std::endl;
739  lambdaBlock->addArgument(
740  ::mlir::rvsdg::RVSDG_CTRLType::get(Builder_->getContext(), 3),
741  Builder_->getUnknownLoc());
742  lambdaBlock->addArgument(Builder_->getType<IOStateEdgeType>(), Builder_->getUnknownLoc());
743  lambdaBlock->addArgument(Builder_->getType<MemStateEdgeType>(), Builder_->getUnknownLoc());
744 
745  auto entryVar1 = Builder_->create<mlir::arith::ConstantIntOp>(Builder_->getUnknownLoc(), 5, 32);
746  lambdaBlock->push_back(entryVar1);
747  auto entryVar2 = Builder_->create<mlir::arith::ConstantIntOp>(Builder_->getUnknownLoc(), 6, 32);
748  lambdaBlock->push_back(entryVar2);
749 
750  ::llvm::SmallVector<::mlir::Type> typeRangeOuput;
751  typeRangeOuput.push_back(::mlir::IntegerType::get(Builder_->getContext(), 32));
752  typeRangeOuput.push_back(::mlir::IntegerType::get(Builder_->getContext(), 32));
753  ::mlir::rvsdg::GammaNode gamma = Builder_->create<::mlir::rvsdg::GammaNode>(
754  Builder_->getUnknownLoc(),
755  ::mlir::TypeRange(::llvm::ArrayRef(typeRangeOuput)), // Ouputs types
756  lambdaBlock->getArgument(0), // predicate
757  ::mlir::ValueRange(::llvm::ArrayRef<::mlir::Value>({ entryVar1, entryVar2 })), // Inputs
758  static_cast<unsigned>(3) // regionsCount
759  );
760  lambdaBlock->push_back(gamma);
761 
762  for (size_t i = 0; i < gamma.getNumRegions(); ++i)
763  {
764  auto & gammaBlock = gamma.getRegion(i).emplaceBlock();
765  auto exitvar1 =
766  Builder_->create<mlir::arith::ConstantIntOp>(Builder_->getUnknownLoc(), i + 1, 32);
767  gammaBlock.push_back(exitvar1);
768  auto exitvar2 =
769  Builder_->create<mlir::arith::ConstantIntOp>(Builder_->getUnknownLoc(), 10 * (i + 1), 32);
770  gammaBlock.push_back(exitvar2);
771  auto gammaResult = Builder_->create<::mlir::rvsdg::GammaResult>(
772  Builder_->getUnknownLoc(),
773  ::llvm::SmallVector<mlir::Value>({ exitvar1, exitvar2 }));
774  gammaBlock.push_back(gammaResult);
775  }
776 
777  // Handle the result of the lambda
778  ::llvm::SmallVector<mlir::Value> regionResults;
779  regionResults.push_back(gamma->getResult(0));
780  regionResults.push_back(gamma->getResult(1));
781  regionResults.push_back(lambdaBlock->getArgument(1));
782  regionResults.push_back(lambdaBlock->getArgument(2));
783  std::cout << "Creating LambdaResult" << std::endl;
784  auto lambdaResult = Builder_->create<LambdaResult>(Builder_->getUnknownLoc(), regionResults);
785  lambdaBlock->push_back(lambdaResult);
786 
787  // Handle the result of the omega
788  std::cout << "Creating OmegaResult" << std::endl;
789  ::llvm::SmallVector<mlir::Value> omegaRegionResults;
790  omegaRegionResults.push_back(lambda.getResult());
791  auto omegaResult = Builder_->create<OmegaResult>(Builder_->getUnknownLoc(), omegaRegionResults);
792  omegaBlock->push_back(omegaResult);
793 
794  // Convert the MLIR to RVSDG and check the result
795  std::cout << "Converting MLIR to RVSDG" << std::endl;
796  std::unique_ptr<mlir::Block> rootBlock = std::make_unique<mlir::Block>();
797  rootBlock->push_back(omega);
798  auto rvsdgModule = jlm::mlir::MlirToJlmConverter::CreateAndConvert(rootBlock);
799  auto region = &rvsdgModule->Rvsdg().GetRootRegion();
800 
801  {
802  using namespace jlm::rvsdg;
803 
804  EXPECT_EQ(region->numNodes(), 1);
805 
806  // Get the lambda block
807  auto convertedLambda =
808  jlm::util::assertedCast<jlm::rvsdg::LambdaNode>(region->Nodes().begin().ptr());
809  EXPECT_TRUE(is<jlm::llvm::LlvmLambdaOperation>(convertedLambda->GetOperation()));
810 
811  auto lambdaRegion = convertedLambda->subregion();
812 
813  // 2 constants + gamma
814  EXPECT_EQ(lambdaRegion->numNodes(), 3);
815 
816  auto gammaNode = &jlm::rvsdg::AssertGetOwnerNode<jlm::rvsdg::GammaNode>(
817  *lambdaRegion->result(0)->origin());
818 
819  std::cout << "Checking gamma operation" << std::endl;
820  auto gammaOp = dynamic_cast<const GammaOperation *>(&gammaNode->GetOperation());
821  EXPECT_EQ(gammaNode->ninputs(), 3);
822  EXPECT_EQ(gammaOp->nalternatives(), 3);
823  EXPECT_EQ(gammaNode->noutputs(), 2);
824  }
825  }
826 }
827 
833 TEST(MlirToJlmConverterTests, TestThetaOp)
834 {
835  {
836  using namespace mlir::rvsdg;
837  using namespace mlir::jlm;
838 
839  // Setup MLIR Context and load dialects
840  std::cout << "Creating MLIR context" << std::endl;
841  auto context = std::make_unique<mlir::MLIRContext>();
842  context->getOrLoadDialect<RVSDGDialect>();
843  context->getOrLoadDialect<JLMDialect>();
844  context->getOrLoadDialect<mlir::arith::ArithDialect>();
845  context->getOrLoadDialect<mlir::LLVM::LLVMDialect>();
846  auto Builder_ = std::make_unique<mlir::OpBuilder>(context.get());
847 
848  auto omega = Builder_->create<OmegaNode>(Builder_->getUnknownLoc());
849  auto & omegaRegion = omega.getRegion();
850  auto * omegaBlock = new mlir::Block;
851  omegaRegion.push_back(omegaBlock);
852 
853  // Add function attributes
854  std::cout << "Creating function attributes" << std::endl;
855  auto attributeName = Builder_->getStringAttr("sym_name");
856  auto attributeValue = Builder_->getStringAttr("test");
857  auto symbolName = Builder_->getNamedAttr(attributeName, attributeValue);
858 
859  auto iotype = Builder_->getType<IOStateEdgeType>();
860  auto memtype = Builder_->getType<MemStateEdgeType>();
861 
862  // Create the lambda node and add it to the region/block it resides in
863  std::cout << "Creating LambdaNode" << std::endl;
864  auto lambda = Builder_->create<LambdaNode>(
865  Builder_->getUnknownLoc(),
866  Builder_->getType<mlir::FunctionType>(
867  ::mlir::TypeRange({ iotype, memtype }),
868  ::mlir::TypeRange({ iotype, memtype })),
869  ::llvm::SmallVector<mlir::Value>(),
870  ::llvm::ArrayRef<::mlir::NamedAttribute>({ symbolName }));
871  omegaBlock->push_back(lambda);
872  auto & lambdaRegion = lambda.getRegion();
873  auto * lambdaBlock = new mlir::Block;
874  lambdaRegion.push_back(lambdaBlock);
875 
876  // Add arguments to the region
877  std::cout << "Adding arguments to the region" << std::endl;
878  lambdaBlock->addArgument(iotype, Builder_->getUnknownLoc());
879  lambdaBlock->addArgument(memtype, Builder_->getUnknownLoc());
880 
881  auto theta = Builder_->create<::mlir::rvsdg::ThetaNode>(
882  Builder_->getUnknownLoc(),
883  ::mlir::TypeRange({ iotype, memtype }), // Ouputs types
884  ::mlir::ValueRange({ lambdaBlock->getArgument(0), lambdaBlock->getArgument(1) }), // Inputs
885  ::llvm::SmallVector<::mlir::NamedAttribute>({}));
886  lambdaBlock->push_back(theta);
887 
888  auto & thetaBlock = theta.getRegion().emplaceBlock();
889  thetaBlock.addArgument(iotype, Builder_->getUnknownLoc());
890  thetaBlock.addArgument(memtype, Builder_->getUnknownLoc());
891  auto predicate = Builder_->create<mlir::rvsdg::ConstantCtrl>(
892  Builder_->getUnknownLoc(),
893  Builder_->getType<::mlir::rvsdg::RVSDG_CTRLType>(2),
894  0);
895  thetaBlock.push_back(predicate);
896 
897  auto thetaResult = Builder_->create<::mlir::rvsdg::ThetaResult>(
898  Builder_->getUnknownLoc(),
899  predicate,
900  ::llvm::SmallVector<mlir::Value>(thetaBlock.getArguments()));
901  thetaBlock.push_back(thetaResult);
902 
903  // Handle the result of the lambda
904  ::llvm::SmallVector<mlir::Value> regionResults;
905  regionResults.push_back(theta->getResult(0));
906  regionResults.push_back(theta->getResult(1));
907  std::cout << "Creating LambdaResult" << std::endl;
908  auto lambdaResult = Builder_->create<LambdaResult>(Builder_->getUnknownLoc(), regionResults);
909  lambdaBlock->push_back(lambdaResult);
910 
911  // Handle the result of the omega
912  std::cout << "Creating OmegaResult" << std::endl;
913  ::llvm::SmallVector<mlir::Value> omegaRegionResults;
914  omegaRegionResults.push_back(lambda);
915  auto omegaResult = Builder_->create<OmegaResult>(Builder_->getUnknownLoc(), omegaRegionResults);
916  omegaBlock->push_back(omegaResult);
917 
918  // Convert the MLIR to RVSDG and check the result
919  std::cout << "Converting MLIR to RVSDG" << std::endl;
920  std::unique_ptr<mlir::Block> rootBlock = std::make_unique<mlir::Block>();
921  rootBlock->push_back(omega);
922  auto rvsdgModule = jlm::mlir::MlirToJlmConverter::CreateAndConvert(rootBlock);
923  auto region = &rvsdgModule->Rvsdg().GetRootRegion();
924 
925  {
926  using namespace jlm::rvsdg;
927 
928  EXPECT_EQ(region->numNodes(), 1);
929 
930  // Get the lambda block
931  auto convertedLambda =
932  jlm::util::assertedCast<jlm::rvsdg::LambdaNode>(region->Nodes().begin().ptr());
933  EXPECT_TRUE(is<jlm::llvm::LlvmLambdaOperation>(convertedLambda->GetOperation()));
934 
935  auto lambdaRegion = convertedLambda->subregion();
936 
937  // Just the theta node
938  EXPECT_EQ(lambdaRegion->numNodes(), 1);
939 
940  auto thetaNode = &jlm::rvsdg::AssertGetOwnerNode<jlm::rvsdg::ThetaNode>(
941  *lambdaRegion->result(0)->origin());
942 
943  std::cout << "Checking theta node" << std::endl;
944  EXPECT_EQ(thetaNode->ninputs(), 2);
945  EXPECT_EQ(thetaNode->GetLoopVars().size(), 2);
946  EXPECT_EQ(thetaNode->noutputs(), 2);
947  EXPECT_EQ(thetaNode->nsubregions(), 1);
948  EXPECT_TRUE(is<jlm::rvsdg::ControlType>(thetaNode->predicate()->Type()));
949  auto predicateType =
950  std::dynamic_pointer_cast<const ControlType>(thetaNode->predicate()->Type());
951  EXPECT_EQ(predicateType->nalternatives(), 2);
952  std::cout << predicate.getValue() << std::endl;
953  }
954  }
955 }
TEST(MlirToJlmConverterTests, TestLambda)
const rvsdg::BitType & Type() const noexcept
static std::unique_ptr< llvm::LlvmRvsdgModule > CreateAndConvert(std::unique_ptr<::mlir::Block > &block)
size_t nbits() const noexcept
Definition: type.hpp:26
Output * origin() const noexcept
Definition: node.hpp:58
Lambda node.
Definition: lambda.hpp:83
Node * node() const noexcept
Definition: node.hpp:572
virtual const Operation & GetOperation() const noexcept=0
NodeInput * input(size_t index) const noexcept
Definition: node.hpp:615
size_t ninputs() const noexcept
Definition: node.hpp:609
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition: node.hpp:366
Represents the argument of a region.
Definition: region.hpp:41
std::string view(const rvsdg::Region *region)
Definition: view.cpp:142