Jlm
Loading...
Searching...
No Matches
MlirToJlmConverter.cpp
Go to the documentation of this file.
1/*
2 * Copyright 2024 Louis Maurin <louis7maurin@gmail.com>
3 * Copyright 2023 Magnus Sjalander <work@sjalander.com>
4 * See COPYING for terms of redistribution.
5 */
6
23#include <jlm/util/common.hpp>
24#include <mlir/Parser/Parser.h>
25#include <mlir/Transforms/TopologicalSortUtils.h>
26
27namespace jlm::mlir
28{
29
30std::unique_ptr<llvm::LlvmRvsdgModule>
32{
33 auto config = ::mlir::ParserConfig(Context_.get());
34 std::unique_ptr<::mlir::Block> block = std::make_unique<::mlir::Block>();
35 auto result = ::mlir::parseSourceFile(filePath.to_str(), block.get(), config);
36 if (result.failed())
37 {
38 JLM_ASSERT("Parsing MLIR input file failed.");
39 }
40 return ConvertMlir(block);
41}
42
43std::unique_ptr<llvm::LlvmRvsdgModule>
44MlirToJlmConverter::ConvertMlir(std::unique_ptr<::mlir::Block> & block)
45{
46 auto & topNode = block->front();
47 if (auto module = ::mlir::dyn_cast<::mlir::ModuleOp>(topNode))
48 {
49 auto & newTopNode = module.getBodyRegion().front().front();
50 auto omegaNode = ::mlir::dyn_cast<::mlir::rvsdg::OmegaNode>(newTopNode);
51 if (!omegaNode)
52 {
53 JLM_UNREACHABLE("frontend : Top node in module op is not an OmegaNode.");
54 }
55 return ConvertOmega(omegaNode);
56 }
57 auto omegaNode = ::mlir::dyn_cast<::mlir::rvsdg::OmegaNode>(topNode);
58 if (!omegaNode)
59 {
60 JLM_UNREACHABLE("frontend : Top node is not an OmegaNode.");
61 }
62 return ConvertOmega(omegaNode);
63}
64
65std::unique_ptr<llvm::LlvmRvsdgModule>
66MlirToJlmConverter::ConvertOmega(::mlir::rvsdg::OmegaNode & omegaNode)
67{
68 auto rvsdgModule =
69 llvm::LlvmRvsdgModule::Create(util::FilePath(""), std::string(), std::string());
70 auto & graph = rvsdgModule->Rvsdg();
71 auto & root = graph.GetRootRegion();
72
73 // Convert all operations in the omega's region.
74 auto resultOutputs = ConvertRegion(omegaNode.getRegion(), root);
75
76 // Get the OmegaResult terminator to extract export names.
77 auto & omegaBlock = omegaNode.getRegion().front();
78 ::mlir::Operation * terminator = omegaBlock.getTerminator();
79 auto omegaResult = ::mlir::dyn_cast<::mlir::rvsdg::OmegaResult>(terminator);
80 JLM_ASSERT(omegaResult != nullptr);
81
82 // Get the exported names from OmegaResult
83 auto exportNames = omegaResult.getExportNames();
84 // All omega results should have an exported name
85 JLM_ASSERT(resultOutputs.size() == exportNames.size());
86
87 // Register OmegaResult outputs as RVSDG root region exports (GraphExport).
88 // The resultOutputs vector is populated by ConvertBlock() which extracts the operands
89 // from the OmegaResult terminator operation.
90 for (size_t i = 0; i < resultOutputs.size(); ++i)
91 {
92 if (auto nameAttr = exportNames[i].dyn_cast_or_null<::mlir::StringAttr>())
93 {
94 rvsdg::GraphExport::Create(*resultOutputs[i], nameAttr.getValue().str());
95 }
96 else
97 {
98 JLM_UNREACHABLE("All omega results should have a name.");
99 }
100 }
101
102 return rvsdgModule;
103}
104
105::llvm::SmallVector<jlm::rvsdg::Output *>
106MlirToJlmConverter::ConvertRegion(::mlir::Region & region, rvsdg::Region & rvsdgRegion)
107{
108 // MLIR use blocks as the innermost "container"
109 // In the RVSDG Dialect a region should contain one and only one block
110 JLM_ASSERT(region.getBlocks().size() == 1);
111 return ConvertBlock(region.front(), rvsdgRegion);
112}
113
114::llvm::SmallVector<jlm::rvsdg::Output *>
116 ::mlir::Operation & mlirOp,
117 const std::unordered_map<void *, rvsdg::Output *> & outputMap)
118{
119 ::llvm::SmallVector<jlm::rvsdg::Output *> inputs;
120 for (::mlir::Value operand : mlirOp.getOperands())
121 {
122 auto key = operand.getAsOpaquePointer();
123 JLM_ASSERT(outputMap.find(key) != outputMap.end());
124 inputs.push_back(outputMap.at(key));
125 }
126 return inputs;
127}
128
129::llvm::SmallVector<jlm::rvsdg::Output *>
130MlirToJlmConverter::ConvertBlock(::mlir::Block & block, rvsdg::Region & rvsdgRegion)
131{
132 ::mlir::sortTopologically(&block);
133
134 // Create an RVSDG node for each MLIR operation and store the mapping from
135 // MLIR values to RVSDG outputs in a hash map for easy lookup
136 std::unordered_map<void *, rvsdg::Output *> outputMap;
137
138 for (size_t i = 0; i < block.getNumArguments(); i++)
139 {
140 auto arg = block.getArgument(i);
141 auto key = arg.getAsOpaquePointer();
142 outputMap[key] = rvsdgRegion.argument(i);
143 }
144
145 for (auto & mlirOp : block.getOperations())
146 {
147 if (auto argument = ::mlir::dyn_cast<::mlir::rvsdg::OmegaArgument>(mlirOp))
148 {
149 auto valueType = argument.getValueType();
150 auto importedType = argument.getImportedValue().getType();
151 auto jlmValueType = ConvertType(valueType);
152 auto jlmImportedType = ConvertType(importedType);
153
154 auto & jlmArgument = jlm::llvm::LlvmGraphImport::create(
155 *rvsdgRegion.graph(),
156 jlmValueType,
157 jlmImportedType,
158 argument.getNameAttr().cast<::mlir::StringAttr>().str(),
159 llvm::linkageFromString(argument.getLinkageAttr().cast<::mlir::StringAttr>().str()),
160 llvm::CallingConvention::Default, // FIXME: Currently not supported in MLIR dialect
161 false, // FIXME: Currently not supported in MLIR dialect
162 1); // FIXME: Currently not supported in MLIR dialect
163
164 auto key = argument.getResult().getAsOpaquePointer();
165 outputMap[key] = &jlmArgument;
166 }
167 else if (::mlir::isa<::mlir::rvsdg::OmegaResult>(mlirOp))
168 {
169 // OmegaResult is handled as the block terminator in ConvertBlock.
170 // Skip it here to avoid processing it as a regular operation.
171 continue;
172 }
173 else
174 {
175 ::llvm::SmallVector<jlm::rvsdg::Output *> inputs = GetConvertedInputs(mlirOp, outputMap);
176
177 auto outputs = ConvertOperation(mlirOp, rvsdgRegion, inputs);
178 JLM_ASSERT(outputs.size() == mlirOp.getNumResults());
179 for (size_t i = 0; i < mlirOp.getNumResults(); i++)
180 {
181 auto result = mlirOp.getResult(i);
182 auto key = result.getAsOpaquePointer();
183 outputMap[key] = outputs[i];
184 }
185 }
186 }
187
188 // The results of the region/block are encoded in the terminator operation
189 ::mlir::Operation * terminator = block.getTerminator();
190
191 return GetConvertedInputs(*terminator, outputMap);
192}
193
196 ::mlir::arith::CmpIOp & CompOp,
197 const ::llvm::SmallVector<rvsdg::Output *> & inputs,
198 size_t nbits)
199{
200 if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::eq)
201 {
202 return &rvsdg::CreateOpNode<jlm::llvm::IntegerEqOperation>({ inputs[0], inputs[1] }, nbits);
203 }
204 else if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::ne)
205 {
206 return &rvsdg::CreateOpNode<jlm::llvm::IntegerNeOperation>({ inputs[0], inputs[1] }, nbits);
207 }
208 else if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::sge)
209 {
210 return &rvsdg::CreateOpNode<jlm::llvm::IntegerSgeOperation>({ inputs[0], inputs[1] }, nbits);
211 }
212 else if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::sgt)
213 {
214 return &rvsdg::CreateOpNode<jlm::llvm::IntegerSgtOperation>({ inputs[0], inputs[1] }, nbits);
215 }
216 else if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::sle)
217 {
218 return &rvsdg::CreateOpNode<jlm::llvm::IntegerSleOperation>({ inputs[0], inputs[1] }, nbits);
219 }
220 else if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::slt)
221 {
222 return &rvsdg::CreateOpNode<jlm::llvm::IntegerSltOperation>({ inputs[0], inputs[1] }, nbits);
223 }
224 else if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::uge)
225 {
226 return &rvsdg::CreateOpNode<jlm::llvm::IntegerUgeOperation>({ inputs[0], inputs[1] }, nbits);
227 }
228 else if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::ugt)
229 {
230 return &rvsdg::CreateOpNode<jlm::llvm::IntegerUgtOperation>({ inputs[0], inputs[1] }, nbits);
231 }
232 else if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::ule)
233 {
234 return &rvsdg::CreateOpNode<jlm::llvm::IntegerUleOperation>({ inputs[0], inputs[1] }, nbits);
235 }
236 else if (CompOp.getPredicate() == ::mlir::arith::CmpIPredicate::ult)
237 {
238 return &rvsdg::CreateOpNode<jlm::llvm::IntegerUltOperation>({ inputs[0], inputs[1] }, nbits);
239 }
240 else
241 {
242 JLM_UNREACHABLE("frontend : Unknown comparison predicate.");
243 }
244}
245
248 ::mlir::LLVM::ICmpOp & operation,
249 rvsdg::Region & rvsdgRegion,
250 const ::llvm::SmallVector<rvsdg::Output *> & inputs)
251{
252 if (operation.getPredicate() == ::mlir::LLVM::ICmpPredicate::eq)
253 {
254 auto newOp = std::make_unique<llvm::PtrCmpOperation>(
258 rvsdgRegion,
259 std::move(newOp),
260 std::vector<jlm::rvsdg::Output *>(inputs.begin(), inputs.end()));
261 }
262 else if (operation.getPredicate() == ::mlir::LLVM::ICmpPredicate::ne)
263 {
264 auto newOp = std::make_unique<llvm::PtrCmpOperation>(
268 rvsdgRegion,
269 std::move(newOp),
270 std::vector<jlm::rvsdg::Output *>(inputs.begin(), inputs.end()));
271 }
272 else if (operation.getPredicate() == ::mlir::LLVM::ICmpPredicate::sge)
273 {
274 auto newOp = std::make_unique<llvm::PtrCmpOperation>(
278 rvsdgRegion,
279 std::move(newOp),
280 std::vector<jlm::rvsdg::Output *>(inputs.begin(), inputs.end()));
281 }
282 else if (operation.getPredicate() == ::mlir::LLVM::ICmpPredicate::sgt)
283 {
284 auto newOp = std::make_unique<llvm::PtrCmpOperation>(
288 rvsdgRegion,
289 std::move(newOp),
290 std::vector<jlm::rvsdg::Output *>(inputs.begin(), inputs.end()));
291 }
292 else if (operation.getPredicate() == ::mlir::LLVM::ICmpPredicate::sle)
293 {
294 auto newOp = std::make_unique<llvm::PtrCmpOperation>(
298 rvsdgRegion,
299 std::move(newOp),
300 std::vector<jlm::rvsdg::Output *>(inputs.begin(), inputs.end()));
301 }
302 else if (operation.getPredicate() == ::mlir::LLVM::ICmpPredicate::slt)
303 {
304 auto newOp = std::make_unique<llvm::PtrCmpOperation>(
308 rvsdgRegion,
309 std::move(newOp),
310 std::vector<jlm::rvsdg::Output *>(inputs.begin(), inputs.end()));
311 }
312 else
313 {
314 JLM_UNREACHABLE("MLIR frontend: Unknown pointer compare operation");
315 }
316}
317
320 const ::mlir::Operation & mlirOperation,
321 const ::llvm::SmallVector<rvsdg::Output *> & inputs)
322{
323 if (inputs.size() != 2)
324 return nullptr;
325 auto op = llvm::fpop::add;
326 auto size = llvm::fpsize::half;
327 if (auto castedOp = ::mlir::dyn_cast<::mlir::arith::AddFOp>(&mlirOperation))
328 {
329 op = llvm::fpop::add;
330 size = ConvertFPSize(castedOp.getType().cast<::mlir::FloatType>().getWidth());
331 }
332 else if (auto castedOp = ::mlir::dyn_cast<::mlir::arith::SubFOp>(&mlirOperation))
333 {
334 op = llvm::fpop::sub;
335 size = ConvertFPSize(castedOp.getType().cast<::mlir::FloatType>().getWidth());
336 }
337 else if (auto castedOp = ::mlir::dyn_cast<::mlir::arith::MulFOp>(&mlirOperation))
338 {
339 op = llvm::fpop::mul;
340 size = ConvertFPSize(castedOp.getType().cast<::mlir::FloatType>().getWidth());
341 }
342 else if (auto castedOp = ::mlir::dyn_cast<::mlir::arith::DivFOp>(&mlirOperation))
343 {
344 op = llvm::fpop::div;
345 size = ConvertFPSize(castedOp.getType().cast<::mlir::FloatType>().getWidth());
346 }
347 else if (auto castedOp = ::mlir::dyn_cast<::mlir::arith::RemFOp>(&mlirOperation))
348 {
349 op = llvm::fpop::mod;
350 size = ConvertFPSize(castedOp.getType().cast<::mlir::FloatType>().getWidth());
351 }
352 else
353 {
354 return nullptr;
355 }
356 return &rvsdg::CreateOpNode<llvm::FBinaryOperation>({ inputs[0], inputs[1] }, op, size);
357}
358
360MlirToJlmConverter::TryConvertFPCMP(const ::mlir::arith::CmpFPredicate & op)
361{
362 const auto & map = GetFpCmpPredicateMap();
363 return map.LookupKey(op);
364}
365
368 ::mlir::Operation & mlirOperation,
369 const ::llvm::SmallVector<rvsdg::Output *> & inputs)
370{
371 if (inputs.size() != 2 || mlirOperation.getNumResults() != 1)
372 return nullptr;
373
374 auto type = mlirOperation.getResult(0).getType();
375
376 size_t width = 0;
377 if (type.isa<::mlir::IntegerType>())
378 {
379 auto integerType = type.cast<::mlir::IntegerType>();
380 width = integerType.getWidth();
381 }
382 else if (type.isIndex())
383 {
385 }
386 else
387 {
388 return nullptr;
389 }
390
391 if (::mlir::isa<::mlir::arith::AddIOp>(mlirOperation))
392 {
393 return &rvsdg::CreateOpNode<jlm::llvm::IntegerAddOperation>({ inputs[0], inputs[1] }, width);
394 }
395 else if (::mlir::isa<::mlir::arith::SubIOp>(mlirOperation))
396 {
397 return &rvsdg::CreateOpNode<jlm::llvm::IntegerSubOperation>({ inputs[0], inputs[1] }, width);
398 }
399 else if (::mlir::isa<::mlir::arith::MulIOp>(mlirOperation))
400 {
401 return &rvsdg::CreateOpNode<jlm::llvm::IntegerMulOperation>({ inputs[0], inputs[1] }, width);
402 }
403 else if (::mlir::isa<::mlir::arith::DivSIOp>(mlirOperation))
404 {
405 return &rvsdg::CreateOpNode<jlm::llvm::IntegerSDivOperation>({ inputs[0], inputs[1] }, width);
406 }
407 else if (::mlir::isa<::mlir::arith::DivUIOp>(mlirOperation))
408 {
409 return &rvsdg::CreateOpNode<jlm::llvm::IntegerUDivOperation>({ inputs[0], inputs[1] }, width);
410 }
411 else if (::mlir::isa<::mlir::arith::RemSIOp>(mlirOperation))
412 {
413 return &rvsdg::CreateOpNode<jlm::llvm::IntegerSRemOperation>({ inputs[0], inputs[1] }, width);
414 }
415 else if (::mlir::isa<::mlir::arith::RemUIOp>(mlirOperation))
416 {
417 return &rvsdg::CreateOpNode<jlm::llvm::IntegerURemOperation>({ inputs[0], inputs[1] }, width);
418 }
419 else if (::mlir::isa<::mlir::LLVM::ShlOp>(mlirOperation))
420 {
421 return &rvsdg::CreateOpNode<jlm::llvm::IntegerShlOperation>({ inputs[0], inputs[1] }, width);
422 }
423 else if (::mlir::isa<::mlir::LLVM::AShrOp>(mlirOperation))
424 {
425 return &rvsdg::CreateOpNode<jlm::llvm::IntegerAShrOperation>({ inputs[0], inputs[1] }, width);
426 }
427 else if (::mlir::isa<::mlir::LLVM::LShrOp>(mlirOperation))
428 {
429 return &rvsdg::CreateOpNode<jlm::llvm::IntegerLShrOperation>({ inputs[0], inputs[1] }, width);
430 }
431 else if (::mlir::isa<::mlir::arith::AndIOp>(mlirOperation))
432 {
433 return &rvsdg::CreateOpNode<jlm::llvm::IntegerAndOperation>({ inputs[0], inputs[1] }, width);
434 }
435 else if (::mlir::isa<::mlir::arith::OrIOp>(mlirOperation))
436 {
437 return &rvsdg::CreateOpNode<jlm::llvm::IntegerOrOperation>({ inputs[0], inputs[1] }, width);
438 }
439 else if (::mlir::isa<::mlir::arith::XOrIOp>(mlirOperation))
440 {
441 return &rvsdg::CreateOpNode<jlm::llvm::IntegerXorOperation>({ inputs[0], inputs[1] }, width);
442 }
443 else
444 {
445 return nullptr;
446 }
447}
448
449static std::vector<llvm::MemoryNodeId>
450arrayAttrToMemoryNodeIds(::mlir::ArrayAttr arrayAttr)
451{
452 std::vector<llvm::MemoryNodeId> memoryNodeIds;
453 for (auto memoryNodeId : arrayAttr)
454 {
455 memoryNodeIds.push_back(memoryNodeId.cast<::mlir::IntegerAttr>().getInt());
456 }
457 return memoryNodeIds;
458}
459
460std::vector<jlm::rvsdg::Output *>
462 ::mlir::Operation & mlirOperation,
463 rvsdg::Region & rvsdgRegion,
464 const ::llvm::SmallVector<rvsdg::Output *> & inputs)
465{
466
467 // ** region Arithmetic Integer Operation **
468 auto convertedBitBinaryNode = ConvertBitBinaryNode(mlirOperation, inputs);
469 // If the operation was converted it means it has been casted to a bit binary operation
470 if (convertedBitBinaryNode)
471 {
472 return rvsdg::outputs(convertedBitBinaryNode);
473 }
474 // ** endregion Arithmetic Integer Operation **
475
476 // ** region Arithmetic Float Operation **
477 auto convertedFloatBinaryNode = ConvertFPBinaryNode(mlirOperation, inputs);
478 // If the operation was converted it means it has been casted to a fp binary operation
479 if (convertedFloatBinaryNode)
480 {
481 return rvsdg::outputs(convertedFloatBinaryNode);
482 }
483
484 if (::mlir::isa<::mlir::LLVM::FMulAddOp>(&mlirOperation))
485 {
486 JLM_ASSERT(inputs.size() == 3);
487 return rvsdg::outputs(
488 &llvm::FMulAddIntrinsicOperation::CreateNode(*inputs[0], *inputs[1], *inputs[2]));
489 }
490 // ** endregion Arithmetic Float Operation **
491
492 if (auto castedOp = ::mlir::dyn_cast<::mlir::arith::ExtUIOp>(&mlirOperation))
493 {
494 auto st = std::dynamic_pointer_cast<const rvsdg::BitType>(inputs[0]->Type());
495 if (!st)
496 JLM_UNREACHABLE("Expected bitstring type for ExtUIOp operation.");
497 ::mlir::Type type = castedOp.getType();
498 return {
499 &llvm::ZExtOperation::create(type.cast<::mlir::IntegerType>().getWidth(), *inputs[0])
500 };
501 }
502 else if (auto castedOp = ::mlir::dyn_cast<::mlir::arith::ExtSIOp>(&mlirOperation))
503 {
504 auto outputType = castedOp.getOut().getType();
505 auto convertedOutputType = ConvertType(outputType);
506 if (!::mlir::isa<::mlir::IntegerType>(castedOp.getType()))
507 JLM_UNREACHABLE("Expected IntegerType for ExtSIOp operation output.");
509 castedOp.getType().cast<::mlir::IntegerType>().getWidth(),
510 *inputs[0]) };
511 }
512 else if (auto sitofpOp = ::mlir::dyn_cast<::mlir::arith::SIToFPOp>(&mlirOperation))
513 {
514 auto st = std::dynamic_pointer_cast<const jlm::rvsdg::BitType>(inputs[0]->Type());
515 if (!st)
516 JLM_UNREACHABLE("Expected bits type for SIToFPOp operation.");
517
518 auto mlirOutputType = sitofpOp.getType();
519 auto rt = ConvertType(mlirOutputType);
520
522 std::vector<jlm::rvsdg::Output *>(inputs.begin(), inputs.end()),
523 std::move(st),
524 std::move(rt)));
525 }
526
527 else if (::mlir::isa<::mlir::rvsdg::OmegaNode>(&mlirOperation))
528 {
529 // Omega doesn't have a corresponding RVSDG node, so we return an empty vector
530 return {};
531 }
532 else if (::mlir::isa<::mlir::rvsdg::LambdaNode>(&mlirOperation))
533 {
534 return rvsdg::outputs(ConvertLambda(mlirOperation, rvsdgRegion, inputs));
535 }
536 else if (auto callOp = ::mlir::dyn_cast<::mlir::jlm::Call>(&mlirOperation))
537 {
538 std::vector<std::shared_ptr<const rvsdg::Type>> argumentTypes;
539 for (auto arg : callOp.getArgs())
540 {
541 auto type = arg.getType();
542 argumentTypes.push_back(ConvertType(type));
543 }
544 argumentTypes.push_back(llvm::IOStateType::Create());
545 argumentTypes.push_back(llvm::MemoryStateType::Create());
546
547 std::vector<std::shared_ptr<const rvsdg::Type>> resultTypes;
548 for (auto res : callOp.getResults())
549 {
550 auto type = res.getType();
551 resultTypes.push_back(ConvertType(type));
552 }
553
554 if (inputs.size() != 1 + argumentTypes.size())
555 throw std::runtime_error("Function call should take target and parameters as input");
556 const auto functionType = rvsdg::FunctionType::Create(argumentTypes, resultTypes);
557
558 const auto target = inputs[0];
559 const auto arguments = std::vector(std::next(inputs.begin()), inputs.end());
561 target,
562 std::move(functionType),
563 llvm::CallingConvention::Default, // FIXME: MLIR dialect does not support calling
564 // conventions
565 llvm::AttributeList::createEmptyList(), // FIXME: MLIR dialect does not support attributes
566 arguments);
567 }
568 else if (auto constant = ::mlir::dyn_cast<::mlir::arith::ConstantIntOp>(&mlirOperation))
569 {
570 auto type = constant.getType();
571 JLM_ASSERT(type.getTypeID() == ::mlir::IntegerType::getTypeID());
572 auto integerType = ::mlir::cast<::mlir::IntegerType>(type);
573
575 rvsdgRegion,
576 integerType.getWidth(),
577 constant.value()));
578 }
579 else if (auto constant = ::mlir::dyn_cast<::mlir::arith::ConstantFloatOp>(&mlirOperation))
580 {
581 auto type = constant.getType();
582 if (!::mlir::isa<::mlir::FloatType>(type))
583 JLM_UNREACHABLE("Expected FloatType for ConstantFloatOp operation.");
584 auto floatType = ::mlir::cast<::mlir::FloatType>(type);
585
586 auto size = ConvertFPSize(floatType.getWidth());
587 return rvsdg::outputs(
588 &rvsdg::CreateOpNode<llvm::ConstantFP>(rvsdgRegion, size, constant.value()));
589 }
590
591 // RVSDG does not have an index type. Indices are therefore converted to integers.
592
593 else if (auto constant = ::mlir::dyn_cast<::mlir::arith::ConstantIndexOp>(&mlirOperation))
594 {
595 auto type = constant.getType();
596 JLM_ASSERT(type.getTypeID() == ::mlir::IndexType::getTypeID());
597
599 rvsdgRegion,
601 constant.value()));
602 }
603 else if (auto indexCast = ::mlir::dyn_cast<::mlir::arith::IndexCastOp>(&mlirOperation))
604 {
605 auto outputType = indexCast.getResult().getType();
606 auto inputType = indexCast.getIn().getType();
607 unsigned inputBits = inputType.getIntOrFloatBitWidth();
608 unsigned outputBits = outputType.getIntOrFloatBitWidth();
609
610 if (inputType.isIndex())
611 {
612 if (outputBits == MlirToJlmConverter::GetIndexBitWidth())
613 {
614 // Nothing is needed to be done so we simply pass on the inputs
615 return { inputs.begin(), inputs.end() };
616 }
617 else if (outputBits > MlirToJlmConverter::GetIndexBitWidth())
618 {
619 return { &llvm::SExtOperation::create(outputBits, *inputs[0]) };
620 }
621 else
622 {
623 return { &llvm::TruncOperation::create(outputBits, *inputs[0]) };
624 }
625 }
626 else
627 {
628 if (inputBits == MlirToJlmConverter::GetIndexBitWidth())
629 {
630 // Nothing to be done as indices are not supported and of default width
631 return { inputs.begin(), inputs.end() };
632 }
633 else if (inputBits > MlirToJlmConverter::GetIndexBitWidth())
634 {
635 return {
637 };
638 }
639 else
640 {
642 }
643 }
644 }
645
646 else if (auto negOp = ::mlir::dyn_cast<::mlir::arith::NegFOp>(&mlirOperation))
647 {
648 auto type = negOp.getResult().getType();
649 auto floatType = ::mlir::cast<::mlir::FloatType>(type);
650
651 llvm::fpsize size = ConvertFPSize(floatType.getWidth());
653 }
654
655 else if (auto extOp = ::mlir::dyn_cast<::mlir::arith::ExtFOp>(&mlirOperation))
656 {
657 auto type = extOp.getResult().getType();
658 auto floatType = ::mlir::cast<::mlir::FloatType>(type);
659
660 llvm::fpsize size = ConvertFPSize(floatType.getWidth());
662 { inputs[0] },
663 inputs[0]->Type(),
665 }
666
667 else if (auto truncOp = ::mlir::dyn_cast<::mlir::arith::TruncIOp>(&mlirOperation))
668 {
669 auto type = truncOp.getResult().getType();
670 auto intType = ::mlir::cast<::mlir::IntegerType>(type);
671 return { &llvm::TruncOperation::create(intType.getIntOrFloatBitWidth(), *inputs[0]) };
672 }
673 else if (auto inttoptrOp = ::mlir::dyn_cast<::mlir::LLVM::IntToPtrOp>(&mlirOperation))
674 {
675 return { llvm::IntToPtrOperation::create(inputs[0]) };
676 }
677 else if (auto constant = ::mlir::dyn_cast<::mlir::arith::ConstantFloatOp>(&mlirOperation))
678 {
679 auto type = constant.getType();
680 auto floatType = ::mlir::cast<::mlir::FloatType>(type);
681
682 llvm::fpsize size = ConvertFPSize(floatType.getWidth());
683 return rvsdg::outputs(&rvsdg::CreateOpNode<jlm::llvm::ConstantFP>({}, size, constant.value()));
684 }
685
686 // Binary Integer Comparision operations
687 else if (auto ComOp = ::mlir::dyn_cast<::mlir::arith::CmpIOp>(&mlirOperation))
688 {
689 auto type = ComOp.getOperandTypes()[0];
690 if (type.isa<::mlir::IntegerType>())
691 {
692 auto integerType = ::mlir::cast<::mlir::IntegerType>(type);
693 return rvsdg::outputs(ConvertCmpIOp(ComOp, inputs, integerType.getWidth()));
694 }
695 else if (type.isIndex())
696 {
698 }
699 else
700 {
701 JLM_UNREACHABLE("Wrong type given to CmpIOp.");
702 }
703 }
704
705 else if (auto ComOp = ::mlir::dyn_cast<::mlir::arith::CmpFOp>(&mlirOperation))
706 {
707 auto type = ComOp.getOperandTypes()[0];
708 auto floatType = ::mlir::cast<::mlir::FloatType>(type);
710 std::vector(inputs.begin(), inputs.end()),
711 TryConvertFPCMP(ComOp.getPredicate()),
712 ConvertFPSize(floatType.getWidth())));
713 }
714
715 // Pointer compare is mapped to LLVM::ICmpOp
716 else if (auto iComOp = ::mlir::dyn_cast<::mlir::LLVM::ICmpOp>(&mlirOperation))
717 {
718 return rvsdg::outputs(ConvertICmpOp(iComOp, rvsdgRegion, inputs));
719 }
720
721 else if (auto UndefOp = ::mlir::dyn_cast<::mlir::jlm::Undef>(&mlirOperation))
722 {
723 auto type = UndefOp.getResult().getType();
724 auto jlmType = ConvertType(type);
725 return { jlm::llvm::UndefValueOperation::Create(rvsdgRegion, jlmType) };
726 }
727
728 else if (auto ArrayOp = ::mlir::dyn_cast<::mlir::jlm::ConstantDataArray>(&mlirOperation))
729 {
730 return { llvm::ConstantDataArrayOperation::Create(std::vector(inputs.begin(), inputs.end())) };
731 }
732
733 else if (auto ZeroOp = ::mlir::dyn_cast<::mlir::LLVM::ZeroOp>(&mlirOperation))
734 {
735 auto type = ZeroOp.getType();
736 // NULL pointers are a special case of ZeroOp
737 if (::mlir::isa<::mlir::LLVM::LLVMPointerType>(type))
738 {
740 }
741 return { llvm::ConstantAggregateZeroOperation::Create(rvsdgRegion, ConvertType(type)) };
742 }
743
744 else if (auto VarArgOp = ::mlir::dyn_cast<::mlir::jlm::CreateVarArgList>(&mlirOperation))
745 {
747 rvsdgRegion,
748 std::vector(inputs.begin(), inputs.end())) };
749 }
750
751 // Memory operations
752
753 else if (auto FreeOp = ::mlir::dyn_cast<::mlir::jlm::Free>(&mlirOperation))
754 {
756 std::vector(inputs.begin(), inputs.end()),
757 inputs.size() - 2));
758 }
759
760 else if (auto AllocaOp = ::mlir::dyn_cast<::mlir::jlm::Alloca>(&mlirOperation))
761 {
762 auto outputType = AllocaOp.getValueType();
763
764 auto jlmType = ConvertType(outputType);
765 if (jlmType->Kind() != rvsdg::TypeKind::Value)
766 JLM_UNREACHABLE("Expected ValueType for AllocaOp operation.");
767
768 if (!rvsdg::is<const rvsdg::BitType>(inputs[0]->Type()))
769 JLM_UNREACHABLE("Expected BitType for AllocaOp operation.");
770
771 auto jlmBitType = std::dynamic_pointer_cast<const jlm::rvsdg::BitType>(inputs[0]->Type());
772
774 std::vector(inputs.begin(), inputs.end()),
775 jlmType,
776 jlmBitType,
777 AllocaOp.getAlignment()));
778 }
779 else if (auto MemstateMergeOp = ::mlir::dyn_cast<::mlir::rvsdg::MemStateMerge>(&mlirOperation))
780 {
781 auto operands = std::vector(inputs.begin(), inputs.end());
783 }
784 else if (
785 auto LambdaEntryMemstateSplitOp =
786 ::mlir::dyn_cast<::mlir::rvsdg::LambdaEntryMemoryStateSplit>(&mlirOperation))
787 {
788 auto memoryNodeIds =
789 arrayAttrToMemoryNodeIds(LambdaEntryMemstateSplitOp.getMemoryStateIndices());
790
791 auto operands = std::vector(inputs.begin(), inputs.end());
793 *operands.front(),
794 std::move(memoryNodeIds)));
795 }
796 if (auto LambdaExitMemstateMergeOp =
797 ::mlir::dyn_cast<::mlir::rvsdg::LambdaExitMemoryStateMerge>(&mlirOperation))
798 {
799 auto memoryNodeIds =
800 arrayAttrToMemoryNodeIds(LambdaExitMemstateMergeOp.getMemoryStateIndices());
801
802 auto operands = std::vector(inputs.begin(), inputs.end());
804 rvsdgRegion,
805 operands,
806 std::move(memoryNodeIds)));
807 }
808 else if (
809 auto CallEntryMemstateMergeOp =
810 ::mlir::dyn_cast<::mlir::rvsdg::CallEntryMemoryStateMerge>(&mlirOperation))
811 {
812 auto memoryNodeIds = arrayAttrToMemoryNodeIds(CallEntryMemstateMergeOp.getMemoryStateIndices());
813
814 auto operands = std::vector(inputs.begin(), inputs.end());
816 rvsdgRegion,
817 operands,
818 std::move(memoryNodeIds)));
819 }
820 else if (
821 auto CallExitMemstateSplitOp =
822 ::mlir::dyn_cast<::mlir::rvsdg::CallExitMemoryStateSplit>(&mlirOperation))
823 {
824 auto memoryNodeIds = arrayAttrToMemoryNodeIds(CallExitMemstateSplitOp.getMemoryStateIndices());
825
826 auto operands = std::vector(inputs.begin(), inputs.end());
828 *operands.front(),
829 std::move(memoryNodeIds)));
830 }
831 else if (::mlir::isa<::mlir::rvsdg::MemoryStateJoin>(&mlirOperation))
832 {
833 std::vector operands(inputs.begin(), inputs.end());
835 }
836 else if (auto IOBarrierOp = ::mlir::dyn_cast<::mlir::jlm::IOBarrier>(&mlirOperation))
837 {
838 auto type = IOBarrierOp.getResult().getType();
840 std::vector(inputs.begin(), inputs.end()),
841 ConvertType(type)));
842 }
843 else if (auto hoistBarrierOp = ::mlir::dyn_cast<::mlir::jlm::MemoryHoistBarrier>(&mlirOperation))
844 {
846 *inputs[0],
847 *inputs[1],
848 hoistBarrierOp.getDereferenceableSize()));
849 }
850 else if (auto MallocOp = ::mlir::dyn_cast<::mlir::jlm::Malloc>(&mlirOperation))
851 {
852 return outputs(&llvm::MallocOperation::createNode(*inputs[0], *inputs[1]));
853 }
854 else if (auto StoreOp = ::mlir::dyn_cast<::mlir::jlm::Store>(&mlirOperation))
855 {
856 // The op is volatile iff its `isVolatile` flag is set; volatile Store operands are
857 // pointer(0), value(1), ioState(2), inputMemStates(3+), while non-volatile ones are
858 // pointer(0), value(1), inputMemStates(2+).
859 const bool isVolatile = StoreOp.getIsVolatile();
860
861 auto address = inputs[0];
862 auto value = inputs[1];
863 if (isVolatile)
864 {
865 JLM_ASSERT(inputs.size() >= 3 && "Volatile store needs at least 3 inputs");
866 std::vector<rvsdg::Output *> memoryStateInputs(std::next(inputs.begin(), 3), inputs.end());
868 *address,
869 *value,
870 *inputs[2], // ioState
871 memoryStateInputs,
872 StoreOp.getAlignment()));
873 }
874 else
875 {
876 std::vector<rvsdg::Output *> memoryStateInputs(std::next(inputs.begin(), 2), inputs.end());
878 *address,
879 *value,
880 memoryStateInputs,
881 StoreOp.getAlignment()));
882 }
883 }
884 else if (auto LoadOp = ::mlir::dyn_cast<::mlir::jlm::Load>(&mlirOperation))
885 {
886 // The op is volatile iff its `isVolatile` flag is set; volatile Load operands are
887 // pointer(0), ioState(1), inputMemStates(2+), while non-volatile ones are
888 // pointer(0), inputMemStates(1+).
889 const bool isVolatile = LoadOp.getIsVolatile();
890 auto address = inputs[0];
891
892 auto outputType = LoadOp.getOutput().getType();
893 auto jlmType = ConvertType(outputType);
894 if (jlmType->Kind() != rvsdg::TypeKind::Value)
895 JLM_UNREACHABLE("Expected ValueType for LoadOp operation output.");
896
897 if (isVolatile)
898 {
899 JLM_ASSERT(inputs.size() >= 2 && "Volatile load needs at least 2 inputs");
900 std::vector<rvsdg::Output *> memoryStateInputs(std::next(inputs.begin(), 2), inputs.end());
902 *address,
903 *inputs[1], // ioState
904 memoryStateInputs,
905 jlmType,
906 LoadOp.getAlignment()));
907 }
908 else
909 {
910 std::vector<rvsdg::Output *> memoryStateInputs(std::next(inputs.begin(), 1), inputs.end());
912 *address,
913 memoryStateInputs,
914 jlmType,
915 LoadOp.getAlignment()));
916 }
917 }
918 else if (auto GepOp = ::mlir::dyn_cast<::mlir::LLVM::GEPOp>(&mlirOperation))
919 {
920 auto elemType = GepOp.getElemType();
921 auto pointeeType = ConvertType(elemType);
922 if (pointeeType->Kind() != rvsdg::TypeKind::Value)
923 JLM_UNREACHABLE("Expected ValueType for GepOp operation pointee.");
924
925 std::vector<rvsdg::Output *> indices;
926 // The first input is the base pointer
927 size_t dynamicInput = 1;
928 for (int32_t constant : GepOp.getRawConstantIndices())
929 {
930 // If magic number then its a dynamic index
931 if (constant == ::mlir::LLVM::GEPOp::kDynamicIndex)
932 {
933 indices.push_back(inputs[dynamicInput++]);
934 }
935 else
936 {
937 // Constant indices are not part of the inputs to a GEPOp,
938 // but they are required as explicit nodes in RVSDG
939 indices.push_back(
940 jlm::llvm::IntegerConstantOperation::Create(rvsdgRegion, 32, constant).output(0));
941 }
942 }
943
944 return { llvm::GetElementPtrOperation::create(inputs[0], indices, pointeeType) };
945 }
946 else if (auto bitCastOp = ::mlir::dyn_cast<::mlir::LLVM::BitcastOp>(&mlirOperation))
947 {
948 auto srcType = inputs[0]->Type();
949 auto mlirDstType = bitCastOp.getType();
950
951 // BitCast on pointer types
952 if (rvsdg::is<llvm::PointerType>(*srcType)
953 && ::mlir::isa<::mlir::LLVM::LLVMPointerType>(mlirDstType))
954 {
955 return { llvm::BitCastOperation::create(inputs[0], ConvertType(mlirDstType)) };
956 }
957 // BitCast on integer types (ExtUI or Trunc depending on size)
958 else if (auto srcBitType = dynamic_cast<const rvsdg::BitType *>(srcType.get()))
959 {
960 auto dstIntType = mlirDstType.cast<::mlir::IntegerType>();
961 auto srcBits = srcBitType->nbits();
962 auto dstBits = dstIntType.getWidth();
963
964 if (dstBits > srcBits)
965 {
966 return { &llvm::ZExtOperation::create(dstBits, *inputs[0]) };
967 }
968 else if (dstBits < srcBits)
969 {
970 return { &llvm::TruncOperation::create(dstBits, *inputs[0]) };
971 }
972 else
973 {
974 // Same bit width - just pass through with BitCastOperation
975 return { llvm::BitCastOperation::create(inputs[0], ConvertType(mlirDstType)) };
976 }
977 }
978 JLM_UNREACHABLE("Unsupported bitcast type combination in BitcastOp.");
979 }
980 else if (::mlir::isa<::mlir::jlm::FuncToPtr>(&mlirOperation))
981 {
982 auto srcFnType = std::dynamic_pointer_cast<const rvsdg::FunctionType>(inputs[0]->Type());
983 JLM_ASSERT(srcFnType);
984 auto & node = rvsdg::CreateOpNode<llvm::FunctionToPointerOperation>({ inputs[0] }, srcFnType);
985 return { node.output(0) };
986 }
987 else if (::mlir::isa<::mlir::jlm::PtrToFunc>(&mlirOperation))
988 {
989 auto dstFnType = std::dynamic_pointer_cast<const rvsdg::FunctionType>(
990 ConvertType(mlirOperation.getResult(0).getType()));
991 JLM_ASSERT(dstFnType);
992 return rvsdg::outputs(
994 }
995 // * region Structural nodes **
996 else if (auto MlirCtrlConst = ::mlir::dyn_cast<::mlir::rvsdg::ConstantCtrl>(&mlirOperation))
997 {
998 JLM_ASSERT(::mlir::isa<::mlir::rvsdg::RVSDG_CTRLType>(MlirCtrlConst.getType()));
1000 rvsdgRegion,
1001 ::mlir::cast<::mlir::rvsdg::RVSDG_CTRLType>(MlirCtrlConst.getType()).getNumOptions(),
1002 MlirCtrlConst.getValue()) };
1003 }
1004 else if (auto mlirGammaNode = ::mlir::dyn_cast<::mlir::rvsdg::GammaNode>(&mlirOperation))
1005 {
1006 auto rvsdgGammaNode = rvsdg::GammaNode::create(
1007 inputs[0], // predicate
1008 mlirGammaNode.getNumRegions() // nalternatives
1009 );
1010
1011 // Add inputs to the gamma node and to all it's subregions
1012 for (size_t i = 1; i < inputs.size(); i++)
1013 {
1014 rvsdgGammaNode->AddEntryVar(inputs[i]);
1015 }
1016
1017 ::llvm::SmallVector<::llvm::SmallVector<jlm::rvsdg::Output *>> regionResults;
1018 for (size_t i = 0; i < mlirGammaNode.getNumRegions(); i++)
1019 {
1020 regionResults.push_back(
1021 ConvertRegion(mlirGammaNode.getRegion(i), *rvsdgGammaNode->subregion(i)));
1022 }
1023
1024 // Connect the outputs
1026 for (size_t exitvarIndex = 0; exitvarIndex < regionResults[0].size(); exitvarIndex++)
1027 {
1028 std::vector<rvsdg::Output *> exitvars;
1029 for (size_t regionIndex = 0; regionIndex < mlirGammaNode.getNumRegions(); regionIndex++)
1030 {
1031 JLM_ASSERT(regionResults[regionIndex].size() == regionResults[0].size());
1032 exitvars.push_back(regionResults[regionIndex][exitvarIndex]);
1033 }
1034 rvsdgGammaNode->AddExitVar(exitvars);
1035 }
1036
1037 return rvsdg::outputs(rvsdgGammaNode);
1038 }
1039 else if (auto mlirThetaNode = ::mlir::dyn_cast<::mlir::rvsdg::ThetaNode>(&mlirOperation))
1040 {
1041 auto rvsdgThetaNode = rvsdg::ThetaNode::create(&rvsdgRegion);
1042
1043 // Add loop vars to the theta node
1044 for (size_t i = 0; i < inputs.size(); i++)
1045 {
1046 rvsdgThetaNode->AddLoopVar(inputs[i]);
1047 }
1048
1049 auto regionResults = ConvertRegion(mlirThetaNode.getRegion(), *rvsdgThetaNode->subregion());
1050
1051 rvsdgThetaNode->set_predicate(regionResults[0]);
1052
1053 auto loopvars = rvsdgThetaNode->GetLoopVars();
1054 for (size_t i = 1; i < regionResults.size(); i++)
1055 {
1056 loopvars[i - 1].post->divert_to(regionResults[i]);
1057 }
1058
1059 return rvsdg::outputs(rvsdgThetaNode);
1060 }
1061 else if (auto mlirDeltaNode = ::mlir::dyn_cast<::mlir::rvsdg::DeltaNode>(&mlirOperation))
1062 {
1063 auto & deltaRegion = mlirDeltaNode.getRegion();
1064 auto & deltaBlock = deltaRegion.front();
1065 auto terminator = deltaBlock.getTerminator();
1066
1067 auto mlirOutputType = terminator->getOperand(0).getType();
1068 auto outputType = ConvertType(mlirOutputType);
1069 auto linakgeString = mlirDeltaNode.getLinkage().str();
1070 auto rvsdgDeltaNode = rvsdg::DeltaNode::Create(
1071 &rvsdgRegion,
1073 outputType,
1074 mlirDeltaNode.getName().str(),
1075 ConvertLinkage(linakgeString),
1076 mlirDeltaNode.getSection().str(),
1077 mlirDeltaNode.getConstant(),
1078 4)); // FIXME: the MLIR delta node does not support the alignment attribute
1079
1080 // Add context variables from inputs to delta's subregion
1081 for (auto input : inputs)
1082 {
1083 rvsdgDeltaNode->AddContextVar(*input);
1084 }
1085
1086 auto outputVector = ConvertRegion(mlirDeltaNode.getRegion(), *rvsdgDeltaNode->subregion());
1087
1088 if (outputVector.size() != 1)
1089 JLM_UNREACHABLE("Expected 1 output for Delta operation.");
1090
1091 rvsdgDeltaNode->finalize(outputVector[0]);
1092
1093 return rvsdg::outputs(rvsdgDeltaNode);
1094 }
1095 else if (auto mlirMatch = ::mlir::dyn_cast<::mlir::rvsdg::Match>(&mlirOperation))
1096 {
1097 std::unordered_map<uint64_t, uint64_t> mapping;
1098 uint64_t defaultAlternative = 0;
1099 for (auto & attr : mlirMatch.getMapping())
1100 {
1101 JLM_ASSERT(attr.isa<::mlir::rvsdg::MatchRuleAttr>());
1102 auto matchRuleAttr = attr.cast<::mlir::rvsdg::MatchRuleAttr>();
1103 if (matchRuleAttr.isDefault())
1104 {
1105 defaultAlternative = matchRuleAttr.getIndex();
1106 continue;
1107 }
1108 // In our Mlir implementation, an index is associated with a single value
1109 mapping[matchRuleAttr.getValues().front()] = matchRuleAttr.getIndex();
1110 }
1111
1113 *(inputs[0]), // predicate
1114 mapping, // mapping
1115 defaultAlternative, // defaultAlternative
1116 mlirMatch.getMapping().size() // numAlternatives
1117 ) };
1118 }
1119 else if (auto selectOp = ::mlir::dyn_cast<::mlir::arith::SelectOp>(&mlirOperation))
1120 {
1121 auto type = selectOp.getType();
1122 auto jlmType = ConvertType(type);
1124 std::vector(inputs.begin(), inputs.end()),
1125 jlmType));
1126 }
1127 else if (auto mlirOmegaResult = ::mlir::dyn_cast<::mlir::rvsdg::OmegaResult>(&mlirOperation))
1128 {
1129 for (auto input : inputs)
1130 {
1131 auto origin = rvsdg::TryGetOwnerNode<rvsdg::Node>(*input);
1132 if (auto lambda = dynamic_cast<rvsdg::LambdaNode *>(origin))
1133 {
1134 auto op = dynamic_cast<llvm::LlvmLambdaOperation *>(&lambda->GetOperation());
1135 jlm::rvsdg::GraphExport::Create(*input, op->name());
1136 }
1137 else if (auto delta = dynamic_cast<rvsdg::DeltaNode *>(origin))
1138 {
1139 auto op = util::assertedCast<const llvm::LlvmDeltaOperation>(&delta->GetOperation());
1140 jlm::rvsdg::GraphExport::Create(*input, op->name());
1141 }
1142 }
1143 return {};
1144 }
1145 // ** endregion Structural nodes **
1146
1147 else if (
1148 ::mlir::isa<::mlir::rvsdg::LambdaResult>(&mlirOperation)
1149 || ::mlir::isa<::mlir::rvsdg::GammaResult>(&mlirOperation)
1150 || ::mlir::isa<::mlir::rvsdg::ThetaResult>(&mlirOperation)
1151 || ::mlir::isa<::mlir::rvsdg::DeltaResult>(&mlirOperation)
1152 // This is a terminating operation that doesn't have a corresponding RVSDG node
1153 || ::mlir::isa<::mlir::rvsdg::OmegaArgument>(&mlirOperation)) // Handled at the top level
1154 {
1155 return {};
1156 }
1157 else
1158 {
1159 mlirOperation.dump();
1160 auto message = util::strfmt(
1161 "Operation not implemented: ",
1162 mlirOperation.getName().getStringRef().str(),
1163 "\n");
1164 JLM_UNREACHABLE(message.c_str());
1165 }
1166}
1167
1170{
1171 switch (size)
1172 {
1173 case 16:
1174 return llvm::fpsize::half;
1175 case 32:
1176 return llvm::fpsize::flt;
1177 case 64:
1178 return llvm::fpsize::dbl;
1179 case 80:
1180 return llvm::fpsize::x86fp80;
1181 case 128:
1182 return llvm::fpsize::fp128;
1183 default:
1184 auto message = util::strfmt("Unsupported floating point size: ", size, "\n");
1185 JLM_UNREACHABLE(message.c_str());
1186 break;
1187 }
1188}
1189
1192{
1193 if (!stringValue.compare("external_linkage"))
1194 {
1196 }
1197 else if (!stringValue.compare("available_externally_linkage"))
1198 {
1200 }
1201 else if (!stringValue.compare("link_once_any_linkage"))
1202 {
1204 }
1205 else if (!stringValue.compare("link_once_odr_linkage"))
1206 {
1208 }
1209 else if (!stringValue.compare("weak_any_linkage"))
1210 {
1212 }
1213 else if (!stringValue.compare("weak_odr_linkage"))
1214 {
1216 }
1217 else if (!stringValue.compare("appending_linkage"))
1218 {
1220 }
1221 else if (!stringValue.compare("internal_linkage"))
1222 {
1224 }
1225 else if (!stringValue.compare("private_linkage"))
1226 {
1228 }
1229 else if (!stringValue.compare("external_weak_linkage"))
1230 {
1232 }
1233 else if (!stringValue.compare("common_linkage"))
1234 {
1236 }
1237 auto message = util::strfmt("Unsupported linkage: ", stringValue, "\n");
1238 JLM_UNREACHABLE(message.c_str());
1239}
1240
1243 ::mlir::Operation & mlirOperation,
1244 rvsdg::Region & rvsdgRegion,
1245 const ::llvm::SmallVector<rvsdg::Output *> & inputs)
1246{
1247 // Get the name of the function
1248 auto functionNameAttribute = mlirOperation.getAttr(::llvm::StringRef("sym_name"));
1249 JLM_ASSERT(functionNameAttribute != nullptr);
1250 auto functionName = ::mlir::cast<::mlir::StringAttr>(functionNameAttribute);
1251
1252 auto lambdaOp = ::mlir::dyn_cast<::mlir::rvsdg::LambdaNode>(&mlirOperation);
1253 auto & lambdaRegion = lambdaOp.getRegion();
1254 auto numNonContextVars = lambdaRegion.getNumArguments() - lambdaOp.getNumOperands();
1255 auto & lambdaBlock = lambdaRegion.front();
1256 auto lamdbaTerminator = lambdaBlock.getTerminator();
1257
1258 // Create the RVSDG function signature
1259 std::vector<std::shared_ptr<const rvsdg::Type>> argumentTypes;
1260 for (size_t argumentIndex = 0; argumentIndex < numNonContextVars; argumentIndex++)
1261 {
1262 auto type = lambdaRegion.getArgument(argumentIndex).getType();
1263 argumentTypes.push_back(ConvertType(type));
1264 }
1265 std::vector<std::shared_ptr<const rvsdg::Type>> resultTypes;
1266 for (auto returnType : lamdbaTerminator->getOperandTypes())
1267 {
1268 resultTypes.push_back(ConvertType(returnType));
1269 }
1270 auto functionType = rvsdg::FunctionType::Create(std::move(argumentTypes), std::move(resultTypes));
1271
1272 // Get the linkage attribute from the MLIR LambdaNode
1273 auto linkageAttribute = mlirOperation.getAttr(::llvm::StringRef("linkage"));
1274 JLM_ASSERT(linkageAttribute != nullptr);
1275 auto linkageStr = ::mlir::cast<::mlir::StringAttr>(linkageAttribute);
1276 auto linkage = llvm::linkageFromString(linkageStr.str());
1277
1278 auto rvsdgLambda = rvsdg::LambdaNode::Create(
1279 rvsdgRegion,
1280 llvm::LlvmLambdaOperation::Create(functionType, functionName.getValue().str(), linkage));
1281
1282 for (auto input : inputs)
1283 {
1284 rvsdgLambda->AddContextVar(*input);
1285 }
1286
1287 auto jlmLambdaRegion = rvsdgLambda->subregion();
1288 auto regionResults = ConvertRegion(lambdaRegion, *jlmLambdaRegion);
1289
1290 rvsdgLambda->finalize(std::vector<rvsdg::Output *>(regionResults.begin(), regionResults.end()));
1291
1292 return rvsdgLambda;
1293}
1294
1295std::shared_ptr<const rvsdg::Type>
1296MlirToJlmConverter::ConvertType(const ::mlir::Type & type)
1297{
1298 if (auto ctrlType = ::mlir::dyn_cast<::mlir::rvsdg::RVSDG_CTRLType>(type))
1299 {
1300 return rvsdg::ControlType::Create(ctrlType.getNumOptions());
1301 }
1302 else if (auto intType = ::mlir::dyn_cast<::mlir::IntegerType>(type))
1303 {
1304 return rvsdg::BitType::Create(intType.getWidth());
1305 }
1306 else if (::mlir::isa<::mlir::Float16Type>(type))
1307 {
1309 }
1310 else if (::mlir::isa<::mlir::Float32Type>(type))
1311 {
1313 }
1314 else if (::mlir::isa<::mlir::Float64Type>(type))
1315 {
1317 }
1318 else if (::mlir::isa<::mlir::Float80Type>(type))
1319 {
1321 }
1322 else if (::mlir::isa<::mlir::Float128Type>(type))
1323 {
1325 }
1326 else if (::mlir::isa<::mlir::rvsdg::MemStateEdgeType>(type))
1327 {
1329 }
1330 else if (::mlir::isa<::mlir::rvsdg::IOStateEdgeType>(type))
1331 {
1333 }
1334 else if (::mlir::isa<::mlir::LLVM::LLVMPointerType>(type))
1335 {
1337 }
1338 else if (::mlir::isa<::mlir::jlm::VarargListType>(type))
1339 {
1341 }
1342 else if (auto arrayType = ::mlir::dyn_cast<::mlir::LLVM::LLVMArrayType>(type))
1343 {
1344 auto mlirElementType = arrayType.getElementType();
1345 std::shared_ptr<const rvsdg::Type> elementType = ConvertType(mlirElementType);
1346 return llvm::ArrayType::Create(elementType, arrayType.getNumElements());
1347 }
1348 else if (auto functionType = ::mlir::dyn_cast<::mlir::FunctionType>(type))
1349 {
1350 std::vector<std::shared_ptr<const rvsdg::Type>> argumentTypes;
1351 for (auto argumentType : functionType.getInputs())
1352 {
1353 argumentTypes.push_back(ConvertType(argumentType));
1354 }
1355 std::vector<std::shared_ptr<const rvsdg::Type>> resultTypes;
1356 for (auto resultType : functionType.getResults())
1357 {
1358 resultTypes.push_back(ConvertType(resultType));
1359 }
1360 return rvsdg::FunctionType::Create(argumentTypes, resultTypes);
1361 }
1362 else if (type.isIndex())
1363 {
1364 // RVSDG does not support indices, which are modeled as integers
1366 }
1367 else if (auto structType = ::mlir::dyn_cast<::mlir::LLVM::LLVMStructType>(type))
1368 {
1369 if (StructTypeMap_.HasKey(&structType))
1370 {
1371 return StructTypeMap_.LookupKey(&structType);
1372 }
1373
1374 std::vector<std::shared_ptr<const rvsdg::Type>> types;
1375 for (auto element : structType.getBody())
1376 {
1377 types.push_back(ConvertType(element));
1378 }
1379
1380 std::shared_ptr<const llvm::StructType> jlmStructType;
1381 if (structType.isIdentified())
1382 {
1384 structType.getName().str(),
1385 types,
1386 structType.isPacked());
1387 }
1388 else
1389 {
1390 jlmStructType = jlm::llvm::StructType::CreateLiteral(types, structType.isPacked());
1391 }
1392
1393 StructTypeMap_.Insert(&structType, jlmStructType);
1394 return jlmStructType;
1395 }
1396 else
1397 {
1398 type.dump();
1399 JLM_UNREACHABLE("Type conversion not implemented\n");
1400 }
1401}
1402
1403} // jlm::mlirrvsdg
util::HashSet< rvsdg::Output * > arguments
static std::shared_ptr< const ArrayType > Create(std::shared_ptr< const Type > type, size_t nelements)
Definition types.hpp:98
static AttributeList createEmptyList()
static jlm::rvsdg::Output * create(jlm::rvsdg::Output *operand, std::shared_ptr< const jlm::rvsdg::Type > rtype)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
static std::vector< rvsdg::Output * > Create(rvsdg::Output *function, std::shared_ptr< const rvsdg::FunctionType > functionType, const std::vector< rvsdg::Output * > &arguments)
Definition call.hpp:482
static rvsdg::Output * Create(rvsdg::Region &region, const std::shared_ptr< const rvsdg::Type > &type)
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &elements)
static rvsdg::Node & createNode(rvsdg::Region &region)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &multiplier, rvsdg::Output &multiplicand, rvsdg::Output &summand)
static std::shared_ptr< const FloatingPointType > Create(fpsize size)
Definition types.cpp:117
static rvsdg::Output * create(rvsdg::Output *baseAddress, const std::vector< rvsdg::Output * > &indices, std::shared_ptr< const rvsdg::Type > gepType)
static std::shared_ptr< const IOStateType > Create()
Definition types.cpp:343
static std::unique_ptr< ThreeAddressCode > create(const Variable *argument)
static rvsdg::Node & Create(rvsdg::Region &region, IntegerValueRepresentation representation)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &operand, std::vector< MemoryNodeId > memoryNodeIds)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands, const std::vector< MemoryNodeId > &memoryNodeIds)
static std::unique_ptr< LlvmDeltaOperation > Create(std::shared_ptr< const rvsdg::Type > type, const std::string &name, const Linkage &linkage, std::string section, bool constant, const size_t alignment)
Definition delta.hpp:82
static LlvmGraphImport & create(rvsdg::Graph &graph, std::shared_ptr< const rvsdg::Type > valueType, std::shared_ptr< const rvsdg::Type > importedType, std::string name, Linkage linkage, CallingConvention callingConvention, const bool isConstant, const size_t alignment)
static std::unique_ptr< LlvmLambdaOperation > Create(std::shared_ptr< const jlm::rvsdg::FunctionType > type, std::string name, const jlm::llvm::Linkage &linkage, jlm::llvm::CallingConvention callingConvention, jlm::llvm::AttributeSet attributes)
Definition lambda.hpp:84
static std::unique_ptr< LlvmRvsdgModule > Create(const util::FilePath &sourceFileName, const std::string &targetTriple, const std::string &dataLayout)
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< LoadNonVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
Definition Load.hpp:470
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< LoadVolatileOperation > loadOperation, const std::vector< rvsdg::Output * > &operands)
Definition Load.cpp:430
static rvsdg::SimpleNode & createNode(rvsdg::Output &size, rvsdg::Output &ioState)
static rvsdg::SimpleNode & createNode(rvsdg::Output &address, rvsdg::Output &ioState, const std::size_t dereferenceableSize)
static rvsdg::SimpleNode & CreateNode(const std::vector< rvsdg::Output * > &operands)
static rvsdg::Output * Create(const std::vector< rvsdg::Output * > &operands)
static std::shared_ptr< const MemoryStateType > Create()
Definition types.cpp:379
static std::shared_ptr< const PointerType > Create()
Definition types.cpp:45
static rvsdg::Output & create(size_t ndstbits, rvsdg::Output &operand)
static rvsdg::SimpleNode & CreateNode(rvsdg::Output &address, rvsdg::Output &value, const std::vector< rvsdg::Output * > &memoryStates, size_t alignment)
Definition Store.hpp:360
static rvsdg::SimpleNode & CreateNode(rvsdg::Region &region, std::unique_ptr< StoreVolatileOperation > storeOperation, const std::vector< rvsdg::Output * > &operands)
Definition Store.hpp:490
static std::shared_ptr< const StructType > CreateLiteral(std::vector< std::shared_ptr< const Type > > types, bool isPacked)
Definition types.hpp:334
static std::shared_ptr< const StructType > CreateIdentified(const std::string &name, std::vector< std::shared_ptr< const Type > > types, bool isPacked)
Definition types.hpp:307
static rvsdg::Output & create(size_t ndstbits, rvsdg::Output &operand)
static jlm::rvsdg::Output * Create(rvsdg::Region &region, std::shared_ptr< const jlm::rvsdg::Type > type)
static std::shared_ptr< const VariableArgumentType > Create()
Definition types.cpp:180
static rvsdg::Output * Create(rvsdg::Region &region, const std::vector< rvsdg::Output * > &operands)
static rvsdg::Output & create(size_t ndstbits, rvsdg::Output &operand)
static ::llvm::SmallVector< jlm::rvsdg::Output * > GetConvertedInputs(::mlir::Operation &mlirOp, const std::unordered_map< void *, rvsdg::Output * > &outputMap)
std::unique_ptr<::mlir::MLIRContext > Context_
std::vector< jlm::rvsdg::Output * > ConvertOperation(::mlir::Operation &mlirOperation, rvsdg::Region &rvsdgRegion, const ::llvm::SmallVector< rvsdg::Output * > &inputs)
rvsdg::Node * ConvertFPBinaryNode(const ::mlir::Operation &mlirOperation, const ::llvm::SmallVector< rvsdg::Output * > &inputs)
rvsdg::Node * ConvertICmpOp(::mlir::LLVM::ICmpOp &operation, rvsdg::Region &rvsdgRegion, const ::llvm::SmallVector< rvsdg::Output * > &inputs)
rvsdg::Node * ConvertLambda(::mlir::Operation &mlirLambda, rvsdg::Region &rvsdgRegion, const ::llvm::SmallVector< rvsdg::Output * > &inputs)
llvm::fpsize ConvertFPSize(unsigned int size)
llvm::Linkage ConvertLinkage(std::string stringValue)
util::BijectiveMap<::mlir::LLVM::LLVMStructType *, std::shared_ptr< const llvm::StructType > > StructTypeMap_
std::unique_ptr< llvm::LlvmRvsdgModule > ReadAndConvertMlir(const util::FilePath &filePath)
jlm::llvm::fpcmp TryConvertFPCMP(const ::mlir::arith::CmpFPredicate &op)
rvsdg::Node * ConvertCmpIOp(::mlir::arith::CmpIOp &CompOp, const ::llvm::SmallVector< rvsdg::Output * > &inputs, size_t nbits)
::llvm::SmallVector< jlm::rvsdg::Output * > ConvertBlock(::mlir::Block &block, rvsdg::Region &rvsdgRegion)
std::unique_ptr< llvm::LlvmRvsdgModule > ConvertOmega(::mlir::rvsdg::OmegaNode &omegaNode)
::llvm::SmallVector< jlm::rvsdg::Output * > ConvertRegion(::mlir::Region &region, rvsdg::Region &rvsdgRegion)
std::shared_ptr< const rvsdg::Type > ConvertType(const ::mlir::Type &type)
std::unique_ptr< llvm::LlvmRvsdgModule > ConvertMlir(std::unique_ptr<::mlir::Block > &block)
rvsdg::Node * ConvertBitBinaryNode(::mlir::Operation &mlirOperation, const ::llvm::SmallVector< rvsdg::Output * > &inputs)
static std::shared_ptr< const BitType > Create(std::size_t nbits)
Creates bit type of specified width.
Definition type.cpp:45
static Output & create(Region &region, ControlValueRepresentation value)
Definition control.hpp:122
static std::shared_ptr< const ControlType > Create(std::size_t nalternatives)
Instantiates control type.
Definition control.cpp:50
static DeltaNode * Create(rvsdg::Region *parent, std::unique_ptr< DeltaOperation > op)
Definition delta.hpp:313
static std::shared_ptr< const FunctionType > Create(std::vector< std::shared_ptr< const jlm::rvsdg::Type > > argumentTypes, std::vector< std::shared_ptr< const jlm::rvsdg::Type > > resultTypes)
static GammaNode * create(jlm::rvsdg::Output *predicate, size_t nalternatives)
Definition gamma.hpp:161
static GraphExport & Create(Output &origin, std::string name)
Definition graph.cpp:62
static LambdaNode * Create(rvsdg::Region &parent, std::unique_ptr< LambdaOperation > operation)
Definition lambda.cpp:141
static Output * Create(Output &predicate, const std::unordered_map< uint64_t, uint64_t > &mapping, const uint64_t defaultAlternative, const size_t numAlternatives)
Definition control.hpp:278
NodeOutput * output(size_t index) const noexcept
Definition node.hpp:650
const std::shared_ptr< const rvsdg::Type > & Type() const noexcept
Definition node.hpp:366
Represent acyclic RVSDG subgraphs.
Definition region.hpp:213
RegionArgument * argument(size_t index) const noexcept
Definition region.hpp:466
Graph * graph() const noexcept
Definition region.hpp:267
static SimpleNode & Create(Region &region, std::unique_ptr< Operation > operation, const std::vector< rvsdg::Output * > &operands)
static ThetaNode * create(rvsdg::Region *parent)
Definition theta.hpp:84
const std::string & to_str() const noexcept
Definition file.hpp:275
#define JLM_ASSERT(x)
Definition common.hpp:16
#define JLM_UNREACHABLE(msg)
Definition common.hpp:43
Linkage linkageFromString(const std::string_view stringValue)
Definition Linkage.cpp:42
const util::BijectiveMap<::mlir::arith::CmpFPredicate, llvm::fpcmp > & GetFpCmpPredicateMap()
static std::vector< llvm::MemoryNodeId > arrayAttrToMemoryNodeIds(::mlir::ArrayAttr arrayAttr)
static std::vector< jlm::rvsdg::Output * > outputs(const Node *node)
Definition node.hpp:1058
@ Value
Designate a value type.
NodeType * TryGetOwnerNode(const rvsdg::Input &input) noexcept
Checks if this is an input to a node of specified type.
Definition node.hpp:872
static std::string strfmt(Args... args)
Definition strfmt.hpp:35