xref: /src/contrib/llvm-project/llvm/lib/Frontend/Offloading/Utility.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
14df029ccSDimitry Andric //===- Utility.cpp ------ Collection of generic offloading utilities ------===//
2b1c73532SDimitry Andric //
3b1c73532SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4b1c73532SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5b1c73532SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6b1c73532SDimitry Andric //
7b1c73532SDimitry Andric //===----------------------------------------------------------------------===//
8b1c73532SDimitry Andric 
9b1c73532SDimitry Andric #include "llvm/Frontend/Offloading/Utility.h"
10b1c73532SDimitry Andric #include "llvm/IR/Constants.h"
11b1c73532SDimitry Andric #include "llvm/IR/GlobalValue.h"
12b1c73532SDimitry Andric #include "llvm/IR/GlobalVariable.h"
13b1c73532SDimitry Andric #include "llvm/IR/Value.h"
14ac9a064cSDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
15b1c73532SDimitry Andric 
16b1c73532SDimitry Andric using namespace llvm;
17b1c73532SDimitry Andric using namespace llvm::offloading;
18b1c73532SDimitry Andric 
getEntryTy(Module & M)19b1c73532SDimitry Andric StructType *offloading::getEntryTy(Module &M) {
20b1c73532SDimitry Andric   LLVMContext &C = M.getContext();
21b1c73532SDimitry Andric   StructType *EntryTy =
22b1c73532SDimitry Andric       StructType::getTypeByName(C, "struct.__tgt_offload_entry");
23b1c73532SDimitry Andric   if (!EntryTy)
24b1c73532SDimitry Andric     EntryTy = StructType::create(
25b1c73532SDimitry Andric         "struct.__tgt_offload_entry", PointerType::getUnqual(C),
26b1c73532SDimitry Andric         PointerType::getUnqual(C), M.getDataLayout().getIntPtrType(C),
27b1c73532SDimitry Andric         Type::getInt32Ty(C), Type::getInt32Ty(C));
28b1c73532SDimitry Andric   return EntryTy;
29b1c73532SDimitry Andric }
30b1c73532SDimitry Andric 
31b1c73532SDimitry Andric // TODO: Rework this interface to be more generic.
324df029ccSDimitry Andric std::pair<Constant *, GlobalVariable *>
getOffloadingEntryInitializer(Module & M,Constant * Addr,StringRef Name,uint64_t Size,int32_t Flags,int32_t Data)334df029ccSDimitry Andric offloading::getOffloadingEntryInitializer(Module &M, Constant *Addr,
344df029ccSDimitry Andric                                           StringRef Name, uint64_t Size,
354df029ccSDimitry Andric                                           int32_t Flags, int32_t Data) {
36ac9a064cSDimitry Andric   llvm::Triple Triple(M.getTargetTriple());
37b1c73532SDimitry Andric   Type *Int8PtrTy = PointerType::getUnqual(M.getContext());
38b1c73532SDimitry Andric   Type *Int32Ty = Type::getInt32Ty(M.getContext());
39b1c73532SDimitry Andric   Type *SizeTy = M.getDataLayout().getIntPtrType(M.getContext());
40b1c73532SDimitry Andric 
41b1c73532SDimitry Andric   Constant *AddrName = ConstantDataArray::getString(M.getContext(), Name);
42b1c73532SDimitry Andric 
43ac9a064cSDimitry Andric   StringRef Prefix =
44ac9a064cSDimitry Andric       Triple.isNVPTX() ? "$offloading$entry_name" : ".offloading.entry_name";
45ac9a064cSDimitry Andric 
46b1c73532SDimitry Andric   // Create the constant string used to look up the symbol in the device.
47ac9a064cSDimitry Andric   auto *Str =
48ac9a064cSDimitry Andric       new GlobalVariable(M, AddrName->getType(), /*isConstant=*/true,
49ac9a064cSDimitry Andric                          GlobalValue::InternalLinkage, AddrName, Prefix);
50b1c73532SDimitry Andric   Str->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
51b1c73532SDimitry Andric 
52b1c73532SDimitry Andric   // Construct the offloading entry.
53b1c73532SDimitry Andric   Constant *EntryData[] = {
54b1c73532SDimitry Andric       ConstantExpr::getPointerBitCastOrAddrSpaceCast(Addr, Int8PtrTy),
55b1c73532SDimitry Andric       ConstantExpr::getPointerBitCastOrAddrSpaceCast(Str, Int8PtrTy),
56b1c73532SDimitry Andric       ConstantInt::get(SizeTy, Size),
57b1c73532SDimitry Andric       ConstantInt::get(Int32Ty, Flags),
58b1c73532SDimitry Andric       ConstantInt::get(Int32Ty, Data),
59b1c73532SDimitry Andric   };
60b1c73532SDimitry Andric   Constant *EntryInitializer = ConstantStruct::get(getEntryTy(M), EntryData);
614df029ccSDimitry Andric   return {EntryInitializer, Str};
624df029ccSDimitry Andric }
634df029ccSDimitry Andric 
emitOffloadingEntry(Module & M,Constant * Addr,StringRef Name,uint64_t Size,int32_t Flags,int32_t Data,StringRef SectionName)644df029ccSDimitry Andric void offloading::emitOffloadingEntry(Module &M, Constant *Addr, StringRef Name,
654df029ccSDimitry Andric                                      uint64_t Size, int32_t Flags, int32_t Data,
664df029ccSDimitry Andric                                      StringRef SectionName) {
674df029ccSDimitry Andric   llvm::Triple Triple(M.getTargetTriple());
684df029ccSDimitry Andric 
694df029ccSDimitry Andric   auto [EntryInitializer, NameGV] =
704df029ccSDimitry Andric       getOffloadingEntryInitializer(M, Addr, Name, Size, Flags, Data);
71b1c73532SDimitry Andric 
72ac9a064cSDimitry Andric   StringRef Prefix =
73ac9a064cSDimitry Andric       Triple.isNVPTX() ? "$offloading$entry$" : ".offloading.entry.";
74b1c73532SDimitry Andric   auto *Entry = new GlobalVariable(
75b1c73532SDimitry Andric       M, getEntryTy(M),
76b1c73532SDimitry Andric       /*isConstant=*/true, GlobalValue::WeakAnyLinkage, EntryInitializer,
77ac9a064cSDimitry Andric       Prefix + Name, nullptr, GlobalValue::NotThreadLocal,
78b1c73532SDimitry Andric       M.getDataLayout().getDefaultGlobalsAddressSpace());
79b1c73532SDimitry Andric 
80b1c73532SDimitry Andric   // The entry has to be created in the section the linker expects it to be.
81b1c73532SDimitry Andric   if (Triple.isOSBinFormatCOFF())
82b1c73532SDimitry Andric     Entry->setSection((SectionName + "$OE").str());
83b1c73532SDimitry Andric   else
84b1c73532SDimitry Andric     Entry->setSection(SectionName);
85b1c73532SDimitry Andric   Entry->setAlignment(Align(1));
86b1c73532SDimitry Andric }
87b1c73532SDimitry Andric 
88b1c73532SDimitry Andric std::pair<GlobalVariable *, GlobalVariable *>
getOffloadEntryArray(Module & M,StringRef SectionName)89b1c73532SDimitry Andric offloading::getOffloadEntryArray(Module &M, StringRef SectionName) {
90b1c73532SDimitry Andric   llvm::Triple Triple(M.getTargetTriple());
91b1c73532SDimitry Andric 
92b1c73532SDimitry Andric   auto *ZeroInitilaizer =
93b1c73532SDimitry Andric       ConstantAggregateZero::get(ArrayType::get(getEntryTy(M), 0u));
94b1c73532SDimitry Andric   auto *EntryInit = Triple.isOSBinFormatCOFF() ? ZeroInitilaizer : nullptr;
95b1c73532SDimitry Andric   auto *EntryType = ArrayType::get(getEntryTy(M), 0);
96ac9a064cSDimitry Andric   auto Linkage = Triple.isOSBinFormatCOFF() ? GlobalValue::WeakODRLinkage
97ac9a064cSDimitry Andric                                             : GlobalValue::ExternalLinkage;
98b1c73532SDimitry Andric 
99ac9a064cSDimitry Andric   auto *EntriesB =
100ac9a064cSDimitry Andric       new GlobalVariable(M, EntryType, /*isConstant=*/true, Linkage, EntryInit,
101b1c73532SDimitry Andric                          "__start_" + SectionName);
102b1c73532SDimitry Andric   EntriesB->setVisibility(GlobalValue::HiddenVisibility);
103ac9a064cSDimitry Andric   auto *EntriesE =
104ac9a064cSDimitry Andric       new GlobalVariable(M, EntryType, /*isConstant=*/true, Linkage, EntryInit,
105b1c73532SDimitry Andric                          "__stop_" + SectionName);
106b1c73532SDimitry Andric   EntriesE->setVisibility(GlobalValue::HiddenVisibility);
107b1c73532SDimitry Andric 
108b1c73532SDimitry Andric   if (Triple.isOSBinFormatELF()) {
109b1c73532SDimitry Andric     // We assume that external begin/end symbols that we have created above will
110b1c73532SDimitry Andric     // be defined by the linker. This is done whenever a section name with a
111b1c73532SDimitry Andric     // valid C-identifier is present. We define a dummy variable here to force
112b1c73532SDimitry Andric     // the linker to always provide these symbols.
113b1c73532SDimitry Andric     auto *DummyEntry = new GlobalVariable(
114ac9a064cSDimitry Andric         M, ZeroInitilaizer->getType(), true, GlobalVariable::InternalLinkage,
115b1c73532SDimitry Andric         ZeroInitilaizer, "__dummy." + SectionName);
116b1c73532SDimitry Andric     DummyEntry->setSection(SectionName);
117ac9a064cSDimitry Andric     appendToCompilerUsed(M, DummyEntry);
118b1c73532SDimitry Andric   } else {
119b1c73532SDimitry Andric     // The COFF linker will merge sections containing a '$' together into a
120b1c73532SDimitry Andric     // single section. The order of entries in this section will be sorted
121b1c73532SDimitry Andric     // alphabetically by the characters following the '$' in the name. Set the
122b1c73532SDimitry Andric     // sections here to ensure that the beginning and end symbols are sorted.
123b1c73532SDimitry Andric     EntriesB->setSection((SectionName + "$OA").str());
124b1c73532SDimitry Andric     EntriesE->setSection((SectionName + "$OZ").str());
125b1c73532SDimitry Andric   }
126b1c73532SDimitry Andric 
127b1c73532SDimitry Andric   return std::make_pair(EntriesB, EntriesE);
128b1c73532SDimitry Andric }
129