| //===- 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); |
| } |