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