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