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