3404 lines · cpp
1//===- ModuleImport.cpp - LLVM to MLIR conversion ---------------*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the import of an LLVM IR module into an LLVM dialect10// module.11//12//===----------------------------------------------------------------------===//13 14#include "mlir/Target/LLVMIR/ModuleImport.h"15#include "mlir/IR/BuiltinAttributes.h"16#include "mlir/Target/LLVMIR/Import.h"17 18#include "AttrKindDetail.h"19#include "DebugImporter.h"20#include "LoopAnnotationImporter.h"21 22#include "mlir/Dialect/DLTI/DLTI.h"23#include "mlir/Dialect/LLVMIR/LLVMDialect.h"24#include "mlir/IR/Builders.h"25#include "mlir/IR/Matchers.h"26#include "mlir/Interfaces/DataLayoutInterfaces.h"27#include "mlir/Target/LLVMIR/DataLayoutImporter.h"28#include "mlir/Tools/mlir-translate/Translation.h"29 30#include "llvm/ADT/DepthFirstIterator.h"31#include "llvm/ADT/PostOrderIterator.h"32#include "llvm/ADT/ScopeExit.h"33#include "llvm/ADT/StringExtras.h"34#include "llvm/ADT/TypeSwitch.h"35#include "llvm/IR/Comdat.h"36#include "llvm/IR/Constants.h"37#include "llvm/IR/DebugProgramInstruction.h"38#include "llvm/IR/InlineAsm.h"39#include "llvm/IR/InstIterator.h"40#include "llvm/IR/Instructions.h"41#include "llvm/IR/IntrinsicInst.h"42#include "llvm/IR/Metadata.h"43#include "llvm/IR/Operator.h"44#include "llvm/Support/LogicalResult.h"45#include "llvm/Support/ModRef.h"46#include <optional>47 48using namespace mlir;49using namespace mlir::LLVM;50using namespace mlir::LLVM::detail;51 52#include "mlir/Dialect/LLVMIR/LLVMConversionEnumsFromLLVM.inc"53 54// Utility to print an LLVM value as a string for passing to emitError().55// FIXME: Diagnostic should be able to natively handle types that have56// operator << (raw_ostream&) defined.57static std::string diag(const llvm::Value &value) {58 std::string str;59 llvm::raw_string_ostream os(str);60 os << value;61 return str;62}63 64// Utility to print an LLVM metadata node as a string for passing65// to emitError(). The module argument is needed to print the nodes66// canonically numbered.67static std::string diagMD(const llvm::Metadata *node,68 const llvm::Module *module) {69 std::string str;70 llvm::raw_string_ostream os(str);71 node->print(os, module, /*IsForDebug=*/true);72 return str;73}74 75/// Returns the name of the global_ctors global variables.76static constexpr StringRef getGlobalCtorsVarName() {77 return "llvm.global_ctors";78}79 80/// Prefix used for symbols of nameless llvm globals.81static constexpr StringRef getNamelessGlobalPrefix() {82 return "mlir.llvm.nameless_global";83}84 85/// Returns the name of the global_dtors global variables.86static constexpr StringRef getGlobalDtorsVarName() {87 return "llvm.global_dtors";88}89 90/// Returns the symbol name for the module-level comdat operation. It must not91/// conflict with the user namespace.92static constexpr StringRef getGlobalComdatOpName() {93 return "__llvm_global_comdat";94}95 96/// Converts the sync scope identifier of `inst` to the string representation97/// necessary to build an atomic LLVM dialect operation. Returns the empty98/// string if the operation has either no sync scope or the default system-level99/// sync scope attached. The atomic operations only set their sync scope100/// attribute if they have a non-default sync scope attached.101static StringRef getLLVMSyncScope(llvm::Instruction *inst) {102 std::optional<llvm::SyncScope::ID> syncScopeID =103 llvm::getAtomicSyncScopeID(inst);104 if (!syncScopeID)105 return "";106 107 // Search the sync scope name for the given identifier. The default108 // system-level sync scope thereby maps to the empty string.109 SmallVector<StringRef> syncScopeName;110 llvm::LLVMContext &llvmContext = inst->getContext();111 llvmContext.getSyncScopeNames(syncScopeName);112 auto *it = llvm::find_if(syncScopeName, [&](StringRef name) {113 return *syncScopeID == llvmContext.getOrInsertSyncScopeID(name);114 });115 if (it != syncScopeName.end())116 return *it;117 llvm_unreachable("incorrect sync scope identifier");118}119 120/// Converts an array of unsigned indices to a signed integer position array.121static SmallVector<int64_t> getPositionFromIndices(ArrayRef<unsigned> indices) {122 SmallVector<int64_t> position;123 llvm::append_range(position, indices);124 return position;125}126 127/// Converts the LLVM instructions that have a generated MLIR builder. Using a128/// static implementation method called from the module import ensures the129/// builders have to use the `moduleImport` argument and cannot directly call130/// import methods. As a result, both the intrinsic and the instruction MLIR131/// builders have to use the `moduleImport` argument and none of them has direct132/// access to the private module import methods.133static LogicalResult convertInstructionImpl(OpBuilder &odsBuilder,134 llvm::Instruction *inst,135 ModuleImport &moduleImport,136 LLVMImportInterface &iface) {137 // Copy the operands to an LLVM operands array reference for conversion.138 SmallVector<llvm::Value *> operands(inst->operands());139 ArrayRef<llvm::Value *> llvmOperands(operands);140 141 // Convert all instructions that provide an MLIR builder.142 if (iface.isConvertibleInstruction(inst->getOpcode()))143 return iface.convertInstruction(odsBuilder, inst, llvmOperands,144 moduleImport);145 // TODO: Implement the `convertInstruction` hooks in the146 // `LLVMDialectLLVMIRImportInterface` and move the following include there.147#include "mlir/Dialect/LLVMIR/LLVMOpFromLLVMIRConversions.inc"148 149 return failure();150}151 152/// Get a topologically sorted list of blocks for the given basic blocks.153static SetVector<llvm::BasicBlock *>154getTopologicallySortedBlocks(ArrayRef<llvm::BasicBlock *> basicBlocks) {155 SetVector<llvm::BasicBlock *> blocks;156 for (llvm::BasicBlock *basicBlock : basicBlocks) {157 if (!blocks.contains(basicBlock)) {158 llvm::ReversePostOrderTraversal<llvm::BasicBlock *> traversal(basicBlock);159 blocks.insert_range(traversal);160 }161 }162 assert(blocks.size() == basicBlocks.size() && "some blocks are not sorted");163 return blocks;164}165 166ModuleImport::ModuleImport(ModuleOp mlirModule,167 std::unique_ptr<llvm::Module> llvmModule,168 bool emitExpensiveWarnings,169 bool importEmptyDICompositeTypes,170 bool preferUnregisteredIntrinsics,171 bool importStructsAsLiterals)172 : builder(mlirModule->getContext()), context(mlirModule->getContext()),173 mlirModule(mlirModule), llvmModule(std::move(llvmModule)),174 iface(mlirModule->getContext()),175 typeTranslator(*mlirModule->getContext(), importStructsAsLiterals),176 debugImporter(std::make_unique<DebugImporter>(177 mlirModule, importEmptyDICompositeTypes)),178 loopAnnotationImporter(179 std::make_unique<LoopAnnotationImporter>(*this, builder)),180 emitExpensiveWarnings(emitExpensiveWarnings),181 preferUnregisteredIntrinsics(preferUnregisteredIntrinsics) {182 builder.setInsertionPointToStart(mlirModule.getBody());183}184 185ComdatOp ModuleImport::getGlobalComdatOp() {186 if (globalComdatOp)187 return globalComdatOp;188 189 OpBuilder::InsertionGuard guard(builder);190 builder.setInsertionPointToEnd(mlirModule.getBody());191 globalComdatOp =192 ComdatOp::create(builder, mlirModule.getLoc(), getGlobalComdatOpName());193 globalInsertionOp = globalComdatOp;194 return globalComdatOp;195}196 197LogicalResult ModuleImport::processTBAAMetadata(const llvm::MDNode *node) {198 Location loc = mlirModule.getLoc();199 200 // If `node` is a valid TBAA root node, then return its optional identity201 // string, otherwise return failure.202 auto getIdentityIfRootNode =203 [&](const llvm::MDNode *node) -> FailureOr<std::optional<StringRef>> {204 // Root node, e.g.:205 // !0 = !{!"Simple C/C++ TBAA"}206 // !1 = !{}207 if (node->getNumOperands() > 1)208 return failure();209 // If the operand is MDString, then assume that this is a root node.210 if (node->getNumOperands() == 1)211 if (const auto *op0 = dyn_cast<const llvm::MDString>(node->getOperand(0)))212 return std::optional<StringRef>{op0->getString()};213 return std::optional<StringRef>{};214 };215 216 // If `node` looks like a TBAA type descriptor metadata,217 // then return true, if it is a valid node, and false otherwise.218 // If it does not look like a TBAA type descriptor metadata, then219 // return std::nullopt.220 // If `identity` and `memberTypes/Offsets` are non-null, then they will221 // contain the converted metadata operands for a valid TBAA node (i.e. when222 // true is returned).223 auto isTypeDescriptorNode = [&](const llvm::MDNode *node,224 StringRef *identity = nullptr,225 SmallVectorImpl<TBAAMemberAttr> *members =226 nullptr) -> std::optional<bool> {227 unsigned numOperands = node->getNumOperands();228 // Type descriptor, e.g.:229 // !1 = !{!"int", !0, /*optional*/i64 0} /* scalar int type */230 // !2 = !{!"agg_t", !1, i64 0} /* struct agg_t { int x; } */231 if (numOperands < 2)232 return std::nullopt;233 234 // TODO: support "new" format (D41501) for type descriptors,235 // where the first operand is an MDNode.236 const auto *identityNode =237 dyn_cast<const llvm::MDString>(node->getOperand(0));238 if (!identityNode)239 return std::nullopt;240 241 // This should be a type descriptor node.242 if (identity)243 *identity = identityNode->getString();244 245 for (unsigned pairNum = 0, e = numOperands / 2; pairNum < e; ++pairNum) {246 const auto *memberNode =247 dyn_cast<const llvm::MDNode>(node->getOperand(2 * pairNum + 1));248 if (!memberNode) {249 emitError(loc) << "operand '" << 2 * pairNum + 1 << "' must be MDNode: "250 << diagMD(node, llvmModule.get());251 return false;252 }253 int64_t offset = 0;254 if (2 * pairNum + 2 >= numOperands) {255 // Allow for optional 0 offset in 2-operand nodes.256 if (numOperands != 2) {257 emitError(loc) << "missing member offset: "258 << diagMD(node, llvmModule.get());259 return false;260 }261 } else {262 auto *offsetCI = llvm::mdconst::dyn_extract<llvm::ConstantInt>(263 node->getOperand(2 * pairNum + 2));264 if (!offsetCI) {265 emitError(loc) << "operand '" << 2 * pairNum + 2266 << "' must be ConstantInt: "267 << diagMD(node, llvmModule.get());268 return false;269 }270 offset = offsetCI->getZExtValue();271 }272 273 if (members)274 members->push_back(TBAAMemberAttr::get(275 cast<TBAANodeAttr>(tbaaMapping.lookup(memberNode)), offset));276 }277 278 return true;279 };280 281 // If `node` looks like a TBAA access tag metadata,282 // then return true, if it is a valid node, and false otherwise.283 // If it does not look like a TBAA access tag metadata, then284 // return std::nullopt.285 // If the other arguments are non-null, then they will contain286 // the converted metadata operands for a valid TBAA node (i.e. when true is287 // returned).288 auto isTagNode = [&](const llvm::MDNode *node,289 TBAATypeDescriptorAttr *baseAttr = nullptr,290 TBAATypeDescriptorAttr *accessAttr = nullptr,291 int64_t *offset = nullptr,292 bool *isConstant = nullptr) -> std::optional<bool> {293 // Access tag, e.g.:294 // !3 = !{!1, !1, i64 0} /* scalar int access */295 // !4 = !{!2, !1, i64 0} /* agg_t::x access */296 //297 // Optional 4th argument is ConstantInt 0/1 identifying whether298 // the location being accessed is "constant" (see for details:299 // https://llvm.org/docs/LangRef.html#representation).300 unsigned numOperands = node->getNumOperands();301 if (numOperands != 3 && numOperands != 4)302 return std::nullopt;303 const auto *baseMD = dyn_cast<const llvm::MDNode>(node->getOperand(0));304 const auto *accessMD = dyn_cast<const llvm::MDNode>(node->getOperand(1));305 auto *offsetCI =306 llvm::mdconst::dyn_extract<llvm::ConstantInt>(node->getOperand(2));307 if (!baseMD || !accessMD || !offsetCI)308 return std::nullopt;309 // TODO: support "new" TBAA format, if needed (see D41501).310 // In the "old" format the first operand of the access type311 // metadata is MDString. We have to distinguish the formats,312 // because access tags have the same structure, but different313 // meaning for the operands.314 if (accessMD->getNumOperands() < 1 ||315 !isa<llvm::MDString>(accessMD->getOperand(0)))316 return std::nullopt;317 bool isConst = false;318 if (numOperands == 4) {319 auto *isConstantCI =320 llvm::mdconst::dyn_extract<llvm::ConstantInt>(node->getOperand(3));321 if (!isConstantCI) {322 emitError(loc) << "operand '3' must be ConstantInt: "323 << diagMD(node, llvmModule.get());324 return false;325 }326 isConst = isConstantCI->getValue()[0];327 }328 if (baseAttr)329 *baseAttr = cast<TBAATypeDescriptorAttr>(tbaaMapping.lookup(baseMD));330 if (accessAttr)331 *accessAttr = cast<TBAATypeDescriptorAttr>(tbaaMapping.lookup(accessMD));332 if (offset)333 *offset = offsetCI->getZExtValue();334 if (isConstant)335 *isConstant = isConst;336 return true;337 };338 339 // Do a post-order walk over the TBAA Graph. Since a correct TBAA Graph is a340 // DAG, a post-order walk guarantees that we convert any metadata node we341 // depend on, prior to converting the current node.342 DenseSet<const llvm::MDNode *> seen;343 SmallVector<const llvm::MDNode *> workList;344 workList.push_back(node);345 while (!workList.empty()) {346 const llvm::MDNode *current = workList.back();347 if (tbaaMapping.contains(current)) {348 // Already converted. Just pop from the worklist.349 workList.pop_back();350 continue;351 }352 353 // If any child of this node is not yet converted, don't pop the current354 // node from the worklist but push the not-yet-converted children in the355 // front of the worklist.356 bool anyChildNotConverted = false;357 for (const llvm::MDOperand &operand : current->operands())358 if (auto *childNode = dyn_cast_or_null<const llvm::MDNode>(operand.get()))359 if (!tbaaMapping.contains(childNode)) {360 workList.push_back(childNode);361 anyChildNotConverted = true;362 }363 364 if (anyChildNotConverted) {365 // If this is the second time we failed to convert an element in the366 // worklist it must be because a child is dependent on it being converted367 // and we have a cycle in the graph. Cycles are not allowed in TBAA368 // graphs.369 if (!seen.insert(current).second)370 return emitError(loc) << "has cycle in TBAA graph: "371 << diagMD(current, llvmModule.get());372 373 continue;374 }375 376 // Otherwise simply import the current node.377 workList.pop_back();378 379 FailureOr<std::optional<StringRef>> rootNodeIdentity =380 getIdentityIfRootNode(current);381 if (succeeded(rootNodeIdentity)) {382 StringAttr stringAttr = *rootNodeIdentity383 ? builder.getStringAttr(**rootNodeIdentity)384 : nullptr;385 // The root nodes do not have operands, so we can create386 // the TBAARootAttr on the first walk.387 tbaaMapping.insert({current, builder.getAttr<TBAARootAttr>(stringAttr)});388 continue;389 }390 391 StringRef identity;392 SmallVector<TBAAMemberAttr> members;393 if (std::optional<bool> isValid =394 isTypeDescriptorNode(current, &identity, &members)) {395 assert(isValid.value() && "type descriptor node must be valid");396 397 tbaaMapping.insert({current, builder.getAttr<TBAATypeDescriptorAttr>(398 identity, members)});399 continue;400 }401 402 TBAATypeDescriptorAttr baseAttr, accessAttr;403 int64_t offset;404 bool isConstant;405 if (std::optional<bool> isValid =406 isTagNode(current, &baseAttr, &accessAttr, &offset, &isConstant)) {407 assert(isValid.value() && "access tag node must be valid");408 tbaaMapping.insert(409 {current, builder.getAttr<TBAATagAttr>(baseAttr, accessAttr, offset,410 isConstant)});411 continue;412 }413 414 return emitError(loc) << "unsupported TBAA node format: "415 << diagMD(current, llvmModule.get());416 }417 return success();418}419 420LogicalResult421ModuleImport::processAccessGroupMetadata(const llvm::MDNode *node) {422 Location loc = mlirModule.getLoc();423 if (failed(loopAnnotationImporter->translateAccessGroup(node, loc)))424 return emitError(loc) << "unsupported access group node: "425 << diagMD(node, llvmModule.get());426 return success();427}428 429LogicalResult430ModuleImport::processAliasScopeMetadata(const llvm::MDNode *node) {431 Location loc = mlirModule.getLoc();432 // Helper that verifies the node has a self reference operand.433 auto verifySelfRef = [](const llvm::MDNode *node) {434 return node->getNumOperands() != 0 &&435 node == dyn_cast<llvm::MDNode>(node->getOperand(0));436 };437 auto verifySelfRefOrString = [](const llvm::MDNode *node) {438 return node->getNumOperands() != 0 &&439 (node == dyn_cast<llvm::MDNode>(node->getOperand(0)) ||440 isa<llvm::MDString>(node->getOperand(0)));441 };442 // Helper that verifies the given operand is a string or does not exist.443 auto verifyDescription = [](const llvm::MDNode *node, unsigned idx) {444 return idx >= node->getNumOperands() ||445 isa<llvm::MDString>(node->getOperand(idx));446 };447 448 auto getIdAttr = [&](const llvm::MDNode *node) -> Attribute {449 if (verifySelfRef(node))450 return DistinctAttr::create(builder.getUnitAttr());451 452 auto *name = cast<llvm::MDString>(node->getOperand(0));453 return builder.getStringAttr(name->getString());454 };455 456 // Helper that creates an alias scope domain attribute.457 auto createAliasScopeDomainOp = [&](const llvm::MDNode *aliasDomain) {458 StringAttr description = nullptr;459 if (aliasDomain->getNumOperands() >= 2)460 if (auto *operand = dyn_cast<llvm::MDString>(aliasDomain->getOperand(1)))461 description = builder.getStringAttr(operand->getString());462 Attribute idAttr = getIdAttr(aliasDomain);463 return builder.getAttr<AliasScopeDomainAttr>(idAttr, description);464 };465 466 // Collect the alias scopes and domains to translate them.467 for (const llvm::MDOperand &operand : node->operands()) {468 if (const auto *scope = dyn_cast<llvm::MDNode>(operand)) {469 llvm::AliasScopeNode aliasScope(scope);470 const llvm::MDNode *domain = aliasScope.getDomain();471 472 // Verify the scope node points to valid scope metadata which includes473 // verifying its domain. Perform the verification before looking it up in474 // the alias scope mapping since it could have been inserted as a domain475 // node before.476 if (!verifySelfRefOrString(scope) || !domain ||477 !verifyDescription(scope, 2))478 return emitError(loc) << "unsupported alias scope node: "479 << diagMD(scope, llvmModule.get());480 if (!verifySelfRefOrString(domain) || !verifyDescription(domain, 1))481 return emitError(loc) << "unsupported alias domain node: "482 << diagMD(domain, llvmModule.get());483 484 if (aliasScopeMapping.contains(scope))485 continue;486 487 // Convert the domain metadata node if it has not been translated before.488 auto it = aliasScopeMapping.find(aliasScope.getDomain());489 if (it == aliasScopeMapping.end()) {490 auto aliasScopeDomainOp = createAliasScopeDomainOp(domain);491 it = aliasScopeMapping.try_emplace(domain, aliasScopeDomainOp).first;492 }493 494 // Convert the scope metadata node if it has not been converted before.495 StringAttr description = nullptr;496 if (!aliasScope.getName().empty())497 description = builder.getStringAttr(aliasScope.getName());498 Attribute idAttr = getIdAttr(scope);499 auto aliasScopeOp = builder.getAttr<AliasScopeAttr>(500 idAttr, cast<AliasScopeDomainAttr>(it->second), description);501 502 aliasScopeMapping.try_emplace(aliasScope.getNode(), aliasScopeOp);503 }504 }505 return success();506}507 508FailureOr<SmallVector<AliasScopeAttr>>509ModuleImport::lookupAliasScopeAttrs(const llvm::MDNode *node) const {510 SmallVector<AliasScopeAttr> aliasScopes;511 aliasScopes.reserve(node->getNumOperands());512 for (const llvm::MDOperand &operand : node->operands()) {513 auto *node = cast<llvm::MDNode>(operand.get());514 aliasScopes.push_back(515 dyn_cast_or_null<AliasScopeAttr>(aliasScopeMapping.lookup(node)));516 }517 // Return failure if one of the alias scope lookups failed.518 if (llvm::is_contained(aliasScopes, nullptr))519 return failure();520 return aliasScopes;521}522 523void ModuleImport::addDebugIntrinsic(llvm::CallInst *intrinsic) {524 debugIntrinsics.insert(intrinsic);525}526 527void ModuleImport::addDebugRecord(llvm::DbgVariableRecord *dbgRecord) {528 if (!dbgRecords.contains(dbgRecord))529 dbgRecords.insert(dbgRecord);530}531 532static Attribute convertCGProfileModuleFlagValue(ModuleOp mlirModule,533 llvm::MDTuple *mdTuple) {534 auto getLLVMFunction =535 [&](const llvm::MDOperand &funcMDO) -> llvm::Function * {536 auto *f = cast_or_null<llvm::ValueAsMetadata>(funcMDO);537 // nullptr is a valid value for the function pointer.538 if (!f)539 return nullptr;540 auto *llvmFn = cast<llvm::Function>(f->getValue()->stripPointerCasts());541 return llvmFn;542 };543 544 // Each tuple element becomes one ModuleFlagCGProfileEntryAttr.545 SmallVector<Attribute> cgProfile;546 for (unsigned i = 0; i < mdTuple->getNumOperands(); i++) {547 const llvm::MDOperand &mdo = mdTuple->getOperand(i);548 auto *cgEntry = cast<llvm::MDNode>(mdo);549 llvm::Constant *llvmConstant =550 cast<llvm::ConstantAsMetadata>(cgEntry->getOperand(2))->getValue();551 uint64_t count = cast<llvm::ConstantInt>(llvmConstant)->getZExtValue();552 auto *fromFn = getLLVMFunction(cgEntry->getOperand(0));553 auto *toFn = getLLVMFunction(cgEntry->getOperand(1));554 // FlatSymbolRefAttr::get(mlirModule->getContext(), llvmFn->getName());555 cgProfile.push_back(ModuleFlagCGProfileEntryAttr::get(556 mlirModule->getContext(),557 fromFn ? FlatSymbolRefAttr::get(mlirModule->getContext(),558 fromFn->getName())559 : nullptr,560 toFn ? FlatSymbolRefAttr::get(mlirModule->getContext(), toFn->getName())561 : nullptr,562 count));563 }564 return ArrayAttr::get(mlirModule->getContext(), cgProfile);565}566 567/// Extract a two element `MDTuple` from a `MDOperand`. Emit a warning in case568/// something else is found.569static llvm::MDTuple *getTwoElementMDTuple(ModuleOp mlirModule,570 const llvm::Module *llvmModule,571 const llvm::MDOperand &md) {572 auto *tupleEntry = dyn_cast_or_null<llvm::MDTuple>(md);573 if (!tupleEntry || tupleEntry->getNumOperands() != 2)574 emitWarning(mlirModule.getLoc())575 << "expected 2-element tuple metadata: " << diagMD(md, llvmModule);576 return tupleEntry;577}578 579/// Extract a constant metadata value from a two element tuple (<key, value>).580/// Return nullptr if requirements are not met. A warning is emitted if the581/// `matchKey` is different from the tuple's key.582static llvm::ConstantAsMetadata *getConstantMDFromKeyValueTuple(583 ModuleOp mlirModule, const llvm::Module *llvmModule,584 const llvm::MDOperand &md, StringRef matchKey, bool optional = false) {585 llvm::MDTuple *tupleEntry = getTwoElementMDTuple(mlirModule, llvmModule, md);586 if (!tupleEntry)587 return nullptr;588 auto *keyMD = dyn_cast<llvm::MDString>(tupleEntry->getOperand(0));589 if (!keyMD || keyMD->getString() != matchKey) {590 if (!optional)591 emitWarning(mlirModule.getLoc())592 << "expected '" << matchKey << "' key, but found: "593 << diagMD(tupleEntry->getOperand(0), llvmModule);594 return nullptr;595 }596 597 return dyn_cast<llvm::ConstantAsMetadata>(tupleEntry->getOperand(1));598}599 600/// Extract an integer value from a two element tuple (<key, value>).601/// Fail if requirements are not met. A warning is emitted if the602/// found value isn't a LLVM constant integer.603static FailureOr<uint64_t>604convertInt64FromKeyValueTuple(ModuleOp mlirModule,605 const llvm::Module *llvmModule,606 const llvm::MDOperand &md, StringRef matchKey) {607 llvm::ConstantAsMetadata *valMD =608 getConstantMDFromKeyValueTuple(mlirModule, llvmModule, md, matchKey);609 if (!valMD)610 return failure();611 612 if (auto *cstInt = dyn_cast<llvm::ConstantInt>(valMD->getValue()))613 return cstInt->getZExtValue();614 615 emitWarning(mlirModule.getLoc())616 << "expected integer metadata value for key '" << matchKey617 << "': " << diagMD(md, llvmModule);618 return failure();619}620 621static std::optional<ProfileSummaryFormatKind>622convertProfileSummaryFormat(ModuleOp mlirModule, const llvm::Module *llvmModule,623 const llvm::MDOperand &formatMD) {624 auto *tupleEntry = getTwoElementMDTuple(mlirModule, llvmModule, formatMD);625 if (!tupleEntry)626 return std::nullopt;627 628 llvm::MDString *keyMD = dyn_cast<llvm::MDString>(tupleEntry->getOperand(0));629 if (!keyMD || keyMD->getString() != "ProfileFormat") {630 emitWarning(mlirModule.getLoc())631 << "expected 'ProfileFormat' key: "632 << diagMD(tupleEntry->getOperand(0), llvmModule);633 return std::nullopt;634 }635 636 llvm::MDString *valMD = dyn_cast<llvm::MDString>(tupleEntry->getOperand(1));637 std::optional<ProfileSummaryFormatKind> fmtKind =638 symbolizeProfileSummaryFormatKind(valMD->getString());639 if (!fmtKind) {640 emitWarning(mlirModule.getLoc())641 << "expected 'SampleProfile', 'InstrProf' or 'CSInstrProf' values, "642 "but found: "643 << diagMD(valMD, llvmModule);644 return std::nullopt;645 }646 647 return fmtKind;648}649 650static FailureOr<SmallVector<ModuleFlagProfileSummaryDetailedAttr>>651convertProfileSummaryDetailed(ModuleOp mlirModule,652 const llvm::Module *llvmModule,653 const llvm::MDOperand &summaryMD) {654 auto *tupleEntry = getTwoElementMDTuple(mlirModule, llvmModule, summaryMD);655 if (!tupleEntry)656 return failure();657 658 llvm::MDString *keyMD = dyn_cast<llvm::MDString>(tupleEntry->getOperand(0));659 if (!keyMD || keyMD->getString() != "DetailedSummary") {660 emitWarning(mlirModule.getLoc())661 << "expected 'DetailedSummary' key: "662 << diagMD(tupleEntry->getOperand(0), llvmModule);663 return failure();664 }665 666 llvm::MDTuple *entriesMD = dyn_cast<llvm::MDTuple>(tupleEntry->getOperand(1));667 if (!entriesMD) {668 emitWarning(mlirModule.getLoc())669 << "expected tuple value for 'DetailedSummary' key: "670 << diagMD(tupleEntry->getOperand(1), llvmModule);671 return failure();672 }673 674 SmallVector<ModuleFlagProfileSummaryDetailedAttr> detailedSummary;675 for (auto &&entry : entriesMD->operands()) {676 llvm::MDTuple *entryMD = dyn_cast<llvm::MDTuple>(entry);677 if (!entryMD || entryMD->getNumOperands() != 3) {678 emitWarning(mlirModule.getLoc())679 << "'DetailedSummary' entry expects 3 operands: "680 << diagMD(entry, llvmModule);681 return failure();682 }683 684 auto *op0 = dyn_cast<llvm::ConstantAsMetadata>(entryMD->getOperand(0));685 auto *op1 = dyn_cast<llvm::ConstantAsMetadata>(entryMD->getOperand(1));686 auto *op2 = dyn_cast<llvm::ConstantAsMetadata>(entryMD->getOperand(2));687 if (!op0 || !op1 || !op2) {688 emitWarning(mlirModule.getLoc())689 << "expected only integer entries in 'DetailedSummary': "690 << diagMD(entry, llvmModule);691 return failure();692 }693 694 auto detaildSummaryEntry = ModuleFlagProfileSummaryDetailedAttr::get(695 mlirModule->getContext(),696 cast<llvm::ConstantInt>(op0->getValue())->getZExtValue(),697 cast<llvm::ConstantInt>(op1->getValue())->getZExtValue(),698 cast<llvm::ConstantInt>(op2->getValue())->getZExtValue());699 detailedSummary.push_back(detaildSummaryEntry);700 }701 return detailedSummary;702}703 704static Attribute705convertProfileSummaryModuleFlagValue(ModuleOp mlirModule,706 const llvm::Module *llvmModule,707 llvm::MDTuple *mdTuple) {708 unsigned profileNumEntries = mdTuple->getNumOperands();709 if (profileNumEntries < 8) {710 emitWarning(mlirModule.getLoc())711 << "expected at 8 entries in 'ProfileSummary': "712 << diagMD(mdTuple, llvmModule);713 return nullptr;714 }715 716 unsigned summayIdx = 0;717 auto checkOptionalPosition = [&](const llvm::MDOperand &md,718 StringRef matchKey) -> LogicalResult {719 // Make sure we won't step over the bound of the array of summary entries.720 // Since (non-optional) DetailedSummary always comes last, the next entry in721 // the tuple operand array must exist.722 if (summayIdx + 1 >= profileNumEntries) {723 emitWarning(mlirModule.getLoc())724 << "the last summary entry is '" << matchKey725 << "', expected 'DetailedSummary': " << diagMD(md, llvmModule);726 return failure();727 }728 729 return success();730 };731 732 auto getOptIntValue =733 [&](const llvm::MDOperand &md,734 StringRef matchKey) -> FailureOr<std::optional<uint64_t>> {735 if (!getConstantMDFromKeyValueTuple(mlirModule, llvmModule, md, matchKey,736 /*optional=*/true))737 return FailureOr<std::optional<uint64_t>>(std::nullopt);738 if (checkOptionalPosition(md, matchKey).failed())739 return failure();740 FailureOr<uint64_t> val =741 convertInt64FromKeyValueTuple(mlirModule, llvmModule, md, matchKey);742 if (failed(val))743 return failure();744 return val;745 };746 747 auto getOptDoubleValue = [&](const llvm::MDOperand &md,748 StringRef matchKey) -> FailureOr<FloatAttr> {749 auto *valMD = getConstantMDFromKeyValueTuple(mlirModule, llvmModule, md,750 matchKey, /*optional=*/true);751 if (!valMD)752 return FloatAttr{};753 if (auto *cstFP = dyn_cast<llvm::ConstantFP>(valMD->getValue())) {754 if (checkOptionalPosition(md, matchKey).failed())755 return failure();756 return FloatAttr::get(Float64Type::get(mlirModule.getContext()),757 cstFP->getValueAPF());758 }759 emitWarning(mlirModule.getLoc())760 << "expected double metadata value for key '" << matchKey761 << "': " << diagMD(md, llvmModule);762 return failure();763 };764 765 // Build ModuleFlagProfileSummaryAttr by sequentially fetching elements in766 // a fixed order: format, total count, etc.767 std::optional<ProfileSummaryFormatKind> format = convertProfileSummaryFormat(768 mlirModule, llvmModule, mdTuple->getOperand(summayIdx++));769 if (!format.has_value())770 return nullptr;771 772 FailureOr<uint64_t> totalCount = convertInt64FromKeyValueTuple(773 mlirModule, llvmModule, mdTuple->getOperand(summayIdx++), "TotalCount");774 if (failed(totalCount))775 return nullptr;776 777 FailureOr<uint64_t> maxCount = convertInt64FromKeyValueTuple(778 mlirModule, llvmModule, mdTuple->getOperand(summayIdx++), "MaxCount");779 if (failed(maxCount))780 return nullptr;781 782 FailureOr<uint64_t> maxInternalCount = convertInt64FromKeyValueTuple(783 mlirModule, llvmModule, mdTuple->getOperand(summayIdx++),784 "MaxInternalCount");785 if (failed(maxInternalCount))786 return nullptr;787 788 FailureOr<uint64_t> maxFunctionCount = convertInt64FromKeyValueTuple(789 mlirModule, llvmModule, mdTuple->getOperand(summayIdx++),790 "MaxFunctionCount");791 if (failed(maxFunctionCount))792 return nullptr;793 794 FailureOr<uint64_t> numCounts = convertInt64FromKeyValueTuple(795 mlirModule, llvmModule, mdTuple->getOperand(summayIdx++), "NumCounts");796 if (failed(numCounts))797 return nullptr;798 799 FailureOr<uint64_t> numFunctions = convertInt64FromKeyValueTuple(800 mlirModule, llvmModule, mdTuple->getOperand(summayIdx++), "NumFunctions");801 if (failed(numFunctions))802 return nullptr;803 804 // Handle optional keys.805 FailureOr<std::optional<uint64_t>> isPartialProfile =806 getOptIntValue(mdTuple->getOperand(summayIdx), "IsPartialProfile");807 if (failed(isPartialProfile))808 return nullptr;809 if (isPartialProfile->has_value())810 summayIdx++;811 812 FailureOr<FloatAttr> partialProfileRatio =813 getOptDoubleValue(mdTuple->getOperand(summayIdx), "PartialProfileRatio");814 if (failed(partialProfileRatio))815 return nullptr;816 if (*partialProfileRatio)817 summayIdx++;818 819 // Handle detailed summary.820 FailureOr<SmallVector<ModuleFlagProfileSummaryDetailedAttr>> detailed =821 convertProfileSummaryDetailed(mlirModule, llvmModule,822 mdTuple->getOperand(summayIdx));823 if (failed(detailed))824 return nullptr;825 826 // Build the final profile summary attribute.827 return ModuleFlagProfileSummaryAttr::get(828 mlirModule->getContext(), *format, *totalCount, *maxCount,829 *maxInternalCount, *maxFunctionCount, *numCounts, *numFunctions,830 *isPartialProfile, *partialProfileRatio, *detailed);831}832 833/// Invoke specific handlers for each known module flag value, returns nullptr834/// if the key is unknown or unimplemented.835static Attribute836convertModuleFlagValueFromMDTuple(ModuleOp mlirModule,837 const llvm::Module *llvmModule, StringRef key,838 llvm::MDTuple *mdTuple) {839 if (key == LLVMDialect::getModuleFlagKeyCGProfileName())840 return convertCGProfileModuleFlagValue(mlirModule, mdTuple);841 if (key == LLVMDialect::getModuleFlagKeyProfileSummaryName())842 return convertProfileSummaryModuleFlagValue(mlirModule, llvmModule,843 mdTuple);844 return nullptr;845}846 847LogicalResult ModuleImport::convertModuleFlagsMetadata() {848 SmallVector<llvm::Module::ModuleFlagEntry> llvmModuleFlags;849 llvmModule->getModuleFlagsMetadata(llvmModuleFlags);850 851 SmallVector<Attribute> moduleFlags;852 for (const auto [behavior, key, val] : llvmModuleFlags) {853 Attribute valAttr = nullptr;854 if (auto *constInt = llvm::mdconst::dyn_extract<llvm::ConstantInt>(val)) {855 valAttr = builder.getI32IntegerAttr(constInt->getZExtValue());856 } else if (auto *mdString = dyn_cast<llvm::MDString>(val)) {857 valAttr = builder.getStringAttr(mdString->getString());858 } else if (auto *mdTuple = dyn_cast<llvm::MDTuple>(val)) {859 valAttr = convertModuleFlagValueFromMDTuple(mlirModule, llvmModule.get(),860 key->getString(), mdTuple);861 }862 863 if (!valAttr) {864 emitWarning(mlirModule.getLoc())865 << "unsupported module flag value for key '" << key->getString()866 << "' : " << diagMD(val, llvmModule.get());867 continue;868 }869 870 moduleFlags.push_back(builder.getAttr<ModuleFlagAttr>(871 convertModFlagBehaviorFromLLVM(behavior),872 builder.getStringAttr(key->getString()), valAttr));873 }874 875 if (!moduleFlags.empty())876 LLVM::ModuleFlagsOp::create(builder, mlirModule.getLoc(),877 builder.getArrayAttr(moduleFlags));878 879 return success();880}881 882LogicalResult ModuleImport::convertLinkerOptionsMetadata() {883 for (const llvm::NamedMDNode &named : llvmModule->named_metadata()) {884 if (named.getName() != "llvm.linker.options")885 continue;886 // llvm.linker.options operands are lists of strings.887 for (const llvm::MDNode *node : named.operands()) {888 SmallVector<StringRef> options;889 options.reserve(node->getNumOperands());890 for (const llvm::MDOperand &option : node->operands())891 options.push_back(cast<llvm::MDString>(option)->getString());892 LLVM::LinkerOptionsOp::create(builder, mlirModule.getLoc(),893 builder.getStrArrayAttr(options));894 }895 }896 return success();897}898 899LogicalResult ModuleImport::convertDependentLibrariesMetadata() {900 for (const llvm::NamedMDNode &named : llvmModule->named_metadata()) {901 if (named.getName() != "llvm.dependent-libraries")902 continue;903 SmallVector<StringRef> libraries;904 for (const llvm::MDNode *node : named.operands()) {905 if (node->getNumOperands() == 1)906 if (auto *mdString = dyn_cast<llvm::MDString>(node->getOperand(0)))907 libraries.push_back(mdString->getString());908 }909 if (!libraries.empty())910 mlirModule->setAttr(LLVM::LLVMDialect::getDependentLibrariesAttrName(),911 builder.getStrArrayAttr(libraries));912 }913 return success();914}915 916LogicalResult ModuleImport::convertIdentMetadata() {917 for (const llvm::NamedMDNode &named : llvmModule->named_metadata()) {918 // llvm.ident should have a single operand. That operand is itself an919 // MDNode with a single string operand.920 if (named.getName() != LLVMDialect::getIdentAttrName())921 continue;922 923 if (named.getNumOperands() == 1)924 if (auto *md = dyn_cast<llvm::MDNode>(named.getOperand(0)))925 if (md->getNumOperands() == 1)926 if (auto *mdStr = dyn_cast<llvm::MDString>(md->getOperand(0)))927 mlirModule->setAttr(LLVMDialect::getIdentAttrName(),928 builder.getStringAttr(mdStr->getString()));929 }930 return success();931}932 933LogicalResult ModuleImport::convertCommandlineMetadata() {934 for (const llvm::NamedMDNode &nmd : llvmModule->named_metadata()) {935 // llvm.commandline should have a single operand. That operand is itself an936 // MDNode with a single string operand.937 if (nmd.getName() != LLVMDialect::getCommandlineAttrName())938 continue;939 940 if (nmd.getNumOperands() == 1)941 if (auto *md = dyn_cast<llvm::MDNode>(nmd.getOperand(0)))942 if (md->getNumOperands() == 1)943 if (auto *mdStr = dyn_cast<llvm::MDString>(md->getOperand(0)))944 mlirModule->setAttr(LLVMDialect::getCommandlineAttrName(),945 builder.getStringAttr(mdStr->getString()));946 }947 return success();948}949 950LogicalResult ModuleImport::convertMetadata() {951 OpBuilder::InsertionGuard guard(builder);952 builder.setInsertionPointToEnd(mlirModule.getBody());953 for (const llvm::Function &func : llvmModule->functions()) {954 for (const llvm::Instruction &inst : llvm::instructions(func)) {955 // Convert access group metadata nodes.956 if (llvm::MDNode *node =957 inst.getMetadata(llvm::LLVMContext::MD_access_group))958 if (failed(processAccessGroupMetadata(node)))959 return failure();960 961 // Convert alias analysis metadata nodes.962 llvm::AAMDNodes aliasAnalysisNodes = inst.getAAMetadata();963 if (!aliasAnalysisNodes)964 continue;965 if (aliasAnalysisNodes.TBAA)966 if (failed(processTBAAMetadata(aliasAnalysisNodes.TBAA)))967 return failure();968 if (aliasAnalysisNodes.Scope)969 if (failed(processAliasScopeMetadata(aliasAnalysisNodes.Scope)))970 return failure();971 if (aliasAnalysisNodes.NoAlias)972 if (failed(processAliasScopeMetadata(aliasAnalysisNodes.NoAlias)))973 return failure();974 }975 }976 if (failed(convertLinkerOptionsMetadata()))977 return failure();978 if (failed(convertDependentLibrariesMetadata()))979 return failure();980 if (failed(convertModuleFlagsMetadata()))981 return failure();982 if (failed(convertIdentMetadata()))983 return failure();984 if (failed(convertCommandlineMetadata()))985 return failure();986 return success();987}988 989void ModuleImport::processComdat(const llvm::Comdat *comdat) {990 if (comdatMapping.contains(comdat))991 return;992 993 ComdatOp comdatOp = getGlobalComdatOp();994 OpBuilder::InsertionGuard guard(builder);995 builder.setInsertionPointToEnd(&comdatOp.getBody().back());996 auto selectorOp = ComdatSelectorOp::create(997 builder, mlirModule.getLoc(), comdat->getName(),998 convertComdatFromLLVM(comdat->getSelectionKind()));999 auto symbolRef =1000 SymbolRefAttr::get(builder.getContext(), getGlobalComdatOpName(),1001 FlatSymbolRefAttr::get(selectorOp.getSymNameAttr()));1002 comdatMapping.try_emplace(comdat, symbolRef);1003}1004 1005LogicalResult ModuleImport::convertComdats() {1006 for (llvm::GlobalVariable &globalVar : llvmModule->globals())1007 if (globalVar.hasComdat())1008 processComdat(globalVar.getComdat());1009 for (llvm::Function &func : llvmModule->functions())1010 if (func.hasComdat())1011 processComdat(func.getComdat());1012 return success();1013}1014 1015LogicalResult ModuleImport::convertGlobals() {1016 for (llvm::GlobalVariable &globalVar : llvmModule->globals()) {1017 if (globalVar.getName() == getGlobalCtorsVarName() ||1018 globalVar.getName() == getGlobalDtorsVarName()) {1019 if (failed(convertGlobalCtorsAndDtors(&globalVar))) {1020 return emitError(UnknownLoc::get(context))1021 << "unhandled global variable: " << diag(globalVar);1022 }1023 continue;1024 }1025 if (failed(convertGlobal(&globalVar))) {1026 return emitError(UnknownLoc::get(context))1027 << "unhandled global variable: " << diag(globalVar);1028 }1029 }1030 return success();1031}1032 1033LogicalResult ModuleImport::convertAliases() {1034 for (llvm::GlobalAlias &alias : llvmModule->aliases()) {1035 if (failed(convertAlias(&alias))) {1036 return emitError(UnknownLoc::get(context))1037 << "unhandled global alias: " << diag(alias);1038 }1039 }1040 return success();1041}1042 1043LogicalResult ModuleImport::convertIFuncs() {1044 for (llvm::GlobalIFunc &ifunc : llvmModule->ifuncs()) {1045 if (failed(convertIFunc(&ifunc))) {1046 return emitError(UnknownLoc::get(context))1047 << "unhandled global ifunc: " << diag(ifunc);1048 }1049 }1050 return success();1051}1052 1053LogicalResult ModuleImport::convertDataLayout() {1054 Location loc = mlirModule.getLoc();1055 DataLayoutImporter dataLayoutImporter(1056 context, llvmModule->getDataLayout().getStringRepresentation());1057 if (!dataLayoutImporter.getDataLayoutSpec())1058 return emitError(loc, "cannot translate data layout: ")1059 << dataLayoutImporter.getLastToken();1060 1061 for (StringRef token : dataLayoutImporter.getUnhandledTokens())1062 emitWarning(loc, "unhandled data layout token: ") << token;1063 1064 mlirModule->setAttr(DLTIDialect::kDataLayoutAttrName,1065 dataLayoutImporter.getDataLayoutSpec());1066 return success();1067}1068 1069void ModuleImport::convertTargetTriple() {1070 mlirModule->setAttr(1071 LLVM::LLVMDialect::getTargetTripleAttrName(),1072 builder.getStringAttr(llvmModule->getTargetTriple().str()));1073}1074 1075void ModuleImport::convertModuleLevelAsm() {1076 llvm::StringRef asmStr = llvmModule->getModuleInlineAsm();1077 llvm::SmallVector<mlir::Attribute> asmArrayAttr;1078 1079 for (llvm::StringRef line : llvm::split(asmStr, '\n'))1080 if (!line.empty())1081 asmArrayAttr.push_back(builder.getStringAttr(line));1082 1083 mlirModule->setAttr(LLVM::LLVMDialect::getModuleLevelAsmAttrName(),1084 builder.getArrayAttr(asmArrayAttr));1085}1086 1087LogicalResult ModuleImport::convertFunctions() {1088 for (llvm::Function &func : llvmModule->functions())1089 if (failed(processFunction(&func)))1090 return failure();1091 return success();1092}1093 1094void ModuleImport::setNonDebugMetadataAttrs(llvm::Instruction *inst,1095 Operation *op) {1096 SmallVector<std::pair<unsigned, llvm::MDNode *>> allMetadata;1097 inst->getAllMetadataOtherThanDebugLoc(allMetadata);1098 for (auto &[kind, node] : allMetadata) {1099 if (!iface.isConvertibleMetadata(kind))1100 continue;1101 if (failed(iface.setMetadataAttrs(builder, kind, node, op, *this))) {1102 if (emitExpensiveWarnings) {1103 Location loc = debugImporter->translateLoc(inst->getDebugLoc());1104 emitWarning(loc) << "unhandled metadata: "1105 << diagMD(node, llvmModule.get()) << " on "1106 << diag(*inst);1107 }1108 }1109 }1110}1111 1112void ModuleImport::setIntegerOverflowFlags(llvm::Instruction *inst,1113 Operation *op) const {1114 auto iface = cast<IntegerOverflowFlagsInterface>(op);1115 1116 IntegerOverflowFlags value = {};1117 value = bitEnumSet(value, IntegerOverflowFlags::nsw, inst->hasNoSignedWrap());1118 value =1119 bitEnumSet(value, IntegerOverflowFlags::nuw, inst->hasNoUnsignedWrap());1120 1121 iface.setOverflowFlags(value);1122}1123 1124void ModuleImport::setExactFlag(llvm::Instruction *inst, Operation *op) const {1125 auto iface = cast<ExactFlagInterface>(op);1126 1127 iface.setIsExact(inst->isExact());1128}1129 1130void ModuleImport::setDisjointFlag(llvm::Instruction *inst,1131 Operation *op) const {1132 auto iface = cast<DisjointFlagInterface>(op);1133 auto *instDisjoint = cast<llvm::PossiblyDisjointInst>(inst);1134 1135 iface.setIsDisjoint(instDisjoint->isDisjoint());1136}1137 1138void ModuleImport::setNonNegFlag(llvm::Instruction *inst, Operation *op) const {1139 auto iface = cast<NonNegFlagInterface>(op);1140 1141 iface.setNonNeg(inst->hasNonNeg());1142}1143 1144void ModuleImport::setFastmathFlagsAttr(llvm::Instruction *inst,1145 Operation *op) const {1146 auto iface = cast<FastmathFlagsInterface>(op);1147 1148 // Even if the imported operation implements the fastmath interface, the1149 // original instruction may not have fastmath flags set. Exit if an1150 // instruction, such as a non floating-point function call, does not have1151 // fastmath flags.1152 if (!isa<llvm::FPMathOperator>(inst))1153 return;1154 llvm::FastMathFlags flags = inst->getFastMathFlags();1155 1156 // Set the fastmath bits flag-by-flag.1157 FastmathFlags value = {};1158 value = bitEnumSet(value, FastmathFlags::nnan, flags.noNaNs());1159 value = bitEnumSet(value, FastmathFlags::ninf, flags.noInfs());1160 value = bitEnumSet(value, FastmathFlags::nsz, flags.noSignedZeros());1161 value = bitEnumSet(value, FastmathFlags::arcp, flags.allowReciprocal());1162 value = bitEnumSet(value, FastmathFlags::contract, flags.allowContract());1163 value = bitEnumSet(value, FastmathFlags::afn, flags.approxFunc());1164 value = bitEnumSet(value, FastmathFlags::reassoc, flags.allowReassoc());1165 FastmathFlagsAttr attr = FastmathFlagsAttr::get(builder.getContext(), value);1166 iface->setAttr(iface.getFastmathAttrName(), attr);1167}1168 1169/// Returns `type` if it is a builtin integer or floating-point vector type that1170/// can be used to create an attribute or nullptr otherwise. If provided,1171/// `arrayShape` is added to the shape of the vector to create an attribute that1172/// matches an array of vectors.1173static Type getVectorTypeForAttr(Type type, ArrayRef<int64_t> arrayShape = {}) {1174 if (!LLVM::isCompatibleVectorType(type))1175 return {};1176 1177 llvm::ElementCount numElements = LLVM::getVectorNumElements(type);1178 if (numElements.isScalable()) {1179 emitError(UnknownLoc::get(type.getContext()))1180 << "scalable vectors not supported";1181 return {};1182 }1183 1184 // An LLVM dialect vector can only contain scalars.1185 Type elementType = cast<VectorType>(type).getElementType();1186 if (!elementType.isIntOrFloat())1187 return {};1188 1189 SmallVector<int64_t> shape(arrayShape);1190 shape.push_back(numElements.getKnownMinValue());1191 return VectorType::get(shape, elementType);1192}1193 1194Type ModuleImport::getBuiltinTypeForAttr(Type type) {1195 if (!type)1196 return {};1197 1198 // Return builtin integer and floating-point types as is.1199 if (type.isIntOrFloat())1200 return type;1201 1202 // Return builtin vectors of integer and floating-point types as is.1203 if (Type vectorType = getVectorTypeForAttr(type))1204 return vectorType;1205 1206 // Multi-dimensional array types are converted to tensors or vectors,1207 // depending on the innermost type being a scalar or a vector.1208 SmallVector<int64_t> arrayShape;1209 while (auto arrayType = dyn_cast<LLVMArrayType>(type)) {1210 arrayShape.push_back(arrayType.getNumElements());1211 type = arrayType.getElementType();1212 }1213 if (type.isIntOrFloat())1214 return RankedTensorType::get(arrayShape, type);1215 return getVectorTypeForAttr(type, arrayShape);1216}1217 1218/// Returns an integer or float attribute for the provided scalar constant1219/// `constScalar` or nullptr if the conversion fails.1220static TypedAttr getScalarConstantAsAttr(OpBuilder &builder,1221 llvm::Constant *constScalar) {1222 MLIRContext *context = builder.getContext();1223 1224 // Convert scalar integers.1225 if (auto *constInt = dyn_cast<llvm::ConstantInt>(constScalar)) {1226 return builder.getIntegerAttr(1227 IntegerType::get(context, constInt->getBitWidth()),1228 constInt->getValue());1229 }1230 1231 // Convert scalar floats.1232 if (auto *constFloat = dyn_cast<llvm::ConstantFP>(constScalar)) {1233 llvm::Type *type = constFloat->getType();1234 FloatType floatType =1235 type->isBFloatTy()1236 ? BFloat16Type::get(context)1237 : LLVM::detail::getFloatType(context, type->getScalarSizeInBits());1238 if (!floatType) {1239 emitError(UnknownLoc::get(builder.getContext()))1240 << "unexpected floating-point type";1241 return {};1242 }1243 return builder.getFloatAttr(floatType, constFloat->getValueAPF());1244 }1245 return {};1246}1247 1248/// Returns an integer or float attribute array for the provided constant1249/// sequence `constSequence` or nullptr if the conversion fails.1250static SmallVector<Attribute>1251getSequenceConstantAsAttrs(OpBuilder &builder,1252 llvm::ConstantDataSequential *constSequence) {1253 SmallVector<Attribute> elementAttrs;1254 elementAttrs.reserve(constSequence->getNumElements());1255 for (auto idx : llvm::seq<int64_t>(0, constSequence->getNumElements())) {1256 llvm::Constant *constElement = constSequence->getElementAsConstant(idx);1257 elementAttrs.push_back(getScalarConstantAsAttr(builder, constElement));1258 }1259 return elementAttrs;1260}1261 1262Attribute ModuleImport::getConstantAsAttr(llvm::Constant *constant) {1263 // Convert scalar constants.1264 if (Attribute scalarAttr = getScalarConstantAsAttr(builder, constant))1265 return scalarAttr;1266 1267 // Returns the static shape of the provided type if possible.1268 auto getConstantShape = [&](llvm::Type *type) {1269 return llvm::dyn_cast_if_present<ShapedType>(1270 getBuiltinTypeForAttr(convertType(type)));1271 };1272 1273 // Convert one-dimensional constant arrays or vectors that store 1/2/4/8-byte1274 // integer or half/bfloat/float/double values.1275 if (auto *constArray = dyn_cast<llvm::ConstantDataSequential>(constant)) {1276 if (constArray->isString())1277 return builder.getStringAttr(constArray->getAsString());1278 auto shape = getConstantShape(constArray->getType());1279 if (!shape)1280 return {};1281 // Convert splat constants to splat elements attributes.1282 auto *constVector = dyn_cast<llvm::ConstantDataVector>(constant);1283 if (constVector && constVector->isSplat()) {1284 // A vector is guaranteed to have at least size one.1285 Attribute splatAttr = getScalarConstantAsAttr(1286 builder, constVector->getElementAsConstant(0));1287 return SplatElementsAttr::get(shape, splatAttr);1288 }1289 // Convert non-splat constants to dense elements attributes.1290 SmallVector<Attribute> elementAttrs =1291 getSequenceConstantAsAttrs(builder, constArray);1292 return DenseElementsAttr::get(shape, elementAttrs);1293 }1294 1295 // Convert multi-dimensional constant aggregates that store all kinds of1296 // integer and floating-point types.1297 if (auto *constAggregate = dyn_cast<llvm::ConstantAggregate>(constant)) {1298 auto shape = getConstantShape(constAggregate->getType());1299 if (!shape)1300 return {};1301 // Collect the aggregate elements in depths first order.1302 SmallVector<Attribute> elementAttrs;1303 SmallVector<llvm::Constant *> workList = {constAggregate};1304 while (!workList.empty()) {1305 llvm::Constant *current = workList.pop_back_val();1306 // Append any nested aggregates in reverse order to ensure the head1307 // element of the nested aggregates is at the back of the work list.1308 if (auto *constAggregate = dyn_cast<llvm::ConstantAggregate>(current)) {1309 for (auto idx :1310 reverse(llvm::seq<int64_t>(0, constAggregate->getNumOperands())))1311 workList.push_back(constAggregate->getAggregateElement(idx));1312 continue;1313 }1314 // Append the elements of nested constant arrays or vectors that store1315 // 1/2/4/8-byte integer or half/bfloat/float/double values.1316 if (auto *constArray = dyn_cast<llvm::ConstantDataSequential>(current)) {1317 SmallVector<Attribute> attrs =1318 getSequenceConstantAsAttrs(builder, constArray);1319 elementAttrs.append(attrs.begin(), attrs.end());1320 continue;1321 }1322 // Append nested scalar constants that store all kinds of integer and1323 // floating-point types.1324 if (Attribute scalarAttr = getScalarConstantAsAttr(builder, current)) {1325 elementAttrs.push_back(scalarAttr);1326 continue;1327 }1328 // Bail if the aggregate contains a unsupported constant type such as a1329 // constant expression.1330 return {};1331 }1332 return DenseElementsAttr::get(shape, elementAttrs);1333 }1334 1335 // Convert zero aggregates.1336 if (auto *constZero = dyn_cast<llvm::ConstantAggregateZero>(constant)) {1337 auto shape = llvm::dyn_cast_if_present<ShapedType>(1338 getBuiltinTypeForAttr(convertType(constZero->getType())));1339 if (!shape)1340 return {};1341 // Convert zero aggregates with a static shape to splat elements attributes.1342 Attribute splatAttr = builder.getZeroAttr(shape.getElementType());1343 assert(splatAttr && "expected non-null zero attribute for scalar types");1344 return SplatElementsAttr::get(shape, splatAttr);1345 }1346 return {};1347}1348 1349FlatSymbolRefAttr1350ModuleImport::getOrCreateNamelessSymbolName(llvm::GlobalVariable *globalVar) {1351 assert(globalVar->getName().empty() &&1352 "expected to work with a nameless global");1353 auto [it, success] = namelessGlobals.try_emplace(globalVar);1354 if (!success)1355 return it->second;1356 1357 // Make sure the symbol name does not clash with an existing symbol.1358 SmallString<128> globalName = SymbolTable::generateSymbolName<128>(1359 getNamelessGlobalPrefix(),1360 [this](StringRef newName) { return llvmModule->getNamedValue(newName); },1361 namelessGlobalId);1362 auto symbolRef = FlatSymbolRefAttr::get(context, globalName);1363 it->getSecond() = symbolRef;1364 return symbolRef;1365}1366 1367OpBuilder::InsertionGuard ModuleImport::setGlobalInsertionPoint() {1368 OpBuilder::InsertionGuard guard(builder);1369 if (globalInsertionOp)1370 builder.setInsertionPointAfter(globalInsertionOp);1371 else1372 builder.setInsertionPointToStart(mlirModule.getBody());1373 return guard;1374}1375 1376LogicalResult ModuleImport::convertAlias(llvm::GlobalAlias *alias) {1377 // Insert the alias after the last one or at the start of the module.1378 OpBuilder::InsertionGuard guard = setGlobalInsertionPoint();1379 1380 Type type = convertType(alias->getValueType());1381 AliasOp aliasOp = AliasOp::create(builder, mlirModule.getLoc(), type,1382 convertLinkageFromLLVM(alias->getLinkage()),1383 alias->getName(),1384 /*dsoLocal=*/alias->isDSOLocal(),1385 /*thread_local=*/alias->isThreadLocal(),1386 /*attrs=*/ArrayRef<NamedAttribute>());1387 globalInsertionOp = aliasOp;1388 1389 clearRegionState();1390 Block *block = builder.createBlock(&aliasOp.getInitializerRegion());1391 setConstantInsertionPointToStart(block);1392 FailureOr<Value> initializer = convertConstantExpr(alias->getAliasee());1393 if (failed(initializer))1394 return failure();1395 ReturnOp::create(builder, aliasOp.getLoc(), *initializer);1396 1397 if (alias->hasAtLeastLocalUnnamedAddr())1398 aliasOp.setUnnamedAddr(convertUnnamedAddrFromLLVM(alias->getUnnamedAddr()));1399 aliasOp.setVisibility_(convertVisibilityFromLLVM(alias->getVisibility()));1400 1401 return success();1402}1403 1404LogicalResult ModuleImport::convertIFunc(llvm::GlobalIFunc *ifunc) {1405 OpBuilder::InsertionGuard guard = setGlobalInsertionPoint();1406 1407 Type type = convertType(ifunc->getValueType());1408 llvm::Constant *resolver = ifunc->getResolver();1409 Type resolverType = convertType(resolver->getType());1410 IFuncOp::create(builder, mlirModule.getLoc(), ifunc->getName(), type,1411 resolver->getName(), resolverType,1412 convertLinkageFromLLVM(ifunc->getLinkage()),1413 ifunc->isDSOLocal(), ifunc->getAddressSpace(),1414 convertUnnamedAddrFromLLVM(ifunc->getUnnamedAddr()),1415 convertVisibilityFromLLVM(ifunc->getVisibility()));1416 return success();1417}1418 1419/// Converts LLVM string, integer, and enum attributes into MLIR attributes,1420/// skipping those in `attributesToSkip` and emitting a warning at `loc` for1421/// any other unsupported attributes.1422static ArrayAttr1423convertLLVMAttributesToMLIR(Location loc, MLIRContext *context,1424 llvm::AttributeSet attributes,1425 ArrayRef<StringLiteral> attributesToSkip = {}) {1426 SmallVector<Attribute> mlirAttributes;1427 for (llvm::Attribute attr : attributes) {1428 StringRef attrName;1429 if (attr.isStringAttribute())1430 attrName = attr.getKindAsString();1431 else1432 attrName = llvm::Attribute::getNameFromAttrKind(attr.getKindAsEnum());1433 if (llvm::is_contained(attributesToSkip, attrName))1434 continue;1435 1436 auto keyAttr = StringAttr::get(context, attrName);1437 if (attr.isStringAttribute()) {1438 StringRef val = attr.getValueAsString();1439 if (val.empty()) {1440 // For string attributes without values, add only the attribute name.1441 mlirAttributes.push_back(keyAttr);1442 continue;1443 }1444 // For string attributes with a value, create a [name, value] pair.1445 mlirAttributes.push_back(1446 ArrayAttr::get(context, {keyAttr, StringAttr::get(context, val)}));1447 continue;1448 }1449 if (attr.isIntAttribute()) {1450 // For integer attributes, convert the value to a string and create a1451 // [name, value] pair.1452 auto val = std::to_string(attr.getValueAsInt());1453 mlirAttributes.push_back(1454 ArrayAttr::get(context, {keyAttr, StringAttr::get(context, val)}));1455 continue;1456 }1457 if (attr.isEnumAttribute()) {1458 // For enum attributes, add only the attribute name.1459 mlirAttributes.push_back(keyAttr);1460 continue;1461 }1462 1463 emitWarning(loc)1464 << "'" << attrName1465 << "' attribute is invalid on current operation, skipping it";1466 }1467 return ArrayAttr::get(context, mlirAttributes);1468}1469 1470/// Converts LLVM attributes from `globalVar` into MLIR attributes and adds them1471/// to `globalOp` as target-specific attributes.1472static void processTargetSpecificAttrs(llvm::GlobalVariable *globalVar,1473 GlobalOp globalOp) {1474 ArrayAttr targetSpecificAttrs = convertLLVMAttributesToMLIR(1475 globalOp.getLoc(), globalOp.getContext(), globalVar->getAttributes());1476 if (!targetSpecificAttrs.empty())1477 globalOp.setTargetSpecificAttrsAttr(targetSpecificAttrs);1478}1479 1480LogicalResult ModuleImport::convertGlobal(llvm::GlobalVariable *globalVar) {1481 // Insert the global after the last one or at the start of the module.1482 OpBuilder::InsertionGuard guard = setGlobalInsertionPoint();1483 1484 Attribute valueAttr;1485 if (globalVar->hasInitializer())1486 valueAttr = getConstantAsAttr(globalVar->getInitializer());1487 Type type = convertType(globalVar->getValueType());1488 1489 uint64_t alignment = 0;1490 llvm::MaybeAlign maybeAlign = globalVar->getAlign();1491 if (maybeAlign.has_value()) {1492 llvm::Align align = *maybeAlign;1493 alignment = align.value();1494 }1495 1496 // Get the global expression associated with this global variable and convert1497 // it.1498 SmallVector<Attribute> globalExpressionAttrs;1499 SmallVector<llvm::DIGlobalVariableExpression *> globalExpressions;1500 globalVar->getDebugInfo(globalExpressions);1501 1502 for (llvm::DIGlobalVariableExpression *expr : globalExpressions) {1503 DIGlobalVariableExpressionAttr globalExpressionAttr =1504 debugImporter->translateGlobalVariableExpression(expr);1505 globalExpressionAttrs.push_back(globalExpressionAttr);1506 }1507 1508 // Workaround to support LLVM's nameless globals. MLIR, in contrast to LLVM,1509 // always requires a symbol name.1510 StringRef globalName = globalVar->getName();1511 if (globalName.empty())1512 globalName = getOrCreateNamelessSymbolName(globalVar).getValue();1513 1514 GlobalOp globalOp = GlobalOp::create(1515 builder, mlirModule.getLoc(), type, globalVar->isConstant(),1516 convertLinkageFromLLVM(globalVar->getLinkage()), StringRef(globalName),1517 valueAttr, alignment, /*addrSpace=*/globalVar->getAddressSpace(),1518 /*dsoLocal=*/globalVar->isDSOLocal(),1519 /*thread_local=*/globalVar->isThreadLocal(), /*comdat=*/SymbolRefAttr(),1520 /*attrs=*/ArrayRef<NamedAttribute>(), /*dbgExprs=*/globalExpressionAttrs);1521 globalInsertionOp = globalOp;1522 1523 if (globalVar->hasInitializer() && !valueAttr) {1524 clearRegionState();1525 Block *block = builder.createBlock(&globalOp.getInitializerRegion());1526 setConstantInsertionPointToStart(block);1527 FailureOr<Value> initializer =1528 convertConstantExpr(globalVar->getInitializer());1529 if (failed(initializer))1530 return failure();1531 ReturnOp::create(builder, globalOp.getLoc(), *initializer);1532 }1533 if (globalVar->hasAtLeastLocalUnnamedAddr()) {1534 globalOp.setUnnamedAddr(1535 convertUnnamedAddrFromLLVM(globalVar->getUnnamedAddr()));1536 }1537 if (globalVar->hasSection())1538 globalOp.setSection(globalVar->getSection());1539 globalOp.setVisibility_(1540 convertVisibilityFromLLVM(globalVar->getVisibility()));1541 1542 if (globalVar->hasComdat())1543 globalOp.setComdatAttr(comdatMapping.lookup(globalVar->getComdat()));1544 1545 processTargetSpecificAttrs(globalVar, globalOp);1546 1547 return success();1548}1549 1550LogicalResult1551ModuleImport::convertGlobalCtorsAndDtors(llvm::GlobalVariable *globalVar) {1552 if (!globalVar->hasInitializer() || !globalVar->hasAppendingLinkage())1553 return failure();1554 llvm::Constant *initializer = globalVar->getInitializer();1555 1556 bool knownInit = isa<llvm::ConstantArray>(initializer) ||1557 isa<llvm::ConstantAggregateZero>(initializer);1558 if (!knownInit)1559 return failure();1560 1561 // ConstantAggregateZero does not engage with the operand initialization1562 // in the loop that follows - there should be no operands. This implies1563 // empty ctor/dtor lists.1564 if (auto *caz = dyn_cast<llvm::ConstantAggregateZero>(initializer)) {1565 if (caz->getElementCount().getFixedValue() != 0)1566 return failure();1567 }1568 1569 SmallVector<Attribute> funcs;1570 SmallVector<int32_t> priorities;1571 SmallVector<Attribute> dataList;1572 for (llvm::Value *operand : initializer->operands()) {1573 auto *aggregate = dyn_cast<llvm::ConstantAggregate>(operand);1574 if (!aggregate || aggregate->getNumOperands() != 3)1575 return failure();1576 1577 auto *priority = dyn_cast<llvm::ConstantInt>(aggregate->getOperand(0));1578 auto *func = dyn_cast<llvm::Function>(aggregate->getOperand(1));1579 auto *data = dyn_cast<llvm::Constant>(aggregate->getOperand(2));1580 if (!priority || !func || !data)1581 return failure();1582 1583 auto *gv = dyn_cast_or_null<llvm::GlobalValue>(data);1584 Attribute dataAttr;1585 if (gv)1586 dataAttr = FlatSymbolRefAttr::get(context, gv->getName());1587 else if (data->isNullValue())1588 dataAttr = ZeroAttr::get(context);1589 else1590 return failure();1591 1592 funcs.push_back(FlatSymbolRefAttr::get(context, func->getName()));1593 priorities.push_back(priority->getValue().getZExtValue());1594 dataList.push_back(dataAttr);1595 }1596 1597 // Insert the global after the last one or at the start of the module.1598 OpBuilder::InsertionGuard guard = setGlobalInsertionPoint();1599 1600 if (globalVar->getName() == getGlobalCtorsVarName()) {1601 globalInsertionOp = LLVM::GlobalCtorsOp::create(1602 builder, mlirModule.getLoc(), builder.getArrayAttr(funcs),1603 builder.getI32ArrayAttr(priorities), builder.getArrayAttr(dataList));1604 return success();1605 }1606 globalInsertionOp = LLVM::GlobalDtorsOp::create(1607 builder, mlirModule.getLoc(), builder.getArrayAttr(funcs),1608 builder.getI32ArrayAttr(priorities), builder.getArrayAttr(dataList));1609 return success();1610}1611 1612SetVector<llvm::Constant *>1613ModuleImport::getConstantsToConvert(llvm::Constant *constant) {1614 // Return the empty set if the constant has been translated before.1615 if (valueMapping.contains(constant))1616 return {};1617 1618 // Traverse the constants in post-order and stop the traversal if a constant1619 // already has a `valueMapping` from an earlier constant translation or if the1620 // constant is traversed a second time.1621 SetVector<llvm::Constant *> orderedSet;1622 SetVector<llvm::Constant *> workList;1623 DenseMap<llvm::Constant *, SmallVector<llvm::Constant *>> adjacencyLists;1624 workList.insert(constant);1625 while (!workList.empty()) {1626 llvm::Constant *current = workList.back();1627 // References of global objects are just pointers to the object. Avoid1628 // walking the elements of these here.1629 if (isa<llvm::GlobalObject>(current) || isa<llvm::GlobalAlias>(current)) {1630 orderedSet.insert(current);1631 workList.pop_back();1632 continue;1633 }1634 1635 // Collect all dependencies of the current constant and add them to the1636 // adjacency list if none has been computed before.1637 auto [adjacencyIt, inserted] = adjacencyLists.try_emplace(current);1638 if (inserted) {1639 // Add all constant operands to the adjacency list and skip any other1640 // values such as basic block addresses.1641 for (llvm::Value *operand : current->operands())1642 if (auto *constDependency = dyn_cast<llvm::Constant>(operand))1643 adjacencyIt->getSecond().push_back(constDependency);1644 // Use the getElementValue method to add the dependencies of zero1645 // initialized aggregate constants since they do not take any operands.1646 if (auto *constAgg = dyn_cast<llvm::ConstantAggregateZero>(current)) {1647 unsigned numElements = constAgg->getElementCount().getFixedValue();1648 for (unsigned i = 0, e = numElements; i != e; ++i)1649 adjacencyIt->getSecond().push_back(constAgg->getElementValue(i));1650 }1651 }1652 // Add the current constant to the `orderedSet` of the traversed nodes if1653 // all its dependencies have been traversed before. Additionally, remove the1654 // constant from the `workList` and continue the traversal.1655 if (adjacencyIt->getSecond().empty()) {1656 orderedSet.insert(current);1657 workList.pop_back();1658 continue;1659 }1660 // Add the next dependency from the adjacency list to the `workList` and1661 // continue the traversal. Remove the dependency from the adjacency list to1662 // mark that it has been processed. Only enqueue the dependency if it has no1663 // `valueMapping` from an earlier translation and if it has not been1664 // enqueued before.1665 llvm::Constant *dependency = adjacencyIt->getSecond().pop_back_val();1666 if (valueMapping.contains(dependency) || workList.contains(dependency) ||1667 orderedSet.contains(dependency))1668 continue;1669 workList.insert(dependency);1670 }1671 1672 return orderedSet;1673}1674 1675FailureOr<Value> ModuleImport::convertConstant(llvm::Constant *constant) {1676 Location loc = UnknownLoc::get(context);1677 1678 // Convert constants that can be represented as attributes.1679 if (Attribute attr = getConstantAsAttr(constant)) {1680 Type type = convertType(constant->getType());1681 if (auto symbolRef = dyn_cast<FlatSymbolRefAttr>(attr)) {1682 return AddressOfOp::create(builder, loc, type, symbolRef.getValue())1683 .getResult();1684 }1685 return ConstantOp::create(builder, loc, type, attr).getResult();1686 }1687 1688 // Convert null pointer constants.1689 if (auto *nullPtr = dyn_cast<llvm::ConstantPointerNull>(constant)) {1690 Type type = convertType(nullPtr->getType());1691 return ZeroOp::create(builder, loc, type).getResult();1692 }1693 1694 // Convert none token constants.1695 if (isa<llvm::ConstantTokenNone>(constant)) {1696 return NoneTokenOp::create(builder, loc).getResult();1697 }1698 1699 // Convert poison.1700 if (auto *poisonVal = dyn_cast<llvm::PoisonValue>(constant)) {1701 Type type = convertType(poisonVal->getType());1702 return PoisonOp::create(builder, loc, type).getResult();1703 }1704 1705 // Convert undef.1706 if (auto *undefVal = dyn_cast<llvm::UndefValue>(constant)) {1707 Type type = convertType(undefVal->getType());1708 return UndefOp::create(builder, loc, type).getResult();1709 }1710 1711 // Convert dso_local_equivalent.1712 if (auto *dsoLocalEquivalent = dyn_cast<llvm::DSOLocalEquivalent>(constant)) {1713 Type type = convertType(dsoLocalEquivalent->getType());1714 return DSOLocalEquivalentOp::create(1715 builder, loc, type,1716 FlatSymbolRefAttr::get(1717 builder.getContext(),1718 dsoLocalEquivalent->getGlobalValue()->getName()))1719 .getResult();1720 }1721 1722 // Convert global variable accesses.1723 if (auto *globalObj = dyn_cast<llvm::GlobalObject>(constant)) {1724 Type type = convertType(globalObj->getType());1725 StringRef globalName = globalObj->getName();1726 FlatSymbolRefAttr symbolRef;1727 // Empty names are only allowed for global variables.1728 if (globalName.empty())1729 symbolRef =1730 getOrCreateNamelessSymbolName(cast<llvm::GlobalVariable>(globalObj));1731 else1732 symbolRef = FlatSymbolRefAttr::get(context, globalName);1733 return AddressOfOp::create(builder, loc, type, symbolRef).getResult();1734 }1735 1736 // Convert global alias accesses.1737 if (auto *globalAliasObj = dyn_cast<llvm::GlobalAlias>(constant)) {1738 Type type = convertType(globalAliasObj->getType());1739 StringRef aliaseeName = globalAliasObj->getName();1740 FlatSymbolRefAttr symbolRef = FlatSymbolRefAttr::get(context, aliaseeName);1741 return AddressOfOp::create(builder, loc, type, symbolRef).getResult();1742 }1743 1744 // Convert constant expressions.1745 if (auto *constExpr = dyn_cast<llvm::ConstantExpr>(constant)) {1746 // Convert the constant expression to a temporary LLVM instruction and1747 // translate it using the `processInstruction` method. Delete the1748 // instruction after the translation and remove it from `valueMapping`,1749 // since later calls to `getAsInstruction` may return the same address1750 // resulting in a conflicting `valueMapping` entry.1751 llvm::Instruction *inst = constExpr->getAsInstruction();1752 auto guard = llvm::make_scope_exit([&]() {1753 assert(!noResultOpMapping.contains(inst) &&1754 "expected constant expression to return a result");1755 valueMapping.erase(inst);1756 inst->deleteValue();1757 });1758 // Note: `processInstruction` does not call `convertConstant` recursively1759 // since all constant dependencies have been converted before.1760 assert(llvm::all_of(inst->operands(), [&](llvm::Value *value) {1761 return valueMapping.contains(value);1762 }));1763 if (failed(processInstruction(inst)))1764 return failure();1765 return lookupValue(inst);1766 }1767 1768 // Convert aggregate constants.1769 if (isa<llvm::ConstantAggregate>(constant) ||1770 isa<llvm::ConstantAggregateZero>(constant)) {1771 // Lookup the aggregate elements that have been converted before.1772 SmallVector<Value> elementValues;1773 if (auto *constAgg = dyn_cast<llvm::ConstantAggregate>(constant)) {1774 elementValues.reserve(constAgg->getNumOperands());1775 for (llvm::Value *operand : constAgg->operands())1776 elementValues.push_back(lookupValue(operand));1777 }1778 if (auto *constAgg = dyn_cast<llvm::ConstantAggregateZero>(constant)) {1779 unsigned numElements = constAgg->getElementCount().getFixedValue();1780 elementValues.reserve(numElements);1781 for (unsigned i = 0, e = numElements; i != e; ++i)1782 elementValues.push_back(lookupValue(constAgg->getElementValue(i)));1783 }1784 assert(llvm::count(elementValues, nullptr) == 0 &&1785 "expected all elements have been converted before");1786 1787 // Generate an UndefOp as root value and insert the aggregate elements.1788 Type rootType = convertType(constant->getType());1789 bool isArrayOrStruct = isa<LLVMArrayType, LLVMStructType>(rootType);1790 assert((isArrayOrStruct || LLVM::isCompatibleVectorType(rootType)) &&1791 "unrecognized aggregate type");1792 Value root = UndefOp::create(builder, loc, rootType);1793 for (const auto &it : llvm::enumerate(elementValues)) {1794 if (isArrayOrStruct) {1795 root =1796 InsertValueOp::create(builder, loc, root, it.value(), it.index());1797 } else {1798 Attribute indexAttr = builder.getI32IntegerAttr(it.index());1799 Value indexValue =1800 ConstantOp::create(builder, loc, builder.getI32Type(), indexAttr);1801 root = InsertElementOp::create(builder, loc, rootType, root, it.value(),1802 indexValue);1803 }1804 }1805 return root;1806 }1807 1808 if (auto *constTargetNone = dyn_cast<llvm::ConstantTargetNone>(constant)) {1809 LLVMTargetExtType targetExtType =1810 cast<LLVMTargetExtType>(convertType(constTargetNone->getType()));1811 assert(targetExtType.hasProperty(LLVMTargetExtType::HasZeroInit) &&1812 "target extension type does not support zero-initialization");1813 // Create llvm.mlir.zero operation to represent zero-initialization of1814 // target extension type.1815 return LLVM::ZeroOp::create(builder, loc, targetExtType).getRes();1816 }1817 1818 if (auto *blockAddr = dyn_cast<llvm::BlockAddress>(constant)) {1819 auto fnSym =1820 FlatSymbolRefAttr::get(context, blockAddr->getFunction()->getName());1821 auto blockTag =1822 BlockTagAttr::get(context, blockAddr->getBasicBlock()->getNumber());1823 return BlockAddressOp::create(1824 builder, loc, convertType(blockAddr->getType()),1825 BlockAddressAttr::get(context, fnSym, blockTag))1826 .getRes();1827 }1828 1829 StringRef error = "";1830 1831 if (isa<llvm::ConstantPtrAuth>(constant))1832 error = " since ptrauth(...) is unsupported";1833 1834 if (isa<llvm::NoCFIValue>(constant))1835 error = " since no_cfi is unsupported";1836 1837 if (isa<llvm::GlobalValue>(constant))1838 error = " since global value is unsupported";1839 1840 return emitError(loc) << "unhandled constant: " << diag(*constant) << error;1841}1842 1843FailureOr<Value> ModuleImport::convertConstantExpr(llvm::Constant *constant) {1844 // Only call the function for constants that have not been translated before1845 // since it updates the constant insertion point assuming the converted1846 // constant has been introduced at the end of the constant section.1847 assert(!valueMapping.contains(constant) &&1848 "expected constant has not been converted before");1849 assert(constantInsertionBlock &&1850 "expected the constant insertion block to be non-null");1851 1852 // Insert the constant after the last one or at the start of the entry block.1853 OpBuilder::InsertionGuard guard(builder);1854 if (!constantInsertionOp)1855 builder.setInsertionPointToStart(constantInsertionBlock);1856 else1857 builder.setInsertionPointAfter(constantInsertionOp);1858 1859 // Convert all constants of the expression and add them to `valueMapping`.1860 SetVector<llvm::Constant *> constantsToConvert =1861 getConstantsToConvert(constant);1862 for (llvm::Constant *constantToConvert : constantsToConvert) {1863 FailureOr<Value> converted = convertConstant(constantToConvert);1864 if (failed(converted))1865 return failure();1866 mapValue(constantToConvert, *converted);1867 }1868 1869 // Update the constant insertion point and return the converted constant.1870 Value result = lookupValue(constant);1871 constantInsertionOp = result.getDefiningOp();1872 return result;1873}1874 1875FailureOr<Value> ModuleImport::convertValue(llvm::Value *value) {1876 assert(!isa<llvm::MetadataAsValue>(value) &&1877 "expected value to not be metadata");1878 1879 // Return the mapped value if it has been converted before.1880 auto it = valueMapping.find(value);1881 if (it != valueMapping.end())1882 return it->getSecond();1883 1884 // Convert constants such as immediate values that have no mapping yet.1885 if (auto *constant = dyn_cast<llvm::Constant>(value))1886 return convertConstantExpr(constant);1887 1888 Location loc = UnknownLoc::get(context);1889 if (auto *inst = dyn_cast<llvm::Instruction>(value))1890 loc = translateLoc(inst->getDebugLoc());1891 return emitError(loc) << "unhandled value: " << diag(*value);1892}1893 1894FailureOr<Value> ModuleImport::convertMetadataValue(llvm::Value *value) {1895 // A value may be wrapped as metadata, for example, when passed to a debug1896 // intrinsic. Unwrap these values before the conversion.1897 auto *nodeAsVal = dyn_cast<llvm::MetadataAsValue>(value);1898 if (!nodeAsVal)1899 return failure();1900 auto *node = dyn_cast<llvm::ValueAsMetadata>(nodeAsVal->getMetadata());1901 if (!node)1902 return failure();1903 value = node->getValue();1904 1905 // Return the mapped value if it has been converted before.1906 auto it = valueMapping.find(value);1907 if (it != valueMapping.end())1908 return it->getSecond();1909 1910 // Convert constants such as immediate values that have no mapping yet.1911 if (auto *constant = dyn_cast<llvm::Constant>(value))1912 return convertConstantExpr(constant);1913 return failure();1914}1915 1916FailureOr<SmallVector<Value>>1917ModuleImport::convertValues(ArrayRef<llvm::Value *> values) {1918 SmallVector<Value> remapped;1919 remapped.reserve(values.size());1920 for (llvm::Value *value : values) {1921 FailureOr<Value> converted = convertValue(value);1922 if (failed(converted))1923 return failure();1924 remapped.push_back(*converted);1925 }1926 return remapped;1927}1928 1929LogicalResult ModuleImport::convertIntrinsicArguments(1930 ArrayRef<llvm::Value *> values, ArrayRef<llvm::OperandBundleUse> opBundles,1931 bool requiresOpBundles, ArrayRef<unsigned> immArgPositions,1932 ArrayRef<StringLiteral> immArgAttrNames, SmallVectorImpl<Value> &valuesOut,1933 SmallVectorImpl<NamedAttribute> &attrsOut) {1934 assert(immArgPositions.size() == immArgAttrNames.size() &&1935 "LLVM `immArgPositions` and MLIR `immArgAttrNames` should have equal "1936 "length");1937 1938 SmallVector<llvm::Value *> operands(values);1939 for (auto [immArgPos, immArgName] :1940 llvm::zip(immArgPositions, immArgAttrNames)) {1941 auto &value = operands[immArgPos];1942 auto *constant = llvm::cast<llvm::Constant>(value);1943 auto attr = getScalarConstantAsAttr(builder, constant);1944 assert(attr && attr.getType().isIntOrFloat() &&1945 "expected immarg to be float or integer constant");1946 auto nameAttr = StringAttr::get(attr.getContext(), immArgName);1947 attrsOut.push_back({nameAttr, attr});1948 // Mark matched attribute values as null (so they can be removed below).1949 value = nullptr;1950 }1951 1952 for (llvm::Value *value : operands) {1953 if (!value)1954 continue;1955 auto mlirValue = convertValue(value);1956 if (failed(mlirValue))1957 return failure();1958 valuesOut.push_back(*mlirValue);1959 }1960 1961 SmallVector<int> opBundleSizes;1962 SmallVector<Attribute> opBundleTagAttrs;1963 if (requiresOpBundles) {1964 opBundleSizes.reserve(opBundles.size());1965 opBundleTagAttrs.reserve(opBundles.size());1966 1967 for (const llvm::OperandBundleUse &bundle : opBundles) {1968 opBundleSizes.push_back(bundle.Inputs.size());1969 opBundleTagAttrs.push_back(StringAttr::get(context, bundle.getTagName()));1970 1971 for (const llvm::Use &opBundleOperand : bundle.Inputs) {1972 auto operandMlirValue = convertValue(opBundleOperand.get());1973 if (failed(operandMlirValue))1974 return failure();1975 valuesOut.push_back(*operandMlirValue);1976 }1977 }1978 1979 auto opBundleSizesAttr = DenseI32ArrayAttr::get(context, opBundleSizes);1980 auto opBundleSizesAttrNameAttr =1981 StringAttr::get(context, LLVMDialect::getOpBundleSizesAttrName());1982 attrsOut.push_back({opBundleSizesAttrNameAttr, opBundleSizesAttr});1983 1984 auto opBundleTagsAttr = ArrayAttr::get(context, opBundleTagAttrs);1985 auto opBundleTagsAttrNameAttr =1986 StringAttr::get(context, LLVMDialect::getOpBundleTagsAttrName());1987 attrsOut.push_back({opBundleTagsAttrNameAttr, opBundleTagsAttr});1988 }1989 1990 return success();1991}1992 1993IntegerAttr ModuleImport::matchIntegerAttr(llvm::Value *value) {1994 IntegerAttr integerAttr;1995 FailureOr<Value> converted = convertValue(value);1996 bool success = succeeded(converted) &&1997 matchPattern(*converted, m_Constant(&integerAttr));1998 assert(success && "expected a constant integer value");1999 (void)success;2000 return integerAttr;2001}2002 2003FloatAttr ModuleImport::matchFloatAttr(llvm::Value *value) {2004 FloatAttr floatAttr;2005 FailureOr<Value> converted = convertValue(value);2006 bool success =2007 succeeded(converted) && matchPattern(*converted, m_Constant(&floatAttr));2008 assert(success && "expected a constant float value");2009 (void)success;2010 return floatAttr;2011}2012 2013DILocalVariableAttr ModuleImport::matchLocalVariableAttr(2014 llvm::PointerUnion<llvm::Value *, llvm::DILocalVariable *> valOrVariable) {2015 llvm::DILocalVariable *node = nullptr;2016 if (auto *value = dyn_cast<llvm::Value *>(valOrVariable)) {2017 auto *nodeAsVal = cast<llvm::MetadataAsValue>(value);2018 node = cast<llvm::DILocalVariable>(nodeAsVal->getMetadata());2019 } else {2020 node = cast<llvm::DILocalVariable *>(valOrVariable);2021 }2022 return debugImporter->translate(node);2023}2024 2025DILabelAttr ModuleImport::matchLabelAttr(llvm::Value *value) {2026 auto *nodeAsVal = cast<llvm::MetadataAsValue>(value);2027 auto *node = cast<llvm::DILabel>(nodeAsVal->getMetadata());2028 return debugImporter->translate(node);2029}2030 2031FPExceptionBehaviorAttr2032ModuleImport::matchFPExceptionBehaviorAttr(llvm::Value *value) {2033 auto *metadata = cast<llvm::MetadataAsValue>(value);2034 auto *mdstr = cast<llvm::MDString>(metadata->getMetadata());2035 std::optional<llvm::fp::ExceptionBehavior> optLLVM =2036 llvm::convertStrToExceptionBehavior(mdstr->getString());2037 assert(optLLVM && "Expecting FP exception behavior");2038 return builder.getAttr<FPExceptionBehaviorAttr>(2039 convertFPExceptionBehaviorFromLLVM(*optLLVM));2040}2041 2042RoundingModeAttr ModuleImport::matchRoundingModeAttr(llvm::Value *value) {2043 auto *metadata = cast<llvm::MetadataAsValue>(value);2044 auto *mdstr = cast<llvm::MDString>(metadata->getMetadata());2045 std::optional<llvm::RoundingMode> optLLVM =2046 llvm::convertStrToRoundingMode(mdstr->getString());2047 assert(optLLVM && "Expecting rounding mode");2048 return builder.getAttr<RoundingModeAttr>(2049 convertRoundingModeFromLLVM(*optLLVM));2050}2051 2052FailureOr<SmallVector<AliasScopeAttr>>2053ModuleImport::matchAliasScopeAttrs(llvm::Value *value) {2054 auto *nodeAsVal = cast<llvm::MetadataAsValue>(value);2055 auto *node = cast<llvm::MDNode>(nodeAsVal->getMetadata());2056 return lookupAliasScopeAttrs(node);2057}2058 2059Location ModuleImport::translateLoc(llvm::DILocation *loc) {2060 return debugImporter->translateLoc(loc);2061}2062 2063LogicalResult2064ModuleImport::convertBranchArgs(llvm::Instruction *branch,2065 llvm::BasicBlock *target,2066 SmallVectorImpl<Value> &blockArguments) {2067 for (auto inst = target->begin(); isa<llvm::PHINode>(inst); ++inst) {2068 auto *phiInst = cast<llvm::PHINode>(&*inst);2069 llvm::Value *value = phiInst->getIncomingValueForBlock(branch->getParent());2070 FailureOr<Value> converted = convertValue(value);2071 if (failed(converted))2072 return failure();2073 blockArguments.push_back(*converted);2074 }2075 return success();2076}2077 2078FailureOr<SmallVector<Value>>2079ModuleImport::convertCallOperands(llvm::CallBase *callInst,2080 bool allowInlineAsm) {2081 bool isInlineAsm = callInst->isInlineAsm();2082 if (isInlineAsm && !allowInlineAsm)2083 return failure();2084 2085 SmallVector<Value> operands;2086 2087 // Cannot use isIndirectCall() here because we need to handle Constant callees2088 // that are not considered indirect calls by LLVM. However, in MLIR, they are2089 // treated as indirect calls to constant operands that need to be converted.2090 // Skip the callee operand if it's inline assembly, as it's handled separately2091 // in InlineAsmOp.2092 llvm::Value *calleeOperand = callInst->getCalledOperand();2093 if (!isa<llvm::Function, llvm::GlobalIFunc>(calleeOperand) && !isInlineAsm) {2094 FailureOr<Value> called = convertValue(calleeOperand);2095 if (failed(called))2096 return failure();2097 operands.push_back(*called);2098 }2099 2100 SmallVector<llvm::Value *> args(callInst->args());2101 FailureOr<SmallVector<Value>> arguments = convertValues(args);2102 if (failed(arguments))2103 return failure();2104 2105 llvm::append_range(operands, *arguments);2106 return operands;2107}2108 2109/// Checks if `callType` and `calleeType` are compatible and can be represented2110/// in MLIR.2111static LogicalResult2112checkFunctionTypeCompatibility(LLVMFunctionType callType,2113 LLVMFunctionType calleeType) {2114 if (callType.getReturnType() != calleeType.getReturnType())2115 return failure();2116 2117 if (calleeType.isVarArg()) {2118 // For variadic functions, the call can have more types than the callee2119 // specifies.2120 if (callType.getNumParams() < calleeType.getNumParams())2121 return failure();2122 } else {2123 // For non-variadic functions, the number of parameters needs to be the2124 // same.2125 if (callType.getNumParams() != calleeType.getNumParams())2126 return failure();2127 }2128 2129 // Check that all operands match.2130 for (auto [operandType, argumentType] :2131 llvm::zip(callType.getParams(), calleeType.getParams()))2132 if (operandType != argumentType)2133 return failure();2134 2135 return success();2136}2137 2138FailureOr<LLVMFunctionType>2139ModuleImport::convertFunctionType(llvm::CallBase *callInst,2140 bool &isIncompatibleCall) {2141 isIncompatibleCall = false;2142 auto castOrFailure = [](Type convertedType) -> FailureOr<LLVMFunctionType> {2143 auto funcTy = dyn_cast_or_null<LLVMFunctionType>(convertedType);2144 if (!funcTy)2145 return failure();2146 return funcTy;2147 };2148 2149 llvm::Value *calledOperand = callInst->getCalledOperand();2150 FailureOr<LLVMFunctionType> callType =2151 castOrFailure(convertType(callInst->getFunctionType()));2152 if (failed(callType))2153 return failure();2154 auto *callee = dyn_cast<llvm::Function>(calledOperand);2155 2156 llvm::FunctionType *origCalleeType = nullptr;2157 if (callee) {2158 origCalleeType = callee->getFunctionType();2159 } else if (auto *ifunc = dyn_cast<llvm::GlobalIFunc>(calledOperand)) {2160 origCalleeType = cast<llvm::FunctionType>(ifunc->getValueType());2161 }2162 2163 // For indirect calls, return the type of the call itself.2164 if (!origCalleeType)2165 return callType;2166 2167 FailureOr<LLVMFunctionType> calleeType =2168 castOrFailure(convertType(origCalleeType));2169 if (failed(calleeType))2170 return failure();2171 2172 // Compare the types and notify users via `isIncompatibleCall` if they are not2173 // compatible.2174 if (failed(checkFunctionTypeCompatibility(*callType, *calleeType))) {2175 isIncompatibleCall = true;2176 Location loc = translateLoc(callInst->getDebugLoc());2177 emitWarning(loc) << "incompatible call and callee types: " << *callType2178 << " and " << *calleeType;2179 return callType;2180 }2181 2182 return calleeType;2183}2184 2185FlatSymbolRefAttr ModuleImport::convertCalleeName(llvm::CallBase *callInst) {2186 llvm::Value *calledOperand = callInst->getCalledOperand();2187 if (isa<llvm::Function, llvm::GlobalIFunc>(calledOperand))2188 return SymbolRefAttr::get(context, calledOperand->getName());2189 return {};2190}2191 2192LogicalResult ModuleImport::convertIntrinsic(llvm::CallInst *inst) {2193 if (succeeded(iface.convertIntrinsic(builder, inst, *this)))2194 return success();2195 2196 Location loc = translateLoc(inst->getDebugLoc());2197 return emitError(loc) << "unhandled intrinsic: " << diag(*inst);2198}2199 2200ArrayAttr2201ModuleImport::convertAsmInlineOperandAttrs(const llvm::CallBase &llvmCall) {2202 const auto *ia = cast<llvm::InlineAsm>(llvmCall.getCalledOperand());2203 unsigned argIdx = 0;2204 SmallVector<mlir::Attribute> opAttrs;2205 bool hasIndirect = false;2206 2207 for (const llvm::InlineAsm::ConstraintInfo &ci : ia->ParseConstraints()) {2208 // Only deal with constraints that correspond to call arguments.2209 if (ci.Type == llvm::InlineAsm::isLabel || !ci.hasArg())2210 continue;2211 2212 // Only increment `argIdx` in terms of constraints containing arguments,2213 // which are guaranteed to happen in the same order of the call arguments.2214 if (ci.isIndirect) {2215 if (llvm::Type *paramEltType = llvmCall.getParamElementType(argIdx)) {2216 SmallVector<mlir::NamedAttribute> attrs;2217 attrs.push_back(builder.getNamedAttr(2218 mlir::LLVM::InlineAsmOp::getElementTypeAttrName(),2219 mlir::TypeAttr::get(convertType(paramEltType))));2220 opAttrs.push_back(builder.getDictionaryAttr(attrs));2221 hasIndirect = true;2222 }2223 } else {2224 opAttrs.push_back(builder.getDictionaryAttr({}));2225 }2226 argIdx++;2227 }2228 2229 // Avoid emitting an array where all entries are empty dictionaries.2230 return hasIndirect ? ArrayAttr::get(mlirModule->getContext(), opAttrs)2231 : nullptr;2232}2233 2234LogicalResult ModuleImport::convertInstruction(llvm::Instruction *inst) {2235 // Convert all instructions that do not provide an MLIR builder.2236 Location loc = translateLoc(inst->getDebugLoc());2237 if (inst->getOpcode() == llvm::Instruction::Br) {2238 auto *brInst = cast<llvm::BranchInst>(inst);2239 2240 SmallVector<Block *> succBlocks;2241 SmallVector<SmallVector<Value>> succBlockArgs;2242 for (auto i : llvm::seq<unsigned>(0, brInst->getNumSuccessors())) {2243 llvm::BasicBlock *succ = brInst->getSuccessor(i);2244 SmallVector<Value> blockArgs;2245 if (failed(convertBranchArgs(brInst, succ, blockArgs)))2246 return failure();2247 succBlocks.push_back(lookupBlock(succ));2248 succBlockArgs.push_back(blockArgs);2249 }2250 2251 if (!brInst->isConditional()) {2252 auto brOp = LLVM::BrOp::create(builder, loc, succBlockArgs.front(),2253 succBlocks.front());2254 mapNoResultOp(inst, brOp);2255 return success();2256 }2257 FailureOr<Value> condition = convertValue(brInst->getCondition());2258 if (failed(condition))2259 return failure();2260 auto condBrOp = LLVM::CondBrOp::create(2261 builder, loc, *condition, succBlocks.front(), succBlockArgs.front(),2262 succBlocks.back(), succBlockArgs.back());2263 mapNoResultOp(inst, condBrOp);2264 return success();2265 }2266 if (inst->getOpcode() == llvm::Instruction::Switch) {2267 auto *swInst = cast<llvm::SwitchInst>(inst);2268 // Process the condition value.2269 FailureOr<Value> condition = convertValue(swInst->getCondition());2270 if (failed(condition))2271 return failure();2272 SmallVector<Value> defaultBlockArgs;2273 // Process the default case.2274 llvm::BasicBlock *defaultBB = swInst->getDefaultDest();2275 if (failed(convertBranchArgs(swInst, defaultBB, defaultBlockArgs)))2276 return failure();2277 2278 // Process the cases.2279 unsigned numCases = swInst->getNumCases();2280 SmallVector<SmallVector<Value>> caseOperands(numCases);2281 SmallVector<ValueRange> caseOperandRefs(numCases);2282 SmallVector<APInt> caseValues(numCases);2283 SmallVector<Block *> caseBlocks(numCases);2284 for (const auto &it : llvm::enumerate(swInst->cases())) {2285 const llvm::SwitchInst::CaseHandle &caseHandle = it.value();2286 llvm::BasicBlock *succBB = caseHandle.getCaseSuccessor();2287 if (failed(convertBranchArgs(swInst, succBB, caseOperands[it.index()])))2288 return failure();2289 caseOperandRefs[it.index()] = caseOperands[it.index()];2290 caseValues[it.index()] = caseHandle.getCaseValue()->getValue();2291 caseBlocks[it.index()] = lookupBlock(succBB);2292 }2293 2294 auto switchOp = SwitchOp::create(builder, loc, *condition,2295 lookupBlock(defaultBB), defaultBlockArgs,2296 caseValues, caseBlocks, caseOperandRefs);2297 mapNoResultOp(inst, switchOp);2298 return success();2299 }2300 if (inst->getOpcode() == llvm::Instruction::PHI) {2301 Type type = convertType(inst->getType());2302 mapValue(inst, builder.getInsertionBlock()->addArgument(2303 type, translateLoc(inst->getDebugLoc())));2304 return success();2305 }2306 if (inst->getOpcode() == llvm::Instruction::Call) {2307 auto *callInst = cast<llvm::CallInst>(inst);2308 llvm::Value *calledOperand = callInst->getCalledOperand();2309 2310 FailureOr<SmallVector<Value>> operands =2311 convertCallOperands(callInst, /*allowInlineAsm=*/true);2312 if (failed(operands))2313 return failure();2314 2315 auto callOp = [&]() -> FailureOr<Operation *> {2316 if (auto *asmI = dyn_cast<llvm::InlineAsm>(calledOperand)) {2317 Type resultTy = convertType(callInst->getType());2318 if (!resultTy)2319 return failure();2320 ArrayAttr operandAttrs = convertAsmInlineOperandAttrs(*callInst);2321 return InlineAsmOp::create(2322 builder, loc, resultTy, *operands,2323 builder.getStringAttr(asmI->getAsmString()),2324 builder.getStringAttr(asmI->getConstraintString()),2325 asmI->hasSideEffects(), asmI->isAlignStack(),2326 convertTailCallKindFromLLVM(callInst->getTailCallKind()),2327 AsmDialectAttr::get(2328 mlirModule.getContext(),2329 convertAsmDialectFromLLVM(asmI->getDialect())),2330 operandAttrs)2331 .getOperation();2332 }2333 bool isIncompatibleCall;2334 FailureOr<LLVMFunctionType> funcTy =2335 convertFunctionType(callInst, isIncompatibleCall);2336 if (failed(funcTy))2337 return failure();2338 2339 FlatSymbolRefAttr callee = nullptr;2340 if (isIncompatibleCall) {2341 // Use an indirect call (in order to represent valid and verifiable LLVM2342 // IR). Build the indirect call by passing an empty `callee` operand and2343 // insert into `operands` to include the indirect call target.2344 FlatSymbolRefAttr calleeSym = convertCalleeName(callInst);2345 Value indirectCallVal = LLVM::AddressOfOp::create(2346 builder, loc, LLVM::LLVMPointerType::get(context), calleeSym);2347 operands->insert(operands->begin(), indirectCallVal);2348 } else {2349 // Regular direct call using callee name.2350 callee = convertCalleeName(callInst);2351 }2352 CallOp callOp = CallOp::create(builder, loc, *funcTy, callee, *operands);2353 2354 if (failed(convertCallAttributes(callInst, callOp)))2355 return failure();2356 2357 // Handle parameter and result attributes unless it's an incompatible2358 // call.2359 if (!isIncompatibleCall)2360 convertArgAndResultAttrs(callInst, callOp);2361 return callOp.getOperation();2362 }();2363 2364 if (failed(callOp))2365 return failure();2366 2367 if (!callInst->getType()->isVoidTy())2368 mapValue(inst, (*callOp)->getResult(0));2369 else2370 mapNoResultOp(inst, *callOp);2371 return success();2372 }2373 if (inst->getOpcode() == llvm::Instruction::LandingPad) {2374 auto *lpInst = cast<llvm::LandingPadInst>(inst);2375 2376 SmallVector<Value> operands;2377 operands.reserve(lpInst->getNumClauses());2378 for (auto i : llvm::seq<unsigned>(0, lpInst->getNumClauses())) {2379 FailureOr<Value> operand = convertValue(lpInst->getClause(i));2380 if (failed(operand))2381 return failure();2382 operands.push_back(*operand);2383 }2384 2385 Type type = convertType(lpInst->getType());2386 auto lpOp =2387 LandingpadOp::create(builder, loc, type, lpInst->isCleanup(), operands);2388 mapValue(inst, lpOp);2389 return success();2390 }2391 if (inst->getOpcode() == llvm::Instruction::Invoke) {2392 auto *invokeInst = cast<llvm::InvokeInst>(inst);2393 2394 if (invokeInst->isInlineAsm())2395 return emitError(loc) << "invoke of inline assembly is not supported";2396 2397 FailureOr<SmallVector<Value>> operands = convertCallOperands(invokeInst);2398 if (failed(operands))2399 return failure();2400 2401 // Check whether the invoke result is an argument to the normal destination2402 // block.2403 bool invokeResultUsedInPhi = llvm::any_of(2404 invokeInst->getNormalDest()->phis(), [&](const llvm::PHINode &phi) {2405 return phi.getIncomingValueForBlock(invokeInst->getParent()) ==2406 invokeInst;2407 });2408 2409 Block *normalDest = lookupBlock(invokeInst->getNormalDest());2410 Block *directNormalDest = normalDest;2411 if (invokeResultUsedInPhi) {2412 // The invoke result cannot be an argument to the normal destination2413 // block, as that would imply using the invoke operation result in its2414 // definition, so we need to create a dummy block to serve as an2415 // intermediate destination.2416 OpBuilder::InsertionGuard g(builder);2417 directNormalDest = builder.createBlock(normalDest);2418 }2419 2420 SmallVector<Value> unwindArgs;2421 if (failed(convertBranchArgs(invokeInst, invokeInst->getUnwindDest(),2422 unwindArgs)))2423 return failure();2424 2425 bool isIncompatibleInvoke;2426 FailureOr<LLVMFunctionType> funcTy =2427 convertFunctionType(invokeInst, isIncompatibleInvoke);2428 if (failed(funcTy))2429 return failure();2430 2431 FlatSymbolRefAttr calleeName = nullptr;2432 if (isIncompatibleInvoke) {2433 // Use an indirect invoke (in order to represent valid and verifiable LLVM2434 // IR). Build the indirect invoke by passing an empty `callee` operand and2435 // insert into `operands` to include the indirect invoke target.2436 FlatSymbolRefAttr calleeSym = convertCalleeName(invokeInst);2437 Value indirectInvokeVal = LLVM::AddressOfOp::create(2438 builder, loc, LLVM::LLVMPointerType::get(context), calleeSym);2439 operands->insert(operands->begin(), indirectInvokeVal);2440 } else {2441 // Regular direct invoke using callee name.2442 calleeName = convertCalleeName(invokeInst);2443 }2444 // Create the invoke operation. Normal destination block arguments will be2445 // added later on to handle the case in which the operation result is2446 // included in this list.2447 auto invokeOp = InvokeOp::create(2448 builder, loc, *funcTy, calleeName, *operands, directNormalDest,2449 ValueRange(), lookupBlock(invokeInst->getUnwindDest()), unwindArgs);2450 2451 if (failed(convertInvokeAttributes(invokeInst, invokeOp)))2452 return failure();2453 2454 // Handle parameter and result attributes unless it's an incompatible2455 // invoke.2456 if (!isIncompatibleInvoke)2457 convertArgAndResultAttrs(invokeInst, invokeOp);2458 2459 if (!invokeInst->getType()->isVoidTy())2460 mapValue(inst, invokeOp.getResults().front());2461 else2462 mapNoResultOp(inst, invokeOp);2463 2464 SmallVector<Value> normalArgs;2465 if (failed(convertBranchArgs(invokeInst, invokeInst->getNormalDest(),2466 normalArgs)))2467 return failure();2468 2469 if (invokeResultUsedInPhi) {2470 // The dummy normal dest block will just host an unconditional branch2471 // instruction to the normal destination block passing the required block2472 // arguments (including the invoke operation's result).2473 OpBuilder::InsertionGuard g(builder);2474 builder.setInsertionPointToStart(directNormalDest);2475 LLVM::BrOp::create(builder, loc, normalArgs, normalDest);2476 } else {2477 // If the invoke operation's result is not a block argument to the normal2478 // destination block, just add the block arguments as usual.2479 assert(llvm::none_of(2480 normalArgs,2481 [&](Value val) { return val.getDefiningOp() == invokeOp; }) &&2482 "An llvm.invoke operation cannot pass its result as a block "2483 "argument.");2484 invokeOp.getNormalDestOperandsMutable().append(normalArgs);2485 }2486 2487 return success();2488 }2489 if (inst->getOpcode() == llvm::Instruction::GetElementPtr) {2490 auto *gepInst = cast<llvm::GetElementPtrInst>(inst);2491 Type sourceElementType = convertType(gepInst->getSourceElementType());2492 FailureOr<Value> basePtr = convertValue(gepInst->getOperand(0));2493 if (failed(basePtr))2494 return failure();2495 2496 // Treat every indices as dynamic since GEPOp::build will refine those2497 // indices into static attributes later. One small downside of this2498 // approach is that many unused `llvm.mlir.constant` would be emitted2499 // at first place.2500 SmallVector<GEPArg> indices;2501 for (llvm::Value *operand : llvm::drop_begin(gepInst->operand_values())) {2502 FailureOr<Value> index = convertValue(operand);2503 if (failed(index))2504 return failure();2505 indices.push_back(*index);2506 }2507 2508 Type type = convertType(inst->getType());2509 auto gepOp = GEPOp::create(2510 builder, loc, type, sourceElementType, *basePtr, indices,2511 static_cast<GEPNoWrapFlags>(gepInst->getNoWrapFlags().getRaw()));2512 mapValue(inst, gepOp);2513 return success();2514 }2515 2516 if (inst->getOpcode() == llvm::Instruction::IndirectBr) {2517 auto *indBrInst = cast<llvm::IndirectBrInst>(inst);2518 2519 FailureOr<Value> basePtr = convertValue(indBrInst->getAddress());2520 if (failed(basePtr))2521 return failure();2522 2523 SmallVector<Block *> succBlocks;2524 SmallVector<SmallVector<Value>> succBlockArgs;2525 for (auto i : llvm::seq<unsigned>(0, indBrInst->getNumSuccessors())) {2526 llvm::BasicBlock *succ = indBrInst->getSuccessor(i);2527 SmallVector<Value> blockArgs;2528 if (failed(convertBranchArgs(indBrInst, succ, blockArgs)))2529 return failure();2530 succBlocks.push_back(lookupBlock(succ));2531 succBlockArgs.push_back(blockArgs);2532 }2533 SmallVector<ValueRange> succBlockArgsRange =2534 llvm::to_vector_of<ValueRange>(succBlockArgs);2535 Location loc = translateLoc(inst->getDebugLoc());2536 auto indBrOp = LLVM::IndirectBrOp::create(builder, loc, *basePtr,2537 succBlockArgsRange, succBlocks);2538 2539 mapNoResultOp(inst, indBrOp);2540 return success();2541 }2542 2543 // Convert all instructions that have an mlirBuilder.2544 if (succeeded(convertInstructionImpl(builder, inst, *this, iface)))2545 return success();2546 2547 return emitError(loc) << "unhandled instruction: " << diag(*inst);2548}2549 2550LogicalResult ModuleImport::processInstruction(llvm::Instruction *inst) {2551 // FIXME: Support uses of SubtargetData.2552 // FIXME: Add support for call / operand attributes.2553 // FIXME: Add support for the cleanupret, catchret, catchswitch, callbr,2554 // vaarg, catchpad, cleanuppad instructions.2555 2556 // Convert LLVM intrinsics calls to MLIR intrinsics.2557 if (auto *intrinsic = dyn_cast<llvm::IntrinsicInst>(inst))2558 return convertIntrinsic(intrinsic);2559 2560 // Process debug records attached to this instruction. Debug variable records2561 // are stored for later processing after all SSA values are converted, while2562 // debug label records can be converted immediately.2563 if (inst->DebugMarker) {2564 for (llvm::DbgRecord &dbgRecord : inst->DebugMarker->getDbgRecordRange()) {2565 // Store debug variable records for later processing.2566 if (auto *dbgVariableRecord =2567 dyn_cast<llvm::DbgVariableRecord>(&dbgRecord)) {2568 addDebugRecord(dbgVariableRecord);2569 continue;2570 }2571 Location loc = translateLoc(dbgRecord.getDebugLoc());2572 auto emitUnsupportedWarning = [&]() -> LogicalResult {2573 if (!emitExpensiveWarnings)2574 return success();2575 std::string options;2576 llvm::raw_string_ostream optionsStream(options);2577 dbgRecord.print(optionsStream);2578 emitWarning(loc) << "unhandled debug record " << optionsStream.str();2579 return success();2580 };2581 // Convert the debug label records in-place.2582 if (auto *dbgLabelRecord = dyn_cast<llvm::DbgLabelRecord>(&dbgRecord)) {2583 DILabelAttr labelAttr =2584 debugImporter->translate(dbgLabelRecord->getLabel());2585 if (!labelAttr)2586 return emitUnsupportedWarning();2587 LLVM::DbgLabelOp::create(builder, loc, labelAttr);2588 continue;2589 }2590 // Warn if an unsupported debug record is encountered.2591 return emitUnsupportedWarning();2592 }2593 }2594 2595 // Convert all remaining LLVM instructions to MLIR operations.2596 return convertInstruction(inst);2597}2598 2599FlatSymbolRefAttr ModuleImport::getPersonalityAsAttr(llvm::Function *f) {2600 if (!f->hasPersonalityFn())2601 return nullptr;2602 2603 llvm::Constant *pf = f->getPersonalityFn();2604 2605 // If it directly has a name, we can use it.2606 if (pf->hasName())2607 return SymbolRefAttr::get(builder.getContext(), pf->getName());2608 2609 // If it doesn't have a name, currently, only function pointers that are2610 // bitcast to i8* are parsed.2611 if (auto *ce = dyn_cast<llvm::ConstantExpr>(pf)) {2612 if (ce->getOpcode() == llvm::Instruction::BitCast &&2613 ce->getType() == llvm::PointerType::getUnqual(f->getContext())) {2614 if (auto *func = dyn_cast<llvm::Function>(ce->getOperand(0)))2615 return SymbolRefAttr::get(builder.getContext(), func->getName());2616 }2617 }2618 return FlatSymbolRefAttr();2619}2620 2621static void processMemoryEffects(llvm::Function *func, LLVMFuncOp funcOp) {2622 llvm::MemoryEffects memEffects = func->getMemoryEffects();2623 2624 auto othermem = convertModRefInfoFromLLVM(2625 memEffects.getModRef(llvm::MemoryEffects::Location::Other));2626 auto argMem = convertModRefInfoFromLLVM(2627 memEffects.getModRef(llvm::MemoryEffects::Location::ArgMem));2628 auto inaccessibleMem = convertModRefInfoFromLLVM(2629 memEffects.getModRef(llvm::MemoryEffects::Location::InaccessibleMem));2630 auto errnoMem = convertModRefInfoFromLLVM(2631 memEffects.getModRef(llvm::MemoryEffects::Location::ErrnoMem));2632 auto targetMem0 = convertModRefInfoFromLLVM(2633 memEffects.getModRef(llvm::MemoryEffects::Location::TargetMem0));2634 auto targetMem1 = convertModRefInfoFromLLVM(2635 memEffects.getModRef(llvm::MemoryEffects::Location::TargetMem1));2636 auto memAttr =2637 MemoryEffectsAttr::get(funcOp.getContext(), othermem, argMem,2638 inaccessibleMem, errnoMem, targetMem0, targetMem1);2639 // Only set the attr when it does not match the default value.2640 if (memAttr.isReadWrite())2641 return;2642 funcOp.setMemoryEffectsAttr(memAttr);2643}2644 2645// List of LLVM IR attributes that map to an explicit attribute on the MLIR2646// LLVMFuncOp.2647static constexpr std::array kExplicitLLVMFuncOpAttributes{2648 StringLiteral("aarch64_in_za"),2649 StringLiteral("aarch64_inout_za"),2650 StringLiteral("aarch64_new_za"),2651 StringLiteral("aarch64_out_za"),2652 StringLiteral("aarch64_preserves_za"),2653 StringLiteral("aarch64_pstate_sm_body"),2654 StringLiteral("aarch64_pstate_sm_compatible"),2655 StringLiteral("aarch64_pstate_sm_enabled"),2656 StringLiteral("alwaysinline"),2657 StringLiteral("convergent"),2658 StringLiteral("denormal-fp-math"),2659 StringLiteral("denormal-fp-math-f32"),2660 StringLiteral("fp-contract"),2661 StringLiteral("frame-pointer"),2662 StringLiteral("inlinehint"),2663 StringLiteral("instrument-function-entry"),2664 StringLiteral("instrument-function-exit"),2665 StringLiteral("memory"),2666 StringLiteral("no-infs-fp-math"),2667 StringLiteral("no-nans-fp-math"),2668 StringLiteral("no-signed-zeros-fp-math"),2669 StringLiteral("noinline"),2670 StringLiteral("nounwind"),2671 StringLiteral("optnone"),2672 StringLiteral("target-features"),2673 StringLiteral("tune-cpu"),2674 StringLiteral("uwtable"),2675 StringLiteral("vscale_range"),2676 StringLiteral("willreturn"),2677};2678 2679/// Converts LLVM attributes from `func` into MLIR attributes and adds them2680/// to `funcOp` as passthrough attributes, skipping those listed in2681/// `kExplicitLLVMFuncAttributes`.2682static void processPassthroughAttrs(llvm::Function *func, LLVMFuncOp funcOp) {2683 llvm::AttributeSet funcAttrs = func->getAttributes().getAttributes(2684 llvm::AttributeList::AttrIndex::FunctionIndex);2685 ArrayAttr passthroughAttr =2686 convertLLVMAttributesToMLIR(funcOp.getLoc(), funcOp.getContext(),2687 funcAttrs, kExplicitLLVMFuncOpAttributes);2688 if (!passthroughAttr.empty())2689 funcOp.setPassthroughAttr(passthroughAttr);2690}2691 2692void ModuleImport::processFunctionAttributes(llvm::Function *func,2693 LLVMFuncOp funcOp) {2694 processMemoryEffects(func, funcOp);2695 processPassthroughAttrs(func, funcOp);2696 2697 if (func->hasFnAttribute(llvm::Attribute::NoInline))2698 funcOp.setNoInline(true);2699 if (func->hasFnAttribute(llvm::Attribute::AlwaysInline))2700 funcOp.setAlwaysInline(true);2701 if (func->hasFnAttribute(llvm::Attribute::InlineHint))2702 funcOp.setInlineHint(true);2703 if (func->hasFnAttribute(llvm::Attribute::OptimizeNone))2704 funcOp.setOptimizeNone(true);2705 if (func->hasFnAttribute(llvm::Attribute::Convergent))2706 funcOp.setConvergent(true);2707 if (func->hasFnAttribute(llvm::Attribute::NoUnwind))2708 funcOp.setNoUnwind(true);2709 if (func->hasFnAttribute(llvm::Attribute::WillReturn))2710 funcOp.setWillReturn(true);2711 2712 if (func->hasFnAttribute("aarch64_pstate_sm_enabled"))2713 funcOp.setArmStreaming(true);2714 else if (func->hasFnAttribute("aarch64_pstate_sm_body"))2715 funcOp.setArmLocallyStreaming(true);2716 else if (func->hasFnAttribute("aarch64_pstate_sm_compatible"))2717 funcOp.setArmStreamingCompatible(true);2718 2719 if (func->hasFnAttribute("aarch64_new_za"))2720 funcOp.setArmNewZa(true);2721 else if (func->hasFnAttribute("aarch64_in_za"))2722 funcOp.setArmInZa(true);2723 else if (func->hasFnAttribute("aarch64_out_za"))2724 funcOp.setArmOutZa(true);2725 else if (func->hasFnAttribute("aarch64_inout_za"))2726 funcOp.setArmInoutZa(true);2727 else if (func->hasFnAttribute("aarch64_preserves_za"))2728 funcOp.setArmPreservesZa(true);2729 2730 llvm::Attribute attr = func->getFnAttribute(llvm::Attribute::VScaleRange);2731 if (attr.isValid()) {2732 MLIRContext *context = funcOp.getContext();2733 auto intTy = IntegerType::get(context, 32);2734 funcOp.setVscaleRangeAttr(LLVM::VScaleRangeAttr::get(2735 context, IntegerAttr::get(intTy, attr.getVScaleRangeMin()),2736 IntegerAttr::get(intTy, attr.getVScaleRangeMax().value_or(0))));2737 }2738 2739 // Process frame-pointer attribute.2740 if (func->hasFnAttribute("frame-pointer")) {2741 StringRef stringRefFramePointerKind =2742 func->getFnAttribute("frame-pointer").getValueAsString();2743 funcOp.setFramePointerAttr(LLVM::FramePointerKindAttr::get(2744 funcOp.getContext(), LLVM::framePointerKind::symbolizeFramePointerKind(2745 stringRefFramePointerKind)2746 .value()));2747 }2748 2749 if (llvm::Attribute attr = func->getFnAttribute("target-cpu");2750 attr.isStringAttribute())2751 funcOp.setTargetCpuAttr(StringAttr::get(context, attr.getValueAsString()));2752 2753 if (llvm::Attribute attr = func->getFnAttribute("tune-cpu");2754 attr.isStringAttribute())2755 funcOp.setTuneCpuAttr(StringAttr::get(context, attr.getValueAsString()));2756 2757 if (llvm::Attribute attr = func->getFnAttribute("target-features");2758 attr.isStringAttribute())2759 funcOp.setTargetFeaturesAttr(2760 LLVM::TargetFeaturesAttr::get(context, attr.getValueAsString()));2761 2762 if (llvm::Attribute attr = func->getFnAttribute("reciprocal-estimates");2763 attr.isStringAttribute())2764 funcOp.setReciprocalEstimatesAttr(2765 StringAttr::get(context, attr.getValueAsString()));2766 2767 if (llvm::Attribute attr = func->getFnAttribute("prefer-vector-width");2768 attr.isStringAttribute())2769 funcOp.setPreferVectorWidth(attr.getValueAsString());2770 2771 if (llvm::Attribute attr = func->getFnAttribute("no-infs-fp-math");2772 attr.isStringAttribute())2773 funcOp.setNoInfsFpMath(attr.getValueAsBool());2774 2775 if (llvm::Attribute attr = func->getFnAttribute("no-nans-fp-math");2776 attr.isStringAttribute())2777 funcOp.setNoNansFpMath(attr.getValueAsBool());2778 2779 if (llvm::Attribute attr = func->getFnAttribute("instrument-function-entry");2780 attr.isStringAttribute())2781 funcOp.setInstrumentFunctionEntry(2782 StringAttr::get(context, attr.getValueAsString()));2783 2784 if (llvm::Attribute attr = func->getFnAttribute("instrument-function-exit");2785 attr.isStringAttribute())2786 funcOp.setInstrumentFunctionExit(2787 StringAttr::get(context, attr.getValueAsString()));2788 2789 if (llvm::Attribute attr = func->getFnAttribute("no-signed-zeros-fp-math");2790 attr.isStringAttribute())2791 funcOp.setNoSignedZerosFpMath(attr.getValueAsBool());2792 2793 if (llvm::Attribute attr = func->getFnAttribute("denormal-fp-math");2794 attr.isStringAttribute())2795 funcOp.setDenormalFpMathAttr(2796 StringAttr::get(context, attr.getValueAsString()));2797 2798 if (llvm::Attribute attr = func->getFnAttribute("denormal-fp-math-f32");2799 attr.isStringAttribute())2800 funcOp.setDenormalFpMathF32Attr(2801 StringAttr::get(context, attr.getValueAsString()));2802 2803 if (llvm::Attribute attr = func->getFnAttribute("fp-contract");2804 attr.isStringAttribute())2805 funcOp.setFpContractAttr(StringAttr::get(context, attr.getValueAsString()));2806 2807 if (func->hasUWTable()) {2808 ::llvm::UWTableKind uwtableKind = func->getUWTableKind();2809 funcOp.setUwtableKindAttr(LLVM::UWTableKindAttr::get(2810 funcOp.getContext(), convertUWTableKindFromLLVM(uwtableKind)));2811 }2812}2813 2814DictionaryAttr2815ModuleImport::convertArgOrResultAttrSet(llvm::AttributeSet llvmAttrSet) {2816 SmallVector<NamedAttribute> paramAttrs;2817 for (auto [llvmKind, mlirName] : getAttrKindToNameMapping()) {2818 auto llvmAttr = llvmAttrSet.getAttribute(llvmKind);2819 // Skip attributes that are not attached.2820 if (!llvmAttr.isValid())2821 continue;2822 2823 // TODO: Import captures(none) as a nocapture unit attribute until the2824 // LLVM dialect switches to the captures representation.2825 if (llvmAttr.hasKindAsEnum() &&2826 llvmAttr.getKindAsEnum() == llvm::Attribute::Captures) {2827 if (llvm::capturesNothing(llvmAttr.getCaptureInfo()))2828 paramAttrs.push_back(2829 builder.getNamedAttr(mlirName, builder.getUnitAttr()));2830 continue;2831 }2832 2833 Attribute mlirAttr;2834 if (llvmAttr.isTypeAttribute())2835 mlirAttr = TypeAttr::get(convertType(llvmAttr.getValueAsType()));2836 else if (llvmAttr.isIntAttribute())2837 mlirAttr = builder.getI64IntegerAttr(llvmAttr.getValueAsInt());2838 else if (llvmAttr.isEnumAttribute())2839 mlirAttr = builder.getUnitAttr();2840 else if (llvmAttr.isConstantRangeAttribute()) {2841 const llvm::ConstantRange &value = llvmAttr.getValueAsConstantRange();2842 mlirAttr = builder.getAttr<LLVM::ConstantRangeAttr>(value.getLower(),2843 value.getUpper());2844 } else {2845 llvm_unreachable("unexpected parameter attribute kind");2846 }2847 paramAttrs.push_back(builder.getNamedAttr(mlirName, mlirAttr));2848 }2849 2850 return builder.getDictionaryAttr(paramAttrs);2851}2852 2853void ModuleImport::convertArgAndResultAttrs(llvm::Function *func,2854 LLVMFuncOp funcOp) {2855 auto llvmAttrs = func->getAttributes();2856 for (size_t i = 0, e = funcOp.getNumArguments(); i < e; ++i) {2857 llvm::AttributeSet llvmArgAttrs = llvmAttrs.getParamAttrs(i);2858 funcOp.setArgAttrs(i, convertArgOrResultAttrSet(llvmArgAttrs));2859 }2860 // Convert the result attributes and attach them wrapped in an ArrayAttribute2861 // to the funcOp.2862 llvm::AttributeSet llvmResAttr = llvmAttrs.getRetAttrs();2863 if (!llvmResAttr.hasAttributes())2864 return;2865 funcOp.setResAttrsAttr(2866 builder.getArrayAttr({convertArgOrResultAttrSet(llvmResAttr)}));2867}2868 2869void ModuleImport::convertArgAndResultAttrs(2870 llvm::CallBase *call, ArgAndResultAttrsOpInterface attrsOp,2871 ArrayRef<unsigned> immArgPositions) {2872 // Compute the set of immediate argument positions.2873 llvm::SmallDenseSet<unsigned> immArgPositionsSet(immArgPositions.begin(),2874 immArgPositions.end());2875 // Convert the argument attributes and filter out immediate arguments.2876 llvm::AttributeList llvmAttrs = call->getAttributes();2877 SmallVector<llvm::AttributeSet> llvmArgAttrsSet;2878 bool anyArgAttrs = false;2879 for (size_t i = 0, e = call->arg_size(); i < e; ++i) {2880 // Skip immediate arguments.2881 if (immArgPositionsSet.contains(i))2882 continue;2883 llvmArgAttrsSet.emplace_back(llvmAttrs.getParamAttrs(i));2884 if (llvmArgAttrsSet.back().hasAttributes())2885 anyArgAttrs = true;2886 }2887 auto getArrayAttr = [&](ArrayRef<DictionaryAttr> dictAttrs) {2888 SmallVector<Attribute> attrs;2889 for (auto &dict : dictAttrs)2890 attrs.push_back(dict ? dict : builder.getDictionaryAttr({}));2891 return builder.getArrayAttr(attrs);2892 };2893 if (anyArgAttrs) {2894 SmallVector<DictionaryAttr> argAttrs;2895 for (auto &llvmArgAttrs : llvmArgAttrsSet)2896 argAttrs.emplace_back(convertArgOrResultAttrSet(llvmArgAttrs));2897 attrsOp.setArgAttrsAttr(getArrayAttr(argAttrs));2898 }2899 2900 // Convert the result attributes.2901 llvm::AttributeSet llvmResAttr = llvmAttrs.getRetAttrs();2902 if (!llvmResAttr.hasAttributes())2903 return;2904 DictionaryAttr resAttrs = convertArgOrResultAttrSet(llvmResAttr);2905 attrsOp.setResAttrsAttr(getArrayAttr({resAttrs}));2906}2907 2908template <typename Op>2909static LogicalResult convertCallBaseAttributes(llvm::CallBase *inst, Op op) {2910 op.setCConv(convertCConvFromLLVM(inst->getCallingConv()));2911 return success();2912}2913 2914LogicalResult ModuleImport::convertInvokeAttributes(llvm::InvokeInst *inst,2915 InvokeOp op) {2916 return convertCallBaseAttributes(inst, op);2917}2918 2919LogicalResult ModuleImport::convertCallAttributes(llvm::CallInst *inst,2920 CallOp op) {2921 setFastmathFlagsAttr(inst, op.getOperation());2922 // Query the attributes directly instead of using `inst->getFnAttr(Kind)`, the2923 // latter does additional lookup to the parent and inherits, changing the2924 // semantics too early.2925 llvm::AttributeList callAttrs = inst->getAttributes();2926 2927 op.setTailCallKind(convertTailCallKindFromLLVM(inst->getTailCallKind()));2928 op.setConvergent(callAttrs.getFnAttr(llvm::Attribute::Convergent).isValid());2929 op.setNoUnwind(callAttrs.getFnAttr(llvm::Attribute::NoUnwind).isValid());2930 op.setWillReturn(callAttrs.getFnAttr(llvm::Attribute::WillReturn).isValid());2931 op.setNoInline(callAttrs.getFnAttr(llvm::Attribute::NoInline).isValid());2932 op.setAlwaysInline(2933 callAttrs.getFnAttr(llvm::Attribute::AlwaysInline).isValid());2934 op.setInlineHint(callAttrs.getFnAttr(llvm::Attribute::InlineHint).isValid());2935 2936 llvm::MemoryEffects memEffects = inst->getMemoryEffects();2937 ModRefInfo othermem = convertModRefInfoFromLLVM(2938 memEffects.getModRef(llvm::MemoryEffects::Location::Other));2939 ModRefInfo argMem = convertModRefInfoFromLLVM(2940 memEffects.getModRef(llvm::MemoryEffects::Location::ArgMem));2941 ModRefInfo inaccessibleMem = convertModRefInfoFromLLVM(2942 memEffects.getModRef(llvm::MemoryEffects::Location::InaccessibleMem));2943 ModRefInfo errnoMem = convertModRefInfoFromLLVM(2944 memEffects.getModRef(llvm::MemoryEffects::Location::ErrnoMem));2945 ModRefInfo targetMem0 = convertModRefInfoFromLLVM(2946 memEffects.getModRef(llvm::MemoryEffects::Location::TargetMem0));2947 ModRefInfo targetMem1 = convertModRefInfoFromLLVM(2948 memEffects.getModRef(llvm::MemoryEffects::Location::TargetMem1));2949 auto memAttr =2950 MemoryEffectsAttr::get(op.getContext(), othermem, argMem, inaccessibleMem,2951 errnoMem, targetMem0, targetMem1);2952 // Only set the attribute when it does not match the default value.2953 if (!memAttr.isReadWrite())2954 op.setMemoryEffectsAttr(memAttr);2955 2956 return convertCallBaseAttributes(inst, op);2957}2958 2959LogicalResult ModuleImport::processFunction(llvm::Function *func) {2960 clearRegionState();2961 2962 auto functionType =2963 dyn_cast<LLVMFunctionType>(convertType(func->getFunctionType()));2964 if (func->isIntrinsic() &&2965 iface.isConvertibleIntrinsic(func->getIntrinsicID()))2966 return success();2967 2968 bool dsoLocal = func->isDSOLocal();2969 CConv cconv = convertCConvFromLLVM(func->getCallingConv());2970 2971 // Insert the function at the end of the module.2972 OpBuilder::InsertionGuard guard(builder);2973 builder.setInsertionPointToEnd(mlirModule.getBody());2974 2975 Location loc = debugImporter->translateFuncLocation(func);2976 LLVMFuncOp funcOp = LLVMFuncOp::create(2977 builder, loc, func->getName(), functionType,2978 convertLinkageFromLLVM(func->getLinkage()), dsoLocal, cconv);2979 2980 convertArgAndResultAttrs(func, funcOp);2981 2982 if (FlatSymbolRefAttr personality = getPersonalityAsAttr(func))2983 funcOp.setPersonalityAttr(personality);2984 else if (func->hasPersonalityFn())2985 emitWarning(funcOp.getLoc(), "could not deduce personality, skipping it");2986 2987 if (func->hasGC())2988 funcOp.setGarbageCollector(StringRef(func->getGC()));2989 2990 if (func->hasAtLeastLocalUnnamedAddr())2991 funcOp.setUnnamedAddr(convertUnnamedAddrFromLLVM(func->getUnnamedAddr()));2992 2993 if (func->hasSection())2994 funcOp.setSection(StringRef(func->getSection()));2995 2996 funcOp.setVisibility_(convertVisibilityFromLLVM(func->getVisibility()));2997 2998 if (func->hasComdat())2999 funcOp.setComdatAttr(comdatMapping.lookup(func->getComdat()));3000 3001 if (llvm::MaybeAlign maybeAlign = func->getAlign())3002 funcOp.setAlignment(maybeAlign->value());3003 3004 // Handle Function attributes.3005 processFunctionAttributes(func, funcOp);3006 3007 // Convert non-debug metadata by using the dialect interface.3008 SmallVector<std::pair<unsigned, llvm::MDNode *>> allMetadata;3009 func->getAllMetadata(allMetadata);3010 for (auto &[kind, node] : allMetadata) {3011 if (!iface.isConvertibleMetadata(kind))3012 continue;3013 if (failed(iface.setMetadataAttrs(builder, kind, node, funcOp, *this))) {3014 emitWarning(funcOp.getLoc())3015 << "unhandled function metadata: " << diagMD(node, llvmModule.get())3016 << " on " << diag(*func);3017 }3018 }3019 3020 if (func->isDeclaration())3021 return success();3022 3023 // Collect the set of basic blocks reachable from the function's entry block.3024 // This step is crucial as LLVM IR can contain unreachable blocks that3025 // self-dominate. As a result, an operation might utilize a variable it3026 // defines, which the import does not support. Given that MLIR lacks block3027 // label support, we can safely remove unreachable blocks, as there are no3028 // indirect branch instructions that could potentially target these blocks.3029 llvm::df_iterator_default_set<llvm::BasicBlock *> reachable;3030 for (llvm::BasicBlock *basicBlock : llvm::depth_first_ext(func, reachable))3031 (void)basicBlock;3032 3033 // Eagerly create all reachable blocks.3034 SmallVector<llvm::BasicBlock *> reachableBasicBlocks;3035 for (llvm::BasicBlock &basicBlock : *func) {3036 // Skip unreachable blocks.3037 if (!reachable.contains(&basicBlock)) {3038 if (basicBlock.hasAddressTaken())3039 return emitError(funcOp.getLoc())3040 << "unreachable block '" << basicBlock.getName()3041 << "' with address taken";3042 continue;3043 }3044 Region &body = funcOp.getBody();3045 Block *block = builder.createBlock(&body, body.end());3046 mapBlock(&basicBlock, block);3047 reachableBasicBlocks.push_back(&basicBlock);3048 }3049 3050 // Add function arguments to the entry block.3051 for (const auto &it : llvm::enumerate(func->args())) {3052 BlockArgument blockArg = funcOp.getFunctionBody().addArgument(3053 functionType.getParamType(it.index()), funcOp.getLoc());3054 mapValue(&it.value(), blockArg);3055 }3056 3057 // Process the blocks in topological order. The ordered traversal ensures3058 // operands defined in a dominating block have a valid mapping to an MLIR3059 // value once a block is translated.3060 SetVector<llvm::BasicBlock *> blocks =3061 getTopologicallySortedBlocks(reachableBasicBlocks);3062 setConstantInsertionPointToStart(lookupBlock(blocks.front()));3063 for (llvm::BasicBlock *basicBlock : blocks)3064 if (failed(processBasicBlock(basicBlock, lookupBlock(basicBlock))))3065 return failure();3066 3067 // Process the debug intrinsics that require a delayed conversion after3068 // everything else was converted.3069 if (failed(processDebugIntrinsics()))3070 return failure();3071 3072 // Process the debug records that require a delayed conversion after3073 // everything else was converted.3074 if (failed(processDebugRecords()))3075 return failure();3076 3077 return success();3078}3079 3080/// Checks if `dbgIntr` is a kill location that holds metadata instead of an SSA3081/// value.3082static bool isMetadataKillLocation(llvm::DbgVariableIntrinsic *dbgIntr) {3083 if (!dbgIntr->isKillLocation())3084 return false;3085 llvm::Value *value = dbgIntr->getArgOperand(0);3086 auto *nodeAsVal = dyn_cast<llvm::MetadataAsValue>(value);3087 if (!nodeAsVal)3088 return false;3089 return !isa<llvm::ValueAsMetadata>(nodeAsVal->getMetadata());3090}3091 3092/// Ensure that the debug intrinsic is inserted right after the operand3093/// definition. Otherwise, the operand might not necessarily dominate the3094/// intrinsic. If the defining operation is a terminator, insert the intrinsic3095/// into a dominated block.3096static LogicalResult setDebugIntrinsicBuilderInsertionPoint(3097 mlir::OpBuilder &builder, DominanceInfo &domInfo, Value argOperand) {3098 if (Operation *op = argOperand.getDefiningOp();3099 op && op->hasTrait<OpTrait::IsTerminator>()) {3100 // Find a dominated block that can hold the debug intrinsic.3101 auto dominatedBlocks = domInfo.getNode(op->getBlock())->children();3102 // If no block is dominated by the terminator, this intrinisc cannot be3103 // converted.3104 if (dominatedBlocks.empty())3105 return failure();3106 // Set insertion point before the terminator, to avoid inserting something3107 // before landingpads.3108 Block *dominatedBlock = (*dominatedBlocks.begin())->getBlock();3109 builder.setInsertionPoint(dominatedBlock->getTerminator());3110 } else {3111 Value insertPt = argOperand;3112 if (auto blockArg = dyn_cast<BlockArgument>(argOperand)) {3113 // The value might be coming from a phi node and is now a block argument,3114 // which means the insertion point is set to the start of the block. If3115 // this block is a target destination of an invoke, the insertion point3116 // must happen after the landing pad operation.3117 Block *insertionBlock = argOperand.getParentBlock();3118 if (!insertionBlock->empty() &&3119 isa<LandingpadOp>(insertionBlock->front()))3120 insertPt = cast<LandingpadOp>(insertionBlock->front()).getRes();3121 }3122 3123 builder.setInsertionPointAfterValue(insertPt);3124 }3125 return success();3126}3127 3128std::tuple<DILocalVariableAttr, DIExpressionAttr, Value>3129ModuleImport::processDebugOpArgumentsAndInsertionPt(3130 Location loc,3131 llvm::function_ref<FailureOr<Value>()> convertArgOperandToValue,3132 llvm::Value *address,3133 llvm::PointerUnion<llvm::Value *, llvm::DILocalVariable *> variable,3134 llvm::DIExpression *expression, DominanceInfo &domInfo) {3135 // Drop debug intrinsics if the associated debug information cannot be3136 // translated due to an unsupported construct.3137 DILocalVariableAttr localVarAttr = matchLocalVariableAttr(variable);3138 if (!localVarAttr)3139 return {};3140 FailureOr<Value> argOperand = convertArgOperandToValue();3141 if (failed(argOperand)) {3142 emitError(loc) << "failed to convert a debug operand: " << diag(*address);3143 return {};3144 }3145 3146 if (setDebugIntrinsicBuilderInsertionPoint(builder, domInfo, *argOperand)3147 .failed())3148 return {};3149 3150 return {localVarAttr, debugImporter->translateExpression(expression),3151 *argOperand};3152}3153 3154LogicalResult3155ModuleImport::processDebugIntrinsic(llvm::DbgVariableIntrinsic *dbgIntr,3156 DominanceInfo &domInfo) {3157 Location loc = translateLoc(dbgIntr->getDebugLoc());3158 auto emitUnsupportedWarning = [&]() {3159 if (emitExpensiveWarnings)3160 emitWarning(loc) << "dropped intrinsic: " << diag(*dbgIntr);3161 return success();3162 };3163 3164 OpBuilder::InsertionGuard guard(builder);3165 auto convertArgOperandToValue = [&]() {3166 return convertMetadataValue(dbgIntr->getArgOperand(0));3167 };3168 3169 // Drop debug intrinsics with an argument list.3170 // TODO: Support this case.3171 if (dbgIntr->hasArgList())3172 return emitUnsupportedWarning();3173 3174 // Drop debug intrinsics with kill locations that have metadata nodes as3175 // location operand, which cannot be converted to poison as the type cannot be3176 // reconstructed.3177 // TODO: Support this case.3178 if (isMetadataKillLocation(dbgIntr))3179 return emitUnsupportedWarning();3180 3181 auto [localVariableAttr, locationExprAttr, locVal] =3182 processDebugOpArgumentsAndInsertionPt(3183 loc, convertArgOperandToValue, dbgIntr->getArgOperand(0),3184 dbgIntr->getArgOperand(1), dbgIntr->getExpression(), domInfo);3185 3186 if (!localVariableAttr)3187 return emitUnsupportedWarning();3188 3189 if (!locVal) // Expected if localVariableAttr is present.3190 return failure();3191 3192 Operation *op = nullptr;3193 if (isa<llvm::DbgDeclareInst>(dbgIntr))3194 op = LLVM::DbgDeclareOp::create(builder, loc, locVal, localVariableAttr,3195 locationExprAttr);3196 else if (isa<llvm::DbgValueInst>(dbgIntr))3197 op = LLVM::DbgValueOp::create(builder, loc, locVal, localVariableAttr,3198 locationExprAttr);3199 else3200 return emitUnsupportedWarning();3201 3202 mapNoResultOp(dbgIntr, op);3203 setNonDebugMetadataAttrs(dbgIntr, op);3204 return success();3205}3206 3207LogicalResult3208ModuleImport::processDebugRecord(llvm::DbgVariableRecord &dbgRecord,3209 DominanceInfo &domInfo) {3210 OpBuilder::InsertionGuard guard(builder);3211 Location loc = translateLoc(dbgRecord.getDebugLoc());3212 auto emitUnsupportedWarning = [&]() -> LogicalResult {3213 if (!emitExpensiveWarnings)3214 return success();3215 std::string options;3216 llvm::raw_string_ostream optionsStream(options);3217 dbgRecord.print(optionsStream);3218 emitWarning(loc) << "unhandled debug variable record "3219 << optionsStream.str();3220 return success();3221 };3222 3223 // Drop debug records with an argument list.3224 // TODO: Support this case.3225 if (dbgRecord.hasArgList())3226 return emitUnsupportedWarning();3227 3228 // Drop all other debug records with a address operand that cannot be3229 // converted to an SSA value such as an empty metadata node.3230 // TODO: Support this case.3231 if (!dbgRecord.getAddress())3232 return emitUnsupportedWarning();3233 3234 auto convertArgOperandToValue = [&]() -> FailureOr<Value> {3235 llvm::Value *value = dbgRecord.getAddress();3236 3237 // Return the mapped value if it has been converted before.3238 auto it = valueMapping.find(value);3239 if (it != valueMapping.end())3240 return it->getSecond();3241 3242 // Convert constants such as immediate values that have no mapping yet.3243 if (auto *constant = dyn_cast<llvm::Constant>(value))3244 return convertConstantExpr(constant);3245 return failure();3246 };3247 3248 auto [localVariableAttr, locationExprAttr, locVal] =3249 processDebugOpArgumentsAndInsertionPt(3250 loc, convertArgOperandToValue, dbgRecord.getAddress(),3251 dbgRecord.getVariable(), dbgRecord.getExpression(), domInfo);3252 3253 if (!localVariableAttr)3254 return emitUnsupportedWarning();3255 3256 if (!locVal) // Expected if localVariableAttr is present.3257 return failure();3258 3259 if (dbgRecord.isDbgDeclare())3260 LLVM::DbgDeclareOp::create(builder, loc, locVal, localVariableAttr,3261 locationExprAttr);3262 else if (dbgRecord.isDbgValue())3263 LLVM::DbgValueOp::create(builder, loc, locVal, localVariableAttr,3264 locationExprAttr);3265 else // isDbgAssign3266 return emitUnsupportedWarning();3267 3268 return success();3269}3270 3271LogicalResult ModuleImport::processDebugIntrinsics() {3272 DominanceInfo domInfo;3273 for (llvm::Instruction *inst : debugIntrinsics) {3274 auto *intrCall = cast<llvm::DbgVariableIntrinsic>(inst);3275 if (failed(processDebugIntrinsic(intrCall, domInfo)))3276 return failure();3277 }3278 return success();3279}3280 3281LogicalResult ModuleImport::processDebugRecords() {3282 DominanceInfo domInfo;3283 for (llvm::DbgVariableRecord *dbgRecord : dbgRecords)3284 if (failed(processDebugRecord(*dbgRecord, domInfo)))3285 return failure();3286 dbgRecords.clear();3287 return success();3288}3289 3290LogicalResult ModuleImport::processBasicBlock(llvm::BasicBlock *bb,3291 Block *block) {3292 builder.setInsertionPointToStart(block);3293 for (llvm::Instruction &inst : *bb) {3294 if (failed(processInstruction(&inst)))3295 return failure();3296 3297 // Skip additional processing when the instructions is a debug intrinsics3298 // that was not yet converted.3299 if (debugIntrinsics.contains(&inst))3300 continue;3301 3302 // Set the non-debug metadata attributes on the imported operation and emit3303 // a warning if an instruction other than a phi instruction is dropped3304 // during the import.3305 if (Operation *op = lookupOperation(&inst)) {3306 setNonDebugMetadataAttrs(&inst, op);3307 } else if (inst.getOpcode() != llvm::Instruction::PHI) {3308 if (emitExpensiveWarnings) {3309 Location loc = debugImporter->translateLoc(inst.getDebugLoc());3310 emitWarning(loc) << "dropped instruction: " << diag(inst);3311 }3312 }3313 }3314 3315 if (bb->hasAddressTaken()) {3316 OpBuilder::InsertionGuard guard(builder);3317 builder.setInsertionPointToStart(block);3318 BlockTagOp::create(builder, block->getParentOp()->getLoc(),3319 BlockTagAttr::get(context, bb->getNumber()));3320 }3321 return success();3322}3323 3324FailureOr<SmallVector<AccessGroupAttr>>3325ModuleImport::lookupAccessGroupAttrs(const llvm::MDNode *node) const {3326 return loopAnnotationImporter->lookupAccessGroupAttrs(node);3327}3328 3329LoopAnnotationAttr3330ModuleImport::translateLoopAnnotationAttr(const llvm::MDNode *node,3331 Location loc) const {3332 return loopAnnotationImporter->translateLoopAnnotation(node, loc);3333}3334 3335FailureOr<DereferenceableAttr>3336ModuleImport::translateDereferenceableAttr(const llvm::MDNode *node,3337 unsigned kindID) {3338 Location loc = mlirModule.getLoc();3339 3340 // The only operand should be a constant integer representing the number of3341 // dereferenceable bytes.3342 if (node->getNumOperands() != 1)3343 return emitError(loc) << "dereferenceable metadata must have one operand: "3344 << diagMD(node, llvmModule.get());3345 3346 auto *numBytesMD = dyn_cast<llvm::ConstantAsMetadata>(node->getOperand(0));3347 auto *numBytesCst = dyn_cast<llvm::ConstantInt>(numBytesMD->getValue());3348 if (!numBytesCst || !numBytesCst->getValue().isNonNegative())3349 return emitError(loc) << "dereferenceable metadata operand must be a "3350 "non-negative constant integer: "3351 << diagMD(node, llvmModule.get());3352 3353 bool mayBeNull = kindID == llvm::LLVMContext::MD_dereferenceable_or_null;3354 auto derefAttr = builder.getAttr<DereferenceableAttr>(3355 numBytesCst->getZExtValue(), mayBeNull);3356 3357 return derefAttr;3358}3359 3360OwningOpRef<ModuleOp> mlir::translateLLVMIRToModule(3361 std::unique_ptr<llvm::Module> llvmModule, MLIRContext *context,3362 bool emitExpensiveWarnings, bool dropDICompositeTypeElements,3363 bool loadAllDialects, bool preferUnregisteredIntrinsics,3364 bool importStructsAsLiterals) {3365 // Preload all registered dialects to allow the import to iterate the3366 // registered LLVMImportDialectInterface implementations and query the3367 // supported LLVM IR constructs before starting the translation. Assumes the3368 // LLVM and DLTI dialects that convert the core LLVM IR constructs have been3369 // registered before.3370 assert(llvm::is_contained(context->getAvailableDialects(),3371 LLVMDialect::getDialectNamespace()));3372 assert(llvm::is_contained(context->getAvailableDialects(),3373 DLTIDialect::getDialectNamespace()));3374 if (loadAllDialects)3375 context->loadAllAvailableDialects();3376 OwningOpRef<ModuleOp> module(ModuleOp::create(FileLineColLoc::get(3377 StringAttr::get(context, llvmModule->getSourceFileName()), /*line=*/0,3378 /*column=*/0)));3379 3380 ModuleImport moduleImport(module.get(), std::move(llvmModule),3381 emitExpensiveWarnings, dropDICompositeTypeElements,3382 preferUnregisteredIntrinsics,3383 importStructsAsLiterals);3384 if (failed(moduleImport.initializeImportInterface()))3385 return {};3386 if (failed(moduleImport.convertDataLayout()))3387 return {};3388 if (failed(moduleImport.convertComdats()))3389 return {};3390 if (failed(moduleImport.convertMetadata()))3391 return {};3392 if (failed(moduleImport.convertGlobals()))3393 return {};3394 if (failed(moduleImport.convertFunctions()))3395 return {};3396 if (failed(moduleImport.convertAliases()))3397 return {};3398 if (failed(moduleImport.convertIFuncs()))3399 return {};3400 moduleImport.convertTargetTriple();3401 moduleImport.convertModuleLevelAsm();3402 return module;3403}3404