Jlm
RvsdgToIpGraphConverter.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2025 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
16 #include <jlm/rvsdg/delta.hpp>
17 #include <jlm/rvsdg/gamma.hpp>
18 #include <jlm/rvsdg/Phi.hpp>
19 #include <jlm/rvsdg/traverser.hpp>
20 #include <jlm/util/Statistics.hpp>
21 #include <jlm/util/time.hpp>
22 
23 #include <vector>
24 
25 namespace jlm::llvm
26 {
27 
29 {
30 public:
31  explicit Context(InterProceduralGraphModule & ipGraphModule)
32  : ControlFlowGraph_(nullptr),
33  IPGraphModule_(ipGraphModule),
35  {}
36 
37  Context(const Context &) = delete;
38 
39  Context(Context &&) = delete;
40 
41  Context &
42  operator=(const Context &) = delete;
43 
44  Context &
45  operator=(Context &&) = delete;
46 
47  [[nodiscard]] InterProceduralGraphModule &
48  GetIpGraphModule() const noexcept
49  {
50  return IPGraphModule_;
51  }
52 
53  void
54  InsertVariable(const rvsdg::Output * output, const llvm::Variable * variable)
55  {
56  JLM_ASSERT(VariableMap_.find(output) == VariableMap_.end());
57  JLM_ASSERT(*output->Type() == *variable->Type());
58  VariableMap_[output] = variable;
59  }
60 
61  const llvm::Variable *
62  GetVariable(const rvsdg::Output * output)
63  {
64  const auto it = VariableMap_.find(output);
65  JLM_ASSERT(it != VariableMap_.end());
66  return it->second;
67  }
68 
69  BasicBlock *
70  GetLastProcessedBasicBlock() const noexcept
71  {
73  }
74 
75  void
76  SetLastProcessedBasicBlock(BasicBlock * lastProcessedBasicBlock) noexcept
77  {
78  LastProcessedBasicBlock = lastProcessedBasicBlock;
79  }
80 
82  GetControlFlowGraph() const noexcept
83  {
84  return ControlFlowGraph_;
85  }
86 
87  void
89  {
90  ControlFlowGraph_ = cfg;
91  }
92 
93  static std::unique_ptr<Context>
95  {
96  return std::make_unique<Context>(ipGraphModule);
97  }
98 
99 private:
103  std::unordered_map<const rvsdg::Output *, const llvm::Variable *> VariableMap_;
104 };
105 
107 {
108 public:
109  ~Statistics() override = default;
110 
111  explicit Statistics(const util::FilePath & filename)
112  : util::Statistics(Id::RvsdgDestruction, filename)
113  {}
114 
115  void
116  Start(const rvsdg::Graph & graph) noexcept
117  {
118  AddMeasurement(Label::NumRvsdgNodes, rvsdg::nnodes(&graph.GetRootRegion()));
120  }
121 
122  void
124  {
127  }
128 
129  static std::unique_ptr<Statistics>
130  Create(const util::FilePath & sourceFile)
131  {
132  return std::make_unique<Statistics>(sourceFile);
133  }
134 };
135 
137 
139 
142 {
143  const auto variable = Context_->GetVariable(&output);
144  if (const auto functionVariable = dynamic_cast<const FunctionVariable *>(variable))
145  {
146  return *functionVariable->function();
147  }
148 
149  if (const auto globalValue = dynamic_cast<const GlobalValue *>(variable))
150  {
151  return *globalValue->node();
152  }
153 
154  throw std::logic_error("Unhandled variable type.");
155 }
156 
157 std::unique_ptr<DataNodeInit>
159 {
160  const auto subregion = deltaNode.subregion();
161 
162  // add delta dependencies to context
163  for (size_t n = 0; n < deltaNode.ninputs(); n++)
164  {
165  const auto variable = Context_->GetVariable(deltaNode.input(n)->origin());
166  Context_->InsertVariable(deltaNode.input(n)->arguments.first(), variable);
167  }
168 
169  if (subregion->numNodes() == 0)
170  {
171  auto value = Context_->GetVariable(subregion->result(0)->origin());
172  return std::make_unique<DataNodeInit>(value);
173  }
174 
175  tacsvector_t tacs;
176  for (const auto & node : rvsdg::TopDownTraverser(deltaNode.subregion()))
177  {
178  JLM_ASSERT(node->noutputs() == 1);
179  const auto output = node->output(0);
180 
181  // collect operand variables
182  std::vector<const Variable *> operands;
183  for (size_t n = 0; n < node->ninputs(); n++)
184  operands.push_back(Context_->GetVariable(node->input(n)->origin()));
185 
186  // convert node to tac
187  auto op = node->GetOperation().copy();
188  tacs.push_back(ThreeAddressCode::create(
189  std::unique_ptr<rvsdg::SimpleOperation>(
190  util::assertedCast<rvsdg::SimpleOperation>(op.release())),
191  operands));
192  Context_->InsertVariable(output, tacs.back()->result(0));
193  }
194 
195  return std::make_unique<DataNodeInit>(std::move(tacs));
196 }
197 
198 void
200 {
201  const auto entryBlock = BasicBlock::create(*Context_->GetControlFlowGraph());
202  Context_->GetLastProcessedBasicBlock()->add_outedge(entryBlock);
203  Context_->SetLastProcessedBasicBlock(entryBlock);
204 
205  for (const auto & node : rvsdg::TopDownTraverser(&region))
206  ConvertNode(*node);
207 
208  const auto exitBlock = BasicBlock::create(*Context_->GetControlFlowGraph());
209  Context_->GetLastProcessedBasicBlock()->add_outedge(exitBlock);
210  Context_->SetLastProcessedBasicBlock(exitBlock);
211 }
212 
213 std::unique_ptr<ControlFlowGraph>
215 {
216  JLM_ASSERT(Context_->GetLastProcessedBasicBlock() == nullptr);
217  const auto & lambdaOperation = *util::assertedCast<LlvmLambdaOperation>(&lambda.GetOperation());
218 
219  auto controlFlowGraph = ControlFlowGraph::create(Context_->GetIpGraphModule());
220  const auto entryBlock = BasicBlock::create(*controlFlowGraph);
221  controlFlowGraph->exit()->divert_inedges(entryBlock);
222  Context_->SetLastProcessedBasicBlock(entryBlock);
223  Context_->SetControlFlowGraph(controlFlowGraph.get());
224 
225  // add function arguments
226  for (const auto functionArgument : lambda.GetFunctionArguments())
227  {
228  auto name = util::strfmt("_a", functionArgument->index(), "_");
229  auto argument = Argument::create(
230  name,
231  functionArgument->Type(),
232  lambdaOperation.GetArgumentAttributes(functionArgument->index()));
233  const auto variable = controlFlowGraph->entry()->append_argument(std::move(argument));
234  Context_->InsertVariable(functionArgument, variable);
235  }
236 
237  // add context variables
238  for (const auto & [input, inner] : lambda.GetContextVars())
239  {
240  const auto variable = Context_->GetVariable(input->origin());
241  Context_->InsertVariable(inner, variable);
242  }
243 
244  ConvertRegion(*lambda.subregion());
245 
246  // add results
247  for (const auto result : lambda.GetFunctionResults())
248  controlFlowGraph->exit()->append_result(Context_->GetVariable(result->origin()));
249 
250  Context_->GetLastProcessedBasicBlock()->add_outedge(controlFlowGraph->exit());
251  Context_->SetLastProcessedBasicBlock(nullptr);
252  Context_->SetControlFlowGraph(nullptr);
253 
254  straighten(*controlFlowGraph);
255  JLM_ASSERT(is_closed(*controlFlowGraph));
256  return controlFlowGraph;
257 }
258 
259 void
261 {
262  std::vector<const Variable *> operands;
263  for (size_t n = 0; n < simpleNode.ninputs(); n++)
264  operands.push_back(Context_->GetVariable(simpleNode.input(n)->origin()));
265 
266  auto operation = simpleNode.GetOperation().copy();
267  Context_->GetLastProcessedBasicBlock()->append_last(ThreeAddressCode::create(
268  std::unique_ptr<rvsdg::SimpleOperation>(
269  util::assertedCast<rvsdg::SimpleOperation>(operation.release())),
270  operands));
271 
272  for (size_t n = 0; n < simpleNode.noutputs(); n++)
273  Context_->InsertVariable(
274  simpleNode.output(n),
275  Context_->GetLastProcessedBasicBlock()->last()->result(n));
276 }
277 
278 void
280 {
281  const auto numSubregions = gammaNode.nsubregions();
282  const auto predicate = gammaNode.predicate()->origin();
283  const auto controlFlowGraph = Context_->GetControlFlowGraph();
284 
285  const auto entryBlock = BasicBlock::create(*controlFlowGraph);
286  const auto exitBlock = BasicBlock::create(*controlFlowGraph);
287  Context_->GetLastProcessedBasicBlock()->add_outedge(entryBlock);
288 
289  // convert gamma regions
290  std::vector<ControlFlowGraphNode *> phi_nodes;
291  entryBlock->append_last(BranchOperation::create(numSubregions, Context_->GetVariable(predicate)));
292  auto entryvars = gammaNode.GetEntryVars();
293  for (size_t n = 0; n < gammaNode.nsubregions(); n++)
294  {
295  const auto subregion = gammaNode.subregion(n);
296 
297  // add arguments to context
298  for (size_t i = 0; i < entryvars.size(); i++)
299  {
300  auto & entryvar = entryvars[i];
301  Context_->InsertVariable(
302  entryvar.branchArgument[n],
303  Context_->GetVariable(entryvar.input->origin()));
304  }
305 
306  // convert subregion
307  const auto regionEntryBlock = BasicBlock::create(*controlFlowGraph);
308  entryBlock->add_outedge(regionEntryBlock);
309  Context_->SetLastProcessedBasicBlock(regionEntryBlock);
310  ConvertRegion(*subregion);
311 
312  phi_nodes.push_back(Context_->GetLastProcessedBasicBlock());
313  Context_->GetLastProcessedBasicBlock()->add_outedge(exitBlock);
314  }
315 
316  // add phi instructions
317  for (size_t n = 0; n < gammaNode.noutputs(); n++)
318  {
319  const auto output = gammaNode.output(n);
320 
321  bool invariant = true;
322  std::vector<std::pair<const Variable *, ControlFlowGraphNode *>> arguments;
323  for (size_t r = 0; r < gammaNode.nsubregions(); r++)
324  {
325  const auto origin = gammaNode.subregion(r)->result(n)->origin();
326 
327  auto v = Context_->GetVariable(origin);
328  arguments.push_back(std::make_pair(v, phi_nodes[r]));
329  invariant &= (v == Context_->GetVariable(gammaNode.subregion(0)->result(n)->origin()));
330  }
331 
332  if (invariant)
333  {
334  // all operands are the same
335  Context_->InsertVariable(output, arguments[0].first);
336  continue;
337  }
338 
339  // create phi instruction
340  exitBlock->append_last(SsaPhiOperation::create(arguments, output->Type()));
341  Context_->InsertVariable(output, exitBlock->last()->result(0));
342  }
343 
344  Context_->SetLastProcessedBasicBlock(exitBlock);
345 }
346 
347 bool
349 {
350  if (ThetaLoopVarIsInvariant(loopVar))
351  return false;
352 
353  if (loopVar.pre->nusers() == 0)
354  return false;
355 
356  return true;
357 }
358 
359 void
361 {
362  const auto subregion = thetaNode.subregion();
363  const auto predicate = subregion->result(0)->origin();
364 
365  auto preEntryBlock = Context_->GetLastProcessedBasicBlock();
366  const auto entryBlock = BasicBlock::create(*Context_->GetControlFlowGraph());
367  preEntryBlock->add_outedge(entryBlock);
368  Context_->SetLastProcessedBasicBlock(entryBlock);
369 
370  // create SSA phi nodes in entry block and add arguments to context
371  std::vector<llvm::ThreeAddressCode *> phis;
372  for (const auto & loopVar : thetaNode.GetLoopVars())
373  {
374  auto variable = Context_->GetVariable(loopVar.input->origin());
375  if (RequiresSsaPhiOperation(loopVar))
376  {
377  auto phi = entryBlock->append_last(SsaPhiOperation::create({}, loopVar.pre->Type()));
378  phis.push_back(phi);
379  variable = phi->result(0);
380  }
381  Context_->InsertVariable(loopVar.pre, variable);
382  }
383 
384  ConvertRegion(*subregion);
385 
386  // add phi operands and results to context
387  size_t phiIndex = 0;
388  for (const auto & loopVar : thetaNode.GetLoopVars())
389  {
390  auto resultVariable = Context_->GetVariable(loopVar.post->origin());
391  Context_->InsertVariable(loopVar.output, resultVariable);
392  if (RequiresSsaPhiOperation(loopVar))
393  {
394  auto entryVariable = Context_->GetVariable(loopVar.input->origin());
395  const auto phi = phis[phiIndex++];
396  phi->replace(
398  { preEntryBlock, Context_->GetLastProcessedBasicBlock() },
399  resultVariable->Type()),
400  { entryVariable, resultVariable });
401  }
402  }
403  JLM_ASSERT(phiIndex == phis.size());
404 
405  Context_->GetLastProcessedBasicBlock()->append_last(
406  BranchOperation::create(2, Context_->GetVariable(predicate)));
407  const auto exitBlock = BasicBlock::create(*Context_->GetControlFlowGraph());
408  Context_->GetLastProcessedBasicBlock()->add_outedge(exitBlock);
409  Context_->GetLastProcessedBasicBlock()->add_outedge(entryBlock);
410  Context_->SetLastProcessedBasicBlock(exitBlock);
411 }
412 
413 void
415 {
416  auto & ipGraphModule = Context_->GetIpGraphModule();
417  auto & ipGraph = ipGraphModule.ipgraph();
418 
419  const auto & operation = *util::assertedCast<LlvmLambdaOperation>(&lambdaNode.GetOperation());
420  const auto functionNode = FunctionNode::create(
421  ipGraph,
422  operation.name(),
423  operation.Type(),
424  operation.linkage(),
425  operation.callingConvention(),
426  operation.attributes());
427  functionNode->add_cfg(CreateControlFlowGraph(lambdaNode));
428 
429  for (auto [input, _] : lambdaNode.GetContextVars())
430  {
431  auto & ipGraphNode = getInterProceduralGraphNode(*input->origin());
432  functionNode->add_dependency(&ipGraphNode);
433  }
434 
435  const auto variable = ipGraphModule.create_variable(functionNode);
436  Context_->InsertVariable(lambdaNode.output(), variable);
437 }
438 
439 void
441 {
442  const auto subregion = phiNode.subregion();
443  auto & ipGraphModule = Context_->GetIpGraphModule();
444  auto & ipGraph = ipGraphModule.ipgraph();
445 
446  // add dependencies to context
447  for (size_t n = 0; n < phiNode.ninputs(); n++)
448  {
449  const auto variable = Context_->GetVariable(phiNode.input(n)->origin());
450  Context_->InsertVariable(phiNode.input(n)->arguments.first(), variable);
451  }
452 
453  // forward declare all functions and global variables
454  for (size_t n = 0; n < subregion->nresults(); n++)
455  {
456  JLM_ASSERT(subregion->argument(n)->input() == nullptr);
457  const auto & origin = *subregion->result(n)->origin();
458 
459  if (const auto lambdaNode = rvsdg::TryGetOwnerNode<rvsdg::LambdaNode>(origin))
460  {
461  const auto & lambdaOperation =
462  dynamic_cast<LlvmLambdaOperation &>(lambdaNode->GetOperation());
463  const auto functionNode = FunctionNode::create(
464  ipGraph,
465  lambdaOperation.name(),
466  lambdaOperation.Type(),
467  lambdaOperation.linkage(),
468  lambdaOperation.callingConvention(),
469  lambdaOperation.attributes());
470  Context_->InsertVariable(subregion->argument(n), ipGraphModule.create_variable(functionNode));
471  }
472  else if (const auto deltaNode = rvsdg::TryGetOwnerNode<rvsdg::DeltaNode>(origin))
473  {
474  auto op = util::assertedCast<const llvm::DeltaOperation>(&deltaNode->GetOperation());
475  const auto dataNode = DataNode::Create(
476  ipGraph,
477  op->name(),
478  op->Type(),
479  op->linkage(),
480  op->Section(),
481  op->constant(),
482  op->getAlignment());
483  Context_->InsertVariable(subregion->argument(n), ipGraphModule.create_global_value(dataNode));
484  }
485  else
486  {
488  "Unhandled node type: ",
489  rvsdg::AssertGetOwnerNode<rvsdg::Node>(origin).DebugString())
490  .c_str());
491  }
492  }
493 
494  // convert function bodies and global variable initializations
495  for (size_t n = 0; n < subregion->nresults(); n++)
496  {
497  JLM_ASSERT(subregion->argument(n)->input() == nullptr);
498  const auto result = subregion->result(n);
499  const auto & origin = *result->origin();
500 
501  if (const auto lambdaNode = rvsdg::TryGetOwnerNode<rvsdg::LambdaNode>(origin))
502  {
503  const auto variable =
504  util::assertedCast<const FunctionVariable>(Context_->GetVariable(subregion->argument(n)));
505  variable->function()->add_cfg(CreateControlFlowGraph(*lambdaNode));
506  Context_->InsertVariable(lambdaNode->output(), variable);
507 
508  for (auto [input, _] : lambdaNode->GetContextVars())
509  {
510  auto & ipGraphNode = getInterProceduralGraphNode(*input->origin());
511  variable->function()->add_dependency(&ipGraphNode);
512  }
513  }
514  else if (const auto deltaNode = rvsdg::TryGetOwnerNode<rvsdg::DeltaNode>(origin))
515  {
516  const auto variable =
517  util::assertedCast<const GlobalValue>(Context_->GetVariable(subregion->argument(n)));
518  variable->node()->set_initialization(CreateInitialization(*deltaNode));
519  Context_->InsertVariable(&deltaNode->output(), variable);
520 
521  for (auto & [input, _] : deltaNode->GetContextVars())
522  {
523  auto & ipGraphNode = getInterProceduralGraphNode(*input->origin());
524  variable->node()->add_dependency(&ipGraphNode);
525  }
526  }
527  else
528  {
530  "Unhandled node type: ",
531  rvsdg::AssertGetOwnerNode<rvsdg::Node>(origin).DebugString())
532  .c_str());
533  }
534  }
535 
536  // add functions and globals to context
537  JLM_ASSERT(phiNode.noutputs() == subregion->nresults());
538  for (size_t n = 0; n < phiNode.noutputs(); n++)
539  Context_->InsertVariable(
540  phiNode.output(n),
541  Context_->GetVariable(subregion->result(n)->origin()));
542 }
543 
544 void
546 {
547  auto & ipGraphModule = Context_->GetIpGraphModule();
548 
549  auto op = util::assertedCast<const llvm::DeltaOperation>(&deltaNode.GetOperation());
550 
551  const auto dataNode = DataNode::Create(
552  ipGraphModule.ipgraph(),
553  op->name(),
554  op->Type(),
555  op->linkage(),
556  op->Section(),
557  op->constant(),
558  op->getAlignment());
559  dataNode->set_initialization(CreateInitialization(deltaNode));
560 
561  for (auto & [input, _] : deltaNode.GetContextVars())
562  {
563  auto & ipGraphNode = getInterProceduralGraphNode(*input->origin());
564  dataNode->add_dependency(&ipGraphNode);
565  }
566 
567  const auto variable = ipGraphModule.create_global_value(dataNode);
568  Context_->InsertVariable(&deltaNode.output(), variable);
569 }
570 
571 void
573 {
574  if (const auto lambdaNode = dynamic_cast<const rvsdg::LambdaNode *>(&node))
575  {
576  ConvertLambdaNode(*lambdaNode);
577  }
578  else if (const auto gammaNode = dynamic_cast<const rvsdg::GammaNode *>(&node))
579  {
580  ConvertGammaNode(*gammaNode);
581  }
582  else if (const auto thetaNode = dynamic_cast<const rvsdg::ThetaNode *>(&node))
583  {
584  ConvertThetaNode(*thetaNode);
585  }
586  else if (const auto phiNode = dynamic_cast<const rvsdg::PhiNode *>(&node))
587  {
588  ConvertPhiNode(*phiNode);
589  }
590  else if (const auto deltaNode = dynamic_cast<const rvsdg::DeltaNode *>(&node))
591  {
592  ConvertDeltaNode(*deltaNode);
593  }
594  else if (const auto simpleNode = dynamic_cast<const rvsdg::SimpleNode *>(&node))
595  {
596  ConvertSimpleNode(*simpleNode);
597  }
598  else
599  {
600  JLM_UNREACHABLE(util::strfmt("Unhandled node type: ", node.DebugString()).c_str());
601  }
602 }
603 
604 void
606 {
607  for (const auto & node : rvsdg::TopDownTraverser(&graph.GetRootRegion()))
608  {
609  ConvertNode(*node);
610  }
611 }
612 
613 void
615 {
616  auto & ipGraphModule = Context_->GetIpGraphModule();
617  auto & ipGraph = ipGraphModule.ipgraph();
618 
619  for (size_t n = 0; n < graph.GetRootRegion().narguments(); n++)
620  {
621  const auto graphImport = util::assertedCast<LlvmGraphImport>(graph.GetRootRegion().argument(n));
622  if (const auto functionType =
623  std::dynamic_pointer_cast<const rvsdg::FunctionType>(graphImport->ValueType()))
624  {
625  const auto functionNode = FunctionNode::create(
626  ipGraph,
627  graphImport->Name(),
628  functionType,
629  graphImport->linkage(),
630  graphImport->callingConvention(),
631  {});
632  const auto variable = ipGraphModule.create_variable(functionNode);
633  Context_->InsertVariable(graphImport, variable);
634  }
635  else
636  {
637  const auto dataNode = DataNode::Create(
638  ipGraph,
639  graphImport->Name(),
640  graphImport->ValueType(),
641  graphImport->linkage(),
642  "",
643  graphImport->isConstant(),
644  graphImport->getAlignment());
645  const auto variable = ipGraphModule.create_global_value(dataNode);
646  Context_->InsertVariable(graphImport, variable);
647  }
648  }
649 }
650 
651 std::unique_ptr<InterProceduralGraphModule>
653  LlvmRvsdgModule & rvsdgModule,
655 {
656  auto statistics = Statistics::Create(rvsdgModule.SourceFileName());
657  statistics->Start(rvsdgModule.Rvsdg());
658 
659  // LLVM expects that we do not create any phi instructions for invariant values
660  // through theta and gamma nodes. This leads otherwise to compilation problems (and not just
661  // performance issues). For example, a direct call in a nested loop would all in a sudden be
662  // considered an indirect call as it would take as its function input the phi instruction, but
663  // not the function itself. See the NestedLoopWithCall test in the RvsdgToIpGraphConverterTests
664  // suite. We simply avoid this problem by removing all invariant theta/gamma values from the RVSDG
665  // using invariant value redirection before converting it to a control flow graph.
666  constexpr InvariantValueRedirection::Configuration configuration{
667  true, // enableGammaOutputRedirection
668  true, // enableThetaOutputRedirection
669  false, // enableThetaGammaCorrelationRedirection
670  false, // enableCallOutputRedirection
671  false // enableLoadMemoryStateRedirection
672  };
673  InvariantValueRedirection::createAndRun(rvsdgModule, std::move(configuration));
674 
675  auto ipGraphModule = InterProceduralGraphModule::create(
676  rvsdgModule.SourceFileName(),
677  rvsdgModule.TargetTriple(),
678  rvsdgModule.DataLayout());
679 
680  Context_ = Context::Create(*ipGraphModule);
681  ConvertImports(rvsdgModule.Rvsdg());
682  ConvertNodes(rvsdgModule.Rvsdg());
683 
684  statistics->End(*ipGraphModule);
685  statisticsCollector.CollectDemandedStatistics(std::move(statistics));
686 
687  return ipGraphModule;
688 }
689 
690 std::unique_ptr<InterProceduralGraphModule>
692  LlvmRvsdgModule & rvsdgModule,
694 {
695  RvsdgToIpGraphConverter converter;
696  return converter.ConvertModule(rvsdgModule, statisticsCollector);
697 }
698 
699 }
static jlm::util::StatisticsCollector statisticsCollector
static std::unique_ptr< Argument > create(const std::string &name, std::shared_ptr< const jlm::rvsdg::Type > type, const AttributeSet &attributes)
Definition: cfg.hpp:59
static BasicBlock * create(ControlFlowGraph &cfg)
Definition: basic-block.cpp:37
static std::unique_ptr< llvm::ThreeAddressCode > create(size_t nalternatives, const Variable *operand)
Definition: operators.hpp:420
static std::unique_ptr< ControlFlowGraph > create(InterProceduralGraphModule &im)
Definition: cfg.hpp:267
static DataNode * Create(InterProceduralGraph &clg, const std::string &name, std::shared_ptr< const jlm::rvsdg::Type > valueType, const llvm::Linkage &linkage, std::string section, const bool constant, const size_t alignment)
Definition: ipgraph.hpp:431
static FunctionNode * create(InterProceduralGraph &ipg, const std::string &name, std::shared_ptr< const rvsdg::FunctionType > type, const llvm::Linkage &linkage, const CallingConvention &callingConvention, const AttributeSet &attributes)
Definition: ipgraph.hpp:242
static std::unique_ptr< InterProceduralGraphModule > create(const jlm::util::FilePath &sourceFilename, const std::string &targetTriple, const std::string &dataLayout)
static void createAndRun(rvsdg::RvsdgModule &rvsdgModule, Configuration configuration)
Lambda operation.
Definition: lambda.hpp:30
const util::FilePath & SourceFileName() const noexcept
const std::string & TargetTriple() const noexcept
const std::string & DataLayout() const noexcept
const llvm::Variable * GetVariable(const rvsdg::Output *output)
void InsertVariable(const rvsdg::Output *output, const llvm::Variable *variable)
ControlFlowGraph * GetControlFlowGraph() const noexcept
std::unordered_map< const rvsdg::Output *, const llvm::Variable * > VariableMap_
BasicBlock * GetLastProcessedBasicBlock() const noexcept
Context & operator=(const Context &)=delete
Context & operator=(Context &&)=delete
Context(InterProceduralGraphModule &ipGraphModule)
void SetControlFlowGraph(ControlFlowGraph *cfg) noexcept
InterProceduralGraphModule & GetIpGraphModule() const noexcept
void SetLastProcessedBasicBlock(BasicBlock *lastProcessedBasicBlock) noexcept
static std::unique_ptr< Context > Create(InterProceduralGraphModule &ipGraphModule)
void Start(const rvsdg::Graph &graph) noexcept
static std::unique_ptr< Statistics > Create(const util::FilePath &sourceFile)
void End(const InterProceduralGraphModule &im)
std::unique_ptr< DataNodeInit > CreateInitialization(const rvsdg::DeltaNode &deltaNode)
InterProceduralGraphNode & getInterProceduralGraphNode(const rvsdg::Output &output) const
std::unique_ptr< InterProceduralGraphModule > ConvertModule(LlvmRvsdgModule &rvsdgModule, util::StatisticsCollector &statisticsCollector)
static std::unique_ptr< InterProceduralGraphModule > CreateAndConvertModule(LlvmRvsdgModule &rvsdgModule, util::StatisticsCollector &statisticsCollector)
void ConvertDeltaNode(const rvsdg::DeltaNode &deltaNode)
static bool RequiresSsaPhiOperation(const rvsdg::ThetaNode::LoopVar &loopVar)
void ConvertImports(const rvsdg::Graph &graph)
void ConvertNode(const rvsdg::Node &node)
void ConvertThetaNode(const rvsdg::ThetaNode &thetaNode)
void ConvertNodes(const rvsdg::Graph &graph)
void ConvertLambdaNode(const rvsdg::LambdaNode &lambdaNode)
void ConvertSimpleNode(const rvsdg::SimpleNode &simpleNode)
void ConvertGammaNode(const rvsdg::GammaNode &gammaNode)
void ConvertPhiNode(const rvsdg::PhiNode &phiNode)
std::unique_ptr< ControlFlowGraph > CreateControlFlowGraph(const rvsdg::LambdaNode &lambda)
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< std::pair< const Variable *, ControlFlowGraphNode * >> &arguments, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition: operators.hpp:76
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition: tac.hpp:135
const std::shared_ptr< const jlm::rvsdg::Type > Type() const noexcept
Definition: variable.hpp:62
Delta node.
Definition: delta.hpp:129
std::vector< ContextVar > GetContextVars() const noexcept
Gets all bound context variables.
Definition: delta.cpp:39
rvsdg::Region * subregion() const noexcept
Definition: delta.hpp:234
const DeltaOperation & GetOperation() const noexcept override
Definition: delta.cpp:71
rvsdg::Output & output() const noexcept
Definition: delta.cpp:110
Conditional operator / pattern matching.
Definition: gamma.hpp:99
std::vector< EntryVar > GetEntryVars() const
Gets all entry variables for this gamma.
Definition: gamma.cpp:305
rvsdg::Input * predicate() const noexcept
Definition: gamma.hpp:487
Region & GetRootRegion() const noexcept
Definition: graph.hpp:99
Output * origin() const noexcept
Definition: node.hpp:58
Lambda node.
Definition: lambda.hpp:83
std::vector< rvsdg::Output * > GetFunctionArguments() const
Definition: lambda.cpp:57
rvsdg::Region * subregion() const noexcept
Definition: lambda.hpp:138
std::vector< rvsdg::Input * > GetFunctionResults() const
Definition: lambda.cpp:69
rvsdg::Output * output() const noexcept
Definition: lambda.cpp:176
std::vector< ContextVar > GetContextVars() const noexcept
Gets all bound context variables.
Definition: lambda.cpp:119
LambdaOperation & GetOperation() const noexcept override
Definition: lambda.cpp:51
virtual std::string DebugString() const =0
size_t ninputs() const noexcept
Definition: node.hpp:609
size_t noutputs() const noexcept
Definition: node.hpp:644
virtual std::unique_ptr< Operation > copy() const =0
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition: node.hpp:366
size_t nusers() const noexcept
Definition: node.hpp:280
A phi node represents the fixpoint of mutually recursive definitions.
Definition: Phi.hpp:46
rvsdg::Region * subregion() const noexcept
Definition: Phi.hpp:320
Represent acyclic RVSDG subgraphs.
Definition: region.hpp:213
RegionResult * result(size_t index) const noexcept
Definition: region.hpp:471
RegionArgument * argument(size_t index) const noexcept
Definition: region.hpp:437
Graph & Rvsdg() noexcept
Definition: RvsdgModule.hpp:57
const SimpleOperation & GetOperation() const noexcept override
Definition: simple-node.cpp:48
NodeInput * input(size_t index) const noexcept
Definition: simple-node.hpp:82
NodeOutput * output(size_t index) const noexcept
Definition: simple-node.hpp:88
size_t nsubregions() const noexcept
StructuralOutput * output(size_t index) const noexcept
StructuralInput * input(size_t index) const noexcept
rvsdg::Region * subregion(size_t index) const noexcept
std::vector< LoopVar > GetLoopVars() const
Returns all loop variables.
Definition: theta.cpp:176
rvsdg::Region * subregion() const noexcept
Definition: theta.hpp:79
ElementType * first() const noexcept
void CollectDemandedStatistics(std::unique_ptr< Statistics > statistics)
Definition: Statistics.hpp:574
Statistics Interface.
Definition: Statistics.hpp:31
util::Timer & GetTimer(const std::string &name)
Definition: Statistics.cpp:137
util::Timer & AddTimer(std::string name)
Definition: Statistics.cpp:158
void AddMeasurement(std::string name, T value)
Definition: Statistics.hpp:177
void start() noexcept
Definition: time.hpp:54
void stop() noexcept
Definition: time.hpp:67
#define JLM_ASSERT(x)
Definition: common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition: common.hpp:43
Global memory state passed between functions.
std::vector< std::unique_ptr< llvm::ThreeAddressCode > > tacsvector_t
Definition: tac.hpp:202
void straighten(ControlFlowGraph &cfg)
size_t ntacs(const AggregationNode &root)
bool is_closed(const ControlFlowGraph &cfg)
static bool ThetaLoopVarIsInvariant(const ThetaNode::LoopVar &loopVar) noexcept
Definition: theta.hpp:227
size_t nnodes(const jlm::rvsdg::Region *region) noexcept
Definition: region.cpp:785
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
Definition: node.hpp:1049
static std::string strfmt(Args... args)
Definition: strfmt.hpp:35
Description of a loop-carried variable.
Definition: theta.hpp:50
rvsdg::Output * pre
Variable before iteration (input argument to subregion).
Definition: theta.hpp:58
static const char * NumRvsdgNodes
Definition: Statistics.hpp:213
static const char * NumThreeAddressCodes
Definition: Statistics.hpp:211
static const char * Timer
Definition: Statistics.hpp:251