-
Notifications
You must be signed in to change notification settings - Fork 14.4k
[mlir][gpu] Add the OffloadEmbeddingAttr
offloading translation attr
#78117
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
fabianmcg
wants to merge
5
commits into
llvm:main
Choose a base branch
from
fabianmcg:offload-attr
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from all commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
61c8809
[mlir][interfaces] Add the `TargetInfo` attribute interface
fabianmcg 436ec9b
[mlir][Target][LLVM] Add offload utility class
fabianmcg 24aa668
Base commit, PR llvm#78073
fabianmcg 90064f0
Base commit, PR llvm#78098
fabianmcg fe36b64
[mlir][gpu] Add the OffloadEmbeddingAttr offloading translation attr
fabianmcg File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
//===- Offload.h - LLVM Target Offload --------------------------*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file declares LLVM target offload utility classes. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#ifndef MLIR_TARGET_LLVM_OFFLOAD_H | ||
#define MLIR_TARGET_LLVM_OFFLOAD_H | ||
|
||
#include "mlir/Support/LogicalResult.h" | ||
#include "llvm/ADT/StringRef.h" | ||
|
||
namespace llvm { | ||
class Constant; | ||
class GlobalVariable; | ||
class Module; | ||
} // namespace llvm | ||
|
||
namespace mlir { | ||
namespace LLVM { | ||
/// `OffloadHandler` is a utility class for creating LLVM offload entries. LLVM | ||
/// offload entries hold information on offload symbols; for example, for a GPU | ||
/// kernel, this includes its host address to identify the kernel and the kernel | ||
/// identifier in the binary. Arrays of offload entries can be used to register | ||
/// functions within the CUDA/HIP runtime. Libomptarget also uses these entries | ||
/// to register OMP target offload kernels and variables. | ||
class OffloadHandler { | ||
public: | ||
using OffloadEntryArray = | ||
std::pair<llvm::GlobalVariable *, llvm::GlobalVariable *>; | ||
OffloadHandler(llvm::Module &module) : module(module) {} | ||
|
||
/// Returns the begin symbol name used in the entry array. | ||
static std::string getBeginSymbol(StringRef suffix); | ||
|
||
/// Returns the end symbol name used in the entry array. | ||
static std::string getEndSymbol(StringRef suffix); | ||
|
||
/// Returns the entry array if it exists or a pair of null pointers. | ||
OffloadEntryArray getEntryArray(StringRef suffix); | ||
|
||
/// Emits an empty array of offloading entries. | ||
OffloadEntryArray emitEmptyEntryArray(StringRef suffix); | ||
|
||
/// Inserts an offloading entry into an existing entry array. This method | ||
/// returns failure if the entry array hasn't been declared. | ||
LogicalResult insertOffloadEntry(StringRef suffix, llvm::Constant *entry); | ||
|
||
protected: | ||
llvm::Module &module; | ||
}; | ||
} // namespace LLVM | ||
} // namespace mlir | ||
|
||
#endif // MLIR_TARGET_LLVM_OFFLOAD_H |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
//===- Offload.cpp - LLVM Target Offload ------------------------*- C++ -*-===// | ||
// | ||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||
// See https://llvm.org/LICENSE.txt for license information. | ||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||
// | ||
//===----------------------------------------------------------------------===// | ||
// | ||
// This file defines LLVM target offload utility classes. | ||
// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "mlir/Target/LLVM/Offload.h" | ||
#include "llvm/Frontend/Offloading/Utility.h" | ||
#include "llvm/IR/Constants.h" | ||
#include "llvm/IR/Module.h" | ||
|
||
using namespace mlir; | ||
using namespace mlir::LLVM; | ||
|
||
std::string OffloadHandler::getBeginSymbol(StringRef suffix) { | ||
return ("__begin_offload_" + suffix).str(); | ||
} | ||
|
||
std::string OffloadHandler::getEndSymbol(StringRef suffix) { | ||
return ("__end_offload_" + suffix).str(); | ||
} | ||
|
||
namespace { | ||
/// Returns the type of the entry array. | ||
llvm::ArrayType *getEntryArrayType(llvm::Module &module, size_t numElems) { | ||
return llvm::ArrayType::get(llvm::offloading::getEntryTy(module), numElems); | ||
} | ||
|
||
/// Creates the initializer of the entry array. | ||
llvm::Constant *getEntryArrayBegin(llvm::Module &module, | ||
ArrayRef<llvm::Constant *> entries) { | ||
// If there are no entries return a constant zero initializer. | ||
llvm::ArrayType *arrayTy = getEntryArrayType(module, entries.size()); | ||
return entries.empty() ? llvm::ConstantAggregateZero::get(arrayTy) | ||
: llvm::ConstantArray::get(arrayTy, entries); | ||
} | ||
|
||
/// Computes the end position of the entry array. | ||
llvm::Constant *getEntryArrayEnd(llvm::Module &module, | ||
llvm::GlobalVariable *begin, size_t numElems) { | ||
llvm::Type *intTy = module.getDataLayout().getIntPtrType(module.getContext()); | ||
return llvm::ConstantExpr::getGetElementPtr( | ||
llvm::offloading::getEntryTy(module), begin, | ||
ArrayRef<llvm::Constant *>({llvm::ConstantInt::get(intTy, numElems)}), | ||
true); | ||
} | ||
} // namespace | ||
|
||
OffloadHandler::OffloadEntryArray | ||
OffloadHandler::getEntryArray(StringRef suffix) { | ||
llvm::GlobalVariable *beginGV = | ||
module.getGlobalVariable(getBeginSymbol(suffix), true); | ||
llvm::GlobalVariable *endGV = | ||
module.getGlobalVariable(getEndSymbol(suffix), true); | ||
return {beginGV, endGV}; | ||
} | ||
|
||
OffloadHandler::OffloadEntryArray | ||
OffloadHandler::emitEmptyEntryArray(StringRef suffix) { | ||
llvm::ArrayType *arrayTy = getEntryArrayType(module, 0); | ||
auto *beginGV = new llvm::GlobalVariable( | ||
module, arrayTy, /*isConstant=*/true, llvm::GlobalValue::InternalLinkage, | ||
getEntryArrayBegin(module, {}), getBeginSymbol(suffix)); | ||
auto *endGV = new llvm::GlobalVariable( | ||
module, llvm::PointerType::get(module.getContext(), 0), | ||
/*isConstant=*/true, llvm::GlobalValue::InternalLinkage, | ||
getEntryArrayEnd(module, beginGV, 0), getEndSymbol(suffix)); | ||
return {beginGV, endGV}; | ||
} | ||
|
||
LogicalResult OffloadHandler::insertOffloadEntry(StringRef suffix, | ||
llvm::Constant *entry) { | ||
// Get the begin and end symbols to the entry array. | ||
std::string beginSymId = getBeginSymbol(suffix); | ||
llvm::GlobalVariable *beginGV = module.getGlobalVariable(beginSymId, true); | ||
llvm::GlobalVariable *endGV = | ||
module.getGlobalVariable(getEndSymbol(suffix), true); | ||
// Fail if the symbols are missing. | ||
if (!beginGV || !endGV) | ||
return failure(); | ||
// Create the entry initializer. | ||
assert(beginGV->getInitializer() && "entry array initializer is missing."); | ||
// Add existing entries into the new entry array. | ||
SmallVector<llvm::Constant *> entries; | ||
if (auto beginInit = dyn_cast_or_null<llvm::ConstantAggregate>( | ||
beginGV->getInitializer())) { | ||
for (unsigned i = 0; i < beginInit->getNumOperands(); ++i) | ||
entries.push_back(beginInit->getOperand(i)); | ||
} | ||
// Add the new entry. | ||
entries.push_back(entry); | ||
// Create a global holding the new updated set of entries. | ||
auto *arrayTy = llvm::ArrayType::get(llvm::offloading::getEntryTy(module), | ||
entries.size()); | ||
auto *entryArr = new llvm::GlobalVariable( | ||
module, arrayTy, /*isConstant=*/true, llvm::GlobalValue::InternalLinkage, | ||
getEntryArrayBegin(module, entries), beginSymId, endGV); | ||
// Replace the old entry array variable withe new one. | ||
beginGV->replaceAllUsesWith(entryArr); | ||
beginGV->eraseFromParent(); | ||
entryArr->setName(beginSymId); | ||
// Update the end symbol. | ||
endGV->setInitializer(getEntryArrayEnd(module, entryArr, entries.size())); | ||
return success(); | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,17 @@ | ||
add_mlir_translation_library(MLIRGPUToLLVMIRTranslation | ||
GPUToLLVMIRTranslation.cpp | ||
SelectObjectAttr.cpp | ||
OffloadingTranslationAttrs.cpp | ||
|
||
LINK_COMPONENTS | ||
Core | ||
FrontendOffloading | ||
Object | ||
|
||
LINK_LIBS PUBLIC | ||
MLIRIR | ||
MLIRGPUDialect | ||
MLIRLLVMDialect | ||
MLIRSupport | ||
MLIRTargetLLVM | ||
MLIRTargetLLVMIRExport | ||
) |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It seems like this is doing the same kind of work that the OffloadInfoManager is doing. Would it be possible to refactor that to not have to add this class?
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Currently, the
OffloadInfoManager
creates the entries and adds them to theomp_offloading_entries
section. However, theOffloadInfoManager
performs no explicit construction of the entry array needed by the binary descriptor. It's the linker's job to implicitly create the array using all the entries in the section.The problem with this approach is that LLJIT doesn't handle the implicit creation of the array very well. To overcome this limitation of LLJIT, the attribute constructs the entry array explicitly.
In summary, this class can be removed up to an extent, but then JIT compilation is impossible, and a real linker is needed to obtain the final executable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It sounds like Clang isn't able to be used with the LLJIT in that case, or if it does, then there is already a solution in Clang. I think making this work both for Clang and MLIR would be useful. If there is already a solution in Clang then it should be migrated to the OpenMPIRBuilder.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The real problem is the lack of comprehensive support of linker sections in LLJIT, so I wouldn't say clang, or the clang-linker-wrapper are at fault. The easiest solution that I found was complying with LLJIT.
I think @jhuber6 was looking into changing the registration mechanism of LibOMPTarget binaries, so maybe we can found a solution that works for all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't have the full view of what LLJIT does here, but the use-case in
clang
is that we need each TU to be able to emit values that need to be registered by the runtime. There are a few alternate solutions to this, but having the linker handle it is the best overall. The rework I was talking about was to simply change the offloading entry struct so it's more generic.How does LLJIT work exactly? If you put globals into a section they will generally appear in order, so if you had a pointer to the first and last globals in that section you could just traverse it once it's gone through the backend. This is somewhat similar to the COFF linker handling which just gives an object at the beginning and end of the others in that section.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, I think the best solution would be to make LLJIT work.
I see.
Honestly, I'm not 100% sure, I only know that the same IR would work if linked with a regular linker and fail with LLJIT.
I asked around on LLJIT discord a couple months ago why it was not picking out the symbols and they didn't give an answer.
I'll inquire further with them and comeback with a more definitive answer.