Jlm
Loading...
Searching...
No Matches
IpGraphToLlvmConverter.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2025 Nico Reißmann <nico.reissmann@gmail.com>
3 * See COPYING for terms of redistribution.
4 */
5
31#include <jlm/rvsdg/control.hpp>
32
33#include <llvm/IR/BasicBlock.h>
34#include <llvm/IR/IRBuilder.h>
35#include <llvm/IR/Module.h>
36
37#include <unordered_map>
38
39namespace jlm::llvm
40{
41
43{
45 std::unordered_map<const ControlFlowGraphNode *, ::llvm::BasicBlock *>::const_iterator;
46
47public:
48 Context(InterProceduralGraphModule & ipGraphModule, ::llvm::Module & llvmModule)
49 : LlvmModule_(llvmModule),
50 IpGraphModule_(ipGraphModule)
51 {}
52
53 Context(const Context &) = delete;
54
55 Context(Context &&) = delete;
56
57 Context &
58 operator=(const Context &) = delete;
59
60 Context &
61 operator=(Context &&) = delete;
62
63 // FIXME: It should be a const reference, but we still have to create variables to translate
64 // expressions.
65 [[nodiscard]] InterProceduralGraphModule &
66 module() const noexcept
67 {
68 return IpGraphModule_;
69 }
70
71 ::llvm::Module &
72 llvm_module() const noexcept
73 {
74 return LlvmModule_;
75 }
76
78 begin() const
79 {
80 return nodes_.begin();
81 }
82
84 end() const
85 {
86 return nodes_.end();
87 }
88
89 void
90 insert(const llvm::ControlFlowGraphNode * node, ::llvm::BasicBlock * bb)
91 {
92 nodes_[node] = bb;
93 }
94
95 void
96 insert(const llvm::Variable * variable, ::llvm::Value * value)
97 {
98 variables_[variable] = value;
99 }
100
101 ::llvm::BasicBlock *
102 basic_block(const llvm::ControlFlowGraphNode * node) const noexcept
103 {
104 auto it = nodes_.find(node);
105 JLM_ASSERT(it != nodes_.end());
106 return it->second;
107 }
108
109 ::llvm::Value *
110 value(const llvm::Variable * variable) const noexcept
111 {
112 auto it = variables_.find(variable);
113 JLM_ASSERT(it != variables_.end());
114 return it->second;
115 }
116
119 {
120 return TypeConverter_;
121 }
122
123 static std::unique_ptr<Context>
124 Create(InterProceduralGraphModule & ipGraphModule, ::llvm::Module & llvmModule)
125 {
126 return std::make_unique<Context>(ipGraphModule, llvmModule);
127 }
128
129private:
130 ::llvm::Module & LlvmModule_;
132 std::unordered_map<const llvm::Variable *, ::llvm::Value *> variables_;
133 std::unordered_map<const llvm::ControlFlowGraphNode *, ::llvm::BasicBlock *> nodes_;
135};
136
138
140
141::llvm::Value *
142IpGraphToLlvmConverter::convert_assignment(
143 const rvsdg::SimpleOperation & op,
144 const std::vector<const Variable *> & args,
145 ::llvm::IRBuilder<> &)
146{
147 JLM_ASSERT(is<AssignmentOperation>(op));
148 return Context_->value(args[0]);
149}
150
151::llvm::Value *
153 const ::llvm::Instruction::BinaryOps opcode,
154 const std::vector<const Variable *> & args,
155 ::llvm::IRBuilder<> & builder)
156{
157 const auto operand1 = Context_->value(args[0]);
158 const auto operand2 = Context_->value(args[1]);
159 return builder.CreateBinOp(opcode, operand1, operand2);
160}
161
162::llvm::Value *
164 const ::llvm::CmpInst::Predicate predicate,
165 const std::vector<const Variable *> & args,
166 ::llvm::IRBuilder<> & builder)
167{
168 const auto operand1 = Context_->value(args[0]);
169 const auto operand2 = Context_->value(args[1]);
170 return builder.CreateICmp(predicate, operand1, operand2);
171}
172
173static ::llvm::APInt
175{
177
178 std::string str = vr.str();
179 std::reverse(str.begin(), str.end());
180
181 return ::llvm::APInt(vr.nbits(), str, 2);
182}
183
184::llvm::Value *
186 const rvsdg::SimpleOperation & op,
187 const std::vector<const Variable *> &,
188 ::llvm::IRBuilder<> & builder)
189{
190 const auto & representation =
191 util::assertedCast<const IntegerConstantOperation>(&op)->Representation();
192 const auto type = ::llvm::IntegerType::get(builder.getContext(), representation.nbits());
193
194 if (representation.is_defined())
195 return ::llvm::ConstantInt::get(type, convert_bitvalue_repr(representation));
196
197 return ::llvm::UndefValue::get(type);
198}
199
200::llvm::Value *
202 const rvsdg::SimpleOperation & op,
203 const std::vector<const Variable *> &,
204 ::llvm::IRBuilder<> & builder)
205{
206 JLM_ASSERT(is<rvsdg::ControlConstantOperation>(op));
207 auto & cop = *static_cast<const rvsdg::ControlConstantOperation *>(&op);
208
209 size_t nbits = cop.value().nalternatives() == 2 ? 1 : 32;
210 auto type = ::llvm::IntegerType::get(builder.getContext(), nbits);
211 return ::llvm::ConstantInt::get(type, cop.value().alternative());
212}
213
214::llvm::Value *
216 const ConstantFP & op,
217 const std::vector<const Variable *> &,
218 ::llvm::IRBuilder<> & builder)
219{
220 return ::llvm::ConstantFP::get(builder.getContext(), op.constant());
221}
222
223::llvm::Value *
225 const rvsdg::SimpleOperation & op,
226 const std::vector<const Variable *> &,
227 ::llvm::IRBuilder<> &)
228{
229 JLM_ASSERT(is<UndefValueOperation>(op));
230 auto & llvmContext = Context_->llvm_module().getContext();
231 auto & typeConverter = Context_->GetTypeConverter();
232
233 auto & resultType = *op.result(0);
234
235 // MemoryState has no llvm representation.
236 if (is<MemoryStateType>(resultType))
237 return nullptr;
238
239 auto type = typeConverter.ConvertJlmType(resultType, llvmContext);
240 return ::llvm::UndefValue::get(type);
241}
242
243::llvm::Value *
245 const PoisonValueOperation & operation,
246 const std::vector<const Variable *> &,
247 ::llvm::IRBuilder<> &)
248{
249 auto & llvmContext = Context_->llvm_module().getContext();
250 auto & typeConverter = Context_->GetTypeConverter();
251
252 auto type = typeConverter.ConvertJlmType(operation.GetType(), llvmContext);
253 return ::llvm::PoisonValue::get(type);
254}
255
256::llvm::Value *
258 const FreezeOperation &,
259 const std::vector<const Variable *> & operands,
260 ::llvm::IRBuilder<> & builder)
261{
262 JLM_ASSERT(operands.size() == 1);
263 auto operand = Context_->value(operands[0]);
264
265 return builder.CreateFreeze(operand);
266}
267
268::llvm::Value *
270 const CallOperation & op,
271 const std::vector<const Variable *> & args,
272 ::llvm::IRBuilder<> & builder)
273{
274 auto function = Context_->value(args[0]);
275 auto & llvmContext = Context_->llvm_module().getContext();
276 auto & typeConverter = Context_->GetTypeConverter();
277
278 std::vector<::llvm::Value *> operands;
279 for (size_t n = 1; n < args.size(); n++)
280 {
281 auto argument = args[n];
282
283 if (rvsdg::is<IOStateType>(argument->type()))
284 continue;
285 if (rvsdg::is<MemoryStateType>(argument->type()))
286 continue;
287
288 if (rvsdg::is<VariableArgumentType>(argument->type()))
289 {
290 JLM_ASSERT(is<ThreeAddressCodeVariable>(argument));
291 auto valist = dynamic_cast<const llvm::ThreeAddressCodeVariable *>(argument)->tac();
292 JLM_ASSERT(is<VariadicArgumentListOperation>(valist->operation()));
293 for (size_t n = 0; n < valist->noperands(); n++)
294 operands.push_back(Context_->value(valist->operand(n)));
295 continue;
296 }
297
298 operands.push_back(Context_->value(argument));
299 }
300
301 auto ftype = typeConverter.ConvertFunctionType(*op.GetFunctionType(), llvmContext);
302 auto callInstruction = builder.CreateCall(ftype, function, operands);
303 callInstruction->setCallingConv(convertCallingConventionToLlvm(op.getCallingConvention()));
304 callInstruction->setAttributes(convertAttributeList(op.getAttributes()));
305 return callInstruction;
306}
307
308static bool
310{
311 for (const auto & pair : op)
312 {
313 if (pair.first != pair.second)
314 return false;
315 }
316
317 return true;
318}
319
320::llvm::Value *
322 const rvsdg::SimpleOperation & op,
323 const std::vector<const Variable *> & args,
324 ::llvm::IRBuilder<> & builder)
325{
326 JLM_ASSERT(is<rvsdg::MatchOperation>(op));
327 auto mop = static_cast<const rvsdg::MatchOperation *>(&op);
328
329 if (is_identity_mapping(*mop))
330 return Context_->value(args[0]);
331
332 if (mop->nalternatives() == 2 && mop->nbits() == 1)
333 {
334 auto i1 = ::llvm::IntegerType::get(builder.getContext(), 1);
335 auto t = ::llvm::ConstantInt::getFalse(i1);
336 auto f = ::llvm::ConstantInt::getTrue(i1);
337 return builder.CreateSelect(Context_->value(args[0]), t, f);
338 }
339
340 /* FIXME: This is not working if the match is not directly connected to a gamma node. */
341 return Context_->value(args[0]);
342}
343
344::llvm::Value *
346 const rvsdg::SimpleOperation & op,
347 const std::vector<const Variable *> &,
348 ::llvm::IRBuilder<> &)
349{
350 JLM_ASSERT(is<BranchOperation>(op));
351 return nullptr;
352}
353
354::llvm::Value *
356 const rvsdg::SimpleOperation & op,
357 const std::vector<const Variable *> &,
358 ::llvm::IRBuilder<> & builder)
359{
360 auto & phi = *util::assertedCast<const SsaPhiOperation>(&op);
361 auto & llvmContext = Context_->llvm_module().getContext();
362 auto & typeConverter = Context_->GetTypeConverter();
363
364 if (rvsdg::is<IOStateType>(phi.Type()))
365 return nullptr;
366 if (rvsdg::is<MemoryStateType>(phi.Type()))
367 return nullptr;
368
369 auto t = typeConverter.ConvertJlmType(*phi.Type(), llvmContext);
370 return builder.CreatePHI(t, op.narguments());
371}
372
373::llvm::Value *
375 const rvsdg::Type & loadedType,
376 const Variable * address,
377 bool isVolatile,
378 size_t alignment,
379 ::llvm::IRBuilder<> & builder)
380{
381 auto & llvmContext = Context_->llvm_module().getContext();
382 auto & typeConverter = Context_->GetTypeConverter();
383
384 auto type = typeConverter.ConvertJlmType(loadedType, llvmContext);
385 auto loadInstruction = builder.CreateLoad(type, Context_->value(address), isVolatile);
386 loadInstruction->setAlignment(::llvm::Align(alignment));
387 return loadInstruction;
388}
389
390::llvm::Value *
392 const LoadNonVolatileOperation & operation,
393 const std::vector<const Variable *> & operands,
394 ::llvm::IRBuilder<> & builder)
395{
397 *operation.GetLoadedType(),
398 operands[0],
399 false,
400 operation.GetAlignment(),
401 builder);
402}
403
404::llvm::Value *
406 const LoadVolatileOperation & operation,
407 const std::vector<const Variable *> & operands,
408 ::llvm::IRBuilder<> & builder)
409{
411 *operation.GetLoadedType(),
412 operands[0],
413 true,
414 operation.GetAlignment(),
415 builder);
416}
417
418void
420 const Variable * address,
421 const Variable * value,
422 bool isVolatile,
423 size_t alignment,
424 ::llvm::IRBuilder<> & builder)
425{
426 auto storeInstruction =
427 builder.CreateStore(Context_->value(value), Context_->value(address), isVolatile);
428 storeInstruction->setAlignment(::llvm::Align(alignment));
429}
430
431::llvm::Value *
433 const rvsdg::SimpleOperation & operation,
434 const std::vector<const Variable *> & operands,
435 ::llvm::IRBuilder<> & builder)
436{
437 auto storeOperation = util::assertedCast<const StoreNonVolatileOperation>(&operation);
438 CreateStoreInstruction(operands[0], operands[1], false, storeOperation->GetAlignment(), builder);
439 return nullptr;
440}
441
442::llvm::Value *
444 const StoreVolatileOperation & operation,
445 const std::vector<const Variable *> & operands,
446 ::llvm::IRBuilder<> & builder)
447{
448 CreateStoreInstruction(operands[0], operands[1], true, operation.GetAlignment(), builder);
449 return nullptr;
450}
451
452::llvm::Value *
454 const rvsdg::SimpleOperation & op,
455 const std::vector<const Variable *> & args,
456 ::llvm::IRBuilder<> & builder)
457{
458 JLM_ASSERT(is<AllocaOperation>(op));
459 auto & aop = *static_cast<const llvm::AllocaOperation *>(&op);
460 auto & llvmContext = Context_->llvm_module().getContext();
461 auto & typeConverter = Context_->GetTypeConverter();
462
463 auto t = typeConverter.ConvertJlmType(*aop.allocatedType(), llvmContext);
464 auto i = builder.CreateAlloca(t, Context_->value(args[0]));
465 i->setAlignment(::llvm::Align(aop.alignment()));
466 return i;
467}
468
469::llvm::Value *
471 const rvsdg::SimpleOperation & op,
472 const std::vector<const Variable *> & args,
473 ::llvm::IRBuilder<> & builder)
474{
475 JLM_ASSERT(is<GetElementPtrOperation>(op) && args.size() >= 2);
476 auto & pop = *static_cast<const GetElementPtrOperation *>(&op);
477 auto & llvmContext = Context_->llvm_module().getContext();
478 auto & typeConverter = Context_->GetTypeConverter();
479
480 std::vector<::llvm::Value *> indices;
481 auto t = typeConverter.ConvertJlmType(*pop.getPointeeType(), llvmContext);
482 for (size_t n = 1; n < args.size(); n++)
483 indices.push_back(Context_->value(args[n]));
484
485 return builder.CreateGEP(t, Context_->value(args[0]), indices);
486}
487
488template<typename T>
489std::vector<T>
490IpGraphToLlvmConverter::get_bitdata(const std::vector<const Variable *> & args)
491{
492 std::vector<T> data;
493 for (size_t n = 0; n < args.size(); n++)
494 {
495 auto c = ::llvm::dyn_cast<const ::llvm::ConstantInt>(Context_->value(args[n]));
496 JLM_ASSERT(c);
497 data.push_back(c->getZExtValue());
498 }
499
500 return data;
501}
502
503template<typename T>
504std::vector<T>
505IpGraphToLlvmConverter::get_fpdata(const std::vector<const Variable *> & args)
506{
507 std::vector<T> data;
508 for (size_t n = 0; n < args.size(); n++)
509 {
510 auto c = ::llvm::dyn_cast<const ::llvm::ConstantFP>(Context_->value(args[n]));
511 JLM_ASSERT(c);
512 data.push_back(c->getValueAPF().bitcastToAPInt().getZExtValue());
513 }
514
515 return data;
516}
517
518::llvm::Value *
521 const std::vector<const Variable *> & operands,
522 ::llvm::IRBuilder<> & builder)
523{
524 JLM_ASSERT(is<ConstantDataArrayOperation>(op));
525
526 if (auto bt = dynamic_cast<const rvsdg::BitType *>(&op.type()->element_type()))
527 {
528 if (bt->nbits() == 8)
529 {
530 auto data = get_bitdata<uint8_t>(operands);
531 return ::llvm::ConstantDataArray::get(builder.getContext(), data);
532 }
533 else if (bt->nbits() == 16)
534 {
535 auto data = get_bitdata<uint16_t>(operands);
536 return ::llvm::ConstantDataArray::get(builder.getContext(), data);
537 }
538 else if (bt->nbits() == 32)
539 {
540 auto data = get_bitdata<uint32_t>(operands);
541 return ::llvm::ConstantDataArray::get(builder.getContext(), data);
542 }
543 else if (bt->nbits() == 64)
544 {
545 auto data = get_bitdata<uint64_t>(operands);
546 return ::llvm::ConstantDataArray::get(builder.getContext(), data);
547 }
548 }
549
550 if (auto ft = dynamic_cast<const FloatingPointType *>(&op.type()->element_type()))
551 {
552 if (ft->size() == fpsize::half)
553 {
554 auto data = get_fpdata<uint16_t>(operands);
555 auto type = ::llvm::Type::getBFloatTy(builder.getContext());
556 return ::llvm::ConstantDataArray::getFP(type, data);
557 }
558 else if (ft->size() == fpsize::flt)
559 {
560 auto data = get_fpdata<uint32_t>(operands);
561 auto type = ::llvm::Type::getFloatTy(builder.getContext());
562 return ::llvm::ConstantDataArray::getFP(type, data);
563 }
564 else if (ft->size() == fpsize::dbl)
565 {
566 auto data = get_fpdata<uint64_t>(operands);
567 auto type = ::llvm::Type::getDoubleTy(builder.getContext());
568 return ::llvm::ConstantDataArray::getFP(type, data);
569 }
570 }
571
572 JLM_UNREACHABLE("This should not have happened!");
573}
574
575::llvm::Value *
577 const ConstantArrayOperation & op,
578 const std::vector<const Variable *> & operands,
579 ::llvm::IRBuilder<> &)
580{
581 ::llvm::LLVMContext & llvmContext = Context_->llvm_module().getContext();
582 auto & typeConverter = Context_->GetTypeConverter();
583
584 std::vector<::llvm::Constant *> data;
585 for (size_t n = 0; n < operands.size(); n++)
586 {
587 auto c = ::llvm::dyn_cast<::llvm::Constant>(Context_->value(operands[n]));
588 JLM_ASSERT(c);
589 data.push_back(c);
590 }
591
592 auto at = std::dynamic_pointer_cast<const ArrayType>(op.result(0));
593 auto type = typeConverter.ConvertArrayType(*at, llvmContext);
594 return ::llvm::ConstantArray::get(type, data);
595}
596
597::llvm::Value *
600 const std::vector<const Variable *> &,
601 ::llvm::IRBuilder<> &)
602{
603 ::llvm::LLVMContext & llvmContext = Context_->llvm_module().getContext();
604 auto & typeConverter = Context_->GetTypeConverter();
605
606 auto type = typeConverter.ConvertJlmType(*op.result(0), llvmContext);
607 return ::llvm::ConstantAggregateZero::get(type);
608}
609
610::llvm::Value *
612 const rvsdg::SimpleOperation & op,
613 const std::vector<const Variable *> & args,
614 ::llvm::IRBuilder<> & builder)
615{
616 JLM_ASSERT(is<PtrCmpOperation>(op));
617 auto & pop = *static_cast<const PtrCmpOperation *>(&op);
618
619 const auto predicate = convertICmpPredicateToLlvm(pop.predicate());
620 const auto op1 = Context_->value(args[0]);
621 const auto op2 = Context_->value(args[1]);
622 return builder.CreateICmp(predicate, op1, op2);
623}
624
625::llvm::Value *
627 const rvsdg::SimpleOperation & op,
628 const std::vector<const Variable *> & args,
629 ::llvm::IRBuilder<> & builder)
630{
631 JLM_ASSERT(is<FCmpOperation>(op));
632 auto & fpcmp = *static_cast<const FCmpOperation *>(&op);
633
634 static std::unordered_map<llvm::fpcmp, ::llvm::CmpInst::Predicate> map(
635 { { fpcmp::oeq, ::llvm::CmpInst::FCMP_OEQ },
636 { fpcmp::ogt, ::llvm::CmpInst::FCMP_OGT },
637 { fpcmp::oge, ::llvm::CmpInst::FCMP_OGE },
638 { fpcmp::olt, ::llvm::CmpInst::FCMP_OLT },
639 { fpcmp::ole, ::llvm::CmpInst::FCMP_OLE },
640 { fpcmp::one, ::llvm::CmpInst::FCMP_ONE },
641 { fpcmp::ord, ::llvm::CmpInst::FCMP_ORD },
642 { fpcmp::uno, ::llvm::CmpInst::FCMP_UNO },
643 { fpcmp::ueq, ::llvm::CmpInst::FCMP_UEQ },
644 { fpcmp::ugt, ::llvm::CmpInst::FCMP_UGT },
645 { fpcmp::uge, ::llvm::CmpInst::FCMP_UGE },
646 { fpcmp::ult, ::llvm::CmpInst::FCMP_ULT },
647 { fpcmp::ule, ::llvm::CmpInst::FCMP_ULE },
648 { fpcmp::une, ::llvm::CmpInst::FCMP_UNE },
649 { fpcmp::TRUE, ::llvm::CmpInst::FCMP_TRUE },
650 { fpcmp::FALSE, ::llvm::CmpInst::FCMP_FALSE } });
651
652 auto op1 = Context_->value(args[0]);
653 auto op2 = Context_->value(args[1]);
654 JLM_ASSERT(map.find(fpcmp.cmp()) != map.end());
655 return builder.CreateFCmp(map[fpcmp.cmp()], op1, op2);
656}
657
658::llvm::Value *
660 const rvsdg::SimpleOperation & op,
661 const std::vector<const Variable *> & args,
662 ::llvm::IRBuilder<> & builder)
663{
664 JLM_ASSERT(is<FBinaryOperation>(op));
665 auto & fpbin = *static_cast<const llvm::FBinaryOperation *>(&op);
666
667 static std::unordered_map<llvm::fpop, ::llvm::Instruction::BinaryOps> map(
668 { { fpop::add, ::llvm::Instruction::FAdd },
669 { fpop::sub, ::llvm::Instruction::FSub },
670 { fpop::mul, ::llvm::Instruction::FMul },
671 { fpop::div, ::llvm::Instruction::FDiv },
672 { fpop::mod, ::llvm::Instruction::FRem } });
673
674 auto op1 = Context_->value(args[0]);
675 auto op2 = Context_->value(args[1]);
676 JLM_ASSERT(map.find(fpbin.fpop()) != map.end());
677 return builder.CreateBinOp(map[fpbin.fpop()], op1, op2);
678}
679
680::llvm::Value *
682 const rvsdg::SimpleOperation & op,
683 const std::vector<const Variable *> & args,
684 ::llvm::IRBuilder<> & builder)
685{
686 JLM_ASSERT(is<FNegOperation>(op));
687 auto operand = Context_->value(args[0]);
688 return builder.CreateUnOp(::llvm::Instruction::FNeg, operand);
689}
690
691::llvm::Value *
693 const rvsdg::SimpleOperation & op,
694 const std::vector<const Variable *> &,
695 ::llvm::IRBuilder<> &)
696{
697 JLM_ASSERT(is<VariadicArgumentListOperation>(op));
698 return nullptr;
699}
700
701::llvm::Value *
703 const ConstantStructOperation & op,
704 const std::vector<const Variable *> & args,
705 ::llvm::IRBuilder<> &)
706{
707 ::llvm::LLVMContext & llvmContext = Context_->llvm_module().getContext();
708 auto & typeConverter = Context_->GetTypeConverter();
709
710 std::vector<::llvm::Constant *> operands;
711 for (const auto & arg : args)
712 operands.push_back(::llvm::cast<::llvm::Constant>(Context_->value(arg)));
713
714 auto t = typeConverter.ConvertStructType(op.type(), llvmContext);
715 return ::llvm::ConstantStruct::get(t, operands);
716}
717
718::llvm::Value *
721 const std::vector<const Variable *> &,
722 ::llvm::IRBuilder<> &)
723{
724 ::llvm::LLVMContext & llvmContext = Context_->llvm_module().getContext();
725 auto & typeConverter = Context_->GetTypeConverter();
726
727 auto pointerType = typeConverter.ConvertPointerType(*PointerType::Create(), llvmContext);
728 return ::llvm::ConstantPointerNull::get(pointerType);
729}
730
731::llvm::Value *
733 const rvsdg::SimpleOperation & op,
734 const std::vector<const Variable *> & operands,
735 ::llvm::IRBuilder<> & builder)
736{
737 auto & select = *util::assertedCast<const SelectOperation>(&op);
738
739 if (select.type().Kind() == rvsdg::TypeKind::State)
740 return nullptr;
741
742 auto c = Context_->value(operands[0]);
743 auto t = Context_->value(operands[1]);
744 auto f = Context_->value(operands[2]);
745 return builder.CreateSelect(c, t, f);
746}
747
748::llvm::Value *
750 const rvsdg::SimpleOperation & op,
751 const std::vector<const Variable *> & args,
752 ::llvm::IRBuilder<> &)
753{
754 JLM_ASSERT(is<ControlToIntOperation>(op));
755 return Context_->value(args[0]);
756}
757
758::llvm::Value *
760 const rvsdg::SimpleOperation & op,
761 const std::vector<const Variable *> & operands,
762 ::llvm::IRBuilder<> &)
763{
764 JLM_ASSERT(is<ConstantVectorOperation>(op));
765
766 std::vector<::llvm::Constant *> ops;
767 for (const auto & operand : operands)
768 ops.push_back(::llvm::cast<::llvm::Constant>(Context_->value(operand)));
769
770 return ::llvm::ConstantVector::get(ops);
771}
772
773::llvm::Value *
775 const rvsdg::SimpleOperation & op,
776 const std::vector<const Variable *> & operands,
777 ::llvm::IRBuilder<> & builder)
778{
779 JLM_ASSERT(is<ConstantDataVectorOperation>(op));
780 auto & cop = *static_cast<const ConstantDataVectorOperation *>(&op);
781
782 if (auto bt = dynamic_cast<const rvsdg::BitType *>(&cop.type()))
783 {
784 if (bt->nbits() == 8)
785 {
786 auto data = get_bitdata<uint8_t>(operands);
787 return ::llvm::ConstantDataVector::get(builder.getContext(), data);
788 }
789 else if (bt->nbits() == 16)
790 {
791 auto data = get_bitdata<uint16_t>(operands);
792 return ::llvm::ConstantDataVector::get(builder.getContext(), data);
793 }
794 else if (bt->nbits() == 32)
795 {
796 auto data = get_bitdata<uint32_t>(operands);
797 return ::llvm::ConstantDataVector::get(builder.getContext(), data);
798 }
799 else if (bt->nbits() == 64)
800 {
801 auto data = get_bitdata<uint64_t>(operands);
802 return ::llvm::ConstantDataVector::get(builder.getContext(), data);
803 }
804 }
805
806 if (auto ft = dynamic_cast<const FloatingPointType *>(&cop.type()))
807 {
808 if (ft->size() == fpsize::half)
809 {
810 auto data = get_fpdata<uint16_t>(operands);
811 auto type = ::llvm::Type::getBFloatTy(builder.getContext());
812 return ::llvm::ConstantDataVector::getFP(type, data);
813 }
814 else if (ft->size() == fpsize::flt)
815 {
816 auto data = get_fpdata<uint32_t>(operands);
817 auto type = ::llvm::Type::getFloatTy(builder.getContext());
818 return ::llvm::ConstantDataVector::getFP(type, data);
819 }
820 else if (ft->size() == fpsize::dbl)
821 {
822 auto data = get_fpdata<uint64_t>(operands);
823 auto type = ::llvm::Type::getDoubleTy(builder.getContext());
824 return ::llvm::ConstantDataVector::getFP(type, data);
825 }
826 }
827
828 JLM_UNREACHABLE("This should not have happened!");
829}
830
831::llvm::Value *
833 const rvsdg::SimpleOperation & op,
834 const std::vector<const Variable *> & args,
835 ::llvm::IRBuilder<> & builder)
836{
837 JLM_ASSERT(is<ExtractElementOperation>(op));
838 return builder.CreateExtractElement(Context_->value(args[0]), Context_->value(args[1]));
839}
840
841::llvm::Value *
843 const ShuffleVectorOperation & op,
844 const std::vector<const Variable *> & operands,
845 ::llvm::IRBuilder<> & builder)
846{
847 auto v1 = Context_->value(operands[0]);
848 auto v2 = Context_->value(operands[1]);
849 return builder.CreateShuffleVector(v1, v2, op.Mask());
850}
851
852::llvm::Value *
854 const rvsdg::SimpleOperation & op,
855 const std::vector<const Variable *> & operands,
856 ::llvm::IRBuilder<> & builder)
857{
858 JLM_ASSERT(is<InsertElementOperation>(op));
859
860 auto vector = Context_->value(operands[0]);
861 auto value = Context_->value(operands[1]);
862 auto index = Context_->value(operands[2]);
863 return builder.CreateInsertElement(vector, value, index);
864}
865
866::llvm::Value *
868 const rvsdg::SimpleOperation & op,
869 const rvsdg::SimpleOperation & originalOp,
870 const std::vector<const Variable *> & operands,
871 ::llvm::IRBuilder<> & builder)
872{
873 JLM_ASSERT(is<VectorUnaryOperation>(op));
874 auto vop = static_cast<const VectorUnaryOperation *>(&op);
875 return convert_operation(vop->operation(), originalOp, operands, builder);
876}
877
878::llvm::Value *
880 const rvsdg::SimpleOperation & op,
881 const rvsdg::SimpleOperation & originalOp,
882 const std::vector<const Variable *> & operands,
883 ::llvm::IRBuilder<> & builder)
884{
885 JLM_ASSERT(is<VectorBinaryOperation>(op));
886 auto vop = static_cast<const VectorBinaryOperation *>(&op);
887 return convert_operation(vop->operation(), originalOp, operands, builder);
888}
889
890::llvm::Value *
892 const VectorSelectOperation &,
893 const std::vector<const Variable *> & operands,
894 ::llvm::IRBuilder<> & builder)
895{
896 auto c = Context_->value(operands[0]);
897 auto t = Context_->value(operands[1]);
898 auto f = Context_->value(operands[2]);
899 return builder.CreateSelect(c, t, f);
900}
901
902template<::llvm::Instruction::CastOps OPCODE>
903::llvm::Value *
905 [[maybe_unused]] const rvsdg::SimpleOperation & op,
906 const rvsdg::SimpleOperation & originalOp,
907 const std::vector<const Variable *> & operands,
908 ::llvm::IRBuilder<> & builder)
909{
910 JLM_ASSERT(::llvm::Instruction::isCast(OPCODE));
911 auto & typeConverter = Context_->GetTypeConverter();
912 ::llvm::LLVMContext & llvmContext = Context_->llvm_module().getContext();
913 auto dsttype = originalOp.result(0);
914 auto operand = operands[0];
915
916 auto type = typeConverter.ConvertJlmType(*dsttype, llvmContext);
917 return builder.CreateCast(OPCODE, Context_->value(operand), type);
918}
919
920::llvm::Value *
922 const ExtractValueOperation & op,
923 const std::vector<const Variable *> & operands,
924 ::llvm::IRBuilder<> & builder)
925{
926 std::vector<unsigned> indices(op.begin(), op.end());
927 return builder.CreateExtractValue(Context_->value(operands[0]), indices);
928}
929
930::llvm::Value *
932 const InsertValueOperation & operation,
933 const std::vector<const Variable *> & operands,
934 ::llvm::IRBuilder<> & builder) const
935{
936 const auto aggregateOperand = Context_->value(operands[0]);
937 const auto valueOperand = Context_->value(operands[1]);
938
939 return builder.CreateInsertValue(aggregateOperand, valueOperand, operation.getIndices());
940}
941
942::llvm::Value *
944 const MallocOperation & op,
945 const std::vector<const Variable *> & args,
946 ::llvm::IRBuilder<> & builder)
947{
948 JLM_ASSERT(args.size() == 2);
949 auto & typeConverter = Context_->GetTypeConverter();
950 auto & llvmModule = Context_->llvm_module();
951
952 auto functionType =
953 typeConverter.ConvertFunctionType(op.getFunctionType(), llvmModule.getContext());
954 auto function = llvmModule.getOrInsertFunction("malloc", functionType);
955 auto operands = std::vector(1, Context_->value(args[0]));
956 return builder.CreateCall(function, operands);
957}
958
959::llvm::Value *
961 const FreeOperation & op,
962 const std::vector<const Variable *> & args,
963 ::llvm::IRBuilder<> & builder)
964{
965 auto & typeConverter = Context_->GetTypeConverter();
966 auto & llvmmod = Context_->llvm_module();
967
968 auto fcttype = typeConverter.ConvertFunctionType(
969 rvsdg::FunctionType({ op.argument(0) }, {}),
970 llvmmod.getContext());
971 auto function = llvmmod.getOrInsertFunction("free", fcttype);
972 auto operands = std::vector<::llvm::Value *>(1, Context_->value(args[0]));
973 return builder.CreateCall(function, operands);
974}
975
976::llvm::Value *
979 const std::vector<const Variable *> & operands,
980 ::llvm::IRBuilder<> & builder)
981{
982 auto & destination = *Context_->value(operands[0]);
983 auto & source = *Context_->value(operands[1]);
984 auto & length = *Context_->value(operands[2]);
985
986 return builder.CreateMemCpy(
987 &destination,
988 ::llvm::MaybeAlign(),
989 &source,
990 ::llvm::MaybeAlign(),
991 &length,
992 false);
993}
994
995::llvm::Value *
998 const std::vector<const Variable *> & operands,
999 ::llvm::IRBuilder<> & builder)
1000{
1001 auto & destination = *Context_->value(operands[0]);
1002 auto & source = *Context_->value(operands[1]);
1003 auto & length = *Context_->value(operands[2]);
1004
1005 return builder.CreateMemCpy(
1006 &destination,
1007 ::llvm::MaybeAlign(),
1008 &source,
1009 ::llvm::MaybeAlign(),
1010 &length,
1011 true);
1012}
1013
1014::llvm::Value *
1016 const rvsdg::SimpleOperation &,
1017 const std::vector<const Variable *> & operands,
1018 ::llvm::IRBuilder<> & builder)
1019{
1020 auto destination = Context_->value(operands[0]);
1021 auto value = Context_->value(operands[1]);
1022 auto length = Context_->value(operands[2]);
1023
1024 return builder.CreateMemSet(destination, value, length, ::llvm::MaybeAlign());
1025}
1026
1027::llvm::Value *
1030 const std::vector<const Variable *> &,
1031 ::llvm::IRBuilder<> &)
1032{
1033 return nullptr;
1034}
1035
1036::llvm::Value *
1039 const std::vector<const Variable *> &,
1040 ::llvm::IRBuilder<> &)
1041{
1042 return nullptr;
1043}
1044
1045::llvm::Value *
1048 const std::vector<const Variable *> &,
1049 ::llvm::IRBuilder<> &)
1050{
1051 return nullptr;
1052}
1053
1054::llvm::Value *
1057 const std::vector<const Variable *> &,
1058 ::llvm::IRBuilder<> &)
1059{
1060 return nullptr;
1061}
1062
1063::llvm::Value *
1066 const std::vector<const Variable *> &,
1067 ::llvm::IRBuilder<> &)
1068{
1069 return nullptr;
1070}
1071
1072::llvm::Value *
1075 const std::vector<const Variable *> &,
1076 ::llvm::IRBuilder<> &)
1077{
1078 return nullptr;
1079}
1080
1081::llvm::Value *
1084 const std::vector<const Variable *> & operands,
1085 ::llvm::IRBuilder<> &)
1086{
1087 return Context_->value(operands[0]);
1088}
1089
1090::llvm::Value *
1093 const std::vector<const Variable *> & operands,
1094 ::llvm::IRBuilder<> &)
1095{
1096 return Context_->value(operands[0]);
1097}
1098
1099template<class OP>
1100::llvm::Value *
1102 const rvsdg::SimpleOperation & op,
1103 const std::vector<const Variable *> & operands,
1104 ::llvm::IRBuilder<> & builder)
1105{
1106 JLM_ASSERT(is<OP>(op));
1107 return convert(*static_cast<const OP *>(&op), operands, builder);
1108}
1109
1110::llvm::Value *
1112 const rvsdg::SimpleOperation & op,
1113 const rvsdg::SimpleOperation & originalOp,
1114 const std::vector<const Variable *> & arguments,
1115 ::llvm::IRBuilder<> & builder)
1116{
1117 if (is<IntegerAddOperation>(op))
1118 {
1119 return CreateBinOpInstruction(::llvm::Instruction::Add, arguments, builder);
1120 }
1121 if (is<IntegerAndOperation>(op))
1122 {
1123 return CreateBinOpInstruction(::llvm::Instruction::And, arguments, builder);
1124 }
1125 if (is<IntegerAShrOperation>(op))
1126 {
1127 return CreateBinOpInstruction(::llvm::Instruction::AShr, arguments, builder);
1128 }
1129 if (is<IntegerSubOperation>(op))
1130 {
1131 return CreateBinOpInstruction(::llvm::Instruction::Sub, arguments, builder);
1132 }
1133 if (is<IntegerUDivOperation>(op))
1134 {
1135 return CreateBinOpInstruction(::llvm::Instruction::UDiv, arguments, builder);
1136 }
1137 if (is<IntegerSDivOperation>(op))
1138 {
1139 return CreateBinOpInstruction(::llvm::Instruction::SDiv, arguments, builder);
1140 }
1141 if (is<IntegerURemOperation>(op))
1142 {
1143 return CreateBinOpInstruction(::llvm::Instruction::URem, arguments, builder);
1144 }
1145 if (is<IntegerSRemOperation>(op))
1146 {
1147 return CreateBinOpInstruction(::llvm::Instruction::SRem, arguments, builder);
1148 }
1149 if (is<IntegerShlOperation>(op))
1150 {
1151 return CreateBinOpInstruction(::llvm::Instruction::Shl, arguments, builder);
1152 }
1153 if (is<IntegerLShrOperation>(op))
1154 {
1155 return CreateBinOpInstruction(::llvm::Instruction::LShr, arguments, builder);
1156 }
1157 if (is<IntegerOrOperation>(op))
1158 {
1159 return CreateBinOpInstruction(::llvm::Instruction::Or, arguments, builder);
1160 }
1161 if (is<IntegerXorOperation>(op))
1162 {
1163 return CreateBinOpInstruction(::llvm::Instruction::Xor, arguments, builder);
1164 }
1165 if (is<IntegerMulOperation>(op))
1166 {
1167 return CreateBinOpInstruction(::llvm::Instruction::Mul, arguments, builder);
1168 }
1169 if (is<IntegerEqOperation>(op))
1170 {
1171 return CreateICmpInstruction(::llvm::CmpInst::ICMP_EQ, arguments, builder);
1172 }
1173 if (is<IntegerNeOperation>(op))
1174 {
1175 return CreateICmpInstruction(::llvm::CmpInst::ICMP_NE, arguments, builder);
1176 }
1177 if (is<IntegerUgtOperation>(op))
1178 {
1179 return CreateICmpInstruction(::llvm::CmpInst::ICMP_UGT, arguments, builder);
1180 }
1181 if (is<IntegerUgeOperation>(op))
1182 {
1183 return CreateICmpInstruction(::llvm::CmpInst::ICMP_UGE, arguments, builder);
1184 }
1185 if (is<IntegerUltOperation>(op))
1186 {
1187 return CreateICmpInstruction(::llvm::CmpInst::ICMP_ULT, arguments, builder);
1188 }
1189 if (is<IntegerUleOperation>(op))
1190 {
1191 return CreateICmpInstruction(::llvm::CmpInst::ICMP_ULE, arguments, builder);
1192 }
1193 if (is<IntegerSgtOperation>(op))
1194 {
1195 return CreateICmpInstruction(::llvm::CmpInst::ICMP_SGT, arguments, builder);
1196 }
1197 if (is<IntegerSgeOperation>(op))
1198 {
1199 return CreateICmpInstruction(::llvm::CmpInst::ICMP_SGE, arguments, builder);
1200 }
1201 if (is<IntegerSltOperation>(op))
1202 {
1203 return CreateICmpInstruction(::llvm::CmpInst::ICMP_SLT, arguments, builder);
1204 }
1205 if (is<IntegerSleOperation>(op))
1206 {
1207 return CreateICmpInstruction(::llvm::CmpInst::ICMP_SLE, arguments, builder);
1208 }
1209 if (is<IOBarrierOperation>(op))
1210 {
1211 return Context_->value(arguments[0]);
1212 }
1213 if (is<IntegerConstantOperation>(op))
1214 {
1215 return ConverterIntegerConstant(op, arguments, builder);
1216 }
1217 if (is<rvsdg::ControlConstantOperation>(op))
1218 {
1219 return convert_ctlconstant(op, arguments, builder);
1220 }
1221 if (is<ConstantFP>(op))
1222 {
1223 return convert<ConstantFP>(op, arguments, builder);
1224 }
1225 if (is<UndefValueOperation>(op))
1226 {
1227 return convert_undef(op, arguments, builder);
1228 }
1229 if (is<PoisonValueOperation>(op))
1230 {
1231 return convert<PoisonValueOperation>(op, arguments, builder);
1232 }
1233 if (is<FreezeOperation>(op))
1234 {
1235 return convert<FreezeOperation>(op, arguments, builder);
1236 }
1237 if (is<rvsdg::MatchOperation>(op))
1238 {
1239 return convert_match(op, arguments, builder);
1240 }
1241 if (is<AssignmentOperation>(op))
1242 {
1243 return convert_assignment(op, arguments, builder);
1244 }
1245 if (is<BranchOperation>(op))
1246 {
1247 return convert_branch(op, arguments, builder);
1248 }
1249 if (is<SsaPhiOperation>(op))
1250 {
1251 return convert_phi(op, arguments, builder);
1252 }
1253 if (is<LoadNonVolatileOperation>(op))
1254 {
1255 return convert<LoadNonVolatileOperation>(op, arguments, builder);
1256 }
1257 if (is<LoadVolatileOperation>(op))
1258 {
1259 return convert<LoadVolatileOperation>(op, arguments, builder);
1260 }
1261 if (is<StoreNonVolatileOperation>(op))
1262 {
1263 return convert_store(op, arguments, builder);
1264 }
1265 if (is<StoreVolatileOperation>(op))
1266 {
1267 return convert<StoreVolatileOperation>(op, arguments, builder);
1268 }
1269 if (is<AllocaOperation>(op))
1270 {
1271 return convert_alloca(op, arguments, builder);
1272 }
1273 if (is<GetElementPtrOperation>(op))
1274 {
1275 return convert_getelementptr(op, arguments, builder);
1276 }
1277 if (is<ConstantDataArrayOperation>(op))
1278 {
1279 return convert<ConstantDataArrayOperation>(op, arguments, builder);
1280 }
1281 if (is<PtrCmpOperation>(op))
1282 {
1283 return convert_ptrcmp(op, arguments, builder);
1284 }
1285 if (is<FCmpOperation>(op))
1286 {
1287 return convert_fpcmp(op, arguments, builder);
1288 }
1289 if (is<FBinaryOperation>(op))
1290 {
1291 return convert_fpbin(op, arguments, builder);
1292 }
1293 if (is<VariadicArgumentListOperation>(op))
1294 {
1295 return convert_valist(op, arguments, builder);
1296 }
1297 if (is<ConstantStructOperation>(op))
1298 {
1299 return convert<ConstantStructOperation>(op, arguments, builder);
1300 }
1301 if (is<ConstantPointerNullOperation>(op))
1302 {
1303 return convert<ConstantPointerNullOperation>(op, arguments, builder);
1304 }
1305 if (is<SelectOperation>(op))
1306 {
1307 return convert_select(op, arguments, builder);
1308 }
1309 if (is<ConstantArrayOperation>(op))
1310 {
1311 return convert<ConstantArrayOperation>(op, arguments, builder);
1312 }
1313 if (is<ConstantAggregateZeroOperation>(op))
1314 {
1315 return convert<ConstantAggregateZeroOperation>(op, arguments, builder);
1316 }
1317 if (is<ControlToIntOperation>(op))
1318 {
1319 return convert_ctl2bits(op, arguments, builder);
1320 }
1321 if (is<ConstantVectorOperation>(op))
1322 {
1323 return convert_constantvector(op, arguments, builder);
1324 }
1325 if (is<ConstantDataVectorOperation>(op))
1326 {
1327 return convert_constantdatavector(op, arguments, builder);
1328 }
1329 if (is<ExtractElementOperation>(op))
1330 {
1331 return convert_extractelement(op, arguments, builder);
1332 }
1333 if (is<ShuffleVectorOperation>(op))
1334 {
1335 return convert<ShuffleVectorOperation>(op, arguments, builder);
1336 }
1337 if (is<InsertElementOperation>(op))
1338 {
1339 return convert_insertelement(op, arguments, builder);
1340 }
1341 if (is<VectorUnaryOperation>(op))
1342 {
1343 return convert_vectorunary(op, originalOp, arguments, builder);
1344 }
1345 if (is<VectorBinaryOperation>(op))
1346 {
1347 return convert_vectorbinary(op, originalOp, arguments, builder);
1348 }
1349 if (is<VectorSelectOperation>(op))
1350 {
1351 return convert<VectorSelectOperation>(op, arguments, builder);
1352 }
1353 if (is<ExtractValueOperation>(op))
1354 {
1355 return convert<ExtractValueOperation>(op, arguments, builder);
1356 }
1357 if (const auto insertValueOperation = dynamic_cast<const InsertValueOperation *>(&op))
1358 {
1359 return convertInsertValueOperation(*insertValueOperation, arguments, builder);
1360 }
1361 if (is<CallOperation>(op))
1362 {
1363 return convert<CallOperation>(op, arguments, builder);
1364 }
1365 if (is<MallocOperation>(op))
1366 {
1367 return convert<MallocOperation>(op, arguments, builder);
1368 }
1369 if (is<FreeOperation>(op))
1370 {
1371 return convert<FreeOperation>(op, arguments, builder);
1372 }
1373 if (is<MemCpyNonVolatileOperation>(op))
1374 {
1375 return convert<MemCpyNonVolatileOperation>(op, arguments, builder);
1376 }
1377 if (is<MemCpyVolatileOperation>(op))
1378 {
1379 return convert<MemCpyVolatileOperation>(op, arguments, builder);
1380 }
1381 if (is<MemSetNonVolatileOperation>(op))
1382 {
1383 return convertMemsetNonVolatileOperation(op, arguments, builder);
1384 }
1385 if (is<MemMoveNonVolatileOperation>(op))
1386 {
1387 const auto destOperand = Context_->value(arguments[0]);
1388 const auto srcOperand = Context_->value(arguments[1]);
1389 const auto lengthOperand = Context_->value(arguments[2]);
1390
1391 return builder.CreateMemMove(
1392 destOperand,
1393 ::llvm::MaybeAlign(),
1394 srcOperand,
1395 ::llvm::MaybeAlign(),
1396 lengthOperand);
1397 }
1398 if (is<FNegOperation>(op))
1399 {
1400 return convert_fpneg(op, arguments, builder);
1401 }
1402 if (is<BitCastOperation>(op))
1403 {
1404 return convert_cast<::llvm::Instruction::BitCast>(op, originalOp, arguments, builder);
1405 }
1406 if (is<FPExtOperation>(op))
1407 {
1408 return convert_cast<::llvm::Instruction::FPExt>(op, originalOp, arguments, builder);
1409 }
1410 if (is<FPToSIOperation>(op))
1411 {
1412 return convert_cast<::llvm::Instruction::FPToSI>(op, originalOp, arguments, builder);
1413 }
1414 if (is<FPToUIOperation>(op))
1415 {
1416 return convert_cast<::llvm::Instruction::FPToUI>(op, originalOp, arguments, builder);
1417 }
1418 if (is<FPTruncOperation>(op))
1419 {
1420 return convert_cast<::llvm::Instruction::FPTrunc>(op, originalOp, arguments, builder);
1421 }
1422 if (is<IntToPtrOperation>(op))
1423 {
1424 return convert_cast<::llvm::Instruction::IntToPtr>(op, originalOp, arguments, builder);
1425 }
1426 if (is<PtrToIntOperation>(op))
1427 {
1428 return convert_cast<::llvm::Instruction::PtrToInt>(op, originalOp, arguments, builder);
1429 }
1430 if (is<SExtOperation>(op))
1431 {
1432 return convert_cast<::llvm::Instruction::SExt>(op, originalOp, arguments, builder);
1433 }
1434 if (is<SIToFPOperation>(op))
1435 {
1436 return convert_cast<::llvm::Instruction::SIToFP>(op, originalOp, arguments, builder);
1437 }
1438 if (is<TruncOperation>(op))
1439 {
1440 return convert_cast<::llvm::Instruction::Trunc>(op, originalOp, arguments, builder);
1441 }
1442 if (is<UIToFPOperation>(op))
1443 {
1444 return convert_cast<::llvm::Instruction::UIToFP>(op, originalOp, arguments, builder);
1445 }
1446 if (is<ZExtOperation>(op))
1447 {
1448 return convert_cast<::llvm::Instruction::ZExt>(op, originalOp, arguments, builder);
1449 }
1450 if (is<MemoryStateMergeOperation>(op))
1451 {
1452 return convert<MemoryStateMergeOperation>(op, arguments, builder);
1453 }
1454 if (is<MemoryStateJoinOperation>(op))
1455 {
1456 // This operation has no equivalent LLVM instruction.
1457 // Nothing needs to be done.
1458 return nullptr;
1459 }
1460 if (is<MemoryStateSplitOperation>(op))
1461 {
1462 return convert<MemoryStateSplitOperation>(op, arguments, builder);
1463 }
1464 if (is<LambdaEntryMemoryStateSplitOperation>(op))
1465 {
1466 return convert<LambdaEntryMemoryStateSplitOperation>(op, arguments, builder);
1467 }
1468 if (is<LambdaExitMemoryStateMergeOperation>(op))
1469 {
1470 return convert<LambdaExitMemoryStateMergeOperation>(op, arguments, builder);
1471 }
1472 if (is<CallEntryMemoryStateMergeOperation>(op))
1473 {
1474 return convert<CallEntryMemoryStateMergeOperation>(op, arguments, builder);
1475 }
1476 if (is<CallExitMemoryStateSplitOperation>(op))
1477 {
1478 return convert<CallExitMemoryStateSplitOperation>(op, arguments, builder);
1479 }
1480 if (is<PointerToFunctionOperation>(op))
1481 {
1482 return convert<PointerToFunctionOperation>(op, arguments, builder);
1483 }
1484 if (is<FunctionToPointerOperation>(op))
1485 {
1486 return convert<FunctionToPointerOperation>(op, arguments, builder);
1487 }
1488 if (is<FMulAddIntrinsicOperation>(op))
1489 {
1490 auto multiplier = Context_->value(arguments[0]);
1491 auto multiplicand = Context_->value(arguments[1]);
1492 auto summand = Context_->value(arguments[2]);
1493
1494 auto type =
1495 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1496 return builder.CreateIntrinsic(
1497 ::llvm::Intrinsic::fmuladd,
1498 { type },
1499 { multiplier, multiplicand, summand });
1500 }
1501 if (is<SMaxOperation>(op))
1502 {
1503 auto operand1 = Context_->value(arguments[0]);
1504 auto operand2 = Context_->value(arguments[1]);
1505
1506 auto type =
1507 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1508 return builder.CreateIntrinsic(::llvm::Intrinsic::smax, { type }, { operand1, operand2 });
1509 }
1510 if (is<UMaxOperation>(op))
1511 {
1512 auto operand1 = Context_->value(arguments[0]);
1513 auto operand2 = Context_->value(arguments[1]);
1514
1515 auto type =
1516 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1517 return builder.CreateIntrinsic(::llvm::Intrinsic::umax, { type }, { operand1, operand2 });
1518 }
1519 if (is<SMinOperation>(op))
1520 {
1521 auto operand1 = Context_->value(arguments[0]);
1522 auto operand2 = Context_->value(arguments[1]);
1523
1524 auto type =
1525 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1526 return builder.CreateIntrinsic(::llvm::Intrinsic::smin, { type }, { operand1, operand2 });
1527 }
1528 if (is<UMinOperation>(op))
1529 {
1530 auto operand1 = Context_->value(arguments[0]);
1531 auto operand2 = Context_->value(arguments[1]);
1532
1533 auto type =
1534 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1535 return builder.CreateIntrinsic(::llvm::Intrinsic::umin, { type }, { operand1, operand2 });
1536 }
1537 if (is<FAbsOperation>(op))
1538 {
1539 auto operand = Context_->value(arguments[0]);
1540
1541 auto type =
1542 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1543 return builder.CreateIntrinsic(::llvm::Intrinsic::fabs, { type }, { operand });
1544 }
1545 if (is<FShlOperation>(op))
1546 {
1547 auto operand1 = Context_->value(arguments[0]);
1548 auto operand2 = Context_->value(arguments[1]);
1549 auto operand3 = Context_->value(arguments[2]);
1550
1551 auto type =
1552 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1553 return builder.CreateIntrinsic(
1554 ::llvm::Intrinsic::fshl,
1555 { type },
1556 { operand1, operand2, operand3 });
1557 }
1558 if (is<FloorOperation>(op))
1559 {
1560 auto operand = Context_->value(arguments[0]);
1561
1562 auto type =
1563 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1564 return builder.CreateIntrinsic(::llvm::Intrinsic::floor, { type }, { operand });
1565 }
1566 if (is<AbsOperation>(op))
1567 {
1568 auto operand1 = Context_->value(arguments[0]);
1569 auto operand2 = Context_->value(arguments[1]);
1570
1571 auto type =
1572 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1573 return builder.CreateIntrinsic(::llvm::Intrinsic::abs, { type }, { operand1, operand2 });
1574 }
1575 if (is<CeilOperation>(op))
1576 {
1577 auto operand = Context_->value(arguments[0]);
1578
1579 auto type =
1580 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1581 return builder.CreateIntrinsic(::llvm::Intrinsic::ceil, { type }, { operand });
1582 }
1583 if (is<RIntOperation>(op))
1584 {
1585 auto operand = Context_->value(arguments[0]);
1586
1587 auto type =
1588 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1589 return builder.CreateIntrinsic(::llvm::Intrinsic::rint, { type }, { operand });
1590 }
1591 if (is<TruncIntrinsicOperation>(op))
1592 {
1593 auto operand = Context_->value(arguments[0]);
1594
1595 auto type =
1596 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1597 return builder.CreateIntrinsic(::llvm::Intrinsic::trunc, { type }, { operand });
1598 }
1599 if (is<BSwapOperation>(op))
1600 {
1601 auto operand = Context_->value(arguments[0]);
1602
1603 auto type =
1604 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1605 return builder.CreateIntrinsic(::llvm::Intrinsic::bswap, { type }, { operand });
1606 }
1607 if (is<CtlzOperation>(op))
1608 {
1609 auto operand = Context_->value(arguments[0]);
1610 auto isZeroPoison = Context_->value(arguments[1]);
1611
1612 auto type =
1613 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1614 return builder.CreateIntrinsic(::llvm::Intrinsic::ctlz, { type }, { operand, isZeroPoison });
1615 }
1616 if (is<CttzOperation>(op))
1617 {
1618 auto operand = Context_->value(arguments[0]);
1619 auto isZeroPoison = Context_->value(arguments[1]);
1620
1621 auto type =
1622 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1623 return builder.CreateIntrinsic(::llvm::Intrinsic::cttz, { type }, { operand, isZeroPoison });
1624 }
1625 if (is<CtpopOperation>(op))
1626 {
1627 auto operand = Context_->value(arguments[0]);
1628
1629 auto type =
1630 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1631 return builder.CreateIntrinsic(::llvm::Intrinsic::ctpop, { type }, { operand });
1632 }
1633 if (is<IsConstantOperation>(op))
1634 {
1635 auto operand = Context_->value(arguments[0]);
1636
1637 auto type =
1638 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1639 return builder.CreateIntrinsic(::llvm::Intrinsic::is_constant, { type }, { operand });
1640 }
1641 if (is<IsFPClassOperation>(op))
1642 {
1643 auto operand1 = Context_->value(arguments[0]);
1644 auto operand2 = Context_->value(arguments[1]);
1645
1646 auto type =
1647 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1648 return builder.CreateIntrinsic(::llvm::Intrinsic::is_fpclass, { type }, { operand1, operand2 });
1649 }
1650 if (is<SAddWithOverflowOperation>(op))
1651 {
1652 auto operand1 = Context_->value(arguments[0]);
1653 auto operand2 = Context_->value(arguments[1]);
1654
1655 auto type =
1656 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1657 return builder.CreateIntrinsic(
1658 ::llvm::Intrinsic::sadd_with_overflow,
1659 { type },
1660 { operand1, operand2 });
1661 }
1662 if (is<UAddWithOverflowOperation>(op))
1663 {
1664 auto operand1 = Context_->value(arguments[0]);
1665 auto operand2 = Context_->value(arguments[1]);
1666
1667 auto type =
1668 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1669 return builder.CreateIntrinsic(
1670 ::llvm::Intrinsic::uadd_with_overflow,
1671 { type },
1672 { operand1, operand2 });
1673 }
1674 if (is<SSubWithOverflowOperation>(op))
1675 {
1676 auto operand1 = Context_->value(arguments[0]);
1677 auto operand2 = Context_->value(arguments[1]);
1678
1679 auto type =
1680 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1681 return builder.CreateIntrinsic(
1682 ::llvm::Intrinsic::ssub_with_overflow,
1683 { type },
1684 { operand1, operand2 });
1685 }
1686 if (is<SMulWithOverflowOperation>(op))
1687 {
1688 auto operand1 = Context_->value(arguments[0]);
1689 auto operand2 = Context_->value(arguments[1]);
1690
1691 auto type =
1692 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1693 return builder.CreateIntrinsic(
1694 ::llvm::Intrinsic::smul_with_overflow,
1695 { type },
1696 { operand1, operand2 });
1697 }
1698 if (is<RoundOperation>(op))
1699 {
1700 auto operand = Context_->value(arguments[0]);
1701
1702 auto type =
1703 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1704 return builder.CreateIntrinsic(::llvm::Intrinsic::round, { type }, { operand });
1705 }
1706 if (is<UMulWithOverflowOperation>(op))
1707 {
1708 auto operand1 = Context_->value(arguments[0]);
1709 auto operand2 = Context_->value(arguments[1]);
1710
1711 auto type =
1712 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1713 return builder.CreateIntrinsic(
1714 ::llvm::Intrinsic::umul_with_overflow,
1715 { type },
1716 { operand1, operand2 });
1717 }
1718 if (is<CopysignOperation>(op))
1719 {
1720 auto operand1 = Context_->value(arguments[0]);
1721 auto operand2 = Context_->value(arguments[1]);
1722
1723 auto type =
1724 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1725 return builder.CreateIntrinsic(::llvm::Intrinsic::copysign, { type }, { operand1, operand2 });
1726 }
1727 if (is<PtrMaskOperation>(op))
1728 {
1729 auto ptrOperand = Context_->value(arguments[0]);
1730 auto maskOperand = Context_->value(arguments[1]);
1731
1732 return builder.CreateIntrinsic(
1733 ::llvm::Intrinsic::ptrmask,
1734 { ptrOperand->getType(), maskOperand->getType() },
1735 { ptrOperand, maskOperand });
1736 }
1737
1738 JLM_UNREACHABLE(util::strfmt("Unhandled operation type: ", op.debug_string()).c_str());
1739}
1740
1741void
1743 const llvm::ThreeAddressCode & tac,
1744 const llvm::ControlFlowGraphNode * node)
1745{
1746 std::vector<const Variable *> operands;
1747 for (size_t n = 0; n < tac.noperands(); n++)
1748 operands.push_back(tac.operand(n));
1749
1750 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1751 const auto & op = tac.operation();
1752 auto r = convert_operation(op, op, operands, builder);
1753 if (r != nullptr)
1754 Context_->insert(tac.result(0), r);
1755}
1756
1757void
1759{
1760 ::llvm::IRBuilder<> builder(Context_->llvm_module().getContext());
1761 for (const auto & tac : tacs)
1762 {
1763 std::vector<const Variable *> operands;
1764 for (size_t n = 0; n < tac->noperands(); n++)
1765 operands.push_back(tac->operand(n));
1766
1767 JLM_ASSERT(tac->nresults() == 1);
1768 const auto & op = tac->operation();
1769 auto r = convert_operation(op, op, operands, builder);
1770 Context_->insert(tac->result(0), r);
1771 }
1772}
1773
1774static const llvm::ThreeAddressCode *
1776{
1777 JLM_ASSERT(is<ThreeAddressCodeVariable>(branch->operand(0)));
1778 auto tv = static_cast<const ThreeAddressCodeVariable *>(branch->operand(0));
1779 return tv->tac();
1780}
1781
1782static bool
1784{
1785 for (size_t n = 0; n < cfg.exit()->nresults(); n++)
1786 {
1787 auto result = cfg.exit()->result(n);
1788 if (result->Type()->Kind() == rvsdg::TypeKind::Value)
1789 return true;
1790 }
1791
1792 return false;
1793}
1794
1795void
1797{
1798 JLM_ASSERT(node->NumOutEdges() == 1);
1799 JLM_ASSERT(node->OutEdge(0)->sink() == node->cfg().exit());
1800 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1801 auto & cfg = node->cfg();
1802
1803 /* return without result */
1804 if (!has_return_value(cfg))
1805 {
1806 builder.CreateRetVoid();
1807 return;
1808 }
1809
1810 auto result = cfg.exit()->result(0);
1811 JLM_ASSERT(result->Type()->Kind() == rvsdg::TypeKind::Value);
1812 builder.CreateRet(Context_->value(result));
1813}
1814
1815void
1817{
1818 JLM_ASSERT(node->NumOutEdges() == 1);
1819 JLM_ASSERT(node->OutEdge(0)->sink() != node->cfg().exit());
1820 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1821 auto target = node->OutEdge(0)->sink();
1822
1823 builder.CreateBr(Context_->basic_block(target));
1824}
1825
1826void
1828{
1829 JLM_ASSERT(node->NumOutEdges() == 2);
1830 JLM_ASSERT(node->OutEdge(0)->sink() != node->cfg().exit());
1831 JLM_ASSERT(node->OutEdge(1)->sink() != node->cfg().exit());
1832 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1833
1834 auto branch = static_cast<const BasicBlock *>(node)->tacs().last();
1835 JLM_ASSERT(branch && is<BranchOperation>(branch));
1836 JLM_ASSERT(Context_->value(branch->operand(0))->getType()->isIntegerTy(1));
1837
1838 auto condition = Context_->value(branch->operand(0));
1839 auto bbfalse = Context_->basic_block(node->OutEdge(0)->sink());
1840 auto bbtrue = Context_->basic_block(node->OutEdge(1)->sink());
1841 builder.CreateCondBr(condition, bbtrue, bbfalse);
1842}
1843
1844void
1846{
1847 JLM_ASSERT(node->NumOutEdges() >= 2);
1848 ::llvm::LLVMContext & llvmContext = Context_->llvm_module().getContext();
1849 auto & typeConverter = Context_->GetTypeConverter();
1850 auto bb = static_cast<const BasicBlock *>(node);
1851 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1852
1853 auto branch = bb->tacs().last();
1854 JLM_ASSERT(branch && is<BranchOperation>(branch));
1855 auto condition = Context_->value(branch->operand(0));
1856 auto match = get_match(branch);
1857
1858 if (is<rvsdg::MatchOperation>(match))
1859 {
1860 JLM_ASSERT(match->result(0) == branch->operand(0));
1861 auto mop = static_cast<const rvsdg::MatchOperation *>(&match->operation());
1862
1863 auto defbb = Context_->basic_block(node->OutEdge(mop->default_alternative())->sink());
1864 auto sw = builder.CreateSwitch(condition, defbb);
1865 for (const auto & alt : *mop)
1866 {
1867 auto & type = *std::static_pointer_cast<const rvsdg::BitType>(mop->argument(0));
1868 auto value =
1869 ::llvm::ConstantInt::get(typeConverter.ConvertBitType(type, llvmContext), alt.first);
1870 sw->addCase(value, Context_->basic_block(node->OutEdge(alt.second)->sink()));
1871 }
1872 }
1873 else
1874 {
1875 auto defbb = Context_->basic_block(node->OutEdge(node->NumOutEdges() - 1)->sink());
1876 auto sw = builder.CreateSwitch(condition, defbb);
1877 for (size_t n = 0; n < node->NumOutEdges() - 1; n++)
1878 {
1879 auto value = ::llvm::ConstantInt::get(::llvm::Type::getInt32Ty(builder.getContext()), n);
1880 sw->addCase(value, Context_->basic_block(node->OutEdge(n)->sink()));
1881 }
1882 }
1883}
1884
1885void
1887{
1888 JLM_ASSERT(is<BasicBlock>(node));
1889 auto & tacs = static_cast<const BasicBlock *>(node)->tacs();
1890 auto & cfg = node->cfg();
1891
1892 // unconditional branch or return statement
1893 if (node->NumOutEdges() == 1)
1894 {
1895 auto target = node->OutEdge(0)->sink();
1896 if (target == cfg.exit())
1897 return create_return(node);
1898
1899 return create_unconditional_branch(node);
1900 }
1901
1902 auto branch = tacs.last();
1903 JLM_ASSERT(branch && is<BranchOperation>(branch));
1904
1905 // conditional branch
1906 if (Context_->value(branch->operand(0))->getType()->isIntegerTy(1))
1907 return create_conditional_branch(node);
1908
1909 // switch
1910 create_switch(node);
1911}
1912
1913::llvm::Attribute::AttrKind
1915{
1916 typedef ::llvm::Attribute::AttrKind ak;
1917
1918 static std::unordered_map<Attribute::kind, ::llvm::Attribute::AttrKind> map(
1919 { { Attribute::kind::None, ak::None },
1920
1921 { Attribute::kind::FirstEnumAttr, ak::FirstEnumAttr },
1922 { Attribute::kind::AllocAlign, ak::AllocAlign },
1923 { Attribute::kind::AllocatedPointer, ak::AllocatedPointer },
1924 { Attribute::kind::AlwaysInline, ak::AlwaysInline },
1925 { Attribute::kind::Builtin, ak::Builtin },
1926 { Attribute::kind::Cold, ak::Cold },
1927 { Attribute::kind::Convergent, ak::Convergent },
1928 { Attribute::kind::CoroDestroyOnlyWhenComplete, ak::CoroDestroyOnlyWhenComplete },
1929 { Attribute::kind::DeadOnUnwind, ak::DeadOnUnwind },
1930 { Attribute::kind::DisableSanitizerInstrumentation, ak::DisableSanitizerInstrumentation },
1931 { Attribute::kind::FnRetThunkExtern, ak::FnRetThunkExtern },
1932 { Attribute::kind::Hot, ak::Hot },
1933 { Attribute::kind::ImmArg, ak::ImmArg },
1934 { Attribute::kind::InReg, ak::InReg },
1935 { Attribute::kind::InlineHint, ak::InlineHint },
1936 { Attribute::kind::JumpTable, ak::JumpTable },
1937 { Attribute::kind::Memory, ak::Memory },
1938 { Attribute::kind::MinSize, ak::MinSize },
1939 { Attribute::kind::MustProgress, ak::MustProgress },
1940 { Attribute::kind::Naked, ak::Naked },
1941 { Attribute::kind::Nest, ak::Nest },
1942 { Attribute::kind::NoAlias, ak::NoAlias },
1943 { Attribute::kind::NoBuiltin, ak::NoBuiltin },
1944 { Attribute::kind::NoCallback, ak::NoCallback },
1945 { Attribute::kind::NoCapture, ak::NoCapture },
1946 { Attribute::kind::NoCfCheck, ak::NoCfCheck },
1947 { Attribute::kind::NoDuplicate, ak::NoDuplicate },
1948 { Attribute::kind::NoFree, ak::NoFree },
1949 { Attribute::kind::NoImplicitFloat, ak::NoImplicitFloat },
1950 { Attribute::kind::NoInline, ak::NoInline },
1951 { Attribute::kind::NoMerge, ak::NoMerge },
1952 { Attribute::kind::NoProfile, ak::NoProfile },
1953 { Attribute::kind::NoRecurse, ak::NoRecurse },
1954 { Attribute::kind::NoRedZone, ak::NoRedZone },
1955 { Attribute::kind::NoReturn, ak::NoReturn },
1956 { Attribute::kind::NoSanitizeBounds, ak::NoSanitizeBounds },
1957 { Attribute::kind::NoSanitizeCoverage, ak::NoSanitizeCoverage },
1958 { Attribute::kind::NoSync, ak::NoSync },
1959 { Attribute::kind::NoUndef, ak::NoUndef },
1960 { Attribute::kind::NoUnwind, ak::NoUnwind },
1961 { Attribute::kind::NonLazyBind, ak::NonLazyBind },
1962 { Attribute::kind::NonNull, ak::NonNull },
1963 { Attribute::kind::NullPointerIsValid, ak::NullPointerIsValid },
1964 { Attribute::kind::OptForFuzzing, ak::OptForFuzzing },
1965 { Attribute::kind::OptimizeForDebugging, ak::OptimizeForDebugging },
1966 { Attribute::kind::OptimizeForSize, ak::OptimizeForSize },
1967 { Attribute::kind::OptimizeNone, ak::OptimizeNone },
1968 { Attribute::kind::PresplitCoroutine, ak::PresplitCoroutine },
1969 { Attribute::kind::ReadNone, ak::ReadNone },
1970 { Attribute::kind::ReadOnly, ak::ReadOnly },
1971 { Attribute::kind::Returned, ak::Returned },
1972 { Attribute::kind::ReturnsTwice, ak::ReturnsTwice },
1973 { Attribute::kind::SExt, ak::SExt },
1974 { Attribute::kind::SafeStack, ak::SafeStack },
1975 { Attribute::kind::SanitizeAddress, ak::SanitizeAddress },
1976 { Attribute::kind::SanitizeHWAddress, ak::SanitizeHWAddress },
1977 { Attribute::kind::SanitizeMemTag, ak::SanitizeMemTag },
1978 { Attribute::kind::SanitizeMemory, ak::SanitizeMemory },
1979 { Attribute::kind::SanitizeThread, ak::SanitizeThread },
1980 { Attribute::kind::ShadowCallStack, ak::ShadowCallStack },
1981 { Attribute::kind::SkipProfile, ak::SkipProfile },
1982 { Attribute::kind::Speculatable, ak::Speculatable },
1983 { Attribute::kind::SpeculativeLoadHardening, ak::SpeculativeLoadHardening },
1984 { Attribute::kind::StackProtect, ak::StackProtect },
1985 { Attribute::kind::StackProtectReq, ak::StackProtectReq },
1986 { Attribute::kind::StackProtectStrong, ak::StackProtectStrong },
1987 { Attribute::kind::StrictFP, ak::StrictFP },
1988 { Attribute::kind::SwiftAsync, ak::SwiftAsync },
1989 { Attribute::kind::SwiftError, ak::SwiftError },
1990 { Attribute::kind::SwiftSelf, ak::SwiftSelf },
1991 { Attribute::kind::WillReturn, ak::WillReturn },
1992 { Attribute::kind::Writable, ak::Writable },
1993 { Attribute::kind::WriteOnly, ak::WriteOnly },
1994 { Attribute::kind::ZExt, ak::ZExt },
1995 { Attribute::kind::LastEnumAttr, ak::LastEnumAttr },
1996
1997 { Attribute::kind::FirstTypeAttr, ak::FirstTypeAttr },
1998 { Attribute::kind::ByRef, ak::ByRef },
1999 { Attribute::kind::ByVal, ak::ByVal },
2000 { Attribute::kind::ElementType, ak::ElementType },
2001 { Attribute::kind::InAlloca, ak::InAlloca },
2002 { Attribute::kind::Preallocated, ak::Preallocated },
2003 { Attribute::kind::StructRet, ak::StructRet },
2004 { Attribute::kind::LastTypeAttr, ak::LastTypeAttr },
2005
2006 { Attribute::kind::FirstIntAttr, ak::FirstIntAttr },
2007 { Attribute::kind::Alignment, ak::Alignment },
2008 { Attribute::kind::AllocKind, ak::AllocKind },
2009 { Attribute::kind::AllocSize, ak::AllocSize },
2010 { Attribute::kind::Dereferenceable, ak::Dereferenceable },
2011 { Attribute::kind::DereferenceableOrNull, ak::DereferenceableOrNull },
2012 { Attribute::kind::NoFPClass, ak::NoFPClass },
2013 { Attribute::kind::StackAlignment, ak::StackAlignment },
2014 { Attribute::kind::UWTable, ak::UWTable },
2015 { Attribute::kind::VScaleRange, ak::VScaleRange },
2016 { Attribute::kind::LastIntAttr, ak::LastIntAttr },
2017
2018 { Attribute::kind::EndAttrKinds, ak::EndAttrKinds } });
2019
2020 JLM_ASSERT(map.find(kind) != map.end());
2021 return map[kind];
2022}
2023
2024::llvm::Attribute
2026{
2027 auto & llvmContext = Context_->llvm_module().getContext();
2028 auto kind = ConvertAttributeKind(attribute.kind());
2029 return ::llvm::Attribute::get(llvmContext, kind);
2030}
2031
2032::llvm::Attribute
2034{
2035 auto & llvmContext = Context_->llvm_module().getContext();
2036 auto kind = ConvertAttributeKind(attribute.kind());
2037 return ::llvm::Attribute::get(llvmContext, kind, attribute.value());
2038}
2039
2040::llvm::Attribute
2042{
2043 auto & typeConverter = Context_->GetTypeConverter();
2044 auto & llvmContext = Context_->llvm_module().getContext();
2045
2046 auto kind = ConvertAttributeKind(attribute.kind());
2047 auto type = typeConverter.ConvertJlmType(attribute.type(), llvmContext);
2048 return ::llvm::Attribute::get(llvmContext, kind, type);
2049}
2050
2051::llvm::Attribute
2053{
2054 auto & llvmContext = Context_->llvm_module().getContext();
2055 return ::llvm::Attribute::get(llvmContext, attribute.kind(), attribute.value());
2056}
2057
2058::llvm::AttributeSet
2060{
2061 ::llvm::AttrBuilder builder(Context_->llvm_module().getContext());
2062 for (auto & attribute : attributeSet.EnumAttributes())
2063 builder.addAttribute(ConvertEnumAttribute(attribute));
2064
2065 for (auto & attribute : attributeSet.IntAttributes())
2066 builder.addAttribute(ConvertIntAttribute(attribute));
2067
2068 for (auto & attribute : attributeSet.TypeAttributes())
2069 builder.addAttribute(ConvertTypeAttribute(attribute));
2070
2071 for (auto & attribute : attributeSet.StringAttributes())
2072 builder.addAttribute(ConvertStringAttribute(attribute));
2073
2074 return ::llvm::AttributeSet::get(Context_->llvm_module().getContext(), builder);
2075}
2076
2077::llvm::AttributeList
2079{
2080 auto & llvmctx = Context_->llvm_module().getContext();
2081
2082 auto fctset = convert_attributes(f.attributes());
2083
2084 // FIXME: return value attributes are currently not supported
2085 auto retset = ::llvm::AttributeSet();
2086
2087 std::vector<::llvm::AttributeSet> argsets;
2088
2089 // Attributes on function arguments are stored in the cfg
2090 if (f.cfg())
2091 {
2092 for (size_t n = 0; n < f.cfg()->entry()->narguments(); n++)
2093 {
2094 auto argument = f.cfg()->entry()->argument(n);
2095
2096 if (argument->type().Kind() == rvsdg::TypeKind::State)
2097 continue;
2098
2099 argsets.push_back(convert_attributes(argument->attributes()));
2100 }
2101 }
2102
2103 return ::llvm::AttributeList::get(llvmctx, fctset, retset, argsets);
2104}
2105
2106::llvm::AttributeList
2108{
2109 const auto functionAttributes = convert_attributes(attributeList.getFunctionAttributes());
2110 const auto returnAttributes = convert_attributes(attributeList.getReturnAttributes());
2111
2112 std::vector<::llvm::AttributeSet> parameterAttributes;
2113 for (auto & attributes : attributeList.getParameterAttributes())
2114 parameterAttributes.emplace_back(convert_attributes(attributes));
2115
2116 return ::llvm::AttributeList::get(
2117 Context_->llvm_module().getContext(),
2118 std::move(functionAttributes),
2119 std::move(returnAttributes),
2120 std::move(parameterAttributes));
2121}
2122
2123std::vector<ControlFlowGraphNode *>
2125 const ControlFlowGraph & controlFlowGraph,
2126 ::llvm::Function & function)
2127{
2128 auto nodes = breadth_first(controlFlowGraph);
2129
2130 uint64_t basicBlockCounter = 0;
2131 for (const auto & node : nodes)
2132 {
2133 if (node == controlFlowGraph.entry())
2134 continue;
2135 if (node == controlFlowGraph.exit())
2136 continue;
2137
2138 auto name = util::strfmt("bb", basicBlockCounter++);
2139 auto * basicBlock = ::llvm::BasicBlock::Create(function.getContext(), name, &function);
2140 Context_->insert(node, basicBlock);
2141 }
2142
2143 return nodes;
2144}
2145
2146void
2148{
2149 JLM_ASSERT(is_closed(cfg));
2150
2151 auto add_arguments = [&](const ControlFlowGraph & cfg, ::llvm::Function & f)
2152 {
2153 size_t n = 0;
2154 for (auto & llvmarg : f.args())
2155 {
2156 auto jlmarg = cfg.entry()->argument(n++);
2157 Context_->insert(jlmarg, &llvmarg);
2158 }
2159 };
2160
2161 straighten(cfg);
2162
2163 auto nodes = ConvertBasicBlocks(cfg, f);
2164
2165 add_arguments(cfg, f);
2166
2167 // create non-terminator instructions
2168 for (const auto & node : nodes)
2169 {
2170 if (node == cfg.entry() || node == cfg.exit())
2171 continue;
2172
2173 JLM_ASSERT(is<BasicBlock>(node));
2174 auto & tacs = static_cast<const BasicBlock *>(node)->tacs();
2175 for (const auto & tac : tacs)
2176 convert_instruction(*tac, node);
2177 }
2178
2179 // create cfg structure
2180 for (const auto & node : nodes)
2181 {
2182 if (node == cfg.entry() || node == cfg.exit())
2183 continue;
2184
2186 }
2187
2188 // patch phi instructions
2189 for (const auto & node : nodes)
2190 {
2191 if (node == cfg.entry() || node == cfg.exit())
2192 continue;
2193
2194 JLM_ASSERT(is<BasicBlock>(node));
2195 auto & tacs = static_cast<const BasicBlock *>(node)->tacs();
2196 for (const auto & tac : tacs)
2197 {
2198 if (!is<SsaPhiOperation>(tac->operation()))
2199 continue;
2200
2201 if (rvsdg::is<IOStateType>(tac->result(0)->type()))
2202 continue;
2203 if (rvsdg::is<MemoryStateType>(tac->result(0)->type()))
2204 continue;
2205
2206 JLM_ASSERT(node->NumInEdges() == tac->noperands());
2207 auto & op = *static_cast<const SsaPhiOperation *>(&tac->operation());
2208 auto phi = ::llvm::dyn_cast<::llvm::PHINode>(Context_->value(tac->result(0)));
2209 for (size_t n = 0; n < tac->noperands(); n++)
2210 phi->addIncoming(
2211 Context_->value(tac->operand(n)),
2212 Context_->basic_block(op.GetIncomingNode(n)));
2213 }
2214 }
2215}
2216
2217void
2219{
2220 if (!node.cfg())
2221 return;
2222
2223 auto & im = Context_->module();
2224 auto f = ::llvm::cast<::llvm::Function>(Context_->value(im.variable(&node)));
2225
2226 // Type, name, attributes and calling convention have already been set on the LLVM Function.
2227 // The only conversion that remains is the function body.
2228
2229 convert_cfg(*node.cfg(), *f);
2230}
2231
2232void
2234{
2235 if (!node.initialization())
2236 return;
2237
2238 auto & jm = Context_->module();
2239 auto init = node.initialization();
2240 convert_tacs(init->tacs());
2241
2242 auto gv = ::llvm::dyn_cast<::llvm::GlobalVariable>(Context_->value(jm.variable(&node)));
2243 gv->setInitializer(::llvm::dyn_cast<::llvm::Constant>(Context_->value(init->value())));
2244}
2245
2246const ::llvm::GlobalValue::LinkageTypes &
2248{
2249 static std::unordered_map<llvm::Linkage, ::llvm::GlobalValue::LinkageTypes> map(
2250 { { llvm::Linkage::externalLinkage, ::llvm::GlobalValue::ExternalLinkage },
2252 ::llvm::GlobalValue::AvailableExternallyLinkage },
2253 { llvm::Linkage::linkOnceAnyLinkage, ::llvm::GlobalValue::LinkOnceAnyLinkage },
2254 { llvm::Linkage::linkOnceOdrLinkage, ::llvm::GlobalValue::LinkOnceODRLinkage },
2255 { llvm::Linkage::weakAnyLinkage, ::llvm::GlobalValue::WeakAnyLinkage },
2256 { llvm::Linkage::weakOdrLinkage, ::llvm::GlobalValue::WeakODRLinkage },
2257 { llvm::Linkage::appendingLinkage, ::llvm::GlobalValue::AppendingLinkage },
2258 { llvm::Linkage::internalLinkage, ::llvm::GlobalValue::InternalLinkage },
2259 { llvm::Linkage::privateLinkage, ::llvm::GlobalValue::PrivateLinkage },
2260 { llvm::Linkage::externalWeakLinkage, ::llvm::GlobalValue::ExternalWeakLinkage },
2261 { llvm::Linkage::commonLinkage, ::llvm::GlobalValue::CommonLinkage } });
2262
2263 JLM_ASSERT(map.find(linkage) != map.end());
2264 return map[linkage];
2265}
2266
2267void
2269{
2270 auto & typeConverter = Context_->GetTypeConverter();
2271 auto & jm = Context_->module();
2272 auto & lm = Context_->llvm_module();
2273
2274 // forward declare all nodes
2275 for (const auto & node : jm.ipgraph())
2276 {
2277 auto v = jm.variable(&node);
2278
2279 if (auto dataNode = dynamic_cast<const DataNode *>(&node))
2280 {
2281 auto type = typeConverter.ConvertJlmType(*dataNode->GetValueType(), lm.getContext());
2282 auto linkage = convert_linkage(dataNode->linkage());
2283
2284 auto gv = new ::llvm::GlobalVariable(
2285 lm,
2286 type,
2287 dataNode->constant(),
2288 linkage,
2289 nullptr,
2290 dataNode->name());
2291 gv->setSection(dataNode->Section());
2292 gv->setAlignment(::llvm::Align(dataNode->getAlignment()));
2293 Context_->insert(v, gv);
2294 }
2295 else if (auto n = dynamic_cast<const FunctionNode *>(&node))
2296 {
2297 auto type = typeConverter.ConvertFunctionType(n->fcttype(), lm.getContext());
2298 auto linkage = convert_linkage(n->linkage());
2299 auto f = ::llvm::Function::Create(type, linkage, n->name(), &lm);
2300
2301 // Set the calling convention and attributes on the function
2302 const auto callingConvention = convertCallingConventionToLlvm(n->callingConvention());
2303 f->setCallingConv(callingConvention);
2304 auto attributes = convert_attributes(*n);
2305 f->setAttributes(attributes);
2306
2307 Context_->insert(v, f);
2308 }
2309 else
2310 JLM_ASSERT(0);
2311 }
2312
2313 // convert all nodes
2314 for (const auto & node : jm.ipgraph())
2315 {
2316 if (auto n = dynamic_cast<const DataNode *>(&node))
2317 {
2319 }
2320 else if (auto n = dynamic_cast<const FunctionNode *>(&node))
2321 {
2322 convert_function(*n);
2323 }
2324 else
2325 JLM_ASSERT(0);
2326 }
2327}
2328
2329std::unique_ptr<::llvm::Module>
2331 InterProceduralGraphModule & ipGraphModule,
2332 ::llvm::LLVMContext & llvmContext)
2333{
2334 std::unique_ptr<::llvm::Module> llvmModule(new ::llvm::Module("module", llvmContext));
2335 llvmModule->setSourceFileName(ipGraphModule.source_filename().to_str());
2336 llvmModule->setTargetTriple(ipGraphModule.target_triple());
2337 llvmModule->setDataLayout(ipGraphModule.data_layout());
2338
2339 Context_ = Context::Create(ipGraphModule, *llvmModule);
2341
2342 return llvmModule;
2343}
2344
2345std::unique_ptr<::llvm::Module>
2347 InterProceduralGraphModule & ipGraphModule,
2348 ::llvm::LLVMContext & ctx)
2349{
2350 IpGraphToLlvmConverter converter;
2351 return converter.ConvertModule(ipGraphModule, ctx);
2352}
2353
2354}
std::vector< rvsdg::Node * > nodes
util::HashSet< rvsdg::Output * > arguments
const std::vector< AttributeSet > & getParameterAttributes() const noexcept
const AttributeSet & getReturnAttributes() const noexcept
const AttributeSet & getFunctionAttributes() const noexcept
EnumAttributeRange EnumAttributes() const
Definition attribute.cpp:50
StringAttributeRange StringAttributes() const
Definition attribute.cpp:68
TypeAttributeRange TypeAttributes() const
Definition attribute.cpp:62
IntAttributeRange IntAttributes() const
Definition attribute.cpp:56
@ None
No attributes have been set.
@ EndAttrKinds
Sentinel value useful for loops.
ThreeAddressCode * last() const noexcept
Call operation class.
Definition call.hpp:251
CallingConvention getCallingConvention() const noexcept
Definition call.hpp:278
const AttributeList & getAttributes() const noexcept
Definition call.hpp:284
const std::shared_ptr< const rvsdg::FunctionType > & GetFunctionType() const noexcept
Definition call.hpp:272
std::shared_ptr< const ArrayType > type() const noexcept
const ::llvm::APFloat & constant() const noexcept
ConstantPointerNullOperation class.
const StructType & type() const noexcept
ControlFlowGraphNode * sink() const noexcept
Definition cfg-node.hpp:57
ControlFlowGraph & cfg() const noexcept
Definition cfg-node.hpp:106
ControlFlowGraphEdge * OutEdge(size_t n) const
Definition cfg-node.hpp:115
size_t NumOutEdges() const noexcept
Definition cfg-node.cpp:46
ExitNode * exit() const noexcept
Definition cfg.hpp:212
EntryNode * entry() const noexcept
Definition cfg.hpp:206
const DataNodeInit * initialization() const noexcept
Definition ipgraph.hpp:413
const llvm::Argument * argument(size_t index) const
Definition cfg.hpp:93
const Attribute::kind & kind() const noexcept
const Variable * result(size_t index) const
Definition cfg.hpp:136
FreezeOperation class.
llvm::ControlFlowGraph * cfg() const noexcept
Definition ipgraph.hpp:190
const AttributeSet & attributes() const noexcept
Definition ipgraph.hpp:229
Get address of compiled function object.
const std::vector< unsigned > & getIndices() const noexcept
Integer attribute.
uint64_t value() const noexcept
const jlm::util::FilePath & source_filename() const noexcept
const std::string & target_triple() const noexcept
const std::string & data_layout() const noexcept
void insert(const llvm::ControlFlowGraphNode *node, ::llvm::BasicBlock *bb)
std::unordered_map< const ControlFlowGraphNode *, ::llvm::BasicBlock * >::const_iterator const_iterator
static std::unique_ptr< Context > Create(InterProceduralGraphModule &ipGraphModule, ::llvm::Module &llvmModule)
::llvm::BasicBlock * basic_block(const llvm::ControlFlowGraphNode *node) const noexcept
void insert(const llvm::Variable *variable, ::llvm::Value *value)
Context & operator=(const Context &)=delete
Context(InterProceduralGraphModule &ipGraphModule, ::llvm::Module &llvmModule)
std::unordered_map< const llvm::ControlFlowGraphNode *, ::llvm::BasicBlock * > nodes_
std::unordered_map< const llvm::Variable *, ::llvm::Value * > variables_
InterProceduralGraphModule & module() const noexcept
Context & operator=(Context &&)=delete
::llvm::Module & llvm_module() const noexcept
::llvm::Value * value(const llvm::Variable *variable) const noexcept
::llvm::AttributeList convertAttributeList(const AttributeList &attributeList)
::llvm::Value * convert(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * convertInsertValueOperation(const InsertValueOperation &operation, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder) const
::llvm::Value * convert_select(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_branch(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &)
void convert_instruction(const llvm::ThreeAddressCode &tac, const llvm::ControlFlowGraphNode *node)
::llvm::Value * convert_constantdatavector(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_store(const rvsdg::SimpleOperation &operation, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * convertMemsetNonVolatileOperation(const rvsdg::SimpleOperation &, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &)
::llvm::Value * convert_fpbin(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
void convert_tacs(const tacsvector_t &tacs)
void create_switch(const ControlFlowGraphNode *node)
::llvm::Attribute::AttrKind ConvertAttributeKind(const Attribute::kind &kind)
const ::llvm::GlobalValue::LinkageTypes & convert_linkage(const llvm::Linkage &linkage)
::llvm::Value * CreateICmpInstruction(const ::llvm::CmpInst::Predicate predicate, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Attribute ConvertStringAttribute(const llvm::StringAttribute &attribute)
::llvm::Value * convert_match(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_fpneg(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_valist(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &)
void CreateStoreInstruction(const Variable *address, const Variable *value, bool isVolatile, size_t alignment, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_insertelement(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * CreateBinOpInstruction(const ::llvm::Instruction::BinaryOps opcode, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
void create_terminator_instruction(const llvm::ControlFlowGraphNode *node)
::llvm::Value * convert_ptrcmp(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_alloca(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_constantvector(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &)
::llvm::Value * convert_vectorunary(const rvsdg::SimpleOperation &op, const rvsdg::SimpleOperation &originalOp, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
std::vector< ControlFlowGraphNode * > ConvertBasicBlocks(const ControlFlowGraph &controlFlowGraph, ::llvm::Function &function)
::llvm::Value * CreateLoadInstruction(const rvsdg::Type &loadedType, const Variable *address, bool isVolatile, size_t alignment, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_ctl2bits(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &)
::llvm::Value * convert_ctlconstant(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_fpcmp(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * ConverterIntegerConstant(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &builder)
void convert_function(const FunctionNode &node)
::llvm::Value * convert_extractelement(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_assignment(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &)
::llvm::Value * convert_operation(const rvsdg::SimpleOperation &op, const rvsdg::SimpleOperation &originalOp, const std::vector< const Variable * > &arguments, ::llvm::IRBuilder<> &builder)
std::unique_ptr<::llvm::Module > ConvertModule(InterProceduralGraphModule &ipGraphModule, ::llvm::LLVMContext &llvmContext)
void create_return(const ControlFlowGraphNode *node)
::llvm::Value * convert_phi(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_vectorbinary(const rvsdg::SimpleOperation &op, const rvsdg::SimpleOperation &originalOp, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Attribute ConvertTypeAttribute(const llvm::TypeAttribute &attribute)
void create_unconditional_branch(const ControlFlowGraphNode *node)
::llvm::Value * convert_getelementptr(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_cast(const rvsdg::SimpleOperation &op, const rvsdg::SimpleOperation &originalOp, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_undef(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &)
::llvm::AttributeList convert_attributes(const FunctionNode &f)
static std::unique_ptr<::llvm::Module > CreateAndConvertModule(InterProceduralGraphModule &ipGraphModule, ::llvm::LLVMContext &ctx)
void create_conditional_branch(const ControlFlowGraphNode *node)
::llvm::Attribute ConvertEnumAttribute(const llvm::EnumAttribute &attribute)
void convert_cfg(ControlFlowGraph &cfg, ::llvm::Function &f)
std::vector< T > get_fpdata(const std::vector< const Variable * > &args)
::llvm::Attribute ConvertIntAttribute(const llvm::IntAttribute &attribute)
std::vector< T > get_bitdata(const std::vector< const Variable * > &args)
std::shared_ptr< const rvsdg::Type > GetLoadedType() const noexcept
Definition Load.hpp:63
size_t GetAlignment() const noexcept
Definition Load.hpp:57
rvsdg::FunctionType getFunctionType() const
Interpret pointer as callable function.
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
PoisonValueOperation class.
const jlm::rvsdg::Type & GetType() const noexcept
const ::llvm::ArrayRef< int > Mask() const
size_t GetAlignment() const noexcept
Definition Store.hpp:57
const std::string & kind() const noexcept
const std::string & value() const noexcept
llvm::ThreeAddressCode * tac() const noexcept
Definition tac.hpp:36
const rvsdg::SimpleOperation & operation() const noexcept
Definition tac.hpp:84
const Variable * operand(size_t index) const noexcept
Definition tac.hpp:96
const ThreeAddressCodeVariable * result(size_t index) const noexcept
Definition tac.hpp:109
size_t noperands() const noexcept
Definition tac.hpp:90
const jlm::rvsdg::Type & type() const noexcept
const ControlValueRepresentation & value() const noexcept
Definition control.hpp:116
size_t nalternatives() const noexcept
Definition control.hpp:89
Function type class.
virtual std::string debug_string() const =0
const std::shared_ptr< const rvsdg::Type > & argument(size_t index) const noexcept
Definition operation.cpp:23
const std::shared_ptr< const rvsdg::Type > & result(size_t index) const noexcept
Definition operation.cpp:36
size_t narguments() const noexcept
Definition operation.cpp:17
const std::string & to_str() const noexcept
Definition file.hpp:275
#define JLM_ASSERT(x)
Definition common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43
Global memory state passed between functions.
std::vector< std::unique_ptr< llvm::ThreeAddressCode > > tacsvector_t
Definition tac.hpp:202
std::vector< ControlFlowGraphNode * > breadth_first(const ControlFlowGraph &cfg)
Definition cfg.cpp:322
static bool is_identity_mapping(const rvsdg::MatchOperation &op)
::llvm::CallingConv::ID convertCallingConventionToLlvm(jlm::llvm::CallingConvention cc)
::llvm::APInt convert_bitvalue_repr(const rvsdg::BitValueRepresentation &vr)
static const llvm::ThreeAddressCode * get_match(const llvm::ThreeAddressCode *branch)
void straighten(ControlFlowGraph &cfg)
static bool has_return_value(const ControlFlowGraph &cfg)
::llvm::CmpInst::Predicate convertICmpPredicateToLlvm(ICmpPredicate predicate)
bool is_closed(const ControlFlowGraph &cfg)
@ State
Designate a state type.
@ Value
Designate a value type.
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
static std::string strfmt(Args... args)
Definition strfmt.hpp:35