120 lines
5.2 KiB
C++
120 lines
5.2 KiB
C++
|
//===- Utility.cpp ------ Collection of generic offloading utilities ------===//
|
||
|
//
|
||
|
// 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
|
||
|
//
|
||
|
//===----------------------------------------------------------------------===//
|
||
|
|
||
|
#include "llvm/Frontend/Offloading/Utility.h"
|
||
|
#include "llvm/IR/Constants.h"
|
||
|
#include "llvm/IR/GlobalValue.h"
|
||
|
#include "llvm/IR/GlobalVariable.h"
|
||
|
#include "llvm/IR/Value.h"
|
||
|
|
||
|
using namespace llvm;
|
||
|
using namespace llvm::offloading;
|
||
|
|
||
|
StructType *offloading::getEntryTy(Module &M) {
|
||
|
LLVMContext &C = M.getContext();
|
||
|
StructType *EntryTy =
|
||
|
StructType::getTypeByName(C, "struct.__tgt_offload_entry");
|
||
|
if (!EntryTy)
|
||
|
EntryTy = StructType::create(
|
||
|
"struct.__tgt_offload_entry", PointerType::getUnqual(C),
|
||
|
PointerType::getUnqual(C), M.getDataLayout().getIntPtrType(C),
|
||
|
Type::getInt32Ty(C), Type::getInt32Ty(C));
|
||
|
return EntryTy;
|
||
|
}
|
||
|
|
||
|
// TODO: Rework this interface to be more generic.
|
||
|
std::pair<Constant *, GlobalVariable *>
|
||
|
offloading::getOffloadingEntryInitializer(Module &M, Constant *Addr,
|
||
|
StringRef Name, uint64_t Size,
|
||
|
int32_t Flags, int32_t Data) {
|
||
|
Type *Int8PtrTy = PointerType::getUnqual(M.getContext());
|
||
|
Type *Int32Ty = Type::getInt32Ty(M.getContext());
|
||
|
Type *SizeTy = M.getDataLayout().getIntPtrType(M.getContext());
|
||
|
|
||
|
Constant *AddrName = ConstantDataArray::getString(M.getContext(), Name);
|
||
|
|
||
|
// Create the constant string used to look up the symbol in the device.
|
||
|
auto *Str = new GlobalVariable(M, AddrName->getType(), /*isConstant=*/true,
|
||
|
GlobalValue::InternalLinkage, AddrName,
|
||
|
".omp_offloading.entry_name");
|
||
|
Str->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
|
||
|
|
||
|
// Construct the offloading entry.
|
||
|
Constant *EntryData[] = {
|
||
|
ConstantExpr::getPointerBitCastOrAddrSpaceCast(Addr, Int8PtrTy),
|
||
|
ConstantExpr::getPointerBitCastOrAddrSpaceCast(Str, Int8PtrTy),
|
||
|
ConstantInt::get(SizeTy, Size),
|
||
|
ConstantInt::get(Int32Ty, Flags),
|
||
|
ConstantInt::get(Int32Ty, Data),
|
||
|
};
|
||
|
Constant *EntryInitializer = ConstantStruct::get(getEntryTy(M), EntryData);
|
||
|
return {EntryInitializer, Str};
|
||
|
}
|
||
|
|
||
|
void offloading::emitOffloadingEntry(Module &M, Constant *Addr, StringRef Name,
|
||
|
uint64_t Size, int32_t Flags, int32_t Data,
|
||
|
StringRef SectionName) {
|
||
|
llvm::Triple Triple(M.getTargetTriple());
|
||
|
|
||
|
auto [EntryInitializer, NameGV] =
|
||
|
getOffloadingEntryInitializer(M, Addr, Name, Size, Flags, Data);
|
||
|
|
||
|
auto *Entry = new GlobalVariable(
|
||
|
M, getEntryTy(M),
|
||
|
/*isConstant=*/true, GlobalValue::WeakAnyLinkage, EntryInitializer,
|
||
|
".omp_offloading.entry." + Name, nullptr, GlobalValue::NotThreadLocal,
|
||
|
M.getDataLayout().getDefaultGlobalsAddressSpace());
|
||
|
|
||
|
// The entry has to be created in the section the linker expects it to be.
|
||
|
if (Triple.isOSBinFormatCOFF())
|
||
|
Entry->setSection((SectionName + "$OE").str());
|
||
|
else
|
||
|
Entry->setSection(SectionName);
|
||
|
Entry->setAlignment(Align(1));
|
||
|
}
|
||
|
|
||
|
std::pair<GlobalVariable *, GlobalVariable *>
|
||
|
offloading::getOffloadEntryArray(Module &M, StringRef SectionName) {
|
||
|
llvm::Triple Triple(M.getTargetTriple());
|
||
|
|
||
|
auto *ZeroInitilaizer =
|
||
|
ConstantAggregateZero::get(ArrayType::get(getEntryTy(M), 0u));
|
||
|
auto *EntryInit = Triple.isOSBinFormatCOFF() ? ZeroInitilaizer : nullptr;
|
||
|
auto *EntryType = ArrayType::get(getEntryTy(M), 0);
|
||
|
|
||
|
auto *EntriesB = new GlobalVariable(M, EntryType, /*isConstant=*/true,
|
||
|
GlobalValue::ExternalLinkage, EntryInit,
|
||
|
"__start_" + SectionName);
|
||
|
EntriesB->setVisibility(GlobalValue::HiddenVisibility);
|
||
|
auto *EntriesE = new GlobalVariable(M, EntryType, /*isConstant=*/true,
|
||
|
GlobalValue::ExternalLinkage, EntryInit,
|
||
|
"__stop_" + SectionName);
|
||
|
EntriesE->setVisibility(GlobalValue::HiddenVisibility);
|
||
|
|
||
|
if (Triple.isOSBinFormatELF()) {
|
||
|
// We assume that external begin/end symbols that we have created above will
|
||
|
// be defined by the linker. This is done whenever a section name with a
|
||
|
// valid C-identifier is present. We define a dummy variable here to force
|
||
|
// the linker to always provide these symbols.
|
||
|
auto *DummyEntry = new GlobalVariable(
|
||
|
M, ZeroInitilaizer->getType(), true, GlobalVariable::ExternalLinkage,
|
||
|
ZeroInitilaizer, "__dummy." + SectionName);
|
||
|
DummyEntry->setSection(SectionName);
|
||
|
DummyEntry->setVisibility(GlobalValue::HiddenVisibility);
|
||
|
} else {
|
||
|
// The COFF linker will merge sections containing a '$' together into a
|
||
|
// single section. The order of entries in this section will be sorted
|
||
|
// alphabetically by the characters following the '$' in the name. Set the
|
||
|
// sections here to ensure that the beginning and end symbols are sorted.
|
||
|
EntriesB->setSection((SectionName + "$OA").str());
|
||
|
EntriesE->setSection((SectionName + "$OZ").str());
|
||
|
}
|
||
|
|
||
|
return std::make_pair(EntriesB, EntriesE);
|
||
|
}
|