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 inline const Variable *
984convert_load_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
985{
986 JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Load);
987 auto instruction = static_cast<::llvm::LoadInst *>(i);
988
989 auto alignment = instruction->getAlign().value();
990 auto address = ConvertValue(instruction->getPointerOperand(), tacs, ctx);
991 auto loadedType = ctx.GetTypeConverter().ConvertLlvmType(*instruction->getType());
992
993 // We currently do not not support atomic load instructions
994 JLM_ASSERT(!instruction->isAtomic());
995
996 const ThreeAddressCodeVariable * loadedValue = nullptr;
997 const ThreeAddressCodeVariable * memoryState = nullptr;
998 const ThreeAddressCodeVariable * ioState = nullptr;
999 if (instruction->isVolatile())
1000 {
1001 auto loadVolatileTac = LoadVolatileOperation::Create(
1002 address,
1003 ctx.iostate(),
1004 ctx.memory_state(),
1005 loadedType,
1006 alignment);
1007 tacs.push_back(std::move(loadVolatileTac));
1008
1009 loadedValue = tacs.back()->result(0);
1010 ioState = tacs.back()->result(1);
1011 memoryState = tacs.back()->result(2);
1012 }
1013 else
1014 {
1015 address = AddIOBarrier(tacs, address, ctx);
1016 auto loadTac =
1017 LoadNonVolatileOperation::Create(address, ctx.memory_state(), loadedType, alignment);
1018 tacs.push_back(std::move(loadTac));
1019 loadedValue = tacs.back()->result(0);
1020 memoryState = tacs.back()->result(1);
1021 }
1022
1023 if (ioState)
1024 {
1025 tacs.push_back(AssignmentOperation::create(ioState, ctx.iostate()));
1026 }
1027 tacs.push_back(AssignmentOperation::create(memoryState, ctx.memory_state()));
1028
1029 return loadedValue;
1030}
1031
1032static inline const Variable *
1033convert_store_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1034{
1035 JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Store);
1036 auto instruction = static_cast<::llvm::StoreInst *>(i);
1037
1038 auto alignment = instruction->getAlign().value();
1039 auto address = ConvertValue(instruction->getPointerOperand(), tacs, ctx);
1040 auto value = ConvertValue(instruction->getValueOperand(), tacs, ctx);
1041
1042 // We currently do not not support atomic store instructions
1043 JLM_ASSERT(!instruction->isAtomic());
1044
1045 const ThreeAddressCodeVariable * memoryState = nullptr;
1046 const ThreeAddressCodeVariable * ioState = nullptr;
1047 if (instruction->isVolatile())
1048 {
1049 auto storeVolatileTac = StoreVolatileOperation::Create(
1050 address,
1051 value,
1052 ctx.iostate(),
1053 ctx.memory_state(),
1054 alignment);
1055 tacs.push_back(std::move(storeVolatileTac));
1056 ioState = tacs.back()->result(0);
1057 memoryState = tacs.back()->result(1);
1058 }
1059 else
1060 {
1061 address = AddIOBarrier(tacs, address, ctx);
1062 auto storeTac =
1063 StoreNonVolatileOperation::Create(address, value, ctx.memory_state(), alignment);
1064 tacs.push_back(std::move(storeTac));
1065 memoryState = tacs.back()->result(0);
1066 }
1067
1068 if (ioState)
1069 {
1070 tacs.push_back(AssignmentOperation::create(ioState, ctx.iostate()));
1071 }
1072 tacs.push_back(AssignmentOperation::create(memoryState, ctx.memory_state()));
1073
1074 return nullptr;
1075}
1076
1077static const Variable *
1078ConvertPhiInstruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1079{
1080 // Some of the blocks reaching this phi instruction might not be converted yet,
1081 // so some of the phi's operands may reference instructions that have not yet been converted.
1082 // For now, a SsaPhiOperation with no operands is created.
1083 // Once all basic blocks are converted, all SsaPhiOperations are revisited and given operands.
1084 auto type = ctx.GetTypeConverter().ConvertLlvmType(*i->getType());
1085 tacs.push_back(SsaPhiOperation::create({}, std::move(type)));
1086 return tacs.back()->result(0);
1087}
1088
1089static const Variable *
1090convert_getelementptr_instruction(::llvm::Instruction * inst, tacsvector_t & tacs, Context & ctx)
1091{
1092 JLM_ASSERT(::llvm::dyn_cast<const ::llvm::GetElementPtrInst>(inst));
1093 auto & typeConverter = ctx.GetTypeConverter();
1094 auto i = ::llvm::cast<::llvm::GetElementPtrInst>(inst);
1095
1096 std::vector<const Variable *> indices;
1097 auto base = ConvertValue(i->getPointerOperand(), tacs, ctx);
1098 for (auto it = i->idx_begin(); it != i->idx_end(); it++)
1099 indices.push_back(ConvertValue(*it, tacs, ctx));
1100
1101 auto pointeeType = typeConverter.ConvertLlvmType(*i->getSourceElementType());
1102
1103 tacs.push_back(GetElementPtrOperation::createTAC(base, indices, pointeeType));
1104
1105 return tacs.back()->result(0);
1106}
1107
1108static const Variable *
1110 const ::llvm::CallInst & instruction,
1111 tacsvector_t & threeAddressCodes,
1112 Context & context)
1113{
1114 auto globalMemoryState = context.memory_state();
1115 const auto globalIOState = context.iostate();
1116
1117 const auto size = ConvertValue(instruction.getArgOperand(0), threeAddressCodes, context);
1118
1119 threeAddressCodes.push_back(MallocOperation::createTac(size, globalIOState));
1120 const auto mallocAddress = threeAddressCodes.back()->result(0);
1121 const auto mallocIOState = threeAddressCodes.back()->result(1);
1122 auto mallocMemoryState = threeAddressCodes.back()->result(2);
1123
1124 threeAddressCodes.push_back(AssignmentOperation::create(mallocIOState, globalIOState));
1125
1126 threeAddressCodes.push_back(
1127 MemoryStateMergeOperation::Create({ mallocMemoryState, globalMemoryState }));
1128 threeAddressCodes.push_back(
1129 AssignmentOperation::create(threeAddressCodes.back()->result(0), globalMemoryState));
1130
1131 return mallocAddress;
1132}
1133
1134static const Variable *
1136 const ::llvm::CallInst & instruction,
1137 tacsvector_t & threeAddressCodes,
1138 Context & context)
1139{
1140 const auto ioState = context.iostate();
1141 auto memstate = context.memory_state();
1142
1143 const auto pointer = ConvertValue(instruction.getArgOperand(0), threeAddressCodes, context);
1144
1145 threeAddressCodes.push_back(FreeOperation::Create(pointer, { memstate }, ioState));
1146 const auto & freeThreeAddressCode = *threeAddressCodes.back().get();
1147
1148 threeAddressCodes.push_back(
1149 AssignmentOperation::create(freeThreeAddressCode.result(0), memstate));
1150 threeAddressCodes.push_back(AssignmentOperation::create(freeThreeAddressCode.result(1), ioState));
1151
1152 return nullptr;
1153}
1154
1163static bool
1164IsVolatile(const ::llvm::Value & value)
1165{
1166 const auto constant = ::llvm::dyn_cast<const ::llvm::ConstantInt>(&value);
1167 JLM_ASSERT(constant != nullptr && constant->getType()->getIntegerBitWidth() == 1);
1168
1169 const auto apInt = constant->getValue();
1170 JLM_ASSERT(apInt.isZero() || apInt.isOne());
1171
1172 return apInt.isOne();
1173}
1174
1175static const Variable *
1177 const ::llvm::IntrinsicInst * instruction,
1178 tacsvector_t & threeAddressCodes,
1179 Context & context)
1180{
1181 JLM_ASSERT(
1182 instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy
1183 || instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy_inline
1184 || instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy_element_unordered_atomic);
1185
1186 if (instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy_inline)
1187 throw std::logic_error("Unhandled memcpy_inline intrinsic.");
1188 if (instruction->getIntrinsicID() == ::llvm::Intrinsic::memcpy_element_unordered_atomic)
1189 throw std::logic_error("Unhandled memcpy_element_unordered_atomic intrinsic.");
1190
1191 const auto ioState = context.iostate();
1192 auto memoryState = context.memory_state();
1193
1194 const auto destination = ConvertValue(instruction->getArgOperand(0), threeAddressCodes, context);
1195 const auto source = ConvertValue(instruction->getArgOperand(1), threeAddressCodes, context);
1196 const auto length = ConvertValue(instruction->getArgOperand(2), threeAddressCodes, context);
1197
1198 if (IsVolatile(*instruction->getArgOperand(3)))
1199 {
1200 threeAddressCodes.push_back(MemCpyVolatileOperation::CreateThreeAddressCode(
1201 *destination,
1202 *source,
1203 *length,
1204 *ioState,
1205 { memoryState }));
1206 const auto & memCpyVolatileTac = *threeAddressCodes.back();
1207 threeAddressCodes.push_back(AssignmentOperation::create(memCpyVolatileTac.result(0), ioState));
1208 threeAddressCodes.push_back(
1209 AssignmentOperation::create(memCpyVolatileTac.result(1), memoryState));
1210 }
1211 else
1212 {
1213 threeAddressCodes.push_back(
1214 MemCpyNonVolatileOperation::create(destination, source, length, { memoryState }));
1215 threeAddressCodes.push_back(
1216 AssignmentOperation::create(threeAddressCodes.back()->result(0), memoryState));
1217 }
1218
1219 return nullptr;
1220}
1221
1222static const Variable *
1224 const ::llvm::IntrinsicInst & instruction,
1225 tacsvector_t & threeAddressCodes,
1226 Context & context)
1227{
1228 JLM_ASSERT(
1229 instruction.getIntrinsicID() == ::llvm::Intrinsic::memset
1230 || instruction.getIntrinsicID() == ::llvm::Intrinsic::memset_inline
1231 || instruction.getIntrinsicID() == ::llvm::Intrinsic::memset_element_unordered_atomic);
1232
1233 if (instruction.getIntrinsicID() == ::llvm::Intrinsic::memset_inline)
1234 throw std::logic_error("Unhandled memset_inline intrinsic.");
1235 if (instruction.getIntrinsicID() == ::llvm::Intrinsic::memset_element_unordered_atomic)
1236 throw std::logic_error("Unhandled memset_element_unordered_atomic intrinsic.");
1237
1238 auto memoryState = context.memory_state();
1239
1240 const auto destination = ConvertValue(instruction.getArgOperand(0), threeAddressCodes, context);
1241 const auto value = ConvertValue(instruction.getArgOperand(1), threeAddressCodes, context);
1242 const auto length = ConvertValue(instruction.getArgOperand(2), threeAddressCodes, context);
1243
1244 if (IsVolatile(*instruction.getArgOperand(3)))
1245 {
1246 throw std::logic_error("Unhandled volatile memset intrinsic.");
1247 }
1248 else
1249 {
1250 threeAddressCodes.push_back(
1251 MemSetNonVolatileOperation::createTac(*destination, *value, *length, { memoryState }));
1252 threeAddressCodes.push_back(
1253 AssignmentOperation::create(threeAddressCodes.back()->result(0), memoryState));
1254 }
1255
1256 return nullptr;
1257}
1258
1259static const Variable *
1261 const ::llvm::IntrinsicInst & instruction,
1262 tacsvector_t & threeAddressCodes,
1263 Context & context)
1264{
1265 JLM_ASSERT(
1266 instruction.getIntrinsicID() == ::llvm::Intrinsic::memmove
1267 || instruction.getIntrinsicID() == ::llvm::Intrinsic::memmove_element_unordered_atomic);
1268
1269 if (instruction.getIntrinsicID() == ::llvm::Intrinsic::memmove_element_unordered_atomic)
1270 throw std::logic_error("Unhandled memmove_element_unordered_atomic intrinsic.");
1271
1272 auto memoryState = context.memory_state();
1273
1274 const auto destOperand = ConvertValue(instruction.getArgOperand(0), threeAddressCodes, context);
1275 const auto srcOperand = ConvertValue(instruction.getArgOperand(1), threeAddressCodes, context);
1276 const auto lengthOperand = ConvertValue(instruction.getArgOperand(2), threeAddressCodes, context);
1277
1278 if (IsVolatile(*instruction.getArgOperand(3)))
1279 {
1280 throw std::logic_error("Unhandled volatile memmove intrinsic.");
1281 }
1282
1283 threeAddressCodes.push_back(MemMoveNonVolatileOperation::createTac(
1284 *destOperand,
1285 *srcOperand,
1286 *lengthOperand,
1287 { memoryState }));
1288 threeAddressCodes.push_back(
1289 AssignmentOperation::create(threeAddressCodes.back()->result(0), memoryState));
1290
1291 return nullptr;
1292}
1293
1294static bool
1295isMallocCall(const ::llvm::CallInst & callInstruction)
1296{
1297 const auto function = callInstruction.getCalledFunction();
1298 return function && function->getName() == "malloc";
1299}
1300
1301static bool
1302isFreeCall(const ::llvm::CallInst & callInstruction)
1303{
1304 const auto function = callInstruction.getCalledFunction();
1305 return function && function->getName() == "free";
1306}
1307
1308static const Variable *
1309convertFMulAddIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & ctx)
1310{
1311 const auto multiplier = ConvertValue(instruction.getArgOperand(0), tacs, ctx);
1312 const auto multiplicand = ConvertValue(instruction.getArgOperand(1), tacs, ctx);
1313 const auto summand = ConvertValue(instruction.getArgOperand(2), tacs, ctx);
1314 tacs.push_back(FMulAddIntrinsicOperation::CreateTac(*multiplier, *multiplicand, *summand));
1315
1316 return tacs.back()->result(0);
1317}
1318
1319static const Variable *
1320convertCeilIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1321{
1322 const auto operand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1323 tacs.push_back(CeilOperation::createTac(*operand));
1324
1325 return tacs.back()->result(0);
1326}
1327
1328static const Variable *
1329convertRIntIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1330{
1331 const auto operand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1332 tacs.push_back(RIntOperation::createTac(*operand));
1333
1334 return tacs.back()->result(0);
1335}
1336
1337static const Variable *
1338convertTruncIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1339{
1340 const auto operand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1341 tacs.push_back(TruncIntrinsicOperation::createTac(*operand));
1342
1343 return tacs.back()->result(0);
1344}
1345
1346static const Variable *
1347convertFloorIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1348{
1349 const auto operand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1350 tacs.push_back(FloorOperation::createTac(*operand));
1351
1352 return tacs.back()->result(0);
1353}
1354
1355static const Variable *
1356convertRoundIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1357{
1358 const auto operand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1359 tacs.push_back(RoundOperation::createTac(*operand));
1360
1361 return tacs.back()->result(0);
1362}
1363
1364static const Variable *
1365convertFShlIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1366{
1367 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1368 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1369 const auto operand3 = ConvertValue(instruction.getArgOperand(2), tacs, context);
1370 tacs.push_back(FShlOperation::createTac(*operand1, *operand2, *operand3));
1371
1372 return tacs.back()->result(0);
1373}
1374
1375static const Variable *
1376convertSMaxIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1377{
1378 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1379 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1380 tacs.push_back(SMaxOperation::createTac(*operand1, *operand2));
1381
1382 return tacs.back()->result(0);
1383}
1384
1385static const Variable *
1386convertUMaxIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1387{
1388 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1389 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1390 tacs.push_back(UMaxOperation::createTac(*operand1, *operand2));
1391
1392 return tacs.back()->result(0);
1393}
1394
1395static const Variable *
1396convertSMinIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1397{
1398 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1399 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1400 tacs.push_back(SMinOperation::createTac(*operand1, *operand2));
1401
1402 return tacs.back()->result(0);
1403}
1404
1405static const Variable *
1406convertUMinIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1407{
1408 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1409 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1410 tacs.push_back(UMinOperation::createTac(*operand1, *operand2));
1411
1412 return tacs.back()->result(0);
1413}
1414
1415static const Variable *
1417 const ::llvm::CallInst & instruction,
1418 tacsvector_t & tacs,
1419 Context & context)
1420{
1421 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1422 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1423 tacs.push_back(CopysignOperation::createTac(*operand1, *operand2));
1424
1425 return tacs.back()->result(0);
1426}
1427
1428static const Variable *
1430 const ::llvm::CallInst & instruction,
1431 tacsvector_t & tacs,
1432 Context & context)
1433{
1434 const auto ptrOperand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1435 const auto maskOperand = ConvertValue(instruction.getArgOperand(1), tacs, context);
1436 tacs.push_back(PtrMaskOperation::createTac(*ptrOperand, *maskOperand));
1437
1438 return tacs.back()->result(0);
1439}
1440
1441static const Variable *
1442convertFAbsIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1443{
1444 const auto operand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1445 tacs.push_back(FAbsOperation::createTac(*operand));
1446
1447 return tacs.back()->result(0);
1448}
1449
1450static const Variable *
1451convertAbsIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1452{
1453 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1454 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1455 tacs.push_back(AbsOperation::createTac(*operand1, *operand2));
1456
1457 return tacs.back()->result(0);
1458}
1459
1460static const Variable *
1461convertBSwapIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1462{
1463 const auto operand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1464 tacs.push_back(BSwapOperation::createTac(*operand));
1465
1466 return tacs.back()->result(0);
1467}
1468
1469static const Variable *
1470convertCtlzIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1471{
1472 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1473 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1474 tacs.push_back(CtlzOperation::createTac(*operand1, *operand2));
1475
1476 return tacs.back()->result(0);
1477}
1478
1479static const Variable *
1480convertCttzIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1481{
1482 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1483 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1484 tacs.push_back(CttzOperation::createTac(*operand1, *operand2));
1485
1486 return tacs.back()->result(0);
1487}
1488
1489static const Variable *
1490convertCtpopIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & context)
1491{
1492 const auto operand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1493 tacs.push_back(CtpopOperation::createTac(*operand));
1494
1495 return tacs.back()->result(0);
1496}
1497
1498static const Variable *
1500 const ::llvm::CallInst & instruction,
1501 tacsvector_t & tacs,
1502 Context & context)
1503{
1504 const auto operand = ConvertValue(instruction.getArgOperand(0), tacs, context);
1505 tacs.push_back(IsConstantOperation::createTac(*operand));
1506
1507 return tacs.back()->result(0);
1508}
1509
1510static const Variable *
1512 const ::llvm::CallInst & instruction,
1513 tacsvector_t & tacs,
1514 Context & context)
1515{
1516 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1517 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1518 tacs.push_back(IsFPClassOperation::createTac(*operand1, *operand2));
1519
1520 return tacs.back()->result(0);
1521}
1522
1523static const Variable *
1525 const ::llvm::CallInst & instruction,
1526 tacsvector_t & tacs,
1527 Context & context)
1528{
1529 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1530 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1531 tacs.push_back(SAddWithOverflowOperation::createTac(*operand1, *operand2));
1532
1533 return tacs.back()->result(0);
1534}
1535
1536static const Variable *
1538 const ::llvm::CallInst & instruction,
1539 tacsvector_t & tacs,
1540 Context & context)
1541{
1542 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1543 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1544 tacs.push_back(UAddWithOverflowOperation::createTac(*operand1, *operand2));
1545
1546 return tacs.back()->result(0);
1547}
1548
1549static const Variable *
1551 const ::llvm::CallInst & instruction,
1552 tacsvector_t & tacs,
1553 Context & context)
1554{
1555 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1556 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1557 tacs.push_back(SSubWithOverflowOperation::createTac(*operand1, *operand2));
1558
1559 return tacs.back()->result(0);
1560}
1561
1562static const Variable *
1564 const ::llvm::CallInst & instruction,
1565 tacsvector_t & tacs,
1566 Context & context)
1567{
1568 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1569 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1570 tacs.push_back(SMulWithOverflowOperation::createTac(*operand1, *operand2));
1571
1572 return tacs.back()->result(0);
1573}
1574
1575static const Variable *
1577 const ::llvm::CallInst & instruction,
1578 tacsvector_t & tacs,
1579 Context & context)
1580{
1581 const auto operand1 = ConvertValue(instruction.getArgOperand(0), tacs, context);
1582 const auto operand2 = ConvertValue(instruction.getArgOperand(1), tacs, context);
1583 tacs.push_back(UMulWithOverflowOperation::createTac(*operand1, *operand2));
1584
1585 return tacs.back()->result(0);
1586}
1587
1588std::vector<const Variable *>
1590 const ::llvm::CallInst & callInstruction,
1591 tacsvector_t & threeAddressCodes,
1592 Context & context)
1593{
1594 const auto functionType = callInstruction.getFunctionType();
1595
1596 std::vector<const Variable *> arguments;
1597 for (size_t n = 0; n < functionType->getNumParams(); n++)
1598 arguments.push_back(ConvertValue(callInstruction.getArgOperand(n), threeAddressCodes, context));
1599
1600 if (functionType->isVarArg())
1601 {
1602 std::vector<const Variable *> variableArguments;
1603 for (size_t n = functionType->getNumParams(); n < callInstruction.getNumOperands() - 1; n++)
1604 variableArguments.push_back(
1605 ConvertValue(callInstruction.getArgOperand(n), threeAddressCodes, context));
1606
1607 threeAddressCodes.push_back(VariadicArgumentListOperation::create(variableArguments));
1608 arguments.push_back(threeAddressCodes.back()->result(0));
1609 }
1610
1611 arguments.push_back(context.iostate());
1612 arguments.push_back(context.memory_state());
1613
1614 return arguments;
1615}
1616
1617static const Variable *
1619 const ::llvm::CallInst & callInstruction,
1620 tacsvector_t & threeAddressCodes,
1621 Context & context)
1622{
1623 const auto functionType = callInstruction.getFunctionType();
1624
1625 auto convertedFunctionType = context.GetTypeConverter().ConvertFunctionType(*functionType);
1626 const auto arguments = convertCallArguments(callInstruction, threeAddressCodes, context);
1627 const auto callingConvention = convertCallingConventionToJlm(callInstruction.getCallingConv());
1628 auto attributes = convertAttributeList(
1629 callInstruction.getAttributes(),
1630 callInstruction.arg_size(),
1631 context.GetTypeConverter());
1632
1633 const Variable * callee =
1634 ConvertValueOrFunction(callInstruction.getCalledOperand(), threeAddressCodes, context);
1635 // Llvm does not distinguish between "function objects" and
1636 // "pointers to functions" while we need to be precise in modeling.
1637 // If the called object is a function object, then we can just
1638 // feed it to the call operator directly, otherwise we have
1639 // to cast it into a function object.
1640 if (is<PointerType>(*callee->Type()))
1641 {
1642 std::unique_ptr<ThreeAddressCode> callee_cast = ThreeAddressCode::create(
1643 std::make_unique<PointerToFunctionOperation>(convertedFunctionType),
1644 { callee });
1645 callee = callee_cast->result(0);
1646 threeAddressCodes.push_back(std::move(callee_cast));
1647 }
1648 else if (auto fntype = std::dynamic_pointer_cast<const rvsdg::FunctionType>(callee->Type()))
1649 {
1650 // Llvm also allows argument type mismatches if the function
1651 // features varargs. The code here could be made more precise by
1652 // validating and accepting only vararg-related mismatches.
1653 if (*convertedFunctionType != *fntype)
1654 {
1655 // Since vararg passing is not modeled explicitly, simply hide the
1656 // argument mismatch via pointer casts.
1657 std::unique_ptr<ThreeAddressCode> ptrCast = ThreeAddressCode::create(
1658 std::make_unique<FunctionToPointerOperation>(fntype),
1659 { callee });
1660 std::unique_ptr<ThreeAddressCode> fnCast = ThreeAddressCode::create(
1661 std::make_unique<PointerToFunctionOperation>(convertedFunctionType),
1662 { ptrCast->result(0) });
1663 callee = fnCast->result(0);
1664 threeAddressCodes.push_back(std::move(ptrCast));
1665 threeAddressCodes.push_back(std::move(fnCast));
1666 }
1667 }
1668 else
1669 {
1670 throw std::runtime_error("Unexpected callee type: " + callee->Type()->debug_string());
1671 }
1672
1673 auto call = CallOperation::create(
1674 callee,
1675 convertedFunctionType,
1676 callingConvention,
1677 std::move(attributes),
1678 arguments);
1679
1680 const auto result = call->result(0);
1681 const auto ioState = call->result(call->nresults() - 2);
1682 const auto memoryState = call->result(call->nresults() - 1);
1683
1684 threeAddressCodes.push_back(std::move(call));
1685 threeAddressCodes.push_back(AssignmentOperation::create(ioState, context.iostate()));
1686 threeAddressCodes.push_back(AssignmentOperation::create(memoryState, context.memory_state()));
1687
1688 return result;
1689}
1690
1697static bool
1698shouldIgnoreIntrinsic(::llvm::Intrinsic::ID intrinsicId)
1699{
1700 switch (intrinsicId)
1701 {
1702 // These intrinsics are ignored because jlm is currently unable to handle them. They only keep
1703 // their arguments live as well as are otherwise converted to an ordinary call
1704 // to an external function, serving as transformation bottleneck in the code.
1705 case ::llvm::Intrinsic::assume:
1706 case ::llvm::Intrinsic::expect:
1707 case ::llvm::Intrinsic::prefetch:
1708
1709 // These intrinsics are ignored because they take pointers to local variables,
1710 // reducing the precision of alias analysis unless specifically handled
1711 case ::llvm::Intrinsic::lifetime_start:
1712 case ::llvm::Intrinsic::lifetime_end:
1713
1714 // This intrinsic is ignored because it takes a parameter of type "metadata"
1715 case ::llvm::Intrinsic::experimental_noalias_scope_decl:
1716 return true;
1717
1718 default:
1719 return false;
1720 }
1721}
1722
1723static const Variable *
1725 const ::llvm::IntrinsicInst & intrinsicInstruction,
1726 tacsvector_t & threeAddressCodes,
1727 Context & context)
1728{
1729 switch (const auto intrinsicId = intrinsicInstruction.getIntrinsicID())
1730 {
1731 case ::llvm::Intrinsic::abs:
1732 return convertAbsIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1733 case ::llvm::Intrinsic::assume:
1734 {
1735 JLM_ASSERT(shouldIgnoreIntrinsic(intrinsicId));
1736 return nullptr;
1737 }
1738 case ::llvm::Intrinsic::bswap:
1739 return convertBSwapIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1740 case ::llvm::Intrinsic::ceil:
1741 return convertCeilIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1742 case ::llvm::Intrinsic::copysign:
1743 return convertCopysignIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1744 case ::llvm::Intrinsic::ctlz:
1745 return convertCtlzIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1746 case ::llvm::Intrinsic::cttz:
1747 return convertCttzIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1748 case ::llvm::Intrinsic::ctpop:
1749 return convertCtpopIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1750 case ::llvm::Intrinsic::expect:
1751 {
1752 JLM_ASSERT(shouldIgnoreIntrinsic(intrinsicId));
1753 return ConvertValue(intrinsicInstruction.getArgOperand(0), threeAddressCodes, context);
1754 }
1755 case ::llvm::Intrinsic::experimental_noalias_scope_decl:
1756 {
1757 JLM_ASSERT(shouldIgnoreIntrinsic(intrinsicId));
1758 return nullptr;
1759 }
1760 case ::llvm::Intrinsic::fabs:
1761 return convertFAbsIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1762 case ::llvm::Intrinsic::floor:
1763 return convertFloorIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1764 case ::llvm::Intrinsic::fmuladd:
1765 return convertFMulAddIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1766 case ::llvm::Intrinsic::fshl:
1767 return convertFShlIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1768 case ::llvm::Intrinsic::is_constant:
1769 return convertIsConstantIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1770 case ::llvm::Intrinsic::is_fpclass:
1771 return convertIsFPClassIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1772 case ::llvm::Intrinsic::lifetime_start:
1773 case ::llvm::Intrinsic::lifetime_end:
1774 {
1775 JLM_ASSERT(shouldIgnoreIntrinsic(intrinsicId));
1776 return nullptr;
1777 }
1778 case ::llvm::Intrinsic::memcpy:
1779 case ::llvm::Intrinsic::memcpy_inline:
1780 case ::llvm::Intrinsic::memcpy_element_unordered_atomic:
1781 return convertMemCpyCall(&intrinsicInstruction, threeAddressCodes, context);
1782 case ::llvm::Intrinsic::memmove:
1783 case ::llvm::Intrinsic::memmove_element_unordered_atomic:
1784 return convertMemMoveCall(intrinsicInstruction, threeAddressCodes, context);
1785 case ::llvm::Intrinsic::memset:
1786 case ::llvm::Intrinsic::memset_inline:
1787 case ::llvm::Intrinsic::memset_element_unordered_atomic:
1788 return convertMemSetCall(intrinsicInstruction, threeAddressCodes, context);
1789 case ::llvm::Intrinsic::prefetch:
1790 {
1791 JLM_ASSERT(shouldIgnoreIntrinsic(intrinsicId));
1792 return nullptr;
1793 }
1794 case ::llvm::Intrinsic::ptrmask:
1795 return convertPtrMaskIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1796 case ::llvm::Intrinsic::rint:
1797 return convertRIntIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1798 case ::llvm::Intrinsic::round:
1799 return convertRoundIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1800 case ::llvm::Intrinsic::sadd_with_overflow:
1801 return convertSAddWithOverflowIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1802 case ::llvm::Intrinsic::smax:
1803 return convertSMaxIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1804 case ::llvm::Intrinsic::smul_with_overflow:
1805 return convertSMulWithOverflowIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1806 case ::llvm::Intrinsic::smin:
1807 return convertSMinIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1808 case ::llvm::Intrinsic::ssub_with_overflow:
1809 return convertSSubWithOverflowIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1810 case ::llvm::Intrinsic::trunc:
1811 return convertTruncIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1812 case ::llvm::Intrinsic::uadd_with_overflow:
1813 return convertUAddWithOverflowIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1814 case ::llvm::Intrinsic::umax:
1815 return convertUMaxIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1816 case ::llvm::Intrinsic::umin:
1817 return convertUMinIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1818 case ::llvm::Intrinsic::umul_with_overflow:
1819 return convertUMulWithOverflowIntrinsic(intrinsicInstruction, threeAddressCodes, context);
1820 default:
1821 {
1822 JLM_ASSERT(!shouldIgnoreIntrinsic(intrinsicId));
1823 return createCall(intrinsicInstruction, threeAddressCodes, context);
1824 }
1825 }
1826}
1827
1828static const Variable *
1830 const ::llvm::CallInst & callInstruction,
1831 tacsvector_t & threeAddressCodes,
1832 Context & context)
1833{
1834 if (const auto intrinsicInstruction = ::llvm::dyn_cast<::llvm::IntrinsicInst>(&callInstruction))
1835 return convertIntrinsicInstruction(*intrinsicInstruction, threeAddressCodes, context);
1836
1837 if (isMallocCall(callInstruction))
1838 return convertMallocCall(callInstruction, threeAddressCodes, context);
1839
1840 if (isFreeCall(callInstruction))
1841 return convertFreeCall(callInstruction, threeAddressCodes, context);
1842
1843 return createCall(callInstruction, threeAddressCodes, context);
1844}
1845
1846static inline const Variable *
1847convert_select_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1848{
1849 JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Select);
1850 auto instruction = static_cast<::llvm::SelectInst *>(i);
1851
1852 auto p = ConvertValue(instruction->getCondition(), tacs, ctx);
1853 auto t = ConvertValue(instruction->getTrueValue(), tacs, ctx);
1854 auto f = ConvertValue(instruction->getFalseValue(), tacs, ctx);
1855
1856 if (i->getType()->isVectorTy())
1857 tacs.push_back(VectorSelectOperation::create(p, t, f));
1858 else
1859 tacs.push_back(SelectOperation::create(p, t, f));
1860
1861 return tacs.back()->result(0);
1862}
1863
1864static std::unique_ptr<rvsdg::BinaryOperation>
1866 const ::llvm::Instruction::BinaryOps binaryOperation,
1867 std::size_t numBits)
1868{
1869 switch (binaryOperation)
1870 {
1871 case ::llvm::Instruction::Add:
1872 return std::make_unique<IntegerAddOperation>(numBits);
1873 case ::llvm::Instruction::And:
1874 return std::make_unique<IntegerAndOperation>(numBits);
1875 case ::llvm::Instruction::AShr:
1876 return std::make_unique<IntegerAShrOperation>(numBits);
1877 case ::llvm::Instruction::LShr:
1878 return std::make_unique<IntegerLShrOperation>(numBits);
1879 case ::llvm::Instruction::Mul:
1880 return std::make_unique<IntegerMulOperation>(numBits);
1881 case ::llvm::Instruction::Or:
1882 return std::make_unique<IntegerOrOperation>(numBits);
1883 case ::llvm::Instruction::SDiv:
1884 return std::make_unique<IntegerSDivOperation>(numBits);
1885 case ::llvm::Instruction::Shl:
1886 return std::make_unique<IntegerShlOperation>(numBits);
1887 case ::llvm::Instruction::SRem:
1888 return std::make_unique<IntegerSRemOperation>(numBits);
1889 case ::llvm::Instruction::Sub:
1890 return std::make_unique<IntegerSubOperation>(numBits);
1891 case ::llvm::Instruction::UDiv:
1892 return std::make_unique<IntegerUDivOperation>(numBits);
1893 case ::llvm::Instruction::URem:
1894 return std::make_unique<IntegerURemOperation>(numBits);
1895 case ::llvm::Instruction::Xor:
1896 return std::make_unique<IntegerXorOperation>(numBits);
1897 default:
1898 JLM_UNREACHABLE("ConvertIntegerBinaryOperation: Unsupported integer binary operation");
1899 }
1900}
1901
1902static std::unique_ptr<rvsdg::BinaryOperation>
1904 const ::llvm::Instruction::BinaryOps binaryOperation,
1905 fpsize floatingPointSize)
1906{
1907 switch (binaryOperation)
1908 {
1909 case ::llvm::Instruction::FAdd:
1910 return std::make_unique<FBinaryOperation>(fpop::add, floatingPointSize);
1911 case ::llvm::Instruction::FSub:
1912 return std::make_unique<FBinaryOperation>(fpop::sub, floatingPointSize);
1913 case ::llvm::Instruction::FMul:
1914 return std::make_unique<FBinaryOperation>(fpop::mul, floatingPointSize);
1915 case ::llvm::Instruction::FDiv:
1916 return std::make_unique<FBinaryOperation>(fpop::div, floatingPointSize);
1917 case ::llvm::Instruction::FRem:
1918 return std::make_unique<FBinaryOperation>(fpop::mod, floatingPointSize);
1919 default:
1920 JLM_UNREACHABLE("ConvertFloatingPointBinaryOperation: Unsupported binary operation");
1921 }
1922}
1923
1924static const Variable *
1925convert(const ::llvm::BinaryOperator * instruction, tacsvector_t & tacs, Context & ctx)
1926{
1927 const auto llvmType = instruction->getType();
1928 auto & typeConverter = ctx.GetTypeConverter();
1929 const auto opcode = instruction->getOpcode();
1930
1931 std::unique_ptr<rvsdg::BinaryOperation> operation;
1932 if (llvmType->isVectorTy() && llvmType->getScalarType()->isIntegerTy())
1933 {
1934 const auto numBits = llvmType->getScalarType()->getIntegerBitWidth();
1935 operation = ConvertIntegerBinaryOperation(opcode, numBits);
1936 }
1937 else if (llvmType->isVectorTy() && llvmType->getScalarType()->isFloatingPointTy())
1938 {
1939 const auto size = typeConverter.ExtractFloatingPointSize(*llvmType->getScalarType());
1940 operation = ConvertFloatingPointBinaryOperation(opcode, size);
1941 }
1942 else if (llvmType->isIntegerTy())
1943 {
1944 operation = ConvertIntegerBinaryOperation(opcode, llvmType->getIntegerBitWidth());
1945 }
1946 else if (llvmType->isFloatingPointTy())
1947 {
1948 const auto size = typeConverter.ExtractFloatingPointSize(*llvmType);
1949 operation = ConvertFloatingPointBinaryOperation(opcode, size);
1950 }
1951 else
1952 {
1953 JLM_ASSERT("convert: Unhandled binary operation type.");
1954 }
1955
1956 const auto jlmType = typeConverter.ConvertLlvmType(*llvmType);
1957 auto operand1 = ConvertValue(instruction->getOperand(0), tacs, ctx);
1958 auto operand2 = ConvertValue(instruction->getOperand(1), tacs, ctx);
1959
1960 if (instruction->getOpcode() == ::llvm::Instruction::SDiv
1961 || instruction->getOpcode() == ::llvm::Instruction::UDiv
1962 || instruction->getOpcode() == ::llvm::Instruction::SRem
1963 || instruction->getOpcode() == ::llvm::Instruction::URem)
1964 {
1965 operand1 = AddIOBarrier(tacs, operand1, ctx);
1966 }
1967
1968 if (llvmType->isVectorTy())
1969 {
1970 tacs.push_back(VectorBinaryOperation::create(*operation, operand1, operand2, jlmType));
1971 }
1972 else
1973 {
1974 tacs.push_back(ThreeAddressCode::create(std::move(operation), { operand1, operand2 }));
1975 }
1976
1977 return tacs.back()->result(0);
1978}
1979
1980static inline const Variable *
1981convert_alloca_instruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
1982{
1983 JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::Alloca);
1984 auto i = static_cast<::llvm::AllocaInst *>(instruction);
1985
1986 auto memstate = ctx.memory_state();
1987 auto size = ConvertValue(i->getArraySize(), tacs, ctx);
1988 auto vtype = ctx.GetTypeConverter().ConvertLlvmType(*i->getAllocatedType());
1989 auto alignment = i->getAlign().value();
1990
1991 tacs.push_back(AllocaOperation::createTac(vtype, size, alignment));
1992 auto result = tacs.back()->result(0);
1993 auto astate = tacs.back()->result(1);
1994
1995 tacs.push_back(MemoryStateMergeOperation::Create({ astate, memstate }));
1996 tacs.push_back(AssignmentOperation::create(tacs.back()->result(0), memstate));
1997
1998 return result;
1999}
2000
2001static const Variable *
2002convert_extractvalue(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
2003{
2004 JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::ExtractValue);
2005 auto ev = ::llvm::dyn_cast<::llvm::ExtractValueInst>(i);
2006
2007 auto aggregate = ConvertValue(ev->getOperand(0), tacs, ctx);
2008 tacs.push_back(ExtractValueOperation::create(aggregate, ev->getIndices()));
2009
2010 return tacs.back()->result(0);
2011}
2012
2013static const Variable *
2015 const ::llvm::InsertValueInst & instruction,
2016 tacsvector_t & tacs,
2017 Context & context)
2018{
2019 const auto aggregateOperand = ConvertValue(instruction.getOperand(0), tacs, context);
2020 const auto valueOperand = ConvertValue(instruction.getOperand(1), tacs, context);
2021
2022 tacs.push_back(
2023 InsertValueOperation::createTac(*aggregateOperand, *valueOperand, instruction.getIndices()));
2024
2025 return tacs.back()->result(0);
2026}
2027
2028static inline const Variable *
2029convert_extractelement_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
2030{
2031 JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::ExtractElement);
2032
2033 auto vector = ConvertValue(i->getOperand(0), tacs, ctx);
2034 auto index = ConvertValue(i->getOperand(1), tacs, ctx);
2035 tacs.push_back(ExtractElementOperation::create(vector, index));
2036
2037 return tacs.back()->result(0);
2038}
2039
2040static const Variable *
2041convert(::llvm::ShuffleVectorInst * i, tacsvector_t & tacs, Context & ctx)
2042{
2043 auto v1 = ConvertValue(i->getOperand(0), tacs, ctx);
2044 auto v2 = ConvertValue(i->getOperand(1), tacs, ctx);
2045
2046 std::vector<int> mask;
2047 for (auto & element : i->getShuffleMask())
2048 mask.push_back(element);
2049
2050 tacs.push_back(ShuffleVectorOperation::create(v1, v2, mask));
2051
2052 return tacs.back()->result(0);
2053}
2054
2055static const Variable *
2056convert_insertelement_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
2057{
2058 JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::InsertElement);
2059
2060 auto vector = ConvertValue(i->getOperand(0), tacs, ctx);
2061 auto value = ConvertValue(i->getOperand(1), tacs, ctx);
2062 auto index = ConvertValue(i->getOperand(2), tacs, ctx);
2063 tacs.push_back(InsertElementOperation::create(vector, value, index));
2064
2065 return tacs.back()->result(0);
2066}
2067
2068static const Variable *
2069convertFreezeInstruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
2070{
2071 JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Freeze);
2072
2073 auto operand = ConvertValue(i->getOperand(0), tacs, ctx);
2074 tacs.push_back(FreezeOperation::createTac(*operand));
2075
2076 return tacs.back()->result(0);
2077}
2078
2079static const Variable *
2080convert(::llvm::UnaryOperator * unaryOperator, tacsvector_t & threeAddressCodeVector, Context & ctx)
2081{
2082 JLM_ASSERT(unaryOperator->getOpcode() == ::llvm::Instruction::FNeg);
2083 auto & typeConverter = ctx.GetTypeConverter();
2084
2085 auto type = unaryOperator->getType();
2086 auto scalarType = typeConverter.ConvertLlvmType(*type->getScalarType());
2087 auto operand = ConvertValue(unaryOperator->getOperand(0), threeAddressCodeVector, ctx);
2088
2089 if (type->isVectorTy())
2090 {
2091 auto vectorType = typeConverter.ConvertLlvmType(*type);
2092 threeAddressCodeVector.push_back(VectorUnaryOperation::create(
2093 FNegOperation(std::static_pointer_cast<const FloatingPointType>(scalarType)),
2094 operand,
2095 vectorType));
2096 }
2097 else
2098 {
2099 threeAddressCodeVector.push_back(FNegOperation::create(operand));
2100 }
2101
2102 return threeAddressCodeVector.back()->result(0);
2103}
2104
2105template<class OP>
2106static std::unique_ptr<rvsdg::SimpleOperation>
2107create_unop(std::shared_ptr<const rvsdg::Type> st, std::shared_ptr<const rvsdg::Type> dt)
2108{
2109 return std::unique_ptr<rvsdg::SimpleOperation>(new OP(std::move(st), std::move(dt)));
2110}
2111
2112static const Variable *
2113convert_cast_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
2114{
2115 JLM_ASSERT(::llvm::dyn_cast<::llvm::CastInst>(i));
2116 auto & typeConverter = ctx.GetTypeConverter();
2117 auto st = i->getOperand(0)->getType();
2118 auto dt = i->getType();
2119
2120 // Most cast operations can be performed on vector types, with the cast done per value.
2121 // Bit casts are an exception, as they can cast between different vector sizes.
2122 bool isLaneWiseCast = false;
2123 if (i->getOpcode() != ::llvm::Instruction::BitCast)
2124 {
2125 isLaneWiseCast = st->isVectorTy();
2126 JLM_ASSERT(st->isVectorTy() == dt->isVectorTy());
2127 }
2128
2129 static std::unordered_map<
2130 unsigned,
2131 std::unique_ptr<rvsdg::SimpleOperation> (*)(
2132 std::shared_ptr<const rvsdg::Type>,
2133 std::shared_ptr<const rvsdg::Type>)>
2134 map({ { ::llvm::Instruction::Trunc, create_unop<TruncOperation> },
2135 { ::llvm::Instruction::ZExt, create_unop<ZExtOperation> },
2136 { ::llvm::Instruction::UIToFP, create_unop<UIToFPOperation> },
2137 { ::llvm::Instruction::SIToFP, create_unop<SIToFPOperation> },
2138 { ::llvm::Instruction::SExt, create_unop<SExtOperation> },
2139 { ::llvm::Instruction::PtrToInt, create_unop<PtrToIntOperation> },
2140 { ::llvm::Instruction::IntToPtr, create_unop<IntToPtrOperation> },
2141 { ::llvm::Instruction::FPTrunc, create_unop<FPTruncOperation> },
2142 { ::llvm::Instruction::FPToSI, create_unop<FPToSIOperation> },
2143 { ::llvm::Instruction::FPToUI, create_unop<FPToUIOperation> },
2144 { ::llvm::Instruction::FPExt, create_unop<FPExtOperation> },
2145 { ::llvm::Instruction::BitCast, create_unop<BitCastOperation> } });
2146
2147 auto type = ctx.GetTypeConverter().ConvertLlvmType(*i->getType());
2148
2149 auto op = ConvertValue(i->getOperand(0), tacs, ctx);
2150 auto srctype = typeConverter.ConvertLlvmType(*(isLaneWiseCast ? st->getScalarType() : st));
2151 auto dsttype = typeConverter.ConvertLlvmType(*(isLaneWiseCast ? dt->getScalarType() : dt));
2152
2153 JLM_ASSERT(map.find(i->getOpcode()) != map.end());
2154 auto unop = map[i->getOpcode()](std::move(srctype), std::move(dsttype));
2155 JLM_ASSERT(is<rvsdg::UnaryOperation>(*unop));
2156
2157 if (isLaneWiseCast)
2158 tacs.push_back(
2159 VectorUnaryOperation::create(*static_cast<rvsdg::UnaryOperation *>(unop.get()), op, type));
2160 else
2161 tacs.push_back(ThreeAddressCode::create(std::move(unop), { op }));
2162
2163 return tacs.back()->result(0);
2164}
2165
2166template<class INSTRUCTIONTYPE>
2167static const Variable *
2168convert(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
2169{
2170 JLM_ASSERT(::llvm::isa<INSTRUCTIONTYPE>(instruction));
2171 return convert(::llvm::cast<INSTRUCTIONTYPE>(instruction), tacs, ctx);
2172}
2173
2174static const Variable *
2176 ::llvm::Instruction * instruction,
2177 std::vector<std::unique_ptr<ThreeAddressCode>> & threeAddressCodes,
2178 Context & context)
2179{
2180 switch (instruction->getOpcode())
2181 {
2182 case ::llvm::Instruction::Trunc:
2183 case ::llvm::Instruction::ZExt:
2184 case ::llvm::Instruction::UIToFP:
2185 case ::llvm::Instruction::SIToFP:
2186 case ::llvm::Instruction::SExt:
2187 case ::llvm::Instruction::PtrToInt:
2188 case ::llvm::Instruction::IntToPtr:
2189 case ::llvm::Instruction::FPTrunc:
2190 case ::llvm::Instruction::FPToSI:
2191 case ::llvm::Instruction::FPToUI:
2192 case ::llvm::Instruction::FPExt:
2193 case ::llvm::Instruction::BitCast:
2194 return convert_cast_instruction(instruction, threeAddressCodes, context);
2195 case ::llvm::Instruction::Add:
2196 case ::llvm::Instruction::And:
2197 case ::llvm::Instruction::AShr:
2198 case ::llvm::Instruction::Sub:
2199 case ::llvm::Instruction::UDiv:
2200 case ::llvm::Instruction::SDiv:
2201 case ::llvm::Instruction::URem:
2202 case ::llvm::Instruction::SRem:
2203 case ::llvm::Instruction::Shl:
2204 case ::llvm::Instruction::LShr:
2205 case ::llvm::Instruction::Or:
2206 case ::llvm::Instruction::Xor:
2207 case ::llvm::Instruction::Mul:
2208 case ::llvm::Instruction::FAdd:
2209 case ::llvm::Instruction::FSub:
2210 case ::llvm::Instruction::FMul:
2211 case ::llvm::Instruction::FDiv:
2212 case ::llvm::Instruction::FRem:
2213 return convert<::llvm::BinaryOperator>(instruction, threeAddressCodes, context);
2214 case ::llvm::Instruction::Ret:
2215 return convert_return_instruction(instruction, threeAddressCodes, context);
2216 case ::llvm::Instruction::Br:
2217 return ConvertBranchInstruction(instruction, threeAddressCodes, context);
2218 case ::llvm::Instruction::Switch:
2220 ::llvm::cast<::llvm::SwitchInst>(instruction),
2221 threeAddressCodes,
2222 context);
2223 case ::llvm::Instruction::Unreachable:
2224 return convert_unreachable_instruction(instruction, threeAddressCodes, context);
2225 case ::llvm::Instruction::FNeg:
2226 return convert<::llvm::UnaryOperator>(instruction, threeAddressCodes, context);
2227 case ::llvm::Instruction::ICmp:
2228 return convert<::llvm::ICmpInst>(instruction, threeAddressCodes, context);
2229 case ::llvm::Instruction::FCmp:
2230 return convert_fcmp_instruction(instruction, threeAddressCodes, context);
2231 case ::llvm::Instruction::Load:
2232 return convert_load_instruction(instruction, threeAddressCodes, context);
2233 case ::llvm::Instruction::Store:
2234 return convert_store_instruction(instruction, threeAddressCodes, context);
2235 case ::llvm::Instruction::PHI:
2236 return ConvertPhiInstruction(instruction, threeAddressCodes, context);
2237 case ::llvm::Instruction::GetElementPtr:
2238 return convert_getelementptr_instruction(instruction, threeAddressCodes, context);
2239 case ::llvm::Instruction::Call:
2241 *::llvm::dyn_cast<::llvm::CallInst>(instruction),
2242 threeAddressCodes,
2243 context);
2244 case ::llvm::Instruction::Select:
2245 return convert_select_instruction(instruction, threeAddressCodes, context);
2246 case ::llvm::Instruction::Alloca:
2247 return convert_alloca_instruction(instruction, threeAddressCodes, context);
2248 case ::llvm::Instruction::ExtractValue:
2249 return convert_extractvalue(instruction, threeAddressCodes, context);
2250 case ::llvm::Instruction::InsertValue:
2252 *::llvm::dyn_cast<::llvm::InsertValueInst>(instruction),
2253 threeAddressCodes,
2254 context);
2255 case ::llvm::Instruction::ExtractElement:
2256 return convert_extractelement_instruction(instruction, threeAddressCodes, context);
2257 case ::llvm::Instruction::ShuffleVector:
2258 return convert<::llvm::ShuffleVectorInst>(instruction, threeAddressCodes, context);
2259 case ::llvm::Instruction::InsertElement:
2260 return convert_insertelement_instruction(instruction, threeAddressCodes, context);
2261 case ::llvm::Instruction::Freeze:
2262 return convertFreezeInstruction(instruction, threeAddressCodes, context);
2263 default:
2264 throw std::runtime_error(util::strfmt(instruction->getOpcodeName(), " is not supported."));
2265 }
2266}
2267
2268static std::vector<::llvm::PHINode *>
2269convert_instructions(::llvm::Function & function, Context & ctx)
2270{
2271 std::vector<::llvm::PHINode *> phis;
2272 ::llvm::ReversePostOrderTraversal<::llvm::Function *> rpotraverser(&function);
2273 for (auto & bb : rpotraverser)
2274 {
2275 for (auto & instruction : *bb)
2276 {
2277 tacsvector_t tacs;
2278 if (auto result = convertInstruction(&instruction, tacs, ctx))
2279 ctx.insert_value(&instruction, result);
2280
2281 // When an LLVM PhiNode is converted to a jlm SsaPhiOperation, some of its operands may not be
2282 // ready. The created SsaPhiOperation therefore has no operands, but is instead added to a
2283 // list. Once all basic blocks have been converted, all SsaPhiOperations are revisited and
2284 // given operands.
2285 if (!tacs.empty() && is<SsaPhiOperation>(tacs.back()->operation()))
2286 {
2287 auto phi = ::llvm::dyn_cast<::llvm::PHINode>(&instruction);
2288 phis.push_back(phi);
2289 }
2290
2291 ctx.get(bb)->append_last(tacs);
2292 }
2293 }
2294
2295 return phis;
2296}
2297
2303static void
2304PatchPhiOperands(const std::vector<::llvm::PHINode *> & phis, Context & ctx)
2305{
2306 for (const auto & phi : phis)
2307 {
2308 std::vector<ControlFlowGraphNode *> incomingNodes;
2309 std::vector<const Variable *> operands;
2310 for (size_t n = 0; n < phi->getNumOperands(); n++)
2311 {
2312 // In LLVM, phi instructions may have incoming basic blocks that are unreachable.
2313 // These are not visited during convert_basic_blocks, and thus do not have corresponding
2314 // jlm::llvm::basic_blocks. The SsaPhiOperation can safely ignore these, as they are dead.
2315 if (!ctx.has(phi->getIncomingBlock(n)))
2316 continue;
2317
2318 // The LLVM phi instruction may have multiple operands with the same incoming cfg node.
2319 // When this happens in valid LLVM IR, all operands from the same basic block are identical.
2320 // We therefore skip any operands that reference already handled basic blocks.
2321 auto predecessor = ctx.get(phi->getIncomingBlock(n));
2322 if (std::find(incomingNodes.begin(), incomingNodes.end(), predecessor) != incomingNodes.end())
2323 continue;
2324
2325 // Convert the operand value in the predecessor basic block, as that is where it is "used".
2326 tacsvector_t tacs;
2327 operands.push_back(ConvertValue(phi->getIncomingValue(n), tacs, ctx));
2328 predecessor->insert_before_branch(tacs);
2329 incomingNodes.push_back(predecessor);
2330 }
2331
2332 JLM_ASSERT(operands.size() >= 1);
2333
2334 auto phi_tac = util::assertedCast<const ThreeAddressCodeVariable>(ctx.lookup_value(phi))->tac();
2335 phi_tac->replace(
2336 SsaPhiOperation(std::move(incomingNodes), phi_tac->result(0)->Type()),
2337 operands);
2338 }
2339}
2340
2341static BasicBlockMap
2342convert_basic_blocks(::llvm::Function & f, ControlFlowGraph & cfg)
2343{
2344 BasicBlockMap bbmap;
2345 ::llvm::ReversePostOrderTraversal<::llvm::Function *> rpotraverser(&f);
2346 for (auto & bb : rpotraverser)
2347 bbmap.Insert(bb, BasicBlock::create(cfg));
2348
2349 return bbmap;
2350}
2351
2352static std::unique_ptr<llvm::Argument>
2353convert_argument(const ::llvm::Argument & argument, Context & ctx)
2354{
2355 auto function = argument.getParent();
2356 auto name = argument.getName().str();
2357 auto type = ctx.GetTypeConverter().ConvertLlvmType(*argument.getType());
2358 auto attributes = convert_attributes(
2359 function->getAttributes().getParamAttrs(argument.getArgNo()),
2360 ctx.GetTypeConverter());
2361
2362 return llvm::Argument::create(name, type, attributes);
2363}
2364
2365static void
2367{
2368 auto exitNode = cfg.exit();
2369
2370 if (exitNode->NumInEdges() == 0)
2371 {
2372 /*
2373 LLVM can produce CFGs that have no incoming edge to the exit node. This can happen if
2374 endless loops are present in the code. For example, this code
2375
2376 \code{.cpp}
2377 int foo()
2378 {
2379 while (1) {
2380 printf("foo\n");
2381 }
2382
2383 return 0;
2384 }
2385 \endcode
2386
2387 results in a JLM CFG with no incoming edge to the exit node.
2388
2389 We solve this problem by finding the first SCC with no exit edge, i.e., an endless loop, and
2390 restructure it to an SCC with an exit edge to the CFG's exit node.
2391 */
2392 auto stronglyConnectedComponents = find_sccs(cfg);
2393 for (auto stronglyConnectedComponent : stronglyConnectedComponents)
2394 {
2395 auto sccStructure = StronglyConnectedComponentStructure::Create(stronglyConnectedComponent);
2396
2397 if (sccStructure->NumExitEdges() == 0)
2398 {
2399 auto repetitionEdge = *sccStructure->RepetitionEdges().begin();
2400
2401 auto basicBlock = BasicBlock::create(cfg);
2402
2403 auto op = std::make_unique<rvsdg::ControlConstantOperation>(
2405 auto operand =
2406 basicBlock->append_last(ThreeAddressCode::create(std::move(op), {}))->result(0);
2407 basicBlock->append_last(BranchOperation::create(2, operand));
2408
2409 basicBlock->add_outedge(exitNode);
2410 basicBlock->add_outedge(repetitionEdge->sink());
2411
2412 repetitionEdge->divert(basicBlock);
2413 break;
2414 }
2415 }
2416 }
2417
2418 if (exitNode->NumInEdges() == 1)
2419 return;
2420
2421 /*
2422 We have multiple incoming edges to the exit node. Insert an empty basic block, divert all
2423 incoming edges to this block, and add an outgoing edge from this block to the exit node.
2424 */
2425 auto basicBlock = BasicBlock::create(cfg);
2426 exitNode->divert_inedges(basicBlock);
2427 basicBlock->add_outedge(exitNode);
2428}
2429
2430static std::unique_ptr<ControlFlowGraph>
2431create_cfg(::llvm::Function & f, Context & ctx)
2432{
2433 auto node = static_cast<const FunctionVariable *>(ctx.lookup_value(&f))->function();
2434
2435 auto add_arguments = [](const ::llvm::Function & f, ControlFlowGraph & cfg, Context & ctx)
2436 {
2437 auto node = static_cast<const FunctionVariable *>(ctx.lookup_value(&f))->function();
2438
2439 size_t n = 0;
2440 for (const auto & arg : f.args())
2441 {
2442 auto argument = cfg.entry()->append_argument(convert_argument(arg, ctx));
2443 ctx.insert_value(&arg, argument);
2444 n++;
2445 }
2446
2447 if (f.isVarArg())
2448 {
2449 JLM_ASSERT(n < node->fcttype().NumArguments());
2450 auto & type = node->fcttype().Arguments()[n++];
2451 cfg.entry()->append_argument(Argument::create("_varg_", type));
2452 }
2453 JLM_ASSERT(n < node->fcttype().NumArguments());
2454
2455 auto & iotype = node->fcttype().Arguments()[n++];
2456 auto iostate = cfg.entry()->append_argument(Argument::create("_io_", iotype));
2457
2458 auto & memtype = node->fcttype().Arguments()[n++];
2459 auto memstate = cfg.entry()->append_argument(Argument::create("_s_", memtype));
2460
2461 JLM_ASSERT(n == node->fcttype().NumArguments());
2462 ctx.set_iostate(iostate);
2463 ctx.set_memory_state(memstate);
2464 };
2465
2466 auto cfg = ControlFlowGraph::create(ctx.module());
2467
2468 add_arguments(f, *cfg, ctx);
2469 auto bbmap = convert_basic_blocks(f, *cfg);
2470
2471 /* create entry block */
2472 auto entry_block = BasicBlock::create(*cfg);
2473 cfg->exit()->divert_inedges(entry_block);
2474 entry_block->add_outedge(bbmap.LookupKey(&f.getEntryBlock()));
2475
2476 /* add results */
2477 const ThreeAddressCodeVariable * result = nullptr;
2478 if (!f.getReturnType()->isVoidTy())
2479 {
2480 auto type = ctx.GetTypeConverter().ConvertLlvmType(*f.getReturnType());
2481 entry_block->append_last(UndefValueOperation::Create(type, "_r_"));
2482 result = entry_block->last()->result(0);
2483
2484 JLM_ASSERT(node->fcttype().NumResults() == 3);
2485 JLM_ASSERT(result->type() == node->fcttype().ResultType(0));
2486 cfg->exit()->append_result(result);
2487 }
2488 cfg->exit()->append_result(ctx.iostate());
2489 cfg->exit()->append_result(ctx.memory_state());
2490
2491 /* convert instructions */
2492 ctx.set_basic_block_map(std::move(bbmap));
2493 ctx.set_result(result);
2494 auto phis = convert_instructions(f, ctx);
2495 PatchPhiOperands(phis, ctx);
2496
2498
2499 // Merge basic blocks A -> B when possible
2500 straighten(*cfg);
2501 // Remove unreachable nodes
2502 prune(*cfg);
2503 return cfg;
2504}
2505
2506static void
2507convert_function(::llvm::Function & function, Context & ctx)
2508{
2509 if (function.isDeclaration())
2510 return;
2511
2512 auto fv = static_cast<const FunctionVariable *>(ctx.lookup_value(&function));
2513
2514 ctx.set_node(fv->function());
2515 fv->function()->add_cfg(create_cfg(function, ctx));
2516 ctx.set_node(nullptr);
2517}
2518
2519static const llvm::Linkage &
2520convert_linkage(const ::llvm::GlobalValue::LinkageTypes & linkage)
2521{
2522 static std::unordered_map<::llvm::GlobalValue::LinkageTypes, llvm::Linkage> map(
2523 { { ::llvm::GlobalValue::ExternalLinkage, llvm::Linkage::externalLinkage },
2524 { ::llvm::GlobalValue::AvailableExternallyLinkage,
2526 { ::llvm::GlobalValue::LinkOnceAnyLinkage, llvm::Linkage::linkOnceAnyLinkage },
2527 { ::llvm::GlobalValue::LinkOnceODRLinkage, llvm::Linkage::linkOnceOdrLinkage },
2528 { ::llvm::GlobalValue::WeakAnyLinkage, llvm::Linkage::weakAnyLinkage },
2529 { ::llvm::GlobalValue::WeakODRLinkage, llvm::Linkage::weakOdrLinkage },
2530 { ::llvm::GlobalValue::AppendingLinkage, llvm::Linkage::appendingLinkage },
2531 { ::llvm::GlobalValue::InternalLinkage, llvm::Linkage::internalLinkage },
2532 { ::llvm::GlobalValue::PrivateLinkage, llvm::Linkage::privateLinkage },
2533 { ::llvm::GlobalValue::ExternalWeakLinkage, llvm::Linkage::externalWeakLinkage },
2534 { ::llvm::GlobalValue::CommonLinkage, llvm::Linkage::commonLinkage } });
2535
2536 JLM_ASSERT(map.find(linkage) != map.end());
2537 return map[linkage];
2538}
2539
2540static void
2541declare_globals(::llvm::Module & lm, Context & ctx)
2542{
2543 auto create_data_node = [](const ::llvm::GlobalVariable & gv, Context & ctx)
2544 {
2545 auto name = gv.getName().str();
2546 auto constant = gv.isConstant();
2547 auto type = ctx.GetTypeConverter().ConvertLlvmType(*gv.getValueType());
2548 auto linkage = convert_linkage(gv.getLinkage());
2549 auto section = gv.getSection().str();
2550 const auto alignment = gv.getAlign().valueOrOne().value();
2551
2552 return DataNode::Create(
2553 ctx.module().ipgraph(),
2554 name,
2555 type,
2556 linkage,
2557 std::move(section),
2558 constant,
2559 alignment);
2560 };
2561
2562 auto create_function_node = [](const ::llvm::Function & f, Context & ctx)
2563 {
2564 auto name = f.getName().str();
2565 auto type = ctx.GetTypeConverter().ConvertFunctionType(*f.getFunctionType());
2566 auto linkage = convert_linkage(f.getLinkage());
2567 auto callingConvention = convertCallingConventionToJlm(f.getCallingConv());
2568 auto attributes = convert_attributes(f.getAttributes().getFnAttrs(), ctx.GetTypeConverter());
2569
2570 return FunctionNode::create(
2571 ctx.module().ipgraph(),
2572 name,
2573 type,
2574 linkage,
2575 callingConvention,
2576 attributes);
2577 };
2578
2579 for (auto & gv : lm.globals())
2580 {
2581 auto node = create_data_node(gv, ctx);
2582 ctx.insert_value(&gv, ctx.module().create_global_value(node));
2583 }
2584
2585 for (auto & f : lm.getFunctionList())
2586 {
2587 if (f.isIntrinsic() && shouldIgnoreIntrinsic(f.getIntrinsicID()))
2588 continue;
2589
2590 auto node = create_function_node(f, ctx);
2591 ctx.insert_value(&f, ctx.module().create_variable(node));
2592 }
2593}
2594
2595static std::unique_ptr<DataNodeInit>
2596create_initialization(::llvm::GlobalVariable & gv, Context & ctx)
2597{
2598 if (!gv.hasInitializer())
2599 return nullptr;
2600
2601 auto init = gv.getInitializer();
2602 auto tacs = ConvertConstant(init, ctx);
2603 if (tacs.empty())
2604 return std::make_unique<DataNodeInit>(ctx.lookup_value(init));
2605
2606 return std::make_unique<DataNodeInit>(std::move(tacs));
2607}
2608
2609static void
2610convert_global_value(::llvm::GlobalVariable & gv, Context & ctx)
2611{
2612 auto v = static_cast<const GlobalValue *>(ctx.lookup_value(&gv));
2613
2614 ctx.set_node(v->node());
2615 v->node()->set_initialization(create_initialization(gv, ctx));
2616 ctx.set_node(nullptr);
2617}
2618
2619static void
2620convert_globals(::llvm::Module & lm, Context & ctx)
2621{
2622 for (auto & gv : lm.globals())
2623 convert_global_value(gv, ctx);
2624
2625 for (auto & f : lm.getFunctionList())
2626 convert_function(f, ctx);
2627}
2628
2629std::unique_ptr<InterProceduralGraphModule>
2630ConvertLlvmModule(::llvm::Module & llvmModule)
2631{
2632 auto ipgModule = InterProceduralGraphModule::create(
2633 util::FilePath(llvmModule.getSourceFileName()),
2634 llvmModule.getTargetTriple(),
2635 llvmModule.getDataLayoutStr());
2636
2637 Context ctx(*ipgModule);
2638 declare_globals(llvmModule, ctx);
2639 convert_globals(llvmModule, ctx);
2640
2641 return ipgModule;
2642}
2643
2644}
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:445
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< llvm::ThreeAddressCode > Create(const Variable *pointer, const std::vector< const Variable * > &memoryStates, const Variable *iOState)
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:447
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:325
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:460
static std::unique_ptr< StronglyConnectedComponentStructure > Create(const StronglyConnectedComponent &scc)
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition tac.hpp:135
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:202
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 * 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