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