Jlm
LlvmInstructionConversion.cpp
Go to the documentation of this file.
1 /*
2  * Copyright 2014 2015 Nico Reißmann <nico.reissmann@gmail.com>
3  * See COPYING for terms of redistribution.
4  */
5 
12 
13 #include <llvm/ADT/StringExtras.h>
14 #include <llvm/IR/Constants.h>
15 #include <llvm/IR/Function.h>
16 #include <llvm/IR/Instructions.h>
17 #include <llvm/IR/IntrinsicInst.h>
18 
19 namespace jlm::llvm
20 {
21 
22 // Converts a value into a variable either representing the llvm
23 // value or representing a function object.
24 // The distinction stems from the fact that llvm treats functions simply
25 // as pointers to the function code while we distinguish between the two.
26 // This function can return either and caller needs to check / adapt.
27 const Variable *
28 ConvertValueOrFunction(::llvm::Value * v, tacsvector_t & tacs, Context & ctx)
29 {
30  auto node = ctx.node();
31  if (node && ctx.has_value(v))
32  {
33  if (auto callee = dynamic_cast<const FunctionVariable *>(ctx.lookup_value(v)))
34  node->add_dependency(callee->function());
35 
36  if (auto data = dynamic_cast<const GlobalValue *>(ctx.lookup_value(v)))
37  node->add_dependency(data->node());
38  }
39 
40  if (ctx.has_value(v))
41  return ctx.lookup_value(v);
42 
43  if (auto c = ::llvm::dyn_cast<::llvm::Constant>(v))
44  return ConvertConstant(c, tacs, ctx);
45 
46  JLM_UNREACHABLE("This should not have happened!");
47 }
48 
49 // Converts a value into a variable representing the llvm value.
50 const Variable *
51 ConvertValue(::llvm::Value * v, tacsvector_t & tacs, Context & ctx)
52 {
53  const Variable * var = ConvertValueOrFunction(v, tacs, ctx);
54  if (auto fntype = std::dynamic_pointer_cast<const rvsdg::FunctionType>(var->Type()))
55  {
56  auto operation = std::make_unique<FunctionToPointerOperation>(fntype);
57  std::unique_ptr<ThreeAddressCode> ptr_cast =
58  ThreeAddressCode::create(std::move(operation), { var });
59  var = ptr_cast->result(0);
60  tacs.push_back(std::move(ptr_cast));
61  }
62  return var;
63 }
64 
65 /* constant */
66 
67 const Variable *
69  ::llvm::Constant *,
70  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> &,
71  Context &);
72 
74 convert_apint(const ::llvm::APInt & value)
75 {
76  ::llvm::APInt v;
77  if (value.isNegative())
78  v = -value;
79 
80  auto str = toString(value, 2, false);
81  std::reverse(str.begin(), str.end());
82 
83  rvsdg::BitValueRepresentation vr(str.c_str());
84  if (value.isNegative())
85  vr = vr.sext(value.getBitWidth() - str.size());
86  else
87  vr = vr.zext(value.getBitWidth() - str.size());
88 
89  return vr;
90 }
91 
92 static const Variable *
94  ::llvm::Constant * c,
95  std::vector<std::unique_ptr<ThreeAddressCode>> & tacs,
96  Context &)
97 {
98  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantIntVal);
99  const auto constant = ::llvm::cast<const ::llvm::ConstantInt>(c);
100 
101  const auto v = convert_apint(constant->getValue());
102  tacs.push_back(
103  ThreeAddressCode::create(std::make_unique<IntegerConstantOperation>(std::move(v)), {}));
104 
105  return tacs.back()->result(0);
106 }
107 
108 static inline const Variable *
110  ::llvm::Constant * c,
111  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
112  Context & ctx)
113 {
114  JLM_ASSERT(c->getValueID() == ::llvm::Value::UndefValueVal);
115 
116  auto t = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
117  tacs.push_back(UndefValueOperation::Create(t));
118 
119  return tacs.back()->result(0);
120 }
121 
122 static const Variable *
124  ::llvm::Constant * constant,
125  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
126  Context & ctx)
127 {
128  JLM_ASSERT(constant->getValueID() == ::llvm::Value::ConstantExprVal);
129  auto c = ::llvm::cast<::llvm::ConstantExpr>(constant);
130 
131  /*
132  FIXME: ConvertInstruction currently assumes that a instruction's result variable
133  is already added to the context. This is not the case for constants and we
134  therefore need to do some poilerplate checking in ConvertInstruction to
135  see whether a variable was already declared or we need to create a new
136  variable.
137  */
138 
139  /* FIXME: getAsInstruction is none const, forcing all llvm parameters to be none const */
140  /* FIXME: The invocation of getAsInstruction() introduces a memory leak. */
141  auto instruction = c->getAsInstruction();
142  auto v = ConvertInstruction(instruction, tacs, ctx);
143  instruction->dropAllReferences();
144  return v;
145 }
146 
147 static const Variable *
149  ::llvm::Constant * constant,
150  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
151  Context & ctx)
152 {
153  JLM_ASSERT(constant->getValueID() == ::llvm::Value::ConstantFPVal);
154  auto c = ::llvm::cast<::llvm::ConstantFP>(constant);
155 
156  auto type = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
157  tacs.push_back(ConstantFP::create(c->getValueAPF(), type));
158 
159  return tacs.back()->result(0);
160 }
161 
162 static const Variable *
164  ::llvm::Constant * c,
165  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
166  Context & ctx)
167 {
168  JLM_ASSERT(c->getValueID() == ::llvm::Value::GlobalVariableVal);
169  return ConvertValue(c, tacs, ctx);
170 }
171 
172 static const Variable *
174  ::llvm::Constant * constant,
175  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
176  Context & ctx)
177 {
178  JLM_ASSERT(::llvm::dyn_cast<const ::llvm::ConstantPointerNull>(constant));
179  auto & c = *::llvm::cast<const ::llvm::ConstantPointerNull>(constant);
180 
181  auto t = ctx.GetTypeConverter().ConvertPointerType(*c.getType());
182  tacs.push_back(ConstantPointerNullOperation::Create(t));
183 
184  return tacs.back()->result(0);
185 }
186 
187 static const Variable *
189  ::llvm::Constant * constant,
190  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> &,
191  Context &)
192 {
193  JLM_ASSERT(constant->getValueID() == ::llvm::Value::BlockAddressVal);
194 
195  JLM_UNREACHABLE("Blockaddress constants are not supported.");
196 }
197 
198 static const Variable *
200  ::llvm::Constant * c,
201  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
202  Context & ctx)
203 {
204  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantAggregateZeroVal);
205 
206  auto type = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
208 
209  return tacs.back()->result(0);
210 }
211 
212 static const Variable *
214  ::llvm::Constant * c,
215  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
216  Context & ctx)
217 {
218  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantArrayVal);
219 
220  std::vector<const Variable *> elements;
221  for (size_t n = 0; n < c->getNumOperands(); n++)
222  {
223  auto operand = c->getOperand(n);
224  JLM_ASSERT(::llvm::dyn_cast<const ::llvm::Constant>(operand));
225  auto constant = ::llvm::cast<::llvm::Constant>(operand);
226  elements.push_back(ConvertConstant(constant, tacs, ctx));
227  }
228 
229  tacs.push_back(ConstantArrayOperation::create(elements));
230 
231  return tacs.back()->result(0);
232 }
233 
234 static const Variable *
236  ::llvm::Constant * constant,
237  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
238  Context & ctx)
239 {
240  JLM_ASSERT(constant->getValueID() == ::llvm::Value::ConstantDataArrayVal);
241  const auto & c = *::llvm::cast<const ::llvm::ConstantDataArray>(constant);
242 
243  std::vector<const Variable *> elements;
244  for (size_t n = 0; n < c.getNumElements(); n++)
245  elements.push_back(ConvertConstant(c.getElementAsConstant(n), tacs, ctx));
246 
247  tacs.push_back(ConstantDataArray::create(elements));
248 
249  return tacs.back()->result(0);
250 }
251 
252 static const Variable *
254  ::llvm::Constant * constant,
255  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
256  Context & ctx)
257 {
258  JLM_ASSERT(constant->getValueID() == ::llvm::Value::ConstantDataVectorVal);
259  auto c = ::llvm::cast<const ::llvm::ConstantDataVector>(constant);
260 
261  std::vector<const Variable *> elements;
262  for (size_t n = 0; n < c->getNumElements(); n++)
263  elements.push_back(ConvertConstant(c->getElementAsConstant(n), tacs, ctx));
264 
265  tacs.push_back(ConstantDataVectorOperation::Create(elements));
266 
267  return tacs.back()->result(0);
268 }
269 
270 static const Variable *
272  ::llvm::Constant * c,
273  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
274  Context & ctx)
275 {
276  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantStructVal);
277 
278  std::vector<const Variable *> elements;
279  for (size_t n = 0; n < c->getNumOperands(); n++)
280  elements.push_back(ConvertConstant(c->getAggregateElement(n), tacs, ctx));
281 
282  auto type = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
283  tacs.push_back(ConstantStruct::create(elements, type));
284 
285  return tacs.back()->result(0);
286 }
287 
288 static const Variable *
290  ::llvm::Constant * c,
291  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
292  Context & ctx)
293 {
294  JLM_ASSERT(c->getValueID() == ::llvm::Value::ConstantVectorVal);
295 
296  std::vector<const Variable *> elements;
297  for (size_t n = 0; n < c->getNumOperands(); n++)
298  elements.push_back(ConvertConstant(c->getAggregateElement(n), tacs, ctx));
299 
300  auto type = ctx.GetTypeConverter().ConvertLlvmType(*c->getType());
301  tacs.push_back(ConstantVectorOperation::create(elements, type));
302 
303  return tacs.back()->result(0);
304 }
305 
306 static inline const Variable *
308  ::llvm::Constant * constant,
309  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> &,
310  Context &)
311 {
312  JLM_ASSERT(constant->getValueID() == ::llvm::Value::GlobalAliasVal);
313 
314  JLM_UNREACHABLE("GlobalAlias constants are not supported.");
315 }
316 
317 static inline const Variable *
318 convert_function(::llvm::Constant * c, tacsvector_t & tacs, Context & ctx)
319 {
320  JLM_ASSERT(c->getValueID() == ::llvm::Value::FunctionVal);
321  return ConvertValue(c, tacs, ctx);
322 }
323 
324 static const Variable *
326  ::llvm::PoisonValue * poisonValue,
327  tacsvector_t & threeAddressCodeVector,
328  Context & context)
329 {
330  auto type = context.GetTypeConverter().ConvertLlvmType(*poisonValue->getType());
331  threeAddressCodeVector.push_back(PoisonValueOperation::Create(type));
332 
333  return threeAddressCodeVector.back()->result(0);
334 }
335 
336 template<class T>
337 static const Variable *
339  ::llvm::Constant * constant,
340  tacsvector_t & threeAddressCodeVector,
341  Context & context)
342 {
343  JLM_ASSERT(::llvm::dyn_cast<T>(constant));
344  return ConvertConstant(::llvm::cast<T>(constant), threeAddressCodeVector, context);
345 }
346 
347 const Variable *
349  ::llvm::Constant * c,
350  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
351  Context & ctx)
352 {
353  static std::unordered_map<
354  unsigned,
355  const Variable * (*)(::llvm::Constant *,
356  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> &,
357  Context & ctx)>
358  constantMap({ { ::llvm::Value::BlockAddressVal, convert_blockAddress },
359  { ::llvm::Value::ConstantAggregateZeroVal, convert_constantAggregateZero },
360  { ::llvm::Value::ConstantArrayVal, convert_constantArray },
361  { ::llvm::Value::ConstantDataArrayVal, convert_constantDataArray },
362  { ::llvm::Value::ConstantDataVectorVal, convert_constantDataVector },
363  { ::llvm::Value::ConstantExprVal, convert_constantExpr },
364  { ::llvm::Value::ConstantFPVal, convert_constantFP },
365  { ::llvm::Value::ConstantIntVal, convert_int_constant },
366  { ::llvm::Value::ConstantPointerNullVal, convert_constantPointerNull },
367  { ::llvm::Value::ConstantStructVal, ConvertConstantStruct },
368  { ::llvm::Value::ConstantVectorVal, convert_constantVector },
369  { ::llvm::Value::FunctionVal, convert_function },
370  { ::llvm::Value::GlobalAliasVal, convert_globalAlias },
371  { ::llvm::Value::GlobalVariableVal, convert_globalVariable },
372  { ::llvm::Value::PoisonValueVal, ConvertConstant<::llvm::PoisonValue> },
373  { ::llvm::Value::UndefValueVal, convert_undefvalue } });
374 
375  if (constantMap.find(c->getValueID()) != constantMap.end())
376  return constantMap[c->getValueID()](c, tacs, ctx);
377 
378  JLM_UNREACHABLE("Unsupported LLVM Constant.");
379 }
380 
381 std::vector<std::unique_ptr<llvm::ThreeAddressCode>>
382 ConvertConstant(::llvm::Constant * c, Context & ctx)
383 {
384  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> tacs;
385  ConvertConstant(c, tacs, ctx);
386  return tacs;
387 }
388 
389 /* instructions */
390 
391 static inline const Variable *
392 convert_return_instruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
393 {
394  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::Ret);
395  auto i = ::llvm::cast<::llvm::ReturnInst>(instruction);
396 
397  auto bb = ctx.get(i->getParent());
398  bb->add_outedge(bb->cfg().exit());
399  if (!i->getReturnValue())
400  return {};
401 
402  auto value = ConvertValue(i->getReturnValue(), tacs, ctx);
403  tacs.push_back(AssignmentOperation::create(value, ctx.result()));
404 
405  return ctx.result();
406 }
407 
408 static const Variable *
409 ConvertBranchInstruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
410 {
411  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::Br);
412  auto i = ::llvm::cast<::llvm::BranchInst>(instruction);
413  auto bb = ctx.get(i->getParent());
414 
415  JLM_ASSERT(bb->NumOutEdges() == 0);
416 
417  if (i->isUnconditional())
418  {
419  bb->add_outedge(ctx.get(i->getSuccessor(0)));
420  return nullptr;
421  }
422 
423  bb->add_outedge(ctx.get(i->getSuccessor(1))); // False out-edge
424  bb->add_outedge(ctx.get(i->getSuccessor(0))); // True out-edge
425 
426  auto c = ConvertValue(i->getCondition(), tacs, ctx);
427  auto nbits = i->getCondition()->getType()->getIntegerBitWidth();
428  auto op =
429  std::unique_ptr<rvsdg::MatchOperation>(new rvsdg::MatchOperation(nbits, { { 1, 1 } }, 0, 2));
430  tacs.push_back(ThreeAddressCode::create(std::move(op), { c }));
431  tacs.push_back(BranchOperation::create(2, tacs.back()->result(0)));
432 
433  return nullptr;
434 }
435 
436 static const Variable *
437 ConvertSwitchInstruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
438 {
439  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::Switch);
440  auto i = ::llvm::cast<::llvm::SwitchInst>(instruction);
441  auto bb = ctx.get(i->getParent());
442 
443  JLM_ASSERT(bb->NumOutEdges() == 0);
444  std::unordered_map<uint64_t, uint64_t> mapping;
445  for (auto it = i->case_begin(); it != i->case_end(); it++)
446  {
447  JLM_ASSERT(it != i->case_default());
448  auto edge = bb->add_outedge(ctx.get(it->getCaseSuccessor()));
449  mapping[it->getCaseValue()->getZExtValue()] = edge->index();
450  }
451 
452  auto defaultEdge = bb->add_outedge(ctx.get(i->case_default()->getCaseSuccessor()));
453 
454  auto c = ConvertValue(i->getCondition(), tacs, ctx);
455  auto nbits = i->getCondition()->getType()->getIntegerBitWidth();
456  auto op = std::make_unique<rvsdg::MatchOperation>(
457  nbits,
458  mapping,
459  defaultEdge->index(),
460  bb->NumOutEdges());
461  tacs.push_back(ThreeAddressCode::create(std::move(op), { c }));
462  tacs.push_back(BranchOperation::create(bb->NumOutEdges(), tacs.back()->result(0)));
463 
464  return nullptr;
465 }
466 
467 static inline const Variable *
468 convert_unreachable_instruction(::llvm::Instruction * i, tacsvector_t &, Context & ctx)
469 {
470  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Unreachable);
471  auto bb = ctx.get(i->getParent());
472  bb->add_outedge(bb->cfg().exit());
473  return nullptr;
474 }
475 
476 static std::unique_ptr<rvsdg::BinaryOperation>
477 ConvertIntegerIcmpPredicate(const ::llvm::CmpInst::Predicate predicate, const std::size_t numBits)
478 {
479  switch (predicate)
480  {
481  case ::llvm::CmpInst::ICMP_SLT:
482  return std::make_unique<IntegerSltOperation>(numBits);
483  case ::llvm::CmpInst::ICMP_ULT:
484  return std::make_unique<IntegerUltOperation>(numBits);
485  case ::llvm::CmpInst::ICMP_SLE:
486  return std::make_unique<IntegerSleOperation>(numBits);
487  case ::llvm::CmpInst::ICMP_ULE:
488  return std::make_unique<IntegerUleOperation>(numBits);
489  case ::llvm::CmpInst::ICMP_EQ:
490  return std::make_unique<IntegerEqOperation>(numBits);
491  case ::llvm::CmpInst::ICMP_NE:
492  return std::make_unique<IntegerNeOperation>(numBits);
493  case ::llvm::CmpInst::ICMP_SGE:
494  return std::make_unique<IntegerSgeOperation>(numBits);
495  case ::llvm::CmpInst::ICMP_UGE:
496  return std::make_unique<IntegerUgeOperation>(numBits);
497  case ::llvm::CmpInst::ICMP_SGT:
498  return std::make_unique<IntegerSgtOperation>(numBits);
499  case ::llvm::CmpInst::ICMP_UGT:
500  return std::make_unique<IntegerUgtOperation>(numBits);
501  default:
502  JLM_UNREACHABLE("ConvertIntegerIcmpPredicate: Unsupported icmp predicate.");
503  }
504 }
505 
506 static std::unique_ptr<rvsdg::BinaryOperation>
507 ConvertPointerIcmpPredicate(const ::llvm::CmpInst::Predicate predicate)
508 {
509  switch (predicate)
510  {
511  case ::llvm::CmpInst::ICMP_ULT:
512  return std::make_unique<PtrCmpOperation>(PointerType::Create(), cmp::lt);
513  case ::llvm::CmpInst::ICMP_ULE:
514  return std::make_unique<PtrCmpOperation>(PointerType::Create(), cmp::le);
515  case ::llvm::CmpInst::ICMP_EQ:
516  return std::make_unique<PtrCmpOperation>(PointerType::Create(), cmp::eq);
517  case ::llvm::CmpInst::ICMP_NE:
518  return std::make_unique<PtrCmpOperation>(PointerType::Create(), cmp::ne);
519  case ::llvm::CmpInst::ICMP_UGE:
520  return std::make_unique<PtrCmpOperation>(PointerType::Create(), cmp::ge);
521  case ::llvm::CmpInst::ICMP_UGT:
522  return std::make_unique<PtrCmpOperation>(PointerType::Create(), cmp::gt);
523  default:
524  JLM_UNREACHABLE("ConvertPointerIcmpPredicate: Unsupported icmp predicate.");
525  }
526 }
527 
528 static const Variable *
529 convert(const ::llvm::ICmpInst * instruction, tacsvector_t & tacs, Context & ctx)
530 {
531  const auto predicate = instruction->getPredicate();
532  const auto operandType = instruction->getOperand(0)->getType();
533  auto op1 = ConvertValue(instruction->getOperand(0), tacs, ctx);
534  auto op2 = ConvertValue(instruction->getOperand(1), tacs, ctx);
535 
536  std::unique_ptr<rvsdg::BinaryOperation> operation;
537  if (operandType->isVectorTy() && operandType->getScalarType()->isIntegerTy())
538  {
539  operation =
540  ConvertIntegerIcmpPredicate(predicate, operandType->getScalarType()->getIntegerBitWidth());
541  }
542  else if (operandType->isVectorTy() && operandType->getScalarType()->isPointerTy())
543  {
544  operation = ConvertPointerIcmpPredicate(predicate);
545  }
546  else if (operandType->isIntegerTy())
547  {
548  operation = ConvertIntegerIcmpPredicate(predicate, operandType->getIntegerBitWidth());
549  }
550  else if (operandType->isPointerTy())
551  {
552  operation = ConvertPointerIcmpPredicate(predicate);
553  }
554  else
555  {
556  JLM_UNREACHABLE("convert: Unhandled icmp type.");
557  }
558 
559  if (operandType->isVectorTy())
560  {
561  const auto instructionType = ctx.GetTypeConverter().ConvertLlvmType(*instruction->getType());
562  tacs.push_back(VectorBinaryOperation::create(*operation, op1, op2, instructionType));
563  }
564  else
565  {
566  tacs.push_back(ThreeAddressCode::create(std::move(operation), { op1, op2 }));
567  }
568 
569  return tacs.back()->result(0);
570 }
571 
572 static const Variable *
573 convert_fcmp_instruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
574 {
575  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::FCmp);
576  auto & typeConverter = ctx.GetTypeConverter();
577  auto i = ::llvm::cast<const ::llvm::FCmpInst>(instruction);
578  auto t = i->getOperand(0)->getType();
579 
580  static std::unordered_map<::llvm::CmpInst::Predicate, llvm::fpcmp> map(
581  { { ::llvm::CmpInst::FCMP_TRUE, fpcmp::TRUE },
582  { ::llvm::CmpInst::FCMP_FALSE, fpcmp::FALSE },
583  { ::llvm::CmpInst::FCMP_OEQ, fpcmp::oeq },
584  { ::llvm::CmpInst::FCMP_OGT, fpcmp::ogt },
585  { ::llvm::CmpInst::FCMP_OGE, fpcmp::oge },
586  { ::llvm::CmpInst::FCMP_OLT, fpcmp::olt },
587  { ::llvm::CmpInst::FCMP_OLE, fpcmp::ole },
588  { ::llvm::CmpInst::FCMP_ONE, fpcmp::one },
589  { ::llvm::CmpInst::FCMP_ORD, fpcmp::ord },
590  { ::llvm::CmpInst::FCMP_UNO, fpcmp::uno },
591  { ::llvm::CmpInst::FCMP_UEQ, fpcmp::ueq },
592  { ::llvm::CmpInst::FCMP_UGT, fpcmp::ugt },
593  { ::llvm::CmpInst::FCMP_UGE, fpcmp::uge },
594  { ::llvm::CmpInst::FCMP_ULT, fpcmp::ult },
595  { ::llvm::CmpInst::FCMP_ULE, fpcmp::ule },
596  { ::llvm::CmpInst::FCMP_UNE, fpcmp::une } });
597 
598  auto type = typeConverter.ConvertLlvmType(*i->getType());
599 
600  auto op1 = ConvertValue(i->getOperand(0), tacs, ctx);
601  auto op2 = ConvertValue(i->getOperand(1), tacs, ctx);
602 
603  JLM_ASSERT(map.find(i->getPredicate()) != map.end());
604  auto fptype = t->isVectorTy() ? t->getScalarType() : t;
605  auto operation = std::make_unique<FCmpOperation>(
606  map[i->getPredicate()],
607  typeConverter.ExtractFloatingPointSize(*fptype));
608 
609  if (t->isVectorTy())
610  tacs.push_back(VectorBinaryOperation::create(*operation, op1, op2, type));
611  else
612  tacs.push_back(ThreeAddressCode::create(std::move(operation), { op1, op2 }));
613 
614  return tacs.back()->result(0);
615 }
616 
617 static const Variable *
618 AddIOBarrier(tacsvector_t & tacs, const Variable * operand, const Context & ctx)
619 {
620  auto ioBarrierOperation = std::make_unique<IOBarrierOperation>(operand->Type());
621  tacs.push_back(
622  ThreeAddressCode::create(std::move(ioBarrierOperation), { operand, ctx.iostate() }));
623  return tacs.back()->result(0);
624 }
625 
626 static inline const Variable *
627 convert_load_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
628 {
629  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Load);
630  auto instruction = static_cast<::llvm::LoadInst *>(i);
631 
632  auto alignment = instruction->getAlign().value();
633  auto address = ConvertValue(instruction->getPointerOperand(), tacs, ctx);
634  auto loadedType = ctx.GetTypeConverter().ConvertLlvmType(*instruction->getType());
635 
636  const ThreeAddressCodeVariable * loadedValue = nullptr;
637  const ThreeAddressCodeVariable * memoryState = nullptr;
638  const ThreeAddressCodeVariable * ioState = nullptr;
639  if (instruction->isVolatile())
640  {
641  auto loadVolatileTac = LoadVolatileOperation::Create(
642  address,
643  ctx.iostate(),
644  ctx.memory_state(),
645  loadedType,
646  alignment);
647  tacs.push_back(std::move(loadVolatileTac));
648 
649  loadedValue = tacs.back()->result(0);
650  ioState = tacs.back()->result(1);
651  memoryState = tacs.back()->result(2);
652  }
653  else
654  {
655  address = AddIOBarrier(tacs, address, ctx);
656  auto loadTac =
657  LoadNonVolatileOperation::Create(address, ctx.memory_state(), loadedType, alignment);
658  tacs.push_back(std::move(loadTac));
659  loadedValue = tacs.back()->result(0);
660  memoryState = tacs.back()->result(1);
661  }
662 
663  if (ioState)
664  {
665  tacs.push_back(AssignmentOperation::create(ioState, ctx.iostate()));
666  }
667  tacs.push_back(AssignmentOperation::create(memoryState, ctx.memory_state()));
668 
669  return loadedValue;
670 }
671 
672 static inline const Variable *
673 convert_store_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
674 {
675  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Store);
676  auto instruction = static_cast<::llvm::StoreInst *>(i);
677 
678  auto alignment = instruction->getAlign().value();
679  auto address = ConvertValue(instruction->getPointerOperand(), tacs, ctx);
680  auto value = ConvertValue(instruction->getValueOperand(), tacs, ctx);
681 
682  const ThreeAddressCodeVariable * memoryState = nullptr;
683  const ThreeAddressCodeVariable * ioState = nullptr;
684  if (instruction->isVolatile())
685  {
686  auto storeVolatileTac = StoreVolatileOperation::Create(
687  address,
688  value,
689  ctx.iostate(),
690  ctx.memory_state(),
691  alignment);
692  tacs.push_back(std::move(storeVolatileTac));
693  ioState = tacs.back()->result(0);
694  memoryState = tacs.back()->result(1);
695  }
696  else
697  {
698  address = AddIOBarrier(tacs, address, ctx);
699  auto storeTac =
700  StoreNonVolatileOperation::Create(address, value, ctx.memory_state(), alignment);
701  tacs.push_back(std::move(storeTac));
702  memoryState = tacs.back()->result(0);
703  }
704 
705  if (ioState)
706  {
707  tacs.push_back(AssignmentOperation::create(ioState, ctx.iostate()));
708  }
709  tacs.push_back(AssignmentOperation::create(memoryState, ctx.memory_state()));
710 
711  return nullptr;
712 }
713 
714 static const Variable *
715 ConvertPhiInstruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
716 {
717  // Some of the blocks reaching this phi instruction might not be converted yet,
718  // so some of the phi's operands may reference instructions that have not yet been converted.
719  // For now, a SsaPhiOperation with no operands is created.
720  // Once all basic blocks are converted, all SsaPhiOperations are revisited and given operands.
721  auto type = ctx.GetTypeConverter().ConvertLlvmType(*i->getType());
722  tacs.push_back(SsaPhiOperation::create({}, std::move(type)));
723  return tacs.back()->result(0);
724 }
725 
726 static const Variable *
727 convert_getelementptr_instruction(::llvm::Instruction * inst, tacsvector_t & tacs, Context & ctx)
728 {
729  JLM_ASSERT(::llvm::dyn_cast<const ::llvm::GetElementPtrInst>(inst));
730  auto & typeConverter = ctx.GetTypeConverter();
731  auto i = ::llvm::cast<::llvm::GetElementPtrInst>(inst);
732 
733  std::vector<const Variable *> indices;
734  auto base = ConvertValue(i->getPointerOperand(), tacs, ctx);
735  for (auto it = i->idx_begin(); it != i->idx_end(); it++)
736  indices.push_back(ConvertValue(*it, tacs, ctx));
737 
738  auto pointeeType = typeConverter.ConvertLlvmType(*i->getSourceElementType());
739  auto resultType = typeConverter.ConvertLlvmType(*i->getType());
740 
741  tacs.push_back(GetElementPtrOperation::Create(base, indices, pointeeType, resultType));
742 
743  return tacs.back()->result(0);
744 }
745 
746 static const Variable *
747 convert_malloc_call(const ::llvm::CallInst * i, tacsvector_t & tacs, Context & ctx)
748 {
749  auto globalMemoryState = ctx.memory_state();
750  auto globalIOState = ctx.iostate();
751 
752  auto size = ConvertValue(i->getArgOperand(0), tacs, ctx);
753 
754  tacs.push_back(MallocOperation::createTac(size, globalIOState));
755  auto mallocAddress = tacs.back()->result(0);
756  auto mallocIOState = tacs.back()->result(1);
757  auto mallocMemoryState = tacs.back()->result(2);
758 
759  tacs.push_back(AssignmentOperation::create(mallocIOState, globalIOState));
760 
761  tacs.push_back(MemoryStateMergeOperation::Create({ mallocMemoryState, globalMemoryState }));
762  tacs.push_back(AssignmentOperation::create(tacs.back()->result(0), globalMemoryState));
763 
764  return mallocAddress;
765 }
766 
767 static const Variable *
768 convert_free_call(const ::llvm::CallInst * i, tacsvector_t & tacs, Context & ctx)
769 {
770  auto iostate = ctx.iostate();
771  auto memstate = ctx.memory_state();
772 
773  auto pointer = ConvertValue(i->getArgOperand(0), tacs, ctx);
774 
775  tacs.push_back(FreeOperation::Create(pointer, { memstate }, iostate));
776  auto & freeThreeAddressCode = *tacs.back().get();
777 
778  tacs.push_back(AssignmentOperation::create(freeThreeAddressCode.result(0), memstate));
779  tacs.push_back(AssignmentOperation::create(freeThreeAddressCode.result(1), iostate));
780 
781  return nullptr;
782 }
783 
792 static bool
793 IsVolatile(const ::llvm::Value & value)
794 {
795  auto constant = ::llvm::dyn_cast<const ::llvm::ConstantInt>(&value);
796  JLM_ASSERT(constant != nullptr && constant->getType()->getIntegerBitWidth() == 1);
797 
798  auto apInt = constant->getValue();
799  JLM_ASSERT(apInt.isZero() || apInt.isOne());
800 
801  return apInt.isOne();
802 }
803 
804 static const Variable *
805 convert_memcpy_call(const ::llvm::CallInst * instruction, tacsvector_t & tacs, Context & ctx)
806 {
807  auto ioState = ctx.iostate();
808  auto memoryState = ctx.memory_state();
809 
810  auto destination = ConvertValue(instruction->getArgOperand(0), tacs, ctx);
811  auto source = ConvertValue(instruction->getArgOperand(1), tacs, ctx);
812  auto length = ConvertValue(instruction->getArgOperand(2), tacs, ctx);
813 
814  if (IsVolatile(*instruction->getArgOperand(3)))
815  {
817  *destination,
818  *source,
819  *length,
820  *ioState,
821  { memoryState }));
822  auto & memCpyVolatileTac = *tacs.back();
823  tacs.push_back(AssignmentOperation::create(memCpyVolatileTac.result(0), ioState));
824  tacs.push_back(AssignmentOperation::create(memCpyVolatileTac.result(1), memoryState));
825  }
826  else
827  {
828  tacs.push_back(
829  MemCpyNonVolatileOperation::create(destination, source, length, { memoryState }));
830  tacs.push_back(AssignmentOperation::create(tacs.back()->result(0), memoryState));
831  }
832 
833  return nullptr;
834 }
835 
836 static bool
837 IsFMulAddIntrinsic(const ::llvm::Instruction & instruction)
838 {
839  const auto intrinsic = ::llvm::dyn_cast<::llvm::IntrinsicInst>(&instruction);
840  return intrinsic && intrinsic->getIntrinsicID() == ::llvm::Intrinsic::fmuladd;
841 }
842 
843 static const Variable *
844 ConvertFMulAddIntrinsic(const ::llvm::CallInst & instruction, tacsvector_t & tacs, Context & ctx)
845 {
846  const auto multiplier = ConvertValue(instruction.getArgOperand(0), tacs, ctx);
847  const auto multiplicand = ConvertValue(instruction.getArgOperand(1), tacs, ctx);
848  const auto summand = ConvertValue(instruction.getArgOperand(2), tacs, ctx);
849  tacs.push_back(FMulAddIntrinsicOperation::CreateTac(*multiplier, *multiplicand, *summand));
850 
851  return tacs.back()->result(0);
852 }
853 
854 static const Variable *
855 convert_call_instruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
856 {
857  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::Call);
858  auto i = ::llvm::cast<::llvm::CallInst>(instruction);
859 
860  auto create_arguments = [](const ::llvm::CallInst * i, tacsvector_t & tacs, Context & ctx)
861  {
862  auto functionType = i->getFunctionType();
863  std::vector<const llvm::Variable *> arguments;
864  for (size_t n = 0; n < functionType->getNumParams(); n++)
865  arguments.push_back(ConvertValue(i->getArgOperand(n), tacs, ctx));
866 
867  return arguments;
868  };
869 
870  auto create_varargs = [](const ::llvm::CallInst * i, tacsvector_t & tacs, Context & ctx)
871  {
872  auto functionType = i->getFunctionType();
873  std::vector<const llvm::Variable *> varargs;
874  for (size_t n = functionType->getNumParams(); n < i->getNumOperands() - 1; n++)
875  varargs.push_back(ConvertValue(i->getArgOperand(n), tacs, ctx));
876 
877  tacs.push_back(VariadicArgumentListOperation::create(varargs));
878  return tacs.back()->result(0);
879  };
880 
881  auto is_malloc_call = [](const ::llvm::CallInst * i)
882  {
883  auto f = i->getCalledFunction();
884  return f && f->getName() == "malloc";
885  };
886 
887  auto is_free_call = [](const ::llvm::CallInst * i)
888  {
889  auto f = i->getCalledFunction();
890  return f && f->getName() == "free";
891  };
892 
893  auto IsMemcpyCall = [](const ::llvm::CallInst * i)
894  {
895  return ::llvm::dyn_cast<::llvm::MemCpyInst>(i) != nullptr;
896  };
897 
898  if (is_malloc_call(i))
899  return convert_malloc_call(i, tacs, ctx);
900  if (is_free_call(i))
901  return convert_free_call(i, tacs, ctx);
902  if (IsMemcpyCall(i))
903  return convert_memcpy_call(i, tacs, ctx);
904  if (IsFMulAddIntrinsic(*instruction))
905  return ConvertFMulAddIntrinsic(*i, tacs, ctx);
906 
907  auto ftype = i->getFunctionType();
908  auto convertedFType = ctx.GetTypeConverter().ConvertFunctionType(*ftype);
909 
910  auto arguments = create_arguments(i, tacs, ctx);
911  if (ftype->isVarArg())
912  arguments.push_back(create_varargs(i, tacs, ctx));
913  arguments.push_back(ctx.iostate());
914  arguments.push_back(ctx.memory_state());
915 
916  const Variable * callee = ConvertValueOrFunction(i->getCalledOperand(), tacs, ctx);
917  // Llvm does not distinguish between "function objects" and
918  // "pointers to functions" while we need to be precise in modelling.
919  // If the called object is a function object, then we can just
920  // feed it to the call operator directly, otherwise we have
921  // to cast it into a function object.
922  if (is<PointerType>(*callee->Type()))
923  {
924  std::unique_ptr<ThreeAddressCode> callee_cast = ThreeAddressCode::create(
925  std::make_unique<PointerToFunctionOperation>(convertedFType),
926  { callee });
927  callee = callee_cast->result(0);
928  tacs.push_back(std::move(callee_cast));
929  }
930  else if (auto fntype = std::dynamic_pointer_cast<const rvsdg::FunctionType>(callee->Type()))
931  {
932  // Llvm also allows argument type mismatches if the function
933  // features varargs. The code here could be made more precise by
934  // validating and accepting only vararg-related mismatches.
935  if (*convertedFType != *fntype)
936  {
937  // Since vararg passing is not modelled explicitly, simply hide the
938  // argument mismtach via pointer casts.
939  std::unique_ptr<ThreeAddressCode> ptrCast = ThreeAddressCode::create(
940  std::make_unique<FunctionToPointerOperation>(fntype),
941  { callee });
942  std::unique_ptr<ThreeAddressCode> fnCast = ThreeAddressCode::create(
943  std::make_unique<PointerToFunctionOperation>(convertedFType),
944  { ptrCast->result(0) });
945  callee = fnCast->result(0);
946  tacs.push_back(std::move(ptrCast));
947  tacs.push_back(std::move(fnCast));
948  }
949  }
950  else
951  {
952  throw std::runtime_error("Unexpected callee type: " + callee->Type()->debug_string());
953  }
954 
955  auto call = CallOperation::create(callee, convertedFType, arguments);
956 
957  auto result = call->result(0);
958  auto iostate = call->result(call->nresults() - 2);
959  auto memstate = call->result(call->nresults() - 1);
960 
961  tacs.push_back(std::move(call));
962  tacs.push_back(AssignmentOperation::create(iostate, ctx.iostate()));
963  tacs.push_back(AssignmentOperation::create(memstate, ctx.memory_state()));
964 
965  return result;
966 }
967 
968 static inline const Variable *
969 convert_select_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
970 {
971  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::Select);
972  auto instruction = static_cast<::llvm::SelectInst *>(i);
973 
974  auto p = ConvertValue(instruction->getCondition(), tacs, ctx);
975  auto t = ConvertValue(instruction->getTrueValue(), tacs, ctx);
976  auto f = ConvertValue(instruction->getFalseValue(), tacs, ctx);
977 
978  if (i->getType()->isVectorTy())
979  tacs.push_back(VectorSelectOperation::create(p, t, f));
980  else
981  tacs.push_back(SelectOperation::create(p, t, f));
982 
983  return tacs.back()->result(0);
984 }
985 
986 static std::unique_ptr<rvsdg::BinaryOperation>
988  const ::llvm::Instruction::BinaryOps binaryOperation,
989  std::size_t numBits)
990 {
991  switch (binaryOperation)
992  {
993  case ::llvm::Instruction::Add:
994  return std::make_unique<IntegerAddOperation>(numBits);
995  case ::llvm::Instruction::And:
996  return std::make_unique<IntegerAndOperation>(numBits);
997  case ::llvm::Instruction::AShr:
998  return std::make_unique<IntegerAShrOperation>(numBits);
999  case ::llvm::Instruction::LShr:
1000  return std::make_unique<IntegerLShrOperation>(numBits);
1001  case ::llvm::Instruction::Mul:
1002  return std::make_unique<IntegerMulOperation>(numBits);
1003  case ::llvm::Instruction::Or:
1004  return std::make_unique<IntegerOrOperation>(numBits);
1005  case ::llvm::Instruction::SDiv:
1006  return std::make_unique<IntegerSDivOperation>(numBits);
1007  case ::llvm::Instruction::Shl:
1008  return std::make_unique<IntegerShlOperation>(numBits);
1009  case ::llvm::Instruction::SRem:
1010  return std::make_unique<IntegerSRemOperation>(numBits);
1011  case ::llvm::Instruction::Sub:
1012  return std::make_unique<IntegerSubOperation>(numBits);
1013  case ::llvm::Instruction::UDiv:
1014  return std::make_unique<IntegerUDivOperation>(numBits);
1015  case ::llvm::Instruction::URem:
1016  return std::make_unique<IntegerURemOperation>(numBits);
1017  case ::llvm::Instruction::Xor:
1018  return std::make_unique<IntegerXorOperation>(numBits);
1019  default:
1020  JLM_UNREACHABLE("ConvertIntegerBinaryOperation: Unsupported integer binary operation");
1021  }
1022 }
1023 
1024 static std::unique_ptr<rvsdg::BinaryOperation>
1026  const ::llvm::Instruction::BinaryOps binaryOperation,
1027  fpsize floatingPointSize)
1028 {
1029  switch (binaryOperation)
1030  {
1031  case ::llvm::Instruction::FAdd:
1032  return std::make_unique<FBinaryOperation>(fpop::add, floatingPointSize);
1033  case ::llvm::Instruction::FSub:
1034  return std::make_unique<FBinaryOperation>(fpop::sub, floatingPointSize);
1035  case ::llvm::Instruction::FMul:
1036  return std::make_unique<FBinaryOperation>(fpop::mul, floatingPointSize);
1037  case ::llvm::Instruction::FDiv:
1038  return std::make_unique<FBinaryOperation>(fpop::div, floatingPointSize);
1039  case ::llvm::Instruction::FRem:
1040  return std::make_unique<FBinaryOperation>(fpop::mod, floatingPointSize);
1041  default:
1042  JLM_UNREACHABLE("ConvertFloatingPointBinaryOperation: Unsupported binary operation");
1043  }
1044 }
1045 
1046 static const Variable *
1047 convert(const ::llvm::BinaryOperator * instruction, tacsvector_t & tacs, Context & ctx)
1048 {
1049  const auto llvmType = instruction->getType();
1050  auto & typeConverter = ctx.GetTypeConverter();
1051  const auto opcode = instruction->getOpcode();
1052 
1053  std::unique_ptr<rvsdg::BinaryOperation> operation;
1054  if (llvmType->isVectorTy() && llvmType->getScalarType()->isIntegerTy())
1055  {
1056  const auto numBits = llvmType->getScalarType()->getIntegerBitWidth();
1057  operation = ConvertIntegerBinaryOperation(opcode, numBits);
1058  }
1059  else if (llvmType->isVectorTy() && llvmType->getScalarType()->isFloatingPointTy())
1060  {
1061  const auto size = typeConverter.ExtractFloatingPointSize(*llvmType->getScalarType());
1062  operation = ConvertFloatingPointBinaryOperation(opcode, size);
1063  }
1064  else if (llvmType->isIntegerTy())
1065  {
1066  operation = ConvertIntegerBinaryOperation(opcode, llvmType->getIntegerBitWidth());
1067  }
1068  else if (llvmType->isFloatingPointTy())
1069  {
1070  const auto size = typeConverter.ExtractFloatingPointSize(*llvmType);
1071  operation = ConvertFloatingPointBinaryOperation(opcode, size);
1072  }
1073  else
1074  {
1075  JLM_ASSERT("convert: Unhandled binary operation type.");
1076  }
1077 
1078  const auto jlmType = typeConverter.ConvertLlvmType(*llvmType);
1079  auto operand1 = ConvertValue(instruction->getOperand(0), tacs, ctx);
1080  auto operand2 = ConvertValue(instruction->getOperand(1), tacs, ctx);
1081 
1082  if (instruction->getOpcode() == ::llvm::Instruction::SDiv
1083  || instruction->getOpcode() == ::llvm::Instruction::UDiv
1084  || instruction->getOpcode() == ::llvm::Instruction::SRem
1085  || instruction->getOpcode() == ::llvm::Instruction::URem)
1086  {
1087  operand1 = AddIOBarrier(tacs, operand1, ctx);
1088  }
1089 
1090  if (llvmType->isVectorTy())
1091  {
1092  tacs.push_back(VectorBinaryOperation::create(*operation, operand1, operand2, jlmType));
1093  }
1094  else
1095  {
1096  tacs.push_back(ThreeAddressCode::create(std::move(operation), { operand1, operand2 }));
1097  }
1098 
1099  return tacs.back()->result(0);
1100 }
1101 
1102 static inline const Variable *
1103 convert_alloca_instruction(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
1104 {
1105  JLM_ASSERT(instruction->getOpcode() == ::llvm::Instruction::Alloca);
1106  auto i = static_cast<::llvm::AllocaInst *>(instruction);
1107 
1108  auto memstate = ctx.memory_state();
1109  auto size = ConvertValue(i->getArraySize(), tacs, ctx);
1110  auto vtype = ctx.GetTypeConverter().ConvertLlvmType(*i->getAllocatedType());
1111  auto alignment = i->getAlign().value();
1112 
1113  tacs.push_back(AllocaOperation::create(vtype, size, alignment));
1114  auto result = tacs.back()->result(0);
1115  auto astate = tacs.back()->result(1);
1116 
1117  tacs.push_back(MemoryStateMergeOperation::Create({ astate, memstate }));
1118  tacs.push_back(AssignmentOperation::create(tacs.back()->result(0), memstate));
1119 
1120  return result;
1121 }
1122 
1123 static const Variable *
1124 convert_extractvalue(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1125 {
1126  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::ExtractValue);
1127  auto ev = ::llvm::dyn_cast<::llvm::ExtractValueInst>(i);
1128 
1129  auto aggregate = ConvertValue(ev->getOperand(0), tacs, ctx);
1130  tacs.push_back(ExtractValueOperation::create(aggregate, ev->getIndices()));
1131 
1132  return tacs.back()->result(0);
1133 }
1134 
1135 static inline const Variable *
1136 convert_extractelement_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1137 {
1138  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::ExtractElement);
1139 
1140  auto vector = ConvertValue(i->getOperand(0), tacs, ctx);
1141  auto index = ConvertValue(i->getOperand(1), tacs, ctx);
1142  tacs.push_back(ExtractElementOperation::create(vector, index));
1143 
1144  return tacs.back()->result(0);
1145 }
1146 
1147 static const Variable *
1148 convert(::llvm::ShuffleVectorInst * i, tacsvector_t & tacs, Context & ctx)
1149 {
1150  auto v1 = ConvertValue(i->getOperand(0), tacs, ctx);
1151  auto v2 = ConvertValue(i->getOperand(1), tacs, ctx);
1152 
1153  std::vector<int> mask;
1154  for (auto & element : i->getShuffleMask())
1155  mask.push_back(element);
1156 
1157  tacs.push_back(ShuffleVectorOperation::create(v1, v2, mask));
1158 
1159  return tacs.back()->result(0);
1160 }
1161 
1162 static const Variable *
1163 convert_insertelement_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1164 {
1165  JLM_ASSERT(i->getOpcode() == ::llvm::Instruction::InsertElement);
1166 
1167  auto vector = ConvertValue(i->getOperand(0), tacs, ctx);
1168  auto value = ConvertValue(i->getOperand(1), tacs, ctx);
1169  auto index = ConvertValue(i->getOperand(2), tacs, ctx);
1170  tacs.push_back(InsertElementOperation::create(vector, value, index));
1171 
1172  return tacs.back()->result(0);
1173 }
1174 
1175 static const Variable *
1176 convert(::llvm::UnaryOperator * unaryOperator, tacsvector_t & threeAddressCodeVector, Context & ctx)
1177 {
1178  JLM_ASSERT(unaryOperator->getOpcode() == ::llvm::Instruction::FNeg);
1179  auto & typeConverter = ctx.GetTypeConverter();
1180 
1181  auto type = unaryOperator->getType();
1182  auto scalarType = typeConverter.ConvertLlvmType(*type->getScalarType());
1183  auto operand = ConvertValue(unaryOperator->getOperand(0), threeAddressCodeVector, ctx);
1184 
1185  if (type->isVectorTy())
1186  {
1187  auto vectorType = typeConverter.ConvertLlvmType(*type);
1188  threeAddressCodeVector.push_back(VectorUnaryOperation::create(
1189  FNegOperation(std::static_pointer_cast<const FloatingPointType>(scalarType)),
1190  operand,
1191  vectorType));
1192  }
1193  else
1194  {
1195  threeAddressCodeVector.push_back(FNegOperation::create(operand));
1196  }
1197 
1198  return threeAddressCodeVector.back()->result(0);
1199 }
1200 
1201 template<class OP>
1202 static std::unique_ptr<rvsdg::SimpleOperation>
1203 create_unop(std::shared_ptr<const rvsdg::Type> st, std::shared_ptr<const rvsdg::Type> dt)
1204 {
1205  return std::unique_ptr<rvsdg::SimpleOperation>(new OP(std::move(st), std::move(dt)));
1206 }
1207 
1208 static const Variable *
1209 convert_cast_instruction(::llvm::Instruction * i, tacsvector_t & tacs, Context & ctx)
1210 {
1211  JLM_ASSERT(::llvm::dyn_cast<::llvm::CastInst>(i));
1212  auto & typeConverter = ctx.GetTypeConverter();
1213  auto st = i->getOperand(0)->getType();
1214  auto dt = i->getType();
1215 
1216  static std::unordered_map<
1217  unsigned,
1218  std::unique_ptr<rvsdg::SimpleOperation> (*)(
1219  std::shared_ptr<const rvsdg::Type>,
1220  std::shared_ptr<const rvsdg::Type>)>
1221  map({ { ::llvm::Instruction::Trunc, create_unop<TruncOperation> },
1222  { ::llvm::Instruction::ZExt, create_unop<ZExtOperation> },
1223  { ::llvm::Instruction::UIToFP, create_unop<UIToFPOperation> },
1224  { ::llvm::Instruction::SIToFP, create_unop<SIToFPOperation> },
1225  { ::llvm::Instruction::SExt, create_unop<SExtOperation> },
1226  { ::llvm::Instruction::PtrToInt, create_unop<PtrToIntOperation> },
1227  { ::llvm::Instruction::IntToPtr, create_unop<IntegerToPointerOperation> },
1228  { ::llvm::Instruction::FPTrunc, create_unop<FPTruncOperation> },
1229  { ::llvm::Instruction::FPToSI, create_unop<FloatingPointToSignedIntegerOperation> },
1230  { ::llvm::Instruction::FPToUI, create_unop<FloatingPointToUnsignedIntegerOperation> },
1231  { ::llvm::Instruction::FPExt, create_unop<FPExtOperation> },
1232  { ::llvm::Instruction::BitCast, create_unop<BitCastOperation> } });
1233 
1234  auto type = ctx.GetTypeConverter().ConvertLlvmType(*i->getType());
1235 
1236  auto op = ConvertValue(i->getOperand(0), tacs, ctx);
1237  auto srctype = typeConverter.ConvertLlvmType(*(st->isVectorTy() ? st->getScalarType() : st));
1238  auto dsttype = typeConverter.ConvertLlvmType(*(dt->isVectorTy() ? dt->getScalarType() : dt));
1239 
1240  JLM_ASSERT(map.find(i->getOpcode()) != map.end());
1241  auto unop = map[i->getOpcode()](std::move(srctype), std::move(dsttype));
1242  JLM_ASSERT(is<rvsdg::UnaryOperation>(*unop));
1243 
1244  if (dt->isVectorTy())
1245  tacs.push_back(
1246  VectorUnaryOperation::create(*static_cast<rvsdg::UnaryOperation *>(unop.get()), op, type));
1247  else
1248  tacs.push_back(ThreeAddressCode::create(std::move(unop), { op }));
1249 
1250  return tacs.back()->result(0);
1251 }
1252 
1253 template<class INSTRUCTIONTYPE>
1254 static const Variable *
1255 convert(::llvm::Instruction * instruction, tacsvector_t & tacs, Context & ctx)
1256 {
1257  JLM_ASSERT(::llvm::isa<INSTRUCTIONTYPE>(instruction));
1258  return convert(::llvm::cast<INSTRUCTIONTYPE>(instruction), tacs, ctx);
1259 }
1260 
1261 const Variable *
1263  ::llvm::Instruction * i,
1264  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> & tacs,
1265  Context & ctx)
1266 {
1267  if (i->isCast())
1268  return convert_cast_instruction(i, tacs, ctx);
1269 
1270  static std::unordered_map<
1271  unsigned,
1272  const Variable * (*)(::llvm::Instruction *,
1273  std::vector<std::unique_ptr<llvm::ThreeAddressCode>> &,
1274  Context &)>
1275  map({ { ::llvm::Instruction::Ret, convert_return_instruction },
1276  { ::llvm::Instruction::Br, ConvertBranchInstruction },
1277  { ::llvm::Instruction::Switch, ConvertSwitchInstruction },
1278  { ::llvm::Instruction::Unreachable, convert_unreachable_instruction },
1279  { ::llvm::Instruction::Add, convert<::llvm::BinaryOperator> },
1280  { ::llvm::Instruction::And, convert<::llvm::BinaryOperator> },
1281  { ::llvm::Instruction::AShr, convert<::llvm::BinaryOperator> },
1282  { ::llvm::Instruction::Sub, convert<::llvm::BinaryOperator> },
1283  { ::llvm::Instruction::UDiv, convert<::llvm::BinaryOperator> },
1284  { ::llvm::Instruction::SDiv, convert<::llvm::BinaryOperator> },
1285  { ::llvm::Instruction::URem, convert<::llvm::BinaryOperator> },
1286  { ::llvm::Instruction::SRem, convert<::llvm::BinaryOperator> },
1287  { ::llvm::Instruction::Shl, convert<::llvm::BinaryOperator> },
1288  { ::llvm::Instruction::LShr, convert<::llvm::BinaryOperator> },
1289  { ::llvm::Instruction::Or, convert<::llvm::BinaryOperator> },
1290  { ::llvm::Instruction::Xor, convert<::llvm::BinaryOperator> },
1291  { ::llvm::Instruction::Mul, convert<::llvm::BinaryOperator> },
1292  { ::llvm::Instruction::FAdd, convert<::llvm::BinaryOperator> },
1293  { ::llvm::Instruction::FSub, convert<::llvm::BinaryOperator> },
1294  { ::llvm::Instruction::FMul, convert<::llvm::BinaryOperator> },
1295  { ::llvm::Instruction::FDiv, convert<::llvm::BinaryOperator> },
1296  { ::llvm::Instruction::FRem, convert<::llvm::BinaryOperator> },
1297  { ::llvm::Instruction::FNeg, convert<::llvm::UnaryOperator> },
1298  { ::llvm::Instruction::ICmp, convert<::llvm::ICmpInst> },
1299  { ::llvm::Instruction::FCmp, convert_fcmp_instruction },
1300  { ::llvm::Instruction::Load, convert_load_instruction },
1301  { ::llvm::Instruction::Store, convert_store_instruction },
1302  { ::llvm::Instruction::PHI, ConvertPhiInstruction },
1303  { ::llvm::Instruction::GetElementPtr, convert_getelementptr_instruction },
1304  { ::llvm::Instruction::Call, convert_call_instruction },
1305  { ::llvm::Instruction::Select, convert_select_instruction },
1306  { ::llvm::Instruction::Alloca, convert_alloca_instruction },
1307  { ::llvm::Instruction::ExtractValue, convert_extractvalue },
1308  { ::llvm::Instruction::ExtractElement, convert_extractelement_instruction },
1309  { ::llvm::Instruction::ShuffleVector, convert<::llvm::ShuffleVectorInst> },
1310  { ::llvm::Instruction::InsertElement, convert_insertelement_instruction } });
1311 
1312  if (map.find(i->getOpcode()) == map.end())
1313  JLM_UNREACHABLE(util::strfmt(i->getOpcodeName(), " is not supported.").c_str());
1314 
1315  return map[i->getOpcode()](i, tacs, ctx);
1316 }
1317 
1318 }
static std::unique_ptr< llvm::ThreeAddressCode > create(std::shared_ptr< const rvsdg::Type > allocatedType, const Variable *size, size_t alignment)
Definition: alloca.hpp:90
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *rhs, const Variable *lhs)
Definition: operators.hpp:117
static std::unique_ptr< llvm::ThreeAddressCode > create(size_t nalternatives, const Variable *operand)
Definition: operators.hpp:418
static std::unique_ptr< ThreeAddressCode > create(const Variable *function, std::shared_ptr< const rvsdg::FunctionType > functionType, const std::vector< const Variable * > &arguments)
Definition: call.hpp:426
static std::unique_ptr< llvm::ThreeAddressCode > create(std::shared_ptr< const jlm::rvsdg::Type > type)
Definition: operators.hpp:1893
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &elements)
Definition: operators.hpp:1838
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &elements)
Definition: operators.hpp:654
static std::unique_ptr< ThreeAddressCode > Create(const std::vector< const Variable * > &elements)
Definition: operators.hpp:2298
static std::unique_ptr< llvm::ThreeAddressCode > create(const ::llvm::APFloat &constant, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:886
static std::unique_ptr< llvm::ThreeAddressCode > Create(std::shared_ptr< const rvsdg::Type > type)
Definition: operators.hpp:454
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &elements, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:1558
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &operands, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:2020
const llvm::Variable * lookup_value(const ::llvm::Value *value) const noexcept
llvm::Variable * memory_state() const noexcept
const llvm::Variable * result() const noexcept
bool has_value(const ::llvm::Value *value) const noexcept
llvm::Variable * iostate() const noexcept
BasicBlock * get(const ::llvm::BasicBlock *bb) const noexcept
InterProceduralGraphNode * node() const noexcept
TypeConverter & GetTypeConverter() noexcept
ControlFlowGraphEdge * add_outedge(ControlFlowGraphNode *sink)
Definition: cfg-node.hpp:130
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *vector, const llvm::Variable *index)
Definition: operators.hpp:1927
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *aggregate, const std::vector< unsigned > &indices)
Definition: operators.hpp:2358
static std::unique_ptr< ThreeAddressCode > CreateTac(const Variable &multiplier, const Variable &multiplicand, const Variable &summand)
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *operand)
Definition: operators.hpp:1314
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *pointer, const std::vector< const Variable * > &memoryStates, const Variable *iOState)
Definition: operators.hpp:2554
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *baseAddress, const std::vector< const Variable * > &offsets, std::shared_ptr< const rvsdg::Type > pointeeType, std::shared_ptr< const rvsdg::Type > resultType)
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *vector, const llvm::Variable *value, const llvm::Variable *index)
Definition: operators.hpp:2062
void add_dependency(const InterProceduralGraphNode *dep)
Definition: ipgraph.hpp:96
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *state, std::shared_ptr< const rvsdg::Type > loadedType, size_t alignment)
Definition: Load.hpp:429
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *iOState, const Variable *memoryState, std::shared_ptr< const rvsdg::Type > loadedType, size_t alignment)
Definition: Load.hpp:228
static std::unique_ptr< ThreeAddressCode > createTac(const Variable *size, const Variable *ioState)
Definition: operators.hpp:2481
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *destination, const Variable *source, const Variable *length, const std::vector< const Variable * > &memoryStates)
Definition: MemCpy.hpp:173
static std::unique_ptr< llvm::ThreeAddressCode > CreateThreeAddressCode(const Variable &destination, const Variable &source, const Variable &length, const Variable &ioState, const std::vector< const Variable * > &memoryStates)
Definition: MemCpy.hpp:271
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &operands)
static std::shared_ptr< const PointerType > Create()
Definition: types.cpp:45
static std::unique_ptr< llvm::ThreeAddressCode > Create(const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:1095
static std::unique_ptr< llvm::ThreeAddressCode > create(const llvm::Variable *p, const llvm::Variable *t, const llvm::Variable *f)
Definition: operators.hpp:158
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *v1, const Variable *v2, const std::vector< int > &mask)
Definition: operators.hpp:1977
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< std::pair< const Variable *, ControlFlowGraphNode * >> &arguments, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition: operators.hpp:74
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *state, size_t alignment)
Definition: Store.hpp:281
static std::unique_ptr< llvm::ThreeAddressCode > Create(const Variable *address, const Variable *value, const Variable *ioState, const Variable *memoryState, size_t alignment)
Definition: Store.hpp:416
static std::unique_ptr< llvm::ThreeAddressCode > create(std::unique_ptr< rvsdg::SimpleOperation > operation, const std::vector< const Variable * > &operands)
Definition: tac.hpp:135
::llvm::PointerType * ConvertPointerType(const PointerType &type, ::llvm::LLVMContext &context)
::llvm::FunctionType * ConvertFunctionType(const rvsdg::FunctionType &functionType, ::llvm::LLVMContext &context)
std::shared_ptr< const rvsdg::Type > ConvertLlvmType(::llvm::Type &type)
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
Definition: operators.hpp:1024
const std::shared_ptr< const jlm::rvsdg::Type > Type() const noexcept
Definition: variable.hpp:62
static std::unique_ptr< llvm::ThreeAddressCode > create(const std::vector< const Variable * > &arguments)
Definition: operators.hpp:1436
static std::unique_ptr< llvm::ThreeAddressCode > create(const rvsdg::BinaryOperation &binop, const llvm::Variable *op1, const llvm::Variable *op2, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:2245
static std::unique_ptr< llvm::ThreeAddressCode > create(const Variable *p, const Variable *t, const Variable *f)
Definition: operators.hpp:206
static std::unique_ptr< llvm::ThreeAddressCode > create(const rvsdg::UnaryOperation &unop, const llvm::Variable *operand, const std::shared_ptr< const jlm::rvsdg::Type > &type)
Definition: operators.hpp:2152
BitValueRepresentation sext(size_t nbits) const
BitValueRepresentation zext(size_t nbits) const
Unary operator.
Definition: unary.hpp:26
#define JLM_ASSERT(x)
Definition: common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition: common.hpp:43
Global memory state passed between functions.
static const Variable * convert_fcmp_instruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
static rvsdg::BitValueRepresentation convert_apint(const ::llvm::APInt &value)
static const Variable * convert_constantFP(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static std::unique_ptr< rvsdg::SimpleOperation > create_unop(std::shared_ptr< const rvsdg::Type > st, std::shared_ptr< const rvsdg::Type > dt)
static bool IsFMulAddIntrinsic(const ::llvm::Instruction &instruction)
static const Variable * convert_malloc_call(const ::llvm::CallInst *i, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_free_call(const ::llvm::CallInst *i, tacsvector_t &tacs, Context &ctx)
static ControlFlowGraphNode * aggregate(ControlFlowGraphNode *, ControlFlowGraphNode *, AggregationMap &)
static const Variable * convert_insertelement_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_globalAlias(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &, Context &)
std::vector< std::unique_ptr< llvm::ThreeAddressCode > > tacsvector_t
Definition: tac.hpp:202
static const Variable * AddIOBarrier(tacsvector_t &tacs, const Variable *operand, const Context &ctx)
static const Variable * convert_globalVariable(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_extractvalue(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static std::unique_ptr< rvsdg::BinaryOperation > ConvertFloatingPointBinaryOperation(const ::llvm::Instruction::BinaryOps binaryOperation, fpsize floatingPointSize)
static const Variable * convert_constantAggregateZero(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_extractelement_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static std::unique_ptr< rvsdg::BinaryOperation > ConvertIntegerBinaryOperation(const ::llvm::Instruction::BinaryOps binaryOperation, std::size_t numBits)
static const Variable * convert_constantVector(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
const Variable * ConvertConstant(::llvm::Constant *, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &, Context &)
static const Variable * convert_call_instruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
static const Variable * ConvertBranchInstruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_alloca_instruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_constantArray(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
const Variable * ConvertValueOrFunction(::llvm::Value *v, tacsvector_t &tacs, Context &ctx)
static const Variable * convert(const ::llvm::ICmpInst *instruction, tacsvector_t &tacs, Context &ctx)
static std::unique_ptr< rvsdg::BinaryOperation > ConvertPointerIcmpPredicate(const ::llvm::CmpInst::Predicate predicate)
static const Variable * convert_int_constant(::llvm::Constant *c, std::vector< std::unique_ptr< ThreeAddressCode >> &tacs, Context &)
static const Variable * ConvertPhiInstruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_constantPointerNull(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * ConvertFMulAddIntrinsic(const ::llvm::CallInst &instruction, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_constantExpr(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_store_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_cast_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
const Variable * ConvertValue(::llvm::Value *v, tacsvector_t &tacs, Context &ctx)
static const Variable * ConvertSwitchInstruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_blockAddress(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &, Context &)
static const Variable * convert_undefvalue(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_load_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_constantDataVector(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_unreachable_instruction(::llvm::Instruction *i, tacsvector_t &, Context &ctx)
static const Variable * convert_getelementptr_instruction(::llvm::Instruction *inst, tacsvector_t &tacs, Context &ctx)
static bool IsVolatile(const ::llvm::Value &value)
static const Variable * convert_return_instruction(::llvm::Instruction *instruction, tacsvector_t &tacs, Context &ctx)
static const Variable * ConvertConstantStruct(::llvm::Constant *c, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_memcpy_call(const ::llvm::CallInst *instruction, tacsvector_t &tacs, Context &ctx)
const Variable * ConvertInstruction(::llvm::Instruction *i, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_constantDataArray(::llvm::Constant *constant, std::vector< std::unique_ptr< llvm::ThreeAddressCode >> &tacs, Context &ctx)
static const Variable * convert_function(::llvm::Constant *c, tacsvector_t &tacs, Context &ctx)
static const Variable * convert_select_instruction(::llvm::Instruction *i, tacsvector_t &tacs, Context &ctx)
static std::unique_ptr< rvsdg::BinaryOperation > ConvertIntegerIcmpPredicate(const ::llvm::CmpInst::Predicate predicate, const std::size_t numBits)
static std::string type(const Node *n)
Definition: view.cpp:255
static std::string strfmt(Args... args)
Definition: strfmt.hpp:35