29 #include <llvm/IR/BasicBlock.h>
30 #include <llvm/IR/IRBuilder.h>
31 #include <llvm/IR/Module.h>
33 #include <unordered_map>
41 std::unordered_map<const ControlFlowGraphNode *, ::llvm::BasicBlock *>::const_iterator;
100 auto it =
nodes_.find(node);
119 static std::unique_ptr<Context>
122 return std::make_unique<Context>(ipGraphModule, llvmModule);
128 std::unordered_map<const llvm::Variable *, ::llvm::Value *>
variables_;
129 std::unordered_map<const llvm::ControlFlowGraphNode *, ::llvm::BasicBlock *>
nodes_;
139 const rvsdg::SimpleOperation & op,
140 const std::vector<const
Variable *> & args,
141 ::
llvm::IRBuilder<> &)
144 return Context_->value(args[0]);
149 const ::llvm::Instruction::BinaryOps opcode,
150 const std::vector<const Variable *> & args,
151 ::llvm::IRBuilder<> & builder)
153 const auto operand1 =
Context_->value(args[0]);
154 const auto operand2 =
Context_->value(args[1]);
155 return builder.CreateBinOp(opcode, operand1, operand2);
160 const ::llvm::CmpInst::Predicate predicate,
161 const std::vector<const Variable *> & args,
162 ::llvm::IRBuilder<> & builder)
164 const auto operand1 =
Context_->value(args[0]);
165 const auto operand2 =
Context_->value(args[1]);
166 return builder.CreateICmp(predicate, operand1, operand2);
174 std::string str = vr.
str();
175 std::reverse(str.begin(), str.end());
177 return ::llvm::APInt(vr.
nbits(), str, 2);
183 const std::vector<const Variable *> &,
184 ::llvm::IRBuilder<> & builder)
186 const auto & representation =
187 util::assertedCast<const IntegerConstantOperation>(&op)->Representation();
188 const auto type = ::llvm::IntegerType::get(builder.getContext(), representation.nbits());
190 if (representation.is_defined())
193 return ::llvm::UndefValue::get(type);
199 const std::vector<const Variable *> &,
200 ::llvm::IRBuilder<> & builder)
202 JLM_ASSERT(is<rvsdg::ControlConstantOperation>(op));
206 auto type = ::llvm::IntegerType::get(builder.getContext(), nbits);
207 return ::llvm::ConstantInt::get(type, cop.value().alternative());
213 const std::vector<const Variable *> &,
214 ::llvm::IRBuilder<> & builder)
216 return ::llvm::ConstantFP::get(builder.getContext(), op.
constant());
222 const std::vector<const Variable *> &,
223 ::llvm::IRBuilder<> &)
226 auto & llvmContext =
Context_->llvm_module().getContext();
227 auto & typeConverter =
Context_->GetTypeConverter();
229 auto & resultType = *op.
result(0);
232 if (is<MemoryStateType>(resultType))
235 auto type = typeConverter.ConvertJlmType(resultType, llvmContext);
236 return ::llvm::UndefValue::get(type);
242 const std::vector<const Variable *> &,
243 ::llvm::IRBuilder<> &)
245 auto & llvmContext =
Context_->llvm_module().getContext();
246 auto & typeConverter =
Context_->GetTypeConverter();
248 auto type = typeConverter.ConvertJlmType(operation.
GetType(), llvmContext);
249 return ::llvm::PoisonValue::get(type);
255 const std::vector<const Variable *> &
operands,
256 ::llvm::IRBuilder<> & builder)
261 return builder.CreateFreeze(operand);
267 const std::vector<const Variable *> & args,
268 ::llvm::IRBuilder<> & builder)
270 auto function =
Context_->value(args[0]);
271 auto & llvmContext =
Context_->llvm_module().getContext();
272 auto & typeConverter =
Context_->GetTypeConverter();
274 std::vector<::llvm::Value *>
operands;
275 for (
size_t n = 1; n < args.size(); n++)
277 auto argument = args[n];
279 if (rvsdg::is<IOStateType>(argument->type()))
281 if (rvsdg::is<MemoryStateType>(argument->type()))
284 if (rvsdg::is<VariableArgumentType>(argument->type()))
286 JLM_ASSERT(is<ThreeAddressCodeVariable>(argument));
288 JLM_ASSERT(is<VariadicArgumentListOperation>(valist->operation()));
289 for (
size_t n = 0; n < valist->noperands(); n++)
297 auto ftype = typeConverter.ConvertFunctionType(*op.
GetFunctionType(), llvmContext);
298 auto callInstruction = builder.CreateCall(ftype,
function,
operands);
301 return callInstruction;
307 for (
const auto & pair : op)
309 if (pair.first != pair.second)
319 const std::vector<const Variable *> & args,
320 ::llvm::IRBuilder<> & builder)
328 if (mop->nalternatives() == 2 && mop->nbits() == 1)
330 auto i1 = ::llvm::IntegerType::get(builder.getContext(), 1);
331 auto t = ::llvm::ConstantInt::getFalse(i1);
332 auto f = ::llvm::ConstantInt::getTrue(i1);
333 return builder.CreateSelect(
Context_->value(args[0]), t, f);
343 const std::vector<const Variable *> &,
344 ::llvm::IRBuilder<> &)
353 const std::vector<const Variable *> &,
354 ::llvm::IRBuilder<> & builder)
356 auto & phi = *util::assertedCast<const SsaPhiOperation>(&op);
357 auto & llvmContext =
Context_->llvm_module().getContext();
358 auto & typeConverter =
Context_->GetTypeConverter();
360 if (rvsdg::is<IOStateType>(phi.Type()))
362 if (rvsdg::is<MemoryStateType>(phi.Type()))
365 auto t = typeConverter.ConvertJlmType(*phi.Type(), llvmContext);
375 ::llvm::IRBuilder<> & builder)
377 auto & llvmContext =
Context_->llvm_module().getContext();
378 auto & typeConverter =
Context_->GetTypeConverter();
380 auto type = typeConverter.ConvertJlmType(loadedType, llvmContext);
381 auto loadInstruction = builder.CreateLoad(type,
Context_->value(address), isVolatile);
382 loadInstruction->setAlignment(::llvm::Align(alignment));
383 return loadInstruction;
389 const std::vector<const Variable *> &
operands,
390 ::llvm::IRBuilder<> & builder)
403 const std::vector<const Variable *> &
operands,
404 ::llvm::IRBuilder<> & builder)
420 ::llvm::IRBuilder<> & builder)
422 auto storeInstruction =
423 builder.CreateStore(
Context_->value(value),
Context_->value(address), isVolatile);
424 storeInstruction->setAlignment(::llvm::Align(alignment));
430 const std::vector<const Variable *> &
operands,
431 ::llvm::IRBuilder<> & builder)
433 auto storeOperation = util::assertedCast<const StoreNonVolatileOperation>(&operation);
441 const std::vector<const Variable *> &
operands,
442 ::llvm::IRBuilder<> & builder)
451 const std::vector<const Variable *> & args,
452 ::llvm::IRBuilder<> & builder)
456 auto & llvmContext =
Context_->llvm_module().getContext();
457 auto & typeConverter =
Context_->GetTypeConverter();
459 auto t = typeConverter.ConvertJlmType(*aop.allocatedType(), llvmContext);
460 auto i = builder.CreateAlloca(t,
Context_->value(args[0]));
461 i->setAlignment(::llvm::Align(aop.alignment()));
468 const std::vector<const Variable *> & args,
469 ::llvm::IRBuilder<> & builder)
471 JLM_ASSERT(is<GetElementPtrOperation>(op) && args.size() >= 2);
473 auto & llvmContext =
Context_->llvm_module().getContext();
474 auto & typeConverter =
Context_->GetTypeConverter();
476 std::vector<::llvm::Value *> indices;
477 auto t = typeConverter.ConvertJlmType(pop.getPointeeType(), llvmContext);
478 for (
size_t n = 1; n < args.size(); n++)
479 indices.push_back(
Context_->value(args[n]));
481 return builder.CreateGEP(t,
Context_->value(args[0]), indices);
489 for (
size_t n = 0; n < args.size(); n++)
491 auto c = ::llvm::dyn_cast<const ::llvm::ConstantInt>(
Context_->value(args[n]));
493 data.push_back(c->getZExtValue());
504 for (
size_t n = 0; n < args.size(); n++)
506 auto c = ::llvm::dyn_cast<const ::llvm::ConstantFP>(
Context_->value(args[n]));
508 data.push_back(c->getValueAPF().bitcastToAPInt().getZExtValue());
517 const std::vector<const Variable *> &
operands,
518 ::llvm::IRBuilder<> & builder)
524 if (bt->nbits() == 8)
526 auto data = get_bitdata<uint8_t>(
operands);
527 return ::llvm::ConstantDataArray::get(builder.getContext(), data);
529 else if (bt->nbits() == 16)
531 auto data = get_bitdata<uint16_t>(
operands);
532 return ::llvm::ConstantDataArray::get(builder.getContext(), data);
534 else if (bt->nbits() == 32)
536 auto data = get_bitdata<uint32_t>(
operands);
537 return ::llvm::ConstantDataArray::get(builder.getContext(), data);
539 else if (bt->nbits() == 64)
541 auto data = get_bitdata<uint64_t>(
operands);
542 return ::llvm::ConstantDataArray::get(builder.getContext(), data);
550 auto data = get_fpdata<uint16_t>(
operands);
551 auto type = ::llvm::Type::getBFloatTy(builder.getContext());
552 return ::llvm::ConstantDataArray::getFP(type, data);
556 auto data = get_fpdata<uint32_t>(
operands);
557 auto type = ::llvm::Type::getFloatTy(builder.getContext());
558 return ::llvm::ConstantDataArray::getFP(type, data);
562 auto data = get_fpdata<uint64_t>(
operands);
563 auto type = ::llvm::Type::getDoubleTy(builder.getContext());
564 return ::llvm::ConstantDataArray::getFP(type, data);
574 const std::vector<const Variable *> &
operands,
575 ::llvm::IRBuilder<> &)
577 ::llvm::LLVMContext & llvmContext =
Context_->llvm_module().getContext();
578 auto & typeConverter =
Context_->GetTypeConverter();
580 std::vector<::llvm::Constant *> data;
581 for (
size_t n = 0; n <
operands.size(); n++)
588 auto at = std::dynamic_pointer_cast<const ArrayType>(op.
result(0));
589 auto type = typeConverter.ConvertArrayType(*at, llvmContext);
590 return ::llvm::ConstantArray::get(type, data);
596 const std::vector<const Variable *> &,
597 ::llvm::IRBuilder<> &)
599 ::llvm::LLVMContext & llvmContext =
Context_->llvm_module().getContext();
600 auto & typeConverter =
Context_->GetTypeConverter();
602 auto type = typeConverter.ConvertJlmType(*op.
result(0), llvmContext);
603 return ::llvm::ConstantAggregateZero::get(type);
609 const std::vector<const Variable *> & args,
610 ::llvm::IRBuilder<> & builder)
616 const auto op1 =
Context_->value(args[0]);
617 const auto op2 =
Context_->value(args[1]);
618 return builder.CreateICmp(predicate, op1, op2);
624 const std::vector<const Variable *> & args,
625 ::llvm::IRBuilder<> & builder)
630 static std::unordered_map<llvm::fpcmp, ::llvm::CmpInst::Predicate> map(
648 auto op1 =
Context_->value(args[0]);
649 auto op2 =
Context_->value(args[1]);
651 return builder.CreateFCmp(map[
fpcmp.cmp()], op1, op2);
657 const std::vector<const Variable *> & args,
658 ::llvm::IRBuilder<> & builder)
663 static std::unordered_map<llvm::fpop, ::llvm::Instruction::BinaryOps> map(
664 { {
fpop::add, ::llvm::Instruction::FAdd },
665 {
fpop::sub, ::llvm::Instruction::FSub },
666 {
fpop::mul, ::llvm::Instruction::FMul },
667 {
fpop::div, ::llvm::Instruction::FDiv },
668 {
fpop::mod, ::llvm::Instruction::FRem } });
670 auto op1 =
Context_->value(args[0]);
671 auto op2 =
Context_->value(args[1]);
672 JLM_ASSERT(map.find(fpbin.fpop()) != map.end());
673 return builder.CreateBinOp(map[fpbin.fpop()], op1, op2);
679 const std::vector<const Variable *> & args,
680 ::llvm::IRBuilder<> & builder)
683 auto operand =
Context_->value(args[0]);
684 return builder.CreateUnOp(::llvm::Instruction::FNeg, operand);
690 const std::vector<const Variable *> &,
691 ::llvm::IRBuilder<> &)
693 JLM_ASSERT(is<VariadicArgumentListOperation>(op));
700 const std::vector<const Variable *> & args,
701 ::llvm::IRBuilder<> &)
703 ::llvm::LLVMContext & llvmContext =
Context_->llvm_module().getContext();
704 auto & typeConverter =
Context_->GetTypeConverter();
706 std::vector<::llvm::Constant *>
operands;
707 for (
const auto & arg : args)
710 auto t = typeConverter.ConvertStructType(op.
type(), llvmContext);
711 return ::llvm::ConstantStruct::get(t,
operands);
717 const std::vector<const Variable *> &,
718 ::llvm::IRBuilder<> &)
720 ::llvm::LLVMContext & llvmContext =
Context_->llvm_module().getContext();
721 auto & typeConverter =
Context_->GetTypeConverter();
723 auto pointerType = typeConverter.ConvertPointerType(operation.
GetPointerType(), llvmContext);
724 return ::llvm::ConstantPointerNull::get(pointerType);
730 const std::vector<const Variable *> &
operands,
731 ::llvm::IRBuilder<> & builder)
733 auto & select = *util::assertedCast<const SelectOperation>(&op);
741 return builder.CreateSelect(c, t, f);
747 const std::vector<const Variable *> & args,
748 ::llvm::IRBuilder<> &)
757 const std::vector<const Variable *> &
operands,
758 ::llvm::IRBuilder<> &)
762 std::vector<::llvm::Constant *> ops;
763 for (
const auto & operand :
operands)
764 ops.push_back(::llvm::cast<::llvm::Constant>(
Context_->value(operand)));
766 return ::llvm::ConstantVector::get(ops);
772 const std::vector<const Variable *> &
operands,
773 ::llvm::IRBuilder<> & builder)
775 JLM_ASSERT(is<ConstantDataVectorOperation>(op));
780 if (bt->nbits() == 8)
782 auto data = get_bitdata<uint8_t>(
operands);
783 return ::llvm::ConstantDataVector::get(builder.getContext(), data);
785 else if (bt->nbits() == 16)
787 auto data = get_bitdata<uint16_t>(
operands);
788 return ::llvm::ConstantDataVector::get(builder.getContext(), data);
790 else if (bt->nbits() == 32)
792 auto data = get_bitdata<uint32_t>(
operands);
793 return ::llvm::ConstantDataVector::get(builder.getContext(), data);
795 else if (bt->nbits() == 64)
797 auto data = get_bitdata<uint64_t>(
operands);
798 return ::llvm::ConstantDataVector::get(builder.getContext(), data);
806 auto data = get_fpdata<uint16_t>(
operands);
807 auto type = ::llvm::Type::getBFloatTy(builder.getContext());
808 return ::llvm::ConstantDataVector::getFP(type, data);
812 auto data = get_fpdata<uint32_t>(
operands);
813 auto type = ::llvm::Type::getFloatTy(builder.getContext());
814 return ::llvm::ConstantDataVector::getFP(type, data);
818 auto data = get_fpdata<uint64_t>(
operands);
819 auto type = ::llvm::Type::getDoubleTy(builder.getContext());
820 return ::llvm::ConstantDataVector::getFP(type, data);
830 const std::vector<const Variable *> & args,
831 ::llvm::IRBuilder<> & builder)
834 return builder.CreateExtractElement(
Context_->value(args[0]),
Context_->value(args[1]));
840 const std::vector<const Variable *> &
operands,
841 ::llvm::IRBuilder<> & builder)
845 return builder.CreateShuffleVector(v1, v2, op.
Mask());
851 const std::vector<const Variable *> &
operands,
852 ::llvm::IRBuilder<> & builder)
859 return builder.CreateInsertElement(vector, value, index);
866 const std::vector<const Variable *> &
operands,
867 ::llvm::IRBuilder<> & builder)
878 const std::vector<const Variable *> &
operands,
879 ::llvm::IRBuilder<> & builder)
889 const std::vector<const Variable *> &
operands,
890 ::llvm::IRBuilder<> & builder)
895 return builder.CreateSelect(c, t, f);
898 template<::llvm::Instruction::CastOps OPCODE>
903 const std::vector<const Variable *> &
operands,
904 ::llvm::IRBuilder<> & builder)
906 JLM_ASSERT(::llvm::Instruction::isCast(OPCODE));
907 auto & typeConverter =
Context_->GetTypeConverter();
908 ::llvm::LLVMContext & llvmContext =
Context_->llvm_module().getContext();
909 auto dsttype = originalOp.
result(0);
912 auto type = typeConverter.ConvertJlmType(*dsttype, llvmContext);
913 return builder.CreateCast(OPCODE,
Context_->value(operand), type);
919 const std::vector<const Variable *> &
operands,
920 ::llvm::IRBuilder<> & builder)
922 std::vector<unsigned> indices(op.
begin(), op.
end());
929 const std::vector<const Variable *> &
operands,
930 ::llvm::IRBuilder<> & builder)
const
935 return builder.CreateInsertValue(aggregateOperand, valueOperand, operation.
getIndices());
941 const std::vector<const Variable *> & args,
942 ::llvm::IRBuilder<> & builder)
945 auto & typeConverter =
Context_->GetTypeConverter();
946 auto & llvmModule =
Context_->llvm_module();
949 typeConverter.ConvertFunctionType(op.
getFunctionType(), llvmModule.getContext());
950 auto function = llvmModule.getOrInsertFunction(
"malloc", functionType);
952 return builder.CreateCall(
function,
operands);
958 const std::vector<const Variable *> & args,
959 ::llvm::IRBuilder<> & builder)
961 auto & typeConverter =
Context_->GetTypeConverter();
962 auto & llvmmod =
Context_->llvm_module();
964 auto fcttype = typeConverter.ConvertFunctionType(
966 llvmmod.getContext());
967 auto function = llvmmod.getOrInsertFunction(
"free", fcttype);
969 return builder.CreateCall(
function,
operands);
975 const std::vector<const Variable *> &
operands,
976 ::llvm::IRBuilder<> & builder)
982 return builder.CreateMemCpy(
984 ::llvm::MaybeAlign(),
986 ::llvm::MaybeAlign(),
994 const std::vector<const Variable *> &
operands,
995 ::llvm::IRBuilder<> & builder)
1001 return builder.CreateMemCpy(
1003 ::llvm::MaybeAlign(),
1005 ::llvm::MaybeAlign(),
1013 const std::vector<const Variable *> &
operands,
1014 ::llvm::IRBuilder<> & builder)
1020 return builder.CreateMemSet(destination, value, length, ::llvm::MaybeAlign());
1026 const std::vector<const Variable *> &,
1027 ::llvm::IRBuilder<> &)
1035 const std::vector<const Variable *> &,
1036 ::llvm::IRBuilder<> &)
1044 const std::vector<const Variable *> &,
1045 ::llvm::IRBuilder<> &)
1053 const std::vector<const Variable *> &,
1054 ::llvm::IRBuilder<> &)
1062 const std::vector<const Variable *> &,
1063 ::llvm::IRBuilder<> &)
1071 const std::vector<const Variable *> &,
1072 ::llvm::IRBuilder<> &)
1080 const std::vector<const Variable *> &
operands,
1081 ::llvm::IRBuilder<> &)
1089 const std::vector<const Variable *> &
operands,
1090 ::llvm::IRBuilder<> &)
1099 const std::vector<const Variable *> &
operands,
1100 ::llvm::IRBuilder<> & builder)
1110 const std::vector<const Variable *> & arguments,
1111 ::llvm::IRBuilder<> & builder)
1113 if (is<IntegerAddOperation>(op))
1117 if (is<IntegerAndOperation>(op))
1121 if (is<IntegerAShrOperation>(op))
1125 if (is<IntegerSubOperation>(op))
1129 if (is<IntegerUDivOperation>(op))
1133 if (is<IntegerSDivOperation>(op))
1137 if (is<IntegerURemOperation>(op))
1141 if (is<IntegerSRemOperation>(op))
1145 if (is<IntegerShlOperation>(op))
1149 if (is<IntegerLShrOperation>(op))
1153 if (is<IntegerOrOperation>(op))
1157 if (is<IntegerXorOperation>(op))
1161 if (is<IntegerMulOperation>(op))
1165 if (is<IntegerEqOperation>(op))
1169 if (is<IntegerNeOperation>(op))
1173 if (is<IntegerUgtOperation>(op))
1177 if (is<IntegerUgeOperation>(op))
1181 if (is<IntegerUltOperation>(op))
1185 if (is<IntegerUleOperation>(op))
1189 if (is<IntegerSgtOperation>(op))
1193 if (is<IntegerSgeOperation>(op))
1197 if (is<IntegerSltOperation>(op))
1201 if (is<IntegerSleOperation>(op))
1205 if (is<IOBarrierOperation>(op))
1207 return Context_->value(arguments[0]);
1209 if (is<IntegerConstantOperation>(op))
1213 if (is<rvsdg::ControlConstantOperation>(op))
1217 if (is<ConstantFP>(op))
1219 return convert<ConstantFP>(op, arguments, builder);
1221 if (is<UndefValueOperation>(op))
1225 if (is<PoisonValueOperation>(op))
1227 return convert<PoisonValueOperation>(op, arguments, builder);
1229 if (is<FreezeOperation>(op))
1231 return convert<FreezeOperation>(op, arguments, builder);
1233 if (is<rvsdg::MatchOperation>(op))
1237 if (is<AssignmentOperation>(op))
1241 if (is<BranchOperation>(op))
1245 if (is<SsaPhiOperation>(op))
1249 if (is<LoadNonVolatileOperation>(op))
1251 return convert<LoadNonVolatileOperation>(op, arguments, builder);
1253 if (is<LoadVolatileOperation>(op))
1255 return convert<LoadVolatileOperation>(op, arguments, builder);
1257 if (is<StoreNonVolatileOperation>(op))
1261 if (is<StoreVolatileOperation>(op))
1263 return convert<StoreVolatileOperation>(op, arguments, builder);
1265 if (is<AllocaOperation>(op))
1269 if (is<GetElementPtrOperation>(op))
1273 if (is<ConstantDataArray>(op))
1275 return convert<ConstantDataArray>(op, arguments, builder);
1277 if (is<PtrCmpOperation>(op))
1281 if (is<FCmpOperation>(op))
1285 if (is<FBinaryOperation>(op))
1289 if (is<VariadicArgumentListOperation>(op))
1293 if (is<ConstantStruct>(op))
1295 return convert<ConstantStruct>(op, arguments, builder);
1297 if (is<ConstantPointerNullOperation>(op))
1299 return convert<ConstantPointerNullOperation>(op, arguments, builder);
1301 if (is<SelectOperation>(op))
1305 if (is<ConstantArrayOperation>(op))
1307 return convert<ConstantArrayOperation>(op, arguments, builder);
1309 if (is<ConstantAggregateZeroOperation>(op))
1311 return convert<ConstantAggregateZeroOperation>(op, arguments, builder);
1313 if (is<ControlToIntOperation>(op))
1317 if (is<ConstantVectorOperation>(op))
1321 if (is<ConstantDataVectorOperation>(op))
1325 if (is<ExtractElementOperation>(op))
1329 if (is<ShuffleVectorOperation>(op))
1331 return convert<ShuffleVectorOperation>(op, arguments, builder);
1333 if (is<InsertElementOperation>(op))
1337 if (is<VectorUnaryOperation>(op))
1341 if (is<VectorBinaryOperation>(op))
1345 if (is<VectorSelectOperation>(op))
1347 return convert<VectorSelectOperation>(op, arguments, builder);
1349 if (is<ExtractValueOperation>(op))
1351 return convert<ExtractValueOperation>(op, arguments, builder);
1357 if (is<CallOperation>(op))
1359 return convert<CallOperation>(op, arguments, builder);
1361 if (is<MallocOperation>(op))
1363 return convert<MallocOperation>(op, arguments, builder);
1365 if (is<FreeOperation>(op))
1367 return convert<FreeOperation>(op, arguments, builder);
1369 if (is<MemCpyNonVolatileOperation>(op))
1371 return convert<MemCpyNonVolatileOperation>(op, arguments, builder);
1373 if (is<MemCpyVolatileOperation>(op))
1375 return convert<MemCpyVolatileOperation>(op, arguments, builder);
1377 if (is<MemSetNonVolatileOperation>(op))
1381 if (is<FNegOperation>(op))
1385 if (is<BitCastOperation>(op))
1387 return convert_cast<::llvm::Instruction::BitCast>(op, originalOp, arguments, builder);
1389 if (is<FPExtOperation>(op))
1391 return convert_cast<::llvm::Instruction::FPExt>(op, originalOp, arguments, builder);
1393 if (is<FloatingPointToSignedIntegerOperation>(op))
1395 return convert_cast<::llvm::Instruction::FPToSI>(op, originalOp, arguments, builder);
1397 if (is<FloatingPointToUnsignedIntegerOperation>(op))
1399 return convert_cast<::llvm::Instruction::FPToUI>(op, originalOp, arguments, builder);
1401 if (is<FPTruncOperation>(op))
1403 return convert_cast<::llvm::Instruction::FPTrunc>(op, originalOp, arguments, builder);
1405 if (is<IntegerToPointerOperation>(op))
1407 return convert_cast<::llvm::Instruction::IntToPtr>(op, originalOp, arguments, builder);
1409 if (is<PtrToIntOperation>(op))
1411 return convert_cast<::llvm::Instruction::PtrToInt>(op, originalOp, arguments, builder);
1413 if (is<SExtOperation>(op))
1415 return convert_cast<::llvm::Instruction::SExt>(op, originalOp, arguments, builder);
1417 if (is<SIToFPOperation>(op))
1419 return convert_cast<::llvm::Instruction::SIToFP>(op, originalOp, arguments, builder);
1421 if (is<TruncOperation>(op))
1423 return convert_cast<::llvm::Instruction::Trunc>(op, originalOp, arguments, builder);
1425 if (is<UIToFPOperation>(op))
1427 return convert_cast<::llvm::Instruction::UIToFP>(op, originalOp, arguments, builder);
1429 if (is<ZExtOperation>(op))
1431 return convert_cast<::llvm::Instruction::ZExt>(op, originalOp, arguments, builder);
1433 if (is<MemoryStateMergeOperation>(op))
1435 return convert<MemoryStateMergeOperation>(op, arguments, builder);
1437 if (is<MemoryStateJoinOperation>(op))
1443 if (is<MemoryStateSplitOperation>(op))
1445 return convert<MemoryStateSplitOperation>(op, arguments, builder);
1447 if (is<LambdaEntryMemoryStateSplitOperation>(op))
1449 return convert<LambdaEntryMemoryStateSplitOperation>(op, arguments, builder);
1451 if (is<LambdaExitMemoryStateMergeOperation>(op))
1453 return convert<LambdaExitMemoryStateMergeOperation>(op, arguments, builder);
1455 if (is<CallEntryMemoryStateMergeOperation>(op))
1457 return convert<CallEntryMemoryStateMergeOperation>(op, arguments, builder);
1459 if (is<CallExitMemoryStateSplitOperation>(op))
1461 return convert<CallExitMemoryStateSplitOperation>(op, arguments, builder);
1463 if (is<PointerToFunctionOperation>(op))
1465 return convert<PointerToFunctionOperation>(op, arguments, builder);
1467 if (is<FunctionToPointerOperation>(op))
1469 return convert<FunctionToPointerOperation>(op, arguments, builder);
1471 if (is<FMulAddIntrinsicOperation>(op))
1473 auto multiplier =
Context_->value(arguments[0]);
1474 auto multiplicand =
Context_->value(arguments[1]);
1475 auto summand =
Context_->value(arguments[2]);
1478 Context_->GetTypeConverter().ConvertJlmType(arguments[0]->type(), builder.getContext());
1479 return builder.CreateIntrinsic(
1480 ::llvm::Intrinsic::fmuladd,
1482 { multiplier, multiplicand, summand });
1493 std::vector<const Variable *>
operands;
1494 for (
size_t n = 0; n < tac.
noperands(); n++)
1497 ::llvm::IRBuilder<> builder(
Context_->basic_block(node));
1507 ::llvm::IRBuilder<> builder(
Context_->llvm_module().getContext());
1508 for (
const auto & tac : tacs)
1510 std::vector<const Variable *>
operands;
1511 for (
size_t n = 0; n < tac->noperands(); n++)
1512 operands.push_back(tac->operand(n));
1515 const auto & op = tac->operation();
1517 Context_->insert(tac->result(0), r);
1532 for (
size_t n = 0; n < cfg.
exit()->nresults(); n++)
1547 ::llvm::IRBuilder<> builder(
Context_->basic_block(node));
1548 auto & cfg = node->
cfg();
1553 builder.CreateRetVoid();
1559 builder.CreateRet(
Context_->value(result));
1567 ::llvm::IRBuilder<> builder(
Context_->basic_block(node));
1570 builder.CreateBr(
Context_->basic_block(target));
1579 ::llvm::IRBuilder<> builder(
Context_->basic_block(node));
1581 auto branch =
static_cast<const BasicBlock *
>(node)->tacs().
last();
1582 JLM_ASSERT(branch && is<BranchOperation>(branch));
1585 auto condition =
Context_->value(branch->operand(0));
1588 builder.CreateCondBr(condition, bbtrue, bbfalse);
1595 ::llvm::LLVMContext & llvmContext =
Context_->llvm_module().getContext();
1596 auto & typeConverter =
Context_->GetTypeConverter();
1597 auto bb =
static_cast<const BasicBlock *
>(node);
1598 ::llvm::IRBuilder<> builder(
Context_->basic_block(node));
1600 auto branch = bb->tacs().last();
1601 JLM_ASSERT(branch && is<BranchOperation>(branch));
1602 auto condition =
Context_->value(branch->operand(0));
1605 if (is<rvsdg::MatchOperation>(match))
1607 JLM_ASSERT(match->result(0) == branch->operand(0));
1611 auto sw = builder.CreateSwitch(condition, defbb);
1612 for (
const auto & alt : *mop)
1614 auto & type = *std::static_pointer_cast<const rvsdg::BitType>(mop->argument(0));
1616 ::llvm::ConstantInt::get(typeConverter.ConvertBitType(type, llvmContext), alt.first);
1623 auto sw = builder.CreateSwitch(condition, defbb);
1624 for (
size_t n = 0; n < node->
NumOutEdges() - 1; n++)
1626 auto value = ::llvm::ConstantInt::get(::llvm::Type::getInt32Ty(builder.getContext()), n);
1636 auto & tacs =
static_cast<const BasicBlock *
>(node)->tacs();
1637 auto & cfg = node->
cfg();
1643 if (target == cfg.exit())
1649 auto branch = tacs.last();
1650 JLM_ASSERT(branch && is<BranchOperation>(branch));
1653 if (
Context_->value(branch->operand(0))->getType()->isIntegerTy(1))
1660 ::llvm::Attribute::AttrKind
1663 typedef ::llvm::Attribute::AttrKind ak;
1665 static std::unordered_map<Attribute::kind, ::llvm::Attribute::AttrKind> map(
1774 auto & llvmContext =
Context_->llvm_module().getContext();
1776 return ::llvm::Attribute::get(llvmContext, kind);
1782 auto & llvmContext =
Context_->llvm_module().getContext();
1784 return ::llvm::Attribute::get(llvmContext, kind, attribute.
value());
1790 auto & typeConverter =
Context_->GetTypeConverter();
1791 auto & llvmContext =
Context_->llvm_module().getContext();
1794 auto type = typeConverter.ConvertJlmType(attribute.
type(), llvmContext);
1795 return ::llvm::Attribute::get(llvmContext, kind, type);
1801 auto & llvmContext =
Context_->llvm_module().getContext();
1802 return ::llvm::Attribute::get(llvmContext, attribute.
kind(), attribute.
value());
1808 ::llvm::AttrBuilder builder(
Context_->llvm_module().getContext());
1821 return ::llvm::AttributeSet::get(
Context_->llvm_module().getContext(), builder);
1827 auto & llvmctx =
Context_->llvm_module().getContext();
1834 std::vector<::llvm::AttributeSet> argsets;
1839 for (
size_t n = 0; n < f.
cfg()->entry()->narguments(); n++)
1850 return ::llvm::AttributeList::get(llvmctx, fctset, retset, argsets);
1859 std::vector<::llvm::AttributeSet> parameterAttributes;
1863 return ::llvm::AttributeList::get(
1864 Context_->llvm_module().getContext(),
1865 std::move(functionAttributes),
1866 std::move(returnAttributes),
1867 std::move(parameterAttributes));
1870 std::vector<ControlFlowGraphNode *>
1873 ::llvm::Function &
function)
1877 uint64_t basicBlockCounter = 0;
1878 for (
const auto & node : nodes)
1880 if (node == controlFlowGraph.
entry())
1882 if (node == controlFlowGraph.
exit())
1886 auto * basicBlock = ::llvm::BasicBlock::Create(
function.getContext(), name, &
function);
1887 Context_->insert(node, basicBlock);
1898 auto add_arguments = [&](
const ControlFlowGraph & cfg, ::llvm::Function & f)
1901 for (
auto & llvmarg : f.args())
1904 Context_->insert(jlmarg, &llvmarg);
1912 add_arguments(cfg, f);
1915 for (
const auto & node : nodes)
1917 if (node == cfg.
entry() || node == cfg.
exit())
1921 auto & tacs =
static_cast<const BasicBlock *
>(node)->tacs();
1922 for (
const auto & tac : tacs)
1927 for (
const auto & node : nodes)
1929 if (node == cfg.
entry() || node == cfg.
exit())
1936 for (
const auto & node : nodes)
1938 if (node == cfg.
entry() || node == cfg.
exit())
1942 auto & tacs =
static_cast<const BasicBlock *
>(node)->tacs();
1943 for (
const auto & tac : tacs)
1945 if (!is<SsaPhiOperation>(tac->operation()))
1948 if (rvsdg::is<IOStateType>(tac->result(0)->type()))
1950 if (rvsdg::is<MemoryStateType>(tac->result(0)->type()))
1953 JLM_ASSERT(node->NumInEdges() == tac->noperands());
1955 auto phi = ::llvm::dyn_cast<::llvm::PHINode>(
Context_->value(tac->result(0)));
1956 for (
size_t n = 0; n < tac->noperands(); n++)
1959 Context_->basic_block(op.GetIncomingNode(n)));
1971 auto f = ::llvm::cast<::llvm::Function>(
Context_->value(im.variable(&node)));
1989 auto gv = ::llvm::dyn_cast<::llvm::GlobalVariable>(
Context_->value(jm.variable(&node)));
1990 gv->setInitializer(::llvm::dyn_cast<::llvm::Constant>(
Context_->value(init->value())));
1993 const ::llvm::GlobalValue::LinkageTypes &
1996 static std::unordered_map<llvm::Linkage, ::llvm::GlobalValue::LinkageTypes> map(
1999 ::llvm::GlobalValue::AvailableExternallyLinkage },
2011 return map[linkage];
2017 auto & typeConverter =
Context_->GetTypeConverter();
2019 auto & lm =
Context_->llvm_module();
2022 for (
const auto & node : jm.ipgraph())
2024 auto v = jm.variable(&node);
2026 if (
auto dataNode =
dynamic_cast<const DataNode *
>(&node))
2028 auto type = typeConverter.ConvertJlmType(*dataNode->GetValueType(), lm.getContext());
2031 auto gv = new ::llvm::GlobalVariable(
2034 dataNode->constant(),
2038 gv->setSection(dataNode->Section());
2039 gv->setAlignment(::llvm::Align(dataNode->getAlignment()));
2042 else if (
auto n =
dynamic_cast<const FunctionNode *
>(&node))
2044 auto type = typeConverter.ConvertFunctionType(n->fcttype(), lm.getContext());
2046 auto f = ::llvm::Function::Create(type, linkage, n->name(), &lm);
2050 f->setCallingConv(callingConvention);
2052 f->setAttributes(attributes);
2061 for (
const auto & node : jm.ipgraph())
2063 if (
auto n =
dynamic_cast<const DataNode *
>(&node))
2067 else if (
auto n =
dynamic_cast<const FunctionNode *
>(&node))
2076 std::unique_ptr<::llvm::Module>
2079 ::llvm::LLVMContext & llvmContext)
2081 std::unique_ptr<::llvm::Module> llvmModule(new ::llvm::Module(
"module", llvmContext));
2084 llvmModule->setDataLayout(ipGraphModule.
data_layout());
2092 std::unique_ptr<::llvm::Module>
2095 ::llvm::LLVMContext & ctx)
const AttributeSet & getReturnAttributes() const noexcept
const AttributeSet & getFunctionAttributes() const noexcept
const std::vector< AttributeSet > & getParameterAttributes() const noexcept
EnumAttributeRange EnumAttributes() const
StringAttributeRange StringAttributes() const
TypeAttributeRange TypeAttributes() const
IntAttributeRange IntAttributes() const
@ None
No attributes have been set.
@ EndAttrKinds
Sentinel value useful for loops.
@ SpeculativeLoadHardening
@ CoroDestroyOnlyWhenComplete
@ DisableSanitizerInstrumentation
ThreeAddressCode * last() const noexcept
CallingConvention getCallingConvention() const noexcept
const std::shared_ptr< const rvsdg::FunctionType > & GetFunctionType() const noexcept
const AttributeList & getAttributes() const noexcept
const jlm::rvsdg::Type & type() const noexcept
const ::llvm::APFloat & constant() const noexcept
ConstantPointerNullOperation class.
const PointerType & GetPointerType() const noexcept
const StructType & type() const noexcept
ControlFlowGraphNode * sink() const noexcept
ControlFlowGraphEdge * OutEdge(size_t n) const
ControlFlowGraph & cfg() const noexcept
size_t NumOutEdges() const noexcept
EntryNode * entry() const noexcept
ExitNode * exit() const noexcept
const DataNodeInit * initialization() const noexcept
const llvm::Argument * argument(size_t index) const
const Attribute::kind & kind() const noexcept
const Variable * result(size_t index) const
const AttributeSet & attributes() const noexcept
llvm::ControlFlowGraph * cfg() const noexcept
Get address of compiled function object.
const std::vector< unsigned > & getIndices() const noexcept
uint64_t value() const noexcept
const jlm::util::FilePath & source_filename() const noexcept
const std::string & target_triple() const noexcept
const std::string & data_layout() const noexcept
InterProceduralGraphModule & IpGraphModule_
void insert(const llvm::ControlFlowGraphNode *node, ::llvm::BasicBlock *bb)
TypeConverter & GetTypeConverter()
std::unordered_map< const ControlFlowGraphNode *, ::llvm::BasicBlock * >::const_iterator const_iterator
const_iterator begin() const
void insert(const llvm::Variable *variable, ::llvm::Value *value)
InterProceduralGraphModule & module() const noexcept
const_iterator end() const
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
Context(const Context &)=delete
static std::unique_ptr< Context > Create(InterProceduralGraphModule &ipGraphModule, ::llvm::Module &llvmModule)
::llvm::Module & LlvmModule_
Context(Context &&)=delete
::llvm::BasicBlock * basic_block(const llvm::ControlFlowGraphNode *node) const noexcept
TypeConverter TypeConverter_
Context & operator=(const Context &)=delete
Context & operator=(Context &&)=delete
::llvm::Module & llvm_module() const noexcept
::llvm::AttributeList convertAttributeList(const AttributeList &attributeList)
::llvm::Value * convertInsertValueOperation(const InsertValueOperation &operation, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder) const
::llvm::Value * convert_select(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_branch(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &)
void convert_instruction(const llvm::ThreeAddressCode &tac, const llvm::ControlFlowGraphNode *node)
::llvm::Value * convert_constantdatavector(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_store(const rvsdg::SimpleOperation &operation, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * convertMemsetNonVolatileOperation(const rvsdg::SimpleOperation &, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &)
::llvm::Value * convert_fpbin(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
void convert_tacs(const tacsvector_t &tacs)
void create_switch(const ControlFlowGraphNode *node)
::llvm::Attribute::AttrKind ConvertAttributeKind(const Attribute::kind &kind)
const ::llvm::GlobalValue::LinkageTypes & convert_linkage(const llvm::Linkage &linkage)
::llvm::Value * CreateICmpInstruction(const ::llvm::CmpInst::Predicate predicate, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Attribute ConvertStringAttribute(const llvm::StringAttribute &attribute)
::llvm::Value * convert_match(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_fpneg(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_valist(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &)
void CreateStoreInstruction(const Variable *address, const Variable *value, bool isVolatile, size_t alignment, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_insertelement(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * CreateBinOpInstruction(const ::llvm::Instruction::BinaryOps opcode, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
void create_terminator_instruction(const llvm::ControlFlowGraphNode *node)
~IpGraphToLlvmConverter() noexcept
::llvm::Value * convert_ptrcmp(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_alloca(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_constantvector(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &)
::llvm::Value * convert_vectorunary(const rvsdg::SimpleOperation &op, const rvsdg::SimpleOperation &originalOp, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
std::vector< ControlFlowGraphNode * > ConvertBasicBlocks(const ControlFlowGraph &controlFlowGraph, ::llvm::Function &function)
::llvm::Value * CreateLoadInstruction(const rvsdg::Type &loadedType, const Variable *address, bool isVolatile, size_t alignment, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_ctl2bits(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &)
::llvm::Value * convert_ctlconstant(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_cast(const rvsdg::SimpleOperation &op, const rvsdg::SimpleOperation &originalOp, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_fpcmp(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * ConverterIntegerConstant(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &builder)
void convert_function(const FunctionNode &node)
::llvm::Value * convert_extractelement(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_assignment(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &)
::llvm::Value * convert_operation(const rvsdg::SimpleOperation &op, const rvsdg::SimpleOperation &originalOp, const std::vector< const Variable * > &arguments, ::llvm::IRBuilder<> &builder)
std::unique_ptr<::llvm::Module > ConvertModule(InterProceduralGraphModule &ipGraphModule, ::llvm::LLVMContext &llvmContext)
void create_return(const ControlFlowGraphNode *node)
::llvm::Value * convert_phi(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_vectorbinary(const rvsdg::SimpleOperation &op, const rvsdg::SimpleOperation &originalOp, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
::llvm::Attribute ConvertTypeAttribute(const llvm::TypeAttribute &attribute)
void create_unconditional_branch(const ControlFlowGraphNode *node)
::llvm::Value * convert_getelementptr(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &args, ::llvm::IRBuilder<> &builder)
::llvm::Value * convert_undef(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &, ::llvm::IRBuilder<> &)
::llvm::AttributeList convert_attributes(const FunctionNode &f)
static std::unique_ptr<::llvm::Module > CreateAndConvertModule(InterProceduralGraphModule &ipGraphModule, ::llvm::LLVMContext &ctx)
void create_conditional_branch(const ControlFlowGraphNode *node)
::llvm::Attribute ConvertEnumAttribute(const llvm::EnumAttribute &attribute)
void convert_cfg(ControlFlowGraph &cfg, ::llvm::Function &f)
std::vector< T > get_fpdata(const std::vector< const Variable * > &args)
::llvm::Attribute ConvertIntAttribute(const llvm::IntAttribute &attribute)
void convert_data_node(const DataNode &node)
::llvm::Value * convert(const rvsdg::SimpleOperation &op, const std::vector< const Variable * > &operands, ::llvm::IRBuilder<> &builder)
std::unique_ptr< Context > Context_
std::vector< T > get_bitdata(const std::vector< const Variable * > &args)
std::shared_ptr< const rvsdg::Type > GetLoadedType() const noexcept
size_t GetAlignment() const noexcept
rvsdg::FunctionType getFunctionType() const
Interpret pointer as callable function.
PoisonValueOperation class.
const jlm::rvsdg::Type & GetType() const noexcept
const ::llvm::ArrayRef< int > Mask() const
size_t GetAlignment() const noexcept
const std::string & value() const noexcept
const std::string & kind() const noexcept
llvm::ThreeAddressCode * tac() const noexcept
const ThreeAddressCodeVariable * result(size_t index) const noexcept
const Variable * operand(size_t index) const noexcept
const rvsdg::SimpleOperation & operation() const noexcept
size_t noperands() const noexcept
const jlm::rvsdg::Type & type() const noexcept
size_t nbits() const noexcept
bool is_defined() const noexcept
const ControlValueRepresentation & value() const noexcept
size_t nalternatives() const noexcept
virtual std::string debug_string() const =0
const std::shared_ptr< const rvsdg::Type > & argument(size_t index) const noexcept
const std::shared_ptr< const rvsdg::Type > & result(size_t index) const noexcept
size_t narguments() const noexcept
const std::string & to_str() const noexcept
#define JLM_UNREACHABLE(msg)
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
std::vector< ControlFlowGraphNode * > breadth_first(const ControlFlowGraph &cfg)
static bool is_identity_mapping(const rvsdg::MatchOperation &op)
::llvm::CallingConv::ID convertCallingConventionToLlvm(jlm::llvm::CallingConvention cc)
@ availableExternallyLinkage
::llvm::APInt convert_bitvalue_repr(const rvsdg::BitValueRepresentation &vr)
void straighten(ControlFlowGraph &cfg)
static bool has_return_value(const ControlFlowGraph &cfg)
::llvm::CmpInst::Predicate convertICmpPredicateToLlvm(ICmpPredicate predicate)
bool is_closed(const ControlFlowGraph &cfg)
@ State
Designate a state type.
@ Value
Designate a value type.
static std::vector< jlm::rvsdg::Output * > operands(const Node *node)
static std::string strfmt(Args... args)