xref: /freebsd-src/contrib/llvm-project/llvm/lib/Frontend/Offloading/Utility.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
17a6dacacSDimitry Andric //===- Utility.cpp ------ Collection of generic offloading utilities ------===//
25f757f3fSDimitry Andric //
35f757f3fSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
45f757f3fSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
55f757f3fSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
65f757f3fSDimitry Andric //
75f757f3fSDimitry Andric //===----------------------------------------------------------------------===//
85f757f3fSDimitry Andric 
95f757f3fSDimitry Andric #include "llvm/Frontend/Offloading/Utility.h"
105f757f3fSDimitry Andric #include "llvm/IR/Constants.h"
115f757f3fSDimitry Andric #include "llvm/IR/GlobalValue.h"
125f757f3fSDimitry Andric #include "llvm/IR/GlobalVariable.h"
135f757f3fSDimitry Andric #include "llvm/IR/Value.h"
14*0fca6ea1SDimitry Andric #include "llvm/Transforms/Utils/ModuleUtils.h"
155f757f3fSDimitry Andric 
165f757f3fSDimitry Andric using namespace llvm;
175f757f3fSDimitry Andric using namespace llvm::offloading;
185f757f3fSDimitry Andric 
195f757f3fSDimitry Andric StructType *offloading::getEntryTy(Module &M) {
205f757f3fSDimitry Andric   LLVMContext &C = M.getContext();
215f757f3fSDimitry Andric   StructType *EntryTy =
225f757f3fSDimitry Andric       StructType::getTypeByName(C, "struct.__tgt_offload_entry");
235f757f3fSDimitry Andric   if (!EntryTy)
245f757f3fSDimitry Andric     EntryTy = StructType::create(
255f757f3fSDimitry Andric         "struct.__tgt_offload_entry", PointerType::getUnqual(C),
265f757f3fSDimitry Andric         PointerType::getUnqual(C), M.getDataLayout().getIntPtrType(C),
275f757f3fSDimitry Andric         Type::getInt32Ty(C), Type::getInt32Ty(C));
285f757f3fSDimitry Andric   return EntryTy;
295f757f3fSDimitry Andric }
305f757f3fSDimitry Andric 
315f757f3fSDimitry Andric // TODO: Rework this interface to be more generic.
327a6dacacSDimitry Andric std::pair<Constant *, GlobalVariable *>
337a6dacacSDimitry Andric offloading::getOffloadingEntryInitializer(Module &M, Constant *Addr,
347a6dacacSDimitry Andric                                           StringRef Name, uint64_t Size,
357a6dacacSDimitry Andric                                           int32_t Flags, int32_t Data) {
36*0fca6ea1SDimitry Andric   llvm::Triple Triple(M.getTargetTriple());
375f757f3fSDimitry Andric   Type *Int8PtrTy = PointerType::getUnqual(M.getContext());
385f757f3fSDimitry Andric   Type *Int32Ty = Type::getInt32Ty(M.getContext());
395f757f3fSDimitry Andric   Type *SizeTy = M.getDataLayout().getIntPtrType(M.getContext());
405f757f3fSDimitry Andric 
415f757f3fSDimitry Andric   Constant *AddrName = ConstantDataArray::getString(M.getContext(), Name);
425f757f3fSDimitry Andric 
43*0fca6ea1SDimitry Andric   StringRef Prefix =
44*0fca6ea1SDimitry Andric       Triple.isNVPTX() ? "$offloading$entry_name" : ".offloading.entry_name";
45*0fca6ea1SDimitry Andric 
465f757f3fSDimitry Andric   // Create the constant string used to look up the symbol in the device.
47*0fca6ea1SDimitry Andric   auto *Str =
48*0fca6ea1SDimitry Andric       new GlobalVariable(M, AddrName->getType(), /*isConstant=*/true,
49*0fca6ea1SDimitry Andric                          GlobalValue::InternalLinkage, AddrName, Prefix);
505f757f3fSDimitry Andric   Str->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);
515f757f3fSDimitry Andric 
525f757f3fSDimitry Andric   // Construct the offloading entry.
535f757f3fSDimitry Andric   Constant *EntryData[] = {
545f757f3fSDimitry Andric       ConstantExpr::getPointerBitCastOrAddrSpaceCast(Addr, Int8PtrTy),
555f757f3fSDimitry Andric       ConstantExpr::getPointerBitCastOrAddrSpaceCast(Str, Int8PtrTy),
565f757f3fSDimitry Andric       ConstantInt::get(SizeTy, Size),
575f757f3fSDimitry Andric       ConstantInt::get(Int32Ty, Flags),
585f757f3fSDimitry Andric       ConstantInt::get(Int32Ty, Data),
595f757f3fSDimitry Andric   };
605f757f3fSDimitry Andric   Constant *EntryInitializer = ConstantStruct::get(getEntryTy(M), EntryData);
617a6dacacSDimitry Andric   return {EntryInitializer, Str};
627a6dacacSDimitry Andric }
637a6dacacSDimitry Andric 
647a6dacacSDimitry Andric void offloading::emitOffloadingEntry(Module &M, Constant *Addr, StringRef Name,
657a6dacacSDimitry Andric                                      uint64_t Size, int32_t Flags, int32_t Data,
667a6dacacSDimitry Andric                                      StringRef SectionName) {
677a6dacacSDimitry Andric   llvm::Triple Triple(M.getTargetTriple());
687a6dacacSDimitry Andric 
697a6dacacSDimitry Andric   auto [EntryInitializer, NameGV] =
707a6dacacSDimitry Andric       getOffloadingEntryInitializer(M, Addr, Name, Size, Flags, Data);
715f757f3fSDimitry Andric 
72*0fca6ea1SDimitry Andric   StringRef Prefix =
73*0fca6ea1SDimitry Andric       Triple.isNVPTX() ? "$offloading$entry$" : ".offloading.entry.";
745f757f3fSDimitry Andric   auto *Entry = new GlobalVariable(
755f757f3fSDimitry Andric       M, getEntryTy(M),
765f757f3fSDimitry Andric       /*isConstant=*/true, GlobalValue::WeakAnyLinkage, EntryInitializer,
77*0fca6ea1SDimitry Andric       Prefix + Name, nullptr, GlobalValue::NotThreadLocal,
785f757f3fSDimitry Andric       M.getDataLayout().getDefaultGlobalsAddressSpace());
795f757f3fSDimitry Andric 
805f757f3fSDimitry Andric   // The entry has to be created in the section the linker expects it to be.
815f757f3fSDimitry Andric   if (Triple.isOSBinFormatCOFF())
825f757f3fSDimitry Andric     Entry->setSection((SectionName + "$OE").str());
835f757f3fSDimitry Andric   else
845f757f3fSDimitry Andric     Entry->setSection(SectionName);
855f757f3fSDimitry Andric   Entry->setAlignment(Align(1));
865f757f3fSDimitry Andric }
875f757f3fSDimitry Andric 
885f757f3fSDimitry Andric std::pair<GlobalVariable *, GlobalVariable *>
895f757f3fSDimitry Andric offloading::getOffloadEntryArray(Module &M, StringRef SectionName) {
905f757f3fSDimitry Andric   llvm::Triple Triple(M.getTargetTriple());
915f757f3fSDimitry Andric 
925f757f3fSDimitry Andric   auto *ZeroInitilaizer =
935f757f3fSDimitry Andric       ConstantAggregateZero::get(ArrayType::get(getEntryTy(M), 0u));
945f757f3fSDimitry Andric   auto *EntryInit = Triple.isOSBinFormatCOFF() ? ZeroInitilaizer : nullptr;
955f757f3fSDimitry Andric   auto *EntryType = ArrayType::get(getEntryTy(M), 0);
96*0fca6ea1SDimitry Andric   auto Linkage = Triple.isOSBinFormatCOFF() ? GlobalValue::WeakODRLinkage
97*0fca6ea1SDimitry Andric                                             : GlobalValue::ExternalLinkage;
985f757f3fSDimitry Andric 
99*0fca6ea1SDimitry Andric   auto *EntriesB =
100*0fca6ea1SDimitry Andric       new GlobalVariable(M, EntryType, /*isConstant=*/true, Linkage, EntryInit,
1015f757f3fSDimitry Andric                          "__start_" + SectionName);
1025f757f3fSDimitry Andric   EntriesB->setVisibility(GlobalValue::HiddenVisibility);
103*0fca6ea1SDimitry Andric   auto *EntriesE =
104*0fca6ea1SDimitry Andric       new GlobalVariable(M, EntryType, /*isConstant=*/true, Linkage, EntryInit,
1055f757f3fSDimitry Andric                          "__stop_" + SectionName);
1065f757f3fSDimitry Andric   EntriesE->setVisibility(GlobalValue::HiddenVisibility);
1075f757f3fSDimitry Andric 
1085f757f3fSDimitry Andric   if (Triple.isOSBinFormatELF()) {
1095f757f3fSDimitry Andric     // We assume that external begin/end symbols that we have created above will
1105f757f3fSDimitry Andric     // be defined by the linker. This is done whenever a section name with a
1115f757f3fSDimitry Andric     // valid C-identifier is present. We define a dummy variable here to force
1125f757f3fSDimitry Andric     // the linker to always provide these symbols.
1135f757f3fSDimitry Andric     auto *DummyEntry = new GlobalVariable(
114*0fca6ea1SDimitry Andric         M, ZeroInitilaizer->getType(), true, GlobalVariable::InternalLinkage,
1155f757f3fSDimitry Andric         ZeroInitilaizer, "__dummy." + SectionName);
1165f757f3fSDimitry Andric     DummyEntry->setSection(SectionName);
117*0fca6ea1SDimitry Andric     appendToCompilerUsed(M, DummyEntry);
1185f757f3fSDimitry Andric   } else {
1195f757f3fSDimitry Andric     // The COFF linker will merge sections containing a '$' together into a
1205f757f3fSDimitry Andric     // single section. The order of entries in this section will be sorted
1215f757f3fSDimitry Andric     // alphabetically by the characters following the '$' in the name. Set the
1225f757f3fSDimitry Andric     // sections here to ensure that the beginning and end symbols are sorted.
1235f757f3fSDimitry Andric     EntriesB->setSection((SectionName + "$OA").str());
1245f757f3fSDimitry Andric     EntriesE->setSection((SectionName + "$OZ").str());
1255f757f3fSDimitry Andric   }
1265f757f3fSDimitry Andric 
1275f757f3fSDimitry Andric   return std::make_pair(EntriesB, EntriesE);
1285f757f3fSDimitry Andric }
129