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<MemoryHoistBarrierOperation>(op))
1214 {
1215 return Context_->value(arguments[0]);
1216 }
1217 if (is<IntegerConstantOperation>(op))
1218 {
1219 return ConverterIntegerConstant(op, arguments, builder);
1220 }
1221 if (is<rvsdg::ControlConstantOperation>(op))
1222 {
1223 return convert_ctlconstant(op, arguments, builder);
1224 }
1225 if (is<ConstantFP>(op))
1226 {
1227 return convert<ConstantFP>(op, arguments, builder);
1228 }
1229 if (is<UndefValueOperation>(op))
1230 {
1231 return convert_undef(op, arguments, builder);
1232 }
1233 if (is<PoisonValueOperation>(op))
1234 {
1235 return convert<PoisonValueOperation>(op, arguments, builder);
1236 }
1237 if (is<FreezeOperation>(op))
1238 {
1239 return convert<FreezeOperation>(op, arguments, builder);
1240 }
1241 if (is<rvsdg::MatchOperation>(op))
1242 {
1243 return convert_match(op, arguments, builder);
1244 }
1245 if (is<AssignmentOperation>(op))
1246 {
1247 return convert_assignment(op, arguments, builder);
1248 }
1249 if (is<BranchOperation>(op))
1250 {
1251 return convert_branch(op, arguments, builder);
1252 }
1253 if (is<SsaPhiOperation>(op))
1254 {
1255 return convert_phi(op, arguments, builder);
1256 }
1257 if (is<LoadNonVolatileOperation>(op))
1258 {
1259 return convert<LoadNonVolatileOperation>(op, arguments, builder);
1260 }
1261 if (is<LoadVolatileOperation>(op))
1262 {
1263 return convert<LoadVolatileOperation>(op, arguments, builder);
1264 }
1265 if (is<StoreNonVolatileOperation>(op))
1266 {
1267 return convert_store(op, arguments, builder);
1268 }
1269 if (is<StoreVolatileOperation>(op))
1270 {
1271 return convert<StoreVolatileOperation>(op, arguments, builder);
1272 }
1273 if (is<AllocaOperation>(op))
1274 {
1275 return convert_alloca(op, arguments, builder);
1276 }
1277 if (is<GetElementPtrOperation>(op))
1278 {
1279 return convert_getelementptr(op, arguments, builder);
1280 }
1281 if (is<ConstantDataArrayOperation>(op))
1282 {
1283 return convert<ConstantDataArrayOperation>(op, arguments, builder);
1284 }
1285 if (is<PtrCmpOperation>(op))
1286 {
1287 return convert_ptrcmp(op, arguments, builder);
1288 }
1289 if (is<FCmpOperation>(op))
1290 {
1291 return convert_fpcmp(op, arguments, builder);
1292 }
1293 if (is<FBinaryOperation>(op))
1294 {
1295 return convert_fpbin(op, arguments, builder);
1296 }
1297 if (is<VariadicArgumentListOperation>(op))
1298 {
1299 return convert_valist(op, arguments, builder);
1300 }
1301 if (is<ConstantStructOperation>(op))
1302 {
1303 return convert<ConstantStructOperation>(op, arguments, builder);
1304 }
1305 if (is<ConstantPointerNullOperation>(op))
1306 {
1307 return convert<ConstantPointerNullOperation>(op, arguments, builder);
1308 }
1309 if (is<SelectOperation>(op))
1310 {
1311 return convert_select(op, arguments, builder);
1312 }
1313 if (is<ConstantArrayOperation>(op))
1314 {
1315 return convert<ConstantArrayOperation>(op, arguments, builder);
1316 }
1317 if (is<ConstantAggregateZeroOperation>(op))
1318 {
1319 return convert<ConstantAggregateZeroOperation>(op, arguments, builder);
1320 }
1321 if (is<ControlToIntOperation>(op))
1322 {
1323 return convert_ctl2bits(op, arguments, builder);
1324 }
1325 if (is<ConstantVectorOperation>(op))
1326 {
1327 return convert_constantvector(op, arguments, builder);
1328 }
1329 if (is<ConstantDataVectorOperation>(op))
1330 {
1331 return convert_constantdatavector(op, arguments, builder);
1332 }
1333 if (is<ExtractElementOperation>(op))
1334 {
1335 return convert_extractelement(op, arguments, builder);
1336 }
1337 if (is<ShuffleVectorOperation>(op))
1338 {
1339 return convert<ShuffleVectorOperation>(op, arguments, builder);
1340 }
1341 if (is<InsertElementOperation>(op))
1342 {
1343 return convert_insertelement(op, arguments, builder);
1344 }
1345 if (is<VectorUnaryOperation>(op))
1346 {
1347 return convert_vectorunary(op, originalOp, arguments, builder);
1348 }
1349 if (is<VectorBinaryOperation>(op))
1350 {
1351 return convert_vectorbinary(op, originalOp, arguments, builder);
1352 }
1353 if (is<VectorSelectOperation>(op))
1354 {
1355 return convert<VectorSelectOperation>(op, arguments, builder);
1356 }
1357 if (is<ExtractValueOperation>(op))
1358 {
1359 return convert<ExtractValueOperation>(op, arguments, builder);
1360 }
1361 if (const auto insertValueOperation = dynamic_cast<const InsertValueOperation *>(&op))
1362 {
1363 return convertInsertValueOperation(*insertValueOperation, arguments, builder);
1364 }
1365 if (is<CallOperation>(op))
1366 {
1367 return convert<CallOperation>(op, arguments, builder);
1368 }
1369 if (is<MallocOperation>(op))
1370 {
1371 return convert<MallocOperation>(op, arguments, builder);
1372 }
1373 if (is<FreeOperation>(op))
1374 {
1375 return convert<FreeOperation>(op, arguments, builder);
1376 }
1377 if (is<MemCpyNonVolatileOperation>(op))
1378 {
1379 return convert<MemCpyNonVolatileOperation>(op, arguments, builder);
1380 }
1381 if (is<MemCpyVolatileOperation>(op))
1382 {
1383 return convert<MemCpyVolatileOperation>(op, arguments, builder);
1384 }
1385 if (is<MemSetNonVolatileOperation>(op))
1386 {
1387 return convertMemsetNonVolatileOperation(op, arguments, builder);
1388 }
1389 if (is<MemMoveNonVolatileOperation>(op))
1390 {
1391 const auto destOperand = Context_->value(arguments[0]);
1392 const auto srcOperand = Context_->value(arguments[1]);
1393 const auto lengthOperand = Context_->value(arguments[2]);
1394
1395 return builder.CreateMemMove(
1396 destOperand,
1397 ::llvm::MaybeAlign(),
1398 srcOperand,
1399 ::llvm::MaybeAlign(),
1400 lengthOperand);
1401 }
1402 if (is<FNegOperation>(op))
1403 {
1404 return convert_fpneg(op, arguments, builder);
1405 }
1406 if (is<BitCastOperation>(op))
1407 {
1408 return convert_cast<::llvm::Instruction::BitCast>(op, originalOp, arguments, builder);
1409 }
1410 if (is<FPExtOperation>(op))
1411 {
1412 return convert_cast<::llvm::Instruction::FPExt>(op, originalOp, arguments, builder);
1413 }
1414 if (is<FPToSIOperation>(op))
1415 {
1416 return convert_cast<::llvm::Instruction::FPToSI>(op, originalOp, arguments, builder);
1417 }
1418 if (is<FPToUIOperation>(op))
1419 {
1420 return convert_cast<::llvm::Instruction::FPToUI>(op, originalOp, arguments, builder);
1421 }
1422 if (is<FPTruncOperation>(op))
1423 {
1424 return convert_cast<::llvm::Instruction::FPTrunc>(op, originalOp, arguments, builder);
1425 }
1426 if (is<IntToPtrOperation>(op))
1427 {
1428 return convert_cast<::llvm::Instruction::IntToPtr>(op, originalOp, arguments, builder);
1429 }
1430 if (is<PtrToIntOperation>(op))
1431 {
1432 return convert_cast<::llvm::Instruction::PtrToInt>(op, originalOp, arguments, builder);
1433 }
1434 if (is<SExtOperation>(op))
1435 {
1436 return convert_cast<::llvm::Instruction::SExt>(op, originalOp, arguments, builder);
1437 }
1438 if (is<SIToFPOperation>(op))
1439 {
1440 return convert_cast<::llvm::Instruction::SIToFP>(op, originalOp, arguments, builder);
1441 }
1442 if (is<TruncOperation>(op))
1443 {
1444 return convert_cast<::llvm::Instruction::Trunc>(op, originalOp, arguments, builder);
1445 }
1446 if (is<UIToFPOperation>(op))
1447 {
1448 return convert_cast<::llvm::Instruction::UIToFP>(op, originalOp, arguments, builder);
1449 }
1450 if (is<ZExtOperation>(op))
1451 {
1452 return convert_cast<::llvm::Instruction::ZExt>(op, originalOp, arguments, builder);
1453 }
1454 if (is<MemoryStateMergeOperation>(op))
1455 {
1456 return convert<MemoryStateMergeOperation>(op, arguments, builder);
1457 }
1458 if (is<MemoryStateJoinOperation>(op))
1459 {
1460 // This operation has no equivalent LLVM instruction.
1461 // Nothing needs to be done.
1462 return nullptr;
1463 }
1464 if (is<MemoryStateSplitOperation>(op))
1465 {
1466 return convert<MemoryStateSplitOperation>(op, arguments, builder);
1467 }
1468 if (is<LambdaEntryMemoryStateSplitOperation>(op))
1469 {
1470 return convert<LambdaEntryMemoryStateSplitOperation>(op, arguments, builder);
1471 }
1472 if (is<LambdaExitMemoryStateMergeOperation>(op))
1473 {
1474 return convert<LambdaExitMemoryStateMergeOperation>(op, arguments, builder);
1475 }
1476 if (is<CallEntryMemoryStateMergeOperation>(op))
1477 {
1478 return convert<CallEntryMemoryStateMergeOperation>(op, arguments, builder);
1479 }
1480 if (is<CallExitMemoryStateSplitOperation>(op))
1481 {
1482 return convert<CallExitMemoryStateSplitOperation>(op, arguments, builder);
1483 }
1484 if (is<PointerToFunctionOperation>(op))
1485 {
1486 return convert<PointerToFunctionOperation>(op, arguments, builder);
1487 }
1488 if (is<FunctionToPointerOperation>(op))
1489 {
1490 return convert<FunctionToPointerOperation>(op, arguments, builder);
1491 }
1492 if (is<FMulAddIntrinsicOperation>(op))
1493 {
1494 auto multiplier = Context_->value(arguments[0]);
1495 auto multiplicand = Context_->value(arguments[1]);
1496 auto summand = Context_->value(arguments[2]);
1497
1498 auto type =
1499 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1500 return builder.CreateIntrinsic(
1501 ::llvm::Intrinsic::fmuladd,
1502 { type },
1503 { multiplier, multiplicand, summand });
1504 }
1505 if (is<SMaxOperation>(op))
1506 {
1507 auto operand1 = Context_->value(arguments[0]);
1508 auto operand2 = Context_->value(arguments[1]);
1509
1510 auto type =
1511 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1512 return builder.CreateIntrinsic(::llvm::Intrinsic::smax, { type }, { operand1, operand2 });
1513 }
1514 if (is<UMaxOperation>(op))
1515 {
1516 auto operand1 = Context_->value(arguments[0]);
1517 auto operand2 = Context_->value(arguments[1]);
1518
1519 auto type =
1520 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1521 return builder.CreateIntrinsic(::llvm::Intrinsic::umax, { type }, { operand1, operand2 });
1522 }
1523 if (is<SMinOperation>(op))
1524 {
1525 auto operand1 = Context_->value(arguments[0]);
1526 auto operand2 = Context_->value(arguments[1]);
1527
1528 auto type =
1529 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1530 return builder.CreateIntrinsic(::llvm::Intrinsic::smin, { type }, { operand1, operand2 });
1531 }
1532 if (is<UMinOperation>(op))
1533 {
1534 auto operand1 = Context_->value(arguments[0]);
1535 auto operand2 = Context_->value(arguments[1]);
1536
1537 auto type =
1538 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1539 return builder.CreateIntrinsic(::llvm::Intrinsic::umin, { type }, { operand1, operand2 });
1540 }
1541 if (is<FAbsOperation>(op))
1542 {
1543 auto operand = Context_->value(arguments[0]);
1544
1545 auto type =
1546 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1547 return builder.CreateIntrinsic(::llvm::Intrinsic::fabs, { type }, { operand });
1548 }
1549 if (is<FShlOperation>(op))
1550 {
1551 auto operand1 = Context_->value(arguments[0]);
1552 auto operand2 = Context_->value(arguments[1]);
1553 auto operand3 = Context_->value(arguments[2]);
1554
1555 auto type =
1556 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1557 return builder.CreateIntrinsic(
1558 ::llvm::Intrinsic::fshl,
1559 { type },
1560 { operand1, operand2, operand3 });
1561 }
1562 if (is<FloorOperation>(op))
1563 {
1564 auto operand = Context_->value(arguments[0]);
1565
1566 auto type =
1567 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1568 return builder.CreateIntrinsic(::llvm::Intrinsic::floor, { type }, { operand });
1569 }
1570 if (is<AbsOperation>(op))
1571 {
1572 auto operand1 = Context_->value(arguments[0]);
1573 auto operand2 = Context_->value(arguments[1]);
1574
1575 auto type =
1576 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1577 return builder.CreateIntrinsic(::llvm::Intrinsic::abs, { type }, { operand1, operand2 });
1578 }
1579 if (is<CeilOperation>(op))
1580 {
1581 auto operand = Context_->value(arguments[0]);
1582
1583 auto type =
1584 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1585 return builder.CreateIntrinsic(::llvm::Intrinsic::ceil, { type }, { operand });
1586 }
1587 if (is<RIntOperation>(op))
1588 {
1589 auto operand = Context_->value(arguments[0]);
1590
1591 auto type =
1592 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1593 return builder.CreateIntrinsic(::llvm::Intrinsic::rint, { type }, { operand });
1594 }
1595 if (is<TruncIntrinsicOperation>(op))
1596 {
1597 auto operand = Context_->value(arguments[0]);
1598
1599 auto type =
1600 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1601 return builder.CreateIntrinsic(::llvm::Intrinsic::trunc, { type }, { operand });
1602 }
1603 if (is<BSwapOperation>(op))
1604 {
1605 auto operand = Context_->value(arguments[0]);
1606
1607 auto type =
1608 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1609 return builder.CreateIntrinsic(::llvm::Intrinsic::bswap, { type }, { operand });
1610 }
1611 if (is<CtlzOperation>(op))
1612 {
1613 auto operand = Context_->value(arguments[0]);
1614 auto isZeroPoison = Context_->value(arguments[1]);
1615
1616 auto type =
1617 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1618 return builder.CreateIntrinsic(::llvm::Intrinsic::ctlz, { type }, { operand, isZeroPoison });
1619 }
1620 if (is<CttzOperation>(op))
1621 {
1622 auto operand = Context_->value(arguments[0]);
1623 auto isZeroPoison = Context_->value(arguments[1]);
1624
1625 auto type =
1626 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1627 return builder.CreateIntrinsic(::llvm::Intrinsic::cttz, { type }, { operand, isZeroPoison });
1628 }
1629 if (is<CtpopOperation>(op))
1630 {
1631 auto operand = Context_->value(arguments[0]);
1632
1633 auto type =
1634 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1635 return builder.CreateIntrinsic(::llvm::Intrinsic::ctpop, { type }, { operand });
1636 }
1637 if (is<IsConstantOperation>(op))
1638 {
1639 auto operand = Context_->value(arguments[0]);
1640
1641 auto type =
1642 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1643 return builder.CreateIntrinsic(::llvm::Intrinsic::is_constant, { type }, { operand });
1644 }
1645 if (is<IsFPClassOperation>(op))
1646 {
1647 auto operand1 = Context_->value(arguments[0]);
1648 auto operand2 = Context_->value(arguments[1]);
1649
1650 auto type =
1651 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1652 return builder.CreateIntrinsic(::llvm::Intrinsic::is_fpclass, { type }, { operand1, operand2 });
1653 }
1654 if (is<SAddWithOverflowOperation>(op))
1655 {
1656 auto operand1 = Context_->value(arguments[0]);
1657 auto operand2 = Context_->value(arguments[1]);
1658
1659 auto type =
1660 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1661 return builder.CreateIntrinsic(
1662 ::llvm::Intrinsic::sadd_with_overflow,
1663 { type },
1664 { operand1, operand2 });
1665 }
1666 if (is<UAddWithOverflowOperation>(op))
1667 {
1668 auto operand1 = Context_->value(arguments[0]);
1669 auto operand2 = Context_->value(arguments[1]);
1670
1671 auto type =
1672 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1673 return builder.CreateIntrinsic(
1674 ::llvm::Intrinsic::uadd_with_overflow,
1675 { type },
1676 { operand1, operand2 });
1677 }
1678 if (is<SSubWithOverflowOperation>(op))
1679 {
1680 auto operand1 = Context_->value(arguments[0]);
1681 auto operand2 = Context_->value(arguments[1]);
1682
1683 auto type =
1684 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1685 return builder.CreateIntrinsic(
1686 ::llvm::Intrinsic::ssub_with_overflow,
1687 { type },
1688 { operand1, operand2 });
1689 }
1690 if (is<SMulWithOverflowOperation>(op))
1691 {
1692 auto operand1 = Context_->value(arguments[0]);
1693 auto operand2 = Context_->value(arguments[1]);
1694
1695 auto type =
1696 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1697 return builder.CreateIntrinsic(
1698 ::llvm::Intrinsic::smul_with_overflow,
1699 { type },
1700 { operand1, operand2 });
1701 }
1702 if (is<RoundOperation>(op))
1703 {
1704 auto operand = Context_->value(arguments[0]);
1705
1706 auto type =
1707 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1708 return builder.CreateIntrinsic(::llvm::Intrinsic::round, { type }, { operand });
1709 }
1710 if (is<UMulWithOverflowOperation>(op))
1711 {
1712 auto operand1 = Context_->value(arguments[0]);
1713 auto operand2 = Context_->value(arguments[1]);
1714
1715 auto type =
1716 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1717 return builder.CreateIntrinsic(
1718 ::llvm::Intrinsic::umul_with_overflow,
1719 { type },
1720 { operand1, operand2 });
1721 }
1722 if (is<CopysignOperation>(op))
1723 {
1724 auto operand1 = Context_->value(arguments[0]);
1725 auto operand2 = Context_->value(arguments[1]);
1726
1727 auto type =
1728 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1729 return builder.CreateIntrinsic(::llvm::Intrinsic::copysign, { type }, { operand1, operand2 });
1730 }
1731 if (is<PtrMaskOperation>(op))
1732 {
1733 auto ptrOperand = Context_->value(arguments[0]);
1734 auto maskOperand = Context_->value(arguments[1]);
1735
1736 return builder.CreateIntrinsic(
1737 ::llvm::Intrinsic::ptrmask,
1738 { ptrOperand->getType(), maskOperand->getType() },
1739 { ptrOperand, maskOperand });
1740 }
1741
1742 JLM_UNREACHABLE(util::strfmt("Unhandled operation type: ", op.debug_string()).c_str());
1743}
1744
1745void
1747 const llvm::ThreeAddressCode & tac,
1748 const llvm::ControlFlowGraphNode * node)
1749{
1750 std::vector<const Variable *> operands;
1751 for (size_t n = 0; n < tac.noperands(); n++)
1752 operands.push_back(tac.operand(n));
1753
1754 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1755 const auto & op = tac.operation();
1756 auto r = convert_operation(op, op, operands, builder);
1757 if (r != nullptr)
1758 Context_->insert(tac.result(0), r);
1759}
1760
1761void
1763{
1764 ::llvm::IRBuilder<> builder(Context_->llvm_module().getContext());
1765 for (const auto & tac : tacs)
1766 {
1767 std::vector<const Variable *> operands;
1768 for (size_t n = 0; n < tac->noperands(); n++)
1769 operands.push_back(tac->operand(n));
1770
1771 JLM_ASSERT(tac->nresults() == 1);
1772 const auto & op = tac->operation();
1773 auto r = convert_operation(op, op, operands, builder);
1774 Context_->insert(tac->result(0), r);
1775 }
1776}
1777
1778static const llvm::ThreeAddressCode *
1780{
1781 JLM_ASSERT(is<ThreeAddressCodeVariable>(branch->operand(0)));
1782 auto tv = static_cast<const ThreeAddressCodeVariable *>(branch->operand(0));
1783 return tv->tac();
1784}
1785
1786static bool
1788{
1789 for (size_t n = 0; n < cfg.exit()->nresults(); n++)
1790 {
1791 auto result = cfg.exit()->result(n);
1792 if (result->Type()->Kind() == rvsdg::TypeKind::Value)
1793 return true;
1794 }
1795
1796 return false;
1797}
1798
1799void
1801{
1802 JLM_ASSERT(node->NumOutEdges() == 1);
1803 JLM_ASSERT(node->OutEdge(0)->sink() == node->cfg().exit());
1804 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1805 auto & cfg = node->cfg();
1806
1807 /* return without result */
1808 if (!has_return_value(cfg))
1809 {
1810 builder.CreateRetVoid();
1811 return;
1812 }
1813
1814 auto result = cfg.exit()->result(0);
1815 JLM_ASSERT(result->Type()->Kind() == rvsdg::TypeKind::Value);
1816 builder.CreateRet(Context_->value(result));
1817}
1818
1819void
1821{
1822 JLM_ASSERT(node->NumOutEdges() == 1);
1823 JLM_ASSERT(node->OutEdge(0)->sink() != node->cfg().exit());
1824 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1825 auto target = node->OutEdge(0)->sink();
1826
1827 builder.CreateBr(Context_->basic_block(target));
1828}
1829
1830void
1832{
1833 JLM_ASSERT(node->NumOutEdges() == 2);
1834 JLM_ASSERT(node->OutEdge(0)->sink() != node->cfg().exit());
1835 JLM_ASSERT(node->OutEdge(1)->sink() != node->cfg().exit());
1836 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1837
1838 auto branch = static_cast<const BasicBlock *>(node)->tacs().last();
1839 JLM_ASSERT(branch && is<BranchOperation>(branch));
1840 JLM_ASSERT(Context_->value(branch->operand(0))->getType()->isIntegerTy(1));
1841
1842 auto condition = Context_->value(branch->operand(0));
1843 auto bbfalse = Context_->basic_block(node->OutEdge(0)->sink());
1844 auto bbtrue = Context_->basic_block(node->OutEdge(1)->sink());
1845 builder.CreateCondBr(condition, bbtrue, bbfalse);
1846}
1847
1848void
1850{
1851 JLM_ASSERT(node->NumOutEdges() >= 2);
1852 ::llvm::LLVMContext & llvmContext = Context_->llvm_module().getContext();
1853 auto & typeConverter = Context_->GetTypeConverter();
1854 auto bb = static_cast<const BasicBlock *>(node);
1855 ::llvm::IRBuilder<> builder(Context_->basic_block(node));
1856
1857 auto branch = bb->tacs().last();
1858 JLM_ASSERT(branch && is<BranchOperation>(branch));
1859 auto condition = Context_->value(branch->operand(0));
1860 auto match = get_match(branch);
1861
1862 if (is<rvsdg::MatchOperation>(match))
1863 {
1864 JLM_ASSERT(match->result(0) == branch->operand(0));
1865 auto mop = static_cast<const rvsdg::MatchOperation *>(&match->operation());
1866
1867 auto defbb = Context_->basic_block(node->OutEdge(mop->default_alternative())->sink());
1868 auto sw = builder.CreateSwitch(condition, defbb);
1869 for (const auto & alt : *mop)
1870 {
1871 auto & type = *std::static_pointer_cast<const rvsdg::BitType>(mop->argument(0));
1872 auto value =
1873 ::llvm::ConstantInt::get(typeConverter.ConvertBitType(type, llvmContext), alt.first);
1874 sw->addCase(value, Context_->basic_block(node->OutEdge(alt.second)->sink()));
1875 }
1876 }
1877 else
1878 {
1879 auto defbb = Context_->basic_block(node->OutEdge(node->NumOutEdges() - 1)->sink());
1880 auto sw = builder.CreateSwitch(condition, defbb);
1881 for (size_t n = 0; n < node->NumOutEdges() - 1; n++)
1882 {
1883 auto value = ::llvm::ConstantInt::get(::llvm::Type::getInt32Ty(builder.getContext()), n);
1884 sw->addCase(value, Context_->basic_block(node->OutEdge(n)->sink()));
1885 }
1886 }
1887}
1888
1889void
1891{
1892 JLM_ASSERT(is<BasicBlock>(node));
1893 auto & tacs = static_cast<const BasicBlock *>(node)->tacs();
1894 auto & cfg = node->cfg();
1895
1896 // unconditional branch or return statement
1897 if (node->NumOutEdges() == 1)
1898 {
1899 auto target = node->OutEdge(0)->sink();
1900 if (target == cfg.exit())
1901 return create_return(node);
1902
1903 return create_unconditional_branch(node);
1904 }
1905
1906 auto branch = tacs.last();
1907 JLM_ASSERT(branch && is<BranchOperation>(branch));
1908
1909 // conditional branch
1910 if (Context_->value(branch->operand(0))->getType()->isIntegerTy(1))
1911 return create_conditional_branch(node);
1912
1913 // switch
1914 create_switch(node);
1915}
1916
1917::llvm::Attribute::AttrKind
1919{
1920 typedef ::llvm::Attribute::AttrKind ak;
1921
1922 static std::unordered_map<Attribute::kind, ::llvm::Attribute::AttrKind> map(
1923 { { Attribute::kind::None, ak::None },
1924
1925 { Attribute::kind::FirstEnumAttr, ak::FirstEnumAttr },
1926 { Attribute::kind::AllocAlign, ak::AllocAlign },
1927 { Attribute::kind::AllocatedPointer, ak::AllocatedPointer },
1928 { Attribute::kind::AlwaysInline, ak::AlwaysInline },
1929 { Attribute::kind::Builtin, ak::Builtin },
1930 { Attribute::kind::Cold, ak::Cold },
1931 { Attribute::kind::Convergent, ak::Convergent },
1932 { Attribute::kind::CoroDestroyOnlyWhenComplete, ak::CoroDestroyOnlyWhenComplete },
1933 { Attribute::kind::DeadOnUnwind, ak::DeadOnUnwind },
1934 { Attribute::kind::DisableSanitizerInstrumentation, ak::DisableSanitizerInstrumentation },
1935 { Attribute::kind::FnRetThunkExtern, ak::FnRetThunkExtern },
1936 { Attribute::kind::Hot, ak::Hot },
1937 { Attribute::kind::ImmArg, ak::ImmArg },
1938 { Attribute::kind::InReg, ak::InReg },
1939 { Attribute::kind::InlineHint, ak::InlineHint },
1940 { Attribute::kind::JumpTable, ak::JumpTable },
1941 { Attribute::kind::Memory, ak::Memory },
1942 { Attribute::kind::MinSize, ak::MinSize },
1943 { Attribute::kind::MustProgress, ak::MustProgress },
1944 { Attribute::kind::Naked, ak::Naked },
1945 { Attribute::kind::Nest, ak::Nest },
1946 { Attribute::kind::NoAlias, ak::NoAlias },
1947 { Attribute::kind::NoBuiltin, ak::NoBuiltin },
1948 { Attribute::kind::NoCallback, ak::NoCallback },
1949 { Attribute::kind::NoCapture, ak::NoCapture },
1950 { Attribute::kind::NoCfCheck, ak::NoCfCheck },
1951 { Attribute::kind::NoDuplicate, ak::NoDuplicate },
1952 { Attribute::kind::NoFree, ak::NoFree },
1953 { Attribute::kind::NoImplicitFloat, ak::NoImplicitFloat },
1954 { Attribute::kind::NoInline, ak::NoInline },
1955 { Attribute::kind::NoMerge, ak::NoMerge },
1956 { Attribute::kind::NoProfile, ak::NoProfile },
1957 { Attribute::kind::NoRecurse, ak::NoRecurse },
1958 { Attribute::kind::NoRedZone, ak::NoRedZone },
1959 { Attribute::kind::NoReturn, ak::NoReturn },
1960 { Attribute::kind::NoSanitizeBounds, ak::NoSanitizeBounds },
1961 { Attribute::kind::NoSanitizeCoverage, ak::NoSanitizeCoverage },
1962 { Attribute::kind::NoSync, ak::NoSync },
1963 { Attribute::kind::NoUndef, ak::NoUndef },
1964 { Attribute::kind::NoUnwind, ak::NoUnwind },
1965 { Attribute::kind::NonLazyBind, ak::NonLazyBind },
1966 { Attribute::kind::NonNull, ak::NonNull },
1967 { Attribute::kind::NullPointerIsValid, ak::NullPointerIsValid },
1968 { Attribute::kind::OptForFuzzing, ak::OptForFuzzing },
1969 { Attribute::kind::OptimizeForDebugging, ak::OptimizeForDebugging },
1970 { Attribute::kind::OptimizeForSize, ak::OptimizeForSize },
1971 { Attribute::kind::OptimizeNone, ak::OptimizeNone },
1972 { Attribute::kind::PresplitCoroutine, ak::PresplitCoroutine },
1973 { Attribute::kind::ReadNone, ak::ReadNone },
1974 { Attribute::kind::ReadOnly, ak::ReadOnly },
1975 { Attribute::kind::Returned, ak::Returned },
1976 { Attribute::kind::ReturnsTwice, ak::ReturnsTwice },
1977 { Attribute::kind::SExt, ak::SExt },
1978 { Attribute::kind::SafeStack, ak::SafeStack },
1979 { Attribute::kind::SanitizeAddress, ak::SanitizeAddress },
1980 { Attribute::kind::SanitizeHWAddress, ak::SanitizeHWAddress },
1981 { Attribute::kind::SanitizeMemTag, ak::SanitizeMemTag },
1982 { Attribute::kind::SanitizeMemory, ak::SanitizeMemory },
1983 { Attribute::kind::SanitizeThread, ak::SanitizeThread },
1984 { Attribute::kind::ShadowCallStack, ak::ShadowCallStack },
1985 { Attribute::kind::SkipProfile, ak::SkipProfile },
1986 { Attribute::kind::Speculatable, ak::Speculatable },
1987 { Attribute::kind::SpeculativeLoadHardening, ak::SpeculativeLoadHardening },
1988 { Attribute::kind::StackProtect, ak::StackProtect },
1989 { Attribute::kind::StackProtectReq, ak::StackProtectReq },
1990 { Attribute::kind::StackProtectStrong, ak::StackProtectStrong },
1991 { Attribute::kind::StrictFP, ak::StrictFP },
1992 { Attribute::kind::SwiftAsync, ak::SwiftAsync },
1993 { Attribute::kind::SwiftError, ak::SwiftError },
1994 { Attribute::kind::SwiftSelf, ak::SwiftSelf },
1995 { Attribute::kind::WillReturn, ak::WillReturn },
1996 { Attribute::kind::Writable, ak::Writable },
1997 { Attribute::kind::WriteOnly, ak::WriteOnly },
1998 { Attribute::kind::ZExt, ak::ZExt },
1999 { Attribute::kind::LastEnumAttr, ak::LastEnumAttr },
2000
2001 { Attribute::kind::FirstTypeAttr, ak::FirstTypeAttr },
2002 { Attribute::kind::ByRef, ak::ByRef },
2003 { Attribute::kind::ByVal, ak::ByVal },
2004 { Attribute::kind::ElementType, ak::ElementType },
2005 { Attribute::kind::InAlloca, ak::InAlloca },
2006 { Attribute::kind::Preallocated, ak::Preallocated },
2007 { Attribute::kind::StructRet, ak::StructRet },
2008 { Attribute::kind::LastTypeAttr, ak::LastTypeAttr },
2009
2010 { Attribute::kind::FirstIntAttr, ak::FirstIntAttr },
2011 { Attribute::kind::Alignment, ak::Alignment },
2012 { Attribute::kind::AllocKind, ak::AllocKind },
2013 { Attribute::kind::AllocSize, ak::AllocSize },
2014 { Attribute::kind::Dereferenceable, ak::Dereferenceable },
2015 { Attribute::kind::DereferenceableOrNull, ak::DereferenceableOrNull },
2016 { Attribute::kind::NoFPClass, ak::NoFPClass },
2017 { Attribute::kind::StackAlignment, ak::StackAlignment },
2018 { Attribute::kind::UWTable, ak::UWTable },
2019 { Attribute::kind::VScaleRange, ak::VScaleRange },
2020 { Attribute::kind::LastIntAttr, ak::LastIntAttr },
2021
2022 { Attribute::kind::EndAttrKinds, ak::EndAttrKinds } });
2023
2024 JLM_ASSERT(map.find(kind) != map.end());
2025 return map[kind];
2026}
2027
2028::llvm::Attribute
2030{
2031 auto & llvmContext = Context_->llvm_module().getContext();
2032 auto kind = ConvertAttributeKind(attribute.kind());
2033 return ::llvm::Attribute::get(llvmContext, kind);
2034}
2035
2036::llvm::Attribute
2038{
2039 auto & llvmContext = Context_->llvm_module().getContext();
2040 auto kind = ConvertAttributeKind(attribute.kind());
2041 return ::llvm::Attribute::get(llvmContext, kind, attribute.value());
2042}
2043
2044::llvm::Attribute
2046{
2047 auto & typeConverter = Context_->GetTypeConverter();
2048 auto & llvmContext = Context_->llvm_module().getContext();
2049
2050 auto kind = ConvertAttributeKind(attribute.kind());
2051 auto type = typeConverter.ConvertJlmType(attribute.type(), llvmContext);
2052 return ::llvm::Attribute::get(llvmContext, kind, type);
2053}
2054
2055::llvm::Attribute
2057{
2058 auto & llvmContext = Context_->llvm_module().getContext();
2059 return ::llvm::Attribute::get(llvmContext, attribute.kind(), attribute.value());
2060}
2061
2062::llvm::AttributeSet
2064{
2065 ::llvm::AttrBuilder builder(Context_->llvm_module().getContext());
2066 for (auto & attribute : attributeSet.EnumAttributes())
2067 builder.addAttribute(ConvertEnumAttribute(attribute));
2068
2069 for (auto & attribute : attributeSet.IntAttributes())
2070 builder.addAttribute(ConvertIntAttribute(attribute));
2071
2072 for (auto & attribute : attributeSet.TypeAttributes())
2073 builder.addAttribute(ConvertTypeAttribute(attribute));
2074
2075 for (auto & attribute : attributeSet.StringAttributes())
2076 builder.addAttribute(ConvertStringAttribute(attribute));
2077
2078 return ::llvm::AttributeSet::get(Context_->llvm_module().getContext(), builder);
2079}
2080
2081::llvm::AttributeList
2083{
2084 auto & llvmctx = Context_->llvm_module().getContext();
2085
2086 auto fctset = convert_attributes(f.attributes());
2087
2088 // FIXME: return value attributes are currently not supported
2089 auto retset = ::llvm::AttributeSet();
2090
2091 std::vector<::llvm::AttributeSet> argsets;
2092
2093 // Attributes on function arguments are stored in the cfg
2094 if (f.cfg())
2095 {
2096 for (size_t n = 0; n < f.cfg()->entry()->narguments(); n++)
2097 {
2098 auto argument = f.cfg()->entry()->argument(n);
2099
2100 if (argument->type().Kind() == rvsdg::TypeKind::State)
2101 continue;
2102
2103 argsets.push_back(convert_attributes(argument->attributes()));
2104 }
2105 }
2106
2107 return ::llvm::AttributeList::get(llvmctx, fctset, retset, argsets);
2108}
2109
2110::llvm::AttributeList
2112{
2113 const auto functionAttributes = convert_attributes(attributeList.getFunctionAttributes());
2114 const auto returnAttributes = convert_attributes(attributeList.getReturnAttributes());
2115
2116 std::vector<::llvm::AttributeSet> parameterAttributes;
2117 for (auto & attributes : attributeList.getParameterAttributes())
2118 parameterAttributes.emplace_back(convert_attributes(attributes));
2119
2120 return ::llvm::AttributeList::get(
2121 Context_->llvm_module().getContext(),
2122 std::move(functionAttributes),
2123 std::move(returnAttributes),
2124 std::move(parameterAttributes));
2125}
2126
2127std::vector<ControlFlowGraphNode *>
2129 const ControlFlowGraph & controlFlowGraph,
2130 ::llvm::Function & function)
2131{
2132 auto nodes = breadth_first(controlFlowGraph);
2133
2134 uint64_t basicBlockCounter = 0;
2135 for (const auto & node : nodes)
2136 {
2137 if (node == controlFlowGraph.entry())
2138 continue;
2139 if (node == controlFlowGraph.exit())
2140 continue;
2141
2142 auto name = util::strfmt("bb", basicBlockCounter++);
2143 auto * basicBlock = ::llvm::BasicBlock::Create(function.getContext(), name, &function);
2144 Context_->insert(node, basicBlock);
2145 }
2146
2147 return nodes;
2148}
2149
2150void
2152{
2153 JLM_ASSERT(is_closed(cfg));
2154
2155 auto add_arguments = [&](const ControlFlowGraph & cfg, ::llvm::Function & f)
2156 {
2157 size_t n = 0;
2158 for (auto & llvmarg : f.args())
2159 {
2160 auto jlmarg = cfg.entry()->argument(n++);
2161 Context_->insert(jlmarg, &llvmarg);
2162 }
2163 };
2164
2165 straighten(cfg);
2166
2167 auto nodes = ConvertBasicBlocks(cfg, f);
2168
2169 add_arguments(cfg, f);
2170
2171 // create non-terminator instructions
2172 for (const auto & node : nodes)
2173 {
2174 if (node == cfg.entry() || node == cfg.exit())
2175 continue;
2176
2177 JLM_ASSERT(is<BasicBlock>(node));
2178 auto & tacs = static_cast<const BasicBlock *>(node)->tacs();
2179 for (const auto & tac : tacs)
2180 convert_instruction(*tac, node);
2181 }
2182
2183 // create cfg structure
2184 for (const auto & node : nodes)
2185 {
2186 if (node == cfg.entry() || node == cfg.exit())
2187 continue;
2188
2190 }
2191
2192 // patch phi instructions
2193 for (const auto & node : nodes)
2194 {
2195 if (node == cfg.entry() || node == cfg.exit())
2196 continue;
2197
2198 JLM_ASSERT(is<BasicBlock>(node));
2199 auto & tacs = static_cast<const BasicBlock *>(node)->tacs();
2200 for (const auto & tac : tacs)
2201 {
2202 if (!is<SsaPhiOperation>(tac->operation()))
2203 continue;
2204
2205 if (rvsdg::is<IOStateType>(tac->result(0)->type()))
2206 continue;
2207 if (rvsdg::is<MemoryStateType>(tac->result(0)->type()))
2208 continue;
2209
2210 JLM_ASSERT(node->NumInEdges() == tac->noperands());
2211 auto & op = *static_cast<const SsaPhiOperation *>(&tac->operation());
2212 auto phi = ::llvm::dyn_cast<::llvm::PHINode>(Context_->value(tac->result(0)));
2213 for (size_t n = 0; n < tac->noperands(); n++)
2214 phi->addIncoming(
2215 Context_->value(tac->operand(n)),
2216 Context_->basic_block(op.GetIncomingNode(n)));
2217 }
2218 }
2219}
2220
2221void
2223{
2224 if (!node.cfg())
2225 return;
2226
2227 auto & im = Context_->module();
2228 auto f = ::llvm::cast<::llvm::Function>(Context_->value(im.variable(&node)));
2229
2230 // Type, name, attributes and calling convention have already been set on the LLVM Function.
2231 // The only conversion that remains is the function body.
2232
2233 convert_cfg(*node.cfg(), *f);
2234}
2235
2236void
2238{
2239 if (!node.initialization())
2240 return;
2241
2242 auto & jm = Context_->module();
2243 auto init = node.initialization();
2244 convert_tacs(init->tacs());
2245
2246 auto gv = ::llvm::dyn_cast<::llvm::GlobalVariable>(Context_->value(jm.variable(&node)));
2247 gv->setInitializer(::llvm::dyn_cast<::llvm::Constant>(Context_->value(init->value())));
2248}
2249
2250const ::llvm::GlobalValue::LinkageTypes &
2252{
2253 static std::unordered_map<llvm::Linkage, ::llvm::GlobalValue::LinkageTypes> map(
2254 { { llvm::Linkage::externalLinkage, ::llvm::GlobalValue::ExternalLinkage },
2256 ::llvm::GlobalValue::AvailableExternallyLinkage },
2257 { llvm::Linkage::linkOnceAnyLinkage, ::llvm::GlobalValue::LinkOnceAnyLinkage },
2258 { llvm::Linkage::linkOnceOdrLinkage, ::llvm::GlobalValue::LinkOnceODRLinkage },
2259 { llvm::Linkage::weakAnyLinkage, ::llvm::GlobalValue::WeakAnyLinkage },
2260 { llvm::Linkage::weakOdrLinkage, ::llvm::GlobalValue::WeakODRLinkage },
2261 { llvm::Linkage::appendingLinkage, ::llvm::GlobalValue::AppendingLinkage },
2262 { llvm::Linkage::internalLinkage, ::llvm::GlobalValue::InternalLinkage },
2263 { llvm::Linkage::privateLinkage, ::llvm::GlobalValue::PrivateLinkage },
2264 { llvm::Linkage::externalWeakLinkage, ::llvm::GlobalValue::ExternalWeakLinkage },
2265 { llvm::Linkage::commonLinkage, ::llvm::GlobalValue::CommonLinkage } });
2266
2267 JLM_ASSERT(map.find(linkage) != map.end());
2268 return map[linkage];
2269}
2270
2271void
2273{
2274 auto & typeConverter = Context_->GetTypeConverter();
2275 auto & jm = Context_->module();
2276 auto & lm = Context_->llvm_module();
2277
2278 // forward declare all nodes
2279 for (const auto & node : jm.ipgraph())
2280 {
2281 auto v = jm.variable(&node);
2282
2283 if (auto dataNode = dynamic_cast<const DataNode *>(&node))
2284 {
2285 auto type = typeConverter.ConvertJlmType(*dataNode->GetValueType(), lm.getContext());
2286 auto linkage = convert_linkage(dataNode->linkage());
2287
2288 auto gv = new ::llvm::GlobalVariable(
2289 lm,
2290 type,
2291 dataNode->constant(),
2292 linkage,
2293 nullptr,
2294 dataNode->name());
2295 gv->setSection(dataNode->Section());
2296 gv->setAlignment(::llvm::Align(dataNode->getAlignment()));
2297 Context_->insert(v, gv);
2298 }
2299 else if (auto n = dynamic_cast<const FunctionNode *>(&node))
2300 {
2301 auto type = typeConverter.ConvertFunctionType(n->fcttype(), lm.getContext());
2302 auto linkage = convert_linkage(n->linkage());
2303 auto f = ::llvm::Function::Create(type, linkage, n->name(), &lm);
2304
2305 // Set the calling convention and attributes on the function
2306 const auto callingConvention = convertCallingConventionToLlvm(n->callingConvention());
2307 f->setCallingConv(callingConvention);
2308 auto attributes = convert_attributes(*n);
2309 f->setAttributes(attributes);
2310
2311 Context_->insert(v, f);
2312 }
2313 else
2314 JLM_ASSERT(0);
2315 }
2316
2317 // convert all nodes
2318 for (const auto & node : jm.ipgraph())
2319 {
2320 if (auto n = dynamic_cast<const DataNode *>(&node))
2321 {
2323 }
2324 else if (auto n = dynamic_cast<const FunctionNode *>(&node))
2325 {
2326 convert_function(*n);
2327 }
2328 else
2329 JLM_ASSERT(0);
2330 }
2331}
2332
2333std::unique_ptr<::llvm::Module>
2335 InterProceduralGraphModule & ipGraphModule,
2336 ::llvm::LLVMContext & llvmContext)
2337{
2338 std::unique_ptr<::llvm::Module> llvmModule(new ::llvm::Module("module", llvmContext));
2339 llvmModule->setSourceFileName(ipGraphModule.source_filename().to_str());
2340 llvmModule->setTargetTriple(ipGraphModule.target_triple());
2341 llvmModule->setDataLayout(ipGraphModule.data_layout());
2342
2343 Context_ = Context::Create(ipGraphModule, *llvmModule);
2345
2346 return llvmModule;
2347}
2348
2349std::unique_ptr<::llvm::Module>
2351 InterProceduralGraphModule & ipGraphModule,
2352 ::llvm::LLVMContext & ctx)
2353{
2354 IpGraphToLlvmConverter converter;
2355 return converter.ConvertModule(ipGraphModule, ctx);
2356}
2357
2358}
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:38
const rvsdg::SimpleOperation & operation() const noexcept
Definition tac.hpp:92
const Variable * operand(size_t index) const noexcept
Definition tac.hpp:104
const ThreeAddressCodeVariable * result(size_t index) const noexcept
Definition tac.hpp:117
size_t noperands() const noexcept
Definition tac.hpp:98
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:223
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