Jlm
LlvmModuleConversion.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014 2015 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
23 
24 #include <llvm/ADT/PostOrderIterator.h>
25 #include <llvm/ADT/StringExtras.h>
26 #include <llvm/IR/BasicBlock.h>
27 #include <llvm/IR/Constants.h>
28 #include <llvm/IR/Function.h>
29 #include <llvm/IR/Instructions.h>
30 #include <llvm/IR/IntrinsicInst.h>
31 #include <llvm/IR/Intrinsics.h>
32 #include <llvm/IR/Module.h>
33 
34 namespace jlm::llvm
35 {
36 
38 
39 class Context final
40 {
41 public:
43  : module_(im),
44  node_(nullptr),
45  iostate_(nullptr),
46  memory_state_(nullptr)
47  {}
48 
49  const llvm::Variable *
50  result() const noexcept
51  {
52  return result_;
53  }
54 
55  inline void
57  {
58  result_ = result;
59  }
60 
62  iostate() const noexcept
63  {
64  return iostate_;
65  }
66 
67  void
69  {
70  iostate_ = state;
71  }
72 
73  inline llvm::Variable *
74  memory_state() const noexcept
75  {
76  return memory_state_;
77  }
78 
79  inline void
81  {
82  memory_state_ = state;
83  }
84 
85  inline bool
86  has(const ::llvm::BasicBlock * bb) const noexcept
87  {
88  return bbmap_.HasKey(bb);
89  }
90 
91  inline bool
92  has(BasicBlock * bb) const noexcept
93  {
94  return bbmap_.HasValue(bb);
95  }
96 
97  inline BasicBlock *
98  get(const ::llvm::BasicBlock * bb) const noexcept
99  {
100  return bbmap_.LookupKey(bb);
101  }
102 
103  inline const ::llvm::BasicBlock *
104  get(BasicBlock * bb) const noexcept
105  {
106  return bbmap_.LookupValue(bb);
107  }
108 
109  inline void
111  {
112  bbmap_ = std::move(bbmap);
113  }
114 
115  inline bool
116  has_value(const ::llvm::Value * value) const noexcept
117  {
118  return vmap_.find(value) != vmap_.end();
119  }
120 
121  inline const llvm::Variable *
122  lookup_value(const ::llvm::Value * value) const noexcept
123  {
124  JLM_ASSERT(has_value(value));
125  return vmap_.find(value)->second;
126  }
127 
128  inline void
129  insert_value(const ::llvm::Value * value, const llvm::Variable * variable)
130  {
131  JLM_ASSERT(!has_value(value));
132  vmap_[value] = variable;
133  }
134 
135  [[nodiscard]] InterProceduralGraphModule &
136  module() const noexcept
137  {
138  return module_;
139  }
140 
141  inline void
143  {
144  node_ = node;
145  }
146 
147  inline InterProceduralGraphNode *
148  node() const noexcept
149  {
150  return node_;
151  }
152 
153  TypeConverter &
154  GetTypeConverter() noexcept
155  {
156  return TypeConverter_;
157  }
158 
159 private:
166  std::unordered_map<const ::llvm::Value *, const llvm::Variable *> vmap_;
168 };
169 
170 static const Variable *
172  ::llvm::Constant *,
173  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> &,
174  Context &);
175 
176 static const Variable *
178  ::llvm::Instruction * instruction,
179  std::vector<std::unique_ptr<ThreeAddressCode>> & threeAddressCodes,
180  Context & context);
181 
182 // Converts a value into a variable either representing the llvm
183 // value or representing a function object.
184 // The distinction stems from the fact that llvm treats functions simply
185 // as pointers to the function code while we distinguish between the two.
186 // This function can return either and caller needs to check / adapt.
187 const Variable *
188 ConvertValueOrFunction(::llvm::Value * v, tacsvector_t & tacs, Context & ctx)
189 {
190  auto node = ctx.node();
191  if (node && ctx.has_value(v))
192  {
193  if (auto callee = dynamic_cast<const FunctionVariable *>(ctx.lookup_value(v)))
194  node->add_dependency(callee->function());
195 
196  if (auto data = dynamic_cast<const GlobalValue *>(ctx.lookup_value(v)))
197  node->add_dependency(data->node());
198  }
199 
200  if (ctx.has_value(v))
201  return ctx.lookup_value(v);
202 
203  if (auto c = ::llvm::dyn_cast<::llvm::Constant>(v))
204  return ConvertConstant(c, tacs, ctx);
205 
206  JLM_UNREACHABLE("This should not have happened!");
207 }
208 
209 // Converts a value into a variable representing the llvm value.
210 const Variable *
211 ConvertValue(::llvm::Value * v, tacsvector_t & tacs, Context & ctx)
212 {
213  const Variable * var = ConvertValueOrFunction(v, tacs, ctx);
214  if (auto fntype = std::dynamic_pointer_cast<const rvsdg::FunctionType>(var->Type()))
215  {
216  auto operation = std::make_unique<FunctionToPointerOperation>(fntype);
217  std::unique_ptr<ThreeAddressCode> ptr_cast =
218  ThreeAddressCode::create(std::move(operation), { var });
219  var = ptr_cast->result(0);
220  tacs.push_back(std::move(ptr_cast));
221  }
222  return var;
223 }
224 
226 convert_apint(const ::llvm::APInt & value)
227 {
228  ::llvm::APInt v;
229  if (value.isNegative())
230  v = -value;
231 
232  auto str = toString(value, 2, false);
233  std::reverse(str.begin(), str.end());
234 
235  rvsdg::BitValueRepresentation vr(str.c_str());
236  if (value.isNegative())
237  vr = vr.sext(value.getBitWidth() - str.size());
238  else
239  vr = vr.zext(value.getBitWidth() - str.size());
240 
241  return vr;
242 }
243 
245 ConvertAttributeKind(const ::llvm::Attribute::AttrKind & kind)
246 {
247  typedef ::llvm::Attribute::AttrKind ak;
248 
249  static std::unordered_map<::llvm::Attribute::AttrKind, Attribute::kind> map(
250  { { ak::None, Attribute::kind::None },
251  { ak::FirstEnumAttr, Attribute::kind::FirstEnumAttr },
252  { ak::AllocAlign, Attribute::kind::AllocAlign },
253  { ak::AllocatedPointer, Attribute::kind::AllocatedPointer },
254  { ak::AlwaysInline, Attribute::kind::AlwaysInline },
255  { ak::Builtin, Attribute::kind::Builtin },
256  { ak::Cold, Attribute::kind::Cold },
257  { ak::Convergent, Attribute::kind::Convergent },
258  { ak::CoroDestroyOnlyWhenComplete, Attribute::kind::CoroDestroyOnlyWhenComplete },
259  { ak::DeadOnUnwind, Attribute::kind::DeadOnUnwind },
260  { ak::DisableSanitizerInstrumentation, Attribute::kind::DisableSanitizerInstrumentation },
261  { ak::FnRetThunkExtern, Attribute::kind::FnRetThunkExtern },
262  { ak::Hot, Attribute::kind::Hot },
263  { ak::ImmArg, Attribute::kind::ImmArg },
264  { ak::InReg, Attribute::kind::InReg },
265  { ak::InlineHint, Attribute::kind::InlineHint },
266  { ak::JumpTable, Attribute::kind::JumpTable },
267  { ak::Memory, Attribute::kind::Memory },
268  { ak::MinSize, Attribute::kind::MinSize },
269  { ak::MustProgress, Attribute::kind::MustProgress },
270  { ak::Naked, Attribute::kind::Naked },
271  { ak::Nest, Attribute::kind::Nest },
272  { ak::NoAlias, Attribute::kind::NoAlias },
273  { ak::NoBuiltin, Attribute::kind::NoBuiltin },
274  { ak::NoCallback, Attribute::kind::NoCallback },
275  { ak::NoCapture, Attribute::kind::NoCapture },
276  { ak::NoCfCheck, Attribute::kind::NoCfCheck },
277  { ak::NoDuplicate, Attribute::kind::NoDuplicate },
278  { ak::NoFree, Attribute::kind::NoFree },
279  { ak::NoImplicitFloat, Attribute::kind::NoImplicitFloat },
280  { ak::NoInline, Attribute::kind::NoInline },
281  { ak::NoMerge, Attribute::kind::NoMerge },
282  { ak::NoProfile, Attribute::kind::NoProfile },
283  { ak::NoRecurse, Attribute::kind::NoRecurse },
284  { ak::NoRedZone, Attribute::kind::NoRedZone },
285  { ak::NoReturn, Attribute::kind::NoReturn },
286  { ak::NoSanitizeBounds, Attribute::kind::NoSanitizeBounds },
287  { ak::NoSanitizeCoverage, Attribute::kind::NoSanitizeCoverage },
288  { ak::NoSync, Attribute::kind::NoSync },
289  { ak::NoUndef, Attribute::kind::NoUndef },
290  { ak::NoUnwind, Attribute::kind::NoUnwind },
291  { ak::NonLazyBind, Attribute::kind::NonLazyBind },
292  { ak::NonNull, Attribute::kind::NonNull },
293  { ak::NullPointerIsValid, Attribute::kind::NullPointerIsValid },
294  { ak::OptForFuzzing, Attribute::kind::OptForFuzzing },
295  { ak::OptimizeForDebugging, Attribute::kind::OptimizeForDebugging },
296  { ak::OptimizeForSize, Attribute::kind::OptimizeForSize },
297  { ak::OptimizeNone, Attribute::kind::OptimizeNone },
298  { ak::PresplitCoroutine, Attribute::kind::PresplitCoroutine },
299  { ak::ReadNone, Attribute::kind::ReadNone },
300  { ak::ReadOnly, Attribute::kind::ReadOnly },
301  { ak::Returned, Attribute::kind::Returned },
302  { ak::ReturnsTwice, Attribute::kind::ReturnsTwice },
303  { ak::SExt, Attribute::kind::SExt },
304  { ak::SafeStack, Attribute::kind::SafeStack },
305  { ak::SanitizeAddress, Attribute::kind::SanitizeAddress },
306  { ak::SanitizeHWAddress, Attribute::kind::SanitizeHWAddress },
307  { ak::SanitizeMemTag, Attribute::kind::SanitizeMemTag },
308  { ak::SanitizeMemory, Attribute::kind::SanitizeMemory },
309  { ak::SanitizeThread, Attribute::kind::SanitizeThread },
310  { ak::ShadowCallStack, Attribute::kind::ShadowCallStack },
311  { ak::SkipProfile, Attribute::kind::SkipProfile },
312  { ak::Speculatable, Attribute::kind::Speculatable },
313  { ak::SpeculativeLoadHardening, Attribute::kind::SpeculativeLoadHardening },
314  { ak::StackProtect, Attribute::kind::StackProtect },
315  { ak::StackProtectReq, Attribute::kind::StackProtectReq },
316  { ak::StackProtectStrong, Attribute::kind::StackProtectStrong },
317  { ak::StrictFP, Attribute::kind::StrictFP },
318  { ak::SwiftAsync, Attribute::kind::SwiftAsync },
319  { ak::SwiftError, Attribute::kind::SwiftError },
320  { ak::SwiftSelf, Attribute::kind::SwiftSelf },
321  { ak::WillReturn, Attribute::kind::WillReturn },
322  { ak::Writable, Attribute::kind::Writable },
323  { ak::WriteOnly, Attribute::kind::WriteOnly },
324  { ak::ZExt, Attribute::kind::ZExt },
325  { ak::LastEnumAttr, Attribute::kind::LastEnumAttr },
326  { ak::FirstTypeAttr, Attribute::kind::FirstTypeAttr },
327  { ak::ByRef, Attribute::kind::ByRef },
328  { ak::ByVal, Attribute::kind::ByVal },
329  { ak::ElementType, Attribute::kind::ElementType },
330  { ak::InAlloca, Attribute::kind::InAlloca },
331  { ak::Preallocated, Attribute::kind::Preallocated },
332  { ak::StructRet, Attribute::kind::StructRet },
333  { ak::LastTypeAttr, Attribute::kind::LastTypeAttr },
334  { ak::FirstIntAttr, Attribute::kind::FirstIntAttr },
335  { ak::Alignment, Attribute::kind::Alignment },
336  { ak::AllocKind, Attribute::kind::AllocKind },
337  { ak::AllocSize, Attribute::kind::AllocSize },
338  { ak::Dereferenceable, Attribute::kind::Dereferenceable },
339  { ak::DereferenceableOrNull, Attribute::kind::DereferenceableOrNull },
340  { ak::NoFPClass, Attribute::kind::NoFPClass },
341  { ak::StackAlignment, Attribute::kind::StackAlignment },
342  { ak::UWTable, Attribute::kind::UWTable },
343  { ak::VScaleRange, Attribute::kind::VScaleRange },
344  { ak::LastIntAttr, Attribute::kind::LastIntAttr },
345  { ak::EndAttrKinds, Attribute::kind::EndAttrKinds } });
346 
347  JLM_ASSERT(map.find(kind) != map.end());
348  return map[kind];
349 }
350 
351 static EnumAttribute
352 ConvertEnumAttribute(const ::llvm::Attribute & attribute)
353 {
354  JLM_ASSERT(attribute.isEnumAttribute());
355  auto kind = ConvertAttributeKind(attribute.getKindAsEnum());
356  return EnumAttribute(kind);
357 }
358 
359 static IntAttribute
360 ConvertIntAttribute(const ::llvm::Attribute & attribute)
361 {
362  JLM_ASSERT(attribute.isIntAttribute());
363  auto kind = ConvertAttributeKind(attribute.getKindAsEnum());
364  return { kind, attribute.getValueAsInt() };
365 }
366 
367 static TypeAttribute
368 ConvertTypeAttribute(const ::llvm::Attribute & attribute, TypeConverter & typeConverter)
369 {
370  JLM_ASSERT(attribute.isTypeAttribute());
371 
372  if (attribute.getKindAsEnum() == ::llvm::Attribute::AttrKind::ByVal)
373  {
374  auto type = typeConverter.ConvertLlvmType(*attribute.getValueAsType());
375  return { Attribute::kind::ByVal, std::move(type) };
376  }
377 
378  if (attribute.getKindAsEnum() == ::llvm::Attribute::AttrKind::StructRet)
379  {
380  auto type = typeConverter.ConvertLlvmType(*attribute.getValueAsType());
381  return { Attribute::kind::StructRet, std::move(type) };
382  }
383 
384  JLM_UNREACHABLE("Unhandled attribute");
385 }
386 
387 static StringAttribute
388 ConvertStringAttribute(const ::llvm::Attribute & attribute)
389 {
390  JLM_ASSERT(attribute.isStringAttribute());
391  return { attribute.getKindAsString().str(), attribute.getValueAsString().str() };
392 }
393 
394 static AttributeSet
395 convert_attributes(const ::llvm::AttributeSet & as, TypeConverter & typeConverter)
396 {
397  AttributeSet attributeSet;
398  for (auto & attribute : as)
399  {
400  if (attribute.isEnumAttribute())
401  {
402  attributeSet.InsertEnumAttribute(ConvertEnumAttribute(attribute));
403  }
404  else if (attribute.isIntAttribute())
405  {
406  attributeSet.InsertIntAttribute(ConvertIntAttribute(attribute));
407  }
408  else if (attribute.isTypeAttribute())
409  {
410  attributeSet.InsertTypeAttribute(ConvertTypeAttribute(attribute, typeConverter));
411  }
412  else if (attribute.isStringAttribute())
413  {
414  attributeSet.InsertStringAttribute(ConvertStringAttribute(attribute));
415  }
416  else
417  {
418  JLM_UNREACHABLE("Unhandled attribute");
419  }
420  }
421 
422  return attributeSet;
423 }
424 
425 AttributeList
427  const ::llvm::AttributeList & attributeList,
428  const size_t numParameters,
429  TypeConverter & typeConverter)
430 {
431  auto returnAttributes = convert_attributes(attributeList.getRetAttrs(), typeConverter);
432  auto functionAttributes = convert_attributes(attributeList.getFnAttrs(), typeConverter);
433 
434  std::vector<AttributeSet> parameterAttributes;
435  for (size_t n = 0; n < numParameters; n++)
436  {
437  parameterAttributes.emplace_back(
438  convert_attributes(attributeList.getParamAttrs(n), typeConverter));
439  }
440 
441  return AttributeList(
442  std::move(functionAttributes),
443  std::move(returnAttributes),
444  std::move(parameterAttributes));
445 }
446 
447 static const Variable *
449  ::llvm::Constant * c,
450  std::vector<std::unique_ptr<ThreeAddressCode>> & tacs,
451  Context &)
452 {
453  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantIntVal);
454  const auto constant = ::llvm::cast<const ::llvm::ConstantInt>(c);
455 
456  const auto v = convert_apint(constant->getValue());
457  tacs.push_back(
458  ThreeAddressCode::create(std::make_unique<IntegerConstantOperation>(std::move(v)), {}));
459 
460  return tacs.back()->result(0);
461 }
462 
463 static inline const Variable *
465  ::llvm::Constant * c,
466  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
467  Context & ctx)
468 {
469  JLM_ASSERT(c->getValueID() == ::llvm::Value::UndefValueVal);
470 
471  auto t = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
472  tacs.push_back(UndefValueOperation::Create(t));
473 
474  return tacs.back()->result(0);
475 }
476 
477 static const Variable *
479  ::llvm::Constant * constant,
480  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
481  Context & ctx)
482 {
483  JLM_ASSERT(constant->getValueID() == ::llvm::Value::ConstantExprVal);
484  auto c = ::llvm::cast<::llvm::ConstantExpr>(constant);
485 
486  /*
487  FIXME: ConvertInstruction currently assumes that a instruction's result variable
488  is already added to the context. This is not the case for constants and we
489  therefore need to do some poilerplate checking in ConvertInstruction to
490  see whether a variable was already declared or we need to create a new
491  variable.
492  */
493 
494  /* FIXME: getAsInstruction is none const, forcing all llvm parameters to be none const */
495  /* FIXME: The invocation of getAsInstruction() introduces a memory leak. */
496  auto instruction = c->getAsInstruction();
497  auto v = convertInstruction(instruction, tacs, ctx);
498  instruction->dropAllReferences();
499  return v;
500 }
501 
502 static const Variable *
504  ::llvm::Constant * constant,
505  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
506  Context & ctx)
507 {
508  JLM_ASSERT(constant->getValueID() == ::llvm::Value::ConstantFPVal);
509  auto c = ::llvm::cast<::llvm::ConstantFP>(constant);
510 
511  auto type = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
512  tacs.push_back(ConstantFP::create(c->getValueAPF(), type));
513 
514  return tacs.back()->result(0);
515 }
516 
517 static const Variable *
519  ::llvm::Constant * c,
520  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
521  Context & ctx)
522 {
523  JLM_ASSERT(c->getValueID() == ::llvm::Value::GlobalVariableVal);
524  return ConvertValue(c, tacs, ctx);
525 }
526 
527 static const Variable *
529  ::llvm::Constant * constant,
530  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
531  Context & ctx)
532 {
533  JLM_ASSERT(::llvm::dyn_cast<const ::llvm::ConstantPointerNull>(constant));
534  auto & c = *::llvm::cast<const ::llvm::ConstantPointerNull>(constant);
535 
536  auto t = ctx.GetTypeConverter().ConvertPointerType(*c.getType());
537  tacs.push_back(ConstantPointerNullOperation::Create(t));
538 
539  return tacs.back()->result(0);
540 }
541 
542 static const Variable *
544  ::llvm::Constant * constant,
545  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> &,
546  Context &)
547 {
548  JLM_ASSERT(constant->getValueID() == ::llvm::Value::BlockAddressVal);
549 
550  JLM_UNREACHABLE("Blockaddress constants are not supported.");
551 }
552 
553 static const Variable *
555  ::llvm::Constant * c,
556  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
557  Context & ctx)
558 {
559  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantAggregateZeroVal);
560 
561  auto type = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
562  tacs.push_back(ConstantAggregateZeroOperation::create(type));
563 
564  return tacs.back()->result(0);
565 }
566 
567 static const Variable *
569  ::llvm::Constant * c,
570  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
571  Context & ctx)
572 {
573  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantArrayVal);
574 
575  std::vector<const Variable *> elements;
576  for (size_t n = 0; n < c->getNumOperands(); n++)
577  {
578  auto operand = c->getOperand(n);
579  JLM_ASSERT(::llvm::dyn_cast<const ::llvm::Constant>(operand));
580  auto constant = ::llvm::cast<::llvm::Constant>(operand);
581  elements.push_back(ConvertConstant(constant, tacs, ctx));
582  }
583 
584  tacs.push_back(ConstantArrayOperation::create(elements));
585 
586  return tacs.back()->result(0);
587 }
588 
589 static const Variable *
591  ::llvm::Constant * constant,
592  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
593  Context & ctx)
594 {
595  JLM_ASSERT(constant->getValueID() == ::llvm::Value::ConstantDataArrayVal);
596  const auto & c = *::llvm::cast<const ::llvm::ConstantDataArray>(constant);
597 
598  std::vector<const Variable *> elements;
599  for (size_t n = 0; n < c.getNumElements(); n++)
600  elements.push_back(ConvertConstant(c.getElementAsConstant(n), tacs, ctx));
601 
602  tacs.push_back(ConstantDataArray::create(elements));
603 
604  return tacs.back()->result(0);
605 }
606 
607 static const Variable *
609  ::llvm::Constant * constant,
610  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
611  Context & ctx)
612 {
613  JLM_ASSERT(constant->getValueID() == ::llvm::Value::ConstantDataVectorVal);
614  auto c = ::llvm::cast<const ::llvm::ConstantDataVector>(constant);
615 
616  std::vector<const Variable *> elements;
617  for (size_t n = 0; n < c->getNumElements(); n++)
618  elements.push_back(ConvertConstant(c->getElementAsConstant(n), tacs, ctx));
619 
620  tacs.push_back(ConstantDataVectorOperation::Create(elements));
621 
622  return tacs.back()->result(0);
623 }
624 
625 static const Variable *
627  ::llvm::Constant * c,
628  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
629  Context & ctx)
630 {
631  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantStructVal);
632 
633  std::vector<const Variable *> elements;
634  for (size_t n = 0; n < c->getNumOperands(); n++)
635  elements.push_back(ConvertConstant(c->getAggregateElement(n), tacs, ctx));
636 
637  auto type = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
638  tacs.push_back(ConstantStruct::create(elements, type));
639 
640  return tacs.back()->result(0);
641 }
642 
643 static const Variable *
645  ::llvm::Constant * c,
646  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
647  Context & ctx)
648 {
649  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantVectorVal);
650 
651  std::vector<const Variable *> elements;
652  for (size_t n = 0; n < c->getNumOperands(); n++)
653  elements.push_back(ConvertConstant(c->getAggregateElement(n), tacs, ctx));
654 
655  auto type = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
656  tacs.push_back(ConstantVectorOperation::create(elements, type));
657 
658  return tacs.back()->result(0);
659 }
660 
661 static inline const Variable *
663  ::llvm::Constant * constant,
664  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> &,
665  Context &)
666 {
667  JLM_ASSERT(constant->getValueID() == ::llvm::Value::GlobalAliasVal);
668 
669  JLM_UNREACHABLE("GlobalAlias constants are not supported.");
670 }
671 
672 static inline const Variable *
673 convert_function(::llvm::Constant * c, tacsvector_t & tacs, Context & ctx)
674 {
675  JLM_ASSERT(c->getValueID() == ::llvm::Value::FunctionVal);
676  return ConvertValue(c, tacs, ctx);
677 }
678 
679 static const Variable *
681  ::llvm::PoisonValue * poisonValue,
682  tacsvector_t & threeAddressCodeVector,
683  Context & context)
684 {
685  auto type = context.GetTypeConverter().ConvertLlvmType(*poisonValue->getType());
686  threeAddressCodeVector.push_back(PoisonValueOperation::Create(type));
687 
688  return threeAddressCodeVector.back()->result(0);
689 }
690 
691 template<class T>
692 static const Variable *
694  ::llvm::Constant * constant,
695  tacsvector_t & threeAddressCodeVector,
696  Context & context)
697 {
698  JLM_ASSERT(::llvm::dyn_cast<T>(constant));
699  return ConvertConstant(::llvm::cast<T>(constant), threeAddressCodeVector, context);
700 }
701 
702 static const Variable *
704  ::llvm::Constant * c,
705  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
706  Context & ctx)
707 {
708  static std::unordered_map<
709  unsigned,
710  const Variable * (*)(::llvm::Constant *,
711  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> &,
712  Context & ctx)>
713  constantMap({ { ::llvm::Value::BlockAddressVal, convert_blockAddress },
714  { ::llvm::Value::ConstantAggregateZeroVal, convert_constantAggregateZero },
715  { ::llvm::Value::ConstantArrayVal, convert_constantArray },
716  { ::llvm::Value::ConstantDataArrayVal, convert_constantDataArray },
717  { ::llvm::Value::ConstantDataVectorVal, convert_constantDataVector },
718  { ::llvm::Value::ConstantExprVal, convert_constantExpr },
719  { ::llvm::Value::ConstantFPVal, convert_constantFP },
720  { ::llvm::Value::ConstantIntVal, convert_int_constant },
721  { ::llvm::Value::ConstantPointerNullVal, convert_constantPointerNull },
722  { ::llvm::Value::ConstantStructVal, ConvertConstantStruct },
723  { ::llvm::Value::ConstantVectorVal, convert_constantVector },
724  { ::llvm::Value::FunctionVal, convert_function },
725  { ::llvm::Value::GlobalAliasVal, convert_globalAlias },
726  { ::llvm::Value::GlobalVariableVal, convert_globalVariable },
727  { ::llvm::Value::PoisonValueVal, ConvertConstant<::llvm::PoisonValue> },
728  { ::llvm::Value::UndefValueVal, convert_undefvalue } });
729 
730  if (constantMap.find(c->getValueID()) != constantMap.end())
731  return constantMap[c->getValueID()](c, tacs, ctx);
732 
733  JLM_UNREACHABLE("Unsupported LLVM Constant.");
734 }
735 
736 static std::vector<std::unique_ptr<llvm::ThreeAddressCode>>
737 ConvertConstant(::llvm::Constant * c, Context & ctx)
738 {
739  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> tacs;
740  ConvertConstant(c, tacs, ctx);
741  return tacs;
742 }
743 
744 static inline const Variable *
745 convert_return_instruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
746 {
747  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::Ret);
748  auto i = ::llvm::cast<::llvm::ReturnInst>(instruction);
749 
750  auto bb = ctx.get(i->getParent());
751  bb->add_outedge(bb->cfg().exit());
752  if (!i->getReturnValue())
753  return {};
754 
755  auto value = ConvertValue(i->getReturnValue(), tacs, ctx);
756  tacs.push_back(AssignmentOperation::create(value, ctx.result()));
757 
758  return ctx.result();
759 }
760 
761 static const Variable *
762 ConvertBranchInstruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
763 {
764  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::Br);
765  auto i = ::llvm::cast<::llvm::BranchInst>(instruction);
766  auto bb = ctx.get(i->getParent());
767 
768  JLM_ASSERT(bb->NumOutEdges() == 0);
769 
770  if (i->isUnconditional())
771  {
772  bb->add_outedge(ctx.get(i->getSuccessor(0)));
773  return nullptr;
774  }
775 
776  bb->add_outedge(ctx.get(i->getSuccessor(1))); // False out-edge
777  bb->add_outedge(ctx.get(i->getSuccessor(0))); // True out-edge
778 
779  auto c = ConvertValue(i->getCondition(), tacs, ctx);
780  auto nbits = i->getCondition()->getType()->getIntegerBitWidth();
781  auto op =
782  std::unique_ptr<rvsdg::MatchOperation>(new rvsdg::MatchOperation(nbits, { { 1, 1 } }, 0, 2));
783  tacs.push_back(ThreeAddressCode::create(std::move(op), { c }));
784  tacs.push_back(BranchOperation::create(2, tacs.back()->result(0)));
785 
786  return nullptr;
787 }
788 
789 static const Variable *
790 convertSwitchInstruction(::llvm::SwitchInst * switchInstruction, tacsvector_t & tacs, Context & ctx)
791 {
792  auto jlmSwitchBasicBlock = ctx.get(switchInstruction->getParent());
793 
794  JLM_ASSERT(jlmSwitchBasicBlock->NumOutEdges() == 0);
795  std::unordered_map<uint64_t, uint64_t> matchMapping;
796  std::unordered_map<::llvm::BasicBlock *, ControlFlowGraphEdge *> outEdgeMapping;
797  for (auto caseIt = switchInstruction->case_begin(); caseIt != switchInstruction->case_end();
798  ++caseIt)
799  {
800  JLM_ASSERT(caseIt != switchInstruction->case_default());
801  auto llvmCaseBasicBlock = caseIt->getCaseSuccessor();
802 
803  if (auto outEdgeIt = outEdgeMapping.find(llvmCaseBasicBlock); outEdgeIt != outEdgeMapping.end())
804  {
805  // We have seen this LLVM basic block already and created an outgoing edge for it. Reuse that
806  // edge.
807  matchMapping[caseIt->getCaseValue()->getZExtValue()] = outEdgeIt->second->index();
808  }
809  else
810  {
811  auto jlmCaseBasicBlock = ctx.get(llvmCaseBasicBlock);
812  auto edge = jlmSwitchBasicBlock->add_outedge(jlmCaseBasicBlock);
813  outEdgeMapping[llvmCaseBasicBlock] = edge;
814  matchMapping[caseIt->getCaseValue()->getZExtValue()] = edge->index();
815  }
816  }
817 
818  auto jlmDefaultBasicBlock = ctx.get(switchInstruction->case_default()->getCaseSuccessor());
819  auto defaultEdge = jlmSwitchBasicBlock->add_outedge(jlmDefaultBasicBlock);
820 
821  auto c = ConvertValue(switchInstruction->getCondition(), tacs, ctx);
822  auto numBits = switchInstruction->getCondition()->getType()->getIntegerBitWidth();
823  auto op = std::make_unique<rvsdg::MatchOperation>(
824  numBits,
825  matchMapping,
826  defaultEdge->index(),
827  jlmSwitchBasicBlock->NumOutEdges());
828  tacs.push_back(ThreeAddressCode::create(std::move(op), { c }));
829  tacs.push_back(
830  BranchOperation::create(jlmSwitchBasicBlock->NumOutEdges(), tacs.back()->result(0)));
831 
832  return nullptr;
833 }
834 
835 static inline const Variable *
836 convert_unreachable_instruction(::llvm::Instruction * i, tacsvector_t &, Context & ctx)
837 {
838  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Unreachable);
839  auto bb = ctx.get(i->getParent());
840  bb->add_outedge(bb->cfg().exit());
841  return nullptr;
842 }
843 
844 static std::unique_ptr<rvsdg::BinaryOperation>
845 ConvertIntegerIcmpPredicate(const ::llvm::CmpInst::Predicate predicate, const std::size_t numBits)
846 {
847  switch (predicate)
848  {
849  case ::llvm::CmpInst::ICMP_SLT:
850  return std::make_unique<IntegerSltOperation>(numBits);
851  case ::llvm::CmpInst::ICMP_ULT:
852  return std::make_unique<IntegerUltOperation>(numBits);
853  case ::llvm::CmpInst::ICMP_SLE:
854  return std::make_unique<IntegerSleOperation>(numBits);
855  case ::llvm::CmpInst::ICMP_ULE:
856  return std::make_unique<IntegerUleOperation>(numBits);
857  case ::llvm::CmpInst::ICMP_EQ:
858  return std::make_unique<IntegerEqOperation>(numBits);
859  case ::llvm::CmpInst::ICMP_NE:
860  return std::make_unique<IntegerNeOperation>(numBits);
861  case ::llvm::CmpInst::ICMP_SGE:
862  return std::make_unique<IntegerSgeOperation>(numBits);
863  case ::llvm::CmpInst::ICMP_UGE:
864  return std::make_unique<IntegerUgeOperation>(numBits);
865  case ::llvm::CmpInst::ICMP_SGT:
866  return std::make_unique<IntegerSgtOperation>(numBits);
867  case ::llvm::CmpInst::ICMP_UGT:
868  return std::make_unique<IntegerUgtOperation>(numBits);
869  default:
870  JLM_UNREACHABLE("ConvertIntegerIcmpPredicate: Unsupported icmp predicate.");
871  }
872 }
873 
874 static std::unique_ptr<rvsdg::BinaryOperation>
875 ConvertPointerIcmpPredicate(const ::llvm::CmpInst::Predicate predicate)
876 {
877  const auto pred = convertICmpPredicateToJlm(predicate);
878  return std::make_unique<PtrCmpOperation>(PointerType::Create(), pred);
879 }
880 
881 static const Variable *
882 convert(const ::llvm::ICmpInst * instruction, tacsvector_t & tacs, Context & ctx)
883 {
884  const auto predicate = instruction->getPredicate();
885  const auto operandType = instruction->getOperand(0)->getType();
886  auto op1 = ConvertValue(instruction->getOperand(0), tacs, ctx);
887  auto op2 = ConvertValue(instruction->getOperand(1), tacs, ctx);
888 
889  std::unique_ptr<rvsdg::BinaryOperation> operation;
890  if (operandType->isVectorTy() && operandType->getScalarType()->isIntegerTy())
891  {
892  operation =
893  ConvertIntegerIcmpPredicate(predicate, operandType->getScalarType()->getIntegerBitWidth());
894  }
895  else if (operandType->isVectorTy() && operandType->getScalarType()->isPointerTy())
896  {
897  operation = ConvertPointerIcmpPredicate(predicate);
898  }
899  else if (operandType->isIntegerTy())
900  {
901  operation = ConvertIntegerIcmpPredicate(predicate, operandType->getIntegerBitWidth());
902  }
903  else if (operandType->isPointerTy())
904  {
905  operation = ConvertPointerIcmpPredicate(predicate);
906  }
907  else
908  {
909  JLM_UNREACHABLE("convert: Unhandled icmp type.");
910  }
911 
912  if (operandType->isVectorTy())
913  {
914  const auto instructionType = ctx.GetTypeConverter().ConvertLlvmType(*instruction->getType());
915  tacs.push_back(VectorBinaryOperation::create(*operation, op1, op2, instructionType));
916  }
917  else
918  {
919  tacs.push_back(ThreeAddressCode::create(std::move(operation), { op1, op2 }));
920  }
921 
922  return tacs.back()->result(0);
923 }
924 
925 static const Variable *
926 convert_fcmp_instruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
927 {
928  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::FCmp);
929  auto & typeConverter = ctx.GetTypeConverter();
930  auto i = ::llvm::cast<const ::llvm::FCmpInst>(instruction);
931  auto t = i->getOperand(0)->getType();
932 
933  static std::unordered_map<::llvm::CmpInst::Predicate, llvm::fpcmp> map(
934  { { ::llvm::CmpInst::FCMP_TRUE, fpcmp::TRUE },
935  { ::llvm::CmpInst::FCMP_FALSE, fpcmp::FALSE },
936  { ::llvm::CmpInst::FCMP_OEQ, fpcmp::oeq },
937  { ::llvm::CmpInst::FCMP_OGT, fpcmp::ogt },
938  { ::llvm::CmpInst::FCMP_OGE, fpcmp::oge },
939  { ::llvm::CmpInst::FCMP_OLT, fpcmp::olt },
940  { ::llvm::CmpInst::FCMP_OLE, fpcmp::ole },
941  { ::llvm::CmpInst::FCMP_ONE, fpcmp::one },
942  { ::llvm::CmpInst::FCMP_ORD, fpcmp::ord },
943  { ::llvm::CmpInst::FCMP_UNO, fpcmp::uno },
944  { ::llvm::CmpInst::FCMP_UEQ, fpcmp::ueq },
945  { ::llvm::CmpInst::FCMP_UGT, fpcmp::ugt },
946  { ::llvm::CmpInst::FCMP_UGE, fpcmp::uge },
947  { ::llvm::CmpInst::FCMP_ULT, fpcmp::ult },
948  { ::llvm::CmpInst::FCMP_ULE, fpcmp::ule },
949  { ::llvm::CmpInst::FCMP_UNE, fpcmp::une } });
950 
951  auto type = typeConverter.ConvertLlvmType(*i->getType());
952 
953  auto op1 = ConvertValue(i->getOperand(0), tacs, ctx);
954  auto op2 = ConvertValue(i->getOperand(1), tacs, ctx);
955 
956  JLM_ASSERT(map.find(i->getPredicate()) != map.end());
957  auto fptype = t->isVectorTy() ? t->getScalarType() : t;
958  auto operation = std::make_unique<FCmpOperation>(
959  map[i->getPredicate()],
960  typeConverter.ExtractFloatingPointSize(*fptype));
961 
962  if (t->isVectorTy())
963  tacs.push_back(VectorBinaryOperation::create(*operation, op1, op2, type));
964  else
965  tacs.push_back(ThreeAddressCode::create(std::move(operation), { op1, op2 }));
966 
967  return tacs.back()->result(0);
968 }
969 
970 static const Variable *
971 AddIOBarrier(tacsvector_t & tacs, const Variable * operand, const Context & ctx)
972 {
973  auto ioBarrierOperation = std::make_unique<IOBarrierOperation>(operand->Type());
974  tacs.push_back(
975  ThreeAddressCode::create(std::move(ioBarrierOperation), { operand, ctx.iostate() }));
976  return tacs.back()->result(0);
977 }
978 
979 static inline const Variable *
980 convert_load_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
981 {
982  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Load);
983  auto instruction = static_cast<::llvm::LoadInst *>(i);
984 
985  auto alignment = instruction->getAlign().value();
986  auto address = ConvertValue(instruction->getPointerOperand(), tacs, ctx);
987  auto loadedType = ctx.GetTypeConverter().ConvertLlvmType(*instruction->getType());
988 
989  // We currently do not not support atomic load instructions
990  JLM_ASSERT(!instruction->isAtomic());
991 
992  const ThreeAddressCodeVariable * loadedValue = nullptr;
993  const ThreeAddressCodeVariable * memoryState = nullptr;
994  const ThreeAddressCodeVariable * ioState = nullptr;
995  if (instruction->isVolatile())
996  {
997  auto loadVolatileTac = LoadVolatileOperation::Create(
998  address,
999  ctx.iostate(),
1000  ctx.memory_state(),
1001  loadedType,
1002  alignment);
1003  tacs.push_back(std::move(loadVolatileTac));
1004 
1005  loadedValue = tacs.back()->result(0);
1006  ioState = tacs.back()->result(1);
1007  memoryState = tacs.back()->result(2);
1008  }
1009  else
1010  {
1011  address = AddIOBarrier(tacs, address, ctx);
1012  auto loadTac =
1013  LoadNonVolatileOperation::Create(address, ctx.memory_state(), loadedType, alignment);
1014  tacs.push_back(std::move(loadTac));
1015  loadedValue = tacs.back()->result(0);
1016  memoryState = tacs.back()->result(1);
1017  }
1018 
1019  if (ioState)
1020  {
1021  tacs.push_back(AssignmentOperation::create(ioState, ctx.iostate()));
1022  }
1023  tacs.push_back(AssignmentOperation::create(memoryState, ctx.memory_state()));
1024 
1025  return loadedValue;
1026 }
1027 
1028 static inline const Variable *
1029 convert_store_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1030 {
1031  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Store);
1032  auto instruction = static_cast<::llvm::StoreInst *>(i);
1033 
1034  auto alignment = instruction->getAlign().value();
1035  auto address = ConvertValue(instruction->getPointerOperand(), tacs, ctx);
1036  auto value = ConvertValue(instruction->getValueOperand(), tacs, ctx);
1037 
1038  // We currently do not not support atomic store instructions
1039  JLM_ASSERT(!instruction->isAtomic());
1040 
1041  const ThreeAddressCodeVariable * memoryState = nullptr;
1042  const ThreeAddressCodeVariable * ioState = nullptr;
1043  if (instruction->isVolatile())
1044  {
1045  auto storeVolatileTac = StoreVolatileOperation::Create(
1046  address,
1047  value,
1048  ctx.iostate(),
1049  ctx.memory_state(),
1050  alignment);
1051  tacs.push_back(std::move(storeVolatileTac));
1052  ioState = tacs.back()->result(0);
1053  memoryState = tacs.back()->result(1);
1054  }
1055  else
1056  {
1057  address = AddIOBarrier(tacs, address, ctx);
1058  auto storeTac =
1059  StoreNonVolatileOperation::Create(address, value, ctx.memory_state(), alignment);
1060  tacs.push_back(std::move(storeTac));
1061  memoryState = tacs.back()->result(0);
1062  }
1063 
1064  if (ioState)
1065  {
1066  tacs.push_back(AssignmentOperation::create(ioState, ctx.iostate()));
1067  }
1068  tacs.push_back(AssignmentOperation::create(memoryState, ctx.memory_state()));
1069 
1070  return nullptr;
1071 }
1072 
1073 static const Variable *
1074 ConvertPhiInstruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1075 {
1076  // Some of the blocks reaching this phi instruction might not be converted yet,
1077  // so some of the phi's operands may reference instructions that have not yet been converted.
1078  // For now, a SsaPhiOperation with no operands is created.
1079  // Once all basic blocks are converted, all SsaPhiOperations are revisited and given operands.
1080  auto type = ctx.GetTypeConverter().ConvertLlvmType(*i->getType());
1081  tacs.push_back(SsaPhiOperation::create({}, std::move(type)));
1082  return tacs.back()->result(0);
1083 }
1084 
1085 static const Variable *
1086 convert_getelementptr_instruction(::llvm::Instruction * inst, tacsvector_t & tacs, Context & ctx)
1087 {
1088  JLM_ASSERT(::llvm::dyn_cast<const ::llvm::GetElementPtrInst>(inst));
1089  auto & typeConverter = ctx.GetTypeConverter();
1090  auto i = ::llvm::cast<::llvm::GetElementPtrInst>(inst);
1091 
1092  std::vector<const Variable *> indices;
1093  auto base = ConvertValue(i->getPointerOperand(), tacs, ctx);
1094  for (auto it = i->idx_begin(); it != i->idx_end(); it++)
1095  indices.push_back(ConvertValue(*it, tacs, ctx));
1096 
1097  auto pointeeType = typeConverter.ConvertLlvmType(*i->getSourceElementType());
1098 
1099  tacs.push_back(GetElementPtrOperation::createTAC(base, indices, pointeeType));
1100 
1101  return tacs.back()->result(0);
1102 }
1103 
1104 static const Variable *
1106  const ::llvm::CallInst & instruction,
1107  tacsvector_t & threeAddressCodes,
1108  Context & context)
1109 {
1110  auto globalMemoryState = context.memory_state();
1111  const auto globalIOState = context.iostate();
1112 
1113  const auto size = ConvertValue(instruction.getArgOperand(0), threeAddressCodes, context);
1114 
1115  threeAddressCodes.push_back(MallocOperation::createTac(size, globalIOState));
1116  const auto mallocAddress = threeAddressCodes.back()->result(0);
1117  const auto mallocIOState = threeAddressCodes.back()->result(1);
1118  auto mallocMemoryState = threeAddressCodes.back()->result(2);
1119 
1120  threeAddressCodes.push_back(AssignmentOperation::create(mallocIOState, globalIOState));
1121 
1122  threeAddressCodes.push_back(
1123  MemoryStateMergeOperation::Create({ mallocMemoryState, globalMemoryState }));
1124  threeAddressCodes.push_back(
1125  AssignmentOperation::create(threeAddressCodes.back()->result(0), globalMemoryState));
1126 
1127  return mallocAddress;
1128 }
1129 
1130 static const Variable *
1132  const ::llvm::CallInst & instruction,
1133  tacsvector_t & threeAddressCodes,
1134  Context & context)
1135 {
1136  const auto ioState = context.iostate();
1137  auto memstate = context.memory_state();
1138 
1139  const auto pointer = ConvertValue(instruction.getArgOperand(0), threeAddressCodes, context);
1140 
1141  threeAddressCodes.push_back(FreeOperation::Create(pointer, { memstate }, ioState));
1142  const auto & freeThreeAddressCode = *threeAddressCodes.back().get();
1143 
1144  threeAddressCodes.push_back(
1145  AssignmentOperation::create(freeThreeAddressCode.result(0), memstate));
1146  threeAddressCodes.push_back(AssignmentOperation::create(freeThreeAddressCode.result(1), ioState));
1147 
1148  return nullptr;
1149 }
1150 
1159 static bool
1160 IsVolatile(const ::llvm::Value & value)
1161 {
1162  const auto constant = ::llvm::dyn_cast<const ::llvm::ConstantInt>(&value);
1163  JLM_ASSERT(constant != nullptr && constant->getType()->getIntegerBitWidth() == 1);
1164 
1165  const auto apInt = constant->getValue();
1166  JLM_ASSERT(apInt.isZero() || apInt.isOne());
1167 
1168  return apInt.isOne();
1169 }
1170 
1171 static const Variable *
1173  const ::llvm::IntrinsicInst * instruction,
1174  tacsvector_t & threeAddressCodes,
1175  Context & context)
1176 {
1177  JLM_ASSERT(
1178  instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy
1179  || instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy_inline
1180  || instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy_element_unordered_atomic);
1181 
1182  if (instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy_inline)
1183  throw std::logic_error("Unhandled memcpy_inline intrinsic.");
1184  if (instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy_element_unordered_atomic)
1185  throw std::logic_error("Unhandled memcpy_element_unordered_atomic intrinsic.");
1186 
1187  const auto ioState = context.iostate();
1188  auto memoryState = context.memory_state();
1189 
1190  const auto destination = ConvertValue(instruction->getArgOperand(0), threeAddressCodes, context);
1191  const auto source = ConvertValue(instruction->getArgOperand(1), threeAddressCodes, context);
1192  const auto length = ConvertValue(instruction->getArgOperand(2), threeAddressCodes, context);
1193 
1194  if (IsVolatile(*instruction->getArgOperand(3)))
1195  {
1196  threeAddressCodes.push_back(MemCpyVolatileOperation::CreateThreeAddressCode(
1197  *destination,
1198  *source,
1199  *length,
1200  *ioState,
1201  { memoryState }));
1202  const auto & memCpyVolatileTac = *threeAddressCodes.back();
1203  threeAddressCodes.push_back(AssignmentOperation::create(memCpyVolatileTac.result(0), ioState));
1204  threeAddressCodes.push_back(
1205  AssignmentOperation::create(memCpyVolatileTac.result(1), memoryState));
1206  }
1207  else
1208  {
1209  threeAddressCodes.push_back(
1210  MemCpyNonVolatileOperation::create(destination, source, length, { memoryState }));
1211  threeAddressCodes.push_back(
1212  AssignmentOperation::create(threeAddressCodes.back()->result(0), memoryState));
1213  }
1214 
1215  return nullptr;
1216 }
1217 
1218 static const Variable *
1220  const ::llvm::IntrinsicInst & instruction,
1221  tacsvector_t & threeAddressCodes,
1222  Context & context)
1223 {
1224  JLM_ASSERT(
1225  instruction.getIntrinsicID() == ::llvm::Intrinsic::memset
1226  || instruction.getIntrinsicID() == ::llvm::Intrinsic::memset_inline
1227  || instruction.getIntrinsicID() == ::llvm::Intrinsic::memset_element_unordered_atomic);
1228 
1229  if (instruction.getIntrinsicID() == ::llvm::Intrinsic::memset_inline)
1230  throw std::logic_error("Unhandled memset_inline intrinsic.");
1231  if (instruction.getIntrinsicID() == ::llvm::Intrinsic::memset_element_unordered_atomic)
1232  throw std::logic_error("Unhandled memset_element_unordered_atomic intrinsic.");
1233 
1234  auto memoryState = context.memory_state();
1235 
1236  const auto destination = ConvertValue(instruction.getArgOperand(0), threeAddressCodes, context);
1237  const auto value = ConvertValue(instruction.getArgOperand(1), threeAddressCodes, context);
1238  const auto length = ConvertValue(instruction.getArgOperand(2), threeAddressCodes, context);
1239 
1240  if (IsVolatile(*instruction.getArgOperand(3)))
1241  {
1242  throw std::logic_error("Unhandled volatile memset intrinsic.");
1243  }
1244  else
1245  {
1246  threeAddressCodes.push_back(
1247  MemSetNonVolatileOperation::createTac(*destination, *value, *length, { memoryState }));
1248  threeAddressCodes.push_back(
1249  AssignmentOperation::create(threeAddressCodes.back()->result(0), memoryState));
1250  }
1251 
1252  return nullptr;
1253 }
1254 
1255 static bool
1256 isMallocCall(const ::llvm::CallInst & callInstruction)
1257 {
1258  const auto function = callInstruction.getCalledFunction();
1259  return function && function->getName() == "malloc";
1260 }
1261 
1262 static bool
1263 isFreeCall(const ::llvm::CallInst & callInstruction)
1264 {
1265  const auto function = callInstruction.getCalledFunction();
1266  return function && function->getName() == "free";
1267 }
1268 
1269 static const Variable *
1270 convertFMulAddIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & ctx)
1271 {
1272  const auto multiplier = ConvertValue(instruction.getArgOperand(0), tacs, ctx);
1273  const auto multiplicand = ConvertValue(instruction.getArgOperand(1), tacs, ctx);
1274  const auto summand = ConvertValue(instruction.getArgOperand(2), tacs, ctx);
1275  tacs.push_back(FMulAddIntrinsicOperation::CreateTac(*multiplier, *multiplicand, *summand));
1276 
1277  return tacs.back()->result(0);
1278 }
1279 
1280 std::vector<const Variable *>
1282  const ::llvm::CallInst & callInstruction,
1283  tacsvector_t & threeAddressCodes,
1284  Context & context)
1285 {
1286  const auto functionType = callInstruction.getFunctionType();
1287 
1288  std::vector<const Variable *> arguments;
1289  for (size_t n = 0; n < functionType->getNumParams(); n++)
1290  arguments.push_back(ConvertValue(callInstruction.getArgOperand(n), threeAddressCodes, context));
1291 
1292  if (functionType->isVarArg())
1293  {
1294  std::vector<const Variable *> variableArguments;
1295  for (size_t n = functionType->getNumParams(); n < callInstruction.getNumOperands() - 1; n++)
1296  variableArguments.push_back(
1297  ConvertValue(callInstruction.getArgOperand(n), threeAddressCodes, context));
1298 
1299  threeAddressCodes.push_back(VariadicArgumentListOperation::create(variableArguments));
1300  arguments.push_back(threeAddressCodes.back()->result(0));
1301  }
1302 
1303  arguments.push_back(context.iostate());
1304  arguments.push_back(context.memory_state());
1305 
1306  return arguments;
1307 }
1308 
1309 static const Variable *
1311  const ::llvm::CallInst & callInstruction,
1312  tacsvector_t & threeAddressCodes,
1313  Context & context)
1314 {
1315  const auto functionType = callInstruction.getFunctionType();
1316 
1317  auto convertedFunctionType = context.GetTypeConverter().ConvertFunctionType(*functionType);
1318  const auto arguments = convertCallArguments(callInstruction, threeAddressCodes, context);
1319  const auto callingConvention = convertCallingConventionToJlm(callInstruction.getCallingConv());
1320  auto attributes = convertAttributeList(
1321  callInstruction.getAttributes(),
1322  callInstruction.arg_size(),
1323  context.GetTypeConverter());
1324 
1325  const Variable * callee =
1326  ConvertValueOrFunction(callInstruction.getCalledOperand(), threeAddressCodes, context);
1327  // Llvm does not distinguish between "function objects" and
1328  // "pointers to functions" while we need to be precise in modeling.
1329  // If the called object is a function object, then we can just
1330  // feed it to the call operator directly, otherwise we have
1331  // to cast it into a function object.
1332  if (is<PointerType>(*callee->Type()))
1333  {
1334  std::unique_ptr<ThreeAddressCode> callee_cast = ThreeAddressCode::create(
1335  std::make_unique<PointerToFunctionOperation>(convertedFunctionType),
1336  { callee });
1337  callee = callee_cast->result(0);
1338  threeAddressCodes.push_back(std::move(callee_cast));
1339  }
1340  else if (auto fntype = std::dynamic_pointer_cast<const rvsdg::FunctionType>(callee->Type()))
1341  {
1342  // Llvm also allows argument type mismatches if the function
1343  // features varargs. The code here could be made more precise by
1344  // validating and accepting only vararg-related mismatches.
1345  if (*convertedFunctionType != *fntype)
1346  {
1347  // Since vararg passing is not modeled explicitly, simply hide the
1348  // argument mismatch via pointer casts.
1349  std::unique_ptr<ThreeAddressCode> ptrCast = ThreeAddressCode::create(
1350  std::make_unique<FunctionToPointerOperation>(fntype),
1351  { callee });
1352  std::unique_ptr<ThreeAddressCode> fnCast = ThreeAddressCode::create(
1353  std::make_unique<PointerToFunctionOperation>(convertedFunctionType),
1354  { ptrCast->result(0) });
1355  callee = fnCast->result(0);
1356  threeAddressCodes.push_back(std::move(ptrCast));
1357  threeAddressCodes.push_back(std::move(fnCast));
1358  }
1359  }
1360  else
1361  {
1362  throw std::runtime_error("Unexpected callee type: " + callee->Type()->debug_string());
1363  }
1364 
1365  auto call = CallOperation::create(
1366  callee,
1367  convertedFunctionType,
1368  callingConvention,
1369  std::move(attributes),
1370  arguments);
1371 
1372  const auto result = call->result(0);
1373  const auto ioState = call->result(call->nresults() - 2);
1374  const auto memoryState = call->result(call->nresults() - 1);
1375 
1376  threeAddressCodes.push_back(std::move(call));
1377  threeAddressCodes.push_back(AssignmentOperation::create(ioState, context.iostate()));
1378  threeAddressCodes.push_back(AssignmentOperation::create(memoryState, context.memory_state()));
1379 
1380  return result;
1381 }
1382 
1389 static bool
1390 shouldIgnoreIntrinsic(::llvm::Intrinsic::ID intrinsicId)
1391 {
1392  switch (intrinsicId)
1393  {
1394  // These intrinsics are ignored because they take pointers to local variables,
1395  // reducing the precision of alias analysis unless specifically handled
1396  case ::llvm::Intrinsic::lifetime_start:
1397  case ::llvm::Intrinsic::lifetime_end:
1398  // This intrinsic is ignored because it takes a parameter of type "metadata"
1399  case ::llvm::Intrinsic::experimental_noalias_scope_decl:
1400  return true;
1401  default:
1402  return false;
1403  }
1404 }
1405 
1406 static const Variable *
1408  const ::llvm::IntrinsicInst & intrinsicInstruction,
1409  tacsvector_t & threeAddressCodes,
1410  Context & context)
1411 {
1412  if (shouldIgnoreIntrinsic(intrinsicInstruction.getIntrinsicID()))
1413  return nullptr;
1414 
1415  switch (intrinsicInstruction.getIntrinsicID())
1416  {
1417  case ::llvm::Intrinsic::fmuladd:
1418  return convertFMulAddIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1419  case ::llvm::Intrinsic::memcpy:
1420  case ::llvm::Intrinsic::memcpy_inline:
1421  case ::llvm::Intrinsic::memcpy_element_unordered_atomic:
1422  return convertMemCpyCall(&intrinsicInstruction, threeAddressCodes, context);
1423  case ::llvm::Intrinsic::memset:
1424  case ::llvm::Intrinsic::memset_inline:
1425  case ::llvm::Intrinsic::memset_element_unordered_atomic:
1426  return convertMemSetCall(intrinsicInstruction, threeAddressCodes, context);
1427  default:
1428  return createCall(intrinsicInstruction, threeAddressCodes, context);
1429  }
1430 }
1431 
1432 static const Variable *
1434  const ::llvm::CallInst & callInstruction,
1435  tacsvector_t & threeAddressCodes,
1436  Context & context)
1437 {
1438  if (const auto intrinsicInstruction = ::llvm::dyn_cast<::llvm::IntrinsicInst>(&callInstruction))
1439  return convertIntrinsicInstruction(*intrinsicInstruction, threeAddressCodes, context);
1440 
1441  if (isMallocCall(callInstruction))
1442  return convertMallocCall(callInstruction, threeAddressCodes, context);
1443 
1444  if (isFreeCall(callInstruction))
1445  return convertFreeCall(callInstruction, threeAddressCodes, context);
1446 
1447  return createCall(callInstruction, threeAddressCodes, context);
1448 }
1449 
1450 static inline const Variable *
1451 convert_select_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1452 {
1453  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Select);
1454  auto instruction = static_cast<::llvm::SelectInst *>(i);
1455 
1456  auto p = ConvertValue(instruction->getCondition(), tacs, ctx);
1457  auto t = ConvertValue(instruction->getTrueValue(), tacs, ctx);
1458  auto f = ConvertValue(instruction->getFalseValue(), tacs, ctx);
1459 
1460  if (i->getType()->isVectorTy())
1461  tacs.push_back(VectorSelectOperation::create(p, t, f));
1462  else
1463  tacs.push_back(SelectOperation::create(p, t, f));
1464 
1465  return tacs.back()->result(0);
1466 }
1467 
1468 static std::unique_ptr<rvsdg::BinaryOperation>
1470  const ::llvm::Instruction::BinaryOps binaryOperation,
1471  std::size_t numBits)
1472 {
1473  switch (binaryOperation)
1474  {
1475  case ::llvm::Instruction::Add:
1476  return std::make_unique<IntegerAddOperation>(numBits);
1477  case ::llvm::Instruction::And:
1478  return std::make_unique<IntegerAndOperation>(numBits);
1479  case ::llvm::Instruction::AShr:
1480  return std::make_unique<IntegerAShrOperation>(numBits);
1481  case ::llvm::Instruction::LShr:
1482  return std::make_unique<IntegerLShrOperation>(numBits);
1483  case ::llvm::Instruction::Mul:
1484  return std::make_unique<IntegerMulOperation>(numBits);
1485  case ::llvm::Instruction::Or:
1486  return std::make_unique<IntegerOrOperation>(numBits);
1487  case ::llvm::Instruction::SDiv:
1488  return std::make_unique<IntegerSDivOperation>(numBits);
1489  case ::llvm::Instruction::Shl:
1490  return std::make_unique<IntegerShlOperation>(numBits);
1491  case ::llvm::Instruction::SRem:
1492  return std::make_unique<IntegerSRemOperation>(numBits);
1493  case ::llvm::Instruction::Sub:
1494  return std::make_unique<IntegerSubOperation>(numBits);
1495  case ::llvm::Instruction::UDiv:
1496  return std::make_unique<IntegerUDivOperation>(numBits);
1497  case ::llvm::Instruction::URem:
1498  return std::make_unique<IntegerURemOperation>(numBits);
1499  case ::llvm::Instruction::Xor:
1500  return std::make_unique<IntegerXorOperation>(numBits);
1501  default:
1502  JLM_UNREACHABLE("ConvertIntegerBinaryOperation: Unsupported integer binary operation");
1503  }
1504 }
1505 
1506 static std::unique_ptr<rvsdg::BinaryOperation>
1508  const ::llvm::Instruction::BinaryOps binaryOperation,
1509  fpsize floatingPointSize)
1510 {
1511  switch (binaryOperation)
1512  {
1513  case ::llvm::Instruction::FAdd:
1514  return std::make_unique<FBinaryOperation>(fpop::add, floatingPointSize);
1515  case ::llvm::Instruction::FSub:
1516  return std::make_unique<FBinaryOperation>(fpop::sub, floatingPointSize);
1517  case ::llvm::Instruction::FMul:
1518  return std::make_unique<FBinaryOperation>(fpop::mul, floatingPointSize);
1519  case ::llvm::Instruction::FDiv:
1520  return std::make_unique<FBinaryOperation>(fpop::div, floatingPointSize);
1521  case ::llvm::Instruction::FRem:
1522  return std::make_unique<FBinaryOperation>(fpop::mod, floatingPointSize);
1523  default:
1524  JLM_UNREACHABLE("ConvertFloatingPointBinaryOperation: Unsupported binary operation");
1525  }
1526 }
1527 
1528 static const Variable *
1529 convert(const ::llvm::BinaryOperator * instruction, tacsvector_t & tacs, Context & ctx)
1530 {
1531  const auto llvmType = instruction->getType();
1532  auto & typeConverter = ctx.GetTypeConverter();
1533  const auto opcode = instruction->getOpcode();
1534 
1535  std::unique_ptr<rvsdg::BinaryOperation> operation;
1536  if (llvmType->isVectorTy() && llvmType->getScalarType()->isIntegerTy())
1537  {
1538  const auto numBits = llvmType->getScalarType()->getIntegerBitWidth();
1539  operation = ConvertIntegerBinaryOperation(opcode, numBits);
1540  }
1541  else if (llvmType->isVectorTy() && llvmType->getScalarType()->isFloatingPointTy())
1542  {
1543  const auto size = typeConverter.ExtractFloatingPointSize(*llvmType->getScalarType());
1544  operation = ConvertFloatingPointBinaryOperation(opcode, size);
1545  }
1546  else if (llvmType->isIntegerTy())
1547  {
1548  operation = ConvertIntegerBinaryOperation(opcode, llvmType->getIntegerBitWidth());
1549  }
1550  else if (llvmType->isFloatingPointTy())
1551  {
1552  const auto size = typeConverter.ExtractFloatingPointSize(*llvmType);
1553  operation = ConvertFloatingPointBinaryOperation(opcode, size);
1554  }
1555  else
1556  {
1557  JLM_ASSERT("convert: Unhandled binary operation type.");
1558  }
1559 
1560  const auto jlmType = typeConverter.ConvertLlvmType(*llvmType);
1561  auto operand1 = ConvertValue(instruction->getOperand(0), tacs, ctx);
1562  auto operand2 = ConvertValue(instruction->getOperand(1), tacs, ctx);
1563 
1564  if (instruction->getOpcode() == ::llvm::Instruction::SDiv
1565  || instruction->getOpcode() == ::llvm::Instruction::UDiv
1566  || instruction->getOpcode() == ::llvm::Instruction::SRem
1567  || instruction->getOpcode() == ::llvm::Instruction::URem)
1568  {
1569  operand1 = AddIOBarrier(tacs, operand1, ctx);
1570  }
1571 
1572  if (llvmType->isVectorTy())
1573  {
1574  tacs.push_back(VectorBinaryOperation::create(*operation, operand1, operand2, jlmType));
1575  }
1576  else
1577  {
1578  tacs.push_back(ThreeAddressCode::create(std::move(operation), { operand1, operand2 }));
1579  }
1580 
1581  return tacs.back()->result(0);
1582 }
1583 
1584 static inline const Variable *
1585 convert_alloca_instruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
1586 {
1587  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::Alloca);
1588  auto i = static_cast<::llvm::AllocaInst *>(instruction);
1589 
1590  auto memstate = ctx.memory_state();
1591  auto size = ConvertValue(i->getArraySize(), tacs, ctx);
1592  auto vtype = ctx.GetTypeConverter().ConvertLlvmType(*i->getAllocatedType());
1593  auto alignment = i->getAlign().value();
1594 
1595  tacs.push_back(AllocaOperation::createTac(vtype, size, alignment));
1596  auto result = tacs.back()->result(0);
1597  auto astate = tacs.back()->result(1);
1598 
1599  tacs.push_back(MemoryStateMergeOperation::Create({ astate, memstate }));
1600  tacs.push_back(AssignmentOperation::create(tacs.back()->result(0), memstate));
1601 
1602  return result;
1603 }
1604 
1605 static const Variable *
1606 convert_extractvalue(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1607 {
1608  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::ExtractValue);
1609  auto ev = ::llvm::dyn_cast<::llvm::ExtractValueInst>(i);
1610 
1611  auto aggregate = ConvertValue(ev->getOperand(0), tacs, ctx);
1612  tacs.push_back(ExtractValueOperation::create(aggregate, ev->getIndices()));
1613 
1614  return tacs.back()->result(0);
1615 }
1616 
1617 static const Variable *
1619  const ::llvm::InsertValueInst & instruction,
1620  tacsvector_t & tacs,
1621  Context & context)
1622 {
1623  const auto aggregateOperand = ConvertValue(instruction.getOperand(0), tacs, context);
1624  const auto valueOperand = ConvertValue(instruction.getOperand(1), tacs, context);
1625 
1626  tacs.push_back(
1627  InsertValueOperation::createTac(*aggregateOperand, *valueOperand, instruction.getIndices()));
1628 
1629  return tacs.back()->result(0);
1630 }
1631 
1632 static inline const Variable *
1633 convert_extractelement_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1634 {
1635  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::ExtractElement);
1636 
1637  auto vector = ConvertValue(i->getOperand(0), tacs, ctx);
1638  auto index = ConvertValue(i->getOperand(1), tacs, ctx);
1639  tacs.push_back(ExtractElementOperation::create(vector, index));
1640 
1641  return tacs.back()->result(0);
1642 }
1643 
1644 static const Variable *
1645 convert(::llvm::ShuffleVectorInst * i, tacsvector_t & tacs, Context & ctx)
1646 {
1647  auto v1 = ConvertValue(i->getOperand(0), tacs, ctx);
1648  auto v2 = ConvertValue(i->getOperand(1), tacs, ctx);
1649 
1650  std::vector<int> mask;
1651  for (auto & element : i->getShuffleMask())
1652  mask.push_back(element);
1653 
1654  tacs.push_back(ShuffleVectorOperation::create(v1, v2, mask));
1655 
1656  return tacs.back()->result(0);
1657 }
1658 
1659 static const Variable *
1660 convert_insertelement_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1661 {
1662  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::InsertElement);
1663 
1664  auto vector = ConvertValue(i->getOperand(0), tacs, ctx);
1665  auto value = ConvertValue(i->getOperand(1), tacs, ctx);
1666  auto index = ConvertValue(i->getOperand(2), tacs, ctx);
1667  tacs.push_back(InsertElementOperation::create(vector, value, index));
1668 
1669  return tacs.back()->result(0);
1670 }
1671 
1672 static const Variable *
1673 convertFreezeInstruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1674 {
1675  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Freeze);
1676 
1677  auto operand = ConvertValue(i->getOperand(0), tacs, ctx);
1678  tacs.push_back(FreezeOperation::createTac(*operand));
1679 
1680  return tacs.back()->result(0);
1681 }
1682 
1683 static const Variable *
1684 convert(::llvm::UnaryOperator * unaryOperator, tacsvector_t & threeAddressCodeVector, Context & ctx)
1685 {
1686  JLM_ASSERT(unaryOperator->getOpcode() == ::llvm::Instruction::FNeg);
1687  auto & typeConverter = ctx.GetTypeConverter();
1688 
1689  auto type = unaryOperator->getType();
1690  auto scalarType = typeConverter.ConvertLlvmType(*type->getScalarType());
1691  auto operand = ConvertValue(unaryOperator->getOperand(0), threeAddressCodeVector, ctx);
1692 
1693  if (type->isVectorTy())
1694  {
1695  auto vectorType = typeConverter.ConvertLlvmType(*type);
1696  threeAddressCodeVector.push_back(VectorUnaryOperation::create(
1697  FNegOperation(std::static_pointer_cast<const FloatingPointType>(scalarType)),
1698  operand,
1699  vectorType));
1700  }
1701  else
1702  {
1703  threeAddressCodeVector.push_back(FNegOperation::create(operand));
1704  }
1705 
1706  return threeAddressCodeVector.back()->result(0);
1707 }
1708 
1709 template<class OP>
1710 static std::unique_ptr<rvsdg::SimpleOperation>
1711 create_unop(std::shared_ptr<const rvsdg::Type> st, std::shared_ptr<const rvsdg::Type> dt)
1712 {
1713  return std::unique_ptr<rvsdg::SimpleOperation>(new OP(std::move(st), std::move(dt)));
1714 }
1715 
1716 static const Variable *
1717 convert_cast_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1718 {
1719  JLM_ASSERT(::llvm::dyn_cast<::llvm::CastInst>(i));
1720  auto & typeConverter = ctx.GetTypeConverter();
1721  auto st = i->getOperand(0)->getType();
1722  auto dt = i->getType();
1723 
1724  // Most cast operations can be performed on vector types, with the cast done per value.
1725  // Bit casts are an exception, as they can cast between different vector sizes.
1726  bool isLaneWiseCast = false;
1727  if (i->getOpcode() != ::llvm::Instruction::BitCast)
1728  {
1729  isLaneWiseCast = st->isVectorTy();
1730  JLM_ASSERT(st->isVectorTy() == dt->isVectorTy());
1731  }
1732 
1733  static std::unordered_map<
1734  unsigned,
1735  std::unique_ptr<rvsdg::SimpleOperation> (*)(
1736  std::shared_ptr<const rvsdg::Type>,
1737  std::shared_ptr<const rvsdg::Type>)>
1738  map({ { ::llvm::Instruction::Trunc, create_unop<TruncOperation> },
1739  { ::llvm::Instruction::ZExt, create_unop<ZExtOperation> },
1740  { ::llvm::Instruction::UIToFP, create_unop<UIToFPOperation> },
1741  { ::llvm::Instruction::SIToFP, create_unop<SIToFPOperation> },
1742  { ::llvm::Instruction::SExt, create_unop<SExtOperation> },
1743  { ::llvm::Instruction::PtrToInt, create_unop<PtrToIntOperation> },
1744  { ::llvm::Instruction::IntToPtr, create_unop<IntegerToPointerOperation> },
1745  { ::llvm::Instruction::FPTrunc, create_unop<FPTruncOperation> },
1746  { ::llvm::Instruction::FPToSI, create_unop<FloatingPointToSignedIntegerOperation> },
1747  { ::llvm::Instruction::FPToUI, create_unop<FloatingPointToUnsignedIntegerOperation> },
1748  { ::llvm::Instruction::FPExt, create_unop<FPExtOperation> },
1749  { ::llvm::Instruction::BitCast, create_unop<BitCastOperation> } });
1750 
1751  auto type = ctx.GetTypeConverter().ConvertLlvmType(*i->getType());
1752 
1753  auto op = ConvertValue(i->getOperand(0), tacs, ctx);
1754  auto srctype = typeConverter.ConvertLlvmType(*(isLaneWiseCast ? st->getScalarType() : st));
1755  auto dsttype = typeConverter.ConvertLlvmType(*(isLaneWiseCast ? dt->getScalarType() : dt));
1756 
1757  JLM_ASSERT(map.find(i->getOpcode()) != map.end());
1758  auto unop = map[i->getOpcode()](std::move(srctype), std::move(dsttype));
1759  JLM_ASSERT(is<rvsdg::UnaryOperation>(*unop));
1760 
1761  if (isLaneWiseCast)
1762  tacs.push_back(
1763  VectorUnaryOperation::create(*static_cast<rvsdg::UnaryOperation *>(unop.get()), op, type));
1764  else
1765  tacs.push_back(ThreeAddressCode::create(std::move(unop), { op }));
1766 
1767  return tacs.back()->result(0);
1768 }
1769 
1770 template<class INSTRUCTIONTYPE>
1771 static const Variable *
1772 convert(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
1773 {
1774  JLM_ASSERT(::llvm::isa<INSTRUCTIONTYPE>(instruction));
1775  return convert(::llvm::cast<INSTRUCTIONTYPE>(instruction), tacs, ctx);
1776 }
1777 
1778 static const Variable *
1780  ::llvm::Instruction * instruction,
1781  std::vector<std::unique_ptr<ThreeAddressCode>> & threeAddressCodes,
1782  Context & context)
1783 {
1784  switch (instruction->getOpcode())
1785  {
1786  case ::llvm::Instruction::Trunc:
1787  case ::llvm::Instruction::ZExt:
1788  case ::llvm::Instruction::UIToFP:
1789  case ::llvm::Instruction::SIToFP:
1790  case ::llvm::Instruction::SExt:
1791  case ::llvm::Instruction::PtrToInt:
1792  case ::llvm::Instruction::IntToPtr:
1793  case ::llvm::Instruction::FPTrunc:
1794  case ::llvm::Instruction::FPToSI:
1795  case ::llvm::Instruction::FPToUI:
1796  case ::llvm::Instruction::FPExt:
1797  case ::llvm::Instruction::BitCast:
1798  return convert_cast_instruction(instruction, threeAddressCodes, context);
1799  case ::llvm::Instruction::Add:
1800  case ::llvm::Instruction::And:
1801  case ::llvm::Instruction::AShr:
1802  case ::llvm::Instruction::Sub:
1803  case ::llvm::Instruction::UDiv:
1804  case ::llvm::Instruction::SDiv:
1805  case ::llvm::Instruction::URem:
1806  case ::llvm::Instruction::SRem:
1807  case ::llvm::Instruction::Shl:
1808  case ::llvm::Instruction::LShr:
1809  case ::llvm::Instruction::Or:
1810  case ::llvm::Instruction::Xor:
1811  case ::llvm::Instruction::Mul:
1812  case ::llvm::Instruction::FAdd:
1813  case ::llvm::Instruction::FSub:
1814  case ::llvm::Instruction::FMul:
1815  case ::llvm::Instruction::FDiv:
1816  case ::llvm::Instruction::FRem:
1817  return convert<::llvm::BinaryOperator>(instruction, threeAddressCodes, context);
1818  case ::llvm::Instruction::Ret:
1819  return convert_return_instruction(instruction, threeAddressCodes, context);
1820  case ::llvm::Instruction::Br:
1821  return ConvertBranchInstruction(instruction, threeAddressCodes, context);
1822  case ::llvm::Instruction::Switch:
1823  return convertSwitchInstruction(
1824  ::llvm::cast<::llvm::SwitchInst>(instruction),
1825  threeAddressCodes,
1826  context);
1827  case ::llvm::Instruction::Unreachable:
1828  return convert_unreachable_instruction(instruction, threeAddressCodes, context);
1829  case ::llvm::Instruction::FNeg:
1830  return convert<::llvm::UnaryOperator>(instruction, threeAddressCodes, context);
1831  case ::llvm::Instruction::ICmp:
1832  return convert<::llvm::ICmpInst>(instruction, threeAddressCodes, context);
1833  case ::llvm::Instruction::FCmp:
1834  return convert_fcmp_instruction(instruction, threeAddressCodes, context);
1835  case ::llvm::Instruction::Load:
1836  return convert_load_instruction(instruction, threeAddressCodes, context);
1837  case ::llvm::Instruction::Store:
1838  return convert_store_instruction(instruction, threeAddressCodes, context);
1839  case ::llvm::Instruction::PHI:
1840  return ConvertPhiInstruction(instruction, threeAddressCodes, context);
1841  case ::llvm::Instruction::GetElementPtr:
1842  return convert_getelementptr_instruction(instruction, threeAddressCodes, context);
1843  case ::llvm::Instruction::Call:
1844  return convertCallInstruction(
1845  *::llvm::dyn_cast<::llvm::CallInst>(instruction),
1846  threeAddressCodes,
1847  context);
1848  case ::llvm::Instruction::Select:
1849  return convert_select_instruction(instruction, threeAddressCodes, context);
1850  case ::llvm::Instruction::Alloca:
1851  return convert_alloca_instruction(instruction, threeAddressCodes, context);
1852  case ::llvm::Instruction::ExtractValue:
1853  return convert_extractvalue(instruction, threeAddressCodes, context);
1854  case ::llvm::Instruction::InsertValue:
1856  *::llvm::dyn_cast<::llvm::InsertValueInst>(instruction),
1857  threeAddressCodes,
1858  context);
1859  case ::llvm::Instruction::ExtractElement:
1860  return convert_extractelement_instruction(instruction, threeAddressCodes, context);
1861  case ::llvm::Instruction::ShuffleVector:
1862  return convert<::llvm::ShuffleVectorInst>(instruction, threeAddressCodes, context);
1863  case ::llvm::Instruction::InsertElement:
1864  return convert_insertelement_instruction(instruction, threeAddressCodes, context);
1865  case ::llvm::Instruction::Freeze:
1866  return convertFreezeInstruction(instruction, threeAddressCodes, context);
1867  default:
1868  throw std::runtime_error(util::strfmt(instruction->getOpcodeName(), " is not supported."));
1869  }
1870 }
1871 
1872 static std::vector<::llvm::PHINode *>
1873 convert_instructions(::llvm::Function & function, Context & ctx)
1874 {
1875  std::vector<::llvm::PHINode *> phis;
1876  ::llvm::ReversePostOrderTraversal<::llvm::Function *> rpotraverser(&function);
1877  for (auto & bb : rpotraverser)
1878  {
1879  for (auto & instruction : *bb)
1880  {
1881  tacsvector_t tacs;
1882  if (auto result = convertInstruction(&instruction, tacs, ctx))
1883  ctx.insert_value(&instruction, result);
1884 
1885  // When an LLVM PhiNode is converted to a jlm SsaPhiOperation, some of its operands may not be
1886  // ready. The created SsaPhiOperation therefore has no operands, but is instead added to a
1887  // list. Once all basic blocks have been converted, all SsaPhiOperations are revisited and
1888  // given operands.
1889  if (!tacs.empty() && is<SsaPhiOperation>(tacs.back()->operation()))
1890  {
1891  auto phi = ::llvm::dyn_cast<::llvm::PHINode>(&instruction);
1892  phis.push_back(phi);
1893  }
1894 
1895  ctx.get(bb)->append_last(tacs);
1896  }
1897  }
1898 
1899  return phis;
1900 }
1901 
1907 static void
1908 PatchPhiOperands(const std::vector<::llvm::PHINode *> & phis, Context & ctx)
1909 {
1910  for (const auto & phi : phis)
1911  {
1912  std::vector<ControlFlowGraphNode *> incomingNodes;
1913  std::vector<const Variable *> operands;
1914  for (size_t n = 0; n < phi->getNumOperands(); n++)
1915  {
1916  // In LLVM, phi instructions may have incoming basic blocks that are unreachable.
1917  // These are not visited during convert_basic_blocks, and thus do not have corresponding
1918  // jlm::llvm::basic_blocks. The SsaPhiOperation can safely ignore these, as they are dead.
1919  if (!ctx.has(phi->getIncomingBlock(n)))
1920  continue;
1921 
1922  // The LLVM phi instruction may have multiple operands with the same incoming cfg node.
1923  // When this happens in valid LLVM IR, all operands from the same basic block are identical.
1924  // We therefore skip any operands that reference already handled basic blocks.
1925  auto predecessor = ctx.get(phi->getIncomingBlock(n));
1926  if (std::find(incomingNodes.begin(), incomingNodes.end(), predecessor) != incomingNodes.end())
1927  continue;
1928 
1929  // Convert the operand value in the predecessor basic block, as that is where it is "used".
1930  tacsvector_t tacs;
1931  operands.push_back(ConvertValue(phi->getIncomingValue(n), tacs, ctx));
1932  predecessor->insert_before_branch(tacs);
1933  incomingNodes.push_back(predecessor);
1934  }
1935 
1936  JLM_ASSERT(operands.size() >= 1);
1937 
1938  auto phi_tac = util::assertedCast<const ThreeAddressCodeVariable>(ctx.lookup_value(phi))->tac();
1939  phi_tac->replace(
1940  SsaPhiOperation(std::move(incomingNodes), phi_tac->result(0)->Type()),
1941  operands);
1942  }
1943 }
1944 
1945 static BasicBlockMap
1946 convert_basic_blocks(::llvm::Function & f, ControlFlowGraph & cfg)
1947 {
1948  BasicBlockMap bbmap;
1949  ::llvm::ReversePostOrderTraversal<::llvm::Function *> rpotraverser(&f);
1950  for (auto & bb : rpotraverser)
1951  bbmap.Insert(bb, BasicBlock::create(cfg));
1952 
1953  return bbmap;
1954 }
1955 
1956 static std::unique_ptr<llvm::Argument>
1957 convert_argument(const ::llvm::Argument & argument, Context & ctx)
1958 {
1959  auto function = argument.getParent();
1960  auto name = argument.getName().str();
1961  auto type = ctx.GetTypeConverter().ConvertLlvmType(*argument.getType());
1962  auto attributes = convert_attributes(
1963  function->getAttributes().getParamAttrs(argument.getArgNo()),
1964  ctx.GetTypeConverter());
1965 
1966  return llvm::Argument::create(name, type, attributes);
1967 }
1968 
1969 static void
1971 {
1972  auto exitNode = cfg.exit();
1973 
1974  if (exitNode->NumInEdges() == 0)
1975  {
1976  /*
1977  LLVM can produce CFGs that have no incoming edge to the exit node. This can happen if
1978  endless loops are present in the code. For example, this code
1979 
1980  \code{.cpp}
1981  int foo()
1982  {
1983  while (1) {
1984  printf("foo\n");
1985  }
1986 
1987  return 0;
1988  }
1989  \endcode
1990 
1991  results in a JLM CFG with no incoming edge to the exit node.
1992 
1993  We solve this problem by finding the first SCC with no exit edge, i.e., an endless loop, and
1994  restructure it to an SCC with an exit edge to the CFG's exit node.
1995  */
1996  auto stronglyConnectedComponents = find_sccs(cfg);
1997  for (auto stronglyConnectedComponent : stronglyConnectedComponents)
1998  {
1999  auto sccStructure = StronglyConnectedComponentStructure::Create(stronglyConnectedComponent);
2000 
2001  if (sccStructure->NumExitEdges() == 0)
2002  {
2003  auto repetitionEdge = *sccStructure->RepetitionEdges().begin();
2004 
2005  auto basicBlock = BasicBlock::create(cfg);
2006 
2007  auto op = std::make_unique<rvsdg::ControlConstantOperation>(
2009  auto operand =
2010  basicBlock->append_last(ThreeAddressCode::create(std::move(op), {}))->result(0);
2011  basicBlock->append_last(BranchOperation::create(2, operand));
2012 
2013  basicBlock->add_outedge(exitNode);
2014  basicBlock->add_outedge(repetitionEdge->sink());
2015 
2016  repetitionEdge->divert(basicBlock);
2017  break;
2018  }
2019  }
2020  }
2021 
2022  if (exitNode->NumInEdges() == 1)
2023  return;
2024 
2025  /*
2026  We have multiple incoming edges to the exit node. Insert an empty basic block, divert all
2027  incoming edges to this block, and add an outgoing edge from this block to the exit node.
2028  */
2029  auto basicBlock = BasicBlock::create(cfg);
2030  exitNode->divert_inedges(basicBlock);
2031  basicBlock->add_outedge(exitNode);
2032 }
2033 
2034 static std::unique_ptr<ControlFlowGraph>
2035 create_cfg(::llvm::Function & f, Context & ctx)
2036 {
2037  auto node = static_cast<const FunctionVariable *>(ctx.lookup_value(&f))->function();
2038 
2039  auto add_arguments = [](const ::llvm::Function & f, ControlFlowGraph & cfg, Context & ctx)
2040  {
2041  auto node = static_cast<const FunctionVariable *>(ctx.lookup_value(&f))->function();
2042 
2043  size_t n = 0;
2044  for (const auto & arg : f.args())
2045  {
2046  auto argument = cfg.entry()->append_argument(convert_argument(arg, ctx));
2047  ctx.insert_value(&arg, argument);
2048  n++;
2049  }
2050 
2051  if (f.isVarArg())
2052  {
2053  JLM_ASSERT(n < node->fcttype().NumArguments());
2054  auto & type = node->fcttype().Arguments()[n++];
2055  cfg.entry()->append_argument(Argument::create("_varg_", type));
2056  }
2057  JLM_ASSERT(n < node->fcttype().NumArguments());
2058 
2059  auto & iotype = node->fcttype().Arguments()[n++];
2060  auto iostate = cfg.entry()->append_argument(Argument::create("_io_", iotype));
2061 
2062  auto & memtype = node->fcttype().Arguments()[n++];
2063  auto memstate = cfg.entry()->append_argument(Argument::create("_s_", memtype));
2064 
2065  JLM_ASSERT(n == node->fcttype().NumArguments());
2066  ctx.set_iostate(iostate);
2067  ctx.set_memory_state(memstate);
2068  };
2069 
2070  auto cfg = ControlFlowGraph::create(ctx.module());
2071 
2072  add_arguments(f, *cfg, ctx);
2073  auto bbmap = convert_basic_blocks(f, *cfg);
2074 
2075  /* create entry block */
2076  auto entry_block = BasicBlock::create(*cfg);
2077  cfg->exit()->divert_inedges(entry_block);
2078  entry_block->add_outedge(bbmap.LookupKey(&f.getEntryBlock()));
2079 
2080  /* add results */
2081  const ThreeAddressCodeVariable * result = nullptr;
2082  if (!f.getReturnType()->isVoidTy())
2083  {
2084  auto type = ctx.GetTypeConverter().ConvertLlvmType(*f.getReturnType());
2085  entry_block->append_last(UndefValueOperation::Create(type, "_r_"));
2086  result = entry_block->last()->result(0);
2087 
2088  JLM_ASSERT(node->fcttype().NumResults() == 3);
2089  JLM_ASSERT(result->type() == node->fcttype().ResultType(0));
2090  cfg->exit()->append_result(result);
2091  }
2092  cfg->exit()->append_result(ctx.iostate());
2093  cfg->exit()->append_result(ctx.memory_state());
2094 
2095  /* convert instructions */
2096  ctx.set_basic_block_map(std::move(bbmap));
2097  ctx.set_result(result);
2098  auto phis = convert_instructions(f, ctx);
2099  PatchPhiOperands(phis, ctx);
2100 
2102 
2103  // Merge basic blocks A -> B when possible
2104  straighten(*cfg);
2105  // Remove unreachable nodes
2106  prune(*cfg);
2107  return cfg;
2108 }
2109 
2110 static void
2111 convert_function(::llvm::Function & function, Context & ctx)
2112 {
2113  if (function.isDeclaration())
2114  return;
2115 
2116  auto fv = static_cast<const FunctionVariable *>(ctx.lookup_value(&function));
2117 
2118  ctx.set_node(fv->function());
2119  fv->function()->add_cfg(create_cfg(function, ctx));
2120  ctx.set_node(nullptr);
2121 }
2122 
2123 static const llvm::Linkage &
2124 convert_linkage(const ::llvm::GlobalValue::LinkageTypes & linkage)
2125 {
2126  static std::unordered_map<::llvm::GlobalValue::LinkageTypes, llvm::Linkage> map(
2127  { { ::llvm::GlobalValue::ExternalLinkage, llvm::Linkage::externalLinkage },
2128  { ::llvm::GlobalValue::AvailableExternallyLinkage,
2130  { ::llvm::GlobalValue::LinkOnceAnyLinkage, llvm::Linkage::linkOnceAnyLinkage },
2131  { ::llvm::GlobalValue::LinkOnceODRLinkage, llvm::Linkage::linkOnceOdrLinkage },
2132  { ::llvm::GlobalValue::WeakAnyLinkage, llvm::Linkage::weakAnyLinkage },
2133  { ::llvm::GlobalValue::WeakODRLinkage, llvm::Linkage::weakOdrLinkage },
2134  { ::llvm::GlobalValue::AppendingLinkage, llvm::Linkage::appendingLinkage },
2135  { ::llvm::GlobalValue::InternalLinkage, llvm::Linkage::internalLinkage },
2136  { ::llvm::GlobalValue::PrivateLinkage, llvm::Linkage::privateLinkage },
2137  { ::llvm::GlobalValue::ExternalWeakLinkage, llvm::Linkage::externalWeakLinkage },
2138  { ::llvm::GlobalValue::CommonLinkage, llvm::Linkage::commonLinkage } });
2139 
2140  JLM_ASSERT(map.find(linkage) != map.end());
2141  return map[linkage];
2142 }
2143 
2144 static void
2145 declare_globals(::llvm::Module & lm, Context & ctx)
2146 {
2147  auto create_data_node = [](const ::llvm::GlobalVariable & gv, Context & ctx)
2148  {
2149  auto name = gv.getName().str();
2150  auto constant = gv.isConstant();
2151  auto type = ctx.GetTypeConverter().ConvertLlvmType(*gv.getValueType());
2152  auto linkage = convert_linkage(gv.getLinkage());
2153  auto section = gv.getSection().str();
2154  const auto alignment = gv.getAlign().valueOrOne().value();
2155 
2156  return DataNode::Create(
2157  ctx.module().ipgraph(),
2158  name,
2159  type,
2160  linkage,
2161  std::move(section),
2162  constant,
2163  alignment);
2164  };
2165 
2166  auto create_function_node = [](const ::llvm::Function & f, Context & ctx)
2167  {
2168  auto name = f.getName().str();
2169  auto type = ctx.GetTypeConverter().ConvertFunctionType(*f.getFunctionType());
2170  auto linkage = convert_linkage(f.getLinkage());
2171  auto callingConvention = convertCallingConventionToJlm(f.getCallingConv());
2172  auto attributes = convert_attributes(f.getAttributes().getFnAttrs(), ctx.GetTypeConverter());
2173 
2174  return FunctionNode::create(
2175  ctx.module().ipgraph(),
2176  name,
2177  type,
2178  linkage,
2179  callingConvention,
2180  attributes);
2181  };
2182 
2183  for (auto & gv : lm.globals())
2184  {
2185  auto node = create_data_node(gv, ctx);
2186  ctx.insert_value(&gv, ctx.module().create_global_value(node));
2187  }
2188 
2189  for (auto & f : lm.getFunctionList())
2190  {
2191  if (f.isIntrinsic() && shouldIgnoreIntrinsic(f.getIntrinsicID()))
2192  continue;
2193 
2194  auto node = create_function_node(f, ctx);
2195  ctx.insert_value(&f, ctx.module().create_variable(node));
2196  }
2197 }
2198 
2199 static std::unique_ptr<DataNodeInit>
2201 {
2202  if (!gv.hasInitializer())
2203  return nullptr;
2204 
2205  auto init = gv.getInitializer();
2206  auto tacs = ConvertConstant(init, ctx);
2207  if (tacs.empty())
2208  return std::make_unique<DataNodeInit>(ctx.lookup_value(init));
2209 
2210  return std::make_unique<DataNodeInit>(std::move(tacs));
2211 }
2212 
2213 static void
2215 {
2216  auto v = static_cast<const GlobalValue *>(ctx.lookup_value(&gv));
2217 
2218  ctx.set_node(v->node());
2219  v->node()->set_initialization(create_initialization(gv, ctx));
2220  ctx.set_node(nullptr);
2221 }
2222 
2223 static void
2224 convert_globals(::llvm::Module & lm, Context & ctx)
2225 {
2226  for (auto & gv : lm.globals())
2227  convert_global_value(gv, ctx);
2228 
2229  for (auto & f : lm.getFunctionList())
2230  convert_function(f, ctx);
2231 }
2232 
2233 std::unique_ptr<InterProceduralGraphModule>
2234 ConvertLlvmModule(::llvm::Module & llvmModule)
2235 {
2236  auto ipgModule = InterProceduralGraphModule::create(
2237  util::FilePath(llvmModule.getSourceFileName()),
2238  llvmModule.getTargetTriple(),
2239  llvmModule.getDataLayoutStr());
2240 
2241  Context ctx(*ipgModule);
2242  declare_globals(llvmModule, ctx);
2243  convert_globals(llvmModule, ctx);
2244 
2245  return ipgModule;
2246 }
2247 
2248 }
static std::unique_ptr< ThreeAddressCode > createTac(std::shared_ptr< const rvsdg::Type > allocatedType, const Variable *count, size_t alignment)
Definition: alloca.hpp:88
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 std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *rhs, const Variable *lhs)
Definition: operators.hpp:119
void InsertTypeAttribute(const TypeAttribute &attribute)
Definition: attribute.hpp:344
void InsertStringAttribute(const StringAttribute &attribute)
Definition: attribute.hpp:350
void InsertEnumAttribute(const EnumAttribute &attribute)
Definition: attribute.hpp:332
void InsertIntAttribute(const IntAttribute &attribute)
Definition: attribute.hpp:338
@ None
No attributes have been set.
@ EndAttrKinds
Sentinel value useful for loops.
static BasicBlock * create(ControlFlowGraph &cfg)
Definition: basic-block.cpp:37
llvm::ThreeAddressCode * append_last(std::unique_ptr< llvm::ThreeAddressCode > tac)
static std::unique_ptr< llvm::ThreeAddressCode > create(size_t nalternatives, const Variable *operand)
Definition: operators.hpp:420
static std::unique_ptr< ThreeAddressCode > create(const Variable *function, std::shared_ptr< const rvsdg::FunctionType > functionType, CallingConvention callingConvention, AttributeList attributes, const std::vector< const Variable * > &arguments)
Definition: call.hpp:445
static std::unique_ptr< llvm::ThreeAddressCode > create(std::shared_ptr< const jlm::rvsdg::Type > type)
Definition: operators.hpp:1977
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &elements)
Definition: operators.hpp:1922
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &elements)
Definition: operators.hpp:656
static std::unique_ptr< ThreeAddressCode > Create(const std::vector< const Variable * > &elements)
Definition: operators.hpp:2386
static std::unique_ptr< llvm::ThreeAddressCode > create(const ::llvm::APFloat &constant, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:917
static std::unique_ptr< llvm::ThreeAddressCode > Create(std::shared_ptr< const rvsdg::Type > type)
Definition: operators.hpp:456
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &elements, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:1642
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &operands, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:2104
const ::llvm::BasicBlock * get(BasicBlock *bb) const noexcept
Context(InterProceduralGraphModule &im)
const llvm::Variable * lookup_value(const ::llvm::Value *value) const noexcept
llvm::Variable * memory_state() const noexcept
const llvm::Variable * result() const noexcept
bool has_value(const ::llvm::Value *value) const noexcept
llvm::Variable * iostate() const noexcept
const llvm::Variable * result_
void set_memory_state(llvm::Variable *state)
InterProceduralGraphModule & module() const noexcept
void set_iostate(llvm::Variable *state)
void set_result(const llvm::Variable *result)
void set_basic_block_map(BasicBlockMap bbmap)
BasicBlock * get(const ::llvm::BasicBlock *bb) const noexcept
InterProceduralGraphNode * node() const noexcept
void set_node(InterProceduralGraphNode *node) noexcept
llvm::Variable * memory_state_
bool has(BasicBlock *bb) const noexcept
std::unordered_map< const ::llvm::Value *, const llvm::Variable * > vmap_
void insert_value(const ::llvm::Value *value, const llvm::Variable *variable)
TypeConverter & GetTypeConverter() noexcept
bool has(const ::llvm::BasicBlock *bb) const noexcept
InterProceduralGraphNode * node_
InterProceduralGraphModule & module_
size_t index() const noexcept
Definition: cfg-node.hpp:66
ControlFlowGraphEdge * add_outedge(ControlFlowGraphNode *sink)
Definition: cfg-node.hpp:130
static std::unique_ptr< ControlFlowGraph > create(InterProceduralGraphModule &im)
Definition: cfg.hpp:267
ExitNode * exit() const noexcept
Definition: cfg.hpp:212
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 std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *vector, const llvm::Variable *index)
Definition: operators.hpp:2011
static std::unique_ptr< ThreeAddressCode > create(const Variable *aggregate, const std::vector< unsigned > &indices)
static std::unique_ptr< ThreeAddressCode > CreateTac(const Variable &multiplier, const Variable &multiplicand, const Variable &summand)
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *operand)
Definition: operators.hpp:1398
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *pointer, const std::vector< const Variable * > &memoryStates, const Variable *iOState)
Definition: operators.hpp:2558
static std::unique_ptr< llvm::ThreeAddressCode > createTac(const Variable &operand)
Definition: operators.hpp:1193
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< ThreeAddressCode > createTAC(const Variable *baseAddress, const std::vector< const Variable * > &offsets, std::shared_ptr< const rvsdg::Type > pointeeType)
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *vector, const llvm::Variable *value, const llvm::Variable *index)
Definition: operators.hpp:2146
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &aggregateOperand, const Variable &valueOperand, std::vector< unsigned > indices)
llvm::Variable * create_variable(std::shared_ptr< const jlm::rvsdg::Type > type, const std::string &name)
GlobalValue * create_global_value(DataNode *node)
static std::unique_ptr< InterProceduralGraphModule > create(const jlm::util::FilePath &sourceFilename, const std::string &targetTriple, const std::string &dataLayout)
InterProceduralGraph & ipgraph() noexcept
void add_dependency(const InterProceduralGraphNode *dep)
Definition: ipgraph.hpp:115
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *state, std::shared_ptr< const rvsdg::Type > loadedType, size_t alignment)
Definition: Load.hpp:444
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *iOState, const Variable *memoryState, std::shared_ptr< const rvsdg::Type > loadedType, size_t alignment)
Definition: Load.hpp:243
static std::unique_ptr< ThreeAddressCode > createTac(const Variable *size, const Variable *ioState)
Definition: operators.hpp:2485
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *destination, const Variable *source, const Variable *length, const std::vector< const Variable * > &memoryStates)
static std::unique_ptr< llvm::ThreeAddressCode > CreateThreeAddressCode(const Variable &destination, const Variable &source, const Variable &length, const Variable &ioState, const std::vector< const Variable * > &memoryStates)
static std::unique_ptr< ThreeAddressCode > createTac(const Variable &destination, const Variable &value, const Variable &length, const std::vector< const Variable * > &memoryStates)
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &operands)
static std::shared_ptr< const PointerType > Create()
Definition: types.cpp:45
static std::unique_ptr< llvm::ThreeAddressCode > Create(const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:1126
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *p, const llvm::Variable *t, const llvm::Variable *f)
Definition: operators.hpp:160
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *v1, const Variable *v2, const std::vector< int > &mask)
Definition: operators.hpp:2061
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(const Variable *address, const Variable *value, const Variable *state, size_t alignment)
Definition: Store.hpp:304
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *ioState, const Variable *memoryState, size_t alignment)
Definition: Store.hpp:439
static std::unique_ptr< StronglyConnectedComponentStructure > Create(const StronglyConnectedComponent &scc)
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition: tac.hpp:135
::llvm::PointerType * ConvertPointerType(const PointerType &type, ::llvm::LLVMContext &context)
::llvm::FunctionType * ConvertFunctionType(const rvsdg::FunctionType &functionType, ::llvm::LLVMContext &context)
std::shared_ptr< const rvsdg::Type > ConvertLlvmType(::llvm::Type &type)
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition: operators.hpp:1055
const jlm::rvsdg::Type & type() const noexcept
Definition: variable.hpp:56
const std::shared_ptr< const jlm::rvsdg::Type > Type() const noexcept
Definition: variable.hpp:62
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &arguments)
Definition: operators.hpp:1520
static std::unique_ptr< llvm::ThreeAddressCode > create(const rvsdg::BinaryOperation &binop, const llvm::Variable *op1, const llvm::Variable *op2, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:2333
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *p, const Variable *t, const Variable *f)
Definition: operators.hpp:208
static std::unique_ptr< llvm::ThreeAddressCode > create(const rvsdg::UnaryOperation &unop, const llvm::Variable *operand, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:2240
BitValueRepresentation sext(size_t nbits) const
BitValueRepresentation zext(size_t nbits) const
Unary operator.
Definition: unary.hpp:26
const V & LookupKey(const K &key) const
const K & LookupValue(const V &value) const
bool Insert(const K &key, const V &value)
bool HasKey(const K &key) const noexcept
bool HasValue(const V &value) const noexcept
#define JLM_ASSERT(x)
Definition: common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition: common.hpp:43
Global memory state passed between functions.
static const Variable * convertInstruction(::llvm::Instruction *instruction, std::vector< std::unique_ptr< ThreeAddressCode >> &threeAddressCodes, Context &context)
static const Variable * convert_fcmp_instruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
static rvsdg::BitValueRepresentation convert_apint(const ::llvm::APInt &value)
static void convert_globals(::llvm::Module &lm, Context &ctx)
static const Variable * convert_constantFP(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static std::unique_ptr< rvsdg::SimpleOperation > create_unop(std::shared_ptr< const rvsdg::Type > st, std::shared_ptr< const rvsdg::Type > dt)
ICmpPredicate convertICmpPredicateToJlm(::llvm::CmpInst::Predicate predicate)
Definition: operators.cpp:350
std::vector< StronglyConnectedComponent > find_sccs(const ControlFlowGraph &cfg)
static ControlFlowGraphNode * aggregate(ControlFlowGraphNode *, ControlFlowGraphNode *, AggregationMap &)
static const Variable * convert_insertelement_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static bool shouldIgnoreIntrinsic(::llvm::Intrinsic::ID intrinsicId)
static const Variable * convertMemSetCall(const ::llvm::IntrinsicInst &instruction, tacsvector_t &threeAddressCodes, Context &context)
static IntAttribute ConvertIntAttribute(const ::llvm::Attribute &attribute)
static const Variable * convert_globalAlias(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &, Context &)
std::vector< std::unique_ptr< llvm::ThreeAddressCode > > tacsvector_t
Definition: tac.hpp:202
static const Variable * AddIOBarrier(tacsvector_t &tacs, const Variable *operand, const Context &ctx)
static const Variable * convert_globalVariable(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
std::vector< const Variable * > convertCallArguments(const ::llvm::CallInst &callInstruction, tacsvector_t &threeAddressCodes, Context &context)
static BasicBlockMap convert_basic_blocks(::llvm::Function &f, ControlFlowGraph &cfg)
static const Variable * convert_extractvalue(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static const Variable * convertMallocCall(const ::llvm::CallInst &instruction, tacsvector_t &threeAddressCodes, Context &context)
static std::unique_ptr< rvsdg::BinaryOperation > ConvertFloatingPointBinaryOperation(const ::llvm::Instruction::BinaryOps binaryOperation, fpsize floatingPointSize)
static const Variable * convert_constantAggregateZero(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static TypeAttribute ConvertTypeAttribute(const ::llvm::Attribute &attribute, TypeConverter &typeConverter)
static std::unique_ptr< DataNodeInit > create_initialization(::llvm::GlobalVariable &gv, Context &ctx)
static const Variable * convert_extractelement_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static std::unique_ptr< rvsdg::BinaryOperation > ConvertIntegerBinaryOperation(const ::llvm::Instruction::BinaryOps binaryOperation, std::size_t numBits)
static const Variable * convert_constantVector(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static EnumAttribute ConvertEnumAttribute(const ::llvm::Attribute &attribute)
static const llvm::Linkage & convert_linkage(const ::llvm::GlobalValue::LinkageTypes &linkage)
std::unique_ptr< InterProceduralGraphModule > ConvertLlvmModule(::llvm::Module &llvmModule)
static bool isMallocCall(const ::llvm::CallInst &callInstruction)
static const Variable * ConvertBranchInstruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
jlm::llvm::CallingConvention convertCallingConventionToJlm(::llvm::CallingConv::ID cc)
static const Variable * convert_alloca_instruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_constantArray(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
const Variable * ConvertValueOrFunction(::llvm::Value *v, tacsvector_t &tacs, Context &ctx)
static const Variable * convert(const ::llvm::ICmpInst *instruction, tacsvector_t &tacs, Context &ctx)
static std::unique_ptr< rvsdg::BinaryOperation > ConvertPointerIcmpPredicate(const ::llvm::CmpInst::Predicate predicate)
static const Variable * convert_int_constant(::llvm::Constant *c, std::vector< std::unique_ptr< ThreeAddressCode >> &tacs, Context &)
static const Variable * ConvertPhiInstruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static void PatchPhiOperands(const std::vector<::llvm::PHINode * > &phis, Context &ctx)
static const Variable * convert_constantPointerNull(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convertFMulAddIntrinsic(const ::llvm::CallInst &instruction, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_constantExpr(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_store_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_cast_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static const Variable * createCall(const ::llvm::CallInst &callInstruction, tacsvector_t &threeAddressCodes, Context &context)
static const Variable * convertMemCpyCall(const ::llvm::IntrinsicInst *instruction, tacsvector_t &threeAddressCodes, Context &context)
static AttributeSet convert_attributes(const ::llvm::AttributeSet &as, TypeConverter &typeConverter)
static const Variable * convertInsertValueInstruction(const ::llvm::InsertValueInst &instruction, tacsvector_t &tacs, Context &context)
static std::unique_ptr< ControlFlowGraph > create_cfg(::llvm::Function &f, Context &ctx)
static const Variable * convert_blockAddress(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &, Context &)
static const Variable * convert_undefvalue(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_load_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static void declare_globals(::llvm::Module &lm, Context &ctx)
static StringAttribute ConvertStringAttribute(const ::llvm::Attribute &attribute)
static void convert_global_value(::llvm::GlobalVariable &gv, Context &ctx)
static const Variable * convertFreezeInstruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_constantDataVector(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_unreachable_instruction(::llvm::Instruction *i, tacsvector_t &, Context &ctx)
static const Variable * convert_getelementptr_instruction(::llvm::Instruction *inst, tacsvector_t &tacs, Context &ctx)
void straighten(ControlFlowGraph &cfg)
static const Variable * convertIntrinsicInstruction(const ::llvm::IntrinsicInst &intrinsicInstruction, tacsvector_t &threeAddressCodes, Context &context)
static const Variable * convertSwitchInstruction(::llvm::SwitchInst *switchInstruction, tacsvector_t &tacs, Context &ctx)
static std::vector<::llvm::PHINode * > convert_instructions(::llvm::Function &function, Context &ctx)
static bool IsVolatile(const ::llvm::Value &value)
static const Variable * convert_return_instruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
static const Variable * ConvertConstantStruct(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static bool isFreeCall(const ::llvm::CallInst &callInstruction)
static const Variable * convertCallInstruction(const ::llvm::CallInst &callInstruction, tacsvector_t &threeAddressCodes, Context &context)
static std::unique_ptr< llvm::Argument > convert_argument(const ::llvm::Argument &argument, Context &ctx)
static const Variable * convert_constantDataArray(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static void EnsureSingleInEdgeToExitNode(ControlFlowGraph &cfg)
static const Variable * convert_function(::llvm::Constant *c, tacsvector_t &tacs, Context &ctx)
Attribute::kind ConvertAttributeKind(const ::llvm::Attribute::AttrKind &kind)
static const Variable * convert_select_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
util::BijectiveMap< const ::llvm::BasicBlock *, BasicBlock * > BasicBlockMap
AttributeList convertAttributeList(const ::llvm::AttributeList &attributeList, const size_t numParameters, TypeConverter &typeConverter)
static const Variable * convertFreeCall(const ::llvm::CallInst &instruction, tacsvector_t &threeAddressCodes, Context &context)
static std::unique_ptr< rvsdg::BinaryOperation > ConvertIntegerIcmpPredicate(const ::llvm::CmpInst::Predicate predicate, const std::size_t numBits)
static const Variable * ConvertConstant(::llvm::Constant *, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &, Context &)
const Variable * ConvertValue(::llvm::Value *v, tacsvector_t &tacs, Context &ctx)
void prune(ControlFlowGraph &cfg)
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
Definition: node.hpp:1049
static std::string strfmt(Args... args)
Definition: strfmt.hpp:35